diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000000..4bb4e50c36 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[run] +source = tinygrad +branch = True diff --git a/.github/actions/setup-tinygrad/action.yml b/.github/actions/setup-tinygrad/action.yml index cf26a3e14a..1ef671025c 100644 --- a/.github/actions/setup-tinygrad/action.yml +++ b/.github/actions/setup-tinygrad/action.yml @@ -41,6 +41,10 @@ inputs: description: "Install LLVM?" required: false default: 'false' + mesa: + description: "Install mesa" + required: false + default: 'false' runs: using: "composite" steps: @@ -57,7 +61,7 @@ runs: uses: actions/cache@v4 with: path: ${{ github.workspace }}/.venv - key: venv-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-${{ inputs.deps }}-${{ inputs.pydeps }}-${{ hashFiles('**/setup.py') }}-${{ env.PYTHON_CACHE_VERSION }} + key: venv-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-${{ inputs.deps }}-${{ inputs.pydeps }}-${{ hashFiles('**/pyproject.toml') }}-${{ env.CACHE_VERSION }} # **** Caching downloads **** @@ -66,13 +70,13 @@ runs: uses: actions/cache@v4 with: path: ~/.cache/tinygrad/downloads/ - key: downloads-cache-${{ inputs.key }}-${{ env.DOWNLOAD_CACHE_VERSION }} + key: downloads-cache-${{ inputs.key }}-${{ env.CACHE_VERSION }} - name: Cache downloads (macOS) if: inputs.key != '' && runner.os == 'macOS' uses: actions/cache@v4 with: path: ~/Library/Caches/tinygrad/downloads/ - key: osx-downloads-cache-${{ inputs.key }}-${{ env.DOWNLOAD_CACHE_VERSION }} + key: osx-downloads-cache-${{ inputs.key }}-${{ env.CACHE_VERSION }} # **** Python deps **** @@ -183,7 +187,7 @@ runs: uses: actions/cache@v4 with: path: /var/cache/apt/archives/ - key: ${{ runner.os }}-apt-${{ steps.apt-pkgs.outputs.hash }}-${{ env.APT_CACHE_VERSION }} + key: ${{ runner.os }}-apt-${{ steps.apt-pkgs.outputs.hash }}-${{ env.CACHE_VERSION }} - name: Run apt Update + Install if: runner.os == 'Linux' && (inputs.opencl == 'true' || inputs.amd == 'true' || inputs.cuda == 'true' || inputs.webgpu == 'true' || inputs.llvm == 'true') @@ -243,7 +247,7 @@ runs: cache-name: cache-gpuocelot-build-1 with: path: ${{ github.workspace }}/gpuocelot/ocelot - key: ${{ runner.os }}-gpuocelot-b16039dc940dc6bc4ea0a98380495769ff35ed99-rebuild-${{ env.BUILD_CACHE_VERSION }} + key: ${{ runner.os }}-gpuocelot-b16039dc940dc6bc4ea0a98380495769ff35ed99-rebuild-${{ env.CACHE_VERSION }} - name: Clone/compile gpuocelot if: inputs.ocelot == 'true' && steps.cache-build.outputs.cache-hit != 'true' shell: bash @@ -289,3 +293,13 @@ runs: if: inputs.llvm == 'true' && runner.os == 'macOS' shell: bash run: brew install llvm@20 + + # **** mesa **** + - name: Install mesa (linux) + if: inputs.mesa == 'true' && runner.os == 'Linux' + shell: bash + run: sudo curl -L https://github.com/sirhcm/tinymesa/releases/download/tinymesa-32dc66c/libtinymesa_cpu-mesa-25.2.4-linux-amd64.so -o /usr/lib/libtinymesa_cpu.so + - name: Install mesa (macOS) + if: inputs.mesa == 'true' && runner.os == 'macOS' + shell: bash + run: brew install sirhcm/tinymesa/tinymesa_cpu diff --git a/.github/workflows/autogen.yml b/.github/workflows/autogen.yml index 4e413c3502..3aedf04d5d 100644 --- a/.github/workflows/autogen.yml +++ b/.github/workflows/autogen.yml @@ -1,10 +1,7 @@ name: Autogen env: # increment this when downloads substantially change to avoid the internet - DOWNLOAD_CACHE_VERSION: '12' - PYTHON_CACHE_VERSION: '3' - APT_CACHE_VERSION: '1' - BUILD_CACHE_VERSION: '1' + CACHE_VERSION: '13' CAPTURE_PROCESS_REPLAY: 1 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONPATH: ${{ github.workspace }} @@ -14,10 +11,10 @@ on: branches: - master pull_request: - paths: + paths: - 'tinygrad/runtime/autogen/**/*' workflow_dispatch: - paths: + paths: - 'tinygrad/runtime/autogen/**/*' jobs: @@ -36,8 +33,9 @@ jobs: cuda: 'true' webgpu: 'true' llvm: 'true' + pydeps: 'pyyaml mako' - name: Install autogen support packages - run: sudo apt-get install -y --no-install-recommends llvm-14-dev libclang-14-dev + run: sudo apt-get install -y --no-install-recommends llvm-14-dev libclang-14-dev llvm-20-dev - name: Verify OpenCL autogen run: | cp tinygrad/runtime/autogen/opencl.py /tmp/opencl.py.bak @@ -70,13 +68,10 @@ jobs: diff /tmp/sqtt.py.bak tinygrad/runtime/autogen/sqtt.py - name: Verify Linux autogen run: | - cp tinygrad/runtime/autogen/libc.py /tmp/libc.py.bak cp tinygrad/runtime/autogen/io_uring.py /tmp/io_uring.py.bak cp tinygrad/runtime/autogen/ib.py /tmp/ib.py.bak - ./autogen_stubs.sh libc ./autogen_stubs.sh io_uring ./autogen_stubs.sh ib - diff /tmp/libc.py.bak tinygrad/runtime/autogen/libc.py diff /tmp/io_uring.py.bak tinygrad/runtime/autogen/io_uring.py diff /tmp/ib.py.bak tinygrad/runtime/autogen/ib.py - name: Verify WebGPU autogen @@ -89,3 +84,26 @@ jobs: cp tinygrad/runtime/autogen/llvm.py /tmp/llvm.py.bak ./autogen_stubs.sh llvm diff /tmp/llvm.py.bak tinygrad/runtime/autogen/llvm.py + - name: Verify mesa autogen + run: | + cp tinygrad/runtime/autogen/mesa.py /tmp/mesa.py.bak + ./autogen_stubs.sh mesa + diff /tmp/mesa.py.bak tinygrad/runtime/autogen/mesa.py + autogen-ng: + name: In-tree Autogen + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - name: Checkout Code + uses: actions/checkout@v4 + - name: Setup Environment + uses: ./.github/actions/setup-tinygrad + with: + pydeps: 'clang>=20' + - name: Install autogen support packages + run: sudo apt-get install -y --no-install-recommends libclang-20-dev + - name: Verify Linux autogen + run: | + mv tinygrad/runtime/autogen/libc.py /tmp/libc.py.bak + python3 -c "from tinygrad.runtime.autogen import libc" + diff /tmp/libc.py.bak tinygrad/runtime/autogen/libc.py diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 857c737144..12e5d7018b 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -51,15 +51,18 @@ jobs: rm -f /tmp/staging.db /tmp/staging.db-shm /tmp/staging.db-wal - name: reset process replay run: python3.11 test/external/process_replay/reset.py + - name: Print macOS version + run: sw_vers - name: Run Stable Diffusion - run: BENCHMARK_LOG=stable_diffusion JIT=1 ASSERT_MIN_STEP_TIME=500 python3.11 examples/stable_diffusion.py --fp16 --seed 0 --noshow --timing | tee sd.txt + run: BENCHMARK_LOG=stable_diffusion JIT=1 ASSERT_MIN_STEP_TIME=800 python3.11 examples/stable_diffusion.py --fp16 --seed 0 --noshow --timing | tee sd.txt - name: Run Stable Diffusion without fp16 - run: BENCHMARK_LOG=stable_diffusion_fp32 JIT=1 ASSERT_MIN_STEP_TIME=700 python3.11 examples/stable_diffusion.py --seed 0 --noshow --timing | tee sd_no_fp16.txt + run: BENCHMARK_LOG=stable_diffusion_fp32 JIT=1 ASSERT_MIN_STEP_TIME=800 python3.11 examples/stable_diffusion.py --seed 0 --noshow --timing | tee sd_no_fp16.txt - name: Run Stable Diffusion v2 - run: BENCHMARK_LOG=stable_diffusion_v2 JIT=1 ASSERT_MIN_STEP_TIME=1600 python3.11 examples/sdv2.py --fp16 --seed 0 --noshow --timing | tee sdv2.txt + # TODO: very slow step time + run: BENCHMARK_LOG=stable_diffusion_v2 JIT=1 ASSERT_MIN_STEP_TIME=4500 python3.11 examples/sdv2.py --fp16 --seed 0 --noshow --timing | tee sdv2.txt # process replay can't capture this, the graph is too large - name: Run SDXL - run: BENCHMARK_LOG=stable_diffusion_xl ASSERT_MIN_STEP_TIME=3000 CAPTURE_PROCESS_REPLAY=0 JIT=1 python3.11 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt + run: BENCHMARK_LOG=stable_diffusion_xl ASSERT_MIN_STEP_TIME=5000 CAPTURE_PROCESS_REPLAY=0 JIT=1 python3.11 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt - name: Run model inference benchmark run: METAL=1 python3.11 test/external/external_model_benchmark.py - name: Test speed vs torch @@ -99,7 +102,7 @@ jobs: - name: Run GPT2 run: | BENCHMARK_LOG=gpt2_nojit JIT=0 python3.11 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_unjitted.txt - BENCHMARK_LOG=gpt2 JIT=1 ASSERT_MIN_STEP_TIME=8 python3.11 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_jitted.txt + BENCHMARK_LOG=gpt2 JIT=1 ASSERT_MIN_STEP_TIME=13 python3.11 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_jitted.txt - name: Run GPT2 w HALF run: BENCHMARK_LOG=gpt2_half HALF=1 python3.11 examples/gpt2.py --count 10 --temperature 0 --timing | tee gpt2_half.txt - name: Run GPT2 w HALF/BEAM @@ -108,14 +111,19 @@ jobs: run: BENCHMARK_LOG=olmoe python3.11 examples/olmoe.py - name: Train MNIST run: time PYTHONPATH=. TARGET_EVAL_ACC_PCT=96.0 python3.11 examples/beautiful_mnist.py | tee beautiful_mnist.txt - - name: Run 10 CIFAR training steps - run: BENCHMARK_LOG=cifar_10steps JIT=1 ASSERT_MIN_STEP_TIME=330 STEPS=10 python3.11 examples/hlb_cifar10.py | tee train_cifar.txt - - name: Run 10 CIFAR training steps w HALF - run: BENCHMARK_LOG=cifar_10steps_half JIT=2 ASSERT_MIN_STEP_TIME=385 STEPS=10 DEFAULT_FLOAT=HALF python3.11 examples/hlb_cifar10.py | tee train_cifar_half.txt + + # NOTE: this is failing in CI. it is not failing on my machine and I don't really have a way to debug it + # the error is "RuntimeError: Internal Error (0000000e:Internal Error)" + #- name: Run 10 CIFAR training steps + # run: BENCHMARK_LOG=cifar_10steps JIT=1 ASSERT_MIN_STEP_TIME=3000 STEPS=10 python3.11 examples/hlb_cifar10.py | tee train_cifar.txt + #- name: Run 10 CIFAR training steps w HALF + # run: BENCHMARK_LOG=cifar_10steps_half JIT=2 ASSERT_MIN_STEP_TIME=3000 STEPS=10 DEFAULT_FLOAT=HALF python3.11 examples/hlb_cifar10.py | tee train_cifar_half.txt + #- name: Run 10 CIFAR training steps w BF16 # run: STEPS=10 DEFAULT_FLOAT=BFLOAT16 python3.11 examples/hlb_cifar10.py | tee train_cifar_bf16.txt - - name: Run 10 CIFAR training steps w winograd - run: BENCHMARK_LOG=cifar_10steps_wino JIT=1 ASSERT_MIN_STEP_TIME=150 WINO=1 STEPS=10 python3.11 examples/hlb_cifar10.py | tee train_cifar_wino.txt + # TODO: too slow + # - name: Run 10 CIFAR training steps w winograd + # run: BENCHMARK_LOG=cifar_10steps_wino JIT=1 ASSERT_MIN_STEP_TIME=150 WINO=1 STEPS=10 python3.11 examples/hlb_cifar10.py | tee train_cifar_wino.txt - name: UsbGPU boot time run: sudo -E PYTHONPATH=. DEBUG=2 AM_RESET=1 AMD=1 AMD_IFACE=USB time python3.11 test/test_tiny.py TestTiny.test_plus - name: UsbGPU tiny tests @@ -123,7 +131,7 @@ jobs: - name: UsbGPU copy speeds run: sudo -E PYTHONPATH=. AMD=1 AMD_IFACE=USB python3.11 test/external/external_test_usb_asm24.py TestDevCopySpeeds #- name: UsbGPU openpilot test - # run: sudo -E PYTHONPATH=. AMD=1 AMD_IFACE=USB NOLOCALS=0 IMAGE=0 GRAPH_ONE_KERNEL=1 python3.11 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/9118973ed03c1ae1d40cf69a29507ec2cc78efd7/selfdrive/modeld/models/supercombo.onnx + # run: sudo -E PYTHONPATH=. AMD=1 AMD_IFACE=USB GRAPH_ONE_KERNEL=1 python3.11 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/9118973ed03c1ae1d40cf69a29507ec2cc78efd7/selfdrive/modeld/models/supercombo.onnx - uses: actions/upload-artifact@v4 with: name: Speed (Mac) @@ -191,7 +199,7 @@ jobs: - name: Test speed vs torch run: NV=1 CAPTURE_PROCESS_REPLAY=0 HALF=1 BIG=2 TORCHCUDA=1 python3 test/speed/external_test_speed_v_torch.py | tee torch_speed.txt - name: Test speed vs theoretical - run: NV=1 IGNORE_BEAM_CACHE=1 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20 + run: NV=1 IGNORE_BEAM_CACHE=1 CCACHE=0 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20 - name: Test benchmark allreduce run: NV=1 python test/external/external_benchmark_multitensor_allreduce.py - name: Test tensor cores @@ -203,6 +211,7 @@ jobs: CUDA=1 SHOULD_USE_TC=1 HALF=1 DEBUG=2 python3 extra/gemm/simple_matmul.py | tee matmul.txt CUDA=1 SHOULD_USE_TC=1 BFLOAT16=1 DEBUG=2 python3 extra/gemm/simple_matmul.py | tee matmul_bfloat16.txt CUDA=1 SHOULD_USE_TC=1 ALLOW_TF32=1 DEBUG=2 ATOL=2e-2 python3 extra/gemm/simple_matmul.py | tee matmul_tf32.txt + CUDA=1 SHOULD_USE_TC=1 FP8E4M3=1 DEBUG=2 python3 extra/gemm/simple_matmul.py | tee matmul_fp8.txt - name: Run Tensor Core GEMM (PTX) run: NV=1 NV_PTX=1 SHOULD_USE_TC=1 HALF=1 DEBUG=2 python3 extra/gemm/simple_matmul.py | tee matmul_ptx.txt - name: Run Tensor Core GEMM (NV) @@ -213,8 +222,9 @@ jobs: run: DEBUG=2 CUDA=1 python -m pytest -rA test/test_tiny.py - name: Run Stable Diffusion run: BENCHMARK_LOG=stable_diffusion NV=1 python3 examples/stable_diffusion.py --fp16 --seed 0 --noshow --timing | tee sd.txt - - name: Run SDXL - run: BENCHMARK_LOG=stable_diffusion_xl ASSERT_MIN_STEP_TIME=2000 CAPTURE_PROCESS_REPLAY=0 NV=1 CAPTURE_PROCESS_REPLAY=0 python3 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt + # TODO: too slow + # - name: Run SDXL + # run: BENCHMARK_LOG=stable_diffusion_xl ASSERT_MIN_STEP_TIME=2000 CAPTURE_PROCESS_REPLAY=0 NV=1 CAPTURE_PROCESS_REPLAY=0 python3 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt - name: Run LLaMA run: | BENCHMARK_LOG=llama_nojit NV=1 JIT=0 python3 examples/llama.py --gen 1 --prompt "Hello." --count 10 --temperature 0 --timing | tee llama_unjitted.txt @@ -229,6 +239,8 @@ jobs: run: BENCHMARK_LOG=llama3_beam NV=1 JITBEAM=2 IGNORE_BEAM_CACHE=1 python3 examples/llama3.py --size 8B --model weights/LLaMA-3/8B-SF-DPO/ --benchmark --temperature 0 | tee llama3_beam.txt - name: Run LLaMA-3 8B on 4 GPUs with BEAM run: BENCHMARK_LOG=llama3_beam_4gpu NV=1 JITBEAM=2 IGNORE_BEAM_CACHE=1 CAPTURE_PROCESS_REPLAY=0 python3 examples/llama3.py --size 8B --shard 4 --model weights/LLaMA-3/8B-SF-DPO/ --benchmark --temperature 0 | tee llama3_four_gpu.txt + - name: Run quantized LLaMA3 + run: BENCHMARK_LOG=llama3_fp8 python3 examples/llama3.py --size 8B --model weights/LLaMA-3/8B-SF-DPO/ --temperature 0 --benchmark --quantize fp8 | tee llama3_fp8.txt # - name: Run LLaMA-3 8B on 6 GPUs # run: NV=1 CAPTURE_PROCESS_REPLAY=0 python3 examples/llama3.py --size 8B --shard 6 --model weights/LLaMA-3/8B-SF-DPO/ --benchmark --temperature 0 | tee llama3_six_gpu.txt # - name: Run LLaMA-2 70B @@ -238,9 +250,9 @@ jobs: - name: Run GPT2 run: | BENCHMARK_LOG=gpt2_nojit NV=1 JIT=0 python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_unjitted.txt - BENCHMARK_LOG=gpt2 NV=1 JIT=1 ASSERT_MIN_STEP_TIME=5 python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_jitted.txt + BENCHMARK_LOG=gpt2 NV=1 JIT=1 ASSERT_MIN_STEP_TIME=4 python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_jitted.txt - name: Run GPT2 w HALF - run: BENCHMARK_LOG=gpt2_half NV=1 HALF=1 ASSERT_MIN_STEP_TIME=5 python3 examples/gpt2.py --count 10 --temperature 0 --timing | tee gpt2_half.txt + run: BENCHMARK_LOG=gpt2_half NV=1 HALF=1 ASSERT_MIN_STEP_TIME=6 python3 examples/gpt2.py --count 10 --temperature 0 --timing | tee gpt2_half.txt - name: Run GPT2 w HALF/BEAM run: BENCHMARK_LOG=gpt2_half_beam NV=1 HALF=1 JITBEAM=2 IGNORE_BEAM_CACHE=1 python3 examples/gpt2.py --count 10 --temperature 0 --timing | tee gpt2_half_beam.txt - uses: actions/upload-artifact@v4 @@ -262,6 +274,7 @@ jobs: llama3_beam.txt llama3_four_gpu.txt llama3_six_gpu.txt + llama3_fp8.txt llama_2_70B.txt mixtral.txt gpt2_unjitted.txt @@ -299,24 +312,28 @@ jobs: rm -f /tmp/staging.db /tmp/staging.db-shm /tmp/staging.db-wal - name: reset process replay run: test/external/process_replay/reset.py - - name: Fuzz Padded Tensor Core GEMM (NV) - run: NV=1 M_START=12 M_STOP=20 M_STEP=1 N_START=6 N_STOP=10 N_STEP=1 K_START=28 K_STOP=36 K_STEP=1 HALF=1 TC_OPT=2 python3 ./extra/gemm/fuzz_matmul.py - - name: Fuzz Padded Tensor Core GEMM (PTX) - run: NV=1 NV_PTX=1 M_START=12 M_STOP=20 M_STEP=1 N_START=6 N_STOP=10 N_STEP=1 K_START=28 K_STOP=36 K_STEP=1 HALF=1 TC_OPT=2 python3 ./extra/gemm/fuzz_matmul.py + # TODO: too slow + # - name: Fuzz Padded Tensor Core GEMM (NV) + # run: NV=1 M_START=12 M_STOP=20 M_STEP=1 N_START=6 N_STOP=10 N_STEP=1 K_START=28 K_STOP=36 K_STEP=1 HALF=1 TC_OPT=2 python3 ./extra/gemm/fuzz_matmul.py + # TODO: too slow + # - name: Fuzz Padded Tensor Core GEMM (PTX) + # run: NV=1 NV_PTX=1 M_START=12 M_STOP=20 M_STEP=1 N_START=6 N_STOP=10 N_STEP=1 K_START=28 K_STOP=36 K_STEP=1 HALF=1 TC_OPT=2 python3 ./extra/gemm/fuzz_matmul.py - name: Train MNIST run: time PYTHONPATH=. NV=1 TARGET_EVAL_ACC_PCT=96.0 python3 examples/beautiful_mnist.py | tee beautiful_mnist.txt + # TODO: too slow - name: Run 10 CIFAR training steps - run: BENCHMARK_LOG=cifar_10steps ASSERT_MIN_STEP_TIME=85 NV=1 STEPS=10 python3 examples/hlb_cifar10.py | tee train_cifar.txt - - name: Run 10 CIFAR training steps w HALF - run: BENCHMARK_LOG=cifar_10steps_half ASSERT_MIN_STEP_TIME=68 NV=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_half.txt - - name: Run 10 CIFAR training steps w BF16 - run: BENCHMARK_LOG=cifar_10steps_bf16 ASSERT_MIN_STEP_TIME=75 NV=1 STEPS=10 DEFAULT_FLOAT=BFLOAT16 python3 examples/hlb_cifar10.py | tee train_cifar_bf16.txt - - name: Run 10 CIFAR training steps w winograd - run: BENCHMARK_LOG=cifar_10steps_half_wino ASSERT_MIN_STEP_TIME=35 NV=1 CAPTURE_PROCESS_REPLAY=0 WINO=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_wino.txt - - name: Run full CIFAR training w 1 GPU - run: time BENCHMARK_LOG=cifar NV=1 DEFAULT_FLOAT=HALF LATEWINO=1 STEPS=1000 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee train_cifar_one_gpu.txt - - name: Run full CIFAR training steps w 6 GPUS - run: time BENCHMARK_LOG=cifar_6gpu CAPTURE_PROCESS_REPLAY=0 NV=1 DEFAULT_FLOAT=HALF STEPS=350 BS=1536 GPUS=6 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee train_cifar_six_gpu.txt + run: BENCHMARK_LOG=cifar_10steps ASSERT_MIN_STEP_TIME=1300 NV=1 STEPS=10 python3 examples/hlb_cifar10.py | tee train_cifar.txt + # - name: Run 10 CIFAR training steps w HALF + # run: BENCHMARK_LOG=cifar_10steps_half ASSERT_MIN_STEP_TIME=240 NV=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_half.txt + # - name: Run 10 CIFAR training steps w BF16 + # run: BENCHMARK_LOG=cifar_10steps_bf16 ASSERT_MIN_STEP_TIME=270 NV=1 STEPS=10 DEFAULT_FLOAT=BFLOAT16 python3 examples/hlb_cifar10.py | tee train_cifar_bf16.txt + # TODO: too slow + # - name: Run 10 CIFAR training steps w winograd + # run: BENCHMARK_LOG=cifar_10steps_half_wino ASSERT_MIN_STEP_TIME=350 NV=1 CAPTURE_PROCESS_REPLAY=0 WINO=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_wino.txt + # - name: Run full CIFAR training w 1 GPU + # run: time BENCHMARK_LOG=cifar NV=1 DEFAULT_FLOAT=HALF STEPS=1000 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee train_cifar_one_gpu.txt + # - name: Run full CIFAR training steps w 6 GPUS + # run: time BENCHMARK_LOG=cifar_6gpu CAPTURE_PROCESS_REPLAY=0 NV=1 DEFAULT_FLOAT=HALF STEPS=350 BS=1536 GPUS=6 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee train_cifar_six_gpu.txt - name: Run MLPerf resnet eval on training data run: time BENCHMARK_LOG=resnet_eval NV=1 MODEL=resnet python3 examples/mlperf/model_eval.py #- name: Run 10 MLPerf ResNet50 training steps (1 gpu) @@ -393,7 +410,7 @@ jobs: # python3 -c "import torch; print(torch.__version__)" # LD_PRELOAD="/opt/rocm/lib/libhsa-runtime64.so" HSA=1 BIG=2 TORCHCUDA=1 python3 test/speed/external_test_speed_v_torch.py | tee torch_speed.txt - name: Test speed vs theoretical - run: AMD=1 IGNORE_BEAM_CACHE=1 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20 + run: AMD=1 IGNORE_BEAM_CACHE=1 CCACHE=0 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20 - name: Test tensor cores run: | AMD=1 AMD_LLVM=0 python3 test/opt/test_tensor_cores.py @@ -415,9 +432,10 @@ jobs: - name: Test AM warm start time run: time AMD=1 python3 test/test_tiny.py TestTiny.test_plus - name: Run Stable Diffusion - run: BENCHMARK_LOG=stable_diffusion ASSERT_MIN_STEP_TIME=450 AMD=1 python3 examples/stable_diffusion.py --fp16 --seed 0 --noshow --timing | tee sd.txt - - name: Run SDXL - run: BENCHMARK_LOG=stable_diffusion_xl ASSERT_MIN_STEP_TIME=1400 CAPTURE_PROCESS_REPLAY=0 AMD=1 python3 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt + run: BENCHMARK_LOG=stable_diffusion ASSERT_MIN_STEP_TIME=550 AMD=1 python3 examples/stable_diffusion.py --fp16 --seed 0 --noshow --timing | tee sd.txt + # TODO: too slow + # - name: Run SDXL + # run: BENCHMARK_LOG=stable_diffusion_xl ASSERT_MIN_STEP_TIME=3200 CAPTURE_PROCESS_REPLAY=0 AMD=1 python3 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt - name: Run LLaMA 7B run: | BENCHMARK_LOG=llama_nojit AMD=1 JIT=0 python3 examples/llama.py --gen 1 --prompt "Hello." --count 10 --temperature 0 --timing | tee llama_unjitted.txt @@ -507,20 +525,22 @@ jobs: run: test/external/process_replay/reset.py - name: Train MNIST run: time PYTHONPATH=. AMD=1 TARGET_EVAL_ACC_PCT=96.0 python3 examples/beautiful_mnist.py | tee beautiful_mnist.txt + # TODO: too slow - name: Run 10 CIFAR training steps - run: BENCHMARK_LOG=cifar_10steps ASSERT_MIN_STEP_TIME=85 AMD=1 STEPS=10 python3 examples/hlb_cifar10.py | tee train_cifar.txt - - name: Run 10 CIFAR training steps w HALF - run: BENCHMARK_LOG=cifar_10steps_half ASSERT_MIN_STEP_TIME=188 AMD=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_half.txt + run: BENCHMARK_LOG=cifar_10steps ASSERT_MIN_STEP_TIME=2000 AMD=1 STEPS=10 python3 examples/hlb_cifar10.py | tee train_cifar.txt + # - name: Run 10 CIFAR training steps w HALF + # run: BENCHMARK_LOG=cifar_10steps_half ASSERT_MIN_STEP_TIME=390 AMD=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_half.txt # - name: Run 10 CIFAR training steps w BF16 # run: BENCHMARK_LOG=cifar_10steps_bf16 ASSERT_MIN_STEP_TIME=288 AMD=1 STEPS=10 DEFAULT_FLOAT=BFLOAT16 python3 examples/hlb_cifar10.py | tee train_cifar_bf16.txt - - name: Run 10 CIFAR training steps w winograd - run: BENCHMARK_LOG=cifar_10steps_half_wino ASSERT_MIN_STEP_TIME=66 AMD=1 WINO=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_wino.txt - - name: Run full CIFAR training w 1 GPU - run: time BENCHMARK_LOG=cifar AMD=1 DEFAULT_FLOAT=HALF LATEWINO=1 STEPS=1000 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee train_cifar_one_gpu.txt + # TODO: too slow + # - name: Run 10 CIFAR training steps w winograd + # run: BENCHMARK_LOG=cifar_10steps_half_wino ASSERT_MIN_STEP_TIME=66 AMD=1 WINO=1 STEPS=10 DEFAULT_FLOAT=HALF python3 examples/hlb_cifar10.py | tee train_cifar_wino.txt + # - name: Run full CIFAR training w 1 GPU + # run: time BENCHMARK_LOG=cifar AMD=1 DEFAULT_FLOAT=HALF STEPS=1000 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee train_cifar_one_gpu.txt #- name: Run full CIFAR training steps w 6 GPUS - # run: time BENCHMARK_LOG=cifar_6gpu AMD=1 DEFAULT_FLOAT=HALF STEPS=350 BS=1536 GPUS=6 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee train_cifar_six_gpu.txt + # run: time BENCHMARK_LOG=cifar_6gpu AMD=1 DEFAULT_FLOAT=HALF STEPS=350 BS=1536 GPUS=6 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee train_cifar_six_gpu.txt #- name: Run full CIFAR training steps w 6 GPUS (REMOTE) - # run: time BENCHMARK_LOG=cifar_6gpu_remote REMOTE=1 REMOTEDEV=AMD DEFAULT_FLOAT=HALF STEPS=350 BS=1536 GPUS=6 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee train_cifar_six_gpu_remote.txt + # run: time BENCHMARK_LOG=cifar_6gpu_remote REMOTE=1 REMOTEDEV=AMD DEFAULT_FLOAT=HALF STEPS=350 BS=1536 GPUS=6 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee train_cifar_six_gpu_remote.txt - uses: actions/upload-artifact@v4 with: name: Speed (AMD Training) @@ -605,22 +625,26 @@ jobs: rm -f /tmp/staging.db /tmp/staging.db-shm /tmp/staging.db-wal - name: reset process replay run: test/external/process_replay/reset.py - - name: benchmark openpilot 0.9.9 driving_vision - run: BENCHMARK_LOG=openpilot_0_9_9_vision ASSERT_MIN_STEP_TIME=30 PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_vision.onnx - - name: benchmark openpilot 0.9.9 driving_policy - run: BENCHMARK_LOG=openpilot_0_9_9_policy ASSERT_MIN_STEP_TIME=45 PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_policy.onnx - - name: benchmark openpilot 0.9.9 dmonitoring - run: BENCHMARK_LOG=openpilot_0_9_9_dmonitoring ASSERT_MIN_STEP_TIME=70 PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/dmonitoring_model.onnx - - name: openpilot compile3 0.9.9 driving_vision - run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_vision.onnx - - name: openpilot compile3 0.9.9 driving_policy - run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_policy.onnx - - name: openpilot compile3 0.9.9 dmonitoring - run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/dmonitoring_model.onnx - - name: openpilot compile3 Space Lab policy + vision - run: | - PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/22aec22a10ce09384d4a4af2a0bbff08d54af7e0c888503508f356fae4ff0e29 - PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/c824f68646a3b94f117f01c70dc8316fb466e05fbd42ccdba440b8a8dc86914b + # - name: openpilot compile3 0.9.9 driving_vision + # run: BENCHMARK_LOG=openpilot_0_9_9_vision PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_vision.onnx + # - name: openpilot compile3 0.9.9 driving_policy + # run: BENCHMARK_LOG=openpilot_0_9_9_policy PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_policy.onnx + # - name: openpilot compile3 0.9.9 dmonitoring + # run: BENCHMARK_LOG=openpilot_0_9_9_dmonitoring PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/dmonitoring_model.onnx + - name: openpilot compile3 0.10.0 driving_policy + run: BENCHMARK_LOG=openpilot_0_10_0_policy PYTHONPATH="." ASSERT_MIN_STEP_TIME=4 DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.10.0/selfdrive/modeld/models/driving_policy.onnx + - name: openpilot compile3 0.10.0 dmonitoring + run: BENCHMARK_LOG=openpilot_0_10_0_dmonitoring PYTHONPATH="." ASSERT_MIN_STEP_TIME=11 DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.10.0/selfdrive/modeld/models/dmonitoring_model.onnx + - name: DEBUG=2 openpilot compile3 0.10.1 driving_vision + run: PYTHONPATH="." DEBUG=2 DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/720392c9a5b986981fdbed1bb8c47a6c5573a50e/selfdrive/modeld/models/driving_vision.onnx + - name: openpilot compile3 0.10.1 driving_vision + # TODO: ASSERT_MIN_STEP_TIME=17 + run: BENCHMARK_LOG=openpilot_0_10_1_vision PYTHONPATH="." ASSERT_MIN_STEP_TIME=18 DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/720392c9a5b986981fdbed1bb8c47a6c5573a50e/selfdrive/modeld/models/driving_vision.onnx + - name: openpilot compile3 0.10.1 driving_policy + run: BENCHMARK_LOG=openpilot_0_10_1_policy PYTHONPATH="." ASSERT_MIN_STEP_TIME=4 DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/720392c9a5b986981fdbed1bb8c47a6c5573a50e/selfdrive/modeld/models/driving_policy.onnx + - name: openpilot compile3 0.10.1 dmonitoring + # TODO: ASSERT_MIN_STEP_TIME=10 + run: BENCHMARK_LOG=openpilot_0_10_1_dmonitoring PYTHONPATH="." ASSERT_MIN_STEP_TIME=11 DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/720392c9a5b986981fdbed1bb8c47a6c5573a50e/selfdrive/modeld/models/dmonitoring_model.onnx - name: benchmark MobileNetV2 on DSP run: | # generate quantized weights @@ -628,19 +652,9 @@ jobs: ln -s /data/home/tiny/tinygrad/testsig-*.so . PYTHONPATH=. CC=clang-19 CPU=1 CPU_LLVM=0 QUANT=1 CNT=0 python3 examples/test_onnx_imagenet.py https://github.com/xamcat/mobcat-samples/raw/refs/heads/master/onnx_runtime/InferencingSample/InferencingSample/mobilenetv2-7.onnx /tmp/model.quant.onnx # benchmark on DSP with NOOPT=1, the devectorizer has issues - PYTHONPATH=. CC=clang-19 DSP=1 DONT_REALIZE_EXPAND=1 NOOPT=1 CNT=2 DEBUG=2 python3 examples/test_onnx_imagenet.py /tmp/model.quant.onnx + PYTHONPATH=. CC=clang-19 DSP=1 NOOPT=1 CNT=2 DEBUG=2 python3 examples/test_onnx_imagenet.py /tmp/model.quant.onnx - name: Run process replay tests run: cp test/external/process_replay/process_replay.py ./process_replay.py && git fetch origin master && git -c advice.detachedHead=false checkout origin/master && PYTHONPATH=. python3 process_replay.py - - uses: actions/upload-artifact@v4 - with: - name: Speed (comma) - path: | - openpilot_compile_0_9_4.txt - openpilot_compile_0_9_7.txt - openpilot_0_9_4.txt - openpilot_0_9_7.txt - openpilot_image_0_9_4.txt - openpilot_image_0_9_7.txt testreddriverbenchmark: name: AM Benchmark @@ -694,8 +708,9 @@ jobs: run: | AMD=1 GRAPH_ONE_KERNEL=1 PYTHONPATH=. NSZ=8192 python3 test/speed/external_test_copy_speed.py TestCopySpeed.testCopyDefaulttoCPUJit AMD=1 GRAPH_ONE_KERNEL=1 PYTHONPATH=. NSZ=8192 python3 test/speed/external_test_copy_speed.py TestCopySpeed.testCopyCPUtoDefaultJit - - name: Run full CIFAR training w 1 GPU - run: time BENCHMARK_LOG=cifar AMD=1 DEFAULT_FLOAT=HALF LATEWINO=1 STEPS=1000 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee am_train_cifar_one_gpu.txt + # TODO: too slow + # - name: Run full CIFAR training w 1 GPU + # run: time BENCHMARK_LOG=cifar AMD=1 DEFAULT_FLOAT=HALF STEPS=1000 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee am_train_cifar_one_gpu.txt # TODO: enable # - name: Run 10 MLPerf ResNet50 training steps (1 gpu) # run: BENCHMARK_LOG=resnet_10steps AMD=1 MNISTMOCK=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=256 GPUS=1 MODEL=resnet python3 examples/mlperf/model_train.py | tee am_train_resnet_one_gpu.txt @@ -757,8 +772,9 @@ jobs: NV=1 GRAPH_ONE_KERNEL=1 PYTHONPATH=. NSZ=8192 python3 test/speed/external_test_copy_speed.py TestCopySpeed.testCopyCPUtoDefaultJit - name: Test LLAMA-3 run: BENCHMARK_LOG=llama3_beam NV=1 JITBEAM=2 IGNORE_BEAM_CACHE=1 python3 examples/llama3.py --size 8B --benchmark --temperature 0 | tee nv_llama3_beam.txt - - name: Run full CIFAR training w 1 GPU - run: time BENCHMARK_LOG=cifar NV=1 DEFAULT_FLOAT=HALF LATEWINO=1 STEPS=1000 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee nv_train_cifar_one_gpu.txt + # TODO: too slow + # - name: Run full CIFAR training w 1 GPU + # run: time BENCHMARK_LOG=cifar NV=1 DEFAULT_FLOAT=HALF STEPS=1000 TARGET_EVAL_ACC_PCT=93.0 python3 examples/hlb_cifar10.py | tee nv_train_cifar_one_gpu.txt #- name: Run 10 MLPerf ResNet50 training steps (1 gpu) # run: BENCHMARK_LOG=resnet_10steps NV=1 MNISTMOCK=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=256 GPUS=1 MODEL=resnet python3 examples/mlperf/model_train.py | tee nv_train_resnet_one_gpu.txt - name: Run 10 MLPerf Bert training steps (1 gpu) diff --git a/.github/workflows/benchmark_search.yml b/.github/workflows/benchmark_search.yml index 1f3dc889e3..2c56c3b82a 100644 --- a/.github/workflows/benchmark_search.yml +++ b/.github/workflows/benchmark_search.yml @@ -22,13 +22,13 @@ jobs: - name: Run SDXL with new search # TODO: GCVM_L2_PROTECTION_FAULT_STATUS with llvm19 run: | - BENCHMARK_LOG=search_sdxl PYTHONPATH=. AMD=1 JITBEAM=2 IGNORE_BEAM_CACHE=1 DISABLE_COMPILER_CACHE=1 python examples/sdxl.py --noshow --timing --seed 0 + BENCHMARK_LOG=search_sdxl PYTHONPATH=. AMD=1 JITBEAM=2 IGNORE_BEAM_CACHE=1 CCACHE=0 python examples/sdxl.py --noshow --timing --seed 0 - name: Run SDXL with cached search run: | BENCHMARK_LOG=search_sdxl_cached PYTHONPATH=. AMD=1 JITBEAM=2 python examples/sdxl.py --noshow --timing --seed 0 - name: Run winograd cifar with new search run: | - BENCHMARK_LOG=search_wino_cifar WINO=1 DEFAULT_FLOAT=HALF JITBEAM=4 IGNORE_BEAM_CACHE=1 DISABLE_COMPILER_CACHE=1 BS=1024 STEPS=500 python examples/hlb_cifar10.py + BENCHMARK_LOG=search_wino_cifar WINO=1 DEFAULT_FLOAT=HALF JITBEAM=4 IGNORE_BEAM_CACHE=1 CCACHE=0 BS=1024 STEPS=500 python examples/hlb_cifar10.py - name: Run winograd cifar with cached search run: | BENCHMARK_LOG=search_wino_cifar_cached WINO=1 DEFAULT_FLOAT=HALF JITBEAM=4 BS=1024 STEPS=500 python examples/hlb_cifar10.py diff --git a/.github/workflows/mlperf.yml b/.github/workflows/mlperf.yml index b965d05414..eedc8989f0 100644 --- a/.github/workflows/mlperf.yml +++ b/.github/workflows/mlperf.yml @@ -12,7 +12,7 @@ jobs: run_script_job: runs-on: [self-hosted, Linux, tinybox] if: github.repository_owner == 'tinygrad' - timeout-minutes: 360 + timeout-minutes: 720 steps: - name: Checkout Code @@ -27,4 +27,4 @@ jobs: run: | rm "~/.cache/tinygrad/cache_mlperf.db" || true BENCHMARK_LOG=mlpert_train_resnet LOGMLPERF=0 CACHEDB="~/.cache/tinygrad/cache_mlperf.db" examples/mlperf/training_submission_v5.1/tinycorp/benchmarks/resnet/implementations/tinybox_red/run_and_time.sh - rm "~/.cache/tinygrad/cache_mlperf.db" + rm "~/.cache/tinygrad/cache_mlperf.db" \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 22f36f2335..8f56f3eed7 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -20,11 +20,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install setuptools wheel build twine - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel + python -m build twine upload dist/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 27944c6edc..60ede62674 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,7 @@ name: Unit Tests env: # increment this when downloads substantially change to avoid the internet - DOWNLOAD_CACHE_VERSION: '12' - PYTHON_CACHE_VERSION: '3' - APT_CACHE_VERSION: '1' - BUILD_CACHE_VERSION: '1' + CACHE_VERSION: '13' CAPTURE_PROCESS_REPLAY: 1 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONPATH: ${{ github.workspace }} @@ -89,64 +86,65 @@ jobs: clang -O2 recognize.c -lm -o recognize cat test/models/efficientnet/Chicken.jpg | ./recognize | grep cock - torchbackend: - name: Torch Backend Tests - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Setup Environment - uses: ./.github/actions/setup-tinygrad - with: - key: torch-backend-pillow-torchvision-et-pt - deps: testing_minimal - pydeps: "pillow torchvision expecttest" - llvm: 'true' - - name: Install ninja - run: | - sudo apt update || true - sudo apt install -y --no-install-recommends ninja-build - - name: Lint with ruff - run: | - pip3 install --upgrade --force-reinstall ruff==0.11.0 - python3 -m ruff check extra/torch_backend/backend.py - - name: Test one op - run: FORWARD_ONLY=1 TINY_BACKEND=1 python3 test/test_ops.py TestOps.test_add - - name: Test ResNet-18 - run: DEBUG=2 python3 extra/torch_backend/example.py - - name: My (custom) tests - run: python3 extra/torch_backend/test.py - - name: Test one op in torch tests - run: DEBUG=2 python3 extra/torch_backend/torch_tests.py TestTinyBackendPRIVATEUSE1.test_unary_log_tiny_float32 - - name: Test Ops with TINY_BACKEND - run: CPU=1 CPU_LLVM=1 LLVMOPT=0 TINY_BACKEND=1 python3 -m pytest -n auto test/test_ops.py --durations=20 - - name: Test in-place operations on views - run: TORCH_DEBUG=1 python3 extra/torch_backend/test_inplace.py - - name: Test multi-gpu - run: CPU=1 CPU_LLVM=1 GPUS=4 TORCH_DEBUG=1 python3 extra/torch_backend/test_multigpu.py + # TODO: fix the torch backend and reenable + # torchbackend: + # name: Torch Backend Tests + # runs-on: ubuntu-latest + # timeout-minutes: 15 + # steps: + # - name: Checkout Code + # uses: actions/checkout@v4 + # - name: Setup Environment + # uses: ./.github/actions/setup-tinygrad + # with: + # key: torch-backend-pillow-torchvision-et-pt + # deps: testing_minimal + # pydeps: "pillow torchvision expecttest" + # llvm: 'true' + # - name: Install ninja + # run: | + # sudo apt update || true + # sudo apt install -y --no-install-recommends ninja-build + # - name: Lint with ruff + # run: | + # pip3 install --upgrade --force-reinstall ruff==0.11.0 + # python3 -m ruff check extra/torch_backend/backend.py + # - name: Test one op + # run: FORWARD_ONLY=1 TINY_BACKEND=1 python3 test/test_ops.py TestOps.test_add + # - name: Test ResNet-18 + # run: DEBUG=2 python3 extra/torch_backend/example.py + # - name: My (custom) tests + # run: python3 extra/torch_backend/test.py + # - name: Test one op in torch tests + # run: DEBUG=2 python3 extra/torch_backend/torch_tests.py TestTinyBackendPRIVATEUSE1.test_unary_log_tiny_float32 + # - name: Test Ops with TINY_BACKEND + # run: CPU=1 CPU_LLVM=1 LLVMOPT=0 TINY_BACKEND=1 python3 -m pytest -n auto test/test_ops.py --durations=20 + # - name: Test in-place operations on views + # run: TORCH_DEBUG=1 python3 extra/torch_backend/test_inplace.py + # - name: Test multi-gpu + # run: CPU=1 CPU_LLVM=1 GPUS=4 TORCH_DEBUG=1 python3 extra/torch_backend/test_multigpu.py - torchbackendmore: - name: Torch Backend Tests More - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Setup Environment - uses: ./.github/actions/setup-tinygrad - with: - key: torch-backend-pillow-torchvision-et-pt - deps: testing_minimal - llvm: 'true' - - name: Install ninja - run: | - sudo apt update || true - sudo apt install -y --no-install-recommends ninja-build - - name: Test beautiful_mnist in torch with TINY_BACKEND - run: SPLIT_REDUCEOP=0 FUSE_ARANGE=1 CPU=1 CPU_LLVM=1 TARGET_EVAL_ACC_PCT=96.0 TINY_BACKEND=1 python3 examples/other_mnist/beautiful_mnist_torch.py - - name: Test some torch tests (expect failure) - run: python3 -m pytest extra/torch_backend/torch_tests.py -v --tb=no || true + # torchbackendmore: + # name: Torch Backend Tests More + # runs-on: ubuntu-latest + # timeout-minutes: 15 + # steps: + # - name: Checkout Code + # uses: actions/checkout@v4 + # - name: Setup Environment + # uses: ./.github/actions/setup-tinygrad + # with: + # key: torch-backend-pillow-torchvision-et-pt + # deps: testing_minimal + # llvm: 'true' + # - name: Install ninja + # run: | + # sudo apt update || true + # sudo apt install -y --no-install-recommends ninja-build + # - name: Test beautiful_mnist in torch with TINY_BACKEND + # run: STEPS=20 CPU=1 TARGET_EVAL_ACC_PCT=90.0 TINY_BACKEND=1 python3 examples/other_mnist/beautiful_mnist_torch.py + # - name: Test some torch tests (expect failure) + # run: python3 -m pytest extra/torch_backend/torch_tests.py -v --tb=no || true bepython: name: Python Backend @@ -160,10 +158,8 @@ jobs: with: key: be-minimal deps: testing_minimal - - name: Test dtype with Python emulator (with RANGEIFY) - run: | - RANGEIFY=0 DEBUG=1 PYTHON=1 python3 -m pytest -n=auto test/test_dtype.py test/test_dtype_alu.py - RANGEIFY=1 DEBUG=1 PYTHON=1 python3 -m pytest -n=auto test/test_dtype.py test/test_dtype_alu.py + - name: Test dtype with Python emulator + run: DEBUG=1 PYTHON=1 python3 -m pytest -n=auto test/test_dtype.py test/test_dtype_alu.py - name: Test ops with Python emulator run: DEBUG=2 SKIP_SLOW_TEST=1 PYTHON=1 python3 -m pytest -n=auto test/test_ops.py --durations=20 - name: Test uops with Python emulator @@ -205,7 +201,7 @@ jobs: DEBUG=2 EMULATE=CUDA FORWARD_ONLY=1 PYTHON=1 python3 test/test_ops.py TestOps.test_gemm_fp16 DEBUG=2 EMULATE=CUDA ALLOW_TF32=1 FORWARD_ONLY=1 PYTHON=1 python3 test/test_ops.py TestOps.test_gemm DEBUG=2 EMULATE=CUDA_SM75 FORWARD_ONLY=1 PYTHON=1 python3 test/test_ops.py TestOps.test_gemm_fp16 - DEBUG=2 EMULATE=CUDA ALLOW_TF32=1 FORWARD_ONLY=1 PYTHON=1 python3 test/opt/test_tensor_cores.py + DEBUG=2 EMULATE=CUDA_SM89 ALLOW_TF32=1 FORWARD_ONLY=1 PYTHON=1 python3 test/opt/test_tensor_cores.py - name: Test emulated INTEL OpenCL tensor cores run: DEBUG=2 EMULATE=INTEL FORWARD_ONLY=1 PYTHON=1 HALF=1 N=64 python3 ./extra/gemm/simple_matmul.py - name: Test emulated AMX tensor cores @@ -231,23 +227,22 @@ jobs: uses: ./.github/actions/setup-tinygrad with: key: linting-only - python-version: '3.10' + python-version: '3.11' deps: linting - name: Lint bad-indentation and trailing-whitespace with pylint - run: python -m pylint --disable=all -e W0311 -e C0303 --jobs=0 --indent-string=' ' --recursive=y . + run: python -m pylint --disable=all -e W0311 -e C0303 --jobs=0 --indent-string=' ' --recursive=y . --ignore-paths='tinygrad/runtime/autogen' - name: Lint with ruff run: | pip3 install --upgrade --force-reinstall ruff==0.11.0 python3 -m ruff check . python3 -m ruff check examples/mlperf/ --ignore E501 - - name: Lint tinygrad with pylint - run: python -m pylint tinygrad/ - name: Run mypy run: | python -m mypy --strict-equality --lineprecision-report . cat lineprecision.txt - - name: Run TYPED=1 - run: TYPED=1 python -c "import tinygrad" + # broken because of UPatAny + #- name: Run TYPED=1 + # run: TYPED=1 python -c "import tinygrad" unittest: name: Unit Tests @@ -269,10 +264,13 @@ jobs: run: CPU=1 python -m pytest -n=auto test/unit/ --durations=20 - name: Run targetted tests on NULL backend run: NULL=1 python3 -m unittest test.test_multitensor.TestMultiTensor.test_data_parallel_resnet_train_step test/device/test_null.py - - name: Run SDXL on NULL backend - run: MAX_BUFFER_SIZE=0 NULL=1 DEBUG=1 python3 examples/sdxl.py --seed 0 --noshow --timing --fakeweights + # TODO: too slow + # - name: Run SDXL on NULL backend + # run: NULL=1 DEBUG=1 python3 examples/sdxl.py --seed 0 --noshow --timing --fakeweights - name: Run Clip tests for SD MLPerf on NULL backend - run: MAX_BUFFER_SIZE=0 NULL=1 python -m pytest -n=auto test/external/mlperf_stable_diffusion/external_test_models.py::TestOpenClip --durations=20 + run: NULL=1 python -m pytest -n=auto test/external/mlperf_stable_diffusion/external_test_models.py::TestOpenClip --durations=20 + - name: Run AMD emulated BERT training on NULL backend + run: EMULATE=AMD_RDNA4 NULL=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=1 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py # TODO: support fake weights #- name: Run LLaMA 7B on 4 fake devices # run: NULL=1 python3 examples/llama.py --gen 1 --size 7B --shard 4 --prompt "Hello." --count 3 --temperature 0 --timing @@ -289,8 +287,27 @@ jobs: python extra/optimization/extract_dataset.py gzip -c /tmp/sops > extra/datasets/sops.gz #DEBUG=1 MIN_ASTS=1 python extra/optimization/get_action_space.py - - name: Repo line count < 18000 lines - run: MAX_LINE_COUNT=18000 python sz.py + - name: Repo line count < 18500 lines + run: MAX_LINE_COUNT=18500 python sz.py + + spec: + strategy: + fail-fast: false + matrix: + group: [1, 2] + name: SPEC=2 (${{ matrix.group }}) + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout Code + uses: actions/checkout@v4 + - name: Setup Environment + uses: ./.github/actions/setup-tinygrad + with: + key: spec-unit + deps: testing_unit + - name: Test SPEC=2 + run: IGNORE_OOB=0 SPEC=2 PYTHONPATH="." pytest --maxfail=10 -n auto --durations=30 --ignore=test/models --ignore test/unit/test_hashing.py --timeout 60 -k "not test_setitem_big" --splits 2 --group ${{ matrix.group }} fuzzing: name: Fuzzing @@ -308,10 +325,6 @@ jobs: run: python test/external/fuzz_symbolic.py - name: Fuzz Test fast idiv run: python test/external/fuzz_fast_idiv.py - - name: Fuzz Test shapetracker - run: | - python test/external/fuzz_shapetracker.py - python test/external/fuzz_shapetracker_math.py - name: Fuzz Test shape ops run: python test/external/fuzz_shape_ops.py @@ -328,14 +341,11 @@ jobs: key: gpu-image deps: testing_minimal opencl: 'true' - - name: Test CL IMAGE=2 ops + training + - name: Test CL IMAGE=2 ops run: | CL=1 IMAGE=2 python -m pytest -n=auto test/test_ops.py --durations=20 - CL=1 IMAGE=2 python test/models/test_end2end.py TestEnd2End.test_linear_mnist - - name: Test CL IMAGE=2 ops + training (rangeify) - run: | - RANGEIFY=1 CL=1 IMAGE=2 python -m pytest -n=auto test/test_ops.py --durations=20 - RANGEIFY=1 CL=1 IMAGE=2 python test/models/test_end2end.py TestEnd2End.test_linear_mnist + # TODO: training is broken + # CL=1 IMAGE=2 python test/models/test_end2end.py TestEnd2End.test_linear_mnist - name: Run process replay tests uses: ./.github/actions/process-replay @@ -357,7 +367,7 @@ jobs: - name: Run Kernel Count Test run: CL=1 python -m pytest -n=auto test/external/external_test_opt.py - name: Run fused optimizer tests - run: CL=1 FUSE_OPTIM=1 python -m pytest -n=auto test/models/test_mnist.py + run: CL=1 FUSE_OPTIM=1 python -m pytest -n=auto test/models/test_mnist.py test/test_optim.py -k "not muon" - name: Upload artifact uses: actions/upload-artifact@v4 with: @@ -380,20 +390,13 @@ jobs: llvm: 'true' - name: Test openpilot model kernel count and gate usage run: | - ALLOWED_KERNEL_COUNT=208 ALLOWED_READ_IMAGE=2160 ALLOWED_GATED_READ_IMAGE=16 RANGEIFY=0 FLOAT16=0 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.4/selfdrive/modeld/models/supercombo.onnx - - name: Test openpilot model with rangeify - run: | - ALLOWED_KERNEL_COUNT=190 ALLOWED_READ_IMAGE=2041 ALLOWED_GATED_READ_IMAGE=33 RANGEIFY=1 FLOAT16=0 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.4/selfdrive/modeld/models/supercombo.onnx - - name: Test openpilot alt model correctness (float32) - run: FLOAT16=0 DEBUGCL=1 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/3799fe46b3a629e491d4b8498b8ae83e4c88c304/selfdrive/modeld/models/supercombo.onnx - - name: Test openpilot fastvits model correctness (float32) - run: FLOAT16=0 DEBUGCL=1 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/9118973ed03c1ae1d40cf69a29507ec2cc78efd7/selfdrive/modeld/models/supercombo.onnx - # - name: Test openpilot simple_plan vision model correctness (float32) - # run: FLOAT16=0 DEBUGCL=1 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/35ff4f4577002f2685e50c8346addae33fe8da27a41dd4d6a0f14d1f4b1af81b - - name: Test openpilot LLVM compile - run: CPU=1 CPU_LLVM=1 LLVMOPT=1 JIT=2 BEAM=0 IMAGE=0 python examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/9118973ed03c1ae1d40cf69a29507ec2cc78efd7/selfdrive/modeld/models/supercombo.onnx - - name: Test openpilot compile4 - run: NOLOCALS=1 CL=1 IMAGE=2 FLOAT16=1 DEBUG=2 python3 examples/openpilot/compile4.py + ALLOWED_KERNEL_COUNT=123 ALLOWED_READ_IMAGE=1397 ALLOWED_GATED_READ_IMAGE=94 FLOAT16=1 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/cf6376aa9a090f0da26c280ef69eabf9bbdd51d1faac9ed392919c3db69be916 + - name: Test openpilot CL compile fp16 + run: FLOAT16=1 DEBUGCL=1 CL=1 IMAGE=2 python examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/cf6376aa9a090f0da26c280ef69eabf9bbdd51d1faac9ed392919c3db69be916 + - name: Test openpilot CL compile fp32 (test correctness) + run: DEBUGCL=1 CL=1 IMAGE=2 SELFTEST=1 python examples/openpilot/compile3.py https://github.com/haraschax/filedump/raw/refs/heads/master/driving_vision_fp32.onnx + - name: Test openpilot LLVM compile fp16 + run: FLOAT16=1 CPU=1 CPU_LLVM=1 python examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/cf6376aa9a090f0da26c280ef69eabf9bbdd51d1faac9ed392919c3db69be916 - name: Run process replay tests uses: ./.github/actions/process-replay @@ -452,10 +455,12 @@ jobs: run: CL=1 IGNORE_BEAM_CACHE=1 python3 -m pytest extra/optimization/test_beam_search.py - name: Test MLPerf stuff run: CL=1 python -m pytest -n=auto test/external/external_test_optim.py test/external/external_test_losses.py test/external/external_test_metrics.py test/external/external_test_datasets.py --durations=20 + - name: NULL=1 beautiful_mnist_multigpu + run: NULL=1 python examples/beautiful_mnist_multigpu.py - name: Test Bert training - run: MAX_BUFFER_SIZE=0 NULL=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=24 GPUS=4 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py + run: NULL=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=24 GPUS=4 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py - name: Test llama 3 training - run: MAX_BUFFER_SIZE=0 NULL=1 SAMPLES=300 BS=8 SEQLEN=512 GRADIENT_ACC_STEPS=8 FAKEDATA=1 DEFAULT_FLOAT=bfloat16 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B MODEL=llama3 python3 examples/mlperf/model_train.py + run: NULL=1 SAMPLES=300 BS=8 SEQLEN=512 GRADIENT_ACC_STEPS=8 FAKEDATA=1 DEFAULT_FLOAT=bfloat16 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B MODEL=llama3 python3 examples/mlperf/model_train.py - name: Run process replay tests uses: ./.github/actions/process-replay @@ -518,88 +523,6 @@ jobs: # ****** Feature Tests ****** - testrangeifycpu: - name: Linux (rangeify) CPU - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Setup Environment - uses: ./.github/actions/setup-tinygrad - with: - key: rangeify-minimal-llvm - deps: testing_minimal - opencl: 'true' - llvm: "true" - - name: Test CPU=1 RANGEIFY=1 - # TODO: add more passing tests here - run: | - CPU=1 CPU_LLVM=0 RANGEIFY=1 python3 -m pytest -n auto --durations 20 \ - test/test_tiny.py test/test_rangeify.py test/test_ops.py test/test_symbolic_ops.py test/test_symbolic_jit.py test/test_tensor_variable.py \ - test/test_outerworld_range.py test/test_randomness.py test/test_nn.py test/test_arange.py test/test_tensor.py test/test_optim.py \ - test/test_setitem.py test/test_assign.py test/test_multitensor.py test/test_const_folding.py - - name: Test CPU=1 DEVECTORIZE=0 (RANGEIFY=1) - run: CPU=1 CPU_LLVM=0 RANGEIFY=1 DEVECTORIZE=0 FUSE_ARANGE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure" - - name: Test CPU=1 CPU_LLVM=1 RANGEIFY=1 - run: | - CPU=1 CPU_LLVM=1 RANGEIFY=1 python3 -m pytest -n auto --durations 20 test/test_edgecases.py - - name: Test Docs RANGEIFY=1 - run: | - RANGEIFY=1 python docs/abstractions2.py - # RANGEIFY=2 isn't supported - #- name: Test CPU=1 RANGEIFY=2 - # run: CPU=1 CPU_LLVM=0 RANGEIFY=2 python3 -m pytest -n auto test/test_tiny.py test/test_rangeify.py test/test_ops.py --durations 20 - # slow (and still wrong on beautiful_mnist) - #- name: Test LLVM RANGEIFY=1 (slow tests) - # run: CPU=1 CPU_LLVM=1 RANGEIFY=1 python3 -m pytest -n auto test/models/test_mnist.py --durations 20 - - name: Run process replay tests - uses: ./.github/actions/process-replay - - testrangeifycl: - name: Linux (rangeify) CL - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Setup Environment - uses: ./.github/actions/setup-tinygrad - with: - key: rangeify-cl - deps: testing - opencl: 'true' - llvm: "true" - - name: Test CL=1 RANGEIFY=1 - run: CL=1 RANGEIFY=1 pytest -n auto test/test_ops.py test/test_schedule.py test/test_symbolic_ops.py test/test_jit.py test/unit/test_disk_tensor.py test/models/test_mnist.py test/unit/test_mnist_dataset.py test/test_optim.py --durations 20 - - name: Test Fuse - run: CL=1 RANGEIFY=2 python3 -m pytest --durations 20 test/test_softmax_fusion.py -k "not test_auto_softmax" - - name: Test ONNX - run: CL=1 RANGEIFY=1 python -m pytest -n=auto test/external/external_test_onnx_backend.py --durations=20 - - name: Run process replay tests - uses: ./.github/actions/process-replay - - testrangeifymacos: - name: MacOS (rangeify) - runs-on: macos-14 - timeout-minutes: 15 - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Setup Environment - uses: ./.github/actions/setup-tinygrad - with: - key: metal - deps: testing - - name: some unit tests - run: METAL=1 RANGEIFY=1 python -m pytest -n=auto test/unit/test_winograd.py test/unit/test_linalg.py --durations=20 - - name: Test METAL=1 RANGEIFY=1 - run: | - METAL=1 RANGEIFY=1 python -m pytest -n=auto test/test_ops.py test/test_multitensor.py --durations=20 - METAL=1 MAX_KERNEL_BUFFERS=6 RANGEIFY=1 PYTHONPATH=. python test/test_multitensor.py TestBatchNorm.test_batchnorm - - name: Run process replay tests - uses: ./.github/actions/process-replay - testdevectorize: name: Linux (devectorize) runs-on: ubuntu-24.04 @@ -615,11 +538,11 @@ jobs: pydeps: "pillow" llvm: "true" - name: Test LLVM=1 DEVECTORIZE=0 - run: CPU=1 CPU_LLVM=1 DEVECTORIZE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure" + run: CPU=1 CPU_LLVM=1 DEVECTORIZE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py - name: Test LLVM=1 DEVECTORIZE=0 for model run: CPU=1 CPU_LLVM=1 DEVECTORIZE=0 python3 test/models/test_efficientnet.py - name: Test CPU=1 DEVECTORIZE=0 - run: CPU=1 CPU_LLVM=0 DEVECTORIZE=0 FUSE_ARANGE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure" + run: CPU=1 CPU_LLVM=0 DEVECTORIZE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py testdsp: name: Linux (DSP) @@ -720,10 +643,9 @@ jobs: run: TRANSCENDENTAL=2 python -m pytest -n=auto test/test_ops.py::TestOps::test_sin test/test_ops.py::TestOps::test_cos test/test_ops.py::TestOps::test_tan test/test_ops.py::TestOps::test_exp test/test_ops.py::TestOps::test_log --durations=20 - name: Run TestOps.test_add with SQTT run: | + VIZ=1 PMC=1 DEBUG=5 python3 test/test_ops.py TestOps.test_add VIZ=1 SQTT=1 DEBUG=5 python3 test/test_ops.py TestOps.test_add extra/sqtt/rgptool.py create "/tmp/profile.pkl.$USER" -o /tmp/gpu0.rgp - - name: Run pytest (amd) with RANGEIFY - run: RANGEIFY=1 python -m pytest test/test_linearizer.py::TestLinearizer::test_where_fold - name: Run process replay tests uses: ./.github/actions/process-replay @@ -765,7 +687,7 @@ jobs: strategy: fail-fast: false matrix: - backend: [llvm, cpu, opencl] + backend: [llvm, cpu, opencl, lvp] name: Linux (${{ matrix.backend }}) runs-on: ubuntu-22.04 @@ -779,9 +701,10 @@ jobs: key: ${{ matrix.backend }}-minimal deps: testing_minimal opencl: ${{ matrix.backend == 'opencl' && 'true' }} - llvm: ${{ matrix.backend == 'llvm' && 'true' }} + llvm: ${{ matrix.backend == 'llvm' || matrix.backend == 'lvp' }} + mesa: ${{ matrix.backend == 'lvp' && 'true' }} - name: Set env - run: printf "${{ matrix.backend == 'llvm' && 'CPU=1\nCPU_LLVM=1' || matrix.backend == 'cpu' && 'CPU=1\nCPU_LLVM=0\nCPU_COUNT=2' || matrix.backend == 'opencl' && 'CL=1' }}" >> $GITHUB_ENV + run: printf "${{ matrix.backend == 'llvm' && 'CPU=1\nCPU_LLVM=1' || matrix.backend == 'cpu' && 'CPU=1\nCPU_LLVM=0\nCPU_COUNT=2' || matrix.backend == 'opencl' && 'CL=1' || matrix.backend == 'lvp' && 'CPU=1\nCPU_LVP=1' }}" >> $GITHUB_ENV - name: Check Device.DEFAULT and print some source run: | python3 -c "from tinygrad import Device; assert Device.DEFAULT in ['CPU','CL'], Device.DEFAULT" @@ -983,7 +906,7 @@ jobs: strategy: fail-fast: false matrix: - backend: [metal, llvm, cpu] + backend: [metal, llvm, cpu, lvp] name: MacOS (${{ matrix.backend }}) runs-on: macos-15 timeout-minutes: 20 @@ -996,12 +919,13 @@ jobs: key: macos-${{ matrix.backend }}-minimal deps: testing_minimal pydeps: "capstone" - llvm: ${{ matrix.backend == 'llvm' && 'true' }} + llvm: ${{ matrix.backend == 'llvm' || matrix.backend == 'lvp' }} + mesa: ${{ matrix.backend == 'lvp' && 'true' }} - name: Set env - run: printf "${{ matrix.backend == 'llvm' && 'CPU=1\nCPU_LLVM=1' || matrix.backend == 'cpu' && 'CPU=1\nCPU_LLVM=0\nCPU_COUNT=2' || matrix.backend == 'metal' && 'METAL=1'}}" >> $GITHUB_ENV + run: printf "${{ matrix.backend == 'llvm' && 'CPU=1\nCPU_LLVM=1' || matrix.backend == 'cpu' && 'CPU=1\nCPU_LLVM=0\nCPU_COUNT=2' || matrix.backend == 'metal' && 'METAL=1' || matrix.backend == 'lvp' && 'CPU=1\nCPU_LVP=1' }}" >> $GITHUB_ENV - name: Check Device.DEFAULT and print some source run: | - python -c "from tinygrad import Device; assert Device.DEFAULT == {'LLVM':'CPU'}.get(x:='${{ matrix.backend }}'.upper(), x), Device.DEFAULT" + python -c "from tinygrad import Device; assert Device.DEFAULT == {'LLVM':'CPU','LVP':'CPU'}.get(x:='${{ matrix.backend }}'.upper(), x), Device.DEFAULT" DEBUG=4 python3 test/test_tiny.py TestTiny.test_plus - name: Run pytest (${{ matrix.backend }}) run: python3 -m pytest -n=auto test/ --ignore=test/models --ignore=test/unit --durations=20 @@ -1043,9 +967,3 @@ jobs: run: | python -c "from tinygrad import Device; assert Device.DEFAULT == {'LLVM':'CPU'}.get(x:='${{ matrix.backend }}'.upper(), x), Device.DEFAULT" python -m pytest -n=auto test/test_tiny.py test/test_ops.py --durations=20 - - name: Run pytest (${{ matrix.backend }}) with RANGEIFY - if: matrix.backend=='webgpu' - env: - RANGEIFY: 1 - shell: bash - run: python -m pytest -n=auto test/test_tiny.py test/test_ops.py --durations=20 diff --git a/.gitignore b/.gitignore index fd1a734bea..430e1b2692 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ extra/huggingface_onnx/models/* extra/huggingface_onnx/*.yaml extra/weights venv +venv_sd_mlperf examples/**/net.*[js,json] examples/**/*.safetensors node_modules @@ -62,3 +63,5 @@ profile_stats *.log target .mypy_cache +mutants +.mutmut-cache \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d3baff37e8..3845e4bd39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,21 +20,15 @@ repos: language: system always_run: true pass_filenames: false - - id: tests - name: subset of tests - entry: env PYTHONPATH="." python3 -m pytest -n=4 test/test_ops.py test/test_dtype.py test/test_schedule.py test/test_assign.py - language: system - always_run: true - pass_filenames: false - id: example - name: multi device tests + name: test all devices entry: python3 test/external/external_test_example.py language: system always_run: true pass_filenames: false - - id: pylint - name: pylint - entry: python3 -m pylint tinygrad/ + - id: tests + name: subset of tests + entry: env OMP_NUM_THREADS=1 PYTHONPATH="." python3 -m pytest -n=6 test/test_ops.py test/test_dtype.py test/test_schedule.py test/test_assign.py language: system always_run: true - pass_filenames: false \ No newline at end of file + pass_filenames: false diff --git a/.pylintrc b/.pylintrc index 2f1de51927..dc51be94d7 100644 --- a/.pylintrc +++ b/.pylintrc @@ -30,10 +30,6 @@ persistent=yes # Specify a configuration file. #rcfile= -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages -suggestion-mode=yes - # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no diff --git a/README.md b/README.md index dab378a23a..a8892c79c5 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,38 @@ tinygrad: For something between [PyTorch](https://github.com/pytorch/pytorch) an --- -Despite tinygrad's size, it is a fully featured deep learning framework. +tinygrad is an end-to-end deep learning stack: -Due to its extreme simplicity, it is the easiest framework to add new accelerators to, with support for both inference and training. If XLA is CISC, tinygrad is RISC. +- **Tensor library** with autograd +- **IR and compiler** that fuse and lower kernels +- **JIT + graph execution** +- **nn / optim / datasets** for real training -tinygrad is now beta software, we [raised some money](https://geohot.github.io/blog/jekyll/update/2023/05/24/the-tiny-corp-raised-5M.html) to make it good. Someday, we will tape out chips. +It’s inspired by PyTorch (ergonomics), JAX (functional transforms and IR-based AD), and TVM (scheduling and codegen), but stays intentionally tiny and hackable. -## Features +--- -### LLaMA and Stable Diffusion +## How tinygrad compares -tinygrad can run [LLaMA](/docs/showcase.md#llama) and [Stable Diffusion](/docs/showcase.md#stable-diffusion)! +**PyTorch** + +- ✅ Similar: eager `Tensor` API, autograd, `optim`, basic datasets and layers. +- ✅ You can write familiar training loops. +- 🔁 Unlike PyTorch, the entire compiler and IR are visible and hackable. + +**JAX** + +- ✅ IR-based autodiff over primitives (like JAXPR + XLA). +- ✅ Function-level JIT (`TinyJit`) that captures and replays kernels. +- 🔁 Fewer functional transforms (no full `vmap`/`pmap` yet), but far easier to read. + +**TVM** + +- ✅ Multiple lowering passes, scheduling, and BEAM search over kernels. +- ✅ Device “graphs” for batched execution. +- 🔁 tinygrad also ships the **front-end framework** (tensors, nn, optim), not just the compiler. + +--- ### Laziness diff --git a/autogen_stubs.sh b/autogen_stubs.sh index b60ced5086..d5c25643af 100755 --- a/autogen_stubs.sh +++ b/autogen_stubs.sh @@ -31,7 +31,9 @@ $(for p in "$@"; do echo " $p,"; done) ] def _try_dlopen_$name(): library = ctypes.util.find_library("$name") - if library: return ctypes.CDLL(library) + if library: + try: return ctypes.CDLL(library) + except OSError: pass for candidate in PATHS_TO_TRY: try: return ctypes.CDLL(candidate) except OSError: pass @@ -186,6 +188,7 @@ nv_status_codes = {} extra/nv_gpu_driver/g_rpc-message-header.h \ extra/nv_gpu_driver/gsp_static_config.h \ extra/nv_gpu_driver/vbios.h \ + extra/nv_gpu_driver/pci_exp_table.h \ --clang-args="-DRPC_MESSAGE_STRUCTURES -DRPC_STRUCTURES -include $NVKERN_SRC/src/common/sdk/nvidia/inc/nvtypes.h -I$NVKERN_SRC/src/nvidia/generated -I$NVKERN_SRC/src/common/inc -I$NVKERN_SRC/src/nvidia/inc -I$NVKERN_SRC/src/nvidia/interface/ -I$NVKERN_SRC/src/nvidia/inc/kernel -I$NVKERN_SRC/src/nvidia/inc/libraries -I$NVKERN_SRC/src/nvidia/arch/nvalloc/common/inc -I$NVKERN_SRC/kernel-open/nvidia-uvm -I$NVKERN_SRC/kernel-open/common/inc -I$NVKERN_SRC/src/common/sdk/nvidia/inc -I$NVKERN_SRC/src/nvidia/arch/nvalloc/unix/include -I$NVKERN_SRC/src/common/sdk/nvidia/inc/ctrl" \ -o $BASE/nv/nv.py @@ -251,23 +254,6 @@ generate_ib() { fixup $BASE/ib.py } -generate_libc() { - clang2py -k cdefstum \ - $(dpkg -L libc6-dev | grep sys/mman.h) \ - $(dpkg -L libc6-dev | grep sys/syscall.h) \ - /usr/include/string.h \ - /usr/include/elf.h \ - /usr/include/unistd.h \ - /usr/include/asm-generic/mman-common.h \ - -o $BASE/libc.py - - sed -i "s\import ctypes\import ctypes, ctypes.util, os\g" $BASE/libc.py - sed -i "s\FIXME_STUB\libc\g" $BASE/libc.py - sed -i "s\FunctionFactoryStub()\None if (libc_path := ctypes.util.find_library('c')) is None else ctypes.CDLL(libc_path, use_errno=True)\g" $BASE/libc.py - - fixup $BASE/libc.py -} - generate_llvm() { INC="$(llvm-config-14 --includedir)" clang2py -k cdefstum \ @@ -414,10 +400,31 @@ generate_sqtt() { clang2py -k cdefstum \ extra/sqtt/sqtt.h \ -o $BASE/sqtt.py - fixup $BASE/sqtt.py sed -i "s\import ctypes\import ctypes, os\g" $BASE/sqtt.py python3 -c "import tinygrad.runtime.autogen.sqtt" + + ROCPROF_COMMIT_HASH=dd0485100971522cc4cd8ae136bdda431061a04d + ROCPROF_SRC=/tmp/rocprof-trace-decoder-$ROCPROF_COMMIT_HASH + if [ ! -d "$ROCPROF_SRC" ]; then + git clone https://github.com/ROCm/rocprof-trace-decoder $ROCPROF_SRC + pushd . + cd $ROCPROF_SRC + git reset --hard $ROCPROF_COMMIT_HASH + popd + fi + + clang2py -k cdefstum \ + $ROCPROF_SRC/include/rocprof_trace_decoder.h \ + $ROCPROF_SRC/include/trace_decoder_instrument.h \ + $ROCPROF_SRC/include/trace_decoder_types.h \ + -o $BASE/rocprof.py + fixup $BASE/rocprof.py + sed -i '1s/^/# pylint: skip-file\n/' $BASE/rocprof.py + sed -i "s/import ctypes/import ctypes, ctypes.util/g" $BASE/rocprof.py + patch_dlopen $BASE/rocprof.py rocprof-trace-decoder "'/usr/local/lib/librocprof-trace-decoder.so'" "'/usr/local/lib/librocprof-trace-decoder.dylib'" + sed -i "s/def _try_dlopen_rocprof-trace-decoder():/def _try_dlopen_rocprof_trace_decoder():/g" $BASE/rocprof.py + sed -i "s|FunctionFactoryStub()|_try_dlopen_rocprof_trace_decoder()|g" $BASE/rocprof.py } generate_webgpu() { @@ -442,6 +449,80 @@ generate_libusb() { python3 -c "import tinygrad.runtime.autogen.libusb" } +generate_mesa() { + MESA_TAG="mesa-25.2.4" + MESA_SRC=/tmp/mesa-$MESA_TAG + TINYMESA_TAG=tinymesa-32dc66c + TINYMESA_DIR=/tmp/tinymesa-$MESA_TAG-$TINYMESA_TAG/ + TINYMESA_SO=$TINYMESA_DIR/libtinymesa_cpu.so + if [ ! -d "$MESA_SRC" ]; then + git clone --depth 1 --branch $MESA_TAG https://gitlab.freedesktop.org/mesa/mesa.git $MESA_SRC + pushd . + cd $MESA_SRC + git reset --hard $MESA_COMMIT_HASH + # clang 14 doesn't support packed enums + sed -i "s/enum \w\+ \(\w\+\);$/uint8_t \1;/" $MESA_SRC/src/nouveau/headers/nv_device_info.h + sed -i "s/enum \w\+ \(\w\+\);$/uint8_t \1;/" $MESA_SRC/src/nouveau/compiler/nak.h + sed -i "s/nir_instr_type \(\w\+\);/uint8_t \1;/" $MESA_SRC/src/compiler/nir/nir.h + mkdir -p gen/util/format + python3 src/util/format/u_format_table.py src/util/format/u_format.yaml --enums > gen/util/format/u_format_gen.h + python3 src/compiler/nir/nir_opcodes_h.py > gen/nir_opcodes.h + python3 src/compiler/nir/nir_intrinsics_h.py --outdir gen + python3 src/compiler/nir/nir_intrinsics_indices_h.py --outdir gen + python3 src/compiler/nir/nir_builder_opcodes_h.py > gen/nir_builder_opcodes.h + python3 src/compiler/nir/nir_intrinsics_h.py --outdir gen + python3 src/compiler/builtin_types_h.py gen/builtin_types.h + popd + fi + + if [ ! -d "$TINYMESA_DIR" ]; then + mkdir $TINYMESA_DIR + curl -L https://github.com/sirhcm/tinymesa/releases/download/$TINYMESA_TAG/libtinymesa_cpu-$MESA_TAG-linux-amd64.so -o $TINYMESA_SO + fi + + clang2py -k cdefstu \ + $MESA_SRC/src/compiler/nir/nir.h \ + $MESA_SRC/src/compiler/nir/nir_builder.h \ + $MESA_SRC/src/compiler/nir/nir_shader_compiler_options.h \ + $MESA_SRC/src/compiler/nir/nir_serialize.h \ + $MESA_SRC/gen/nir_intrinsics.h \ + $MESA_SRC/src/nouveau/headers/nv_device_info.h \ + $MESA_SRC/src/nouveau/compiler/nak.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_passmgr.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_misc.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_type.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_init.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_nir.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_struct.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_jit_types.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_flow.h \ + $MESA_SRC/src/gallium/auxiliary/gallivm/lp_bld_const.h \ + $MESA_SRC/src/compiler/glsl_types.h \ + $MESA_SRC/src/util/blob.h \ + $MESA_SRC/src/util/ralloc.h \ + --clang-args="-DHAVE_ENDIAN_H -DHAVE_STRUCT_TIMESPEC -DHAVE_PTHREAD -I$MESA_SRC/src -I$MESA_SRC/include -I$MESA_SRC/gen -I$MESA_SRC/src/compiler/nir -I$MESA_SRC/src/gallium/auxiliary -I$MESA_SRC/src/gallium/include -I$(llvm-config-20 --includedir)" \ + -l $TINYMESA_SO \ + -o $BASE/mesa.py + + LVP_NIR_OPTIONS=$(./extra/mesa/lvp_nir_options.sh $MESA_SRC) + + fixup $BASE/mesa.py + patch_dlopen $BASE/mesa.py tinymesa_cpu "(BASE:=os.getenv('MESA_PATH', f\"/usr{'/local/' if helpers.OSX else '/'}lib\"))+'/libtinymesa_cpu'+(EXT:='.dylib' if helpers.OSX else '.so')" "f'{BASE}/libtinymesa{EXT}'" "'/opt/homebrew/lib/libtinymesa_cpu.dylib'" "'/opt/homebrew/lib/libtinymesa.dylib'" + echo "lvp_nir_options = gzip.decompress(base64.b64decode('$LVP_NIR_OPTIONS'))" >> $BASE/mesa.py + sed -i "/in_dll/s/.*/try: &\nexcept (AttributeError, ValueError): pass/" $BASE/mesa.py + sed -i "s/import ctypes/import ctypes, ctypes.util, os, gzip, base64, subprocess, tinygrad.helpers as helpers/" $BASE/mesa.py + sed -i "s/ctypes.CDLL('.\+')/(dll := _try_dlopen_tinymesa_cpu())/" $BASE/mesa.py + echo "def __getattr__(nm): raise AttributeError('LLVMpipe requires tinymesa_cpu' if 'tinymesa_cpu' not in dll._name else f'attribute {nm} not found') if dll else FileNotFoundError(f'libtinymesa not found (MESA_PATH={BASE}). See https://github.com/sirhcm/tinymesa ($TINYMESA_TAG, $MESA_TAG)')" >> $BASE/mesa.py + sed -i "s/ctypes.glsl_base_type/glsl_base_type/" $BASE/mesa.py + # bitfield bug in clang2py + sed -i "s/('fp_fast_math', ctypes.c_bool, 9)/('fp_fast_math', ctypes.c_uint32, 9)/" $BASE/mesa.py + sed -i "s/('\(\w\+\)', pipe_shader_type, 8)/('\1', ctypes.c_ubyte)/" $BASE/mesa.py + sed -i "s/\([0-9]\+\)()/\1/" $BASE/mesa.py + sed -i '/struct_nir_builder._pack_ = 1 # source:False/d' "$BASE/mesa.py" + python3 -c "import tinygrad.runtime.autogen.mesa" +} + if [ "$1" == "opencl" ]; then generate_opencl elif [ "$1" == "hip" ]; then generate_hip elif [ "$1" == "comgr" ]; then generate_comgr @@ -452,12 +533,10 @@ elif [ "$1" == "kfd" ]; then generate_kfd elif [ "$1" == "nv" ]; then generate_nv elif [ "$1" == "amd" ]; then generate_amd elif [ "$1" == "am" ]; then generate_am -elif [ "$1" == "nvdrv" ]; then generate_nvdrv elif [ "$1" == "sqtt" ]; then generate_sqtt elif [ "$1" == "qcom" ]; then generate_qcom elif [ "$1" == "io_uring" ]; then generate_io_uring elif [ "$1" == "ib" ]; then generate_ib -elif [ "$1" == "libc" ]; then generate_libc elif [ "$1" == "llvm" ]; then generate_llvm elif [ "$1" == "kgsl" ]; then generate_kgsl elif [ "$1" == "adreno" ]; then generate_adreno @@ -465,6 +544,7 @@ elif [ "$1" == "pci" ]; then generate_pci elif [ "$1" == "vfio" ]; then generate_vfio elif [ "$1" == "webgpu" ]; then generate_webgpu elif [ "$1" == "libusb" ]; then generate_libusb -elif [ "$1" == "all" ]; then generate_opencl; generate_hip; generate_comgr; generate_cuda; generate_nvrtc; generate_hsa; generate_kfd; generate_nv; generate_amd; generate_io_uring; generate_libc; generate_am; generate_webgpu +elif [ "$1" == "mesa" ]; then generate_mesa +elif [ "$1" == "all" ]; then generate_opencl; generate_hip; generate_comgr; generate_cuda; generate_nvrtc; generate_hsa; generate_kfd; generate_nv; generate_amd; generate_io_uring; generate_am; generate_webgpu; generate_mesa else echo "usage: $0 " fi diff --git a/docs/abstractions2.py b/docs/abstractions2.py index cc23b27f6a..c1d13a86cf 100644 --- a/docs/abstractions2.py +++ b/docs/abstractions2.py @@ -42,7 +42,6 @@ import struct from tinygrad.dtype import dtypes from tinygrad.device import Buffer, Device from tinygrad.uop.ops import UOp, Ops -from tinygrad.shape.shapetracker import ShapeTracker # allocate some buffers + load in values out = Buffer(DEVICE, 1, dtypes.int32).allocate() @@ -51,13 +50,12 @@ b = Buffer(DEVICE, 1, dtypes.int32).allocate().copyin(memoryview(bytearray(struc # NOTE: a._buf is the same as the return from cpu.allocator.alloc # describe the computation +idx = UOp.const(dtypes.index, 0) buf_1 = UOp(Ops.DEFINE_GLOBAL, dtypes.int32.ptr(), (), 1) buf_2 = UOp(Ops.DEFINE_GLOBAL, dtypes.int32.ptr(), (), 2) -ld_1 = UOp(Ops.LOAD, dtypes.int32, (buf_1.view(ShapeTracker.from_shape((1,))),)) -ld_2 = UOp(Ops.LOAD, dtypes.int32, (buf_2.view(ShapeTracker.from_shape((1,))),)) -alu = ld_1 + ld_2 +alu = buf_1.index(idx) + buf_2.index(idx) output_buf = UOp(Ops.DEFINE_GLOBAL, dtypes.int32.ptr(), (), 0) -st_0 = UOp(Ops.STORE, dtypes.void, (output_buf.view(ShapeTracker.from_shape((1,))), alu)) +st_0 = UOp(Ops.STORE, dtypes.void, (output_buf.index(idx), alu)) s = UOp(Ops.SINK, dtypes.void, (st_0,)) # convert the computation to a "linearized" format (print the format) @@ -80,8 +78,6 @@ print("******** third, the UOp ***********") from tinygrad.engine.realize import run_schedule from tinygrad.engine.schedule import create_schedule_with_vars -from tinygrad.helpers import RANGEIFY -from tinygrad.schedule.kernelize import get_kernelize_map from tinygrad.schedule.rangeify import get_rangeify_map # allocate some values + load in values @@ -95,7 +91,7 @@ out = a + b s = UOp(Ops.SINK, dtypes.void, (out,)) # group the computation into kernels -becomes_map = get_rangeify_map(s) if RANGEIFY else get_kernelize_map(s) +becomes_map = get_rangeify_map(s) # the compute maps to an assign assign = becomes_map[a+b].base diff --git a/docs/developer/kernelize.md b/docs/developer/kernelize.md deleted file mode 100644 index b38db222b4..0000000000 --- a/docs/developer/kernelize.md +++ /dev/null @@ -1,109 +0,0 @@ -# Kernel Creation - -Tinygrad lazily builds up a graph of Tensor operations. The Tensor graph includes a mix of: - -- Buffer and Assignment Ops: `BUFFER`, `BUFFER_VIEW`, `COPY`, `ASSIGN` -- Movement Ops: `RESHAPE`, `EXPAND`, `PERMUTE`, `PAD`, `SHRINK`, `FLIP` -- Compute Ops: `ADD`, `MUL`, `REDUCE_AXIS`, ... - -`Tensor.kernelize` creates the kernels and buffers needed to realize the output Tensor(s). - -## Kernelize flow - -Let's see how a multiply add Tensor graph becomes a fused elementwise kernel. - -```py -# initialize 3 input buffers on the device -a = Tensor([1]).realize() -b = Tensor([2]).realize() -c = Tensor([3]).realize() - -# create the Tensor graph -mul = a*b -out = mul+c - -print(mul) # , None)> on METAL with grad None> -print(out) # , None)> on METAL with grad None> - -out.kernelize() - -print(mul) # , None)> on METAL with grad None> -print(out) # , None)> on METAL with grad None> -``` - -The multiply Tensor stays the same because it is fused. The output Tensor's UOp becomes a new ASSIGN UOp: - -```py -print(out.uop) -``` - -The first source is the output BUFFER: - -``` -UOp(Ops.BUFFER, dtypes.int, arg=1, src=( - UOp(Ops.DEVICE, dtypes.void, arg='METAL', src=()), - UOp(Ops.UNIQUE, dtypes.void, arg=6, src=()),)) -``` - -And the second source is the KERNEL and its 4 buffer edges (output_buffer, a, b, c): - -``` -UOp(Ops.KERNEL, dtypes.void, arg=,) (__add__, __mul__)>, src=( - UOp(Ops.BUFFER, dtypes.int, arg=1, src=( - x1:=UOp(Ops.DEVICE, dtypes.void, arg='METAL', src=()), - UOp(Ops.UNIQUE, dtypes.void, arg=6, src=()),)), - UOp(Ops.BUFFER, dtypes.int, arg=1, src=( - x1, - UOp(Ops.UNIQUE, dtypes.void, arg=1, src=()),)), - UOp(Ops.BUFFER, dtypes.int, arg=1, src=( - x1, - UOp(Ops.UNIQUE, dtypes.void, arg=3, src=()),)), - UOp(Ops.BUFFER, dtypes.int, arg=1, src=( - x1, - UOp(Ops.UNIQUE, dtypes.void, arg=5, src=()),)),)) -``` - -KERNEL describes the compute AST, metadata and memory dependencies. - -BUFFER holds a reference to the device memory where the output will be stored. - -Once a Tensor is kernelized, all children will LOAD its BUFFER, instead of fusing it: - -```py -child = out+2 -child.kernelize() -print(child.uop.src[1].arg.ast) -``` - -``` -UOp(Ops.SINK, dtypes.void, arg=None, src=( - UOp(Ops.STORE, dtypes.void, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(1), arg=0, src=()), - x2:=UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(1,), strides=(0,), offset=0, mask=None, contiguous=True),)), src=()), - UOp(Ops.ADD, dtypes.int, arg=None, src=( - UOp(Ops.LOAD, dtypes.int, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(1), arg=1, src=()), - x2,)), - UOp(Ops.CONST, dtypes.int, arg=2, src=( - x2,)),)),)),)) -``` - -`Tensor.realize` will execute the kernels and write outputs to memory: - -```py -Tensor.realize(out) -print(out) # , )> on METAL with grad None> -print(out.item()) # 5 -``` - -
- -**Summary** - -- The large Tensor graph is built from a mix of data, compute and movement Ops. - -- `Tensor.kernelize` splits the Tensor graph into data (BUFFER), compute (KERNEL) and links dependencies with ASSIGN. - -- `Tensor.realize` executes KERNELs on device and replaces the Tensor graph with just a BUFFER. - -- Kernelize can be called multiple times on a Tensor. This allows for incrementally building the kernel fusion layout of a large Tensor graph, without having to call `realize` or `schedule`. diff --git a/docs/developer/layout.md b/docs/developer/layout.md index ab7701fbde..bd56a169f5 100644 --- a/docs/developer/layout.md +++ b/docs/developer/layout.md @@ -10,7 +10,7 @@ Directories are listed in order of how they are processed. Group UOps into kernels. -::: tinygrad.schedule.kernelize.get_kernelize_map +::: tinygrad.schedule.rangeify.get_rangeify_map options: members: false show_labels: false diff --git a/docs/env_vars.md b/docs/env_vars.md index f8844ba70b..0f059aec66 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -41,7 +41,7 @@ BEAM | [#] | number of beams in kernel beam search DEFAULT_FLOAT | [HALF, ...]| specify the default float dtype (FLOAT32, HALF, BFLOAT16, FLOAT64, ...), default to FLOAT32 IMAGE | [1-2] | enable 2d specific optimizations FLOAT16 | [1] | use float16 for images instead of float32 -VISIBLE_DEVICES | [list[int]]| restricts the NV/AMD devices that are available. The format is a comma-separated list of identifiers (indexing starts with 0). +HCQ_VISIBLE_DEVICES | [list[int]]| restricts the HCQ devices that are available. The format is a comma-separated list of identifiers (indexing starts with 0). JIT | [0-2] | 0=disabled, 1=[jit enabled](quickstart.md#jit) (default), 2=jit enabled, but graphs are disabled VIZ | [1] | 0=disabled, 1=[viz enabled](https://github.com/tinygrad/tinygrad/tree/master/tinygrad/viz) ALLOW_TF32 | [1] | enable TensorFloat-32 tensor cores on Ampere or newer GPUs. diff --git a/examples/beautiful_cifar.py b/examples/beautiful_cifar.py index cea8262f17..5bc2fc87c3 100644 --- a/examples/beautiful_cifar.py +++ b/examples/beautiful_cifar.py @@ -10,7 +10,7 @@ GPUS = [f'{Device.DEFAULT}:{i}' for i in range(getenv("GPUS", 1))] # override tinygrad defaults dtypes.default_float = dtypes.half -Context(FUSE_ARANGE=1, FUSE_OPTIM=1).__enter__() +Context(FUSE_OPTIM=1).__enter__() # from https://github.com/tysam-code/hlb-CIFAR10/blob/main/main.py batchsize = getenv("BS", 1024) diff --git a/examples/benchmark_onnx.py b/examples/benchmark_onnx.py index ad7c1ebb18..27568117f3 100644 --- a/examples/benchmark_onnx.py +++ b/examples/benchmark_onnx.py @@ -1,6 +1,6 @@ import sys, time from tinygrad import TinyJit, GlobalCounters, fetch, getenv -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner from extra.onnx_helpers import get_example_inputs, validate def load_onnx_model(onnx_file): diff --git a/examples/compile_tensorflow.py b/examples/compile_tensorflow.py index 33434c831c..1962661818 100644 --- a/examples/compile_tensorflow.py +++ b/examples/compile_tensorflow.py @@ -8,7 +8,7 @@ import numpy as np import subprocess import tensorflow as tf import tf2onnx -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner from tinygrad.tensor import Tensor from tinygrad.helpers import to_mv from extra.export_model import export_model_clang, compile_net, jit_model diff --git a/examples/gpt2.py b/examples/gpt2.py index 7b508c1b3a..5c4dd28f2b 100644 --- a/examples/gpt2.py +++ b/examples/gpt2.py @@ -232,7 +232,7 @@ if __name__ == "__main__": gpt2 = GPT2.build_gguf(args.model_size) if args.model_size.startswith("gpt2_gguf_") else GPT2.build(args.model_size) if args.benchmark != -1: - gpt2.model(Tensor.rand(args.batch_size, args.benchmark), Variable("a", 0, MAX_CONTEXT).bind(0)).realize() + gpt2.model(Tensor.randint(args.batch_size, args.benchmark), Variable("a", 0, MAX_CONTEXT).bind(0)).realize() else: texts = gpt2.generate(args.prompt, args.count, args.temperature, timing=args.timing, batch_size=args.batch_size) if not args.noshow: diff --git a/examples/hlb_cifar10.py b/examples/hlb_cifar10.py index 27fecf02d8..35ca8d352a 100644 --- a/examples/hlb_cifar10.py +++ b/examples/hlb_cifar10.py @@ -145,7 +145,6 @@ hyp = { }, } -@Context(FUSE_ARANGE=getenv("FUSE_ARANGE", 1)) def train_cifar(): def set_seed(seed): diff --git a/examples/llama3.py b/examples/llama3.py index d7c7f2c921..54aa8eafea 100644 --- a/examples/llama3.py +++ b/examples/llama3.py @@ -145,6 +145,41 @@ def NF4Linear(block_size): return new_state_dict return _NF4Linear +def quantize_to_fp8(x: Tensor, dtype=dtypes.fp8e4m3): + fp8_min = -448.0 if dtype == dtypes.fp8e4m3 else -57344.0 + fp8_max = 448.0 if dtype == dtypes.fp8e4m3 else 57344.0 + scale = fp8_max / x.abs().max() + x_scl_sat = (x * scale).clamp(fp8_min, fp8_max) + return x_scl_sat.cast(dtype), scale.float().reciprocal() + +class FP8Linear: + def __init__(self, in_features, out_features, bias=True): + self.weight = Tensor.empty(out_features, in_features, dtype=dtypes.fp8e4m3) + self.bias = Tensor.empty(out_features, dtype=dtypes.float16) if bias else None + self.weight_scale = Tensor.empty((), dtype=dtypes.float16) + + def __call__(self, x:Tensor): + y = x.dot(self.weight.T.cast(dtypes.float32)) * self.weight_scale + if self.bias is not None: y = y + self.bias.cast(y.dtype) + return y.cast(x.dtype) + + @staticmethod + def quantize(tensors, device, scale_dtype=dtypes.float16, quantize_embeds=False): + assert not quantize_embeds + new_tensors = {} + for name,v in tensors.items(): + if "feed_forward" in name or "attention.w" in name: + assert "weight" in name, name + fp8_weight, scale = quantize_to_fp8(v) + new_tensors[name] = fp8_weight + new_tensors[name.replace('weight', 'weight_scale')] = scale.cast(scale_dtype) + if isinstance(device, tuple): + new_tensors[name].shard_(device, axis=-1) + new_tensors[name.replace('weight', 'weight_scale')].shard_(device, axis=None) + else: + new_tensors[name] = v + return new_tensors + MODEL_PARAMS = { "1B": { "args": {"dim": 2048, "n_heads": 32, "n_kv_heads": 8, "n_layers": 16, "norm_eps": 1e-5, "rope_theta": 500000, "vocab_size": 128256, "hidden_dim": 8192}, @@ -167,6 +202,7 @@ def build_transformer(model_path: Path, model_size="8B", quantize=None, scale_dt # build model if quantize == "int8": linear, embedding, quantize_embeds = Int8Linear, Int8Embedding, True elif quantize == "nf4": linear, embedding, quantize_embeds = NF4Linear(64), nn.Embedding, False + elif quantize == "fp8": linear, embedding, quantize_embeds = FP8Linear, nn.Embedding, False else: linear, embedding, quantize_embeds = nn.Linear, nn.Embedding, False model = Transformer(**MODEL_PARAMS[model_size]["args"], linear=linear, embedding=embedding, max_context=max_context, jit=True) @@ -242,7 +278,7 @@ if __name__ == "__main__": parser.add_argument("--model", type=Path, help="Model path") parser.add_argument("--size", choices=["1B", "8B", "70B", "405B"], default="1B", help="Model size") parser.add_argument("--shard", type=int, default=1, help="Shard the model across multiple devices") - parser.add_argument("--quantize", choices=["int8", "nf4", "float16"], help="Quantization method") + parser.add_argument("--quantize", choices=["int8", "nf4", "float16", "fp8"], help="Quantization method") parser.add_argument("--no_api", action="store_true", help="Disable the api and run a cli test interface") parser.add_argument("--host", type=str, default="0.0.0.0", help="Web server bind address") parser.add_argument("--port", type=int, default=7776, help="Web server port") diff --git a/examples/mlperf/model_train.py b/examples/mlperf/model_train.py index 4b333918e3..a8189c4ee5 100644 --- a/examples/mlperf/model_train.py +++ b/examples/mlperf/model_train.py @@ -3,7 +3,7 @@ from pathlib import Path import multiprocessing from tinygrad import Device, GlobalCounters, Tensor, TinyJit, dtypes -from tinygrad.helpers import getenv, BEAM, WINO, round_up, diskcache_clear, FUSE_CONV_BW, Profiling +from tinygrad.helpers import getenv, BEAM, WINO, round_up, diskcache_clear, Profiling from tinygrad.nn.state import get_parameters, get_state_dict, load_state_dict, safe_load, safe_save from tinygrad.nn.optim import LAMB, LARS, SGD, OptimizerGroup, Adam, AdamW @@ -707,7 +707,7 @@ def train_unet3d(): ```BASEDIR= ./examples/mlperf/scripts/setup_kits19_dataset.sh``` 2) To start training the model, run the following: - ```time PYTHONPATH=. WANDB=1 TRAIN_BEAM=3 FUSE_CONV_BW=1 GPUS=6 BS=6 MODEL=unet3d python3 examples/mlperf/model_train.py``` + ```time PYTHONPATH=. WANDB=1 TRAIN_BEAM=3 GPUS=6 BS=6 MODEL=unet3d python3 examples/mlperf/model_train.py``` """ from examples.mlperf.losses import dice_ce_loss from examples.mlperf.metrics import dice_score @@ -749,7 +749,6 @@ def train_unet3d(): "train_beam": TRAIN_BEAM, "eval_beam": EVAL_BEAM, "wino": WINO.value, - "fuse_conv_bw": FUSE_CONV_BW.value, "gpus": GPUS, "default_float": dtypes.default_float.name } @@ -1189,7 +1188,9 @@ def train_bert(): if MLLOGGER and RUNMLPERF: MLLOGGER.start(key=mllog_constants.EVAL_START, value=None, metadata={"epoch_num": i*GBS, "step_num": i}) if getenv("RESET_STEP"): train_step_bert.reset() - elif getenv("FREE_INTERMEDIATE", 1) and train_step_bert.captured is not None: train_step_bert.captured.free_intermediates() + elif getenv("FREE_INTERMEDIATE", 0) and train_step_bert.captured is not None: + # TODO: FREE_INTERMEDIATE nan'ed after jit step 2 + train_step_bert.captured.free_intermediates() eval_lm_losses = [] eval_clsf_losses = [] eval_lm_accs = [] @@ -1223,7 +1224,7 @@ def train_bert(): return if getenv("RESET_STEP"): eval_step_bert.reset() - elif getenv("FREE_INTERMEDIATE", 1) and eval_step_bert.captured is not None: eval_step_bert.captured.free_intermediates() + elif getenv("FREE_INTERMEDIATE", 0) and eval_step_bert.captured is not None: eval_step_bert.captured.free_intermediates() del eval_data avg_lm_loss = sum(eval_lm_losses) / len(eval_lm_losses) @@ -1309,7 +1310,7 @@ def train_llama3(): EVAL_BS = config["EVAL_BS"] = getenv("EVAL_BS", 16) EVAL_TARGET = config["EVAL_TARGET"] = getenv("EVAL_TARGET", 5.6) - # LR=1e-4 TRAIN_ON_VAL=1 DEFAULT_FLOAT=bfloat16 FUSE_ARANGE=1 JITBEAM=2 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B WARMUP_STEPS=36 DECAY_STEPS=360 SEQLEN=512 PYTHONPATH=. AMD=1 AMD_LLVM=0 MODEL=llama3 python3 examples/mlperf/model_train.py + # LR=1e-4 TRAIN_ON_VAL=1 DEFAULT_FLOAT=bfloat16 JITBEAM=2 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B WARMUP_STEPS=36 DECAY_STEPS=360 SEQLEN=512 PYTHONPATH=. AMD=1 AMD_LLVM=0 MODEL=llama3 python3 examples/mlperf/model_train.py # trains to 7 opt_adamw_beta_1 = 0.9 diff --git a/examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/stable_diffusion/implementations/tinybox_8xMI300X/dev_run.sh b/examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/stable_diffusion/implementations/tinybox_8xMI300X/dev_run.sh new file mode 100755 index 0000000000..5e35ff65a4 --- /dev/null +++ b/examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/stable_diffusion/implementations/tinybox_8xMI300X/dev_run.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +DATETIME=${2:-$(date "+%m%d%H%M")} +LOGFILE="${HOME}/logs/sd_mi300x_${DATETIME}.log" +# UNET_CKPTDIR must be set: training saves checkpoints to this path, then a separate eval process scans this path to know which checkpoints to eval +export UNET_CKPTDIR="${HOME}/stable_diffusion/training_checkpoints/${DATETIME}" +mkdir -p "${HOME}/logs" "$UNET_CKPTDIR" + +# run this script in isolation when using the --bg flag +if [[ "${1:-}" == "--bg" ]]; then + echo "logging output to $LOGFILE" + echo "saving UNet checkpoints to $UNET_CKPTDIR" + script_path="$(readlink -f "${BASH_SOURCE[0]}")" + nohup bash "$script_path" run "$DATETIME" >"$LOGFILE" 2>&1 & disown $! + exit 0 +fi + +# venv management +if [[ -d .venv-sd-mlperf ]]; then + . .venv-sd-mlperf/bin/activate +else + python3 -m venv .venv-sd-mlperf && . .venv-sd-mlperf/bin/activate + pip install --index-url https://download.pytorch.org/whl/cpu torch && pip install tqdm numpy ftfy regex pillow scipy wandb webdataset +fi +pip list +apt list --installed | grep amdgpu +rocm-smi --version +modinfo amdgpu | grep version + +export BEAM=2 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 IGNORE_JIT_FIRST_BEAM=1 HCQDEV_WAIT_TIMEOUT_MS=300000 +export AMD_LLVM=0 # bf16 seems to require this +export DATADIR="/raid/datasets/stable_diffusion" +export CKPTDIR="/raid/weights/stable_diffusion" +export EVAL_CKPT_DIR=$UNET_CKPTDIR +export MODEL="stable_diffusion" PYTHONPATH="." +export GPUS=8 BS=304 +export CONTEXT_BS=816 DENOISE_BS=600 DECODE_BS=384 INCEPTION_BS=560 CLIP_BS=240 +export WANDB=1 +export PARALLEL=4 +export PYTHONUNBUFFERED=1 +sudo rocm-smi -d 0 1 2 3 4 5 6 7 --setperfdeterminism 1500 || exit 1 + +# Retry BEAM search if script fails before BEAM COMPLETE is printed, but don't retry after that +run_retry(){ local try=0 max=5 code tmp py pgid kids + while :; do + tmp=$(mktemp) + setsid bash -c 'exec env "$@"' _ "$@" > >(tee -a "$LOGFILE" | tee "$tmp") 2>&1 & + py=$!; pgid=$(ps -o pgid= -p "$py" | tr -d ' ') + wait "$py"; code=$? + [[ -n "$pgid" ]] && { kill -TERM -"$pgid" 2>/dev/null; sleep 1; kill -KILL -"$pgid" 2>/dev/null; } + kids=$(pgrep -P "$py" || true) + while [[ -n "$kids" ]]; do + kill -TERM $kids 2>/dev/null; sleep 0.5 + kids=$(for k in $kids; do pgrep -P "$k" || true; done) + done + grep -q 'BEAM COMPLETE' "$tmp" && { rm -f "$tmp"; return 1; } + rm -f "$tmp" + ((code==0)) && return 0 + ((try>=max)) && return 2 + ((try++)); sleep 90; echo "try = ${try}" + done +} + +# Power limiting to 400W is only needed if GPUs fall out of sync (causing 2.2x increased train time) at higher power, which has been observed at 450W +sudo rocm-smi -d 0 1 2 3 4 5 6 7 --setpoweroverdrive 750 && \ +run_retry TOTAL_CKPTS=7 python3 examples/mlperf/model_train.py; (( $? == 2 )) && { echo "training failed before BEAM completion"; exit 2; } +sleep 90 + +run_retry EVAL_SAMPLES=600 python3 examples/mlperf/model_eval.py; (( $? == 2 )) && { echo "eval failed before BEAM completion"; exit 2; } +# Checkpoints will be evaluated in reverse chronological order, even if above training crashed early +# STOP_IF_CONVERGED=1: Stop the eval after the first time convergence is detected; no more checkpoints will be evaluated after that. +STOP_IF_CONVERGED=1 python3 examples/mlperf/model_eval.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_1xMI300X/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_1xMI300X/dev_beam.sh new file mode 100755 index 0000000000..68e5fdfcde --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_1xMI300X/dev_beam.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" GPUS=1 BS=128 EVAL_BS=128 + +export IGNORE_OOB=1 + +export BEAM=3 BEAM_UOPS_MAX=4000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +# export BEAM_LOG_SURPASS_MAX=1 +# export BASEDIR="/raid/datasets/wiki" + +export RESET_STEP=1 +export BENCHMARK=10 BERT_LAYERS=2 DEBUG=2 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/README.md b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/README.md new file mode 100644 index 0000000000..844b90f949 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/README.md @@ -0,0 +1,69 @@ +# 1. Problem + +This problem uses BERT for NLP. + +## Requirements + +Install tinygrad and mlperf-logging (uncomment mlperf from setup.py) from branch mlperf_training_v5.0. +``` +git clone https://github.com/tinygrad/tinygrad.git +python3 -m pip install -e ".[mlperf]" +``` +Also install gdown (for dataset), numpy, tqdm and tensorflow. +``` +pip install gdown numpy tqdm tensorflow +``` + +### tinybox_green +Install the p2p driver per [README](https://github.com/tinygrad/open-gpu-kernel-modules/blob/550.54.15-p2p/README.md) +This is the default on production tinybox green. + +# 2. Directions + +## Steps to download and verify data + +### 1. Download raw data + +``` +BASEDIR="/raid/datasets/wiki" WIKI_TRAIN=1 VERIFY_CHECKSUM=1 python3 extra/datasets/wikipedia_download.py +``` + +### 2. Preprocess train and validation data + +Note: The number of threads used for preprocessing is limited by available memory. With 128GB of RAM, a maximum of 16 threads is recommended. + +#### Training: +``` +BASEDIR="/raid/datasets/wiki" NUM_WORKERS=16 python3 extra/datasets/wikipedia.py pre-train all +``` + +Generating a specific topic (Between 0 and 499) +``` +BASEDIR="/raid/datasets/wiki" python3 extra/datasets/wikipedia.py pre-train 42 +``` + +#### Validation: +``` +BASEDIR="/raid/datasets/wiki" python3 extra/datasets/wikipedia.py pre-eval +``` +## Running + +### tinybox_green + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_green/run_and_time.sh +``` + +### tinybox_red + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_red/run_and_time.sh +``` +### tinybox_8xMI300X + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/run_and_time.sh +``` \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/dev_beam.sh new file mode 100755 index 0000000000..278eff316d --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/dev_beam.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024 +export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0 +export BASEDIR="/raid/datasets/wiki" + +export BENCHMARK=10 BERT_LAYERS=2 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/dev_run.sh new file mode 100755 index 0000000000..a6a42a6de0 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/dev_run.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024 + +# similar to https://github.com/mlcommons/training_results_v3.1/blob/d06288b2bd675a9d88e0e6181f5bb5626b71ec19/Quanta_Cloud_Technology/results/D54U-3U/bert/result_1.txt#L54 +export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1 +export TRAIN_STEPS=3900 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0 +export BASEDIR="/raid/datasets/wiki" + +export WANDB=1 PARALLEL=0 + +RUNMLPERF=1 python3 examples/mlperf/model_train.py \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/run_and_time.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/run_and_time.sh new file mode 100755 index 0000000000..1dbef0e48e --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/run_and_time.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e # Exit on any error +set -o pipefail # Make pipeline fail if any command fails + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export SUBMISSION_PLATFORM="tinybox_8xMI300X" +export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024 + +# similar to https://github.com/mlcommons/training_results_v3.1/blob/d06288b2bd675a9d88e0e6181f5bb5626b71ec19/Quanta_Cloud_Technology/results/D54U-3U/bert/result_1.txt#L54 +export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1 +export TRAIN_STEPS=3900 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0 +export BASEDIR="/raid/datasets/wiki" + +# pip install -e ".[mlperf]" +export LOGMLPERF=1 + +export SEED=$RANDOM +DATETIME=$(date "+%m%d%H%M") +LOGFILE="bert_8xMI300x_${DATETIME}_${SEED}.log" + +BENCHMARK=10 INITMLPERF=1 BERT_LAYERS=2 python3 examples/mlperf/model_train.py | tee $LOGFILE + +# run +PARALLEL=0 RUNMLPERF=1 python3 examples/mlperf/model_train.py | tee -a $LOGFILE diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/README.md b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/README.md new file mode 100644 index 0000000000..844b90f949 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/README.md @@ -0,0 +1,69 @@ +# 1. Problem + +This problem uses BERT for NLP. + +## Requirements + +Install tinygrad and mlperf-logging (uncomment mlperf from setup.py) from branch mlperf_training_v5.0. +``` +git clone https://github.com/tinygrad/tinygrad.git +python3 -m pip install -e ".[mlperf]" +``` +Also install gdown (for dataset), numpy, tqdm and tensorflow. +``` +pip install gdown numpy tqdm tensorflow +``` + +### tinybox_green +Install the p2p driver per [README](https://github.com/tinygrad/open-gpu-kernel-modules/blob/550.54.15-p2p/README.md) +This is the default on production tinybox green. + +# 2. Directions + +## Steps to download and verify data + +### 1. Download raw data + +``` +BASEDIR="/raid/datasets/wiki" WIKI_TRAIN=1 VERIFY_CHECKSUM=1 python3 extra/datasets/wikipedia_download.py +``` + +### 2. Preprocess train and validation data + +Note: The number of threads used for preprocessing is limited by available memory. With 128GB of RAM, a maximum of 16 threads is recommended. + +#### Training: +``` +BASEDIR="/raid/datasets/wiki" NUM_WORKERS=16 python3 extra/datasets/wikipedia.py pre-train all +``` + +Generating a specific topic (Between 0 and 499) +``` +BASEDIR="/raid/datasets/wiki" python3 extra/datasets/wikipedia.py pre-train 42 +``` + +#### Validation: +``` +BASEDIR="/raid/datasets/wiki" python3 extra/datasets/wikipedia.py pre-eval +``` +## Running + +### tinybox_green + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_green/run_and_time.sh +``` + +### tinybox_red + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_red/run_and_time.sh +``` +### tinybox_8xMI300X + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/run_and_time.sh +``` \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/dev_beam.sh new file mode 100755 index 0000000000..a22eb3e987 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/dev_beam.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +export PYTHONPATH="." NV=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +export BEAM_LOG_SURPASS_MAX=1 +export BASEDIR="/raid/datasets/wiki" + +export BENCHMARK=10 BERT_LAYERS=2 DEBUG=2 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/dev_run.sh new file mode 100755 index 0000000000..c906579887 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/dev_run.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +export PYTHONPATH="." NV=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +export BASEDIR="/raid/datasets/wiki" + +export WANDB=1 PARALLEL=0 + +RUNMLPERF=1 python3 examples/mlperf/model_train.py \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/run_and_time.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/run_and_time.sh new file mode 100755 index 0000000000..4b81469316 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_green/run_and_time.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e # Exit on any error +set -o pipefail # Make pipeline fail if any command fails + +export PYTHONPATH="." NV=1 +export MODEL="bert" +export SUBMISSION_PLATFORM="tinybox_green" +export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +export BASEDIR="/raid/datasets/wiki" + +# pip install -e ".[mlperf]" +export LOGMLPERF=1 + +export SEED=$RANDOM +DATETIME=$(date "+%m%d%H%M") +LOGFILE="bert_green_${DATETIME}_${SEED}.log" + +# init +BENCHMARK=10 INITMLPERF=1 BERT_LAYERS=2 python3 examples/mlperf/model_train.py | tee $LOGFILE + +# run +PARALLEL=0 RUNMLPERF=1 python3 examples/mlperf/model_train.py | tee -a $LOGFILE diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/README.md b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/README.md new file mode 100644 index 0000000000..844b90f949 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/README.md @@ -0,0 +1,69 @@ +# 1. Problem + +This problem uses BERT for NLP. + +## Requirements + +Install tinygrad and mlperf-logging (uncomment mlperf from setup.py) from branch mlperf_training_v5.0. +``` +git clone https://github.com/tinygrad/tinygrad.git +python3 -m pip install -e ".[mlperf]" +``` +Also install gdown (for dataset), numpy, tqdm and tensorflow. +``` +pip install gdown numpy tqdm tensorflow +``` + +### tinybox_green +Install the p2p driver per [README](https://github.com/tinygrad/open-gpu-kernel-modules/blob/550.54.15-p2p/README.md) +This is the default on production tinybox green. + +# 2. Directions + +## Steps to download and verify data + +### 1. Download raw data + +``` +BASEDIR="/raid/datasets/wiki" WIKI_TRAIN=1 VERIFY_CHECKSUM=1 python3 extra/datasets/wikipedia_download.py +``` + +### 2. Preprocess train and validation data + +Note: The number of threads used for preprocessing is limited by available memory. With 128GB of RAM, a maximum of 16 threads is recommended. + +#### Training: +``` +BASEDIR="/raid/datasets/wiki" NUM_WORKERS=16 python3 extra/datasets/wikipedia.py pre-train all +``` + +Generating a specific topic (Between 0 and 499) +``` +BASEDIR="/raid/datasets/wiki" python3 extra/datasets/wikipedia.py pre-train 42 +``` + +#### Validation: +``` +BASEDIR="/raid/datasets/wiki" python3 extra/datasets/wikipedia.py pre-eval +``` +## Running + +### tinybox_green + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_green/run_and_time.sh +``` + +### tinybox_red + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_red/run_and_time.sh +``` +### tinybox_8xMI300X + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/bert/implementations/tinybox_8xMI300X/run_and_time.sh +``` \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/dev_beam.sh new file mode 100755 index 0000000000..d21bf8d9e8 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/dev_beam.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +export BEAM_LOG_SURPASS_MAX=1 +export BASEDIR="/raid/datasets/wiki" + +export RESET_STEP=1 +export BENCHMARK=10 BERT_LAYERS=2 DEBUG=2 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/dev_run.sh new file mode 100755 index 0000000000..3010d3cc4a --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/dev_run.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +export BASEDIR="/raid/datasets/wiki" + +export WANDB=1 PARALLEL=0 + +RUNMLPERF=1 python3 examples/mlperf/model_train.py \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/run_and_time.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/run_and_time.sh new file mode 100755 index 0000000000..c3025bdcfa --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/bert/implementations/tinybox_red/run_and_time.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e # Exit on any error +set -o pipefail # Make pipeline fail if any command fails + +export PYTHONPATH="." AMD=1 +export MODEL="bert" +export SUBMISSION_PLATFORM="tinybox_red" +export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export IGNORE_OOB=1 +export REWRITE_STACK_LIMIT=500000 + +export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 +export IGNORE_JIT_FIRST_BEAM=1 +export BASEDIR="/raid/datasets/wiki" + +# pip install -e ".[mlperf]" +export LOGMLPERF=${LOGMLPERF:-1} + +export SEED=$RANDOM +DATETIME=$(date "+%m%d%H%M") +LOGFILE="bert_red_${DATETIME}_${SEED}.log" + +export HCQDEV_WAIT_TIMEOUT_MS=100000 # prevents hang? + +# init +sleep 5 && sudo rmmod amdgpu || true +BENCHMARK=10 INITMLPERF=1 BERT_LAYERS=2 python3 examples/mlperf/model_train.py | tee $LOGFILE + +# run +PARALLEL=0 RUNMLPERF=1 python3 examples/mlperf/model_train.py | tee -a $LOGFILE diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/README.md b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/README.md new file mode 100644 index 0000000000..d380cec5b5 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/README.md @@ -0,0 +1,50 @@ +# 1. Problem + +This problem uses the ResNet-50 CNN to do image classification. + +## Requirements + +Install tinygrad and mlperf-logging from master. +``` +git clone https://github.com/tinygrad/tinygrad.git +python3 -m pip install -e ".[mlperf]" +``` + +### tinybox_green +Install the p2p driver per [README](https://github.com/tinygrad/open-gpu-kernel-modules/blob/550.54.15-p2p/README.md) +This is the default on production tinybox green. + +### tinybox_red +Disable cwsr +This is the default on production tinybox red. +``` +sudo vi /etc/modprobe.d/amdgpu.conf +cat < /etc/modprobe.d/amdgpu.conf +options amdgpu cwsr_enable=0 +EOF +sudo update-initramfs -u +sudo reboot + +# validate +sudo cat /sys/module/amdgpu/parameters/cwsr_enable #= 0 +``` + +# 2. Directions + +## Steps to download and verify data + +``` +IMGNET_TRAIN=1 python3 extra/datasets/imagenet_download.py +``` + +## Steps for one time setup + +### tinybox_red +``` +examples/mlperf/training_submission_v4.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/setup.sh +``` + +## Steps to run benchmark +``` +examples/mlperf/training_submission_v4.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/run_and_time.sh +``` diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/dev_beam.sh new file mode 100755 index 0000000000..2319da3fdc --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/dev_beam.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +export PYTHONPATH="." NV=1 +export MODEL="resnet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=1536 EVAL_BS=192 + +export RESET_STEP=0 + +export TRAIN_BEAM=4 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=10 BEAM_PADTO=0 + +export BENCHMARK=10 DEBUG=2 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/dev_run.sh new file mode 100755 index 0000000000..ebe927c373 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/dev_run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +export PYTHONPATH="." NV=1 +export MODEL="resnet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=1536 EVAL_BS=192 + +export RESET_STEP=0 + +export TRAIN_BEAM=4 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=10 BEAM_PADTO=0 + +export EVAL_START_EPOCH=3 EVAL_FREQ=4 + +export WANDB=1 PARALLEL=0 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/run_and_time.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/run_and_time.sh new file mode 100755 index 0000000000..9c7193288a --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_green/run_and_time.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e # Exit on any error +set -o pipefail # Make pipeline fail if any command fails + +export PYTHONPATH="." NV=1 +export MODEL="resnet" +export SUBMISSION_PLATFORM="tinybox_green" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=1536 EVAL_BS=192 + +export RESET_STEP=0 + +export TRAIN_BEAM=4 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=10 BEAM_PADTO=0 + +# pip install -e ".[mlperf]" +export LOGMLPERF=${LOGMLPERF:-1} + +export SEED=$RANDOM +DATETIME=$(date "+%m%d%H%M") +LOGFILE="resnet_green_${DATETIME}_${SEED}.log" + +# init +BENCHMARK=10 INITMLPERF=1 python3 examples/mlperf/model_train.py | tee $LOGFILE + +# run +PARALLEL=0 RUNMLPERF=1 EVAL_START_EPOCH=3 EVAL_FREQ=4 python3 examples/mlperf/model_train.py | tee -a $LOGFILE diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/README.md b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/README.md new file mode 100644 index 0000000000..d380cec5b5 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/README.md @@ -0,0 +1,50 @@ +# 1. Problem + +This problem uses the ResNet-50 CNN to do image classification. + +## Requirements + +Install tinygrad and mlperf-logging from master. +``` +git clone https://github.com/tinygrad/tinygrad.git +python3 -m pip install -e ".[mlperf]" +``` + +### tinybox_green +Install the p2p driver per [README](https://github.com/tinygrad/open-gpu-kernel-modules/blob/550.54.15-p2p/README.md) +This is the default on production tinybox green. + +### tinybox_red +Disable cwsr +This is the default on production tinybox red. +``` +sudo vi /etc/modprobe.d/amdgpu.conf +cat < /etc/modprobe.d/amdgpu.conf +options amdgpu cwsr_enable=0 +EOF +sudo update-initramfs -u +sudo reboot + +# validate +sudo cat /sys/module/amdgpu/parameters/cwsr_enable #= 0 +``` + +# 2. Directions + +## Steps to download and verify data + +``` +IMGNET_TRAIN=1 python3 extra/datasets/imagenet_download.py +``` + +## Steps for one time setup + +### tinybox_red +``` +examples/mlperf/training_submission_v4.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/setup.sh +``` + +## Steps to run benchmark +``` +examples/mlperf/training_submission_v4.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/run_and_time.sh +``` diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/dev_beam.sh new file mode 100755 index 0000000000..7bcbec2f03 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/dev_beam.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="resnet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=1536 EVAL_BS=192 + +export RESET_STEP=0 + +export TRAIN_BEAM=4 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=2000 BEAM_UPCAST_MAX=96 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +export BENCHMARK=10 DEBUG=${DEBUG:-2} + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/dev_run.sh new file mode 100755 index 0000000000..aad23e43df --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/dev_run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="resnet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=1536 EVAL_BS=192 + +export RESET_STEP=0 + +export TRAIN_BEAM=4 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=2000 BEAM_UPCAST_MAX=96 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +export EVAL_START_EPOCH=3 EVAL_FREQ=4 + +export WANDB=1 PARALLEL=0 + +python3 examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/run_and_time.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/run_and_time.sh new file mode 100755 index 0000000000..7a93d435a5 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/run_and_time.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e # Exit on any error +set -o pipefail # Make pipeline fail if any command fails + +export PYTHONPATH="." AMD=1 +export MODEL="resnet" +export SUBMISSION_PLATFORM="tinybox_red" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=1536 EVAL_BS=192 + +export RESET_STEP=0 + +export TRAIN_BEAM=4 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=2000 BEAM_UPCAST_MAX=96 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +# pip install -e ".[mlperf]" +export LOGMLPERF=${LOGMLPERF:-1} + +export SEED=$RANDOM +DATETIME=$(date "+%m%d%H%M") +LOGFILE="resnet_red_${DATETIME}_${SEED}.log" + +# init +sleep 5 && sudo rmmod amdgpu || true +BENCHMARK=10 INITMLPERF=1 python3 examples/mlperf/model_train.py | tee $LOGFILE + +# run +PARALLEL=0 RUNMLPERF=1 EVAL_START_EPOCH=3 EVAL_FREQ=4 python3 examples/mlperf/model_train.py | tee -a $LOGFILE diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/setup.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/setup.sh new file mode 100755 index 0000000000..a9806164f4 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/resnet/implementations/tinybox_red/setup.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +rocm-smi --setprofile compute +rocm-smi --setmclk 3 +rocm-smi --setperflevel high + +# power cap to 350W +echo "350000000" | sudo tee /sys/class/drm/card{1..6}/device/hwmon/hwmon*/power1_cap diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/README.md b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/README.md new file mode 100644 index 0000000000..ce1ac9b9a3 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/README.md @@ -0,0 +1,38 @@ +# 1. Problem + +This problem uses RetinaNet for SSD. + +## Requirements + +Install tinygrad and mlperf-logging (uncomment mlperf from setup.py) from branch mlperf_training_v5.0. +``` +git clone https://github.com/tinygrad/tinygrad.git +python3 -m pip install -e ".[mlperf]" +``` + +Also install the following dependencies: +``` +pip install tqdm numpy pycocotools boto3 pandas torch torchvision +``` + +### tinybox_green +Install the p2p driver per [README](https://github.com/tinygrad/open-gpu-kernel-modules/blob/550.54.15-p2p/README.md) +This is the default on production tinybox green. + +# 2. Directions + +## Steps to download data + +Run the following: +``` +BASEDIR=/raid/datasets/openimages python3 extra/datasets/openimages.py +``` + +## Running + +### tinybox_green + +#### Steps to run benchmark +``` +examples/mlperf/training_submission_v5.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/run_and_time.sh +``` diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/dev_beam.sh new file mode 100755 index 0000000000..6e25bb9671 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/dev_beam.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +export PYTHONPATH="." NV=1 +export MODEL="retinanet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=96 EVAL_BS=96 +export BASEDIR="/raid/datasets/openimages" + +# export RESET_STEP=0 + +export TRAIN_BEAM=2 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +export BENCHMARK=5 DEBUG=2 + +python examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/dev_run.sh new file mode 100755 index 0000000000..7a3ee0dfa2 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/dev_run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +export PYTHONPATH="." NV=1 +export MODEL="retinanet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=96 EVAL_BS=96 +export BASEDIR="/raid/datasets/openimages" + +# export RESET_STEP=0 + +export TRAIN_BEAM=2 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +export WANDB=1 PARALLEL=0 +export RUNMLPERF=1 + +python examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/run_and_time.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/run_and_time.sh new file mode 100755 index 0000000000..74cdc87a1b --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_green/run_and_time.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e # Exit on any error +set -o pipefail # Make pipeline fail if any command fails + +export PYTHONPATH="." NV=1 +export MODEL="retinanet" +export SUBMISSION_PLATFORM="tinybox_green" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=96 EVAL_BS=96 + +export TRAIN_BEAM=2 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 +export IGNORE_JIT_FIRST_BEAM=1 +export BASEDIR="/raid/datasets/openimages" + +# pip install -e ".[mlperf]" +export LOGMLPERF=1 + +export SEED=$RANDOM +DATETIME=$(date "+%m%d%H%M") +LOGFILE="retinanet_green_${DATETIME}_${SEED}.log" + +# init +BENCHMARK=10 INITMLPERF=1 python3 examples/mlperf/model_train.py | tee $LOGFILE + +# run +PARALLEL=0 RUNMLPERF=1 python3 examples/mlperf/model_train.py | tee -a $LOGFILE diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_red/dev_beam.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_red/dev_beam.sh new file mode 100755 index 0000000000..97aa5155eb --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_red/dev_beam.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="retinanet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=96 EVAL_BS=96 +export BASEDIR="/raid/datasets/openimages" + +# export RESET_STEP=0 + +export TRAIN_BEAM=2 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +export BENCHMARK=5 DEBUG=2 + +python examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_red/dev_run.sh b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_red/dev_run.sh new file mode 100755 index 0000000000..5fb4d109fd --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/benchmarks/retinanet/implementations/tinybox_red/dev_run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +export PYTHONPATH="." AMD=1 +export MODEL="retinanet" +export DEFAULT_FLOAT="HALF" GPUS=6 BS=96 EVAL_BS=96 +export BASEDIR="/raid/datasets/openimages" + +# export RESET_STEP=0 + +export TRAIN_BEAM=2 IGNORE_JIT_FIRST_BEAM=1 BEAM_UOPS_MAX=1500 BEAM_UPCAST_MAX=64 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 BEAM_PADTO=0 + +export WANDB=1 PARALLEL=0 +export RUNMLPERF=1 + +python examples/mlperf/model_train.py diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_8xMI300X.json b/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_8xMI300X.json new file mode 100644 index 0000000000..1e0f789430 --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_8xMI300X.json @@ -0,0 +1,38 @@ +{ + "submitter": "tinycorp", + "division": "closed", + "status": "Available on-premise", + "system_name": "tinybox 8xMI300X", + "number_of_nodes": "1", + "host_processors_per_node": "2", + "host_processor_model_name": "AMD EPYC 9354", + "host_processor_core_count": "32", + "host_processor_vcpu_count": "64", + "host_processor_frequency": "", + "host_processor_caches": "", + "host_processor_interconnect": "", + "host_memory_capacity": "2304GB", + "host_storage_type": "NVMe SSD", + "host_storage_capacity": "3x 4TB raid array", + "host_networking": "", + "host_networking_topology": "", + "host_memory_configuration": "24x 96GB DDR5", + "accelerators_per_node": "8", + "accelerator_model_name": "AMD Instinct MI300X 192GB HBM3", + "accelerator_host_interconnect": "PCIe 5.0 x16", + "accelerator_frequency": "", + "accelerator_on-chip_memories": "", + "accelerator_memory_configuration": "HBM3", + "accelerator_memory_capacity": "192GB", + "accelerator_interconnect": "", + "accelerator_interconnect_topology": "", + "cooling": "air", + "hw_notes": "", + "framework": "tinygrad, branch mlperf_training_v5.0", + "other_software_stack": { + "python": "3.10.16", + "ROCm": "3.0.0+94441cb" + }, + "operating_system": "Ubuntu 24.04.1 LTS", + "sw_notes": "" + } \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_green.json b/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_green.json new file mode 100644 index 0000000000..24cbce1f1c --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_green.json @@ -0,0 +1,38 @@ +{ + "submitter": "tinycorp", + "division": "closed", + "status": "Available on-premise", + "system_name": "tinybox green", + "number_of_nodes": "1", + "host_processors_per_node": "1", + "host_processor_model_name": "AMD EPYC 7532", + "host_processor_core_count": "32", + "host_processor_vcpu_count": "64", + "host_processor_frequency": "", + "host_processor_caches": "", + "host_processor_interconnect": "", + "host_memory_capacity": "128GB", + "host_storage_type": "NVMe SSD", + "host_storage_capacity": "4 TB raid array + 1 TB boot", + "host_networking": "", + "host_networking_topology": "", + "host_memory_configuration": "8x 16GB DDR4", + "accelerators_per_node": "6", + "accelerator_model_name": "NVIDIA GeForce RTX 4090", + "accelerator_host_interconnect": "PCIe 4.0 x16", + "accelerator_frequency": "", + "accelerator_on-chip_memories": "", + "accelerator_memory_configuration": "GDDR6X", + "accelerator_memory_capacity": "24GB", + "accelerator_interconnect": "", + "accelerator_interconnect_topology": "", + "cooling": "air", + "hw_notes": "", + "framework": "tinygrad, branch mlperf_training_v5.0", + "other_software_stack": { + "python": "3.10.12", + "CUDA": "12.4" + }, + "operating_system": "Ubuntu 22.04.4", + "sw_notes": "" +} \ No newline at end of file diff --git a/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_red.json b/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_red.json new file mode 100644 index 0000000000..58b6efe77c --- /dev/null +++ b/examples/mlperf/training_submission_v6.0/tinycorp/systems/tinybox_red.json @@ -0,0 +1,37 @@ +{ + "submitter": "tinycorp", + "division": "closed", + "status": "Available on-premise", + "system_name": "tinybox red", + "number_of_nodes": "1", + "host_processors_per_node": "1", + "host_processor_model_name": "AMD EPYC 7532", + "host_processor_core_count": "32", + "host_processor_vcpu_count": "64", + "host_processor_frequency": "", + "host_processor_caches": "", + "host_processor_interconnect": "", + "host_memory_capacity": "128GB", + "host_storage_type": "NVMe SSD", + "host_storage_capacity": "4 TB raid array + 1 TB boot", + "host_networking": "", + "host_networking_topology": "", + "host_memory_configuration": "8x 16GB DDR4", + "accelerators_per_node": "6", + "accelerator_model_name": "AMD Radeon RX 7900 XTX", + "accelerator_host_interconnect": "PCIe 4.0 x16", + "accelerator_frequency": "", + "accelerator_on-chip_memories": "", + "accelerator_memory_configuration": "GDDR6", + "accelerator_memory_capacity": "24GB", + "accelerator_interconnect": "", + "accelerator_interconnect_topology": "", + "cooling": "air", + "hw_notes": "", + "framework": "tinygrad, branch mlperf_training_v5.0", + "other_software_stack": { + "python": "3.10.12" + }, + "operating_system": "Ubuntu 22.04.4", + "sw_notes": "" +} \ No newline at end of file diff --git a/examples/openpilot/compile3.py b/examples/openpilot/compile3.py index 6159bca5d6..0c820c3ff0 100644 --- a/examples/openpilot/compile3.py +++ b/examples/openpilot/compile3.py @@ -1,16 +1,11 @@ -import os, sys, pickle, time +import os, sys, pickle, time, re import numpy as np -if "FLOAT16" not in os.environ: os.environ["FLOAT16"] = "1" -if "IMAGE" not in os.environ: os.environ["IMAGE"] = "2" -if "NOLOCALS" not in os.environ: os.environ["NOLOCALS"] = "1" if "JIT_BATCH_SIZE" not in os.environ: os.environ["JIT_BATCH_SIZE"] = "0" from tinygrad import fetch, Tensor, TinyJit, Context, GlobalCounters, Device, dtypes from tinygrad.helpers import DEBUG, getenv from tinygrad.engine.realize import CompiledRunner - -import onnx -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner OPENPILOT_MODEL = sys.argv[1] if len(sys.argv) > 1 else "https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/supercombo.onnx" OUTPUT = sys.argv[2] if len(sys.argv) > 2 else "/tmp/openpilot.pkl" @@ -21,11 +16,14 @@ def compile(onnx_file): input_shapes = {name: spec.shape for name, spec in run_onnx.graph_inputs.items()} input_types = {name: spec.dtype for name, spec in run_onnx.graph_inputs.items()} + # Float inputs and outputs to tinyjits for openpilot are always float32 + # TODO this seems dumb input_types = {k:(dtypes.float32 if v is dtypes.float16 else v) for k,v in input_types.items()} Tensor.manual_seed(100) - new_inputs = {k:Tensor.randn(*shp, dtype=input_types[k]).mul(8).realize() for k,shp in sorted(input_shapes.items())} - new_inputs_numpy = {k:v.numpy() for k,v in new_inputs.items()} + inputs = {k:Tensor(Tensor.randn(*shp, dtype=input_types[k]).mul(8).realize().numpy(), device='NPY') for k,shp in sorted(input_shapes.items())} + if not getenv("NPY_IMG"): + inputs = {k:Tensor(v.numpy(), device=Device.DEFAULT).realize() if 'img' in k else v for k,v in inputs.items()} print("created tensors") run_onnx_jit = TinyJit(lambda **kwargs: @@ -33,8 +31,6 @@ def compile(onnx_file): for i in range(3): GlobalCounters.reset() print(f"run {i}") - inputs = {**{k:v.clone() for k,v in new_inputs.items() if 'img' in k}, - **{k:Tensor(v, device="NPY").realize() for k,v in new_inputs_numpy.items() if 'img' not in k}} with Context(DEBUG=max(DEBUG.value, 2 if i == 2 else 1)): ret = run_onnx_jit(**inputs).numpy() # copy i == 1 so use of JITBEAM is okay @@ -43,7 +39,7 @@ def compile(onnx_file): np.testing.assert_equal(test_val, ret, "JIT run failed") print("jit run validated") - # checks from compile2 + # check gated read_image usage kernel_count = 0 read_image_count = 0 gated_read_image_count = 0 @@ -52,6 +48,8 @@ def compile(onnx_file): kernel_count += 1 read_image_count += ei.prg.p.src.count("read_image") gated_read_image_count += ei.prg.p.src.count("?read_image") + for v in [m.group(1) for m in re.finditer(r'(val\d+)\s*=\s*read_imagef\(', ei.prg.p.src)]: + if len(re.findall(fr'[\?\:]{v}\.[xyzw]', ei.prg.p.src)) > 0: gated_read_image_count += 1 print(f"{kernel_count=}, {read_image_count=}, {gated_read_image_count=}") if (allowed_kernel_count:=getenv("ALLOWED_KERNEL_COUNT", -1)) != -1: assert kernel_count == allowed_kernel_count, f"different kernels! {kernel_count=}, {allowed_kernel_count=}" @@ -67,85 +65,77 @@ def compile(onnx_file): print(f"mdl size is {mdl_sz/1e6:.2f}M") print(f"pkl size is {pkl_sz/1e6:.2f}M") print("**** compile done ****") - return test_val + return inputs, test_val -def test_vs_compile(run, new_inputs, test_val=None): - new_inputs_numpy = {k:v.numpy() for k,v in new_inputs.items()} - - # create fake "from_blob" tensors for the inputs, and wrapped NPY tensors for the numpy inputs (these have the same underlying memory) - inputs = {**{k:v for k,v in new_inputs.items() if 'img' in k}, - **{k:Tensor(v, device="NPY").realize() for k,v in new_inputs_numpy.items() if 'img' not in k}} +def test_vs_compile(run, inputs, test_val=None): # run 20 times + step_times = [] for _ in range(20): st = time.perf_counter() out = run(**inputs) mt = time.perf_counter() val = out.numpy() et = time.perf_counter() - print(f"enqueue {(mt-st)*1e3:6.2f} ms -- total run {(et-st)*1e3:6.2f} ms") - print(out, val.shape, val.dtype) + step_times.append((et-st)*1e3) + print(f"enqueue {(mt-st)*1e3:6.2f} ms -- total run {step_times[-1]:6.2f} ms") + + if (assert_time:=getenv("ASSERT_MIN_STEP_TIME")): + min_time = min(step_times) + assert min_time < assert_time, f"Speed regression, expected min step time of < {assert_time} ms but took: {min_time} ms" + if test_val is not None: np.testing.assert_equal(test_val, val) print("**** test done ****") # test that changing the numpy changes the model outputs - if any([x.device == 'NPY' for x in inputs.values()]): - for v in new_inputs_numpy.values(): v *= 2 - out = run(**inputs) - changed_val = out.numpy() - np.testing.assert_raises(AssertionError, np.testing.assert_array_equal, val, changed_val) + inputs_2x = {k: Tensor(v.numpy()*2, device=v.device) for k,v in inputs.items()} + out = run(**inputs_2x) + changed_val = out.numpy() + np.testing.assert_raises(AssertionError, np.testing.assert_array_equal, val, changed_val) return val -def test_vs_onnx(new_inputs, test_val, onnx_file, ort=False): - new_inputs_numpy = {k:v.numpy() for k,v in new_inputs.items()} +def test_vs_onnx(new_inputs, test_val, onnx_file, tol): + import onnx + import onnxruntime as ort + + onnx_inputs = {k:v.numpy() for k,v in new_inputs.items()} onnx_model = onnx.load(onnx_file) - timings = [] - if ort: - # test with onnxruntime - import onnxruntime as ort - onnx_session = ort.InferenceSession(onnx_file) - for _ in range(1 if test_val is not None else 5): - st = time.perf_counter() - onnx_output = onnx_session.run([onnx_model.graph.output[0].name], {k:v.astype(np.float16) for k,v in new_inputs_numpy.items()}) - timings.append(time.perf_counter() - st) - new_torch_out = onnx_output[0] - else: - # test with torch - import torch - from onnx2torch import convert - inputs = {k.name:new_inputs_numpy[k.name] for k in onnx_model.graph.input} - torch_model = convert(onnx_model).float() - with torch.no_grad(): - for _ in range(1 if test_val is not None else 5): - st = time.perf_counter() - torch_out = torch_model(*[torch.tensor(x) for x in inputs.values()]) - timings.append(time.perf_counter() - st) - new_torch_out = torch_out.numpy() + ORT_TO_NP_DTYPES: dict[str, np.dtype] = { + 'tensor(float)': np.dtype('float32'), + 'tensor(float16)': np.dtype('float16'), + 'tensor(uint8)': np.dtype('uint8'), + } - if test_val is not None: - np.testing.assert_allclose(new_torch_out.reshape(test_val.shape), test_val, atol=1e-4, rtol=1e-2) - print("test vs onnx passed") + timings = [] + onnx_session = ort.InferenceSession(onnx_file) + onnx_types = {x.name: ORT_TO_NP_DTYPES[x.type] for x in onnx_session.get_inputs()} + onnx_inputs = {k:onnx_inputs[k].astype(onnx_types[k]) for k in onnx_inputs} + + for _ in range(1 if test_val is not None else 5): + st = time.perf_counter() + onnx_output = onnx_session.run([onnx_model.graph.output[0].name], onnx_inputs) + timings.append(time.perf_counter() - st) + + np.testing.assert_allclose(onnx_output[0].reshape(test_val.shape), test_val, atol=tol, rtol=tol) + print("test vs onnx passed") return timings +def bench(run, inputs): + from extra.bench_log import WallTimeEvent, BenchEvent + for _ in range(10): + with WallTimeEvent(BenchEvent.STEP): + run(**inputs).numpy() + if __name__ == "__main__": onnx_file = fetch(OPENPILOT_MODEL) - test_val = compile(onnx_file) if not getenv("RUN") else None + inputs, outputs = compile(onnx_file) with open(OUTPUT, "rb") as f: pickle_loaded = pickle.load(f) - # same randomness as compile - Tensor.manual_seed(100) - new_inputs = {nm:Tensor.randn(*st.shape, dtype=dtype).mul(8).realize() for nm, (st, _, dtype, _) in - sorted(zip(pickle_loaded.captured.expected_names, pickle_loaded.captured.expected_st_vars_dtype_device))} - - test_val = test_vs_compile(pickle_loaded, new_inputs, test_val) - if getenv("BENCHMARK"): - for be in ["torch", "ort"]: - try: - timings = test_vs_onnx(new_inputs, None, onnx_file, be=="ort") - print(f"timing {be}: {min(timings)*1000:.2f} ms") - except Exception as e: - print(f"{be} fail with {e}") - if not getenv("FLOAT16"): test_vs_onnx(new_inputs, test_val, onnx_file, getenv("ORT")) + test_vs_compile(pickle_loaded, inputs, outputs) + if getenv("SELFTEST"): + test_vs_onnx(inputs, outputs, onnx_file, 1e-4) + if getenv("BENCHMARK_LOG", ""): + bench(pickle_loaded, inputs) diff --git a/examples/openpilot/compile4.py b/examples/openpilot/compile4.py deleted file mode 100644 index 55fcccbfbf..0000000000 --- a/examples/openpilot/compile4.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -from tinygrad import Tensor, fetch, GlobalCounters, dtypes -from tinygrad.uop.ops import UOp -from tinygrad.frontend.onnx import OnnxRunner -from tinygrad.schedule.kernelize import get_kernelize_map -from tinygrad.engine.schedule import create_schedule_with_vars -from tinygrad.engine.realize import run_schedule - -# NOLOCALS=1 CL=1 IMAGE=2 FLOAT16=1 VIZ=1 DEBUG=2 python3 examples/openpilot/compile4.py - -OPENPILOT_MODEL = sys.argv[1] if len(sys.argv) > 1 else "https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/supercombo.onnx" -OUTPUT = sys.argv[2] if len(sys.argv) > 2 else "/tmp/openpilot.pkl" - -if __name__ == "__main__": - onnx_file = fetch(OPENPILOT_MODEL) - run_onnx = OnnxRunner(onnx_file) - - inputs = run_onnx.get_empty_input_data("npy", dtypes.float32) - out: Tensor = next(iter(run_onnx({k:v.to(None) for k,v in inputs.items()}).values())).to('cpu') - root = out.uop - targets = [x.uop for x in inputs.values()] - print(targets) - - # TODO: abstract this from gradient? - - # compute the target path (top down) - in_target_path: dict[UOp, bool] = {} - for u in root.toposort(): in_target_path[u] = any(x in targets or in_target_path[x] for x in u.src) - independent_set = {} - for u in root.toposort(): - if in_target_path[u]: - for s in u.src: - if not in_target_path[s]: - independent_set[s] = None - independent = UOp.sink(*independent_set.keys()) - kernelized = get_kernelize_map(independent) - independent = independent.substitute(kernelized) - schedule, var_vals = create_schedule_with_vars(independent) - run_schedule(schedule) - - print("**** real ****") - GlobalCounters.reset() - out.uop = root.substitute(kernelized) - out.kernelize() - - # realize - out.realize() diff --git a/examples/other_mnist/beautiful_mnist_torch.py b/examples/other_mnist/beautiful_mnist_torch.py index 9fa597bae8..8e0b7dd64d 100644 --- a/examples/other_mnist/beautiful_mnist_torch.py +++ b/examples/other_mnist/beautiful_mnist_torch.py @@ -27,7 +27,7 @@ class Model(nn.Module): if __name__ == "__main__": if getenv("TINY_BACKEND"): - import tinygrad.frontend.torch # noqa: F401 + import tinygrad.nn.torch # noqa: F401 device = torch.device("tiny") else: device = torch.device({"METAL":"mps","NV":"cuda"}.get(Device.DEFAULT, "cpu")) diff --git a/examples/sdv2.py b/examples/sdv2.py index 29b1abb8fd..856cf239ad 100644 --- a/examples/sdv2.py +++ b/examples/sdv2.py @@ -99,6 +99,7 @@ if __name__ == "__main__": parser.add_argument('--timing', action='store_true', help="Print timing per step") parser.add_argument('--noshow', action='store_true', help="Don't show the image") parser.add_argument('--fp16', action='store_true', help="Cast the weights to float16") + parser.add_argument('--fakeweights', action='store_true', help="Skip loading checkpoints and use fake weights") args = parser.parse_args() N = 1 @@ -112,19 +113,22 @@ if __name__ == "__main__": model = StableDiffusionV2(**params) - default_weights_url = 'https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-ema-pruned.safetensors' - weights_fn = args.weights_fn - if not weights_fn: - weights_url = args.weights_url if args.weights_url else default_weights_url - weights_fn = fetch(weights_url, os.path.basename(str(weights_url))) - with WallTimeEvent(BenchEvent.LOAD_WEIGHTS): - load_state_dict(model, safe_load(weights_fn), strict=False) + if not args.fakeweights: + default_weights_url = 'https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-ema-pruned.safetensors' + weights_fn = args.weights_fn + if not weights_fn: + weights_url = args.weights_url if args.weights_url else default_weights_url + weights_fn = fetch(weights_url, os.path.basename(str(weights_url))) + + load_state_dict(model, safe_load(weights_fn), strict=False) if args.fp16: for k,v in get_state_dict(model).items(): if k.startswith("model"): - v.replace(v.cast(dtypes.float16).realize()) + v.replace(v.cast(dtypes.float16)) + + Tensor.realize(*get_state_dict(model).values()) c = { "crossattn": model.cond_stage_model(args.prompt) } uc = { "crossattn": model.cond_stage_model("") } diff --git a/examples/stable_diffusion.py b/examples/stable_diffusion.py index fe85aaffab..4650b7e1d9 100644 --- a/examples/stable_diffusion.py +++ b/examples/stable_diffusion.py @@ -263,18 +263,23 @@ if __name__ == "__main__": parser.add_argument('--timing', action='store_true', help="Print timing per step") parser.add_argument('--seed', type=int, help="Set the random latent seed") parser.add_argument('--guidance', type=float, default=7.5, help="Prompt strength") + parser.add_argument('--fakeweights', action='store_true', help="Skip loading checkpoints and use fake weights") args = parser.parse_args() model = StableDiffusion() # load in weights with WallTimeEvent(BenchEvent.LOAD_WEIGHTS): - load_state_dict(model, torch_load(fetch('https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt', 'sd-v1-4.ckpt'))['state_dict'], strict=False) + if not args.fakeweights: + model_bin = fetch('https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt', 'sd-v1-4.ckpt') + load_state_dict(model, torch_load(model_bin)['state_dict'], verbose=False, strict=False, realize=False) if args.fp16: for k,v in get_state_dict(model).items(): if k.startswith("model"): - v.replace(v.cast(dtypes.float16).realize()) + v.replace(v.cast(dtypes.float16)) + + Tensor.realize(*get_state_dict(model).values()) # run through CLIP to get context tokenizer = Tokenizer.ClipTokenizer() diff --git a/examples/test_onnx_imagenet.py b/examples/test_onnx_imagenet.py index 11f469aebd..98a560f1b9 100644 --- a/examples/test_onnx_imagenet.py +++ b/examples/test_onnx_imagenet.py @@ -19,8 +19,8 @@ from tinygrad.helpers import fetch, getenv # QUANT=1 python3 examples/test_onnx_imagenet.py # https://github.com/xamcat/mobcat-samples/raw/refs/heads/master/onnx_runtime/InferencingSample/InferencingSample/mobilenetv2-7.onnx -# DONT_REALIZE_EXPAND=1 python3 examples/test_onnx_imagenet.py /tmp/model.quant.onnx -# VIZ=1 DONT_REALIZE_EXPAND=1 python3 examples/benchmark_onnx.py /tmp/model.quant.onnx +# python3 examples/test_onnx_imagenet.py /tmp/model.quant.onnx +# VIZ=1 python3 examples/benchmark_onnx.py /tmp/model.quant.onnx def imagenet_dataloader(cnt=0): input_mean = Tensor([0.485, 0.456, 0.406]).reshape(1, -1, 1, 1) diff --git a/examples/train_resnet.py b/examples/train_resnet.py index 8feee80820..d15e05e450 100755 --- a/examples/train_resnet.py +++ b/examples/train_resnet.py @@ -32,7 +32,7 @@ if __name__ == "__main__": lr = 5e-3 transform = ComposeTransforms([ - lambda x: [Image.fromarray(xx, mode='L').resize((64, 64)) for xx in x], + lambda x: [Image.fromarray(xx).resize((64, 64)) for xx in x], lambda x: np.stack([np.asarray(xx) for xx in x], 0), lambda x: x / 255.0, lambda x: np.tile(np.expand_dims(x, 1), (1, 3, 1, 1)).astype(np.float32), diff --git a/examples/whisper.py b/examples/whisper.py index 2df3122628..5a189ad0a9 100644 --- a/examples/whisper.py +++ b/examples/whisper.py @@ -3,7 +3,7 @@ import sys, base64, multiprocessing, itertools, collections from typing import Optional, Union, Literal, List -from tinygrad import Tensor, TinyJit, Variable, nn +from tinygrad import Tensor, TinyJit, Variable, nn, dtypes from tinygrad.nn.state import torch_load, load_state_dict from tinygrad.helpers import getenv, fetch @@ -244,15 +244,16 @@ def transcribe_waveform(model: Whisper, enc, waveforms, truncate=False): log_spec = prep_audio(waveforms, model.batch_size, truncate) nsample = model.decoder.max_tokens_to_sample + nctx = model.decoder.max_self_attn_cache_len def inferloop(ctx: Union[np.ndarray, List[np.ndarray]], encoded_audio): pos, next_tokens = 0, ctx - for i in range((nsample-len(start_tokens))*2): - next_tokens = model.decoder(Tensor(next_tokens), pos, encoded_audio)[:, -1].argmax(axis=-1).numpy().astype(np.int32).reshape(-1, 1) + for i in range(nsample): + next_tokens = model.decoder(Tensor(next_tokens, dtype=dtypes.int32), pos, encoded_audio)[:, -1].argmax(axis=-1).numpy().astype(np.int32).reshape(-1, 1) next_tokens[ctx[:, -1] == eot] = eot ctx = np.concatenate((ctx, next_tokens), axis=1) pos = ctx.shape[-1] - 1 - if (next_tokens == eot).all(): break + if (next_tokens == eot).all() or pos == nctx: break return ctx def gettexttoks(line): return [tok for tok in line if tok < eot or tok > enc._special_tokens["<|notimestamps|>"]][-nsample+len(start_tokens):] diff --git a/examples/yolov8-onnx.py b/examples/yolov8-onnx.py index bc3d50ab9e..637d3b54e6 100644 --- a/examples/yolov8-onnx.py +++ b/examples/yolov8-onnx.py @@ -2,7 +2,7 @@ import os from ultralytics import YOLO from pathlib import Path -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner from extra.onnx_helpers import get_example_inputs os.chdir("/tmp") diff --git a/extra/cl_android.sh b/extra/cl_android.sh new file mode 100644 index 0000000000..eeeec7eb22 --- /dev/null +++ b/extra/cl_android.sh @@ -0,0 +1,4 @@ +# source extra/cl_android.sh +export LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib:/system/vendor/lib64 +export LD_PRELOAD=/system/vendor/lib64/libOpenCL.so + diff --git a/extra/gemm/amd_uop_matmul.py b/extra/gemm/amd_uop_matmul.py index 78dbf81a1d..3d644969bd 100644 --- a/extra/gemm/amd_uop_matmul.py +++ b/extra/gemm/amd_uop_matmul.py @@ -1,355 +1,168 @@ from tinygrad import Tensor, Device, Context, GlobalCounters, dtypes -from tinygrad.uop.ops import UOp, Ops, KernelInfo, graph_rewrite, AxisType, PatternMatcher, UPat -from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program +from tinygrad.uop.ops import UOp, KernelInfo, sint, AxisType +from tinygrad.engine.realize import ExecItem, get_runner from tinygrad.dtype import AddrSpace -from tinygrad.helpers import getenv, colored, prod, unwrap -from tinygrad.shape.shapetracker import ShapeTracker, View -from tinygrad.shape.view import strides_for_shape -from tinygrad.codegen.opt.kernel import axis_colors, Opt, OptOps -from tinygrad.codegen.opt.swizzler import merge_views, view_left - -def to_colored(full_shape, axis_types): return '_'.join([colored(str(s), axis_colors[at]) for s,at in zip(full_shape, axis_types)]) +from tinygrad.helpers import getenv N = 4096 +M = K = N run_count = 5 -BN = 128 -BM = 128 -BK = 8 +# --------------------------- +# launch/config constants +# --------------------------- -TN = 4 -TM = 4 +WARP_SIZE = 32 -# NOTE: this is from testgrad -# change reduceop axes and input ShapeTrackers, view gets replaced with a reshape. -# src->r->view --> src->view->r -def swizzle_reduceop(src:UOp, r:UOp, view:UOp): - if r.tag is not None: return None - # confirm the input is in order - # TODO: replace this with a UOp that allows for nothing else then remove this - permute = tuple(i for i in range(len(src.shape)) if i not in r.axis_arg)+r.axis_arg - assert permute == tuple(range(len(permute))), f"reduce axis must already be in order, {permute} isn't" +# Threadblock tile sizes (block-level tile of C that a block computes) +BLOCK_N = 128 # columns of C (N-dim) per block +BLOCK_M = 128 # rows of C (M-dim) per block +BLOCK_K = 8 # K-slice per block iteration - # append the reduce shape to each of the views - prshape = prod(rshape:=src.shape[-len(r.axis_arg):]) - rstrides = strides_for_shape(rshape) - nv = [View.create(v.shape+rshape, tuple(x*prshape for x in v.strides)+rstrides, v.offset*prshape, - v.mask+tuple((0,s) for s in rshape) if v.mask is not None else None) for v in unwrap(view.st).views] +# Register tile sizes (per-thread accumulator tile of C) +TN = 4 # columns per thread +TM = 4 # rows per thread - # no reshape required with shrinking REDUCE_AXIS - return UOp(Ops.REDUCE_AXIS, r.dtype, (src.view(ShapeTracker(tuple(nv))),), - (r.arg[0], tuple(range(len(view.shape), len(view.shape) + len(r.axis_arg))))) +is_kernel5 = getenv("K5", 0) +THREADS_PER_BLOCK = 128 if is_kernel5 else 256 +assert THREADS_PER_BLOCK % BLOCK_N == 0, "THREADS_PER_BLOCK must be divisible by BLOCK_N" +assert THREADS_PER_BLOCK % BLOCK_K == 0, "THREADS_PER_BLOCK must be divisible by BLOCK_K" +assert (BLOCK_N * BLOCK_K) % THREADS_PER_BLOCK == 0 +assert (BLOCK_M * BLOCK_K) % THREADS_PER_BLOCK == 0 -pm = PatternMatcher([ - (UPat(Ops.VIEW, src=(UPat(Ops.REDUCE_AXIS, src=(UPat.var("src"),), name="r"),), name="view"), swizzle_reduceop), -]) +WARPS_PER_BLOCK = THREADS_PER_BLOCK // WARP_SIZE +WAVE_TILE_N = 128 if is_kernel5 else 64 +WAVE_TILE_M = BLOCK_N * BLOCK_M // WARPS_PER_BLOCK // WAVE_TILE_N +assert BLOCK_N % WAVE_TILE_N == 0, "BN must be a multiple of WN" +assert BLOCK_M % WAVE_TILE_M == 0, "BM must be a multiple of WM" +WAVES_IN_BLOCK_X = BLOCK_N // WAVE_TILE_N +WAVES_IN_BLOCK_Y = BLOCK_M // WAVE_TILE_M +assert WAVES_IN_BLOCK_X * WAVES_IN_BLOCK_Y == WARPS_PER_BLOCK, "wave grid must match warps/block" -def rangeify_kernel3(): - a = Tensor.empty(N,N) - b = Tensor.empty(N,N) - c = a@b - #c = c.reshape((32,2,16,4,32,2,16,4)).contiguous() - with Context(RANGEIFY=1): - sink = c.schedule()[-1].ast - #print(sink) +LANES_PER_WAVE_X = 8 +LANES_PER_WAVE_Y = 4 +ITERS_PER_WAVE_N = WAVE_TILE_N // (LANES_PER_WAVE_X * TN) +ITERS_PER_WAVE_M = WAVE_TILE_M // (LANES_PER_WAVE_Y * TM) +assert WAVE_TILE_N % (LANES_PER_WAVE_X * TN) == 0, "WAVE_TILE_N must be divisible by LANES_PER_WAVE_X*TN" +assert WAVE_TILE_M % (LANES_PER_WAVE_Y * TM) == 0, "WAVE_TILE_M must be divisible by LANES_PER_WAVE_Y*TM" - opts = [Opt(OptOps.UPCAST, 0, 4), Opt(OptOps.LOCAL, 0, 16), Opt(OptOps.UPCAST, 0, 2)] - opts += [Opt(OptOps.UPCAST, 1, 4), Opt(OptOps.LOCAL, 1, 16), Opt(OptOps.UPCAST, 1, 2)] - opts += [Opt(OptOps.UNROLL, 0, 8)] +def rngs_for_shape(shape:tuple[sint, ...], rng:int, axis_type=AxisType.LOOP): return [UOp.range(s, rng+i, axis_type) for i,s in enumerate(shape)] +def copy(dest:UOp, src:UOp, rng:int, set=False, upcast=False): + assert dest.shape == src.shape + rngs = rngs_for_shape(src.shape, rng, AxisType.UPCAST if upcast else AxisType.LOOP) + copy = dest[*rngs].store(src[*rngs]).end(*rngs) + return dest.after(copy) if set else copy - return sink.replace(arg=KernelInfo(opts_to_apply=tuple(opts))) +def hand_spec_kernel3(): + # --------------------------- + # block indices & placeholders + # --------------------------- + blockIdx_x = UOp.special(N // BLOCK_N, "gidx0") + blockIdx_y = UOp.special(N // BLOCK_M, "gidx1") -def top_spec_kernel3(): - a = Tensor.empty(N,N) - b = Tensor.empty(N,N) - c = a@b - sink = c.schedule()[-1].ast - L = 16 - sink = sink.reshape((N//L, L, N//L, L)) #.lift({0:UOp.range(N//BM, 0), 2:UOp.range(N//BN, 1)}) - sink = graph_rewrite(sink, view_left+pm) - axis_types = (AxisType.GLOBAL, AxisType.LOCAL, AxisType.GLOBAL, AxisType.LOCAL, AxisType.REDUCE) - return sink.replace(arg=KernelInfo(name="top_"+to_colored(sink.full_shape, axis_types), axis_types=axis_types)) + a = UOp.placeholder((N, N), dtypes.float, slot=1) + b = UOp.placeholder((N, N), dtypes.float, slot=2) + c = UOp.placeholder((N, N), dtypes.float, slot=0) -def hl_spec_kernel3(): - nbIterWaveM = 2 - nbIterWaveN = 2 + # index the output with the globals + c = c.reshape(M // BLOCK_M, BLOCK_M, N // BLOCK_N, BLOCK_N)[blockIdx_y, :, blockIdx_x, :] - # define buffers - # TODO: remove these views once the defines have a shape - a = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(N*N), arg=1).view(ShapeTracker.from_shape((N,N))) - b = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(N*N), arg=2).view(ShapeTracker.from_shape((N,N))).permute((1,0)) - c = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(N*N), arg=0).view(ShapeTracker.from_shape((N,N))) - As = UOp(Ops.DEFINE_LOCAL, dtypes.float.ptr(BK*BM, AddrSpace.LOCAL), arg=0).view(ShapeTracker.from_shape((BK, BM))).permute((1,0)) - Bs = UOp(Ops.DEFINE_LOCAL, dtypes.float.ptr(BK*BN, AddrSpace.LOCAL), arg=1).view(ShapeTracker.from_shape((BK, BN))).permute((1,0)) - A_col = UOp(Ops.DEFINE_REG, dtypes.float.ptr(nbIterWaveM * TM, AddrSpace.REG), arg=0).view(ShapeTracker.from_shape((nbIterWaveM * TM,))) - B_row = UOp(Ops.DEFINE_REG, dtypes.float.ptr(nbIterWaveN * TN, AddrSpace.REG), arg=1).view(ShapeTracker.from_shape((nbIterWaveN * TN,))) + # open the main reduction range + k_tile_range = UOp.range(N // BLOCK_K, 0, AxisType.REDUCE) + a = a.reshape(M // BLOCK_M, BLOCK_M, N // BLOCK_K, BLOCK_K)[blockIdx_y, :, k_tile_range, :] + b = b.reshape(N // BLOCK_K, BLOCK_K, N // BLOCK_N, BLOCK_N)[k_tile_range, :, blockIdx_x, :] - # shape buffers. TODO: permutes - full_shape = (N//BM, nbIterWaveM, BM//(nbIterWaveM * TM), TM, N//BN, nbIterWaveN, BN//(nbIterWaveN * TN), TN, N//BK, BK) - a = a.reshape((N//BM, nbIterWaveM, BM//(nbIterWaveM * TM), TM, 1, 1, 1, 1, N//BK, BK)).expand(full_shape) - b = b.reshape((1, 1, 1, 1, N//BN, nbIterWaveN, BN//(nbIterWaveN * TN), TN, N//BK, BK)).expand(full_shape) - c = c.reshape((N//BM, nbIterWaveM, BM//(nbIterWaveM * TM), TM, N//BN, nbIterWaveN, BN//(nbIterWaveN * TN), TN, 1, 1)) - As = As.reshape((1, nbIterWaveM, BM//(nbIterWaveM * TM), TM, 1, 1, 1, 1, 1, BK)).expand(full_shape) - Bs = Bs.reshape((1, 1, 1, 1, 1, nbIterWaveN, BN//(nbIterWaveN * TN), TN, 1, BK)).expand(full_shape) - A_col = A_col.reshape((1, nbIterWaveM, 1, TM, 1, 1, 1, 1, 1, 1)).expand(full_shape) - B_row = B_row.reshape((1, 1, 1, 1, 1, nbIterWaveN, 1, TN, 1, 1)).expand(full_shape) + # globals are no longer used, they are already in the indexes + del blockIdx_y, blockIdx_x - # U1 L2 L3 L4 L5 U6 U7 U9 L10 L11 L12 L13 U14 U15 U17 U18 U19 - expanded_shape = (32, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 512, 2, 2, 2) - assert len(expanded_shape) == 20 - permute_a = list(range(len(expanded_shape))) - permute_b = permute_a[:] + # --------------------------- + # GLOBAL -> LOCAL (As, Bs) + # --------------------------- + tid = UOp.special(THREADS_PER_BLOCK, "lidx0") - # this makes all the global loads match - # this can also be more simply done by rebinding the RANGEs - # but sadly, rebinding the RANGEs doesn't work to change the order of the local axes - permute_a[17:20] = [11,12,13] - permute_a[11:14] = [17,18,19] - permute_a[7], permute_a[10] = permute_a[10], permute_a[7] - permute_a[2:7] = [3,4,5,6,2] + # A: read BM x BK tiles (permute on store into locals) + BM_As_stride = (BLOCK_M + 4) if is_kernel5 else BLOCK_M + As = UOp.placeholder((BLOCK_K, BM_As_stride), dtypes.float, slot=0, addrspace=AddrSpace.LOCAL).shrink_to((BLOCK_K, BLOCK_M)) + As_store = copy(As.permute((1,0)).reshape(-1, THREADS_PER_BLOCK)[:, tid], a.reshape(-1, THREADS_PER_BLOCK)[:, tid], rng=100) - permute_b[2:16] = [19,9,10,11,17,18,8,2,12,13,14,15,3,4] - permute_b[17:20] = [5,6,7] + # B: read BK x BN tiles + Bs = UOp.placeholder((BLOCK_K, BLOCK_N), dtypes.float, slot=1, addrspace=AddrSpace.LOCAL) + Bs_store = copy(Bs.reshape(-1, THREADS_PER_BLOCK)[:, tid], b.reshape(-1, THREADS_PER_BLOCK)[:, tid], rng=200) - a_permute = a.reshape(expanded_shape).permute(tuple(permute_a)).reshape(full_shape) - As_permute = As.reshape(expanded_shape).permute(tuple(permute_a)).reshape(full_shape) + # TODO: can we automate barrier? + barrier = UOp.barrier(As_store, Bs_store) + As, Bs = As.after(barrier), Bs.after(barrier) - b_permute = b.reshape(expanded_shape).permute(tuple(permute_b)).reshape(full_shape) - Bs_permute = Bs.reshape(expanded_shape).permute(tuple(permute_b)).reshape(full_shape) + # open inner k range + k = UOp.range(BLOCK_K, 3, AxisType.REDUCE) - #out = (a.load() * b.load()).r(Ops.ADD, (8, 9)) - out = (As.load(As_permute.store(a_permute.load())) * Bs.load(Bs_permute.store(b_permute.load()))).r(Ops.ADD, (8, 9)) - #out = (A_col.load(A_col.store(As.load(As.store(a.load())))) * B_row.load(B_row.store(Bs.load(Bs.store(b.load()))))).r(Ops.ADD, (8, 9)) + # --------------------------- + # LOCAL -> REG (per-wave tiles) + # --------------------------- + waveIdx = (tid // WARP_SIZE) % WAVES_IN_BLOCK_X + waveIdy = (tid // WARP_SIZE) // WAVES_IN_BLOCK_X + assert waveIdy.vmax+1 == WAVES_IN_BLOCK_Y - axis_types = ( - AxisType.GLOBAL, AxisType.UPCAST, AxisType.LOCAL, AxisType.UPCAST, - AxisType.GLOBAL, AxisType.UPCAST, AxisType.LOCAL, AxisType.UPCAST, - AxisType.REDUCE, AxisType.REDUCE) + laneIdx = (tid % WARP_SIZE) % LANES_PER_WAVE_X + laneIdy = (tid % WARP_SIZE) // LANES_PER_WAVE_X + assert laneIdy.vmax+1 == LANES_PER_WAVE_Y - sink = c.store(out).sink(arg=KernelInfo(name="tg_"+to_colored(full_shape, axis_types), axis_types=axis_types)) - sink = graph_rewrite(sink, merge_views) - return sink + A_col = UOp.placeholder((ITERS_PER_WAVE_M, TM), dtypes.float, slot=0, addrspace=AddrSpace.REG) + A_col = copy(A_col, As[k, :].reshape(WAVES_IN_BLOCK_Y, ITERS_PER_WAVE_M, LANES_PER_WAVE_Y, TM)[waveIdy, :, laneIdy, :], 300, set=True, upcast=True) -def hand_spec_kernel3(kernel4=getenv("K4", 0), kernel5=getenv("K5", 0)): - BLOCK_SIZE = 128 if kernel5 else 256 + B_row = UOp.placeholder((ITERS_PER_WAVE_N, TN), dtypes.float, slot=1, addrspace=AddrSpace.REG) + B_row = copy(B_row, Bs[k, :].reshape(WAVES_IN_BLOCK_X, ITERS_PER_WAVE_N, LANES_PER_WAVE_X, TN)[waveIdx, :, laneIdx, :], 400, set=True, upcast=True) - nbWaves = BLOCK_SIZE // 32 - WN = 128 if kernel5 else 64 - WM = BN * BM // nbWaves // WN + # --------------------------- + # FMA: c_regs += A_col * B_row + # --------------------------- + c_regs = UOp.placeholder((ITERS_PER_WAVE_M, TM, ITERS_PER_WAVE_N, TN), dtypes.float, slot=2, addrspace=AddrSpace.REG) + i = UOp.range(c_regs.size, 16) + c_regs = c_regs.after(c_regs.flatten()[i].store(0.0).end(i)) - nbWaveX = BN // WN - nbWaveY = BM // WM + # TODO: why don't these work as upcast? + # why if the ranges merge is it slow?!? (if you change the order on end, they will merge. big slowdown on METAL) + iterWaveM, yt, iterWaveN, xt = rngs = rngs_for_shape(c_regs.shape, 500) + sink = c_regs[*rngs].store(c_regs.after(k)[*rngs] + A_col[iterWaveM, yt] * B_row[iterWaveN, xt]).end(iterWaveM, iterWaveN, yt, xt) - threadIdx_x = UOp(Ops.SPECIAL, dtypes.int, arg=("lidx0", BLOCK_SIZE)) - waveIndex = threadIdx_x // 32 - waveIdx = waveIndex % nbWaveX - waveIdy = waveIndex // nbWaveX - indexInWave = threadIdx_x % 32 + # Close k, sync, and close K tiles + sink = sink.end(k).barrier().end(k_tile_range) - nbThreadXPerWave = 8 - nbThreadYPerWave = 4 + # --------------------------- + # REG -> GLOBAL (epilogue) + # --------------------------- + c = c.reshape(WAVES_IN_BLOCK_Y, ITERS_PER_WAVE_M, LANES_PER_WAVE_Y, TM, + WAVES_IN_BLOCK_X, ITERS_PER_WAVE_N, LANES_PER_WAVE_X, TN) + c = c[waveIdy, :, laneIdy, :, + waveIdx, :, laneIdx, :] + sink = copy(c, c_regs.after(sink), rng=600) - idxInWave = indexInWave % nbThreadXPerWave - idyInWave = indexInWave // nbThreadXPerWave + return sink.sink(arg=KernelInfo(opts_to_apply=())).simplify() - nbIterWaveN = WN // (nbThreadXPerWave * TN) - nbIterWaveM = WM // (nbThreadYPerWave * TM) +def test_matmul(sink:UOp, N=N): + with Context(DEBUG=0): + a = Tensor.randn(N, N) + b = Tensor.randn(N, N) + hc = Tensor.empty(N, N) + Tensor.realize(a, b, hc) - SUBWN = WN // nbIterWaveN - SUBWM = WM // nbIterWaveM + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in [hc, a, b]]) - # Thread mapping to read BKxBN block from A - rAIdx = threadIdx_x % BK - rAIdy = threadIdx_x // BK - # Thread mapping to read BNxBK block from B - rBIdx = threadIdx_x % BN - rBIdy = threadIdx_x // BN + GlobalCounters.reset() + ets = [] + with Context(DEBUG=2): + for _ in range(run_count): + ets.append(ei.run(wait=True)) + print(f"REAL TFLOPS {N * N * N * 2 / min(ets) * 1e-12:.2f}") - strideReadB = BLOCK_SIZE // BN - strideReadA = BLOCK_SIZE // BK - nbReadsB = BN * BK // BLOCK_SIZE - nbReadsA = BM * BK // BLOCK_SIZE - - blockIdx_x = UOp(Ops.SPECIAL, dtypes.int, arg=("gidx0", N//BN)) - blockIdx_y = UOp(Ops.SPECIAL, dtypes.int, arg=("gidx1", N//BM)) - - a = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(N*N), arg=1) - b = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(N*N), arg=2) - c = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(N*N), arg=0) - - A_col = UOp(Ops.DEFINE_REG, dtypes.float.ptr(nbIterWaveM * TM, AddrSpace.REG), arg=0) - B_row = UOp(Ops.DEFINE_REG, dtypes.float.ptr(nbIterWaveN * TN, AddrSpace.REG), arg=1) - - BM_As_stride = (BM+4) if kernel5 else BM - As = UOp(Ops.DEFINE_LOCAL, dtypes.float.ptr(BK*BM_As_stride, AddrSpace.LOCAL), arg=0) - Bs = UOp(Ops.DEFINE_LOCAL, dtypes.float.ptr(BK*BN, AddrSpace.LOCAL), arg=1) - - c_regs = UOp(Ops.DEFINE_REG, dtypes.float.ptr(TM * nbIterWaveM * TN * nbIterWaveN), arg=2) - - i = UOp.range(c_regs.dtype.size, 16) - init_store = c_regs[i].store(UOp.const(dtypes.float, 0.0), i) - - if kernel4: - regA = UOp(Ops.DEFINE_REG, dtypes.float.ptr(nbReadsA, AddrSpace.REG), arg=3) - regB = UOp(Ops.DEFINE_REG, dtypes.float.ptr(nbReadsB, AddrSpace.REG), arg=4) - - # initial load from globals into locals (0) - kId = 0 - - # load from globals into locals - i = UOp.range(nbReadsB, 0) - index_x = BN * blockIdx_x + rBIdx - index_y = rBIdy + i * strideReadB + kId - Bs_store = Bs[(index_y % BK) * BN + index_x % BN].store(b[N * index_y + index_x].load(), i) - - i = UOp.range(nbReadsA, 1) - index_x = rAIdx + kId - index_y = BM * blockIdx_y + rAIdy + i * strideReadA - As_store = As[(index_x % BK) * BM_As_stride + index_y % BM].store(a[N * index_y + index_x].load(), i) - - # iterate over the middle chunk - kId_range = UOp.range(N//BK-1, 2) - kId = kId_range*BK - - barrier = UOp.barrier(As_store, Bs_store) - - # load from globals into registers (next round) - i = UOp.range(nbReadsB, 3) - index_x = BN * blockIdx_x + rBIdx - index_y = rBIdy + i * strideReadB + kId + BK - regB_store = regB[i].store(b[N * index_y + index_x].load(), i) - - i = UOp.range(nbReadsA, 4) - index_x = rAIdx + kId + BK - index_y = BM * blockIdx_y + rAIdy + i * strideReadA - regA_store = regA[i].store(a[N * index_y + index_x].load(), i) - - def inner_loop(first_range, inp_dep=()): - # inner unroll - k = UOp.range(BK, first_range+0) - - # load from locals into registers - iterWave = UOp.range(nbIterWaveN, first_range+1) - i = UOp.range(TN, first_range+2) - index = waveIdx * WN + iterWave * SUBWN + TN * idxInWave + i - B_row_store = B_row[iterWave*TN + i].store(Bs[k*BN + index].load(*inp_dep), iterWave, i) - - iterWave = UOp.range(nbIterWaveM, first_range+3) - i = UOp.range(TM, first_range+4) - index = waveIdy * WM + iterWave * SUBWM + TM * idyInWave + i - A_col_store = A_col[iterWave*TM + i].store(As[k*BM_As_stride + index].load(*inp_dep), iterWave, i) - - # do the GEMM math - iterWaveM = UOp.range(nbIterWaveM, first_range+5) - yt = UOp.range(TM, first_range+6) - iterWaveN = UOp.range(nbIterWaveN, first_range+7) - xt = UOp.range(TN, first_range+8) - x = iterWaveN * TN + xt - y = iterWaveM * TM + yt - c_regs_idx = c_regs[y * TN * nbIterWaveN + x] - # sketchy, this should end the kId_range but it doesn't - sink = c_regs_idx.store(c_regs_idx.load(init_store) + A_col[y].load(A_col_store) * B_row[x].load(B_row_store), - iterWaveM, iterWaveN, yt, xt, k) - return sink - - # TODO: kId_range should endrange after a barrier - sink = inner_loop(5, (barrier, regB_store, regA_store)).barrier() - - # load from registers into locals - i = UOp.range(nbReadsB, 14) - index_x = BN * blockIdx_x + rBIdx - index_y = rBIdy + i * strideReadB + kId + BK - Bs_store = Bs[(index_y % BK) * BN + index_x % BN].store(regB[i].load(sink), i, kId_range) - - i = UOp.range(nbReadsA, 15) - index_x = rAIdx + kId + BK - index_y = BM * blockIdx_y + rAIdy + i * strideReadA - As_store = As[(index_x % BK) * BM_As_stride + index_y % BM].store(regA[i].load(sink), i, kId_range) - - # final iteration without the copy - sink = inner_loop(16, (UOp.barrier(Bs_store, As_store),)) - else: - kId_range = UOp.range(N//BK, 0) - kId = kId_range*BK - - # load from globals into locals - i = UOp.range(nbReadsB, 1) - index_x = BN * blockIdx_x + rBIdx - index_y = rBIdy + i * strideReadB + kId - Bs_store = Bs[(index_y % BK) * BN + index_x % BN].store(b[N * index_y + index_x].load(), i) - - i = UOp.range(nbReadsA, 2) - index_x = rAIdx + kId - index_y = BM * blockIdx_y + rAIdy + i * strideReadA - As_store = As[(index_x % BK) * BM_As_stride + index_y % BM].store(a[N * index_y + index_x].load(), i) - - barrier = UOp.barrier(As_store, Bs_store) - - k = UOp.range(BK, 3) - - # load from locals into registers - iterWave = UOp.range(nbIterWaveN, 4) - i = UOp.range(TN, 5) - index = waveIdx * WN + iterWave * SUBWN + TN * idxInWave + i - B_row_store = B_row[iterWave*TN + i].store(Bs[k*BN + index].load(barrier), iterWave, i) - - iterWave = UOp.range(nbIterWaveM, 6) - i = UOp.range(TM, 7) - index = waveIdy * WM + iterWave * SUBWM + TM * idyInWave + i - A_col_store = A_col[iterWave*TM + i].store(As[k*BM_As_stride + index].load(barrier), iterWave, i) - - # do the GEMM math - iterWaveM = UOp.range(nbIterWaveM, 8) - yt = UOp.range(TM, 9) - iterWaveN = UOp.range(nbIterWaveN, 10) - xt = UOp.range(TN, 12) - x = iterWaveN * TN + xt - y = iterWaveM * TM + yt - c_regs_idx = c_regs[y * TN * nbIterWaveN + x] - sink = c_regs_idx.store(c_regs_idx.load(init_store) + A_col[y].load(A_col_store) * B_row[x].load(B_row_store), - iterWaveM, iterWaveN, yt, xt, k, kId_range) - - # store c_regs into c - iterWaveM = UOp.range(nbIterWaveM, 1000) - yt = UOp.range(TM, 1001) - iterWaveN = UOp.range(nbIterWaveN, 1002) - xt = UOp.range(TN, 1003) - xOut = blockIdx_x * BN + waveIdx * WN + iterWaveN * SUBWN + TN * idxInWave - yOut = blockIdx_y * BM + waveIdy * WM + iterWaveM * SUBWM + TM * idyInWave - indexC = N * (yOut + yt) + xOut + xt - sink = c[indexC].store(c_regs[TN * nbIterWaveN * (iterWaveM * TM + yt) + (iterWaveN * TN + xt)].load(sink), - iterWaveM, iterWaveN, yt, xt) - - return sink.sink(arg=KernelInfo(name="tinygemm")) + GlobalCounters.reset() + with Context(DEBUG=2): + tc = (a @ b).realize() + with Context(DEBUG=0): + err = (hc - tc).square().mean().item() + print(f"mean squared error {err}") + if err > 1e-06: + raise RuntimeError("matmul is wrong!") if __name__ == "__main__": - HL = getenv("HL") - if HL == 3: hprg = rangeify_kernel3() - elif HL == 2: hprg = top_spec_kernel3() - elif HL == 1: hprg = hl_spec_kernel3() - else: hprg = hand_spec_kernel3() - if HL == 3: - with Context(RANGEIFY=1, BLOCK_REORDER=0): - prg = get_program(hprg, Device.default.renderer) - else: - prg = get_program(hprg, Device.default.renderer) - print(prg.src) - if getenv("SRC"): exit(0) - hrunner = CompiledRunner(prg) - - a = Tensor.randn(N, N).realize() - b = Tensor.randn(N, N).realize() - hc = Tensor.zeros(N, N).contiguous().realize() - - GlobalCounters.reset() - with Context(DEBUG=2): - for _ in range(run_count): tc = (a@b).realize() - - GlobalCounters.reset() - buffers = [hc.uop.buffer, a.uop.buffer, b.uop.buffer] - ei = ExecItem(hrunner, buffers) - with Context(DEBUG=2): - for _ in range(run_count): ei.run(wait=True) - err = (hc-tc).square().mean().item() - print(f"hrunner {err}") - if err > 1e-06: raise RuntimeError("matmul is wrong!") + test_matmul(hand_spec_kernel3(), N=N) diff --git a/extra/gemm/max_matmul.py b/extra/gemm/max_matmul.py index 5041497839..0d1bb9e7c5 100644 --- a/extra/gemm/max_matmul.py +++ b/extra/gemm/max_matmul.py @@ -1,17 +1,11 @@ import numpy as np, os from tinygrad.helpers import getenv, flat_mv from tinygrad import dtypes -from typing import Optional, List, Tuple, cast, Dict, Final, DefaultDict, Self from tinygrad.engine.realize import get_program # for copied uops -from tinygrad.codegen.opt.kernel import Kernel, KernelOptError -from tinygrad.uop.ops import UOp, Ops, BinaryOps, UnaryOps, TernaryOps, KernelInfo -from tinygrad.codegen.opt.search import Opt, OptOps -from tinygrad import Device, dtypes, Tensor -from tinygrad.dtype import PtrDType, DType, DTYPES_DICT -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View +from tinygrad import dtypes +from tinygrad.dtype import DTYPES_DICT script_dir = os.path.dirname(os.path.abspath(__file__)) @@ -53,12 +47,6 @@ def randoms(): nc = nc.astype(np.bfloat16 if DTYPE_IN == dtypes.bfloat16 else np.float16) return na, nb, nc -def ast_to_cuda_prog(compiler, ast, opts): - k = Kernel(ast) - k.apply_opts(opts) - p = get_program(k.ast, k.opts, k.applied_opts) - return CUDAProgram(device, p.function_name, compiler.compile(p.src)) - if __name__ == "__main__": print(f"gemm variation: {GEMM_VARIATION=} {M=} {N=} {K=} {DTYPE_IN=} {DTYPE_OUT=} {DTYPE_ACC=}") prog, global_size, local_size = None, None, None @@ -189,11 +177,11 @@ if __name__ == "__main__": tms = [] na, nb, nc = randoms() - cudaalloc.copyin(a, bytearray(na)) - cudaalloc.copyin(b, bytearray(nb)) + cudaalloc._copyin(a, memoryview(bytearray(na))) + cudaalloc._copyin(b, memoryview(bytearray(nb))) for i in range(CNT): tms.append(prog(*args, **kwargs)) - cudaalloc.copyout(flat_mv(nc.data), c) + cudaalloc._copyout(flat_mv(nc.data), c) comp = na.astype(np.float32) @ nb.astype(np.float32) result = nc.reshape(M, N).astype(np.float32) diff --git a/extra/gemm/metal_uop_matmul.py b/extra/gemm/metal_uop_matmul.py new file mode 100644 index 0000000000..a2d619b45e --- /dev/null +++ b/extra/gemm/metal_uop_matmul.py @@ -0,0 +1,42 @@ +from tinygrad import UOp, dtypes +from tinygrad.uop.ops import AxisType, Ops, KernelInfo, AddrSpace +from extra.gemm.amd_uop_matmul import test_matmul + +N = 2048 + +# metal has an 8x8 tensor core. this is the indexing +def mat_idx(buf, g0, g1, warp, u): + l = [(warp//2**i)%2 for i in range(5)] + return buf[g0, l[4]*4 + l[2]*2 + l[1], g1, l[3]*4 + l[0]*2 + u] + +def hand_spec_tc_cores(): + gx = UOp.special(N // 8, "gidx0") + gy = UOp.special(N // 8, "gidx1") + warp = UOp.special(32, "lidx0") + + c = UOp.placeholder((N, N), dtypes.float, slot=0).reshape((N//8, 8, N//8, 8)) + a = UOp.placeholder((N, N), dtypes.float, slot=1).reshape((N//8, 8, N//8, 8)) + b = UOp.placeholder((N, N), dtypes.float, slot=2).reshape((N//8, 8, N//8, 8)) + + gk = UOp.range(N // 8, 0, AxisType.REDUCE) + + a_tc = UOp.vectorize(*[mat_idx(a, gx, gk, warp, i) for i in range(2)]) + b_tc = UOp.vectorize(*[mat_idx(b, gk, gy, warp, i) for i in range(2)]) + + acc = UOp.placeholder((2,), dtypes.float, slot=0, addrspace=AddrSpace.REG) + acc = acc[0].set(0.0) + acc = acc[1].set(0.0) + + # TODO: make this simple + wmma_arg = ('WMMA_8_8_8_float_float', (8, 8, 8), dtypes.float, dtypes.float, 'METAL', 32, (((3, 2),), ((3, 2),), ((3, 2),)), ()) + + acc_load = UOp.vectorize(acc.after(gk)[0], acc.after(gk)[1]) + out = UOp(Ops.WMMA, dtypes.float.vec(2), (a_tc, b_tc, acc_load), arg=wmma_arg) + + end_loop = UOp.group(*[acc[i].store(out.gep(i)) for i in range(2)]).end(gk) + + sink = UOp.group(*[mat_idx(c.after(end_loop), gx, gy, warp, i).store(acc[i]) for i in range(2)]) + return sink.sink(arg=KernelInfo(name="custom_metal_matmul", opts_to_apply=())).simplify() + +if __name__ == "__main__": + test_matmul(hand_spec_tc_cores(), N=N) diff --git a/extra/gemm/mi350x_uop_matmul.py b/extra/gemm/mi350x_uop_matmul.py new file mode 100644 index 0000000000..8aba22eb19 --- /dev/null +++ b/extra/gemm/mi350x_uop_matmul.py @@ -0,0 +1,229 @@ +import os +import numpy as np +np.set_printoptions(linewidth=1000000) +os.environ["AMD_LLVM"] = "0" + +from tinygrad import Tensor, Context, dtypes, UOp, GlobalCounters +from tinygrad.helpers import DEBUG, getenv +from tinygrad.dtype import AddrSpace +from tinygrad.uop.ops import AxisType, KernelInfo, Ops + +WARP_SIZE = 64 + +# Reg tile sizes (tensor cores) +TC_M = 16 +TC_N = 16 +TC_K = 32 + +# 1024 matrix cores +# 16 cycle mfma +# 2.2 GHz +# 16x16x32x2 FLOPS/mma = 16384 +# 2.2*1e9*16384*1024/16*1e-12 TFLOPS = 2306 TFLOPS + +#N,M,K = 256,256,64 +N,M,K = 4096,4096,4096 + +# Threadblock tile sizes (block-level tile of C that a block computes) +#BLOCK_M = 128 # rows of C (M-dim) per block +#BLOCK_N = 128 # columns of C (N-dim) per block +#BLOCK_K = 128 # K-slice per block iteration + +BLOCK_M = 64 +BLOCK_N = 64 +BLOCK_K = 128 + +WARPGROUP_SIZE = 1 +BLOCK_M = BLOCK_M * WARPGROUP_SIZE + +# TODO: improve the syntax of this. better syntax, faster iteration +# -- DONE: add working slice a[gx, :, i] -> shape of the : (aka (16,16,32) becomes (16,)) +# -- DONE(ish): add argfix to movement (traits shared with Tensor) +# -- fix WMMA to not require all the junk +# -- improve syntax for vectorized loads/stores (both with DEVECTORIZE and without) +# -- DONE: be able to use CONTRACT on a range +# -- fix upcasted RANGE on an already vectorized buffer +# -- improve "all ranges not ended error" / fix the bug with after on ended ranges (if you are after end of range, range is closed) + +CUS_PER_GPU = 256 +assert ((M//BLOCK_M) * (N//BLOCK_N)) >= CUS_PER_GPU, "not enough globals" + +def custom_gemm(C:UOp, A:UOp, B:UOp) -> UOp: + # A = (M x K) + # B = (K x N) + # C = (M x N) + + # check it's proper matmul + assert C.shape[0] == A.shape[0] + assert C.shape[1] == B.shape[1] + assert A.shape[1] == B.shape[0] + + gx, gy = UOp.special(M//BLOCK_M, "gidx0"), UOp.special(N//BLOCK_N, "gidx1") + warp = UOp.special(WARP_SIZE, "lidx0") + warpgroup = UOp.special(WARPGROUP_SIZE, "lidx1") + + # generic copy logic (not good) + def generic_copy(glbl, gargs, lcl, rng): + # Fully coalesced 128-bit loads/stores. + INNER_SIZE = 8 + cp_i = UOp.range(lcl.size//(WARPGROUP_SIZE*WARP_SIZE*INNER_SIZE), rng) + cp_inner = UOp.range(INNER_SIZE, rng+1, AxisType.UPCAST) + idx_i = cp_i*WARPGROUP_SIZE*WARP_SIZE*INNER_SIZE + warpgroup*WARP_SIZE*INNER_SIZE + warp*INNER_SIZE + cp_inner + return lcl[idx_i].store(glbl[*gargs, idx_i]).end(cp_i, cp_inner) + + # split out the globals into blocks + C = C.reshape((M//BLOCK_M, BLOCK_M, N//BLOCK_N, BLOCK_N)) + A = A.reshape((M//BLOCK_M, BLOCK_M, K//BLOCK_K, BLOCK_K)) + B = B.reshape((K//BLOCK_K, BLOCK_K, N//BLOCK_N, BLOCK_N)) + + # this is the big accumulator + acc = UOp.placeholder((BLOCK_N//TC_N, BLOCK_M//TC_M//WARPGROUP_SIZE), dtypes.float.vec(4), 0, AddrSpace.REG) + assert acc.size*WARP_SIZE*WARPGROUP_SIZE*4 == BLOCK_M*BLOCK_N + acc = acc[init_l:=UOp.range(acc.size, 500)].set(UOp.const(dtypes.float.vec(4), 0.0), end=init_l) + + # create locals (note A is permuted, and the stride is changed to avoid bank conflicts) + def make_locals(slot) -> tuple[UOp, UOp]: + BM_As_stride = (BLOCK_M + 1) + BN_Bs_stride = (BLOCK_N + 0) + INNER_SLICE = 8 + As = UOp.placeholder((BLOCK_K//INNER_SLICE, BM_As_stride, INNER_SLICE), dtypes.half, slot=slot, addrspace=AddrSpace.LOCAL) + INNER_SLICE = 1 + Bs = UOp.placeholder((BLOCK_K//INNER_SLICE, BN_Bs_stride, INNER_SLICE), dtypes.half, slot=slot+1, addrspace=AddrSpace.LOCAL) + As = As.permute((0,2,1)).reshape((BLOCK_K, BM_As_stride)).shrink_to((BLOCK_K, BLOCK_M)) + Bs = Bs.permute((0,2,1)).reshape((BLOCK_K, BN_Bs_stride)).shrink_to((BLOCK_K, BLOCK_N)) + return As, Bs + + # load from globals into locals (TODO: use the warpgroup) + + def load_to_locals(l_K_outer_loop:UOp, Asl:UOp, Bsl:UOp, rng:int, barrier=True) -> tuple[UOp, UOp]: + if getenv("FAKE"): + return Asl[0].set(0), Bsl[0].set(0) + else: + pA = A.permute((0,2,1,3)).reshape((M//BLOCK_M, K//BLOCK_K, BLOCK_M*BLOCK_K)) + pas = Asl.permute((1,0)).reshape((BLOCK_M*BLOCK_K,)) + As_store = generic_copy(pA, (gx, l_K_outer_loop), pas, rng) + + pB = B.permute((0,2,1,3)).reshape((K//BLOCK_K, N//BLOCK_N, BLOCK_K*BLOCK_N)) + pbs = Bsl.reshape((BLOCK_K*BLOCK_N,)) + Bs_store = generic_copy(pB, (l_K_outer_loop, gy), pbs, rng+2) + + barrier = UOp.barrier(As_store, Bs_store) if barrier else UOp.group(As_store, Bs_store) + return Asl.after(barrier), Bsl.after(barrier) + + def compute_on_locals(acc:UOp, Asl:UOp, Bsl:UOp, rng:int, afters:tuple[UOp, ...]=()) -> UOp: + K_inner_loop = UOp.range(BLOCK_K//TC_K, rng, AxisType.REDUCE) + + # load from locals into registers + Ar = UOp.placeholder((BLOCK_M//TC_M//WARPGROUP_SIZE,), dtypes.half.vec(8), slot=1, addrspace=AddrSpace.REG) + Br = UOp.placeholder((BLOCK_N//TC_N,), dtypes.half.vec(8), slot=2, addrspace=AddrSpace.REG) + + M_load_loop = UOp.range(BLOCK_M//TC_M//WARPGROUP_SIZE, rng+10) + Asl = Asl.reshape((BLOCK_K//TC_K, TC_K, BLOCK_M//TC_M//WARPGROUP_SIZE, WARPGROUP_SIZE, TC_M)) + load_rng = UOp.range(8, rng+11, axis_type=AxisType.UPCAST) + A_in = Asl[K_inner_loop, (warp//16)*8+load_rng, M_load_loop, warpgroup, warp%16].contract(load_rng) + Ar = Ar[M_load_loop].set(A_in, end=M_load_loop) + + N_load_loop = UOp.range(BLOCK_N//TC_N, rng+20) + Bsl = Bsl.reshape((BLOCK_K//TC_K, TC_K, BLOCK_N//TC_N, TC_N)) + load_rng = UOp.range(8, rng+21, axis_type=AxisType.UPCAST) + B_in = Bsl[K_inner_loop, (warp//16)*8+load_rng, N_load_loop, warp%16].contract(load_rng) + Br = Br[N_load_loop].set(B_in, end=N_load_loop) + + M_inner_loop = UOp.range(BLOCK_M//TC_M//WARPGROUP_SIZE, rng+30) + N_inner_loop = UOp.range(BLOCK_N//TC_N, rng+31) + + # load values + acc_after = acc.after(*afters, M_inner_loop, N_inner_loop, K_inner_loop) + acc_load = acc_after[N_inner_loop, M_inner_loop] + + # do WMMA + wmma_arg = ('WMMA_16_16_32_half_float', (16, 16, 32), dtypes.half, dtypes.float, 'AMD', 64, ((), (), ((3, 2), (2, 2))), ()) + out = UOp(Ops.WMMA, dtypes.float.vec(4), (Ar[M_inner_loop], Br[N_inner_loop], acc_load), arg=wmma_arg) + + # store back the acc + acc_store = acc[N_inner_loop, M_inner_loop].store(out) + return acc_store.end(M_inner_loop, N_inner_loop, K_inner_loop) + + # **** START INNER LOOP ***** + # inner loop -- locals -> regs + + # no pipeline + if not getenv("PIPELINE"): + As, Bs = make_locals(slot=0) + + K_outer_loop = UOp.range(K//BLOCK_K, 0, AxisType.REDUCE) + As, Bs = load_to_locals(K_outer_loop, As, Bs, 1000, barrier=True) + acc_store = compute_on_locals(acc, As, Bs, 1500, afters=(K_outer_loop,)) + acc = acc.after(acc_store.barrier().end(K_outer_loop)) + else: + # this doesn't work + As0, Bs0 = make_locals(slot=0) + As1, Bs1 = make_locals(slot=2) + As0, Bs0 = load_to_locals(0, As0, Bs0, 1000) + + K_outer_loop = UOp.range((K//BLOCK_K-2)//2, 0, AxisType.REDUCE) + As1, Bs1 = load_to_locals(K_outer_loop+1, As1, Bs1, 2000, barrier=False) + acc_store = compute_on_locals(acc, As0, Bs0, 1500, afters=(K_outer_loop,)) + As0, Bs0 = load_to_locals(K_outer_loop+2, As0, Bs0, 3000, barrier=False) + acc_store = compute_on_locals(acc, As1, Bs1, 2500, afters=(acc_store, As0, Bs0)) + acc = acc.after(acc_store.barrier().end(K_outer_loop)) + + #acc_store = compute_on_locals(acc, As0, Bs0, 3500, afters=(acc_store.barrier().end(K_outer_loop))) + """ + As1, Bs1 = load_to_locals(K//BLOCK_K-1, As1, Bs1, 4000) + acc_store = compute_on_locals(acc, As1, Bs1, 4500, afters=(acc_store)) + """ + #acc = acc.after(acc_store) + + # **** END LOOPS ***** + + # store the acc into gmem + cp_i, cp_j = UOp.range(BLOCK_M//TC_M//WARPGROUP_SIZE, 10004), UOp.range(BLOCK_N//TC_N, 10005) + c_load = lambda i: C[gx, cp_i*TC_M*WARPGROUP_SIZE + warpgroup*TC_M + (warp//16)*4+i, gy, cp_j*TC_N + warp%16] + store = UOp.group(*[c_load(i).store(acc[cp_j, cp_i].gep(i)) for i in range(4)]) + store = store.end(cp_i, cp_j) + + return store.sink(arg=KernelInfo(name="custom_gemm", opts_to_apply=())).simplify() + +# simplest WMMA +""" +# init the acc +acc = UOp.placeholder((4,), dtypes.float, 0, AddrSpace.REG) +acc = acc[init_l:=UOp.range(4, 1)].set(0.0, end=init_l) + +# do the wmma +acc_load = UOp.vectorize(*[acc.after(K_loop)[i] for i in range(4)]) +wmma_arg = ('WMMA_16_16_32_half_float', (16, 16, 32), dtypes.half, dtypes.float, 'AMD', 64, ((), (), ((3, 2), (2, 2))), ()) +out = UOp(Ops.WMMA, dtypes.float.vec(4), (A_in, B_in, acc_load), arg=wmma_arg) + +# store back the acc +acc = acc.after(UOp.group(*[acc[i].store(out.gep(i)) for i in range(4)]).end(K_loop)) + +# store the acc into gmem +store = UOp.group(*[C[gx, (warp//16)*4+i, gy, warp%16].store(acc[i]) for i in range(4)]) +""" + +if __name__ == "__main__": + a = Tensor.randn(M, K, dtype=dtypes.half) + b = Tensor.randn(K, N, dtype=dtypes.half) + + #a = Tensor.zeros(M, K, dtype=dtypes.half).contiguous() + #a[0,16] = 1 + #b = Tensor.ones(K, N, dtype=dtypes.half).contiguous() + + c = Tensor.empty(M, N, dtype=dtypes.float) + with Context(DEBUG=0): Tensor.realize(a,b) + + ref = a.dot(b, dtype=dtypes.float) + ref.realize() + + GlobalCounters.reset() + with Context(DEBUG=max(2, DEBUG.value), DEVECTORIZE=2): + tst = Tensor.custom_kernel(c, a, b, fxn=custom_gemm)[0] + tst.realize() + print(f"{(N*M*K*2 / GlobalCounters.time_sum_s)*1e-12:.2f} REAL TFLOPS") + + with Context(DEBUG=0): + #print(ref.numpy()) + #print(tst.numpy()) + assert Tensor.isclose(ref, tst, atol=1e-2).all().item(), "matrix not close" diff --git a/extra/gemm/simple_matmul.py b/extra/gemm/simple_matmul.py index 0c91005a16..45a359be38 100644 --- a/extra/gemm/simple_matmul.py +++ b/extra/gemm/simple_matmul.py @@ -5,8 +5,10 @@ from tinygrad.dtype import _to_np_dtype from tinygrad.codegen.opt import OptOps from tinygrad.engine.realize import lower_schedule -dtype_in = dtypes.half if getenv("HALF") else dtypes.bfloat16 if getenv("BFLOAT16") else dtypes.float -acc_dtype = dtypes.half if getenv("ACC_HALF") else dtypes.bfloat16 if getenv("ACC_BFLOAT16") else None +dtype_in = (dtypes.half if getenv("HALF") else dtypes.bfloat16 if getenv("BFLOAT16") else + dtypes.fp8e4m3 if getenv("FP8E4M3") else dtypes.fp8e5m2 if getenv("FP8E5M2") else dtypes.float) +acc_dtype = (dtypes.half if getenv("ACC_HALF") else dtypes.bfloat16 if getenv("ACC_BFLOAT16") else + dtypes.fp8e4m3 if getenv("ACC_FP8E4M3") else dtypes.fp8e5m2 if getenv("ACC_FP8E5M2") else None) if getenv("INT"): dtype_in, acc_dtype = dtypes.int8, dtypes.int32 if getenv("UINT"): dtype_in, acc_dtype = dtypes.uint8, dtypes.int32 @@ -14,8 +16,10 @@ N = getenv("N", 4096) M = getenv("M", N) K = getenv("K", N) CNT = getenv("CNT", 10) -ATOL = getenv("ATOL", 1e-4) -RTOL = getenv("RTOL", 3e-2) + +atol, rtol = {dtypes.half:{1e-3, 1e-2}, dtypes.bfloat16:(1e-3, 1e-2), dtypes.fp8e4m3:(1e-1, 1e-1), dtypes.fp8e5m2:(1.0, 5e-1)}.get(dtype_in, (1e-4, 3e-2)) +ATOL, RTOL = getenv("ATOL", atol), getenv("RTOL", rtol) + INT_LOW = getenv("INT_LOW", 0) INT_HIGH = getenv("INT_HIGH", 10) diff --git a/extra/gemm/torch_gemm.py b/extra/gemm/torch_gemm.py index 6dde871980..aee1a8e6aa 100644 --- a/extra/gemm/torch_gemm.py +++ b/extra/gemm/torch_gemm.py @@ -8,19 +8,23 @@ import torch torch.set_num_threads(1) from tinygrad.helpers import getenv CUDA = getenv("CUDA", 1) +MPS = getenv("MPS", 0) +if getenv("FP16_ACC"): torch.backends.cuda.matmul.allow_fp16_accumulation = True -for dtype in [torch.float32, torch.float16]: +for dtype in [torch.float32, torch.float16, torch.bfloat16]: for N in [256, 512, 1024, 2048, 4096]: FLOPS = N*N*N*2 b = torch.rand((N,N), dtype=dtype) c = torch.rand((N,N), dtype=dtype) if CUDA: b,c = b.cuda(),c.cuda() + if MPS: b,c = b.to('mps'),c.to('mps') def torch_prog(b, c): st = time.perf_counter() a = b@c if CUDA: torch.cuda.synchronize() + if MPS: torch.mps.synchronize() return time.perf_counter() - st tm = min([torch_prog(b, c) for _ in range(20)]) print(f"{N*N:10d} {tm*1e6:9.2f} us, would be {FLOPS*1e-9/tm:9.2f} GFLOPS {N:4d}x{N:4d}x{N:4d} matmul in {dtype}") diff --git a/extra/hcq/hcq_smi.py b/extra/hcq/hcq_smi.py index b5cd627d0a..dc883e3f3f 100755 --- a/extra/hcq/hcq_smi.py +++ b/extra/hcq/hcq_smi.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 -from tinygrad.runtime.support.system import System -import argparse, glob, os, re, time, subprocess, sys +import argparse, glob, os, time, subprocess, sys def scan_devs_based_on_lock(prefix:str, args) -> list[str]: target_dev = args.pci_bus if 'pci_bus' in args.__dir__() else "" @@ -12,7 +11,7 @@ def scan_devs_based_on_lock(prefix:str, args) -> list[str]: if os.path.exists(f"/sys/bus/pci/devices/{dev_id}") and dev_id.startswith(target_dev): devs.append(dev_id) return devs -def _do_reset_device(pci_bus): System.pci_reset(pci_bus) +def _do_reset_device(pci_bus): os.system(f"sudo sh -c 'echo 1 > /sys/bus/pci/devices/{pci_bus}/reset'") def _is_module_loaded(name: str) -> bool: return os.path.isdir(f"/sys/module/{name}") def cmd_remove_module(args): diff --git a/extra/hcqfuzz/tests/bert.py b/extra/hcqfuzz/tests/bert.py index 4514b74556..1ac72ac7c6 100644 --- a/extra/hcqfuzz/tests/bert.py +++ b/extra/hcqfuzz/tests/bert.py @@ -7,7 +7,6 @@ bert_train_params = { "GPUS": 6, "BS": 96, "EVAL_BS": 96, - "FUSE_ARANGE": 1, "BASEDIR": "/raid/datasets/wiki", } diff --git a/extra/hcqfuzz/tools.py b/extra/hcqfuzz/tools.py index 2f58528136..5b9b1d9504 100644 --- a/extra/hcqfuzz/tools.py +++ b/extra/hcqfuzz/tools.py @@ -51,11 +51,15 @@ def create_report(dev, test, result, stdout, stderr): dmesg_output = subprocess.check_output(["sudo", "dmesg", "--ctime", "--color=never"], text=True) with open(dmesg_path, "w") as f: f.write(dmesg_output) + env_vars = " ".join(f"{k}={v}" for k, v in test.env.items()) + reproduce_cmd = f"{env_vars} {test.cmd}" + summary_path = os.path.join(report_path, "summary.txt") with open(summary_path, "w") as f: f.write(f"Test: {test.name()}\n") f.write(f"Dev params: {vars(dev)}\n") f.write(f"Test params: {vars(test)}\n") + f.write(f"Reproduce cmd: {reproduce_cmd}\n") f.write(f"Exit Code: {result}\n") print(f"Crash report saved to {report_path}") diff --git a/extra/hip_gpu_driver/hip_ioctl.py b/extra/hip_gpu_driver/hip_ioctl.py index 20c4f3248a..fcb3a9f2da 100644 --- a/extra/hip_gpu_driver/hip_ioctl.py +++ b/extra/hip_gpu_driver/hip_ioctl.py @@ -50,7 +50,7 @@ def ioctls_from_header(): hdr = (pathlib.Path(__file__).parent / "kfd_ioctl.h").read_text().replace("\\\n", "") pattern = r'#define\s+(AMDKFD_IOC_[A-Z0-9_]+)\s+AMDKFD_IOW?R?\((0x[0-9a-fA-F]+),\s+struct\s([A-Za-z0-9_]+)\)' matches = re.findall(pattern, hdr, re.MULTILINE) - return {int(nr, 0x10):(name, getattr(kfd_ioctl, "struct_"+sname)) for name, nr, sname in matches} + return {int(nr, 0x10):(name, getattr(kfd_ioctl, "struct_"+sname, None)) for name, nr, sname in matches} nrs = ioctls_from_header() @ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulong, ctypes.c_void_p) diff --git a/extra/hip_gpu_driver/kfd_ioctl.h b/extra/hip_gpu_driver/kfd_ioctl.h index af96af174d..4b2c16ad22 100644 --- a/extra/hip_gpu_driver/kfd_ioctl.h +++ b/extra/hip_gpu_driver/kfd_ioctl.h @@ -32,9 +32,20 @@ * - 1.4 - Indicate new SRAM EDC bit in device properties * - 1.5 - Add SVM API * - 1.6 - Query clear flags in SVM get_attr API + * - 1.7 - Checkpoint Restore (CRIU) API + * - 1.8 - CRIU - Support for SDMA transfers with GTT BOs + * - 1.9 - Add available memory ioctl + * - 1.10 - Add SMI profiler event log + * - 1.11 - Add unified memory for ctx save/restore area + * - 1.12 - Add DMA buf export ioctl + * - 1.13 - Add debugger API + * - 1.14 - Update kfd_event_data + * - 1.15 - Enable managing mappings in compute VMs with GEM_VA ioctl + * - 1.16 - Add contiguous VRAM allocation flag + * - 1.17 - Add SDMA queue creation with target SDMA engine ID */ #define KFD_IOCTL_MAJOR_VERSION 1 -#define KFD_IOCTL_MINOR_VERSION 6 +#define KFD_IOCTL_MINOR_VERSION 17 struct kfd_ioctl_get_version_args { __u32 major_version; /* from KFD */ @@ -46,6 +57,7 @@ struct kfd_ioctl_get_version_args { #define KFD_IOC_QUEUE_TYPE_SDMA 0x1 #define KFD_IOC_QUEUE_TYPE_COMPUTE_AQL 0x2 #define KFD_IOC_QUEUE_TYPE_SDMA_XGMI 0x3 +#define KFD_IOC_QUEUE_TYPE_SDMA_BY_ENG_ID 0x4 #define KFD_MAX_QUEUE_PERCENTAGE 100 #define KFD_MAX_QUEUE_PRIORITY 15 @@ -68,6 +80,8 @@ struct kfd_ioctl_create_queue_args { __u64 ctx_save_restore_address; /* to KFD */ __u32 ctx_save_restore_size; /* to KFD */ __u32 ctl_stack_size; /* to KFD */ + __u32 sdma_engine_id; /* to KFD */ + __u32 pad; }; struct kfd_ioctl_destroy_queue_args { @@ -98,6 +112,38 @@ struct kfd_ioctl_get_queue_wave_state_args { __u32 pad; }; +struct kfd_ioctl_get_available_memory_args { + __u64 available; /* from KFD */ + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_dbg_device_info_entry { + __u64 exception_status; + __u64 lds_base; + __u64 lds_limit; + __u64 scratch_base; + __u64 scratch_limit; + __u64 gpuvm_base; + __u64 gpuvm_limit; + __u32 gpu_id; + __u32 location_id; + __u32 vendor_id; + __u32 device_id; + __u32 revision_id; + __u32 subsystem_vendor_id; + __u32 subsystem_device_id; + __u32 fw_version; + __u32 gfx_target_version; + __u32 simd_count; + __u32 max_waves_per_simd; + __u32 array_count; + __u32 simd_arrays_per_engine; + __u32 num_xcc; + __u32 capability; + __u32 debug_prop; +}; + /* For kfd_ioctl_set_memory_policy_args.default_policy and alternate_policy */ #define KFD_IOC_CACHE_POLICY_COHERENT 0 #define KFD_IOC_CACHE_POLICY_NONCOHERENT 1 @@ -194,6 +240,19 @@ struct kfd_ioctl_dbg_wave_control_args { __u32 buf_size_in_bytes; /*including gpu_id and buf_size */ }; +#define KFD_INVALID_FD 0xffffffff + +struct kfd_ioctl_dbg_trap_args_deprecated { + __u64 exception_mask; /* to KFD */ + __u64 ptr; /* to KFD -- used for pointer arguments: queue arrays */ + __u32 pid; /* to KFD */ + __u32 op; /* to KFD */ + __u32 data1; /* to KFD */ + __u32 data2; /* to KFD */ + __u32 data3; /* to KFD */ + __u32 data4; /* to KFD */ +}; + /* Matching HSA_EVENTTYPE */ #define KFD_IOC_EVENT_SIGNAL 0 #define KFD_IOC_EVENT_NODECHANGE 1 @@ -279,12 +338,20 @@ struct kfd_hsa_hw_exception_data { __u32 gpu_id; }; +/* hsa signal event data */ +struct kfd_hsa_signal_event_data { + __u64 last_event_age; /* to and from KFD */ +}; + /* Event data */ struct kfd_event_data { union { + /* From KFD */ struct kfd_hsa_memory_exception_data memory_exception_data; struct kfd_hsa_hw_exception_data hw_exception_data; - }; /* From KFD */ + /* To and From KFD */ + struct kfd_hsa_signal_event_data signal_event_data; + }; __u64 kfd_event_data_ext; /* pointer to an extension structure for future exception types */ __u32 event_id; /* to KFD */ @@ -355,6 +422,8 @@ struct kfd_ioctl_acquire_vm_args { #define KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM (1 << 27) #define KFD_IOC_ALLOC_MEM_FLAGS_COHERENT (1 << 26) #define KFD_IOC_ALLOC_MEM_FLAGS_UNCACHED (1 << 25) +#define KFD_IOC_ALLOC_MEM_FLAGS_EXT_COHERENT (1 << 24) +#define KFD_IOC_ALLOC_MEM_FLAGS_CONTIGUOUS (1 << 23) /* Allocate memory for later SVM (shared virtual memory) mapping. * @@ -450,6 +519,12 @@ struct kfd_ioctl_import_dmabuf_args { __u32 dmabuf_fd; /* to KFD */ }; +struct kfd_ioctl_export_dmabuf_args { + __u64 handle; /* to KFD */ + __u32 flags; /* to KFD */ + __u32 dmabuf_fd; /* from KFD */ +}; + /* * KFD SMI(System Management Interface) events */ @@ -459,15 +534,277 @@ enum kfd_smi_event { KFD_SMI_EVENT_THERMAL_THROTTLE = 2, KFD_SMI_EVENT_GPU_PRE_RESET = 3, KFD_SMI_EVENT_GPU_POST_RESET = 4, + KFD_SMI_EVENT_MIGRATE_START = 5, + KFD_SMI_EVENT_MIGRATE_END = 6, + KFD_SMI_EVENT_PAGE_FAULT_START = 7, + KFD_SMI_EVENT_PAGE_FAULT_END = 8, + KFD_SMI_EVENT_QUEUE_EVICTION = 9, + KFD_SMI_EVENT_QUEUE_RESTORE = 10, + KFD_SMI_EVENT_UNMAP_FROM_GPU = 11, + + /* + * max event number, as a flag bit to get events from all processes, + * this requires super user permission, otherwise will not be able to + * receive event from any process. Without this flag to receive events + * from same process. + */ + KFD_SMI_EVENT_ALL_PROCESS = 64 +}; + +/* The reason of the page migration event */ +enum KFD_MIGRATE_TRIGGERS { + KFD_MIGRATE_TRIGGER_PREFETCH, /* Prefetch to GPU VRAM or system memory */ + KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, /* GPU page fault recover */ + KFD_MIGRATE_TRIGGER_PAGEFAULT_CPU, /* CPU page fault recover */ + KFD_MIGRATE_TRIGGER_TTM_EVICTION /* TTM eviction */ +}; + +/* The reason of user queue evition event */ +enum KFD_QUEUE_EVICTION_TRIGGERS { + KFD_QUEUE_EVICTION_TRIGGER_SVM, /* SVM buffer migration */ + KFD_QUEUE_EVICTION_TRIGGER_USERPTR, /* userptr movement */ + KFD_QUEUE_EVICTION_TRIGGER_TTM, /* TTM move buffer */ + KFD_QUEUE_EVICTION_TRIGGER_SUSPEND, /* GPU suspend */ + KFD_QUEUE_EVICTION_CRIU_CHECKPOINT, /* CRIU checkpoint */ + KFD_QUEUE_EVICTION_CRIU_RESTORE /* CRIU restore */ +}; + +/* The reason of unmap buffer from GPU event */ +enum KFD_SVM_UNMAP_TRIGGERS { + KFD_SVM_UNMAP_TRIGGER_MMU_NOTIFY, /* MMU notifier CPU buffer movement */ + KFD_SVM_UNMAP_TRIGGER_MMU_NOTIFY_MIGRATE,/* MMU notifier page migration */ + KFD_SVM_UNMAP_TRIGGER_UNMAP_FROM_CPU /* Unmap to free the buffer */ }; #define KFD_SMI_EVENT_MASK_FROM_INDEX(i) (1ULL << ((i) - 1)) +#define KFD_SMI_EVENT_MSG_SIZE 96 struct kfd_ioctl_smi_events_args { __u32 gpuid; /* to KFD */ __u32 anon_fd; /* from KFD */ }; +/** + * kfd_ioctl_spm_op - SPM ioctl operations + * + * @KFD_IOCTL_SPM_OP_ACQUIRE: acquire exclusive access to SPM + * @KFD_IOCTL_SPM_OP_RELEASE: release exclusive access to SPM + * @KFD_IOCTL_SPM_OP_SET_DEST_BUF: set or unset destination buffer for SPM streaming + */ +enum kfd_ioctl_spm_op { + KFD_IOCTL_SPM_OP_ACQUIRE, + KFD_IOCTL_SPM_OP_RELEASE, + KFD_IOCTL_SPM_OP_SET_DEST_BUF +}; + +/** + * kfd_ioctl_spm_args - Arguments for SPM ioctl + * + * @op[in]: specifies the operation to perform + * @gpu_id[in]: GPU ID of the GPU to profile + * @dst_buf[in]: used for the address of the destination buffer + * in @KFD_IOCTL_SPM_SET_DEST_BUFFER + * @buf_size[in]: size of the destination buffer + * @timeout[in/out]: [in]: timeout in milliseconds, [out]: amount of time left + * `in the timeout window + * @bytes_copied[out]: amount of data that was copied to the previous dest_buf + * @has_data_loss: boolean indicating whether data was lost + * (e.g. due to a ring-buffer overflow) + * + * This ioctl performs different functions depending on the @op parameter. + * + * KFD_IOCTL_SPM_OP_ACQUIRE + * ------------------------ + * + * Acquires exclusive access of SPM on the specified @gpu_id for the calling process. + * This must be called before using KFD_IOCTL_SPM_OP_SET_DEST_BUF. + * + * KFD_IOCTL_SPM_OP_RELEASE + * ------------------------ + * + * Releases exclusive access of SPM on the specified @gpu_id for the calling process, + * which allows another process to acquire it in the future. + * + * KFD_IOCTL_SPM_OP_SET_DEST_BUF + * ----------------------------- + * + * If @dst_buf is NULL, the destination buffer address is unset and copying of counters + * is stopped. + * + * If @dst_buf is not NULL, it specifies the pointer to a new destination buffer. + * @buf_size specifies the size of the buffer. + * + * If @timeout is non-0, the call will wait for up to @timeout ms for the previous + * buffer to be filled. If previous buffer to be filled before timeout, the @timeout + * will be updated value with the time remaining. If the timeout is exceeded, the function + * copies any partial data available into the previous user buffer and returns success. + * The amount of valid data in the previous user buffer is indicated by @bytes_copied. + * + * If @timeout is 0, the function immediately replaces the previous destination buffer + * without waiting for the previous buffer to be filled. That means the previous buffer + * may only be partially filled, and @bytes_copied will indicate how much data has been + * copied to it. + * + * If data was lost, e.g. due to a ring buffer overflow, @has_data_loss will be non-0. + * + * Returns negative error code on failure, 0 on success. + */ +struct kfd_ioctl_spm_args { + __u64 dest_buf; + __u32 buf_size; + __u32 op; + __u32 timeout; + __u32 gpu_id; + __u32 bytes_copied; + __u32 has_data_loss; +}; + +/* + * SVM event tracing via SMI system management interface + * + * Open event file descriptor + * use ioctl AMDKFD_IOC_SMI_EVENTS, pass in gpuid and return a anonymous file + * descriptor to receive SMI events. + * If calling with sudo permission, then file descriptor can be used to receive + * SVM events from all processes, otherwise, to only receive SVM events of same + * process. + * + * To enable the SVM event + * Write event file descriptor with KFD_SMI_EVENT_MASK_FROM_INDEX(event) bitmap + * mask to start record the event to the kfifo, use bitmap mask combination + * for multiple events. New event mask will overwrite the previous event mask. + * KFD_SMI_EVENT_MASK_FROM_INDEX(KFD_SMI_EVENT_ALL_PROCESS) bit requires sudo + * permisson to receive SVM events from all process. + * + * To receive the event + * Application can poll file descriptor to wait for the events, then read event + * from the file into a buffer. Each event is one line string message, starting + * with the event id, then the event specific information. + * + * To decode event information + * The following event format string macro can be used with sscanf to decode + * the specific event information. + * event triggers: the reason to generate the event, defined as enum for unmap, + * eviction and migrate events. + * node, from, to, prefetch_loc, preferred_loc: GPU ID, or 0 for system memory. + * addr: user mode address, in pages + * size: in pages + * pid: the process ID to generate the event + * ns: timestamp in nanosecond-resolution, starts at system boot time but + * stops during suspend + * migrate_update: GPU page fault is recovered by 'M' for migrate, 'U' for update + * rw: 'W' for write page fault, 'R' for read page fault + * rescheduled: 'R' if the queue restore failed and rescheduled to try again + */ +#define KFD_EVENT_FMT_UPDATE_GPU_RESET(reset_seq_num, reset_cause)\ + "%x %s\n", (reset_seq_num), (reset_cause) + +#define KFD_EVENT_FMT_THERMAL_THROTTLING(bitmask, counter)\ + "%llx:%llx\n", (bitmask), (counter) + +#define KFD_EVENT_FMT_VMFAULT(pid, task_name)\ + "%x:%s\n", (pid), (task_name) + +#define KFD_EVENT_FMT_PAGEFAULT_START(ns, pid, addr, node, rw)\ + "%lld -%d @%lx(%x) %c\n", (ns), (pid), (addr), (node), (rw) + +#define KFD_EVENT_FMT_PAGEFAULT_END(ns, pid, addr, node, migrate_update)\ + "%lld -%d @%lx(%x) %c\n", (ns), (pid), (addr), (node), (migrate_update) + +#define KFD_EVENT_FMT_MIGRATE_START(ns, pid, start, size, from, to, prefetch_loc,\ + preferred_loc, migrate_trigger)\ + "%lld -%d @%lx(%lx) %x->%x %x:%x %d\n", (ns), (pid), (start), (size),\ + (from), (to), (prefetch_loc), (preferred_loc), (migrate_trigger) + +#define KFD_EVENT_FMT_MIGRATE_END(ns, pid, start, size, from, to, migrate_trigger)\ + "%lld -%d @%lx(%lx) %x->%x %d\n", (ns), (pid), (start), (size),\ + (from), (to), (migrate_trigger) + +#define KFD_EVENT_FMT_QUEUE_EVICTION(ns, pid, node, evict_trigger)\ + "%lld -%d %x %d\n", (ns), (pid), (node), (evict_trigger) + +#define KFD_EVENT_FMT_QUEUE_RESTORE(ns, pid, node, rescheduled)\ + "%lld -%d %x %c\n", (ns), (pid), (node), (rescheduled) + +#define KFD_EVENT_FMT_UNMAP_FROM_GPU(ns, pid, addr, size, node, unmap_trigger)\ + "%lld -%d @%lx(%lx) %x %d\n", (ns), (pid), (addr), (size),\ + (node), (unmap_trigger) + +/************************************************************************************************** + * CRIU IOCTLs (Checkpoint Restore In Userspace) + * + * When checkpointing a process, the userspace application will perform: + * 1. PROCESS_INFO op to determine current process information. This pauses execution and evicts + * all the queues. + * 2. CHECKPOINT op to checkpoint process contents (BOs, queues, events, svm-ranges) + * 3. UNPAUSE op to un-evict all the queues + * + * When restoring a process, the CRIU userspace application will perform: + * + * 1. RESTORE op to restore process contents + * 2. RESUME op to start the process + * + * Note: Queues are forced into an evicted state after a successful PROCESS_INFO. User + * application needs to perform an UNPAUSE operation after calling PROCESS_INFO. + */ + +enum kfd_criu_op { + KFD_CRIU_OP_PROCESS_INFO, + KFD_CRIU_OP_CHECKPOINT, + KFD_CRIU_OP_UNPAUSE, + KFD_CRIU_OP_RESTORE, + KFD_CRIU_OP_RESUME, +}; + +/** + * kfd_ioctl_criu_args - Arguments perform CRIU operation + * @devices: [in/out] User pointer to memory location for devices information. + * This is an array of type kfd_criu_device_bucket. + * @bos: [in/out] User pointer to memory location for BOs information + * This is an array of type kfd_criu_bo_bucket. + * @priv_data: [in/out] User pointer to memory location for private data + * @priv_data_size: [in/out] Size of priv_data in bytes + * @num_devices: [in/out] Number of GPUs used by process. Size of @devices array. + * @num_bos [in/out] Number of BOs used by process. Size of @bos array. + * @num_objects: [in/out] Number of objects used by process. Objects are opaque to + * user application. + * @pid: [in/out] PID of the process being checkpointed + * @op [in] Type of operation (kfd_criu_op) + * + * Return: 0 on success, -errno on failure + */ +struct kfd_ioctl_criu_args { + __u64 devices; /* Used during ops: CHECKPOINT, RESTORE */ + __u64 bos; /* Used during ops: CHECKPOINT, RESTORE */ + __u64 priv_data; /* Used during ops: CHECKPOINT, RESTORE */ + __u64 priv_data_size; /* Used during ops: PROCESS_INFO, RESTORE */ + __u32 num_devices; /* Used during ops: PROCESS_INFO, RESTORE */ + __u32 num_bos; /* Used during ops: PROCESS_INFO, RESTORE */ + __u32 num_objects; /* Used during ops: PROCESS_INFO, RESTORE */ + __u32 pid; /* Used during ops: PROCESS_INFO, RESUME */ + __u32 op; +}; + +struct kfd_criu_device_bucket { + __u32 user_gpu_id; + __u32 actual_gpu_id; + __u32 drm_fd; + __u32 pad; +}; + +struct kfd_criu_bo_bucket { + __u64 addr; + __u64 size; + __u64 offset; + __u64 restored_offset; /* During restore, updated offset for BO */ + __u32 gpu_id; /* This is the user_gpu_id */ + __u32 alloc_flags; + __u32 dmabuf_fd; + __u32 pad; +}; + +/* CRIU IOCTLs - END */ +/**************************************************************************************************/ /* Register offset inside the remapped mmio page */ enum kfd_mmio_remap { @@ -475,6 +812,39 @@ enum kfd_mmio_remap { KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL = 4, }; +struct kfd_ioctl_ipc_export_handle_args { + __u64 handle; /* to KFD */ + __u32 share_handle[4]; /* from KFD */ + __u32 gpu_id; /* to KFD */ + __u32 flags; /* to KFD */ +}; + +struct kfd_ioctl_ipc_import_handle_args { + __u64 handle; /* from KFD */ + __u64 va_addr; /* to KFD */ + __u64 mmap_offset; /* from KFD */ + __u32 share_handle[4]; /* to KFD */ + __u32 gpu_id; /* to KFD */ + __u32 flags; /* from KFD */ +}; + +struct kfd_ioctl_cross_memory_copy_deprecated_args { + /* to KFD: Process ID of the remote process */ + __u32 pid; + /* to KFD: See above definition */ + __u32 flags; + /* to KFD: Source GPU VM range */ + __u64 src_mem_range_array; + /* to KFD: Size of above array */ + __u64 src_mem_array_size; + /* to KFD: Destination GPU VM range */ + __u64 dst_mem_range_array; + /* to KFD: Size of above array */ + __u64 dst_mem_array_size; + /* from KFD: Total amount of bytes copied */ + __u64 bytes_copied; +}; + /* Guarantee host access to memory */ #define KFD_IOCTL_SVM_FLAG_HOST_ACCESS 0x00000001 /* Fine grained coherency between all devices with access */ @@ -487,6 +857,10 @@ enum kfd_mmio_remap { #define KFD_IOCTL_SVM_FLAG_GPU_EXEC 0x00000010 /* GPUs mostly read, may allow similar optimizations as RO, but writes fault */ #define KFD_IOCTL_SVM_FLAG_GPU_READ_MOSTLY 0x00000020 +/* Keep GPU memory mapping always valid as if XNACK is disable */ +#define KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED 0x00000040 +/* Fine grained coherency between all devices using device-scope atomics */ +#define KFD_IOCTL_SVM_FLAG_EXT_COHERENT 0x00000080 /** * kfd_ioctl_svm_op - SVM ioctl operations @@ -596,7 +970,7 @@ struct kfd_ioctl_svm_args { __u32 op; __u32 nattr; /* Variable length array of attributes */ - struct kfd_ioctl_svm_attribute attrs[0]; + struct kfd_ioctl_svm_attribute attrs[]; }; /** @@ -637,6 +1011,733 @@ struct kfd_ioctl_set_xnack_mode_args { __s32 xnack_enabled; }; +/* Wave launch override modes */ +enum kfd_dbg_trap_override_mode { + KFD_DBG_TRAP_OVERRIDE_OR = 0, + KFD_DBG_TRAP_OVERRIDE_REPLACE = 1 +}; + +/* Wave launch overrides */ +enum kfd_dbg_trap_mask { + KFD_DBG_TRAP_MASK_FP_INVALID = 1, + KFD_DBG_TRAP_MASK_FP_INPUT_DENORMAL = 2, + KFD_DBG_TRAP_MASK_FP_DIVIDE_BY_ZERO = 4, + KFD_DBG_TRAP_MASK_FP_OVERFLOW = 8, + KFD_DBG_TRAP_MASK_FP_UNDERFLOW = 16, + KFD_DBG_TRAP_MASK_FP_INEXACT = 32, + KFD_DBG_TRAP_MASK_INT_DIVIDE_BY_ZERO = 64, + KFD_DBG_TRAP_MASK_DBG_ADDRESS_WATCH = 128, + KFD_DBG_TRAP_MASK_DBG_MEMORY_VIOLATION = 256, + KFD_DBG_TRAP_MASK_TRAP_ON_WAVE_START = (1 << 30), + KFD_DBG_TRAP_MASK_TRAP_ON_WAVE_END = (1 << 31) +}; + +/* Wave launch modes */ +enum kfd_dbg_trap_wave_launch_mode { + KFD_DBG_TRAP_WAVE_LAUNCH_MODE_NORMAL = 0, + KFD_DBG_TRAP_WAVE_LAUNCH_MODE_HALT = 1, + KFD_DBG_TRAP_WAVE_LAUNCH_MODE_DEBUG = 3 +}; + +/* Address watch modes */ +enum kfd_dbg_trap_address_watch_mode { + KFD_DBG_TRAP_ADDRESS_WATCH_MODE_READ = 0, + KFD_DBG_TRAP_ADDRESS_WATCH_MODE_NONREAD = 1, + KFD_DBG_TRAP_ADDRESS_WATCH_MODE_ATOMIC = 2, + KFD_DBG_TRAP_ADDRESS_WATCH_MODE_ALL = 3 +}; + +/* Additional wave settings */ +enum kfd_dbg_trap_flags { + KFD_DBG_TRAP_FLAG_SINGLE_MEM_OP = 1, + KFD_DBG_TRAP_FLAG_SINGLE_ALU_OP = 2, +}; + +/* Trap exceptions */ +enum kfd_dbg_trap_exception_code { + EC_NONE = 0, + /* per queue */ + EC_QUEUE_WAVE_ABORT = 1, + EC_QUEUE_WAVE_TRAP = 2, + EC_QUEUE_WAVE_MATH_ERROR = 3, + EC_QUEUE_WAVE_ILLEGAL_INSTRUCTION = 4, + EC_QUEUE_WAVE_MEMORY_VIOLATION = 5, + EC_QUEUE_WAVE_APERTURE_VIOLATION = 6, + EC_QUEUE_PACKET_DISPATCH_DIM_INVALID = 16, + EC_QUEUE_PACKET_DISPATCH_GROUP_SEGMENT_SIZE_INVALID = 17, + EC_QUEUE_PACKET_DISPATCH_CODE_INVALID = 18, + EC_QUEUE_PACKET_RESERVED = 19, + EC_QUEUE_PACKET_UNSUPPORTED = 20, + EC_QUEUE_PACKET_DISPATCH_WORK_GROUP_SIZE_INVALID = 21, + EC_QUEUE_PACKET_DISPATCH_REGISTER_INVALID = 22, + EC_QUEUE_PACKET_VENDOR_UNSUPPORTED = 23, + EC_QUEUE_PREEMPTION_ERROR = 30, + EC_QUEUE_NEW = 31, + /* per device */ + EC_DEVICE_QUEUE_DELETE = 32, + EC_DEVICE_MEMORY_VIOLATION = 33, + EC_DEVICE_RAS_ERROR = 34, + EC_DEVICE_FATAL_HALT = 35, + EC_DEVICE_NEW = 36, + /* per process */ + EC_PROCESS_RUNTIME = 48, + EC_PROCESS_DEVICE_REMOVE = 49, + EC_MAX +}; + +/* Mask generated by ecode in kfd_dbg_trap_exception_code */ +#define KFD_EC_MASK(ecode) (1ULL << (ecode - 1)) + +/* Masks for exception code type checks below */ +#define KFD_EC_MASK_QUEUE (KFD_EC_MASK(EC_QUEUE_WAVE_ABORT) | \ + KFD_EC_MASK(EC_QUEUE_WAVE_TRAP) | \ + KFD_EC_MASK(EC_QUEUE_WAVE_MATH_ERROR) | \ + KFD_EC_MASK(EC_QUEUE_WAVE_ILLEGAL_INSTRUCTION) | \ + KFD_EC_MASK(EC_QUEUE_WAVE_MEMORY_VIOLATION) | \ + KFD_EC_MASK(EC_QUEUE_WAVE_APERTURE_VIOLATION) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_DIM_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_GROUP_SEGMENT_SIZE_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_CODE_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_RESERVED) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_UNSUPPORTED) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_WORK_GROUP_SIZE_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_REGISTER_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_VENDOR_UNSUPPORTED) | \ + KFD_EC_MASK(EC_QUEUE_PREEMPTION_ERROR) | \ + KFD_EC_MASK(EC_QUEUE_NEW)) +#define KFD_EC_MASK_DEVICE (KFD_EC_MASK(EC_DEVICE_QUEUE_DELETE) | \ + KFD_EC_MASK(EC_DEVICE_RAS_ERROR) | \ + KFD_EC_MASK(EC_DEVICE_FATAL_HALT) | \ + KFD_EC_MASK(EC_DEVICE_MEMORY_VIOLATION) | \ + KFD_EC_MASK(EC_DEVICE_NEW)) +#define KFD_EC_MASK_PROCESS (KFD_EC_MASK(EC_PROCESS_RUNTIME) | \ + KFD_EC_MASK(EC_PROCESS_DEVICE_REMOVE)) +#define KFD_EC_MASK_PACKET (KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_DIM_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_GROUP_SEGMENT_SIZE_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_CODE_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_RESERVED) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_UNSUPPORTED) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_WORK_GROUP_SIZE_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_DISPATCH_REGISTER_INVALID) | \ + KFD_EC_MASK(EC_QUEUE_PACKET_VENDOR_UNSUPPORTED)) + +/* Checks for exception code types for KFD search */ +#define KFD_DBG_EC_IS_VALID(ecode) (ecode > EC_NONE && ecode < EC_MAX) +#define KFD_DBG_EC_TYPE_IS_QUEUE(ecode) \ + (KFD_DBG_EC_IS_VALID(ecode) && !!(KFD_EC_MASK(ecode) & KFD_EC_MASK_QUEUE)) +#define KFD_DBG_EC_TYPE_IS_DEVICE(ecode) \ + (KFD_DBG_EC_IS_VALID(ecode) && !!(KFD_EC_MASK(ecode) & KFD_EC_MASK_DEVICE)) +#define KFD_DBG_EC_TYPE_IS_PROCESS(ecode) \ + (KFD_DBG_EC_IS_VALID(ecode) && !!(KFD_EC_MASK(ecode) & KFD_EC_MASK_PROCESS)) +#define KFD_DBG_EC_TYPE_IS_PACKET(ecode) \ + (KFD_DBG_EC_IS_VALID(ecode) && !!(KFD_EC_MASK(ecode) & KFD_EC_MASK_PACKET)) + + +/* Runtime enable states */ +enum kfd_dbg_runtime_state { + DEBUG_RUNTIME_STATE_DISABLED = 0, + DEBUG_RUNTIME_STATE_ENABLED = 1, + DEBUG_RUNTIME_STATE_ENABLED_BUSY = 2, + DEBUG_RUNTIME_STATE_ENABLED_ERROR = 3 +}; + +/* Runtime enable status */ +struct kfd_runtime_info { + __u64 r_debug; + __u32 runtime_state; + __u32 ttmp_setup; +}; + +/* Enable modes for runtime enable */ +#define KFD_RUNTIME_ENABLE_MODE_ENABLE_MASK 1 +#define KFD_RUNTIME_ENABLE_MODE_TTMP_SAVE_MASK 2 + +/** + * kfd_ioctl_runtime_enable_args - Arguments for runtime enable + * + * Coordinates debug exception signalling and debug device enablement with runtime. + * + * @r_debug - pointer to user struct for sharing information between ROCr and the debuggger + * @mode_mask - mask to set mode + * KFD_RUNTIME_ENABLE_MODE_ENABLE_MASK - enable runtime for debugging, otherwise disable + * KFD_RUNTIME_ENABLE_MODE_TTMP_SAVE_MASK - enable trap temporary setup (ignore on disable) + * @capabilities_mask - mask to notify runtime on what KFD supports + * + * Return - 0 on SUCCESS. + * - EBUSY if runtime enable call already pending. + * - EEXIST if user queues already active prior to call. + * If process is debug enabled, runtime enable will enable debug devices and + * wait for debugger process to send runtime exception EC_PROCESS_RUNTIME + * to unblock - see kfd_ioctl_dbg_trap_args. + * + */ +struct kfd_ioctl_runtime_enable_args { + __u64 r_debug; + __u32 mode_mask; + __u32 capabilities_mask; +}; + +/* Queue information */ +struct kfd_queue_snapshot_entry { + __u64 exception_status; + __u64 ring_base_address; + __u64 write_pointer_address; + __u64 read_pointer_address; + __u64 ctx_save_restore_address; + __u32 queue_id; + __u32 gpu_id; + __u32 ring_size; + __u32 queue_type; + __u32 ctx_save_restore_area_size; + __u32 reserved; +}; + +/* Queue status return for suspend/resume */ +#define KFD_DBG_QUEUE_ERROR_BIT 30 +#define KFD_DBG_QUEUE_INVALID_BIT 31 +#define KFD_DBG_QUEUE_ERROR_MASK (1 << KFD_DBG_QUEUE_ERROR_BIT) +#define KFD_DBG_QUEUE_INVALID_MASK (1 << KFD_DBG_QUEUE_INVALID_BIT) + +/* Context save area header information */ +struct kfd_context_save_area_header { + struct { + __u32 control_stack_offset; + __u32 control_stack_size; + __u32 wave_state_offset; + __u32 wave_state_size; + } wave_state; + __u32 debug_offset; + __u32 debug_size; + __u64 err_payload_addr; + __u32 err_event_id; + __u32 reserved1; +}; + +/* + * Debug operations + * + * For specifics on usage and return values, see documentation per operation + * below. Otherwise, generic error returns apply: + * - ESRCH if the process to debug does not exist. + * + * - EINVAL (with KFD_IOC_DBG_TRAP_ENABLE exempt) if operation + * KFD_IOC_DBG_TRAP_ENABLE has not succeeded prior. + * Also returns this error if GPU hardware scheduling is not supported. + * + * - EPERM (with KFD_IOC_DBG_TRAP_DISABLE exempt) if target process is not + * PTRACE_ATTACHED. KFD_IOC_DBG_TRAP_DISABLE is exempt to allow + * clean up of debug mode as long as process is debug enabled. + * + * - EACCES if any DBG_HW_OP (debug hardware operation) is requested when + * AMDKFD_IOC_RUNTIME_ENABLE has not succeeded prior. + * + * - ENODEV if any GPU does not support debugging on a DBG_HW_OP call. + * + * - Other errors may be returned when a DBG_HW_OP occurs while the GPU + * is in a fatal state. + * + */ +enum kfd_dbg_trap_operations { + KFD_IOC_DBG_TRAP_ENABLE = 0, + KFD_IOC_DBG_TRAP_DISABLE = 1, + KFD_IOC_DBG_TRAP_SEND_RUNTIME_EVENT = 2, + KFD_IOC_DBG_TRAP_SET_EXCEPTIONS_ENABLED = 3, + KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_OVERRIDE = 4, /* DBG_HW_OP */ + KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_MODE = 5, /* DBG_HW_OP */ + KFD_IOC_DBG_TRAP_SUSPEND_QUEUES = 6, /* DBG_HW_OP */ + KFD_IOC_DBG_TRAP_RESUME_QUEUES = 7, /* DBG_HW_OP */ + KFD_IOC_DBG_TRAP_SET_NODE_ADDRESS_WATCH = 8, /* DBG_HW_OP */ + KFD_IOC_DBG_TRAP_CLEAR_NODE_ADDRESS_WATCH = 9, /* DBG_HW_OP */ + KFD_IOC_DBG_TRAP_SET_FLAGS = 10, + KFD_IOC_DBG_TRAP_QUERY_DEBUG_EVENT = 11, + KFD_IOC_DBG_TRAP_QUERY_EXCEPTION_INFO = 12, + KFD_IOC_DBG_TRAP_GET_QUEUE_SNAPSHOT = 13, + KFD_IOC_DBG_TRAP_GET_DEVICE_SNAPSHOT = 14 +}; + +/** + * kfd_ioctl_dbg_trap_enable_args + * + * Arguments for KFD_IOC_DBG_TRAP_ENABLE. + * + * Enables debug session for target process. Call @op KFD_IOC_DBG_TRAP_DISABLE in + * kfd_ioctl_dbg_trap_args to disable debug session. + * + * @exception_mask (IN) - exceptions to raise to the debugger + * @rinfo_ptr (IN) - pointer to runtime info buffer (see kfd_runtime_info) + * @rinfo_size (IN/OUT) - size of runtime info buffer in bytes + * @dbg_fd (IN) - fd the KFD will nofify the debugger with of raised + * exceptions set in exception_mask. + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * Copies KFD saved kfd_runtime_info to @rinfo_ptr on enable. + * Size of kfd_runtime saved by the KFD returned to @rinfo_size. + * - EBADF if KFD cannot get a reference to dbg_fd. + * - EFAULT if KFD cannot copy runtime info to rinfo_ptr. + * - EINVAL if target process is already debug enabled. + * + */ +struct kfd_ioctl_dbg_trap_enable_args { + __u64 exception_mask; + __u64 rinfo_ptr; + __u32 rinfo_size; + __u32 dbg_fd; +}; + +/** + * kfd_ioctl_dbg_trap_send_runtime_event_args + * + * + * Arguments for KFD_IOC_DBG_TRAP_SEND_RUNTIME_EVENT. + * Raises exceptions to runtime. + * + * @exception_mask (IN) - exceptions to raise to runtime + * @gpu_id (IN) - target device id + * @queue_id (IN) - target queue id + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * - ENODEV if gpu_id not found. + * If exception_mask contains EC_PROCESS_RUNTIME, unblocks pending + * AMDKFD_IOC_RUNTIME_ENABLE call - see kfd_ioctl_runtime_enable_args. + * All other exceptions are raised to runtime through err_payload_addr. + * See kfd_context_save_area_header. + */ +struct kfd_ioctl_dbg_trap_send_runtime_event_args { + __u64 exception_mask; + __u32 gpu_id; + __u32 queue_id; +}; + +/** + * kfd_ioctl_dbg_trap_set_exceptions_enabled_args + * + * Arguments for KFD_IOC_SET_EXCEPTIONS_ENABLED + * Set new exceptions to be raised to the debugger. + * + * @exception_mask (IN) - new exceptions to raise the debugger + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + */ +struct kfd_ioctl_dbg_trap_set_exceptions_enabled_args { + __u64 exception_mask; +}; + +/** + * kfd_ioctl_dbg_trap_set_wave_launch_override_args + * + * Arguments for KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_OVERRIDE + * Enable HW exceptions to raise trap. + * + * @override_mode (IN) - see kfd_dbg_trap_override_mode + * @enable_mask (IN/OUT) - reference kfd_dbg_trap_mask. + * IN is the override modes requested to be enabled. + * OUT is referenced in Return below. + * @support_request_mask (IN/OUT) - reference kfd_dbg_trap_mask. + * IN is the override modes requested for support check. + * OUT is referenced in Return below. + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * Previous enablement is returned in @enable_mask. + * Actual override support is returned in @support_request_mask. + * - EINVAL if override mode is not supported. + * - EACCES if trap support requested is not actually supported. + * i.e. enable_mask (IN) is not a subset of support_request_mask (OUT). + * Otherwise it is considered a generic error (see kfd_dbg_trap_operations). + */ +struct kfd_ioctl_dbg_trap_set_wave_launch_override_args { + __u32 override_mode; + __u32 enable_mask; + __u32 support_request_mask; + __u32 pad; +}; + +/** + * kfd_ioctl_dbg_trap_set_wave_launch_mode_args + * + * Arguments for KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_MODE + * Set wave launch mode. + * + * @mode (IN) - see kfd_dbg_trap_wave_launch_mode + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + */ +struct kfd_ioctl_dbg_trap_set_wave_launch_mode_args { + __u32 launch_mode; + __u32 pad; +}; + +/** + * kfd_ioctl_dbg_trap_suspend_queues_ags + * + * Arguments for KFD_IOC_DBG_TRAP_SUSPEND_QUEUES + * Suspend queues. + * + * @exception_mask (IN) - raised exceptions to clear + * @queue_array_ptr (IN) - pointer to array of queue ids (u32 per queue id) + * to suspend + * @num_queues (IN) - number of queues to suspend in @queue_array_ptr + * @grace_period (IN) - wave time allowance before preemption + * per 1K GPU clock cycle unit + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Destruction of a suspended queue is blocked until the queue is + * resumed. This allows the debugger to access queue information and + * the its context save area without running into a race condition on + * queue destruction. + * Automatically copies per queue context save area header information + * into the save area base + * (see kfd_queue_snapshot_entry and kfd_context_save_area_header). + * + * Return - Number of queues suspended on SUCCESS. + * . KFD_DBG_QUEUE_ERROR_MASK and KFD_DBG_QUEUE_INVALID_MASK masked + * for each queue id in @queue_array_ptr array reports unsuccessful + * suspend reason. + * KFD_DBG_QUEUE_ERROR_MASK = HW failure. + * KFD_DBG_QUEUE_INVALID_MASK = queue does not exist, is new or + * is being destroyed. + */ +struct kfd_ioctl_dbg_trap_suspend_queues_args { + __u64 exception_mask; + __u64 queue_array_ptr; + __u32 num_queues; + __u32 grace_period; +}; + +/** + * kfd_ioctl_dbg_trap_resume_queues_args + * + * Arguments for KFD_IOC_DBG_TRAP_RESUME_QUEUES + * Resume queues. + * + * @queue_array_ptr (IN) - pointer to array of queue ids (u32 per queue id) + * to resume + * @num_queues (IN) - number of queues to resume in @queue_array_ptr + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - Number of queues resumed on SUCCESS. + * KFD_DBG_QUEUE_ERROR_MASK and KFD_DBG_QUEUE_INVALID_MASK mask + * for each queue id in @queue_array_ptr array reports unsuccessful + * resume reason. + * KFD_DBG_QUEUE_ERROR_MASK = HW failure. + * KFD_DBG_QUEUE_INVALID_MASK = queue does not exist. + */ +struct kfd_ioctl_dbg_trap_resume_queues_args { + __u64 queue_array_ptr; + __u32 num_queues; + __u32 pad; +}; + +/** + * kfd_ioctl_dbg_trap_set_node_address_watch_args + * + * Arguments for KFD_IOC_DBG_TRAP_SET_NODE_ADDRESS_WATCH + * Sets address watch for device. + * + * @address (IN) - watch address to set + * @mode (IN) - see kfd_dbg_trap_address_watch_mode + * @mask (IN) - watch address mask + * @gpu_id (IN) - target gpu to set watch point + * @id (OUT) - watch id allocated + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * Allocated watch ID returned to @id. + * - ENODEV if gpu_id not found. + * - ENOMEM if watch IDs can be allocated + */ +struct kfd_ioctl_dbg_trap_set_node_address_watch_args { + __u64 address; + __u32 mode; + __u32 mask; + __u32 gpu_id; + __u32 id; +}; + +/** + * kfd_ioctl_dbg_trap_clear_node_address_watch_args + * + * Arguments for KFD_IOC_DBG_TRAP_CLEAR_NODE_ADDRESS_WATCH + * Clear address watch for device. + * + * @gpu_id (IN) - target device to clear watch point + * @id (IN) - allocated watch id to clear + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * - ENODEV if gpu_id not found. + * - EINVAL if watch ID has not been allocated. + */ +struct kfd_ioctl_dbg_trap_clear_node_address_watch_args { + __u32 gpu_id; + __u32 id; +}; + +/** + * kfd_ioctl_dbg_trap_set_flags_args + * + * Arguments for KFD_IOC_DBG_TRAP_SET_FLAGS + * Sets flags for wave behaviour. + * + * @flags (IN/OUT) - IN = flags to enable, OUT = flags previously enabled + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * - EACCESS if any debug device does not allow flag options. + */ +struct kfd_ioctl_dbg_trap_set_flags_args { + __u32 flags; + __u32 pad; +}; + +/** + * kfd_ioctl_dbg_trap_query_debug_event_args + * + * Arguments for KFD_IOC_DBG_TRAP_QUERY_DEBUG_EVENT + * + * Find one or more raised exceptions. This function can return multiple + * exceptions from a single queue or a single device with one call. To find + * all raised exceptions, this function must be called repeatedly until it + * returns -EAGAIN. Returned exceptions can optionally be cleared by + * setting the corresponding bit in the @exception_mask input parameter. + * However, clearing an exception prevents retrieving further information + * about it with KFD_IOC_DBG_TRAP_QUERY_EXCEPTION_INFO. + * + * @exception_mask (IN/OUT) - exception to clear (IN) and raised (OUT) + * @gpu_id (OUT) - gpu id of exceptions raised + * @queue_id (OUT) - queue id of exceptions raised + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on raised exception found + * Raised exceptions found are returned in @exception mask + * with reported source id returned in @gpu_id or @queue_id. + * - EAGAIN if no raised exception has been found + */ +struct kfd_ioctl_dbg_trap_query_debug_event_args { + __u64 exception_mask; + __u32 gpu_id; + __u32 queue_id; +}; + +/** + * kfd_ioctl_dbg_trap_query_exception_info_args + * + * Arguments KFD_IOC_DBG_TRAP_QUERY_EXCEPTION_INFO + * Get additional info on raised exception. + * + * @info_ptr (IN) - pointer to exception info buffer to copy to + * @info_size (IN/OUT) - exception info buffer size (bytes) + * @source_id (IN) - target gpu or queue id + * @exception_code (IN) - target exception + * @clear_exception (IN) - clear raised @exception_code exception + * (0 = false, 1 = true) + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * If @exception_code is EC_DEVICE_MEMORY_VIOLATION, copy @info_size(OUT) + * bytes of memory exception data to @info_ptr. + * If @exception_code is EC_PROCESS_RUNTIME, copy saved + * kfd_runtime_info to @info_ptr. + * Actual required @info_ptr size (bytes) is returned in @info_size. + */ +struct kfd_ioctl_dbg_trap_query_exception_info_args { + __u64 info_ptr; + __u32 info_size; + __u32 source_id; + __u32 exception_code; + __u32 clear_exception; +}; + +/** + * kfd_ioctl_dbg_trap_get_queue_snapshot_args + * + * Arguments KFD_IOC_DBG_TRAP_GET_QUEUE_SNAPSHOT + * Get queue information. + * + * @exception_mask (IN) - exceptions raised to clear + * @snapshot_buf_ptr (IN) - queue snapshot entry buffer (see kfd_queue_snapshot_entry) + * @num_queues (IN/OUT) - number of queue snapshot entries + * The debugger specifies the size of the array allocated in @num_queues. + * KFD returns the number of queues that actually existed. If this is + * larger than the size specified by the debugger, KFD will not overflow + * the array allocated by the debugger. + * + * @entry_size (IN/OUT) - size per entry in bytes + * The debugger specifies sizeof(struct kfd_queue_snapshot_entry) in + * @entry_size. KFD returns the number of bytes actually populated per + * entry. The debugger should use the KFD_IOCTL_MINOR_VERSION to determine, + * which fields in struct kfd_queue_snapshot_entry are valid. This allows + * growing the ABI in a backwards compatible manner. + * Note that entry_size(IN) should still be used to stride the snapshot buffer in the + * event that it's larger than actual kfd_queue_snapshot_entry. + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * Copies @num_queues(IN) queue snapshot entries of size @entry_size(IN) + * into @snapshot_buf_ptr if @num_queues(IN) > 0. + * Otherwise return @num_queues(OUT) queue snapshot entries that exist. + */ +struct kfd_ioctl_dbg_trap_queue_snapshot_args { + __u64 exception_mask; + __u64 snapshot_buf_ptr; + __u32 num_queues; + __u32 entry_size; +}; + +/** + * kfd_ioctl_dbg_trap_get_device_snapshot_args + * + * Arguments for KFD_IOC_DBG_TRAP_GET_DEVICE_SNAPSHOT + * Get device information. + * + * @exception_mask (IN) - exceptions raised to clear + * @snapshot_buf_ptr (IN) - pointer to snapshot buffer (see kfd_dbg_device_info_entry) + * @num_devices (IN/OUT) - number of debug devices to snapshot + * The debugger specifies the size of the array allocated in @num_devices. + * KFD returns the number of devices that actually existed. If this is + * larger than the size specified by the debugger, KFD will not overflow + * the array allocated by the debugger. + * + * @entry_size (IN/OUT) - size per entry in bytes + * The debugger specifies sizeof(struct kfd_dbg_device_info_entry) in + * @entry_size. KFD returns the number of bytes actually populated. The + * debugger should use KFD_IOCTL_MINOR_VERSION to determine, which fields + * in struct kfd_dbg_device_info_entry are valid. This allows growing the + * ABI in a backwards compatible manner. + * Note that entry_size(IN) should still be used to stride the snapshot buffer in the + * event that it's larger than actual kfd_dbg_device_info_entry. + * + * Generic errors apply (see kfd_dbg_trap_operations). + * Return - 0 on SUCCESS. + * Copies @num_devices(IN) device snapshot entries of size @entry_size(IN) + * into @snapshot_buf_ptr if @num_devices(IN) > 0. + * Otherwise return @num_devices(OUT) queue snapshot entries that exist. + */ +struct kfd_ioctl_dbg_trap_device_snapshot_args { + __u64 exception_mask; + __u64 snapshot_buf_ptr; + __u32 num_devices; + __u32 entry_size; +}; + +/** + * kfd_ioctl_dbg_trap_args + * + * Arguments to debug target process. + * + * @pid - target process to debug + * @op - debug operation (see kfd_dbg_trap_operations) + * + * @op determines which union struct args to use. + * Refer to kern docs for each kfd_ioctl_dbg_trap_*_args struct. + */ +struct kfd_ioctl_dbg_trap_args { + __u32 pid; + __u32 op; + + union { + struct kfd_ioctl_dbg_trap_enable_args enable; + struct kfd_ioctl_dbg_trap_send_runtime_event_args send_runtime_event; + struct kfd_ioctl_dbg_trap_set_exceptions_enabled_args set_exceptions_enabled; + struct kfd_ioctl_dbg_trap_set_wave_launch_override_args launch_override; + struct kfd_ioctl_dbg_trap_set_wave_launch_mode_args launch_mode; + struct kfd_ioctl_dbg_trap_suspend_queues_args suspend_queues; + struct kfd_ioctl_dbg_trap_resume_queues_args resume_queues; + struct kfd_ioctl_dbg_trap_set_node_address_watch_args set_node_address_watch; + struct kfd_ioctl_dbg_trap_clear_node_address_watch_args clear_node_address_watch; + struct kfd_ioctl_dbg_trap_set_flags_args set_flags; + struct kfd_ioctl_dbg_trap_query_debug_event_args query_debug_event; + struct kfd_ioctl_dbg_trap_query_exception_info_args query_exception_info; + struct kfd_ioctl_dbg_trap_queue_snapshot_args queue_snapshot; + struct kfd_ioctl_dbg_trap_device_snapshot_args device_snapshot; + }; +}; + +/** + * kfd_ioctl_pc_sample_op - PC Sampling ioctl operations + * + * @KFD_IOCTL_PCS_OP_QUERY_CAPABILITIES: Query device PC Sampling capabilities + * @KFD_IOCTL_PCS_OP_CREATE: Register this process with a per-device PC sampler instance + * @KFD_IOCTL_PCS_OP_DESTROY: Unregister from a previously registered PC sampler instance + * @KFD_IOCTL_PCS_OP_START: Process begins taking samples from a previously registered PC sampler instance + * @KFD_IOCTL_PCS_OP_STOP: Process stops taking samples from a previously registered PC sampler instance + */ +enum kfd_ioctl_pc_sample_op { + KFD_IOCTL_PCS_OP_QUERY_CAPABILITIES, + KFD_IOCTL_PCS_OP_CREATE, + KFD_IOCTL_PCS_OP_DESTROY, + KFD_IOCTL_PCS_OP_START, + KFD_IOCTL_PCS_OP_STOP, +}; + +/* Values have to be a power of 2*/ +#define KFD_IOCTL_PCS_FLAG_POWER_OF_2 0x00000001 + +enum kfd_ioctl_pc_sample_method { + KFD_IOCTL_PCS_METHOD_HOSTTRAP = 1, + KFD_IOCTL_PCS_METHOD_STOCHASTIC, +}; + +enum kfd_ioctl_pc_sample_type { + KFD_IOCTL_PCS_TYPE_TIME_US, + KFD_IOCTL_PCS_TYPE_CLOCK_CYCLES, + KFD_IOCTL_PCS_TYPE_INSTRUCTIONS +}; + +struct kfd_pc_sample_info { + __u64 interval; /* [IN] if PCS_TYPE_INTERVAL_US: sample interval in us + * if PCS_TYPE_CLOCK_CYCLES: sample interval in graphics core clk cycles + * if PCS_TYPE_INSTRUCTIONS: sample interval in instructions issued by + * graphics compute units + */ + __u64 interval_min; /* [OUT] */ + __u64 interval_max; /* [OUT] */ + __u64 flags; /* [OUT] indicate potential restrictions e.g FLAG_POWER_OF_2 */ + __u32 method; /* [IN/OUT] kfd_ioctl_pc_sample_method */ + __u32 type; /* [IN/OUT] kfd_ioctl_pc_sample_type */ +}; + +#define KFD_IOCTL_PCS_QUERY_TYPE_FULL (1 << 0) /* If not set, return current */ + +struct kfd_ioctl_pc_sample_args { + __u64 sample_info_ptr; /* array of kfd_pc_sample_info */ + __u32 num_sample_info; + __u32 op; /* kfd_ioctl_pc_sample_op */ + __u32 gpu_id; + __u32 trace_id; + __u32 flags; /* kfd_ioctl_pcs_query flags */ + __u32 version; +}; + +#define KFD_IOC_PROFILER_VERSION_NUM 1 +enum kfd_profiler_ops { + KFD_IOC_PROFILER_PMC = 0, + KFD_IOC_PROFILER_PC_SAMPLE = 1, + KFD_IOC_PROFILER_VERSION = 2, +}; + +/** + * Enables/Disables GPU Specific profiler settings + */ +struct kfd_ioctl_pmc_settings { + __u32 gpu_id; /* This is the user_gpu_id */ + __u32 lock; /* Lock GPU for Profiling */ + __u32 perfcount_enable; /* Force Perfcount Enable for queues on GPU */ +}; + +struct kfd_ioctl_profiler_args { + __u32 op; /* kfd_profiler_op */ + union { + struct kfd_ioctl_pc_sample_args pc_sample; + struct kfd_ioctl_pmc_settings pmc; + __u32 version; /* KFD_IOC_PROFILER_VERSION_NUM */ + }; +}; + #define AMDKFD_IOCTL_BASE 'K' #define AMDKFD_IO(nr) _IO(AMDKFD_IOCTL_BASE, nr) #define AMDKFD_IOR(nr, type) _IOR(AMDKFD_IOCTL_BASE, nr, type) @@ -679,16 +1780,16 @@ struct kfd_ioctl_set_xnack_mode_args { #define AMDKFD_IOC_WAIT_EVENTS \ AMDKFD_IOWR(0x0C, struct kfd_ioctl_wait_events_args) -#define AMDKFD_IOC_DBG_REGISTER \ +#define AMDKFD_IOC_DBG_REGISTER_DEPRECATED \ AMDKFD_IOW(0x0D, struct kfd_ioctl_dbg_register_args) -#define AMDKFD_IOC_DBG_UNREGISTER \ +#define AMDKFD_IOC_DBG_UNREGISTER_DEPRECATED \ AMDKFD_IOW(0x0E, struct kfd_ioctl_dbg_unregister_args) -#define AMDKFD_IOC_DBG_ADDRESS_WATCH \ +#define AMDKFD_IOC_DBG_ADDRESS_WATCH_DEPRECATED \ AMDKFD_IOW(0x0F, struct kfd_ioctl_dbg_address_watch_args) -#define AMDKFD_IOC_DBG_WAVE_CONTROL \ +#define AMDKFD_IOC_DBG_WAVE_CONTROL_DEPRECATED \ AMDKFD_IOW(0x10, struct kfd_ioctl_dbg_wave_control_args) #define AMDKFD_IOC_SET_SCRATCH_BACKING_VA \ @@ -742,7 +1843,47 @@ struct kfd_ioctl_set_xnack_mode_args { #define AMDKFD_IOC_SET_XNACK_MODE \ AMDKFD_IOWR(0x21, struct kfd_ioctl_set_xnack_mode_args) +#define AMDKFD_IOC_CRIU_OP \ + AMDKFD_IOWR(0x22, struct kfd_ioctl_criu_args) + +#define AMDKFD_IOC_AVAILABLE_MEMORY \ + AMDKFD_IOWR(0x23, struct kfd_ioctl_get_available_memory_args) + +#define AMDKFD_IOC_EXPORT_DMABUF \ + AMDKFD_IOWR(0x24, struct kfd_ioctl_export_dmabuf_args) + +#define AMDKFD_IOC_RUNTIME_ENABLE \ + AMDKFD_IOWR(0x25, struct kfd_ioctl_runtime_enable_args) + +#define AMDKFD_IOC_DBG_TRAP \ + AMDKFD_IOWR(0x26, struct kfd_ioctl_dbg_trap_args) + #define AMDKFD_COMMAND_START 0x01 -#define AMDKFD_COMMAND_END 0x22 +#define AMDKFD_COMMAND_END 0x27 + +/* non-upstream ioctls */ +#define AMDKFD_IOC_IPC_IMPORT_HANDLE \ + AMDKFD_IOWR(0x80, struct kfd_ioctl_ipc_import_handle_args) + +#define AMDKFD_IOC_IPC_EXPORT_HANDLE \ + AMDKFD_IOWR(0x81, struct kfd_ioctl_ipc_export_handle_args) + +#define AMDKFD_IOC_DBG_TRAP_DEPRECATED \ + AMDKFD_IOWR(0x82, struct kfd_ioctl_dbg_trap_args_deprecated) + +#define AMDKFD_IOC_CROSS_MEMORY_COPY_DEPRECATED \ + AMDKFD_IOWR(0x83, struct kfd_ioctl_cross_memory_copy_deprecated_args) + +#define AMDKFD_IOC_RLC_SPM \ + AMDKFD_IOWR(0x84, struct kfd_ioctl_spm_args) + +#define AMDKFD_IOC_PC_SAMPLE \ + AMDKFD_IOWR(0x85, struct kfd_ioctl_pc_sample_args) + +#define AMDKFD_IOC_PROFILER \ + AMDKFD_IOWR(0x86, struct kfd_ioctl_profiler_args) + +#define AMDKFD_COMMAND_START_2 0x80 +#define AMDKFD_COMMAND_END_2 0x87 #endif diff --git a/extra/huggingface_onnx/run_models.py b/extra/huggingface_onnx/run_models.py index fa8771a11a..2989c58e74 100644 --- a/extra/huggingface_onnx/run_models.py +++ b/extra/huggingface_onnx/run_models.py @@ -1,7 +1,7 @@ import onnx, yaml, tempfile, time, argparse, json from pathlib import Path from typing import Any -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner from extra.onnx_helpers import validate, get_example_inputs from extra.huggingface_onnx.huggingface_manager import DOWNLOADS_DIR, snapshot_download_with_retry diff --git a/extra/mesa/lvp_nir_options.sh b/extra/mesa/lvp_nir_options.sh new file mode 100755 index 0000000000..9634728a3c --- /dev/null +++ b/extra/mesa/lvp_nir_options.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ "$#" -ne 1 ] || ! [ -d $1 ]; then + echo "usage: $0 MESA_PREFIX" + exit 1 +fi + +TMP=$(mktemp) +trap 'rm -f "$TMP"' EXIT + +( + cat < +#include "nir_shader_compiler_options.h" +#include "compiler/shader_enums.h" +EOF + sed -n '/struct nir_shader_compiler_options/,/^}/{p;/^}/q}' $1/src/gallium/drivers/llvmpipe/lp_screen.c + echo "int main(void) { write(1, &gallivm_nir_options, sizeof(gallivm_nir_options)); }" +) | cc -x c -o $TMP - -I$1/src/compiler/nir -I$1/src -I$1/include && $TMP | gzip | base64 -w0 + diff --git a/extra/mmapeak/mmapeak.py b/extra/mmapeak/mmapeak.py index 032a6d798e..36c2cf842c 100644 --- a/extra/mmapeak/mmapeak.py +++ b/extra/mmapeak/mmapeak.py @@ -7,31 +7,34 @@ import os NUM_WORKGROUPS = 96 WAVE_SIZE = 32 NUM_WAVES = 2 -FLOPS_PER_MATMUL = 16*16*16*2 -INTERNAL_LOOP = 1_000_000 -INSTRUCTIONS_PER_LOOP = 1_000 +FLOPS_PER_MATMUL = 16*16*16*2 +INTERNAL_LOOP = 1_000_00 +INSTRUCTIONS_PER_LOOP = 200 +DIRECTIVE = ".amdhsa_wavefront_size32 1" assemblyTemplate = (pathlib.Path(__file__).parent / "template.s").read_text() -def launchBenchmark(instruction, vgprIndices, dense = True): - if dense: +def launchBenchmark(instruction, vgprIndices, dense=True, accum=False, extra=""): + if accum: + instructions = "{} a[0:{}], v[{}:{}], v[{}:{}], 1{}\n".format(instruction, vgprIndices[0], + vgprIndices[1], vgprIndices[2], + vgprIndices[1], vgprIndices[2], extra) + elif dense: instructions = "{} v[0:{}], v[{}:{}], v[{}:{}], 1\n".format(instruction, vgprIndices[0], vgprIndices[1], vgprIndices[2], - vgprIndices[1], vgprIndices[2]) * INSTRUCTIONS_PER_LOOP + vgprIndices[1], vgprIndices[2]) else: instructions = "{} v[0:{}], v[{}:{}], v[{}:{}], v{}\n".format(instruction, vgprIndices[0], - vgprIndices[1], vgprIndices[2], - vgprIndices[3], vgprIndices[4], - vgprIndices[5]) * INSTRUCTIONS_PER_LOOP - src = assemblyTemplate.replace("INSTRUCTION", instructions) + vgprIndices[1], vgprIndices[2], + vgprIndices[3], vgprIndices[4], + vgprIndices[5]) + src = assemblyTemplate.replace("INTERNAL_LOOP", str(INTERNAL_LOOP)).replace("INSTRUCTION", instructions*INSTRUCTIONS_PER_LOOP) + src = src.replace("DIRECTIVE", DIRECTIVE) lib = COMPILER.compile(src) fxn = AMDProgram(DEV, "matmul", lib) - start = time.perf_counter() - fxn(global_size=(NUM_WORKGROUPS,1,1), local_size=(WAVE_SIZE*NUM_WAVES,1,1), wait=True) #For some reason the returned time is very small after the first kernel execution - end = time.perf_counter() - elapsed = end-start + elapsed = fxn(global_size=(NUM_WORKGROUPS,1,1), local_size=(WAVE_SIZE*NUM_WAVES,1,1), wait=True) FLOPs = FLOPS_PER_MATMUL * NUM_WAVES * NUM_WORKGROUPS * INTERNAL_LOOP * INSTRUCTIONS_PER_LOOP - print("{:<29} : {} T(FL)OPS".format(instruction, round(FLOPs/elapsed/10**12, 2))) + print(f"{instruction:<29} : {FLOPs/elapsed/10**12:.2f} T(FL)OPS") if __name__=="__main__": DEVICENUM = os.getenv("DEVICENUM", "0") @@ -40,18 +43,17 @@ if __name__=="__main__": except: raise RuntimeError("Error while initiating AMD device") - if (ARCH := DEV.arch) not in ['gfx1100', 'gfx1201']: - raise RuntimeError("only gfx1100 and gfx1201 supported") - COMPILER = HIPCompiler(ARCH) - - if ARCH == 'gfx1100': + COMPILER = HIPCompiler(DEV.arch) + if DEV.arch in {'gfx1100', 'gfx1103'}: + if DEV.arch == 'gfx1103': + NUM_WORKGROUPS = 8 launchBenchmark("v_wmma_bf16_16x16x16_bf16", (7,8,15)) launchBenchmark("v_wmma_f16_16x16x16_f16", (7,8,15)) launchBenchmark("v_wmma_f32_16x16x16_bf16", (7,8,15)) launchBenchmark("v_wmma_f32_16x16x16_f16", (7,8,15)) launchBenchmark("v_wmma_i32_16x16x16_iu4", (7,8,9)) launchBenchmark("v_wmma_i32_16x16x16_iu8", (7,8,11)) - if ARCH == 'gfx1201': + elif DEV.arch == 'gfx1201': NUM_WORKGROUPS = 64 launchBenchmark("v_wmma_bf16_16x16x16_bf16", (3,4,7)) launchBenchmark("v_wmma_f16_16x16x16_f16", (3,4,7)) @@ -76,4 +78,20 @@ if __name__=="__main__": launchBenchmark("v_swmmac_f32_16x16x32_bf8_fp8", (7,8,9,10,13,14), False) launchBenchmark("v_swmmac_f32_16x16x32_bf8_bf8", (7,8,9,10,13,14), False) FLOPS_PER_MATMUL = 16*16*64*2 - launchBenchmark("v_swmmac_i32_16x16x64_iu4", (7,8,9,10,13,14), False) \ No newline at end of file + launchBenchmark("v_swmmac_i32_16x16x64_iu4", (7,8,9,10,13,14), False) + elif DEV.arch == 'gfx950': + DIRECTIVE = ".amdhsa_accum_offset 4" + NUM_WORKGROUPS = 256 + WAVE_SIZE = 64 + NUM_WAVES = 4 + launchBenchmark("v_mfma_f32_16x16x16_f16", (3,0,1), accum=True) + launchBenchmark("v_mfma_f32_16x16x16_bf16", (3,0,1), accum=True) + FLOPS_PER_MATMUL = 16*16*32*2 + launchBenchmark("v_mfma_f32_16x16x32_f16", (3,0,3), accum=True) + launchBenchmark("v_mfma_f32_16x16x32_bf16", (3,0,3), accum=True) + FLOPS_PER_MATMUL = 16*16*128*2 + launchBenchmark("v_mfma_f32_16x16x128_f8f6f4", (3,0,7), accum=True) # fp8 + launchBenchmark("v_mfma_f32_16x16x128_f8f6f4", (3,0,5), accum=True, extra=", cbsz:2 blgp:2") # fp6 + launchBenchmark("v_mfma_f32_16x16x128_f8f6f4", (3,0,3), accum=True, extra=", cbsz:4 blgp:4") # fp4 + else: + raise RuntimeError(f"arch {DEV.arch} not supported.") diff --git a/extra/mmapeak/template.s b/extra/mmapeak/template.s index f3fc5f2ba2..ecf0704e2b 100644 --- a/extra/mmapeak/template.s +++ b/extra/mmapeak/template.s @@ -1,9 +1,9 @@ .text .globl matmul - .p2align 8 + .p2align 8 .type matmul,@function matmul: - s_mov_b32 s1, 1000000 + s_mov_b32 s1, INTERNAL_LOOP s_mov_b32 s2, 0 inner_loop: INSTRUCTION @@ -17,7 +17,7 @@ matmul: .amdhsa_kernel matmul .amdhsa_next_free_vgpr .amdgcn.next_free_vgpr .amdhsa_next_free_sgpr .amdgcn.next_free_sgpr - .amdhsa_wavefront_size32 1 + DIRECTIVE .end_amdhsa_kernel .amdgpu_metadata @@ -28,7 +28,7 @@ amdhsa.version: amdhsa.kernels: - .name: matmul .symbol: matmul.kd - .kernarg_segment_size: 0 + .kernarg_segment_size: 0 .group_segment_fixed_size: 0 .private_segment_fixed_size: 0 .kernarg_segment_align: 4 @@ -36,6 +36,5 @@ amdhsa.kernels: .sgpr_count: 8 .vgpr_count: 32 .max_flat_workgroup_size: 1024 - .args: ... .end_amdgpu_metadata \ No newline at end of file diff --git a/extra/models/llama.py b/extra/models/llama.py index d8de35af79..e0ac6857ec 100644 --- a/extra/models/llama.py +++ b/extra/models/llama.py @@ -89,6 +89,20 @@ class Attention: keys, values = repeat_kv(keys, self.n_rep), repeat_kv(values, self.n_rep) xq, keys, values = xq.transpose(1, 2), keys.transpose(1, 2), values.transpose(1, 2) attn = xq.scaled_dot_product_attention(keys, values, mask).transpose(1, 2) + if getenv("STUB_ATTENTION"): + # TODO: do we need mask? + from tinygrad.uop.ops import UOp, KernelInfo + def fa_custom_forward(attn:UOp, q:UOp, k:UOp, v:UOp) -> UOp: + return UOp.sink(arg=KernelInfo(name="fa_custom_forward")) + def fa_custom_backward(out_q:UOp, out_k:UOp, out_v:UOp, grad:UOp, q:UOp, k:UOp, v:UOp) -> UOp: + return UOp.sink(arg=KernelInfo(name="fa_custom_backward")) + def fa_backward(grad:UOp, kernel:UOp) -> tuple[None, UOp, UOp, UOp]: + grad_q = Tensor.empty_like(q:=Tensor(kernel.src[1])) + grad_k = Tensor.empty_like(k:=Tensor(kernel.src[2])) + grad_v = Tensor.empty_like(v:=Tensor(kernel.src[3])) + ck = Tensor.custom_kernel(grad_q, grad_k, grad_v, Tensor(grad), q, k, v, fxn=fa_custom_backward)[:3] + return (None, ck[0].uop, ck[1].uop, ck[2].uop) + attn = Tensor.empty_like(attn).custom_kernel(xq, keys, values, fxn=fa_custom_forward, grad_fxn=fa_backward)[0] attn = attn.reshape(bsz, seqlen, -1) return self.wo(attn) diff --git a/extra/nv_gpu_driver/pci_exp_table.h b/extra/nv_gpu_driver/pci_exp_table.h new file mode 100644 index 0000000000..e83101341e --- /dev/null +++ b/extra/nv_gpu_driver/pci_exp_table.h @@ -0,0 +1,134 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 1993-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef PCIEXPTBL_H +#define PCIEXPTBL_H + +#define NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_BASE 0x00 +#define NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_EXT 0xE0 + +// +// The VBIOS object comes from walking the PCI expansion code block +// The following structure holds the expansion code format. +// +#define PCI_EXP_ROM_SIGNATURE 0xaa55 +#define PCI_EXP_ROM_SIGNATURE_NV 0x4e56 // "VN" in word format +#define PCI_EXP_ROM_SIGNATURE_NV2 0xbb77 +#define IS_VALID_PCI_ROM_SIG(sig) ((sig == PCI_EXP_ROM_SIGNATURE) || \ + (sig == PCI_EXP_ROM_SIGNATURE_NV) || \ + (sig == PCI_EXP_ROM_SIGNATURE_NV2)) + +#define OFFSETOF_PCI_EXP_ROM_SIG 0x0 +#define OFFSETOF_PCI_EXP_ROM_NBSI_DATA_OFFSET 0x16 +#define OFFSETOF_PCI_EXP_ROM_PCI_DATA_STRUCT_PTR 0x18 + +#pragma pack(1) +typedef struct _PCI_EXP_ROM_STANDARD +{ + NvU16 sig; // 00h: ROM Signature 0xaa55 + NvU8 reserved [0x16]; // 02h: Reserved (processor architecture unique data) + NvU16 pciDataStrucPtr; // 18h: Pointer to PCI Data Structure + NvU32 sizeOfBlock; // 1Ah: +} PCI_EXP_ROM_STANDARD, *PPCI_EXP_ROM_STANDARD; +#pragma pack() + +#pragma pack(1) +typedef struct _PCI_EXP_ROM_NBSI +{ + NvU16 sig; // 00h: ROM Signature 0xaa55 + NvU8 reserved [0x14]; // 02h: Reserved (processor architecture unique data) + NvU16 nbsiDataOffset; // 16h: Offset from header to NBSI image + NvU16 pciDataStrucPtr; // 18h: Pointer to PCI Data Structure + NvU32 sizeOfBlock; // 1Ah: +} PCI_EXP_ROM_NBSI, *PPCI_EXP_ROM_NBSI; +#pragma pack() + +typedef union _PCI_EXP_ROM { + PCI_EXP_ROM_STANDARD standard; + PCI_EXP_ROM_NBSI nbsi; +} PCI_EXP_ROM, *PPCI_EXP_ROM; + +#define PCI_DATA_STRUCT_SIGNATURE 0x52494350 // "PCIR" in dword format +#define PCI_DATA_STRUCT_SIGNATURE_NV 0x5344504E // "NPDS" in dword format +#define PCI_DATA_STRUCT_SIGNATURE_NV2 0x53494752 // "RGIS" in dword format +#define IS_VALID_PCI_DATA_SIG(sig) ((sig == PCI_DATA_STRUCT_SIGNATURE) || \ + (sig == PCI_DATA_STRUCT_SIGNATURE_NV) || \ + (sig == PCI_DATA_STRUCT_SIGNATURE_NV2)) + +#define PCI_LAST_IMAGE NVBIT(7) +#define PCI_ROM_IMAGE_BLOCK_SIZE 512U + +#define OFFSETOF_PCI_DATA_STRUCT_SIG 0x0 +#define OFFSETOF_PCI_DATA_STRUCT_VENDOR_ID 0x4 +#define OFFSETOF_PCI_DATA_STRUCT_LEN 0xa +#define OFFSETOF_PCI_DATA_STRUCT_CLASS_CODE 0xd +#define OFFSETOF_PCI_DATA_STRUCT_CODE_TYPE 0x14 +#define OFFSETOF_PCI_DATA_STRUCT_IMAGE_LEN 0x10 +#define OFFSETOF_PCI_DATA_STRUCT_LAST_IMAGE 0x15 + +#pragma pack(1) +typedef struct _PCI_DATA_STRUCT +{ + NvU32 sig; // 00h: Signature, the string "PCIR" or NVIDIA's alternate "NPDS" + NvU16 vendorID; // 04h: Vendor Identification + NvU16 deviceID; // 06h: Device Identification + NvU16 deviceListPtr; // 08h: Device List Pointer + NvU16 pciDataStructLen; // 0Ah: PCI Data Structure Length + NvU8 pciDataStructRev; // 0Ch: PCI Data Structure Revision + NvU8 classCode[3]; // 0Dh: Class Code + NvU16 imageLen; // 10h: Image Length (units of 512 bytes) + NvU16 vendorRomRev; // 12h: Revision Level of the Vendor's ROM + NvU8 codeType; // 14h: holds NBSI_OBJ_CODE_TYPE (0x70) and others + NvU8 lastImage; // 15h: Last Image Indicator: bit7=1 is lastImage + NvU16 maxRunTimeImageLen; // 16h: Maximum Run-time Image Length (units of 512 bytes) +} PCI_DATA_STRUCT, *PPCI_DATA_STRUCT; +#pragma pack() + +#define NV_PCI_DATA_EXT_SIG 0x4544504E // "NPDE" in dword format +#define NV_PCI_DATA_EXT_REV_10 0x100 // 1.0 +#define NV_PCI_DATA_EXT_REV_11 0x101 // 1.1 + +#define OFFSETOF_PCI_DATA_EXT_STRUCT_SIG 0x0 +#define OFFSETOF_PCI_DATA_EXT_STRUCT_LEN 0x6 +#define OFFSETOF_PCI_DATA_EXT_STRUCT_REV 0x4 +#define OFFSETOF_PCI_DATA_EXT_STRUCT_SUBIMAGE_LEN 0x8 +#define OFFSETOF_PCI_DATA_EXT_STRUCT_LAST_IMAGE 0xa +#define OFFSETOF_PCI_DATA_EXT_STRUCT_FLAGS 0xb + +#define PCI_DATA_EXT_STRUCT_FLAGS_CHECKSUM_DISABLED 0x04 + +#pragma pack(1) +typedef struct _NV_PCI_DATA_EXT_STRUCT +{ + NvU32 signature; // 00h: Signature, the string "NPDE" + NvU16 nvPciDataExtRev; // 04h: NVIDIA PCI Data Extension Revision + NvU16 nvPciDataExtLen; // 06h: NVIDIA PCI Data Extension Length + NvU16 subimageLen; // 08h: Sub-image Length + NvU8 privLastImage; // 0Ah: Private Last Image Indicator + NvU8 flags; // 0Bh: Private images enabled if bit0=1 +} NV_PCI_DATA_EXT_STRUCT, *PNV_PCI_DATA_EXT_STRUCT; +#pragma pack() + +#endif // PCIEXPTBL_H + + diff --git a/extra/onnx_helpers.py b/extra/onnx_helpers.py index 632d5df8d7..7d3af8fa70 100644 --- a/extra/onnx_helpers.py +++ b/extra/onnx_helpers.py @@ -1,10 +1,23 @@ from tinygrad import Tensor from tinygrad.tensor import _to_np_dtype -from tinygrad.frontend.onnx import OnnxRunner, OnnxValue +from tinygrad.nn.onnx import OnnxRunner, OnnxValue import numpy as np import onnxruntime as ort +ort_options = ort.SessionOptions() +ort_options.log_severity_level = 3 def get_example_inputs(graph_inputs:dict[str, OnnxValue], config={}): + """ + Generate example input tensors based on the provided ONNX graph input specifications. + + NOTE: This is not guaranteed to be reliable. It's a best-effort helper + that uses heuristics to guess input shapes and values. + + Example: + from tinygrad.nn.onnx import OnnxRunner + from extra.onnx_helpers import get_example_inputs + inputs = get_example_inputs(OnnxRunner(model_path).graph_inputs) + """ def _get_shape(onnx_shape: tuple[str|int]): shape = [] for onnx_dim in onnx_shape: @@ -44,11 +57,9 @@ def get_example_inputs(graph_inputs:dict[str, OnnxValue], config={}): ret.update({name:value}) return ret -def validate(onnx_file, inputs, rtol=1e-5, atol=1e-5): +def _get_tinygrad_and_ort_np_outputs(onnx_file, inputs): run_onnx = OnnxRunner(onnx_file) - ort_options = ort.SessionOptions() - ort_options.log_severity_level = 3 ort_sess = ort.InferenceSession(onnx_file, ort_options, ["CPUExecutionProvider"]) np_inputs = {k:v.numpy() if isinstance(v, Tensor) else v for k,v in inputs.items()} out_names = list(run_onnx.graph_outputs) @@ -56,9 +67,101 @@ def validate(onnx_file, inputs, rtol=1e-5, atol=1e-5): ort_out = dict(zip(out_names, out_values)) tinygrad_out = run_onnx(inputs) + Tensor.realize(*(x for x in tinygrad_out.values() if x is not None)) + tinygrad_out = {k:v.numpy() if v is not None else None for k,v in tinygrad_out.items()} + return tinygrad_out, ort_out + +def validate(onnx_file, inputs, rtol=1e-5, atol=1e-5): + """ + Compares the final output tensors of an onnx model run in tinygrad and onnxruntime. + """ + tinygrad_out, ort_out = _get_tinygrad_and_ort_np_outputs(onnx_file, inputs) assert tinygrad_out.keys() == ort_out.keys() for k in tinygrad_out.keys(): tiny_v, onnx_v = tinygrad_out[k], ort_out[k] if tiny_v is None: assert onnx_v is None, f"{k}: {tiny_v=}, {onnx_v=}" - else: np.testing.assert_allclose(tiny_v.numpy(), onnx_v, rtol=rtol, atol=atol, err_msg=f"For tensor '{k}' in {tinygrad_out.keys()}") \ No newline at end of file + else: np.testing.assert_allclose(tiny_v, onnx_v, rtol=rtol, atol=atol, err_msg=f"For tensor '{k}' in {tinygrad_out.keys()}") + +def validate_all_intermediates(onnx_file, inputs, rtol=1e-5, atol=1e-5): + """ + Compares all intermediate node output of an onnx model run in tinygrad and onnxruntime. + """ + report = generate_node_output_report(onnx_file, inputs) + for i, node in enumerate(report): + node_name = node["node"] + op = node["op"] + outputs = node["outputs"] + for output in outputs: + output_name = output["name"] + tinygrad_out = output["tinygrad"] + ort_out = output["onnxruntime"] + try: + if tinygrad_out is None: assert ort_out is None, f"None outputs are not equal {tinygrad_out=} {ort_out=}" + else: np.testing.assert_allclose(tinygrad_out, ort_out, rtol=rtol, atol=atol) + print(f"Validated {i}: {op=} {node_name=} {output_name=}") + except AssertionError as e: + print(f"FAILED {i}: {op=} {node_name=} {output_name=}") + print(str(e).strip() + "\n") + +def generate_node_output_report(onnx_file, inputs): + """ + Build a report of all ONNX node outputs from tinygrad and onnxruntime + + Returns: + A list of dictionaries, where each entry corresponds to one + node in the ONNX graph. The structure is as follows: + [ + { + "node": str, # The name of the ONNX node. + "op": str, # The operation type of the ONNX node. + "outputs": [ + { + "name": str, # The name of the output tensor. + "tinygrad": np.ndarray | None, # The output value from tinygrad. + "onnxruntime": np.ndarray | None, # The output value from onnxruntime. + }, + ... + ] + }, + ... + ] + """ + import onnx_graphsurgeon as gs + import onnx + import tempfile + + # rewrite the model to output all the node outputs + # `infer_shapes` here tries to fill the shapes and dtypes of intermediate values which graphsurgeon requires when assigning them as outputs + inferred_model = onnx.shape_inference.infer_shapes(onnx.load(onnx_file)) + model = gs.import_onnx(inferred_model) + model_nodes = model.nodes + node_outputs = [n.outputs for n in model.nodes] + model.outputs = [ + each_output for outputs in node_outputs for each_output in outputs + if not (each_output.dtype is None and each_output.shape is None) # output with None dtype and None shape is likely a `None` value + ] + rewritten_model = gs.export_onnx(model) + + # TODO: remove this once ORT supports 1.18.0 + if getattr(rewritten_model, "ir_version", 0) > 10: + rewritten_model.ir_version = 10 + + with tempfile.NamedTemporaryFile(suffix=".onnx") as f: + onnx.save(rewritten_model, f.name) + rewritten_model_path = f.name + tinygrad_out, ort_out = _get_tinygrad_and_ort_np_outputs(rewritten_model_path, inputs) + + report = [] + for node in model_nodes: + outputs = [] + for each_output in node.outputs: + if each_output.dtype is None and each_output.shape is None: + continue + name = each_output.name + tinygrad_output = tinygrad_out[name] + ort_output = ort_out[name] + outputs.append({"name": name, "tinygrad": tinygrad_output, "onnxruntime": ort_output}) + report.append({"node": node.name, "op": node.op, "outputs": outputs}) + + return report diff --git a/extra/optimization/helpers.py b/extra/optimization/helpers.py index d8ab1279d4..88807fba97 100644 --- a/extra/optimization/helpers.py +++ b/extra/optimization/helpers.py @@ -81,7 +81,7 @@ def lin_to_feats(lin:Kernel, use_sts=True): ret = [float(x) for x in ret] if use_sts: - my_sts = dedup([(x.shape == lin.full_shape, x.real_strides(), any(v.mask is not None for v in x.views), len(x.views)) for x in lin.sts]) + my_sts = dedup([(x.shape == lin.full_shape, x.is_expanded(), any(v.mask is not None for v in x.views), len(x.views)) for x in lin.sts]) assert len(my_sts) < MAX_BUFS sts_len = 3 + 5*MAX_DIMS for s in my_sts: diff --git a/extra/qcom_gpu_driver/adreno_pm4.xml b/extra/qcom_gpu_driver/adreno_pm4.xml index 1b687eed5a..c617856ba3 100644 --- a/extra/qcom_gpu_driver/adreno_pm4.xml +++ b/extra/qcom_gpu_driver/adreno_pm4.xml @@ -1,7 +1,8 @@ +xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> + @@ -20,9 +21,9 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> - - - + + + @@ -30,8 +31,8 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> - If A6XX_RB_SAMPLE_COUNT_CONTROL.copy is true, writes OQ Z passed - sample counts to RB_SAMPLE_COUNT_ADDR. This writes to main + If A6XX_RB_SAMPLE_COUNTER_CNTL.copy is true, writes OQ Z passed + sample counts to RB_SAMPLE_COUNTER_BASE. This writes to main memory, skipping UCHE. @@ -96,6 +97,13 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> + + Flip between the primary and secondary LRZ buffers. This is used + for concurrent binning, so that BV can write to one buffer while + BR reads from the other. + + + Clears based on GRAS_LRZ_CNTL configuration, could clear fast-clear buffer or LRZ direction. @@ -112,11 +120,12 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> - + + - - + + @@ -129,21 +138,22 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> Doesn't seem to do anything - - - - - - - - - - - - + + + + + + + + + + + + - - + + + @@ -324,7 +334,7 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> fetch state sub-blocks and initiate shader code DMAs load constant into chip and to memory - + load sequencer instruction memory (pointer-based) load sequencer instruction memory (code embedded in packet) @@ -371,7 +381,7 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> Conditionally load a IB based on a flag, prefetch enabled - + Conditionally load a IB based on a flag, prefetch disabled Load a buffer with pre-fetch enabled @@ -514,7 +524,7 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> @@ -537,7 +547,7 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> - + + + Write CP_CONTEXT_SWITCH_*_INFO from CP to the following dwords, and forcibly switch to the indicated context. - - + - + Write to a scratch memory that is read by CP_REG_TEST with SOURCE_SCRATCH_MEM set. It's not the same scratch as scratch registers. @@ -648,6 +658,11 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> Reset various on-chip state used for synchronization + + Invalidates the "CCHE" introduced on a740 + + + @@ -790,14 +805,14 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - + + - + @@ -903,12 +918,6 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - @@ -1084,8 +1093,10 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - + + + @@ -1119,39 +1130,63 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) + + + + + + + + A mask of bins, starting at VSC_N, whose + visibility is OR'd together. A value of 0 is + interpreted as 1 (i.e. just use VSC_N for + visbility) for backwards compatibility. Only + exists on a7xx. + + + + + If this field is 1, VSC_MASK and VSC_N are + ignored and instead a new ordinal immediately + after specifies the full 32-bit mask of bins + to use. The mask is "absolute" instead of + relative to VSC_N. + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -1162,23 +1197,42 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) stream is recorded. + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1196,6 +1250,9 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) + + + @@ -1209,7 +1266,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - + @@ -1217,12 +1274,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + + + + + + @@ -1238,12 +1295,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + @@ -1263,18 +1315,8 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - - - - - - - + + @@ -1287,12 +1329,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + + + + + + @@ -1312,6 +1354,10 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) + + + + + + @@ -1368,12 +1416,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + + + + + + @@ -1425,24 +1473,14 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + - - - - - - + @@ -1457,12 +1495,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + @@ -1480,12 +1513,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + @@ -1619,12 +1647,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) TODO what is gpuaddr for, seems to be all 0's.. maybe needed for context switch? --> - - - - - - + @@ -1653,8 +1676,8 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - + + @@ -1668,15 +1691,11 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) + - - - - - - + @@ -1743,9 +1762,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - + @@ -1754,12 +1771,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - - - - - - + @@ -1771,40 +1783,88 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) Tell CP the current operation mode, indicates save and restore procedure + + + + + + + + + - - - - - - + + + + + + + - + - - - - - + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1830,9 +1890,9 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) If concurrent binning is disabled then BR also does binning so it will also write the "real" registers in BR. --> - - - + + + @@ -1933,11 +1993,11 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) a bitmask of which modes pass the test. --> - + - + @@ -2010,54 +2070,45 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - + - Used by the userspace driver to set various IB's which are - executed during context save/restore for handling - state that isn't restored by the - context switch routine itself. + Used by the userspace and kernel drivers to set various IB's + which are executed during context save/restore for handling + state that isn't restored by the context switch routine itself. - - + + Executed unconditionally when switching back to the context. - + Executed when switching back after switching away during execution of - a CP_SET_MARKER packet with RM6_YIELD as the - payload *and* the normal save routine was - bypassed for a shorter one. I think this is - connected to the "skipsaverestore" bit set by - the kernel when preempting. + a CP_SET_MARKER packet with RM6_BIN_RENDER_END as the + payload *and* skipsaverestore is set. This is + expected to restore static register values not + saved when skipsaverestore is set. - + Executed when switching away from the context, except for context switches initiated via CP_YIELD. - + This can only be set by the RB (i.e. the kernel) and executes with protected mode off, but - is otherwise similar to SAVE_IB. - - Note, kgsl calls this CP_KMD_AMBLE_TYPE + is otherwise similar to POSTAMBLE_AMBLE_TYPE. - - - - - - + - + @@ -2089,12 +2140,12 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) Tracks GRAS_LRZ_CNTL::GREATER, GRAS_LRZ_CNTL::DIR, and - GRAS_LRZ_DEPTH_VIEW with previous values, and if one of + GRAS_LRZ_VIEW_INFO with previous values, and if one of the following is true: - GRAS_LRZ_CNTL::GREATER has changed - GRAS_LRZ_CNTL::DIR has changed, the old value is not CUR_DIR_GE, and the new value is not CUR_DIR_DISABLED - - GRAS_LRZ_DEPTH_VIEW has changed + - GRAS_LRZ_VIEW_INFO has changed then it does a LRZ_FLUSH with GRAS_LRZ_CNTL::ENABLE forced to 1. Only exists in a650_sqe.fw. @@ -2209,7 +2260,7 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - Best guess is that it is a faster way to fetch all the VSC_STATE registers + Best guess is that it is a faster way to fetch all the VSC_CHANNEL_VISIBILITY registers and keep them in a local scratch memory instead of fetching every time when skipping IBs. @@ -2257,7 +2308,25 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) - + + + + + + + + + + + + + + + + + + + diff --git a/extra/qcom_gpu_driver/msm_kgsl.py b/extra/qcom_gpu_driver/msm_kgsl.py index 870ad572a7..d5df84bf86 100644 --- a/extra/qcom_gpu_driver/msm_kgsl.py +++ b/extra/qcom_gpu_driver/msm_kgsl.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/extra/qcom_gpu_driver/opencl_ioctl.py b/extra/qcom_gpu_driver/opencl_ioctl.py index ea1896bd01..bdcb8f3d32 100644 --- a/extra/qcom_gpu_driver/opencl_ioctl.py +++ b/extra/qcom_gpu_driver/opencl_ioctl.py @@ -97,7 +97,7 @@ def parse_cmd_buf(dat): if state_block == SB6_CS_SHADER: from extra.disassemblers.adreno import disasm_raw - if state_type == ST6_SHADER and IOCTL > 2: + if state_type == ST6_SHADER and IOCTL > 3: disasm_raw(get_mem(((vals[2] << 32) | vals[1]), num_unit * 128)) if state_type == ST6_CONSTANTS: x = get_mem(((vals[2] << 32) | vals[1]), num_unit*4) @@ -106,25 +106,30 @@ def parse_cmd_buf(dat): print('constants') hexdump(x) if state_type == ST6_IBO: - ibos_bytes = get_mem((vals[2] << 32) | vals[1], num_unit * 16 * 4) + if state_src == 0x1: + ibos_bytes = get_mem(CAPTURED_STATE['bindless_base'] + ((vals[2] << 32) | vals[1]) * 4, num_unit * 64) + else: ibos_bytes = get_mem((vals[2] << 32) | vals[1], num_unit * 16 * 4) CAPTURED_STATE['ibos'] = ibos_bytes[:] if IOCTL > 1: print('texture ibos') hexdump(ibos_bytes) elif state_block == SB6_CS_TEX: if state_type == ST6_SHADER: - samplers_bytes = get_mem((vals[2] << 32) | vals[1], num_unit * 4 * 4) + if state_src == 0x1: + samplers_bytes = get_mem(CAPTURED_STATE['bindless_base'] + ((vals[2] << 32) | vals[1]) * 4, num_unit * 64) + else: samplers_bytes = get_mem((vals[2] << 32) | vals[1], num_unit * 4 * 4) CAPTURED_STATE['samplers'] = samplers_bytes[:] if IOCTL > 1: print('texture samplers') hexdump(samplers_bytes) if state_type == ST6_CONSTANTS: - descriptors_bytes = get_mem((vals[2] << 32) | vals[1], 1600) + if state_src == 0x1: + descriptors_bytes = get_mem(CAPTURED_STATE['bindless_base'] + ((vals[2] << 32) | vals[1]) * 4, num_unit * 64) + else: descriptors_bytes = get_mem((vals[2] << 32) | vals[1], 1600) CAPTURED_STATE['descriptors'] = descriptors_bytes[:] if IOCTL > 1: print('texture descriptors') hexdump(descriptors_bytes) - elif ops[opcode] == "CP_REG_TO_MEM": reg, cnt, b64, accum = vals[0] & 0x3FFFF, (vals[0] >> 18) & 0xFFF, (vals[0] >> 30) & 0x1, (vals[0] >> 31) & 0x1 dest = vals[1] | (vals[2] << 32) @@ -152,6 +157,10 @@ def parse_cmd_buf(dat): if IOCTL > 0: print(f'THREADSIZE-{(vals[0] >> 20)&0x1}\nEARLYPREAMBLE-{(vals[0] >> 23) & 0x1}\nMERGEDREGS-{(vals[0] >> 3) & 0x1}\nTHREADMODE-{vals[0] & 0x1}\nHALFREGFOOTPRINT-{(vals[0] >> 1) & 0x3f}\nFULLREGFOOTPRINT-{(vals[0] >> 7) & 0x3f}\nBRANCHSTACK-{(vals[0] >> 14) & 0x3f}\n') print(f'SP_CS_UNKNOWN_A9B1-{vals[1]}\nSP_CS_BRANCH_COND-{vals[2]}\nSP_CS_OBJ_FIRST_EXEC_OFFSET-{vals[3]}\nSP_CS_OBJ_START-{vals[4] | (vals[5] << 32)}\nSP_CS_PVT_MEM_PARAM-{vals[6]}\nSP_CS_PVT_MEM_ADDR-{vals[7] | (vals[8] << 32)}\nSP_CS_PVT_MEM_SIZE-{vals[9]}') + if offset == 0xa9e8: + CAPTURED_STATE['bindless_base'] = (vals[0] | (vals[1] << 32)) & ~0b11 + # print(hex(CAPTURED_STATE['bindless_base'])) + # hexdump(get_mem(CAPTURED_STATE['bindless_base'], 0x200)) if offset == 0xb180: if IOCTL > 0: print('border color offset', hex(vals[1] << 32 | vals[0])) @@ -171,8 +180,8 @@ def ioctl(fd, request, argp): name, stype = nrs[nr] s = get_struct(argp, stype) if IOCTL > 0: print(f"{ret:2d} = {name:40s}", ' '.join(format_struct(s))) - if name == "IOCTL_KGSL_GPUOBJ_INFO": pass - # mmaped[s.gpuaddr] = mmap.mmap(fd, s.size, offset=s.id*0x1000) + if name == "IOCTL_KGSL_GPUOBJ_INFO": + mmaped[s.gpuaddr] = mmap.mmap(fd, s.size, offset=s.id*0x1000) if name == "IOCTL_KGSL_GPU_COMMAND": for i in range(s.numcmds): cmd = get_struct(s.cmdlist+ctypes.sizeof(msm_kgsl.struct_kgsl_command_object)*i, msm_kgsl.struct_kgsl_command_object) diff --git a/extra/remu/src/thread.rs b/extra/remu/src/thread.rs index ca448d7c23..4f73557bbc 100644 --- a/extra/remu/src/thread.rs +++ b/extra/remu/src/thread.rs @@ -882,6 +882,11 @@ impl<'a> Thread<'a> { let s1 = sign_ext((s1 & 0xffffff) as u64, 24) as i32; (s0 * s1) as u32 } + 10 => { + let s0 = sign_ext((s0 & 0xffffff) as u64, 24) as i64; + let s1 = sign_ext((s1 & 0xffffff) as u64, 24) as i64; + ((s0 * s1) >> 32) as u32 + } 17 | 18 | 26 => { let (s0, s1) = (s0 as i32, s1 as i32); (match op { @@ -930,7 +935,7 @@ impl<'a> Thread<'a> { let op = ((instr >> 16) & 0x3ff) as u32; match op { - 764 | 765 | 288 | 289 | 290 | 766 | 767 | 768 | 769 => { + 764 | 765 | 288 | 289 | 290 | 766 | 767 | 768 | 769 | 770 => { let vdst = (instr & 0xff) as usize; let sdst = ((instr >> 8) & 0x7f) as usize; let f = |i: u32| -> usize { ((instr >> i) & 0x1ff) as usize }; @@ -996,6 +1001,10 @@ impl<'a> Thread<'a> { let ret = s0.wrapping_sub(s1); (ret as u32, s1 > s0) } + 770 => { + let ret = s1.wrapping_sub(s0); + (ret as u32, s0 > s1) + } _ => todo_instr!(instruction)?, }; if self.exec.read() { diff --git a/extra/remu/test/hwtest.py b/extra/remu/test/hwtest.py index 76bd2f6e69..769d687045 100644 --- a/extra/remu/test/hwtest.py +++ b/extra/remu/test/hwtest.py @@ -1,98 +1,32 @@ import numpy as np import unittest import subprocess, struct, math -from typing import cast -from tinygrad.runtime.ops_amd import AMDProgram, AMDDevice -from tinygrad import Tensor, dtypes, Device -from tinygrad.helpers import diskcache, OSX, getenv +from tinygrad import Tensor, dtypes, Device, UOp +from tinygrad.helpers import getenv +from tinygrad.runtime.support.compiler_amd import amdgpu_disassemble +from tinygrad.renderer import ProgramSpec +from tinygrad.engine.realize import CompiledRunner -@diskcache -def assemble(code:str) -> bytes: - try: - LLVM_MC = "llvm-mc" if OSX else "/opt/rocm/llvm/bin/llvm-mc" - return subprocess.run([LLVM_MC, "--arch=amdgcn", "--mcpu=gfx1100", "--triple=amdgcn-amd-amdhsa", "-filetype=obj", "-o", "-"], - input=code.encode("utf-8"), stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True).stdout - except subprocess.CalledProcessError as e: - print("stderr:") - print(e.stderr.decode()) - raise - -# copied from extra/rdna -def get_prg(code:str, v_cnt:int, s_cnt:int): - function_name = "test" - metadata = f""" -amdhsa.kernels: -- .args: - - .address_space: global - .name: buf_0 - .offset: 0 - .size: 8 - .type_name: unsigned int* - .value_kind: global_buffer - .group_segment_fixed_size: 0 - .kernarg_segment_align: 8 - .kernarg_segment_size: 8 - .language: OpenCL C - .language_version: - - 1 - - 2 - .max_flat_workgroup_size: 256 - .name: test - .private_segment_fixed_size: 0 - .sgpr_count: {s_cnt} - .sgpr_spill_count: 0 - .symbol: test.kd - .uses_dynamic_stack: false - .vgpr_count: {v_cnt} - .vgpr_spill_count: 0 - .wavefront_size: 32 -amdhsa.target: amdgcn-amd-amdhsa--gfx1100 -amdhsa.version: -- 1 -- 2 - """ - boilerplate_start = f""" - .rodata - .global {function_name}.kd - .type {function_name}.kd,STT_OBJECT - .align 0x10 - .amdhsa_kernel {function_name}""" - kernel_desc = { - '.amdhsa_group_segment_fixed_size': 0, '.amdhsa_private_segment_fixed_size': 0, '.amdhsa_kernarg_size': 0, - '.amdhsa_next_free_vgpr': v_cnt, # this matters! - '.amdhsa_reserve_vcc': 0, '.amdhsa_reserve_xnack_mask': 0, - '.amdhsa_next_free_sgpr': s_cnt, - '.amdhsa_float_round_mode_32': 0, '.amdhsa_float_round_mode_16_64': 0, '.amdhsa_float_denorm_mode_32': 3, '.amdhsa_float_denorm_mode_16_64': 3, - '.amdhsa_dx10_clamp': 1, '.amdhsa_ieee_mode': 1, '.amdhsa_fp16_overflow': 0, - '.amdhsa_workgroup_processor_mode': 1, '.amdhsa_memory_ordered': 1, '.amdhsa_forward_progress': 0, '.amdhsa_enable_private_segment': 0, - '.amdhsa_system_sgpr_workgroup_id_x': 1, '.amdhsa_system_sgpr_workgroup_id_y': 1, '.amdhsa_system_sgpr_workgroup_id_z': 1, - '.amdhsa_system_sgpr_workgroup_info': 0, '.amdhsa_system_vgpr_workitem_id': 2, # is amdhsa_system_vgpr_workitem_id real? - '.amdhsa_exception_fp_ieee_invalid_op': 0, '.amdhsa_exception_fp_denorm_src': 0, - '.amdhsa_exception_fp_ieee_div_zero': 0, '.amdhsa_exception_fp_ieee_overflow': 0, '.amdhsa_exception_fp_ieee_underflow': 0, - '.amdhsa_exception_fp_ieee_inexact': 0, '.amdhsa_exception_int_div_zero': 0, - '.amdhsa_user_sgpr_dispatch_ptr': 0, '.amdhsa_user_sgpr_queue_ptr': 0, '.amdhsa_user_sgpr_kernarg_segment_ptr': 1, - '.amdhsa_user_sgpr_dispatch_id': 0, '.amdhsa_user_sgpr_private_segment_size': 0, '.amdhsa_wavefront_size32': 1, '.amdhsa_uses_dynamic_stack': 0} - code_start = f""".end_amdhsa_kernel - .text - .global {function_name} - .type {function_name},@function - .p2align 8 - {function_name}: - """ - ret = ".amdgpu_metadata\n" + metadata + ".end_amdgpu_metadata" + boilerplate_start + "\n" + '\n'.join("%s %d" % x for x in kernel_desc.items()) \ - + "\n" + code_start + code + f"\n.size {function_name}, .-{function_name}" - return AMDProgram(cast(AMDDevice, Device["AMD"]), function_name, assemble(ret)) - -def get_output(s:str, n_threads:int=1): - assert n_threads <= 32 - code = "\n".join(["s_load_b64 s[0:1], s[0:1], null", "v_lshlrev_b32_e32 v0, 2, v0", s, - "s_waitcnt 0", - "global_store_b32 v0, v1, s[0:1]", - "s_nop 0", "s_sendmsg sendmsg(MSG_DEALLOC_VGPRS)", "s_endpgm"]) - test = Tensor.zeros((n_threads,), dtype=dtypes.uint32).contiguous().realize().uop.buffer - prg = get_prg(code, 32, 32) - prg(test._buf, global_size=(1, 1, 1), local_size=(n_threads, 1, 1), wait=True) - return test.numpy() +def get_output(asm:str, n_threads:int=1): + input_asm = "\n".join([ln if ln.strip().startswith('asm volatile') else f'asm volatile("{ln.strip().lstrip()}" : "+v"(a), "+v"(b));' + for ln in asm.strip().splitlines() if ln.strip()]) + src = f""" + typedef long unsigned int size_t; + extern "C" __attribute__((device, const)) size_t __ockl_get_local_id(unsigned int); + extern "C" __attribute__((global)) void __attribute__((amdgpu_flat_work_group_size(1, {n_threads}))) test(unsigned int* data0_1) {{ + int l = __ockl_get_local_id(0); + unsigned a = 0, b = 0, c = 0; + {input_asm} + unsigned res; + asm volatile("v_mov_b32 %0, %1" : "=v"(res) : "v"(a)); + *(data0_1+l) = res; + }}""" + t = Tensor.zeros(n_threads, dtype=dtypes.uint32).contiguous().realize() + prg = ProgramSpec("test", src, Device.DEFAULT, UOp.sink(t), global_size=[1, 1, 1], local_size=[n_threads, 1, 1]) + car = CompiledRunner(prg) + if getenv("PRINT_ASM"): amdgpu_disassemble(car.lib) + car([t.uop.buffer], {}, wait=True) + return t.numpy() def f16_to_bits(x:float) -> int: return struct.unpack(' float: return struct.unpack(' dict[int, tuple[str, int]]: + llvm.LLVMInitializeAMDGPUTargetInfo() + llvm.LLVMInitializeAMDGPUTargetMC() + llvm.LLVMInitializeAMDGPUAsmParser() + llvm.LLVMInitializeAMDGPUDisassembler() + ctx = llvm.LLVMCreateDisasmCPUFeatures("amdgcn-amd-amdhsa".encode(), arch.encode(), "".encode(), None, 0, None, None) + + image, sections, relocs = elf_loader(lib) + text = next((sh.header for sh in sections if sh.name == ".text"), None) + off, sz = unwrap(text).sh_addr, unwrap(text).sh_size + + addr_table:dict[int, tuple[str, int]] = {} + out = ctypes.create_string_buffer(128) + cur_off = off + while cur_off < sz + off: + view = (ctypes.c_ubyte * ((sz + off) - cur_off)).from_buffer_copy(memoryview(image)[cur_off:]) + instr_sz = llvm.LLVMDisasmInstruction(ctx, view, ctypes.c_uint64(len(view)), ctypes.c_uint64(0), out, ctypes.c_size_t(128)) + addr_table[cur_off] = (out.value.decode("utf-8", "replace").strip(), instr_sz) + cur_off += instr_sz + return addr_table + +@dataclasses.dataclass(frozen=True) +class InstExec: + typ:str + inst:str + stall:int + dur:int + time:int + +@dataclasses.dataclass(frozen=True) +class WaveExec: + wave_id:int + cu:int + simd:int + begin_time:int + end_time:int + insts:list[InstExec] + +class _ROCParseCtx: + def __init__(self, dev_evs:dict[str, ProfileDeviceEvent], sqtt_evs:list[ProfileSQTTEvent], prog_evs:list[ProfileProgramEvent]): + self.dev_evs, self.sqtt_evs, self.prog_evs = dev_evs, iter(sqtt_evs), prog_evs + self.disasms:dict[tuple[str, int], tuple[str, int]] = {} + self.inst_execs:dict[str, list[WaveExec]] = {} + + for prog in prog_evs: + arch = "gfx%d%x%x" % ((trgt:=unwrap(dev_evs[prog.device].props)['gfx_target_version']) // 10000, (trgt // 100) % 100, trgt % 100) + for addr, info in llvm_disasm(arch, unwrap(prog.lib)).items(): + self.disasms[(prog.name, unwrap(prog.base) + addr)] = info + + def next_sqtt(self): + x = next(self.sqtt_evs, None) + self.active_kern = x.kern if x is not None else None + self.active_se = x.se if x is not None else None + self.active_blob = (ctypes.c_ubyte * len(x.blob)).from_buffer_copy(x.blob) if x is not None else None + return self.active_blob + + def on_occupancy_ev(self, ev): + if DEBUG >= 5: print("OCC", ev.time, self.active_se, ev.cu, ev.simd, ev.wave_id, ev.start) + + def on_wave_ev(self, ev): + if DEBUG >= 5: print("WAVE", ev.wave_id, self.active_se, ev.cu, ev.simd, ev.contexts, ev.begin_time, ev.end_time) + + inst_execs:list[InstExec] = [] + for j in range(ev.instructions_size): + inst_ev = ev.instructions_array[j] + inst_typ = rocprof.rocprofiler_thread_trace_decoder_inst_category_t__enumvalues[inst_ev.category] + inst_disasm = self.disasms[(unwrap(self.active_kern), unwrap(inst_ev.pc.address))][0] + inst_execs.append(InstExec(inst_typ, inst_disasm, inst_ev.stall, inst_ev.duration, inst_ev.time)) + + if ev.instructions_size > 0: + self.inst_execs.setdefault(unwrap(self.active_kern), []).append(WaveExec(ev.wave_id, ev.cu, ev.simd, ev.begin_time, ev.end_time, inst_execs)) + +def decode(profile:list[ProfileEvent]) -> _ROCParseCtx: + dev_events:dict[str, ProfileDeviceEvent] = {} + sqtt_events:list[ProfileSQTTEvent] = [] + prog_events:list[ProfileProgramEvent] = [] + for e in profile: + if isinstance(e, ProfileDeviceEvent): dev_events[e.device] = e + if isinstance(e, ProfileSQTTEvent): sqtt_events.append(e) + if isinstance(e, ProfileProgramEvent) and e.device.startswith("AMD"): prog_events.append(e) + + ROCParseCtx = _ROCParseCtx(dev_events, sqtt_events, prog_events) + + @rocprof.rocprof_trace_decoder_se_data_callback_t + def copy_cb(buf, buf_size, data_ptr): + if (prof_info:=ROCParseCtx.next_sqtt()) is None: return 0 + buf[0] = ctypes.cast(prof_info, ctypes.POINTER(ctypes.c_ubyte)) + buf_size[0] = len(prof_info) + return len(prof_info) + + @rocprof.rocprof_trace_decoder_trace_callback_t + def trace_cb(record_type, events_ptr, n, data_ptr): + match record_type: + case rocprof.ROCPROFILER_THREAD_TRACE_DECODER_RECORD_OCCUPANCY: + for ev in (rocprof.rocprofiler_thread_trace_decoder_occupancy_t * n).from_address(events_ptr): ROCParseCtx.on_occupancy_ev(ev) + case rocprof.ROCPROFILER_THREAD_TRACE_DECODER_RECORD_WAVE: + for ev in (rocprof.rocprofiler_thread_trace_decoder_wave_t * n).from_address(events_ptr): ROCParseCtx.on_wave_ev(ev) + case _: + if DEBUG >= 5: print(rocprof.rocprofiler_thread_trace_decoder_record_type_t__enumvalues[record_type], events_ptr, n) + return rocprof.ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS + + @rocprof.rocprof_trace_decoder_isa_callback_t + def isa_cb(instr_ptr, mem_size_ptr, size_ptr, pc, data_ptr): + instr, mem_size_ptr[0] = ROCParseCtx.disasms[(unwrap(ROCParseCtx.active_kern), pc.address)] + + # this is the number of bytes to next instruction, set to 0 for end_pgm + if instr == "s_endpgm": mem_size_ptr[0] = 0 + if (max_sz:=size_ptr[0]) == 0: return rocprof.ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES + + # truncate the instr if it doesn't fit + if (str_sz:=len(instr_bytes:=instr.encode()))+1 > max_sz: str_sz = max_sz + ctypes.memmove(instr_ptr, instr_bytes, str_sz) + size_ptr[0] = str_sz + + return rocprof.ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS + + try: + rocprof.rocprof_trace_decoder_parse_data(copy_cb, trace_cb, isa_cb, None) + except AttributeError as e: raise RuntimeError("Failed to find rocprof-trace-decoder. Run sudo ./extra/sqtt/install_sqtt_decoder.py to install") from e + return ROCParseCtx + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--profile', type=pathlib.Path, help='Path to profile', default=pathlib.Path(temp("profile.pkl", append_user=True))) + args = parser.parse_args() + + with args.profile.open("rb") as f: profile = pickle.load(f) + rctx = decode(profile) + print('SQTT:', rctx.inst_execs.keys()) + + for ev in profile: + if not isinstance(ev, ProfilePMCEvent): continue + print(f"PMC Event: dev={ev.device} kern={ev.kern}") + ptr = 0 + for s in ev.sched: + view = memoryview(ev.blob).cast('Q') + print(f"\t{s.name}") + for xcc, inst, se_idx, sa_idx, wgp_idx in itertools.product(range(s.xcc), range(s.inst), range(s.se), range(s.sa), range(s.wgp)): + print(f"\t\tXCC {xcc} Inst {inst} SE {se_idx} SA {sa_idx} WGP {wgp_idx}: {view[ptr]:#x}") + ptr += 1 diff --git a/extra/sqtt/sqtt.h b/extra/sqtt/sqtt.h index 775655840c..ac641acabd 100644 --- a/extra/sqtt/sqtt.h +++ b/extra/sqtt/sqtt.h @@ -43,6 +43,7 @@ enum sqtt_version SQTT_VERSION_2_3 = 0x6, /* GFX9 */ SQTT_VERSION_2_4 = 0x7, /* GFX10+ */ SQTT_VERSION_3_2 = 0xb, /* GFX11+ */ + SQTT_VERSION_3_3 = 0xc, /* GFX12+ */ }; enum sqtt_file_chunk_type @@ -144,6 +145,8 @@ enum sqtt_gfxip_level SQTT_GFXIP_LEVEL_GFXIP_10_1 = 0x7, SQTT_GFXIP_LEVEL_GFXIP_10_3 = 0x9, SQTT_GFXIP_LEVEL_GFXIP_11_0 = 0xc, + SQTT_GFXIP_LEVEL_GFXIP_11_5 = 0xd, + SQTT_GFXIP_LEVEL_GFXIP_12 = 0x10, }; enum sqtt_memory_type @@ -427,6 +430,8 @@ enum elf_gfxip_level EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033, EF_AMDGPU_MACH_AMDGCN_GFX1030 = 0x036, EF_AMDGPU_MACH_AMDGCN_GFX1100 = 0x041, + EF_AMDGPU_MACH_AMDGCN_GFX1150 = 0x043, + EF_AMDGPU_MACH_AMDGCN_GFX1200 = 0x04e, }; struct sqtt_file_chunk_spm_db { diff --git a/extra/sqtt/test_timing.py b/extra/sqtt/test_timing.py new file mode 100644 index 0000000000..f0f51516c3 --- /dev/null +++ b/extra/sqtt/test_timing.py @@ -0,0 +1,112 @@ +import os +os.environ["PYTHONPATH"] = "." +os.environ["SQTT"] = "1" +if "DEV" not in os.environ: os.environ["DEV"] = "AMD" +os.environ["VIZ"] = "1" +os.environ["AMD_LLVM"] = "0" + +import unittest +import sys, contextlib +from tinygrad import Tensor +from tinygrad.dtype import dtypes +from tinygrad.renderer import ProgramSpec +from tinygrad.uop.ops import UOp, Ops, KernelInfo, AddrSpace +from tinygrad.engine.realize import CompiledRunner +from tinygrad.device import Device, ProfileDeviceEvent + +from extra.sqtt.roc import decode, InstExec, PrgExec + +dev = Device[os.environ["DEV"]] + +def custom(arg:str, s:UOp|None=None) -> UOp: return UOp(Ops.CUSTOM, src=(s,) if s is not None else (), arg=arg) + +def asm_kernel(instrs:list[str], l:int=1, g:int=1) -> Tensor: + name = sys._getframe(1).f_code.co_name + def fxn(_): + L = UOp.special(l, "lidx0") + G = UOp.special(g, "gidx0") + op = custom("asm volatile (") + for inst in instrs: op = custom(f' "{inst}\\n\\t"', op) + op = custom(");", op) + return UOp.sink(op, L, G, arg=KernelInfo(name=name)) + k = Tensor.custom_kernel(Tensor.empty(1), fxn=fxn)[0] + return k + +@contextlib.contextmanager +def save_sqtt(): + # clear the old traces + dev.profile_events.clear() + sqtt:dict[PrgExec, list[InstExec]] = {} + yield sqtt + # decode sqtt + if os.environ["DEV"] == "AMD": + rctx = decode(dev.profile_events+[ProfileDeviceEvent("AMD", props=dev.device_props())]) + assert len(rctx.inst_execs) > 0, "empty sqtt output" + sqtt.update(rctx.inst_execs) + +class TestTiming(unittest.TestCase): + def test_v_add(self): + with save_sqtt() as sqtt: + asm_kernel([f"v_add_f32 v{10+i} v{10+i+1} {10+i}" for i in range(3)]).realize() + wave = list(sqtt.values())[0][:-1] + assert all(s.dur == 1 for s in wave) + assert all(s.stall == 0 for s in wave) + + def test_chain_v_add_1l(self): + with save_sqtt() as sqtt: + asm_kernel([ + "v_add_f32_e32 v1 v0 v0", + "v_add_f32_e32 v2 v1 v1", + ]).realize() + wave = list(sqtt.values())[0][:-1] + assert all(s.dur == 1 for s in wave) + assert all(s.stall == 0 for s in wave) + + def test_multi_cycle_inst(self): + def custom_vrcp(A, B): + op = custom("float a = 0.0;") + op = custom("float b = (*(data1_1+0));", op) + #op = custom('asm volatile("v_mul_f32_e32 %2 %2 %1" : "+v"(a) : "v"(b));', op) + op = custom('asm volatile("v_rcp_f32_e32 %2 %1" : "+v"(a) : "v"(b));', op) + op = custom('asm volatile("v_add_f32_e64 %1 %1 1.0" : "+v"(a));', op) + op = custom("*(data0_1+0) = a;", op) + return UOp.sink(op, A, B, arg=KernelInfo(name="custom_vrcp")) + out = Tensor([0.]).realize() + inp = Tensor([-2.0]).realize() + with save_sqtt() as sqtt: + Tensor.custom_kernel(out, inp, fxn=custom_vrcp)[0].realize() + + wave = list(sqtt.values())[0][0] + for i in range(len(wave.insts)): + if wave.insts[i].inst.startswith("global_store"): + print(f"store diff {wave.insts[i].time-(wave.insts[i-1].time)}") + self.assertEqual(out.item(), 0.5) + + def test_wmma(self): + with save_sqtt() as sqtt: + asm_kernel([ + "v_wmma_f32_16x16x16_f16 v[16:23], v[0:7], v[8:15], v[16:23]", + "v_add_f32_e32 v0 v16 v0", + ], l=32*4).realize() + assert len(sqtt) == 2, f"expected two waves, got {len(sqtt)} {list(sqtt.keys())}" + wmma = list(sqtt.values())[0][0] + self.assertGreater(wmma.dur, 1) # rgp says 32 clocks + + def test_sleep(self): + n = 1 + def sleep_kernel(data0): + assert data0.dtype.base == dtypes.ulong + op = custom("unsigned long long t0 = __builtin_readcyclecounter();") + op = custom(f"__builtin_amdgcn_s_sleep({n});", op) + op = custom(f"unsigned long long t1 = __builtin_readcyclecounter();", op) + op = custom(f"data0_{data0.size}[0] = t1 - t0;", op) + return UOp.sink(data0, op, arg=KernelInfo(name=f"sleep_{n}")) + diff_hw_reg = Tensor.empty(1, dtype=dtypes.ulong) + diff_hw_reg = Tensor.custom_kernel(diff_hw_reg, fxn=sleep_kernel)[0] + with save_sqtt() as sqtt: + diff_hw_reg.realize() + diff_sqtt = list(sqtt.values())[0][2] + self.assertEqual(diff_sqtt.dur, diff_hw_reg.item()-1) # 1 cycle for reading the counter register + +if __name__ == "__main__": + unittest.main() diff --git a/extra/test_hcopt.py b/extra/test_hcopt.py deleted file mode 100644 index 36978bf831..0000000000 --- a/extra/test_hcopt.py +++ /dev/null @@ -1,40 +0,0 @@ -import time -from extra.optimization.helpers import load_worlds, ast_str_to_ast -from tinygrad import Device -from tinygrad.codegen.lowerer import pm_lowerer, get_index -from tinygrad.uop.ops import graph_rewrite -from tinygrad.codegen.opt.kernel import Kernel -from tinygrad.codegen.opt.postrange import Scheduler -from tinygrad.codegen.opt.heuristic import hand_coded_optimizations -from tinygrad.helpers import getenv - -if __name__ == "__main__": - renderer = Device.default.renderer - ast_strs = load_worlds() - if (n:=getenv("N", -1)) != -1: ast_strs = ast_strs[n:n+1] - good = 0 - for i, ast_str in enumerate(ast_strs): - ast = ast_str_to_ast(ast_str) - - st = time.perf_counter() - lin = Kernel(ast, renderer) - opt1 = hand_coded_optimizations(lin) - et_lin = time.perf_counter() - st - - lowered = graph_rewrite(ast, pm_lowerer, ctx=get_index(ast), bottom_up=True) - st = time.perf_counter() - sch = Scheduler(lowered, renderer) - sch.convert_loop_to_global() - sch.simplify_merge_adjacent() - opt2 = hand_coded_optimizations(sch) - et_sch = time.perf_counter() - st - - if opt1 != opt2: - print(f"******* {i:6d}") - print("Kernel: ", lin.colored_shape(), "->", lin.apply_opts(opt1).colored_shape()) - print("Scheduler: ", sch.colored_shape(), "->", sch.apply_opts(opt2).colored_shape()) - print(opt1) - print(opt2) - else: - good += 1 - print(f"******* {i:6d} MATCH {good/(i+1)*100:.2f}% -- {et_lin/et_sch:4.2f}x speedup") diff --git a/extra/thunder/cuda/fa.cu b/extra/thunder/cuda/fa.cu new file mode 100644 index 0000000000..a18e2f155f --- /dev/null +++ b/extra/thunder/cuda/fa.cu @@ -0,0 +1,106 @@ +#include "kittens.cuh" + +using namespace kittens; + +constexpr int NUM_WORKERS = 4; +constexpr int PIPE_STAGES = 3; + +constexpr int ATTN_B = 16; +constexpr int ATTN_N = 1024; +constexpr int ATTN_H = 16; +constexpr int ATTN_D = 64; + +template constexpr size_t ROWS = 16*(64/D); // height of each worker tile (rows) +template using qkvo_tile = rt, D, L>; +template using attn_tile = rt, ROWS>; +template using shared_tile = st_bf, D>; +template using global_layout = gl; // B, N, H, specified at runtime, D known at compile time for this kernel +template struct globals { global_layout Qg, Kg, Vg, Og; }; + +__launch_bounds__(NUM_WORKERS*WARP_THREADS, 1) +__global__ void attend_ker(bf16 *O_ptr, bf16 *Q_ptr, bf16 *K_ptr, bf16 *V_ptr) { + constexpr int D = ATTN_D; + global_layout Qg{Q_ptr, ATTN_B, ATTN_N, ATTN_H, nullptr}; + global_layout Kg{K_ptr, ATTN_B, ATTN_N, ATTN_H, nullptr}; + global_layout Vg{V_ptr, ATTN_B, ATTN_N, ATTN_H, nullptr}; + global_layout Og{O_ptr, ATTN_B, ATTN_N, ATTN_H, nullptr}; + globals g(Qg, Kg, Vg, Og); + + using load_group = kittens::group<2>; // pairs of workers collaboratively load k, v tiles + int loadid = load_group::groupid(), workerid = kittens::warpid(); // which worker am I? + constexpr int LOAD_BLOCKS = NUM_WORKERS / load_group::GROUP_WARPS; + const int batch = blockIdx.z, head = blockIdx.y, q_seq = blockIdx.x * NUM_WORKERS + workerid; + + extern __shared__ alignment_dummy __shm[]; + shared_allocator al((int*)&__shm[0]); + + shared_tile (&k_smem)[LOAD_BLOCKS][PIPE_STAGES] = al.allocate, LOAD_BLOCKS, PIPE_STAGES>(); + shared_tile (&v_smem)[LOAD_BLOCKS][PIPE_STAGES] = al.allocate, LOAD_BLOCKS, PIPE_STAGES>(); + + shared_tile (&qo_smem)[NUM_WORKERS] = reinterpret_cast(&)[NUM_WORKERS]>(k_smem); + // Initialize all of the register tiles. + qkvo_tile q_reg, k_reg; // Q and K are both row layout, as we use mma_ABt. + qkvo_tile v_reg; // V is column layout, as we use mma_AB. + qkvo_tile o_reg; // Output tile. + attn_tile att_block; // attention tile, in float. (We want to use float wherever possible.) + attn_tile att_block_mma; // bf16 attention tile for the second mma_AB. We cast right before that op. + typename attn_tile::col_vec max_vec_last, max_vec, norm_vec; // these are column vectors for the in-place softmax. + // each warp loads its own Q tile of 16x64 + if (q_seq*ROWS < g.Qg.depth()) { + warp::load<1, false>(qo_smem[workerid], g.Qg, {batch, q_seq, head, 0}); // going through shared memory improves coalescing of dram reads. + __syncwarp(); + warp::load(q_reg, qo_smem[workerid]); + } + __syncthreads(); + + if constexpr(D == 64) q_reg *= __float2bfloat16(0.125f * 1.44269504089f); + else if constexpr(D == 128) q_reg *= __float2bfloat16(0.08838834764f * 1.44269504089f); + + max_vec = base_types::constants::neg_infty(); + norm_vec = 0.f; + o_reg = 0.f; + // launch the load of the first k, v tiles + int kv_blocks = (g.Kg.depth() + LOAD_BLOCKS*ROWS-1) / (LOAD_BLOCKS*ROWS), tic = 0; + load_group::load_async<1, false>(k_smem[loadid][0], g.Kg, {batch, loadid, head, 0}); + load_group::load_async<1, false>(v_smem[loadid][0], g.Vg, {batch, loadid, head, 0}); + // iterate over k, v for these q's that have been loaded + for(auto kv_idx = 0; kv_idx < kv_blocks; kv_idx++, tic=(tic+1)%3) { + int next_load_idx = (kv_idx+1)*LOAD_BLOCKS + loadid; + if(next_load_idx*ROWS < g.Kg.depth()) { + int next_tic = (tic+1)%3; + load_group::load_async<1, false>(k_smem[loadid][next_tic], g.Kg, {batch, next_load_idx, head, 0}); + load_group::load_async<1, false>(v_smem[loadid][next_tic], g.Vg, {batch, next_load_idx, head, 0}); + load_async_wait<1>(); // next k, v can stay in flight. + } + else load_async_wait(); + __syncthreads(); + + #pragma unroll LOAD_BLOCKS + for(int subtile = 0; subtile < LOAD_BLOCKS && (kv_idx*LOAD_BLOCKS + subtile)*ROWS < g.Kg.depth(); subtile++) { + warp::load(k_reg, k_smem[subtile][tic]); // load k from shared into registers + att_block = 0.f; // zero 16x16 attention tile + warp::mma(att_block, q_reg, k_reg, att_block); // Q@K.T + // int first_index = (kv_idx*LOAD_BLOCKS + subtile)*ROWS; // one past the last KV index of this tile + // int start_fill = g.Kg.depth()-first_index < ROWS ? g.Kg.depth()-first_index : ROWS; + // right_fill(att_block, att_block, start_fill, base_types::constants::neg_infty()); + max_vec_last = max_vec; + max_vec = warp::max(att_block, max_vec); + att_block = warp::exp2(att_block - max_vec); + max_vec_last = warp::exp2(max_vec_last - max_vec); + norm_vec *= max_vec_last; + norm_vec = warp::sum(att_block, norm_vec); + att_block_mma = att_block; // copy to bf16 tile + warp::load(v_reg, v_smem[subtile][tic]); + o_reg *= max_vec_last; + warp::mma(o_reg, att_block_mma, v_reg, o_reg); + } + } + + o_reg /= norm_vec; + __syncthreads(); + if (q_seq*ROWS < g.Og.depth()) { // write out o. + warp::store(qo_smem[workerid], o_reg); // going through shared memory improves coalescing of dram writes. + __syncwarp(); + warp::store<1, false>(g.Og, qo_smem[workerid], {batch, q_seq, head, 0}); + } +} diff --git a/extra/thunder/cuda/fa.py b/extra/thunder/cuda/fa.py new file mode 100644 index 0000000000..fd0c5bede7 --- /dev/null +++ b/extra/thunder/cuda/fa.py @@ -0,0 +1,43 @@ +import pathlib +from tinygrad import Device, Tensor +from tinygrad.helpers import Context +from tinygrad.runtime.support.compiler_cuda import pretty_ptx, NVCCCompiler + +if __name__ == "__main__": + code = (pathlib.Path(__file__).parent / "fa.cu").read_text() + device = Device["CUDA"] + kitten_args = [f"-I{(pathlib.Path(__file__).parent / 'include').as_posix()}", "-std=c++20", "--expt-relaxed-constexpr", "-DKITTENS_4090"] + lib = NVCCCompiler(device.compiler.arch, kitten_args).compile(code) + kernel_name = lib.decode().split(".globl\t")[1].split("\n")[0] + print("kernel name", kernel_name) + print(pretty_ptx(lib.decode())) + + prg = device.runtime(kernel_name, lib) + prg.smem = 16384 * 3 + + B, N, H, D = 16, 1024, 16, 64 + q = Tensor.randn(B, N, H, D, device='CUDA', dtype="bfloat16") + k = Tensor.randn(B, N, H, D, device='CUDA', dtype="bfloat16") + v = Tensor.randn(B, N, H, D, device='CUDA', dtype="bfloat16") + out = Tensor.empty(B, N, H, D, device='CUDA', dtype="bfloat16") + Tensor.realize(q, k, v, out) + + NUM_WORKERS = 4 + ROWS = 16 * (64 // D) + + gsz = (N // (ROWS*NUM_WORKERS), H, B) + for _ in range(5): + et = prg(out.uop.buffer.ensure_allocated()._buf, q.uop.buffer._buf, k.uop.buffer._buf, v.uop.buffer._buf, + global_size=gsz, local_size=(ROWS*NUM_WORKERS,1,1), wait=True) + + attn_flops = 2 * B * H * N * N * D + \ + 4 * B * H * N * N + \ + 2 * B * H * N * N * D + print(f"{attn_flops/(et*1e9):2f} GFLOPS") + + for _ in range(5): + with Context(DEBUG=2): + ref = q.scaled_dot_product_attention(k, v) + + ref, out = ref.float(), out.float() + print((ref-out).mean().item(), (ref-out).max().item()) diff --git a/extra/thunder/cuda/include/common/base_ops.cuh b/extra/thunder/cuda/include/common/base_ops.cuh new file mode 100644 index 0000000000..cbade07113 --- /dev/null +++ b/extra/thunder/cuda/include/common/base_ops.cuh @@ -0,0 +1,400 @@ +/** + * @file + * @brief Basic operations on generic types. + */ + +#pragma once + +#include +#include +#include "base_types.cuh" + +namespace kittens { + +/** + * @namespace base_ops + * + * @brief A namespace for operations on basic data types. + */ +namespace base_ops { + +/* ---------- CONST OPS ---------- */ + +/** + * @brief Represents the zero constant operation. + * + * This operation returns the zero value of the specified type. + * + * @tparam T The data type for which to return the zero value. + * @return The zero value of type T. + */ +struct zero { + template __device__ static inline constexpr T op(args... _) { return base_types::constants::zero(); } +}; +/** + * @brief Represents the one constant operation. + * + * This operation returns the one value of the specified type. + * + * @tparam T The data type for which to return the one value. + * @return The one value of type T. + */ +struct one { + template __device__ static inline constexpr T op(args... _) { return base_types::constants::one(); } +}; +/** + * @brief Represents the positive infinity constant operation. + * + * This operation returns the positive infinity value of the specified type. + * + * @tparam T The data type for which to return the positive infinity value. + * @return The positive infinity value of type T. + */ +struct pos_infty { + template __device__ static inline constexpr T op(args... _) { return base_types::constants::pos_infty(); } +}; +/** + * @brief Represents the negative infinity constant operation. + * + * This operation returns the negative infinity value of the specified type. + * + * @tparam T The data type for which to return the negative infinity value. + * @return The negative infinity value of type T. + */ +struct neg_infty { + template __device__ static inline constexpr T op(args... _) { return base_types::constants::neg_infty(); } +}; + + +/* ---------- UNARY OPS ---------- */ + +/** + * @brief Exponential function operation. + * + * This operation calculates the exponential of the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The exponential of the input value. + */ +struct exp { + template static __device__ inline T op(const T &x) { return exp(x); } +}; +template<> __device__ inline float exp::op (const float &x ) { return __expf(x); } +template<> __device__ inline float2 exp::op(const float2 &x) { return float2{__expf(x.x), __expf(x.y)}; } +template<> __device__ inline bf16 exp::op (const bf16 &x ) { return hexp(x); } +template<> __device__ inline bf16_2 exp::op(const bf16_2 &x) { return h2exp(x); } +template<> __device__ inline half exp::op (const half &x ) { return hexp(x); } +template<> __device__ inline half_2 exp::op(const half_2 &x) { return h2exp(x); } + +/** + * @brief Exponential function operation, in base 2 + * + * This operation calculates the exponential of the input value, in base 2. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The exponential of the input value. + */ +struct exp2 { + template static __device__ inline T op(const T &x) { return exp2f(x); } +}; +template<> __device__ inline float exp2::op (const float &x ) { return exp2f(x); } +template<> __device__ inline float2 exp2::op(const float2 &x) { return float2{exp2f(x.x), exp2f(x.y)}; } +template<> __device__ inline bf16 exp2::op (const bf16 &x ) { return hexp2(x); } +template<> __device__ inline bf16_2 exp2::op(const bf16_2 &x) { return h2exp2(x); } +template<> __device__ inline half exp2::op (const half &x ) { return hexp2(x); } +template<> __device__ inline half_2 exp2::op(const half_2 &x) { return h2exp2(x); } +/** + * @brief Natural log function operation. + * + * This operation calculates the natural logarithm of the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The natural logarithm of the input value. + */ +struct log { + template static __device__ inline T op(const T &x) { return log(x); } +}; +template<> __device__ inline float log::op (const float &x ) { return __logf(x); } +template<> __device__ inline float2 log::op(const float2 &x) { return float2{__logf(x.x), __logf(x.y)}; } +template<> __device__ inline bf16 log::op (const bf16 &x ) { return hlog(x); } +template<> __device__ inline bf16_2 log::op(const bf16_2 &x) { return h2log(x); } +template<> __device__ inline half log::op (const half &x ) { return hlog(x); } +template<> __device__ inline half_2 log::op(const half_2 &x) { return h2log(x); } +/** + * @brief Logarithm base 2 operation. + * + * This operation calculates the logarithm base 2 of the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The logarithm base 2 of the input value. + */ +struct log2 { + template static __device__ inline T op(const T &x) { return log2(x); } +}; +template<> __device__ inline float log2::op (const float &x ) { return __log2f(x); } +template<> __device__ inline float2 log2::op(const float2 &x) { return float2{__log2f(x.x), __log2f(x.y)}; } +template<> __device__ inline bf16 log2::op (const bf16 &x ) { return hlog2(x); } +template<> __device__ inline bf16_2 log2::op(const bf16_2 &x) { return h2log2(x); } +template<> __device__ inline half log2::op (const half &x ) { return hlog2(x); } +template<> __device__ inline half_2 log2::op(const half_2 &x) { return h2log2(x); } +/** + * @brief Absolute value operation. + * + * This operation calculates the absolute value of the input. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The absolute value of the input. + */ +struct abs { + template static __device__ inline T op(const T &x) { return abs(x); } +}; +template<> __device__ inline float abs::op (const float &x ) { return fabsf(x); } +template<> __device__ inline float2 abs::op(const float2 &x) { return float2{fabsf(x.x), fabsf(x.y)}; } +template<> __device__ inline bf16 abs::op (const bf16 &x ) { return __habs(x); } +template<> __device__ inline bf16_2 abs::op(const bf16_2 &x) { return __habs2(x); } +template<> __device__ inline half abs::op (const half &x ) { return __habs(x); } +template<> __device__ inline half_2 abs::op(const half_2 &x) { return __habs2(x); } +/** + * @brief Rectified Linear Unit (ReLU) operation. + * + * This operation applies the ReLU function to the input, which is the + * maximum of zero and the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The result of ReLU function applied to the input. + */ +struct relu { + template static __device__ inline T op(const T &x) { return max(x, base_types::constants::zero()); } +}; +template<> __device__ inline float relu::op (const float &x ) { return max(x, 0.f); } +template<> __device__ inline float2 relu::op(const float2 &x) { return float2{max(x.x, 0.f), max(x.y, 0.f)}; } +template<> __device__ inline bf16 relu::op (const bf16 &x ) { return __hmax(x, base_types::constants::zero()); } +template<> __device__ inline bf16_2 relu::op(const bf16_2 &x) { return __hmax2(x, base_types::constants::zero()); } +template<> __device__ inline half relu::op (const half &x ) { return __hmax(x, base_types::constants::zero()); } +template<> __device__ inline half_2 relu::op(const half_2 &x) { return __hmax2(x, base_types::constants::zero()); } +/** + * @brief Copy operation. + * + * This operation returns the input value unchanged. + * + * @tparam T The data type of the input and output values. + * @param a[in] The input value. + * @return The same value as the input. + */ +struct copy { // for non-compile-time setters. + template static __device__ inline T op(const T &a) { return a; } +}; + + +/* ---------- BINARY OPS ---------- */ + +/** + * @brief Copy2 operation. + * + * This operation returns the second input value unchanged. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value (ignored). + * @param b[in] The second input value. + * @return The same value as the second input. + */ +struct copy2 { // this turns out to be a slightly hacky op that makes some code cleaner :/ + template static __device__ inline T op(const T &a, const T &b) { return b; } +}; +/** + * @brief Sum operation. + * + * This operation calculates the sum of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The sum of the input values. + */ +struct sum { + template static __device__ inline T op(const T &a, const T &b) { return a+b; } +}; +template<> __device__ inline float2 sum::op(const float2 &a, const float2 &b) { +#ifdef KITTENS_BLACKWELL + float2 c; + asm volatile("add.f32x2 %0, %1, %2;" : "=l"(*(uint64_t*)&c) : "l"(*(uint64_t*)&a), "l"(*(uint64_t*)&b)); + return c; +#else + return float2{a.x+b.x, a.y+b.y}; +#endif +} +template<> __device__ inline bf16 sum::op (const bf16 &a, const bf16 &b) { return __hadd(a, b); } +template<> __device__ inline bf16_2 sum::op(const bf16_2 &a, const bf16_2 &b) { return __hadd2(a, b); } +template<> __device__ inline half sum::op (const half &a, const half &b) { return __hadd(a, b); } +template<> __device__ inline half_2 sum::op(const half_2 &a, const half_2 &b) { return __hadd2(a, b); } +/** + * @brief Subtraction operation. + * + * This operation calculates the difference between two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The difference between the input values. + */ +struct sub { + template static __device__ inline T op(const T &a, const T &b) { return a-b; } +}; +template<> __device__ inline float2 sub::op(const float2 &a, const float2 &b) { +#ifdef KITTENS_BLACKWELL + float2 c; + asm volatile("sub.f32x2 %0, %1, %2;" : "=l"(*(uint64_t*)&c) : "l"(*(uint64_t*)&a), "l"(*(uint64_t*)&b)); + return c; +#else + return float2{a.x-b.x, a.y-b.y}; +#endif +} +template<> __device__ inline bf16 sub::op (const bf16 &a, const bf16 &b) { return __hsub(a, b); } +template<> __device__ inline bf16_2 sub::op(const bf16_2 &a, const bf16_2 &b) { return __hsub2(a, b); } +template<> __device__ inline half sub::op (const half &a, const half &b) { return __hsub(a, b); } +template<> __device__ inline half_2 sub::op(const half_2 &a, const half_2 &b) { return __hsub2(a, b); } +/** + * @brief Multiplication operation. + * + * This operation calculates the product of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The product of the input values. + */ +struct mul { + template static __device__ inline T op(const T &a, const T &b) { return a*b; } +}; +template<> __device__ inline float2 mul::op(const float2 &a, const float2 &b) { +#ifdef KITTENS_BLACKWELL + float2 c; + asm volatile("mul.f32x2 %0, %1, %2;" : "=l"(*(uint64_t*)&c) : "l"(*(uint64_t*)&a), "l"(*(uint64_t*)&b)); + return c; +#else + return float2{a.x*b.x, a.y*b.y}; +#endif +} +template<> __device__ inline bf16 mul::op (const bf16 &a, const bf16 &b) { return __hmul(a, b); } +template<> __device__ inline bf16_2 mul::op(const bf16_2 &a, const bf16_2 &b) { return __hmul2(a, b); } +template<> __device__ inline half mul::op (const half &a, const half &b) { return __hmul(a, b); } +template<> __device__ inline half_2 mul::op(const half_2 &a, const half_2 &b) { return __hmul2(a, b); } +/** + * @brief Division operation. + * + * This operation calculates the quotient of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The quotient of the input values. + */ +struct div { + template static __device__ inline T op(const T &a, const T &b) { return a/b; } +}; +template<> __device__ inline float2 div::op(const float2 &a, const float2 &b) { return float2{a.x/b.x, a.y/b.y}; } +template<> __device__ inline bf16 div::op (const bf16 &a, const bf16 &b) { return __hdiv(a, b); } +template<> __device__ inline bf16_2 div::op(const bf16_2 &a, const bf16_2 &b) { return __h2div(a, b); } // this op is a special snowflake +template<> __device__ inline half div::op (const half &a, const half &b) { return __hdiv(a, b); } +template<> __device__ inline half_2 div::op(const half_2 &a, const half_2 &b) { return __h2div(a, b); } +/** + * @brief Maximum operation. + * + * This operation calculates the maximum of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The maximum of the input values. + */ + struct max { + template static __device__ inline T op(const T &a, const T &b) { return ::max(a, b); } +}; +template<> __device__ inline float2 max::op(const float2 &a, const float2 &b) { return float2{::max(a.x, b.x), ::max(a.y, b.y)}; } +template<> __device__ inline bf16 max::op (const bf16 &a, const bf16 &b) { return __hmax(a, b); } +template<> __device__ inline bf16_2 max::op(const bf16_2 &a, const bf16_2 &b) { return __hmax2(a, b); } +template<> __device__ inline half max::op (const half &a, const half &b) { return __hmax(a, b); } +template<> __device__ inline half_2 max::op(const half_2 &a, const half_2 &b) { return __hmax2(a, b); } +/** + * @brief Minimum operation. + * + * This operation calculates the minimum of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The minimum of the input values. + */ +struct min { + template static __device__ inline T op(const T &a, const T &b) { return ::min(a, b); } +}; +template<> __device__ inline float2 min::op(const float2 &a, const float2 &b) { return float2{::min(a.x, b.x), ::min(a.y, b.y)}; } +template<> __device__ inline bf16 min::op (const bf16 &a, const bf16 &b) { return __hmin(a, b); } +template<> __device__ inline bf16_2 min::op(const bf16_2 &a, const bf16_2 &b) { return __hmin2(a, b); } +template<> __device__ inline half min::op (const half &a, const half &b) { return __hmin(a, b); } +template<> __device__ inline half_2 min::op(const half_2 &a, const half_2 &b) { return __hmin2(a, b); } + + +/* ---------- TERNARY OPS ---------- */ + +/** + * @brief Fused multiply-add operation A * B + C. + * + * This operation performs a fused multiply-add, computing (A * B) + C with only one rounding. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @param c[in] The third input value to be added. + * @return The result of the fused multiply-add operation. + */ +struct fma_AxBtC { + template static __device__ inline T op(const T &a, const T &b, const T &c) { + return sum::op(mul::op(a, b), c); + } +}; +template<> __device__ inline float2 fma_AxBtC::op(const float2 &a, const float2 &b, const float2 &c) { +#ifdef KITTENS_BLACKWELL + float2 d; + asm volatile("fma.rn.f32x2 %0, %1, %2, %3;" : "=l"(*(uint64_t*)&d) : "l"(*(uint64_t*)&a), "l"(*(uint64_t*)&b), "l"(*(uint64_t*)&c)); + return d; +#else + return float2{a.x*b.x+c.x, a.y*b.y+c.y}; +#endif +} +/** + * @brief Fused multiply-add operation A * C + B. + * + * This operation performs a fused multiply-add, computing (A * C) + B with only one rounding. + * This is particularly useful for attention mechanisms in neural networks. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The third input value to be added. + * @param c[in] The second input value. + * @return The result of the fused multiply-add operation. + */ +struct fma_AxCtB { // this is the one needed for attention + template static __device__ inline T op(const T &a, const T &b, const T &c) { + return sum::op(mul::op(a, c), b); + } +}; +template<> __device__ inline float2 fma_AxCtB::op(const float2 &a, const float2 &b, const float2 &c) { +#ifdef KITTENS_BLACKWELL + float2 d; + asm volatile("fma.rn.f32x2 %0, %1, %2, %3;" : "=l"(*(uint64_t*)&d) : "l"(*(uint64_t*)&a), "l"(*(uint64_t*)&c), "l"(*(uint64_t*)&b)); + return d; +#else + return float2{a.x*c.x+b.x, a.y*c.y+b.y}; +#endif +} + +} // namespace base_ops + +} // namespace kittens diff --git a/extra/thunder/cuda/include/common/base_types.cuh b/extra/thunder/cuda/include/common/base_types.cuh new file mode 100644 index 0000000000..bd1109c40c --- /dev/null +++ b/extra/thunder/cuda/include/common/base_types.cuh @@ -0,0 +1,519 @@ +/** + * @file + * @brief Declarations, manipulations, and wrappers for basic types. + * + * This file is a bunch of utilities for going back and forth between different types. + * + * Many of them are for the compiler, so as to clean up the code. It unfortunately + * seems necessary when we have types we really care about that are less than word width. + */ + +#pragma once + +#ifdef KITTENS_HOPPER +#include +#endif + +#include +#include +#include +#include + + +namespace kittens { + +/** + * @brief Bfloat16 floating-point type. + */ +using bf16 = __nv_bfloat16; +/** + * @brief Half-precision floating-point type. + */ +using half = __half; +/** + * @brief Packed word of two bfloat16 floating-point values. + */ +using bf16_2 = __nv_bfloat162; +/** + * @brief Packed word of two half-precision floating-point values. + */ +using half_2 = __half2; +#ifdef KITTENS_HOPPER +/** + * @brief float8 floating-point type. + */ +using fp8e4m3 = __nv_fp8_e4m3; +using fp8e5m2 = __nv_fp8_e5m2; +#ifdef KITTENS_BLACKWELL +using fp8e8m0 = __nv_fp8_e8m0; +#endif +/** + * @brief 2-packed float8 floating-point type. + */ +using fp8e4m3_2 = __nv_fp8x2_e4m3; +using fp8e5m2_2 = __nv_fp8x2_e5m2; +#ifdef KITTENS_BLACKWELL +using fp8e8m0_2 = __nv_fp8x2_e8m0; +#endif +/** + * @brief 4-packed float8 floating-point type. + */ +using fp8e4m3_4 = __nv_fp8x4_e4m3; +using fp8e5m2_4 = __nv_fp8x4_e5m2; +#ifdef KITTENS_BLACKWELL +using fp8e8m0_4 = __nv_fp8x4_e8m0; +#endif +#endif + +namespace ducks { +/** + * @namespace base_types + * + * @brief A namespace for concepts for basic data types. + */ +namespace base_types { + +#ifdef KITTENS_HOPPER +#ifdef KITTENS_BLACKWELL +template +concept T2 = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; // could add half_2 later if implemented. +template +concept T1 = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; // could add half_2 later if implemented. +#else +template +concept T2 = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; +template +concept T1 = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; +#endif +#else +template +concept T2 = std::is_same_v || std::is_same_v || std::is_same_v; +template +concept T1 = std::is_same_v || std::is_same_v || std::is_same_v; +#endif + +} // namespace base_types +} // namespace ducks + +/** + * @namespace base_types + * + * @brief A namespace for ThunderKittens basic data types. + */ +namespace base_types { + +/** + * @brief Provides compile-time constants for different types. + * + * @tparam T The type for which to provide constants. + */ +template struct constants { + /** + * @brief Zero + * @return Constexpr zero with type T + */ + static __device__ inline constexpr T zero() { return T{0}; } + /** + * @brief One + * @return Constexpr one with type T + */ + static __device__ inline constexpr T one() { return T{1}; } + /** + * @brief Positive infinity. Particularly useful for initializing before a min op. + * @return Constexpr positive infinity with type T + */ + static __device__ inline constexpr T pos_infty() { return T{INFINITY}; } // I'll find a better way at some point but this appears to work. + /** + * @brief Negative infinity. Particularly useful for initializing before a max op. + * @return Constexpr negative infinity with type T + */ + static __device__ inline constexpr T neg_infty() { return T{-INFINITY}; } +}; +template<> struct constants { + static __device__ inline constexpr float2 zero() { return float2{0.f, 0.f}; } + static __device__ inline constexpr float2 one() { return float2{1.f, 1.f}; } + static __device__ inline constexpr float2 pos_infty() { return float2{constants::pos_infty(), constants::pos_infty()}; } + static __device__ inline constexpr float2 neg_infty() { return float2{constants::neg_infty(), constants::neg_infty()}; } +}; +template<> struct constants { + static __device__ inline constexpr bf16 zero() { return std::bit_cast<__nv_bfloat16>(uint16_t(0x0000)); } // unfortunately __float2bf16_rn is not constexpr + static __device__ inline constexpr bf16 one() { return std::bit_cast<__nv_bfloat16>(uint16_t(0x3F80)); } + static __device__ inline constexpr bf16 pos_infty() { return std::bit_cast<__nv_bfloat16>(uint16_t(0x7F80)); } + static __device__ inline constexpr bf16 neg_infty() { return std::bit_cast<__nv_bfloat16>(uint16_t(0xFF80)); } +}; +template<> struct constants { + static __device__ inline constexpr bf16_2 zero() { return bf16_2{constants::zero(), constants::zero()}; } + static __device__ inline constexpr bf16_2 one() { return bf16_2{constants::one(), constants::one()}; } + static __device__ inline constexpr bf16_2 pos_infty() { return bf16_2{constants::pos_infty(), constants::pos_infty()}; } + static __device__ inline constexpr bf16_2 neg_infty() { return bf16_2{constants::neg_infty(), constants::neg_infty()}; } +}; +template<> struct constants { + static __device__ inline constexpr half zero() { return std::bit_cast<__half>(uint16_t(0x0000)); } + static __device__ inline constexpr half one() { return std::bit_cast<__half>(uint16_t(0x3C00)); } + static __device__ inline constexpr half pos_infty() { return std::bit_cast<__half>(uint16_t(0x7C00)); } + static __device__ inline constexpr half neg_infty() { return std::bit_cast<__half>(uint16_t(0xFC00)); } +}; +template<> struct constants { + static __device__ inline constexpr half_2 zero() { return half_2{constants::zero(), constants::zero()}; } + static __device__ inline constexpr half_2 one() { return half_2{constants::one(), constants::one()}; } + static __device__ inline constexpr half_2 pos_infty() { return half_2{constants::pos_infty(), constants::pos_infty()}; } + static __device__ inline constexpr half_2 neg_infty() { return half_2{constants::neg_infty(), constants::neg_infty()}; } +}; +#ifdef KITTENS_HOPPER +template<> struct constants { + static __device__ inline constexpr fp8e4m3 zero() { return std::bit_cast<__nv_fp8_e4m3>(uint8_t(0x00)); } + static __device__ inline constexpr fp8e4m3 one() { return std::bit_cast<__nv_fp8_e4m3>(uint8_t(0x38)); } +}; +template<> struct constants { + static __device__ inline constexpr fp8e4m3_2 zero() { return std::bit_cast(uint16_t(0x0000)); } + static __device__ inline constexpr fp8e4m3_2 one() { return std::bit_cast(uint16_t(0x3838)); } +}; +template<> struct constants { + static __device__ inline constexpr fp8e4m3_4 zero() { return std::bit_cast(uint32_t(0x00000000)); } + static __device__ inline constexpr fp8e4m3_4 one() { return std::bit_cast(uint32_t(0x38383838)); } +}; +template<> struct constants { + static __device__ inline constexpr fp8e5m2 zero() { return std::bit_cast<__nv_fp8_e5m2>(uint8_t(0x00)); } + static __device__ inline constexpr fp8e5m2 one() { return std::bit_cast<__nv_fp8_e5m2>(uint8_t(0x3C)); } +}; +template<> struct constants { + static __device__ inline constexpr fp8e5m2_2 zero() { return std::bit_cast(uint16_t(0x0000)); } + static __device__ inline constexpr fp8e5m2_2 one() { return std::bit_cast(uint16_t(0x3C3C)); } +}; +template<> struct constants { + static __device__ inline constexpr fp8e5m2_4 zero() { return std::bit_cast(uint32_t(0x00000000)); } + static __device__ inline constexpr fp8e5m2_4 one() { return std::bit_cast(uint32_t(0x3C3C3C3C)); } +}; +#endif + +template<> struct constants { + static __device__ inline constexpr int zero() { return 0; } + static __device__ inline constexpr int one() { return 1; } +}; +template<> struct constants { + static __device__ inline constexpr int2 zero() { return int2{0, 0}; } + static __device__ inline constexpr int2 one() { return int2{1, 1}; } +}; + +/** + * @brief Provides information about packing of elements for a given type. + * + * @tparam T The type for which to provide packing information. + */ +template struct packing { + /** + * @brief The number of elements packed together. + * + * @return constexpr int representing number of elements within the type. + */ + static __device__ inline constexpr int num() { return 1; } + /** + * @brief Packs a single T element twice (replicated) into its packed type. + * + * @param i[in] The element to pack. + * @return The packed type. + */ + static __device__ inline constexpr T pack(const bf16 &i); +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = bf16; + using packed_type = bf16_2; + static __device__ inline constexpr bf16_2 pack(const bf16 &i) { return bf16_2{i, i}; } +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = bf16; + using packed_type = bf16_2; + static __device__ inline constexpr bf16_2 pack(const bf16 &i) { return bf16_2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = half; + using packed_type = half_2; + static __device__ inline constexpr half_2 pack(const half &i) { return half_2{i, i}; } +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = half; + using packed_type = half_2; + static __device__ inline constexpr half_2 pack(const half &i) { return half_2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = float; + using packed_type = float2; + static __device__ inline constexpr float2 pack(const float &i) { return float2{i, i}; } +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = float; + using packed_type = float2; + static __device__ inline constexpr float2 pack(const float &i) { return float2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = char; + using packed_type = char2; + static __device__ inline constexpr char2 pack(const char &i) { return char2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = char; + using packed_type = char2; + static __device__ inline constexpr char2 pack(const char &i) { return char2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = int; + using packed_type = int2; + static __device__ inline constexpr int2 pack(const int &i) { return int2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = int; + using packed_type = int2; + static __device__ inline constexpr int2 pack(const int &i) { return int2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = uint; + using packed_type = uint2; + static __device__ inline constexpr uint2 pack(const uint &i) { return uint2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = uint; + using packed_type = uint2; + static __device__ inline constexpr uint2 pack(const uint &i) { return uint2{i, i}; } // this replication makes code cleaner later. +}; +struct uint64_2 { uint64_t x, y; }; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = uint64_t; + using packed_type = uint64_2; + static __device__ inline constexpr uint64_2 pack(const uint64_t &i) { return uint64_2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 2; } + using unpacked_type = uint64_t; + using packed_type = uint64_2; + static __device__ inline constexpr uint64_2 pack(const uint64_t &i) { return uint64_2{i, i}; } // this replication makes code cleaner later. +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 4; } +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 4; } +}; +#ifdef KITTENS_HOPPER +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = fp8e4m3; + using packed_type = fp8e4m3_4; +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 4; } + using unpacked_type = fp8e4m3; + using packed_type = fp8e4m3_4; +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = fp8e5m2; + using packed_type = fp8e5m2_4; +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 4; } + using unpacked_type = fp8e5m2; + using packed_type = fp8e5m2_4; +}; +#ifdef KITTENS_BLACKWELL +template<> struct packing { + static __device__ inline constexpr int num() { return 1; } + using unpacked_type = fp8e8m0; + using packed_type = fp8e8m0_4; +}; +template<> struct packing { + static __device__ inline constexpr int num() { return 4; } + using unpacked_type = fp8e8m0; + using packed_type = fp8e8m0_4; +}; +#endif +#endif + + +/** + * @brief Provides templated functionality to convert between different types. + * + * @tparam T The target type for conversion. + * @tparam U The source type for conversion. + */ +template struct convertor { + /** + * @brief Converts a value of type U to type T. + * + * @param u[in] The value of type U to convert. + * @return T The converted value of type T. + */ + static __host__ __device__ inline T convert(const U & u) { + return (T)u; + } +}; +template<> struct convertor { + static __host__ __device__ inline float convert(const bf16 & u) { + return __bfloat162float(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline bf16 convert(const float & u) { + return __float2bfloat16_rn(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float2 convert(const bf16_2 & u) { + return __bfloat1622float2(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline bf16_2 convert(const float2 & u) { + return __float22bfloat162_rn(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float convert(const half & u) { + return __half2float(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline half convert(const float & u) { + return __float2half(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float2 convert(const half_2 & u) { + return __half22float2(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline half_2 convert(const float2 & u) { + return __float22half2_rn(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline bf16 convert(const half & u) { + return __float2bfloat16_rn(__half2float(u)); + } +}; +template<> struct convertor { + static __host__ __device__ inline half convert(const bf16 & u) { + return __float2half(__bfloat162float(u)); + } +}; +template<> struct convertor { + static __host__ __device__ inline bf16_2 convert(const half_2 & u) { + return __float22bfloat162_rn(__half22float2(u)); + } +}; +template<> struct convertor { + static __host__ __device__ inline half_2 convert(const bf16_2 & u) { + return __float22half2_rn(__bfloat1622float2(u)); + } +}; +#ifdef KITTENS_HOPPER +// fp8e4m3 +template<> struct convertor { + static __host__ __device__ inline fp8e4m3_4 convert(const float4& u) { + return __nv_fp8x4_e4m3(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float4 convert(const fp8e4m3_4& u) { + __nv_fp8_e4m3 *vals = reinterpret_cast<__nv_fp8_e4m3*>(const_cast<__nv_fp8x4_e4m3*>(&u)); + return make_float4(float(vals[0]), float(vals[1]), float(vals[2]), float(vals[3])); + } +}; +template<> struct convertor { + static __host__ __device__ inline fp8e4m3_2 convert(const float2& u) { + return __nv_fp8x2_e4m3(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float2 convert(const fp8e4m3_2& u) { + __nv_fp8_e4m3 *vals = reinterpret_cast<__nv_fp8_e4m3*>(const_cast<__nv_fp8x2_e4m3*>(&u)); + return make_float2(float(vals[0]), float(vals[1])); + } +}; +template<> struct convertor { + static __host__ __device__ inline fp8e4m3 convert(const float & u) { + return __nv_fp8_e4m3(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float convert(const fp8e4m3 & u) { + return float(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline bf16_2 convert(const fp8e4m3_4 & u) { + float4 f4 = convertor::convert(u); + float2 f2 = make_float2(f4.x, f4.y); + return __float22bfloat162_rn(f2); + } +}; +template<> struct convertor { + static __host__ __device__ inline fp8e4m3_4 convert(const bf16_2 & u) { + float2 f2 = __bfloat1622float2(u); + float4 f4 = make_float4(f2.x, f2.y, 0.0f, 0.0f); + return __nv_fp8x4_e4m3(f4); + } +}; +// fp8e5m2 +template<> struct convertor { + static __host__ __device__ inline fp8e5m2_4 convert(const float4& u) { + return __nv_fp8x4_e5m2(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float4 convert(const fp8e5m2_4& u) { + __nv_fp8_e5m2 *vals = reinterpret_cast<__nv_fp8_e5m2*>(const_cast<__nv_fp8x4_e5m2*>(&u)); + return make_float4(float(vals[0]), float(vals[1]), float(vals[2]), float(vals[3])); + } +}; +template<> struct convertor { + static __host__ __device__ inline fp8e5m2_2 convert(const float2& u) { + return __nv_fp8x2_e5m2(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float2 convert(const fp8e5m2_2& u) { + __nv_fp8_e5m2 *vals = reinterpret_cast<__nv_fp8_e5m2*>(const_cast<__nv_fp8x2_e5m2*>(&u)); + return make_float2(float(vals[0]), float(vals[1])); + } +}; +template<> struct convertor { + static __host__ __device__ inline fp8e5m2 convert(const float & u) { + return __nv_fp8_e5m2(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline float convert(const fp8e5m2 & u) { + return float(u); + } +}; +template<> struct convertor { + static __host__ __device__ inline bf16_2 convert(const fp8e5m2_4 & u) { + float4 f4 = convertor::convert(u); + float2 f2 = make_float2(f4.x, f4.y); + return __float22bfloat162_rn(f2); + } +}; +template<> struct convertor { + static __host__ __device__ inline fp8e5m2_4 convert(const bf16_2 & u) { + float2 f2 = __bfloat1622float2(u); + float4 f4 = make_float4(f2.x, f2.y, 0.0f, 0.0f); + return __nv_fp8x4_e5m2(f4); + } +}; +#endif +} +} diff --git a/extra/thunder/cuda/include/common/common.cuh b/extra/thunder/cuda/include/common/common.cuh new file mode 100644 index 0000000000..7a95a713cf --- /dev/null +++ b/extra/thunder/cuda/include/common/common.cuh @@ -0,0 +1,11 @@ +/** + * @file + * @brief A collection of common resources on which ThunderKittens depends. + */ + + +#pragma once + +#include "util.cuh" +#include "base_types.cuh" +#include "base_ops.cuh" \ No newline at end of file diff --git a/extra/thunder/cuda/include/common/debug.cuh b/extra/thunder/cuda/include/common/debug.cuh new file mode 100644 index 0000000000..586cbd3ce2 --- /dev/null +++ b/extra/thunder/cuda/include/common/debug.cuh @@ -0,0 +1,56 @@ +#pragma once + +// Reset +#define TK_RESET "\033[0m" + +// Foreground colors +#define TK_FG_BLACK "\033[30m" +#define TK_FG_RED "\033[31m" +#define TK_FG_GREEN "\033[32m" +#define TK_FG_YELLOW "\033[33m" +#define TK_FG_BLUE "\033[34m" +#define TK_FG_MAGENTA "\033[35m" +#define TK_FG_CYAN "\033[36m" +#define TK_FG_WHITE "\033[37m" + +// Background colors +#define TK_BG_BLACK "\033[40m" +#define TK_BG_RED "\033[41m" +#define TK_BG_GREEN "\033[42m" +#define TK_BG_YELLOW "\033[43m" +#define TK_BG_BLUE "\033[44m" +#define TK_BG_MAGENTA "\033[45m" +#define TK_BG_CYAN "\033[46m" +#define TK_BG_WHITE "\033[47m" + +// Bright foreground colors +#define TK_FG_BRIGHT_BLACK "\033[90m" +#define TK_FG_BRIGHT_RED "\033[91m" +#define TK_FG_BRIGHT_GREEN "\033[92m" +#define TK_FG_BRIGHT_YELLOW "\033[93m" +#define TK_FG_BRIGHT_BLUE "\033[94m" +#define TK_FG_BRIGHT_MAGENTA "\033[95m" +#define TK_FG_BRIGHT_CYAN "\033[96m" +#define TK_FG_BRIGHT_WHITE "\033[97m" + +// Bright background colors +#define TK_BG_BRIGHT_BLACK "\033[100m" +#define TK_BG_BRIGHT_RED "\033[101m" +#define TK_BG_BRIGHT_GREEN "\033[102m" +#define TK_BG_BRIGHT_YELLOW "\033[103m" +#define TK_BG_BRIGHT_BLUE "\033[104m" +#define TK_BG_BRIGHT_MAGENTA "\033[105m" +#define TK_BG_BRIGHT_CYAN "\033[106m" +#define TK_BG_BRIGHT_WHITE "\033[107m" + +// Text styles +#define TK_BOLD "\033[1m" +#define TK_DIM "\033[2m" +#define TK_ITALIC "\033[3m" +#define TK_UNDERLINE "\033[4m" +#define TK_BLINK "\033[5m" +#define TK_REVERSE "\033[7m" +#define TK_HIDDEN "\033[8m" + +// Macro to combine styles +#define TK_STYLE(...) "\033[" #__VA_ARGS__ "m" \ No newline at end of file diff --git a/extra/thunder/cuda/include/common/util.cuh b/extra/thunder/cuda/include/common/util.cuh new file mode 100644 index 0000000000..d1f06f9cbc --- /dev/null +++ b/extra/thunder/cuda/include/common/util.cuh @@ -0,0 +1,314 @@ +/** + * @file + * @brief General utilities for ThunderKittens. + */ + +#pragma once + +#include +#include +#include +#include + +// CUDA driver API +#define CUCHECK(cmd) do { \ + CUresult err = cmd; \ + if (err != CUDA_SUCCESS) { \ + const char *errStr; \ + cuGetErrorString(err, &errStr); \ + fprintf(stderr, "Failed: CUDA error %s:%d '%s'\n", \ + __FILE__, __LINE__, errStr); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +// CUDA runtime API +#define CUDACHECK(cmd) do { \ + cudaError_t err = cmd; \ + if (err != cudaSuccess) { \ + fprintf(stderr, "Failed: CUDA error %s:%d '%s'\n", \ + __FILE__, __LINE__, cudaGetErrorString(err)); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +/** + * @namespace kittens + * + * @brief The main namespace of ThunderKittens. + */ +namespace kittens { + +/* ---------- GENERAL CONSTANTS FOR KITTENS ---------- */ + +/** + * @brief Tile dimension constant. + */ +template constexpr int TILE_COL_DIM = sizeof(T) == 1 ? 32 : 16; +template constexpr int TILE_ROW_DIM = 16; +/** + * @brief Tile num elements constant calculated as TILE_DIM squared. + */ +template constexpr int TILE_ELEMENTS{TILE_COL_DIM*TILE_ROW_DIM}; +/** + * @brief Constant representing number of threads in a warp. + */ +constexpr int WARP_THREADS{32}; +/** + * @brief Constant representing number of threads in a warpgroup of four warps. + */ +constexpr int WARPGROUP_THREADS{128}; +/** + + * @brief Constant representing number of warps in a warpgroup of four warps. + */ +constexpr int WARPGROUP_WARPS{4}; +/** + + * @brief Get the warp ID of the current thread. + * @return The warp ID. + */ +__device__ static __forceinline__ int warpid() { + // uint32_t wid; + // asm volatile("mov.u32 %0, %warpid;" : "=r"(wid)); + // return wid; + return threadIdx.x >> 5; +} +/** + * @brief Get the warpgroup ID of the current thread. + * @return The warpgroup ID. + */ +__device__ static __forceinline__ int warpgroupid() { return warpid() >> 2; } +/** + * @brief Get the lane ID of the current thread within its warp. + * @return The lane ID. + */ +__device__ static __forceinline__ int laneid() { + // uint32_t lid; + // asm volatile("mov.u32 %0, %laneid;" : "=r"(lid)); + // return lid; + return threadIdx.x & 31; +} + +#if defined(KITTENS_HOPPER) +constexpr int MAX_SHARED_MEMORY = 227000; +#elif defined(KITTENS_A100) +constexpr int MAX_SHARED_MEMORY = 164000; +#elif defined(KITTENS_4090) +constexpr int MAX_SHARED_MEMORY = 100000; +#endif + +struct transpose { + static constexpr int N = 0; // not transposed + static constexpr int T = 1; // transposed +}; +struct axis { + static constexpr int ROW = 0; // row axis of a tile + static constexpr int COL = 1; // column axis of a tile +}; + +/* ---------- TYPE HELPERS ---------- */ + +/** + * @namespace ducks + * + * @brief ThunderKittens' namespace for template metaprogramming.. + * + * This includes primarily dummy types and concept wrappers, along + * with a few additional utilities. + */ +namespace ducks { + +/** + * @brief A type representing an empty default for a template. + */ +struct default_type {}; + +// This macro can't be done as a template, so it doesn't really have a location in kittens. +#define typeof(A) typename std::remove_const::type>::type + +} + +/* ---------- SHUFFLE UTILS ---------- */ + +/** + * @brief Mask constant for all active threads in a warp. + */ +static constexpr uint32_t MASK_ALL = 0xFFFFFFFF; + +/** + * @brief Perform a shuffle down operation on a packed type synchronously across a warp. + * @tparam T The type of the value to be shuffled. + * @param mask[in] The mask of active threads. + * @param f[in] The value to be shuffled. + * @param delta[in] The number of positions to shuffle down. + * @return The result of the shuffle operation. + */ +template +__device__ static inline T packed_shfl_down_sync(uint32_t mask, const T &f, int delta) { + return __shfl_down_sync(mask, f, delta); +} +template<> +__device__ inline float2 packed_shfl_down_sync(uint32_t mask, const float2 &f, int delta) { + float2 r; + r.x = __shfl_down_sync(mask, f.x, delta); + r.y = __shfl_down_sync(mask, f.y, delta); + return r; +} +/** + * @brief Perform a packed shuffle operation synchronously across a warp. + * @tparam T The type of the value to be shuffled. + * @param mask[in] The mask of active threads. + * @param f[in] The value to be shuffled. + * @param src[in] The source lane from which to shuffle. + * @return The result of the shuffle operation. + */ +template +__device__ static inline T packed_shfl_sync(uint32_t mask, const T &f, int src) { + return __shfl_sync(mask, f, src); +} +template<> +__device__ inline float2 packed_shfl_sync(uint32_t mask, const float2 &f, int src) { + float2 r; + r.x = __shfl_sync(mask, f.x, src); + r.y = __shfl_sync(mask, f.y, src); + return r; +} + +/* ---------- SHARED MEMORY UTILS ---------- */ + +// namespace ducks { +// namespace sb { +// struct identifier {}; +// } +// } + +// template +// struct sb { +// using identifier = ducks::sb::identifier; +// Args... args; +// }; + +// namespace ducks { +// namespace sb { +// template concept all = requires { +// typename T::identifier; +// } && std::is_same_v; +// } +// } + +// Joyously stolen from https://github.com/NVIDIA/cutlass/blob/5c447dd84f8ae0e1d48ff9a2eae26ce8c4958101/include/cute/container/alignment.hpp#L51 +#if defined(__CUDACC__) +#define KITTENS_ALIGN_AS(n) __align__(n) +#else +#define KITTENS_ALIGN_AS(n) alignas(n) +#endif + +#ifdef KITTENS_HOPPER +#define KITTENS_DEFAULT_ALIGN KITTENS_ALIGN_AS(128) +#else +#define KITTENS_DEFAULT_ALIGN KITTENS_ALIGN_AS(16) +#endif + +/** + * @brief Dummy structure for alignment purposes. Needed for WGMMA and TMA calls. + */ +struct KITTENS_DEFAULT_ALIGN alignment_dummy { int dummy; }; +/** + * @brief Very simple allocator for dynamic shared memory. Advances pointer and tracks alignments. + * @tparam default_alignment The default alignment this allocator will enforce. If <=0 (default -1) it will not align. + */ +#ifdef KITTENS_HOPPER +template +#else +template +#endif +struct shared_allocator { + int *ptr; + + private: + // Recursive template to generate N-dimensional array type + template + struct variadic_array; + template + struct variadic_array { + using type = typename variadic_array::type[first_dim]; + }; + template + struct variadic_array { + using type = A; + }; + template + using variadic_array_t = typename variadic_array::type; + + template + __device__ inline void align_ptr() { + if constexpr (alignment > 0) { + uint64_t p = reinterpret_cast(ptr); + if(p % alignment != 0) { + ptr = (int*)(p + (alignment-(p%alignment))); + } + } + } + + public: + /** + * @brief Construct a new shared allocator using a pointer to extern shared memory. + * @param[in] _ptr Pointer to the start of the extern shared memory. + */ + __device__ shared_allocator(int *_ptr): ptr(_ptr) {} + /** + * @brief Allocate shared memory for a single instance or N-dimensional array of type A. + * @tparam A The type of the object to allocate. + * @tparam dims... A list of dimensions for the N-dimensional array. + * @return Reference to the allocated object. + */ + template + __device__ inline variadic_array_t& allocate() { + // static_assert(sizeof(A) % default_alignment == 0, "Type is not aligned properly for array allocation"); + align_ptr(); + using at = variadic_array_t; + at*p = reinterpret_cast(ptr); + ptr += sizeof(at)/sizeof(int); + return *p; + } + /** + * @brief Allocate shared memory for a single instance or N-dimensional array of type A. + * @tparam alignment An alignment to enforce for this particular object. + * @tparam A The type of the object to allocate. + * @tparam dims... A list of dimensions for the N-dimensional array. + * @return Reference to the allocated object. + */ + template + __device__ inline variadic_array_t& allocate() { + // static_assert(sizeof(A) % alignment == 0, "Type is not aligned properly for array allocation"); + align_ptr(); + using at = variadic_array_t; + at*p = reinterpret_cast(ptr); + ptr += sizeof(at)/sizeof(int); + return *p; + } +}; +#if (defined(KITTENS_HOPPER) || defined(KITTENS_BLACKWELL)) +/** + * @brief A wrapper for an allocator that enforces sufficient alignment to be used for TMA loads and stores. + */ +using tma_allocator = shared_allocator<1024>; +using tma_swizzle_allocator = tma_allocator; // swizzled TMA modes require up to 1024 byte alignments :/ + +/* Get CTA ID within a cluster */ +__device__ static inline int3 clusterIdx() { + int3 cluster_idx; + asm volatile("mov.u32 %0, %clusterid.x;\n" : "=r"(cluster_idx.x)); + asm volatile("mov.u32 %0, %clusterid.y;\n" : "=r"(cluster_idx.y)); + asm volatile("mov.u32 %0, %clusterid.z;\n" : "=r"(cluster_idx.z)); + return cluster_idx; +} +__device__ static inline int cluster_ctarank() { + uint32_t ctarank; + asm volatile("mov.u32 %0, %cluster_ctarank;\n" : "=r"(ctarank)); + return ctarank; +} +#endif + +} // namespace kittens diff --git a/extra/thunder/cuda/include/kittens.cuh b/extra/thunder/cuda/include/kittens.cuh new file mode 100644 index 0000000000..974a896f1c --- /dev/null +++ b/extra/thunder/cuda/include/kittens.cuh @@ -0,0 +1,12 @@ +/** + * @file + * @brief The master header file of ThunderKittens. This file includes everything you need! + */ + +#pragma once + +#include "common/common.cuh" +#include "types/types.cuh" +#include "ops/ops.cuh" +#include "pyutils/util.cuh" +// #include "pyutils/pyutils.cuh" // for simple binding without including torch \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/device/device.cuh b/extra/thunder/cuda/include/ops/device/device.cuh new file mode 100644 index 0000000000..412791ea45 --- /dev/null +++ b/extra/thunder/cuda/include/ops/device/device.cuh @@ -0,0 +1,51 @@ +/** + * @file + * @brief An aggregate header of all device (multi-GPU) operations defined by ThunderKittens + */ + +#pragma once + +#include "../../types/types.cuh" + +namespace kittens { + +template +struct device { + +static_assert(_NUM_DEVICES >= 0 && _NUM_DEVICES <= 72, "Invalid number of devices"); +static constexpr int NUM_DEVICES = _NUM_DEVICES; + +#ifdef KITTENS_HOPPER + +using barrier_t = pgl, NUM_DEVICES, true>; + +/** + * @brief Multi-GPU synchronization barrier for coordinated kernel exit + * + * Performs a synchronization across all devices to ensure all GPUs complete + * their work before any kernel exits. Does not synchronize intra-node threads + * or threadblocks. + * + * @param barrier Pre-allocated barrier structure, must be initialized to 0 + * @param dev_idx Current device index (0 to NUM_DEVICES - 1) + * @param id Synchronization point identifier (default: 0). 0 is fine for most cases + * + */ +__device__ static inline void sync_on_exit(const barrier_t &barrier, const int dev_idx, const int id = 0) { + if (blockIdx.x == 0 && blockIdx.y == 0 && blockIdx.z == 0 && + threadIdx.x == 0 && threadIdx.y == 0 && threadIdx.z == 0) { + cuda::atomic_ref barrier_uc(barrier[dev_idx][{id}]); + + // Inter-note check-in + multimem::red(barrier.mc_ptr_at({id}), 1); + asm volatile ("{fence.proxy.alias;}" ::: "memory"); + while (barrier_uc.load(cuda::memory_order_acquire) < NUM_DEVICES); + barrier_uc.fetch_sub(NUM_DEVICES, cuda::memory_order_release); + } +} + +#endif + +}; + +} // namespace kittens diff --git a/extra/thunder/cuda/include/ops/group/group.cuh b/extra/thunder/cuda/include/ops/group/group.cuh new file mode 100644 index 0000000000..b9e23634c6 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/group.cuh @@ -0,0 +1,96 @@ +/** + * @file + * @brief An aggregate header of all group (multi-warp) operations defined by ThunderKittens + */ + +#pragma once + +#include + +#include "../../common/common.cuh" +#include "../../types/types.cuh" +#include "../thread/thread.cuh" // several group memory ops rely on underlying warp-scope ops + +#define KITTENS_CHECK_WARP static_assert(GROUP_WARPS==1, "Warp (GROUP_WARPS=1) function called from a non-warp group."); +// A "warpgroup" is a special group of 4 consecutive warps defined by NVIDIA for certain SM_90+ operations. +#define KITTENS_CHECK_WARPGROUP static_assert(GROUP_WARPS==4, "Warpgroup (GROUP_WARPS=4) function called from a non-warpgroup group."); + +// WGMMA relies on some template structures that cannot be specialized within the group struct, so we declare them in advance. +#ifdef KITTENS_HOPPER +#include "mma/warpgroup/base/base.cuh" +#endif + +namespace kittens { +/* +This is meant to be used with a `using group_N = kittens::group;` at the start of every kernel. +*/ +template +struct group { +static constexpr int GROUP_WARPS = _GROUP_WARPS; // This alias produces nice parallelism. +static constexpr int GROUP_THREADS = GROUP_WARPS * kittens::WARP_THREADS; // This alias produces nice parallelism. +__device__ static inline int laneid() { return threadIdx.x % GROUP_THREADS; } +__device__ static inline int warpid() { return laneid() / kittens::WARP_THREADS; } +__device__ static inline int groupid() { return threadIdx.x / GROUP_THREADS; } + +__device__ static inline void sync(int id) { + asm volatile("bar.sync %0, %1;\n" :: "r"(id), "n"(GROUP_THREADS)); +} +template __device__ static inline void sync() { + static_assert(GROUP_WARPS==1, "barrier-less sync() can only be called by a single warp!"); + asm volatile("bar.warp.sync %0;\n" :: "n"(MASK)); +} +__device__ static inline void arrive(int id) { + asm volatile("bar.arrive %0, %1;\n" :: "r"(id), "n"(GROUP_THREADS)); +} + +#include "memory/memory.cuh" +#include "shared/shared.cuh" +#include "register/register.cuh" +#include "mma/mma.cuh" + +#ifdef KITTENS_HOPPER + +template __device__ static inline void increase_registers() { + static_assert(n_reg % 8 == 0, "n_reg must be a multiple of 8"); + asm volatile("setmaxnreg.inc.sync.aligned.u32 %0;\n" :: "n"(n_reg)); +} +template __device__ static inline void decrease_registers() { + static_assert(n_reg % 8 == 0, "n_reg must be a multiple of 8"); + asm volatile("setmaxnreg.dec.sync.aligned.u32 %0;\n" :: "n"(n_reg)); +} +__device__ static inline void producer_registers() { decrease_registers<24>(); } +template __device__ static inline void consumer_registers() { increase_registers<480/NCWG - 8*(NCWG>3) - 224*(NCWG==1)>(); } + +#endif + +}; + +namespace everyone { + +// Block-level synchronization +__device__ static inline void sync(int id) { + asm volatile("bar.sync %0;\n" :: "r"(id)); +} + +// Cluster-level synchronization functions +namespace tma { +namespace cluster { +__device__ static inline void arrive_aligned() { // All threads in the cluster must call this + asm volatile ("barrier.cluster.arrive.release.aligned;\n"); +} +__device__ static inline void wait_aligned() { + asm volatile ("barrier.cluster.wait.acquire.aligned;\n"); +} +__device__ static inline void sync() { + arrive_aligned(); + wait_aligned(); +} +} +} + +}; + +using warp = group<1>; // scope used by most pre-Hopper GPUs, and also for most register operations. +using warpgroup = group<4>; // special scope commonly used by Hopper and later. + +} diff --git a/extra/thunder/cuda/include/ops/group/memory/memory.cuh b/extra/thunder/cuda/include/ops/group/memory/memory.cuh new file mode 100644 index 0000000000..2607a11327 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/memory.cuh @@ -0,0 +1,21 @@ +/** + * @file + * @brief An aggregate header of colaborative group memory movement operations + */ + +#include "util/util.cuh" +#include "tile/tile.cuh" +#include "vec/vec.cuh" + +#ifdef KITTENS_HOPPER +struct tma { +#include "util/tma.cuh" +#include "tile/tma.cuh" +#include "vec/tma.cuh" +struct cluster { +#include "util/tma_cluster.cuh" +#include "tile/tma_cluster.cuh" +#include "vec/tma_cluster.cuh" +}; +}; +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_global_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_global_to_register.cuh new file mode 100644 index 0000000000..fb35caa1b2 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_global_to_register.cuh @@ -0,0 +1,42 @@ +/** + * @file + * @brief Functions for a group to collaboratively transfer data directly between global memory and registers and back. + */ + +/** + * @brief Collaboratively loads data from a source array into register tiles. + * + * @tparam RT The register tile type. + * @tparam U The data type of the source array. + * @param dst[out] The destination tile to load data into. + * @param src[in] The source array to load data from. + * @param row_stride[in] The stride in elements between rows in the source array. + */ +template>> +__device__ inline static void load(CRT &dst, const CGL &src, const COORD &idx) { + load(dst.real, src.real, idx); + load(dst.imag, src.imag, idx); +} +template>> +__device__ inline static void load(CRT &dst, const CGL &src, const COORD &idx) { + load<2, CRT, CGL>(dst, src, idx); +} + +/** + * @brief Collaboratively stores data from register tiles to a destination array in global memory. + * + * @tparam RT The register tile type. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register tile to store data from. + * @param row_stride[in] The stride in elements between rows in the destination array. + */ +template>> +__device__ inline static void store(CGL &dst, const CRT &src, const COORD &idx) { + store(dst.real, src.real, idx); + store(dst.imag, src.imag, idx); +} +template>> +__device__ inline static void store(CGL &dst, const CRT &src, const COORD &idx) { + store<2, CRT, CGL>(dst, src, idx); +} diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_global_to_shared.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_global_to_shared.cuh new file mode 100644 index 0000000000..789bea84d2 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_global_to_shared.cuh @@ -0,0 +1,37 @@ +/** + * @file + * @brief Group (collaborative warp) ops for loading shared tiles from and storing to global memory. + */ + +template> +__device__ static inline void load(CST &dst, const CGL &src, const COORD &idx) { + load(dst.real, src.real, idx); + load(dst.imag, src.imag, idx); +} +template> +__device__ static inline void load(CST &dst, const CGL &src, const COORD &idx) { + load<2, false, typename CST::component, typename CGL::component, COORD>(dst.real, src.real, idx); + load<2, false, typename CST::component, typename CGL::component, COORD>(dst.imag, src.imag, idx); +} + +template> +__device__ static inline void store(CGL &dst, const CST &src, const COORD &idx) { + store(dst.real, src.real, idx); + store(dst.imag, src.imag, idx); +} +template> +__device__ static inline void store(CGL &dst, const CST &src, const COORD &idx) { + store<2, false, typename CST::component, typename CGL::component, COORD>(dst.real, src.real, idx); + store<2, false, typename CST::component, typename CGL::component, COORD>(dst.imag, src.imag, idx); +} + +template> +__device__ static inline void load_async(CST &dst, const CGL &src, const COORD &idx) { + load_async(dst.real, src.real, idx); + load_async(dst.imag, src.imag, idx); +} +template> +__device__ static inline void load_async(CST &dst, const CGL &src, const COORD &idx) { + load_async<2, false, typename CST::component, typename CGL::component, COORD>(dst.real, src.real, idx); + load_async<2, false, typename CST::component, typename CGL::component, COORD>(dst.imag, src.imag, idx); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_shared_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_shared_to_register.cuh new file mode 100644 index 0000000000..85b2d0437e --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/complex/complex_shared_to_register.cuh @@ -0,0 +1,34 @@ +/** + * @file + * @brief Functions for a warpgroup to collaboratively transfer data directly between shared memory and registers and back. + */ + +/** + * @brief Collaboratively load data from a shared tile into register tiles split across a warpgroup. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + */ +template +__device__ inline static void load(RT &dst, const ST &src) { + load(dst.real, src.real); + load(dst.imag, src.imag); +} + + +/** + * @brief Collaboratively store data into a shared tile from register tiles split across a warpgroup. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + */ +template +__device__ inline static void store(ST &dst, const RT &src) { + store(dst.real, src.real); + store(dst.imag, src.imag); +} + diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/global_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/global_to_register.cuh new file mode 100644 index 0000000000..e22570d116 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/global_to_register.cuh @@ -0,0 +1,207 @@ +/** + * @file + * @brief Functions for a group to collaboratively transfer data directly between global memory and registers and back. + */ + +/** + * @brief Collaboratively loads data from a source array into row-major layout tiles. + * + * @tparam RT The row-major layout tile type. + * @tparam U The data type of the source array. + * @param dst[out] The destination tile to load data into. + * @param src[in] The source array to load data from. + * @param row_stride[in] The stride in elements between rows in the source array. + */ +template>> +__device__ inline static void load(RT &dst, const GL &src, const COORD &idx) { + using T2 = RT::dtype; + using U = typename GL::dtype; + + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Unsupported type for load/store"); + #endif + + U *src_ptr = (U*)&src[(idx.template unit_coord())]; + const int row_stride = src.template stride(); + using U2 = base_types::packing::packed_type; + int warp_laneid = threadIdx.x % WARP_THREADS; + int local_warpid; + if constexpr(GROUP_WARPS % 4 == 0) local_warpid = (warpid()/4+(warpid()%4)*(GROUP_WARPS/4)); + else local_warpid = warpid(); + const int row_offset = dst.rows*local_warpid; + #pragma unroll + for(int i = 0; i < dst.height; i++) { + int row = row_offset + i*dst.tile_size_row + (warp_laneid / 4); + #pragma unroll + for(int j = 0; j < dst.width; j++) { + int col = j*dst.tile_size_col + 2*(warp_laneid % 4); + dst.tiles[i][j].data[0] = base_types::convertor::convert(*(U2*)(&src_ptr[(row+0)*row_stride + (col+0)])); + dst.tiles[i][j].data[2] = base_types::convertor::convert(*(U2*)(&src_ptr[(row+0)*row_stride + (col+8)])); + } + #pragma unroll + for(int j = 0; j < dst.width; j++) { + int col = j*dst.tile_size_col + 2*(warp_laneid % 4); + dst.tiles[i][j].data[1] = base_types::convertor::convert(*(U2*)(&src_ptr[(row+8)*row_stride + (col+0)])); + dst.tiles[i][j].data[3] = base_types::convertor::convert(*(U2*)(&src_ptr[(row+8)*row_stride + (col+8)])); + } + } +} +/** + * @brief Collaboratively loads data from a source array into column-major layout tiles. + * + * @tparam RT The column-major layout tile type. + * @tparam U The data type of the source array. + * @param dst[out] The destination tile to load data into. + * @param src[in] The source array to load data from. + * @param row_stride[in] The stride in elements between rows in the source array. + */ +template>> +__device__ inline static void load(RT &dst, const GL &src, const COORD &idx) { + using T = typename RT::T; + using U = typename GL::dtype; + + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Unsupported type for load/store"); + #endif + + U *src_ptr = (U*)&src[(idx.template unit_coord())]; + const int row_stride = src.template stride(); + int warp_laneid = threadIdx.x % WARP_THREADS; + int local_warpid; + if constexpr(GROUP_WARPS % 4 == 0) local_warpid = (warpid()/4+(warpid()%4)*(GROUP_WARPS/4)); + else local_warpid = warpid(); + const int row_offset = dst.rows*local_warpid; + #pragma unroll + for(int i = 0; i < dst.height; i++) { + int row = row_offset + i*dst.tile_size_row + 2*(warp_laneid % 4); + #pragma unroll + for(int j = 0; j < dst.width; j++) { + int col = j*dst.tile_size_col + (warp_laneid / 4); + dst.tiles[i][j].data[0].x = base_types::convertor::convert(src_ptr[(row+0)*row_stride + (col+0)]); + dst.tiles[i][j].data[1].x = base_types::convertor::convert(src_ptr[(row+0)*row_stride + (col+8)]); + } + #pragma unroll + for(int j = 0; j < dst.width; j++) { + int col = j*dst.tile_size_col + (warp_laneid / 4); + dst.tiles[i][j].data[0].y = base_types::convertor::convert(src_ptr[(row+1)*row_stride + (col+0)]); + dst.tiles[i][j].data[1].y = base_types::convertor::convert(src_ptr[(row+1)*row_stride + (col+8)]); + } + #pragma unroll + for(int j = 0; j < dst.width; j++) { + int col = j*dst.tile_size_col + (warp_laneid / 4); + dst.tiles[i][j].data[2].x = base_types::convertor::convert(src_ptr[(row+8)*row_stride + (col+0)]); + dst.tiles[i][j].data[3].x = base_types::convertor::convert(src_ptr[(row+8)*row_stride + (col+8)]); + } + #pragma unroll + for(int j = 0; j < dst.width; j++) { + int col = j*dst.tile_size_col + (warp_laneid / 4); + dst.tiles[i][j].data[2].y = base_types::convertor::convert(src_ptr[(row+9)*row_stride + (col+0)]); + dst.tiles[i][j].data[3].y = base_types::convertor::convert(src_ptr[(row+9)*row_stride + (col+8)]); + } + } +} +template>> +__device__ inline static void load(RT &dst, const GL &src, const COORD &idx) { + load<2>(dst, src, idx); +} +/** + * @brief Collaboratively stores data from register tiles to a destination array in global memory with a row-major layout. + * + * @tparam RT The register tile type with a row-major layout. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register tile to store data from. + * @param row_stride[in] The stride in elements between rows in the destination array. + */ +template>> +__device__ inline static void store(const GL &dst, const RT &src, const COORD &idx) { + using T2 = RT::dtype; + using U = typename GL::dtype; + + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Unsupported type for load/store"); + #endif + + U *dst_ptr = (U*)&dst[(idx.template unit_coord())]; + const int row_stride = dst.template stride(); + using U2 = base_types::packing::packed_type; + int warp_laneid = threadIdx.x % WARP_THREADS; + int local_warpid; + if constexpr(GROUP_WARPS % 4 == 0) local_warpid = (warpid()/4+(warpid()%4)*(GROUP_WARPS/4)); + else local_warpid = warpid(); + const int row_offset = src.rows*local_warpid; + #pragma unroll + for(int i = 0; i < src.height; i++) { + int row = row_offset + i*src.tile_size_row + (warp_laneid / 4); + #pragma unroll + for(int j = 0; j < src.width; j++) { + int col = j*src.tile_size_col + 2*(warp_laneid % 4); + *(U2*)(&dst_ptr[(row+0)*row_stride + (col+0)]) = base_types::convertor::convert(src.tiles[i][j].data[0]); + *(U2*)(&dst_ptr[(row+0)*row_stride + (col+8)]) = base_types::convertor::convert(src.tiles[i][j].data[2]); + } + #pragma unroll + for(int j = 0; j < src.width; j++) { + int col = j*src.tile_size_col + 2*(warp_laneid % 4); + *(U2*)(&dst_ptr[(row+8)*row_stride + (col+0)]) = base_types::convertor::convert(src.tiles[i][j].data[1]); + *(U2*)(&dst_ptr[(row+8)*row_stride + (col+8)]) = base_types::convertor::convert(src.tiles[i][j].data[3]); + } + } +} +/** + * @brief Collaboratively stores data from register tiles to a destination array in global memory with a column-major layout. + * + * @tparam RT The register tile type with a column-major layout. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register tile to store data from. + * @param row_stride[in] The stride in elements between rows in the destination array. + */ +template>> +__device__ inline static void store(const GL &dst, const RT &src, const COORD &idx) { + using T = base_types::packing::unpacked_type; + using U = typename GL::dtype; + + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Unsupported type for load/store"); + #endif + + U *dst_ptr = (U*)&dst[(idx.template unit_coord())]; + const int row_stride = dst.template stride(); + int warp_laneid = threadIdx.x % WARP_THREADS; + int local_warpid; + if constexpr(GROUP_WARPS % 4 == 0) local_warpid = (warpid()/4+(warpid()%4)*(GROUP_WARPS/4)); + else local_warpid = warpid(); + const int row_offset = src.rows*local_warpid; + #pragma unroll + for(int i = 0; i < src.height; i++) { + int row = row_offset + i*src.tile_size_row + 2*(warp_laneid % 4); + #pragma unroll + for(int j = 0; j < src.width; j++) { + int col = j*src.tile_size_col + (warp_laneid / 4); + dst_ptr[(row+0)*row_stride + (col+0)] = base_types::convertor::convert(src.tiles[i][j].data[0].x); + dst_ptr[(row+0)*row_stride + (col+8)] = base_types::convertor::convert(src.tiles[i][j].data[1].x); + } + #pragma unroll + for(int j = 0; j < src.width; j++) { + int col = j*src.tile_size_col + (warp_laneid / 4); + dst_ptr[(row+1)*row_stride + (col+0)] = base_types::convertor::convert(src.tiles[i][j].data[0].y); + dst_ptr[(row+1)*row_stride + (col+8)] = base_types::convertor::convert(src.tiles[i][j].data[1].y); + } + #pragma unroll + for(int j = 0; j < src.width; j++) { + int col = j*src.tile_size_col + (warp_laneid / 4); + dst_ptr[(row+8)*row_stride + (col+0)] = base_types::convertor::convert(src.tiles[i][j].data[2].x); + dst_ptr[(row+8)*row_stride + (col+8)] = base_types::convertor::convert(src.tiles[i][j].data[3].x); + } + #pragma unroll + for(int j = 0; j < src.width; j++) { + int col = j*src.tile_size_col + (warp_laneid / 4); + dst_ptr[(row+9)*row_stride + (col+0)] = base_types::convertor::convert(src.tiles[i][j].data[2].y); + dst_ptr[(row+9)*row_stride + (col+8)] = base_types::convertor::convert(src.tiles[i][j].data[3].y); + } + } +} +template>> +__device__ inline static void store(const GL &dst, const RT &src, const COORD &idx) { + store<2>(dst, src, idx); +} diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/global_to_shared.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/global_to_shared.cuh new file mode 100644 index 0000000000..831f2298bf --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/global_to_shared.cuh @@ -0,0 +1,168 @@ +/** + * @file + * @brief Group (collaborative warp) ops for loading shared tiles from and storing to global memory. + */ + + +/** + * @brief Loads data from global memory into a shared memory tile. + * + * @tparam ST The type of the shared tile. + * @param[out] dst The destination shared memory tile. + * @param[in] src The source global memory array. + * @param[in] idx The coordinate of the tile in the global memory array. + */ +template> +__device__ static inline void load(ST &dst, const GL &src, const COORD &idx) { + using T = typename ST::dtype; + const int row_stride = src.template stride(); + // we can handle this many rows each time we run a memcpy_async + constexpr int elem_per_memcpy = sizeof(float4)/sizeof(typename ST::dtype); + constexpr int memcpy_per_row = dst.cols / elem_per_memcpy; + constexpr int total_calls = (dst.height*dst.width * kittens::TILE_ROW_DIM*kittens::TILE_COL_DIM + GROUP_THREADS*elem_per_memcpy-1) / (GROUP_THREADS*elem_per_memcpy); // round up + constexpr int total_rows = dst.height*dst.width; + + coord<> unit_coord = idx.template unit_coord(); + typename GL::dtype *src_ptr = (typename GL::dtype*)&src[unit_coord]; + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + int laneid = threadIdx.x % GROUP_THREADS; + + #pragma unroll + for(int i = 0; i < total_calls; i++) { + + int load_idx = i * GROUP_THREADS + laneid; + + int row = load_idx / memcpy_per_row; + int col = (load_idx*elem_per_memcpy) % dst.cols; + + if constexpr (assume_aligned) { + float4 tmp; + move::ldg(tmp, (float4*)&src_ptr[row*row_stride + col]); + move::sts(dst.idx(dst_ptr, {row, col}), tmp); + } + else { + if (row + unit_coord.template dim() < src.template shape()) { + float4 tmp; + move::ldg(tmp, (float4*)&src_ptr[row*row_stride + col]); + move::sts(dst.idx(dst_ptr, {row, col}), tmp); + } + else { + float4 zeros = {0.f,0.f,0.f,0.f}; + move::sts(dst.idx(dst_ptr, {row, col}), zeros); // use the default value + } + } + } +} +template> +__device__ static inline void load(ST &dst, const GL &src, const COORD &idx) { + load<2, false, ST, GL, COORD>(dst, src, idx); +} + +/** + * @brief Stores data from a shared memory tile into global memory. + * + * @tparam ST The type of the shared tile. + * @param[out] dst The destination global memory array. + * @param[in] src The source shared memory tile. + * @param row_stride[in] The stride between rows in the destination array. + */ +template> +__device__ static inline void store(const GL &dst, const ST &src, const COORD &idx) { + using T = typename ST::dtype; + const int row_stride = dst.template stride(); + // we can handle this many rows each time we run a memcpy_async + constexpr int elem_per_memcpy = sizeof(float4)/sizeof(typename ST::dtype); + constexpr int memcpy_per_row = src.cols / elem_per_memcpy; + constexpr int total_calls = (src.height*src.width * kittens::TILE_ROW_DIM*kittens::TILE_COL_DIM + GROUP_THREADS*elem_per_memcpy-1) / (GROUP_THREADS*elem_per_memcpy); // round up + + coord<> unit_coord = idx.template unit_coord(); + typename GL::dtype *dst_ptr = (typename GL::dtype*)&dst[unit_coord]; + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src.data[0])); + int laneid = threadIdx.x % GROUP_THREADS; + + #pragma unroll + for(int i = 0; i < total_calls; i++) { + + int load_idx = i * GROUP_THREADS + laneid; + + int row = load_idx / memcpy_per_row; + int col = (load_idx*elem_per_memcpy) % src.cols; + + if constexpr (assume_aligned) { + float4 tmp; + move::lds(tmp, src.idx(src_ptr, {row, col})); + move::stg((float4*)&dst_ptr[row*row_stride + col], tmp); + } + else { + if (row + unit_coord.template dim() < dst.template shape()) { + float4 tmp; + move::lds(tmp, src.idx(src_ptr, {row, col})); + move::stg((float4*)&dst_ptr[row*row_stride + col], tmp); + } + } + } +} +template> +__device__ static inline void store(const GL &dst, const ST &src, const COORD &idx) { + store<2, false, ST, GL, COORD>(dst, src, idx); +} + +/** + * @brief Asynchronously loads data from global memory into a shared memory tile. + * + * @tparam ST The type of the shared tile. + * @param[out] dst The destination shared memory tile. + * @param[in] src The source global memory array. + * + * @note This function expects 16-byte alignments. Otherwise, behavior is undefined. + */ +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx) { + using T = typename ST::dtype; + const int row_stride = src.template stride(); + // we can handle this many rows each time we run a memcpy_async + constexpr int elem_per_memcpy = sizeof(float4)/sizeof(typename ST::dtype); + constexpr int memcpy_per_row = dst.cols / elem_per_memcpy; + constexpr int total_calls = (dst.height*dst.width * kittens::TILE_ROW_DIM*kittens::TILE_COL_DIM + GROUP_THREADS*elem_per_memcpy-1) / (GROUP_THREADS*elem_per_memcpy); // round up + + coord<> unit_coord = idx.template unit_coord(); + typename GL::dtype *src_ptr = (typename GL::dtype*)&src[unit_coord]; + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + int laneid = threadIdx.x % GROUP_THREADS; + + #pragma unroll + for(int i = 0; i < total_calls; i++) { + + int load_idx = i * GROUP_THREADS + laneid; + + int row = load_idx / memcpy_per_row; + int col = (load_idx*elem_per_memcpy) % dst.cols; + + if constexpr (assume_aligned) { + asm volatile( + "cp.async.cg.shared.global.L2::128B [%0], [%1], 16;\n" + :: "r"(dst.idx(dst_ptr, {row, col})), "l"(&src_ptr[row*row_stride + col]) + : "memory" + ); + } + else { + if (row + unit_coord.template dim() < src.template shape()) { + asm volatile( + "cp.async.cg.shared.global.L2::128B [%0], [%1], 16;\n" + :: "r"(dst.idx(dst_ptr, {row, col})), "l"(&src_ptr[row*row_stride + col]) + : "memory" + ); + } + else { + // printf("thread %d skipping async load on row %d, col %d\n", threadIdx.x, row + unit_coord.template dim(), col); + float4 zeros = {0.f,0.f,0.f,0.f}; + move::sts(dst.idx(dst_ptr, {row, col}), zeros); // use the default value + } + } + } + asm volatile("cp.async.commit_group;\n" ::: "memory"); +} +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx) { + load_async<2, false, ST, GL, COORD>(dst, src, idx); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/shared_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/shared_to_register.cuh new file mode 100644 index 0000000000..06f5b2e076 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/shared_to_register.cuh @@ -0,0 +1,323 @@ +/** + * @file + * @brief Functions for a warpgroup to collaboratively transfer data directly between shared memory and registers and back. + */ + +/** + * @brief Collaboratively load data from a shared tile into register tiles split across a warpgroup. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + */ +template +__device__ inline static void load(RT &dst, const ST &src) { + constexpr int height = ST::height; + constexpr int warp_height = RT::height; + static_assert(height%GROUP_WARPS == 0, "Group load / store requires tile height to be a multiple of GROUP_WARPS."); + static_assert(height%warp_height == 0, "Group load / store requires tile height to be a multiple of the RT height."); + static_assert(ST::width==RT::width, "Group load / store requires tile widths to match."); + int local_warpid; + if constexpr(GROUP_WARPS % 4 == 0) local_warpid = (warpid()/4+(warpid()%4)*(GROUP_WARPS/4)); + else local_warpid = warpid(); + using T2 = RT::dtype; + using U = ST::dtype; + using T = base_types::packing::unpacked_type; + using U2 = base_types::packing::packed_type; + int warp_laneid = ::kittens::laneid(); + + // convert to shared state space + uint32_t shared_addr = static_cast(__cvta_generic_to_shared(&src.data[0])); + + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + if constexpr (sizeof(typename ST::dtype) == 2) { + // handle the row-major layout for 16-bit types + U2 tmp[4]; + int row = (local_warpid*warp_height + i)*dst.tile_size_row + (warp_laneid % 16); + int col = j*dst.tile_size_col + (warp_laneid / 16) * 8; + if constexpr (std::is_same_v) { + move::ldsm4(tmp[0], tmp[1], tmp[2], tmp[3], src.idx(shared_addr, {row, col})); + } + else { + move::ldsm4t(tmp[0], tmp[2], tmp[1], tmp[3], src.idx(shared_addr, {row, col})); + } + dst.tiles[i][j].data[0] = base_types::convertor::convert(tmp[0]); + dst.tiles[i][j].data[1] = base_types::convertor::convert(tmp[1]); + dst.tiles[i][j].data[2] = base_types::convertor::convert(tmp[2]); + dst.tiles[i][j].data[3] = base_types::convertor::convert(tmp[3]); + } + else if constexpr (std::is_same_v && sizeof(typename ST::dtype) == 1) { + // handle the row-major layout for 8-bit types + int warp_group_16 = (warp_laneid / 16); // divide each warp into two groups of 16 threads + int lane_in_16 = warp_laneid % 16; // position in group of 16 threads + int row = (local_warpid*warp_height + i)*dst.tile_size_row + (lane_in_16 % 16); // find base row for warp in warpgroup and then distribute the 16 threads in the warp across the rows + int col = j*dst.tile_size_col + warp_group_16 * 16; // find base column and then *16 for second half of the warp + + U2 tmp[4]; + if constexpr (std::is_same_v) { + move::ldsm4(tmp[0], tmp[1], tmp[2], tmp[3], src.idx(shared_addr, {row, col})); + } + else { + move::ldsm4t(tmp[0], tmp[2], tmp[1], tmp[3], src.idx(shared_addr, {row, col})); + } + dst.tiles[i][j].data[0] = base_types::convertor::convert(tmp[0]); + dst.tiles[i][j].data[1] = base_types::convertor::convert(tmp[1]); + dst.tiles[i][j].data[2] = base_types::convertor::convert(tmp[2]); + dst.tiles[i][j].data[3] = base_types::convertor::convert(tmp[3]); + } + else if constexpr (std::is_same_v && sizeof(typename ST::dtype) == 4) { + // handle the row-major layout for 32-bit types + int row = (local_warpid*warp_height + i)*dst.tile_size_row + (warp_laneid / 4); + int col = j*dst.tile_size_col + 2*(warp_laneid % 4); + if constexpr (ST::rows != ST::underlying_rows || ST::cols != ST::underlying_cols) { // subtile case + row += src.row_offset; + col += src.col_offset; + } + int blit = sizeof(typename ST::dtype) * ((warp_laneid%4) / 2); + U2 tmp[4]; + static constexpr int swizzle_repeat = ST::swizzle_bytes * 8; + static constexpr int subtile_cols = ST::swizzle_bytes / sizeof(U); + const int outer_idx = col/subtile_cols; + const uint32_t addr_1 = shared_addr + sizeof(U)*(outer_idx*ST::underlying_rows*subtile_cols + (row+0)*subtile_cols + col%subtile_cols); + const uint32_t addr_2 = shared_addr + sizeof(U)*(outer_idx*ST::underlying_rows*subtile_cols + (row+8)*subtile_cols + col%subtile_cols); + const int swizzle_1 = blit ^ ((addr_1 % swizzle_repeat) >> 7) << 4; + const int swizzle_2 = blit ^ ((addr_2 % swizzle_repeat) >> 7) << 4; + move::lds(tmp[0].x, (addr_1+ 0)^swizzle_1); + move::lds(tmp[0].y, (addr_1+ 4)^swizzle_1); + move::lds(tmp[2].x, (addr_1+32)^swizzle_1); + move::lds(tmp[2].y, (addr_1+36)^swizzle_1); + move::lds(tmp[1].x, (addr_2+ 0)^swizzle_2); + move::lds(tmp[1].y, (addr_2+ 4)^swizzle_2); + move::lds(tmp[3].x, (addr_2+32)^swizzle_2); + move::lds(tmp[3].y, (addr_2+36)^swizzle_2); + dst.tiles[i][j].data[0] = base_types::convertor::convert(tmp[0]); + dst.tiles[i][j].data[1] = base_types::convertor::convert(tmp[1]); + dst.tiles[i][j].data[2] = base_types::convertor::convert(tmp[2]); + dst.tiles[i][j].data[3] = base_types::convertor::convert(tmp[3]); + if(blit) { + #pragma unroll + for(int k = 0; k < 4; k++) { + dst.tiles[i][j].data[k] = T2{dst.tiles[i][j].data[k].y, dst.tiles[i][j].data[k].x}; + } + } + } + else { + // handle the column-major layout + int row = (local_warpid*warp_height + i)*dst.tile_size_row + 2*(warp_laneid % 4); + int col = j*dst.tile_size_col + (warp_laneid / 4); + U2 tmp[4]; + move::lds(tmp[0].x, src.idx(shared_addr, {row+0, col+0})); + move::lds(tmp[0].y, src.idx(shared_addr, {row+1, col+0})); + move::lds(tmp[1].x, src.idx(shared_addr, {row+0, col+8})); + move::lds(tmp[1].y, src.idx(shared_addr, {row+1, col+8})); + move::lds(tmp[2].x, src.idx(shared_addr, {row+8, col+0})); + move::lds(tmp[2].y, src.idx(shared_addr, {row+9, col+0})); + move::lds(tmp[3].x, src.idx(shared_addr, {row+8, col+8})); + move::lds(tmp[3].y, src.idx(shared_addr, {row+9, col+8})); + dst.tiles[i][j].data[0] = base_types::convertor::convert(tmp[0]); + dst.tiles[i][j].data[1] = base_types::convertor::convert(tmp[1]); + dst.tiles[i][j].data[2] = base_types::convertor::convert(tmp[2]); + dst.tiles[i][j].data[3] = base_types::convertor::convert(tmp[3]); + } + } + } +} + + +/** + * @brief Collaboratively store data into a shared tile from register tiles split across a warpgroup. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + */ +template +__device__ inline static void store(ST &dst, const RT &src) { + constexpr int height = ST::height; + constexpr int warp_height = RT::height; + static_assert(height%GROUP_WARPS == 0, "Group load / store requires tile height to be a multiple of GROUP_WARPS."); + static_assert(height%warp_height == 0, "Group load / store requires tile height to be a multiple of the RT height."); + static_assert(ST::width==RT::width, "Group load / store requires tile widths to match."); + int local_warpid; + if constexpr(GROUP_WARPS % 4 == 0) local_warpid = (warpid()/4+(warpid()%4)*(GROUP_WARPS/4)); + else local_warpid = warpid(); + using T2 = RT::dtype; + using U = ST::dtype; + using T = base_types::packing::unpacked_type; + using U2 = base_types::packing::packed_type; + int warp_laneid = ::kittens::laneid(); + + // convert to shared state space + uint32_t shared_addr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + + #pragma unroll + for(int i = 0; i < warp_height; i++) { + #pragma unroll + for(int j = 0; j < src.width; j++) { + if constexpr (sizeof(typename ST::dtype) == 2) { + // handle the row-major layout + U2 tmp[4]; + tmp[0] = base_types::convertor::convert(src.tiles[i][j].data[0]); + tmp[1] = base_types::convertor::convert(src.tiles[i][j].data[1]); + tmp[2] = base_types::convertor::convert(src.tiles[i][j].data[2]); + tmp[3] = base_types::convertor::convert(src.tiles[i][j].data[3]); +#ifdef KITTENS_HOPPER + int row = (local_warpid*warp_height + i)*src.tile_size_row + (warp_laneid % 16); + int col = j*src.tile_size_col + (warp_laneid / 16) * 8; + if constexpr (std::is_same_v) { + move::stsm4(dst.idx(shared_addr, {row, col}), tmp[0], tmp[1], tmp[2], tmp[3]); + } + else { + move::stsm4t(dst.idx(shared_addr, {row, col}), tmp[0], tmp[2], tmp[1], tmp[3]); + } +#else + if constexpr (std::is_same_v) { + int row = (local_warpid*warp_height + i)*src.tile_size_row + (warp_laneid / 4); + int col = j*src.tile_size_col + 2*(warp_laneid % 4); + move::sts(dst.idx(shared_addr, {row+0, col+0}), tmp[0]); + move::sts(dst.idx(shared_addr, {row+8, col+0}), tmp[1]); + move::sts(dst.idx(shared_addr, {row+0, col+8}), tmp[2]); + move::sts(dst.idx(shared_addr, {row+8, col+8}), tmp[3]); + } + else { + int row = (local_warpid*warp_height + i)*src.tile_size_row + 2*(warp_laneid % 4); + int col = j*src.tile_size_col + (warp_laneid / 4); + move::sts(dst.idx(shared_addr, {row+0, col+0}), tmp[0].x); + move::sts(dst.idx(shared_addr, {row+1, col+0}), tmp[0].y); + move::sts(dst.idx(shared_addr, {row+0, col+8}), tmp[1].x); + move::sts(dst.idx(shared_addr, {row+1, col+8}), tmp[1].y); + move::sts(dst.idx(shared_addr, {row+8, col+0}), tmp[2].x); + move::sts(dst.idx(shared_addr, {row+9, col+0}), tmp[2].y); + move::sts(dst.idx(shared_addr, {row+8, col+8}), tmp[3].x); + move::sts(dst.idx(shared_addr, {row+9, col+8}), tmp[3].y); + } +#endif + } + else if constexpr (std::is_same_v && sizeof(typename ST::dtype) == 1) { + // handle the row-major layout for 8-bit types + + int warp_group_16 = (warp_laneid / 16); // divide each warp into two groups of 16 threads + int lane_in_16 = warp_laneid % 16; // position in group of 16 threads + int row = (local_warpid*warp_height + i)*src.tile_size_row + (lane_in_16 % 16); // find base row for warp in warpgroup and then distribute the 16 threads in the warp across the rows + int col = j*src.tile_size_col + warp_group_16 * 16; // find base column and then *16 for second half of the warp + + U2 tmp[4]; + tmp[0] = base_types::convertor::convert(src.tiles[i][j].data[0]); + tmp[1] = base_types::convertor::convert(src.tiles[i][j].data[1]); + tmp[2] = base_types::convertor::convert(src.tiles[i][j].data[2]); + tmp[3] = base_types::convertor::convert(src.tiles[i][j].data[3]); + if constexpr (std::is_same_v) { + move::stsm4(dst.idx(shared_addr, {row, col}), tmp[0], tmp[1], tmp[2], tmp[3]); + } + else { + move::stsm4t(dst.idx(shared_addr, {row, col}), tmp[0], tmp[2], tmp[1], tmp[3]); + } + } + else if constexpr (std::is_same_v && sizeof(typename ST::dtype) == 4) { + // handle the row-major layout for 32-bit types + int row = (local_warpid*warp_height + i)*src.tile_size_row + (warp_laneid / 4); + int col = j*src.tile_size_col + 2*(warp_laneid % 4); + if constexpr (ST::rows != ST::underlying_rows || ST::cols != ST::underlying_cols) { // subtile case + row += dst.row_offset; + col += dst.col_offset; + } + int blit = sizeof(typename ST::dtype) * ((warp_laneid%4) / 2); + T2 reg_tmp[4]; + if(blit) { + #pragma unroll + for(int k = 0; k < 4; k++) { + reg_tmp[k] = T2{src.tiles[i][j].data[k].y, src.tiles[i][j].data[k].x}; + } + } + else { + #pragma unroll + for(int k = 0; k < 4; k++) { + reg_tmp[k] = src.tiles[i][j].data[k]; + } + } + U2 tmp[4]; + tmp[0] = base_types::convertor::convert(reg_tmp[0]); + tmp[1] = base_types::convertor::convert(reg_tmp[1]); + tmp[2] = base_types::convertor::convert(reg_tmp[2]); + tmp[3] = base_types::convertor::convert(reg_tmp[3]); + static constexpr int swizzle_repeat = ST::swizzle_bytes * 8; + static constexpr int subtile_cols = ST::swizzle_bytes / sizeof(U); + const int outer_idx = col/subtile_cols; + const uint32_t addr_1 = shared_addr + sizeof(U)*(outer_idx*ST::underlying_rows*subtile_cols + (row+0)*subtile_cols + col%subtile_cols); + const uint32_t addr_2 = shared_addr + sizeof(U)*(outer_idx*ST::underlying_rows*subtile_cols + (row+8)*subtile_cols + col%subtile_cols); + const int swizzle_1 = blit ^ ((addr_1 % swizzle_repeat) >> 7) << 4; + const int swizzle_2 = blit ^ ((addr_2 % swizzle_repeat) >> 7) << 4; + move::sts((addr_1+ 0)^swizzle_1, tmp[0].x); + move::sts((addr_1+ 4)^swizzle_1, tmp[0].y); + move::sts((addr_1+32)^swizzle_1, tmp[2].x); + move::sts((addr_1+36)^swizzle_1, tmp[2].y); + move::sts((addr_2+ 0)^swizzle_2, tmp[1].x); + move::sts((addr_2+ 4)^swizzle_2, tmp[1].y); + move::sts((addr_2+32)^swizzle_2, tmp[3].x); + move::sts((addr_2+36)^swizzle_2, tmp[3].y); + } + else { + // handle the column-major layout + int row = (local_warpid*warp_height + i)*src.tile_size_row + 2*(warp_laneid % 4); + int col = j*src.tile_size_col + (warp_laneid / 4); + U2 tmp[4]; + tmp[0] = base_types::convertor::convert(src.tiles[i][j].data[0]); + tmp[1] = base_types::convertor::convert(src.tiles[i][j].data[1]); + tmp[2] = base_types::convertor::convert(src.tiles[i][j].data[2]); + tmp[3] = base_types::convertor::convert(src.tiles[i][j].data[3]); + move::sts(dst.idx(shared_addr, {row+0, col+0}), tmp[0].x); + move::sts(dst.idx(shared_addr, {row+1, col+0}), tmp[0].y); + move::sts(dst.idx(shared_addr, {row+0, col+8}), tmp[1].x); + move::sts(dst.idx(shared_addr, {row+1, col+8}), tmp[1].y); + move::sts(dst.idx(shared_addr, {row+8, col+0}), tmp[2].x); + move::sts(dst.idx(shared_addr, {row+9, col+0}), tmp[2].y); + move::sts(dst.idx(shared_addr, {row+8, col+8}), tmp[3].x); + move::sts(dst.idx(shared_addr, {row+9, col+8}), tmp[3].y); + } + } + } +} + +// Load and store of vectors from/to shared tiles. + +template +__device__ inline static auto load(RV &dst, const ST &src, int2 row_col) { + KITTENS_CHECK_WARP; + static_assert(ST::cols>=RV::length, "Shared tile must be at least as wide as the vector."); + using T = RV::T; + using U = ST::T; + int warp_laneid = ::kittens::laneid(); + + // convert to shared state space + uint32_t shared_addr = static_cast(__cvta_generic_to_shared(&src.data[0])); + + #pragma unroll + for(int col = warp_laneid; col < dst.length; col+=WARP_THREADS) { + U tmp; + move::lds(tmp, src.idx(shared_addr, {row_col.x, row_col.y + col})); + dst.data[col/WARP_THREADS][0] = base_types::convertor::convert(tmp); + } +} + +template +__device__ inline static auto store(ST &dst, const RV &src, int2 row_col) { + KITTENS_CHECK_WARP; + static_assert(ST::cols>=RV::length, "Shared tile must be at least as wide as the vector."); + using T = RV::T; + using U = ST::T; + int warp_laneid = ::kittens::laneid(); + + // convert to shared state space + uint32_t shared_addr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + + #pragma unroll + for(int col = warp_laneid; col < src.length; col+=WARP_THREADS) { + U tmp = base_types::convertor::convert(src.data[col/WARP_THREADS][0]); + move::sts(dst.idx(shared_addr, {row_col.x, row_col.y + col}), tmp); + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/tensor_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/tensor_to_register.cuh new file mode 100644 index 0000000000..c2ff7f30a8 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/tensor_to_register.cuh @@ -0,0 +1,325 @@ +/** + * @file + * @brief Group (collaborative warp) ops for loading tensor tiles into register tiles. + */ + +/** + * @brief Load data from a tensor tile into a register tile. + * + * @tparam RT The register tile type + * @tparam TM The tensor memory tile type + * @param dst[out] The destination register tile. + * @param src[in] The source tensor tile. + */ +template +__device__ inline static void load_async(RT &dst, const TM &src) { + if constexpr (GROUP_WARPS == 1) { + static_assert(RT::height == TM::height, "register tile and tensor tile must match height"); + static_assert(RT::width == TM::width, "register tile and tensor tile must match width"); + + using T2 = RT::dtype; + using U = typename TM::dtype; + using U2 = base_types::packing::packed_type; + + if constexpr (sizeof(typename TM::dtype) == 1) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + asm volatile( + "tcgen05.ld.sync.aligned.16x128b.x2.pack::16b.b32 {%0, %1, %2, %3}, [%4];\n" + : "=r"(*(uint32_t*) &dst.tiles[i][j].data[0]), + "=r"(*(uint32_t*) &dst.tiles[i][j].data[1]), + "=r"(*(uint32_t*) &dst.tiles[i][j].data[2]), + "=r"(*(uint32_t*) &dst.tiles[i][j].data[3]) + : "r"(src.addr + ((i * dst.tile_size_row) << 16) + (j * dst.tile_size_col)/(4/(uint32_t)sizeof(U))) + ); + } + } + } else if constexpr (sizeof(typename TM::dtype) == 2) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + asm volatile( + "tcgen05.ld.sync.aligned.16x128b.x2.pack::16b.b32 {%0, %1, %2, %3}, [%4];\n" + : "=r"(*(uint32_t*) &dst.tiles[i][j].data[0]), + "=r"(*(uint32_t*) &dst.tiles[i][j].data[1]), + "=r"(*(uint32_t*) &dst.tiles[i][j].data[2]), + "=r"(*(uint32_t*) &dst.tiles[i][j].data[3]) + : "r"(src.addr + ((i * dst.tile_size_row) << 16) + (j * dst.tile_size_col)) + ); + } + } + } + else if constexpr (sizeof(typename TM::dtype) == 4) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + if constexpr (dst.width%4 == 0) { + #pragma unroll + for(int j = 0; j < dst.width; j+=4) { + U2 data[16]; + asm volatile( + "tcgen05.ld.sync.aligned.16x256b.x8.b32 {%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, [%32];\n" + : "=f"(data[0].x), "=f"(data[0].y), + "=f"(data[1].x), "=f"(data[1].y), + "=f"(data[2].x), "=f"(data[2].y), + "=f"(data[3].x), "=f"(data[3].y), + "=f"(data[4].x), "=f"(data[4].y), + "=f"(data[5].x), "=f"(data[5].y), + "=f"(data[6].x), "=f"(data[6].y), + "=f"(data[7].x), "=f"(data[7].y), + "=f"(data[8].x), "=f"(data[8].y), + "=f"(data[9].x), "=f"(data[9].y), + "=f"(data[10].x), "=f"(data[10].y), + "=f"(data[11].x), "=f"(data[11].y), + "=f"(data[12].x), "=f"(data[12].y), + "=f"(data[13].x), "=f"(data[13].y), + "=f"(data[14].x), "=f"(data[14].y), + "=f"(data[15].x), "=f"(data[15].y) + : "r"(src.addr + ((i * dst.tile_size_row) << 16) + (j * dst.tile_size_col)/(4/(uint32_t)sizeof(U))) + ); + #pragma unroll + for(int k = 0; k < 4; k++) { + dst.tiles[i][j+0].data[k] = base_types::convertor::convert(data[k]); + dst.tiles[i][j+1].data[k] = base_types::convertor::convert(data[k+4]); + dst.tiles[i][j+2].data[k] = base_types::convertor::convert(data[k+8]); + dst.tiles[i][j+3].data[k] = base_types::convertor::convert(data[k+12]); + } + } + } + else if constexpr (dst.width%2 == 0) { + #pragma unroll + for(int j = 0; j < dst.width; j+=2) { + U2 data[8]; + asm volatile( + "tcgen05.ld.sync.aligned.16x256b.x4.b32 {%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, [%16];\n" + : "=f"(data[0].x), "=f"(data[0].y), + "=f"(data[1].x), "=f"(data[1].y), + "=f"(data[2].x), "=f"(data[2].y), + "=f"(data[3].x), "=f"(data[3].y), + "=f"(data[4].x), "=f"(data[4].y), + "=f"(data[5].x), "=f"(data[5].y), + "=f"(data[6].x), "=f"(data[6].y), + "=f"(data[7].x), "=f"(data[7].y) + : "r"(src.addr + ((i * dst.tile_size_row) << 16) + (j * dst.tile_size_col)/(4/(uint32_t)sizeof(U))) + ); + #pragma unroll + for(int k = 0; k < 4; k++) { + dst.tiles[i][j+0].data[k] = base_types::convertor::convert(data[k]); + dst.tiles[i][j+1].data[k] = base_types::convertor::convert(data[k+4]); + } + } + } + else { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + U2 data[4]; + asm volatile( + "tcgen05.ld.sync.aligned.16x256b.x2.b32 {%0, %1, %2, %3, %4, %5, %6, %7}, [%8];\n" + : "=f"(data[0].x), "=f"(data[0].y), + "=f"(data[1].x), "=f"(data[1].y), + "=f"(data[2].x), "=f"(data[2].y), + "=f"(data[3].x), "=f"(data[3].y) + : "r"(src.addr + ((i * dst.tile_size_row) << 16) + (j * dst.tile_size_col)/(4/(uint32_t)sizeof(U))) + ); + #pragma unroll + for(int k = 0; k < 4; k++) { + dst.tiles[i][j].data[k] = base_types::convertor::convert(data[k]); + } + } + } + } + } + } + else { + static_assert(GROUP_WARPS==4 || GROUP_WARPS==8); + constexpr int warp_rows = TM::rows/GROUP_WARPS; + static_assert(TM::cols==RT::cols); + static_assert(warp_rows==RT::rows); + if constexpr (GROUP_WARPS == 4) { + auto src_subtile = src.template subtile>(32*warpid(), 0); + ::kittens::group<1>::load_async(dst, src_subtile); + } + else { + auto src_subtile = src.template subtile>(32*(warpid()%4)+16*(warpid()/4), 0); + ::kittens::group<1>::load_async(dst, src_subtile); + } + } +} + + +/** + * @brief Store data into a tensor tile from a register tile. + * + * @tparam RT The register tile type + * @tparam TM The tensor memory tile type + * @param dst[out] The destination tensor tile. + * @param src[in] The source register tile. + */ +template +__device__ inline static void store_async(TM &dst, const RT &src) { + if constexpr (GROUP_WARPS == 1) { + static_assert(RT::height == TM::height, "register tile and tensor tile must match height"); + static_assert(RT::width == TM::width, "register tile and tensor tile must match width"); + + using T2 = RT::dtype; + using T = base_types::packing::unpacked_type; + using U = TM::dtype; + using U2 = base_types::packing::packed_type; + + if constexpr (sizeof(typename TM::dtype) == 2) { + #pragma unroll + for(int i = 0; i < src.height; i++) { + if constexpr (src.width%4 == 0) { + #pragma unroll + for(int j = 0; j < src.width; j+=4) { + asm volatile( + "tcgen05.st.sync.aligned.16x128b.x8.b32 [%0], {%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16};\n" + :: "r"(dst.addr + ((i * src.tile_size_row) << 16) + (j * src.tile_size_col)/(4/(uint32_t)sizeof(U))), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[3]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[3]), + "r"(*(uint32_t*)&src.tiles[i][j+2].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j+2].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j+2].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j+2].data[3]), + "r"(*(uint32_t*)&src.tiles[i][j+3].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j+3].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j+3].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j+3].data[3]) + ); + } + } + else if constexpr (src.width%2 == 0) { + #pragma unroll + for(int j = 0; j < src.width; j+=2) { + asm volatile( + "tcgen05.st.sync.aligned.16x128b.x4.b32 [%0], {%1, %2, %3, %4, %5, %6, %7, %8};\n" + :: "r"(dst.addr + ((i * src.tile_size_row) << 16) + (j * src.tile_size_col)/(4/(uint32_t)sizeof(U))), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j+0].data[3]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j+1].data[3]) + ); + } + } + else { + #pragma unroll + for(int j = 0; j < src.width; j++) { + asm volatile( + "tcgen05.st.sync.aligned.16x128b.x2.b32 [%0], {%1, %2, %3, %4};\n" + :: "r"(dst.addr + ((i * src.tile_size_row) << 16) + (j * src.tile_size_col)/(4/(uint32_t)sizeof(U))), + "r"(*(uint32_t*)&src.tiles[i][j].data[0]), + "r"(*(uint32_t*)&src.tiles[i][j].data[1]), + "r"(*(uint32_t*)&src.tiles[i][j].data[2]), + "r"(*(uint32_t*)&src.tiles[i][j].data[3]) + ); + } + } + } + } + else if constexpr (sizeof(typename TM::dtype) == 4) { + #pragma unroll + for(int i = 0; i < src.height; i++) { + if constexpr(src.width%4 == 0) { + #pragma unroll + for(int j = 0; j < src.width; j+=4) { + U2 data[16]; + #pragma unroll + for(int k = 0; k < 4; k++) { + data[k] = base_types::convertor::convert(src.tiles[i][j].data[k]); + data[k+4] = base_types::convertor::convert(src.tiles[i][j+1].data[k]); + data[k+8] = base_types::convertor::convert(src.tiles[i][j+2].data[k]); + data[k+12] = base_types::convertor::convert(src.tiles[i][j+3].data[k]); + } + asm volatile( + "tcgen05.st.sync.aligned.16x256b.x8.b32 [%0], {%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32};\n" + :: "r"(dst.addr + ((i * src.tile_size_row) << 16) + (j * src.tile_size_col)/(4/(uint32_t)sizeof(U))), + "f"(data[0].x), "f"(data[0].y), + "f"(data[1].x), "f"(data[1].y), + "f"(data[2].x), "f"(data[2].y), + "f"(data[3].x), "f"(data[3].y), + "f"(data[4].x), "f"(data[4].y), + "f"(data[5].x), "f"(data[5].y), + "f"(data[6].x), "f"(data[6].y), + "f"(data[7].x), "f"(data[7].y), + "f"(data[8].x), "f"(data[8].y), + "f"(data[9].x), "f"(data[9].y), + "f"(data[10].x), "f"(data[10].y), + "f"(data[11].x), "f"(data[11].y), + "f"(data[12].x), "f"(data[12].y), + "f"(data[13].x), "f"(data[13].y), + "f"(data[14].x), "f"(data[14].y), + "f"(data[15].x), "f"(data[15].y) + ); + } + } + else if constexpr(src.width%2 == 0) { + #pragma unroll + for(int j = 0; j < src.width; j+=2) { + U2 data[8]; + #pragma unroll + for(int k = 0; k < 4; k++) { + data[k] = base_types::convertor::convert(src.tiles[i][j].data[k]); + data[k+4] = base_types::convertor::convert(src.tiles[i][j+1].data[k]); + } + asm volatile( + "tcgen05.st.sync.aligned.16x256b.x4.b32 [%0], {%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16};\n" + :: "r"(dst.addr + ((i * src.tile_size_row) << 16) + (j * src.tile_size_col)/(4/(uint32_t)sizeof(U))), + "f"(data[0].x), "f"(data[0].y), + "f"(data[1].x), "f"(data[1].y), + "f"(data[2].x), "f"(data[2].y), + "f"(data[3].x), "f"(data[3].y), + "f"(data[4].x), "f"(data[4].y), + "f"(data[5].x), "f"(data[5].y), + "f"(data[6].x), "f"(data[6].y), + "f"(data[7].x), "f"(data[7].y) + ); + } + } + else { + #pragma unroll + for(int j = 0; j < src.width; j++) { + U2 data[4]; + #pragma unroll + for(int k = 0; k < 4; k++) { + data[k] = base_types::convertor::convert(src.tiles[i][j].data[k]); + } + asm volatile( + "tcgen05.st.sync.aligned.16x256b.x2.b32 [%0], {%1, %2, %3, %4, %5, %6, %7, %8};\n" + :: "r"(dst.addr + ((i * src.tile_size_row) << 16) + (j * src.tile_size_col)/(4/(uint32_t)sizeof(U))), + "f"(data[0].x), "f"(data[0].y), + "f"(data[1].x), "f"(data[1].y), + "f"(data[2].x), "f"(data[2].y), + "f"(data[3].x), "f"(data[3].y) + ); + } + } + } + } + } + else { + static_assert(GROUP_WARPS==4 || GROUP_WARPS==8); + constexpr int warp_rows = TM::rows/GROUP_WARPS; + static_assert(TM::cols==RT::cols); + static_assert(warp_rows==RT::rows); + if constexpr (GROUP_WARPS == 4) { + auto dst_subtile = dst.template subtile>(32*warpid(), 0); + ::kittens::group<1>::store_async(dst_subtile, src); + } + else { + auto dst_subtile = dst.template subtile>(32*(warpid()%4)+16*(warpid()/4), 0); + ::kittens::group<1>::store_async(dst_subtile, src); + } + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/tile.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/tile.cuh new file mode 100644 index 0000000000..da6125811a --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/tile.cuh @@ -0,0 +1,16 @@ +/** + * @file + * @brief An aggregate header of group memory operations on tiles. + */ + +#include "shared_to_register.cuh" +#include "global_to_register.cuh" +#include "global_to_shared.cuh" +#ifdef KITTENS_BLACKWELL +#include "tensor_to_register.cuh" +#endif + +#include "complex/complex_shared_to_register.cuh" +#include "complex/complex_global_to_register.cuh" +#include "complex/complex_global_to_shared.cuh" + diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/tma.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/tma.cuh new file mode 100644 index 0000000000..c8d14de735 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/tma.cuh @@ -0,0 +1,134 @@ +/** + * @file + * @brief Functions for a group scope to call tile TMA functions. + */ + +template> +__device__ static inline void prefetch(ST &dst, const GL &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::prefetch(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void prefetch(ST &dst, const GL &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::prefetch(dst, src, idx); // Don't do the mask + } +} + +template> +__device__ static inline void store_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_add_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_add_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_add_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_add_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_add_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_add_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_add_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_add_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_min_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_min_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_min_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_min_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_min_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_min_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_min_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_min_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_max_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_max_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_max_async(const GL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_max_async(dst, src, idx); + } +} + +template> +__device__ static inline void store_max_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_max_async(dst, src, idx); // Don't do the mask + } +} +template> +__device__ static inline void store_max_async(const PGL &dst, const ST &src, const COORD &idx) { + if(laneid() == 0) { + ::kittens::tma::store_max_async(dst, src, idx); + } +} + +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar) { + if(laneid() == 0) { + ::kittens::tma::load_async(dst, src, idx, bar); // Don't do the mask + } +} +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar) { + if(laneid() == 0) { + ::kittens::tma::load_async(dst, src, idx, bar); + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/tile/tma_cluster.cuh b/extra/thunder/cuda/include/ops/group/memory/tile/tma_cluster.cuh new file mode 100644 index 0000000000..4b2ae0ff22 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/tile/tma_cluster.cuh @@ -0,0 +1,33 @@ +/** + * @file + * @brief Functions for a group scope to call tile TMA cluster functions. + */ + + +#ifdef KITTENS_BLACKWELL +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { + if(laneid() == 0) { + ::kittens::tma::cluster::load_async(dst, src, idx, bar, cluster_mask, dst_mbar_cta); + } +} +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { + if(laneid() == 0) { + ::kittens::tma::cluster::load_async(dst, src, idx, bar, cluster_mask, dst_mbar_cta); + } +} +#else +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask) { + if(laneid() == 0) { + ::kittens::tma::cluster::load_async(dst, src, idx, bar, cluster_mask); + } +} +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask) { + if(laneid() == 0) { + ::kittens::tma::cluster::load_async(dst, src, idx, bar, cluster_mask); + } +} +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/util/tma.cuh b/extra/thunder/cuda/include/ops/group/memory/util/tma.cuh new file mode 100644 index 0000000000..f51afa5a03 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/util/tma.cuh @@ -0,0 +1,68 @@ +/** + * @file + * @brief Various utilities for group TMA memory operations. + */ + +/* ---------- Barrier functions for async load ---------- */ + +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the semaphore for the first thread in the warp. +* It converts the semaphore pointer to a generic shared memory pointer and uses an inline assembly +* instruction to set the expected number of bytes. +* +* @param semaphore Reference to the semaphore variable. +* @param bytes The number of bytes expected at the semaphore. +*/ +__device__ static inline void expect_bytes(semaphore& bar, uint32_t bytes) { + if(laneid() == 0) { + ::kittens::tma::expect_bytes(bar, bytes); + } +} +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the mbarrier before the transaction arrives. +*/ +template +__device__ static inline void expect(semaphore& bar, const T& _1, const args&... _2) { + expect_bytes(bar, size_bytes); +} + +/* ---------- Synchronization functions for async store ---------- */ + +/** + * @brief Commits previous asynchronous TMA stores to a group and performs them. +*/ +__device__ static inline void store_commit_group() { + asm volatile("cp.async.bulk.commit_group;"); +} +/** + * @brief Waits for previous committed TMA store groups to complete. + * + * @tparam N The maximum number of remaining TMA store groups. Defaults to 0. +*/ +template +__device__ static inline void store_async_wait() { + asm volatile ( + "cp.async.bulk.wait_group %0;" + : + : "n"(N) + : "memory" + ); +} +/** + * @brief Waits for previous committed TMA store groups to finish reading from shared memory. + * + * @tparam N The maximum number of remaining TMA store groups. Defaults to 0. +*/ +template +__device__ static inline void store_async_read_wait() { + asm volatile ( + "cp.async.bulk.wait_group.read %0;" + : + : "n"(N) + : "memory" + ); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/util/tma_cluster.cuh b/extra/thunder/cuda/include/ops/group/memory/util/tma_cluster.cuh new file mode 100644 index 0000000000..30db9aa6de --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/util/tma_cluster.cuh @@ -0,0 +1,90 @@ + +/** +* @brief Waits for the requested semaphore phase, at cluster scope +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void wait(semaphore& bar, int kPhaseBit) { + void const* const ptr = &bar; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.try_wait.parity.acquire.cluster.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +} + +/** +* @brief Sets the number of bytes expected at the semaphore, assuming a multicast instruction. +* +* This function sets the number of bytes expected at the semaphore for the first thread in the warp. +* It converts the semaphore pointer to a generic shared memory pointer and uses an inline assembly +* instruction to set the expected number of bytes. +* +* It's worth being aware that this function is particularly necessary for multicast loads, and +* distributed shared memory can actually be done with a normal tma::expect followed by wait. See +* the unit tests of dsmem for an example. +* +* @param semaphore Reference to the semaphore variable. +* @param bytes The number of bytes expected at the semaphore. +*/ +__device__ static inline void expect_bytes(semaphore& bar, uint32_t bytes, int dst_cta) { + if(laneid() == 0) { + ::kittens::tma::cluster::expect_bytes(bar, bytes, dst_cta); + } +} +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the semaphore for the first thread in the warp. +* It converts the semaphore pointer to a generic shared memory pointer and uses an inline assembly +* instruction to set the expected number of bytes. +* +* @tparam T The type of the data to be stored at the semaphore. +* @param semaphore Reference to the semaphore variable. +*/ +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the mbarrier before the transaction arrives. +*/ +template +__device__ static inline void expect(semaphore& bar, int dst_cta, const T& _1, const args&... _2) { + expect_bytes(bar, size_bytes, dst_cta); +} + +/** +* @brief Arrives at a semaphore in cluster scope. +* +* Marks a thread arrival at an mbarrier +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void arrive(semaphore& bar, int dst_cta, uint32_t count=1) { + if(laneid() == 0) { + ::kittens::tma::cluster::arrive(bar, dst_cta, count); + } +} + +// Generic transfer +__device__ static inline void store_async(void *dst, void *src, int dst_cta, uint32_t size_bytes, semaphore& bar) { + if(laneid() == 0) { + ::kittens::tma::cluster::store_async(dst, src, dst_cta, size_bytes, bar); + } +} + +// Templated transfer for convenience +template +__device__ static inline void store_async(T &dst_, T &src_, int dst_cta, semaphore& bar) { + store_async((void*)&dst_, (void*)&src_, dst_cta, size_bytes, bar); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/util/util.cuh b/extra/thunder/cuda/include/ops/group/memory/util/util.cuh new file mode 100644 index 0000000000..cf5d4b4a8d --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/util/util.cuh @@ -0,0 +1,168 @@ +/** + * @file + * @brief Various utilities for group memory operations. + */ + + +template __device__ static inline void load_async_wait(int bar_id) { // for completing (non-TMA) async loads + asm volatile("cp.async.wait_group %0;\n" : : "n"(N) : "memory"); + sync(bar_id); +} +template __device__ static inline void load_async_wait() { // for completing (non-TMA) async loads + KITTENS_CHECK_WARP + asm volatile("cp.async.wait_group %0;\n" : : "n"(N) : "memory"); + __syncwarp(); +} + +__device__ static inline void arrive(barrier bar) { + asm volatile("bar.arrive %0, %1;\n" :: "r"(bar.barrier_id), "n"(GROUP_WARPS*WARP_THREADS) : "memory"); +} +__device__ static inline void arrive_and_wait(barrier bar) { + asm volatile("bar.sync %0, %1;\n" :: "r"(bar.barrier_id), "n"(GROUP_WARPS*WARP_THREADS) : "memory"); +} + +/** + * @brief Initializes a synchronization semaphore with a transaction count and sets the expected number of bytes. + * + * This function sets up a semaphore that is used to synchronize threads within a block during asynchronous operations. + * It initializes the semaphore with a thread count semaphore. + * + * Additionally, if it is given a shared tile type, it will also call `set_bytes` to prepare for the memory transaction. + * + * @param[out] semaphore The semaphore variable to initialize. + * @param[in] tc The thread counter for the semaphore. + */ +__device__ static inline void init_semaphore(semaphore& bar, int thread_count, int transaction_count=0) { + if (laneid() == 0) { + void const* const ptr = &bar; + uint32_t bar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + asm volatile ( + "mbarrier.init.shared::cta.b64 [%0], %1;\n" + :: "r"(bar_ptr), "r"(thread_count+transaction_count) + ); + } +} +/** + * @brief Invalidate an mbarrier + * + * @param[out] semaphore The semaphore variable to initialize. + * @param[in] tc The thread counter for the semaphore. + */ +__device__ static inline void invalidate_semaphore(semaphore& bar) { + if (laneid() == 0) { + void const* const ptr = &bar; + uint32_t bar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + asm volatile ( + "mbarrier.inval.shared::cta.b64 [%0];\n" + :: "r"(bar_ptr) + ); + } +} + +/** +* @brief Arrives at a semaphore. +* +* Marks a warp arrival at an mbarrier +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void arrive(semaphore& sem) { + if(laneid() == 0) { + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&sem)); + asm volatile ( + "mbarrier.arrive.release.cta.shared::cta.b64 _, [%0];\n" + : + : "r"(mbar_ptr) + : "memory" + ); + } +} +template __device__ static inline void arrive(barrier bar) { + asm volatile("bar.arrive %0, %1;\n" :: "r"(bar.barrier_id), "n"(num_warps*WARP_THREADS) : "memory"); +} + +#ifdef KITTENS_HOPPER +/** +* @brief Arrives at a semaphore. +* +* Marks a warp arrival at an mbarrier +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void arrive(semaphore& sem, uint32_t count) { + if(laneid() == 0) { + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&sem)); + asm volatile ( + "mbarrier.arrive.release.cta.shared::cta.b64 _, [%0], %1;\n" + : + : "r"(mbar_ptr), "r"(count) + : "memory" + ); + } +} +#endif + +/** +* @brief Waits for the requested semaphore phase. +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void wait(semaphore& sem, int kPhaseBit) { + void const* const ptr = &sem; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + +#ifdef KITTENS_HOPPER + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.try_wait.parity.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +#else + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.test_wait.parity.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "nanosleep.u32 5;\n" // wait a few nanoseconds on pre-Hopper architectures to save instruction issue slots + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +#endif +} + +/** +* @brief Checks if the requested semaphore phase is ready. +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline int test_wait(semaphore& sem, int kPhaseBit) { + void const* const ptr = &sem; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + int result; + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "mbarrier.test_wait.parity.shared::cta.b64 P1, [%1], %2;\n" + "selp.u32 %0,1,0,P1;" + "}\n" + : "=r"(result) + : "r"(mbar_ptr), "r"(kPhaseBit) + ); + return result; +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/vec/global_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/vec/global_to_register.cuh new file mode 100644 index 0000000000..2567150ce1 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/vec/global_to_register.cuh @@ -0,0 +1,138 @@ +/** + * @file + * @brief Functions for a warpgroup to collaboratively transfer data directly between global memory and registers and back. + */ + +/** + * @brief Collaboratively loads data into register vectors from a source array in global memory. + * + * @tparam RV The register vector type. + * @tparam U The data type of the source array. + * @param[out] dst The destination register vector to load data into. + * @param[in] src The source array in global memory to load data from. + */ +template +__device__ inline static void load(RV &dst, const GL &src, const coord> &idx) { + if constexpr (GROUP_WARPS == 1) { + using T2 = RV::dtype; + using U = typename GL::dtype; + using U2 = base_types::packing::packed_type; + using T = base_types::packing::unpacked_type; + + U *src_ptr = (U*)&src[(idx.template unit_coord<-1, 3>())]; + int laneid = ::kittens::laneid(); + + if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < (dst.outer_dim+3)/4; w++) { + int idx = w*64 + (laneid/4)*8 + 2*(laneid%4); + int o_dim = w*4 + (laneid/4) / 2; + int i_dim = (laneid/4) % 2; + // this should be a maximally coalesced load. + if(idx < dst.outer_dim*16) + dst[o_dim][i_dim] = base_types::convertor::convert(*(U2*)&src_ptr[idx]); + } + // now we need to do a bunch of shuffle_sync's to make sure everyone has everything they need. + #pragma unroll + for(auto w = 0; w < dst.outer_dim; w++) { + int leader = 8*(w%4) + (laneid%4); // repeats every 64 columns + dst[w][0] = packed_shfl_sync(MASK_ALL, dst[w][0], leader); + dst[w][1] = packed_shfl_sync(MASK_ALL, dst[w][1], leader+4); + } + } + else if constexpr (std::is_same_v) { + // really hoping https://stackoverflow.com/questions/15029765/is-coalescing-triggered-for-accessing-memory-in-reverse-order is still true + // otherwise there will be some pain :/ + #pragma unroll + for(auto w = 0; w < (dst.outer_dim+1)/2; w++) { + int idx = w*32 + (laneid%4)*8 + (laneid/4); + int o_dim = w*2 + (laneid%4) / 2; + // this should be a maximally coalesced load. + if(idx < dst.outer_dim*16) { + T tmp = base_types::convertor::convert(src_ptr[idx]); + if(laneid%2==0) dst[o_dim][0].x = tmp; + else dst[o_dim][0].y = tmp; + } + } + // now we need to do a bunch of shuffle_sync's to make sure everyone has everything they need. + #pragma unroll + for(auto w = 0; w < dst.outer_dim; w++) { + int leader = (laneid/4)*4 + 2*(w%2); // repeats every 64 columns + dst[w][0].x = __shfl_sync(MASK_ALL, dst[w][0].x, leader); + dst[w][0].y = __shfl_sync(MASK_ALL, dst[w][0].y, leader+1); + } + } + else if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < dst.outer_dim; w++) { + if(w < dst.outer_dim-1 || dst.length%32 == 0 || laneid<16) { + dst[w][0] = base_types::convertor::convert(src_ptr[w*32 + laneid]); + } + } + } + } + else { + // Call warp level load + ::kittens::group<1>::load(dst, src, coord(idx.b, idx.d, idx.r, idx.c*GROUP_WARPS+warpid())); + } +} +/** + * @brief Collaboratively stores data from register vectors to a destination array in global memory. + * + * @tparam RV The register vector type. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register vector to store data from. + */ +template +__device__ inline static void store(GL &dst, const RV &src, const coord> &idx) { + if constexpr (GROUP_WARPS == 1) { + using T2 = RV::dtype; + using U = typename GL::dtype; + using U2 = base_types::packing::packed_type; + using T = base_types::packing::unpacked_type; + + U *dst_ptr = (U*)&dst[(idx.template unit_coord<-1, 3>())]; + int laneid = ::kittens::laneid(); + + if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < (src.outer_dim+3)/4; w++) { + int idx = w*64 + (laneid/4)*8 + 2*(laneid%4); + int o_dim = w*4 + (laneid/4) / 2; + int i_dim = (laneid/4) % 2; + // this should be a maximally coalesced store. I hope! + if(idx < src.outer_dim*16) + *(U2*)&dst_ptr[idx] = base_types::convertor::convert(src[o_dim][i_dim]); + } + } + else if constexpr (std::is_same_v) { + // really hoping https://stackoverflow.com/questions/15029765/is-coalescing-triggered-for-accessing-memory-in-reverse-order is still true + // otherwise there will be some pain :/ + #pragma unroll + for(auto w = 0; w < (src.outer_dim+1)/2; w++) { + int idx = w*32 + (laneid%4)*8 + (laneid/4); + int o_dim = w*2 + (laneid%4) / 2; + // this should be a maximally coalesced load. + if(idx < src.outer_dim*16) { + U tmp; + if(laneid%2==0) tmp = base_types::convertor::convert(src[o_dim][0].x); + else tmp = base_types::convertor::convert(src[o_dim][0].y); + dst_ptr[idx] = tmp; + } + } + } + else if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < src.outer_dim; w++) { + if(w < src.outer_dim-1 || src.length%32 == 0 || laneid<16) { + dst_ptr[w*32 + laneid] = base_types::convertor::convert(src[w][0]); + } + } + } + } + else { + // Call warp level store + ::kittens::group<1>::store(dst, src, coord(idx.b, idx.d, idx.r, idx.c*GROUP_WARPS+warpid())); + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/vec/global_to_shared.cuh b/extra/thunder/cuda/include/ops/group/memory/vec/global_to_shared.cuh new file mode 100644 index 0000000000..73f0826cd3 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/vec/global_to_shared.cuh @@ -0,0 +1,77 @@ +/** + * @file + * @brief Group (collaborative warp) ops for loading shared vectors from and storing to global memory. + */ + +/** + * @brief Loads data from global memory into shared memory vector. + * + * This function loads data from a global memory location pointed to by `src` into a shared memory vector `dst`. + * It calculates the number of elements that can be transferred in one operation based on the size ratio of `float4` to the data type of `SV`. + * The function ensures coalesced memory access and efficient use of bandwidth by dividing the work among threads in a warp. + * + * @tparam SV Shared vector type, must satisfy ducks::sv::all concept. + * @param dst Reference to the shared vector where the data will be loaded. + * @param src Pointer to the global memory location from where the data will be loaded. + */ +template> +__device__ static inline void load(SV &dst, const GL &src, const COORD &idx) { + constexpr uint32_t elem_per_transfer = sizeof(float4) / sizeof(typename SV::dtype); + constexpr uint32_t total_calls = SV::length / elem_per_transfer; // guaranteed to divide + typename GL::dtype *src_ptr = (typename GL::dtype*)&src[(idx.template unit_coord<-1, 3>())]; + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + #pragma unroll + for(uint32_t i = threadIdx.x%GROUP_THREADS; i < total_calls; i+=GROUP_THREADS) { + if(i * elem_per_transfer < dst.length) { + float4 tmp; + move::ldg(tmp, (float4*)&src_ptr[i*elem_per_transfer]); + move::sts(dst_ptr + sizeof(typename SV::dtype)*i*elem_per_transfer, tmp); + } + } +} + +/** + * @brief Stores data from a shared memory vector to global memory. + * + * This function stores data from a shared memory vector `src` to a global memory location pointed to by `dst`. + * Similar to the load function, it calculates the number of elements that can be transferred in one operation based on the size ratio of `float4` to the data type of `SV`. + * The function ensures coalesced memory access and efficient use of bandwidth by dividing the work among threads in a warp. + * + * @tparam SV Shared vector type, must satisfy ducks::sv::all concept. + * @param dst Pointer to the global memory location where the data will be stored. + * @param src Reference to the shared vector from where the data will be stored. + */ +template> +__device__ static inline void store(GL &dst, const SV &src, const COORD &idx) { + constexpr uint32_t elem_per_transfer = sizeof(float4) / sizeof(typename SV::dtype); + constexpr uint32_t total_calls = SV::length / elem_per_transfer; // guaranteed to divide + typename GL::dtype *dst_ptr = (typename GL::dtype*)&dst[(idx.template unit_coord<-1, 3>())]; + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src.data[0])); + #pragma unroll + for(uint32_t i = threadIdx.x%GROUP_THREADS; i < total_calls; i+=GROUP_THREADS) { + if(i * elem_per_transfer < src.length) { + float4 tmp; + move::lds(tmp, src_ptr + sizeof(typename SV::dtype)*i*elem_per_transfer); + move::stg((float4*)&dst_ptr[i*elem_per_transfer], tmp); + } + } +} + +template> +__device__ static inline void load_async(SV &dst, const GL &src, const COORD &idx) { + constexpr uint32_t elem_per_transfer = sizeof(float4) / sizeof(typename SV::dtype); + constexpr uint32_t total_calls = SV::length / elem_per_transfer; // guaranteed to divide + typename GL::dtype *src_ptr = (typename GL::dtype*)&src[(idx.template unit_coord<-1, 3>())]; + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + #pragma unroll + for(uint32_t i = threadIdx.x%GROUP_THREADS; i < total_calls; i+=GROUP_THREADS) { + if(i * elem_per_transfer < dst.length) { + asm volatile( + "cp.async.cg.shared.global.L2::128B [%0], [%1], 16;\n" + :: "r"(dst_ptr + (uint32_t)sizeof(typename SV::dtype)*i*elem_per_transfer), "l"((uint64_t)&src_ptr[i*elem_per_transfer]) + : "memory" + ); + } + } + asm volatile("cp.async.commit_group;\n" ::: "memory"); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/vec/shared_to_register.cuh b/extra/thunder/cuda/include/ops/group/memory/vec/shared_to_register.cuh new file mode 100644 index 0000000000..12152597dd --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/vec/shared_to_register.cuh @@ -0,0 +1,159 @@ +/** + * @file + * @brief Functions for a group to collaboratively transfer data directly between shared memory and registers and back. + */ + +/** + * @brief Collaboratively load data from a shared vector into register vectors split across a warpgroup. + * + * @tparam RV The register vector type + * @tparam SV The shared vector type + * @param dst[out] The destination register vector. + * @param src[in] The source shared vector. + */ +template +__device__ inline static void load(RV &dst, const SV &src) { + using T2 = RV::dtype; + using U = SV::dtype; + using U2 = base_types::packing::packed_type; + using T = base_types::packing::unpacked_type; + if constexpr (GROUP_WARPS == 1) { + static_assert(SV::length == RV::length); + + int laneid = ::kittens::laneid(); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src.data[0])); + + __syncwarp(); + if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < (dst.outer_dim+3)/4; w++) { + int idx = w*64 + (laneid/4)*8 + 2*(laneid%4); + int o_dim = w*4 + (laneid/4) / 2; + int i_dim = (laneid/4) % 2; + // this should be a maximally coalesced load. + if(idx < dst.outer_dim*16) { + U2 tmp; + move::lds(tmp, src_ptr + sizeof(typename SV::dtype)*idx); + dst[o_dim][i_dim] = base_types::convertor::convert(tmp); + } + } + __syncwarp(); + // now we need to do a bunch of shuffle_sync's to make sure everyone has everything they need. + #pragma unroll + for(auto w = 0; w < dst.outer_dim; w++) { + int leader = 8*(w%4) + (laneid%4); // repeats every 64 columns + dst[w][0] = packed_shfl_sync(MASK_ALL, dst[w][0], leader); + dst[w][1] = packed_shfl_sync(MASK_ALL, dst[w][1], leader+4); + } + } + else if constexpr (std::is_same_v) { + // really hoping https://stackoverflow.com/questions/15029765/is-coalescing-triggered-for-accessing-memory-in-reverse-order is still true + // otherwise there will be some pain :/ + #pragma unroll + for(auto w = 0; w < (dst.outer_dim+1)/2; w++) { + int idx = w*32 + (laneid%4)*8 + (laneid/4); + int o_dim = w*2 + (laneid%4) / 2; + // this should be a maximally coalesced load. + if(idx < dst.outer_dim*16) { + U tmp; + move::lds(tmp, src_ptr + sizeof(typename SV::dtype)*idx); + if(laneid%2==0) dst[o_dim][0].x = base_types::convertor::convert(tmp); + else dst[o_dim][0].y = base_types::convertor::convert(tmp); + } + } + __syncwarp(); + // now we need to do a bunch of shuffle_sync's to make sure everyone has everything they need. + #pragma unroll + for(auto w = 0; w < dst.outer_dim; w++) { + int leader = (laneid/4)*4 + 2*(w%2); // repeats every 64 columns + dst[w][0].x = __shfl_sync(MASK_ALL, dst[w][0].x, leader); + dst[w][0].y = __shfl_sync(MASK_ALL, dst[w][0].y, leader+1); + } + } + else if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < dst.outer_dim; w++) { + if(w < dst.outer_dim-1 || RV::length%32 == 0 || laneid<16) { + U tmp; + move::lds(tmp, src_ptr + sizeof(typename SV::dtype)*(w*32 + laneid)); + dst[w][0] = base_types::convertor::convert(tmp); + } + } + } + } + else { + static_assert(SV::length == RV::length*GROUP_WARPS);// confirm size correct + auto &_src = src.template subvec(warpid()); // pretend it's smaller and do warp-level load + + ::kittens::group<1>::load(dst, _src); // warp-level + } +} + +/** + * @brief Collaboratively store data into a shared vector from register vectors split across a warpgroup. + * + * @tparam RV The register vector type + * @tparam SV The shared vector type + * @param dst[out] The destination shared vector. + * @param src[in] The source register vector. + */ +template +__device__ inline static void store(SV &dst, const RV &src) { + using T2 = RV::dtype; + using U = SV::dtype; + using U2 = base_types::packing::packed_type; + using T = base_types::packing::unpacked_type; + + if constexpr (GROUP_WARPS == 1) { + static_assert(SV::length == RV::length); + + int laneid = ::kittens::laneid(); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst.data[0])); + + __syncwarp(); + if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < (src.outer_dim+3)/4; w++) { + int idx = w*64 + (laneid/4)*8 + 2*(laneid%4); + int o_dim = w*4 + (laneid/4) / 2; + int i_dim = (laneid/4) % 2; + // this should be a maximally coalesced store. I hope! + if(idx < src.outer_dim*16) { + U2 tmp = base_types::convertor::convert(src[o_dim][i_dim]); + move::sts(dst_ptr + sizeof(typename SV::dtype)*idx, tmp); + } + } + } + else if constexpr (std::is_same_v) { + // really hoping https://stackoverflow.com/questions/15029765/is-coalescing-triggered-for-accessing-memory-in-reverse-order is still true + // otherwise there will be some pain :/ + #pragma unroll + for(auto w = 0; w < (src.outer_dim+1)/2; w++) { + int idx = w*32 + (laneid%4)*8 + (laneid/4); + int o_dim = w*2 + (laneid%4) / 2; + // this should be a maximally coalesced load. + if(idx < src.outer_dim*16) { + U tmp; + if(laneid%2==0) tmp = base_types::convertor::convert(src[o_dim][0].x); + else tmp = base_types::convertor::convert(src[o_dim][0].y); + move::sts(dst_ptr + sizeof(typename SV::dtype)*idx, tmp); + } + } + } + else if constexpr (std::is_same_v) { + #pragma unroll + for(auto w = 0; w < src.outer_dim; w++) { + if(w < src.outer_dim-1 || RV::length%32 == 0 || laneid<16) { + U tmp = base_types::convertor::convert(src[w][0]); + move::sts(dst_ptr + sizeof(typename SV::dtype)*(w*32 + laneid), tmp); + } + } + } + } + else { + static_assert(SV::length == RV::length*GROUP_WARPS);// confirm size correct + auto &_dst = dst.template subvec(warpid()); // pretend it's smaller and do warp-level load + + ::kittens::group<1>::store(_dst, src); // warp-level + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/memory/vec/tma.cuh b/extra/thunder/cuda/include/ops/group/memory/vec/tma.cuh new file mode 100644 index 0000000000..8f88ccf4ae --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/vec/tma.cuh @@ -0,0 +1,221 @@ +/** + * @file + * @brief Functions for a group scope to call vec TMA functions. + */ + +/* ---------- Prefetch Tensor Map ---------- */ + +/** + * @brief Prefetches data from global memory into a shared memory vector, along with the tensormap. + * + * @tparam SV A shared vector type with a TMA-compatible layout + * @param[out] dst The destination shared memory vector. + * @param[in] src_tma_map The source tensormap address in global memory + * @param[in] vec_idx The coord of the requested vector. + */ +template> +__device__ static inline void prefetch(SV &dst, const GL &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + ::kittens::detail::tma::vec_prefetch_tma_internal(tma_ptr, tma_coord); + } +} +__KITTENS_TMA_DEFINE_DEFAULT_LOAD_CACHE_VEC__(prefetch) + + +/* ---------- Async load and store data from gmem/smem ---------- */ + +/** + * @brief Asynchronously stores data into global memory from a shared memory vector. + * + * This function performs an asynchronous copy operation using CUDA's cp.async.bulk.tensor instruction. + * + * @tparam SV A shared vector type with a TMA-compatible layout + * @param[out] dst_tma_map The destination tensormap address in global memory + * @param[in] src The source shared memory vector. + * @param[in] vec_idx The coord of the vector destination. + */ +template> +__device__ static inline void store_async(const GL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_async) + +template> +__device__ static inline void store_async(const PGL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_async) + + +/** +* @brief Asynchronously performs an add reduction and stores the result into global memory. +* +* This function performs an asynchronous add reduction operation using CUDA's cp.reduce.async.bulk.tensor instruction. +* +* @tparam SV A shared vector type with a TMA-compatible layout +* @param[out] dst_tma_map The destination tensormap address in global memory +* @param[in] src The source shared memory vector. +* @param[in] vec_idx The coord of the vector destination. +*/ +template> +__device__ static inline void store_add_async(const GL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_add_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_add_async) + +template> +__device__ static inline void store_add_async(const PGL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_add_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_add_async) + + +/** +* @brief Asynchronously performs an min reduction and stores the result into global memory. +* +* This function performs an asynchronous min reduction operation using CUDA's cp.reduce.async.bulk.tensor instruction. +* +* @tparam SV A shared vector type with a TMA-compatible layout +* @param[out] dst_tma_map The destination tensormap address in global memory +* @param[in] src The source shared memory vector. +* @param[in] vec_idx The coord of the vector destination. +*/ +template> +__device__ static inline void store_min_async(const GL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_min_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_min_async) + +template> +__device__ static inline void store_min_async(const PGL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_min_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_min_async) + +/** +* @brief Asynchronously performs an max reduction and stores the result into global memory. +* +* This function performs an asynchronous max reduction operation using CUDA's cp.reduce.async.bulk.tensor instruction. +* +* @tparam SV A shared vector type with a TMA-compatible layout +* @param[out] dst_tma_map The destination tensormap address in global memory +* @param[in] src The source shared memory vector. +* @param[in] vec_idx The coord of the vector destination. +*/ +template> +__device__ static inline void store_max_async(const GL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_max_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_max_async) + +template> +__device__ static inline void store_max_async(const PGL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_max_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_max_async) + +/** + * @brief Asynchronously loads data from global memory into a shared memory vector. + * + * This function performs an asynchronous copy operation using CUDA's cp.async.bulk.tensor instruction. + * + * @tparam SV A shared vector type with a TMA-compatible layout + * @param[out] dst The destination shared memory vector. + * @param[in] src_tma_map The source tensormap address in global memory + * @param[in] vec_idx The coord of the requested vector. + * @param[in,out] bar The semaphore used for synchronization of the asynchronous copy. + */ +template> +__device__ static inline void load_async(SV &dst, const GL &src, const COORD &idx, semaphore& bar) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t dst_i_ptr = dst_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_load_async_tma_internal(tma_ptr, dst_i_ptr, mbar_ptr, tma_coord); + } +} +__KITTENS_TMA_DEFINE_SEMAPHORE_CACHE_VEC__(load_async) diff --git a/extra/thunder/cuda/include/ops/group/memory/vec/tma_cluster.cuh b/extra/thunder/cuda/include/ops/group/memory/vec/tma_cluster.cuh new file mode 100644 index 0000000000..3ae848c404 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/vec/tma_cluster.cuh @@ -0,0 +1,31 @@ +/** + * @file + * @brief Functions for a group scope to call vec TMA cluster functions. + */ + +/** + * @brief Asynchronously loads data from global memory into a shared memory vector, broadcast across a cluster + * + * This function performs an asynchronous copy operation using CUDA's cp.async.bulk.tensor instruction. + * + * @tparam SV A shared vector type with a TMA-compatible layout + * @param[out] dst The destination shared memory vector. + * @param[in] src_tma_map The source tensormap address in global memory + * @param[in,out] bar The semaphore used for synchronization of the asynchronous copy. + * @param[in] vec_idx The coord of the requested vector. + * @param[in] cluster_mask The mask of the clusters to broadcast to. + */ +template> +__device__ static inline void load_async(SV &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst)); + for(int i = ::kittens::laneid(); i < ::kittens::detail::tma::sv_tma_dim2; i += WARP_THREADS) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t dst_i_ptr = dst_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::cluster::vec_load_async_tma_internal(tma_ptr, dst_i_ptr, mbar_ptr, tma_coord, cluster_mask, dst_mbar_cta); + } +} +__KITTENS_TMA_DEFINE_CLUSTER_SEMAPHORE_CACHE_VEC__(load_async) diff --git a/extra/thunder/cuda/include/ops/group/memory/vec/vec.cuh b/extra/thunder/cuda/include/ops/group/memory/vec/vec.cuh new file mode 100644 index 0000000000..ac4229e27b --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/memory/vec/vec.cuh @@ -0,0 +1,8 @@ +/** + * @file + * @brief An aggregate header of group memory operations on vectors. + */ + +#include "shared_to_register.cuh" +#include "global_to_register.cuh" +#include "global_to_shared.cuh" diff --git a/extra/thunder/cuda/include/ops/group/mma/mma.cuh b/extra/thunder/cuda/include/ops/group/mma/mma.cuh new file mode 100644 index 0000000000..cc4fc63dfd --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/mma.cuh @@ -0,0 +1,17 @@ +/** + * @file + * @brief An aggregate header for all group-scope MMA operations. + */ + +// All compilation targets can use the warp-scope MMA operations. +#include "warp/warp.cuh" + +// Hopper has its own warpgroup-scope MMA operations. +#ifdef KITTENS_HOPPER +#include "warpgroup/warpgroup.cuh" +#endif + +// Blackwell has its own tensor-scope MMA operations. +#ifdef KITTENS_BLACKWELL +#include "tensor/tensor.cuh" +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/tensor/tensor.cuh b/extra/thunder/cuda/include/ops/group/mma/tensor/tensor.cuh new file mode 100644 index 0000000000..bad42c9a2e --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/tensor/tensor.cuh @@ -0,0 +1,172 @@ +/** + * @file Group-level tcgen05 MMA operations. +*/ + +template +__device__ static inline void mma(D &d, const A &a, const B &b, semaphore &sem) { + if(laneid() == 0) ::kittens::mma(d, a, b, sem); +} +template +__device__ static inline void mma2(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm2(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} + +template +__device__ static inline void mma_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma2_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma2_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma2_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma2_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} + +template +__device__ static inline void mm_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm2_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm2_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm2_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm2_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} + +// no sem versions + + +template +__device__ static inline void mma(D &d, const A &a, const B &b) { + if(laneid() == 0) ::kittens::mma(d, a, b); +} +template +__device__ static inline void mma2(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2(D &d, const A &a, const B &b) { + mma2(d, a, b); +} + +template +__device__ static inline void mma_AB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_AB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mma_ABt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_ABt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mma_AtB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_AtB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mma_AtBt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_AtBt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} + +template +__device__ static inline void mm_AB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_AB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mm_ABt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_ABt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mm_AtB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_AtB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mm_AtBt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_AtBt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warp/warp.cuh b/extra/thunder/cuda/include/ops/group/mma/warp/warp.cuh new file mode 100644 index 0000000000..90692c35d9 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warp/warp.cuh @@ -0,0 +1,947 @@ +/** + * @file + * @brief Matrix multiply-accumulate operations for tiles stored in registers. + */ + +/** + * @brief Perform the HMMA.16816 operation. + * + * This function performs the half-precision matrix multiply-accumulate operation + * using the `mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32` instruction. + * + * @param[out] d0 The first half of the output float2 accumulator. + * @param[out] d1 The second half of the output float2 accumulator. + * @param[in] a0 The first half of the first input bf16_2 matrix. + * @param[in] a1 The second half of the first input bf16_2 matrix. + * @param[in] a2 The first half of the second input bf16_2 matrix. + * @param[in] a3 The second half of the second input bf16_2 matrix. + * @param[in] b0 The first half of the bf16_2 matrix B. + * @param[in] b1 The second half of the bf16_2 matrix B. + * @param[in] c0 The first half of the float2 accumulator matrix C. + * @param[in] c1 The second half of the float2 accumulator matrix C. + */ +__device__ static inline void hmma16816( float2 &d0, float2 &d1, + const bf16_2 &a0, const bf16_2 &a1, const bf16_2 &a2, const bf16_2 &a3, + const bf16_2 &b0, const bf16_2 &b1, + const float2 &c0, const float2 &c1 ) { + asm volatile( + // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#multiply-and-accumulate-instruction-mma + "mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 " \ + "{%0, %1, %2, %3}, " \ + "{%4, %5, %6, %7}, " \ + "{%8, %9}, " \ + "{%10, %11, %12, %13};" + + // D matrix + : "+f"(d0.x), "+f"(d0.y), + "+f"(d1.x), "+f"(d1.y) + + // A matrix + : "r"(*(uint32_t*)(&a0)), "r"(*(uint32_t*)(&a1)), + "r"(*(uint32_t*)(&a2)), "r"(*(uint32_t*)(&a3)), + + // B matrix + "r"(*(uint32_t*)(&b0)), "r"(*(uint32_t*)(&b1)), + + // C matrix + "f"(c0.x), "f"(c0.y), + "f"(c1.x), "f"(c1.y) + ); +} +/** + * @brief Perform the HMMA.16816 operation with inputs as fp16 and fp32 accumulators + * + * This function performs the half-precision matrix multiply-accumulate operation + * using the `mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32` instruction. + * + * @param[out] d0 The first half of the output float2 accumulator. + * @param[out] d1 The second half of the output float2 accumulator. + * @param[in] a0 The first half of the first input half_2 matrix. + * @param[in] a1 The second half of the first input half_2 matrix. + * @param[in] a2 The first half of the second input half_2 matrix. + * @param[in] a3 The second half of the second input half_2 matrix. + * @param[in] b0 The first half of the half_2 matrix B. + * @param[in] b1 The second half of the half_2 matrix B. + * @param[in] c0 The first half of the float2 accumulator matrix C. + * @param[in] c1 The second half of the float2 accumulator matrix C. + */ +__device__ static inline void hmma16816( float2 &d0, float2 &d1, + const half_2 &a0, const half_2 &a1, const half_2 &a2, const half_2 &a3, + const half_2 &b0, const half_2 &b1, + const float2 &c0, const float2 &c1 ) { + asm volatile( + // https://docs.nvidia.com/cuda/parallel-thread-execution/#multiply-and-accumulate-instruction-mma + "mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 " \ + "{%0, %1, %2, %3}, " \ + "{%4, %5, %6, %7}, " \ + "{%8, %9}, " \ + "{%10, %11, %12, %13};" + + // D matrix + : "+f"(d0.x), "+f"(d0.y), + "+f"(d1.x), "+f"(d1.y) + + // A matrix + : "r"(*(uint32_t*)(&a0)), "r"(*(uint32_t*)(&a1)), + "r"(*(uint32_t*)(&a2)), "r"(*(uint32_t*)(&a3)), + + // B matrix + "r"(*(uint32_t*)(&b0)), "r"(*(uint32_t*)(&b1)), + + // C matrix + "f"(c0.x), "f"(c0.y), + "f"(c1.x), "f"(c1.y) + ); +} +/** + * @brief Perform the HMMA.16816 operation. + * + * This function performs the half-precision matrix multiply-accumulate operation + * using the `mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16` instruction. + * + * @param[out] d0 The first half of the output half_2 accumulator. + * @param[out] d1 The second half of the output half_2 accumulator. + * @param[in] a0 The first half of the first input half_2 matrix. + * @param[in] a1 The second half of the first input half_2 matrix. + * @param[in] a2 The first half of the second input half_2 matrix. + * @param[in] a3 The second half of the second input half_2 matrix. + * @param[in] b0 The first half of the half_2 matrix B. + * @param[in] b1 The second half of the half_2 matrix B. + * @param[in] c0 The first half of the half_2 accumulator matrix C. + * @param[in] c1 The second half of the half_2 accumulator matrix C. + */ +__device__ static inline void hmma16816( half_2 &d0, half_2 &d1, + const half_2 &a0, const half_2 &a1, const half_2 &a2, const half_2 &a3, + const half_2 &b0, const half_2 &b1, + const half_2 &c0, const half_2 &c1 ) { + asm volatile( + // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#multiply-and-accumulate-instruction-mma + "mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16 " \ + "{%0, %1}, " \ + "{%2, %3, %4, %5}, " \ + "{%6, %7}, " \ + "{%8, %9};" + + // D matrix + : "=r"(*(uint32_t*)(&d0)), "=r"(*(uint32_t*)(&d1)) + + // A matrix + : "r"(*(uint32_t*)(&a0)), "r"(*(uint32_t*)(&a1)), + "r"(*(uint32_t*)(&a2)), "r"(*(uint32_t*)(&a3)), + + // B matrix + "r"(*(uint32_t*)(&b0)), "r"(*(uint32_t*)(&b1)), + + // C matrix + "r"(*(uint32_t*)(&c0)), "r"(*(uint32_t*)(&c1)) + ); +} + +#ifdef KITTENS_HOPPER +/** +* @brief Perform the HMMA.16816 operation for FP8 using fp8e4m3_2. +* +* Using mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32 instruction +* but with fp8e4m3_2 (2 FP8 values) instead of fp8e4m3_4 +*/ +/** + * @brief Perform the HMMA.16816 operation for FP8. + * + * This function performs the fp8-precision matrix multiply-accumulate operation + * using the `mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32` instruction. + * + * @param[out] d0 The first half of the output float2 accumulator. + * @param[out] d1 The second half of the output float2 accumulator. + * @param[in] a0,a1,a2,a3 Input FP8 matrix A values + * @param[in] b0,b1 Input FP8 matrix B values + * @param[in] c0,c1 Input float2 accumulator matrix C values + */ +__device__ static inline void hmma16816( float2 &d0, float2 &d1, + const fp8e4m3_4 &a0, const fp8e4m3_4 &a1, + const fp8e4m3_4 &a2, const fp8e4m3_4 &a3, + const fp8e4m3_4 &b0, const fp8e4m3_4 &b1, + const float2 &c0, const float2 &c1) { + asm volatile( + "mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32 " + "{%0, %1, %2, %3}, " + "{%4, %5, %6, %7}, " + "{%8, %9}, " + "{%10, %11, %12, %13};" + + // D matrix (output) + : "+f"(d0.x), "+f"(d0.y), + "+f"(d1.x), "+f"(d1.y) + + // A matrix + : "r"(*(uint32_t*)(&a0)), "r"(*(uint32_t*)(&a1)), + "r"(*(uint32_t*)(&a2)), "r"(*(uint32_t*)(&a3)), + + // B matrix + "r"(*(uint32_t*)(&b0)), "r"(*(uint32_t*)(&b1)), + + // C matrix + "f"(c0.x), "f"(c0.y), + "f"(c1.x), "f"(c1.y) + ); +} +#endif + +/** + * @brief Base matrix multiply-accumulate operation for row layout. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +/** + * @brief Base matrix multiply-accumulate operation for row layout + * with fp16 inputs and fp32 accumulators. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +#ifdef KITTENS_HOPPER +/** + * @brief Base matrix multiply-accumulate operation for row layout. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +#endif +/** + * @brief Base matrix multiply-accumulate operation for row layout. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +/** + * @brief Base dot product operation for row layout. + * + * This function performs the base dot product operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in row-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_ABt_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in row-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], // for some reason this one seems to need to be backwards + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], // for some reason this one seems to need to be backwards + c.data[2], c.data[3] + ); +} +/** + * @brief Base dot product operation for row layout + * with fp16 inputs and fp32 accumulators. + * + * This function performs the base dot product operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in row-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_ABt_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in row-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], // for some reason this one seems to need to be backwards + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], // for some reason this one seems to need to be backwards + c.data[2], c.data[3] + ); +} +#ifdef KITTENS_HOPPER +/** + * @brief Base dot product operation for row layout. + * + * This function performs the base dot product operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in row-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_ABt_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in row-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], // for some reason this one seems to need to be backwards + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], // for some reason this one seems to need to be backwards + c.data[2], c.data[3] + ); +} +#endif + + +/** + * @brief Base matrix multiply-accumulate operation for row layout with transposed A. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AtB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +/** + * @brief Base matrix multiply-accumulate operation for row layout with transposed A + * with fp16 inputs and fp32 accumulators. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AtB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +#ifdef KITTENS_HOPPER +/** + * @brief Base matrix multiply-accumulate operation for row layout with transposed A. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AtB_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +#endif + +/** + * @brief Base matrix multiply-accumulate operation for row layout with transposed A and B. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AtBt_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +/** + * @brief Base matrix multiply-accumulate operation for row layout with transposed A and B + * with fp16 inputs and fp32 accumulators. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in row-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AtBt_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in row-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +#ifdef KITTENS_HOPPER +/** + * @brief Base matrix multiply-accumulate operation for row layout with transposed A and B. + * + * This function performs the base matrix multiply-accumulate operation + * using the `hmma16816` function for matrices in row layout. + * + * @param[out] d The output rt_base accumulator. + * @param[in] a The first input rt_base matrix. + * @param[in] b The second input rt_base matrix in column-major mode. + * @param[in] c The input rt_base accumulator matrix. + */ +__device__ static inline void mma_AtBt_base(rt_base &d, + const rt_base &a, + const rt_base &b, // in col-major mode + const rt_base &c) { + hmma16816( + d.data[0], d.data[1], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[0], b.data[2], + c.data[0], c.data[1] + ); + hmma16816( + d.data[2], d.data[3], + a.data[0], a.data[1], a.data[2], a.data[3], + b.data[1], b.data[3], + c.data[2], c.data[3] + ); +} +#endif + +/** + * @brief Matrix multiply-accumulate operation. + * + * This function performs the matrix multiply-accumulate operation + * using the `hmma16816` function. + * + * @tparam N The number of row tiles. + * @tparam K The number of column tiles for the A matrix and row tiles for the B matrix. + * @tparam M The number of column tiles for the B matrix. + * @param[out] d The output rt_hf accumulator. + * @param[in] a The first input rt_hf matrix. + * @param[in] b The second input rt_hf matrix in column-major mode. + * @param[in] c The input rt_hf accumulator matrix. + */ +template +__device__ static inline void mma_AB(D &d, + const A &a, + const B &b, + const C &c) { + KITTENS_CHECK_WARP + static_assert(D::rows == A::rows && D::cols == B::cols); // Check D matches A, B + static_assert(A::cols == B::rows); // Check reduction dim is same + static_assert(D::rows == C::rows && D::cols == C::cols); // Check D matches C + #ifdef KITTENS_HOPPER + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #else + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #endif + #pragma unroll + for(int n = 0; n < D::height; n++) { + #pragma unroll + for(int m = 0; m < D::width; m++) { + mma_AB_base( + d.tiles[n][m], + a.tiles[n][0], + b.tiles[0][m], + c.tiles[n][m] + ); + #pragma unroll + for(int k = 1; k < A::width; k++) { + mma_AB_base( + d.tiles[n][m], + a.tiles[n][k], + b.tiles[k][m], + d.tiles[n][m] + ); + } + } + } +} +/** + * @brief Dot product operation for row layout. + * + * This function performs the dot product operation + * using the `hmma16816` function. + * + * @tparam N The number of row tiles. + * @tparam K The number of column tiles for the A matrix and row tiles for the B matrix. + * @tparam M The number of column tiles for the B matrix. + * @param[out] d The output rt_fl accumulator. + * @param[in] a The first input rt_bf matrix. + * @param[in] b The second input rt_bf matrix in row-major mode. + * @param[in] c The input rt_fl accumulator matrix. + */ +template +__device__ static inline void mma_ABt(D &d, + const A &a, + const B &b, // notice row and (M, K) instead of col and (K, M) + const C &c) { + KITTENS_CHECK_WARP + static_assert(D::rows == A::rows && D::cols == B::rows); // Check D matches A, B + static_assert(A::cols == B::cols); // Check reduction dim is same + static_assert(D::rows == C::rows && D::cols == C::cols); // Check D matches C + #ifdef KITTENS_HOPPER + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #else + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #endif + #pragma unroll + for(int n = 0; n < D::height; n++) { + #pragma unroll + for(int m = 0; m < D::width; m++) { + mma_ABt_base( + d.tiles[n][m], + a.tiles[n][0], + b.tiles[m][0], + c.tiles[n][m] + ); + #pragma unroll + for(int k = 1; k < A::width; k++) { + mma_ABt_base( + d.tiles[n][m], + a.tiles[n][k], + b.tiles[m][k], + d.tiles[n][m] + ); + } + } + } +} +/** + * @brief Matrix multiply-accumulate operation with transposed A. + * + * This function performs the matrix multiply-accumulate operation + * using the `hmma16816` instruction. + * + * @tparam N The number of row tiles. + * @tparam K The number of column tiles for the A matrix and row tiles for the B matrix. + * @tparam M The number of column tiles for the B matrix. + * @param[out] d The output rt_fl accumulator. + * @param[in] a The first input rt_bf matrix. + * @param[in] b The second input rt_bf matrix in column-major mode. + * @param[in] c The input rt_fl accumulator matrix. + */ +template +__device__ static inline void mma_AtB(D &d, + const A &a, + const B &b, + const C &c) { + KITTENS_CHECK_WARP + static_assert(D::rows == A::cols && D::cols == B::cols); // Check D matches A, B + static_assert(A::rows == B::rows); // Check reduction dim is same + static_assert(D::rows == C::rows && D::cols == C::cols); // Check D matches C + #ifdef KITTENS_HOPPER + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #else + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #endif + #pragma unroll + for(int n = 0; n < D::height; n++) { + #pragma unroll + for(int m = 0; m < D::width; m++) { + mma_AtB_base( + d.tiles[n][m], + a.tiles[0][n], + b.tiles[0][m], + c.tiles[n][m] + ); + #pragma unroll + for(int k = 1; k < A::height; k++) { + mma_AtB_base( + d.tiles[n][m], + a.tiles[k][n], + b.tiles[k][m], + d.tiles[n][m] + ); + } + } + } +} +/** + * @brief Matrix multiply-accumulate operation with transposed A and B. + * + * This function performs the matrix multiply-accumulate operation + * using the `hmma16816` instruction. + * + * @tparam N The number of row tiles. + * @tparam K The number of column tiles for the A matrix and row tiles for the B matrix. + * @tparam M The number of column tiles for the B matrix. + * @param[out] d The output rt_fl accumulator. + * @param[in] a The first input rt_bf matrix. + * @param[in] b The second input rt_bf matrix in column-major mode. + * @param[in] c The input rt_fl accumulator matrix. + */ +template +__device__ static inline void mma_AtBt(D &d, + const A &a, + const B &b, + const C &c) { + KITTENS_CHECK_WARP + static_assert(D::rows == A::cols && D::cols == B::rows); // Check D matches A, B + static_assert(A::rows == B::cols); // Check reduction dim is same + static_assert(D::rows == C::rows && D::cols == C::cols); // Check D matches C + #ifdef KITTENS_HOPPER + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #else + static_assert( + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v && + std::is_same_v && std::is_same_v) + ); + #endif + #pragma unroll + for(int n = 0; n < D::height; n++) { + #pragma unroll + for(int m = 0; m < D::width; m++) { + mma_AtBt_base( + d.tiles[n][m], + a.tiles[0][n], + b.tiles[m][0], + c.tiles[n][m] + ); + #pragma unroll + for(int k = 1; k < A::height; k++) { + mma_AtBt_base( + d.tiles[n][m], + a.tiles[k][n], + b.tiles[m][k], + d.tiles[n][m] + ); + } + } + } +} + +template +__device__ static inline void mma(D &d, + const A &a, + const B &b, + const C &c) { + KITTENS_CHECK_WARP + if constexpr(trans_A == transpose::T) { + if constexpr(trans_B == transpose::T) { + mma_AtBt(d, a, b, c); + } else { + mma_AtB(d, a, b, c); + } + } else { + if constexpr(trans_B == transpose::T) { + mma_ABt(d, a, b, c); + } else { + mma_AB(d, a, b, c); + } + } +} +template +__device__ static inline C mma(const A &a, + const B &b, + const C &c) { + KITTENS_CHECK_WARP + C d; + if constexpr(trans_A == transpose::T) { + if constexpr(trans_B == transpose::T) { + mma_AtBt(d, a, b, c); + } else { + mma_AtB(d, a, b, c); + } + } else { + if constexpr(trans_B == transpose::T) { + mma_ABt(d, a, b, c); + } else { + mma_AB(d, a, b, c); + } + } + return d; +} + + +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------- COMPLEX INPUTS -------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- + + + +/** + * @brief Matrix multiply-accumulate operation for complex tiles + * + * This function calls mma_AB with hf arguments + * + * @tparam N The number of row tiles. + * @tparam K The number of column tiles for the A matrix and row tiles for the B matrix. + * @tparam M The number of column tiles for the B matrix. + * @param[out] d The output rt_cmplx_hf accumulator. + * @param[in] a The first input rt_cmplx_hf matrix. + * @param[in] b The second input rt_cmplx_hf matrix in column-major mode. + * @param[in] c The input rt_cmplx_hf accumulator matrix. + */ +template +__device__ static inline void mma_AB(crt_hf &d, + const crt_hf &a, + const crt_hf &b, + const crt_hf &c) { + KITTENS_CHECK_WARP + + // Copy data from input accumulate register into output + ::kittens::group<1>::copy(d.real, c.real); + ::kittens::group<1>::copy(d.imag, c.imag); + + // Negative on B matrix so we can use single accum register + rt_hf tmp; + // Hex value for -1 in float16 + constexpr half factor = std::bit_cast<__half>(uint16_t(0xFB80)); + ::kittens::group<1>::mul(tmp, a.imag, factor); + mma_AB(d.real, a.real, b.real, d.real); + mma_AB(d.real, tmp, b.imag, d.real); + + mma_AB(d.imag, a.real, b.imag, d.imag); + mma_AB(d.imag, a.imag, b.real, d.imag); +} +/** + * @brief Matrix multiply-accumulate operation for complex tiles + * + * This function calls mma_AB with bf16 arguments + * + * @tparam N The number of row tiles. + * @tparam K The number of column tiles for the A matrix and row tiles for the B matrix. + * @tparam M The number of column tiles for the B matrix. + * @param[out] d The output rt_cmplx_fl accumulator. + * @param[in] a The first input rt_cmplx_bf matrix. + * @param[in] b The second input rt_cmplx_bf matrix in column-major mode. + * @param[in] c The input rt_cmplx_fl accumulator matrix. + */ + +template +__device__ static inline void mma_AB(crt_fl &d, + const crt_bf &a, + const crt_bf &b, + const crt_fl &c) { + KITTENS_CHECK_WARP + + // Copy data from input accumulate register into output + ::kittens::group<1>::copy(d.real, c.real); + ::kittens::group<1>::copy(d.imag, c.imag); + + // Negative on B matrix so we can use single accum register + kittens::rt_bf tmp; + // Hex value for -1 in bf16 + constexpr bf16 factor = std::bit_cast<__nv_bfloat16>(uint16_t(0xBF80)); + ::kittens::group<1>::mul(tmp, a.imag, factor); + mma_AB(d.real, a.real, b.real, d.real); + mma_AB(d.real, tmp, b.imag, d.real); + + mma_AB(d.imag, a.real, b.imag, d.imag); + mma_AB(d.imag, a.imag, b.real, d.imag); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x112.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x112.impl new file mode 100644 index 0000000000..3cba73022c --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x112.impl @@ -0,0 +1,334 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %61, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n112k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55}, " \ + "{%56, %57, %58, %59}, " \ + "%60, " \ + "p, 1, %63, %62;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %61, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n112k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55}, " \ + "{%56, %57, %58, %59}, " \ + "%60, " \ + "p, 1, %63, %62;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %33, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n112k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27}, " \ + "{%28, %29, %30, %31}, " \ + "%32, " \ + "p, 1, %35, %34;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %58, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n112k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55}, " \ + "%56, " \ + "%57, " \ + "p, 1, %61, %59, %60;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %58, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n112k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55}, " \ + "%56, " \ + "%57, " \ + "p, 1, %61, %59, %60;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %30, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n112k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27}, " \ + "%28, " \ + "%29, " \ + "p, 1, %33, %31, %32;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x128.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x128.impl new file mode 100644 index 0000000000..8e1cf35a9a --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x128.impl @@ -0,0 +1,813 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %71, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %71, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %39, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %69, %67, %68;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %69, %67, %68;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %37, %35, %36;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %67;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %67;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y), + "+f"(dst.tiles[0][6].data[0].x), "+f"(dst.tiles[0][6].data[0].y), + "+f"(dst.tiles[0][6].data[1].x), "+f"(dst.tiles[0][6].data[1].y), + "+f"(dst.tiles[0][6].data[2].x), "+f"(dst.tiles[0][6].data[2].y), + "+f"(dst.tiles[0][6].data[3].x), "+f"(dst.tiles[0][6].data[3].y), + "+f"(dst.tiles[0][7].data[0].x), "+f"(dst.tiles[0][7].data[0].y), + "+f"(dst.tiles[0][7].data[1].x), "+f"(dst.tiles[0][7].data[1].y), + "+f"(dst.tiles[0][7].data[2].x), "+f"(dst.tiles[0][7].data[2].y), + "+f"(dst.tiles[0][7].data[3].x), "+f"(dst.tiles[0][7].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %35;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n128k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %35;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][7].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x144.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x144.impl new file mode 100644 index 0000000000..0616a66a99 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x144.impl @@ -0,0 +1,382 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %77, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n144k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71}, " \ + "{%72, %73, %74, %75}, " \ + "%76, " \ + "p, 1, %79, %78;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %77, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n144k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71}, " \ + "{%72, %73, %74, %75}, " \ + "%76, " \ + "p, 1, %79, %78;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %41, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n144k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35}, " \ + "{%36, %37, %38, %39}, " \ + "%40, " \ + "p, 1, %43, %42;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %74, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n144k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71}, " \ + "%72, " \ + "%73, " \ + "p, 1, %77, %75, %76;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %74, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n144k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71}, " \ + "%72, " \ + "%73, " \ + "p, 1, %77, %75, %76;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %38, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n144k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35}, " \ + "%36, " \ + "%37, " \ + "p, 1, %41, %39, %40;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x16.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x16.impl new file mode 100644 index 0000000000..578991c127 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x16.impl @@ -0,0 +1,190 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %13, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n16k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "{%8, %9, %10, %11}, " \ + "%12, " \ + "p, 1, %15, %14;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %13, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n16k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "{%8, %9, %10, %11}, " \ + "%12, " \ + "p, 1, %15, %14;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %9, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n16k16.f16.f16.f16 " \ + "{%0, %1, %2, %3}, " \ + "{%4, %5, %6, %7}, " \ + "%8, " \ + "p, 1, %11, %10;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %10, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n16k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "%8, " \ + "%9, " \ + "p, 1, %13, %11, %12;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %10, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n16k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "%8, " \ + "%9, " \ + "p, 1, %13, %11, %12;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %6, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n16k16.f16.f16.f16 " \ + "{%0, %1, %2, %3}, " \ + "%4, " \ + "%5, " \ + "p, 1, %9, %7, %8;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x160.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x160.impl new file mode 100644 index 0000000000..533dd02157 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x160.impl @@ -0,0 +1,666 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %85, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "{%80, %81, %82, %83}, " \ + "%84, " \ + "p, 1, %87, %86;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %85, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "{%80, %81, %82, %83}, " \ + "%84, " \ + "p, 1, %87, %86;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %45, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39}, " \ + "{%40, %41, %42, %43}, " \ + "%44, " \ + "p, 1, %47, %46;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %85, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "{%80, %81, %82, %83}, " \ + "%84, " \ + "p, 1, %86;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %85, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "{%80, %81, %82, %83}, " \ + "%84, " \ + "p, 1, %86;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %82, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "%80, " \ + "%81, " \ + "p, 1, %85, %83, %84;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %82, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "%80, " \ + "%81, " \ + "p, 1, %85, %83, %84;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %42, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39}, " \ + "%40, " \ + "%41, " \ + "p, 1, %45, %43, %44;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %82, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "%80, " \ + "%81, " \ + "p, 1, %83;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %82, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n160k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79}, " \ + "%80, " \ + "%81, " \ + "p, 1, %83;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x176.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x176.impl new file mode 100644 index 0000000000..4a8f355cdb --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x176.impl @@ -0,0 +1,430 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %93, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n176k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87}, " \ + "{%88, %89, %90, %91}, " \ + "%92, " \ + "p, 1, %95, %94;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %93, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n176k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87}, " \ + "{%88, %89, %90, %91}, " \ + "%92, " \ + "p, 1, %95, %94;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %49, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n176k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43}, " \ + "{%44, %45, %46, %47}, " \ + "%48, " \ + "p, 1, %51, %50;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %90, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n176k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87}, " \ + "%88, " \ + "%89, " \ + "p, 1, %93, %91, %92;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %90, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n176k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87}, " \ + "%88, " \ + "%89, " \ + "p, 1, %93, %91, %92;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %46, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n176k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43}, " \ + "%44, " \ + "%45, " \ + "p, 1, %49, %47, %48;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x192.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x192.impl new file mode 100644 index 0000000000..e5e73f3459 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x192.impl @@ -0,0 +1,674 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %101, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "{%96, %97, %98, %99}, " \ + "%100, " \ + "p, 1, %103, %102;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %101, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "{%96, %97, %98, %99}, " \ + "%100, " \ + "p, 1, %103, %102;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %53, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "{%48, %49, %50, %51}, " \ + "%52, " \ + "p, 1, %55, %54;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %101, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "{%96, %97, %98, %99}, " \ + "%100, " \ + "p, 1, %102;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %101, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "{%96, %97, %98, %99}, " \ + "%100, " \ + "p, 1, %102;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %98, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "%96, " \ + "%97, " \ + "p, 1, %101, %99, %100;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %98, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "%96, " \ + "%97, " \ + "p, 1, %101, %99, %100;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %50, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "%48, " \ + "%49, " \ + "p, 1, %53, %51, %52;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %98, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n192k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95}, " \ + "%96, " \ + "%97, " \ + "p, 1, %99;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x208.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x208.impl new file mode 100644 index 0000000000..92325639ac --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x208.impl @@ -0,0 +1,478 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %109, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n208k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103}, " \ + "{%104, %105, %106, %107}, " \ + "%108, " \ + "p, 1, %111, %110;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %109, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n208k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103}, " \ + "{%104, %105, %106, %107}, " \ + "%108, " \ + "p, 1, %111, %110;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %57, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n208k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51}, " \ + "{%52, %53, %54, %55}, " \ + "%56, " \ + "p, 1, %59, %58;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %106, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n208k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103}, " \ + "%104, " \ + "%105, " \ + "p, 1, %109, %107, %108;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %106, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n208k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103}, " \ + "%104, " \ + "%105, " \ + "p, 1, %109, %107, %108;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %54, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n208k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51}, " \ + "%52, " \ + "%53, " \ + "p, 1, %57, %55, %56;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x224.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x224.impl new file mode 100644 index 0000000000..6405bf7cad --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x224.impl @@ -0,0 +1,826 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %117, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "{%112, %113, %114, %115}, " \ + "%116, " \ + "p, 1, %119, %118;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %117, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "{%112, %113, %114, %115}, " \ + "%116, " \ + "p, 1, %119, %118;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %61, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55}, " \ + "{%56, %57, %58, %59}, " \ + "%60, " \ + "p, 1, %63, %62;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %117, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "{%112, %113, %114, %115}, " \ + "%116, " \ + "p, 1, %118;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %117, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "{%112, %113, %114, %115}, " \ + "%116, " \ + "p, 1, %118;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %114, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "%112, " \ + "%113, " \ + "p, 1, %117, %115, %116;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %114, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "%112, " \ + "%113, " \ + "p, 1, %117, %115, %116;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %58, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55}, " \ + "%56, " \ + "%57, " \ + "p, 1, %61, %59, %60;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %114, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "%112, " \ + "%113, " \ + "p, 1, %117, %115, %116;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %114, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n224k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111}, " \ + "%112, " \ + "%113, " \ + "p, 1, %117, %115, %116;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x240.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x240.impl new file mode 100644 index 0000000000..7a3246d2e6 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x240.impl @@ -0,0 +1,526 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %125, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n240k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119}, " \ + "{%120, %121, %122, %123}, " \ + "%124, " \ + "p, 1, %127, %126;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %125, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n240k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119}, " \ + "{%120, %121, %122, %123}, " \ + "%124, " \ + "p, 1, %127, %126;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %65, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n240k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59}, " \ + "{%60, %61, %62, %63}, " \ + "%64, " \ + "p, 1, %67, %66;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %122, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n240k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119}, " \ + "%120, " \ + "%121, " \ + "p, 1, %125, %123, %124;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %122, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n240k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119}, " \ + "%120, " \ + "%121, " \ + "p, 1, %125, %123, %124;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %62, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n240k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59}, " \ + "%60, " \ + "%61, " \ + "p, 1, %65, %63, %64;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x256.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x256.impl new file mode 100644 index 0000000000..cc46f822fb --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x256.impl @@ -0,0 +1,1260 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %133, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "{%128, %129, %130, %131}, " \ + "%132, " \ + "p, 1, %135, %134;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %133, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "{%128, %129, %130, %131}, " \ + "%132, " \ + "p, 1, %135, %134;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %71, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %133, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "{%128, %129, %130, %131}, " \ + "%132, " \ + "p, 1, %134;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %133, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "{%128, %129, %130, %131}, " \ + "%132, " \ + "p, 1, %134;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %69, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "{%64, %65, %66, %67}, " \ + "%68, " \ + "p, 1, %70;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %130, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "%128, " \ + "%129, " \ + "p, 1, %133, %131, %132;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %130, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "%128, " \ + "%129, " \ + "p, 1, %133, %131, %132;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %69, %67, %68;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %130, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "%128, " \ + "%129, " \ + "p, 1, %131;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %130, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f32.e5m.e5m " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63, %64, %65, %66, %67, %68, %69, %70, %71, %72, %73, %74, %75, %76, %77, %78, %79, %80, %81, %82, %83, %84, %85, %86, %87, %88, %89, %90, %91, %92, %93, %94, %95, %96, %97, %98, %99, %100, %101, %102, %103, %104, %105, %106, %107, %108, %109, %110, %111, %112, %113, %114, %115, %116, %117, %118, %119, %120, %121, %122, %123, %124, %125, %126, %127}, " \ + "%128, " \ + "%129, " \ + "p, 1, %131;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][ 0].data[0].x), "+f"(dst.tiles[0][ 0].data[0].y), + "+f"(dst.tiles[0][ 0].data[1].x), "+f"(dst.tiles[0][ 0].data[1].y), + "+f"(dst.tiles[0][ 0].data[2].x), "+f"(dst.tiles[0][ 0].data[2].y), + "+f"(dst.tiles[0][ 0].data[3].x), "+f"(dst.tiles[0][ 0].data[3].y), + "+f"(dst.tiles[0][ 1].data[0].x), "+f"(dst.tiles[0][ 1].data[0].y), + "+f"(dst.tiles[0][ 1].data[1].x), "+f"(dst.tiles[0][ 1].data[1].y), + "+f"(dst.tiles[0][ 1].data[2].x), "+f"(dst.tiles[0][ 1].data[2].y), + "+f"(dst.tiles[0][ 1].data[3].x), "+f"(dst.tiles[0][ 1].data[3].y), + "+f"(dst.tiles[0][ 2].data[0].x), "+f"(dst.tiles[0][ 2].data[0].y), + "+f"(dst.tiles[0][ 2].data[1].x), "+f"(dst.tiles[0][ 2].data[1].y), + "+f"(dst.tiles[0][ 2].data[2].x), "+f"(dst.tiles[0][ 2].data[2].y), + "+f"(dst.tiles[0][ 2].data[3].x), "+f"(dst.tiles[0][ 2].data[3].y), + "+f"(dst.tiles[0][ 3].data[0].x), "+f"(dst.tiles[0][ 3].data[0].y), + "+f"(dst.tiles[0][ 3].data[1].x), "+f"(dst.tiles[0][ 3].data[1].y), + "+f"(dst.tiles[0][ 3].data[2].x), "+f"(dst.tiles[0][ 3].data[2].y), + "+f"(dst.tiles[0][ 3].data[3].x), "+f"(dst.tiles[0][ 3].data[3].y), + "+f"(dst.tiles[0][ 4].data[0].x), "+f"(dst.tiles[0][ 4].data[0].y), + "+f"(dst.tiles[0][ 4].data[1].x), "+f"(dst.tiles[0][ 4].data[1].y), + "+f"(dst.tiles[0][ 4].data[2].x), "+f"(dst.tiles[0][ 4].data[2].y), + "+f"(dst.tiles[0][ 4].data[3].x), "+f"(dst.tiles[0][ 4].data[3].y), + "+f"(dst.tiles[0][ 5].data[0].x), "+f"(dst.tiles[0][ 5].data[0].y), + "+f"(dst.tiles[0][ 5].data[1].x), "+f"(dst.tiles[0][ 5].data[1].y), + "+f"(dst.tiles[0][ 5].data[2].x), "+f"(dst.tiles[0][ 5].data[2].y), + "+f"(dst.tiles[0][ 5].data[3].x), "+f"(dst.tiles[0][ 5].data[3].y), + "+f"(dst.tiles[0][ 6].data[0].x), "+f"(dst.tiles[0][ 6].data[0].y), + "+f"(dst.tiles[0][ 6].data[1].x), "+f"(dst.tiles[0][ 6].data[1].y), + "+f"(dst.tiles[0][ 6].data[2].x), "+f"(dst.tiles[0][ 6].data[2].y), + "+f"(dst.tiles[0][ 6].data[3].x), "+f"(dst.tiles[0][ 6].data[3].y), + "+f"(dst.tiles[0][ 7].data[0].x), "+f"(dst.tiles[0][ 7].data[0].y), + "+f"(dst.tiles[0][ 7].data[1].x), "+f"(dst.tiles[0][ 7].data[1].y), + "+f"(dst.tiles[0][ 7].data[2].x), "+f"(dst.tiles[0][ 7].data[2].y), + "+f"(dst.tiles[0][ 7].data[3].x), "+f"(dst.tiles[0][ 7].data[3].y), + "+f"(dst.tiles[0][ 8].data[0].x), "+f"(dst.tiles[0][ 8].data[0].y), + "+f"(dst.tiles[0][ 8].data[1].x), "+f"(dst.tiles[0][ 8].data[1].y), + "+f"(dst.tiles[0][ 8].data[2].x), "+f"(dst.tiles[0][ 8].data[2].y), + "+f"(dst.tiles[0][ 8].data[3].x), "+f"(dst.tiles[0][ 8].data[3].y), + "+f"(dst.tiles[0][ 9].data[0].x), "+f"(dst.tiles[0][ 9].data[0].y), + "+f"(dst.tiles[0][ 9].data[1].x), "+f"(dst.tiles[0][ 9].data[1].y), + "+f"(dst.tiles[0][ 9].data[2].x), "+f"(dst.tiles[0][ 9].data[2].y), + "+f"(dst.tiles[0][ 9].data[3].x), "+f"(dst.tiles[0][ 9].data[3].y), + "+f"(dst.tiles[0][10].data[0].x), "+f"(dst.tiles[0][10].data[0].y), + "+f"(dst.tiles[0][10].data[1].x), "+f"(dst.tiles[0][10].data[1].y), + "+f"(dst.tiles[0][10].data[2].x), "+f"(dst.tiles[0][10].data[2].y), + "+f"(dst.tiles[0][10].data[3].x), "+f"(dst.tiles[0][10].data[3].y), + "+f"(dst.tiles[0][11].data[0].x), "+f"(dst.tiles[0][11].data[0].y), + "+f"(dst.tiles[0][11].data[1].x), "+f"(dst.tiles[0][11].data[1].y), + "+f"(dst.tiles[0][11].data[2].x), "+f"(dst.tiles[0][11].data[2].y), + "+f"(dst.tiles[0][11].data[3].x), "+f"(dst.tiles[0][11].data[3].y), + "+f"(dst.tiles[0][12].data[0].x), "+f"(dst.tiles[0][12].data[0].y), + "+f"(dst.tiles[0][12].data[1].x), "+f"(dst.tiles[0][12].data[1].y), + "+f"(dst.tiles[0][12].data[2].x), "+f"(dst.tiles[0][12].data[2].y), + "+f"(dst.tiles[0][12].data[3].x), "+f"(dst.tiles[0][12].data[3].y), + "+f"(dst.tiles[0][13].data[0].x), "+f"(dst.tiles[0][13].data[0].y), + "+f"(dst.tiles[0][13].data[1].x), "+f"(dst.tiles[0][13].data[1].y), + "+f"(dst.tiles[0][13].data[2].x), "+f"(dst.tiles[0][13].data[2].y), + "+f"(dst.tiles[0][13].data[3].x), "+f"(dst.tiles[0][13].data[3].y), + "+f"(dst.tiles[0][14].data[0].x), "+f"(dst.tiles[0][14].data[0].y), + "+f"(dst.tiles[0][14].data[1].x), "+f"(dst.tiles[0][14].data[1].y), + "+f"(dst.tiles[0][14].data[2].x), "+f"(dst.tiles[0][14].data[2].y), + "+f"(dst.tiles[0][14].data[3].x), "+f"(dst.tiles[0][14].data[3].y), + "+f"(dst.tiles[0][15].data[0].x), "+f"(dst.tiles[0][15].data[0].y), + "+f"(dst.tiles[0][15].data[1].x), "+f"(dst.tiles[0][15].data[1].y), + "+f"(dst.tiles[0][15].data[2].x), "+f"(dst.tiles[0][15].data[2].y), + "+f"(dst.tiles[0][15].data[3].x), "+f"(dst.tiles[0][15].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %67;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %66, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n256k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47, %48, %49, %50, %51, %52, %53, %54, %55, %56, %57, %58, %59, %60, %61, %62, %63}, " \ + "%64, " \ + "%65, " \ + "p, 1, %67;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 5].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 6].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 7].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 8].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][ 9].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][10].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][11].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][12].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][13].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][14].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][15].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x32.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x32.impl new file mode 100644 index 0000000000..12507de27c --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x32.impl @@ -0,0 +1,446 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %23, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %23, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %13, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "{%8, %9, %10, %11}, " \ + "%12, " \ + "p, 1, %15, %14;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %13, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "{%8, %9, %10, %11}, " \ + "%12, " \ + "p, 1, %14;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %21, %19, %20;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %21, %19, %20;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %10, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "%8, " \ + "%9, " \ + "p, 1, %13, %11, %12;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %19;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %19;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %10, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "%8, " \ + "%9, " \ + "p, 1, %11;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %10, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n32k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7}, " \ + "%8, " \ + "%9, " \ + "p, 1, %11;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x48.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x48.impl new file mode 100644 index 0000000000..d573d922d8 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x48.impl @@ -0,0 +1,238 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %29, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n48k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "{%24, %25, %26, %27}, " \ + "%28, " \ + "p, 1, %31, %30;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %29, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n48k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "{%24, %25, %26, %27}, " \ + "%28, " \ + "p, 1, %31, %30;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %17, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n48k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11}, " \ + "{%12, %13, %14, %15}, " \ + "%16, " \ + "p, 1, %19, %18;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %26, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n48k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "%24, " \ + "%25, " \ + "p, 1, %29, %27, %28;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %26, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n48k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "%24, " \ + "%25, " \ + "p, 1, %29, %27, %28;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %14, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n48k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11}, " \ + "%12, " \ + "%13, " \ + "p, 1, %17, %15, %16;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x64.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x64.impl new file mode 100644 index 0000000000..59605361fb --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x64.impl @@ -0,0 +1,587 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %39, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %39, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %23, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %37, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "{%32, %33, %34, %35}, " \ + "%36, " \ + "p, 1, %38;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %21, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "{%16, %17, %18, %19}, " \ + "%20, " \ + "p, 1, %22;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %37, %35, %36;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %37, %35, %36;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %21, %19, %20;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %35;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), // transpose is not supported for FP8 + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %34, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31}, " \ + "%32, " \ + "%33, " \ + "p, 1, %35;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), // transpose is not supported for FP8 + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %19;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %18, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n64k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15}, " \ + "%16, " \ + "%17, " \ + "p, 1, %19;\n" \ + "}\n" + // a_mat descriptor, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a, imm-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x80.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x80.impl new file mode 100644 index 0000000000..c813c82246 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x80.impl @@ -0,0 +1,286 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %45, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n80k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39}, " \ + "{%40, %41, %42, %43}, " \ + "%44, " \ + "p, 1, %47, %46;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %45, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n80k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39}, " \ + "{%40, %41, %42, %43}, " \ + "%44, " \ + "p, 1, %47, %46;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %25, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n80k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19}, " \ + "{%20, %21, %22, %23}, " \ + "%24, " \ + "p, 1, %27, %26;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %42, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n80k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39}, " \ + "%40, " \ + "%41, " \ + "p, 1, %45, %43, %44;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %42, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n80k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39}, " \ + "%40, " \ + "%41, " \ + "p, 1, %45, %43, %44;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %22, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n80k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19}, " \ + "%20, " \ + "%21, " \ + "p, 1, %25, %23, %24;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x96.impl b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x96.impl new file mode 100644 index 0000000000..29ca752f17 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/64x96.impl @@ -0,0 +1,703 @@ +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt_base & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %53, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "{%48, %49, %50, %51}, " \ + "%52, " \ + "p, 1, %55, %54;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %53, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "{%48, %49, %50, %51}, " \ + "%52, " \ + "p, 1, %55, %54;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %29, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "{%24, %25, %26, %27}, " \ + "%28, " \ + "p, 1, %31, %30;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), "r"(scale_d), "n"(trans_b), "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %53, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "{%48, %49, %50, %51}, " \ + "%52, " \ + "p, 1, %54;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %53, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "{%48, %49, %50, %51}, " \ + "%52, " \ + "p, 1, %54;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %29, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "{%24, %25, %26, %27}, " \ + "%28, " \ + "p, 1, %30;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %29, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "{%24, %25, %26, %27}, " \ + "%28, " \ + "p, 1, %30;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]) + + : "r"(*(uint32_t*)&a_rt.data[0]), "r"(*(uint32_t*)&a_rt.data[1]), + "r"(*(uint32_t*)&a_rt.data[2]), "r"(*(uint32_t*)&a_rt.data[3]), + + "l"(b_st_desc), + "r"(scale_d), + // "n"(trans_b), + "n"(scale_b) + ); + } + + } + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ) { + static_assert( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v), + "Invalid type combination for WGMMA." + ); + static_assert(scale_b==1 || scale_b==-1, "Invalid scale B (invert) option"); + // ----- BF16,BF16 -> FP32 ----- // + if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %50, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k16.f32.bf16.bf16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "%48, " \ + "%49, " \ + "p, 1, %53, %51, %52;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %50, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k16.f32.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "%48, " \ + "%49, " \ + "p, 1, %53, %51, %52;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP16,FP16 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %26, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k16.f16.f16.f16 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "%24, " \ + "%25, " \ + "p, 1, %29, %27, %28;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + "n"(trans_a), + "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %50, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f32.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "%48, " \ + "%49, " \ + "p, 1, %51;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP32 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %50, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f32.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44, %45, %46, %47}, " \ + "%48, " \ + "%49, " \ + "p, 1, %51;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+f"(dst.tiles[0][0].data[0].x), "+f"(dst.tiles[0][0].data[0].y), + "+f"(dst.tiles[0][0].data[1].x), "+f"(dst.tiles[0][0].data[1].y), + "+f"(dst.tiles[0][0].data[2].x), "+f"(dst.tiles[0][0].data[2].y), + "+f"(dst.tiles[0][0].data[3].x), "+f"(dst.tiles[0][0].data[3].y), + "+f"(dst.tiles[0][1].data[0].x), "+f"(dst.tiles[0][1].data[0].y), + "+f"(dst.tiles[0][1].data[1].x), "+f"(dst.tiles[0][1].data[1].y), + "+f"(dst.tiles[0][1].data[2].x), "+f"(dst.tiles[0][1].data[2].y), + "+f"(dst.tiles[0][1].data[3].x), "+f"(dst.tiles[0][1].data[3].y), + "+f"(dst.tiles[0][2].data[0].x), "+f"(dst.tiles[0][2].data[0].y), + "+f"(dst.tiles[0][2].data[1].x), "+f"(dst.tiles[0][2].data[1].y), + "+f"(dst.tiles[0][2].data[2].x), "+f"(dst.tiles[0][2].data[2].y), + "+f"(dst.tiles[0][2].data[3].x), "+f"(dst.tiles[0][2].data[3].y), + "+f"(dst.tiles[0][3].data[0].x), "+f"(dst.tiles[0][3].data[0].y), + "+f"(dst.tiles[0][3].data[1].x), "+f"(dst.tiles[0][3].data[1].y), + "+f"(dst.tiles[0][3].data[2].x), "+f"(dst.tiles[0][3].data[2].y), + "+f"(dst.tiles[0][3].data[3].x), "+f"(dst.tiles[0][3].data[3].y), + "+f"(dst.tiles[0][4].data[0].x), "+f"(dst.tiles[0][4].data[0].y), + "+f"(dst.tiles[0][4].data[1].x), "+f"(dst.tiles[0][4].data[1].y), + "+f"(dst.tiles[0][4].data[2].x), "+f"(dst.tiles[0][4].data[2].y), + "+f"(dst.tiles[0][4].data[3].x), "+f"(dst.tiles[0][4].data[3].y), + "+f"(dst.tiles[0][5].data[0].x), "+f"(dst.tiles[0][5].data[0].y), + "+f"(dst.tiles[0][5].data[1].x), "+f"(dst.tiles[0][5].data[1].y), + "+f"(dst.tiles[0][5].data[2].x), "+f"(dst.tiles[0][5].data[2].y), + "+f"(dst.tiles[0][5].data[3].x), "+f"(dst.tiles[0][5].data[3].y) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %26, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f16.e4m3.e4m3 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "%24, " \ + "%25, " \ + "p, 1, %27;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + // ----- FP8,FP8 -> FP16 ----- // + else if constexpr (std::is_same_v && std::is_same_v) { + asm volatile ( + "{\n" + ".reg .pred p;\n" \ + "setp.ne.b32 p, %26, 0;\n" \ + "wgmma.mma_async.sync.aligned.m64n96k32.f16.e5m2.e5m2 " \ + "{%0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23}, " \ + "%24, " \ + "%25, " \ + "p, 1, %27;\n" \ + "}\n" + // a_regs, b_mat descriptor, scale-d, imm-scale-a, imm-scale-b, im-trans-a im-trans-b + + : "+r"(*(uint32_t*)&dst.tiles[0][0].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][0].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][1].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][2].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][3].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][4].data[3]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[0]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[1]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[2]), + "+r"(*(uint32_t*)&dst.tiles[0][5].data[3]) + + : "l"(a_st_desc), + "l"(b_st_desc), + + "r"(scale_d), + // "n"(trans_a), + // "n"(trans_b), + "n"(scale_b) + ); + } + } +}; \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/base.cuh b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/base.cuh new file mode 100644 index 0000000000..6bd09c6816 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/base/base.cuh @@ -0,0 +1,47 @@ +#pragma once + +#include "../../../../../common/common.cuh" +#include "../../../../../types/types.cuh" + +namespace kittens { +namespace detail { +namespace wgmma { + +// templated wrapper for PTX +template +struct base { + template __device__ static inline void rt_st( + rt &dst, + const rt & a_rt, + const uint64_t b_st_desc, + int scale_d = 1 + ); + template __device__ static inline void st_st( + rt &dst, + const uint64_t a_st_desc, + const uint64_t b_st_desc, + int scale_d = 1 + ); +}; + +// all the ptx's +#include "64x16.impl" +#include "64x32.impl" +#include "64x48.impl" +#include "64x64.impl" +#include "64x80.impl" +#include "64x96.impl" +#include "64x112.impl" +#include "64x128.impl" +#include "64x144.impl" +#include "64x160.impl" +#include "64x176.impl" +#include "64x192.impl" +#include "64x208.impl" +#include "64x224.impl" +#include "64x240.impl" +#include "64x256.impl" + +} // namespace wgmma +} // namespace detail +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/mma/warpgroup/warpgroup.cuh b/extra/thunder/cuda/include/ops/group/mma/warpgroup/warpgroup.cuh new file mode 100644 index 0000000000..ae4c315281 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/mma/warpgroup/warpgroup.cuh @@ -0,0 +1,1170 @@ +/** + * @file + * @brief Warpgroup matrix-multiply accumulate operations. These ops are necessary to achieve full utilization on H100 GPUs. + */ + + + +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------------ FENCES ------------------------------------------------------ +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- + + +/** + * @brief Synchronize the warp group and ensure that all writes to shared memory are visible to all threads in the warp group. + * + * This function acts as a fence for shared memory operations, ensuring that all previous writes are visible before proceeding. + * This function should be called before running wgmma::mma or wgmma::dot instructions. + * + * @tparam height The height of the matrix `dst`. + * @tparam width The width of the matrix `dst`. + * @param dst[in,out] The destination register-tile matrix to be synchronized. + */ +template +__device__ static inline void mma_fence(D &dst) { + KITTENS_CHECK_WARPGROUP + #pragma unroll + for(int i = 0; i < D::height; i++) { + #pragma unroll + for(int j = 0; j < D::width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k++) { + if constexpr(std::is_same_v) { + asm volatile("" : "+f"(dst.tiles[i][j].data[k].x) :: "memory"); + asm volatile("" : "+f"(dst.tiles[i][j].data[k].y) :: "memory"); + } else { + asm volatile("" : "+r"(*(uint32_t*)&dst.tiles[i][j].data[k]) :: "memory"); + } + } + } + } + asm volatile ("wgmma.fence.sync.aligned;\n" ::: "memory"); + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); +} +template +__device__ static inline void mma_fence(D &dst) { + KITTENS_CHECK_WARPGROUP + #pragma unroll + for(int i = 0; i < D::height; i++) { + #pragma unroll + for(int j = 0; j < D::width; j++) { + #pragma unroll + for(int k = 0; k < dst.real.packed_per_tile; k++) { + if constexpr(std::is_same_v) { + asm volatile("" : "+f"(dst.real.tiles[i][j].data[k].x) :: "memory"); + asm volatile("" : "+f"(dst.real.tiles[i][j].data[k].y) :: "memory"); + asm volatile("" : "+f"(dst.imag.tiles[i][j].data[k].x) :: "memory"); + asm volatile("" : "+f"(dst.imag.tiles[i][j].data[k].y) :: "memory"); + } else { + asm volatile("" : "+r"(*(uint32_t*)&dst.real.tiles[i][j].data[k]) :: "memory"); + asm volatile("" : "+r"(*(uint32_t*)&dst.imag.tiles[i][j].data[k]) :: "memory"); + } + } + } + } + asm volatile ("wgmma.fence.sync.aligned;\n" ::: "memory"); + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); +} +template // prevents static assert being instantiated unless called. +__device__ static inline void mma_fence() { + KITTENS_CHECK_WARPGROUP + asm volatile ("wgmma.fence.sync.aligned;\n" ::: "memory"); + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); +} + +/** + * @brief Commit the current set of warp group matrix multiply accumulate calls. + */ +template // prevents static assert being instantiated unless called. +__device__ static inline void mma_commit_group() { + KITTENS_CHECK_WARPGROUP + asm volatile("wgmma.commit_group.sync.aligned;\n" ::: "memory"); +} + +/** + * @brief Wait for the warp group to reach a synchronization point. + * + * This function stalls the current warpgroup until enough WGMMA committed groups have been completed. + * + * @tparam N The number of remaining active WGMMA committed groups allowed. This will stall until the number of active groups is less than or equal to N. Defaults to 0. + */ +template +__device__ static inline void mma_async_wait() { + KITTENS_CHECK_WARPGROUP + asm volatile ("wgmma.wait_group.sync.aligned %0;" : : "n"(N) : "memory"); +} + + +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------------ NORMAL ------------------------------------------------------ +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- + +/* + ### OPTIONS: + + REG+SMEM -> REG + - mma_AB (accum) [DONE] + - mm_AB (reset) [DONE] + - mma_ABt (accum) [DONE] + - mm_ABt (reset) [DONE] + + SMEM+SMEM -> REG + - mma_AB (accum) [DONE] + - mm_AB (reset) [DONE] + - mma_ABt (accum) [DONE] + - mm_ABt (reset) [DONE] + - mma_AtB (accum) [DONE] + - mm_AtB (reset) [DONE] + - mma_AtBt (accum) [DONE] + - mm_AtBt (reset) [DONE] + +Note: mma is an alias for mma_AB and dot is an alias for mma_ABt +*/ + +// [(register, shared) -> register] edition +/** + * @brief Perform matrix multiply-accumulate operation using warp group matrix multiply-accumulate (WGMMA) primitives. + * + * This function multiplies a register tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam N_DIV_4 The height of the matrix `a` divided by 4. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The width of the matrices `b` and `d`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source register tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_AB(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M_DIV_4 = A::height; + static_assert(D::height == M_DIV_4); // output register is correctly sized + constexpr int N = B::width; + constexpr int K = A::width; + static_assert(B::height == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 0, 1>; + kittens::st_descriptor, 1> b_desc(b); // apologies for this hack -- it either calls ST constructor or copy constructor. + + if constexpr (fence) { mma_fence(d); } + + // Do it + #pragma unroll + for(int m = 0; m < M_DIV_4; m++) { + rt, TILE_COL_DIM*N, ducks::rt_layout::row> &d_ref = group<1>::subtile_inplace>(d, m); + base::rt_st( + d_ref, + a.tiles[m][0], + b_desc.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::rt_st( + d_ref, + a.tiles[m][k], + b_desc.chunk_descriptor(k), + 1 + ); + } + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AB(D &d, + const A &a, + const B &b) { + mma_AB(d, a, b); +} + +template +__device__ static inline void mma_AB(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::height; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::width; + constexpr int K = A::width; + static_assert(B::height == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 0, 1>; + kittens::st_descriptor, 0> a_desc(a); + kittens::st_descriptor, 1> b_desc(b); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d, + a_desc.chunk_descriptor(0), + b_desc.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d, + a_desc.chunk_descriptor(k), + b_desc.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AB(D &d, + const A &a, + const B &b) { + mma_AB(d, a, b); +} + +// [(register, shared) -> register] edition +/** + * @brief Perform matrix outer product operation using warp group matrix multiply-accumulate (WGMMA) primitives. + * + * This function computes an outer product of a register tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam N_DIV_4 The height of the matrix `a` divided by 4. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The height of the matrices `b` and `d`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source register tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_ABt(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M_DIV_4 = A::height; + static_assert(D::height == M_DIV_4); // output register is correctly sized + constexpr int N = B::height; + constexpr int K = A::width; + static_assert(B::width == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + using base = kittens::detail::wgmma::base*N, 0, 0>; + kittens::st_descriptor, 0> b_desc(b); + + if constexpr (fence) { mma_fence(d); } + + // Do it + #pragma unroll + for(int m = 0; m < M_DIV_4; m++) { + rt, TILE_COL_DIM*N, ducks::rt_layout::row> &d_ref = group<1>::subtile_inplace>(d, m); + base::rt_st( + d_ref, + a.tiles[m][0], + b_desc.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::rt_st( + d_ref, + a.tiles[m][k], + b_desc.chunk_descriptor(k), + 1 + ); + } + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_ABt(D &d, + const A &a, + const B &b) { + mma_ABt(d, a, b); +} + +// [(shared, shared) -> register] edition +/** + * @brief Perform matrix outer product operation using warp group matrix multiply-accumulate (WGMMA) primitives. + * + * This function computes an outer product of a shared tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The height of the matrices `b` and `d`. + * @tparam L_A The layout of the matrix `a`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source shared tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_ABt(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::height; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::height; + constexpr int K = A::width; + static_assert(B::width == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + using base = kittens::detail::wgmma::base*N, 0, 0>; + kittens::st_descriptor, 0> a_desc(a); + kittens::st_descriptor, 0> b_desc(b); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d, + a_desc.chunk_descriptor(0), + b_desc.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d, + a_desc.chunk_descriptor(k), + b_desc.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_ABt(D &d, + const A &a, + const B &b) { + mma_ABt(d, a, b); +} + +// [(shared, shared) -> register] edition +/** + * @brief Perform matrix multiply using warp group matrix multiply-accumulate (WGMMA) primitives, with A transposed. + * + * This function computes an outer product of a shared tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The height of the matrices `b` and `d`. + * @tparam L_A The layout of the matrix `a`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source shared tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_AtB(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::width; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::width; + constexpr int K = A::height; + static_assert(B::height == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 1, 1>; + kittens::st_descriptor, 1> a_desc(a); + kittens::st_descriptor, 1> b_desc(b); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d, + a_desc.chunk_descriptor(0), + b_desc.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d, + a_desc.chunk_descriptor(k), + b_desc.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AtB(D &d, + const A &a, + const B &b) { + mma_AtB(d, a, b); +} + +// [(shared, shared) -> register] edition +/** + * @brief Perform matrix multiply using warp group matrix multiply-accumulate (WGMMA) primitives, with A and B transposed. + * + * This function computes an outer product of a shared tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam D The destination register tile type. + * @tparam A The source shared tile type. + * @tparam B The source shared tile type. + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + */ +template +__device__ static inline void mma_AtBt(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::width; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::height; + constexpr int K = A::height; + static_assert(B::width == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 1, 0>; + kittens::st_descriptor, 1> a_desc(a); + kittens::st_descriptor, 0> b_desc(b); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d, + a_desc.chunk_descriptor(0), + b_desc.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d, + a_desc.chunk_descriptor(k), + b_desc.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AtBt(D &d, + const A &a, + const B &b) { + mma_AtBt(d, a, b); +} + + + +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------- COMPLEX INPUTS -------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- + + +/* + ### OPTIONS: + + REG+SMEM -> REG + - mma_AB (accum) [TODO] + - mm_AB (reset) [TODO] + - mma_ABt (accum) [TODO] + - mm_ABt (reset) [TODO] + + SMEM+SMEM -> REG + - mma_AB (accum) [TODO] + - mm_AB (reset) [TODO] + - mma_ABt (accum) [TODO] + - mm_ABt (reset) [TODO] + - mma_AtB (accum) [TODO] + - mm_AtB (reset) [TODO] + - mma_AtBt (accum) [TODO] + - mm_AtBt (reset) [TODO] + +Note: mma is an alias for mma_AB and dot is an alias for mma_ABt +*/ + +// [(register, shared) -> register] edition +/** + * @brief Perform matrix multiply-accumulate operation using warp group matrix multiply-accumulate (WGMMA) primitives. + * + * This function multiplies a register tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam N_DIV_4 The height of the matrix `a` divided by 4. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The width of the matrices `b` and `d`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source register tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_AB(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M_DIV_4 = A::height; + static_assert(D::height == M_DIV_4); // output register is correctly sized + constexpr int N = B::width; + constexpr int K = A::width; + static_assert(B::height == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 0, 1>; + kittens::st_descriptor, 1> b_desc_real(b.real); + kittens::st_descriptor, 1> b_desc_imag(b.imag); + + if constexpr (fence) { mma_fence(d); } + + // Do it + #pragma unroll // Do real part + for(int m = 0; m < M_DIV_4; m++) { + rt, TILE_COL_DIM*N, ducks::rt_layout::row> &d_ref = group<1>::subtile_inplace>(d.real, m); + base::rt_st( + d_ref, + a.real.tiles[m][0], + b_desc_real.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::rt_st( + d_ref, + a.real.tiles[m][k], + b_desc_real.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::rt_st<-1>( // INVERT THE SIGN OF THE IMAGINARY PART + d_ref, + a.imag.tiles[m][k], + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + } + #pragma unroll // Do imaginary part + for(int m = 0; m < M_DIV_4; m++) { + rt, TILE_COL_DIM*N, ducks::rt_layout::row> &d_ref = group<1>::subtile_inplace>(d.imag, m); + base::rt_st( + d_ref, + a.real.tiles[m][0], + b_desc_imag.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::rt_st( + d_ref, + a.real.tiles[m][k], + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::rt_st( + d_ref, + a.imag.tiles[m][k], + b_desc_real.chunk_descriptor(k), + 1 + ); + } + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AB(D &d, + const A &a, + const B &b) { + mma_AB(d, a, b); +} + +template +__device__ static inline void mma_AB(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::height; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::width; + constexpr int K = A::width; + static_assert(B::height == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 0, 1>; + kittens::st_descriptor, 0> a_desc_real(a.real); + kittens::st_descriptor, 0> a_desc_imag(a.imag); + kittens::st_descriptor, 1> b_desc_real(b.real); + kittens::st_descriptor, 1> b_desc_imag(b.imag); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d.real, + a_desc_real.chunk_descriptor(0), + b_desc_real.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.real, + a_desc_real.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st<-1>( // INVERT THE SIGN OF THE IMAGINARY PART + d.real, + a_desc_imag.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(0), + b_desc_imag.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st( + d.imag, + a_desc_imag.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AB(D &d, + const A &a, + const B &b) { + mma_AB(d, a, b); +} + +// [(register, shared) -> register] edition +/** + * @brief Perform matrix outer product operation using warp group matrix multiply-accumulate (WGMMA) primitives. + * + * This function computes an outer product of a register tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam N_DIV_4 The height of the matrix `a` divided by 4. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The height of the matrices `b` and `d`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source register tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_ABt(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M_DIV_4 = A::height; + static_assert(D::height == M_DIV_4); // output register is correctly sized + constexpr int N = B::height; + constexpr int K = A::width; + static_assert(B::width == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + using base = kittens::detail::wgmma::base*N, 0, 0>; + kittens::st_descriptor, 0> b_desc_real(b.real); + kittens::st_descriptor, 0> b_desc_imag(b.imag); + + if constexpr (fence) { mma_fence(d); } + + // Do it + #pragma unroll + for(int m = 0; m < M_DIV_4; m++) { + rt, TILE_ROW_DIM*N, ducks::rt_layout::row> &d_ref = group<1>::subtile_inplace>(d.real, m); + base::rt_st( + d_ref, + a.real.tiles[m][0], + b_desc_real.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::rt_st( + d_ref, + a.real.tiles[m][k], + b_desc_real.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::rt_st<-1>( // INVERT THE SIGN OF THE IMAGINARY PART + d_ref, + a.imag.tiles[m][k], + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + } + #pragma unroll + for(int m = 0; m < M_DIV_4; m++) { + rt, TILE_ROW_DIM*N, ducks::rt_layout::row> &d_ref = group<1>::subtile_inplace>(d.imag, m); + base::rt_st( + d_ref, + a.real.tiles[m][0], + b_desc_imag.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::rt_st( + d_ref, + a.real.tiles[m][k], + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::rt_st( + d_ref, + a.imag.tiles[m][k], + b_desc_real.chunk_descriptor(k), + 1 + ); + } + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_ABt(D &d, + const A &a, + const B &b) { + mma_ABt(d, a, b); +} + +// [(shared, shared) -> register] edition +/** + * @brief Perform matrix outer product operation using warp group matrix multiply-accumulate (WGMMA) primitives. + * + * This function computes an outer product of a shared tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The height of the matrices `b` and `d`. + * @tparam L_A The layout of the matrix `a`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source shared tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_ABt(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::height; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::height; + constexpr int K = A::width; + static_assert(B::width == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + using base = kittens::detail::wgmma::base*N, 0, 0>; + kittens::st_descriptor, 0> a_desc_real(a.real); + kittens::st_descriptor, 0> a_desc_imag(a.imag); + kittens::st_descriptor, 0> b_desc_real(b.real); + kittens::st_descriptor, 0> b_desc_imag(b.imag); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d.real, + a_desc_real.chunk_descriptor(0), + b_desc_real.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.real, + a_desc_real.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st<-1>( // INVERT THE SIGN OF THE IMAGINARY PART + d.real, + a_desc_imag.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(0), + b_desc_imag.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st( + d.imag, + a_desc_imag.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_ABt(D &d, + const A &a, + const B &b) { + mma_ABt(d, a, b); +} + +// [(shared, shared) -> register] edition +/** + * @brief Perform matrix multiply using warp group matrix multiply-accumulate (WGMMA) primitives, with A transposed. + * + * This function computes an outer product of a shared tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + * @tparam K The common dimension of matrices `a` and `b`. + * @tparam M The height of the matrices `b` and `d`. + * @tparam L_A The layout of the matrix `a`. + * @tparam L_B The layout of the matrix `b`. + * @param d[out] The destination register tile where the result is accumulated or written. + * @param a[in] The source shared tile to be multiplied. + * @param b[in] The source shared tile to be multiplied. + */ +template +__device__ static inline void mma_AtB(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::width; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::width; + constexpr int K = A::height; + static_assert(B::height == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 1, 1>; + kittens::st_descriptor, 1> a_desc_real(a.real); + kittens::st_descriptor, 1> a_desc_imag(a.imag); + kittens::st_descriptor, 1> b_desc_real(b.real); + kittens::st_descriptor, 1> b_desc_imag(b.imag); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d.real, + a_desc_real.chunk_descriptor(0), + b_desc_real.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.real, + a_desc_real.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st<-1>( // INVERT THE SIGN OF THE IMAGINARY PART + d.real, + a_desc_imag.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(0), + b_desc_imag.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st( + d.imag, + a_desc_imag.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AtB(D &d, + const A &a, + const B &b) { + mma_AtB(d, a, b); +} + +// [(shared, shared) -> register] edition +/** + * @brief Perform matrix multiply using warp group matrix multiply-accumulate (WGMMA) primitives, with A and B transposed. + * + * This function computes an outer product of a shared tile `a` with a shared tile `b` and writes the result into a register tile `d`. + * + * @tparam D The destination register tile type. + * @tparam A The source shared tile type. + * @tparam B The source shared tile type. + * @tparam accumulate Whether to accumulate the result into `d` or overwrite `d`. + */ +template +__device__ static inline void mma_AtBt(D &d, + const A &a, + const B &b) { + // Checks + KITTENS_CHECK_WARPGROUP + constexpr int M = A::width; + static_assert(M == 4); + static_assert(D::height == 1); // output register is correctly sized + constexpr int N = B::height; + constexpr int K = A::height; + static_assert(B::width == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; + using T_D = D::T; + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + static_assert(!std::is_same_v && !std::is_same_v, "Currently unsupported type"); + #endif + using base = kittens::detail::wgmma::base*N, 1, 0>; + kittens::st_descriptor, 1> a_desc_real(a.real); + kittens::st_descriptor, 1> a_desc_imag(a.imag); + kittens::st_descriptor, 0> b_desc_real(b.real); + kittens::st_descriptor, 0> b_desc_imag(b.imag); + + if constexpr (fence) { mma_fence(d); } + + // Do it + base::st_st( + d.real, + a_desc_real.chunk_descriptor(0), + b_desc_real.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.real, + a_desc_real.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st<-1>( // INVERT THE SIGN OF THE IMAGINARY PART + d.real, + a_desc_imag.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(0), + b_desc_imag.chunk_descriptor(0), + accumulate + ); + #pragma unroll + for(int k = 1; k < K; k++) { + base::st_st( + d.imag, + a_desc_real.chunk_descriptor(k), + b_desc_imag.chunk_descriptor(k), + 1 + ); + } + #pragma unroll + for(int k = 0; k < K; k++) { + base::st_st( + d.imag, + a_desc_imag.chunk_descriptor(k), + b_desc_real.chunk_descriptor(k), + 1 + ); + } + mma_commit_group(); // commit the group of these WGMMA calls. +} +template +__device__ static inline void mm_AtBt(D &d, + const A &a, + const B &b) { + mma_AtBt(d, a, b); +} + +// Some extra wrappers for prettiness + +template +__device__ static inline void mma(D &d, + const A &a, + const B &b) { + if constexpr(trans_A == transpose::T) { + if constexpr(trans_B == transpose::T) { + mma_AtBt(d, a, b); + } else { + mma_AtB(d, a, b); + } + } else { + if constexpr(trans_B == transpose::T) { + mma_ABt(d, a, b); + } else { + mma_AB(d, a, b); + } + } +} +template +__device__ static inline void mm(D &d, + const A &a, + const B &b) { + if constexpr(trans_A == transpose::T) { + if constexpr(trans_B == transpose::T) { + mm_AtBt(d, a, b); + } else { + mm_AtB(d, a, b); + } + } else { + if constexpr(trans_B == transpose::T) { + mm_ABt(d, a, b); + } else { + mm_AB(d, a, b); + } + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/register.cuh b/extra/thunder/cuda/include/ops/group/register/register.cuh new file mode 100644 index 0000000000..f87cfe017a --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/register.cuh @@ -0,0 +1,7 @@ +/** + * @file + * @brief An aggregate header for warp operations on data stored in registers. + */ + +#include "tile/tile.cuh" +#include "vec/vec.cuh" \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/tile/complex/complex_conversions.cuh b/extra/thunder/cuda/include/ops/group/register/tile/complex/complex_conversions.cuh new file mode 100644 index 0000000000..6430a0a381 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/tile/complex/complex_conversions.cuh @@ -0,0 +1,98 @@ +/** + * @file + * @brief Conversions between data layouts and types for complex register tiles. + */ + +/* ---------- LAYOUT SWAPS ---------- */ + +/** + * @brief Swaps the layout of a complex register tile. + * + * This function swaps the layout of a complex register tile by + * swapping the real and imaginary component tiles' layouts + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the register tile. + * @tparam _width The width of the register tile. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the destination register tile where the result will be stored. + * @param src[in] Reference to the source register tile to be swapped. + */ +template +__device__ static inline void swap_layout(crt::type> &dst, const crt &src) { + swap_layout(dst.real, src.real); + swap_layout(dst.real, src.real); +} +/** + * @brief Swaps the layout of a complex register tile in place. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the register tile. + * @tparam _width The width of the register tile. + * @tparam layout The current layout of the register tile. + * @param tile[in,out] Reference to the register tile to be swapped in place. + * @return A reference to the swapped register tile. + */ +template +__device__ static inline crt::type>& swap_layout_inplace(crt &tile) { + tile.real = swap_layout_inplace(tile.real); + tile.imag = swap_layout_inplace(tile.imag); + return tile; +} + +/* ---------- TRANSPOSE ---------- */ + +/** + * @brief Transposes a complex register tile. + * + * This function is marked "sep", which means that the registers underlying dst MUST be separate + * from the registers underlying src. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the src register tile, and the width of the dst tile. + * @tparam _width The width of the src register tile, and the height of the dst tile. + * @tparam layout The layout of the register tile. + * @param dst[out] Reference to the register tile in which to store the transposed src. + * @param src[in] Reference to the register tile to be transposed. + */ +template +__device__ static inline void transpose_sep(crt &dst, const crt &src) { + transpose_sep(dst.real, src.real); + transpose_sep(dst.imag, src.imag); +} +/** + * @brief Transposes a square complex register tile in-place. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height (in units of 16) of the src register tile, and the width of the dst tile. (Must be the same as _width.) + * @tparam _width The width (in units of 16) of the src register tile, and the height of the dst tile. (Must be the same as _height.) + * @tparam layout The current layout of the register tile. + * @param src[in] Reference to the register tile to be transposed. + * @return A reference to the transposed register tile. + */ +template +__device__ static inline crt& transpose_inplace(crt &tile) { + tile.real = transpose_inplace(tile.real); + tile.imag = transpose_inplace(tile.imag); + + return tile; +} + +/* ---------- TYPE SWAPS ---------- */ + +/** + * @brief Copies a complex register tile, converting the underlying type if necessary. + * + * @tparam T2 The data type of the destination register elements. + * @tparam U2 The data type of the source register elements. + * @tparam _height The height (in units of 16) of the register tiles. + * @tparam _width The width (in units of 16) of the register tiles. + * @tparam layout The current layout of the register tile. + * @param[out] dst A reference to the destination register tile. + * @param[in] src A reference to the source register tile. + */ +template +__device__ static inline void copy(crt &dst, const crt &src) { + copy(dst.real, src.real); + copy(dst.imag, src.imag); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/tile/complex/complex_maps.cuh b/extra/thunder/cuda/include/ops/group/register/tile/complex/complex_maps.cuh new file mode 100644 index 0000000000..46fce709f0 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/tile/complex/complex_maps.cuh @@ -0,0 +1,137 @@ +/** + * @file + * @brief Map operations between complex tiles. + */ + +/** + * @brief Sets all elements of a complex tile to zero. + * + * @tparam T Complex tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +__device__ static inline void zero(T &dst) { + zero(dst.real); + zero(dst.imag); +} +/** + * @brief Applies the exponential function to each element of a complex tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the exponential function on. + */ +template +__device__ static inline void exp(T &dst, const T &src) { + using dtype = T::dtype; + dtype tmp; + // out of place storage + dtype rdst; + dtype idst; + + // exp(a) + exp(rdst, src.real); + copy(idst, rdst); + // exp(a)cos(b) + exp(a)sin(b)i + cos(tmp, src.imag); + mul(rdst, rdst, tmp); + sin(tmp, src.imag); + mul(idst, idst, tmp); + + copy(dst.real, rdst); + copy(dst.imag, idst); +} +/** + * @brief Adds two complex tiles element-wise. + * + * @tparam T Complex Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the addition. + * @param rhs[in] Right-hand side source tile for the addition. + */ +template +__device__ static inline void add(T &dst, const T &lhs, const T &rhs) { + add(dst.real, lhs.real, rhs.real); + add(dst.imag, lhs.imag, rhs.imag); +} +/** + * @brief Subtracts two tiles element-wise. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the subtraction. + * @param rhs[in] Right-hand side source tile for the subtraction. + */ +template +__device__ static inline void sub(T &dst, const T &lhs, const T &rhs) { + sub(dst.real, lhs.real, rhs.real); + sub(dst.imag, lhs.imag, rhs.imag); +} +/** + * @brief Multiplies two tiles element-wise. + * + * @tparam T Complex tile type. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the multiplication. + * @param rhs[in] Right-hand side source tile for the multiplication. + */ +template +__device__ static inline void mul(T &dst, const T &lhs, const T &rhs) { + using dtype = T::component; + dtype tmp; + // out of place storage regs + dtype rdst; + dtype idst; + + // (a + bi) * (c + di) --> (ac - bd) + (ad + bc)i + // Real component + mul(rdst, lhs.real, rhs.real); + mul(tmp, lhs.imag, rhs.imag); + sub(rdst, rdst, tmp); + + // Imag component + mul(idst, lhs.imag, rhs.real); + mul(tmp, lhs.real, rhs.imag); + add(idst, idst, tmp); + + copy(dst.real, rdst); + copy(dst.imag, idst); +} +/** + * @brief Divides two tiles element-wise. + * + * @tparam T Complex tile type. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the division. + * @param rhs[in] Right-hand side source tile or scalar for the division. + */ +template +__device__ static inline void div(T &dst, const T &lhs, const T &rhs) { + using dtype = T::dtype; + dtype tmp; + dtype denom; + // out of place storage regs + dtype rdst; + dtype idst; + + // Calculate denom - square of b terms + mul(tmp, rhs.real, rhs.real); + mul(denom, rhs.imag, rhs.imag); + add(denom, tmp, denom); + // Real component + mul(rdst, lhs.real, rhs.real); + mul(tmp, lhs.imag, rhs.imag); + add(rdst, rdst, tmp); + // Imag component + mul(dst.imag, lhs.imag, rhs.real); + mul(tmp, lhs.real, rhs.imag); + sub(idst, idst, tmp); + // Divide components by denom + div(rdst, rdst, denom); + div(idst, idst, denom); + copy(dst.real, rdst); + copy(dst.imag, idst); +} + + diff --git a/extra/thunder/cuda/include/ops/group/register/tile/conversions.cuh b/extra/thunder/cuda/include/ops/group/register/tile/conversions.cuh new file mode 100644 index 0000000000..f3a7d74345 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/tile/conversions.cuh @@ -0,0 +1,415 @@ +/** + * @file + * @brief Conversions between data layouts and types for register tiles. + */ + +/* ---------- LAYOUT SWAPS ---------- */ + +/** + * @brief Perform a matrix transpose on a block of 8 bf16_2 elements using inline assembly. + * + * This low-level operation is utilized by higher-level layout swap functions to transpose + * the layout of bf16_2 elements within a register tile. The function leverages inline PTX + * assembly to efficiently swap the layout of the given block. + * + * @param[out] dst A reference to the destination bf16_2 element where the transposed result is stored. + * @param[in] src A reference to the source bf16_2 element to be transposed. + */ +__device__ static inline void swap_layout_8(bf16_2 &dst, const bf16_2 &src) { + KITTENS_CHECK_WARP + asm volatile ( + "movmatrix.sync.aligned.m8n8.trans.b16 %0, %1;\n" + : "+r"(*(uint32_t*)(&dst)) + : "r"(*(uint32_t*)(&src)) + ); +} +/** + * @brief Swaps the layout of a register base tile. + * + * This function swaps the layout of a register base tile by performing a series of layout swaps + * on its constituent bf16_2 elements. It is used to change the data layout within a register tile. + * + * @tparam T2 The data type of the register tile elements. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the destination register base tile where the result will be stored. + * @param src[in] Reference to the source register base tile to be swapped. + */ +template +__device__ static inline void swap_layout(rt_base::type> &dst, const rt_base &src) { + swap_layout_8(dst.data[0], src.data[0]); + // technically this swap can be eliminated if we simply reinterpret the layout of the registers + // everywhere else in the code, but that feels... very likely to cause bugs and not worth it. + typename rt_base::T2 data1_cache = src.data[1]; // important for swap! + swap_layout_8(dst.data[1], src.data[2]); + swap_layout_8(dst.data[2], data1_cache); + swap_layout_8(dst.data[3], src.data[3]); +} +/** + * @brief Swaps the layout of a register tile. + * + * This function swaps the layout of a register tile by iterating over its height and width + * and performing layout swaps on each of its base elements. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the register tile. + * @tparam _width The width of the register tile. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the destination register tile where the result will be stored. + * @param src[in] Reference to the source register tile to be swapped. + */ +template +__device__ static inline void swap_layout(rt::type> &dst, const rt &src) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + swap_layout(dst.tiles[i][j], src.tiles[i][j]); + } + } +} + +/** + * @brief Swaps the layout of a register base tile in place. + * + * This function swaps the layout of a register base tile in place by casting it to the + * transposed layout type and then performing the layout swap. + * + * @tparam T2 The data type of the register tile elements. + * @tparam layout The current layout of the register tile. + * @param src[in] Reference to the register base tile to be swapped in place. + * @return A reference to the swapped register base tile. + */ +template +__device__ static inline rt_base::type>& swap_layout_inplace(const rt_base &src) { + rt_base::type> &dst = *(rt_base::type>*)(&src); + swap_layout(dst, src); + return dst; +} +/** + * @brief Swaps the layout of a register tile in place. + * + * This function swaps the layout of a register tile in place by iterating over its height and width + * and performing in-place layout swaps on each of its base elements. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the register tile. + * @tparam _width The width of the register tile. + * @tparam layout The current layout of the register tile. + * @param tile[in,out] Reference to the register tile to be swapped in place. + * @return A reference to the swapped register tile. + */ +template +__device__ static inline rt::type>& swap_layout_inplace(rt &tile) { + #pragma unroll + for(int i = 0; i < tile.height; i++) { + #pragma unroll + for(int j = 0; j < tile.width; j++) { + swap_layout_inplace(tile.tiles[i][j]); + } + } + return *(rt::type>*)(&tile); +} + +/* ---------- TRANSPOSE ---------- */ + +/** + * @brief Transposes a register base tile. + * + * @tparam T2 The data type of the register tile elements. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the register tile in which to store the transposed src. + * @param src[in] Reference to the register base tile to be transposed. + */ +template +__device__ static inline void transpose(rt_base &dst, const rt_base &src) { + swap_layout_8(dst.data[0], src.data[0]); + // technically this swap can be eliminated if we simply reinterpret the layout of the registers + // everywhere else in the code, but that feels... very likely to cause bugs and not worth it. + typename rt_base::T2 data1_cache = src.data[1]; // important for swap! + swap_layout_8(dst.data[1], src.data[2]); + swap_layout_8(dst.data[2], data1_cache); + swap_layout_8(dst.data[3], src.data[3]); +} +/** + * @brief Transposes a register tile. + * + * This function is marked "sep", which means that the registers underlying dst MUST be separate + * from the registers underlying src. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the src register tile, and the width of the dst tile. + * @tparam _width The width of the src register tile, and the height of the dst tile. + * @tparam layout The layout of the register tile. + * @param dst[out] Reference to the register tile in which to store the transposed src. + * @param src[in] Reference to the register tile to be transposed. + */ +template +__device__ static inline void transpose_sep(RT &dst, const rt &src) { + #pragma unroll + for(int i = 0; i < RT::height; i++) { + #pragma unroll + for(int j = 0; j < RT::width; j++) { + transpose(dst.tiles[i][j], src.tiles[j][i]); + } + } +} + +/** + * @brief Transposes a register base tile in-place. + * + * @tparam T2 The data type of the register base tile elements. + * @tparam layout The current layout of the register base tile. + * @param src[in] Reference to the register tile to be transposed. + * @return A reference to the transposed register base tile. + */ +template +__device__ static inline rt_base& transpose_inplace(rt_base &src) { + transpose(src, src); + return src; +} +/** + * @brief Transposes a square register tile in-place. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height (in units of 16) of the src register tile, and the width of the dst tile. (Must be the same as _width.) + * @tparam _width The width (in units of 16) of the src register tile, and the height of the dst tile. (Must be the same as _height.) + * @tparam layout The current layout of the register tile. + * @param src[in] Reference to the register tile to be transposed. + * @return A reference to the transposed register tile. + */ +template +__device__ static inline rt& transpose_inplace(rt &tile) { + static_assert(_cols == _rows, "in-place register tile transpose is only allowed for square tiles."); + #pragma unroll + for(int i = 0; i < tile.height; i++) { + #pragma unroll + for(int j = 0; j < i; j++) { + rt_base tmp; + copy(tmp, tile.tiles[i][j]); + transpose(tile.tiles[i][j], tile.tiles[j][i]); + transpose(tile.tiles[j][i], tmp); + } + transpose_inplace(tile.tiles[i][i]); + } + return tile; +} + +/* ---------- TYPE SWAPS ---------- */ + +/** + * @brief Copies a register base tile, converting the underlying type if necessary. + * + * @tparam T2 The data type of the destination register elements. + * @tparam U2 The data type of the source register elements. + * @tparam layout The current layout of the register base tile. + * @param[out] dst A reference to the destination register base tile. + * @param[in] src A reference to the source register base tile. + */ +template +__device__ static inline void copy(rt_base &dst, const rt_base &src) { + using T2 = typename base_types::packing::packed_type; + using U2 = typename base_types::packing::packed_type; + #pragma unroll + for(int k = 0; k < dst.packed_per_thread; k++) { + dst.data[k] = base_types::convertor::convert(src.data[k]); + } +} +#ifdef KITTENS_HOPPER +/** + * @brief Copies a register tile, converting the underlying type if necessary. + * + * @tparam T2 The data type of the destination register elements. + * @tparam U2 The data type of the source register elements. + * @tparam _height The height (in units of 16) of the register tiles. + * @tparam _width The width (in units of 16) of the register tiles. + * @tparam layout The current layout of the register tile. + * @param[out] dst A reference to the destination register tile. + * @param[in] src A reference to the source register tile. + */ +template +__device__ static inline void copy(rt &dst, const rt &src) { + + if constexpr ( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) + ) { + // FLOAT (SRC -- 1H x 2W) to FP8 (DST -- 1H x 1W) + int laneid = threadIdx.x % 32; + + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.tiles[0][0].packed_per_thread; k++) { + + // check for half, float, bf16 + using src_t = std::conditional_t, float2, std::conditional_t, bf16_2, half2>>; + src_t val1, val2; + + // Put something up for adoption + if (laneid % 2 == 0) { + // put up src left core matrix first as 0, 2 + val1 = src.tiles[i][2*j + k/2].data[(k%2)+0]; + val2 = src.tiles[i][2*j + k/2].data[(k%2)+2]; + } else { + // put up src right core matrix first as 1, 3 + val1 = src.tiles[i][2*j + k/2].data[(k%2)+2]; + val2 = src.tiles[i][2*j + k/2].data[(k%2)+0]; + } + + // Shuffle first 4 floats + int row_mask = 4 * ( laneid / 4 ); + int row_offset = row_mask + ( (laneid-row_mask) / 2 ) + ( laneid % 2 ); + int src_offset = (laneid % 2 == 0 ) ? row_offset + 0 : ( row_offset + 1 ); + src_t val01 = packed_shfl_sync(MASK_ALL, val1, src_offset); // Get from even thread + + int src_offset2 = (laneid % 4 < 2 ) ? src_offset + 1 : (src_offset - 1); + src_t val23 = packed_shfl_sync(MASK_ALL, val2, src_offset2); // Get from odd thread + + // Convert to fp8e4m3_4 + float4 f4; + using fp8_4_t = std::conditional_t, fp8e4m3_4, fp8e5m2_4>; + fp8_4_t f4_fp8; + if ( laneid % 4 < 2 ) { + f4.x = val01.x; // Thread 2N's first value + f4.y = val01.y; // Thread 2N's second value + f4.z = val23.x; // Thread 2N+1's first value + f4.w = val23.y; // Thread 2N+1's second value + f4_fp8 = base_types::convertor::convert(f4); + dst.tiles[i][j].data[k] = f4_fp8; + } else { + f4.x = val23.x; // Thread 2N+1's first value + f4.y = val23.y; // Thread 2N+1's second value + f4.z = val01.x; // Thread 2N's first value + f4.w = val01.y; // Thread 2N's second value + f4_fp8 = base_types::convertor::convert(f4); + dst.tiles[i][j].data[k] = f4_fp8; + } + } + } + } + } + else if constexpr ( + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v) + ) { + // FP8 (SRC -- 1H x 1W) to FLOAT (DST -- 1H x 2W) + int laneid = threadIdx.x % 32; + + #pragma unroll + for(int i = 0; i < src.height; i++) { + #pragma unroll + for(int j = 0; j < src.width; j++) { + #pragma unroll + for(int k = 0; k < src.tiles[0][0].packed_per_thread; k++) { + int dst_j = 2*j + k/2; + + // Put something up for adoption + using fp8_4_t = std::conditional_t, fp8e4m3_4, fp8e5m2_4>; + fp8_4_t val = src.tiles[i][j].data[k]; + float4 f4 = base_types::convertor::convert(val); + float2 f2_0, f2_1; + if ( laneid % 4 < 2 ) { // src 0 and 1 should put up .x and .y first + f2_0 = make_float2(f4.x, f4.y); + f2_1 = make_float2(f4.z, f4.w); + } + else { // src 2 and 3 should put up .z and .w first + f2_0 = make_float2(f4.z, f4.w); + f2_1 = make_float2(f4.x, f4.y); + } + + int row_offset = 4 * (laneid/4) + (laneid%2) * 2 + (laneid%4) / 2; + float2 f2_0_shfl = packed_shfl_sync(MASK_ALL, f2_0, row_offset); + float2 f2_1_shfl = packed_shfl_sync(MASK_ALL, f2_1, row_offset^2); + + // convert to dst type if needed + using dst_t = std::conditional_t, float2, std::conditional_t, bf16_2, half2>>; + if constexpr (!(std::is_same_v)) { + dst_t f2_0_shfl_t = base_types::convertor::convert(f2_0_shfl); + dst_t f2_1_shfl_t = base_types::convertor::convert(f2_1_shfl); + if (laneid % 2 == 0) { + dst.tiles[i][dst_j].data[(k%2)+0] = f2_0_shfl_t; + dst.tiles[i][dst_j].data[(k%2)+2] = f2_1_shfl_t; + } else { + dst.tiles[i][dst_j].data[(k%2)+0] = f2_1_shfl_t; + dst.tiles[i][dst_j].data[(k%2)+2] = f2_0_shfl_t; + } + } else { + if (laneid % 2 == 0) { + dst.tiles[i][dst_j].data[(k%2)+0] = f2_0_shfl; + dst.tiles[i][dst_j].data[(k%2)+2] = f2_1_shfl; + } else { + dst.tiles[i][dst_j].data[(k%2)+0] = f2_1_shfl; + dst.tiles[i][dst_j].data[(k%2)+2] = f2_0_shfl; + } + } + } + } + } + } + // default case where the layouts map 1:1 in thread ownership logic + else { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + copy(dst.tiles[i][j], src.tiles[i][j]); + } + } + } +} +#else +/** + * @brief Copies a register tile, converting the underlying type if necessary. + * + * @tparam T2 The data type of the destination register elements. + * @tparam U2 The data type of the source register elements. + * @tparam _height The height (in units of 16) of the register tiles. + * @tparam _width The width (in units of 16) of the register tiles. + * @tparam layout The current layout of the register tile. + * @param[out] dst A reference to the destination register tile. + * @param[in] src A reference to the source register tile. + */ +template +__device__ static inline void copy(rt &dst, const rt &src) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + copy(dst.tiles[i][j], src.tiles[i][j]); + } + } +} +#endif + +/* ---------- SUBTILE ---------- */ + +/** +* @brief Returns a reference to a subtile of the given tile. +* +* @tparam subtile_height The height of the subtile. +* @tparam RT The type of the input tile, which must satisfy the ducks::rt::all concept. +* @param src The input tile. +* @param idx The coord of the subtile. +* @return A reference to the subtile. +* +* @note The subtile height must evenly divide the tile height. +*/ +template +__device__ static inline rt &subtile_inplace(RT & src, int idx) { + KITTENS_CHECK_WARP + using T = typename RT::T; + static_assert(RT::height % (subtile_rows / TILE_ROW_DIM) == 0, "subtile height should evenly divide tile height."); + return reinterpret_cast&>( + src.tiles[idx*(subtile_rows / TILE_ROW_DIM)] + ); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/tile/maps.cuh b/extra/thunder/cuda/include/ops/group/register/tile/maps.cuh new file mode 100644 index 0000000000..c623aa6b67 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/tile/maps.cuh @@ -0,0 +1,836 @@ +/** + * @file + * @brief Map operations: between tiles, and those which apply vectors to tiles. + */ + +/* ---------- Uniform tile maps (independent of layout) ---------- */ + +/** + * @brief Applies a unary operation to each element of a tile. + * + * @tparam op Unary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + */ +template +__device__ static inline void unary_map(T &dst, const T &src) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k++) { + dst.tiles[i][j].data[k] = op::template op(src.tiles[i][j].data[k]); + } + } + } +} + +/** + * @brief Applies a binary operation to each element of a tile with a scalar parameter. + * + * @tparam op Binary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param param[in] Scalar parameter for the binary operation. + */ +template +__device__ static inline void bin_map(T &dst, const T &src, const typename T::dtype ¶m) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k++) { + dst.tiles[i][j].data[k] = op::template op(src.tiles[i][j].data[k], param); + } + } + } +} +/** + * @brief Applies a binary operation to each element of a tile with an unpacked scalar parameter. + * + * @tparam op Binary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param param[in] Unpacked scalar parameter for the binary operation. + */ +template +__device__ static inline void bin_map(T &dst, const T &src, const typename base_types::packing::unpacked_type ¶m) { + // The optimizing compiler should eliminate this pack in the 32-bit case but not in the 16-bit case + bin_map(dst, src, base_types::packing::pack(param)); +} +/** + * @brief Applies a binary operation element-wise between two tiles. + * + * @tparam op Binary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the operation. + * @param rhs[in] Right-hand side source tile for the operation. + */ +template +__device__ static inline void bin_map(T &dst, const T &lhs, const T &rhs) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k++) { + dst.tiles[i][j].data[k] = op::template op(lhs.tiles[i][j].data[k], rhs.tiles[i][j].data[k]); + } + } + } +} + +template +__device__ static inline void apply(RT &dst, const RT &src, Lambda &&lambda) { + int row_offset = 0; + if constexpr(GROUP_WARPS > 1) { + row_offset = warpid()*RT::height; + } + static_assert(sizeof(RT::T) != 1, "Cannot apply lambda to 8-bit types"); + if constexpr (ducks::rt::row_layout) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k++) { + int row = row_offset + i*TILE_ROW_DIM + (k%2) * (TILE_ROW_DIM/2) + ::kittens::laneid()/4; + int col = j*TILE_COL_DIM + (k/2) * (TILE_COL_DIM/2) + (::kittens::laneid()%4)*2; + dst.tiles[i][j].data[k].x = lambda(row, col+0, src.tiles[i][j].data[k].x); + dst.tiles[i][j].data[k].y = lambda(row, col+1, src.tiles[i][j].data[k].y); + } + } + } + } + else { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k++) { + int row = row_offset + i*TILE_ROW_DIM + (k/2) * (TILE_ROW_DIM/2) + (::kittens::laneid()%4)*2; + int col = j*TILE_COL_DIM + (k%2) * (TILE_COL_DIM/2) + ::kittens::laneid()/4; + dst.tiles[i][j].data[k].x = lambda(row+0, col, src.tiles[i][j].data[k].x); + dst.tiles[i][j].data[k].y = lambda(row+1, col, src.tiles[i][j].data[k].y); + } + } + } + } +} +template +__device__ static inline RT apply(const RT &src, Lambda &&lambda) { + RT dst; + apply(dst, src, std::forward(lambda)); + return dst; +} + +/* ---------- Row tile maps ----------*/ + +/** + * @brief Applies an operation across the rows of a tile in a row-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +__device__ static inline void row_map(T &dst, const T &src, const V &row_values) { + + static_assert(std::is_same_v::col_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::height); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int i = 0; i < dst.height; i++) { + dtype packed_top_row = base_types::packing::pack(row_values[i][0].x); // first value in eager mode + dtype packed_bottom_row = base_types::packing::pack(row_values[i][0].y); // second value in eager mode + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k+=2) { + dst.tiles[i][j].data[k+0] = op::template op(src.tiles[i][j].data[k+0], packed_top_row); + dst.tiles[i][j].data[k+1] = op::template op(src.tiles[i][j].data[k+1], packed_bottom_row); + } + } + } +} +/** + * @brief Applies an operation across the rows of a tile in a column-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with column-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +__device__ static inline void row_map(T &dst, const T &src, const V &row_values) { + + static_assert(std::is_same_v); // compatible type + static_assert(std::is_same_v::col_vec_layout>); // compatible layout + static_assert(V::outer_dim == T::height); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile/2; k++) { + dst.tiles[i][j].data[k+0] = op::template op(src.tiles[i][j].data[k+0], row_values[i][0]); + dst.tiles[i][j].data[k+2] = op::template op(src.tiles[i][j].data[k+2], row_values[i][1]); + } + } + } +} + + +// Three-operand row map. Mostly useful for FMA instructions. + +/** + * @brief Applies an operation across the rows of two tiles in a row-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +__device__ static inline void row_map(T &dst, const T &a, const T &b, const V &row_values) { + + static_assert(std::is_same_v::col_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::height); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int i = 0; i < dst.height; i++) { + dtype packed_top_row = base_types::packing::pack(row_values[i][0].x); // first value in eager mode + dtype packed_bottom_row = base_types::packing::pack(row_values[i][0].y); // second value in eager mode + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k+=2) { + dst.tiles[i][j].data[k+0] = op::template op(a.tiles[i][j].data[k+0], b.tiles[i][j].data[k+0], packed_top_row); + dst.tiles[i][j].data[k+1] = op::template op(a.tiles[i][j].data[k+1], b.tiles[i][j].data[k+1], packed_bottom_row); + } + } + } +} +/** + * @brief Applies an operation across the rows of two tiles in a column-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with column-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +__device__ static inline void row_map(T &dst, const T &a, const T &b, const V &row_values) { + + static_assert(std::is_same_v::col_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::height); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile/2; k++) { + dst.tiles[i][j].data[k+0] = op::template op(a.tiles[i][j].data[k+0], b.tiles[i][j].data[k+0], row_values[i][0]); + dst.tiles[i][j].data[k+2] = op::template op(a.tiles[i][j].data[k+2], b.tiles[i][j].data[k+2], row_values[i][1]); + } + } + } +} + +/* ---------- Col major tile maps ----------*/ + +/** + * @brief Applies an operation across the columns of a tile in a row-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +__device__ static inline void col_map(T &dst, const T &src, const V &col_values) { + KITTENS_CHECK_WARP + + static_assert(std::is_same_v::row_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::width); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile/2; k++) { + dst.tiles[i][j].data[k+0] = op::template op(src.tiles[i][j].data[k+0], col_values[j][0]); + dst.tiles[i][j].data[k+2] = op::template op(src.tiles[i][j].data[k+2], col_values[j][1]); + } + } + } +} +/** + * @brief Applies an operation across the columns of a tile in a column-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with column-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +__device__ static inline void col_map(T &dst, const T &src, const V &col_values) { + KITTENS_CHECK_WARP + + static_assert(std::is_same_v::row_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::width); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int j = 0; j < dst.width; j++) { + dtype packed_left_col = base_types::packing::pack(col_values[j][0].x); // first value in eager mode + dtype packed_right_col = base_types::packing::pack(col_values[j][0].y); // second value in eager mode + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k+=2) { + dst.tiles[i][j].data[k+0] = op::template op(src.tiles[i][j].data[k+0], packed_left_col); + dst.tiles[i][j].data[k+1] = op::template op(src.tiles[i][j].data[k+1], packed_right_col); + } + } + } +} + +// Three-operand col map +/** + * @brief Applies an operation across the columns of two tiles in a row-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +__device__ static inline void col_map(T &dst, const T &a, const T &b, const V &col_values) { + KITTENS_CHECK_WARP + + static_assert(std::is_same_v::row_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::width); // compatible size + + using dtype = T::dtype; + + #pragma unroll + for(int j = 0; j < dst.width; j++) { + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile/2; k++) { + dst.tiles[i][j].data[k+0] = op::template op(a.tiles[i][j].data[k+0], b.tiles[i][j].data[k+0], col_values[j][0]); + dst.tiles[i][j].data[k+2] = op::template op(a.tiles[i][j].data[k+2], b.tiles[i][j].data[k+2], col_values[j][1]); + } + } + } +} +/** + * @brief Applies an operation across the columns of two tiles in a column-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with column-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +__device__ static inline void col_map(T &dst, const T &a, const T &b, const V &col_values) { + KITTENS_CHECK_WARP + + static_assert(std::is_same_v); // compatible type + static_assert(std::is_same_v::row_vec_layout>); // compatible layout + static_assert(V::outer_dim == T::width); // compatible size + + using dtype = T::dtype; + #pragma unroll + for(int j = 0; j < dst.width; j++) { + dtype packed_left_col = base_types::packing::pack(col_values[j][0].x); // first value in eager mode + dtype packed_right_col = base_types::packing::pack(col_values[j][0].y); // second value in eager mode + #pragma unroll + for(int i = 0; i < dst.height; i++) { + #pragma unroll + for(int k = 0; k < dst.packed_per_tile; k+=2) { + dst.tiles[i][j].data[k+0] = op::template op(a.tiles[i][j].data[k+0], b.tiles[i][j].data[k+0], packed_left_col); + dst.tiles[i][j].data[k+1] = op::template op(a.tiles[i][j].data[k+1], b.tiles[i][j].data[k+1], packed_right_col); + } + } + } +} + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// All of the annoying qualifiers *should* be automatically inferred during compile-time. +// So, syntax should just be kittens::add_row(tile, colvec); + +/** + * @brief Sets all elements of a tile to zero. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +__device__ static inline void zero(T &dst) { + unary_map(dst, dst); +} +/** + * @brief Sets all elements of a tile to one. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +__device__ static inline void one(T &dst) { + unary_map(dst, dst); +} +/** + * @brief Sets all elements of a tile to positive infinity. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +__device__ static inline void pos_infty(T &dst) { + unary_map(dst, dst); +} +/** + * @brief Sets all elements of a tile to negative infinity. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +__device__ static inline void neg_infty(T &dst) { + unary_map(dst, dst); +} + +/** + * @brief Applies the exponential function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the exponential function on. + */ +template +__device__ static inline void exp(T &dst, const T &src) { + unary_map(dst, src); +} +template +__device__ static inline T exp(const T &src) { + T dst; + exp(dst, src); + return dst; +} + +/** + * @brief Applies the exponential function to each element of a tile, in base 2. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the exponential function on. + */ +template +__device__ static inline void exp2(T &dst, const T &src) { + unary_map(dst, src); +} +template +__device__ static inline T exp2(const T &src) { + T dst; + exp2(dst, src); + return dst; +} + +/** + * @brief Applies the natural logarithm function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the natural logarithm function on. + */ +template +__device__ static inline void log(T &dst, const T &src) { + unary_map(dst, src); +} +template +__device__ static inline T log(const T &src) { + T dst; + log(dst, src); + return dst; +} + +/** + * @brief Applies the logarithm base 2 function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the logarithm base 2 function on. + */ +template +__device__ static inline void log2(T &dst, const T &src) { + unary_map(dst, src); +} +template +__device__ static inline T log2(const T &src) { + T dst; + log2(dst, src); + return dst; +} + +/** + * @brief Applies the absolute value function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the absolute value function on. + */ +template +__device__ static inline void abs(T &dst, const T &src) { + unary_map(dst, src); +} +template +__device__ static inline T abs(const T &src) { + T dst; + abs(dst, src); + return dst; +} + +/** + * @brief Applies the rectified linear unit (ReLU) function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the ReLU function on. + */ +template +__device__ static inline void relu(T &dst, const T &src) { + unary_map(dst, src); +} +template +__device__ static inline T relu(const T &src) { + T dst; + relu(dst, src); + return dst; +} + +/** + * @brief Copies the elements from one tile to another. + * + * @tparam T Destination tile type. + * @tparam U Source tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to copy from. + */ +template +__device__ static inline void copy(T &dst, const U &src) { + bin_map(dst, src); +} + +/** + * @brief Applies the max operation element-wise between two tiles or a tile and a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the operation. + * @param rhs[in] Right-hand side source tile or scalar for the operation. + */ +template +__device__ static inline void max(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} +template +__device__ static inline T max(const T &lhs, const U &rhs) { + T dst; + max(dst, lhs, rhs); + return dst; +} + +/** + * @brief Applies the min operation element-wise between two tiles or a tile and a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the operation. + * @param rhs[in] Right-hand side source tile or scalar for the operation. + */ +template +__device__ static inline void min(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} +template +__device__ static inline T min(const T &lhs, const U &rhs) { + T dst; + min(dst, lhs, rhs); + return dst; +} + +/** + * @brief Adds two tiles element-wise or adds a scalar to each element of a tile. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the addition. + * @param rhs[in] Right-hand side source tile or scalar for the addition. + */ +template +__device__ static inline void add(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +/** + * @brief Subtracts two tiles element-wise or subtracts a scalar from each element of a tile. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the subtraction. + * @param rhs[in] Right-hand side source tile or scalar for the subtraction. + */ +template +__device__ static inline void sub(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} +/** + * @brief Multiplies two tiles element-wise or multiplies each element of a tile by a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the multiplication. + * @param rhs[in] Right-hand side source tile or scalar for the multiplication. + */ +template +__device__ static inline void mul(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +/** + * @brief Divides two tiles element-wise or divides each element of a tile by a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the division. + * @param rhs[in] Right-hand side source tile or scalar for the division. + */ +template +__device__ static inline void div(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +/** + * @brief Adds row values to each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param row_values[in] Column vector containing values to add to each row. + */ +template +__device__ static inline void add_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +/** + * @brief Subtracts row values from each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param row_values[in] Column vector containing values to subtract from each row. + */ +template +__device__ static inline void sub_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +/** + * @brief Multiplies each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param row_values[in] Column vector containing values to multiply each row by. + */ +template +__device__ static inline void mul_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +/** + * @brief Divides each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param row_values[in] Column vector containing values to divide each row by. + */ +template +__device__ static inline void div_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +/** + * @brief Broadcast a vector into into a tile's rows. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Column vector containing values to broadcast into rows. + */ +template +__device__ static inline void broadcast_row(T &dst, const V &row_values) { + row_map(dst, dst, row_values); +} +template +__device__ static inline T broadcast_row(const V &row_values) { + T dst; + broadcast_row(dst, row_values); + return dst; +} + + +// col maps +/** + * @brief Adds column values to each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param col_values[in] Row vector containing values to add to each column. + */ +template +__device__ static inline void add_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +/** + * @brief Subtracts column values from each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param col_values[in] Row vector containing values to subtract from each column. + */ +template +__device__ static inline void sub_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +/** + * @brief Multiplies each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param col_values[in] Row vector containing values to multiply each column by. + */ +template +__device__ static inline void mul_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +/** + * @brief Divides each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param col_values[in] Row vector containing values to divide each column by. + */ +template +__device__ static inline void div_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +/** + * @brief Broadcast a vector into into a tile's columns. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Row vector containing values to broadcast into cols. + */ +template +__device__ static inline void broadcast_col(T &dst, const V &col_values) { + col_map(dst, dst, col_values); +} +template +__device__ static inline T broadcast_col(const V &col_values) { + T dst; + broadcast_col(dst, col_values); + return dst; +} + +// Triangular masks +template +__device__ static inline void tril(RT &dst, const RT &src, int diagonal=0, const typename base_types::packing::unpacked_type &val=0) { + apply(dst, src, [val, diagonal]__device__(int row, int col, auto &src_val) { + return col <= row + diagonal ? src_val : val; + }); +} +template +__device__ static inline void triu(RT &dst, const RT &src, int diagonal=0, const typename base_types::packing::unpacked_type &val=0) { + apply(dst, src, [val, diagonal]__device__(int row, int col, auto &src_val) { + return col >= row + diagonal ? src_val : val; + }); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/tile/reductions.cuh b/extra/thunder/cuda/include/ops/group/register/tile/reductions.cuh new file mode 100644 index 0000000000..49efa39ab5 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/tile/reductions.cuh @@ -0,0 +1,554 @@ +/** + * @file + * @brief Reduction operations mapping tiles to vectors. + */ + +/** + * @brief Perform a row-wise reduction on a matrix in row-major layout. + * + * This function template performs a parallel reduction across the rows of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type with row layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +__device__ static inline void row_reduce(V &row_accum, const T &src, const V &src_accum) { + // I actually like these static asserts because they give more verbose errors when things go wrong. + static_assert(std::is_same_v::col_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::height); // compatible size + + using dtype = V::dtype; + + const int leader = threadIdx.x & 0x1C; // 11100 in binary + #pragma unroll + for(int i = 0; i < src.height; i++) { + dtype accum_top_row = op::template op(src.tiles[i][0].data[0], src.tiles[i][0].data[2]); + dtype accum_bottom_row = op::template op(src.tiles[i][0].data[1], src.tiles[i][0].data[3]); + #pragma unroll + for(int j = 1; j < src.width; j++) { + #pragma unroll + for(int k = 0; k < src.packed_per_tile; k+=2) { + accum_top_row = op::template op(accum_top_row, src.tiles[i][j].data[k+0]); + accum_bottom_row = op::template op(accum_bottom_row, src.tiles[i][j].data[k+1]); + } + } + dtype accum_packed; + accum_packed.x = op::template op::unpacked_type>(accum_top_row.x, accum_top_row.y); + accum_packed.y = op::template op::unpacked_type>(accum_bottom_row.x, accum_bottom_row.y); + + // Now we need to do a lil shuffle to make everyone happy. + + accum_packed = op::template op(accum_packed, packed_shfl_down_sync(MASK_ALL, accum_packed, 2)); + accum_packed = op::template op(accum_packed, packed_shfl_down_sync(MASK_ALL, accum_packed, 1)); + + accum_packed = packed_shfl_sync(MASK_ALL, accum_packed, leader); + + if(reset) { + row_accum[i][0] = accum_packed; + } + else { + row_accum[i][0] = op::template op(src_accum[i][0], accum_packed); + } + } +} +/** + * @brief Perform a row-wise reduction on a matrix in column-major layout. + * + * This function template performs a parallel reduction across the rows of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication and is optimized for column-major matrices. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type with column layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +__device__ static inline void row_reduce(V &row_accum, const T &src, const V &src_accum) { + // I actually like these static asserts because they give more verbose errors when things go wrong. + static_assert(std::is_same_v::col_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::height); // compatible size + + using dtype = V::dtype; + + const int leader = threadIdx.x & 0x3; // 00011 in binary + #pragma unroll + for(int i = 0; i < src.height; i++) { + dtype accum_top_rows = op::template op(src.tiles[i][0].data[0], src.tiles[i][0].data[1]); + dtype accum_bottom_rows = op::template op(src.tiles[i][0].data[2], src.tiles[i][0].data[3]); + #pragma unroll + for(int j = 1; j < src.width; j++) { + #pragma unroll + for(int k = 0; k < src.packed_per_tile/2; k++) { + accum_top_rows = op::template op(accum_top_rows, src.tiles[i][j].data[k+0]); + accum_bottom_rows = op::template op(accum_bottom_rows, src.tiles[i][j].data[k+2]); + } + } + + // Now we need to do a lil shuffle to make everyone happy. + + accum_top_rows = op::template op(accum_top_rows, packed_shfl_down_sync(MASK_ALL, accum_top_rows, 16)); + accum_top_rows = op::template op(accum_top_rows, packed_shfl_down_sync(MASK_ALL, accum_top_rows, 8)); + accum_top_rows = op::template op(accum_top_rows, packed_shfl_down_sync(MASK_ALL, accum_top_rows, 4)); + + accum_bottom_rows = op::template op(accum_bottom_rows, packed_shfl_down_sync(MASK_ALL, accum_bottom_rows, 16)); + accum_bottom_rows = op::template op(accum_bottom_rows, packed_shfl_down_sync(MASK_ALL, accum_bottom_rows, 8)); + accum_bottom_rows = op::template op(accum_bottom_rows, packed_shfl_down_sync(MASK_ALL, accum_bottom_rows, 4)); + + accum_top_rows = packed_shfl_sync(MASK_ALL, accum_top_rows, leader); + accum_bottom_rows = packed_shfl_sync(MASK_ALL, accum_bottom_rows, leader); + + if(reset) { + row_accum[i][0] = accum_top_rows; + row_accum[i][1] = accum_bottom_rows; + } + else { + row_accum[i][0] = op::template op(src_accum[i][0], accum_top_rows); + row_accum[i][1] = op::template op(src_accum[i][1], accum_bottom_rows); + } + } +} + +// Col reduction. +/** + * @brief Perform a column-wise reduction on a matrix in row-major layout. + * + * This function template performs a parallel reduction across the columns of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication and is optimized for row-major matrices. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the column accumulator. + * @tparam T The matrix type with row layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +__device__ static inline void col_reduce(V &col_accum, const T &src, const V &src_accum) { + // I actually like these static asserts because they give more verbose errors when things go wrong. + KITTENS_CHECK_WARP + static_assert(std::is_same_v::row_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::width); // compatible size + + using dtype = V::dtype; + + const int leader = threadIdx.x & 0x3; // 00011 in binary + #pragma unroll + for(int j = 0; j < src.width; j++) { + dtype accum_left_cols = op::template op(src.tiles[0][j].data[0], src.tiles[0][j].data[1]); + dtype accum_right_cols = op::template op(src.tiles[0][j].data[2], src.tiles[0][j].data[3]); + #pragma unroll + for(int i = 1; i < src.height; i++) { + #pragma unroll + for(int k = 0; k < src.packed_per_tile/2; k++) { + accum_left_cols = op::template op(accum_left_cols, src.tiles[i][j].data[k+0]); + accum_right_cols = op::template op(accum_right_cols, src.tiles[i][j].data[k+2]); + } + } + + // Now we need to do a lil shuffle to make everyone happy. + + accum_left_cols = op::template op(accum_left_cols, packed_shfl_down_sync(MASK_ALL, accum_left_cols, 16)); + accum_left_cols = op::template op(accum_left_cols, packed_shfl_down_sync(MASK_ALL, accum_left_cols, 8)); + accum_left_cols = op::template op(accum_left_cols, packed_shfl_down_sync(MASK_ALL, accum_left_cols, 4)); + + accum_right_cols = op::template op(accum_right_cols, packed_shfl_down_sync(MASK_ALL, accum_right_cols, 16)); + accum_right_cols = op::template op(accum_right_cols, packed_shfl_down_sync(MASK_ALL, accum_right_cols, 8)); + accum_right_cols = op::template op(accum_right_cols, packed_shfl_down_sync(MASK_ALL, accum_right_cols, 4)); + + accum_left_cols = packed_shfl_sync(MASK_ALL, accum_left_cols, leader); + accum_right_cols = packed_shfl_sync(MASK_ALL, accum_right_cols, leader); + + if(reset) { + col_accum[j][0] = accum_left_cols; + col_accum[j][1] = accum_right_cols; + } + else { + col_accum[j][0] = op::template op(src_accum[j][0], accum_left_cols); + col_accum[j][1] = op::template op(src_accum[j][1], accum_right_cols); + } + } +} +/** + * @brief Perform a column-wise reduction on a matrix in column-major layout. + * + * This function template performs a parallel reduction across the columns of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication and is optimized for column-major matrices. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the column accumulator. + * @tparam T The matrix type with column layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +__device__ static inline void col_reduce(V &col_accum, const T &src, const V &src_accum) { + // I actually like these static asserts because they give more verbose errors when things go wrong. + KITTENS_CHECK_WARP + static_assert(std::is_same_v::row_vec_layout>); // compatible layout + static_assert(std::is_same_v); // compatible type + static_assert(V::outer_dim == T::width); // compatible size + + using dtype = V::dtype; + const int leader = threadIdx.x & 0x1C; // 11100 in binary + #pragma unroll + for(int j = 0; j < src.width; j++) { // note now width is the outer loop + dtype accum_left_col = op::template op(src.tiles[0][j].data[0], src.tiles[0][j].data[2]); + dtype accum_right_col = op::template op(src.tiles[0][j].data[1], src.tiles[0][j].data[3]); + #pragma unroll + for(int i = 1; i < src.height; i++) { // and height is the inner loop + #pragma unroll + for(int k = 0; k < src.packed_per_tile; k+=2) { + accum_left_col = op::template op(accum_left_col, src.tiles[i][j].data[k+0]); + accum_right_col = op::template op(accum_right_col, src.tiles[i][j].data[k+1]); + } + } + dtype accum_packed; + accum_packed.x = op::template op::unpacked_type>(accum_left_col.x, accum_left_col.y); + accum_packed.y = op::template op::unpacked_type>(accum_right_col.x, accum_right_col.y); + + // Now we need to do a lil shuffle to make everyone happy. + + accum_packed = op::template op(accum_packed, packed_shfl_down_sync(MASK_ALL, accum_packed, 2)); + accum_packed = op::template op(accum_packed, packed_shfl_down_sync(MASK_ALL, accum_packed, 1)); + + accum_packed = packed_shfl_sync(MASK_ALL, accum_packed, leader); + + if(reset) { + col_accum[j][0] = accum_packed; + } + else { + col_accum[j][0] = op::template op(src_accum[j][0], accum_packed); + } + } +} + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// two-operand row reductions. (Accumulate and REPLACE.) +/** + * @brief Store the maximum of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_max(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +/** + * @brief Store the minimum of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_min(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +/** + * @brief Store the sum of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_sum(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +/** + * @brief Store the product of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_prod(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +// three-operand row reductions. (Accumulate ONTO.) +/** + * @brief Store the maximum of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_max(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} +/** + * @brief Store the minimum of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_min(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} +/** + * @brief Store the sum of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_sum(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} +/** + * @brief Store the product of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_prod(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} + +// two-operand col reductions. (Accumulate and REPLACE.) + +/** + * @brief Store the maximum of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_max(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +/** + * @brief Store the minimum of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_min(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +/** + * @brief Store the sum of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_sum(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +/** + * @brief Store the product of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_prod(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +// three-operand col reductions. (Accumulate ONTO.) +/** + * @brief Store the maximum of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_max(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} +/** + * @brief Store the minimum of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_min(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} +/** + * @brief Store the sum of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_sum(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} +/** + * @brief Store the product of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_prod(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} + +// templated versions of each + +template +__device__ static inline void max(RV &dst, const T &src, const RV &src_accum) { + if constexpr (ax == axis::COL) row_max(dst, src, src_accum); + else col_max(dst, src, src_accum); +} +template +__device__ static inline auto max(const T &src, const RV &src_accum) { + RV dst; + if constexpr (ax == axis::COL) row_max(dst, src, src_accum); + else col_max(dst, src, src_accum); + return dst; +} +template +__device__ static inline void max(RV &dst, const T &src) { + if constexpr (ax == axis::COL) row_max(dst, src); + else col_max(dst, src); +} +template +__device__ static inline auto max(const T &src) { + using RV = std::conditional_t; + RV dst; + if constexpr (ax == axis::COL) row_max(dst, src); + else col_max(dst, src); + return dst; +} + +template +__device__ static inline void min(RV &dst, const T &src, const RV &src_accum) { + if constexpr (ax == axis::COL) row_min(dst, src, src_accum); + else col_min(dst, src, src_accum); +} +template +__device__ static inline auto min(const T &src, const RV &src_accum) { + RV dst; + if constexpr (ax == axis::COL) row_min(dst, src, src_accum); + else col_min(dst, src, src_accum); + return dst; +} +template +__device__ static inline void min(RV &dst, const T &src) { + if constexpr (ax == axis::COL) row_min(dst, src); + else col_min(dst, src); +} +template +__device__ static inline auto min(const T &src) { + using RV = std::conditional_t; + RV dst; + if constexpr (ax == axis::COL) row_min(dst, src); + else col_min(dst, src); + return dst; +} + +template +__device__ static inline void sum(RV &dst, const T &src, const RV &src_accum) { + if constexpr (ax == axis::COL) row_sum(dst, src, src_accum); + else col_sum(dst, src, src_accum); +} +template +__device__ static inline auto sum(const T &src, const RV &src_accum) { + RV dst; + if constexpr (ax == axis::COL) row_sum(dst, src, src_accum); + else col_sum(dst, src, src_accum); + return dst; +} +template +__device__ static inline void sum(RV &dst, const T &src) { + if constexpr (ax == axis::COL) row_sum(dst, src); + else col_sum(dst, src); +} +template +__device__ static inline auto sum(const T &src) { + using RV = std::conditional_t; + RV dst; + if constexpr (ax == axis::COL) row_sum(dst, src); + else col_sum(dst, src); + return dst; +} + +template +__device__ static inline void prod(RV &dst, const T &src, const RV &src_accum) { + if constexpr (ax == axis::COL) row_prod(dst, src, src_accum); + else col_prod(dst, src, src_accum); +} +template +__device__ static inline auto prod(const T &src, const RV &src_accum) { + RV dst; + if constexpr (ax == axis::COL) row_prod(dst, src, src_accum); + else col_prod(dst, src, src_accum); + return dst; +} +template +__device__ static inline void prod(RV &dst, const T &src) { + if constexpr (ax == axis::COL) row_prod(dst, src); + else col_prod(dst, src); +} +template +__device__ static inline auto prod(const T &src) { + using RV = std::conditional_t; + RV dst; + if constexpr (ax == axis::COL) row_prod(dst, src); + else col_prod(dst, src); + return dst; +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/tile/tile.cuh b/extra/thunder/cuda/include/ops/group/register/tile/tile.cuh new file mode 100644 index 0000000000..1ddbaf4380 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/tile/tile.cuh @@ -0,0 +1,47 @@ +/** + * @file + * @brief An aggregate header for warp operations on register tiles. + */ + +#include "conversions.cuh" +#include "maps.cuh" +#include "reductions.cuh" + +template +__device__ static inline bool hasnan(const RT &src) { + KITTENS_CHECK_WARP + bool nan_detected = false; + #pragma unroll + for(int i = 0; i < RT::height; i++) { + #pragma unroll + for(int j = 0; j < RT::width; j++) { + #pragma unroll + for(int k = 0; k < RT::packed_per_tile; k++) { + if constexpr (std::is_same_v) { + if(isnan(src.tiles[i][j].data[k].x) || isnan(src.tiles[i][j].data[k].y)) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__bfloat162float(src.tiles[i][j].data[k].x)) || isnan(__bfloat162float(src.tiles[i][j].data[k].y))) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__half2float(src.tiles[i][j].data[k].x)) || isnan(__half2float(src.tiles[i][j].data[k].y))) { + nan_detected = true; + } + } + else { + static_assert(sizeof(typename RT::T) == 999, "Unsupported dtype"); + } + } + } + } + // Ballot across the warp to see if any lane detected a nan + return (__ballot_sync(0xffffffff, nan_detected) != 0); +} + +#include "complex/complex_conversions.cuh" +#include "complex/complex_maps.cuh" + diff --git a/extra/thunder/cuda/include/ops/group/register/vec/conversions.cuh b/extra/thunder/cuda/include/ops/group/register/vec/conversions.cuh new file mode 100644 index 0000000000..3bc7177e17 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/vec/conversions.cuh @@ -0,0 +1,153 @@ +/** + * @file + * @brief Conversions on vectors stored in registers. + */ + +struct vec_conversion_detail { + +// i am not smart enough to figure out these indices without these helpers :/ +// again, blame nvidia for these stupid, stupid layouts +__device__ static inline int row_from_indices_dim2(int laneid, int inner_dim, int x_or_y) { + return 8*inner_dim + (laneid%4)*2 + x_or_y; +} +__device__ static inline int row_from_indices_dim1(int laneid, int x_or_y) { + return 8*x_or_y + (laneid/4); +} +__device__ static inline int canonical_src_lane_dim2(int row) { + return (row/2)%4 + 4*(row%2); // draw even rows from 0...3 and odds from 4...7 +} +__device__ static inline int canonical_src_lane_dim1(int row) { + return (row*4)%32; +} + +}; + +/** + * @brief Copies data from one register vector to another. + * + * @tparam RV1 The type of the destination register vector. + * @tparam RV2 The type of the source register vector. + * @param dst[out] The destination register vector. + * @param src[in] The source register vector to copy from. + */ +template +__device__ static inline void copy(RV1 &dst, const RV2 &src) { + KITTENS_CHECK_WARP + static_assert(RV1::length == RV2::length, "Register vectors must be the same length."); + using D1 = RV1::dtype; + using D2 = RV2::dtype; + if constexpr (std::is_same_v) { // just a simple copy / typecast + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + #pragma unroll + for(int j = 0; j < RV1::inner_dim; j++) { + dst[i][j] = base_types::convertor::convert(src[i][j]); + } + } + } + else { // Inner dimensions are not the same, this is really a layout conversion. + int laneid = ::kittens::laneid(); + if constexpr (std::is_same_v && std::is_same_v) { // align -> ortho layout + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + dst[i][0].x = packed_shfl_sync( + kittens::MASK_ALL, + laneid < 4 ? src[i][0].x : src[i][0].y, // mirrors canonical_src_lane_dim2 + vec_conversion_detail::canonical_src_lane_dim2(vec_conversion_detail::row_from_indices_dim1(laneid, 0)) + ); + dst[i][0].y = packed_shfl_sync( + kittens::MASK_ALL, + laneid < 4 ? src[i][1].x : src[i][1].y, // mirrors canonical_src_lane_dim2 + vec_conversion_detail::canonical_src_lane_dim2(vec_conversion_detail::row_from_indices_dim1(laneid, 1)) + ); + } + } + else if constexpr (std::is_same_v && std::is_same_v) { // ortho -> align layout + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + dst[i][0].x = packed_shfl_sync( + kittens::MASK_ALL, + src[i][0].x, // first 8 rows + vec_conversion_detail::canonical_src_lane_dim1(vec_conversion_detail::row_from_indices_dim2(laneid, 0, 0)) + ); + dst[i][0].y = packed_shfl_sync( + kittens::MASK_ALL, + src[i][0].x, // first 8 rows + vec_conversion_detail::canonical_src_lane_dim1(vec_conversion_detail::row_from_indices_dim2(laneid, 0, 1)) + ); + dst[i][1].x = packed_shfl_sync( + kittens::MASK_ALL, + src[i][0].y, // last 8 rows + vec_conversion_detail::canonical_src_lane_dim1(vec_conversion_detail::row_from_indices_dim2(laneid, 1, 0)) + ); + dst[i][1].y = packed_shfl_sync( + kittens::MASK_ALL, + src[i][0].y, // last 8 rows + vec_conversion_detail::canonical_src_lane_dim1(vec_conversion_detail::row_from_indices_dim2(laneid, 1, 1)) + ); + } + } + else if constexpr (std::is_same_v && std::is_same_v) { // naive -> ortho layout + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + dst[i][0].x = packed_shfl_sync( + kittens::MASK_ALL, src[i/2][0], + 16*(i%2) + 0 + (laneid/4) + ); + dst[i][0].y = packed_shfl_sync( + kittens::MASK_ALL, src[i/2][0], + 16*(i%2) + 8 + (laneid/4) + ); + } + } + else if constexpr (std::is_same_v && std::is_same_v) { // ortho -> naive layout + int lane_replication = laneid%4; // 0...3 + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + D1 tmp = 0; + if(RV1::length%32==0 || i < RV1::outer_dim-1 || lane_replication<2) { + tmp = lane_replication%2 ? src[2*i + (lane_replication>=2)][0].y : src[2*i + (lane_replication>=2)][0].x; + } + dst[i][0] = packed_shfl_sync( + kittens::MASK_ALL, tmp, + (laneid%8)*4 + (laneid/8) + ); + } + } + else if constexpr (std::is_same_v && std::is_same_v) { // naive -> align layout + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + dst[i][0].x = packed_shfl_sync( + kittens::MASK_ALL, src[i/2][0], + 16*(i%2) + 0 + 2*(laneid%4) + 0 + ); + dst[i][0].y = packed_shfl_sync( + kittens::MASK_ALL, src[i/2][0], + 16*(i%2) + 0 + 2*(laneid%4) + 1 + ); + dst[i][1].x = packed_shfl_sync( + kittens::MASK_ALL, src[i/2][0], + 16*(i%2) + 8 + 2*(laneid%4) + 0 + ); + dst[i][1].y = packed_shfl_sync( + kittens::MASK_ALL, src[i/2][0], + 16*(i%2) + 8 + 2*(laneid%4) + 1 + ); + } + } + else if constexpr (std::is_same_v && std::is_same_v) { // align -> naive layout + int lane_replication = laneid/8; // 0...3 + #pragma unroll + for(int i = 0; i < RV1::outer_dim; i++) { + D1 tmp = 0; + if(RV1::length%32==0 || i < RV1::outer_dim-1 || laneid<16) { + tmp = (laneid%8)<4 ? src[2*i + (lane_replication>=2)][lane_replication%2].x : src[2*i + (lane_replication>=2)][lane_replication%2].y; + } + dst[i][0] = packed_shfl_sync( + kittens::MASK_ALL, tmp, + 4*(laneid%2) + (laneid%8)/2 + (laneid&0b11000) + ); + } + } + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/vec/maps.cuh b/extra/thunder/cuda/include/ops/group/register/vec/maps.cuh new file mode 100644 index 0000000000..fb0ccbc3c2 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/vec/maps.cuh @@ -0,0 +1,374 @@ +/** + * @file + * @brief Maps on vectors stored in registers. + */ + +/* ---------- Vector Maps ---------- */ + +/** + * @brief Perform a unary operation on a vector. + * + * @tparam op The unary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector to perform the operation on. + */ +template +__device__ static inline void unary_op(T &dst, const T &src) { + #pragma unroll + for(int i = 0; i < dst.outer_dim; i++) { + #pragma unroll + for(int j = 0; j < dst.inner_dim; j++) { + dst[i][j] = op::template op(src[i][j]); + } + } +} +/** + * @brief Perform a binary operation on two vectors. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vectors. + * @param dst[out] The destination vector where the result is stored. + * @param lhs[in] The left-hand side vector for the operation. + * @param rhs[in] The right-hand side vector for the operation. + */ +template +__device__ static inline void bin_op(T &dst, const T &lhs, const T &rhs) { + #pragma unroll + for(int i = 0; i < dst.outer_dim; i++) { + #pragma unroll + for(int j = 0; j < dst.inner_dim; j++) { + dst[i][j] = op::template op(lhs[i][j], rhs[i][j]); + } + } +} +/** + * @brief Perform a binary operation on a vector and a scalar. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector for the operation. + * @param param[in] The scalar parameter for the operation. + */ +template +__device__ static inline void bin_op(T &dst, const T &src, const typename T::dtype ¶m) { + #pragma unroll + for(int i = 0; i < dst.outer_dim; i++) { + #pragma unroll + for(int j = 0; j < dst.inner_dim; j++) { + dst[i][j] = op::template op(src[i][j], param); + } + } +} +/** + * @brief Perform a binary operation on a vector and an unpacked scalar. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector for the operation. + * @param param[in] The unpacked scalar parameter for the operation. + */ +template +__device__ static inline void bin_op(T &dst, const T &src, const typename base_types::packing::unpacked_type ¶m) { + bin_op(dst, src, base_types::packing::pack(param)); +} + + +template +__device__ static inline void apply(RV &dst, const RV &src, Lambda &&lambda) { + int group_offset = 0; + if constexpr(GROUP_WARPS > 1) { + group_offset = warpid()*RV::length; + } + static_assert(sizeof(RV::T) != 1, "Cannot apply lambda to 8-bit types"); + if constexpr (ducks::rv::ortho_layout) { + #pragma unroll + for(int i = 0; i < dst.outer_dim; i++) { + int base_idx = group_offset + i*16 + ::kittens::laneid()/4; + dst[i][0].x = lambda(base_idx+0, src[i][0].x); + dst[i][0].y = lambda(base_idx+8, src[i][0].y); + } + } + else if constexpr (ducks::rv::align_layout) { + #pragma unroll + for(int i = 0; i < dst.outer_dim; i++) { + int base_idx = group_offset + i*16 + 2*(::kittens::laneid()%4); + dst[i][0].x = lambda(base_idx+0, src[i][0].x); + dst[i][0].y = lambda(base_idx+1, src[i][0].y); + dst[i][1].x = lambda(base_idx+8, src[i][1].x); + dst[i][1].y = lambda(base_idx+9, src[i][1].y); + } + } + else { + #pragma unroll + for(int i = 0; i < dst.outer_dim; i++) { + int base_idx = group_offset + i*32 + ::kittens::laneid(); + if (i < dst.outer_dim-1 || dst.length%32 == 0 || ::kittens::laneid()<16) { + dst[i][0] = lambda(base_idx, src[i][0]); + } + } + } +} +template +__device__ static inline RV apply(const RV &src, Lambda &&lambda) { + RV dst; + apply(dst, src, std::forward(lambda)); + return dst; +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// ---- const ops ---- + +/** + * @brief Sets all elements of a register vector to zero. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to zero. + */ +template +__device__ static inline void zero(T &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a register vector to one. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to one. + */ +template +__device__ static inline void one(T &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a register vector to positive infinity. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to positive infinity. + */ +template +__device__ static inline void pos_infty(T &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a register vector to negative infinity. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to negative infinity. + */ +template +__device__ static inline void neg_infty(T &dst) { + unary_op(dst, dst); +} + +// ---- unary ops ---- + +/** + * @brief Copies the elements from one register vector to another. + * + * @tparam T Register vector type. + * @tparam U Type of the source vector. + * @param dst[out] Destination vector where the elements will be copied to. + * @param src[in] Source vector to copy the elements from. + */ +template +__device__ static inline void copy(T &dst, const U &src) { + bin_op(dst, dst, src); // the second arg is ignored here. +} +/** + * @brief Applies the exponential function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +__device__ static inline void exp(T &dst, const T &src) { + unary_op(dst, src); +} +template +__device__ static inline T exp(const T &src) { + T dst; + exp(dst, src); + return dst; +} +/** + * @brief Applies the exponential function element-wise to a register vector, in base 2. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +__device__ static inline void exp2(T &dst, const T &src) { + unary_op(dst, src); +} +template +__device__ static inline T exp2(const T &src) { + T dst; + exp2(dst, src); + return dst; +} +/** + * @brief Applies the natural logarithm function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +__device__ static inline void log(T &dst, const T &src) { + unary_op(dst, src); +} +template +__device__ static inline T log(const T &src) { + T dst; + log(dst, src); + return dst; +} +/** + * @brief Applies the logarithm base 2 function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the logarithm base 2 function to. + */ +template +__device__ static inline void log2(T &dst, const T &src) { + unary_op(dst, src); +} +template +__device__ static inline T log2(const T &src) { + T dst; + log2(dst, src); + return dst; +} +/** + * @brief Applies the absolute value function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the absolute values will be stored. + * @param src[in] Source vector to apply the absolute value function to. + */ +template +__device__ static inline void abs(T &dst, const T &src) { + unary_op(dst, src); +} +template +__device__ static inline T abs(const T &src) { + T dst; + abs(dst, src); + return dst; +} +/** + * @brief Applies the rectified linear unit (ReLU) function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the ReLU values will be stored. + * @param src[in] Source vector to apply the ReLU function to. + */ +template +__device__ static inline void relu(T &dst, const T &src) { + unary_op(dst, src); +} +template +__device__ static inline T relu(const T &src) { + T dst; + relu(dst, src); + return dst; +} + +// ---- binary ops ---- + +/** + * @brief Computes the element-wise maximum of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the maximum values will be stored. + * @param lhs[in] First vector for the maximum operation. + * @param rhs[in] Second vector for the maximum operation. + */ +template +__device__ static inline void max(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +template +__device__ static inline T max(const T &lhs, const U &rhs) { + T dst; + max(dst, lhs, rhs); + return dst; +} +/** + * @brief Computes the element-wise minimum of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the minimum values will be stored. + * @param lhs[in] First vector for the minimum operation. + * @param rhs[in] Second vector for the minimum operation. + */ +template +__device__ static inline void min(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +template +__device__ static inline T min(const T &lhs, const U &rhs) { + T dst; + min(dst, lhs, rhs); + return dst; +} +/** + * @brief Computes the element-wise sum of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the sum values will be stored. + * @param lhs[in] First vector for the sum operation. + * @param rhs[in] Second vector for the sum operation. + */ +template +__device__ static inline void add(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise difference of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the difference values will be stored. + * @param lhs[in] First vector for the difference operation. + * @param rhs[in] Second vector for the difference operation. + */ +template +__device__ static inline void sub(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise product of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the product values will be stored. + * @param lhs[in] First vector for the product operation. + * @param rhs[in] Second vector for the product operation. + */ +template +__device__ static inline void mul(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise division of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the division values will be stored. + * @param lhs[in] First vector for the division operation. + * @param rhs[in] Second vector for the division operation. + */ +template +__device__ static inline void div(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/vec/reductions.cuh b/extra/thunder/cuda/include/ops/group/register/vec/reductions.cuh new file mode 100644 index 0000000000..f9ae971924 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/vec/reductions.cuh @@ -0,0 +1,233 @@ +/** + * @file + * @brief Reductions on vectors stored in registers. + */ + +/* ---------- Vector Reductions ---------- */ + +/** + * @brief Performs a reduction operation on elements of a register vector within a warp. + * + * This function applies a specified operation to reduce the elements of a register vector `src` to a single value. + * The result is stored in `accum`. If the `reset` parameter is true, the reduction includes an initial value `src_accum`. + * The reduction operation is performed in a warp-wide context, ensuring synchronization between threads in the warp. + * + * @tparam op The operation to perform on the elements. Must provide a static `op` method. + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @tparam reset A boolean flag indicating whether to include an initial value in the reduction. + * @param[out] accum The result of the reduction operation. + * @param[in] src The register vector to reduce. + * @param[in] src_accum The initial value to include in the reduction if `reset` is false. + */ +template +__device__ static inline void reduce( + typename base_types::packing::unpacked_type &dst_accum, + const RV &src, + const typename base_types::packing::unpacked_type &src_accum) { + KITTENS_CHECK_WARP + using T = base_types::packing::unpacked_type; + int laneid = kittens::laneid(); + if constexpr (std::is_same_v) { + T accum = op::template op(src[0][0].x, src[0][0].y); + #pragma unroll + for(int i = 1; i < src.outer_dim; i++) { + accum = op::template op(accum, src[i][0].x); + accum = op::template op(accum, src[i][0].y); + } + // we've now reduced everything into 8 distinct values, replicated across lanes x, x+1, x+2, x+3 for x≡0(mod4) + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 16)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 8)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 4)); + // we've now reduced everything into 1 distinct value, replicated across lanes 0, 1, 2, 3 + if constexpr (!reset) accum = op::template op(accum, src_accum); + // final result has now been achieved (incorporating src_accum if necessary), finally broadcast back to all threads. + dst_accum = packed_shfl_sync(kittens::MASK_ALL, accum, 0); + } + else if constexpr (std::is_same_v) { + T accum = op::template op(src[0][0].x, src[0][0].y); + accum = op::template op(accum, src[0][1].x); + accum = op::template op(accum, src[0][1].y); + #pragma unroll + for(int i = 1; i < src.outer_dim; i++) { + // it is possible that shfl_sync's would be faster but I doubt it, replication is likely better. Certainly simpler. + accum = op::template op(accum, src[i][0].x); + accum = op::template op(accum, src[i][0].y); + accum = op::template op(accum, src[i][1].x); + accum = op::template op(accum, src[i][1].y); + } + // we've now reduced everything into 4 distinct values, replicated across lanes x, x+4, x+8, ..., x+28 for x<4 + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 2)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 1)); + // we've now reduced everything into 1 distinct value, replicated across lanes 0, 4, 8, 12, ..., 28 + if constexpr (!reset) accum = op::template op(accum, src_accum); + // final result has now been achieved (incorporating src_accum if necessary), finally broadcast back to all threads from lane 0 + dst_accum = packed_shfl_sync(kittens::MASK_ALL, accum, 0); + } + else if constexpr (std::is_same_v) { + T accum = src[0][0]; + #pragma unroll + for(int i = 1; i < src.outer_dim; i++) { + if (i < src.outer_dim-1 || i*kittens::TILE_ROW_DIM*2 + laneid < src.length) { + accum = op::template op(accum, src[i][0]); + } + } + if(src.length > 16) accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 16)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 8)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 4)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 2)); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 1)); + if constexpr (!reset) accum = op::template op(accum, src_accum); + dst_accum = packed_shfl_sync(kittens::MASK_ALL, accum, 0); + } +} + + +/** + * @brief Finds the maximum element in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] max_val The maximum value found in the vector. + * @param[in] src The register vector to find the maximum in. + */ +template +__device__ static inline void max(typename base_types::packing::unpacked_type &max_val, const RV &src) { + reduce(max_val, src, max_val); +} +template +__device__ static inline typename base_types::packing::unpacked_type max(const RV &src) { + typename base_types::packing::unpacked_type max_val; + reduce(max_val, src, max_val); + return max_val; +} + +/** + * @brief Finds the minimum element in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] min_val The minimum value found in the vector. + * @param[in] src The register vector to find the minimum in. + */ +template +__device__ static inline void min(typename base_types::packing::unpacked_type &min_val, const RV &src) { + reduce(min_val, src, min_val); +} +template +__device__ static inline typename base_types::packing::unpacked_type min(const RV &src) { + typename base_types::packing::unpacked_type min_val; + reduce(min_val, src, min_val); + return min_val; +} + +/** + * @brief Calculates the sum of elements in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] sum_val The sum of the values in the vector. + * @param[in] src The register vector to sum. + */ +template +__device__ static inline void sum(typename base_types::packing::unpacked_type &sum_val, const RV &src) { + reduce(sum_val, src, sum_val); +} +template +__device__ static inline typename base_types::packing::unpacked_type sum(const RV &src) { + typename base_types::packing::unpacked_type sum_val; + reduce(sum_val, src, sum_val); + return sum_val; +} + +/** + * @brief Calculates the product of elements in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] prod_val The product of the values in the vector. + * @param[in] src The register vector to multiply. + */ +template +__device__ static inline void prod(typename base_types::packing::unpacked_type &prod_val, const RV &src) { + reduce(prod_val, src, prod_val); +} +template +__device__ static inline typename base_types::packing::unpacked_type prod(const RV &src) { + typename base_types::packing::unpacked_type prod_val; + reduce(prod_val, src, prod_val); + return prod_val; +} + +// Three operand versions. + +/** + * @brief Finds the maximum element in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] max_val The maximum value found in the vector, accumulated with src_accum. + * @param[in] src The register vector to find the maximum in. + * @param[in] src_accum The initial value to accumulate with the maximum value found. + */ +template +__device__ static inline void max(typename base_types::packing::unpacked_type &max_val, const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + reduce(max_val, src, src_accum); +} +template +__device__ static inline typename base_types::packing::unpacked_type max(const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + typename base_types::packing::unpacked_type max_val; + reduce(max_val, src, src_accum); + return max_val; +} + +/** + * @brief Finds the minimum element in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] min_val The minimum value found in the vector, accumulated with src_accum. + * @param[in] src The register vector to find the minimum in. + * @param[in] src_accum The initial value to accumulate with the minimum value found. + */ +template +__device__ static inline void min(typename base_types::packing::unpacked_type &min_val, const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + reduce(min_val, src, src_accum); +} +template +__device__ static inline typename base_types::packing::unpacked_type min(const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + typename base_types::packing::unpacked_type min_val; + reduce(min_val, src, src_accum); + return min_val; +} + +/** + * @brief Calculates the sum of elements in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] sum_val The sum of the values in the vector, accumulated with src_accum. + * @param[in] src The register vector to sum. + * @param[in] src_accum The initial value to accumulate with the sum of the vector. + */ +template +__device__ static inline void sum(typename base_types::packing::unpacked_type &sum_val, const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + reduce(sum_val, src, src_accum); +} +template +__device__ static inline typename base_types::packing::unpacked_type sum(const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + typename base_types::packing::unpacked_type sum_val; + reduce(sum_val, src, src_accum); + return sum_val; +} + +/** + * @brief Calculates the product of elements in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] prod_val The product of the values in the vector, accumulated with src_accum. + * @param[in] src The register vector to multiply. + * @param[in] src_accum The initial value to accumulate with the product of the vector. + */ +template +__device__ static inline void prod(typename base_types::packing::unpacked_type &prod_val, const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + reduce(prod_val, src, src_accum); +} +template +__device__ static inline typename base_types::packing::unpacked_type prod(const RV &src, const typename base_types::packing::unpacked_type &src_accum) { + typename base_types::packing::unpacked_type prod_val; + reduce(prod_val, src, src_accum); + return prod_val; +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/register/vec/vec.cuh b/extra/thunder/cuda/include/ops/group/register/vec/vec.cuh new file mode 100644 index 0000000000..cd5f9d35ee --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/register/vec/vec.cuh @@ -0,0 +1,59 @@ +/** + * @file + * @brief An aggregate header for warp operations on register vectors. + */ + +#include "conversions.cuh" +#include "maps.cuh" +#include "reductions.cuh" + +template +__device__ static inline bool hasnan(const RV &src) { + KITTENS_CHECK_WARP + bool nan_detected = false; + #pragma unroll + for(int i = 0; i < RV::outer_dim; i++) { + #pragma unroll + for(int j = 0; j < RV::inner_dim; j++) { + if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + if(isnan(src[i][j].x) || isnan(src[i][j].y)) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__bfloat162float(src[i][j].x)) || isnan(__bfloat162float(src[i][j].y))) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__half2float(src[i][j].x)) || isnan(__half2float(src[i][j].y))) { + nan_detected = true; + } + } + } + else if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + if(isnan(src[i][j])) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__bfloat162float(src[i][j]))) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__half2float(src[i][j]))) { + nan_detected = true; + } + } + } + else { + static_assert(sizeof(typename RV::dtype) == 999, "Unsupported dtype"); + } + } + } + // Ballot across the warp to see if any lane detected a nan + return (__ballot_sync(0xffffffff, nan_detected) != 0); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/shared.cuh b/extra/thunder/cuda/include/ops/group/shared/shared.cuh new file mode 100644 index 0000000000..6558b07f15 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/shared.cuh @@ -0,0 +1,7 @@ +/** + * @file + * @brief An aggregate header of group operations on data in shared memory + */ + +#include "tile/tile.cuh" +#include "vec/vec.cuh" \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/tile/conversions.cuh b/extra/thunder/cuda/include/ops/group/shared/tile/conversions.cuh new file mode 100644 index 0000000000..95c614b23a --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/tile/conversions.cuh @@ -0,0 +1,16 @@ +/** + * @file + * @brief Group conversions between different shared memory tile types. + */ + +/* ---------- COPIES ---------- */ + +template +__device__ static inline void copy(ST1 &dst, const ST2 &src) { + static_assert(ST1::height == ST2::height && ST1::width == ST2::width, "Tiles must have the same height and width"); + #pragma unroll + for(int i = laneid(); i < dst.num_elements; i+=GROUP_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = base_types::convertor::convert(src[{row, col}]); + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/tile/maps.cuh b/extra/thunder/cuda/include/ops/group/shared/tile/maps.cuh new file mode 100644 index 0000000000..b0b7330944 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/tile/maps.cuh @@ -0,0 +1,236 @@ +/** + * @file + * @brief Group maps on shared tiles. + */ + + +template // T2, w, h can be inferred from dst as long as op is specialized +__device__ static inline void unary_map(T &dst, const T &src) { + #pragma unroll + for(int i = laneid(); i < dst.num_elements; i += GROUP_THREADS) { + dst.data[i] = op::template op(src.data[i]); + } +} + +template +__device__ static inline void bin_map(T &dst, const T &src, const typename T::dtype ¶m) { + #pragma unroll + for(int i = laneid(); i < dst.num_elements; i += GROUP_THREADS) { + dst.data[i] = op::template op(src.data[i], param); + } +} + +template +__device__ static inline void bin_map(T &dst, const T &lhs, const T &rhs) { + #pragma unroll + for(int i = laneid(); i < dst.num_elements; i += GROUP_THREADS) { + dst.data[i] = op::template op(lhs.data[i], rhs.data[i]); + } +} + +template +__device__ static inline void row_map(T &dst, const T &src, const V &vec) { + static_assert(std::is_same::value, "Tile and vector must have the same data type"); + static_assert(V::length == T::rows, "Vector length must match the number of rows in the tile"); + #pragma unroll + for(int i = laneid(); i < dst.num_elements; i += GROUP_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = op::template op(src[{row, col}], vec[row]); + } +} + +template +__device__ static inline void col_map(T &dst, const T &src, const V &vec) { + static_assert(std::is_same::value, "Tile and vector must have the same data type"); + static_assert(V::length == T::cols, "Vector length must match the number of columns in the tile"); + #pragma unroll + for(int i = laneid(); i < dst.num_elements; i += GROUP_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = op::template op(src[{row, col}], vec[col]); + } +} + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// All of the annoying qualifiers *should* be automatically inferred during compile-time. +// So, syntax should just be kittens::add_row(tile, colvec); + +// const maps + +template +__device__ static inline void zero(T &dst) { + unary_map(dst, dst); +} + +template +__device__ static inline void one(T &dst) { + unary_map(dst, dst); +} + +template +__device__ static inline void pos_infty(T &dst) { + unary_map(dst, dst); +} + +template +__device__ static inline void neg_infty(T &dst) { + unary_map(dst, dst); +} + +// unary maps + +template +__device__ static inline void exp(T &dst, const T &src) { + unary_map(dst, src); +} + +template +__device__ static inline void exp2(T &dst, const T &src) { + unary_map(dst, src); +} + +template +__device__ static inline void log(T &dst, const T &src) { + unary_map(dst, src); +} + +template +__device__ static inline void log2(T &dst, const T &src) { + unary_map(dst, src); +} + +template +__device__ static inline void abs(T &dst, const T &src) { + unary_map(dst, src); +} + +template +__device__ static inline void relu(T &dst, const T &src) { + unary_map(dst, src); +} + +template +__device__ static inline void copy(T &dst, const U &src) { + bin_map(dst, src); +} + +// uniform binary maps + +template +__device__ static inline void max(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +template +__device__ static inline void min(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +template +__device__ static inline void add(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +template +__device__ static inline void sub(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +template +__device__ static inline void mul(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +template +__device__ static inline void div(T &dst, const T &lhs, const U &rhs) { + bin_map(dst, lhs, rhs); +} + +// Row and col maps + + +template +__device__ static inline void add_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +template +__device__ static inline void sub_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +template +__device__ static inline void mul_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +template +__device__ static inline void div_row(T &dst, const T &src, const V &row_values) { + row_map(dst, src, row_values); +} + +template +__device__ static inline void broadcast_row(T &dst, const V &row_values) { + row_map(dst, dst, row_values); +} + + +// col maps + +template +__device__ static inline void add_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +template +__device__ static inline void sub_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +template +__device__ static inline void mul_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +template +__device__ static inline void div_col(T &dst, const T &src, const V &col_values) { + col_map(dst, src, col_values); +} + +template +__device__ static inline void broadcast_col(T &dst, const V &col_values) { + col_map(dst, dst, col_values); +} + +// Templated versions of each + +template +__device__ static inline void add(T &dst, const T &src, const V &col_values) { + if constexpr (axis == axis::COL) add_col(dst, src, col_values); + else add_row(dst, src, col_values); +} + +template +__device__ static inline void sub(T &dst, const T &src, const V &col_values) { + if constexpr (axis == axis::COL) sub_col(dst, src, col_values); + else sub_row(dst, src, col_values); +} + +template +__device__ static inline void mul(T &dst, const T &src, const V &col_values) { + if constexpr (axis == axis::COL) mul_col(dst, src, col_values); + else mul_row(dst, src, col_values); +} + +template +__device__ static inline void div(T &dst, const T &src, const V &col_values) { + if constexpr (axis == axis::COL) div_col(dst, src, col_values); + else div_row(dst, src, col_values); +} + +template +__device__ static inline void broadcast(T &dst, const V &col_values) { + if constexpr (axis == axis::COL) broadcast_col(dst, col_values); + else broadcast_row(dst, col_values); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/tile/reductions.cuh b/extra/thunder/cuda/include/ops/group/shared/tile/reductions.cuh new file mode 100644 index 0000000000..f237f93247 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/tile/reductions.cuh @@ -0,0 +1,372 @@ +/** + * @file + * @brief Group reductions on shared tiles. + */ + +/** + * Performs row-wise reduction on a matrix using a specified operation. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type with row layout. + * @param row_accum The accumulator where the result of the reduction is stored. + * @param src The source matrix on which to perform the reduction. + * @param src_accum The initial value of the accumulator, used when reset is false. + * @param reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + */ +template +__device__ static inline void row_reduce(V &row_accum, const T &src, const V &src_accum) { + using dtype = typename V::dtype; + for (int row = laneid(); row < src.rows; row += GROUP_THREADS) { + dtype accum = src[{row, 0}]; + #pragma unroll + for (int col = 1; col < src.cols; col++) { + accum = op::template op(accum, src[{row, col}]); + } + if (reset) { + row_accum[row] = accum; + } else { + row_accum[row] = op::template op(src_accum[row], accum); + } + } +} + +/** + * Performs column-wise reduction on a matrix using a specified operation. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The shared vector type for the column accumulator. + * @tparam T The shared matrix type with column layout. + * @param col_accum The accumulator where the result of the reduction is stored. + * @param src The source matrix on which to perform the reduction. + * @param src_accum The initial value of the accumulator, used when reset is false. + * @param reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + */ +template +__device__ static inline void col_reduce(V &col_accum, const T &src, const V &src_accum) { + using dtype = typename V::dtype; + for (int col = laneid(); col < src.cols; col += GROUP_THREADS) { + dtype accum = src[{0, col}]; + #pragma unroll + for (int row = 1; row < src.rows; row++) { + accum = op::template op(accum, src[{row, col}]); + } + if (reset) { + col_accum[col] = accum; + } else { + col_accum[col] = op::template op(src_accum[col], accum); + } + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +/** + * @brief Store the maximum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_max(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +/** + * @brief Store the minimum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_min(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +/** + * @brief Store the sum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_sum(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} +/** + * @brief Store the product of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void row_prod(V &row_accum, const T &src) { + row_reduce(row_accum, src, row_accum); +} + +/** + * @brief Store the maximum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_max(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} +/** + * @brief Store the minimum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_min(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} +/** + * @brief Store the sum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_sum(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} +/** + * @brief Store the product of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void row_prod(V &row_accum, const T &src, const V &src_accum) { + row_reduce(row_accum, src, src_accum); +} + +/** + * @brief Store the maximum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_max(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +/** + * @brief Store the minimum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_min(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +/** + * @brief Store the sum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_sum(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} +/** + * @brief Store the product of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +__device__ static inline void col_prod(V &col_accum, const T &src) { + col_reduce(col_accum, src, col_accum); +} + +/** + * @brief Store the maximum of each column of the src shared matrix, as well as the src_accum shared vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_max(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} +/** + * @brief Store the minimum of each column of the src shared matrix, as well as the src_accum shared vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_min(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} +/** + * @brief Store the sum of each column of the src shared tile, as well as the src_accum row vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_sum(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} +/** + * @brief Store the product of each column of the src shared tile, as well as the src_accum row vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +__device__ static inline void col_prod(V &col_accum, const T &src, const V &src_accum) { + col_reduce(col_accum, src, src_accum); +} + +// templated versions of each + +template +__device__ static inline void max(V &dst, const T &src, const V &src_accum) { + if constexpr (ax == axis::COL) row_max(dst, src, src_accum); + else col_max(dst, src, src_accum); +} +template +__device__ static inline auto max(const T &src, const V &src_accum) { + V dst; + if constexpr (ax == axis::COL) row_max(dst, src, src_accum); + else col_max(dst, src, src_accum); + return dst; +} +template +__device__ static inline void max(V &dst, const T &src) { + if constexpr (ax == axis::COL) row_max(dst, src); + else col_max(dst, src); +} +template +__device__ static inline auto max(const T &src) { + using V = std::conditional_t; + V dst; + if constexpr (ax == axis::COL) row_max(dst, src); + else col_max(dst, src); + return dst; +} + +template +__device__ static inline void min(V &dst, const T &src, const V &src_accum) { + if constexpr (ax == axis::COL) row_min(dst, src, src_accum); + else col_min(dst, src, src_accum); +} +template +__device__ static inline auto min(const T &src, const V &src_accum) { + V dst; + if constexpr (ax == axis::COL) row_min(dst, src, src_accum); + else col_min(dst, src, src_accum); + return dst; +} +template +__device__ static inline void min(V &dst, const T &src) { + if constexpr (ax == axis::COL) row_min(dst, src); + else col_min(dst, src); +} +template +__device__ static inline auto min(const T &src) { + using V = std::conditional_t; + V dst; + if constexpr (ax == axis::COL) row_min(dst, src); + else col_min(dst, src); + return dst; +} + +template +__device__ static inline void sum(V &dst, const T &src, const V &src_accum) { + if constexpr (ax == axis::COL) row_sum(dst, src, src_accum); + else col_sum(dst, src, src_accum); +} +template +__device__ static inline auto sum(const T &src, const V &src_accum) { + V dst; + if constexpr (ax == axis::COL) row_sum(dst, src, src_accum); + else col_sum(dst, src, src_accum); + return dst; +} +template +__device__ static inline void sum(V &dst, const T &src) { + if constexpr (ax == axis::COL) row_sum(dst, src); + else col_sum(dst, src); +} +template +__device__ static inline auto sum(const T &src) { + using V = std::conditional_t; + V dst; + if constexpr (ax == axis::COL) row_sum(dst, src); + else col_sum(dst, src); + return dst; +} + +template +__device__ static inline void prod(V &dst, const T &src, const V &src_accum) { + if constexpr (ax == axis::COL) row_prod(dst, src, src_accum); + else col_prod(dst, src, src_accum); +} +template +__device__ static inline auto prod(const T &src, const V &src_accum) { + V dst; + if constexpr (ax == axis::COL) row_prod(dst, src, src_accum); + else col_prod(dst, src, src_accum); + return dst; +} +template +__device__ static inline void prod(V &dst, const T &src) { + if constexpr (ax == axis::COL) row_prod(dst, src); + else col_prod(dst, src); +} +template +__device__ static inline auto prod(const T &src) { + using V = std::conditional_t; + V dst; + if constexpr (ax == axis::COL) row_prod(dst, src); + else col_prod(dst, src); + return dst; +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/tile/tile.cuh b/extra/thunder/cuda/include/ops/group/shared/tile/tile.cuh new file mode 100644 index 0000000000..e1bb87bba4 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/tile/tile.cuh @@ -0,0 +1,37 @@ +/** + * @file + * @brief An aggregate header for group operations on shared tiles. + */ + +#include "conversions.cuh" +#include "maps.cuh" +#include "reductions.cuh" + +template +__device__ static inline bool hasnan(const ST &src) { + KITTENS_CHECK_WARP + bool nan_detected = false; + #pragma unroll + for(int i = laneid(); i < ST::num_elements; i+=GROUP_THREADS) { + if constexpr (std::is_same_v) { + if(isnan(src[i])) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__bfloat162float(src[i]))) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__half2float(src[i]))) { + nan_detected = true; + } + } + else { + static_assert(sizeof(typename ST::T) == 999, "Unsupported dtype"); + } + } + // Ballot across the warp to see if any lane detected a nan + return (__ballot_sync(0xffffffff, nan_detected) != 0); +} diff --git a/extra/thunder/cuda/include/ops/group/shared/vec/conversions.cuh b/extra/thunder/cuda/include/ops/group/shared/vec/conversions.cuh new file mode 100644 index 0000000000..4d4c7d3635 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/vec/conversions.cuh @@ -0,0 +1,27 @@ +/** + * @file + * @brief Group conversions on shared vectors. + */ + +/** + * @brief Copies data from one shared vector to another, converting data types if necessary. + * + * This function copies data from the source shared vector `src` to the destination shared vector `dst`. + * If the data types of `src` and `dst` are the same, it performs a direct memory copy. Otherwise, it + * converts each element from the source data type to the destination data type using the appropriate + * converter before copying. + * + * @tparam SV1 The type of the destination shared vector, must satisfy the ducks::sv::all concept. + * @tparam SV2 The type of the source shared vector, must satisfy the ducks::sv::all concept. + * @param[out] dst The destination shared vector. + * @param[in] src The source shared vector. + * @note The lengths of `src` and `dst` must be equal. This is enforced at compile time. + */ +template +__device__ static inline void copy(SV1 &dst, const SV2 &src) { + static_assert(SV1::length == SV2::length, "Source and destination vectors must have the same length."); + #pragma unroll + for(int i = laneid(); i < dst.length; i+=GROUP_THREADS) { + dst[i] = base_types::convertor::convert(src[i]); + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/vec/maps.cuh b/extra/thunder/cuda/include/ops/group/shared/vec/maps.cuh new file mode 100644 index 0000000000..987a2cb00b --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/vec/maps.cuh @@ -0,0 +1,259 @@ +/** + * @file + * @brief Group maps on shared vectors. + */ + +/** + * @brief Applies a unary operation to each element of a shared memory vector. + * + * @tparam op Unary operation type. + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector in which to store the result. + * @param src[in] Source vector to apply the unary operation. + */ +template +__device__ static inline void unary_op(T &dst, const T &src) { + #pragma unroll + for(auto cur = laneid(); cur < T::length; cur+=GROUP_THREADS) { + dst[cur] = op::template op(src[cur]); + } +} +/** + * @brief Perform a binary operation on two shared vectors. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vectors. + * @param dst[out] The destination vector where the result is stored. + * @param lhs[in] The left-hand side vector for the operation. + * @param rhs[in] The right-hand side vector for the operation. + */ +template +__device__ static inline void bin_op(T &dst, const T &lhs, const T &rhs) { + #pragma unroll + for(auto cur = laneid(); cur < T::length; cur+=GROUP_THREADS) { + dst[cur] = op::template op(lhs[cur], rhs[cur]); + } +} +/** + * @brief Perform a binary operation on a shared vector and a scalar. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector for the operation. + * @param param[in] The scalar parameter for the operation. + */ +template +__device__ static inline void bin_op(T &dst, const T &src, const typename T::dtype ¶m) { + #pragma unroll + for(auto cur = laneid(); cur < T::length; cur+=GROUP_THREADS) { + dst[cur] = op::template op(src[cur], param); + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// ---- const ops ---- + +/** + * @brief Sets all elements of a shared memory vector to zero. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to zero. + */ +template +__device__ static inline void zero(T &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a shared memory vector to one. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to one. + */ +template +__device__ static inline void one(T &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a shared memory vector to positive infinity. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to positive infinity. + */ +template +__device__ static inline void pos_infty(T &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a shared memory vector to negative infinity. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to negative infinity. + */ +template +__device__ static inline void neg_infty(T &dst) { + unary_op(dst, dst); +} + +// ---- unary ops ---- + +/** + * @brief Copies the elements from one shared vector to another. + * + * @tparam T Shared vector type. + * @tparam U Type of the source vector. + * @param dst[out] Destination vector where the elements will be copied to. + * @param src[in] Source vector to copy the elements from. + */ +template +__device__ static inline void copy(T &dst, const U &src) { + bin_op(dst, dst, src); // the second arg is ignored here. +} +/** + * @brief Applies the exponential function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +__device__ static inline void exp(T &dst, const T &src) { + unary_op(dst, src); +} +/** + * @brief Applies the exponential function element-wise to a shared vector, in base 2. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +__device__ static inline void exp2(T &dst, const T &src) { + unary_op(dst, src); +} +/** + * @brief Applies the natural logarithm function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the logarithm values will be stored. + * @param src[in] Source vector to apply the logarithm function to. + */ +template +__device__ static inline void log(T &dst, const T &src) { + unary_op(dst, src); +} +/** + * @brief Applies the logarithm base 2 function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the logarithm base 2 values will be stored. + * @param src[in] Source vector to apply the logarithm base 2 function to. + */ +template +__device__ static inline void log2(T &dst, const T &src) { + unary_op(dst, src); +} +/** + * @brief Applies the absolute value function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the absolute values will be stored. + * @param src[in] Source vector to apply the absolute value function to. + */ +template +__device__ static inline void abs(T &dst, const T &src) { + unary_op(dst, src); +} +/** + * @brief Applies the rectified linear unit (ReLU) function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the ReLU values will be stored. + * @param src[in] Source vector to apply the ReLU function to. + */ +template +__device__ static inline void relu(T &dst, const T &src) { + unary_op(dst, src); +} + +// ---- binary ops ---- + +/** + * @brief Computes the element-wise maximum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the maximum values will be stored. + * @param lhs[in] First vector for the maximum operation. + * @param rhs[in] Second vector for the maximum operation. + */ +template +__device__ static inline void max(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise minimum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the minimum values will be stored. + * @param lhs[in] First vector for the minimum operation. + * @param rhs[in] Second vector for the minimum operation. + */ +template +__device__ static inline void min(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise sum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the sum values will be stored. + * @param lhs[in] First vector for the sum operation. + * @param rhs[in] Second vector for the sum operation. + */ +template +__device__ static inline void add(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise difference of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the difference values will be stored. + * @param lhs[in] First vector for the difference operation. + * @param rhs[in] Second vector for the difference operation. + */ +template +__device__ static inline void sub(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise product of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the product values will be stored. + * @param lhs[in] First vector for the product operation. + * @param rhs[in] Second vector for the product operation. + */ +template +__device__ static inline void mul(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise division of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the division values will be stored. + * @param lhs[in] First vector for the division operation. + * @param rhs[in] Second vector for the division operation. + */ +template +__device__ static inline void div(T &dst, const T &lhs, const U &rhs) { + bin_op(dst, lhs, rhs); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/vec/reductions.cuh b/extra/thunder/cuda/include/ops/group/shared/vec/reductions.cuh new file mode 100644 index 0000000000..8cf858e8dc --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/vec/reductions.cuh @@ -0,0 +1,193 @@ +/** + * @file + * @brief Group reductions on shared vectors. + */ + +// The fastest way to do this, under most circumstances, is actually to just have each warp replicate it. +// This is not true for enormous shared vectors, but doing that efficiently actually requires some extra scratch shared memory. +// So, this is sufficient for the time being. +template +__device__ static inline void reduce(typename SV::dtype &dst_accum, const SV &src, const typename SV::dtype &src_accum) { + if constexpr (GROUP_WARPS == 1) { + using T = SV::dtype; + int lane = laneid(); + T accum; + if(lane < src.length) accum = src[lane]; // initialize a register accumulator + __syncwarp(); + for(int i = lane+kittens::WARP_THREADS; i < src.length; i+=kittens::WARP_THREADS) { + accum = op::template op(accum, src[i]); + } + __syncwarp(); + // We can now reduce within the warp. + if constexpr (src.length > 16) { + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 16)); + __syncwarp(); + } + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 8)); + __syncwarp(); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 4)); + __syncwarp(); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 2)); + __syncwarp(); + accum = op::template op(accum, packed_shfl_down_sync(kittens::MASK_ALL, accum, 1)); + __syncwarp(); + if constexpr (!reset) accum = op::template op(accum, src_accum); + // broadcast to all threads in the warp. + dst_accum = packed_shfl_sync(kittens::MASK_ALL, accum, 0); // everyone takes from warp leader + } + else { + ::kittens::group<1>::reduce(dst_accum, src, src_accum); + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +/** + * @brief Finds the maximum element in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] max_val The maximum value found in the vector. + * @param[in] src The shared memory vector to find the maximum in. + */ +template +__device__ static inline void max(typename SV::dtype &max_val, const SV &src) { + reduce(max_val, src, max_val); +} +template +__device__ static inline typename SV::dtype max(const SV &src) { + typename SV::dtype max_val; + reduce(max_val, src, max_val); + return max_val; +} + +/** + * @brief Finds the minimum element in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] min_val The minimum value found in the vector. + * @param[in] src The shared memory vector to find the minimum in. + */ +template +__device__ static inline void min(typename SV::dtype &min_val, const SV &src) { + reduce(min_val, src, min_val); +} +template +__device__ static inline typename SV::dtype min(const SV &src) { + typename SV::dtype min_val; + reduce(min_val, src, min_val); + return min_val; +} + +/** + * @brief Calculates the sum of elements in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] sum_val The sum of the values in the vector. + * @param[in] src The shared memory vector to sum. + */ +template +__device__ static inline void sum(typename SV::dtype &sum_val, const SV &src) { + reduce(sum_val, src, sum_val); +} +template +__device__ static inline typename SV::dtype sum(const SV &src) { + typename SV::dtype sum_val; + reduce(sum_val, src, sum_val); + return sum_val; +} + +/** + * @brief Calculates the product of elements in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] prod_val The product of the values in the vector. + * @param[in] src The shared memory vector to multiply. + */ +template +__device__ static inline void prod(typename SV::dtype &prod_val, const SV &src) { + reduce(prod_val, src, prod_val); +} +template +__device__ static inline typename SV::dtype prod(const SV &src) { + typename SV::dtype prod_val; + reduce(prod_val, src, prod_val); + return prod_val; +} + +// Three operand versions. + +/** + * @brief Finds the maximum element in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] max_val The maximum value found in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to find the maximum in. + * @param[in] src_accum The initial value to accumulate with the maximum value found. + */ +template +__device__ static inline void max(typename SV::dtype &max_val, const SV &src, const typename SV::dtype &src_accum) { + reduce(max_val, src, src_accum); +} +template +__device__ static inline typename SV::dtype max(const SV &src, const typename SV::dtype &src_accum) { + typename SV::dtype max_val; + reduce(max_val, src, src_accum); + return max_val; +} + +/** + * @brief Finds the minimum element in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] min_val The minimum value found in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to find the minimum in. + * @param[in] src_accum The initial value to accumulate with the minimum value found. + */ +template +__device__ static inline void min(typename SV::dtype &min_val, const SV &src, const typename SV::dtype &src_accum) { + reduce(min_val, src, src_accum); +} +template +__device__ static inline typename SV::dtype min(const SV &src, const typename SV::dtype &src_accum) { + typename SV::dtype min_val; + reduce(min_val, src, src_accum); + return min_val; +} + +/** + * @brief Calculates the sum of elements in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] sum_val The sum of the values in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to sum. + * @param[in] src_accum The initial value to accumulate with the sum of the vector. + */ +template +__device__ static inline void sum(typename SV::dtype &sum_val, const SV &src, const typename SV::dtype &src_accum) { + reduce(sum_val, src, src_accum); +} +template +__device__ static inline typename SV::dtype sum(const SV &src, const typename SV::dtype &src_accum) { + typename SV::dtype sum_val; + reduce(sum_val, src, src_accum); + return sum_val; +} + +/** + * @brief Calculates the product of elements in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] prod_val The product of the values in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to multiply. + * @param[in] src_accum The initial value to accumulate with the product of the vector. + */ +template +__device__ static inline void prod(typename SV::dtype &prod_val, const SV &src, const typename SV::dtype &src_accum) { + reduce(prod_val, src, src_accum); +} +template +__device__ static inline typename SV::dtype prod(const SV &src, const typename SV::dtype &src_accum) { + typename SV::dtype prod_val; + reduce(prod_val, src, src_accum); + return prod_val; +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/group/shared/vec/vec.cuh b/extra/thunder/cuda/include/ops/group/shared/vec/vec.cuh new file mode 100644 index 0000000000..883ad52700 --- /dev/null +++ b/extra/thunder/cuda/include/ops/group/shared/vec/vec.cuh @@ -0,0 +1,38 @@ +/** + * @file + * @brief An aggregate header for group operations on shared vectors. + */ + +#include "conversions.cuh" +#include "maps.cuh" +// no group vector reductions as they would require additional shared memory and synchronization, and those side effects just aren't worth it. +// warp vector reductions should be plenty fast in 99.9% of situations. + +template +__device__ static inline bool hasnan(const SV &src) { + KITTENS_CHECK_WARP + bool nan_detected = false; + #pragma unroll + for(int i = laneid(); i < SV::length; i+=GROUP_THREADS) { + if constexpr (std::is_same_v) { + if(isnan(src[i])) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__bfloat162float(src[i]))) { + nan_detected = true; + } + } + else if constexpr (std::is_same_v) { + if(isnan(__half2float(src[i]))) { + nan_detected = true; + } + } + else { + static_assert(sizeof(typename SV::T) == 999, "Unsupported dtype"); + } + } + // Ballot across the warp to see if any lane detected a nan + return (__ballot_sync(0xffffffff, nan_detected) != 0); +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/ops.cuh b/extra/thunder/cuda/include/ops/ops.cuh new file mode 100644 index 0000000000..dfc075dc9a --- /dev/null +++ b/extra/thunder/cuda/include/ops/ops.cuh @@ -0,0 +1,262 @@ +/** + * @file + * @brief A collection of all of the operations that ThunderKittens defines. + */ + +#pragma once + +#include "thread/thread.cuh" +#include "group/group.cuh" +#include "device/device.cuh" + +namespace kittens { + +// Operator overloading, which defaults to warp scope. + +// Tile operators + +template +__device__ static inline T operator+(const T &lhs, const U &rhs) { + T dst; + warp::add(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator+=(T &lhs, const U &rhs) { + warp::add(lhs, lhs, rhs); +} +template +__device__ static inline T operator-(const T &lhs, const U &rhs) { + T dst; + warp::sub(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator-=(T &lhs, const U &rhs) { + warp::sub(lhs, lhs, rhs); +} +template +__device__ static inline T operator*(const T &lhs, const U &rhs) { + T dst; + warp::mul(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator*=(T &lhs, const U &rhs) { + warp::mul(lhs, lhs, rhs); +} +template +__device__ static inline T operator/(const T &lhs, const U &rhs) { + T dst; + warp::div(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator/=(T &lhs, const U &rhs) { + warp::div(lhs, lhs, rhs); +} +template +__device__ static inline T operator+(const T &src, const V &row_values) { + T dst; + warp::add_row(dst, src, row_values); + return dst; +} +template +__device__ static inline T operator+(const T &src, const V &row_values) { + T dst; + warp::add_row(dst, src, row_values); + return dst; +} +template +__device__ static inline void operator+=(T &lhs, const V &row_values) { + warp::add_row(lhs, lhs, row_values); +} +template +__device__ static inline void operator+=(T &lhs, const V &row_values) { + warp::add_row(lhs, lhs, row_values); +} +template +__device__ static inline T operator-(const T &src, const V &row_values) { + T dst; + warp::sub_row(dst, src, row_values); + return dst; +} +template +__device__ static inline T operator-(const T &src, const V &row_values) { + T dst; + warp::sub_row(dst, src, row_values); + return dst; +} +template +__device__ static inline void operator-=(T &lhs, const V &row_values) { + warp::sub_row(lhs, lhs, row_values); +} +template +__device__ static inline void operator-=(T &lhs, const V &row_values) { + warp::sub_row(lhs, lhs, row_values); +} +template +__device__ static inline T operator*(const T &src, const V &row_values) { + T dst; + warp::mul_row(dst, src, row_values); + return dst; +} +template +__device__ static inline T operator*(const T &src, const V &row_values) { + T dst; + warp::mul_row(dst, src, row_values); + return dst; +} +template +__device__ static inline void operator*=(T &lhs, const V &row_values) { + warp::mul_row(lhs, lhs, row_values); +} +template +__device__ static inline void operator*=(T &lhs, const V &row_values) { + warp::mul_row(lhs, lhs, row_values); +} +template +__device__ static inline T operator/(const T &src, const V &row_values) { + T dst; + warp::div_row(dst, src, row_values); + return dst; +} +template +__device__ static inline T operator/(const T &src, const V &row_values) { + T dst; + warp::div_row(dst, src, row_values); + return dst; +} +template +__device__ static inline void operator/=(T &lhs, const V &row_values) { + warp::div_row(lhs, lhs, row_values); +} +template +__device__ static inline void operator/=(T &lhs, const V &row_values) { + warp::div_row(lhs, lhs, row_values); +} +template +__device__ static inline T operator+(const T &src, const V &col_values) { + T dst; + warp::add_col(dst, src, col_values); + return dst; +} +template +__device__ static inline T operator+(const T &src, const V &col_values) { + T dst; + warp::add_col(dst, src, col_values); + return dst; +} +template +__device__ static inline void operator+=(T &lhs, const V &col_values) { + warp::add_col(lhs, lhs, col_values); +} +template +__device__ static inline void operator+=(T &lhs, const V &col_values) { + warp::add_col(lhs, lhs, col_values); +} +template +__device__ static inline T operator-(const T &src, const V &col_values) { + T dst; + warp::sub_col(dst, src, col_values); + return dst; +} +template +__device__ static inline T operator-(const T &src, const V &col_values) { + T dst; + warp::sub_col(dst, src, col_values); + return dst; +} +template +__device__ static inline void operator-=(T &lhs, const V &col_values) { + warp::sub_col(lhs, lhs, col_values); +} +template +__device__ static inline void operator-=(T &lhs, const V &col_values) { + warp::sub_col(lhs, lhs, col_values); +} +template +__device__ static inline T operator*(const T &src, const V &col_values) { + T dst; + warp::mul_col(dst, src, col_values); + return dst; +} +template +__device__ static inline T operator*(const T &src, const V &col_values) { + T dst; + warp::mul_col(dst, src, col_values); + return dst; +} +template +__device__ static inline void operator*=(T &lhs, const V &col_values) { + warp::mul_col(lhs, lhs, col_values); +} +template +__device__ static inline void operator*=(T &lhs, const V &col_values) { + warp::mul_col(lhs, lhs, col_values); +} +template +__device__ static inline T operator/(const T &src, const V &col_values) { + T dst; + warp::div_col(dst, src, col_values); + return dst; +} +template +__device__ static inline T operator/(const T &src, const V &col_values) { + T dst; + warp::div_col(dst, src, col_values); + return dst; +} +template +__device__ static inline void operator/=(T &lhs, const V &col_values) { + warp::div_col(lhs, lhs, col_values); +} +template +__device__ static inline void operator/=(T &lhs, const V &col_values) { + warp::div_col(lhs, lhs, col_values); +} + +// Vector operators + +template +__device__ static inline T operator+(const T &lhs, const U &rhs) { + T dst; + warp::add(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator+=(T &lhs, const U &rhs) { + warp::add(lhs, lhs, rhs); +} +template +__device__ static inline T operator-(const T &lhs, const U &rhs) { + T dst; + warp::sub(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator-=(T &lhs, const U &rhs) { + warp::sub(lhs, lhs, rhs); +} +template +__device__ static inline T operator*(const T &lhs, const U &rhs) { + T dst; + warp::mul(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator*=(T &lhs, const U &rhs) { + warp::mul(lhs, lhs, rhs); +} +template +__device__ static inline T operator/(const T &lhs, const U &rhs) { + T dst; + warp::div(dst, lhs, rhs); + return dst; +} +template +__device__ static inline void operator/=(T &lhs, const U &rhs) { + warp::div(lhs, lhs, rhs); +} + +} diff --git a/extra/thunder/cuda/include/ops/thread/memory/memory.cuh b/extra/thunder/cuda/include/ops/thread/memory/memory.cuh new file mode 100644 index 0000000000..dc151ce49f --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/memory.cuh @@ -0,0 +1,10 @@ +/** + * @file + * @brief An aggregate header of warp memory operations, where a single warp loads or stores data on its own. + */ + +#pragma once + +#include "util/util.cuh" +#include "tile/tile.cuh" +#include "vec/vec.cuh" \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/memory/tile/tile.cuh b/extra/thunder/cuda/include/ops/thread/memory/tile/tile.cuh new file mode 100644 index 0000000000..f2bbdcc9be --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/tile/tile.cuh @@ -0,0 +1,10 @@ +/** + * @file + * @brief An aggregate header of warp memory operations on tiles, where a single warp loads or stores data on its own. + */ + +#pragma once + +#ifdef KITTENS_HOPPER +#include "tma.cuh" +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/memory/tile/tma.cuh b/extra/thunder/cuda/include/ops/thread/memory/tile/tma.cuh new file mode 100644 index 0000000000..3b1d543771 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/tile/tma.cuh @@ -0,0 +1,564 @@ +#pragma once + +#include "../../../../common/common.cuh" +#include "../../../../types/types.cuh" +#include "../util/util.cuh" + +#include +#include + +namespace kittens { +namespace tma { + +namespace detail { +template __device__ inline int4 tma_coords(const coord &unit_coord) { + constexpr int swizzle_elements = ST::swizzle_bytes / sizeof(typename ST::dtype); + if constexpr (axis == 2) return {unit_coord.r, unit_coord.c / swizzle_elements, unit_coord.d, unit_coord.b}; + else if constexpr (axis == 1) return {unit_coord.d, unit_coord.c / swizzle_elements, unit_coord.r, unit_coord.b}; + else if constexpr (axis == 0) return {unit_coord.b, unit_coord.c / swizzle_elements, unit_coord.r, unit_coord.d}; +} +} + +/* ---------- Prefetch Tensor Map ---------- */ + +/** + * @brief Prefetches data from global memory into a shared memory tile, along with the tensormap. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination shared memory tile. + * @param[in] src_tma_map The source tensormap address in global memory + * @param[in] tile_row_idx The row coord of the requested tile. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the requested tile. This is in units of complete tiles. + */ +template> +__device__ static inline void prefetch(ST &dst, const GL &src, const COORD &idx) { + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.prefetch.tensor.5d.L2.global.tile" + " [%0, {%1, %2, %3, %4, %5}];" + : + : "l"(tma_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.prefetch.tensor.5d.L2.global.tile.L2::cache_hint" + " [%0, {%1, %2, %3, %4, %5}], %6;" + : + : "l"(tma_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } +} +template> +__device__ static inline void prefetch(ST &dst, const GL &src, const COORD &idx) { + prefetch(dst, src, idx); +} + +/* ---------- Async load and store data from gmem/smem ---------- */ + +/** + * @brief Asynchronously stores data into global memory from a shared memory tile. + * + * This function performs an asynchronous copy operation using CUDA's cp.async.bulk.tensor instruction. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination tensormap address in global memory + * @param[in] src_tma_map The source shared memory tile. + * @param[in] tile_row_idx The row coord of the tile destination. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the tile destination. This is in units of complete tiles. + */ +template> +__device__ static inline void store_async(const GL &dst, const ST &src, const COORD &idx) { + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.5d.global.shared::cta.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.5d.global.shared::cta.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_async(const GL &dst, const ST &src, const COORD &idx) { + store_async(dst, src, idx); +} +template> +__device__ static inline void store_async(const PGL &dst, const ST &src, const COORD &idx) { + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.5d.global.shared::cta.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.5d.global.shared::cta.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_async(const PGL &dst, const ST &src, const COORD &idx) { + store_async(dst, src, idx); +} + +/* ---------- Async reduction + store data from gmem/smem ---------- */ + +/** + * @brief Asynchronously performs an add reduction and stores the result into global memory from a shared memory tile. + * + * This function performs an asynchronous add reduction and copy operation using CUDA's cp.reduce.async.bulk.tensor instruction. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination tensormap address in global memory + * @param[in] src_tma_map The source shared memory tile. + * @param[in] tile_row_idx The row coord of the tile destination. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the tile destination. This is in units of complete tiles. + */ +template> +__device__ static inline void store_add_async(const GL &dst, const ST &src, const COORD &idx) { + + static_assert(!(std::is_same_v || + std::is_same_v), + "TMA does not support async add reductions for fp8 types."); + + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.add.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.add.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_add_async(const GL &dst, const ST &src, const COORD &idx) { + store_add_async(dst, src, idx); +} +template> +__device__ static inline void store_add_async(const PGL &dst, const ST &src, const COORD &idx) { + + static_assert(!(std::is_same_v || + std::is_same_v), + "TMA does not support async add reductions for fp8 types."); + + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.add.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.add.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_add_async(const PGL &dst, const ST &src, const COORD &idx) { + store_add_async(dst, src, idx); +} + +/** + * @brief Asynchronously performs an min reduction and stores the result into global memory from a shared memory tile. + * + * This function performs an asynchronous min reduction and copy operation using CUDA's cp.reduce.async.bulk.tensor instruction. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination tensormap address in global memory + * @param[in] src_tma_map The source shared memory tile. + * @param[in] tile_row_idx The row coord of the tile destination. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the tile destination. This is in units of complete tiles. + */ +template> +__device__ static inline void store_min_async(const GL &dst, const ST &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + + static_assert(!(std::is_same_v || + std::is_same_v), + "TMA does not support async add reductions for fp8 types."); + + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.min.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.min.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_min_async(const GL &dst, const ST &src, const COORD &idx) { + store_min_async(dst, src, idx); +} +template> +__device__ static inline void store_min_async(const PGL &dst, const ST &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + + static_assert(!(std::is_same_v || + std::is_same_v), + "TMA does not support async add reductions for fp8 types."); + + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.min.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.min.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_min_async(const PGL &dst, const ST &src, const COORD &idx) { + store_min_async(dst, src, idx); +} + +/** + * @brief Asynchronously performs an max reduction and stores the result into global memory from a shared memory tile. + * + * This function performs an asynchronous max reduction and copy operation using CUDA's cp.reduce.async.bulk.tensor instruction. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination tensormap address in global memory + * @param[in] src_tma_map The source shared memory tile. + * @param[in] tile_row_idx The row coord of the tile destination. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the tile destination. This is in units of complete tiles. + */ +template> +__device__ static inline void store_max_async(const GL &dst, const ST &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + + static_assert(!(std::is_same_v || + std::is_same_v), + "TMA does not support async add reductions for fp8 types."); + + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.max.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.max.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_max_async(const GL &dst, const ST &src, const COORD &idx) { + store_max_async(dst, src, idx); +} +template> +__device__ static inline void store_max_async(const PGL &dst, const ST &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + + static_assert(!(std::is_same_v || + std::is_same_v), + "TMA does not support async add reductions for fp8 types."); + + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.max.tile.bulk_group" + " [%0, {%2, %3, %4, %5, %6}], [%1];" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.5d.global.shared::cta.max.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5, %6}], [%1], %7;" + : + : "l"(tma_ptr), "r"(src_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } + store_commit_group(); +} +template> +__device__ static inline void store_max_async(const PGL &dst, const ST &src, const COORD &idx) { + store_max_async(dst, src, idx); +} + +/** + * @brief Asynchronously loads data from global memory into a shared memory tile. + * + * This function performs an asynchronous copy operation using CUDA's cp.async.bulk.tensor instruction. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination shared memory tile. + * @param[in] src_tma_map The source tensormap address in global memory + * @param[in,out] bar The semaphore used for synchronization of the asynchronous copy. + * @param[in] tile_row_idx The row coord of the requested tile. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the requested tile. This is in units of complete tiles. + */ +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar) { + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + + if constexpr (policy == cache_policy::NORMAL) { + asm volatile( + "cp.async.bulk.tensor.5d.shared::cluster.global.tile.mbarrier::complete_tx::bytes" + " [%0], [%1, {%3, %4, %5, %6, %7}], [%2];" + : + : "r"(dst_ptr), "l"(tma_ptr), "r"(mbar_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w) + : "memory" + ); + } + else { + asm volatile( + "cp.async.bulk.tensor.5d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.L2::cache_hint" + " [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8;" + : + : "r"(dst_ptr), "l"(tma_ptr), "r"(mbar_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "l"(make_cache_policy()) + : "memory" + ); + } +} +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar) { + load_async(dst, src, idx, bar); +} + +namespace cluster { + +/** + * @brief Asynchronously loads data from global memory into a shared memory tile, across a threadblock cluster + * + * This function performs an asynchronous copy operation using CUDA's cp.async.bulk.tensor instruction. + * + * @tparam ST A shared tile type with a TMA-compatible layout + * @param[out] dst The destination shared memory tile. + * @param[in] src_tma_map The source tensormap address in global memory + * @param[in,out] bar The semaphore used for synchronization of the asynchronous copy. + * @param[in] tile_row_idx The row coord of the requested tile. This is in units of complete tiles. + * @param[in] tile_col_idx The column coord of the requested tile. This is in units of complete tiles. + * @param[in] cluster_mask The mask of the clusters to broadcast to. + */ +#ifdef KITTENS_BLACKWELL +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) +#else +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask) +#endif +{ + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst)); + coord unit_coord = idx.template unit_coord(); // convert to unit coordinates + int4 tma_coords = detail::tma_coords(unit_coord); + +#ifdef KITTENS_BLACKWELL + if(dst_mbar_cta != -1) { + uint32_t neighbor_mbar_ptr; + asm volatile ( + "mapa.shared::cluster.u32 %0, %1, %2;\n" + : "=r"(neighbor_mbar_ptr) + : "r"(mbar_ptr), "r"(dst_mbar_cta) + ); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.5d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.cta_group::2.multicast::cluster" + " [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8;" + : + : "r"(dst_ptr), "l"(tma_ptr), "r"(neighbor_mbar_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "h"(cluster_mask) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.5d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.cta_group::2.multicast::cluster.L2::cache_hint" + " [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8, %9;" + : + : "r"(dst_ptr), "l"(tma_ptr), "r"(neighbor_mbar_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "h"(cluster_mask), "l"(make_cache_policy()) + : "memory" + ); + } + } else +#endif + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.5d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.multicast::cluster" + " [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8;" + : + : "r"(dst_ptr), "l"(tma_ptr), "r"(mbar_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "h"(cluster_mask) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.5d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint" + " [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8, %9;" + : + : "r"(dst_ptr), "l"(tma_ptr), "r"(mbar_ptr), + "n"(0), "r"(tma_coords.x), "r"(tma_coords.y), "r"(tma_coords.z), "r"(tma_coords.w), "h"(cluster_mask), "l"(make_cache_policy()) + : "memory" + ); + } +} +#ifdef KITTENS_BLACKWELL +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { + load_async(dst, src, idx, bar, cluster_mask, dst_mbar_cta); +} +#else +template> +__device__ static inline void load_async(ST &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask) { + load_async(dst, src, idx, bar, cluster_mask); +} +#endif + +} // namespace cluster +} // namespace tma + +} // namespace kittens diff --git a/extra/thunder/cuda/include/ops/thread/memory/util/multimem.cuh b/extra/thunder/cuda/include/ops/thread/memory/util/multimem.cuh new file mode 100644 index 0000000000..e308428dc5 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/util/multimem.cuh @@ -0,0 +1,405 @@ +/** + * @file + * @brief Wrappers for multimem operations + */ + +#pragma once + +namespace kittens { + +enum class reduce_op { + ADD = 0, + MIN = 1, + MAX = 2 +}; + +enum class memory_model { + WEAK = 0, + STRONG = 1 +}; + +template +struct multimem; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(int &dst, const int *src) { + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.s32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.s32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MIN) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.min.s32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.min.s32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MAX) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.max.s32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.max.s32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(int *dst, const int &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.s32 [%0], %1;" + :: "l"(dst), "r"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.s32 [%0], %1;" + :: "l"(dst), "r"(src) : "memory"); + } + } + template + __device__ static inline void red(int *dst, const int &src) { + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.s32 [%0], %1;" + : : "l"(dst), "r"(src) : "memory"); + } else if constexpr (Op == reduce_op::MIN) { + asm volatile("multimem.red.release.sys.global.min.s32 [%0], %1;" + : : "l"(dst), "r"(src) : "memory"); + } else if constexpr (Op == reduce_op::MAX) { + asm volatile("multimem.red.release.sys.global.max.s32 [%0], %1;" + : : "l"(dst), "r"(src) : "memory"); + } + } +}; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(uint &dst, const uint *src) { + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.u32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.u32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MIN) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.min.u32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.min.u32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MAX) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.max.u32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.max.u32 %0, [%1];" + : "=r"(dst) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(uint *dst, const uint &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.u32 [%0], %1;" + :: "l"(dst), "r"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.u32 [%0], %1;" + :: "l"(dst), "r"(src) : "memory"); + } + } + template + __device__ static inline void red(uint *dst, const uint &src) { + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.u32 [%0], %1;" + : : "l"(dst), "r"(src) : "memory"); + } else if constexpr (Op == reduce_op::MIN) { + asm volatile("multimem.red.release.sys.global.min.u32 [%0], %1;" + : : "l"(dst), "r"(src) : "memory"); + } else if constexpr (Op == reduce_op::MAX) { + asm volatile("multimem.red.release.sys.global.max.u32 [%0], %1;" + : : "l"(dst), "r"(src) : "memory"); + } + } +}; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(float &dst, const float *src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for f32 ld_reduce operations"); + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.f32 %0, [%1];" + : "=f"(dst) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.f32 %0, [%1];" + : "=f"(dst) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(float *dst, const float &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.f32 [%0], %1;" + :: "l"(dst), "f"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.f32 [%0], %1;" + :: "l"(dst), "f"(src) : "memory"); + } + } + template + __device__ static inline void red(float *dst, const float &src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for f32 red operations"); + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.f32 [%0], %1;" + : : "l"(dst), "f"(src) : "memory"); + } + } +}; + + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(float2 &dst, const float2 *src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for f32 ld_reduce operations"); + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.v2.f32 {%0, %1}, [%2];" + : "=f"(dst.x), "=f"(dst.y) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.v2.f32 {%0, %1}, [%2];" + : "=f"(dst.x), "=f"(dst.y) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(float2 *dst, const float2 &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.v2.f32 [%0], {%1, %2};" + :: "l"(dst), "f"(src.x), "f"(src.y) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.v2.f32 [%0], {%1, %2};" + :: "l"(dst), "f"(src.x), "f"(src.y) : "memory"); + } + } + template + __device__ static inline void red(float2 *dst, const float2 &src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for f32 red operations"); + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.v2.f32 [%0], {%1, %2};" + : : "l"(dst), "f"(src.x), "f"(src.y) : "memory"); + } + } +}; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(bf16 &dst, const bf16 *src) { + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.acc::f32.bf16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.acc::f32.bf16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MIN) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.min.bf16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.min.bf16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MAX) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.max.bf16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.max.bf16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(bf16 *dst, const bf16 &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.bf16 [%0], %1;" + :: "l"(dst), "h"(*reinterpret_cast(&src)) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.bf16 [%0], %1;" + :: "l"(dst), "h"(*reinterpret_cast(&src)) : "memory"); + } + } + template + __device__ static inline void red(bf16 *dst, const bf16 &src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for bf16 red operations"); + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.bf16 [%0], %1;" + : : "l"(dst), "h"(*reinterpret_cast(&src)) : "memory"); + } + } +}; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(bf16_2 &dst, const bf16_2 *src) { + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.acc::f32.bf16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.acc::f32.bf16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MIN) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.min.bf16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.min.bf16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MAX) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.max.bf16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.max.bf16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(bf16_2 *dst, const bf16_2 &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.bf16x2 [%0], %1;" + :: "l"(dst), "r"(*reinterpret_cast(&src)) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.bf16x2 [%0], %1;" + :: "l"(dst), "r"(*reinterpret_cast(&src)) : "memory"); + } + } + template + __device__ static inline void red(bf16_2 *dst, const bf16_2 &src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for bf16_2 red operations"); + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.bf16x2 [%0], %1;" + : : "l"(dst), "r"(*reinterpret_cast(&src)) : "memory"); + } + } +}; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(half &dst, const half *src) { + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.acc::f32.f16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.acc::f32.f16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MIN) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.min.f16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.min.f16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MAX) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.max.f16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.max.f16 %0, [%1];" + : "=h"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(half *dst, const half &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.f16 [%0], %1;" + :: "l"(dst), "h"(*reinterpret_cast(&src)) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.f16 [%0], %1;" + :: "l"(dst), "h"(*reinterpret_cast(&src)) : "memory"); + } + } + template + __device__ static inline void red(half *dst, const half &src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for f16 red operations"); + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.f16 [%0], %1;" + : : "l"(dst), "h"(*reinterpret_cast(&src)) : "memory"); + } + } +}; + +template <> +struct multimem { + template + __device__ static inline void ld_reduce(half_2 &dst, const half_2 *src) { + if constexpr (Op == reduce_op::ADD) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.add.acc::f32.f16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.add.acc::f32.f16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MIN) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.min.f16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.min.f16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } else if constexpr (Op == reduce_op::MAX) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.ld_reduce.weak.global.max.f16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.ld_reduce.acquire.sys.global.max.f16x2 %0, [%1];" + : "=r"(*reinterpret_cast(&dst)) : "l"(src) : "memory"); + } + } + } + template + __device__ static inline void st(half_2 *dst, const half_2 &src) { + if constexpr (M == memory_model::WEAK) { + asm volatile("multimem.st.weak.global.f16x2 [%0], %1;" + :: "l"(dst), "r"(*reinterpret_cast(&src)) : "memory"); + } else if constexpr (M == memory_model::STRONG) { + asm volatile("multimem.st.release.sys.global.f16x2 [%0], %1;" + :: "l"(dst), "r"(*reinterpret_cast(&src)) : "memory"); + } + } + template + __device__ static inline void red(half_2 *dst, const half_2 &src) { + static_assert(Op == reduce_op::ADD, "MIN/MAX are not supported for f16_2 red operations"); + if constexpr (Op == reduce_op::ADD) { + asm volatile("multimem.red.release.sys.global.add.f16x2 [%0], %1;" + : : "l"(dst), "r"(*reinterpret_cast(&src)) : "memory"); + } + } +}; + +} // namespace kittens diff --git a/extra/thunder/cuda/include/ops/thread/memory/util/tensor.cuh b/extra/thunder/cuda/include/ops/thread/memory/util/tensor.cuh new file mode 100644 index 0000000000..657f596302 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/util/tensor.cuh @@ -0,0 +1,30 @@ +/** + * @file + * @brief Functions for transferring data directly between tensor memory and register memory. + */ + +#pragma once + +#include + +#include "../../../../common/common.cuh" +#include "../../../../types/types.cuh" +#include "util.cuh" + +namespace kittens { + +__device__ static inline void tensor_before_thread_sync() { + asm volatile("tcgen05.fence::before_thread_sync;\n"); +} +__device__ static inline void tensor_after_thread_sync() { + asm volatile("tcgen05.fence::after_thread_sync;\n"); +} + +__device__ inline static void tensor_load_wait() { + asm volatile("tcgen05.wait::ld.sync.aligned;"); +} +__device__ inline static void tensor_store_wait() { + asm volatile("tcgen05.wait::st.sync.aligned;"); +} + +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/memory/util/tma.cuh b/extra/thunder/cuda/include/ops/thread/memory/util/tma.cuh new file mode 100644 index 0000000000..82c6210bd8 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/util/tma.cuh @@ -0,0 +1,249 @@ +#pragma once + +#include "../../../../common/common.cuh" +#include "../../../../types/types.cuh" + +#include +#include + +namespace kittens { +/** + * @brief A namespace for all of ThunderKittens' TMA functionality. +*/ +namespace tma { + +/* ---------- Barrier functions for async load ---------- */ + +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the semaphore for the first thread in the warp. +* It converts the semaphore pointer to a generic shared memory pointer and uses an inline assembly +* instruction to set the expected number of bytes. +* +* @param semaphore Reference to the semaphore variable. +* @param bytes The number of bytes expected at the semaphore. +*/ +__device__ static inline void expect_bytes(semaphore& bar, uint32_t bytes) { + void const* const ptr = &bar; + uint32_t bar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + asm volatile ("mbarrier.arrive.expect_tx.shared::cta.b64 _, [%0], %1;\n" + :: "r"(bar_ptr), "r"(bytes)); +} +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the mbarrier before the transaction arrives. +*/ +template +__device__ static inline void expect(semaphore& bar, const T& _1, const args&... _2) { + expect_bytes(bar, size_bytes); +} + +/* ---------- Synchronization functions for async store ---------- */ + +/** + * @brief Commits previous asynchronous TMA stores to a group and performs them. +*/ +__device__ static inline void store_commit_group() { + asm volatile("cp.async.bulk.commit_group;"); +} +/** + * @brief Waits for previous committed TMA store groups to complete. + * + * @tparam N The maximum number of remaining TMA store groups. Defaults to 0. +*/ +template +__device__ static inline void store_async_wait() { + asm volatile ( + "cp.async.bulk.wait_group %0;" + : + : "n"(N) + : "memory" + ); +} +/** + * @brief Waits for previous committed TMA store groups to finish reading from shared memory. + * + * @tparam N The maximum number of remaining TMA store groups. Defaults to 0. +*/ +template +__device__ static inline void store_async_read_wait() { + asm volatile ( + "cp.async.bulk.wait_group.read %0;" + : + : "n"(N) + : "memory" + ); +} + +/* ---------- Cluster-scope operations ---------- */ + +namespace cluster { + +/** +* @brief Waits for the requested semaphore phase, at cluster scope +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void wait(semaphore& bar, int kPhaseBit) { + void const* const ptr = &bar; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.try_wait.parity.acquire.cluster.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +} + +__device__ static inline void careful_wait(semaphore& bar, int kPhaseBit) { + void const* const ptr = &bar; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + asm volatile ( + "{\n" + ".reg .b64 start_clock, current_clock;\n" + "mov.b64 start_clock, %clock64;\n" + ".reg .pred P_CLOCK;\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.try_wait.parity.acquire.cluster.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "mov.b64 current_clock, %clock64;\n" + "sub.u64 current_clock, current_clock, start_clock;\n" + "setp.ge.u64 P_CLOCK, current_clock, 1000000;\n" + "@P_CLOCK trap;\n" + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +} + +/** +* @brief Sets the number of bytes expected at the semaphore, assuming a multicast instruction. +* +* This function sets the number of bytes expected at the semaphore for the first thread in the warp. +* It converts the semaphore pointer to a generic shared memory pointer and uses an inline assembly +* instruction to set the expected number of bytes. +* +* It's worth being aware that this function is particularly necessary for multicast loads, and +* distributed shared memory can actually be done with a normal tma::expect followed by wait. See +* the unit tests of dsmem for an example. +* +* @param semaphore Reference to the semaphore variable. +* @param bytes The number of bytes expected at the semaphore. +*/ +__device__ static inline void expect_bytes(semaphore& bar, uint32_t bytes, int dst_cta) { + uint32_t mbar_addr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t neighbor_mbar_addr; + asm volatile ( + "mapa.shared::cluster.u32 %0, %1, %2;\n" + : "=r"(neighbor_mbar_addr) + : "r"(mbar_addr), "r"(dst_cta) + ); + + asm volatile ("mbarrier.arrive.expect_tx.shared::cluster.b64 _, [%0], %1;\n" + :: "r"(neighbor_mbar_addr), "r"(bytes)); +} +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the semaphore for the first thread in the warp. +* It converts the semaphore pointer to a generic shared memory pointer and uses an inline assembly +* instruction to set the expected number of bytes. +* +* @tparam T The type of the data to be stored at the semaphore. +* @param semaphore Reference to the semaphore variable. +*/ +/** +* @brief Sets the number of bytes expected at the semaphore. +* +* This function sets the number of bytes expected at the mbarrier before the transaction arrives. +*/ +template +__device__ static inline void expect(semaphore& bar, int dst_cta, const T& _1, const args&... _2) { + expect_bytes(bar, size_bytes, dst_cta); +} + +/** +* @brief Arrives at a semaphore in cluster scope. +* +* Marks a thread arrival at an mbarrier +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void arrive(semaphore& bar, int dst_cta, uint32_t count=1) { + uint32_t mbar_addr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t neighbor_mbar_addr; + asm volatile ( + "mapa.shared::cluster.u32 %0, %1, %2;\n" + : "=r"(neighbor_mbar_addr) + : "r"(mbar_addr), "r"(dst_cta) + ); + asm volatile ( + "mbarrier.arrive.shared::cluster.b64 _, [%0], %1;\n" + : + : "r"(neighbor_mbar_addr), "r" (count) + : "memory" + ); +} + +// Generic transfer +__device__ static inline void store_async(void *dst, void *src, int dst_cta, uint32_t size_bytes, semaphore& bar) { + void const* const ptr = &bar; + uint32_t mbarrier_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + // ************************************************** + // load from src to dst in different threadblocks + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(src)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(dst)); + + // mapa instr = https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-mapa + // find dst addr in neighbor's cta + uint32_t neighbor_addr_dst; + asm volatile ( + "mapa.shared::cluster.u32 %0, %1, %2;\n" + : "=r"(neighbor_addr_dst) + : "r"(dst_ptr), "r"(dst_cta) + ); + + uint32_t neighbor_addr_mbarrier = mbarrier_ptr; + asm volatile ( + "mapa.shared::cluster.u32 %0, %1, %2;\n" + : "=r"(neighbor_addr_mbarrier) + : "r"(mbarrier_ptr), "r"(dst_cta) + ); + + // cp.async instr = https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-cp-async-bulk + // copy src into dst in neighbor's cta + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + asm volatile ( + "cp.async.bulk.shared::cluster.shared::cta.mbarrier::complete_tx::bytes [%0], [%1], %2, [%3];\n" + : + : "r"(neighbor_addr_dst), "r"(src_ptr), "r"(size_bytes), "r"(neighbor_addr_mbarrier) + : "memory" + ); +} + +// Templated transfer for convenience +template +__device__ static inline void store_async(T &dst_, T &src_, int dst_cta, semaphore& bar) { + store_async((void*)&dst_, (void*)&src_, dst_cta, size_bytes, bar); +} + +} // namespace cluster +} // namespace tma +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/memory/util/util.cuh b/extra/thunder/cuda/include/ops/thread/memory/util/util.cuh new file mode 100644 index 0000000000..cd3c760dbd --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/util/util.cuh @@ -0,0 +1,443 @@ +/** + * @file + * @brief General memory utilities not specialized for either tiles or vectors. + */ + +#pragma once + +namespace kittens { + +/* ---------- To prevent generic addressing, PTX ---------- */ + +template struct move { + __device__ static inline void lds(T& dst, uint32_t src); + __device__ static inline void sts(uint32_t dst, const T& src); + __device__ static inline void ldg(T& dst, T* src); + __device__ static inline void stg(T* dst, const T& src); +}; +// unpacked types +template<> struct move { + __device__ static inline void lds(bf16& dst, uint32_t src) { + asm volatile("ld.shared.b16 %0, [%1];\n" : "=h"(*(uint16_t*)&dst) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const bf16& src) { + asm volatile("st.shared.b16 [%1], %0;\n" : : "h"(*(uint16_t*)&src), "r"(dst)); + } + __device__ static inline void ldg(bf16& dst, bf16* src) { + asm volatile("ld.global.b16 %0, [%1];\n" : "=h"(*(uint16_t*)&dst) : "l"(src)); + } + __device__ static inline void stg(bf16* dst, const bf16& src) { + asm volatile("st.global.b16 [%1], %0;\n" : : "h"(*(uint16_t*)&src), "l"(dst)); + } +}; +template<> struct move { + __device__ static inline void lds(half& dst, uint32_t src) { + asm volatile("ld.shared.b16 %0, [%1];\n" : "=h"(*(uint16_t*)&dst) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const half& src) { + asm volatile("st.shared.b16 [%1], %0;\n" : : "h"(*(uint16_t*)&src), "r"(dst)); + } + __device__ static inline void ldg(half& dst, half* src) { + asm volatile("ld.global.b16 %0, [%1];\n" : "=h"(*(uint16_t*)&dst) : "l"(src)); + } + __device__ static inline void stg(half* dst, const half& src) { + asm volatile("st.global.b16 [%1], %0;\n" : : "h"(*(uint16_t*)&src), "l"(dst)); + } +}; +template<> struct move { + __device__ static inline void lds(float& dst, uint32_t src) { + asm volatile("ld.shared.f32 %0, [%1];\n" : "=f"(dst) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const float& src) { + asm volatile("st.shared.f32 [%1], %0;\n" : : "f"(src), "r"(dst)); + } + __device__ static inline void ldg(float& dst, float* src) { + asm volatile("ld.global.f32 %0, [%1];\n" : "=f"(dst) : "l"(src)); + } + __device__ static inline void stg(float* dst, const float& src) { + asm volatile("st.global.f32 [%1], %0;\n" : : "f"(src), "l"(dst)); + } +}; +template<> struct move { + __device__ static inline void lds(int& dst, uint32_t src) { + asm volatile("ld.shared.u32 %0, [%1];\n" : "=r"(dst) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const int& src) { + asm volatile("st.shared.u32 [%1], %0;\n" : : "r"(src), "r"(dst)); + } + __device__ static inline void ldg(int& dst, int* src) { + asm volatile("ld.global.u32 %0, [%1];\n" : "=r"(dst) : "l"(src)); + } + __device__ static inline void stg(int* dst, const int& src) { + asm volatile("st.global.u32 [%1], %0;\n" : : "r"(src), "l"(dst)); + } +}; +// packed types +template<> struct move { + __device__ static inline void lds(bf16_2& dst, uint32_t src) { + asm volatile("ld.shared.b32 %0, [%1];\n" : "=r"(*(uint32_t*)&dst) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const bf16_2& src) { + asm volatile("st.shared.b32 [%1], %0;\n" : : "r"(*(uint32_t*)&src), "r"(dst)); + } + __device__ static inline void ldg(bf16_2& dst, bf16_2* src) { + asm volatile("ld.global.b32 %0, [%1];\n" : "=r"(*(uint32_t*)&dst) : "l"(src)); + } + __device__ static inline void stg(bf16_2* dst, const bf16_2& src) { + asm volatile("st.global.b32 [%1], %0;\n" : : "r"(*(uint32_t*)&src), "l"(dst)); + } + __device__ static inline void ldsm4(bf16_2& dst1, bf16_2& dst2, bf16_2& dst3, bf16_2& dst4, uint32_t src) { + asm volatile("ldmatrix.sync.aligned.m8n8.x4.shared::cta.b16 {%0, %1, %2, %3}, [%4];\n" : + "=r"(*(uint32_t*)&dst1), "=r"(*(uint32_t*)&dst2), "=r"(*(uint32_t*)&dst3), "=r"(*(uint32_t*)&dst4) : "r"(src)); + } + __device__ static inline void ldsm4t(bf16_2& dst1, bf16_2& dst2, bf16_2& dst3, bf16_2& dst4, uint32_t src) { + asm volatile("ldmatrix.sync.aligned.m8n8.x4.trans.shared::cta.b16 {%0, %1, %2, %3}, [%4];\n" : + "=r"(*(uint32_t*)&dst1), "=r"(*(uint32_t*)&dst2), "=r"(*(uint32_t*)&dst3), "=r"(*(uint32_t*)&dst4) : "r"(src)); + } + __device__ static inline void stsm4(uint32_t dst, bf16_2& src1, bf16_2& src2, bf16_2& src3, bf16_2& src4) { + asm volatile("stmatrix.sync.aligned.m8n8.x4.shared::cta.b16 [%4], {%0, %1, %2, %3};\n" :: + "r"(*(uint32_t*)&src1), "r"(*(uint32_t*)&src2), "r"(*(uint32_t*)&src3), "r"(*(uint32_t*)&src4), "r"(dst)); + } + __device__ static inline void stsm4t(uint32_t dst, bf16_2& src1, bf16_2& src2, bf16_2& src3, bf16_2& src4) { + asm volatile("stmatrix.sync.aligned.m8n8.x4.trans.shared::cta.b16 [%4], {%0, %1, %2, %3};\n" :: + "r"(*(uint32_t*)&src1), "r"(*(uint32_t*)&src2), "r"(*(uint32_t*)&src3), "r"(*(uint32_t*)&src4), "r"(dst)); + } +}; +template<> struct move { + __device__ static inline void lds(half_2& dst, uint32_t src) { + asm volatile("ld.shared.b32 %0, [%1];\n" : "=r"(*(uint32_t*)&dst) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const half_2& src) { + asm volatile("st.shared.b32 [%1], %0;\n" : : "r"(*(uint32_t*)&src), "r"(dst)); + } + __device__ static inline void ldg(half_2& dst, half_2* src) { + asm volatile("ld.global.b32 %0, [%1];\n" : "=r"(*(uint32_t*)&dst) : "l"(src)); + } + __device__ static inline void stg(half_2* dst, const half_2& src) { + asm volatile("st.global.b32 [%1], %0;\n" : : "r"(*(uint32_t*)&src), "l"(dst)); + } + __device__ static inline void ldsm4(half_2& dst1, half_2& dst2, half_2& dst3, half_2& dst4, uint32_t src) { + asm volatile("ldmatrix.sync.aligned.m8n8.x4.shared::cta.b16 {%0, %1, %2, %3}, [%4];\n" : + "=r"(*(uint32_t*)&dst1), "=r"(*(uint32_t*)&dst2), "=r"(*(uint32_t*)&dst3), "=r"(*(uint32_t*)&dst4) : "r"(src)); + } + __device__ static inline void ldsm4t(half_2& dst1, half_2& dst2, half_2& dst3, half_2& dst4, uint32_t src) { + asm volatile("ldmatrix.sync.aligned.m8n8.x4.trans.shared::cta.b16 {%0, %1, %2, %3}, [%4];\n" : + "=r"(*(uint32_t*)&dst1), "=r"(*(uint32_t*)&dst2), "=r"(*(uint32_t*)&dst3), "=r"(*(uint32_t*)&dst4) : "r"(src)); + } + __device__ static inline void stsm4(uint32_t dst, half_2& src1, half_2& src2, half_2& src3, half_2& src4) { + asm volatile("stmatrix.sync.aligned.m8n8.x4.shared::cta.b16 [%4], {%0, %1, %2, %3};\n" :: + "r"(*(uint32_t*)&src1), "r"(*(uint32_t*)&src2), "r"(*(uint32_t*)&src3), "r"(*(uint32_t*)&src4), "r"(dst)); + } + __device__ static inline void stsm4t(uint32_t dst, half_2& src1, half_2& src2, half_2& src3, half_2& src4) { + asm volatile("stmatrix.sync.aligned.m8n8.x4.trans.shared::cta.b16 [%4], {%0, %1, %2, %3};\n" :: + "r"(*(uint32_t*)&src1), "r"(*(uint32_t*)&src2), "r"(*(uint32_t*)&src3), "r"(*(uint32_t*)&src4), "r"(dst)); + } +}; +template<> struct move { + __device__ static inline void lds(float2& dst, uint32_t src) { + asm volatile("ld.shared.v2.f32 {%0, %1}, [%2];\n" : "=f"(dst.x), "=f"(dst.y) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const float2& src) { + asm volatile("st.shared.v2.f32 [%2], {%0, %1};\n" : : "f"(src.x), "f"(src.y), "r"(dst)); + } + __device__ static inline void ldg(float2& dst, float2* src) { + asm volatile("ld.global.v2.f32 {%0, %1}, [%2];\n" : "=f"(dst.x), "=f"(dst.y) : "l"(src)); + } + __device__ static inline void stg(float2* dst, const float2& src) { + asm volatile("st.global.v2.f32 [%2], {%0, %1};\n" : : "f"(src.x), "f"(src.y), "l"(dst)); + } +}; +template<> struct move { + __device__ static inline void lds(float4& dst, uint32_t src) { + asm volatile("ld.shared.v4.f32 {%0, %1, %2, %3}, [%4];\n" : "=f"(dst.x), "=f"(dst.y), "=f"(dst.z), "=f"(dst.w) : "r"(src)); + } + __device__ static inline void sts(uint32_t dst, const float4& src) { + asm volatile("st.shared.v4.f32 [%4], {%0, %1, %2, %3};\n" : : "f"(src.x), "f"(src.y), "f"(src.z), "f"(src.w), "r"(dst)); + } + __device__ static inline void ldg(float4& dst, float4* src) { + asm volatile("ld.global.v4.f32 {%0, %1, %2, %3}, [%4];\n" : "=f"(dst.x), "=f"(dst.y), "=f"(dst.z), "=f"(dst.w) : "l"(src)); + } + __device__ static inline void stg(float4* dst, const float4& src) { + asm volatile("st.global.v4.f32 [%4], {%0, %1, %2, %3};\n" : : "f"(src.x), "f"(src.y), "f"(src.z), "f"(src.w), "l"(dst)); + } +}; +#ifdef KITTENS_HOPPER +template<> struct move { + __device__ static inline void ldsm4(fp8e4m3_4& dst1, fp8e4m3_4& dst2, fp8e4m3_4& dst3, fp8e4m3_4& dst4, uint32_t src) { + asm volatile("ldmatrix.sync.aligned.m8n8.x4.shared::cta.b16 {%0, %1, %2, %3}, [%4];\n" : + "=r"(*(uint32_t*)&dst1), "=r"(*(uint32_t*)&dst2), "=r"(*(uint32_t*)&dst3), "=r"(*(uint32_t*)&dst4) : "r"(src)); + } + __device__ static inline void stsm4(uint32_t dst, fp8e4m3_4& src1, fp8e4m3_4& src2, fp8e4m3_4& src3, fp8e4m3_4& src4) { + asm volatile("stmatrix.sync.aligned.m8n8.x4.shared::cta.b16 [%4], {%0, %1, %2, %3};\n" :: + "r"(*(uint32_t*)&src1), "r"(*(uint32_t*)&src2), "r"(*(uint32_t*)&src3), "r"(*(uint32_t*)&src4), "r"(dst)); + } + +}; +template<> struct move { + __device__ static inline void ldsm4(fp8e5m2_4& dst1, fp8e5m2_4& dst2, fp8e5m2_4& dst3, fp8e5m2_4& dst4, uint32_t src) { + asm volatile("ldmatrix.sync.aligned.m8n8.x4.shared::cta.b16 {%0, %1, %2, %3}, [%4];\n" : + "=r"(*(uint32_t*)&dst1), "=r"(*(uint32_t*)&dst2), "=r"(*(uint32_t*)&dst3), "=r"(*(uint32_t*)&dst4) : "r"(src)); + } + __device__ static inline void stsm4(uint32_t dst, fp8e5m2_4& src1, fp8e5m2_4& src2, fp8e5m2_4& src3, fp8e5m2_4& src4) { + asm volatile("stmatrix.sync.aligned.m8n8.x4.shared::cta.b16 [%4], {%0, %1, %2, %3};\n" :: + "r"(*(uint32_t*)&src1), "r"(*(uint32_t*)&src2), "r"(*(uint32_t*)&src3), "r"(*(uint32_t*)&src4), "r"(dst)); + } +}; +#endif + +/* ---------- Constants for Cache policies ---------- */ + +enum cache_policy { + NORMAL = 0, + EVICT_FIRST = 1, + EVICT_LAST = 2 +}; +template __device__ inline uint64_t make_cache_policy() { + uint64_t cache_policy_val; + constexpr float fraction = 1.0f; + static_assert(policy == cache_policy::EVICT_FIRST || policy == cache_policy::EVICT_LAST, "Unexpected cache policy"); + if constexpr (policy == cache_policy::EVICT_FIRST) { + asm volatile("createpolicy.fractional.L2::evict_first.b64 %0, %1;\n" : "=l"(cache_policy_val) : "f"(fraction)); + } + else { + asm volatile("createpolicy.fractional.L2::evict_last.b64 %0, %1;\n" : "=l"(cache_policy_val) : "f"(fraction)); + } + return cache_policy_val; +} +/* ---------- Generic (non-Hopper specific) semaphore functions ---------- */ + +struct semaphore { +private: + uint64_t value; +}; // note that this is an opaque type, so the value should not be accessed directly. +template struct barrier { + int barrier_id; + __device__ __forceinline__ barrier(int _id) : barrier_id(_id) {} + __device__ __forceinline__ barrier operator[](int i) { + return barrier(barrier_id + i); + } +}; + +/** + * @brief Initializes a synchronization semaphore with a transaction count and sets the expected number of bytes. + * + * This function sets up a semaphore that is used to synchronize threads within a block during asynchronous operations. + * It initializes the semaphore with a thread count semaphore. + * + * Additionally, if it is given a shared tile type, it will also call `set_bytes` to prepare for the memory transaction. + * + * @param[out] semaphore The semaphore variable to initialize. + * @param[in] tc The thread counter for the semaphore. + */ +__device__ static inline void init_semaphore(semaphore& bar, int thread_count, int transaction_count=0) { + void const* const ptr = &bar; + uint32_t bar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + + asm volatile ( + "mbarrier.init.shared::cta.b64 [%0], %1;\n" + :: "r"(bar_ptr), "r"(thread_count+transaction_count) + ); +} +/** + * @brief Invalidate an mbarrier + * + * @param[out] semaphore The semaphore variable to initialize. + * @param[in] tc The thread counter for the semaphore. + */ +__device__ static inline void invalidate_semaphore(semaphore& bar) { + void const* const ptr = &bar; + uint32_t bar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + asm volatile ( + "mbarrier.inval.shared::cta.b64 [%0];\n" + :: "r"(bar_ptr) + ); +} + +/** +* @brief Arrives at a semaphore. +* +* Marks a warp arrival at an mbarrier +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void arrive(semaphore& sem) { + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&sem)); + asm volatile ( + "mbarrier.arrive.release.cta.shared::cta.b64 _, [%0];\n" + : + : "r"(mbar_ptr) + : "memory" + ); +} +template __device__ static inline void arrive(barrier bar) { + asm volatile("bar.arrive %0, %1;\n" :: "r"(bar.barrier_id), "n"(num_warps*WARP_THREADS) : "memory"); +} + +#ifdef KITTENS_HOPPER +/** +* @brief Arrives at a semaphore. +* +* Marks a warp arrival at an mbarrier +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void arrive(semaphore& sem, uint32_t count) { + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&sem)); + asm volatile ( + "mbarrier.arrive.release.cta.shared::cta.b64 _, [%0], %1;\n" + : + : "r"(mbar_ptr), "r"(count) + : "memory" + ); +} +#endif + +/** +* @brief Waits for the requested semaphore phase. +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline void wait(semaphore& sem, int kPhaseBit) { + void const* const ptr = &sem; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + +#ifdef KITTENS_HOPPER + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.try_wait.parity.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +#else + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.test_wait.parity.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "nanosleep.u32 5;\n" // wait a few nanoseconds on pre-Hopper architectures to save instruction issue slots + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +#endif +} + +__device__ static inline void careful_wait(semaphore& sem, int kPhaseBit) { + void const* const ptr = &sem; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + +#ifdef KITTENS_HOPPER + asm volatile ( + "{\n" + ".reg .b64 start_clock, current_clock;\n" + "mov.b64 start_clock, %clock64;\n" + ".reg .pred P_CLOCK;\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.try_wait.parity.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "mov.b64 current_clock, %clock64;\n" + "sub.u64 current_clock, current_clock, start_clock;\n" + "setp.ge.u64 P_CLOCK, current_clock, 1000000;\n" + "@P_CLOCK trap;\n" + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +#else + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "LAB_WAIT:\n" + "mbarrier.test_wait.parity.shared::cta.b64 P1, [%0], %1;\n" + "@P1 bra.uni DONE;\n" + "nanosleep.u32 5;\n" // wait a few nanoseconds on pre-Hopper architectures to save instruction issue slots + "bra.uni LAB_WAIT;\n" + "DONE:\n" + "}\n" + :: "r"(mbar_ptr), + "r"(kPhaseBit) + ); +#endif +} + +/** +* @brief Checks if the requested semaphore phase is ready. +* +* @param semaphore Reference to the semaphore variable. +* @param kPhaseBit The phase bit used for the semaphore. +*/ +__device__ static inline int test_wait(semaphore& sem, int kPhaseBit) { + void const* const ptr = &sem; + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(ptr)); + int result; + asm volatile ( + "{\n" + ".reg .pred P1;\n" + "mbarrier.test_wait.parity.shared::cta.b64 P1, [%1], %2;\n" + "selp.u32 %0,1,0,P1;" + "}\n" + : "=r"(result) + : "r"(mbar_ptr), "r"(kPhaseBit) + ); + return result; +} + +__device__ static inline void arrive_and_wait(semaphore& sem, int kPhaseBit) { + arrive(sem); + wait(sem, kPhaseBit); +} +template __device__ static inline void arrive_and_wait(barrier bar) { + asm volatile("bar.sync %0, %1;\n" :: "r"(bar.barrier_id), "n"(num_warps*WARP_THREADS) : "memory"); +} + +template __device__ static inline void load_async_wait() { // for completing (non-TMA) async loads + if constexpr (N == 0) { + asm volatile("cp.async.wait_all;\n" ::); + } else { + asm volatile("cp.async.wait_group %0;\n" :: "n"(N)); + } + __syncwarp(); +} + +// meant to be used only with shared tiles and shared vectors +namespace detail { +template struct size_info { + static constexpr uint32_t bytes = sizeof(std::remove_reference_t); +}; +template struct size_info { + static constexpr uint32_t elements = ST::num_elements; + static constexpr uint32_t bytes = ST::num_elements * sizeof(typename ST::dtype); +}; +template struct size_info { + static constexpr uint32_t elements = SV::length; + static constexpr uint32_t bytes = SV::length * sizeof(typename SV::dtype); +}; +} +template inline constexpr uint32_t size_bytes = 0; // base case +template inline constexpr uint32_t size_bytes = detail::size_info::bytes + size_bytes; // recursive case + +} // namespace kittens + +#ifdef KITTENS_HOPPER +#include "multimem.cuh" +#include "tma.cuh" +#endif + +#ifdef KITTENS_BLACKWELL +#include "tensor.cuh" +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/memory/vec/tma.cuh b/extra/thunder/cuda/include/ops/thread/memory/vec/tma.cuh new file mode 100644 index 0000000000..dd92ccab44 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/vec/tma.cuh @@ -0,0 +1,416 @@ +#pragma once + +#include "../../../../common/common.cuh" +#include "../../../../types/types.cuh" +#include "../util/util.cuh" + +#include +#include + +// This is a macro that helps us define default cache policy versions of each function. +#define __KITTENS_TMA_DEFINE_DEFAULT_LOAD_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(SV &dst, const GL &src, const COORD &idx) { \ + function_name(dst, src, idx); \ +} +#define __KITTENS_TMA_DEFINE_PGL_DEFAULT_LOAD_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(SV &dst, const PGL &src, const COORD &idx) { \ + function_name(dst, src, idx); \ +} +#define __KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(const GL &dst, const SV &src, const COORD &idx) { \ + function_name(dst, src, idx); \ +} +#define __KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(const PGL &dst, const SV &src, const COORD &idx) { \ + function_name(dst, src, idx); \ +} +#define __KITTENS_TMA_DEFINE_SEMAPHORE_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(SV &dst, const GL &src, const COORD &idx, semaphore& bar) { \ + function_name(dst, src, idx, bar); \ +} +#define __KITTENS_TMA_DEFINE_PGL_SEMAPHORE_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(SV &dst, const PGL &src, const COORD &idx, semaphore& bar) { \ + function_name(dst, src, idx, bar); \ +} +#define __KITTENS_TMA_DEFINE_CLUSTER_SEMAPHORE_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(SV &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { \ + function_name(dst, src, idx, bar, cluster_mask, dst_mbar_cta); \ +} +#define __KITTENS_TMA_DEFINE_PGL_CLUSTER_SEMAPHORE_CACHE_VEC__(function_name) \ +template> \ +__device__ static inline void function_name(SV &dst, const PGL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { \ + function_name(dst, src, idx, bar, cluster_mask, dst_mbar_cta); \ +} + + +namespace kittens { + +namespace detail { +namespace tma { + +template __device__ static inline void vec_prefetch_tma_internal(uint64_t tma_ptr, coord<> tma_coord) { + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.prefetch.tensor.4d.L2.global.tile" + " [%0, {%1, %2, %3, %4}];" + : + : "l"(tma_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.prefetch.tensor.4d.L2.global.tile.L2::cache_hint" + " [%0, {%1, %2, %3, %4}], %5;" + : + : "l"(tma_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "l"(make_cache_policy()) + : "memory" + ); + } +} + +template __device__ static inline void vec_store_async_tma_internal(uint64_t tma_ptr, uint32_t src_i_ptr, coord<> tma_coord) { + asm volatile("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.4d.global.shared::cta.tile.bulk_group" + " [%0, {%2, %3, %4, %5}], [%1];" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.4d.global.shared::cta.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5}], [%1], %6;" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "l"(make_cache_policy()) + : "memory" + ); + } +} + +template __device__ static inline void vec_store_add_async_tma_internal(uint64_t tma_ptr, uint32_t src_i_ptr, coord<> tma_coord) { + asm volatile("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.4d.global.shared::cta.add.tile.bulk_group" + " [%0, {%2, %3, %4, %5}], [%1];" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.4d.global.shared::cta.add.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5}], [%1], %6;" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "l"(make_cache_policy()) + : "memory" + ); + } +} + +template __device__ static inline void vec_store_min_async_tma_internal(uint64_t tma_ptr, uint32_t src_i_ptr, coord<> tma_coord) { + asm volatile("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.4d.global.shared::cta.min.tile.bulk_group" + " [%0, {%2, %3, %4, %5}], [%1];" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.4d.global.shared::cta.min.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5}], [%1], %6;" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "l"(make_cache_policy()) + : "memory" + ); + } +} + +template __device__ static inline void vec_store_max_async_tma_internal(uint64_t tma_ptr, uint32_t src_i_ptr, coord<> tma_coord) { + asm volatile("fence.proxy.async.shared::cta;\n" ::: "memory"); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.reduce.async.bulk.tensor.4d.global.shared::cta.max.tile.bulk_group" + " [%0, {%2, %3, %4, %5}], [%1];" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b) + : "memory" + ); + } + else { + asm volatile ( + "cp.reduce.async.bulk.tensor.4d.global.shared::cta.max.tile.bulk_group.L2::cache_hint" + " [%0, {%2, %3, %4, %5}], [%1], %6;" + : + : "l"(tma_ptr), "r"(src_i_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "l"(make_cache_policy()) + : "memory" + ); + } +} + +template __device__ static inline void vec_load_async_tma_internal(uint64_t tma_ptr, uint32_t dst_i_ptr, uint32_t mbar_ptr, coord<> tma_coord) { + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.4d.shared::cluster.global.tile.mbarrier::complete_tx::bytes" + " [%0], [%1, {%3, %4, %5, %6}], [%2];" + : + : "r"(dst_i_ptr), "l"(tma_ptr), "r"(mbar_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.4d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.L2::cache_hint" + " [%0], [%1, {%3, %4, %5, %6}], [%2], %7;" + : + : "r"(dst_i_ptr), "l"(tma_ptr), "r"(mbar_ptr), "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "l"(make_cache_policy()) + : "memory" + ); + } +} + +namespace cluster { +template __device__ static inline void vec_load_async_tma_internal(uint64_t tma_ptr, uint32_t dst_i_ptr, uint32_t mbar_ptr, coord<> tma_coord, uint16_t cluster_mask, int dst_mbar_cta=-1) { +#ifdef KITTENS_BLACKWELL + if(dst_mbar_cta != -1) { + uint32_t neighbor_mbar_ptr; + asm volatile ( + "mapa.shared::cluster.u32 %0, %1, %2;\n" + : "=r"(neighbor_mbar_ptr) + : "r"(mbar_ptr), "r"(dst_mbar_cta) + ); + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.4d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.cta_group::2.multicast::cluster" + " [%0], [%1, {%3, %4, %5, %6}], [%2], %7;" + : + : "r"(dst_i_ptr), "l"(tma_ptr), "r"(neighbor_mbar_ptr), + "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "h"(cluster_mask) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.4d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.cta_group::2.multicast::cluster.L2::cache_hint" + " [%0], [%1, {%3, %4, %5, %6}], [%2], %7, %8;" + : + : "r"(dst_i_ptr), "l"(tma_ptr), "r"(neighbor_mbar_ptr), + "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "h"(cluster_mask), "l"(make_cache_policy()) + : "memory" + ); + } + } else +#endif + if constexpr (policy == cache_policy::NORMAL) { + asm volatile ( + "cp.async.bulk.tensor.4d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.multicast::cluster" + " [%0], [%1, {%3, %4, %5, %6}], [%2], %7;" + : + : "r"(dst_i_ptr), "l"(tma_ptr), "r"(mbar_ptr), + "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "h"(cluster_mask) + : "memory" + ); + } + else { + asm volatile ( + "cp.async.bulk.tensor.4d.shared::cluster.global.tile.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint" + " [%0], [%1, {%3, %4, %5, %6}], [%2], %7, %8;" + : + : "r"(dst_i_ptr), "l"(tma_ptr), "r"(mbar_ptr), + "r"(tma_coord.c), "r"(tma_coord.r), "r"(tma_coord.d), "r"(tma_coord.b), "h"(cluster_mask), "l"(make_cache_policy()) + : "memory" + ); + } +} +} // namespace cluster + +} // namespace tma +} // namespace detail + +namespace tma { + +template> +__device__ static inline void prefetch(SV &dst, const GL &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + ::kittens::detail::tma::vec_prefetch_tma_internal(tma_ptr, tma_coord); + } +} +__KITTENS_TMA_DEFINE_DEFAULT_LOAD_CACHE_VEC__(prefetch) + +template> +__device__ static inline void store_async(const GL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_async) + +template> +__device__ static inline void store_async(const PGL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_async) + +template> +__device__ static inline void store_add_async(const GL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_add_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_add_async) + +template> +__device__ static inline void store_add_async(const PGL &dst, const SV &src, const COORD &idx) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_add_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_add_async) + +template> +__device__ static inline void store_min_async(const GL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_min_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_min_async) + +template> +__device__ static inline void store_min_async(const PGL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_min_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_min_async) + +template> +__device__ static inline void store_max_async(const GL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_max_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_DEFAULT_STORE_CACHE_VEC__(store_max_async) + +template> +__device__ static inline void store_max_async(const PGL &dst, const SV &src, const COORD &idx) { + static_assert(!std::is_same_v, "TMA does not support async min/max reductions for fp32 types."); + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(dst.template get_tma()); + uint32_t src_ptr = static_cast(__cvta_generic_to_shared(&src)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t src_i_ptr = src_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_store_max_async_tma_internal(tma_ptr, src_i_ptr, tma_coord); + } + ::kittens::tma::store_commit_group(); +} +__KITTENS_TMA_DEFINE_PGL_DEFAULT_STORE_CACHE_VEC__(store_max_async) + +template> +__device__ static inline void load_async(SV &dst, const GL &src, const COORD &idx, semaphore& bar) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t dst_i_ptr = dst_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::vec_load_async_tma_internal(tma_ptr, dst_i_ptr, mbar_ptr, tma_coord); + } +} +__KITTENS_TMA_DEFINE_SEMAPHORE_CACHE_VEC__(load_async) + +namespace cluster { +template> +__device__ static inline void load_async(SV &dst, const GL &src, const COORD &idx, semaphore& bar, uint16_t cluster_mask, int dst_mbar_cta=-1) { + coord<> unit_coord = idx.template unit_coord<-1, 3>(); + uint64_t tma_ptr = reinterpret_cast(src.template get_tma()); + uint32_t mbar_ptr = static_cast(__cvta_generic_to_shared(&bar)); + uint32_t dst_ptr = static_cast(__cvta_generic_to_shared(&dst)); + for(int i = 0; i < ::kittens::detail::tma::sv_tma_dim2; i++) { + coord<> tma_coord = unit_coord; + tma_coord.c += i * ::kittens::detail::tma::sv_tma_dim1; + uint32_t dst_i_ptr = dst_ptr + i*::kittens::detail::tma::sv_tma_dim1*sizeof(typename SV::dtype); + ::kittens::detail::tma::cluster::vec_load_async_tma_internal(tma_ptr, dst_i_ptr, mbar_ptr, tma_coord, cluster_mask, dst_mbar_cta); + } +} +__KITTENS_TMA_DEFINE_CLUSTER_SEMAPHORE_CACHE_VEC__(load_async) +} // namespace cluster +} // namespace tma +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/memory/vec/vec.cuh b/extra/thunder/cuda/include/ops/thread/memory/vec/vec.cuh new file mode 100644 index 0000000000..7a42c6790f --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/memory/vec/vec.cuh @@ -0,0 +1,10 @@ +/** + * @file + * @brief An aggregate header of warp memory operations on vectors, where a single warp loads or stores data on its own. + */ + +#pragma once + +#ifdef KITTENS_HOPPER +#include "tma.cuh" +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/mma/mma.cuh b/extra/thunder/cuda/include/ops/thread/mma/mma.cuh new file mode 100644 index 0000000000..67eec84383 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/mma/mma.cuh @@ -0,0 +1,8 @@ +/** + * @file + * @brief An aggregate header for warp operations on data stored in tensor memory. + */ + +#pragma once + +#include "tensor/tensor.cuh" \ No newline at end of file diff --git a/extra/thunder/cuda/include/ops/thread/mma/tensor/tensor.cuh b/extra/thunder/cuda/include/ops/thread/mma/tensor/tensor.cuh new file mode 100644 index 0000000000..72911ca6c5 --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/mma/tensor/tensor.cuh @@ -0,0 +1,523 @@ +/** + * @file + * @brief Matrix multiply-accumulate operations for tiles stored in tensor memory. + */ + +#pragma once + +#include "../../../../common/common.cuh" +#include "../../../../types/types.cuh" + +namespace kittens { +namespace detail { +namespace tcgen05 { +// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#instruction-descriptor +template +__device__ static inline uint32_t instruction_descriptor() { + uint32_t desc = 0; + if constexpr (sizeof(AB) == 2) { // kind::f16 + // either accumulate to float, or the input is half and the output is half + static_assert(std::is_same_v || std::is_same_v); + desc |= 0b00 << 0; // sparsity bits unneeded + desc |= 0b0 << 2; // dense + desc |= 0b0 << 3; // no saturate on fp types + if constexpr (std::is_same_v) { + desc |= 0b01 << 4; // D matrix is FP32 + } + else { + desc |= 0b00 << 4; // D matrix is FP16 + } + desc |= 0b0 << 6; // reserved + if constexpr (std::is_same_v) { + desc |= 0b000 << 7; // 16-bit A input type as FP16 + desc |= 0b000 << 10; // 16-bit B input type as FP16 + } else if constexpr (std::is_same_v) { + desc |= 0b001 << 7; // 16-bit A input type as BF16 + desc |= 0b001 << 10; // 16-bit B input type as BF16 + } else if constexpr (std::is_same_v) { + desc |= 0b000 << 7; // 8-bit A input type as FP8 e4m3 + desc |= 0b000 << 10; // 8-bit B input type as FP8 e4m3 + } else if constexpr (std::is_same_v) { + desc |= 0b001 << 7; // 8-bit A input type as FP8 e5m2 + desc |= 0b001 << 10; // 8-bit B input type as FP8 e5m2 + } + /* fp6 and fp4 + else if constexpr (std::is_same_v) { + desc |= 0b011 << 7; // 6-bit A input type as FP6 e2m3 + desc |= 0b011 << 10; // 6-bit B input type as FP6 e2m3 + } + else if constexpr (std::is_same_v) { + desc |= 0b100 << 7; // 6-bit A input type as FP6 e3m2 + desc |= 0b100 << 10; // 6-bit B input type as FP6 e3m2 + } + else if constexpr (std::is_same_v) { + desc |= 0b101 << 7; // 4-bit A input type as FP4 e3m1 + desc |= 0b101 << 10; // 4-bit B input type as FP4 e3m1 + } + */ + if constexpr (neg) { + desc |= 0b1 << 13; // Do negate A matrix + } + else { + desc |= 0b0 << 13; // Don't negate A matrix + } + desc |= 0b0 << 14; // Don't negate B matrix (in all cases) + if constexpr (trans_a) { + desc |= 0b1 << 15; // Transpose A matrix + } + else { + desc |= 0b0 << 15; // Don't transpose A matrix + } + if constexpr (trans_b) { + desc |= 0b1 << 16; // Transpose B matrix + } + else { + desc |= 0b0 << 16; // Don't transpose B matrix + } + desc |= (N >> 3) << 17; // B matrix has dimension N, encoded + desc |= 0b0 << 23; // reserved + desc |= (M >> 4) << 24; // A matrix has dimension M, encoded + desc |= 0b0 << 29; // reserved + desc |= 0b00 << 30; // no shift for B-matrix reuse + } else if constexpr (sizeof(AB) == 1) { // kind::f8f6f4 + static_assert(std::is_same_v || std::is_same_v); // FP8/6/4 has to accumulate to float or half + desc |= 0b00 << 0; // sparsity bits unneeded + desc |= 0b0 << 2; // dense + desc |= 0b0 << 3; // no saturate on fp types + if constexpr (std::is_same_v) { + desc |= 0b01 << 4; // D matrix is FP32 + } + else { + desc |= 0b00 << 4; // D matrix is FP16 + } + desc |= 0b0 << 6; // reserved + if constexpr (std::is_same_v) { + desc |= 0b000 << 7; // 8-bit A input type as FP8 e4m3 + desc |= 0b000 << 10; // 8-bit B input type as FP8 e4m3 + } else if constexpr (std::is_same_v) { + desc |= 0b001 << 7; // 8-bit A input type as FP8 e5m2 + desc |= 0b001 << 10; // 8-bit B input type as FP8 e5m2 + } + /* fp6 and fp4 + else if constexpr (std::is_same_v) { + desc |= 0b011 << 7; // 6-bit A input type as FP6 e2m3 + desc |= 0b011 << 10; // 6-bit B input type as FP6 e2m3 + } + else if constexpr (std::is_same_v) { + desc |= 0b100 << 7; // 6-bit A input type as FP6 e3m2 + desc |= 0b100 << 10; // 6-bit B input type as FP6 e3m2 + } + else if constexpr (std::is_same_v) { + desc |= 0b101 << 7; // 4-bit A input type as FP4 e3m1 + desc |= 0b101 << 10; // 4-bit B input type as FP4 e3m1 + } + */ + if constexpr (neg) { + desc |= 0b1 << 13; // Do negate A matrix + } + else { + desc |= 0b0 << 13; // Don't negate A matrix + } + desc |= 0b0 << 14; // Don't negate B matrix (in all cases) + if constexpr (trans_a) { + desc |= 0b1 << 15; // Transpose A matrix + } + else { + desc |= 0b0 << 15; // Don't transpose A matrix + } + if constexpr (trans_b) { + desc |= 0b1 << 16; // Transpose B matrix + } + else { + desc |= 0b0 << 16; // Don't transpose B matrix + } + desc |= (N >> 3) << 17; // B matrix has dimension N, encoded + desc |= 0b0 << 23; // reserved + desc |= (M >> 4) << 24; // A matrix has dimension M, encoded + desc |= 0b0 << 29; // reserved + desc |= 0b00 << 30; // no shift for B-matrix reuse + } + else { + static_assert(sizeof(AB) == 999, "Invalid AB type size; not implemented yet."); + } + return desc; +}; + +template +__device__ static inline void tt_st(uint32_t d_tt_addr, uint32_t a_tt_addr, uint64_t b_desc, uint32_t idesc) { + if constexpr (std::is_same_v || std::is_same_v) { + // TODO(danfu): is there a better way to do this with string manipulation that the compiler likes? + if constexpr (ncta == 1) { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::1.kind::f8f6f4 [%0], [%1], %2, %3, p;}\n" + :: "r"(d_tt_addr), "r"(a_tt_addr), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + else { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::2.kind::f8f6f4 [%0], [%1], %2, %3, p;}\n" + :: "r"(d_tt_addr), "r"(a_tt_addr), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + } else { + if constexpr (ncta == 1) { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::1.kind::f16 [%0], [%1], %2, %3, p;}\n" + :: "r"(d_tt_addr), "r"(a_tt_addr), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + else { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::2.kind::f16 [%0], [%1], %2, %3, p;}\n" + :: "r"(d_tt_addr), "r"(a_tt_addr), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + } +} + +template +__device__ static inline void st_st(uint32_t d_tt_addr, uint64_t a_desc, uint64_t b_desc, uint32_t idesc) { + if constexpr (std::is_same_v || std::is_same_v) { + // TODO(danfu): is there a better way to do this with string manipulation that the compiler likes? + if constexpr (ncta == 1) { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::1.kind::f8f6f4 [%0], %1, %2, %3, p;}\n" + :: "r"(d_tt_addr), "l"(a_desc), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + else { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::2.kind::f8f6f4 [%0], %1, %2, %3, p;}\n" + :: "r"(d_tt_addr), "l"(a_desc), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + } else { + if constexpr (ncta == 1) { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::1.kind::f16 [%0], %1, %2, %3, p;}\n" + :: "r"(d_tt_addr), "l"(a_desc), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + else { + asm volatile( + "{.reg .pred p;\n" \ + "setp.eq.u32 p, 1, %4;\n" \ + "tcgen05.mma.cta_group::2.kind::f16 [%0], %1, %2, %3, p;}\n" + :: "r"(d_tt_addr), "l"(a_desc), "l"(b_desc), "r"(idesc), "n"(acc) + ); + } + } +} + +template __device__ static inline void commit(kittens::semaphore &sem) { + if constexpr (ncta == 1) { + asm volatile( + "tcgen05.commit.cta_group::1.mbarrier::arrive::one.b64 [%0];\n" + :: "l"(&sem) + ); + } + else { + asm volatile( + "tcgen05.commit.cta_group::2.mbarrier::arrive::one.shared::cluster.multicast::cluster.b64 [%0], %1;\n" + :: "l"(&sem), "h"((uint16_t)(0b11)) + ); + } +} + +} // namespace tcgen05 +} // namespace detail + +template constexpr int reduction_dimension = sizeof(T_AB) == 2 ? 16 : sizeof(T_AB) == 4 ? 8 : 32; // haven't added fp4 yet. +// RS matmul equivalent +template +__device__ static inline void mma(D &d, const A &a, const B &b) { + constexpr int trans_b = 1 - n_trans_b; + + // Do everything here. + constexpr int M = (trans_a ? A::cols : A::rows) * ncta; + static_assert(M == D::rows*ncta && ((ncta == 1 && (M == 64 || M == 128)) || (ncta == 2 && (M == 128 || M == 256)))); // output register is correctly sized + + constexpr int N = (trans_b ? B::cols : B::rows) * ncta; + static_assert(N == D::cols); // output register is correctly sized + + constexpr int K = trans_a ? A::rows : A::cols; + static_assert((trans_b ? B::rows : B::cols) == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; static_assert(std::is_same_v); + using T_D = D::T; + + constexpr int red_dim = reduction_dimension; + static_assert(K%red_dim == 0, "K dimension must be divisible by red_dim."); + + static_assert( + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v), + "Currently unsupported type combination for matrix multiply." + ); + uint32_t idesc = detail::tcgen05::instruction_descriptor(); + kittens::st_descriptor, trans_b> b_desc(b); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + + detail::tcgen05::template tt_st( + d.addr, + a.template chunk_addr(0), + b_desc.chunk_descriptor(0), + idesc + ); + #pragma unroll + for(int i = 1; i < K/red_dim; i++) { + detail::tcgen05::template tt_st( + d.addr, + a.template chunk_addr(i), + b_desc.chunk_descriptor(i), + idesc + ); + } +} +template +__device__ static inline void mma(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b); + detail::tcgen05::commit(sem); +} +// SS matmul equivalent +template +__device__ static inline void mma(D &d, const A &a, const B &b) { + constexpr int trans_b = 1 - n_trans_b; + + // Do everything here. + constexpr int M = (trans_a ? A::cols : A::rows) * ncta; + static_assert(M == D::rows*ncta && ((ncta == 1 && (M == 64 || M == 128)) || (ncta == 2 && (M == 128 || M == 256)))); // output register is correctly sized + + constexpr int N = (trans_b ? B::cols : B::rows) * ncta; + static_assert(N == D::cols); // output register is correctly sized + + constexpr int K = trans_a ? A::rows : A::cols; + static_assert((trans_b ? B::rows : B::cols) == K); // K dimension must match + static_assert(std::is_same_v); // A and B must match type. + + // Usings + using T_AB = A::T; static_assert(std::is_same_v); + using T_D = D::T; + + constexpr int red_dim = reduction_dimension; + static_assert(K%red_dim == 0, "K dimension must be divisible by red_dim."); + + static_assert( + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v) || + (std::is_same_v && !std::is_same_v), + "Currently unsupported type combination for matrix multiply." + ); + uint32_t idesc = detail::tcgen05::instruction_descriptor(); + kittens::st_descriptor, trans_a> a_desc(a); + kittens::st_descriptor, trans_b> b_desc(b); + + asm volatile ("fence.proxy.async.shared::cta;\n" ::: "memory"); + + detail::tcgen05::template st_st( + d.addr, + a_desc.chunk_descriptor(0), + b_desc.chunk_descriptor(0), + idesc + ); + #pragma unroll + for(int i = 1; i < K/red_dim; i++) { + detail::tcgen05::template st_st( + d.addr, + a_desc.chunk_descriptor(i), + b_desc.chunk_descriptor(i), + idesc + ); + } +} +template +__device__ static inline void mma(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b); + detail::tcgen05::commit(sem); +} +// Accumulator / numcta wrappers +template +__device__ static inline void mma2(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma2(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm2(D &d, const A &a, const B &b) { + mma2(d, a, b); +} + +// Transpose wrappers +template +__device__ static inline void mma_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma_AB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma2_AB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mma_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma_ABt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma2_ABt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mma_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma_AtB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma2_AtB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mma_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mma_AtBt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mma2_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mma2_AtBt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} + +template +__device__ static inline void mm_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm_AB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_AB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm2_AB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mm_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm_ABt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_ABt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm2_ABt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mm_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm_AtB(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_AtB(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm2_AtB(D &d, const A &a, const B &b) { + mma2(d, a, b); +} +template +__device__ static inline void mm_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma(d, a, b, sem); +} +template +__device__ static inline void mm_AtBt(D &d, const A &a, const B &b) { + mma(d, a, b); +} +template +__device__ static inline void mm2_AtBt(D &d, const A &a, const B &b, semaphore &sem) { + mma2(d, a, b, sem); +} +template +__device__ static inline void mm2_AtBt(D &d, const A &a, const B &b) { + mma2(d, a, b); +} + + +} // namespace kittens + diff --git a/extra/thunder/cuda/include/ops/thread/thread.cuh b/extra/thunder/cuda/include/ops/thread/thread.cuh new file mode 100644 index 0000000000..d6de48003b --- /dev/null +++ b/extra/thunder/cuda/include/ops/thread/thread.cuh @@ -0,0 +1,13 @@ +/** + * @file + * @brief An aggregate header of all warp (worker) operations defined by ThunderKittens + */ + +#pragma once + +// no namespace wrapper needed here + +#include "memory/memory.cuh" +#ifdef KITTENS_BLACKWELL +#include "mma/mma.cuh" +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/pyutils/broker.cuh b/extra/thunder/cuda/include/pyutils/broker.cuh new file mode 100644 index 0000000000..a045679754 --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/broker.cuh @@ -0,0 +1,551 @@ +/** + * @file broker.cuh + * @brief Utility for multiprocess data exchange and synchronization. + * + * This file provides the KittensBroker class, which enables efficient inter-process + * communication and synchronization using POSIX shared memory, semaphores, and sockets. + * The broker is designed to work in multi-GPU environments where processes need to + * exchange data and synchronize execution across different local ranks. + * + * @note This implementation relies on POSIX IPC mechanisms and is intended for + * Unix-like systems. All processes must be running on the same node. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + #error "KittensBroker is not supported on Windows" +#endif + +namespace kittens { + +namespace detail { +namespace broker { + +static constexpr int MAX_LOCAL_WORLD_SIZE = 72; +static constexpr int VAULT_SIZE_PER_RANK = 64; // sizeof(cudaIpcMemHandle_t) + +struct KittensVault { + static constexpr int INIT_CODE = 0x43617473; // "Cats" + int init; + int barrier; + int sense; + uint8_t data[MAX_LOCAL_WORLD_SIZE * VAULT_SIZE_PER_RANK]; +}; + +static constexpr int SHM_SIZE = (sizeof(KittensVault) + 4095) / 4096 * 4096; + +__host__ inline static void init_sync( + int local_rank, + volatile KittensVault *vault +) { + if (local_rank == 0) { + // initialize barrier resources + vault->barrier = 0; + vault->sense = 0; + __sync_synchronize(); // make previous writes visible + vault->init = KittensVault::INIT_CODE; + } else { + while (vault->init != KittensVault::INIT_CODE) usleep(1); + __sync_synchronize(); // see leader's previous writes + } +} + +__host__ inline static void sync( + int local_world_size, + volatile KittensVault *vault +) { + if (vault->init != KittensVault::INIT_CODE) + throw std::runtime_error("KittensBroker: KittensVault not initialized"); + + // Phase 1 + int arrived = __sync_add_and_fetch(&vault->barrier, 1); + if (arrived == local_world_size) vault->sense = 1; + while (!vault->sense) usleep(1); + + // Make previous writes visible + __sync_synchronize(); + + // Phase 2 + arrived = __sync_add_and_fetch(&vault->barrier, -1); + if (arrived == 0) vault->sense = 0; + while (vault->sense) usleep(1); +} + +__host__ inline void *create_shm(const char *key, size_t size) { + int shm_fd; + shm_fd = shm_open(key, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600); + + if (shm_fd < 0) { + if (errno == EEXIST) + throw std::runtime_error("KittensBroker: Named shared memory already exists"); + throw std::runtime_error("KittensBroker: Failed to create shared memory"); + } + + if (ftruncate(shm_fd, size) != 0) { + shm_unlink(key); + close(shm_fd); + throw std::runtime_error("KittensBroker: Failed to truncate shared memory"); + } + + void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + close(shm_fd); + if (addr == MAP_FAILED) { + shm_unlink(key); + throw std::runtime_error("KittensBroker: Failed to map to shared memory"); + } + + return addr; +} + +__host__ inline void *open_shm(const char *key, size_t size) { + int shm_fd; + while (true) { + shm_fd = shm_open(key, O_RDWR | O_CLOEXEC, 0); + if (shm_fd >= 0) + break; + if (errno != ENOENT) + throw std::runtime_error("KittensBroker: Failed to open shared memory"); + usleep(1); + } + + struct stat shm_st; + do { + if (fstat(shm_fd, &shm_st) != 0) { + shm_unlink(key); + close(shm_fd); + throw std::runtime_error("KittensBroker: Failed to open shared memory stats"); + } + usleep(1); + } while ((size_t)shm_st.st_size < size); + + void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + close(shm_fd); + if (addr == MAP_FAILED) { + shm_unlink(key); + throw std::runtime_error("KittensBroker: Failed to map to shared memory"); + } + + return addr; +} + +__host__ inline void unlink_shm(const char *key) { + shm_unlink(key); +} + +__host__ inline void unmap_shm(void *addr, size_t size) { + munmap(addr, size); +} + +__host__ inline int create_socket(const char *key, int local_rank) { + int sock_fd; + if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) + throw std::runtime_error("KittensBroker: Socket creation error"); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + + char unique_key[64]; + int n = snprintf(unique_key, sizeof(unique_key), "%s%d", key, local_rank); + if (n < 0 || n >= (int)sizeof(unique_key)) { + close(sock_fd); + throw std::runtime_error("KittensBroker: Socket name too long"); + } + + size_t len = strnlen(unique_key, sizeof(addr.sun_path)); + if (len > (sizeof(addr.sun_path) - 1)) { + close(sock_fd); + throw std::runtime_error("KittensBroker: Socket name too long"); + } + strcpy(addr.sun_path, unique_key); + unlink(unique_key); + + if (bind(sock_fd, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0) { + close(sock_fd); + throw std::runtime_error("KittensBroker: Failed to bind socket"); + } + + return sock_fd; +} + +__host__ inline void send_fd( + int sock_fd, + int data_fd, + const char *dst_key, + int dst_local_rank, + int src_local_rank +) { + union { + struct cmsghdr cm; + char* control; + } control_un; + + size_t sizeof_control = CMSG_SPACE(sizeof(int)); + control_un.control = reinterpret_cast(malloc(sizeof_control)); + if (!control_un.control) { + close(sock_fd); + close(data_fd); + throw std::runtime_error("KittensBroker: Failed to allocate a control buffer"); + } + + struct msghdr msg {}; + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof_control; + + struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg); + cmptr->cmsg_len = CMSG_LEN(sizeof(int)); + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + memmove(CMSG_DATA(cmptr), &data_fd, sizeof(data_fd)); + + struct sockaddr_un addr {}; + addr.sun_family = AF_UNIX; + char dst_unique_key[64]; + int n = snprintf(dst_unique_key, sizeof(dst_unique_key), "%s%d", dst_key, dst_local_rank); + if (n < 0 || n >= (int)sizeof(dst_unique_key)) { + free(control_un.control); + close(sock_fd); + close(data_fd); + throw std::runtime_error("KittensBroker: dst path too long"); + } + strcpy(addr.sun_path, dst_unique_key); + msg.msg_name = (void *)&addr; + msg.msg_namelen = sizeof(struct sockaddr_un); + + int payload = src_local_rank; + struct iovec iov[1]; + iov[0].iov_base = &payload; + iov[0].iov_len = sizeof(payload); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + while (true) { + ssize_t sent = sendmsg(sock_fd, &msg, 0); + if (sent <= 0) { + if (errno == EINTR) continue; + close(sock_fd); + close(data_fd); + free(control_un.control); + throw std::runtime_error("KittensBroker: Failed to send FD over socket"); + } + break; + } + + free(control_un.control); +} + +__host__ inline void recv_fd(int sock_fd, int *data_fd, int *src_local_rank) { + union { + struct cmsghdr cm; + char* control; + } control_un; + + size_t sizeof_control = CMSG_SPACE(sizeof(int)); + control_un.control = reinterpret_cast(malloc(sizeof_control)); + if (!control_un.control) { + close(sock_fd); + throw std::runtime_error("KittensBroker: Failed to allocate a control buffer"); + } + + struct msghdr msg {}; + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof_control; + + int payload = -1; + struct iovec iov[1]; + iov[0].iov_base = &payload; + iov[0].iov_len = sizeof(payload); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + while (true) { + ssize_t received = recvmsg(sock_fd, &msg, 0); + if (received < 0 && errno == EINTR) { + msg.msg_controllen = sizeof_control; + msg.msg_iovlen = 1; + continue; + } + if (received < static_cast(sizeof(*data_fd))) { + free(control_un.control); + close(sock_fd); + throw std::runtime_error("KittensBroker: Failed to receive data over socket"); + } + break; + } + + if (msg.msg_flags & MSG_CTRUNC) { + free(control_un.control); + close(sock_fd); + throw std::runtime_error("KittensBroker: Control data truncated"); + } + + struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg); + if (!cmptr || + cmptr->cmsg_len != CMSG_LEN(sizeof(int)) || + cmptr->cmsg_level != SOL_SOCKET || + cmptr->cmsg_type != SCM_RIGHTS) { + free(control_un.control); + close(sock_fd); + throw std::runtime_error("KittensBroker: Failed to receive data over socket"); + } + + memmove(data_fd, CMSG_DATA(cmptr), sizeof(*data_fd)); + free(control_un.control); + *src_local_rank = payload; +} + +__host__ inline void unlink_socket(const char *key, int local_rank) { + char unique_key[64]; + int n = snprintf(unique_key, sizeof(unique_key), "%s%d", key, local_rank); + if (n < 0 || n >= (int)sizeof(unique_key)) + throw std::runtime_error("KittensBroker: Socket name too long"); + unlink(unique_key); +} + +__host__ inline void close_socket(int sock_fd) { + close(sock_fd); +} + +} // namespace broker +} // namespace detail + +/** + @brief KittensBroker utility for multiprocess data exchange. + + Note that the code relies on POSIX sockets/shared memory/semaphores for + inter-process communication and synchronization. + + The main functions meant to be used by the user are: + + KittensBroker broker(local_rank, local_world_size); + broker.exchange_data(dst, src, size); // exchange data between all processes + broker.exchange_fds(dst, src_fd); // exchange file descriptors between all processes + broker.broadcast_fd(dst, src_fd, src_rank); // broadcast file descriptor from src_rank to all processes + broker.sync(); // wait until all processes reach here + */ +struct KittensBroker { + // TODO: make unique per process group + static inline constexpr const char *SHM_KEY_ = "/kittens_broker_shm"; + static inline constexpr const char *SOCK_KEY_ = "/tmp/kittens_broker.sock"; + + int local_rank_; + int local_world_size_; + + void *shm_raw_; + volatile detail::broker::KittensVault *shm_; + int sock_; + + __host__ inline KittensBroker(int local_rank, int local_world_size) + : local_rank_(local_rank), + local_world_size_(local_world_size), + shm_raw_(nullptr), + shm_(nullptr), + sock_(-1) { + if (local_rank_ < 0) + throw std::runtime_error("KittensBroker: Local rank must be non-negative"); + if (local_rank_ >= local_world_size_) + throw std::runtime_error("KittensBroker: Local rank is greater than local world size"); + if (local_world_size_ > detail::broker::MAX_LOCAL_WORLD_SIZE) + throw std::runtime_error("KittensBroker: Local world size is greater than MAX_LOCAL_WORLD_SIZE"); + + if (local_rank_ == 0) { + shm_raw_ = detail::broker::create_shm(SHM_KEY_, sizeof(detail::broker::KittensVault)); + shm_ = reinterpret_cast(shm_raw_); + memset(shm_raw_, 0, sizeof(detail::broker::KittensVault)); + } else { + shm_raw_ = detail::broker::open_shm(SHM_KEY_, sizeof(detail::broker::KittensVault)); + shm_ = reinterpret_cast(shm_raw_); + } + detail::broker::init_sync(local_rank_, shm_); + detail::broker::sync(local_world_size_, shm_); + + if (local_rank_ ==0) + detail::broker::unlink_shm(SHM_KEY_); + detail::broker::sync(local_world_size_, shm_); + + sock_ = detail::broker::create_socket(SOCK_KEY_, local_rank_); + detail::broker::sync(local_world_size_, shm_); + } + + KittensBroker(const KittensBroker&) = delete; + KittensBroker& operator=(const KittensBroker&) = delete; + + __host__ inline KittensBroker(KittensBroker&& other) noexcept + : local_rank_(other.local_rank_), + local_world_size_(other.local_world_size_), + shm_raw_(other.shm_raw_), + shm_(other.shm_), + sock_(other.sock_) { + other.local_rank_ = -1; + other.local_world_size_ = -1; + other.shm_raw_ = nullptr; + other.shm_ = nullptr; + other.sock_ = -1; + } + + __host__ inline void destroy() { + if (shm_raw_) { + detail::broker::unmap_shm(shm_raw_, sizeof(detail::broker::KittensVault)); + shm_raw_ = nullptr; + shm_ = nullptr; + } + if (sock_ >= 0) { + detail::broker::unlink_socket(SOCK_KEY_, local_rank_); + detail::broker::close_socket(sock_); + sock_ = -1; + } + local_rank_ = -1; + local_world_size_ = -1; + } + + __host__ inline KittensBroker& operator=(KittensBroker&& other) noexcept { + if (this != &other) { + destroy(); + local_rank_ = other.local_rank_; + local_world_size_ = other.local_world_size_; + shm_raw_ = other.shm_raw_; + shm_ = other.shm_; + sock_ = other.sock_; + other.local_rank_ = -1; + other.local_world_size_ = -1; + other.shm_raw_ = nullptr; + other.shm_ = nullptr; + other.sock_ = -1; + } + return *this; + } + + __host__ inline ~KittensBroker() { + destroy(); + } + + __host__ inline void sync(int num_ranks = -1) { + if (num_ranks == -1) + num_ranks = local_world_size_; + else if (num_ranks < 0 || num_ranks > local_world_size_) + throw std::runtime_error("KittensBroker: Invalid number of ranks"); + + detail::broker::sync(num_ranks, shm_); + } + + __host__ inline void exchange_data(void *dst_, const void *src_, size_t size) { + if (size > detail::broker::VAULT_SIZE_PER_RANK) + throw std::runtime_error("KittensBroker: Size is greater than VAULT_SIZE_PER_RANK"); + + uint8_t *dst = reinterpret_cast(dst_); + const uint8_t *src = reinterpret_cast(src_); + + // Exchange data + sync(); // ensure all processes enter together + memcpy(const_cast(shm_->data) + local_rank_ * detail::broker::VAULT_SIZE_PER_RANK, src, size); + sync(); // ensure all processes exit together + + // Pack and copy back to destination + for (int i = 0; i < local_world_size_; i++) + memcpy(dst + i * size, const_cast(shm_->data) + i * detail::broker::VAULT_SIZE_PER_RANK, size); + } + + __host__ inline void exchange_fds(int *dst, const int data_fd) { + if (dst == nullptr) + throw std::runtime_error("KittensBroker: dst is null"); + if (data_fd < 0) + throw std::runtime_error("KittensBroker: source fd is negative"); + + // Initialize dst buffer + for (int i = 0; i < local_world_size_; ++i) + dst[i] = -1; + + // Ensure all processes enter together + sync(); + + if (local_rank_ == 0) { + // Rank 0 receives all FDs from and distributes them to other ranks + dst[0] = data_fd; + for (int i = 0; i < local_world_size_ - 1; i++) { + int received_fd; + int src_local_rank; + detail::broker::recv_fd(sock_, &received_fd, &src_local_rank); + if (received_fd < 0) + throw std::runtime_error("KittensBroker: Failed to receive FD over socket"); + if (src_local_rank == local_rank_) + throw std::runtime_error("KittensBroker: Invalid source rank"); + dst[src_local_rank] = received_fd; + } + for (int dst_local_rank = 1; dst_local_rank < local_world_size_; dst_local_rank++) { + for (int src_local_rank = 0; src_local_rank < local_world_size_; src_local_rank++) { + if (dst_local_rank == src_local_rank) + continue; + detail::broker::send_fd(sock_, dst[src_local_rank], SOCK_KEY_, dst_local_rank, src_local_rank); + } + } + close(dst[0]); // no longer needed + dst[0] = -1; + } else { + // The rest sends its FD to and receives the other FDs from rank 0 + detail::broker::send_fd(sock_, data_fd, SOCK_KEY_, 0, local_rank_); + close(data_fd); // no longer needed + for (int i = 0; i < local_world_size_ - 1; i++) { + int received_fd; + int src_local_rank; + detail::broker::recv_fd(sock_, &received_fd, &src_local_rank); + if (received_fd < 0) + throw std::runtime_error("KittensBroker: Failed to receive FD over socket"); + if (src_local_rank == local_rank_) + throw std::runtime_error("KittensBroker: Invalid source rank"); + dst[src_local_rank] = received_fd; + } + } + + // Ensure all processes exit together + sync(); + } + + __host__ inline void broadcast_fd(int *dst, const int data_fd, const int src_local_rank) { + if (src_local_rank < 0 || src_local_rank >= local_world_size_) + throw std::runtime_error("KittensBroker: Invalid source rank"); + + // Ensure all processes enter together + sync(); + + if (local_rank_ == src_local_rank) { + if (data_fd < 0) + throw std::runtime_error("KittensBroker: Source rank has invalid FD"); + for (int dst_local_rank = 0; dst_local_rank < local_world_size_; dst_local_rank++) { + if (dst_local_rank == src_local_rank) + continue; + detail::broker::send_fd(sock_, data_fd, SOCK_KEY_, dst_local_rank, src_local_rank); + } + close(data_fd); // no longer needed + } else { + if (!dst) + throw std::runtime_error("KittensBroker: Destination rank has invalid buffer"); + int _src_local_rank; + detail::broker::recv_fd(sock_, dst, &_src_local_rank); + if (*dst < 0) + throw std::runtime_error("KittensBroker: Failed to receive valid FD over socket"); + if (_src_local_rank != src_local_rank) + throw std::runtime_error("KittensBroker: Invalid source rank"); + } + + // Ensure all processes exit together + sync(); + } +}; + +} // namespace kittens diff --git a/extra/thunder/cuda/include/pyutils/club.cuh b/extra/thunder/cuda/include/pyutils/club.cuh new file mode 100644 index 0000000000..9d5580fca9 --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/club.cuh @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include + +/* + CUDA-specific ThreadPool + + Example usage + + // Construction + KittensClub club(device_ids, NUM_DEVICES); + + // Dispatch work to all threads (no need to set device) + club.execute([&](int dev_idx) { + int dev; + CUDACHECK(cudaGetDevice(&dev)); + if (dev != dev_idx) { + fprintf(stderr, "Device mismatch: expected %d, got %d\n", dev_idx, dev); + exit(1); + } + }); +*/ +class KittensClub { +public: + __host__ inline KittensClub(const int *device_ids, const int num_devices); + __host__ inline KittensClub(const int *device_ids, const cudaStream_t *streams, const int num_devices); + __host__ inline ~KittensClub(); + + // Dispatches `task` to all threads, and waits for all threads to finish (using cv) + __host__ inline void execute(std::function task); + +private: + // Condition indicators + bool stop; + std::vector task_available; + int n_task_done; + + // Threadpool + std::vector workers; + + // Streams for each device + std::vector streams; + + // Main entry point for each thread + __host__ inline void worker(int worker_id, int device_id); + + // Used to dispatch work to all threads + std::function current_task; + + // Synchronization + std::mutex mutex; + std::condition_variable cond_task_available; + std::condition_variable cond_task_done; +}; + +__host__ inline KittensClub::KittensClub(const int *device_ids, const int num_devices) : stop(false), n_task_done(0) { + for (size_t dev_idx = 0; dev_idx < num_devices; ++dev_idx) { + task_available.push_back(false); + streams.push_back(0); // Use default stream (null stream) + workers.emplace_back([this, dev_idx, device_ids] { worker(dev_idx, device_ids[dev_idx]); }); + } +} + +__host__ inline KittensClub::KittensClub(const int *device_ids, const cudaStream_t *streams_in, const int num_devices) : stop(false), n_task_done(0) { + for (size_t dev_idx = 0; dev_idx < num_devices; ++dev_idx) { + task_available.push_back(false); + streams.push_back(streams_in[dev_idx]); + workers.emplace_back([this, dev_idx, device_ids] { worker(dev_idx, device_ids[dev_idx]); }); + } +} + +__host__ inline KittensClub::~KittensClub() { + { + std::lock_guard lock(mutex); + stop = true; + } + cond_task_available.notify_all(); + for (std::thread &worker : workers) { + worker.join(); + } +} + +__host__ inline void KittensClub::execute(std::function task) { + { + std::lock_guard lock(mutex); + current_task = task; + for (size_t i = 0; i < task_available.size(); ++i) + task_available[i] = true; + } + cond_task_available.notify_all(); + { + std::unique_lock lock(mutex); + cond_task_done.wait(lock, [this] { return n_task_done == workers.size(); }); + n_task_done = 0; + } +} + +__host__ inline void KittensClub::worker(int worker_id, int device_id) { + cudaSetDevice(device_id); // done once and never again! This saves a LOT of time + while (true) { + std::function task; + { + std::unique_lock lock(mutex); + cond_task_available.wait(lock, [this, worker_id] { return stop || task_available[worker_id]; }); + + if (stop) + return; + + task = current_task; + task_available[worker_id] = false; + } + task(worker_id, streams[worker_id]); + { + std::lock_guard lock(mutex); // adds about 10 microseconds overhead + ++n_task_done; + if (n_task_done == workers.size()) + cond_task_done.notify_one(); + } + } +} diff --git a/extra/thunder/cuda/include/pyutils/parallel_tensor.cuh b/extra/thunder/cuda/include/pyutils/parallel_tensor.cuh new file mode 100644 index 0000000000..ecbcca5c60 --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/parallel_tensor.cuh @@ -0,0 +1,336 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include "../types/device/vmm.cuh" +#include "../types/device/ipc.cuh" +#include "broker.cuh" + +namespace kittens { +namespace py { + +/** + * @brief Distributed tensor wrapper for multi-GPU IPC sharing and multicast. + * Can be later used for easy PGL creation right before a kernel call. + * Meant to be used as a single object per thread/process. + */ +struct TKParallelTensor { + inline static std::map, KittensBroker> brokers_; // lazily initialized + + at::Tensor data_; // for direct access from PyTorch + std::vector shape_; + at::ScalarType dtype_; + + std::vector raw_ptrs_; + size_t allocated_size_; + + int local_rank_; // identical to device index + int local_world_size_; + + bool multicast_; + void *multicast_ptr_; + size_t multicast_allocated_size_; + + detail::ipc::flavor ipc_flavor_; + + __host__ inline TKParallelTensor( + const at::Tensor &tensor, + int local_rank, + int local_world_size, + bool multicast + ) : data_(tensor), + shape_(tensor.sizes().vec()), + dtype_(tensor.scalar_type()), + raw_ptrs_(local_world_size, nullptr), + allocated_size_(tensor.nbytes()), + local_rank_(local_rank), + local_world_size_(local_world_size), + multicast_(multicast), + multicast_ptr_(nullptr), + multicast_allocated_size_(0), + ipc_flavor_(detail::ipc::flavor::LEGACY) { + + TORCH_CHECK(tensor.is_cuda(), "Tensor must be on CUDA device"); + TORCH_CHECK(tensor.is_contiguous(), "Tensor must be contiguous"); + TORCH_CHECK(tensor.dim() <= 4, "Only tensors with dim <= 4 are supported for TKParallelTensor"); + TORCH_CHECK(tensor.device().index() == local_rank_, "Tensor device index must match local_rank"); + TORCH_CHECK(local_rank_ >= 0, "local_rank must be non-negative"); + TORCH_CHECK(local_rank_ < local_world_size_, "local_rank must be less than local_world_size"); + TORCH_CHECK(!multicast, "Multicast is not supported for pre-allocated tensors"); + + brokers_.try_emplace( + {local_rank_, local_world_size_}, + local_rank_, local_world_size_ + ); + + if (brokers_.size() > 1) + std::cerr << "WARNING: 2 KittensBroker instances created in the same process. This is not safe." << std::endl; + + c10::cuda::CUDAGuard device_guard(local_rank_); + exchange_ipc_handles(); + } + + __host__ inline TKParallelTensor( + const std::vector &shape, + const at::ScalarType dtype, + int local_rank, + int local_world_size, + bool multicast + ) : shape_(shape), + dtype_(dtype), + raw_ptrs_(local_world_size, nullptr), + allocated_size_(0), + local_rank_(local_rank), + local_world_size_(local_world_size), + multicast_(multicast), + multicast_ptr_(nullptr), + multicast_allocated_size_(0), + ipc_flavor_(detail::ipc::flavor::VMM) { + + TORCH_CHECK(local_rank_ >= 0, "local_rank must be non-negative"); + TORCH_CHECK(local_rank_ < local_world_size_, "local_rank must be less than local_world_size"); + + brokers_.try_emplace( + {local_rank_, local_world_size_}, + local_rank_, local_world_size_ + ); + + if (brokers_.size() > 1) + std::cerr << "WARNING: 2 KittensBroker instances created in the same process. This is not safe." << std::endl; + + c10::cuda::CUDAGuard device_guard(local_rank_); + create_shareable_cuda_tensor(); + exchange_ipc_handles(); + + if (multicast_) + initialize_multicast(); + } + + TKParallelTensor(const TKParallelTensor&) = delete; + TKParallelTensor& operator=(const TKParallelTensor&) = delete; + TKParallelTensor& operator=(TKParallelTensor&& other) = delete; + + __host__ inline TKParallelTensor(TKParallelTensor&& other) : + data_(std::move(other.data_)), + shape_(std::move(other.shape_)), + dtype_(std::move(other.dtype_)), + raw_ptrs_(std::move(other.raw_ptrs_)), + allocated_size_(other.allocated_size_), + local_rank_(other.local_rank_), + local_world_size_(other.local_world_size_), + multicast_(other.multicast_), + multicast_ptr_(other.multicast_ptr_), + multicast_allocated_size_(other.multicast_allocated_size_), + ipc_flavor_(other.ipc_flavor_) { + other.data_ = at::Tensor(); + other.shape_.clear(); + other.dtype_ = at::ScalarType::Undefined; + other.raw_ptrs_.clear(); + other.allocated_size_ = 0; + other.local_rank_ = -1; + other.local_world_size_ = -1; + other.multicast_ = false; + other.multicast_ptr_ = nullptr; + other.multicast_allocated_size_ = 0; + } + + __host__ inline ~TKParallelTensor() { + destroy(); + } + + __host__ inline at::Tensor data() const { + return data_; + } + + __host__ inline void create_shareable_cuda_tensor() { + c10::cuda::CUDAGuard device_guard(local_rank_); + + TORCH_CHECK(!shape_.empty(), "Shape must be non-empty"); + TORCH_CHECK(shape_.size() <= 4, "Shape must have at most 4 dimensions for TKParallelTensor"); + size_t size = c10::elementSize(dtype_); + for (auto dim : shape_) { + TORCH_CHECK(dim > 0, "Size dimensions must be positive"); + size *= static_cast(dim); + } + + void *raw_ptr; + detail::vmm::vm_alloc_map_set_access( + &raw_ptr, &allocated_size_, size, local_rank_, local_world_size_); + + // Create local copies for capture + int local_rank = local_rank_; + size_t allocated_size = allocated_size_; + + auto deleter = [local_rank, raw_ptr, allocated_size](void* p) mutable { + if (!p) return; + c10::cuda::CUDAGuard device_guard(local_rank); + auto stream = c10::cuda::getCurrentCUDAStream().stream(); + CUDACHECK(cudaStreamSynchronize(stream)); + detail::vmm::vm_unmap(raw_ptr, allocated_size); + }; + + at::TensorOptions options = at::TensorOptions() + .dtype(dtype_) + .device(at::kCUDA, local_rank_); + + data_ = at::from_blob(raw_ptr, shape_, std::move(deleter), options); + } + + template + __host__ inline void exchange_ipc_handles() { + using handle_t = detail::ipc::handle; + + // Get IPC handle + detail::ipc::check_support(local_rank_); + void *raw_ptr = reinterpret_cast(data_.data_ptr()); + handle_t ipc_handle; + detail::ipc::export_handle(&ipc_handle, raw_ptr); + + // Exchange IPC handles + std::vector all_ipc_handles(local_world_size_); + if constexpr (IPC_FLAVOR == detail::ipc::flavor::LEGACY) { + brokers_.at({local_rank_, local_world_size_}).exchange_data( + reinterpret_cast(all_ipc_handles.data()), + reinterpret_cast(&ipc_handle), + sizeof(handle_t) + ); + } else if constexpr (IPC_FLAVOR == detail::ipc::flavor::VMM) { + brokers_.at({local_rank_, local_world_size_}).exchange_fds( + reinterpret_cast(all_ipc_handles.data()), + ipc_handle.handle_ + ); + } else { + throw std::runtime_error("Invalid IPC flavor"); + } + + // Import IPC handles + for (int i = 0; i < local_world_size_; i++) { + if (i == local_rank_) + raw_ptrs_[i] = raw_ptr; + else + detail::ipc::import_handle(&raw_ptrs_[i], all_ipc_handles[i], allocated_size_, local_world_size_); + } + } + + __host__ inline void initialize_multicast() { + using handle_t = detail::ipc::handle; + + detail::vmm::multicast_check(local_rank_); + detail::ipc::check_support(local_rank_); + detail::vmm::handle multicast_handle; + + if (local_rank_ == 0) { + // Create multicast handle; only a single rank should create MC handle + detail::vmm::multicast_create_handle( + &multicast_handle, + &multicast_allocated_size_, + allocated_size_, + local_world_size_ + ); + + // Currently, non-rank-0 path assumes allocated_size_ == multicast_allocated_size_ + if (allocated_size_ != multicast_allocated_size_) + throw std::runtime_error("Multicast allocated size does not match memory allocated size"); + + // Get IPC handle + handle_t ipc_handle; + detail::ipc::export_handle(&ipc_handle, multicast_handle); + + // Broadcast the IPC multicast handle + brokers_.at({local_rank_, local_world_size_}).broadcast_fd(nullptr, ipc_handle.handle_, 0); + } else { + // Receive the IPC multicast handle from rank 0 + handle_t ipc_handle; + brokers_.at({local_rank_, local_world_size_}).broadcast_fd(&ipc_handle.handle_, -1, 0); + multicast_allocated_size_ = allocated_size_; + detail::ipc::import_handle(&multicast_handle, ipc_handle, multicast_allocated_size_, local_world_size_); + } + + // Add all devices to the MC handle. Must sync + detail::vmm::multicast_bind_device(multicast_handle, local_rank_); + brokers_.at({local_rank_, local_world_size_}).sync(); // must ensure all devices are added + + // Bind all memory to the MC handle and map to a virtual address; must be done after adding all devices + detail::vmm::handle memory_handle; + detail::vmm::vm_retrieve_handle(&memory_handle, raw_ptrs_[local_rank_]); + detail::vmm::multicast_bind_memory(multicast_handle, memory_handle, allocated_size_); + brokers_.at({local_rank_, local_world_size_}).sync(); + + // Map virtual address to multicast handle and set access; must be done after adding all devices + detail::vmm::vm_map(&multicast_ptr_, multicast_handle, multicast_allocated_size_); + detail::vmm::vm_set_access(multicast_ptr_, multicast_allocated_size_, local_world_size_); + + // Free the handles immediately + detail::vmm::vm_free(multicast_handle); + detail::vmm::vm_free(memory_handle); + } + + __host__ inline void destroy() { + // 1. Multicast cleanup + if (multicast_ && multicast_ptr_) { + brokers_.at({local_rank_, local_world_size_}).sync(); + detail::vmm::handle multicast_handle; + detail::vmm::vm_retrieve_handle(&multicast_handle, multicast_ptr_); + detail::vmm::vm_unmap(multicast_ptr_, multicast_allocated_size_); + detail::vmm::multicast_unbind_device(multicast_handle, multicast_allocated_size_, local_rank_); + brokers_.at({local_rank_, local_world_size_}).sync(); + detail::vmm::vm_free(multicast_handle); + } + + // 2. Imported handle cleanup + for (int i = 0; i < local_world_size_; i++) { + if (i != local_rank_ && i < raw_ptrs_.size()) { + if (ipc_flavor_ == detail::ipc::flavor::LEGACY) { + detail::ipc::free_handle(raw_ptrs_[i], allocated_size_); + } else if (ipc_flavor_ == detail::ipc::flavor::VMM) { + detail::ipc::free_handle(raw_ptrs_[i], allocated_size_); + } else { + throw std::runtime_error("Invalid IPC flavor"); + } + } + } + brokers_.at({local_rank_, local_world_size_}).sync(); // must sync before destroying the tensor + + // 3. Tensor cleanup + if (data_.defined()) + data_.reset(); // properly decreases the ref count + + // 4. Member variables cleanup + shape_.clear(); + dtype_ = at::ScalarType::Undefined; + raw_ptrs_.clear(); + allocated_size_ = 0; + local_rank_ = -1; + local_world_size_ = -1; + multicast_ = false; + multicast_ptr_ = nullptr; + multicast_allocated_size_ = 0; + } +}; + +} // namespace py +} // namespace kittens + +#define BIND_TK_PARALLEL_TENSOR(m) \ + pybind11::class_(m, "TKParallelTensor") \ + .def(pybind11::init(), \ + pybind11::arg("tensor"), \ + pybind11::arg("local_rank"), \ + pybind11::arg("local_world_size"), \ + pybind11::arg("multicast") = false) \ + .def(pybind11::init&, const at::ScalarType&, int, int, bool>(), \ + pybind11::arg("shape"), \ + pybind11::arg("dtype"), \ + pybind11::arg("local_rank"), \ + pybind11::arg("local_world_size"), \ + pybind11::arg("multicast") = false) \ + .def("data", &kittens::py::TKParallelTensor::data) \ + .def_readonly("data_", &kittens::py::TKParallelTensor::data_) \ + .def_readonly("local_rank_", &kittens::py::TKParallelTensor::local_rank_) \ + .def_readonly("local_world_size_", &kittens::py::TKParallelTensor::local_world_size_) diff --git a/extra/thunder/cuda/include/pyutils/pyutils.cuh b/extra/thunder/cuda/include/pyutils/pyutils.cuh new file mode 100644 index 0000000000..0f3101927d --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/pyutils.cuh @@ -0,0 +1,235 @@ +#pragma once + +#include "util.cuh" +#include +#include // for automatic Python list -> std::vector conversion + +namespace kittens { +namespace py { + +template struct from_object { + static T make(pybind11::object obj) { + return obj.cast(); + } + static T unwrap(pybind11::object obj, int dev_idx) { + return make(obj); // Scalars should be passed in as a scalar + } +}; +template struct from_object { + static GL make(pybind11::object obj) { + // Check if argument is a torch.Tensor + if (pybind11::hasattr(obj, "__class__") && + obj.attr("__class__").attr("__name__").cast() == "Tensor") { + + // Check if tensor is contiguous + if (!obj.attr("is_contiguous")().cast()) { + throw std::runtime_error("Tensor must be contiguous"); + } + if (obj.attr("device").attr("type").cast() == "cpu") { + throw std::runtime_error("Tensor must be on CUDA device"); + } + + // Get shape, pad with 1s if needed + std::array shape = {1, 1, 1, 1}; + auto py_shape = obj.attr("shape").cast(); + size_t dims = py_shape.size(); + if (dims > 4) { + throw std::runtime_error("Expected Tensor.ndim <= 4"); + } + for (size_t i = 0; i < dims; ++i) { + shape[4 - dims + i] = pybind11::cast(py_shape[i]); + } + + // Get data pointer using data_ptr() + uint64_t data_ptr = obj.attr("data_ptr")().cast(); + + // Create GL object using make_gl + return make_gl(data_ptr, shape[0], shape[1], shape[2], shape[3]); + } + throw std::runtime_error("Expected a torch.Tensor"); + } + static GL unwrap(pybind11::object obj, int dev_idx) { + if (!pybind11::isinstance(obj)) + throw std::runtime_error("GL unwrap expected a Python list."); + pybind11::list lst = pybind11::cast(obj); + if (dev_idx >= lst.size()) + throw std::runtime_error("Device index out of bounds."); + return *lst[dev_idx].cast>(); + } +}; +template struct from_object { + static PGL make(pybind11::object obj) { + static_assert(!PGL::MULTICAST, "Multicast not yet supported on pyutils. Please initialize the multicast pointer manually."); + if (!pybind11::isinstance(obj)) + throw std::runtime_error("PGL from_object expected a Python list."); + pybind11::list tensors = pybind11::cast(obj); + if (tensors.size() != PGL::num_devices) + throw std::runtime_error("Expected a list of " + std::to_string(PGL::num_devices) + " tensors"); + std::array shape = {1, 1, 1, 1}; + uint64_t data_ptrs[PGL::num_devices]; + for (int i = 0; i < PGL::num_devices; i++) { + auto tensor = tensors[i]; + if (!pybind11::hasattr(tensor, "__class__") || + tensor.attr("__class__").attr("__name__").cast() != "Tensor") + throw std::runtime_error("Expected a list of torch.Tensor"); + if (!tensor.attr("is_contiguous")().cast()) + throw std::runtime_error("Tensor must be contiguous"); + if (tensor.attr("device").attr("type").cast() == "cpu") + throw std::runtime_error("Tensor must be on CUDA device"); + auto py_shape = tensor.attr("shape").cast(); + size_t dims = py_shape.size(); + if (dims > 4) + throw std::runtime_error("Expected Tensor.ndim <= 4"); + for (size_t j = 0; j < dims; ++j) { + if (i == 0) + shape[4 - dims + j] = pybind11::cast(py_shape[j]); + else if (shape[4 - dims + j] != pybind11::cast(py_shape[j])) + throw std::runtime_error("All tensors must have the same shape"); + } + data_ptrs[i] = tensor.attr("data_ptr")().cast(); + } + return make_pgl(data_ptrs, shape[0], shape[1], shape[2], shape[3]); + } + static PGL unwrap(pybind11::object obj, int dev_idx) { + return *obj.cast>(); + } +}; + +static std::unordered_set registered; +template static void register_pyclass(pybind11::module &m) { + if constexpr (ducks::gl::all || ducks::pgl::all) { + std::string _typename = typeid(T).name(); + if (registered.find(_typename) == registered.end()) { + pybind11::class_>(m, _typename.c_str()); + registered.insert(_typename); + } + } +} +template static pybind11::object multigpu_make(pybind11::object obj) { + if constexpr (ducks::gl::all) { + if (!pybind11::isinstance(obj)) + throw std::runtime_error("multigpu_make [GL] expected a Python list."); + pybind11::list lst = pybind11::cast(obj); + std::vector> gls; + for (int i = 0; i < lst.size(); i++) + gls.push_back(std::make_shared(from_object::make(lst[i]))); + return pybind11::cast(gls); + } else if constexpr (ducks::pgl::all) { + return pybind11::cast(std::make_shared(from_object::make(obj))); + } else { + return pybind11::cast(from_object::make(obj)); + } +} + +template concept has_dynamic_shared_memory = requires(T t) { { t.dynamic_shared_memory() } -> std::convertible_to; }; +template concept is_multigpu_globals = requires { + { T::num_devices } -> std::convertible_to; + { T::dev_idx } -> std::convertible_to; +} && T::num_devices >= 1; + +template struct trait; +template struct trait { using member_type = MT; using type = T; }; +template using object = pybind11::object; +template static void bind_kernel(auto m, auto name, auto TGlobal::*... member_ptrs) { + m.def(name, [](object... args, pybind11::kwargs kwargs) { + TGlobal __g__ {from_object::member_type>::make(args)...}; + cudaStream_t raw_stream = nullptr; + if (kwargs.contains("stream")) { + // Extract stream pointer + uintptr_t stream_ptr = kwargs["stream"].attr("cuda_stream").cast(); + raw_stream = reinterpret_cast(stream_ptr); + } + if constexpr (has_dynamic_shared_memory) { + int __dynamic_shared_memory__ = (int)__g__.dynamic_shared_memory(); + cudaFuncSetAttribute(kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, __dynamic_shared_memory__); + kernel<<<__g__.grid(), __g__.block(), __dynamic_shared_memory__, raw_stream>>>(__g__); + } else { + kernel<<<__g__.grid(), __g__.block(), 0, raw_stream>>>(__g__); + } + }); +} +template static void bind_function(auto m, auto name, auto TGlobal::*... member_ptrs) { + m.def(name, [](object... args) { + TGlobal __g__ {from_object::member_type>::make(args)...}; + function(__g__); + }); +} +static void bind_multigpu_boilerplate(auto m) { + m.def("enable_all_p2p_access", [](const std::vector& device_ids) { + int device_count; + CUDACHECK(cudaGetDeviceCount(&device_count)); + if (device_count < device_ids.size()) + throw std::runtime_error("Not enough CUDA devices available"); + for (int i = 0; i < device_ids.size(); i++) { + CUDACHECK(cudaSetDevice(device_ids[i])); + for (int j = 0; j < device_ids.size(); j++) { + if (i == j) continue; + int can_access = 0; + CUDACHECK(cudaDeviceCanAccessPeer(&can_access, device_ids[i], device_ids[j])); + if (!can_access) + throw std::runtime_error("Device " + std::to_string(device_ids[i]) + " cannot access device " + std::to_string(device_ids[j])); + cudaError_t res = cudaDeviceEnablePeerAccess(device_ids[j], 0); + if (res != cudaSuccess && res != cudaErrorPeerAccessAlreadyEnabled) { + CUDACHECK(res); + } + } + } + }); + pybind11::class_>(m, "KittensClub") + .def(pybind11::init([](const std::vector& device_ids) { + int device_count; + CUDACHECK(cudaGetDeviceCount(&device_count)); + if (device_count < device_ids.size()) + throw std::runtime_error("Not enough CUDA devices available"); + auto club = std::make_shared(device_ids.data(), device_ids.size()); + club->execute([&](int dev_idx, cudaStream_t stream) {}); // warmup + return club; + }), pybind11::arg("device_ids")) + .def(pybind11::init([](const std::vector& device_ids, const std::vector& streams) { + int device_count; + CUDACHECK(cudaGetDeviceCount(&device_count)); + if (device_count < device_ids.size()) + throw std::runtime_error("Not enough CUDA devices available"); + if (streams.size() != device_ids.size()) + throw std::runtime_error("Number of streams must match number of devices"); + + std::vector raw_streams(streams.size()); + for (size_t i = 0; i < streams.size(); ++i) { + uintptr_t stream_ptr = streams[i].attr("cuda_stream").cast(); + raw_streams[i] = reinterpret_cast(stream_ptr); + } + + auto club = std::make_shared(device_ids.data(), raw_streams.data(), device_ids.size()); + club->execute([&](int dev_idx, cudaStream_t stream) {}); // warmup + return club; + }), pybind11::arg("device_ids"), pybind11::arg("streams")); +} +template static void bind_multigpu_kernel(auto m, auto name, auto TGlobal::*... member_ptrs) { + static_assert(is_multigpu_globals, "Multigpu globals must have a member num_devices >= 1 and dev_idx"); + (register_pyclass::member_type>(m), ...); + m.def((std::string("make_globals_")+name).c_str(), [](object... args) -> std::vector { + return {multigpu_make::member_type>(args)...}; + }); + m.def(name, [](std::shared_ptr club, object... args) { + std::vector __g__; + for (int i = 0; i < TGlobal::num_devices; i++) { + __g__.emplace_back(from_object::member_type>::unwrap(args, i)...); + __g__.back().dev_idx = i; + } + if constexpr (has_dynamic_shared_memory) { + club->execute([&](int dev_idx, cudaStream_t stream) { + int __dynamic_shared_memory__ = (int)__g__[dev_idx].dynamic_shared_memory(); + cudaFuncSetAttribute(kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, __dynamic_shared_memory__); + kernel<<<__g__[dev_idx].grid(), __g__[dev_idx].block(), __dynamic_shared_memory__, stream>>>(__g__[dev_idx]); + }); + } else { + club->execute([&](int dev_idx, cudaStream_t stream) { + kernel<<<__g__[dev_idx].grid(), __g__[dev_idx].block(), 0, stream>>>(__g__[dev_idx]); + }); + } + }); + // TODO: PGL destructor binding +} + +} // namespace py +} // namespace kittens diff --git a/extra/thunder/cuda/include/pyutils/torch_helpers.cuh b/extra/thunder/cuda/include/pyutils/torch_helpers.cuh new file mode 100644 index 0000000000..4b0f6b34d2 --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/torch_helpers.cuh @@ -0,0 +1,7 @@ +#pragma once + +#include + +#define CHECK_CUDA(x) TORCH_CHECK(x.device().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") +#define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) \ No newline at end of file diff --git a/extra/thunder/cuda/include/pyutils/torchutils.cuh b/extra/thunder/cuda/include/pyutils/torchutils.cuh new file mode 100644 index 0000000000..e2c4ca299c --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/torchutils.cuh @@ -0,0 +1,180 @@ +#pragma once + +#include +#include + +#include "kittens.cuh" +#include "parallel_tensor.cuh" + +namespace kittens { +namespace py { + +template +concept has_min_blocks_per_sm = requires { std::integral_constant{}; }; + +template +consteval int min_blocks_per_sm() { + if constexpr(has_min_blocks_per_sm) + return Config::MIN_BLOCKS_PER_SM; + else + return 1; +} + +template +__global__ +__launch_bounds__(Config::NUM_THREADS, min_blocks_per_sm()) +void global_kernel_unclustered(const __grid_constant__ Globals G) { + Kernel(G); +} + +template +__global__ +__launch_bounds__(Config::NUM_THREADS, min_blocks_per_sm()) +__cluster_dims__(Config::CLUSTER_SIZE) +void global_kernel_clustered(const __grid_constant__ Globals G) { + Kernel(G); +} + +template +static inline void tensor_check(const at::Tensor &t) { + TORCH_CHECK(t.is_cuda(), "Tensor must be on CUDA device") + TORCH_CHECK(t.is_contiguous(), "Tensor must be contiguous") + TORCH_CHECK(t.dim() <= 4, "Expected Tensor.dim() <= 4"); + + if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Char, "Tensor has invalid dtype (expected int8)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Short, "Tensor has invalid dtype (expected int16)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Int, "Tensor has invalid dtype (expected int32)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Long, "Tensor has invalid dtype (expected int64)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Float8_e4m3fn, "Tensor has invalid dtype (expected fp8e4m3)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Float8_e5m2, "Tensor has invalid dtype (expected fp8e5m2)"); +#ifdef KITTENS_BLACKWELL + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Byte, "Tensor has invalid dtype (expected fp8e8m0 represented as uint8)"); +#endif + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::BFloat16, "Tensor has invalid dtype (expected bfloat16)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Half, "Tensor has invalid dtype (expected float16)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Float, "Tensor has invalid dtype (expected float32)"); + } else if constexpr (std::is_same_v) { + TORCH_CHECK(t.dtype() == at::ScalarType::Double, "Tensor has invalid dtype (expected float64)"); + } else { + TORCH_CHECK(false, "Unsupported dtype"); + } +} + +template +static inline void parallel_tensor_check(const TKParallelTensor& t) { + tensor_check(t.data_); + TORCH_CHECK(t.data_.sizes().vec() == t.shape_, "Shape mismatch between TKParallelTensor and the underlying tensor"); + TORCH_CHECK(t.data_.dtype() == t.dtype_, "Dtype mismatch between TKParallelTensor and the underlying tensor"); + TORCH_CHECK(t.raw_ptrs_.size() == PGL::num_devices, "Number of devices mismatch between PGL and TKParallelTensor"); + TORCH_CHECK(t.local_rank_ == t.data_.device().index(), "Current tensor device index mismatch within TKParallelTensor"); + TORCH_CHECK(t.local_world_size_ == PGL::num_devices, "Number of devices mismatch between PGL and TKParallelTensor"); + TORCH_CHECK(t.multicast_ == PGL::multicast, "Multicast mismatch between PGL and TKParallelTensor"); + TORCH_CHECK(t.raw_ptrs_[t.local_rank_] == reinterpret_cast(t.data_.data_ptr()), "Current tensor data pointer not found in TKParallelTensor's raw_ptrs_"); +} + +template +static inline GL tensor_to_gl(const at::Tensor &t) { + tensor_check(t); + + std::array shape = {1, 1, 1, 1}; + for (int i = 0; i < static_cast(t.dim()); ++i) + shape[4 - t.dim() + i] = static_cast(t.size(i)); + + uint64_t data_ptr = reinterpret_cast(t.data_ptr()); + + return ::kittens::make_gl(data_ptr, shape[0], shape[1], shape[2], shape[3]); +} + +template +static inline PGL parallel_tensor_to_pgl(TKParallelTensor &t) { + parallel_tensor_check(t); + + std::array shape = {1, 1, 1, 1}; + for (int i = 0; i < static_cast(t.data_.dim()); ++i) { + shape[4 - t.data_.dim() + i] = static_cast(t.data_.size(i)); + } + + if constexpr (PGL::multicast) + return ::kittens::make_pgl( + reinterpret_cast(t.multicast_ptr_), reinterpret_cast(t.raw_ptrs_.data()), shape[0], shape[1], shape[2], shape[3]); + else + return ::kittens::make_pgl( + reinterpret_cast(t.raw_ptrs_.data()), shape[0], shape[1], shape[2], shape[3]); +} + +template +static inline GL make_fake_gl(const int batch, const int depth, const int rows, const int cols) { + return ::kittens::make_gl(reinterpret_cast(nullptr), batch, depth, rows, cols); +} + +static inline void _device_check(const at::Tensor& first, const at::Tensor& second) { + TORCH_CHECK(first.device() == second.device(), "All tensors must be on the same device"); +} + +template +static inline void device_check(const T1& first, const Ts&... rest) { + (_device_check(first, rest), ...); +} + +static inline void _parallel_tensor_check(const TKParallelTensor& first, const TKParallelTensor& second) { + TORCH_CHECK(first.local_rank_ == second.local_rank_, "All parallel tensors must have the same local_rank"); + TORCH_CHECK(first.local_world_size_ == second.local_world_size_, "All parallel tensors must have the same local_world_size"); +} + +template +static inline void parallel_tensor_check(const T1& first, const Ts&... rest) { + (_parallel_tensor_check(first, rest), ...); +} + +template +concept static_grid = requires { Config::NUM_BLOCKS; }; + +template +concept static_block = requires { Config::NUM_THREADS; }; + +template +concept static_dynamic_shared_memory = requires { Config::DYNAMIC_SHARED_MEMORY; }; + +template +static inline void launch_kernel(const Globals &G) { + dim3 grid; + if constexpr (static_grid) + grid = dim3{Config::NUM_BLOCKS, 1, 1}; + else + grid = G.grid(); + + dim3 block; + if constexpr (static_block) + block = dim3{Config::NUM_THREADS, 1, 1}; + else + block = G.block(); + + int dynamic_shared_memory; + if constexpr (static_dynamic_shared_memory) + dynamic_shared_memory = static_cast(Config::DYNAMIC_SHARED_MEMORY); + else + dynamic_shared_memory = G.dynamic_shared_memory(); + + cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + + if constexpr (Config::CLUSTER_SIZE <= 1) { + CUDACHECK(cudaFuncSetAttribute(global_kernel_unclustered, cudaFuncAttributeMaxDynamicSharedMemorySize, dynamic_shared_memory)); + global_kernel_unclustered<<>>(G); + } else { + CUDACHECK(cudaFuncSetAttribute(global_kernel_clustered, cudaFuncAttributeMaxDynamicSharedMemorySize, dynamic_shared_memory)); + global_kernel_clustered<<>>(G); + } +} + +} // namespace py +} // namespace kittens diff --git a/extra/thunder/cuda/include/pyutils/util.cuh b/extra/thunder/cuda/include/pyutils/util.cuh new file mode 100644 index 0000000000..0f92c6d905 --- /dev/null +++ b/extra/thunder/cuda/include/pyutils/util.cuh @@ -0,0 +1,19 @@ +#pragma once + +#include "../ops/ops.cuh" +#include "club.cuh" +#include + +#define CHECK_CUDA_ERROR(val) check((val), #val, __FILE__, __LINE__) +template +void check(T err, char const* const func, char const* const file, + int const line) +{ + if (err != cudaSuccess) + { + std::cerr << "CUDA Runtime Error at: " << file << ":" << line + << std::endl; + std::cerr << cudaGetErrorString(err) << " " << func << std::endl; + //std::exit(EXIT_FAILURE); + } +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/device/device.cuh b/extra/thunder/cuda/include/types/device/device.cuh new file mode 100644 index 0000000000..069d4af899 --- /dev/null +++ b/extra/thunder/cuda/include/types/device/device.cuh @@ -0,0 +1,12 @@ +/** + * @file + * @brief An aggregate header file for all the device types defined by ThunderKittens. + */ + +#pragma once + +#if defined(KITTENS_HOPPER) || defined(KITTENS_BLACKWELL) +#include "ipc.cuh" +#include "pgl.cuh" +#include "vmm.cuh" +#endif diff --git a/extra/thunder/cuda/include/types/device/ipc.cuh b/extra/thunder/cuda/include/types/device/ipc.cuh new file mode 100644 index 0000000000..6c3f09a8d5 --- /dev/null +++ b/extra/thunder/cuda/include/types/device/ipc.cuh @@ -0,0 +1,195 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "../../common/common.cuh" +#include "vmm.cuh" + +namespace kittens { +namespace ducks { +namespace ipc { +namespace handle { + +struct identifier {}; + +template concept all = requires { + typename T::identifier; +} && std::is_same_v; + +} // namespace handle +} // namespace ipc +} // namespace ducks + +namespace detail { +namespace ipc { + +enum flavor { + LEGACY = 0, + VMM = 1 +}; + +template +struct handle; + +template<> +struct handle { + using identifier = ducks::ipc::handle::identifier; + static constexpr flavor flavor_ = flavor::LEGACY; + cudaIpcMemHandle_t handle_ {}; +}; + +template<> +struct handle { + using identifier = ducks::ipc::handle::identifier; + static constexpr flavor flavor_ = flavor::VMM; + int handle_; +}; + +__host__ inline static void check_support(const int device_id) { + CUdevice device; + CUCHECK(cuDeviceGet(&device, device_id)); + + int ipc_supported = 0; + CUDACHECK(cudaDeviceGetAttribute(&ipc_supported, cudaDevAttrIpcEventSupport, device_id)); + int ipc_handle_supported = 0; + CUCHECK(cuDeviceGetAttribute(&ipc_handle_supported, CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR_SUPPORTED, device)); + + if (!ipc_supported || !ipc_handle_supported) + throw std::runtime_error("CUDA IPC is not supported on this device"); +} + +template +__host__ inline static void export_handle( + IPC_HANDLE *ipc_handle, + void *ptr +) { + if constexpr (IPC_HANDLE::flavor_ == flavor::LEGACY) { + CUDACHECK(cudaIpcGetMemHandle(&ipc_handle->handle_, ptr)); + } else if constexpr (IPC_HANDLE::flavor_ == flavor::VMM) { + CUmemGenericAllocationHandle memory_handle; + detail::vmm::vm_retrieve_handle(&memory_handle, ptr); + // ** Important: this handle (FD) must be manually closed by the user ** + CUCHECK(cuMemExportToShareableHandle(&ipc_handle->handle_, memory_handle, detail::vmm::HANDLE_TYPE, 0)); + detail::vmm::vm_free(memory_handle); + } else { + throw std::runtime_error("Invalid IPC handle type"); + } +} + +template +__host__ inline static void export_handle( + IPC_HANDLE *ipc_handle, + CUmemGenericAllocationHandle &memory_handle +) { + if constexpr (IPC_HANDLE::flavor_ == flavor::VMM) { + CUCHECK(cuMemExportToShareableHandle(&ipc_handle->handle_, memory_handle, detail::vmm::HANDLE_TYPE, 0)); + } else { + throw std::runtime_error("Invalid IPC handle type"); + } +} + +template +__host__ inline static void import_handle ( + void **ptr, + IPC_HANDLE &ipc_handle, + const size_t size, + int local_world_size +) { + if constexpr (IPC_HANDLE::flavor_ == flavor::LEGACY) { + CUDACHECK(cudaIpcOpenMemHandle(ptr, ipc_handle.handle_, cudaIpcMemLazyEnablePeerAccess)); // this is the only flag supported + } else if constexpr (IPC_HANDLE::flavor_ == flavor::VMM) { + CUmemGenericAllocationHandle memory_handle; + CUCHECK(cuMemImportFromShareableHandle(&memory_handle, reinterpret_cast(static_cast(ipc_handle.handle_)), detail::vmm::HANDLE_TYPE)); + detail::vmm::vm_map(ptr, memory_handle, size); + detail::vmm::vm_set_access(*ptr, size, local_world_size); + detail::vmm::vm_free(memory_handle); + close(ipc_handle.handle_); // close fd immediately + ipc_handle.handle_ = -1; + } else { + throw std::runtime_error("Invalid IPC handle type"); + } +} + +template +__host__ inline static void import_handle ( + CUmemGenericAllocationHandle *memory_handle, + IPC_HANDLE &ipc_handle, + const size_t size, + int local_world_size +) { + if constexpr (IPC_HANDLE::flavor_ == flavor::VMM) { + CUCHECK(cuMemImportFromShareableHandle(memory_handle, reinterpret_cast(static_cast(ipc_handle.handle_)), detail::vmm::HANDLE_TYPE)); + close(ipc_handle.handle_); // close fd immediately + ipc_handle.handle_ = -1; + } else { + throw std::runtime_error("Invalid IPC handle type"); + } +} + +template +__host__ inline static void free_handle( + void *ptr, + const size_t size +) { + if constexpr (_flavor == flavor::LEGACY) { + CUDACHECK(cudaIpcCloseMemHandle(ptr)); + } else if constexpr (_flavor == flavor::VMM) { + detail::vmm::vm_unmap(ptr, size); + } else { + throw std::runtime_error("Invalid IPC handle type"); + } +} + +__host__ inline static void enable_all_peer_access(int num_devices) { + int num_available_devices; + CUCHECK(cuDeviceGetCount(&num_available_devices)); + if (num_available_devices < num_devices) + throw std::runtime_error("Not enough GPUs available"); + + std::vector devices(num_devices); + std::vector contexts(num_devices); + + for (int i = 0; i < num_devices; i++) { + CUCHECK(cuDeviceGet(&devices[i], i)); + CUCHECK(cuCtxCreate(&contexts[i], 0, devices[i])); + } + + for (int i = 0; i < num_devices; i++) { + int device_compute_mode; + CUCHECK(cuDeviceGetAttribute(&device_compute_mode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, devices[i])); + if (device_compute_mode != CU_COMPUTEMODE_DEFAULT) + throw std::runtime_error("Device is in an unsupported compute mode"); + + int vmm_supported = 0; + CUCHECK(cuDeviceGetAttribute(&vmm_supported, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED, devices[i])); + if (!vmm_supported) + throw std::runtime_error("Device does not support CUDA VMM"); + + int ipc_handle_supported; + CUCHECK(cuDeviceGetAttribute(&ipc_handle_supported, CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR_SUPPORTED, devices[i])); + if (!ipc_handle_supported) + throw std::runtime_error("Device does not support IPC handles"); + + for (int j = 0; j < num_devices; j++) { + if (i == j) continue; + int can_access_peer; + CUCHECK(cuDeviceCanAccessPeer(&can_access_peer, devices[i], devices[j])); + if (!can_access_peer) + throw std::runtime_error("Device cannot access peer device"); + CUCHECK(cuCtxSetCurrent(contexts[i])); + CUCHECK(cuCtxEnablePeerAccess(contexts[j], 0)); + } + } + + for (size_t i = 0; i < contexts.size(); ++i) + CUCHECK(cuCtxDestroy(contexts[i])); +} + +} // namespace ipc +} // namespace detail +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/device/pgl.cuh b/extra/thunder/cuda/include/types/device/pgl.cuh new file mode 100644 index 0000000000..f0f7910603 --- /dev/null +++ b/extra/thunder/cuda/include/types/device/pgl.cuh @@ -0,0 +1,173 @@ +/** + * @file + * @brief Templated layouts for parallel global memory. + */ + +#pragma once + +#include "../../common/common.cuh" +#include "../shared/shared.cuh" +#include "../global/global.cuh" + +namespace kittens { + +/* ---------- Parallel global layout descriptor ---------- */ + +namespace ducks { +namespace pgl { + +struct identifier {}; + +/** + * @brief Concept for all parallel global layouts. + * @tparam T The type to check against the concept requirements. + * + * Requires: + * - T has a nested type identifier that is the same as ducks::pgl::identifier. + */ +template concept all = requires { + typename T::identifier; +} && std::is_same_v; + +} // namespace pgl +} // namespace ducks + +/** + * @brief Parallel global layout. Represents a region of data spread across multiple devices. + * @tparam GL The underlying global layout on each device. + * @tparam NUM_DEVICES The number of GPU devices. + * @tparam MULTICAST Whether the multicast object should be initialized by the caller. + * @tparam TMA_Types The types of TMA descriptors to use for the multicast locations. + Only valid if MULTICAST is true. + */ +template +struct pgl { + using identifier = ducks::pgl::identifier; + using GL = _GL; + using T = GL::dtype; + using dtype = T; + + static constexpr int num_devices = NUM_DEVICES; + static constexpr bool multicast = MULTICAST; + + T *mc_ptr; // multicast pointer; nullptr if MULTICAST is false + GL gls[NUM_DEVICES]; + + detail::descriptor_dict tma_descs; + + __host__ __device__ const GL &operator[](int idx) const { return gls[idx]; } + __device__ inline T* mc_ptr_at(const coord &idx) const { + static_assert(MULTICAST, "Multicast is not enabled for this PGL."); + const GL &gl = gls[0]; // all gls have the same shape + return &mc_ptr[((idx.b * gl.depth() + idx.d) * gl.rows() + idx.r) * gl.cols() + idx.c]; + } + + __host__ inline pgl(T **_data, // an array of NUM_DEVICES pointers to the data on each device + ducks::gl::make_arg_t _batch, + ducks::gl::make_arg_t _depth, + ducks::gl::make_arg_t _rows, + ducks::gl::make_arg_t _cols) : + pgl(std::make_index_sequence{}, _data, _batch, _depth, _rows, _cols) { } + + __host__ inline pgl(T *_mc_ptr, // multicast pointer, initialized by the caller + T **_data, // an array of NUM_DEVICES pointers to the data on each device + ducks::gl::make_arg_t _batch, + ducks::gl::make_arg_t _depth, + ducks::gl::make_arg_t _rows, + ducks::gl::make_arg_t _cols) : + pgl(std::make_index_sequence{}, _mc_ptr, _data, _batch, _depth, _rows, _cols) { } + + template + __host__ inline pgl(std::index_sequence, + T **_data, + ducks::gl::make_arg_t _batch, + ducks::gl::make_arg_t _depth, + ducks::gl::make_arg_t _rows, + ducks::gl::make_arg_t _cols) : + mc_ptr(nullptr), gls{GL(_data[I], _batch, _depth, _rows, _cols)...} { + static_assert(!MULTICAST, "Multicast pointer not passed to multicast-enabled PGL."); + } + + template + __host__ inline pgl(std::index_sequence, + T *_mc_ptr, + T **_data, + ducks::gl::make_arg_t _batch, + ducks::gl::make_arg_t _depth, + ducks::gl::make_arg_t _rows, + ducks::gl::make_arg_t _cols) : + mc_ptr(_mc_ptr), gls{GL(_data[I], _batch, _depth, _rows, _cols)...} { + static_assert(MULTICAST, "Multicast pointer passed to multicast-disabled PGL."); + tma_descs = detail::descriptor_dict( + mc_ptr, gls[0].batch_internal, gls[0].depth_internal, gls[0].rows_internal, gls[0].cols_internal); + } + + template + __device__ inline const CUtensorMap* get_tma() const { + return tma_descs.template get(); + } + + __host__ __device__ inline auto batch() const { return gls[0].batch(); } + __host__ __device__ inline auto depth() const { return gls[0].depth(); } + __host__ __device__ inline auto rows() const { return gls[0].rows(); } + __host__ __device__ inline auto cols() const { return gls[0].cols(); } + __host__ __device__ inline size_t numel() const { return static_cast(batch()) * depth() * rows() * cols(); } + + template __device__ inline size_t shape() const { return gls[0].template shape(); } + template __device__ inline size_t stride() const { return gls[0].template stride(); } +}; + +template __host__ inline PGL make_pgl( + uint64_t *data, int b, int d, int r, int c +) { + if constexpr (safe) { + if (PGL::GL::__b__ > 0 && b != PGL::GL::__b__) { + throw std::runtime_error("Batch dimension mismatch. Expected: " + std::to_string(PGL::GL::__b__) + ", Got: " + std::to_string(b)); + } + if (PGL::GL::__d__ > 0 && d != PGL::GL::__d__) { + throw std::runtime_error("Depth dimension mismatch. Expected: " + std::to_string(PGL::GL::__d__) + ", Got: " + std::to_string(d)); + } + if (PGL::GL::__r__ > 0 && r != PGL::GL::__r__) { + throw std::runtime_error("Row dimension mismatch. Expected: " + std::to_string(PGL::GL::__r__) + ", Got: " + std::to_string(r)); + } + if (PGL::GL::__c__ > 0 && c != PGL::GL::__c__) { + throw std::runtime_error("Column dimension mismatch. Expected: " + std::to_string(PGL::GL::__c__) + ", Got: " + std::to_string(c)); + } + } + return PGL( + reinterpret_cast(data), + make_unsafe_gl_arg(b), + make_unsafe_gl_arg(d), + make_unsafe_gl_arg(r), + make_unsafe_gl_arg(c) + ); +} + +template __host__ inline PGL make_pgl( + uint64_t mc_ptr, uint64_t *data, int b, int d, int r, int c +) { + if constexpr (safe) { + if (PGL::GL::__b__ > 0 && b != PGL::GL::__b__) { + throw std::runtime_error("Batch dimension mismatch. Expected: " + std::to_string(PGL::GL::__b__) + ", Got: " + std::to_string(b)); + } + if (PGL::GL::__d__ > 0 && d != PGL::GL::__d__) { + throw std::runtime_error("Depth dimension mismatch. Expected: " + std::to_string(PGL::GL::__d__) + ", Got: " + std::to_string(d)); + } + if (PGL::GL::__r__ > 0 && r != PGL::GL::__r__) { + throw std::runtime_error("Row dimension mismatch. Expected: " + std::to_string(PGL::GL::__r__) + ", Got: " + std::to_string(r)); + } + if (PGL::GL::__c__ > 0 && c != PGL::GL::__c__) { + throw std::runtime_error("Column dimension mismatch. Expected: " + std::to_string(PGL::GL::__c__) + ", Got: " + std::to_string(c)); + } + } + return PGL( + reinterpret_cast(mc_ptr), + reinterpret_cast(data), + make_unsafe_gl_arg(b), + make_unsafe_gl_arg(d), + make_unsafe_gl_arg(r), + make_unsafe_gl_arg(c) + ); +} + +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/device/vmm.cuh b/extra/thunder/cuda/include/types/device/vmm.cuh new file mode 100644 index 0000000000..8b8d274ec2 --- /dev/null +++ b/extra/thunder/cuda/include/types/device/vmm.cuh @@ -0,0 +1,180 @@ +#pragma once + +#include +#include +#include + +#include "../../common/common.cuh" + +namespace kittens { +namespace detail { +namespace vmm { + +// Intra-node shareable handle type +// This makes the handle shareable with cuMemExportToShareableHandle/cuMemImportFromShareableHandle +static constexpr CUmemAllocationHandleType HANDLE_TYPE = CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR; + +typedef CUmemGenericAllocationHandle handle; + +__host__ inline static void vm_alloc( + CUmemGenericAllocationHandle *handle, + size_t *allocated_size, + const size_t size, + const int device_id +) { + CUmemAllocationProp prop = {}; + prop.location.id = device_id; + prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE; + prop.requestedHandleTypes = HANDLE_TYPE; + prop.type = CU_MEM_ALLOCATION_TYPE_PINNED; + + size_t granularity; + CUCHECK(cuMemGetAllocationGranularity(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED)); + *allocated_size = (size + granularity - 1) / granularity * granularity; // round-up + + CUCHECK(cuMemCreate(handle, *allocated_size, &prop, 0)); +} + +__host__ inline static void vm_map( + void **ptr, + const CUmemGenericAllocationHandle &handle, + const size_t size +) { + CUdeviceptr device_ptr; + CUCHECK(cuMemAddressReserve(&device_ptr, size, 0, 0, 0)); + CUCHECK(cuMemMap(device_ptr, size, 0, handle, 0)); + *ptr = (void *)device_ptr; +} + +__host__ inline static void vm_set_access( + void *ptr, + const size_t size, + const int num_devices +) { + std::vector descs(num_devices); + for (int i = 0; i < num_devices; i++) { + descs[i].location.id = i; + descs[i].location.type = CU_MEM_LOCATION_TYPE_DEVICE; + descs[i].flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE; + } + CUCHECK(cuMemSetAccess(reinterpret_cast(ptr), size, descs.data(), num_devices)); +} + +__host__ inline static void vm_retrieve_handle( + CUmemGenericAllocationHandle *handle, + void *ptr +) { + // Every call to this requires a corresponding call to cuMemRelease + CUCHECK(cuMemRetainAllocationHandle(handle, ptr)); +} + +__host__ inline static void vm_unmap( + void *ptr, + const size_t size +) { + CUCHECK(cuMemUnmap(reinterpret_cast(ptr), size)); + CUCHECK(cuMemAddressFree(reinterpret_cast(ptr), size)); +} + +__host__ inline static void vm_free(CUmemGenericAllocationHandle &handle) { + // It is recommended to free the handle ASAP; the backing memory will + // only be freed when all handles AND address mappings are released + CUCHECK(cuMemRelease(handle)); +} + +__host__ inline static void vm_alloc_map_set_access( + void **ptr, + size_t *allocated_size, + const size_t size, + const int device_id, + const int num_devices +) { + CUmemGenericAllocationHandle handle; + vm_alloc(&handle, allocated_size, size, device_id); + vm_map(ptr, handle, *allocated_size); + vm_set_access(*ptr, *allocated_size, num_devices); + vm_free(handle); // release the handle ASAP +} + +__host__ inline static void multicast_check(const int device_id) { + CUdevice device; + CUCHECK(cuDeviceGet(&device, device_id)); + + int multicast_supported; + CUresult result = cuDeviceGetAttribute( + &multicast_supported, + CU_DEVICE_ATTRIBUTE_MULTICAST_SUPPORTED, + device + ); + + if (!multicast_supported) + throw std::runtime_error("Device does not support multicast"); +} + +__host__ inline static void multicast_create_handle( + CUmemGenericAllocationHandle *handle, + size_t *allocated_size, + const size_t size, + const int num_devices +) { + if (num_devices <= 1) + throw std::runtime_error("Multicast requires at least 2 devices"); + + CUmulticastObjectProp prop = {}; + prop.numDevices = num_devices; + prop.handleTypes = HANDLE_TYPE; + + size_t granularity; + CUCHECK(cuMulticastGetGranularity(&granularity, &prop, CU_MULTICAST_GRANULARITY_RECOMMENDED)); + *allocated_size = (size + granularity - 1) / granularity * granularity; + prop.size = *allocated_size; + + // After this, the handle must be shared with all processes through MPI, KittensBroker, etc. + cuMulticastCreate(handle, &prop); +} + +__host__ inline static void multicast_bind_device( + const CUmemGenericAllocationHandle &handle, + const int device_id +) { + // All processes must sync after this, before binding any memory + CUdevice device; + CUCHECK(cuDeviceGet(&device, device_id)); + CUCHECK(cuMulticastAddDevice(handle, device)); +} + +__host__ inline static void multicast_bind_memory( + const CUmemGenericAllocationHandle &multicast_handle, + const CUmemGenericAllocationHandle &memory_handle, + const size_t size +) { + // All processes should finish adding device before calling this function + CUCHECK(cuMulticastBindMem(multicast_handle, 0, memory_handle, 0, size, 0)); +} + +__host__ inline static void multicast_bind_address( + const CUmemGenericAllocationHandle &multicast_handle, + void *ptr, + const size_t size +) { + // All processes should finish adding device before calling this function + CUmemGenericAllocationHandle memory_handle; + vm_retrieve_handle(&memory_handle, ptr); + multicast_bind_memory(multicast_handle, memory_handle, size); + vm_free(memory_handle); +} + +__host__ inline static void multicast_unbind_device( + const CUmemGenericAllocationHandle &handle, + const size_t size, + const int device_id +) { + // Unbinding memory is not needed + CUdevice device; + CUCHECK(cuDeviceGet(&device, device_id)); + CUCHECK(cuMulticastUnbind(handle, device, 0, size)); +} + +} // namespace vmm +} // namespace detail +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/global/cgl.cuh b/extra/thunder/cuda/include/types/global/cgl.cuh new file mode 100644 index 0000000000..67565c02c6 --- /dev/null +++ b/extra/thunder/cuda/include/types/global/cgl.cuh @@ -0,0 +1,56 @@ +/** + * @file + * @brief Templated layouts for complex global memory. + */ + +#pragma once + +#include "../../common/common.cuh" +#include "../shared/cst.cuh" +#include "gl.cuh" +#include "util.cuh" +#ifdef KITTENS_HOPPER +#include "tma.cuh" +#endif + +namespace kittens { + +/* ---------- Global layout descriptor ---------- */ + +namespace ducks { +namespace cgl { +struct identifier {}; +} +} + +// namespace detail { +// template concept tile = ducks::cst::all || ducks::crt::all; +// template concept vec = ducks::csv::all || ducks::crv::all; +// } + +template +struct cgl { + using identifier = ducks::cgl::identifier; + using component = _GL; + using T = component::T; + using T2 = component::T2; + using dtype = component::dtype; + component real, imag; +}; + +namespace ducks { +namespace cgl { +/** +* @brief Concept for all complex global layouts. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as ducks::cgl::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::cgl::identifier +} +} + +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/global/gl.cuh b/extra/thunder/cuda/include/types/global/gl.cuh new file mode 100644 index 0000000000..cbbc3f3f9d --- /dev/null +++ b/extra/thunder/cuda/include/types/global/gl.cuh @@ -0,0 +1,225 @@ +/** + * @file + * @brief Templated layouts for global memory. + */ + +#pragma once + +#include "../../common/common.cuh" +#include "../shared/shared.cuh" +#include "util.cuh" +#ifdef KITTENS_HOPPER +#include +#include "tma.cuh" +#endif + +namespace kittens { + +/* ---------- Global layout axes ---------- */ + +struct dim { + static constexpr int BATCH = 0; + static constexpr int DEPTH = 1; + static constexpr int ROW = 2; + static constexpr int COL = 3; +}; + +/* ---------- Associative dictionary for global layouts ---------- */ + +#ifdef KITTENS_HOPPER +namespace ducks { +namespace tma { +namespace descriptor { +struct identifier {}; +template concept all = requires { + typename T::identifier; +} && std::is_same_v; +} // namespace descriptor +} // namespace tma +} // namespace ducks +namespace detail { +namespace tma { +template struct descriptor_copy_helper {}; +template struct descriptor_copy_helper<_T> { static constexpr int value = _T::axis; using T = _T::T; static constexpr bool swizzle_flag = _T::swizzle_flag; }; +template struct descriptor_copy_helper<_T> { static constexpr int value = 2; using T = _T; static constexpr bool swizzle_flag = true; }; +template struct descriptor_copy_helper<_T> { static constexpr int value = -1; using T = _T; static constexpr bool swizzle_flag = true; }; +template using descriptor_copy_helper_t = descriptor_copy_helper::T; +template static constexpr int descriptor_copy_helper_v = descriptor_copy_helper::value; +template static constexpr bool descriptor_copy_helper_swizzle_flag = descriptor_copy_helper::swizzle_flag; +} // namespace tma +} // namespace detail +namespace tma { +template struct descriptor { + using identifier = ducks::tma::descriptor::identifier; + using T = detail::tma::descriptor_copy_helper_t<_T>; + static_assert(ducks::st::all || ducks::sv::all || ducks::tma::descriptor::all, "Must be a shared TK type to generate a TMA descriptor."); + static constexpr int axis = ( + ducks::tma::descriptor::all<_T> ? detail::tma::descriptor_copy_helper_v<_T> : // if a copy, inherit the axis from the original descriptor. + (_axis != -9999) ? _axis : detail::tma::descriptor_copy_helper_v<_T>); // if a default value was provided, use it. + static_assert((kittens::ducks::st::all && axis >= 0 && axis <= 2) || (kittens::ducks::sv::all && axis == -1), "Internal template error detected."); + static constexpr bool swizzle_flag = ducks::tma::descriptor::all<_T> ? detail::tma::descriptor_copy_helper_swizzle_flag<_T> : _swizzle_flag; +}; +} // namespace tma +#endif + +namespace detail { +template +struct descriptor_dict { + __host__ __device__ descriptor_dict() {} + template __host__ __device__ descriptor_dict(T _, int b, int d, int r, int c) {} + __host__ __device__ descriptor_dict(const descriptor_dict &other) {} +#ifdef KITTENS_HOPPER + template __device__ const CUtensorMap* get() const { + static_assert( + std::is_same_v && std::is_same_v, + "SKILL ISSUE: Requested a TMA descriptor for a type not initialized in the global layout." + ); + } +#endif +}; + +#ifdef KITTENS_HOPPER +template +struct descriptor_dict<_T, Args...> { + static_assert(ducks::sv::all<_T> || ducks::st::all<_T> || ducks::tma::descriptor::all<_T>, "Must be a shared TK type to generate a TMA descriptor."); + using DESC = kittens::tma::descriptor<_T>; // copy or initialize with a default value + CUtensorMap tma_desc; + descriptor_dict other_descs; + __host__ __device__ descriptor_dict() {} + __host__ __device__ descriptor_dict(typename DESC::T::dtype *data, int b, int d, int r, int c): other_descs(data, b, d, r, c) { + kittens::detail::tma::create_tensor_map(&tma_desc, data, b, d, r, c); + } + __host__ __device__ inline descriptor_dict(const descriptor_dict &other) : + tma_desc(other.tma_desc), other_descs(other.other_descs) {} + template __device__ inline const CUtensorMap* get() const { + if constexpr (std::is_same_v && DESC::axis == axis) { return &tma_desc; } + else { return other_descs.template get(); } + } +}; +#endif +} + +/* ---------- Global layout descriptor ---------- */ + +namespace ducks { +namespace gl { +struct identifier {}; +} +} + +template +struct gl { + using identifier = ducks::gl::identifier; + + using T = base_types::packing<_T>::unpacked_type; + using T2 = base_types::packing<_T>::packed_type; + using dtype = T; + + T* raw_ptr; + + static constexpr int __b__ = b, __d__ = d, __r__ = r, __c__ = c; // Not to be touched by the user. + + ducks::gl::make_dim_t batch_internal; + ducks::gl::make_dim_t depth_internal; + ducks::gl::make_dim_t rows_internal; + ducks::gl::make_dim_t cols_internal; + + template __device__ __host__ static constexpr std::enable_if_t<(B > 0), int> batch() { return B; } + template __device__ __host__ std::enable_if_t<(B == -1), int> batch() const { return batch_internal; } + template __device__ __host__ static constexpr std::enable_if_t<(D > 0), int> depth() { return D; } + template __device__ __host__ std::enable_if_t<(D == -1), int> depth() const { return depth_internal; } + template __device__ __host__ static constexpr std::enable_if_t<(R > 0), int> rows() { return R; } + template __device__ __host__ std::enable_if_t<(R == -1), int> rows() const { return rows_internal; } + template __device__ __host__ static constexpr std::enable_if_t<(C > 0), int> cols() { return C; } + template __device__ __host__ std::enable_if_t<(C == -1), int> cols() const { return cols_internal; } + + detail::descriptor_dict tma_descs; + + __host__ __device__ inline gl(T *_data, + ducks::gl::make_arg_t _batch, + ducks::gl::make_arg_t _depth, + ducks::gl::make_arg_t _rows, + ducks::gl::make_arg_t _cols) : + raw_ptr(_data), batch_internal(_batch), depth_internal(_depth), rows_internal(_rows), cols_internal(_cols) { + tma_descs = detail::descriptor_dict(raw_ptr, batch_internal, depth_internal, rows_internal, cols_internal); + } + __host__ __device__ inline gl(const gl &other) : + raw_ptr(other.raw_ptr), batch_internal(other.batch_internal), depth_internal(other.depth_internal), rows_internal(other.rows_internal), cols_internal(other.cols_internal), tma_descs(other.tma_descs) {} +#ifdef KITTENS_HOPPER + template __device__ inline const CUtensorMap* get_tma() const { + return tma_descs.template get(); + } +#endif + __device__ inline T& operator[](const coord &idx) const { // yes I am abusing the const qualifier here a bit. + return raw_ptr[((idx.b*depth() + idx.d)*rows() + idx.r)*cols() + idx.c]; + } + template __device__ inline size_t shape() const { + static_assert(axis==0 || axis==1 || axis==2 || axis==3, "Axis must be 0, 1, 2, or 3."); + if constexpr (axis==0) { return size_t(batch()); } + else if constexpr (axis==1) { return size_t(depth()); } + else if constexpr (axis==2) { return size_t(rows()); } + else if constexpr (axis==3) { return size_t(cols()); } + } + template __device__ inline size_t stride() const { + static_assert(axis==0 || axis==1 || axis==2 || axis==3, "Axis must be 0, 1, 2, or 3."); + if constexpr (axis==0) { return depth()*rows()*cols(); } + else if constexpr (axis==1) { return rows()*cols(); } + else if constexpr (axis==2) { return cols(); } + else if constexpr (axis==3) { return 1; } + } +}; + +template using gl3 = gl<_T, 1, d, r, c, TMA_Types...>; +template using gl2 = gl<_T, 1, 1, r, c, TMA_Types...>; +template using gl1 = gl<_T, 1, 1, 1, c, TMA_Types...>; + +namespace ducks { +namespace gl { +/** +* @brief Concept for all global layouts. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as ducks::gl::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::gl::identifier +} +} + +// Structs for initializing global layouts automatically. +// struct unsafe_gl { +// uint64_t data; +// int b, d, r, c; +// unsafe_gl(uint64_t data, int b, int d, int r, int c) : data(data), b(b), d(d), r(r), c(c) {} +// }; +template auto make_unsafe_gl_arg(int param) { // typename std::conditional_t<(N < 0), std::nullptr_t, int> + if constexpr (N > 0) { return nullptr; } + else { return param; } +} +template __host__ inline GL make_gl(uint64_t data, int b, int d, int r, int c) { + if constexpr (safe) { + if(GL::__b__ > 0 && b != GL::__b__) { + throw std::runtime_error("Batch dimension mismatch. Expected: " + std::to_string(GL::__b__) + ", Got: " + std::to_string(b)); + } + if(GL::__d__ > 0 && d != GL::__d__) { + throw std::runtime_error("Depth dimension mismatch. Expected: " + std::to_string(GL::__d__) + ", Got: " + std::to_string(d)); + } + if(GL::__r__ > 0 && r != GL::__r__) { + throw std::runtime_error("Row dimension mismatch. Expected: " + std::to_string(GL::__r__) + ", Got: " + std::to_string(r)); + } + if(GL::__c__ > 0 && c != GL::__c__) { + throw std::runtime_error("Column dimension mismatch. Expected: " + std::to_string(GL::__c__) + ", Got: " + std::to_string(c)); + } + } + return GL( + reinterpret_cast(data), + make_unsafe_gl_arg(b), + make_unsafe_gl_arg(d), + make_unsafe_gl_arg(r), + make_unsafe_gl_arg(c) + ); +} + +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/global/global.cuh b/extra/thunder/cuda/include/types/global/global.cuh new file mode 100644 index 0000000000..00d894626b --- /dev/null +++ b/extra/thunder/cuda/include/types/global/global.cuh @@ -0,0 +1,13 @@ +/** + * @file + * @brief An aggregate header file for all the global types defined by ThunderKittens. + */ + +#pragma once + +#ifdef KITTENS_HOPPER +#include "tma.cuh" +#endif +#include "util.cuh" +#include "gl.cuh" +#include "cgl.cuh" diff --git a/extra/thunder/cuda/include/types/global/tma.cuh b/extra/thunder/cuda/include/types/global/tma.cuh new file mode 100644 index 0000000000..4ffa9ba0bd --- /dev/null +++ b/extra/thunder/cuda/include/types/global/tma.cuh @@ -0,0 +1,428 @@ +#pragma once + +#include +#include +#include +#include // for std::hash +#include +#include +#include "../../common/common.cuh" +#include "../shared/shared.cuh" + +namespace kittens { +namespace detail { +namespace tma { + +__host__ static inline std::string format_tma_error( + const char* error_type, + const char* error_string, + int batch, int depth, int rows, int cols, + CUtensorMap* tma_map, + CUtensorMapDataType tma_format, + uint32_t tma_dim, + void* global_addr, + const uint64_t* gmem_shape, + const uint64_t* gmem_stride, + const uint32_t* smem_shape, + const uint32_t* smem_stride, + size_t gmem_shape_size, + size_t gmem_stride_size, + size_t smem_shape_size, + size_t smem_stride_size, + CUtensorMapInterleave tma_interleave, + CUtensorMapSwizzle tma_swizzle, + CUtensorMapL2promotion tma_l2Promotion, + CUtensorMapFloatOOBfill tma_oobFill, + const std::string& extra_info = "" +) { + std::ostringstream oss; + oss << "Error in " << error_type << " TMA descriptor creation: "; + oss << (error_string ? error_string : "Unknown CUDA error"); + oss << "\nParameters:"; + oss << "\n batch: " << batch; + oss << "\n depth: " << depth; + oss << "\n rows: " << rows; + oss << "\n cols: " << cols; + if (!extra_info.empty()) + oss << "\n " << extra_info; + + oss << "\ncuTensorMapEncodeTiled arguments:"; + oss << "\n tma_map: " << reinterpret_cast(tma_map); + oss << "\n tma_format: " << tma_format; + oss << "\n tma_dim: " << tma_dim; + oss << "\n global_addr: " << reinterpret_cast(global_addr); + + // Check if global_addr is valid device memory + cudaPointerAttributes attributes; + cudaError_t err = cudaPointerGetAttributes(&attributes, global_addr); + if (err == cudaSuccess) { + oss << "\n global_addr memory type: "; + if (attributes.type == cudaMemoryTypeDevice) { + oss << "valid device memory"; + } else if (attributes.type == cudaMemoryTypeHost) { + oss << "host memory (invalid for TMA)"; + } else if (attributes.type == cudaMemoryTypeManaged) { + oss << "managed memory"; + } else { + oss << "unknown memory type"; + } + } else { + oss << "\n global_addr memory type: unable to determine (error: " << cudaGetErrorString(err) << ")"; + } + + oss << "\n gmem_shape: " << reinterpret_cast(gmem_shape) << " ["; + for (size_t i = 0; i < gmem_shape_size; ++i) + oss << gmem_shape[i] << (i < gmem_shape_size - 1 ? ", " : ""); + oss << "]"; + + oss << "\n gmem_stride: " << reinterpret_cast(gmem_stride) << " ["; + for (size_t i = 0; i < gmem_stride_size; ++i) + oss << gmem_stride[i] << (i < gmem_stride_size - 1 ? ", " : ""); + oss << "]"; + + oss << "\n smem_shape: " << reinterpret_cast(smem_shape) << " ["; + for (size_t i = 0; i < smem_shape_size; ++i) + oss << smem_shape[i] << (i < smem_shape_size - 1 ? ", " : ""); + oss << "]"; + + oss << "\n smem_stride: " << reinterpret_cast(smem_stride) << " ["; + for (size_t i = 0; i < smem_stride_size; ++i) + oss << smem_stride[i] << (i < smem_stride_size - 1 ? ", " : ""); + oss << "]"; + + oss << "\n tma_interleave: " << tma_interleave; + oss << "\n tma_swizzle: " << tma_swizzle; + oss << "\n tma_l2Promotion: " << tma_l2Promotion; + oss << "\n tma_oobFill: " << tma_oobFill; + + return oss.str(); +} + +/* ---------- Create tile tensor map descriptor (HOST) ---------- */ + +/** +* @brief Creates a tensor map for the given source tensor. +* +* This function creates a tensor map (CUtensorMap) for the specified source shared tile type. The tensor map +* is used to describe the shape and layout of the tensor in memory. The function sets up the tensor +* map based on the provided source tensor pointer and the layout specified by the ST template parameter. +* +* @tparam ST The source tensor type, which must be TMA-compatible. +* @tparam blocks_height The number of tiles present on the height axis in global memory. +* @tparam blocks_width The number of tiles present on the width axis in global memory. Defaults to 1. +* @param tma_map Pointer to the CUtensorMap object to be initialized. +* @param src Pointer to the source tensor data in global memory. +*/ +template +__host__ static inline void create_tensor_map(CUtensorMap *tma_map, const typename ST::dtype *src, int batch, int depth, int rows, int cols) { + using dtype = typename ST::dtype; + static_assert(axis==0 || axis==1 || axis==2, "axis must be 0, 1, or 2"); + + constexpr uint32_t tma_dim = enable_swizzle ? 5 : 4; + void *global_addr = (void*)(src); + + constexpr CUtensorMapDataType tma_format = ( + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_BFLOAT16 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_FLOAT16 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_FLOAT32 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_UINT8 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_UINT8 : +#ifdef KITTENS_BLACKWELL + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_UINT8 : +#endif + CUtensorMapDataType(-1) + ); + constexpr CUtensorMapInterleave tma_interleave = CU_TENSOR_MAP_INTERLEAVE_NONE; + constexpr CUtensorMapL2promotion tma_l2Promotion = CU_TENSOR_MAP_L2_PROMOTION_NONE; + constexpr CUtensorMapFloatOOBfill tma_oobFill = CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE; + constexpr CUtensorMapSwizzle tma_swizzle = enable_swizzle ? ( + ST::swizzle_bytes == 32 ? CU_TENSOR_MAP_SWIZZLE_32B : + ST::swizzle_bytes == 64 ? CU_TENSOR_MAP_SWIZZLE_64B : + ST::swizzle_bytes == 128 ? CU_TENSOR_MAP_SWIZZLE_128B : + CU_TENSOR_MAP_SWIZZLE_NONE + ) : CU_TENSOR_MAP_SWIZZLE_NONE; + + // Works for tma_dim = 4 too + uint64_t gmem_shape [5] = {0, 0, 0, 0, 0}; + uint64_t gmem_stride[4] = {0, 0, 0, 0}; + uint32_t smem_shape [5] = {0, 0, 0, 0, 0}; + uint32_t smem_stride[5] = {1, 1, 1, 1, 1}; + + constexpr uint64_t shared_tile_height = ST::rows; + constexpr uint64_t shared_tile_width = ST::cols; + + constexpr int swizzle_elements = ST::swizzle_bytes / sizeof(dtype); + + if constexpr (enable_swizzle) { + if constexpr (axis == 2) { + gmem_shape[0] = swizzle_elements; + gmem_shape[1] = (uint64_t)rows; + gmem_shape[2] = (uint64_t)(cols+swizzle_elements-1) / swizzle_elements; // round up, note this can potentially screw up out of bounds access handling :/ + gmem_shape[3] = (uint64_t)depth; + gmem_shape[4] = (uint64_t)batch; + + gmem_stride[0] = (uint64_t)cols * sizeof(dtype); + gmem_stride[1] = ST::swizzle_bytes; + gmem_stride[2] = (uint64_t)rows * cols * sizeof(dtype); + gmem_stride[3] = (uint64_t)depth * rows * cols * sizeof(dtype); + } + else if constexpr (axis == 1) { + gmem_shape[0] = swizzle_elements; + gmem_shape[1] = (uint64_t)depth; + gmem_shape[2] = (uint64_t)(cols+swizzle_elements-1) / swizzle_elements; // round up, note this can potentially screw up out of bounds access handling :/ + gmem_shape[3] = (uint64_t)rows; + gmem_shape[4] = (uint64_t)batch; + + gmem_stride[0] = (uint64_t)rows * cols * sizeof(dtype); + gmem_stride[1] = ST::swizzle_bytes; + gmem_stride[2] = (uint64_t)cols * sizeof(dtype); + gmem_stride[3] = (uint64_t)depth * rows * cols * sizeof(dtype); + + } + else { + gmem_shape[0] = swizzle_elements; + gmem_shape[1] = (uint64_t)batch; + gmem_shape[2] = (uint64_t)(cols+swizzle_elements-1) / swizzle_elements; // round up, note this can potentially screw up out of bounds access handling :/ + gmem_shape[3] = (uint64_t)rows; + gmem_shape[4] = (uint64_t)depth; + + gmem_stride[0] = (uint64_t)depth * rows * cols * sizeof(dtype); + gmem_stride[1] = ST::swizzle_bytes; + gmem_stride[2] = (uint64_t)cols * sizeof(dtype); + gmem_stride[3] = (uint64_t)rows * cols * sizeof(dtype); + } + smem_shape[0] = swizzle_elements; + smem_shape[1] = shared_tile_height; + smem_shape[2] = shared_tile_width / swizzle_elements; + smem_shape[3] = 1; + smem_shape[4] = 1; + } else { + gmem_shape[0] = (uint64_t)cols; + gmem_shape[1] = (uint64_t)rows; + gmem_shape[2] = (uint64_t)depth; + gmem_shape[3] = (uint64_t)batch; + + gmem_stride[0] = (uint64_t)cols * sizeof(dtype); + gmem_stride[1] = (uint64_t)rows * cols * sizeof(dtype); + gmem_stride[2] = (uint64_t)depth * rows * cols * sizeof(dtype); + + smem_shape[0] = shared_tile_width; + smem_shape[1] = shared_tile_height; + smem_shape[2] = 1; + smem_shape[3] = 1; + } + + // ensure that the global address is always 16-byte aligned + assert((reinterpret_cast(global_addr) & 0b1111) == 0); + + assert(gmem_stride[0] % 16 == 0); // gmem_stride[0] elements must be a multiple of 16B + assert(gmem_stride[1] % 16 == 0); // gmem_stride[1] elements must be a multiple of 16B + assert(gmem_stride[2] % 16 == 0); // gmem_stride[2] elements must be a multiple of 16B + assert(gmem_stride[3] % 16 == 0); // gmem_stride[2] elements must be a multiple of 16B + + assert(smem_shape[0] <= 256); // smem_shape[0] elements must be <= 256 + assert(smem_shape[1] <= 256); // smem_shape[1] elements must be <= 256 + assert(smem_shape[2] <= 256); // smem_shape[2] elements must be <= 256 + + assert((smem_shape[0]*sizeof(dtype)) % 16 == 0); // if wgmma_interleave is none, then smem_shape[0] * sizeof(dtype) must be a multiple of 16B + + assert(smem_stride[0] <= 8); // smem_stride[0] must be less <= 8 + assert(smem_stride[1] <= 8); // smem_stride[1] must be less <= 8 + assert(smem_stride[2] <= 8); // smem_stride[2] must be less <= 8 + assert(smem_stride[3] <= 8); // smem_stride[3] must be less <= 8 + assert(smem_stride[4] <= 8); // smem_stride[3] must be less <= 8 + + assert(smem_stride[0] == 1); // smem_stride[0] is ignored when wgmma_interleave is none + + if constexpr (tma_interleave == CU_TENSOR_MAP_INTERLEAVE_NONE && tma_swizzle != CU_TENSOR_MAP_SWIZZLE_NONE) { + assert(smem_shape[0] * sizeof(dtype) <= ST::swizzle_bytes); + } + + const uint64_t *gmem_shape_ptr = &gmem_shape[0]; + const uint64_t *gmem_stride_ptr = &gmem_stride[0]; + const uint32_t *smem_shape_ptr = &smem_shape[0]; + const uint32_t *smem_stride_ptr = &smem_stride[0]; + + CUresult result = cuTensorMapEncodeTiled( + tma_map, + tma_format, + tma_dim, + global_addr, + gmem_shape_ptr, + gmem_stride_ptr, + smem_shape_ptr, + smem_stride_ptr, + tma_interleave, + tma_swizzle, + tma_l2Promotion, + tma_oobFill); + + const char *error_string; + CUresult res = cuGetErrorString(result, &error_string); + if (result != CUDA_SUCCESS) { + std::string error_msg = format_tma_error( + "tile", error_string, + batch, depth, rows, cols, + tma_map, tma_format, tma_dim, global_addr, + gmem_shape_ptr, gmem_stride_ptr, + smem_shape_ptr, smem_stride_ptr, + 5, 4, 5, 5, + tma_interleave, tma_swizzle, tma_l2Promotion, tma_oobFill, + "ST::rows: " + std::to_string(ST::rows) + "\n ST::cols: " + std::to_string(ST::cols) + ); + throw std::runtime_error(error_msg); + } +} + +/** +* @brief Allocates on the GPU and initializes a tensor map for the given source tensor. +* +* This function creates a tensor map (CUtensorMap) for the specified source shared tile type. The tensor map +* is used to describe the shape and layout of the tensor in memory. The function sets up the tensor +* map based on the provided source tensor pointer and the layout specified by the ST template parameter. +* +* @tparam ST The source tensor type, which must be TMA-compatible. +* @tparam blocks_height The number of tiles present on the height axis in global memory. +* @tparam blocks_width The number of tiles present on the width axis in global memory. Defaults to 1. +* @param src Pointer to the source tensor data in global memory. +* @returns Pointer to the CUtensorMap object to be initialized. +*/ +template +__host__ static inline CUtensorMap* allocate_and_create_tensor_map(const typename ST::dtype *src, int batch, int depth, int rows, int cols) { + CUtensorMap *tma_map_d; + cudaMalloc(&tma_map_d, sizeof(CUtensorMap)); + CUtensorMap tma_map_host; // put it on the stack, why not. + create_tensor_map(&tma_map_host, src, batch, depth, rows, cols); + cudaMemcpy(tma_map_d, &tma_map_host, sizeof(CUtensorMap), cudaMemcpyHostToDevice); + return tma_map_d; +} + +/* ---------- Create vector tensor map descriptor (HOST) ---------- */ + +// First, we need a template system to determine how to divide up a long shared vector into multiple subvectors. +// We have to do this because the first dimension for TMA is limited to 256 elements. +// Our goal is to find the largest multiple of 16 that is <= 256 and divides the vector length evenly. + +template struct find_vector_divider { + static constexpr int value = (SV::length % (16*D) == 0 && (SV::length < 256 || ((16*D)*sizeof(typename SV::dtype)) % 128 == 0)) ? + 16*D : find_vector_divider::value; +}; +template struct find_vector_divider { static constexpr int value = 16; }; // base case +template constexpr int sv_tma_dim1 = find_vector_divider::value; // inner dim +template constexpr int sv_tma_dim2 = (SV::length / sv_tma_dim1); + +/** +* @brief Creates a tensor map for the given source vector. +* +* This function creates a tensor map (CUtensorMap) for the specified source shared vector type. The tensor map +* is used to describe the shape and layout of the tensor in memory. The function sets up the tensor +* map based on the provided source tensor pointer and the layout specified by the SV template parameter. +* +* @tparam SV The source tensor type, which must be TMA-compatible. +* @tparam num_vectors The number of vectors present in global memory. +* @param tma_map Pointer to the CUtensorMap object to be initialized. +* @param src Pointer to the source tensor data in global memory. +*/ +template +__host__ static inline void create_tensor_map(CUtensorMap *tma_map, const typename SV::dtype *src, int batch, int depth, int rows, int cols) { + using dtype = typename SV::dtype; + static_assert(axis == -1, "for vector TMA, row axis must be -1 as it's unused"); + static_assert(SV::length <= 256 || (SV::length*sizeof(dtype)) % 128 == 0); + // There is technically a way around ^ that involves instantiating two separate TMA descriptors, one of size 256 + // and the other of size %256, but this is a fairly mild restriction and the other approach is a real PITA and incurs other costs. + static_assert(disable_swizzle, "for vector TMA, swizzle should be disabled"); + + constexpr uint32_t tma_dim = 4; + void *global_addr = (void*)(src); + + constexpr CUtensorMapDataType tma_format = ( + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_BFLOAT16 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_FLOAT16 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_FLOAT32 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_UINT8 : + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_UINT8 : +#ifdef KITTENS_BLACKWELL + std::is_same_v ? CU_TENSOR_MAP_DATA_TYPE_UINT8 : +#endif + CUtensorMapDataType(-1) + ); + constexpr CUtensorMapInterleave tma_interleave = CU_TENSOR_MAP_INTERLEAVE_NONE; + constexpr CUtensorMapL2promotion tma_l2Promotion = CU_TENSOR_MAP_L2_PROMOTION_NONE; + constexpr CUtensorMapFloatOOBfill tma_oobFill = CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE; + constexpr CUtensorMapSwizzle swizzle = CU_TENSOR_MAP_SWIZZLE_NONE; + + constexpr uint64_t dim1 = sv_tma_dim1; // inner dim + // constexpr uint64_t dim2 = sv_tma_dim2; outer dim, not used here. + + uint64_t gmem_shape [4] = {(uint64_t)cols, (uint64_t)rows, (uint64_t)depth, (uint64_t)batch}; + uint64_t gmem_stride[3] = {(uint64_t)cols*sizeof(dtype), (uint64_t)cols*rows*sizeof(dtype), (uint64_t)cols*rows*depth*sizeof(dtype)}; + uint32_t smem_shape [4] = {(uint32_t)dim1, 1, 1, 1}; + uint32_t smem_stride[4] = {1, 1, 1, 1}; + + // ensure that the global address is always 16-byte aligned + assert((reinterpret_cast(global_addr) & 0b1111) == 0); + + assert(smem_shape[0] <= 256); // smem_shape[0] elements must be <= 256. + + const uint64_t *gmem_shape_ptr = &gmem_shape[0]; + const uint64_t *gmem_stride_ptr = &gmem_stride[0]; + const uint32_t *smem_shape_ptr = &smem_shape[0]; + const uint32_t *smem_stride_ptr = &smem_stride[0]; + + CUresult result = cuTensorMapEncodeTiled( + tma_map, + tma_format, + tma_dim, + global_addr, + gmem_shape_ptr, + gmem_stride_ptr, + smem_shape_ptr, + smem_stride_ptr, + tma_interleave, + swizzle, + tma_l2Promotion, + tma_oobFill + ); + + const char *error_string; + CUresult res = cuGetErrorString(result, &error_string); + if (result != CUDA_SUCCESS) { + std::string error_msg = format_tma_error( + "vector", error_string, + batch, depth, rows, cols, + tma_map, tma_format, tma_dim, global_addr, + gmem_shape_ptr, gmem_stride_ptr, + smem_shape_ptr, smem_stride_ptr, + 4, 3, 4, 4, + tma_interleave, swizzle, tma_l2Promotion, tma_oobFill, + "SV::length: " + std::to_string(SV::length) + ); + throw std::runtime_error(error_msg); + } +}; + +/** +* @brief Allocates on the GPU and initializes a tensor map for the given source tensor. +* +* This function creates a tensor map (CUtensorMap) for the specified source shared vector type. The tensor map +* is used to describe the shape and layout of the tensor in memory. The function sets up the tensor +* map based on the provided source tensor pointer and the layout specified by the SV template parameter. +* +* @tparam SV The source tensor type, which must be TMA-compatible. +* @tparam num_vectors The number of vectors present in global memory. +* @param src Pointer to the source tensor data in global memory. +* @returns Pointer to the CUtensorMap object to be initialized. +*/ +template +__host__ static inline CUtensorMap* allocate_and_create_tensor_map(const typename SV::dtype *src, int batch, int depth, int rows, int cols) { + CUtensorMap *tma_map_d; + cudaMalloc(&tma_map_d, sizeof(CUtensorMap)); + CUtensorMap tma_map_host; // put it on the stack, why not. + create_tensor_map(&tma_map_host, src, batch, depth, rows, cols); + cudaMemcpy(tma_map_d, &tma_map_host, sizeof(CUtensorMap), cudaMemcpyHostToDevice); + return tma_map_d; +} + +} // namespace tma +} // namespace detail +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/global/util.cuh b/extra/thunder/cuda/include/types/global/util.cuh new file mode 100644 index 0000000000..3490286113 --- /dev/null +++ b/extra/thunder/cuda/include/types/global/util.cuh @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include "../register/register.cuh" + +namespace kittens { +namespace ducks { +namespace gl { + +template concept cdim = (d > 0); // represents a compile-time dimension +template concept rdim = (d == -1); // represents a runtime dimension +template struct compiled_dim { + static_assert(cdim<_v>, "Invalid compile-time dimension value"); + static constexpr size_t v = _v; + __host__ __device__ inline compiled_dim(const std::nullptr_t &_) {} + __host__ __device__ inline constexpr operator size_t() const { return v; } +}; +struct runtime_dim { + size_t v; + __host__ __device__ inline runtime_dim(const size_t &_v) : v(_v) {} + __host__ __device__ inline operator size_t() const { return v; } +}; +template using make_dim_t = std::conditional_t, runtime_dim, compiled_dim>; +template using make_arg_t = std::conditional_t, size_t, std::nullptr_t>; // we pass runtime dims as size_t, comptime dims as nullptr_t +} +} + +namespace detail { +template concept tile = ducks::st::all || ducks::rt::all || ducks::cst::all || ducks::crt::all; +template concept vec = ducks::sv::all || ducks::rv::all || ducks::csv::all || ducks::crv::all; +} + +namespace ducks { +namespace coord { +struct identifier {}; +} +} +template struct coord { // essentially a named int4 for tensor coordinates. + using identifier = ducks::coord::identifier; + using BASE = _T; // in units of what type? + static_assert(std::is_same_v || detail::tile || detail::vec); // ensure BASE is a valid type + int b, d, r, c; + __device__ inline coord(int _b, int _d, int _r, int _c) : b(_b), d(_d), r(_r), c(_c) {} + __device__ inline coord( int _d, int _r, int _c) : b( 0), d(_d), r(_r), c(_c) {} + __device__ inline coord( int _r, int _c) : b( 0), d( 0), r(_r), c(_c) {} + __device__ inline coord( int _c) : b( 0), d( 0), r( 0), c(_c) {} + __device__ inline coord( ) : b( 0), d( 0), r( 0), c( 0) {} + template __device__ inline coord(const coord &other) : b(other.b), d(other.d), r(other.r), c(other.c) {} + __device__ inline coord(const int4 &other) : b(other.x), d(other.y), r(other.z), c(other.w) {} + __device__ inline operator int4() const { return int4(b, d, r, c); } + template __device__ inline coord unit_coord() const { + if constexpr (detail::tile) { + static_assert(row_axis != col_axis, "row and column axes must be different"); + static_assert(row_axis >= 0 && row_axis <= 3, "row axis must be between 0 and 3"); + static_assert(col_axis >= 0 && col_axis <= 3, "column axis must be between 0 and 3"); + static_assert(col_axis == 3, "for now, column axis must be 3"); + return coord( + row_axis == 0 ? b*BASE::rows : b, + row_axis == 1 ? d*BASE::rows : d, + row_axis == 2 ? r*BASE::rows : r, + c*BASE::cols + ); + } + else if constexpr (detail::vec) { + static_assert(row_axis == -1, "row axis must be be -1 for a vector coordinate to be converted to a unit coordinate"); + static_assert(col_axis >= 0 && col_axis <= 3, "column axis must be between 0 and 3"); + static_assert(col_axis == 3, "for now, column axis must be 3"); + return coord(b, d, r, c*BASE::length); + } + else { + return coord(*this); + } + } + template __device__ inline int dim() const { + static_assert(axis >= 0 && axis <= 3, "axis must be between 0 and 3"); + if constexpr (axis == 0) { return b; } + else if constexpr (axis == 1) { return d; } + else if constexpr (axis == 2) { return r; } + else { return c; } + } +}; +namespace ducks { +namespace coord { +/** +* @brief Concept for all coordinate types. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as ducks::coord::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::coord::identifier +template concept tile = all && (std::is_same_v || detail::tile); +template concept vec = all && (std::is_same_v || detail::vec); +} +} +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/register/crt.cuh b/extra/thunder/cuda/include/types/register/crt.cuh new file mode 100644 index 0000000000..023ae713a2 --- /dev/null +++ b/extra/thunder/cuda/include/types/register/crt.cuh @@ -0,0 +1,95 @@ +/** + * @file + * @brief Abstraction for a complex register tile composed of real and imaginary tiles + */ + +#pragma once + +#include "rt.cuh" +#include "crv.cuh" + +namespace kittens { + +namespace ducks { +namespace crt { +/** + * @brief A dummy type used to identify complex register tiles. + * + * For a type to quack like an rt_cmplx, it should define its identifier as ducks::rt::cmplx_identifier. + * If a type quacks like ducks::rt::cmplx_identifier, it will be treated as an rt_cmplx by compiler checks. + */ +struct identifier {}; +/** +* @brief Concept for register tiles that are complex. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T is a register tile. +* - T has a complex tile identifier. +*/ +template concept all = requires { + typename T::identifier; +} && std::is_same_v && ducks::rt::all; + +/* +* Requires: +* - T is a register tile. +* - T has an internal type layout that is ducks::rt_layout::row. +*/ +template +concept row_layout = all && std::is_same_v; +/** +* @brief Concept for register tiles with col layout. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T is a register tile. +* - T has an internal type layout that is ducks::rt_layout::col. +*/ +template +concept col_layout = all && std::is_same_v; +} // namespace rt +} // namespace ducks + +/** + * @brief Complex tile structure + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _rows The height of the tile in terms of the number of subtiles. + * @tparam _cols The width of the tile in terms of the number of subtiles. + * @tparam _layout The layout of the internal register tiles, either row-major or column-major. + * + * This structure is designed to abstract complex number operations internally to the real and imaginary + * register tiles, respectively + * + * In general, you probably want a row-major tile, unless you specifically want to call mma + */ +template +struct crt { + using identifier = ducks::crt::identifier; + using component = rt<_T, _rows, _cols, _layout>; /// Data type of each internal tile. + using layout = component::layout; ///< Layout of the matrix tile, ensures compatibility with the rt concepts + using T = component::T; + using T2 = component::T2; + using dtype = component::dtype; ///< Data type of the elements in the tile. + + static constexpr int rows = component::rows; + static constexpr int cols = component::cols; + static constexpr int height = component::height; + static constexpr int width = component::width; + + // Real/imag tiles have same internal layout and size + component real; + component imag; + + using row_vec = crv::row_vec_layout>; ///< A type representing a column vector for this tile. + using col_vec = crv::col_vec_layout>; ///< A type representing a column vector for this tile. +}; + +template using crt_fl = crt; +template using crt_bf = crt; +template using crt_hf = crt; + + + +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/register/crv.cuh b/extra/thunder/cuda/include/types/register/crv.cuh new file mode 100644 index 0000000000..e688f723a8 --- /dev/null +++ b/extra/thunder/cuda/include/types/register/crv.cuh @@ -0,0 +1,88 @@ +/** + * @file + * @brief Register vectors for computations on axes. + */ + +#pragma once + +#include +#include + +#include "../../common/common.cuh" +#include "rv_layout.cuh" + +namespace kittens { + +/* ---------- MAIN VECTOR STRUCT ---------- */ + +// helper struct for type inference +namespace ducks { +/** + * @namespace rt + * + * @brief The namespace where concepts and abstract types for register vectors live. + */ +namespace crv { +/** + * @brief A dummy type used to identify register vectors. + * + * For a type to quack like an rv, it should define its identifier as ducks::rv::identifier. + * If a type quacks like ducks::rv::identifier, it will be treated as an rv by compiler checks. + */ +struct identifier {}; +/** +* @brief Concept for all register vectors. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as rv::identifier. +*/ +template +concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::rv::identifier. + +template concept naive_layout = all && std::is_same_v; +template concept align_layout = all && std::is_same_v; +template concept ortho_layout = all && std::is_same_v; +template concept tile_layout = align_layout || ortho_layout; // vector layouts for interacting with tiles. +} +} +/** + * @brief Register vector structure. + * + * @tparam _T The packed data type used for the vector elements. + * @tparam _outer_dim The size of the tile, in units of TILE_DIM (16). + * @tparam _inner_dim This controls the layout of the tile in terms of which axis it maps on the register tile layout. + * + * Register vectors are used to accumulate and map values across tiles. You can do computation + * on them directly if you want, but they're not designed to be maximally efficient vectors + * as they have substantial duplication and strange layouts to help them work efficiently with + * the register layouts used by the tensor cores. ThunderKittens wants you working with tiles + * where possible! + */ + +template +struct crv { + using identifier = ducks::crv::identifier; + using component = rv<_T, _length, _layout>; /// Data type of each internal tile. + using layout = component::layout; ///< Layout of the matrix tile, ensures compatibility with the rv concepts + + using T = component::T; + using T2 = component::T2; + using dtype = component::dtype; ///< Data type of the elements in the tile. + + static constexpr int length = component::length; + static constexpr int tiles = component::tiles; + + // Real/imag tiles have same internal layout and size + component real; + component imag; +}; + + +template using crv_fl = crv; +template using crv_bf = crv; +template using crv_hf = crv; + +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/register/register.cuh b/extra/thunder/cuda/include/types/register/register.cuh new file mode 100644 index 0000000000..f3525a0416 --- /dev/null +++ b/extra/thunder/cuda/include/types/register/register.cuh @@ -0,0 +1,15 @@ +/** + * @file + * @brief An aggregate header file for all the register types defined by ThunderKittens. + */ + +#pragma once + +#include "rv_layout.cuh" +#include "rt_base.cuh" +#include "rv.cuh" +#include "rt.cuh" + +#include "crv.cuh" +#include "crt.cuh" + diff --git a/extra/thunder/cuda/include/types/register/rt.cuh b/extra/thunder/cuda/include/types/register/rt.cuh new file mode 100644 index 0000000000..b5765d570a --- /dev/null +++ b/extra/thunder/cuda/include/types/register/rt.cuh @@ -0,0 +1,155 @@ +/** + * @file + * @brief The main ThunderKittens register tile struct, where most computation happens. + */ + +#pragma once + +#include +#include + +#include "../../common/common.cuh" + +#include "rt_layout.cuh" +#include "rt_base.cuh" +#include "rv.cuh" + +namespace kittens { + +/* ---------- MAIN TILE STRUCT ---------- */ + +// helper struct for type inference +namespace ducks { +/** + * @namespace rt + * + * @brief The namespace where concepts and abstract types for register tiles live. + */ +namespace rt { +/** + * @brief A dummy type used to identify register tiles. + * + * For a type to quack like an rt, it should define its identifier as ducks::rt::identifier. + * If a type quacks like ducks::rt::identifier, it will be treated as an rt by compiler checks. + */ +struct identifier {}; +/** +* @brief Concept for all register tiles. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as rt::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::rt::identifier +/** +* @brief Concept for register tiles with row layout. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T is a register tile. +* - T has an internal type layout that is ducks::rt_layout::row. +*/ +template +concept row_layout = all && std::is_same_v; +/** +* @brief Concept for register tiles with col layout. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T is a register tile. +* - T has an internal type layout that is ducks::rt_layout::col. +*/ +template +concept col_layout = all && std::is_same_v; +} // namespace rt +} // namespace ducks + +/** + * @brief Main tile structure for manipulating data in registers. + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _height The height of the tile in terms of the number of subtiles. + * @tparam _width The width of the tile in terms of the number of subtiles. + * @tparam _layout The layout of the internal base tiles, either row-major or column-major. + * + * This structure is designed to handle matrix tiles in a flexible manner, allowing + * for operations on tiles that are composed of smaller subtiles. It supports both + * row-major and column-major layouts and includes helper structs for type inference + * in vector maps. + * + * In general, you probably want a row-major tile, unless you specifically want to call mma + */ +template +struct rt { + using identifier = ducks::rt::identifier; ///< Type identifier for the rt structure. + using layout = _layout; ///< Layout of the matrix tile. + static_assert(kittens::ducks::base_types::T1<_T>); // confirm it's a supported type + using T = kittens::base_types::packing<_T>::unpacked_type; + using T2 = kittens::base_types::packing<_T>::packed_type; + using dtype = T2; ///< Data type of the matrix elements + + static constexpr int rows = _rows; ///< Total number of rows. + static_assert(rows % rt_base::tile_size_row == 0, "Rows must be divisible by the tile size"); + static constexpr int cols = _cols; ///< Total number of columns. + static_assert(cols % rt_base::tile_size_col == 0, "Columns must be divisible by the tile size"); + static constexpr int height = rows / rt_base::tile_size_row; ///< Height in subtiles. + static constexpr int width = cols / rt_base::tile_size_col; ///< Width in subtiles. + static constexpr int tile_size_row = rt_base::tile_size_row; ///< Size of the base tile. + static constexpr int tile_size_col = rt_base::tile_size_col; ///< Size of the base tile. + static constexpr int num_elements = rt_base::num_elements * width * height; ///< Total number of elements. + static constexpr int elements_per_thread = rt_base::elements_per_thread * width * height; ///< Elements handled per thread. + static constexpr int packed_per_thread = rt_base::packed_per_thread * width * height; ///< Packed elements per thread. + static constexpr int packed_per_tile = rt_base::packed_per_thread; ///< Packed elements per tile. + + rt_base tiles[height][width]; ///< The actual storage for the matrix tile, organized in subtiles. + + using row_vec = rv::row_vec_layout>; ///< A type representing a column vector for this tile. + using col_vec = rv::col_vec_layout>; ///< A type representing a column vector for this tile. + + __device__ inline void operator=(const T &value) { + T2 value2 = base_types::packing::pack(value); + #pragma unroll + for(int i = 0; i < height; i++) { + #pragma unroll + for(int j = 0; j < width; j++) { + #pragma unroll + for(int k = 0; k < packed_per_tile; k++) { + tiles[i][j].data[k] = value2; + } + } + } + } + template + __device__ inline void operator=(const rt &other) { + using U2 = base_types::packing::packed_type; + #pragma unroll + for(int i = 0; i < height; i++) { + #pragma unroll + for(int j = 0; j < width; j++) { + #pragma unroll + for(int k = 0; k < packed_per_tile; k++) { + tiles[i][j].data[k] = base_types::convertor::convert(other.tiles[i][j].data[k]); + } + } + } + } +}; + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// layout and type wrappers + +template using rt_fl = rt; +template using rt_bf = rt; +template using rt_hf = rt; +#ifdef KITTENS_HOPPER +template using rt_fp8e4m3 = rt; +template using rt_fp8e5m2 = rt; +#ifdef KITTENS_BLACKWELL +template using rt_fp8e8m0 = rt; +#endif +#endif +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/register/rt_base.cuh b/extra/thunder/cuda/include/types/register/rt_base.cuh new file mode 100644 index 0000000000..c15f1c5910 --- /dev/null +++ b/extra/thunder/cuda/include/types/register/rt_base.cuh @@ -0,0 +1,112 @@ +/** + * @file + * @brief The basic 16x16 register tile on which larger register tiles are built. + */ + +#pragma once + +#include + +#include "../../common/common.cuh" +#include "rt_layout.cuh" +#include "rv_layout.cuh" + +namespace kittens { + +/* ---------- BASE 16x16 SUBTILE STRUCT ---------- */ + +namespace ducks { +/** + * @namespace rt_base + * + * @brief The namespace where concepts and abstract types for register base (16x16) tiles live. + */ +namespace rt_base { +/** + * @brief A dummy type used to identify register base tiles. + * + * For a type to quack like an rt_base, it should define its identifier as ducks::rt_base::identifier. + * If a type quacks like ducks::rt_base::identifier, it will be treated as an rt_base by compiler checks. + */ +struct identifier {}; +} +} // namespace ducks + +/** + * @brief Basic tile structure for computation in registers. + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _layout The layout of the base tile, either row-major or column-major. + * + * This type is a primarily utility for building larger inline templates + * out of PTX primitives and managing layouts. + * + * In general, you probably want a row-major tile, unless you specifically want to call mma + */ +template struct rt_base { + using identifier = ducks::rt_base::identifier; ///< Type identifier for the rt_base structure. + using layout = _layout; ///< Layout of the matrix tile. + static_assert(kittens::ducks::base_types::T1<_T>); // confirm it's a supported type + using T = kittens::base_types::packing<_T>::unpacked_type; + using T2 = kittens::base_types::packing<_T>::packed_type; + using dtype = T2; ///< Data type of the matrix elements + + #ifdef KITTENS_HOPPER + static_assert( + std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v, + "rt_base was provided an unsupported type." + ); + #else + static_assert( + std::is_same_v || std::is_same_v || std::is_same_v, + "rt_base was provided an unsupported type." + ); + #endif + + static constexpr int tile_size_row = kittens::TILE_ROW_DIM; // < Tile size is a constant 16 for everyone + static constexpr int tile_size_col = kittens::TILE_COL_DIM; + static constexpr int rows = tile_size_row; ///< Number of rows. + static constexpr int cols = tile_size_col; ///< Number of cols. + static constexpr int num_elements = rows*cols; // 256 (64 for fp8e4m3) + static constexpr int elements_per_thread = num_elements / 32; // 8 (2 for fp8e4m3) + + static constexpr int packed_per_thread = (elements_per_thread / base_types::packing::num()) ; // 4 + static constexpr int registers_per_thread = packed_per_thread * sizeof(dtype) / 4; // 4 or 8, registers are 32-bit words + + using row_vec_layout = std::conditional_t, ducks::rv_layout::align, ducks::rv_layout::ortho>; // for holding column reductions + using col_vec_layout = std::conditional_t, ducks::rv_layout::ortho, ducks::rv_layout::align>; // for holding row reductions + + dtype data[packed_per_thread]; ///< The actual storage for the base tile +}; + +// rt_base is 2x the number of elements for fp8e4m3 +// then when we convert a 16x16 of float2, we have 512 elements in the tile +// and with fp8e4m3x4 packed type, we have 16x32x4=2048 elements in the tile + +/* ---------- CONCEPTS ---------- */ + +namespace ducks { +namespace rt_base { +/** +* @brief Concept for all register base tiles. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as rt_base::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::rt::identifier +} // namespace rt +} // namespace ducks + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using rt_base_fl = rt_base; +template using rt_base_bf = rt_base; +template using rt_base_hf = rt_base; +#ifdef KITTENS_HOPPER +template using rt_base_fp8e4m3 = rt_base; +template using rt_base_fp8e5m2 = rt_base; +#endif +} diff --git a/extra/thunder/cuda/include/types/register/rt_layout.cuh b/extra/thunder/cuda/include/types/register/rt_layout.cuh new file mode 100644 index 0000000000..a9f9f337cf --- /dev/null +++ b/extra/thunder/cuda/include/types/register/rt_layout.cuh @@ -0,0 +1,42 @@ +/** + * @file + * @brief Layouts and their manipulations for register tiles. + */ + +#pragma once + +#include + +namespace kittens { +namespace ducks { +/** + * @namespace rt_layout + * + * @brief A namespace for template metaprogramming with register tile layouts. + */ +namespace rt_layout { + +/** + * @brief A dummy type used to identify a row-major layout for a register tile. + */ +struct row {}; // for most matrices +/** + * @brief A dummy type used to identify a col-major layout for a register tile. + */ +struct col {}; // for the B-matrix of MMA ops. + +/** + * @brief A concept to check if a type is a register tile layout. + */ +template +concept all = std::is_same_v || std::is_same_v; + +/** + * @brief A struct to generate a transposed layout. + */ +template struct transpose { using type = col; }; +template<> struct transpose { using type = row; }; + +} // namespace rt_layout +} // namespace ducks +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/register/rv.cuh b/extra/thunder/cuda/include/types/register/rv.cuh new file mode 100644 index 0000000000..21af8ffabc --- /dev/null +++ b/extra/thunder/cuda/include/types/register/rv.cuh @@ -0,0 +1,122 @@ +/** + * @file + * @brief Register vectors for computations on axes. + */ + +#pragma once + +#include +#include + +#include "../../common/common.cuh" +#include "rv_layout.cuh" + +namespace kittens { + +/* ---------- MAIN VECTOR STRUCT ---------- */ + +// helper struct for type inference +namespace ducks { +/** + * @namespace rt + * + * @brief The namespace where concepts and abstract types for register vectors live. + */ +namespace rv { +/** + * @brief A dummy type used to identify register vectors. + * + * For a type to quack like an rv, it should define its identifier as ducks::rv::identifier. + * If a type quacks like ducks::rv::identifier, it will be treated as an rv by compiler checks. + */ +struct identifier {}; +/** +* @brief Concept for all register vectors. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as rv::identifier. +*/ +template +concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::rv::identifier. + +template concept naive_layout = all && std::is_same_v; +template concept align_layout = all && std::is_same_v; +template concept ortho_layout = all && std::is_same_v; +template concept tile_layout = align_layout || ortho_layout; // vector layouts for interacting with tiles. +} +} +/** + * @brief Register vector structure. + * + * @tparam _T The packed data type used for the vector elements. + * @tparam _outer_dim The size of the tile, in units of TILE_DIM (16). + * @tparam _inner_dim This controls the layout of the tile in terms of which axis it maps on the register tile layout. + * + * Register vectors are used to accumulate and map values across tiles. You can do computation + * on them directly if you want, but they're not designed to be maximally efficient vectors + * as they have substantial duplication and strange layouts to help them work efficiently with + * the register layouts used by the tensor cores. ThunderKittens wants you working with tiles + * where possible! + */ +template +struct rv { + using identifier = ducks::rv::identifier; ///< Type identifier for the rv structure. + static_assert(kittens::ducks::base_types::T1<_T>); // confirm it's a supported type + using layout = _layout; + static constexpr bool is_naive = std::is_same_v; + using T = kittens::base_types::packing<_T>::unpacked_type; + using T2 = kittens::base_types::packing<_T>::packed_type; + using dtype = std::conditional_t; ///< Data type of the vector elements + + static constexpr int length = _length; ///< Length in elements. + static_assert(length % kittens::TILE_ROW_DIM == 0, "Length must be divisible by the tile dimension"); + static constexpr int tiles = _length / kittens::TILE_ROW_DIM; ///< Length in subtiles, aliased for consistency with sv type + static constexpr int inner_dim = layout::inner_dim; ///< Internal layout within a subtile. Either 1 or 2. + static constexpr int outer_dim = is_naive ? (tiles+1)/2 : tiles; ///< Outer dim (also length in tiles) + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Unsupported type for fp8"); + #endif + + dtype data[outer_dim][inner_dim]; ///< The actual register vector data. + + __device__ inline dtype* operator[](size_t idx) { return &data[idx][0]; } ///< A wrapper for indexing into vector data. + __device__ inline const dtype* operator[](size_t idx) const { return &data[idx][0]; } ///< A wrapper for indexing into vector data. + __device__ inline dtype& operator[](int2 outin) { return data[outin.x][outin.y]; } ///< A wrapper for indexing into vector data. + __device__ inline const dtype& operator[](int2 outin) const { return data[outin.x][outin.y]; } ///< A wrapper for indexing into vector data. + + __device__ inline void operator=(const T &value) { + dtype value2; + if constexpr(is_naive) { + value2 = value; + } else { + value2 = base_types::packing::pack(value); + } + #pragma unroll + for(int i = 0; i < outer_dim; i++) { + #pragma unroll + for(int j = 0; j < inner_dim; j++) { + data[i][j] = value2; + } + } + } + template + __device__ inline void operator=(const rv &other) { + using U2 = base_types::packing::packed_type; + #pragma unroll + for(int i = 0; i < outer_dim; i++) { + #pragma unroll + for(int j = 0; j < inner_dim; j++) { + data[i][j] = base_types::convertor::convert(other.data[i][j]); + } + } + } +}; + +template using rv_fl = rv; +template using rv_bf = rv; +template using rv_hf = rv; + +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/register/rv_layout.cuh b/extra/thunder/cuda/include/types/register/rv_layout.cuh new file mode 100644 index 0000000000..0165a86f76 --- /dev/null +++ b/extra/thunder/cuda/include/types/register/rv_layout.cuh @@ -0,0 +1,40 @@ +/** + * @file + * @brief Layouts and their manipulations for register tiles. + */ + +#pragma once + +#include + +namespace kittens { +namespace ducks { +/** + * @namespace rv_layout + * + * @brief A namespace for template metaprogramming with register vector layouts. + */ +namespace rv_layout { + +/** + * @brief A dummy type used to identify an aligned (8x replicated) layout. + */ +struct align { constexpr static int inner_dim = 2; }; +/** + * @brief A dummy type used to identify an orthogonal (4x replicated) layout. + */ +struct ortho { constexpr static int inner_dim = 1; }; +/** + * @brief A dummy type used to identify an unreplicated layout, for better coalesced loads and vector operations like layernorm. + */ +struct naive { constexpr static int inner_dim = 1; }; + +/** + * @brief A concept to check if a type is a register tile layout. + */ +template +concept all = std::is_same_v || std::is_same_v || std::is_same_v; + +} // namespace rv_layout +} // namespace ducks +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/shared/cst.cuh b/extra/thunder/cuda/include/types/shared/cst.cuh new file mode 100644 index 0000000000..98c63f9a3a --- /dev/null +++ b/extra/thunder/cuda/include/types/shared/cst.cuh @@ -0,0 +1,82 @@ +/** + * @file + * @brief Abstraction for a complex register tile composed of real and imaginary tiles + */ + +#pragma once + +#include "st.cuh" + +namespace kittens { + +namespace ducks { +namespace cst { +/** + * @brief A dummy type used to identify complex register tiles. + * + * For a type to quack like an st_cmplx, it should define its identifier as ducks::st::cmplx_identifier. + * If a type quacks like ducks::st::cmplx_identifier, it will be treated as an st_cmplx by compiler checks. + */ +struct identifier {}; + +/** +* @brief Concept for shared tiles that are complex. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T is a shared tile. +* - T has a complex tile identifier. +*/ +template concept all = requires { + typename T::identifier; +} && std::is_same_v && ducks::st::all; + +} // namespace st +} // namespace ducks + +/** + * @brief Complex tile structure + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _rows The height of the tile in terms of the number of subtiles. + * @tparam _cols The width of the tile in terms of the number of subtiles. + * @tparam _layout The layout of the internal register tiles + * + * This structure is designed to abstract complex number operations internally to the real and imaginary + * shared tiles, respectively + * + * + */ +template +struct cst { + using identifier = ducks::cst::identifier; + using component = st<_T, _rows, _cols>; /// Data type of each internal tile. + using T = component::T; + using T2 = component::T2; + using dtype = component::dtype; ///< Data type of the elements in the tile. + + static constexpr int rows = component::rows; + static constexpr int cols = component::cols; + static constexpr int height = component::height; + static constexpr int width = component::width; + + // todo: fill in the rest for convenience, but they're all accessible via component so it's not urgent. + + // Real/imag tiles have same internal layout and size + component real; + component imag; + + // vector types + using col_vec = csv; + using row_vec = csv; +}; + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using cst_bf = cst; +template using cst_hf = cst; +template using cst_fl = cst; + + + +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/shared/csv.cuh b/extra/thunder/cuda/include/types/shared/csv.cuh new file mode 100644 index 0000000000..dab205fa23 --- /dev/null +++ b/extra/thunder/cuda/include/types/shared/csv.cuh @@ -0,0 +1,74 @@ +/** + * @file + * @brief Abstraction for a complex register tile composed of real and imaginary tiles + */ + +#pragma once + +#include "st.cuh" + +namespace kittens { + +namespace ducks { +namespace csv { +/** + * @brief A dummy type used to identify complex register tiles. + * + * For a type to quack like an st_cmplx, it should define its identifier as ducks::st::cmplx_identifier. + * If a type quacks like ducks::st::cmplx_identifier, it will be treated as an st_cmplx by compiler checks. + */ +struct identifier {}; +/** +* @brief Concept for shared vectors that are complex. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T is a shared tile. +* - T has a complex tile identifier. +*/ +template concept all = requires { + typename T::identifier; +} && std::is_same_v && ducks::sv::all; + +} // namespace st +} // namespace ducks + +/** + * @brief Complex tile structure + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _height The height of the tile in terms of the number of subtiles. + * @tparam _width The width of the tile in terms of the number of subtiles. + * @tparam _layout The layout of the internal register tiles + * + * This structure is designed to abstract complex number operations internally to the real and imaginary + * shared tiles, respectively + * + * + */ +template +struct csv { + using identifier = ducks::csv::identifier; + using component = sv<_T, _length>; /// Data type of each internal tile. + using T = component::T; + using T2 = component::T2; + using dtype = component::dtype; ///< Data type of the elements in the tile. + + static constexpr int length = component::length; + static constexpr int tiles = component::tiles; + + // todo: fill in the rest for convenience, but they're all accessible via component so it's not urgent. + + // Real/imag tiles have same internal layout and size + component real; + component imag; +}; + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using csv_bf = csv; +template using csv_hf = csv; +template using csv_fl = csv; + +} \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/shared/shared.cuh b/extra/thunder/cuda/include/types/shared/shared.cuh new file mode 100644 index 0000000000..773011b07c --- /dev/null +++ b/extra/thunder/cuda/include/types/shared/shared.cuh @@ -0,0 +1,14 @@ +/** + * @file + * @brief An aggregate header file for all the shared types defined by ThunderKittens. + */ + +#pragma once + +#include "sv.cuh" +#include "st.cuh" + +#include "csv.cuh" +#include "cst.cuh" + +#include "st_descriptor.cuh" \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/shared/st.cuh b/extra/thunder/cuda/include/types/shared/st.cuh new file mode 100644 index 0000000000..8176438382 --- /dev/null +++ b/extra/thunder/cuda/include/types/shared/st.cuh @@ -0,0 +1,349 @@ +/** + * @file + * @brief The ThunderKittens shared tile struct. + */ + +#pragma once + +#include "../../common/common.cuh" +#include "sv.cuh" + +/* ---------- MAIN TILE STRUCT ---------- */ + +// these are helper structs for type inference +namespace kittens { +namespace ducks { +/** + * @namespace rt + * + * @brief The namespace where concepts and abstract types for shared tiles live. + */ +namespace st { +/** + * @brief A dummy type used to identify shared tiles. + * + * For a type to quack like an st, it should define its identifier as ducks::st::identifier. + * If a type quacks like ducks::st::identifier, it will be treated as an st by compiler checks. + * This is particularly useful for subtiles. + */ +struct identifier {}; +/** +* @brief Concept for all shared tiles. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as st::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::st::identifier +} +} // namespace ducks + +// Forward declaration of subtile +template< + typename ST, + int _subtile_height, + int _subtile_width +> +struct st_subtile; + +/** + * @brief Shared memory tile structure for various data types and layouts. + * + * @tparam T The data type of the elements in the tile. Not packed! + * @tparam _rows The height of the tile. + * @tparam _cols The width of the tile. + */ +template +struct KITTENS_DEFAULT_ALIGN st { + using identifier = ducks::st::identifier; ///< Type identifier for shared memory tile. + using T = base_types::packing<_T>::unpacked_type; + using T2 = base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the elements in the tile. + + // define underlying data as same as that projected, to make clear that this is *not* a subtile. + static constexpr int underlying_rows = _rows; + static constexpr int underlying_cols = _cols; + static constexpr int underlying_height = _rows / kittens::TILE_ROW_DIM; + static constexpr int underlying_width = _cols / kittens::TILE_COL_DIM; + static constexpr int underlying_num_elements = underlying_rows * underlying_cols; + + static constexpr int rows = _rows; ///< Total number of rows in the tile. + static_assert(rows % kittens::TILE_ROW_DIM == 0, "Rows must be divisible by the tile dimension"); + static constexpr int cols = _cols; ///< Total number of cols in the tile. + static_assert(cols % kittens::TILE_COL_DIM == 0, "Cols must be divisible by the tile dimension"); + static constexpr int height = _rows / kittens::TILE_ROW_DIM; ///< Height of the tile in terms of 16-element subtiles. + static constexpr int width = _cols / kittens::TILE_COL_DIM; ///< Width of the tile in terms of 16-element subtiles. + static constexpr int num_elements = rows * cols; ///< Total number of elements in the tile. + + static_assert(base_types::packing::num() == 1); // must be a 1-packed type (e.g. float, bf16, etc) + + static constexpr int swizzle_bytes = ( + sizeof(dtype) == 1 ? ( // Add FP8 case + underlying_width%4 == 0 ? 128 : + underlying_width%2 == 0 ? 64 : 32 + ) : + sizeof(dtype) == 2 ? ( + underlying_width%4 == 0 ? 128 : + underlying_width%2 == 0 ? 64 : 32 + ) : + sizeof(dtype) == 4 ? ( + underlying_width%2 == 0 ? 128 : 64 + ) : -1 + ); + + // wgmma layout with swizzling + dtype data[rows*cols]; ///< Raw data storage for the tile. + + __device__ static inline T* idx(T *ptr, int2 coord) { // naive row-major coord default + int r = coord.x, c = coord.y; // alias + static constexpr int swizzle_repeat = swizzle_bytes * 8; + static constexpr int subtile_cols = swizzle_bytes / sizeof(T); + const int outer_idx = c/subtile_cols; + const uint64_t addr = (uint64_t)(&ptr[outer_idx*rows*subtile_cols + r*subtile_cols + c%subtile_cols]); + const int swizzle = ((addr % swizzle_repeat) >> 7) << 4; + return (T*)(addr ^ swizzle); + } + __device__ static inline uint32_t idx(uint32_t ptr, int2 coord) { + int r = coord.x, c = coord.y; // alias + static constexpr int swizzle_repeat = swizzle_bytes * 8; + static constexpr int subtile_cols = swizzle_bytes / sizeof(T); + const int outer_idx = c/subtile_cols; + const uint32_t addr = ptr + sizeof(T)*(outer_idx*rows*subtile_cols + r*subtile_cols + c%subtile_cols); + const int swizzle = ((addr % swizzle_repeat) >> 7) << 4; + return (addr ^ swizzle); + } + /** + * @brief Access a shared tile element using a row and column, as if the tile were row-major. + * + * This is the preferred way to access memory within a shared tile, which abstracts + * indexing calculations for swizzled layouts. + */ + __device__ inline dtype& operator[](const int2 &rowcol) { + return *idx(data, rowcol); + } + __device__ inline const dtype& operator[](const int2 &rowcol) const { + return *(const dtype*)idx((dtype*)data, rowcol); + } + __device__ inline dtype& operator[](int idx) { + return data[idx]; + } + __device__ inline const dtype& operator[](int idx) const { + return data[idx]; + } + + template + __device__ inline st_subtile, subtile_rows, subtile_cols> subtile(int2 rowcol); + + // vector types + using col_vec = sv; ///< Column vector type for this tile + using row_vec = sv; ///< Row vector type for this tile +}; + + + +/** + * @brief A reference into a chunk of shared tile memory. + * + * The st_subtile is a drop-in replacement for an st which internally + * references the appropriate memory while performing minimal address + * calculations. You should never create this directly, but instead + * have subtile_inplace return it for you instead. (`auto` is nice.) + * + * You can generally just pretend this is an st. But not for wgmma's. + */ +template< + typename _ST, + int _subtile_rows, + int _subtile_cols +> +struct st_subtile { + using identifier = ducks::st::identifier; // i quack like an st, gcc will never know the difference + using ST = _ST; + using T = ST::T; + using T2 = ST::T2; + using dtype = T; ///< Data type of the elements in the tile. + + static constexpr int underlying_rows = ST::underlying_rows; + static_assert(underlying_rows % kittens::TILE_ROW_DIM == 0, "Underlying rows must be divisible by the tile dimension"); + static constexpr int underlying_cols = ST::underlying_cols; + static_assert(underlying_cols % kittens::TILE_COL_DIM == 0, "Underlying cols must be divisible by the tile dimension"); + static constexpr int underlying_height = ST::underlying_height; + static constexpr int underlying_width = ST::underlying_width; + static constexpr int underlying_num_elements = ST::underlying_num_elements; + + static constexpr int rows = _subtile_rows; + static_assert(rows % kittens::TILE_ROW_DIM == 0, "Rows must be divisible by the tile dimension"); + static constexpr int cols = _subtile_cols; + static_assert(cols % kittens::TILE_COL_DIM == 0, "Cols must be divisible by the tile dimension"); + static constexpr int height = rows / kittens::TILE_ROW_DIM; + static constexpr int width = cols / kittens::TILE_COL_DIM; + static constexpr int num_elements = rows * cols; + + static constexpr int swizzle_bytes = ST::swizzle_bytes; + + dtype *data; + int row_offset, col_offset; + + __device__ st_subtile(ST &src, int2 rowcol) { + data = &src.data[0]; + row_offset = rowcol.x * rows; + col_offset = rowcol.y * cols; + } + + __device__ inline T* idx(T *ptr, const int2 coord) { // naive row-major coord default + int r = coord.x+row_offset, c = coord.y+col_offset; // alias + static constexpr int swizzle_repeat = swizzle_bytes * 8; + static constexpr int subtile_cols = swizzle_bytes / sizeof(T); + const int outer_idx = c/subtile_cols; + const uint64_t addr = (uint64_t)(&ptr[outer_idx*underlying_rows*subtile_cols + r*subtile_cols + c%subtile_cols]); + const int swizzle = ((addr % swizzle_repeat) >> 7) << 4; + return (T*)(addr ^ swizzle); + } + __device__ inline uint32_t idx(uint32_t ptr, const int2 coord) const { // naive row-major coord default + int r = coord.x+row_offset, c = coord.y+col_offset; // alias + static constexpr int swizzle_repeat = swizzle_bytes * 8; + static constexpr int subtile_cols = swizzle_bytes / sizeof(T); + const int outer_idx = c/subtile_cols; + const uint32_t addr = ptr + sizeof(T)*(outer_idx*underlying_rows*subtile_cols + r*subtile_cols + c%subtile_cols); + const int swizzle = ((addr % swizzle_repeat) >> 7) << 4; + return (addr ^ swizzle); + } + /** + * @brief Access a shared tile element using a row and column, as if the tile were row-major. + * + * This is the preferred way to access memory within a shared tile, which abstracts + * indexing calculations for swizzled layouts. + */ + __device__ inline dtype& operator[](const int2 &rowcol) { + return *idx(data, rowcol); + } + __device__ inline const dtype& operator[](const int2 &rowcol) const { + return *(const dtype*)idx((dtype*)data, rowcol); + } + + // single-coord operator[] is left undefined as it would likely be an improper use of st_subtile type. + // can of course be end-run by just accessing .data directly. + + // vector types + using col_vec = sv; + using row_vec = sv; + + __device__ inline void operator=(const dtype &value) { // runs at warp scope by default + #pragma unroll + for(int i = kittens::laneid(); i < num_elements; i += WARP_THREADS) { + data[i] = value; + } + } +}; + +template // Class template parameters +template // Function template parameters +__device__ inline st_subtile, subtile_rows, subtile_cols> // Return type +st<_T, _rows, _cols>::subtile(int2 rowcol) // Qualified function name and parameters +{ + // Type aliases for convenience within the function body + using ST_t = st<_T, _rows, _cols>; // Alias for the parent tile type + using dtype = typename ST_t::dtype; // Alias for the data type + + // Static assertions (as provided in the initial request) + static_assert(subtile_rows > 0 && subtile_cols > 0, "Subtile dimensions must be positive."); + static_assert(subtile_rows % kittens::TILE_ROW_DIM == 0, + "Subtile rows must be divisible by the base tile row dimension."); + static_assert(subtile_cols % kittens::TILE_COL_DIM == 0, + "Subtile cols must be divisible by the base tile col dimension."); + + // Calculate height/width in terms of base tiles for further checks + constexpr int subtile_height = subtile_rows / kittens::TILE_ROW_DIM; + constexpr int subtile_width = subtile_cols / kittens::TILE_COL_DIM; + static_assert(subtile_height > 0 && subtile_width > 0, "Subtile height/width in base tiles must be positive."); + + // Check divisibility of parent height/width by subtile height/width + static_assert(ST_t::height % subtile_height == 0, + "Parent tile height (in base tiles) must be divisible by subtile height (in base tiles)."); + static_assert(ST_t::width % subtile_width == 0, + "Parent tile width (in base tiles) must be divisible by subtile width (in base tiles)."); + + // Ensure the parent st object is not itself a subtile view by comparing its + // dimensions to its underlying dimensions. + static_assert(ST_t::height == ST_t::underlying_height && ST_t::width == ST_t::underlying_width, + "Cannot create a subtile from an object that appears to be a subtile view (height/width mismatch underlying)."); + // Also check rows/cols directly for robustness, though height/width check might suffice. + static_assert(ST_t::rows == ST_t::underlying_rows && ST_t::cols == ST_t::underlying_cols, + "Cannot create a subtile from an object that appears to be a subtile view (rows/cols mismatch underlying)."); + + + // Construct and return the st_subtile object using its constructor: + // st_subtile(ST &src, int2 rowcol) + // Here, 'src' is the current 'st' object (*this) + return st_subtile(*this, rowcol); +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using st_bf = st; +template using st_hf = st; +template using st_fl = st; +#ifdef KITTENS_HOPPER +template using st_fp8e4m3 = st; +template using st_fp8e5m2 = st; +#ifdef KITTENS_BLACKWELL +template using st_fp8e8m0 = st; +#endif +#endif + +/* ---------- PRINTOUTS ---------- */ + +/** + * @brief Print the contents of a shared tile as a formatted table. + * + * This function should be called by a single thread in the warp. + * It will print the entire tile atomically to avoid interleaved output. + * + * @param tile The shared tile to print + */ +template +__device__ inline void print(const ST& tile) { + printf("Shared Tile %dx%d:\n", ST::rows, ST::cols); + + // Print column headers + printf(" "); // Padding for row indices + for (int c = 0; c < ST::cols; c++) { + printf("%8d ", c); + } + printf("\n"); + + // Print separator line + printf(" "); + for (int c = 0; c < ST::cols; c++) { + printf("--------+"); + } + printf("\n"); + + // Print data rows + for (int r = 0; r < ST::rows; r++) { + printf("%3d |", r); // Row index + for (int c = 0; c < ST::cols; c++) { + if constexpr (std::is_same_v) { + printf("%8.3f ", static_cast(tile[{r,c}])); +#ifdef KITTENS_BLACKWELL + } else if constexpr (std::is_same_v) { + printf("%8.3f ", static_cast(tile[{r,c}])); +#endif + } else if constexpr (std::is_same_v) { + printf("%8.3f ", tile[{r,c}]); + } else if constexpr (std::is_same_v) { + printf("%8.3f ", __bfloat162float(tile[{r,c}])); + } else if constexpr (std::is_integral_v) { + printf("%8d ", (int)tile[{r,c}]); + } else { + printf("%8.3f ", (float)tile[{r,c}]); + } + } + printf("\n"); + } + printf("\n"); +} + +} diff --git a/extra/thunder/cuda/include/types/shared/st_descriptor.cuh b/extra/thunder/cuda/include/types/shared/st_descriptor.cuh new file mode 100644 index 0000000000..d9cc24e111 --- /dev/null +++ b/extra/thunder/cuda/include/types/shared/st_descriptor.cuh @@ -0,0 +1,118 @@ +/** + * @file + * @brief The ThunderKittens shared tile descriptors, used for Hopper and Blackwell tensor cores. + */ + +#pragma once + +#if defined(KITTENS_HOPPER) || defined(KITTENS_BLACKWELL) + +#include "../../common/common.cuh" +#include "st.cuh" +#include "cst.cuh" + +namespace kittens { +namespace ducks { +namespace st_descriptor { +struct identifier {}; +} +} + +namespace detail { +// see https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#asynchronous-warpgroup-level-matrix-shared-memory-layout-matrix-descriptor +__device__ static inline uint64_t matrix_descriptor_encode(uint64_t x) { return (((x) & 0x3FFFF) >> 0x4); } +} + +template +struct st_descriptor { + using identifier = ducks::st_descriptor::identifier; + using ST = _ST; + static constexpr int height = ST::height; + static constexpr int width = ST::width; + using T = ST::T; + uint64_t base_desc; + __device__ inline st_descriptor(const ST &tile) { +#ifdef KITTENS_BLACKWELL + base_desc = detail::matrix_descriptor_encode((uint64_t)(&tile.data[0])) | (1llu<<46); // needed for blackwell shared memory descriptors. +#else + base_desc = detail::matrix_descriptor_encode((uint64_t)(&tile.data[0])); +#endif + if constexpr (transpose) { // transpose mode + if constexpr (ST::width%4 == 0) { + base_desc |= detail::matrix_descriptor_encode((uint64_t)2048*ST::height) << 16; + base_desc |= detail::matrix_descriptor_encode((uint64_t)1024) << 32; + base_desc |= 1llu << 62; // set wgmma_swizzle mode + } + else if constexpr (ST::width%2 == 0) { + base_desc |= detail::matrix_descriptor_encode((uint64_t)1024*ST::height) << 16; + base_desc |= detail::matrix_descriptor_encode((uint64_t)512) << 32; + base_desc |= 2llu << 62; // set wgmma_swizzle mode + } + else { + base_desc |= detail::matrix_descriptor_encode((uint64_t)512*ST::height) << 16; + base_desc |= detail::matrix_descriptor_encode((uint64_t)256) << 32; + base_desc |= 3llu << 62; // set wgmma_swizzle mode + } + } + else { // normal mode + if constexpr (ST::width%4 == 0) { + base_desc |= detail::matrix_descriptor_encode((uint64_t)16) << 16; // this line doesn't matter + base_desc |= detail::matrix_descriptor_encode((uint64_t)1024) << 32; // 128 byte swizzle x 8 for core matrix rows + base_desc |= 1llu << 62; // set wgmma_swizzle mode + } + else if constexpr (ST::width%2 == 0) { + base_desc |= detail::matrix_descriptor_encode((uint64_t)16) << 16; // this line doesn't matter + base_desc |= detail::matrix_descriptor_encode((uint64_t)512) << 32; // 64 byte swizzle x 8 for core matrix rows + base_desc |= 2llu << 62; // set wgmma_swizzle mode + } + else { + base_desc |= detail::matrix_descriptor_encode((uint64_t)16) << 16; // this line doesn't matter + base_desc |= detail::matrix_descriptor_encode((uint64_t)256) << 32; // 32 byte swizzle x 8 for core matrix rows + base_desc |= 3llu << 62; // set wgmma_swizzle mode + } + } + } + __device__ inline st_descriptor(const st_descriptor &other) : base_desc(other.base_desc) {} // copy constructor + __device__ inline uint64_t chunk_descriptor(int chunk_idx) { + if constexpr (transpose) { // transpose mode + if constexpr (ST::width%4 == 0) { + return base_desc + detail::matrix_descriptor_encode(chunk_idx*2048); + } + else if constexpr (ST::width%2 == 0) { + return base_desc + detail::matrix_descriptor_encode(chunk_idx*1024); + } + else { + return base_desc + detail::matrix_descriptor_encode(chunk_idx*512); + } + } + else { // normal mode + if constexpr (ST::width%4 == 0) { + return base_desc + detail::matrix_descriptor_encode((chunk_idx%4)*32 + (chunk_idx/4)*ST::height*2048); + } + else if constexpr (ST::width%2 == 0) { + return base_desc + detail::matrix_descriptor_encode((chunk_idx%2)*32 + (chunk_idx/2)*ST::height*1024); + } + else { + return base_desc + detail::matrix_descriptor_encode(chunk_idx*ST::height*512); + } + } + } +}; + +namespace ducks { +namespace st_descriptor { +// input refers to either an ST directly or to a pre-generated descriptor, which can save cycles in certain situations. +template concept input = ducks::st::all || (requires {typename T::identifier;} && std::is_same_v); +template concept complex_input = ducks::cst::all; +namespace detail { +template struct st_getter { using type = typename T::ST; }; +template struct st_getter { using type = T; }; +template struct st_getter { using type = T::component; }; +template using get_st = typename st_getter::type; +} // namespace detail +} // namespace st_descriptor +} // namespace ducks + +} // namespace kittens + +#endif \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/shared/sv.cuh b/extra/thunder/cuda/include/types/shared/sv.cuh new file mode 100644 index 0000000000..475c51b777 --- /dev/null +++ b/extra/thunder/cuda/include/types/shared/sv.cuh @@ -0,0 +1,130 @@ +/** + * @file + * @brief The ThunderKittens shared vector struct. + */ + +#pragma once + +#include +#include + +#include "../../common/common.cuh" + +namespace kittens { + +/* ---------- MAIN VECTOR STRUCT ---------- */ + +namespace ducks { +/** + * @namespace sv + * + * @brief The namespace where concepts and abstract types for shared vectors live. + */ +namespace sv { +/** + * @brief A dummy type used to identify shared vectors. + * + * For a type to quack like an sv, it should define its identifier as ducks::sv::identifier. + * If a type quacks like ducks::sv::identifier, it will be treated as an sv by compiler checks. + */ +struct identifier {}; +/** +* @brief Concept for all shared vectors. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as sv::identifier. +*/ +template +concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::sv::identifier +} +} + +/** + * @brief Shared vector structure. + * + * @tparam _T The packed data type used for the vector elements. + * @tparam _tiles The size of the tile, in units of TILE_ROW_DIM (16 for fp16, bf16, fp32). + * + * Shared vectors are used to accumulate and map values across shared tiles. + * Unlike every other structure present in ThunderKittens, these have a simple + * uniform layout which is just an array in memory. EZ! + */ +template +struct KITTENS_DEFAULT_ALIGN sv { + using identifier = ducks::sv::identifier; + using T = base_types::packing<_T>::unpacked_type; + using T2 = base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the elements in the tile. + + static constexpr int length = _length; ///< Length in elements. + static_assert(length % TILE_ROW_DIM == 0, "Length must be divisible by the tile dimension"); + static constexpr int tiles = length / TILE_ROW_DIM; ///< Length in subtiles.' + #ifdef KITTENS_HOPPER + static_assert(!std::is_same_v && !std::is_same_v, "Unsupported type for fp8"); + #endif + +#ifdef KITTENS_HOPPER + static constexpr int num_alloc_elements = ((length * sizeof(dtype) + 127) / 128) * (128 / sizeof(dtype)); // round up to the nearest 128-byte boundary +#else + static constexpr int num_alloc_elements = length; +#endif + dtype data[num_alloc_elements]; ///< The actual shared vector data. + + __device__ static inline T* idx(T *ptr, int idx) { // useful for computations in shared address space, as silly as it sounds. + return ptr[idx]; + } + + __device__ inline dtype& operator[](size_t idx) { return data[idx]; } + __device__ inline const dtype& operator[](size_t idx) const { return data[idx]; } + + template __device__ inline sv<_T, sub_length> &subvec(int idx) { + return *(sv*)&data[idx * sub_length]; + } + template __device__ inline const sv<_T, sub_length> &subvec(int idx) const { + return *(sv*)&data[idx * sub_length]; + } + + __device__ inline void operator=(const dtype &value) { // runs at warp scope by default + #pragma unroll + for(int i = kittens::laneid(); i < length; i += WARP_THREADS) { + data[i] = value; + } + } +}; + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// vector types +template using sv_bf = sv; +template using sv_hf = sv; +template using sv_fl = sv; + +/* ---------- PRINTOUTS ---------- */ + +template +__device__ inline void print(const SV& sv) { + printf("Shared Vector %d:\n", SV::length); + for(int i = 0; i < SV::length; i++) { + if constexpr (std::is_same_v) { + printf("%f ", static_cast(sv[i])); +#ifdef KITTENS_BLACKWELL + } else if constexpr (std::is_same_v) { + printf("%f ", static_cast(sv[i])); +#endif + } else if constexpr (std::is_same_v) { + printf("%f ", __bfloat162float(sv[i])); + } else if constexpr (std::is_same_v) { + printf("%f ", __half2float(sv[i])); + } else if constexpr (std::is_same_v) { + printf("%f ", sv[i]); + } else { + printf("%d ", (int)(sv[i])); + } + } + printf("\n"); +} + +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/tensor/tensor.cuh b/extra/thunder/cuda/include/types/tensor/tensor.cuh new file mode 100644 index 0000000000..fd26274b0a --- /dev/null +++ b/extra/thunder/cuda/include/types/tensor/tensor.cuh @@ -0,0 +1,112 @@ +/** + * @file + * @brief An aggregate header file for all the tensor types defined by ThunderKittens. + */ + +#pragma once + +#include "tt.cuh" + +// A thin wrapper that allows for certain compile-time checks to be performed when allocating tensor memory. +namespace kittens { +namespace ducks { +/** + * @namespace tensor_allocator + * + * @brief The namespace where concepts and abstract types for tensor memory allocation live. + */ +namespace tensor_allocator { +/** + * @brief A dummy type used to identify tensor memory. + */ +struct identifier {}; +/** +* @brief Concept for all tensor_allocator types. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as tensor_allocator::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::tt::identifier +} // namespace tensor_allocator +} // namespace ducks + +template struct tensor_allocator { + using identifier = ducks::tensor_allocator::identifier; + static constexpr int nblocks = _nblocks; + static constexpr int cols =((512/nblocks) / 32) * 32; + static constexpr int ncta = _ncta; + uint32_t addr; + template __device__ inline void check_bounds() { + static_assert(col_offset >= 0 && col_offset + TT::cols <= cols, "Tile allocation extends out of bounds of the tensor allocator!"); + } + __device__ inline tensor_allocator() { + __shared__ uint32_t shared_addr; + static_assert(cols>0 && cols%32==0, "cols must be a multiple of 32"); + if constexpr (ncta == 1) { + if(warpid() == 0) { + asm volatile( + "tcgen05.alloc.cta_group::1.sync.aligned.shared::cta.b32 [%0], %1;\n" + :: "l"((uint64_t)&shared_addr), "n"(cols) + ); + asm volatile("tcgen05.relinquish_alloc_permit.cta_group::1.sync.aligned;\n"); + } + } + else { + if(warpid() == 0) { + asm volatile( + "tcgen05.alloc.cta_group::2.sync.aligned.shared::cta.b32 [%0], %1;\n" + :: "l"((uint64_t)&shared_addr), "n"(cols) + ); + asm volatile("tcgen05.relinquish_alloc_permit.cta_group::2.sync.aligned;\n"); + } + } + asm volatile("tcgen05.fence::before_thread_sync;\n"); + asm volatile("bar.sync 0;\n"); + asm volatile("tcgen05.fence::after_thread_sync;\n"); + addr = shared_addr; + } + __device__ inline uint32_t get_addr(int superlane, int col_offset) const { return addr + ((superlane*16) << 16) + col_offset; } + template __device__ inline auto allocate(int superlane, int col_offset) { +#ifndef NDEBUG + if(col_offset + TT::cols > cols) { + printf("Tile allocation extends out of bounds of the tensor allocator! col_offset: %d, TT::cols: %d, allocator cols: %d\n", col_offset, TT::cols, cols); + asm volatile("trap;"); + } + if(superlane < 0 || superlane > 1) { + printf("Superlane must be 0 or 1! superlane: %d\n", superlane); + asm volatile("trap;"); + } +#endif + return TT(get_addr(superlane, col_offset)); + } + template __device__ inline auto allocate(int col_offset) { +#ifndef NDEBUG + if(col_offset + TT::cols > cols) { + printf("Tile allocation extends out of bounds of the tensor allocator! col_offset: %d, TT::cols: %d, allocator cols: %d\n", col_offset, TT::cols, cols); + asm volatile("trap;"); + } +#endif + return TT(get_addr(0, col_offset)); + } + __device__ inline ~tensor_allocator() { // Note that this must be called after all threads are done with that tensor memory -- likely after a syncthreads / cluster::sync()! + if constexpr (ncta == 1) { + if(warpid() == 0) { + asm volatile("tcgen05.dealloc.cta_group::1.sync.aligned.b32 %0, %1;\n" + :: "r"(addr), "n"(cols) + ); + } + } + else { + if(warpid() == 0) { + asm volatile("tcgen05.dealloc.cta_group::2.sync.aligned.b32 %0, %1;\n" + :: "r"(addr), "n"(cols) + ); + } + } + } +}; + +} // namespace kittens \ No newline at end of file diff --git a/extra/thunder/cuda/include/types/tensor/tt.cuh b/extra/thunder/cuda/include/types/tensor/tt.cuh new file mode 100644 index 0000000000..2b1aba2f70 --- /dev/null +++ b/extra/thunder/cuda/include/types/tensor/tt.cuh @@ -0,0 +1,97 @@ +/** + * @file + * @brief The ThunderKittens tensor memory struct. + */ + +#pragma once + +#include "../../common/common.cuh" + +/* ---------- MAIN tt STRUCT ---------- */ + +// these are helper structs for type inference +namespace kittens { +namespace ducks { +/** + * @namespace tt + * + * @brief The namespace where concepts and abstract types for shared tiles live. + */ +namespace tt { +/** + * @brief A dummy type used to identify tensor memory. + */ +struct identifier {}; +/** +* @brief Concept for all tt tiles. +* @tparam T The type to check against the concept requirements. +* +* Requires: +* - T has a nested type identifier that is the same as tt::identifier. +*/ +template concept all = requires { + typename T::identifier; // Checks if T::identifier exists +} && std::is_same_v; // Checks if T::identifier is ducks::tt::identifier +template concept half = all && T::rows == 64; +template concept full = all && T::rows == 128; +} // namespace tt +} // namespace ducks + +/** + * @brief Shared memory tile structure for various data types and layouts. + * + * @tparam T The data type of the elements in the tile. Not packed! + * @tparam _rows The height of the tile. + * @tparam _cols The width of the tile. + */ +template +struct tt { + using identifier = ducks::tt::identifier; ///< Type identifier for shared memory tile. + using T = base_types::packing<_T>::unpacked_type; + using T2 = base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the elements in the tile. + + static constexpr int rows = _rows; + static constexpr int cols = _cols; + static constexpr int height = rows / kittens::TILE_ROW_DIM; + static constexpr int width = cols / kittens::TILE_COL_DIM; + + uint32_t addr; + + __device__ inline tt() : addr(0) {} + __device__ inline tt(uint32_t addr) : addr(addr) {} + + template __device__ inline TT subtile(int row_offset, int col_offset) const { +#ifndef NDEBUG + if(row_offset < 0 || row_offset+TT::rows > rows || col_offset < 0 || col_offset+TT::cols > cols) { + printf("Subtile out of bounds! full tile rows: %d, full tile cols: %d, subtile rows: %d, subtile cols: %d, row_offset: %d, col_offset: %d\n", rows, cols, TT::rows, TT::cols, row_offset, col_offset); + asm volatile("trap;"); + } +#endif + return TT(addr + (row_offset<<16) + col_offset/(4/(uint32_t)sizeof(T))); + } + template __device__ inline uint32_t chunk_addr(int chunk) const { + if constexpr (transpose) { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { + return addr + ((16 * chunk) << 16); + } + else { + static_assert(sizeof(T) == 999, "Currently unsupported type for input to an mma."); + } + } + else { + if constexpr (std::is_same_v || std::is_same_v) { + return addr + (16 * chunk / (4/(uint32_t)sizeof(T))); + } + else if constexpr (std::is_same_v || std::is_same_v) { + return addr + (32 * chunk / (4/(uint32_t)sizeof(T))); + } + else { + static_assert(sizeof(T) == 999, "Currently unsupported type for input to an mma."); + } + } + } + +}; + +} // namespace kittens diff --git a/extra/thunder/cuda/include/types/types.cuh b/extra/thunder/cuda/include/types/types.cuh new file mode 100644 index 0000000000..42fbb1a3d5 --- /dev/null +++ b/extra/thunder/cuda/include/types/types.cuh @@ -0,0 +1,68 @@ +/** + * @file + * @brief An aggregate header file for all the register and shared types defined by ThunderKittens. + */ + +#pragma once + +#include "device/device.cuh" +#include "register/register.cuh" +#include "shared/shared.cuh" +#include "global/global.cuh" +#if defined(KITTENS_HOPPER) || defined(KITTENS_BLACKWELL) +#include "device/device.cuh" +#endif +#ifdef KITTENS_BLACKWELL +#include "tensor/tensor.cuh" +#endif + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +namespace kittens { + +/** + * @brief Row vector type alias. + * + * This template alias provides a convenient way to refer to the row vector type + * associated with a given class or type `T`. It assumes that the class `T` has + * a nested type named `row_vec`. + * + * @tparam T The class or type for which the row vector type is defined. + * + * Example usage: + * @code + * kittens::row_vec row_vector; + * @endcode + */ +template +using row_vec = T::row_vec; + +/** + * @brief Column vector type alias. + * + * This template alias provides a convenient way to refer to the column vector type + * associated with a given class or type `T`. It assumes that the class `T` has + * a nested type named `col_vec`. + * + * @tparam T The class or type for which the column vector type is defined. + * + * Example usage: + * @code + * kittens::col_vec col_vector; + * @endcode + */ +template +using col_vec = T::col_vec; + +// ^ this code lives here because it applies to both sv and rv types + +// register tile layouts +using row_l = ducks::rt_layout::row; +using col_l = ducks::rt_layout::col; + +// register vector layouts +using align_l = ducks::rv_layout::align; +using ortho_l = ducks::rv_layout::ortho; +using naive_l = ducks::rv_layout::naive; + +} diff --git a/extra/thunder/cuda/matmul.cu b/extra/thunder/cuda/matmul.cu new file mode 100644 index 0000000000..3f0ea766d1 --- /dev/null +++ b/extra/thunder/cuda/matmul.cu @@ -0,0 +1,45 @@ +// https://github.com/HazyResearch/ThunderKittens/blob/main/kernels/matmul/educational/level_04.cu +#include "kittens.cuh" +using namespace kittens; + +constexpr int g_N = 8192; +constexpr int BLOCK_SIZE = 32; +#define NUM_WORKERS (1) + +using sub_tile = st_bf; +using tile_gl = gl; + +__launch_bounds__(NUM_WORKERS*WARP_THREADS, 1) +__global__ void kernel(bf16 *c_ptr, bf16 *a_ptr, bf16 *b_ptr) { + tile_gl g_C{c_ptr, nullptr, nullptr, nullptr, nullptr}; + tile_gl g_A{a_ptr, nullptr, nullptr, nullptr, nullptr}; + tile_gl g_B{b_ptr, nullptr, nullptr, nullptr, nullptr}; + + extern __shared__ alignment_dummy __shm[]; + shared_allocator al((int*)&__shm[0]); + st_bf &As = al.allocate>(); + st_bf &Bs = al.allocate>(); + + rt_bf A_reg; + rt_bf B_reg; + rt_bf B_reg_col; + rt_fl C_accum; + + int col = blockIdx.x; + int row = blockIdx.y; + + warp::zero(C_accum); + int num_tiles = (g_N + BLOCK_SIZE - 1) / BLOCK_SIZE; + for (int tile = 0; tile < num_tiles; ++tile) { + warp::load(As, g_A, {0, 0, row, tile}); + warp::load(Bs, g_B, {0, 0, tile, col}); + __syncthreads(); + warp::load(A_reg, As); + warp::load(B_reg, Bs); + warp::swap_layout(B_reg_col, B_reg); + __syncthreads(); + warp::mma_AB(C_accum, A_reg, B_reg_col, C_accum); + __syncthreads(); + } + warp::store(g_C, C_accum, {0, 0, row, col}); +} diff --git a/extra/thunder/cuda/matmul.py b/extra/thunder/cuda/matmul.py new file mode 100644 index 0000000000..ace4cd9adf --- /dev/null +++ b/extra/thunder/cuda/matmul.py @@ -0,0 +1,55 @@ +import pathlib +from tinygrad import Device, Tensor +from tinygrad.helpers import Context, getenv +from tinygrad.runtime.support.compiler_cuda import pretty_ptx, NVCCCompiler + +if __name__ == "__main__": + if getenv("MATMUL2"): + code = (pathlib.Path(__file__).parent / "matmul2.cu").read_text() + else: + code = (pathlib.Path(__file__).parent / "matmul.cu").read_text() + + device = Device["CUDA"] + kitten_args = [f"-I{(pathlib.Path(__file__).parent / 'include').as_posix()}", "-std=c++20", "--expt-relaxed-constexpr"] + lib = NVCCCompiler(device.compiler.arch, kitten_args).compile(code) + kernel_name = lib.decode().split(".globl\t")[1].split("\n")[0] + print("kernel name", kernel_name) + print(pretty_ptx(lib.decode())) + + prg = device.runtime(kernel_name, lib) + if getenv("MATMUL2"): + prg.smem = 16384 * 2 + else: + prg.smem = 10000 + + N = 8192 + a = Tensor.randn(N, N, device='CUDA', dtype="bfloat16") + b = Tensor.randn(N, N, device='CUDA', dtype="bfloat16") + c = Tensor.empty(N, N, device='CUDA', dtype="bfloat16") + Tensor.realize(a, b, c) + + WARP_THREADS = 32 + if getenv("MATMUL2"): + SUPER_N = 2 + SUPER_M = 2 + NUM_WORKERS = SUPER_N * SUPER_M + BLOCK_SIZE = 32 + gsz = (N // (BLOCK_SIZE * SUPER_N), N // (BLOCK_SIZE * SUPER_M), 1) + else: + NUM_WORKERS = 1 + BLOCK_SIZE = 32 + gsz = (N // (BLOCK_SIZE), N // (BLOCK_SIZE), 1) + + for _ in range(5): + et = prg(c.uop.buffer.ensure_allocated()._buf, a.uop.buffer._buf, b.uop.buffer._buf, + global_size=gsz, local_size=(NUM_WORKERS*WARP_THREADS,1,1), wait=True) + print(f"{N*N*N*2/(et*1e9):2f} GFLOPS") + + # print(c.tolist()) + + for _ in range(5): + with Context(DEBUG=2): + ref = (a@b).realize() + + ref, c = ref.float(), c.float() + print((ref-c).mean().item(), (ref-c).max().item()) diff --git a/extra/thunder/cuda/matmul2.cu b/extra/thunder/cuda/matmul2.cu new file mode 100644 index 0000000000..6c31cf5766 --- /dev/null +++ b/extra/thunder/cuda/matmul2.cu @@ -0,0 +1,105 @@ +#include "kittens.cuh" +using namespace kittens; + +constexpr int g_N = 8192; + +constexpr int SUPER_N = 2; +constexpr int SUPER_M = 2; +constexpr int NUM_WORKERS = SUPER_N * SUPER_M; +constexpr int LOAD_TASKS = SUPER_N + SUPER_M; + +constexpr int WORKER_M = 32; +constexpr int WORKER_N = 32; + +constexpr int BLOCK_K = 32; +constexpr int BLOCK_M = WORKER_M * SUPER_M; +constexpr int BLOCK_N = WORKER_N * SUPER_N; + +constexpr int PIPE_STAGES = 2; + +using reg_tile_A = rt_bf; +using reg_tile_B_col = rt_bf; +using reg_tile_C = rt_fl; + +using shared_tile_A = st_bf; +using shared_tile_B = st_bf; +using shared_tile_C = st_bf; + +using gl_tile_A = gl; +using gl_tile_B = gl; +using gl_tile_C = gl; + +__launch_bounds__(NUM_WORKERS *WARP_THREADS, 1) __global__ + void kernel(bf16 *c_ptr, bf16 *a_ptr, bf16 *b_ptr) { + gl_tile_C g_C{c_ptr, nullptr, nullptr, nullptr, nullptr}; + gl_tile_A g_A{a_ptr, nullptr, nullptr, nullptr, nullptr}; + gl_tile_B g_B{b_ptr, nullptr, nullptr, nullptr, nullptr}; + + extern __shared__ alignment_dummy __shm[]; + shared_allocator al((int *)&__shm[0]); + + shared_tile_A(&As)[SUPER_M][PIPE_STAGES] = + al.allocate(); + shared_tile_B(&Bs)[SUPER_N][PIPE_STAGES] = + al.allocate(); + + reg_tile_A A_reg; + reg_tile_B_col B_reg_col; + reg_tile_C C_accum; + + int warpid = kittens::warpid(); + int warp_m = warpid % SUPER_M; + int warp_n = warpid / SUPER_M; + + int load_group_id = warpgroup::groupid(); + + int block_row = blockIdx.y * SUPER_M; + int block_col = blockIdx.x * SUPER_N; + + warp::zero(C_accum); + int num_tiles = (g_N + BLOCK_K - 1) / BLOCK_K; + + for (int load_tile = 0; load_tile < (PIPE_STAGES - 1); load_tile++) { + if (load_tile < num_tiles) { + int load_smem_idx = load_tile % PIPE_STAGES; + for (int task_id = warpid; task_id < LOAD_TASKS; task_id += NUM_WORKERS) { + if (task_id < SUPER_M) { + warp::load_async(As[task_id][load_smem_idx], g_A, {0, 0, block_row + task_id, load_tile}); + } else { + int n_index = task_id - SUPER_M; + warp::load_async(Bs[n_index][load_smem_idx], g_B, {0, 0, load_tile, block_col + n_index}); + } + } + } + } + + for (int tile = 0; tile < num_tiles; tile++) { + int compute_smem_idx = tile % PIPE_STAGES; + + int load_tile = tile + PIPE_STAGES - 1; + int load_smem_idx = load_tile % PIPE_STAGES; + + if (load_tile < num_tiles) { + for (int task_id = warpid; task_id < LOAD_TASKS; task_id += NUM_WORKERS) { + if (task_id < SUPER_M) { + warp::load_async(As[task_id][load_smem_idx], g_A, + {0, 0, block_row + task_id, load_tile}); + } else { + int n_index = task_id - SUPER_M; + warp::load_async(Bs[n_index][load_smem_idx], g_B, + {0, 0, load_tile, block_col + n_index}); + } + } + load_async_wait<1>(); + } else + load_async_wait(); + __syncthreads(); + + warp::load(A_reg, As[warp_m][compute_smem_idx]); + warp::load(B_reg_col, Bs[warp_n][compute_smem_idx]); + + warp::mma_AB(C_accum, A_reg, B_reg_col, C_accum); + __syncthreads(); + } + warp::store(g_C, C_accum, {0, 0, block_row + warp_m, block_col + warp_n}); +} diff --git a/extra/thunder/metal/gemm.py b/extra/thunder/metal/gemm.py new file mode 100644 index 0000000000..61d3dae787 --- /dev/null +++ b/extra/thunder/metal/gemm.py @@ -0,0 +1,74 @@ +# include directory copied from https://github.com/HazyResearch/ThunderMittens +# https://hazyresearch.stanford.edu/blog/2024-11-28-tk-mlx + +gemm = """ +#include +#include "include/tk.metal" +using namespace mittens; + +#define GEMM_PARAMS_DEF(T) \ + device T* D [[buffer(0)]], \ + device T* A [[buffer(1)]], \ + device T* B [[buffer(2)]], \ + const constant int &N [[buffer(3)]], \ + const constant int &K [[buffer(4)]], \ + const constant int &M [[buffer(5)]], \ + uint3 tg_id [[threadgroup_position_in_grid]], \ + uint simd_lane_id [[thread_index_in_simdgroup]] + +template +kernel void matmul_naive(GEMM_PARAMS_DEF(T)) { + using global_layout = gl; + global_layout gl_a(A, nullptr, nullptr, N, K); + global_layout gl_b(B, nullptr, nullptr, K, M); + global_layout gl_d(D, nullptr, nullptr, N, M); + rt a_reg; + rt b_reg; + rt d_reg; + zero(d_reg); + #pragma clang loop unroll(full) + for (int k = 0; k < K / (K_BLOCK * TILE_DIM); k++) { + load(a_reg, gl_a, {0, 0, (int)tg_id.y, k}, simd_lane_id); + load(b_reg, gl_b, {0, 0, k, (int)tg_id.x}, simd_lane_id); + mma_AB(d_reg, a_reg, b_reg, d_reg); + } + store(gl_d, d_reg, {0, 0, (int)tg_id.y, (int)tg_id.x}, simd_lane_id); +} + +#define instantiate_matmul_custom(type_name, T) \ + template [[host_name("matmul_custom_" #type_name)]] [[kernel]] \ + void matmul_naive(GEMM_PARAMS_DEF(T)); \ + +instantiate_matmul_custom(float32, float); +""" + +from tinygrad import Device, Tensor, Context + +if __name__ == "__main__": + device = Device["METAL"] + lib = device.compiler.compile(gemm) + prg = device.runtime("matmul_custom_float32", lib) + + N = 4096 + a = Tensor.randn(N, N) + b = Tensor.randn(N, N) + c = Tensor.empty(N, N) + Tensor.realize(a, b, c) + + TILE_DIM = 8 + N_BLOCK = 4 + M_BLOCK = 4 + + gsz = (N // (M_BLOCK * TILE_DIM), N // (N_BLOCK * TILE_DIM), 1) + for _ in range(5): + et = prg(c.uop.buffer.ensure_allocated()._buf, a.uop.buffer._buf, b.uop.buffer._buf, + global_size=gsz, local_size=(32,1,1), vals=(N, N, N), wait=True) + print(f"{N*N*N*2/(et*1e9):2f} GFLOPS") + + for _ in range(5): + with Context(DEBUG=2): + ref = (a@b).realize() + + print((ref-c).mean().item()) + + diff --git a/extra/thunder/metal/include/common/base_ops.metal b/extra/thunder/metal/include/common/base_ops.metal new file mode 100644 index 0000000000..c3a28c813c --- /dev/null +++ b/extra/thunder/metal/include/common/base_ops.metal @@ -0,0 +1,392 @@ +/** + * @file + * @brief Basic operations on generic types. + */ +#pragma once +#include "base_types.metal" +#include + +namespace mittens { +/** + * @namespace base_ops + * + * @brief A namespace for operations on basic data types. + */ +namespace base_ops { +#define TEMPLATE_OPS_SINGLE(func_contents) \ + template static METAL_FUNC T op(device const T &x) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &x) { func_contents } \ + template static METAL_FUNC T op(thread const T &x) { func_contents } + +#define TEMPLATE_OPS_OVERRIDE_SINGLE(T, op_name, func_contents) \ + template<> METAL_FUNC T op_name::op(device const T &x) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &x) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &x) { func_contents } + +#define TEMPLATE_OPS_DOUBLE(func_contents) \ + template static METAL_FUNC T op(device const T &a, device const T &b) { func_contents } \ + template static METAL_FUNC T op(device const T &a, threadgroup const T &b) { func_contents } \ + template static METAL_FUNC T op(device const T &a, thread const T &b) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, device const T &b) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, threadgroup const T &b) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, thread const T &b) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, device const T &b) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, threadgroup const T &b) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, thread const T &b) { func_contents } + +#define TEMPLATE_OPS_OVERRIDE_DOUBLE(T, op_name, func_contents) \ + template<> METAL_FUNC T op_name::op(device const T &a, device const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, threadgroup const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, thread const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, device const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, threadgroup const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, thread const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, device const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, threadgroup const T &b) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, thread const T &b) { func_contents } + +#define TEMPLATE_OPS_TRIPLE(func_contents) \ + template static METAL_FUNC T op(device const T &a, device const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, device const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, device const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, threadgroup const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, threadgroup const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, threadgroup const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, thread const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, thread const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(device const T &a, thread const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, device const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, device const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, device const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, threadgroup const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, threadgroup const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, threadgroup const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, thread const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, thread const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(threadgroup const T &a, thread const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, device const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, device const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, device const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, threadgroup const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, threadgroup const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, threadgroup const T &b, thread const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, thread const T &b, device const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, thread const T &b, threadgroup const T &c) { func_contents } \ + template static METAL_FUNC T op(thread const T &a, thread const T &b, thread const T &c) { func_contents } + +#define TEMPLATE_OPS_OVERRIDE_TRIPLE(T, op_name, func_contents) \ + template<> METAL_FUNC T op_name::op(device const T &a, device const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, device const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, device const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, threadgroup const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, threadgroup const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, threadgroup const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, thread const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, thread const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(device const T &a, thread const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, device const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, device const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, device const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, threadgroup const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, threadgroup const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, threadgroup const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, thread const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, thread const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(threadgroup const T &a, thread const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, device const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, device const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, device const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, threadgroup const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, threadgroup const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, threadgroup const T &b, thread const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, thread const T &b, device const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, thread const T &b, threadgroup const T &c) { func_contents } \ + template<> METAL_FUNC T op_name::op(thread const T &a, thread const T &b, thread const T &c) { func_contents } + + + +/* ---------- CONST OPS ---------- */ + +/** + * @brief Represents the zero constant operation. + * + * This operation returns the zero value of the specified type. + * + * @tparam T The data type for which to return the zero value. + * @return The zero value of type T. + */ +struct zero { + template static METAL_FUNC constexpr T op(args... _) { return base_types::constants::zero(); } +}; +/** + * @brief Represents the one constant operation. + * + * This operation returns the one value of the specified type. + * + * @tparam T The data type for which to return the one value. + * @return The one value of type T. + */ +struct one { + template static METAL_FUNC constexpr T op(args... _) { return base_types::constants::one(); } +}; + +/** + * @brief Represents the positive infinity constant operation. + * + * This operation returns the positive infinity value of the specified type. + * + * @tparam T The data type for which to return the positive infinity value. + * @return The positive infinity value of type T. + */ +struct pos_infty { + template static METAL_FUNC constexpr T op(args... _) { return base_types::constants::pos_infty(); } +}; +/** + * @brief Represents the negative infinity constant operation. + * + * This operation returns the negative infinity value of the specified type. + * + * @tparam T The data type for which to return the negative infinity value. + * @return The negative infinity value of type T. + */ +struct neg_infty { + template static METAL_FUNC constexpr T op(args... _) { return base_types::constants::neg_infty(); } +}; + + +/* ---------- UNARY OPS ---------- */ +/** + * @brief Exponential function operation. + * + * This operation calculates the exponential of the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The exponential of the input value. + */ +struct exp { + TEMPLATE_OPS_SINGLE(return metal::exp(x);) +}; + +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16, exp, return bf16(metal::exp((float)x));) +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16_2, exp, return bf16_2(metal::exp(float2(x)));) + + /** + * @brief Exponential function operation, in base 2 + * + * This operation calculates the exponential of the input value, in base 2. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The exponential of the input value. + */ +struct exp2 { + template static METAL_FUNC T op(device const T &x) { return metal::exp2(x); } \ + template static METAL_FUNC T op(threadgroup const T &x) { return metal::exp2(x); } \ + template static METAL_FUNC T op(thread const T &x) { return metal::exp2(x); } +}; + +//template<> METAL_FUNC bf16 exp2::op(device const bf16 &x) { return bf16(metal::exp2(x)); } \ +//template<> METAL_FUNC bf16 exp2::op(threadgroup const bf16 &x) { return bf16(metal::exp2(x)); } \ +//template<> METAL_FUNC bf16 exp2::op(thread const bf16 &x) { return bf16(metal::exp2(x)); } +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16, exp2, return bf16(metal::exp2(x));) +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16_2, exp2, return bf16_2(metal::exp2((float2)x));) + +/** + * @brief Natural log function operation. + * + * This operation calculates the natural logarithm of the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The natural logarithm of the input value. + */ +struct log { + TEMPLATE_OPS_SINGLE(return metal::log(x);) +}; +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16, log, return bf16(metal::log(x));) +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16_2, log, return bf16_2(metal::log((float2)x));) + +/** + * @brief Absolute value operation. + * + * This operation calculates the absolute value of the input. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The absolute value of the input. + */ +struct abs { + TEMPLATE_OPS_SINGLE(return metal::abs(x);) +}; +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16 , abs, return bf16(metal::abs((float)x));) +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16_2, abs, return bf16_2(metal::abs((float2)x));) +/** + * @brief Rectified Linear Unit (ReLU) operation. + * + * This operation applies the ReLU function to the input, which is the + * maximum of zero and the input value. + * + * @tparam T The data type of the input and output values. + * @param x[in] The input value. + * @return The result of ReLU function applied to the input. + */ +struct relu { + TEMPLATE_OPS_SINGLE(return max(x, base_types::constants::zero());) +}; +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16 , relu, return bf16(metal::max((float)x, base_types::constants::zero()));) +TEMPLATE_OPS_OVERRIDE_SINGLE(bf16_2, relu, return bf16_2(metal::max((float2)x, base_types::constants::zero()));) +/** + * @brief Copy operation. + * + * This operation returns the input value unchanged. + * + * @tparam T The data type of the input and output values. + * @param a[in] The input value. + * @return The same value as the input. + */ +struct copy { // for non-compile-time setters. + TEMPLATE_OPS_SINGLE(return x;) +}; + +/* ---------- BINARY OPS ---------- */ + + +/** + * @brief Copy2 operation. + * + * This operation returns the second input value unchanged. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value (ignored). + * @param b[in] The second input value. + * @return The same value as the second input. + */ +struct copy2 { // this turns out to be a slightly hacky op that makes some code cleaner :/ + TEMPLATE_OPS_DOUBLE(return b;) +}; +/** + * @brief Sum operation. + * + * This operation calculates the sum of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The sum of the input values. + */ +struct sum { + TEMPLATE_OPS_DOUBLE(return a+b;) +}; + +/** + * @brief Subtraction operation. + * + * This operation calculates the difference between two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The difference between the input values. + */ +struct sub { + TEMPLATE_OPS_DOUBLE(return a-b;) +}; +/** + * @brief Multiplication operation. + * + * This operation calculates the product of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The product of the input values. + */ +struct mul { + TEMPLATE_OPS_DOUBLE(return a*b;) +}; +/** + * @brief Division operation. + * + * This operation calculates the quotient of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The quotient of the input values. + */ +struct div { + TEMPLATE_OPS_DOUBLE(return a/b;) +}; +/** + * @brief Maximum operation. + * + * This operation calculates the maximum of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The maximum of the input values. + */ +struct max { + TEMPLATE_OPS_DOUBLE(return metal::max(a,b);) +}; +TEMPLATE_OPS_OVERRIDE_DOUBLE(bf16 , max, return (bf16)metal::max((float)a, (float)b);) +TEMPLATE_OPS_OVERRIDE_DOUBLE(bf16_2, max, return (bf16_2)metal::max((float2)a, (float2)b);) +/** + * @brief Minimum operation. + * + * This operation calculates the minimum of two input values. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @return The minimum of the input values. + */ +struct min { + TEMPLATE_OPS_DOUBLE(return metal::min(a,b);) +}; +TEMPLATE_OPS_OVERRIDE_DOUBLE(bf16 , min, return (bf16)metal::min((float)a, (float)b);) +TEMPLATE_OPS_OVERRIDE_DOUBLE(bf16_2, min, return (bf16_2)metal::min((float2)a, (float2)b);) + + +/* ---------- TERNARY OPS ---------- */ +/** + * @brief Fused multiply-add operation A * B + C. + * + * This operation performs a fused multiply-add, computing (A * B) + C with only one rounding. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The second input value. + * @param c[in] The third input value to be added. + * @return The result of the fused multiply-add operation. + */ +struct fma_AxBtC { + TEMPLATE_OPS_TRIPLE(return sum::op(mul::op(a, b), c);) +}; + +/** + * @brief Fused multiply-add operation A * C + B. + * + * This operation performs a fused multiply-add, computing (A * C) + B with only one rounding. + * This is particularly useful for attention mechanisms in neural networks. + * + * @tparam T The data type of the input and output values. + * @param a[in] The first input value. + * @param b[in] The third input value to be added. + * @param c[in] The second input value. + * @return The result of the fused multiply-add operation. + */ +struct fma_AxCtB { // this is the one needed for attention + TEMPLATE_OPS_TRIPLE(return sum::op(mul::op(a, c), b);) +}; + +#undef TEMPLATE_OPS_SINGLE +#undef TEMPLATE_OPS_OVERRIDE_SINGLE +#undef TEMPLATE_OPS_DOUBLE +#undef TEMPLATE_OPS_OVERRIDE_DOUBLE +#undef TEMPLATE_OPS_TRIPLE +#undef TEMPLATE_OPS_OVERRIDE_TRIPLE +} // base_ops +} // mittens diff --git a/extra/thunder/metal/include/common/base_types.metal b/extra/thunder/metal/include/common/base_types.metal new file mode 100644 index 0000000000..5647580a80 --- /dev/null +++ b/extra/thunder/metal/include/common/base_types.metal @@ -0,0 +1,321 @@ + +#pragma once + +namespace mittens { + +using bf16 = bfloat; +using bf16_2 = bfloat2; +using bf16_4 = bfloat4; +//using half_2 = half2; + +namespace ducks { +namespace base_types { +template +static METAL_FUNC constexpr const bool isT1() { + return metal::is_same::value || + metal::is_same::value || + metal::is_same::value; +} +template +static METAL_FUNC constexpr const bool isT2() { + return metal::is_same::value || + metal::is_same::value || + metal::is_same::value; +} + +template +static METAL_FUNC constexpr const bool isT1Type() { + return metal::is_same::value || + metal::is_same::value || + metal::is_same::value; +} +template +static METAL_FUNC constexpr const bool isT2Type() { + return metal::is_same::value || + metal::is_same::value || + metal::is_same::value; +} + +template +static METAL_FUNC constexpr const bool isT1Ptr() { + return metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value; +} +template +static METAL_FUNC constexpr const bool isT2Ptr() { + return metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value || + metal::is_same::value; +} + +template +static METAL_FUNC constexpr const bool isTKType() { // good enough + return !isT1Type() && !isT2Type() && !isT1Ptr() && !isT2Ptr(); +} + +} // namespace base_types +} // namespace ducks + +/** + * @namespace base_types + * + * @brief A namespace for Thundermittens basic data types. + */ +namespace base_types { +/** + * @brief Provides compile-time constants for different types. + * + * @tparam T The type for which to provide constants. + */ +template struct constants { + /** + * @brief Zero + * @return Constexpr zero with type T + */ + static METAL_FUNC constexpr T zero() { return T{0}; } + /** + * @brief One + * @return Constexpr one with type T + */ + static METAL_FUNC constexpr T one() { return T{1}; } + /** + * @brief Positive infinity. Particularly useful for initializing before a min op. + * @return Constexpr positive infinity with type T + */ + static METAL_FUNC constexpr T pos_infty() { return T{INFINITY}; } // I'll find a better way at some point but this appears to work. + /** + * @brief Negative infinity. Particularly useful for initializing before a max op. + * @return Constexpr negative infinity with type T + */ + static METAL_FUNC constexpr T neg_infty() { return T{-INFINITY}; } +}; +template<> struct constants { + static METAL_FUNC constexpr float zero() { return 0.f; } + static METAL_FUNC constexpr float one() { return 1.f; } + static METAL_FUNC constexpr float pos_infty() { return INFINITY; } + static METAL_FUNC constexpr float neg_infty() { return -INFINITY; } +}; +template<> struct constants { + static METAL_FUNC constexpr float2 zero() { return float2(0.f, 0.f); } + static METAL_FUNC constexpr float2 one() { return float2(1.f, 1.f); } + static METAL_FUNC constexpr float2 pos_infty() { return float2(constants::pos_infty(), constants::pos_infty()); } + static METAL_FUNC constexpr float2 neg_infty() { return float2(constants::neg_infty(), constants::neg_infty()); } +}; +template<> struct constants { + static METAL_FUNC constexpr bf16 zero() { return 0.bf; } + static METAL_FUNC constexpr bf16 one() { return 1.bf; } + static METAL_FUNC constexpr bf16 pos_infty() { return HUGE_VALBF; } + static METAL_FUNC constexpr bf16 neg_infty() { return -HUGE_VALBF; } +}; +template<> struct constants { + static METAL_FUNC constexpr bf16_2 zero() { return bf16_2(constants::zero(), constants::zero()); } + static METAL_FUNC constexpr bf16_2 one() { return bf16_2(constants::one(), constants::one()); } + static METAL_FUNC constexpr bf16_2 pos_infty() { return bf16_2(constants::pos_infty(), constants::pos_infty()); } + static METAL_FUNC constexpr bf16_2 neg_infty() { return bf16_2(constants::neg_infty(), constants::neg_infty()); } +}; +template<> struct constants { + static METAL_FUNC constexpr half zero() { return half(0.h); } + static METAL_FUNC constexpr half one() { return half(1.h); } + static METAL_FUNC constexpr half pos_infty() { return HUGE_VALH; } + static METAL_FUNC constexpr half neg_infty() { return -HUGE_VALH; } +}; + +template<> struct constants { + static METAL_FUNC constexpr half2 zero() { return half2(constants::zero(), constants::zero()); } + static METAL_FUNC constexpr half2 one() { return half2(constants::one(), constants::one()); } + static METAL_FUNC constexpr half2 pos_infty() { return half2(constants::pos_infty(), constants::pos_infty()); } + static METAL_FUNC constexpr half2 neg_infty() { return half2(constants::neg_infty(), constants::neg_infty()); } +}; + + + +/** + * @brief Provides information about packing of elements for a given type. + * + * @tparam T The type for which to provide packing information. + */ +template struct packing { +// /** +// * @brief The number of elements packed together. +// * +// * @return constexpr int representing number of elements within the type. +// */ +// static METAL_FUNC constexpr int num() { return 1; } +// /** +// * @brief Packs a single T element twice (replicated) into its packed type. +// * +// * @param i[in] The element to pack. +// * @return The packed type. +// */ +// static METAL_FUNC constexpr T pack(device const bf16 &i); +// static METAL_FUNC constexpr T pack(threadgroup const bf16 &i); +// static METAL_FUNC constexpr T pack(thread const bf16 &i); +}; + +#define PACK_FUNCTIONS(T1, T2) \ + static METAL_FUNC constexpr T2 pack(device const T1 &i) { return T2{i, i}; } \ + static METAL_FUNC constexpr T2 pack(threadgroup const T1 &i) { return T2{i, i}; } \ + static METAL_FUNC constexpr T2 pack(thread const T1 &i) { return T2{i, i}; } + +template<> struct packing { + static METAL_FUNC constexpr int num() { return 1; } + using unpacked_type = bf16; + using packed_type = bf16_2; + using packed_four = bf16_4; + PACK_FUNCTIONS(unpacked_type, packed_type) +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 1; } + using unpacked_type = half; + using packed_type = half2; + using packed_four = half4; + PACK_FUNCTIONS(unpacked_type, packed_type) +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 1; } + using unpacked_type = float; + using packed_type = float2; + using packed_four = float4; + + PACK_FUNCTIONS(unpacked_type, packed_type) +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 2; } + using unpacked_type = bf16; + using packed_type = bf16_2; + using packed_four = bf16_4; + PACK_FUNCTIONS(unpacked_type, packed_type) +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 2; } + using unpacked_type = half; + using packed_type = half2; + using packed_four = half4; + PACK_FUNCTIONS(unpacked_type, packed_type) +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 2; } + using unpacked_type = float; + using packed_type = float2; + using packed_four = float4; + PACK_FUNCTIONS(unpacked_type, packed_type) +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 2; } +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 4; } +}; +template<> struct packing { + static METAL_FUNC constexpr int num() { return 4; } +}; + + +/** + * @brief Provides templated functionality to convert between different types. + * + * @tparam T The target type for conversion. + * @tparam U The source type for conversion. + */ +template struct convertor { + /** + * @brief Converts a value of type U to type T. + * + * @param u[in] The value of type U to convert. + * @return T The converted value of type T. + */ + static METAL_FUNC T convert(device const U & u) { return (T)u; } + static METAL_FUNC T convert(threadgroup const U & u) { return (T)u; } + static METAL_FUNC T convert(thread const U & u) { return (T)u; } +}; + +template<> struct convertor { + // fptrunc float %_ to bfloat + static METAL_FUNC float convert(device const bf16 & u) { return float(u);} + static METAL_FUNC float convert(threadgroup const bf16 & u) { return float(u);} + static METAL_FUNC float convert(thread const bf16 & u) { return float(u);} +}; +template<> struct convertor { + // fpext bfloat %_ to float + static METAL_FUNC bf16 convert(device const float & u) { return bf16(u); } + static METAL_FUNC bf16 convert(threadgroup const float & u) { return bf16(u); } + static METAL_FUNC bf16 convert(thread const float & u) { return bf16(u); } +}; +template<> struct convertor { + // tail call fast <2 x float> @air.convert.f.v2f32.f.v2bf16(<2 x bfloat> %_) + static METAL_FUNC float2 convert(device const bf16_2 & u) { return float2(u); } + static METAL_FUNC float2 convert(threadgroup const bf16_2 & u) { return float2(u); } + static METAL_FUNC float2 convert(thread const bf16_2 & u) { return float2(u); } +}; +template<> struct convertor { + // tail call fast <2 x bfloat> @air.convert.f.v2bf16.f.v2f32(<2 x float> %_) + static METAL_FUNC bf16_2 convert(device const float2 & u) { return bf16_2(u); } + static METAL_FUNC bf16_2 convert(threadgroup const float2 & u) { return bf16_2(u); } + static METAL_FUNC bf16_2 convert(thread const float2 & u) { return bf16_2(u); } +}; + +template<> struct convertor { + // fptrunc float %_ to half + static METAL_FUNC float convert(device const half & u) { return float(u); } + static METAL_FUNC float convert(threadgroup const half & u) { return float(u); } + static METAL_FUNC float convert(thread const half & u) { return float(u); } +}; +template<> struct convertor { + //fpext half %_ to float + static METAL_FUNC half convert(device const float & u) { return half(u); } + static METAL_FUNC half convert(threadgroup const float & u) { return half(u); } + static METAL_FUNC half convert(thread const float & u) { return half(u); } +}; +template<> struct convertor { + // tail call fast <2 x float> @air.convert.f.v2f32.f.v2f16(<2 x half> %_) + static METAL_FUNC float2 convert(device const half2 & u) { return float2(u); } + static METAL_FUNC float2 convert(threadgroup const half2 & u) { return float2(u); } + static METAL_FUNC float2 convert(thread const half2 & u) { return float2(u); } +}; +template<> struct convertor { + // tail call fast <2 x half> @air.convert.f.v2f16.f.v2f32(<2 x float> %_) + static METAL_FUNC half2 convert(device const float2 & u) { return half2(u); } + static METAL_FUNC half2 convert(threadgroup const float2 & u) { return half2(u); } + static METAL_FUNC half2 convert(thread const float2 & u) { return half2(u); } +}; +template<> struct convertor { + static METAL_FUNC bf16 convert(device const half & u) { return bf16(u); } + static METAL_FUNC bf16 convert(threadgroup const half & u) { return bf16(u); } + static METAL_FUNC bf16 convert(thread const half & u) { return bf16(u); } +}; +template<> struct convertor { + static METAL_FUNC half convert(device const bf16 & u) { return half(u); } + static METAL_FUNC half convert(threadgroup const bf16 & u) { return half(u); } + static METAL_FUNC half convert(thread const bf16 & u) { return half(u); } +}; +template<> struct convertor { + // tail call fast <2 x bfloat> @air.convert.f.v2bf16.f.v2f16(<2 x half> %_) + static METAL_FUNC bf16_2 convert(device const half2 & u) { return bf16_2(u); } + static METAL_FUNC bf16_2 convert(threadgroup const half2 & u) { return bf16_2(u); } + static METAL_FUNC bf16_2 convert(thread const half2 & u) { return bf16_2(u); } +}; +template<> struct convertor { + // tail call fast <2 x half> @air.convert.f.v2f16.f.v2bf16(<2 x bfloat> %_) + static METAL_FUNC half2 convert(device const bf16_2 & u) { return half2(u); } + static METAL_FUNC half2 convert(threadgroup const bf16_2 & u) { return half2(u); } + static METAL_FUNC half2 convert(thread const bf16_2 & u) { return half2(u); } +}; + + + +} // base_types + +} // mittens diff --git a/extra/thunder/metal/include/common/common.metal b/extra/thunder/metal/include/common/common.metal new file mode 100644 index 0000000000..69aed7f092 --- /dev/null +++ b/extra/thunder/metal/include/common/common.metal @@ -0,0 +1,10 @@ +/** + * @file + * @brief A collection of common resources on which Thundermittens depends. + */ + + +#pragma once +#include "base_types.metal" +#include "base_ops.metal" +#include "utils.metal" diff --git a/extra/thunder/metal/include/common/utils.metal b/extra/thunder/metal/include/common/utils.metal new file mode 100644 index 0000000000..264b97af5c --- /dev/null +++ b/extra/thunder/metal/include/common/utils.metal @@ -0,0 +1,225 @@ +/** + * @file + * @brief General utilities for Thundermittens. + */ +#pragma once // not done +/* + TODO: + shared allocator + max shared mem for other hardware + */ + +#include +#include "base_types.metal" +/** + * @namespace mittens + * + * @brief The main namespace of Thundermittens. + */ +namespace mittens { +/** + * @namespace ore + * + * @brief The main namespace of Thundermittens Metal. + */ + +/* ---------- GENERAL CONSTANTS FOR mittens ---------- */ + +/** + * @brief Tile dimension constant. + */ +constant constexpr const int TILE_DIM{8}; +constant constexpr const int TILE_ELEMENTS{TILE_DIM*TILE_DIM}; +constant constexpr const int SIMD_THREADS{32}; + + +#ifdef M2_PRO +constant constexpr int MAX_SHARED_MEMORY = 32768; +#else +constant constexpr int MAX_SHARED_MEMORY = 32768; +#endif +/* ---------- TYPE HELPERS ---------- */ +/** + * @namespace ducks + * + * @brief Thundermittens' namespace for template metaprogramming.. + * + * This includes primarily dummy types and concept wrappers, along + * with a few additional utilities. + */ +namespace ducks { + +/** + * @brief A type representing an empty default for a template. + */ +struct default_type {}; + +// This macro can't be done as a template, so it doesn't really have a location in mittens. +#define typeof(A) typename std::remove_const::type>::type + + +} + +/* ---------- SHUFFLE UTILS ---------- */ +/** + * @brief Mask constant for all active threads in a warp. + */ +constant static constexpr uint32_t MASK_ALL = 0xFFFFFFFF; + +template +static METAL_FUNC T shfl_sync(thread const T &f, const ushort laneid) { + return metal::simd_shuffle(f, laneid); +} + +template<> +METAL_FUNC bfloat shfl_sync(thread const bf16 &f, const ushort laneid) { +// return as_type(metal::simd_shuffle(*(thread half*)(&f), laneid)); + float f_val = (float)f; + float shfl_val = metal::simd_shuffle(f_val, laneid); + return (bf16)shfl_val; +} + +template<> +METAL_FUNC bfloat2 shfl_sync(thread const bf16_2 &f, const ushort laneid) { +// return as_type(metal::simd_shuffle(*(thread half2*)(&f), laneid)); + float2 f_val = (float2)f; + float2 shfl_val = metal::simd_shuffle(f_val, laneid); + return (bf16_2)shfl_val; +} + +template +static METAL_FUNC T shfl_down_fill_sync(thread const T &f, thread const T& fill_data, const ushort laneid) { + return metal::simd_shuffle_and_fill_down(f, laneid, fill_data); +} + +template<> +METAL_FUNC bfloat shfl_down_fill_sync(thread const bfloat &f, thread const bfloat &fill_data, const ushort laneid) { +// return as_type(metal::simd_shuffle_and_fill_down(*(thread half*)(&f), *(thread half*)(&fill_data), laneid)); + float f_val = (float)f; + float fill_data_f = (float)fill_data; + float shfl_val = metal::simd_shuffle_and_fill_down(f_val, fill_data_f, laneid); + return (bf16)shfl_val; +} +template<> +METAL_FUNC bfloat2 shfl_down_fill_sync(thread const bfloat2 &f, thread const bfloat2 &fill_data, const ushort laneid) { +// return as_type(metal::simd_shuffle_and_fill_down(*(thread half2*)(&f), *(thread half2*)(&fill_data), laneid)); + float2 f_val = (float2)f; + float2 fill_data_f = (float2)fill_data; + float2 shfl_val = metal::simd_shuffle_and_fill_down(f_val, fill_data_f, laneid); + return (bf16_2)shfl_val; +} +/** + * @brief Perform a shuffle down operation on a packed type synchronously across a warp. + * @tparam T The type of the value to be shuffled. + * @param mask[in] The mask of active threads. + * @param f[in] The value to be shuffled. + * @param delta[in] The number of positions to shuffle down. + * @return The result of the shuffle operation. + */ +template +static METAL_FUNC T shfl_down_sync(thread const T &f, int delta) { + return metal::simd_shuffle_rotate_down(f, delta); +} + +template<> +METAL_FUNC bfloat shfl_down_sync(thread const bf16 &f, int delta) { +// return base_types::convertor::convert(metal::simd_shuffle_rotate_down(base_types::convertor::convert(f), delta)); +// return as_type(metal::simd_shuffle_rotate_down(*(thread half*)(&f), delta)); + float f_val = (float)f; + float shfl_val = metal::simd_shuffle_rotate_down(f_val, delta); + return (bf16)shfl_val; +} + +template<> +METAL_FUNC bfloat2 shfl_down_sync(thread const bf16_2 &f, int delta) { +// return as_type(metal::simd_shuffle_rotate_down(*(thread const half2*)(&f), delta)); +// return base_types::convertor::convert(metal::simd_shuffle_rotate_down(base_types::convertor::convert(f), delta)); + + float2 f_val = (float2)f; + float2 shfl_val = metal::simd_shuffle_rotate_down(f_val, delta); + return (bf16_2)shfl_val; +// return as_type(metal::simd_shuffle_rotate_down(*(thread half2*)(&f), delta)); +} + + +/* ---------- LOOP UNROLLING UTILS ---------- */ + +namespace meta { +template +struct unroll_i_in_range { + template + static METAL_FUNC void run(F f, Args... args) { + f(Start, args...); + unroll_i_in_range::run(f, args...); + } +}; + +template +struct unroll_i_in_range { + template + static METAL_FUNC void run(F, Args...) { + } +}; + + +template +struct unroll_i_j_in_range_inner { + template + static METAL_FUNC void run(F f, int outerIndex, Args... args) { + f(outerIndex, Start, args...); + unroll_i_j_in_range_inner::run(f, outerIndex, args...); + } +}; + +template +struct unroll_i_j_in_range_inner { + template + static METAL_FUNC void run(F, int, Args...) { + } +}; + +template +struct unroll_i_j_in_range { + template + static METAL_FUNC void run(F f, Args... args) { + unroll_i_j_in_range_inner::run( + f, StartOuter, args... + ); + unroll_i_j_in_range< + StartOuter + StrideOuter, EndOuter, StrideOuter, + StartInner, EndInner, StrideInner + >::run(f, args...); + } +}; + +template +struct unroll_i_j_in_range { + template + static METAL_FUNC void run(F, Args...) { + } +}; + +} + + +template +struct ReadVector { + float _[N]; +}; + +/* ---------- SHARED MEMORY UTILS ---------- */ + +#define mittens_ALIGN_AS(n) alignas(n) +#define mittens_DEFAULT_ALIGN mittens_ALIGN_AS(16) + +/** + * @brief Dummy structure for alignment purposes. Needed for WGMMA and TMA calls. + */ +struct mittens_DEFAULT_ALIGN alignment_dummy { int dummy; }; +} + + diff --git a/extra/thunder/metal/include/ops/group/group.metal b/extra/thunder/metal/include/ops/group/group.metal new file mode 100644 index 0000000000..49dd1571dd --- /dev/null +++ b/extra/thunder/metal/include/ops/group/group.metal @@ -0,0 +1,24 @@ +/** + * @file + * @brief An aggregate header of all group (multi-warp) operations defined by Thundermittens + */ + +#pragma once +#include "../../common/common.metal" +#include "../../types/types.metal" +#include "../warp/warp.metal" // several group memory ops rely on underlying warp-scope ops +namespace mittens { +template +struct group { + constant static constexpr int GROUP_WARPS = N_WARPS; // This alias produces nice parallelism. + constant static constexpr int GROUP_THREADS = N_WARPS * mittens::SIMD_THREADS; // This alias produces nice parallelism. + static METAL_FUNC int simd_laneid(const unsigned threadIdx) { return threadIdx % mittens::SIMD_THREADS; } + static METAL_FUNC int laneid (const unsigned threadIdx) { return threadIdx % GROUP_THREADS; } + static METAL_FUNC int warpid (const unsigned threadIdx) { return laneid(threadIdx) / mittens::SIMD_THREADS; } + static METAL_FUNC int groupid (const unsigned threadIdx) { return threadIdx / GROUP_THREADS; } + #include "memory/memory.metal" + #include "shared/shared.metal" +}; + + +} diff --git a/extra/thunder/metal/include/ops/group/memory/memory.metal b/extra/thunder/metal/include/ops/group/memory/memory.metal new file mode 100644 index 0000000000..32eb19fe5e --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/memory.metal @@ -0,0 +1,2 @@ +#include "tile/tile.metal" +#include "vec/vec.metal" diff --git a/extra/thunder/metal/include/ops/group/memory/tile/global_to_register.metal b/extra/thunder/metal/include/ops/group/memory/tile/global_to_register.metal new file mode 100644 index 0000000000..cfc7605cd8 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/tile/global_to_register.metal @@ -0,0 +1,132 @@ + +/** + * @file + * @brief Functions for a group to collaboratively transfer data directly between global memory and registers and back. + */ + +/** + * @brief Collaboratively loads data from a source array into row-major layout tiles. + * + * @tparam RT The row-major layout tile type. + * @tparam U The data type of the source array. + * @param dst[out] The destination tile to load data into. + * @param src[in] The source array to load data from. + * @param row_stride[in] The stride in elements between rows in the source array. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(thread RT &dst, thread const GL &_src, thread const coord &idx, const int threadIdx) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + const device U *src = (device U*)&_src.template get(idx); + const int row_stride = _src.row_stride(); + + int warp_laneid = threadIdx % 32; + const int row_offset = dst.rows * warpid(threadIdx); + const short qid = warp_laneid / 4; + const short simd_y = row_offset + (qid & 4) + (warp_laneid / 2) % 4; + const short simd_x = (qid & 2) * 2 + (warp_laneid % 2) * 2; + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + int row = simd_y + i * RT::tile_size; + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + int col = simd_x + j * RT::tile_size; + T2 src2 = base_types::convertor::convert(*((device U2*)(&src[row * row_stride + col]))); + dst.tiles[i][j].data.thread_elements()[0] = src2[0]; + dst.tiles[i][j].data.thread_elements()[1] = src2[1]; + } + } +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(thread RT &dst, thread const GL &_src, thread const coord &idx, const int threadIdx) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + const device U *src = (device U*)&_src.template get(idx); + const int row_stride = _src.row_stride(); + + int warp_laneid = threadIdx % 32; + const int row_offset = dst.rows * warpid(threadIdx); + const short qid = warp_laneid / 4; + const short simd_y = row_offset + (qid & 2) * 2 + (warp_laneid % 2) * 2;; + const short simd_x = (qid & 4) + (warp_laneid / 2) % 4; + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + int row = simd_y + i * RT::tile_size; + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + int col = simd_x + j * RT::tile_size; + T2 src2 = base_types::convertor::convert(*((device U2*)(&src[row * row_stride + col]))); + dst.tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert(src[row * row_stride + col]); + dst.tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert(src[(row + 1) * row_stride + col]); + } + } +} +/** + * @brief Collaboratively stores data from register tiles to a destination array in global memory with a row-major layout. + * + * @tparam RT The register tile type with a row-major layout. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register tile to store data from. + * @param row_stride[in] The stride in elements between rows in the destination array. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +store(thread GL &_dst, thread const RT &src, thread const coord &idx, const int threadIdx) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + device U *dst = (device U*)&(_dst.template get(idx)); + const int row_stride = _dst.row_stride(); + int warp_laneid = simd_laneid(threadIdx); + const int row_offset = src.rows * warpid(threadIdx); + const short qid = warp_laneid / 4; + const short simd_y = row_offset + (qid & 4) + (warp_laneid / 2) % 4; + const short simd_x = (qid & 2) * 2 + (warp_laneid % 2) * 2; + #pragma clang loop unroll(full) + for(int i = 0; i < src.height; i++) { + int row = simd_y + i * RT::tile_size; + #pragma clang loop unroll(full) + for(int j = 0; j < src.width; j++) { + int col = simd_x + j * RT::tile_size; + U2 src2 = base_types::convertor::convert(T2(src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1])); + *(device U2*)(&dst[row*row_stride + col]) = src2; + } + } +} + +template +static METAL_FUNC typename metal::enable_if(), void>::type +store(thread GL &_dst, thread const RT &src, thread const coord &idx, const int threadIdx) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + device U *dst = (device U*)&(_dst.template get(idx)); + const int row_stride = _dst.row_stride(); + int warp_laneid = simd_laneid(threadIdx); + const int row_offset = src.rows * warpid(threadIdx); + const short qid = warp_laneid / 4; +// const short simd_y = row_offset + (qid & 4) + (warp_laneid / 2) % 4; +// const short simd_x = (qid & 2) * 2 + (warp_laneid % 2) * 2; + const short simd_y = row_offset + (qid & 2) * 2 + (warp_laneid % 2) * 2; + const short simd_x = (qid & 4) + (warp_laneid / 2) % 4; + #pragma clang loop unroll(full) + for(int i = 0; i < src.height; i++) { + int row = simd_y + i * RT::tile_size; + #pragma clang loop unroll(full) + for(int j = 0; j < src.width; j++) { + int col = simd_x + j * RT::tile_size; + dst[row*row_stride + col] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[0]); + dst[(row + 1) * row_stride + col] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[1]); + } + } +} diff --git a/extra/thunder/metal/include/ops/group/memory/tile/global_to_shared.metal b/extra/thunder/metal/include/ops/group/memory/tile/global_to_shared.metal new file mode 100644 index 0000000000..bf343bd048 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/tile/global_to_shared.metal @@ -0,0 +1,144 @@ +/** + * @file + * @brief Group (collaborative warp) ops for loading shared tiles from and storing to global memory. + */ + + +//template +//static METAL_FUNC typename metal::enable_if(), void>::type +//load(int i, +// threadgroup ST *dst, device U* src, +// thread const int& group_laneid, +// thread const int& memcpy_per_row, +// thread const int& elem_per_memcpy, +// thread const int& row_stride) +//{ +// int idx = i * GROUP_THREADS + group_laneid; +// int row = idx / memcpy_per_row; +// int col = (idx*elem_per_memcpy) % ST::cols; +// if (row < ST::rows) { +// *(threadgroup float4*)(&(*dst)[{row, col}]) = *(device float4*)(&src[row*row_stride + col]); +// } +//} + + +template +static METAL_FUNC typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(threadgroup ST &dst, thread const GL &_src, thread const coord &idx, const int threadIdx) { + int group_laneid = threadIdx % GROUP_THREADS; + using T = typename ST::T; + using U = typename GL::dtype; + device U *src = (device U*)&_src.template get(idx); + const int row_stride = _src.row_stride(); + using read_vector = ReadVector<1>; + // we can handle this many rows each time we run a memcpy_async + constexpr const int elem_per_memcpy = sizeof(read_vector)/sizeof(typename ST::dtype); + constexpr const int memcpy_per_row = ST::cols / elem_per_memcpy; + int total_calls = ((ST::height * ST::width + (N_WARPS-1))) * TILE_DIM*TILE_DIM / (N_WARPS*SIMD_THREADS*elem_per_memcpy); // round up + #pragma clang loop unroll(full) + for(int i = 0; i < total_calls; i++) { + + int idx = i * GROUP_THREADS + group_laneid; + int row = idx / memcpy_per_row; + int col = (idx*elem_per_memcpy) % dst.cols; + if (row::convert(1.f); +// dst[{0, 0}] = total_calls; +// meta::unroll_i_in_range<0, total_calls, 1>::run(load, &dst, src, group_laneid, memcpy_per_row, elem_per_memcpy, row_stride); +} + + +//template +//static METAL_FUNC typename metal::enable_if() && ducks::is_global_layout(), void>::type +//load(threadgroup ST &dst, thread const GL &_src, thread const coord &idx, const int threadIdx) { +// int group_laneid = threadIdx % GROUP_THREADS; +// int groupid = threadIdx / GROUP_THREADS; +// int laneid = threadIdx % SIMD_THREADS; +// +// using U = typename GL::dtype; +// device U *src = (device U*)&_src.template get(idx); +// const int row_stride = _src.row_stride(); +// +// int elem_per_memcpy = sizeof(float)/sizeof(typename ST::dtype); +// int memcpy_per_row = ST::cols / elem_per_memcpy; +// int total_calls = ((ST::height * ST::width + (N_WARPS-1))) * TILE_DIM*TILE_DIM / (N_WARPS*SIMD_THREADS*elem_per_memcpy); // round up +// /* +// 1x16 or 8 x 128 +// */ +// int offset = ST::num_elements / (GROUP_WARPS); +//// int offset = group_laneid +// #pragma clang loop unroll(full) +// for(int i = 0; i < total_calls; i++) { +// int idx = i * SIMD_THREADS + laneid; +//// int idx = i * () + group_laneid; +// int row = idx / memcpy_per_row; +// int col = (idx*elem_per_memcpy) % dst.cols; +// if (row +//static METAL_FUNC typename metal::enable_if() && ducks::is_global_layout(), void>::type +//load(threadgroup ST &dst, thread const GL &_src, thread const coord &idx, const int threadIdx) { +// int warp_id = threadIdx / SIMD_THREADS; +// int lane_id = threadIdx % SIMD_THREADS; +//// int N_WARPS = /* number of warps in your group */; +// +// using U = typename GL::dtype; +// device U *src = (device U*)&_src.template get(idx); +// const int row_stride = _src.row_stride(); +// +// int elem_per_memcpy = sizeof(float)/sizeof(typename ST::dtype); +// int memcpy_per_row = ST::cols / elem_per_memcpy; +// int total_memcpy_elems = (ST::height * ST::cols) / elem_per_memcpy; +// int elems_per_warp = (total_memcpy_elems + N_WARPS - 1) / N_WARPS; // Ceiling division +// +// int start_idx = warp_id * elems_per_warp; +// int end_idx = metal::min(start_idx + elems_per_warp, total_memcpy_elems); +// +// #pragma clang loop unroll(full) +// for (int idx = start_idx + lane_id; idx < end_idx; idx += SIMD_THREADS) { +// int row = idx / memcpy_per_row; +// int col = (idx % memcpy_per_row) * elem_per_memcpy; +// if (row < ST::height) { +// *(threadgroup float*)(&dst[{row, col}]) = *(device float*)(&src[row * row_stride + col]); +// } +// } +//} + +template +static METAL_FUNC typename metal::enable_if() && ducks::is_global_layout(), void>::type +store(thread const GL &_dst, threadgroup const ST &src, thread const coord &idx, const int threadIdx) { + int group_laneid = threadIdx % GROUP_THREADS; + using U = typename GL::dtype; + device U *dst = (device U*)&_dst.template get(idx); + const int row_stride = _dst.row_stride(); + using read_vector = ReadVector<1>; + // we can handle this many rows each time we run a memcpy_async + int elem_per_memcpy = sizeof(read_vector)/sizeof(typename ST::dtype); // float/float -> 1 + int memcpy_per_row = ST::cols / elem_per_memcpy; // 240 memcpy per row + int total_calls = ((src.height * src.width + (N_WARPS-1))) * TILE_DIM*TILE_DIM / (N_WARPS*SIMD_THREADS*elem_per_memcpy); // round up + + #pragma clang loop unroll(full) + for(int i = 0; i < total_calls; i++) { + + int idx = i * GROUP_THREADS + group_laneid; + + int row = idx / memcpy_per_row; + int col = (idx*elem_per_memcpy) % src.cols; + if (row::convert(1); +} + diff --git a/extra/thunder/metal/include/ops/group/memory/tile/shared_to_register.metal b/extra/thunder/metal/include/ops/group/memory/tile/shared_to_register.metal new file mode 100644 index 0000000000..b7a6b4b199 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/tile/shared_to_register.metal @@ -0,0 +1,152 @@ +/** + * @file + * @brief Functions for a warpgroup to collaboratively transfer data directly between shared memory and registers and back. + */ + +/** + * @brief Collaboratively load data from a shared tile into register tiles split across a warpgroup. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +load(thread RT &dst, threadgroup const ST &src, const int threadIdx) { + constexpr int height = ST::height; + constexpr int warp_height = RT::height; + static_assert(height%N_WARPS == 0, "Group load / store requires tile height to be a multiple of N_WARPS."); + static_assert(height%warp_height == 0, "Group load / store requires tile height to be a multiple of the RT height."); + static_assert(warp_height * N_WARPS == height, "RT height * N_WARPS must = ST height"); + static_assert(ST::width==RT::width, "Group load / store requires tile widths to match."); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + + int warp_laneid = simd_laneid(threadIdx); + const int row_offset = RT::rows * warpid(threadIdx); + const short qid = warp_laneid / 4; + const short simd_y = row_offset + (qid & 4) + (warp_laneid / 2) % 4; + const short simd_x = (qid & 2) * 2 + (warp_laneid % 2) * 2; + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + int row = simd_y + i * mittens::TILE_DIM; + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + int col = simd_x + j * mittens::TILE_DIM; + T2 src2 = base_types::convertor::convert(*((threadgroup U2*)(&src[{row, col}]))); + dst.tiles[i][j].data.thread_elements()[0] = src2[0]; + dst.tiles[i][j].data.thread_elements()[1] = src2[1]; + } + } +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +load(thread RT &dst, threadgroup const ST &src, const int threadIdx) { + constexpr int height = ST::height; + constexpr int warp_height = RT::height; + static_assert(height%N_WARPS == 0, "Group load / store requires tile height to be a multiple of N_WARPS."); + static_assert(height%warp_height == 0, "Group load / store requires tile height to be a multiple of the RT height."); + static_assert(warp_height * N_WARPS == height, "RT height * N_WARPS must = ST height"); + static_assert(ST::width==RT::width, "Group load / store requires tile widths to match."); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + + int warp_laneid = simd_laneid(threadIdx); + const int row_offset = RT::rows * warpid(threadIdx); + const short qid = warp_laneid / 4; + const short simd_y = row_offset + (qid & 2) * 2 + (warp_laneid % 2) * 2; + const short simd_x = (qid & 4) + (warp_laneid / 2) % 4; + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + int row = simd_y + i * mittens::TILE_DIM; + int col = simd_x + j * mittens::TILE_DIM; + dst.tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert(src[{row + 0, col}]); + dst.tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert(src[{row + 1, col}]); + } + } +} + +/** + * @brief Collaboratively store data into a shared tile from register tiles split across a warpgroup. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +store(threadgroup ST &dst, thread const RT &src, const int threadIdx) { + constexpr int height = ST::height; + constexpr int warp_height = RT::height; + static_assert(height%N_WARPS == 0, "Group load / store requires tile height to be a multiple of N_WARPS."); + static_assert(height%warp_height == 0, "Group load / store requires tile height to be a multiple of the RT height."); + static_assert(warp_height * N_WARPS == height, "RT height * N_WARPS must = ST height"); + static_assert(ST::width==RT::width, "Group load / store requires tile widths to match."); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int warp_laneid = simd_laneid(threadIdx); + const int row_offset = RT::rows * warpid(threadIdx); + const short qid = warp_laneid / 4; + const short simd_y = row_offset + (qid & 4) + (warp_laneid / 2) % 4; + const short simd_x = (qid & 2) * 2 + (warp_laneid % 2) * 2; + #pragma clang loop unroll(full) + for(int i = 0; i < RT::height; i++) { + int row = simd_y + i * mittens::TILE_DIM; + #pragma clang loop unroll(full) + for(int j = 0; j < RT::width; j++) { + int col = simd_x + j * mittens::TILE_DIM; + U2 src2 = base_types::convertor::convert(T2(src.tiles[i][j].data.thread_elements()[0], + src.tiles[i][j].data.thread_elements()[1])); + *(threadgroup U2*)(&dst[{row, col}]) = src2; + } + } +} + + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +store(threadgroup ST &dst, thread const RT &src, const int threadIdx) { + constexpr int height = ST::height; + constexpr int warp_height = RT::height; + static_assert(height%N_WARPS == 0, "Group load / store requires tile height to be a multiple of N_WARPS."); + static_assert(height%warp_height == 0, "Group load / store requires tile height to be a multiple of the RT height."); + static_assert(warp_height * N_WARPS == height, "RT height * N_WARPS must = ST height"); + static_assert(ST::width==RT::width, "Group load / store requires tile widths to match."); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int warp_laneid = simd_laneid(threadIdx); + const int row_offset = RT::rows * warpid(threadIdx); + const short qid = warp_laneid / 4; +// const short simd_y = row_offset + (qid & 4) + (warp_laneid / 2) % 4; +// const short simd_x = (qid & 2) * 2 + (warp_laneid % 2) * 2; + const short simd_y = row_offset + (qid & 2) * 2 + (warp_laneid % 2) * 2; + const short simd_x = (qid & 4) + (warp_laneid / 2) % 4; + #pragma clang loop unroll(full) + for(int i = 0; i < RT::height; i++) { + + #pragma clang loop unroll(full) + for(int j = 0; j < RT::width; j++) { + int row = simd_y + i * mittens::TILE_DIM; + int col = simd_x + j * mittens::TILE_DIM; +// U2 src2 = base_types::convertor::convert(T2(src.tiles[i][j].data.thread_elements()[0], +// src.tiles[i][j].data.thread_elements()[1])); +// *(threadgroup U2*)(&dst[{row, col}]) = src2; + + dst[{row + 0, col}] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[0]); + dst[{row + 1, col}] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[1]); + } + } +} diff --git a/extra/thunder/metal/include/ops/group/memory/tile/tile.metal b/extra/thunder/metal/include/ops/group/memory/tile/tile.metal new file mode 100644 index 0000000000..2c1312b22b --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/tile/tile.metal @@ -0,0 +1,8 @@ +/** + * @file + * @brief An aggregate header of group memory operations on tiles. + */ + +#include "shared_to_register.metal" +#include "global_to_register.metal" +#include "global_to_shared.metal" diff --git a/extra/thunder/metal/include/ops/group/memory/vec/global_to_register.metal b/extra/thunder/metal/include/ops/group/memory/vec/global_to_register.metal new file mode 100644 index 0000000000..6839b164d8 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/vec/global_to_register.metal @@ -0,0 +1,47 @@ + +/** + * @file + * @brief Functions for a warpgroup to collaboratively transfer data directly between global memory and registers and back. + */ + +/** + * @brief Collaboratively loads data into register vectors from a source array in global memory. + * + * @tparam RV The register vector type. + * @tparam U The data type of the source array. + * @param[out] dst The destination register vector to load data into. + * @param[in] src The source array in global memory to load data from. + */ +template +METAL_FUNC static typename metal::enable_if(), void>::type +load(thread RV &dst, thread const GL &_src, thread coord idx, const int threadIdx) { + using T = typename RV::dtype; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + using T2 = typename base_types::packing::packed_type; + + idx.c += warpid(threadIdx); + // Call warp level store + ::mittens::load(dst, _src, idx, simd_laneid(threadIdx)); +} + +/** + * @brief Collaboratively stores data from register vectors to a destination array in global memory. + * + * @tparam RV The register vector type. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register vector to store data from. + */ +template +METAL_FUNC static typename metal::enable_if(), void>::type +store(thread GL &_dst, thread const RV &src, thread coord idx, const int threadIdx) { + using T = typename RV::dtype; +// using U2 = typename base_types::packing::packed_type; + using T2 = typename base_types::packing::packed_type; + + idx.c += warpid(threadIdx); + + // Call warp level store + ::mittens::store(_dst, src, idx, simd_laneid(threadIdx)); +} diff --git a/extra/thunder/metal/include/ops/group/memory/vec/global_to_shared.metal b/extra/thunder/metal/include/ops/group/memory/vec/global_to_shared.metal new file mode 100644 index 0000000000..a988da68fc --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/vec/global_to_shared.metal @@ -0,0 +1,59 @@ +/** + * @file + * @brief Group (collaborative warp) ops for loading shared vectors from and storing to global memory. + */ + +/** + * @brief Loads data from global memory into shared memory vector. + * + * This function loads data from a global memory location pointed to by `src` into a shared memory vector `dst`. + * It calculates the number of elements that can be transferred in one operation based on the size ratio of `float4` to the data type of `SV`. + * The function ensures coalesced memory access and efficient use of bandwidth by dividing the work among threads in a warp. + * + * @tparam SV Shared vector type, must satisfy ducks::sv::all concept. + * @param dst Reference to the shared vector where the data will be loaded. + * @param src Pointer to the global memory location from where the data will be loaded. + */ +template +METAL_FUNC static typename metal::enable_if(), void>::type +load(threadgroup SV &dst, thread const GL &_src, thread const coord &idx, const int threadIdx) { + using U = typename GL::dtype; + using read_vector = ReadVector<1>; + constexpr int elem_per_transfer = sizeof(read_vector) / sizeof(typename SV::dtype); + constexpr int total_calls = SV::length / elem_per_transfer; // guaranteed to divide + device U *src = (device U*)&_src.template get(idx); + + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < total_calls; i+=GROUP_THREADS) { + if(i * elem_per_transfer < dst.length) + *(threadgroup read_vector*)&dst[i*elem_per_transfer] = *(device read_vector*)&src[i*elem_per_transfer]; + } +} + +/** + * @brief Stores data from a shared memory vector to global memory. + * + * This function stores data from a shared memory vector `src` to a global memory location pointed to by `dst`. + * Similar to the load function, it calculates the number of elements that can be transferred in one operation based on the size ratio of `float4` to the data type of `SV`. + * The function ensures coalesced memory access and efficient use of bandwidth by dividing the work among threads in a warp. + * + * @tparam SV Shared vector type, must satisfy ducks::sv::all concept. + * @param dst Pointer to the global memory location where the data will be stored. + * @param src Reference to the shared vector from where the data will be stored. + */ +template +METAL_FUNC static typename metal::enable_if(), void>::type +store(thread const GL &_dst, threadgroup const SV &src, thread const coord &idx, const int threadIdx) { + using read_vector = ReadVector<1>; + using U = typename GL::dtype; + constexpr int elem_per_transfer = sizeof(read_vector) / sizeof(typename SV::dtype); + constexpr int total_calls = SV::length / elem_per_transfer; // guaranteed to divide + device U *dst = (device U*)&_dst.template get(idx); + + metal::simdgroup_barrier(metal::mem_flags::mem_none); + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < total_calls; i+= GROUP_THREADS) { + if(i * elem_per_transfer < src.length) + *(device read_vector*)&dst[i*elem_per_transfer] = *(threadgroup read_vector*)&src[i*elem_per_transfer]; // lmao it's identical + } +} diff --git a/extra/thunder/metal/include/ops/group/memory/vec/shared_to_register.metal b/extra/thunder/metal/include/ops/group/memory/vec/shared_to_register.metal new file mode 100644 index 0000000000..856dd0148a --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/vec/shared_to_register.metal @@ -0,0 +1,60 @@ +/** + * @file + * @brief Functions for a group to collaboratively transfer data directly between shared memory and registers and back. + */ + +/** + * @brief Collaboratively load data from a shared vector into register vectors split across a warpgroup. + * + * @tparam RV The register vector type + * @tparam SV The shared vector type + * @param dst[out] The destination register vector. + * @param src[in] The source shared vector. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_vector(), void>::type +load(thread RV &dst, threadgroup const SV &_src, const int threadIdx) { + using T = typename RV::dtype; + using U = typename SV::dtype; + using U2 = typename base_types::packing::packed_type; + using T2 = typename base_types::packing::packed_type; + + static_assert(SV::length == RV::length*N_WARPS, "rv and sv dimensions do not match");// confirm size correct +// threadgroup typename SV::template subvec &src = subvec_inplace(_src, warpid(threadIdx)); + // threadgroup subvec &src = subvec_inplace(_src, warpid(threadIdx)); + unsigned warpId = warpid(threadIdx); + using subvec = typename SV::template subvec; + + threadgroup subvec& src = *(threadgroup subvec*)(&_src[warpId *RV::length]); + + ::mittens::load(dst, src, simd_laneid(threadIdx)); // warp-level +} + +/** + * @brief Collaboratively store data into a shared vector from register vectors split across a warpgroup. + * + * @tparam RV The register vector type + * @tparam SV The shared vector type + * @param dst[out] The destination shared vector. + * @param src[in] The source register vector. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_vector(), void>::type +store(threadgroup SV &_dst, thread const RV &src, const int threadIdx) { + using T = typename RV::dtype; + using U = typename SV::dtype; + using T2 = typename base_types::packing::packed_type; + using U2 = typename base_types::packing::packed_type; + + + static_assert(SV::length == RV::length*N_WARPS, "rv and sv dimensions do not match");// confirm size correct + +// threadgroup typename SV::template subvec &dst = subvec_inplace(_dst, warpid(threadIdx)); +// ::mittens::store, RV>(dst, src, simd_laneid(threadIdx)); // warp-level + + unsigned warpId = warpid(threadIdx); + using subvec = typename SV::template subvec; + threadgroup subvec& dst = *(threadgroup subvec*)(&_dst[warpId * RV::length]); + + ::mittens::store(dst, src, simd_laneid(threadIdx)); // warp-level +} diff --git a/extra/thunder/metal/include/ops/group/memory/vec/vec.metal b/extra/thunder/metal/include/ops/group/memory/vec/vec.metal new file mode 100644 index 0000000000..480b087ee6 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/memory/vec/vec.metal @@ -0,0 +1,8 @@ +/** + * @file + * @brief An aggregate header of group memory operations on vectors. + */ + +#include "shared_to_register.metal" +#include "global_to_register.metal" +#include "global_to_shared.metal" diff --git a/extra/thunder/metal/include/ops/group/shared/shared.metal b/extra/thunder/metal/include/ops/group/shared/shared.metal new file mode 100644 index 0000000000..3666325b1d --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/shared.metal @@ -0,0 +1,3 @@ + +#include "tile/tile.metal" +#include "vec/vec.metal" diff --git a/extra/thunder/metal/include/ops/group/shared/tile/conversions.metal b/extra/thunder/metal/include/ops/group/shared/tile/conversions.metal new file mode 100644 index 0000000000..af8e6a0867 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/tile/conversions.metal @@ -0,0 +1,27 @@ +/** + * @file + * @brief Group conversions between different shared memory tile types. + */ + +/* ---------- COPIES ---------- */ + +/** + * @brief Copies data from one shared memory tile to another, potentially with different data types and layouts. + * + * @tparam T The data type of the destination tile. + * @tparam U The data type of the source tile. + * @tparam _height The height of the tile. + * @tparam _width The width of the tile. + * @tparam L1 The layout of the destination tile. + * @tparam L2 The layout of the source tile. + * @param[out] dst The destination tile. + * @param[in] src The source tile. + */ +template +static METAL_FUNC void copy(threadgroup st &dst, threadgroup const st &src, const int threadIdx) { + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.num_elements; i+=GROUP_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = base_types::convertor::convert(src[{row, col}]); + } +} diff --git a/extra/thunder/metal/include/ops/group/shared/tile/maps.metal b/extra/thunder/metal/include/ops/group/shared/tile/maps.metal new file mode 100644 index 0000000000..6941e1ccdf --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/tile/maps.metal @@ -0,0 +1,475 @@ +/** + * @file + * @brief Group maps on shared tiles. + */ + +/** + * @brief Performs a uniform unary operation on a tile. + * + * This function applies a given unary operation to each element of the source tile and stores the result in the destination tile. + * The operation is applied independently to each element, without considering its position or the values of neighboring elements. + * + * @tparam op The unary operation to be applied. Must be specialized to support operation on the data type of T. + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the unary operation is applied. + */ +template // T2, w, h can be inferred from dst as long as op is specialized +static METAL_FUNC typename metal::enable_if(), void>::type + unary_map(threadgroup ST &dst, threadgroup const ST &src, const int threadIdx) { + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.num_elements; i += GROUP_THREADS) { + dst.data[i] = op::template op(src.data[i]); + } +} + +/** + * @brief Performs a uniform binary operation on a tile with a scalar parameter. + * + * This function applies a given binary operation to each element of the source tile and a scalar parameter, then stores the result in the destination tile. + * The operation is applied independently to each element, treating the scalar parameter as the second operand for each operation. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T and the scalar parameter. + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the binary operation is applied. + * @param[in] param The scalar parameter to be used as the second operand in the binary operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + bin_map(threadgroup ST &dst, threadgroup const ST &src, thread const typename ST::dtype ¶m, const int threadIdx) { + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.num_elements; i += GROUP_THREADS) { + dst.data[i] = op::template op(src.data[i], param); + } +} + +/** + * @brief Performs a uniform binary operation on two tiles. + * + * This function applies a given binary operation to corresponding elements of two source tiles and stores the result in the destination tile. + * The operation is applied independently to each pair of elements, without considering their positions or the values of neighboring elements. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T. + * @tparam T The type of the tiles. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile to which the binary operation is applied. + * @param[in] rhs The second source tile to which the binary operation is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + bin_map(threadgroup ST &dst, threadgroup const ST &lhs, threadgroup const ST &rhs, const int threadIdx) { + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.num_elements; i += GROUP_THREADS) { + dst.data[i] = op::template op(lhs.data[i], rhs.data[i]); + } +} + +/** + * @brief Performs a row-wise binary operation on a tile with a vector. + * + * This function applies a given binary operation to each row of the source tile and the corresponding element of the source vector, + * then stores the result in the destination tile. The operation is applied independently to each row, using the vector element as + * the second operand for each element in the row. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T and the vector elements. + * @tparam T The type of the tiles. Must satisfy the `ducks::st::all` concept. + * @tparam V The type of the vector. Must have the same data type as T. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the binary operation is applied. + * @param[in] vec The source vector containing the second operand for each row operation. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_map(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &vec, const int threadIdx) { + static_assert(metal::is_same::value, "Tile and vector must have the same data type"); + static_assert(SV::length == ST::rows, "Vector length must match the number of rows in the tile"); + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.num_elements; i += GROUP_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = op::template op(src[{row, col}], vec[row]); + } +} + +/** + * @brief Performs a column-wise binary operation on a tile with a vector. + * + * This function applies a given binary operation to each column of the source tile and the corresponding element of the source vector, + * then stores the result in the destination tile. The operation is applied independently to each column, using the vector element as + * the second operand for each element in the column. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T and the vector elements. + * @tparam T The type of the tiles. Must satisfy the `ducks::st::all` concept. + * @tparam V The type of the vector. Must have the same data type as T. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the binary operation is applied. + * @param[in] vec The source vector containing the second operand for each column operation. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_map(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &vec, const int threadIdx) { + static_assert(metal::is_same::value, "Tile and vector must have the same data type"); + static_assert(SV::length == ST::cols, "Vector length must match the number of columns in the tile"); + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.num_elements; i += GROUP_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = op::template op(src[{row, col}], vec[col]); + } +} + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// All of the annoying qualifiers *should* be automatically inferred during compile-time. +// So, syntax should just be mittens::add_row(tile, colvec); + +// const maps +/** + * @brief Sets all elements of the destination tile to zero. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + zero(threadgroup ST &dst, const int threadIdx) { + unary_map(dst, dst, threadIdx); +} +/** + * @brief Sets all elements of the destination tile to one. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + one(threadgroup ST &dst, const int threadIdx) { + unary_map(dst, dst, threadIdx); +} +/** + * @brief Sets all elements of the destination tile to positive infinity. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + pos_infty(threadgroup ST &dst, const int threadIdx) { + unary_map(dst, dst, threadIdx); +} +/** + * @brief Sets all elements of the destination tile to negative infinity. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + neg_infty(threadgroup ST &dst, const int threadIdx) { + unary_map(dst, dst, threadIdx); +} + +// unary maps +/** + * @brief Applies the exponential function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the exponential function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + exp(threadgroup ST &dst, threadgroup const ST &src, const int threadIdx) { + unary_map(dst, src, threadIdx); +} +/** + * @brief Applies the exponential function to each element of the source tile and stores the result in the destination tile, in base 2. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the exponential function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + exp2(threadgroup ST &dst, threadgroup const ST &src, const int threadIdx) { + unary_map(dst, src, threadIdx); +} +/** + * @brief Applies the natural logarithm function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the natural logarithm function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +log(threadgroup ST &dst, threadgroup const ST &src, const int threadIdx) { + unary_map(dst, src, threadIdx); +} +/** + * @brief Applies the absolute function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the absolute function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +abs(threadgroup ST &dst, threadgroup const ST &src, const int threadIdx) { + unary_map(dst, src, threadIdx); +} +/** + * @brief Applies the rectified linear unit function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the rectified linear unit function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +relu(threadgroup ST &dst, threadgroup const ST &src, const int threadIdx) { + unary_map(dst, src, threadIdx); +} +/** + * @brief Copies the elements of the source tile to the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source data to be copied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + copy(threadgroup ST &dst, thread const U &src, const int threadIdx) { + bin_map(dst, src, threadIdx); +} + +// uniform binary maps +/** + * @brief Finds the maximum of each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + max(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const int threadIdx) { + bin_map(dst, lhs, rhs, threadIdx); +} +/** + * @brief Finds the minimum of each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + min(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const int threadIdx) { + bin_map(dst, lhs, rhs, threadIdx); +} +/** + * @brief Adds each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + add(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const int threadIdx) { + bin_map(dst, lhs, rhs, threadIdx); +} +/** + * @brief Subtracts each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + sub(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const int threadIdx) { + bin_map(dst, lhs, rhs, threadIdx); +} +/** + * @brief Multiplies each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + mul(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const int threadIdx) { + bin_map(dst, lhs, rhs, threadIdx); +} +/** + * @brief Divides each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +div(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const int threadIdx) { + bin_map(dst, lhs, rhs, threadIdx); +} + +// Row and col maps + +/** + * @brief Adds row values to each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param row_values[in] Column vector containing values to add to each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + add_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const int threadIdx) { + row_map(dst, src, row_values, threadIdx); +} +/** + * @brief Subtracts row values from each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param row_values[in] Column vector containing values to subtract from each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + sub_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const int threadIdx) { + row_map(dst, src, row_values, threadIdx); +} +/** + * @brief Multiplies each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param row_values[in] Column vector containing values to multiply each row by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + mul_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const int threadIdx) { + row_map(dst, src, row_values, threadIdx); +} +/** + * @brief Divides each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param row_values[in] Column vector containing values to divide each row by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + div_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const int threadIdx) { + row_map(dst, src, row_values, threadIdx); +} +/** + * @brief Broadcast a vector into into a tile's rows. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Column vector containing values to broadcast into rows. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + broadcast_row(threadgroup ST &dst, threadgroup const SV &row_values, const int threadIdx) { + row_map(dst, dst, row_values, threadIdx); +} + + +// col maps +/** + * @brief Adds column values to each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param col_values[in] Row vector containing values to add to each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + add_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const int threadIdx) { + col_map(dst, src, col_values, threadIdx); +} +/** + * @brief Subtracts column values from each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param col_values[in] Row vector containing values to subtract from each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + sub_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const int threadIdx) { + col_map(dst, src, col_values, threadIdx); +} +/** + * @brief Multiplies each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param col_values[in] Row vector containing values to multiply each column by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + mul_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const int threadIdx) { + col_map(dst, src, col_values, threadIdx); +} +/** + * @brief Divides each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param col_values[in] Row vector containing values to divide each column by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + div_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const int threadIdx) { + col_map(dst, src, col_values, threadIdx); +} +/** + * @brief Broadcast a vector into into a tile's columns. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Row vector containing values to broadcast into cols. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + broadcast_col(threadgroup ST &dst, threadgroup const SV &col_values, const int threadIdx) { + col_map(dst, dst, col_values, threadIdx); +} diff --git a/extra/thunder/metal/include/ops/group/shared/tile/reductions.metal b/extra/thunder/metal/include/ops/group/shared/tile/reductions.metal new file mode 100644 index 0000000000..9ad2e6e598 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/tile/reductions.metal @@ -0,0 +1,284 @@ +/** + * @file + * @brief Group reductions on shared tiles. + */ + +/** + * Performs row-wise reduction on a matrix using a specified operation. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type with row layout. + * @param row_accum The accumulator where the result of the reduction is stored. + * @param src The source matrix on which to perform the reduction. + * @param src_accum The initial value of the accumulator, used when reset is false. + * @param reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_reduce(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + using dtype = typename SV::dtype; + for (int row = laneid(threadIdx); row < src.rows; row += GROUP_THREADS) { + dtype accum = src[{row, 0}]; + #pragma clang loop unroll(full) + for (int col = 1; col < src.cols; col++) { + accum = op::template op(accum, src[{row, col}]); + } + if (reset) { + row_accum[row] = accum; + } else { + row_accum[row] = op::template op(src_accum[row], accum); + } + } +} + +/** + * Performs column-wise reduction on a matrix using a specified operation. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The shared vector type for the column accumulator. + * @tparam T The shared matrix type with column layout. + * @param col_accum The accumulator where the result of the reduction is stored. + * @param src The source matrix on which to perform the reduction. + * @param src_accum The initial value of the accumulator, used when reset is false. + * @param reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_reduce(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + using dtype = typename SV::dtype; + for (int col = laneid(threadIdx); col < src.cols; col += GROUP_THREADS) { + dtype accum = src[{0, col}]; + #pragma clang loop unroll(full) + for (int row = 1; row < src.rows; row++) { + accum = op::template op(accum, src[{row, col}]); + } + if (reset) { + col_accum[col] = accum; + } else { + col_accum[col] = op::template op(src_accum[col], accum); + } + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +/** + * @brief Store the maximum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_max(threadgroup SV &row_accum, threadgroup const ST &src, const int threadIdx) { + row_reduce(row_accum, src, row_accum, threadIdx); +} +/** + * @brief Store the minimum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_min(threadgroup SV &row_accum, threadgroup const ST &src, const int threadIdx) { + row_reduce(row_accum, src, row_accum, threadIdx); +} +/** + * @brief Store the sum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_sum(threadgroup SV &row_accum, threadgroup const ST &src, const int threadIdx) { + row_reduce(row_accum, src, row_accum, threadIdx); +} +/** + * @brief Store the product of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_prod(threadgroup SV &row_accum, threadgroup const ST &src, const int threadIdx) { + row_reduce(row_accum, src, row_accum, threadIdx); +} + +/** + * @brief Store the maximum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_max(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + row_reduce(row_accum, src, src_accum, threadIdx); +} +/** + * @brief Store the minimum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_min(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + row_reduce(row_accum, src, src_accum, threadIdx); +} +/** + * @brief Store the sum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_sum(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + row_reduce(row_accum, src, src_accum, threadIdx); +} +/** + * @brief Store the product of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + row_prod(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + row_reduce(row_accum, src, src_accum, threadIdx); +} + +/** + * @brief Store the maximum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_max(threadgroup SV &col_accum, threadgroup const ST &src, const int threadIdx) { + col_reduce(col_accum, src, col_accum, threadIdx); +} +/** + * @brief Store the minimum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_min(threadgroup SV &col_accum, threadgroup const ST &src, const int threadIdx) { + col_reduce(col_accum, src, col_accum, threadIdx); +} +/** + * @brief Store the sum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_sum(threadgroup SV &col_accum, threadgroup const ST &src, const int threadIdx) { + col_reduce(col_accum, src, col_accum, threadIdx); +} +/** + * @brief Store the product of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_prod(threadgroup SV &col_accum, threadgroup const ST &src, const int threadIdx) { + col_reduce(col_accum, src, col_accum, threadIdx); +} + +/** + * @brief Store the maximum of each column of the src shared matrix, as well as the src_accum shared vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_max(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + col_reduce(col_accum, src, src_accum, threadIdx); +} +/** + * @brief Store the minimum of each column of the src shared matrix, as well as the src_accum shared vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_min(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + col_reduce(col_accum, src, src_accum, threadIdx); +} +/** + * @brief Store the sum of each column of the src shared tile, as well as the src_accum row vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_sum(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + col_reduce(col_accum, src, src_accum, threadIdx); +} +/** + * @brief Store the product of each column of the src shared tile, as well as the src_accum row vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type + col_prod(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const int threadIdx) { + col_reduce(col_accum, src, src_accum, threadIdx); +} diff --git a/extra/thunder/metal/include/ops/group/shared/tile/tile.metal b/extra/thunder/metal/include/ops/group/shared/tile/tile.metal new file mode 100644 index 0000000000..d6e52936a8 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/tile/tile.metal @@ -0,0 +1,3 @@ +#include "conversions.metal" +#include "maps.metal" +#include "reductions.metal" diff --git a/extra/thunder/metal/include/ops/group/shared/vec/conversions.metal b/extra/thunder/metal/include/ops/group/shared/vec/conversions.metal new file mode 100644 index 0000000000..82c382c239 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/vec/conversions.metal @@ -0,0 +1,29 @@ +/** + * @file + * @brief Group conversions on shared vectors. + */ + +/** + * @brief Copies data from one shared vector to another, converting data types if necessary. + * + * This function copies data from the source shared vector `src` to the destination shared vector `dst`. + * If the data types of `src` and `dst` are the same, it performs a direct memory copy. Otherwise, it + * converts each element from the source data type to the destination data type using the appropriate + * converter before copying. + * + * @tparam SV1 The type of the destination shared vector, must satisfy the ducks::sv::all concept. + * @tparam SV2 The type of the source shared vector, must satisfy the ducks::sv::all concept. + * @param[out] dst The destination shared vector. + * @param[in] src The source shared vector. + * @note The lengths of `src` and `dst` must be equal. This is enforced at compile time. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +copy(threadgroup SV1 &dst, threadgroup const SV2 &src, const int threadIdx) { + static_assert(SV1::length == SV2::length, "Source and destination vectors must have the same length."); + #pragma clang loop unroll(full) + for(int i = laneid(threadIdx); i < dst.length; i+=GROUP_THREADS) { + dst[i] = base_types::convertor::convert(src[i]); + } +} + diff --git a/extra/thunder/metal/include/ops/group/shared/vec/maps.metal b/extra/thunder/metal/include/ops/group/shared/vec/maps.metal new file mode 100644 index 0000000000..bbc827c2ba --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/vec/maps.metal @@ -0,0 +1,267 @@ +/** + * @file + * @brief Group maps on shared vectors. + */ + +/** + * @brief Applies a unary operation to each element of a shared memory vector. + * + * @tparam op Unary operation type. + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector in which to store the result. + * @param src[in] Source vector to apply the unary operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +unary_op(threadgroup SV &dst, threadgroup const SV &src, const int threadIdx) { + #pragma clang loop unroll(full) + for(auto cur = laneid(threadIdx); cur < SV::length; cur+=GROUP_THREADS) { + dst[cur] = op::template op(src[cur]); + } +} +/** + * @brief Perform a binary operation on two shared vectors. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vectors. + * @param dst[out] The destination vector where the result is stored. + * @param lhs[in] The left-hand side vector for the operation. + * @param rhs[in] The right-hand side vector for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_op(threadgroup SV &dst, threadgroup const SV &lhs, threadgroup const SV &rhs, const int threadIdx) { + #pragma clang loop unroll(full) + for(auto cur = laneid(threadIdx); cur < SV::length; cur+=GROUP_THREADS) { + dst[cur] = op::template op(lhs[cur], rhs[cur]); + } +} +/** + * @brief Perform a binary operation on a shared vector and a scalar. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector for the operation. + * @param param[in] The scalar parameter for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_op(threadgroup SV &dst, threadgroup const SV &src, thread const typename SV::dtype ¶m, const int threadIdx) { + #pragma clang loop unroll(full) + for(auto cur = laneid(threadIdx); cur < SV::length; cur+=GROUP_THREADS) { + dst[cur] = op::template op(src[cur], param); + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// ---- const ops ---- + +/** + * @brief Sets all elements of a shared memory vector to zero. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to zero. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +zero(threadgroup SV &dst, const int threadIdx) { + unary_op(dst, dst, threadIdx); +} +/** + * @brief Sets all elements of a shared memory vector to one. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to one. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +one(threadgroup SV &dst, const int threadIdx) { + unary_op(dst, dst, threadIdx); +} +/** + * @brief Sets all elements of a shared memory vector to positive infinity. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to positive infinity. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +pos_infty(threadgroup SV &dst, const int threadIdx) { + unary_op(dst, dst, threadIdx); +} +/** + * @brief Sets all elements of a shared memory vector to negative infinity. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to negative infinity. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +neg_infty(threadgroup SV &dst, const int threadIdx) { + unary_op(dst, dst, threadIdx); +} + +// ---- unary ops ---- + +/** + * @brief Copies the elements from one shared vector to another. + * + * @tparam T Shared vector type. + * @tparam U Type of the source vector. + * @param dst[out] Destination vector where the elements will be copied to. + * @param src[in] Source vector to copy the elements from. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(threadgroup SV &dst, thread const U &src, const int threadIdx) { + bin_op(dst, dst, src, threadIdx); // the second arg is ignored here. +} +/** + * @brief Applies the exponential function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp(threadgroup SV &dst, threadgroup const SV &src, const int threadIdx) { + unary_op(dst, src, threadIdx); +} +/** + * @brief Applies the exponential function element-wise to a shared vector, in base 2. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp2(threadgroup SV &dst, threadgroup const SV &src, const int threadIdx) { + unary_op(dst, src, threadIdx); +} +/** + * @brief Applies the natural logarithm function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the logarithm function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +log(threadgroup SV &dst, threadgroup const SV &src, const int threadIdx) { + unary_op(dst, src, threadIdx); +} +/** + * @brief Applies the absolute value function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the absolute values will be stored. + * @param src[in] Source vector to apply the absolute value function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +abs(threadgroup SV &dst, threadgroup const SV &src, const int threadIdx) { + unary_op(dst, src, threadIdx); +} +/** + * @brief Applies the rectified linear unit (ReLU) function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the ReLU values will be stored. + * @param src[in] Source vector to apply the ReLU function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +relu(threadgroup SV &dst, threadgroup const SV &src, const int threadIdx) { + unary_op(dst, src, threadIdx); +} + +// ---- binary ops ---- + +/** + * @brief Computes the element-wise maximum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the maximum values will be stored. + * @param lhs[in] First vector for the maximum operation. + * @param rhs[in] Second vector for the maximum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const int threadIdx) { + bin_op(dst, lhs, rhs, threadIdx); +} +/** + * @brief Computes the element-wise minimum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the minimum values will be stored. + * @param lhs[in] First vector for the minimum operation. + * @param rhs[in] Second vector for the minimum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const int threadIdx) { + bin_op(dst, lhs, rhs, threadIdx); +} +/** + * @brief Computes the element-wise sum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the sum values will be stored. + * @param lhs[in] First vector for the sum operation. + * @param rhs[in] Second vector for the sum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +add(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const int threadIdx) { + bin_op(dst, lhs, rhs, threadIdx); +} +/** + * @brief Computes the element-wise difference of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the difference values will be stored. + * @param lhs[in] First vector for the difference operation. + * @param rhs[in] Second vector for the difference operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sub(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const int threadIdx) { + bin_op(dst, lhs, rhs, threadIdx); +} +/** + * @brief Computes the element-wise product of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the product values will be stored. + * @param lhs[in] First vector for the product operation. + * @param rhs[in] Second vector for the product operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +mul(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const int threadIdx) { + bin_op(dst, lhs, rhs, threadIdx); +} +/** + * @brief Computes the element-wise division of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the division values will be stored. + * @param lhs[in] First vector for the division operation. + * @param rhs[in] Second vector for the division operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +div(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const int threadIdx) { + bin_op(dst, lhs, rhs, threadIdx); +} diff --git a/extra/thunder/metal/include/ops/group/shared/vec/vec.metal b/extra/thunder/metal/include/ops/group/shared/vec/vec.metal new file mode 100644 index 0000000000..755c137214 --- /dev/null +++ b/extra/thunder/metal/include/ops/group/shared/vec/vec.metal @@ -0,0 +1,3 @@ +#include "conversions.metal" +#include "maps.metal" + diff --git a/extra/thunder/metal/include/ops/ops.metal b/extra/thunder/metal/include/ops/ops.metal new file mode 100644 index 0000000000..4c9120a64f --- /dev/null +++ b/extra/thunder/metal/include/ops/ops.metal @@ -0,0 +1,3 @@ +#pragma once +#include "group/group.metal" +#include "warp/warp.metal" diff --git a/extra/thunder/metal/include/ops/warp/memory/memory.metal b/extra/thunder/metal/include/ops/warp/memory/memory.metal new file mode 100644 index 0000000000..eb053c3468 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/memory.metal @@ -0,0 +1,4 @@ +#pragma once +#include "tile/tile.metal" +#include "util/util.metal" +#include "vec/vec.metal" diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_global_to_register.metal b/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_global_to_register.metal new file mode 100644 index 0000000000..05ac89f243 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_global_to_register.metal @@ -0,0 +1,51 @@ +/** +* @file +* @brief Functions for transferring data directly between global memory and registers and back. +*/ + +#pragma once + +#include "../../../../../common/common.metal" +#include "../../../../../types/types.metal" + +#include "../global_to_register.metal" + +namespace mittens { +/** + * @brief Load data from source arrays into a complex-type tile. + * + * @tparam CRT The complex tile type. + * @tparam U The data type of the source arrays. + * @param dst[out] The destination tile to load data into. + * @param resrc[in] The source array to load the real component data from. + * @param imsrc[in] The source array to load the imaginary component data from. + * @param re_row_stride[in] The stride in elements between rows in the real component source array. + * @param im_row_stride[in] The stride in elements between rows in the imaginary component source array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_complex_global_layout(), void>::type +load(thread CRT &dst, thread const CGL &src, thread const coord &idx, const short laneid) { + // Internally will use the correct load() method for row and column types + load(dst.real, src.real, idx); + load(dst.imag, src.imag, idx); +} + +/** + * @brief Store data from a complex register tile to destination arrays in global memory. + * + * @tparam CRT The complex tile type. + * @tparam U The data type of the destination arrays. + * @param redst[out] The destination array in global memory to store the real component data into. + * @param imdst[out] The destination array in global memory to store the imaginary component data into. + * @param src[in] The source register tile to store data from. + * @param re_row_stride[in] The stride in elements between rows in the real component destination array. + * @param im_row_stride[in] The stride in elements between rows in the imaginary component destination array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_complex_global_layout(), void>::type +store(thread CGL &dst, thread const CRT &src, thread const coord &idx) { + // Internally will use the correct load() method for row and column types + store(dst.real, src.real, idx); + store(dst.imag, src.imag, idx); +} +} diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_global_to_shared.metal b/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_global_to_shared.metal new file mode 100644 index 0000000000..dccaebf3eb --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_global_to_shared.metal @@ -0,0 +1,48 @@ +/** +* @file +* @brief Functions for transferring data directly between global and shared memory and back. +*/ + +#pragma once + +#include "../../../../../common/common.metal" +#include "../../../../../types/types.metal" + +#include "../global_to_shared.metal" + +namespace mittens { +/** + * @brief Loads data from global memory into a complex shared memory tile with a row layout. + * + * @tparam CST The type of the complex shared tile. + * @param[out] dst The destination complex shared memory tile. + * @param[in] resrc The source global memory array for the real component. + * @param[in] imsrc The source global memory array for the imaginary component. + * @param re_row_stride[in] The stride between rows in the source real component array. + * @param im_row_stride[in] The stride between rows in the source imaginary component array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(threadgroup CST &dst, thread const CGL &src, thread const coord &idx) { + load(dst.real, src.real, idx); + load(dst.imag, src.imag, idx); +} + +/** + * @brief Stores bf16 data from a complex shared memory tile with a row layout into global memory. + * + * @tparam CST The type of the complex shared tile. + * @param[out] redst The destination global memory array for the real component. + * @param[out] imdst The destination global memory array for the imaginary component. + * @param[in] src The source complex shared memory tile. + * @param re_row_stride[in] The stride between rows in the destination real component array. + * @param im_row_stride[in] The stride between rows in the destination imaginary component array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_complex_global_layout(), void>::type +store(thread const CGL &dst, threadgroup CST &src, thread const coord &idx) { + store(dst.real, src.real, idx); + store(dst.imag, src.imag, idx); +} + +} diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_shared_to_register.metal b/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_shared_to_register.metal new file mode 100644 index 0000000000..e8a36bb444 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/complex/complex_shared_to_register.metal @@ -0,0 +1,47 @@ +/** +* @file +* @brief Functions for transferring data directly between shared memory and registers and back. +*/ + +#pragma once + + +#include "../../../../../common/common.metal" +#include "../../../../../types/types.metal" + +#include "../shared_to_register.metal" + +namespace mittens { +/** + * @brief Load data from a complex shared tile into a complex register tile. + * + * @tparam CRT The complex register tile type + * @tparam CST The complex shared tile type + * @param dst[out] The destination complex register tile. + * @param src[in] The source complex shared tile. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_complex_register_tile(), void>::type +load(thread CRT &dst, threadgroup const CST &src) { + load(dst.real, src.real); + load(dst.imag, src.imag); +} + +/** + * @brief Store data into a complex shared tile from a complex register tile. + * + * @tparam RT The complex register tile type + * @tparam ST The complex shared tile type + * @param dst[out] The destination complex shared tile. + * @param src[in] The source complex register tile. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_complex_register_tile(), void>::type +store(threadgroup CST &dst, thread const CRT &src) { + store(dst.real, src.real); + store(dst.imag, src.imag); +} + + +} + diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/global_to_register.metal b/extra/thunder/metal/include/ops/warp/memory/tile/global_to_register.metal new file mode 100644 index 0000000000..66b4968840 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/global_to_register.metal @@ -0,0 +1,217 @@ +/** + * @file + * @brief Functions for transferring data directly between global memory and registers and back. + */ + +#pragma once // done! +#include "../../../../types/types.metal" +#include "../../../../common/common.metal" +#include +namespace mittens{ + +namespace meta { +template +METAL_FUNC static typename metal::enable_if(), void>::type +load(int i, int j, thread RT *dst, const device U *src_ptr, const short simd_y, const short simd_x, const int row_stride) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + unsigned offset = (simd_y + i * rt_base::tile_size) * row_stride + (simd_x + j * rt_base::tile_size); + T2 src2 = base_types::convertor::convert(*((device U2*)(&src_ptr[offset]))); + dst->tiles[i][j].data.thread_elements()[0] = src2[0]; + dst->tiles[i][j].data.thread_elements()[1] = src2[1]; +} + +template +METAL_FUNC static typename metal::enable_if(), void>::type +load(int i, int j, thread RT *dst, const device U *src_ptr, const short simd_y, const short simd_x, const int row_stride) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + unsigned offset = (simd_y + i * rt_base::tile_size) * row_stride + (simd_x + j * rt_base::tile_size); + dst->tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert(src_ptr[offset]); + offset += row_stride; + dst->tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert(src_ptr[offset]); +} + +template +METAL_FUNC static typename metal::enable_if(), void>::type +store(int i, int j, device U *dst_ptr, const thread RT *src, const short simd_y, const short simd_x, const int row_stride) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + unsigned offset = (simd_y + i * TILE_DIM) * row_stride + (simd_x + j * TILE_DIM); + U2 src2 = base_types::convertor::convert( + T2(src->tiles[i][j].data.thread_elements()[0], + src->tiles[i][j].data.thread_elements()[1]) + ); + *((device U2*)&dst_ptr[offset]) = src2; +} + +template +METAL_FUNC static typename metal::enable_if(), void>::type +store(int i, int j, device U *dst_ptr, const thread RT *src, const short simd_y, const short simd_x, const int row_stride) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + unsigned offset = (simd_y + i * rt_base::tile_size) * row_stride + (simd_x + j * rt_base::tile_size); + dst_ptr[offset] = base_types::convertor::convert(src->tiles[i][j].data.thread_elements()[0]); + offset += row_stride; + dst_ptr[offset] = base_types::convertor::convert(src->tiles[i][j].data.thread_elements()[1]); +} + +} + +/** + * @brief Load data from a source array into a row-major layout tile. + * + * @tparam RT The row-major layout tile type. + * @tparam U The data type of the source array. + * @param dst[out] The destination tile to load data into. + * @param src[in] The source array to load data from. + * @param row_stride[in] The stride in elements between rows in the source array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(thread RT &dst, thread const GL &src, thread const coord &idx, const short laneid) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + const device U *src_ptr = (device U*)&src.template get(idx); + const int row_stride = src.row_stride(); + + const short qid = laneid / 4; + const short simd_y = (qid & 4) + (laneid / 2) % 4; + const short simd_x = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for (int i = 0; i < RT::height; i++) { +// #pragma clang loop unroll(full) +// for (int j = 0; j < RT::width; j++) { +// unsigned offset = (simd_y + i * rt_base::tile_size) * row_stride + (simd_x + j * rt_base::tile_size); +// T2 src2 = base_types::convertor::convert(*((device U2*)(&src_ptr[offset]))); +// dst.tiles[i][j].data.thread_elements()[0] = src2[0]; +// dst.tiles[i][j].data.thread_elements()[1] = src2[1]; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::load, &dst, src_ptr, simd_y, simd_x, row_stride); +} +/** + * @brief Load data from a source array into a col-major layout tile. + * + * @tparam RT The row-major layout tile type. + * @tparam U The data type of the source array. + * @param dst[out] The destination tile to load data into. + * @param src[in] The source array to load data from. + * @param row_stride[in] The stride in elements between rows in the source array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(thread RT &dst, thread const GL &src, thread const coord &idx, const short laneid) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U = typename GL::dtype; + using layout = typename RT::layout; + const device U *src_ptr = (device U*)&(src.template get(idx)); + const int row_stride = src.row_stride(); + + const short qid = laneid / 4; + const short simd_x = (qid & 4) + (laneid / 2) % 4; + const short simd_y = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for (int i = 0; i < RT::height; i++) { +// #pragma clang loop unroll(full) +// for (int j = 0; j < RT::width; j++) { +// unsigned offset = (simd_y + i * rt_base::tile_size) * row_stride + (simd_x + j * rt_base::tile_size); +// dst.tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert(src_ptr[offset]); +// offset += row_stride; +// dst.tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert(src_ptr[offset]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::load, &dst, src_ptr, simd_y, simd_x, row_stride); +} + +/** + * @brief Store data from a register tile to a destination array in global memory with a row-major layout. + * + * @tparam RT The register tile type with a row-major layout. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register tile to store data from. + * @param row_stride[in] The stride in elements between rows in the destination array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +store(thread GL &dst, thread const RT &src, thread const coord &idx, const short laneid) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + device U *dst_ptr = (device U*)&(dst.template get(idx)); +// device U* dst_ptr = dst.raw_ptr; + const int row_stride = dst.row_stride(); + const short qid = laneid / 4; + const short simd_y = (qid & 4) + (laneid / 2) % 4; + const short simd_x = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for (int i = 0; i < RT::height; i++) { +// #pragma clang loop unroll(full) +// for (int j = 0; j < RT::width; j++) { +// unsigned offset = (simd_y + i * TILE_DIM) * row_stride + (simd_x + j * TILE_DIM); +// U2 src2 = base_types::convertor::convert( +// T2(src.tiles[i][j].data.thread_elements()[0], +// src.tiles[i][j].data.thread_elements()[1]) +// ); +// *((device U2*)&dst_ptr[offset]) = src2; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::store, dst_ptr, &src, simd_y, simd_x, row_stride); +} + +/** + * @brief Store data from a register tile to a destination array in global memory with a col-major layout. + * + * @tparam RT The register tile type with a row-major layout. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register tile to store data from. + * @param row_stride[in] The stride in elements between rows in the destination array. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +store(thread GL &dst, thread const RT &src, thread const coord &idx, const short laneid) { + using T = typename RT::dtype; + using T2 = typename RT::T2; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + using layout = typename RT::layout; + device U *dst_ptr = (device U*)&(dst.template get(idx)); + const int row_stride = dst.row_stride(); + const short qid = laneid / 4; + const short simd_x = (qid & 4) + (laneid / 2) % 4; + const short simd_y = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for (int i = 0; i < RT::height; i++) { +// #pragma clang loop unroll(full) +// for (int j = 0; j < RT::width; j++) { +// unsigned offset = (simd_y + i * rt_base::tile_size) * row_stride + (simd_x + j * rt_base::tile_size); +// dst_ptr[offset] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[0]); +// offset += row_stride; +// dst_ptr[offset] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[1]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::store, dst_ptr, &src, simd_y, simd_x, row_stride); +} + + +} diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/global_to_shared.metal b/extra/thunder/metal/include/ops/warp/memory/tile/global_to_shared.metal new file mode 100644 index 0000000000..2aceacc45d --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/global_to_shared.metal @@ -0,0 +1,192 @@ +/** + * @file + * @brief Functions for transferring data directly between global and shared memory and back. + */ + +#pragma once // not done! +#include "../../../../types/types.metal" +#include "../../../../common/common.metal" +#include +namespace mittens { + +// +namespace meta { +template +METAL_FUNC static typename metal::enable_if(), void>::type +load(int i, threadgroup ST *dst, device const typename ST::dtype *src, thread const int& row_stride, thread const short& laneid) { + { + unsigned idx = i + laneid; + unsigned row = idx / memcpy_per_row; + unsigned col = (idx*elem_per_memcpy) % ST::cols; + *(threadgroup ReadVector*)(&(*dst)[int2(row, col)]) = *(device ReadVector*)(&src[row*row_stride + col]); + } +} + +template +METAL_FUNC static typename metal::enable_if(), void>::type +store(int i, device typename ST::dtype *dst, threadgroup const ST *src, thread const int& row_stride, thread const short& laneid) { + { + unsigned idx = i + laneid; + unsigned row = idx / memcpy_per_row; + unsigned col = (idx*elem_per_memcpy) % ST::cols; + *(device ReadVector*)(&dst[row*row_stride + col]) = *(threadgroup ReadVector*)(&(*src)[int2(row, col)]); + } +} + +} // namespace meta + +// +///** +// * @brief Loads data from global memory into a shared memory tile with a row layout. +// * +// * @tparam ST The type of the shared tile. +// * @param[out] dst The destination shared memory tile. +// * @param[in] src The source global memory array. +// * @param row_stride[in] The stride between rows in the source array. +// * @param laneid[in] Thread's index in SIMD group +// */ +//template +//static METAL_FUNC void load(threadgroup ST &dst, device const typename ST::dtype *src, const int row_stride, short laneid) { +// using read_type = float; +// ducks::assert_shared_tile(); +// constexpr const unsigned elem_per_memcpy = sizeof(read_type)/sizeof(typename ST::dtype); // 2 +// constexpr const unsigned memcpy_per_row = ST::cols / elem_per_memcpy; // 32/2=16 not power of 2 +// constexpr const unsigned total_calls = ST::num_elements / (SIMD_THREADS*elem_per_memcpy); // 1024/(32*2)=16 +//// #pragma clang loop unroll_count(1) +//// #pragma clang loop unroll(disable) +// #pragma clang loop unroll(full) +// for(unsigned i = 0; i < total_calls; i++) { +// unsigned idx = i * 32 + laneid; +// unsigned row = idx / memcpy_per_row; +// unsigned col = (idx*elem_per_memcpy) % ST::cols; +// *(threadgroup read_type*)(&dst[int2(row, col)]) = *(device read_type*)(&src[row*row_stride + col]); +// } +// +//// ducks::assert_shared_tile(); +//// const constexpr int read_size = 1; +//// using read_type = ReadVector; +//// constexpr const unsigned elem_per_memcpy = sizeof(read_type)/sizeof(typename ST::dtype); // 2 +//// constexpr const unsigned memcpy_per_row = ST::cols / elem_per_memcpy; // 32/2=16 not power of 2 +//// constexpr const unsigned total_calls = ST::num_elements / (SIMD_THREADS*elem_per_memcpy); // 1024/(32*2)=16 +//// +//// +//// meta::unroll_i_in_range<0, total_calls * SIMD_THREADS, SIMD_THREADS>::run(meta::load, &dst, src, row_stride, laneid); +//} +// +// +///** +// * @brief Stores data from a shared memory tile with a row layout into global memory. +// * +// * @tparam ST The type of the shared tile. +// * @param[out] dst The destination global memory array. +// * @param[in] src The source shared memory tile. +// * @param row_stride[in] The stride between rows in the destination array. +// * @param laneid[in] Thread's index in SIMD group +// */ +//template +//static METAL_FUNC void store(device typename ST::dtype *dst, threadgroup const ST &src, const int row_stride, short laneid) { +// using read_type = float4; +// ducks::assert_shared_tile(); +// constexpr const unsigned elem_per_memcpy = sizeof(read_type)/sizeof(typename ST::dtype); +// constexpr const unsigned memcpy_per_row = ST::cols / elem_per_memcpy; +// constexpr const unsigned total_calls = ST::num_elements / (SIMD_THREADS*elem_per_memcpy); +//// #pragma clang loop unroll_count(READ_SIZE) +////#pragma clang loop unroll(disable) +// #pragma clang loop unroll(full) +// for(unsigned i = 0; i < total_calls; i++) { +// unsigned idx = i * 32 + laneid; +// unsigned row = idx / memcpy_per_row; +// unsigned col = (idx*elem_per_memcpy) % src.cols; +// *(device read_type*)(&dst[row*row_stride + col]) = *(threadgroup read_type*)(&src[int2(row, col)]); +// } +// +//// +//// ducks::assert_shared_tile(); +//// const constexpr int read_size = 1; +//// using read_type = ReadVector; +//// +//// constexpr const unsigned elem_per_memcpy = sizeof(read_type)/sizeof(typename ST::dtype); +//// constexpr const unsigned memcpy_per_row = ST::cols / elem_per_memcpy; +//// constexpr const unsigned total_calls = ST::num_elements / (SIMD_THREADS*elem_per_memcpy); +//// +//// +//// meta::unroll_i_in_range<0, total_calls * SIMD_THREADS, SIMD_THREADS>::run(meta::store, dst, &src, row_stride, laneid); +//} + + + +/** + * @brief Loads data from global memory into a shared memory tile with a row layout. + * + * @tparam ST The type of the shared tile. + * @param[out] dst The destination shared memory tile. + * @param[in] src The source global memory array. + * @param row_stride[in] The stride between rows in the source array. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(threadgroup ST &dst, thread const GL &src, thread const coord &idx, short laneid) { + using U = typename GL::dtype; + constexpr const int read_size = 1; + using read_type = ReadVector; + device U *src_ptr = (device U*)&src.template get(idx); + const int row_stride = src.row_stride(); + constexpr const unsigned elem_per_memcpy = sizeof(read_type)/sizeof(typename ST::dtype); // 2 + constexpr const unsigned memcpy_per_row = ST::cols / elem_per_memcpy; // 32/2=16 not power of 2 + constexpr const unsigned total_calls = ST::num_elements / (SIMD_THREADS*elem_per_memcpy); // 1024/(32*2)=16 +// #pragma clang loop unroll_count(1) +// #pragma clang loop unroll(disable) +// #pragma clang loop unroll(full) +// for(unsigned i = 0; i < total_calls; i++) { +// unsigned idx = i * 32 + laneid; +// unsigned row = idx / memcpy_per_row; +// unsigned col = (idx*elem_per_memcpy) % ST::cols; +// *(threadgroup read_type*)(&dst[int2(row, col)]) = *(device read_type*)(&src_ptr[row*row_stride + col]); +// } + meta::unroll_i_in_range<0, total_calls * SIMD_THREADS, SIMD_THREADS>::run(meta::load, &dst, src_ptr, row_stride, laneid); +} + /* + + */ + + +/** + * @brief Stores data from a shared memory tile with a row layout into global memory. + * + * @tparam ST The type of the shared tile. + * @param[out] dst The destination global memory array. + * @param[in] src The source shared memory tile. + * @param row_stride[in] The stride between rows in the destination array. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +store(thread GL &dst, threadgroup const ST &src, thread const coord &idx, short laneid) { + using U = typename GL::dtype; + constexpr const int read_size = 1; + using read_type = ReadVector; + device U *dst_ptr = (device U*)&dst.template get(idx); + const int row_stride = dst.row_stride(); + + constexpr const unsigned elem_per_memcpy = sizeof(read_type)/sizeof(typename ST::dtype); + constexpr const unsigned memcpy_per_row = ST::cols / elem_per_memcpy; + constexpr const unsigned total_calls = ST::num_elements / (SIMD_THREADS*elem_per_memcpy); +// #pragma clang loop unroll_count(READ_SIZE) +//#pragma clang loop unroll(disable) +// #pragma clang loop unroll(full) +// for(unsigned i = 0; i < total_calls; i++) { +// unsigned idx = i * 32 + laneid; +// unsigned row = idx / memcpy_per_row; +// unsigned col = (idx*elem_per_memcpy) % src.cols; +// *(device read_type*)(&dst_ptr[row*row_stride + col]) = *(threadgroup read_type*)(&src[int2(row, col)]); +// } + + meta::unroll_i_in_range<0, total_calls * SIMD_THREADS, SIMD_THREADS>::run(meta::store, dst_ptr, &src, row_stride, laneid); +} + + + +} + + diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/shared_to_register.metal b/extra/thunder/metal/include/ops/warp/memory/tile/shared_to_register.metal new file mode 100644 index 0000000000..8cd24f8216 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/shared_to_register.metal @@ -0,0 +1,461 @@ +/** + * @file + * @brief Functions for transferring data directly between shared memory and registers and back. + */ +#pragma once // done! + +#include "../../../../types/types.metal" +#include "../../../../common/common.metal" +#include +namespace mittens { + +// These probably need to be redone to reduce bank conflicts. +// They currently work fine with xor layout but it should be +// possible to reduce their bank conflicts with other layouts too. +// +namespace meta { + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +loadStR(int i, int j, thread RT *dst, threadgroup const ST *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; + T2 values = base_types::convertor::convert(*((threadgroup U2*)(&(*src)[int2(y, x)]))); + dst->tiles[i][j].data.thread_elements()[0] = values[0]; + dst->tiles[i][j].data.thread_elements()[1] = values[1]; +// +// simdgroup_load(dst->tiles[i][j].data, +// (threadgroup T*)(src->data), +// src->cols, +// {i * mittens::TILE_DIM, j * mittens::TILE_DIM}, +// +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +storeStR(int i, int j, threadgroup ST *dst, thread const RT *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; + U2 values = base_types::convertor::convert({src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}); + *((threadgroup U2*)(&(*dst)[int2(y, x)])) = values; +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +loadStR(int i, int j, thread RT *dst, threadgroup const ST *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; +// dst->tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert((*src)[int2(y , x)]); +// dst->tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert((*src)[int2(y+1, x)]); + T2 vals = base_types::convertor::convert({(*src)[int2(y , x)], (*src)[int2(y+1, x)]}); + dst->tiles[i][j].data.thread_elements()[0] = vals[0]; + dst->tiles[i][j].data.thread_elements()[1] = vals[1]; +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +storeStR(int i, int j, threadgroup ST *dst, thread const RT *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; +// (*dst)[int2(y , x)] = base_types::convertor::convert(src->tiles[i][j].data.thread_elements()[0]); +// (*dst)[int2(y+1, x)] = base_types::convertor::convert(src->tiles[i][j].data.thread_elements()[1]); + + U2 vals = base_types::convertor::convert({src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}); + (*dst)[int2(y , x)] = vals[0]; + (*dst)[int2(y+1, x)] = vals[1]; +} + +} + +/** + * @brief Load data from a shared tile into a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +load(thread RT &dst, threadgroup const ST &src, short laneid) { + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + const short qid = laneid / 4; + int offsetY = (qid & 4) + (laneid / 2) % 4; + int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// T2 values = base_types::convertor::convert(*((threadgroup U2*)(&src[int2(y, x)]))); +// dst.tiles[i][j].data.thread_elements()[0] = values[0]; +// dst.tiles[i][j].data.thread_elements()[1] = values[1]; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::loadStR, &dst, &src, laneid, offsetY, offsetX); +} + +/** + * @brief Load data from a shared tile into a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +load(thread RT &dst, threadgroup const ST &src, short laneid) { + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + const short qid = laneid / 4; +// int offsetY = (qid & 4) + (laneid / 2) % 4; +// int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; + int offsetX = (qid & 4) + (laneid / 2) % 4; + int offsetY = (qid & 2) * 2 + (laneid % 2) * 2; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// dst.tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert(src[int2(y , x)]); +// dst.tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert(src[int2(y+1, x)]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::loadStR, &dst, &src, laneid, offsetY, offsetX); +} + +/** + * @brief Store data into a shared tile from a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +store(threadgroup ST &dst, thread const RT &src, short laneid) { + ducks::assert_register_tile(); + ducks::assert_shared_tile(); + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + + const short qid = laneid / 4; + int offsetY = (qid & 4) + (laneid / 2) % 4; + int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < src.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// U2 values = base_types::convertor::convert({src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}); +// *((threadgroup U2*)(&dst[int2(y, x)])) = values; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::storeStR, &dst, &src, laneid, offsetY, offsetX); +} + +/** + * @brief Store data into a shared tile from a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +store(threadgroup ST &dst, thread const RT &src, short laneid) { + ducks::assert_register_tile(); + ducks::assert_shared_tile(); + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + + const short qid = laneid / 4; +// int offsetY = (qid & 4) + (laneid / 2) % 4; +// int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; + int offsetX = (qid & 4) + (laneid / 2) % 4; + int offsetY = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < src.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// dst[int2(y , x)] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[0]); +// dst[int2(y+1, x)] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[1]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::storeStR, &dst, &src, laneid, offsetY, offsetX); +} + +/*---------------------------------------------------------------------------------*/ +// These probably need to be redone to reduce bank conflicts. +// They currently work fine with xor layout but it should be +// possible to reduce their bank conflicts with other layouts too. +// +namespace meta { + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +loadStR_r(int i, int j, thread RT *dst, thread const ST *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; + T2 values = base_types::convertor::convert(*((threadgroup U2*)(&(*src)[int2(y, x)]))); + dst->tiles[i][j].data.thread_elements()[0] = values[0]; + dst->tiles[i][j].data.thread_elements()[1] = values[1]; +// +// simdgroup_load(dst->tiles[i][j].data, +// (threadgroup T*)(src->data), +// src->cols, +// {i * mittens::TILE_DIM, j * mittens::TILE_DIM}, +// +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +storeStR_r(int i, int j, thread ST *dst, thread const RT *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; + U2 values = base_types::convertor::convert({src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}); + *((threadgroup U2*)(&(*dst)[int2(y, x)])) = values; +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +loadStR_c(int i, int j, thread RT *dst, thread const ST *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; +// dst->tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert((*src)[int2(y , x)]); +// dst->tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert((*src)[int2(y+1, x)]); + T2 vals = base_types::convertor::convert({(*src)[int2(y , x)], (*src)[int2(y+1, x)]}); + dst->tiles[i][j].data.thread_elements()[0] = vals[0]; + dst->tiles[i][j].data.thread_elements()[1] = vals[1]; +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +storeStR_c(int i, int j, thread ST *dst, thread const RT *src, short laneid, int offsetY, int offsetX) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + int y = offsetY + i * mittens::TILE_DIM; + int x = offsetX + j * mittens::TILE_DIM; +// (*dst)[int2(y , x)] = base_types::convertor::convert(src->tiles[i][j].data.thread_elements()[0]); +// (*dst)[int2(y+1, x)] = base_types::convertor::convert(src->tiles[i][j].data.thread_elements()[1]); + + U2 vals = base_types::convertor::convert({src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}); + (*dst)[int2(y , x)] = vals[0]; + (*dst)[int2(y+1, x)] = vals[1]; +} + +} + +/** + * @brief Load data from a shared tile into a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +load(thread RT &dst, thread const ST &src, short laneid) { + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + const short qid = laneid / 4; + int offsetY = (qid & 4) + (laneid / 2) % 4; + int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// T2 values = base_types::convertor::convert(*((threadgroup U2*)(&src[int2(y, x)]))); +// dst.tiles[i][j].data.thread_elements()[0] = values[0]; +// dst.tiles[i][j].data.thread_elements()[1] = values[1]; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::loadStR_r, &dst, &src, laneid, offsetY, offsetX); +} + +/** + * @brief Load data from a shared tile into a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination register tile. + * @param src[in] The source shared tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +load(thread RT &dst, thread const ST &src, short laneid) { + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + const short qid = laneid / 4; +// int offsetY = (qid & 4) + (laneid / 2) % 4; +// int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; + int offsetX = (qid & 4) + (laneid / 2) % 4; + int offsetY = (qid & 2) * 2 + (laneid % 2) * 2; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// dst.tiles[i][j].data.thread_elements()[0] = base_types::convertor::convert(src[int2(y , x)]); +// dst.tiles[i][j].data.thread_elements()[1] = base_types::convertor::convert(src[int2(y+1, x)]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::loadStR_c, &dst, &src, laneid, offsetY, offsetX); +} + +/** + * @brief Store data into a shared tile from a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +store(thread ST &dst, thread const RT &src, short laneid) { + ducks::assert_register_tile(); + ducks::assert_shared_tile(); + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + + const short qid = laneid / 4; + int offsetY = (qid & 4) + (laneid / 2) % 4; + int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < src.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// U2 values = base_types::convertor::convert({src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}); +// *((threadgroup U2*)(&dst[int2(y, x)])) = values; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::storeStR_r, &dst, &src, laneid, offsetY, offsetX); +} + +/** + * @brief Store data into a shared tile from a register tile. + * + * @tparam RT The register tile type + * @tparam ST The shared tile type + * @param dst[out] The destination shared tile. + * @param src[in] The source register tile. + * @param laneid[in] Thread's index in SIMD group + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_tile(), void>::type +store(thread ST &dst, thread const RT &src, short laneid) { + ducks::assert_register_tile(); + ducks::assert_shared_tile(); + static_assert(RT::height == ST::height, "register tile and shared tile must match height"); + static_assert(RT::width == ST::width, "register tile and shared tile must match width"); + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; + using U = typename ST::dtype; + using U2 = typename base_types::packing::packed_type; + + const short qid = laneid / 4; +// int offsetY = (qid & 4) + (laneid / 2) % 4; +// int offsetX = (qid & 2) * 2 + (laneid % 2) * 2; + int offsetX = (qid & 4) + (laneid / 2) % 4; + int offsetY = (qid & 2) * 2 + (laneid % 2) * 2; + +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < src.width; j++) { +// int y = offsetY + i * mittens::TILE_DIM; +// int x = offsetX + j * mittens::TILE_DIM; +// dst[int2(y , x)] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[0]); +// dst[int2(y+1, x)] = base_types::convertor::convert(src.tiles[i][j].data.thread_elements()[1]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::storeStR_c, &dst, &src, laneid, offsetY, offsetX); +} + +} + + diff --git a/extra/thunder/metal/include/ops/warp/memory/tile/tile.metal b/extra/thunder/metal/include/ops/warp/memory/tile/tile.metal new file mode 100644 index 0000000000..5913649770 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/tile/tile.metal @@ -0,0 +1,7 @@ +#pragma once + +#include "global_to_register.metal" +#include "global_to_shared.metal" +#include "shared_to_register.metal" + + diff --git a/extra/thunder/metal/include/ops/warp/memory/util/util.metal b/extra/thunder/metal/include/ops/warp/memory/util/util.metal new file mode 100644 index 0000000000..bc2edac064 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/util/util.metal @@ -0,0 +1,37 @@ +/** + * @file + * @brief General utilities not specialized for either tiles or vectors. + */ +#pragma once // done! +#include "../tile/tile.metal" +#include "../../../../types/shared/shared.metal" +namespace mittens { + +// sizeof() can be unreliable when working with references to objects +// plus, template magic allows arrays of these objects to be copied, too. +namespace detail { + +template +struct size_info; + +template +struct size_info { +private: + static_assert(ducks::is_shared_tile() || ducks::is_shared_vector(), "T must be a shared tile or shared vector"); + constant static constexpr uint32_t elements = ducks::is_shared_tile() ? T::num_elements : T::length; + constant static constexpr uint32_t bytes = elements * sizeof(typename T::dtype); +}; + +template +struct size_info { + constant static constexpr uint32_t elements = dim * size_info::elements; + constant static constexpr uint32_t bytes = dim * size_info::bytes; +}; +} + +template constant constexpr uint32_t size_elements = detail::size_info::elements; +template constant constexpr uint32_t size_bytes = detail::size_info::bytes; + + + +} diff --git a/extra/thunder/metal/include/ops/warp/memory/vec/global_to_register.metal b/extra/thunder/metal/include/ops/warp/memory/vec/global_to_register.metal new file mode 100644 index 0000000000..b0fa9869df --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/vec/global_to_register.metal @@ -0,0 +1,103 @@ +/** + * @file + * @brief Functions for transferring data directly between global memory and registers and back. +*/ +#pragma once // not done +/* + TODO: + change loads/stores, prevent unnecessary + */ +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { +/** + * @brief Load data into a register vector from a source array in global memory. + * + * @tparam RV The register vector type. + * @tparam U The data type of the source array. + * @param[out] dst The destination register vector to load data into. + * @param[in] src The source array in global memory to load data from. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(thread RV &dst, thread const GL &src, thread const coord &idx, const short laneid) { + using RV_T = typename RV::dtype; + using RV_T2 = typename base_types::packing::packed_type; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + device U *src_ptr = (device U*)&src.template get(idx); + if (ducks::is_align_layout()) { + constexpr const uint32_t MASK_1 = 0x00AA00AA; // kitty bit magic + constexpr const uint32_t MASK_2 = 0x55005500; + constexpr const uint32_t MASK_3 = 0xAA00AA00; + unsigned offset = ((MASK_1 >> laneid) & 1u) * 2 + ((MASK_2 >> laneid) & 1u) * 4 + ((MASK_3 >> laneid) & 1u) * 6; + #pragma clang loop unroll(full) + for (int t = 0; t < RV::outer_dim; offset+=8, t++) { + RV_T2 src2 = base_types::convertor::convert(*(device U2*)(&src_ptr[offset])); + dst.data[t][0] = src2[0]; + dst.data[t][1] = src2[1]; + } + } else if (ducks::is_ortho_layout()) { // RV::inner_dim == 1 + const short laneid_div2 = laneid / 2; + unsigned offset = laneid_div2 % 4 + (laneid_div2 / 8) * 4; + #pragma clang loop unroll(full) + for (int t = 0; t < RV::outer_dim; offset+=8, t++) { + dst.data[t][0] = base_types::convertor::convert(src_ptr[offset]); + } + } else if (ducks::is_naive_layout()) { + #pragma clang loop unroll(full) + for(auto w = 0; w < RV::outer_dim; w++) { +// if(w < dst.outer_dim-1 || dst.length%32 == 0 || laneid<16) { + if (w * SIMD_THREADS + laneid < RV::length) { + dst[w][0] = base_types::convertor::convert(src_ptr[w * SIMD_THREADS + laneid]); + } + } + } +} + +/** + * @brief Store data from a register vector to a destination array in global memory. + * + * @tparam RV The register vector type. + * @tparam U The data type of the destination array. + * @param[out] dst The destination array in global memory to store data into. + * @param[in] src The source register vector to store data from. + */ +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +store(thread GL &dst, thread const RV &src, thread const coord &idx, const short laneid) { + using RV_T = typename RV::dtype; + using RV_T2 = typename base_types::packing::packed_type; + using U = typename GL::dtype; + using U2 = typename base_types::packing::packed_type; + device U *dst_ptr = (device U*)&(dst.template get(idx)); + if (ducks::is_align_layout()) { + constexpr const uint32_t MASK_1 = 0x00AA00AA; // kitty bit magic + constexpr const uint32_t MASK_2 = 0x55005500; + constexpr const uint32_t MASK_3 = 0xAA00AA00; + unsigned offset = ((MASK_1 >> laneid) & 1u) * 2 + ((MASK_2 >> laneid) & 1u) * 4 + ((MASK_3 >> laneid) & 1u) * 6; + #pragma clang loop unroll(full) + for (int t = 0; t < RV::outer_dim; offset+=8, t++) { + U2 src2 = base_types::convertor::convert({src.data[t][0], src.data[t][1]}); + *(device U2*)(&dst_ptr[offset]) = src2; + } + } else if (ducks::is_ortho_layout()){ // RV::inner_dim == 1 + const short laneid_div2 = laneid / 2; + unsigned offset = laneid_div2 % 4 + (laneid_div2 / 8) * 4; + #pragma clang loop unroll(full) + for (int t = 0; t < RV::outer_dim; offset+=8, t++) { + dst_ptr[offset] = base_types::convertor::convert(src.data[t][0]); + } + } else { + #pragma clang loop unroll(full) + for(auto w = 0; w < RV::outer_dim; w++) { + // if(w < dst.outer_dim-1 || dst.length%32 == 0 || laneid<16) { + if (w * SIMD_THREADS + laneid < RV::length) { + dst_ptr[w * SIMD_THREADS + laneid] = base_types::convertor::convert(src.data[w][0]); + } + } + } +} + +} diff --git a/extra/thunder/metal/include/ops/warp/memory/vec/global_to_shared.metal b/extra/thunder/metal/include/ops/warp/memory/vec/global_to_shared.metal new file mode 100644 index 0000000000..ada324ca04 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/vec/global_to_shared.metal @@ -0,0 +1,44 @@ +/** + * @file + * @brief Functions for transferring data directly between global and shared memory and back. + */ + +#pragma once // done! +#include "../../../../types/types.metal" + +namespace mittens { + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +load(threadgroup SV &dst, thread const GL &src, thread const coord &idx, const unsigned laneid) { + using read_type = float4; + using U = typename GL::dtype; + constexpr int elem_per_transfer = sizeof(read_type) / sizeof(typename SV::dtype); + constexpr int total_calls = SV::length / elem_per_transfer; // guaranteed to divide + device U *src_ptr = (device U*)&src.template get(idx); + #pragma clang loop unroll(full) + for (int i = laneid; i < total_calls; i += mittens::SIMD_THREADS) { + if(i * elem_per_transfer < dst.length) { + *(threadgroup read_type*)&dst[i*elem_per_transfer] = *(device read_type*)&src_ptr[i*elem_per_transfer]; + } + } +} + +template +METAL_FUNC static typename metal::enable_if() && ducks::is_global_layout(), void>::type +store(thread const GL &dst, threadgroup const SV &src, thread const coord &idx, const unsigned laneid) { + using read_type = float4; + using U = typename GL::dtype; + constexpr int elem_per_transfer = sizeof(read_type) / sizeof(typename SV::dtype); + constexpr int total_calls = SV::length / elem_per_transfer; // guaranteed to divide + device U *dst_ptr = (device U*)&dst.template get(idx); + #pragma clang loop unroll(full) + for (int i = laneid; i < total_calls; i += mittens::SIMD_THREADS) { + if(i * elem_per_transfer < src.length) { + *(device read_type*)&dst_ptr[i*elem_per_transfer] = *(threadgroup read_type*)&src[i*elem_per_transfer]; + } + } +} + +} + diff --git a/extra/thunder/metal/include/ops/warp/memory/vec/shared_to_register.metal b/extra/thunder/metal/include/ops/warp/memory/vec/shared_to_register.metal new file mode 100644 index 0000000000..83731259f7 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/vec/shared_to_register.metal @@ -0,0 +1,208 @@ +/** + * @file + * @brief Functions for transferring data directly between shared memory and registers and back. + */ + +#pragma once // not done +/* + TODO: + prevent unnecesary memory back forth + + */ +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +/** + * @brief Load data from a shared vector into a register vector. + * + * @tparam RV The register vector type + * @tparam SV The shared vector type + * @param dst[out] The destination register vector. + * @param src[in] The source shared vector. + */ + +/* + "For row-vectors: + 0,2,4,6,16,18,20,22 holds %8+0 & %8 +1 + 1,3,5,7,17,19,21,23 holds %8+2 & %8+3 + 00000000101010100000000010101010 = 0x00AA00AA + 8,10,12,14,24,26,28,30 holds %8+4 & %8+5 + 01010101000000000101010100000000 = 0x55005500 + 9,11,13,15,25,27,29,31 holds %8+6 & %8+7" + 10101010000000001010101000000000 = 0xAA00AA00 + + "For colum-vectors: + 0,1,8,9 holds %8+0 + 2,3,10,11 holds %8+1 + 4,5,12,13 holds %8+2 + 6,7,14,15 holds %8+3 + 16,17,24,25 holds %8+4 + 18,19,26,27 holds %8+5 + 20,21,28,29 holds %8+6 + 22,23,30,31 holds %8+7 + + 0,0,4,4 holds %8+0 + 1,1,5,5 holds %8+1 + 2,2,6,6 holds %8+2 + 3,3,7,7 holds %8+3 + 8,8,12,12 holds %8+4 + 9,9,13,13 holds %8+5 + 10,10,14,14 holds %8+6 + 11,11,15,15 holds %8+7 + " + + 0 0 1 1 8 8 9 9 + 2 2 3 3 10 10 11 11 + 4 4 5 5 12 12 13 13 + 6 6 7 7 14 14 15 15 + 16 16 17 17 24 24 25 25 + 18 18 19 19 26 26 27 27 + 20 20 21 21 28 28 29 29 + 22 22 23 23 30 30 31 31 + */ +// optimize later +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_vector(), void>::type +load(thread RV &dst, threadgroup const SV &src, const short laneid) { + using RV_T = typename RV::dtype; + using RV_T2 = typename base_types::packing::packed_type; + using SV_T = typename SV::dtype; + using SV_T2 = typename base_types::packing::packed_type; + + + static_assert(SV::tiles == RV::tiles, "RV and SV dimensions must match"); + + if (ducks::is_align_layout()) { + constexpr const uint32_t MASK_1 = 0x00AA00AA; // kitty bit magic + constexpr const uint32_t MASK_2 = 0x55005500; + constexpr const uint32_t MASK_3 = 0xAA00AA00; + unsigned offset = ((MASK_1 >> laneid) & 1u) * 2 + ((MASK_2 >> laneid) & 1u) * 4 + ((MASK_3 >> laneid) & 1u) * 6; + #pragma clang loop unroll(full) + for (int t = 0; t < SV::tiles; offset+=8, t++) { + RV_T2 src2 = base_types::convertor::convert(*(threadgroup SV_T2*)(&src.data[offset])); + dst.data[t][0] = src2[0]; + dst.data[t][1] = src2[1]; +// dst.data[t][0] = 7.f; +// dst.data[t][1] = 7.f; + } + } else if (ducks::is_ortho_layout()) { + const short laneid_div2 = laneid / 2; + unsigned offset = laneid_div2 % 4 + (laneid_div2 / 8) * 4; + #pragma clang loop unroll(full) + for (int t = 0; t < SV::tiles; offset+=8, t++) { + dst.data[t][0] = base_types::convertor::convert(src[offset]); + } + } else if (ducks::is_naive_layout()) { + #pragma clang loop unroll(full) + for(auto w = 0; w < RV::outer_dim; w++) { + if (w * SIMD_THREADS + laneid < RV::length) { + dst.data[w][0] = base_types::convertor::convert(src[w * SIMD_THREADS + laneid]); + } + } + } +} + + +/** + * @brief Store data into a shared vector from a register vector. + * + * @tparam RV The register vector type + * @tparam SV The shared vector type + * @param dst[out] The destination shared vector. + * @param src[in] The source register vector. + */ + // optimize later +template +METAL_FUNC static typename metal::enable_if() && ducks::is_shared_vector(), void>::type +store(threadgroup SV &dst, thread const RV &src, const short laneid) { + ducks::assert_shared_vector(); + ducks::assert_register_vector(); + using RV_T = typename RV::dtype; + using RV_T2 = typename base_types::packing::packed_type; + using SV_T = typename SV::dtype; + using SV_T2 = typename base_types::packing::packed_type; + + + static_assert(SV::tiles == RV::tiles, "RV and SV dimensions must match"); + + if (ducks::is_align_layout()) { + constexpr const uint32_t MASK_1 = 0x00AA00AA; // kitty bit magic + constexpr const uint32_t MASK_2 = 0x55005500; + constexpr const uint32_t MASK_3 = 0xAA00AA00; + unsigned offset = ((MASK_1 >> laneid) & 1u) * 2 + ((MASK_2 >> laneid) & 1u) * 4 + ((MASK_3 >> laneid) & 1u) * 6; + #pragma clang loop unroll(full) + for (int t = 0; t < SV::tiles; offset+=8, t++) { + SV_T2 src2 = base_types::convertor::convert({src.data[t][0], src.data[t][1]}); + *(threadgroup SV_T2*)(&dst.data[offset]) = src2; + +// *(threadgroup SV_T2*)(&dst.data[offset]) = (SV_T2)1.f; + } + } else if (ducks::is_ortho_layout()) { + const short laneid_div2 = laneid / 2; + unsigned offset = laneid_div2 % 4 + (laneid_div2 / 8) * 4; + #pragma clang loop unroll(full) + for (int t = 0; t < SV::tiles; offset+=8, t++) { + dst[offset] = base_types::convertor::convert(src.data[t][0]); + } + } else if (ducks::is_naive_layout()) { + #pragma clang loop unroll(full) + for(auto w = 0; w < RV::outer_dim; w++) { + if (w * SIMD_THREADS + laneid < RV::length) { + dst[w * SIMD_THREADS + laneid] = base_types::convertor::convert(src.data[w][0]); + } + } + } +} + +} + + + +///// TRASH CAN + +/* + template + METAL_FUNC static typename metal::enable_if() && ducks::is_shared_vector(), void>::type + load(thread RV &dst, threadgroup const SV &src, const short laneid, const int start_tile, const int size_tile) { + using RV_T = typename RV::dtype; + using RV_T2 = typename base_types::packing::packed_type; + using SV_T = typename SV::dtype; + using SV_T2 = typename base_types::packing::packed_type; + + + // static_assert(RV::tiles == size_tile , "RV and SV dimensions must match"); + + if (ducks::is_align_layout()) { + constexpr const uint32_t MASK_1 = 0x00AA00AA; // kitty bit magic + constexpr const uint32_t MASK_2 = 0x55005500; + constexpr const uint32_t MASK_3 = 0xAA00AA00; + unsigned offset = ((MASK_1 >> laneid) & 1u) * 2 + ((MASK_2 >> laneid) & 1u) * 4 + ((MASK_3 >> laneid) & 1u) * 6 + + 8 * start_tile; + #pragma clang loop unroll(full) + for (int t = start_tile; t < start_tile + size_tile; offset+=8, t++) { + // RV_T2 src2 = base_types::convertor::convert(*(threadgroup SV_T2*)(&src.data[offset])); + // dst.data[t][0] = src2[0]; + // dst.data[t][1] = src2[1]; + } + } else if (ducks::is_ortho_layout()) { + const short laneid_div2 = laneid / 2; + unsigned offset = laneid_div2 % 4 + (laneid_div2 / 8) * 4 + + 8 * start_tile; + #pragma clang loop unroll(full) + for (int t = start_tile; t < start_tile + size_tile; offset+=8, t++) { + dst.data[t][0] = base_types::convertor::convert(src[offset]); + } + } + // else if (ducks::is_naive_layout()) { + // #pragma clang loop unroll(full) + // for(auto w = 0; w < RV::outer_dim; w++) { + // if (w * SIMD_THREADS + laneid < RV::length) { + // dst.data[w][0] = base_types::convertor::convert(src[w * SIMD_THREADS + laneid]); + // } + // } + // } + } + + */ diff --git a/extra/thunder/metal/include/ops/warp/memory/vec/vec.metal b/extra/thunder/metal/include/ops/warp/memory/vec/vec.metal new file mode 100644 index 0000000000..53e313e7d4 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/memory/vec/vec.metal @@ -0,0 +1,4 @@ +#pragma once +#include "global_to_register.metal" +#include "global_to_shared.metal" +#include "shared_to_register.metal" diff --git a/extra/thunder/metal/include/ops/warp/register/register.metal b/extra/thunder/metal/include/ops/warp/register/register.metal new file mode 100644 index 0000000000..02980d3201 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/register.metal @@ -0,0 +1,3 @@ +#pragma once +#include "tile/tile.metal" +#include "vec/vec.metal" diff --git a/extra/thunder/metal/include/ops/warp/register/tile/conversions.metal b/extra/thunder/metal/include/ops/warp/register/tile/conversions.metal new file mode 100644 index 0000000000..aabe59cc5a --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/tile/conversions.metal @@ -0,0 +1,313 @@ +/** + * @file + * @brief Conversions between data layouts and types for register tiles. + */ + +#pragma once // not done: +/* + swaping register layout doesn't exist. no layout to swap + SUBTILE + + */ +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { +/* ---------- TRANSPOSE ---------- */ +METAL_FUNC int compute_laneid(ushort y, ushort x) { + // Extract bits from simd_y + ushort b1 = y & 1; + ushort temp_y = y >> 1; + ushort b2 = temp_y & 1; + ushort b4 = temp_y >> 1; + + // Extract bits from simd_x + ushort b0 = (x >> 1) & 1; + ushort b3 = x >> 2; + + // Reconstruct laneid + ushort laneid = (b4 << 4) | (b3 << 3) | (b2 << 2) | (b1 << 1) | b0; + return laneid; +} +/** + * @brief Transposes a register base tile. + * + * @tparam T2 The data type of the register tile elements. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the register tile in which to store the transposed src. + * @param src[in] Reference to the register base tile to be transposed. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +swap_layout(thread rt_base::type> &dst, + thread const rt_base &src, + const ushort laneid) { + const ushort qid = laneid / 4; + const ushort simd_y = (qid & 4) + (laneid / 2) % 4; + const ushort simd_x = (qid & 2) * 2 + (laneid % 2) * 2; + + const ushort src_laneid_start = compute_laneid(simd_x, simd_y); + const ushort2 src_laneid = ushort2(src_laneid_start, src_laneid_start+(ushort)2); + const ushort first_idx = (laneid / 2) % 2; + + dst.data.thread_elements()[first_idx] = shfl_sync(src.data.thread_elements()[first_idx], src_laneid[first_idx]); + + dst.data.thread_elements()[1 - first_idx] = shfl_sync(src.data.thread_elements()[1 - first_idx], src_laneid[1 - first_idx]); +} + +/** + * @brief Swaps the layout of a register tile. + * + * This function swaps the layout of a register tile by iterating over its height and width + * and performing layout swaps on each of its base elements. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the register tile. + * @tparam _width The width of the register tile. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the destination register tile where the result will be stored. + * @param src[in] Reference to the source register tile to be swapped. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +swap_layout(thread rt::type> &dst, thread const rt &src, const short laneid) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + swap_layout(dst.tiles[i][j], src.tiles[i][j], laneid); + } + } +} + +/** + * @brief Swaps the layout of a register base tile in place. + * + * This function swaps the layout of a register base tile in place by casting it to the + * transposed layout type and then performing the layout swap. + * + * @tparam T2 The data type of the register tile elements. + * @tparam layout The current layout of the register tile. + * @param src[in] Reference to the register base tile to be swapped in place. + * @return A reference to the swapped register base tile. + */ +template +static METAL_FUNC typename metal::enable_if(), thread rt_base::type>&>::type +swap_layout_inplace(thread const rt_base &src) { + thread rt_base::type> &dst = *(thread rt_base::type>*)(&src); + swap_layout(dst, src); + return dst; +} + +/* ---------- TRANSPOSE ---------- */ + +/** + * @brief Transposes a register base tile. + * + * @tparam T2 The data type of the register tile elements. + * @tparam layout The current layout of the register tile. + * @param dst[out] Reference to the register tile in which to store the transposed src. + * @param src[in] Reference to the register base tile to be transposed. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +transpose(thread rt_base &dst, thread const rt_base &src, const ushort laneid) { + const ushort qid = laneid / 4; + const ushort simd_y = (qid & 4) + (laneid / 2) % 4; + const ushort simd_x = (qid & 2) * 2 + (laneid % 2) * 2; + + const ushort src_laneid_start = compute_laneid(simd_x, simd_y); + const ushort2 src_laneid = ushort2(src_laneid_start, src_laneid_start+(ushort)2); + const ushort first_idx = (laneid / 2) % 2; + + dst.data.thread_elements()[first_idx] = shfl_sync(src.data.thread_elements()[first_idx], src_laneid[first_idx]); + + dst.data.thread_elements()[1 - first_idx] = shfl_sync(src.data.thread_elements()[1 - first_idx], src_laneid[1 - first_idx]); +} +/** + * @brief Transposes a register tile. + * + * This function is marked "sep", which means that the registers underlying dst MUST be separate + * from the registers underlying src. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height of the src register tile, and the width of the dst tile. + * @tparam _width The width of the src register tile, and the height of the dst tile. + * @tparam layout The layout of the register tile. + * @param dst[out] Reference to the register tile in which to store the transposed src. + * @param src[in] Reference to the register tile to be transposed. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +transpose_sep(thread RT &dst, thread const rt &src, + const int laneid) { + #pragma clang loop unroll(full) + for(int i = 0; i < RT::height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < RT::width; j++) { + transpose(dst.tiles[i][j], src.tiles[j][i], laneid); + } + } +} + +/** + * @brief Transposes a register base tile in-place. + * + * @tparam T2 The data type of the register base tile elements. + * @tparam layout The current layout of the register base tile. + * @param src[in] Reference to the register tile to be transposed. + * @return A reference to the transposed register base tile. + */ +template +static METAL_FUNC typename metal::enable_if(), thread rt_base&>::type +transpose_inplace(thread rt_base &src, const ushort laneid) { + transpose(src, src, laneid); + return src; +} + +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(thread rt_base &dst, thread const rt_base &src); + +/** + * @brief Transposes a square register tile in-place. + * + * @tparam T2 The data type of the register tile elements. + * @tparam _height The height (in units of 16) of the src register tile, and the width of the dst tile. (Must be the same as _width.) + * @tparam _width The width (in units of 16) of the src register tile, and the height of the dst tile. (Must be the same as _height.) + * @tparam layout The current layout of the register tile. + * @param src[in] Reference to the register tile to be transposed. + * @return A reference to the transposed register tile. + */ +template +static METAL_FUNC typename metal::enable_if() && RT::cols == RT::rows, thread RT&>::type +transpose_inplace(thread RT &tile, const ushort laneid) { + #pragma clang loop unroll(full) + for(int i = 0; i < tile.height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < i; j++) { + rt_base tmp; + copy(tmp, tile.tiles[i][j]); + transpose(tile.tiles[i][j], tile.tiles[j][i], laneid); + transpose(tile.tiles[j][i], tmp, laneid); + } + transpose_inplace(tile.tiles[i][i], laneid); + } + return tile; +} +/* ---------- TYPE SWAPS ---------- */ +/** + * @brief Copies a register base tile, converting the underlying type if necessary. + * + * @tparam T2 The data type of the destination register elements. + * @tparam U2 The data type of the source register elements. + * @tparam layout The current layout of the register base tile. + * @param[out] dst A reference to the destination register base tile. + * @param[in] src A reference to the source register base tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(thread rt_base &dst, thread const rt_base &src) { + using T1 = typename base_types::packing::unpacked_type; + using U1 = typename base_types::packing::unpacked_type; + dst.data.thread_elements()[0] = base_types::convertor::convert(src.data.thread_elements()[0]); + dst.data.thread_elements()[1] = base_types::convertor::convert(src.data.thread_elements()[1]); +} + +/** + * @brief Copies a register tile, converting the underlying type if necessary. + * + * @tparam T2 The data type of the destination register elements. + * @tparam U2 The data type of the source register elements. + * @tparam _height The height (in units of 8) of the register tiles. + * @tparam _width The width (in units of 8) of the register tiles. + * @tparam layout The current layout of the register tile. + * @param[out] dst A reference to the destination register tile. + * @param[in] src A reference to the source register tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(thread rt &dst, thread const rt &src) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + copy(dst.tiles[i][j], src.tiles[i][j]); + } + } +} + +/* ---------- CAUSAL ---------- */ + +/** + * @brief Makes a square register tile causal by zeroing elements above the main diagonal. + * + * This function modifies a square register tile in-place to make it causal. All elements + * above the main diagonal are set to zero, while elements on or below the main diagonal + * are left unchanged. + * + * @tparam T The data type of the register tile elements. + * @tparam _size The size (height and width) of the square register tile. + * @tparam layout The current layout of the register tile. + * @param tile[in,out] Reference to the register tile to be made causal. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +make_causal(thread RT &dst, thread const RT &src, const unsigned laneid, thread const typename base_types::packing::unpacked_type &val=0) { + ducks::assert_register_tile(); + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + if(j < i) { // below the diagonal, copy + dst.tiles[i][j].data.thread_elements()[0] = src.tiles[i][j].data.thread_elements()[0]; + dst.tiles[i][j].data.thread_elements()[1] = src.tiles[i][j].data.thread_elements()[1]; + } + else if(j > i) { // above the diagonal, zero + dst.tiles[i][j].data.thread_elements()[0] = val; + dst.tiles[i][j].data.thread_elements()[1] = val; + } + else { // on the diagonal + constexpr uint32_t MASK_0 = (ducks::is_row_register_tile()) ? 0x0A00FF0A : 0xD4FF00D4; + constexpr uint32_t MASK_1 = (ducks::is_row_register_tile()) ? 0x2B00FF2B : 0x50FF0050; + if((MASK_0 >> laneid) & 1) { + dst.tiles[i][j].data.thread_elements()[0] = val; + } + else { + dst.tiles[i][j].data.thread_elements()[0] = src.tiles[i][j].data.thread_elements()[0]; + } + if((MASK_1 >> laneid) & 1) { + dst.tiles[i][j].data.thread_elements()[1] = val; + } + else { + dst.tiles[i][j].data.thread_elements()[1] = src.tiles[i][j].data.thread_elements()[1]; + } + } + } + } +} + + + +/* ---------- SUBTILE ---------- */ + +/** +* @brief Returns a reference to a subtile of the given tile. +* +* @tparam subtile_height The height of the subtile. +* @tparam RT The type of the input tile, which must satisfy the ducks::rt::all concept. +* @param src The input tile. +* @param idx The index of the subtile. +* @return A reference to the subtile. +* +* @note The subtile height must evenly divide the tile height. +*/ +//template +//__device__ inline rt &subtile_inplace(RT & src, int idx) { +// static_assert(RT::height % subtile_height == 0, "subtile height should evenly divide tile height."); +// return reinterpret_cast&>( +// src.tiles[idx*subtile_height] +// ); +//} + +} diff --git a/extra/thunder/metal/include/ops/warp/register/tile/maps.metal b/extra/thunder/metal/include/ops/warp/register/tile/maps.metal new file mode 100644 index 0000000000..12439b2295 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/tile/maps.metal @@ -0,0 +1,878 @@ +#pragma once // doneington but add register tile col +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { +/* ---------- Uniform tile maps (independent of layout) ---------- */ + +namespace meta { +template +static METAL_FUNC typename metal::enable_if(), void>::type +unary_map_unroll(int i, int j, thread RT *dst, thread const RT *src) { + using T2 = typename RT::T2; + T2 vals = op::template op(T2{src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}); + dst->tiles[i][j].data.thread_elements()[0] = vals[0]; + dst->tiles[i][j].data.thread_elements()[1] = vals[1]; +} +} +/** + * @brief Applies a unary operation to each element of a tile. + * + * @tparam op Unary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +unary_map(thread RT &dst, thread const RT &src) { + using T = typename RT::T; + ducks::assert_register_tile(); + using T2 = typename RT::T2; + using T4 = typename base_types::packing::packed_four; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// T2 op2 = op::template op(T2{src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}); +//// dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0]); +//// dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1]); +// +// dst.tiles[i][j].data.thread_elements()[0] = op2[0]; +// dst.tiles[i][j].data.thread_elements()[1] = op2[1]; +// +//// dst.tiles[i][j].data.thread_elements()[0] = base_ops::abs::template op(src.tiles[i][j].data.thread_elements()[0]); +//// dst.tiles[i][j].data.thread_elements()[1] = base_ops::abs::template op(src.tiles[i][j].data.thread_elements()[1]); +//// dst.tiles[i][j].data.thread_elements()[0] = (T)(metal::abs(-1.f)); +//// dst.tiles[i][j].data.thread_elements()[1] = (T)(metal::abs(-1.f)); +// +//// ((T)(((float)src.tiles[i][j].data.thread_elements()[0]))); +//// dst.tiles[i][j].data.thread_elements()[1] = metal::abs((T)((float)src.tiles[i][j].data.thread_elements()[1])); +// +//// dst.tiles[i][j].data.thread_elements()[0] = base_types::constants::one(); +//// dst.tiles[i][j].data.thread_elements()[1] = base_types::constants::one(); +//// metal::simdgroup_barrier(metal::mem_flags::mem_none); +// +////// T2 val = op::template op(T2{src.tiles[i][j].data.thread_elements()[0], +////// src.tiles[i][j].data.thread_elements()[1]}); +////// dst.tiles[i][j].data.thread_elements()[0] = val[0]; +////// dst.tiles[i][j].data.thread_elements()[1] = val[1]; +//////// +////// T4 val = op::template op(T4{src.tiles[i][j].data.thread_elements()[0], +////// src.tiles[i][j].data.thread_elements()[1], +////// src.tiles[i][j+1].data.thread_elements()[0], +////// src.tiles[i][j+1].data.thread_elements()[1],}); +////// dst.tiles[i][j].data.thread_elements()[0] = val[0]; +////// dst.tiles[i][j].data.thread_elements()[1] = val[1]; +////// dst.tiles[i][j+1].data.thread_elements()[0] = val[2]; +////// dst.tiles[i][j+1].data.thread_elements()[1] = val[3]; +// } +// } + + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::unary_map_unroll, &dst, &src); +} + + +namespace meta { +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_map_unroll(int i, int j, thread RT *dst, thread const RT *src, thread const typename RT::dtype *param) { + using T = typename RT::T; + using T2 = typename RT::T2; +// T2 vals = op::template op({src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}, {*param, *param}); +// dst->tiles[i][j].data.thread_elements()[0] = vals[0]; +// dst->tiles[i][j].data.thread_elements()[1] = vals[1]; + dst->tiles[i][j].data.thread_elements()[0] = op::template op(src->tiles[i][j].data.thread_elements()[0], *param); + dst->tiles[i][j].data.thread_elements()[1] = op::template op(src->tiles[i][j].data.thread_elements()[1], *param); +} +} +/** + * @brief Applies a binary operation to each element of a tile with a scalar parameter. + * + * @tparam op Binary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param param[in] Scalar parameter for the binary operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_map(thread RT &dst, thread const RT &src, thread const typename RT::dtype ¶m) { +// using T = typename RT::T; +// using T2 = typename RT::T2; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// T2 vals = op::template op({src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}, {param, param}); +// dst.tiles[i][j].data.thread_elements()[0] = vals[0]; +// dst.tiles[i][j].data.thread_elements()[1] = vals[1]; +//// dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], param); +//// dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], param); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::bin_map_unroll, &dst, &src, ¶m); +} + +namespace meta { +template +static METAL_FUNC typename metal::enable_if(), void>::type +binary_map_unroll(int i, int j, thread RT *dst, thread const RT *lhs, thread const RT *rhs) { + using T2 = typename RT::T2; + using T4 = typename base_types::packing::packed_four; + dst->tiles[i][j].data.thread_elements()[0] = op::template op(lhs->tiles[i][j].data.thread_elements()[0], + rhs->tiles[i][j].data.thread_elements()[0]); + dst->tiles[i][j].data.thread_elements()[1] = op::template op(lhs->tiles[i][j].data.thread_elements()[1], + rhs->tiles[i][j].data.thread_elements()[1]); +// T2 vals = op::template op({lhs->tiles[i][j].data.thread_elements()[0], lhs->tiles[i][j].data.thread_elements()[1]}, +// {rhs->tiles[i][j].data.thread_elements()[0], rhs->tiles[i][j].data.thread_elements()[1]}); +//// +// dst->tiles[i][j].data.thread_elements()[0] = vals[0]; +// dst->tiles[i][j].data.thread_elements()[1] = vals[1]; + +// dst->tiles[i][j].data.thread_elements()[0] = op::template op(lhs->tiles[i][j].data.thread_elements()[0], +// rhs->tiles[i][j].data.thread_elements()[0]); +// dst->tiles[i][j].data.thread_elements()[1] = op::template op(lhs->tiles[i][j].data.thread_elements()[1], +// rhs->tiles[i][j].data.thread_elements()[1]); +// T4 val = op::template op(T4{src->tiles[i][j].data.thread_elements()[0], +// src->tiles[i][j].data.thread_elements()[1], +// src->tiles[i][j+1].data.thread_elements()[0], +// src->tiles[i][j+1].data.thread_elements()[1]}); +// dst->tiles[i][j].data.thread_elements()[0] = val[0]; +// dst->tiles[i][j].data.thread_elements()[1] = val[1]; +// dst->tiles[i][j+1].data.thread_elements()[0] = val[2]; +// dst->tiles[i][j+1].data.thread_elements()[1] = val[3]; +} +} +/** + * @brief Applies a binary operation element-wise between two tiles. + * + * @tparam op Binary operation to apply. + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the operation. + * @param rhs[in] Right-hand side source tile for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_map(thread RT &dst, thread const RT &lhs, thread const RT &rhs) { + using T = typename RT::dtype; + using T2 = typename base_types::packing::packed_type; +// #pragma clang loop unroll(full) +// for(int i = 0; i < dst.height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < dst.width; j++) { +// dst.tiles[i][j].data.thread_elements()[0] = op::template op(lhs.tiles[i][j].data.thread_elements()[0], +// rhs.tiles[i][j].data.thread_elements()[0]); +// dst.tiles[i][j].data.thread_elements()[1] = op::template op(lhs.tiles[i][j].data.thread_elements()[1], +// rhs.tiles[i][j].data.thread_elements()[1]); +// dst.tiles[i][j].data.thread_elements()[0] = lhs.tiles[i][j].data.thread_elements()[0] + rhs.tiles[i][j].data.thread_elements()[0]; +// dst.tiles[i][j].data.thread_elements()[1] = lhs.tiles[i][j].data.thread_elements()[1] + rhs.tiles[i][j].data.thread_elements()[1]; +//// +// T2 vals = op::template op(T2(lhs.tiles[i][j].data.thread_elements()[0], lhs.tiles[i][j].data.thread_elements()[1]), +// T2(rhs.tiles[i][j].data.thread_elements()[0], rhs.tiles[i][j].data.thread_elements()[1])); +// dst.tiles[i][j].data.thread_elements()[0] = vals[0]; +// dst.tiles[i][j].data.thread_elements()[1] = vals[1]; +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::binary_map_unroll, &dst, &lhs, &rhs); +} + +/* ---------- Row tile maps ----------*/ + +namespace meta { +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_map_unroll(int i, int j, thread RT *dst, thread const RT *src, thread const RV *row_values) { + using T2 = typename RT::T2; + T2 val = op::template op({src->tiles[i][j].data.thread_elements()[0], src->tiles[i][j].data.thread_elements()[1]}, {(*row_values)[i][0], (*row_values)[i][0]}); + dst->tiles[i][j].data.thread_elements()[0] = val[0]; + dst->tiles[i][j].data.thread_elements()[1] = val[1]; +} + +} +/** + * @brief Applies an operation across the rows of a tile in a row-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_map(thread RT &dst, thread const RT &src, thread const RV &row_values) { + static_assert(ducks::is_ortho_layout(), "RV must be otho layout (col vec for row rt)"); + static_assert(metal::is_same_v, "rt and rv must be of same type"); // compatible type + static_assert(RV::outer_dim == RT::height, "RV outer dim and RT height do not match"); // compatible size + using T4 = typename base_types::packing::packed_four; + using T2 = typename RT::T2; + using T = typename RT::dtype; + + +// #pragma clang loop unroll(full) +// for(int i = 0; i < RT::height; i++) { +// T row_val = row_values[i][0]; +// #pragma clang loop unroll(full) +// for(int j = 0; j < RT::width; j++) { +// T2 val = op::template op({src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}, {row_val, row_val}); +// dst.tiles[i][j].data.thread_elements()[0] = val[0]; +// dst.tiles[i][j].data.thread_elements()[1] = val[1]; +//// dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], row_values[i][0]); +//// dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], row_values[i][0]); +// } +// } + meta::unroll_i_j_in_range<0, RT::height, 1, 0, RT::width, 1>::run(meta::row_map_unroll, &dst, &src, &row_values); + + +// meta::unroll_i_j_in_range<0, RT::height, 1, +// 0, (RT::width / 2) * 2, 2>::run(meta::row_map_unroll, &dst, &src, &row_values); +// meta::unroll_i_j_in_range<0, (RT::height / 2) * 2, 2, +// (RT::width / 2) * 2, RT::width, 1>::run(meta::row_map_unroll, &dst, &src, &row_values); +// +// meta::unroll_i_j_in_range<(RT::height / 2) * 2, RT::height, 1, +// (RT::width / 2) * 2, RT::width, 1>::run(meta::row_map_unroll, &dst, &src, &row_values); +} + +/** + * @brief Applies an operation across the rows of a tile in a row-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_map(thread RT &dst, thread const RT &src, thread const RV &row_values) { + static_assert(ducks::is_align_layout(), "RV must be align layout (col vec for col rt)"); + static_assert(metal::is_same_v, "rt and rv must be of same type"); // compatible type + static_assert(RV::outer_dim == RT::height, "RV outer dim and RT height do not match"); // compatible size + using T4 = typename base_types::packing::packed_four; + using T2 = typename RT::T2; + using T = typename RT::dtype; + + + #pragma clang loop unroll(full) + for(int i = 0; i < RT::height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < RT::width; j++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], row_values[i][0]); + dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], row_values[i][1]); + } + } +// +// meta::unroll_i_j_in_range<0, RT::height, 1, +// 0, (RT::width / 2) * 2, 2>::run(meta::row_map_unroll, &dst, &src, &row_values); +// meta::unroll_i_j_in_range<0, (RT::height / 2) * 2, 2, +// (RT::width / 2) * 2, RT::width, 1>::run(meta::row_map_unroll, &dst, &src, &row_values); +// +// meta::unroll_i_j_in_range<(RT::height / 2) * 2, RT::height, 1, +// (RT::width / 2) * 2, RT::width, 1>::run(meta::row_map_unroll, &dst, &src, &row_values); +} + +// Three-operand row map. Mostly useful for FMA instructions. + +/** + * @brief Applies an operation across the rows of two tiles in a row-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_map(thread RT &dst, thread const RT &a, thread const RT &b, thread const RV &row_values) { + static_assert(ducks::is_ortho_layout(), "rv must be ortho layout for row rt"); + static_assert(metal::is_same_v, "rt and rv must be same type"); // compatible type + static_assert(RV::outer_dim == RT::height, "rv and rt dimensions don't match"); // compatible size + + + using dtype = typename RT::dtype; + + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + dtype vec_val = row_values[i][0]; + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(a.tiles[i][j].data.thread_elements()[0], b.tiles[i][j].data.thread_elements()[0], vec_val); + + dst.tiles[i][j].data.thread_elements()[1] = op::template op(a.tiles[i][j].data.thread_elements()[1], b.tiles[i][j].data.thread_elements()[1], vec_val); + } + } +} + +/** + * @brief Applies an operation across the rows of two tiles in a column-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with column-major layout. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param row_values[in] Column vector containing values to apply across each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_map(thread RT &dst, thread const RT &a, thread const RT &b, thread const RV &row_values) { + static_assert(ducks::is_align_layout(), "rv must be align layout for row rt"); + static_assert(metal::is_same_v, "rt and rv must be same type"); // compatible type + static_assert(RV::outer_dim == RT::height, "rv and rt dimensions don't match"); // compatible size + + + using dtype = typename RT::dtype; + + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(a.tiles[i][j].data.thread_elements()[0], b.tiles[i][j].data.thread_elements()[0], row_values[i][0]); + + dst.tiles[i][j].data.thread_elements()[1] = op::template op(a.tiles[i][j].data.thread_elements()[1], b.tiles[i][j].data.thread_elements()[1], row_values[i][1]); + } + } +} + +/* ---------- Col major tile maps ----------*/ + +/** + * @brief Applies an operation across the columns of a tile in a row-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_map(thread RT &dst, thread const RT &src, thread const RV &col_values) { + static_assert(ducks::is_align_layout(), "rv must be align layout for row rt"); // compatible type + static_assert(metal::is_same_v, "rv and rt must be of the same type"); // compatible type + static_assert(RV::outer_dim == RT::width, "rv and rt dimensions do not match"); // compatible size + + using dtype = typename RT::dtype; + + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], col_values[j][0]); + dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], col_values[j][1]); + } + } +} + +/** + * @brief Applies an operation across the columns of a tile in a col-major layout. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_map(thread RT &dst, thread const RT &src, thread const RV &col_values) { + static_assert(ducks::is_ortho_layout(), "rv must be ortho layout for row rt"); // compatible type + static_assert(metal::is_same_v, "rv and rt must be of the same type"); // compatible type + static_assert(RV::outer_dim == RT::width, "rv and rt dimensions do not match"); // compatible size + + using dtype = typename RT::dtype; + + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], col_values[j][0]); + dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], col_values[j][0]); + } + } +} + +// Three-operand col map +/** + * @brief Applies an operation across the columns of two tiles in a row-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_map(thread RT &dst, thread const RT &a, thread const RT &b, thread const RV &col_values) { + static_assert(ducks::is_align_layout(), "rv must be align layout"); + static_assert(metal::is_same_v, "rv and rt must be of the same type"); // compatible type + static_assert(RV::outer_dim == RT::width, "rv and rt dims don't match"); // compatible size + + + using dtype = typename RT::dtype; + + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(a.tiles[i][j].data.thread_elements()[0], b.tiles[i][j].data.thread_elements()[0], col_values[j][0]); + dst.tiles[i][j].data.thread_elements()[1] = op::template op(a.tiles[i][j].data.thread_elements()[1], b.tiles[i][j].data.thread_elements()[1], col_values[j][1]); + } + } +} + +/** + * @brief Applies an operation across the columns of two tiles in a row-major layout, using a third operand. + * + * @tparam op Operation to apply. + * @tparam T Tile type with row-major layout. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param a[in] First source tile to apply the operation on. + * @param b[in] Second source tile to apply the operation on. + * @param col_values[in] Row vector containing values to apply across each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_map(thread RT &dst, thread const RT &a, thread const RT &b, thread const RV &col_values) { + static_assert(ducks::is_ortho_layout(), "rv must be ortho layout"); + static_assert(metal::is_same_v, "rv and rt must be of the same type"); // compatible type + static_assert(RV::outer_dim == RT::width, "rv and rt dims don't match"); // compatible size + + + using dtype = typename RT::dtype; + + #pragma clang loop unroll(full) + for(int j = 0; j < dst.width; j++) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.height; i++) { + dst.tiles[i][j].data.thread_elements()[0] = op::template op(a.tiles[i][j].data.thread_elements()[0], b.tiles[i][j].data.thread_elements()[0], col_values[j][0]); + dst.tiles[i][j].data.thread_elements()[1] = op::template op(a.tiles[i][j].data.thread_elements()[1], b.tiles[i][j].data.thread_elements()[1], col_values[j][0]); + } + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// All of the annoying qualifiers *should* be automatically inferred during compile-time. +// So, syntax should just be mittens::add_row(tile, colvec); + +/** + * @brief Sets all elements of a tile to zero. + * + * @tparam RT Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +zero(thread RT &dst) { + unary_map(dst, dst); +} +/** + * @brief Sets all elements of a tile to one. + * + * @tparam RT Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +one(thread RT &dst) { + unary_map(dst, dst); +} +/** + * @brief Sets all elements of a tile to positive infinity. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +pos_infty(thread RT &dst) { + unary_map(dst, dst); +} +/** + * @brief Sets all elements of a tile to negative infinity. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +neg_infty(thread RT &dst) { + unary_map(dst, dst); +} + +/** + * @brief Applies the exponential function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the exponential function on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp(thread RT &dst, thread const RT &src) { + unary_map(dst, src); +} +/** + * @brief Applies the exponential function to each element of a tile, in base 2. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the exponential function on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp2(thread RT &dst, thread const RT &src) { + unary_map(dst, src); +} +/** + * @brief Applies the natural logarithm function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the natural logarithm function on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +log(thread RT &dst, thread const RT &src) { + unary_map(dst, src); +} +/** + * @brief Applies the absolute value function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the absolute value function on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +abs(thread RT &dst, thread const RT &src) { + unary_map(dst, src); +} +/** + * @brief Applies the rectified linear unit (ReLU) function to each element of a tile. + * + * @tparam T Tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the ReLU function on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +relu(thread RT &dst, thread const RT &src) { + unary_map(dst, src); +} +/** + * @brief Copies the elements from one tile to another. + * + * @tparam T Destination tile type. + * @tparam U Source tile type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to copy from. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(thread RT &dst, thread const U &src) { + bin_map(dst, dst, src); +} + +/** + * @brief Applies the max operation element-wise between two tiles or a tile and a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the operation. + * @param rhs[in] Right-hand side source tile or scalar for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(thread RT &dst, thread const RT &lhs, thread const U &rhs) { + bin_map(dst, lhs, rhs); +} +/** + * @brief Applies the min operation element-wise between two tiles or a tile and a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the operation. + * @param rhs[in] Right-hand side source tile or scalar for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(thread RT &dst, thread const RT &lhs, thread const U &rhs) { + bin_map(dst, lhs, rhs); +} +/** + * @brief Adds two tiles element-wise or adds a scalar to each element of a tile. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the addition. + * @param rhs[in] Right-hand side source tile or scalar for the addition. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +add(thread RT &dst, thread const RT &lhs, thread const U &rhs) { + bin_map(dst, lhs, rhs); +} +/** + * @brief Subtracts two tiles element-wise or subtracts a scalar from each element of a tile. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the subtraction. + * @param rhs[in] Right-hand side source tile or scalar for the subtraction. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sub(thread RT &dst, const thread RT &lhs, thread const U &rhs) { + bin_map(dst, lhs, rhs); +} +/** + * @brief Multiplies two tiles element-wise or multiplies each element of a tile by a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the multiplication. + * @param rhs[in] Right-hand side source tile or scalar for the multiplication. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +mul(thread RT &dst, thread const RT &lhs, thread const U &rhs) { + bin_map(dst, lhs, rhs); +} +/** + * @brief Divides two tiles element-wise or divides each element of a tile by a scalar. + * + * @tparam T Tile type. + * @tparam U Second operand type, which can be a tile or a scalar. + * @param dst[out] Destination tile where the result is stored. + * @param lhs[in] Left-hand side source tile for the division. + * @param rhs[in] Right-hand side source tile or scalar for the division. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +div(thread RT &dst, thread const RT &lhs, thread const U &rhs) { + bin_map(dst, lhs, rhs); +} + +/** + * @brief Adds row values to each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param row_values[in] Column vector containing values to add to each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +add_row(thread RT &dst, thread const RT &src, thread const RV &row_values) { + row_map(dst, src, row_values); +} +/** + * @brief Subtracts row values from each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param row_values[in] Column vector containing values to subtract from each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +sub_row(thread RT &dst, thread const RT &src, thread const RV &row_values) { + row_map(dst, src, row_values); +// using T4 = typename base_types::packing::packed_four; +// #pragma clang loop unroll(full) +// for(int i = 0; i < RT::height; i++) { +// // #pragma clang loop unroll(full) +// // for(int j = 0; j < RT::width; j+=2) { +// // T4 val = op::template op({src.tiles[i][j].data.thread_elements()[0], +// // src.tiles[i][j].data.thread_elements()[1], +// // src.tiles[i][j+1].data.thread_elements()[0], +// // src.tiles[i][j+1].data.thread_elements()[1],}, +// // {row_values[i][0], row_values[i][0],row_values[i][0], row_values[i][0]}); +// // +// // dst.tiles[i][j].data.thread_elements()[0] = val[0]; +// // dst.tiles[i][j].data.thread_elements()[1] = val[1]; +// // dst.tiles[i][j+1].data.thread_elements()[0] = val[2]; +// // dst.tiles[i][j+1].data.thread_elements()[1] = val[3]; +// // } +// +// // #pragma clang loop unroll(full) +// // for(int j = 0; j < RT::width; j++) { +// // T2 val = op::template op({src.tiles[i][j].data.thread_elements()[0], +// // src.tiles[i][j].data.thread_elements()[1]}, +// // {row_values[i][0], row_values[i][0]}); +// // +// // dst.tiles[i][j].data.thread_elements()[0] = val[0]; +// // dst.tiles[i][j].data.thread_elements()[1] = val[1]; +// // } +// #pragma clang loop unroll(full) +// for(int j = 0; j < RT::width; j+=2) { +// T4 val = T4(src.tiles[i][j].data.thread_elements()[0], +// src.tiles[i][j].data.thread_elements()[1], +// src.tiles[i][j+1].data.thread_elements()[0], +// src.tiles[i][j+1].data.thread_elements()[1]) - T4(row_values[i][0], row_values[i][0], row_values[i][0], row_values[i][0]); +// dst.tiles[i][j].data.thread_elements()[0] = val[0]; +// dst.tiles[i][j].data.thread_elements()[1] = val[1]; +// dst.tiles[i][j+1].data.thread_elements()[0] = val[2]; +// dst.tiles[i][j+1].data.thread_elements()[1] = val[3]; +// } +// } +} +/** + * @brief Multiplies each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param row_values[in] Column vector containing values to multiply each row by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +mul_row(thread RT &dst, thread const RT &src, thread const RV &row_values) { +// using T = typename RT::T; +// using T2 = typename RT::T2; +// #pragma clang loop unroll(full) +// for(int i = 0; i < RT::height; i++) { +// #pragma clang loop unroll(full) +// for(int j = 0; j < RT::width; j++) { +//// T s1 = src.tiles[i][j].data.thread_elements()[0]; +//// T v1 = row_values[i][0]; +//// dst.tiles[i][j].data.thread_elements()[0] = s1 * v1; +//// T s2 = src.tiles[i][j].data.thread_elements()[1]; +//// T v2 = row_values[i][1]; +//// dst.tiles[i][j].data.thread_elements()[1] = s2 * v2; +// +// +//// dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], row_values[i][0]); +//// dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], row_values[i][0]); +// T2 val = op::template op({src.tiles[i][j].data.thread_elements()[0], row_values[i][0]); +// dst.tiles[i][j].data.thread_elements()[0] = op::template op(src.tiles[i][j].data.thread_elements()[0], row_values[i][0]); +// dst.tiles[i][j].data.thread_elements()[1] = op::template op(src.tiles[i][j].data.thread_elements()[1], row_values[i][0]); +// } +// } + row_map(dst, src, row_values); +} +/** + * @brief Divides each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param row_values[in] Column vector containing values to divide each row by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +div_row(thread RT &dst, thread const RT &src, thread const RV &row_values) { + row_map(dst, src, row_values); +} +/** + * @brief Broadcast a vector into into a tile's rows. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Column vector containing values to broadcast into rows. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +broadcast_row(thread RT &dst, thread const RV &row_values) { + row_map(dst, dst, row_values); +} + + +// col maps +/** + * @brief Adds column values to each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param col_values[in] Row vector containing values to add to each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +add_col(thread RT &dst, thread const RT &src, thread const RV &col_values) { + col_map(dst, src, col_values); +} +/** + * @brief Subtracts column values from each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param col_values[in] Row vector containing values to subtract from each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +sub_col(thread RT &dst, thread const RT &src, thread const RV &col_values) { + col_map(dst, src, col_values); +} +/** + * @brief Multiplies each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param col_values[in] Row vector containing values to multiply each column by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +mul_col(thread RT &dst, thread const RT &src, thread const RV &col_values) { + col_map(dst, src, col_values); +} +/** + * @brief Divides each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param col_values[in] Row vector containing values to divide each column by. + */ +template +static METAL_FUNC void div_col(thread RT &dst, thread const RT &src, thread const RV &col_values) { + col_map(dst, src, col_values); +} +/** + * @brief Broadcast a vector into into a tile's columns. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Row vector containing values to broadcast into cols. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +broadcast_col(thread RT &dst, thread const RV &col_values) { + col_map(dst, dst, col_values); +} + + +} diff --git a/extra/thunder/metal/include/ops/warp/register/tile/mma.metal b/extra/thunder/metal/include/ops/warp/register/tile/mma.metal new file mode 100644 index 0000000000..92d8c6bba6 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/tile/mma.metal @@ -0,0 +1,214 @@ +#pragma once // doneington + +#include +#include "../../../../types/types.metal" +#include "../../../../common/common.metal" +namespace mittens { + +template +METAL_FUNC static void mma_base(thread rt_base& d, + thread rt_base& a, + thread rt_base& b, + thread rt_base& c) { + metal::simdgroup_multiply_accumulate(d.data, a.data, b.data, c.data); +} + +template +METAL_FUNC static void mm_base(thread rt_base& d, + thread rt_base& a, + thread rt_base& b) { + metal::simdgroup_multiply(d.data, a.data, b.data); +} + +namespace meta { +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_AB_unroll_inner(int k, int n, int m, + thread rt* d, + thread rt* a, + thread rt* b) { + mma_base( + d->tiles[n][m], + a->tiles[n][k], + b->tiles[k][m], + d->tiles[n][m] + ); +} + + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_AB_unroll(int n, int m, + thread rt* d, + thread rt* a, + thread rt* b, + thread rt* c) { + mma_base( + d->tiles[n][m], + a->tiles[n][0], + b->tiles[0][m], + c->tiles[n][m] + ); + meta::unroll_i_in_range<1, K/TILE_DIM, 1>::run(meta::mma_AB_unroll_inner, n, m, d, a, b); +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mm_AB_unroll(int n, int m, + thread rt* d, + thread rt* a, + thread rt* b) { + mm_base( + d->tiles[n][m], + a->tiles[n][0], + b->tiles[0][m] + ); + meta::unroll_i_in_range<1, K/TILE_DIM, 1>::run(meta::mma_AB_unroll_inner, n, m, d, a, b); +} +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_AB(thread rt& d, + thread rt& a, + thread rt& b, + thread rt& c) { + meta::unroll_i_j_in_range<0, N/TILE_DIM, 1, 0, M/TILE_DIM, 1>::run(meta::mma_AB_unroll, &d, &a, &b, &c); +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mm_AB(thread rt& d, + thread rt& a, + thread rt& b) { + meta::unroll_i_j_in_range<0, N/TILE_DIM, 1, 0, M/TILE_DIM, 1>::run(meta::mm_AB_unroll, &d, &a, &b); +} + +namespace meta { +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_ABt_unroll_inner(int k, int n, int m, + thread rt* d, + thread rt* a, + thread rt* b) { + mma_base( + d->tiles[n][m], + a->tiles[n][k], + b->tiles[m][k], + d->tiles[n][m] + ); +} + + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_ABt_unroll(int n, int m, + thread rt* d, + thread rt* a, + thread rt* b, + thread rt* c) { + mma_base( + d->tiles[n][m], + a->tiles[n][0], + b->tiles[m][0], + c->tiles[n][m] + ); + meta::unroll_i_in_range<1, K/TILE_DIM, 1>::run(meta::mma_ABt_unroll_inner, n, m, d, a, b); +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mm_ABt_unroll(int n, int m, + thread rt* d, + thread rt* a, + thread rt* b) { + mm_base( + d->tiles[n][m], + a->tiles[n][0], + b->tiles[m][0] + ); + meta::unroll_i_in_range<1, K/TILE_DIM, 1>::run(meta::mma_ABt_unroll_inner, n, m, d, a, b); +} +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_ABt(thread rt& d, + thread rt& a, + thread rt& b, + thread rt& c) { + meta::unroll_i_j_in_range<0, N/TILE_DIM, 1, 0, M/TILE_DIM, 1>::run(meta::mma_ABt_unroll, &d, &a, &b, &c); +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mm_ABt(thread rt& d, + thread rt& a, + thread rt& b) { + meta::unroll_i_j_in_range<0, N/TILE_DIM, 1, 0, M/TILE_DIM, 1>::run(meta::mm_ABt_unroll, &d, &a, &b); +} + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_AtB(thread rt& d, + thread rt& a, + thread rt& b, + thread rt& c) { + #pragma clang loop unroll(full) + for (int n = 0; n < N / TILE_DIM; n++) { + #pragma clang loop unroll(full) + for (int m = 0; m < M / TILE_DIM; m++) { + mma_base( + d.tiles[n][m], + a.tiles[0][n], + b.tiles[0][m], + c.tiles[n][m] + ); + #pragma clang loop unroll(full) + for (int k = 1; k < K / TILE_DIM; k++) { + mma_base( + d.tiles[n][m], + a.tiles[k][n], + b.tiles[k][m], + d.tiles[n][m] + ); + } + } + } +} + + +template +static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type() && ducks::base_types::isT1Type(), void>::type +mma_AtBt(thread rt& d, + thread rt& a, + thread rt& b, + thread rt& c) { + #pragma clang loop unroll(full) + for (int n = 0; n < N / TILE_DIM; n++) { + #pragma clang loop unroll(full) + for (int m = 0; m < M / TILE_DIM; m++) { + mma_base( + d.tiles[n][m], + a.tiles[0][n], + b.tiles[m][0], + c.tiles[n][m] + ); + #pragma clang loop unroll(full) + for (int k = 1; k < K / TILE_DIM; k++) { + mma_base( + d.tiles[n][m], + a.tiles[k][n], + b.tiles[m][k], + d.tiles[n][m] + ); + } + } + } +} + + + +} diff --git a/extra/thunder/metal/include/ops/warp/register/tile/reductions.metal b/extra/thunder/metal/include/ops/warp/register/tile/reductions.metal new file mode 100644 index 0000000000..72f99b00f0 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/tile/reductions.metal @@ -0,0 +1,636 @@ +/** + * @file + * @brief Reduction operations mapping tiles to vectors. + */ + +#pragma once //doneington (but register col layotus) + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +namespace meta { + +//template +//static METAL_FUNC typename metal::enable_if(), void>::type +//row_reduce_unroll_inner(int i, thread const RT *src, thread typename RT::T& accum_thread) { +// accum_thread = op::template op(accum_thread, src->tiles[i][0].data.thread_elements()[0]); +// accum_thread = op::template op(accum_thread, src->tiles[i][0].data.thread_elements()[1]); +//} +// +//template +//static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +//row_reduce_unroll(int i, thread RV *row_accum, thread const RT *src, thread const RV *src_accum, const short leader) { +// using T = typename RV::T; +// T accum_thread = op::template op(src->tiles[i][0].data.thread_elements()[0], src->tiles[i][0].data.thread_elements()[1]); +// +// meta::unroll_i_in_range<1, RT::width, 1>::run(meta::row_reduce_unroll_inner, src, accum_thread); +// accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 1)); +// accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 8)); +// +// accum_thread = shfl_sync(accum_thread, leader); +// +// if(reset) { (*row_accum)[i][0] = accum_thread; } +// else { (*row_accum)[i][0] = op::template op((*src_accum)[i][0], accum_thread); } +//} + +//template +//static METAL_FUNC typename metal::enable_if(), void>::type +//row_reduce_unroll_inner(int i, thread const RT *src, thread typename RT::T2& accum_thread) { +// accum_thread = op::template op(accum_thread, {src->tiles[i][0].data.thread_elements()[0], src->tiles[i][0].data.thread_elements()[1]}); +//} + +/* + pragma clang loop unroll(full) + for(int i = 0; i < src.height; i++) { + T accum_thread = op::template op(src.tiles[i][0].data.thread_elements()[0], src.tiles[i][0].data.thread_elements()[1]); + #pragma clang loop unroll(full) + for(int j = 1; j < src.width; j++) { + accum_thread = op::template op(accum_thread, src.tiles[i][j].data.thread_elements()[0]); + accum_thread = op::template op(accum_thread, src.tiles[i][j].data.thread_elements()[1]); + } + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 1)); + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 8)); + + accum_thread = shfl_sync(accum_thread, leader); + + if(reset) { row_accum[i][0] = accum_thread; } + else { row_accum[i][0] = op::template op(src_accum[i][0], accum_thread); } + } + */ + +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_reduce_unroll(int i, thread RV *row_accum, thread const RT *src, thread const RV *src_accum, const short leader) { + using T = typename RV::T; + using T2 = typename RV::T2; + T accum_thread = op::template op(src->tiles[i][0].data.thread_elements()[0], src->tiles[i][0].data.thread_elements()[1]); + for(int j = 1; j < src->width; j++) { + accum_thread = op::template op(accum_thread, src->tiles[i][j].data.thread_elements()[0]); + accum_thread = op::template op(accum_thread, src->tiles[i][j].data.thread_elements()[1]); + } + + T shfl_val = shfl_down_sync(accum_thread, 1); + accum_thread = op::template op(accum_thread, shfl_val); + shfl_val = shfl_down_sync(accum_thread, 8); + accum_thread = op::template op(accum_thread, shfl_val); + + accum_thread = shfl_sync(accum_thread, leader); + + if(reset) { + (*row_accum)[i][0] = accum_thread; + } + else { + (*row_accum)[i][0] = op::template op((*src_accum)[i][0], accum_thread);; + } +} + + +} +/** + * @brief Perform a row-wise reduction on a matrix in row-major layout. + * + * This function template performs a parallel reduction across the rows of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type with row layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_reduce(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const short laneid) { + static_assert(ducks::is_ortho_layout(), "rv must be ortho for row RT"); + static_assert(metal::is_same_v, "rv and rt must be the same type"); // compatible type + static_assert(RV::outer_dim == RT::height, "rv and rt dims don't match"); // compatible size + using T = typename RV::T; + using T2 = typename RV::T2; + const short leader = (laneid / 16) * 16 + ((laneid / 2) % 4) * 2; + +// constexpr const uint32_t COL_0 = 0x00550055; +// constexpr const uint32_t COL_1 = 0x00AA00AA; +// constexpr const uint32_t COL_2 = 0x55005500; +// constexpr const uint32_t COL_3 = 0xAA00AA00; +// +// constexpr const uint32_t COL_0_2 = COL_0 | COL_2; +// constexpr const uint32_t COL_0_1 = COL_0 | COL_1; +// constexpr const uint32_t COL_2_3 = COL_2 | COL_3; +// const ushort src_lane1 = laneid + ((COL_0_2 >> laneid) & 1) * 1 + ((COL_1 >> laneid) & 1) * 7 - ((COL_3 >> laneid) & 1) * 9; +// const ushort src_lane2 = laneid + ((COL_0_1 >> laneid) & 1) * 8 - ((COL_2_3 >> laneid) & 1) * 8; +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// T accum_thread = op::template op(src.tiles[i][0].data.thread_elements()[0], src.tiles[i][0].data.thread_elements()[1]); +// #pragma clang loop unroll(full) +// for(int j = 1; j < src.width; j++) { +// accum_thread = op::template op(accum_thread, src.tiles[i][j].data.thread_elements()[0]); +// accum_thread = op::template op(accum_thread, src.tiles[i][j].data.thread_elements()[1]); +// } +// accum_thread = op::template op(accum_thread, shfl_sync(accum_thread, src_lane1)); +// accum_thread = op::template op(accum_thread, shfl_sync(accum_thread, src_lane2)); +// +// +// if(reset) { row_accum[i][0] = accum_thread; } +// else { row_accum[i][0] = op::template op(src_accum[i][0], accum_thread); } +// } + +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// T accum_thread = op::template op(src.tiles[i][0].data.thread_elements()[0], src.tiles[i][0].data.thread_elements()[1]); +// #pragma clang loop unroll(full) +// for(int j = 1; j < src.width; j++) { +// accum_thread = op::template op(accum_thread, src.tiles[i][j].data.thread_elements()[0]); +// accum_thread = op::template op(accum_thread, src.tiles[i][j].data.thread_elements()[1]); +// } +// accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 1)); +// accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 8)); +// +// accum_thread = shfl_sync(accum_thread, leader); +// +// if(reset) { row_accum[i][0] = accum_thread; } +// else { row_accum[i][0] = op::template op(src_accum[i][0], accum_thread); } +// } + + meta::unroll_i_in_range<0, RT::height, 1>::run(meta::row_reduce_unroll, &row_accum, &src, &src_accum, leader); +} + +/** + * @brief Perform a row-wise reduction on a matrix in row-major layout. + * + * This function template performs a parallel reduction across the rows of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type with row layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_reduce(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const short laneid) { + static_assert(ducks::is_align_layout(), "rv must be align for row RT"); + static_assert(metal::is_same_v, "rv and rt must be the same type"); // compatible type + static_assert(RV::outer_dim == RT::height, "rv and rt dims don't match"); // compatible size + + using T = typename RV::T; + using T2 = typename RV::T2; + + const int leader = (laneid % 2) + ((laneid / 8) % 2) * 8; + #pragma clang loop unroll(full) + for(int i = 0; i < src.height; i++) { + T2 accum_thread = {src.tiles[i][0].data.thread_elements()[0], src.tiles[i][0].data.thread_elements()[1]}; + #pragma clang loop unroll(full) + for(int j = 1; j < src.width; j++) { + accum_thread = op::template op(accum_thread, {src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}); + } + // Now we need to do a lil shuffle to make everyone happy. + + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 2)); + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 4)); + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 16)); + + accum_thread = shfl_sync(accum_thread, leader); + + if(reset) { + row_accum[i][0] = accum_thread[0]; + row_accum[i][1] = accum_thread[1]; + } + else { + row_accum[i][0] = op::template op(row_accum[i][0], accum_thread[0]); + row_accum[i][1] = op::template op(row_accum[i][1], accum_thread[1]); + } + } +} + + +/** + * @brief Perform a column-wise reduction on a matrix in row-major layout. + * + * This function template performs a parallel reduction across the columns of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication and is optimized for row-major matrices. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the column accumulator. + * @tparam T The matrix type with row layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_reduce(thread RV &col_accum, thread const RT &src, thread const RV &src_accum, const ushort laneid) { + static_assert(ducks::is_align_layout(), "rv must be align layout"); + static_assert(metal::is_same_v, "rt and rv must be same type"); // compatible type + static_assert(RV::outer_dim == RT::width, "rv and rt dims don't match"); // compatible size + + using dtype = typename RV::dtype; + using T2 = typename base_types::packing::packed_type; + + const int leader = (laneid % 2) + ((laneid / 8) % 2) * 8; + #pragma clang loop unroll(full) + for(int j = 0; j < src.width; j++) { +// dtype accum_left_cols = src.tiles[0][j].data.thread_elements()[0]; +// dtype accum_right_cols = src.tiles[0][j].data.thread_elements()[1]; + T2 accum_cols = {src.tiles[0][j].data.thread_elements()[0], src.tiles[0][j].data.thread_elements()[1]}; +// dtype accum_right_cols = src.tiles[0][j].data.thread_elements()[1]; + #pragma clang loop unroll(full) + for(int i = 1; i < src.height; i++) { +// accum_left_cols = op::template op(accum_left_cols , src.tiles[i][j].data.thread_elements()[0]); +// accum_right_cols = op::template op(accum_right_cols, src.tiles[i][j].data.thread_elements()[1]); + accum_cols = op::template op(accum_cols, {src.tiles[i][j].data.thread_elements()[0], src.tiles[i][j].data.thread_elements()[1]}); + } + +// accum_left_cols = op::template op(accum_left_cols, shfl_down_sync(accum_left_cols, 2)); +// accum_left_cols = op::template op(accum_left_cols, shfl_down_sync(accum_left_cols, 4)); +// accum_left_cols = op::template op(accum_left_cols, shfl_down_sync(accum_left_cols, 16)); + +// accum_right_cols = op::template op(accum_right_cols, shfl_down_sync(accum_right_cols, 2)); +// accum_right_cols = op::template op(accum_right_cols, shfl_down_sync(accum_right_cols, 4)); +// accum_right_cols = op::template op(accum_right_cols, shfl_down_sync(accum_right_cols, 16)); + accum_cols = op::template op(accum_cols, shfl_down_sync(accum_cols, 2)); + accum_cols = op::template op(accum_cols, shfl_down_sync(accum_cols, 4)); + accum_cols = op::template op(accum_cols, shfl_down_sync(accum_cols, 16)); + +// accum_left_cols = shfl_sync(accum_left_cols, leader); +// accum_right_cols = shfl_sync(accum_right_cols, leader); + accum_cols = shfl_sync(accum_cols, leader); + + + if(reset) { +// col_accum[j][0] = accum_left_cols; +// col_accum[j][1] = accum_right_cols; + col_accum[j][0] = accum_cols[0]; + col_accum[j][1] = accum_cols[1]; + } + else { +// col_accum[j][0] = op::template op(src_accum[j][0], accum_left_cols); +// col_accum[j][1] = op::template op(src_accum[j][1], accum_right_cols); + col_accum[j][0] = op::template op(src_accum[j][0], accum_cols[0]); + col_accum[j][1] = op::template op(src_accum[j][1], accum_cols[1]); + } + } +} + +/** + * @brief Perform a column-wise reduction on a matrix in row-major layout. + * + * This function template performs a parallel reduction across the columns of a matrix using a specified operation. + * It leverages warp shuffle functions for efficient intra-warp communication and is optimized for row-major matrices. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The vector type for the column accumulator. + * @tparam T The matrix type with row layout. + * @tparam reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when reset is false. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_reduce(thread RV &col_accum, thread const RT &src, thread const RV &src_accum, const ushort laneid) { + static_assert(ducks::is_ortho_layout(), "rv must be ortho layout"); + static_assert(metal::is_same_v, "rt and rv must be same type"); // compatible type + static_assert(RV::outer_dim == RT::width, "rv and rt dims don't match"); // compatible size + + using T = typename RV::T; + using T2 = typename base_types::packing::packed_type; + + const int leader = (laneid / 16) * 16 + ((laneid / 2) % 4) * 2; // lololol + #pragma clang loop unroll(full) + for(int i = 0; i < src.width; i++) { + T accum_thread = op::template op(src.tiles[0][i].data.thread_elements()[0], src.tiles[0][i].data.thread_elements()[1]); + #pragma clang loop unroll(full) + for(int j = 1; j < src.height; j++) { + accum_thread = op::template op(accum_thread, src.tiles[j][i].data.thread_elements()[0]); + accum_thread = op::template op(accum_thread, src.tiles[j][i].data.thread_elements()[1]); + } + // Now we need to do a lil shuffle to make everyone happy. + + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 1)); + accum_thread = op::template op(accum_thread, shfl_down_sync(accum_thread, 8)); + + accum_thread = shfl_sync(accum_thread, leader); + + if(reset) { + col_accum[i][0] = accum_thread; + } + else { + col_accum[i][0] = op::template op(col_accum[i][0], accum_thread); + } + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ +// two-operand row reductions. (Accumulate and REPLACE.) +/** + * @brief Store the maximum of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_max(thread RV &row_accum, thread const RT &src, const int laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} +/** + * @brief Store the minimum of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_min(thread RV &row_accum, thread const RT &src, const int laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} +/** + * @brief Store the sum of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_sum(thread RV &row_accum, thread const RT &src, const int laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} +/** + * @brief Store the product of each row of the src register tile in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_prod(thread RV &row_accum, thread const RT &src, const int laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} + +// three-operand row reductions. (Accumulate ONTO.) +/** + * @brief Store the maximum of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_max(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { +// using T = typename RV::T; +// using T2 = typename RV::T2; +// const short leader = (laneid / 16) * 16 + ((laneid / 2) % 4) * 2; +// +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// T accum_thread = metal::max(src.tiles[i][0].data.thread_elements()[0], src.tiles[i][0].data.thread_elements()[1]); +// #pragma clang loop unroll(full) +// for(int j = 1; j < src.width; j++) { +// accum_thread = metal::max(accum_thread, src.tiles[i][j].data.thread_elements()[0]); +// accum_thread = metal::max(accum_thread, src.tiles[i][j].data.thread_elements()[1]); +// } +// accum_thread = metal::max(accum_thread, shfl_down_sync(accum_thread, 1)); +// accum_thread = metal::max(accum_thread, shfl_down_sync(accum_thread, 8)); +// accum_thread = shfl_sync(accum_thread, leader); +// if(false) { row_accum[i][0] = accum_thread; } +// else { row_accum[i][0] = metal::max(src_accum[i][0], accum_thread); } +// } + + row_reduce(row_accum, src, src_accum, laneid); +} +/** + * @brief Store the minimum of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_min(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { + row_reduce(row_accum, src, src_accum, laneid); +} +/** + * @brief Store the sum of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_sum(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { +// using T = typename RV::T; +// using T2 = typename RV::T2; +// const short leader = (laneid / 16) * 16 + ((laneid / 2) % 4) * 2; +// +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// T accum_thread = (src.tiles[i][0].data.thread_elements()[0] + src.tiles[i][0].data.thread_elements()[1]); +// #pragma clang loop unroll(full) +// for(int j = 1; j < src.width; j++) { +// accum_thread = (accum_thread + src.tiles[i][j].data.thread_elements()[0]); +// accum_thread = (accum_thread + src.tiles[i][j].data.thread_elements()[1]); +// } +// T shfl_val = shfl_down_sync(accum_thread, 1); +// accum_thread = (accum_thread + shfl_val); +// shfl_val = shfl_down_sync(accum_thread, 8); +// accum_thread = (accum_thread + shfl_val); +// accum_thread = shfl_sync(accum_thread, leader); +//// accum_thread = metal::simd_sum(accum_thread); +// if(false) { +// row_accum[i][0] = accum_thread; +// } +// else { +// T src_val = src_accum[i][0]; +// row_accum[i][0] = (src_val + accum_thread); +// } +// } + row_reduce(row_accum, src, src_accum, laneid); +} +//template +//static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +//row_sum(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const int laneid, const int warpId, threadgroup typename RT::T* smem) { +// using T = typename RV::T; +// using T2 = typename RV::T2; +// using T4 = typename base_types::packing::packed_four; +// const short leader = (laneid / 16) * 16 + ((laneid / 2) % 4) * 2; +// const short qid = laneid / 4; +// const int offsetX = (qid & 4) + (laneid / 2) % 4; +// const int offsetY = (qid & 2) + laneid % 2; +// const int smem_idx_row = 32 * warpId + offsetY * 4; +// const int smem_idx = smem_idx_row + offsetX; +// #pragma clang loop unroll(full) +// for(int i = 0; i < src.height; i++) { +// T accum_thread = src.tiles[i][0].data.thread_elements()[0] + src.tiles[i][0].data.thread_elements()[1]; +// #pragma clang loop unroll(full) +// for(int j = 1; j < src.width; j++) { +// accum_thread = accum_thread + src.tiles[i][0].data.thread_elements()[0]; +// accum_thread = accum_thread + src.tiles[i][0].data.thread_elements()[1]; +// } +// { +// metal::simdgroup_barrier(metal::mem_flags::mem_none); +// smem[smem_idx] = accum_thread; +// metal::simdgroup_barrier(metal::mem_flags::mem_threadgroup); +// T4 vals = *(threadgroup T4*)(&smem[smem_idx_row]); +// accum_thread = vals[0] + vals[1] + vals[2] + vals[3]; +// } +// row_accum[i][0] = src_accum[i][0] + accum_thread; +// +// } +//} + + +/** + * @brief Store the product of each row of the src register tile, as well as the src_accum column vector, in the row_accum column vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +row_prod(thread RV &row_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { + row_reduce(row_accum, src, src_accum, laneid); +} +// two-operand col reductions. (Accumulate and REPLACE.) + +/** + * @brief Store the maximum of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_max(thread RV &col_accum, thread const RT &src, const int laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} +/** + * @brief Store the minimum of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_min(thread RV &col_accum, thread const RT &src, const int laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} +/** + * @brief Store the sum of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_sum(thread RV &col_accum, thread const RT &src, const int laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} + +/** + * @brief Store the product of each column of the src register tile in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_prod(thread RV &col_accum, thread const RT &src, const int laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} +// three-operand col reductions. (Accumulate ONTO.) +/** + * @brief Store the maximum of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_max(thread RV &col_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} +/** + * @brief Store the minimum of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_min(thread RV &col_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} + +/** + * @brief Store the sum of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_sum(thread RV &col_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} +/** + * @brief Store the product of each column of the src register tile, as well as the src_accum row vector, in the col_accum row vector. + * + * @tparam V The vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +col_prod(thread RV &col_accum, thread const RT &src, thread const RV &src_accum, const int laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} + + +} diff --git a/extra/thunder/metal/include/ops/warp/register/tile/tile.metal b/extra/thunder/metal/include/ops/warp/register/tile/tile.metal new file mode 100644 index 0000000000..beff838b16 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/tile/tile.metal @@ -0,0 +1,11 @@ +/** + * @file + * @brief An aggregate header for warp operations on register tiles. + */ + +#pragma once + +#include "conversions.metal" +#include "maps.metal" +#include "mma.metal" +#include "reductions.metal" diff --git a/extra/thunder/metal/include/ops/warp/register/vec/conversions.metal b/extra/thunder/metal/include/ops/warp/register/vec/conversions.metal new file mode 100644 index 0000000000..5e282d867c --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/vec/conversions.metal @@ -0,0 +1,162 @@ +/** + * @file + * @brief Conversions on vectors stored in registers. + */ + +#pragma once // done + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +namespace detail { + static METAL_FUNC int colstart_from_laneid(const int laneid) { // rowvec + return (laneid % 2) * 2 + ((laneid / 8) % 2) * 4; + } + // 0,1,2,3,4,5,6,7 -> 0,2,1,3,8,10,9,11 + static METAL_FUNC int leader_from_col(const int col) { // rowvec + return (col / 4) * 8 + (col / 2) % 2 + (col % 2) * 2; + } + // 0,2,1,3,8,10,9,11 -> 0,1,0,1,0,1,0,1 + static METAL_FUNC int idx_from_colleader(const int laneid) { // rowvec + return ((laneid % 8) / 2) % 2; // % 2 to protect against non-leaders + } + + static METAL_FUNC int row_from_laneid(const int laneid) { // rowvec + return (laneid / 2) % 4 + (laneid / 16) * 4; + } + // 0,1,2,3,4,5,6,7 -> 0, 2, 4, 6, 16, 18, 20, 22 + static METAL_FUNC int leader_from_row(const int row) { // rowvec + return (row/4) * 16 + (row % 4) * 2; + } + + + /* ----- ducks::is_align_register_vector() && ducks::is_naive_register_vector() -----*/ + static METAL_FUNC int col_leader_from_naive_laneid(const int laneid) { // rowvec + int tile_col = laneid % 8; + int base_leader = (tile_col / 4) * 8 + (tile_col / 2) % 2 + (tile_col % 2) * 16; + return base_leader + 2 * (laneid / 8); + } + + static METAL_FUNC int local_send_idx_from_col(const int laneid) { + return laneid >= 16; + } + + static METAL_FUNC int src_basetile_from_laneid(const int laneid) { // rowvec + return (laneid/ 2) % 4; + } + + /* ----- ducks::is_ortho_register_vector() && ducks::is_naive_register_vector() -----*/ + static METAL_FUNC int row_leader_from_naive_laneid(const int laneid) { // rowvec + int row = laneid % 8; + int base_row = (row/4) * 16 + (row % 4) * 2; + return base_row + (laneid / 8) % 2 + (laneid >= 16) * 8; + } + + static METAL_FUNC int ortho_send_tile_from_laneid(const int laneid) { // rowvec +// uint32_t MASK_1 = 0b00000000010101010000000001010101; + uint32_t MASK_2 = 0b00000000101010100000000010101010; + uint32_t MASK_3 = 0b01010101000000000101010100000000; + uint32_t MASK_4 = 0b10101010000000001010101000000000; + return ((MASK_2 >> laneid) & 1) + ((MASK_3 >> laneid) & 1) * 2 + ((MASK_4 >> laneid) & 1) * 3; + } + + + + +} +/** + * @brief Copies data from one register vector to another. + * + * @tparam RV1 The type of the destination register vector. + * @tparam RV2 The type of the source register vector. + * @param dst[out] The destination register vector. + * @param src[in] The source register vector to copy from. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_register_vector(), void>::type +copy(thread RV2 &dst, thread const RV1 &src, const ushort laneid) { + static_assert(RV1::length == RV2::length, "Outer dimensions of the register vectors must be the same."); + using D1 = typename RV1::dtype; + using D2 = typename RV2::dtype; + if (metal::is_same_v) { + #pragma clang loop unroll(full) + for(int i = 0; i < RV1::outer_dim; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < RV1::inner_dim; j++) { + dst[i][j] = base_types::convertor::convert(src[i][j]); + } + } + } else if (ducks::is_align_register_vector() && ducks::is_ortho_register_vector()) { // align vector -> ortho vector + const int row = detail::row_from_laneid(laneid); + const int laneid_src = detail::leader_from_col(row); + const int send_idx = detail::idx_from_colleader(laneid); + #pragma clang loop unroll(full) + for(int i = 0; i < RV1::outer_dim; i++) { + dst[i][0] = base_types::convertor::convert(shfl_sync(src[i][send_idx], laneid_src)); +// dst[i][0] = 1; + } + } else if (ducks::is_ortho_register_vector() && ducks::is_align_register_vector()) { // ortho vector -> align vector + const int col1 = detail::colstart_from_laneid(laneid); + const int col2 = col1 + 1; + const int laneid_src1 = detail::leader_from_row(col1); + const int laneid_src2 = detail::leader_from_row(col2); + #pragma clang loop unroll(full) + for(int i = 0; i < RV1::outer_dim; i++) { + dst[i][0] = base_types::convertor::convert(shfl_sync(src[i][0], laneid_src1)); + dst[i][1] = base_types::convertor::convert(shfl_sync(src[i][0], laneid_src2)); + } + } else if (ducks::is_align_register_vector() && ducks::is_naive_register_vector()) { + const int src_laneid = detail::col_leader_from_naive_laneid(laneid); + int align_send_tile = detail::src_basetile_from_laneid(laneid); + int align_local_send_idx = detail::local_send_idx_from_col(laneid); + int naive_tile_idx = 0; + for (int l_idx = 0; + l_idx < RV2::length; + l_idx += 32, naive_tile_idx++, align_send_tile += 4) + { + D1 send_val = 0; + if (align_send_tile < RV1::outer_dim) send_val = src[align_send_tile][align_local_send_idx]; + D1 recieve_val = shfl_sync(send_val, src_laneid); + if (l_idx + laneid < RV2::length) dst[l_idx / 32][0] = base_types::convertor::convert(recieve_val); + } + } else if (ducks::is_naive_register_vector() && ducks::is_align_register_vector()) { + int col1 = detail::colstart_from_laneid(laneid); + int col2 = col1 + 1; + for (int i = 0; i < RV2::outer_dim; i++) { + int src1 = (i%4) * 8 + col1; + int src2 = (i%4) * 8 + col2; + D1 send_val = src[i / 4][0]; + D1 recieve_val1 = shfl_sync(send_val, src1); + D1 recieve_val2 = shfl_sync(send_val, src2); + dst[i][0] = recieve_val1; + dst[i][1] = recieve_val2; + } + } else if (ducks::is_ortho_register_vector() && ducks::is_naive_register_vector()) { + const int src_laneid = detail::row_leader_from_naive_laneid(laneid); + int ortho_send_tile = detail::ortho_send_tile_from_laneid(laneid); + int naive_tile_idx = 0; + for (int l_idx = 0; l_idx < RV2::length; + l_idx += 32, naive_tile_idx++, ortho_send_tile += 4) + { + D1 send_val = 10; + if (ortho_send_tile < RV1::outer_dim) send_val = src[ortho_send_tile][0]; + D1 recieve_val = shfl_sync(send_val, src_laneid); + if (l_idx + laneid < RV2::length) dst[l_idx / 32][0] = base_types::convertor::convert(recieve_val); + } + } else if (ducks::is_naive_register_vector() && ducks::is_ortho_register_vector()) { + int row = detail::row_from_laneid(laneid); + for (int i = 0; i < RV2::outer_dim; i++) { + int src_laneid = (i%4) * 8 + row; + D1 send_val = src[i / 4][0]; + D1 recieve_val = shfl_sync(send_val, src_laneid); + dst[i][0] = recieve_val; + } + } + else { +// static_assert(RV1::inner_dim == RV2::inner_dim, "Something has gone deeply wrong with how register vectors were instantiated."); + } +} + +} diff --git a/extra/thunder/metal/include/ops/warp/register/vec/maps.metal b/extra/thunder/metal/include/ops/warp/register/vec/maps.metal new file mode 100644 index 0000000000..d77148dfc5 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/vec/maps.metal @@ -0,0 +1,288 @@ +/** + * @file + * @brief Maps on vectors stored in registers. + */ + +#pragma once // doneington + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +/* ---------- Vector Maps ---------- */ + +/** + * @brief Perform a unary operation on a vector. + * + * @tparam op The unary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector to perform the operation on. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +unary_op(thread RV &dst, thread const RV &src) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.outer_dim; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.inner_dim; j++) { + dst[i][j] = op::template op(src[i][j]); + } + } +} +/** + * @brief Perform a binary operation on two vectors. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vectors. + * @param dst[out] The destination vector where the result is stored. + * @param lhs[in] The left-hand side vector for the operation. + * @param rhs[in] The right-hand side vector for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_op(thread RV &dst, thread const RV &lhs, thread const RV &rhs) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.outer_dim; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.inner_dim; j++) { + dst[i][j] = op::template op(lhs[i][j], rhs[i][j]); + } + } +} +/** + * @brief Perform a binary operation on a vector and a scalar. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector for the operation. + * @param param[in] The scalar parameter for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_op(thread RV &dst, thread const RV &src, thread const typename RV::dtype ¶m) { + #pragma clang loop unroll(full) + for(int i = 0; i < dst.outer_dim; i++) { + #pragma clang loop unroll(full) + for(int j = 0; j < dst.inner_dim; j++) { + dst[i][j] = op::template op(src[i][j], param); + } + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// ---- const ops ---- + +/** + * @brief Sets all elements of a register vector to zero. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to zero. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +zero(thread RV &dst) { + unary_op(dst, dst); +} + +/** + * @brief Sets all elements of a register vector to one. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to one. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +one(thread RV &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a register vector to positive infinity. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to positive infinity. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +pos_infty(thread RV &dst) { + unary_op(dst, dst); +} +/** + * @brief Sets all elements of a register vector to negative infinity. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector to be set to negative infinity. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +neg_infty(thread RV &dst) { + unary_op(dst, dst); +} + +// ---- unary ops ---- + +/** + * @brief Copies the elements from one register vector to another. + * + * @tparam T Register vector type. + * @tparam U Type of the source vector. + * @param dst[out] Destination vector where the elements will be copied to. + * @param src[in] Source vector to copy the elements from. + */ +template + static METAL_FUNC typename metal::enable_if() && ducks::base_types::isT1Type(), void>::type +copy(thread RV &dst, thread const U &src) { + bin_op(dst, dst, src); // the second arg is ignored here. +} +/** + * @brief Applies the exponential function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp(thread RV &dst, thread const RV &src) { + unary_op(dst, src); +} +/** + * @brief Applies the exponential function element-wise to a register vector, in base 2. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp2(thread RV &dst, thread const RV &src) { + unary_op(dst, src); +} +/** + * @brief Applies the natural logarithm function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +log(thread RV &dst, thread const RV &src) { + unary_op(dst, src); +} +/** + * @brief Applies the absolute value function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the absolute values will be stored. + * @param src[in] Source vector to apply the absolute value function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +abs(thread RV &dst, thread const RV &src) { + unary_op(dst, src); +} +/** + * @brief Applies the rectified linear unit (ReLU) function element-wise to a register vector. + * + * @tparam T Register vector type. + * @param dst[out] Destination vector where the ReLU values will be stored. + * @param src[in] Source vector to apply the ReLU function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +relu(thread RV &dst, thread const RV &src) { + unary_op(dst, src); +} + +// ---- binary ops ---- + +/** + * @brief Computes the element-wise maximum of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the maximum values will be stored. + * @param lhs[in] First vector for the maximum operation. + * @param rhs[in] Second vector for the maximum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(thread RV &dst, thread const RV &lhs, thread const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise minimum of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the minimum values will be stored. + * @param lhs[in] First vector for the minimum operation. + * @param rhs[in] Second vector for the minimum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(thread RV &dst, thread const RV &lhs, thread const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise sum of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the sum values will be stored. + * @param lhs[in] First vector for the sum operation. + * @param rhs[in] Second vector for the sum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +add(thread RV &dst, thread const RV &lhs, thread const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise difference of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the difference values will be stored. + * @param lhs[in] First vector for the difference operation. + * @param rhs[in] Second vector for the difference operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sub(thread RV &dst, thread const RV &lhs, thread const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise product of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the product values will be stored. + * @param lhs[in] First vector for the product operation. + * @param rhs[in] Second vector for the product operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +mul(thread RV &dst, thread const RV &lhs, thread const U &rhs) { + bin_op(dst, lhs, rhs); +} +/** + * @brief Computes the element-wise division of two register vectors. + * + * @tparam T Register vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the division values will be stored. + * @param lhs[in] First vector for the division operation. + * @param rhs[in] Second vector for the division operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +div(thread RV &dst, thread const RV &lhs, thread const U &rhs) { + bin_op(dst, lhs, rhs); +} +} + diff --git a/extra/thunder/metal/include/ops/warp/register/vec/reductions.metal b/extra/thunder/metal/include/ops/warp/register/vec/reductions.metal new file mode 100644 index 0000000000..64f0fc46ae --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/vec/reductions.metal @@ -0,0 +1,236 @@ +/** + * @file + * @brief Reductions on vectors stored in registers. + */ + +#pragma once // done + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { +/* ---------- Vector Reductions ---------- */ + +/** + * @brief Performs a reduction operation on elements of a register vector within a warp. + * + * This function applies a specified operation to reduce the elements of a register vector `src` to a single value. + * The result is stored in `accum`. If the `reset` parameter is true, the reduction includes an initial value `src_accum`. + * The reduction operation is performed in a warp-wide context, ensuring synchronization between threads in the warp. + * + * @tparam op The operation to perform on the elements. Must provide a static `op` method. + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @tparam reset A boolean flag indicating whether to include an initial value in the reduction. + * @param[out] accum The result of the reduction operation. + * @param[in] src The register vector to reduce. + * @param[in] src_accum The initial value to include in the reduction if `reset` is false. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +reduce( + thread typename RV::T &dst_accum, + thread const RV &src, + thread const typename RV::T &src_accum, + const ushort laneid) { + using T = typename RV::T; + if (ducks::is_ortho_register_vector()) { // col vector + T accum = src[0][0]; + #pragma clang loop unroll(full) + for(int i = 1; i < src.outer_dim; i++) { + accum = op::template op(accum, src[i][0]); + } + accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + accum = op::template op(accum, shfl_down_sync(accum, 16)); + if (!reset) accum = op::template op(accum, src_accum); + dst_accum = shfl_sync(accum, 0); + } + else if (ducks::is_align_register_vector()) { // row vector + T accum = op::template op(src[0][0], src[0][1]); + #pragma clang loop unroll(full) + for(int i = 1; i < src.outer_dim; i++) { + accum = op::template op(accum, src[i][0]); + accum = op::template op(accum, src[i][1]); + } + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 1)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 8)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + + accum = shfl_sync(accum, 0); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + if (!reset) accum = op::template op(accum, src_accum); + dst_accum = accum; + } + else if (ducks::is_naive_register_vector()) { +// T accum = src[0][0]; + T accum; + if (laneid < src.length) accum = src[0][0]; + #pragma clang loop unroll(full) + for(int i = 1; i < src.outer_dim; i++) { + if (i*SIMD_THREADS + laneid < src.length) { + accum = op::template op(accum, src[i][0]); + } + } + if (src.length == 8) { + accum = op::template op(accum, shfl_down_sync(accum, 1)); + accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + } else if (src.length == 16) { + accum = op::template op(accum, shfl_down_sync(accum, 1)); + accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + accum = op::template op(accum, shfl_down_sync(accum, 8)); + } else if (src.length == 24) { + if (laneid < 24) { + accum = op::template op(accum, shfl_down_sync(accum, 1)); + accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + + T shfle_val = shfl_down_sync(accum, 8); + if (laneid < 16) { + accum = op::template op(accum, shfle_val); + } + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 16)); + } + + } else { + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 1)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 2)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 8)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + accum = op::template op(accum, shfl_down_sync(accum, 16)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); + } + + if (!reset) accum = op::template op(accum, src_accum); + dst_accum = shfl_sync(accum, 0); + } +} + +/** + * @brief Finds the maximum element in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] max_val The maximum value found in the vector. + * @param[in] src The register vector to find the maximum in. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(thread typename base_types::packing::unpacked_type &max_val, thread const RV &src, const ushort laneid) { + reduce(max_val, src, max_val, laneid); +} + +/** + * @brief Finds the minimum element in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] min_val The minimum value found in the vector. + * @param[in] src The register vector to find the minimum in. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(thread typename base_types::packing::unpacked_type &min_val, thread const RV &src, const ushort laneid) { + reduce(min_val, src, min_val, laneid); +} + +/** + * @brief Calculates the sum of elements in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] sum_val The sum of the values in the vector. + * @param[in] src The register vector to sum. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sum(thread typename base_types::packing::unpacked_type &sum_val, thread const RV &src, const ushort laneid) { + reduce(sum_val, src, sum_val, laneid); +} + +/** + * @brief Calculates the product of elements in a register vector. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] prod_val The product of the values in the vector. + * @param[in] src The register vector to multiply. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +prod(thread typename base_types::packing::unpacked_type &prod_val, thread const RV &src, const ushort laneid) { + reduce(prod_val, src, prod_val, laneid); +} + +// Three operand versions. + +/** + * @brief Finds the maximum element in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] max_val The maximum value found in the vector, accumulated with src_accum. + * @param[in] src The register vector to find the maximum in. + * @param[in] src_accum The initial value to accumulate with the maximum value found. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(thread typename base_types::packing::unpacked_type &max_val, + thread const RV &src, + thread const typename base_types::packing::unpacked_type &src_accum, const ushort laneid) { + reduce(max_val, src, src_accum, laneid); +} + +/** + * @brief Finds the minimum element in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] min_val The minimum value found in the vector, accumulated with src_accum. + * @param[in] src The register vector to find the minimum in. + * @param[in] src_accum The initial value to accumulate with the minimum value found. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(thread typename base_types::packing::unpacked_type &min_val, + thread const RV &src, + thread const typename base_types::packing::unpacked_type &src_accum, const ushort laneid) { + reduce(min_val, src, src_accum, laneid); +} + +/** + * @brief Calculates the sum of elements in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] sum_val The sum of the values in the vector, accumulated with src_accum. + * @param[in] src The register vector to sum. + * @param[in] src_accum The initial value to accumulate with the sum of the vector. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sum(thread typename base_types::packing::unpacked_type &sum_val, + thread const RV &src, + thread const typename base_types::packing::unpacked_type &src_accum, const ushort laneid) { + reduce(sum_val, src, src_accum, laneid); +} + +/** + * @brief Calculates the product of elements in a register vector and accumulates it with src_accum. + * + * @tparam RV The type of the register vector. Must satisfy the `ducks::rv::all` concept. + * @param[out] prod_val The product of the values in the vector, accumulated with src_accum. + * @param[in] src The register vector to multiply. + * @param[in] src_accum The initial value to accumulate with the product of the vector. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +prod(thread typename base_types::packing::unpacked_type &prod_val, + thread const RV &src, + thread const typename base_types::packing::unpacked_type &src_accum, const ushort laneid) { + reduce(prod_val, src, src_accum, laneid); +} + +} diff --git a/extra/thunder/metal/include/ops/warp/register/vec/vec.metal b/extra/thunder/metal/include/ops/warp/register/vec/vec.metal new file mode 100644 index 0000000000..9a3aff871d --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/register/vec/vec.metal @@ -0,0 +1,4 @@ +#pragma once +#include "conversions.metal" +#include "maps.metal" +#include "reductions.metal" diff --git a/extra/thunder/metal/include/ops/warp/shared/shared.metal b/extra/thunder/metal/include/ops/warp/shared/shared.metal new file mode 100644 index 0000000000..02980d3201 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/shared.metal @@ -0,0 +1,3 @@ +#pragma once +#include "tile/tile.metal" +#include "vec/vec.metal" diff --git a/extra/thunder/metal/include/ops/warp/shared/tile/conversions.metal b/extra/thunder/metal/include/ops/warp/shared/tile/conversions.metal new file mode 100644 index 0000000000..7623974d75 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/tile/conversions.metal @@ -0,0 +1,59 @@ +/** + * @file + * @brief Conversions between shared tile types. + */ + +#pragma once // not done, add subtile + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { +/* ---------- COPIES ---------- */ +/** + * @brief Copies data from one shared memory tile to another, potentially with different data types and layouts. + * + * @tparam T The data type of the destination tile. + * @tparam U The data type of the source tile. + * @tparam _height The height of the tile. + * @tparam _width The width of the tile. + * @tparam L1 The layout of the destination tile. + * @tparam L2 The layout of the source tile. + * @param[out] dst The destination tile. + * @param[in] src The source tile. + */ +template +static METAL_FUNC void copy(threadgroup st &dst, threadgroup const st &src, const ushort laneid) { + #pragma clang loop unroll(full) + for(int i = laneid; i < dst.num_elements; i+=mittens::SIMD_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = base_types::convertor::convert(src[{row, col}]); + } +} + +///* ---------- SUBTILE ---------- */ +// +///** +//* @brief Returns a reference to a subtile of the given shared tile. +//* +//* @tparam subtile_height The height of the subtile. +//* @tparam subtile_width The width of the subtile. +//* @tparam ST The type of the input tile, which must satisfy the ducks::st::all concept. +//* @param src The input tile. +//* @param row_idx The row index of the subtile, in units of subtile_height*16 elements. +//* @param col_idx The col index of the subtile, in units of subtile_width*16 elements. +//* @return A reference to the subtile. +//* +//* @note The subtile {height, width} must evenly divide the tile {height, width}. +//*/ +//template +//__device__ inline typename ST::subtile subtile_inplace(ST &src, int row_idx, int col_idx) { +// static_assert(ST::height % subtile_height == 0); +// static_assert(ST::width % subtile_width == 0); +// return typename ST::subtile( +// &src[0], subtile_height*16*row_idx, subtile_width*16*col_idx +// ); +//} + +} + diff --git a/extra/thunder/metal/include/ops/warp/shared/tile/maps.metal b/extra/thunder/metal/include/ops/warp/shared/tile/maps.metal new file mode 100644 index 0000000000..336fceceae --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/tile/maps.metal @@ -0,0 +1,485 @@ +/** + * @file + * @brief Warp-scope maps on shared tiles. + */ + +#pragma once + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { +/* ---------- Uniform tile maps (independent of layout) ---------- */ + +/** + * @brief Performs a uniform unary operation on a tile. + * + * This function applies a given unary operation to each element of the source tile and stores the result in the destination tile. + * The operation is applied independently to each element, without considering its position or the values of neighboring elements. + * + * @tparam op The unary operation to be applied. Must be specialized to support operation on the data type of T. + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the unary operation is applied. + */ +template // T2, w, h can be inferred from dst as long as op is specialized +static METAL_FUNC typename metal::enable_if(), void>::type +unary_map(threadgroup ST &dst, threadgroup const ST &src, const ushort laneid) { + #pragma clang loop unroll(full) + for(int i = laneid; i < ST::num_elements; i += SIMD_THREADS) { + dst.data[i] = op::template op(src.data[i]); + } +} + + +/** + * @brief Performs a uniform binary operation on a tile with a scalar parameter. + * + * This function applies a given binary operation to each element of the source tile and a scalar parameter, then stores the result in the destination tile. + * The operation is applied independently to each element, treating the scalar parameter as the second operand for each operation. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T and the scalar parameter. + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the binary operation is applied. + * @param[in] param The scalar parameter to be used as the second operand in the binary operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_map(threadgroup ST &dst, threadgroup const ST &src, thread const typename ST::dtype ¶m, const short laneid) { + #pragma clang loop unroll(full) + for(int i = laneid; i < dst.num_elements; i += SIMD_THREADS) { + dst.data[i] = op::template op(src.data[i], param); + } +} + +/** + * @brief Performs a uniform binary operation on two tiles. + * + * This function applies a given binary operation to corresponding elements of two source tiles and stores the result in the destination tile. + * The operation is applied independently to each pair of elements, without considering their positions or the values of neighboring elements. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T. + * @tparam T The type of the tiles. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile to which the binary operation is applied. + * @param[in] rhs The second source tile to which the binary operation is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_map(threadgroup ST &dst, threadgroup const ST &lhs, threadgroup const ST &rhs, const ushort laneid) { + #pragma clang loop unroll(full) + for(int i = laneid; i < dst.num_elements; i += SIMD_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst.data[i] = op::template op(lhs.data[i], rhs.data[i]); + } +} + +/** + * @brief Performs a row-wise binary operation on a tile with a vector. + * + * This function applies a given binary operation to each row of the source tile and the corresponding element of the source vector, + * then stores the result in the destination tile. The operation is applied independently to each row, using the vector element as + * the second operand for each element in the row. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T and the vector elements. + * @tparam T The type of the tiles. Must satisfy the `ducks::st::all` concept. + * @tparam V The type of the vector. Must have the same data type as T. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the binary operation is applied. + * @param[in] vec The source vector containing the second operand for each row operation. + */ +template + static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector, void>::type +row_map(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &vec, const ushort laneid) { + static_assert(metal::is_same::value, "Tile and vector must have the same data type"); + static_assert(SV::length == ST::rows, "Vector length must match the number of rows in the tile"); + #pragma clang loop unroll(full) + for(int i = laneid; i < dst.num_elements; i += SIMD_THREADS) { + int row = i/ST::cols, col = i%ST::cols; + dst[{row, col}] = op::template op(src[{row, col}], vec[row]); + } +} + +/** + * @brief Performs a column-wise binary operation on a tile with a vector. + * + * This function applies a given binary operation to each column of the source tile and the corresponding element of the source vector, + * then stores the result in the destination tile. The operation is applied independently to each column, using the vector element as + * the second operand for each element in the column. + * + * @tparam op The binary operation to be applied. Must be specialized to support operation on the data type of T and the vector elements. + * @tparam T The type of the tiles. Must satisfy the `ducks::st::all` concept. + * @tparam V The type of the vector. Must have the same data type as T. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the binary operation is applied. + * @param[in] vec The source vector containing the second operand for each column operation. + */ +template + static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_map(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &vec, const ushort laneid) { + static_assert(metal::is_same::value, "Tile and vector must have the same data type"); + static_assert(SV::length == ST::cols, "Vector length must match the number of columns in the tile"); + #pragma clang loop unroll(full) + for(int i = laneid; i < dst.num_elements; i += SIMD_THREADS) { + int row = i/dst.cols, col = i%dst.cols; + dst[{row, col}] = op::template op(src[{row, col}], vec[col]); + } +} + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// const maps +/** + * @brief Sets all elements of the destination tile to zero. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +zero(threadgroup ST &dst, const ushort laneid) { + unary_map(dst, dst, laneid); +} +/** + * @brief Sets all elements of the destination tile to one. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +one(threadgroup ST &dst, const ushort laneid) { + unary_map(dst, dst, laneid); +} +/** + * @brief Sets all elements of the destination tile to positive infinity. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +pos_infty(threadgroup ST &dst, const ushort laneid) { + unary_map(dst, dst, laneid); +} +/** + * @brief Sets all elements of the destination tile to negative infinity. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +neg_infty(threadgroup ST &dst, const ushort laneid) { + unary_map(dst, dst, laneid); +} + +// unary maps +/** + * @brief Applies the exponential function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the exponential function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp(threadgroup ST &dst, threadgroup const ST &src, const ushort laneid) { + unary_map(dst, src, laneid); +} +/** + * @brief Applies the exponential function to each element of the source tile and stores the result in the destination tile, in base 2. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the exponential function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp2(threadgroup ST &dst, threadgroup const ST &src, const ushort laneid) { + unary_map(dst, src, laneid); +} +/** + * @brief Applies the natural logarithm function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the natural logarithm function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +log(threadgroup ST &dst, threadgroup const ST &src, const ushort laneid) { + unary_map(dst, src, laneid); +} +/** + * @brief Applies the absolute function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the absolute function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +abs(threadgroup ST &dst, threadgroup const ST &src, const ushort laneid) { + unary_map(dst, src, laneid); +} +/** + * @brief Applies the rectified linear unit function to each element of the source tile and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source tile to which the rectified linear unit function is applied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +relu(threadgroup ST &dst, const threadgroup ST &src, const ushort laneid) { + unary_map(dst, src, laneid); +} +/** + * @brief Copies the elements of the source tile to the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] src The source data to be copied. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(threadgroup ST &dst, thread const U &src, const ushort laneid) { + bin_map(dst, dst, src, laneid); +} + +// uniform binary maps +/** + * @brief Finds the maximum of each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const ushort laneid) { + bin_map(dst, lhs, rhs, laneid); +} +/** + * @brief Finds the minimum of each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const ushort laneid) { + bin_map(dst, lhs, rhs, laneid); +} +/** + * @brief Adds each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +add(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const ushort laneid) { + bin_map(dst, lhs, rhs, laneid); +} +/** + * @brief Subtracts each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sub(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const ushort laneid) { + bin_map(dst, lhs, rhs, laneid); +} +/** + * @brief Multiplies each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +mul(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const ushort laneid) { + bin_map(dst, lhs, rhs, laneid); +} +/** + * @brief Divides each pair of corresponding elements in the two source tiles and stores the result in the destination tile. + * + * @tparam T The type of the tile. Must satisfy the `ducks::st::all` concept. + * @tparam U The type of the second source data. Must be convertible to the data type of the destination tile. + * @param[out] dst The destination tile where the results are stored. + * @param[in] lhs The first source tile. + * @param[in] rhs The second source data. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +div(threadgroup ST &dst, threadgroup const ST &lhs, thread const U &rhs, const ushort laneid) { + bin_map(dst, lhs, rhs, laneid); +} + +// Row and col maps + +/** + * @brief Adds row values to each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param row_values[in] Column vector containing values to add to each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +add_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const ushort laneid) { + row_map(dst, src, row_values, laneid); +} +/** + * @brief Subtracts row values from each row of a tile. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param row_values[in] Column vector containing values to subtract from each row. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +sub_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const ushort laneid) { + row_map(dst, src, row_values, laneid); +} +/** + * @brief Multiplies each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param row_values[in] Column vector containing values to multiply each row by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +mul_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const ushort laneid) { + row_map(dst, src, row_values, laneid); +} +/** + * @brief Divides each row of a tile by row values. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param row_values[in] Column vector containing values to divide each row by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_tile(), void>::type +div_row(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &row_values, const ushort laneid) { + row_map(dst, src, row_values, laneid); +} +/** + * @brief Broadcast a vector into into a tile's rows. + * + * @tparam T Tile type. + * @tparam V Column vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Column vector containing values to broadcast into rows. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +broadcast_row(threadgroup ST &dst, threadgroup const SV &row_values, const ushort laneid) { + row_map(dst, dst, row_values, laneid); +} + + +// col maps +/** + * @brief Adds column values to each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the addition on. + * @param col_values[in] Row vector containing values to add to each column. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +add_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const ushort laneid) { + col_map(dst, src, col_values, laneid); +} +/** + * @brief Subtracts column values from each column of a tile. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the subtraction on. + * @param col_values[in] Row vector containing values to subtract from each column. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sub_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const ushort laneid) { + col_map(dst, src, col_values, laneid); +} +/** + * @brief Multiplies each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the multiplication on. + * @param col_values[in] Row vector containing values to multiply each column by. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +mul_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const ushort laneid) { + col_map(dst, src, col_values, laneid); +} +/** + * @brief Divides each column of a tile by column values. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param src[in] Source tile to apply the division on. + * @param col_values[in] Row vector containing values to divide each column by. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type + div_col(threadgroup ST &dst, threadgroup const ST &src, threadgroup const SV &col_values, const ushort laneid) { + col_map(dst, src, col_values, laneid); +} +/** + * @brief Broadcast a vector into into a tile's columns. + * + * @tparam T Tile type. + * @tparam V Row vector type. + * @param dst[out] Destination tile where the result is stored. + * @param row_values[in] Row vector containing values to broadcast into cols. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +broadcast_col(threadgroup ST &dst, threadgroup const SV &col_values, const ushort laneid) { + col_map(dst, dst, col_values, laneid); +} + + +} diff --git a/extra/thunder/metal/include/ops/warp/shared/tile/reductions.metal b/extra/thunder/metal/include/ops/warp/shared/tile/reductions.metal new file mode 100644 index 0000000000..b4b41b0c8b --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/tile/reductions.metal @@ -0,0 +1,295 @@ +/** + * @file + * @brief Warp-scope reductions on shared tiles. + */ + +#pragma once + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +/** + * Performs row-wise reduction on a matrix using a specified operation. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type with row layout. + * @param row_accum The accumulator where the result of the reduction is stored. + * @param src The source matrix on which to perform the reduction. + * @param src_accum The initial value of the accumulator, used when reset is false. + * @param reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_reduce(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + using dtype = typename SV::dtype; + #pragma clang loop unroll(full) + for (int row = laneid; row < ST::rows; row += mittens::SIMD_THREADS) { + dtype accum = src[{row, 0}]; + #pragma clang loop unroll(full) + for (int col = 1; col < src.cols; col++) { + accum = op::template op(accum, src[{row, col}]); + } + if (reset) { + row_accum[row] = accum; + } else { + row_accum[row] = op::template op(src_accum[row], accum); + } + } +} + +/** + * Performs column-wise reduction on a matrix using a specified operation. + * + * @tparam op The operation to be applied for reduction. + * @tparam V The shared vector type for the column accumulator. + * @tparam T The shared matrix type with column layout. + * @param col_accum The accumulator where the result of the reduction is stored. + * @param src The source matrix on which to perform the reduction. + * @param src_accum The initial value of the accumulator, used when reset is false. + * @param reset A boolean flag indicating whether to reset the accumulator (ignore src_accum) or not. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_reduce(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + using dtype = typename SV::dtype; + #pragma clang loop unroll(full) + for (int col = laneid; col < src.cols; col += mittens::SIMD_THREADS) { + dtype accum = src[int2(0, col)]; + #pragma clang loop unroll(full) + for (int row = 1; row < src.rows; row++) { + accum = op::template op(accum, src[int2(row, col)]); + } + if (reset) { + col_accum[col] = accum; + } else { + col_accum[col] = op::template op(src_accum[col], accum); + } + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +/** + * @brief Store the maximum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_max(threadgroup SV &row_accum, threadgroup const ST &src, const ushort laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} +/** + * @brief Store the minimum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_min(threadgroup SV &row_accum, threadgroup const ST &src, const ushort laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} +/** + * @brief Store the sum of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_sum(threadgroup SV &row_accum, threadgroup const ST &src, const ushort laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} +/** + * @brief Store the product of each row of the src shared matrix in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_prod(threadgroup SV &row_accum, threadgroup const ST &src, const ushort laneid) { + row_reduce(row_accum, src, row_accum, laneid); +} + +/** + * @brief Store the maximum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_max(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + row_reduce(row_accum, src, src_accum, laneid); +} +/** + * @brief Store the minimum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_min(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + row_reduce(row_accum, src, src_accum, laneid); +} +/** + * @brief Store the sum of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_sum(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + row_reduce(row_accum, src, src_accum, laneid); +} +/** + * @brief Store the product of each row of the src shared matrix, as well as the src_accum shared vector, in the row_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] row_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +row_prod(threadgroup SV &row_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + row_reduce(row_accum, src, src_accum, laneid); +} + +/** + * @brief Store the maximum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_max(threadgroup SV &col_accum, threadgroup const ST &src, const ushort laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} +/** + * @brief Store the minimum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_min(threadgroup SV &col_accum, threadgroup const ST &src, const ushort laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} +/** + * @brief Store the sum of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_sum(threadgroup SV &col_accum, threadgroup const ST &src, const ushort laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} +/** + * @brief Store the product of each column of the src shared matrix in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_prod(threadgroup SV &col_accum, threadgroup const ST &src, const ushort laneid) { + col_reduce(col_accum, src, col_accum, laneid); +} + +/** + * @brief Store the maximum of each column of the src shared matrix, as well as the src_accum shared vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_max(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} +/** + * @brief Store the minimum of each column of the src shared matrix, as well as the src_accum shared vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_min(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} +/** + * @brief Store the sum of each column of the src shared tile, as well as the src_accum row vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_sum(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} +/** + * @brief Store the product of each column of the src shared tile, as well as the src_accum row vector, in the col_accum shared vector. + * + * @tparam V The shared vector type for the row accumulator. + * @tparam T The shared matrix type. + * @param[out] col_accum The accumulator where the result of the reduction is stored. + * @param[in] src The source matrix on which to perform the reduction. + * @param[in] src_accum The initial value of the accumulator, used when accumulating onto an existing value. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +col_prod(threadgroup SV &col_accum, threadgroup const ST &src, threadgroup const SV &src_accum, const ushort laneid) { + col_reduce(col_accum, src, src_accum, laneid); +} + +} diff --git a/extra/thunder/metal/include/ops/warp/shared/tile/tile.metal b/extra/thunder/metal/include/ops/warp/shared/tile/tile.metal new file mode 100644 index 0000000000..9a3aff871d --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/tile/tile.metal @@ -0,0 +1,4 @@ +#pragma once +#include "conversions.metal" +#include "maps.metal" +#include "reductions.metal" diff --git a/extra/thunder/metal/include/ops/warp/shared/vec/conversions.metal b/extra/thunder/metal/include/ops/warp/shared/vec/conversions.metal new file mode 100644 index 0000000000..b2de6bece0 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/vec/conversions.metal @@ -0,0 +1,60 @@ +/** + * @file + * @brief Warp-scope conversions on shared vectors. + */ + +#pragma once // done! + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + + +/** + * @brief Copies data from one shared vector to another, converting data types if necessary. + * + * This function copies data from the source shared vector `src` to the destination shared vector `dst`. + * If the data types of `src` and `dst` are the same, it performs a direct memory copy. Otherwise, it + * converts each element from the source data type to the destination data type using the appropriate + * converter before copying. + * + * @tparam SV1 The type of the destination shared vector, must satisfy the ducks::sv::all concept. + * @tparam SV2 The type of the source shared vector, must satisfy the ducks::sv::all concept. + * @param[out] dst The destination shared vector. + * @param[in] src The source shared vector. + * @note The lengths of `src` and `dst` must be equal. This is enforced at compile time. + */ +template +static METAL_FUNC typename metal::enable_if() && ducks::is_shared_vector(), void>::type +copy(threadgroup SV1 &dst, threadgroup const SV2 &src, const ushort laneid) { + static_assert(SV1::length == SV2::length, "Source and destination vectors must have the same length."); + #pragma clang loop unroll(full) + for(int i = laneid; i < dst.length; i+=SIMD_THREADS) { + dst[i] = base_types::convertor::convert(src[i]); + } +} + +/* ---------- SUBVEC ---------- */ + +/** +* @brief Returns a reference to a subvec of a given shared vector +* +* @tparam subvec_tiles The length, in subtiles, of the subvec. +* @tparam SV The type of the input vector, which must satisfy the ducks::sv::all concept. +* @param src The input tile. +* @param vec_idx The index of the subtile, in units of subvec_tiles*16 elements. +* @return A reference to the subvec. +* +* @note The subvec length must evenly divide the vector length. +*/ +template +//using subvec = typename SV::template subvec; +static METAL_FUNC typename metal::enable_if(), threadgroup typename SV::template subvec&>::type +subvec_inplace(threadgroup SV &src, int vec_idx) { + return *(threadgroup typename SV::template subvec*)(&src[vec_idx*TILE_DIM*subvec_tiles]); +} + +} + + diff --git a/extra/thunder/metal/include/ops/warp/shared/vec/maps.metal b/extra/thunder/metal/include/ops/warp/shared/vec/maps.metal new file mode 100644 index 0000000000..e95d9637bd --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/vec/maps.metal @@ -0,0 +1,278 @@ +/** + * @file + * @brief Warp-scope maps on shared vectors. + */ + +#pragma once + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +/** + * @brief Applies a unary operation to each element of a shared memory vector. + * + * @tparam op Unary operation type. + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector in which to store the result. + * @param src[in] Source vector to apply the unary operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +unary_op(threadgroup SV &dst, threadgroup const SV &src, const ushort laneid) { + metal::simdgroup_barrier(metal::mem_flags::mem_none); + #pragma clang loop unroll(full) + for(int cur = laneid; cur < SV::length; cur+=SIMD_THREADS) { + dst[cur] = op::template op(src[cur]); + } +} +/** + * @brief Perform a binary operation on two shared vectors. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vectors. + * @param dst[out] The destination vector where the result is stored. + * @param lhs[in] The left-hand side vector for the operation. + * @param rhs[in] The right-hand side vector for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_op(threadgroup SV &dst, threadgroup const SV &lhs, threadgroup const SV &rhs, const ushort laneid) { + #pragma clang loop unroll(full) + for(int cur = laneid; cur < SV::length; cur+=SIMD_THREADS) { + dst[cur] = op::template op(lhs[cur], rhs[cur]); + } +} +/** + * @brief Perform a binary operation on a shared vector and a scalar. + * + * @tparam op The binary operation to perform. + * @tparam T The type of the vector. + * @param dst[out] The destination vector where the result is stored. + * @param src[in] The source vector for the operation. + * @param param[in] The scalar parameter for the operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +bin_op(threadgroup SV &dst, threadgroup const SV &src, thread const typename SV::T ¶m, const ushort laneid) { + metal::simdgroup_barrier(metal::mem_flags::mem_none); + #pragma clang loop unroll(full) + for(int cur = laneid; cur < SV::length; cur+=SIMD_THREADS) { + dst[cur] = op::template op(src[cur], param); + } +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// ---- const ops ---- + +/** + * @brief Sets all elements of a shared memory vector to zero. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to zero. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +zero(threadgroup SV &dst, const ushort laneid) { + unary_op(dst, dst, laneid); +} +/** + * @brief Sets all elements of a shared memory vector to one. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to one. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +one(threadgroup SV &dst, const ushort laneid) { + unary_op(dst, dst, laneid); +} +/** + * @brief Sets all elements of a shared memory vector to positive infinity. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to positive infinity. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +pos_infty(threadgroup SV &dst, const ushort laneid) { + unary_op(dst, dst, laneid); +} +/** + * @brief Sets all elements of a shared memory vector to negative infinity. + * + * @tparam T Shared memory vector type. + * @param dst[out] Destination vector to be set to negative infinity. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +neg_infty(threadgroup SV &dst, const ushort laneid) { + unary_op(dst, dst, laneid); +} + +// ---- unary ops ---- + +/** + * @brief Copies the elements from one shared vector to another. + * + * @tparam T Shared vector type. + * @tparam U Type of the source vector. + * @param dst[out] Destination vector where the elements will be copied to. + * @param src[in] Source vector to copy the elements from. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +copy(threadgroup SV &dst, thread const U &src, const ushort laneid) { + bin_op(dst, dst, src, laneid); // the second arg is ignored here. +} +/** + * @brief Applies the exponential function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp(threadgroup SV &dst, threadgroup const SV &src, const ushort laneid) { + unary_op(dst, src, laneid); +} +/** + * @brief Applies the exponential function element-wise to a shared vector, in base 2. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the exponential values will be stored. + * @param src[in] Source vector to apply the exponential function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +exp2(threadgroup SV &dst, threadgroup const SV &src, const ushort laneid) { + unary_op(dst, src, laneid); +} +/** + * @brief Applies the natural logarithm function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the logarithm values will be stored. + * @param src[in] Source vector to apply the logarithm function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +log(threadgroup SV &dst, threadgroup const SV &src, const ushort laneid) { + unary_op(dst, src, laneid); +} +/** + * @brief Applies the absolute value function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the absolute values will be stored. + * @param src[in] Source vector to apply the absolute value function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +abs(threadgroup SV &dst, threadgroup const SV &src, const ushort laneid) { + unary_op(dst, src, laneid); +} +/** + * @brief Applies the rectified linear unit (ReLU) function element-wise to a shared vector. + * + * @tparam T Shared vector type. + * @param dst[out] Destination vector where the ReLU values will be stored. + * @param src[in] Source vector to apply the ReLU function to. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +relu(threadgroup SV &dst, threadgroup const SV &src, const ushort laneid) { + unary_op(dst, src, laneid); +} + +// ---- binary ops ---- + +/** + * @brief Computes the element-wise maximum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the maximum values will be stored. + * @param lhs[in] First vector for the maximum operation. + * @param rhs[in] Second vector for the maximum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const ushort laneid) { + bin_op(dst, lhs, rhs, laneid); +} +/** + * @brief Computes the element-wise minimum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the minimum values will be stored. + * @param lhs[in] First vector for the minimum operation. + * @param rhs[in] Second vector for the minimum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const ushort laneid) { + bin_op(dst, lhs, rhs, laneid); +} +/** + * @brief Computes the element-wise sum of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the sum values will be stored. + * @param lhs[in] First vector for the sum operation. + * @param rhs[in] Second vector for the sum operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +add(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const ushort laneid) { + bin_op(dst, lhs, rhs, laneid); +} +/** + * @brief Computes the element-wise difference of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the difference values will be stored. + * @param lhs[in] First vector for the difference operation. + * @param rhs[in] Second vector for the difference operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sub(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const ushort laneid) { + bin_op(dst, lhs, rhs, laneid); +} +/** + * @brief Computes the element-wise product of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the product values will be stored. + * @param lhs[in] First vector for the product operation. + * @param rhs[in] Second vector for the product operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +mul(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const ushort laneid) { + bin_op(dst, lhs, rhs, laneid); +} +/** + * @brief Computes the element-wise division of two shared vectors. + * + * @tparam T Shared vector type. + * @tparam U Type of the second vector. + * @param dst[out] Destination vector where the division values will be stored. + * @param lhs[in] First vector for the division operation. + * @param rhs[in] Second vector for the division operation. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +div(threadgroup SV &dst, threadgroup const SV &lhs, thread const U &rhs, const ushort laneid) { + bin_op(dst, lhs, rhs, laneid); +} + +} diff --git a/extra/thunder/metal/include/ops/warp/shared/vec/reductions.metal b/extra/thunder/metal/include/ops/warp/shared/vec/reductions.metal new file mode 100644 index 0000000000..483725c9a4 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/vec/reductions.metal @@ -0,0 +1,268 @@ +/** + * @file + * @brief Warp-scope maps on shared vectors. + */ + +#pragma once + +#include "../../../../common/common.metal" +#include "../../../../types/types.metal" + +namespace mittens { + +/** + * @brief Performs a reduction operation on elements of a shared memory vector within a warp. + * + * This function applies a specified operation to reduce the elements of a shared memory vector `src` to a single value. + * The result is stored in `accum`. If the `reset` parameter is true, the reduction includes an initial value `src_accum`. + * The reduction operation is performed in a warp-wide context, ensuring synchronization between threads in the warp. + * + * @tparam op The operation to perform on the elements. Must provide a static `op` method. + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @tparam reset A boolean flag indicating whether to include an initial value in the reduction. + * @param[out] accum The result of the reduction operation. + * @param[in] src The shared memory vector to reduce. + * @param[in] src_accum The initial value to include in the reduction if `reset` is false. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +reduce(thread typename SV::dtype &dst_accum, threadgroup const SV &src, thread const typename SV::dtype &src_accum, const ushort laneid) { + using T = typename SV::dtype; + + { + T accum = src[0]; + for (int i = 1; i < SV::length; i++) { + accum = op::template op(accum, src[i]); + } + dst_accum = shfl_sync(accum, 0); + return; + } + +// + T accum; + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = op::template op(accum, src[i]); + } + if (src.length >= 32) { +// accum = op::template op(accum, shfl_down_sync(accum, 1)); + accum = op::template op(accum, (T)metal::simd_shuffle_rotate_down((float)accum, 1)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); +// accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, (T)metal::simd_shuffle_rotate_down((float)accum, 2)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); +// accum = op::template op(accum, shfl_down_sync(accum, 4)); + accum = op::template op(accum, (T)metal::simd_shuffle_rotate_down((float)accum, 4)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); +// accum = op::template op(accum, shfl_down_sync(accum, 8)); + accum = op::template op(accum, (T)metal::simd_shuffle_rotate_down((float)accum, 8)); + metal::simdgroup_barrier(metal::mem_flags::mem_none); +// accum = op::template op(accum, shfl_down_sync(accum, 16)); + accum = op::template op(accum, (T)metal::simd_shuffle_rotate_down((float)accum, 16)); + + } else if (src.length == 24) { + T shfl_val = shfl_down_sync(accum, 1); + accum = op::template op(accum, shfl_val); + + shfl_val = shfl_down_sync(accum, 2); + accum = op::template op(accum, shfl_val); + + shfl_val = shfl_down_sync(accum, 4); + accum = op::template op(accum, shfl_val); + + shfl_val = shfl_down_sync(accum, 8); + if (laneid < 16) { + accum = op::template op(accum, shfl_val); + } + shfl_val = shfl_down_sync(accum, 16); + accum = op::template op(accum, shfl_val); + } else if (src.length == 16) { + accum = op::template op(accum, shfl_down_sync(accum, 1)); + accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + accum = op::template op(accum, shfl_down_sync(accum, 8)); + } else if (src.length == 8) { + accum = op::template op(accum, shfl_down_sync(accum, 1)); + accum = op::template op(accum, shfl_down_sync(accum, 2)); + accum = op::template op(accum, shfl_down_sync(accum, 4)); + } + if (!reset) accum = op::template op(accum, src_accum); + dst_accum = shfl_sync(accum, 0); +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +/** + * @brief Finds the maximum element in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] max_val The maximum value found in the vector. + * @param[in] src The shared memory vector to find the maximum in. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(thread typename SV::dtype &max_val, threadgroup const SV &src, const ushort laneid) { +// reduce(max_val, src, max_val, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::neg_infty(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::max::template op(accum, src[i]); + } + max_val = (T)metal::simd_max((float)accum); +} + +/** + * @brief Finds the minimum element in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] min_val The minimum value found in the vector. + * @param[in] src The shared memory vector to find the minimum in. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(thread typename SV::dtype &min_val, threadgroup const SV &src, const ushort laneid) { +// reduce(min_val, src, min_val); + + using T = typename SV::dtype; + T accum = base_types::constants::pos_infty(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::min::template op(accum, src[i]); + } + min_val = (T)metal::simd_min((float)accum); +} + +/** + * @brief Calculates the sum of elements in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] sum_val The sum of the values in the vector. + * @param[in] src The shared memory vector to sum. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sum(thread typename SV::dtype &sum_val, threadgroup const SV &src, const ushort laneid) { +// reduce(sum_val, src, sum_val, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::zero(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::min::template op(accum, src[i]); + } + sum_val = (T)metal::simd_sum((float)accum); +} + +/** + * @brief Calculates the product of elements in a shared memory vector. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] prod_val The product of the values in the vector. + * @param[in] src The shared memory vector to multiply. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +prod(thread typename SV::dtype &prod_val, threadgroup const SV &src, const ushort laneid) { +// reduce(prod_val, src, prod_val, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::one(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::min::template op(accum, src[i]); + } + prod_val = (T)metal::simd_product((float)accum); +} + +// Three operand versions. + +/** + * @brief Finds the maximum element in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] max_val The maximum value found in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to find the maximum in. + * @param[in] src_accum The initial value to accumulate with the maximum value found. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +max(thread typename SV::dtype &max_val, threadgroup const SV &src, thread const typename SV::dtype &src_accum, const ushort laneid) { +// reduce(max_val, src, src_accum, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::neg_infty(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::max::template op(accum, src[i]); + } + max_val = (T)metal::simd_max((float)accum); + max_val = base_ops::max::template op(max_val, src_accum); +} + +/** + * @brief Finds the minimum element in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] min_val The minimum value found in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to find the minimum in. + * @param[in] src_accum The initial value to accumulate with the minimum value found. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +min(thread typename SV::dtype &min_val, threadgroup const SV &src, thread const typename SV::dtype &src_accum, const ushort laneid) { +// reduce(min_val, src, src_accum, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::pos_infty(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::max::template op(accum, src[i]); + } + min_val = (T)metal::simd_min((float)accum); + min_val = base_ops::max::template op(min_val, src_accum); +} + +/** + * @brief Calculates the sum of elements in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] sum_val The sum of the values in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to sum. + * @param[in] src_accum The initial value to accumulate with the sum of the vector. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +sum(thread typename SV::dtype &sum_val, threadgroup const SV &src, threadgroup const typename SV::dtype &src_accum, const ushort laneid) { +// reduce(sum_val, src, src_accum, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::zero(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::max::template op(accum, src[i]); + } + sum_val = (T)metal::simd_sum((float)accum); + sum_val = base_ops::max::template op(sum_val, src_accum); +} + +/** + * @brief Calculates the product of elements in a shared memory vector and accumulates it with src_accum. + * + * @tparam SV The type of the shared memory vector. Must satisfy the `ducks::sv::all` concept. + * @param[out] prod_val The product of the values in the vector, accumulated with src_accum. + * @param[in] src The shared memory vector to multiply. + * @param[in] src_accum The initial value to accumulate with the product of the vector. + */ +template +static METAL_FUNC typename metal::enable_if(), void>::type +prod(thread typename SV::dtype &prod_val, threadgroup const SV &src, thread const typename SV::dtype &src_accum, const ushort laneid) { +// reduce(prod_val, src, src_accum, laneid); + using T = typename SV::dtype; + T accum = base_types::constants::one(); + if(laneid < SV::length) accum = src[laneid]; // initialize a register accumulator + for(int i = laneid + 32; i < SV::length; i+=32) { + accum = base_ops::max::template op(accum, src[i]); + } + prod_val = (T)metal::simd_product((float)accum); + prod_val = base_ops::max::template op(prod_val, src_accum); +} +} + + + diff --git a/extra/thunder/metal/include/ops/warp/shared/vec/vec.metal b/extra/thunder/metal/include/ops/warp/shared/vec/vec.metal new file mode 100644 index 0000000000..9a3aff871d --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/shared/vec/vec.metal @@ -0,0 +1,4 @@ +#pragma once +#include "conversions.metal" +#include "maps.metal" +#include "reductions.metal" diff --git a/extra/thunder/metal/include/ops/warp/warp.metal b/extra/thunder/metal/include/ops/warp/warp.metal new file mode 100644 index 0000000000..6026798610 --- /dev/null +++ b/extra/thunder/metal/include/ops/warp/warp.metal @@ -0,0 +1,4 @@ +#pragma once +#include "memory/memory.metal" +#include "register/register.metal" +#include "shared/shared.metal" diff --git a/extra/thunder/metal/include/tk.metal b/extra/thunder/metal/include/tk.metal new file mode 100644 index 0000000000..fa660921a2 --- /dev/null +++ b/extra/thunder/metal/include/tk.metal @@ -0,0 +1,4 @@ +#pragma once +#include "common/common.metal" +#include "ops/ops.metal" +#include "types/types.metal" diff --git a/extra/thunder/metal/include/types/global/cgl.metal b/extra/thunder/metal/include/types/global/cgl.metal new file mode 100644 index 0000000000..604d4e7990 --- /dev/null +++ b/extra/thunder/metal/include/types/global/cgl.metal @@ -0,0 +1,63 @@ +/** +* @file +* @brief Templated layouts for complex global memory. +*/ + +#pragma once + +#include "../../common/common.metal" +//#include "../shared/cst.metal" +#include "gl.metal" +#include "util.metal" +#ifdef mittens_HOPPER +#include "tma.metal" +#endif + +namespace mittens { +/* ---------- Global layout descriptor ---------- */ + +namespace ducks { +namespace cgl { +struct identifier {}; +} +} + +template +struct cgl { + static_assert(ducks::is_global_layout, "GL must satisfy global layout requirements."); + + using identifier = ducks::cgl::identifier; + using T = typename GL::T; + using T2 = typename GL::T2; + using dtype = typename GL::dtype; + + GL real, imag; +}; + +namespace ducks { +template +struct has_cgl_identifier { + static constant constexpr bool value = false; // Default case +}; + +//template +//struct has_cgl_identifier> { +// static constant constexpr bool value = true; +//}; +template +struct has_cgl_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_complex_global_layout() { + return has_rt_identifier::value; +} +template +static constexpr void assert_cgl() { + static_assert(is_complex_global_layout(), "T must be a cgl"); +} +} + +} + diff --git a/extra/thunder/metal/include/types/global/gl.metal b/extra/thunder/metal/include/types/global/gl.metal new file mode 100644 index 0000000000..359c64166e --- /dev/null +++ b/extra/thunder/metal/include/types/global/gl.metal @@ -0,0 +1,213 @@ +/** + * @file + * @brief Templated layouts for global memory. + */ + +#pragma once + +#include "../../common/common.metal" +#include "../shared/shared.metal" +#include "../register/register.metal" +#include "util.metal" + + +namespace mittens { +/* ---------- Associative dictionary for global layouts ---------- */ + +namespace detail { +template +struct descriptor_dict { + METAL_FUNC descriptor_dict() {} + template METAL_FUNC descriptor_dict(T _, int b, int d, int r, int c) {} + METAL_FUNC descriptor_dict(thread const descriptor_dict &other) {} +}; +} + +/* ---------- Global layout descriptor ---------- */ + +namespace ducks { +namespace gl { +struct identifier {}; +} + +template +static constexpr bool is_tile() { + return mittens::ducks::is_shared_tile() || mittens::ducks::is_register_tile(); +} + +template +static constexpr bool is_vec() { + return mittens::ducks::is_shared_vector() || mittens::ducks::is_register_vector(); +} +} + + +template +struct gl { + using identifier = ducks::gl::identifier; + + using T = typename base_types::packing<_T>::unpacked_type; + using T2 = typename base_types::packing<_T>::packed_type; + using dtype = T; + + device T* raw_ptr; + + ducks::g::make_dim_t batch; + ducks::g::make_dim_t depth; + ducks::g::make_dim_t rows; + ducks::g::make_dim_t cols; +// int batch; +// int depth; +// int rows; +// int cols; + + METAL_FUNC gl(device T *_data, + ducks::g::make_arg_t _batch, + ducks::g::make_arg_t _depth, + ducks::g::make_arg_t _rows, + ducks::g::make_arg_t _cols) : + raw_ptr(_data), batch(_batch), depth(_depth), rows(_rows), cols(_cols) { + } +// METAL_FUNC gl(device T *_data, +// int _batch, +// int _depth, +// int _rows, +// int _cols) : +// raw_ptr(_data), batch(_batch), depth(_depth), rows(_rows), cols(_cols) { +// } +// + METAL_FUNC gl(thread const gl &other) : + raw_ptr(other.raw_ptr), batch(other.batch), depth(other.depth), rows(other.rows), cols(other.cols) {} + + METAL_FUNC gl(constant const gl &other) : + raw_ptr(other.raw_ptr), batch(other.batch), depth(other.depth), rows(other.rows), cols(other.cols) {} + + METAL_FUNC device T& operator[](const thread coord &idx) { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c]; + } + METAL_FUNC device const T& operator[](const thread coord &idx) const { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c]; + } + template + METAL_FUNC typename metal::enable_if(), device T&>::type + get(const thread coord &idx) { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r*TILE::rows)*cols + idx.c*TILE::cols]; + } + template + METAL_FUNC typename metal::enable_if(), device const T&>::type + get(const thread coord &idx) const { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r*TILE::rows)*cols + idx.c*TILE::cols]; + } + template + METAL_FUNC typename metal::enable_if(), device T&>::type + get(const thread coord &idx) { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c*VEC::length]; + } + template + METAL_FUNC typename metal::enable_if(), device const T&>::type + get(const thread coord &idx) const { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c*VEC::length]; + } + METAL_FUNC size_t row_stride() const { return cols; } +}; + +namespace ducks { +template +struct has_gl_identifier { + static constant constexpr bool value = false; // Default case +}; + +template +struct has_gl_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_global_layout() { + return has_gl_identifier::value; +} +template +static constexpr void assert_gl() { + static_assert(is_global_layout(), "T must be a gl"); +} +} + + + + + + + +template +struct gl2 { + using identifier = ducks::gl::identifier; + + using T = typename base_types::packing<_T>::unpacked_type; + using T2 = typename base_types::packing<_T>::packed_type; + using dtype = T; + + device T* raw_ptr; + +// ducks::g::make_dim_t batch; +// ducks::g::make_dim_t depth; +// ducks::g::make_dim_t rows; +// ducks::g::make_dim_t cols; +// +// METAL_FUNC gl2(device T *_data, +// ducks::g::make_arg_t _batch, +// ducks::g::make_arg_t _depth, +// ducks::g::make_arg_t _rows, +// ducks::g::make_arg_t _cols) : +// raw_ptr(_data), batch(_batch), depth(_depth), rows(_rows), cols(_cols) { +// } + + int batch; + int depth; + int rows; + int cols; + + METAL_FUNC gl2(device T *_data, + int _batch, + int _depth, + int _rows, + int _cols) : + raw_ptr(_data), batch(_batch), depth(_depth), rows(_rows), cols(_cols) { + } + + +// METAL_FUNC gl2(thread const gl2 &other) : +// raw_ptr(other.raw_ptr), batch(other.batch), depth(other.depth), rows(other.rows), cols(other.cols) {} +// +// METAL_FUNC gl2(constant const gl2 &other) : +// raw_ptr(other.raw_ptr), batch(other.batch), depth(other.depth), rows(other.rows), cols(other.cols) {} + + METAL_FUNC device T& operator[](const thread coord &idx) { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c]; + } + METAL_FUNC device const T& operator[](const thread coord &idx) const { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c]; + } + template + METAL_FUNC typename metal::enable_if(), device T&>::type + get(const thread coord &idx) { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r*TILE::rows)*cols + idx.c*TILE::cols]; + } + template + METAL_FUNC typename metal::enable_if(), device const T&>::type + get(const thread coord &idx) const { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r*TILE::rows)*cols + idx.c*TILE::cols]; + } + template + METAL_FUNC typename metal::enable_if(), device T&>::type + get(const thread coord &idx) { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c*VEC::length]; + } + template + METAL_FUNC typename metal::enable_if(), device const T&>::type + get(const thread coord &idx) const { + return raw_ptr[((idx.b*depth + idx.d)*rows + idx.r)*cols + idx.c*VEC::length]; + } + METAL_FUNC size_t row_stride() const { return cols; } +}; + +} diff --git a/extra/thunder/metal/include/types/global/global.metal b/extra/thunder/metal/include/types/global/global.metal new file mode 100644 index 0000000000..73d4ebac03 --- /dev/null +++ b/extra/thunder/metal/include/types/global/global.metal @@ -0,0 +1,9 @@ +/** + * @file + * @brief An aggregate header file for all the global types defined by Thundermittens. + */ + +#pragma once +#include "util.metal" +#include "gl.metal" +#include "cgl.metal" diff --git a/extra/thunder/metal/include/types/global/util.metal b/extra/thunder/metal/include/types/global/util.metal new file mode 100644 index 0000000000..4bb40e7f3f --- /dev/null +++ b/extra/thunder/metal/include/types/global/util.metal @@ -0,0 +1,44 @@ +#pragma once + +namespace mittens { +namespace ducks { +namespace g { + + //template concept cdim = (d > 0); // represents a compile-time dimension + //template concept rdim = (d == -1); // represents a runtime dimension + + template + struct compiled_dim { + static_assert(d > 0, "Invalid compile-time dimension value"); // Replace `cdim` concept check + static constant constexpr uint32_t v = d; + + METAL_FUNC compiled_dim(thread const metal::nullptr_t &_) {} + + METAL_FUNC constexpr operator uint32_t() const { return v; } + }; + + struct runtime_dim { + uint32_t v; + METAL_FUNC runtime_dim(thread const uint32_t &_v) : v(_v) {} + METAL_FUNC operator uint32_t() const { return v; } + }; + + template using make_dim_t = metal::conditional_t>; + template using make_arg_t = metal::conditional_t; // we pass runtime dims as size_t, comptime dims as nullptr_t + +} +} + +struct coord { // essentially a named int4 for tensor coordinates. + int b, d, r, c; + METAL_FUNC coord(int _b, int _d, int _r, int _c) : b(_b), d(_d), r(_r), c(_c) {} + METAL_FUNC coord( int _d, int _r, int _c) : b( 0), d(_d), r(_r), c(_c) {} + METAL_FUNC coord( int _r, int _c) : b( 0), d( 0), r(_r), c(_c) {} + METAL_FUNC coord( int _c) : b( 0), d( 0), r( 0), c(_c) {} + METAL_FUNC coord( ) : b( 0), d( 0), r( 0), c( 0) {} + METAL_FUNC coord(thread const coord &other) : b(other.b), d(other.d), r(other.r), c(other.c) {} + METAL_FUNC coord(thread const int4 &other) : b(other.x), d(other.y), r(other.z), c(other.w) {} + METAL_FUNC operator int4() const { return int4(b, d, r, c); } +}; + +} diff --git a/extra/thunder/metal/include/types/register/crt.metal b/extra/thunder/metal/include/types/register/crt.metal new file mode 100644 index 0000000000..34df657511 --- /dev/null +++ b/extra/thunder/metal/include/types/register/crt.metal @@ -0,0 +1,91 @@ +/** +* @file +* @brief Abstraction for a complex register tile composed of real and imaginary tiles +*/ + +#pragma once + +#include "rt.metal" +#include "crv.metal" + +namespace mittens { + +namespace ducks { +namespace crt { +/** + * @brief A dummy type used to identify complex register tiles. + * + * For a type to quack like an rt_cmplx, it should define its identifier as ducks::rt::cmplx_identifier. + * If a type quacks like ducks::rt::cmplx_identifier, it will be treated as an rt_cmplx by compiler checks. + */ +struct identifier {}; +} // namespace rt +} // namespace ducks + +/** +* @brief Complex tile structure +* +* @tparam T2 The packed data type used for the matrix elements. +* @tparam _rows The height of the tile in terms of the number of subtiles. +* @tparam _cols The width of the tile in terms of the number of subtiles. +* @tparam _layout The layout of the internal register tiles, either row-major or column-major. +* +* This structure is designed to abstract complex number operations internally to the real and imaginary +* register tiles, respectively +* +* In general, you probably want a row-major tile, unless you specifically want to call mma +*/ +template +struct crt { + using identifier = ducks::crt::identifier; + static_assert(ducks::is_rt_layout<_layout>(), "crt was given invalid layout"); + using component = rt<_T, _rows, _cols, _layout>; /// Data type of each internal tile. + using layout = typename component::layout; ///< Layout of the matrix tile, ensures compatibility with the rt concepts + using T = typename component::T; + using T2 = typename component::T2; + using dtype = typename component::dtype; ///< Data type of the elements in the tile. + + constant static constexpr int rows = component::rows; + constant static constexpr int cols = component::cols; + constant static constexpr int height = component::height; + constant static constexpr int width = component::width; + + // Real/imag tiles have same internal layout and size + component real; + component imag; + + using row_vec = crv::row_vec_layout>; ///< A type representing a column vector for this tile. + using col_vec = crv::col_vec_layout>; ///< A type representing a column vector for this tile. +}; + +/* ---------- CONCEPTS ---------- */ + +namespace ducks { +template +struct has_crt_identifier { + static constant constexpr bool value = false; // Default case +}; + +// Specialize for specific template instantiations of st +template +struct has_crt_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_complex_register_tile() { + return has_crt_identifier::value; +} +template +static constexpr void assert_complex_register_tile() { + static_assert(is_register_tile(), "T must be a rt"); +} +} + +template using crt_fl = crt; +template using crt_bf = crt; +template using crt_hf = crt; + + +} + diff --git a/extra/thunder/metal/include/types/register/crv.metal b/extra/thunder/metal/include/types/register/crv.metal new file mode 100644 index 0000000000..730cbc0e15 --- /dev/null +++ b/extra/thunder/metal/include/types/register/crv.metal @@ -0,0 +1,97 @@ +/** +* @file +* @brief Register vectors for computations on axes. +*/ + +#pragma once + +#include "../../common/common.metal" +#include "rv_layout.metal" +#include "rv.metal" + +namespace mittens { + +/* ---------- MAIN VECTOR STRUCT ---------- */ + +// helper struct for type inference +namespace ducks { +/** +* @namespace rt +* +* @brief The namespace where concepts and abstract types for register vectors live. +*/ +namespace crv { +/** + * @brief A dummy type used to identify register vectors. + * + * For a type to quack like an rv, it should define its identifier as ducks::rv::identifier. + * If a type quacks like ducks::rv::identifier, it will be treated as an rv by compiler checks. + */ +struct identifier {}; +} +} +/** +* @brief Register vector structure. +* +* @tparam _T The packed data type used for the vector elements. +* @tparam _outer_dim The size of the tile, in units of TILE_DIM (16). +* @tparam _inner_dim This controls the layout of the tile in terms of which axis it maps on the register tile layout. +* +* Register vectors are used to accumulate and map values across tiles. You can do computation +* on them directly if you want, but they're not designed to be maximally efficient vectors +* as they have substantial duplication and strange layouts to help them work efficiently with +* the register layouts used by the tensor cores. Thundermittens wants you working with tiles +* where possible! +*/ + +template +struct crv { + static_assert(ducks::is_rv_layout<_layout>(), "_layout must be a rv layout"); + static_assert(ducks::base_types::isT1Type<_T>(), "T must be float, bf16, or half"); + using identifier = ducks::crv::identifier; + using component = rv<_T, _length, _layout>; /// Data type of each internal tile. + using layout = typename component::layout; ///< Layout of the matrix tile, ensures compatibility with the rv concepts + + using T = typename component::T; + using T2 = typename component::T2; + using dtype = typename component::dtype; ///< Data type of the elements in the tile. + + constant static constexpr int length = component::length; + constant static constexpr int tiles = component::tiles; + + // Real/imag tiles have same internal layout and size + component real; + component imag; +}; + +/* ---------- CONCEPTS ---------- */ + +namespace ducks { +template +struct has_crv_identifier { + static constant constexpr bool value = false; // Default case +}; + +// Specialize for specific template instantiations of st +template +struct has_crv_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_complex_register_vector() { + return has_crv_identifier::value; +} +template +static constexpr void assert_complex_register_vector() { + static_assert(is_complex_register_vector(), "T must be a crv"); +} +} // namespace ducks + +template using crv_fl = crv; +template using crv_bf = crv; +template using crv_hf = crv; + + +} // namespace mittens + diff --git a/extra/thunder/metal/include/types/register/register.metal b/extra/thunder/metal/include/types/register/register.metal new file mode 100644 index 0000000000..68aed70bc0 --- /dev/null +++ b/extra/thunder/metal/include/types/register/register.metal @@ -0,0 +1,15 @@ +/** + * @file + * @brief An aggregate header file for all the register types defined by Thundermittens. + */ + +#pragma once +#include "crv.metal" +#include "rv.metal" +#include "rv_layout.metal" +#include "crt.metal" +#include "rt.metal" +#include "rt_layout.metal" +#include "rt_base.metal" + + diff --git a/extra/thunder/metal/include/types/register/rt.metal b/extra/thunder/metal/include/types/register/rt.metal new file mode 100644 index 0000000000..62340b79cd --- /dev/null +++ b/extra/thunder/metal/include/types/register/rt.metal @@ -0,0 +1,129 @@ +/** + * @file + * @brief The main Thundermittens register tile struct, where most computation happens. + */ +#pragma once // kinda done +/* + TODO: + consider if column layout rly rly rly makes no sense and no implement needed, not me being lazy + */ +#include +#include "../../common/common.metal" +#include "rt_base.metal" +#include "rv.metal" + +/* ---------- MAIN TILE STRUCT ---------- */ + + +namespace mittens { +/* ---------- MAIN TILE STRUCT ---------- */ +// helper struct for type inference +namespace ducks { +/** + * @namespace rt + * + * @brief The namespace where concepts and abstract types for register tiles live. + */ +namespace rt { +/** + * @brief A dummy type used to identify register tiles. + * + * For a type to quack like an rt, it should define its identifier as ducks::rt::identifier. + * If a type quacks like ducks::rt::identifier, it will be treated as an rt by compiler checks. + */ +struct identifier {}; + +} // namespace rt + +} // namespace ducks + +/** + * @brief Main tile structure for manipulating data in registers. + * + * @tparam _T The data type used for the matrix elements. + * @tparam _height The height of the tile in terms of the number of subtiles. + * @tparam _width The width of the tile in terms of the number of subtiles. + * + * This structure is designed to handle matrix tiles in a flexible manner, allowing + * for operations on tiles that are composed of smaller subtiles. + */ +template +struct rt { + using identifier = ducks::rt::identifier; ///< Type identifier for the rt structure. + using layout = _layout; + using T = typename base_types::packing<_T>::unpacked_type; + static_assert(ducks::base_types::isT1Type(), "T must be float, bf16, or half"); + static_assert(ducks::is_rt_layout<_layout>(), "T must be float, bf16, or half"); + using T2 = typename base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the elements in the tile. + constant static constexpr int rows = _rows; ///< Total number of rows. + static_assert(rows % rt_base::tile_size == 0, "Rows must be divisible by the tile size"); + constant static constexpr int cols = _cols; ///< Total number of columns. + static_assert(cols % rt_base::tile_size == 0, "Columns must be divisible by the tile size"); + constant static constexpr int height = rows / rt_base::tile_size; ///< Height in subtiles. + constant static constexpr int width = cols / rt_base::tile_size; ///< Width in subtiles. + constant static constexpr int tile_size = rt_base::tile_size; ///< Size of the base tile. + constant static constexpr int num_elements = rt_base::num_elements * width * height; ///< Total number of elements. + constant static constexpr int elements_per_thread = rt_base::elements_per_thread * width * height; ///< Elements handled per thread. + constant static constexpr int packed_per_thread = rt_base::packed_per_thread * width * height; ///< Packed elements per thread. + constant static constexpr int packed_per_tile = rt_base::packed_per_thread; ///< Packed elements per tile. + + rt_base tiles[height][width]; ///< The actual storage for the matrix tile, organized in subtiles. + + using row_vec = rv::row_vec_layout>; ///< A type representing a column vector for this tile. + using col_vec = rv::col_vec_layout>; ///< A type representing a column vector for this tile. +}; + + + +namespace ducks{ +template +struct has_rt_identifier { + static constant constexpr bool value = false; // Default case + static constant constexpr bool is_row = false; + static constant constexpr bool is_col = false; +}; + +template +struct has_rt_identifier> { + static constant constexpr bool value = true; + static constant constexpr bool is_row = true; // Row-specific indicator + static constant constexpr bool is_col = false; +}; + +template +struct has_rt_identifier> { + static constant constexpr bool value = true; + static constant constexpr bool is_row = false; + static constant constexpr bool is_col = true; // Col-specific indicator +}; + +template +static constexpr bool is_register_tile() { + return has_rt_identifier::value; +} + +template +static constexpr bool is_row_register_tile() { + return has_rt_identifier::is_row; +} + +template +static constexpr bool is_col_register_tile() { + return has_rt_identifier::is_col; +} + + +template +static constexpr void assert_register_tile() { + static_assert(is_register_tile(), "T must be a rt"); +} +} + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ +// layout and type wrappers + +template using rt_fl = rt; +template using rt_bf = rt; +template using rt_hf = rt; +} // namespace mittens diff --git a/extra/thunder/metal/include/types/register/rt_base.metal b/extra/thunder/metal/include/types/register/rt_base.metal new file mode 100644 index 0000000000..00acc167ee --- /dev/null +++ b/extra/thunder/metal/include/types/register/rt_base.metal @@ -0,0 +1,84 @@ +/** + * @file + * @brief The basic 8x8 register tile on which larger register tiles are built. + */ +#pragma once // todo: col/row layout if needed +#include + +#include "../../common/common.metal" +#include "rt_layout.metal" +#include "rv_layout.metal" +namespace mittens { +/* ---------- BASE 8x8 SUBTILE STRUCT ---------- */ +namespace ducks { +/** + * @namespace rt_base + * + * @brief The namespace where concepts and abstract types for register base (16x16) tiles live. + */ +namespace rt_base { +/** + * @brief A dummy type used to identify register base tiles. + * + * For a type to quack like an rt_base, it should define its identifier as ducks::rt_base::identifier. + * If a type quacks like ducks::rt_base::identifier, it will be treated as an rt_base by compiler checks. + */ +struct identifier {}; +} +template +static constexpr bool is_register_tile_base() { + return metal::is_same::value; +} +template +static constexpr void assert_register_tile_base() { + static_assert(is_register_tile_base(), "T must be a rt_base"); +} +} // namespace ducks + +/** + * @brief Basic tile structure for computation in registers. + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _layout The layout of the base tile, either row-major or column-major. + * + * This type is a primarily utility for building larger inline templates + * out of PTX primitives and managing layouts. + * + * In general, you probably want a row-major tile, unless you specifically want to call mma + */ +template +struct rt_base { + using identifier = ducks::rt_base::identifier; ///< Type identifier for the rt_base structure. + using layout = _layout; ///< Layout of the matrix tile. + static_assert(ducks::base_types::isT1Type<_T>(), "rt_base was provided an unsupported type"); + static_assert(ducks::is_rt_layout(), "rt_base was provided an unsupported layout"); + using T = typename base_types::packing<_T>::unpacked_type; + using T2 = typename base_types::packing<_T>::packed_type; + using dtype = T; + + + + static constant constexpr const int tile_size = mittens::TILE_DIM; + static constant constexpr const int rows = tile_size; + static constant constexpr const int cols = tile_size; + static constant constexpr const int num_elements = rows*cols; + static constant constexpr const int elements_per_thread = num_elements / mittens::SIMD_THREADS; + + static constant constexpr const int registers_per_thread = elements_per_thread; + static constant constexpr const int packed_per_thread = elements_per_thread / base_types::packing::num(); + metal::simdgroup_matrix data; + + using row_vec_layout = metal::conditional_t, ducks::rv_layout::align, ducks::rv_layout::ortho>; // for holding column reductions + + using col_vec_layout = metal::conditional_t, ducks::rv_layout::ortho, ducks::rv_layout::align>; // for holding row reductions +}; + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using rt_base_fl = rt_base; +template using rt_base_bf = rt_base; +template using rt_base_hf = rt_base; + + +} + diff --git a/extra/thunder/metal/include/types/register/rt_layout.metal b/extra/thunder/metal/include/types/register/rt_layout.metal new file mode 100644 index 0000000000..a918a1477a --- /dev/null +++ b/extra/thunder/metal/include/types/register/rt_layout.metal @@ -0,0 +1,45 @@ +/** +* @file +* @brief Layouts and their manipulations for register tiles. +*/ + +#pragma once + + +namespace mittens { +namespace ducks { +/** + * @namespace rt_layout + * + * @brief A namespace for template metaprogramming with register tile layouts. + */ +namespace rt_layout { + +/** + * @brief A dummy type used to identify a row-major layout for a register tile. + */ +struct row {}; // for most matrices +/** + * @brief A dummy type used to identify a col-major layout for a register tile. + */ +struct col {}; // for the B-matrix of MMA ops. + +template struct transpose { using type = rt_layout::col; }; +template<> struct transpose { using type = rt_layout::row; }; +} // namespace rt_layout +template +METAL_FUNC static constexpr bool is_row_layout() { + return metal::is_same_v<_layout, rt_layout::row>; +} +template +METAL_FUNC static constexpr bool is_col_layout() { + return metal::is_same_v<_layout, rt_layout::col>; +} +template +METAL_FUNC static constexpr bool is_rt_layout() { + return is_row_layout<_layout>() || is_col_layout<_layout>(); +} + + +} // namespace ducks +} // namespace mittens diff --git a/extra/thunder/metal/include/types/register/rv.metal b/extra/thunder/metal/include/types/register/rv.metal new file mode 100644 index 0000000000..ece8d966e5 --- /dev/null +++ b/extra/thunder/metal/include/types/register/rv.metal @@ -0,0 +1,125 @@ +/** + * @file + * @brief Register vectors for computations on axes. + */ +#pragma once +#include "../../common/common.metal" +#include "rv_layout.metal" +namespace mittens { +/* ---------- MAIN VECTOR STRUCT ---------- */ + +// helper struct for type inference +namespace ducks { +/** + * @namespace rt + * + * @brief The namespace where concepts and abstract types for register vectors live. + */ +namespace rv { +/** + * @brief A dummy type used to identify register vectors. + * + * For a type to quack like an rv, it should define its identifier as ducks::rv::identifier. + * If a type quacks like ducks::rv::identifier, it will be treated as an rv by compiler checks. + */ +struct identifier {}; +} + +} + +/** + * @brief Register vector structure. + * + * @tparam _T The packed data type used for the vector elements. + * @tparam _outer_dim The size of the tile, in units of TILE_DIM (8). + * @tparam _inner_dim This controls the layout of the tile in terms of which axis it maps on the register tile layout. + * + * Register vectors are used to accumulate and map values across tiles. You can do computation + * on them directly if you want, but they're not designed to be maximally efficient vectors + * as they have substantial duplication and strange layouts to help them work efficiently with + * the register layouts used by the tensor cores. Thundermittens wants you working with tiles + * where possible! + */ + +template +struct rv { + using identifier = ducks::rv::identifier; ///< Type identifier for the rv structure. + + static_assert(ducks::is_rv_layout<_layout>(), "_layout must be a rv layout"); + static_assert(ducks::base_types::isT1Type<_T>(), "T must be float, bf16, or half"); + using layout = _layout; + constant static constexpr bool is_naive = ducks::is_naive_layout(); + using T = typename mittens::base_types::packing<_T>::unpacked_type; + using T2 =typename mittens::base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the matrix elements + + constant static constexpr int length = _length; ///< Length in elements. + static_assert(length % mittens::TILE_DIM == 0, "Length must be divisible by the tile dimension"); + constant static constexpr int tiles = _length / mittens::TILE_DIM; ///< Length in subtiles, aliased for consistency with sv type + constant static constexpr int inner_dim = layout::inner_dim; ///< Internal layout within a subtile. Either 1 or 2. + constant static constexpr int outer_dim = is_naive ? (tiles+3)/4 : tiles; ///< Outer dim (also length in tiles) + dtype data[outer_dim][inner_dim]; ///< The actual register vector data. + + METAL_FUNC thread dtype* operator[](size_t idx) { return &data[idx][0]; } ///< A wrapper for indexing into vector data. + METAL_FUNC thread const dtype* operator[](size_t idx) const { return &data[idx][0]; } ///< A wrapper for indexing into vector data. + METAL_FUNC thread dtype& operator[](int2 outin) { return data[outin.x][outin.y]; } ///< A wrapper for indexing into vector data. + METAL_FUNC thread const dtype& operator[](int2 outin) const { return data[outin.x][outin.y]; } ///< A wrapper for indexing into vector data. +}; + +namespace ducks{ +template +struct has_rv_align_identifier { + static constant constexpr bool value = false; // Default case +}; +template +struct has_rv_align_identifier> { + static constant constexpr bool value = true; +}; +template +static constexpr bool is_align_register_vector() { + return has_rv_align_identifier::value; +} + +template +struct has_rv_ortho_identifier { + static constant constexpr bool value = false; // Default case +}; +template +struct has_rv_ortho_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_ortho_register_vector() { + return has_rv_ortho_identifier::value; +} + +template +struct has_rv_naive_identifier { + static constant constexpr bool value = false; // Default case +}; +template +struct has_rv_naive_identifier> { + static constant constexpr bool value = true; +}; +template +static constexpr bool is_naive_register_vector() { + return has_rv_naive_identifier::value; +} + +template +static constexpr bool is_register_vector() { + return is_align_register_vector() || is_ortho_register_vector() || is_naive_register_vector(); +} + +template +static constexpr void assert_register_vector() { + static_assert(is_register_vector(), "T must be a rv"); +} +} +template using rv_fl = rv; +template using rv_bf = rv; +template using rv_hf = rv; + +} + diff --git a/extra/thunder/metal/include/types/register/rv_layout.metal b/extra/thunder/metal/include/types/register/rv_layout.metal new file mode 100644 index 0000000000..f338a79c30 --- /dev/null +++ b/extra/thunder/metal/include/types/register/rv_layout.metal @@ -0,0 +1,54 @@ +/** +* @file +* @brief Layouts and their manipulations for register tiles. +*/ + +#pragma once + + +namespace mittens { +namespace ducks { +/** +* @namespace rv_layout +* +* @brief A namespace for template metaprogramming with register vector layouts. +*/ +namespace rv_layout { + +/** + * @brief A dummy type used to identify an aligned (8x replicated) layout. + */ +struct align { constant constexpr static int inner_dim = 2; }; +/** + * @brief A dummy type used to identify an orthogonal (4x replicated) layout. + */ +struct ortho { constant constexpr static int inner_dim = 1; }; +/** + * @brief A dummy type used to identify an unreplicated layout, for better coalesced loads and vector operations like layernorm. + */ +struct naive { constant constexpr static int inner_dim = 1; }; + + +} // namespace rv_layout + +template +METAL_FUNC static constexpr bool is_align_layout() { + return metal::is_same_v<_layout, rv_layout::align>; +} +template +METAL_FUNC static constexpr bool is_ortho_layout() { + return metal::is_same_v<_layout, rv_layout::ortho>; +} +template +METAL_FUNC static constexpr bool is_naive_layout() { + return metal::is_same_v<_layout, rv_layout::naive>; +} +template +METAL_FUNC static constexpr bool is_rv_layout() { + return is_align_layout<_layout>() || is_ortho_layout<_layout>() || is_naive_layout<_layout>(); +} + + + +} // namespace ducks +} // namespace mittens diff --git a/extra/thunder/metal/include/types/shared/cst.metal b/extra/thunder/metal/include/types/shared/cst.metal new file mode 100644 index 0000000000..bf67820005 --- /dev/null +++ b/extra/thunder/metal/include/types/shared/cst.metal @@ -0,0 +1,94 @@ +/** +* @file +* @brief Abstraction for a complex register tile composed of real and imaginary tiles +*/ + +#pragma once + +#include "st.metal" +#include "csv.metal" +namespace mittens { +namespace ducks { +namespace cst { +/** + * @brief A dummy type used to identify complex register tiles. + * + * For a type to quack like an st_cmplx, it should define its identifier as ducks::st::cmplx_identifier. + * If a type quacks like ducks::st::cmplx_identifier, it will be treated as an st_cmplx by compiler checks. + */ +struct identifier {}; +} // namespace st +} // namespace ducks + +/** + * @brief Complex tile structure + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _rows The height of the tile in terms of the number of subtiles. + * @tparam _cols The width of the tile in terms of the number of subtiles. + * @tparam _layout The layout of the internal register tiles + * + * This structure is designed to abstract complex number operations internally to the real and imaginary + * shared tiles, respectively + * + * + */ +template +struct cst { + using identifier = ducks::cst::identifier; + using component = st<_T, _rows, _cols>; /// Data type of each internal tile. + using T = typename component::T; + using T2 = typename component::T2; + using dtype = typename component::dtype; ///< Data type of the elements in the tile. + + constant static constexpr int rows = component::rows; + constant static constexpr int cols = component::cols; + constant static constexpr int height = component::height; + constant static constexpr int width = component::width; + + // todo: fill in the rest for convenience, but they're all accessible via component so it's not urgent. + + // Real/imag tiles have same internal layout and size + component real; + component imag; + + // vector types + using col_vec = csv; + using row_vec = csv; +}; + +/* ---------- CONCEPTS ---------- */ + +namespace ducks { +template +struct has_cst_identifier { + static constant constexpr bool value = false; // Default case +}; + +// Specialize for specific template instantiations of st +template +struct has_cst_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_complex_shared_tile() { + return has_cst_identifier::value; +} +template +static constexpr void assert_complex_shared_tile() { + static_assert(is_complex_shared_tile(), "T must be a cst"); +} + +} // namespace ducks + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using cst_bf = cst; +template using cst_hf = cst; +template using cst_fl = cst; + + + +} diff --git a/extra/thunder/metal/include/types/shared/csv.metal b/extra/thunder/metal/include/types/shared/csv.metal new file mode 100644 index 0000000000..524147b512 --- /dev/null +++ b/extra/thunder/metal/include/types/shared/csv.metal @@ -0,0 +1,86 @@ +/** +* @file +* @brief Abstraction for a complex register tile composed of real and imaginary tiles +*/ + +#pragma once + +#include "st.metal" + +namespace mittens { +namespace ducks { +namespace csv { +/** + * @brief A dummy type used to identify complex register tiles. + * + * For a type to quack like an st_cmplx, it should define its identifier as ducks::st::cmplx_identifier. + * If a type quacks like ducks::st::cmplx_identifier, it will be treated as an st_cmplx by compiler checks. + */ +struct identifier {}; +} // namespace st +} // namespace ducks + +/** + * @brief Complex tile structure + * + * @tparam T2 The packed data type used for the matrix elements. + * @tparam _height The height of the tile in terms of the number of subtiles. + * @tparam _width The width of the tile in terms of the number of subtiles. + * @tparam _layout The layout of the internal register tiles + * + * This structure is designed to abstract complex number operations internally to the real and imaginary + * shared tiles, respectively + * + * + */ +template +struct csv { + using identifier = ducks::csv::identifier; + using component = sv<_T, _length>; /// Data type of each internal tile. + using T = typename component::T; + using T2 = typename component::T2; + using dtype = typename component::dtype; ///< Data type of the elements in the tile. + + constant static constexpr int length = component::length; + constant static constexpr int tiles = component::tiles; + + // todo: fill in the rest for convenience, but they're all accessible via component so it's not urgent. + + // Real/imag tiles have same internal layout and size + component real; + component imag; +}; + +/* ---------- CONCEPTS ---------- */ + +namespace ducks { +template +struct has_csv_identifier { + static constant constexpr bool value = false; // Default case +}; + +// Specialize for specific template instantiations of st +template +struct has_csv_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_complex_shared_vector() { + return has_csv_identifier::value; +} +template +static constexpr void assert_complex_shared_vector() { + static_assert(is_complex_shared_vector(), "T must be a csv"); +} +} // namespace ducks + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +template using csv_bf = csv; +template using csv_hf = csv; +template using csv_fl = csv; + +} + diff --git a/extra/thunder/metal/include/types/shared/shared.metal b/extra/thunder/metal/include/types/shared/shared.metal new file mode 100644 index 0000000000..9bffd30dc9 --- /dev/null +++ b/extra/thunder/metal/include/types/shared/shared.metal @@ -0,0 +1,10 @@ +/** + * @file + * @brief An aggregate header file for all the shared types defined by Thundermittens. + */ + +#pragma once +#include "st.metal" +#include "sv.metal" +#include "cst.metal" +#include "csv.metal" diff --git a/extra/thunder/metal/include/types/shared/st.metal b/extra/thunder/metal/include/types/shared/st.metal new file mode 100644 index 0000000000..811a523f3d --- /dev/null +++ b/extra/thunder/metal/include/types/shared/st.metal @@ -0,0 +1,379 @@ +/** + * @file + * @brief The Thundermittens shared tile struct. + */ + +#pragma once // kinda done + +/* + add subtile, make it work + */ +#include +#include "../../common/common.metal" +#include "sv.metal" +/* ---------- MAIN TILE STRUCT ---------- */ + +// these are helper structs for type inference +namespace mittens { + +namespace ducks { +/** + * @namespace st + * + * @brief The namespace where concepts and abstract types for shared tiles live. + */ +namespace st { +/** + * @brief A dummy type used to identify shared tiles. + * + * For a type to quack like an st, it should define its identifier as ducks::st::identifier. + * If a type quacks like ducks::st::identifier, it will be treated as an st by compiler checks. + * This is particularly useful for subtiles. + */ +struct identifier {}; +} // namespace st + +}// namespace ducks + +// Forward declaration of subtile +template< + typename ST, + int _subtile_height, + int _subtile_width +> +struct st_subtile; + +/** + * @brief Shared memory tile structure for various data types and layouts. + * + * @tparam T The data type of the elements in the tile. Not packed! + * @tparam _height The height of the tile in units of 8-element subtiles. + * @tparam _width The width of the tile in units of 8-element subtiles. + */ +template +struct mittens_DEFAULT_ALIGN st { + using identifier = ducks::st::identifier; ///< Type identifier for the rt structure. + using T = typename base_types::packing<_T>::unpacked_type; + using T2 = typename base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the elements in the tile. + static_assert(base_types::packing::num() == 1, "st type must be 1-packed (float, bf16, etc)"); // must be a 1-packed type (e.g. float, bf16, etc) + // define underlying data as same as that projected, to make clear that this is *not* a subtile. + static constant constexpr const int underlying_rows = _rows; + static constant constexpr const int underlying_cols = _cols; + static constant constexpr const int underlying_height = _rows / TILE_DIM; + static constant constexpr const int underlying_width = _cols / TILE_DIM; + static constant constexpr const int underlying_num_elements = underlying_rows * underlying_cols; + + static constant constexpr const int rows = _rows; ///< Total number of rows in the tile. + static_assert(rows % TILE_DIM == 0, "Rows must be divisible by the tile dimension"); + static constant constexpr const int cols = _cols; ///< Total number of cols in the tile. + static_assert(cols % TILE_DIM == 0, "Rows must be divisible by the tile dimension"); + static constant constexpr const int height = _rows / TILE_DIM; ///< Height of the tile in terms of 16-element subtiles. + static constant constexpr const int width = _cols / TILE_DIM; ///< Width of the tile in terms of 16-element subtiles. + + static constant constexpr const int num_elements = rows * cols; ///< Total number of elements in the tile. +// static constant constexpr const int row_incr = 32 / memcpy_per_row; + + + + dtype data[rows*cols]; ///< Raw data storage for the tile. + + + + /* ---------- static vars ---------- */ +// /* static METAL_FUNC threadgroup float* idx(threadgroup float *ptr, int r, int c)*/ + static constant constexpr const int swizzle_bytes = underlying_width % 4 == 0 ? 128 : underlying_width%2==0 ? 64 : 32; + static constant constexpr const int swizzle_repeat = swizzle_bytes * 8; + static constant constexpr const int subtile_cols = swizzle_bytes / sizeof(T); + + static constant constexpr const int subtile_cols_log2 = (swizzle_bytes == 128) ? 5 : (swizzle_bytes == 64) ? 4 : 3; + static constant constexpr const int subtile_cols_mask = subtile_cols - 1; + static constant constexpr int swizzle_mask = swizzle_repeat - 1; + static constant constexpr int swizzle_offset_shift = 7; + static constant constexpr int swizzle_adjust_shift = 4; + static constant constexpr int mask = (swizzle_repeat - 1) >> swizzle_offset_shift; + +// static constant constexpr const int load_block_bytes = 8; + static constant constexpr const int laod_block_words = 4; +// static constant constexpr const int load_block_words = 2; + static constant constexpr const int col_load_block_words = cols / laod_block_words; + static constant constexpr const int load_block_words_mask = laod_block_words - 1; + + + static METAL_FUNC threadgroup T* idx(threadgroup T * __restrict ptr, int2 coord) { // naive row-major index default + int r = coord.x, c = coord.y; + return ptr + r * underlying_cols + c; +// +// c = (c + ((r / 2) * 8)) % cols; +// return ptr + r * underlying_cols + c; +//// CORRECT 0.124 | 0.168 +// const int outer_idx = c/subtile_cols; +// const uint64_t addr = (uint64_t)(&ptr[outer_idx*rows*subtile_cols + r*subtile_cols + c%subtile_cols]); +// const int swizzle = ((addr % swizzle_repeat) >> 7) << 4; +// return (threadgroup T*)(addr ^ swizzle); + +// const int outer_idx = c/subtile_cols; +// ptr = &ptr[outer_idx*rows*subtile_cols + r*subtile_cols + c%subtile_cols]; +// const int swizzle = (((uintptr_t)ptr % swizzle_repeat) >> 7) << 4; +// return (threadgroup T*)((uintptr_t)ptr ^ swizzle); +//// +//// CORRECT 0.097 | 0.120 +// int idx = (((c >> subtile_cols_log2) * rows + r) << subtile_cols_log2) + (c & subtile_cols_mask); +// // Compute address in bytes (since ptr is float*, multiply idx by sizeof(float) = 4) +// int addr_bytes = idx << 2; // Equivalent to idx * 4 +// // Compute swizzle without modulo operation +// int swizzle = (((addr_bytes & swizzle_mask) >> 7) << 4); +// // Compute final swizzled address +// return (threadgroup T*)((threadgroup char*)ptr + (addr_bytes ^ swizzle)); +// +//// CORRECT ____ | 0.169 +// int idx = (((c >> subtile_cols_log2) * rows + r) << subtile_cols_log2) + (c & subtile_cols_mask); +// +// // Compute address in bytes (since ptr is float*, multiply idx by sizeof(float) = 4) +// uint64_t addr_bytes = ((uint64_t)ptr) + ((uint64_t)idx << 2); // Full address in bytes +// +// // Compute swizzle including the base address +// int swizzle = ((addr_bytes % swizzle_repeat) >> 7) << 4; +// +// // Compute final swizzled address +// addr_bytes ^= swizzle; +// +// // Return the swizzled address +// return (threadgroup float*)(addr_bytes); +// + } + static METAL_FUNC uint32_t idx(uint32_t ptr, int2 coord) { // naive row-major index + int r = coord.x, c = coord.y; // alias + return ptr + sizeof(T) * (r * underlying_cols + c); + +// c = (c + ((r / 2) * 8)) % cols; +// return ptr + r * underlying_cols + c; +// return ptr + sizeof(T) * (r * underlying_cols + c); + } + /** + * @brief Access a shared tile element using a row and column, as if the tile were row-major. + * + * This is the preferred way to access memory within a shared tile, which abstracts + * indexing calculations for swizzled layouts. + */ + METAL_FUNC threadgroup T& operator[](thread const int2& rowcol) threadgroup { + return *idx(data, rowcol); + } + METAL_FUNC const threadgroup T& operator[](thread const int2 &rowcol) const threadgroup { + return *(const threadgroup T*)idx((threadgroup T*)data, rowcol); + } + + METAL_FUNC threadgroup T& operator[](int idx) threadgroup { + return data[idx]; + } + METAL_FUNC const threadgroup T& operator[](int idx) const threadgroup { + return data[idx]; + } + + using col_vec = sv; ///< Column vector type for this tile + using row_vec = sv; ///< Row vector type for this tile + template using subtile = st_subtile< + st, subtile_rows, subtile_cols + >; ///< A templated subtile type wrapper for this tile. +}; + + +/** + * @brief A reference into a chunk of shared tile memory. + * + * The st_subtile is a drop-in replacement for an st which internally + * references the appropriate memory while performing minimal address + * calculations. You should never create this directly, but instead + * have subtile_inplace return it for you instead. (`auto` is nice.) + * + * You can generally just pretend this is an st. But not for wgmma's. + */ +template< + typename _ST, + int _subtile_rows, + int _subtile_cols +> +struct st_subtile { + using identifier = ducks::st::identifier; // i quack like an st, gcc will never know the difference + using ST = _ST; + using T = typename ST::T; + using T2 = typename ST::T2; + using dtype = T; ///< Data type of the elements in the tile. + + + constant static constexpr int underlying_rows = ST::underlying_rows; + static_assert(underlying_rows % TILE_DIM == 0, "Underlying rows must be divisible by the tile dimension"); + constant static constexpr int underlying_cols = ST::underlying_cols; + static_assert(underlying_cols % TILE_DIM == 0, "Underlying cols must be divisible by the tile dimension"); + constant static constexpr int underlying_height = ST::underlying_height; + constant static constexpr int underlying_width = ST::underlying_width; + constant static constexpr int underlying_num_elements = ST::underlying_num_elements; + + constant static constexpr int rows = _subtile_rows; + static_assert(rows % TILE_DIM == 0, "Rows must be divisible by the tile dimension"); + constant static constexpr int cols = _subtile_cols; + static_assert(cols % TILE_DIM == 0, "Cols must be divisible by the tile dimension"); + constant static constexpr int height = rows / TILE_DIM; + constant static constexpr int width = cols / TILE_DIM; + constant static constexpr int num_elements = rows * cols; + +// constant static constexpr int swizzle_bytes = ST::swizzle_bytes; + +// device dtype *data; + threadgroup T* data; + int row_offset, col_offset; + +// METAL_FUNC st_subtile(threadgroup ST &src, int2 rowcol) { +// data = reinterpret_cast(&src.data[0]); +// row_offset = rowcol.x * rows; +// col_offset = rowcol.y * cols; +// } +// void METAL_FUNC init_subtile(threadgroup ST &src, int2 rowcol) { +//// data = &(src.data[0]); +// row_offset = rowcol.x * rows; +// col_offset = rowcol.y * cols; +// } + template + static void METAL_FUNC init_subtile(threadgroup SUBTILE& sub_st, threadgroup ST& src, int2 rowcol) { + sub_st.data = (threadgroup T*)src.data; + sub_st.row_offset = rowcol.x * rows; + sub_st.col_offset = rowcol.y * cols; + } + + template + static void METAL_FUNC init_subtile(thread SUBTILE& sub_st, threadgroup ST& src, int2 rowcol) { + sub_st.data = (threadgroup T*)src.data; + sub_st.row_offset = rowcol.x * rows; + sub_st.col_offset = rowcol.y * cols; + } + +// METAL_FUNC threadgroup T* idx(threadgroup T *ptr, const int2 coord) { // naive row-major index default +// int r = coord.x+row_offset, c = coord.y+col_offset; // alias +// return ptr + r * underlying_cols + c; +// } +// // Add this const overload of idx +// METAL_FUNC const threadgroup T* idx(const threadgroup T *ptr, const int2 coord) const { +// int r = coord.x + row_offset, c = coord.y + col_offset; +// return ptr + r * underlying_cols + c; +// } +// +// METAL_FUNC uint32_t idx(uint32_t ptr, const int2 coord) const { // naive row-major index default +// int r = coord.x+row_offset, c = coord.y+col_offset; // alias +// return ptr + sizeof(T) * (r * underlying_cols + c); +// } +// METAL_FUNC threadgroup T& operator[](thread const int2 &rowcol) threadgroup { +// return *idx(data, rowcol); +// } +// METAL_FUNC const threadgroup T& operator[](thread const int2 &rowcol) const threadgroup { +// return *idx(data, rowcol); +// } + // Declare idx as a const member function +// METAL_FUNC threadgroup T* idx(threadgroup T * __restrict ptr, const int2 coord) const { +// int r = coord.x + row_offset, c = coord.y + col_offset; +// return ptr + r * underlying_cols + c; +// } +// +// // New idx function (const overload) +// METAL_FUNC uint32_t idx(uint32_t ptr, int2 coord) { +// int r = coord.x + row_offset, c = coord.y + col_offset; +// return ptr + r * underlying_cols + c; +// } +// +// // Non-const operator[] +// METAL_FUNC threadgroup T& operator[](thread const int2& rowcol) threadgroup { +// return *idx(data, rowcol); +// } +// +// // Const operator[] +// METAL_FUNC const threadgroup T& operator[](thread const int2 &rowcol) threadgroup const { +// return *idx(data, rowcol); +// } + // idx function returning threadgroup T* + METAL_FUNC threadgroup T* idx(threadgroup T * __restrict ptr, const int2 coord) threadgroup const { + int r = coord.x + row_offset, c = coord.y + col_offset; + return ptr + r * underlying_cols + c; + } + + // idx function returning uint32_t + METAL_FUNC uint32_t idx(uint32_t ptr, int2 coord) threadgroup const { + int r = coord.x + row_offset, c = coord.y + col_offset; + return ptr + r * underlying_cols + c; + } + + // Non-const operator[] + METAL_FUNC threadgroup T& operator[](thread const int2& rowcol) threadgroup { + return *idx(data, rowcol); + } + + // Const operator[] + METAL_FUNC const threadgroup T& operator[](thread const int2 &rowcol) threadgroup const { + return *idx(data, rowcol); + } + + + METAL_FUNC threadgroup T* idx(threadgroup T * __restrict ptr, const int2 coord) thread const { + int r = coord.x + row_offset, c = coord.y + col_offset; + return ptr + r * underlying_cols + c; + } + + // idx function returning uint32_t + METAL_FUNC uint32_t idx(uint32_t ptr, int2 coord) thread const { + int r = coord.x + row_offset, c = coord.y + col_offset; + return ptr + r * underlying_cols + c; + } + + // Non-const operator[] + METAL_FUNC threadgroup T& operator[](thread const int2& rowcol) thread { + return *idx(data, rowcol); + } + + // Const operator[] + METAL_FUNC const threadgroup T& operator[](thread const int2 &rowcol) thread const { + return *idx(data, rowcol); + } + + + + + // single-index operator[] is left undefined as it would likely be an improper use of st_subtile type. + // can of course be end-run by just accessing .data directly. + +}; + +namespace ducks{ +template +struct has_st_identifier { + static constant constexpr bool value = false; // Default case +}; + +// Specialize for specific template instantiations of st +template +struct has_st_identifier> { + static constant constexpr bool value = true; +}; + +template +struct has_st_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_shared_tile() { + return has_st_identifier::value; +} +template +static constexpr void assert_shared_tile() { + static_assert(is_shared_tile(), "T must be a st"); +} +} + + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ + +// layout and type wrappers +template using st_bf = st; +template using st_hf = st; +template using st_fl = st; +} // namespace mittens + diff --git a/extra/thunder/metal/include/types/shared/sv.metal b/extra/thunder/metal/include/types/shared/sv.metal new file mode 100644 index 0000000000..d1436fcdeb --- /dev/null +++ b/extra/thunder/metal/include/types/shared/sv.metal @@ -0,0 +1,86 @@ +/** + * @file + * @brief The Thundermittens shared vector struct. + */ + +#pragma once +#include "../../common/common.metal" +#include +namespace mittens { +namespace ducks { +/** +* @namespace sv +* +* @brief The namespace where concepts and abstract types for shared vectors live. +*/ +namespace sv { +/** + * @brief A dummy type used to identify shared vectors. + * + * For a type to quack like an sv, it should define its identifier as ducks::sv::identifier. + * If a type quacks like ducks::sv::identifier, it will be treated as an sv by compiler checks. + */ +struct identifier {}; +} +} + + +/** + * @brief Shared vector structure. + * + * @tparam _T The packed data type used for the vector elements. + * @tparam _tiles The size of the tile, in units of TILE_DIM (16). + * + * Shared vectors are used to accumulate and map values across shared tiles. + * Unlike every other structure present in Thundermittens, these have a simple + * uniform layout which is just an array in memory. EZ! + */ +template +struct mittens_DEFAULT_ALIGN sv { + using identifier = ducks::sv::identifier; + using T = typename base_types::packing<_T>::unpacked_type; + using T2 = typename base_types::packing<_T>::packed_type; + using dtype = T; ///< Data type of the elements in the tile. + + constant static constexpr int length = _length; ///< Length in elements. + static_assert(length % TILE_DIM == 0, "Length must be divisible by the tile dimension"); + constant static constexpr int tiles = length / TILE_DIM; ///< Length in subtiles. + + dtype data[length]; ///< The actual shared vector data. + + METAL_FUNC threadgroup dtype& operator[](size_t idx) threadgroup { return data[idx]; } + METAL_FUNC const threadgroup dtype& operator[](size_t idx) const threadgroup { return data[idx]; } + + template using subvec = sv; +}; + + +namespace ducks { +template +struct has_sv_identifier { + static constant constexpr bool value = false; // Default case +}; + +// Specialize for specific template instantiations of st +template +struct has_sv_identifier> { + static constant constexpr bool value = true; +}; + +template +static constexpr bool is_shared_vector() { + return has_sv_identifier::value; +} +template +static constexpr void assert_shared_vector() { + static_assert(is_shared_vector(), "T must be a sv"); +} +} + + +template using sv_bf = sv; +template using sv_hf = sv; +template using sv_fl = sv; +} + + diff --git a/extra/thunder/metal/include/types/types.metal b/extra/thunder/metal/include/types/types.metal new file mode 100644 index 0000000000..3cc216e922 --- /dev/null +++ b/extra/thunder/metal/include/types/types.metal @@ -0,0 +1,49 @@ +#pragma once +#include "global/global.metal" +#include "register/register.metal" +#include "shared/shared.metal" + + +/* ---------- WRAPPERS FOR PRETTINESS ---------- */ +namespace mittens { +/** + * @brief Row vector type alias. + * + * This template alias provides a convenient way to refer to the row vector type + * associated with a given class or type `T`. It assumes that the class `T` has + * a nested type named `row_vec`. + * + * @tparam T The class or type for which the row vector type is defined. + * + * Example usage: + * @code + * mittens::row_vec row_vector; + * @endcode + */ +template +using row_vec = typename T::row_vec; + +/** + * @brief Column vector type alias. + * + * This template alias provides a convenient way to refer to the column vector type + * associated with a given class or type `T`. It assumes that the class `T` has + * a nested type named `col_vec`. + * + * @tparam T The class or type for which the column vector type is defined. + * + * Example usage: + * @code + * mittens::col_vec col_vector; + * @endcode + */ +template +using col_vec = typename T::col_vec; + +// register vector layouts +using align_l = ducks::rv_layout::align; +using ortho_l = ducks::rv_layout::ortho; +using naive_l = ducks::rv_layout::naive; + +// ^ this code lives here because it applies to both sv and rv types +} diff --git a/extra/thunder/tiny/tk/__init__.py b/extra/thunder/tiny/tk/__init__.py new file mode 100644 index 0000000000..27dfca23e2 --- /dev/null +++ b/extra/thunder/tiny/tk/__init__.py @@ -0,0 +1 @@ +WARP_THREADS = 32 diff --git a/extra/thunder/tiny/tk/group.py b/extra/thunder/tiny/tk/group.py new file mode 100644 index 0000000000..5ab1e4a01b --- /dev/null +++ b/extra/thunder/tiny/tk/group.py @@ -0,0 +1,287 @@ +import math, functools +from typing import cast, Callable +from tinygrad import Tensor, Device, Context, GlobalCounters, dtypes +from tinygrad.uop.ops import AxisType, UOp, KernelInfo, Ops +from tinygrad.engine.realize import ExecItem, get_runner +from tinygrad.dtype import AddrSpace, PtrDType +from tinygrad.helpers import getenv, prod + +from extra.thunder.tiny.tk import WARP_THREADS +from extra.thunder.tiny.tk.tiles import RT + +class Group: + def __init__(self, warps:int, ker): + self.warps = warps + self.group_threads = warps * WARP_THREADS + self.threadIdx_x = ker.threadIdx_x + self.ker = ker + + # helpers + @property + def laneid(self): return self.threadIdx_x % self.group_threads + @property + def warpid(self): return self.laneid // WARP_THREADS + @property + def groupid(self): return self.threadIdx_x // self.group_threads + + # ops that only work on a single warp + + clear_rid = 1000 + def clear(self, reg:UOp, value:float=0): + assert self.warps == 1 + + i = UOp.range(reg.size, Group.clear_rid) + Group.clear_rid += 1 + + reg_store = reg.reshape((reg.size,))[i].store(value).end(i) + + self.ker.push_store(reg_store, reg) + return reg.after(reg_store).reshape(reg.shape) + + def zero(self, reg:UOp): return self.clear(reg, 0) + def neg_inf(self, reg:UOp): return self.clear(reg, -math.inf) + + copy_rid = 300 + def copy(self, dst:UOp, src:UOp): + assert self.warps == 1 + + assert dst.shape == src.shape + assert cast(PtrDType, dst.dtype).addrspace == AddrSpace.REG + assert cast(PtrDType, src.dtype).addrspace == AddrSpace.REG + + rngs_for_shape = tuple(UOp.range(dim, Group.copy_rid + i) for i, dim in enumerate(dst.shape)) + Group.copy_rid += len(dst.shape) + + dst_store = dst[*rngs_for_shape].store(src[*rngs_for_shape].cast(dst.dtype.base)).end(*rngs_for_shape) + + self.ker.push_store(dst_store, dst) + return dst.after(dst_store).reshape(dst.shape) + + mma_rid = 600 + def mma_AB(self, c:UOp, a:UOp, b:UOp, after=True): + assert self.warps == 1 + + mma_i_height = UOp.range(c.shape[-3], Group.mma_rid) + mma_i_width = UOp.range(c.shape[-2], Group.mma_rid+1) + mma_i_inner = UOp.range(a.shape[-2], Group.mma_rid+2, AxisType.REDUCE) + Group.mma_rid += 3 + + wmma_arg = ("WMMA_8_16_16_bfloat16_float", (8, 16, 16), dtypes.bfloat16, dtypes.float, "CUDA", 32, (((4, 2), (3, 2), (8, 2)), ((4, 2), (3, 2)), ((4, 2), (3, 2))), ()) + + a_in = UOp.vectorize(*[a[mma_i_height, mma_i_inner, i] for i in range(8)]) + b_in1 = UOp.vectorize(*([b[mma_i_inner, mma_i_width, i] for i in range(2)] + [b[mma_i_inner, mma_i_width, 4+i] for i in range(2)])) + c_out1 = UOp.vectorize(*[c[mma_i_height, mma_i_width, i] for i in range(4)]) + b_in2 = UOp.vectorize(*([b[mma_i_inner, mma_i_width, 2+i] for i in range(2)] + [b[mma_i_inner, mma_i_width, 6+i] for i in range(2)])) + c_out2 = UOp.vectorize(*[c[mma_i_height, mma_i_width, 4+i] for i in range(4)]) + + out1 = UOp(Ops.WMMA, dtypes.float32.vec(4), (a_in, b_in1, c_out1), arg=wmma_arg) + out2 = UOp(Ops.WMMA, dtypes.float32.vec(4), (a_in, b_in2, c_out2), arg=wmma_arg) + c_i = [c[mma_i_height, mma_i_width, i].store(out1.gep(i)) for i in range(4)] + [c[mma_i_height, mma_i_width, 4+i].store(out2.gep(i)) for i in range(4)] + c_store = UOp.group(*c_i).end(mma_i_height, mma_i_width, mma_i_inner) + + self.ker.push_store(c_store, c) + return c.after(c_store).reshape(c.shape) if after else c_store + + def mma_ABt(self, c:UOp, a:UOp, b:UOp, after=True): + assert self.warps == 1 + + mma_i_height = UOp.range(c.shape[-3], Group.mma_rid) + mma_i_width = UOp.range(c.shape[-2], Group.mma_rid+1) + mma_i_inner = UOp.range(a.shape[-2], Group.mma_rid+2, AxisType.REDUCE) + Group.mma_rid += 3 + + wmma_arg = ("WMMA_8_16_16_bfloat16_float", (8, 16, 16), dtypes.bfloat16, dtypes.float, "CUDA", 32, (((4, 2), (3, 2), (8, 2)), ((4, 2), (3, 2)), ((4, 2), (3, 2))), ()) + + a_in = UOp.vectorize(*[a[mma_i_height, mma_i_inner, i] for i in range(8)]) + b_in1 = UOp.vectorize(*([b[mma_i_width, mma_i_inner, i] for i in range(2)] + [b[mma_i_width, mma_i_inner, 4+i] for i in range(2)])) + c_out1 = UOp.vectorize(*[c[mma_i_height, mma_i_width, i] for i in range(4)]) + b_in2 = UOp.vectorize(*([b[mma_i_width, mma_i_inner, 2+i] for i in range(2)] + [b[mma_i_width, mma_i_inner, 6+i] for i in range(2)])) + c_out2 = UOp.vectorize(*[c[mma_i_height, mma_i_width, 4+i] for i in range(4)]) + + out1 = UOp(Ops.WMMA, dtypes.float32.vec(4), (a_in, b_in1, c_out1), arg=wmma_arg) + out2 = UOp(Ops.WMMA, dtypes.float32.vec(4), (a_in, b_in2, c_out2), arg=wmma_arg) + c_i = [c[mma_i_height, mma_i_width, i].store(out1.gep(i)) for i in range(4)] + [c[mma_i_height, mma_i_width, 4+i].store(out2.gep(i)) for i in range(4)] + c_store = UOp.group(*c_i).end(mma_i_height, mma_i_width, mma_i_inner) + + self.ker.push_store(c_store, c) + return c.after(c_store).reshape(c.shape) if after else c_store + + map_rid = 400 + def map(self, a:UOp, op:Callable[[UOp], UOp]|Callable[[UOp, tuple], UOp]): + assert self.warps == 1 + + rngs_for_shape = tuple(UOp.range(dim, Group.map_rid + i) for i, dim in enumerate(a.shape)) + Group.map_rid += len(a.shape) + + if op.__code__.co_argcount == 1: + to_store = op(a[*rngs_for_shape]) + else: + to_store = op(a[*rngs_for_shape], rngs_for_shape) + + a_store = a[*rngs_for_shape].store(to_store).end(*rngs_for_shape) + + self.ker.push_store(a_store, a) + return a.after(a_store).reshape(a.shape) + + def row_reduce(self, vec:UOp, src:UOp, op:Callable[[UOp, UOp], UOp]): + assert self.warps == 1 + + red_local = self.ker.alloc((self.group_threads, 2), src.dtype.base, AddrSpace.LOCAL) + red_reg = self.ker.alloc((2,), src.dtype.base, AddrSpace.REG) + + for height in self.ker.range(src.shape[-3], track=False): + i = UOp.range(red_reg.size, Group.clear_rid) + Group.clear_rid += 1 + red_reg = red_reg.after(height, *[tkr._rng for tkr in self.ker.range_stack]) + reg_store = red_reg.flatten()[i].store(0.).end(i) + red_reg = red_reg.after(reg_store).reshape(red_reg.shape) + + for i_outer in self.ker.range(2, track=False): + for width in self.ker.range(src.shape[-2], AxisType.REDUCE, track=False): + for i_inner in self.ker.range(4, AxisType.REDUCE, track=False): + elem_index = i_inner + 2 * (i_inner // 2) + i_outer * 2 + reg_store = red_reg[i_outer].store(op(red_reg[i_outer], src[height, width, elem_index])).end(i_inner, width, i_outer) + red_reg = red_reg.after(reg_store).reshape(red_reg.shape) + + # store to shared memory + for i_outer in self.ker.range(2, track=False): + red_local_store = red_local[self.laneid, i_outer].store(red_reg[i_outer]).end(i_outer) + red_local = red_local.after(red_local_store.barrier()).reshape(red_local.shape) + + # reduce from shared memory + for i_outer in self.ker.range(2, track=False): + for i_inner in self.ker.range(3, AxisType.REDUCE, track=False): + offset = (self.laneid // 4) * 4 + ((self.laneid + i_inner + 1) % 4) + reg_store = red_reg[i_outer].store(op(red_reg[i_outer], red_local[offset, i_outer])).end(i_inner, i_outer) + red_reg = red_reg.after(reg_store).reshape(red_reg.shape) + + # reduce with vec + for i_outer in self.ker.range(2, track=False): + vec_store = vec[height, 0, i_outer].store(op(vec[height, 0, i_outer], red_reg[i_outer])).end(i_outer, height) + + self.ker.push_store(vec_store, vec) + return vec.after(vec_store).reshape(vec.shape) + + # ops that can work across multiple warps + + LOAD_INNER = 8 + load_rid = 100 + def load(self, dst:UOp, src:UOp, dst_idxs:tuple[UOp|int,...]=(), idxs:tuple[UOp|int,...]=(), axis:int=0, transpose:bool=False): + assert isinstance(dst.dtype, PtrDType) and isinstance(src.dtype, PtrDType) + dst_dtype, src_dtype = cast(PtrDType, dst.dtype), cast(PtrDType, src.dtype) + if dst_dtype.addrspace == AddrSpace.REG and src_dtype.addrspace == AddrSpace.LOCAL: + srcf = src.flatten(-2) + + load_i_height = UOp.range(dst.shape[-3], Group.load_rid) + load_i_width = UOp.range(dst.shape[-2], Group.load_rid+1) + load_i_inner = UOp.range(RT.BASE_TILE_NEPT, Group.load_rid+2) + Group.load_rid += 3 + + if self.warps % 4 == 0: local_warpid = (self.warpid // 4) + (self.warpid % 4) * (self.warps // 4) + else: local_warpid = self.warpid + warp_laneid = self.threadIdx_x % WARP_THREADS + + if not transpose: + row = (local_warpid * dst.shape[-3] + load_i_height) * RT.TILE_ROW_DIM + (warp_laneid // 4) + col = load_i_width * RT.TILE_COL_DIM + 2 * (warp_laneid % 4) + + row_offset = ((load_i_inner % 4) // 2) * 8 + col_offset = (load_i_inner % 2) + (load_i_inner // 4) * 8 + else: + row = (local_warpid * dst.shape[-3] + load_i_height) * RT.TILE_ROW_DIM + 2 * (warp_laneid % 4) + col = load_i_width * RT.TILE_COL_DIM + (warp_laneid // 4) + + row_offset = (load_i_inner % 2) + (load_i_inner // 4) * 8 + col_offset = ((load_i_inner % 4) // 2) * 8 + + src_i_last = (row + row_offset) * src.shape[-1] + col + col_offset + + dst_store = dst[*dst_idxs, load_i_height, load_i_width, load_i_inner].store(srcf[*idxs[:-2], src_i_last]) + dst_store = dst_store.end(load_i_height, load_i_width, load_i_inner) + elif dst_dtype.addrspace == AddrSpace.LOCAL and src_dtype.addrspace == AddrSpace.GLOBAL: + dstf = dst.flatten(-2) + + srcf = src.flatten() + row_stride = prod(src.shape[axis+1:]) + + idxs = tuple(idx * dst.shape[-2] if i == axis else idx for i, idx in enumerate(idxs)) + idxs = tuple(idx * dst.shape[-1] if i == 3 else idx for i, idx in enumerate(idxs)) + src_i = ((idxs[0] * src.shape[-3] + idxs[1]) * src.shape[-2] + idxs[2]) * src.shape[-1] + idxs[3] + + memcpy_per_row = dst.shape[-1] // Group.LOAD_INNER + total_calls = prod(dst.shape[-2:]) // (self.group_threads * Group.LOAD_INNER) + + load_i_outer = UOp.range(total_calls, Group.load_rid) + load_i_inner = UOp.range(Group.LOAD_INNER, Group.load_rid+1) + Group.load_rid += 2 + + load_idx = load_i_outer * self.group_threads + self.laneid + row = load_idx // memcpy_per_row + col = (load_idx * Group.LOAD_INNER) % dst.shape[-1] + + dst_i = row * dst.shape[-1] + col + load_i_inner + src_i += row * row_stride + col + load_i_inner + + dst_store = dstf[*dst_idxs, dst_i].store(srcf[src_i]).end(load_i_outer, load_i_inner) + else: + raise NotImplementedError(f"load from {src_dtype.addrspace} to {dst_dtype.addrspace} not implemented") + + return dst.after(dst_store.barrier()).reshape(dst.shape) + + STORE_INNER = 8 + store_rid = 200 + def store(self, dst:UOp, src:UOp, idxs:tuple[UOp|int,...]=(), src_idxs:tuple[UOp|int,...]=(), axis=0, after=True): + assert isinstance(dst.dtype, PtrDType) and isinstance(src.dtype, PtrDType) + dst_dtype, src_dtype = cast(PtrDType, dst.dtype), cast(PtrDType, src.dtype) + if src_dtype.addrspace == AddrSpace.REG and dst_dtype.addrspace == AddrSpace.LOCAL: + dstf = dst.flatten(-2) + + store_i_height = UOp.range(src.shape[-3], Group.store_rid) + store_i_width = UOp.range(src.shape[-2], Group.store_rid+1) + store_i_inner = UOp.range(RT.BASE_TILE_NEPT, Group.store_rid+2) + Group.store_rid += 3 + + if self.warps % 4 == 0: local_warpid = (self.warpid // 4) + (self.warpid % 4) * (self.warps // 4) + else: local_warpid = self.warpid + warp_laneid = self.threadIdx_x % WARP_THREADS + + row = (local_warpid * src.shape[-3] + store_i_height) * RT.TILE_ROW_DIM + (warp_laneid // 4) + col = store_i_width * RT.TILE_COL_DIM + 2 * (warp_laneid % 4) + + row_offset = ((store_i_inner % 4) // 2) * 8 + col_offset = (store_i_inner % 2) + (store_i_inner // 4) * 8 + + dst_i_last = (row + row_offset) * dst.shape[-1] + col + col_offset + + dst_store = dstf[*idxs[:-2], dst_i_last].store(src[*src_idxs, store_i_height, store_i_width, store_i_inner]) + dst_store = dst_store.end(store_i_height, store_i_width, store_i_inner) + elif src_dtype.addrspace == AddrSpace.LOCAL and dst_dtype.addrspace == AddrSpace.GLOBAL: + dstf = dst.flatten() + row_stride = prod(dst.shape[axis+1:]) + + idxs = tuple(idx * src.shape[-2] if i == axis else idx for i, idx in enumerate(idxs)) + idxs = tuple(idx * src.shape[-1] if i == 3 else idx for i, idx in enumerate(idxs)) + dst_i = ((idxs[0] * dst.shape[-3] + idxs[1]) * dst.shape[-2] + idxs[2]) * dst.shape[-1] + idxs[3] + + srcf = src.flatten(-2) + + memcpy_per_row = src.shape[-1] // Group.STORE_INNER + total_calls = prod(src.shape[-2:]) // (self.group_threads * Group.STORE_INNER) + + store_i_outer = UOp.range(total_calls, Group.store_rid) + store_i_inner = UOp.range(Group.STORE_INNER, Group.store_rid+1) + Group.store_rid += 2 + + load_idx = store_i_outer * self.group_threads + self.laneid + row = load_idx // memcpy_per_row + col = (load_idx * Group.STORE_INNER) % src.shape[-1] + + src_i = row * src.shape[-1] + col + store_i_inner + dst_i += row * row_stride + col + store_i_inner + + dst_store = dstf[dst_i].store(srcf[*src_idxs, src_i]).end(store_i_outer, store_i_inner) + else: + raise NotImplementedError(f"store from {src_dtype.addrspace} to {dst_dtype.addrspace} not implemented") + + self.ker.push_store(dst_store, dst) + return dst.after(dst_store.barrier()).reshape(dst.shape) if after else dst_store diff --git a/extra/thunder/tiny/tk/kernel.py b/extra/thunder/tiny/tk/kernel.py new file mode 100644 index 0000000000..68d89ea3b2 --- /dev/null +++ b/extra/thunder/tiny/tk/kernel.py @@ -0,0 +1,88 @@ +from contextlib import AbstractContextManager +from tinygrad.uop.ops import UOp, KernelInfo, AxisType, AddrSpace +from extra.thunder.tiny.tk import WARP_THREADS +from extra.thunder.tiny.tk.group import Group +from extra.thunder.tiny.tk.tiles import GL, ST, RT, RV + +class _tk_range: + user_rid = 0 + def __init__(self, end:int, axis_type:AxisType): self.end, self.axis_type, self.done = end, axis_type, False + def __iter__(self): return self + def __next__(self): + if not self.done: + self.done = True + _tk_range.user_rid += 1 + self._rng = UOp.range(self.end, _tk_range.user_rid-1, axis_type=self.axis_type) + return self._rng + raise StopIteration + +class Kernel(AbstractContextManager): + def __init__(self, grid_size:tuple[int, int, int], block_size:int): + self.blockIdx_x = UOp.special(grid_size[0], "gidx0") + self.blockIdx_y = UOp.special(grid_size[1], "gidx1") + self.blockIdx_z = UOp.special(grid_size[2], "gidx2") + self.threadIdx_x = UOp.special(block_size, "lidx0") + + self.range_stack = [] + self.store_stack = [] + + self.global_slot = 0 + self.shared_slot = 0 + self.register_slot = 0 + self.allocs = {} + + @property + def warpid(self): return self.threadIdx_x // WARP_THREADS + + def __enter__(self): return self + def __exit__(self, exc_type, exc_value, traceback): pass + + def group(self, size:int): return Group(size, self) + @property + def warp(self): return self.group(1) + @property + def warpgroup(self): return self.group(4) + + def range(self, end:int, axis_type:AxisType=AxisType.LOOP, track:bool=True): + rng = _tk_range(end, axis_type) + if track: self.range_stack.append(rng) + return rng + + def alloc(self, shape, dtype, addrspace:AddrSpace, name:str|None=None): + match addrspace: + case AddrSpace.GLOBAL: + slot = self.global_slot + self.global_slot += 1 + case AddrSpace.LOCAL: + slot = self.shared_slot + self.shared_slot += 1 + case AddrSpace.REG: + slot = self.register_slot + self.register_slot += 1 + + uop = UOp.placeholder(shape, dtype, slot=slot, addrspace=addrspace) + + if name: + if (name, shape) in self.allocs: return self.allocs[(name, shape)] + self.allocs[(name, shape)] = uop + + return uop + + def gl(self, shape, dtype): return GL(shape, dtype, self)._uop + def st(self, shape, dtype): return ST(shape, dtype, self)._uop + def rt(self, shape, dtype): return RT(shape, dtype, self)._uop + def rv(self, length, dtype, layout="naive"): return RV(length, dtype, layout, self)._uop + + def push_store(self, store:UOp, uop:UOp): self.store_stack.append((store, uop)) + + def finish(self): + # end all ranges + rngs = [] + while self.range_stack: rngs.append(self.range_stack.pop(0)._rng) + + return self.store_stack.pop()[0].end(*rngs).sink(arg=KernelInfo(opts_to_apply=())).simplify() + + def endrange(self): + last_store = self.store_stack.pop() + last_range = self.range_stack.pop() + return last_store[1].after(last_store[0].barrier().end(last_range._rng)).reshape(last_store[1].shape) diff --git a/extra/thunder/tiny/tk/tiles.py b/extra/thunder/tiny/tk/tiles.py new file mode 100644 index 0000000000..0a8ecc987f --- /dev/null +++ b/extra/thunder/tiny/tk/tiles.py @@ -0,0 +1,45 @@ +from tinygrad.dtype import AddrSpace + +from extra.thunder.tiny.tk import WARP_THREADS + +class GL: + def __init__(self, shape, dtype, ker): + self.shape, self.dtype = shape, dtype + self._uop = ker.alloc(shape, dtype, AddrSpace.GLOBAL) + +class ST: + def __init__(self, shape, dtype, ker): + self.shape, self.dtype = shape, dtype + self._uop = ker.alloc(shape, dtype, AddrSpace.LOCAL) + +class RT: + TILE_ROW_DIM, TILE_COL_DIM = 16, 16 + BASE_TILE_NE = TILE_ROW_DIM * TILE_COL_DIM + BASE_TILE_NEPT = BASE_TILE_NE // WARP_THREADS + + def __init__(self, shape, dtype, ker): + assert len(shape) == 2 + assert shape[0] % RT.TILE_ROW_DIM == 0 + assert shape[1] % RT.TILE_COL_DIM == 0 + + height = shape[0] // RT.TILE_ROW_DIM + width = shape[1] // RT.TILE_COL_DIM + + self.shape, self.dtype = (height, width, self.BASE_TILE_NEPT), dtype + self._uop = ker.alloc(self.shape, dtype, AddrSpace.REG) + +class RV: + def __init__(self, length, dtype, layout, ker): + tiles = length // RT.TILE_ROW_DIM + + match layout: + case "naive": + inner_dim = 1 + outer_dim = (tiles + 1) // 2 + case "ortho": + inner_dim = 1 + outer_dim = tiles + case _: raise NotImplementedError(f"rv layout {layout} not implemented") + + self.shape, self.dtype = (outer_dim, inner_dim, 2), dtype + self._uop = ker.alloc(self.shape, dtype, AddrSpace.REG) diff --git a/extra/tinyfs/fetch_file.py b/extra/tinyfs/fetch_file.py new file mode 100644 index 0000000000..51cf72a4a2 --- /dev/null +++ b/extra/tinyfs/fetch_file.py @@ -0,0 +1,11 @@ +from tinygrad.tensor import Tensor +import argparse + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--hash", type=str, required=True, help="file hash to fetch") + parser.add_argument("--len", type=int, required=True, help="file length to fetch") + parser.add_argument("--dest", type=str, required=True, help="destination path to save the file") + args = parser.parse_args() + + Tensor(bytes.fromhex(args.hash), device="CPU").load(args.len).to(f"disk:{args.dest}").realize() diff --git a/extra/tinyfs/fetch_raid.py b/extra/tinyfs/fetch_raid.py new file mode 100644 index 0000000000..780fd157ea --- /dev/null +++ b/extra/tinyfs/fetch_raid.py @@ -0,0 +1,39 @@ +import json, multiprocessing +from pathlib import Path + +from tinygrad.tensor import Tensor +from tinygrad.helpers import tqdm, getenv + +raid_root = Path(getenv("RAID_ROOT", "/raid")) + +def fetch_file(item): + path, info = item + h, size = info["hash"], info["size"] + + path = raid_root / Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + + try: + pt = Tensor(bytes.fromhex(h), device="CPU").load(size).to(f"disk:{path.as_posix()}").realize() + except Exception as e: + print(f"error fetching {path}, {h}, {size}: {e}") + raise + + pt.uop.buffer.deallocate() + +def fetch_mapping(): + mapping_tensor = Tensor(bytes.fromhex("d734f5e3be9f1e9d863bfaa4fc6c1ef2")).load(175866113).realize() + mapping = mapping_tensor.data().tobytes().decode() + mapping = json.loads(mapping) + mapped_files = mapping.items() + return list(mapped_files) + +if __name__ == "__main__": + with multiprocessing.Pool(processes=1) as pool: + mapped_files = pool.apply(fetch_mapping) + + print(f"fetched mapping for {len(mapped_files)} files") + + with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool: + for _ in tqdm(pool.imap_unordered(fetch_file, mapped_files), total=len(mapped_files)): + pass diff --git a/extra/tinyfs/upload_raid.py b/extra/tinyfs/upload_raid.py new file mode 100644 index 0000000000..0c1b6ee0ae --- /dev/null +++ b/extra/tinyfs/upload_raid.py @@ -0,0 +1,31 @@ +from pathlib import Path +import multiprocessing, json + +from tinygrad.tensor import Tensor +from tinygrad.helpers import tqdm + +raid_root = Path("/raid") + +def upload_file(path: Path): + pt = Tensor(path).realize() + h = pt.store().realize() + pt.uop.realized.deallocate() + return h.data().hex(), path, pt.nbytes() + +if __name__ == "__main__": + raid_files = sorted([p for p in raid_root.rglob("*") if p.is_file()]) + print(f"found {len(raid_files)} files in /raid") + + mapping = {} + with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool: + for h, p, s in tqdm(pool.imap_unordered(upload_file, raid_files), total=len(raid_files)): + mapping[p.relative_to(raid_root).as_posix()] = {"hash": h, "size": s} + + # sort the mapping by key + mapping = dict(sorted(mapping.items())) + + mapping = json.dumps(mapping).encode() + mapping_tensor = Tensor(mapping, device="CPU") + h = mapping_tensor.store().realize() + + print(f"final hash: {h.data().hex()}, size: {len(mapping)}") diff --git a/extra/torch_backend/backend.py b/extra/torch_backend/backend.py index d5993f64b0..37a58efc5a 100644 --- a/extra/torch_backend/backend.py +++ b/extra/torch_backend/backend.py @@ -155,16 +155,14 @@ def index_tensor(x, y): def zero_(x): if TORCH_DEBUG: print(f"zero_ {x.shape}") tt = unwrap(x) - # NOTE: unconditional contiguous covers if x is contiguous (match it) or if x is view (realize for inplace) - # TODO: consolidate - tt.assign(tt.zeros_like().contiguous()) + tt.assign(tt.zeros_like()) @torch.library.impl("aten::fill_.Scalar", "privateuseone") @inplace_fn("x") def fill_scalar(x, y): if TORCH_DEBUG: print(f"fill_.Scalar {x.shape} {y}") tt = unwrap(x) - tt.assign(tt.full_like(y).contiguous()) + tt.assign(tt.full_like(y)) @torch.library.impl("aten::_local_scalar_dense", "privateuseone") def _local_scalar_dense(tensor): return unwrap(tensor).item() @@ -644,10 +642,11 @@ def get_real_tinygrad_buffers(): torch.nn.modules.module.register_module_buffer_registration_hook(register_torch_buffer) from torch.nn.modules import Module -def backward_hook(model:Module, _grad_input, _grad_out): - grads_to_realize = [unwrap(p.grad) for p in model.parameters() if p.grad is not None] - if len(grads_to_realize): Tensor.realize(*grads_to_realize) -def module_hook(module:Module, _name, _submodule): module.register_backward_hook(backward_hook) +def param_hook(_grad): + if _grad is not None and _grad.is_tiny: Tensor.realize(unwrap(_grad)) +def module_hook(module:Module, _name, _submodule): + for param in _submodule.parameters(recurse=False): + if param.requires_grad: param.register_hook(param_hook) torch.nn.modules.module.register_module_module_registration_hook(module_hook) def realize_optimizer_step(optimizer: torch.optim.Optimizer, *args, **kwargs): diff --git a/extra/torch_backend/test.py b/extra/torch_backend/test.py index 463eed6f2c..3348344f7f 100644 --- a/extra/torch_backend/test.py +++ b/extra/torch_backend/test.py @@ -227,16 +227,15 @@ class TestTorchBackend(unittest.TestCase): np.testing.assert_equal(result.cpu().numpy(), [3., 3., 2.]) def test_mnist_index(self): - with Context(FUSE_ARANGE=1, SPLIT_REDUCEOP=0): - GlobalCounters.reset() - from tinygrad.nn.datasets import mnist - X_train, Y_train, _, _ = mnist() - X_train = torch.tensor(X_train.float().numpy(), device=device) - Y_train = torch.tensor(Y_train.cast('int64').numpy(), device=device) - samples = torch.randint(0, X_train.shape[0], (32,)) - X,Y = X_train[samples], Y_train[samples] - X.cpu(), Y.cpu() - self.assertLessEqual(GlobalCounters.global_ops, 10_000_000) + GlobalCounters.reset() + from tinygrad.nn.datasets import mnist + X_train, Y_train, _, _ = mnist() + X_train = torch.tensor(X_train.float().numpy(), device=device) + Y_train = torch.tensor(Y_train.cast('int64').numpy(), device=device) + samples = torch.randint(0, X_train.shape[0], (32,)) + X,Y = X_train[samples], Y_train[samples] + X.cpu(), Y.cpu() + self.assertLessEqual(GlobalCounters.global_ops, 10_000_000) def _test_diagonal(self, *shape): a = torch.randn(*shape, dtype=torch.float32, device=device) diff --git a/extra/torch_backend/test_inplace.py b/extra/torch_backend/test_inplace.py index e6f171f05f..788f8d2eb3 100644 --- a/extra/torch_backend/test_inplace.py +++ b/extra/torch_backend/test_inplace.py @@ -1,6 +1,6 @@ import unittest import torch -import tinygrad.frontend.torch +import tinygrad.nn.torch torch.set_default_device("tiny") import numpy as np diff --git a/extra/torch_backend/test_multigpu.py b/extra/torch_backend/test_multigpu.py index 9a21898132..cff18bf2af 100644 --- a/extra/torch_backend/test_multigpu.py +++ b/extra/torch_backend/test_multigpu.py @@ -1,7 +1,7 @@ import unittest from tinygrad.helpers import getenv import torch -import tinygrad.frontend.torch +import tinygrad.nn.torch torch.set_default_device("tiny") import numpy as np diff --git a/extra/torch_muon.py b/extra/torch_muon.py deleted file mode 100644 index 1478757725..0000000000 --- a/extra/torch_muon.py +++ /dev/null @@ -1,75 +0,0 @@ -import torch - -#credit to KellerJordan at https://github.com/KellerJordan/Muon/tree/master -#some changes: classic momentum instead of weighting gradient -#added ns_steps, ns_params, nesterov as hyperparams -def zeropower_via_newtonschulz5(G:torch.tensor, steps:int, params:tuple[int, ...]): - """ - Newton-Schulz iteration to compute the zeroth power / orthogonalization of G. We opt to use a - quintic iteration whose coefficients are selected to maximize the slope at zero. For the purpose - of minimizing steps, it turns out to be empirically effective to keep increasing the slope at - zero even beyond the point where the iteration no longer converges all the way to one everywhere - on the interval. This iteration therefore does not produce UV^T but rather something like US'V^T - where S' is diagonal with S_{ii}' ~ Uniform(0.5, 1.5), which turns out not to hurt model - performance at all relative to UV^T, where USV^T = G is the SVD. - """ - assert G.ndim >= 2 # batched Muon implementation by @scottjmaddox, and put into practice in the record by @YouJiacheng - - a, b, c = params - X = G - if G.size(-2) > G.size(-1): - X = X.mT - - # Ensure spectral norm is at most 1 - X = X / (X.norm(dim=(-2, -1), keepdim=True) + 1e-7) - # Perform the NS iterations - for _ in range(steps): - A = X @ X.mT - B = b * A + c * A @ A # quintic computation strategy adapted from suggestion by @jxbz, @leloykun, and @YouJiacheng - X = a * X + B @ X - - if G.size(-2) > G.size(-1): - X = X.mT - - return X - -def muon_update(grad, momentum, beta=0.95, ns_steps=5, ns_params=(3.4445, -4.7750, 2.0315), nesterov=True): - if beta: - momentum.mul_(beta).add_(grad) - update = grad.add(momentum,alpha=beta) if nesterov else momentum - else: update = grad - if update.ndim == 4: # for the case of conv filters - update = update.view(len(update), -1) - update = zeropower_via_newtonschulz5(update, steps=ns_steps, params=ns_params) - return update - -class SingleDeviceMuon(torch.optim.Optimizer): - """ - Muon variant for usage in non-distributed settings. - """ - def __init__(self, params, lr=0.02, weight_decay=0.0, momentum=0.95, ns_steps=5, ns_params=(3.4445, -4.7750, 2.0315), nesterov=True): - defaults = dict(lr=lr, weight_decay=weight_decay, momentum=momentum, ns_steps=ns_steps, ns_params=ns_params, nesterov=nesterov) - super().__init__(params, defaults) - - @torch.no_grad() - def step(self, closure=None): - - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - for group in self.param_groups: - for p in group["params"]: - if p.grad is None: - p.grad = torch.zeros_like(p) # Force synchronization - state = self.state[p] - if len(state) == 0: - state["momentum_buffer"] = torch.zeros_like(p) - update = muon_update(p.grad, state["momentum_buffer"], beta=group["momentum"], ns_steps=group["ns_steps"], - ns_params=group["ns_params"], nesterov=group["nesterov"]) - p.mul_(1.0 - group["lr"] * group["weight_decay"]) - - p.add_(update.reshape(p.shape), alpha=-group["lr"]) - - return loss diff --git a/extra/usbgpu/patch.py b/extra/usbgpu/patch.py index e9e62682d8..533d9c6532 100755 --- a/extra/usbgpu/patch.py +++ b/extra/usbgpu/patch.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import sys, os, zlib, struct, hashlib -from hexdump import hexdump from tinygrad.helpers import DEBUG, getenv, fetch from tinygrad.runtime.support.usb import USB3 diff --git a/extra/usbgpu/tbgpu/installer/.gitignore b/extra/usbgpu/tbgpu/installer/.gitignore new file mode 100644 index 0000000000..5427d09d18 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/.gitignore @@ -0,0 +1,13 @@ +xcuserdata/ + +**/*.xcodeproj/project.xcworkspace/* +!**/*.xcodeproj/project.xcworkspace/xcshareddata + +**/*.xcodeproj/project.xcworkspace/xcshareddata/* +!**/*.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings + +**/*.playground/playground.xcworkspace/* +!**/*.playground/playground.xcworkspace/xcshareddata + +**/*.playground/playground.xcworkspace/xcshareddata/* +!**/*.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/AccentColor.colorset/Contents.json b/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000..eb87897008 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json b/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..c136eaff76 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,148 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/Contents.json b/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift new file mode 100644 index 0000000000..1f4f6d4248 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUApp.swift @@ -0,0 +1,19 @@ +import AppKit +import SwiftUI + +final class AppDelegate: NSObject, NSApplicationDelegate { + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + true + } +} + +@main +struct TinyGPUApp: App { + @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + + var body: some Scene { + WindowGroup { + TinyGPUView() + } + } +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUView.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUView.swift new file mode 100644 index 0000000000..f4a6b14efc --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUView.swift @@ -0,0 +1,33 @@ +import SwiftUI + +struct TinyGPUView: View { + @ObservedObject var viewModel = TinyGPUViewModel() + + var body: some View { +#if os(macOS) + VStack(alignment: .center) { + Text("TinyGPU Intsaller") + .padding() + .font(.title) + Text(self.viewModel.dextLoadingState) + .multilineTextAlignment(.center) + HStack { + Button( + action: { + self.viewModel.activateMyDext() + }, label: { + Text("Install extension") + } + ) + } + } + .frame(width: 500, height: 200, alignment: .center) +#endif + } +} + +struct TinyGPUView_Previews: PreviewProvider { + static var previews: some View { + TinyGPUView() + } +} diff --git a/extra/usbgpu/tbgpu/installer/Shared/TinyGPUViewModel.swift b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUViewModel.swift new file mode 100644 index 0000000000..58f1d8090b --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/Shared/TinyGPUViewModel.swift @@ -0,0 +1,142 @@ +import Foundation +import os.log +import SystemExtensions + +class TinyGPUDriverLoadingStateMachine { + enum State { case unloaded, activating, needsApproval, activated, activationError } +} + +class TinyGPUViewModel: NSObject { + + @Published private var state: TinyGPUDriverLoadingStateMachine.State = .unloaded + + override init() { + super.init() + refreshInitialDextState() + } + + private func refreshInitialDextState() { +#if os(macOS) + Task.detached { [dextIdentifier] in + let newState = Self.queryDextState(bundleID: dextIdentifier) + await MainActor.run { self.state = newState } + } +#endif + } + +#if os(macOS) + private static func queryDextState(bundleID: String) -> TinyGPUDriverLoadingStateMachine.State { + let tool = "/usr/bin/systemextensionsctl" + let p = Process() + p.executableURL = URL(fileURLWithPath: tool) + p.arguments = ["list"] + + let pipe = Pipe() + p.standardOutput = pipe + p.standardError = Pipe() + + do { + try p.run() + p.waitUntilExit() + let data = pipe.fileHandleForReading.readDataToEndOfFile() + guard let output = String(data: data, encoding: .utf8) else { return .unloaded } + + // Look for our bundle id line + if let line = output.split(separator: "\n").first(where: { $0.contains(bundleID) }) { + if line.contains("[activated enabled]") { return .activated } + if line.contains("[activated waiting for user]") { return .needsApproval } + if line.contains("terminated waiting to uninstall") { return .unloaded } + return .activating + } else { + return .unloaded + } + } catch { + return .unloaded + } + } +#endif + + private let dextIdentifier: String = "org.tinygrad.tinygpu.edriver" + + public var dextLoadingState: String { + switch state { + case .unloaded: + return "TinyGPUDriver isn't loaded." + case .activating: + return "Activating TinyGPUDriver, please wait." + case .needsApproval: + return "Please follow the prompt to approve TinyGPUDriver." + case .activated: + return "TinyGPUDriver has been activated and is ready to use. You can close the installer." + case .activationError: + return "TinyGPUDriver has experienced an error during activation.\nPlease check the logs to find the error." + } + } +} + +extension TinyGPUViewModel: ObservableObject { + +#if os(macOS) + func activateMyDext() { + activateExtension(dextIdentifier) + } + + func deactivateMyDext() { + deactivateExtension(dextIdentifier) + } + + func activateExtension(_ dextIdentifier: String) { + + let request = OSSystemExtensionRequest + .activationRequest(forExtensionWithIdentifier: dextIdentifier, + queue: .main) + request.delegate = self + OSSystemExtensionManager.shared.submitRequest(request) + + self.state = .activating + } + + func deactivateExtension(_ dextIdentifier: String) { + + let request = OSSystemExtensionRequest.deactivationRequest(forExtensionWithIdentifier: dextIdentifier, queue: .main) + request.delegate = self + OSSystemExtensionManager.shared.submitRequest(request) + + self.state = .unloaded + } +#endif +} + +#if os(macOS) +extension TinyGPUViewModel: OSSystemExtensionRequestDelegate { + + func request( + _ request: OSSystemExtensionRequest, + actionForReplacingExtension existing: OSSystemExtensionProperties, + withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction { + + var replacementAction: OSSystemExtensionRequest.ReplacementAction + + os_log("sysex actionForReplacingExtension: %@ %@", existing, ext) + + replacementAction = .replace + self.state = .activating + return replacementAction + } + + func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) { + os_log("sysex requestNeedsUserApproval") + self.state = .needsApproval + } + + func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) { + os_log("sysex didFinishWithResult: %d", result.rawValue) + self.state = .activated + } + + func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) { + os_log("sysex didFailWithError: %@", error.localizedDescription) + self.state = .activationError + } +} +#endif diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..5d7cf10710 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.pbxproj @@ -0,0 +1,589 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0ACB55392E9CB880007029EF /* PCIDriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ACB55382E9CB880007029EF /* PCIDriverKit.framework */; }; + 54798269286A3512009785F6 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54798268286A3512009785F6 /* CoreAudio.framework */; }; + 549EB121286A1A37009D38AB /* TinyGPUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549EB11F286A1A37009D38AB /* TinyGPUViewModel.swift */; }; + 549EB123286A1D48009D38AB /* org.tinygrad.tinygpu.edriver.dext in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = C5B7D9BC26128AC50089B4C3 /* org.tinygrad.tinygpu.edriver.dext */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 549EB131286A2B98009D38AB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549EB130286A2B98009D38AB /* IOKit.framework */; }; + 54E42BC8286A1697000E1E9A /* TinyGPUApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E42BB8286A1696000E1E9A /* TinyGPUApp.swift */; }; + 54E42BCA286A1697000E1E9A /* TinyGPUView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E42BB9286A1696000E1E9A /* TinyGPUView.swift */; }; + 54E42BCC286A1697000E1E9A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 54E42BBA286A1697000E1E9A /* Assets.xcassets */; }; + C5B7D9C326128AC50089B4C3 /* TinyGPUDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C5B7D9C226128AC50089B4C3 /* TinyGPUDriver.cpp */; }; + C5B7D9C526128AC50089B4C3 /* TinyGPUDriver.iig in Sources */ = {isa = PBXBuildFile; fileRef = C5B7D9C426128AC50089B4C3 /* TinyGPUDriver.iig */; }; + C5C3BBB32612ACDC003C7BFE /* AudioDriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5C3BBB12612ACD3003C7BFE /* AudioDriverKit.framework */; }; + C5C3BBB52612ACEF003C7BFE /* DriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5C3BBB42612ACEF003C7BFE /* DriverKit.framework */; }; + C5D787AC261667FC006047E5 /* TinyGPUDriverUserClient.iig in Sources */ = {isa = PBXBuildFile; fileRef = C5D787AB261667FC006047E5 /* TinyGPUDriverUserClient.iig */; }; + C5D787AE26168E59006047E5 /* TinyGPUDriverUserClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C5D787AD26168D1E006047E5 /* TinyGPUDriverUserClient.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 549EB126286A1D66009D38AB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C5B7D9B326128AC50089B4C3 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C5B7D9BB26128AC50089B4C3; + remoteInfo = SimpleAudioDriver; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 549EB122286A1D3A009D38AB /* Embed System Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(SYSTEM_EXTENSIONS_FOLDER_PATH)"; + dstSubfolderSpec = 16; + files = ( + 549EB123286A1D48009D38AB /* org.tinygrad.tinygpu.edriver.dext in Embed System Extensions */, + ); + name = "Embed System Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0ACB55382E9CB880007029EF /* PCIDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PCIDriverKit.framework; path = System/DriverKit/System/Library/Frameworks/PCIDriverKit.framework; sourceTree = SDKROOT; }; + 54798268286A3512009785F6 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/CoreAudio.framework; sourceTree = DEVELOPER_DIR; }; + 549EB11F286A1A37009D38AB /* TinyGPUViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUViewModel.swift; sourceTree = ""; usesTabs = 1; }; + 549EB130286A2B98009D38AB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + 549EB132286A2B9D009D38AB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + 54E42BB8286A1696000E1E9A /* TinyGPUApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUApp.swift; sourceTree = ""; }; + 54E42BB9286A1696000E1E9A /* TinyGPUView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyGPUView.swift; sourceTree = ""; }; + 54E42BBA286A1697000E1E9A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 54E42BC4286A1697000E1E9A /* TinyGPU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TinyGPU.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 54E42BC6286A1697000E1E9A /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; + C5B7D9BC26128AC50089B4C3 /* org.tinygrad.tinygpu.edriver.dext */ = {isa = PBXFileReference; explicitFileType = "wrapper.driver-extension"; includeInIndex = 0; path = org.tinygrad.tinygpu.edriver.dext; sourceTree = BUILT_PRODUCTS_DIR; }; + C5B7D9BF26128AC50089B4C3 /* DriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DriverKit.framework; path = Library/Frameworks/DriverKit.framework; sourceTree = DEVELOPER_DIR; }; + C5B7D9C226128AC50089B4C3 /* TinyGPUDriver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TinyGPUDriver.cpp; sourceTree = ""; usesTabs = 1; }; + C5B7D9C426128AC50089B4C3 /* TinyGPUDriver.iig */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.iig; path = TinyGPUDriver.iig; sourceTree = ""; }; + C5B7D9C626128AC50089B4C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C5B7D9CC26128ADA0089B4C3 /* AudioDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioDriverKit.framework; path = System/DriverKit/System/Library/Frameworks/AudioDriverKit.framework; sourceTree = SDKROOT; }; + C5B7D9CE26128B150089B4C3 /* TinyGPUDriver.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TinyGPUDriver.entitlements; sourceTree = ""; }; + C5C0063326178F98003345D8 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; + C5C006352617ACB8003345D8 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/Library/Frameworks/CoreAudio.framework; sourceTree = DEVELOPER_DIR; }; + C5C3BBB12612ACD3003C7BFE /* AudioDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioDriverKit.framework; path = Platforms/DriverKit.platform/Developer/SDKs/DriverKit.MacOSX21.0.Internal.sdk/System/DriverKit/System/Library/Frameworks/AudioDriverKit.framework; sourceTree = DEVELOPER_DIR; }; + C5C3BBB42612ACEF003C7BFE /* DriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DriverKit.framework; path = Platforms/DriverKit.platform/Developer/SDKs/DriverKit.MacOSX21.0.Internal.sdk/System/DriverKit/System/Library/Frameworks/DriverKit.framework; sourceTree = DEVELOPER_DIR; }; + C5D787AB261667FC006047E5 /* TinyGPUDriverUserClient.iig */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.iig; path = TinyGPUDriverUserClient.iig; sourceTree = ""; }; + C5D787AD26168D1E006047E5 /* TinyGPUDriverUserClient.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TinyGPUDriverUserClient.cpp; sourceTree = ""; }; + C5D787B026169723006047E5 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + C5D787B22616973F006047E5 /* SystemExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemExtensions.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/Library/Frameworks/SystemExtensions.framework; sourceTree = DEVELOPER_DIR; }; + C5D787B426169747006047E5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 54E42BC1286A1697000E1E9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 54798269286A3512009785F6 /* CoreAudio.framework in Frameworks */, + 549EB131286A2B98009D38AB /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C5B7D9B926128AC50089B4C3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C5C3BBB32612ACDC003C7BFE /* AudioDriverKit.framework in Frameworks */, + C5C3BBB52612ACEF003C7BFE /* DriverKit.framework in Frameworks */, + 0ACB55392E9CB880007029EF /* PCIDriverKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 54E42BB7286A1696000E1E9A /* Shared */ = { + isa = PBXGroup; + children = ( + 54E42BB8286A1696000E1E9A /* TinyGPUApp.swift */, + 54E42BB9286A1696000E1E9A /* TinyGPUView.swift */, + 549EB11F286A1A37009D38AB /* TinyGPUViewModel.swift */, + 54E42BBA286A1697000E1E9A /* Assets.xcassets */, + ); + path = Shared; + sourceTree = ""; + }; + 54E42BC5286A1697000E1E9A /* macOS */ = { + isa = PBXGroup; + children = ( + 54E42BC6286A1697000E1E9A /* macOS.entitlements */, + ); + path = macOS; + sourceTree = ""; + }; + C5B7D9B226128AC50089B4C3 = { + isa = PBXGroup; + children = ( + C5B7D9C126128AC50089B4C3 /* TinyGPUDriverExtension */, + 54E42BB7286A1696000E1E9A /* Shared */, + 54E42BC5286A1697000E1E9A /* macOS */, + C5B7D9BE26128AC50089B4C3 /* Frameworks */, + C5B7D9BD26128AC50089B4C3 /* Products */, + ); + sourceTree = ""; + usesTabs = 1; + }; + C5B7D9BD26128AC50089B4C3 /* Products */ = { + isa = PBXGroup; + children = ( + C5B7D9BC26128AC50089B4C3 /* org.tinygrad.tinygpu.edriver.dext */, + 54E42BC4286A1697000E1E9A /* TinyGPU.app */, + ); + name = Products; + sourceTree = ""; + }; + C5B7D9BE26128AC50089B4C3 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0ACB55382E9CB880007029EF /* PCIDriverKit.framework */, + 54798268286A3512009785F6 /* CoreAudio.framework */, + 549EB130286A2B98009D38AB /* IOKit.framework */, + 549EB132286A2B9D009D38AB /* IOKit.framework */, + C5C006352617ACB8003345D8 /* CoreAudio.framework */, + C5C0063326178F98003345D8 /* AppKit.framework */, + C5D787B426169747006047E5 /* Foundation.framework */, + C5D787B22616973F006047E5 /* SystemExtensions.framework */, + C5D787B026169723006047E5 /* IOKit.framework */, + C5C3BBB42612ACEF003C7BFE /* DriverKit.framework */, + C5B7D9CC26128ADA0089B4C3 /* AudioDriverKit.framework */, + C5C3BBB12612ACD3003C7BFE /* AudioDriverKit.framework */, + C5B7D9BF26128AC50089B4C3 /* DriverKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + C5B7D9C126128AC50089B4C3 /* TinyGPUDriverExtension */ = { + isa = PBXGroup; + children = ( + C5B7D9C226128AC50089B4C3 /* TinyGPUDriver.cpp */, + C5B7D9C426128AC50089B4C3 /* TinyGPUDriver.iig */, + C5D787AD26168D1E006047E5 /* TinyGPUDriverUserClient.cpp */, + C5D787AB261667FC006047E5 /* TinyGPUDriverUserClient.iig */, + C5B7D9C626128AC50089B4C3 /* Info.plist */, + C5B7D9CE26128B150089B4C3 /* TinyGPUDriver.entitlements */, + ); + path = TinyGPUDriverExtension; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + C5B7D9B726128AC50089B4C3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 54E42BC3286A1697000E1E9A /* TinyGPU Installer (macOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 54E42BD2286A1697000E1E9A /* Build configuration list for PBXNativeTarget "TinyGPU Installer (macOS)" */; + buildPhases = ( + 54E42BC0286A1697000E1E9A /* Sources */, + 54E42BC1286A1697000E1E9A /* Frameworks */, + 54E42BC2286A1697000E1E9A /* Resources */, + 549EB122286A1D3A009D38AB /* Embed System Extensions */, + ); + buildRules = ( + ); + dependencies = ( + 549EB127286A1D66009D38AB /* PBXTargetDependency */, + ); + name = "TinyGPU Installer (macOS)"; + productName = "SimpleAudioDriverExtension2 (macOS)"; + productReference = 54E42BC4286A1697000E1E9A /* TinyGPU.app */; + productType = "com.apple.product-type.application"; + }; + C5B7D9BB26128AC50089B4C3 /* TinyGPUDriver */ = { + isa = PBXNativeTarget; + buildConfigurationList = C5B7D9C926128AC50089B4C3 /* Build configuration list for PBXNativeTarget "TinyGPUDriver" */; + buildPhases = ( + C5B7D9B726128AC50089B4C3 /* Headers */, + C5B7D9B826128AC50089B4C3 /* Sources */, + C5B7D9B926128AC50089B4C3 /* Frameworks */, + C5B7D9BA26128AC50089B4C3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TinyGPUDriver; + productName = SimpleAudioDriverExtension; + productReference = C5B7D9BC26128AC50089B4C3 /* org.tinygrad.tinygpu.edriver.dext */; + productType = "com.apple.product-type.driver-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C5B7D9B326128AC50089B4C3 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + DefaultBuildSystemTypeForWorkspace = Latest; + LastSwiftUpdateCheck = 1400; + LastUpgradeCheck = 1600; + ORGANIZATIONNAME = Apple; + TargetAttributes = { + 54E42BC3286A1697000E1E9A = { + CreatedOnToolsVersion = 14.0; + LastSwiftMigration = 1400; + }; + C5B7D9BB26128AC50089B4C3 = { + CreatedOnToolsVersion = 13.0; + }; + }; + }; + buildConfigurationList = C5B7D9B626128AC50089B4C3 /* Build configuration list for PBXProject "TinyGPUDriverExtension" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C5B7D9B226128AC50089B4C3; + productRefGroup = C5B7D9BD26128AC50089B4C3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C5B7D9BB26128AC50089B4C3 /* TinyGPUDriver */, + 54E42BC3286A1697000E1E9A /* TinyGPU Installer (macOS) */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 54E42BC2286A1697000E1E9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 54E42BCC286A1697000E1E9A /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C5B7D9BA26128AC50089B4C3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 54E42BC0286A1697000E1E9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 549EB121286A1A37009D38AB /* TinyGPUViewModel.swift in Sources */, + 54E42BCA286A1697000E1E9A /* TinyGPUView.swift in Sources */, + 54E42BC8286A1697000E1E9A /* TinyGPUApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C5B7D9B826128AC50089B4C3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C5B7D9C526128AC50089B4C3 /* TinyGPUDriver.iig in Sources */, + C5D787AE26168E59006047E5 /* TinyGPUDriverUserClient.cpp in Sources */, + C5D787AC261667FC006047E5 /* TinyGPUDriverUserClient.iig in Sources */, + C5B7D9C326128AC50089B4C3 /* TinyGPUDriver.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 549EB127286A1D66009D38AB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C5B7D9BB26128AC50089B4C3 /* TinyGPUDriver */; + targetProxy = 549EB126286A1D66009D38AB /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 54E42BCF286A1697000E1E9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_IDENTITY = "-"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 9YG3G8543N; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 12.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.installer; + PRODUCT_NAME = TinyGPU; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 54E42BD0286A1697000E1E9A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_IDENTITY = "-"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 9YG3G8543N; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 12.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.installer; + PRODUCT_NAME = TinyGPU; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + C5B7D9C726128AC50089B4C3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DRIVERKIT_DEPLOYMENT_TARGET = 21.0; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = driverkit; + }; + name = Debug; + }; + C5B7D9C826128AC50089B4C3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DRIVERKIT_DEPLOYMENT_TARGET = 21.0; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = driverkit; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + C5B7D9CA26128AC50089B4C3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + AD_HOC_CODE_SIGNING_ALLOWED = YES; + CODE_SIGN_ENTITLEMENTS = TinyGPUDriverExtension/TinyGPUDriver.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 9YG3G8543N; + DRIVERKIT_DEPLOYMENT_TARGET = 21.0; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/System/DriverKit/System/Library/Frameworks", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TinyGPUDriverExtension/Info.plist; + INFOPLIST_KEY_OSBundleUsageDescription = "Sample Code Audio Driver Kit Extension"; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.edriver; + PRODUCT_NAME = "$(inherited)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = driverkit; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + C5B7D9CB26128AC50089B4C3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + AD_HOC_CODE_SIGNING_ALLOWED = YES; + CODE_SIGN_ENTITLEMENTS = TinyGPUDriverExtension/TinyGPUDriver.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 9YG3G8543N; + DRIVERKIT_DEPLOYMENT_TARGET = 21.0; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/System/DriverKit/System/Library/Frameworks", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TinyGPUDriverExtension/Info.plist; + INFOPLIST_KEY_OSBundleUsageDescription = "Sample Code Audio Driver Kit Extension"; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.tinygrad.tinygpu.edriver; + PRODUCT_NAME = "$(inherited)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = driverkit; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 54E42BD2286A1697000E1E9A /* Build configuration list for PBXNativeTarget "TinyGPU Installer (macOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 54E42BCF286A1697000E1E9A /* Debug */, + 54E42BD0286A1697000E1E9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C5B7D9B626128AC50089B4C3 /* Build configuration list for PBXProject "TinyGPUDriverExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C5B7D9C726128AC50089B4C3 /* Debug */, + C5B7D9C826128AC50089B4C3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C5B7D9C926128AC50089B4C3 /* Build configuration list for PBXNativeTarget "TinyGPUDriver" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C5B7D9CA26128AC50089B4C3 /* Debug */, + C5B7D9CB26128AC50089B4C3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C5B7D9B326128AC50089B4C3 /* Project object */; +} diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..280eff1f10 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + BuildSystemType + Latest + DerivedDataLocationStyle + Default + + diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/Info.plist b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/Info.plist new file mode 100644 index 0000000000..edd76f97ec --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/Info.plist @@ -0,0 +1,37 @@ + + + + + IOKitPersonalities + + TinyGPUDriver + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + IOClass + IOUserService + IOMatchCategory + TinyGPUDriver + IOPCIClassMatch + 0x03000000 + IOPCITunnelCompatible + + IOProviderClass + IOPCIDevice + IOResourceMatch + IOKit + IOUserClass + TinyGPUDriver + IOUserServerName + org.tinygrad.tinygpu.Driver + TinyGPUDriverUserClientProperties + + IOClass + IOUserUserClient + IOUserClass + TinyGPUDriverUserClient + + + + + diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.cpp b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.cpp new file mode 100644 index 0000000000..56f56d528d --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.cpp @@ -0,0 +1,259 @@ +#include "TinyGPUDriver.h" +#include "TinyGPUDriverUserClient.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct TinyGPUDriver_IVars +{ + IOPCIDevice *pci = nullptr; +}; + +bool TinyGPUDriver::init() +{ + os_log(OS_LOG_DEFAULT, "tinygpu: init"); + + auto answer = super::init(); + if (!answer) { + return false; + } + + ivars = new TinyGPUDriver_IVars(); + if (ivars == nullptr) { + return false; + } + + return true; +} + +void TinyGPUDriver::free() +{ + if (ivars != nullptr) { + + } + IOSafeDeleteNULL(ivars, TinyGPUDriver_IVars, 1); + super::free(); +} + +kern_return_t TinyGPUDriver::Start_Impl(IOService* in_provider) +{ + IOServiceName service_name; + os_log(OS_LOG_DEFAULT, "tinygpu: on gpu detected"); + + kern_return_t err = Start(in_provider, SUPERDISPATCH); + if (err) return err; + + ivars->pci = OSDynamicCast(IOPCIDevice, in_provider); + if (!ivars->pci) return kIOReturnNoDevice; + + err = ivars->pci->Open(this, 0); + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: Open() failed 0x%08x", err); + ivars->pci = nullptr; + return err; + } + + uint16_t ven = 0, dev = 0; + ivars->pci->ConfigurationRead16(kIOPCIConfigurationOffsetVendorID, &ven); + ivars->pci->ConfigurationRead16(kIOPCIConfigurationOffsetDeviceID, &dev); + os_log(OS_LOG_DEFAULT, "tinygpu: opened device ven=0x%04x dev=0x%04x", ven, dev); + +#if 0 + uint32_t off = 0x100; + while (off) { + uint32_t hdr = 0, next = 0, cap_id = 0; + ivars->pci->ConfigurationRead32(off, &hdr); + cap_id = hdr & 0xFFFFu; + next = (hdr >> 20) & 0xFFCu; + os_log(OS_LOG_DEFAULT, "tinygpu: cap: %u", cap_id); + if (cap_id == 0x15) { + uint32_t cap = 0, ctrl = 0; + ivars->pci->ConfigurationRead32(off+0x4, &cap); + ivars->pci->ConfigurationRead32(off+0x8, &ctrl); + + uint32_t new_bar_size = 31 - __builtin_clz(cap >> 4); + uint32_t new_ctrl = (ctrl & ~0x1f00) | (new_bar_size << 8); + ivars->pci->ConfigurationWrite32(off+0x8, new_ctrl); + + os_log(OS_LOG_DEFAULT, "tinygpu: rebar: cap=%u ctrl=%u new_bar_size=%u new_ctrl=%u", cap, ctrl, new_bar_size, new_ctrl); + ivars->pci->Reset(0); + break; + } + off = next; + } + ivars->pci->Reset(kIOPCIDeviceResetTypeHotReset); +#endif + + uint16_t commandRegister; + ivars->pci->ConfigurationRead16(kIOPCIConfigurationOffsetCommand, &commandRegister); + commandRegister |= (kIOPCICommandIOSpace | kIOPCICommandBusMaster | kIOPCICommandMemorySpace); + ivars->pci->ConfigurationWrite16(kIOPCIConfigurationOffsetCommand, commandRegister); + + memcpy((void*)service_name, (void*)"tinygpu\0", 8); + SetName(service_name); + + os_log(OS_LOG_DEFAULT, "tinygpu: will register service %s", service_name); + RegisterService(); + + os_log(OS_LOG_DEFAULT, "tinygpu: service started %s", service_name); + return 0; +} + +kern_return_t TinyGPUDriver::Stop_Impl(IOService* in_provider) +{ + ivars->pci->Close(this, 0); + return 0; +} + +kern_return_t TinyGPUDriver::NewUserClient_Impl(uint32_t in_type, IOUserClient** out_user_client) +{ + kern_return_t err = 0; + + IOService* user_client_service = nullptr; + err = Create(this, "TinyGPUDriverUserClientProperties", &user_client_service); + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: failed to create NewUserClient"); + goto error; + } + *out_user_client = OSDynamicCast(IOUserClient, user_client_service); + os_log(OS_LOG_DEFAULT, "tinygpu: NewUserClient created"); + +error: + return err; +} + +kern_return_t TinyGPUDriver::MapBar(uint32_t bar, IOMemoryDescriptor** memory) +{ + kern_return_t err = 0; + uint8_t barMemoryIndex, barMemoryType; + uint64_t barMemorySize; + err = ivars->pci->GetBARInfo(bar, &barMemoryIndex, &barMemorySize, &barMemoryType); + if (err) return err; + + os_log(OS_LOG_DEFAULT, "tinygpu: requested bar mapping %d, %d", bar, (uint32_t)barMemoryIndex); + err = ivars->pci->_CopyDeviceMemoryWithIndex(barMemoryIndex, memory, this); + return err; +} + +kern_return_t TinyGPUDriver::CreateDMA(size_t size, TinyGPUCreateDMAResp* dmaDesc) +{ + kern_return_t err = 0; + IOMemoryMap* memoryMap = nullptr; + IOBufferMemoryDescriptor* sharedBuf = nullptr; + IODMACommand* dmaCmd = nullptr; + uint64_t flags = kIOMemoryDirectionInOut; + uint32_t segCount = 32; + IOAddressSegment segments[32]; + IODMACommandSpecification dmaSpec = { + .options = 0, + .maxAddressBits = 40, + }; + + err = IOBufferMemoryDescriptor::Create(kIOMemoryDirectionInOut, size, IOVMPageSize, &sharedBuf); + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: failed to alloc user buffer, err=%d", err); + goto error; + } + + err = IODMACommand::Create(ivars->pci, kIODMACommandCreateNoOptions, &dmaSpec, &dmaCmd); + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: failed to create dma command, err=%d", err); + goto error; + } + + err = dmaCmd->PrepareForDMA(kIODMACommandPrepareForDMANoOptions, sharedBuf, 0, size, + &flags, &segCount, segments); + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: failed to prepare for dma, err=%d", err); + goto error; + } + + // pass addresses to userland + { + // debug + for (int i = 0; i < segCount; i++) { + os_log(OS_LOG_DEFAULT, "tinygpu: new dma mapping (sz=0x%zx) %d 0x%llx 0x%llx", size, i, segments[i].address, segments[i].length); + } + + err = sharedBuf->CreateMapping(0, 0, 0, IOVMPageSize, IOVMPageSize, &memoryMap); // one page should be fine + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: failed to map memory, err=%d", err); + goto error; + } + + // Send back gpu addresses + uint64_t* addr = (uint64_t*)memoryMap->GetAddress(); + for (int i = 0; i < segCount; i++) { + addr[i * 2] = segments[i].address; + addr[i * 2 + 1] = segments[i].length; + } + addr[segCount * 2] = 0; + addr[segCount * 2 + 1] = 0; + + // free memoryMap + memoryMap->release(); + memoryMap = nullptr; + } + + dmaDesc->sharedBuf = sharedBuf; + dmaDesc->dmaCmd = dmaCmd; + return 0; + +error: + if (memoryMap) { + memoryMap->release(); + memoryMap = nullptr; + } + if (dmaCmd) { + dmaCmd->CompleteDMA(kIODMACommandCompleteDMANoOptions); + dmaCmd->release(); + dmaCmd = nullptr; + } + if (sharedBuf) { + sharedBuf->release(); + sharedBuf = nullptr; + } + return err; +} + +kern_return_t TinyGPUDriver::CfgRead(uint32_t off, uint32_t size, uint32_t* outVal) +{ + if (!ivars->pci || !outVal) return kIOReturnNotReady; + + if (size == 1) { + uint8_t v8 = 0; + ivars->pci->ConfigurationRead8(off, &v8); + *outVal = v8; + } else if (size == 2) { + uint16_t v16 = 0; + ivars->pci->ConfigurationRead16(off, &v16); + *outVal = v16; + } else if (size == 4) { + uint32_t v32 = 0; + ivars->pci->ConfigurationRead32(off, &v32); + *outVal = v32; + } + return 0; +} + +kern_return_t TinyGPUDriver::CfgWrite(uint32_t off, uint32_t size, uint32_t val) +{ + if (!ivars->pci) return kIOReturnNotReady; + if (size == 1) ivars->pci->ConfigurationWrite8 (off, (uint8_t)val); + else if (size == 2) ivars->pci->ConfigurationWrite16(off, (uint16_t)val); + else if (size == 4) ivars->pci->ConfigurationWrite32(off, (uint32_t)val); + return 0; +} + +kern_return_t TinyGPUDriver::ResetDevice() +{ + if (!ivars->pci) return kIOReturnNotReady; + ivars->pci->Reset(kIOPCIDeviceResetTypeFunctionReset); + return 0; +} diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements new file mode 100644 index 0000000000..1c19bbd29d --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.entitlements @@ -0,0 +1,21 @@ + + + + + com.apple.developer.driverkit.transport.pci + + + IOPCIMatch + 0x00001002&0x0000FFFF + + + IOPCIMatch + 0x000010de&0x0000FFFF + + + com.apple.developer.driverkit.allow-any-userclient-access + + com.apple.developer.driverkit + + + diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.iig b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.iig new file mode 100644 index 0000000000..5f535b4852 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriver.iig @@ -0,0 +1,38 @@ +#ifndef TinyGPUDriver_h +#define TinyGPUDriver_h + +#include +#include +#include +#include +#include + +struct TinyGPUCreateDMAResp +{ + IOBufferMemoryDescriptor* sharedBuf; + IODMACommand* dmaCmd; +}; + +class TinyGPUDriver: public IOService +{ +public: + virtual bool init() override; + + virtual void free() override; + + virtual kern_return_t Start(IOService * provider) override; + + virtual kern_return_t Stop(IOService * provider) override; + + virtual kern_return_t NewUserClient(uint32_t in_type, IOUserClient** out_user_client) override; + + kern_return_t MapBar(uint32_t bar, IOMemoryDescriptor** memory) LOCALONLY; + kern_return_t CreateDMA(size_t size, TinyGPUCreateDMAResp* dmaDesc) LOCALONLY; + + kern_return_t CfgRead(uint32_t off, uint32_t size, uint32_t* val) LOCALONLY; + kern_return_t CfgWrite(uint32_t off, uint32_t size, uint32_t val) LOCALONLY; + kern_return_t ResetDevice() LOCALONLY; + kern_return_t BarInfo() LOCALONLY; +}; + +#endif /* TinyGPUDriver_h */ diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriverUserClient.cpp b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriverUserClient.cpp new file mode 100644 index 0000000000..b84985df43 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriverUserClient.cpp @@ -0,0 +1,161 @@ +#include "TinyGPUDriverUserClient.h" +#include "TinyGPUDriver.h" +#include +#include +#include + +struct TinyGPUDriverUserClient_IVars +{ + OSSharedPtr provider = nullptr; + + TinyGPUCreateDMAResp *dmas = nullptr; + size_t dmaCount = 0; + size_t dmaCap = 0; + + int ensureDMACap(size_t need) + { + // not thread-safe + if (need <= dmaCap) return 0; + + size_t newCap = dmaCap ? dmaCap * 2 : 16; + while (newCap < need) newCap *= 2; + + auto *newArr = IONewZero(TinyGPUCreateDMAResp, newCap); + if (!newArr) return -kIOReturnNoMemory; + + if (dmas && dmaCount) { + memcpy(newArr, dmas, dmaCount * sizeof(TinyGPUCreateDMAResp)); + } + + IOSafeDeleteNULL(dmas, TinyGPUCreateDMAResp, dmaCap); + dmas = newArr; + dmaCap = newCap; + return 0; + } +}; + +bool TinyGPUDriverUserClient::init() +{ + auto ok = super::init(); + if (!ok) return false; + + ivars = IONewZero(TinyGPUDriverUserClient_IVars, 1); + if (!ivars) return false; + return true; +} + +void TinyGPUDriverUserClient::free() +{ + if (ivars) { + IOSafeDeleteNULL(ivars, TinyGPUDriverUserClient_IVars, 1); + } + super::free(); +} + +kern_return_t TinyGPUDriverUserClient::Start_Impl(IOService* in_provider) +{ + kern_return_t err = kIOReturnSuccess; + if (!in_provider) { + os_log(OS_LOG_DEFAULT, "tinygpu: provider is null"); + err = kIOReturnBadArgument; + goto error; + } + + err = Start(in_provider, SUPERDISPATCH); + if (err) { + os_log(OS_LOG_DEFAULT, "tinygpu: failed to start super (%d)", err); + goto error; + } + + ivars->provider = OSSharedPtr(OSDynamicCast(TinyGPUDriver, in_provider), OSRetain); + return 0; + +error: + ivars->provider.reset(); + return err; +} + +kern_return_t TinyGPUDriverUserClient::Stop_Impl(IOService* in_provider) +{ + // release all DMA allocations for this client + if (ivars) { + for (size_t i = 0; i < ivars->dmaCount; i++) { + auto &d = ivars->dmas[i]; + if (d.dmaCmd) { + d.dmaCmd->CompleteDMA(kIODMACommandCompleteDMANoOptions); + d.dmaCmd->release(); + d.dmaCmd = nullptr; + } + } + ivars->dmaCount = 0; + IOSafeDeleteNULL(ivars->dmas, TinyGPUCreateDMAResp, ivars->dmaCap); + ivars->dmas = nullptr; + ivars->provider.reset(); + } + + return Stop(in_provider, SUPERDISPATCH); +} + +kern_return_t TinyGPUDriverUserClient::ExternalMethod(uint64_t selector, IOUserClientMethodArguments* args, const IOUserClientMethodDispatch* in_dispatch, OSObject* in_target, void* in_reference) +{ + kern_return_t err = 0; + + os_log(OS_LOG_DEFAULT, "tinygpu: rpc (%llu) in:%d, out:%d", selector, args->scalarInputCount, args->scalarOutputCount); + + if (selector == TinyGPURPC::ReadCfg) { + if (args->scalarInputCount != 2 or args->scalarOutputCount < 1) return kIOReturnBadArgument; + + uint32_t off = uint32_t(args->scalarInput[0]); + uint32_t size = uint32_t(args->scalarInput[1]); + + uint32_t val = 0; + err = ivars->provider->CfgRead(off, size, &val); + os_log(OS_LOG_DEFAULT, "tinygpu: read cfg off:%x sz:%d, val:%x", off, size, val); + + if (!err) { + args->scalarOutput[0] = val; + args->scalarOutputCount = 1; + } + return err; + } else if (selector == TinyGPURPC::WriteCfg) { + if (args->scalarInputCount != 3) return kIOReturnBadArgument; + + uint32_t off = uint32_t(args->scalarInput[0]); + uint32_t size = uint32_t(args->scalarInput[1]); + uint32_t val = uint32_t(args->scalarInput[2]); + + os_log(OS_LOG_DEFAULT, "tinygpu: wr cfg off:%x sz:%d, val:%x", off, size, val); + return ivars->provider->CfgWrite(off, size, val); + } else if (selector == TinyGPURPC::Reset) { + os_log(OS_LOG_DEFAULT, "tinygpu: reset"); + return ivars->provider->ResetDevice(); + } + + return kIOReturnUnsupported; +} + +kern_return_t IMPL(TinyGPUDriverUserClient, CopyClientMemoryForType) +{ + if (!memory) return kIOReturnBadArgument; + if (!ivars->provider.get()) return kIOReturnNotAttached; + + // bar handling, type is bar num + if (type < 6) { + uint32_t bar = (uint32_t)type; + return ivars->provider->MapBar(bar, memory); + } + + // dma handling, type is size + if (ivars->ensureDMACap(ivars->dmaCount + 1)) { + os_log(OS_LOG_DEFAULT, "tinygpu: cannot grow dma array"); + return kIOReturnNoMemory; + } + + TinyGPUCreateDMAResp buf{}; + kern_return_t err = ivars->provider->CreateDMA(type, &buf); + if (err) return err; + + ivars->dmas[ivars->dmaCount++] = buf; + *memory = buf.sharedBuf; + return 0; +} diff --git a/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriverUserClient.iig b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriverUserClient.iig new file mode 100644 index 0000000000..9713cf823e --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/TinyGPUDriverExtension/TinyGPUDriverUserClient.iig @@ -0,0 +1,28 @@ +#ifndef TinyGPUDriverUserClient_h +#define TinyGPUDriverUserClient_h + +#include + +enum TinyGPURPC +{ + ReadCfg, + WriteCfg, + Reset +}; + +class TinyGPUDriverUserClient : public IOUserClient +{ +public: + virtual bool init() final; + virtual void free() final; + + virtual kern_return_t Start(IOService* in_provider) final; + virtual kern_return_t Stop(IOService* in_provider) final; + + virtual kern_return_t ExternalMethod(uint64_t in_selector, IOUserClientMethodArguments* in_arguments, const IOUserClientMethodDispatch* in_dispatch, OSObject* in_target, void* in_reference) final; + + virtual kern_return_t CopyClientMemoryForType( + uint64_t type, uint64_t *options, IOMemoryDescriptor **memory) final; +}; + +#endif /* TinyGPUDriverUserClient_h */ diff --git a/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements b/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements new file mode 100644 index 0000000000..729c9e7634 --- /dev/null +++ b/extra/usbgpu/tbgpu/installer/macOS/macOS.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.developer.system-extension.install + + + diff --git a/extra/usbgpu/tbgpu/main.cpp b/extra/usbgpu/tbgpu/main.cpp new file mode 100644 index 0000000000..98e7da6a0c --- /dev/null +++ b/extra/usbgpu/tbgpu/main.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +static io_connect_t open_uc_by_name(const char *svc_name) { + io_connect_t conn = IO_OBJECT_NULL; + io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching(svc_name)); + if (!service) { fprintf(stderr, "service not found: %s\n", svc_name); return IO_OBJECT_NULL; } + kern_return_t kr = IOServiceOpen(service, mach_task_self(), /*type*/0, &conn); + IOObjectRelease(service); + if (kr) { fprintf(stderr, "IOServiceOpen 0x%x\n", kr); return IO_OBJECT_NULL; } + return conn; +} + +int main(int argc, char **argv) { + uint32_t bar = (argc > 1) ? (uint32_t)strtoul(argv[1], NULL, 0) : 0; // pick BAR index + io_connect_t conn = open_uc_by_name("tinygpu"); + if (!conn) return 2; + + mach_vm_address_t addr = 0; + mach_vm_size_t size = 0; + kern_return_t kr = IOConnectMapMemory64(conn, bar, mach_task_self(), &addr, &size, kIOMapAnywhere); + if (kr) { fprintf(stderr, "Map BAR%u failed 0x%x\n", bar, kr); IOServiceClose(conn); return 3; } + + printf("BAR%u mapped at 0x%llx, size 0x%llx\n", bar, (unsigned long long)addr, (unsigned long long)size); + + // example: read a 32-bit register at offset 0x0 (make sure it’s safe!) + volatile uint32_t *mmio = (volatile uint32_t*)(uintptr_t)addr; + uint32_t v = mmio[0]; + printf("mmio[0]=0x%08x\n", v); + + kr = IOConnectUnmapMemory64(conn, bar, mach_task_self(), addr); + if (kr) fprintf(stderr, "Unmap failed 0x%x\n", kr); + + IOServiceClose(conn); + return 0; +} \ No newline at end of file diff --git a/extra/usbgpu/tbgpu/main.py b/extra/usbgpu/tbgpu/main.py new file mode 100644 index 0000000000..74719f5953 --- /dev/null +++ b/extra/usbgpu/tbgpu/main.py @@ -0,0 +1,82 @@ +import ctypes, ctypes.util, sys + +cf = ctypes.CDLL(ctypes.util.find_library("CoreFoundation")) +iokit = ctypes.CDLL(ctypes.util.find_library("IOKit")) +libsys = ctypes.CDLL(ctypes.util.find_library("System")) + +kern_return_t = ctypes.c_int +mach_port_t = ctypes.c_uint +io_object_t = mach_port_t +io_service_t = io_object_t +io_connect_t = mach_port_t +CFMutableDictionaryRef = ctypes.c_void_p +CFStringRef = ctypes.c_void_p + +kIOMasterPortDefault = mach_port_t(0) + +libsys.mach_task_self_.restype = mach_port_t + +iokit.IOServiceNameMatching.argtypes = [ctypes.c_char_p] +iokit.IOServiceNameMatching.restype = CFMutableDictionaryRef + +iokit.IOServiceGetMatchingService.argtypes = [mach_port_t, CFMutableDictionaryRef] +iokit.IOServiceGetMatchingService.restype = io_service_t + +iokit.IOObjectRelease.argtypes = [io_object_t] +iokit.IOObjectRelease.restype = kern_return_t + +iokit.IOServiceOpen.argtypes = [io_service_t, mach_port_t, ctypes.c_uint32, ctypes.POINTER(io_connect_t)] +iokit.IOServiceOpen.restype = kern_return_t + +iokit.IOConnectCallMethod.argtypes = [io_connect_t, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint32, ctypes.c_void_p, + ctypes.c_size_t, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_uint32), ctypes.c_void_p, ctypes.POINTER(ctypes.c_size_t)] +iokit.IOConnectCallMethod.restype = kern_return_t + +def open_userclient_by_name(name: str, uc_type: int = 0) -> io_connect_t: + mdict = iokit.IOServiceNameMatching(name.encode("utf-8")) + if not mdict: raise RuntimeError("IOServiceNameMatching returned NULL") + + # Grab the first matching service + service = iokit.IOServiceGetMatchingService(kIOMasterPortDefault, mdict) + if not service: raise RuntimeError(f'service "{name}" not found') + + # print("lol", service) + # print(libsys.mach_task_self_) + # cast libsys.mach_task_self_ to uint and print + # print("lol", ctypes.cast(libsys.mach_task_self_, ctypes.POINTER(ctypes.c_uint)).contents.value) + + try: + # Open user client (type -> passed to NewUserClient_Impl) + conn = io_connect_t(0) + # print("lol", libsys.mach_task_self_) + kr = iokit.IOServiceOpen(service, ctypes.cast(libsys.mach_task_self_, ctypes.POINTER(ctypes.c_uint)).contents.value, + ctypes.c_uint32(uc_type), ctypes.byref(conn)) + if kr != 0: raise OSError(kr, f"IOServiceOpen failed (0x{kr:08x})") + return conn + finally: iokit.IOObjectRelease(service) + +def external_method(conn: io_connect_t, selector: int = 0) -> int: + # no scalars in/out, no struct in/out — just ping selector 0 + in_scalars = ctypes.POINTER(ctypes.c_uint64)() # NULL + out_scalars = (ctypes.c_uint64 * 1)() # space if driver returns something + out_scalars_cnt = ctypes.c_uint32(0) # driver can set this + + return iokit.IOConnectCallMethod(conn, ctypes.c_uint32(selector), in_scalars, ctypes.c_uint32(0), None, ctypes.c_size_t(0), + out_scalars, ctypes.byref(out_scalars_cnt), None, ctypes.byref(ctypes.c_size_t(0))) + +def close_userclient(conn: io_connect_t) -> None: + # IOServiceClose is a macro; exported symbol is IOServiceClose in IOKit + iokit.IOServiceClose.argtypes = [io_connect_t] + iokit.IOServiceClose.restype = kern_return_t + iokit.IOServiceClose(conn) + +if __name__ == "__main__": + try: + conn = open_userclient_by_name("tinygpu", uc_type=0) + kr = external_method(conn, selector=0) + print(f"ExternalMethod(0) -> 0x{kr:08x}") + except Exception as e: + print(e) + sys.exit(1) + finally: + if 'conn' in locals() and conn.value: close_userclient(conn) diff --git a/extra/weekly_commits_table.py b/extra/weekly_commits_table.py new file mode 100644 index 0000000000..3dd5639e70 --- /dev/null +++ b/extra/weekly_commits_table.py @@ -0,0 +1,43 @@ +# extra/weekly_commits_table.py +import os, subprocess, datetime as dt + +NAMES = ["chenyu","George Hotz","nimlgen","qazal","wozeparrot"] +REPO = os.environ.get("REPO_PATH",".") +today = dt.date.today() +days = [(today - dt.timedelta(i)).strftime("%Y-%m-%d") for i in range(6,-1,-1)] +seen = {d:{n:False for n in NAMES} for d in days} + +cmd = ["git","-C",REPO,"log","--use-mailmap","--since=7 days ago","--no-merges", + "--date=short","--pretty=%ad%x09%aN%x09%ae"] +out = subprocess.run(cmd, capture_output=True, text=True).stdout.splitlines() +for line in out: + try: d, name, email = line.split("\t") + except: continue + if d in seen: + low = (name+" "+email).lower() + for n in NAMES: + if n.lower() in low: seen[d][n] = True + +# --- width-aware padding so emoji align --- +try: + from wcwidth import wcswidth as _wcswidth + vlen = lambda s: _wcswidth(s) +except Exception: + vlen = lambda s: sum(2 if ch in "✅❌" else 1 for ch in s) +pad = lambda s,w: s + " " * max(0, w - vlen(s)) + +w_date = 10 +w_cols = [max(3, vlen(n)) for n in NAMES] + +header = " | ".join([pad("date", w_date)] + [pad(n, w_cols[i]) for i,n in enumerate(NAMES)]) +rule = "-+-".join(["-"*w_date] + ["-"*w for w in w_cols]) + +rows=[] +for d in days: + cells = ["✅" if seen[d][n] else "❌" for n in NAMES] + rows.append(" | ".join([pad(d, w_date)] + [pad(c, w_cols[i]) for i,c in enumerate(cells)])) + +print("** Commits by day (last 7) **") +print("```") +print("\n".join([header, rule] + rows)) +print("```") diff --git a/mkdocs.yml b/mkdocs.yml index 1dd77b6867..ed3ee04251 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,8 +25,6 @@ nav: - Layout: developer/layout.md - Speed: developer/speed.md - UOp: developer/uop.md - - Grouper: - - developer/kernelize.md - Runtime: - developer/runtime.md - HCQ: developer/hcq.md diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 8a838bd232..0000000000 --- a/mypy.ini +++ /dev/null @@ -1,10 +0,0 @@ -[mypy] -warn_unused_configs = True -files = tinygrad -ignore_missing_imports = True -check_untyped_defs = True -explicit_package_bases = True -warn_unreachable = True -warn_redundant_casts = True -# NOTE: had to comment this out to make mypy pass on both CI and OSX -#warn_unused_ignores = True diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..4f4d0f8841 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,233 @@ +[project] +name = "tinygrad" +version = "0.11.0" +description = "You like pytorch? You like micrograd? You love tinygrad! <3" +authors = [{ name = "George Hotz" }] + +classifiers = ["Programming Language :: Python :: 3"] + +license = 'MIT' +readme = "README.md" +requires-python = ">=3.11" +dependencies = [] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +include-package-data = true +packages = [ + 'tinygrad', + 'tinygrad.apps', + 'tinygrad.codegen', + 'tinygrad.codegen.opt', + 'tinygrad.codegen.late', + 'tinygrad.engine', + 'tinygrad.mixin', + 'tinygrad.nn', + 'tinygrad.renderer', + 'tinygrad.runtime', + 'tinygrad.runtime.autogen', + 'tinygrad.runtime.autogen.am', + 'tinygrad.runtime.autogen.nv', + 'tinygrad.runtime.graph', + 'tinygrad.runtime.support', + 'tinygrad.runtime.support.am', + 'tinygrad.runtime.support.nv', + 'tinygrad.schedule', + 'tinygrad.uop', + 'tinygrad.viz', +] + +[tool.setuptools.package-data] +tinygrad = ["py.typed"] +"tinygrad.viz" = ["index.html", "assets/**/*", "js/*"] + + +[project.optional-dependencies] +arm = ["unicorn"] +triton = ["triton-nightly>=2.1.0.dev20231014192330"] +linting = [ + "pylint", + "mypy==1.18.1", + "typing-extensions", + "pre-commit", + "ruff", + "numpy", + "typeguard", +] +# mlperf = [ +# "mlperf-logging @ git+https://github.com/mlperf/logging.git@5.0.0-rc3", +# ] +testing_minimal = [ + "numpy", + "torch==2.9.0", + "pytest", + "pytest-xdist", + "pytest-timeout", + "pytest-split", + "hypothesis", + "z3-solver", +] +testing_unit = ["tinygrad[testing_minimal]", "tqdm", "safetensors", "tabulate"] +testing = [ + "tinygrad[testing_minimal]", + "pillow", + "onnx==1.18.0", + "onnx2torch", + "onnxruntime", + "opencv-python", + "tabulate", + "tqdm", + "safetensors", + "transformers", + "sentencepiece", + "tiktoken", + "blobfile", + "librosa", + # librosa needs numba but uv ignores python upper bounds and some numba versions require =0.55", + "networkx", + "nibabel", + "bottle", + "ggml-python", + "capstone", + "pycocotools", + "boto3", + "pandas", + "influxdb3-python", +] +docs = [ + "mkdocs", + "mkdocs-material", + "mkdocstrings[python]", + "markdown-callouts", + "markdown-exec[ansi]", + "black", + "numpy", +] + + +[tool.mutmut] +paths_to_mutate = ["tinygrad/"] +do_not_mutate = [ + "tinygrad/apps/*", + "tinygrad/codegen/*", + "tinygrad/engine/*", + "tinygrad/nn/*", + "tinygrad/renderer/*", + "tinygrad/runtime/*", + "tinygrad/schedule/*", + "tinygrad/uop/*", + "tinygrad/viz/*", + "tinygrad/device.py", + "tinygrad/dtype.py", + "tinygrad/gradient.py", + "tinygrad/helpers.py", + "tinygrad/tensor.py", +] +tests_dir = ["test/test_tiny.py", "test/test_ops.py"] +debug = true + + +[tool.mypy] +warn_unused_configs = true +files = ["tinygrad"] +ignore_missing_imports = true +check_untyped_defs = true +explicit_package_bases = true +warn_unreachable = true +warn_redundant_casts = true +# NOTE: had to comment this out to make mypy pass on both CI and OSX +#warn_unused_ignores = true + +[tool.pytest.ini_options] +norecursedirs = [ + "extra", + ".hypothesis", + ".git", +] +timeout = 300 +timeout_method = "thread" +timeout_func_only = true +testpaths = ["test"] + +[tool.ruff] +preview = true +target-version = "py311" +line-length = 150 +indent-width = 2 +exclude = [ + ".git/", + "docs/", + "extra/", + "tinygrad/runtime/autogen", + "test/external/mlperf_resnet", + "test/external/mlperf_unet3d", +] + +[tool.ruff.lint] +select = [ + "F", # Pyflakes + "W6", + "E71", + "E72", + "E112", # no-indented-block + "E113", # unexpected-indentation + # "E124", + "E203", # whitespace-before-punctuation + "E272", # multiple-spaces-before-keyword + "E275", # missing-whitespace-after-keyword + "E303", # too-many-blank-lines + "E304", # blank-line-after-decorator + "E501", # line-too-long + # "E502", + "E702", # multiple-statements-on-one-line-semicolon + "E703", # useless-semicolon + "E731", # lambda-assignment + "W191", # tab-indentation + "W291", # trailing-whitespace + "W293", # blank-line-with-whitespace + "UP039", # unnecessary-class-parentheses + "C416", # unnecessary-comprehension + "RET506", # superfluous-else-raise + "RET507", # superfluous-else-continue + "A", # builtin-variable-shadowing, builtin-argument-shadowing, builtin-attribute-shadowing + "FURB110",# if-exp-instead-of-or-operator + "RUF018", # assignment-in-assert +] + +# detect unused imports in examples +[tool.ruff.lint.per-file-ignores] +"examples/**/*.py" = [ + "W6", + "E71", + "E72", + "E112", + "E113", + "E203", + "E272", + "E275", + "E303", + "E304", + "E501", + "E702", + "E703", + "E731", + "W191", + "W291", + "W293", + "UP039", + "C416", + "RET506", + "RET507", + "A", + "FURB110", + "RUF018", + "F541", + "F841", +] + +[tool.ruff.format] +exclude = ["*"] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index fe28b7e961..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[pytest] -norecursedirs = extra -timeout = 240 -timeout_method = thread -timeout_func_only = true -testpaths = test diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 22f9bf566b..0000000000 --- a/ruff.toml +++ /dev/null @@ -1,53 +0,0 @@ -indent-width = 2 -preview = true -target-version = "py310" - -lint.select = [ - "F", # Pyflakes - "W6", - "E71", - "E72", - "E112", # no-indented-block - "E113", # unexpected-indentation - # "E124", - "E203", # whitespace-before-punctuation - "E272", # multiple-spaces-before-keyword - "E275", # missing-whitespace-after-keyword - "E303", # too-many-blank-lines - "E304", # blank-line-after-decorator - "E501", # line-too-long - # "E502", - "E702", # multiple-statements-on-one-line-semicolon - "E703", # useless-semicolon - "E731", # lambda-assignment - "W191", # tab-indentation - "W291", # trailing-whitespace - "W293", # blank-line-with-whitespace - "UP039", # unnecessary-class-parentheses - "C416", # unnecessary-comprehension - "RET506", # superfluous-else-raise - "RET507", # superfluous-else-continue - "A", # builtin-variable-shadowing, builtin-argument-shadowing, builtin-attribute-shadowing - "FURB110",# if-exp-instead-of-or-operator - "RUF018", # assignment-in-assert -] - -line-length = 150 - -exclude = [ - ".git/", - "docs/", - "extra/", - "tinygrad/runtime/autogen", - "test/external/mlperf_resnet", - "test/external/mlperf_unet3d", -] - -# detect unused imports in examples -[lint.per-file-ignores] -"examples/**/*.py" = [ - "W6", "E71", "E72", "E112", "E113", "E203", "E272", "E275", - "E303", "E304", "E501", "E702", "E703", "E731", "W191", - "W291", "W293", "UP039", "C416", "RET506", "RET507", "A", - "FURB110", "RUF018", "F541", "F841" -] \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index f90a52b584..0000000000 --- a/setup.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python3 - -from pathlib import Path -from setuptools import setup - -directory = Path(__file__).resolve().parent -with open(directory / 'README.md', encoding='utf-8') as f: - long_description = f.read() - -testing_minimal = [ - "numpy", - "torch==2.8.0", - "pytest", - "pytest-xdist", - "pytest-timeout", - "hypothesis", - "z3-solver", -] - -setup(name='tinygrad', - version='0.11.0', - description='You like pytorch? You like micrograd? You love tinygrad! <3', - author='George Hotz', - license='MIT', - long_description=long_description, - long_description_content_type='text/markdown', - packages = [ - 'tinygrad', - 'tinygrad.apps', - 'tinygrad.codegen', - 'tinygrad.codegen.opt', - 'tinygrad.codegen.late', - 'tinygrad.engine', - 'tinygrad.frontend', - 'tinygrad.nn', - 'tinygrad.renderer', - 'tinygrad.runtime', - 'tinygrad.runtime.autogen', - 'tinygrad.runtime.autogen.am', - 'tinygrad.runtime.autogen.nv', - 'tinygrad.runtime.graph', - 'tinygrad.runtime.support', - 'tinygrad.runtime.support.am', - 'tinygrad.runtime.support.nv', - 'tinygrad.schedule', - 'tinygrad.shape', - 'tinygrad.uop', - 'tinygrad.viz', - ], - package_data = {'tinygrad': ['py.typed'], 'tinygrad.viz': ['index.html', 'assets/**/*', 'js/*']}, - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License" - ], - install_requires=[], - python_requires='>=3.10', - extras_require={ - 'arm': ["unicorn"], - 'triton': ["triton-nightly>=2.1.0.dev20231014192330"], - 'linting': [ - "pylint", - "mypy==1.18.1", - "typing-extensions", - "pre-commit", - "ruff", - "numpy", - "typeguard", - ], - #'mlperf': ["mlperf-logging @ git+https://github.com/mlperf/logging.git@5.0.0-rc3"], - 'testing_minimal': testing_minimal, - 'testing_unit': testing_minimal + [ - "tqdm", - "safetensors", - "tabulate", # for sz.py - ], - 'testing': testing_minimal + [ - "pillow", - "onnx==1.18.0", - "onnx2torch", - "onnxruntime", - "opencv-python", - "tabulate", - "tqdm", - "safetensors", - "transformers", - "sentencepiece", - "tiktoken", - "blobfile", - "librosa", - "numba>=0.55", # librosa needs numba but uv ignores python upper bounds and some numba versions require 0 else str(diff) +NONCORE_DIRS = {"tinygrad/apps", "tinygrad/nn", "tinygrad/renderer", "tinygrad/runtime", "tinygrad/viz"} + if __name__ == "__main__": if len(sys.argv) == 3: headers = ["Name", "Lines", "Diff", "Tokens/Line", "Diff"] @@ -76,9 +78,12 @@ if __name__ == "__main__": else: print(tabulate([headers] + sorted(table, key=lambda x: -x[1]), headers="firstrow", floatfmt=".1f")+"\n") groups = sorted([('/'.join(x[0].rsplit("/", 1)[0].split("/")[0:2]), x[1], x[2]) for x in table]) + dir_sizes = {} for dir_name, group in itertools.groupby(groups, key=lambda x:x[0]): - print(f"{dir_name:30s} : {sum([x[1] for x in group]):6d}") + dir_sizes[dir_name] = sum([x[1] for x in group]) + print(f"{dir_name:30s} : {dir_sizes[dir_name]:6d}") + print(f"\n core line count: {sum([v for k,v in dir_sizes.items() if k not in NONCORE_DIRS])}") total_lines = sum([x[1] for x in table]) - print(f"\ntotal line count: {total_lines}") + print(f"total line count: {total_lines}") max_line_count = int(os.getenv("MAX_LINE_COUNT", "-1")) assert max_line_count == -1 or total_lines <= max_line_count, f"OVER {max_line_count} LINES" diff --git a/test/external/external_benchmark_bert_matmuls.py b/test/external/external_benchmark_bert_matmuls.py index 4f64629b54..fa2afd0388 100644 --- a/test/external/external_benchmark_bert_matmuls.py +++ b/test/external/external_benchmark_bert_matmuls.py @@ -13,6 +13,6 @@ if __name__ == "__main__": (Tensor.empty(BS, 16, 512, 512), Tensor.empty(BS, 512, 16, 64).permute(0,2,1,3)), # qk@v ] for t0, t1 in tensors: - print(f"{t0.shape=}, {t0.uop.st.real_strides()=}, {t1.shape=}, {t1.uop.st.real_strides()=}") + print(f"{t0.shape=}, {t0.uop.st.is_expanded()=}, {t1.shape=}, {t1.uop.st.is_expanded()=}") for _ in range(5): t0.dot(t1, dtype=acc_dtype).realize() diff --git a/test/external/external_benchmark_bert_softmax.py b/test/external/external_benchmark_bert_softmax.py index 176e2061a4..131b05dce4 100644 --- a/test/external/external_benchmark_bert_softmax.py +++ b/test/external/external_benchmark_bert_softmax.py @@ -1,4 +1,4 @@ -from tinygrad import Tensor, dtypes, Context, GlobalCounters +from tinygrad import Tensor, dtypes, GlobalCounters dtypes.default_float = dtypes.float16 from tinygrad.dtype import to_dtype from tinygrad.helpers import getenv @@ -13,6 +13,5 @@ if __name__ == "__main__": # test single kernel softmax GlobalCounters.reset() - with Context(DONT_GROUP_REDUCES=1): - single_kernel_softmax(t, -1, acc_dtype).realize() + single_kernel_softmax(t, -1, acc_dtype).realize() diff --git a/test/external/external_benchmark_op_conv.py b/test/external/external_benchmark_op_conv.py new file mode 100644 index 0000000000..31806b917b --- /dev/null +++ b/test/external/external_benchmark_op_conv.py @@ -0,0 +1,106 @@ +# ruff: noqa: E501 E712 F401 +from tinygrad import dtypes, Device +from tinygrad.uop.ops import UOp, AxisType, Ops, KernelInfo +from tinygrad.codegen import full_rewrite +from tinygrad.codegen.opt import Opt, OptOps # pylint: disable=unused-import +from tinygrad.renderer import ProgramSpec +from tinygrad.engine.realize import CompiledRunner +from tinygrad.helpers import dedup, getenv +from tinygrad.device import Buffer +from tinygrad.dtype import ImageDType, Invalid + +# PYTHONPATH="." DEV=QCOM FLOAT16=1 IMAGE=2 NOLOCALS=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/720392c9a5b986981fdbed1bb8c47a6c5573a50e/selfdrive/modeld/models/driving_vision.onnx + +def vision_conv_143(): + c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((16, 1024, 4)), (), 0) + c2 = UOp.range(32, 3, AxisType.LOOP) + c5 = UOp.range(128, 4, AxisType.LOOP) + c8 = UOp.range(16, 2, AxisType.LOOP) + c16 = UOp.range(7, 0, AxisType.REDUCE) + c17 = c8*2+c16 + c24 = ((c17<3)!=True)&(c17<35) + c26 = UOp.range(7, 1, AxisType.REDUCE) + c27 = c2*2+c26 + c32 = ((c27<3)!=True)&(c27<67) + c34 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((32, 1024, 4)), (), 1) + c38 = c5//2 + c45 = (c32&c24).where((c27*64+c38+c17*4096+-12480), UOp.const(dtypes.index, Invalid)) + c48 = (c24&c32).where(c34.index(c45), UOp.const(dtypes.float, 0.0)) + c49 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((64, 49, 4)), (), 2) + c61 = c48*c49.index((c26*4+c5%2+c16*28+c38*196)) + c63 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(128), (), 3) + c65 = c61.reduce(c16, c26, arg=Ops.ADD)+c63.index(c5) + c67 = c0.index((c2*128+c5+c8*4096), ptr=True).store(c65).end(c8, c2, c5) + + opts = None + # JITBEAM=2 + # (Opt(op=OptOps.UPCAST, axis=2, arg=4), Opt(op=OptOps.NOLOCALS, axis=None, arg=None), Opt(op=OptOps.UPCAST, axis=2, arg=2), Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.SWAP, axis=1, arg=2)) + return c67.sink(arg=KernelInfo(name="conv", opts_to_apply=opts)) + +def vision_conv_153(): + c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((8, 1024, 4)), (), 0) + c2 = UOp.range(16, 3, AxisType.LOOP) + c5 = UOp.range(256, 4, AxisType.LOOP) + c8 = UOp.range(8, 2, AxisType.LOOP) + c16 = UOp.range(7, 0, AxisType.REDUCE) + c17 = c8*2+c16 + c24 = ((c17<3)!=True)&(c17<19) + c26 = UOp.range(7, 1, AxisType.REDUCE) + c27 = c2*2+c26 + c32 = ((c27<3)!=True)&(c27<35) + c34 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((16, 1024, 4)), (), 1) + c38 = c5//2 + c45 = (c32&c24).where((c27*128+c38+c17*4096+-12672), UOp.const(dtypes.index, Invalid)) + c48 = (c24&c32).where(c34.index(c45), UOp.const(dtypes.float, 0.0)) + c49 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((128, 49, 4)), (), 2) + c61 = c48*c49.index((c26*4+c5%2+c16*28+c38*196)) + c63 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(256), (), 3) + c65 = c61.reduce(c16, c26, arg=Ops.ADD)+c63.index(c5) + c67 = c0.index((c2*256+c5+c8*4096), ptr=True).store(c65).end(c8, c2, c5) + + opts = None + # JITBEAM=2 + # (Opt(op=OptOps.UPCAST, axis=2, arg=4), Opt(op=OptOps.NOLOCALS, axis=None, arg=None), Opt(op=OptOps.UPCAST, axis=2, arg=2), Opt(op=OptOps.SWAP, axis=1, arg=2)) + return c67.sink(arg=KernelInfo(name="conv", opts_to_apply=opts)) + +def dm_conv_172(): + c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((1, 240, 4)), (), 0) + c2 = UOp.range(960, 4, AxisType.LOOP) + c5 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((8, 384, 4)), (), 1) + c7 = UOp.range(32, 0, AxisType.REDUCE) + c10 = UOp.range(4, 1, AxisType.REDUCE) + c13 = UOp.range(12, 3, AxisType.REDUCE) + c18 = UOp.range(8, 2, AxisType.REDUCE) + c23 = UOp(Ops.DEFINE_GLOBAL, dtypes.imageh((240, 128, 4)), (), 2) + c35 = c5.index((c7*4+c10+c13*128+c18*1536))*c23.index((c10*4+c2%4+c7*16+c2//4*512)) + c37 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(960), (), 3) + c39 = c35.reduce(c7, c10, arg=Ops.ADD)+c37.index(c2) + c50 = (1.0+((c39+0.044708251953125*(c39*(c39*c39)))*-2.3021129851685216).exp2()).reciprocal()*c39 + c53 = c50.reduce(c18, c13, arg=Ops.ADD)*0.010416666666666666 + c55 = c0.index(c2, ptr=True).store(c53).end(c2) + + opts = None + # JITBEAM=2 + # (Opt(op=OptOps.UPCAST, axis=0, arg=4), Opt(op=OptOps.GROUPTOP, axis=1, arg=32), Opt(op=OptOps.UNROLL, axis=1, arg=4), Opt(op=OptOps.LOCAL, axis=0, arg=8), Opt(op=OptOps.UNROLL, axis=0, arg=4), Opt(op=OptOps.GROUP, axis=1, arg=0)) + return c55.sink(arg=KernelInfo(name="conv", opts_to_apply=opts)) + +ast = {143: vision_conv_143, 153: vision_conv_153, 172: dm_conv_172}[getenv("NUM", 143)]() + +compiler = Device.default.compiler +renderer = Device.default.renderer +allocator = Device.default.allocator + +uops = full_rewrite(ast, renderer) +src = renderer.render(uops) + +lib = compiler.compile(src) +ps = ProgramSpec("conv", src, Device.DEFAULT, ast, uops) +cr = CompiledRunner(ps, precompiled=lib) + +gs = sorted(dedup([u for u in ast.toposort() if u.op is Ops.DEFINE_GLOBAL]), key=lambda u: u.arg) +# print(len(gs)) +# print([g.dtype for g in gs]) +bufs = [Buffer(ps.device, g.size, g.dtype if isinstance(g.dtype, ImageDType) else g.dtype._base).ensure_allocated() for g in gs] + +t = cr(bufs, wait=True) +print(f"{t*1e6:.2f} us") \ No newline at end of file diff --git a/test/external/external_benchmark_openpilot.py b/test/external/external_benchmark_openpilot.py deleted file mode 100644 index 158f41f6a1..0000000000 --- a/test/external/external_benchmark_openpilot.py +++ /dev/null @@ -1,67 +0,0 @@ -import time, sys, hashlib -from pathlib import Path -from tinygrad.frontend.onnx import OnnxRunner -from tinygrad import Tensor, dtypes, TinyJit -from tinygrad.helpers import IMAGE, GlobalCounters, fetch, colored, getenv, trange -import numpy as np -from extra.bench_log import BenchEvent, WallTimeEvent - -OPENPILOT_MODEL = sys.argv[1] if len(sys.argv) > 1 else "https://github.com/commaai/openpilot/raw/v0.9.4/selfdrive/modeld/models/supercombo.onnx" - -if __name__ == "__main__": - run_onnx = OnnxRunner(fetch(OPENPILOT_MODEL)) - - Tensor.manual_seed(100) - input_shapes = {name: spec.shape for name, spec in run_onnx.graph_inputs.items()} - input_types = {name: spec.dtype for name, spec in run_onnx.graph_inputs.items()} - new_inputs = {k:Tensor.randn(*shp, dtype=input_types[k]).mul(8).realize() for k,shp in input_shapes.items()} - new_inputs_junk = {k:Tensor.randn(*shp, dtype=input_types[k]).mul(8).realize() for k,shp in input_shapes.items()} - new_inputs_junk_numpy = {k:v.numpy() for k,v in new_inputs_junk.items()} - - # benchmark - for _ in range(5): - GlobalCounters.reset() - st = time.perf_counter_ns() - ret = next(iter(run_onnx(new_inputs_junk).values())).cast(dtypes.float32).numpy() - print(f"unjitted: {(time.perf_counter_ns() - st)*1e-6:7.4f} ms") - - # NOTE: the inputs to a JIT must be first level arguments - run_onnx_jit = TinyJit(lambda **kwargs: run_onnx(kwargs), prune=True) - step_times = [] - for _ in range(20): - GlobalCounters.reset() - st = time.perf_counter_ns() - with WallTimeEvent(BenchEvent.STEP): - # Need to cast non-image inputs from numpy, this is only realistic way to run model - inputs = {**{k:v for k,v in new_inputs_junk.items() if 'img' in k}, - **{k:Tensor(v) for k,v in new_inputs_junk_numpy.items() if 'img' not in k}} - ret = next(iter(run_onnx_jit(**inputs).values())).cast(dtypes.float32).numpy() - step_times.append(t:=(time.perf_counter_ns() - st)*1e-6) - print(f"jitted: {t:7.4f} ms") - - if (assert_time:=getenv("ASSERT_MIN_STEP_TIME")): - min_time = min(step_times) - assert min_time < assert_time, f"Speed regression, expected min step time of < {assert_time} ms but took: {min_time} ms" - - suffix = "" - if IMAGE.value < 2: suffix += f"_image{IMAGE.value}" # image=2 has no suffix for compatibility - if getenv("FLOAT16") == 1: suffix += "_float16" - path = Path(__file__).parent / "openpilot" / f"{hashlib.md5(OPENPILOT_MODEL.encode()).hexdigest()}{suffix}.npy" - - # validate if we have records - tinygrad_out = next(iter(run_onnx_jit(**new_inputs).values())).cast(dtypes.float32).numpy() - if getenv("SAVE_OUTPUT"): - np.save(path, tinygrad_out) - print(f"saved output to {path}!") - elif getenv("FUZZ") and path.exists(): - known_good_out = np.load(path) - for _ in trange(1000): - ret = next(iter(run_onnx_jit(**new_inputs).values())).cast(dtypes.float32).numpy() - np.testing.assert_allclose(known_good_out, ret, atol=1e-2, rtol=1e-2) - print(colored("fuzz validated!", "green")) - elif path.exists(): - known_good_out = np.load(path) - np.testing.assert_allclose(known_good_out, tinygrad_out, atol=1e-2, rtol=1e-2) - print(colored("outputs validated!", "green")) - else: - print(colored("skipping validation", "yellow")) diff --git a/test/external/external_benchmark_schedule.py b/test/external/external_benchmark_schedule.py index 3dce947828..86879e7489 100644 --- a/test/external/external_benchmark_schedule.py +++ b/test/external/external_benchmark_schedule.py @@ -2,8 +2,9 @@ from extra.models.resnet import ResNet50 from tinygrad import Tensor, nn, Device from tinygrad.helpers import Profiling, Timing, getenv from tinygrad.uop.ops import Ops -from tinygrad.codegen import get_rewrites_for_renderer, apply_rewrites, rewrites_for_linearizer -from tinygrad.uop.spec import type_verify +from tinygrad.codegen import full_rewrite_to_sink +from tinygrad.codegen.late.linearizer import linearize +from tinygrad.uop.spec import type_verify, program_spec if __name__ == "__main__": mdl = ResNet50() @@ -28,18 +29,17 @@ if __name__ == "__main__": asts = list({x.ast.key:x.ast for x in sched if x.ast.op is Ops.SINK}.values()) if (restrict_kernel := getenv("RESTRICT_KERNEL", -1)) != -1: asts = asts[restrict_kernel:restrict_kernel+1] - rewrites = get_rewrites_for_renderer(Device.default.renderer, linearizer=False) with Profiling(PROFILE, fn="/tmp/rewrite.prof"): with Timing("***** model rewrite in "): rewritten_uops = [] for u in asts: - rewritten_uops.append(apply_rewrites(u, rewrites)) + rewritten_uops.append(full_rewrite_to_sink(u, ren=Device.default.renderer)) if LINEARIZE: with Timing("***** model linearize in "): uops_line = [] for u in rewritten_uops: - uops_line.append(apply_rewrites(u, rewrites_for_linearizer)) + uops_line.append(linearize(u)) with Timing("***** model verify in "): - for u in uops_line: type_verify(u.arg.lst) - print(sum(len(u.arg.lst) for u in uops_line)) + for u in uops_line: type_verify(u, program_spec) + print(sum(len(u) for u in uops_line)) diff --git a/test/external/external_debug_metal_sd_conv.py b/test/external/external_debug_metal_sd_conv.py deleted file mode 100644 index e13c6a4857..0000000000 --- a/test/external/external_debug_metal_sd_conv.py +++ /dev/null @@ -1,46 +0,0 @@ -# ruff: noqa: E501 -from tinygrad.codegen.opt.kernel import Kernel, Opt, OptOps -from tinygrad.dtype import dtypes -from tinygrad.engine.realize import CompiledRunner, get_program -from tinygrad.codegen.opt.search import bufs_from_lin -from tinygrad.uop.ops import UOp, Ops -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View - -ast = UOp(Ops.SINK, dtypes.void, arg=None, src=( - UOp(Ops.STORE, dtypes.void, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(), arg=0, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(2, 1, 1280, 8, 8, 1, 1, 1), strides=(81920, 0, 64, 8, 1, 0, 0, 0), offset=0, mask=None, contiguous=True),)), src=()), - UOp(Ops.ADD, dtypes.half, arg=None, src=( - UOp(Ops.ADD, dtypes.half, arg=None, src=( - UOp(Ops.CAST, dtypes.half, arg=None, src=( - UOp(Ops.REDUCE_AXIS, dtypes.float, arg=(Ops.ADD, (5, 6, 7)), src=( - UOp(Ops.CAST, dtypes.float, arg=None, src=( - UOp(Ops.MUL, dtypes.half, arg=None, src=( - UOp(Ops.LOAD, dtypes.half, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(), arg=1, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(1, 2, 1, 2560, 4, 10, 4, 10), strides=(0, 163840, 0, 64, 0, 8, 0, 1), offset=-9, mask=((0, 1), (0, 2), (0, 1), (0, 2560), (0, 4), (1, 9), (0, 4), (1, 9)), contiguous=False), View(shape=(2, 1, 1280, 8, 8, 2560, 3, 3), strides=(4096000, 0, 0, 40, 1, 1600, 440, 11), offset=0, mask=None, contiguous=False))), src=()),)), - UOp(Ops.LOAD, dtypes.half, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(), arg=2, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(2, 1, 1280, 8, 8, 2560, 3, 3), strides=(0, 0, 23040, 0, 0, 9, 3, 1), offset=0, mask=None, contiguous=False),)), src=()),)),)),)),)),)), - UOp(Ops.LOAD, dtypes.half, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(), arg=3, src=()), - x17:=UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(2, 1, 1280, 8, 8, 1, 1, 1), strides=(0, 0, 1, 0, 0, 0, 0, 0), offset=0, mask=None, contiguous=False),)), src=()),)),)), - UOp(Ops.LOAD, dtypes.half, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(), arg=4, src=()), - x17,)),)),)),)) -opts = [Opt(op=OptOps.UPCAST, axis=3, arg=4), Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.UNROLL, axis=2, arg=0), Opt(op=OptOps.UNROLL, axis=1, arg=0), Opt(op=OptOps.LOCAL, axis=1, arg=8), Opt(op=OptOps.LOCAL, axis=2, arg=8), Opt(op=OptOps.LOCAL, axis=2, arg=2)] - -k = Kernel(ast) -k.apply_opts(opts) -bufs = bufs_from_lin(k) - -prg = CompiledRunner(get_program(k.ast, k.opts, k.applied_opts)) - -for i in range(10): - speed = prg(bufs, var_vals={}, wait=True) - print(f"kernel time: {speed*1e3:.2f} ms") - -# on M1 Max -# 11ms before block 9b0859d71780fef5cf3831e317f74e53f2483229 -# 15ms after block cbcc1c20eb09a1342f6581cfbb99632bade982a8 \ No newline at end of file diff --git a/test/external/external_fuzz_am_interrupts.py b/test/external/external_fuzz_am_interrupts.py deleted file mode 100644 index 2ed5724288..0000000000 --- a/test/external/external_fuzz_am_interrupts.py +++ /dev/null @@ -1,39 +0,0 @@ -import subprocess -import random -import time -from concurrent.futures import ThreadPoolExecutor, as_completed - -def run_test(i, full_run=False): - print(f"\rRunning iteration {i}...", end=" ", flush=True) - - p = subprocess.Popen(['python3', 'test/test_tiny.py', 'TestTiny.test_plus'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - if not full_run: - time.sleep(random.uniform(0, 1200) / 1000) - p.kill() - _, stderr = p.communicate() - else: - _, stderr = p.communicate() - - if full_run: - stderr_text = stderr.decode() - print(stderr_text) - assert "Ran 1 test in" in stderr_text and "OK" in stderr_text - -max_workers = 4 -with ThreadPoolExecutor(max_workers=max_workers) as executor: - futures = [] - for i in range(1000000): - if i % 100 == 0: - for future in as_completed(futures): - try: future.result() - except Exception as e: - print(f"\nError in iteration: {e}") - futures = [] - - run_test(i, True) - else: - future = executor.submit(run_test, i, False) - futures.append(future) - - if len(futures) > max_workers * 2: futures = [f for f in futures if not f.done()] \ No newline at end of file diff --git a/test/external/external_fuzz_hcq_mp.py b/test/external/external_fuzz_hcq_mp.py new file mode 100644 index 0000000000..5fb68bdeaf --- /dev/null +++ b/test/external/external_fuzz_hcq_mp.py @@ -0,0 +1,44 @@ +import subprocess +import random +import time +from concurrent.futures import ProcessPoolExecutor, as_completed +from tinygrad.helpers import getenv + +# checks that HCQ drivers can be killed during operation without causing issues + +def run_test(i, full_run=False, force_ok=False): + print(f"\rRunning iteration {i}...", end=" ", flush=True) + + p = subprocess.Popen(["python3", "test/test_tiny.py", "TestTiny.test_plus"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + if not full_run: + time.sleep(random.uniform(0, 1200) / 1000.0) + p.kill() + _, stderr = p.communicate() + else: + _, stderr = p.communicate() + stderr_text = stderr.decode() + assert ("Ran 1 test in" in stderr_text and "OK" in stderr_text) or (not force_ok and "Failed to take lock file" in stderr_text), stderr_text + +if __name__ == "__main__": + max_workers = getenv("MAX_WORKERS", 4) + with ProcessPoolExecutor(max_workers=max_workers) as executor: + futures = [] + for i in range(1000000): + if i % 100 == 0: + # wait for everything we launched so far + for f in as_completed(futures): + try: + f.result() + except Exception as e: + print(f"\nError in iteration: {e}") + futures = [] + + # do a full run in the main proc + run_test(i, True, force_ok=True) + else: + futures.append(executor.submit(run_test, i, bool(getenv("FULL_RUN", 0)))) + + # keep list small + if len(futures) > max_workers * 2: + futures = [f for f in futures if not f.done()] diff --git a/test/external/external_model_benchmark.py b/test/external/external_model_benchmark.py index b29892f2d9..a5ecac4623 100644 --- a/test/external/external_model_benchmark.py +++ b/test/external/external_model_benchmark.py @@ -4,7 +4,7 @@ import torch torch.set_num_threads(1) import onnxruntime as ort from onnx2torch import convert -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner from tinygrad.helpers import OSX, DEBUG, fetch, getenv from tinygrad.dtype import _to_np_dtype from tinygrad import Tensor, Device, dtypes diff --git a/test/external/external_nhwc_conv.py b/test/external/external_nhwc_conv.py new file mode 100644 index 0000000000..541de1154b --- /dev/null +++ b/test/external/external_nhwc_conv.py @@ -0,0 +1,38 @@ +from tinygrad import Tensor, nn, Context, GlobalCounters + +if __name__ == "__main__": + conv = nn.Conv2d(64, 128, 3) + img = Tensor.randn((1,64,128,128)) + with Context(DEBUG=0, BEAM=0): + Tensor.realize(img, conv.weight, conv.bias) + + tst = conv(img).permute(0,2,3,1).realize() + print(tst.shape) + + print("NEW") + img_perm = img.permute(0,2,3,1).contiguous() + print(img_perm.shape) + pp = img_perm.permute(0,3,1,2)._pool((3,3)).permute(0,2,3,4,5,1) + + def hwio(pp, conv): + pp = pp.unsqueeze(-1) + weight = conv.weight.permute(2,3,1,0).contiguous() + print(pp.shape, weight.shape, (pp*weight).shape) + return (pp * weight).sum([-4,-3, -2]) + + def ohwi(pp, conv): + pp = pp.unsqueeze(-4) + weight = conv.weight.permute(0,2,3,1).contiguous() + print(pp.shape, weight.shape, (pp*weight).shape) + return (pp * weight).sum([-3,-2,-1]) + + for f in [hwio, ohwi]: + GlobalCounters.reset() + print("\n**************", f.__name__, "**************") + out = f(pp, conv) + out.realize() + print(out.shape) + + with Context(DEBUG=0, BEAM=0): + err = (tst-out).square() + print(err.mean().item(), err.max().item()) diff --git a/test/external/external_test_dev_var.py b/test/external/external_test_dev_var.py new file mode 100644 index 0000000000..41abbe8e79 --- /dev/null +++ b/test/external/external_test_dev_var.py @@ -0,0 +1,39 @@ +import subprocess, unittest, os, sys +from tinygrad.device import Device + +class TestTinygradSlow(unittest.TestCase): + def test_env_overwrite_default_device(self): + subprocess.run([f'{Device.DEFAULT}=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + subprocess.run([f'DISK=1 {Device.DEFAULT}=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + subprocess.run([f'NPY=1 {Device.DEFAULT}=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + + if Device.DEFAULT != "CPU": + # setting multiple devices fail + with self.assertRaises(subprocess.CalledProcessError): + subprocess.run([f'{Device.DEFAULT}=1 CPU=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + + # setting device via DEV + subprocess.run([f'DEV={Device.DEFAULT.capitalize()} python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + subprocess.run([f'DEV={Device.DEFAULT.lower()} python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + subprocess.run([f'DEV={Device.DEFAULT.upper()} python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + + with self.assertRaises(subprocess.CalledProcessError): + subprocess.run([f'DEV={Device.DEFAULT} CPU=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], + shell=True, check=True) + +class TestRunAsModule(unittest.TestCase): + def test_module_runs(self): + p = subprocess.run([sys.executable, "-m", "tinygrad.device"],stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env={**os.environ, "DEBUG": "1"}, timeout=40,) + out = (p.stdout + p.stderr).decode() + self.assertEqual(p.returncode, 0, msg=out) + +if __name__ == '__main__': + unittest.main() diff --git a/test/external/external_test_example.py b/test/external/external_test_example.py index 86c3958c80..a2740f3a5e 100644 --- a/test/external/external_test_example.py +++ b/test/external/external_test_example.py @@ -58,8 +58,8 @@ class TestExample(unittest.TestCase): print(f"WARNING: {device} test isn't running") return - x = Tensor.eye(64, device=device, requires_grad=True) - y = Tensor.eye(64, device=device, requires_grad=True) + x = Tensor.eye(8, device=device, requires_grad=True) + y = Tensor.eye(8, device=device, requires_grad=True) z = y.matmul(x).sum() z.backward() diff --git a/test/external/external_test_hcq_open.py b/test/external/external_test_hcq_open.py new file mode 100644 index 0000000000..0b0f073f13 --- /dev/null +++ b/test/external/external_test_hcq_open.py @@ -0,0 +1,20 @@ +import os +if "DEV" not in os.environ: os.environ["DEV"] = "AMD" + +import unittest, time +from tinygrad import Device + +class TestOpen(unittest.TestCase): + def generate_test_open(n): + def test(self): + dev = Device[Device.DEFAULT] + for i in range(10): + dev.allocator.alloc(10 << 20) + time.sleep(0.5) + test.__name__ = f'test_open_{n}' + return test + + for i in range(64): locals()[f'test_open_{i}'] = generate_test_open(i) + +if __name__ == '__main__': + unittest.main() diff --git a/test/external/external_test_onnx_backend.py b/test/external/external_test_onnx_backend.py index 112ccd797c..d467d24ece 100644 --- a/test/external/external_test_onnx_backend.py +++ b/test/external/external_test_onnx_backend.py @@ -6,7 +6,7 @@ import numpy as np from tinygrad import Tensor, Device, dtypes from tinygrad.helpers import getenv, OSX from tinygrad.device import is_dtype_supported -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner # pip3 install tabulate pytest_plugins = 'onnx.backend.test.report', @@ -112,7 +112,6 @@ backend_test.exclude('test_dequantizelinear_e5m2_cpu') backend_test.exclude('test_dequantizelinear_float4e2m1_cpu') # we don't support indexes -backend_test.exclude('test_nonzero_*') # no support for int pow backend_test.exclude('test_pow_types_int32_int32_cpu') diff --git a/test/external/external_test_onnx_ops.py b/test/external/external_test_onnx_ops.py index e4be34fa5e..ce62b32b58 100644 --- a/test/external/external_test_onnx_ops.py +++ b/test/external/external_test_onnx_ops.py @@ -5,7 +5,7 @@ from typing import Any import unittest, onnx, tempfile from tinygrad import dtypes, Tensor -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner import numpy as np from extra.onnx_helpers import validate from onnx.defs import ONNX_DOMAIN, AI_ONNX_PREVIEW_TRAINING_DOMAIN @@ -272,6 +272,10 @@ class TestMainOnnxOps(TestOnnxOps): def test_qlinearmatmul_2D_int8_float32(self): self._run_qlinearmatmul_test(np.int8, np.float32, 2) def test_qlinearmatmul_3D_int8_float32(self): self._run_qlinearmatmul_test(np.int8, np.float32, 3) + def test_reduce_l2_half(self): + inputs = {"data": np.random.randn(1, 1, 32, 32, 32).astype(np.half)*100} + self.helper_test_single_op("ReduceL2", inputs, {}, ["reduced"]) + class TestTrainingOnnxOps(TestOnnxOps): # NOTE: ORT doesn't actually support training ops on cpu so we test using functions provided by onnx DOMAIN = AI_ONNX_PREVIEW_TRAINING_DOMAIN @@ -282,11 +286,11 @@ class TestTrainingOnnxOps(TestOnnxOps): tiny_out = runner(inps) onnx_out = onnx_fxn(**inps, **opts) for (nm, t_out), o_out in zip(tiny_out.items(), onnx_out): - np.testing.assert_allclose(t_out.numpy(), o_out, rtol=1e-3, atol=1e-6, err_msg=f"{nm} failed") + np.testing.assert_allclose(t_out.numpy(), o_out, rtol=1e-6, atol=1e-6, err_msg=f"{nm} failed") - def test_adagrad_t_greater_than_zero(self): + def test_adagrad_t(self): from onnx.backend.test.case.node.adagrad import apply_adagrad - for t in [1, 3, 100]: + for t in [0, 1, 3, 100]: inputs = { "r": np.array(0.01, dtype=np.float32), "t": np.array(t, dtype=np.int32), @@ -298,10 +302,10 @@ class TestTrainingOnnxOps(TestOnnxOps): outputs = ["X_out", "H_out"] self._validate_training("Adagrad", apply_adagrad, inputs, attributes, outputs) - def test_momentum_t_greater_than_zero(self): + def test_momentum(self): from onnx.backend.test.case.node.momentum import apply_momentum, apply_nesterov for onnx_fxn, mode in ((apply_momentum, "standard"), (apply_nesterov, "nesterov")): - for t in [1, 3, 100]: + for t in [0, 1, 3, 100]: inputs = { "r": np.array(0.01, dtype=np.float32), "t": np.array(t, dtype=np.int32), @@ -313,9 +317,9 @@ class TestTrainingOnnxOps(TestOnnxOps): outputs = ["X_out", "V_out"] self._validate_training("Momentum", onnx_fxn, inputs, attributes, outputs) - def test_adam_t_greater_than_zero(self): + def test_adam(self): from onnx.backend.test.case.node.adam import apply_adam - for t in [1, 3, 100]: + for t in [0, 1, 3, 100]: inputs = { "r": np.array(0.01, dtype=np.float32), "t": np.array(t, dtype=np.int32), @@ -422,6 +426,7 @@ class TestContribOnnxOps(TestOnnxOps): outputs = ["C"] self.helper_test_single_op("QLinearAdd", inputs, attributes, outputs, atol=1) # TODO: look into why this is inaccurate + def test_qlinear_add_round_half_to_even(self): with self.subTest(test_case="round_half_to_even"): inputs = { "A": np.array([1, 1, 1, 1], dtype=np.int8), @@ -435,7 +440,7 @@ class TestContribOnnxOps(TestOnnxOps): } attributes = {} outputs = ["C"] - self.helper_test_single_op("QLinearAdd", inputs, attributes, outputs) + self.helper_test_single_op("QLinearAdd", inputs, attributes, outputs, atol=1) # TODO: look into why this is inaccurate def test_qlinear_mul(self): for dtype, zero_point in [(np.uint8, 128), (np.int8, 0)]: @@ -486,4 +491,4 @@ class TestContribOnnxOps(TestOnnxOps): self.helper_test_single_op("QLinearGlobalAveragePool", inputs, attributes, outputs) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/test/external/external_test_onnx_runner.py b/test/external/external_test_onnx_runner.py index f0d8941b45..0b853bc22e 100644 --- a/test/external/external_test_onnx_runner.py +++ b/test/external/external_test_onnx_runner.py @@ -3,7 +3,7 @@ import numpy as np from tinygrad import dtypes, Tensor from tinygrad.uop.ops import Ops from tinygrad.device import is_dtype_supported -from tinygrad.frontend.onnx import OnnxRunner, OnnxDataType +from tinygrad.nn.onnx import OnnxRunner, OnnxDataType from hypothesis import given, strategies as st # copied from test_const_folding.py diff --git a/test/external/external_test_opt.py b/test/external/external_test_opt.py index c59e60de80..f1bab81d26 100644 --- a/test/external/external_test_opt.py +++ b/test/external/external_test_opt.py @@ -4,7 +4,7 @@ import numpy as np import torch from tinygrad import GlobalCounters, Tensor, Device -from tinygrad.helpers import getenv, Context, RANGEIFY +from tinygrad.helpers import getenv from tinygrad.nn.state import get_parameters from tinygrad.engine.realize import capturing from tinygrad.tensor import _to_np_dtype @@ -164,7 +164,7 @@ class TestOpt(unittest.TestCase): def test_permute_was_pushed(self): a = Tensor.randn(16, 16, 16) - with CLCache(1 if RANGEIFY else 2): + with CLCache(1): c = a.sum(2) d = c.permute(1,0).contiguous() d.realize() @@ -172,7 +172,7 @@ class TestOpt(unittest.TestCase): def test_permute_was_pushed_through_contract_reshape(self): a = Tensor.randn(4, 4, 4, 4, 4) - with CLCache(1 if RANGEIFY else 2): + with CLCache(1): c = a.sum(-1) d = c.reshape(16,16).permute(1,0).contiguous() d.realize() @@ -180,7 +180,7 @@ class TestOpt(unittest.TestCase): def test_permute_was_pushed_through_contractw1s_reshape(self): a = Tensor.randn(4, 4, 4, 4, 4) - with CLCache(1 if RANGEIFY else 2): + with CLCache(1): c = a.sum(-1) d = c.reshape(16,1,16).permute(2,1,0).contiguous() d.realize() @@ -188,7 +188,7 @@ class TestOpt(unittest.TestCase): def test_permute_was_pushed_through_expand_reshape(self): a = Tensor.randn(16, 16, 16) - with CLCache(1 if RANGEIFY else 2): + with CLCache(1): c = a.sum(2) d = c.reshape(4,4,4,4).permute(2,3,0,1).contiguous() d.realize() @@ -217,24 +217,22 @@ class TestOpt(unittest.TestCase): assert cache_len == 1, "reduceop was rerun!" def test_expand_reduce_is_folded_on_same_axis(self): - with Context(FUSE_CONV_BW=1): - for axis in [0, 1]: - for n in [4, 8, 16]: - b = torch.ones(n, n).sum(axis).reshape(n, 1).expand(n, n).sum(axis) - with CLCache(allowed=3 if RANGEIFY else 2): - a = Tensor.ones(n, n).contiguous().sum(axis).reshape(n, 1).expand(n, n).sum(axis) - a.realize() - np.testing.assert_allclose(a.numpy(), b.numpy(), rtol=1e-3, atol=1e-5) - - def test_expand_reduce_is_folded_on_different_axes(self): - with Context(FUSE_CONV_BW=1): - axis1, axis2 = 0, 1 + for axis in [0, 1]: for n in [4, 8, 16]: - b = torch.ones(n, n).sum(axis1).reshape(n, 1).expand(n, n).sum(axis2) - with CLCache(allowed=3 if RANGEIFY else 2): - a = Tensor.ones(n, n).contiguous().sum(axis1).reshape(n, 1).expand(n, n).sum(axis2) + b = torch.ones(n, n).sum(axis).reshape(n, 1).expand(n, n).sum(axis) + with CLCache(allowed=3): + a = Tensor.ones(n, n).contiguous().sum(axis).reshape(n, 1).expand(n, n).sum(axis) a.realize() np.testing.assert_allclose(a.numpy(), b.numpy(), rtol=1e-3, atol=1e-5) + def test_expand_reduce_is_folded_on_different_axes(self): + axis1, axis2 = 0, 1 + for n in [4, 8, 16]: + b = torch.ones(n, n).sum(axis1).reshape(n, 1).expand(n, n).sum(axis2) + with CLCache(allowed=3): + a = Tensor.ones(n, n).contiguous().sum(axis1).reshape(n, 1).expand(n, n).sum(axis2) + a.realize() + np.testing.assert_allclose(a.numpy(), b.numpy(), rtol=1e-3, atol=1e-5) + if __name__ == '__main__': unittest.main() diff --git a/test/external/external_test_simple_tokenizer.py b/test/external/external_test_simple_tokenizer.py index 9c3ca8f420..8fc3299ee1 100644 --- a/test/external/external_test_simple_tokenizer.py +++ b/test/external/external_test_simple_tokenizer.py @@ -1,41 +1,50 @@ +import functools, multiprocessing from transformers import AutoTokenizer from datasets import load_dataset -from tinygrad.apps.llm import SimpleTokenizer, gpt2_decode_vocab, get_llama_re +from tinygrad.apps.llm import SimpleTokenizer from tinygrad.helpers import tqdm, getenv, partition +@functools.cache +def get_tokenizers(): + print("getting tokenizers") + base_tokenizer = AutoTokenizer.from_pretrained("NousResearch/Meta-Llama-3-8B-Instruct") + special_tokens, normal_tokens = partition(((t, tid) for t, tid in base_tokenizer.vocab.items()), lambda e: e[1] in base_tokenizer.all_special_ids) + simple_tokenizer = SimpleTokenizer(dict(normal_tokens), dict(special_tokens)) + return base_tokenizer, simple_tokenizer + +def test_tokenize(samp) -> bool: + base_tokenizer, simple_tokenizer = get_tokenizers() + idx, txt = samp + try: simple_tokens = tuple(simple_tokenizer.encode(txt)) + except RuntimeError: simple_tokens = () + base_tokens = tuple(base_tokenizer.encode(txt, add_special_tokens=False)) + if simple_tokens != base_tokens: + print(f"tokens mismatch at index: {idx}.\n") + color_codes = [91, 92, 94, 93, 95] + def color_tokens(tids): + return "".join(f"\033[{color_codes[i%len(color_codes)]}m{base_tokenizer.decode([t])}" for i, t in enumerate(tids)) + "\033[0m" + print("simple: ", color_tokens(simple_tokens)) + print("official:", color_tokens(base_tokens) + "\n") + return False + if simple_tokenizer.decode(simple_tokens) != txt: + print(f"decode mismatch at {idx}") + return False + return True + # use ALLOW_FAILED=-1 to go over the entire dataset without printing. if __name__ == "__main__": - base_tokenizer = AutoTokenizer.from_pretrained("NousResearch/Meta-Llama-3-8B-Instruct") - special_tokens, normal_tokens = partition(((t, tid) for t, tid in base_tokenizer.vocab.items()), - lambda e: e[1] in base_tokenizer.all_special_ids) - inv_vocab = { tid: word for word, tid in base_tokenizer.get_vocab().items() } - simple_tokenizer = SimpleTokenizer(get_llama_re(), gpt2_decode_vocab(dict(normal_tokens)), dict(special_tokens)) - - color_codes = [ 91, 92, 94, 93, 95 ] - def color_tokens(tids): - return "".join(f"\033[{color_codes[i%len(color_codes)]}m{base_tokenizer.decode([t])}" for i, t in enumerate(tids)) + "\033[0m" - + print("loading datasets") ds = load_dataset("OpenAssistant/oasst1") + loaded_ds = [(idx, el["text"]) for idx, el in enumerate(ds["train"])] + print(f"loaded {len(loaded_ds)}") + allow_failed = getenv("ALLOW_FAILED", 10) - fail_count, total = 0, 0 - - for idx, el in enumerate(tqdm(ds["train"])): - total += 1 - - try: simple_tokens = tuple(simple_tokenizer.encode(el["text"])) - except RuntimeError: simple_tokens = () - base_tokens = tuple(base_tokenizer.encode(el["text"], add_special_tokens=False)) - - if simple_tokens != base_tokens: - fail_count += 1 - allow_failed -= 1 - - if allow_failed >= 0: - print(f"tokens mismatch at index: {idx}.\n") - - print("simple: ", color_tokens(simple_tokens)) - print("official:", color_tokens(base_tokens) + "\n") - - if allow_failed == 0: break - print(f"{fail_count}/{total} samples are inconsistent with the official tokenizer.") + with multiprocessing.Pool(16) as pool: + for good in tqdm(pool.imap_unordered(test_tokenize, loaded_ds), total=len(loaded_ds)): + total += 1 + if not good: + fail_count += 1 + allow_failed -= 1 + if allow_failed == 0: break + print(f"{fail_count}/{total} samples are inconsistent with the official tokenizer.") diff --git a/test/external/external_test_train_gpt2.py b/test/external/external_test_train_gpt2.py deleted file mode 100644 index 196beff5a1..0000000000 --- a/test/external/external_test_train_gpt2.py +++ /dev/null @@ -1,55 +0,0 @@ -# ruff: noqa: E501 -import unittest - -from tinygrad.uop.ops import UOp, Ops -from .search import Opt, OptOps -from tinygrad.dtype import dtypes -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View -from tinygrad.codegen.opt.kernel import Kernel - -from test.external.fuzz_linearizer import run_linearizer - -class TestTrainGpt2Kernel(unittest.TestCase): - def test_1(self): - # kernel 244 - ast = UOp(Ops.SINK, dtypes.void, arg=None, src=( - UOp(Ops.STORE, dtypes.void, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(206045184), arg=0, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4, 1024, 50304, 1), strides=(51511296, 50304, 1, 0), offset=0, mask=None, contiguous=True),)), src=()), - UOp(Ops.REDUCE_AXIS, dtypes.float, arg=(Ops.ADD, (3,)), src=( - UOp(Ops.MUL, dtypes.float, arg=None, src=( - UOp(Ops.LOAD, dtypes.float, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(3145728), arg=1, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4, 1024, 50304, 768), strides=(786432, 768, 0, 1), offset=0, mask=None, contiguous=False),)), src=()),)), - UOp(Ops.LOAD, dtypes.float, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(38633472), arg=2, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4, 1024, 50304, 768), strides=(0, 0, 768, 1), offset=0, mask=None, contiguous=False),)), src=()),)),)),)),)),)) - - opts = [Opt(op=OptOps.LOCAL, axis=0, arg=16), Opt(op=OptOps.UPCAST, axis=1, arg=3), Opt(op=OptOps.LOCAL, axis=0, arg=2)] - kernel = Kernel(ast) - kernel.apply_opts(opts) - run_linearizer(kernel) - - def test_2(self): - # kernel 254 - ast = UOp(Ops.SINK, dtypes.void, arg=None, src=( - UOp(Ops.STORE, dtypes.void, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(3145728), arg=0, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4, 1024, 1, 768), strides=(786432, 768, 0, 1), offset=0, mask=None, contiguous=True),)), src=()), - UOp(Ops.REDUCE_AXIS, dtypes.float, arg=(Ops.ADD, (2,)), src=( - UOp(Ops.MUL, dtypes.float, arg=None, src=( - UOp(Ops.LOAD, dtypes.float, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(38633472), arg=1, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4, 1024, 50304, 768), strides=(0, 0, 768, 1), offset=0, mask=None, contiguous=False),)), src=()),)), - UOp(Ops.LOAD, dtypes.float, arg=None, src=( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(205852672), arg=2, src=()), - UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4, 1024, 50304, 768), strides=(51463168, 50257, 1, 0), offset=0, mask=((0, 4), (0, 1024), (0, 50257), (0, 768)), contiguous=False),)), src=()),)),)),)),)),)) - - opts = [Opt(op=OptOps.LOCAL, axis=1, arg=16), Opt(op=OptOps.LOCAL, axis=0, arg=8), Opt(op=OptOps.UPCAST, axis=2, arg=4), Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.LOCAL, axis=1, arg=4), Opt(op=OptOps.UPCAST, axis=3, arg=4)] - kernel = Kernel(ast) - kernel.apply_opts(opts) - run_linearizer(kernel) - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/test/external/external_uop_gc.py b/test/external/external_uop_gc.py index a773ac5053..4327b69a56 100644 --- a/test/external/external_uop_gc.py +++ b/test/external/external_uop_gc.py @@ -1,7 +1,8 @@ import gc -from tinygrad import Tensor, UOp, Device -from tinygrad.shape.shapetracker import views_to_valid_uop +from tinygrad import Tensor, UOp, Device, nn from tinygrad.engine.realize import method_cache, get_program +from tinygrad.schedule.indexing import apply_movement_op +from test.test_tiny import TestTiny def uops_allocated(): return sum([isinstance(x, UOp) for x in gc.get_objects()]) def print_uops(): @@ -46,9 +47,16 @@ def realized_gradient(): z = y.matmul(x).sum() z.backward() Tensor.realize(x, y, z, x.grad, y.grad) +def nn_batchnorm(): nn.BatchNorm(64) +def nn_conv2d(): nn.Conv2d(64, 64, 3) +def plus(): TestTiny().test_plus() +def mnist(): TestTiny().test_mnist() +def mnist_backward(): TestTiny().test_mnist_backward() + tests = [start, single_tensor, two_plus_two, two_plus_two_schedule, two_plus_two_kernel, two_plus_two_linearize, two_plus_two_realize, two_plus_two_item, gradient_test, - realized_eye, realized_list, kernel_matmul, realized_matmul, realized_gradient] + realized_eye, realized_list, kernel_matmul, realized_matmul, realized_gradient, + nn_batchnorm, nn_conv2d, plus, mnist, mnist_backward] if __name__ == "__main__": gc.disable() @@ -60,12 +68,13 @@ if __name__ == "__main__": # these caches will keep uops alive method_cache.clear() - views_to_valid_uop.cache_clear() + apply_movement_op.cache_clear() + Tensor._device_seeds.clear() + Tensor._device_rng_counters.clear() new_uops = uops_allocated() - print_uops() gc.collect() new_uops_gc = uops_allocated() print(f"{t.__name__:30s}: {new_uops:3d} -> {new_uops_gc:3d}") + if new_uops != start_uops: print_uops() assert new_uops == start_uops - #print_uops() diff --git a/test/external/fuzz_fast_idiv.py b/test/external/fuzz_fast_idiv.py index a6e48f1d8a..8d6e556b1a 100644 --- a/test/external/fuzz_fast_idiv.py +++ b/test/external/fuzz_fast_idiv.py @@ -1,7 +1,7 @@ import random import z3 from tinygrad import dtypes -from tinygrad.uop.spec import uops_to_z3, z3_cdiv +from tinygrad.uop.validate import uops_to_z3, z3_cdiv from tinygrad.uop.ops import UOp from tinygrad.uop.decompositions import fast_idiv random.seed(42) diff --git a/test/external/fuzz_linearizer.py b/test/external/fuzz_linearizer.py index 19ed23f5d6..093474345e 100644 --- a/test/external/fuzz_linearizer.py +++ b/test/external/fuzz_linearizer.py @@ -207,7 +207,7 @@ def fuzz_linearizer(lin: Kernel, rtol=1e-2, atol=1e-2, opts_list=None): if not FUZZ_ALL_ACTIONS and test_lin.applied_opts: print(f"applied opts: {test_lin.applied_opts}") # stop if kernel uops repeat - try: tuops = tuplize_uops(get_program(test_lin.get_optimized_ast(), test_lin.opts).uops) + try: tuops = tuplize_uops(get_program(test_lin.get_optimized_ast(), test_lin.ren).uops) except KeyboardInterrupt: raise except BaseException as e: print(test_lin.ast) @@ -224,7 +224,7 @@ def fuzz_linearizer(lin: Kernel, rtol=1e-2, atol=1e-2, opts_list=None): (msg, rawbufs, var_vals, ground_truth, state1) = compare_linearizer(test_lin, rawbufs, var_vals, ground_truth, rtol=rtol, atol=atol) if state1 is not None and validate_device is not None: validate_lin = test_lin.copy() - validate_lin.opts = validate_device.renderer + validate_lin.ren = validate_device.renderer if validate_rawbufs is None: validate_rawbufs = [get_fuzz_rawbuf_like(x, copy=True, force_device=validate_device.device) for x in rawbufs] (_msg, _, _, _, state2) = compare_linearizer(validate_lin, validate_rawbufs, var_vals, ground_truth, rtol=rtol, atol=atol) diff --git a/test/external/fuzz_shapetracker_math.py b/test/external/fuzz_shapetracker_math.py index c7364ae3e5..9d1e86a654 100644 --- a/test/external/fuzz_shapetracker_math.py +++ b/test/external/fuzz_shapetracker_math.py @@ -2,7 +2,6 @@ import random from tinygrad.helpers import getenv, DEBUG, colored, trange from tinygrad.shape.shapetracker import ShapeTracker from test.external.fuzz_shapetracker import shapetracker_ops -from test.external.fuzz_shapetracker import do_permute, do_reshape_split_one, do_reshape_combine_two, do_flip, do_pad from test.unit.test_shapetracker_math import st_equal, MultiShapeTracker def fuzz_plus() -> tuple[ShapeTracker, ShapeTracker]: @@ -14,21 +13,10 @@ def fuzz_plus() -> tuple[ShapeTracker, ShapeTracker]: st_sum = backup + m.sts[1] return m.sts[0], st_sum -# shrink and expand aren't invertible, and stride is only invertible in the flip case -invertible_shapetracker_ops = [do_permute, do_reshape_split_one, do_reshape_combine_two, do_flip, do_pad] - -def fuzz_invert() -> tuple[ShapeTracker, ShapeTracker]: - start = ShapeTracker.from_shape((random.randint(1, 10), random.randint(1, 10), random.randint(1, 10))) - m = MultiShapeTracker([start]) - for _ in range(8): random.choice(invertible_shapetracker_ops)(m) - inv = m.sts[0].invert(start.shape) - st_sum = (m.sts[0] + inv) if inv else None - return start, st_sum - if __name__ == "__main__": if seed:=getenv("SEED"): random.seed(seed) total = getenv("CNT", 1000) - for fuzz in [globals()[f'fuzz_{x}'] for x in getenv("FUZZ", "invert,plus").split(",")]: + for fuzz in [globals()[f'fuzz_{x}'] for x in getenv("FUZZ", "plus").split(",")]: same_but_neq = 0 for _ in trange(total, desc=f"{fuzz}"): st1, st2 = fuzz() diff --git a/test/external/fuzz_shapetracker_size.py b/test/external/fuzz_shapetracker_size.py deleted file mode 100644 index dc76f3aecd..0000000000 --- a/test/external/fuzz_shapetracker_size.py +++ /dev/null @@ -1,13 +0,0 @@ -from tinygrad.shape.shapetracker import ShapeTracker -from test.external.fuzz_shapetracker import shapetracker_ops as st_ops -from test.unit.test_shapetracker_math import MultiShapeTracker -from tinygrad.helpers import getenv -import random - -random.seed(getenv("SEED", 42)) -for i in range(getenv("CNT", 2000)): - if getenv("DEBUG", 0) >= 1: print() - N = random.randint(1, 10000) - mst = MultiShapeTracker([ShapeTracker.from_shape((N,))]) # st_ops don't mutate regular shapetrackers for some reason - for j in range(20): random.choice(st_ops)(mst) - assert mst.sts[0].real_size() <= N, f"{N=}, real_size={mst.sts[0].real_size()}, st={mst.sts[0]}" diff --git a/test/external/fuzz_symbolic.py b/test/external/fuzz_symbolic.py index 0e87883d6b..060ce2ee8b 100644 --- a/test/external/fuzz_symbolic.py +++ b/test/external/fuzz_symbolic.py @@ -2,7 +2,7 @@ import random, operator import z3 from tinygrad import Variable, dtypes from tinygrad.uop.ops import UOp -from tinygrad.uop.spec import uops_to_z3 +from tinygrad.uop.validate import uops_to_z3 from tinygrad.helpers import DEBUG, Context seed = random.randint(0, 100) diff --git a/test/external/process_replay/process_replay.py b/test/external/process_replay/process_replay.py index 5baf9f2015..ea71e9ef7c 100755 --- a/test/external/process_replay/process_replay.py +++ b/test/external/process_replay/process_replay.py @@ -8,12 +8,12 @@ ASSERT_DIFF = int((flag:="[pr]") in os.getenv("COMMIT_MESSAGE", flag) or flag in if not int(os.getenv("ASSERT_PROCESS_REPLAY", "1")): ASSERT_DIFF = 0 try: - from tinygrad.schedule.kernelize import get_kernelize_map + from tinygrad.schedule.rangeify import get_rangeify_map from tinygrad.renderer import Renderer, ProgramSpec from tinygrad.engine.realize import get_program from tinygrad.uop.ops import UOp, Ops, KernelInfo from tinygrad.codegen.opt import Opt - from tinygrad.helpers import VERSION, Context, ContextVar, colored, db_connection, getenv, tqdm + from tinygrad.helpers import VERSION, Context, ContextVar, colored, db_connection, getenv, tqdm, BEAM from tinygrad.device import Device except ImportError as e: print(repr(e)) @@ -42,17 +42,17 @@ class ProcessReplayWarning(Warning): pass # *** replay the function and convert return values to string -def replay_kernelize(ret:dict[UOp, UOp], big_sink:UOp) -> tuple[str, str, tuple[Any, ...]]: +def replay_get_rangeify_map(ret:dict[UOp, UOp], big_sink:UOp) -> tuple[str, str, tuple[Any, ...]]: UOp.unique_num = itertools.count(max([u.arg for u in big_sink.toposort() if u.op is Ops.UNIQUE], default=0)+1) - new_sink = big_sink.substitute(get_kernelize_map(big_sink)) + new_sink = big_sink.substitute(get_rangeify_map(big_sink)) def to_str(ret:UOp) -> str: asts = [repr(u.arg.ast) for u in ret.toposort() if u.op is Ops.KERNEL] return "\n".join([f"{len(asts)} kernels", *asts]) - return to_str(new_sink), to_str(ret[big_sink]), (big_sink,) + return to_str(new_sink), to_str(big_sink.substitute(ret)), (big_sink,) def replay_get_program(p:ProgramSpec, ast:UOp, renderer:Renderer|None=None, opts:list[Opt]|None=None) -> tuple[str, str, tuple[Any, ...]]: - # NOTE: this always uses the opts_to_apply path - sink_arg = ast.arg or KernelInfo(opts_to_apply=p.applied_opts) + # the ast.arg is non None if we are inside of search.py + sink_arg = ast.arg or KernelInfo(opts_to_apply=tuple(opts) if opts is not None else p.applied_opts if BEAM>=1 else None) input_ast = ast.replace(arg=replace(sink_arg, name=p.name)) # if no renderer was provided, open the device to get it if renderer is None: renderer = Device[p.device].renderer @@ -65,7 +65,7 @@ def replay_get_program(p:ProgramSpec, ast:UOp, renderer:Renderer|None=None, opts ast_repr = codecs.decode(str(input_ast), "unicode_escape") return to_str(p2), to_str(p), (ast_repr, renderer) -replayers: dict[str, Callable[..., tuple[str, str, tuple[Any, ...]]]] = {"get_kernelize_map":replay_kernelize, "get_program":replay_get_program} +replayers: dict[str, Callable[..., tuple[str, str, tuple[Any, ...]]]] = {"get_rangeify_map":replay_get_rangeify_map, "get_program":replay_get_program} # *** run replayers on captured rows and print diffs @@ -114,7 +114,7 @@ def _pmap(fxns:dict[str, Callable]) -> None: with multiprocessing.get_context("spawn").Pool(multiprocessing.cpu_count()) as pool: bar = tqdm(total=row_count) - for _ in pool.imap_unordered(functools.partial(diff, fxns=fxns), range(0, row_count, PAGE_SIZE)): bar.update(PAGE_SIZE) + for _ in pool.imap_unordered(functools.partial(diff, fxns=fxns), range(0, row_count, s:=min(PAGE_SIZE, row_count))): bar.update(s) pool.close() pool.join() pool.terminate() diff --git a/test/external/speed_v_theoretical.py b/test/external/speed_v_theoretical.py index 8b04d4af2b..4f09759942 100644 --- a/test/external/speed_v_theoretical.py +++ b/test/external/speed_v_theoretical.py @@ -85,17 +85,16 @@ class TestKernelSpeed(unittest.TestCase): gbs = mems / tm / 1e9 self._compare(tm, tflops, gbs, nv_tflops, nv_gbs, amd_tflops, amd_gbs) - # NOTE: tiny7 was slower than tiny12 # TODO: why are convs so slow?!? def test_conv_3x3_256_32_32_256_256(self): self._test_conv_3x3(256, 32, 32, 256, 256, nv_tflops=27, amd_tflops=14) # theoretical is nv_tflops=165, amd_tflops=123 - def test_gemm_4096(self): self._test_matmul(4096, nv_tflops=115, amd_tflops=65) - def test_gemm_8192(self): self._test_matmul(8192, nv_tflops=125, amd_tflops=60) + def test_gemm_4096(self): self._test_matmul(4096, nv_tflops=110, amd_tflops=65) + def test_gemm_8192(self): self._test_matmul(8192, nv_tflops=115, amd_tflops=60) # theoretical is nv_gbs=1008, amd_gbs=960 def test_gemv_16384_4096(self): self._test_matmul(16384, 4096, 1, nv_gbs=840, amd_gbs=750) - def test_gemv_4096_16384(self): self._test_matmul(4096, 16384, 1, nv_gbs=830, amd_gbs=750) + def test_gemv_4096_16384(self): self._test_matmul(4096, 16384, 1, nv_gbs=820, amd_gbs=750) if __name__ == '__main__': unittest.main() diff --git a/test/mockgpu/amd/amddriver.py b/test/mockgpu/amd/amddriver.py index 9933fbba24..317f57a75f 100644 --- a/test/mockgpu/amd/amddriver.py +++ b/test/mockgpu/amd/amddriver.py @@ -17,7 +17,7 @@ def ioctls_from_header(): pattern = r'#define\s+(AMDKFD_IOC_[A-Z0-9_]+)\s+AMDKFD_(IOW?R?)\((0x[0-9a-fA-F]+),\s+struct\s([A-Za-z0-9_]+)\)' matches = re.findall(pattern, hdr, re.MULTILINE) return type("KFD_IOCTLS", (object, ), {name: int(nr, 0x10) for name, _, nr, _ in matches}), \ - {int(nr, 0x10): getattr(kfd, "struct_"+sname) for name, idir, nr, sname in matches} + {int(nr, 0x10): getattr(kfd, "struct_"+sname, None) for name, idir, nr, sname in matches} kfd_ioctls, kfd_headers = ioctls_from_header() class KFDFileDesc(VirtFileDesc): @@ -85,6 +85,8 @@ class AMDDriver(VirtDriver): VirtFile(f'/sys/devices/virtual/kfd/kfd/topology/nodes/{gpu_id}/gpu_id', functools.partial(TextFileDesc, text=f"{gpu_id}")), VirtFile(f'/sys/devices/virtual/kfd/kfd/topology/nodes/{gpu_id}/properties', functools.partial(TextFileDesc, text=gpu_props.format(drm_render_minor=gpu_id))), + VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/power_dpm_force_performance_level', + functools.partial(TextFileDesc, text='profile_standard\n')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0', functools.partial(DirFileDesc, child_names=[str(am.GC_HWID), str(am.SDMA0_HWID), str(am.NBIF_HWID)])), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}', functools.partial(DirFileDesc, child_names=['0'])), @@ -115,6 +117,10 @@ class AMDDriver(VirtDriver): struct = kfd_headers[nr].from_address(argp) if nr == kfd_ioctls.AMDKFD_IOC_ACQUIRE_VM: pass + elif nr == kfd_ioctls.AMDKFD_IOC_RUNTIME_ENABLE: pass + elif nr == kfd_ioctls.AMDKFD_IOC_GET_VERSION: + struct.major_version = 1 + struct.minor_version = 14 elif nr == kfd_ioctls.AMDKFD_IOC_ALLOC_MEMORY_OF_GPU: if struct.gpu_id not in self.gpus: return -1 struct.handle = self._alloc_handle() diff --git a/test/mockgpu/amd/amdgpu.py b/test/mockgpu/amd/amdgpu.py index 152ee2e913..b30a9db4b3 100644 --- a/test/mockgpu/amd/amdgpu.py +++ b/test/mockgpu/amd/amdgpu.py @@ -14,6 +14,9 @@ regSQ_THREAD_TRACE_BUF0_BASE = 0x39e8 + amd_gpu.GC_BASE__INST0_SEG1 regSQ_THREAD_TRACE_BUF0_SIZE = 0x39e9 + amd_gpu.GC_BASE__INST0_SEG1 regSQ_THREAD_TRACE_WPTR = 0x39ef + amd_gpu.GC_BASE__INST0_SEG1 regSQ_THREAD_TRACE_STATUS = 0x39f4 + amd_gpu.GC_BASE__INST0_SEG1 +regCP_PERFMON_CNTL = 0x3808 + amd_gpu.GC_BASE__INST0_SEG1 +regCPG_PERFCOUNTER1_LO = 0x3000 + amd_gpu.GC_BASE__INST0_SEG1 +regGUS_PERFCOUNTER_HI = 0x3643 + amd_gpu.GC_BASE__INST0_SEG1 class SQTT_EVENTS: THREAD_TRACE_FINISH = 0x00000037 @@ -130,7 +133,7 @@ class PM4Executor(AMDQueue): _src_addr_hi = self._next_dword() dst_addr_lo = self._next_dword() dst_addr_hi = self._next_dword() - assert copy_data_flags == 0x100204, hex(copy_data_flags) # better fail than silently do the wrong thing + assert copy_data_flags in {0x100204, 0x000204}, hex(copy_data_flags) # better fail than silently do the wrong thing to_mv(dst_addr_hi<<32|dst_addr_lo, 4).cast('I')[0] = self.gpu.regs[src_addr_lo] def _exec_wait_reg_mem(self, n): @@ -280,6 +283,9 @@ class AMDGPURegisters: self.regs: dict[tuple[int, int], int] = {} def __getitem__(self, addr:int) -> int: if addr == regGRBM_GFX_INDEX: return self.grbm_index + if regCPG_PERFCOUNTER1_LO < addr < regGUS_PERFCOUNTER_HI: + assert self.regs[(regCP_PERFMON_CNTL, 0)] == 0x401, "read mode should be enabled" + return addr << 16 | self.grbm_index return self.regs[(addr, getbits(self.grbm_index, 16, 23))] def __setitem__(self, addr:int, val:int): if addr == regGRBM_GFX_INDEX: self.grbm_index = val diff --git a/test/mockgpu/nv/nvgpu.py b/test/mockgpu/nv/nvgpu.py index deff54bd1e..6be5f00447 100644 --- a/test/mockgpu/nv/nvgpu.py +++ b/test/mockgpu/nv/nvgpu.py @@ -1,4 +1,4 @@ -import ctypes, ctypes.util, time +import ctypes, time import tinygrad.runtime.autogen.nv_gpu as nv_gpu from enum import Enum, auto from test.mockgpu.gpu import VirtGPU diff --git a/test/models/test_efficientnet.py b/test/models/test_efficientnet.py index 8e434ba8aa..3a5b3324ba 100644 --- a/test/models/test_efficientnet.py +++ b/test/models/test_efficientnet.py @@ -101,7 +101,8 @@ class TestResNet(unittest.TestCase): def test_chicken(self): labels = _infer(self.model, chicken_img) - self.assertEqual(_LABELS[labels[0]], "hen") + # NOTE: logits for these two are close + self.assertIn(_LABELS[labels[0]], ("hen", "cock")) def test_car(self): labels = _infer(self.model, car_img) diff --git a/test/models/test_onnx.py b/test/models/test_onnx.py index 34e5a1320d..34ed658e43 100644 --- a/test/models/test_onnx.py +++ b/test/models/test_onnx.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import unittest import numpy as np -from tinygrad.frontend.onnx import OnnxRunner +from tinygrad.nn.onnx import OnnxRunner from tinygrad.device import Device from tinygrad.helpers import fetch, Context diff --git a/test/models/test_real_world.py b/test/models/test_real_world.py index ccfccf45e9..0d8389b76c 100644 --- a/test/models/test_real_world.py +++ b/test/models/test_real_world.py @@ -94,7 +94,7 @@ class TestRealWorld(unittest.TestCase): @TinyJit def test(t, v): with Context(JIT=0): return model(t, v).realize() - helper_test("test_gpt2", lambda: (Tensor([[1,]]),Variable("pos", 1, 100).bind(1)), test, 0.23 if CI else 0.9, 160 if CI else 396, all_jitted=True) + helper_test("test_gpt2", lambda: (Tensor([[1,]]),Variable("pos", 1, 100).bind(1)), test, 0.23 if CI else 0.9, 160 if CI else 468, all_jitted=True) @unittest.skipIf(CI and Device.DEFAULT == "CPU", "slow") def test_train_mnist(self): @@ -112,7 +112,7 @@ class TestRealWorld(unittest.TestCase): loss.backward() optimizer.step() - helper_test("train_mnist", lambda: (Tensor.randn(BS, 1, 28, 28),), train, 0.07, 102) + helper_test("train_mnist", lambda: (Tensor.randn(BS, 1, 28, 28),), train, 0.07, 103) @unittest.skipIf(CI and Device.DEFAULT in {"CPU", "CL"}, "slow") def test_forward_cifar(self): @@ -176,7 +176,7 @@ class TestRealWorld(unittest.TestCase): for v in data.values(): v.to_(Device.DEFAULT) helper_test("train_bert", lambda: (data["input_ids"], data["segment_ids"], data["input_mask"], data["masked_lm_positions"], \ - data["masked_lm_ids"], data["masked_lm_weights"], data["next_sentence_labels"]), train, 0.28, 357) + data["masked_lm_ids"], data["masked_lm_weights"], data["next_sentence_labels"]), train, 0.31, 427) if __name__ == '__main__': unittest.main() diff --git a/test/opt/test_gen_float4.py b/test/opt/test_gen_float4.py index 1b72514bfd..357dccae6d 100644 --- a/test/opt/test_gen_float4.py +++ b/test/opt/test_gen_float4.py @@ -2,7 +2,6 @@ import unittest from tinygrad import Device, Tensor, dtypes from tinygrad.uop.ops import UOp, Ops from tinygrad.codegen.opt import Opt, OptOps -from tinygrad.shape.shapetracker import ShapeTracker, View from tinygrad.engine.realize import get_program from tinygrad.helpers import AMX @@ -149,32 +148,5 @@ class TestFloat4(unittest.TestCase): assert TestFloat4.count_float4(uops) == (1, 1) - def test_half4_load_unrolled(self): - # from llama 7B shard 4 gpus - ast = UOp(Ops.SINK, dtypes.void, arg=None, src=( - UOp(Ops.STORE, dtypes.void, arg=None, src=( - UOp(Ops.VIEW, dtypes.float.ptr(96000), arg=ShapeTracker(views=(View(shape=(1, 3, 32000, 1), strides=(0, 32000, 1, 0), offset=0, mask=None, contiguous=True),)), src=( # noqa: E501 - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(96000), arg=0, src=()),)), - UOp(Ops.REDUCE_AXIS, dtypes.float, arg=(Ops.ADD, (3,)), src=( - UOp(Ops.CAST, dtypes.float, arg=None, src=( - UOp(Ops.MUL, dtypes.half, arg=None, src=( - UOp(Ops.LOAD, dtypes.half, arg=None, src=( - UOp(Ops.VIEW, dtypes.half.ptr(9216), arg=ShapeTracker(views=(View(shape=(1, 3, 32000, 1024), strides=(0, 4096, 0, 1), offset=0, mask=None, contiguous=False),)), src=( # noqa: E501 - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(9216), arg=1, src=()),)),)), - UOp(Ops.LOAD, dtypes.half, arg=None, src=( - UOp(Ops.VIEW, dtypes.half.ptr(32768000), arg=ShapeTracker(views=(View(shape=(1, 3, 32000, 1024), strides=(0, 0, 1024, 1), offset=0, mask=None, contiguous=False),)), src=( # noqa: E501 - UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(32768000), arg=2, src=()),)),)),)),)),)),)),)) - - # TODO: fix this, expected might change but should be positive - for expected, opts in [ - ((7, 0), [Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.UPCAST, axis=0, arg=3), Opt(op=OptOps.UNROLL, axis=0, arg=4)]), - ((5, 0), [Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.UNROLL, axis=0, arg=4)]), - ((2, 0), [Opt(op=OptOps.UNROLL, axis=0, arg=4)]), - ]: - program = get_program(ast, Device[Device.DEFAULT].renderer, opts=opts) - - count = TestFloat4.count_half4(program.uops) - assert count == expected, f"{count=}, {expected=}" - if __name__ == '__main__': unittest.main() diff --git a/test/opt/test_kernel_opts.py b/test/opt/test_kernel_opts.py index fda46a36c1..4ff0eab038 100644 --- a/test/opt/test_kernel_opts.py +++ b/test/opt/test_kernel_opts.py @@ -1,6 +1,5 @@ import unittest from tinygrad import Device, Tensor, dtypes -from tinygrad.helpers import CI, RANGEIFY from tinygrad.codegen.opt import Opt, OptOps, KernelOptError # TODO: write a clean version of this @@ -177,9 +176,7 @@ class TestKernelOpts(unittest.TestCase): ], apply_tc=True, atol=atol, rtol=rtol) def test_padto_matmul(self): - if (CI and Device.DEFAULT in ["AMD", "NV", "CUDA"]): - self.skipTest("super slow on CUDA and AMD because of the big grid dims") - N = 17 * 17 + N = 17 Tensor.manual_seed(289) a = Tensor.rand(N, N) b = Tensor.rand(N, N) @@ -213,7 +210,7 @@ class TestKernelOpts(unittest.TestCase): helper_linearizer_opt(a@b, [[Opt(OptOps.UNROLL, 0, 0), Opt(OptOps.PADTO, 2, 8)]]) def test_padto_sum_ok(self): - N = 18 * 18 + N = 18 # NOTE: this setup prevents 17 * 17 contiguous merged into one dimension a = Tensor.rand(N, N).realize().shrink(((0, 17), (0, 17))) * 100 b = (Tensor.rand(N, N) < 0.5).realize().shrink(((0, 17), (0, 17))) @@ -244,7 +241,7 @@ class TestKernelOpts(unittest.TestCase): helper_linearizer_opt(a.sum(0).exp(), [[Opt(OptOps.PADTO, 1, 32)],]) def test_padto_sum_not_ok(self): - N = 18 * 18 + N = 18 # NOTE: this setup prevents 17 * 17 contiguous merged into one dimension a = Tensor.rand(N, N).shrink(((0, 17), (0, 17))).exp() # exp is not safe to pad @@ -261,7 +258,7 @@ class TestKernelOpts(unittest.TestCase): helper_linearizer_opt(b.sum(0), [[Opt(OptOps.PADTO, 1, 32)],]) def test_padto_max(self): - N = 18 * 18 + N = 18 # NOTE: this setup prevents 17 * 17 contiguous merged into one axis a = -Tensor.rand(N, N).shrink(((0, 17), (0, 17))) * 100 @@ -282,7 +279,7 @@ class TestKernelOpts(unittest.TestCase): def test_padto_where(self): Tensor.manual_seed(0) - N = 17 * 17 + N = 17 a = (Tensor.randn(N, N).realize().max(axis=0, keepdim=True) > 1).where(1, 0) helper_linearizer_opt(a.max(0), [ [Opt(OptOps.PADTO, 0, 32)], @@ -291,7 +288,7 @@ class TestKernelOpts(unittest.TestCase): def test_padto_where_multioutput(self): Tensor.manual_seed(0) - N = 17 * 17 + N = 17 r = Tensor.randn(N, N).realize().max(axis=0, keepdim=True) > 1 a0 = r.where(1, 0) a1 = r.where(2, 0) @@ -351,7 +348,6 @@ class TestKernelOpts(unittest.TestCase): ] + [[Opt(OptOps.THREAD, 0, 4)] if Device[Device.DEFAULT].renderer.global_max[0] >= 4 else []] + [[Opt(OptOps.THREAD, 0, 8)] if Device[Device.DEFAULT].renderer.global_max[0] >= 8 else []]) - @unittest.skipUnless(RANGEIFY>=1, "Kernel only fuses with rangeify") def test_double_sum_group(self): a = Tensor.rand(4, 4, 4) r = a.sum((1, 2)).sum() diff --git a/test/opt/test_tensor_cores.py b/test/opt/test_tensor_cores.py index 0639bf587a..d293de1283 100644 --- a/test/opt/test_tensor_cores.py +++ b/test/opt/test_tensor_cores.py @@ -14,6 +14,8 @@ from tinygrad.codegen.opt import Opt, OptOps, KernelOptError # TODO: write a clean version of this from test.test_linearizer import helper_realized_ast, helper_linearizer_opt +# NOTE: get_program always passes in Device[Device.DEFAULT].renderer explicitly for process_replay!!! + def helper_tc_ensure_uops_and_opts_count(N: int, M:int, K:int, dtype_in:DType, dtype_out:DType, axis:int=0, tc_select:int=-1, tc_opt:int=0, ensure_triggered:bool=True): a, b = Tensor.rand(M, K, dtype=dtype_in), Tensor.rand(K, N, dtype=dtype_in) @@ -41,7 +43,7 @@ def helper_tc_allclose(N:int, M:int, K:int, dtype_in:DType, dtype_out:DType, axi if dtype_in == dtypes.bfloat16: r = r.float() realized_ast, bufs = helper_realized_ast(r) opts = [Opt(op=OptOps.TC, axis=axis, arg=(tc_select, tc_opt, use_tensor_cores))] - prg = CompiledRunner(replace(get_program(realized_ast, opts=opts), device=Device.DEFAULT)) + prg = CompiledRunner(replace(get_program(realized_ast, Device[Device.DEFAULT].renderer, opts=opts), device=Device.DEFAULT)) if use_tensor_cores == 1: assert len([uop for uop in prg.p.uops if uop.op is Ops.WMMA]) > 0, "wmma not triggered" assert len([x for x in prg.p.uops[-1].arg.applied_opts if x.op is OptOps.TC]) == 1, "tensor core opt not included" prg.exec(bufs) @@ -68,7 +70,7 @@ class TestTensorCores(unittest.TestCase): n, m, k = tc.dims[0], tc.dims[1], 2 if AMX else tc.dims[2] a, b = Tensor.rand(m, k, dtype=tc.dtype_in), Tensor.rand(k, n, dtype=tc.dtype_in) r = a.matmul(b, dtype=tc.dtype_out) - prg = get_program(r.schedule()[-1].ast, opts=[Opt(op=OptOps.TC, axis=0, arg=(-1, 2, 1))]) + prg = get_program(r.schedule()[-1].ast, Device[Device.DEFAULT].renderer, opts=[Opt(op=OptOps.TC, axis=0, arg=(-1, 2, 1))]) if Device.DEFAULT == "CPU" and CPU_LLVM: assert "0x201000" in prg.src elif Device.DEFAULT == "AMD" and AMD_LLVM: @@ -154,7 +156,7 @@ class TestTensorCores(unittest.TestCase): r = x.matmul(y, dtype=tc.dtype_out) opts = [Opt(OptOps.UNROLL, 0, 4)] ast = helper_linearizer_opt(r, [opts], apply_tc=True, atol=3e-2, rtol=1e-3) - for u in get_program(ast, opts=opts).uops: + for u in get_program(ast, Device[Device.DEFAULT].renderer, opts=opts).uops: if u.op is Ops.WMMA: assert u.src[-1].src[0].op != Ops.STORE @@ -167,7 +169,7 @@ class TestTensorCores(unittest.TestCase): r = x.matmul(y, dtype=tc.dtype_out) opts = [Opt(OptOps.UNROLL, 0, 4)] ast = helper_linearizer_opt(r, [opts], apply_tc=True, atol=3e-2, rtol=1e-3) - for u in get_program(ast, opts=opts).uops: + for u in get_program(ast, Device[Device.DEFAULT].renderer, opts=opts).uops: if u.op is Ops.WMMA: #assert u.src[-1].dtype == dtypes.float.vec(prod(tc.thread_local_sizes[2])) assert u.src[-1].src[0].op != Ops.STORE @@ -182,7 +184,7 @@ class TestTensorCores(unittest.TestCase): r = x.matmul(y, dtype=tc.dtype_out).relu() opts = [Opt(OptOps.UNROLL, 0, 4)] ast = helper_linearizer_opt(r, [opts], apply_tc=True, atol=3e-2, rtol=1e-3) - for u in get_program(ast, opts=opts).uops: + for u in get_program(ast, Device[Device.DEFAULT].renderer, opts=opts).uops: if u.op is Ops.WMMA: #assert u.src[-1].dtype == dtypes.float.vec(prod(tc.thread_local_sizes[2])) assert u.src[-1].src[0].op != Ops.STORE diff --git a/test/test_arange.py b/test/test_arange.py index a46b38a087..4fea9f90f1 100644 --- a/test/test_arange.py +++ b/test/test_arange.py @@ -1,7 +1,7 @@ import unittest import numpy as np from tinygrad import Tensor, GlobalCounters, dtypes, nn, Device, Variable -from tinygrad.helpers import CI, Context, getenv, RANGEIFY +from tinygrad.helpers import CI, Context, getenv from tinygrad.engine.realize import run_schedule from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program from tinygrad.uop.ops import Ops @@ -25,22 +25,6 @@ class TestArange(unittest.TestCase): t = Tensor.arange(2, dtype=dtypes.int)+Tensor([3]) self.assertEqual(t.cat(t).tolist(), [3, 4, 3, 4]) -class TestRand(unittest.TestCase): - def test_fused_rand_less_ops(self, noopt=1): - GlobalCounters.reset() - with Context(FUSE_ARANGE=0, NOOPT=noopt): - out = Tensor.rand(16384) - out.realize() - unfused_ops = GlobalCounters.global_ops - - GlobalCounters.reset() - with Context(FUSE_ARANGE=1, NOOPT=noopt): - out = Tensor.rand(16384) - out.realize() - print(f"fused {GlobalCounters.global_ops} unfused {unfused_ops}") - self.assertLessEqual(GlobalCounters.global_ops, unfused_ops*2) - def test_fused_rand_less_ops_opt(self): self.test_fused_rand_less_ops(0) - DSET, DDIM = 2048, 32 class TestIndexing(unittest.TestCase): @@ -48,7 +32,7 @@ class TestIndexing(unittest.TestCase): needle = Tensor.zeros(16384, dtype=dtypes.int).contiguous() needle[1337] = 1 needle.realize() - with Context(NOOPT=1, FUSE_ARANGE=1): + with Context(NOOPT=1): GlobalCounters.reset() out = ((Tensor.arange(1,16385)-1)*needle).sum() sched = out.schedule() @@ -61,7 +45,7 @@ class TestIndexing(unittest.TestCase): idxs = Tensor([0,3,5,6]).realize() real_index = dataset.numpy()[idxs.numpy()] print("*** indexing ***") - with Context(NOOPT=1, FUSE_ARANGE=1): + with Context(NOOPT=1): GlobalCounters.reset() rng = Tensor.ones(4, DDIM, DSET, dtype=dtypes.int)._cumalu(axis=-1, op=Ops.ADD, _include_initial=True).reshape(4, DDIM, DSET, 1) idxs = idxs.reshape(4,1,1,1).expand(4, DDIM, DSET, 1) @@ -77,7 +61,7 @@ class TestIndexing(unittest.TestCase): def test_index_variable(self): dataset = Tensor.rand(DSET, DDIM).realize() v = Variable("v", 0, DDIM-1) - with Context(NOOPT=1, FUSE_ARANGE=1, SPLIT_REDUCEOP=0): + with Context(NOOPT=1): GlobalCounters.reset() vb = Tensor(v.bind(12)) comp = dataset[vb].numpy() @@ -106,12 +90,12 @@ class TestIndexing(unittest.TestCase): idxs = Tensor([0,3,5,6]).realize() real_index = dataset.numpy()[idxs.numpy()] print("*** indexing ***") - with Context(NOOPT=noopt, FUSE_ARANGE=1): + with Context(NOOPT=noopt): GlobalCounters.reset() X = dataset[idxs] assert X.shape == (4,DDIM) sched = X.schedule() - self.assertEqual(len(sched), 1 if RANGEIFY else 2) + self.assertEqual(len(sched), 1) run_schedule(sched) assert GlobalCounters.global_ops < 4*DSET, f"too many ops {GlobalCounters.global_ops} != {4*DSET}" np.testing.assert_allclose(real_index, X.numpy()) @@ -121,7 +105,7 @@ class TestIndexing(unittest.TestCase): def test_index_fused_out_of_bounds(self): dataset = Tensor.rand(256, 256).realize() idxs = Tensor([-19238, -257, 256, 495, 10982377]).realize() - with Context(NOOPT=1, FUSE_ARANGE=1): + with Context(NOOPT=1): X = dataset[idxs] np.testing.assert_equal(X.numpy(), 0) @@ -130,7 +114,7 @@ class TestIndexing(unittest.TestCase): if Device.DEFAULT == "WEBGPU": op_limit *= 15 from tinygrad.nn.datasets import mnist X_train, Y_train, _, _ = mnist() - with Context(NOOPT=noopt, FUSE_ARANGE=1, SPLIT_REDUCEOP=split_reduceop): + with Context(NOOPT=noopt, SPLIT_REDUCEOP=split_reduceop): samples = Tensor.randint(getenv("BS", 512), high=X_train.shape[0]).realize() GlobalCounters.reset() x = X_train[samples].numpy() @@ -147,10 +131,9 @@ class TestIndexing(unittest.TestCase): # llama3 is 128256 vocab_size, embed_size = (10, 3) if CI else (32000, 4096) emb = nn.Embedding(vocab_size, embed_size) - # TODO: why is a new realize needed here - emb_w = emb.weight.realize().numpy() + emb_w = emb.weight.numpy() x = Tensor([1,2,3,4]) - with Context(NOOPT=noopt, FUSE_ARANGE=1): + with Context(NOOPT=noopt): GlobalCounters.reset() z = emb(x).realize() self.assertLessEqual(GlobalCounters.global_ops, op_limit) diff --git a/test/test_assign.py b/test/test_assign.py index f8ffe3fee7..19aafad603 100644 --- a/test/test_assign.py +++ b/test/test_assign.py @@ -1,10 +1,9 @@ #!/usr/bin/env python import unittest -import contextlib import numpy as np from tinygrad import dtypes, Tensor, TinyJit, GlobalCounters, Variable from tinygrad.device import is_dtype_supported -from tinygrad.helpers import temp, RANGEIFY +from tinygrad.helpers import temp N = 200 # has to be bigger than the cache to fail @@ -130,6 +129,12 @@ class TestAssign(unittest.TestCase): @unittest.expectedFailure def test_assign_changes_realized_alt(self): return self.test_assign_changes_alt(realize=True) + @unittest.skip("assign to contiguous shouldn't change the base buffer") + def test_assign_changes_buffer_alt(self): + a, b = [Tensor(Tensor(0).contiguous().realize().uop.as_buf()) for _ in range(2)] + Tensor.realize(a.contiguous().assign(1), b.contiguous().assign(2)) + self.assertEqual((a + b).item(), 3) + def test_assign_diamond_cycle(self): # NOTE: should *not* raise AssertionError from numpy with self.assertRaisesRegex(RuntimeError, "cycle"): @@ -266,8 +271,6 @@ class TestAssign(unittest.TestCase): b.assign(a.contiguous()).realize() assert GlobalCounters.kernel_count - kc == 2 - # passing in RANGEIFY=1, RANGEIFY=0 asserts permuted assigns it can't fuse - def assert_permuted_assign(self): return self.assertRaisesRegex(RuntimeError, "contiguous") if not RANGEIFY else contextlib.nullcontext() def test_permuted_assignment(self): a = Tensor(np.arange(N*N, dtype=np.float32)).reshape(N,N) b = Tensor(np.arange(N*N, dtype=np.float32)).reshape(N,N) @@ -275,13 +278,13 @@ class TestAssign(unittest.TestCase): b.realize() ba1 = a.uop.base.realized bb1 = b.uop.base.realized - with self.assertRaises((RuntimeError, AssertionError)): - a = a.permute(1,0) - a += b - a.realize() - ba2 = a.uop.base.realized - assert ba1 != ba2 and ba1 != bb1 - np.testing.assert_allclose(a.numpy(), np.arange(N*N).reshape((N,N)) + np.arange(N*N).reshape((N,N)).transpose(1,0)) + a = a.permute(1,0) + a += b + a.realize() + ba2 = a.uop.base.realized + np.testing.assert_allclose(a.numpy(), np.arange(N*N).reshape((N,N)) + np.arange(N*N).reshape((N,N)).transpose(1,0)) + # permute and base are the same buffer + assert ba1 == ba2 and ba1 != bb1 def test_post_permuted_assignment(self): a = Tensor(np.arange(N*N, dtype=np.float32)).reshape(N,N) @@ -291,15 +294,13 @@ class TestAssign(unittest.TestCase): #GlobalCounters.cache = [] ba1 = a.uop.base.realized # noqa: F841 bb1 = b.uop.base.realized # noqa: F841 - with self.assert_permuted_assign(): - a.assign(a.permute(1,0) + b) # this should not work! - a.realize() - ba2 = a.uop.base.realized # noqa: F841 - # NOTE: don't test that it's assigned - #assert ba1 == ba2 and ba1 != bb1 - np.testing.assert_allclose(a.numpy(), np.arange(N*N).reshape((N,N)) + np.arange(N*N).reshape((N,N)).transpose(1,0)) + a.assign(a.permute(1,0) + b) # this should not work! + a.realize() + ba2 = a.uop.base.realized # noqa: F841 + # NOTE: don't test that it's assigned + #assert ba1 == ba2 and ba1 != bb1 + np.testing.assert_allclose(a.numpy(), np.arange(N*N).reshape((N,N)) + np.arange(N*N).reshape((N,N)).transpose(1,0)) - @unittest.skipUnless(RANGEIFY, "only correct in rangeify") def test_post_permuted_assignment_alt(self): a = Tensor.arange(N*N).reshape(N,N).contiguous().realize() b = Tensor.arange(N*N).reshape(N,N).contiguous().realize() @@ -339,21 +340,18 @@ class TestAssign(unittest.TestCase): def test_permuted_assignment_correct(self): a = Tensor.arange(4 * 4).reshape(4, 4).contiguous().realize() b = Tensor.arange(4 * 4).reshape(4, 4).contiguous().realize() - # TODO: swizzler.py limitation, should NOT raise AssertionError from numpy. - with self.assert_permuted_assign(): - a = a.permute(1, 0) - new_val = a + b - a.assign(new_val) - np.testing.assert_equal(a.numpy(), np.arange(4 * 4).reshape(4, 4).transpose(1, 0) + np.arange(4 * 4).reshape(4, 4)) + a = a.permute(1, 0) + new_val = a + b + a.assign(new_val) + np.testing.assert_equal(a.numpy(), np.arange(4 * 4).reshape(4, 4).transpose(1, 0) + np.arange(4 * 4).reshape(4, 4)) def test_permuted_reduceop_child_dual_use(self): a = Tensor.randn(32, 32, 32).realize() b = Tensor.full((32, 32), 1.).contiguous().realize() - with self.assert_permuted_assign(): - r = a.sum(axis=1) - b.assign(r + b.permute(1, 0)) - b.realize() - np.testing.assert_allclose(b.numpy(), a.numpy().sum(axis=1)+np.ones((32, 32)).transpose(1, 0), atol=1e-6, rtol=1e-3) + r = a.sum(axis=1) + b.assign(r + b.permute(1, 0)) + b.realize() + np.testing.assert_allclose(b.numpy(), a.numpy().sum(axis=1)+np.ones((32, 32)).transpose(1, 0), atol=1e-6, rtol=1e-3) @unittest.skip("multi output not supported anymore") def test_permuted_reduceop_multioutput_dual_use(self): @@ -395,11 +393,10 @@ class TestAssign(unittest.TestCase): def test_permuted_assignment_masked_view_not_contiguous(self): a = Tensor.ones(4, 4).contiguous().realize() - with self.assert_permuted_assign(): - b = a.shrink((None, (0, 2))).pad((None, (0, 2)), value=2).permute(1, 0) - a.assign(a + b) - a.realize() - self.assertListEqual(a.tolist(), [[2.,2.,2.,2.],[2.,2.,2.,2.],[3.,3.,3.,3.], [3.,3.,3.,3.]]) + b = a.shrink((None, (0, 2))).pad((None, (0, 2)), value=2).permute(1, 0) + a.assign(a + b) + a.realize() + self.assertListEqual(a.tolist(), [[2.,2.,2.,2.],[2.,2.,2.,2.],[3.,3.,3.,3.], [3.,3.,3.,3.]]) # TODO: is there a way to sneak in a permute such that it returns the wrong answer? diff --git a/test/test_compile_failures.py b/test/test_compile_failures.py index cc25b90d36..7d9b0e33d5 100644 --- a/test/test_compile_failures.py +++ b/test/test_compile_failures.py @@ -1,7 +1,7 @@ import unittest, io from contextlib import redirect_stdout from tinygrad import Tensor, dtypes, Device -from tinygrad.helpers import OSX, CPU_LLVM +from tinygrad.helpers import OSX, CPU_LLVM, CPU_LVP from tinygrad.engine.realize import lower_schedule from tinygrad.device import is_dtype_supported from tinygrad.engine.realize import get_program @@ -19,7 +19,7 @@ class TestCompileFailures(unittest.TestCase): class TestDisassembly(unittest.TestCase): # TODO: fails on llvm. llvm.LLVMGetHostCPUName() returns "generic" - @unittest.skipUnless(Device.DEFAULT in ("CPU",) and not CPU_LLVM and OSX, "m series cpus support fp16 arithmetic") + @unittest.skipUnless(Device.DEFAULT in ("CPU",) and not (CPU_LLVM or CPU_LVP) and OSX, "m series cpus support fp16 arithmetic") def test_float16_alu(self): c = Tensor([1], dtype=dtypes.float16) + Tensor([1], dtype=dtypes.float16) s = c.schedule()[-1] diff --git a/test/test_const_folding.py b/test/test_const_folding.py index 7dd245088a..3a709b1908 100644 --- a/test/test_const_folding.py +++ b/test/test_const_folding.py @@ -1,9 +1,8 @@ import unittest, itertools, math -from tinygrad import Tensor, Device, dtypes +from tinygrad import Tensor, Device, dtypes, Context from tinygrad.dtype import DType, ConstType from tinygrad.uop.ops import Ops, UOp from tinygrad.codegen import full_rewrite_to_sink -from tinygrad.helpers import RANGEIFY from tinygrad.device import is_dtype_supported import numpy as np from test.helpers import not_support_multi_device @@ -25,7 +24,6 @@ class TestUnaryOpsConstFolding(unittest.TestCase): _check_ast_count(0, Tensor.ones(4).cast(dtypes.int16)) _check_ast_count(0, Tensor.full(4, fill_value=-1).cast(dtypes.uint16)) - @unittest.expectedFailure # no two level fold def test_neg_folding(self): _check_ast_count(0, Tensor([1, 2, 3]).mul(-1).neg()) _check_ast_count(0, Tensor([1, 2, 3]).neg().mul(-1)) @@ -81,10 +79,8 @@ class TestBinaryOpsConstFolding(unittest.TestCase): def test_div_tensor_one(self): _check_ast_count(0, Tensor([1.0, 2, 3, 4]) / Tensor.ones(4)) - @unittest.expectedFailure # TODO: fix def test_idiv_literal_one(self): _check_ast_count(0, Tensor([1, 2, 3, 4]) // 1) - @unittest.expectedFailure # TODO: fix def test_idiv_tensor_one(self): _check_ast_count(0, Tensor([1, 2, 3, 4]) // Tensor.ones(4, dtype=dtypes.int32)) @@ -130,7 +126,8 @@ class TestBitcastConstFolding(unittest.TestCase): t({dtypes.int64: 4598983288165178391, dtypes.uint64: 4598983288165178391, dtypes.float64: 0.29485681936461233}) def test_vec_bitcast(self): - r = full_rewrite_to_sink(UOp.const(dtypes.int32.vec(3), (-1, -2**31, 75)).bitcast(dtypes.uint32.vec(3)).sink()).src[0] + with Context(SPEC=0): + r = full_rewrite_to_sink(UOp.const(dtypes.int32.vec(3), (-1, -2**31, 75)).bitcast(dtypes.uint32.vec(3)).sink()).src[0] self.assertEqual(r.op, Ops.VECTORIZE) self.assertEqual(r.dtype, dtypes.uint32.vec(3)) self.assertEqual(tuple(x.arg for x in r.src), (2**32-1, 2**31, 75)) @@ -155,8 +152,7 @@ class TestMovedConstFolding(unittest.TestCase): _check_ast_count(0, Tensor([1.0, 2, 3, 4]) + Tensor.zeros(6).shrink(((1, 5),))) def test_add_padded_zero(self): - # TODO: it's 1 now, this might be possible to fold - _check_ast_count(0 if RANGEIFY else 1, Tensor([1.0, 2, 3, 4]) + Tensor.zeros(2).pad(((1, 1),))) + _check_ast_count(0, Tensor([1.0, 2, 3, 4]) + Tensor.zeros(2).pad(((1, 1),))) def test_mul_shrunk_one(self): _check_ast_count(0, Tensor([1.0, 2, 3, 4]) * Tensor.ones(6).shrink(((1, 5),))) @@ -165,16 +161,16 @@ class TestMovedConstFolding(unittest.TestCase): _check_ast_count(1, Tensor([1.0, 2, 3, 4]) * Tensor.ones(2).pad(((1, 1),))) def test_cast_padded(self): - # NOTE: RANGEIFY or not, it's always 1 kernel when calling .numpy, limitation of _check_ast_count + # NOTE: it's always 1 kernel when calling .numpy, limitation of _check_ast_count if is_dtype_supported(dtypes.int16): - _check_ast_count(1 if RANGEIFY else 0, Tensor.ones(4).pad(((1, 1),)).cast(dtypes.int16)) + _check_ast_count(1, Tensor.ones(4).pad(((1, 1),)).cast(dtypes.int16)) np.testing.assert_equal(Tensor.ones(4).pad(((1, 1),)).cast(dtypes.int16).numpy(), [0, 1, 1, 1, 1, 0]) if is_dtype_supported(dtypes.uint16): - _check_ast_count(1 if RANGEIFY else 0, Tensor.full(4, fill_value=-1).pad(((1, 1),)).cast(dtypes.uint16)) + _check_ast_count(1, Tensor.full(4, fill_value=-1).pad(((1, 1),)).cast(dtypes.uint16)) np.testing.assert_equal(Tensor.full(4, fill_value=-1).pad(((1, 1),)).cast(dtypes.uint16).numpy(), [0, 65535, 65535, 65535, 65535, 0]) # folded if is_dtype_supported(dtypes.int64): - _check_ast_count(1 if RANGEIFY else 0, Tensor.ones(4).pad(((1, 1),)).cast(dtypes.int64)) + _check_ast_count(1, Tensor.ones(4).pad(((1, 1),)).cast(dtypes.int64)) np.testing.assert_equal(Tensor.ones(4).pad(((1, 1),)).cast(dtypes.int64).numpy(), [0, 1, 1, 1, 1, 0]) class TestReduceOpsConstFolding(unittest.TestCase): @@ -187,7 +183,7 @@ class TestReduceOpsConstFolding(unittest.TestCase): np.testing.assert_equal(Tensor(4).sum().numpy(), 4) def test_padded_const_sum(self): - _check_ast_count(1, Tensor.ones(4).pad(((1, 1),)).sum()) + _check_ast_count(0, Tensor.ones(4).pad(((1, 1),)).sum()) np.testing.assert_equal(Tensor.ones(4).pad(((1, 1),)).sum().numpy(), 4) # NOTE: cannot just count the non-padded area because some Ops f do not have f(0) = 0. @@ -246,7 +242,7 @@ class TestReduceOpsConstFolding(unittest.TestCase): t = Tensor.ones(16, dtype=dt).reshape(4, 4) assert t.sum().dtype == t.contiguous().sum().dtype -@unittest.skipIf(not_support_multi_device() or RANGEIFY, "no multi, RANGEIFY doesn't support multi const folding") +@unittest.skipIf(not_support_multi_device() or True, "no multi, RANGEIFY doesn't support multi const folding") class TestMultiConstFolding(unittest.TestCase): def test_multi_const_folding_literal(self): ds = tuple(f"{Device.DEFAULT}:{i}" for i in range(4)) diff --git a/test/test_custom_kernel.py b/test/test_custom_kernel.py new file mode 100644 index 0000000000..d563e61170 --- /dev/null +++ b/test/test_custom_kernel.py @@ -0,0 +1,221 @@ +import unittest +from tinygrad import Tensor, UOp, Context +from tinygrad.dtype import AddrSpace +from tinygrad.uop.ops import KernelInfo, AxisType + +# **** kernels **** + +def custom_arange_kernel(C:UOp) -> UOp: + i = UOp.range(C.size, 0) + return C[i].store(i.cast(C.dtype.base)).end(i).sink(arg=KernelInfo(name=f"custom_arange_{C.size}")) + +def custom_eye_kernel(C:UOp) -> UOp: + i = UOp.range(C.shape[0], 0) + j = UOp.range(C.shape[1], 1) + return C[i, j].store((i.eq(j)).cast(C.dtype.base)).end(i, j).sink(arg=KernelInfo(name=f"custom_eye_{C.size}")) + +def custom_add_one_kernel(B:UOp, A:UOp) -> UOp: + A,B = A.flatten(), B.flatten() + assert B.size == A.size + i = UOp.range(A.size, 0) + return B[i].store(A[i] + 1).end(i).sink(arg=KernelInfo(name=f"add_one_{A.size}")) + +def custom_elementwise_add_kernel(C:UOp, A:UOp, B:UOp) -> UOp: + C,A,B = C.flatten(), A.flatten(), B.flatten() + i = UOp.range(C.size, 0) + return C[i].store(A[i]+B[i]).end(i).sink(arg=KernelInfo(name=f"custom_add_kernel_{C.size}")).simplify() + +def custom_elementwise_addmul_kernel(C:UOp, D:UOp, A:UOp, B:UOp) -> UOp: + C,D,A,B = C.flatten(), D.flatten(), A.flatten(), B.flatten() + assert C.size == D.size + i = UOp.range(C.size, 0) + store_c = C[i].store(A[i]+B[i]) + store_d = D[i].store(A[i]*B[i]) + return UOp.group(store_c, store_d).end(i).sink(arg=KernelInfo(name=f"custom_addmul_kernel_{C.size}")).simplify() + +def custom_gemm(C:UOp, A:UOp, B:UOp) -> UOp: + assert A.shape[1] == B.shape[0] + i, j, k = UOp.range(C.shape[0], 0), UOp.range(C.shape[1], 1), UOp.range(A.shape[1], 2, axis_type=AxisType.REDUCE) + C = C[i, j].set(0.0) + C = C[i, j].set(C.after(k)[i, j] + A[i, k] * B[k, j], end=k) + prog = C.end(i, j) + return prog.sink(arg=KernelInfo(name=f"custom_gemm_{C.shape[0]}_{C.shape[1]}_{A.shape[1]}", opts_to_apply=())) + +def custom_sum(B:UOp, A:UOp) -> UOp: + i = UOp.range(A.shape[0], 0, axis_type=AxisType.REDUCE) + B = B[0].set(0.0) + B = B[0].set(B.after(i)[0] + A[i], end=i) + return B.sink(arg=KernelInfo(name=f"custom_sum_{A.shape[0]}", opts_to_apply=())) + +def flip_contract_kernel(dest:UOp, src:UOp): + i = UOp.range(dest.shape[0], 0) + j = UOp.range(dest.shape[1], 1, AxisType.UPCAST) + vec = src[i, j].contract(j) + store = UOp.group(*[dest[i, k].store(vec.gep(3-k)) for k in range(4)]) + return store.end(i).sink(arg=KernelInfo(name=f"flip_contract_{dest.size}", opts_to_apply=())) + +def slice_sum_kernel(dest:UOp, src:UOp): + G = UOp.range(src.shape[0], 0) + slice_src = src[G, :] + reg = UOp.placeholder((1,), dest.dtype.base, 0, addrspace=AddrSpace.REG) + reg = reg.after(G)[0].set(0) + R = UOp.range(src.shape[1], 1, AxisType.REDUCE) + reg = reg[0].set(reg.after(R)[0] + slice_src[R], end=R) + ast = dest[G].set(reg[0], end=G) + return ast.sink(arg=KernelInfo(name=f"slice_sum_{src.shape[0]}_{src.shape[1]}", opts_to_apply=())) + +def simple_qkv_kernel(O:UOp, Q:UOp, K:UOp, V:UOp) -> UOp: + # attention without softmax + N, d = Q.shape[0], Q.shape[1] + + i = UOp.range(N, 0) # output row + d_out = UOp.range(d, 1) # output column + j = UOp.range(N, 2, axis_type=AxisType.REDUCE) + + k_inner = UOp.range(d, 3, axis_type=AxisType.REDUCE) + qk_acc = UOp.placeholder((1,), Q.dtype.base, 0, addrspace=AddrSpace.REG) + qk_acc = qk_acc.after(i, j)[0].set(0.0) + qk_acc = qk_acc[0].set(qk_acc.after(k_inner)[0] + Q[i, k_inner] * K[j, k_inner], end=k_inner) + qk_score = qk_acc[0] / (d ** 0.5) + + out_acc = UOp.placeholder((1,), Q.dtype.base, 1, addrspace=AddrSpace.REG) + out_acc = out_acc.after(i, d_out)[0].set(0.0) + out_acc = out_acc[0].set(out_acc.after(j)[0] + qk_score * V[j, d_out], end=j) + + store = O[i, d_out].store(out_acc[0]) + return store.end(d_out).end(i).sink(arg=KernelInfo(name=f"simple_qkv_{N}_{d}", opts_to_apply=())) + +# **** backward callbacks **** + +def backward_gemm(gradient:UOp, kernel:UOp) -> tuple[UOp, UOp]: + out, a, b = kernel.src + grad_a = (Tensor(gradient) @ Tensor(b).T).uop + grad_b = (Tensor(a).T @ Tensor(gradient)).uop + return (None, grad_a, grad_b) + +def backward_gemm_custom(gradient:UOp, kernel:UOp) -> tuple[UOp, UOp]: + out, a, b = kernel.src + grad_a = Tensor.empty_like(Tensor(a)).custom_kernel(Tensor(gradient), Tensor(b).T, fxn=custom_gemm)[0].uop + grad_b = Tensor.empty_like(Tensor(b)).custom_kernel(Tensor(a).T, Tensor(gradient), fxn=custom_gemm)[0].uop + return (None, grad_a, grad_b) + +# **** tests **** + +class TestCustomKernel(unittest.TestCase): + def test_simple(self): + a = Tensor.ones(16, 16).contiguous() + b = Tensor.ones(16, 16).contiguous() + c = Tensor.empty(16, 16) + + c = Tensor.custom_kernel(c,a,b, fxn=custom_elementwise_add_kernel)[0] + + out = c.flatten().tolist() + assert all(x == 2 for x in out), "all 2" + + def test_multioutput(self): + a = Tensor.full((16, 16), 3.).contiguous() + b = Tensor.full((16, 16), 3.).contiguous() + c = Tensor.empty(16, 16) + d = Tensor.empty(16, 16) + + c,d = Tensor.custom_kernel(c,d,a,b, fxn=custom_elementwise_addmul_kernel)[:2] + Tensor.realize(c,d) + + assert all(x == 6 for x in c.flatten().tolist()), "all 6" + assert all(x == 9 for x in d.flatten().tolist()), "all 9" + + def test_arange(self): + ref = Tensor.arange(100) + tst = Tensor.empty_like(ref) + tst = tst.custom_kernel(fxn=custom_arange_kernel)[0] + self.assertTrue((ref == tst).all().item()) + + def test_eye(self): + ref = Tensor.eye(1024).contiguous().realize() + tst = Tensor.empty_like(ref) + tst = tst.custom_kernel(fxn=custom_eye_kernel)[0] + self.assertTrue((ref == tst).all().item()) + + def test_flip_contract(self): + a = Tensor.randn(10,4) + b = Tensor.empty_like(a) + b = b.custom_kernel(a, fxn=flip_contract_kernel)[0] + self.assertTrue((a.flip(1) == b).all().item()) + + def test_noncontig(self): + a = Tensor.ones(16, 16).contiguous() + tst = Tensor.empty_like(a) + b = a+1 + b_p1 = Tensor.custom_kernel(tst, b, fxn=custom_add_one_kernel)[0] + self.assertTrue((b_p1 == 3).all().item()) + + def test_sum(self): + # TODO: this only works for float, and silently fails with int + a = Tensor([1.0, 2, 3, 4, 5]) + tst = Tensor.empty(1) + b = Tensor.custom_kernel(tst, a, fxn=custom_sum)[0] + self.assertEqual(b.item(), 15) + + def test_slice_sum(self): + A = Tensor.randn(16, 16).contiguous() + B = Tensor.empty(16) + B = Tensor.custom_kernel(B, A, fxn=slice_sum_kernel)[0] + self.assertTrue(B.allclose(A.sum(1))) + + def test_gemm(self): + N = 16 + a = Tensor.randn(N, N) + b = Tensor.randn(N, N) + c = Tensor.empty(N, N) + + tst = Tensor.custom_kernel(c, a, b, fxn=custom_gemm)[0] + err = (tst - (a@b)).square().max() + self.assertLess(err.item(), 1e-6) + + def test_gemm_backward_custom(self): self.test_gemm_backward(True) + # NOTE: grad_fxn doesn't work with pyrender + @Context(SPEC=1) + def test_gemm_backward(self, custom_backward_gemm=False): + N = 4 + a_rand = Tensor.randn(N, 8) + b_rand = Tensor.randn(8, N) + Tensor.realize(a_rand, b_rand) + + a, b = Tensor(a_rand.numpy(), requires_grad=True), Tensor(b_rand.numpy(), requires_grad=True) + c = Tensor.empty(N, N) + tst = Tensor.custom_kernel(c, a, b, fxn=custom_gemm, grad_fxn=backward_gemm_custom if custom_backward_gemm else backward_gemm)[0] + tst.sum().backward() + grad_a, grad_b = a.grad, b.grad + Tensor.realize(tst, grad_a, grad_b) + + a, b = Tensor(a_rand.numpy(), requires_grad=True), Tensor(b_rand.numpy(), requires_grad=True) + ref = (a@b) + ref.sum().backward() + real_grad_a, real_grad_b = a.grad, b.grad + Tensor.realize(ref, real_grad_a, real_grad_b) + + err = (tst - ref).square().max() + self.assertLess(err.item(), 1e-6) + + err = (grad_a - real_grad_a).square().max() + self.assertLess(err.item(), 1e-6) + + err = (grad_b - real_grad_b).square().max() + self.assertLess(err.item(), 1e-6) + + def test_simple_qkv(self): + N, d = 8, 4 + Q = Tensor.randn(N, d) + K = Tensor.randn(N, d) + V = Tensor.randn(N, d) + O = Tensor.empty(N, d) + + O_custom = Tensor.custom_kernel(O, Q, K, V, fxn=lambda o,q,k,v: simple_qkv_kernel(o,q,k,v))[0] + O_ref = ((Q @ K.T) / (d ** 0.5)) @ V + + Tensor.realize(O_custom, O_ref) + err = (O_custom - O_ref).square().max() + self.assertLess(err.item(), 1e-6) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_dtype.py b/test/test_dtype.py index 7762166b03..bc7ca7e507 100644 --- a/test/test_dtype.py +++ b/test/test_dtype.py @@ -6,6 +6,7 @@ from tinygrad.device import is_dtype_supported from tinygrad.helpers import getenv, DEBUG, CI from tinygrad.dtype import DType, DTYPES_DICT, least_upper_dtype, fp8_to_float, float_to_fp8, _to_np_dtype, _to_torch_dtype, truncate from tinygrad.renderer.ptx import PTXRenderer +from tinygrad.renderer.nir import NIRRenderer from tinygrad import Device, Tensor, dtypes from hypothesis import given, settings, strategies as strat from test.helpers import rand_for_dtype @@ -102,7 +103,7 @@ class TestDType(unittest.TestCase): )) @unittest.skipIf(Device.DEFAULT == "PYTHON", "skip for now") - @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "skip for now") + @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, (PTXRenderer, NIRRenderer)), "skip for now") def test_uint_overflow(self): if not dtypes.is_unsigned(self.DTYPE): raise unittest.SkipTest("only for unsigned") v = dtypes.max(self.DTYPE) @@ -261,7 +262,7 @@ class TestFloatDType(TestDType): class TestDoubleDType(TestDType): DTYPE = dtypes.double @unittest.skipIf((CI and Device.DEFAULT in {"CUDA", "NV"}) or \ - isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "conversion not supported on CI CUDA and PTX") # TODO: why not? + isinstance(Device[Device.DEFAULT].renderer, (PTXRenderer, NIRRenderer)), "conversion not supported on CI CUDA, PTX, and NIR") # TODO: why not? def test_float64_increased_precision(self): for func in [ lambda t: t.exp(), diff --git a/test/test_dtype_alu.py b/test/test_dtype_alu.py index 19debe432d..4584dad4b3 100644 --- a/test/test_dtype_alu.py +++ b/test/test_dtype_alu.py @@ -6,6 +6,7 @@ from tinygrad.tensor import _to_np_dtype from tinygrad.device import is_dtype_supported from tinygrad.runtime.ops_python import from_storage_scalar from tinygrad.renderer.ptx import PTXRenderer +from tinygrad.renderer.nir import NIRRenderer import numpy as np import pytest from hypothesis import assume, given, strategies as strat, settings, HealthCheck @@ -29,8 +30,8 @@ unary_operations = [(Tensor.exp, np.exp), (Tensor.log, np.log), (Tensor.sin, np. # TODO: enable this (this is a dtype issue) #binary_operations.append(operator.truediv) -# TODO: CI CUDA segfaults on sin, WEBGPU sin is not precise enough for large numbers -if (getenv("MOCKGPU") and Device.DEFAULT in {"NV", "CUDA"}) or Device.DEFAULT == "WEBGPU": +# TODO: CI CUDA segfaults on sin, WEBGPU and NIR sines are not precise enough for large numbers +if (getenv("MOCKGPU") and Device.DEFAULT in {"NV", "CUDA"}) or Device.DEFAULT == "WEBGPU" or isinstance(Device[Device.DEFAULT].renderer, NIRRenderer): unary_operations.remove((Tensor.sin, np.sin)) unary_operations.remove((Tensor.cos, np.cos)) @@ -74,7 +75,10 @@ def universal_test_unary(a, dtype, op): out: Tensor = op[0](ta) tensor_value = out.numpy() numpy_value = op[1](ta.numpy()) - if dtype in dtypes.fp8s: numpy_value = truncate[dtype](numpy_value) + if dtype in dtypes.fp8s: + # cuda cast f32 inf to f8 MAX, amd cast it to nan(E4M3)/inf(E5M2) + if math.isinf(numpy_value): return + numpy_value = truncate[dtype](numpy_value) if dtype in dtypes.floats: atol, rtol = { dtypes.float16:(1e-3, 1e-2), dtypes.bfloat16:(1e-3, 2e-2), dtypes.fp8e4m3:(1e-1, 1e-1), dtypes.fp8e5m2: (1.0, 5e-1)}.get(dtype, (1e-6, 1e-5)) @@ -184,12 +188,13 @@ class TestDTypeALU(unittest.TestCase): @given(ht.int32, ht.int32, ht.float32, strat.sampled_from(integer_binary_operations), strat.sampled_from(binary_operations)) def test_int32_midcast_float(self, a, b, c, op1, op2): universal_test_midcast(a, b, c, op1, op2, dtypes.int32, dtypes.float32) - # Metal and CUDA and HIP behave differently than numpy in CI for overflows - skip_overflow = CI and Device.DEFAULT in {"AMD", "NV", "CUDA"} + # Metal and CUDA and HIP and NIR behave differently than numpy in CI for overflows + skip_overflow = (CI and Device.DEFAULT in {"AMD", "NV", "CUDA"}) or isinstance(Device[Device.DEFAULT].renderer, NIRRenderer) @given(strat.floats(width=32, min_value=0, max_value=10.0) if skip_overflow else ht.float32, strat.floats(width=32, min_value=0, max_value=10.0) if skip_overflow else ht.float32, ht.int32, strat.sampled_from(binary_operations), strat.sampled_from(integer_binary_operations)) @unittest.skipIf(Device.DEFAULT == "PYTHON", "TODO: fix cast inf to int32 in PYTHON") + @unittest.skip("broken on Mac") def test_float_midcast_int32(self, a, b, c, op1, op2): universal_test_midcast(a, b, c, op1, op2, dtypes.float32, dtypes.int32) @unittest.skip("broken. TODO: fix it") diff --git a/test/test_edgecases.py b/test/test_edgecases.py index 026ec2fb23..06531ef997 100644 --- a/test/test_edgecases.py +++ b/test/test_edgecases.py @@ -26,8 +26,9 @@ import unittest import numpy as np import torch from tinygrad import Tensor, dtypes, nn -from tinygrad.device import is_dtype_supported +from tinygrad.device import Device, is_dtype_supported from tinygrad.helpers import getenv +from tinygrad.renderer.nir import NIRRenderer MOCKGPU = getenv("MOCKGPU") @@ -206,7 +207,8 @@ class TestUOpValidationIssue(unittest.TestCase): # these fail with UOp verification error. # we want more of these with diverse errors! - @unittest.skipIf((not is_dtype_supported(dtypes.long)) or MOCKGPU, "hangs gpuocelot") + @unittest.skipIf((not is_dtype_supported(dtypes.long)) or MOCKGPU or isinstance(Device[Device.DEFAULT].renderer, NIRRenderer), + "hangs gpuocelot, NIR cannot render") def test_tensor_index_overflow(self): val = Tensor([1]) big = val.expand(2**31 + 3) diff --git a/test/test_fusion_op.py b/test/test_fusion_op.py index 255479cc48..6dd9040dc1 100644 --- a/test/test_fusion_op.py +++ b/test/test_fusion_op.py @@ -51,7 +51,7 @@ class TestFusionOp(unittest.TestCase): a = Tensor(val) for _ in range(24): a = Tensor.stack(a, a)[0] sched = a.schedule() - self.assertEqual(len(sched), 1) + self.assertEqual(len(sched), 0) self.assertLess(time.perf_counter()-st, 2.0) def test_recursive_reshape(self): diff --git a/test/test_image_dtype.py b/test/test_image_dtype.py index 41e7f891e1..da1f3aeeea 100644 --- a/test/test_image_dtype.py +++ b/test/test_image_dtype.py @@ -4,7 +4,7 @@ from tinygrad import Device, dtypes, Tensor, Context from tinygrad.device import LRUAllocator, is_dtype_supported from tinygrad.dtype import ImageDType from tinygrad.engine.realize import lower_schedule -from tinygrad.helpers import prod, unwrap, RANGEIFY +from tinygrad.helpers import prod, unwrap from test.helpers import REAL_DEV IMAGE_SUPPORTED_DEVICES = ("QCOM", "CL") @@ -52,7 +52,6 @@ class TestImageDType(unittest.TestCase): assert isinstance(it.uop.base.realized.dtype, ImageDType) np.testing.assert_equal(tst, it.numpy()) - @unittest.expectedFailure # this isn't supported anymore, CAST to ImageDType stays ImageDType def test_image_cast_and_back_collapses(self): data = Tensor.randn(9*27*4).realize() tst = data.numpy() @@ -139,7 +138,7 @@ class TestImageDType(unittest.TestCase): # NOTE: the w1 grad must realize to a seperate kernel assert w1.grad.uop.is_realized, f"never realized {w1.grad}" self.assertEqual(w1.grad.uop.base.buffer.dtype, dtypes.float32) - self.assertEqual(len(sched), 9 if RANGEIFY else 10) + self.assertEqual(len(sched), 9) @unittest.skipUnless(REAL_DEV in IMAGE_SUPPORTED_DEVICES, "Images not supported") class TestImageRealization(unittest.TestCase): diff --git a/test/test_jit.py b/test/test_jit.py index a7d4536cfd..bba8ebd54a 100644 --- a/test/test_jit.py +++ b/test/test_jit.py @@ -838,7 +838,7 @@ class TestJitRandom(unittest.TestCase): tst = {0:[], 1:[]} for r in [0,1]: Tensor.manual_seed(1337) - with Context(RANGEIFY=r): + with Context(JIT=r): _ = Tensor.randint(4, high=3) # this second one makes the behavior different _ = Tensor.randint(4, high=3) diff --git a/test/test_linearizer.py b/test/test_linearizer.py index ba12e97a8f..8db737e2b8 100644 --- a/test/test_linearizer.py +++ b/test/test_linearizer.py @@ -4,16 +4,15 @@ from dataclasses import replace from tinygrad.codegen.opt import Opt, OptOps from tinygrad.codegen.gpudims import get_grouped_dims -from tinygrad.uop.ops import UOp, Ops, GroupOp +from tinygrad.uop.ops import UOp, Ops, GroupOp, AxisType, PatternMatcher, graph_rewrite, UPat from tinygrad.device import Device, Buffer, is_dtype_supported -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View from tinygrad.tensor import Tensor, _to_np_dtype from tinygrad.engine.realize import run_schedule, lower_schedule, CompiledRunner, get_program -from tinygrad.helpers import Context, flatten, dedup, TC_SELECT, TC_OPT, RANGEIFY +from tinygrad.helpers import Context, flatten, dedup, TC_SELECT, TC_OPT, getenv from tinygrad.dtype import DType, dtypes, PtrDType, AddrSpace -from tinygrad.codegen import apply_rewrites, rewrites_for_views from tinygrad.renderer.ptx import PTXRenderer +from tinygrad.renderer.cstyle import CUDARenderer +MOCKGPU = getenv("MOCKGPU") class TestLinearizer(unittest.TestCase): def test_arg_dedup(self): @@ -39,28 +38,26 @@ class TestLinearizer(unittest.TestCase): np.testing.assert_equal(a.numpy(), ta) np.testing.assert_equal(b.numpy(), tb) - def test_multioutput(self): - dtype, st = dtypes.int, ShapeTracker.from_shape((8,)) - g0, g1, g2, g3 = [UOp(Ops.DEFINE_GLOBAL, dtype.ptr(), arg=i) for i in range(4)] - a = UOp(Ops.LOAD, dtype, src=(g2.view(st),)) - b = UOp(Ops.LOAD, dtype, src=(g3.view(st),)) - out0 = UOp(Ops.STORE, dtypes.void, src=(g0.view(st), a + b)) - out1 = UOp(Ops.STORE, dtypes.void, src=(g1.view(st), a * b)) - sink = UOp(Ops.SINK, src=(out0, out1)) - - a_t = Tensor.full(st.shape, 2).contiguous().realize() - b_t = Tensor.full(st.shape, 3).contiguous().realize() - helper_linearizer_ast(sink, [a_t, b_t], wanna_output=[a_t.numpy()+b_t.numpy(), a_t.numpy()*b_t.numpy()]) - uops = get_program(sink, opts=[]).uops - stores = [u for u in uops if u.op is Ops.STORE] - mutable_bufs = dedup(flatten([[x for x in u.src[0].toposort() if x.op is Ops.DEFINE_GLOBAL] for u in stores])) - assert len(mutable_bufs) == len(stores) == 2 - self.assertSetEqual(set([u.arg for u in mutable_bufs]), set([0,1])) + @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "broken on ptx") + def test_late_bias_load(self): + img = Tensor.empty(1, 3, 16, 16) + w = Tensor.empty(16, 3, 3, 3) + b = Tensor.empty(16) + out = img.conv2d(w, b) + ast = helper_linearizer_opt(out) + uops = get_program(ast, opts=[]).uops + # slice at the last loop end + uslice = [i for i,u in enumerate(uops) if u.op == Ops.END][-1] + # only valid test if outermost range is the reduce + if uops[uslice].src[-1].arg[-1] == AxisType.REDUCE: + load_types = [u.src[0].dtype for u in uops[uslice+1:] if u.op == Ops.LOAD] + # assert that there is a global load after the reduce ends + assert any(dt.addrspace == AddrSpace.GLOBAL for dt in load_types) def _test_no_nested_ranges(self, lins, skip=None): for l in lins: range_in_acc = flatten([[x for x in u.src if x.op is Ops.RANGE] for u in l.uops if u.op is Ops.DEFINE_REG]) - ranges = [u.op for u in l.uops if (u.op is Ops.RANGE and u in range_in_acc) or (u.op is Ops.ENDRANGE and u.src[0] in range_in_acc)] + ranges = [u.op for u in l.uops if (u.op is Ops.RANGE and u in range_in_acc) or (u.op is Ops.END and u.src[0] in range_in_acc)] for i,u in enumerate(ranges): if skip and i in skip: continue assert ranges[i-1] != u, f"multireduce nested the ranges! {ranges[i-1], {u}}" @@ -81,6 +78,7 @@ class TestLinearizer(unittest.TestCase): ranges = [i for i,u in enumerate(uops) if u.op is Ops.RANGE] assert len(ranges) == 1 # NOTE: it collapses now + @unittest.expectedFailure # TODO: investigate def test_two_nested_range_alt_indexing(self): a = Tensor([2, 2]).realize() out = a.reshape(2, 1).pad(((1, 1), (1, 1)), value=2).sum() @@ -89,7 +87,8 @@ class TestLinearizer(unittest.TestCase): ranges = [i for i,u in enumerate(uops) if u.op is Ops.RANGE] # RANGE -> ALU -> RANGE -> ALU + LOAD -> STORE assert any(x.op in GroupOp.ALU for x in uops[ranges[0]:ranges[1]]) - assert not any(x.op is Ops.LOAD for x in uops[ranges[0]:ranges[1]]) + # the index of the load doesnt depend on the second range + assert any(x.op is Ops.LOAD for x in uops[ranges[0]:ranges[1]]) assert any(x.op in {*GroupOp.ALU, Ops.LOAD} for x in uops[ranges[1]:]) def test_range_outer_op_before_phi(self): @@ -173,6 +172,7 @@ class TestLinearizer(unittest.TestCase): assert stores[1].src[1].dtype == dtypes.float assert any(x.op is Ops.DEFINE_GLOBAL for x in stores[1].toposort()) + @unittest.skipIf(Device.DEFAULT=="CPU", "CPU splits the cat so cant upcast") def test_zero_fold(self): a, b = Tensor.randn(1).realize(), Tensor.randn(1).realize() r = Tensor.stack(a, b) @@ -223,7 +223,7 @@ class TestLinearizer(unittest.TestCase): # the uops graph is DEFINE_REG -> 4x STORE 0.0 -> RANGE -> 4x ALU -> 4x STORE -> ENDRANGE uops = get_program(ast, opts=opt).uops begin_range = [i for i, x in enumerate(uops) if x.op is Ops.RANGE][-1] - end_range = [i for i, x in enumerate(uops) if x.op is Ops.ENDRANGE][0] + end_range = [i for i, x in enumerate(uops) if x.op is Ops.END][0] for i,u in enumerate(uops): print(i, u.op, [uops.index(s) for s in u.src], u.arg, u.dtype) for u in uops: if u.op is Ops.STORE and isinstance(dt:=u.src[0].dtype, PtrDType) and dt.addrspace is AddrSpace.REG: @@ -232,8 +232,8 @@ class TestLinearizer(unittest.TestCase): else: assert u.src[1].op in GroupOp.ALU assert begin_range < uops.index(u) < end_range - # children of STORE are placed after ENDRANGE - if any(x.op is Ops.STORE and x.src[1].op in GroupOp.ALU for x in u.src): + # children of END are placed after ENDRANGE + if any(x.op is Ops.END and x.src[1].op in GroupOp.ALU for x in u.src): assert end_range < uops.index(u) def test_grouped_dims(self): @@ -279,6 +279,8 @@ class TestLinearizer(unittest.TestCase): _assert_grouped_dims("gidx", (65536,), (16,16,256), False, [16,16,256], False) # 2 -> 3 _assert_grouped_dims("gidx", (128,128), (16,16,256), False, [16,16,64], False) + # 2 -> 2 + _assert_grouped_dims("gidx", (65536,2), (65535,65535,65535), False, [32768,4], False) # test when the only divisor is the square root of dim _assert_grouped_dims("gidx", (121,), (12,12,12), False, [11,11], False) @@ -303,6 +305,27 @@ class TestLinearizer(unittest.TestCase): with self.assertRaises(RuntimeError): get_grouped_dims("gidx", (2,3,4,5,6), (16,16,16)) + # TODO: In the above cases we only test if the shape after reshape is correct, never the indices. + # We should check if the returned indices are correct, for all cases. + # (65536, 2) -> (32768, 4) + dims, expected_limited_dims = (65536,2), (32768, 4) + idxs = get_grouped_dims("gidx", dims, (65535,65535,65535)) + def match_div(): raise RuntimeError("match_div") + def match_mod(): raise RuntimeError("match_mod") + flat_idx_pattern = UPat(Ops.SPECIAL, arg='gidx0')*expected_limited_dims[1]+UPat(Ops.SPECIAL, arg='gidx1') + pm = PatternMatcher([ + (flat_idx_pattern//dims[1], match_div), + (flat_idx_pattern%dims[1], match_mod) + ]) + + with self.assertRaises(RuntimeError) as error: + graph_rewrite(idxs[0], pm) + self.assertIn("match_div", str(error.exception)) + + with self.assertRaises(RuntimeError) as error: + graph_rewrite(idxs[1], pm) + self.assertIn("match_mod", str(error.exception)) + # # variable too large # with self.assertRaises(AssertionError): # get_grouped_dims("gidx", (Variable("start_pos",0,16),3,4), (16,16,16), False,) @@ -335,7 +358,7 @@ class TestLinearizer(unittest.TestCase): a.realize() np.testing.assert_equal(a.flatten().numpy(), [1.,1.,1.,1.,2.,2.,2.,2.,1.,1.,1.,1.,1.,1.,1.,1.]) - @unittest.skipIf(RANGEIFY and isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "PTX indexes differently. might be ok?") + @unittest.skipIf(MOCKGPU and isinstance(Device[Device.DEFAULT].renderer, (PTXRenderer, CUDARenderer)), "PTX indexes differently. might be ok?") def test_where_fold(self): a = Tensor.ones(4, 4).contiguous().realize() b = a.shrink(((1, 2), None)).pad(((1, 2), None)) @@ -411,14 +434,15 @@ class TestLinearizer(unittest.TestCase): uops = get_program(ast, opts=opt).uops local_stores = [u for u in uops if u.op is Ops.STORE and any(x.op is Ops.DEFINE_LOCAL for x in get_recursive(u.src[0]))] global_stores = [u for u in uops if u.op is Ops.STORE and any(x.op is Ops.DEFINE_GLOBAL for x in get_recursive(u.src[0]))] - barrier = [u for u in uops if u.op is Ops.BARRIER][0] + barrier = [u for u in uops if u.op is Ops.BARRIER] + assert len(barrier) == 1 # check that the float4 cast collapses for all stores for store in local_stores+global_stores: assert store.src[1].dtype.count > 1 # and store.src[2].op is not Ops.VECTORIZE # # check the children's vins # TODO: src ALU are not the same, should it? # assert barrier.src == tuple(local_stores) - assert len([u for u in uops if u.op is Ops.IF and u.src[-1] == barrier]) == 1 + assert len([u for u in uops if u.op is Ops.IF]) @unittest.skipUnless(Device[Device.DEFAULT].renderer.has_local, "test requires locals") @unittest.skipUnless(Device[Device.DEFAULT].renderer.has_shared, "test requires shared") @@ -438,45 +462,8 @@ class TestLinearizer(unittest.TestCase): # the global store doesn't change assert stores[1].src[1].dtype == dtypes.float - @unittest.skipUnless(Device[Device.DEFAULT].renderer.has_local, "test requires locals") - @unittest.skipUnless(Device[Device.DEFAULT].renderer.supports_float4, "test requires float4") - def test_skip_unmatching_upcasts(self): - Tensor.manual_seed(0) - c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(9600), arg=0, src=()) - c1 = c0.view(ShapeTracker(views=(View(shape=(240, 40, 1, 1), strides=(40, 1, 0, 0), offset=0, mask=None, contiguous=True),))) - c2 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(9600), arg=1, src=()) - c3 = c2.view(ShapeTracker(views=(View(shape=(240, 40, 1, 1), strides=(1, 240, 0, 0), offset=0, mask=None, contiguous=False),))) - c4 = c3.load() - c5 = c1.store(c4) - ast = c5.sink() - opt = [Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.LOCAL, axis=0, arg=16), - Opt(op=OptOps.LOCAL, axis=1, arg=2), Opt(op=OptOps.UPCAST, axis=3, arg=2)] - helper_linearizer_ast(ast, [Tensor.randn(240*40).realize()], opts=[opt]) - out = [u for u in get_program(ast, opts=opt).uops if u.op is Ops.STORE][0] - assert out.src[1].op is Ops.VECTORIZE and out.src[1].dtype == dtypes.float.vec(4) - - @unittest.skipUnless(Device[Device.DEFAULT].renderer.has_local, "test requires locals") - @unittest.skipUnless(Device[Device.DEFAULT].renderer.supports_float4, "test requires float4") - def test_skip_unmatching_upcasts_with_gep(self): - Tensor.manual_seed(0) - c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(256), arg=0, src=()) - c1 = c0.view(ShapeTracker(views=(View(shape=(8, 32, 1, 1), strides=(32, 1, 0, 0), offset=0, mask=None, contiguous=True),))) - c2 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(256), arg=1, src=()) - c3 = c2.view(ShapeTracker(views=(View(shape=(8, 32, 1, 1), strides=(1, 8, 0, 0), offset=0, mask=None, contiguous=False),))) - c4 = c3.load() - c5 = c1.store(c4) - ast = c5.sink() - opt = [Opt(op=OptOps.LOCAL, axis=1, arg=4), Opt(op=OptOps.UPCAST, axis=2, arg=2), Opt(op=OptOps.LOCAL, axis=1, arg=8), - Opt(op=OptOps.UPCAST, axis=1, arg=0), Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.LOCAL, axis=0, arg=8), - Opt(op=OptOps.UPCAST, axis=1, arg=0), Opt(op=OptOps.UPCAST, axis=0, arg=2)] - helper_linearizer_ast(ast, [Tensor.randn(8*32).realize()], opts=[opt]) - out = [u for u in get_program(ast).uops if u.op is Ops.STORE][0] - assert out.src[1].op is Ops.VECTORIZE and out.src[1].dtype.count != 1 - # *** helpers *** -def push_views(ast): return apply_rewrites(ast, rewrites_for_views) - def helper_realized_ast(r:Tensor|list[Tensor]) -> tuple[UOp, list[Buffer]]: if isinstance(r, Tensor): r = [r] s = Tensor.schedule(*r) @@ -485,12 +472,14 @@ def helper_realized_ast(r:Tensor|list[Tensor]) -> tuple[UOp, list[Buffer]]: # now all input buffers in s[-1] should be realized # create fresh buffers for the outputs bufs = [Buffer(x.device, x.size, x.dtype).allocate() if i < len(s[-1].ast.src) else x for i,x in enumerate(s[-1].bufs)] - return push_views(s[-1].ast), bufs + # ensure buffers are allocated + for b in bufs: b.ensure_allocated() + return s[-1].ast, bufs def helper_linearizer_ast(ast:UOp, inputs:list[Tensor], *args, **kwargs): assert isinstance(ast, UOp), "ast must be UOp" inbufs = [x.uop.base.buffer for x in inputs] - outbufs = [Buffer(inbufs[-1].device if inbufs else Device.DEFAULT, out.st_arg.size, out.src[1].dtype).allocate() for out in ast.src] + outbufs = [Buffer(inbufs[-1].device if inbufs else Device.DEFAULT, out.size, out.src[1].dtype).allocate() for out in ast.src] _helper_linearizer_opt_ast(ast, outbufs+inbufs, *args, **kwargs) def helper_linearizer_opt(r:Tensor|list[Tensor], *args, **kwargs): diff --git a/test/test_linearizer_dumb.py b/test/test_linearizer_dumb.py index fd9b55ee2f..bc550ce812 100644 --- a/test/test_linearizer_dumb.py +++ b/test/test_linearizer_dumb.py @@ -4,12 +4,9 @@ import unittest from tinygrad import Device, dtypes -from tinygrad.device import is_dtype_supported from tinygrad.uop.ops import UOp, Ops, AxisType, KernelInfo -from tinygrad.shape.shapetracker import ShapeTracker, View from tinygrad.codegen.opt.search import Opt, OptOps from tinygrad.engine.realize import get_program -from tinygrad.renderer.ptx import PTXRenderer class TestLinearizerFailure(unittest.TestCase): @unittest.skipUnless(Device.DEFAULT == "METAL", "only tested on METAL") @@ -19,100 +16,16 @@ class TestLinearizerFailure(unittest.TestCase): c2 = UOp.range(UOp.const(dtypes.index, 784), 1, AxisType.GLOBAL) c3 = UOp.range(UOp.const(dtypes.index, 10), 3, AxisType.GLOBAL) c4 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(512), arg=1, src=()) - c5 = c4.index(c1.valid(UOp.const(dtypes.bool, True))).load() + c5 = c4.index(c1.valid(UOp.const(dtypes.bool, True))) c6 = UOp.range(UOp.const(dtypes.index, 6000), 1004, AxisType.REDUCE) c7 = UOp.range(UOp.const(dtypes.index, 3750), 2006, AxisType.REDUCE) c8 = UOp.range(UOp.const(dtypes.index, 16), 2007, AxisType.GROUP_REDUCE) c9 = UOp(Ops.DEFINE_GLOBAL, dtypes.uchar.ptr(47040000), arg=2, src=()) - c10 = c9.index((((c3*UOp.const(dtypes.index, 4704000))+c2)+(c6*UOp.const(dtypes.index, 784))).valid(UOp.const(dtypes.bool, True))).load() + c10 = c9.index((((c3*UOp.const(dtypes.index, 4704000))+c2)+(c6*UOp.const(dtypes.index, 784))).valid(UOp.const(dtypes.bool, True))) c11 = c5.alu(Ops.CMPNE, ((((c3*UOp.const(dtypes.index, 6000))+c6)+((c7*UOp.const(dtypes.index, 16))+c8)).alu(Ops.CMPLT, UOp.const(dtypes.index, 59999)).where(UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 1)).reduce(c7, c8, arg=Ops.ADD)+UOp.const(dtypes.int, -1))).where(UOp.const(dtypes.uchar, 0), c10).reduce(c6, arg=Ops.ADD) - c12 = c0.index((((c1*UOp.const(dtypes.index, 7840))+(c2*UOp.const(dtypes.index, 10)))+c3).valid(UOp.const(dtypes.bool, True))).store(c11, c1, c2, c3) + c12 = c0.index((((c1*UOp.const(dtypes.index, 7840))+(c2*UOp.const(dtypes.index, 10)))+c3).valid(UOp.const(dtypes.bool, True))).store(c11).end(c1, c2, c3) ast = c12.sink(arg=KernelInfo(name='test', axis_types=(), dont_use_locals=False, applied_opts=(Opt(op=OptOps.GROUP, axis=1, arg=16),), opts_to_apply=None)) _ = get_program(ast, Device["METAL"].renderer) -class TestLinearizerDumb(unittest.TestCase): - @unittest.skipUnless(Device[Device.DEFAULT].renderer.has_local, "need local") - def test_max_simplify_and_cancel(self): - c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(1000), arg=0, src=()) - c1 = c0.view(ShapeTracker(views=(View(shape=(1000, 1), strides=(1, 0), offset=0, mask=None, contiguous=True),))) - c2 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(1000), arg=1, src=()) - c3 = c2.view(ShapeTracker(views=(View(shape=(1000, 1), strides=(1, 0), offset=0, mask=None, contiguous=True),))) - c4 = c3.load() - c5 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(1), arg=2, src=()) - c6 = c5.view(ShapeTracker(views=(View(shape=(1000, 1), strides=(0, 0), offset=0, mask=None, contiguous=False),))) - c7 = c6.load() - c8 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(1000, 1), strides=(0, 0), offset=0, mask=None, contiguous=False),)), src=()) - c9 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(1001, 1999), strides=(0, 0), offset=0, mask=((0, 1001), (999, 1999)), contiguous=False), View(shape=(1000, 1000), strides=(1, 2000), offset=0, mask=None, contiguous=False))), src=()) - c10 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(1000, 1000), strides=(0, 0), offset=0, mask=None, contiguous=False),)), src=()) - c11 = c1.store((c4.alu(Ops.CMPNE, c7).alu(Ops.CMPNE, UOp.const(dtypes.bool, True, src=c8)).cast(dtypes.int)*(c9.f(Ops.VALID, dtype=dtypes.bool).where(UOp.const(dtypes.int, -1, src=c10), UOp.const(dtypes.int, 0, src=c10)).f(Ops.REDUCE_AXIS, arg=(Ops.ADD, (1,)))+UOp.const(dtypes.int, 1000, src=c8)))) - ast = c11.sink() - #opts = [Opt(op=OptOps.UNROLL, axis=0, arg=4), Opt(op=OptOps.LOCAL, axis=0, arg=8)] - opts = [Opt(op=OptOps.LOCAL, axis=0, arg=8)] - prg = get_program(ast, Device[Device.DEFAULT].renderer, opts) - print(prg.src) - assert prg.uops is not None and not any(uop.op is Ops.MAX for uop in prg.uops), "leftover MAX" - - # this was a bug in embedding, someday we should fold this anyway - @unittest.skipUnless(is_dtype_supported(dtypes.half), f"half dtype not supported on {Device.DEFAULT}") - def test_llama_embedding(self): - c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(4096), arg=0, src=()) - c1 = c0.view(ShapeTracker(views=(View(shape=(4096, 1, 1), strides=(1, 0, 0), offset=0, mask=None, contiguous=True),))) - c2 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(32001, 63999), strides=(0, 0), offset=0, mask=((0, 32001), (31999, 63999)), contiguous=False), View(shape=(4096, 32000, 32000), strides=(0, 1, 64000), offset=0, mask=None, contiguous=False))), src=()) - c3 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4096, 32000, 32000), strides=(0, 0, 0), offset=0, mask=None, contiguous=False),)), src=()) - c4 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(4096, 32000, 1), strides=(0, 0, 0), offset=0, mask=None, contiguous=False),)), src=()) - c5 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(1), arg=1, src=()) - c6 = c5.view(ShapeTracker(views=(View(shape=(4096, 32000, 1), strides=(0, 0, 0), offset=0, mask=None, contiguous=False),))) - c7 = c6.load() - c8 = UOp(Ops.DEFINE_GLOBAL, dtypes.half.ptr(131072000), arg=2, src=()) - c9 = c8.view(ShapeTracker(views=(View(shape=(4096, 32000, 1), strides=(1, 4096, 0), offset=0, mask=None, contiguous=False),))) - c10 = c9.load() - c11 = c1.store(((c2.f(Ops.VALID, dtype=dtypes.bool).where(UOp.const(dtypes.int, 1, src=c3), UOp.const(dtypes.int, 0, src=c3)).f(Ops.REDUCE_AXIS, arg=(Ops.ADD, (2,)))+UOp.const(dtypes.int, -1, src=c4)).alu(Ops.CMPNE, c7).alu(Ops.CMPNE, UOp.const(dtypes.bool, True, src=c4)).cast(dtypes.half)*c10).cast(dtypes.float).f(Ops.REDUCE_AXIS, arg=(Ops.ADD, (1,))).cast(dtypes.half)) - ast = c11.sink() - prg = get_program(ast, Device[Device.DEFAULT].renderer) - print(prg.src) - - @unittest.expectedFailure - @unittest.skipUnless(Device[Device.DEFAULT].renderer.supports_float4, "need float4") - def test_unrolled_float4_align(self): - c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(1), arg=0, src=()) - c1 = c0.view(ShapeTracker(views=(View(shape=(1, 1), strides=(0, 0), offset=0, mask=None, contiguous=True),))) - c2 = UOp(Ops.DEFINE_GLOBAL, dtypes.long.ptr(18), arg=1, src=()) - c3 = c2.view(ShapeTracker(views=(View(shape=(3, 6), strides=(6, 1), offset=0, mask=None, contiguous=True),))) - c4 = c3.load() - c5 = UOp(Ops.VIEW, dtypes.void, arg=ShapeTracker(views=(View(shape=(3, 6), strides=(0, 0), offset=0, mask=None, contiguous=False),)), src=()) - c6 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(18), arg=2, src=()) - c7 = c6.view(ShapeTracker(views=(View(shape=(3, 6), strides=(6, 1), offset=0, mask=None, contiguous=True),))) - c8 = c7.load() - c9 = c1.store(c4.alu(Ops.CMPNE, UOp.const(dtypes.long, -1, src=c5)).alu(Ops.CMPNE, UOp.const(dtypes.bool, True, src=c5)).where(UOp.const(dtypes.float, 0.0, src=c5), c8).f(Ops.REDUCE_AXIS, arg=(Ops.ADD, (0, 1)))) - ast = c9.sink() - opts = [Opt(op=OptOps.UNROLL, axis=0, arg=0)] - prg = get_program(ast, Device[Device.DEFAULT].renderer, opts) - print(prg.src) - load_idxs = [x.src[1] for x in prg.uops if x.op is Ops.LOAD and x.src[0].arg == 2] - assert load_idxs[0] < load_idxs[1], f"first loaded idx {load_idxs[0].arg} then {load_idxs[1].arg}!" - - @unittest.expectedFailure - @unittest.skipUnless(Device[Device.DEFAULT].renderer.supports_float4, "need float4") - @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "this is somehow correct in PTX") - def test_upcasted_stores_out_of_order(self): - c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(9360), arg=0, src=()) - c1 = c0.view(ShapeTracker(views=(View(shape=(4, 5, 13, 1, 1, 1, 1, 1, 4, 3, 3), strides=(2340, 468, 36, 0, 0, 0, 0, 0, 9, 3, 1), offset=0, mask=None, contiguous=True),))) - c2 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(144), arg=1, src=()) - c3 = c2.view(ShapeTracker(views=(View(shape=(4, 5, 13, 1, 1, 1, 4, 1, 4, 3, 3), strides=(0, 0, 0, 0, 0, 0, 1, 0, 4, 48, 16), offset=0, mask=None, contiguous=False),))) - c4 = c3.load() - c5 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(1040), arg=2, src=()) - c6 = c5.view(ShapeTracker(views=(View(shape=(4, 5, 13, 1, 1, 1, 4, 1, 4, 3, 3), strides=(260, 13, 1, 0, 0, 0, 65, 0, 0, 0, 0), offset=0, mask=None, contiguous=False),))) - c7 = c6.load() - c8 = c1.store((c4*c7).f(Ops.REDUCE_AXIS, arg=(Ops.ADD, (6,)))) - ast = c8.sink() - opts = [Opt(op=OptOps.UPCAST, axis=3, arg=0), Opt(op=OptOps.UPCAST, axis=2, arg=0)] - prg = get_program(ast, Device[Device.DEFAULT].renderer, opts) - print(prg.src) - store_idxs = [x.src[1] for x in prg.uops if x.op is Ops.STORE] - for i in range(len(store_idxs) - 1): - first_bounds = store_idxs[i].vmin+store_idxs[i].vmax - next_bounds = store_idxs[i+1].vmin+store_idxs[i+1].vmax - assert first_bounds < next_bounds, f"first stored (max) idx {first_bounds} then {next_bounds}!" - if __name__ == '__main__': unittest.main() diff --git a/test/test_linearizer_failures.py b/test/test_linearizer_failures.py index 7bd0864c8e..e5c1521b91 100644 --- a/test/test_linearizer_failures.py +++ b/test/test_linearizer_failures.py @@ -12,11 +12,11 @@ class TestLinearizerFailures(unittest.TestCase): c3 = ((c1*UOp.const(dtypes.index, 32))+c2) c4 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(163840), arg=1, src=()) c5 = UOp.range(UOp.const(dtypes.index, 2560), 0, AxisType.REDUCE) - c6 = c4.index(((((((c5//UOp.const(dtypes.index, 8))%UOp.const(dtypes.index, 8))*UOp.const(dtypes.index, 8))+(c5%UOp.const(dtypes.index, 8)))+(((c2*UOp.const(dtypes.index, 40))+(c5//UOp.const(dtypes.index, 64)))*UOp.const(dtypes.index, 64)))+(c1*UOp.const(dtypes.index, 81920)))).load() + c6 = c4.index(((((((c5//UOp.const(dtypes.index, 8))%UOp.const(dtypes.index, 8))*UOp.const(dtypes.index, 8))+(c5%UOp.const(dtypes.index, 8)))+(((c2*UOp.const(dtypes.index, 40))+(c5//UOp.const(dtypes.index, 64)))*UOp.const(dtypes.index, 64)))+(c1*UOp.const(dtypes.index, 81920)))) c7 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(64), arg=2, src=()) - c8 = c7.index(c3).load() + c8 = c7.index(c3) c9 = ((((c6+(c8*UOp.const(dtypes.float, -1.0)))*(c6+(c8*UOp.const(dtypes.float, -1.0)))).reduce(c5, arg=Ops.ADD)*UOp.const(dtypes.float, 0.000390625))+UOp.const(dtypes.float, 1e-05)).sqrt().reciprocal() - c10 = c0.index(c3).store(c9, c1, c2) + c10 = c0.index(c3).store(c9).end(c1, c2) ast = c10.sink() get_program(ast) diff --git a/test/test_multitensor.py b/test/test_multitensor.py index fa6086da11..bca243c5e5 100644 --- a/test/test_multitensor.py +++ b/test/test_multitensor.py @@ -2,7 +2,7 @@ import unittest, functools, random from tinygrad import Tensor, Device, nn, GlobalCounters, TinyJit, dtypes, Variable from tinygrad.device import is_dtype_supported from tinygrad.uop.ops import Ops, UOp -from tinygrad.helpers import CI, getenv, prod, Context, RANGEIFY +from tinygrad.helpers import CI, getenv, prod, Context from tinygrad.nn.state import get_parameters, get_state_dict from tinygrad.engine.realize import lower_schedule, BufferCopy, CompiledRunner, run_schedule import numpy as np @@ -201,6 +201,13 @@ class TestMultiTensor(unittest.TestCase): fn = f(n) np.testing.assert_allclose(fX.numpy(), fn, rtol=1e-6, atol=1e-6) + def test_allreduce_shard_ring_sum(self): + for axis in (0, 1, None): + for use_ring in (0, 2): + t = Tensor([1, 2, 3, 4]).reshape(2, 2) + with Context(RING=use_ring): + np.testing.assert_equal(t.shard(devices_2, axis=axis).sum().item(), 10) + def test_allreduce_naive(self): with Context(RING=0): a,b = _test_allreduce(Tensor.rand(256, 256)) @@ -383,7 +390,6 @@ class TestMultiTensor(unittest.TestCase): # NOTE: this is failing on LLVM CI, no idea why. Works locally. @unittest.skipIf(CI and REAL_DEV in ("CUDA", "NV", "CPU", "AMD"), "slow, and flaky on CPU") - @unittest.skipIf(RANGEIFY, "TODO: pm_rangeify hangs") def test_data_parallel_resnet(self): from extra.models.resnet import ResNet18 @@ -420,7 +426,7 @@ class TestMultiTensor(unittest.TestCase): np.testing.assert_allclose(grad, shard_grad, atol=1e-5, rtol=1e-5) @unittest.skipIf(CI and REAL_DEV in ("CUDA", "NV", "CPU", "AMD"), "slow, and flaky on CPU") - @unittest.skipIf(RANGEIFY, "TODO: pm_rangeify hangs") + @unittest.skip("TODO: pm_rangeify hangs") def test_data_parallel_resnet_train_step(self): from extra.models.resnet import ResNet18 fake_image = Tensor.rand((2, 3, 224//16, 224//16)) @@ -428,7 +434,7 @@ class TestMultiTensor(unittest.TestCase): m = ResNet18() self._test_model_train_step(m, fake_image, labels) - @unittest.skipIf(RANGEIFY, "TODO: pm_rangeify hangs") + @unittest.skip("TODO: pm_rangeify hangs") def test_data_parallel_simple_train_step(self): class Model: def __init__(self): self.conv1 = nn.Linear(128,128) @@ -590,6 +596,12 @@ class TestMultiTensor(unittest.TestCase): # ast are the same on devices self.assertEqual(len(set(asts)), 1) + def test_flip(self): + rng = Tensor.rand((10, 10, 10)) + t0 = rng.shard(devices_2, axis=1) + out = t0.flip(0) + 1 + self.assertTrue((rng.flip(0)+1).allclose(out.to(rng.device))) + def test_reshape_on_axis(self): t0 = Tensor.rand((26, 15, 7)).shard(devices_3, axis=1) @@ -652,7 +664,7 @@ class TestMultiTensor(unittest.TestCase): # it doesn't work like this anymore # NOTE: this never failed in assign_multi, it failed tensor spec because MULTI was never pushed in the graph - @unittest.expectedFailure + @unittest.skip("this test is broken") def test_mlb_assign_change_axis(self): t_none = Tensor.zeros((16, 16)).shard(devices_2).contiguous().realize() t_zero = Tensor.ones((16, 16)).shard(devices_2, axis=0) @@ -793,7 +805,7 @@ class TestMultiTensor(unittest.TestCase): t = Tensor.rand(16, 16).shard(devices_2, axis=0) np.testing.assert_allclose(t.numpy(), t.clone().numpy()) - @unittest.skipIf(RANGEIFY, "RANGEIFY doesn't support multi const folding") + @unittest.skip("RANGEIFY doesn't support multi const folding") def test_multi_const_folding(self): with Context(TRACK_MATCH_STATS=0): a = Tensor.arange(3).realize() @@ -1130,6 +1142,7 @@ class TestMultiRamUsage(unittest.TestCase): del _ self.assertUsed(0) + @unittest.skip("flaky") def test_zeros_copy(self): _ = Tensor.zeros(self.N, self.N).contiguous().to(devices_2).realize() # NOTE: the first one on the DEFAULT device should be freed diff --git a/test/test_nn.py b/test/test_nn.py index ddada1eccb..00fcf70291 100644 --- a/test/test_nn.py +++ b/test/test_nn.py @@ -447,11 +447,11 @@ class TestNN(unittest.TestCase): # TODO: fused with opts uses more ops def test_embedding_one_kernel_fused(self): - with Context(FUSE_ARANGE=1, NOOPT=0): + with Context(NOOPT=0): self.test_embedding_one_kernel(ops=612_000, kcount=2) def test_embedding_one_kernel_fused_noopt(self): - with Context(FUSE_ARANGE=1, NOOPT=1): + with Context(NOOPT=1): self.test_embedding_one_kernel(ops=0, kcount=2) def test_embedding_shape(self): @@ -465,10 +465,9 @@ class TestNN(unittest.TestCase): def test_embedding_regression(self): # used to fail bounds check - with Context(FUSE_ARANGE=1): - embedding = Embedding(100, 1024) - input_ids = Tensor.empty(16, 16, dtype=dtypes.int) - embedding(input_ids).realize() + embedding = Embedding(100, 1024) + input_ids = Tensor.empty(16, 16, dtype=dtypes.int) + embedding(input_ids).realize() def test_load_state_dict(self): layer = Conv2d(3, 5, kernel_size=3) diff --git a/test/test_ops.py b/test/test_ops.py index dbd232edcf..2da830b7be 100644 --- a/test/test_ops.py +++ b/test/test_ops.py @@ -2,13 +2,13 @@ import time, math, unittest, functools, platform, warnings import numpy as np from typing import List, Callable import torch -from tinygrad.helpers import getenv, IMAGE, DEBUG, CI, Context, TRANSCENDENTAL, CPU_LLVM, AMD_LLVM, RANGEIFY +from tinygrad.helpers import getenv, IMAGE, DEBUG, CI, Context, CPU_LLVM, CPU_LVP, AMD_LLVM from tinygrad import Tensor, Device, dtypes from tinygrad.tensor import _to_np_dtype from tinygrad.device import is_dtype_supported if getenv("TINY_BACKEND"): - import tinygrad.frontend.torch # noqa: F401 # pylint: disable=unused-import + import tinygrad.nn.torch # noqa: F401 # pylint: disable=unused-import torch.set_default_device("tiny") if CI: @@ -698,8 +698,8 @@ class TestOps(unittest.TestCase): def test_pow_zero_tensor(self): helper_test_op(None, lambda x,y: x**y, vals=[[0.0], [0.0]]) - # TODO: fix WEBGPU - if Device.DEFAULT != "WEBGPU": + # TODO: fix WEBGPU and LVP + if Device.DEFAULT != "WEBGPU" and not CPU_LVP: helper_test_op(None, lambda x,y: x**y, vals=[[0.0], [0.3]]) helper_test_op(None, lambda x,y: x**y, vals=[[0.0], [-0.3]]) def test_pow_zero_const(self): @@ -830,6 +830,7 @@ class TestOps(unittest.TestCase): self.assertEqual(a, b) self.assertEqual(Tensor(-1).contiguous().idiv(4).item(), 0) # NOTE this is trunc-div behaviour + @unittest.skipIf(getenv("NV_NAK"), "MUFU.SIN is not accurate enough") def test_sin(self): helper_test_op([(45,65)], lambda x: x.sin()) helper_test_op([()], lambda x: x.sin()) @@ -839,6 +840,7 @@ class TestOps(unittest.TestCase): helper_test_op(None, lambda x: x.sin(), vals=[[1e1, 1e2, 1e3, 1e4, 1e5, 1e6, -1e1, -1e2, -1e3, -1e4, -1e5, -1e6]], atol=3e-3, rtol=3e-3, grad_atol=3e-3, grad_rtol=3e-3) @unittest.skipIf(Device.DEFAULT == "WEBGPU" and platform.system() == "Windows", "Not accurate enough with DirectX backend") + @unittest.skipIf(getenv("NV_NAK"), "MUFU.SIN is not accurate enough") def test_cos(self): helper_test_op([(45,65)], lambda x: x.cos()) helper_test_op([()], lambda x: x.cos()) @@ -847,6 +849,7 @@ class TestOps(unittest.TestCase): helper_test_op(None, lambda x: x.cos(), vals=[[1e1, 1e2, 1e3, 1e4, 1e5, 1e6, -1e1, -1e2, -1e3, -1e4, -1e5, -1e6]], atol=3e-3, rtol=3e-3, grad_atol=3e-3, grad_rtol=3e-3) @unittest.skipIf(Device.DEFAULT == "WEBGPU" and platform.system() == "Windows", "Not accurate enough with DirectX backend") + @unittest.skipIf(getenv("NV_NAK"), "MUFU.SIN is not accurate enough") def test_tan(self): # NOTE: backward has much higher diff with input close to pi/2 and -pi/2 helper_test_op([(45,65)], lambda x: x.tan(), low=-1.5, high=1.5) @@ -901,7 +904,6 @@ class TestOps(unittest.TestCase): def test_abs_exact(self): helper_test_op(None, torch.abs, Tensor.abs, vals=[[-1.,0,1]]) - @unittest.skipIf(TRANSCENDENTAL and Device.DEFAULT=="AMD", "TODO: remu crashes") def test_log(self): helper_test_op([(45,65)], torch.log, Tensor.log) helper_test_op(None, torch.log, Tensor.log, vals=[[math.inf, -math.inf, math.nan]]) @@ -911,7 +913,6 @@ class TestOps(unittest.TestCase): helper_test_op(None, torch.log2, Tensor.log2, vals=[[math.inf, -math.inf, math.nan]]) helper_test_op([()], torch.log2, Tensor.log2) - @unittest.skipIf(TRANSCENDENTAL and Device.DEFAULT=="AMD", "TODO: remu crashes") def test_exp(self): helper_test_op([(45,65)], torch.exp, Tensor.exp) helper_test_op(None, torch.exp, Tensor.exp, vals=[[math.inf, -math.inf, math.nan]]) @@ -1549,10 +1550,11 @@ class TestOps(unittest.TestCase): helper_test_op([(3,4,5,6)], lambda x: torch.stack(torch.std_mean(x, axis=(1,2))), lambda x: Tensor.stack(*x.std_mean(axis=(1,2)))) - @unittest.skip("TODO: this fails because of loaded nan in mul folding") def test_std_mean_loaded_nan(self): - helper_test_op([(1,0,3,0,5)], lambda x: torch.stack(torch.std_mean(x, axis=(1,3))), - lambda x: Tensor.stack(*x.std_mean(axis=(1,3)))) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message="std_mean\\(\\): degrees of freedom is <= 0") + helper_test_op([(1,0,3,0,5)], lambda x: torch.stack(torch.std_mean(x, axis=(1,3))), + lambda x: Tensor.stack(*x.std_mean(axis=(1,3)))) def test_softmax(self): helper_test_op([(45,65)], torch.nn.Softmax(dim=1), Tensor.softmax, atol=1e-7, grad_atol=1e-7) helper_test_op([(45)], torch.nn.Softmax(dim=0), Tensor.softmax, atol=1e-7, grad_atol=1e-7) @@ -2602,17 +2604,13 @@ class TestOps(unittest.TestCase): lambda x: torch.nn.functional.avg_pool2d(x, kernel_size=(111,28)), lambda x: Tensor.avg_pool2d(x, kernel_size=(111,28)), rtol=1e-5) - def test_avg_pool3d_failure(self): - with Context(NOOPT=0): - helper_test_op([(1,1,16,16,16)], - lambda x: torch.nn.functional.avg_pool3d(x, kernel_size=(8,8,8), stride=5, padding=1, count_include_pad=False), - lambda x: Tensor.avg_pool2d(x, kernel_size=(8,8,8), stride=5, padding=1, count_include_pad=False), rtol=1e-5, forward_only=True) - - def test_avg_pool3d_noopt(self): - with Context(NOOPT=1): - helper_test_op([(1,1,16,16,16)], - lambda x: torch.nn.functional.avg_pool3d(x, kernel_size=(8,8,8), stride=5, padding=1, count_include_pad=False), - lambda x: Tensor.avg_pool2d(x, kernel_size=(8,8,8), stride=5, padding=1, count_include_pad=False), rtol=1e-5, forward_only=True) + def test_avg_pool3d(self): + # TODO: AMD_LLVM has larger atol + # TODO: PYTHON=1 backward hangs? + atol = 1e-2 if AMD_LLVM else 1e-6 + helper_test_op([(1,1,16,16,16)], + lambda x: torch.nn.functional.avg_pool3d(x, kernel_size=(8,8,8), stride=5, padding=1, count_include_pad=False), + lambda x: Tensor.avg_pool2d(x, kernel_size=(8,8,8), stride=5, padding=1, count_include_pad=False), atol=atol, rtol=1e-5, forward_only=True) def test_interpolate_linear(self): for in_sz, out_sz in [((52,),(29,)), ((29,),(52,))]: @@ -2824,13 +2822,13 @@ class TestOps(unittest.TestCase): @slow_test def test_slice_fancy_indexing_list_indices(self): a,b,c,d,e,i,j,k,o,p = self._get_index_randoms() - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[[0]]], lambda x: x[[[0]]]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[0],b,c,d,:], lambda x: x[[0],j,k,o,:]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[((0,),)]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[(0,),b,c,d,:], lambda x: x[(0,),j,k,o,:]) helper_test_op([(2,5,6,5,3,4)], lambda x: x[[[[0]]],b,c,d,[[1]]], lambda x: x[[[[0]]],j,k,o,[[1]]]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[1,0,-1],b,c,d,:], lambda x: x[[1,0,-1],j,k,o,:]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[a,b,c,[1,2,3],...], lambda x: x[i,j,k,[1,2,3],...]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[(1,0,-1),b,c,d,:], lambda x: x[(1,0,-1),j,k,o,:]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[a,b,c,(1,2,3),...], lambda x: x[i,j,k,(1,2,3),...]) helper_test_op([(2,5,6,5,3,4)], lambda x: x[a,b,c,[[1],[2],[3]],...], lambda x: x[i,j,k,[[1],[2],[3]],...]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[a,[2,1,0],c,[-2,1,0],e], lambda x: x[i,[2,1,0],k,[-2,1,0],p]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[a,(2,1,0),c,(-2,1,0),e], lambda x: x[i,(2,1,0),k,(-2,1,0),p]) @slow_test def test_slice_fancy_indexing_tuple_indices(self): @@ -2845,11 +2843,10 @@ class TestOps(unittest.TestCase): @slow_test def test_slice_fancy_indexing_list_with_tensors(self): a,b,c,d,e,i,j,k,o,p = self._get_index_randoms() - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[a]], lambda x: x[[i]]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[a,1]], lambda x: x[[i,1]]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[a,[1,1]]], lambda x: x[[i,[1,1]]]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[a,(1,1)]], lambda x: x[[i,(1,1)]]) - helper_test_op([(2,5,6,5,3,4)], lambda x: x[[a,b,c,d,e]], lambda x: x[[i,j,k,o,p]]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[(a,)], lambda x: x[(i,)]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[(a,1)], lambda x: x[(i,1)]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[(a,(1,1))], lambda x: x[(i,(1,1))]) + helper_test_op([(2,5,6,5,3,4)], lambda x: x[(a,b,c,d,e)], lambda x: x[(i,j,k,o,p)]) def test_slice_fancy_indexing_errors(self): a = Tensor.ones(10,11,12) @@ -3040,7 +3037,6 @@ class TestOps(unittest.TestCase): pos_weight=torch.tensor(pos_weight)), lambda x,y: x.binary_crossentropy_logits(y.clip(0,1),pos_weight=Tensor(pos_weight))) - @unittest.skipIf(RANGEIFY > 1, "broken on RANGEIFY > 1, TODO: fix") def test_cross_entropy_class_probabilities(self): helper_test_op([(32,), (32,)], lambda x,y: torch.nn.functional.cross_entropy(x, y), lambda x,y: x.cross_entropy(y)) helper_test_op([(32,10), (32,10)], lambda x,y: torch.nn.functional.cross_entropy(x, y), lambda x,y: x.cross_entropy(y)) @@ -3164,8 +3160,8 @@ class TestOps(unittest.TestCase): helper_test_op([(32,10)], lambda x: x.masked_fill((x>0.1).detach(), -math.inf)) helper_test_op([(32,10)], lambda x: x.masked_fill((x<0.1).detach(), -math.inf)) - @unittest.skipIf(RANGEIFY and (getenv("MOCKGPU") or Device.DEFAULT == "PYTHON"), "very slow on MOCKGPU because reduce does not fold") - @unittest.skipIf(RANGEIFY and Device.DEFAULT == "WEBGPU", "webgpu runtime issue") + @unittest.skipIf((getenv("MOCKGPU") or Device.DEFAULT == "PYTHON"), "very slow on MOCKGPU because reduce does not fold") + @unittest.skipIf(Device.DEFAULT == "WEBGPU", "webgpu runtime issue") def test_masked_select(self): helper_test_op([(32, 10)], lambda x: x.masked_select(x>0.5), lambda x: x.masked_select(x>0.5), forward_only=True) helper_test_op([(32, 10)], lambda x: x.masked_select(torch.tensor(True)), lambda x: x.masked_select(Tensor(True)), forward_only=True) @@ -3181,6 +3177,7 @@ class TestOps(unittest.TestCase): def test_bitcast(self): helper_test_op([(3, 3)], lambda x: x.view(torch.int32), lambda x: x.bitcast(dtypes.int32), forward_only=True) + @unittest.skip("we have test_linalg, no need to test here. TODO: should be in torch backend tests") def test_svd(self): # test for tiny backend. real svd tests are in test_linalg A = torch.randn(5, 5) diff --git a/test/test_optim.py b/test/test_optim.py index 06d90e8670..40bbd01636 100644 --- a/test/test_optim.py +++ b/test/test_optim.py @@ -5,7 +5,6 @@ from tinygrad import Tensor, Device, dtypes from tinygrad.nn.optim import Adam, SGD, AdamW, Muon from tinygrad.helpers import CI from tinygrad.device import is_dtype_supported -from extra.torch_muon import SingleDeviceMuon as TorchMuon np.random.seed(1337) x_init = np.random.randn(1,4).astype(np.float32) @@ -58,12 +57,11 @@ class TestOptim(unittest.TestCase): def _test_sgd(self, steps, opts, atol, rtol): self._test_optim(SGD, torch.optim.SGD, steps, opts, atol, rtol) def _test_adam(self, steps, opts, atol, rtol): self._test_optim(Adam, torch.optim.Adam, steps, opts, atol, rtol) def _test_adamw(self, steps, opts, atol, rtol): self._test_optim(AdamW, torch.optim.AdamW, steps, opts, atol, rtol) - #TODO: use torch.muon when it comes out - def _test_muon(self, steps, opts, atol, rtol): self._test_optim(Muon, TorchMuon, steps, opts, atol, rtol) + def _test_muon(self, steps, opts, atol, rtol): self._test_optim(Muon, torch.optim.Muon, steps, opts, atol, rtol) def test_multistep_sgd_high_lr_teeny(self): self._test_sgd(2, {'lr': 1.1, 'teeny': True}, 1e-6, 1e-5) def test_multistep_adam_high_lr_teeny(self): self._test_adam(2, {'lr': 1.1, 'teeny': True}, 2e-4, 5e-4) - def test_multistep_muon_high_lr_teeny(self): self._test_muon(2, {'lr': 1.1, 'teeny': True}, 2e-4, 5e-4) + def test_multistep_muon_high_lr_teeny(self): self._test_muon(2, {'lr': 1.1, 'teeny': True}, 1e-2, 5e-4) def test_sgd(self): self._test_sgd(1, {'lr': 0.001}, 1e-6, 0) def test_sgd_high_lr(self): self._test_sgd(1, {'lr': 10}, 1e-6, 1e-5) @@ -87,27 +85,34 @@ class TestOptim(unittest.TestCase): def test_multistep_sgd_high_lr_nesterov_momentum_wd(self): self._test_sgd(10, {'lr': 9, 'momentum': 0.9, 'nesterov': True, 'weight_decay': 0.1}, 1e-5, 3e-4) - def test_muon(self): self._test_muon(1, {'lr': 0.001}, 1e-6, 0) - def test_muon_high_lr(self): self._test_muon(1, {'lr': 10}, 1e-6, 3e-4) - def test_muon_wd(self): self._test_muon(1, {'lr': 0.001, 'weight_decay': 0.01}, 1e-6, 0) - def test_muon_high_lr_wd(self): self._test_muon(1, {'lr': 10, 'weight_decay': 0.01}, 1e-6, 3e-4) + def test_muon(self): self._test_muon(1, {'lr': 0.001}, 1e-3, 0) + # TODO: disabled due to big atol + # def test_muon_high_lr(self): self._test_muon(1, {'lr': 10}, 1e-6, 3e-4) + def test_muon_wd(self): self._test_muon(1, {'lr': 0.001, 'weight_decay': 0.01}, 1e-3, 3e-4) + # TODO: disabled due to big atol + # def test_muon_high_lr_wd(self): self._test_muon(1, {'lr': 10, 'weight_decay': 0.01}, 1e-6, 5e-4) # NOTE: momentum set to 0.95 by default, nesterov set to True by default - def test_multistep_muon_momentum_wd(self): self._test_muon(10, {'lr': 0.001, 'weight_decay': 0.01}, 1e-5, 0) + def test_multistep_muon_momentum_wd(self): self._test_muon(10, {'lr': 0.001, 'weight_decay': 0.01}, 3e-3, 0) # ns defaults are numerically unstable, but it is tolerable in real training (see nsteps/nparam tests) - def test_multistep_muon_high_lr_momentum_wd(self): self._test_muon(10, {'lr': 10, 'weight_decay': 0.01}, 1e-1, 3e-4) - def test_multistep_muon_no_nesterov_momentum(self): self._test_muon(10, {'lr': 0.001, 'nesterov': False}, 1e-5, 0) - def test_multistep_muon_high_lr_no_nesterov_momentum(self): self._test_muon(10, {'lr': 10, 'nesterov': False}, 0.5e-1, 1e-1) + # TODO: disabled due to big atol + # def test_multistep_muon_high_lr_momentum_wd(self): self._test_muon(10, {'lr': 10, 'weight_decay': 0.01}, 1e-1, 3e-4) + def test_multistep_muon_no_nesterov_momentum(self): self._test_muon(10, {'lr': 0.001, 'nesterov': False}, 1e-3, 0) + # TODO: disabled due to big atol + # def test_multistep_muon_high_lr_no_nesterov_momentum(self): self._test_muon(10, {'lr': 10, 'nesterov': False}, 5e-2, 1e-1) - def test_muon_ns_steps(self): self._test_muon(1, {'lr': 0.001, 'ns_steps': 3}, 1e-6, 0) - def test_muon_high_lr_ns_steps(self): self._test_muon(1, {'lr': 10, 'ns_steps': 3}, 1e-5, 3e-4) - def test_muon_ns_params(self): self._test_muon(1, {'lr': 0.001,'ns_params': (2.0,-1.5,0.5)}, 1e-6, 0) - def test_muon_high_lr_ns_params(self): self._test_muon(1, {'lr': 10,'ns_params': (2.0,-1.5,0.5)}, 1e-5, 3e-4) + def test_muon_ns_steps(self): self._test_muon(1, {'lr': 0.001, 'ns_steps': 3}, 1e-4, 0) + # TODO: disabled due to big atol + # def test_muon_high_lr_ns_steps(self): self._test_muon(1, {'lr': 10, 'ns_steps': 3}, 1e-5, 3e-4) + def test_muon_ns_coefficients(self): self._test_muon(1, {'lr': 0.001,'ns_coefficients': (2.0,-1.5,0.5)}, 1e-5, 3e-4) + # TODO: disabled due to big atol + # def test_muon_high_lr_ns_coefficients(self): self._test_muon(1, {'lr': 10,'ns_coefficients': (2.0,-1.5,0.5)}, 1e-5, 3e-4) - def test_muon_momentum_wd_ns_steps_ns_params(self): - self._test_muon(10, {'lr': 0.001, 'momentum': 0.90, 'weight_decay': 0.01, 'ns_steps': 3, 'ns_params': (2.0,-1.5,0.5)}, 1e-5, 0) - def test_multistep_muon_high_lr_momentum_wd_ns_steps_ns_params(self): - self._test_muon(10, {'lr': 10, 'momentum': 0.90, 'weight_decay': 0.01, 'ns_steps': 3, 'ns_params': (2.0,-1.5,0.5)}, 1e-5, 3e-4) + def test_muon_momentum_wd_ns_steps_ns_coefficients(self): + self._test_muon(10, {'lr': 0.001, 'momentum': 0.90, 'weight_decay': 0.01, 'ns_steps': 3, 'ns_coefficients': (2.0,-1.5,0.5)}, 1e-4, 0) + # TODO: disabled due to big atol + # def test_multistep_muon_high_lr_momentum_wd_ns_steps_ns_coefficients(self): + # self._test_muon(10, {'lr': 10, 'momentum': 0.90, 'weight_decay': 0.01, 'ns_steps': 3, 'ns_coefficients': (2.0,-1.5,0.5)}, 1e-5, 3e-4) def test_adam(self): self._test_adam(1, {'lr': 0.001}, 1e-5, 0) def test_adam_high_lr(self): self._test_adam(1, {'lr': 10}, 1e-4, 1e-4) diff --git a/test/test_opts.py b/test/test_opts.py index 7bbdcfb61b..67f90ef1f1 100644 --- a/test/test_opts.py +++ b/test/test_opts.py @@ -1,6 +1,6 @@ import unittest from tinygrad import Tensor, Device -from tinygrad.helpers import CPU_LLVM +from tinygrad.helpers import CPU_LLVM, CPU_LVP from tinygrad.codegen.opt import Opt, OptOps from tinygrad.engine.realize import get_program @@ -12,7 +12,7 @@ class TestOpts(unittest.TestCase): out = (a+b).contiguous(arg=opts) s = out.schedule() self.assertEqual(s[-1].ast.arg.opts_to_apply, opts) - if Device.DEFAULT in {"CPU", "CL", "METAL"} and not CPU_LLVM: + if Device.DEFAULT in {"CPU", "CL", "METAL"} and not CPU_LLVM and not CPU_LVP: prg = get_program(s[-1].ast) self.assertIn('float4', prg.src) diff --git a/test/test_outerworld.py b/test/test_outerworld.py new file mode 100644 index 0000000000..5714cc0748 --- /dev/null +++ b/test/test_outerworld.py @@ -0,0 +1,74 @@ +import unittest +from tinygrad import Tensor, UOp +from tinygrad.uop.ops import AxisType, Ops + +class TestOuterworldReduce(unittest.TestCase): + def test_reduce(self): + x = Tensor.ones(5, 5).contiguous() + a = UOp.range(5, -1, AxisType.REDUCE) + out = x[a] + # TODO: syntax for this + t = Tensor(UOp(Ops.REDUCE, dtype=out.uop.dtype, src=(out.uop, a), arg=Ops.ADD)) + self.assertListEqual(t.tolist(), [5.,5.,5.,5.,5.]) + +class TestOuterworld(unittest.TestCase): + def test_range_plus_1(self): + t = Tensor.arange(100).reshape(10,10).realize() + + # passthrough ranges + a = UOp.range(10, -1) + sel = t[a] + 1 + assert sel.shape == (10,) + cpy = sel.reshape(1, 10).expand(a, 10).contiguous().realize() + + self.assertTrue((t+1==cpy).all().item()) + + def test_range_plus_1_transpose(self): + t = Tensor.arange(100).reshape(10,10).realize() + + # passthrough ranges + a = UOp.range(10, -1) + sel = t[a] + 1 + assert sel.shape == (10,) + cpy = sel.reshape(10, 1).expand(10, a).contiguous().realize() + + self.assertTrue(((t+1).T==cpy).all().item()) + + def test_flip_range(self): + t = Tensor.rand(10, 10).realize() + + # passthrough ranges + a = UOp.range(10, -1) + sel = t[9-a] + cpy = sel.reshape(1, 10).expand(a, 10).contiguous().realize() + + self.assertTrue((t.flip(0)==cpy).all().item()) + + def test_vmap(self): + def f(x): return x.sum(axis=0)*2 + + x = Tensor.ones(3, 10, 2).contiguous() + + # vmap across axis 0 + a = UOp.range(3, -1) + out = f(x[a]) + out = out.reshape(1, 2).expand(a, 2).contiguous() + + # 3x2 grid of 20 + out.realize() + self.assertTrue((out==20).all().item()) + + def test_fancy_vmap(self): + def f(x,y): return x+y + + x = Tensor.arange(9).reshape(3,3).contiguous() + y = Tensor.arange(9).reshape(3,3).contiguous() + + a = UOp.range(3, -1) + out = f(x[:,a], y[a,:]) + # TODO: this should support flatten + out = out.reshape(1, 3).expand(a, 3).contiguous().realize() + self.assertListEqual([[0,4,8],[4,8,12],[8,12,16]], out.tolist()) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/test_profiler.py b/test/test_profiler.py index 6143086ca0..2836aa4432 100644 --- a/test/test_profiler.py +++ b/test/test_profiler.py @@ -92,7 +92,9 @@ class TestProfiler(unittest.TestCase): # assert evs[i].st > evs[i-1].en, "timestamp not aranged" def test_profile_multidev(self): - d1 = Device[f"{Device.DEFAULT}:1"] + try: d1 = Device[f"{Device.DEFAULT}:1"] + except Exception as e: self.skipTest(f"second device not available {e}") + buf1 = Buffer(Device.DEFAULT, 2, dtypes.float, options=BufferSpec(nolru=True)).ensure_allocated() buf2 = Buffer(f"{Device.DEFAULT}:1", 2, dtypes.float, options=BufferSpec(nolru=True)).ensure_allocated() @@ -109,7 +111,8 @@ class TestProfiler(unittest.TestCase): assert evs[0].is_copy, "kernel should be copy" def test_profile_multidev_transfer(self): - d1 = Device[f"{Device.DEFAULT}:1"] + try: d1 = Device[f"{Device.DEFAULT}:1"] + except Exception as e: self.skipTest(f"second device not available {e}") buf1 = Tensor.randn(10, 10, device=f"{Device.DEFAULT}:0").realize() with helper_collect_profile(TestProfiler.d0, d1) as profile: @@ -122,7 +125,8 @@ class TestProfiler(unittest.TestCase): @unittest.skipIf(Device.DEFAULT in "METAL" or (MOCKGPU and Device.DEFAULT == "AMD"), "AMD mockgpu does not support queue wait interrupts") def test_profile_graph(self): - d1 = Device[f"{Device.DEFAULT}:1"] + try: d1 = Device[f"{Device.DEFAULT}:1"] + except Exception as e: self.skipTest(f"second device not available {e}") def f(a): x = (a + 1).realize() @@ -145,7 +149,9 @@ class TestProfiler(unittest.TestCase): @unittest.skipIf(CI or not issubclass(type(Device[Device.DEFAULT]), HCQCompiled), "skip CI") def test_dev_jitter_matrix(self): dev_cnt = 6 - devs = [Device[f"{Device.DEFAULT}:{i}"] for i in range(dev_cnt)] + try: devs = [Device[f"{Device.DEFAULT}:{i}"] for i in range(dev_cnt)] + except Exception as e: self.skipTest(f"multiple devices not available {e}") + for dev in devs: dev.synchronize() for dev in devs: dev._at_profile_finalize() @@ -193,6 +199,7 @@ class TestProfiler(unittest.TestCase): #self.assertLess(e1.st, e2.st) #self.assertGreater(e1.en-e1.st, e2.en-e2.st) + @unittest.skipIf(not CI, "this test is flaky locally") @unittest.skipUnless(Device[Device.DEFAULT].graph is not None, "graph support required") def test_graph(self): from test.test_graph import helper_alloc_rawbuffer, helper_exec_op, helper_test_graphs @@ -217,9 +224,9 @@ class TestProfiler(unittest.TestCase): Tensor.realize(a, b) profile, _ = helper_profile_filter_device(profile, TestProfiler.d0.device) exec_points = [e for e in profile if isinstance(e, ProfilePointEvent) and e.name == "exec"] - range_events = [e for e in profile if isinstance(e, ProfileRangeEvent)] + range_events = [e for e in profile if isinstance(e, ProfileRangeEvent) and not e.is_copy] self.assertEqual(len(exec_points), len(range_events), 2) - self.assertEqual(len(dedup(e.key for e in exec_points)), 1) + self.assertEqual(len(dedup(e.arg['name'] for e in exec_points)), 1) self.assertEqual(len(dedup(e.arg['metadata'] for e in exec_points)), 1) if __name__ == "__main__": diff --git a/test/test_quantize_onnx.py b/test/test_quantize_onnx.py index 005d978902..dba794cbc8 100644 --- a/test/test_quantize_onnx.py +++ b/test/test_quantize_onnx.py @@ -68,11 +68,11 @@ class TestQuantizeOnnxCPU(unittest.TestCase): import onnx # noqa: F401 # pylint: disable=unused-import except ImportError: raise unittest.SkipTest() - from tinygrad.frontend.onnx import OnnxRunner + from tinygrad.nn.onnx import OnnxRunner out_file = get_quantized_model(sz) run_onnx = OnnxRunner(out_file) inp = Tensor(np.random.uniform(size=(sz, sz)).astype(np.float32)) - with Context(DONT_REALIZE_EXPAND=1, QUANTIZE=1): + with Context(QUANTIZE=1): sched = run_onnx({"input":inp})["output"].schedule() ei = lower_schedule_item(sched[-2]) daccs = [u for u in ei.prg.p.uops if u.op is Ops.DEFINE_REG] @@ -86,8 +86,7 @@ class TestQuantizeOnnx(unittest.TestCase): # divide is ~1500-2000 without reduce_range, 750-900 with it out_file = get_quantized_model(sz) run_onnx_jit, _ = load_onnx_model(out_file) - with Context(DONT_REALIZE_EXPAND=1): - run_onnx_jit(input=Tensor(np.random.uniform(size=(sz, sz)).astype(np.float32))) + run_onnx_jit(input=Tensor(np.random.uniform(size=(sz, sz)).astype(np.float32))) def test_prequant_conv2d_1x1(self): X = Tensor(np.random.uniform(0, 255, size=(1, 32, 128, 128)).astype(np.uint8)) @@ -109,11 +108,10 @@ class TestQuantizeOnnx(unittest.TestCase): N = 512 X = Tensor(np.random.uniform(0, 255, size=(N,N)).astype(xi)) W = Tensor(np.random.uniform(0, 255, size=(N,N)).astype(wi)) - with Context(DONT_REALIZE_EXPAND=1): - # this divide is interesting and forces the accumulator to actually be an int - out = (X.cast("int").matmul(W.cast("int"))//1000).cast("int8") - opts = [Opt(op=OptOps.UPCAST, axis=1, arg=128), Opt(op=OptOps.UNROLL, axis=0, arg=4)] - sexec(out, opts) + # this divide is interesting and forces the accumulator to actually be an int + out = (X.cast("int").matmul(W.cast("int"))//1000).cast("int8") + opts = [Opt(op=OptOps.UPCAST, axis=1, arg=128), Opt(op=OptOps.UNROLL, axis=0, arg=4)] + sexec(out, opts) def test_prequant_gemm_handcode(self): src = """typedef int int128 __attribute__((aligned(512),vector_size(512))); @@ -203,14 +201,12 @@ class TestQuantizeOnnx(unittest.TestCase): def test_prequant_gemm_intacc(self, xi=np.uint8, wi=np.uint8, replace_src=None, N=512, clip=True, opts=None): X = Tensor(m1:=(np.random.uniform(0, 255, size=(N,N)).astype(xi))).realize() W = Tensor(m2:=(np.random.uniform(0, 255, size=(N,N)).astype(wi))).realize() - # ugh, it's so broken with those casts. need DONT_REALIZE_EXPAND=1 python3 test/test_quantize_onnx.py TestQuantizeOnnx.test_prequant tg_dtype = dtypes.int8 if xi == np.int8 else dtypes.uint8 - with Context(DONT_REALIZE_EXPAND=1): - out = (X.int().matmul(W.int())//1000) - if clip: out = out.clip(dtypes.min(tg_dtype),dtypes.max(tg_dtype)) - out = out.cast(tg_dtype) - opts = [Opt(op=OptOps.UPCAST, axis=1, arg=128), Opt(op=OptOps.UNROLL, axis=0, arg=4)] if opts is None else opts - sexec(out, opts, replace_src, run_count=1) + out = (X.int().matmul(W.int())//1000) + if clip: out = out.clip(dtypes.min(tg_dtype),dtypes.max(tg_dtype)) + out = out.cast(tg_dtype) + opts = [Opt(op=OptOps.UPCAST, axis=1, arg=128), Opt(op=OptOps.UNROLL, axis=0, arg=4)] if opts is None else opts + sexec(out, opts, replace_src, run_count=1) tout = out.numpy() mout = ((m1.astype(np.int32) @ m2.astype(np.int32)) // 1000) if clip: mout = mout.clip(dtypes.min(tg_dtype),dtypes.max(tg_dtype)) @@ -225,7 +221,6 @@ class TestQuantizeOnnx(unittest.TestCase): def test_prequant_gemv(self): N = 2048 - # ugh, it's so broken with those casts. need DONT_REALIZE_EXPAND=1 python3 test/test_quantize_onnx.py TestQuantizeOnnx.test_prequant X = Tensor(np.random.uniform(0, 255, size=(1,N)).astype(np.uint8)).realize() W = Tensor(np.random.uniform(0, 255, size=(N,N)).astype(np.uint8)).realize() #out = X.cast(dtypes.int) @ W.cast(dtypes.int) diff --git a/test/test_randomness.py b/test/test_randomness.py index 521e4b4c40..68de24add3 100644 --- a/test/test_randomness.py +++ b/test/test_randomness.py @@ -6,6 +6,7 @@ from tinygrad.helpers import getenv, CI, OSX from tinygrad.device import is_dtype_supported from tinygrad.engine.realize import lower_schedule, CompiledRunner from tinygrad.renderer.ptx import PTXRenderer +from tinygrad.renderer.nir import NIRRenderer from test.helpers import not_support_multi_device import numpy as np @@ -100,7 +101,7 @@ class TestRandomness(unittest.TestCase): np.testing.assert_allclose(jr, r) - @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "fails with PTX") + @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, (NIRRenderer, PTXRenderer)), "PTX and NIR use pointer arithmetic") def test_threefry_doesnt_use_long(self): for (_,ei) in lower_schedule(Tensor.rand(20).schedule()): if isinstance(ei.prg, CompiledRunner): diff --git a/test/test_rangeify.py b/test/test_rangeify.py index b976b5109b..ab6018cfe8 100644 --- a/test/test_rangeify.py +++ b/test/test_rangeify.py @@ -1,9 +1,56 @@ import unittest -from tinygrad import Tensor, nn -from tinygrad.helpers import RANGEIFY, Context, GlobalCounters -from tinygrad.uop.ops import UOp +from tinygrad import Tensor, nn, Device +from tinygrad.helpers import Context, GlobalCounters, CI, getenv, PCONTIG, DEBUG +from tinygrad.uop.ops import graph_rewrite, PatternMatcher, UPat, Ops +from tinygrad.codegen.opt import OptOps, Opt +from tinygrad.renderer.ptx import PTXRenderer +from tinygrad.renderer.nir import NIRRenderer + +@unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, (NIRRenderer, PTXRenderer)), "broken in LVP and PTX") +class TestDoubleMatmul(unittest.TestCase): + def setUp(self): + with Context(DEBUG=0): + self.a, self.b, self.c = [Tensor.randn(16, 16).contiguous().realize() for _ in range(3)] + self.ref = (self.a @ self.b @ self.c).realize() + + def _test(self, opts): + with Context(PCONTIG=2, DEBUG=max(2, DEBUG.value)): + out = (self.a @ self.b @ self.c).contiguous(arg=opts).realize() + + with Context(DEBUG=0): + err = (out-self.ref).square() + self.assertLess(err.max().item(), 1e-4) + self.assertLess(err.mean().item(), 1e-6) + + def test_baseline(self): self._test(()) + def test_upcast_0(self): self._test((Opt(OptOps.UPCAST, 0, 4),)) + def test_upcast_1(self): self._test((Opt(OptOps.UPCAST, 1, 4),)) + def test_upcast_2(self): self._test((Opt(OptOps.UPCAST, 2, 4),)) + def test_upcast_01(self): self._test((Opt(OptOps.UPCAST, 0, 4), Opt(OptOps.UPCAST, 1, 4))) + def test_upcast_01_mismatch(self): self._test((Opt(OptOps.UPCAST, 0, 2), Opt(OptOps.UPCAST, 1, 4))) + def test_upcast_02(self): self._test((Opt(OptOps.UPCAST, 0, 4), Opt(OptOps.UPCAST, 2, 4))) + def test_upcast_12(self): self._test((Opt(OptOps.UPCAST, 1, 4), Opt(OptOps.UPCAST, 2, 4))) + + def test_unroll_0(self): self._test((Opt(OptOps.UNROLL, 0, 4),)) + def test_unroll_1(self): self._test((Opt(OptOps.UNROLL, 1, 4),)) + def test_unroll_01(self): self._test((Opt(OptOps.UNROLL, 0, 4), Opt(OptOps.UNROLL, 1, 4))) + + def test_upcast_0_unroll_0(self): self._test((Opt(OptOps.UPCAST, 0, 4), Opt(OptOps.UNROLL, 0, 4))) + def test_upcast_1_unroll_0(self): self._test((Opt(OptOps.UPCAST, 1, 4), Opt(OptOps.UNROLL, 0, 4))) + def test_upcast_2_unroll_0(self): self._test((Opt(OptOps.UPCAST, 2, 4), Opt(OptOps.UNROLL, 0, 4))) + + def test_upcast_0_unroll_1(self): self._test((Opt(OptOps.UPCAST, 0, 4), Opt(OptOps.UNROLL, 1, 4))) + def test_upcast_1_unroll_1(self): self._test((Opt(OptOps.UPCAST, 1, 4), Opt(OptOps.UNROLL, 1, 4))) + def test_upcast_2_unroll_1(self): self._test((Opt(OptOps.UPCAST, 2, 4), Opt(OptOps.UNROLL, 1, 4))) + + def test_upcast_1_unroll_1_small(self): self._test((Opt(OptOps.UPCAST, 1, 2), Opt(OptOps.UNROLL, 1, 2))) + def test_upcast_1_unroll_1_rev(self): self._test((Opt(OptOps.UNROLL, 1, 2), Opt(OptOps.UPCAST, 1, 2))) + + def test_upcast_01_unroll_01(self): + self._test((Opt(OptOps.UPCAST, 0, 4), Opt(OptOps.UPCAST, 1, 4), Opt(OptOps.UNROLL, 0, 4), Opt(OptOps.UNROLL, 1, 4))) + def test_upcast_12_unroll_01(self): + self._test((Opt(OptOps.UPCAST, 1, 4), Opt(OptOps.UPCAST, 2, 4), Opt(OptOps.UNROLL, 0, 4), Opt(OptOps.UNROLL, 1, 4))) -@unittest.skipIf(RANGEIFY<1, "tests only for RANGEIFY") class TestRangeifyAssign(unittest.TestCase): def test_assign_permuted(self): A = Tensor.empty(4, 4, dtype='int') @@ -18,8 +65,99 @@ class TestRangeifyAssign(unittest.TestCase): self.assertListEqual(lst, lst3) self.assertListEqual(lst2, B.permute(1, 0).tolist()) +class TestRangeifyEdgeCase(unittest.TestCase): + def test_matmul_relu_cat(self): + a = Tensor.ones(100, 512).contiguous().realize() + c = Tensor.ones(1, 512).contiguous().realize() + cm = Tensor.ones(512, 512) + c = c @ cm + c = c.relu() + + res = Tensor.cat(a, c, dim=0) + self.assertEqual(res.numpy()[-1, :16].tolist(), [512] * 16) + +if getenv("BIG") > 2: + # llama 8B (8192) + BS, HEADS, SEQLEN, EMB = 4, 32, 8192, 128 +elif getenv("BIG") > 1: + # llama 8B + BS, HEADS, SEQLEN, EMB = 4, 32, 2048, 128 +elif getenv("BIG") > 0: + # bigger + BS, HEADS, SEQLEN, EMB = 4, 32, 128, 128 +else: + BS, HEADS, SEQLEN, EMB = 4, 2, 16, 8 + +def fa(): + Tensor.manual_seed(1337) + with Context(DEBUG=0): q,k,v = [Tensor.rand(BS, HEADS, SEQLEN, EMB).contiguous().realize() for _ in range(3)] + GlobalCounters.reset() + return q.scaled_dot_product_attention(k, v) + +def fa_bw(): + Tensor.manual_seed(1337) + with Context(DEBUG=0): + q,k,v = [Tensor.rand(BS, HEADS, SEQLEN, EMB).contiguous().realize().requires_grad_() for _ in range(3)] + attn_output = nn.Linear(HEADS*EMB, HEADS*EMB, bias=False) + attn_output.weight.requires_grad_().realize() + target = Tensor.rand(BS, SEQLEN, HEADS*EMB).contiguous().realize() + + GlobalCounters.reset() + attn = q.scaled_dot_product_attention(k, v).contiguous().contiguous_backward() + attn = attn.transpose(1, 2).reshape(BS, SEQLEN, -1) + out = attn_output(attn) + loss = (out - target).square().mean() + loss.backward() + #ret = [out, Tensor.stack(q.grad, k.grad, v.grad, dim=-1)] + #ret = [out, Tensor.stack(q.grad, k.grad, dim=-1), v.grad] + ret = [out, q.grad, k.grad, v.grad] + Tensor.realize(*ret) + return ret + +@unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, (NIRRenderer, PTXRenderer)), "broken in LVP and PTX") +class TestPcontig(unittest.TestCase): + def test_flash_attention_bw(self): + with Context(PCONTIG=max(2, PCONTIG.value), DEBUG=2): + grads = fa_bw() + print(f"{GlobalCounters.global_ops/1e9:.2f} GFLOPS") + + with Context(PCONTIG=0, DEBUG=2): + cmp_grads = fa_bw() + print(f"{GlobalCounters.global_ops/1e9:.2f} GFLOPS") + + with Context(DEBUG=0): + mses = [((x-y)**2).sum().item() for x,y in zip(grads, cmp_grads)] + mse = sum(mses) + print(f"mse: {mse}") + self.assertLessEqual(mse, 1e-6) + + def test_flash_attention(self, opts=None): + with Context(PCONTIG=2, DEBUG=max(2, DEBUG.value)): + ret = fa().realize() if opts is None else fa().contiguous(arg=opts).realize() + print(f"{GlobalCounters.global_ops/1e9:.2f} GFLOPS") + with Context(DEBUG=2): + cmp = fa().realize() + print(f"{GlobalCounters.global_ops/1e9:.2f} GFLOPS") + with Context(DEBUG=0): + mse = ((cmp-ret)**2).sum().item() + print(f"mse: {mse}") + self.assertLessEqual(mse, 1e-6) + + def test_flash_attention_opt(self): + opts = () + # columns in top matrix + opts += (Opt(OptOps.UPCAST, 0, 4),) + # columns in bottom matrix + opts += (Opt(OptOps.UPCAST, 3, 4),) + # rows in all the matrix + opts += (Opt(OptOps.UPCAST, 4, 4),) + self.test_flash_attention(opts) + +# *** non CI rangeify tests below this line *** + N = 256 +@unittest.skipIf(CI, "useless in CI, doesn't test anything") class TestRangeifyOpt(unittest.TestCase): def test_randperm(self): Tensor.randperm(10000).realize() @@ -55,7 +193,7 @@ class TestRangeifyOpt(unittest.TestCase): A = Tensor.empty(8,8,8,8).permute(1,0,3,2).flatten() A.sum().realize() -@unittest.skipIf(RANGEIFY<1, "tests only for RANGEIFY") +@unittest.skipIf(CI, "useless in CI, doesn't test anything") class TestRangeify(unittest.TestCase): def test_groupnorm(self): # ranges 1 and 3 are merging @@ -72,6 +210,7 @@ class TestRangeify(unittest.TestCase): ret = A.sum(axis=2).contiguous(arg=(1,)).sum(axis=1) ret.realize() + @unittest.skip("RANGEIFY=0 does nothing") def test_double_gemm_real(self): def go(): with Context(DEBUG=0): @@ -161,6 +300,12 @@ class TestRangeify(unittest.TestCase): w2 = Tensor.empty(12, 8, 3, 3) x.conv2d(w1).conv2d(w2).realize() + def test_resnet_conv2d(self): + x = Tensor.empty(1, 8, 32, 32) + w1 = Tensor.empty(8, 8, 3, 3) + w2 = Tensor.empty(8, 8, 1, 1) + x.conv2d(w1).conv2d(w2).realize() + def test_xception_conv2d(self): # NOTE: this fusion is bad, it's recomputing the inner many times x = Tensor.empty(1, 4, 32, 32) @@ -201,104 +346,58 @@ class TestRangeify(unittest.TestCase): out = blk._feed_forward(x) out.realize() - def test_flash_attention(self): - BS, HEADS, SEQLEN, EMB = 4, 2, 16, 8 - - # bigger - #BS, HEADS, SEQLEN, EMB = 4, 32, 1024, 64 - - # llama 8B - #BS, HEADS, SEQLEN, EMB = 4, 32, 2048, 128 - - def fa(): - Tensor.manual_seed(1337) - with Context(DEBUG=0): q,k,v = [Tensor.rand(BS, HEADS, SEQLEN, EMB).contiguous().realize() for _ in range(3)] - return q.scaled_dot_product_attention(k, v).realize() - - with Context(DEBUG=4): - GlobalCounters.reset() - ret = fa() - with Context(RANGEIFY=0): - with Context(DEBUG=2): - GlobalCounters.reset() - cmp = fa() - with Context(DEBUG=0): - mse = ((cmp-ret)**2).sum().item() - print(f"mse: {mse}") - self.assertLessEqual(mse, 1e-6) - # contiguous + reduce can support ranges? -@unittest.skip("okay to disable this for now") -@unittest.skipIf(RANGEIFY<1, "tests only for RANGEIFY") -class TestOuterworld(unittest.TestCase): - def test_passthrough_range(self): - t = Tensor.rand(10, 10).realize() +@unittest.skip("pm_rangeify no longer exists. test this in a different way") +class TestRangeifyPM(unittest.TestCase): + def setUp(self): self.base = Tensor.empty(10*10).reshape(10, 10).contiguous() + def assert_same(self, a, b): + def run_pm_rangeify(t:Tensor): + from tinygrad.schedule.rangeify import pm_rangeify, RangeifyContext + sink = t.uop.sink() + pm_realize = PatternMatcher([(UPat(Ops.CONTIGUOUS, name="x"), lambda x: x.replace(op=Ops.REALIZE))]) + sink = graph_rewrite(sink, pm_realize) + return graph_rewrite(sink, pm_rangeify, ctx=RangeifyContext()) + self.assertIs(run_pm_rangeify(a.contiguous()), run_pm_rangeify(b.contiguous())) - # passthrough ranges - a = UOp.range(10, -1) - sel = t[a] - cpy = sel.contiguous(a).realize() + def test_nothing_match(self): + a = self.base.pad(((0,0),(0,1))) + b = self.base.pad(((0,0),(0,1))) + self.assert_same(a, b) - self.assertTrue((t==cpy).all().item()) + def test_reshape_match(self): + a = self.base + b = self.base.reshape(100).reshape(10, 10) + self.assert_same(a, b) - def test_flip_range(self): - t = Tensor.rand(10, 10).realize() + def test_permute_reshape_match(self): + a = self.base + b = self.base.permute(1,0).reshape(100).reshape(10, 10).permute(1,0) + self.assert_same(a, b) - # passthrough ranges - a = UOp.range(10, -1) - sel = t[9-a] - cpy = sel.contiguous(a).realize() + def test_padded_permute_match(self): + a = self.base.pad(((0,0),(0,1))) + b = self.base.permute(1,0).pad(((0,1),(0,0))).permute(1,0) + self.assert_same(a, b) - self.assertTrue((t.flip(0)==cpy).all().item()) + @unittest.expectedFailure + def test_padded_reshape_match(self): + a = self.base.pad(((0,0),(0,1))) + b = self.base.reshape(100).reshape(10, 10).pad(((0,0),(0,1))) + self.assert_same(a, b) - def test_vmap(self): - def f(x): return x.sum(axis=0)*2 + @unittest.expectedFailure + def test_padded_permute_reshape_match(self): + a = self.base.pad(((0,0),(0,1))) + b = self.base.permute(1,0).reshape(100).reshape(10, 10).pad(((0,1),(0,0))).permute(1,0) + self.assert_same(a, b) - x = Tensor.ones(3, 10, 2).contiguous() - - # vmap across axis 0 - a = UOp.range(3, -1) - out = f(x[a]) - out = out.contiguous(a) - - # 3x2 grid of 20 - out.realize() - print(out.numpy()) - - @unittest.skip("opts don't work") - def test_triple_gemm(self): - x = Tensor.rand(1, 16).realize() - W = Tensor.rand(3, 16, 16).realize() - - manual = (x @ W[0] @ W[1] @ W[2]).contiguous().realize() - - a = UOp.range(3, -1) - x = x.assign(x @ W[a]) - out = x.contiguous(a)[-1].contiguous().realize() - - self.assertTrue((manual==out).all().item()) - - def test_setitem_pyrange(self): - with Context(DEBUG=0): - t = Tensor.rand(10).realize() - o = Tensor.empty(10) - GlobalCounters.reset() - for i in range(10): - o[i] = t[i] - o.realize() - self.assertTrue((t==o).all().item()) - - @unittest.skip("TODO: fix this") - def test_setitem(self): - with Context(DEBUG=0): - t = Tensor.rand(10).realize() - o = Tensor.empty(10) - GlobalCounters.reset() - i = UOp.range(10, -1) - o[i] = t[i] - o.contiguous(i).realize() - self.assertTrue((t==o).all().item()) + # why is this failing? + @unittest.expectedFailure + def test_cross_pad_match(self): + a = self.base.pad(((0,0),(0,1))).pad(((0,1),(0,0))) + b = self.base.pad(((0,1),(0,0))).pad(((0,0),(0,1))) + self.assert_same(a, b) if __name__ == '__main__': unittest.main() diff --git a/test/test_renderer_failures.py b/test/test_renderer_failures.py index 8092914be7..4baebae6b7 100644 --- a/test/test_renderer_failures.py +++ b/test/test_renderer_failures.py @@ -1,5 +1,4 @@ import unittest -from typing import List, cast import numpy as np from tinygrad.device import Buffer, Device, is_dtype_supported from tinygrad.dtype import dtypes, ConstType @@ -15,15 +14,15 @@ from tinygrad.tensor import Tensor, _to_np_dtype from tinygrad.codegen import full_rewrite from tinygrad.engine.realize import lower_schedule_item -def _test_uop_result(inputs:List[Tensor], stores:List[UOp], local_size=None): +def _test_uop_result(inputs:list[Tensor], stores:list[UOp], local_size=None): for x in inputs: x.realize() # NOTE: we only toposort the stores - uops: List[UOp] = [] - def _recursive_add(uop:UOp) -> List[UOp]: return flatten([_recursive_add(x) for x in uop.src])+[uop] + uops: list[UOp] = [] + def _recursive_add(uop:UOp) -> list[UOp]: return flatten([_recursive_add(x) for x in uop.src])+[uop] uops = dedup(flatten(_recursive_add(st) for st in stores)) outbufs = [Buffer(Device.DEFAULT, sz:=(1 if local_size is None else prod(local_size)), (dtype:=u.src[1].dtype), \ initial_value=np.zeros(sz, dtype=_to_np_dtype(dtype)).data) for u in uops if u.op is Ops.STORE] - inbufs = [cast(UOp,x.uop).base.buffer for x in inputs] + inbufs = [x.uop.base.buffer for x in inputs] src = Device[Device.DEFAULT].renderer.render(uops) ei = CompiledRunner(ProgramSpec(uops[-1].arg.name if uops[-1].arg is not None else "test", src, Device.DEFAULT, uops[-1], uops=uops, local_size=local_size)) @@ -35,7 +34,7 @@ def _setup_and_test_alu(alu_op:Ops, input_val:ConstType, *alu_src_uops:UOp): a = UOp(Ops.DEFINE_GLOBAL, dtype.ptr(), (), 0) b = UOp(Ops.DEFINE_GLOBAL, dtype.ptr(), (), 1) idx = UOp.const(dtypes.int, 0) - ld = UOp(Ops.LOAD, dtype, (b.index(idx),)) + ld = b.index(idx) alu = ld.alu(alu_op, *alu_src_uops) store = UOp.store(a.index(idx), alu) sink = UOp(Ops.SINK, dtypes.void, (store,)) @@ -47,7 +46,7 @@ class TestRendererFailures(unittest.TestCase): def test_gated_store_with_alu(self): a = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 0) gate_alu = (lidx0:=UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 4),), 'lidx0')).ne(0) - gated_alu_store = UOp(Ops.STORE, dtypes.void, (a.index(lidx0, gate_alu), UOp.const(dtypes.int, 1))) + gated_alu_store = UOp(Ops.STORE, dtypes.void, (a.index(lidx0.valid(gate_alu)), UOp.const(dtypes.int, 1))) sink = UOp(Ops.SINK, dtypes.void, (gated_alu_store,)) uops = full_rewrite(sink, Device[Device.DEFAULT].renderer) ret = _test_uop_result([], uops, local_size=[4, 1, 1])[0] @@ -58,7 +57,7 @@ class TestRendererFailures(unittest.TestCase): a = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 0) gate_alu_0 = (lidx0:=UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 4),), 'lidx0')).ne(0) gate_alu_1 = (lidx1:=UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 2),), 'lidx1')).ne(0) - gated_alu_store = UOp(Ops.STORE, dtypes.void, (a.index(lidx0+lidx1*4, gate_alu_0&gate_alu_1), UOp.const(dtypes.int, 1))) + gated_alu_store = UOp(Ops.STORE, dtypes.void, (a.index((lidx0+lidx1*4).valid(gate_alu_0&gate_alu_1)), UOp.const(dtypes.int, 1))) sink = UOp(Ops.SINK, dtypes.void, (gated_alu_store,)) uops = full_rewrite(sink, Device[Device.DEFAULT].renderer) ret = _test_uop_result([], uops, local_size=[4, 2, 1])[0] diff --git a/test/test_schedule.py b/test/test_schedule.py index 7f022966d0..5ac74c5d2c 100644 --- a/test/test_schedule.py +++ b/test/test_schedule.py @@ -2,20 +2,17 @@ # schedule confirms the right things are capable of fusing # NOTE: this has overlap with external_test_opt.py -import unittest +import unittest, functools import numpy as np -import functools from typing import cast from hypothesis import assume, given, settings, strategies as strat from tinygrad import nn, dtypes, Device, Tensor, Variable from tinygrad.device import is_dtype_supported from tinygrad.dtype import DType, ImageDType -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.uop.ops import UOp, Ops, GroupOp, UPat, graph_rewrite, track_rewrites -from tinygrad.uop.symbolic import symbolic_simple -from tinygrad.helpers import CI, DEBUG, SPLIT_REDUCEOP, GlobalCounters, Context, getenv, all_same, temp, RANGEIFY -from tinygrad.schedule.kernelize import merge_views, get_kernelize_map, Kernel +from tinygrad.uop.ops import UOp, Ops, GroupOp, UPat +from tinygrad.helpers import CI, DEBUG, SPLIT_REDUCEOP, GlobalCounters, Context, getenv, all_same, temp +from tinygrad.schedule.rangeify import get_rangeify_map, Kernel from tinygrad.engine.schedule import create_schedule_with_vars from tinygrad.engine.realize import CompiledRunner, run_schedule, lower_schedule @@ -28,12 +25,11 @@ def check_schedule(t:Tensor|list[Tensor]|UOp, allowed:int, to_prerealize:list[Te else: assert isinstance(t, UOp), f"can't schedule {t}" sink = UOp.sink(t) if t.op is not Ops.SINK else t - becomes_map = get_kernelize_map(sink) + becomes_map = get_rangeify_map(sink) sched, _ = create_schedule_with_vars(sink.substitute(becomes_map)) # test lowering all the ScheduleItems to ExecItems kernel_cnt = len([si for si,ei in lower_schedule(sched.copy()) if isinstance(ei.prg, CompiledRunner) or not filter_sink]) if kernel_cnt != allowed: - if RANGEIFY: return sched # allow different kernel count, TODO: fix the asserts print(f"SCHEDULE ISSUE, expecting {allowed} got {len(sched)}") if DEBUG >= 3: for i,s in enumerate(sched): @@ -42,13 +38,10 @@ def check_schedule(t:Tensor|list[Tensor]|UOp, allowed:int, to_prerealize:list[Te raise KernelCountException(f"{kernel_cnt} != {allowed}") return sched -def expect_rangeify_fails(fxn): return (unittest.expectedFailure if RANGEIFY else (lambda f:f))(fxn) -def expect_nonrangeify_fails(fxn): return (unittest.expectedFailure if not RANGEIFY else (lambda f:f))(fxn) - def _realize_weights(m): for p in nn.state.get_parameters(m): p.realize() -def _test_conv2d(allowed:int, dtype:DType=dtypes.float, **kwargs): +def _test_conv2d(allowed:int, dtype:DType=dtypes.float): old_default_float, dtypes.default_float = dtypes.default_float, dtype dtypes.default_float = dtype Tensor.manual_seed(0) @@ -57,7 +50,7 @@ def _test_conv2d(allowed:int, dtype:DType=dtypes.float, **kwargs): w = Tensor.uniform(16, CIN, 3, 3, requires_grad=True).realize() ret = Tensor.conv2d(img, w).relu().mean().backward() dtypes.default_float = old_default_float - with Context(**kwargs): s = Tensor.schedule(ret, img.grad, w.grad) + s = Tensor.schedule(ret, img.grad, w.grad) run_schedule(s.copy()) cnt = len([si for si in s if si.ast.op is Ops.SINK]) assert cnt == allowed, f"expected {allowed} kernels, got {cnt}" @@ -70,9 +63,6 @@ def _test_conv2d(allowed:int, dtype:DType=dtypes.float, **kwargs): np.testing.assert_allclose(img.grad.numpy(), ref_img.grad.detach().numpy(), atol=1e-6 if dtype == dtypes.float else 1e-2) np.testing.assert_allclose(w.grad.numpy(), ref_w.grad.detach().numpy(), atol=1e-6 if dtype == dtypes.float else 1e-2) -@track_rewrites(name=True) -def schedule_graph_rewrite(big_sink:UOp): return get_kernelize_map(big_sink)[big_sink] - class TestSchedule(unittest.TestCase): def test_arange_avgpool2d(self, kcount=1): x = Tensor.arange(25).reshape(1,1,5,5).cast(dtypes.float32) @@ -85,37 +75,33 @@ class TestSchedule(unittest.TestCase): np.testing.assert_allclose(t.numpy(), torch_out) def test_arange_avgpool2d_fused_noopt(self): - with Context(FUSE_ARANGE=1, NOOPT=1): self.test_arange_avgpool2d(kcount=1) + with Context(NOOPT=1): self.test_arange_avgpool2d(kcount=1) # linearizer error @unittest.skip("recursion error no longer raised") @unittest.skipUnless(Device[Device.DEFAULT].renderer.supports_float4, "needs supports_float4 to fail") def test_arange_avgpool2d_fused(self): with self.assertRaises(RecursionError): - with Context(FUSE_ARANGE=1, NOOPT=0): self.test_arange_avgpool2d(kcount=1) + with Context(NOOPT=0): self.test_arange_avgpool2d(kcount=1) # when we're fusing a reduce, all ReduceOps must have the same N in the dimensions # all permutes, reshapes, expands and shrinks push through the reduce def test_arange_sum(self): a = Tensor.arange(6).reshape(3, 2).sum(axis=1) - with Context(FUSE_ARANGE=1): - run_schedule(check_schedule(a, 1)) + run_schedule(check_schedule(a, 1)) self.assertListEqual(a.tolist(), [1, 5, 9]) def test_arange_sum_alt(self): a = (Tensor.arange(5).reshape(1,5).expand(6,5)*Tensor(2)).reshape(1,6,5).sum(axis=2) - with Context(FUSE_ARANGE=1): - run_schedule(check_schedule(a, 1)) + run_schedule(check_schedule(a, 1)) np.testing.assert_equal(a.numpy(), 20) def test_permute_arange(self): a = Tensor.arange(6).reshape(6, 1, 1).permute(2, 0, 1).sum(axis=1) - with Context(FUSE_ARANGE=1): - run_schedule(check_schedule(a, 1)) + run_schedule(check_schedule(a, 1)) self.assertListEqual(a.tolist(), [[15]]) @unittest.skipIf(Device.DEFAULT == "CPU", "devices must mismatch") - @expect_rangeify_fails def test_error_on_device_mismatch(self): a = Tensor.empty(10) b = Tensor.empty(10, device="CPU") @@ -123,15 +109,13 @@ class TestSchedule(unittest.TestCase): with self.assertRaisesRegex(RuntimeError, "all buffers must be on the same device"): check_schedule(c, 1) @unittest.skipIf(Device.DEFAULT == "CPU", "devices must mismatch") - @expect_rangeify_fails def test_error_on_device_mismatch_alt(self): a = Tensor.empty(10) b = Tensor.empty((1,), device="CPU").expand(10).contiguous() c = a+b - with self.assertRaisesRegex(RuntimeError, "all buffers must be on the same device"): check_schedule(c, 2 if RANGEIFY else 1) + with self.assertRaisesRegex(RuntimeError, "all buffers must be on the same device"): check_schedule(c, 2) - @unittest.skipUnless(is_dtype_supported(dtypes.half) and getenv("CAST_AFTER_EXPAND"), "need half and CAST_AFTER_EXPAND=1") - @unittest.skip("CAST_AFTER_EXPAND is not supported") + @unittest.skipUnless(is_dtype_supported(dtypes.half), "need half") def test_expand_buffer_before_cast(self): a = Tensor.randn(4, 2, 1).realize().permute((1, 0, 2)) b = a.cast(dtypes.half).expand((2, 4, 4))+2 @@ -141,8 +125,7 @@ class TestSchedule(unittest.TestCase): def test_indexing_scalars_simple(self): X = Tensor.randn(2, 2).realize() xt = X[Tensor(1)][Tensor(0)] - with Context(FUSE_ARANGE=1): - run_schedule(check_schedule(xt, 2)) + run_schedule(check_schedule(xt, 1)) np.testing.assert_equal(xt.numpy(), X.numpy()[1][0]) @unittest.skipIf(CI and Device.DEFAULT == "NV", "crashes on NV CI") @@ -162,32 +145,30 @@ class TestSchedule(unittest.TestCase): assume(a1 children but should still fuse # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 3)) + run_schedule(check_schedule(out, 2)) np.testing.assert_allclose(out.numpy(), \ (c.numpy()*a.numpy().sum(axis=-1,keepdims=True)).sum(-1) + (b.numpy()*a.numpy().sum(axis=-1,keepdims=True)).sum(-1), atol=1e-4, rtol=1e-4) @@ -1124,8 +1101,7 @@ class TestSchedule(unittest.TestCase): x = Tensor.randn(4, 32).realize() y = Tensor.randn(4, 32).realize() out = y.sum(axis=-1) + x.sum(axis=-1) - # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) np.testing.assert_allclose(out.numpy(), y.numpy().sum(axis=-1) + x.numpy().sum(axis=-1), atol=1e-4, rtol=1e-4) def test_multireduce_fusion_sequential(self): @@ -1142,7 +1118,7 @@ class TestSchedule(unittest.TestCase): y = Tensor.randn(4, 32).realize() out = x.std(-1) + y.std(-1) # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 4)) + run_schedule(check_schedule(out, 3)) np.testing.assert_allclose(out.numpy(), x.numpy().std(axis=-1, ddof=1) + y.numpy().std(axis=-1, ddof=1), atol=1e-4, rtol=1e-4) def test_multireduce_diffops_sequential(self): @@ -1158,8 +1134,7 @@ class TestSchedule(unittest.TestCase): x = Tensor.randn(4, 32).realize() y = Tensor.randn(4, 32).realize() out = x.sum(-1) + y.max(-1) - # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) np.testing.assert_allclose(out.numpy(), x.numpy().sum(axis=-1) + y.numpy().max(axis=-1), atol=1e-4, rtol=1e-4) def test_multireduce_fusion_sequential_and_parallel(self): @@ -1171,7 +1146,7 @@ class TestSchedule(unittest.TestCase): np_mu = (x.numpy() - x.numpy().max(axis=-1, keepdims=True)).mean(axis=-1, keepdims=True) + \ (y.numpy() - y.numpy().max(axis=-1, keepdims=True)).mean(axis=-1, keepdims=True) # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 6)) + run_schedule(check_schedule(out, 5)) np.testing.assert_allclose(out[0].numpy(), np.sqrt(np.square(x.numpy() - np_mu).sum(-1)/x.shape[-1]), atol=1e-4, rtol=1e-4) np.testing.assert_allclose(out[1].numpy(), np.sqrt(np.square(y.numpy() - np_mu).sum(-1)/y.shape[-1]), atol=1e-4, rtol=1e-4) @@ -1180,8 +1155,7 @@ class TestSchedule(unittest.TestCase): a,b = Tensor.randn(4, 64).realize(), Tensor.rand(64,8).realize() c,d = Tensor.randn(4, 64).realize(), Tensor.rand(64,8).realize() out = a@b + c@d - # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) np.testing.assert_allclose(out.numpy(), a.numpy()@b.numpy() + c.numpy()@d.numpy(), atol=1e-4, rtol=1e-4) def test_softmax_fusion(self): @@ -1193,15 +1167,14 @@ class TestSchedule(unittest.TestCase): np.testing.assert_allclose(out.numpy(), expected, atol=1e-4, rtol=1e-4) @unittest.skipUnless(is_dtype_supported(dtypes.half), "need half") - @expect_rangeify_fails def test_softmax_upcast(self): # input half, softmax in float Tensor.manual_seed(0) x = Tensor.randn(4, 12, 64, 64, dtype=dtypes.half).realize() out = x.softmax(dtype=dtypes.float) sched = out.schedule() - self.assertEqual(len(sched), 2 if RANGEIFY else 3) - self.assertEqual(sched[0].bufs[0].dtype, dtypes.half) + self.assertEqual(len(sched), 3) + self.assertEqual(sched[0].bufs[0].dtype, dtypes.float) # input float, softmax in float Tensor.manual_seed(0) @@ -1233,12 +1206,12 @@ class TestSchedule(unittest.TestCase): def test_scaled_dot_product_attention_fusion(self): x, y, z, m = (Tensor.empty(32, 8, 16, 16) for _ in range(4)) out = Tensor.scaled_dot_product_attention(x, y, z, attn_mask=m) - check_schedule(out, 5) + check_schedule(out, 4) def test_scaled_dot_product_attention_causal_fusion(self): x, y, z = (Tensor.empty(32, 8, 16, 16) for _ in range(3)) out = Tensor.scaled_dot_product_attention(x, y, z, is_causal=True) - check_schedule(out, 5) + check_schedule(out, 4) def test_adam_step_fusion(self): with Tensor.train(): @@ -1247,7 +1220,7 @@ class TestSchedule(unittest.TestCase): _realize_weights(layer) opt = nn.optim.Adam(nn.state.get_parameters(layer), lr=1e-4) layer(x).relu().sum().backward() - check_schedule(opt.schedule_step(), 16) + check_schedule(opt.schedule_step(), 19) def test_adam_conv_fuse(self): with Tensor.train(): @@ -1257,7 +1230,7 @@ class TestSchedule(unittest.TestCase): opt = nn.optim.Adam(nn.state.get_parameters(c1), lr=1e-4) opt.zero_grad() c1(img).relu().sum().backward() - check_schedule(opt.schedule_step(), 16) + check_schedule(opt.schedule_step(), 19) def test_adam_2convs_fuse(self): with Tensor.train(): @@ -1268,7 +1241,7 @@ class TestSchedule(unittest.TestCase): opt = nn.optim.Adam(nn.state.get_parameters([c1, c2]), lr=1e-4) opt.zero_grad() c2(c1(img).relu()).relu().sum().backward() - check_schedule(opt.schedule_step(), 20) + check_schedule(opt.schedule_step(), 21) def test_sgd_conv_fuse(self): with Tensor.train(): @@ -1278,7 +1251,7 @@ class TestSchedule(unittest.TestCase): opt = nn.optim.SGD(nn.state.get_parameters(c1)) opt.zero_grad() c1(img).relu().sum().backward() - check_schedule(opt.schedule_step(), 3) + check_schedule(opt.schedule_step(), 5) # TODO: 3? def test_sgd_2convs_fuse(self): with Tensor.train(): @@ -1314,7 +1287,7 @@ class TestSchedule(unittest.TestCase): opt = nn.optim.SGD(nn.state.get_parameters([c1, c2, c3, c4])) opt.zero_grad() c4(c3(c2(c1(img).relu()).relu()).relu()).relu().sum().backward() - check_schedule(opt.schedule_step(), 17) + check_schedule(opt.schedule_step(), 15) def test_sgd_4convs_fuse_conv_bw(self): with Tensor.train(): @@ -1327,50 +1300,7 @@ class TestSchedule(unittest.TestCase): opt = nn.optim.SGD(nn.state.get_parameters([c1, c2, c3, c4])) opt.zero_grad() c4(c3(c2(c1(img).relu()).relu()).relu()).relu().sum().backward() - with Context(FUSE_CONV_BW=1): check_schedule(opt.schedule_step(), 14) - - @unittest.skipUnless(is_dtype_supported(dtypes.half), "need half") - @expect_rangeify_fails - def test_prefer_half_buffer(self): - x = Tensor.ones(4).contiguous().realize() - # y = Tensor.ones(4).contiguous().realize() - z = Tensor.ones(4, 4).contiguous().realize() - - # should not create extra kernel if output will be realized anyways - dummy = x.sum().half().float() - check_schedule(dummy, 1) - dummy = x.sum().half().float().contiguous() + 1 - check_schedule(dummy, 2) - - # shared between two outputs - shared = x.sum().half().float() - a = shared * 2 - b = shared * 3 - sched = check_schedule([a, b], 3) - # store reduceop in half - self.assertEqual(sched[0].bufs[0].dtype, dtypes.half) - # fuse cast with the child kernel - self.assertEqual(sched[1].bufs[0].dtype, dtypes.float) - self.assertEqual(sched[2].bufs[0].dtype, dtypes.float) - - # reduce - a = z.sum(axis=0).half().float().sum(axis=0) - sched = check_schedule(a, 2) - self.assertEqual(sched[0].bufs[0].dtype, dtypes.half) - self.assertEqual(sched[1].bufs[0].dtype, dtypes.float) - - # expand - # expand will realize just after the .float(), so requires change to realize-before-expand - # normal = (x.sum().half().float().reshape(1) * y).sum() - # sched = check_schedule(normal, 2) - # for si in sched[:-1]: assert all(out.dtype == dtypes.half for out in si.outputs[:-1]) - - # parallel reduce - # a = x.sum().half().float() * y.sum().half().float() - # b = a + 1 - # c = a + 2 - # sched = check_schedule([b, c], 4) - # doesn't store either in half because it doesn't chase + check_schedule(opt.schedule_step(), 15) def test_reduce_simple_chase(self): a = Tensor.empty(4, 4, 4) @@ -1419,7 +1349,7 @@ class TestSchedule(unittest.TestCase): c = Tensor.empty(16, ) r = a.sum(1) + c d = r[:4] * b - check_schedule(d, 2) + check_schedule(d, 1) def test_multireduce_push_shrink_chase(self): Tensor.manual_seed(0) @@ -1429,22 +1359,20 @@ class TestSchedule(unittest.TestCase): d = Tensor.randn(16, 16).realize() r = a.sum(1) + c out = r[:4] * b + d.sum(1)[:4] - # schedule = check_schedule(out, 2) - schedule = check_schedule(out, 3) + schedule = check_schedule(out, 1) run_schedule(schedule) np.testing.assert_allclose(out.numpy(), (a.numpy().sum(1) + c.numpy())[:4] * b.numpy() + d.numpy().sum(1)[:4], atol=1e-4, rtol=1e-4) def test_midreduce_nochase(self): a = Tensor.empty(16, 16) b = (a.sum(0) + a.max(1)) + 2 - check_schedule(b, 2) + check_schedule(b, 1) def test_multireduce_midreduce_nochase(self): Tensor.manual_seed(0) a = Tensor.randn(16, 16).realize() b = (a.sum(0)+a.max(0) + a.max(1)+a.sum(1)) + 2 - # schedule = check_schedule(b, 2) - schedule = check_schedule(b, 4) + schedule = check_schedule(b, 1) run_schedule(schedule) np.testing.assert_allclose(b.numpy(), a.numpy().sum(0)+a.numpy().max(0) + a.numpy().max(1)+a.numpy().sum(1)+2, atol=1e-4, rtol=1e-4) @@ -1456,7 +1384,7 @@ class TestSchedule(unittest.TestCase): c = a.sum() + 2 d = (a.sum() - b.sum()) * 4 # run_schedule(check_schedule([c, d], 1)) - run_schedule(check_schedule([c, d], 3)) + run_schedule(check_schedule([c, d], 2)) np.testing.assert_allclose(c.numpy(), a.numpy().sum()+2, atol=1e-4, rtol=1e-4) np.testing.assert_allclose(d.numpy(), (a.numpy().sum() - b.numpy().sum()) * 4, atol=1e-4, rtol=1e-4) @@ -1482,7 +1410,7 @@ class TestSchedule(unittest.TestCase): e = c * d f = b.sum() - e # run_schedule(check_schedule([c, d, e, f], 1)) - run_schedule(check_schedule([c, d, e, f], 2 if RANGEIFY else 5)) + run_schedule(check_schedule([c, d, e, f], 4)) np.testing.assert_allclose(c.numpy(), c_np:=a.numpy().sum()+2, atol=1e-4, rtol=1e-4) np.testing.assert_allclose(d.numpy(), d_np:=a.numpy().sum()*2, atol=1e-4, rtol=1e-4) np.testing.assert_allclose(e.numpy(), e_np:=c_np*d_np, atol=1e-4, rtol=1e-4) @@ -1497,7 +1425,7 @@ class TestSchedule(unittest.TestCase): e = c * d f = (b - d).sum() - e # run_schedule(check_schedule([c, d, e, f], 1)) - run_schedule(check_schedule([c, d, e, f], 5)) + run_schedule(check_schedule([c, d, e, f], 4)) np.testing.assert_allclose(c.numpy(), c_np:=a.numpy().sum()+2, atol=1e-4, rtol=1e-4) np.testing.assert_allclose(d.numpy(), d_np:=a.numpy().sum()*2, atol=1e-4, rtol=1e-4) np.testing.assert_allclose(e.numpy(), e_np:=c_np*d_np, atol=1e-4, rtol=1e-4) @@ -1516,8 +1444,7 @@ class TestSchedule(unittest.TestCase): a = Tensor.randn(3, 4, 5).realize() b = Tensor.randn(3, 4, 5).realize() out = (a.pad(((0, 1), (0, 1), (0, 1)), value=1.0).sum(keepdim=True)+b.pad(((0, 1), (0, 1), (0, 1)), value=1.0).sum()).contiguous() - # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) np.testing.assert_allclose(out.numpy(), np.pad(a.numpy(), ((0, 1), (0, 1), (0, 1)), constant_values=1.0).sum(keepdims=True) + \ np.pad(b.numpy(), ((0, 1), (0, 1), (0, 1)), constant_values=1.0).sum(), atol=1e-4, rtol=1e-4) @@ -1525,7 +1452,7 @@ class TestSchedule(unittest.TestCase): Tensor.manual_seed(0) a = Tensor.rand(3, 4, 5).realize() out = a.log2().pad(((0, 1), (0, 1), (0, 1)), value=1.0).sum().contiguous() - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) np.testing.assert_allclose(out.numpy(), np.pad(np.log2(a.numpy()), ((0, 1), (0, 1), (0, 1)), constant_values=1.0).sum(), atol=1e-5, rtol=1e-6) def test_multireduce_pad_reduce_unsafe(self): @@ -1534,9 +1461,9 @@ class TestSchedule(unittest.TestCase): b = Tensor.randn(3, 4, 5).abs().realize() out = (a.log2().pad(((0, 1), (0, 1), (0, 1)), value=1.0).sum()+b).abs().log2().pad(((0, 1), (0, 1), (0, 1)), value=1.0).sum().contiguous() # run_schedule(check_schedule(out, 1)) - run_schedule(check_schedule(out, 4)) + run_schedule(check_schedule(out, 2)) np.testing.assert_allclose(out.numpy(), np.pad(np.log2(np.abs(np.pad(np.log2(a.numpy()), ((0, 1), (0, 1), (0, 1)), constant_values=1.0).sum() + \ - b.numpy())), ((0, 1), (0, 1), (0, 1)), constant_values=1.0).sum(), atol=3e-4, rtol=1e-6) + b.numpy())), ((0, 1), (0, 1), (0, 1)), constant_values=1.0).sum(), atol=3e-4, rtol=1e-5) def test_shrink_pad_safe(self): a = Tensor.ones((3, )).contiguous().realize() @@ -1548,7 +1475,7 @@ class TestSchedule(unittest.TestCase): def test_shrink_pad_unsafe(self): a = Tensor.ones((3, )).contiguous().realize() out = a.exp2().shrink(((0, 1),)).pad(((0, 1),)).contiguous() - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) np.testing.assert_equal(out.numpy(), [2, 0]) def test_base_change_shrink_pad(self): @@ -1556,7 +1483,7 @@ class TestSchedule(unittest.TestCase): b = a.exp2() c = b[:-1, :-1] d = c.pad(((0, 1), (0, 1))) * 2 - run_schedule(check_schedule(d, 2)) + run_schedule(check_schedule(d, 1)) np.testing.assert_equal(d.numpy(), np.pad(np.exp2(a.numpy())[:-1, :-1], ((0, 1), (0, 1)))*2) def test_base_change_expand_pad(self): @@ -1564,25 +1491,36 @@ class TestSchedule(unittest.TestCase): b = a.exp2() c = b[:, None, :] d = c.pad(((0, 0), (1, 1), (0, 0))) * 2 - run_schedule(check_schedule(d, 2)) + run_schedule(check_schedule(d, 1)) np.testing.assert_equal(d.numpy(), np.pad(np.exp2(a.numpy())[:, None, :], ((0, 0), (1, 1), (0, 0)))*2) def test_fuse_arange_pad_replicate_mode(self): x = Tensor.empty(3,3,3,3, requires_grad=True) y = x.pad((-1,2,2,-1), mode="replicate") dx = y.sum().gradient(x)[0] - with Context(FUSE_ARANGE=1): - sched = check_schedule(dx, 3) + sched = check_schedule(dx, 1) run_schedule(sched) np.testing.assert_allclose(dx.numpy(), [[[[0.,3.,9.],[0,1.,3.],[0.,0.,0.]]]*3]*3) + def test_fuse_arange_avg_pool2d_ceil_mode(self): + x = Tensor.avg_pool2d(Tensor.empty(1,1,6,6), kernel_size=(3,3), padding=1, stride=3, ceil_mode=True) + sched = check_schedule(x, 1) + self.assertEqual(len([x for x in sched[0].ast.backward_slice_with_self if x.op is Ops.REDUCE]), 1) + + def test_fuse_arange_pad_circular_mode_bw(self): + x = Tensor.empty(1,1,5,5,5) + out = x.pad((1,2,3,5,1,2), mode="circular") + g = out.sum().gradient(x)[0] + sched = check_schedule(g, 1) + self.assertEqual(len([x for x in sched[0].ast.backward_slice_with_self if x.op is Ops.REDUCE]), 0) + # TODO like openpilot with imagef @unittest.skipUnless(is_dtype_supported(dtypes.half), "need half") def test_base_change_expand_expand(self): a = Tensor.ones(4, 4).contiguous().realize() b = a.cast(dtypes.half).expand(2, 4, 4) c = b.cast(dtypes.int).expand(2, 2, 4, 4) - run_schedule(check_schedule(c, 2)) + run_schedule(check_schedule(c, 1)) np.testing.assert_equal(c.numpy(), np.ones(((2, 2, 4, 4)), dtype=np.int32)) def test_base_change_pad_expand(self): @@ -1590,7 +1528,7 @@ class TestSchedule(unittest.TestCase): b = Tensor.full((4, 4), 2.).contiguous().realize() c = (a + b).pad(((1, 1), (1, 1))) d = c.cast(dtypes.int).expand((2, 6, 6)) * 4 - run_schedule(check_schedule(d, 2)) + run_schedule(check_schedule(d, 1)) c_np = np.pad((np.full((4, 4), 2., dtype=np.float32) + np.full((4, 4), 1., dtype=np.float32)), ((1, 1), (1, 1)), constant_values=0.0) np.testing.assert_equal(d.numpy(), np.broadcast_to(c_np.astype(np.half), (2, *c_np.shape)) * 4) @@ -1632,15 +1570,21 @@ class TestSchedule(unittest.TestCase): out = x.argmax(1) run_schedule(check_schedule(out, 2)) - def test_conv2d(self): _test_conv2d(5 if RANGEIFY else 7) - def test_conv2d_fused(self): _test_conv2d(5 if RANGEIFY else 5, FUSE_CONV_BW=1) + def test_conv2d(self): _test_conv2d(5 if SPLIT_REDUCEOP else 4) + def test_conv2d_fused(self): _test_conv2d(5 if SPLIT_REDUCEOP else 4) + + def test_resnet_conv2d(self): + x = Tensor.empty(1, 8, 32, 32) + w1 = Tensor.empty(8, 8, 3, 3) + w2 = Tensor.empty(8, 8, 1, 1) + out = x.conv2d(w1).conv2d(w2) + check_schedule(out, 2) @unittest.skipUnless(is_dtype_supported(dtypes.half) and is_dtype_supported(dtypes.ulong), "need half and ulong") - def test_conv2d_half(self): _test_conv2d(5 if RANGEIFY else 7, dtype=dtypes.half) + def test_conv2d_half(self): _test_conv2d(5 if SPLIT_REDUCEOP else 4, dtype=dtypes.half) @unittest.skipUnless(is_dtype_supported(dtypes.half), "need half") @unittest.skipIf(Device.DEFAULT == "WEBGPU", "Causes other tests to fail") - @unittest.skipIf(not RANGEIFY, "passes on RANGEIFY") - def test_conv2d_fused_half(self): _test_conv2d(5, dtype=dtypes.half) + def test_conv2d_fused_half(self): _test_conv2d(5 if SPLIT_REDUCEOP else 4, dtype=dtypes.half) def test_schedule_mem_used(self): base = GlobalCounters.mem_used @@ -1690,7 +1634,7 @@ class TestSchedule(unittest.TestCase): self._test_fusion([(4, 4), (1, 4)], lambda a,b:a.sum(1).reshape(b.shape)+b, 1) def test_late_fusion_post_permute(self): - self._test_fusion([(4, 6, 4), (4, 4, 1)], lambda a,b:a.sum(1, keepdim=True).permute((2, 0, 1))+b, 2) + self._test_fusion([(4, 6, 4), (4, 4, 1)], lambda a,b:a.sum(1, keepdim=True).permute((2, 0, 1))+b, 1) def test_late_fusion_double_transpose(self): self._test_fusion([(32, 16, 1)], @@ -1699,15 +1643,14 @@ class TestSchedule(unittest.TestCase): def test_late_fusion_post_expand(self): self._test_fusion([(32, 32)], lambda a:a-a.sum(1), 2) - @expect_rangeify_fails def test_cast_padded_view(self): a = Tensor.arange(4).reshape(1, 4) casted_view = a.pad(((0, 1), (0, 0))).cast(dtypes.float) casted_view.realize() - self.assertEqual(casted_view.uop.base.realized.size, 4) - realized_view = casted_view.contiguous().realize() - self.assertEqual(realized_view.uop.base.realized.size, 8) - self.assertListEqual(realized_view.tolist(), [[0.0, 1.0, 2.0, 3.0], [0.0, 0.0, 0.0, 0.0]]) + self.assertEqual(casted_view.uop.base.realized.size, 8) + contig = casted_view.contiguous().realize() + self.assertEqual(contig.uop.base.realized.size, 8) + self.assertListEqual(contig.tolist(), [[0.0, 1.0, 2.0, 3.0], [0.0, 0.0, 0.0, 0.0]]) # NOTE: we only reorder CAST if it's an EXPAND def test_cast_after_shrink(self): @@ -1729,7 +1672,7 @@ class TestSchedule(unittest.TestCase): self.assertListEqual(realized_const_view.tolist(), [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) @given(strat.sampled_from(dtypes.all), strat.sampled_from(dtypes.all)) - @expect_rangeify_fails + @unittest.skip("kernel count depends on input") def test_cast_padded_const(self, dt1, dt2): assume(is_dtype_supported(dt1) and is_dtype_supported(dt2)) a = Tensor(1, dtype=dt1).reshape(1, 1).pad(((1, 1), None)) @@ -1743,7 +1686,7 @@ class TestSchedule(unittest.TestCase): X = Tensor.randn(10, 10).realize() idxs = Tensor([0, 2]).realize() xt = X[idxs] - run_schedule(check_schedule(xt, 2)) + run_schedule(check_schedule(xt, 1)) np.testing.assert_equal(xt.numpy(), X.numpy()[idxs.numpy()]) def test_simple_indexing_alt(self): @@ -1761,7 +1704,7 @@ class TestSchedule(unittest.TestCase): def test_advanced_indexing_alt(self): X = Tensor.arange(6).reshape(3, 2)+1 xt = X[[Tensor([2]), Tensor([1])]] - run_schedule(check_schedule(xt, 3)) + run_schedule(check_schedule(xt, 1)) np.testing.assert_equal(xt.numpy(), 6) def test_advanced_simple_indexing_combined(self): @@ -1809,7 +1752,7 @@ class TestSchedule(unittest.TestCase): x = Tensor.full((2,2), 16) y = x.idiv(Tensor.linspace(2, 8, steps=4, dtype=dtypes.int).reshape(2,2)).pad(((1,1), (1,1))) out = y.sum(axis=1) - run_schedule(check_schedule(out, 2)) + run_schedule(check_schedule(out, 1)) self.assertListEqual(out.tolist(), [0, 12, 4, 0]) def test_arange_transposed_descendants(self): @@ -1842,7 +1785,7 @@ class TestSchedule(unittest.TestCase): x = Tensor.randn(5, 2).realize() a = Tensor.arange(10).contiguous() out = (x + a[2]).sum() - run_schedule(check_schedule(out, 3)) + run_schedule(check_schedule(out, 2)) np.testing.assert_allclose(out.numpy(), (x.numpy()+np.arange(10)[2]).sum(), atol=1e-5, rtol=1e-6) def test_arange_index_child(self): @@ -1858,7 +1801,7 @@ class TestSchedule(unittest.TestCase): x = Tensor.randn(5, 2).realize() a = (Tensor.arange(10)+1).contiguous() out = (x + a[2]).sum() - run_schedule(check_schedule(out, 3)) + run_schedule(check_schedule(out, 2)) np.testing.assert_allclose(out.numpy(), (x.numpy()+(np.arange(10)+1)[2]).sum(), atol=1e-5, rtol=1e-6) @unittest.skip("BUFFER_VIEW no longer supported on non-disk devices") @@ -1873,11 +1816,10 @@ class TestSchedule(unittest.TestCase): from extra.models.llama import precompute_freqs_cis args = {"dim":32 if CI else 128, "end":2048 if CI else 8192, "theta":10000} fused = precompute_freqs_cis(**args) - with Context(FUSE_ARANGE=1): - run_schedule(check_schedule(fused, 3)) + run_schedule(check_schedule(fused, 1)) if getenv("CHECK", 1): ref = precompute_freqs_cis(**args) - run_schedule(check_schedule(ref, 3)) + run_schedule(check_schedule(ref, 1)) np.testing.assert_equal(fused.numpy(), ref.numpy()) def test_fuse_assign_contiguous(self): @@ -1901,9 +1843,7 @@ class TestSchedule(unittest.TestCase): tst = x.shrink((None, (0, 2))).assign(a).realize() xref[:, :2] = np.arange(8).reshape(4, 2)+y.numpy() np.testing.assert_equal(x.numpy(), xref) - if RANGEIFY > 0: - # NOTE: this is a bug on non rangeify - np.testing.assert_equal(tst.numpy(), a.numpy()) + np.testing.assert_equal(tst.numpy(), a.numpy()) def test_setitem_sched(self, mop=lambda x:x, expected_kcount=1): a = Tensor.arange(16, device="CPU").reshape(4, 4).contiguous().realize() @@ -1914,7 +1854,6 @@ class TestSchedule(unittest.TestCase): run_schedule(sched) self.assertListEqual(a.tolist(), expected) self.assertEqual(kcount, expected_kcount) - @unittest.skipUnless(RANGEIFY>0, "this asserts on non rangeify") def test_setitem_permuted_sched(self): self.test_setitem_sched(lambda x: x.T, 2) def test_setitem_paddded_sched(self): self.test_setitem_sched(lambda x: x.shrink_to(4, 1).pad_to(4, 4), 1) @@ -1922,9 +1861,18 @@ class TestSchedule(unittest.TestCase): X = Tensor([[0, 2, 3], [1, 2, 3]]).realize() Y = Tensor([1, 2]).realize() loss = X.sparse_categorical_crossentropy(Y) - run_schedule(check_schedule(loss, 4)) + run_schedule(check_schedule(loss, 3)) np.testing.assert_allclose(loss.item(), 0.878309, atol=1e-5, rtol=1e-6) + def test_const_folding_alt(self): + t = Tensor.full((2,), 1.) + lt = (t < 0.) + a = Tensor.empty(2).assign(t*lt.where(-1., 0.)) + b = Tensor.empty(2, dtype=dtypes.bool).assign(lt) + Tensor.realize(a, b) + self.assertEqual(a.tolist(), [0., 0.]) + self.assertEqual(b.tolist(), [False, False]) + @unittest.skipIf(Device.DEFAULT == "WEBGPU", "Validation error on WebGPU") def test_mnist_val(self): from tinygrad.nn.datasets import mnist @@ -1934,7 +1882,7 @@ class TestSchedule(unittest.TestCase): yt = Tensor.randn(BS, 10).realize() with Context(SPLIT_REDUCEOP=0): loss = yt.sparse_categorical_crossentropy(Y_train[samples]) - run_schedule(check_schedule(loss, 6)) + run_schedule(check_schedule(loss, 4)) loss_fused = loss.numpy() loss_ref = torch.nn.CrossEntropyLoss()(torch.tensor(yt.numpy()), torch.tensor(Y_train.numpy())[torch.tensor(samples.numpy())]) np.testing.assert_allclose(loss_fused, loss_ref.numpy(), atol=1e-6, rtol=1e-6) @@ -1944,26 +1892,16 @@ class TestSchedule(unittest.TestCase): r = (X+Tensor.arange(16).reshape(4, 4)).sum() out0 = r+2 out1 = r+3 - run_schedule(check_schedule([out0, out1], 1 if RANGEIFY else 3)) + run_schedule(check_schedule([out0, out1], 2)) # TODO: 1? r_ref = (X.numpy()+np.arange(16).reshape(4, 4)).sum() np.testing.assert_allclose(out0.numpy(), r_ref+2, rtol=2e-7) np.testing.assert_allclose(out1.numpy(), r_ref+3, rtol=2e-7) - @unittest.skip("multi output isn't supported") - def test_multiview_arange_children(self): - X = Tensor.randn(2,3,4,4).numpy() - with Context(FUSE_ARANGE=1): - compare = Tensor(X).interpolate(size=(2, 2), mode="linear").numpy() - with Context(FUSE_ARANGE=0, TRACK_MATCH_STATS=0): - ref = Tensor(X).interpolate(size=(2, 2), mode="linear").numpy() - np.testing.assert_allclose(ref, compare, atol=1e-5, rtol=1e-6) - def test_recursive_swizzle(self): a = Tensor([1,2,3,4]).realize() for _ in range(24): a = a + a new_uop = a.reshape(4,1).realize().uop - self.assertEqual(new_uop.st, ShapeTracker.from_shape((4,)).reshape((4, 1))) - self.assertEqual(swizzle_cnt(new_uop), 0) + assert new_uop.base.op is Ops.BUFFER @unittest.skipIf(CI and Device.DEFAULT == "NV", "crashes on NV CI") def test_limit_bufs_with_var(self): @@ -1989,9 +1927,6 @@ class TestSchedule(unittest.TestCase): sched = z.schedule() self.assertEqual(len(sched), kcount+1) -def swizzle_cnt(u:UOp) -> int: - return len([x for x in u.toposort() if x.op is Ops.VIEW and len(x.src) != 0 and x.src[0].op not in {Ops.BUFFER, Ops.DEFINE_GLOBAL, Ops.ASSIGN}]) - class TestSwizzle(unittest.TestCase): def test_swizzle_simple(self): Tensor.manual_seed(0) @@ -1999,8 +1934,7 @@ class TestSwizzle(unittest.TestCase): a = Tensor.randint(32, 32).realize() r = (a+a).sum(1).sum(0) # double reduce collapses to a single reduce - with Context(DONT_GROUP_REDUCES=1): - run_schedule(check_schedule(r, 1)) + run_schedule(check_schedule(r, 1)) self.assertEqual(r.numpy(), (a.numpy()+a.numpy()).sum(1).sum(0)) def test_single_swizzle(self): @@ -2020,33 +1954,29 @@ class TestSwizzle(unittest.TestCase): b = Tensor.randint(4,).realize() # parallel reduce! add = a.sum(0)+b.sum(0) - with Context(DONT_GROUP_REDUCES=1): - run_schedule(check_schedule(add, 1)) + run_schedule(check_schedule(add, 1)) self.assertEqual(add.numpy(), a.numpy().sum(0)+b.numpy().sum(0)) - @unittest.skip("TODO: how do we express the norm") def test_softmax_one_kernel(self): Tensor.manual_seed(0) with Context(DEBUG=0, TRACK_MATCH_STATS=0): a = Tensor.randn(32, 32).realize() t = a.softmax() - with Context(DONT_GROUP_REDUCES=1, DONT_REALIZE_EXPAND=1): - check_schedule(t, 1) + check_schedule(t, 3) # TODO: 1? def test_argmax_one_kernel(self): Tensor.manual_seed(0) with Context(DEBUG=0, TRACK_MATCH_STATS=0): a = Tensor.randn(10, 20).realize() t = a.argmax(0) - with Context(DONT_GROUP_REDUCES=1, DONT_REALIZE_EXPAND=1): t.realize() + check_schedule(t, 2) # TODO: 1? def test_swizzle_reduceop(self): Tensor.manual_seed(0) x = Tensor.randn(4,4).realize() y = Tensor.randn(4,4,4).realize() out = x.reshape(4,4,1).expand(4,4,4).sum(axis=(1,))+y - with Context(DONT_REALIZE_EXPAND=1, DONT_GROUP_REDUCES=1): - run_schedule(check_schedule(out, 1)) + run_schedule(check_schedule(out, 2)) # TODO: 1? np.testing.assert_allclose(out.numpy(), np.tile(x.numpy().reshape(4,4,1), (1,1,4)).sum(axis=1)+y.numpy()) def test_permute_rewrite(self): @@ -2054,7 +1984,7 @@ class TestSwizzle(unittest.TestCase): y = Tensor.randn(4, 1, 16).realize() z = Tensor.randn(4, 4, 1).realize() t = (x*y).sum(axis=(0, 2)).reshape(1, 4, 1).permute(0, 2, 1)+z - with Context(DONT_GROUP_REDUCES=1, DONT_REALIZE_EXPAND=1): run_schedule(check_schedule(t, 1)) + run_schedule(check_schedule(t, 2)) # TODO: 1? t_np = (x.numpy()*y.numpy()).sum(axis=(0, 2)).reshape(1, 4, 1).transpose(0, 2, 1)+z.numpy() np.testing.assert_allclose(t.numpy(), t_np, atol=1e-6, rtol=1e-3) @@ -2065,14 +1995,14 @@ class TestSwizzle(unittest.TestCase): a_reduce = a.sum(axis=(2,), keepdim=True).sum(axis=(1,)) b_reduce = b.sum(axis=(0,)) t = a_reduce+b_reduce - with Context(DONT_GROUP_REDUCES=1, DONT_REALIZE_EXPAND=1): run_schedule(check_schedule(t, 1)) + run_schedule(check_schedule(t, 1)) def test_parallel_reduce_possible(self): Tensor.manual_seed(0) x = Tensor.randn(4, 2, 2).realize() y = Tensor.randn(4, 2, 2).realize() t = x.sum(axis=1)+y.sum(axis=1) - with Context(DONT_GROUP_REDUCES=1): run_schedule(check_schedule(t, 1)) + run_schedule(check_schedule(t, 1)) np.testing.assert_allclose(t.numpy(), x.numpy().sum(axis=1)+y.numpy().sum(axis=1), atol=1e-6, rtol=1e-3) # kernels can only have 1 or n in each dim @@ -2081,7 +2011,7 @@ class TestSwizzle(unittest.TestCase): x = Tensor.randn(4, 2, 2).realize() y = Tensor.randn(4, 3, 2).realize() t = x.sum(axis=1)+y.sum(axis=1) - with Context(DONT_GROUP_REDUCES=1): run_schedule(check_schedule(t, 1)) + run_schedule(check_schedule(t, 1)) np.testing.assert_allclose(t.numpy(), x.numpy().sum(axis=1)+y.numpy().sum(axis=1), atol=1e-6, rtol=1e-3) def test_unsafe_pad(self): @@ -2102,14 +2032,12 @@ class TestView(unittest.TestCase): run_schedule(sched) np.testing.assert_equal(b.numpy(), 0) - @expect_rangeify_fails def test_mask_dim_1(self): # mask out dim = 1 works too a = Tensor.rand(10, 10).realize() b = a.pad((None, (0, 10)))[:, 10:] assert b.shape == (10, 10) sched = check_schedule(b.contiguous(), 1) - self.assertEqual(sched[-1].ast.full_shape, (10, 10)) run_schedule(sched) np.testing.assert_equal(b.numpy(), 0) @@ -2129,7 +2057,6 @@ class TestView(unittest.TestCase): # a*VIEW(x), where VIEW(x) = 0 # x collapses along with its children - @unittest.skipIf(RANGEIFY, "this only fails if you run all of TestSchedule, some global tensor map bug?") def test_parent_view_collapses(self): a = Tensor([1, 2]) b = Tensor.arange(3).contiguous() @@ -2161,56 +2088,6 @@ class TestView(unittest.TestCase): run_schedule(s) self.assertEqual(other_child.tolist(), [2, 3, 4]) -def tensor_rewrite(t) -> UOp: return graph_rewrite(t.uop.base, merge_views+symbolic_simple) -class TestSimplifier(unittest.TestCase): - def test_sink_childless_const(self): - x = Tensor(0) - check_schedule(x, 0) - - def test_sink_childless_const_alt_expanded(self): - x = Tensor.zeros(4, 4).contiguous() - check_schedule(x, 1) - - def test_all_const_uops(self): - a = Tensor(4)*Tensor(2) - sink = tensor_rewrite(a) - assert UPat.cvar().match(sink, {}) - - def test_masked_const_elementwise(self): - a = Tensor.eye(10)@Tensor.eye(10) - sink = tensor_rewrite(a) - assert UPat(Ops.REDUCE_AXIS, src=(UPat.cvar().view()*UPat.cvar().view(),)).match(sink, {}) - - def test_elementwise_ops(self): - a = Tensor.empty(4, 4, dtype=dtypes.int) - sink = tensor_rewrite(a*0) - assert UPat(Ops.CONST, arg=0).match(sink, {}) - self.assertIs(tensor_rewrite(a*1).base, a.uop.base) - self.assertIs(tensor_rewrite(a+0).base, a.uop.base) - - def test_cast_folding(self): - a = Tensor(1.0).cast(dtypes.int) - sink = tensor_rewrite(a) - assert UPat.cvar(dtype=dtypes.int).match(sink, {}) - - def test_const_folding_mul(self): - a = Tensor([1]) - sink = tensor_rewrite(a*0) - assert UPat(Ops.CONST, arg=0).match(sink, {}), f"expected {sink} to collapse to a const 0" - assert sink.shape == a.shape - - def test_const_folding_ne(self): - a = Tensor([1]) - sink = tensor_rewrite(a != a) - assert UPat(Ops.CONST, arg=False).match(sink, {}), f"expected {sink} to collapse to a const False" - assert sink.shape == a.shape - - def test_const_folding_lt(self): - a = Tensor([1]) - sink = tensor_rewrite(a < a) - assert UPat(Ops.CONST, arg=False).match(sink, {}), f"expected {sink} to collapse to a const False" - assert sink.shape == a.shape - @unittest.skipIf(Device.DEFAULT == "CPU", "tests copy from another device to cpu") class TestCopyFolding(unittest.TestCase): def test_const_copy_is_free(self): @@ -2218,6 +2095,16 @@ class TestCopyFolding(unittest.TestCase): check_schedule(b, 0, filter_sink=False) assert b.item() == 1 + def test_one_hot_with_copy(self): + y = Tensor([1, 2, 3]).to("CPU") + x = y.one_hot(10) + check_schedule(x, 3, filter_sink=False) + + def test_const_copy_multi(self): + x = Tensor.ones(1, device="CPU").to_(["CPU", "CPU:1"]) + check_schedule(x, 0, filter_sink=False) + self.assertEqual(x.item(), 1) + def test_late_const_copy_folding(self): a = Tensor.arange(3).realize() zeros = Tensor.zeros(3).realize() @@ -2230,8 +2117,8 @@ class TestCopyFolding(unittest.TestCase): a = Tensor.ones((4,)).to("CPU") b = Tensor.empty(4, device="CPU") add = a+b - add.kernelize() assert all_same([x.device for x in add.uop.src]), f"ALU has different devices! {[x.device for x in add.src]}" + add.kernelize() def test_alu_before_copy(self): buf = Tensor.ones(1).contiguous().realize() @@ -2242,18 +2129,12 @@ class TestCopyFolding(unittest.TestCase): def test_copy_to_same_device(self): a = Tensor.empty(4).uop b = a.copy_to_device(a.device) - check_schedule(b, 0, filter_sink=False) - b = schedule_graph_rewrite(b) - # NOTE: Tensor.empty(4) always creates a VIEW(BUFFER) with ShapeTracker((4,)), we simplify this to jsut a BUFFER - # in the scheduler because buffer already has shape (4,) - self.assertIs(b, a.base) + check_schedule(b, 1, filter_sink=False) # TODO: 0? def test_copy_to_same_device_alt(self): a = Tensor.empty(4, 4).uop b = a.copy_to_device(a.device) - check_schedule(b, 0, filter_sink=False) - b = schedule_graph_rewrite(b) - self.assertIs(b.base, a.base) + check_schedule(b, 1, filter_sink=False) # TODO: 0? def test_copy_to_same_device_sched(self): a = Tensor.ones(4).contiguous().realize().uop.as_buf() @@ -2268,13 +2149,11 @@ class TestCopyFolding(unittest.TestCase): a = Tensor.empty(4) check_schedule(a.clone(), 1, filter_sink=False) - # NOTE: moving copy before view might change this def test_shrink_copy(self): a = Tensor.arange(4) view = a.shrink(((0, 2),)) b = view.clone() - # NOTE: this was sort of a bug making this 2 - run_schedule(check_schedule(b, 2, filter_sink=False)) + run_schedule(check_schedule(b, 1, filter_sink=False)) self.assertEqual(b.uop.base.buffer.size, 2) self.assertEqual(b.uop.size, 2) self.assertListEqual(b.tolist(), [0, 1]) @@ -2283,7 +2162,7 @@ class TestCopyFolding(unittest.TestCase): a = Tensor.arange(2) view = a.reshape(2, 1).expand(2, 2) b = view.clone() - run_schedule(check_schedule(b, 2, filter_sink=False)) + run_schedule(check_schedule(b, 1, filter_sink=False)) self.assertEqual(b.uop.base.buffer.size, 4) self.assertEqual(b.uop.size, 4) self.assertListEqual(b.tolist(), [[0, 0], [1, 1]]) @@ -2301,10 +2180,9 @@ class TestCopyFolding(unittest.TestCase): b.realize() self.assertListEqual(b.tolist(), [[0, 2], [1, 3]]) - @expect_nonrangeify_fails def test_permute_on_disk_contiguous(self): - with open(temp('dt_arange_4_permute'), "wb") as f: f.write(Tensor.arange(4).realize().uop.base.buffer.as_buffer()) - a = Tensor.empty(4, dtype=dtypes.int32, device=f"disk:{temp('dt_arange_4_permute')}") + with open(temp('dt_arange_4_permute_contig'), "wb") as f: f.write(Tensor.arange(4).realize().uop.base.buffer.as_buffer()) + a = Tensor.empty(4, dtype=dtypes.int32, device=f"disk:{temp('dt_arange_4_permute_contig')}") b = a.reshape(2, 2).permute(1, 0).contiguous().to("CPU") b.realize() self.assertListEqual(b.tolist(), [[0, 2], [1, 3]]) @@ -2316,8 +2194,6 @@ class TestCopyFolding(unittest.TestCase): self.assertListEqual(b.tolist(), [[0, 2], [1, 3]]) # NOTE: disk permute must come after COPY - # TODO: this is wrong because of the permute - @expect_nonrangeify_fails def test_permute_after_shrink_on_disk(self): with open(temp('dt_arange_5_permute'), "wb") as f: f.write(Tensor.arange(5).realize().uop.base.buffer.as_buffer()) a = Tensor.empty(5, dtype=dtypes.int32, device=f"disk:{temp('dt_arange_5_permute')}") @@ -2330,7 +2206,7 @@ class TestBufferUOp(unittest.TestCase): def test_buffer_has_buffer(self): buf = Tensor.empty(10) self.assertIsNotNone(buf.uop.buffer) - self.assertEqual(buf.uop.st, ShapeTracker.from_shape((10,))) + self.assertEqual(buf.uop.shape, (10,)) # the device Buffer remains unallocated until it's we run the schedule self.assertFalse(buf.uop.buffer.is_allocated()) add = buf+1 @@ -2354,9 +2230,8 @@ class TestBufferUOp(unittest.TestCase): def test_buffer_view_not_allowed(self): permuted_view = Tensor.empty(1, 2, 3).permute(0, 2, 1) - merged = graph_rewrite(permuted_view.uop, merge_views) - with self.assertRaisesRegex(AssertionError, "VIEW only works here if it's contiguous"): - merged.buffer # cannot access Buffer of a non contiguous VIEW + with self.assertRaisesRegex(AssertionError, "can only be RESHAPE"): + permuted_view.uop.buffer # cannot access Buffer of a non contiguous VIEW def test_buffer_only_after_realize(self): a = Tensor([1])+Tensor([2]) @@ -2448,25 +2323,22 @@ class TestUOpBecome(unittest.TestCase): self.assertEqual(add.uop.shape, (8, 2)) assert add.uop is not add.uop.base - @expect_rangeify_fails def test_new_flat_buffer(self): a = Tensor.empty(4,) b = Tensor.empty(4,) add = a+b check_schedule(add, 1) # BUFFER already has a shape (4,), this tensor just becomes a contiguous BUFFER - assert UPat(Ops.BUFFER).match(add.uop, {}) + assert UPat(Ops.BUFFER).match(add.uop.base, {}) # sometimes we prefer to perform an op before movement ops, in this case we should stack the mops on top of the new buffer - # NOTE: this expand is not reordered because there's before it to fuse - @expect_rangeify_fails def test_reorder_expand(self): a = Tensor.empty(4, 1) b = a.expand(4, 4).reciprocal() check_schedule(b, 1) - self.assertEqual(b.uop.base.buffer.size, 16) - self.assertEqual(b.uop.st, ShapeTracker.from_shape((4, 4))) + self.assertEqual(b.uop.base.buffer.size, 4) + self.assertEqual(b.uop.shape, (4, 4)) def test_reorder_expand_alt(self): x = Tensor.empty(4, 1) @@ -2475,13 +2347,13 @@ class TestUOpBecome(unittest.TestCase): z = (img*x) / y check_schedule(z, 1) - @expect_rangeify_fails + # TODO: rangeify doesn't yet cleanup this kind of re-indexing + @unittest.expectedFailure def test_become_existing_buffer(self): a = Tensor.empty(4, 4) b = a*1 assert UPat(Ops.MUL).match(b.uop, {}) # before scheduling it's a mul check_schedule(b, 0) - assert UPat(Ops.VIEW, src=(UPat(Ops.BUFFER))).match(b.uop, {}) # scheduling merges all MovementOps into a single VIEW self.assertIs(a.uop.base.buffer, b.uop.base.buffer) def test_become_buf_with_mops(self): @@ -2503,17 +2375,6 @@ class TestUOpBecome(unittest.TestCase): check_schedule(b, 0) assert UPat(Ops.CONST, arg=0).match(b.uop.base, {}) # scheduling replaces the tensor uop with a VIEW(BUFFER) - @expect_rangeify_fails - def test_become_const_in_view(self): - # if we shrink the base down to a size 0, only the VIEW becomes CONST, base is unchanged. - add = Tensor.empty(2, 2)+Tensor.empty(2, 2) - b = add.shrink(((0, 1), (0, 0))) - check_schedule(b, 0) - assert UPat(Ops.CONST, arg=0).match(b.uop, {}) - self.assertEqual(b.shape, (1, 0)) - # the base is untouched. - assert UPat(Ops.ADD).match(add.uop, {}) - def test_become_const_from_const(self): const_add = Tensor(1)+Tensor(2) assert UPat(Ops.ADD).match(const_add.uop, {}) @@ -2521,7 +2382,7 @@ class TestUOpBecome(unittest.TestCase): assert UPat(Ops.CONST, arg=3).match(const_add.uop.base, {}) # tensors can become another realized tensor source - @expect_rangeify_fails + @unittest.expectedFailure def test_become_existing_buf_simple(self): a = Tensor.empty(4, 4) b = a+0 @@ -2530,14 +2391,14 @@ class TestUOpBecome(unittest.TestCase): self.assertIs(a.uop, b.uop) # they can also chain other movement ops on top of the tensor source - @expect_rangeify_fails + @unittest.expectedFailure def test_become_existing_buf_view(self): a = Tensor.empty(4, 4) b = a.permute((1, 0))+0 check_schedule(b, 0) self.assertEqual(b.uop.st, a.uop.permute((1, 0)).st) - @expect_rangeify_fails + @unittest.expectedFailure def test_become_existing_buf_view_alt(self): a = Tensor.empty(4, 4) b = a.permute((1, 0)).reshape((8, 2))+0 @@ -2545,7 +2406,7 @@ class TestUOpBecome(unittest.TestCase): self.assertEqual(b.uop.st, a.uop.permute((1, 0)).reshape((8, 2)).st) # they can also have other base parents that simplified, in that case we just backtrack to the chained mops - @expect_rangeify_fails + @unittest.expectedFailure def test_become_existing_buf_complex(self): a = Tensor.empty(4, 4) b = (a.permute((1, 0))+0).reshape((8, 2))+0 @@ -2553,28 +2414,22 @@ class TestUOpBecome(unittest.TestCase): self.assertEqual(b.uop.st, a.uop.permute((1, 0)).reshape((8, 2)).st) assert b.uop.base.op is Ops.BUFFER - @expect_rangeify_fails + @unittest.expectedFailure def test_become_multiple_choices(self): a = Tensor.empty(16) b = (a.reshape(1, 1, 4, 1, 4)+0).reshape(1, 1, 4, 4).shrink(((0, 1), (0, 1), (0, 3), (0, 3)))+0 c = (a.reshape(1, 1, 4, 4)+0).shrink(((0, 1), (0, 1), (0, 3), (0, 3)))+0 check_schedule([b, c], 0) assert all_same([x.uop.base.realized for x in [a,b,c]]) - # these movement ops result in the same ShapeTracker - assert b.uop.st == c.uop.st - assert b.uop is c.uop - assert UPat(Ops.VIEW, src=(UPat(Ops.BUFFER),)).match(c.uop, {}) - @expect_rangeify_fails def test_setitem_becomes_subbuffer(self): a = Tensor.full((4,), 2.).contiguous().realize() b = a.shrink(((0, 2),)).assign(Tensor.full((2,), 1.0)) b.realize() assert a.uop.is_realized assert a.uop.buffer._base is None - # b is a subbuffer of a - assert b.uop.op is Ops.BUFFER_VIEW - assert b.uop.src[0] is a.uop + assert b.uop.op_in_backward_slice_with_self(Ops.SHRINK) + assert b.uop.base is a.uop.base def test_setitem_offset(self): a = Tensor.full((16,), 0.).contiguous().realize() diff --git a/test/test_setitem.py b/test/test_setitem.py index 2005b7c801..c8ad43198f 100644 --- a/test/test_setitem.py +++ b/test/test_setitem.py @@ -52,7 +52,6 @@ class TestSetitem(unittest.TestCase): def test_setitem_into_noncontiguous(self): t = Tensor.ones(4) - self.assertFalse(t.uop.st.contiguous) with self.assertRaises(RuntimeError): t[1] = 5 @unittest.skip("TODO: flaky") diff --git a/test/test_softmax_fusion.py b/test/test_softmax_fusion.py index a86b3e40ee..da141205da 100644 --- a/test/test_softmax_fusion.py +++ b/test/test_softmax_fusion.py @@ -2,7 +2,7 @@ import unittest import numpy as np from tinygrad import Tensor, GlobalCounters, Context, Device from tinygrad.dtype import DTypeLike, dtypes -from tinygrad.helpers import DEBUG, get_single_element, RANGEIFY +from tinygrad.helpers import DEBUG, get_single_element from tinygrad.engine.realize import lower_schedule_item from tinygrad.device import is_dtype_supported @@ -32,24 +32,24 @@ def run_one_schedule_item(out): lower_schedule_item(get_single_element(out.sched class TestFuse(unittest.TestCase): def _test_fuse(self, fxn, *args, atol=1e-6, allow_multiple=False, **kwargs): GlobalCounters.reset() - out_single = fxn(*args, **kwargs).fuse() + out_single = fxn(*args, **kwargs) if not allow_multiple: run_one_schedule_item(out_single) np_single = out_single.numpy() GlobalCounters.reset() np_multi = fxn(*args, **kwargs).numpy() np.testing.assert_allclose(np_single, np_multi, atol=atol) - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_fuse_norm(self): a = Tensor.rand(50,50).realize() self._test_fuse(lambda a: a / a.mean(axis=1), a) - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_fuse_argmax(self): a = Tensor.rand(50,50).realize() self._test_fuse(lambda a: a.argmax(axis=-1), a) - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_fuse_softmax(self): a = Tensor.rand(50,50).realize() self._test_fuse(lambda a: a.softmax(axis=-1), a) @@ -60,7 +60,7 @@ class TestFuse(unittest.TestCase): self._test_fuse(lambda a,b: ((a@b).relu()+a).contiguous().softmax(axis=-1), a,b, allow_multiple=True) @unittest.skipUnless(is_dtype_supported(dtypes.float16, Device.DEFAULT), f"no float16 on {Device.DEFAULT}") - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_fuse_softmax_dtype(self): a = Tensor.rand(50,50).realize() self._test_fuse(lambda a: a.softmax(axis=-1, dtype='half'), a, atol=3e-4) @@ -68,7 +68,7 @@ class TestFuse(unittest.TestCase): def test_fuse_arange_eye(self): self._test_fuse(lambda: Tensor.arange(10).reshape(10,1).expand(10,10) == Tensor.arange(10).reshape(1,10).expand(10,10)) - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_double_gemm(self): N = 32 with Context(TRACK_MATCH_STATS=0, DEBUG=0): @@ -91,7 +91,7 @@ class TestFuse(unittest.TestCase): return (arange == idx).mul(vals).sum(-2, dtype=vals.dtype) self._test_fuse(embedding, a, atol=1e-5) - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_attention_kernel_count(self): wq = Tensor.empty(32, 32) wk = Tensor.empty(32, 32) @@ -100,11 +100,11 @@ class TestFuse(unittest.TestCase): q = (x @ wq).contiguous() k = (x @ wk).contiguous() v = (x @ wv).contiguous() - attn = q.scaled_dot_product_attention(k, v).fuse() + attn = q.scaled_dot_product_attention(k, v) s = attn.schedule() self.assertEqual(len(s), 4) # 3 matmul and 1 attention - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_flash_attention(self): BS = 4 HEADS = 2 @@ -121,7 +121,7 @@ class TestFuse(unittest.TestCase): def test_mismatch_reduce(self): a = Tensor.ones(16, 10).contiguous().realize() b = Tensor.ones(16, 20).contiguous().realize() - c = (a.sum(axis=1) + b.sum(axis=1)).fuse() + c = (a.sum(axis=1) + b.sum(axis=1)) self.assertListEqual(c.tolist(), [30]*16) @unittest.skipUnless(Device.DEFAULT == "METAL", "METAL TC") @@ -129,7 +129,7 @@ class TestFuse(unittest.TestCase): A = Tensor.randn(8, 8).realize() B = Tensor.randn(8, 8).realize() C = Tensor.ones(1, 8, 8).pad(((1,1), None, None),).sum(0) - out = (C + (A @ B)).fuse() + out = (C + (A @ B)) out.realize() class TestSoftmaxFusion(unittest.TestCase): @@ -165,14 +165,13 @@ class TestSoftmaxFusion(unittest.TestCase): sout.realize() print("*** single kernel softmax ***") - # NOTE: DONT_GROUP_REDUCES is required here - with Context(NOOPT=1, DEBUG=max(DEBUG.value, 2), DONT_GROUP_REDUCES=1): + with Context(NOOPT=1, DEBUG=max(DEBUG.value, 2)): out = single_kernel_softmax(self.test) out.realize() np.testing.assert_allclose(sout.numpy(), out.numpy(), atol=3e-7) - @unittest.skipIf(01") + @unittest.skip("needs RANGEIFY>1") def test_auto_softmax(self): print("*** softmax ***") with Context(NOOPT=1, DEBUG=max(DEBUG.value, 2)): @@ -181,12 +180,11 @@ class TestSoftmaxFusion(unittest.TestCase): print("*** auto single kernel softmax ***") with Context(NOOPT=1, DEBUG=max(DEBUG.value, 2)): - out = self.test.contiguous().softmax(-1).fuse() + out = self.test.contiguous().softmax(-1) run_one_schedule_item(out) np.testing.assert_allclose(sout.numpy(), out.numpy(), atol=3e-7) - @unittest.skip("recursion error no longer raised") def test_softmax_bw(self): print("*** softmax bw ***") self.test.requires_grad_() @@ -197,14 +195,11 @@ class TestSoftmaxFusion(unittest.TestCase): self.test.grad = None print("*** single kernel softmax bw ***") - # NOTE: DONT_GROUP_REDUCES is required here - # TODO: fix RecursionError with DONT_GROUP_REDUCES - with self.assertRaises(RecursionError): - with Context(NOOPT=1, DEBUG=max(DEBUG.value, 2), DONT_GROUP_REDUCES=1): - single_kernel_softmax(self.test).sum().backward() - g = self.test.grad.realize() + with Context(NOOPT=1, DEBUG=max(DEBUG.value, 2)): + single_kernel_softmax(self.test).sum().backward() + g = self.test.grad.realize() - np.testing.assert_allclose(sg.numpy(), g.numpy(), atol=1e-7) + np.testing.assert_allclose(sg.numpy(), g.numpy(), atol=1e-7) if __name__ == '__main__': unittest.main() diff --git a/test/test_stunning.py b/test/test_stunning.py index 285829235e..4d9e966a77 100644 --- a/test/test_stunning.py +++ b/test/test_stunning.py @@ -40,7 +40,7 @@ class TestStunning(unittest.TestCase): Y_train = Y_train.one_hot(10) X_samp, Y_samp = X_train[samples], Y_train[samples] vi = Variable('i', 0, samples.shape[0]-1) - with Context(FUSE_ARANGE=1, SPLIT_REDUCEOP=0): + with Context(SPLIT_REDUCEOP=0): with Tensor.train(): losses = [] for i in range(samples.shape[0]): diff --git a/test/test_symbolic_jit.py b/test/test_symbolic_jit.py index f28d274dcc..9174a47187 100644 --- a/test/test_symbolic_jit.py +++ b/test/test_symbolic_jit.py @@ -2,7 +2,6 @@ import unittest from test.helpers import assert_jit_cache_len from tinygrad import Variable, Tensor, TinyJit -from tinygrad.helpers import RANGEIFY import numpy as np class TestSymbolicJit(unittest.TestCase): @@ -27,7 +26,7 @@ class TestSymbolicJit(unittest.TestCase): symbolic = jf(a[:, :vi]).numpy() expected = f(a[:, :i]).numpy() np.testing.assert_allclose(symbolic, expected, atol=1e-6, rtol=1e-6) - assert_jit_cache_len(jf, 1 if RANGEIFY else 2) # one add and one pad, can be one kernel? + assert_jit_cache_len(jf, 1) def test_add(self): def f(a, b): return (a+b).realize() @@ -80,7 +79,7 @@ class TestSymbolicJit(unittest.TestCase): symbolic = jf(q, k[:, :vi], v[:, :vi])[:2, :4, :1, :8].numpy() expected = f(q, k[:, :i], v[:, :i]).numpy() np.testing.assert_allclose(symbolic, expected, atol=1e-6, rtol=1e-6) - assert_jit_cache_len(jf, 4 if RANGEIFY else 5) + assert_jit_cache_len(jf, 4) def test_cat_dim0(self): def f(a, b): return a.cat(b, dim=0).realize() diff --git a/test/test_symbolic_ops.py b/test/test_symbolic_ops.py index 991a9dcc93..7ae45c24f4 100644 --- a/test/test_symbolic_ops.py +++ b/test/test_symbolic_ops.py @@ -1,6 +1,5 @@ import unittest from tinygrad import Tensor, Variable, GlobalCounters -from tinygrad.shape.shapetracker import View from tinygrad.uop.ops import sym_infer from tinygrad.dtype import dtypes from tinygrad.device import is_dtype_supported @@ -64,14 +63,6 @@ class TestSymbolicOps(unittest.TestCase): self.test_attention(imin=4, imax=5, use_symbolic=False) self.test_attention(imin=4, imax=5, use_symbolic=True) - # until this works, symbolic single kernel softmax won't - @unittest.expectedFailure - def test_attention_simple_view(self): - i = Variable("i", 2, 10) - v1 = View.create((2,4,1,i,i), ((i*4),i,0,0,1)) - v2 = View.create((2,4,1,i,i,i), (((i*i)*4),(i*i),0,0,i,1)) - self.assertIsNotNone(v1+v2) - def test_attention_training(self): with Tensor.train(): self.test_attention(dropout_p=0.0) @@ -296,7 +287,6 @@ class TestSymbolicOps(unittest.TestCase): symbolic = symbolic_result[:].numpy() np.testing.assert_allclose(symbolic, expected, atol=1e-6, rtol=0) - @unittest.expectedFailure def test_conv2d_ceildiv_edge_case(self): v = Variable('v', 11, 50_000) val = 39601 @@ -304,9 +294,10 @@ class TestSymbolicOps(unittest.TestCase): weight = Tensor.randn(256, 22, 12) result = x.conv2d(weight=weight, groups=1, stride=6, dilation=1, padding=(3, 3)) - var_val = {v: val} + var_val = {v.expr: val} shape = tuple(sym_infer(s, var_val) for s in result.shape) - self.assertEqual(shape, (1, 256, 6600)) # TODO: fails if ceildiv is incorrect + with self.assertRaises(AssertionError): + self.assertEqual(shape, (1, 256, 6600)) # TODO: fails if ceildiv is incorrect # TODO: test output is correct if __name__ == '__main__': diff --git a/test/test_tensor.py b/test/test_tensor.py index defeaac580..a053549781 100644 --- a/test/test_tensor.py +++ b/test/test_tensor.py @@ -1,15 +1,15 @@ -import subprocess import numpy as np import torch import unittest, copy, mmap, random, math, array from tinygrad import Tensor, Device, dtypes from tinygrad.tensor import _METADATA -from tinygrad.helpers import getenv, temp, mv_address, RANGEIFY +from tinygrad.helpers import Context, getenv, temp, mv_address from extra.gradcheck import numerical_jacobian, jacobian, gradcheck from hypothesis import given, settings, strategies as strat from tinygrad.device import is_dtype_supported from tinygrad.uop.ops import Ops, UOp from tinygrad.renderer.ptx import PTXRenderer +from tinygrad.renderer.nir import NIRRenderer from tinygrad.codegen import full_rewrite from tinygrad.dtype import DType @@ -515,32 +515,6 @@ class TestTinygrad(unittest.TestCase): print(a) print(c) - def test_env_overwrite_default_device(self): - subprocess.run([f'{Device.DEFAULT}=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - subprocess.run([f'DISK=1 {Device.DEFAULT}=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - subprocess.run([f'NPY=1 {Device.DEFAULT}=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - - if Device.DEFAULT != "CPU": - # setting multiple devices fail - with self.assertRaises(subprocess.CalledProcessError): - subprocess.run([f'{Device.DEFAULT}=1 CPU=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - - # setting device via DEV - subprocess.run([f'DEV={Device.DEFAULT.capitalize()} python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - subprocess.run([f'DEV={Device.DEFAULT.lower()} python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - subprocess.run([f'DEV={Device.DEFAULT.upper()} python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - - with self.assertRaises(subprocess.CalledProcessError): - subprocess.run([f'DEV={Device.DEFAULT} CPU=1 python3 -c "from tinygrad import Device; assert Device.DEFAULT == \\"{Device.DEFAULT}\\""'], - shell=True, check=True) - def test_no_attributeerror_after_apply_uop_exception(self): try: Tensor.arange(4).reshape(3,2) @@ -553,6 +527,7 @@ class TestTinygrad(unittest.TestCase): self.assertListEqual(t.shrink_to(16).tolist(), list(range(16))) t = t.reshape(4, 8).contiguous().realize() self.assertListEqual(t.shrink_to(2, 2).tolist(), [[0, 1], [8, 9]]) + self.assertListEqual(t.shrink_to(None, 2).tolist(), t.shrink_to(4, 2).tolist()) with self.assertRaises(ValueError): t.shrink_to(2) with self.assertRaises(ValueError): t.shrink_to(2, 2, 2) @@ -595,22 +570,6 @@ class TestMoveTensor(unittest.TestCase): np.testing.assert_equal(x.grad.numpy(), [[2,2,2],[0,0,0],[-2,-2,-2]]) class TestZeroShapeTensor(unittest.TestCase): - def test_shape_stride(self): - t = Tensor.empty(3, 2, 0) - assert t.shape == (3, 2, 0) - # numpy has stride 0, 0, 0; torch has stride 2, 1, 1 - assert t.uop.st.real_strides() == (0, 0, 0) - - t = Tensor.empty(3, 0, 2) - assert t.shape == (3, 0, 2) - # numpy has stride 0, 0, 0; torch has stride 2, 2, 1 - assert t.uop.st.real_strides() == (0, 0, 0) - - t = Tensor.empty(0, 0, 0) - assert t.shape == (0, 0, 0) - # numpy has stride 0, 0, 0; torch has stride 1, 1, 1 - assert t.uop.st.real_strides() == (0, 0, 0) - def test_rand(self): t = Tensor.rand(3, 2, 0) assert t.shape == (3, 2, 0) @@ -662,8 +621,10 @@ class TestZeroShapeTensor(unittest.TestCase): np.testing.assert_equal(Tensor([1, 2]).pad_to(4).numpy(), [1, 2, 0, 0]) np.testing.assert_equal(Tensor([[1, 2]]).pad_to(2, 3).numpy(), [[1, 2, 0], [0, 0, 0]]) - with self.assertRaises(TypeError): Tensor([1, 2]).pad_to(2, 3) - with self.assertRaises(TypeError): Tensor([[1, 2]]).pad_to(3) + np.testing.assert_equal(Tensor([[1, 2]]).pad_to(1, 3).numpy(), [[1, 2, 0]]) + np.testing.assert_equal(Tensor([[1, 2]]).pad_to(None, 3).numpy(), [[1, 2, 0]]) + with self.assertRaises(ValueError): Tensor([1, 2]).pad_to(2, 3) + with self.assertRaises(ValueError): Tensor([[1, 2]]).pad_to(3) def test_shrink_into_zero(self): t = Tensor.rand(3, 4).realize() @@ -849,6 +810,14 @@ class TestTensorMetadata(unittest.TestCase): self.assertEqual(len(si.metadata), 1) self.assertEqual(si.metadata[0].name, "relu") + @unittest.skip("this no longer works") + def test_assign(self): + x = Tensor.empty(10, 10).realize() + x.assign(Tensor.ones(10, 10).contiguous()) + si = x.schedule()[-1] + self.assertEqual(len(si.metadata), 1) + self.assertEqual(si.metadata[0].name, "assign") + def test_complex(self): x = Tensor.rand(3, requires_grad=True) y = Tensor.rand(3, requires_grad=True) @@ -871,18 +840,21 @@ class TestTensorMetadata(unittest.TestCase): self.assertEqual(y.grad.uop.metadata[0].name, "sigmoid") self.assertTrue(y.grad.uop.metadata[0].backward) si = Tensor.schedule(out, x.grad, y.grad)[-1] - if not RANGEIFY: - self.assertEqual(len(si.metadata), 4, f"failed with {si.metadata}") - self.assertSetEqual(set(m.name for m in si.metadata), {"sigmoid", "__mul__", "relu"}) - bw = [m for m in si.metadata if m.backward] - self.assertEqual(len(bw), 2) - self.assertEqual(bw[0].name, "sigmoid") - else: - self.assertEqual(len(si.metadata), 3, f"failed with {si.metadata}") - self.assertSetEqual(set(m.name for m in si.metadata), {"sigmoid", "relu"}) - bw = [m for m in si.metadata if m.backward] - self.assertEqual(len(bw), 1) - self.assertEqual(bw[0].name, "sigmoid") + #self.assertEqual(len(si.metadata), 3, f"failed with {si.metadata}") + self.assertSetEqual(set(m.name for m in si.metadata), {"sigmoid", "relu"}) + #bw = [m for m in si.metadata if m.backward] + #self.assertEqual(len(bw), 1) + #self.assertEqual(bw[0].name, "sigmoid") + + def test_tracemeta_0(self): + with Context(TRACEMETA=0): + x = Tensor.rand(3, requires_grad=True) + y = Tensor.rand(3, requires_grad=True) + out = (x.relu() * y.sigmoid()).sum() + self.assertIsNone(out.uop.metadata) + self.assertIsNone(out.uop.src[0].metadata) + si = out.schedule()[-1] + self.assertEqual(si.metadata, ()) class TestIdxUpcast(unittest.TestCase): def _find_op(self, ast: UOp, op: Ops): @@ -904,7 +876,8 @@ class TestIdxUpcast(unittest.TestCase): store = next(uop for uop in uops if uop.op is Ops.STORE) assert store.op is Ops.STORE idx = self._find_op(store, Ops.INDEX) - if idx is not None: # PTX turns Ops.INDEX into pointer arithmetic earlier than cstyle, plus it's already cast to int64 + # PTX and NIR turn Ops.INDEX into pointer arithmetic earlier than cstyle, plus it's already cast to int64 + if not isinstance(Device[Device.DEFAULT].renderer, (PTXRenderer, NIRRenderer)): assert idx.op is Ops.INDEX idx_val = idx.src[1] assert idx_val.dtype is dtype @@ -928,7 +901,7 @@ class TestIdxUpcast(unittest.TestCase): def test_regular_sym(self): self.do_op_then_assert(dtypes.int, 2048, 2048, UOp.variable("dim3", 1, 64).bind(32)) - @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "PTX always convert Ops.INDEX to int64") + @unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, (PTXRenderer, NIRRenderer)), "PTX and NIR always converts Ops.INDEX to int64") def test_symfold(self): # This would cause an overflow, but after sym fold it's within int32 a = Tensor.arange(65535) @@ -957,5 +930,38 @@ class TestIdxUpcast(unittest.TestCase): a = Tensor.empty(2**11, 2**11, 1, dtype=dtypes.int8).permute((2, 0, 1)).expand((2**9+10, -1, -1)).contiguous() a.realize() +class TestTensorUnique(unittest.TestCase): + def test_empty_bufs_unique(self): + a = Tensor.empty(10, 10).contiguous() + b = Tensor.empty(10, 10).contiguous() + Tensor.realize(a,b) + self.assertIsNot(a.uop.buffer, b.uop.buffer) + + def test_zeros_bufs_unique_sep(self): + a = Tensor.zeros(10, 10).contiguous() + Tensor.realize(a) + b = Tensor.zeros(10, 10).contiguous() + Tensor.realize(b) + self.assertIsNot(a.uop.buffer, b.uop.buffer) + + def test_zeros_bufs_unique(self): + a = Tensor.zeros(10, 10).contiguous() + b = Tensor.zeros(10, 10).contiguous() + Tensor.realize(a,b) + self.assertIsNot(a.uop.buffer, b.uop.buffer) + + def test_eye_bufs_unique(self): + a = Tensor.eye(10).contiguous() + b = Tensor.eye(10).contiguous() + Tensor.realize(a,b) + self.assertIsNot(a.uop.buffer, b.uop.buffer) + + def test_times_2_not_unique(self): + a = Tensor.zeros(10, 10).contiguous() + b = a * 2 + c = a * 2 + Tensor.realize(b,c) + self.assertIs(b.uop.buffer, c.uop.buffer) + if __name__ == '__main__': unittest.main() diff --git a/test/test_tensor_uop.py b/test/test_tensor_uop.py index 72c9f3a661..21dfe41b57 100644 --- a/test/test_tensor_uop.py +++ b/test/test_tensor_uop.py @@ -3,15 +3,15 @@ import numpy as np import unittest from tinygrad import Tensor, Device, dtypes from tinygrad.engine.realize import run_schedule -from tinygrad.uop.ops import Ops, UOp, UPat +from tinygrad.uop.ops import UOp +from tinygrad.helpers import SPLIT_REDUCEOP class TestTensorUOp(unittest.TestCase): def test_fromcpu_shape_tracker(self): def helper(a: np.ndarray): print(a.shape, a.strides, a.flags.c_contiguous) b = Tensor(a).uop - #assert b.st.contiguous == a.flags.c_contiguous - assert b.st.shape == a.shape + assert b.shape == a.shape np.testing.assert_equal(a, Tensor(b).numpy()) for ndims in range(1, 4): @@ -93,30 +93,25 @@ class TestTensorUOp(unittest.TestCase): out.realize() self.assertEqual(out.tolist(), Tensor.zeros(4, 8).tolist()) -reduce_kernel = UPat(Ops.SINK, src=(UPat(Ops.STORE, allow_any_len=True, src=(UPat(), UPat((Ops.REDUCE_AXIS, Ops.REDUCE)))))) +@unittest.skipUnless(SPLIT_REDUCEOP, "only for SPLIT_REDUCEOP") class TestReduceOp(unittest.TestCase): def test_no_split_reduce_kernel(self): a = Tensor.rand(4, 4).realize() a = a.sum() sched = a.schedule() assert len(sched) == 1 - assert reduce_kernel.match(sched[0].ast, {}) def test_split_reduce_kernel_dim0(self): a = Tensor.rand(256, 255).realize() a = a.sum() sched = a.schedule() assert len(sched) == 2 - for s in sched: - assert reduce_kernel.match(s.ast, {}) def test_split_reduce_kernel_dim1(self): a = Tensor.rand(255, 256).realize() a = a.sum() sched = a.schedule() assert len(sched) == 2 - for s in sched: - assert reduce_kernel.match(s.ast, {}) if __name__ == "__main__": unittest.main() diff --git a/test/test_tensor_variable.py b/test/test_tensor_variable.py index a046555d1b..cbffc2dbb5 100644 --- a/test/test_tensor_variable.py +++ b/test/test_tensor_variable.py @@ -93,7 +93,7 @@ class TestTensorVariable(unittest.TestCase): vb = v.bind(3) t = Tensor.empty(3, vb) assert t.uop.base.buffer.size == 30 - assert t.uop.st.shape == (3, vb) + assert t.uop.shape == (3, vb) if __name__ == '__main__': diff --git a/test/test_tiny.py b/test/test_tiny.py index 31bb84f595..72f274a6b8 100644 --- a/test/test_tiny.py +++ b/test/test_tiny.py @@ -15,6 +15,10 @@ class TestTiny(unittest.TestCase): out = Tensor([1.,2,3]) self.assertListEqual(out.tolist(), [1.0, 2.0, 3.0]) + def test_elu(self): + out = Tensor([[1.,2],[3,4]]).sum(axis=1).elu() + self.assertListEqual(out.tolist(), [3.0, 7.0]) + def test_plus(self): out = Tensor([1.,2,3]) + Tensor([4.,5,6]) self.assertListEqual(out.tolist(), [5.0, 7.0, 9.0]) @@ -130,8 +134,8 @@ class TestTiny(unittest.TestCase): def test_mnist_backward(self): # NOTE: we don't have the whole model here for speed layers = [ - nn.Conv2d(1, 32, 5), Tensor.relu, - nn.Conv2d(32, 32, 5), Tensor.relu] + nn.Conv2d(1, 8, 5), Tensor.relu, + nn.Conv2d(8, 8, 5), Tensor.relu] # replace random weights with ones # TODO: there's a bug here where it's tying two of the biases together. we need UNIQUE const @@ -140,7 +144,7 @@ class TestTiny(unittest.TestCase): # realize gradients for x in nn.state.get_parameters(layers): x.requires_grad_() - Tensor.empty(4, 1, 28, 28).sequential(layers).sum().backward() + Tensor.empty(4, 1, 14, 14).sequential(layers).sum().backward() Tensor.realize(*[x.grad for x in nn.state.get_parameters(layers) if x.grad is not None]) # *** image *** diff --git a/test/test_transcendental.py b/test/test_transcendental.py index 932cfa2935..503286773c 100644 --- a/test/test_transcendental.py +++ b/test/test_transcendental.py @@ -149,6 +149,7 @@ class TestTranscendentalVectorized(unittest.TestCase): for vec_size in [1,2,3,4,5,127,128]: self._test_vectorized_op(Tensor.log2, np.log2, (0.001, 200), vec_size) @unittest.skipIf(getenv("DSP"), "requires int division") + @unittest.skipIf(getenv("NV_NAK"), "MUFU.SIN is not accurate enough") def test_sin_vectorized(self): for vec_size in [1,2,3,4,5,127,128]: self._test_vectorized_op(Tensor.sin, np.sin, (-100, 100), vec_size) diff --git a/test/test_uop_graph.py b/test/test_uop_graph.py index d5d75462f3..16aba5c44a 100644 --- a/test/test_uop_graph.py +++ b/test/test_uop_graph.py @@ -1,12 +1,11 @@ -from typing import List import unittest, pytest from tinygrad import dtypes, Variable from tinygrad.dtype import AddrSpace from tinygrad.helpers import DEBUG, Context -from tinygrad.uop.ops import Ops, UOp, UPat, PatternMatcher, track_rewrites, graph_rewrite, GroupOp, KernelInfo +from tinygrad.uop.ops import Ops, UOp, UPat, PatternMatcher, track_rewrites, graph_rewrite, GroupOp, AxisType from tinygrad.uop.symbolic import sym -from tinygrad.codegen import full_rewrite, full_rewrite_to_sink from tinygrad.codegen.late.expander import expander +from test.test_uops import to_uops_list simple_pm = PatternMatcher([ (UPat.cvar('x', dtypes.int), lambda x: UOp.const(dtypes.float, 1.0) + UOp.const(dtypes.float, 2.0)), @@ -15,12 +14,6 @@ simple_pm = PatternMatcher([ ((UPat.var('x') + UPat.cvar('c1')) + UPat.cvar('c2'), lambda x,c1,c2: x + (c1.arg+c2.arg)), ]) -def to_uops_list(u:List[UOp]) -> List[UOp]: - # we strip the SINK here for legacy reasons - ret = full_rewrite(UOp.sink(*u, arg=KernelInfo(opts_to_apply=()))) - assert ret[-1].op is Ops.SINK - return ret[:-1] - class TestGraphRewriteConst(unittest.TestCase): def test_gep_const(self): v1 = UOp.const(dtypes.int.vec(3), (0,1,2)) @@ -270,6 +263,7 @@ class TestUOpGraph(unittest.TestCase): uops = to_uops_list([out]) self.assertEqual(len([x for x in uops if x.op is Ops.VECTORIZE]), 0) + @unittest.skip("this test isn't valid uops") def test_gep_vec_fold(self): d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) d1 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 1) @@ -313,9 +307,10 @@ class TestUOpGraph(unittest.TestCase): for vec_size in [2, 4, 8]: consts = [UOp.const(dtypes.float, float(i)) for i in range(vec_size)] vec = UOp(Ops.VECTORIZE, dtypes.float.vec(vec_size), tuple(consts)) - uops = to_uops_list([UOp(Ops.GEP, dtypes.float, (vec,), (i,)) for i in range(vec_size)]) - for uop, const in zip(uops, consts): - self.assertEqual(uop, const) + with Context(SPEC=0): + uops = to_uops_list([UOp(Ops.GEP, dtypes.float, (vec,), (i,)) for i in range(vec_size)]) + for uop, const in zip(uops, consts): + self.assertEqual(uop, const) @unittest.skip("no longer testable standalone") def test_wmma_vectorize_fold(self): @@ -381,7 +376,7 @@ class TestUOpGraph(unittest.TestCase): d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.bool.ptr(), arg=0) d1 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), arg=1) idx = UOp.const(dtypes.int, 0) - ld = UOp(Ops.LOAD, dtypes.int, (d1.index(idx),)) + ld = d1.index(idx) alu = (ld<1).cast(dtypes.bool) out = UOp(Ops.STORE, dtypes.void, (d0.index(idx), alu)) uops = to_uops_list([out]) @@ -391,7 +386,7 @@ class TestUOpGraph(unittest.TestCase): d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), arg=0) d1 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), arg=1) idx = UOp.const(dtypes.int, 0) - ld = UOp(Ops.LOAD, dtypes.int, (d1.index(idx),)) + ld = d1.index(idx) alu = ld.cast(dtypes.float).cast(dtypes.float) out = UOp(Ops.STORE, dtypes.void, (d0.index(idx), alu)) uops = to_uops_list([out]) @@ -413,7 +408,7 @@ class TestUOpGraph(unittest.TestCase): def test_bitcast_to_same_dtype_fold(self): for dt in dtypes.ints + dtypes.floats + (dtypes.bool,): d0 = UOp(Ops.DEFINE_GLOBAL, dt.ptr(), arg=0) - v = UOp(Ops.LOAD, dt, (d0.index(UOp.const(dtypes.int, 0)),)) + v = d0.index(UOp.const(dtypes.int, 0)) uops = to_uops_list([v.bitcast(dt)]) self.assertEqual(len([x for x in uops if x.op is Ops.BITCAST]), 0, f"dtype = {dt}") @@ -425,7 +420,7 @@ class TestUOpGraph(unittest.TestCase): def test_where_on_gated_load_fold(self): ridx0 = UOp.range(100, 0) d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.long.ptr(), (), 0) - ld = d0.index(ridx0.valid(ridx0<50)).load() + ld = d0.index(ridx0.valid(ridx0<50)) w = (ridx0<50).where(ld, 5) uops = to_uops_list([w]) for u in uops: @@ -435,7 +430,7 @@ class TestUOpGraph(unittest.TestCase): def test_where_on_gated_load_folds_swapped_branches(self): ridx0 = UOp.range(100, 0) d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.long.ptr(), (), 0) - ld = d0.index(ridx0.valid((ridx0<50).logical_not())).load() + ld = d0.index(ridx0.valid((ridx0<50).logical_not())) w = (ridx0<50).where(5, ld) uops = to_uops_list([w]) for u in uops: @@ -446,7 +441,7 @@ class TestUOpGraph(unittest.TestCase): ridx0 = UOp.range(100, 0) d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 0) gate_idx = ridx0.valid((ridx0<50)) - ld = d0.index(gate_idx).load().cast(dtypes.float) + ld = d0.index(gate_idx).cast(dtypes.float) w = (ridx0<50).where(ld, 5.0) uops = to_uops_list([w]) for u in uops: @@ -459,65 +454,65 @@ class TestUOpGraph(unittest.TestCase): idx = d0.index(ridx0) ld = idx.load() val = (ridx0<50).where(5, ld) - st = idx.store(val, ridx0) + st = idx.store(val).end(ridx0) uops = to_uops_list([st]) for u in uops: assert u.op is not Ops.WHERE if u.op is Ops.STORE: assert u.src[1].arg==5 def test_load_idx_becomes_int(self): - # These loads wont overflow int since we know from the gate that the value is bounded - r0 = UOp.range(10, 0) - d0 = UOp(Ops.DEFINE_GLOBAL, dtypes.long.ptr(), (), 0) - d1 = UOp(Ops.DEFINE_GLOBAL, dtypes.long.ptr(), (), 1) - l0 = UOp(Ops.LOAD, dtypes.long, (d0.index(UOp.const(dtypes.int, 0)),)).cast(dtypes.index) - idx = l0 * 600 - valid = (l0<-1).ne(True)&(l0<3000) - l1 = UOp(Ops.LOAD, dtypes.long, (d1.index(idx.valid(valid)),)) - uops = to_uops_list([l1]) + # mnist indexing with split reduceop + # Make sure we are not doign math on the loaded index, which would promote it to long + c0 = UOp(Ops.DEFINE_GLOBAL, dtypes.uchar.ptr(128000), arg=0, src=()) + c1 = UOp.range(UOp.const(dtypes.index, 512), 1, AxisType.LOOP) + c2 = UOp.range(UOp.const(dtypes.index, 250), 2, AxisType.LOOP) + c3 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(512), arg=1, src=()) + c4 = c3.index(c1) + c5 = UOp.range(UOp.const(dtypes.index, 240), 0, AxisType.REDUCE) + c6 = ((c2*UOp.const(dtypes.index, 240))+c5) + c7 = UOp(Ops.DEFINE_GLOBAL, dtypes.uchar.ptr(60000), arg=2, src=()) + c8 = c7.index(c6) + c9 = ((c4<0).where((c4+60000), c4)!=c6.cast(dtypes.int)).where(0, c8.cast(dtypes.uint).cast(dtypes.uchar)).reduce(c5, arg=Ops.ADD) + c10 = c0.index(((c1*UOp.const(dtypes.index, 250))+c2)).store(c9).end(c1, c2) + uops = to_uops_list([c10]) for u in uops: - if u.op is Ops.INDEX: self.assertEqual(u.src[1].dtype, dtypes.int) - - valid = (10*r0<5-l0).ne(True)&(l0<3000) - l2 = UOp(Ops.LOAD, dtypes.long, (d1.index(idx.valid(valid)),)) - uops = to_uops_list([l2]) - for u in uops: - if u.op is Ops.INDEX: self.assertEqual(u.src[1].dtype, dtypes.int) + self.assertNotEqual(u.dtype, dtypes.long) def test_in_out_of_bounds_access(self): with Context(IGNORE_OOB=0): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), (), 0) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 0)),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 0), ptr=True),)) to_uops_list([ld0]) - ld1 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 15)),)) + ld1 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 15), ptr=True),)) to_uops_list([ld1]) - ld1 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 7)),)) + ld1 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 7), ptr=True),)) to_uops_list([ld1]) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 42)),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 42), ptr=True),)) with self.assertRaises(RuntimeError): to_uops_list([ld0]) def test_in_out_of_bounds_access_symbolic(self): with Context(IGNORE_OOB=0): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), (), 0) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(Variable("i", 1, 10)),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(Variable("i", 1, 10), ptr=True),)) to_uops_list([ld0]) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(Variable("i", 0, 15)),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(Variable("i", 0, 15), ptr=True),)) to_uops_list([ld0]) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(Variable("i", 0, 20)),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(Variable("i", 0, 20), ptr=True),)) with self.assertRaises(RuntimeError): to_uops_list([ld0]) def test_in_out_of_bounds_access_gated_store(self): with Context(IGNORE_OOB=0): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), src=(), arg=0) v = Variable("v", 0, 20) - st0 = UOp(Ops.STORE, dtypes.void, src=(glbl0.index(v, v<16), UOp.const(dtypes.int, 0))) + st0 = UOp(Ops.STORE, dtypes.void, src=(glbl0.index(v.valid(v<16)), UOp.const(dtypes.int, 0))) 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.valid(v<20)), v)) with self.assertRaises(RuntimeError): to_uops_list([st1]) + @unittest.skip("if not allowed in graph") def test_in_bounds_access_gated_local(self): with Context(IGNORE_OOB=0): # Define buffers @@ -536,7 +531,7 @@ class TestUOpGraph(unittest.TestCase): if_barrier = UOp(Ops.IF, dtypes.void, (gate, barrier)) # Load from local memory (after the IF/barrier) - local_load = UOp(Ops.LOAD, dtypes.uint, (sbuf.index(lidx), if_barrier)) + local_load = UOp(Ops.LOAD, dtypes.uint, (sbuf.index(lidx, ptr=True), if_barrier)) # Store to global memory global_store = UOp(Ops.STORE, dtypes.void, (gbuf.index(gidx), local_load)) @@ -547,18 +542,18 @@ class TestUOpGraph(unittest.TestCase): ridx = UOp.range(20, 0) glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), (), 0) i = (ridx.cast(dtypes.float)*0.68).trunc().cast(dtypes.int) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(i, ((0<=i)&(i<16))),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(i.valid((0<=i)&(i<16)), ptr=True),)) to_uops_list([ld0]) glblfloat = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(20), (), 0) ldfloat = UOp(Ops.LOAD, dtypes.float, (glblfloat.index(ridx),)) i = (ldfloat+3.14).cast(dtypes.int) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(i, ((0<=i)&(i<16))),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(i, ((0<=i)&(i<16)), ptr=True),)) def test_load_cast_to_bool(self): with Context(IGNORE_OOB=0): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(1), (), 0) ridx = UOp.range(20, 0) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(ridx, ridx.cast(dtypes.bool).logical_not()),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(ridx.valid(ridx.cast(dtypes.bool).logical_not()), ptr=True),)) to_uops_list([ld0]) @unittest.skip("Bool load is not supported yet") @@ -567,48 +562,48 @@ class TestUOpGraph(unittest.TestCase): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), (), 0) mask = UOp(Ops.DEFINE_GLOBAL, dtypes.bool.ptr(16), (), 0) ridx = UOp.range(20, 0) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(ridx, ridx<16&mask),))) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(ridx, ridx<16&mask), ptr=True))) to_uops_list([ld0]) def test_out_of_bounds_off_by_one_access(self): with Context(IGNORE_OOB=0): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), (), 0) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 16)),)) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(UOp.const(dtypes.int, 16), ptr=True),)) with self.assertRaises(RuntimeError): to_uops_list([ld0]) def test_in_out_bounds_access_with_mask(self): with Context(IGNORE_OOB=0): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(16), (), 0) - gidx0 = UOp(Ops.SPECIAL, dtypes.index, (UOp.const(dtypes.index, 42),), "gidx0") - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(gidx0, (5=0)&(ld0<32)),)) + gidx0 = UOp.range(42, 0, AxisType.GLOBAL) + ld0 = UOp(Ops.LOAD, dtypes.int, (glbl0.index(gidx0.valid(gidx0<8), ptr=True),)).cast(dtypes.index) + ld1 = UOp(Ops.LOAD, dtypes.int, (glbl1.index((ld0*2).valid((ld0>=0)&(ld0<32)), ptr=True),)) to_uops_list([ld1]) - ld1 = UOp(Ops.LOAD, dtypes.int, (glbl1.index(ld0*2, (ld0>=0)&(ld0<64)),)) + ld1 = UOp(Ops.LOAD, dtypes.int, (glbl1.index((ld0*2).valid((ld0>=0)&(ld0<64)), ptr=True),)) with self.assertRaises(RuntimeError): to_uops_list([ld1]) def test_bounds_with_loaded_bool(self): @@ -616,8 +611,8 @@ class TestUOpGraph(unittest.TestCase): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.bool.ptr(16), (), 0) glbl1 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(8), (), 0) gidx0 = UOp(Ops.SPECIAL, dtypes.index, (UOp.const(dtypes.index, 16),), "gidx0") - ld0 = glbl0.index(gidx0).load() - ld1 = glbl1.index(gidx0.valid(ld0)).load() + ld0 = glbl0.index(gidx0, ptr=True).load() + ld1 = glbl1.index(gidx0.valid(ld0), ptr=True).load() with self.assertRaises(RuntimeError): to_uops_list([ld1]) def test_fold_gated_load(self): @@ -625,38 +620,38 @@ class TestUOpGraph(unittest.TestCase): glbl1 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 1) glbl2 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 2) idx = UOp.const(dtypes.int, 0) - ld0 = UOp(Ops.LOAD, dtypes.int, (glbl1.index(UOp.invalid()),)) - ld1 = UOp(Ops.LOAD, dtypes.int, (glbl2.index(idx, UOp.const(dtypes.bool, True)),)) + ld0 = glbl1.index(UOp.invalid()) + ld1 = glbl2.index(idx.valid(UOp.const(dtypes.bool, True))) uops = to_uops_list([UOp(Ops.STORE, dtypes.void, (glbl0.index(idx), ld1+ld0))]) ld0 = uops[-1].src[-1] # the gate and invalid value are deleted from ld1 - self.assertEqual(ld0, UOp.load(glbl2.index(idx), dtype=dtypes.int)) + self.assertEqual(ld0, UOp.load(glbl2.index(idx, ptr=True), dtype=dtypes.int)) def test_fold_gated_load_local(self): glbl0 = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 0) smem = UOp(Ops.DEFINE_LOCAL, dtypes.int.ptr(size=18, addrspace=AddrSpace.LOCAL), (), "temp") lidx = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 16),), "lidx0") - st = UOp(Ops.STORE, dtypes.void, (smem.index(lidx), UOp.load(glbl0.index(lidx), dtype=dtypes.int))) + st = UOp(Ops.STORE, dtypes.void, (smem.index(lidx, ptr=True), glbl0.index(lidx, ptr=True).load())) barrier = UOp(Ops.BARRIER, dtypes.void, (st, )) - ld0 = UOp(Ops.LOAD, dtypes.int, (smem.index(UOp.invalid()), barrier)) - ld1 = UOp(Ops.LOAD, dtypes.int, (smem.index(lidx+2, UOp.const(dtypes.bool, True)), barrier)) + ld0 = smem.after(barrier).index(UOp.invalid()) + ld1 = smem.after(barrier).index((lidx+2).valid(UOp.const(dtypes.bool, True))) uops = to_uops_list([UOp(Ops.STORE, dtypes.void, (glbl0.index(lidx), ld1+ld0))]) ld0 = uops[-1].src[-1] # the gate and invalid value are deleted from ld1 - self.assertEqual(ld0.src[0], smem.index(lidx+2)) + self.assertEqual(ld0.src[0], smem.after(barrier).index(lidx+2, ptr=True)) def test_fold_gated_store(self): glbl = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 0) idx0 = UOp.const(dtypes.int, 0) idx1 = UOp.const(dtypes.int, 0) val = UOp.const(dtypes.int, 42) - st0 = glbl.index(UOp.invalid()).store(val) - st1 = glbl.index(idx0, UOp.const(dtypes.bool, True)).store(val) + st0 = glbl.index(UOp.invalid(), ptr=True).store(val) + st1 = glbl.index(idx0.valid(UOp.const(dtypes.bool, True)), ptr=True).store(val) uops = to_uops_list([st0, st1]) # only the second store happens self.assertEqual(len(uops), 5) - self.assertEqual(uops[-1], glbl.index(idx1).store(val)) + self.assertEqual(uops[-1], glbl.index(idx1, ptr=True).store(val)) @unittest.skip("this is a uop type error") def test_asserts_bad_gate(self): @@ -665,19 +660,6 @@ class TestUOpGraph(unittest.TestCase): bad_gate = UOp.const(dtypes.int, 1) with self.assertRaises(AssertionError): to_uops_list([UOp(Ops.STORE, dtypes.void, (glbl0, idx, UOp.const(dtypes.int, 42), bad_gate))]) - def test_switched_range_order(self): - glbl = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), (), 0) - cf = UOp.const(dtypes.float, 0.0) - r1 = UOp.range(2, 0) - r2 = UOp.range(2, 1) - alu = UOp(Ops.MUL, dtypes.int, (r2, r1)) - store = UOp(Ops.STORE, dtypes.void, (glbl.index(alu), cf)) - uops = to_uops_list([store]) - ranges = [x for x in uops if x.op is Ops.RANGE] - endranges = [x for x in uops if x.op is Ops.ENDRANGE] - # ranges are closed in the right order - self.assertEqual(endranges[-1].src[0], ranges[0]) - @track_rewrites() def expander_rewrite(sink): return graph_rewrite(sink, sym + expander) @@ -739,7 +721,7 @@ class TestExpander(unittest.TestCase): self.assertTupleEqual(sink.src[0].arg, (0,2,1,3,4,6,5,7)) def test_contract_no_expand(self): - e1 = UOp(Ops.DEFINE_VAR, dtypes.int) + e1 = UOp.variable("i", 0, 10, dtype=dtypes.int) con = UOp(Ops.CONTRACT, dtypes.int.vec(2), (e1,), ((2,2),)) sink = expander_rewrite(con) assert sink.op is Ops.VECTORIZE and len(sink.src) == 2 @@ -828,60 +810,6 @@ class TestExpander(unittest.TestCase): sink = expander_rewrite(sink) print(sink) -class TestIFUOps(unittest.TestCase): - def test_create_ifs(self): - gbuf = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) - sbuf = UOp(Ops.DEFINE_LOCAL, dtypes.float.ptr(size=4, addrspace=AddrSpace.LOCAL), (), "smem") - valid = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 10),), "gidx0")<5 - lidx = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 4),), "lidx0") - gate = valid&(lidx.ne(2)) - idx = UOp.const(dtypes.int, 0) - st = UOp(Ops.STORE, dtypes.void, (sbuf.index(idx), UOp.const(dtypes.float, 42))) - barrier = UOp(Ops.BARRIER, dtypes.void, (st,)) - lbuf = UOp(Ops.LOAD, dtypes.float, (sbuf.index(UOp.const(dtypes.int, 0)), barrier)) - store = UOp(Ops.STORE, dtypes.void, (gbuf.index(UOp.const(dtypes.int, 0), gate), lbuf)) - sink = UOp(Ops.SINK, dtypes.void, (store,)) - sink = full_rewrite_to_sink(sink) - if_uops = [u for u in sink.toposort() if u.op is Ops.IF] - self.assertEqual(len(if_uops), 1) - self.assertEqual(if_uops[0].src[0], gate) - for st in sink.src: - self.assertEqual(len(st.src), 2) - - def test_expand_ifs_one_gate(self): - gbuf = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) - sbuf = UOp(Ops.DEFINE_LOCAL, dtypes.float.ptr(size=16, addrspace=AddrSpace.LOCAL), (), "smem") - valid = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 4),), "gidx0")<1 - lidx = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 16),), "lidx0") - gate = valid&(lidx.ne(2)) - st = UOp(Ops.STORE, dtypes.void, (sbuf, lidx, UOp.const(dtypes.float, 42))) - barrier = UOp(Ops.BARRIER, dtypes.void, (st,)) - lbufs = [UOp(Ops.LOAD, dtypes.float, (sbuf.index(UOp.const(dtypes.int, i)), barrier)) for i in range(4)] - stores = [UOp(Ops.STORE, dtypes.void, (gbuf.index(UOp.const(dtypes.int, i), gate), lbufs[i])) for i in range(4)] - sink = UOp(Ops.SINK, dtypes.void, tuple(stores)) - sink = full_rewrite_to_sink(sink) - if_uops = [u for u in sink.toposort() if u.op is Ops.IF] - self.assertEqual(len(if_uops), 1) - self.assertEqual(if_uops[0].src[0], gate) - for st in sink.src: - self.assertEqual(len(st.src), 2) - - # this will be fixed with the merge gated stores bounty - @unittest.expectedFailure - def test_expand_ifs_dumb(self): - buf = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) - valid = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 10),), "gidx0")<5 - lidx = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 4),), "lidx0") - gate = valid&(lidx.ne(2)) - stores = [UOp(Ops.STORE, dtypes.void, (buf, UOp.const(dtypes.int, i), UOp.const(dtypes.float, i), gate)) for i in range(4)] - sink = UOp(Ops.SINK, dtypes.void, tuple(stores)) - sink = full_rewrite_to_sink(sink) - if_uops = [u for u in sink.toposort() if u.op is Ops.IF] - self.assertEqual(len(if_uops), 1) - self.assertEqual(if_uops[0].src[0], gate) - for st in sink.src: - self.assertEqual(len(st.src), 2) - class TestUOpTags(unittest.TestCase): def test_inc_by_one(self): g = UOp.const(dtypes.int, 1) + UOp.const(dtypes.int, 1) diff --git a/test/test_uops.py b/test/test_uops.py index 0f22c56816..64fd5bee6f 100644 --- a/test/test_uops.py +++ b/test/test_uops.py @@ -1,26 +1,30 @@ from typing import Optional, Any import unittest, math import numpy as np -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View # noqa F401 from tinygrad.tensor import Tensor, _to_np_dtype -from tinygrad.helpers import CI, DEBUG, getenv, Timing +from tinygrad.helpers import CI, DEBUG, getenv, Timing, Context from tinygrad.dtype import dtypes, DType, AddrSpace from tinygrad.device import Buffer, Device -from tinygrad.uop.ops import Ops, UOp, UPat, KernelInfo, exec_alu # noqa F401 -from tinygrad.uop.spec import spec +from tinygrad.uop.ops import Ops, UOp, UPat, KernelInfo, exec_alu, AxisType +from tinygrad.uop.spec import shared_spec from tinygrad.renderer import ProgramSpec -from tinygrad.engine.realize import CompiledRunner, get_program +from tinygrad.engine.realize import CompiledRunner, get_program, get_runner, ExecItem from tinygrad.codegen import full_rewrite from tinygrad.uop.symbolic import sym from tinygrad.device import is_dtype_supported from tinygrad.codegen.opt import Opt, OptOps from tinygrad.renderer.ptx import PTXRenderer -def to_uops_list(u:list[UOp], opts=None, skip_check=False) -> list[UOp]: return full_rewrite(UOp.sink(*u), opts) +def to_uops_list(u:list[UOp], ren=None) -> list[UOp]: + sink = UOp.group(*u) + for r in sink.ranges: sink = sink.end(r) + # we strip the SINK here for legacy reasons + ret = full_rewrite(sink.sink(arg=KernelInfo(opts_to_apply=())), ren) + assert ret[-1].op is Ops.SINK + return ret[:-1] def _uops_to_prg(uops_list): - uops = full_rewrite(ast:=UOp.sink(*uops_list), opts=Device[Device.DEFAULT].renderer) + uops = full_rewrite(ast:=UOp.sink(*uops_list), ren=Device[Device.DEFAULT].renderer) src = Device[Device.DEFAULT].renderer.render(uops) has_local = Device[Device.DEFAULT].renderer.has_local return CompiledRunner(ProgramSpec(uops[-1].arg.name if uops[-1].arg is not None else "test", src, Device.DEFAULT, ast, uops=uops, @@ -35,9 +39,9 @@ def _test_single_value(vals, op, dts): output_dtype = dtypes.bool if op in (Ops.CMPLT, Ops.CMPNE) else dts[-1] buf_store = uop(uops, Ops.DEFINE_GLOBAL, output_dtype.ptr(), (), 0) buf_loads = [uop(uops, Ops.DEFINE_GLOBAL, dtype.ptr(), (), i+1) for i,dtype in enumerate(dts)] - loads = (uop(uops, Ops.LOAD, dtype, [buf_loads[i].index(uop(uops, Ops.CONST, dtypes.int32, (), 0))]) for i, dtype in enumerate(dts)) + loads = (buf_loads[i].index(uop(uops, Ops.CONST, dtypes.int32, (), 0)) for i, dtype in enumerate(dts)) alu = uop(uops, op, output_dtype, loads) - out = uop(uops, Ops.STORE, dtypes.void, (buf_store.index(uop(uops, Ops.CONST, dtypes.int32, (), 0)), alu)) + out = uop(uops, Ops.STORE, dtypes.void, (buf_store.index(uop(uops, Ops.CONST, dtypes.int32, (), 0), ptr=True), alu)) buf = Buffer(Device.DEFAULT, 1, output_dtype).allocate() buf2 = [Buffer(Device.DEFAULT, 1, dtype).allocate().copyin(np.array([a], dtype=_to_np_dtype(dtype)).data) for a,dtype in zip(vals, dts)] prg = _uops_to_prg([out]) @@ -52,7 +56,7 @@ def _test_single_value_const(vals, op, dts): buf_store = uop(uops, Ops.DEFINE_GLOBAL, output_dtype.ptr(), (), 0) loads = (uop(uops, Ops.CONST, dtype, [], a) for a,dtype in zip(vals, dts)) alu = uop(uops, op, output_dtype, loads) - out = uop(uops, Ops.STORE, dtypes.void, (buf_store.index(uop(uops, Ops.CONST, dtypes.int32, (), 0)), alu)) + out = buf_store[UOp.const(dtypes.int32, 0)].store(alu) buf = Buffer(Device.DEFAULT, 1, output_dtype).allocate() prg = _uops_to_prg([out]) prg.exec([buf]) @@ -111,7 +115,7 @@ class TestFloatUOps(TestUOps): def test_log2(self): self._test_uop_fxn(Ops.LOG2, lambda a: math.log2(a) if a > 0 else float('-inf' if a==0 else 'nan')) @unittest.skipIf(Device.DEFAULT == "CPU", 'not supported as uop') def test_sin(self): self._test_uop_fxn(Ops.SIN, lambda a: math.sin(a)) - def test_recip(self): self._test_uop_fxn(Ops.RECIP, lambda a: 1/a if a != 0 else float('inf')) + def test_recip(self): self._test_uop_fxn(Ops.RECIPROCAL, lambda a: 1/a if a != 0 else float('inf')) def test_sqrt(self): self._test_uop_fxn(Ops.SQRT, lambda a: math.sqrt(a) if a >= 0 else float('nan')) def test_add(self): self._test_bop_fxn(Ops.ADD, lambda a,b: a+b) @@ -214,18 +218,18 @@ class TestExecALU(TestUOps): self.assertEqual(exec_alu(Ops.IDIV, dtypes.int8, (7, -3)), -2) self.assertEqual(exec_alu(Ops.IDIV, dtypes.int8, (-50, 6)), -8) - np.testing.assert_allclose(exec_alu(Ops.MUL, dtypes.float32, (7.0, exec_alu(Ops.RECIP, dtypes.float32, (3.0,)))), 2+(1.0/3.0)) - np.testing.assert_allclose(exec_alu(Ops.MUL, dtypes.float32, (7.0, exec_alu(Ops.RECIP, dtypes.float32, (-3.0,)))), -2-(1.0/3.0)) + np.testing.assert_allclose(exec_alu(Ops.MUL, dtypes.float32, (7.0, exec_alu(Ops.RECIPROCAL, dtypes.float32, (3.0,)))), 2+(1.0/3.0)) + np.testing.assert_allclose(exec_alu(Ops.MUL, dtypes.float32, (7.0, exec_alu(Ops.RECIPROCAL, dtypes.float32, (-3.0,)))), -2-(1.0/3.0)) def test_recip(self): - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, (8,)), 1/8) - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, (7,)), 1/7) - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, (-3,)), 1/-3) - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, (-50,)), 1/-50) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, (8,)), 1/8) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, (7,)), 1/7) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, (-3,)), 1/-3) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, (-50,)), 1/-50) - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, ((32+521+3),)), 1/(32+521+3)) - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, ((34**2),)), 1/(34**2)) - np.testing.assert_allclose(exec_alu(Ops.RECIP, dtypes.float32, (10,)), 1/10) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, ((32+521+3),)), 1/(32+521+3)) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, ((34**2),)), 1/(34**2)) + np.testing.assert_allclose(exec_alu(Ops.RECIPROCAL, dtypes.float32, (10,)), 1/10) def test_bool_cmplt(self): self.assertEqual(exec_alu(Ops.CMPLT, dtypes.bool, (False, False)), False) @@ -273,7 +277,7 @@ class TestGatedStoreRewrite(unittest.TestCase): gmem = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) gidx0 = UOp(Ops.SPECIAL, dtypes.int, (UOp.const(dtypes.int, 4),), 'gidx0') gate = gidx0>6)*18725)>>17) instead of (int)((((long)(ridx0)*1198373)>>29)) @@ -453,9 +458,8 @@ class TestAssembly(unittest.TestCase): def test_use_cmpeq(self): g = UOp(Ops.DEFINE_GLOBAL, dtypes.uint32.ptr(), (), 0) c = UOp(Ops.CONST, dtypes.uint, (), 7) - l = UOp(Ops.LOAD, dtypes.uint, (g.index(c),)) - comp = l.ne(c).ne(True) - uops = to_uops_list([comp], opts=Device[Device.DEFAULT].renderer) + comp = g.index(c).ne(c).ne(True) + uops = to_uops_list([comp], ren=Device[Device.DEFAULT].renderer) Device[Device.DEFAULT].renderer.render(uops) ops = [x.op for x in uops] self.assertIn(Ops.CMPEQ, ops) @@ -492,15 +496,6 @@ class TestUOpMethod(unittest.TestCase): self.assertIs(x.replace(arg=None).arg, None) with self.assertRaises(AssertionError): x.replace(field="a") - def test_device(self): - x = UOp(Ops.VIEW, dtypes.int, (UOp.new_buffer(Device.DEFAULT, 1, dtypes.int), UOp.const(dtypes.int, 1)), ShapeTracker.from_shape(())) - self.assertEqual(x.device, Device.DEFAULT) - # NOTE: CONST doesn't have device - buffer, const = x.src - self.assertEqual(buffer.device, Device.DEFAULT) - self.assertEqual(const._device, None) - with self.assertRaises(AssertionError): const.device - class TestUOpStr(unittest.TestCase): def test_uop_str(self): a = UOp(Ops.CONST, dtypes.float, (), 2.0) + UOp(Ops.CONST, dtypes.float, (), 3.0) @@ -522,8 +517,8 @@ class TestUOpStr(unittest.TestCase): class TestUPatHelpers(unittest.TestCase): def test_location(self): - self.assertEqual(sym.patterns[-1][0].location[0].replace("\\", "/").split("/")[-1], "symbolic.py") - self.assertEqual(spec.patterns[0][0].location[0].replace("\\", "/").split("/")[-1], "spec.py") + self.assertEqual(sym.patterns[-1][0].location[0].replace("\\", "/").split("/")[-1], "math.py") + self.assertEqual(shared_spec.patterns[0][0].location[0].replace("\\", "/").split("/")[-1], "spec.py") test_upat = UPat(Ops.CONST, dtypes.bool) self.assertEqual(test_upat.location[0].split("/")[-1], __file__.replace("\\", "/").split("/")[-1]) test_upat_named = test_upat.named("test_name") @@ -544,29 +539,99 @@ class TestUopsObject(unittest.TestCase): with Timing("create 10k uops:"): ret = [UOp(Ops.CONST, dtypes.int, arg=10000000+i) for i in range(10000)] assert len(ret) == 10000 -class TestUOpChildren(unittest.TestCase): - def test_children_exist(self): - a = UOp.variable("weird_name_234", 0, 10) - b = a*a - self.assertEqual(len(a.children), 1) - self.assertIs(list(a.children)[0](), b) + def test_nested(self): + a = UOp.new_buffer(Device.DEFAULT, 1, dtypes.char) + for _ in range(10_000): a = a+a + self.assertEqual(a.device, Device.DEFAULT) - def test_children_cleaned_up(self): - a = UOp.variable("weird_name_235", 0, 10) - b = a*a - self.assertEqual(len(a.children), 1) - del b - self.assertEqual(len(a.children), 0) +class TestUOpRender(unittest.TestCase): + def test_render_vectorize_same(self): + u = UOp(Ops.VECTORIZE, dtype=dtypes.int.vec(3), src=(UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 0))) + self.assertEqual(u.render(simplify=False), "{0, ...}") + def test_render_vectorize_different(self): + u = UOp(Ops.VECTORIZE, dtype=dtypes.int.vec(3), src=(UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 1), UOp.const(dtypes.int, 2))) + self.assertEqual(u.render(simplify=False), "{0,1,2}") + def test_render_vectorize_same_simplified(self): + u = UOp(Ops.VECTORIZE, dtype=dtypes.int.vec(3), src=(UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 0))) + self.assertEqual(u.render(), "0") + def test_render_vectorize_different_simplified(self): + u = UOp(Ops.VECTORIZE, dtype=dtypes.int.vec(3), src=(UOp.const(dtypes.int, 0), UOp.const(dtypes.int, 1), UOp.const(dtypes.int, 2))) + self.assertEqual(u.render(), "(0, 1, 2)") - def test_children_cleaned_up_two(self): - a = UOp.variable("weird_name_236", 0, 10) - b = a*a - c = a*2 - self.assertEqual(len(a.children), 2) - del b - self.assertEqual(len(a.children), 1) - del c - self.assertEqual(len(a.children), 0) +class TestZeroRange(unittest.TestCase): + def test_reduce_variable(self): + for i in range(3,-1,-1): + v = UOp.variable("i", 0, 5).bind(i) + out = Tensor.ones(10, dtype=dtypes.int).contiguous().shrink(((0,v),)).sum() + self.assertEqual(out.item(), i) + +class TestUOpPrograms(unittest.TestCase): + def _run(self, prog:UOp, *tensors:Tensor): + ExecItem(get_runner(Device.DEFAULT, prog), [t.uop.buffer for t in tensors]).run(wait=True) + + def test_simple(self): + out = Tensor.empty(10,10,dtype=dtypes.int) + + ptr = UOp.placeholder(out.shape, out.dtype, slot=0) + i, j = UOp.range(10, axis_id=0), UOp.range(10, axis_id=1) + prog = ptr[i,j].set(42).end(i,j) + self._run(prog.sink(), out) + + with Context(DEBUG=0): self.assertTrue((out == 42).all().item()) + + def test_matmul(self): + a = Tensor.randn(10,10) + b = Tensor.randn(10,10) + c = Tensor.empty(10,10) + ref = (a@b) + with Context(DEBUG=0): Tensor.realize(a, b, c, ref) + + # C[i,j] = sum_k A[i,k] * B[k,j] + # Shapes: A[M,K], B[K,N], C[M,N] + M = N = K = 10 + DT = dtypes.float32 + + # Placeholders (bind slots explicitly) + A = UOp.placeholder((M, K), DT, slot=0) + B = UOp.placeholder((K, N), DT, slot=1) + C = UOp.placeholder((M, N), DT, slot=2) + + # Axes: i,j are spatial; k is a reduction axis over the shared dim K + i = UOp.range(M, axis_id=0) # rows of A/C + j = UOp.range(N, axis_id=1) # cols of B/C + k = UOp.range(K, axis_id=2, axis_type=AxisType.REDUCE) # reduction over K + + # Zero-init: write a scalar 0 to each (i,j). + C = C[i, j].set(0.0) + + # Accumulate: C_after(k) enforces the dependency along the reduction axis + C = C[i, j].set(C.after(k)[i, j] + A[i, k] * B[k, j]) + + # Finalize the loop nest / schedule in (i, j, k) order + prog = C.end(i, j, k) + + # run program + # TODO: make this work with opts_to_apply + self._run(prog.sink(arg=KernelInfo(opts_to_apply=())), a, b, c) + + with Context(DEBUG=0): self.assertLessEqual((c-ref).square().mean().item(), 1e-6) + + def test_matmul_relu(self): + a, b, c = Tensor.randn(10,10), Tensor.randn(10,10), Tensor.empty(10,10) + ref = (a@b).relu() + with Context(DEBUG=0): Tensor.realize(a, b, c, ref) + + A, B, C = a.uop.placeholder_like(0), b.uop.placeholder_like(1), c.uop.placeholder_like(2) + i, j, k = UOp.range(10, 0), UOp.range(10, 1), UOp.range(10, 2, axis_type=AxisType.REDUCE) + + C = C[i, j].set(0.0) + C = C[i, j].set(C.after(k)[i, j] + A[i, k] * B[k, j], end=k) + C = C[i, j].set(C[i, j].maximum(0.0)) + + prog = C.end(i, j) + + self._run(prog.sink(arg=KernelInfo(opts_to_apply=())), a, b, c) + with Context(DEBUG=0): self.assertLessEqual((c-ref).square().mean().item(), 1e-6) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/test/test_uops_stats.py b/test/test_uops_stats.py index 83dfcf0be6..1aff484ab6 100644 --- a/test/test_uops_stats.py +++ b/test/test_uops_stats.py @@ -1,6 +1,6 @@ import unittest from tinygrad import Tensor -from tinygrad.helpers import getenv, GlobalCounters, EMULATE, RANGEIFY +from tinygrad.helpers import getenv, GlobalCounters, EMULATE from tinygrad.engine.realize import lower_schedule_item, ProgramSpec, get_program from tinygrad.renderer import Estimates from tinygrad.codegen import full_rewrite @@ -51,11 +51,8 @@ class TestMemoryCount(unittest.TestCase): a = Tensor.empty(1024, 1, dtype=dtypes.uint8).expand(1024, 1024) b = Tensor.empty(1024, 1, dtype=dtypes.uint8).expand(1024, 1024) _, mem = get_stats(a+b) - if RANGEIFY: - # rangeify is smart! - self.assertEqual(mem, 1024 + 2*1024) # 2 lil reads + 1 lil write - else: - self.assertEqual(mem, 1024*1024 + 2*1024) # 2 lil reads + 1 write + # rangeify is smart! + self.assertEqual(mem, 1024 + 2*1024) # 2 lil reads + 1 lil write def test_self_add(self): a = Tensor.empty(1024, 1024, dtype=dtypes.uint8) @@ -144,8 +141,8 @@ class TestUOpsStats(unittest.TestCase): globl = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), tuple()) o1 = UOp(Ops.CONST, dtypes.int, tuple(), 1) o2 = UOp(Ops.CONST, dtypes.int, tuple(), 2) - u1 = UOp(Ops.LOAD, dtypes.int, (globl.index(o1),)) - u2 = UOp(Ops.LOAD, dtypes.int, (globl.index(o2),)) + u1 = globl.index(o1) + u2 = globl.index(o2) u3 = UOp(Ops.CONST, dtypes.int, tuple(), 3) u4 = UOp(Ops.MUL, dtypes.int, (u1,u2)) u5 = UOp(Ops.ADD, dtypes.int, (u4,u3)) @@ -154,8 +151,8 @@ class TestUOpsStats(unittest.TestCase): globl = UOp(Ops.DEFINE_GLOBAL, dtypes.int.ptr(), tuple()) o1 = UOp(Ops.CONST, dtypes.int, tuple(), 1) o2 = UOp(Ops.CONST, dtypes.int, tuple(), 2) - u1 = UOp(Ops.LOAD, dtypes.int, (globl.index(o1),)) - u2 = UOp(Ops.LOAD, dtypes.int, (globl.index(o2),)) + u1 = globl.index(o1) + u2 = globl.index(o2) u3 = UOp(Ops.CONST, dtypes.int, tuple(), 3) u4 = UOp(Ops.MULACC, dtypes.int, (u1,u2,u3)) uops_fma = full_rewrite(u4.sink()) diff --git a/test/testextra/test_tk.py b/test/testextra/test_tk.py new file mode 100644 index 0000000000..ec2294bf0e --- /dev/null +++ b/test/testextra/test_tk.py @@ -0,0 +1,405 @@ +import unittest, math + +from tinygrad import Tensor, Device, dtypes, Context +from tinygrad.engine.realize import ExecItem, get_runner +from tinygrad.helpers import CI +from tinygrad.renderer.ptx import PTXRenderer +import numpy as np + +from extra.thunder.tiny.tk import WARP_THREADS +from extra.thunder.tiny.tk.kernel import Kernel + +@unittest.skipUnless(Device.DEFAULT in ["CUDA", "NV"], "only cuda") +@unittest.skipIf(isinstance(Device[Device.DEFAULT].renderer, PTXRenderer), "no ptx") +class TestTK(unittest.TestCase): + @unittest.skipIf(CI, "no wmma in ci") + def test_simple_matmul(self): + N = 32 + BLOCK_SIZE = 16 + with Kernel((N // BLOCK_SIZE, N // BLOCK_SIZE, 1), WARP_THREADS) as ker: + warp = ker.warp + + c = ker.gl((1, 1, N, N), dtypes.float32) + a = ker.gl((1, 1, N, N), dtypes.bfloat16) + b = ker.gl((1, 1, N, N), dtypes.bfloat16) + + a_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + b_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + c_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + a_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + b_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + c_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + col, row = ker.blockIdx_x, ker.blockIdx_y + + c_reg = warp.zero(c_reg) + for tile in ker.range(N // BLOCK_SIZE): + a_smem = warp.load(a_smem, a, (), (0, 0, row, tile), axis=2) + b_smem = warp.load(b_smem, b, (), (0, 0, tile, col), axis=2) + + a_reg = warp.load(a_reg, a_smem) + b_reg = warp.load(b_reg, b_smem, transpose=True) + + c_reg = warp.mma_AB(c_reg, a_reg, b_reg) + c_reg = ker.endrange() + + c_smem = warp.store(c_smem, c_reg) + c = warp.store(c, c_smem, (0, 0, row, col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, N, dtype="bfloat16").contiguous() + b = Tensor.rand(1, 1, N, N, dtype="bfloat16").contiguous() + c = Tensor.empty(1, 1, N, N, dtype="float32") + Tensor.realize(a, b, c) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (c, a, b)]) + for _ in range(5): ei.run(wait=True) + c = c.float() + + ref = a.matmul(b, dtype=dtypes.float32).float() + + np.testing.assert_allclose(c.numpy(), ref.numpy()) + + @unittest.skipIf(CI, "no wmma in ci") + def test_simple_matmul_transposed(self): + N = 32 + BLOCK_SIZE = 16 + with Kernel((N // BLOCK_SIZE, N // BLOCK_SIZE, 1), WARP_THREADS) as ker: + warp = ker.warp + + c = ker.gl((1, 1, N, N), dtypes.float32) + a = ker.gl((1, 1, N, N), dtypes.bfloat16) + b = ker.gl((1, 1, N, N), dtypes.bfloat16) + + a_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + b_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + c_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + a_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + b_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.bfloat16) + c_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + col, row = ker.blockIdx_x, ker.blockIdx_y + + c_reg = warp.zero(c_reg) + for tile in ker.range(N // BLOCK_SIZE): + a_smem = warp.load(a_smem, a, (), (0, 0, row, tile), axis=2) + b_smem = warp.load(b_smem, b, (), (0, 0, col, tile), axis=2) + + a_reg = warp.load(a_reg, a_smem) + b_reg = warp.load(b_reg, b_smem) + + c_reg = warp.mma_ABt(c_reg, a_reg, b_reg) + c_reg = ker.endrange() + + c_smem = warp.store(c_smem, c_reg) + c = warp.store(c, c_smem, (0, 0, row, col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, N, dtype="bfloat16").contiguous() + b = Tensor.rand(1, 1, N, N, dtype="bfloat16").contiguous() + c = Tensor.empty(1, 1, N, N, dtype="float32") + Tensor.realize(a, b, c) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (c, a, b)]) + for _ in range(5): ei.run(wait=True) + c = c.float() + + ref = a.matmul(b.transpose(2, 3), dtype=dtypes.float32).float() + + np.testing.assert_allclose(c.numpy(), ref.numpy()) + + def test_load_store(self): + N = 32 + BLOCK_SIZE = 16 + with Kernel((N // BLOCK_SIZE, N // BLOCK_SIZE, 1), WARP_THREADS) as ker: + warp = ker.warp + + b = ker.gl((1, 1, N, N), dtypes.float32) + a = ker.gl((1, 1, N, N), dtypes.float32) + + a_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + b_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + a_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + b_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + col, row = ker.blockIdx_x, ker.blockIdx_y + + a_smem = warp.load(a_smem, a, (), (0, 0, row, col), axis=2) + a_reg = warp.load(a_reg, a_smem) + b_reg = warp.copy(b_reg, a_reg) + b_smem = warp.store(b_smem, b_reg) + b = warp.store(b, b_smem, (0, 0, row, col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, N, dtype="float32").contiguous() + b = Tensor.empty(1, 1, N, N, dtype="float32") + Tensor.realize(a, b) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (b, a)]) + for _ in range(5): ei.run(wait=True) + b = b.float() + + ref = a.float() + + np.testing.assert_allclose(b.numpy(), ref.numpy()) + + def test_max(self): + N = 16 + BLOCK_SIZE = 16 + with Kernel((1, 1, 1), WARP_THREADS) as ker: + warp = ker.warp + + b = ker.gl((1, 1, N, N), dtypes.float32) + a = ker.gl((1, 1, N, N), dtypes.float32) + + a_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + b_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + a_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + b_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + max_reg = ker.rv(BLOCK_SIZE, dtypes.float32, "ortho") + + for tile_row in ker.range(N // BLOCK_SIZE): + max_reg = warp.neg_inf(max_reg.after(tile_row)) + + for tile_col in ker.range(N // BLOCK_SIZE): + a_smem = warp.load(a_smem, a, (), (0, 0, tile_row, tile_col), axis=2) + a_reg = warp.load(a_reg, a_smem) + max_reg = warp.row_reduce(max_reg, a_reg, lambda a, b: a.maximum(b)) + max_reg = ker.endrange() + + b_reg = warp.map(b_reg, lambda _, idx: max_reg[idx[0], 0, (idx[2]%4)//2]) + b_smem = warp.store(b_smem, b_reg) + + for tile_col in ker.range(N // BLOCK_SIZE): + b = warp.store(b, b_smem, (0, 0, tile_row, tile_col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, N, dtype="float32").contiguous() + b = Tensor.empty(1, 1, N, N, dtype="float32") + Tensor.realize(a, b) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (b, a)]) + for _ in range(5): ei.run(wait=True) + b = b.float() + + ref = a.float().max(axis=3, keepdim=True).expand(a.shape) + + np.testing.assert_allclose(b.numpy(), ref.numpy()) + + def test_max_nonsquare(self): + N, M = 16, 64 + BLOCK_N, BLOCK_M = 16, 64 + with Kernel((1, 1, 1), WARP_THREADS) as ker: + warp = ker.warp + + b = ker.gl((1, 1, N, M), dtypes.float32) + a = ker.gl((1, 1, N, M), dtypes.float32) + + a_smem = ker.st((BLOCK_N, BLOCK_M), dtypes.float32) + b_smem = ker.st((BLOCK_N, BLOCK_M), dtypes.float32) + + a_reg = ker.rt((BLOCK_N, BLOCK_M), dtypes.float32) + b_reg = ker.rt((BLOCK_N, BLOCK_M), dtypes.float32) + + max_reg = ker.rv(BLOCK_N, dtypes.float32, "ortho") + + for tile_row in ker.range(N // BLOCK_N): + max_reg = warp.neg_inf(max_reg.after(tile_row)) + + for tile_col in ker.range(M // BLOCK_M): + a_smem = warp.load(a_smem, a, (), (0, 0, tile_row, tile_col), axis=2) + a_reg = warp.load(a_reg, a_smem) + max_reg = warp.row_reduce(max_reg, a_reg, lambda a, b: a.maximum(b)) + max_reg = ker.endrange() + + b_reg = warp.map(b_reg, lambda _, idx: max_reg[idx[0], 0, (idx[2]%4)//2]) + b_smem = warp.store(b_smem, b_reg) + + for tile_col in ker.range(M // BLOCK_M): + b = warp.store(b, b_smem, (0, 0, tile_row, tile_col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, M, dtype="float32").contiguous() + b = Tensor.empty(1, 1, N, M, dtype="float32") + Tensor.realize(a, b) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (b, a)]) + for _ in range(5): ei.run(wait=True) + b = b.float() + + ref = a.float().max(axis=3, keepdim=True).expand(a.shape) + + np.testing.assert_allclose(b.numpy(), ref.numpy()) + + def test_sum(self): + N = 32 + BLOCK_SIZE = 16 + with Kernel((1, 1, 1), WARP_THREADS) as ker: + warp = ker.warp + + b = ker.gl((1, 1, N, N), dtypes.float32) + a = ker.gl((1, 1, N, N), dtypes.float32) + + a_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + b_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + a_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + b_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + sum_reg = ker.rv(BLOCK_SIZE, dtypes.float32, "ortho") + + for tile_row in ker.range(N // BLOCK_SIZE): + sum_reg = warp.zero(sum_reg.after(tile_row)) + + for tile_col in ker.range(N // BLOCK_SIZE): + a_smem = warp.load(a_smem, a, (), (0, 0, tile_row, tile_col), axis=2) + a_reg = warp.load(a_reg, a_smem) + sum_reg = warp.row_reduce(sum_reg, a_reg, lambda a, b: a + b) + sum_reg = ker.endrange() + + b_reg = warp.map(b_reg, lambda _, idx: sum_reg[idx[0], 0, (idx[2]%4)//2]) + b_smem = warp.store(b_smem, b_reg) + + for tile_col in ker.range(N // BLOCK_SIZE): + b = warp.store(b, b_smem, (0, 0, tile_row, tile_col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, N, dtype="float32").contiguous() + b = Tensor.empty(1, 1, N, N, dtype="float32") + Tensor.realize(a, b) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (b, a)]) + for _ in range(5): ei.run(wait=True) + b = b.float() + + ref = a.float().sum(axis=3, keepdim=True).expand(a.shape) + + np.testing.assert_allclose(b.numpy(), ref.numpy(), atol=1e-5, rtol=1e-5) + + def test_sum_nonsquare(self): + N, M = 16, 64 + BLOCK_N, BLOCK_M = 16, 64 + with Kernel((1, 1, 1), WARP_THREADS) as ker: + warp = ker.warp + + b = ker.gl((1, 1, N, M), dtypes.float32) + a = ker.gl((1, 1, N, M), dtypes.float32) + + a_smem = ker.st((BLOCK_N, BLOCK_M), dtypes.float32) + b_smem = ker.st((BLOCK_N, BLOCK_M), dtypes.float32) + + a_reg = ker.rt((BLOCK_N, BLOCK_M), dtypes.float32) + b_reg = ker.rt((BLOCK_N, BLOCK_M), dtypes.float32) + + sum_reg = ker.rv(BLOCK_N, dtypes.float32, "ortho") + + for tile_row in ker.range(N // BLOCK_N): + sum_reg = warp.zero(sum_reg.after(tile_row)) + + for tile_col in ker.range(M // BLOCK_M): + a_smem = warp.load(a_smem, a, (), (0, 0, tile_row, tile_col), axis=2) + a_reg = warp.load(a_reg, a_smem) + sum_reg = warp.row_reduce(sum_reg, a_reg, lambda a, b: a + b) + sum_reg = ker.endrange() + + b_reg = warp.map(b_reg, lambda _, idx: sum_reg[idx[0], 0, (idx[2]%4)//2]) + b_smem = warp.store(b_smem, b_reg) + + for tile_col in ker.range(M // BLOCK_M): + b = warp.store(b, b_smem, (0, 0, tile_row, tile_col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, N, M, dtype="float32").contiguous() + b = Tensor.empty(1, 1, N, M, dtype="float32") + Tensor.realize(a, b) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (b, a)]) + for _ in range(5): ei.run(wait=True) + b = b.float() + + ref = a.float().sum(axis=3, keepdim=True).expand(a.shape) + + np.testing.assert_allclose(b.numpy(), ref.numpy(), atol=1e-5, rtol=1e-5) + + @unittest.skip("fake range not ended") + def test_softmax(self): + N = 32 + BLOCK_SIZE = 16 + with Kernel((1, 1, 1), WARP_THREADS) as ker: + warp = ker.warp + + b = ker.gl((1, 1, BLOCK_SIZE, N), dtypes.float32) + a = ker.gl((1, 1, BLOCK_SIZE, N), dtypes.float32) + + a_smem = ker.st((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + a_reg = ker.rt((BLOCK_SIZE, BLOCK_SIZE), dtypes.float32) + + max_vec_last = ker.rv(BLOCK_SIZE, dtypes.float32, "ortho") + max_vec = ker.rv(BLOCK_SIZE, dtypes.float32, "ortho") + norm_vec = ker.rv(BLOCK_SIZE, dtypes.float32, "ortho") + + max_vec = warp.neg_inf(max_vec) + norm_vec = warp.zero(norm_vec) + + for tile_col in ker.range(N // BLOCK_SIZE): + a_smem = warp.load(a_smem, a, (), (0, 0, 0, tile_col), axis=2) + a_reg = warp.load(a_reg, a_smem) + + a_reg = warp.map(a_reg, lambda x: x * (1.0 / math.log(2))) + + max_vec_last = warp.copy(max_vec_last.after(tile_col), max_vec) + max_vec = warp.row_reduce(max_vec, a_reg, lambda a, b: a.maximum(b)) + a_reg = warp.map(a_reg, lambda x, idx: (x - max_vec[idx[0], 0, (idx[2]%4)//2]).exp2()) + max_vec_last = warp.map(max_vec_last, lambda x, idx: (x - max_vec[*idx]).exp2()) + norm_vec = warp.map(norm_vec, lambda x, idx: x * max_vec_last[*idx]) + norm_vec = warp.row_reduce(norm_vec, a_reg, lambda a, b: a + b) + norm_vec = ker.endrange() + + for tile_col in ker.range(N // BLOCK_SIZE): + a_smem = warp.load(a_smem, a, (), (0, 0, 0, tile_col), axis=2) + a_reg = warp.load(a_reg, a_smem) + + a_reg = warp.map(a_reg, lambda x: x * (1.0 / math.log(2))) + a_reg = warp.map(a_reg, lambda x, idx: (x - max_vec[idx[0], 0, (idx[2]%4)//2]).exp2()) + a_reg = warp.map(a_reg, lambda x, idx: x / norm_vec[idx[0], 0, (idx[2]%4)//2]) + + a_smem = warp.store(a_smem, a_reg) + b = warp.store(b, a_smem, (0, 0, 0, tile_col), (), axis=2) + + sink = ker.finish() + + with Context(DEBUG=0): + a = Tensor.rand(1, 1, BLOCK_SIZE, N, dtype="float32") + b = Tensor.empty(1, 1, BLOCK_SIZE, N, dtype="float32") + Tensor.realize(a, b) + + ei = ExecItem(get_runner(Device.DEFAULT, sink), [t.uop.buffer for t in (b, a)]) + for _ in range(5): ei.run(wait=True) + b = b.float() + + ref = a.float().softmax(axis=3) + + np.testing.assert_allclose(b.numpy(), ref.numpy(), atol=1e-5, rtol=1e-5) + +if __name__ == "__main__": + unittest.main() diff --git a/test/unit/test_attention.py b/test/unit/test_attention.py index 5043f7335a..e47b74fbe4 100644 --- a/test/unit/test_attention.py +++ b/test/unit/test_attention.py @@ -1,12 +1,10 @@ import unittest from tinygrad import Tensor, dtypes, TinyJit, UOp -from tinygrad.helpers import RANGEIFY from tinygrad.apps.llm import apply_rope #from tinygrad.engine.realize import run_schedule # TODO: test_scheduler, but just in uint class TestAttention(unittest.TestCase): - @unittest.skipIf(RANGEIFY > 0, "not half on rangeify") def test_half_qkv_buffers(self): BS, seqlen, dim = 10, 4, 100 q = Tensor.ones(BS, seqlen, dim, dtype=dtypes.half).contiguous().realize() @@ -14,12 +12,11 @@ class TestAttention(unittest.TestCase): v = Tensor.ones(BS, seqlen, dim, dtype=dtypes.half).contiguous().realize() attn = q.scaled_dot_product_attention(k, v) sched = attn.schedule() - #run_schedule(sched[:]) - # attention has 5 kernels now - self.assertEqual(len(sched), 4 if RANGEIFY else 5) - softmax_inputs = sched[1:4] - for i,si in enumerate(softmax_inputs): - assert all(b.dtype == dtypes.half for b in si.bufs), f"non half {si.bufs=} in kernel {i}" + # attention has 4 kernels now + self.assertEqual(len(sched), 4) + # softmax_inputs = sched[1:4] + # for i,si in enumerate(softmax_inputs): + # assert all(b.dtype == dtypes.half for b in si.bufs), f"non half {si.bufs=} in kernel {i}" def test_apply_rope(self): x = Tensor.randn(1, 2, 4, 8, dtype=dtypes.float32) diff --git a/test/unit/test_autogen.py b/test/unit/test_autogen.py new file mode 100644 index 0000000000..1ece479dff --- /dev/null +++ b/test/unit/test_autogen.py @@ -0,0 +1,47 @@ +import ctypes, subprocess, tempfile, unittest +from tinygrad.helpers import WIN +from tinygrad.runtime.support.c import Struct + +class TestAutogen(unittest.TestCase): + def test_packed_struct_sizeof(self): + layout = [('a', ctypes.c_char), ('b', ctypes.c_int, 5), ('c', ctypes.c_char)] + class X(ctypes.Structure): _fields_, _layout_ = layout, 'gcc-sysv' + class Y(ctypes.Structure): _fields_, _pack_, _layout_ = layout, 1, 'ms' + class Z(Struct): _packed_, _fields_ = True, layout + self.assertNotEqual(ctypes.sizeof(X), 4) # ctypes bug! gcc-13.3.0 says this should have size 4 + self.assertEqual(ctypes.sizeof(Y), 6) + self.assertEqual(ctypes.sizeof(Z), 3) + layout = [('a', ctypes.c_int, 31), ('b', ctypes.c_int, 31), ('c', ctypes.c_int, 1), ('d', ctypes.c_int, 1)] + class Foo(ctypes.Structure): _fields_, _layout_ = layout, 'gcc-sysv' + class Bar(ctypes.Structure): _fields_, _pack_, _layout_ = layout, 1, 'ms' + class Baz(Struct): _fields_, _packed_ = layout, True + self.assertEqual(ctypes.sizeof(Foo), 12) + self.assertEqual(ctypes.sizeof(Bar), 12) + self.assertEqual(ctypes.sizeof(Baz), 8) + + @unittest.skipIf(WIN, "doesn't compile on windows") + def test_packed_struct_interop(self): + class Baz(Struct): pass + Baz._packed_ = True + Baz._fields_ = [('a', ctypes.c_int, 30), ('b', ctypes.c_int, 30), ('c', ctypes.c_int, 2), ('d', ctypes.c_int, 2)] + src = ''' + struct __attribute__((packed)) baz { + int a:30; + int b:30; + int c:2; + int d:2; + }; + + int test(struct baz x) { + return x.a + x.b + x.c + x.d; + } + ''' + args = ('-x', 'c', '-fPIC', '-shared') + with tempfile.NamedTemporaryFile(suffix=".so") as f: + subprocess.check_output(('clang',) + args + ('-', '-o', f.name), input=src.encode('utf-8')) + b = Baz(0xAA000, 0x00BB0, 0, 1) + test = ctypes.CDLL(f.name).test + test.argtypes = [Baz] + self.assertEqual(test(b), b.a + b.b + b.c + b.d) + +if __name__ == "__main__": unittest.main() diff --git a/test/unit/test_block_reorder.py b/test/unit/test_block_reorder.py deleted file mode 100644 index e81b1ff6c5..0000000000 --- a/test/unit/test_block_reorder.py +++ /dev/null @@ -1,76 +0,0 @@ -import unittest, random -from tinygrad.dtype import dtypes -from tinygrad.uop.ops import print_uops, UOp, Ops -from tinygrad.codegen.late.linearize import block_reorder -from tinygrad.renderer.cstyle import OpenCLRenderer - -def is_toposorted(lst:list[UOp]): - seen = set() - for u in lst: - if any(p not in seen for p in u.src): return False - seen.add(u) - return True - -class TestBlockReorder(unittest.TestCase): - def _test_randomize(self, golden:list[UOp]): - # test random order is always same - for _ in range(50): - # shuffle and form a valid toposort - lst = golden[:] - random.shuffle(lst) - topolst = [] - for u in lst: - for p in u.toposort(): - if p not in topolst: topolst.append(p) - assert is_toposorted(topolst) - - for x,y in zip(golden, this_order:=block_reorder(topolst)): - if x is not y: - print_uops(golden) - print_uops(this_order) - self.assertIs(x, y) - - def _test_render(self, golden:list[UOp]): - return OpenCLRenderer().render(golden) - - def test_loads(self): - a = UOp(Ops.DEFINE_GLOBAL, dtype=dtypes.float.ptr(), arg=0) - b = UOp(Ops.DEFINE_GLOBAL, dtype=dtypes.float.ptr(), arg=1) - c = UOp(Ops.DEFINE_GLOBAL, dtype=dtypes.float.ptr(), arg=2) - v1 = UOp(Ops.SPECIAL, dtype=dtypes.int, src=(UOp.const(dtypes.int, 4),), arg="gidx0") - v2 = UOp(Ops.SPECIAL, dtype=dtypes.int, src=(UOp.const(dtypes.int, 4),), arg="gidx1") - v1 = v1*27 - v2 = v2*4 - loads = [ - a.index(v1).load(dtype=dtypes.float), - a.index(v1+1).load(dtype=dtypes.float), - a.index(v1+2).load(dtype=dtypes.float), - a.index(v1+3).load(dtype=dtypes.float), - b.index(v2).load(dtype=dtypes.float), - b.index(v2+1).load(dtype=dtypes.float), - b.index(v2+2).load(dtype=dtypes.float), - b.index(v2+3).load(dtype=dtypes.float)] - #random.shuffle(loads) - sink = c.store(sum(loads)).sink() - - # determine golden order - golden = block_reorder(list(sink.toposort())) - - # render for test - print(self._test_render(golden)) - #print_uops(golden) - - # assert the loads are in this order - self.assertListEqual([g.src[0].src[1].render() for g in golden if g.op is Ops.LOAD], - ['(gidx1*4)', '((gidx1*4)+1)', '((gidx1*4)+2)', '((gidx1*4)+3)', - '(gidx0*27)', '((gidx0*27)+1)', '((gidx0*27)+2)', '((gidx0*27)+3)']) - - # assert math is after loads - first_math = [i for i,g in enumerate(golden) if g.op is Ops.ADD and g.dtype == dtypes.float][0] - assert not any(x.op is Ops.LOAD for x in golden[first_math:]) - - # confirm the sort is stable - self._test_randomize(golden) - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_conv.py b/test/unit/test_conv.py index edc27fccfe..4626b16639 100644 --- a/test/unit/test_conv.py +++ b/test/unit/test_conv.py @@ -62,6 +62,7 @@ class TestConv(unittest.TestCase): np.testing.assert_allclose(r1.numpy(), np.maximum(out.numpy(), 0), atol=1e-5) np.testing.assert_allclose(r2.numpy(), np.where(out.numpy() > 0, out.numpy(), (np.exp(out.numpy()) - 1)), atol=1e-5) + @unittest.skip("this test is flaky") def test_two_overlapping_binops_no_rerun_wino(self): with Context(WINO=1): x = Tensor.randn(1,4,16,16) diff --git a/test/unit/test_device.py b/test/unit/test_device.py index 984feaf751..2778b4c708 100644 --- a/test/unit/test_device.py +++ b/test/unit/test_device.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -import unittest, os, subprocess, sys +import unittest, os, subprocess from tinygrad import Tensor -from tinygrad.device import Device, Compiler +from tinygrad.device import Device, Compiler, enumerate_devices_str from tinygrad.helpers import diskcache_get, diskcache_put, getenv, Context, WIN, CI class TestDevice(unittest.TestCase): @@ -30,7 +30,7 @@ class TestDevice(unittest.TestCase): @unittest.skipIf(WIN and CI, "skipping windows test") # TODO: subproccess causes memory violation? def test_env_overwrite_default_compiler(self): - expect_failure = "\ntry: assert Device[Device.DEFAULT].compiler is None;\nexcept RuntimeError: pass" + expect_failure = "\ntry: assert Device[Device.DEFAULT].compiler is None;\nexcept Exception: pass" if Device.DEFAULT == "CPU": from tinygrad.runtime.support.compiler_cpu import CPULLVMCompiler, ClangJITCompiler @@ -81,29 +81,26 @@ class TestCompiler(unittest.TestCase): def test_compile_cached(self): diskcache_put("key", "123", None) # clear cache getenv.cache_clear() - with Context(DISABLE_COMPILER_CACHE=0): + with Context(CCACHE=1): self.assertEqual(MockCompiler("key").compile_cached("123"), str.encode("123")) self.assertEqual(diskcache_get("key", "123"), str.encode("123")) def test_compile_cached_disabled(self): diskcache_put("disabled_key", "123", None) # clear cache getenv.cache_clear() - with Context(DISABLE_COMPILER_CACHE=1): + with Context(CCACHE=0): self.assertEqual(MockCompiler("disabled_key").compile_cached("123"), str.encode("123")) self.assertIsNone(diskcache_get("disabled_key", "123")) def test_device_compile(self): getenv.cache_clear() - with Context(DISABLE_COMPILER_CACHE=1): + with Context(CCACHE=0): a = Tensor([0.,1.], device=Device.DEFAULT).realize() (a + 1).realize() class TestRunAsModule(unittest.TestCase): def test_module_runs(self): - p = subprocess.run([sys.executable, "-m", "tinygrad.device"],stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env={**os.environ, "DEBUG": "1"}, timeout=40,) - out = (p.stdout + p.stderr).decode() - self.assertEqual(p.returncode, 0, msg=out) + out = '\n'.join(enumerate_devices_str()) self.assertIn("CPU", out) # for sanity check if __name__ == "__main__": diff --git a/test/unit/test_disk_tensor.py b/test/unit/test_disk_tensor.py index 57584df295..9b0aed2b0b 100644 --- a/test/unit/test_disk_tensor.py +++ b/test/unit/test_disk_tensor.py @@ -418,5 +418,30 @@ class TestPathTensor(unittest.TestCase): Tensor(pathlib.Path(test_file)).tolist() os.chmod(test_file, 0o644) assert Tensor(pathlib.Path(test_file)).tolist(), list(range(10)) + +class TestDiskTensorMovement(unittest.TestCase): + def setUp(self): + self.fn = pathlib.Path(temp("custom_disk_range")) + self.fn.unlink(missing_ok=True) + Tensor.arange(100, dtype=dtypes.uint8).to(f"disk:{str(self.fn)}").realize() + + def test_simple_read(self): + t = Tensor(self.fn) + self.assertTrue(Tensor.all(t.to(None) == Tensor.arange(100, dtype=dtypes.uint8)).item()) + + def test_slice_read(self): + t = Tensor(self.fn) + self.assertListEqual(t[16:18].tolist(), [16,17]) + + def test_slice_read_cat(self): + t = Tensor(self.fn) + with self.assertRaises(AssertionError): + self.assertListEqual(Tensor.cat(t[16:18], t[20:22]).tolist(), [16,17,20,21]) + + def test_slice_sum(self): + t = Tensor(self.fn) + with self.assertRaises(AssertionError): + self.assertListEqual((t[16:18]+t[20:22]).tolist(), [16+20,17+21]) + if __name__ == "__main__": unittest.main() diff --git a/test/unit/test_elf.py b/test/unit/test_elf.py index cdf02b7728..2dca88b077 100644 --- a/test/unit/test_elf.py +++ b/test/unit/test_elf.py @@ -24,6 +24,15 @@ class TestElfLoader(unittest.TestCase): ''' with self.assertRaisesRegex(RuntimeError, 'evil_external_function'): ClangJITCompiler().compile(src) + def test_link(self): + src = ''' + float powf(float, float); // from libm + float test(float x, float y) { return powf(x, y); } + ''' + args = ('-x', 'c', '-c', '-target', f'{platform.machine()}-none-unknown-elf', '-march=native', '-fPIC', '-O2', '-ffreestanding', '-nostdlib') + obj = subprocess.check_output(('clang',) + args + ('-', '-o', '-'), input=src.encode()) + with self.assertRaisesRegex(RuntimeError, 'powf'): elf_loader(obj) + elf_loader(obj, link_libs=['m']) if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_graph_rewrite.py b/test/unit/test_graph_rewrite.py index 8655019a60..bff8c7d055 100644 --- a/test/unit/test_graph_rewrite.py +++ b/test/unit/test_graph_rewrite.py @@ -1,11 +1,12 @@ import unittest, math from tinygrad import dtypes -from tinygrad.helpers import all_same +from tinygrad.helpers import all_same, Context from tinygrad.uop.ops import GroupOp, UOp, Ops, exec_alu, PatternMatcher, TrackedPatternMatcher, UPat from tinygrad.codegen import full_rewrite_to_sink from hypothesis import given, strategies as strat # Helper function to apply the graph rewrite +@Context(SPEC=0) def apply_rewrite(expr): return full_rewrite_to_sink(expr.sink()).src[0] @@ -305,19 +306,19 @@ class TestRecurse(unittest.TestCase): graph_rewrite(a, pm, bottom_up=True) def test_inf_loop(self): - a = UOp.variable('a', 0, 10) + a = UOp.const(dtypes.int, 3) pm = PatternMatcher([ - (UPat(Ops.DEFINE_VAR, name="x"), lambda x: x.replace(op=Ops.CONST)), - (UPat(Ops.CONST, name="x"), lambda x: x.replace(op=Ops.DEFINE_VAR)), + (UPat(Ops.CONST, arg=3, name="x"), lambda x: x.replace(arg=4)), + (UPat(Ops.CONST, arg=4, name="x"), lambda x: x.replace(arg=3)), ]) with self.assertRaises(RuntimeError): graph_rewrite(a, pm) def test_inf_loop_bottom_up(self): - a = UOp.variable('a', 0, 10) + a = UOp.const(dtypes.int, 3) pm = PatternMatcher([ - (UPat(Ops.DEFINE_VAR, name="x"), lambda x: x.replace(op=Ops.CONST)), - (UPat(Ops.CONST, name="x"), lambda x: x.replace(op=Ops.DEFINE_VAR)), + (UPat(Ops.CONST, arg=3, name="x"), lambda x: x.replace(arg=4)), + (UPat(Ops.CONST, arg=4, name="x"), lambda x: x.replace(arg=3)), ]) with self.assertRaises(RuntimeError): graph_rewrite(a, pm, bottom_up=True) @@ -334,5 +335,19 @@ class TestBidirectional(unittest.TestCase): graph_rewrite(c, pm, ctx=ctx_list, bpm=bpm) self.assertListEqual(ctx_list, [('+', True), (1, True), (1, False), (2, True), (2, False), ('+', False)]) +class TestStopEarly(unittest.TestCase): + def test_stop_early(self): + a = UOp.const(dtypes.int, 3) + b = UOp.const(dtypes.int, 4) + c = a+b + cn = UOp.const(dtypes.int, 7) + d = UOp.const(dtypes.int, 2) + def visit_const(c:UOp): + print(f"visit {c.arg}") + assert c.arg not in (3,4) + pm_cvisit = PatternMatcher([(UPat(Ops.CONST, name="c"), visit_const),]) + ret = (c+d).substitute({c:cn}, extra_pm=pm_cvisit) + assert ret == cn+d + if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_hashing.py b/test/unit/test_hashing.py index a73e1929a6..d35fac435c 100644 --- a/test/unit/test_hashing.py +++ b/test/unit/test_hashing.py @@ -3,6 +3,8 @@ import hashlib, random, unittest from tinygrad import Tensor, Device, getenv, dtypes from tinygrad.device import is_dtype_supported from tinygrad.helpers import CI +from tinygrad.uop.ops import UOp +from tinygrad.engine.jit import TinyJit @unittest.skipUnless(is_dtype_supported(dtypes.uint8) and is_dtype_supported(dtypes.uint64), "Device must support uint8 and uint64") @unittest.skipIf(getenv("MOCKGPU") and Device.DEFAULT == "NV", "crashes in NV CI") @@ -29,8 +31,11 @@ class TestKeccak(unittest.TestCase): out_shape = Tensor.randint(*s[i:], high=255, dtype=dtypes.uint8).keccak().shape self.assertTupleEqual(s[i:-1], out_shape[:-1]) + @unittest.skipUnless(Device.DEFAULT=="METAL", "slow") def test_sha3_224(self): self._test_preset("sha3_224", [143, 144]) + @unittest.skipUnless(Device.DEFAULT=="METAL", "slow") def test_sha3_256(self): self._test_preset("sha3_256", [135, 136]) + @unittest.skipUnless(Device.DEFAULT=="METAL", "slow") def test_shake_128(self): self._test_preset("shake_128", [167, 168], lambda d: hashlib.shake_128(d).digest(16)) def _test_preset(self, name: str, special_sizes: list[int], hasher: Callable[[bytes], bytes] | None = None): @@ -69,5 +74,52 @@ class TestKeccak(unittest.TestCase): data = b"\x00" * 1000 self.assertEqual(bytes(Tensor(data).keccak("shake_128").tolist()), hashlib.shake_128(data).digest(16)) + def test_variable_bs(self): + data = Tensor([b"abc", b"abc", b"abc"], dtype=dtypes.uint8).repeat(2048, 1) + + bs = UOp.variable("bs", 1, 4096).bind(1) + out = data.shrink_to(bs, data.shape[-1]).keccak().shrink_to(1, 32) + self.assertEqual(bytes(out[0].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + + bs = UOp.variable("bs", 1, 4096).bind(2) + out = data.shrink_to(bs, data.shape[-1]).keccak().shrink_to(2, 32) + self.assertEqual(bytes(out[0].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + self.assertEqual(bytes(out[1].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + + bs = UOp.variable("bs", 1, 4096).bind(3) + data = Tensor([b"abc", b"abc", b"def"], dtype=dtypes.uint8).repeat(2048, 1) + out = data.shrink_to(bs, data.shape[-1]).keccak().shrink_to(3, 32) + self.assertEqual(bytes(out[0].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + self.assertEqual(bytes(out[1].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + self.assertEqual(bytes(out[2].tolist()), bytearray.fromhex("8e0d8f672252acb0 ffc5093db8653b18 1513bf9a2097e737 b4f73533dcaf46df")) + + def test_variable_bs_jit(self): + def f(data): + return data.keccak() + jit_f = TinyJit(f) + + data = Tensor([b"abc", b"abc", b"abc"], dtype=dtypes.uint8).repeat(2048, 1) + + # initialize jit + for _ in range(3): + bs = UOp.variable("bs", 1, 4096).bind(4096) + _ = jit_f(data.shrink_to(bs, data.shape[-1])) + + bs = UOp.variable("bs", 1, 4096).bind(1) + out = jit_f(data.shrink_to(bs, data.shape[-1])).shrink_to(1, 32) + self.assertEqual(bytes(out[0].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + + bs = UOp.variable("bs", 1, 4096).bind(2) + out = jit_f(data.shrink_to(bs, data.shape[-1])).shrink_to(2, 32) + self.assertEqual(bytes(out[0].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + self.assertEqual(bytes(out[1].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + + bs = UOp.variable("bs", 1, 4096).bind(3) + data = Tensor([b"abc", b"abc", b"def"], dtype=dtypes.uint8).repeat(2048, 1) + out = jit_f(data.shrink_to(bs, data.shape[-1])).shrink_to(3, 32) + self.assertEqual(bytes(out[0].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + self.assertEqual(bytes(out[1].tolist()), bytearray.fromhex("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532")) + self.assertEqual(bytes(out[2].tolist()), bytearray.fromhex("8e0d8f672252acb0 ffc5093db8653b18 1513bf9a2097e737 b4f73533dcaf46df")) + if __name__ == "__main__": unittest.main() diff --git a/test/unit/test_helpers.py b/test/unit/test_helpers.py index 3000ef89ed..f3e38ff44e 100644 --- a/test/unit/test_helpers.py +++ b/test/unit/test_helpers.py @@ -1,9 +1,8 @@ import ctypes, gzip, unittest, timeit from tinygrad import Variable -from tinygrad.helpers import Context, ContextVar, argfix, colored, word_wrap, is_numpy_ndarray, CI, mv_address +from tinygrad.helpers import Context, ContextVar, argfix, colored, word_wrap, is_numpy_ndarray, CI, mv_address, get_contraction from tinygrad.helpers import merge_dicts, strip_parens, prod, round_up, fetch, fully_flatten, from_mv, to_mv, polyN, time_to_str, cdiv, cmod, getbits from tinygrad.tensor import Tensor, get_shape -from tinygrad.shape.view import get_contraction, get_contraction_with_reduce import numpy as np VARIABLE = ContextVar("VARIABLE", 0) @@ -100,6 +99,11 @@ class TestStripParens(unittest.TestCase): def test_simple(self): self.assertEqual("1+2", strip_parens("(1+2)")) def test_nested(self): self.assertEqual("1+(2+3)", strip_parens("(1+(2+3))")) def test_casted_no_strip(self): self.assertEqual("(int)(1+2)", strip_parens("(int)(1+2)")) + def test_unmatched_parens(self): self.assertEqual("((c35+c39>>23&255)+-127).cast(dtypes.float)", + strip_parens("((c35+c39>>23&255)+-127).cast(dtypes.float)")) + def test_single_paren_left(self): self.assertEqual("(abc", strip_parens("(abc")) + def test_single_paren_right(self): self.assertEqual("abc)", strip_parens("abc)")) + def test_parens_at_different_depths(self): self.assertEqual("(a+(b))*(c)", strip_parens("(a+(b))*(c)")) class TestProd(unittest.TestCase): def test_empty(self): self.assertEqual(1, prod(tuple())) @@ -219,20 +223,6 @@ class TestMemoryview(unittest.TestCase): print(f"from_mv vs mv_address: {fmv_us:8.3f} µs vs {mva_us:8.3f} µs") class TestGetContraction(unittest.TestCase): - def test_contraction_with_reduce(self): - r = get_contraction((16, 1, 1, 1), (16, 1, 1)) - self.assertEqual(r, [[0], [], [1, 2, 3]]) - r = get_contraction_with_reduce((16, 1, 1, 1), (16, 1, 1), (1,)) - self.assertEqual(r, [[0], [1, 2], [3]]) - - r = get_contraction((16, 1, 1, 1, 1), (16, 1, 1, 1)) - self.assertEqual(r, [[0], [], [], [1, 2, 3, 4]]) - r = get_contraction_with_reduce((16, 1, 1, 1, 1), (16, 1, 1, 1), (1,)) - self.assertEqual(r, [[0], [1, 2], [3], [4]]) - - r = get_contraction_with_reduce((2, 512, 1, 1), (2, 1, 512), (1,)) - self.assertIsNone(r) - def test_contraction(self): r = get_contraction((1,2,3,4), (2,3,4)) self.assertEqual(r, [[0, 1], [2], [3]]) diff --git a/test/unit/test_indexing.py b/test/unit/test_indexing.py index c9d6d7c7da..9fad1cd381 100644 --- a/test/unit/test_indexing.py +++ b/test/unit/test_indexing.py @@ -5,8 +5,6 @@ import numpy as np from tinygrad import Tensor, dtypes, Device, TinyJit from tinygrad.device import is_dtype_supported -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View from tinygrad.helpers import CI, all_same, prod random.seed(42) @@ -22,11 +20,13 @@ def consec(shape, start=1): # creates strided tensor with base set to reference tensor's base, equivalent to torch.set_() def set_(reference: Tensor, shape, strides, offset): raise NotImplementedError("need to implement without calling uop.view") + """ if reference.uop.base.realized is None: reference.realize() assert reference.uop.base.realized, "base has to be realized before setting it to strided's base" strided = Tensor(reference.uop.view(ShapeTracker((View.create(shape=shape, strides=strides, offset=offset),)))) assert strided.uop.st.real_strides() == strides, "real_strides should equal strides for strided" return strided + """ def clone(original:Tensor): return original.clone() def copy_(src:Tensor, other:Tensor) -> Tensor: return src.clone() @@ -180,474 +180,6 @@ class TestIndexing(unittest.TestCase): # def delitem(): del reference[0] # self.assertRaises(TypeError, delitem) - # TODO: LLVM is quite fast, why are other compiled backends slow? - @unittest.skipIf(CI and Device.DEFAULT in ["CPU", "CL", "METAL", "NV", "AMD"], "slow") - def test_advancedindex(self): - # integer array indexing - - # pick a random valid indexer type - def ri(indices): - choice = random.randint(0, 2) - if choice == 0: return Tensor(indices) - if choice == 1: return list(indices) - return tuple(indices) - - def validate_indexing(x): - numpy_testing_assert_equal_helper(x[[0]], consec((1,))) - numpy_testing_assert_equal_helper(x[ri([0]),], consec((1,))) - numpy_testing_assert_equal_helper(x[ri([3]),], consec((1,), 4)) - numpy_testing_assert_equal_helper(x[[2, 3, 4]], consec((3,), 3)) - numpy_testing_assert_equal_helper(x[ri([2, 3, 4]),], consec((3,), 3)) - numpy_testing_assert_equal_helper(x[ri([0, 2, 4]),], np.array([1, 3, 5])) - - def validate_setting(x): - x[[0]] = -2 - numpy_testing_assert_equal_helper(x[[0]], np.array([-2])) - x[[0]] = -1 - numpy_testing_assert_equal_helper(x[ri([0]), ], np.array([-1])) - x[[2, 3, 4]] = 4 - numpy_testing_assert_equal_helper(x[[2, 3, 4]], np.array([4, 4, 4])) - x[ri([2, 3, 4]), ] = 3 - numpy_testing_assert_equal_helper(x[ri([2, 3, 4]), ], np.array([3, 3, 3])) - x[ri([0, 2, 4]), ] = Tensor([5, 4, 3]) - numpy_testing_assert_equal_helper(x[ri([0, 2, 4]), ], np.array([5, 4, 3])) - - # Case 1: Purely Integer Array Indexing - reference = consec((10,)) - validate_indexing(reference) - # setting values - validate_setting(reference) - - # Tensor with stride != 1 - # strided is [1, 3, 5, 7] - - # # TODO: set stride - # reference = consec((10,)) - # strided = set_(reference, (4,), (2,), 0) - - # numpy_testing_assert_equal_helper(strided[[0]], np.array([1])) - # numpy_testing_assert_equal_helper(strided[ri([0]), ], np.array([1])) - # numpy_testing_assert_equal_helper(strided[ri([3]), ], np.array([7])) - # numpy_testing_assert_equal_helper(strided[[1, 2]], np.array([3, 5])) - # numpy_testing_assert_equal_helper(strided[ri([1, 2]), ], np.array([3, 5])) - # numpy_testing_assert_equal_helper(strided[ri([[2, 1], [0, 3]]), ], - # np.array([[5, 3], [1, 7]])) - - # stride is [4, 8] - - # strided = set_(reference, (2,), (4,), offset=4) - - # numpy_testing_assert_equal_helper(strided[[0]], np.array([5])) - # numpy_testing_assert_equal_helper(strided[ri([0]), ], np.array([5])) - # numpy_testing_assert_equal_helper(strided[ri([1]), ], np.array([9])) - # numpy_testing_assert_equal_helper(strided[[0, 1]], np.array([5, 9])) - # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ], np.array([5, 9])) - # numpy_testing_assert_equal_helper(strided[ri([[0, 1], [1, 0]]), ], - # np.array([[5, 9], [9, 5]])) - - # reference is 1 2 - # 3 4 - # 5 6 - reference = consec((3, 2)) - numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], np.array([1, 3, 5])) - numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([1])], np.array([2, 4, 6])) - numpy_testing_assert_equal_helper(reference[ri([0]), ri([0])], consec((1,))) - numpy_testing_assert_equal_helper(reference[ri([2]), ri([1])], consec((1,), 6)) - numpy_testing_assert_equal_helper(reference[[ri([0, 0]), ri([0, 1])]], np.array([1, 2])) - numpy_testing_assert_equal_helper(reference[[ri([0, 1, 1, 0, 2]), ri([1])]], np.array([2, 4, 4, 2, 6])) - numpy_testing_assert_equal_helper(reference[[ri([0, 0, 1, 1]), ri([0, 1, 0, 0])]], np.array([1, 2, 3, 3])) - - rows = ri([[0, 0], - [1, 2]]) - columns = [0], - numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[1, 1], - [3, 5]])) - - rows = ri([[0, 0], - [1, 2]]) - columns = ri([1, 0]) - numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[2, 1], - [4, 5]])) - rows = ri([[0, 0], - [1, 2]]) - columns = ri([[0, 1], - [1, 0]]) - numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[1, 2], - [4, 5]])) - - # setting values - reference[ri([0]), ri([1])] = -1 - numpy_testing_assert_equal_helper(reference[ri([0]), ri([1])], np.array([-1])) - reference[ri([0, 1, 2]), ri([0])] = Tensor([-1, 2, -4]) - numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], - np.array([-1, 2, -4])) - reference[rows, columns] = Tensor([[4, 6], [2, 3]]) - numpy_testing_assert_equal_helper(reference[rows, columns], - np.array([[4, 6], [2, 3]])) - - # Verify still works with Transposed (i.e. non-contiguous) Tensors - reference = Tensor([[0, 1, 2, 3], - [4, 5, 6, 7], - [8, 9, 10, 11]]).T - - # Transposed: [[0, 4, 8], - # [1, 5, 9], - # [2, 6, 10], - # [3, 7, 11]] - - numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], np.array([0, 1, 2])) - numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([1])], np.array([4, 5, 6])) - numpy_testing_assert_equal_helper(reference[ri([0]), ri([0])], np.array([0])) - numpy_testing_assert_equal_helper(reference[ri([2]), ri([1])], np.array([6])) - numpy_testing_assert_equal_helper(reference[[ri([0, 0]), ri([0, 1])]], np.array([0, 4])) - numpy_testing_assert_equal_helper(reference[[ri([0, 1, 1, 0, 3]), ri([1])]], np.array([4, 5, 5, 4, 7])) - numpy_testing_assert_equal_helper(reference[[ri([0, 0, 1, 1]), ri([0, 1, 0, 0])]], np.array([0, 4, 1, 1])) - - rows = ri([[0, 0], - [1, 2]]) - columns = [0], - numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[0, 0], [1, 2]])) - - rows = ri([[0, 0], - [1, 2]]) - columns = ri([1, 0]) - numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[4, 0], [5, 2]])) - rows = ri([[0, 0], - [1, 3]]) - columns = ri([[0, 1], - [1, 2]]) - numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[0, 4], [5, 11]])) - - # TODO: non contiguous setitem - ''' - # setting values - reference[ri([0]), ri([1])] = -1 - numpy_testing_assert_equal_helper(reference[ri([0]), ri([1])], - np.array([-1])) - reference[ri([0, 1, 2]), ri([0])] = np.array([-1, 2, -4]) - numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], - np.array([-1, 2, -4])) - reference[rows, columns] = np.array([[4, 6], [2, 3]]) - numpy_testing_assert_equal_helper(reference[rows, columns], - np.array([[4, 6], [2, 3]])) - ''' - - # stride != 1 - - # strided is [[1 3 5 7], - # [9 11 13 15]] - - # # TODO: set stride - # reference = Tensor.arange(0., 24).reshape(3, 8) - # strided = set_(reference, (2,4), (8,2), 1) - - # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([0])], np.array([1, 9])) - # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([1])], np.array([3, 11])) - # numpy_testing_assert_equal_helper(strided[ri([0]), ri([0])], np.array([1])) - # numpy_testing_assert_equal_helper(strided[ri([1]), ri([3])], np.array([15])) - # numpy_testing_assert_equal_helper(strided[[ri([0, 0]), ri([0, 3])]], np.array([1, 7])) - # numpy_testing_assert_equal_helper(strided[[ri([1]), ri([0, 1, 1, 0, 3])]], np.array([9, 11, 11, 9, 15])) - # numpy_testing_assert_equal_helper(strided[[ri([0, 0, 1, 1]), ri([0, 1, 0, 0])]], np.array([1, 3, 9, 9])) - - # rows = ri([[0, 0], - # [1, 1]]) - # columns = [0], - # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[1, 1], [9, 9]])) - - # rows = ri([[0, 1], - # [1, 0]]) - # columns = ri([1, 2]) - # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[3, 13], [11, 5]])) - # rows = ri([[0, 0], - # [1, 1]]) - # columns = ri([[0, 1], - # [1, 2]]) - # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[1, 3], [11, 13]])) - - # setting values - - # strided is [[10, 11], - # [17, 18]] - - # # TODO: set stride - # reference = Tensor.arange(0., 24).reshape(3, 8) - # strided = set_(reference, (2,2), (7,1), 10) - - # numpy_testing_assert_equal_helper(strided[ri([0]), ri([1])], np.array([11])) - - # TODO non contiguous setitem - ''' - strided[ri([0]), ri([1])] = -1 - numpy_testing_assert_equal_helper(strided[ri([0]), ri([1])], - Tensor([-1])) - ''' - # # TODO: set stride - # reference = Tensor.arange(0., 24).reshape(3, 8) - # strided = set_(reference, (2,2), (7,1), 10) - - # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([1, 0])], np.array([11, 17])) - - # TODO non contiguous setitem - ''' - strided[ri([0, 1]), ri([1, 0])] = Tensor([-1, 2]) - numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([1, 0])], - Tensor([-1, 2])) - ''' - - # # TODO: set stride - # reference = Tensor.arange(0., 24).realize().reshape(3, 8) - # strided = set_(reference, (2,2), (7,1), 10) - - # rows = ri([[0], - # [1]]) - # columns = ri([[0, 1], - # [0, 1]]) - # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[10, 11], [17, 18]])) - - # TODO non contiguous setitem - ''' - strided[rows, columns] = Tensor([[4, 6], [2, 3]]) - numpy_testing_assert_equal_helper(strided[rows, columns], - Tensor([[4, 6], [2, 3]])) - ''' - - # Tests using less than the number of dims, and ellipsis - - # reference is 1 2 - # 3 4 - # 5 6 - reference = consec((3, 2)) - numpy_testing_assert_equal_helper(reference[ri([0, 2]),], np.array([[1, 2], [5, 6]])) - numpy_testing_assert_equal_helper(reference[ri([1]), ...], np.array([[3, 4]])) - numpy_testing_assert_equal_helper(reference[..., ri([1])], np.array([[2], [4], [6]])) - - # verify too many indices fails - with self.assertRaises(IndexError): reference[ri([1]), ri([0, 2]), ri([3])] - - # test invalid index fails - reference = Tensor.empty(10) - for err_idx in (10, -11): - with self.assertRaises(IndexError): - reference[err_idx] - # NOTE cannot check for out of bounds with Tensor indexing - # see tensor.py: __getitem__ (Tiny Things) - ''' - with self.assertRaises(IndexError): - reference[Tensor([err_idx], dtype=dtypes.int64)] - with self.assertRaises(IndexError): - reference[[err_idx]] - ''' - - def tensor_indices_to_np(tensor: Tensor, indices): - npt = tensor.numpy() - idxs = tuple(i.numpy().tolist() if isinstance(i, Tensor) and i.dtype == dtypes.int64 else - i for i in indices) - return npt, idxs - - def get_numpy(tensor, indices): - npt, idxs = tensor_indices_to_np(tensor, indices) - return Tensor(npt[idxs]) - - def set_numpy(tensor:Tensor, indices, value): - if not isinstance(value, int): - value = value.numpy() - npt, idxs = tensor_indices_to_np(tensor, indices) - npt[idxs] = value - return npt - - def assert_get_eq(tensor, indexer): - numpy_testing_assert_equal_helper(tensor[indexer], get_numpy(tensor, indexer)) - - def assert_set_eq(tensor: Tensor, indexer, val): - pyt = clone(tensor) - numt = clone(tensor) - pyt[indexer] = val - numt = set_numpy(numt, indexer, val) - numpy_testing_assert_equal_helper(pyt, numt) - - # NOTE: torch initiates the gradients using g0cpu (rand as gradients) - def assert_backward_eq(tensor: Tensor, indexer): - cpu = clone(tensor.float()) - cpu.requires_grad = True - outcpu = cpu[indexer].sum() - outcpu.backward() - dev = cpu.detach() - dev.requires_grad = True - outdev = dev[indexer].sum() - outdev.backward() - numpy_testing_assert_equal_helper(cpu.grad, dev.grad) - - def get_set_tensor(indexed: Tensor, indexer): - set_size = indexed[indexer].shape - set_count = indexed[indexer].numel() - set_tensor = Tensor.randint(set_count, high=set_count).reshape(set_size) #.cast(dtypes.float64) - return set_tensor - - # Tensor is 0 1 2 3 4 - # 5 6 7 8 9 - # 10 11 12 13 14 - # 15 16 17 18 19 - reference = Tensor.arange(0., 20).reshape(4, 5) - - indices_to_test = [ - # grab the second, fourth columns - [slice(None), [1, 3]], - - # first, third rows, - [[0, 2], slice(None)], - - # weird shape - [slice(None), [[0, 1], - [2, 3]]], - # negatives - [[-1], [0]], - [[0, 2], [-1]], - [slice(None), [-1]], - ] - - # only test dupes on gets - get_indices_to_test = indices_to_test + [[slice(None), [0, 1, 1, 2, 2]]] - - for indexer in get_indices_to_test: - assert_get_eq(reference, indexer) - assert_backward_eq(reference, indexer) - - for indexer in indices_to_test: - assert_set_eq(reference, indexer, 44) - assert_set_eq(reference, indexer, get_set_tensor(reference, indexer)) - - reference = Tensor.arange(0., 160).reshape(4, 8, 5) - - indices_to_test = [ - [slice(None), slice(None), [0, 3, 4]], - [slice(None), [2, 4, 5, 7], slice(None)], - [[2, 3], slice(None), slice(None)], - [slice(None), [0, 2, 3], [1, 3, 4]], - [slice(None), [0], [1, 2, 4]], - [slice(None), [0, 1, 3], [4]], - [slice(None), [[0, 1], [1, 0]], [[2, 3]]], - [slice(None), [[0, 1], [2, 3]], [[0]]], - [slice(None), [[5, 6]], [[0, 3], [4, 4]]], - [[0, 2, 3], [1, 3, 4], slice(None)], - [[0], [1, 2, 4], slice(None)], - [[0, 1, 3], [4], slice(None)], - [[[0, 1], [1, 0]], [[2, 1], [3, 5]], slice(None)], - [[[0, 1], [1, 0]], [[2, 3]], slice(None)], - [[[0, 1], [2, 3]], [[0]], slice(None)], - [[[2, 1]], [[0, 3], [4, 4]], slice(None)], - [[[2]], [[0, 3], [4, 1]], slice(None)], - # non-contiguous indexing subspace - [[0, 2, 3], slice(None), [1, 3, 4]], - - # less dim, ellipsis - [[0, 2], ], - [[0, 2], slice(None)], - [[0, 2], Ellipsis], - [[0, 2], slice(None), Ellipsis], - [[0, 2], Ellipsis, slice(None)], - [[0, 2], [1, 3]], - [[0, 2], [1, 3], Ellipsis], - [Ellipsis, [1, 3], [2, 3]], - [Ellipsis, [2, 3, 4]], - [Ellipsis, slice(None), [2, 3, 4]], - [slice(None), Ellipsis, [2, 3, 4]], - - # ellipsis counts for nothing - [Ellipsis, slice(None), slice(None), [0, 3, 4]], - [slice(None), Ellipsis, slice(None), [0, 3, 4]], - [slice(None), slice(None), Ellipsis, [0, 3, 4]], - [slice(None), slice(None), [0, 3, 4], Ellipsis], - [Ellipsis, [[0, 1], [1, 0]], [[2, 1], [3, 5]], slice(None)], - [[[0, 1], [1, 0]], [[2, 1], [3, 5]], Ellipsis, slice(None)], - [[[0, 1], [1, 0]], [[2, 1], [3, 5]], slice(None), Ellipsis], - ] - - for indexer in indices_to_test: - assert_get_eq(reference, indexer) - - assert_set_eq(reference, indexer, 212) - assert_set_eq(reference, indexer, get_set_tensor(reference, indexer)) - assert_backward_eq(reference, indexer) - - reference = Tensor.arange(0., 1296).reshape(3, 9, 8, 6) - - indices_to_test = [ - [slice(None), slice(None), slice(None), [0, 3, 4]], - [slice(None), slice(None), [2, 4, 5, 7], slice(None)], - [slice(None), [2, 3], slice(None), slice(None)], - [[1, 2], slice(None), slice(None), slice(None)], - [slice(None), slice(None), [0, 2, 3], [1, 3, 4]], - [slice(None), slice(None), [0], [1, 2, 4]], - [slice(None), slice(None), [0, 1, 3], [4]], - [slice(None), slice(None), [[0, 1], [1, 0]], [[2, 3]]], - [slice(None), slice(None), [[0, 1], [2, 3]], [[0]]], - [slice(None), slice(None), [[5, 6]], [[0, 3], [4, 4]]], - [slice(None), [0, 2, 3], [1, 3, 4], slice(None)], - [slice(None), [0], [1, 2, 4], slice(None)], - [slice(None), [0, 1, 3], [4], slice(None)], - [slice(None), [[0, 1], [3, 4]], [[2, 3], [0, 1]], slice(None)], - [slice(None), [[0, 1], [3, 4]], [[2, 3]], slice(None)], - [slice(None), [[0, 1], [3, 2]], [[0]], slice(None)], - [slice(None), [[2, 1]], [[0, 3], [6, 4]], slice(None)], - [slice(None), [[2]], [[0, 3], [4, 2]], slice(None)], - [[0, 1, 2], [1, 3, 4], slice(None), slice(None)], - [[0], [1, 2, 4], slice(None), slice(None)], - [[0, 1, 2], [4], slice(None), slice(None)], - [[[0, 1], [0, 2]], [[2, 4], [1, 5]], slice(None), slice(None)], - [[[0, 1], [1, 2]], [[2, 0]], slice(None), slice(None)], - [[[2, 2]], [[0, 3], [4, 5]], slice(None), slice(None)], - [[[2]], [[0, 3], [4, 5]], slice(None), slice(None)], - [slice(None), [3, 4, 6], [0, 2, 3], [1, 3, 4]], - [slice(None), [2, 3, 4], [1, 3, 4], [4]], - [slice(None), [0, 1, 3], [4], [1, 3, 4]], - [slice(None), [6], [0, 2, 3], [1, 3, 4]], - [slice(None), [2, 3, 5], [3], [4]], - [slice(None), [0], [4], [1, 3, 4]], - [slice(None), [6], [0, 2, 3], [1]], - [slice(None), [[0, 3], [3, 6]], [[0, 1], [1, 3]], [[5, 3], [1, 2]]], - [[2, 2, 1], [0, 2, 3], [1, 3, 4], slice(None)], - [[2, 0, 1], [1, 2, 3], [4], slice(None)], - [[0, 1, 2], [4], [1, 3, 4], slice(None)], - [[0], [0, 2, 3], [1, 3, 4], slice(None)], - [[0, 2, 1], [3], [4], slice(None)], - [[0], [4], [1, 3, 4], slice(None)], - [[1], [0, 2, 3], [1], slice(None)], - [[[1, 2], [1, 2]], [[0, 1], [2, 3]], [[2, 3], [3, 5]], slice(None)], - - # less dim, ellipsis - [Ellipsis, [0, 3, 4]], - [Ellipsis, slice(None), [0, 3, 4]], - [Ellipsis, slice(None), slice(None), [0, 3, 4]], - [slice(None), Ellipsis, [0, 3, 4]], - [slice(None), slice(None), Ellipsis, [0, 3, 4]], - [slice(None), [0, 2, 3], [1, 3, 4]], - [slice(None), [0, 2, 3], [1, 3, 4], Ellipsis], - [Ellipsis, [0, 2, 3], [1, 3, 4], slice(None)], - [[0], [1, 2, 4]], - [[0], [1, 2, 4], slice(None)], - [[0], [1, 2, 4], Ellipsis], - [[0], [1, 2, 4], Ellipsis, slice(None)], - [[1], ], - [[0, 2, 1], [3], [4]], - [[0, 2, 1], [3], [4], slice(None)], - [[0, 2, 1], [3], [4], Ellipsis], - [Ellipsis, [0, 2, 1], [3], [4]], - ] - - for indexer in indices_to_test: - assert_get_eq(reference, indexer) - assert_set_eq(reference, indexer, 1333) - assert_set_eq(reference, indexer, get_set_tensor(reference, indexer)) - - indices_to_test += [ - [slice(None), slice(None), [[0, 1], [1, 0]], [[2, 3], [3, 0]]], - [slice(None), slice(None), [[2]], [[0, 3], [4, 4]]], - ] - for indexer in indices_to_test: - assert_get_eq(reference, indexer) - assert_set_eq(reference, indexer, 1333) - assert_backward_eq(reference, indexer) - # TODO setitem backward ''' def test_set_item_to_scalar_tensor(self): @@ -969,11 +501,6 @@ class TestIndexing(unittest.TestCase): y = x[:, :, :, 1] z = y[:, 1:1, :] numpy_testing_assert_equal_helper((2, 0, 4), z.shape) - # this isn't technically necessary, but matches NumPy stride calculations. - # NOTE: this is empty and shouldn't have strides - #numpy_testing_assert_equal_helper((60, 20, 5), z.uop.st.real_strides()) - # NOTE tinygrad's int slicing implementation makes this not contiguous - # self.assertTrue(z.uop.st.contiguous) @unittest.skip("bool indexing not supported") def test_index_getitem_copy_bools_slices(self): @@ -1367,7 +894,7 @@ class TestNumpy(unittest.TestCase): a = Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - self.assertIsNot(a[...], a) + self.assertIs(a[...], a) numpy_testing_assert_equal_helper(a[...], a) # `a[...]` was `a` in numpy <1.9. #numpy_testing_assert_equal_helper(data_ptr(a[...]), data_ptr(a)) @@ -1510,9 +1037,9 @@ class TestNumpy(unittest.TestCase): # Before `...` would return a itself. a = Tensor([5]) - self.assertIsNot(a, a[()]) - self.assertIsNot(a, a[...]) - self.assertIsNot(a, a[:]) + self.assertIs(a, a[()]) + self.assertIs(a, a[...]) + self.assertIs(a, a[:]) def test_broaderrors_indexing(self): a = Tensor.zeros(5, 5) @@ -1569,5 +1096,474 @@ class TestNumpy(unittest.TestCase): numpy_testing_assert_equal_helper(kernel, kernel2) ''' +def tensor_indices_to_np(tensor: Tensor, indices): + npt = tensor.numpy() + idxs = tuple(i.numpy().tolist() if isinstance(i, Tensor) and i.dtype == dtypes.int64 else + i for i in indices) + return npt, idxs + +def get_numpy(tensor, indices): + npt, idxs = tensor_indices_to_np(tensor, indices) + return Tensor(npt[idxs]) + +def set_numpy(tensor:Tensor, indices, value): + if not isinstance(value, int): + value = value.numpy() + npt, idxs = tensor_indices_to_np(tensor, indices) + npt[idxs] = value + return npt + +def assert_get_eq(tensor, indexer): + numpy_testing_assert_equal_helper(tensor[indexer], get_numpy(tensor, indexer)) + +def assert_set_eq(tensor: Tensor, indexer, val): + pyt = clone(tensor) + numt = clone(tensor) + pyt[indexer] = val + numt = set_numpy(numt, indexer, val) + numpy_testing_assert_equal_helper(pyt, numt) + +# NOTE: torch initiates the gradients using g0cpu (rand as gradients) +def assert_backward_eq(tensor: Tensor, indexer): + cpu = clone(tensor.float()) + cpu.requires_grad = True + outcpu = cpu[indexer].sum() + outcpu.backward() + dev = cpu.detach() + dev.requires_grad = True + outdev = dev[indexer].sum() + outdev.backward() + numpy_testing_assert_equal_helper(cpu.grad, dev.grad) + +def get_set_tensor(indexed: Tensor, indexer): + set_size = indexed[indexer].shape + set_count = indexed[indexer].numel() + set_tensor = Tensor.randint(set_count, high=set_count).reshape(set_size) #.cast(dtypes.float64) + return set_tensor + +@unittest.skipIf(CI and Device.DEFAULT in ["CPU", "CL", "METAL", "NV", "AMD"], "slow") +class TestAdvancedIndexing(unittest.TestCase): + def test_integer_array_indexing(self): + # pick a random valid indexer type + def ri(indices): + choice = random.randint(0, 2) + if choice == 0: return Tensor(indices) + if choice == 1: return list(indices) + return tuple(indices) + + def validate_indexing(x): + numpy_testing_assert_equal_helper(x[[0]], consec((1,))) + numpy_testing_assert_equal_helper(x[ri([0]),], consec((1,))) + numpy_testing_assert_equal_helper(x[ri([3]),], consec((1,), 4)) + numpy_testing_assert_equal_helper(x[[2, 3, 4]], consec((3,), 3)) + numpy_testing_assert_equal_helper(x[ri([2, 3, 4]),], consec((3,), 3)) + numpy_testing_assert_equal_helper(x[ri([0, 2, 4]),], np.array([1, 3, 5])) + + def validate_setting(x): + x[[0]] = -2 + numpy_testing_assert_equal_helper(x[[0]], np.array([-2])) + x[[0]] = -1 + numpy_testing_assert_equal_helper(x[ri([0]), ], np.array([-1])) + x[[2, 3, 4]] = 4 + numpy_testing_assert_equal_helper(x[[2, 3, 4]], np.array([4, 4, 4])) + x[ri([2, 3, 4]), ] = 3 + numpy_testing_assert_equal_helper(x[ri([2, 3, 4]), ], np.array([3, 3, 3])) + x[ri([0, 2, 4]), ] = Tensor([5, 4, 3]) + numpy_testing_assert_equal_helper(x[ri([0, 2, 4]), ], np.array([5, 4, 3])) + + # Case 1: Purely Integer Array Indexing + reference = consec((10,)) + validate_indexing(reference) + # setting values + validate_setting(reference) + + # Tensor with stride != 1 + # strided is [1, 3, 5, 7] + + # # TODO: set stride + # reference = consec((10,)) + # strided = set_(reference, (4,), (2,), 0) + + # numpy_testing_assert_equal_helper(strided[[0]], np.array([1])) + # numpy_testing_assert_equal_helper(strided[ri([0]), ], np.array([1])) + # numpy_testing_assert_equal_helper(strided[ri([3]), ], np.array([7])) + # numpy_testing_assert_equal_helper(strided[[1, 2]], np.array([3, 5])) + # numpy_testing_assert_equal_helper(strided[ri([1, 2]), ], np.array([3, 5])) + # numpy_testing_assert_equal_helper(strided[ri([[2, 1], [0, 3]]), ], + # np.array([[5, 3], [1, 7]])) + + # stride is [4, 8] + + # strided = set_(reference, (2,), (4,), offset=4) + + # numpy_testing_assert_equal_helper(strided[[0]], np.array([5])) + # numpy_testing_assert_equal_helper(strided[ri([0]), ], np.array([5])) + # numpy_testing_assert_equal_helper(strided[ri([1]), ], np.array([9])) + # numpy_testing_assert_equal_helper(strided[[0, 1]], np.array([5, 9])) + # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ], np.array([5, 9])) + # numpy_testing_assert_equal_helper(strided[ri([[0, 1], [1, 0]]), ], + # np.array([[5, 9], [9, 5]])) + + # reference is 1 2 + # 3 4 + # 5 6 + reference = consec((3, 2)) + numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], np.array([1, 3, 5])) + numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([1])], np.array([2, 4, 6])) + numpy_testing_assert_equal_helper(reference[ri([0]), ri([0])], consec((1,))) + numpy_testing_assert_equal_helper(reference[ri([2]), ri([1])], consec((1,), 6)) + numpy_testing_assert_equal_helper(reference[[ri([0, 0]), ri([0, 1])]], np.array([1, 2])) + numpy_testing_assert_equal_helper(reference[[ri([0, 1, 1, 0, 2]), ri([1])]], np.array([2, 4, 4, 2, 6])) + numpy_testing_assert_equal_helper(reference[[ri([0, 0, 1, 1]), ri([0, 1, 0, 0])]], np.array([1, 2, 3, 3])) + + rows = ri([[0, 0], + [1, 2]]) + columns = [0], + numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[1, 1], + [3, 5]])) + + rows = ri([[0, 0], + [1, 2]]) + columns = ri([1, 0]) + numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[2, 1], + [4, 5]])) + rows = ri([[0, 0], + [1, 2]]) + columns = ri([[0, 1], + [1, 0]]) + numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[1, 2], + [4, 5]])) + + # setting values + reference[ri([0]), ri([1])] = -1 + numpy_testing_assert_equal_helper(reference[ri([0]), ri([1])], np.array([-1])) + reference[ri([0, 1, 2]), ri([0])] = Tensor([-1, 2, -4]) + numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], + np.array([-1, 2, -4])) + reference[rows, columns] = Tensor([[4, 6], [2, 3]]) + numpy_testing_assert_equal_helper(reference[rows, columns], + np.array([[4, 6], [2, 3]])) + + # Verify still works with Transposed (i.e. non-contiguous) Tensors + reference = Tensor([[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11]]).T + + # Transposed: [[0, 4, 8], + # [1, 5, 9], + # [2, 6, 10], + # [3, 7, 11]] + + numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], np.array([0, 1, 2])) + numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([1])], np.array([4, 5, 6])) + numpy_testing_assert_equal_helper(reference[ri([0]), ri([0])], np.array([0])) + numpy_testing_assert_equal_helper(reference[ri([2]), ri([1])], np.array([6])) + numpy_testing_assert_equal_helper(reference[[ri([0, 0]), ri([0, 1])]], np.array([0, 4])) + numpy_testing_assert_equal_helper(reference[[ri([0, 1, 1, 0, 3]), ri([1])]], np.array([4, 5, 5, 4, 7])) + numpy_testing_assert_equal_helper(reference[[ri([0, 0, 1, 1]), ri([0, 1, 0, 0])]], np.array([0, 4, 1, 1])) + + rows = ri([[0, 0], + [1, 2]]) + columns = [0], + numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[0, 0], [1, 2]])) + + rows = ri([[0, 0], + [1, 2]]) + columns = ri([1, 0]) + numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[4, 0], [5, 2]])) + rows = ri([[0, 0], + [1, 3]]) + columns = ri([[0, 1], + [1, 2]]) + numpy_testing_assert_equal_helper(reference[rows, columns], np.array([[0, 4], [5, 11]])) + + # TODO: non contiguous setitem + ''' + # setting values + reference[ri([0]), ri([1])] = -1 + numpy_testing_assert_equal_helper(reference[ri([0]), ri([1])], + np.array([-1])) + reference[ri([0, 1, 2]), ri([0])] = np.array([-1, 2, -4]) + numpy_testing_assert_equal_helper(reference[ri([0, 1, 2]), ri([0])], + np.array([-1, 2, -4])) + reference[rows, columns] = np.array([[4, 6], [2, 3]]) + numpy_testing_assert_equal_helper(reference[rows, columns], + np.array([[4, 6], [2, 3]])) + ''' + + # stride != 1 + + # strided is [[1 3 5 7], + # [9 11 13 15]] + + # # TODO: set stride + # reference = Tensor.arange(0., 24).reshape(3, 8) + # strided = set_(reference, (2,4), (8,2), 1) + + # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([0])], np.array([1, 9])) + # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([1])], np.array([3, 11])) + # numpy_testing_assert_equal_helper(strided[ri([0]), ri([0])], np.array([1])) + # numpy_testing_assert_equal_helper(strided[ri([1]), ri([3])], np.array([15])) + # numpy_testing_assert_equal_helper(strided[[ri([0, 0]), ri([0, 3])]], np.array([1, 7])) + # numpy_testing_assert_equal_helper(strided[[ri([1]), ri([0, 1, 1, 0, 3])]], np.array([9, 11, 11, 9, 15])) + # numpy_testing_assert_equal_helper(strided[[ri([0, 0, 1, 1]), ri([0, 1, 0, 0])]], np.array([1, 3, 9, 9])) + + # rows = ri([[0, 0], + # [1, 1]]) + # columns = [0], + # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[1, 1], [9, 9]])) + + # rows = ri([[0, 1], + # [1, 0]]) + # columns = ri([1, 2]) + # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[3, 13], [11, 5]])) + # rows = ri([[0, 0], + # [1, 1]]) + # columns = ri([[0, 1], + # [1, 2]]) + # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[1, 3], [11, 13]])) + + # setting values + + # strided is [[10, 11], + # [17, 18]] + + # # TODO: set stride + # reference = Tensor.arange(0., 24).reshape(3, 8) + # strided = set_(reference, (2,2), (7,1), 10) + + # numpy_testing_assert_equal_helper(strided[ri([0]), ri([1])], np.array([11])) + + # TODO non contiguous setitem + ''' + strided[ri([0]), ri([1])] = -1 + numpy_testing_assert_equal_helper(strided[ri([0]), ri([1])], + Tensor([-1])) + ''' + # # TODO: set stride + # reference = Tensor.arange(0., 24).reshape(3, 8) + # strided = set_(reference, (2,2), (7,1), 10) + + # numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([1, 0])], np.array([11, 17])) + + # TODO non contiguous setitem + ''' + strided[ri([0, 1]), ri([1, 0])] = Tensor([-1, 2]) + numpy_testing_assert_equal_helper(strided[ri([0, 1]), ri([1, 0])], + Tensor([-1, 2])) + ''' + + # # TODO: set stride + # reference = Tensor.arange(0., 24).realize().reshape(3, 8) + # strided = set_(reference, (2,2), (7,1), 10) + + # rows = ri([[0], + # [1]]) + # columns = ri([[0, 1], + # [0, 1]]) + # numpy_testing_assert_equal_helper(strided[rows, columns], np.array([[10, 11], [17, 18]])) + + # TODO non contiguous setitem + ''' + strided[rows, columns] = Tensor([[4, 6], [2, 3]]) + numpy_testing_assert_equal_helper(strided[rows, columns], + Tensor([[4, 6], [2, 3]])) + ''' + + # Tests using less than the number of dims, and ellipsis + + # reference is 1 2 + # 3 4 + # 5 6 + reference = consec((3, 2)) + numpy_testing_assert_equal_helper(reference[ri([0, 2]),], np.array([[1, 2], [5, 6]])) + numpy_testing_assert_equal_helper(reference[ri([1]), ...], np.array([[3, 4]])) + numpy_testing_assert_equal_helper(reference[..., ri([1])], np.array([[2], [4], [6]])) + + # verify too many indices fails + with self.assertRaises(IndexError): reference[ri([1]), ri([0, 2]), ri([3])] + + # test invalid index fails + reference = Tensor.empty(10) + for err_idx in (10, -11): + with self.assertRaises(IndexError): + reference[err_idx] + # NOTE cannot check for out of bounds with Tensor indexing + # see tensor.py: __getitem__ (Tiny Things) + ''' + with self.assertRaises(IndexError): + reference[Tensor([err_idx], dtype=dtypes.int64)] + with self.assertRaises(IndexError): + reference[[err_idx]] + ''' + + def test_numpy_parity_and_backward_2d(self): + # Tensor is 0 1 2 3 4 + # 5 6 7 8 9 + # 10 11 12 13 14 + # 15 16 17 18 19 + reference = Tensor.arange(0., 20).reshape(4, 5) + + indices_to_test = [ + # grab the second, fourth columns + [slice(None), [1, 3]], + + # first, third rows, + [[0, 2], slice(None)], + + # weird shape + [slice(None), [[0, 1], + [2, 3]]], + # negatives + [[-1], [0]], + [[0, 2], [-1]], + [slice(None), [-1]], + ] + + # only test dupes on gets + get_indices_to_test = indices_to_test + [[slice(None), [0, 1, 1, 2, 2]]] + + for indexer in get_indices_to_test: + assert_get_eq(reference, indexer) + assert_backward_eq(reference, indexer) + + for indexer in indices_to_test: + assert_set_eq(reference, indexer, 44) + assert_set_eq(reference, indexer, get_set_tensor(reference, indexer)) + + def test_numpy_parity_and_backward_3d(self): + reference = Tensor.arange(0., 160).reshape(4, 8, 5) + + indices_to_test = [ + [slice(None), slice(None), [0, 3, 4]], + [slice(None), [2, 4, 5, 7], slice(None)], + [[2, 3], slice(None), slice(None)], + [slice(None), [0, 2, 3], [1, 3, 4]], + [slice(None), [0], [1, 2, 4]], + [slice(None), [0, 1, 3], [4]], + [slice(None), [[0, 1], [1, 0]], [[2, 3]]], + [slice(None), [[0, 1], [2, 3]], [[0]]], + [slice(None), [[5, 6]], [[0, 3], [4, 4]]], + [[0, 2, 3], [1, 3, 4], slice(None)], + [[0], [1, 2, 4], slice(None)], + [[0, 1, 3], [4], slice(None)], + [[[0, 1], [1, 0]], [[2, 1], [3, 5]], slice(None)], + [[[0, 1], [1, 0]], [[2, 3]], slice(None)], + [[[0, 1], [2, 3]], [[0]], slice(None)], + [[[2, 1]], [[0, 3], [4, 4]], slice(None)], + [[[2]], [[0, 3], [4, 1]], slice(None)], + # non-contiguous indexing subspace + [[0, 2, 3], slice(None), [1, 3, 4]], + + # less dim, ellipsis + [[0, 2], ], + [[0, 2], slice(None)], + [[0, 2], Ellipsis], + [[0, 2], slice(None), Ellipsis], + [[0, 2], Ellipsis, slice(None)], + [[0, 2], [1, 3]], + [[0, 2], [1, 3], Ellipsis], + [Ellipsis, [1, 3], [2, 3]], + [Ellipsis, [2, 3, 4]], + [Ellipsis, slice(None), [2, 3, 4]], + [slice(None), Ellipsis, [2, 3, 4]], + + # ellipsis counts for nothing + [Ellipsis, slice(None), slice(None), [0, 3, 4]], + [slice(None), Ellipsis, slice(None), [0, 3, 4]], + [slice(None), slice(None), Ellipsis, [0, 3, 4]], + [slice(None), slice(None), [0, 3, 4], Ellipsis], + [Ellipsis, [[0, 1], [1, 0]], [[2, 1], [3, 5]], slice(None)], + [[[0, 1], [1, 0]], [[2, 1], [3, 5]], Ellipsis, slice(None)], + [[[0, 1], [1, 0]], [[2, 1], [3, 5]], slice(None), Ellipsis], + ] + + for indexer in indices_to_test: + assert_get_eq(reference, indexer) + + assert_set_eq(reference, indexer, 212) + assert_set_eq(reference, indexer, get_set_tensor(reference, indexer)) + assert_backward_eq(reference, indexer) + + def test_numpy_parity_and_backward_4d(self): + reference = Tensor.arange(0., 1296).reshape(3, 9, 8, 6) + + indices_to_test = [ + [slice(None), slice(None), slice(None), [0, 3, 4]], + [slice(None), slice(None), [2, 4, 5, 7], slice(None)], + [slice(None), [2, 3], slice(None), slice(None)], + [[1, 2], slice(None), slice(None), slice(None)], + [slice(None), slice(None), [0, 2, 3], [1, 3, 4]], + [slice(None), slice(None), [0], [1, 2, 4]], + [slice(None), slice(None), [0, 1, 3], [4]], + [slice(None), slice(None), [[0, 1], [1, 0]], [[2, 3]]], + [slice(None), slice(None), [[0, 1], [2, 3]], [[0]]], + [slice(None), slice(None), [[5, 6]], [[0, 3], [4, 4]]], + [slice(None), [0, 2, 3], [1, 3, 4], slice(None)], + [slice(None), [0], [1, 2, 4], slice(None)], + [slice(None), [0, 1, 3], [4], slice(None)], + [slice(None), [[0, 1], [3, 4]], [[2, 3], [0, 1]], slice(None)], + [slice(None), [[0, 1], [3, 4]], [[2, 3]], slice(None)], + [slice(None), [[0, 1], [3, 2]], [[0]], slice(None)], + [slice(None), [[2, 1]], [[0, 3], [6, 4]], slice(None)], + [slice(None), [[2]], [[0, 3], [4, 2]], slice(None)], + [[0, 1, 2], [1, 3, 4], slice(None), slice(None)], + [[0], [1, 2, 4], slice(None), slice(None)], + [[0, 1, 2], [4], slice(None), slice(None)], + [[[0, 1], [0, 2]], [[2, 4], [1, 5]], slice(None), slice(None)], + [[[0, 1], [1, 2]], [[2, 0]], slice(None), slice(None)], + [[[2, 2]], [[0, 3], [4, 5]], slice(None), slice(None)], + [[[2]], [[0, 3], [4, 5]], slice(None), slice(None)], + [slice(None), [3, 4, 6], [0, 2, 3], [1, 3, 4]], + [slice(None), [2, 3, 4], [1, 3, 4], [4]], + [slice(None), [0, 1, 3], [4], [1, 3, 4]], + [slice(None), [6], [0, 2, 3], [1, 3, 4]], + [slice(None), [2, 3, 5], [3], [4]], + [slice(None), [0], [4], [1, 3, 4]], + [slice(None), [6], [0, 2, 3], [1]], + [slice(None), [[0, 3], [3, 6]], [[0, 1], [1, 3]], [[5, 3], [1, 2]]], + [[2, 2, 1], [0, 2, 3], [1, 3, 4], slice(None)], + [[2, 0, 1], [1, 2, 3], [4], slice(None)], + [[0, 1, 2], [4], [1, 3, 4], slice(None)], + [[0], [0, 2, 3], [1, 3, 4], slice(None)], + [[0, 2, 1], [3], [4], slice(None)], + [[0], [4], [1, 3, 4], slice(None)], + [[1], [0, 2, 3], [1], slice(None)], + [[[1, 2], [1, 2]], [[0, 1], [2, 3]], [[2, 3], [3, 5]], slice(None)], + + # less dim, ellipsis + [Ellipsis, [0, 3, 4]], + [Ellipsis, slice(None), [0, 3, 4]], + [Ellipsis, slice(None), slice(None), [0, 3, 4]], + [slice(None), Ellipsis, [0, 3, 4]], + [slice(None), slice(None), Ellipsis, [0, 3, 4]], + [slice(None), [0, 2, 3], [1, 3, 4]], + [slice(None), [0, 2, 3], [1, 3, 4], Ellipsis], + [Ellipsis, [0, 2, 3], [1, 3, 4], slice(None)], + [[0], [1, 2, 4]], + [[0], [1, 2, 4], slice(None)], + [[0], [1, 2, 4], Ellipsis], + [[0], [1, 2, 4], Ellipsis, slice(None)], + [[1], ], + [[0, 2, 1], [3], [4]], + [[0, 2, 1], [3], [4], slice(None)], + [[0, 2, 1], [3], [4], Ellipsis], + [Ellipsis, [0, 2, 1], [3], [4]], + ] + + for indexer in indices_to_test: + assert_get_eq(reference, indexer) + assert_set_eq(reference, indexer, 1333) + assert_set_eq(reference, indexer, get_set_tensor(reference, indexer)) + + indices_to_test += [ + [slice(None), slice(None), [[0, 1], [1, 0]], [[2, 3], [3, 0]]], + [slice(None), slice(None), [[2]], [[0, 3], [4, 4]]], + ] + for indexer in indices_to_test: + assert_get_eq(reference, indexer) + assert_set_eq(reference, indexer, 1333) + assert_backward_eq(reference, indexer) + if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_kernelize.py b/test/unit/test_kernelize.py index baa49baff3..3cc0b0c0cc 100644 --- a/test/unit/test_kernelize.py +++ b/test/unit/test_kernelize.py @@ -1,7 +1,6 @@ import unittest from tinygrad import Tensor from tinygrad.uop import Ops -from tinygrad.helpers import RANGEIFY class TestKernelize(unittest.TestCase): def test_add_reshaped(self): @@ -18,11 +17,11 @@ class TestKernelize(unittest.TestCase): a1 = a.sum(axis=1) a0 = a1.sum(axis=0) a0.kernelize() - self.assertEqual(len([s for s in a0.uop.toposort() if s.op is Ops.KERNEL]), 2 if RANGEIFY else 3) - self.assertIs(a1.uop.base.op, Ops.REDUCE_AXIS if RANGEIFY else Ops.ASSIGN) + self.assertEqual(len([s for s in a0.uop.toposort() if s.op is Ops.KERNEL]), 2) + self.assertIs(a1.uop.base.op, Ops.REDUCE_AXIS) # input Tensor and user contiguous kernelize - self.assertIs(a0.uop.base.op, Ops.ASSIGN) - self.assertIs(a.uop.base.op, Ops.ASSIGN) + self.assertIs(a0.uop.base.op, Ops.AFTER) + self.assertIs(a.uop.base.op, Ops.AFTER) def test_two_reduce_w_add(self): a = Tensor.ones(16,16).contiguous() @@ -32,7 +31,7 @@ class TestKernelize(unittest.TestCase): # NOTE: the +1 is fused with a1, so a1 is not kernelized self.assertIs(a1.uop.base.op, Ops.REDUCE_AXIS) # the input to the REDUCE_AXIS is an ASSIGN though - self.assertIs(a1.uop.base.src[0].base.op, Ops.ASSIGN) + self.assertIs(a1.uop.base.src[0].base.op, Ops.AFTER) if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_linalg.py b/test/unit/test_linalg.py index 58fbe167e9..beb8800ff2 100644 --- a/test/unit/test_linalg.py +++ b/test/unit/test_linalg.py @@ -1,5 +1,5 @@ import unittest, functools -from tinygrad import Tensor +from tinygrad import Tensor, Context import numpy as np def orthogonality_helper(A:Tensor, tolerance=1e-5): @@ -12,6 +12,7 @@ def reconstruction_helper(A:list[Tensor],B:Tensor, tolerance=1e-5): np.testing.assert_allclose(reconstructed_tensor.numpy(),B.numpy(),atol=tolerance,rtol=tolerance) class TestLinAlg(unittest.TestCase): + @unittest.skip("TODO: reenable this") def test_svd_general(self): sizes = [(2,2),(5,3),(3,5),(3,4,4),(2,2,2,2,3)] for size in sizes: @@ -25,9 +26,8 @@ class TestLinAlg(unittest.TestCase): orthogonality_helper(V) reconstruction_helper([U,s_diag,V],a) - def test_svd_nonfull(self): - sizes = [(2,2),(5,3),(3,5),(2,2,2,2,3)] - for size in sizes: + def _test_svd_nonfull(self, size): + with Context(IGNORE_OOB=1): # sometimes this is slow in CI a = Tensor.randn(size).realize() U,S,V = a.svd(full_matrices=False) b_shape,m,n = size[0:-2],size[-2],size[-1] @@ -38,6 +38,12 @@ class TestLinAlg(unittest.TestCase): else: orthogonality_helper(U.transpose(-2,-1)),orthogonality_helper(V.transpose(-2,-1)) reconstruction_helper([U,s_diag,V],a) + # faster for parallel pytest + def test_svd_nonfull_2_2(self): self._test_svd_nonfull((2,2)) + def test_svd_nonfull_5_3(self): self._test_svd_nonfull((5,3)) + def test_svd_nonfull_3_5(self): self._test_svd_nonfull((3,5)) + def test_svd_nonfull_2_2_2_2_3(self): self._test_svd_nonfull((2,2,2,2,3)) + @unittest.skip("very big. recommend wrapping with TinyJit around inner function") def test_svd_large(self): size = (1024,1024) @@ -70,4 +76,4 @@ class TestLinAlg(unittest.TestCase): orthogonality_helper(b if size[-1] > size[-2] else b.transpose(-2, -1), tolerance=1e-3) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/test/unit/test_llm_tokenizer.py b/test/unit/test_llm_tokenizer.py index 7b65818a6f..1e7f6cb48a 100644 --- a/test/unit/test_llm_tokenizer.py +++ b/test/unit/test_llm_tokenizer.py @@ -1,19 +1,21 @@ import unittest, base64, functools, sys -from tinygrad.apps.llm import SimpleTokenizer, get_llama_re +from tinygrad.apps.llm import SimpleTokenizer from tinygrad.helpers import fetch @unittest.skipIf(sys.platform == 'win32', "fetch race condition on Windows") class TestLLMTokenizer(unittest.TestCase): - @functools.cached_property - def basic_tok(self): return SimpleTokenizer(".*", { b"a": 0, b"b": 1, b"c": 2, b"ab": 3, b"bc": 4 }, { "": 5, "": 6, "": 7 }) - @functools.cached_property def llama_tok(self): # from https://github.com/tinygrad/tinygrad/blob/e0106b6b257ebc003eb3694144e3e198f7d8cc37/examples/llama3.py#L14 model_file = fetch("https://huggingface.co/bofenghuang/Meta-Llama-3-8B/resolve/main/original/tokenizer.model") with open(model_file, "rt") as fd: - str_vocab = [ line.split(maxsplit=1) for line in fd.read().splitlines() if line ] - normal_tokens = { base64.b64decode(stok): int(srank) for stok, srank in str_vocab } + str_vocab = [line.split(maxsplit=1) for line in fd.read().splitlines() if line] + + # https://github.com/openai/gpt-2/blob/9b63575ef42771a015060c964af2c3da4cf7c8ab/src/encoder.py#L9 + bs = [*range(33, 127), *range(161, 173), *range(174, 256)] # bytes that map to themselves + _byte_decoder = {chr(b): b for b in bs} | {chr(256+i): b for i,b in enumerate(b for b in range(256) if b not in bs)} + _byte_encoder = {v:k for k,v in _byte_decoder.items()} + normal_tokens = {''.join([_byte_encoder[x] for x in base64.b64decode(stok)]): int(srank) for stok, srank in str_vocab} special_tokens = [ "<|begin_of_text|>", @@ -27,22 +29,12 @@ class TestLLMTokenizer(unittest.TestCase): "<|reserved_special_token_4|>", "<|eot_id|>", ] + [ f"<|reserved_special_token_{i}|>" for i in range(5, 256 - 5) ] - return SimpleTokenizer(get_llama_re(), normal_tokens, { token: len(normal_tokens) + i for i, token in enumerate(special_tokens) }) + return SimpleTokenizer(normal_tokens, {token: len(normal_tokens) + i for i, token in enumerate(special_tokens)}) def _test_coding(self, tok: SimpleTokenizer, text: str, expected_tokens: list[int]): self.assertEqual(tok.encode(text), expected_tokens) self.assertEqual(tok.decode(expected_tokens), text) - def test_abc(self): self._test_coding(self.basic_tok, "abc", [ 3, 2 ]) - def test_abbc(self): self._test_coding(self.basic_tok, "abbc", [ 3, 4 ]) - def test_aabbbcc(self): self._test_coding(self.basic_tok, "aabbbcc", [ 0, 3, 1, 4, 2 ]) - def test_specials1(self): self._test_coding(self.basic_tok, "aaaa", [ 0, 5, 0, 6, 0, 7, 0 ]) - def test_specials2(self): self._test_coding(self.basic_tok, "aa", [ 5, 0, 6, 0, 7 ]) - def test_invalid_token(self): - with self.assertRaises(RuntimeError): self._test_coding(self.basic_tok, "L", []) - - def test_no_specials(self): self._test_coding(SimpleTokenizer(".*", { bytes([i]): i for i in range(256) }, {}), "abc", [97, 98, 99]) - # NOTE: the correct tokenization for this can only be found by looking up the text chunk in the vocab, not by applying merges def test_llama_early_tokenize(self): self._test_coding(self.llama_tok, " например", [ 111797 ]) diff --git a/test/unit/test_pattern_matcher.py b/test/unit/test_pattern_matcher.py index c759f6436c..47c6055350 100644 --- a/test/unit/test_pattern_matcher.py +++ b/test/unit/test_pattern_matcher.py @@ -50,7 +50,7 @@ class TestPatternMatcher(unittest.TestCase): def fxn(ctx, x): ctx.append(True) assert len(x.src) == 0 - return UOp(Ops.CONST, src=(UOp(Ops.CONST),)) + return x.replace(src=(UOp(Ops.DEVICE, arg="blah"),)) matcher = PatternMatcher([(UPat(Ops.CONST, src=(), name="x"), fxn)]) c1 = UOp(Ops.CONST, dtypes.float, arg=1.0) # second rewrite shouldn't match anything diff --git a/test/unit/test_rewrite_map.py b/test/unit/test_rewrite_map.py index 0e4d4c7772..a299888725 100644 --- a/test/unit/test_rewrite_map.py +++ b/test/unit/test_rewrite_map.py @@ -28,6 +28,22 @@ class TestRewriteMap(unittest.TestCase): self.assertIs(sub_map[a+b], e) self.assertIs(sub_map[(a+b)*c], f) + def test_multistage_substitute(self): + a = UOp.variable('a', 0, 10) + b = UOp.variable('b', 0, 10) + c = UOp.variable('c', 0, 10) + d = UOp.variable('d', 0, 10) + sub1 = {a+b:c} + start = (a+b)*c + # stage 1: (a+b)*c -> c*c + sub_map1 = graph_rewrite_map(start, _substitute, sub1, bottom_up=True) + self.assertIs(sub_map1[(a+b)*c], c*c) + # stage 2: c*c -> d + sub2 = {c*c:d} + sub_map2 = graph_rewrite_map(sub_map1[start], _substitute, sub2, input_map=sub_map1, bottom_up=True) + # (a+b)*c -> c*c -> d + self.assertIs(sub_map2[(a+b)*c], d) + def test_add_zero(self): # Build a small graph: add(0, add(const=0, const=5)) zero_node = UOp.const(dtypes.index, 0) @@ -128,11 +144,11 @@ class TestRewriteMap(unittest.TestCase): yz_sum_zero = yz_sum + zero_node -> rewrites to yz_sum yz_neg = -yz_sum_zero -> -(y+z) yz_dneg = -yz_neg -> y+z (double neg gone) - x_plus_yz = x_var + yz_dneg -> (x+y)+z (add nodes get sorted) - double_neg_x = -(-x_plus_yz) -> (x+y)+z - final_expr = double_neg_x * one_node -> (x+y)+z + x_plus_yz = x_var + yz_dneg -> x + (y+z) + double_neg_x = -(-x_plus_yz) -> x + (y+z) + final_expr = double_neg_x * one_node -> x + (y+z) - We expect the final result to be ((x+y)+z). + We expect the final result to be (x + (y+z)). Each original node should map to the final node that replaces it, which might be structurally equivalent but not the same reference. """ @@ -147,9 +163,9 @@ class TestRewriteMap(unittest.TestCase): yz_sum_zero = yz_sum + zero_node # (y + z) + 0 yz_neg = -yz_sum_zero # -(y+z) yz_dneg = -yz_neg # -(-(y+z)) -> (y+z) - x_plus_yz = x_var + yz_dneg # x + (y+z) -> (x+y)+z - double_neg_x = -(-x_plus_yz) # neg(neg(x+(y+z))) -> (x+y)+z - final_expr = double_neg_x * one_node # ((x+y)+z) * 1 -> (x+y)+z + x_plus_yz = x_var + yz_dneg # x + (y+z) + double_neg_x = -(-x_plus_yz) # neg(neg(x+(y+z))) -> x+(y+z) + final_expr = double_neg_x * one_node # (x+(y+z)) * 1 -> x+(y+z) node_map = graph_rewrite_map(final_expr, symbolic) @@ -166,15 +182,14 @@ class TestRewriteMap(unittest.TestCase): # -(-(y+z)) => (y+z) self.assertEqual(node_map[yz_dneg], yz_sum) - # x + (y+z) => (x+y)+z - expected_xyz = (x_var + y_var) + z_var - self.assertEqual(node_map[x_plus_yz], expected_xyz) + # x + (y+z) => might get recreated if yz_dneg was changed, so compare to x + yz_sum + self.assertEqual(node_map[x_plus_yz], x_var + yz_sum) - # -(-(x+(y+z))) => (x+y)+z - self.assertEqual(node_map[double_neg_x], expected_xyz) + # -(-(x+(y+z))) => x + (y+z) + self.assertEqual(node_map[double_neg_x], x_var + yz_sum) - # ((x+y)+z) * 1 => (x+y)+z - self.assertEqual(node_map[final_expr], expected_xyz) + # (x+(y+z)) * 1 => x+(y+z) + self.assertEqual(node_map[final_expr], x_var + yz_sum) # Unchanged atomic nodes map to themselves self.assertEqual(node_map[x_var], x_var) diff --git a/test/unit/test_rewrite_not_ready.py b/test/unit/test_rewrite_not_ready.py deleted file mode 100644 index b1e19fe0c1..0000000000 --- a/test/unit/test_rewrite_not_ready.py +++ /dev/null @@ -1,110 +0,0 @@ -import unittest -from dataclasses import dataclass, field -from tinygrad.uop.ops import PatternMatcher, UOp, graph_rewrite, Ops, UPat, GroupOp, RewriteNotReady - -# we could insert CHILDREN node - -@dataclass -class ChildrenContext: - children: dict[UOp, list[UOp]]|None = None - -# this is a generic child labeller -def extract_children(ctx:ChildrenContext, x:UOp): - if ctx.children is not None: return - ctx.children = {k:list(v.keys()) for k,v in x.get_children_map().items() if len(v) > 1} - -def mark_children(ctx:ChildrenContext, x:UOp): - new_srcs = [(UOp(Ops.CHILD, s.dtype, src=(s,), arg=(ctx.children[s].index(x), len(ctx.children[s]))) if s in ctx.children else s) for s in x.src] - return x.replace(src=tuple(new_srcs)) - -pm_children = PatternMatcher([ - (UPat(Ops.SINK, name="x"), extract_children), - (UPat(GroupOp.All-{Ops.CHILD}, name="x"), mark_children), -]) - -@dataclass -class TestContext: - seen_children: dict[UOp, set[int]] = field(default_factory=dict) - ready_children: dict[UOp, set[int]] = field(default_factory=dict) - seen_consts:int = 0 - saved_seen_consts:int = 0 - exp2_visit_count:int = 0 - -# this is a generic pattern -def visit_child(ctx:ChildrenContext, x:UOp): - if x.src[0] not in ctx.seen_children: - ctx.seen_children[x.src[0]] = set() - ctx.ready_children[x.src[0]] = set() - ctx.seen_children[x.src[0]].add(x.arg[0]) - if len(ctx.seen_children[x.src[0]]) != x.arg[1]: - print(f"visit CHILD {x.arg} bottom up -- not ready {ctx.seen_children[x.src[0]]}") - raise RewriteNotReady - print(f"visit CHILD {x.arg} bottom up -- READY {ctx.seen_children[x.src[0]]}") - ctx.ready_children[x.src[0]].add(x.arg[0]) - -pm_child_visitor = PatternMatcher([ - (UPat(Ops.CHILD, name="x"), visit_child), -]) - -# this is for the test -def see_const(ctx:ChildrenContext, c:UOp): ctx.seen_consts += c.arg -def see_exp2(ctx:ChildrenContext): ctx.exp2_visit_count += 1 -def save_seen_consts(ctx:ChildrenContext, x:UOp): ctx.saved_seen_consts = ctx.seen_consts -pm_consts = PatternMatcher([ - (UPat(Ops.DEFINE_VAR, name="x"), save_seen_consts), - (UPat()+UPat.cvar("c"), see_const), - (UPat(Ops.EXP2), see_exp2), -]) - -class TestChildrenRewrite(unittest.TestCase): - def test_not_ready_double_simple(self): - global_a = UOp.variable("a", 0, 10).exp2() - inter = (global_a+global_a).exp2() - global_sink = (inter+inter).sink() - - sink = graph_rewrite(global_sink, pm_children, ctx=ChildrenContext(), bottom_up=True) - ctx = TestContext() - graph_rewrite(sink, pm_consts, ctx=ctx, bottom_up=True) - self.assertEqual(ctx.exp2_visit_count, 2) - - def test_not_ready_double(self): - global_a = UOp.variable("a", 0, 10).exp2() - inter = ((global_a+1000)+(global_a+100)).exp2() - global_sink = ((inter+10)+(inter+1)).sink() - - sink = graph_rewrite(global_sink, pm_children, ctx=ChildrenContext(), bottom_up=True) - print("test_not_ready_double") - ctx = TestContext() - graph_rewrite(sink, pm_child_visitor+pm_consts, ctx=ctx, bottom_up=True) - self.assertEqual(ctx.exp2_visit_count, 2) - self.assertEqual(ctx.seen_consts, ctx.saved_seen_consts) - self.assertEqual(ctx.seen_consts, 1111) - - def test_in_srcs_twice(self): - global_a = UOp.variable("a", 0, 10).exp2() - global_sink = (global_a+global_a).sink() - - ctx = TestContext() - graph_rewrite(global_sink, pm_consts, ctx=ctx, bottom_up=True) - self.assertEqual(ctx.exp2_visit_count, 1) - - def test_not_ready(self): - global_a = UOp.variable("a", 0, 10).exp2() - global_sink = ((global_a+2)+(global_a+3)).sink() - - # without children and not ready, we don't see both adds before the DEFINE_VAR - ctx = TestContext() - graph_rewrite(global_sink, pm_consts, ctx=ctx, bottom_up=True) - self.assertNotEqual(ctx.seen_consts, ctx.saved_seen_consts) - self.assertEqual(ctx.exp2_visit_count, 1) - - # with children and not ready we do - sink = graph_rewrite(global_sink, pm_children, ctx=ChildrenContext(), bottom_up=True) - ctx = TestContext() - graph_rewrite(sink, pm_child_visitor+pm_consts, ctx=ctx, bottom_up=True) - self.assertEqual(ctx.seen_consts, ctx.saved_seen_consts) - self.assertEqual(ctx.exp2_visit_count, 1) - self.assertSetEqual(list(ctx.ready_children.values())[0], {0,1}) - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_rewrite_tracked_childen.py b/test/unit/test_rewrite_tracked_childen.py deleted file mode 100644 index 21c32269ef..0000000000 --- a/test/unit/test_rewrite_tracked_childen.py +++ /dev/null @@ -1,63 +0,0 @@ -import unittest -from tinygrad import Tensor -from tinygrad.uop.ops import PatternMatcher, Ops, UPat, graph_rewrite, RewriteContext, UOp -from tinygrad.schedule.kernelize import kernelize_sym, merge_views - -class TestRewriteTrackedChildren(unittest.TestCase): - @unittest.skip("track_children no longer supported") - def test_children_in_context(self): - def print_children(ctx:RewriteContext, sink:UOp): - view_w_child = sink.src[0].src[0].src[0] - assert view_w_child.op is Ops.VIEW - assert set([x.arg for x in ctx.children[view_w_child]]) == set((2,3)) - ctx.update_children() - assert set([x.arg for x in ctx.children[view_w_child]]) == set((3,4)) - # this is the 3 - assert len(ctx.children[sink.src[0].src[1]]) == 1 - assert next(iter(ctx.children[sink.src[0].src[1]])).op is Ops.ADD - # this is the 4 - assert len(ctx.children[sink.src[0].src[0]]) == 1 - assert next(iter(ctx.children[sink.src[0].src[0]])).op is Ops.ADD - rewrite = PatternMatcher([ - (UPat(Ops.CONST, arg=2, name="x"), lambda x: x.replace(arg=4)), - (UPat(Ops.SINK, name="sink"), print_children) - ]) - a = Tensor(2) - b = Tensor(3) - c = a + b - sink = c.uop.sink() - sink = graph_rewrite(sink, rewrite, track_children=True) - - def test_simple_child(self): - rewrite = PatternMatcher([ - (UPat(Ops.CONST, arg=2, name="x"), lambda x: x.replace(arg=4)), - ]) - a = Tensor(2) - b = Tensor(3) - c = a + b - sink = c.uop - view_w_child = a.uop.src[0] - print([x().arg for x in view_w_child.children]) - print([x.arg for x in sink.get_children_map()[view_w_child]]) - self.assertSetEqual(set([x.arg for x in sink.get_children_map()[view_w_child]]), set((2,3))) - # children can either be added to or removed from the map with graph_rewrite - # added to is easy to detect, just hook the UOp constructor - # when are children removed? - # * if a rewrite rule returns a UOp, the matched node is removed from the graph - sink = graph_rewrite(sink, rewrite) - print([x().arg for x in view_w_child.children]) - print([x.arg for x in sink.get_children_map()[view_w_child]]) - self.assertSetEqual(set([x.arg for x in sink.get_children_map()[view_w_child]]), set((3,4))) - - @unittest.skip("track_children no longer supported") - def test_child_after_parent_update(self): - def print_children(ctx, r): - ctx.update_children() - print(ctx.children[r]) - extra = PatternMatcher([(UPat(Ops.REDUCE_AXIS, name="r"), print_children)]) - a = Tensor.empty(3, 3) - r = (a+0).sum() - graph_rewrite(r.uop, merge_views+kernelize_sym+extra, track_children=True) - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_shapetracker.py b/test/unit/test_shapetracker.py deleted file mode 100644 index ee9a201a36..0000000000 --- a/test/unit/test_shapetracker.py +++ /dev/null @@ -1,858 +0,0 @@ -#!/usr/bin/env python -import unittest -import numpy as np -from tinygrad.dtype import dtypes, Invalid -from tinygrad.helpers import prod -from tinygrad.shape.shapetracker import ShapeTracker, View -from tinygrad import Variable -from tinygrad.uop.ops import UOp, Ops, graph_rewrite -from tinygrad.codegen.late.devectorizer import sym -from itertools import product - -def shapetracker_getitem(st:ShapeTracker, val:int): - valid_idx = st.reshape((st.size,)).to_valid_uop([UOp.const(dtypes.int, val)]) - idx, valid = valid_idx.get_idx(), valid_idx.get_valid() - idx, valid = graph_rewrite(idx, sym), graph_rewrite(valid, sym) - assert idx.op is Ops.CONST and valid.op is Ops.CONST - return idx.arg, valid.arg - -class CheckingShapeTracker: - def __init__(self, shape): - self.st = ShapeTracker.from_shape(shape) - self.t = np.arange(prod(shape), dtype=np.int32).reshape(shape) - - @property - def shape(self): - return self.t.shape - - def simplify(self): - self.st = self.st.simplify() - return self - - def reshape(self, new_shape): - self.st = self.st.reshape(new_shape) - self.t = self.t.reshape(new_shape) - return self - - def permute(self, axis): - self.st = self.st.permute(axis) - self.t = np.transpose(self.t, axis) - return self - - def expand(self, new_shape): - self.st = self.st.expand(new_shape) - self.t = np.broadcast_to(self.t, new_shape) - return self - - def flip(self, arg): - self.st = self.st.flip(arg) - self.t = np.flip(self.t, tuple(i for i in range(len(arg)) if arg[i])) - return self - - def shrink(self, arg): - self.st = self.st.shrink(arg) - self.t = self.t[tuple([slice(x[0], x[1]) for x in arg])] - return self - - def pad(self, arg): - self.st = self.st.pad(arg) - self.t = np.pad(self.t, arg, constant_values=-1) - return self - - def __getitem__(self, val): - return self.t.flatten()[val] - - @property - def views(self): return self.st.views - - @property - def contiguous(self): return self.st.contiguous - - def assert_same(self): - x = [(v[0] if (v:=shapetracker_getitem(self.st, i))[1] and v[0] is not Invalid else -1) for i in range(prod(self.st.shape))] - y = [self[i] for i in range(prod(self.shape))] - assert self.st.shape == self.shape - assert x == y, f"mismatch shapetracker:{x} real:{y}" - -@unittest.skip("don't create shapetrackers with views") -class TestRealIssues(unittest.TestCase): - def test_reshape_doesnt_multiview(self): - self.st = ShapeTracker((View.create((256, 256, 2, 2, 2, 2, 2, 256, 8, 2), (0, 8, 0, 4, 0, 0, 2, 16384, 2048, 1), 0, None),)) - self.st.reshape((128, 2, 256, 2, 2, 2, 2, 2, 256, 8, 2)) - assert len(self.st.views) == 1 - - def test_reshape_stable_diffusion(self): - # regression test for https://github.com/tinygrad/tinygrad/pull/2616 - st = ShapeTracker((View((2, 1920, 32, 32), (1310720, 1024, 32, 1), 0, ((0, 2), (0, 1280), (0, 32), (0, 32)), False),)) - st = st.reshape((2, 32, 240, 256)) - assert len(st.views) == 2 - - def test_reshape_trailing_invalid_ones(self): - st = ShapeTracker((View(shape=(1, 1, 5), strides=(0, 0, 1), offset=-5, mask=((1, 1), (0, 1), (0, 5)), contiguous=False),)) - st = st.reshape((5,)) - assert len(st.views) == 1 - assert st.views[0].mask == ((0,0),) - -class TestRealDoesntSimplify(unittest.TestCase): - def tearDown(self): - st = self.st.real_strides() - print(st) - self.st = self.st.simplify() - assert len(self.st.views) != 1 - assert None in st - - def test_1(self): - self.st = ShapeTracker(( - View.create((8, 3, 1, 2, 11, 1), (33, 11, 0, 0, 1, 0), 0, None), - View.create((8, 6, 11), (66, 11, 1), 0, None))) - self.assertEqual(self.st.real_strides(), (33, None, 1)) - - def test_2(self): - self.st = ShapeTracker(( - View.create((2, 2, 4, 3, 3), (72, 9, 18, -3, -1), 8, None), - View.create((4, 4, 3, 3), (36, 9, 3, 1), 0, None))) - self.assertEqual(self.st.real_strides(), (None, 18, -3, -1)) - -class TestRealStrides(unittest.TestCase): - def test_1(self): - st = ShapeTracker(( - View.create((2048,), (1,), 0, ((0, 512),)), - View.create((16, 32, 4), (128, 4, 1), 0, None), - )) - self.assertEqual(st.real_strides(), (None, 4, 1)) - - def test_2(self): - # test/test_ops.py::TestOps::test_simple_padding_conv1d - st = ShapeTracker(( - View.create((6, 2, 5, 14), (90, 45, 1, 5), 0, ((0, 6), (0, 2), (0, 5), (0, 9))), - View.create((6, 2, 78), (140, 70, 1), 0, ((0, 6), (0, 2), (0, 70))), - View.create((6, 2, 13, 6), (156, 78, 1, 13), 0, None), - )) - self.assertEqual(st.real_strides(), (90, 45, None, None)) - - def test_3(self): - # test/test_ops.py::TestOps::test_simple_cumsum - st = ShapeTracker(( - View.create((4, 256, 512), (256, 0, 1), 0, ((0, 4), (0, 256), (0, 256))), - View.create((4, 131327), (131072, 1), 0, ((0, 4), (0, 131072))), - View.create((4, 511, 257), (131327, 1, 511), 0, None), - )) - self.assertEqual(st.real_strides(), (256, None, None)) - - def test_4(self): - # test/test_nn.py::TestNN::test_conv_transpose1d - st = ShapeTracker(( - View.create((4, 16, 56, 2), (896, 56, 1, 0), 0, ((0, 4), (0, 16), (0, 56), (0, 1))), - View.create((1, 4, 1, 16, 8, 121), (0, 1792, 0, 112, 0, 1), -5, ((0, 1), (0, 4), (0, 1), (0, 16), (0, 8), (5, 116))), - View.create((4, 64, 115, 16, 7), (15488, 0, 1, 968, 122), 0, None), - )) - self.assertEqual(st.real_strides(), (896, 0, None, 56, None)) - - def test_5(self): - # test/test_ops.py::TestOps::test_conv2d - st = ShapeTracker(( - View.create((1, 3, 1, 12, 2, 8), (0, 132, 0, 12, 1, 2), 0, ((0, 1), (0, 3), (0, 1), (0, 11), (0, 2), (0, 6))), - View.create((1, 3, 22, 21), (0, 192, 16, 1), 0, ((0, 1), (0, 3), (0, 12), (0, 16))), - View.create((3, 11, 7, 2, 3), (462, 21, 1, 231, 7), 0, None), - )) - self.assertEqual(st.real_strides(), (132, 12, None, None, None)) - -class TestRealSimplifies(unittest.TestCase): - def tearDown(self): - st = self.st.real_strides() - self.st = self.st.simplify() - assert len(self.st.views) == 1 - print(self.st.views[-1].strides, st) - self.assertEqual(self.st.views[-1].strides, st) - - def test_1(self): - self.st = ShapeTracker(( - View.create((1, 3, 2, 11, 4, 28), (0, 308, 0, 28, 0, 1), 0, None), - View.create((1, 3, 2, 11, 26, 1, 1, 3), (0, 2464, 0, 112, 1, 0, 0, 29), 0, None))) - - def test_2(self): - self.st = ShapeTracker(( - View.create((8, 3, 3, 11, 2, 28), (924, 308, 0, 28, 0, 1), 0, None), - View.create((8, 1, 6, 10, 28, 3, 2, 1), (5544, 0, 0, 56, 1, 1848, 672, 0), 0, None))) - -class TestViewMinify(unittest.TestCase): - def test_minifies(self): - assert len(View.create((10,10)).minify().shape) == 1 - assert len(View.create((10,10)).permute((1,0)).minify().shape) == 2 - assert len(View.create((10,10,10,10)).permute((1,0,2,3)).minify().shape) == 3 - -class TestIndexExpressions2d(unittest.TestCase): - def setUp(self): - shapes = [(30, 5), (15, 10), (15, 1), (5, 10), (5, 1)] # Make sure dim0 is a multiple of 5, one of the tests divides this dimension by 5 - offsets = [0, 1, 15, 28, 10000] - self.sts = [ShapeTracker.from_shape((prod(base_shape)+offset,)).shrink(((offset, offset+prod(base_shape)),)).\ - reshape(base_shape) for base_shape in shapes for offset in offsets] - self.offset = [offset for base_shape in shapes for offset in offsets] - self.shapes = [shape for shape in shapes for offset in offsets] - self.idxs_exprs = [] - - def tearDown(self): - for st, offset, shape, idxs_expr in zip(self.sts, self.offset, self.shapes, self.idxs_exprs): - numel = prod(shape) - self.check_bounds(idxs_expr(self.default_idxs(st.shape)), offset, numel) - idx0s = [(0,0), (0, min(1, st.shape[0]-1)), (0, st.shape[0]-1), (min(3, st.shape[0]-1), min(6, st.shape[0]-1)), (st.shape[0]-1, st.shape[0]-1)] - idx1s = [(0,0), (0, min(1, st.shape[1]-1)), (0, st.shape[1]-1), (min(3, st.shape[1]-1), min(6, st.shape[1]-1)), (st.shape[1]-1, st.shape[1]-1)] - idx2s = [(0,0), (0, min(1, st.shape[2]-1)), (0, st.shape[2]-1), (min(3, st.shape[2]-1), min(6, st.shape[2]-1)), - (st.shape[2]-1, st.shape[2]-1)] if len(st.shape) == 3 else [None for _ in idx0s] - for idx0, idx1, idx2 in product(idx0s, idx1s, idx2s): - idxs = [Variable(f"idx{i}", idx[0], idx[1]) for i, idx in enumerate((idx0, idx1, idx2)) if idx is not None] - self.check_bounds(idxs_expr(idxs), offset, numel) - - def default_idx(self, shape): - return Variable("idx", 0, prod(shape)-1) - - def default_idxs(self, shape): - return [Variable(f"idx{i}", 0, d-1) for i,d in enumerate(shape)] - - def check_bounds(self, expr, offset, numel): - assert expr.vmin >= offset - assert expr.vmax <= offset + numel - 1 - - def test_noop(self): - for st, base_shape, offset in zip(self.sts, self.shapes, self.offset): - self.idxs_exprs.append(lambda idxs, base_shape=base_shape, offset=offset: idxs[0]*base_shape[1] + idxs[1] + offset) - - def test_permute(self): - new_st = [] - for st, base_shape, offset in zip(self.sts, self.shapes, self.offset): - st = st.permute((1, 0)) - self.idxs_exprs.append(lambda idxs, base_shape=base_shape, offset=offset: idxs[0] + idxs[1]*base_shape[1] + offset) - new_st.append(st) - self.sts = new_st - - def test_reshape(self): - new_st = [] - for st, base_shape, offset in zip(self.sts, self.shapes, self.offset): - st = st.reshape((base_shape[0], 1, base_shape[1])) - self.idxs_exprs.append(lambda idxs, base_shape=base_shape, offset=offset: idxs[0]*base_shape[1] + idxs[2] + offset) - new_st.append(st) - self.sts = new_st - - def test_reshape_expand(self): - new_st = [] - for st, base_shape, offset in zip(self.sts, self.shapes, self.offset): - st = st.reshape((base_shape[0], 1, base_shape[1])) - st = st.expand((base_shape[0], base_shape[1], base_shape[1])) - self.idxs_exprs.append(lambda idxs, base_shape=base_shape, offset=offset: idxs[0]*base_shape[1] + idxs[2] + offset) - new_st.append(st) - self.sts = new_st - - def test_permute_reshape_1(self): # This tests multiple views - new_st = [] - for st, base_shape, offset in zip(self.sts, self.shapes, self.offset): - st = st.permute((1, 0)) - st = st.reshape((base_shape[0]//5, 1, base_shape[1]*5)) - self.idxs_exprs.append(lambda idxs, base_shape=base_shape, offset=offset: (idxs[0]*(base_shape[1]*5)+idxs[2])%base_shape[0]*base_shape[1] + \ - (idxs[0]*(base_shape[1]*5)+idxs[2])//base_shape[0] + offset) - new_st.append(st) - self.sts = new_st - - def test_permute_reshape_2(self): - new_st = [] - for st, base_shape, offset in zip(self.sts, self.shapes, self.offset): - st = st.permute((1, 0)) - st = st.reshape((1, base_shape[0]//5, base_shape[1]*5)) - self.idxs_exprs.append(lambda idxs, base_shape=base_shape, offset=offset: (idxs[1]*(base_shape[1]*5)+idxs[2])%base_shape[0]*base_shape[1] + \ - (idxs[1]*(base_shape[1]*5)+idxs[2])//base_shape[0] + offset) - new_st.append(st) - self.sts = new_st - - def test_reshaping_splitting(self): - self.st = CheckingShapeTracker((5,10,5,10)) - self.st.permute((1, 0, 3, 2)) - self.st.pad(((0,0), (0,5), (0,0), (0,5))) - self.st.reshape((10,2,5,10,2,5)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_reshape_splitting_1(self): - self.st = CheckingShapeTracker((1,10,1)) - self.st.pad(((0,4),(0,0),(1,0))) - self.st.reshape((5,5,2,2)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_reshape_combining_1(self): - self.st = CheckingShapeTracker((2,1,10)) - self.st.pad(((2,6), (0,0), (0,0))) - self.st.reshape((100,)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_reshape_combining_2(self): - self.st = CheckingShapeTracker((1,1,5)) - self.st.pad(((3,6), (0,0), (0,5))) - self.st.reshape((100,)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_reshape_combining_3(self): - self.st = CheckingShapeTracker((1,1,4)) - self.st.pad(((3,6), (0,0), (1,5))) - self.st.reshape((100,)) - assert len(self.st.views) == 1 - assert self.st.views[0].mask[0] == (31, 35) - self.st.assert_same() - - def test_reshape_combining_4(self): - # interestingly this one is quite slow - self.st = CheckingShapeTracker((1,1,5,5,1,1,5)) - self.st.pad(((2,1), (0,0), (0,2), (0,0), (2,1), (0,0), (0,2))) - self.st.reshape((28,5,28)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_reshape_splitting_combining(self): - self.st = CheckingShapeTracker((1,5,5)) - self.st.pad(((0,4), (0,5), (0,0))) - self.st.reshape((10,25)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_reshape_only_1s(self): - self.st = CheckingShapeTracker((1, 1, 1, 4, 1, 3, 5, 1)) - self.st.pad(((0,4), (0,0), (0,0), (1,1), (0,0), (0,0), (0,0), (0,0))) - self.st.reshape((5, 6, 3, 5)) - assert len(self.st.views) == 1 - self.st.assert_same() - self.st.reshape((1, 1, 5, 6, 3, 5, 1, 1)) - assert len(self.st.views) == 1 - self.st.assert_same() - self.st.reshape((1, 5, 6, 1, 3, 1, 5, 1)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_zero_mask_1(self): - self.st = CheckingShapeTracker((1, 3, 2)) - self.st.pad(((0,0), (0,3), (0,0))) - self.st.shrink(((0,1), (3,6), (0,2))) - self.st.reshape((3,2)) - assert len(self.st.views) == 1 - self.st.assert_same() - self.st.reshape((1, 3, 1, 2, 1)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_zero_mask_2(self): - self.st = CheckingShapeTracker((1, 3, 2)) - self.st.pad(((0,2), (0,3), (0,0))) - self.st.shrink(((2,3), (3,6), (0,2))) - self.st.reshape((3,2)) - assert len(self.st.views) == 1 - self.st.assert_same() - self.st.reshape((1, 3, 1, 2, 1)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_expanded_reshaped(self): - self.st = CheckingShapeTracker((1, 3, 2, 1)) - self.st.expand((5, 3, 2, 2)) - self.st.pad(((0,0), (0,3), (0,0), (0, 0))) - self.st.reshape((5, 2, 3, 2, 2)) - assert len(self.st.views) == 1 - self.st.assert_same() - - def test_splitting_big(self): - self.st = CheckingShapeTracker((1, 5, 1, 15, 1)) - self.st.pad(((0,0), (0,5), (0,0), (0,15), (0,0))) - self.st.reshape((10, 1, 30)) - self.st.permute((2,1,0)) - self.st.reshape((2,3,5,2,5)) - assert len(self.st.views) == 1 - v = self.st.views[-1] - assert v.strides == (0, 5, 1, 0, 15) and v.mask == ((0, 1), (0, 3), (0, 5), (0, 1), (0, 5)) - self.st.assert_same() - - def test_combining_big(self): - self.st = CheckingShapeTracker((1,3,1,5,3,1)) - self.st.pad(((0,0),(2,2),(0,0),(0,0),(0,0),(0,0))) - self.st.reshape((1,1,1,105,1,1)) - assert len(self.st.views) == 1 - v = self.st.views[-1] - assert v.strides == (0, 0, 0, 1, 0, 0) and v.mask == ((0, 1), (0, 1), (0, 1), (30, 75), (0, 1), (0, 1)) and v.offset == -30 - self.st.assert_same() - - def test_pad_reshape(self): - self.st = CheckingShapeTracker((4,)) - self.st.pad(((2,2),)) - self.st.reshape((4,2)) - assert len(self.st.views) == 1 - self.st.assert_same() - -class TestSimplifyingShapeTracker(unittest.TestCase): - def setUp(self): - self.st = CheckingShapeTracker((1, 10)) - - def tearDown(self): - self.st.assert_same() - - # multiview simplify - def test_expand_contract_simple(self): - self.st = self.st.expand((10, 10)) - self.st = self.st.reshape((100,)) - print(self.st.views) - assert (len(self.st.views) == 2) - self.st = self.st.reshape((10, 10)) - print(self.st.views) - - self.st = self.st.simplify() - print(self.st.views) - assert (len(self.st.views) == 1) - - # multiview simplify - def test_expand_contract_different_shape(self): - self.st.expand((10, 10)) - self.st.reshape((100,)) - print(self.st.views) - assert (len(self.st.views) == 2) - self.st.reshape((2, 5, 2, 5)) - print(self.st.views) - - self.st = self.st.simplify() - print(self.st.views) - assert (len(self.st.views) == 1) - - # multiview simplify - def test_expand_contract_still_complex(self): - self.st.expand((10, 10)) - self.st.reshape((100,)) - print(self.st.views) - assert (len(self.st.views) == 2) - self.st.reshape((5, 20)) - - self.st = self.st.simplify() - print(self.st.views) - assert (len(self.st.views) == 2) - -# Tensor.zeros(2, 4).permute(1,0).reshape(2, 4) -# (d1*4 + d0%4), d1=x//4, d0=x%4 = ((x//4)*4) + (x%4)%4 - -class TestComplexShapeTracker(unittest.TestCase): - def test_add_1s(self): - self.st = CheckingShapeTracker((4, 4)) - self.st.permute((1,0)) - self.st.reshape((1,4,1,4,1)) - assert not self.st.contiguous - self.st.permute((0,3,2,1,4)) - assert self.st.contiguous - - def test_permute_1s_simple(self): - self.st = CheckingShapeTracker((1, 16, 9,9)) - self.st.permute((1,0,2,3)) - assert self.st.contiguous - self.st = CheckingShapeTracker((2, 16, 9,9)) - self.st.permute((1,0,2,3)) - assert not self.st.contiguous - - def test_remove_1s_simple(self): - self.st = CheckingShapeTracker((1, 16, 1, 1)) - self.st.reshape((16,)) - assert self.st.contiguous - - def test_remove_1s(self): - self.st = CheckingShapeTracker((1, 4, 1, 4, 1)) - self.st.permute((0,3,2,1,4)) - self.st.reshape((4,4)) - assert not self.st.contiguous - self.st.permute((1,0)) - assert self.st.contiguous - - def test_permute_reshape(self): - self.st = CheckingShapeTracker((4, 4)) - self.st.permute((1,0)) - self.st.reshape((2, 2, 2, 2)) - # TODO: should also be tested by test_super_complex - assert len(self.st.views) == 1 - - def test_factorize_split(self): - self.st = CheckingShapeTracker((4, 4)) - self.st.permute((1,0)) - self.st.reshape((2, 2, 2, 2)) - self.st.permute((2,3,0,1)) - assert self.st.contiguous - - def test_factorize_combine(self): - self.st = CheckingShapeTracker((4, 4, 4)) - self.st.permute((2, 0, 1)) - self.st.reshape((4, 16)) - self.st.permute((1, 0)) - assert self.st.contiguous - - def test_factorize_combine_add_ones(self): - self.st = CheckingShapeTracker((4, 4, 4)) - self.st.permute((2, 0, 1)) - self.st.reshape((4, 16, 1, 1)) - self.st.permute((1, 0, 2, 3)) - assert self.st.contiguous - - def test_fancy_factorize(self): - self.st = CheckingShapeTracker((32, 3, 3, 1)) - self.st.reshape((8, 4, 3, 3)) - assert len(self.st.views) == 1 - - def test_super_complex_2_fail(self): - self.st = CheckingShapeTracker((4, 4, 4)) - self.st.permute((2, 0, 1)) - self.st.reshape((16, 4)) - assert len(self.st.views) != 1 - - def test_work(self): - self.st = CheckingShapeTracker((64, 1024, 4)) - self.st.reshape((1, 64, 128, 32)) - self.st.permute((0, 3, 1, 2)) - self.st.reshape((1, 32, 1, 64, 128)) - self.st.permute((0, 3, 4, 1, 2)) - assert self.st.contiguous - - def test_work2(self): - self.st = CheckingShapeTracker((64, 1024, 4)) - self.st.reshape((1, 64, 128, 32)) - self.st.permute((0, 3, 1, 2)) - self.st.reshape((1, 1, 32, 64, 128)) - self.st.permute((0, 3, 4, 1, 2)) - self.st.reshape((64, 1024, 4)) - print(self.st.views) - assert self.st.contiguous - -class TestShapeTrackerEquality(unittest.TestCase): - def test_simple_equals(self): - self.assertEqual(ShapeTracker.from_shape((10,10)), ShapeTracker.from_shape((10,10))) - def test_other_equals(self): - st1 = ShapeTracker(views=(View(shape=(3,), strides=(1,), offset=0, mask=None, contiguous=True))) - st2 = ShapeTracker(views=(View(shape=(3,), strides=(1,), offset=0, mask=None, contiguous=True))) - self.assertEqual(st1, st2) - -class TestSingleShapeTracker(unittest.TestCase): - def setUp(self): - self.st = CheckingShapeTracker((7,4)) - - def tearDown(self): - self.st.assert_same() - - def test_reshape(self): - self.st.reshape((7,1,4)) - assert self.st.contiguous - - def test_permute(self): - self.st.permute((1,0)) - assert not self.st.contiguous - - def test_shrink(self): - self.st.shrink(((1,2), (0,4))) - assert not self.st.contiguous - - def test_double_permute(self): - self.st.permute((1,0)) - self.st.permute((1,0)) - assert self.st.contiguous - - def test_reshape_permute(self): - self.st.reshape((7,1,4)) - self.st.permute((0,1,2)) - assert self.st.contiguous - - def test_reshape_permute_yes(self): - self.st.reshape((7,1,4)) - self.st.permute((0,2,1)) - assert self.st.contiguous - - def test_reshape_permute_no(self): - self.st.reshape((4,7)) - self.st.permute((1,0)) - assert not self.st.contiguous - -class TestShapeTrackerFuzzFailures(unittest.TestCase): - def setUp(self): - self.st = CheckingShapeTracker((3,3,3)) - def tearDown(self): - self.st.assert_same() - def test_case_1(self): - self.st.shrink(((1, 2), (1, 3), (1, 3))) - self.st.reshape((1, 4)) - self.st.shrink(((0, 1), (1, 3))) - self.st = self.st.simplify() - def test_case_2(self): - self.st.flip( (True, False, True) ) - self.st.reshape( (3, 9) ) - self.st.shrink( ((1, 2), (1, 5)) ) - self.st.flip( (True, True) ) - def test_case_3(self): - self.st.shrink( ((0, 2), (0, 2), (0, 1)) ) - self.st.permute( (1, 0, 2) ) - self.st.reshape( (4,) ) - self.st.shrink( ((0, 3),) ) - self.st.flip( (True, False) ) - def test_case_4(self): - self.st.reshape( (3, 3, 3, 1) ) - self.st.pad( ((0, 0), (0, 0), (0, 0), (1, 1)) ) - self.st.shrink( ((0, 2), (1, 2), (0, 2), (0, 1)) ) - self.st.expand( (2, 1, 2, 3) ) - -class TestMaskedShapeTracker(unittest.TestCase): - def test_pad_1x1(self): - self.st = CheckingShapeTracker((1,1)) - self.st.pad(((1,1), (1,1))) - self.st.assert_same() - - def test_pad_2x2(self): - self.st = CheckingShapeTracker((2,2)) - self.st.pad(((1,1), (1,1))) - self.st.assert_same() - - def test_pad_reshape(self): - st1 = CheckingShapeTracker((1, 2)) - st1.pad(((1, 0), (0, 1))) - st1.reshape((3, 2)) - st1.assert_same() - - st2 = CheckingShapeTracker((1, 2)) - st2.pad(((1, 1), (0, 2))) - st2.reshape((4, 3)) - st2.assert_same() - - st3 = CheckingShapeTracker((1, 1, 1, 2)) - st3.pad(((0, 2), (1, 2), (2, 2), (0, 4))) - st3.reshape((4, 3, 6, 5)) - st3.assert_same() - -class TestShapeTracker(unittest.TestCase): - def setUp(self): - self.st = CheckingShapeTracker((7,4)) - self.apply = lambda fxn: [fxn(x) for x in [self.st]] - - def tearDown(self): - self.st.assert_same() - - def test_noop(self): - pass - - def test_simple_split(self): - self.test_permute() - self.apply(lambda x: x.reshape((prod(self.st.shape), ))) - - def test_simple_pad(self): - self.st.pad(((1,1), (1,1))) - - def test_pad_shrink(self): - self.st.pad(((1,1), (1,1))) - self.st.shrink(((0,4), (0,4))) - - def test_pad_one_sided(self): - self.st.pad(((0,1), (0,0))) - - def test_pad_reshape(self): - self.st.pad(((0,1), (0,0))) - self.st.reshape((8*4,)) - - def test_pad_pad(self): - self.st.pad(((1,1), (1,1))) - self.st.pad(((1,1), (1,1))) - - def test_pad_permute(self): - self.st.pad(((1,1), (2,2))) - self.st.permute((1,0)) - - def test_pad_expand(self): - self.st.reshape((7,4,1)) - self.st.pad(((1,1), (1,1), (0,0))) - self.st.expand((9,6,4)) - - def test_pad_expand_alt(self): - self.st.pad(((1,1), (1,1))) - self.st.reshape((9,6,1)) - self.st.expand((9,6,4)) - - def test_pad_flip(self): - self.st.pad(((1,4), (1,3))) - self.st.flip((True, False)) - - def test_pad_flip_int(self): - self.st.pad(((1,4), (1,3))) - self.st.flip((0, 1)) - - def test_reshape(self): - new_shape = self.st.shape[::-1] - self.apply(lambda x: x.reshape(new_shape)) - - def test_permute(self): - if len(self.st.shape) == 2: self.apply(lambda x: x.permute((1,0))) - elif len(self.st.shape) == 3: self.apply(lambda x: x.permute((2,0,1))) - - def test_reshape_with_1(self): - new_shape = (self.st.shape[0], 1, self.st.shape[1]) - self.apply(lambda x: x.reshape(new_shape)) - - def test_expand(self): - self.test_reshape_with_1() - new_shape = list(self.st.shape) - new_shape[1] = 2 - self.apply(lambda x: x.expand(tuple(new_shape))) - - def test_flip_0(self): - self.apply(lambda x: x.flip((True, False))) - - def test_flip_1(self): - self.apply(lambda x: x.flip((False, True))) - - def test_flip_01(self): - self.apply(lambda x: x.flip((True, True))) - - def test_slice_0(self): - self.apply(lambda x: x.shrink(((1, x.shape[0]), (0, x.shape[1])))) - - def test_slice_1(self): - self.apply(lambda x: x.shrink(((0, x.shape[0]), (1, x.shape[1])))) - - def test_slice_1c1(self): - self.apply(lambda x: x.shrink(((0, 1), (0, 1)))) - - def test_slice_1c2(self): - self.apply(lambda x: x.shrink(((1, 2), (1, 2)))) - - def test_double_permute(self): - self.apply(lambda x: x.permute((1, 0))) - self.apply(lambda x: x.permute((1, 0))) - - def test_slice_permute(self): - self.apply(lambda x: x.shrink(((0, 2), (2, 4)))) - self.apply(lambda x: x.permute((1, 0))) - - def test_slice_expand(self): - self.apply(lambda x: x.shrink(((0, 2), (3, 4)))) - self.apply(lambda x: x.expand((2, 10))) - - def test_double_flip(self): - self.apply(lambda x: x.flip((True, False))) - self.apply(lambda x: x.flip((True, False))) - - def test_flip(self): self.apply(lambda x: x.flip((True, False))) - def test_flip2(self): self.apply(lambda x: x.flip((False, True))) - def test_flip3(self): self.apply(lambda x: x.flip((True, True))) - - def test_reshape_then_permute(self): - self.test_reshape() - self.test_permute() - - def test_reshape_then_expand(self): - self.test_reshape() - self.test_expand() - - def test_permute_then_reshape(self): - self.test_permute() - self.test_reshape() - - def test_expand_then_reshape(self): - self.test_expand() - self.test_reshape() - - def test_combo(self): - self.test_permute() - self.test_reshape() - self.test_slice_1() - self.test_expand() - self.test_permute() - -class TestShapeTrackerSize(unittest.TestCase): - def test_simple_size(self): - st = ShapeTracker.from_shape((100, 100)) - self.assertEqual(st.real_size(), 100*100) - - def test_0_in_shape_size(self): - st = ShapeTracker.from_shape((0, 100)) - self.assertEqual(st.real_size(), 0) - st = ShapeTracker.from_shape((100, 0)) - self.assertEqual(st.real_size(), 0) - - def test_expand_size(self): - st = ShapeTracker.from_shape((100, 100)) - st = st.reshape((100, 100, 1)) - st = st.expand((100, 100, 100)) - self.assertEqual(st.real_size(), 100*100) - - def test_expand_size_flatten(self): - st = ShapeTracker.from_shape((100, 100)) - st = st.reshape((100, 100, 1)) - st = st.expand((100, 100, 100)) - st = st.reshape((100*100*100,)) - self.assertEqual(st.real_size(), 100*100) - - def test_shrink_size_axis_0(self): - st = ShapeTracker.from_shape((100, 100)) - st = st.shrink(((0, 50), (0, 100))) - self.assertEqual(st.real_size(), 50*100) - - def test_shrink_size_axis_0_variable(self): - st = ShapeTracker.from_shape((100, 100)) - st = st.shrink(((0, Variable("a", 0, 50)), (0, 100))) - self.assertEqual(st.real_size(), 50*100) - - def test_shrink_size_axis_1(self): - st = ShapeTracker.from_shape((100, 100)) - st = st.shrink(((0, 100), (0, 50))) - self.assertEqual(st.real_size(), 9950) # careful here - - def test_size_variable(self): - st = ShapeTracker(views=(View(shape=(1, 1, 1, (Variable('start_pos', 0, 8192)+1), 1, 8, 4, 128), strides=(0, 0, 0, 1024, 0, 128, 0, 1), - offset=0, mask=None, contiguous=False), View(shape=(1, 32, 1, (Variable('start_pos', 0, 8192)+1), 128), - strides=(0, 128, 0, 4096, 1), offset=0, mask=None, contiguous=False))) - self.assertEqual(st.real_size(), 8389632) - - def test_pad_size_simple(self): - st = ShapeTracker.from_shape((10,)).pad(((2,4),)) - self.assertEqual(st.real_size(), 10) - - def test_pad_size_multiview(self): - st = ShapeTracker.from_shape((10,10)).pad(((2,4), (3,1))).reshape((16*14,)) - self.assertEqual(st.real_size(), 100) - - def test_flip_size(self): - st = ShapeTracker.from_shape((10,10)).pad(((2,4), (3,1))).flip((True, True)) - self.assertEqual(st.real_size(), 100) - -class TestVariableShrink(unittest.TestCase): - def test_shrink(self): - st = ShapeTracker.from_shape((10,)) - st = st.shrink(((0, Variable("i", 1, 10)),)) - assert len(st.views) == 1 - - def test_shrink_bound(self): - st = ShapeTracker.from_shape((10,)) - st = st.shrink(((0, Variable("i", 1, 10).bind(3)),)) - assert len(st.views) == 1 - -class TestVariableMerge(unittest.TestCase): - def test_add_reshape(self): - vi = Variable("i", 1, 10) - st1 = ShapeTracker.from_shape((vi,)) - st2 = ShapeTracker.from_shape((1, vi,)) - st = st1+st2 - assert len(st.views) == 1 - - def test_add_stride_0(self): - st1 = ShapeTracker.from_shape((3,), (0,)) - st2 = ShapeTracker.from_shape((Variable("i", 1, 10).bind(3),), (0,)) - st = st1+st2 - assert len(st.views) == 1, f"multiview {st}" - - def test_add_reshape_bound(self): - vi = Variable("i", 1, 10).bind(3) - st1 = ShapeTracker.from_shape((vi,)) - st2 = ShapeTracker.from_shape((1, vi,)) - st = st1+st2 - assert len(st.views) == 1 - - def test_simplify(self): - vi = Variable("i", 1, 10).bind(3) - st1 = ShapeTracker.from_shape((vi,)) - st2 = ShapeTracker.from_shape((1, vi,)) - st = ShapeTracker((st1.views[0], st2.views[0])) - st = st.simplify() - assert len(st.views) == 1 - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_shapetracker_math.py b/test/unit/test_shapetracker_math.py deleted file mode 100644 index 3a74ae30b1..0000000000 --- a/test/unit/test_shapetracker_math.py +++ /dev/null @@ -1,164 +0,0 @@ -import unittest -from tinygrad.helpers import prod -from tinygrad.shape.view import View -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad import Variable -from test.unit.test_shapetracker import shapetracker_getitem - -class MultiShapeTracker: - def __init__(self, sts:list[ShapeTracker]): self.sts = sts - @property - def shape(self): return self.sts[0].shape - def reshape(self, arg): self.sts = [x.reshape(arg) for x in self.sts] - def permute(self, arg): self.sts = [x.permute(arg) for x in self.sts] - def expand(self, arg): self.sts = [x.expand(arg) for x in self.sts] - def shrink(self, arg): self.sts = [x.shrink(arg) for x in self.sts] - def flip(self, arg): self.sts = [x.flip(arg) for x in self.sts] - def pad(self, arg): self.sts = [x.pad(arg) for x in self.sts] - -def st_equal(st1:ShapeTracker, st2:ShapeTracker) -> bool: - if st1.shape != st2.shape: return False - if st1 == st2: return True - for i in range(0, prod(st1.shape)): - st1_off, st1_v = shapetracker_getitem(st1, i) - st2_off, st2_v = shapetracker_getitem(st2, i) - if st1_v != st2_v or (st1_off != st2_off and st1_v): - print(f"ST MISMATCH @ {i}, {st1_v=} != {st2_v=}, {st1_off=} != {st2_off=}") - print(st1) - print(st2) - return False - return True - -class TestShapeTrackerBasics(unittest.TestCase): - def test_pad_shrink_removes_mask(self): - a = ShapeTracker.from_shape((10, 10)) - a = a.pad(((0,2), (0,2))) - a = a.shrink(((0,10), (0,10))) - assert len(a.views) == 1 and a.views[-1].mask is None - - def test_pad_shrink_leaves_mask(self): - a = ShapeTracker.from_shape((10, 10)) - a = a.pad(((0,2), (0,2))) - a = a.shrink(((0,10), (0,11))) - assert len(a.views) == 1 and a.views[-1].mask is not None - - def test_reshape_makes_same(self): - a = ShapeTracker.from_shape((2, 5)) - x = a.pad( ((2, 0), (0, 0)) ) - x = x.reshape( (2, 2, 5) ) - x1 = x.reshape( (4, 5) ) - x1 = x1.reshape( (2, 2, 5) ) - assert x == x1.simplify() - - def test_simplify_is_correct(self): - multiv = ShapeTracker(views=(View(shape=(15, 3), strides=(9, 1), offset=6, mask=None, contiguous=False), - View(shape=(4, 3), strides=(12, 4), offset=0, mask=None, contiguous=False))) - assert st_equal(multiv, multiv.simplify()) - -class TestShapeTrackerAdd(unittest.TestCase): - def test_simple_add_reshape(self): - a = ShapeTracker.from_shape((10, 10)) - a = a.reshape((100,)) - b = ShapeTracker.from_shape((100,)) - assert a+b == b - - def test_simple_add_permute(self): - a = ShapeTracker.from_shape((10, 10)) - a = a.permute((1,0)) - b = ShapeTracker.from_shape((10, 10)) - b = b.permute((1,0)) - assert a+b == ShapeTracker.from_shape((10, 10)) - - def test_plus_real1(self): - st = MultiShapeTracker([ShapeTracker.from_shape((15, 9))]) - st.shrink( ((0, 15), (6, 9)) ) - backup = st.sts[0] - st.sts.append(ShapeTracker.from_shape(backup.shape)) - st.reshape( (45,) ) - st.flip( (True,) ) - st.reshape( (15, 3) ) - assert st_equal(backup + st.sts[1], st.sts[0]) - - def test_off_by_one(self): - st1 = ShapeTracker(views=(View(shape=(5,), strides=(1,), offset=0, mask=None, contiguous=True), - View(shape=(5,), strides=(1,), offset=0, mask=None, contiguous=True))) - st2 = ShapeTracker(views=(View(shape=(4,), strides=(1,), offset=0, mask=None, contiguous=True), - View(shape=(5,), strides=(1,), offset=0, mask=None, contiguous=True))) - assert not (st_equal(st1, st2)) - -class TestShapeTrackerAddVariable(unittest.TestCase): - def test_merge_symbolic_views(self): - var_i = Variable('i', 1, 10) - var_j = Variable('i', 1, 10) - vm1 = View(shape=(var_i, var_j, 3), strides=(3, 0, 1), offset=0, mask=None, contiguous=False) - vm2 = View(shape=(var_i, var_j, 3), strides=(var_j*3, 3, 1), offset=0, mask=None, contiguous=True) - ShapeTracker((vm1,)) + ShapeTracker((vm2,)) - - def test_merge_symbolic_views_2(self): - var_i = Variable('i', 1, 10) - var_j = Variable('j', 1, 10) - vm1 = View(shape=(var_i, var_j), strides=(0, 0), offset=0, mask=None, contiguous=False) - vm2 = View(shape=(var_i, var_j), strides=(var_j, 1), offset=0, mask=None, contiguous=True) - ret = (ShapeTracker((vm1,)) + ShapeTracker((vm2,))).reshape((var_i, var_j, 1)) - ret_2 = ShapeTracker((vm1,)) + ShapeTracker((vm2,)).reshape((var_i, var_j, 1)) - assert ret == ret_2 - -class TestShapeTrackerInvert(unittest.TestCase): - def test_invert_reshape(self): - a = ShapeTracker.from_shape((10, 10)) - x = a.reshape((5, 20)) - ap = ShapeTracker.from_shape(x.shape) + x.invert(a.shape) - assert ap == a, f"{ap} != {a}" - - def test_invert_permute(self): - a = ShapeTracker.from_shape((5, 20)) - x = a.permute((1,0)) - ap = x + x.invert(a.shape) - assert ap == a, f"{ap} != {a}" - - def test_invert_permute_3(self): - a = ShapeTracker.from_shape((8, 4, 5)) - x = a.permute((1,2,0)) - ap = x + x.invert(a.shape) - assert ap == a, f"{ap} != {a}" - - def test_invert_real1(self): - a = ShapeTracker.from_shape((3, 6, 10)) - x = a.reshape( (3, 3, 2, 10) ) - x = x.permute( (2, 1, 3, 0) ) - ap = x + x.invert(a.shape) - assert ap == a, f"{ap} != {a}" - - def test_cant_invert_expand(self): - a = ShapeTracker.from_shape((10, 1)) - x = a.expand((10,10)) - assert x.invert(a.shape) is None - - def test_cant_invert_shrink(self): - a = ShapeTracker.from_shape((10, 10)) - x = a.shrink(((0,10),(2,8))) - assert x.invert(a.shape) is None - - def test_can_invert_flip(self): - a = ShapeTracker.from_shape((20, 10)) - x = a.flip((True,False)) - ap = x + x.invert(a.shape) - assert st_equal(ap, a) - - def test_can_invert_flip_permute(self): - a = ShapeTracker.from_shape((20, 10)) - x = a.permute((1,0)) - x = x.flip((True,False)) - ap = x + x.invert(a.shape) - assert st_equal(ap, a) - - def test_invert_failure(self): - a = ShapeTracker.from_shape((2, 5)) - x = a.pad( ((2, 0), (0, 0)) ) - x = x.reshape( (2, 2, 5) ) - x = x.reshape( (4, 5) ) - ap = x + x.invert(a.shape) - assert st_equal(ap, a) - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_shm_tensor.py b/test/unit/test_shm_tensor.py index 0c953a7767..93b26c7568 100644 --- a/test/unit/test_shm_tensor.py +++ b/test/unit/test_shm_tensor.py @@ -1,11 +1,11 @@ import unittest import multiprocessing.shared_memory as shared_memory -from tinygrad.helpers import CI, WIN, RANGEIFY +from tinygrad.helpers import CI, WIN from tinygrad.tensor import Tensor, Device import numpy as np class TestRawShmBuffer(unittest.TestCase): - @unittest.skipIf(WIN and CI and RANGEIFY, "only fails with RANGEIFY on CI windows instance") + @unittest.skipIf(WIN and CI, "only fails on CI windows instance") def test_e2e(self): t = Tensor.randn(2, 2, 2).realize() diff --git a/test/unit/test_simplify_valid_idx.py b/test/unit/test_simplify_valid_idx.py index 7a27cc83ca..c4c64cd669 100644 --- a/test/unit/test_simplify_valid_idx.py +++ b/test/unit/test_simplify_valid_idx.py @@ -5,16 +5,17 @@ from tinygrad.dtype import dtypes from tinygrad.uop.ops import UOp, Ops from tinygrad.uop.symbolic import simplify_valid from tinygrad.helpers import Context +from test.unit.test_uop_symbolic import check_uop_against_string def get_gated_load_uop(valid:UOp, idx:UOp): return UOp(Ops.LOAD, dtypes.float, ( - UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), arg=0).index(idx.valid(valid)), + UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), arg=0).index(idx.valid(valid), ptr=True), UOp.const(dtypes.float, 0.0) )) def get_load_image_uop(image_shape:tuple[int, ...], valid:UOp, idx:tuple[UOp, UOp]): return UOp(Ops.LOAD, dtypes.float.vec(4), ( - UOp(Ops.DEFINE_GLOBAL, dtypes.imagef(image_shape), arg=0).index(UOp(Ops.VECTORIZE, dtypes.index.vec(2), idx).valid(valid)), + UOp(Ops.DEFINE_GLOBAL, dtypes.imagef(image_shape), arg=0).index(UOp(Ops.VECTORIZE, dtypes.index.vec(2), idx).valid(valid), ptr=True), UOp(Ops.VECTORIZE, dtypes.float.vec(4), src=(UOp.const(dtypes.float, 0.0),) * 4) )) @@ -40,17 +41,17 @@ class TestHelpers(unittest.TestCase): self.assertTrue(f2.is_increasing()) self.assertTrue(f3.is_increasing()) - rng = UOp(Ops.RANGE, dtypes.int, arg=(2, True), src=(UOp(Ops.CONST, dtypes.int, arg=5, src=()),)) + rng = UOp.range(5, 2) self.assertTrue(rng.is_increasing()) self.assertTrue((rng+2).is_increasing()) class TestValidIdxSimplification(unittest.TestCase): def check(self, load, sidx, svalid): - with Context(NOOPT=1): + with Context(NOOPT=1, SPEC=0): load = full_rewrite_to_sink(load.sink()).src[0] idx, valid = load.src[0].src[1], load.src[0].src[2] - self.assertEqual(idx.render(simplify=False), sidx) - self.assertEqual(valid.render(simplify=False), svalid) + check_uop_against_string(self, idx, sidx) + check_uop_against_string(self, valid, svalid) def test_cumsum(self): gidx0 = Special("gidx0", 5) @@ -60,7 +61,7 @@ class TestValidIdxSimplification(unittest.TestCase): load = get_gated_load_uop(gate, idx) self.check(load, "0", - "((((gidx0*4)+lidx0)<19)!=True)") + "(((lidx0+(gidx0*4))<19)!=True)") def test_simplify_within_valid1(self): ridx0 = Range(0, 4) @@ -104,7 +105,9 @@ class TestValidIdxSimplification(unittest.TestCase): def test_simplify_valid_from_div(self): x = Variable("x", -100, 100) valid = ((x<0)&((100%x).cast(dtypes.bool))) - self.assertIsNone(simplify_valid(valid)) + # NOTE: this simplifies the (100%x) part somehow, still has two clauses + self.assertIsNotNone(simplify_valid(valid)) + self.assertEqual(len(list(valid.split_uop(Ops.AND))), 2) @unittest.expectedFailure # TODO: fix def test_from_merge_views(self): @@ -189,7 +192,8 @@ class TestValidIdxSimplification(unittest.TestCase): ridx1 = Range(1, 4) ridx2 = Range(2, 4) ridx3 = Range(3, 4) - idx= ((ridx0+ridx1+ridx2+ridx3+28)//30) + # TODO: this should also work without the extra nesting + idx = (((ridx0+ridx1)+(ridx2+ridx3)+28)//30) valid = ((ridx0+ridx1)<1).ne(True) & ((ridx2+ridx3)<1).ne(True) load = get_gated_load_uop(valid, idx) self.check(load, @@ -209,16 +213,16 @@ class TestValidIdxSimplification(unittest.TestCase): class TestImageSimplification(unittest.TestCase): def check(self, load, svalid, sidx0, sidx1): - with Context(NOOPT=1): + with Context(NOOPT=1, SPEC=0): load = full_rewrite_to_sink(load.sink()).src[0] idx = load.src[0].src[1] self.assertEqual(idx.op, Ops.VECTORIZE) self.assertEqual(len(idx.src), 2) idx0, idx1 = idx.src[0], idx.src[1] - self.assertEqual(idx0.render(simplify=False), sidx0) - self.assertEqual(idx1.render(simplify=False), sidx1) + check_uop_against_string(self, idx0, sidx0) + check_uop_against_string(self, idx1, sidx1) if svalid is not None: - self.assertEqual(load.src[0].src[2].render(simplify=False), svalid) + check_uop_against_string(self, load.src[0].src[2], svalid) else: self.assertEqual(len(load.src[0].src), 2, "svalid is None but load still has a valid") @@ -279,7 +283,8 @@ class TestImageSimplification(unittest.TestCase): # empty -> invalid load = get_load_image_uop(shape, (gidx0<8) & (gidx0<8).ne(True), idx) - load = full_rewrite_to_sink(load.sink()).src[0] + with Context(NOOPT=1, SPEC=0): + load = full_rewrite_to_sink(load.sink()).src[0] self.assertEqual(load.op, Ops.VECTORIZE) self.assertEqual(load.dtype.count, 4) @@ -303,7 +308,7 @@ class TestImageSimplification(unittest.TestCase): idx = ((alu4+1530)%1536, alu1+((idx1+((ridx2+7)//8)+31)//32)+(-2)) load = get_load_image_uop(shape, valid, idx) - self.check(load, None, "((((idx1*48)+r0)+(r2*6))+-6)", "(((idx2*2)+r1)+-1)") + self.check(load, None, "((((idx1*48)+(r2*6))+r0)+-6)", "(((idx2*2)+r1)+-1)") def test_openpilot_conv2(self): # conv in test/external/external_test_valid_remove.py @@ -324,7 +329,7 @@ class TestImageSimplification(unittest.TestCase): idx = ((alu3+765)%768, alu1+((idx1+((ridx2+7)//8)+31)//32)+(-2)) load = get_load_image_uop(shape, valid, idx) - self.check(load, None, "((((idx1*24)+r0)+(r2*3))+-3)", "(((idx2*2)+r1)+-1)") + self.check(load, None, "((((idx1*24)+(r2*3))+r0)+-3)", "(((idx2*2)+r1)+-1)") def test_openpilot_conv3(self): # in openpilot 0.9.7 @@ -346,8 +351,8 @@ class TestImageSimplification(unittest.TestCase): self.check(load, "((((idx2*2)+r0)<11)&((((idx1*8)+r1)<3)!=True))", - "(((idx0+(idx1*512))+(r1*64))+-192)", - "((((idx2*2)+(((idx1+((r1+5)//8))+1)//2))+r0)+-4)") + "(((idx0+((idx1*512)+(r1*64)))+832)%1024)", + "((((idx2*2)+r0)+(((idx1+((r1+5)//8))+1)//2))+-4)") def test_simplify1(self): # idx has the form (A % m, A // m + k) and valid has (c0 < A) and (A < c1) @@ -385,16 +390,16 @@ class TestImageSimplification(unittest.TestCase): # TODO: can this be simplified further? load = get_load_image_uop(shape, alu9, (((alu8+(alu2*8))%64),(alu2//8))) - self.check(load, "(idx0<256)", "((((idx0//32)+((idx0%8)*32))+8)%64)", "((idx0%8)//2)") + self.check(load, "(idx0<256)", "(((((idx0%8)*32)+(idx0//32))+8)%64)", "((idx0%8)//2)") load = get_load_image_uop(shape, alu9, (((alu8+(alu3*8))%64),(alu3//8))) - self.check(load, "(idx0<256)", "((((idx0//32)+((idx0%8)*32))+16)%64)", "((idx0%8)//2)") + self.check(load, "(idx0<256)", "(((((idx0%8)*32)+(idx0//32))+16)%64)", "((idx0%8)//2)") load = get_load_image_uop(shape, alu9, (((alu8+(alu4*8))%64),(alu4//8))) - self.check(load, "(idx0<256)", "((((idx0//32)+((idx0%8)*32))+24)%64)", "((idx0%8)//2)") + self.check(load, "(idx0<256)", "(((((idx0%8)*32)+(idx0//32))+24)%64)", "((idx0%8)//2)") load = get_load_image_uop(shape, alu9, (((alu8+(alu5*8))%64),(alu5//8))) - self.check(load, "(idx0<256)", "(((idx0//32)+((idx0%8)*32))%64)", "((idx0%8)//2)") + self.check(load, "(idx0<256)", "((((idx0%8)*32)+(idx0//32))%64)", "((idx0%8)//2)") def test_simplify5(self): # openpilot 0.9.7, chunk replacement to simplify diff --git a/test/unit/test_symbolic_shapetracker.py b/test/unit/test_symbolic_shapetracker.py index c89419a2f9..8d876c2a9f 100644 --- a/test/unit/test_symbolic_shapetracker.py +++ b/test/unit/test_symbolic_shapetracker.py @@ -1,5 +1,4 @@ import unittest -from tinygrad.shape.shapetracker import ShapeTracker, View from tinygrad import Variable from tinygrad.tensor import Tensor @@ -7,117 +6,33 @@ class TestSymbolic(unittest.TestCase): def assert_tuple_equal(self, x, y): for a,b in zip(x,y): self.assertFalse(a != b) - def test_symbolic_st(self): - x = Variable("x", 1, 100) - st = ShapeTracker.from_shape((x, 3)) - assert st.shape == (x, 3) - assert st.real_strides() == (3, 1) - - def test_real_strides_0(self): - st = ShapeTracker(views=(View(shape=(2, (Variable('start_pos', 1, 8)+1), 1, 1), strides=(8, 1, 0, 0), offset=0, mask=((0, 2), (0, Variable('start_pos', 1, 8)), (0, 1), (0, 1)), contiguous=False), View(shape=(2, (Variable('start_pos', 1, 8)+1)), strides=((Variable('start_pos', 1, 8)+1), 1), offset=0, mask=None, contiguous=True))) # noqa: E501 - self.assertEqual(st.real_strides(), (8, None)) - - @unittest.expectedFailure - def test_real_strides_1(self): - st = ShapeTracker(views=(View(shape=(3, (Variable('i', 1, 10)+2)), strides=(Variable('i', 1, 10), 1), offset=0, mask=((0, 3), (0, Variable('i', 1, 10))), contiguous=False),)) # noqa: E501 - self.assertEqual(st.real_strides(), (Variable('i', 1, 10), None)) - - @unittest.expectedFailure - def test_real_strides_2(self): - st = ShapeTracker(views=(View(shape=(3, (Variable('i', 1, 10)+Variable('j', 1, 10))), strides=(Variable('i', 1, 10), 1), offset=0, mask=((0, 3), (0, Variable('i', 1, 10))), contiguous=False),)) # noqa: E501 - self.assertEqual(st.real_strides(), (Variable('i', 1, 10), None)) - - def test_merge_view_recursion_err(self): - vm2 = View(shape=(Variable('j', 1, 10),), strides=(0,), offset=0, mask=None, contiguous=False) - vm1 = View(shape=(1,), strides=(0,), offset=0, mask=None, contiguous=True) - self.assertEqual(vm2+vm1, vm1) - - def test_merge_view_recursion_err2(self): - vm2 = View(shape=(Variable('a', 1, 10).bind(4),), strides=(0,), offset=0, mask=None, contiguous=False) - # NOTE: vm1 is different from what create function would give, and this test vm2+vm1 halts - vm1 = View(shape=(Variable('a', 1, 10).bind(4),), strides=(1,), offset=0, mask=((0, Variable('a', 1, 10).bind(4)),), contiguous=False) - self.assertEqual(vm2+vm1, None) - - vm3 = View.create(shape=(Variable('a', 1, 10).bind(4),)) - self.assertEqual(vm3.shape, vm1.shape) - self.assertEqual(vm3.strides, vm1.strides) - self.assertEqual(vm2+vm3, vm2) - - def test_cat_dim0_strides(self): + def test_cat_dim0_is_expanded(self): i = Variable("i", 1, 5).bind(3) j = Variable("j", 1, 5).bind(3) k = Variable("k", 1, 5).bind(3) t = Tensor.rand(5, 4)[:i].cat(Tensor.rand(5, 4)[:j], dim=0).cat(Tensor.rand(5, 4)[:k], dim=0) - st = t.uop.st - self.assert_tuple_equal(st.shape, (i+j+k, 4)) - assert st.real_strides() == (4, 1) + self.assert_tuple_equal(t.shape, (i+j+k, 4)) t = Tensor.rand(5, 3)[:i].cat(Tensor.rand(5, 3)[:i], dim=0).cat(Tensor.rand(3, 3), dim=0) - st = t.uop.st - self.assert_tuple_equal(st.shape, (2*i+3, 3)) - assert st.real_strides() == (3, 1) + self.assert_tuple_equal(t.shape, (2*i+3, 3)) def test_cat_dim1_strides(self): i = Variable("i", 1, 5).bind(4) j = Variable("j", 1, 5).bind(4) k = Variable("k", 1, 5).bind(4) t = Tensor.rand(3, 5)[:, :i].cat(Tensor.rand(3, 5)[:, :j], dim=1).cat(Tensor.rand(3, 5)[:, :k], dim=1) - st = t.uop.st - self.assert_tuple_equal(st.shape, (3, i+j+k)) - self.assert_tuple_equal(st.real_strides(), (i+j+k, 1)) + self.assert_tuple_equal(t.shape, (3, i+j+k)) class TestSymbolicVarVals(unittest.TestCase): def assert_equal(self, x, y): self.assertFalse(x != y) - def test_var_vals_empty(self): - assert ShapeTracker.from_shape((3, 4, 5)).var_vals == {} - - def test_var_vals_shape(self): - x = Variable("x", 1, 100).bind(3) - assert ShapeTracker.from_shape((x, 3)).var_vals == {"x": 3} - - def test_var_vals_offset(self): - x = Variable("x", 1, 100).bind(3) - st = ShapeTracker.from_shape((4, 3)).shrink(((x, x+1), (0, 3))) - self.assert_equal(st.views[-1].offset, x * 3) - assert st.var_vals == {"x": 3} - - def test_var_vals_mask(self): - x = Variable("x", 1, 100).bind(3) - view = View.create(shape=(3,4), strides=(4,1), offset=0, mask=((0, x), (0, 4))) - st = ShapeTracker(views=(view,)) - assert st.var_vals == {"x": 3} - - def test_var_vals_complex(self): - x = Variable("x", 1, 100).bind(3) - y = Variable("y", 1, 100).bind(4) - z = Variable("z", 1, 100).bind(5) - st = ShapeTracker.from_shape((x, 5, y)).shrink(((0, x), (z, z+1), (0, 3))) - self.assert_equal(st.views[-1].offset, y * z) - assert st.var_vals == {"x": 3, "y": 4, "z": 5} - - def test_shrink_reshape(self): - x = Variable("x", 1, 100).bind(3) - st = ShapeTracker.from_shape((10, 10, 10)).shrink(((x, x+3), (3, 7), (2, 5))) - st = st.reshape((3*4*3,)) - assert st.var_vals == {"x": 3} - -class TestShapeTrackerUnbind(unittest.TestCase): - def test_view_unbind(self): - v = Variable("v", 1, 100) - bv = Variable("v", 1, 100).bind(3) - unbound_view, var_val = View.create(shape=(bv, 4)).unbind() - assert unbound_view == View.create(shape=(v, 4)) - assert var_val == {v: 3} def test_shrink_unbind(self): v = Variable("v", 1, 100) bv = Variable("v", 1, 100).bind(2) t = Tensor.rand(3, 4).shrink(((0,bv),(0,4))) - unbound_st, var_val = t.uop.st.unbind() - assert unbound_st == ShapeTracker((View.create(shape=(v, 4)),)) + unbound_st, var_val = t.uop.unbind_all() assert var_val == {v: 2} t = Tensor.rand(3, 4).shrink(((bv, bv+1), (0, 4))) - unbound_st, var_val = t.uop.st.unbind() - assert unbound_st == ShapeTracker((View.create(shape=(1, 4), offset=4*v),)) + unbound_st, var_val = t.uop.unbind_all() assert var_val == {v: 2} class TestSymbolicReshape(unittest.TestCase): @@ -147,17 +62,6 @@ class TestSymbolicReshape(unittest.TestCase): ret = ret.reshape(1, vi*vj) assert ret.shape == (1, vi*vj) - def test_symbolic_mask(self): - # taken from gpt2 single kvcache - # these two caused problems in gpt2 if reshape merged views - view = View(shape=(1, (Variable('start_pos', 1, 128).bind(2)+1), 16, 64), strides=(0, 0, 64, 1), offset=1024, mask=((0, 1), (Variable('start_pos', 1, 128).bind(2), (Variable('start_pos', 1, 128).bind(2)+1)), (0, 16), (0, 64)), contiguous=False) # noqa: E501 - new_shape = (1, 1, (Variable('start_pos', 1, 128).bind(2)+1), 16, 64) - assert view.reshape(new_shape) is None - - view = View(shape=(2, 1, (Variable('start_pos', 1, 128)+1), 16, 64), strides=(0, 0, 1024, 64, 1), offset=131072, mask=((1, 2), (0, 1), (0, (Variable('start_pos', 1, 128)+1)), (0, 16), (0, 64)), contiguous=False) # noqa: E501 - new_shape = (2, (Variable('start_pos', 1, 128)+1), 16, 64) - assert view.reshape(new_shape) is None - class TestSymbolicExpand(unittest.TestCase): def test_expand_into_symbols(self): vi = Variable("i", 1, 5).bind(3) @@ -200,6 +104,5 @@ class TestSymbolicPad(unittest.TestCase): t = t[:9] assert t.tolist() == [0,0,0,0,1,1,1,1,1] - if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_tensor_uop_representation.py b/test/unit/test_tensor_uop_representation.py index f93ae2437f..e3b173d639 100644 --- a/test/unit/test_tensor_uop_representation.py +++ b/test/unit/test_tensor_uop_representation.py @@ -4,9 +4,6 @@ from tinygrad.uop.ops import UPat, Ops, UOp # NOTE: unlike before base for a realized tensor is always a BUFFER realized_pattern = UPat(Ops.BUFFER) -# after realization, base tensor uops become RESHAPE(BUFFER) -buffer_view_pattern = UPat(Ops.RESHAPE, src=(UPat(Ops.BUFFER),)) -const_pattern = UPat(Ops.CONST, src=(UPat(Ops.VIEW, src=(UPat(Ops.DEVICE),),))) def is_pattern_uop(u:UOp, pat:UPat): assert pat.match(u, {}), f"{u}\nis not\n{pat}" def is_pattern(ten:Tensor, pat:UPat): is_pattern_uop(ten.uop, pat) @@ -58,13 +55,5 @@ class TestTensorUopRepresentation(unittest.TestCase): is_pattern(c, UPat(Ops.ADD)) for s in c.uop.src: is_pattern_uop(s.base, realized_pattern) - def test_empty_buf(self): - a = Tensor.empty(3, 3) - is_pattern(a, UPat(Ops.RESHAPE, src=(UPat(Ops.BUFFER),))) - vi = UOp.variable("i", 1, 3).bind(1) - a = Tensor.empty(3, vi) - is_pattern(a, UPat(Ops.RESHAPE, src=(UPat(Ops.SHRINK, src=(UPat(Ops.BUFFER),))),)) - self.assertEqual(a.uop.base.buffer.size, 9) - if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_tinyfs.py b/test/unit/test_tinyfs.py new file mode 100644 index 0000000000..9fe4fed13f --- /dev/null +++ b/test/unit/test_tinyfs.py @@ -0,0 +1,22 @@ +import unittest +from tinygrad import Tensor + +class TestLoadStore(unittest.TestCase): + def test_load_shape(self): + t = Tensor(bytes(16)).load(1024).kernelize() + assert t.shape == (1024,), t.shape + + def test_store_shape(self): + t = Tensor.zeros(1024).store().kernelize() + assert t.shape == (16,), t.shape + + def test_load_large_shape(self): + t = Tensor(bytes(16)).load(10_000_000).kernelize() + assert t.shape == (10_000_000,), t.shape + + def test_store_large_shape(self): + t = Tensor.zeros(10_000_000).store().kernelize() + assert t.shape == (16,), t.shape + +if __name__ == "__main__": + unittest.main() diff --git a/test/unit/test_transcendental_helpers.py b/test/unit/test_transcendental_helpers.py index 4c697903a1..6f3b9a324c 100644 --- a/test/unit/test_transcendental_helpers.py +++ b/test/unit/test_transcendental_helpers.py @@ -11,7 +11,7 @@ class TestTranscendentalFunctions(unittest.TestCase): # TODO: Test constant input when constant folding is fixed (or maybe test both variants) # Load input value from a buffer to prevent constant folding input_buf = UOp(Ops.DEFINE_GLOBAL, dtypes.double.ptr(), arg=1, src=()) - loaded_value = UOp.load(input_buf.index(UOp.const(dtypes.int, 0)), dtype=dtypes.double) + loaded_value = input_buf.index(UOp.const(dtypes.int, 0)) def eval_payne_hanek_reduction(v:float) -> tuple[float, int]: return tuple(eval_uop(u, [(dtypes.float64, [v])]) for u in payne_hanek_reduction(loaded_value)) diff --git a/test/unit/test_uop_spec.py b/test/unit/test_uop_spec.py deleted file mode 100644 index 97f6d9040f..0000000000 --- a/test/unit/test_uop_spec.py +++ /dev/null @@ -1,97 +0,0 @@ -from __future__ import annotations -import unittest - -from tinygrad import Tensor -from tinygrad.helpers import DEBUG, RANGEIFY -from tinygrad.uop.ops import UOp, Ops, print_uops -from tinygrad.uop.spec import type_verify, ast_spec, tensor_uop_spec -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad import dtypes -from tinygrad.shape.view import View -from tinygrad.engine.realize import get_program -from tinygrad.device import Device - -class InvalidASTException(Exception): pass -def helper_test_verify_ast(*stores:UOp): - sink = UOp(Ops.SINK, dtypes.void, stores) - if DEBUG >= 3: - for op in stores: print(op) - try: type_verify(list(sink.toposort()), ast_spec) - except RuntimeError as e: raise InvalidASTException(e.args) - program = get_program(sink, Device[Device.DEFAULT].renderer) - - if DEBUG >= 6: print_uops(program.uops) - if DEBUG >= 4: print(program.src) - -class TestUOpSpec(unittest.TestCase): - def test_tiny_add(self): - dtype = dtypes.int - buf_0 = UOp(Ops.DEFINE_GLOBAL, dtype.ptr(), (), 0) - buf_1 = UOp(Ops.DEFINE_GLOBAL, dtype.ptr(), (), 1) - buf_2 = UOp(Ops.DEFINE_GLOBAL, dtype.ptr(), (), 2) - a = UOp(Ops.LOAD, dtype, (buf_1.view(ShapeTracker.from_shape((32, 1))),)) - b = UOp(Ops.LOAD, dtype, (buf_2.view(ShapeTracker.from_shape((32, 1))),)) - store = UOp(Ops.STORE, dtypes.void, (buf_0.view(ShapeTracker.from_shape((32, 1))), a+b)) - helper_test_verify_ast(store) - - def test_no_implicit_broadcasting(self): - bufs = [UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), i) for i in range(2)] - a = UOp(Ops.LOAD, dtypes.float, (bufs[1].view(ShapeTracker.from_shape((4, 32))),)) - b = a + UOp(Ops.REDUCE_AXIS, dtypes.float, (a,), (Ops.MAX, (1,))) - st = UOp(Ops.STORE, dtypes.void, (bufs[0].view(ShapeTracker.from_shape((4, 32))), b)) - with self.assertRaises(InvalidASTException): helper_test_verify_ast(st) - - def test_shrink_ok(self): - bufs = [UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), i) for i in range(2)] - a = UOp(Ops.LOAD, dtypes.float, (bufs[1].view(ShapeTracker((View((32, 32), strides=(32, 1), offset=0, mask=None, contiguous=True),))),)) - b = UOp(Ops.LOAD, dtypes.float, (bufs[1].view(ShapeTracker((View((32, 32), strides=(0, 1), offset=0, mask=None, contiguous=False),))),)) - st = UOp.store(bufs[0].view(ShapeTracker.from_shape((32, 32))), a+b) - helper_test_verify_ast(st) - - def test_reduce_store(self): - bufs = [UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), i) for i in range(2)] - a = UOp(Ops.LOAD, dtypes.float, (bufs[1].view(ShapeTracker.from_shape((32, 1))),)) - r = UOp(Ops.REDUCE_AXIS, dtypes.float, (a,), (Ops.ADD, (0,))) - st = UOp.store(bufs[0].view(ShapeTracker.from_shape((32, 1))), r) - with self.assertRaises(InvalidASTException): helper_test_verify_ast(st) - - def test_reduce_add_store(self): - bufs = [UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), i) for i in range(2)] - a = UOp(Ops.LOAD, dtypes.float, (bufs[1].view(ShapeTracker.from_shape((32, 1))),)) - r = UOp(Ops.REDUCE_AXIS, dtypes.float, (a,), (Ops.ADD, (0,))) - st = UOp.store(bufs[0].view(ShapeTracker.from_shape((32, 1))), r+a) - with self.assertRaises(InvalidASTException): helper_test_verify_ast(st) - - def test_assert_swizzle(self): - buf = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) - a = UOp(Ops.LOAD, dtypes.float, (buf.view(ShapeTracker.from_shape((32, 1))),)) - r = UOp(Ops.REDUCE_AXIS, dtypes.float, (a,), (Ops.ADD, (0,))) - st = UOp.store(buf.view(ShapeTracker.from_shape((32, 1))), r.view(r.st.expand((32, 1)))+a) - with self.assertRaisesRegex(InvalidASTException, "UOp verification failed"): helper_test_verify_ast(st) - - def test_const_view_always_valid(self): - buf = UOp(Ops.DEFINE_GLOBAL, dtypes.float.ptr(), (), 0) - a = UOp.const(dtypes.int, 0).replace(src=(UOp(Ops.VIEW, dtypes.void, (), ShapeTracker.from_shape(())),)) - st = UOp.store(buf.view(ShapeTracker.from_shape(())), a.cast(dtypes.float)) - helper_test_verify_ast(st) - - @unittest.skipIf(RANGEIFY, "RANGEIFY does not push views") - def test_assert_masked_view_in_const(self): - t = Tensor(6).uop - a = t.replace(src=(t.src[0].replace(arg=t.st.reshape((1,)).pad(((0, 1),))),)) - with self.assertRaisesRegex(RuntimeError, "UOp verification failed"): - type_verify([a], tensor_uop_spec) - -class TestUOpSink(unittest.TestCase): - def test_0(self): - s = UOp.sink() - self.assertEqual(len(s.src), 0) - - def test_1(self): - a = UOp.const(dtypes.int, 0) - s1 = UOp.sink(a) - s2 = a.sink() - self.assertIs(s1, s2) - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_uop_symbolic.py b/test/unit/test_uop_symbolic.py index b961efee60..b958b62a45 100644 --- a/test/unit/test_uop_symbolic.py +++ b/test/unit/test_uop_symbolic.py @@ -5,14 +5,17 @@ import z3 from tinygrad.dtype import dtypes, ConstType, DType, Invalid from tinygrad.codegen import full_rewrite from tinygrad.helpers import Context -from tinygrad.uop.ops import UOp, Ops, graph_rewrite, sym_infer, track_rewrites -from tinygrad.uop.symbolic import sym -from tinygrad.uop.spec import uops_to_z3 +from tinygrad.uop.ops import UOp, Ops, graph_rewrite, sym_infer +from tinygrad.uop.symbolic import sym, commutative +from tinygrad.uop.validate import uops_to_z3 -@track_rewrites(name="simplify symbolic uop") -def render(v) -> UOp: - v_simplified = graph_rewrite(v, sym) - return v_simplified +def check_uop_against_string(self, v:UOp, s:str): + sym_vars = {v.render():v for v in v.toposort() if v.op in (Ops.DEFINE_VAR, Ops.RANGE, Ops.SPECIAL)} + s_eval = eval(s, sym_vars) + if isinstance(s_eval, int) and v.dtype==dtypes.index: s_eval = UOp.const(dtypes.index, s_eval) + elif isinstance(s_eval, (bool, int, float)): s_eval = UOp.const(dtypes.from_py(s_eval), s_eval) + s_eval = graph_rewrite(s_eval, commutative, name="cannonicalize eval") + self.assertIs(s_eval, v, f"eval did not match simplified: {s_eval} != {v} for {s}") def Variable(name: str, min_val: ConstType, max_val: ConstType, dtype: DType=dtypes.index): return UOp.variable(name,min_val,max_val,dtype) def uconst(val): return UOp.const(dtypes.index, val) @@ -33,11 +36,11 @@ class TestSymbolic(unittest.TestCase): self.assertEqual(solver.check(expr1 != expr2), z3.unsat, "simplified expression not equal to original") def helper_test_variable(self, v, n, m, s, test_z3:bool=True): - v_simplified = render(v) + v_simplified = graph_rewrite(v, sym, name="simplify symbolic uop") if test_z3: self.check_equal_z3(v, v_simplified) - rendered, nmin, nmax = v_simplified.render(simplify=False), v_simplified.vmin, v_simplified.vmax - if isinstance(s, tuple): self.assertIn(rendered, s) - else: self.assertEqual(rendered, s) + nmin, nmax = v_simplified.vmin, v_simplified.vmax + check_uop_against_string(self, v_simplified, s) + # eval the test string and see if we get the same uop self.assertEqual(nmin, n) self.assertEqual(nmax, m) @@ -76,7 +79,7 @@ class TestSymbolic(unittest.TestCase): def test_lt_factors(self): expr = (Variable("idx1", 0, 511)*4 + Variable("FLOAT4_INDEX", 0, 256)) < 512 - self.helper_test_variable(expr, 0, 1, ("(((idx1*4)+FLOAT4_INDEX)<512)", "((FLOAT4_INDEX+(idx1*4))<512)")) + self.helper_test_variable(expr, 0, 1, "(((idx1*4)+FLOAT4_INDEX)<512)") def test_div_reduction(self): self.helper_test_variable(Variable("a", 2, 3)//2, 1, 1, "1") @@ -116,39 +119,6 @@ class TestSymbolic(unittest.TestCase): self.assertEqual((a*b*3+a*b*b).divide_exact(a*b).simplify(), b+3) self.assertEqual((((a*-2)+14)*b).divide_exact(((a*-2)+14)).simplify(), b) - def helper_test_factor(self, expr, *factors): - factored = expr.factor(*factors) - self.check_equal_z3(expr, factored) - for fac in factors: self.assertIn(fac, factored.toposort()) - - def test_uop_factor(self): - a = Variable("a", 0, 8) - b = Variable("b", 0, 8) - c = Variable("c", 0, 8) - self.helper_test_factor((1400*a+2800*b), (a+2*b)) - self.helper_test_factor((1400*a+2800*b)%9000, (a+2*b)) - self.helper_test_factor((a+2*b), (a+2*b)) - self.helper_test_factor((a+c+2*b), (a+2*b)) - self.helper_test_factor((1400*a+c+2800*b)%9000, (a+2*b)) - self.helper_test_factor((1399*a+c+2800*b)%9000+1400*a+2800*b, (a+2*b)) - self.helper_test_factor((1400*a+c+2800*b)%9000+1400*a+2800*b, (a+2*b)) - # self.assertIsNone((a+c+3*b).factor(a+2*b)) - # self.assertIsNone((1399*a+c+2800*b).factor(a+2*b)) - - def test_uop_multiple_factors(self): - a = Variable("a", 0, 8) - b = Variable("b", 0, 8) - c = Variable("c", 0, 8) - d = Variable("d", 0, 8) - self.helper_test_factor((1400*a+2800*b+2*c+d), (a+2*b), (2*c+d)) - self.helper_test_factor((100*a+200*b+5*c), (a+2*b), (5*c)) - self.helper_test_factor((3*a+6*b+2*c+4*d), (a+2*b), (c+2*d)) - self.helper_test_factor((7*a+14*b+3*c+6*d), (a+2*b), (3*c+6*d)) - self.helper_test_factor((10*a+20*b+10*c+30*d), (a+2*b), (c+3*d)) - self.helper_test_factor((10*c+(10*a+20*b)//3+30*d), (a+2*b), (c+3*d)) - self.helper_test_factor((10*c+(10*a+20*b)//3+30*d), (a+2*b), (c+3*d)) - # self.assertIsNone((7*a+14*b+3*c+6*d).factor((a+8*b), (2*c+6*d))) - def test_divide_exact_not(self): a = Variable("a", 1, 8) b = Variable("b", 1, 8) @@ -163,13 +133,13 @@ class TestSymbolic(unittest.TestCase): a = Variable("a", 0, 8) b = Variable("b", 0, 8) self.helper_test_variable(a*2+a*3, 0, 8*5, "(a*5)") - self.helper_test_variable(b+a*2+a*3, 0, 8*6, "((a*5)+b)") + self.helper_test_variable(b+a*2+a*3, 0, 8*6, "(b+(a*5))") def test_factorize_no_mul(self): a = Variable("a", 0, 8) b = Variable("b", 0, 8) self.helper_test_variable(a+a*3, 0, 8*4, "(a*4)") - self.helper_test_variable((a+b)+a*3, 0, 8*5, "((a*4)+b)") + self.helper_test_variable((a+b)+a*3, 0, 8*5, "(b+(a*4))") self.helper_test_variable((a*3+b)+b*3, 0, 8*7, "((a*3)+(b*4))") def test_neg(self): @@ -192,15 +162,8 @@ class TestSymbolic(unittest.TestCase): b = Variable("b", 0, 8) self.helper_test_variable(a+a, 0, 16, "(a*2)") self.helper_test_variable((a+b)+b, 0, 24, "(a+(b*2))") - self.helper_test_variable((a*3+b)+a, 0, 40, "((a*4)+b)") - self.helper_test_variable((a+b)+a*3, 0, 40, "((a*4)+b)") - - def test_add_self_seperated(self): - a = Variable("a", 0, 8) - b = Variable("b", 0, 8) - c = Variable("c", 0, 8) - self.helper_test_variable((a+b)+c+a, 0, 32, "(((a*2)+b)+c)") - self.helper_test_variable((a*3+b*2)+c*2+a*5, 0, 96, "(((a*8)+(b*2))+(c*2))") + self.helper_test_variable((a*3+b)+a, 0, 40, "(b+(a*4))") + self.helper_test_variable((a+b)+a*3, 0, 40, "(b+(a*4))") def test_sub_self(self): a = Variable("a", 0, 8) @@ -227,7 +190,7 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable(Variable("a", 0, 8)%1, 0, 0, "0") def test_max_folds(self): - self.helper_test_variable(Variable("a", 0, 20).maximum(10).maximum(11), 11, 20, "max(a, 11)") + self.helper_test_variable(Variable("a", 0, 20).maximum(10).maximum(11), 11, 20, "a.maximum(11)") def test_add_min_max(self): self.helper_test_variable(Variable("a", 0, 8) * 2 + 12, 12, 16+12, "((a*2)+12)") @@ -256,7 +219,7 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable(usum([Variable("a", 0, 7)*4, Variable("b", 0, 3)*4]) % 2, 0, 0, "0") def test_sum_div_some_factor(self): - self.helper_test_variable(usum([Variable("a", 0, 7)*5, Variable("b", 0, 3)*4]) // 2, 0, 23, ("(((a*5)//2)+(b*2))", "((b*2)+((a*5)//2))")) + self.helper_test_variable(usum([Variable("a", 0, 7)*5, Variable("b", 0, 3)*4]) // 2, 0, 23, "(((a*5)//2)+(b*2))") def test_sum_div_trim_const(self): self.helper_test_variable((Variable("a", 0, 7)*4 + Variable("b", 0, 3)*4 + 7) // 16, 0, 2, "(((a+b)+1)//4)") @@ -319,7 +282,7 @@ class TestSymbolic(unittest.TestCase): def test_mod_congruence_multiple_vars(self): self.helper_test_variable((9+9*Variable("x",0,3)+9*Variable("y",0,3))%10, 3, 9, "(((x*-1)+(y*-1))+9)") self.helper_test_variable((7+9*Variable("x",0,2)+9*Variable("y",0,2)+Variable("z",0,2))%10, 3, 9, - ("(((z+(x*-1))+(y*-1))+7)", "(((y*-1)+(z+(x*-1)))+7)", "((((x*-1)+(y*-1))+z)+7)")) + "(((z+(x*-1))+(y*-1))+7)") self.helper_test_variable((10+12*Variable("x",0,2)+Variable("y", 0, 4)%3)%13, 8, 12, "(((x*-1)+(y%3))+10)") def test_div_congruence(self): @@ -341,8 +304,7 @@ class TestSymbolic(unittest.TestCase): def test_sum_lt_fold(self): self.helper_test_variable(usum([Variable("a", 0, 7) * 4, Variable("b", 0, 3)]) < 16, 0, 1, "(a<4)") - self.helper_test_variable(usum([Variable("a", 0, 7) * 4, Variable("b", 0, 4)]) < 16, 0, 1, - ("(((a*4)+b)<16)", "((b+(a*4))<16)")) + self.helper_test_variable(usum([Variable("a", 0, 7) * 4, Variable("b", 0, 4)]) < 16, 0, 1, "(((a*4)+b)<16)") self.helper_test_variable(usum([Variable("uidx", 0, 3), Variable("a", 0, 1529) * 12]) < (4 * 67), 0, 1, "(a<23)") def test_mul_mod_large(self): @@ -404,7 +366,7 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable((1+Variable("a", 0, 3))*(-2)+12, 4, 10, "((a*-2)+10)") def test_mod_mul_sum(self): - self.helper_test_variable(usum([Variable("b", 0, 2), Variable("a", 0, 5)*10])%9, 0, 7, ("(b+a)", "(a+b)")) + self.helper_test_variable(usum([Variable("b", 0, 2), Variable("a", 0, 5)*10])%9, 0, 7, "(b+a)") def test_sum_0(self): self.helper_test_variable(usum([Variable("a", 0, 7)]), 0, 7, "a") @@ -435,11 +397,11 @@ class TestSymbolic(unittest.TestCase): def test_lt_sum_factor_rhs_partial(self): self.helper_test_variable((Variable("a", 0, 6)*6 + Variable("b", 0, 6)*4 + Variable("c", 0, 6)*8) < 4, 0, 1, - ("((((a*3)+(b*2))+(c*4))<2)", "(((b*2)+((a*3)+(c*4)))<2)")) + "((((a*3)+(b*2))+(c*4))<2)") def test_lt_sum_factor_rhs_all(self): self.helper_test_variable((Variable("a", 0, 6)*6 + Variable("b", 0, 6)*4 + Variable("c", 0, 6)*8) < 2, 0, 1, - ("((((a*3)+(b*2))+(c*4))<1)", "(((b*2)+((a*3)+(c*4)))<1)")) + "((((a*3)+(b*2))+(c*4))<1)") def test_and_fold(self): self.helper_test_variable(uand([uconst(0), Variable("a", 0, 1)]), 0, 0, "0") @@ -495,7 +457,7 @@ class TestSymbolic(unittest.TestCase): ridx1005 = UOp.variable("ridx1005", 0, 2) ridx1006 = UOp.variable("ridx1006", 0, 2) self.helper_test_variable((lidx1+((gidx1*18)+(ridx1005*18)+(lidx0*162))+(gidx0*2)+(ridx1006*2)+-40)//18, -2, 20, - "((((((((gidx0*2)+(gidx1*18))+(lidx0*162))+lidx1)+(ridx1005*18))+(ridx1006*2))+-40)//18)") + "(((((lidx1+(((gidx1*18)+(ridx1005*18))+(lidx0*162)))+(gidx0*2))+(ridx1006*2))+-40)//18)") def test_add_div(self): # careful about the lower bounds and upper bounds @@ -538,7 +500,7 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable((d1*a*b*d1)//(d1), -1000, 1000, "(a*(b*d1))", test_z3=False) self.helper_test_variable((d1*a*d2*b*d1)//(d1*d2), -1000, 1000, "(a*(b*d1))", test_z3=False) self.helper_test_variable((d1*a + b*d1)//(d1), -20, 20, "(a+b)", test_z3=False) - self.helper_test_variable((d1*a + b*d1 + c*d1)//(d1), -30, 30, "((a+b)+c)", test_z3=False) + self.helper_test_variable((d1*a + b*d1 + c*d1)//(d1), -30, 30, "(c+(a+b))", test_z3=False) self.helper_test_variable((3*a*d1 + 9*b*d1)//(3*d1*d2), -40, 40, "(((a+(b*3))//(d2*-1))*-1)", test_z3=False) self.helper_test_variable((3*a*d1 + 9*b*d1+3)//(3*d1*d2), -401, 399, "(((((a*d1)+((b*d1)*3))+1)//((d1*d2)*-1))*-1)", test_z3=False) @@ -548,7 +510,7 @@ class TestSymbolic(unittest.TestCase): d = Variable("d", 1, 10) self.helper_test_variable((d*a+b)//d, 0, 20, "(a+(b//d))") self.helper_test_variable((d*a*20+b)//(5*d), 0, 42, "((a*4)+(b//(d*5)))") - self.helper_test_variable((d*a*20+b*d*5+10)//(5*d), 0, 52, "(((a*4)+b)+(2//d))") + self.helper_test_variable((d*a*20+b*d*5+10)//(5*d), 0, 52, "((b+(a*4))+(2//d))") def test_mod_gcd_factor_neg(self): self.helper_test_variable((Variable("a", 0, 10)*-4+4)%8, -4, 4, "((((a*-1)+1)%2)*4)") @@ -601,36 +563,35 @@ class TestSymbolic(unittest.TestCase): lidx2 = Variable("lidx2", 0, 3) alu0 = gidx2*640+gidx1*160+(gidx0//5)*2+lidx0*320+lidx1*10 self.helper_test_variable((alu0+lidx2*2+1)//20, 0, 8192, - ("((((gidx1*8)+(gidx2*32))+(lidx0*16))+((lidx1+((lidx2+(gidx0//5))//5))//2))",)) + "((((((gidx0//5)+lidx2)//5)+lidx1)//2)+(((gidx2*32)+(gidx1*8))+(lidx0*16)))") def test_sum_div_complex2(self): gidx0 = Variable("gidx0", 0, 7) lidx2 = Variable("lidx2", 0, 1) lidx3 = Variable("lidx3", 0, 1) - self.helper_test_variable((gidx0*4+lidx2*2+1)//10, 0, 3, ("(((gidx0*2)+lidx2)//5)", "((lidx2+(gidx0*2))//5)")) - self.helper_test_variable((gidx0*4+lidx2*2+lidx3)//10, 0, 3, ("(((gidx0*2)+lidx2)//5)", "((lidx2+(gidx0*2))//5)")) + self.helper_test_variable((gidx0*4+lidx2*2+1)//10, 0, 3, "(((gidx0*2)+lidx2)//5)") + self.helper_test_variable((gidx0*4+lidx2*2+lidx3)//10, 0, 3, "(((gidx0*2)+lidx2)//5)") self.helper_test_variable((gidx0*2+lidx2)//10, 0, 1, "(gidx0//5)") def test_sum_div_complex3(self): gidx0 = Variable("gidx0", 0, 7) lidx2 = Variable("lidx2", 0, 12) lidx3 = Variable("lidx3", 0, 1) - self.helper_test_variable((gidx0*4+lidx2*2+lidx3)//12, 0, 4, ("(((lidx2//2)+gidx0)//3)", "((gidx0+(lidx2//2))//3)")) - self.helper_test_variable((lidx2*2+gidx0*4+lidx3)//12, 0, 4, ("(((lidx2//2)+gidx0)//3)", "((gidx0+(lidx2//2))//3)")) + self.helper_test_variable((gidx0*4+lidx2*2+lidx3)//12, 0, 4, "(((lidx2//2)+gidx0)//3)") + self.helper_test_variable((lidx2*2+gidx0*4+lidx3)//12, 0, 4, "(((lidx2//2)+gidx0)//3)") @unittest.expectedFailure # TODO: improve nest_div_by_smallest_factor def test_sum_div_complex4(self): gidx0 = Variable("gidx0", 0, 2) lidx2 = Variable("lidx2", 0, 12) lidx3 = Variable("lidx3", 0, 12) - self.helper_test_variable((gidx0*3+lidx2*19+lidx3*38)//(3*19), 0, 12, ("((lidx2+(lidx3*2))//3)")) + self.helper_test_variable((gidx0*3+lidx2*19+lidx3*38)//(3*19), 0, 12, "((lidx2+(lidx3*2))//3)") def test_sum_mul_distribute(self): gidx0 = Variable("gidx0", 0, 7) lidx2 = Variable("lidx2", 0, 12) lidx3 = Variable("lidx3", 0, 1) - self.helper_test_variable((gidx0+lidx2+lidx3)*4, 0, 80, - ("(((gidx0*4)+(lidx2*4))+(lidx3*4))","((lidx3*4)+((gidx0*4)+(lidx2*4)))")) + self.helper_test_variable((gidx0+lidx2+lidx3)*4, 0, 80, "(((gidx0*4)+(lidx2*4))+(lidx3*4))") @unittest.expectedFailure def test_variable_divmod(self): @@ -679,21 +640,12 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable((gidx//4)*4+gidx%4, 0, 124, "gidx") self.helper_test_variable(lidx+gidx%4+(gidx//4)*4, 0, 248, "(gidx+lidx)") self.helper_test_variable(lidx+(gidx//4)*4+gidx%4, 0, 248, "(gidx+lidx)") - self.helper_test_variable(lidx+(gidx//4)*8+2*(gidx%4), 0, 372, "((gidx*2)+lidx)") - self.helper_test_variable(lidx+2*(gidx%4)+(gidx//4)*8, 0, 372, "((gidx*2)+lidx)") + self.helper_test_variable(lidx+(gidx//4)*8+2*(gidx%4), 0, 372, "(lidx+(gidx*2))") + self.helper_test_variable(lidx+2*(gidx%4)+(gidx//4)*8, 0, 372, "(lidx+(gidx*2))") - def test_div_mod_recombine_seperated(self): - gidx = Variable("gidx", 0, 124) - lidx = Variable("lidx", 0, 124) - a = Variable("a", 0, 3) - b = Variable("b", 0, 3) - c = Variable("c", 0, 3) - self.helper_test_variable(gidx%4+a+b+c+(gidx//4)*4, 0, 133, "(((a+b)+c)+gidx)") - self.helper_test_variable((gidx//4)*4+a+b*10+gidx%4, 0, 157, "((a+(b*10))+gidx)") - self.helper_test_variable(lidx+gidx%4+a+b+c//2+(gidx//4)*4, 0, 255, "((((a+b)+gidx)+lidx)+(c//2))") - self.helper_test_variable(lidx+(gidx//4)*8+b+c+a*8+2*(gidx%4), 0, 402, "(((((a*8)+b)+c)+(gidx*2))+lidx)") - # TODO: need better sorting for this one - # self.helper_test_variable(lidx+(gidx//4)*4+a*3+b*3+(c*10)%3+gidx%4, , , "") + def test_div_mod_recombine_partial(self): + gidx = Variable("gidx", 0, 15) + self.helper_test_variable((gidx//2)%4+(gidx//8)*4, 0, 7, "gidx//2") def test_div_mod_recombine_folded_mod(self): a = Variable("a", 0, 2) @@ -713,7 +665,7 @@ class TestSymbolic(unittest.TestCase): idx = Variable("idx", 0, 24) self.helper_test_variable(idx//4, 0, 6, "(idx//4)") # TODO: simplify the true branch - self.helper_test_variable((idx<4).where(idx//4, idx.const_like(-1)), -1, 6, "((idx//4) if (idx<4) else -1)") + self.helper_test_variable((idx<4).where(idx//4, idx.const_like(-1)), -1, 6, "(idx<4).where((idx//4), -1)") def test_idiv_lt(self): idx = Variable("idx", 0, 24) @@ -732,8 +684,8 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable((a*3+b*4<1).ne(True), 0, 1, "(((a+b)<1)!=True)") self.helper_test_variable((a*(-3)+b*4<1).ne(True), 0, 1, "((((a*-3)+(b*4))<1)!=True)") # negative coeff, should not be simplified self.helper_test_variable((a*3+d*4<1).ne(True), 0, 1, "((((a*3)+(d*4))<1)!=True)") # var can be negative, should not be simplified - self.helper_test_variable((a+b+c*2<1).ne(True), 0, 1, ("((((a+b)+c)<1)!=True)", "(((c+(a+b))<1)!=True)", '(((b+(a+c))<1)!=True)')) - self.helper_test_variable((a+b*2+c*4<1).ne(True), 0, 1, ("((((a+b)+c)<1)!=True)", "(((c+(a+b))<1)!=True)", '(((b+(a+c))<1)!=True)')) + self.helper_test_variable((a+b+c*2<1).ne(True), 0, 1, "((((a+b)+c)<1)!=True)") + self.helper_test_variable((a+b*2+c*4<1).ne(True), 0, 1, "((((a+b)+c)<1)!=True)") def test_where_removal(self): cond = Variable("a", 0, 3) < 2 @@ -751,30 +703,30 @@ class TestSymbolic(unittest.TestCase): c = Variable("c", 0, 3) aa = cond.where(a, a.ufix(0)) bb = cond.where(b, b.ufix(1)) - self.helper_test_variable(aa, 0, 3, "(a if (x<2) else 0)") - self.helper_test_variable(bb, 0, 3, "(b if (x<2) else 1)") - self.helper_test_variable(aa+bb, 0, 6, "((a+b) if (x<2) else 1)") - self.helper_test_variable(aa.maximum(bb), 0, 3, "(max(a, b) if (x<2) else 1)") - self.helper_test_variable((c+aa)+bb, 0, 9, "(c+((a+b) if (x<2) else 1))") + self.helper_test_variable(aa, 0, 3, "(x<2).where(a, 0)") + self.helper_test_variable(bb, 0, 3, "(x<2).where(b, 1)") + self.helper_test_variable(aa+bb, 0, 6, "(x<2).where((a+b), 1)") + self.helper_test_variable(aa.maximum(bb), 0, 3, "(x<2).where(a.maximum(b), 1)") + self.helper_test_variable((c+aa)+bb, 0, 9, "(c+(x<2).where((a+b), 1))") # not combining because it increased total ALU cc = cond.where(c, c+1) - self.helper_test_variable(bb+cc, 0, 7, "((b if (x<2) else 1)+(c if (x<2) else (c+1)))") + self.helper_test_variable(bb+cc, 0, 7, "((x<2).where(b, 1)+(x<2).where(c, (c+1)))") # not combining # TODO: can combine if it can further simplify? ab = cond.where(a, b) ba = cond.where(b, a) - self.helper_test_variable(ab+ba, 0, 6, "((a if (x<2) else b)+(b if (x<2) else a))") + self.helper_test_variable(ab+ba, 0, 6, "((x<2).where(a, b)+(x<2).where(b, a))") # not combining # TODO: can combine if one is identity element const - self.helper_test_variable(aa+ab, 0, 6, "((a if (x<2) else b)+(a if (x<2) else 0))") + self.helper_test_variable(aa+ab, 0, 6, "((x<2).where(a, b)+(x<2).where(a, 0))") def test_negation_in_where(self): cond = Variable("x", 0, 3) < 2 a = Variable("a", 0, 3) b = Variable("b", 0, 3) w = cond.logical_not().where(a, b) - self.helper_test_variable(w, 0, 3, "(b if (x<2) else a)") + self.helper_test_variable(w, 0, 3, "(x<2).where(b, a)") def test_neg_in_comp(self): a = Variable("a", 0, 3) @@ -801,7 +753,7 @@ class TestSymbolic(unittest.TestCase): a = Variable("a", 0, 3) b = Variable("b", 0, 3) expr = cond1.where(cond2.where(a, b), b) - self.helper_test_variable(expr, 0, 3, "(a if ((s<6)&(2 (a if (s<5) else b) - self.helper_test_variable(expr, 0, 3, "(a if (s<5) else b)") + self.helper_test_variable(expr, 0, 3, "(s<5).where(a, b)") def test_symbolic_div(self): # from symbolic arange @@ -821,11 +773,15 @@ class TestSymbolic(unittest.TestCase): self.helper_test_variable(numerator, 3, 390, "(a*((a*4)+-1))") self.helper_test_variable((numerator//denominator)<=0, 1, 1, "True") + def test_symbolic_range_doesnt_collapse(self): + r0 = UOp.range((Variable("a", 1, 10)<5).cast(dtypes.index), 0) + self.helper_test_variable(r0, 0, 0, "r0") + def test_const_reciprocal(self): a = Variable("a", 1, 10, dtypes.float) # TODO: bounds for reciprocal # TODO: should z3 work? - self.helper_test_variable(2*(2*a).reciprocal(), -math.inf, math.inf, "(1/a)", test_z3=False) + self.helper_test_variable(2*(2*a).reciprocal(), -math.inf, math.inf, "a.reciprocal()", test_z3=False) def test_trunc_noop(self): a = Variable("a", 1, 10, dtypes.int) @@ -834,8 +790,8 @@ class TestSymbolic(unittest.TestCase): def test_do_math_in_int32(self): a = Variable("a", 1, 10, dtypes.int) b = Variable("b", 1, 10, dtypes.int) - self.helper_test_variable(a.cast(dtypes.long)+b.cast(dtypes.long), 2, 20, "(long)((a+b))") - self.helper_test_variable(a.cast(dtypes.long)*b.cast(dtypes.long), 1, 100, "(long)((a*b))") + self.assertIn((a.cast(dtypes.long)+b.cast(dtypes.long)).render(), "(long)((a+b))") + self.assertIn((a.cast(dtypes.long)*b.cast(dtypes.long)).render(), "(long)((a*b))") class TestSymbolicNumeric(unittest.TestCase): def helper_test_numeric(self, f): @@ -1067,11 +1023,7 @@ class TestSymbolicRealWorld(unittest.TestCase): #print(idx.render()) # NOTE: this used to have 13,151,129,600 in the output which is out of int32 range. self.assertIn(idx.render(), - ("((((((((((lidx5+1)//16)*802816)+(((lidx5+1)%16)*49))+(gidx0*3211264))+(gidx1*784))+(gidx2*8))+(lidx4*100352))+lidx3)+2207744)", - '((lidx3+((((((((lidx5+1)//16)*802816)+(((lidx5+1)%16)*49))+(gidx0*3211264))+(gidx1*784))+(gidx2*8))+(lidx4*100352)))+2207744)', - '((lidx3+((lidx4*100352)+((gidx2*8)+((gidx1*784)+((gidx0*3211264)+((((lidx5+1)//16)*802816)+(((lidx5+1)%16)*49)))))))+2207744)', - '((((((((gidx0*3211264)+(gidx1*784))+(gidx2*8))+lidx3)+(lidx4*100352))+(((lidx5+1)//16)*802816))+(((lidx5+1)%16)*49))+2207744)', - )) + ("(lidx3+((lidx5+1)//16*802816+(lidx5+1)%16*49+gidx0*3211264+gidx1*784+gidx2*8+lidx4*100352)+2207744)",)) class TestBounds(unittest.TestCase): def test_unrolled_arange(self): diff --git a/test/unit/test_uop_vmin_vmax.py b/test/unit/test_uop_vmin_vmax.py index 2d13c94968..2935d971f6 100644 --- a/test/unit/test_uop_vmin_vmax.py +++ b/test/unit/test_uop_vmin_vmax.py @@ -40,15 +40,14 @@ class TestVminVmaxProperties(unittest.TestCase): self.assertEqual(uop.vmin, 0) self.assertEqual(uop.vmax, 5) - # this can be improved uop = x & 15 self.assertEqual(uop.vmin, 0) self.assertEqual(uop.vmax, 15) - # this can be improved + # TODO: this can be improved uop = x & 32 self.assertEqual(uop.vmin, 0) - self.assertEqual(uop.vmax, 20) + self.assertEqual(uop.vmax, 20) # shoud be 0 def test_vmin_vmax_multiplication_with_variable(self): # vmin and vmax for multiplication with a variable diff --git a/test/unit/test_upat_compile.py b/test/unit/test_upat_compile.py index 1f68a8830b..c1366b006b 100644 --- a/test/unit/test_upat_compile.py +++ b/test/unit/test_upat_compile.py @@ -1,5 +1,5 @@ import unittest -from tinygrad.helpers import DEBUG +from tinygrad.helpers import DEBUG, Context from tinygrad.dtype import dtypes from tinygrad.uop.ops import UPat, track_rewrites, GroupOp, Ops from tinygrad.uop.upat import _get_code, upat_compile @@ -14,6 +14,7 @@ def do_compile(up): if DEBUG >= 2: dis.dis(match) return match_code[0] +@Context(SPEC=0) class TestUPatCompile(unittest.TestCase): def test_double(self): up = UPat.var("x") * UPat.cvar("c0") + UPat.var("x") * UPat.cvar("c1") diff --git a/test/unit/test_view.py b/test/unit/test_view.py deleted file mode 100644 index 8929418ab4..0000000000 --- a/test/unit/test_view.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env python -import unittest -from tinygrad.shape.view import View, merge_dims -# from tinygrad.shape.shapetracker import ShapeTracker - -class TestView(unittest.TestCase): - def test_canonicalize_empty_mask(self): - v = View.create(shape=(2,2,2), strides=(4,2,1), mask=((0,2),(0,2),(0,2))) - self.assertIsNone(v.mask) - v = View.create(shape=(4,3,2), strides=(1,4,10), mask=((0,4),(0,3),(0,2))) - self.assertIsNone(v.mask) - - def test_minify_zero_strided_dims(self): - target = View.create(shape=(2,2), strides=(30,2), offset=7, mask=None) - v = View.create(shape=(2,1,2), strides=(30,0,2), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(1,2,2), strides=(0,30,2), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(2,2,1), strides=(30,2,0), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(2,1,1,2), strides=(30,0,0,2), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(1,1,2,2), strides=(0,0,30,2), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(2,2,1,1), strides=(30,2,0,0), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(1,2,2,1), strides=(0,30,2,0), offset=7, mask=None) - self.assertEqual(v.minify(), target) - v = View.create(shape=(1,2,1,2), strides=(0,30,0,2), offset=7, mask=None) - self.assertEqual(v.minify(), target) - - def test_empty_mask_contiguous(self): - v1 = View.create(shape=(2,2,2), strides=(4,2,1), mask=None) - v2 = View.create(shape=(2,2,2), strides=(4,2,1), mask=((0,2),(0,2),(0,2))) - self.assertEqual(v1.contiguous, v2.contiguous) - v1 = View.create(shape=(1,1,1,4), strides=(0,0,0,1), offset=0, mask=None) - v2 = View.create(shape=(1,1,1,4), strides=(0,0,0,1), offset=0, mask=((0,1),(0,1),(0,1),(0,4))) - self.assertEqual(v1.contiguous, v2.contiguous) - v = View.create(shape=(2,3,4), mask=((0,2),(0,3),(0,4))) - self.assertTrue(v.contiguous) - - def test_reshape_all_invalid(self): - v = View.create((4,5), mask=((0,0), (0,0))).reshape((20,)) - self.assertIsNotNone(v) - self.assertEqual(v, View.create((20,), mask=((0,0),))) - - def test_add_0(self): - v1 = View.create((2,3,4)) - v2 = View.create((2,0,4)) - self.assertEqual(v2, v1+v2) - - def test_add_0_masked(self): - v1 = View.create((2,3,4), mask=((0, 0), (0, 0), (0, 0))) - v2 = View.create((2,0,4)) - self.assertEqual(v2, v1+v2) - -class TestMergeDims(unittest.TestCase): - def test_contiguous(self): - shape = (2, 3, 4) - strides = (12, 4, 1) #=strides_for_shape(shape) - m = merge_dims(shape, strides) - self.assertEqual(m, ((24, 1, 24),)) - - def test_0_in_strides(self): - shape = (2, 3, 4) - self.assertEqual(merge_dims(shape, (0, 4, 1)), ((2, 0, 0), (12, 1, 12))) - self.assertEqual(merge_dims(shape, (0, 0, 1)), ((6, 0, 0), (4, 1, 4))) - self.assertEqual(merge_dims(shape, (3, 1, 0)), ((6, 1, 6), (4, 0, 4))) - self.assertEqual(merge_dims(shape, (0, 0, 0)), ((24, 0, 0),)) - - def test_pad(self): - # print(ShapeTracker.from_shape((1, 2)).pad(((1, 0), (0, 1))).views[-1]) - self.assertEqual(merge_dims((2, 3), (0, 1), ((1, 2), (0, 2))), ((6, 1, 3),)) - - # print(f"{ShapeTracker.from_shape((1, 1, 2)).pad(((1, 0), (1, 0), (0, 1))).views[-1]}") - self.assertEqual(merge_dims((2, 2, 3), (0, 0, 1), ((1, 2), (1, 2), (0, 2))), ((12, 1, 3),)) - - # print(f"{ShapeTracker.from_shape((1, 1, 2, 2)).pad(((1, 0), (1, 0), (0, 1), (0, 1))).views[-1]}") - self.assertEqual(merge_dims((2, 2, 3, 3), (0, 0, 2, 1), ((1, 2), (1, 2), (0, 2), (0, 2))), ((12, 2, 3), (3, 1, 3))) - - # print(f"{ShapeTracker.from_shape((2, 1, 2)).pad(((0, 0), (1, 0), (0, 1))).views[-1]}") - self.assertEqual(merge_dims((2, 2, 3), (2, 0, 1), ((0, 2), (1, 2), (0, 2))), ((2, 2, 2), (6, 1, 3))) - - def test_different_1_pad(self): - # print(f"{ShapeTracker.from_shape((2, 2, 1)).pad(((0, 0), (0, 0), (0, 1))).views[-1]}") - self.assertEqual(merge_dims((2, 2, 2), (2, 1, 0), ((0, 2), (0, 2), (0, 1))), ((4, 1, 4), (2, 0, 2))) - - # print(f"{ShapeTracker.from_shape((2, 1, 1)).pad(((0, 0), (0, 1), (0, 1))).views[-1]}") - self.assertEqual(merge_dims((2, 2, 2), (1, 0, 0), ((0, 2), (0, 2), (0, 1))), ((2, 1, 2), (4, 0, 4))) - -class TestMergeViews(unittest.TestCase): - def test_with_mask_0(self): - # from test/test_ops.py::TestOps::test_pad_reflect_mode - v0 = View(shape=(1, 1, 5, 8), strides=(0, 0, 5, 1), offset=-3, mask=((0, 1), (0, 1), (0, 5), (3, 8)), contiguous=False) - v1 = View(shape=(1, 1, 2, 2), strides=(0, 0, 8, 1), offset=3, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(1, 1, 2, 2), strides=(0, 0, 5, 1), offset=0, mask=None, contiguous=False)) - - def test_with_mask_1(self): - # from test/test_ops.py::TestOps::test_pad_reflect_mode - v0 = View(shape=(3, 3, 5, 3), strides=(27, 9, 3, 1), offset=-6, mask=((0, 3), (0, 3), (2, 4), (1, 3)), contiguous=False) - v1 = View(shape=(3, 3, 2, 2), strides=(45, 15, 3, 1), offset=7, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(3, 3, 2, 2), strides=(27, 9, 3, 1), offset=1, mask=None, contiguous=False)) - - def test_with_mask_2(self): - # from test/test_ops.py::TestOps::test_pad_reflect_mode - v0 = View(shape=(3, 3, 5, 3), strides=(27, 9, -3, 1), offset=6, mask=((0, 3), (0, 3), (0, 2), (0, 2)), contiguous=False) - v1 = View(shape=(3, 3, 2, 2), strides=(45, 15, -3, 1), offset=3, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(3, 3, 2, 2), strides=(27, 9, 3, 1), offset=3, mask=None, contiguous=False)) - - def test_with_mask_3(self): - # from test/test_ops.py::TestOps::test_pad_reflect_mode - # has a mask in the final view - v0 = View(shape=(3, 3, 4, 4), strides=(27, 9, 3, 1), offset=-5, mask=((0, 3), (0, 3), (2, 4), (0, 2)), contiguous=False) - v1 = View(shape=(3, 3, 4, 2), strides=(48, 16, 4, 1), offset=0, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(3, 3, 4, 2), strides=(27, 9, 3, 1), offset=-5, mask=((0, 3), (0, 3), (2, 4), (0, 2)), contiguous=False)) - - def test_with_mask_4(self): - # from test/test_ops.py::TestOps::test_pad_reflect_mode - # has a mask in the final view - v0 = View(shape=(3, 3, 5, 3), strides=(27, 9, -3, 1), offset=6, mask=((0, 3), (0, 3), (0, 2), (1, 3)), contiguous=False) - v1 = View(shape=(3, 3, 3, 3), strides=(45, 15, 3, 1), offset=6, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(3, 3, 3, 3), strides=(0, 0, 0, 0), offset=0, mask=((0, 0), (0, 0), (0, 0), (0, 0)), contiguous=False)) - - def test_with_mask_5(self): - # from test/test_ops.py::TestOps::test_pad_reflect_mode - # has a mask in the final view - v0 = View(shape=(1, 1, 6, 5), strides=(0, 0, 5, 1), offset=-5, mask=((0, 1), (0, 1), (1, 6), (0, 5)), contiguous=False) - v1 = View(shape=(1, 1, 6, 3), strides=(0, 0, 5, -1), offset=3, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(1, 1, 6, 3), strides=(0, 0, 5, -1), offset=-2, mask=((0, 1), (0, 1), (1, 6), (0, 3)), contiguous=False)) - - @unittest.expectedFailure # TODO: fix these - def test_merges_from_fuzzer1(self): - v0 = View(shape=(2, 4), strides=(2, 1), offset=-2, mask=((0, 2), (2, 4)), contiguous=False) - v1 = View(shape=(2, 4, 2, 2), strides=(4, 0, -2, -1), offset=3, mask=None, contiguous=False) - target = View(shape=(2, 4, 2, 2), strides=(2, 0, 0, -1), offset=1, mask=((0, 2), (0, 4), (0, 1), (0, 2)), contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, target) - - @unittest.expectedFailure # TODO: fix these - def test_merges_from_fuzzer2(self): - v0 = View(shape=(5, 10, 12), strides=(100, 1, 10), offset=-20, mask=((0, 5), (0, 10), (2, 12)), contiguous=False) - v1 = View(shape=(10, 6, 5, 2, 2), strides=(12, 2, 120, 1, 0), offset=0, mask=None, contiguous=False) - target = View(shape=(10, 6, 5, 2, 2), strides=(1, 20, 100, 10, 0), offset=-20, mask=((0, 10), (1, 6), (0, 5), (0, 2), (0, 2)), contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, target) - - @unittest.expectedFailure # TODO: fix these - def test_merges_from_fuzzer3(self): - v0 = View(shape=(8, 7, 3), strides=(1, 12, -4), offset=6, mask=((2, 6), (0, 7), (0, 3)), contiguous=False) - v1 = View(shape=(4, 2, 6, 2, 1), strides=(42, 21, 3, 1, 0), offset=4, mask=None, contiguous=False) - target = View(shape=(4, 2, 6, 2, 1), strides=(2, 1, 12, -4, 0), offset=14, mask=((1, 3), (0, 2), (0, 6), (0, 2), (0, 1)), contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, target) - - @unittest.expectedFailure # TODO: fix these - def test_merges_from_fuzzer4(self): - v0 = View(shape=(7, 21, 3), strides=(54, 3, 1), offset=-9, mask=((0, 6), (3, 21), (0, 3)), contiguous=False) - v1 = View(shape=(5, 3, 3, 7), strides=(63, 1, 3, 9), offset=63, mask=None, contiguous=False) - target = View(shape=(5, 3, 3, 7), strides=(54, 1, 3, 9), offset=45, mask=((0, 5), (0, 3), (0, 3), (1, 7)), contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, target) - - @unittest.expectedFailure # TODO: fix these - def test_merges_from_fuzzer5(self): - v0 = View(shape=(5, 1, 24), strides=(20, 0, 1), offset=-2, mask=((0, 5), (0, 1), (2, 22)), contiguous=False) - v1 = View(shape=(12, 2, 5, 2, 1), strides=(2, 1, 24, 0, 0), offset=0, mask=None, contiguous=False) - target = View(shape=(12, 2, 5, 2, 1), strides=(2, 1, 20, 0, 0), offset=-2, mask=((1, 11), (0, 2), (0, 5), (0, 2), (0, 1)), contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, target) - - def test_merge_views_variable(self): - from tinygrad import Variable - N = 100 - start_pos = Variable("start_pos", 1, N-1) - v0 = View(shape=(N, 32, 2), strides=(32, 1, 0), offset=0, mask=((0, N), (0, 32), (0, 1)), contiguous=False) - v1 = View(shape=(1, 8, 1, 32), strides=(0, 0, 0, 2), offset=start_pos*64, mask=None, contiguous=False) - target = View(shape=(1, 8, 1, 32), strides=(0,0,0,1), offset=start_pos*32, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, target) - - def test_view_padded_area1(self): - # test_multinomial - v0 = View(shape=(2,), strides=(0,), offset=0, mask=((1, 2),), contiguous=False) - v1 = View(shape=(1,), strides=(0,), offset=0, mask=None, contiguous=True) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(1,), strides=(0,), offset=0, mask=((0, 0),), contiguous=False)) - - def test_view_padded_area2(self): - # test_pad_reflect_mode - v0 = View(shape=(1, 1, 10, 7), strides=(0, 0, 5, 1), offset=-15, mask=((0, 1), (0, 1), (3, 8), (0, 5)), contiguous=False) - v1 = View(shape=(0, 0, 0, 0), strides=(0, 0, 0, 0), offset=0, mask=None, contiguous=True) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(0, 0, 0, 0), strides=(0, 0, 0, 0), offset=0, mask=None, contiguous=True)) - - def test_view_padded_area3(self): - # test_roll - v0 = View(shape=(2, 4), strides=(0, 1), offset=4, mask=((0, 1), (0, 4)), contiguous=False) - v1 = View(shape=(1, 4), strides=(0, 1), offset=4, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(1, 4), strides=(0, 0), offset=0, mask=((0, 0), (0, 0)), contiguous=False)) - - def test_view_padded_area4(self): - # test_std_mean - v0 = View(shape=(2,), strides=(0,), offset=0, mask=((0, 1),), contiguous=False) - v1 = View(shape=(1, 1, 1), strides=(0, 0, 0), offset=1, mask=None, contiguous=False) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(1, 1, 1), strides=(0, 0, 0), offset=0, mask=((0, 0), (0, 0), (0, 0)), contiguous=False)) - - def test_empty_shape_view1(self): - # test_stack_slice - v0 = View(shape=(3, 5), strides=(0, 1), offset=0, mask=((0, 1), (0, 5)), contiguous=False) - v1 = View(shape=(), strides=(), offset=0, mask=None, contiguous=True) - v = v0 + v1 - self.assertIsNotNone(v) - self.assertEqual(v, View(shape=(), strides=(), offset=0, mask=None, contiguous=True)) - - def test_empty_shape_view2(self): - # test_std_mean - v0 = View(shape=(2,), strides=(0,), offset=0, mask=((1, 2),), contiguous=False) - v1 = View(shape=(), strides=(), offset=0, mask=None, contiguous=True) - v = v0 + v1 - # TODO: why is this different? - self.assertIsNone(v) - -if __name__ == '__main__': - unittest.main() diff --git a/test/unit/test_viz.py b/test/unit/test_viz.py index 7ecdbe4172..e51f85b1fa 100644 --- a/test/unit/test_viz.py +++ b/test/unit/test_viz.py @@ -2,8 +2,7 @@ import unittest, decimal, json, struct from dataclasses import dataclass from typing import Generator -from tinygrad.uop.ops import UOp, UPat, Ops, PatternMatcher, TrackedPatternMatcher -from tinygrad.uop.ops import graph_rewrite, track_rewrites, TRACK_MATCH_STATS +from tinygrad.uop.ops import UOp, UPat, Ops, PatternMatcher, TrackedPatternMatcher, graph_rewrite, track_rewrites, TRACK_MATCH_STATS, profile_matches from tinygrad.uop.symbolic import sym from tinygrad.dtype import dtypes from tinygrad.helpers import PROFILE, colored, ansistrip, flatten, TracingKey, ProfileRangeEvent, ProfileEvent, Context, cpu_events, profile_marker @@ -15,21 +14,23 @@ def exec_rewrite(sink:UOp, pm_lst:list[PatternMatcher], names:None|list[str]=Non sink = graph_rewrite(sink, TrackedPatternMatcher(pm.patterns), name=names[i] if names else None) return sink -# real VIZ=1 pickles these tracked values -from tinygrad.uop.ops import tracked_keys, tracked_ctxs, uop_fields, active_rewrites, _name_cnt -traces = [(tracked_keys, tracked_ctxs, uop_fields)] -from tinygrad.viz.serve import get_metadata, uop_to_json, get_details -def get_viz_list(): return get_metadata(traces) +# real VIZ=1 loads the trace from a file, we just keep it in memory for tests +from tinygrad.uop.ops import tracked_keys, tracked_ctxs, uop_fields, active_rewrites, _name_cnt, RewriteTrace +from tinygrad.viz import serve +serve.trace = RewriteTrace(tracked_keys, tracked_ctxs, uop_fields) +from tinygrad.viz.serve import get_rewrites, get_full_rewrite, uop_to_json +def get_viz_list(): return get_rewrites(serve.trace) def get_viz_details(rewrite_idx:int, step:int) -> Generator[dict, None, None]: lst = get_viz_list() assert len(lst) > rewrite_idx, "only loaded {len(lst)} traces, expecting at least {idx}" - return get_details(tracked_ctxs[rewrite_idx][step]) + return get_full_rewrite(tracked_ctxs[rewrite_idx][step]) class BaseTestViz(unittest.TestCase): def setUp(self): # clear the global context for lst in [tracked_keys, tracked_ctxs, active_rewrites, _name_cnt]: lst.clear() Buffer.profile_events.clear() + cpu_events.clear() self.tms = TRACK_MATCH_STATS.value self.profile = PROFILE.value TRACK_MATCH_STATS.value = 2 @@ -116,6 +117,28 @@ class TestViz(BaseTestViz): # NOTE: names from TracingKey do not get deduped self.assertEqual(lst[0]["name"], "custom_name") + def test_profile_matches(self): + @profile_matches + def nested_function(u:UOp): + for i in range(2): graph_rewrite(u, PatternMatcher([]), name=f"step {i+1}") + + @track_rewrites() + def main_rewrite(u:UOp): + graph_rewrite(u, PatternMatcher([]), name="init") + nested_function(u) + + main_rewrite(UOp.variable("a", 1, 10)+UOp.variable("b", 1, 10)) + steps = get_viz_list()[0]["steps"] + self.assertEqual(steps[0]["name"], "init") + self.assertEqual(steps[1]["name"], "nested_function") + self.assertEqual(len(steps), 4) + + def test_profile_matches_invalid_arg(self): + @profile_matches + def invalid_fxn(arg:str): return graph_rewrite(UOp(Ops.SINK), PatternMatcher([])) + with self.assertRaisesRegex(AssertionError, "invalid match tracing input"): + invalid_fxn("test") + def test_colored_label(self): # NOTE: dataclass repr prints literal escape codes instead of unicode chars @dataclass(frozen=True) @@ -125,12 +148,20 @@ class TestViz(BaseTestViz): a2 = uop_to_json(a)[id(a)] self.assertEqual(ansistrip(a2["label"]), f"CUSTOM\n{TestStruct.__qualname__}(colored_field='xyz12345')") + def test_colored_label_multiline(self): + arg = colored("x", "green")+"\n"+colored("y", "red")+colored("z", "yellow")+colored("ww\nw", "magenta") + src = [Tensor.empty(1).uop for _ in range(10)] + a = UOp(Ops.CUSTOM, src=tuple(src), arg=arg) + exec_rewrite(a, [PatternMatcher([])]) + a2 = next(get_viz_details(0, 0))["graph"][id(a)] + self.assertEqual(ansistrip(a2["label"]), "CUSTOM\nx\nyzww\nw") + def test_inf_loop(self): - a = UOp.variable('a', 0, 10) - b = a.replace(op=Ops.CONST) + a = UOp.const(dtypes.int, 3) + b = UOp.const(dtypes.int, 4) pm = PatternMatcher([ - (UPat(Ops.DEFINE_VAR, name="x"), lambda x: x.replace(op=Ops.CONST)), - (UPat(Ops.CONST, name="x"), lambda x: x.replace(op=Ops.DEFINE_VAR)), + (UPat(Ops.CONST, arg=3, name="x"), lambda x: x.replace(arg=4)), + (UPat(Ops.CONST, arg=4, name="x"), lambda x: x.replace(arg=3)), ]) with self.assertRaises(RuntimeError): exec_rewrite(a, [pm]) graphs = flatten(x["graph"].values() for x in get_viz_details(0, 0)) @@ -141,8 +172,8 @@ class TestViz(BaseTestViz): self.assertEqual(graphs[2], uop_to_json(nop)[id(nop)]) def test_const_node_visibility(self): - a = UOp.variable("a", 0, 10) - z = UOp.const(dtypes.index, 0) + a = UOp.variable("a", 0, 10, dtype=dtypes.int) + z = UOp.const(a.dtype, 0) alu = a*z exec_rewrite(alu, [sym]) lst = get_viz_list() @@ -290,6 +321,13 @@ class TestVizIntegration(BaseTestViz): self.assertEqual(list(next(get_viz_details(1, 0))["graph"]), [id(c)]) self.assertEqual(list(next(get_viz_details(1, 1))["graph"]), [id(c+2)]) + def test_recurse(self): + a = Tensor.empty(10) + for _ in range(10_000): a += a + graph_rewrite(a.uop, PatternMatcher([])) + lst = get_viz_list() + assert len(lst) == 1 + from tinygrad.device import ProfileDeviceEvent, ProfileGraphEvent, ProfileGraphEntry from tinygrad.viz.serve import get_profile @@ -318,18 +356,18 @@ def load_profile(lst:list[ProfileEvent]) -> dict: event_type, event_count = u(" list[int]: + if (early_token:=self._normal_tokens.get(word)) is not None: return [early_token] + parts = [bytes([b]) for b in word] + # greedily merge any parts that we can + while True: + i = min([(sys.maxsize, -1)] + [(self._normal_tokens.get(parts[j]+parts[j+1], sys.maxsize), j) for j in range(len(parts)-1)])[1] + if i == -1: break + parts[i:i+2] = [parts[i] + parts[i+1]] + try: return [self._normal_tokens[p] for p in parts] + except KeyError: raise RuntimeError("token not found") + def _encode_sentence(self, chunk:str) -> list[int]: + return [tok for word in self._split_to_word.findall(chunk) for tok in self._encode_word(word.encode())] + def encode(self, text:str) -> list[int]: tokens: list[int] = [] pos = 0 - for match in self._special_re.finditer(text): + for match in self._split_to_sentence.finditer(text): tokens.extend(self._encode_sentence(text[pos:match.start(0)]) + [self._special_tokens[text[match.start(0):match.end(0)]]]) pos = match.end(0) return tokens + self._encode_sentence(text[pos:]) - def decode(self, ids: list[int]) -> str: return b''.join(self._tok2str[tid] for tid in ids).decode() + def decode(self, ids:list[int]) -> str: return b''.join(self._tok2bytes[tid] for tid in ids).decode() def role(self, role:str): return self.encode("<|start_header_id|>" + role + "<|end_header_id|>\n\n") - def _encode_sentence(self, chunk: str): return [ tok for word in self._pat.findall(chunk) for tok in self._encode_word(word.encode()) ] - def _encode_word(self, word: bytes): - if (early_token:=self._normal_tokens.get(word)) is not None: return [early_token] - parts = [word[i:i+1] for i in range(len(word))] - while True: - min_tid, min_idx = 2**32, -1 - for idx, (p1, p2) in enumerate(zip(parts[:-1], parts[1:])): - tid = self._normal_tokens.get(p1 + p2, min_tid) - if tid < min_tid: min_tid, min_idx = tid, idx - if min_idx == -1: break - parts = parts[:min_idx] + [parts[min_idx] + parts[min_idx+1]] + parts[min_idx+2:] - try: return [ self._normal_tokens[p] for p in parts ] - except KeyError: raise RuntimeError("token not found") - def apply_rope(x:Tensor, start_pos:int|UOp, base:float = 10000.0) -> Tensor: B, H, T, Hd = x.shape - assert (Hd & 1) == 0, "RoPE requires an even head dimension" + assert isinstance(Hd, int) and (Hd & 1) == 0, "RoPE requires an even head dimension" half = Hd // 2 - angles = (Tensor.arange(T, dtype="float32") + start_pos)[:, None] * (base ** (-(Tensor.arange(half, dtype="float32") / half)))[None, :] + t_start_pos = start_pos if isinstance(start_pos, int) else Tensor(start_pos) + angles = (Tensor.arange(T, dtype="float32") + t_start_pos)[:, None] * (base ** (-(Tensor.arange(half, dtype="float32") / half)))[None, :] # contiguous here allows RoPE to be pruned in the JIT cos, sin = angles.cos().reshape(1, 1, T, half).cast(x.dtype).contiguous(), angles.sin().reshape(1, 1, T, half).cast(x.dtype).contiguous() x_pairs = x.reshape(B, H, T, half, 2) diff --git a/tinygrad/codegen/__init__.py b/tinygrad/codegen/__init__.py index 4870bda7fd..572df13857 100644 --- a/tinygrad/codegen/__init__.py +++ b/tinygrad/codegen/__init__.py @@ -1,137 +1,142 @@ -from typing import Any, Callable -import functools -from dataclasses import dataclass -from tinygrad.helpers import QUANTIZE, DEVECTORIZE, TRANSCENDENTAL, RANGEIFY -from tinygrad.uop.ops import PatternMatcher, graph_rewrite, UOp, pm_lower_index_dtype -from tinygrad.uop.spec import type_verify +from typing import cast +import itertools +from tinygrad.helpers import DEVECTORIZE, TRANSCENDENTAL, SPEC +from tinygrad.uop.ops import PatternMatcher, graph_rewrite, UOp, pm_lower_index_dtype, Ops, UPat +from tinygrad.uop.spec import type_verify, program_spec, kernel_spec from tinygrad.renderer import Renderer +from tinygrad.dtype import dtypes, PtrDType +from tinygrad.helpers import panic # import all pattern matchers here -from tinygrad.codegen.lowerer import pm_lowerer, get_index -from tinygrad.codegen.quantize import pm_quant from tinygrad.codegen.gpudims import pm_add_gpudims -from tinygrad.uop.symbolic import sym, symbolic_simple, gep_pushing, symbolic +from tinygrad.uop.symbolic import sym, symbolic_simple, gep_pushing, symbolic, pm_move_where_on_load from tinygrad.uop.decompositions import get_late_rewrite_patterns -from tinygrad.codegen.late.expander import migrate_indexing, expander, pm_pre_expander, pm_group_for_reduce +from tinygrad.codegen.late.expander import expander, pm_pre_expander, pm_group_for_reduce from tinygrad.codegen.late.devectorizer import load_store_folding, load_store_indexing, devectorize, pm_reduce, \ - ReduceContext, correct_load_store, pm_render -from tinygrad.codegen.late.linearize import block_create, pm_blockend_merge, block_merge, pm_finalize, BlockContext -from tinygrad.codegen.opt.swizzler import view_left, view_right, fix_kernel_ops -from tinygrad.codegen.opt.postrange import pm_postrange_opt -from tinygrad.codegen.simplify import pm_simplify_ranges, pm_reduce_simplify, pm_flatten_range, pm_split_ranges -from tinygrad.schedule.rangeify import pm_add_buffers, rangeify_codegen + ReduceContext, correct_load_store, pm_render, pm_add_loads +from tinygrad.codegen.opt.postrange import apply_opts +from tinygrad.codegen.simplify import pm_simplify_ranges, pm_flatten_range, pm_split_ranges, pm_load_collapse, pm_split_store +from tinygrad.schedule.rangeify import pm_add_buffers_local, rangeify_codegen, pm_mops +from tinygrad.codegen.late.linearizer import CFGContext, pm_split_ends, pm_add_control_flow, linearize -@dataclass -class RewriteStep: - pm: PatternMatcher - ctx: Callable[[UOp], Any]|None = None - name: str|None = None - bottom_up: bool = False - def __call__(self, sink:UOp): - return graph_rewrite(sink, self.pm, ctx=self.ctx(sink) if self.ctx is not None else None, name=self.name, bottom_up=self.bottom_up) +pm_syntactic_sugar = PatternMatcher([ + # INDEX on ptr INDEX concats them + (UPat(Ops.INDEX, name="i1").f(Ops.INDEX, name="i2", allow_any_len=True), + lambda i1,i2: i2.replace(src=i1.src+i2.src[1:]) if isinstance(i1.dtype, PtrDType) and not isinstance(i2.dtype, PtrDType) else None), +]) -def apply_rewrites(sink:UOp, rewrites:list[RewriteStep]): return functools.reduce(lambda x,f: f(x), rewrites, sink) +def full_rewrite_to_sink(sink:UOp, ren:Renderer|None=None, optimize:bool=True) -> UOp: + if ren is None: ren = Renderer() -rewrites_for_views = [ - RewriteStep(view_left, name="Main View Left"), - RewriteStep(view_right, name="Main View Right"), - RewriteStep(view_left+fix_kernel_ops, bottom_up=True, name="Finalize Kernel"), -] + if SPEC: type_verify(sink, kernel_spec) -rewrites_for_linearizer = [ - RewriteStep(block_create, ctx=BlockContext.from_sink, name="Linearizer: Create Blocks", bottom_up=True), - RewriteStep(pm_blockend_merge, name="Linearizer: Merge Blockends"), - RewriteStep(block_merge, name="Linearizer: Merge Blocks"), - RewriteStep(pm_finalize, name="Linearizer: Finalize")] - -def get_rewrites_for_renderer(opts:Renderer, optimize:bool=True, linearizer:bool=True) -> list[RewriteStep]: - # cache with the values of the context vars - return _get_rewrites_for_renderer(opts, optimize, linearizer, QUANTIZE.value, DEVECTORIZE.value, TRANSCENDENTAL.value, RANGEIFY.value) - -@functools.cache -def _get_rewrites_for_renderer(opts:Renderer, optimize:bool, linearizer:bool, _QUANTIZE, _DEVECTORIZE, _TRANSCENDENTAL, - _RANGEIFY) -> list[RewriteStep]: - # ** lowerer (rewrite_shapetracker_with_index) ** - ret: list[RewriteStep] = [] + # preprocess + sink = graph_rewrite(sink, pm_mops+pm_syntactic_sugar, name="early movement ops", bottom_up=True) + # first we optimize if optimize: - # view pushing - if not _RANGEIFY: ret.extend(rewrites_for_views) - - # lowerer first - if _QUANTIZE and opts.device in {"CPU", "DSP"}: ret.append(RewriteStep(pm_quant, name="quantize")) - ret.append(RewriteStep(pm_lowerer, get_index, name="lowerer", bottom_up=True)) + # collapse loads reduce (indexing by a tensor) + sink = graph_rewrite(sink, pm_load_collapse, name="load collapse") # split ranges - if _RANGEIFY: - ret.append(RewriteStep(pm_split_ranges+pm_flatten_range, ctx=lambda _: {}, name="split ranges")) + sink = graph_rewrite(sink, pm_split_ranges+pm_flatten_range, ctx={}, name="split ranges") # symbolic (NOTE: this is a requirement for pm_simplify_ranges to be correct) - ret.append(RewriteStep(sym+pm_flatten_range, name="initial symbolic")) + sink = graph_rewrite(sink, sym+pm_flatten_range, name="initial symbolic") # optimize (schedule) the AST - ret.append(RewriteStep(pm_simplify_ranges, name="simplify ranges")) - ret.append(RewriteStep(pm_reduce_simplify, name="simplify reduces")) - ret.append(RewriteStep(pm_postrange_opt, ctx=lambda _: opts, name="post optimize ast")) + sink = graph_rewrite(sink, pm_simplify_ranges, name="simplify ranges") + + # split store range (only on CPU for now) + sink = graph_rewrite(sink, pm_split_store, ctx=ren.device, name="cut store ranges") + + # do postrange optimization, BEAM or hand_coded_optimizations + sink = apply_opts(sink, ren) # ** expander (expand_rewrite) ** - ret.append(RewriteStep(sym+migrate_indexing, name="postopt symbolic")) + sink = graph_rewrite(sink, sym+pm_move_where_on_load, name="postopt symbolic") # expand - ret.append(RewriteStep(sym+pm_pre_expander+pm_group_for_reduce+expander, name="expander")) + sink = graph_rewrite(sink, sym+pm_pre_expander+pm_group_for_reduce+expander, name="expander") # add locals - ret.append(RewriteStep(pm_add_buffers+rangeify_codegen, name="add local buffers")) + sink = graph_rewrite(sink, pm_add_buffers_local+rangeify_codegen, ctx=itertools.count(0), name="add local buffers") # ** devectorizer (full_graph_rewrite) ** # remove reduce - ret.append(RewriteStep(pm_reduce+gep_pushing, lambda _: ReduceContext(), name="remove_reduce")) + sink = graph_rewrite(sink, pm_reduce+gep_pushing, ctx=ReduceContext(), name="remove_reduce") # add gpu dims (late). this works after devectorize, but it's faster here - ret.append(RewriteStep(pm_add_gpudims, lambda _: opts, name="add gpudims")) + sink = graph_rewrite(sink, pm_add_gpudims, ctx=ren, name="add gpudims") + + # **** optimizations are done, now we lower to actual code **** + + # add loads + sink = graph_rewrite(sink, pm_add_loads, name="** add loads (code)") # devectorize (TODO: does this need opts?) - if _DEVECTORIZE >= 2: pm_devectorize = sym+load_store_folding+load_store_indexing - elif _DEVECTORIZE: pm_devectorize = sym+devectorize+load_store_folding+correct_load_store+load_store_indexing + if DEVECTORIZE >= 2: pm_devectorize = sym+load_store_folding+load_store_indexing + elif DEVECTORIZE: pm_devectorize = sym+devectorize+load_store_folding+correct_load_store+load_store_indexing else: pm_devectorize = sym+load_store_folding+correct_load_store+load_store_indexing - ret.append(RewriteStep(pm_devectorize, lambda _: opts, name="devectorize")) - - supported_ops = tuple(opts.code_for_op.keys()) - extra_matcher = opts.extra_matcher if opts.extra_matcher is not None else PatternMatcher([]) + sink = graph_rewrite(sink, pm_devectorize, ctx=ren, name="devectorize") # lower the index dtype to a concrete int - ret.append(RewriteStep(pm_lower_index_dtype+load_store_indexing, lambda _: opts.device, name="lower all index dtypes")) - ret.append(RewriteStep(symbolic, name="post index symbolic")) + sink = graph_rewrite(sink, pm_lower_index_dtype+load_store_indexing, ctx=ren.device, name="lower all index dtypes") + sink = graph_rewrite(sink, symbolic, name="post index symbolic") # optional pre matcher - if opts.pre_matcher is not None: ret.append(RewriteStep(opts.pre_matcher, name="pre_matcher")) + if ren.pre_matcher is not None: sink = graph_rewrite(sink, ren.pre_matcher, name="pre_matcher") # decompositions - pm_decomp = symbolic_simple+get_late_rewrite_patterns(supported_ops, _TRANSCENDENTAL>=2) - ret.append(RewriteStep(pm_decomp, lambda _: opts.device, name="decompositions")) + supported_ops = tuple(ren.code_for_op.keys()) + pm_decomp = symbolic_simple+get_late_rewrite_patterns(supported_ops, TRANSCENDENTAL>=2) + sink = graph_rewrite(sink, pm_decomp, ctx=ren.device, name="decompositions") # final rules for the renderer (without sym) - pm_final_rewrite = pm_decomp+pm_render+extra_matcher - ret.append(RewriteStep(pm_final_rewrite, lambda _: opts.device, name="final rewrite")) + extra_matcher = ren.extra_matcher if ren.extra_matcher is not None else PatternMatcher([]) + pm_final_rewrite = pm_decomp+pm_render+extra_matcher+pm_split_ends + sink = graph_rewrite(sink, pm_final_rewrite, ctx=ren.device, name="final rewrite") - # return the list (with optional linearizer) - return ret + (rewrites_for_linearizer if linearizer else []) + # this was the linearizer + sink = graph_rewrite(sink, pm_add_control_flow, ctx=CFGContext(sink), name="add control flow", bottom_up=True) -def full_rewrite_to_sink(sink:UOp, opts:Renderer|None=None, optimize:bool=True, linearizer:bool=False) -> UOp: - return apply_rewrites(sink, get_rewrites_for_renderer(opts if opts is not None else Renderer(), optimize, linearizer)) + # return the rewritten sink + return sink -def full_rewrite(sink:UOp, opts:Renderer|None=None) -> list[UOp]: +# inject IF/ENDIF. only needed if device doesn't support gated stores +pm_linearize_cleanups = PatternMatcher([ + # if statements are not allowed in the graph + (UPat((Ops.IF, Ops.ENDIF)), lambda: panic(RuntimeError("if not allowed in graph"))), + # gated INDEX becomes IF-STORE-ENDIF. this is the only use of IF-ENDIF + (UPat(Ops.STORE, name="u", src=(UPat(Ops.INDEX, src=(UPat(), UPat(), UPat(name="gate", dtype=dtypes.bool))).or_casted(), UPat()), + allow_any_len=True), lambda u, gate: (u, [mif:=UOp(Ops.IF, src=(gate, u.src[0])), u, UOp(Ops.ENDIF, src=(mif,))])) +]) + +# requires lst be toposorted. like graph rewrite, but for lines +def line_rewrite(lst:list[UOp], pm:PatternMatcher) -> list[UOp]: + newlst = [] + replaced: dict[UOp, UOp] = {} + for u in lst: + nu = u.replace(src=tuple([replaced[x] for x in u.src])) + ret: tuple[UOp, list[UOp]] = cast(tuple[UOp, list[UOp]]|None, pm.rewrite(nu)) or (nu, [nu]) + replaced[u] = ret[0] + newlst.extend(ret[1]) + return newlst + +def full_rewrite(sink:UOp, ren:Renderer|None=None) -> list[UOp]: """ Function to transform the Kernel UOp graph into a linearized program. Args: sink: The Ops.SINK rooting the Kernel graph. - opts: The Renderer (can change how things are processed, fix this). + ren: The Renderer (can change how things are processed, fix this). Returns: Linear program in UOps. """ - lst = list(full_rewrite_to_sink(sink, opts, optimize=sink.tag is None, linearizer=True).arg.lst) - if __debug__: type_verify(lst) + full_sink = full_rewrite_to_sink(sink, ren, optimize=sink.tag is None) + assert len(full_sink.ranges) == 0, f"all ranges must end by the sink, {full_sink.ranges}" + lst = line_rewrite(linearize(full_sink), pm_linearize_cleanups) + if SPEC: type_verify(lst, program_spec) return lst diff --git a/tinygrad/codegen/gpudims.py b/tinygrad/codegen/gpudims.py index 3bc67e5177..5a70c6d23b 100644 --- a/tinygrad/codegen/gpudims.py +++ b/tinygrad/codegen/gpudims.py @@ -1,8 +1,7 @@ -import math +import math, functools, operator from tinygrad.uop.ops import UOp, Ops, sint, PatternMatcher, UPat, KernelInfo, ssimplify, AxisType, sint_to_uop -from tinygrad.helpers import all_int, dedup -from tinygrad.dtype import dtypes -from tinygrad.shape.view import get_contraction +from tinygrad.helpers import all_int, dedup, get_contraction +from tinygrad.dtype import dtypes, AddrSpace, Invalid from tinygrad.renderer import Renderer def _group_dims(dims:tuple[sint, ...], max_sizes:tuple[int, ...]): @@ -27,28 +26,35 @@ def _split_dims(dims, max_sizes): return tuple(_dims[:2] if _dims[2] == 1 else _dims[0] if _dims[1:3] == [1,1] else _dims) def get_grouped_dims(prefix, dims:tuple[sint, ...], max_sizes:tuple[int, ...]|None, reverse=False) -> list[UOp]: - if reverse: dims = dims[::-1] - # try to group first: (a, b, c, d) -> (ab, c, d) - limited = (grouped if (grouped := _group_dims(dims, max_sizes)) else dims) if max_sizes is not None else dims - # check if grouping failed - if max_sizes is not None and len(limited) > len(max_sizes): raise RuntimeError(f"cannot limit dim {dims=}, {max_sizes=}") - # try to split up dims: (a,) -> (b, c) - if limited == dims: limited = _split_dims(dims, max_sizes) if max_sizes is not None else dims - ret = raw_idxs = [UOp(Ops.SPECIAL, dtypes.index, (sint_to_uop(s),), (f"{prefix}{i}")) for i,s in enumerate(limited)] + if reverse: return get_grouped_dims(prefix, dims[::-1], max_sizes)[::-1] + if max_sizes is None: limited = dims + else: + # try to group first: (a, b, c, d) -> (ab, c, d) + limited = grouped if (grouped := _group_dims(dims, max_sizes)) else dims + # check if grouping failed + if len(limited) > len(max_sizes): raise RuntimeError(f"cannot limit dim {dims=}, {max_sizes=}") + # try to split up dims: (a,) -> (b, c) + if limited == dims: limited = _split_dims(dims, max_sizes) + raw_idxs = [UOp(Ops.SPECIAL, dtypes.index, (sint_to_uop(s),), (f"{prefix}{i}")) for i,s in enumerate(limited)] if len(limited) < len(dims): ret = [] - if (contraction:=get_contraction(dims, limited)) is None: raise AssertionError(f"get_contraction should not be None {dims=} {limited=}") + if (contraction:=get_contraction(dims, limited)) is None: raise RuntimeError(f"get_contraction should not be None {dims=} {limited=}") for idx, contraction_group in zip(raw_idxs, contraction): for c in contraction_group[:-1]: ret.append(idx % dims[c]) idx //= dims[c] ret.append(idx) - elif len(limited) > len(dims): - a, b = len(limited), len(dims) - if a == 2 and b == 1: ret = [raw_idxs[0] * limited[1] + raw_idxs[1]] - if a == 3 and b == 1: ret = [raw_idxs[0] * (limited[1] * limited[2]) + raw_idxs[1] * limited[2] + raw_idxs[2]] - if a == 3 and b == 2: ret = [raw_idxs[0] * limited[1] + raw_idxs[1], raw_idxs[2]] - return ret[::-1] if reverse else ret + return ret + elif (a:=len(limited)) > (b:=len(dims)): + if a == 2 and b == 1: return [raw_idxs[0] * limited[1] + raw_idxs[1]] + if a == 3 and b == 1: return [(raw_idxs[0] * limited[1] + raw_idxs[1]) * limited[2] + raw_idxs[2]] + if a == 3 and b == 2: return [raw_idxs[0] * limited[1] + raw_idxs[1], raw_idxs[2]] + elif limited != dims: + # Convert to 1D + flat = raw_idxs[0]*limited[1]+raw_idxs[1] if len(dims) == 2 else raw_idxs[0]*(limited[1]*limited[2])+raw_idxs[1]*limited[2]+raw_idxs[2] + # Get back original indices from 1D + return [flat//dims[1], flat%dims[1]] if len(dims) == 2 else [flat//(dims[2]*dims[1]), (flat//dims[2])%dims[1], flat%dims[2]] + return raw_idxs def add_gpudims(ctx:Renderer, s:UOp): if s.arg is None: return None @@ -80,6 +86,14 @@ def add_gpudims(ctx:Renderer, s:UOp): # apply to multiple ranges subs = {} for r in s_topo: + # look for local INDEXes that are not used in the GLOBAL store, then add them as an INVALID + if r.op is Ops.STORE and r.buf_target().ptrdtype.addrspace == AddrSpace.GLOBAL: + idx = r.src[0] + missing_locals = [all_ranges[rng] for rng in local_dims if all_ranges[rng] not in idx.ranges] + if len(missing_locals): + assert len(idx.src) == 2, "index has 2 sources" + mask: UOp = functools.reduce(operator.and_, [x.eq(0) for x in missing_locals]) + subs[idx] = idx.replace(src=(idx.src[0], mask.broadcast(idx.src[1].dtype.count).where(idx.src[1], Invalid))) if r.op is not Ops.RANGE: continue try: ii = (global_dims+local_dims).index(r.arg[0:-1]) diff --git a/tinygrad/codegen/late/devectorizer.py b/tinygrad/codegen/late/devectorizer.py index 50a33b5ffe..b16cdc6ee7 100644 --- a/tinygrad/codegen/late/devectorizer.py +++ b/tinygrad/codegen/late/devectorizer.py @@ -2,17 +2,17 @@ from typing import Any, cast import functools, operator, itertools from collections import defaultdict from dataclasses import dataclass -from tinygrad.dtype import dtypes, ImageDType, DType, AddrSpace, Invalid +from tinygrad.dtype import dtypes, ImageDType, DType, AddrSpace, Invalid, PtrDType from tinygrad.uop.ops import UOp, Ops, UPat, PatternMatcher, graph_rewrite, GroupOp, identity_element -from tinygrad.uop.symbolic import uop_given_valid, parse_valid, sym, symbolic_flat, invalid_gate +from tinygrad.uop.symbolic import uop_given_valid, parse_valid, sym, symbolic, invalid_gate from tinygrad.helpers import getenv, flatten, AMX, prod from tinygrad.renderer import Renderer # ***** image load valid simplification ***** def simplify_valid_load(buf:UOp, start_idx:UOp, valid:UOp) -> UOp|None: - if (idx:=uop_given_valid(valid, start_idx)) is None: return buf.index(UOp.invalid()) - if not isinstance(buf.dtype, ImageDType): return None if idx is start_idx else buf.index(idx.valid(valid)) + idx = uop_given_valid(valid, start_idx) + if not isinstance(buf.dtype, ImageDType): return None if idx is start_idx else buf.index(idx.valid(valid), ptr=True) # wait for it to be image indexed before running simplification if start_idx.dtype.count != 2: return None @@ -20,8 +20,8 @@ def simplify_valid_load(buf:UOp, start_idx:UOp, valid:UOp) -> UOp|None: # can drop valid if idx is out of bound when valid is False drop_stmt = [] for stmt in valid.split_uop(Ops.AND): - try: X, is_upper_bound, c = parse_valid(stmt) - except ValueError: return None + if (res:=parse_valid(stmt)) is None: continue + X, is_upper_bound, c = res # for X0 + X1 + ... >= 1, check if it's out of bound when Xi = 0 for all i if not is_upper_bound and c == 1 and all(u.op in GroupOp.Irreducible and u.vmin == 0 for u in X.split_uop(Ops.ADD)): @@ -43,26 +43,16 @@ def simplify_valid_load(buf:UOp, start_idx:UOp, valid:UOp) -> UOp|None: if not drop_stmt and idx is start_idx: return None new_valid = functools.reduce(operator.and_, ss) if (ss:=[s for s in valid.split_uop(Ops.AND) if s not in drop_stmt]) else None - return buf.index(idx.valid(new_valid) if new_valid is not None else idx) + return buf.index(idx.valid(new_valid) if new_valid is not None else idx, ptr=True) -def delete_redundant_gates(store:UOp, buf:UOp, idx:UOp, val:UOp, store_gate:UOp, cast:UOp|None=None) -> UOp|None: - if store_gate not in [gate.src[0] for gate in val.toposort() if gate.op is Ops.IF]: return None - # remove the gate from the index - return UOp.store(buf.index(idx).cast(cast.dtype) if cast is not None else buf.index(idx), val, *store.src[2:]) -def no_load(u:UOp) -> bool: return not any(x.op is Ops.LOAD for x in u.sparents) load_store_indexing = PatternMatcher([ # image load valid idx simplification (UPat(Ops.INDEX, src=(UPat.var("buf"), invalid_gate)), lambda buf,x,i,cond: simplify_valid_load(buf, x, cond)), # simplify away long after index has been lowered (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("x", dtypes.long), UPat.var("c", dtypes.bool))), lambda buf,x,c: simplify_valid_load(buf, x, c)), # drop true gate - (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("x"), UPat.const(dtypes.bool, True)),), lambda buf,x: buf.index(x)), - # delete_redundant_gates (after expand) - (UPat(Ops.STORE, src=(UPat.any(stidx:=UPat.var("buf").index(UPat.var("idx"), UPat.var("store_gate")), stidx.cast().named("cast")), - UPat.var("val")), name="store", allow_any_len=True), delete_redundant_gates), - # we want to make sure we dont do math on a loaded index since that can cause overflow, this undoes a pattern in reduce_collapse - (UPat.var("c")<(UPat.var("x", dtypes.index)+UPat.var("y")), lambda x,y,c: (-x < -(c-y)) if no_load(y) and no_load(c) and not no_load(x) else None), + (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("x"), UPat.const(dtypes.bool, True)),), lambda buf,x: buf.index(x, ptr=True)), ]) # ***** load/store grouping ***** @@ -70,8 +60,8 @@ load_store_indexing = PatternMatcher([ def expand_index(buf:UOp, vec:UOp): if getenv("UNSAFE_DISABLE_MASK", 0): vec = vec.get_idx() # generate the individual indexes - midx = graph_rewrite(UOp.sink(*[buf.index(vec.gep(i)) for i in range(vec.dtype.count)]), - symbolic_flat+load_store_indexing, name=f"index_buf_{buf.arg}") + midx = graph_rewrite(UOp.sink(*[buf.index(vec.gep(i), ptr=True) for i in range(vec.dtype.count)]), + symbolic+load_store_indexing, name=f"index_buf_{buf.arg}") # extract all the relevant offsets offsets_rootsrc: defaultdict[Any, dict[int, list[int]]] = defaultdict(dict) for i in range(vec.dtype.count): @@ -112,7 +102,7 @@ def cat_after_store(cat:UOp, data:UOp, sto:UOp): for s in cat.src: ret.append(s.store(data.gep(tuple(range(offset, offset+s.dtype.count))), *sto.src[2:])) offset += s.dtype.count - return UOp(Ops.NOOP, src=tuple(ret)) + return UOp.group(*ret) def gep_on_store(gep:UOp, st:UOp, sto:UOp): # NOTE: we need to invert the gep here, but it may be an expanding gep @@ -123,7 +113,7 @@ def gep_on_store(gep:UOp, st:UOp, sto:UOp): return gep.src[0].store(st.gep(new_arg), *sto.src[2:]) load_store_folding = PatternMatcher([ - (UPat(Ops.INDEX, src=(UPat(Ops.VECTORIZE, src=UPat(GroupOp.Defines, name="buf")), UPat.var("vec"))), expand_index), + (UPat(Ops.INDEX, src=(UPat(Ops.VECTORIZE, src=UPat(GroupOp.Defines).or_after(name="buf")), UPat.var("vec"))), expand_index), # GEP after LOAD (UPat(Ops.LOAD, src=(UPat(Ops.GEP, name="gep"),), name="ld", allow_any_len=True), lambda gep, ld: ld.replace(dtype=ld.dtype.scalar().vec(gep.dtype.count), src=(gep.src[0],)+ld.src[1:]).gep(gep.arg)), @@ -151,7 +141,7 @@ def split_load_store(ctx:Renderer|None, ls:UOp, idx:UOp): if ctx is not None and ctx.device == "DSP": lengths = [128,64,32,16,8,4] must_divide = False - elif buf.dtype.base != dtypes.float and buf.dtype.base != dtypes.half and not isinstance(buf.dtype, ImageDType): + elif buf.dtype.base not in (dtypes.float, dtypes.half, *dtypes.fp8s) and not isinstance(buf.dtype, ImageDType): pass elif buf.ptrdtype.addrspace == AddrSpace.REG: pass @@ -173,7 +163,7 @@ def split_load_store(ctx:Renderer|None, ls:UOp, idx:UOp): # with 1 at the end of the lengths list, this will always hit for fold_length in lengths: if global_offset+fold_length > sz: continue - lidx = buf.index((offset + global_offset).valid(mask)) + lidx = buf.index((offset + global_offset).valid(mask), ptr=True) if fold_length > 1: lidx = lidx.cast(buf.ptrdtype.base.vec(fold_length).ptr(size=buf.ptrdtype.size, addrspace=buf.ptrdtype.addrspace)) if ls.op is Ops.STORE: ret.append(ls.replace(src=(lidx,ls.src[1].gep(tuple(range(global_offset, global_offset+fold_length))))+ls.src[2:])) else: ret.append(ls.replace(src=(lidx,)+ls.src[1:], dtype=ls.dtype.scalar().vec(fold_length))) @@ -182,7 +172,7 @@ def split_load_store(ctx:Renderer|None, ls:UOp, idx:UOp): # if it wasn't split, we return None. otherwise we CAT them if len(ret) <= 1: return None - return UOp(Ops.CAT, ls.dtype, tuple(ret)) if ls.op is Ops.LOAD else UOp(Ops.NOOP, src=tuple(ret)) + return UOp(Ops.CAT, ls.dtype, tuple(ret)) if ls.op is Ops.LOAD else UOp.group(*ret) def image_fixup(ls:UOp): # normal image load or store, with the CAST from expand_index @@ -239,15 +229,32 @@ def no_vectorized_buf(buf:UOp): def no_vectorized_index(buf:UOp, cast:UOp, idx:UOp): cnt = cast.dtype.count assert idx.dtype.count == 1, f"idx dtype must be 1 {idx.dtype}" - return buf.broadcast(cnt).index(idx.broadcast(cnt)*cnt+UOp.const(dtypes.index.vec(cnt), tuple(range(cnt)))) + return buf.broadcast(cnt).index(idx.broadcast(cnt)*cnt+UOp.const(dtypes.index.vec(cnt), tuple(range(cnt))), ptr=True) + +def no_vectorized_index_broadcast(buf:UOp, cast:UOp, bcast:UOp, idx:UOp): + cnt = cast.dtype.count + precnt = bcast.dtype.vcount + input_gep = bcast.arg if bcast.op is Ops.GEP else ([0]*precnt) + gep_arg = tuple(flatten([range(precnt) for _ in range(cnt)])) + sum_arg = tuple(flatten([[i+y for y in input_gep] for i in range(cnt)])) + return buf.broadcast(cnt*precnt).index(idx.gep(gep_arg)*cnt+UOp.const(dtypes.index.vec(cnt*precnt), sum_arg), ptr=True) + +devectorize_buf_and_index = PatternMatcher([ + (UPat((Ops.DEFINE_LOCAL, Ops.DEFINE_REG), name="buf"), no_vectorized_buf), + (UPat((Ops.DEFINE_LOCAL, Ops.DEFINE_REG)).or_after(name="buf").cast(name="cast").index(UPat.var("idx")), no_vectorized_index), + (UPat((Ops.DEFINE_LOCAL, Ops.DEFINE_REG)).or_after(name="buf").cast(name="cast").broadcast(name="bcast").index(UPat.var("idx")), + no_vectorized_index_broadcast), + (UPat((Ops.DEFINE_LOCAL, Ops.DEFINE_REG)).or_after(name="buf").cast(name="cast").gep(name="bcast").index(UPat.var("idx")), + no_vectorized_index_broadcast), +]) devectorize = PatternMatcher([ + # CAST after AFTER + (UPat(Ops.CAST, name="c").f(Ops.AFTER, allow_any_len=True, name="a"), lambda c,a: c.src[0].after(*a.src[1:]).cast(c.dtype)), # no ALU on vectorized dtypes (UPat((*GroupOp.ALU, Ops.CAST, Ops.BITCAST), name="alu"), no_vectorized_alu), (UPat(Ops.WMMA, name="wmma"), no_vectorized_wmma), - (UPat((Ops.DEFINE_LOCAL, Ops.DEFINE_REG), name="buf"), no_vectorized_buf), - (UPat((Ops.DEFINE_LOCAL, Ops.DEFINE_REG), name="buf").cast(name="cast").index(UPat.var("idx")), no_vectorized_index), -]) +])+devectorize_buf_and_index pm_render = PatternMatcher([ # for rendering, we use explicit VECTORIZE @@ -266,10 +273,6 @@ pm_render = PatternMatcher([ UPat.var("a")), lambda c,idx,l,a: l.replace(src=(l.src[0], a.cast(l.dtype))+l.src[2:]).cast(a.dtype)), (UPat.var("c").where(UPat.var("a"), UPat(Ops.LOAD, src=(UPat().index(UPat.var("idx"), UPat.var("c").logical_not()).or_casted(),), allow_any_len=True, name="l").or_casted()), lambda c,idx,l,a: l.replace(src=(l.src[0], a.cast(l.dtype))+l.src[2:]).cast(a.dtype)), - # gate any stores that aren't gated with ifs - (UPat(Ops.STORE, src=(UPat(src=(UPat(), UPat(), UPat(dtype=dtypes.bool)), name="idx").or_casted(), UPat()), name="store", allow_any_len=True), - lambda store,idx: UOp(Ops.STORE, dtype=store.dtype, src=store.src[:2]+(UOp(Ops.IF, src=(idx.src[2],)),)+store.src[2:]) if \ - len(store.src) <= 2 or store.src[2].op != Ops.IF else None), ]) # *** Ops.REDUCE -> Ops.DEFINE_ACC *** @@ -293,15 +296,17 @@ def reduce_to_acc(ctx:ReduceContext, red:UOp): # if we have a range if len(reduce_range) != 0: topo = inp.toposort() - stored_ranges = flatten([x.src[2:] for x in topo if x.op is Ops.STORE]) - input_ranges = tuple([x for x in topo if x.op is Ops.RANGE and x not in reduce_range and x not in stored_ranges]) + ended_ranges = flatten([x.ended_ranges for x in topo if x.op is Ops.END]) + input_ranges = tuple([x for x in topo if x.op is Ops.RANGE and x not in reduce_range and x not in ended_ranges]) identity = red.const(red.dtype, identity_element(red.arg, red.dtype.scalar())) - acc = UOp(Ops.DEFINE_REG, red.dtype.ptr(size=1, addrspace=AddrSpace.REG), arg=(ctx.acc_num,)).index(UOp.const(dtypes.int, 0)) - do_store = acc.store(identity, UOp(Ops.NOOP, src=input_ranges)) if len(input_ranges) else acc.store(identity) - lst = [acc.load(do_store, *reduce_range)] + lst # put acc as the first element + acc = UOp(Ops.DEFINE_REG, red.dtype.ptr(size=1, addrspace=AddrSpace.REG), arg=ctx.acc_num) + acc_init = acc.after(*input_ranges).index(UOp.const(dtypes.int, 0)).store(identity) if len(input_ranges) else \ + acc.index(UOp.const(dtypes.int, 0)).store(identity) + lst = [acc.after(acc_init, *reduce_range).index(UOp.const(dtypes.int, 0))] + lst # put acc as the first element ctx.acc_num += 1 ret = functools.reduce(lambda x,y: x.alu(red.arg, y), lst) - return acc.load(acc.store(ret, *reduce_range)) if len(reduce_range) != 0 else ret + if len(reduce_range) == 0: return ret + return acc.after(acc.index(UOp.const(dtypes.int, 0)).store(ret).end(*reduce_range)).index(UOp.const(dtypes.int, 0)) pm_reduce = PatternMatcher([ # REDUCE -> DEFINE_ACC+ASSIGN @@ -310,3 +315,14 @@ pm_reduce = PatternMatcher([ (UPat(Ops.WMMA, name="wmma") + UPat.var("add"), lambda add, wmma: UOp(wmma.op, wmma.dtype, (wmma.src[0], wmma.src[1], wmma.src[2]+add), wmma.arg)), ])+sym + +# add loads + +pm_add_loads = PatternMatcher([ + # add loads to non ptr index + (UPat(Ops.INDEX, name="idx"), lambda idx: None if isinstance(idx.dtype, (PtrDType, ImageDType)) else + idx.replace(dtype=idx.src[0].dtype).load(dtype=idx.dtype.base)), + # remove loads from stores + (UPat(Ops.STORE, src=(UPat(Ops.LOAD),), allow_any_len=True, name="s"), lambda s: s.replace(src=(s.src[0].src[0],)+s.src[1:])), +]) + diff --git a/tinygrad/codegen/late/expander.py b/tinygrad/codegen/late/expander.py index 9a42d414ce..a3eb42bf0d 100644 --- a/tinygrad/codegen/late/expander.py +++ b/tinygrad/codegen/late/expander.py @@ -1,5 +1,5 @@ # this converts a lowerer program into a vectorized program -import functools, itertools, operator +import functools, itertools from tinygrad.dtype import dtypes, PtrDType, AddrSpace from tinygrad.helpers import AMX, dedup, flatten, all_same, prod, partition from tinygrad.uop.ops import UOp, Ops, UPat, PatternMatcher, GroupOp, AxisType, range_start @@ -34,10 +34,7 @@ def do_expand(root:UOp): new_srcs = [] for i,src in enumerate(root.src): if src.op is Ops.UNROLL: - if root.op is Ops.IF and i == 0: - # IF means OR on first arg to IF - new_srcs.append(functools.reduce(operator.__or__, [src.src[0].gep(i) for i in range(expand_sz)])) - elif expand_args == src.arg: + if expand_args == src.arg: # just remove the expand new_srcs.append(src.src[0]) else: @@ -47,10 +44,7 @@ def do_expand(root:UOp): new_srcs.append(src.src[0].gep(tuple(lst))) else: # non-UNROLL input - if root.op is Ops.IF or src.op is Ops.IF: - # for the first arg of IF, just pass them through ignoring UNROLLS - new_srcs.append(src) - elif root.op in range_start and i >= range_start[root.op]: + if root.op in range_start and i >= range_start[root.op]: # for any range args of STORE/REDUCE, pass them through new_srcs.append(src) elif root.op is Ops.INDEX and i >= 1 and not isinstance(root.dtype, PtrDType): @@ -81,13 +75,27 @@ def do_contract(con:UOp): idxs += [_expand_arg_to_idx(ex.arg, {**rpk, **lrpk}) for lrpk in _choices_from_args(con.arg)] return UOp(Ops.UNROLL, con.dtype, (ex.src[0].gep(tuple(idxs)),), new_ex_args) +def end_unrolls(u:UOp): + unrolls, src = partition(u.src[1:], lambda x: x.op is Ops.UNROLL) + if not len(unrolls): return None + ret = UOp(Ops.CONTRACT, dtypes.void, (u.src[0],), sum([x.arg for x in unrolls], start=())) + return u.replace(src=(ret,)+tuple(src)) + expander = PatternMatcher([ + # push broadcast through AFTER + (UPat.var("x").broadcast(name="b").after(name="a", allow_any_len=True), lambda x,b,a: x.after(*a.src[1:]).broadcast(len(b.src))), + (UPat.var("x").broadcast(name="b").end(name="a", allow_any_len=True), lambda x,b,a: x.end(*a.src[1:]).broadcast(len(b.src))), + # END on UNROLL ends the UNROLL + (UPat(Ops.END, name="u"), end_unrolls), + # BUFFERIZE puts UNROLLs for ranges as contract + (UPat(Ops.BUFFERIZE, src=(UPat(Ops.UNROLL), UPat(Ops.UNROLL)), name="x"), + lambda x: x.replace(src=tuple(UOp(Ops.CONTRACT, dtype=s.dtype.vec(x.src[1].src[0].dtype.count), src=(s,), arg=x.src[1].arg) for s in x.src))), # double expand (UPat(Ops.UNROLL, name="outer", src=(UPat(Ops.UNROLL, name="inner"),)), lambda outer, inner: UOp(Ops.UNROLL, outer.dtype, (inner.src[0],), inner.arg+outer.arg)), # do expansion (UPat((*GroupOp.ALU, Ops.CAST, Ops.BITCAST, Ops.GEP, Ops.WMMA, Ops.LOAD, Ops.STORE, Ops.INDEX, Ops.BUFFERIZE, - Ops.VECTORIZE, Ops.IF, Ops.REDUCE), name="root", custom_early_reject=set([Ops.UNROLL])), do_expand), + Ops.VECTORIZE, Ops.REDUCE, Ops.END, Ops.AFTER), name="root", custom_early_reject=set([Ops.UNROLL])), do_expand), (UPat(Ops.CONTRACT, name="con"), do_contract), # BARRIERs aren't actually expanded (UPat(Ops.BARRIER, src=(UPat(Ops.UNROLL, name="ex"),)), @@ -99,22 +107,6 @@ expander = PatternMatcher([ lambda ex,x,y: UOp(Ops.UNROLL, ex.dtype, tuple((x+y).gep(i) for i in range(256 if AMX else 8)), ex.arg)), ]) -def create_gate(root:UOp) -> UOp|None: - @functools.cache - def _gate_srcs(u:UOp, gate:UOp) -> UOp: - if u.op is Ops.BARRIER: return u - if u.op is Ops.LOAD and u.src[-1].op is Ops.BARRIER: - return UOp(u.op, u.dtype, u.src[:-1]+(UOp(Ops.IF, src=(gate, u.src[-1])),), arg=u.arg) - return u if (replace_source:=tuple(_gate_srcs(x, gate) for x in u.src)) == u.src else UOp(u.op, u.dtype, replace_source, u.arg) - idx = root.src[0] - if idx.op is Ops.CAST: idx = idx.src[0] - return None if idx.op is not Ops.INDEX or len(idx.src) == 2 or (ret:=_gate_srcs(root, idx.src[2])) is root else ret - -migrate_indexing = PatternMatcher([ - # create gate MUST BE BEFORE expander - (UPat(Ops.STORE, name="root"), create_gate), -]) - # **** def fix_reduce_unroll(x:UOp): @@ -145,8 +137,7 @@ def fix_group_for_reduce(x:UOp): reduce_loop = [x.replace(arg=(x.arg[0]+100, AxisType.REDUCE)) for x in reduce_gfr] buf = ret.bufferize(*upstream_locals, *reduce_gfr, arg=BufferizeOpts(reduce_gfr[0].arg[0], AddrSpace.LOCAL)).index(*upstream_locals, *reduce_loop) - # gate with an if on the store + do the final reduce - buf = UOp(Ops.IF, dtype=buf.dtype, src=(functools.reduce(operator.and_, [x.eq(0) for x in reduce_gfr]), buf)) + # do the final reduce (if/barrier are added in gpudims step) return buf.reduce(*reduce_loop, arg=x.arg) pm_pre_expander = PatternMatcher([ diff --git a/tinygrad/codegen/late/linearize.py b/tinygrad/codegen/late/linearize.py deleted file mode 100644 index d860125adf..0000000000 --- a/tinygrad/codegen/late/linearize.py +++ /dev/null @@ -1,243 +0,0 @@ -from __future__ import annotations -import heapq -from collections import defaultdict -from dataclasses import dataclass, replace -from tinygrad.uop.ops import UOp, Ops, PatternMatcher, UPat, GroupOp, BottomUpGate -from tinygrad.helpers import dedup, all_same, flatten, BLOCK_REORDER - -# NOTE: any toposort should be valid here, unlike last time this isn't required, it's just for speed -def block_reorder(lst:list[UOp]) -> list[UOp]: - in_this_block = set(lst) - local_children: defaultdict[UOp, list[UOp]] = defaultdict(list) - in_degree:dict[UOp, int] = {} - priorities:dict[UOp, int] = {} - - # get local children and assign priorities - # NOTE: this requires the lst be locally toposorted - for u in reversed(lst): - in_degree[u] = 0 - for s in u.src: - if s in in_this_block: - local_children[s].append(u) - in_degree[u] += 1 - # put loads in the beginning of the block and prevent priority inversion. hack for BARRIER grouping too - priority = [0] + [priorities[x] for x in local_children[u]] - if u.op is Ops.LOAD: priority.append(-1000) - if u.op is Ops.BARRIER: priority.append(-1500) - priorities[u] = min(priority) - - # number the uops in "ideal" order - nkey = {u:i for i,u in enumerate(sorted(lst, key=lambda x: (priorities[x],)+x.tuplize))} - - # then force then to be toposorted in as close to the ideal order as possible - heapq.heapify(heap:=[(nkey[u],u) for u in lst if in_degree[u] == 0]) - newlst = [] - while heap: - newlst.append(u:=heapq.heappop(heap)[1]) - for v in local_children[u]: - in_degree[v] -= 1 - if in_degree[v] == 0: heapq.heappush(heap, (nkey[v],v)) - - assert len(newlst) == len(lst), f"len mismatch {len(newlst)} != {len(lst)}" - return newlst - -# ***** basic block ***** - -def disp(y:UOp) -> str: - if y.op is Ops.IF: return f'IF{id(y)}' - if y.op is Ops.RANGE: return str(y.arg) - return "" - -@dataclass(frozen=True, eq=False) -class BasicBlock: - lst: tuple[UOp, ...] - ctx: tuple[UOp, ...] = () - end: UOp|None = None - cnt: int = 0 - child_ctx: tuple[UOp, ...]|None = None - def __lt__(self, _:BasicBlock): raise RuntimeError("no comparing basic blocks") - def __repr__(self): - return f"{(str(disp(self.end))+' ') if self.end is not None else ''}"+f'f{self.cnt} '+\ - f"{[disp(y) for y in self.ctx]} {[disp(y) for y in self.child_ctx] if self.child_ctx is not None else '-'} "+\ - f"{len(self.lst)}" + "\n" + '\n'.join([str(x.op) for x in self.lst]) - def last_ctx(self): return self.child_ctx if self.child_ctx is not None else self.ctx - -def _sort_ctx(inp): return tuple(sorted(dedup(inp), key=lambda x: x.tuplize)) - -# ***** block context ***** - -@dataclass -class BlockContext: - child_count: dict[UOp, int] - block_ctxs: dict[UOp, tuple[UOp, ...]] - child_ctxs: dict[UOp, tuple[UOp, ...]] - def last_ctx(self, u): return self.child_ctxs.get(u, self.block_ctxs[u]) - @staticmethod - def from_sink(sink:UOp) -> BlockContext: - # get children and all block contexts - ctx = BlockContext({}, {}, {}) - for u in sink.toposort(gate=lambda u:u.op is not Ops.SPECIAL): - this_block_ctx: list[UOp] = [] - ctx.child_count[u] = 0 - - # get children and accumulate the last_ctx - for s in u.src: - if s.op is Ops.SPECIAL: continue - # NOTE: if a parent appears multiple times in the src, it counts multiple times as a child - ctx.child_count[s] += 1 - this_block_ctx += ctx.last_ctx(s) - - # save the block ctx. SINK never has anything - ctx.block_ctxs[u] = _sort_ctx(this_block_ctx) if u.op is not Ops.SINK else () - - # RANGE/IF add to the next ctx - # STORE/ASSIGN subtract from the next ctx - if u.op in {Ops.RANGE, Ops.IF}: ctx.child_ctxs[u] = _sort_ctx(ctx.block_ctxs[u] + (u,)) - elif u.op is Ops.STORE: ctx.child_ctxs[u] = tuple([y for y in ctx.block_ctxs[u] if y not in u.src]) - return ctx - -# ***** make blocks ***** - -DONT_PLACE_IN_BLOCK = {Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_REG, Ops.DEFINE_VAR, Ops.SPECIAL, Ops.CONST} - -def add_blockends(base_block:UOp, new_ctx:tuple[UOp, ...], current_ctx:tuple[UOp, ...], cnt:int=1) -> UOp: - ends_to_add = [z for z in new_ctx if z not in current_ctx] - while len(ends_to_add): - r:UOp = ends_to_add.pop(-1) - new_ctx = tuple([z for z in new_ctx if z is not r]) - end_uop = UOp(Ops.ENDIF if r.op is Ops.IF else Ops.ENDRANGE, src=(r,)) - base_block = UOp(Ops.BLOCKEND, src=(base_block,)*cnt, arg=BasicBlock((end_uop,), tuple(new_ctx), end=r, cnt=cnt)) - return base_block - -def make_block_bottom_up(ctx:BlockContext, x:UOp): - if x.op is Ops.BLOCKSTART: - current_ctx, child_ctx = x.arg - lst = list(x.src) - child_count = 1 - else: - current_ctx, child_count, child_ctx = ctx.block_ctxs[x], ctx.child_count[x], ctx.child_ctxs.get(x, None) - lst = [x] - - # count of times we've seen this block, or a seed for a new block if we can't merge it - unmergable: defaultdict[UOp, int] = defaultdict(int) - blockseeds = defaultdict(list) - - # add the srcs of this to the frontier - # NOTE: things may be in here multiple times, that's okay - frontier_nodes = list(flatten(y.src[::-1] for y in lst)) - while len(frontier_nodes): - u = frontier_nodes.pop(0) - if u.op not in DONT_PLACE_IN_BLOCK and ctx.child_count[u] == unmergable[u]+1: - # count is correct - if (newctx:=ctx.block_ctxs[u]) == current_ctx: - # block has same context, merge it, and put the srcs on the frontier - lst.append(u) - frontier_nodes.extend(u.src[::-1]) - else: - # block has different context, add it to blockseeds - blockseeds[(newctx, ctx.child_ctxs.get(u, None))].append(u) - del unmergable[u] - else: - # count is incorrect (or it's DONT_PLACE_IN_BLOCK), add it to unmergable - unmergable[u] += 1 - - # add unmergables to sources - srcs = [] - for u,cnt in unmergable.items(): srcs += [add_blockends(u, ctx.block_ctxs.get(u,()), current_ctx, cnt=cnt)]*cnt - - # add blockseeds, with blockends as needed - for (new_ctx, new_child_ctx), v in blockseeds.items(): - base_block = UOp(Ops.BLOCKSTART, src=tuple(v), arg=(new_ctx, new_child_ctx)) - srcs.append(add_blockends(base_block, new_ctx, current_ctx)) - - lst = lst[::-1] - if BLOCK_REORDER: lst = block_reorder(lst) - bb = BasicBlock(tuple(lst), ctx=current_ctx, cnt=child_count, child_ctx=child_ctx) - return UOp(Ops.BLOCK, src=tuple(srcs), arg=bb) - -# we prevent the source of the SPECIAL from being linearized since its not part of the kernel -def raise_bottom_up_gate(): raise BottomUpGate() - -block_create = PatternMatcher([ - (UPat(GroupOp.All-DONT_PLACE_IN_BLOCK.union({Ops.BLOCK, Ops.BLOCKEND}), name="x"), make_block_bottom_up), - (UPat(Ops.SPECIAL), raise_bottom_up_gate) -]) - -# ***** blockend merging **** - -def merge_blockends(sink:UOp) -> UOp|None: - # only run on the final BLOCK with the SINK in it - if sink.arg.lst[-1].op is not Ops.SINK: return None - # combine matching BLOCKENDS, the keys of this dictionary are the RANGE UOps, values are the BLOCKENDs - blockends_to_arg: dict[UOp, list[UOp]] = {} - for be in sink.toposort(): - if be.op is Ops.BLOCKEND: blockends_to_arg.setdefault(be.arg.end, []).append(be) - new_forks = {} - for k,v in blockends_to_arg.items(): - # NOTE: if any BLOCKEND is the parent of any other with the same arg, this algo fails - if len(v) > 1: - bb = BasicBlock(v[0].arg.lst, _sort_ctx(flatten([y.arg.ctx for y in v])), k, cnt=sum(y.arg.cnt for y in v)) - out = UOp(Ops.BLOCKEND, src=tuple(flatten([x.src for x in v])), arg=bb) - # NOTE: bb.ctx != u.arg.ctx can cause problems here - for u in v: new_forks[u] = out - if len(new_forks) == 0: return None - return sink.substitute(new_forks) - -pm_blockend_merge = PatternMatcher([(UPat(Ops.BLOCK, name="sink"), merge_blockends)]) - -# ***** block merging **** - -def merge_block(x:UOp): - unmergable_blocks, mergable_blocks = [], [] - mergable_dict: defaultdict[UOp, int] = defaultdict(int) - for y in x.src: - if y.op is Ops.BLOCK and x.op is Ops.BLOCK and x.arg.ctx == y.arg.ctx: mergable_dict[y] += 1 - elif y.op is Ops.BLOCK and x.op is Ops.BLOCKEND and x.arg.end in y.arg.ctx: mergable_dict[y] += 1 - else: unmergable_blocks.append(y) - for k,v in mergable_dict.items(): - if v == k.arg.cnt: mergable_blocks.append(k) - else: unmergable_blocks.extend([k]*v) - if len(mergable_blocks) == 0: return None - del mergable_dict - - # create the block - arg = replace(x.arg, lst=tuple(flatten([y.arg.lst for y in mergable_blocks]))+x.arg.lst) - return UOp(x.op, src=tuple(flatten([y.src for y in mergable_blocks])+unmergable_blocks), arg=arg) - -def remove_blockend(x:UOp): - # if there's any remaining blocks that need to go in this BLOCKEND, we don't remove it - if any(x.arg.end in y.arg.ctx for y in x.src if y.op in {Ops.BLOCK, Ops.BLOCKEND}): return None - - if (parent_blocks := [y for y in x.src if y.op is Ops.BLOCK and y.arg.child_ctx is not None and x.arg.end in y.arg.child_ctx]): - assert all_same(parent_blocks), f"should never have two parent blocks (has {len(parent_blocks)})" - parent_block = parent_blocks[0] - assert len(parent_blocks) == parent_block.arg.cnt - # NOTE: DEFINE_ACC doesn't have to be handled in any special way - late_ops = list(x.arg.lst) - # NOTE: we have to add a barrier at the start if barrier is used in the range - if x.op is Ops.BLOCKEND and any(y.op is Ops.BARRIER for y in late_ops) and late_ops[-1].op is Ops.ENDRANGE: - late_ops = [UOp(Ops.BARRIER)] + late_ops - # peephole opt, remove any BARRIERs next to each other - for i in range(len(late_ops)-1): - if late_ops[i].op is Ops.BARRIER and late_ops[i+1].op is Ops.BARRIER: late_ops[i+1] = UOp(Ops.NOOP) - arg = BasicBlock(parent_block.arg.lst+tuple(late_ops), tuple([y for y in x.arg.ctx if y is not x.arg.end]), cnt=x.arg.cnt) - return UOp(Ops.BLOCK, src=tuple(y for y in x.src if y is not parent_block)+parent_block.src, arg=arg) - # else the whole context ended by the blockend is already in this block and we can safely turn it into a block - return UOp(Ops.BLOCK, src=x.src, arg=BasicBlock(x.arg.lst, tuple([y for y in x.arg.ctx if y is not x.arg.end]), cnt=x.arg.cnt)) - -block_merge = PatternMatcher([ - (UPat((Ops.BLOCK, Ops.BLOCKEND), name="x"), merge_block), - (UPat(Ops.BLOCKEND, name="x"), remove_blockend), -]) - -# ****** finalize ****** - -def finalize(sink:UOp) -> UOp: - if sink.op is not Ops.BLOCK or not all(x.op in DONT_PLACE_IN_BLOCK for x in sink.src): - raise RuntimeError(f"linearize failure {sink.op} {[x.op for x in sink.src if x.op not in DONT_PLACE_IN_BLOCK]}") - - # place the early things - lst = sorted(dedup(sink.src), key=lambda x: x.tuplize) + list(sink.arg.lst) - return UOp(Ops.BLOCKFINAL, arg=BasicBlock(tuple(lst))) - -pm_finalize = PatternMatcher([(UPat(Ops.BLOCK, name="sink"), finalize)]) diff --git a/tinygrad/codegen/late/linearizer.py b/tinygrad/codegen/late/linearizer.py new file mode 100644 index 0000000000..6471ec76f1 --- /dev/null +++ b/tinygrad/codegen/late/linearizer.py @@ -0,0 +1,101 @@ +import heapq +from typing import Any +from collections import defaultdict +from tinygrad.uop.ops import PatternMatcher, UOp, Ops, UPat, multirange_str +from tinygrad.helpers import prod, getenv, TUPLE_ORDER + +def linearize(sink:UOp) -> list[UOp]: + # this is a toposort with priority + lst = list(sink.toposort()) + consumers: defaultdict[UOp, list[UOp]] = defaultdict(list) + in_degree:dict[UOp, int] = {} + out_degree:dict[UOp, int] = {} + priorities:dict[UOp, tuple[int, int, Any]] = {} + + # get consumers and assign priorities + # NOTE: this requires the lst be locally toposorted + for u in reversed(lst): + for s in u.src: consumers[s].append(u) + in_degree[u] = len(u.src) + out_degree[u] = len(consumers[u]) + + # we place UOps with higher run_counts later + run_count = prod([int(r.vmax)+1 for r in u.ranges]) + + # simple priority override. this is all bottom up now, smaller numbers will be closer to the top + extra = None + match u.op: + # the order and placement of these defines is important + case Ops.DEFINE_GLOBAL: priority, extra = -20, u.arg + case Ops.DEFINE_VAR: priority, extra = -19, u.arg + case Ops.DEFINE_LOCAL: priority = -18 + case Ops.DEFINE_REG: priority = -17 + case Ops.CONST: priority = -10 # early consts + case Ops.LOAD: priority = -1 # place loads early + case Ops.STORE: priority = 1 # place stores late + case Ops.RANGE: priority = 5 # placing RANGE is good + case Ops.END: priority = -5 # placing END is bad + case _: priority = 0 # everything else has priority 0 + priorities[u] = (run_count, priority, extra) + + # number the uops in "ideal" order + nkey = {u:i for i,u in enumerate(sorted(lst, key=lambda x: priorities[x]+(x.tuplize if TUPLE_ORDER else ())))} + + # then force them to be toposorted in as close to the ideal order as possible + heap = [(-nkey[sink], sink)] + newlst = [] + while heap: + newlst.append(u:=heapq.heappop(heap)[1]) + for v in u.src: + out_degree[v] -= 1 + if out_degree[v] == 0: heapq.heappush(heap, (-nkey[v],v)) + newlst = newlst[::-1] + + if getenv("DEBUG_LINEARIZE"): + for i,u in enumerate(newlst): + print(f"{i:4d} {str(u.op):20s} {multirange_str(u.ranges, color=True, pad=10)} {priorities[u]}") + return newlst + +class CFGContext: + def __init__(self, sink:UOp): + # there are 3 relationships between ranges: + # nested, meaning endrange y is a dependency of endrange x and range x is a dependency of endrange y + # dependent, meaning endrange y is a dependency of endrange x and range x is not a dependency of endrange y + # independent, endrange y is not a dependency of endrange x + # everything is nested inside the sink + deps: dict[UOp, dict[UOp, None]] = {} + nesting: dict[UOp, UOp] = {} + for u in sink.toposort(): + # get the deps from the src + deps[u] = {} + for s in u.src: deps[u] |= deps[s] + + if u.op in (Ops.END, Ops.SINK): + nesting |= {x:u for x in deps[u] if x.op is Ops.END and (u.op is Ops.SINK or u.src[1] in deps[x]) and x not in nesting} + if u.op in (Ops.RANGE, Ops.END): deps[u][u] = None + + self.edges: dict[UOp, UOp] = {} + siblings: dict[UOp, list[UOp]] = {} + for k,vv in nesting.items(): siblings.setdefault(vv, []).append(k) + for k,v in siblings.items(): + # ranges that have dependencies on other siblings need to be scheduled after them + order = sorted(v, key=lambda x: len([u for u in v if u in deps[x]])) + zipped = zip(order, order[1:]) if k.op is Ops.SINK else zip([k.src[1]] + order, order) + for x,y in zipped: + # TODO: this can happen! it causes infinite loop in shufflenet + assert y.src[1] not in x.backward_slice_with_self + self.edges[y.src[1]] = x + +pm_add_control_flow = PatternMatcher([ + (UPat(Ops.RANGE, name="x"), lambda ctx,x: x.replace(src=x.src+(y,)) if (y:=ctx.edges.get(x)) is not None else None), +]) + +def do_split_ends(e:UOp): + ret = e.src[0] + for r in sorted(UOp.sink(*e.src[1:]).ranges, key=lambda x: x.arg, reverse=True): ret = ret.end(r) + return ret + +pm_split_ends = PatternMatcher([ + # split the ends + (UPat(Ops.END, name="e"), do_split_ends), +]) \ No newline at end of file diff --git a/tinygrad/codegen/lowerer.py b/tinygrad/codegen/lowerer.py deleted file mode 100644 index 236aff36a4..0000000000 --- a/tinygrad/codegen/lowerer.py +++ /dev/null @@ -1,86 +0,0 @@ -# the job of the lowerer is to do indexing -from dataclasses import dataclass -from tinygrad.uop.ops import KernelInfo, UOp, Ops, PatternMatcher, UPat, sint_to_uop, AxisType, graph_rewrite, resolve - -# ***** indexing ***** - -@dataclass -class IndexContext: - axis_types: tuple[AxisType, ...] - idxs: list[UOp] - start: int = 0 - -def shape_to_idx(s, axis_types, start=0): - return [UOp.range(sint_to_uop(s), start+i, at) for i, (s, at) in enumerate(zip(s, axis_types))] - -def get_index(ast:UOp) -> IndexContext: - axis_types = ast.arg.axis_types if isinstance(ast.arg, KernelInfo) else () - 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)]) - return IndexContext(axis_types, [], 0) - -# ***** lowering (given index) ***** - -def subblock(ctx: IndexContext, full_new_idx: list[UOp], src: UOp): - lc = IndexContext(ctx.axis_types, full_new_idx, ctx.start+1000) - ctx.start = lc.start - return graph_rewrite(src, pm_lowerer, lc, name="subblock", bottom_up=True) - -def lower_reduce_axis(ctx: IndexContext, x: UOp): - new_idxs = shape_to_idx(x.src[0].shape, ctx.axis_types, ctx.start) - full_new_idx = list(ctx.idxs) - for a in x.axis_arg: full_new_idx[a] = new_idxs[a] - ret = subblock(ctx, full_new_idx, x.src[0]) - return UOp(Ops.REDUCE, x.dtype, (ret,)+tuple([full_new_idx[i] for i in x.axis_arg]), x.arg[0]) - -def lower_store(ctx: IndexContext, x: UOp, buf: UOp): - # TODO: reenable after REDUCE_AXIS is fixed - #assert x.src[1].shape == x.src[0].shape, f"shape mismatch on store {x.src[1].shape} != {x.src[0].shape}" - - new_idxs = shape_to_idx(x.src[0].shape, ctx.axis_types, ctx.start) - idx = x.st_arg.to_valid_uop(new_idxs) - used_idxs = [x for x in idx.toposort() if x in new_idxs] - real_new_idxs = [] - for i in range(len(x.src[0].shape)): - if new_idxs[i] in used_idxs or len(ctx.idxs) <= i: real_new_idxs.append(new_idxs[i]) - else: real_new_idxs.append(ctx.idxs[i]) - - stored = subblock(ctx, real_new_idxs, x.src[1]) - used_ranges = [x for x in used_idxs if x.op is Ops.RANGE] - return buf.index(idx).store(stored, *used_ranges) - -def fixup_wmma(ctx:IndexContext, x:UOp): - if x.tag is not None: return None - new_idxs = shape_to_idx(x.src[0].shape, ctx.axis_types, ctx.start) - full_new_idx = list(ctx.idxs) - for a in x.arg[-1]: full_new_idx[a] = new_idxs[a] - - srcs = subblock(ctx, full_new_idx, UOp.sink(*x.src)).src - - # NOTE: this assumes these are expanded. which now shouldn't change anything - new_x_arg_m2 = tuple([tuple([(full_new_idx[a].arg[0], sz) for a,sz in v]) for v in x.arg[-2]]) - new_x_arg_m1 = tuple([full_new_idx[a].arg[0] for a in x.arg[-1]]) - return x.replace(src=srcs, arg=x.arg[:-2]+(new_x_arg_m2, new_x_arg_m1), tag=1) - -pm_lowerer = PatternMatcher([ - # TODO: remove these hacks - # hack for old style CONST(VIEW) (now it's just VIEW(CONST)) - (UPat((Ops.DEFINE_VAR, Ops.CONST), src=(UPat(Ops.VIEW, name="v"),), name="c"), lambda c,v: c.replace(src=()).view(v.arg)), - # hack for old style VALID (now it's just VIEW(CONST)) - (UPat(Ops.VALID, src=(UPat(Ops.VIEW, name="v"),)).where(UPat.cvar("c"), UPat(Ops.CONST, arg=0)), lambda c,v: c.replace(src=()).view(v.arg)), - - # consts and loads - (UPat(Ops.VIEW, src=(UPat((Ops.CONST, Ops.DEFINE_VAR), name="c"),), name="view"), - lambda ctx,view,c: c if all(x.mask is None for x in view.arg.views) else view.arg.to_valid_uop(ctx.idxs).get_valid().where(c, c.const_like(0))), - (UPat(Ops.LOAD, src=(UPat.var("buf").view(),), allow_any_len=True, name="x"), - lambda ctx,buf,x: UOp(Ops.LOAD, x.dtype, (buf.index(x.st_arg.to_valid_uop(ctx.idxs)),)+x.src[1:])), - - # reduce/view_const - (UPat(Ops.REDUCE_AXIS, name="x"), lower_reduce_axis), - (UPat(Ops.STORE, src=(UPat.var("buf").view(),), allow_any_len=True, name="x"), lower_store), - (UPat(Ops.WMMA, name="x"), fixup_wmma), - - # axis fixups for WMMA - (UPat((Ops.CONTRACT, Ops.UNROLL), name="x"), - lambda ctx,x: x.replace(tag=1, arg=tuple([(ctx.idxs[a].arg[0], sz) for a,sz in x.arg])) if x.tag is None else None), -]) diff --git a/tinygrad/codegen/opt/__init__.py b/tinygrad/codegen/opt/__init__.py index a47d785b5a..fb4b84ddee 100644 --- a/tinygrad/codegen/opt/__init__.py +++ b/tinygrad/codegen/opt/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations from enum import Enum, auto from dataclasses import dataclass -from tinygrad.uop.ops import AxisType class OptOps(Enum): TC = auto(); UPCAST = auto(); UNROLL = auto(); LOCAL = auto(); THREAD = auto() # noqa: E702 @@ -16,11 +15,6 @@ class Opt: arg: int|tuple|None = None def __repr__(self): return f"Opt(op={self.op}, axis={self.axis}, arg={self.arg})" -axis_letters = {AxisType.GLOBAL: "g", AxisType.THREAD: "t", AxisType.LOCAL: "l", AxisType.WARP: "w", AxisType.LOOP: "L", AxisType.UPCAST: "u", - AxisType.GROUP_REDUCE: "G", AxisType.REDUCE: "R", AxisType.UNROLL: "r"} -axis_colors = {AxisType.GLOBAL: "blue", AxisType.THREAD: "BLUE", AxisType.LOCAL: "cyan", AxisType.WARP: "CYAN", AxisType.LOOP: "WHITE", - AxisType.UPCAST: "yellow", AxisType.GROUP_REDUCE: "green", AxisType.REDUCE: "red", AxisType.UNROLL: "magenta"} - class KernelOptError(Exception): pass def check(cond:bool, msg:str=""): if not cond: raise KernelOptError(msg) diff --git a/tinygrad/codegen/opt/heuristic.py b/tinygrad/codegen/opt/heuristic.py index c1c69ef498..2bbcffd4f3 100644 --- a/tinygrad/codegen/opt/heuristic.py +++ b/tinygrad/codegen/opt/heuristic.py @@ -27,15 +27,15 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # NOTE: unless TC_OPT is > 0, we only trigger tensor cores if there's only one reduce axis if USE_TC > 0 and (len(k.axes_of(AxisType.GROUP_REDUCE, AxisType.REDUCE)) == 1 or (TC_OPT.value >= 1)): good_tc_opt = False + tk = k.copy() try: # check TC first and apply hand-coded opts if successful - tk = k.copy() rngs = tk.apply_opt(Opt(OptOps.TC, 0, (TC_SELECT.value, TC_OPT.value, USE_TC.value))) good_tc_opt = True except KernelOptError: pass - if good_tc_opt: - # skip hand-coded TC opts if AMX, upcasting will make kernel slower - if rngs is not None and not AMX: + # skip hand-coded TC opts if AMX, upcasting will make kernel slower + if good_tc_opt and not AMX: + if rngs is not None: for tc_dim in [1,0]: # attempt to upcast M and N szs = [sz for sz in [5,4,3,2] if rngs[tc_dim].src[0].divides(sz) is not None] if szs: @@ -51,7 +51,7 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # upcast float4 images, this must be early so we don't accidentally add locals before the upcast for buf_index,buf in enumerate(k.bufs): if isinstance(buf.src[0].dtype, ImageDType): - # part of real_strides + # part of is_expanded unit_stride_axes_mul_4 = [k.rngs.index(c) for c in k.bufs[buf_index].src[1].get_idx().split_uop(Ops.ADD) if c.op is Ops.RANGE and (c.vmax+1)%4 == 0] if len(unit_stride_axes_mul_4): @@ -62,10 +62,10 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # should use matvec - TODO: adjust/tune based on the wide vs tall/large vs small mat MV_BLOCKSIZE, MV_THREADS_PER_ROW, MV_ROWS_PER_THREAD = getenv("MV_BLOCKSIZE", 4), getenv("MV_THREADS_PER_ROW", 8), getenv("MV_ROWS_PER_THREAD", 4) - if k.opts.has_local and getenv("MV",1) != 0 and (MV_BLOCKSIZE > 1 or MV_THREADS_PER_ROW > 1 or MV_ROWS_PER_THREAD > 1) and \ - k.reduceop is not None and k.reduceop.arg[0] is Ops.ADD and len(k.full_shape) >= 2 and k.opts.has_shared and \ - (mulop:=k.reduceop.src[0]).op is Ops.MUL and mulop.src[0].op is Ops.LOAD and mulop.src[1].op is Ops.LOAD: - idx0, idx1 = mulop.src[0].src[0].src[1].get_idx(), mulop.src[1].src[0].src[1].get_idx() + if k.ren.has_local and getenv("MV",1) != 0 and (MV_BLOCKSIZE > 1 or MV_THREADS_PER_ROW > 1 or MV_ROWS_PER_THREAD > 1) and \ + k.reduceop is not None and k.reduceop.arg[0] is Ops.ADD and len(k.full_shape) >= 2 and k.ren.has_shared and \ + (mulop:=k.reduceop.src[0]).op is Ops.MUL and mulop.src[0].op is Ops.INDEX and mulop.src[1].op is Ops.INDEX: + idx0, idx1 = mulop.src[0].src[1].get_idx(), mulop.src[1].src[1].get_idx() if k.ranges_of(AxisType.REDUCE): first_reduce_rng = k.ranges_of(AxisType.REDUCE)[0] if any(u is first_reduce_rng for u in idx0.split_uop(Ops.ADD)) and all(r in idx1.ranges for r in idx0.ranges): @@ -73,16 +73,18 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: if first_reduce_rng.src[0].divides(MV_THREADS_PER_ROW) is not None and k.full_shape[global_idx]%(MV_BLOCKSIZE*MV_ROWS_PER_THREAD) == 0: if DEBUG >= 3: print(f"MATVEC: {k.full_shape=} {first_reduce_rng.render()} {MV_BLOCKSIZE=} {MV_THREADS_PER_ROW=} {MV_ROWS_PER_THREAD=}") - if MV_THREADS_PER_ROW > 1: k.apply_opt(Opt(OptOps.GROUP, 0, MV_THREADS_PER_ROW)) + try: + if MV_THREADS_PER_ROW > 1: k.apply_opt(Opt(OptOps.GROUP, 0, MV_THREADS_PER_ROW)) + except KernelOptError: pass if MV_BLOCKSIZE > 1: k.apply_opt(Opt(OptOps.LOCAL, global_idx, MV_BLOCKSIZE)) if MV_ROWS_PER_THREAD > 1: k.apply_opt(Opt(OptOps.UPCAST, global_idx, MV_ROWS_PER_THREAD)) return k # are we grouping? (requires local shape support) - if resolve(prod(k.output_shape[i] for i in k.upcastable_dims) <= 2048, False): - for sz in [16]: + if resolve(prod(k.output_shape[i] for i in k.upcastable_dims) <= (240 if NOLOCALS else 2048), False): + for axis, sz in itertools.product((0, 1, 2), (16,)): try: - k.apply_opt(Opt(OptOps.GROUPTOP, 0, sz)) + k.apply_opt(Opt(OptOps.GROUPTOP, axis, sz)) break except KernelOptError: pass @@ -96,28 +98,28 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # upcast leading axes first (hack-ish for winograd; we actually want to upcast masked axes with low stride first) for axis in k.upcastable_dims: # for Schedule, we check if the range is used in INDEX gates or WHERE gates - is_masked = any(any(o is k.rngs[axis] for o in u.src[0].parents) for u in k.ast.parents if u.op is Ops.WHERE) + is_masked = any(any(o is k.rngs[axis] for o in u.src[0].backward_slice) for u in k.ast.backward_slice if u.op is Ops.WHERE) if k.full_shape[axis] <= 7 and is_masked and prod(k.full_shape[j] for j in to_upcast) * k.full_shape[axis] <= 7 * 7: if DEBUG >= 4: print(f"upcasting masked axis : {axis}") to_upcast.append(axis) for axis in to_upcast[::-1]: k.apply_opt(Opt(OptOps.UPCAST, axis, 0)) # potentially do more upcasts of non reduce axes based on a heuristic - is_dsp = k.opts is not None and k.opts.device == "DSP" + is_dsp = k.ren is not None and k.ren.device == "DSP" upcasted_axis: set[int] = set() - while resolve(prod(k.output_shape[i] for i in k.upcastable_dims) >= 1024): + while resolve(prod(k.output_shape[i] for i in k.upcastable_dims) >= 1024) and (k.upcast_size() < 32): xb_choices = [] # consider all upcastable axes with 3 or 4 upcast (128 on the DSP) for axis, upcast_amount in itertools.product(k.upcastable_dims, ([128] if not len(upcasted_axis) else []) if is_dsp else [3,4]): # if we haven't upcasted it, it mods, and buffer has stride 0 on axis while having no stride 0 in the upcasted axis already if axis in upcasted_axis or k.full_shape[axis]%upcast_amount != 0: continue rng = k.rngs[axis] - if any(rng not in b.src[1].get_idx().parents and all(r2 in b.src[1].get_idx().parents + if any(rng not in b.src[1].get_idx().backward_slice and all(r2 in b.src[1].get_idx().backward_slice for r2 in k.ranges_of(AxisType.UPCAST, AxisType.UNROLL)) for b in k.bufs): num_strides, sum_strides = 0, 0 for b in k.bufs: idx = b.src[1].get_idx() - if rng in idx.parents: num_strides += 1 + if rng in idx.backward_slice: num_strides += 1 for c in idx.split_uop(Ops.ADD): if c is rng: sum_strides += 1 if c.op is Ops.MUL and c.src[0] is rng and c.src[1].op is Ops.CONST: sum_strides += c.src[1].arg @@ -133,8 +135,7 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # if last reduce dim is small(ish), loop unroll the reduce # NOTE: this can fail on multireduce with mismatching dimensions, this is okay try: - upcast_size = prod(k.full_shape[a] for a in k.axes_of(AxisType.UPCAST, AxisType.UNROLL)) - if k.unrollable_dims and (upcast_size <= 4 or not k.axes_of(AxisType.UNROLL)) and (upcast_size < 64): + if k.unrollable_dims and (k.upcast_size() <= 4 or not k.axes_of(AxisType.UNROLL)) and (k.upcast_size() < 64): if (s:=k.full_shape[k.unrollable_dims[-1]]) <= 32: k.apply_opt(Opt(OptOps.UNROLL, len(k.unrollable_dims)-1, 0)) # if it's small, upcast a second reduce dimension too @@ -149,18 +150,17 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # if nothing at all is upcasted and it's easy to, do an upcast for splits in [4]: - # TODO: somehow this never hits a reduce if not k.upcasted and k.upcastable_dims and k.full_shape[k.upcastable_dims[-1]] % splits == 0: k.apply_opt(Opt(OptOps.UPCAST, k.upcastable_dims[-1], splits)) # **** local groups **** - if k.opts.has_local: + if k.ren.has_local: if NOLOCALS: k.apply_opt(Opt(OptOps.NOLOCALS)) else: # prioritize making expand axes local - local_axis_ranking = [(any(k.rngs[axis] not in b.src[1].get_idx().parents for b in k.bufs), axis) \ + local_axis_ranking = [(any(k.rngs[axis] not in b.src[1].get_idx().backward_slice for b in k.bufs), axis) \ for axis in k.axes_of(AxisType.GLOBAL, AxisType.LOOP) if k.rngs[axis].src[0].op is Ops.CONST] to_local: list[tuple[int, int]] = [] for _, axis in sorted(local_axis_ranking, key=lambda x: (-x[0], -x[1])): @@ -176,13 +176,14 @@ def hand_coded_optimizations(k:Scheduler) -> Scheduler: # **** threading **** - if k.opts.has_threads and k.opts.global_max is not None: + if k.ren.has_threads and k.ren.global_max is not None: for threads in [32,16,12,8,6,5,4,3,2]: - # Skip is too many threads. Heuristic: use about 128K ops per thread - if threads > k.opts.global_max[0] or resolve(prod(k.full_shape) // (128 << 10) < threads): continue + # Skip if too many threads. Heuristic: use about 128K ops per thread + if threads > k.ren.global_max[0] or resolve(prod(k.full_shape) // (128 << 10) < threads): continue for axis in k.axes_of(AxisType.LOOP): if k.full_shape[axis] % threads == 0: - k.apply_opt(Opt(OptOps.THREAD, axis, threads)) + try: k.apply_opt(Opt(OptOps.THREAD, axis, threads)) + except KernelOptError: pass break if k.applied_opts and k.applied_opts[-1].op is OptOps.THREAD: break diff --git a/tinygrad/codegen/opt/postrange.py b/tinygrad/codegen/opt/postrange.py index c1a2448ad6..f23445578a 100644 --- a/tinygrad/codegen/opt/postrange.py +++ b/tinygrad/codegen/opt/postrange.py @@ -2,11 +2,11 @@ from __future__ import annotations import math, itertools from collections import defaultdict from typing import cast, Final -from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, KernelInfo, graph_rewrite, AxisType, ssimplify, can_pad, GroupOp +from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, KernelInfo, graph_rewrite, AxisType, ssimplify, GroupOp, axis_letters, axis_colors from tinygrad.device import Buffer -from tinygrad.dtype import AddrSpace, dtypes, ImageDType -from tinygrad.helpers import colored, BEAM, getenv, DEBUG, to_function_name, NOOPT, argsort, round_up, prod, merge_dicts, get_single_element -from tinygrad.codegen.opt import axis_colors, Opt, OptOps, KernelOptError, check, axis_letters +from tinygrad.dtype import dtypes, ImageDType +from tinygrad.helpers import colored, BEAM, getenv, DEBUG, to_function_name, NOOPT, argsort, round_up, prod, merge_dicts, get_single_element, flatten +from tinygrad.codegen.opt import Opt, OptOps, KernelOptError, check from tinygrad.codegen.simplify import pm_flatten_range from tinygrad.renderer import Renderer @@ -17,15 +17,15 @@ axis_to_pos = {AxisType.LOOP: -1, AxisType.THREAD: 0, AxisType.GLOBAL: 0, AxisTy AxisType.GROUP_REDUCE: 2, AxisType.REDUCE: 4, AxisType.UNROLL: 5} class Scheduler: - def __init__(self, ast:UOp, opts:Renderer): - self.ast, self.opts = ast, opts + def __init__(self, ast:UOp, ren:Renderer): + self.ast, self.ren = ast, ren self.dont_use_locals = self.ast.arg.dont_use_locals if self.ast.arg is not None else False self.applied_opts = list(self.ast.arg.applied_opts) if self.ast.arg is not None else [] @property def rngs(self): # always in order by axistype - return sorted([u for u in self.ast.parents if u.op is Ops.RANGE and u.vmax > 0], key=lambda x: (axis_to_pos[x.arg[-1]],) + x.arg[0:-1]) + return sorted([u for u in self.ast.backward_slice if u.op is Ops.RANGE and u.vmax > 0], key=lambda x: (axis_to_pos[x.arg[-1]],) + x.arg[0:-1]) @property def shape_len(self): return len(self.rngs) @property @@ -46,7 +46,7 @@ class Scheduler: def shape_str_to_axis(self, nms:list[str]) -> tuple[int, ...]: return tuple([self.shape_str().index(x) for x in nms]) def copy(self): - ret = Scheduler(self.ast, self.opts) + ret = Scheduler(self.ast, self.ren) ret.dont_use_locals = self.dont_use_locals ret.applied_opts = self.applied_opts[:] return ret @@ -63,32 +63,34 @@ class Scheduler: self.ast = graph_rewrite(self.ast, pm_flatten_range, name="flatten range") return self.ast.replace(arg=KernelInfo(name=name, applied_opts=tuple(self.applied_opts), dont_use_locals=self.dont_use_locals), tag=1) + def _output_rngs(self) -> list[UOp]: + return flatten([[r for r in UOp.sink(*s.src[1:]).ranges if r.arg[-1] != AxisType.REDUCE] for s in self.ast.src if s.op is Ops.END]) def _globalizable_rngs(self) -> list[UOp]: - 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].ptrdtype.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]) - - # filter any not in reduces - # TODO: enable this - """ - reduce_rngs = [x.ranges for x in self.ast.toposort() if x.op is Ops.REDUCE] - for ls in reduce_rngs: store_rngs = tuple([x for x in store_rngs if x in ls]) - """ - - return [x for x in UOp.sink(*store_rngs).toposort() if x.op is Ops.RANGE and x.arg[-1] == AxisType.LOOP] if store_rngs else [] + ret = [r for r in self._output_rngs() if r.arg[-1] == AxisType.LOOP] + # exclude any output ranges from global that don't appear in all BUFFERIZE + for x in self.ast.toposort(): + if x.op is Ops.BUFFERIZE: + ret = [r for r in ret if r in x.ranges] + return ret def convert_loop_to_global(self): - if not self.opts.has_local: return None + if not self.ren.has_local: return None globalizible_rngs = self._globalizable_rngs() rng = [x.replace(arg=x.arg[0:-1]+(AxisType.GLOBAL,)) if x in globalizible_rngs else x for x in self.rngs] self.ast = self.ast.substitute(dict(zip(self.rngs, rng))) - def colors(self) -> list[str]: return [axis_colors[x] if not self.dont_use_locals or not x == AxisType.GLOBAL else "BLUE" for x in self.axis_types] + def colors(self) -> list[str]: + output_rngs = self._output_rngs() + globalizible_rngs = self._globalizable_rngs() + ret = [] + for x,r in zip(self.axis_types, self.rngs): + if self.dont_use_locals and x == AxisType.GLOBAL: ret.append("BLUE") + elif r not in output_rngs and x == AxisType.LOOP: ret.append("BLACK") + elif r not in globalizible_rngs and x == AxisType.LOOP: ret.append("white") + else: ret.append(axis_colors[x]) + return ret def colored_shape(self) -> str: return ' '.join([colored(f'{x.src[0].render():>4s}', color) for x,color in zip(self.rngs, self.colors())]) def shift_to(self, rng:UOp, amount:int, new_type:AxisType, top:bool=False, input_new_rng=None): @@ -97,12 +99,14 @@ class Scheduler: new_rng = UOp.range(amount, self.maxarg+1, new_type) if input_new_rng is None else input_new_rng replaced_rng = rng.replace(src=(UOp.const(dtypes.int, old_sz),)) sub_axis = (new_rng * old_sz + replaced_rng) if top else (replaced_rng * amount + new_rng) - self.ast = self.ast.substitute({rng:sub_axis}, name=f"shift {rng.arg[0]} {amount} {str(new_type).split('.')[1].lower()}") + self.ast = self.ast.substitute({rng:sub_axis}, name=f"shift {rng.arg[:-1]} {amount} {str(new_type).split('.')[1].lower()}") return replaced_rng, new_rng def ranges_of(self, *axis_type:AxisType) -> list[UOp]: return [r for r in self.rngs if r.arg[-1] in axis_type] def axes_of(self, *axis_type:AxisType) -> list[int]: return [i for i,t in enumerate(self.axis_types) if t in axis_type] + def upcast_size(self) -> int: return prod(self.full_shape[a] for a in self.axes_of(AxisType.UPCAST, AxisType.UNROLL)) + # copied from kernel.py @property def upcastable_dims(self) -> list[int]: return [i for i in self.axes_of(AxisType.GLOBAL, AxisType.LOCAL, AxisType.LOOP) \ @@ -128,7 +132,7 @@ class Scheduler: return if opt.op in {OptOps.LOCAL, OptOps.GROUP, OptOps.GROUPTOP}: - check(self.opts.has_local, "locals needed for opt") + check(self.ren.has_local, "locals needed for opt") rng = self.rngs[real_axis] if (real_axis:=self.real_axis(opt.op, opt.axis)) >= 0 else UOp(Ops.NOOP) @@ -146,10 +150,10 @@ class Scheduler: (self.group_for_reduces and opt.op not in {OptOps.NOLOCALS, OptOps.PADTO})): upcast_local_sz = prod([self.full_shape[a] for a in self.axes_of(AxisType.UPCAST, AxisType.WARP, AxisType.LOCAL, AxisType.GROUP_REDUCE)]) smem_sz = amt*upcast_local_sz*self.reduceop.dtype.itemsize - check(smem_sz <= self.opts.shared_max, f"exceeds maximum shared memory size: needs {smem_sz}, max {self.opts.shared_max}") + check(smem_sz <= self.ren.shared_max, f"exceeds maximum shared memory size: needs {smem_sz}, max {self.ren.shared_max}") if self.reduceop is not None and (opt.op in {OptOps.GROUP, OptOps.GROUPTOP}): # We currently dont support a group within another rudece, TODO: fix if-contexts - reduce = [u for u in self.ast.parents if u.op is Ops.REDUCE and rng in merge_dicts([r.ranges for r in u.src[1:]])][0] + reduce = [u for u in self.ast.backward_slice if u.op is Ops.REDUCE and rng in merge_dicts([r.ranges for r in u.src[1:]])][0] check(not any(u.arg[-1] in (AxisType.REDUCE, AxisType.UNROLL, AxisType.GROUP_REDUCE) for u in reduce.ranges), "cannot have a GROUP_REDUCE inside another reduce") @@ -157,14 +161,14 @@ class Scheduler: check(amt <= 32, "don't unroll more than 32") check(rng.arg[-1] in {AxisType.GROUP_REDUCE, AxisType.REDUCE}, "unroll is for GROUP_REDUCE/REDUCE") if opt.op is OptOps.UPCAST: - check((self.opts is not None and self.opts.device == "DSP") or amt <= 16, "don't upcast more than 16") + check((self.ren is not None and self.ren.device == "DSP") or amt <= 16, "don't upcast more than 16") check(rng.arg[-1] in {AxisType.GLOBAL, AxisType.LOCAL, AxisType.LOOP}, f"upcast is for GLOBAL/LOCAL/LOOP, not {rng.arg[-1]}") if opt.op is OptOps.LOCAL: check(not self.dont_use_locals, "can't use locals") check(rng.arg[-1] in {AxisType.GLOBAL, AxisType.LOOP}, "local is for globals") if opt.op is OptOps.THREAD: - check(self.opts is not None and self.opts.has_threads, "target does not support threads") - check(self.opts is not None and self.opts.global_max is not None and amt <= self.opts.global_max[0], "too many threads") + check(self.ren is not None and self.ren.has_threads, "target does not support threads") + check(self.ren is not None and self.ren.global_max is not None and amt <= self.ren.global_max[0], "too many threads") check(all(x is not AxisType.THREAD for x in self.axis_types), "already threaded") check(rng in self._globalizable_rngs(), "can't apply range to this dim") if opt.op in {OptOps.GROUP, OptOps.GROUPTOP}: @@ -176,7 +180,7 @@ class Scheduler: check(len(self.applied_opts) == 0, "tensor core opts must be first") # TODO: remove the need for this by having warps check(opt.axis is not None, "tensor core opts must have an axis") check(opt.arg is not None and isinstance(opt.arg, tuple) and len(opt.arg) == 3, "tensor core opts must have valid arg") - check(-1 <= (tc_select:=cast(tuple, opt.arg)[0]) < len(self.opts.tensor_cores), "tensor core opts must have valid tc_select") + check(-1 <= (tc_select:=cast(tuple, opt.arg)[0]) < len(self.ren.tensor_cores), "tensor core opts must have valid tc_select") check(0 <= (tc_opt:=cast(tuple, opt.arg)[1]) <= 2, "tensor core opts must have valid tc_opt") check(0 < (use_tensor_cores:=cast(tuple, opt.arg)[2]) <= 2, "use_tensor_cores value is not valid") try: ret = self._apply_tc_opt(use_tensor_cores, cast(int, opt.axis), tc_select, tc_opt) @@ -188,25 +192,26 @@ class Scheduler: check(rng.arg[-1] is not AxisType.THREAD, "cannot pad thread") # ok to pad SUM if all parent ALU ops have f(0) = 0 if (r:=self.reduceop) is not None and rng.arg[-1] in (AxisType.GROUP_REDUCE, AxisType.REDUCE): - check(r.arg[0] is Ops.ADD and can_pad(r, {}), f"cannot pad {r}") + check(r.arg[0] is Ops.ADD and not r.op_in_backward_slice_with_self(*GroupOp.UnsafePad), f"cannot pad {r}") new_sz = round_up(int(rng.vmax+1), cast(int, opt.arg)) check(rng.vmax+1 > new_sz//4, "pad adds more than quadruple the work") replaced_rng = UOp.range(new_sz, *rng.arg) replaces = {rng:replaced_rng} valid = replaced_rng < rng.vmax+1 for b in self.bufs: - if rng in (i:=b.src[1].get_idx()).sparents: + if rng in (i:=b.src[1].get_idx()).backward_slice_with_self: replaces[b] = b.replace(src=(b.src[0],(valid&b.src[1].get_valid()).where(i, UOp.invalid()))) self.ast = self.ast.substitute(replaces, f"padto {rng.arg[:-1]} {opt.arg}") elif opt.op is OptOps.SWAP: try: - altrng = self.rngs[opt.arg] + altrng:UOp = self.rngs[opt.arg] except IndexError: raise KernelOptError check(rng.arg[-1] == AxisType.GLOBAL and altrng.arg[-1] == AxisType.GLOBAL, "swap only for globals") self.ast = self.ast.substitute({rng:rng.replace(arg=(*altrng.arg[0:-1], rng.arg[-1]), tag=1), - altrng:altrng.replace(arg=(*rng.arg[0:-1], altrng.arg[-1]), tag=1)}) - self.ast = graph_rewrite(self.ast, remove_tags) + altrng:altrng.replace(arg=(*rng.arg[0:-1], altrng.arg[-1]), tag=1)}, + name=f"swap {rng.arg[:-1]} {altrng.arg[:-1]}") + self.ast = graph_rewrite(self.ast, remove_tags, name="swap remove tags") else: raise KernelOptError(f"unsupported opt {opt.op}") @@ -214,15 +219,14 @@ class Scheduler: return ret def _apply_tc_opt(self, use_tensor_cores:int, axis:int, tc_select:int, opt_level:int) -> None|list[UOp]: - 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") + if not (reduceops := self.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 None in0, in1 = mul.src try: - tensor_cores = self.opts.tensor_cores if tc_select == -1 else [self.opts.tensor_cores[tc_select]] + tensor_cores = self.ren.tensor_cores if tc_select == -1 else [self.ren.tensor_cores[tc_select]] except IndexError: raise KernelOptError(f"invalid tensor core choice {tc_select}") for tc in tensor_cores: @@ -293,7 +297,7 @@ class Scheduler: # TODO: remove tc_upcast_axes from the arg # do the reduce_axes always disappear? i think they don't # they need to be moved into the WMMA srcs - wmma_arg = (str(tc), tc.dims, tc.dtype_in, tc.dtype_out, self.opts.device, tc.threads, tc_upcast_axes, ()) #, tc_reduce_axes) + wmma_arg = (str(tc), tc.dims, tc.dtype_in, tc.dtype_out, self.ren.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), @@ -309,9 +313,10 @@ class Scheduler: # helpers for hand_coded_optimizations @property + def reduceops(self) -> list[UOp]: return [x for x in self.ast.backward_slice if x.op is Ops.REDUCE] + @property def reduceop(self) -> UOp|None: - red = [x for x in self.ast.parents if x.op is Ops.REDUCE] - if not len(red): return None + if not (red := self.reduceops): return None return UOp(Ops.REDUCE_AXIS, red[0].dtype, red[0].src, (red[0].arg, ())) @property def bufs(self) -> list[UOp]: return [x for x in self.ast.toposort() if x.op is Ops.INDEX][::-1] @@ -324,26 +329,22 @@ class Scheduler: def group_for_reduces(self) -> int: return len(self.axes_of(AxisType.GROUP_REDUCE)) 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) + glbls = sorted([x for x in ast.backward_slice if x.op is Ops.DEFINE_GLOBAL], key=lambda x: x.arg) return [Buffer(dname, x.ptrdtype.size, x.dtype.base if not isinstance(x.dtype, ImageDType) else x.dtype) for x in glbls] -def apply_opts(ctx:Renderer, ast:UOp): - if ast.tag is not None: return None - k = Scheduler(ast, ctx) +def apply_opts(ast:UOp, ren:Renderer) -> UOp: + if ast.tag is not None: return ast + k = Scheduler(ast, ren) k.convert_loop_to_global() if ast.arg is not None and ast.arg.opts_to_apply is not None: for opt in ast.arg.opts_to_apply: k.apply_opt(opt) elif BEAM >= 1: from tinygrad.codegen.opt.search import beam_search - rawbufs = bufs_from_ast(ast, ctx.device) + rawbufs = bufs_from_ast(ast, ren.device) k = beam_search(k, rawbufs, BEAM.value, bool(getenv("BEAM_ESTIMATE", 1))) elif not NOOPT and (ast.arg is None or ast.arg.applied_opts == ()): from tinygrad.codegen.opt.heuristic import hand_coded_optimizations # NOTE: hand_coded_optimizations doesn't support multiblock opts yet - if all(len(u.src) == 1 for u in ast.parents if u.op is Ops.LOAD): + if not any(u.op is Ops.BUFFERIZE for u in ast.backward_slice): k = hand_coded_optimizations(k) return k.get_optimized_ast(name_override=ast.arg.name if ast.arg is not None and ast.arg.name != "test" else None) - -pm_postrange_opt = PatternMatcher([ - (UPat(Ops.SINK, name="ast"), apply_opts), -]) diff --git a/tinygrad/codegen/opt/search.py b/tinygrad/codegen/opt/search.py index b5c3a1ebce..20e45c9a46 100644 --- a/tinygrad/codegen/opt/search.py +++ b/tinygrad/codegen/opt/search.py @@ -1,9 +1,8 @@ -from typing import cast import functools, math, time, multiprocessing, traceback, signal, atexit from dataclasses import replace from tinygrad.uop.ops import sym_infer, AxisType, pyrender from tinygrad.device import Device, Buffer, Compiler -from tinygrad.helpers import prod, flatten, DEBUG, CACHELEVEL, diskcache_get, diskcache_put, getenv, Context, colored, time_to_str +from tinygrad.helpers import prod, flatten, DEBUG, CACHELEVEL, diskcache_get, diskcache_put, getenv, Context, colored, time_to_str, unwrap from tinygrad.helpers import IGNORE_BEAM_CACHE from tinygrad.codegen.opt import Opt, OptOps, KernelOptError from tinygrad.tensor import Tensor @@ -50,7 +49,7 @@ def _time_program(p:ProgramSpec, lib:bytes, var_vals:dict[str, int], rawbufs:lis if hasattr(dev:=Device[p.device], 'invalidate_caches'): dev.invalidate_caches() else: with Context(DEBUG=0, BEAM=0, CAPTURING=0, TRACK_MATCH_STATS=0): Tensor.ones(1024,1024).contiguous().realize(do_update_stats=False) - tms.append(cast(float, car(input_bufs, var_vals, wait=True))*factor) + tms.append(unwrap(car(input_bufs, var_vals, wait=True))*factor) if early_stop is not None and early_stop < min(tms): break return tms @@ -59,14 +58,14 @@ def timeout_handler(signum, frame): if DEBUG >= 2: print("*** BEAM COMPILE TIMEOUT") raise TimeoutException() -def _try_compile_linearized_w_idx(x:tuple[int,Scheduler], compiler:Compiler) -> tuple[int, tuple[ProgramSpec, bytes, float]|None]: +def _try_compile(x:tuple[int,Scheduler], compiler:Compiler) -> tuple[int, tuple[ProgramSpec, bytes, float]|None]: if hasattr(signal, "alarm"): signal.signal(getattr(signal, 'SIGALRM'), timeout_handler) # set timeout signal.alarm(getenv("BEAM_TIMEOUT_SEC", 10)) ret = None try: - p = get_program(x[1].copy().get_optimized_ast(name_override="test"), x[1].opts) + p = get_program(x[1].copy().get_optimized_ast(name_override="test"), x[1].ren) assert p.uops is not None, "uop list wasn't generated?" if len(p.uops) >= (uops_max:=getenv("BEAM_UOPS_MAX", 3000)) > 0: if getenv("BEAM_LOG_SURPASS_MAX"): print(f"too many uops. {len(p.uops)=}, {uops_max=}") @@ -93,42 +92,42 @@ def _ensure_buffer_alloc(bufs:list[Buffer]) -> list[Buffer]: return [buf.ensure_ # *** external API *** # get dictionary of all possible actions -def get_kernel_actions(lin:Scheduler, include_0=True, candidates:list[Opt]|None=None) -> dict[int, Scheduler]: - acted_lins, max_up, max_lcl = {0:lin} if include_0 else {}, getenv("BEAM_UPCAST_MAX", 256), getenv("BEAM_LOCAL_MAX", 1024) +def get_kernel_actions(s:Scheduler, include_0=True, candidates:list[Opt]|None=None) -> dict[int, Scheduler]: + acted, max_up, max_lcl = {0:s} if include_0 else {}, getenv("BEAM_UPCAST_MAX", 256), getenv("BEAM_LOCAL_MAX", 1024) kernel_actions = (actions if candidates is None else candidates).copy() for i,a in enumerate(kernel_actions): if a.axis is not None and a.op is not OptOps.TC: - try: ax = lin.real_axis(a.op, a.axis) + try: ax = s.real_axis(a.op, a.axis) except KernelOptError: continue - if (ax >= lin.shape_len) or (lin.full_shape[ax] == a.arg and Opt(a.op, a.axis, 0) in kernel_actions): continue - lin2 = lin.copy() + if (ax >= s.shape_len) or (s.full_shape[ax] == a.arg and Opt(a.op, a.axis, 0) in kernel_actions): continue + s2 = s.copy() try: - lin2.apply_opt(a) - up, lcl, tc_up = 1, 1, prod(tc.dims)//tc.threads if hasattr(lin2, 'tensor_core') and (tc:=lin2.tensor_core) else 1 - for s,c in zip(lin2.full_shape, lin2.axis_types): - if c in (AxisType.UPCAST, AxisType.UNROLL): up *= s - elif c in (AxisType.WARP, AxisType.LOCAL, AxisType.GROUP_REDUCE): lcl *= s + s2.apply_opt(a) + up, lcl, tc_up = 1, 1, prod(tc.dims)//tc.threads if hasattr(s2, 'tensor_core') and (tc:=s2.tensor_core) else 1 + for x,t in zip(s2.full_shape, s2.axis_types): + if t in (AxisType.UPCAST, AxisType.UNROLL): up *= x + elif t in (AxisType.WARP, AxisType.LOCAL, AxisType.GROUP_REDUCE): lcl *= x if up//tc_up > max_up or lcl > max_lcl: if getenv("BEAM_LOG_SURPASS_MAX"): print(f"too many upcast/local. {up//tc_up=}, {max_up=}, {lcl=}, {max_lcl=}") continue - acted_lins[i+1] = lin2 + acted[i+1] = s2 except KernelOptError: pass - return acted_lins + return acted beam_pool, BEAM_DEBUG = None, getenv("BEAM_DEBUG") -def beam_search(lin:Scheduler, rawbufs:list[Buffer], amt:int, allow_test_size=True, disable_cache=IGNORE_BEAM_CACHE.value): +def beam_search(s:Scheduler, rawbufs:list[Buffer], amt:int, allow_test_size=True, disable_cache=IGNORE_BEAM_CACHE.value): global beam_pool - key = {"ast": lin.ast.key, "amt": amt, "allow_test_size": allow_test_size, "device": lin.opts.device, "suffix": lin.opts.suffix} + key = {"ast": s.ast.key, "amt": amt, "allow_test_size": allow_test_size, "device": s.ren.device, "suffix": s.ren.suffix} if not disable_cache and CACHELEVEL >= 1 and (val:=diskcache_get("beam_search", key)) is not None: - ret = lin.copy() - for o in val[len(lin.applied_opts):]: ret.apply_opt(o) + ret = s.copy() + for o in val[len(s.applied_opts):]: ret.apply_opt(o) return ret - beam: list[tuple[Scheduler, float]] = [(lin, float("inf"))] + beam: list[tuple[Scheduler, float]] = [(s, float("inf"))] seen_libs = set() - default_parallel = multiprocessing.cpu_count() if lin.opts.device in {"CUDA", "AMD", "NV", "METAL", "HIP"} else 0 + default_parallel = multiprocessing.cpu_count() if s.ren.device in {"CUDA", "AMD", "NV", "METAL", "HIP"} else 0 if beam_pool is None and (workers := getenv("PARALLEL", default_parallel)): beam_pool = multiprocessing.get_context("spawn").Pool(workers, _init_worker, (), getenv("BEAM_MAX_TASKS_PER_CHILD", 16)) @atexit.register @@ -137,43 +136,52 @@ def beam_search(lin:Scheduler, rawbufs:list[Buffer], amt:int, allow_test_size=Tr min_progress = getenv("BEAM_MIN_PROGRESS", 0.01)/1e6 if BEAM_DEBUG: print("BEAM_SEARCH:") - print('\n'.join(pyrender(lin.ast.replace(arg=None)))) - if DEBUG >= 2: print(f" 0.00s: from 1 -> 1 actions {lin.colored_shape()}") + print(pyrender(s.ast.replace(arg=None))) + if DEBUG >= 2: print(f" 0.00s: from 1 -> 1 actions {s.colored_shape()}") try: rawbufs = _ensure_buffer_alloc(rawbufs) - var_vals: dict[str, int] = {k.expr:int(k.vmax+k.vmin)//2 for k in lin.ast.variables()} + var_vals: dict[str, int] = {k.expr:int(k.vmax+k.vmin)//2 for k in s.ast.variables()} exiting, st = False, time.perf_counter() - dev = Device[lin.opts.device] + dev = Device[s.ren.device] while not exiting: - acted_lins: list[Scheduler] = flatten([get_kernel_actions(lin, include_0=False).values() for lin,_ in beam]) - timed_lins: list[tuple[Scheduler, float]] = [] - _compile_fn = functools.partial(_try_compile_linearized_w_idx, compiler=dev.compiler) + candidates: list[Scheduler] = flatten([get_kernel_actions(si, include_0=False).values() for si,_ in beam]) + timed: list[tuple[Scheduler, float]] = [] + _compile_fn = functools.partial(_try_compile, compiler=dev.compiler) least_compute_ops = math.inf - for i,proc in (map(_compile_fn, enumerate(acted_lins)) if beam_pool is None else beam_pool.imap_unordered(_compile_fn, enumerate(acted_lins))): + for i,proc in (map(_compile_fn, enumerate(candidates)) if beam_pool is None else beam_pool.imap_unordered(_compile_fn, enumerate(candidates))): if proc is None: continue p, lib, compile_et = proc if lib in seen_libs: continue # filter out kernels that use 1000x more compute than the smallest least_compute_ops = min(this_compute_ops:=sym_infer(p.estimates.ops, var_vals), least_compute_ops) - if least_compute_ops*1000 < this_compute_ops: continue + if least_compute_ops*1000 < this_compute_ops: + if getenv("BEAM_LOG_SURPASS_MAX"): print(f"too much compute. {this_compute_ops} when least is {least_compute_ops}") + continue seen_libs.add(lib) try: tms = _time_program(p, lib, var_vals, rawbufs, early_stop=beam[0][1]*3 if len(beam) else 1.0, allow_test_size=allow_test_size, clear_l2=hasattr(dev, 'invalidate_caches')) except Exception as e: - if BEAM_DEBUG: print(f"BEAM failed for opts: {acted_lins[i].applied_opts}\n{e}") + if BEAM_DEBUG: print(f"BEAM failed for opts: {candidates[i].applied_opts}\n{e}") if isinstance(e, RuntimeError): continue raise - timed_lins.append((acted_lins[i], min(tms))) - if BEAM_DEBUG > 1: print(f"{time.perf_counter() - st:7.2f}s: {i:5d} {len(cast(list, p.uops)):5d} uops {time_to_str(compile_et, w=12)} compile/{time_to_str(timed_lins[-1][1], w=12)} run {len(timed_lins):4d}/{len(acted_lins):4d} {timed_lins[-1][0].colored_shape()}") # noqa: E501 - elif DEBUG >= 2: print(f"\r{time.perf_counter() - st:7.2f}s: {time_to_str(timed_lins[-1][1], w=12)} {len(timed_lins):4d}/{len(acted_lins):4d} {timed_lins[-1][0].colored_shape()}\033[K", end="") # noqa: E501 + timed.append((candidates[i], min(tms))) + if BEAM_DEBUG > 1: + print(f"{time.perf_counter() - st:7.2f}s: {i:5d} {len(unwrap(p.uops)):5d} uops", + f"{time_to_str(compile_et, w=12)} compile/{time_to_str(timed[-1][1], w=12)} run", + f" {len(timed):4d}/{len(candidates):4d} {timed[-1][0].colored_shape()}") + elif DEBUG >= 2: + print(f"\r{time.perf_counter() - st:7.2f}s: {time_to_str(timed[-1][1], w=12)}", + f" {len(timed):4d}/{len(candidates):4d} {timed[-1][0].colored_shape()}\033[K", end="") # done - opts = sorted(timed_lins, key=lambda x: x[1]) + opts = sorted(timed, key=lambda x: x[1]) exiting = len(opts) == 0 or (opts[0][1] < min_progress) or (len(beam) > 0 and ((beam[0][1]-opts[0][1]) < min_progress)) if not exiting: beam = opts[:amt] elif len(opts) > 0 and opts[0][1] < beam[0][1]: beam = opts[:1] - if DEBUG >= 2: print(f"\r{time.perf_counter() - st:7.2f}s:", colored(time_to_str(beam[0][1], w=12), "green" if exiting else None), f"from {len(acted_lins):3d} -> {len(opts):3d} actions\033[K", beam[0][0].colored_shape()) # noqa: E501 + if DEBUG >= 2: + print(f"\r{time.perf_counter() - st:7.2f}s:", colored(time_to_str(beam[0][1], w=12), "green" if exiting else None), + f"from {len(candidates):3d} -> {len(opts):3d} actions\033[K", beam[0][0].colored_shape()) except KeyboardInterrupt as e: if beam_pool is not None: beam_pool.terminate() raise e diff --git a/tinygrad/codegen/opt/swizzler.py b/tinygrad/codegen/opt/swizzler.py deleted file mode 100644 index 75521b8311..0000000000 --- a/tinygrad/codegen/opt/swizzler.py +++ /dev/null @@ -1,135 +0,0 @@ -from tinygrad.uop.ops import UOp, Ops, GroupOp, PatternMatcher, UPat, graph_rewrite, resolve, sint -from tinygrad.helpers import all_same, prod, unwrap, colored -from tinygrad.shape.shapetracker import ShapeTracker -from tinygrad.shape.view import View, strides_for_shape, get_contraction_with_reduce -from tinygrad.schedule.grouper import ALWAYS_CONTIGUOUS -from tinygrad.dtype import ImageDType, dtypes - -merge_views = PatternMatcher([ - # merge adjacent views - (UPat(Ops.VIEW, src=(UPat(Ops.VIEW, name="v1"),), name="v2"), lambda v1,v2: v1.replace(arg=v1.arg+v2.arg)), - # replace MovementOps with VIEW - (UPat(GroupOp.Movement, src=(UPat.var("x"),), name="mop"), lambda mop,x: x.base.view(mop.st)), - # remove NOOP views - (UPat.var("x").view(name="view"), - lambda x,view: x if x.st is not None and x.op not in GroupOp.Defines and view.st.contiguous and view.shape == x.shape else None), - (UPat(GroupOp.All-{Ops.DEFINE_GLOBAL}).view(name="view"), - lambda view: view.const_like(0) if (mask:=view.st.views[-1].mask) is not None and any((x[1]-x[0]) == 0 for x in mask) else None), - # only unmaksed VIEW on CONST replaces the ShapeTracker - (UPat(Ops.VIEW, src=(UPat((Ops.CONST, Ops.DEFINE_VAR), name="x"),), name="view"), - lambda x,view: x.replace(src=(UOp(Ops.VIEW, x.dtype, x.src, view.arg),)) if all(v.mask is None for v in view.st.views) else None), -]) - -def reduce_push_add_ones(src:UOp, r:UOp, view:UOp): - # contiguous, expand, and the same with ones removed - if unwrap(view.st).contiguous and len(r.shape) < len(view.shape) and \ - tuple(x for x in r.shape if resolve(x != 1)) == tuple(x for x in view.shape if resolve(x != 1)): - new_shape: list[sint] = [] - new_reduce_axis = [] - if (contraction:=get_contraction_with_reduce(view.shape, r.shape, r.arg[1])) is None: return None - for i,pairs in enumerate(contraction): - new_shape_chunk = [view.shape[p] for p in pairs] - if i in r.arg[1]: - # if this is a reduce axis, we need a 1 in the view here to put it - assert len(new_shape_chunk) > 0 - new_shape += [1]*(len(pairs)-1) + [src.shape[i]] - new_reduce_axis.append(len(new_shape)-1) - else: - # otherwise, pass through the new_shape_chunk - new_shape += new_shape_chunk - ret = r.replace(src=(src.reshape(tuple(new_shape)),), arg=(r.arg[0], tuple(new_reduce_axis))+r.arg[2:]) - assert ret.shape == view.shape, f"shape mismatch on reduce_push_add_ones, {ret.shape} != {view.shape}" - return ret - return None - -view_left = merge_views+PatternMatcher([ - # view before elementwise and buffer ops - (UPat(Ops.VIEW, src=(UPat({*GroupOp.ALU, Ops.CAST, Ops.BITCAST, Ops.BIND, Ops.STORE, Ops.VALID, Ops.SINK}, name="e"),), name="view"), - lambda e,view: e.replace(src=tuple(s.view(view.st) for s in e.src))), - # if there's ones added after reduce, put this before the reduce - (UPat(Ops.VIEW, src=(UPat(Ops.REDUCE_AXIS, src=(UPat.var("src"),), name="r"),), name="view"), reduce_push_add_ones), -]) - -view_left_through_load = PatternMatcher([ - # view before load - (UPat(Ops.VIEW, src=(UPat(Ops.LOAD, name="e"),), name="view"), - lambda e,view: e.replace(src=tuple(s.view(view.st) for s in e.src))), -]) - -def apply_swizzle(u:UOp) -> UOp: return graph_rewrite(u, view_left, name="Sub View Left") - -# change reduceop axes and input ShapeTrackers, view gets replaced with a reshape. -def swizzle_reduceop(r:UOp, src:UOp, view:UOp, fuse=False): - # contiguous and same size can push to children - # if there's a reduce child, shapes match with ones removed - if unwrap(view.st).contiguous and view.size == r.size and \ - (not (len(r.arg) == 3 and r.arg[2]) or # arg[2] = True is fuse marker - tuple((i,x) for i,x in enumerate(r.shape) if resolve(x != 1)) == tuple((i,x) for i,x in enumerate(view.shape) if resolve(x != 1))): - return None - # swizzle the input - input_st = ShapeTracker.from_shape(src.shape) - tmp = input_st.permute(tuple(i for i in range(len(input_st.shape)) if i not in r.axis_arg)+r.axis_arg) - prshape = prod(rshape:=tmp.shape[-len(r.axis_arg):]) - strides = strides_for_shape(rshape) - nv = [View.create(v.shape+rshape, tuple(x*prshape for x in v.strides)+strides, - v.offset*prshape, v.mask+tuple((0,s) for s in rshape) if v.mask is not None else None) for v in unwrap(view.st).views] - new_view = tmp + ShapeTracker(tuple(nv)) - swizzled_input = apply_swizzle(src.view(new_view)) - # create a new reduceop - new_axis = tuple(range(len(view.shape), len(view.shape) + len(r.axis_arg))) - if fuse: red = UOp(Ops.REDUCE_AXIS, r.dtype, (swizzled_input.fuse(),), (r.arg[0], new_axis, True)) - else: red = UOp(Ops.REDUCE_AXIS, r.dtype, (swizzled_input,), (r.arg[0], new_axis)) - return red.reshape(view.shape) - -def reduceop_view_right(src:UOp, v:UOp, r:UOp): - assert unwrap(v.st).contiguous and v.size == src.size, f"can't compute new axis for {src.shape} -> {r.shape}" - new_axis = [i for i,(s,u) in enumerate(zip(src.shape, r.shape)) if s != u] - return src.r(r.arg[0], tuple(new_axis)).reshape(r.shape) - -def elementwise_view_right(root:UOp): - if not (swizzles:=[x for x in root.src if x.op is Ops.VIEW and x.base.op not in ALWAYS_CONTIGUOUS]): return None - assert all_same([x.base.size for x in swizzles]), f"swizzle inputs must have the same size {swizzles}" - # place view after applying the elementwise op - new_st = ShapeTracker.from_shape(swizzles[0].base.shape) - new_src = [x.base if x.base.shape==new_st.shape else apply_swizzle(x.view(new_st)) for x in root.src] - # reshape to match downstream shapes - return root.replace(src=tuple(new_src)).reshape(root.shape) - -# push VIEW to children -view_right = merge_views+PatternMatcher([ - # push a non contiguous ShapeTracker through reduceop - (UPat(Ops.VIEW, src=(UPat(Ops.REDUCE_AXIS, src=(UPat.var("src"),), name="r"),), name="view"), swizzle_reduceop), - # apply view after reduceops - (UPat(Ops.REDUCE_AXIS, src=(UPat(Ops.VIEW, src=(UPat(GroupOp.All-ALWAYS_CONTIGUOUS, name="src"),), name="v"),), name="r"), reduceop_view_right), - # apply view after elementwise ops - (UPat(GroupOp.All-{Ops.SINK, Ops.REDUCE_AXIS}, name="root"), elementwise_view_right), - # merge axes for double reduce (invert of SPLIT_REDUCEOP=1) - (UPat(Ops.REDUCE_AXIS, src=(UPat(Ops.REDUCE_AXIS, name="r1"),), name="r2"), - lambda r1,r2: r1.replace(arg=(r1.arg[0], r2.arg[1]+r1.arg[1])) if r1.arg[0] is r2.arg[0] else None), - # remove view from sink - (UPat(Ops.VIEW, name="v").sink(name="sink"), lambda v,sink: v.src[0].sink(arg=sink.arg)), -]) - -def check_load_st(glbl:UOp, view:UOp): - if glbl.arg != 0 or (st:=unwrap(view.st)).contiguous: return - # if it has a single view and it becomes contiguous when you shrink expanded axes, it's fine - if len(st.views) == 1 and st.shrink(tuple((0,1) if st == 0 else (0,s) for s,st in zip(st.shape, st.views[0].strides))).contiguous: return - # if it has a single view and it's equal when you shrink a contig, it's fine - if len(st.views) == 1 and (mask:=st.views[0].mask) is not None and ShapeTracker.from_shape(st.shape).shrink(mask) == st.shrink(mask): return - # otherwise, it's not fine - raise RuntimeError("self operand of augmented assign must be contiguous.\nhelp: consider using .contiguous():\n" - +colored(" - a += a.T\n", "red")+colored(" + a += a.T.contiguous()", "green")) - -fix_kernel_ops = view_left_through_load+PatternMatcher([ - # add view to LOAD and STORE - (UPat(Ops.DEFINE_GLOBAL, name="g").load(), lambda g: g.view(g.st).load()), - (UPat(Ops.DEFINE_GLOBAL, name="g").store(UPat.var('x')), lambda g,x: g.view(g.st).store(x)), - # VALID - (UPat(Ops.VIEW, src=(UPat.cvar(),), name="self"), - lambda self: UOp.where(UOp(Ops.VALID, dtypes.bool, (UOp(Ops.VIEW, arg=self.st),)), self.const_like(self.base.arg), 0)), - # no ImageDType after index - (UPat(GroupOp.All-{Ops.DEFINE_GLOBAL, Ops.VIEW, Ops.INDEX}, name="x"), - lambda x: x.replace(dtype=x.dtype.base) if isinstance(x.dtype, ImageDType) else None), - # if this kernel also assigns to the loaded buffer, ensure we can index it correctly - (UPat(Ops.LOAD, src=(UPat.var("glbl").view(name="view"),)), check_load_st), -]) diff --git a/tinygrad/codegen/opt/tc.py b/tinygrad/codegen/opt/tc.py index d32266c47a..7dbdf4b071 100644 --- a/tinygrad/codegen/opt/tc.py +++ b/tinygrad/codegen/opt/tc.py @@ -80,6 +80,10 @@ cuda_81616 = [TensorCore(dims=(8,16,16), threads=32, elements_per_thread=(8,4,4) swizzle=((('r1', 'r2', 'l2', 'l3', 'l4'), ('u1', 'r3'), ('l0', 'l1', 'u0', 'r0')), (('r1', 'r2', 'u0', 'l0', 'l1'), ('r0', 'r3'), ('l2', 'l3', 'l4', 'u1')))) for di,do in [(dtypes.half,dtypes.float), (dtypes.bfloat16,dtypes.float), (dtypes.half,dtypes.half)]] +cuda_81632_f8 = [TensorCore(dims=(8,16,32), threads=32, elements_per_thread=(16,8,4), dtype_in=di, dtype_out=do, opts=cuda_tc_opts, + swizzle=((('r2', 'r3', 'l2', 'l3', 'l4'), ('u1', 'r4'), ('l0', 'l1', 'u0', 'r0', 'r1')), + (('r2', 'r3', 'u0', 'l0', 'l1'), ('r1', 'r4'), ('l2', 'l3', 'l4', 'u1', 'r0')))) + for di,do in [(dtypes.fp8e4m3,dtypes.float),(dtypes.fp8e5m2,dtypes.float)]] cuda_8168_f16 = [TensorCore(dims=(8,16,8), threads=32, elements_per_thread=(4,2,4), dtype_in=di, dtype_out=do, opts=cuda_tc_opts, swizzle=((('r1', 'r2', 'l2', 'l3', 'l4'), ('r0', 'u1'), ('l0', 'l1', 'u0')), (('r1', 'r2', 'u0', 'l0', 'l1'), ('u1', 'r0'), ('l2', 'l3', 'l4')))) @@ -87,9 +91,10 @@ cuda_8168_f16 = [TensorCore(dims=(8,16,8), threads=32, elements_per_thread=(4,2, cuda_8168_tf32 = [TensorCore(dims=(8,16,8), threads=32, elements_per_thread=(4,2,4), dtype_in=dtypes.float, dtype_out=dtypes.float, opts=cuda_tc_opts, swizzle=((('r0', 'r1', 'l2', 'l3', 'l4'), ('u1', 'r2'), ('l0', 'l1', 'u0')), (('r0', 'r1', 'u0', 'l0', 'l1'), ('u1', 'r2'), ('l2', 'l3', 'l4'))))] +cuda_sm75: list[TensorCore] = cuda_8168_f16 cuda_sm80: list[TensorCore] = cuda_81616 + cuda_8168_f16 if getenv("ALLOW_TF32", 0): cuda_sm80 += cuda_8168_tf32 -cuda_sm75: list[TensorCore] = cuda_8168_f16 +cuda_sm89: list[TensorCore] = cuda_sm80 + cuda_81632_f8 # ***** AMD ***** @@ -106,12 +111,22 @@ amd_rdna4 = [TensorCore(dims=(16,16,16), threads=32, elements_per_thread=(8,8,8) for di,do in [(dtypes.half,dtypes.float),(dtypes.half,dtypes.half),(dtypes.bfloat16,dtypes.float),(dtypes.bfloat16,dtypes.bfloat16)]] # https://gpuopen.com/learn/amd-lab-notes/amd-lab-notes-matrix-cores-readme -amd_cdna = [TensorCore(dims=(16,16,16), threads=64, elements_per_thread=(4,4,4), dtype_in=di, dtype_out=do, +amd_cdna_161616 = [TensorCore(dims=(16,16,16), threads=64, elements_per_thread=(4,4,4), dtype_in=di, dtype_out=do, opts=("l0","l0","l0","l0","u1","u1","l1","l1"), swizzle=((('u0', 'u1', 'l4', 'l5', 'r2', 'r3'), ('r0', 'r1'), ('l0', 'l1', 'l2', 'l3')), (('l0', 'l1', 'l2', 'l3', 'r2', 'r3'), ('r0', 'r1'), ('l4', 'l5', 'u0', 'u1')))) for di,do in [(dtypes.half,dtypes.float),(dtypes.bfloat16,dtypes.float)]] +amd_cdna_161632 = [TensorCore(dims=(16,16,32), threads=64, elements_per_thread=(8,8,4), dtype_in=di, dtype_out=do, + opts=("l0","l0","l0","l0","u1","u1","l1","l1"), + swizzle=((('u0', 'u1', 'l4', 'l5', 'r3', 'r4'), ('r0', 'r1'), ('l0', 'l1', 'l2', 'l3', 'r2')), + (('l0', 'l1', 'l2', 'l3', 'r3', 'r4'), ('r0', 'r1'), ('l4', 'l5', 'u0', 'u1', 'r2')))) + for di,do in [(dtypes.fp8e5m2,dtypes.float),(dtypes.fp8e4m3,dtypes.float),(dtypes.half,dtypes.float),(dtypes.bfloat16,dtypes.float)]] + +amd_cdna3 = amd_cdna_161632[:2] + amd_cdna_161616 + +amd_cdna4 = amd_cdna_161632 + amd_cdna_161616 + # ***** Apple Metal ***** metal = [TensorCore(dims=(8,8,8), threads=32, elements_per_thread=(2,2,2), dtype_in=di, dtype_out=do, diff --git a/tinygrad/codegen/quantize.py b/tinygrad/codegen/quantize.py deleted file mode 100644 index a94bec18bb..0000000000 --- a/tinygrad/codegen/quantize.py +++ /dev/null @@ -1,67 +0,0 @@ -from tinygrad.dtype import dtypes, least_upper_dtype -from tinygrad.uop.ops import UOp, Ops, PatternMatcher, UPat -from tinygrad.uop.symbolic import symbolic - -# **** this is the "quantization preprocessor", it makes ONNX quantized models, and probably also others, actually use ints **** -# this is badly tested and low quality. remove it? - -FP = (1 << 15) -pm_quant = symbolic+PatternMatcher([ - # cast after add/mul - (UPat.var("x").cast(dtypes.float32) + UPat.var("y").cast(dtypes.float32), - lambda x,y: (x.cast(least_upper_dtype(x.dtype, y.dtype))+y.cast(least_upper_dtype(x.dtype, y.dtype))).cast(dtypes.float32)), - (UPat.var("x").cast(dtypes.float32) * UPat.var("y").cast(dtypes.float32), - lambda x,y: (x.cast(least_upper_dtype(x.dtype, y.dtype))*y.cast(least_upper_dtype(x.dtype, y.dtype))).cast(dtypes.float32)), - - # masked MUL after masked ADD - ((UPat.var("x") + UPat.var("v").where(UPat.var('cadd'), UPat(Ops.CONST, arg=0))) * UPat.var("v").where(UPat.var('cmul'), UPat(Ops.CONST, arg=0)), - lambda x,v,cadd,cmul: x*v.where(cmul, 0)+v.where(cadd*cmul, 0)), - - # MUL after reduce - (UPat(Ops.REDUCE_AXIS, src=(UPat.var("x") * UPat.cvar("c"),), name="r"), lambda x,c,r: r.replace(src=(x,))*c.arg), - # CAST after reduce (doesn't work if it's a size change) - (UPat(Ops.REDUCE_AXIS, src=(UPat(Ops.CAST, src=(UPat.var("x"),)),), name="r"), - lambda x,r: r.replace(dtype=x.dtype, src=(x,)).cast(r.dtype) if dtypes.is_float(r.dtype) else None), - - # x*c1 + y*c2 -> (x+y)*c1 (if c1 and c2 are close floats) - (UPat.var("x")*UPat.cvar("c1", dtype=dtypes.floats) + UPat.var("y")*UPat.cvar("c2", dtype=dtypes.floats), - lambda x,y,c1,c2: (x+y)*c1 if abs(c1.arg-c2.arg) < 1e-9 else None), - # mul 0 * c1 is 0 - (UPat(Ops.VALID, src=(UPat(Ops.VIEW, name="v"),)).where(UPat.cvar("c1"), UPat(Ops.CONST, arg=0)) * - UPat(Ops.LOAD, src=(UPat().view(name="v"),)).cast(dtypes.int).cast(dtypes.float).named("ld"), lambda ld,v,c1: ld*c1), - # mul (with plus) 0 * c1 is 0 - (UPat(Ops.VALID, src=(UPat(Ops.VIEW, name="v"),)).where(UPat.cvar("c1"), UPat(Ops.CONST, arg=0)) * - (UPat(Ops.LOAD, src=(UPat().view(name="v"),)).cast(dtypes.int) + \ - UPat(Ops.VALID, src=(UPat(Ops.VIEW, name="v"),)).where(UPat.cvar(), UPat(Ops.CONST, arg=0))).cast(dtypes.float).named("ld"), - lambda ld,v,c1: ld*c1), - - # const push through add - ((UPat.var("x")*UPat.cvar("c1") + UPat.var("y")*UPat.cvar("c2")) * UPat.cvar("c3"), lambda x,y,c1,c2,c3: (x*c1*c3) + (y*c2*c3)), - - # fixed point mult, replace (x.float()*c1+c2).int() with an int expression - ((UPat.var("x").cast(dtypes.float)*UPat.var("c1")+UPat.var("cc")).cast(dtypes.int), - lambda x,c1,cc: ((x*(c1*FP).cast(x.dtype) + (cc*FP).cast(x.dtype)) // FP).cast(dtypes.int)), - # fixed point mult, replace (x.float()*c1 + y.float()*c2)*cc.int() with an int expression - ((UPat.var("x").cast(dtypes.float)*UPat.var("c1")+UPat.var("y").cast(dtypes.float)*UPat.var("c2")+UPat.var("cc")).cast(dtypes.int), - lambda x,c1,y,c2,cc: ((x*(c1*FP).cast(x.dtype) + y.cast(x.dtype)*(c2*FP).cast(x.dtype) + (cc*FP).cast(x.dtype)) // FP).cast(dtypes.int)), - - # where move - (UPat.var("valid").where(UPat.var("yes"), UPat(Ops.CONST, arg=0))*UPat.var("mul"), lambda valid, yes, mul: - (yes*mul*valid.where(UOp.const(mul.dtype, 1), UOp.const(mul.dtype, 0))) if yes.op is not Ops.CONST or yes.arg != 1 else None), - ((UPat.var("x")*UPat.cvar("c"))*(UPat.var().where(UPat(Ops.CONST, arg=1), UPat(Ops.CONST, arg=0)).named("v")), lambda x,c,v: (x*v)*c), - (UPat.var("x").cast().named('c') * UPat.var('valid').where(UPat(Ops.CONST, arg=1), UPat(Ops.CONST, arg=0)), lambda x,c,valid: - (x*valid.where(UOp.const(x.dtype, 1), UOp.const(x.dtype, 0))).cast(c.dtype)), - ((UPat.var('x') * UPat.var('v1').where(UPat(Ops.CONST, arg=1), UPat(Ops.CONST, arg=0)) * - UPat.var('v2').where(UPat(Ops.CONST, arg=1), UPat(Ops.CONST, arg=0))).named("mul"), lambda x, mul, v1, v2: - x * (v1&v2).where(UOp.const(mul.dtype, 1), UOp.const(mul.dtype, 0))), - - # where on two adds - (UPat.var("x") + UPat.var("v").where(UPat.var("a0"), UPat.var("a1")) + UPat.var("v").where(UPat.var("b0"), UPat.var("b1")), - lambda x,v,a0,a1,b0,b1: x + v.where(a0+b0, a1+b1)), - - # split REDUCE into multiple reduces (who remembers FOIL?) - (UPat(Ops.REDUCE_AXIS, src=((UPat(Ops.CAST, name="v1")+UPat.var("c1")) * UPat(Ops.CAST, name="v2"),), name="r"), - lambda v1,v2,c1,r: r.replace(src=(v1*v2,)) + r.replace(src=(c1*v2,))), - (UPat(Ops.REDUCE_AXIS, src=((UPat(Ops.CAST, name="v1")+UPat.var("c1")) * (UPat(Ops.CAST, name="v2",)+UPat.var("c2")),), name="r"), - lambda v1,v2,c1,c2,r: r.replace(src=(v1*v2,)) + r.replace(src=(c2*v1,)) + r.replace(src=(c1*v2,)) + r.replace(src=(c1*c2,))), -]) \ No newline at end of file diff --git a/tinygrad/codegen/simplify.py b/tinygrad/codegen/simplify.py index 9e5cc3adc8..3e3514e7cb 100644 --- a/tinygrad/codegen/simplify.py +++ b/tinygrad/codegen/simplify.py @@ -1,6 +1,7 @@ +import itertools from tinygrad.uop.ops import UOp, PatternMatcher, UPat, Ops, graph_rewrite, _substitute, range_start, ImageDType -from tinygrad.uop.symbolic import symbolic_flat, sym, invalid_pat -from tinygrad.helpers import partition +from tinygrad.uop.symbolic import symbolic +from tinygrad.helpers import partition, dedup from tinygrad.dtype import dtypes def flatten_range(r:UOp): @@ -12,15 +13,14 @@ def flatten_range(r:UOp): pm_flatten_range = PatternMatcher([ # real ranges only - (UPat((Ops.REDUCE, Ops.STORE), name="r"), flatten_range), + (UPat((Ops.REDUCE, Ops.STORE, Ops.END), name="r"), flatten_range), ]) def count_divmod(x:UOp): return len([u for u in x.toposort() if u.op in {Ops.IDIV, Ops.MOD}]) def simplify_merge_adjacent(u:UOp) -> UOp|None: - reduce_ranges = [x.ranges for x in u.sparents if x.op is Ops.REDUCE] - i = range_start[u.op] - while i < len(u.src)-1: - r0, r1 = u.src[i], u.src[i+1] + reduce_ranges = [x.ranges for x in u.backward_slice_with_self if x.op is Ops.REDUCE] + # on END we only want to merge adjacent ranges, on REDUCE we want to try all combinations + for r0, r1 in (zip(u.ended_ranges, u.ended_ranges[1:]) if u.op is Ops.END else itertools.permutations(u.ended_ranges, 2)): # check same type if r0.arg[-1] == r1.arg[-1]: # check if the ranges to merge are in the same reduces @@ -28,18 +28,16 @@ def simplify_merge_adjacent(u:UOp) -> UOp|None: s0, s1 = r0.src[0], r1.src[0] # do the merge new_range = r0.replace(src=(s0*s1,)) - nidx = graph_rewrite(u, _substitute+symbolic_flat+pm_flatten_range, ctx={r0:new_range//s1, r1:new_range%s1}, + nidx = graph_rewrite(u, _substitute+symbolic+pm_flatten_range, ctx={r0:new_range//s1, r1:new_range%s1}, name=f"check_merge_{r0.arg[0]}_{r1.arg[0]}") # check if it simplifies if count_divmod(nidx) <= count_divmod(u): u = nidx - continue - i += 1 return u pm_simplify_ranges = PatternMatcher([ - (UPat((Ops.STORE, Ops.REDUCE), name="u"), simplify_merge_adjacent), + (UPat((Ops.END, Ops.REDUCE), name="u"), simplify_merge_adjacent), ]) def mark_range_mod(ctx, r:UOp, c:UOp): @@ -56,8 +54,8 @@ def do_substitute(ctx, x: UOp): return ret def dont_sub_ranges_for_image(ctx, x:UOp): - if isinstance(x.src[0].dtype, ImageDType): - for s in x.src[1:]: ctx[s] = None + if isinstance(x.src[0].src[0].dtype, ImageDType): + for s in x.src[0].ranges: ctx[s] = None pm_split_ranges = PatternMatcher([ (UPat(Ops.RANGE, name="r")%UPat.cvar("c"), mark_range_mod), @@ -67,69 +65,12 @@ pm_split_ranges = PatternMatcher([ # **** reduce simplification **** -def no_range(u:UOp) -> bool: return not any(x.op is Ops.RANGE for x in u.sparents) - -def reduce_rangeless(red:UOp): - # TODO: share code with reduce_unparented - if red.arg not in {Ops.ADD, Ops.MAX}: return None - if red.src[0].dtype != red.dtype: return None - if not no_range(red.src[0]): return None - ret = red.src[0] - if red.arg is Ops.ADD: - for r in red.src[1:]: - ret = ret * r.src[0].cast(ret.dtype.scalar()).broadcast(ret.dtype.count) - return ret - -pm_reduce_collapse = PatternMatcher([ - # lift x+y out of reduce on lt - ((UPat.var("x")+UPat.var("y")).or_casted() < UPat.var("c"), lambda x,y,c: (x < (c.cast(y.dtype)-y)) if no_range(y) and no_range(c) else None), - # lift x*y out of reduce - ((UPat.var("x")*UPat.var("y")) < UPat.var("c"), - lambda x,y,c: (x < ((c+y-1) // y)) if no_range(y) and no_range(c) and y.vmin > 0 else None), - # lift x+y out of reduce on ne - ((UPat.var("x")+UPat.var("y")).or_casted() != UPat.var("c"), lambda x,y,c: (x != (c.cast(y.dtype)-y)) if no_range(y) and no_range(c) else None), - # fold the range - ((UPat(Ops.RANGE, name="r") < UPat.var("cut")).where(0, UPat.cvar("val")).reduce(arg=Ops.ADD, allow_any_len=True), - lambda r,cut,val: (r.src[0]-cut).maximum(0).minimum(r.src[0]).cast(val.dtype) * val), - ((UPat(Ops.RANGE, name="r") < UPat.var("cut")).where(UPat.cvar("val"), 0).reduce(arg=Ops.ADD, allow_any_len=True), - lambda r,cut,val: cut.maximum(0).minimum(r.src[0]).cast(val.dtype) * val), - # REDUCE on ADD - ((UPat.var("x")+UPat.var("y")).reduce(arg=Ops.ADD, allow_any_len=True, name="r"), - lambda x,y,r: x.reduce(*r.src[1:], arg=Ops.ADD) + y.reduce(*r.src[1:],arg=Ops.ADD)), - # MUL casted bool - ((UPat.var("x") * UPat.var("gate", dtype=dtypes.bool).cast().or_broadcasted(name="b")), - lambda x,gate,b=None: gate.broadcast(x.dtype.count).where(x, 0) if b is not None else gate.where(x, 0)), - # WHERE on LOAD (works on max too) - (UPat.var("gate").where(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx"))).load(), 0).reduce(arg=Ops.ADD, allow_any_len=True), - lambda buf,idx,gate: buf.index(idx.valid(gate)).load()), - (UPat.var("gate").where(0, UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx"))).load()).reduce(arg=Ops.ADD, allow_any_len=True), - lambda buf,idx,gate: buf.index(idx.valid(gate.logical_not())).load()), - # INDEX on RANGE / gated RANGE - (UPat.var("buf").index(UPat.var("idx").eq(UPat(Ops.RANGE, name="r").or_casted()).where(UPat.var("expr"), invalid_pat)), - lambda buf,r,idx,expr,i: buf.index(expr.substitute({r:idx.cast(r.dtype)}).valid((idx.cast(r.dtype) >= 0) & (idx.cast(r.dtype) < r.src[0])))), - # AND on WHERE - ((UPat.any(UPat(Ops.DEFINE_VAR, name="x"), UPat(Ops.DEFINE_VAR).gep(name="x")) & UPat.var("y")) \ - .where(UPat.cvar("c"), 0).reduce(arg=Ops.ADD, allow_any_len=True, name="r"), - lambda x,y,c,r: y.where(c, 0).reduce(*r.src[1:], arg=Ops.ADD)*x.cast(c.dtype)), - # remove REDUCEs that no longer have a RANGE in the src - (UPat(Ops.REDUCE, name="red"), reduce_rangeless), -])+sym - -def reduce_collapse(red:UOp): - included, not_included = partition(red.parents, lambda x: any(y in x.sparents for y in red.src[1:])) - if any(x.op in {Ops.STORE, Ops.REDUCE} for x in included): return None - replaces: dict[UOp, UOp] = {} - for u in included: - for s in u.src: - if s in not_included and s not in replaces and s.op not in {Ops.CONST, Ops.VCONST, Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_VAR}: - replaces[s] = UOp(Ops.DEFINE_VAR, dtype=s.dtype, arg=(f'in{len(replaces)}', s.vmin, s.vmax)) - collapse_fxn = red.substitute(replaces) - sink = graph_rewrite(collapse_fxn, pm_reduce_collapse, name="reduce_collapse") - return sink.substitute({v:k for k,v in replaces.items()}) if no_range(sink) else None +def no_range(u:UOp) -> bool: return not any(x.op is Ops.RANGE for x in u.backward_slice_with_self) def reduce_unparented(red:UOp): if red.arg not in {Ops.ADD, Ops.MAX, Ops.MUL}: return None - reduce_parented, reduce_unparented = partition(red.src[1:], lambda x: x in red.src[0].sparents) + assert all(x.op is Ops.RANGE for x in red.src[1:]), "some reduce srcs aren't ranges" + reduce_parented, reduce_unparented = partition(red.src[1:], lambda x: x in red.src[0].ranges) if len(reduce_unparented) == 0: return None ret = red.replace(src=(red.src[0],)+tuple(reduce_parented)) if len(reduce_parented) or red.dtype != red.src[0].dtype else red.src[0] if red.arg is Ops.ADD: @@ -143,7 +84,78 @@ pm_reduce_unparented = PatternMatcher([ (UPat(Ops.REDUCE, name="red"), reduce_unparented), ]) +pm_reduce_collapse = pm_reduce_unparented + PatternMatcher([ + # lift x+y out of reduce on lt + ((UPat.var("x")+UPat.var("y")).or_casted() < UPat.var("c"), lambda x,y,c: (x < (c.cast(y.dtype)-y)) if no_range(y) and no_range(c) else None), + # lift x*y out of reduce + ((UPat.var("x")*UPat.var("y")) < UPat.var("c"), lambda x,y,c: (x < ((c+y-1) // y)) if no_range(y) and no_range(c) and y.vmin > 0 else None), + # fold the range + # bound from below + ((UPat(Ops.RANGE, name="r") < UPat.var("cut")).where(0, UPat.var("val")).reduce(UPat.var("r"), arg=Ops.ADD), + lambda r,cut,val: (r.src[0]-cut).maximum(0).minimum(r.src[0]).cast(val.dtype) * val if no_range(val) else None), + # bound from two sides + (((UPat.var("r")= 0) & (idx.cast(r.dtype) < r.src[0])).where(expr.substitute({r:idx.cast(r.dtype).valid(v)}),0)), +]) + +def reduce_collapse(red:UOp, u:UOp, pm=pm_reduce_collapse): + for r in red.src[1:]: + included = u.toposort(gate=lambda x: r in x.ranges) + if any(x.op in {Ops.STORE, Ops.REDUCE} for x in included): return None + replaces: dict[UOp, UOp] = {} + for u in included: + for s in u.src: + if s in included or s in replaces or s.op in {Ops.CONST, Ops.VCONST, Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_VAR}: continue + replaces[s] = UOp(Ops.DEFINE_VAR, dtype=s.dtype, arg=(f'in{len(replaces)}', s.vmin, s.vmax)) + collapse_fxn = u.substitute(replaces).reduce(r, arg=Ops.ADD) + sink = graph_rewrite(collapse_fxn, pm, name="reduce_collapse") + if not no_range(sink): return None + u = sink.substitute({v:k for k,v in replaces.items()}) + return u + +def reduce_load_collapse(red:UOp, u:UOp): return reduce_collapse(red, u, pm=pm_reduce_load_collapse) + +# remove REDUCE without loads (generic arange opt / indexing). pm_reduce_simplify = pm_reduce_unparented + PatternMatcher([ - # remove REDUCE without loads (generic arange opt / indexing). TODO: support multi range - (UPat(Ops.REDUCE, src=(UPat(), UPat()), name="red"), reduce_collapse), + (UPat(Ops.REDUCE, src=(UPat.var("u"),), allow_any_len=True, arg=Ops.ADD, name="red"), reduce_collapse), +]) +# remove REDUCE on load, comes from indexing a tensor with another tensor +def no_load(u:UOp) -> bool: return not any(x.op is Ops.INDEX for x in u.backward_slice_with_self) +pm_load_collapse = PatternMatcher([ + (UPat(Ops.REDUCE, src=(UPat.var("u"), UPat()), name="red"), reduce_load_collapse), + # we want to make sure we dont do math on a loaded index since that can cause overflow, this undoes the rule in pm_reduce_load_collapse + ((UPat.var("x", dtypes.index)+UPat.var("y")) Compiled: return self.__get_canonicalized_item(self.canonicalize(ix)) @functools.cache # this class is a singleton, pylint: disable=method-cache-max-size-none def __get_canonicalized_item(self, ix:str) -> Compiled: - assert ALLOW_DEVICE_USAGE or ix.split(":")[0] in ["DISK", "NPY", "PYTHON"], f"usage of device {ix} disallowed" + assert ALLOW_DEVICE_USAGE or ix.split(":")[0] in ["DISK", "TINYFS", "NPY", "PYTHON"], f"usage of device {ix} disallowed" base = (__package__ or __name__).split('.')[0] # tinygrad x = ix.split(":")[0].lower() ret = [cls for cname, cls in inspect.getmembers(importlib.import_module(f'{base}.runtime.ops_{x}')) \ @@ -39,7 +39,7 @@ class _Device: @functools.cached_property def DEFAULT(self) -> str: dev = [dev] if (dev:=getenv("DEV", "").upper()) else [] - from_env = dedup(dev + [d for d in self._devices if d not in ["DISK", "NPY"] and getenv(d) == 1]) + from_env = dedup(dev + [d for d in self._devices if d not in ["DISK", "TINYFS", "NPY"] and getenv(d) == 1]) assert len(from_env) < 2, f"multiple devices set in env: {from_env}" if len(from_env) == 1: return from_env[0] try: @@ -47,14 +47,14 @@ class _Device: os.environ[device] = "1" # we set this in environment for spawned children return device except StopIteration as exc: raise RuntimeError("no usable devices") from exc -Device = _Device() +Device: _Device = _Device() atexit.register(lambda: [Device[dn].finalize() for dn in Device._opened_devices]) # **************** Profile **************** @dataclass(frozen=True) class ProfileDeviceEvent(ProfileEvent): - device:str; comp_tdiff:decimal.Decimal=decimal.Decimal(0); copy_tdiff:decimal.Decimal=decimal.Decimal(0) # noqa: E702 + device:str; comp_tdiff:decimal.Decimal=decimal.Decimal(0); copy_tdiff:decimal.Decimal=decimal.Decimal(0); props:dict[str,Any]|None=None # noqa: E702 @dataclass(frozen=True) class ProfileProgramEvent(ProfileEvent): device:str; name:str; lib:bytes|None; base:int|None # noqa: E702 @@ -125,7 +125,7 @@ class Buffer: def allocate(self, opaque=None, external_ptr=None) -> Buffer: assert not self.is_initialized(), "can't allocate already allocated buffer" if DEBUG >= 7: print(f"buffer: allocate {self.nbytes} bytes on {self.device}") - if MAX_BUFFER_SIZE > 0 and self.size > MAX_BUFFER_SIZE: raise RuntimeError(f"buffer of size {self.size/1e6:.2f}M is too large") + if not self.device.startswith("NULL") and self.size > MAX_BUFFER_SIZE > 0: raise RuntimeError(f"buffer of size {self.size/1e6:.2f}M is too large") self.allocator:Allocator = Device[self.device].allocator if external_ptr is not None: self.options = replace(self.options, external_ptr=external_ptr) if self.options else BufferSpec(external_ptr=external_ptr) @@ -137,16 +137,14 @@ class Buffer: else: self._buf = opaque if opaque is not None else self.allocator.alloc(self.nbytes, self.options) if not self.device.startswith("DISK"): GlobalCounters.mem_used += self.nbytes - if PROFILE: - self._prof_num = num = len(Buffer.profile_events) - Buffer.profile_events.append(ProfilePointEvent(self.device, "alloc", num, {"dtype":self.dtype, "sz":self.size})) + if PROFILE: Buffer.profile_events.append(ProfilePointEvent(self.device, "alloc", self.trace_num, {"dtype":self.dtype, "sz":self.size})) return self def deallocate(self): assert hasattr(self, '_buf'), "buffer must be allocated to deallocate" if DEBUG is not None and DEBUG >= 7: print(f"buffer: deallocate {self.nbytes} bytes on {self.device}") if self._base is None and (self.options is None or self.options.external_ptr is None): if GlobalCounters is not None and not self.device.startswith("DISK"): GlobalCounters.mem_used -= self.nbytes - if PROFILE: Buffer.profile_events.append(ProfilePointEvent(self.device, "free", self._prof_num)) + if PROFILE: Buffer.profile_events.append(ProfilePointEvent(self.device, "free", self.trace_num)) self.allocator.free(self._buf, self.nbytes, self.options) elif self._base is not None: self._base.allocated_views -= 1 del self._buf @@ -160,7 +158,12 @@ class Buffer: self.copyout(memoryview(buf)) return self.__class__, (self.device, self.size, self.dtype, None, self.options, buf, self.uop_refcount) @property + def trace_num(self) -> int: + if not hasattr(self, '_trace_num'): self._trace_num = len(Buffer.profile_events) + return self._trace_num + @property def nbytes(self): return self.size*self.dtype.itemsize + @suppress_finalizing def __del__(self): (not hasattr(self, '_buf')) or self.deallocate() def __repr__(self): return f" bytes: return src.encode() # NOTE: empty compiler is the default def compile_cached(self, src:str) -> bytes: if self.cachekey is None or (lib := diskcache_get(self.cachekey, src)) is None: @@ -288,8 +291,8 @@ class Compiled: if len(enable_comps) > 1: raise RuntimeError(f"{self.device}: multiple compilers set in env {enable_comps}") for _, comp_pair in disable_comps: self.compilers.remove(comp_pair) - try: self.renderer, self.compiler = next(self._get_available_compilers([list(enable_comps)[0][1]] if len(enable_comps) == 1 else self.compilers)) - except StopIteration as exc: raise RuntimeError(f"no usable compilers for {self.device}") from exc + self.renderer, self.compiler = select_first_inited([list(enable_comps)[0][1]] if len(enable_comps) == 1 else self.compilers, + f"No compiler for {self.device} is available") if DEBUG >= 1: print(f"{self.device}: using {self.compiler.__class__.__name__}") @@ -297,10 +300,6 @@ class Compiled: compiler_name = f"{unwrap_class_type(c).__name__.upper().removesuffix('COMPILER').removeprefix(devname:=self.device.split(':')[0].upper())}" return f"{devname}_{compiler_name if len(compiler_name) > 0 else unwrap_class_type(c).__name__.upper()}" - def _get_available_compilers(self, compilers) -> Iterator[tuple[Renderer, Compiler]]: - for renderer, compiler in compilers: - with contextlib.suppress(Exception): yield renderer(), compiler() - def synchronize(self): """ Synchronize all pending operations on the device. @@ -325,10 +324,13 @@ def is_dtype_supported(dtype:DType, device:str|None=None) -> bool: if device is None: device = Device.DEFAULT if dtype == dtypes.bfloat16: if device == "METAL": return not CI - if device in {"CUDA", "NV"}: return not CI and not getenv(f"{device}_PTX") - if device in {"CPU"}: return not CI and platform.machine() in {"arm", "arm64", "aarch64", "x86_64", "amd64"} + if device in {"CUDA", "NV"}: return not CI and not getenv(f"{device}_PTX") and not getenv("NV_NAK") + if device in {"CPU"}: return not CI and platform.machine() in {"arm", "arm64", "aarch64", "x86_64", "amd64"} and not getenv("CPU_LVP") return device in {"AMD", "PYTHON", "NULL"} - if dtype in dtypes.fp8s: return device in {"PYTHON", "NULL"} + if dtype in dtypes.fp8s: + if device in {"CUDA", "NV"}: return not CI and not getenv(f"{device}_PTX") and not getenv("NV_NAK") + if device == "AMD": return not CI and not AMD_LLVM and getattr(Device["AMD"], "target") in {(9,4,2), (9,5,0)} + return device in {"PYTHON", "NULL"} if device == "WEBGPU": return dtype in [dtypes.bool, dtypes.char, dtypes.uchar, dtypes.short, dtypes.ushort, dtypes.float, dtypes.int32, dtypes.uint32, dtypes.half] # for CI GPU and OSX, cl_khr_fp16 isn't supported @@ -337,6 +339,7 @@ def is_dtype_supported(dtype:DType, device:str|None=None) -> bool: # PYTHON supports half memoryview in 3.12+ https://github.com/python/cpython/issues/90751 if dtype == dtypes.half: if device == "CL": return not CI and not OSX + if device == "QCOM": return False # QCOM compiler is flaky with half if device in ["CUDA", "NV"]: return not CI if device == "CPU" and CPU_LLVM: return OSX if device == "PYTHON": return sys.version_info >= (3, 12) @@ -355,7 +358,7 @@ if PROFILE: from tinygrad.uop.ops import launch_viz launch_viz("PROFILE", fn) -if __name__ == "__main__": +def enumerate_devices_str() -> Generator[str, None, None]: from tinygrad import Tensor, Device for device in ALL_DEVICES: @@ -374,4 +377,7 @@ if __name__ == "__main__": result = (colored('PASS', 'green') if any_works else f"{colored('FAIL', 'yellow')}") + ''.join([f'\n{" "*16} {x}' for x in compilers_results]) except Exception as e: result = f"{colored('FAIL', 'red')} {e}" - print(f"{'*' if device == Device.DEFAULT else ' '} {device:10s}: {result}") + yield f"{'*' if device == Device.DEFAULT else ' '} {device:10s}: {result}" + +if __name__ == "__main__": + for s in enumerate_devices_str(): print(s) diff --git a/tinygrad/dtype.py b/tinygrad/dtype.py index 11373bb3a8..09d00bab0c 100644 --- a/tinygrad/dtype.py +++ b/tinygrad/dtype.py @@ -7,13 +7,15 @@ from enum import Enum, auto class InvalidTypeMetaClass(type): instance:None|InvalidType = None - def __call__(cls, *args, **kwargs): + def __call__(cls): if (ret:=InvalidTypeMetaClass.instance) is not None: return ret InvalidTypeMetaClass.instance = ret = super().__call__() return ret class InvalidType(metaclass=InvalidTypeMetaClass): def __eq__(self, other): return self is other + def __lt__(self, other): return self is not other + def __gt__(self, other): return self is not other def __hash__(self): return id(self) def __repr__(self): return "Invalid" def __reduce__(self): return (InvalidType, ()) # Return the global Invalid instance @@ -47,7 +49,7 @@ class DType(metaclass=DTypeMetaClass): @staticmethod def new(priority:int, itemsize:int, name:str, fmt:FmtStr|None): return DType(priority, itemsize, name, fmt, 1, None) def __reduce__(self): return type(self), tuple(getattr(self, f.name) for f in fields(self)) - def __repr__(self): return f"dtypes.{INVERSE_DTYPES_DICT[self.scalar().name]}"+(f".vec({self.count})" if self.count > 1 else "") + def __repr__(self): return f"dtypes.{INVERSE_DTYPES_DICT[self.scalar().name]}"+(f".vec({self.count})" if self.count != 1 else "") def __lt__(self, o:DType): return (self.priority, self.itemsize, self.name, self.fmt, self.count) < (o.priority, o.itemsize, o.name, o.fmt, o.count) @property def base(self): return self @@ -61,7 +63,7 @@ class DType(metaclass=DTypeMetaClass): def ptr(self, size=-1, addrspace=AddrSpace.GLOBAL) -> PtrDType: return PtrDType(self.priority, self.itemsize, self.name, self.fmt, self.count, None, self, addrspace, 1, size) def scalar(self) -> DType: return self._scalar if self._scalar is not None else self - def nbytes(self): raise RuntimeError("only ptr types have nbytes") + def nbytes(self) -> int: raise RuntimeError("only ptr types have nbytes") @property def min(self): return dtypes.min(self) @property @@ -82,7 +84,7 @@ class PtrDType(DType): if isinstance(self, ImageDType): return ImageDType(self.priority, self.itemsize, self.name, self.fmt, self.count, self, self._base, self.addrspace, sz, self.size, self.shape) return type(self)(self.priority, self.itemsize, self.name, self.fmt, self.count, self, self._base, self.addrspace, sz, self.size) - def ptr(self, size=-1, addrspace=AddrSpace.GLOBAL): raise RuntimeError("can't make a pointer from a pointer") + def ptr(self, size=-1, addrspace=AddrSpace.GLOBAL) -> PtrDType: raise RuntimeError("can't make a pointer from a pointer") def nbytes(self) -> int: if self.size == -1: raise RuntimeError("can't get nbytes of a pointer with unlimited size") return self.size*self.itemsize @@ -183,7 +185,7 @@ class dtypes: uints = (uint8, uint16, uint32, uint64) sints = (int8, int16, int32, int64) ints = uints + sints - all = floats + ints + (bool, index) + all = floats + ints + (bool, index) # noqa: A003 if (env_default_float := getenv("DEFAULT_FLOAT", "")): dtypes.default_float = getattr(dtypes, env_default_float.lower()) @@ -219,9 +221,9 @@ def can_safe_cast(dt0:DType, dt1:DType) -> bool: if dt0 == dt1 or dt0 == dtypes.bool: return True match dt1: case dtypes.index: return dt0 in dtypes.ints - case dtypes.double: return dt0 in (dtypes.float, dtypes.half, dtypes.bfloat16, + case dtypes.double: return dt0 in (dtypes.float, dtypes.half, dtypes.bfloat16, *dtypes.fp8s, dtypes.uint32, dtypes.uint16, dtypes.uint8, dtypes.int32, dtypes.int16, dtypes.int8) - case dtypes.float: return dt0 in (dtypes.half, dtypes.bfloat16, dtypes.uint16, dtypes.uint8, dtypes.int16, dtypes.int8) + case dtypes.float: return dt0 in (dtypes.half, dtypes.bfloat16, *dtypes.fp8s, dtypes.uint16, dtypes.uint8, dtypes.int16, dtypes.int8) case dtypes.uint64: return dt0 in (dtypes.uint32, dtypes.uint16, dtypes.uint8) case dtypes.uint32: return dt0 in (dtypes.uint16, dtypes.uint8) case dtypes.int64: return dt0 in (dtypes.uint32, dtypes.uint16, dtypes.uint8, dtypes.int32, dtypes.int16, dtypes.int8) diff --git a/tinygrad/engine/jit.py b/tinygrad/engine/jit.py index 6cc2612d7b..834a401d0a 100644 --- a/tinygrad/engine/jit.py +++ b/tinygrad/engine/jit.py @@ -5,10 +5,10 @@ from tinygrad.helpers import flatten, merge_dicts, DEBUG, Context, BEAM, getenv, from tinygrad.device import Buffer, Compiled, Device, MultiBuffer from tinygrad.dtype import DType from tinygrad.uop.ops import UOp, Variable, sym_infer, Ops -from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.engine.realize import ExecItem, capturing, ViewOp, BufferCopy, BufferXfer, CompiledRunner, Runner, Estimates from tinygrad.engine.memory import _internal_memory_planner from tinygrad.nn.state import get_parameters +from tinygrad.schedule.rangeify import mop_cleanup from dataclasses import dataclass from weakref import WeakKeyDictionary @@ -158,7 +158,7 @@ class CapturedJit(Generic[ReturnType]): input_replace: dict[tuple[int, int], int] extra_view_inputs: list[tuple[int, int, str, int, DType]] expected_names: list[int|str] - expected_st_vars_dtype_device: list[tuple[ShapeTracker, tuple[Variable, ...], DType, str]] + expected_st_vars_dtype_device: list[tuple[UOp, tuple[Variable, ...], DType, str]] def __reduce__(self): # TODO: free_intermediates here? replan_buffers_memory_layout here? @@ -224,7 +224,7 @@ def _prepare_jit_inputs(args, kwargs): input_buffers: list[Buffer] = flatten([rb.bufs if isinstance(rb:=lb.base.realized, MultiBuffer) else [rb] for lb in lbs if lb.base.realized is not None]) assert len(set(input_buffers)) == len(input_buffers), "duplicate inputs to JIT" - st_varval_dtype_device = [(*unwrap(lb.st).unbind(), lb.dtype, lb.device) for lb in lbs] + st_varval_dtype_device = [(*(lb.substitute({lb.base:UOp(Ops.NOOP)}, extra_pm=mop_cleanup).unbind_all()), lb.dtype, lb.device) for lb in lbs] _var_vals = merge_dicts([x[1] for x in st_varval_dtype_device] + [dict(v.unbind() for v in (args + tuple(kwargs.values())) if isinstance(v, UOp))]) var_vals = {k.expr:v for k,v in _var_vals.items()} st_vars_dtype_device = [(x[0], tuple(sorted(x[1].keys(), key=lambda v: v.expr)), x[2], x[3]) for x in st_varval_dtype_device] diff --git a/tinygrad/engine/realize.py b/tinygrad/engine/realize.py index 50474a6284..770eb280ca 100644 --- a/tinygrad/engine/realize.py +++ b/tinygrad/engine/realize.py @@ -3,6 +3,7 @@ import time, pprint, random, itertools, math from dataclasses import dataclass, replace, field from tinygrad.helpers import all_same, colored, DEBUG, GlobalCounters, ansilen, BEAM, NOOPT, all_int, CAPTURING, Metadata, TRACEMETA, TracingKey from tinygrad.helpers import DEVECTORIZE, time_to_str, VALIDATE_WITH_CPU, getenv, cpu_profile, PROFILE, ProfilePointEvent, cpu_events, prod, Context +from tinygrad.helpers import unwrap, disable_gc from tinygrad.uop.ops import Ops, PatternMatcher, UOp, UPat, sym_infer, graph_rewrite, print_uops, track_rewrites, KernelInfo, pyrender from tinygrad.device import Device, Buffer from tinygrad.renderer import Renderer, ProgramSpec, Estimates @@ -12,6 +13,7 @@ from tinygrad.codegen.opt import Opt # **************** Program Creation **************** +@disable_gc() @track_rewrites(name=lambda *args,ret,**kwargs: TracingKey(ret.name, (ret.function_name, ret.ast), ret=ret), replay=True) def get_program(ast:UOp, renderer:Renderer|None=None, opts:list[Opt]|None=None) -> ProgramSpec: """ @@ -26,7 +28,7 @@ def get_program(ast:UOp, renderer:Renderer|None=None, opts:list[Opt]|None=None) """ if getenv("VIZ"): graph_rewrite(ast, PatternMatcher([]), name="View Base AST") - if DEBUG >= 5: print('\n'.join(pyrender(ast))) + if DEBUG >= 5: print(pyrender(ast)) # linearize if renderer is None: renderer = Device.default.renderer @@ -38,7 +40,7 @@ def get_program(ast:UOp, renderer:Renderer|None=None, opts:list[Opt]|None=None) except RuntimeError as e: print("***** LINEARIZE FAILURE *****") print(e) - print('\n'.join(pyrender(ast))) + print(pyrender(ast)) raise assert uops[-1].op is Ops.SINK, "last uop must be sink" @@ -78,6 +80,7 @@ def optimize_local_size(_prg:Callable, global_size:list[int], rawbufs:list[Buffe class CompiledRunner(Runner): def __init__(self, p:ProgramSpec, precompiled:bytes|None=None, prg=None): + if DEBUG >= 3: print(p.applied_opts) if DEBUG >= 4: print(p.src) self.p:ProgramSpec = p if precompiled is not None: self.lib = precompiled @@ -90,7 +93,8 @@ class CompiledRunner(Runner): def __reduce__(self): return self.__class__, (self.p, self.lib) - def __call__(self, rawbufs:list[Buffer], var_vals:dict[str, int], wait=False) -> float|None: + def __call__(self, rawbufs:list[Buffer], var_vals:dict[str, int]|None=None, wait=False) -> float|None: + if var_vals is None: var_vals = {} has_local = Device[self.p.device].renderer.has_local global_size, local_size = self.p.launch_dims(var_vals) if has_local and global_size is not None and local_size is None and all_int(self.p.global_size): # type: ignore[arg-type] @@ -121,7 +125,7 @@ class BufferCopy(Runner): getattr(src.allocator.dev, 'fd', None) is not None and dest.allocator.supports_copy_from_disk if src.device.startswith("DISK") and hasattr(dest.allocator, 'copy_from_disk') and disk_supports_fast_copyout and src.nbytes >= 4096: dest.allocator.copy_from_disk(dest._buf, src._buf, src.nbytes) - elif src.device.startswith("DISK") and hasattr(dest.allocator, '_as_buffer'): + elif (src.device.startswith("DISK") or src.device.startswith("TINYFS")) and hasattr(dest.allocator, '_as_buffer'): # fast(ish) path, uses readinto in diskbuffers src.allocator._copyout(dest.allocator._as_buffer(dest._buf), src._buf) else: @@ -164,8 +168,11 @@ class ExecItem: fixedvars: dict[str, int] = field(default_factory=dict) def run(self, _var_vals:dict[str, int]|None=None, wait=False, jit=False, do_update_stats=True) -> float|None: var_vals = self.fixedvars if _var_vals is None else (_var_vals|self.fixedvars) - bufs = [cast(Buffer, x) for x in self.bufs] if jit else [cast(Buffer, x).ensure_allocated() for x in self.bufs] - if PROFILE: cpu_events.append(ProfilePointEvent(self.prg.device, "exec", self.prg.display_name, {"metadata":self.metadata, "var_vals":var_vals})) + bufs = [unwrap(x) for x in self.bufs] if jit else [unwrap(x).ensure_allocated() for x in self.bufs] + if PROFILE: + payload = {"metadata":self.metadata, "var_vals":var_vals, "bufs":[b.trace_num for b in bufs], "name":self.prg.display_name} + payload["outputs"], payload["inputs"] = (self.prg.p.outs, self.prg.p.ins) if isinstance(self.prg, CompiledRunner) else ([0], [1]) + cpu_events.append(ProfilePointEvent(self.prg.device, "exec", len(cpu_events), payload)) et = self.prg(bufs, var_vals, wait=wait or DEBUG >= 2) if do_update_stats: GlobalCounters.kernel_count += 1 @@ -178,10 +185,11 @@ class ExecItem: header_color = 'magenta' if jit else ('green' if self.prg.first_run else None) ptm = colored(time_to_str(et, w=9), "yellow" if et > 0.01 else None) if et is not None else "" flops, membw, ldsbw = op_est/(et or 1e-20), mem_est/(et or 1e-20), lds_est/(et or 1e-20) - flops_str = f"{flops*1e-9:9.2f} GFLOPS" if flops < 1e14 else colored(f"{flops*1e-12:9.2f} TFLOPS", 'green') - mem_str = f"{membw*1e-9:6.1f}|{ldsbw*1e-9:<7.1f} GB/s" if membw < 1e13 else colored(f"{membw*1e-12:6.1f}|{ldsbw*1e-12:<7.1f} TB/s", 'green') + flops_str = f"{flops*1e-9:7.0f} GFLOPS" if flops < 1e14 else colored(f"{flops*1e-12:7.0f} TFLOPS", 'green') + mem_str = f"{membw*1e-9:4.0f}|{ldsbw*1e-9:<6.0f} GB/s" if membw < 1e13 and ldsbw < 1e15 else \ + colored(f"{membw*1e-12:4.0f}|{ldsbw*1e-12:<6.0f} TB/s", 'green') print(f"{colored(f'*** {self.prg.device[:7]:7s} {GlobalCounters.kernel_count:4d}', header_color)}"+ - f" {self.prg.display_name+' '*(44-ansilen(self.prg.display_name))} arg {len(bufs):2d} mem {GlobalCounters.mem_used/1e9:5.2f} GB"+ + f" {self.prg.display_name+' '*(46-ansilen(self.prg.display_name))} arg {len(bufs):2d} mem {GlobalCounters.mem_used/1e9:6.2f} GB"+ ("" if et is None else f" tm {ptm}/{GlobalCounters.time_sum_s*1e3:9.2f}ms ({flops_str} {mem_str})")+ f" {[repr(m) if TRACEMETA >= 2 else str(m) for m in self.metadata] if self.metadata else ''}") self.prg.first_run = False diff --git a/tinygrad/engine/schedule.py b/tinygrad/engine/schedule.py index e56c908309..655cd0d242 100644 --- a/tinygrad/engine/schedule.py +++ b/tinygrad/engine/schedule.py @@ -22,18 +22,18 @@ def create_schedule_with_vars(sched_sink:UOp) -> tuple[list[ScheduleItem], dict[ in_degree: dict[UOp, int] = {} var_vals: dict[str, int] = {} for u in sched_sink.toposort(): - if u.op is not Ops.ASSIGN: continue # anything that's not an ASSIGN doesn't write a kernel, so we can skip + if u.op is not Ops.AFTER: continue # anything that's not an ASSIGN doesn't write a kernel, so we can skip k = u.src[1] in_degree.setdefault(k, 0) for s in k.src: - if s.op is Ops.ASSIGN: + if s.op is Ops.AFTER: children[s.src[1]].append(k) in_degree[k] += 1 elif s.op in {Ops.MSELECT, Ops.MSTACK}: for ss in s.src: if ss.op is Ops.MSELECT: ss = ss.src[0] if ss.op is not Ops.BUFFER: - assert ss.op is Ops.ASSIGN, f"ss.op is not ASSIGN, it's {ss.op}" + assert ss.op is Ops.AFTER, f"ss.op is not AFTER, it's {ss.op}" children[ss.src[1]].append(k) in_degree[k] += 1 elif s.op is Ops.BUFFER: @@ -43,7 +43,7 @@ def create_schedule_with_vars(sched_sink:UOp) -> tuple[list[ScheduleItem], dict[ assert var.expr not in var_vals or var_vals[var.expr] == val, f"bind mismatch on {var}, {var_vals[var.expr]} != {val}" var_vals[var.expr] = val else: - raise RuntimeError(f"input to kernel must be ASSIGN or BUFFER, not {s.op}") + raise RuntimeError(f"input to kernel must be AFTER or BUFFER, not {s.op}") # linearize KERNEL UOps into ScheduleItems in BFS order diff --git a/tinygrad/frontend/__init__.py b/tinygrad/frontend/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tinygrad/gradient.py b/tinygrad/gradient.py index c538555ad2..23e6e5dce0 100644 --- a/tinygrad/gradient.py +++ b/tinygrad/gradient.py @@ -4,18 +4,18 @@ from tinygrad.uop.ops import UOp, PatternMatcher, UPat, Ops, all_metadata from tinygrad.helpers import argsort def reduce_gradient(ctx:UOp, ret:UOp): - def to_inp_shape(x): return x.reshape(x.shape+(1,)*(len(ret.src[0].shape)-len(x.shape))).expand(ret.src[0].shape) - if ret.arg[0] == Ops.ADD: return (to_inp_shape(ctx),) + def broadcast_to_input(x): return x.reshape(x.shape+(1,)*(len(ret.src[0].shape)-len(x.shape))).expand(ret.src[0].shape) + if ret.arg[0] == Ops.ADD: return (broadcast_to_input(ctx),) if ret.arg[0] == Ops.MAX: - max_is_1s = ret.src[0].eq(to_inp_shape(ret)).cast(ctx.dtype) - div = to_inp_shape(max_is_1s.r(Ops.ADD, ret.arg[1])) - return ((max_is_1s/div) * to_inp_shape(ctx),) - if ret.arg[0] == Ops.MUL: return (to_inp_shape(ctx * ret) / ret.src[0],) + mask = ret.src[0].eq(broadcast_to_input(ret)).cast(ctx.dtype) + count = mask.r(Ops.ADD, ret.arg[1]) + return ((mask/broadcast_to_input(count)) * broadcast_to_input(ctx),) + if ret.arg[0] == Ops.MUL: return (broadcast_to_input(ctx * ret) / ret.src[0],) # ctx is grad_output pm_gradient = PatternMatcher([ (UPat(Ops.CAST, name="ret"), lambda ctx, ret: (ctx.cast(ret.src[0].dtype),)), - (UPat(Ops.RECIP, name="ret"), lambda ctx, ret: (-ctx * ret * ret,)), + (UPat(Ops.RECIPROCAL, name="ret"), lambda ctx, ret: (-ctx * ret * ret,)), (UPat(Ops.SIN, name="ret"), lambda ctx, ret: ((math.pi/2 - ret.src[0]).sin() * ctx,)), (UPat(Ops.LOG2, name="ret"), lambda ctx, ret: (ctx / (ret.src[0] * math.log(2)),)), (UPat(Ops.EXP2, name="ret"), lambda ctx, ret: (ret * ctx * math.log(2),)), @@ -24,22 +24,25 @@ pm_gradient = PatternMatcher([ (UPat(Ops.ADD), lambda ctx: (ctx, ctx)), (UPat(Ops.POW, name="ret", src=(UPat.var("b"), UPat.var("e"))), lambda ctx, ret, b, e: (ctx * (b.eq(0)&e.eq(0)).where(e, e*b.pow(e-1)), ctx * b.eq(0).where((e<0).where(ret.const_like(-math.inf), 0), ret*b.log2()*math.log(2.0)))), - (UPat(Ops.MAX, name="ret", src=(UPat.var("x"), UPat.var("y"))), lambda ctx, ret, x, y: + (UPat(Ops.MAX, src=(UPat.var("x"), UPat.var("y"))), lambda ctx, x, y: ((x>y).where(ctx, (x.eq(y)).where(ctx * 0.5, 0)), (x list[UOp]: @@ -60,5 +63,9 @@ def compute_gradient(root:UOp, root_grad:UOp, targets:set[UOp]) -> dict[UOp, UOp if v is None: continue if k in grads: grads[k] = grads[k] + v else: grads[k] = v - if len(forward_metadata:=all_metadata.get(t0, ())): all_metadata[v] = tuple(dataclasses.replace(x, backward=True) for x in forward_metadata) + if len(forward_metadata:=all_metadata.get(t0, ())): + backward_metadata = tuple(dataclasses.replace(x, backward=True) for x in forward_metadata) + # we add the backward metadata to everything new in the graph + for bw_uop in v.toposort(lambda x: x not in (t0, *t0.src, grads[t0])): + all_metadata[bw_uop] = all_metadata.get(bw_uop, ())+backward_metadata return grads diff --git a/tinygrad/helpers.py b/tinygrad/helpers.py index a9b63afdb6..a780be1ccd 100644 --- a/tinygrad/helpers.py +++ b/tinygrad/helpers.py @@ -1,8 +1,8 @@ from __future__ import annotations -import os, functools, platform, time, re, contextlib, operator, hashlib, pickle, sqlite3, tempfile, pathlib, string, ctypes, sys, gzip, getpass -import urllib.request, subprocess, shutil, math, types, copyreg, inspect, importlib, decimal +import os, functools, platform, time, re, contextlib, operator, hashlib, pickle, sqlite3, tempfile, pathlib, string, ctypes, sys, gzip, getpass, gc +import urllib.request, subprocess, shutil, math, types, copyreg, inspect, importlib, decimal, itertools from dataclasses import dataclass, field -from typing import ClassVar, Iterable, Any, TypeVar, Callable, Sequence, TypeGuard, Iterator, Generic, Generator +from typing import ClassVar, Iterable, Any, TypeVar, Callable, Sequence, TypeGuard, Iterator, Generic, Generator, cast, overload T = TypeVar("T") U = TypeVar("U") @@ -23,10 +23,13 @@ def argfix(*x): if len(x) != 1: raise ValueError(f"bad arg {x}") return tuple(x[0]) return x -def argsort(x): return type(x)(sorted(range(len(x)), key=x.__getitem__)) # https://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python +# https://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python +def argsort(x): return type(x)(sorted(range(len(x)), key=x.__getitem__)) def all_same(items:tuple[T, ...]|list[T]): return all(x == items[0] for x in items) def all_int(t: Sequence[Any]) -> TypeGuard[tuple[int, ...]]: return all(isinstance(s, int) for s in t) -def colored(st, color:str|None, background=False): return f"\u001b[{10*background+60*(color.upper() == color)+30+['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'].index(color.lower())}m{st}\u001b[0m" if color is not None else st # replace the termcolor library with one line # noqa: E501 +def colored(st, color:str|None, background=False): # replace the termcolor library + colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'] + return f"\u001b[{10*background+60*(color.upper() == color)+30+colors.index(color.lower())}m{st}\u001b[0m" if color is not None else st def colorize_float(x: float): return colored(f"{x:7.2f}x", 'green' if x < 0.75 else 'red' if x > 1.15 else 'yellow') def time_to_str(t:float, w=8) -> str: return next((f"{t * d:{w}.2f}{pr}" for d,pr in [(1, "s "),(1e3, "ms")] if t > 10/d), f"{t * 1e6:{w}.2f}us") def ansistrip(s:str): return re.sub('\x1b\\[(K|.*?m)', '', s) @@ -41,7 +44,8 @@ def fully_flatten(l): return flattened return [l] def fromimport(mod, frm): return getattr(__import__(mod, fromlist=[frm]), frm) -def strip_parens(fst:str): return fst[1:-1] if fst[0] == '(' and fst[-1] == ')' and fst[1:-1].find('(') <= fst[1:-1].find(')') else fst +def _is_balanced(s:str) -> bool: return (d := 0, all((d := d + (c == '(') - (c == ')')) >= 0 for c in s))[1] and d == 0 +def strip_parens(fst:str) -> str: return fst[1:-1] if fst and fst[0]=='(' and fst[-1] == ')' and _is_balanced(fst[1:-1]) else fst def ceildiv(num, amt): return int(ret) if isinstance((ret:=-(num//-amt)), float) else ret def round_up(num:int, amt:int) -> int: return (num+amt-1)//amt * amt def round_down(num:int, amt:int) -> int: return -round_up(-num, amt) @@ -81,15 +85,43 @@ def word_wrap(x, wrap=80): i = 0 while len(ansistrip(x[:i])) < wrap and i < len(x): i += 1 return x[:i] + "\n" + word_wrap(x[i:], wrap) +def pad_bytes(b:bytes, align:int) -> bytes: return b + b'\x00' * ((align - (len(b) % align)) % align) +def panic(e:Exception|None=None): + if e is None: raise RuntimeError("PANIC!") + raise e + +@functools.cache +def canonicalize_strides(shape:tuple[T, ...], strides:tuple[T, ...]) -> tuple[T, ...]: + return tuple(cast(T, 0) if s == 1 else st for s, st in zip(shape, strides)) + +@functools.cache +def strides_for_shape(shape:tuple[T, ...]) -> tuple[T, ...]: + if not shape: return () + strides = tuple(itertools.accumulate(reversed(shape[1:]), operator.mul, initial=1))[::-1] + return canonicalize_strides(shape, strides) + +# returns the axes to create new_shape if new_shape can be created by combining axis from old_shape +def get_contraction(old_shape:tuple[T, ...], new_shape:tuple[T, ...]) -> list[list[int]]|None: # T is sint + acc_old, acc_new = list(itertools.accumulate(old_shape, operator.mul)), list(itertools.accumulate(new_shape, operator.mul)) + try: split = [acc_old.index(acc)+1 if acc != 1 else 0 for acc in acc_new] + except ValueError: return None + return [list(range(st,ed)) for st,ed in zip([0]+split[:-1], split[:-1]+[len(old_shape)])] def suppress_finalizing(func): def wrapper(*args, **kwargs): try: return func(*args, **kwargs) - except (AttributeError, TypeError, ImportError): + except (RuntimeError, AttributeError, TypeError, ImportError): if not getattr(sys, 'is_finalizing', lambda: True)(): raise # re-raise if not finalizing return wrapper -def unwrap_class_type(cls_t:T): return cls_t.func if isinstance(cls_t, functools.partial) else cls_t +def select_first_inited(candidates:Sequence[Callable[...,T]|Sequence[Callable[...,T]]], err_msg: str) -> tuple[T,...]|T: + excs = [] + for typ in candidates: + try: return tuple([cast(Callable, t)() for t in typ]) if isinstance(typ, Sequence) else cast(Callable, typ)() + except Exception as e: excs.append(e) + raise ExceptionGroup(err_msg, excs) + +def unwrap_class_type(cls_t): return cls_t.func if isinstance(cls_t, functools.partial) else cls_t def pluralize(st:str, cnt:int): return f"{cnt} {st}"+('' if cnt == 1 else 's') @@ -102,8 +134,13 @@ def polyN(x:T, p:list[float]) -> T: return functools.reduce(lambda acc,c: acc*x+ @functools.cache def to_function_name(s:str): return ''.join([c if c in (string.ascii_letters+string.digits+'_') else f'{ord(c):02X}' for c in ansistrip(s)]) +@overload +def getenv(key:str) -> int: ... +@overload +def getenv(key:str, default:T) -> T: ... @functools.cache -def getenv(key:str, default=0): return type(default)(os.getenv(key, default)) +def getenv(key:str, default:Any=0): return type(default)(os.getenv(key, default)) + def temp(x:str, append_user:bool=False) -> str: return (pathlib.Path(tempfile.gettempdir()) / (f"{x}.{getpass.getuser()}" if append_user else x)).as_posix() @@ -133,23 +170,25 @@ JIT, JIT_BATCH_SIZE = ContextVar("JIT", 2 if OSX and ARCH_X86 else 1), ContextVa WINO, CAPTURING, TRACEMETA = ContextVar("WINO", 0), ContextVar("CAPTURING", 1), ContextVar("TRACEMETA", 1) USE_TC, TC_SELECT, TC_OPT, AMX = ContextVar("TC", 1), ContextVar("TC_SELECT", -1), ContextVar("TC_OPT", 0), ContextVar("AMX", 0) TRANSCENDENTAL, NOLOCALS = ContextVar("TRANSCENDENTAL", 1), ContextVar("NOLOCALS", 0) -FUSE_ARANGE, FUSE_CONV_BW = ContextVar("FUSE_ARANGE", 1), ContextVar("FUSE_CONV_BW", 0) SPLIT_REDUCEOP, NO_MEMORY_PLANNER, RING = ContextVar("SPLIT_REDUCEOP", 1), ContextVar("NO_MEMORY_PLANNER", 0), ContextVar("RING", 1) PICKLE_BUFFERS, LRU = ContextVar("PICKLE_BUFFERS", 1), ContextVar("LRU", 1) CACHELEVEL, IGNORE_BEAM_CACHE, DEVECTORIZE = ContextVar("CACHELEVEL", 2), ContextVar("IGNORE_BEAM_CACHE", 0), ContextVar("DEVECTORIZE", 1) -DISABLE_COMPILER_CACHE, BLOCK_REORDER = ContextVar("DISABLE_COMPILER_CACHE", 0), ContextVar("BLOCK_REORDER", 1) -DONT_REALIZE_EXPAND, DONT_GROUP_REDUCES = ContextVar("DONT_REALIZE_EXPAND", 0), ContextVar("DONT_GROUP_REDUCES", 0) -QUANTIZE, VALIDATE_WITH_CPU, DISABLE_FAST_IDIV = ContextVar("QUANTIZE", 0), ContextVar("VALIDATE_WITH_CPU", 0), ContextVar("DISABLE_FAST_IDIV", 0) +VALIDATE_WITH_CPU, DISABLE_FAST_IDIV = ContextVar("VALIDATE_WITH_CPU", 0), ContextVar("DISABLE_FAST_IDIV", 0) CORRECT_DIVMOD_FOLDING, FUSE_OPTIM = ContextVar("CORRECT_DIVMOD_FOLDING", 0), ContextVar("FUSE_OPTIM", 0) ALLOW_DEVICE_USAGE, MAX_BUFFER_SIZE = ContextVar("ALLOW_DEVICE_USAGE", 1), ContextVar("MAX_BUFFER_SIZE", 0) -RANGEIFY, FUSE_ATTENTION = ContextVar("RANGEIFY", 0), ContextVar("FUSE_ATTENTION", 0) EMULATE = ContextVar("EMULATE", "") -CPU_COUNT = ContextVar("CPU_COUNT", max(1, (os.cpu_count() or 1) // (4 if ARCH_X86 else 2))) # take 1/2 of the cores, accounting HT -CPU_LLVM, AMD_LLVM = ContextVar("CPU_LLVM", 0), ContextVar("AMD_LLVM", 1) +CPU_COUNT = ContextVar("CPU_COUNT", max(1, len(os.sched_getaffinity(0)) if hasattr(os, "sched_getaffinity") else (os.cpu_count() or 1))) +CPU_LLVM, CPU_LVP, AMD_LLVM = ContextVar("CPU_LLVM", 0), ContextVar("CPU_LVP", 0), ContextVar("AMD_LLVM", 0) VIZ = PROFILE = ContextVar("VIZ", 0) -SPEC = ContextVar("SPEC", 0) +SPEC = ContextVar("SPEC", 1) # TODO: disable by default due to speed IGNORE_OOB = ContextVar("IGNORE_OOB", 1) +PCONTIG = ContextVar("PCONTIG", 0) # partial contiguous in rangeify +DEBUG_RANGEIFY = ContextVar("DEBUG_RANGEIFY", 0) +# set to 1, this uses tuplize in the linearizer sort order +TUPLE_ORDER = ContextVar("TUPLE_ORDER", 1) +# set to 0 to disable the compiler cache +CCACHE = ContextVar("CCACHE", 1) @dataclass(frozen=True) class Metadata: @@ -157,7 +196,6 @@ class Metadata: caller: str backward: bool = False def __hash__(self): return hash(self.name) - def __repr__(self): return str(self) + (f" - {self.caller}" if self.caller else "") def __str__(self): return self.name + (" bw" if self.backward else "") # **************** global state Counters **************** @@ -203,20 +241,39 @@ class Profiling(contextlib.ContextDecorator): def perf_counter_us() -> decimal.Decimal: return decimal.Decimal(time.perf_counter_ns())/1000 +@functools.cache +def lines(fn) -> list[str]: + try: + with open(fn, encoding="utf-8") as f: return f.readlines() + except (FileNotFoundError, OSError): return [] + +def printable(loc:tuple[str, int]) -> str: + try: return lines(loc[0])[loc[1]-1].strip() + except IndexError: return "" + +def get_stacktrace(frm, max_frames=30) -> tuple[tuple, ...]: + ret:list[tuple] = [] + for i in range(max_frames): + if (frm:=frm.f_back) is None: break + ret.append(((fc:=frm.f_code).co_filename, frm.f_lineno, fc.co_name, printable((fc.co_filename, frm.f_lineno)))) + return tuple(ret) + @dataclass(frozen=True) class TracingKey: display_name:str # display name of this trace event keys:tuple[Any, ...]=() # optional keys to search for related traces ret:Any=None + tb:tuple[tuple, ...]|None=field(default_factory=lambda: get_stacktrace(sys._getframe(1)) if VIZ else None) class ProfileEvent: pass @dataclass -class ProfileRangeEvent(ProfileEvent): device:str; name:str|TracingKey; st:decimal.Decimal; en:decimal.Decimal|None=None; is_copy:bool=False # noqa: E702 +class ProfileRangeEvent(ProfileEvent): + device:str; name:str|TracingKey; st:decimal.Decimal; en:decimal.Decimal|None=None; is_copy:bool=False # noqa: E702 @dataclass(frozen=True) -class ProfilePointEvent(ProfileEvent): device:str; name:str; key:Any; arg:dict=field(default_factory=dict); \ - ts:decimal.Decimal=field(default_factory=perf_counter_us) # noqa: E702 +class ProfilePointEvent(ProfileEvent): + device:str; name:str; key:Any; arg:dict=field(default_factory=dict); ts:decimal.Decimal=field(default_factory=perf_counter_us) # noqa: E702 cpu_events:list[ProfileEvent] = [] @contextlib.contextmanager @@ -275,7 +332,8 @@ def diskcache_put(table:str, key:dict|str|int, val:Any, prepickled=False): ltypes = ', '.join(f"{k} {TYPES[type(key[k])]}" for k in key.keys()) cur.execute(f"CREATE TABLE IF NOT EXISTS '{table}_{VERSION}' ({ltypes}, val blob, PRIMARY KEY ({', '.join(key.keys())}))") _db_tables.add(table) - cur.execute(f"REPLACE INTO '{table}_{VERSION}' ({', '.join(key.keys())}, val) VALUES ({', '.join(['?']*len(key))}, ?)", tuple(key.values()) + (val if prepickled else pickle.dumps(val), )) # noqa: E501 + cur.execute(f"REPLACE INTO '{table}_{VERSION}' ({', '.join(key.keys())}, val) VALUES ({', '.join(['?']*len(key))}, ?)", + tuple(key.values()) + (val if prepickled else pickle.dumps(val),)) conn.commit() cur.close() return val @@ -322,10 +380,12 @@ def fetch(url:str, name:pathlib.Path|str|None=None, subdir:str|None=None, gunzip # *** Exec helpers +def system(cmd, **kwargs): return subprocess.check_output(cmd.split(), **kwargs).decode().strip() + def cpu_objdump(lib, objdump_tool='objdump'): with tempfile.NamedTemporaryFile(delete=True) as f: pathlib.Path(f.name).write_bytes(lib) - print(subprocess.check_output([objdump_tool, '-d', f.name]).decode('utf-8')) + print(system(f"{objdump_tool} -d {f.name}")) def capstone_flatdump(lib: bytes): try: import capstone @@ -341,10 +401,10 @@ def capstone_flatdump(lib: bytes): print(f"{instr.address:#08x}: {instr.mnemonic}\t{instr.op_str}") sys.stdout.flush() -def wait_cond(cb, value=True, timeout_ms=10000, msg="") -> bool: +def wait_cond(cb, *args, value=True, timeout_ms=10000, msg="") -> bool: start_time = int(time.perf_counter() * 1000) while int(time.perf_counter() * 1000) - start_time < timeout_ms: - if (val:=cb()) == value: return val + if (val:=cb(*args)) == value: return val raise TimeoutError(f"{msg}. Timed out after {timeout_ms} ms, condition not met: {val} != {value}") # *** ctypes helpers @@ -403,6 +463,13 @@ class tqdm(Generic[T]): class trange(tqdm): def __init__(self, n:int, **kwargs): super().__init__(iterable=range(n), total=n, **kwargs) +class disable_gc(contextlib.ContextDecorator): + def __enter__(self): + self._was_enabled = gc.isenabled() + if self._was_enabled: gc.disable() + def __exit__(self, *exc): + if self._was_enabled: gc.enable() + # *** universal support for code object pickling def _reconstruct_code(*args): return types.CodeType(*args) diff --git a/tinygrad/mixin/__init__.py b/tinygrad/mixin/__init__.py new file mode 100644 index 0000000000..d33a9eb479 --- /dev/null +++ b/tinygrad/mixin/__init__.py @@ -0,0 +1,4 @@ +from tinygrad.mixin.math import MathMixin +from tinygrad.mixin.movement import MovementMixin + +class OpMixin(MathMixin, MovementMixin): pass \ No newline at end of file diff --git a/tinygrad/uop/mathtraits.py b/tinygrad/mixin/math.py similarity index 52% rename from tinygrad/uop/mathtraits.py rename to tinygrad/mixin/math.py index 0de976c90b..10cfa3a5b5 100644 --- a/tinygrad/uop/mathtraits.py +++ b/tinygrad/mixin/math.py @@ -1,15 +1,16 @@ +from typing import Self from tinygrad.uop import Ops -from tinygrad.helpers import T -from tinygrad.dtype import dtypes +from tinygrad.dtype import dtypes, ConstType -class MathTrait: +class MathMixin: # required to implement - def alu(self:T, op:Ops, *src) -> T: raise NotImplementedError - def const_like(self:T, b) -> T: raise NotImplementedError + def alu(self, op:Ops, *src:Self) -> Self: raise NotImplementedError + def const_like(self, b:ConstType) -> Self: raise NotImplementedError # great functions you get! - def ufix(self, x): return self.const_like(x) if not isinstance(x, MathTrait) else x - def _binop(self, op, x, reverse): return self.ufix(x).alu(op, self) if reverse else self.alu(op, self.ufix(x)) + def ufix(self, x:Self|ConstType) -> Self: return self.const_like(x) if not isinstance(x, MathMixin) else x + def _binop(self, op:Ops, x:Self|ConstType, reverse:bool) -> Self: + return self.ufix(x).alu(op, self) if reverse else self.alu(op, self.ufix(x)) def logical_not(self): return self.ne(True) def neg(self): if (dtype:=getattr(self, 'dtype')) is None: raise TypeError(f"MathTraits __neg__ requires a dtype, {self=}") @@ -18,7 +19,7 @@ class MathTrait: if (dtype:=getattr(self, 'dtype')) is not None: if isinstance(dtype, tuple): dtype = dtype[0] if not (dtypes.is_bool(dtype) or dtypes.is_int(dtype)): raise RuntimeError(f"{dtype} is not supported") - def add(self, x, reverse=False): + def add(self, x:Self|ConstType, reverse:bool=False): """ Adds `self` and `x`. Equivalent to `self + x`. @@ -36,7 +37,7 @@ class MathTrait: ``` """ return self._binop(Ops.ADD, x, reverse) - def mul(self, x, reverse=False): + def mul(self, x:Self|ConstType, reverse:bool=False): """ Multiplies `self` and `x`. Equivalent to `self * x`. @@ -55,7 +56,7 @@ class MathTrait: ``` """ return self._binop(Ops.MUL, x, reverse) - def bitwise_and(self, x, reverse=False): + def bitwise_and(self, x:Self|ConstType, reverse:bool=False): """ Computes the bitwise AND of `self` and `x`. Equivalent to `self & x`. @@ -69,7 +70,7 @@ class MathTrait: """ self._check_dtype() return self._binop(Ops.AND, x, reverse) - def bitwise_or(self, x, reverse=False): + def bitwise_or(self, x:Self|ConstType, reverse:bool=False): """ Computes the bitwise OR of `self` and `x`. Equivalent to `self | x`. @@ -83,7 +84,7 @@ class MathTrait: """ self._check_dtype() return self._binop(Ops.OR, x, reverse) - def bitwise_xor(self, x, reverse=False): + def bitwise_xor(self, x:Self|ConstType, reverse:bool=False): """ Computes bitwise xor of `self` and `x`. Equivalent to `self ^ x`. @@ -98,7 +99,7 @@ class MathTrait: """ self._check_dtype() return self._binop(Ops.XOR, x, reverse) - def idiv(self, x, reverse=False): + def idiv(self, x:Self|ConstType, reverse:bool=False): """ Divides `self` by `x`. Equivalent to `self // x`. @@ -110,61 +111,62 @@ class MathTrait: ``` """ return self._binop(Ops.IDIV, x, reverse) - def mod(self, x, reverse=False): return self._binop(Ops.MOD, x, reverse) - def sub(self, x, reverse=False): return self.ufix(x).alu(Ops.ADD, -self) if reverse else self.alu(Ops.ADD, self.ufix(-x)) - def div(self, x, reverse=False): return (self.ufix(x)*self.alu(Ops.RECIP)) if reverse else (self*self.ufix(x).alu(Ops.RECIP)) + def mod(self, x:Self|ConstType, reverse:bool=False): return self._binop(Ops.MOD, x, reverse) + def sub(self, x:Self|ConstType, reverse:bool=False): return self.ufix(x).alu(Ops.ADD, -self) if reverse else self.alu(Ops.ADD, self.ufix(-x)) + def div(self, x:Self|ConstType, reverse:bool=False): + return (self.ufix(x)*self.alu(Ops.RECIPROCAL)) if reverse else (self*self.ufix(x).alu(Ops.RECIPROCAL)) def __neg__(self): return self.neg() - def __add__(self, x): return self.add(x) - def __sub__(self, x): return self.sub(x) - def __mul__(self, x): return self.mul(x) - def __truediv__(self, x): return self.div(x) - def __floordiv__(self, x): return self.idiv(x) # TODO: idiv is trunc div, not floordiv - def __mod__(self, x): return self.mod(x) - def __and__(self, x): return self.bitwise_and(x) - def __or__(self, x): return self.bitwise_or(x) - def __xor__(self, x): return self.bitwise_xor(x) + def __add__(self, x:Self|ConstType): return self.add(x) + def __sub__(self, x:Self|ConstType): return self.sub(x) + def __mul__(self, x:Self|ConstType): return self.mul(x) + def __truediv__(self, x:Self|ConstType): return self.div(x) + def __floordiv__(self, x:Self|ConstType): return self.idiv(x) # TODO: idiv is trunc div, not floordiv + def __mod__(self, x:Self|ConstType): return self.mod(x) + def __and__(self, x:Self|ConstType): return self.bitwise_and(x) + def __or__(self, x:Self|ConstType): return self.bitwise_or(x) + def __xor__(self, x:Self|ConstType): return self.bitwise_xor(x) - def __radd__(self, x): return self.add(x, True) - def __rsub__(self, x): return self.sub(x, True) - def __rmul__(self, x): return self.mul(x, True) - def __rtruediv__(self, x): return self.div(x, True) - def __rfloordiv__(self, x): return self.idiv(x, True) - def __rand__(self, x): return self.bitwise_and(x, True) - def __ror__(self, x): return self.bitwise_or(x, True) - def __rxor__(self, x): return self.bitwise_xor(x, True) - def __rmod__(self, x): return self.mod(x, True) + def __radd__(self, x:Self|ConstType): return self.add(x, True) + def __rsub__(self, x:Self|ConstType): return self.sub(x, True) + def __rmul__(self, x:Self|ConstType): return self.mul(x, True) + def __rtruediv__(self, x:Self|ConstType): return self.div(x, True) + def __rfloordiv__(self, x:Self|ConstType): return self.idiv(x, True) + def __rand__(self, x:Self|ConstType): return self.bitwise_and(x, True) + def __ror__(self, x:Self|ConstType): return self.bitwise_or(x, True) + def __rxor__(self, x:Self|ConstType): return self.bitwise_xor(x, True) + def __rmod__(self, x:Self|ConstType): return self.mod(x, True) - def __lt__(self, x): return self.alu(Ops.CMPLT, self.ufix(x)) - def __gt__(self, x): return self.ufix(x).alu(Ops.CMPLT, self) - def __ge__(self, x): return (self < x).logical_not() - def __le__(self, x): return (self > x).logical_not() + def __lt__(self, x:Self|ConstType): return self.alu(Ops.CMPLT, self.ufix(x)) + def __gt__(self, x:Self|ConstType): return self.ufix(x).alu(Ops.CMPLT, self) + def __ge__(self, x:Self|ConstType): return (self < x).logical_not() + def __le__(self, x:Self|ConstType): return (self > x).logical_not() - def ne(self, x): return self.alu(Ops.CMPNE, self.ufix(x)) - def eq(self, x): return self.ne(x).logical_not() - def __ne__(self, x): return self.ne(x) + def ne(self, x:Self|ConstType): return self.alu(Ops.CMPNE, self.ufix(x)) + def eq(self, x:Self|ConstType): return self.ne(x).logical_not() + def __ne__(self, x:Self|ConstType): return self.ne(x) # type: ignore[override] # NOTE: __eq__ isn't overridden, and means the same thing as is by default - def lshift(self, x, reverse=False): return self._binop(Ops.SHL, x, reverse) - def rshift(self, x, reverse=False): return self._binop(Ops.SHR, x, reverse) - def __lshift__(self, x): return self.lshift(x) - def __rshift__(self, x): return self.rshift(x) - def __rlshift__(self, x): return self.lshift(x, True) - def __rrshift__(self, x): return self.rshift(x, True) + def lshift(self, x:Self|int, reverse:bool=False): return self._binop(Ops.SHL, x, reverse) + def rshift(self, x:Self|int, reverse:bool=False): return self._binop(Ops.SHR, x, reverse) + def __lshift__(self, x:Self|int): return self.lshift(x) + def __rshift__(self, x:Self|int): return self.rshift(x) + def __rlshift__(self, x:Self|int): return self.lshift(x, True) + def __rrshift__(self, x:Self|int): return self.rshift(x, True) - def maximum(self, x): return self.alu(Ops.MAX, self.ufix(x)) - def minimum(self, x): return -(-self).maximum(-x) - def where(self, x, y): - if type(self) is type(x): return self.alu(Ops.WHERE, x, x.ufix(y)) - if type(self) is type(y): return self.alu(Ops.WHERE, y.ufix(x), y) + def maximum(self, x:Self|ConstType): return self.alu(Ops.MAX, self.ufix(x)) + def minimum(self, x:Self|ConstType): return -(-self).maximum(-x) + def where(self, x:Self|ConstType, y:Self|ConstType): + if isinstance(x, type(self)): return self.alu(Ops.WHERE, x, x.ufix(y)) + if isinstance(y, type(self)): return self.alu(Ops.WHERE, y.ufix(x), y) raise RuntimeError("where needs at least one UOp arg") - def threefry(self, seed): return self.alu(Ops.THREEFRY, seed) - def reciprocal(self): return self.alu(Ops.RECIP) + def threefry(self, seed:Self): return self.alu(Ops.THREEFRY, seed) + def reciprocal(self): return self.alu(Ops.RECIPROCAL) def trunc(self): return self.alu(Ops.TRUNC) def sqrt(self): return self.alu(Ops.SQRT) def sin(self): return self.alu(Ops.SIN) def log2(self): return self.alu(Ops.LOG2) def exp2(self): return self.alu(Ops.EXP2) - def pow(self, x): return self.alu(Ops.POW, self.ufix(x)) - def __pow__(self, x): return self.pow(x) + def pow(self, x:Self|ConstType): return self.alu(Ops.POW, self.ufix(x)) + def __pow__(self, x:Self|ConstType): return self.pow(x) diff --git a/tinygrad/mixin/movement.py b/tinygrad/mixin/movement.py new file mode 100644 index 0000000000..e7967885f3 --- /dev/null +++ b/tinygrad/mixin/movement.py @@ -0,0 +1,350 @@ +# mixins add syntactic sugar to Tensor and UOp +import functools +from typing import TypeAlias, TYPE_CHECKING, Self +from tinygrad.uop import Ops +from tinygrad.helpers import prod, argfix, flatten, dedup, make_tuple, ceildiv +from tinygrad.uop.ops import resolve, smax +if TYPE_CHECKING: from tinygrad.uop.ops import UOp +sint: TypeAlias = "UOp | int" + +def _align_left(*shapes:tuple[sint, ...]) -> tuple[tuple[sint, ...], ...]: + # unsqueeze left to make every shape same length + max_dim = max(len(shape) for shape in shapes) + return tuple((1,) * (max_dim - len(shape)) + shape for shape in shapes) + +class MovementMixin: + # required to implement + def _mop(self, op:Ops, arg) -> Self: raise NotImplementedError + @property + def shape(self) -> tuple[sint, ...]: raise NotImplementedError + + # great functions you get! + @property + def ndim(self) -> int: + """ + Returns the number of dimensions in the tensor. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor([[1, 2], [3, 4]]) + print(t.ndim) + ``` + """ + return len(self.shape) + + def numel(self) -> sint: + """ + Returns the total number of elements in the tensor. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) + print(t.numel()) + ``` + """ + return prod(self.shape) + + def _resolve_dim(self, dim:int, *, extra:bool=False) -> int: + total = self.ndim + int(extra) + if not -max(1, total) <= dim <= max(1, total)-1: raise IndexError(f"{dim=} out of range {[-max(1, total), max(1, total)-1]}") + return dim + total if dim < 0 else dim + + def _broadcast_to(self, new_shape:tuple[sint, ...]) -> Self: + if self.shape == new_shape: return self + if self.ndim > len(new_shape): raise ValueError(f"cannot broadcast tensor to fewer dimensions. shape={self.shape} to {new_shape=}") + # first unsqueeze left with 1s https://data-apis.org/array-api/latest/API_specification/broadcasting.html + shape, _ = _align_left(self.shape, new_shape) + # for each dimension, check either dim is 1, or it does not change + if not all(s == ns or s == 1 for s,ns in zip(shape, new_shape)): + raise ValueError(f"cannot broadcast {self.shape} to {new_shape=}") + reshaped = self.reshape(shape) + ret = reshaped._mop(Ops.EXPAND, arg=new_shape) + return reshaped if ret.shape == reshaped.shape else ret + + def expand(self, shape, *args) -> Self: + """ + Returns a tensor that is expanded to the shape that is specified. + Expand can also increase the number of dimensions that a tensor has. + + Passing a `-1` or `None` to a dimension means that its size will not be changed. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor([1, 2, 3]) + print(t.expand(4, -1).numpy()) + ``` + """ + new_shape = tuple(from_ if to == -1 or to is None else to for from_, to in zip(*(_align_left(self.shape, argfix(shape, *args))))) + return self._broadcast_to(new_shape) + + def reshape(self, shape, *args) -> Self: + """ + Returns a tensor with the same data as the original tensor but with a different shape. + `shape` can be passed as a tuple or as separate arguments. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.arange(6) + print(t.reshape(2, 3).numpy()) + ``` + """ + # resolve None and args + new_shape = tuple([s if s is not None else self.shape[i] for i,s in enumerate(argfix(shape, *args))]) + # resolve -1 + if (c := new_shape.count(-1)) > 1: raise RuntimeError(f"only one dimension can be inferred using -1, getting {new_shape}") + if c: new_shape = tuple([-prod(self.shape) // prod(new_shape) if s == -1 else s for s in new_shape]) + if prod(self.shape) != prod(new_shape): raise ValueError(f"size mismatch, can't reshape ({self.shape}) -> ({new_shape})") + ret = self._mop(Ops.RESHAPE, arg=new_shape) + return self if ret.shape == self.shape else ret + + def shrink(self, arg:tuple[tuple[sint, sint]|None, ...]) -> Self: + """ + Returns a tensor that shrinks the each axis based on input arg. + `arg` must have the same length as `self.ndim`. + For each axis, it can be `None`, which means no shrink, or a tuple `(start, end)` that works the same as Python slice. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.arange(9).reshape(3, 3) + print(t.numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.shrink(((None, (1, 3)))).numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.shrink((((0, 2), (0, 2)))).numpy()) + ``` + """ + if self.ndim != len(arg): raise ValueError(f"{self.ndim=} != {len(arg)=}") + ret = self._mop(Ops.SHRINK, arg=[x if x is not None else (0,s) for x,s in zip(arg, self.shape)]) + return self if ret.shape == self.shape else ret + + def permute(self, order, *args) -> Self: + """ + Returns a tensor that is a permutation of the original tensor. + The new tensor has the same data as the original tensor but with the dimensions permuted according to the order specified. + `order` can be passed as a tuple or as separate arguments. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.empty(2, 3, 5) + print(t.shape) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.permute(2, 0, 1).shape) + ``` + """ + order_arg = tuple(self._resolve_dim(x) for x in argfix(order, *args)) + if sorted(order_arg) != list(range(self.ndim)): raise RuntimeError(f"order is not a valid permutation, getting {order_arg}") + return self._mop(Ops.PERMUTE, arg=order_arg) if order_arg != tuple(range(self.ndim)) else self + + def flip(self, axis, *args) -> Self: + """ + Returns a tensor that reverses the order of the original tensor along given `axis`. + `axis` can be passed as a tuple or as separate arguments. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.arange(6).reshape(2, 3) + print(t.numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.flip(0).numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.flip((0, 1)).numpy()) + ``` + """ + axis_arg = tuple(self._resolve_dim(x) for x in argfix(axis, *args)) + assert all(not isinstance(x, bool) and x >= 0 and x < self.ndim for x in axis_arg), f"flip args must be axis ints {axis_arg}" + if len(axis_arg) != len(dedup(axis_arg)): raise RuntimeError(f"dim can appear at most once, getting {axis_arg}") + flip_arg = tuple([i in axis_arg for i in range(len(self.shape))]) + return self._mop(Ops.FLIP, arg=flip_arg) if any(flip_arg) else self + + # **** high level **** + + def shrink_to(self, shape, *args) -> Self: + return self.shrink(tuple([None if ns is None else (0, ns) for ns in argfix(shape, *args)])) + + def view(self, shape, *args) -> Self: + """`.view` is an alias for `.reshape`.""" + return self.reshape(shape, *args) + + def squeeze(self, dim:int|None=None) -> Self: + """ + Returns a tensor with specified dimensions of input of size 1 removed. + If `dim` is not specified, all dimensions with size 1 are removed. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.zeros(2, 1, 2, 1, 2) + print(t.squeeze().shape) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.squeeze(0).shape) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.squeeze(1).shape) + ``` + """ + if dim is None: return self.reshape(tuple(dim for dim in self.shape if dim != 1)) + dim = self._resolve_dim(dim) + return self if not self.ndim or self.shape[dim] != 1 else self.reshape(self.shape[:dim] + self.shape[dim+1:]) + + def unsqueeze(self, dim:int) -> Self: + """ + Returns a tensor with a new dimension of size 1 inserted at the specified `dim`. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor([1, 2, 3, 4]) + print(t.unsqueeze(0).numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.unsqueeze(1).numpy()) + ``` + """ + dim = self._resolve_dim(dim, extra=True) + return self.reshape(self.shape[:dim] + (1,) + self.shape[dim:]) + + @property + def T(self) -> Self: + """`.T` is an alias for `.transpose()`.""" + return self.transpose() + + def transpose(self, dim0=1, dim1=0) -> Self: + """ + Returns a tensor that is a transposed version of the original tensor. + The given dimensions `dim0` and `dim1` are swapped. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.arange(6).reshape(2, 3) + print(t.numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.transpose(0, 1).numpy()) + ``` + """ + order = list(range(self.ndim)) + order[dim0], order[dim1] = order[dim1], order[dim0] + return self.permute(order) + + def flatten(self, start_dim=0, end_dim=-1) -> Self: + """ + Flattens the tensor by reshaping it into a one-dimensional tensor. + If `start_dim` or `end_dim` are passed, only dimensions starting with `start_dim` and ending with `end_dim` are flattened. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor.arange(8).reshape(2, 2, 2) + print(t.flatten().numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.flatten(start_dim=1).numpy()) + ``` + """ + start_dim, end_dim = self._resolve_dim(start_dim), self._resolve_dim(end_dim) + return self.reshape(self.shape[:start_dim] + (prod(self.shape[start_dim:end_dim+1]), ) + self.shape[end_dim+1:]) + + def unflatten(self, dim:int, sizes:tuple[int,...]) -> Self: + """ + Unflattens dimension `dim` of the tensor into multiple dimensions specified by `sizes`. `Tensor.flatten()` is the inverse of this function. + + ```python exec="true" source="above" session="tensor" result="python" + print(Tensor.ones(3, 4, 1).unflatten(1, (2, 2)).shape) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(Tensor.ones(3, 4, 1).unflatten(1, (-1, 2)).shape) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(Tensor.ones(5, 12, 3).unflatten(-2, (2, 2, 3, 1, 1)).shape) + ``` + """ + dim = self._resolve_dim(dim) + return self.reshape(self.shape[:dim] + sizes + self.shape[dim+1:]) + + def rearrange(self, formula:str, **sizes) -> Self: + """ + Rearranges input according to formula + + See: https://einops.rocks/api/rearrange/ + + ```python exec="true" source="above" session="tensor" result="python" + x = Tensor([[1, 2], [3, 4]]) + print(Tensor.rearrange(x, "batch channel -> (batch channel)").numpy()) + ``` + """ + def parse_formula(formula: str): + tokens = f" {formula} ".replace("…", "...").replace("(", " ( ").replace(")", " ) ").replace(" ", " ").replace(" 1 ", " ( ) ").split() + lparens, rparens = map(lambda x: [i for i, ch in enumerate(tokens) if ch == x], ("(", ")")) + pairs = list(zip(lparens, rparens)) + assert len(lparens) == len(rparens) and sorted(flatten(pairs)) == flatten(pairs), "bracket mismatch" + return [name for name in tokens if name not in ("(", ")")], [(s - 2*i, e - 1 - 2*i) for i, (s, e) in enumerate(pairs)] + + assert formula.count("->") == 1, 'need exactly one "->" in formula' + + (lhs, unflatten_dims), (rhs, flatten_dims) = map(parse_formula, formula.split("->")) + + for name in sizes: assert name in lhs, f"axis {name} is not used in transform" + assert sorted(lhs) == sorted(rhs) and len(lhs) == len(set(lhs)), f"name mismatch in {formula}" + for name in flatten((lhs, rhs)): assert name == "..." or (name.isidentifier() and "_" not in (name[0], name[-1])), f"invalid axis name {name}" + assert "..." not in flatten([lhs[s:e] for s, e in unflatten_dims]), f"cannot have collapsed ellipsis (...) in lhs of {formula}" + assert lhs.count("...") <= 1, f"too many ellipses in {formula}" + + # resolve ellipsis + if "..." in lhs: ell_len = len(self.shape) - len(lhs) + 1 + sum(e - s - 1 for s, e in unflatten_dims) + lhs, rhs = map(lambda l: l[:(i:=l.index("..."))] + [f"...{j}" for j in range(ell_len)] + l[i + 1:] if "..." in l else l, (lhs, rhs)) + unflatten_dims = [(s + (ell_len - 1 if "...0" in lhs[:s] else 0), e + (ell_len - 1 if "...0" in lhs[:e] else 0)) for s, e in unflatten_dims] + flatten_dims = [(s + (ell_len - 1 if "...0" in rhs[:s] else 0), e + (ell_len - 1 if "...0" in rhs[:e] else 0)) for s, e in flatten_dims] + + # apply movement ops in order unflatten -> permute -> flatten/unsqueeze + t = functools.reduce(lambda x, dims: x.unflatten(dims[0], tuple(sizes.get(lhs[d], -1) for d in range(*dims))), unflatten_dims, self) + for i, name in enumerate(lhs): assert (name not in sizes) or sizes[name] == t.shape[i], f"size provided for dimension {name} incorrect" + t = t.permute([lhs.index(name) for name in rhs]) + return functools.reduce(lambda x, dims: x.flatten(dims[0], dims[1] - 1) if dims[0] Self: + """ + Repeats elements of a tensor. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor([1, 2, 3]) + print(t.repeat_interleave(2).numpy()) + ``` + """ + x, dim = (self.flatten(), 0) if dim is None else (self, self._resolve_dim(dim)) + shp = x.shape + return x.reshape(*shp[:dim+1], 1, *shp[dim+1:]).expand(*shp[:dim+1], repeats, *shp[dim+1:]).reshape(*shp[:dim], shp[dim]*repeats, *shp[dim+1:]) + + def repeat(self, repeats, *args) -> Self: + """ + Repeats tensor number of times along each dimension specified by `repeats`. + `repeats` can be passed as a tuple or as separate arguments. + + ```python exec="true" source="above" session="tensor" result="python" + t = Tensor([1, 2, 3]) + print(t.repeat(4, 2).numpy()) + ``` + ```python exec="true" source="above" session="tensor" result="python" + print(t.repeat(4, 2, 1).shape) + ``` + """ + repeats = argfix(repeats, *args) + base_shape = _align_left(self.shape, repeats)[0] + unsqueezed_shape = flatten([[s] if r == 1 else [1, s] for r,s in zip(repeats, base_shape)]) + expanded_shape = flatten([[s] if r == 1 else [r, s] for r,s in zip(repeats, base_shape)]) + final_shape = [r*s for r,s in zip(repeats, base_shape)] + return self.reshape(unsqueezed_shape).expand(expanded_shape).reshape(final_shape) + + # **** pool level **** + + def _pool(self, k_:tuple[sint, ...], stride:int|tuple[int, ...]=1, dilation:int|tuple[int, ...]=1) -> Self: + assert len(self.shape) >= len(k_), f"can't pool {self.shape} with {k_}" + s_, d_ = make_tuple(stride, len(k_)), make_tuple(dilation, len(k_)) + assert len(k_) == len(s_) == len(d_), f"stride/dilation mismatch kernel:{k_} stride:{s_} dilation:{d_}" + noop, i_ = [None] * (self.ndim-len(k_)), self.shape[-len(k_):] + assert all(resolve(d*(k-1)+1 <= i) for k,d,i in zip(k_,d_,i_)), "kernel size cannot be greater than actual input size" + o_ = [ceildiv(i-d*(k-1), s) for i,d,k,s in zip(i_,d_,k_,s_)] + # input size scaling factor to make sure shrink for stride is possible + f_ = [smax(1, ceildiv(o*s - d, i)) for o,s,i,d in zip(o_,s_,i_,d_)] + # repeats such that we don't need padding + x = self.repeat([1]*len(noop) + [ceildiv(k*(i*f+d),i) for k,i,d,f in zip(k_,i_,d_,f_)]) + # handle dilation + x = x.shrink_to(noop + [k*(i*f+d) for k,i,d,f in zip(k_,i_,d_,f_)]).reshape(noop + flatten((k,(i*f+d)) for k,i,d,f in zip(k_,i_,d_,f_))) + # handle stride + x = x.shrink_to(noop + flatten((k,o*s) for k,o,s in zip(k_,o_,s_))).reshape(noop + flatten((k,o,s) for k,o,s in zip(k_,o_,s_))) + x = x.shrink_to(noop + flatten((k,o,1) for k,o in zip(k_,o_))).reshape(noop + flatten((k,o) for k,o in zip(k_,o_))) + # permute to move reduce to the end + return x.permute(*range(len(noop)), *[len(noop)+i*2+1 for i in range(len(i_))], *[len(noop)+i*2 for i in range(len(i_))]) diff --git a/tinygrad/nn/__init__.py b/tinygrad/nn/__init__.py index d32a3d5e2f..5d5ced5c32 100644 --- a/tinygrad/nn/__init__.py +++ b/tinygrad/nn/__init__.py @@ -36,7 +36,7 @@ class BatchNorm: self.weight: Tensor|None = Tensor.ones(sz) if affine else None self.bias: Tensor|None = Tensor.zeros(sz) if affine else None - self.num_batches_tracked = Tensor.zeros(1, dtype='long' if is_dtype_supported(dtypes.long) else 'int', requires_grad=False) + self.num_batches_tracked = Tensor.zeros(dtype='long' if is_dtype_supported(dtypes.long) else 'int', requires_grad=False) if track_running_stats: self.running_mean, self.running_var = Tensor.zeros(sz, requires_grad=False), Tensor.ones(sz, requires_grad=False) def calc_stats(self, x:Tensor) -> tuple[Tensor, Tensor]: @@ -223,7 +223,7 @@ class InstanceNorm: print(t.mean().item(), t.std().item()) ``` """ - def __init__(self, num_features:int, eps=1e-5, affine=True): + def __init__(self, num_features:int, eps:float=1e-5, affine:bool=True): self.num_features, self.eps = num_features, eps self.weight: Tensor|None = Tensor.ones(num_features) if affine else None self.bias: Tensor|None = Tensor.zeros(num_features) if affine else None @@ -249,16 +249,16 @@ class LayerNorm: print(t.mean().item(), t.std().item()) ``` """ - def __init__(self, normalized_shape:int|tuple[int, ...], eps=1e-5, elementwise_affine=True): + def __init__(self, normalized_shape:int|tuple[int, ...], eps:float=1e-5, elementwise_affine:bool=True): self.normalized_shape: tuple[int, ...] = make_tuple(normalized_shape, 1) - self.axis, self.eps, self.elementwise_affine = tuple(-1-i for i in range(len(self.normalized_shape))), eps, elementwise_affine + self.axis, self.eps = tuple(-1-i for i in range(len(self.normalized_shape))), eps self.weight: Tensor|None = Tensor.ones(*self.normalized_shape) if elementwise_affine else None self.bias: Tensor|None = Tensor.zeros(*self.normalized_shape) if elementwise_affine else None def __call__(self, x:Tensor) -> Tensor: assert self.normalized_shape == x.shape[-len(self.normalized_shape):], f"last dimensions of {x.shape} must match {self.normalized_shape}" x = x.layernorm(eps=self.eps, axis=self.axis) - if not self.elementwise_affine: return x + if self.weight is None or self.bias is None: return x return x * self.weight + self.bias class LayerNorm2d(LayerNorm): @@ -323,7 +323,7 @@ class Embedding: if not dtypes.is_int(idx.dtype): raise TypeError(f"Expected integer dtype for index in embedding, got {idx.dtype}") big_shp = idx.shape+(self.vocab_sz, self.embed_sz) arange, idx, vals = self.arange.expand(big_shp), idx.reshape(idx.shape+(1, 1)).expand(big_shp), self.weight.expand(big_shp) - return (arange == idx).mul(vals).sum(-2, dtype=vals.dtype) + return (arange == idx).where(vals, 0).sum(-2, dtype=vals.dtype) class LSTMCell: """ diff --git a/tinygrad/frontend/onnx.py b/tinygrad/nn/onnx.py similarity index 97% rename from tinygrad/frontend/onnx.py rename to tinygrad/nn/onnx.py index 33d5408602..4845d27ea5 100644 --- a/tinygrad/frontend/onnx.py +++ b/tinygrad/nn/onnx.py @@ -5,7 +5,7 @@ from io import BufferedReader from tinygrad.nn.state import TensorIO from tinygrad.tensor import Tensor, _broadcast_shape, ReductionStr from tinygrad.helpers import getenv, DEBUG, all_same, prod, flatten, make_tuple, argsort, is_numpy_ndarray, get_single_element, polyN -from tinygrad.dtype import DType, ConstType, dtypes, _from_np_dtype, truncate +from tinygrad.dtype import DType, ConstType, dtypes, _from_np_dtype, truncate, least_upper_dtype from tinygrad.device import is_dtype_supported, Device # ***** protobuf definitions ****** @@ -670,7 +670,8 @@ def get_onnx_ops() -> dict[str, types.FunctionType|dict[OpSetId, types.FunctionT def ReduceL1(data:Tensor, axes:list[int]|None=None, keepdims:int=1, noop_with_empty_axes:int=0): return ReduceSum(data.abs(), axes, keepdims, noop_with_empty_axes) def ReduceL2(data:Tensor, axes:list[int]|None=None, keepdims:int=1, noop_with_empty_axes:int=0): - return ReduceSumSquare(data, axes, keepdims, noop_with_empty_axes).sqrt() + dtype = dtypes.float if data.dtype in (dtypes.float16, dtypes.bfloat16) else data.dtype + return ReduceSum(data.cast(dtype).square(), axes, keepdims, noop_with_empty_axes).sqrt().cast(data.dtype) def ReduceLogSum(data:Tensor, axes:list[int]|None=None, keepdims:int=1, noop_with_empty_axes:int=0): return ReduceSum(data, axes, keepdims, noop_with_empty_axes).log() def ReduceLogSumExp(data:Tensor, axes:list[int]|None=None, keepdims:int=1, noop_with_empty_axes:int=0): @@ -897,7 +898,7 @@ def get_onnx_ops() -> dict[str, types.FunctionType|dict[OpSetId, types.FunctionT def BatchNormalization(X:Tensor, scale:Tensor, B:Tensor, input_mean:Tensor, input_var:Tensor, epsilon:float=1e-05, momentum:float=0.9, training_mode:int=0, spatial=1, is_test=0): if training_mode: - x_detached = X.detach() + x_detached = X.detach().cast(least_upper_dtype(X.dtype, dtypes.float32)) current_mean = x_detached.mean(axis=(0,2,3)) y = (x_detached - current_mean.reshape(shape=[1, -1, 1, 1])) current_var = (y*y).mean(axis=(0,2,3)) @@ -906,18 +907,20 @@ def get_onnx_ops() -> dict[str, types.FunctionType|dict[OpSetId, types.FunctionT running_mean = input_mean * momentum + current_mean * (1 - momentum) running_var = input_var * momentum + current_var * (1 - momentum) - return X.batchnorm(scale, B, current_mean, current_invstd), running_mean, running_var + return X.batchnorm(scale, B, current_mean, current_invstd).cast(X.dtype),running_mean.cast(input_mean.dtype),running_var.cast(input_var.dtype) return X.batchnorm(scale, B, input_mean, (input_var + epsilon).rsqrt()) - def GroupNormalization(x:Tensor, scale:Tensor, bias:Tensor, num_groups:int, epsilon:float=1e-05): - x = x.reshape(x.shape[0], num_groups, -1).layernorm(eps=epsilon).reshape(x.shape) + def GroupNormalization(x:Tensor, scale:Tensor, bias:Tensor, num_groups:int, epsilon:float=1e-05, stash_type:int=1): + assert stash_type == 1, "only float32 is supported" + x = x.reshape(x.shape[0], num_groups, -1).cast(dtypes.float).layernorm(eps=epsilon).cast(x.dtype).reshape(x.shape) return x * scale.reshape(1, -1, *[1] * (x.ndim-2)) + bias.reshape(1, -1, *[1] * (x.ndim-2)) def InstanceNormalization(x:Tensor, scale:Tensor, bias:Tensor, epsilon:float=1e-05): return GroupNormalization(x, scale, bias, num_groups=cast(int, x.shape[1]), epsilon=epsilon) def LayerNormalization(x:Tensor, scale:Tensor, bias:Tensor, axis:int=-1, epsilon:float=1e-05, stash_type:int=1): assert stash_type == 1, "only float32 is supported" axes = tuple(i for i in range(axis if axis >= 0 else x.ndim + axis, x.ndim)) - mean = x.mean(axis=axes, keepdim=True) - return x.layernorm(axes, epsilon).mul(scale).add(bias), mean, (x.sub(mean)).square().mean(axis=axes, keepdim=True).add(epsilon).rsqrt() + mean = (x32:=x.cast(dtypes.float)).mean(axis=axes, keepdim=True) + inv_std_dev = (x32.sub(mean)).square().mean(axis=axes, keepdim=True).add(epsilon).rsqrt() + return (x32.sub(mean)*inv_std_dev).cast(x.dtype).mul(scale).add(bias), mean, inv_std_dev def SkipLayerNormalization(x:Tensor, skip:Tensor, gamma:Tensor, beta:Tensor|None=None, bias:Tensor|None=None, epsilon:float=1e-12): x = x + skip if bias is not None: x = x + bias @@ -1089,9 +1092,10 @@ def get_onnx_ops() -> dict[str, types.FunctionType|dict[OpSetId, types.FunctionT return output, present_key, present_value, qk_matmul_return_val Attention = {OpSetId(Domain.ONNX, 1): attention_onnx, OpSetId(Domain.MICROSOFT_CONTRIB_OPS, 1): attention_contrib} - def RMSNormalization(X:Tensor, scale:Tensor, axis:int=-1, epsilon:float=1e-5): - norm = X.square().mean(axis=tuple(range(axis + X.ndim if axis < 0 else axis, X.ndim)), keepdim=True).add(epsilon).rsqrt() - return X * norm * scale + def RMSNormalization(X:Tensor, scale:Tensor, axis:int=-1, epsilon:float=1e-5, stash_type:int=1): + assert stash_type == 1, "only float32 is supported" + norm = X.cast(dtypes.float).square().mean(axis=tuple(range(axis + X.ndim if axis < 0 else axis, X.ndim)), keepdim=True).add(epsilon).rsqrt() + return X.cast(X.dtype) * norm * scale def RotaryEmbedding(X:Tensor, cos_cache:Tensor, sin_cache:Tensor, position_ids:Tensor|None=None, interleaved:int=0, num_heads:int|None=None, rotary_embedding_dim:int=0): @@ -1120,6 +1124,16 @@ def get_onnx_ops() -> dict[str, types.FunctionType|dict[OpSetId, types.FunctionT return output.flatten(start_dim=2) if len(original_input_shape) == 3 else output.permute(0, 2, 1, 3) # ***** Indexing Ops ***** + def NonZero(x:Tensor): + mask = (x!=0).flatten() + flat_idx = Tensor.arange(mask.numel(), dtype=dtypes.int64, device=x.device).masked_select(mask) + if flat_idx.ndim == 0: flat_idx = flat_idx.reshape(1) + if x.ndim == 0: + return Tensor.zeros((0, flat_idx.shape[0]), dtype=dtypes.int64, device=x.device, requires_grad=False) + strides = [prod(int(s) for s in x.shape[i+1:]) if i+1 < x.ndim else 1 for i in range(x.ndim)] + coords = [((flat_idx // stride) % int(dim)) for stride, dim in zip(strides, x.shape)] + return Tensor.stack(*coords, dim=0) + def ArrayFeatureExtractor(x:Tensor, indices:Tensor): return x[..., indices] def Gather(x:Tensor, indices:Tensor, axis:int=0): @@ -1242,7 +1256,8 @@ def get_onnx_ops() -> dict[str, types.FunctionType|dict[OpSetId, types.FunctionT G, V, H = G.detach(), V.detach(), H.detach() X.grad = norm_coefficient * X.detach() + G opt = TinyAdam([X], b1=alpha, b2=beta, eps=epsilon) - opt.m, opt.v, opt.lr = [V], [H], R + # NOTE: FUSE_OPTIM can change shapes of m and v + opt.m, opt.v, opt.lr = [V.reshape(opt.m[0].shape)], [H.reshape(opt.v[0].shape)], R # need no-op for m_hat and v_hat if T == 0 if T == 0: opt.b1_t, opt.b2_t = opt.b1_t.zeros_like(), opt.b2_t.zeros_like() else: diff --git a/tinygrad/nn/optim.py b/tinygrad/nn/optim.py index e93a06a901..53cb043acb 100644 --- a/tinygrad/nn/optim.py +++ b/tinygrad/nn/optim.py @@ -50,7 +50,7 @@ class Optimizer: if self.fused: # optimizer fusion just concatenates all the buffers, runs the _step, then splits them back up out, extra = self._step([Tensor.cat(*[t.flatten() for t in self.params], dim=0)], - [Tensor.cat(*[unwrap(t.grad).flatten() for t in self.params], dim=0)]) + [Tensor.cat(*[unwrap(t.grad).contiguous().flatten() for t in self.params], dim=0)]) updated_params = [out[0][self.pos_params[i]:self.pos_params[i+1]].reshape(tt.shape) for i, tt in enumerate(self.params)] else: updated_params, extra = self._step(self.params, [unwrap(t.grad) for t in self.params]) @@ -80,7 +80,7 @@ def SGD(params: list[Tensor], lr=0.001, momentum=0.0, weight_decay=0.0, nesterov return LARS(params, lr, momentum, weight_decay, 0, None, nesterov, classic=classic, pre_wd=True, tcoef=0.0, fused=fused) # Muon applies the newton schulz algorithm on gradient. also can include momentum, nesterov, and weight decay -def Muon(params: list[Tensor], lr=0.02, momentum=0.95, weight_decay=0.0, ns_steps=5, ns_params=(3.4445, -4.775, 2.0315), +def Muon(params: list[Tensor], lr=0.001, momentum=0.95, weight_decay=0.1, ns_steps=5, ns_coefficients=(3.4445, -4.775, 2.0315), nesterov=True, fused=FUSE_OPTIM): """ SGD with newton-schulz iteration and post momentum weight decay. @@ -89,7 +89,7 @@ def Muon(params: list[Tensor], lr=0.02, momentum=0.95, weight_decay=0.0, ns_step - Paper: https://arxiv.org/pdf/2502.16982 """ assert not fused, "FUSE_OPTIM not allowed for Muon optimizer" - return LARS(params, lr, momentum, weight_decay, ns_steps, ns_params, nesterov, classic=False, pre_wd=False, tcoef=0.0, fused=fused) + return LARS(params, lr, momentum, weight_decay, ns_steps, ns_coefficients, nesterov, classic=False, pre_wd=False, tcoef=0.0, fused=fused) class LARS(Optimizer): """ @@ -97,10 +97,10 @@ class LARS(Optimizer): - Paper: https://arxiv.org/abs/1708.03888v3 """ - def __init__(self, params:list[Tensor], lr=0.001, momentum=0.9, weight_decay=1e-4, ns_steps=0, ns_params=None, + def __init__(self, params:list[Tensor], lr=0.001, momentum=0.9, weight_decay=1e-4, ns_steps=0, ns_coefficients=None, nesterov=False, classic=True, pre_wd=True, tcoef=0.001, fused=FUSE_OPTIM): super().__init__(params, lr, fused) - self.momentum, self.wd, self.ns_steps, self.ns_params = momentum, weight_decay, ns_steps, ns_params + self.momentum, self.wd, self.ns_steps, self.ns_coefficients = momentum, weight_decay, ns_steps, ns_coefficients self.nesterov, self.classic, self.pre_wd, self.tcoef = nesterov, classic, pre_wd, tcoef self.b = self._new_optim_param() if self.momentum else [] @@ -116,11 +116,9 @@ class LARS(Optimizer): # classic momentum does post learning rate update if self.classic: g = g * r * self.lr if self.momentum: - # TODO: this contiguous is required for correctness because self.b[i] becomes a non contiguous view - # the scheduler should detect this and just insert contiguous - self.b[i].assign(self.momentum * self.b[i].contiguous() + g) # NOTE: self.b[i] is zero on the first run, no if required + self.b[i].assign(self.momentum * self.b[i] + g) # NOTE: self.b[i] is zero on the first run, no if required g = (g + self.momentum * self.b[i]) if self.nesterov else self.b[i] - if self.ns_params: g = g.reshape(g.shape[0], -1).newton_schulz(self.ns_steps, self.ns_params).reshape(g.shape) + if self.ns_coefficients: g = g.reshape(g.shape[0], -1).newton_schulz(self.ns_steps, self.ns_coefficients).reshape(g.shape) # muon does post momentum weight decay if not self.pre_wd and self.wd > 0: t = t.detach() * (1.0 - self.wd * self.lr) # popular momentum does pre learning rate update diff --git a/tinygrad/nn/state.py b/tinygrad/nn/state.py index 110da5ecd7..5349fde65a 100644 --- a/tinygrad/nn/state.py +++ b/tinygrad/nn/state.py @@ -1,10 +1,9 @@ import json, pathlib, zipfile, pickle, tarfile, struct, functools, io from collections import OrderedDict -from typing import Any, Callable, BinaryIO, Iterable +from typing import Any, Callable, BinaryIO, Iterable, cast from tinygrad.tensor import Tensor from tinygrad.dtype import dtypes -from tinygrad.helpers import prod, argsort, DEBUG, Timing, CI, unwrap, GlobalCounters, tqdm, round_up, T -from tinygrad.shape.view import strides_for_shape +from tinygrad.helpers import prod, argsort, DEBUG, Timing, CI, unwrap, GlobalCounters, tqdm, round_up, T, strides_for_shape class TensorIO(io.RawIOBase, BinaryIO): def __init__(self, t: Tensor): @@ -210,7 +209,7 @@ def torch_load(t:Tensor) -> dict[str, Tensor]: assert tuple([shape_strides[i][1] for i in argsort(permute_indexes)]) == strides_for_shape(intermediate_shape), "nonpermutable strides" if DEBUG >= 3: print(f"WARNING: this torch load is slow. to permute {intermediate_shape} with {permute_indexes}") assert storage[1] != dtypes.bfloat16, "can't permute BF16" - # TODO: find a nice way to support all shapetracker on disktensors + # TODO: find a nice way to support all movement ops on disktensors ret = ret.to(None).reshape(intermediate_shape).permute(permute_indexes) return ret.reshape(size) @@ -238,11 +237,18 @@ def torch_load(t:Tensor) -> dict[str, Tensor]: if passthrough_reset(zipfile.is_zipfile(fobj)): # NOTE: passthrough_reset required to support python < 3.14 myzip = zipfile.ZipFile(fobj, 'r') - base_name = myzip.namelist()[0].split('/', 1)[0] - for n in myzip.namelist(): - if n.startswith(f'{base_name}/data/'): - with myzip.open(n) as myfile: - offsets[n.split("/")[-1]] = myfile._orig_compress_start # type: ignore + base_name = None + header_offsets = {} + for zi in myzip.filelist: + if base_name is None: base_name = zi.filename.split('/', 1)[0] + if zi.filename.startswith(f'{base_name}/data/'): header_offsets[zi.filename.split("/")[-1]] = zi.header_offset + # sadly there's no way to get the start of the file in the zip without reading the header + # at least here we read them in parallel + header_contents = [t[v+26:v+30].bitcast(dtypes.uint16).to('CPU') for v in header_offsets.values()] + Tensor.realize(*header_contents) + for (n,o),c in zip(header_offsets.items(), header_contents): + # header_offset + sizeFileHeader + File name length + Extra field length : https://en.wikipedia.org/wiki/ZIP_(file_format) + offsets[n] = o+30+sum(cast(list[int], c.tolist())) with myzip.open(f'{base_name}/data.pkl') as myfile: return TorchPickle(myfile).load() elif passthrough_reset(tarfile.is_tarfile(fobj)): # NOTE: passthrough_reset required to support python < 3.11 diff --git a/tinygrad/frontend/torch.py b/tinygrad/nn/torch.py similarity index 100% rename from tinygrad/frontend/torch.py rename to tinygrad/nn/torch.py diff --git a/tinygrad/renderer/__init__.py b/tinygrad/renderer/__init__.py index 068e8afb26..c63dbff3df 100644 --- a/tinygrad/renderer/__init__.py +++ b/tinygrad/renderer/__init__.py @@ -1,13 +1,12 @@ from __future__ import annotations -from typing import Callable, cast, TYPE_CHECKING +from typing import Callable, cast import functools from dataclasses import dataclass, field from tinygrad.helpers import to_function_name, dedup, prod from tinygrad.uop.ops import Ops, UOp, sym_infer, sint, Variable, ssimplify, GroupOp, PatternMatcher from tinygrad.dtype import AddrSpace, PtrDType -if TYPE_CHECKING: - from tinygrad.codegen.opt.tc import TensorCore - from tinygrad.codegen.opt.kernel import Opt +from tinygrad.codegen.opt.tc import TensorCore +from tinygrad.codegen.opt import Opt @dataclass(frozen=True) class Estimates: @@ -28,9 +27,12 @@ class Estimates: mult_stack: list[sint] = [] dont_count: set[UOp] = set() if ignore_indexing: + def range_gate(x): return x.op is not Ops.RANGE for u in uops: - if u.op in {Ops.LOAD, Ops.STORE} and (not isinstance(u.src[0].dtype, PtrDType) or u.src[0].dtype.addrspace != AddrSpace.REG): - dont_count = dont_count.union(u.src[0].toposort()) + if u.op in {Ops.LOAD, Ops.STORE}: + # if u.src[0] is INDEX, we have to include the buffer since it might be an AFTER + dont_count = dont_count.union((UOp.sink(*u.src[0].src[1:]) if u.src[0].op is Ops.INDEX else u.src[0]).toposort(range_gate)) + # TODO: is this correct? this all needs to be cleaned up if len(u.src) > 2: dont_count = dont_count.union(u.src[2].toposort()) elif u.op is Ops.IF: dont_count = dont_count.union(u.src[0].toposort()) @@ -45,7 +47,7 @@ class Estimates: mults *= cast(sint, u.src[0].ssimplify()) # SPECIAL are already counted in mults mults = mults.substitute({x:x.const_like(0) for x in mults.toposort() if x.op is Ops.SPECIAL}) if isinstance(mults, UOp) else mults - elif u.op is Ops.ENDRANGE: mults = mult_stack.pop(-1) + elif u.op is Ops.END: mults = mult_stack.pop(-1) elif u.op is Ops.SPECIAL: mults *= cast(sint, u.src[0].ssimplify()) # NOTE: we don't push to the mult_stack here, you can't end these elif u.op is Ops.LOAD and (not isinstance(u.src[0].dtype, PtrDType) or u.src[0].dtype.addrspace != AddrSpace.REG): lds += u.dtype.itemsize * mults @@ -78,12 +80,15 @@ class ProgramSpec: for u in self.uops: if u.op is Ops.DEFINE_VAR: self.vars.append(u) if u.op is Ops.DEFINE_GLOBAL: self.globals.append(u.arg) - if u.op is Ops.STORE: self.outs.extend([x.arg for x in u.src[0].toposort() if x.op is Ops.DEFINE_GLOBAL]) - if u.op is Ops.LOAD: self.ins.extend([x.arg for x in u.src[0].toposort() if x.op is Ops.DEFINE_GLOBAL]) + if u.op in (Ops.STORE, Ops.LOAD): + if (idx:=u.src[0]).op is Ops.INDEX or (u.src[0].op is Ops.CAST and (idx:=u.src[0].src[0]).op is Ops.INDEX): + if (buf:=idx.src[0]).op is Ops.DEFINE_GLOBAL: (self.outs if u.op is Ops.STORE else self.ins).append(buf.arg) + # TODO: can else happen? if u.op is Ops.SPECIAL: # NOTE: you have to set local_size and global_size to the base [1,1,1] outside this if u.arg[0] == 'i': self.local_size = None special_size = self.local_size if u.arg[0] == 'l' else self.global_size + # TODO: this cast is wrong, u.src[0].ssimplify() can be sint if special_size is not None: special_size[int(u.arg[-1])] = cast(int, u.src[0].ssimplify()) self.vars = sorted(self.vars, key=lambda v: v.arg) self.outs = sorted(dedup(self.outs)) @@ -98,8 +103,10 @@ class ProgramSpec: def function_name(self) -> str: return to_function_name(self.name) @property - def applied_opts(self) -> tuple[Opt, ...]|None: return self.uops[-1].arg.applied_opts if \ - self.uops is not None and self.uops[-1].op is Ops.SINK and self.uops[-1].arg is not None else None + def applied_opts(self) -> tuple[Opt, ...]|None: + if self.uops is None: return None + assert self.uops[-1].op is Ops.SINK, self.uops[-1].op + return self.uops[-1].arg.applied_opts def launch_dims(self, var_vals:dict[str, int]): global_size = [sym_infer(sz, var_vals) for sz in self.global_size] if self.global_size is not None else None diff --git a/tinygrad/renderer/cstyle.py b/tinygrad/renderer/cstyle.py index 0916f18ccd..0d9ef047e7 100644 --- a/tinygrad/renderer/cstyle.py +++ b/tinygrad/renderer/cstyle.py @@ -2,7 +2,7 @@ from typing import Literal, Callable, cast import os, math, sys from collections import defaultdict, Counter from tinygrad.codegen.opt import tc -from tinygrad.uop.ops import GroupOp, Ops, UOp, PatternMatcher, UPat, sint_to_uop, range_str +from tinygrad.uop.ops import GroupOp, Ops, UOp, PatternMatcher, UPat, range_str, axis_letters from tinygrad.helpers import strip_parens, getenv, prod, dedup, AMX, CPU_COUNT from tinygrad.dtype import ImageDType, dtypes, DType, PtrDType, AddrSpace, truncate from tinygrad.renderer import Renderer @@ -11,7 +11,7 @@ from tinygrad.codegen.late.devectorizer import no_vectorized_alu base_rewrite = PatternMatcher([ (UPat(Ops.DEFINE_REG, name="x"), lambda ctx,x: f"{ctx.render_dtype(x.dtype.base)} {ctx[x]}[{x.dtype.size}];"), (UPat(Ops.IF, name="x"), lambda ctx,x: f"if ({ctx[x.src[0]]}) {{"), - (UPat((Ops.ENDIF, Ops.ENDRANGE)), lambda ctx: "}"), + (UPat((Ops.ENDIF, Ops.END)), lambda ctx: "}"), (UPat(Ops.WMMA, name="x"), lambda ctx,x: f"__{x.arg[0]}({ctx[x.src[0]]}, {ctx[x.src[1]]}, {ctx[x.src[2]]})"), # r method accesses (UPat(Ops.RANGE, name="x"), @@ -37,7 +37,7 @@ base_rewrite = PatternMatcher([ (UPat(Ops.CONST, dtype=dtypes.uint32, name="x"), lambda ctx,x: f"{truncate[x.dtype](x.arg)}u"), (UPat(Ops.CONST, dtype=dtypes.bool, name="x"), lambda ctx,x: "1" if x.arg else "0"), # consts are rendered to larger type and casted - (UPat(Ops.CONST, (dtypes.bfloat16, dtypes.half), name="x"), lambda ctx,x: f"({ctx.render_cast(x.dtype, f'{x.arg}f')})"), + (UPat(Ops.CONST, (*dtypes.fp8s, dtypes.bfloat16, dtypes.half), name="x"), lambda ctx,x: f"({ctx.render_cast(x.dtype, f'{x.arg}f')})"), (UPat(Ops.CONST, (dtypes.uint8, dtypes.uint16), name="x"), lambda ctx,x: f"({ctx.render_cast(x.dtype, f'{x.arg}u')})"), (UPat(Ops.CONST, (dtypes.int8, dtypes.int16), name="x"), lambda ctx,x: f"({ctx.render_cast(x.dtype, str(x.arg))})"), # default const render @@ -71,11 +71,26 @@ extra_pm = PatternMatcher([ (UPat(Ops.WHERE, name="alu"), no_vectorized_alu), ]) +def create_non_native_float_pats(dts:tuple[DType, ...], casting:bool=True): + patterns = PatternMatcher([ + (UPat(Ops.WHERE, src=(UPat.var("b"), UPat.var("x", dtype=dts), UPat.var("y", dtype=dts))), + lambda b,x,y: UOp(Ops.WHERE, dtype=dtypes.float, src=(b,x.cast(dtypes.float),y.cast(dtypes.float))).cast(x.dtype)), + (UPat(GroupOp.ALU, dtype=dts, name="x"), + lambda x: UOp(x.op, dtypes.float, tuple(vv.cast(dtypes.float) for vv in x.src), x.arg).cast(x.dtype)), + (UPat(GroupOp.ALU, dtypes.bool, name="alu", src=(UPat.var("x", dtype=dts), UPat.var("y", dtype=dts))), + lambda alu,x,y: UOp(alu.op, dtypes.bool, (x.cast(dtypes.float), y.cast(dtypes.float)), alu.arg))]) + if casting: + # add float intermediate casting + patterns += PatternMatcher([ + (UPat(Ops.CAST, dts, (UPat.var("x"),), name="y"), lambda x,y: x.cast(dtypes.float).cast(y.dtype) if x.dtype!=dtypes.float else None), + (UPat(Ops.CAST, name="x", src=(UPat.var("y", dts),)), lambda x,y: y.cast(dtypes.float).cast(x.dtype) if x.dtype!=dtypes.float else None)]) + return patterns + def uops_to_dtypes(uops:list[UOp]) -> list[DType]: return dedup(u.dtype for u in uops if not isinstance(u.dtype, (ImageDType, PtrDType))) # (name, dims, dtype_in, dtype_out, device, threads, upcast_axes, reduce_axes) def wmma_args(uops:list[UOp]): - return dedup((uop.arg[0], uop.arg[1], uop.src[0].dtype.scalar(), uop.dtype.scalar(), *(uop.arg[4:8])) for uop in uops if uop.op is Ops.WMMA) + return dedup((uop.arg[0], uop.arg[1], uop.arg[2], uop.dtype.scalar(), *(uop.arg[4:8])) for uop in uops if uop.op is Ops.WMMA) class CStyleLanguage(Renderer): kernel_typedef: str = "void" @@ -95,7 +110,7 @@ class CStyleLanguage(Renderer): infinity: str = "INFINITY" nan: str = "NAN" code_for_op: dict = { - Ops.SQRT: lambda x,dtype: f"sqrt({x})", Ops.RECIP: lambda x,dtype: f"(1/{x})", Ops.NEG: lambda x,dtype: f"-{x}", + Ops.SQRT: lambda x,dtype: f"sqrt({x})", Ops.RECIPROCAL: lambda x,dtype: f"(1/{x})", Ops.NEG: lambda x,dtype: f"-{x}", Ops.EXP2: lambda x,dtype: f"exp2({x})", Ops.LOG2: lambda x,dtype: f"log2({x})", Ops.SIN: lambda x,dtype: f"sin({x})", Ops.TRUNC: lambda x,dtype: f"trunc({x})", Ops.AND: lambda a,b,dtype: f"({a}&{b})", Ops.XOR: lambda a,b,dtype: f"({a}^{b})", Ops.OR: lambda a,b,dtype: f"({a}|{b})", @@ -108,11 +123,13 @@ class CStyleLanguage(Renderer): extra_matcher = extra_pm def render_kernel(self, function_name:str, kernel:list[str], bufs:list[tuple[str,tuple[DType,bool]]], uops:list[UOp], prefix=None) -> str: - tmp = "const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;\n" if any(isinstance(dtype, ImageDType) for _,(dtype,_) in bufs) else "" # noqa: E501 + tmp = "" + if any(isinstance(dtype, ImageDType) for _,(dtype,_) in bufs): + tmp = "const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;\n" buftypes = [(name, self.render_dtype(dtype, mutable)+self.buffer_suffix if isinstance(dtype, (ImageDType, PtrDType)) else self.arg_int_prefix if dtype == dtypes.int else None) for name,(dtype,mutable) in bufs] local_dims = [u.src[0] for u in uops if u.op is Ops.SPECIAL and u.arg[0] == "l"] - launch_bounds = sint_to_uop(prod(local_dims)).vmax + launch_bounds = prod([d.vmax for d in local_dims]) prg = ''.join([f"{self.kernel_typedef.format(launch_bounds=launch_bounds)} {function_name}(",] + [', '.join([f'{t} {name}' for name,t in buftypes] + self.extra_args)] + [") {\n" + tmp] + ['\n'.join(kernel), "\n}"]) @@ -141,7 +158,10 @@ class CStyleLanguage(Renderer): c: defaultdict[str, int] = defaultdict(int) name = "test" for u in uops: - if u.op is Ops.NOOP: continue + if u.op in {Ops.NOOP, Ops.GROUP}: continue + if u.op is Ops.AFTER: + r[u] = r[u.src[0]] + continue if u.op is Ops.SINK: if u.arg is not None: name = u.arg.function_name continue @@ -158,7 +178,7 @@ class CStyleLanguage(Renderer): # naming prefix = None if u.op is Ops.SPECIAL: r[u] = u.arg - elif u.op is Ops.RANGE: r[u] = "ridx"+range_str(u) + elif u.op is Ops.RANGE: r[u] = f"{axis_letters[u.arg[-1]]}idx"+range_str(u) else: prefix = {Ops.WMMA: "wmma", Ops.DEFINE_LOCAL: "temp", Ops.CONST: "const", Ops.CAST: "cast", Ops.BITCAST: "cast", Ops.GEP: "gep", Ops.VECTORIZE: "cast", Ops.PRECAST: "precast", @@ -168,7 +188,7 @@ class CStyleLanguage(Renderer): l = cast(str, self.string_rewrite.rewrite(u, ctx=self)) assert l is not None, f"failed to render {u.op} {u.dtype} {[(x.op,x.dtype) for x in u.src]} {u.arg}" - if u.op in {Ops.ENDIF, Ops.ENDRANGE}: depth -= 1 + if u.op in {Ops.ENDIF, Ops.END}: depth -= 1 if (u.op is not Ops.CAST or u.dtype.vcount == 1) and (u.op in {Ops.CONST, Ops.GEP, Ops.INDEX, Ops.CUSTOMI} or \ (u.op is Ops.LOAD and u.src[0].ptrdtype.addrspace == AddrSpace.REG) or \ (u.op is Ops.CAST and isinstance(u.dtype, PtrDType)) or \ @@ -203,7 +223,7 @@ class ClangRenderer(CStyleLanguage): # language options buffer_suffix = " restrict" type_map = {dtypes.bool:"_Bool", dtypes.half:"__fp16"} - code_for_op = {**({k:v for k,v in CStyleLanguage.code_for_op.items() if k not in [Ops.EXP2, Ops.SIN, Ops.LOG2, Ops.TRUNC, Ops.RECIP]}), + code_for_op = {**({k:v for k,v in CStyleLanguage.code_for_op.items() if k not in [Ops.EXP2, Ops.SIN, Ops.LOG2, Ops.TRUNC, Ops.RECIPROCAL]}), Ops.SQRT: lambda x,dtype: f"__builtin_sqrt({x})" if dtype == dtypes.float64 else f"__builtin_sqrtf({x})", Ops.TRUNC: lambda x,dtype: f"__builtin_trunc({x})" if dtype == dtypes.float64 else f"__builtin_truncf({x})", Ops.FDIV: lambda a,b,dtype: f"({a}/{b})"} @@ -229,10 +249,12 @@ class ClangRenderer(CStyleLanguage): # 'static' in C roughly means that function symbol isn't exported. LLVM puts those symbols at the end of object file which allows Clang JIT # to just jump at the start of a shellcode without having to deal with symbols or trampolines at all. This is better than having to inline # wmma function every time it is called or wasting complexity on a symbol parsing and a memory page on trampoline. - prefix += [f"""static {(out := self.render_dtype(dtype_in.vec(N*N)))} __{name}({self.render_dtype(dtype_in.vec(N))} data1, {self.render_dtype(dtype_in.vec(M))} data2, {out} data0){{ + out, dt1, dt2 = self.render_dtype(dtype_in.vec(N*N)), self.render_dtype(dtype_in.vec(N)), self.render_dtype(dtype_in.vec(M)) + prefix += [f"""static {out} __{name}({dt1} data1, {dt2} data2, {out} data0){{ AMX_SET(0);\n for(int ridx0 = 0; ridx0 < 16; ridx0++){{ AMX(4, (int *)(&data0), 0ull<<62 | (ridx0*4ull)<<56 | ridx0*64ull); }} AMX(0, (int *)(&data2), 0ull<<62); AMX(1, (int *)(&data1), 0ull<<62); AMX(12, 0, 0ull); - for(int ridx0 = 0; ridx0 < 16; ridx0++){{ AMX(5, (int *)(&data0), 0ull<<62 | (ridx0*4ull)<<56 | ridx0*64ull); }}\n AMX_SET(1);\n return data0;\n}}"""] # noqa: E501 + for(int ridx0 = 0; ridx0 < 16; ridx0++){{ AMX(5, (int *)(&data0), 0ull<<62 | (ridx0*4ull)<<56 | ridx0*64ull); }} + AMX_SET(1);\n return data0;\n}}"""] return prefix def _render_body(self, function_name, kernel, bufs, uops, pref=None) -> str: return super().render_kernel(function_name, kernel, bufs, uops, pref) def _render_entry(self, function_name:str, bufs:list[tuple[str,tuple[DType,bool]]]) -> str: return "" @@ -262,7 +284,8 @@ class OpenCLRenderer(CStyleLanguage): lambda ctx,buf,idx,var,gate: f"({ctx[gate]}?read_imagef({ctx[buf]}, smp, {ctx[idx]}):{ctx[var]})"), (UPat(Ops.LOAD, dtype=dtypes.float.vec(4), src=(UPat.var('buf').index(UPat.var('idx', dtypes.int.vec(2))),)), lambda ctx,buf,idx: f"read_imagef({ctx[buf]}, smp, {ctx[idx]})"), - (UPat(Ops.STORE, src=(UPat.var('buf').index(UPat.var('idx', dtypes.int.vec(2))), UPat.var("var", dtypes.float.vec(4))), allow_any_len=True), + (UPat(Ops.STORE, src=(UPat.var('buf').index(UPat.var('idx', dtypes.int.vec(2)), allow_any_len=True), + UPat.var("var", dtypes.float.vec(4))), allow_any_len=True), lambda ctx,buf,idx,var: f"write_imagef({ctx[buf]}, {ctx[idx]}, {ctx[var]});"), ]) + base_rewrite @@ -338,7 +361,8 @@ class CUDARenderer(CStyleLanguage): shared_max = 49152 def __init__(self, arch:str): - self.tensor_cores, self.arch = tc.cuda_sm80 if int(arch[3:]) >= 80 else tc.cuda_sm75 if int(arch[3:]) >= 75 else [], arch + self.arch = arch + self.tensor_cores = tc.cuda_sm89 if int(arch[3:]) >= 89 else tc.cuda_sm80 if int(arch[3:]) >= 80 else tc.cuda_sm75 if int(arch[3:]) >= 75 else [] def __reduce__(self): return self.__class__, (self.arch,) # language options @@ -356,9 +380,11 @@ class CUDARenderer(CStyleLanguage): Ops.LOG2: lambda x,dtype: f"hlog2({x})" if dtype in (dtypes.half, dtypes.bfloat16) else f"log2({x})", Ops.EXP2: lambda x,dtype: f"hexp2({x})" if dtype in (dtypes.half, dtypes.bfloat16) else f"exp2({x})", Ops.SQRT: lambda x,dtype: f"hsqrt({x})" if dtype in (dtypes.half, dtypes.bfloat16) else f"sqrt({x})", - Ops.RECIP: lambda x,dtype: f"hrcp({x})" if dtype in (dtypes.half, dtypes.bfloat16) else f"(1/{x})" } - type_map = {dtypes.bfloat16: "nv_bfloat16"} - + Ops.RECIPROCAL: lambda x,dtype: f"hrcp({x})" if dtype in (dtypes.half, dtypes.bfloat16) else f"(1/{x})" } + type_map = {dtypes.bfloat16: "nv_bfloat16", dtypes.fp8e4m3: "__nv_fp8_e4m3", dtypes.fp8e5m2: "__nv_fp8_e5m2"} + extra_matcher = create_non_native_float_pats(dtypes.fp8s, casting=False) + PatternMatcher([ + (UPat(Ops.CAST, dtypes.fp8s, UPat.var("x", dtypes.fp8s), name='y'), lambda x,y: x.cast(dtypes.float).cast(y.dtype) if x.dtype!=y.dtype else None), + ]) + extra_pm def render_vector_prefix(self, dt:DType) -> str: vec, scal = self.render_dtype(dt), self.render_dtype(dt.scalar()), elems, header = ', '.join(_nms[:dt.count]), ', '.join([f"{scal} {x}" for x in _nms[:dt.count]]) @@ -369,11 +395,12 @@ class CUDARenderer(CStyleLanguage): prefix = ["#define INFINITY (__int_as_float(0x7f800000))","#define NAN (__int_as_float(0x7fffffff))"] used_dtypes = uops_to_dtypes(uops) + if any(dt.scalar() in dtypes.fp8s for dt in used_dtypes): prefix.append("#include ") if any(dt.scalar() == dtypes.half for dt in used_dtypes): prefix.append("#include ") if any(dt.scalar() == dtypes.bfloat16 for dt in used_dtypes): prefix.append("#include ") - prefix += [self.render_vector_prefix(dt) for dt in used_dtypes if dt.count in (4,8) and dt.scalar() in {dtypes.half, dtypes.bfloat16}] - - dt_map_in = { dtypes.float: "tf32", dtypes.half: "f16", dtypes.bfloat16: "bf16" } + prefix += [self.render_vector_prefix(dt) for dt in used_dtypes if (dt.count in (4,8) and dt.scalar() in {dtypes.half, dtypes.bfloat16}) + or (dt.count in (2,4,8,16) and dt.scalar() in dtypes.fp8s)] + dt_map_in = { dtypes.float: "tf32", dtypes.half: "f16", dtypes.bfloat16: "bf16", dtypes.fp8e4m3: "e4m3", dtypes.fp8e5m2: "e5m2" } dt_map_out = { dtypes.float: "f32", dtypes.half: "f16" } for name, (N, M, K), dtype_in, dtype_out, _, _, upcast_axes, _ in wmma_args(uops): upcast_sizes = [prod(size for _, size in upcast) for upcast in upcast_axes] @@ -407,25 +434,25 @@ class AMDRenderer(CStyleLanguage): @staticmethod def get_tensor_cores(arch): - return {"gfx942": tc.amd_cdna, "gfx950": tc.amd_cdna, "gfx1200": tc.amd_rdna4, "gfx1201": tc.amd_rdna4}.get(arch.split(":")[0], tc.amd_rdna3) + return {"gfx942": tc.amd_cdna3, "gfx950": tc.amd_cdna4, "gfx1200": tc.amd_rdna4, "gfx1201": tc.amd_rdna4}.get(arch.split(":")[0], tc.amd_rdna3) + @staticmethod + def is_cdna(arch): return arch.split(":")[0] in {"gfx942", "gfx950"} def __init__(self, arch:str): # gfx942 => MI300, gfx1100 => RX 7900, gfx1201 => RX 9700 self.arch = arch self.tensor_cores = self.get_tensor_cores(arch) - if self.tensor_cores == tc.amd_cdna: + if self.is_cdna(self.arch): self.string_rewrite = PatternMatcher([ - (UPat(Ops.WMMA, name="x"), lambda ctx,x: f"__{x.arg[0]}({ctx[x.src[0]]}, {ctx[x.src[1]]}, {ctx[x.src[2]]}, 0, 0, 0)")]) + base_rewrite + (UPat(Ops.WMMA, name="x"), lambda ctx,x: f"__{x.arg[0]}({ctx[x.src[0]]}, {ctx[x.src[1]]}, {ctx[x.src[2]]}, 0, 0, 0)"), + (UPat(Ops.CAST, dtypes.fp8s, (UPat.var("y", dtypes.float),), name="x",), + lambda ctx,x, y: f"f32_to_fp8({ctx[x.src[0]]}, {'1' if x.dtype == dtypes.fp8e5m2 else '0'})"), + (UPat(Ops.CAST, dtypes.float, (UPat.var("y", dtypes.fp8s),), name="x",), + lambda ctx,x, y: f"__builtin_amdgcn_cvt_f32_{'bf8' if y.dtype == dtypes.fp8e5m2 else 'fp8'}((unsigned int){ctx[x.src[0]]}, 0)"), + ]) + base_rewrite def __reduce__(self): return self.__class__, (self.arch,) - # language options - ockl = [(f"__ockl_get_{name}", "unsigned int", "size_t", "const") for name in ["local_id", "group_id", "local_size"]] - ocml = [(f"__ocml_{name}_f{n}", f"{dt}, {dt}" if "fmax" == name else dt, dt, atr) - for dt, n in [(dtype.name, dtype.itemsize * 8) for dtype in [dtypes.float, dtypes.double, dtypes.half]] - for name, atr in [("fmax", "const"), ("exp2", "pure"), ("log2", "pure"), ("sqrt", "const"), ("sin", ""), ("trunc", "")]] - - kernel_typedef = "\n".join(f'extern "C" __attribute__((device{f", {atr}" if atr else ""})) {dto} {meth}({dti});' for meth,dti,dto,atr in ockl+ocml) # https://clang.llvm.org/docs/AttributeReference.html#amdgpu-flat-work-group-size # NOTE: this makes hlb_cifar10 twice as fast, there may be more gains in tweaking these parameters - kernel_typedef += '\nextern "C" __attribute__((global)) void __attribute__((amdgpu_flat_work_group_size(1, {launch_bounds})))' + kernel_typedef = 'extern "C" __attribute__((global)) void __attribute__((amdgpu_flat_work_group_size(1, {launch_bounds})))' code_for_workitem = {"g": lambda x: f"__ockl_get_group_id({x})", "l": lambda x: f"__ockl_get_local_id({x})", "i": lambda x: f"(__ockl_get_group_id({x})*__ockl_get_local_size({x})+__ockl_get_local_id({x}))"} code_for_op = { **CStyleLanguage.code_for_op, @@ -439,20 +466,11 @@ class AMDRenderer(CStyleLanguage): barrier = '__builtin_amdgcn_fence(__ATOMIC_RELEASE, "workgroup");' + '__builtin_amdgcn_s_barrier();' + \ '__builtin_amdgcn_fence(__ATOMIC_ACQUIRE, "workgroup");' float4 = "make_float4" - type_map = {dtypes.bfloat16: "hip_bfloat16"} - extra_matcher = PatternMatcher([ - # cast bfloat16 alus to float - (UPat(Ops.WHERE, src=(UPat.var("b"), UPat.var("x", dtype=dtypes.bfloat16), UPat.var("y", dtype=dtypes.bfloat16))), - lambda b,x,y: UOp(Ops.WHERE, dtype=dtypes.float, src=(b,x.cast(dtypes.float),y.cast(dtypes.float))).cast(dtypes.bfloat16)), - (UPat(GroupOp.ALU, dtype=dtypes.bfloat16, name="x"), - lambda x: UOp(x.op, dtypes.float, tuple(vv.cast(dtypes.float) for vv in x.src), x.arg).cast(dtypes.bfloat16)), - (UPat(GroupOp.ALU, dtypes.bool, name="alu", src=(UPat.var("x", dtype=dtypes.bfloat16), UPat.var("y", dtype=dtypes.bfloat16))), - lambda alu,x,y: UOp(alu.op, dtypes.bool, (x.cast(dtypes.float), y.cast(dtypes.float)), alu.arg)), - # add float intermediate casting for bfloat16 - (UPat(Ops.CAST, name="x", src=(UPat.var("y", dtypes.bfloat16),)), - lambda x,y: y.cast(dtypes.float).cast(x.dtype) if x.dtype!=dtypes.float else None), - (UPat(Ops.CAST, dtypes.bfloat16, (UPat.var("x"),)), - lambda x: x.cast(dtypes.float).cast(dtypes.bfloat16) if x.dtype!=dtypes.float else None), + type_map = {dtypes.bfloat16: "hip_bfloat16", dtypes.fp8e4m3: "hip_fp8", dtypes.fp8e5m2: "hip_bf8"} + extra_matcher = create_non_native_float_pats((dtypes.bfloat16, *dtypes.fp8s)) + PatternMatcher([ + (UPat(Ops.WMMA, name="x", dtype=dtypes.float.vec(4)), + lambda x: UOp(Ops.WMMA, x.dtype, (x.src[0].bitcast(dtypes.uint64), x.src[1].bitcast(dtypes.uint64), + x.src[2]), (*x.arg,)) if x.src[0].dtype in (dtypes.fp8e4m3.vec(8), dtypes.fp8e5m2.vec(8)) else None), # bfloat16 casting (UPat.cvar('x', dtypes.bfloat16), lambda x: cast_float_to_bf16(UOp.const(dtypes.float, x.arg))), (UPat(Ops.CAST, dtypes.float, (UPat.var("x", dtypes.bfloat16),)), @@ -465,15 +483,32 @@ class AMDRenderer(CStyleLanguage): f"{vec} make_{vec}({', '.join([f'{scal} {x}' for x in _nms[:dtype.count]])}) {{ return {{ {', '.join(_nms[:dtype.count])} }}; }}" def render_kernel(self, function_name, kernel, bufs, uops, prefix=None) -> str: - prefix = ["#define INFINITY (__builtin_inff())","#define NAN (__builtin_nanf(\"\"))","typedef long unsigned int size_t;","#define half _Float16"] - type_map = { dtypes.bfloat16: "bf16", dtypes.float: "f32", dtypes.half: "f16" } + prefix, ockl = [], [] + type_map = { dtypes.bfloat16: "bf16", dtypes.float: "f32", dtypes.half: "f16", dtypes.fp8e4m3: "_fp8_fp8", dtypes.fp8e5m2: "_bf8_bf8" } used_dtypes = uops_to_dtypes(uops) + if any(u.op is Ops.CONST and not math.isfinite(u.arg) for u in uops): + prefix += ["#define INFINITY (__builtin_inff())", "#define NAN (__builtin_nanf(\"\"))"] + if any(u.op is Ops.SPECIAL for u in uops): + prefix.append("typedef long unsigned int size_t;") + ockl = [(f"__ockl_get_{name}", "unsigned int", "size_t", "const") for name in ["local_id", "group_id", "local_size"]] + ocml_ops = {Ops.EXP2: ("exp2", "pure"), Ops.LOG2: ("log2", "pure"), Ops.SQRT: ("sqrt", "const"), Ops.SIN: ("sin", ""), Ops.TRUNC: ("trunc", "")} + ocml = [(f"__ocml_{ocml_ops[op][0]}_f{dt.itemsize * 8}", dt.name, dt.name, ocml_ops[op][1]) + for op, dt in dedup((u.op, u.dtype.scalar()) for u in uops) if op in ocml_ops and dt in (dtypes.half, dtypes.float, dtypes.double)] if any(dt.scalar() == dtypes.bfloat16 for dt in used_dtypes): prefix.append("typedef unsigned short hip_bfloat16;") + if any(dt.scalar() == dtypes.half for dt in used_dtypes): prefix.append("#define half _Float16") + if any(dt.scalar() in dtypes.fp8s for dt in used_dtypes): + prefix += ["typedef unsigned char hip_bf8;", "typedef unsigned char hip_fp8;"] + prefix.append("""static inline __attribute__((device)) unsigned char f32_to_fp8(float v, int is_bf8) { + v = (((*(unsigned*)&v)&0x7F800000)!=0x7F800000)?__builtin_amdgcn_fmed3f(v,is_bf8?57344.0f:448.0f,is_bf8?-57344.0f:-448.0f) : v; + return (unsigned char)(is_bf8?__builtin_amdgcn_cvt_pk_bf8_f32(v,v,0,false):__builtin_amdgcn_cvt_pk_fp8_f32(v,v,0,false));\n}""") + prefix += [f'extern "C" __attribute__((device{f", {atr}" if atr else ""})) {dto} {meth}({dti});' for meth,dti,dto,atr in ockl+ocml] prefix += [self.render_vector_prefix(dt) for dt in used_dtypes if dt.count > 1] - for name, _, dtype_in, dtype_out, _, _, _, _ in wmma_args(uops): # TODO: handle TCs f32_bf16 and bf16_bf16 w/ wrapper - if self.tensor_cores == tc.amd_cdna: - prefix.append(f"#define __{name} __builtin_amdgcn_mfma_f32_16x16x16{'f16' if dtype_in == dtypes.half else 'bf16_1k'}") + for name, (N, M, K), dtype_in, dtype_out, _, _, _, _ in wmma_args(uops): # TODO: handle TCs f32_bf16 and bf16_bf16 w/ wrapper + if self.is_cdna(self.arch): + if (N, M, K) == (16, 16, 16): type_map[dtypes.bfloat16] = 'bf16_1k' + elif (N, M, K) == (16, 16, 32): type_map = {**type_map, dtypes.bfloat16: "_bf16", dtypes.half: "_f16"} + prefix.append(f"#define __{name} __builtin_amdgcn_mfma_f32_{N}x{M}x{K}{type_map[dtype_in]}") # #define __WMMA_16_16_16_half_half __builtin_amdgcn_wmma_f16_16x16x16_f16_w32_gfx12 elif self.tensor_cores == tc.amd_rdna4: prefix.append(f"#define __{name} __builtin_amdgcn_wmma_{type_map[dtype_out]}_16x16x16_{type_map[dtype_in]}_w32_gfx12") diff --git a/tinygrad/renderer/llvmir.py b/tinygrad/renderer/llvmir.py index 605df487f2..7fd3dd207e 100644 --- a/tinygrad/renderer/llvmir.py +++ b/tinygrad/renderer/llvmir.py @@ -4,7 +4,7 @@ from tinygrad.codegen.opt import tc from tinygrad.renderer import Renderer from tinygrad.renderer.cstyle import AMDRenderer from tinygrad.uop.decompositions import xexp2, xlog2 -from tinygrad.uop.ops import UOp, PatternMatcher, UPat, Ops, GroupOp, sint_to_uop, range_str +from tinygrad.uop.ops import UOp, PatternMatcher, UPat, Ops, GroupOp, range_str from tinygrad.dtype import dtypes, DType, PtrDType, truncate from tinygrad.helpers import prod, AMX @@ -49,9 +49,11 @@ def render_wmma_amx(ctx, wmma: UOp) -> str: def render_wmma_amd(ctx, wmma: UOp, cdna=False) -> str: dt_map = {dtypes.half: "f16", dtypes.float: "f32", dtypes.ushort: "bf16.1k" if cdna else "bf16", dtypes.bfloat16: "bf16.1k" if cdna else "bf16"} # https://github.com/llvm/llvm-project/blob/main/clang/test/CodeGenOpenCL/builtins-amdgcn-mfma.cl + N,M,K = wmma.arg[1] if cdna: + if K == 32: dt_map.update({dtypes.half: ".f16", dtypes.bfloat16: ".bf16"}) return f" {ctx[wmma]} = call {ldt(wmma.dtype)} @llvm.amdgcn.mfma.{dt_map[wmma.src[-1].dtype.scalar()]}" + \ - f".16x16x16{dt_map[wmma.src[0].dtype.scalar()]}(" + ", ".join([f"{ldt(w.dtype)} {ctx[w]}" for w in wmma.src]) + ", i32 0, i32 0, i32 0)" + f".{N}x{M}x{K}{dt_map[wmma.src[0].dtype.scalar()]}(" + ", ".join([f"{ldt(w.dtype)} {ctx[w]}" for w in wmma.src]) + ", i32 0, i32 0, i32 0)" # https://github.com/llvm/llvm-project/blob/main/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.wmma_32.ll # example: %wmma0 = call <8 x float> @llvm.amdgcn.wmma.f32.16x16x16.f16(<16 x half> %v99,<16 x half> %v100,<8 x float> %v101) return f" {ctx[wmma]} = call {ldt(wmma.dtype)} @llvm.amdgcn.wmma.{dt_map[wmma.src[-1].dtype.scalar()]}.16x16x16." + \ @@ -104,15 +106,21 @@ base_rewrite = PatternMatcher([ f" {ctx[x]} = select {ldt(x.src[0].dtype)} {ctx[x.src[0]]}, {ldt(x.src[1].dtype)} {ctx[x.src[1]]}, {ldt(x.src[2].dtype)} {ctx[x.src[2]]}"), # range - (UPat(Ops.RANGE, name="x"), lambda ctx,x: - f" br label %loop_entry_{range_str(x)}\nloop_entry_{range_str(x)}:\n" - f" br label %loop_body_{range_str(x)}\nloop_body_{range_str(x)}:\n" - f" {ctx[x]} = phi {ldt(x.dtype)} [ 0, %loop_entry_{range_str(x)} ], [ {ctx[x]}phi, %loop_latch_{range_str(x)} ]"), - (UPat(Ops.ENDRANGE, name="x"), lambda ctx,x: - f" br label %loop_latch_{range_str(x.src[0])}\nloop_latch_{range_str(x.src[0])}:\n" - f" {ctx[x.src[0]]}phi = add {ldt(x.src[0].dtype)} {ctx[x.src[0]]}, 1\n" - f" {ctx[x]} = icmp ult {ldt(x.src[0].dtype)} {ctx[x.src[0]]}phi, {ctx[x.src[0].src[0]]}\n" - f" br i1 {ctx[x]}, label %loop_body_{range_str(x.src[0])}, label %loop_exit_{range_str(x.src[0])}\nloop_exit_{range_str(x.src[0])}:"), + (UPat(Ops.RANGE, name="r"), lambda ctx,r: + f" br label %loop_entry_{range_str(r)}\n" + f"loop_entry_{range_str(r)}:\n" + f" br label %loop_latch_{range_str(r)}\n" + f"loop_latch_{range_str(r)}:\n" + f" {ctx[r]} = phi {ldt(r.dtype)} [ 0, %loop_entry_{range_str(r)} ], [ {ctx[r]}phi, %loop_footer_{range_str(r)} ]\n" + f" {ctx[r]}phi = add {ldt(r.dtype)} {ctx[r]}, 1\n" + f" {ctx[r]}cmp = icmp ult {ldt(r.dtype)} {ctx[r]}, {ctx[r.src[0]]}\n" + f" br i1 {ctx[r]}cmp, label %loop_body_{range_str(r)}, label %loop_exit_{range_str(r)}\n" + f"loop_body_{range_str(r)}:"), + (UPat(Ops.END, src=(UPat(), UPat(Ops.RANGE, name="r"))), lambda r: + f" br label %loop_footer_{range_str(r)}\n" + f"loop_footer_{range_str(r)}:\n" + f" br label %loop_latch_{range_str(r)}\n" + f"loop_exit_{range_str(r)}:"), # if (UPat(Ops.IF, name="x"), lambda ctx,x: f" br i1 {ctx[x.src[0]]}, label %ifbody_{ctx[x][1:]}, label %ifskip_{ctx[x][1:]}\nifbody_{ctx[x][1:]}:"), @@ -166,7 +174,10 @@ class LLVMRenderer(Renderer): name = "test" for u in uops: - if u.op is Ops.NOOP: continue + if u.op in {Ops.NOOP, Ops.GROUP}: continue + if u.op is Ops.AFTER: + r[u] = r[u.src[0]] + continue if u.op is Ops.SINK: if u.arg is not None: name = u.arg.function_name continue @@ -176,8 +187,10 @@ class LLVMRenderer(Renderer): elif u.op in (Ops.DEFINE_LOCAL, Ops.DEFINE_REG): r[u] = f"%{'local' if u.op is Ops.DEFINE_LOCAL else 'reg'}_{str(u.arg).replace('(', '').replace(')', '').replace(',', '_').replace(' ', '')}" assert isinstance(u.dtype, PtrDType) - if self.device == "CPU" or u.op is Ops.DEFINE_REG: + if u.op is Ops.DEFINE_REG: kernel.append(f" {r[u]} = alloca [{u.dtype.size} x {ldt(u.dtype.base)}]") + elif self.device == "CPU" and u.op is Ops.DEFINE_LOCAL: + kernel.append(f" {r[u]} = alloca [{u.dtype.size} x {ldt(u.dtype.base)}], align 16") else: local_args.append(f"@{r[u][1:]} = internal unnamed_addr addrspace(3) global [{u.dtype.size} x {ldt(u.dtype)}] undef, align 16") kernel.append(f" {r[u]} = addrspacecast [{u.dtype.size} x {ldt(u.dtype)}] addrspace(3)* @{r[u][1:]} to [{u.dtype.size} x {ldt(u.dtype)}]*") @@ -226,14 +239,14 @@ class AMDLLVMRenderer(LLVMRenderer): def _render_footer(self, uops: list[UOp]) -> str: # TODO: this is copied from cstyle local_dims = [u.src[0] for u in uops if u.op is Ops.SPECIAL and u.arg[0] == "l"] - requiredMaxThreadsPerBlock = sint_to_uop(prod(local_dims)).vmax + requiredMaxThreadsPerBlock = prod([d.vmax for d in local_dims]) attributes = ["alwaysinline", "nounwind", '"no-builtins"', f'"amdgpu-flat-work-group-size"="1,{requiredMaxThreadsPerBlock}"', '"no-trapping-math"="true"'] return 'attributes #0 = { ' + ' '.join(attributes) + ' }' def __init__(self, arch:str): self.arch = arch self.tensor_cores = AMDRenderer.get_tensor_cores(arch) - self.is_cdna = arch.split(":")[0] in {"gfx942", "gfx950"} + self.is_cdna = AMDRenderer.is_cdna(arch) self.string_rewrite += PatternMatcher([(UPat(Ops.WMMA, name="wmma"), lambda ctx, wmma, cdna=self.is_cdna: render_wmma_amd(ctx, wmma, cdna))]) if self.is_cdna: self.extra_matcher += PatternMatcher([ @@ -248,7 +261,7 @@ class AMDLLVMRenderer(LLVMRenderer): (UPat(Ops.WMMA, name="x"), lambda x: UOp(Ops.WMMA, x.dtype, (x.src[0].bitcast(dtypes.uint16.vec(16)), x.src[1].bitcast(dtypes.uint16.vec(16)), x.src[2]), x.arg) if x.src[0].dtype == dtypes.bfloat16.vec(16) else None), ]) - if self.arch.split(":")[0] == "gfx1201": + if self.arch.split(":")[0] in {"gfx1200", "gfx1201"}: self.extra_matcher += PatternMatcher([ (UPat(Ops.WMMA, name="x", dtype=dtypes.bfloat16.vec(8)), lambda x: UOp(Ops.WMMA, dtypes.uint16.vec(8), (x.src[0].bitcast(dtypes.uint16.vec(8)), x.src[1].bitcast(dtypes.uint16.vec(8)), x.src[2].bitcast(dtypes.uint16.vec(8))), (*x.arg,)) diff --git a/tinygrad/renderer/nir.py b/tinygrad/renderer/nir.py new file mode 100644 index 0000000000..8fcba798a5 --- /dev/null +++ b/tinygrad/renderer/nir.py @@ -0,0 +1,244 @@ +from typing import Callable, cast, Any +from tinygrad.dtype import AddrSpace, DType, PtrDType, dtypes +from tinygrad.helpers import DEBUG, OSX, unwrap +from tinygrad.renderer import Renderer +from tinygrad.renderer.cstyle import CUDARenderer +from tinygrad.uop.ops import GroupOp, Ops, UOp, PatternMatcher, UPat, range_str +import tinygrad.runtime.autogen.mesa as mesa +import base64, ctypes, ctypes.util, struct, functools, inspect + +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)) + +# this is a ridiculous hack, but I can't find a better way to grab the glsl_type objects +glsl_base = {**{d:g(f"GLSL_TYPE_{'U' if d in dtypes.uints else ''}INT{d.itemsize*8 if d.itemsize != 4 else ''}") for d in dtypes.ints}, + **{getattr(dtypes,d):g(f"GLSL_TYPE_{d.upper()}") for d in ['double', 'float', 'float16']}, dtypes.bool: mesa.GLSL_TYPE_UINT8} +def glsl_type(t:DType) -> mesa.struct_glsl_type: + if isinstance(t, PtrDType): return mesa.glsl_array_type(glsl_type(t.base), t.size, 0).contents + return mesa.glsl_get_base_glsl_type(mesa.glsl_type(base_type=glsl_base[t])).contents + +# alu ops, aop[][] +u_aop = { Ops.ADD: "iadd", Ops.MUL: "imul", Ops.IDIV: "udiv", Ops.MOD: "umod", Ops.CMPLT: "ult", Ops.CMPNE: "ine", Ops.CMPEQ: "ieq", Ops.OR: "ior", + Ops.AND: "iand", Ops.XOR: "ixor", Ops.WHERE: "bcsel", Ops.MAX: "umax"} +s_aop = {**u_aop, Ops.CMPLT: "ilt", Ops.IDIV: "idiv", Ops.MOD: "irem", Ops.MAX: "imax"} +f_aop = { Ops.ADD: "fadd", Ops.MUL: "fmul", Ops.CMPLT: "flt", Ops.CMPNE: "fneu", Ops.CMPEQ: "feq", Ops.FDIV: "fdiv", Ops.RECIPROCAL: "frcp", + Ops.MAX: "fmax", Ops.TRUNC: "ftrunc", Ops.SIN: "fsin", Ops.EXP2: "fexp2", Ops.LOG2: "flog2"} +aop = {**{x:u_aop for x in (dtypes.bool,)+dtypes.uints}, **{x:s_aop for x in dtypes.sints}, **{x:f_aop for x in dtypes.floats}} + +def c(t:DType, u:bool=True) -> str: return "u" if t in dtypes.uints and u else ("i" if t in dtypes.ints else ("f" if t in dtypes.floats else "b")) +def ncast(b:mesa.nir_builder, src:mesa.nir_def, it:DType, ot:DType) -> mesa.nir_def: + if isinstance(it, PtrDType) and ot == dtypes.long: return src + if ot == dtypes.bool: return nalu(b, c(it, False)+'ne'+('u' if c(it) == 'f' else ''), src, nimm(b, 0, it)) + return nalu(b, f"{c(it)}2{c(it) if it in dtypes.ints and ot in dtypes.ints else c(ot, ot == dtypes.bool)}{ot.itemsize*8}", src) + +def nif(b:mesa.nir_builder, cond:mesa.nir_def, then_fn:Callable, else_fn:Callable): + nif = mesa.nir_push_if(b, cond) + t = then_fn() + mesa.nir_push_else(b, nif) + e = else_fn() + mesa.nir_pop_if(b, nif) + return t, e + +def nalu(b:mesa.nir_builder, op:str, *srcs:mesa.nir_def) -> mesa.nir_def: return g(f"nir_build_alu{len(srcs)}")(b, g(f"nir_op_{op}"), *srcs).contents + +def nir_instr(nc=1, bs=lambda: None, intrins=None, srcs=None, has_def=True, df=None, also=lambda: None, **contents): + def dec(f:Callable): + @functools.wraps(f) + def wrapper(*args, **kwargs) -> mesa.nir_def: + (ba:=inspect.signature(f).bind(*args, **kwargs)).apply_defaults() + def go(g): return g(**{nm: ba.arguments[nm] for nm in inspect.signature(g).parameters}) if callable(g) else g + + instr = f(*args, **kwargs) + if has_def: mesa.nir_def_init(instr.contents.instr, getattr(instr.contents, "def"), go(nc), go(bs)) + for k, v in go(intrins or {}).items(): + idx = mesa.nir_intrinsic_infos[instr.contents.intrinsic].index_map[g(f"NIR_INTRINSIC_{k}")] + assert idx > 0 + instr.contents.const_index[idx - 1] = go(v) + for i, src in enumerate(go(srcs or [])): ctypes.cast(instr.contents.src, ctypes.POINTER(mesa.nir_src))[i] = go(src) + for k,v in {k:vcomp for k,v in contents.items() if (vcomp:=go(v)) is not None}.items(): setattr(instr.contents, k, go(v)) + mesa.nir_builder_instr_insert(ba.arguments['b'], instr.contents.instr) + go(also) + return getattr(instr.contents, "def") if has_def else (mesa.nir_def() if df is None else go(df)) + return wrapper + return dec + +@nir_instr(nc=1, bs=lambda src: src.bit_size, exact=lambda b:b.exact, fp_fast_math=lambda b:b.fp_fast_math) +def nchannel(b:mesa.nir_builder, src:mesa.nir_def, c:int): + alu_src = mesa.nir_alu_src(src=nsrc(src)) + alu_src.swizzle[0] = c + mov = mesa.nir_alu_instr_create(b.shader, mesa.nir_op_mov) + ctypes.cast(mov.contents.src, ctypes.POINTER(mesa.nir_alu_src))[0] = alu_src + return mov + +@nir_instr(nc=1, bs=lambda dtype: 1 if dtype == dtypes.bool else dtype.itemsize * 8) +def nimm(b:mesa.nir_builder, x, dtype:DType) -> mesa.nir_def: + instr = mesa.nir_load_const_instr_create(b.shader, 1, 1 if dtype == dtypes.bool else dtype.itemsize * 8) + struct.pack_into(unwrap(dtype.fmt), (ctypes.c_ubyte * dtype.itemsize).from_address(ctypes.addressof(instr.contents.value)), 0, x) + return instr + +deref_var = nir_instr(nc=1, bs=32, modes=lambda var:var.data.mode, type=lambda var:var.type, var=lambda var:ctypes.pointer(var))( # pylint: disable=W0108 + lambda b, var: mesa.nir_deref_instr_create(b.shader, mesa.nir_deref_type_var)) + +def iointr(space): return {"ALIGN_MUL":lambda dtype:dtype.itemsize} if space != AddrSpace.REG else {} +def scope(space): return 'global' if space == AddrSpace.GLOBAL else ('shared' if space == AddrSpace.LOCAL else 'deref') +nstore = nir_instr(has_def=False, df=lambda addr:addr, intrins=lambda space,val: {"WRITE_MASK":(1< mesa.nir_def: + @nir_instr(nc=1, bs=32, modes=lambda buf: buf.data.mode, type=lambda buf: mesa.glsl_get_array_element(buf.type)) + def reg(b, buf): + deref = mesa.nir_deref_instr_create(b.shader, mesa.nir_deref_type_array) + deref.contents.parent, deref.contents.arr.index = nsrc(deref_var(b, buf)), nsrc(off) + return deref + f = (functools.partial(reg, b, buf) if dtype.addrspace == AddrSpace.REG else + lambda: nalu(b, "iadd", buf, nalu(b, "imul", off, nimm(b, dtype.itemsize, dtypes.long)))) + return if_phi(b, gate, f, lambda: buf) if gate is not None else f() + +class NIRRenderer(Renderer): + suffix = "NAK" + global_max, local_max, shared_max = CUDARenderer.global_max, CUDARenderer.local_max, CUDARenderer.shared_max + code_for_op = {**{k:lambda:None for k in u_aop.keys()}, **{k:lambda:None for k in s_aop.keys()}, **{k:lambda:None for k in f_aop.keys()}} + + extra_matcher = PatternMatcher([ + # handle negative unsigned CONST + (UPat.cvar("x", dtypes.uints), lambda x: UOp(Ops.CONST, dtype=x.dtype, arg=x.dtype.max+x.arg+1) if x.arg < 0 else None), + # from ptx + (UPat.var('x', dtype=dtypes.bool) uint8 + (UPat(Ops.LOAD, dtypes.bool, name="x"), + lambda x: x.replace(dtype=dtypes.uint8, src=x.src[0:1]+((x.src[1].cast(dtypes.uint8),) if len(x.src)>=2 else ())+x.src[2:]).cast(dtypes.bool)), + (UPat(Ops.STORE, src=(UPat(), UPat(dtype=dtypes.bool)), name="x", allow_any_len=True), + lambda x: x.replace(src=x.src[0:1] + (x.src[1].cast(dtypes.uint8),) + x.src[2:])), + # load/store use pointer arithmetic, and the cast does nothing + (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("off")), allow_any_len=True, name="x"), + lambda x,buf,off: x.replace(src=(buf,off.cast(dtypes.long))+x.src[2:]) if buf.dtype.addrspace != AddrSpace.REG and off.op != Ops.CAST else None), + (UPat(Ops.CAST, name="x"), lambda x: x.src[0] if isinstance(x.dtype, PtrDType) or x.src[0].dtype == dtypes.void else None), + ]) + + def_rewrite = PatternMatcher([ + (UPat(Ops.CONST, name="x"), lambda ctx,x: nimm(ctx.b, x.arg, x.dtype)), + (UPat(Ops.DEFINE_GLOBAL, name="x"), lambda ctx,x: ctx.param(ctx.b, x.dtype, 8)), + (UPat(Ops.DEFINE_VAR, name="x"), lambda ctx,x: ctx.param(ctx.b, x.dtype, 4)), + (UPat(Ops.SPECIAL, name="x"), lambda ctx,x: nchannel(ctx.b, ngid(ctx.b) if x.arg[0] == 'g' else nlid(ctx.b), int(x.arg[-1]))), + (UPat(Ops.STORE, src=(UPat(Ops.INDEX, src=(UPat.var("buf"),UPat.var("off")), allow_any_len=True), UPat.var("val")), allow_any_len=True, name="x"), + lambda ctx,x,buf,off,val: nstore(ctx.b, buf.ptrdtype.addrspace, nidx(ctx.b, ctx.r[buf], ctx.r[off], buf.dtype), ctx.r[val], val.dtype)), + (UPat(Ops.LOAD, src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("off"), UPat.var("gate"))), UPat.var("alt")), allow_any_len=True, name="x"), + lambda ctx,x,buf,off,alt,gate: if_phi(ctx.b, ctx.r[gate], + lambda: nload(ctx.b, buf.ptrdtype.addrspace, nidx(ctx.b, ctx.r[buf], ctx.r[off], buf.dtype, ctx.r[gate]), x.dtype), lambda: ctx.r[alt])), + (UPat(Ops.LOAD, src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("off"))),), allow_any_len=True, name="x"), + lambda ctx,x,buf,off: nload(ctx.b, buf.ptrdtype.addrspace, nidx(ctx.b, ctx.r[buf], ctx.r[off], buf.dtype), x.dtype)), + (UPat(Ops.VECTORIZE, name="x"), lambda ctx,x: nalu(ctx.b, f"vec{x.dtype.count}", *[ctx.r[src] for src in x.src])), + (UPat(GroupOp.ALU, name="x"), lambda ctx,x: nalu(ctx.b, aop[x.src[0].dtype.scalar()][x.op], *[ctx.r[src] for src in x.src])), + (UPat(Ops.CAST, name="x"), lambda ctx,x: ncast(ctx.b, ctx.r[x.src[0]], x.src[0].dtype, x.dtype)), + (UPat(Ops.BITCAST, src=(UPat.var("a"),), allow_any_len=True), lambda ctx,a: ctx.r[a]), + (UPat(Ops.GEP, src=(UPat.var("a"),), name="x"), lambda ctx,x,a: nchannel(ctx.b, ctx.r[a], x.arg[0])), + (UPat(Ops.DEFINE_REG, name="x"), lambda ctx,x:mesa.nir_local_variable_create(ctx.b.impl, glsl_type(x.dtype), f"acc{x.arg}".encode()).contents), + (UPat(Ops.BARRIER), lambda ctx: nbarrier(ctx.b)), + (UPat(Ops.IF, name="x"), lambda ctx,x: mesa.nir_push_if(ctx.b, ctx.r[x.src[0]])), + (UPat(Ops.ENDIF, name="x"), lambda ctx,x: (lambda _: mesa.nir_def())(mesa.nir_pop_if(ctx.b, ctx.r[x.src[0]]))) + ]) + + def __init__(self): mesa.glsl_type_singleton_init_or_ref() + + def __del__(self): + try: mesa.glsl_type_singleton_decref() + except FileNotFoundError: pass + + @property + def nir_options(self): raise NotImplementedError("needs nir_options") + def param(self, b:mesa.nir_builder, dtype:DType, sz:int) -> mesa.nir_def: raise NotImplementedError("needs param") + def prerender(self, uops:list[UOp]): + self.b = mesa.nir_builder_init_simple_shader(mesa.MESA_SHADER_COMPUTE, mesa.nir_shader_compiler_options.from_buffer_copy(self.nir_options), None) + + def render(self, uops:list[UOp]): + self.prerender(uops) + for u in [u for u in uops if u.op is Ops.SPECIAL and u.arg[0] == "l"]: self.b.shader.contents.info.workgroup_size[int(u.arg[-1])] = u.src[0].arg + self.r: dict[UOp, Any] = {} + self.param_idx, ranges = 0, [] + + for u in uops: + if u.op in {Ops.NOOP, Ops.GROUP, Ops.INDEX}: pass + elif u.op is Ops.AFTER: + self.r[u] = self.r[u.src[0]] + elif u.op == Ops.SINK: + if u.arg is not None: self.b.shader.contents.info.name = mesa.char_pointer_cast(u.arg.function_name) + elif u.op == Ops.DEFINE_LOCAL: + self.r[u] = nimm(self.b, self.b.shader.contents.info.shared_size, dtypes.long) + self.b.shader.contents.info.shared_size += u.dtype.nbytes() + elif u.op == Ops.RANGE: + ranges.append(i:=deref_var(self.b, mesa.nir_local_variable_create(self.b.impl, glsl_type(u.dtype), f"idx{range_str(u)}".encode()).contents)) + nstore(self.b, AddrSpace.REG, i, nimm(self.b, 0, u.dtype), u.dtype) + mesa.nir_push_loop(self.b) + self.r[u] = nload(self.b, AddrSpace.REG, i, u.dtype) + nif(self.b, nalu(self.b, "ilt", self.r[u], self.r[u.src[0]]), lambda: None, lambda: njump(self.b, mesa.nir_jump_break)) + elif u.op == Ops.END: + r = u.src[1] + next_i = nalu(self.b, "iadd", self.r[r], nimm(self.b, 1, r.dtype)) + # TODO: this nif should be removable ... but TestMultiTensor.test_double_matmul_shard_W_0 segfaults with it gone + nif(self.b, nalu(self.b, "ilt", next_i, self.r[r.src[0]]), lambda: None, lambda: njump(self.b, mesa.nir_jump_break)) + nstore(self.b, AddrSpace.REG, ranges.pop(), next_i, r.dtype), + mesa.nir_pop_loop(self.b, None) + else: + if (d:=self.def_rewrite.rewrite(u, ctx=self)) is None: raise RuntimeError(f"failed to render {u.op} srcs {[x.dtype for x in u.src]}") + self.r[u] = cast(mesa.nir_def, d) + + mesa.nir_validate_shader(self.b.shader, b"after render") + if DEBUG >= 4: mesa.nir_print_shader(self.b.shader, ctypes.POINTER(mesa.struct__IO_FILE).in_dll(ctypes.CDLL(ctypes.util.find_library('c')), + "__stdoutp" if OSX else "stdout")) + mesa.nir_serialize(blob:=mesa.struct_blob(), self.b.shader, False) + ret = base64.b64encode(ctypes.string_at(blob.data, blob.size)).decode() + + mesa.ralloc_free(self.b.shader) + ctypes.CDLL(None).free(blob.data) + del self.b, self.r + + return ret + +class NAKRenderer(NIRRenderer): + device = "NV" + def __init__(self, dev=None, nir_options=None): + self.dev, self._nir_options = dev, nir_options + super().__init__() + + def __reduce__(self): return NAKRenderer, (None, self.nir_options,) + + @property + def nir_options(self): + if self._nir_options is None: self._nir_options = self.dev.compiler.nir_options + return self._nir_options + + param = nir_instr(nc=1, num_components=1, bs=lambda sz:sz*8, also=lambda self,sz: setattr(self, "param_idx", self.param_idx + sz), + intrins={"ALIGN_MUL":lambda sz:sz}, srcs=lambda self,b: [nsrc(nimm(b, 0, dtypes.int)), nsrc(nimm(b, self.param_idx, dtypes.int))])( + lambda self, b, dtype, sz: mesa.nir_intrinsic_instr_create(b.shader, mesa.nir_intrinsic_ldc_nv)) + +class LVPRenderer(NIRRenderer): + device = "CPU" + has_local = False + has_shared = False + global_max = (1, 0, 0) + nir_options = mesa.lvp_nir_options + + param = nir_instr(nc=1, bs=lambda sz: sz * 8, num_components=1, intrins={"ALIGN_MUL":lambda sz: sz, "RANGE":lambda self: self.param_sz}, + srcs=lambda b, self: [nsrc(nimm(b, 0, dtypes.int)), nsrc(nimm(b, self.param_idx, dtypes.int))], also=lambda self, sz: + setattr(self, "param_idx", self.param_idx+sz))(lambda self, b, dtype, sz: mesa.nir_intrinsic_instr_create(b.shader, mesa.nir_intrinsic_load_ubo)) + + def prerender(self, uops:list[UOp]): + super().prerender(uops) + self.param_sz = sum([8 if u.op == Ops.DEFINE_GLOBAL else u.dtype.itemsize for u in uops if u.op in (Ops.DEFINE_GLOBAL, Ops.DEFINE_VAR)]) + diff --git a/tinygrad/renderer/ptx.py b/tinygrad/renderer/ptx.py index d620a1b03b..e61fc3eda1 100644 --- a/tinygrad/renderer/ptx.py +++ b/tinygrad/renderer/ptx.py @@ -2,11 +2,11 @@ from typing import cast, Callable import struct from collections import defaultdict from tinygrad.codegen.opt import tc -from tinygrad.uop.ops import Ops, UOp, PatternMatcher, UPat, GroupOp, sint_to_uop +from tinygrad.uop.ops import Ops, UOp, PatternMatcher, UPat, GroupOp from tinygrad.dtype import dtypes, DType, PtrDType, AddrSpace from tinygrad.renderer import Renderer from tinygrad.renderer.cstyle import CUDARenderer -from tinygrad.helpers import flatten, get_single_element, prod +from tinygrad.helpers import flatten, get_single_element, prod, unwrap def render_val(x, dtype): if dtypes.is_float(dtype): @@ -16,7 +16,7 @@ def render_val(x, dtype): return str(int(x)) + ("U" if dtypes.is_unsigned(dtype) else "") asm_for_op: dict[Ops, Callable] = { - Ops.RECIP: lambda d,a,dt,name: f"rcp{'.approx' if dtypes.is_float(dt) else ''}.{name} {d}, {a};", + Ops.RECIPROCAL: lambda d,a,dt,name: f"rcp{'.approx' if dtypes.is_float(dt) else ''}.{name} {d}, {a};", Ops.EXP2: lambda d,a,dt,name: f"ex2.approx.{name} {d}, {a};", Ops.LOG2: lambda d,a,dt,name: f"lg2.approx.{name} {d}, {a};", Ops.SIN: lambda d,a,dt,name: f"sin.approx.{name} {d}, {a};", Ops.SQRT: lambda d,a,dt,name: f"sqrt.approx.{name} {d}, {a};", Ops.TRUNC: lambda d,a,dt,name: f"cvt.rzi.{name}.{name} {d}, {a};", @@ -49,21 +49,23 @@ ptx_matcher = PatternMatcher([ lambda x: UOp(x.op, dtypes.uint8, x.src[0:1] + ((x.src[1].cast(dtypes.uint8),) if len(x.src) >= 2 else ()) + x.src[2:]).cast(dtypes.bool)), (UPat(Ops.STORE, src=(UPat(dtype=dtypes.int64), UPat(dtype=dtypes.bool)), name="x", allow_any_len=True), lambda x: UOp(x.op, dtypes.void, x.src[0:1] + (x.src[1].cast(dtypes.uint8),) + x.src[2:])), + # indexing on PTX is in uint64, we do the math while it's still in the graph + (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx")), name="op", allow_any_len=True), lambda buf,idx,op: + UOp(Ops.INDEX, dtype=dtypes.int64, src=(buf, buf.cast(dtypes.int64)+idx.cast(dtypes.int64)*buf.dtype.itemsize)+op.src[2:]) \ + if op.dtype != dtypes.int64 and buf.dtype.addrspace != AddrSpace.REG else None), # load/store use pointer arithmetic, and the cast does nothing - (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx"))), - lambda buf,idx: (buf.cast(dtypes.int64) + idx.cast(dtypes.int64)*buf.dtype.itemsize) if buf.dtype.addrspace != AddrSpace.REG else None), (UPat(Ops.CAST, name="x"), lambda x: x.src[0] if isinstance(x.dtype, PtrDType) or x.src[0].dtype == dtypes.void else None), - # move mask from INDEX to the load/store to enable pointer arithmetic - (UPat(Ops.LOAD, src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx"), UPat.var("gate"))), UPat.var("alt")), allow_any_len=True, name="l"), - lambda buf,idx,gate,alt,l: UOp(Ops.LOAD, alt.dtype, (buf.index(idx), alt, gate, *l.src[2:]))), - (UPat(Ops.STORE, src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx"), UPat())), UPat.var("val"), UPat.var("gate")), allow_any_len=True), - lambda buf,idx,val,gate: UOp.store(buf.index(idx), val, gate)), # ptx shr and shl instructions require y to be uint (UPat.var("x") << UPat.var("y"), lambda x,y: UOp(Ops.SHL, x.dtype, (x,y.cast(dtypes.uint))) if y.dtype != dtypes.uint else None), (UPat.var("x") >> UPat.var("y"), lambda x,y: UOp(Ops.SHR, x.dtype, (x,y.cast(dtypes.uint))) if y.dtype != dtypes.uint else None), ]) -def mem_type(x: UOp): return 'shared' if any(_x.op is Ops.DEFINE_LOCAL for _x in x.src[0].toposort()) else 'global' +def mem_type(x:UOp) -> str: + match x.op: + case Ops.AFTER: return mem_type(x.src[0]) + case Ops.DEFINE_LOCAL: return 'shared' + case Ops.DEFINE_GLOBAL: return 'global' + case _: raise RuntimeError(f"{x.op} needs to be memory") def render_wmma(ctx: "PTXRenderer", wmma: UOp): assert ctx.wmma_r, "registry values for wmma must be populated" @@ -88,9 +90,6 @@ def modifier(a: DType, b: DType): return '.rzi' if dtypes.is_int(a) and dtypes.i string_rewrite = PatternMatcher([ (UPat.cvar("x", dtypes.bool), lambda ctx, x: f"setp.ne.s16 {ctx.r[x]}, {render_val(x.arg, x.dtype)}, 0;"), (UPat.cvar("x"), lambda ctx, x: f"mov.b{ctx.types[x.dtype][1:]} {ctx.r[x]}, {render_val(x.arg, x.dtype)};"), - (UPat(Ops.STORE, name="x", src=(UPat.var('bidx'), UPat.var("var")), allow_any_len=True), lambda ctx, x, bidx, var: f"st.{mem_type(bidx)}" + \ - f"{f'.v{cnt}' if ((cnt:=var.dtype.count)>1) else ''}.{ctx.mem_types[var.dtype.scalar()]} " + \ - f"[{ctx.r[bidx]}+0], {('{' + ', '.join(ctx.r[var]) + '}') if var.dtype.count > 1 else ctx.r[var]};"), (UPat(Ops.SPECIAL, name="x"), lambda ctx,x: f"mov.u32 %{x.arg}, %{'ctaid' if x.arg[0] == 'g' else 'tid'}.{chr(120+int(x.arg[-1]))};"), (UPat(Ops.DEFINE_GLOBAL, name="x"), lambda ctx, x: f"ld.param.{ctx.types[dtypes.ulong]} {ctx.r[x]}, [data{x.arg}+0];"), (UPat((Ops.CMPLT, Ops.CMPNE, Ops.CMPEQ), name="x", allow_any_len=True, src=(UPat.var("src0"),)), @@ -103,22 +102,32 @@ string_rewrite = PatternMatcher([ lambda ctx, x, a: f"setp.ne.b{ctx.types[a.dtype][1:]} {ctx.r[x]}, {ctx.r[a]}, {render_val(0, a.dtype)};"), (UPat(Ops.CAST, name="x", src=(UPat.var("a"),)), lambda ctx, x, a: f"cvt{modifier(x.dtype, a.dtype)}.{ctx.cast_types[x.dtype]}.{ctx.cast_types[a.dtype]} {ctx.r[x]}, {ctx.r[a]};"), - (UPat(Ops.LOAD, name="x", src=(UPat.var('loc'), UPat(name='alt'), UPat(name="gate", op=GroupOp.ALU)), allow_any_len=True), - lambda ctx, x, loc, alt, gate: flatten([ + # store / gated load / load + (UPat(Ops.STORE, src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("loc")), allow_any_len=True), UPat.var("var"))), + lambda ctx, loc, var, buf: f"st.{mem_type(buf)}" + \ + f"{f'.v{cnt}' if ((cnt:=var.dtype.count)>1) else ''}.{ctx.mem_types[var.dtype.scalar()]} " + \ + f"[{ctx.r[loc]}+0], {('{' + ', '.join(ctx.r[var]) + '}') if var.dtype.count > 1 else ctx.r[var]};"), + (UPat(Ops.LOAD, name="x", src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("loc"), UPat.var("gate"))), UPat.var("alt")), allow_any_len=True), + lambda ctx, x, loc, alt, gate, buf: flatten([ [f"mov.{ctx.mem_types[x.dtype.scalar()]} {v}, {render_val(0, x.dtype.scalar())};" for v in ctx.r[x]], - [f"@{ctx.r[gate]} ld.{mem_type(x)}.v{x.dtype.count}.{ctx.mem_types[x.dtype.scalar()]} {{{', '.join(ctx.r[x])}}}, [{ctx.r[loc]}+0];"] + [f"@{ctx.r[gate]} ld.{mem_type(buf)}.v{x.dtype.count}.{ctx.mem_types[x.dtype.scalar()]} {{{', '.join(ctx.r[x])}}}, [{ctx.r[loc]}+0];"] ]) if alt.dtype.count > 1 else [ - f"@{ctx.r[gate]} ld.{mem_type(x)}.{ctx.mem_types[x.dtype.scalar()]} {ctx.r[x]}, [{ctx.r[loc]}+0];", + f"@{ctx.r[gate]} ld.{mem_type(buf)}.{ctx.mem_types[x.dtype.scalar()]} {ctx.r[x]}, [{ctx.r[loc]}+0];", f"@!{ctx.r[gate]} mov.b{ctx.types[x.dtype.scalar()][1:]} {ctx.r[x]}, {ctx.r[alt]};"]), - (UPat(Ops.LOAD, name="x", src=(UPat.var('loc'),), allow_any_len=True), - lambda ctx, x, loc: f"ld.{mem_type(x)}.v{x.dtype.count}.{ctx.mem_types[x.dtype.scalar()]} {{{', '.join(ctx.r[x])}}}, [{ctx.r[loc]}+0];" \ - if x.dtype.count > 1 else f"ld.{mem_type(x)}.{ctx.mem_types[x.dtype]} {ctx.r[x]}, [{ctx.r[loc]}+0];"), + (UPat(Ops.LOAD, name="x", src=(UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("loc"))),), allow_any_len=True), + lambda ctx, x, loc, buf: f"ld.{mem_type(buf)}.v{x.dtype.count}.{ctx.mem_types[x.dtype.scalar()]} {{{', '.join(ctx.r[x])}}}, [{ctx.r[loc]}+0];" \ + if x.dtype.count > 1 else f"ld.{mem_type(buf)}.{ctx.mem_types[x.dtype]} {ctx.r[x]}, [{ctx.r[loc]}+0];"), + # simple (UPat(Ops.DEFINE_REG, src=()), lambda ctx: []), - (UPat(Ops.RANGE, name="x"), lambda ctx, x: [f"mov.u32 {ctx.r[x]}, 0;", "LOOP_" + f"{ctx.r[x][1:]}:"]), - (UPat(Ops.ENDRANGE, name="x", src=(UPat.var("src0"),)), lambda ctx, x, src0: [ - ctx.code_for_op[Ops.ADD](ctx.r[src0], ctx.r[src0], "1", dtypes.int, ctx.types[dtypes.int]), - ctx.code_for_op[Ops.CMPLT](ctx.r[x], ctx.r[x.src[0]], ctx.r[src0.src[0]], dtypes.int, ctx.types[dtypes.int]), - f"@{ctx.r[x]} bra LOOP_{ctx.r[src0][1:]};"]), + (UPat(Ops.RANGE, name="r"), lambda ctx, r: [ + f"mov.u32 {ctx.r[r]}, -1;", + f"bra END_{ctx.r[r][1:]};", + "LOOP_" + f"{ctx.r[r][1:]}:"]), + (UPat(Ops.END, name="x", src=(UPat(), UPat(Ops.RANGE, name="r"))), lambda ctx, x, r: [ + "END_" + f"{ctx.r[r][1:]}:", + ctx.code_for_op[Ops.ADD](ctx.r[r], ctx.r[r], "1", dtypes.int, ctx.types[dtypes.int]), + ctx.code_for_op[Ops.CMPLT](ctx.r[x], ctx.r[r], ctx.r[r.src[0]], dtypes.int, ctx.types[dtypes.int]), + f"@{ctx.r[x]} bra LOOP_{ctx.r[r][1:]};"]), (UPat(Ops.DEFINE_LOCAL, name="x"), lambda ctx, x: [f".shared .align 16 .b8 local{x.arg}[{x.dtype.size*x.dtype.itemsize}];", f"mov.u64 {ctx.r[x]}, local{x.arg}[0];"]), (UPat(Ops.IF, name="x"), lambda ctx, x: f"@!{ctx.r[x.src[0]]} bra IF_{ctx.r[x.src[0]][1:]}_{ctx.uops.index(x)};"), @@ -157,7 +166,7 @@ class PTXRenderer(Renderer): def fmt(line): return line if line[0]=="$" else "\t" + line.replace(" ", "\t" if len(line.split(" ")[0]) > 7 else "\t\t", 1) kernel = '\n'.join(map(fmt, [f".reg .{reg.split('_')[-2]} %{reg}<{cnt}>;" for reg,cnt in regs] + kernel + ["ret;"])) local_dims = [u.src[0] for u in uops if u.op is Ops.SPECIAL and u.arg[0] == "l"] - launch_bounds = sint_to_uop(prod(local_dims)).vmax + launch_bounds = prod([d.vmax for d in local_dims]) params = ',\n\t'.join([f".param .{'u64' if dtype.__class__ == PtrDType else self.types[dtype]} {name}" for name,dtype in bufs]) return f"{self.kernel_prefix.format(launch_bounds=launch_bounds)} {function_name} (\n\t{params}\n)\n.maxntid {launch_bounds}\n{{\n{kernel}\n}}" @@ -172,13 +181,16 @@ class PTXRenderer(Renderer): def ssa(prefix:str, u:UOp|None=None, dtype:str|None=None) -> str: nonlocal c, r - prefix += f"_{dtype if dtype is not None else self.types[cast(UOp, u).dtype.base]}_" + prefix += f"_{dtype if dtype is not None else self.types[unwrap(u).dtype.base]}_" c[prefix] += 1 return f"%{prefix}{c[prefix]-1}" name = "test" for u in uops: - if u.op is Ops.NOOP: continue + if u.op in {Ops.NOOP, Ops.GROUP}: continue + if u.op is Ops.AFTER: + self.r[u] = self.r[u.src[0]] + continue if u.op is Ops.SINK: if u.arg is not None: name = u.arg.function_name continue @@ -204,6 +216,7 @@ class PTXRenderer(Renderer): typ = "pred" if u.src[1].dtype == dtypes.bool else ("b"+self.types[u.src[1].dtype][1:]) kernel.append(f"mov.{typ} {self.r[u.src[0]]}, {self.r[u.src[1]]};") continue + if u.op is Ops.INDEX: continue # other index we can skip if u.op is Ops.SPECIAL: r[u] = "%" + u.arg elif u.op is Ops.DEFINE_VAR: bufs.append((u.arg[0], u.dtype)) elif u.op is Ops.LOAD: @@ -216,7 +229,7 @@ class PTXRenderer(Renderer): [ssa("wmma_in", dtype="b32") for _ in range(0, len(r[u.src[1]]), 4 // u.src[0].dtype.scalar().itemsize)], [ssa("wmma_acc", dtype="b32") for _ in range(0, len(r[u.src[2]]), 4 // u.dtype.scalar().itemsize)]] r[u] = [ssa("wmma", dtype=self.types[u.dtype.scalar()]) for _ in range(u.dtype.count)] - prefix, dtype = {Ops.CAST: ("cast", None), Ops.BITCAST: ("cast", None), Ops.ENDRANGE: ("pred", "pred"), Ops.RANGE: ("ridx", None), + prefix, dtype = {Ops.CAST: ("cast", None), Ops.BITCAST: ("cast", None), Ops.END: ("pred", "pred"), Ops.RANGE: ("ridx", None), Ops.DEFINE_VAR: ("dat", None), Ops.CONST: ("const", None), Ops.DEFINE_LOCAL: ("local",self.types[dtypes.ulong]), Ops.DEFINE_GLOBAL: ("dat", self.types[dtypes.ulong]), **{op: ("alu", None) for op in GroupOp.ALU}}.get(u.op, (None, None)) if prefix: r[u] = ssa(prefix, u, dtype) diff --git a/tinygrad/runtime/autogen/__init__.py b/tinygrad/runtime/autogen/__init__.py new file mode 100644 index 0000000000..2e042bc387 --- /dev/null +++ b/tinygrad/runtime/autogen/__init__.py @@ -0,0 +1,17 @@ +import importlib, pathlib +from tinygrad.helpers import system + +root = (here:=pathlib.Path(__file__).parent).parents[2] + +def load(name, dll, files, **kwargs): + if not (f:=(root/(path:=kwargs.pop("path", __name__)).replace('.','/')/f"{name}.py")).exists(): + files = files() if callable(files) else files + f.write_text(importlib.import_module("tinygrad.runtime.support.autogen").gen(dll, files, **kwargs)) + return importlib.import_module(f"{path}.{name.replace('/', '.')}") + +def __getattr__(nm): + match nm: + case "libc": return load("libc", ["find_library('c')"], lambda: ( + [i for i in system("dpkg -L libc6-dev").split() if 'sys/mman.h' in i or 'sys/syscall.h' in i] + + ["/usr/include/string.h", "/usr/include/elf.h", "/usr/include/unistd.h", "/usr/include/asm-generic/mman-common.h"]), use_errno=True) + case _: raise AttributeError(f"no such autogen: {nm}") diff --git a/tinygrad/runtime/autogen/am/am.py b/tinygrad/runtime/autogen/am/am.py index 0bbfe1b886..cad89c6925 100644 --- a/tinygrad/runtime/autogen/am/am.py +++ b/tinygrad/runtime/autogen/am/am.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/pm4_nv.py b/tinygrad/runtime/autogen/am/pm4_nv.py index c21fbfb2bc..a12b11eb93 100644 --- a/tinygrad/runtime/autogen/am/pm4_nv.py +++ b/tinygrad/runtime/autogen/am/pm4_nv.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/pm4_soc15.py b/tinygrad/runtime/autogen/am/pm4_soc15.py index 16e9ee3d5e..3301a0d11b 100644 --- a/tinygrad/runtime/autogen/am/pm4_soc15.py +++ b/tinygrad/runtime/autogen/am/pm4_soc15.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/sdma_4_0_0.py b/tinygrad/runtime/autogen/am/sdma_4_0_0.py index a48adeed78..14f7ee660e 100644 --- a/tinygrad/runtime/autogen/am/sdma_4_0_0.py +++ b/tinygrad/runtime/autogen/am/sdma_4_0_0.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/sdma_4_4_2.py b/tinygrad/runtime/autogen/am/sdma_4_4_2.py index a48adeed78..14f7ee660e 100644 --- a/tinygrad/runtime/autogen/am/sdma_4_4_2.py +++ b/tinygrad/runtime/autogen/am/sdma_4_4_2.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/sdma_5_0_0.py b/tinygrad/runtime/autogen/am/sdma_5_0_0.py index 1eb64252ca..57f541bee5 100644 --- a/tinygrad/runtime/autogen/am/sdma_5_0_0.py +++ b/tinygrad/runtime/autogen/am/sdma_5_0_0.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/sdma_6_0_0.py b/tinygrad/runtime/autogen/am/sdma_6_0_0.py index b8934de798..37d2329ca6 100644 --- a/tinygrad/runtime/autogen/am/sdma_6_0_0.py +++ b/tinygrad/runtime/autogen/am/sdma_6_0_0.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/smu_v13_0_0.py b/tinygrad/runtime/autogen/am/smu_v13_0_0.py index b67f1ce734..b4257a2454 100644 --- a/tinygrad/runtime/autogen/am/smu_v13_0_0.py +++ b/tinygrad/runtime/autogen/am/smu_v13_0_0.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/am/smu_v14_0_2.py b/tinygrad/runtime/autogen/am/smu_v14_0_2.py index 46cc1dc94d..4d3cc93966 100644 --- a/tinygrad/runtime/autogen/am/smu_v14_0_2.py +++ b/tinygrad/runtime/autogen/am/smu_v14_0_2.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/amd_gpu.py b/tinygrad/runtime/autogen/amd_gpu.py index 5ced4e01fc..03812d8c16 100644 --- a/tinygrad/runtime/autogen/amd_gpu.py +++ b/tinygrad/runtime/autogen/amd_gpu.py @@ -10,6 +10,8 @@ import ctypes, os class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/comgr.py b/tinygrad/runtime/autogen/comgr.py index 3159606fe1..55779420a8 100644 --- a/tinygrad/runtime/autogen/comgr.py +++ b/tinygrad/runtime/autogen/comgr.py @@ -15,7 +15,9 @@ PATHS_TO_TRY = [ ] def _try_dlopen_amd_comgr(): library = ctypes.util.find_library("amd_comgr") - if library: return ctypes.CDLL(library) + if library: + try: return ctypes.CDLL(library) + except OSError: pass for candidate in PATHS_TO_TRY: try: return ctypes.CDLL(candidate) except OSError: pass @@ -52,6 +54,8 @@ else: c_long_double_t = ctypes.c_ubyte*16 class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/cuda.py b/tinygrad/runtime/autogen/cuda.py index 55c101aecc..c29d6af34d 100644 --- a/tinygrad/runtime/autogen/cuda.py +++ b/tinygrad/runtime/autogen/cuda.py @@ -10,6 +10,8 @@ import ctypes, ctypes.util class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/hip.py b/tinygrad/runtime/autogen/hip.py index fa8dbd1570..a6d3b8df0a 100644 --- a/tinygrad/runtime/autogen/hip.py +++ b/tinygrad/runtime/autogen/hip.py @@ -10,6 +10,8 @@ import ctypes, os class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/hsa.py b/tinygrad/runtime/autogen/hsa.py index bb65911bf5..31a9843cb8 100644 --- a/tinygrad/runtime/autogen/hsa.py +++ b/tinygrad/runtime/autogen/hsa.py @@ -31,6 +31,8 @@ def char_pointer_cast(string, encoding='utf-8'): _libraries = {} _libraries['libhsa-runtime64.so'] = ctypes.CDLL(os.getenv('ROCM_PATH')+'/lib/libhsa-runtime64.so' if os.getenv('ROCM_PATH') else ctypes.util.find_library('hsa-runtime64')) class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/ib.py b/tinygrad/runtime/autogen/ib.py index 8ea06c22f8..d3c5266b16 100644 --- a/tinygrad/runtime/autogen/ib.py +++ b/tinygrad/runtime/autogen/ib.py @@ -10,6 +10,8 @@ import ctypes, ctypes.util class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/io_uring.py b/tinygrad/runtime/autogen/io_uring.py index 420d75030d..4a8c10d11d 100644 --- a/tinygrad/runtime/autogen/io_uring.py +++ b/tinygrad/runtime/autogen/io_uring.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/kfd.py b/tinygrad/runtime/autogen/kfd.py index e8ed441e09..0720e9e579 100644 --- a/tinygrad/runtime/autogen/kfd.py +++ b/tinygrad/runtime/autogen/kfd.py @@ -24,6 +24,8 @@ def _IOR(base, nr, type): return functools.partial(_do_ioctl, 2, ord(base) if is def _IOWR(base, nr, type): return functools.partial(_do_ioctl, 3, ord(base) if isinstance(base, str) else base, nr, type) class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/kgsl.py b/tinygrad/runtime/autogen/kgsl.py index 439484d15b..cc6f121c49 100644 --- a/tinygrad/runtime/autogen/kgsl.py +++ b/tinygrad/runtime/autogen/kgsl.py @@ -10,6 +10,8 @@ import ctypes, os class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/libc.py b/tinygrad/runtime/autogen/libc.py index 45ba91a8ad..1420cbe20b 100644 --- a/tinygrad/runtime/autogen/libc.py +++ b/tinygrad/runtime/autogen/libc.py @@ -1,3669 +1,277 @@ # mypy: ignore-errors -# -*- coding: utf-8 -*- -# -# TARGET arch is: [] -# WORD_SIZE is: 8 -# POINTER_SIZE is: 8 -# LONGDOUBLE_SIZE is: 16 -# -import ctypes, ctypes.util, os +import ctypes +from tinygrad.helpers import unwrap +from tinygrad.runtime.support.c import Struct, CEnum, _IO, _IOW, _IOR, _IOWR +from ctypes.util import find_library +def dll(): + try: return ctypes.CDLL(unwrap(find_library('c')), use_errno=True) + except: pass + return None +dll = dll() - -c_int128 = ctypes.c_ubyte*16 -c_uint128 = c_int128 -void = None -if ctypes.sizeof(ctypes.c_longdouble) == 16: - c_long_double_t = ctypes.c_longdouble -else: - c_long_double_t = ctypes.c_ubyte*16 - -class FunctionFactoryStub: - def __getattr__(self, _): - return ctypes.CFUNCTYPE(lambda y:y) - -# libraries['libc'] explanation -# As you did not list (-l libraryname.so) a library that exports this function -# This is a non-working stub instead. -# You can either re-run clan2py with -l /path/to/library.so -# Or manually fix this by comment the ctypes.CDLL loading -_libraries = {} -_libraries['libc'] = None if (libc_path := ctypes.util.find_library('c')) is None else ctypes.CDLL(libc_path, use_errno=True) # ctypes.CDLL('libc') -def string_cast(char_pointer, encoding='utf-8', errors='strict'): - value = ctypes.cast(char_pointer, ctypes.c_char_p).value - if value is not None and encoding is not None: - value = value.decode(encoding, errors=errors) - return value - - -def char_pointer_cast(string, encoding='utf-8'): - if encoding is not None: - try: - string = string.encode(encoding) - except AttributeError: - # In Python3, bytes has no encode attribute - pass - string = ctypes.c_char_p(string) - return ctypes.cast(string, ctypes.POINTER(ctypes.c_char)) - - - -class AsDictMixin: - @classmethod - def as_dict(cls, self): - result = {} - if not isinstance(self, AsDictMixin): - # not a structure, assume it's already a python object - return self - if not hasattr(cls, "_fields_"): - return result - # sys.version_info >= (3, 5) - # for (field, *_) in cls._fields_: # noqa - for field_tuple in cls._fields_: # noqa - field = field_tuple[0] - if field.startswith('PADDING_'): - continue - value = getattr(self, field) - type_ = type(value) - if hasattr(value, "_length_") and hasattr(value, "_type_"): - # array - if not hasattr(type_, "as_dict"): - value = [v for v in value] - else: - type_ = type_._type_ - value = [type_.as_dict(v) for v in value] - elif hasattr(value, "contents") and hasattr(value, "_type_"): - # pointer - try: - if not hasattr(type_, "as_dict"): - value = value.contents - else: - type_ = type_._type_ - value = type_.as_dict(value.contents) - except ValueError: - # nullptr - value = None - elif isinstance(value, AsDictMixin): - # other structure - value = type_.as_dict(value) - result[field] = value - return result - - -class Structure(ctypes.Structure, AsDictMixin): - - def __init__(self, *args, **kwds): - # We don't want to use positional arguments fill PADDING_* fields - - args = dict(zip(self.__class__._field_names_(), args)) - args.update(kwds) - super(Structure, self).__init__(**args) - - @classmethod - def _field_names_(cls): - if hasattr(cls, '_fields_'): - return (f[0] for f in cls._fields_ if not f[0].startswith('PADDING')) - else: - return () - - @classmethod - def get_type(cls, field): - for f in cls._fields_: - if f[0] == field: - return f[1] - return None - - @classmethod - def bind(cls, bound_fields): - fields = {} - for name, type_ in cls._fields_: - if hasattr(type_, "restype"): - if name in bound_fields: - if bound_fields[name] is None: - fields[name] = type_() - else: - # use a closure to capture the callback from the loop scope - fields[name] = ( - type_((lambda callback: lambda *args: callback(*args))( - bound_fields[name])) - ) - del bound_fields[name] - else: - # default callback implementation (does nothing) - try: - default_ = type_(0).restype().value - except TypeError: - default_ = None - fields[name] = type_(( - lambda default_: lambda *args: default_)(default_)) - else: - # not a callback function, use default initialization - if name in bound_fields: - fields[name] = bound_fields[name] - del bound_fields[name] - else: - fields[name] = type_() - if len(bound_fields) != 0: - raise ValueError( - "Cannot bind the following unknown callback(s) {}.{}".format( - cls.__name__, bound_fields.keys() - )) - return cls(**fields) - - -class Union(ctypes.Union, AsDictMixin): - pass - - - - - -_SYS_MMAN_H = 1 # macro -__need_size_t = True # macro -__off_t_defined = True # macro -__mode_t_defined = True # macro -# MAP_FAILED = ((void*)-1) # macro off_t = ctypes.c_int64 mode_t = ctypes.c_uint32 size_t = ctypes.c_uint64 __off_t = ctypes.c_int64 -try: - mmap = _libraries['libc'].mmap - mmap.restype = ctypes.POINTER(None) - mmap.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, __off_t] -except AttributeError: - pass -try: - munmap = _libraries['libc'].munmap - munmap.restype = ctypes.c_int32 - munmap.argtypes = [ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - mprotect = _libraries['libc'].mprotect - mprotect.restype = ctypes.c_int32 - mprotect.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_int32] -except AttributeError: - pass -try: - msync = _libraries['libc'].msync - msync.restype = ctypes.c_int32 - msync.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_int32] -except AttributeError: - pass -try: - madvise = _libraries['libc'].madvise - madvise.restype = ctypes.c_int32 - madvise.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_int32] -except AttributeError: - pass -try: - posix_madvise = _libraries['libc'].posix_madvise - posix_madvise.restype = ctypes.c_int32 - posix_madvise.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_int32] -except AttributeError: - pass -try: - mlock = _libraries['libc'].mlock - mlock.restype = ctypes.c_int32 - mlock.argtypes = [ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - munlock = _libraries['libc'].munlock - munlock.restype = ctypes.c_int32 - munlock.argtypes = [ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - mlockall = _libraries['libc'].mlockall - mlockall.restype = ctypes.c_int32 - mlockall.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - munlockall = _libraries['libc'].munlockall - munlockall.restype = ctypes.c_int32 - munlockall.argtypes = [] -except AttributeError: - pass -try: - mincore = _libraries['libc'].mincore - mincore.restype = ctypes.c_int32 - mincore.argtypes = [ctypes.POINTER(None), size_t, ctypes.POINTER(ctypes.c_ubyte)] -except AttributeError: - pass -try: - shm_open = _libraries['libc'].shm_open - shm_open.restype = ctypes.c_int32 - shm_open.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32, mode_t] -except AttributeError: - pass -try: - shm_unlink = _libraries['libc'].shm_unlink - shm_unlink.restype = ctypes.c_int32 - shm_unlink.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -_SYSCALL_H = 1 # macro -_STRING_H = 1 # macro -__GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION = True # macro -__need_NULL = True # macro -try: - memcpy = _libraries['libc'].memcpy - memcpy.restype = ctypes.POINTER(None) - memcpy.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - memmove = _libraries['libc'].memmove - memmove.restype = ctypes.POINTER(None) - memmove.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - memccpy = _libraries['libc'].memccpy - memccpy.restype = ctypes.POINTER(None) - memccpy.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), ctypes.c_int32, size_t] -except AttributeError: - pass -try: - memset = _libraries['libc'].memset - memset.restype = ctypes.POINTER(None) - memset.argtypes = [ctypes.POINTER(None), ctypes.c_int32, size_t] -except AttributeError: - pass -try: - memcmp = _libraries['libc'].memcmp - memcmp.restype = ctypes.c_int32 - memcmp.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - __memcmpeq = _libraries['libc'].__memcmpeq - __memcmpeq.restype = ctypes.c_int32 - __memcmpeq.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - memchr = _libraries['libc'].memchr - memchr.restype = ctypes.POINTER(None) - memchr.argtypes = [ctypes.POINTER(None), ctypes.c_int32, size_t] -except AttributeError: - pass -try: - strcpy = _libraries['libc'].strcpy - strcpy.restype = ctypes.POINTER(ctypes.c_char) - strcpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strncpy = _libraries['libc'].strncpy - strncpy.restype = ctypes.POINTER(ctypes.c_char) - strncpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strcat = _libraries['libc'].strcat - strcat.restype = ctypes.POINTER(ctypes.c_char) - strcat.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strncat = _libraries['libc'].strncat - strncat.restype = ctypes.POINTER(ctypes.c_char) - strncat.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strcmp = _libraries['libc'].strcmp - strcmp.restype = ctypes.c_int32 - strcmp.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strncmp = _libraries['libc'].strncmp - strncmp.restype = ctypes.c_int32 - strncmp.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strcoll = _libraries['libc'].strcoll - strcoll.restype = ctypes.c_int32 - strcoll.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strxfrm = _libraries['libc'].strxfrm - strxfrm.restype = ctypes.c_uint64 - strxfrm.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -class struct___locale_struct(Structure): - pass +# extern void *mmap(void *__addr, size_t __len, int __prot, int __flags, int __fd, __off_t __offset) __attribute__((nothrow)) +try: (mmap:=dll.mmap).restype, mmap.argtypes = ctypes.c_void_p, [ctypes.c_void_p, size_t, ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_int64] +except AttributeError: pass -class struct___locale_data(Structure): - pass +# extern int munmap(void *__addr, size_t __len) __attribute__((nothrow)) +try: (munmap:=dll.munmap).restype, munmap.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t] +except AttributeError: pass -struct___locale_struct._pack_ = 1 # source:False +# extern int mprotect(void *__addr, size_t __len, int __prot) __attribute__((nothrow)) +try: (mprotect:=dll.mprotect).restype, mprotect.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t, ctypes.c_int32] +except AttributeError: pass + +# extern int msync(void *__addr, size_t __len, int __flags) +try: (msync:=dll.msync).restype, msync.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t, ctypes.c_int32] +except AttributeError: pass + +# extern int madvise(void *__addr, size_t __len, int __advice) __attribute__((nothrow)) +try: (madvise:=dll.madvise).restype, madvise.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t, ctypes.c_int32] +except AttributeError: pass + +# extern int posix_madvise(void *__addr, size_t __len, int __advice) __attribute__((nothrow)) +try: (posix_madvise:=dll.posix_madvise).restype, posix_madvise.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t, ctypes.c_int32] +except AttributeError: pass + +# extern int mlock(const void *__addr, size_t __len) __attribute__((nothrow)) +try: (mlock:=dll.mlock).restype, mlock.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern int munlock(const void *__addr, size_t __len) __attribute__((nothrow)) +try: (munlock:=dll.munlock).restype, munlock.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern int mlockall(int __flags) __attribute__((nothrow)) +try: (mlockall:=dll.mlockall).restype, mlockall.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern int munlockall(void) __attribute__((nothrow)) +try: (munlockall:=dll.munlockall).restype, munlockall.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern int mincore(void *__start, size_t __len, unsigned char *__vec) __attribute__((nothrow)) +try: (mincore:=dll.mincore).restype, mincore.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t, ctypes.POINTER(ctypes.c_ubyte)] +except AttributeError: pass + +# extern int shm_open(const char *__name, int __oflag, mode_t __mode) +try: (shm_open:=dll.shm_open).restype, shm_open.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.c_int32, mode_t] +except AttributeError: pass + +# extern int shm_unlink(const char *__name) +try: (shm_unlink:=dll.shm_unlink).restype, shm_unlink.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern void *memcpy(void *restrict __dest, const void *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (memcpy:=dll.memcpy).restype, memcpy.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern void *memmove(void *__dest, const void *__src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (memmove:=dll.memmove).restype, memmove.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern void *memccpy(void *restrict __dest, const void *restrict __src, int __c, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (memccpy:=dll.memccpy).restype, memccpy.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int32, size_t] +except AttributeError: pass + +# extern void *memset(void *__s, int __c, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (memset:=dll.memset).restype, memset.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_int32, size_t] +except AttributeError: pass + +# extern int memcmp(const void *__s1, const void *__s2, size_t __n) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (memcmp:=dll.memcmp).restype, memcmp.argtypes = ctypes.c_int32, [ctypes.c_void_p, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern int __memcmpeq(const void *__s1, const void *__s2, size_t __n) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (__memcmpeq:=dll.__memcmpeq).restype, __memcmpeq.argtypes = ctypes.c_int32, [ctypes.c_void_p, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern void *memchr(const void *__s, int __c, size_t __n) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1))) +try: (memchr:=dll.memchr).restype, memchr.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_int32, size_t] +except AttributeError: pass + +# extern char *strcpy(char *restrict __dest, const char *restrict __src) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strcpy:=dll.strcpy).restype, strcpy.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strncpy(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strncpy:=dll.strncpy).restype, strncpy.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern char *strcat(char *restrict __dest, const char *restrict __src) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strcat:=dll.strcat).restype, strcat.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strncat(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strncat:=dll.strncat).restype, strncat.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int strcmp(const char *__s1, const char *__s2) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strcmp:=dll.strcmp).restype, strcmp.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int strncmp(const char *__s1, const char *__s2, size_t __n) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strncmp:=dll.strncmp).restype, strncmp.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int strcoll(const char *__s1, const char *__s2) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strcoll:=dll.strcoll).restype, strcoll.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern unsigned long strxfrm(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (strxfrm:=dll.strxfrm).restype, strxfrm.argtypes = ctypes.c_uint64, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +class struct___locale_struct(Struct): pass +class struct___locale_data(Struct): pass struct___locale_struct._fields_ = [ - ('__locales', ctypes.POINTER(struct___locale_data) * 13), - ('__ctype_b', ctypes.POINTER(ctypes.c_uint16)), - ('__ctype_tolower', ctypes.POINTER(ctypes.c_int32)), - ('__ctype_toupper', ctypes.POINTER(ctypes.c_int32)), - ('__names', ctypes.POINTER(ctypes.c_char) * 13), + ('__locales', (ctypes.POINTER(struct___locale_data) * 13)), + ('__ctype_b', ctypes.POINTER(ctypes.c_uint16)), + ('__ctype_tolower', ctypes.POINTER(ctypes.c_int32)), + ('__ctype_toupper', ctypes.POINTER(ctypes.c_int32)), + ('__names', (ctypes.POINTER(ctypes.c_char) * 13)), ] - locale_t = ctypes.POINTER(struct___locale_struct) -try: - strcoll_l = _libraries['libc'].strcoll_l - strcoll_l.restype = ctypes.c_int32 - strcoll_l.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), locale_t] -except AttributeError: - pass -try: - strxfrm_l = _libraries['libc'].strxfrm_l - strxfrm_l.restype = size_t - strxfrm_l.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t, locale_t] -except AttributeError: - pass -try: - strdup = _libraries['libc'].strdup - strdup.restype = ctypes.POINTER(ctypes.c_char) - strdup.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strndup = _libraries['libc'].strndup - strndup.restype = ctypes.POINTER(ctypes.c_char) - strndup.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strchr = _libraries['libc'].strchr - strchr.restype = ctypes.POINTER(ctypes.c_char) - strchr.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - strrchr = _libraries['libc'].strrchr - strrchr.restype = ctypes.POINTER(ctypes.c_char) - strrchr.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - strchrnul = _libraries['libc'].strchrnul - strchrnul.restype = ctypes.POINTER(ctypes.c_char) - strchrnul.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - strcspn = _libraries['libc'].strcspn - strcspn.restype = ctypes.c_uint64 - strcspn.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strspn = _libraries['libc'].strspn - strspn.restype = ctypes.c_uint64 - strspn.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strpbrk = _libraries['libc'].strpbrk - strpbrk.restype = ctypes.POINTER(ctypes.c_char) - strpbrk.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strstr = _libraries['libc'].strstr - strstr.restype = ctypes.POINTER(ctypes.c_char) - strstr.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strtok = _libraries['libc'].strtok - strtok.restype = ctypes.POINTER(ctypes.c_char) - strtok.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - __strtok_r = _libraries['libc'].__strtok_r - __strtok_r.restype = ctypes.POINTER(ctypes.c_char) - __strtok_r.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.POINTER(ctypes.c_char))] -except AttributeError: - pass -try: - strtok_r = _libraries['libc'].strtok_r - strtok_r.restype = ctypes.POINTER(ctypes.c_char) - strtok_r.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.POINTER(ctypes.c_char))] -except AttributeError: - pass -try: - strcasestr = _libraries['libc'].strcasestr - strcasestr.restype = ctypes.POINTER(ctypes.c_char) - strcasestr.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - memmem = _libraries['libc'].memmem - memmem.restype = ctypes.POINTER(None) - memmem.argtypes = [ctypes.POINTER(None), size_t, ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - __mempcpy = _libraries['libc'].__mempcpy - __mempcpy.restype = ctypes.POINTER(None) - __mempcpy.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - mempcpy = _libraries['libc'].mempcpy - mempcpy.restype = ctypes.POINTER(None) - mempcpy.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - strlen = _libraries['libc'].strlen - strlen.restype = ctypes.c_uint64 - strlen.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strnlen = _libraries['libc'].strnlen - strnlen.restype = size_t - strnlen.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strerror = _libraries['libc'].strerror - strerror.restype = ctypes.POINTER(ctypes.c_char) - strerror.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - strerror_r = _libraries['libc'].strerror_r - strerror_r.restype = ctypes.c_int32 - strerror_r.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strerror_l = _libraries['libc'].strerror_l - strerror_l.restype = ctypes.POINTER(ctypes.c_char) - strerror_l.argtypes = [ctypes.c_int32, locale_t] -except AttributeError: - pass -try: - explicit_bzero = _libraries['libc'].explicit_bzero - explicit_bzero.restype = None - explicit_bzero.argtypes = [ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - strsep = _libraries['libc'].strsep - strsep.restype = ctypes.POINTER(ctypes.c_char) - strsep.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - strsignal = _libraries['libc'].strsignal - strsignal.restype = ctypes.POINTER(ctypes.c_char) - strsignal.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - __stpcpy = _libraries['libc'].__stpcpy - __stpcpy.restype = ctypes.POINTER(ctypes.c_char) - __stpcpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - stpcpy = _libraries['libc'].stpcpy - stpcpy.restype = ctypes.POINTER(ctypes.c_char) - stpcpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - __stpncpy = _libraries['libc'].__stpncpy - __stpncpy.restype = ctypes.POINTER(ctypes.c_char) - __stpncpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - stpncpy = _libraries['libc'].stpncpy - stpncpy.restype = ctypes.POINTER(ctypes.c_char) - stpncpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strlcpy = _libraries['libc'].strlcpy - strlcpy.restype = size_t - strlcpy.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - strlcat = _libraries['libc'].strlcat - strlcat.restype = size_t - strlcat.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -_ELF_H = 1 # macro -EI_NIDENT = (16) # macro -EI_MAG0 = 0 # macro -ELFMAG0 = 0x7f # macro -EI_MAG1 = 1 # macro -ELFMAG1 = 'E' # macro -EI_MAG2 = 2 # macro -ELFMAG2 = 'L' # macro -EI_MAG3 = 3 # macro -ELFMAG3 = 'F' # macro -ELFMAG = "\177ELF" # macro -SELFMAG = 4 # macro -EI_CLASS = 4 # macro -ELFCLASSNONE = 0 # macro -ELFCLASS32 = 1 # macro -ELFCLASS64 = 2 # macro -ELFCLASSNUM = 3 # macro -EI_DATA = 5 # macro -ELFDATANONE = 0 # macro -ELFDATA2LSB = 1 # macro -ELFDATA2MSB = 2 # macro -ELFDATANUM = 3 # macro -EI_VERSION = 6 # macro -EI_OSABI = 7 # macro -ELFOSABI_NONE = 0 # macro -ELFOSABI_SYSV = 0 # macro -ELFOSABI_HPUX = 1 # macro -ELFOSABI_NETBSD = 2 # macro -ELFOSABI_GNU = 3 # macro -ELFOSABI_LINUX = 3 # macro -ELFOSABI_SOLARIS = 6 # macro -ELFOSABI_AIX = 7 # macro -ELFOSABI_IRIX = 8 # macro -ELFOSABI_FREEBSD = 9 # macro -ELFOSABI_TRU64 = 10 # macro -ELFOSABI_MODESTO = 11 # macro -ELFOSABI_OPENBSD = 12 # macro -ELFOSABI_ARM_AEABI = 64 # macro -ELFOSABI_ARM = 97 # macro -ELFOSABI_STANDALONE = 255 # macro -EI_ABIVERSION = 8 # macro -EI_PAD = 9 # macro -ET_NONE = 0 # macro -ET_REL = 1 # macro -ET_EXEC = 2 # macro -ET_DYN = 3 # macro -ET_CORE = 4 # macro -ET_NUM = 5 # macro -ET_LOOS = 0xfe00 # macro -ET_HIOS = 0xfeff # macro -ET_LOPROC = 0xff00 # macro -ET_HIPROC = 0xffff # macro -EM_NONE = 0 # macro -EM_M32 = 1 # macro -EM_SPARC = 2 # macro -EM_386 = 3 # macro -EM_68K = 4 # macro -EM_88K = 5 # macro -EM_IAMCU = 6 # macro -EM_860 = 7 # macro -EM_MIPS = 8 # macro -EM_S370 = 9 # macro -EM_MIPS_RS3_LE = 10 # macro -EM_PARISC = 15 # macro -EM_VPP500 = 17 # macro -EM_SPARC32PLUS = 18 # macro -EM_960 = 19 # macro -EM_PPC = 20 # macro -EM_PPC64 = 21 # macro -EM_S390 = 22 # macro -EM_SPU = 23 # macro -EM_V800 = 36 # macro -EM_FR20 = 37 # macro -EM_RH32 = 38 # macro -EM_RCE = 39 # macro -EM_ARM = 40 # macro -EM_FAKE_ALPHA = 41 # macro -EM_SH = 42 # macro -EM_SPARCV9 = 43 # macro -EM_TRICORE = 44 # macro -EM_ARC = 45 # macro -EM_H8_300 = 46 # macro -EM_H8_300H = 47 # macro -EM_H8S = 48 # macro -EM_H8_500 = 49 # macro -EM_IA_64 = 50 # macro -EM_MIPS_X = 51 # macro -EM_COLDFIRE = 52 # macro -EM_68HC12 = 53 # macro -EM_MMA = 54 # macro -EM_PCP = 55 # macro -EM_NCPU = 56 # macro -EM_NDR1 = 57 # macro -EM_STARCORE = 58 # macro -EM_ME16 = 59 # macro -EM_ST100 = 60 # macro -EM_TINYJ = 61 # macro -EM_X86_64 = 62 # macro -EM_PDSP = 63 # macro -EM_PDP10 = 64 # macro -EM_PDP11 = 65 # macro -EM_FX66 = 66 # macro -EM_ST9PLUS = 67 # macro -EM_ST7 = 68 # macro -EM_68HC16 = 69 # macro -EM_68HC11 = 70 # macro -EM_68HC08 = 71 # macro -EM_68HC05 = 72 # macro -EM_SVX = 73 # macro -EM_ST19 = 74 # macro -EM_VAX = 75 # macro -EM_CRIS = 76 # macro -EM_JAVELIN = 77 # macro -EM_FIREPATH = 78 # macro -EM_ZSP = 79 # macro -EM_MMIX = 80 # macro -EM_HUANY = 81 # macro -EM_PRISM = 82 # macro -EM_AVR = 83 # macro -EM_FR30 = 84 # macro -EM_D10V = 85 # macro -EM_D30V = 86 # macro -EM_V850 = 87 # macro -EM_M32R = 88 # macro -EM_MN10300 = 89 # macro -EM_MN10200 = 90 # macro -EM_PJ = 91 # macro -EM_OPENRISC = 92 # macro -EM_ARC_COMPACT = 93 # macro -EM_XTENSA = 94 # macro -EM_VIDEOCORE = 95 # macro -EM_TMM_GPP = 96 # macro -EM_NS32K = 97 # macro -EM_TPC = 98 # macro -EM_SNP1K = 99 # macro -EM_ST200 = 100 # macro -EM_IP2K = 101 # macro -EM_MAX = 102 # macro -EM_CR = 103 # macro -EM_F2MC16 = 104 # macro -EM_MSP430 = 105 # macro -EM_BLACKFIN = 106 # macro -EM_SE_C33 = 107 # macro -EM_SEP = 108 # macro -EM_ARCA = 109 # macro -EM_UNICORE = 110 # macro -EM_EXCESS = 111 # macro -EM_DXP = 112 # macro -EM_ALTERA_NIOS2 = 113 # macro -EM_CRX = 114 # macro -EM_XGATE = 115 # macro -EM_C166 = 116 # macro -EM_M16C = 117 # macro -EM_DSPIC30F = 118 # macro -EM_CE = 119 # macro -EM_M32C = 120 # macro -EM_TSK3000 = 131 # macro -EM_RS08 = 132 # macro -EM_SHARC = 133 # macro -EM_ECOG2 = 134 # macro -EM_SCORE7 = 135 # macro -EM_DSP24 = 136 # macro -EM_VIDEOCORE3 = 137 # macro -EM_LATTICEMICO32 = 138 # macro -EM_SE_C17 = 139 # macro -EM_TI_C6000 = 140 # macro -EM_TI_C2000 = 141 # macro -EM_TI_C5500 = 142 # macro -EM_TI_ARP32 = 143 # macro -EM_TI_PRU = 144 # macro -EM_MMDSP_PLUS = 160 # macro -EM_CYPRESS_M8C = 161 # macro -EM_R32C = 162 # macro -EM_TRIMEDIA = 163 # macro -EM_QDSP6 = 164 # macro -EM_8051 = 165 # macro -EM_STXP7X = 166 # macro -EM_NDS32 = 167 # macro -EM_ECOG1X = 168 # macro -EM_MAXQ30 = 169 # macro -EM_XIMO16 = 170 # macro -EM_MANIK = 171 # macro -EM_CRAYNV2 = 172 # macro -EM_RX = 173 # macro -EM_METAG = 174 # macro -EM_MCST_ELBRUS = 175 # macro -EM_ECOG16 = 176 # macro -EM_CR16 = 177 # macro -EM_ETPU = 178 # macro -EM_SLE9X = 179 # macro -EM_L10M = 180 # macro -EM_K10M = 181 # macro -EM_AARCH64 = 183 # macro -EM_AVR32 = 185 # macro -EM_STM8 = 186 # macro -EM_TILE64 = 187 # macro -EM_TILEPRO = 188 # macro -EM_MICROBLAZE = 189 # macro -EM_CUDA = 190 # macro -EM_TILEGX = 191 # macro -EM_CLOUDSHIELD = 192 # macro -EM_COREA_1ST = 193 # macro -EM_COREA_2ND = 194 # macro -EM_ARCV2 = 195 # macro -EM_OPEN8 = 196 # macro -EM_RL78 = 197 # macro -EM_VIDEOCORE5 = 198 # macro -EM_78KOR = 199 # macro -EM_56800EX = 200 # macro -EM_BA1 = 201 # macro -EM_BA2 = 202 # macro -EM_XCORE = 203 # macro -EM_MCHP_PIC = 204 # macro -EM_INTELGT = 205 # macro -EM_KM32 = 210 # macro -EM_KMX32 = 211 # macro -EM_EMX16 = 212 # macro -EM_EMX8 = 213 # macro -EM_KVARC = 214 # macro -EM_CDP = 215 # macro -EM_COGE = 216 # macro -EM_COOL = 217 # macro -EM_NORC = 218 # macro -EM_CSR_KALIMBA = 219 # macro -EM_Z80 = 220 # macro -EM_VISIUM = 221 # macro -EM_FT32 = 222 # macro -EM_MOXIE = 223 # macro -EM_AMDGPU = 224 # macro -EM_RISCV = 243 # macro -EM_BPF = 247 # macro -EM_CSKY = 252 # macro -EM_LOONGARCH = 258 # macro -EM_NUM = 259 # macro -EM_ARC_A5 = 93 # macro -EM_ALPHA = 0x9026 # macro -EV_NONE = 0 # macro -EV_CURRENT = 1 # macro -EV_NUM = 2 # macro -SHN_UNDEF = 0 # macro -SHN_LORESERVE = 0xff00 # macro -SHN_LOPROC = 0xff00 # macro -SHN_BEFORE = 0xff00 # macro -SHN_AFTER = 0xff01 # macro -SHN_HIPROC = 0xff1f # macro -SHN_LOOS = 0xff20 # macro -SHN_HIOS = 0xff3f # macro -SHN_ABS = 0xfff1 # macro -SHN_COMMON = 0xfff2 # macro -SHN_XINDEX = 0xffff # macro -SHN_HIRESERVE = 0xffff # macro -SHT_NULL = 0 # macro -SHT_PROGBITS = 1 # macro -SHT_SYMTAB = 2 # macro -SHT_STRTAB = 3 # macro -SHT_RELA = 4 # macro -SHT_HASH = 5 # macro -SHT_DYNAMIC = 6 # macro -SHT_NOTE = 7 # macro -SHT_NOBITS = 8 # macro -SHT_REL = 9 # macro -SHT_SHLIB = 10 # macro -SHT_DYNSYM = 11 # macro -SHT_INIT_ARRAY = 14 # macro -SHT_FINI_ARRAY = 15 # macro -SHT_PREINIT_ARRAY = 16 # macro -SHT_GROUP = 17 # macro -SHT_SYMTAB_SHNDX = 18 # macro -SHT_RELR = 19 # macro -SHT_NUM = 20 # macro -SHT_LOOS = 0x60000000 # macro -SHT_GNU_ATTRIBUTES = 0x6ffffff5 # macro -SHT_GNU_HASH = 0x6ffffff6 # macro -SHT_GNU_LIBLIST = 0x6ffffff7 # macro -SHT_CHECKSUM = 0x6ffffff8 # macro -SHT_LOSUNW = 0x6ffffffa # macro -SHT_SUNW_move = 0x6ffffffa # macro -SHT_SUNW_COMDAT = 0x6ffffffb # macro -SHT_SUNW_syminfo = 0x6ffffffc # macro -SHT_GNU_verdef = 0x6ffffffd # macro -SHT_GNU_verneed = 0x6ffffffe # macro -SHT_GNU_versym = 0x6fffffff # macro -SHT_HISUNW = 0x6fffffff # macro -SHT_HIOS = 0x6fffffff # macro -SHT_LOPROC = 0x70000000 # macro -SHT_HIPROC = 0x7fffffff # macro -SHT_LOUSER = 0x80000000 # macro -SHT_HIUSER = 0x8fffffff # macro -SHF_WRITE = (1<<0) # macro -SHF_ALLOC = (1<<1) # macro -SHF_EXECINSTR = (1<<2) # macro -SHF_MERGE = (1<<4) # macro -SHF_STRINGS = (1<<5) # macro -SHF_INFO_LINK = (1<<6) # macro -SHF_LINK_ORDER = (1<<7) # macro -SHF_OS_NONCONFORMING = (1<<8) # macro -SHF_GROUP = (1<<9) # macro -SHF_TLS = (1<<10) # macro -SHF_COMPRESSED = (1<<11) # macro -SHF_MASKOS = 0x0ff00000 # macro -SHF_MASKPROC = 0xf0000000 # macro -SHF_GNU_RETAIN = (1<<21) # macro -SHF_ORDERED = (1<<30) # macro -SHF_EXCLUDE = (1<<31) # macro -ELFCOMPRESS_ZLIB = 1 # macro -ELFCOMPRESS_ZSTD = 2 # macro -ELFCOMPRESS_LOOS = 0x60000000 # macro -ELFCOMPRESS_HIOS = 0x6fffffff # macro -ELFCOMPRESS_LOPROC = 0x70000000 # macro -ELFCOMPRESS_HIPROC = 0x7fffffff # macro -GRP_COMDAT = 0x1 # macro -SYMINFO_BT_SELF = 0xffff # macro -SYMINFO_BT_PARENT = 0xfffe # macro -SYMINFO_BT_LOWRESERVE = 0xff00 # macro -SYMINFO_FLG_DIRECT = 0x0001 # macro -SYMINFO_FLG_PASSTHRU = 0x0002 # macro -SYMINFO_FLG_COPY = 0x0004 # macro -SYMINFO_FLG_LAZYLOAD = 0x0008 # macro -SYMINFO_NONE = 0 # macro -SYMINFO_CURRENT = 1 # macro -SYMINFO_NUM = 2 # macro -def ELF32_ST_BIND(val): # macro - return (((val))>>4) -def ELF32_ST_TYPE(val): # macro - return ((val)&0xf) -def ELF32_ST_INFO(bind, type): # macro - return (((bind)<<4)+((type)&0xf)) -def ELF64_ST_BIND(val): # macro - return ELF32_ST_BIND(val) -def ELF64_ST_TYPE(val): # macro - return ELF32_ST_TYPE(val) -def ELF64_ST_INFO(bind, type): # macro - return ELF32_ST_INFO((bind),(type)) -STB_LOCAL = 0 # macro -STB_GLOBAL = 1 # macro -STB_WEAK = 2 # macro -STB_NUM = 3 # macro -STB_LOOS = 10 # macro -STB_GNU_UNIQUE = 10 # macro -STB_HIOS = 12 # macro -STB_LOPROC = 13 # macro -STB_HIPROC = 15 # macro -STT_NOTYPE = 0 # macro -STT_OBJECT = 1 # macro -STT_FUNC = 2 # macro -STT_SECTION = 3 # macro -STT_FILE = 4 # macro -STT_COMMON = 5 # macro -STT_TLS = 6 # macro -STT_NUM = 7 # macro -STT_LOOS = 10 # macro -STT_GNU_IFUNC = 10 # macro -STT_HIOS = 12 # macro -STT_LOPROC = 13 # macro -STT_HIPROC = 15 # macro -STN_UNDEF = 0 # macro -def ELF32_ST_VISIBILITY(o): # macro - return ((o)&0x03) -def ELF64_ST_VISIBILITY(o): # macro - return ELF32_ST_VISIBILITY(o) -STV_DEFAULT = 0 # macro -STV_INTERNAL = 1 # macro -STV_HIDDEN = 2 # macro -STV_PROTECTED = 3 # macro -def ELF32_R_SYM(val): # macro - return ((val)>>8) -def ELF32_R_TYPE(val): # macro - return ((val)&0xff) -def ELF32_R_INFO(sym, type): # macro - return (((sym)<<8)+((type)&0xff)) -def ELF64_R_SYM(i): # macro - return ((i)>>32) -def ELF64_R_TYPE(i): # macro - return ((i)&0xffffffff) -PN_XNUM = 0xffff # macro -PT_NULL = 0 # macro -PT_LOAD = 1 # macro -PT_DYNAMIC = 2 # macro -PT_INTERP = 3 # macro -PT_NOTE = 4 # macro -PT_SHLIB = 5 # macro -PT_PHDR = 6 # macro -PT_TLS = 7 # macro -PT_NUM = 8 # macro -PT_LOOS = 0x60000000 # macro -PT_GNU_EH_FRAME = 0x6474e550 # macro -PT_GNU_STACK = 0x6474e551 # macro -PT_GNU_RELRO = 0x6474e552 # macro -PT_GNU_PROPERTY = 0x6474e553 # macro -PT_GNU_SFRAME = 0x6474e554 # macro -PT_LOSUNW = 0x6ffffffa # macro -PT_SUNWBSS = 0x6ffffffa # macro -PT_SUNWSTACK = 0x6ffffffb # macro -PT_HISUNW = 0x6fffffff # macro -PT_HIOS = 0x6fffffff # macro -PT_LOPROC = 0x70000000 # macro -PT_HIPROC = 0x7fffffff # macro -PF_X = (1<<0) # macro -PF_W = (1<<1) # macro -PF_R = (1<<2) # macro -PF_MASKOS = 0x0ff00000 # macro -PF_MASKPROC = 0xf0000000 # macro -NT_PRSTATUS = 1 # macro -NT_PRFPREG = 2 # macro -NT_FPREGSET = 2 # macro -NT_PRPSINFO = 3 # macro -NT_PRXREG = 4 # macro -NT_TASKSTRUCT = 4 # macro -NT_PLATFORM = 5 # macro -NT_AUXV = 6 # macro -NT_GWINDOWS = 7 # macro -NT_ASRS = 8 # macro -NT_PSTATUS = 10 # macro -NT_PSINFO = 13 # macro -NT_PRCRED = 14 # macro -NT_UTSNAME = 15 # macro -NT_LWPSTATUS = 16 # macro -NT_LWPSINFO = 17 # macro -NT_PRFPXREG = 20 # macro -NT_SIGINFO = 0x53494749 # macro -NT_FILE = 0x46494c45 # macro -NT_PRXFPREG = 0x46e62b7f # macro -NT_PPC_VMX = 0x100 # macro -NT_PPC_SPE = 0x101 # macro -NT_PPC_VSX = 0x102 # macro -NT_PPC_TAR = 0x103 # macro -NT_PPC_PPR = 0x104 # macro -NT_PPC_DSCR = 0x105 # macro -NT_PPC_EBB = 0x106 # macro -NT_PPC_PMU = 0x107 # macro -NT_PPC_TM_CGPR = 0x108 # macro -NT_PPC_TM_CFPR = 0x109 # macro -NT_PPC_TM_CVMX = 0x10a # macro -NT_PPC_TM_CVSX = 0x10b # macro -NT_PPC_TM_SPR = 0x10c # macro -NT_PPC_TM_CTAR = 0x10d # macro -NT_PPC_TM_CPPR = 0x10e # macro -NT_PPC_TM_CDSCR = 0x10f # macro -NT_PPC_PKEY = 0x110 # macro -NT_PPC_DEXCR = 0x111 # macro -NT_PPC_HASHKEYR = 0x112 # macro -NT_386_TLS = 0x200 # macro -NT_386_IOPERM = 0x201 # macro -NT_X86_XSTATE = 0x202 # macro -NT_X86_SHSTK = 0x204 # macro -NT_S390_HIGH_GPRS = 0x300 # macro -NT_S390_TIMER = 0x301 # macro -NT_S390_TODCMP = 0x302 # macro -NT_S390_TODPREG = 0x303 # macro -NT_S390_CTRS = 0x304 # macro -NT_S390_PREFIX = 0x305 # macro -NT_S390_LAST_BREAK = 0x306 # macro -NT_S390_SYSTEM_CALL = 0x307 # macro -NT_S390_TDB = 0x308 # macro -NT_S390_VXRS_LOW = 0x309 # macro -NT_S390_VXRS_HIGH = 0x30a # macro -NT_S390_GS_CB = 0x30b # macro -NT_S390_GS_BC = 0x30c # macro -NT_S390_RI_CB = 0x30d # macro -NT_S390_PV_CPU_DATA = 0x30e # macro -NT_ARM_VFP = 0x400 # macro -NT_ARM_TLS = 0x401 # macro -NT_ARM_HW_BREAK = 0x402 # macro -NT_ARM_HW_WATCH = 0x403 # macro -NT_ARM_SYSTEM_CALL = 0x404 # macro -NT_ARM_SVE = 0x405 # macro -NT_ARM_PAC_MASK = 0x406 # macro -NT_ARM_PACA_KEYS = 0x407 # macro -NT_ARM_PACG_KEYS = 0x408 # macro -NT_ARM_TAGGED_ADDR_CTRL = 0x409 # macro -NT_ARM_PAC_ENABLED_KEYS = 0x40a # macro -NT_VMCOREDD = 0x700 # macro -NT_MIPS_DSP = 0x800 # macro -NT_MIPS_FP_MODE = 0x801 # macro -NT_MIPS_MSA = 0x802 # macro -NT_RISCV_CSR = 0x900 # macro -NT_RISCV_VECTOR = 0x901 # macro -NT_LOONGARCH_CPUCFG = 0xa00 # macro -NT_LOONGARCH_CSR = 0xa01 # macro -NT_LOONGARCH_LSX = 0xa02 # macro -NT_LOONGARCH_LASX = 0xa03 # macro -NT_LOONGARCH_LBT = 0xa04 # macro -NT_LOONGARCH_HW_BREAK = 0xa05 # macro -NT_LOONGARCH_HW_WATCH = 0xa06 # macro -NT_VERSION = 1 # macro -DT_NULL = 0 # macro -DT_NEEDED = 1 # macro -DT_PLTRELSZ = 2 # macro -DT_PLTGOT = 3 # macro -DT_HASH = 4 # macro -DT_STRTAB = 5 # macro -DT_SYMTAB = 6 # macro -DT_RELA = 7 # macro -DT_RELASZ = 8 # macro -DT_RELAENT = 9 # macro -DT_STRSZ = 10 # macro -DT_SYMENT = 11 # macro -DT_INIT = 12 # macro -DT_FINI = 13 # macro -DT_SONAME = 14 # macro -DT_RPATH = 15 # macro -DT_SYMBOLIC = 16 # macro -DT_REL = 17 # macro -DT_RELSZ = 18 # macro -DT_RELENT = 19 # macro -DT_PLTREL = 20 # macro -DT_DEBUG = 21 # macro -DT_TEXTREL = 22 # macro -DT_JMPREL = 23 # macro -DT_BIND_NOW = 24 # macro -DT_INIT_ARRAY = 25 # macro -DT_FINI_ARRAY = 26 # macro -DT_INIT_ARRAYSZ = 27 # macro -DT_FINI_ARRAYSZ = 28 # macro -DT_RUNPATH = 29 # macro -DT_FLAGS = 30 # macro -DT_ENCODING = 32 # macro -DT_PREINIT_ARRAY = 32 # macro -DT_PREINIT_ARRAYSZ = 33 # macro -DT_SYMTAB_SHNDX = 34 # macro -DT_RELRSZ = 35 # macro -DT_RELR = 36 # macro -DT_RELRENT = 37 # macro -DT_NUM = 38 # macro -DT_LOOS = 0x6000000d # macro -DT_HIOS = 0x6ffff000 # macro -DT_LOPROC = 0x70000000 # macro -DT_HIPROC = 0x7fffffff # macro -DT_VALRNGLO = 0x6ffffd00 # macro -DT_GNU_PRELINKED = 0x6ffffdf5 # macro -DT_GNU_CONFLICTSZ = 0x6ffffdf6 # macro -DT_GNU_LIBLISTSZ = 0x6ffffdf7 # macro -DT_CHECKSUM = 0x6ffffdf8 # macro -DT_PLTPADSZ = 0x6ffffdf9 # macro -DT_MOVEENT = 0x6ffffdfa # macro -DT_MOVESZ = 0x6ffffdfb # macro -DT_FEATURE_1 = 0x6ffffdfc # macro -DT_POSFLAG_1 = 0x6ffffdfd # macro -DT_SYMINSZ = 0x6ffffdfe # macro -DT_SYMINENT = 0x6ffffdff # macro -DT_VALRNGHI = 0x6ffffdff # macro -def DT_VALTAGIDX(tag): # macro - return (0x6ffffdff-(tag)) -DT_VALNUM = 12 # macro -DT_ADDRRNGLO = 0x6ffffe00 # macro -DT_GNU_HASH = 0x6ffffef5 # macro -DT_TLSDESC_PLT = 0x6ffffef6 # macro -DT_TLSDESC_GOT = 0x6ffffef7 # macro -DT_GNU_CONFLICT = 0x6ffffef8 # macro -DT_GNU_LIBLIST = 0x6ffffef9 # macro -DT_CONFIG = 0x6ffffefa # macro -DT_DEPAUDIT = 0x6ffffefb # macro -DT_AUDIT = 0x6ffffefc # macro -DT_PLTPAD = 0x6ffffefd # macro -DT_MOVETAB = 0x6ffffefe # macro -DT_SYMINFO = 0x6ffffeff # macro -DT_ADDRRNGHI = 0x6ffffeff # macro -def DT_ADDRTAGIDX(tag): # macro - return (0x6ffffeff-(tag)) -DT_ADDRNUM = 11 # macro -DT_VERSYM = 0x6ffffff0 # macro -DT_RELACOUNT = 0x6ffffff9 # macro -DT_RELCOUNT = 0x6ffffffa # macro -DT_FLAGS_1 = 0x6ffffffb # macro -DT_VERDEF = 0x6ffffffc # macro -DT_VERDEFNUM = 0x6ffffffd # macro -DT_VERNEED = 0x6ffffffe # macro -DT_VERNEEDNUM = 0x6fffffff # macro -def DT_VERSIONTAGIDX(tag): # macro - return (0x6fffffff-(tag)) -DT_VERSIONTAGNUM = 16 # macro -DT_AUXILIARY = 0x7ffffffd # macro -DT_FILTER = 0x7fffffff # macro -DT_EXTRANUM = 3 # macro -DF_ORIGIN = 0x00000001 # macro -DF_SYMBOLIC = 0x00000002 # macro -DF_TEXTREL = 0x00000004 # macro -DF_BIND_NOW = 0x00000008 # macro -DF_STATIC_TLS = 0x00000010 # macro -DF_1_NOW = 0x00000001 # macro -DF_1_GLOBAL = 0x00000002 # macro -DF_1_GROUP = 0x00000004 # macro -DF_1_NODELETE = 0x00000008 # macro -DF_1_LOADFLTR = 0x00000010 # macro -DF_1_INITFIRST = 0x00000020 # macro -DF_1_NOOPEN = 0x00000040 # macro -DF_1_ORIGIN = 0x00000080 # macro -DF_1_DIRECT = 0x00000100 # macro -DF_1_TRANS = 0x00000200 # macro -DF_1_INTERPOSE = 0x00000400 # macro -DF_1_NODEFLIB = 0x00000800 # macro -DF_1_NODUMP = 0x00001000 # macro -DF_1_CONFALT = 0x00002000 # macro -DF_1_ENDFILTEE = 0x00004000 # macro -DF_1_DISPRELDNE = 0x00008000 # macro -DF_1_DISPRELPND = 0x00010000 # macro -DF_1_NODIRECT = 0x00020000 # macro -DF_1_IGNMULDEF = 0x00040000 # macro -DF_1_NOKSYMS = 0x00080000 # macro -DF_1_NOHDR = 0x00100000 # macro -DF_1_EDITED = 0x00200000 # macro -DF_1_NORELOC = 0x00400000 # macro -DF_1_SYMINTPOSE = 0x00800000 # macro -DF_1_GLOBAUDIT = 0x01000000 # macro -DF_1_SINGLETON = 0x02000000 # macro -DF_1_STUB = 0x04000000 # macro -DF_1_PIE = 0x08000000 # macro -DF_1_KMOD = 0x10000000 # macro -DF_1_WEAKFILTER = 0x20000000 # macro -DF_1_NOCOMMON = 0x40000000 # macro -DTF_1_PARINIT = 0x00000001 # macro -DTF_1_CONFEXP = 0x00000002 # macro -DF_P1_LAZYLOAD = 0x00000001 # macro -DF_P1_GROUPPERM = 0x00000002 # macro -VER_DEF_NONE = 0 # macro -VER_DEF_CURRENT = 1 # macro -VER_DEF_NUM = 2 # macro -VER_FLG_BASE = 0x1 # macro -VER_FLG_WEAK = 0x2 # macro -VER_NDX_LOCAL = 0 # macro -VER_NDX_GLOBAL = 1 # macro -VER_NDX_LORESERVE = 0xff00 # macro -VER_NDX_ELIMINATE = 0xff01 # macro -VER_NEED_NONE = 0 # macro -VER_NEED_CURRENT = 1 # macro -VER_NEED_NUM = 2 # macro -AT_NULL = 0 # macro -AT_IGNORE = 1 # macro -AT_EXECFD = 2 # macro -AT_PHDR = 3 # macro -AT_PHENT = 4 # macro -AT_PHNUM = 5 # macro -AT_PAGESZ = 6 # macro -AT_BASE = 7 # macro -AT_FLAGS = 8 # macro -AT_ENTRY = 9 # macro -AT_NOTELF = 10 # macro -AT_UID = 11 # macro -AT_EUID = 12 # macro -AT_GID = 13 # macro -AT_EGID = 14 # macro -AT_CLKTCK = 17 # macro -AT_PLATFORM = 15 # macro -AT_HWCAP = 16 # macro -AT_FPUCW = 18 # macro -AT_DCACHEBSIZE = 19 # macro -AT_ICACHEBSIZE = 20 # macro -AT_UCACHEBSIZE = 21 # macro -AT_IGNOREPPC = 22 # macro -AT_SECURE = 23 # macro -AT_BASE_PLATFORM = 24 # macro -AT_RANDOM = 25 # macro -AT_HWCAP2 = 26 # macro -AT_RSEQ_FEATURE_SIZE = 27 # macro -AT_RSEQ_ALIGN = 28 # macro -AT_HWCAP3 = 29 # macro -AT_HWCAP4 = 30 # macro -AT_EXECFN = 31 # macro -AT_SYSINFO = 32 # macro -AT_SYSINFO_EHDR = 33 # macro -AT_L1I_CACHESHAPE = 34 # macro -AT_L1D_CACHESHAPE = 35 # macro -AT_L2_CACHESHAPE = 36 # macro -AT_L3_CACHESHAPE = 37 # macro -AT_L1I_CACHESIZE = 40 # macro -AT_L1I_CACHEGEOMETRY = 41 # macro -AT_L1D_CACHESIZE = 42 # macro -AT_L1D_CACHEGEOMETRY = 43 # macro -AT_L2_CACHESIZE = 44 # macro -AT_L2_CACHEGEOMETRY = 45 # macro -AT_L3_CACHESIZE = 46 # macro -AT_L3_CACHEGEOMETRY = 47 # macro -AT_MINSIGSTKSZ = 51 # macro -ELF_NOTE_SOLARIS = "SUNW Solaris" # macro -ELF_NOTE_GNU = "GNU" # macro -ELF_NOTE_FDO = "FDO" # macro -ELF_NOTE_PAGESIZE_HINT = 1 # macro -NT_GNU_ABI_TAG = 1 # macro -ELF_NOTE_ABI = 1 # macro -ELF_NOTE_OS_LINUX = 0 # macro -ELF_NOTE_OS_GNU = 1 # macro -ELF_NOTE_OS_SOLARIS2 = 2 # macro -ELF_NOTE_OS_FREEBSD = 3 # macro -NT_GNU_HWCAP = 2 # macro -NT_GNU_BUILD_ID = 3 # macro -NT_GNU_GOLD_VERSION = 4 # macro -NT_GNU_PROPERTY_TYPE_0 = 5 # macro -NT_FDO_PACKAGING_METADATA = 0xcafe1a7e # macro -NOTE_GNU_PROPERTY_SECTION_NAME = ".note.gnu.property" # macro -GNU_PROPERTY_STACK_SIZE = 1 # macro -GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2 # macro -GNU_PROPERTY_UINT32_AND_LO = 0xb0000000 # macro -GNU_PROPERTY_UINT32_AND_HI = 0xb0007fff # macro -GNU_PROPERTY_UINT32_OR_LO = 0xb0008000 # macro -GNU_PROPERTY_UINT32_OR_HI = 0xb000ffff # macro -GNU_PROPERTY_1_NEEDED = 0xb0008000 # macro -GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS = (1<<0) # macro -GNU_PROPERTY_LOPROC = 0xc0000000 # macro -GNU_PROPERTY_HIPROC = 0xdfffffff # macro -GNU_PROPERTY_LOUSER = 0xe0000000 # macro -GNU_PROPERTY_HIUSER = 0xffffffff # macro -GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000 # macro -GNU_PROPERTY_AARCH64_FEATURE_1_BTI = (1<<0) # macro -GNU_PROPERTY_AARCH64_FEATURE_1_PAC = (1<<1) # macro -GNU_PROPERTY_X86_ISA_1_USED = 0xc0010002 # macro -GNU_PROPERTY_X86_ISA_1_NEEDED = 0xc0008002 # macro -GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002 # macro -GNU_PROPERTY_X86_ISA_1_BASELINE = (1<<0) # macro -GNU_PROPERTY_X86_ISA_1_V2 = (1<<1) # macro -GNU_PROPERTY_X86_ISA_1_V3 = (1<<2) # macro -GNU_PROPERTY_X86_ISA_1_V4 = (1<<3) # macro -GNU_PROPERTY_X86_FEATURE_1_IBT = (1<<0) # macro -GNU_PROPERTY_X86_FEATURE_1_SHSTK = (1<<1) # macro -def ELF32_M_SYM(info): # macro - return ((info)>>8) -def ELF32_M_SIZE(info): # macro - return ((info)) -def ELF32_M_INFO(sym, size): # macro - return (((sym)<<8)+(size)) -def ELF64_M_SYM(info): # macro - return ELF32_M_SYM(info) -def ELF64_M_SIZE(info): # macro - return ELF32_M_SIZE(info) -def ELF64_M_INFO(sym, size): # macro - return ELF32_M_INFO(sym,size) -EF_CPU32 = 0x00810000 # macro -R_68K_NONE = 0 # macro -R_68K_32 = 1 # macro -R_68K_16 = 2 # macro -R_68K_8 = 3 # macro -R_68K_PC32 = 4 # macro -R_68K_PC16 = 5 # macro -R_68K_PC8 = 6 # macro -R_68K_GOT32 = 7 # macro -R_68K_GOT16 = 8 # macro -R_68K_GOT8 = 9 # macro -R_68K_GOT32O = 10 # macro -R_68K_GOT16O = 11 # macro -R_68K_GOT8O = 12 # macro -R_68K_PLT32 = 13 # macro -R_68K_PLT16 = 14 # macro -R_68K_PLT8 = 15 # macro -R_68K_PLT32O = 16 # macro -R_68K_PLT16O = 17 # macro -R_68K_PLT8O = 18 # macro -R_68K_COPY = 19 # macro -R_68K_GLOB_DAT = 20 # macro -R_68K_JMP_SLOT = 21 # macro -R_68K_RELATIVE = 22 # macro -R_68K_TLS_GD32 = 25 # macro -R_68K_TLS_GD16 = 26 # macro -R_68K_TLS_GD8 = 27 # macro -R_68K_TLS_LDM32 = 28 # macro -R_68K_TLS_LDM16 = 29 # macro -R_68K_TLS_LDM8 = 30 # macro -R_68K_TLS_LDO32 = 31 # macro -R_68K_TLS_LDO16 = 32 # macro -R_68K_TLS_LDO8 = 33 # macro -R_68K_TLS_IE32 = 34 # macro -R_68K_TLS_IE16 = 35 # macro -R_68K_TLS_IE8 = 36 # macro -R_68K_TLS_LE32 = 37 # macro -R_68K_TLS_LE16 = 38 # macro -R_68K_TLS_LE8 = 39 # macro -R_68K_TLS_DTPMOD32 = 40 # macro -R_68K_TLS_DTPREL32 = 41 # macro -R_68K_TLS_TPREL32 = 42 # macro -R_68K_NUM = 43 # macro -R_386_NONE = 0 # macro -R_386_32 = 1 # macro -R_386_PC32 = 2 # macro -R_386_GOT32 = 3 # macro -R_386_PLT32 = 4 # macro -R_386_COPY = 5 # macro -R_386_GLOB_DAT = 6 # macro -R_386_JMP_SLOT = 7 # macro -R_386_RELATIVE = 8 # macro -R_386_GOTOFF = 9 # macro -R_386_GOTPC = 10 # macro -R_386_32PLT = 11 # macro -R_386_TLS_TPOFF = 14 # macro -R_386_TLS_IE = 15 # macro -R_386_TLS_GOTIE = 16 # macro -R_386_TLS_LE = 17 # macro -R_386_TLS_GD = 18 # macro -R_386_TLS_LDM = 19 # macro -R_386_16 = 20 # macro -R_386_PC16 = 21 # macro -R_386_8 = 22 # macro -R_386_PC8 = 23 # macro -R_386_TLS_GD_32 = 24 # macro -R_386_TLS_GD_PUSH = 25 # macro -R_386_TLS_GD_CALL = 26 # macro -R_386_TLS_GD_POP = 27 # macro -R_386_TLS_LDM_32 = 28 # macro -R_386_TLS_LDM_PUSH = 29 # macro -R_386_TLS_LDM_CALL = 30 # macro -R_386_TLS_LDM_POP = 31 # macro -R_386_TLS_LDO_32 = 32 # macro -R_386_TLS_IE_32 = 33 # macro -R_386_TLS_LE_32 = 34 # macro -R_386_TLS_DTPMOD32 = 35 # macro -R_386_TLS_DTPOFF32 = 36 # macro -R_386_TLS_TPOFF32 = 37 # macro -R_386_SIZE32 = 38 # macro -R_386_TLS_GOTDESC = 39 # macro -R_386_TLS_DESC_CALL = 40 # macro -R_386_TLS_DESC = 41 # macro -R_386_IRELATIVE = 42 # macro -R_386_GOT32X = 43 # macro -R_386_NUM = 44 # macro -STT_SPARC_REGISTER = 13 # macro -EF_SPARCV9_MM = 3 # macro -EF_SPARCV9_TSO = 0 # macro -EF_SPARCV9_PSO = 1 # macro -EF_SPARCV9_RMO = 2 # macro -EF_SPARC_LEDATA = 0x800000 # macro -EF_SPARC_EXT_MASK = 0xFFFF00 # macro -EF_SPARC_32PLUS = 0x000100 # macro -EF_SPARC_SUN_US1 = 0x000200 # macro -EF_SPARC_HAL_R1 = 0x000400 # macro -EF_SPARC_SUN_US3 = 0x000800 # macro -R_SPARC_NONE = 0 # macro -R_SPARC_8 = 1 # macro -R_SPARC_16 = 2 # macro -R_SPARC_32 = 3 # macro -R_SPARC_DISP8 = 4 # macro -R_SPARC_DISP16 = 5 # macro -R_SPARC_DISP32 = 6 # macro -R_SPARC_WDISP30 = 7 # macro -R_SPARC_WDISP22 = 8 # macro -R_SPARC_HI22 = 9 # macro -R_SPARC_22 = 10 # macro -R_SPARC_13 = 11 # macro -R_SPARC_LO10 = 12 # macro -R_SPARC_GOT10 = 13 # macro -R_SPARC_GOT13 = 14 # macro -R_SPARC_GOT22 = 15 # macro -R_SPARC_PC10 = 16 # macro -R_SPARC_PC22 = 17 # macro -R_SPARC_WPLT30 = 18 # macro -R_SPARC_COPY = 19 # macro -R_SPARC_GLOB_DAT = 20 # macro -R_SPARC_JMP_SLOT = 21 # macro -R_SPARC_RELATIVE = 22 # macro -R_SPARC_UA32 = 23 # macro -R_SPARC_PLT32 = 24 # macro -R_SPARC_HIPLT22 = 25 # macro -R_SPARC_LOPLT10 = 26 # macro -R_SPARC_PCPLT32 = 27 # macro -R_SPARC_PCPLT22 = 28 # macro -R_SPARC_PCPLT10 = 29 # macro -R_SPARC_10 = 30 # macro -R_SPARC_11 = 31 # macro -R_SPARC_64 = 32 # macro -R_SPARC_OLO10 = 33 # macro -R_SPARC_HH22 = 34 # macro -R_SPARC_HM10 = 35 # macro -R_SPARC_LM22 = 36 # macro -R_SPARC_PC_HH22 = 37 # macro -R_SPARC_PC_HM10 = 38 # macro -R_SPARC_PC_LM22 = 39 # macro -R_SPARC_WDISP16 = 40 # macro -R_SPARC_WDISP19 = 41 # macro -R_SPARC_GLOB_JMP = 42 # macro -R_SPARC_7 = 43 # macro -R_SPARC_5 = 44 # macro -R_SPARC_6 = 45 # macro -R_SPARC_DISP64 = 46 # macro -R_SPARC_PLT64 = 47 # macro -R_SPARC_HIX22 = 48 # macro -R_SPARC_LOX10 = 49 # macro -R_SPARC_H44 = 50 # macro -R_SPARC_M44 = 51 # macro -R_SPARC_L44 = 52 # macro -R_SPARC_REGISTER = 53 # macro -R_SPARC_UA64 = 54 # macro -R_SPARC_UA16 = 55 # macro -R_SPARC_TLS_GD_HI22 = 56 # macro -R_SPARC_TLS_GD_LO10 = 57 # macro -R_SPARC_TLS_GD_ADD = 58 # macro -R_SPARC_TLS_GD_CALL = 59 # macro -R_SPARC_TLS_LDM_HI22 = 60 # macro -R_SPARC_TLS_LDM_LO10 = 61 # macro -R_SPARC_TLS_LDM_ADD = 62 # macro -R_SPARC_TLS_LDM_CALL = 63 # macro -R_SPARC_TLS_LDO_HIX22 = 64 # macro -R_SPARC_TLS_LDO_LOX10 = 65 # macro -R_SPARC_TLS_LDO_ADD = 66 # macro -R_SPARC_TLS_IE_HI22 = 67 # macro -R_SPARC_TLS_IE_LO10 = 68 # macro -R_SPARC_TLS_IE_LD = 69 # macro -R_SPARC_TLS_IE_LDX = 70 # macro -R_SPARC_TLS_IE_ADD = 71 # macro -R_SPARC_TLS_LE_HIX22 = 72 # macro -R_SPARC_TLS_LE_LOX10 = 73 # macro -R_SPARC_TLS_DTPMOD32 = 74 # macro -R_SPARC_TLS_DTPMOD64 = 75 # macro -R_SPARC_TLS_DTPOFF32 = 76 # macro -R_SPARC_TLS_DTPOFF64 = 77 # macro -R_SPARC_TLS_TPOFF32 = 78 # macro -R_SPARC_TLS_TPOFF64 = 79 # macro -R_SPARC_GOTDATA_HIX22 = 80 # macro -R_SPARC_GOTDATA_LOX10 = 81 # macro -R_SPARC_GOTDATA_OP_HIX22 = 82 # macro -R_SPARC_GOTDATA_OP_LOX10 = 83 # macro -R_SPARC_GOTDATA_OP = 84 # macro -R_SPARC_H34 = 85 # macro -R_SPARC_SIZE32 = 86 # macro -R_SPARC_SIZE64 = 87 # macro -R_SPARC_WDISP10 = 88 # macro -R_SPARC_JMP_IREL = 248 # macro -R_SPARC_IRELATIVE = 249 # macro -R_SPARC_GNU_VTINHERIT = 250 # macro -R_SPARC_GNU_VTENTRY = 251 # macro -R_SPARC_REV32 = 252 # macro -R_SPARC_NUM = 253 # macro -DT_SPARC_REGISTER = 0x70000001 # macro -DT_SPARC_NUM = 2 # macro -EF_MIPS_NOREORDER = 1 # macro -EF_MIPS_PIC = 2 # macro -EF_MIPS_CPIC = 4 # macro -EF_MIPS_XGOT = 8 # macro -EF_MIPS_UCODE = 16 # macro -EF_MIPS_ABI2 = 32 # macro -EF_MIPS_ABI_ON32 = 64 # macro -EF_MIPS_OPTIONS_FIRST = 0x00000080 # macro -EF_MIPS_32BITMODE = 0x00000100 # macro -EF_MIPS_FP64 = 512 # macro -EF_MIPS_NAN2008 = 1024 # macro -EF_MIPS_ARCH_ASE = 0x0f000000 # macro -EF_MIPS_ARCH_ASE_MDMX = 0x08000000 # macro -EF_MIPS_ARCH_ASE_M16 = 0x04000000 # macro -EF_MIPS_ARCH_ASE_MICROMIPS = 0x02000000 # macro -EF_MIPS_ARCH = 0xf0000000 # macro -EF_MIPS_ARCH_1 = 0x00000000 # macro -EF_MIPS_ARCH_2 = 0x10000000 # macro -EF_MIPS_ARCH_3 = 0x20000000 # macro -EF_MIPS_ARCH_4 = 0x30000000 # macro -EF_MIPS_ARCH_5 = 0x40000000 # macro -EF_MIPS_ARCH_32 = 0x50000000 # macro -EF_MIPS_ARCH_64 = 0x60000000 # macro -EF_MIPS_ARCH_32R2 = 0x70000000 # macro -EF_MIPS_ARCH_64R2 = 0x80000000 # macro -EF_MIPS_ARCH_32R6 = 0x90000000 # macro -EF_MIPS_ARCH_64R6 = 0xa0000000 # macro -EF_MIPS_ABI = 0x0000F000 # macro -EF_MIPS_ABI_O32 = 0x00001000 # macro -EF_MIPS_ABI_O64 = 0x00002000 # macro -EF_MIPS_ABI_EABI32 = 0x00003000 # macro -EF_MIPS_ABI_EABI64 = 0x00004000 # macro -EF_MIPS_MACH = 0x00FF0000 # macro -EF_MIPS_MACH_3900 = 0x00810000 # macro -EF_MIPS_MACH_4010 = 0x00820000 # macro -EF_MIPS_MACH_4100 = 0x00830000 # macro -EF_MIPS_MACH_ALLEGREX = 0x00840000 # macro -EF_MIPS_MACH_4650 = 0x00850000 # macro -EF_MIPS_MACH_4120 = 0x00870000 # macro -EF_MIPS_MACH_4111 = 0x00880000 # macro -EF_MIPS_MACH_SB1 = 0x008a0000 # macro -EF_MIPS_MACH_OCTEON = 0x008b0000 # macro -EF_MIPS_MACH_XLR = 0x008c0000 # macro -EF_MIPS_MACH_OCTEON2 = 0x008d0000 # macro -EF_MIPS_MACH_OCTEON3 = 0x008e0000 # macro -EF_MIPS_MACH_5400 = 0x00910000 # macro -EF_MIPS_MACH_5900 = 0x00920000 # macro -EF_MIPS_MACH_IAMR2 = 0x00930000 # macro -EF_MIPS_MACH_5500 = 0x00980000 # macro -EF_MIPS_MACH_9000 = 0x00990000 # macro -EF_MIPS_MACH_LS2E = 0x00A00000 # macro -EF_MIPS_MACH_LS2F = 0x00A10000 # macro -EF_MIPS_MACH_GS464 = 0x00A20000 # macro -EF_MIPS_MACH_GS464E = 0x00A30000 # macro -EF_MIPS_MACH_GS264E = 0x00A40000 # macro -E_MIPS_ARCH_1 = 0x00000000 # macro -E_MIPS_ARCH_2 = 0x10000000 # macro -E_MIPS_ARCH_3 = 0x20000000 # macro -E_MIPS_ARCH_4 = 0x30000000 # macro -E_MIPS_ARCH_5 = 0x40000000 # macro -E_MIPS_ARCH_32 = 0x50000000 # macro -E_MIPS_ARCH_64 = 0x60000000 # macro -SHN_MIPS_ACOMMON = 0xff00 # macro -SHN_MIPS_TEXT = 0xff01 # macro -SHN_MIPS_DATA = 0xff02 # macro -SHN_MIPS_SCOMMON = 0xff03 # macro -SHN_MIPS_SUNDEFINED = 0xff04 # macro -SHT_MIPS_LIBLIST = 0x70000000 # macro -SHT_MIPS_MSYM = 0x70000001 # macro -SHT_MIPS_CONFLICT = 0x70000002 # macro -SHT_MIPS_GPTAB = 0x70000003 # macro -SHT_MIPS_UCODE = 0x70000004 # macro -SHT_MIPS_DEBUG = 0x70000005 # macro -SHT_MIPS_REGINFO = 0x70000006 # macro -SHT_MIPS_PACKAGE = 0x70000007 # macro -SHT_MIPS_PACKSYM = 0x70000008 # macro -SHT_MIPS_RELD = 0x70000009 # macro -SHT_MIPS_IFACE = 0x7000000b # macro -SHT_MIPS_CONTENT = 0x7000000c # macro -SHT_MIPS_OPTIONS = 0x7000000d # macro -SHT_MIPS_SHDR = 0x70000010 # macro -SHT_MIPS_FDESC = 0x70000011 # macro -SHT_MIPS_EXTSYM = 0x70000012 # macro -SHT_MIPS_DENSE = 0x70000013 # macro -SHT_MIPS_PDESC = 0x70000014 # macro -SHT_MIPS_LOCSYM = 0x70000015 # macro -SHT_MIPS_AUXSYM = 0x70000016 # macro -SHT_MIPS_OPTSYM = 0x70000017 # macro -SHT_MIPS_LOCSTR = 0x70000018 # macro -SHT_MIPS_LINE = 0x70000019 # macro -SHT_MIPS_RFDESC = 0x7000001a # macro -SHT_MIPS_DELTASYM = 0x7000001b # macro -SHT_MIPS_DELTAINST = 0x7000001c # macro -SHT_MIPS_DELTACLASS = 0x7000001d # macro -SHT_MIPS_DWARF = 0x7000001e # macro -SHT_MIPS_DELTADECL = 0x7000001f # macro -SHT_MIPS_SYMBOL_LIB = 0x70000020 # macro -SHT_MIPS_EVENTS = 0x70000021 # macro -SHT_MIPS_TRANSLATE = 0x70000022 # macro -SHT_MIPS_PIXIE = 0x70000023 # macro -SHT_MIPS_XLATE = 0x70000024 # macro -SHT_MIPS_XLATE_DEBUG = 0x70000025 # macro -SHT_MIPS_WHIRL = 0x70000026 # macro -SHT_MIPS_EH_REGION = 0x70000027 # macro -SHT_MIPS_XLATE_OLD = 0x70000028 # macro -SHT_MIPS_PDR_EXCEPTION = 0x70000029 # macro -SHT_MIPS_ABIFLAGS = 0x7000002a # macro -SHT_MIPS_XHASH = 0x7000002b # macro -SHF_MIPS_GPREL = 0x10000000 # macro -SHF_MIPS_MERGE = 0x20000000 # macro -SHF_MIPS_ADDR = 0x40000000 # macro -SHF_MIPS_STRINGS = 0x80000000 # macro -SHF_MIPS_NOSTRIP = 0x08000000 # macro -SHF_MIPS_LOCAL = 0x04000000 # macro -SHF_MIPS_NAMES = 0x02000000 # macro -SHF_MIPS_NODUPE = 0x01000000 # macro -STO_MIPS_DEFAULT = 0x0 # macro -STO_MIPS_INTERNAL = 0x1 # macro -STO_MIPS_HIDDEN = 0x2 # macro -STO_MIPS_PROTECTED = 0x3 # macro -STO_MIPS_PLT = 0x8 # macro -STO_MIPS_SC_ALIGN_UNUSED = 0xff # macro -STB_MIPS_SPLIT_COMMON = 13 # macro -ODK_NULL = 0 # macro -ODK_REGINFO = 1 # macro -ODK_EXCEPTIONS = 2 # macro -ODK_PAD = 3 # macro -ODK_HWPATCH = 4 # macro -ODK_FILL = 5 # macro -ODK_TAGS = 6 # macro -ODK_HWAND = 7 # macro -ODK_HWOR = 8 # macro -OEX_FPU_MIN = 0x1f # macro -OEX_FPU_MAX = 0x1f00 # macro -OEX_PAGE0 = 0x10000 # macro -OEX_SMM = 0x20000 # macro -OEX_FPDBUG = 0x40000 # macro -OEX_PRECISEFP = 0x40000 # macro -OEX_DISMISS = 0x80000 # macro -OEX_FPU_INVAL = 0x10 # macro -OEX_FPU_DIV0 = 0x08 # macro -OEX_FPU_OFLO = 0x04 # macro -OEX_FPU_UFLO = 0x02 # macro -OEX_FPU_INEX = 0x01 # macro -OHW_R4KEOP = 0x1 # macro -OHW_R8KPFETCH = 0x2 # macro -OHW_R5KEOP = 0x4 # macro -OHW_R5KCVTL = 0x8 # macro -OPAD_PREFIX = 0x1 # macro -OPAD_POSTFIX = 0x2 # macro -OPAD_SYMBOL = 0x4 # macro -OHWA0_R4KEOP_CHECKED = 0x00000001 # macro -OHWA1_R4KEOP_CLEAN = 0x00000002 # macro -R_MIPS_NONE = 0 # macro -R_MIPS_16 = 1 # macro -R_MIPS_32 = 2 # macro -R_MIPS_REL32 = 3 # macro -R_MIPS_26 = 4 # macro -R_MIPS_HI16 = 5 # macro -R_MIPS_LO16 = 6 # macro -R_MIPS_GPREL16 = 7 # macro -R_MIPS_LITERAL = 8 # macro -R_MIPS_GOT16 = 9 # macro -R_MIPS_PC16 = 10 # macro -R_MIPS_CALL16 = 11 # macro -R_MIPS_GPREL32 = 12 # macro -R_MIPS_SHIFT5 = 16 # macro -R_MIPS_SHIFT6 = 17 # macro -R_MIPS_64 = 18 # macro -R_MIPS_GOT_DISP = 19 # macro -R_MIPS_GOT_PAGE = 20 # macro -R_MIPS_GOT_OFST = 21 # macro -R_MIPS_GOT_HI16 = 22 # macro -R_MIPS_GOT_LO16 = 23 # macro -R_MIPS_SUB = 24 # macro -R_MIPS_INSERT_A = 25 # macro -R_MIPS_INSERT_B = 26 # macro -R_MIPS_DELETE = 27 # macro -R_MIPS_HIGHER = 28 # macro -R_MIPS_HIGHEST = 29 # macro -R_MIPS_CALL_HI16 = 30 # macro -R_MIPS_CALL_LO16 = 31 # macro -R_MIPS_SCN_DISP = 32 # macro -R_MIPS_REL16 = 33 # macro -R_MIPS_ADD_IMMEDIATE = 34 # macro -R_MIPS_PJUMP = 35 # macro -R_MIPS_RELGOT = 36 # macro -R_MIPS_JALR = 37 # macro -R_MIPS_TLS_DTPMOD32 = 38 # macro -R_MIPS_TLS_DTPREL32 = 39 # macro -R_MIPS_TLS_DTPMOD64 = 40 # macro -R_MIPS_TLS_DTPREL64 = 41 # macro -R_MIPS_TLS_GD = 42 # macro -R_MIPS_TLS_LDM = 43 # macro -R_MIPS_TLS_DTPREL_HI16 = 44 # macro -R_MIPS_TLS_DTPREL_LO16 = 45 # macro -R_MIPS_TLS_GOTTPREL = 46 # macro -R_MIPS_TLS_TPREL32 = 47 # macro -R_MIPS_TLS_TPREL64 = 48 # macro -R_MIPS_TLS_TPREL_HI16 = 49 # macro -R_MIPS_TLS_TPREL_LO16 = 50 # macro -R_MIPS_GLOB_DAT = 51 # macro -R_MIPS_PC21_S2 = 60 # macro -R_MIPS_PC26_S2 = 61 # macro -R_MIPS_PC18_S3 = 62 # macro -R_MIPS_PC19_S2 = 63 # macro -R_MIPS_PCHI16 = 64 # macro -R_MIPS_PCLO16 = 65 # macro -R_MIPS16_26 = 100 # macro -R_MIPS16_GPREL = 101 # macro -R_MIPS16_GOT16 = 102 # macro -R_MIPS16_CALL16 = 103 # macro -R_MIPS16_HI16 = 104 # macro -R_MIPS16_LO16 = 105 # macro -R_MIPS16_TLS_GD = 106 # macro -R_MIPS16_TLS_LDM = 107 # macro -R_MIPS16_TLS_DTPREL_HI16 = 108 # macro -R_MIPS16_TLS_DTPREL_LO16 = 109 # macro -R_MIPS16_TLS_GOTTPREL = 110 # macro -R_MIPS16_TLS_TPREL_HI16 = 111 # macro -R_MIPS16_TLS_TPREL_LO16 = 112 # macro -R_MIPS16_PC16_S1 = 113 # macro -R_MIPS_COPY = 126 # macro -R_MIPS_JUMP_SLOT = 127 # macro -R_MIPS_RELATIVE = 128 # macro -R_MICROMIPS_26_S1 = 133 # macro -R_MICROMIPS_HI16 = 134 # macro -R_MICROMIPS_LO16 = 135 # macro -R_MICROMIPS_GPREL16 = 136 # macro -R_MICROMIPS_LITERAL = 137 # macro -R_MICROMIPS_GOT16 = 138 # macro -R_MICROMIPS_PC7_S1 = 139 # macro -R_MICROMIPS_PC10_S1 = 140 # macro -R_MICROMIPS_PC16_S1 = 141 # macro -R_MICROMIPS_CALL16 = 142 # macro -R_MICROMIPS_GOT_DISP = 145 # macro -R_MICROMIPS_GOT_PAGE = 146 # macro -R_MICROMIPS_GOT_OFST = 147 # macro -R_MICROMIPS_GOT_HI16 = 148 # macro -R_MICROMIPS_GOT_LO16 = 149 # macro -R_MICROMIPS_SUB = 150 # macro -R_MICROMIPS_HIGHER = 151 # macro -R_MICROMIPS_HIGHEST = 152 # macro -R_MICROMIPS_CALL_HI16 = 153 # macro -R_MICROMIPS_CALL_LO16 = 154 # macro -R_MICROMIPS_SCN_DISP = 155 # macro -R_MICROMIPS_JALR = 156 # macro -R_MICROMIPS_HI0_LO16 = 157 # macro -R_MICROMIPS_TLS_GD = 162 # macro -R_MICROMIPS_TLS_LDM = 163 # macro -R_MICROMIPS_TLS_DTPREL_HI16 = 164 # macro -R_MICROMIPS_TLS_DTPREL_LO16 = 165 # macro -R_MICROMIPS_TLS_GOTTPREL = 166 # macro -R_MICROMIPS_TLS_TPREL_HI16 = 169 # macro -R_MICROMIPS_TLS_TPREL_LO16 = 170 # macro -R_MICROMIPS_GPREL7_S2 = 172 # macro -R_MICROMIPS_PC23_S2 = 173 # macro -R_MIPS_PC32 = 248 # macro -R_MIPS_EH = 249 # macro -R_MIPS_GNU_REL16_S2 = 250 # macro -R_MIPS_GNU_VTINHERIT = 253 # macro -R_MIPS_GNU_VTENTRY = 254 # macro -R_MIPS_NUM = 255 # macro -PT_MIPS_REGINFO = 0x70000000 # macro -PT_MIPS_RTPROC = 0x70000001 # macro -PT_MIPS_OPTIONS = 0x70000002 # macro -PT_MIPS_ABIFLAGS = 0x70000003 # macro -PF_MIPS_LOCAL = 0x10000000 # macro -DT_MIPS_RLD_VERSION = 0x70000001 # macro -DT_MIPS_TIME_STAMP = 0x70000002 # macro -DT_MIPS_ICHECKSUM = 0x70000003 # macro -DT_MIPS_IVERSION = 0x70000004 # macro -DT_MIPS_FLAGS = 0x70000005 # macro -DT_MIPS_BASE_ADDRESS = 0x70000006 # macro -DT_MIPS_MSYM = 0x70000007 # macro -DT_MIPS_CONFLICT = 0x70000008 # macro -DT_MIPS_LIBLIST = 0x70000009 # macro -DT_MIPS_LOCAL_GOTNO = 0x7000000a # macro -DT_MIPS_CONFLICTNO = 0x7000000b # macro -DT_MIPS_LIBLISTNO = 0x70000010 # macro -DT_MIPS_SYMTABNO = 0x70000011 # macro -DT_MIPS_UNREFEXTNO = 0x70000012 # macro -DT_MIPS_GOTSYM = 0x70000013 # macro -DT_MIPS_HIPAGENO = 0x70000014 # macro -DT_MIPS_RLD_MAP = 0x70000016 # macro -DT_MIPS_DELTA_CLASS = 0x70000017 # macro -DT_MIPS_DELTA_CLASS_NO = 0x70000018 # macro -DT_MIPS_DELTA_INSTANCE = 0x70000019 # macro -DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a # macro -DT_MIPS_DELTA_RELOC = 0x7000001b # macro -DT_MIPS_DELTA_RELOC_NO = 0x7000001c # macro -DT_MIPS_DELTA_SYM = 0x7000001d # macro -DT_MIPS_DELTA_SYM_NO = 0x7000001e # macro -DT_MIPS_DELTA_CLASSSYM = 0x70000020 # macro -DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021 # macro -DT_MIPS_CXX_FLAGS = 0x70000022 # macro -DT_MIPS_PIXIE_INIT = 0x70000023 # macro -DT_MIPS_SYMBOL_LIB = 0x70000024 # macro -DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025 # macro -DT_MIPS_LOCAL_GOTIDX = 0x70000026 # macro -DT_MIPS_HIDDEN_GOTIDX = 0x70000027 # macro -DT_MIPS_PROTECTED_GOTIDX = 0x70000028 # macro -DT_MIPS_OPTIONS = 0x70000029 # macro -DT_MIPS_INTERFACE = 0x7000002a # macro -DT_MIPS_DYNSTR_ALIGN = 0x7000002b # macro -DT_MIPS_INTERFACE_SIZE = 0x7000002c # macro -DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d # macro -DT_MIPS_PERF_SUFFIX = 0x7000002e # macro -DT_MIPS_COMPACT_SIZE = 0x7000002f # macro -DT_MIPS_GP_VALUE = 0x70000030 # macro -DT_MIPS_AUX_DYNAMIC = 0x70000031 # macro -DT_MIPS_PLTGOT = 0x70000032 # macro -DT_MIPS_RWPLT = 0x70000034 # macro -DT_MIPS_RLD_MAP_REL = 0x70000035 # macro -DT_MIPS_XHASH = 0x70000036 # macro -DT_MIPS_NUM = 0x37 # macro -DT_PROCNUM = DT_MIPS_NUM # macro -RHF_NONE = 0 # macro -RHF_QUICKSTART = (1<<0) # macro -RHF_NOTPOT = (1<<1) # macro -RHF_NO_LIBRARY_REPLACEMENT = (1<<2) # macro -RHF_NO_MOVE = (1<<3) # macro -RHF_SGI_ONLY = (1<<4) # macro -RHF_GUARANTEE_INIT = (1<<5) # macro -RHF_DELTA_C_PLUS_PLUS = (1<<6) # macro -RHF_GUARANTEE_START_INIT = (1<<7) # macro -RHF_PIXIE = (1<<8) # macro -RHF_DEFAULT_DELAY_LOAD = (1<<9) # macro -RHF_REQUICKSTART = (1<<10) # macro -RHF_REQUICKSTARTED = (1<<11) # macro -RHF_CORD = (1<<12) # macro -RHF_NO_UNRES_UNDEF = (1<<13) # macro -RHF_RLD_ORDER_SAFE = (1<<14) # macro -LL_NONE = 0 # macro -LL_EXACT_MATCH = (1<<0) # macro -LL_IGNORE_INT_VER = (1<<1) # macro -LL_REQUIRE_MINOR = (1<<2) # macro -LL_EXPORTS = (1<<3) # macro -LL_DELAY_LOAD = (1<<4) # macro -LL_DELTA = (1<<5) # macro -MIPS_AFL_REG_NONE = 0x00 # macro -MIPS_AFL_REG_32 = 0x01 # macro -MIPS_AFL_REG_64 = 0x02 # macro -MIPS_AFL_REG_128 = 0x03 # macro -MIPS_AFL_ASE_DSP = 0x00000001 # macro -MIPS_AFL_ASE_DSPR2 = 0x00000002 # macro -MIPS_AFL_ASE_EVA = 0x00000004 # macro -MIPS_AFL_ASE_MCU = 0x00000008 # macro -MIPS_AFL_ASE_MDMX = 0x00000010 # macro -MIPS_AFL_ASE_MIPS3D = 0x00000020 # macro -MIPS_AFL_ASE_MT = 0x00000040 # macro -MIPS_AFL_ASE_SMARTMIPS = 0x00000080 # macro -MIPS_AFL_ASE_VIRT = 0x00000100 # macro -MIPS_AFL_ASE_MSA = 0x00000200 # macro -MIPS_AFL_ASE_MIPS16 = 0x00000400 # macro -MIPS_AFL_ASE_MICROMIPS = 0x00000800 # macro -MIPS_AFL_ASE_XPA = 0x00001000 # macro -MIPS_AFL_ASE_MASK = 0x00001fff # macro -MIPS_AFL_EXT_XLR = 1 # macro -MIPS_AFL_EXT_OCTEON2 = 2 # macro -MIPS_AFL_EXT_OCTEONP = 3 # macro -MIPS_AFL_EXT_LOONGSON_3A = 4 # macro -MIPS_AFL_EXT_OCTEON = 5 # macro -MIPS_AFL_EXT_5900 = 6 # macro -MIPS_AFL_EXT_4650 = 7 # macro -MIPS_AFL_EXT_4010 = 8 # macro -MIPS_AFL_EXT_4100 = 9 # macro -MIPS_AFL_EXT_3900 = 10 # macro -MIPS_AFL_EXT_10000 = 11 # macro -MIPS_AFL_EXT_SB1 = 12 # macro -MIPS_AFL_EXT_4111 = 13 # macro -MIPS_AFL_EXT_4120 = 14 # macro -MIPS_AFL_EXT_5400 = 15 # macro -MIPS_AFL_EXT_5500 = 16 # macro -MIPS_AFL_EXT_LOONGSON_2E = 17 # macro -MIPS_AFL_EXT_LOONGSON_2F = 18 # macro -MIPS_AFL_FLAGS1_ODDSPREG = 1 # macro -EF_PARISC_TRAPNIL = 0x00010000 # macro -EF_PARISC_EXT = 0x00020000 # macro -EF_PARISC_LSB = 0x00040000 # macro -EF_PARISC_WIDE = 0x00080000 # macro -EF_PARISC_NO_KABP = 0x00100000 # macro -EF_PARISC_LAZYSWAP = 0x00400000 # macro -EF_PARISC_ARCH = 0x0000ffff # macro -EFA_PARISC_1_0 = 0x020b # macro -EFA_PARISC_1_1 = 0x0210 # macro -EFA_PARISC_2_0 = 0x0214 # macro -SHN_PARISC_ANSI_COMMON = 0xff00 # macro -SHN_PARISC_HUGE_COMMON = 0xff01 # macro -SHT_PARISC_EXT = 0x70000000 # macro -SHT_PARISC_UNWIND = 0x70000001 # macro -SHT_PARISC_DOC = 0x70000002 # macro -SHF_PARISC_SHORT = 0x20000000 # macro -SHF_PARISC_HUGE = 0x40000000 # macro -SHF_PARISC_SBP = 0x80000000 # macro -STT_PARISC_MILLICODE = 13 # macro -STT_HP_OPAQUE = (10+0x1) # macro -STT_HP_STUB = (10+0x2) # macro -R_PARISC_NONE = 0 # macro -R_PARISC_DIR32 = 1 # macro -R_PARISC_DIR21L = 2 # macro -R_PARISC_DIR17R = 3 # macro -R_PARISC_DIR17F = 4 # macro -R_PARISC_DIR14R = 6 # macro -R_PARISC_PCREL32 = 9 # macro -R_PARISC_PCREL21L = 10 # macro -R_PARISC_PCREL17R = 11 # macro -R_PARISC_PCREL17F = 12 # macro -R_PARISC_PCREL14R = 14 # macro -R_PARISC_DPREL21L = 18 # macro -R_PARISC_DPREL14R = 22 # macro -R_PARISC_GPREL21L = 26 # macro -R_PARISC_GPREL14R = 30 # macro -R_PARISC_LTOFF21L = 34 # macro -R_PARISC_LTOFF14R = 38 # macro -R_PARISC_SECREL32 = 41 # macro -R_PARISC_SEGBASE = 48 # macro -R_PARISC_SEGREL32 = 49 # macro -R_PARISC_PLTOFF21L = 50 # macro -R_PARISC_PLTOFF14R = 54 # macro -R_PARISC_LTOFF_FPTR32 = 57 # macro -R_PARISC_LTOFF_FPTR21L = 58 # macro -R_PARISC_LTOFF_FPTR14R = 62 # macro -R_PARISC_FPTR64 = 64 # macro -R_PARISC_PLABEL32 = 65 # macro -R_PARISC_PLABEL21L = 66 # macro -R_PARISC_PLABEL14R = 70 # macro -R_PARISC_PCREL64 = 72 # macro -R_PARISC_PCREL22F = 74 # macro -R_PARISC_PCREL14WR = 75 # macro -R_PARISC_PCREL14DR = 76 # macro -R_PARISC_PCREL16F = 77 # macro -R_PARISC_PCREL16WF = 78 # macro -R_PARISC_PCREL16DF = 79 # macro -R_PARISC_DIR64 = 80 # macro -R_PARISC_DIR14WR = 83 # macro -R_PARISC_DIR14DR = 84 # macro -R_PARISC_DIR16F = 85 # macro -R_PARISC_DIR16WF = 86 # macro -R_PARISC_DIR16DF = 87 # macro -R_PARISC_GPREL64 = 88 # macro -R_PARISC_GPREL14WR = 91 # macro -R_PARISC_GPREL14DR = 92 # macro -R_PARISC_GPREL16F = 93 # macro -R_PARISC_GPREL16WF = 94 # macro -R_PARISC_GPREL16DF = 95 # macro -R_PARISC_LTOFF64 = 96 # macro -R_PARISC_LTOFF14WR = 99 # macro -R_PARISC_LTOFF14DR = 100 # macro -R_PARISC_LTOFF16F = 101 # macro -R_PARISC_LTOFF16WF = 102 # macro -R_PARISC_LTOFF16DF = 103 # macro -R_PARISC_SECREL64 = 104 # macro -R_PARISC_SEGREL64 = 112 # macro -R_PARISC_PLTOFF14WR = 115 # macro -R_PARISC_PLTOFF14DR = 116 # macro -R_PARISC_PLTOFF16F = 117 # macro -R_PARISC_PLTOFF16WF = 118 # macro -R_PARISC_PLTOFF16DF = 119 # macro -R_PARISC_LTOFF_FPTR64 = 120 # macro -R_PARISC_LTOFF_FPTR14WR = 123 # macro -R_PARISC_LTOFF_FPTR14DR = 124 # macro -R_PARISC_LTOFF_FPTR16F = 125 # macro -R_PARISC_LTOFF_FPTR16WF = 126 # macro -R_PARISC_LTOFF_FPTR16DF = 127 # macro -R_PARISC_LORESERVE = 128 # macro -R_PARISC_COPY = 128 # macro -R_PARISC_IPLT = 129 # macro -R_PARISC_EPLT = 130 # macro -R_PARISC_TPREL32 = 153 # macro -R_PARISC_TPREL21L = 154 # macro -R_PARISC_TPREL14R = 158 # macro -R_PARISC_LTOFF_TP21L = 162 # macro -R_PARISC_LTOFF_TP14R = 166 # macro -R_PARISC_LTOFF_TP14F = 167 # macro -R_PARISC_TPREL64 = 216 # macro -R_PARISC_TPREL14WR = 219 # macro -R_PARISC_TPREL14DR = 220 # macro -R_PARISC_TPREL16F = 221 # macro -R_PARISC_TPREL16WF = 222 # macro -R_PARISC_TPREL16DF = 223 # macro -R_PARISC_LTOFF_TP64 = 224 # macro -R_PARISC_LTOFF_TP14WR = 227 # macro -R_PARISC_LTOFF_TP14DR = 228 # macro -R_PARISC_LTOFF_TP16F = 229 # macro -R_PARISC_LTOFF_TP16WF = 230 # macro -R_PARISC_LTOFF_TP16DF = 231 # macro -R_PARISC_GNU_VTENTRY = 232 # macro -R_PARISC_GNU_VTINHERIT = 233 # macro -R_PARISC_TLS_GD21L = 234 # macro -R_PARISC_TLS_GD14R = 235 # macro -R_PARISC_TLS_GDCALL = 236 # macro -R_PARISC_TLS_LDM21L = 237 # macro -R_PARISC_TLS_LDM14R = 238 # macro -R_PARISC_TLS_LDMCALL = 239 # macro -R_PARISC_TLS_LDO21L = 240 # macro -R_PARISC_TLS_LDO14R = 241 # macro -R_PARISC_TLS_DTPMOD32 = 242 # macro -R_PARISC_TLS_DTPMOD64 = 243 # macro -R_PARISC_TLS_DTPOFF32 = 244 # macro -R_PARISC_TLS_DTPOFF64 = 245 # macro -R_PARISC_TLS_LE21L = 154 # macro -R_PARISC_TLS_LE14R = 158 # macro -R_PARISC_TLS_IE21L = 162 # macro -R_PARISC_TLS_IE14R = 166 # macro -R_PARISC_TLS_TPREL32 = 153 # macro -R_PARISC_TLS_TPREL64 = 216 # macro -R_PARISC_HIRESERVE = 255 # macro -PT_HP_TLS = (0x60000000+0x0) # macro -PT_HP_CORE_NONE = (0x60000000+0x1) # macro -PT_HP_CORE_VERSION = (0x60000000+0x2) # macro -PT_HP_CORE_KERNEL = (0x60000000+0x3) # macro -PT_HP_CORE_COMM = (0x60000000+0x4) # macro -PT_HP_CORE_PROC = (0x60000000+0x5) # macro -PT_HP_CORE_LOADABLE = (0x60000000+0x6) # macro -PT_HP_CORE_STACK = (0x60000000+0x7) # macro -PT_HP_CORE_SHM = (0x60000000+0x8) # macro -PT_HP_CORE_MMF = (0x60000000+0x9) # macro -PT_HP_PARALLEL = (0x60000000+0x10) # macro -PT_HP_FASTBIND = (0x60000000+0x11) # macro -PT_HP_OPT_ANNOT = (0x60000000+0x12) # macro -PT_HP_HSL_ANNOT = (0x60000000+0x13) # macro -PT_HP_STACK = (0x60000000+0x14) # macro -PT_PARISC_ARCHEXT = 0x70000000 # macro -PT_PARISC_UNWIND = 0x70000001 # macro -PF_PARISC_SBP = 0x08000000 # macro -PF_HP_PAGE_SIZE = 0x00100000 # macro -PF_HP_FAR_SHARED = 0x00200000 # macro -PF_HP_NEAR_SHARED = 0x00400000 # macro -PF_HP_CODE = 0x01000000 # macro -PF_HP_MODIFY = 0x02000000 # macro -PF_HP_LAZYSWAP = 0x04000000 # macro -PF_HP_SBP = 0x08000000 # macro -EF_ALPHA_32BIT = 1 # macro -EF_ALPHA_CANRELAX = 2 # macro -SHT_ALPHA_DEBUG = 0x70000001 # macro -SHT_ALPHA_REGINFO = 0x70000002 # macro -SHF_ALPHA_GPREL = 0x10000000 # macro -STO_ALPHA_NOPV = 0x80 # macro -STO_ALPHA_STD_GPLOAD = 0x88 # macro -R_ALPHA_NONE = 0 # macro -R_ALPHA_REFLONG = 1 # macro -R_ALPHA_REFQUAD = 2 # macro -R_ALPHA_GPREL32 = 3 # macro -R_ALPHA_LITERAL = 4 # macro -R_ALPHA_LITUSE = 5 # macro -R_ALPHA_GPDISP = 6 # macro -R_ALPHA_BRADDR = 7 # macro -R_ALPHA_HINT = 8 # macro -R_ALPHA_SREL16 = 9 # macro -R_ALPHA_SREL32 = 10 # macro -R_ALPHA_SREL64 = 11 # macro -R_ALPHA_GPRELHIGH = 17 # macro -R_ALPHA_GPRELLOW = 18 # macro -R_ALPHA_GPREL16 = 19 # macro -R_ALPHA_COPY = 24 # macro -R_ALPHA_GLOB_DAT = 25 # macro -R_ALPHA_JMP_SLOT = 26 # macro -R_ALPHA_RELATIVE = 27 # macro -R_ALPHA_TLS_GD_HI = 28 # macro -R_ALPHA_TLSGD = 29 # macro -R_ALPHA_TLS_LDM = 30 # macro -R_ALPHA_DTPMOD64 = 31 # macro -R_ALPHA_GOTDTPREL = 32 # macro -R_ALPHA_DTPREL64 = 33 # macro -R_ALPHA_DTPRELHI = 34 # macro -R_ALPHA_DTPRELLO = 35 # macro -R_ALPHA_DTPREL16 = 36 # macro -R_ALPHA_GOTTPREL = 37 # macro -R_ALPHA_TPREL64 = 38 # macro -R_ALPHA_TPRELHI = 39 # macro -R_ALPHA_TPRELLO = 40 # macro -R_ALPHA_TPREL16 = 41 # macro -R_ALPHA_NUM = 46 # macro -LITUSE_ALPHA_ADDR = 0 # macro -LITUSE_ALPHA_BASE = 1 # macro -LITUSE_ALPHA_BYTOFF = 2 # macro -LITUSE_ALPHA_JSR = 3 # macro -LITUSE_ALPHA_TLS_GD = 4 # macro -LITUSE_ALPHA_TLS_LDM = 5 # macro -DT_ALPHA_PLTRO = (0x70000000+0) # macro -DT_ALPHA_NUM = 1 # macro -EF_PPC_EMB = 0x80000000 # macro -EF_PPC_RELOCATABLE = 0x00010000 # macro -EF_PPC_RELOCATABLE_LIB = 0x00008000 # macro -R_PPC_NONE = 0 # macro -R_PPC_ADDR32 = 1 # macro -R_PPC_ADDR24 = 2 # macro -R_PPC_ADDR16 = 3 # macro -R_PPC_ADDR16_LO = 4 # macro -R_PPC_ADDR16_HI = 5 # macro -R_PPC_ADDR16_HA = 6 # macro -R_PPC_ADDR14 = 7 # macro -R_PPC_ADDR14_BRTAKEN = 8 # macro -R_PPC_ADDR14_BRNTAKEN = 9 # macro -R_PPC_REL24 = 10 # macro -R_PPC_REL14 = 11 # macro -R_PPC_REL14_BRTAKEN = 12 # macro -R_PPC_REL14_BRNTAKEN = 13 # macro -R_PPC_GOT16 = 14 # macro -R_PPC_GOT16_LO = 15 # macro -R_PPC_GOT16_HI = 16 # macro -R_PPC_GOT16_HA = 17 # macro -R_PPC_PLTREL24 = 18 # macro -R_PPC_COPY = 19 # macro -R_PPC_GLOB_DAT = 20 # macro -R_PPC_JMP_SLOT = 21 # macro -R_PPC_RELATIVE = 22 # macro -R_PPC_LOCAL24PC = 23 # macro -R_PPC_UADDR32 = 24 # macro -R_PPC_UADDR16 = 25 # macro -R_PPC_REL32 = 26 # macro -R_PPC_PLT32 = 27 # macro -R_PPC_PLTREL32 = 28 # macro -R_PPC_PLT16_LO = 29 # macro -R_PPC_PLT16_HI = 30 # macro -R_PPC_PLT16_HA = 31 # macro -R_PPC_SDAREL16 = 32 # macro -R_PPC_SECTOFF = 33 # macro -R_PPC_SECTOFF_LO = 34 # macro -R_PPC_SECTOFF_HI = 35 # macro -R_PPC_SECTOFF_HA = 36 # macro -R_PPC_TLS = 67 # macro -R_PPC_DTPMOD32 = 68 # macro -R_PPC_TPREL16 = 69 # macro -R_PPC_TPREL16_LO = 70 # macro -R_PPC_TPREL16_HI = 71 # macro -R_PPC_TPREL16_HA = 72 # macro -R_PPC_TPREL32 = 73 # macro -R_PPC_DTPREL16 = 74 # macro -R_PPC_DTPREL16_LO = 75 # macro -R_PPC_DTPREL16_HI = 76 # macro -R_PPC_DTPREL16_HA = 77 # macro -R_PPC_DTPREL32 = 78 # macro -R_PPC_GOT_TLSGD16 = 79 # macro -R_PPC_GOT_TLSGD16_LO = 80 # macro -R_PPC_GOT_TLSGD16_HI = 81 # macro -R_PPC_GOT_TLSGD16_HA = 82 # macro -R_PPC_GOT_TLSLD16 = 83 # macro -R_PPC_GOT_TLSLD16_LO = 84 # macro -R_PPC_GOT_TLSLD16_HI = 85 # macro -R_PPC_GOT_TLSLD16_HA = 86 # macro -R_PPC_GOT_TPREL16 = 87 # macro -R_PPC_GOT_TPREL16_LO = 88 # macro -R_PPC_GOT_TPREL16_HI = 89 # macro -R_PPC_GOT_TPREL16_HA = 90 # macro -R_PPC_GOT_DTPREL16 = 91 # macro -R_PPC_GOT_DTPREL16_LO = 92 # macro -R_PPC_GOT_DTPREL16_HI = 93 # macro -R_PPC_GOT_DTPREL16_HA = 94 # macro -R_PPC_TLSGD = 95 # macro -R_PPC_TLSLD = 96 # macro -R_PPC_EMB_NADDR32 = 101 # macro -R_PPC_EMB_NADDR16 = 102 # macro -R_PPC_EMB_NADDR16_LO = 103 # macro -R_PPC_EMB_NADDR16_HI = 104 # macro -R_PPC_EMB_NADDR16_HA = 105 # macro -R_PPC_EMB_SDAI16 = 106 # macro -R_PPC_EMB_SDA2I16 = 107 # macro -R_PPC_EMB_SDA2REL = 108 # macro -R_PPC_EMB_SDA21 = 109 # macro -R_PPC_EMB_MRKREF = 110 # macro -R_PPC_EMB_RELSEC16 = 111 # macro -R_PPC_EMB_RELST_LO = 112 # macro -R_PPC_EMB_RELST_HI = 113 # macro -R_PPC_EMB_RELST_HA = 114 # macro -R_PPC_EMB_BIT_FLD = 115 # macro -R_PPC_EMB_RELSDA = 116 # macro -R_PPC_DIAB_SDA21_LO = 180 # macro -R_PPC_DIAB_SDA21_HI = 181 # macro -R_PPC_DIAB_SDA21_HA = 182 # macro -R_PPC_DIAB_RELSDA_LO = 183 # macro -R_PPC_DIAB_RELSDA_HI = 184 # macro -R_PPC_DIAB_RELSDA_HA = 185 # macro -R_PPC_IRELATIVE = 248 # macro -R_PPC_REL16 = 249 # macro -R_PPC_REL16_LO = 250 # macro -R_PPC_REL16_HI = 251 # macro -R_PPC_REL16_HA = 252 # macro -R_PPC_TOC16 = 255 # macro -DT_PPC_GOT = (0x70000000+0) # macro -DT_PPC_OPT = (0x70000000+1) # macro -DT_PPC_NUM = 2 # macro -PPC_OPT_TLS = 1 # macro -R_PPC64_NONE = 0 # macro -R_PPC64_ADDR32 = 1 # macro -R_PPC64_ADDR24 = 2 # macro -R_PPC64_ADDR16 = 3 # macro -R_PPC64_ADDR16_LO = 4 # macro -R_PPC64_ADDR16_HI = 5 # macro -R_PPC64_ADDR16_HA = 6 # macro -R_PPC64_ADDR14 = 7 # macro -R_PPC64_ADDR14_BRTAKEN = 8 # macro -R_PPC64_ADDR14_BRNTAKEN = 9 # macro -R_PPC64_REL24 = 10 # macro -R_PPC64_REL14 = 11 # macro -R_PPC64_REL14_BRTAKEN = 12 # macro -R_PPC64_REL14_BRNTAKEN = 13 # macro -R_PPC64_GOT16 = 14 # macro -R_PPC64_GOT16_LO = 15 # macro -R_PPC64_GOT16_HI = 16 # macro -R_PPC64_GOT16_HA = 17 # macro -R_PPC64_COPY = 19 # macro -R_PPC64_GLOB_DAT = 20 # macro -R_PPC64_JMP_SLOT = 21 # macro -R_PPC64_RELATIVE = 22 # macro -R_PPC64_UADDR32 = 24 # macro -R_PPC64_UADDR16 = 25 # macro -R_PPC64_REL32 = 26 # macro -R_PPC64_PLT32 = 27 # macro -R_PPC64_PLTREL32 = 28 # macro -R_PPC64_PLT16_LO = 29 # macro -R_PPC64_PLT16_HI = 30 # macro -R_PPC64_PLT16_HA = 31 # macro -R_PPC64_SECTOFF = 33 # macro -R_PPC64_SECTOFF_LO = 34 # macro -R_PPC64_SECTOFF_HI = 35 # macro -R_PPC64_SECTOFF_HA = 36 # macro -R_PPC64_ADDR30 = 37 # macro -R_PPC64_ADDR64 = 38 # macro -R_PPC64_ADDR16_HIGHER = 39 # macro -R_PPC64_ADDR16_HIGHERA = 40 # macro -R_PPC64_ADDR16_HIGHEST = 41 # macro -R_PPC64_ADDR16_HIGHESTA = 42 # macro -R_PPC64_UADDR64 = 43 # macro -R_PPC64_REL64 = 44 # macro -R_PPC64_PLT64 = 45 # macro -R_PPC64_PLTREL64 = 46 # macro -R_PPC64_TOC16 = 47 # macro -R_PPC64_TOC16_LO = 48 # macro -R_PPC64_TOC16_HI = 49 # macro -R_PPC64_TOC16_HA = 50 # macro -R_PPC64_TOC = 51 # macro -R_PPC64_PLTGOT16 = 52 # macro -R_PPC64_PLTGOT16_LO = 53 # macro -R_PPC64_PLTGOT16_HI = 54 # macro -R_PPC64_PLTGOT16_HA = 55 # macro -R_PPC64_ADDR16_DS = 56 # macro -R_PPC64_ADDR16_LO_DS = 57 # macro -R_PPC64_GOT16_DS = 58 # macro -R_PPC64_GOT16_LO_DS = 59 # macro -R_PPC64_PLT16_LO_DS = 60 # macro -R_PPC64_SECTOFF_DS = 61 # macro -R_PPC64_SECTOFF_LO_DS = 62 # macro -R_PPC64_TOC16_DS = 63 # macro -R_PPC64_TOC16_LO_DS = 64 # macro -R_PPC64_PLTGOT16_DS = 65 # macro -R_PPC64_PLTGOT16_LO_DS = 66 # macro -R_PPC64_TLS = 67 # macro -R_PPC64_DTPMOD64 = 68 # macro -R_PPC64_TPREL16 = 69 # macro -R_PPC64_TPREL16_LO = 70 # macro -R_PPC64_TPREL16_HI = 71 # macro -R_PPC64_TPREL16_HA = 72 # macro -R_PPC64_TPREL64 = 73 # macro -R_PPC64_DTPREL16 = 74 # macro -R_PPC64_DTPREL16_LO = 75 # macro -R_PPC64_DTPREL16_HI = 76 # macro -R_PPC64_DTPREL16_HA = 77 # macro -R_PPC64_DTPREL64 = 78 # macro -R_PPC64_GOT_TLSGD16 = 79 # macro -R_PPC64_GOT_TLSGD16_LO = 80 # macro -R_PPC64_GOT_TLSGD16_HI = 81 # macro -R_PPC64_GOT_TLSGD16_HA = 82 # macro -R_PPC64_GOT_TLSLD16 = 83 # macro -R_PPC64_GOT_TLSLD16_LO = 84 # macro -R_PPC64_GOT_TLSLD16_HI = 85 # macro -R_PPC64_GOT_TLSLD16_HA = 86 # macro -R_PPC64_GOT_TPREL16_DS = 87 # macro -R_PPC64_GOT_TPREL16_LO_DS = 88 # macro -R_PPC64_GOT_TPREL16_HI = 89 # macro -R_PPC64_GOT_TPREL16_HA = 90 # macro -R_PPC64_GOT_DTPREL16_DS = 91 # macro -R_PPC64_GOT_DTPREL16_LO_DS = 92 # macro -R_PPC64_GOT_DTPREL16_HI = 93 # macro -R_PPC64_GOT_DTPREL16_HA = 94 # macro -R_PPC64_TPREL16_DS = 95 # macro -R_PPC64_TPREL16_LO_DS = 96 # macro -R_PPC64_TPREL16_HIGHER = 97 # macro -R_PPC64_TPREL16_HIGHERA = 98 # macro -R_PPC64_TPREL16_HIGHEST = 99 # macro -R_PPC64_TPREL16_HIGHESTA = 100 # macro -R_PPC64_DTPREL16_DS = 101 # macro -R_PPC64_DTPREL16_LO_DS = 102 # macro -R_PPC64_DTPREL16_HIGHER = 103 # macro -R_PPC64_DTPREL16_HIGHERA = 104 # macro -R_PPC64_DTPREL16_HIGHEST = 105 # macro -R_PPC64_DTPREL16_HIGHESTA = 106 # macro -R_PPC64_TLSGD = 107 # macro -R_PPC64_TLSLD = 108 # macro -R_PPC64_TOCSAVE = 109 # macro -R_PPC64_ADDR16_HIGH = 110 # macro -R_PPC64_ADDR16_HIGHA = 111 # macro -R_PPC64_TPREL16_HIGH = 112 # macro -R_PPC64_TPREL16_HIGHA = 113 # macro -R_PPC64_DTPREL16_HIGH = 114 # macro -R_PPC64_DTPREL16_HIGHA = 115 # macro -R_PPC64_JMP_IREL = 247 # macro -R_PPC64_IRELATIVE = 248 # macro -R_PPC64_REL16 = 249 # macro -R_PPC64_REL16_LO = 250 # macro -R_PPC64_REL16_HI = 251 # macro -R_PPC64_REL16_HA = 252 # macro -EF_PPC64_ABI = 3 # macro -DT_PPC64_GLINK = (0x70000000+0) # macro -DT_PPC64_OPD = (0x70000000+1) # macro -DT_PPC64_OPDSZ = (0x70000000+2) # macro -DT_PPC64_OPT = (0x70000000+3) # macro -DT_PPC64_NUM = 4 # macro -PPC64_OPT_TLS = 1 # macro -PPC64_OPT_MULTI_TOC = 2 # macro -PPC64_OPT_LOCALENTRY = 4 # macro -STO_PPC64_LOCAL_BIT = 5 # macro -STO_PPC64_LOCAL_MASK = (7<<5) # macro -def PPC64_LOCAL_ENTRY_OFFSET(other): # macro - return (((1<<(((other)&(7<<5))>>5))>>2)<<2) -EF_ARM_RELEXEC = 0x01 # macro -EF_ARM_HASENTRY = 0x02 # macro -EF_ARM_INTERWORK = 0x04 # macro -EF_ARM_APCS_26 = 0x08 # macro -EF_ARM_APCS_FLOAT = 0x10 # macro -EF_ARM_PIC = 0x20 # macro -EF_ARM_ALIGN8 = 0x40 # macro -EF_ARM_NEW_ABI = 0x80 # macro -EF_ARM_OLD_ABI = 0x100 # macro -EF_ARM_SOFT_FLOAT = 0x200 # macro -EF_ARM_VFP_FLOAT = 0x400 # macro -EF_ARM_MAVERICK_FLOAT = 0x800 # macro -EF_ARM_ABI_FLOAT_SOFT = 0x200 # macro -EF_ARM_ABI_FLOAT_HARD = 0x400 # macro -EF_ARM_SYMSARESORTED = 0x04 # macro -EF_ARM_DYNSYMSUSESEGIDX = 0x08 # macro -EF_ARM_MAPSYMSFIRST = 0x10 # macro -EF_ARM_EABIMASK = 0XFF000000 # macro -EF_ARM_BE8 = 0x00800000 # macro -EF_ARM_LE8 = 0x00400000 # macro -def EF_ARM_EABI_VERSION(flags): # macro - return ((flags)&0XFF000000) -EF_ARM_EABI_UNKNOWN = 0x00000000 # macro -EF_ARM_EABI_VER1 = 0x01000000 # macro -EF_ARM_EABI_VER2 = 0x02000000 # macro -EF_ARM_EABI_VER3 = 0x03000000 # macro -EF_ARM_EABI_VER4 = 0x04000000 # macro -EF_ARM_EABI_VER5 = 0x05000000 # macro -STT_ARM_TFUNC = 13 # macro -STT_ARM_16BIT = 15 # macro -SHF_ARM_ENTRYSECT = 0x10000000 # macro -SHF_ARM_COMDEF = 0x80000000 # macro -PF_ARM_SB = 0x10000000 # macro -PF_ARM_PI = 0x20000000 # macro -PF_ARM_ABS = 0x40000000 # macro -PT_ARM_EXIDX = (0x70000000+1) # macro -SHT_ARM_EXIDX = (0x70000000+1) # macro -SHT_ARM_PREEMPTMAP = (0x70000000+2) # macro -SHT_ARM_ATTRIBUTES = (0x70000000+3) # macro -R_AARCH64_NONE = 0 # macro -R_AARCH64_P32_ABS32 = 1 # macro -R_AARCH64_P32_COPY = 180 # macro -R_AARCH64_P32_GLOB_DAT = 181 # macro -R_AARCH64_P32_JUMP_SLOT = 182 # macro -R_AARCH64_P32_RELATIVE = 183 # macro -R_AARCH64_P32_TLS_DTPMOD = 184 # macro -R_AARCH64_P32_TLS_DTPREL = 185 # macro -R_AARCH64_P32_TLS_TPREL = 186 # macro -R_AARCH64_P32_TLSDESC = 187 # macro -R_AARCH64_P32_IRELATIVE = 188 # macro -R_AARCH64_ABS64 = 257 # macro -R_AARCH64_ABS32 = 258 # macro -R_AARCH64_ABS16 = 259 # macro -R_AARCH64_PREL64 = 260 # macro -R_AARCH64_PREL32 = 261 # macro -R_AARCH64_PREL16 = 262 # macro -R_AARCH64_MOVW_UABS_G0 = 263 # macro -R_AARCH64_MOVW_UABS_G0_NC = 264 # macro -R_AARCH64_MOVW_UABS_G1 = 265 # macro -R_AARCH64_MOVW_UABS_G1_NC = 266 # macro -R_AARCH64_MOVW_UABS_G2 = 267 # macro -R_AARCH64_MOVW_UABS_G2_NC = 268 # macro -R_AARCH64_MOVW_UABS_G3 = 269 # macro -R_AARCH64_MOVW_SABS_G0 = 270 # macro -R_AARCH64_MOVW_SABS_G1 = 271 # macro -R_AARCH64_MOVW_SABS_G2 = 272 # macro -R_AARCH64_LD_PREL_LO19 = 273 # macro -R_AARCH64_ADR_PREL_LO21 = 274 # macro -R_AARCH64_ADR_PREL_PG_HI21 = 275 # macro -R_AARCH64_ADR_PREL_PG_HI21_NC = 276 # macro -R_AARCH64_ADD_ABS_LO12_NC = 277 # macro -R_AARCH64_LDST8_ABS_LO12_NC = 278 # macro -R_AARCH64_TSTBR14 = 279 # macro -R_AARCH64_CONDBR19 = 280 # macro -R_AARCH64_JUMP26 = 282 # macro -R_AARCH64_CALL26 = 283 # macro -R_AARCH64_LDST16_ABS_LO12_NC = 284 # macro -R_AARCH64_LDST32_ABS_LO12_NC = 285 # macro -R_AARCH64_LDST64_ABS_LO12_NC = 286 # macro -R_AARCH64_MOVW_PREL_G0 = 287 # macro -R_AARCH64_MOVW_PREL_G0_NC = 288 # macro -R_AARCH64_MOVW_PREL_G1 = 289 # macro -R_AARCH64_MOVW_PREL_G1_NC = 290 # macro -R_AARCH64_MOVW_PREL_G2 = 291 # macro -R_AARCH64_MOVW_PREL_G2_NC = 292 # macro -R_AARCH64_MOVW_PREL_G3 = 293 # macro -R_AARCH64_LDST128_ABS_LO12_NC = 299 # macro -R_AARCH64_MOVW_GOTOFF_G0 = 300 # macro -R_AARCH64_MOVW_GOTOFF_G0_NC = 301 # macro -R_AARCH64_MOVW_GOTOFF_G1 = 302 # macro -R_AARCH64_MOVW_GOTOFF_G1_NC = 303 # macro -R_AARCH64_MOVW_GOTOFF_G2 = 304 # macro -R_AARCH64_MOVW_GOTOFF_G2_NC = 305 # macro -R_AARCH64_MOVW_GOTOFF_G3 = 306 # macro -R_AARCH64_GOTREL64 = 307 # macro -R_AARCH64_GOTREL32 = 308 # macro -R_AARCH64_GOT_LD_PREL19 = 309 # macro -R_AARCH64_LD64_GOTOFF_LO15 = 310 # macro -R_AARCH64_ADR_GOT_PAGE = 311 # macro -R_AARCH64_LD64_GOT_LO12_NC = 312 # macro -R_AARCH64_LD64_GOTPAGE_LO15 = 313 # macro -R_AARCH64_TLSGD_ADR_PREL21 = 512 # macro -R_AARCH64_TLSGD_ADR_PAGE21 = 513 # macro -R_AARCH64_TLSGD_ADD_LO12_NC = 514 # macro -R_AARCH64_TLSGD_MOVW_G1 = 515 # macro -R_AARCH64_TLSGD_MOVW_G0_NC = 516 # macro -R_AARCH64_TLSLD_ADR_PREL21 = 517 # macro -R_AARCH64_TLSLD_ADR_PAGE21 = 518 # macro -R_AARCH64_TLSLD_ADD_LO12_NC = 519 # macro -R_AARCH64_TLSLD_MOVW_G1 = 520 # macro -R_AARCH64_TLSLD_MOVW_G0_NC = 521 # macro -R_AARCH64_TLSLD_LD_PREL19 = 522 # macro -R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523 # macro -R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524 # macro -R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525 # macro -R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526 # macro -R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527 # macro -R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528 # macro -R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529 # macro -R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530 # macro -R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531 # macro -R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532 # macro -R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533 # macro -R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534 # macro -R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535 # macro -R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536 # macro -R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537 # macro -R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538 # macro -R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539 # macro -R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540 # macro -R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541 # macro -R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542 # macro -R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543 # macro -R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544 # macro -R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545 # macro -R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546 # macro -R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547 # macro -R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548 # macro -R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549 # macro -R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550 # macro -R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551 # macro -R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552 # macro -R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553 # macro -R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554 # macro -R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555 # macro -R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556 # macro -R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557 # macro -R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558 # macro -R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559 # macro -R_AARCH64_TLSDESC_LD_PREL19 = 560 # macro -R_AARCH64_TLSDESC_ADR_PREL21 = 561 # macro -R_AARCH64_TLSDESC_ADR_PAGE21 = 562 # macro -R_AARCH64_TLSDESC_LD64_LO12 = 563 # macro -R_AARCH64_TLSDESC_ADD_LO12 = 564 # macro -R_AARCH64_TLSDESC_OFF_G1 = 565 # macro -R_AARCH64_TLSDESC_OFF_G0_NC = 566 # macro -R_AARCH64_TLSDESC_LDR = 567 # macro -R_AARCH64_TLSDESC_ADD = 568 # macro -R_AARCH64_TLSDESC_CALL = 569 # macro -R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570 # macro -R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571 # macro -R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572 # macro -R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573 # macro -R_AARCH64_COPY = 1024 # macro -R_AARCH64_GLOB_DAT = 1025 # macro -R_AARCH64_JUMP_SLOT = 1026 # macro -R_AARCH64_RELATIVE = 1027 # macro -R_AARCH64_TLS_DTPMOD = 1028 # macro -R_AARCH64_TLS_DTPREL = 1029 # macro -R_AARCH64_TLS_TPREL = 1030 # macro -R_AARCH64_TLSDESC = 1031 # macro -R_AARCH64_IRELATIVE = 1032 # macro -PT_AARCH64_MEMTAG_MTE = (0x70000000+2) # macro -DT_AARCH64_BTI_PLT = (0x70000000+1) # macro -DT_AARCH64_PAC_PLT = (0x70000000+3) # macro -DT_AARCH64_VARIANT_PCS = (0x70000000+5) # macro -DT_AARCH64_NUM = 6 # macro -STO_AARCH64_VARIANT_PCS = 0x80 # macro -R_ARM_NONE = 0 # macro -R_ARM_PC24 = 1 # macro -R_ARM_ABS32 = 2 # macro -R_ARM_REL32 = 3 # macro -R_ARM_PC13 = 4 # macro -R_ARM_ABS16 = 5 # macro -R_ARM_ABS12 = 6 # macro -R_ARM_THM_ABS5 = 7 # macro -R_ARM_ABS8 = 8 # macro -R_ARM_SBREL32 = 9 # macro -R_ARM_THM_PC22 = 10 # macro -R_ARM_THM_PC8 = 11 # macro -R_ARM_AMP_VCALL9 = 12 # macro -R_ARM_SWI24 = 13 # macro -R_ARM_TLS_DESC = 13 # macro -R_ARM_THM_SWI8 = 14 # macro -R_ARM_XPC25 = 15 # macro -R_ARM_THM_XPC22 = 16 # macro -R_ARM_TLS_DTPMOD32 = 17 # macro -R_ARM_TLS_DTPOFF32 = 18 # macro -R_ARM_TLS_TPOFF32 = 19 # macro -R_ARM_COPY = 20 # macro -R_ARM_GLOB_DAT = 21 # macro -R_ARM_JUMP_SLOT = 22 # macro -R_ARM_RELATIVE = 23 # macro -R_ARM_GOTOFF = 24 # macro -R_ARM_GOTPC = 25 # macro -R_ARM_GOT32 = 26 # macro -R_ARM_PLT32 = 27 # macro -R_ARM_CALL = 28 # macro -R_ARM_JUMP24 = 29 # macro -R_ARM_THM_JUMP24 = 30 # macro -R_ARM_BASE_ABS = 31 # macro -R_ARM_ALU_PCREL_7_0 = 32 # macro -R_ARM_ALU_PCREL_15_8 = 33 # macro -R_ARM_ALU_PCREL_23_15 = 34 # macro -R_ARM_LDR_SBREL_11_0 = 35 # macro -R_ARM_ALU_SBREL_19_12 = 36 # macro -R_ARM_ALU_SBREL_27_20 = 37 # macro -R_ARM_TARGET1 = 38 # macro -R_ARM_SBREL31 = 39 # macro -R_ARM_V4BX = 40 # macro -R_ARM_TARGET2 = 41 # macro -R_ARM_PREL31 = 42 # macro -R_ARM_MOVW_ABS_NC = 43 # macro -R_ARM_MOVT_ABS = 44 # macro -R_ARM_MOVW_PREL_NC = 45 # macro -R_ARM_MOVT_PREL = 46 # macro -R_ARM_THM_MOVW_ABS_NC = 47 # macro -R_ARM_THM_MOVT_ABS = 48 # macro -R_ARM_THM_MOVW_PREL_NC = 49 # macro -R_ARM_THM_MOVT_PREL = 50 # macro -R_ARM_THM_JUMP19 = 51 # macro -R_ARM_THM_JUMP6 = 52 # macro -R_ARM_THM_ALU_PREL_11_0 = 53 # macro -R_ARM_THM_PC12 = 54 # macro -R_ARM_ABS32_NOI = 55 # macro -R_ARM_REL32_NOI = 56 # macro -R_ARM_ALU_PC_G0_NC = 57 # macro -R_ARM_ALU_PC_G0 = 58 # macro -R_ARM_ALU_PC_G1_NC = 59 # macro -R_ARM_ALU_PC_G1 = 60 # macro -R_ARM_ALU_PC_G2 = 61 # macro -R_ARM_LDR_PC_G1 = 62 # macro -R_ARM_LDR_PC_G2 = 63 # macro -R_ARM_LDRS_PC_G0 = 64 # macro -R_ARM_LDRS_PC_G1 = 65 # macro -R_ARM_LDRS_PC_G2 = 66 # macro -R_ARM_LDC_PC_G0 = 67 # macro -R_ARM_LDC_PC_G1 = 68 # macro -R_ARM_LDC_PC_G2 = 69 # macro -R_ARM_ALU_SB_G0_NC = 70 # macro -R_ARM_ALU_SB_G0 = 71 # macro -R_ARM_ALU_SB_G1_NC = 72 # macro -R_ARM_ALU_SB_G1 = 73 # macro -R_ARM_ALU_SB_G2 = 74 # macro -R_ARM_LDR_SB_G0 = 75 # macro -R_ARM_LDR_SB_G1 = 76 # macro -R_ARM_LDR_SB_G2 = 77 # macro -R_ARM_LDRS_SB_G0 = 78 # macro -R_ARM_LDRS_SB_G1 = 79 # macro -R_ARM_LDRS_SB_G2 = 80 # macro -R_ARM_LDC_SB_G0 = 81 # macro -R_ARM_LDC_SB_G1 = 82 # macro -R_ARM_LDC_SB_G2 = 83 # macro -R_ARM_MOVW_BREL_NC = 84 # macro -R_ARM_MOVT_BREL = 85 # macro -R_ARM_MOVW_BREL = 86 # macro -R_ARM_THM_MOVW_BREL_NC = 87 # macro -R_ARM_THM_MOVT_BREL = 88 # macro -R_ARM_THM_MOVW_BREL = 89 # macro -R_ARM_TLS_GOTDESC = 90 # macro -R_ARM_TLS_CALL = 91 # macro -R_ARM_TLS_DESCSEQ = 92 # macro -R_ARM_THM_TLS_CALL = 93 # macro -R_ARM_PLT32_ABS = 94 # macro -R_ARM_GOT_ABS = 95 # macro -R_ARM_GOT_PREL = 96 # macro -R_ARM_GOT_BREL12 = 97 # macro -R_ARM_GOTOFF12 = 98 # macro -R_ARM_GOTRELAX = 99 # macro -R_ARM_GNU_VTENTRY = 100 # macro -R_ARM_GNU_VTINHERIT = 101 # macro -R_ARM_THM_PC11 = 102 # macro -R_ARM_THM_PC9 = 103 # macro -R_ARM_TLS_GD32 = 104 # macro -R_ARM_TLS_LDM32 = 105 # macro -R_ARM_TLS_LDO32 = 106 # macro -R_ARM_TLS_IE32 = 107 # macro -R_ARM_TLS_LE32 = 108 # macro -R_ARM_TLS_LDO12 = 109 # macro -R_ARM_TLS_LE12 = 110 # macro -R_ARM_TLS_IE12GP = 111 # macro -R_ARM_ME_TOO = 128 # macro -R_ARM_THM_TLS_DESCSEQ = 129 # macro -R_ARM_THM_TLS_DESCSEQ16 = 129 # macro -R_ARM_THM_TLS_DESCSEQ32 = 130 # macro -R_ARM_THM_GOT_BREL12 = 131 # macro -R_ARM_IRELATIVE = 160 # macro -R_ARM_RXPC25 = 249 # macro -R_ARM_RSBREL32 = 250 # macro -R_ARM_THM_RPC22 = 251 # macro -R_ARM_RREL32 = 252 # macro -R_ARM_RABS22 = 253 # macro -R_ARM_RPC24 = 254 # macro -R_ARM_RBASE = 255 # macro -R_ARM_NUM = 256 # macro -R_CKCORE_NONE = 0 # macro -R_CKCORE_ADDR32 = 1 # macro -R_CKCORE_PCRELIMM8BY4 = 2 # macro -R_CKCORE_PCRELIMM11BY2 = 3 # macro -R_CKCORE_PCREL32 = 5 # macro -R_CKCORE_PCRELJSR_IMM11BY2 = 6 # macro -R_CKCORE_RELATIVE = 9 # macro -R_CKCORE_COPY = 10 # macro -R_CKCORE_GLOB_DAT = 11 # macro -R_CKCORE_JUMP_SLOT = 12 # macro -R_CKCORE_GOTOFF = 13 # macro -R_CKCORE_GOTPC = 14 # macro -R_CKCORE_GOT32 = 15 # macro -R_CKCORE_PLT32 = 16 # macro -R_CKCORE_ADDRGOT = 17 # macro -R_CKCORE_ADDRPLT = 18 # macro -R_CKCORE_PCREL_IMM26BY2 = 19 # macro -R_CKCORE_PCREL_IMM16BY2 = 20 # macro -R_CKCORE_PCREL_IMM16BY4 = 21 # macro -R_CKCORE_PCREL_IMM10BY2 = 22 # macro -R_CKCORE_PCREL_IMM10BY4 = 23 # macro -R_CKCORE_ADDR_HI16 = 24 # macro -R_CKCORE_ADDR_LO16 = 25 # macro -R_CKCORE_GOTPC_HI16 = 26 # macro -R_CKCORE_GOTPC_LO16 = 27 # macro -R_CKCORE_GOTOFF_HI16 = 28 # macro -R_CKCORE_GOTOFF_LO16 = 29 # macro -R_CKCORE_GOT12 = 30 # macro -R_CKCORE_GOT_HI16 = 31 # macro -R_CKCORE_GOT_LO16 = 32 # macro -R_CKCORE_PLT12 = 33 # macro -R_CKCORE_PLT_HI16 = 34 # macro -R_CKCORE_PLT_LO16 = 35 # macro -R_CKCORE_ADDRGOT_HI16 = 36 # macro -R_CKCORE_ADDRGOT_LO16 = 37 # macro -R_CKCORE_ADDRPLT_HI16 = 38 # macro -R_CKCORE_ADDRPLT_LO16 = 39 # macro -R_CKCORE_PCREL_JSR_IMM26BY2 = 40 # macro -R_CKCORE_TOFFSET_LO16 = 41 # macro -R_CKCORE_DOFFSET_LO16 = 42 # macro -R_CKCORE_PCREL_IMM18BY2 = 43 # macro -R_CKCORE_DOFFSET_IMM18 = 44 # macro -R_CKCORE_DOFFSET_IMM18BY2 = 45 # macro -R_CKCORE_DOFFSET_IMM18BY4 = 46 # macro -R_CKCORE_GOT_IMM18BY4 = 48 # macro -R_CKCORE_PLT_IMM18BY4 = 49 # macro -R_CKCORE_PCREL_IMM7BY4 = 50 # macro -R_CKCORE_TLS_LE32 = 51 # macro -R_CKCORE_TLS_IE32 = 52 # macro -R_CKCORE_TLS_GD32 = 53 # macro -R_CKCORE_TLS_LDM32 = 54 # macro -R_CKCORE_TLS_LDO32 = 55 # macro -R_CKCORE_TLS_DTPMOD32 = 56 # macro -R_CKCORE_TLS_DTPOFF32 = 57 # macro -R_CKCORE_TLS_TPOFF32 = 58 # macro -EF_CSKY_ABIMASK = 0XF0000000 # macro -EF_CSKY_OTHER = 0X0FFF0000 # macro -EF_CSKY_PROCESSOR = 0X0000FFFF # macro -EF_CSKY_ABIV1 = 0X10000000 # macro -EF_CSKY_ABIV2 = 0X20000000 # macro -SHT_CSKY_ATTRIBUTES = (0x70000000+1) # macro -EF_IA_64_MASKOS = 0x0000000f # macro -EF_IA_64_ABI64 = 0x00000010 # macro -EF_IA_64_ARCH = 0xff000000 # macro -PT_IA_64_ARCHEXT = (0x70000000+0) # macro -PT_IA_64_UNWIND = (0x70000000+1) # macro -PT_IA_64_HP_OPT_ANOT = (0x60000000+0x12) # macro -PT_IA_64_HP_HSL_ANOT = (0x60000000+0x13) # macro -PT_IA_64_HP_STACK = (0x60000000+0x14) # macro -PF_IA_64_NORECOV = 0x80000000 # macro -SHT_IA_64_EXT = (0x70000000+0) # macro -SHT_IA_64_UNWIND = (0x70000000+1) # macro -SHF_IA_64_SHORT = 0x10000000 # macro -SHF_IA_64_NORECOV = 0x20000000 # macro -DT_IA_64_PLT_RESERVE = (0x70000000+0) # macro -DT_IA_64_NUM = 1 # macro -R_IA64_NONE = 0x00 # macro -R_IA64_IMM14 = 0x21 # macro -R_IA64_IMM22 = 0x22 # macro -R_IA64_IMM64 = 0x23 # macro -R_IA64_DIR32MSB = 0x24 # macro -R_IA64_DIR32LSB = 0x25 # macro -R_IA64_DIR64MSB = 0x26 # macro -R_IA64_DIR64LSB = 0x27 # macro -R_IA64_GPREL22 = 0x2a # macro -R_IA64_GPREL64I = 0x2b # macro -R_IA64_GPREL32MSB = 0x2c # macro -R_IA64_GPREL32LSB = 0x2d # macro -R_IA64_GPREL64MSB = 0x2e # macro -R_IA64_GPREL64LSB = 0x2f # macro -R_IA64_LTOFF22 = 0x32 # macro -R_IA64_LTOFF64I = 0x33 # macro -R_IA64_PLTOFF22 = 0x3a # macro -R_IA64_PLTOFF64I = 0x3b # macro -R_IA64_PLTOFF64MSB = 0x3e # macro -R_IA64_PLTOFF64LSB = 0x3f # macro -R_IA64_FPTR64I = 0x43 # macro -R_IA64_FPTR32MSB = 0x44 # macro -R_IA64_FPTR32LSB = 0x45 # macro -R_IA64_FPTR64MSB = 0x46 # macro -R_IA64_FPTR64LSB = 0x47 # macro -R_IA64_PCREL60B = 0x48 # macro -R_IA64_PCREL21B = 0x49 # macro -R_IA64_PCREL21M = 0x4a # macro -R_IA64_PCREL21F = 0x4b # macro -R_IA64_PCREL32MSB = 0x4c # macro -R_IA64_PCREL32LSB = 0x4d # macro -R_IA64_PCREL64MSB = 0x4e # macro -R_IA64_PCREL64LSB = 0x4f # macro -R_IA64_LTOFF_FPTR22 = 0x52 # macro -R_IA64_LTOFF_FPTR64I = 0x53 # macro -R_IA64_LTOFF_FPTR32MSB = 0x54 # macro -R_IA64_LTOFF_FPTR32LSB = 0x55 # macro -R_IA64_LTOFF_FPTR64MSB = 0x56 # macro -R_IA64_LTOFF_FPTR64LSB = 0x57 # macro -R_IA64_SEGREL32MSB = 0x5c # macro -R_IA64_SEGREL32LSB = 0x5d # macro -R_IA64_SEGREL64MSB = 0x5e # macro -R_IA64_SEGREL64LSB = 0x5f # macro -R_IA64_SECREL32MSB = 0x64 # macro -R_IA64_SECREL32LSB = 0x65 # macro -R_IA64_SECREL64MSB = 0x66 # macro -R_IA64_SECREL64LSB = 0x67 # macro -R_IA64_REL32MSB = 0x6c # macro -R_IA64_REL32LSB = 0x6d # macro -R_IA64_REL64MSB = 0x6e # macro -R_IA64_REL64LSB = 0x6f # macro -R_IA64_LTV32MSB = 0x74 # macro -R_IA64_LTV32LSB = 0x75 # macro -R_IA64_LTV64MSB = 0x76 # macro -R_IA64_LTV64LSB = 0x77 # macro -R_IA64_PCREL21BI = 0x79 # macro -R_IA64_PCREL22 = 0x7a # macro -R_IA64_PCREL64I = 0x7b # macro -R_IA64_IPLTMSB = 0x80 # macro -R_IA64_IPLTLSB = 0x81 # macro -R_IA64_COPY = 0x84 # macro -R_IA64_SUB = 0x85 # macro -R_IA64_LTOFF22X = 0x86 # macro -R_IA64_LDXMOV = 0x87 # macro -R_IA64_TPREL14 = 0x91 # macro -R_IA64_TPREL22 = 0x92 # macro -R_IA64_TPREL64I = 0x93 # macro -R_IA64_TPREL64MSB = 0x96 # macro -R_IA64_TPREL64LSB = 0x97 # macro -R_IA64_LTOFF_TPREL22 = 0x9a # macro -R_IA64_DTPMOD64MSB = 0xa6 # macro -R_IA64_DTPMOD64LSB = 0xa7 # macro -R_IA64_LTOFF_DTPMOD22 = 0xaa # macro -R_IA64_DTPREL14 = 0xb1 # macro -R_IA64_DTPREL22 = 0xb2 # macro -R_IA64_DTPREL64I = 0xb3 # macro -R_IA64_DTPREL32MSB = 0xb4 # macro -R_IA64_DTPREL32LSB = 0xb5 # macro -R_IA64_DTPREL64MSB = 0xb6 # macro -R_IA64_DTPREL64LSB = 0xb7 # macro -R_IA64_LTOFF_DTPREL22 = 0xba # macro -EF_SH_MACH_MASK = 0x1f # macro -EF_SH_UNKNOWN = 0x0 # macro -EF_SH1 = 0x1 # macro -EF_SH2 = 0x2 # macro -EF_SH3 = 0x3 # macro -EF_SH_DSP = 0x4 # macro -EF_SH3_DSP = 0x5 # macro -EF_SH4AL_DSP = 0x6 # macro -EF_SH3E = 0x8 # macro -EF_SH4 = 0x9 # macro -EF_SH2E = 0xb # macro -EF_SH4A = 0xc # macro -EF_SH2A = 0xd # macro -EF_SH4_NOFPU = 0x10 # macro -EF_SH4A_NOFPU = 0x11 # macro -EF_SH4_NOMMU_NOFPU = 0x12 # macro -EF_SH2A_NOFPU = 0x13 # macro -EF_SH3_NOMMU = 0x14 # macro -EF_SH2A_SH4_NOFPU = 0x15 # macro -EF_SH2A_SH3_NOFPU = 0x16 # macro -EF_SH2A_SH4 = 0x17 # macro -EF_SH2A_SH3E = 0x18 # macro -R_SH_NONE = 0 # macro -R_SH_DIR32 = 1 # macro -R_SH_REL32 = 2 # macro -R_SH_DIR8WPN = 3 # macro -R_SH_IND12W = 4 # macro -R_SH_DIR8WPL = 5 # macro -R_SH_DIR8WPZ = 6 # macro -R_SH_DIR8BP = 7 # macro -R_SH_DIR8W = 8 # macro -R_SH_DIR8L = 9 # macro -R_SH_SWITCH16 = 25 # macro -R_SH_SWITCH32 = 26 # macro -R_SH_USES = 27 # macro -R_SH_COUNT = 28 # macro -R_SH_ALIGN = 29 # macro -R_SH_CODE = 30 # macro -R_SH_DATA = 31 # macro -R_SH_LABEL = 32 # macro -R_SH_SWITCH8 = 33 # macro -R_SH_GNU_VTINHERIT = 34 # macro -R_SH_GNU_VTENTRY = 35 # macro -R_SH_TLS_GD_32 = 144 # macro -R_SH_TLS_LD_32 = 145 # macro -R_SH_TLS_LDO_32 = 146 # macro -R_SH_TLS_IE_32 = 147 # macro -R_SH_TLS_LE_32 = 148 # macro -R_SH_TLS_DTPMOD32 = 149 # macro -R_SH_TLS_DTPOFF32 = 150 # macro -R_SH_TLS_TPOFF32 = 151 # macro -R_SH_GOT32 = 160 # macro -R_SH_PLT32 = 161 # macro -R_SH_COPY = 162 # macro -R_SH_GLOB_DAT = 163 # macro -R_SH_JMP_SLOT = 164 # macro -R_SH_RELATIVE = 165 # macro -R_SH_GOTOFF = 166 # macro -R_SH_GOTPC = 167 # macro -R_SH_NUM = 256 # macro -EF_S390_HIGH_GPRS = 0x00000001 # macro -R_390_NONE = 0 # macro -R_390_8 = 1 # macro -R_390_12 = 2 # macro -R_390_16 = 3 # macro -R_390_32 = 4 # macro -R_390_PC32 = 5 # macro -R_390_GOT12 = 6 # macro -R_390_GOT32 = 7 # macro -R_390_PLT32 = 8 # macro -R_390_COPY = 9 # macro -R_390_GLOB_DAT = 10 # macro -R_390_JMP_SLOT = 11 # macro -R_390_RELATIVE = 12 # macro -R_390_GOTOFF32 = 13 # macro -R_390_GOTPC = 14 # macro -R_390_GOT16 = 15 # macro -R_390_PC16 = 16 # macro -R_390_PC16DBL = 17 # macro -R_390_PLT16DBL = 18 # macro -R_390_PC32DBL = 19 # macro -R_390_PLT32DBL = 20 # macro -R_390_GOTPCDBL = 21 # macro -R_390_64 = 22 # macro -R_390_PC64 = 23 # macro -R_390_GOT64 = 24 # macro -R_390_PLT64 = 25 # macro -R_390_GOTENT = 26 # macro -R_390_GOTOFF16 = 27 # macro -R_390_GOTOFF64 = 28 # macro -R_390_GOTPLT12 = 29 # macro -R_390_GOTPLT16 = 30 # macro -R_390_GOTPLT32 = 31 # macro -R_390_GOTPLT64 = 32 # macro -R_390_GOTPLTENT = 33 # macro -R_390_PLTOFF16 = 34 # macro -R_390_PLTOFF32 = 35 # macro -R_390_PLTOFF64 = 36 # macro -R_390_TLS_LOAD = 37 # macro -R_390_TLS_GDCALL = 38 # macro -R_390_TLS_LDCALL = 39 # macro -R_390_TLS_GD32 = 40 # macro -R_390_TLS_GD64 = 41 # macro -R_390_TLS_GOTIE12 = 42 # macro -R_390_TLS_GOTIE32 = 43 # macro -R_390_TLS_GOTIE64 = 44 # macro -R_390_TLS_LDM32 = 45 # macro -R_390_TLS_LDM64 = 46 # macro -R_390_TLS_IE32 = 47 # macro -R_390_TLS_IE64 = 48 # macro -R_390_TLS_IEENT = 49 # macro -R_390_TLS_LE32 = 50 # macro -R_390_TLS_LE64 = 51 # macro -R_390_TLS_LDO32 = 52 # macro -R_390_TLS_LDO64 = 53 # macro -R_390_TLS_DTPMOD = 54 # macro -R_390_TLS_DTPOFF = 55 # macro -R_390_TLS_TPOFF = 56 # macro -R_390_20 = 57 # macro -R_390_GOT20 = 58 # macro -R_390_GOTPLT20 = 59 # macro -R_390_TLS_GOTIE20 = 60 # macro -R_390_IRELATIVE = 61 # macro -R_390_NUM = 62 # macro -R_CRIS_NONE = 0 # macro -R_CRIS_8 = 1 # macro -R_CRIS_16 = 2 # macro -R_CRIS_32 = 3 # macro -R_CRIS_8_PCREL = 4 # macro -R_CRIS_16_PCREL = 5 # macro -R_CRIS_32_PCREL = 6 # macro -R_CRIS_GNU_VTINHERIT = 7 # macro -R_CRIS_GNU_VTENTRY = 8 # macro -R_CRIS_COPY = 9 # macro -R_CRIS_GLOB_DAT = 10 # macro -R_CRIS_JUMP_SLOT = 11 # macro -R_CRIS_RELATIVE = 12 # macro -R_CRIS_16_GOT = 13 # macro -R_CRIS_32_GOT = 14 # macro -R_CRIS_16_GOTPLT = 15 # macro -R_CRIS_32_GOTPLT = 16 # macro -R_CRIS_32_GOTREL = 17 # macro -R_CRIS_32_PLT_GOTREL = 18 # macro -R_CRIS_32_PLT_PCREL = 19 # macro -R_CRIS_NUM = 20 # macro -R_X86_64_NONE = 0 # macro -R_X86_64_64 = 1 # macro -R_X86_64_PC32 = 2 # macro -R_X86_64_GOT32 = 3 # macro -R_X86_64_PLT32 = 4 # macro -R_X86_64_COPY = 5 # macro -R_X86_64_GLOB_DAT = 6 # macro -R_X86_64_JUMP_SLOT = 7 # macro -R_X86_64_RELATIVE = 8 # macro -R_X86_64_GOTPCREL = 9 # macro -R_X86_64_32 = 10 # macro -R_X86_64_32S = 11 # macro -R_X86_64_16 = 12 # macro -R_X86_64_PC16 = 13 # macro -R_X86_64_8 = 14 # macro -R_X86_64_PC8 = 15 # macro -R_X86_64_DTPMOD64 = 16 # macro -R_X86_64_DTPOFF64 = 17 # macro -R_X86_64_TPOFF64 = 18 # macro -R_X86_64_TLSGD = 19 # macro -R_X86_64_TLSLD = 20 # macro -R_X86_64_DTPOFF32 = 21 # macro -R_X86_64_GOTTPOFF = 22 # macro -R_X86_64_TPOFF32 = 23 # macro -R_X86_64_PC64 = 24 # macro -R_X86_64_GOTOFF64 = 25 # macro -R_X86_64_GOTPC32 = 26 # macro -R_X86_64_GOT64 = 27 # macro -R_X86_64_GOTPCREL64 = 28 # macro -R_X86_64_GOTPC64 = 29 # macro -R_X86_64_GOTPLT64 = 30 # macro -R_X86_64_PLTOFF64 = 31 # macro -R_X86_64_SIZE32 = 32 # macro -R_X86_64_SIZE64 = 33 # macro -R_X86_64_GOTPC32_TLSDESC = 34 # macro -R_X86_64_TLSDESC_CALL = 35 # macro -R_X86_64_TLSDESC = 36 # macro -R_X86_64_IRELATIVE = 37 # macro -R_X86_64_RELATIVE64 = 38 # macro -R_X86_64_GOTPCRELX = 41 # macro -R_X86_64_REX_GOTPCRELX = 42 # macro -R_X86_64_NUM = 43 # macro -SHT_X86_64_UNWIND = 0x70000001 # macro -DT_X86_64_PLT = (0x70000000+0) # macro -DT_X86_64_PLTSZ = (0x70000000+1) # macro -DT_X86_64_PLTENT = (0x70000000+3) # macro -DT_X86_64_NUM = 4 # macro -R_MN10300_NONE = 0 # macro -R_MN10300_32 = 1 # macro -R_MN10300_16 = 2 # macro -R_MN10300_8 = 3 # macro -R_MN10300_PCREL32 = 4 # macro -R_MN10300_PCREL16 = 5 # macro -R_MN10300_PCREL8 = 6 # macro -R_MN10300_GNU_VTINHERIT = 7 # macro -R_MN10300_GNU_VTENTRY = 8 # macro -R_MN10300_24 = 9 # macro -R_MN10300_GOTPC32 = 10 # macro -R_MN10300_GOTPC16 = 11 # macro -R_MN10300_GOTOFF32 = 12 # macro -R_MN10300_GOTOFF24 = 13 # macro -R_MN10300_GOTOFF16 = 14 # macro -R_MN10300_PLT32 = 15 # macro -R_MN10300_PLT16 = 16 # macro -R_MN10300_GOT32 = 17 # macro -R_MN10300_GOT24 = 18 # macro -R_MN10300_GOT16 = 19 # macro -R_MN10300_COPY = 20 # macro -R_MN10300_GLOB_DAT = 21 # macro -R_MN10300_JMP_SLOT = 22 # macro -R_MN10300_RELATIVE = 23 # macro -R_MN10300_TLS_GD = 24 # macro -R_MN10300_TLS_LD = 25 # macro -R_MN10300_TLS_LDO = 26 # macro -R_MN10300_TLS_GOTIE = 27 # macro -R_MN10300_TLS_IE = 28 # macro -R_MN10300_TLS_LE = 29 # macro -R_MN10300_TLS_DTPMOD = 30 # macro -R_MN10300_TLS_DTPOFF = 31 # macro -R_MN10300_TLS_TPOFF = 32 # macro -R_MN10300_SYM_DIFF = 33 # macro -R_MN10300_ALIGN = 34 # macro -R_MN10300_NUM = 35 # macro -R_M32R_NONE = 0 # macro -R_M32R_16 = 1 # macro -R_M32R_32 = 2 # macro -R_M32R_24 = 3 # macro -R_M32R_10_PCREL = 4 # macro -R_M32R_18_PCREL = 5 # macro -R_M32R_26_PCREL = 6 # macro -R_M32R_HI16_ULO = 7 # macro -R_M32R_HI16_SLO = 8 # macro -R_M32R_LO16 = 9 # macro -R_M32R_SDA16 = 10 # macro -R_M32R_GNU_VTINHERIT = 11 # macro -R_M32R_GNU_VTENTRY = 12 # macro -R_M32R_16_RELA = 33 # macro -R_M32R_32_RELA = 34 # macro -R_M32R_24_RELA = 35 # macro -R_M32R_10_PCREL_RELA = 36 # macro -R_M32R_18_PCREL_RELA = 37 # macro -R_M32R_26_PCREL_RELA = 38 # macro -R_M32R_HI16_ULO_RELA = 39 # macro -R_M32R_HI16_SLO_RELA = 40 # macro -R_M32R_LO16_RELA = 41 # macro -R_M32R_SDA16_RELA = 42 # macro -R_M32R_RELA_GNU_VTINHERIT = 43 # macro -R_M32R_RELA_GNU_VTENTRY = 44 # macro -R_M32R_REL32 = 45 # macro -R_M32R_GOT24 = 48 # macro -R_M32R_26_PLTREL = 49 # macro -R_M32R_COPY = 50 # macro -R_M32R_GLOB_DAT = 51 # macro -R_M32R_JMP_SLOT = 52 # macro -R_M32R_RELATIVE = 53 # macro -R_M32R_GOTOFF = 54 # macro -R_M32R_GOTPC24 = 55 # macro -R_M32R_GOT16_HI_ULO = 56 # macro -R_M32R_GOT16_HI_SLO = 57 # macro -R_M32R_GOT16_LO = 58 # macro -R_M32R_GOTPC_HI_ULO = 59 # macro -R_M32R_GOTPC_HI_SLO = 60 # macro -R_M32R_GOTPC_LO = 61 # macro -R_M32R_GOTOFF_HI_ULO = 62 # macro -R_M32R_GOTOFF_HI_SLO = 63 # macro -R_M32R_GOTOFF_LO = 64 # macro -R_M32R_NUM = 256 # macro -R_MICROBLAZE_NONE = 0 # macro -R_MICROBLAZE_32 = 1 # macro -R_MICROBLAZE_32_PCREL = 2 # macro -R_MICROBLAZE_64_PCREL = 3 # macro -R_MICROBLAZE_32_PCREL_LO = 4 # macro -R_MICROBLAZE_64 = 5 # macro -R_MICROBLAZE_32_LO = 6 # macro -R_MICROBLAZE_SRO32 = 7 # macro -R_MICROBLAZE_SRW32 = 8 # macro -R_MICROBLAZE_64_NONE = 9 # macro -R_MICROBLAZE_32_SYM_OP_SYM = 10 # macro -R_MICROBLAZE_GNU_VTINHERIT = 11 # macro -R_MICROBLAZE_GNU_VTENTRY = 12 # macro -R_MICROBLAZE_GOTPC_64 = 13 # macro -R_MICROBLAZE_GOT_64 = 14 # macro -R_MICROBLAZE_PLT_64 = 15 # macro -R_MICROBLAZE_REL = 16 # macro -R_MICROBLAZE_JUMP_SLOT = 17 # macro -R_MICROBLAZE_GLOB_DAT = 18 # macro -R_MICROBLAZE_GOTOFF_64 = 19 # macro -R_MICROBLAZE_GOTOFF_32 = 20 # macro -R_MICROBLAZE_COPY = 21 # macro -R_MICROBLAZE_TLS = 22 # macro -R_MICROBLAZE_TLSGD = 23 # macro -R_MICROBLAZE_TLSLD = 24 # macro -R_MICROBLAZE_TLSDTPMOD32 = 25 # macro -R_MICROBLAZE_TLSDTPREL32 = 26 # macro -R_MICROBLAZE_TLSDTPREL64 = 27 # macro -R_MICROBLAZE_TLSGOTTPREL32 = 28 # macro -R_MICROBLAZE_TLSTPREL32 = 29 # macro -DT_NIOS2_GP = 0x70000002 # macro -R_NIOS2_NONE = 0 # macro -R_NIOS2_S16 = 1 # macro -R_NIOS2_U16 = 2 # macro -R_NIOS2_PCREL16 = 3 # macro -R_NIOS2_CALL26 = 4 # macro -R_NIOS2_IMM5 = 5 # macro -R_NIOS2_CACHE_OPX = 6 # macro -R_NIOS2_IMM6 = 7 # macro -R_NIOS2_IMM8 = 8 # macro -R_NIOS2_HI16 = 9 # macro -R_NIOS2_LO16 = 10 # macro -R_NIOS2_HIADJ16 = 11 # macro -R_NIOS2_BFD_RELOC_32 = 12 # macro -R_NIOS2_BFD_RELOC_16 = 13 # macro -R_NIOS2_BFD_RELOC_8 = 14 # macro -R_NIOS2_GPREL = 15 # macro -R_NIOS2_GNU_VTINHERIT = 16 # macro -R_NIOS2_GNU_VTENTRY = 17 # macro -R_NIOS2_UJMP = 18 # macro -R_NIOS2_CJMP = 19 # macro -R_NIOS2_CALLR = 20 # macro -R_NIOS2_ALIGN = 21 # macro -R_NIOS2_GOT16 = 22 # macro -R_NIOS2_CALL16 = 23 # macro -R_NIOS2_GOTOFF_LO = 24 # macro -R_NIOS2_GOTOFF_HA = 25 # macro -R_NIOS2_PCREL_LO = 26 # macro -R_NIOS2_PCREL_HA = 27 # macro -R_NIOS2_TLS_GD16 = 28 # macro -R_NIOS2_TLS_LDM16 = 29 # macro -R_NIOS2_TLS_LDO16 = 30 # macro -R_NIOS2_TLS_IE16 = 31 # macro -R_NIOS2_TLS_LE16 = 32 # macro -R_NIOS2_TLS_DTPMOD = 33 # macro -R_NIOS2_TLS_DTPREL = 34 # macro -R_NIOS2_TLS_TPREL = 35 # macro -R_NIOS2_COPY = 36 # macro -R_NIOS2_GLOB_DAT = 37 # macro -R_NIOS2_JUMP_SLOT = 38 # macro -R_NIOS2_RELATIVE = 39 # macro -R_NIOS2_GOTOFF = 40 # macro -R_NIOS2_CALL26_NOAT = 41 # macro -R_NIOS2_GOT_LO = 42 # macro -R_NIOS2_GOT_HA = 43 # macro -R_NIOS2_CALL_LO = 44 # macro -R_NIOS2_CALL_HA = 45 # macro -R_TILEPRO_NONE = 0 # macro -R_TILEPRO_32 = 1 # macro -R_TILEPRO_16 = 2 # macro -R_TILEPRO_8 = 3 # macro -R_TILEPRO_32_PCREL = 4 # macro -R_TILEPRO_16_PCREL = 5 # macro -R_TILEPRO_8_PCREL = 6 # macro -R_TILEPRO_LO16 = 7 # macro -R_TILEPRO_HI16 = 8 # macro -R_TILEPRO_HA16 = 9 # macro -R_TILEPRO_COPY = 10 # macro -R_TILEPRO_GLOB_DAT = 11 # macro -R_TILEPRO_JMP_SLOT = 12 # macro -R_TILEPRO_RELATIVE = 13 # macro -R_TILEPRO_BROFF_X1 = 14 # macro -R_TILEPRO_JOFFLONG_X1 = 15 # macro -R_TILEPRO_JOFFLONG_X1_PLT = 16 # macro -R_TILEPRO_IMM8_X0 = 17 # macro -R_TILEPRO_IMM8_Y0 = 18 # macro -R_TILEPRO_IMM8_X1 = 19 # macro -R_TILEPRO_IMM8_Y1 = 20 # macro -R_TILEPRO_MT_IMM15_X1 = 21 # macro -R_TILEPRO_MF_IMM15_X1 = 22 # macro -R_TILEPRO_IMM16_X0 = 23 # macro -R_TILEPRO_IMM16_X1 = 24 # macro -R_TILEPRO_IMM16_X0_LO = 25 # macro -R_TILEPRO_IMM16_X1_LO = 26 # macro -R_TILEPRO_IMM16_X0_HI = 27 # macro -R_TILEPRO_IMM16_X1_HI = 28 # macro -R_TILEPRO_IMM16_X0_HA = 29 # macro -R_TILEPRO_IMM16_X1_HA = 30 # macro -R_TILEPRO_IMM16_X0_PCREL = 31 # macro -R_TILEPRO_IMM16_X1_PCREL = 32 # macro -R_TILEPRO_IMM16_X0_LO_PCREL = 33 # macro -R_TILEPRO_IMM16_X1_LO_PCREL = 34 # macro -R_TILEPRO_IMM16_X0_HI_PCREL = 35 # macro -R_TILEPRO_IMM16_X1_HI_PCREL = 36 # macro -R_TILEPRO_IMM16_X0_HA_PCREL = 37 # macro -R_TILEPRO_IMM16_X1_HA_PCREL = 38 # macro -R_TILEPRO_IMM16_X0_GOT = 39 # macro -R_TILEPRO_IMM16_X1_GOT = 40 # macro -R_TILEPRO_IMM16_X0_GOT_LO = 41 # macro -R_TILEPRO_IMM16_X1_GOT_LO = 42 # macro -R_TILEPRO_IMM16_X0_GOT_HI = 43 # macro -R_TILEPRO_IMM16_X1_GOT_HI = 44 # macro -R_TILEPRO_IMM16_X0_GOT_HA = 45 # macro -R_TILEPRO_IMM16_X1_GOT_HA = 46 # macro -R_TILEPRO_MMSTART_X0 = 47 # macro -R_TILEPRO_MMEND_X0 = 48 # macro -R_TILEPRO_MMSTART_X1 = 49 # macro -R_TILEPRO_MMEND_X1 = 50 # macro -R_TILEPRO_SHAMT_X0 = 51 # macro -R_TILEPRO_SHAMT_X1 = 52 # macro -R_TILEPRO_SHAMT_Y0 = 53 # macro -R_TILEPRO_SHAMT_Y1 = 54 # macro -R_TILEPRO_DEST_IMM8_X1 = 55 # macro -R_TILEPRO_TLS_GD_CALL = 60 # macro -R_TILEPRO_IMM8_X0_TLS_GD_ADD = 61 # macro -R_TILEPRO_IMM8_X1_TLS_GD_ADD = 62 # macro -R_TILEPRO_IMM8_Y0_TLS_GD_ADD = 63 # macro -R_TILEPRO_IMM8_Y1_TLS_GD_ADD = 64 # macro -R_TILEPRO_TLS_IE_LOAD = 65 # macro -R_TILEPRO_IMM16_X0_TLS_GD = 66 # macro -R_TILEPRO_IMM16_X1_TLS_GD = 67 # macro -R_TILEPRO_IMM16_X0_TLS_GD_LO = 68 # macro -R_TILEPRO_IMM16_X1_TLS_GD_LO = 69 # macro -R_TILEPRO_IMM16_X0_TLS_GD_HI = 70 # macro -R_TILEPRO_IMM16_X1_TLS_GD_HI = 71 # macro -R_TILEPRO_IMM16_X0_TLS_GD_HA = 72 # macro -R_TILEPRO_IMM16_X1_TLS_GD_HA = 73 # macro -R_TILEPRO_IMM16_X0_TLS_IE = 74 # macro -R_TILEPRO_IMM16_X1_TLS_IE = 75 # macro -R_TILEPRO_IMM16_X0_TLS_IE_LO = 76 # macro -R_TILEPRO_IMM16_X1_TLS_IE_LO = 77 # macro -R_TILEPRO_IMM16_X0_TLS_IE_HI = 78 # macro -R_TILEPRO_IMM16_X1_TLS_IE_HI = 79 # macro -R_TILEPRO_IMM16_X0_TLS_IE_HA = 80 # macro -R_TILEPRO_IMM16_X1_TLS_IE_HA = 81 # macro -R_TILEPRO_TLS_DTPMOD32 = 82 # macro -R_TILEPRO_TLS_DTPOFF32 = 83 # macro -R_TILEPRO_TLS_TPOFF32 = 84 # macro -R_TILEPRO_IMM16_X0_TLS_LE = 85 # macro -R_TILEPRO_IMM16_X1_TLS_LE = 86 # macro -R_TILEPRO_IMM16_X0_TLS_LE_LO = 87 # macro -R_TILEPRO_IMM16_X1_TLS_LE_LO = 88 # macro -R_TILEPRO_IMM16_X0_TLS_LE_HI = 89 # macro -R_TILEPRO_IMM16_X1_TLS_LE_HI = 90 # macro -R_TILEPRO_IMM16_X0_TLS_LE_HA = 91 # macro -R_TILEPRO_IMM16_X1_TLS_LE_HA = 92 # macro -R_TILEPRO_GNU_VTINHERIT = 128 # macro -R_TILEPRO_GNU_VTENTRY = 129 # macro -R_TILEPRO_NUM = 130 # macro -R_TILEGX_NONE = 0 # macro -R_TILEGX_64 = 1 # macro -R_TILEGX_32 = 2 # macro -R_TILEGX_16 = 3 # macro -R_TILEGX_8 = 4 # macro -R_TILEGX_64_PCREL = 5 # macro -R_TILEGX_32_PCREL = 6 # macro -R_TILEGX_16_PCREL = 7 # macro -R_TILEGX_8_PCREL = 8 # macro -R_TILEGX_HW0 = 9 # macro -R_TILEGX_HW1 = 10 # macro -R_TILEGX_HW2 = 11 # macro -R_TILEGX_HW3 = 12 # macro -R_TILEGX_HW0_LAST = 13 # macro -R_TILEGX_HW1_LAST = 14 # macro -R_TILEGX_HW2_LAST = 15 # macro -R_TILEGX_COPY = 16 # macro -R_TILEGX_GLOB_DAT = 17 # macro -R_TILEGX_JMP_SLOT = 18 # macro -R_TILEGX_RELATIVE = 19 # macro -R_TILEGX_BROFF_X1 = 20 # macro -R_TILEGX_JUMPOFF_X1 = 21 # macro -R_TILEGX_JUMPOFF_X1_PLT = 22 # macro -R_TILEGX_IMM8_X0 = 23 # macro -R_TILEGX_IMM8_Y0 = 24 # macro -R_TILEGX_IMM8_X1 = 25 # macro -R_TILEGX_IMM8_Y1 = 26 # macro -R_TILEGX_DEST_IMM8_X1 = 27 # macro -R_TILEGX_MT_IMM14_X1 = 28 # macro -R_TILEGX_MF_IMM14_X1 = 29 # macro -R_TILEGX_MMSTART_X0 = 30 # macro -R_TILEGX_MMEND_X0 = 31 # macro -R_TILEGX_SHAMT_X0 = 32 # macro -R_TILEGX_SHAMT_X1 = 33 # macro -R_TILEGX_SHAMT_Y0 = 34 # macro -R_TILEGX_SHAMT_Y1 = 35 # macro -R_TILEGX_IMM16_X0_HW0 = 36 # macro -R_TILEGX_IMM16_X1_HW0 = 37 # macro -R_TILEGX_IMM16_X0_HW1 = 38 # macro -R_TILEGX_IMM16_X1_HW1 = 39 # macro -R_TILEGX_IMM16_X0_HW2 = 40 # macro -R_TILEGX_IMM16_X1_HW2 = 41 # macro -R_TILEGX_IMM16_X0_HW3 = 42 # macro -R_TILEGX_IMM16_X1_HW3 = 43 # macro -R_TILEGX_IMM16_X0_HW0_LAST = 44 # macro -R_TILEGX_IMM16_X1_HW0_LAST = 45 # macro -R_TILEGX_IMM16_X0_HW1_LAST = 46 # macro -R_TILEGX_IMM16_X1_HW1_LAST = 47 # macro -R_TILEGX_IMM16_X0_HW2_LAST = 48 # macro -R_TILEGX_IMM16_X1_HW2_LAST = 49 # macro -R_TILEGX_IMM16_X0_HW0_PCREL = 50 # macro -R_TILEGX_IMM16_X1_HW0_PCREL = 51 # macro -R_TILEGX_IMM16_X0_HW1_PCREL = 52 # macro -R_TILEGX_IMM16_X1_HW1_PCREL = 53 # macro -R_TILEGX_IMM16_X0_HW2_PCREL = 54 # macro -R_TILEGX_IMM16_X1_HW2_PCREL = 55 # macro -R_TILEGX_IMM16_X0_HW3_PCREL = 56 # macro -R_TILEGX_IMM16_X1_HW3_PCREL = 57 # macro -R_TILEGX_IMM16_X0_HW0_LAST_PCREL = 58 # macro -R_TILEGX_IMM16_X1_HW0_LAST_PCREL = 59 # macro -R_TILEGX_IMM16_X0_HW1_LAST_PCREL = 60 # macro -R_TILEGX_IMM16_X1_HW1_LAST_PCREL = 61 # macro -R_TILEGX_IMM16_X0_HW2_LAST_PCREL = 62 # macro -R_TILEGX_IMM16_X1_HW2_LAST_PCREL = 63 # macro -R_TILEGX_IMM16_X0_HW0_GOT = 64 # macro -R_TILEGX_IMM16_X1_HW0_GOT = 65 # macro -R_TILEGX_IMM16_X0_HW0_PLT_PCREL = 66 # macro -R_TILEGX_IMM16_X1_HW0_PLT_PCREL = 67 # macro -R_TILEGX_IMM16_X0_HW1_PLT_PCREL = 68 # macro -R_TILEGX_IMM16_X1_HW1_PLT_PCREL = 69 # macro -R_TILEGX_IMM16_X0_HW2_PLT_PCREL = 70 # macro -R_TILEGX_IMM16_X1_HW2_PLT_PCREL = 71 # macro -R_TILEGX_IMM16_X0_HW0_LAST_GOT = 72 # macro -R_TILEGX_IMM16_X1_HW0_LAST_GOT = 73 # macro -R_TILEGX_IMM16_X0_HW1_LAST_GOT = 74 # macro -R_TILEGX_IMM16_X1_HW1_LAST_GOT = 75 # macro -R_TILEGX_IMM16_X0_HW3_PLT_PCREL = 76 # macro -R_TILEGX_IMM16_X1_HW3_PLT_PCREL = 77 # macro -R_TILEGX_IMM16_X0_HW0_TLS_GD = 78 # macro -R_TILEGX_IMM16_X1_HW0_TLS_GD = 79 # macro -R_TILEGX_IMM16_X0_HW0_TLS_LE = 80 # macro -R_TILEGX_IMM16_X1_HW0_TLS_LE = 81 # macro -R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE = 82 # macro -R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE = 83 # macro -R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE = 84 # macro -R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE = 85 # macro -R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD = 86 # macro -R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD = 87 # macro -R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD = 88 # macro -R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD = 89 # macro -R_TILEGX_IMM16_X0_HW0_TLS_IE = 92 # macro -R_TILEGX_IMM16_X1_HW0_TLS_IE = 93 # macro -R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL = 94 # macro -R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL = 95 # macro -R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL = 96 # macro -R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL = 97 # macro -R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL = 98 # macro -R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL = 99 # macro -R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE = 100 # macro -R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE = 101 # macro -R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE = 102 # macro -R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE = 103 # macro -R_TILEGX_TLS_DTPMOD64 = 106 # macro -R_TILEGX_TLS_DTPOFF64 = 107 # macro -R_TILEGX_TLS_TPOFF64 = 108 # macro -R_TILEGX_TLS_DTPMOD32 = 109 # macro -R_TILEGX_TLS_DTPOFF32 = 110 # macro -R_TILEGX_TLS_TPOFF32 = 111 # macro -R_TILEGX_TLS_GD_CALL = 112 # macro -R_TILEGX_IMM8_X0_TLS_GD_ADD = 113 # macro -R_TILEGX_IMM8_X1_TLS_GD_ADD = 114 # macro -R_TILEGX_IMM8_Y0_TLS_GD_ADD = 115 # macro -R_TILEGX_IMM8_Y1_TLS_GD_ADD = 116 # macro -R_TILEGX_TLS_IE_LOAD = 117 # macro -R_TILEGX_IMM8_X0_TLS_ADD = 118 # macro -R_TILEGX_IMM8_X1_TLS_ADD = 119 # macro -R_TILEGX_IMM8_Y0_TLS_ADD = 120 # macro -R_TILEGX_IMM8_Y1_TLS_ADD = 121 # macro -R_TILEGX_GNU_VTINHERIT = 128 # macro -R_TILEGX_GNU_VTENTRY = 129 # macro -R_TILEGX_NUM = 130 # macro -EF_RISCV_RVC = 0x0001 # macro -EF_RISCV_FLOAT_ABI = 0x0006 # macro -EF_RISCV_FLOAT_ABI_SOFT = 0x0000 # macro -EF_RISCV_FLOAT_ABI_SINGLE = 0x0002 # macro -EF_RISCV_FLOAT_ABI_DOUBLE = 0x0004 # macro -EF_RISCV_FLOAT_ABI_QUAD = 0x0006 # macro -EF_RISCV_RVE = 0x0008 # macro -EF_RISCV_TSO = 0x0010 # macro -R_RISCV_NONE = 0 # macro -R_RISCV_32 = 1 # macro -R_RISCV_64 = 2 # macro -R_RISCV_RELATIVE = 3 # macro -R_RISCV_COPY = 4 # macro -R_RISCV_JUMP_SLOT = 5 # macro -R_RISCV_TLS_DTPMOD32 = 6 # macro -R_RISCV_TLS_DTPMOD64 = 7 # macro -R_RISCV_TLS_DTPREL32 = 8 # macro -R_RISCV_TLS_DTPREL64 = 9 # macro -R_RISCV_TLS_TPREL32 = 10 # macro -R_RISCV_TLS_TPREL64 = 11 # macro -R_RISCV_BRANCH = 16 # macro -R_RISCV_JAL = 17 # macro -R_RISCV_CALL = 18 # macro -R_RISCV_CALL_PLT = 19 # macro -R_RISCV_GOT_HI20 = 20 # macro -R_RISCV_TLS_GOT_HI20 = 21 # macro -R_RISCV_TLS_GD_HI20 = 22 # macro -R_RISCV_PCREL_HI20 = 23 # macro -R_RISCV_PCREL_LO12_I = 24 # macro -R_RISCV_PCREL_LO12_S = 25 # macro -R_RISCV_HI20 = 26 # macro -R_RISCV_LO12_I = 27 # macro -R_RISCV_LO12_S = 28 # macro -R_RISCV_TPREL_HI20 = 29 # macro -R_RISCV_TPREL_LO12_I = 30 # macro -R_RISCV_TPREL_LO12_S = 31 # macro -R_RISCV_TPREL_ADD = 32 # macro -R_RISCV_ADD8 = 33 # macro -R_RISCV_ADD16 = 34 # macro -R_RISCV_ADD32 = 35 # macro -R_RISCV_ADD64 = 36 # macro -R_RISCV_SUB8 = 37 # macro -R_RISCV_SUB16 = 38 # macro -R_RISCV_SUB32 = 39 # macro -R_RISCV_SUB64 = 40 # macro -R_RISCV_GNU_VTINHERIT = 41 # macro -R_RISCV_GNU_VTENTRY = 42 # macro -R_RISCV_ALIGN = 43 # macro -R_RISCV_RVC_BRANCH = 44 # macro -R_RISCV_RVC_JUMP = 45 # macro -R_RISCV_RVC_LUI = 46 # macro -R_RISCV_GPREL_I = 47 # macro -R_RISCV_GPREL_S = 48 # macro -R_RISCV_TPREL_I = 49 # macro -R_RISCV_TPREL_S = 50 # macro -R_RISCV_RELAX = 51 # macro -R_RISCV_SUB6 = 52 # macro -R_RISCV_SET6 = 53 # macro -R_RISCV_SET8 = 54 # macro -R_RISCV_SET16 = 55 # macro -R_RISCV_SET32 = 56 # macro -R_RISCV_32_PCREL = 57 # macro -R_RISCV_IRELATIVE = 58 # macro -R_RISCV_PLT32 = 59 # macro -R_RISCV_SET_ULEB128 = 60 # macro -R_RISCV_SUB_ULEB128 = 61 # macro -R_RISCV_NUM = 62 # macro -STO_RISCV_VARIANT_CC = 0x80 # macro -SHT_RISCV_ATTRIBUTES = (0x70000000+3) # macro -PT_RISCV_ATTRIBUTES = (0x70000000+3) # macro -DT_RISCV_VARIANT_CC = (0x70000000+1) # macro -R_BPF_NONE = 0 # macro -R_BPF_64_64 = 1 # macro -R_BPF_64_32 = 10 # macro -R_METAG_HIADDR16 = 0 # macro -R_METAG_LOADDR16 = 1 # macro -R_METAG_ADDR32 = 2 # macro -R_METAG_NONE = 3 # macro -R_METAG_RELBRANCH = 4 # macro -R_METAG_GETSETOFF = 5 # macro -R_METAG_REG32OP1 = 6 # macro -R_METAG_REG32OP2 = 7 # macro -R_METAG_REG32OP3 = 8 # macro -R_METAG_REG16OP1 = 9 # macro -R_METAG_REG16OP2 = 10 # macro -R_METAG_REG16OP3 = 11 # macro -R_METAG_REG32OP4 = 12 # macro -R_METAG_HIOG = 13 # macro -R_METAG_LOOG = 14 # macro -R_METAG_REL8 = 15 # macro -R_METAG_REL16 = 16 # macro -R_METAG_GNU_VTINHERIT = 30 # macro -R_METAG_GNU_VTENTRY = 31 # macro -R_METAG_HI16_GOTOFF = 32 # macro -R_METAG_LO16_GOTOFF = 33 # macro -R_METAG_GETSET_GOTOFF = 34 # macro -R_METAG_GETSET_GOT = 35 # macro -R_METAG_HI16_GOTPC = 36 # macro -R_METAG_LO16_GOTPC = 37 # macro -R_METAG_HI16_PLT = 38 # macro -R_METAG_LO16_PLT = 39 # macro -R_METAG_RELBRANCH_PLT = 40 # macro -R_METAG_GOTOFF = 41 # macro -R_METAG_PLT = 42 # macro -R_METAG_COPY = 43 # macro -R_METAG_JMP_SLOT = 44 # macro -R_METAG_RELATIVE = 45 # macro -R_METAG_GLOB_DAT = 46 # macro -R_METAG_TLS_GD = 47 # macro -R_METAG_TLS_LDM = 48 # macro -R_METAG_TLS_LDO_HI16 = 49 # macro -R_METAG_TLS_LDO_LO16 = 50 # macro -R_METAG_TLS_LDO = 51 # macro -R_METAG_TLS_IE = 52 # macro -R_METAG_TLS_IENONPIC = 53 # macro -R_METAG_TLS_IENONPIC_HI16 = 54 # macro -R_METAG_TLS_IENONPIC_LO16 = 55 # macro -R_METAG_TLS_TPOFF = 56 # macro -R_METAG_TLS_DTPMOD = 57 # macro -R_METAG_TLS_DTPOFF = 58 # macro -R_METAG_TLS_LE = 59 # macro -R_METAG_TLS_LE_HI16 = 60 # macro -R_METAG_TLS_LE_LO16 = 61 # macro -R_NDS32_NONE = 0 # macro -R_NDS32_32_RELA = 20 # macro -R_NDS32_COPY = 39 # macro -R_NDS32_GLOB_DAT = 40 # macro -R_NDS32_JMP_SLOT = 41 # macro -R_NDS32_RELATIVE = 42 # macro -R_NDS32_TLS_TPOFF = 102 # macro -R_NDS32_TLS_DESC = 119 # macro -EF_LARCH_ABI_MODIFIER_MASK = 0x07 # macro -EF_LARCH_ABI_SOFT_FLOAT = 0x01 # macro -EF_LARCH_ABI_SINGLE_FLOAT = 0x02 # macro -EF_LARCH_ABI_DOUBLE_FLOAT = 0x03 # macro -EF_LARCH_OBJABI_V1 = 0x40 # macro -R_LARCH_NONE = 0 # macro -R_LARCH_32 = 1 # macro -R_LARCH_64 = 2 # macro -R_LARCH_RELATIVE = 3 # macro -R_LARCH_COPY = 4 # macro -R_LARCH_JUMP_SLOT = 5 # macro -R_LARCH_TLS_DTPMOD32 = 6 # macro -R_LARCH_TLS_DTPMOD64 = 7 # macro -R_LARCH_TLS_DTPREL32 = 8 # macro -R_LARCH_TLS_DTPREL64 = 9 # macro -R_LARCH_TLS_TPREL32 = 10 # macro -R_LARCH_TLS_TPREL64 = 11 # macro -R_LARCH_IRELATIVE = 12 # macro -R_LARCH_MARK_LA = 20 # macro -R_LARCH_MARK_PCREL = 21 # macro -R_LARCH_SOP_PUSH_PCREL = 22 # macro -R_LARCH_SOP_PUSH_ABSOLUTE = 23 # macro -R_LARCH_SOP_PUSH_DUP = 24 # macro -R_LARCH_SOP_PUSH_GPREL = 25 # macro -R_LARCH_SOP_PUSH_TLS_TPREL = 26 # macro -R_LARCH_SOP_PUSH_TLS_GOT = 27 # macro -R_LARCH_SOP_PUSH_TLS_GD = 28 # macro -R_LARCH_SOP_PUSH_PLT_PCREL = 29 # macro -R_LARCH_SOP_ASSERT = 30 # macro -R_LARCH_SOP_NOT = 31 # macro -R_LARCH_SOP_SUB = 32 # macro -R_LARCH_SOP_SL = 33 # macro -R_LARCH_SOP_SR = 34 # macro -R_LARCH_SOP_ADD = 35 # macro -R_LARCH_SOP_AND = 36 # macro -R_LARCH_SOP_IF_ELSE = 37 # macro -R_LARCH_SOP_POP_32_S_10_5 = 38 # macro -R_LARCH_SOP_POP_32_U_10_12 = 39 # macro -R_LARCH_SOP_POP_32_S_10_12 = 40 # macro -R_LARCH_SOP_POP_32_S_10_16 = 41 # macro -R_LARCH_SOP_POP_32_S_10_16_S2 = 42 # macro -R_LARCH_SOP_POP_32_S_5_20 = 43 # macro -R_LARCH_SOP_POP_32_S_0_5_10_16_S2 = 44 # macro -R_LARCH_SOP_POP_32_S_0_10_10_16_S2 = 45 # macro -R_LARCH_SOP_POP_32_U = 46 # macro -R_LARCH_ADD8 = 47 # macro -R_LARCH_ADD16 = 48 # macro -R_LARCH_ADD24 = 49 # macro -R_LARCH_ADD32 = 50 # macro -R_LARCH_ADD64 = 51 # macro -R_LARCH_SUB8 = 52 # macro -R_LARCH_SUB16 = 53 # macro -R_LARCH_SUB24 = 54 # macro -R_LARCH_SUB32 = 55 # macro -R_LARCH_SUB64 = 56 # macro -R_LARCH_GNU_VTINHERIT = 57 # macro -R_LARCH_GNU_VTENTRY = 58 # macro -R_LARCH_B16 = 64 # macro -R_LARCH_B21 = 65 # macro -R_LARCH_B26 = 66 # macro -R_LARCH_ABS_HI20 = 67 # macro -R_LARCH_ABS_LO12 = 68 # macro -R_LARCH_ABS64_LO20 = 69 # macro -R_LARCH_ABS64_HI12 = 70 # macro -R_LARCH_PCALA_HI20 = 71 # macro -R_LARCH_PCALA_LO12 = 72 # macro -R_LARCH_PCALA64_LO20 = 73 # macro -R_LARCH_PCALA64_HI12 = 74 # macro -R_LARCH_GOT_PC_HI20 = 75 # macro -R_LARCH_GOT_PC_LO12 = 76 # macro -R_LARCH_GOT64_PC_LO20 = 77 # macro -R_LARCH_GOT64_PC_HI12 = 78 # macro -R_LARCH_GOT_HI20 = 79 # macro -R_LARCH_GOT_LO12 = 80 # macro -R_LARCH_GOT64_LO20 = 81 # macro -R_LARCH_GOT64_HI12 = 82 # macro -R_LARCH_TLS_LE_HI20 = 83 # macro -R_LARCH_TLS_LE_LO12 = 84 # macro -R_LARCH_TLS_LE64_LO20 = 85 # macro -R_LARCH_TLS_LE64_HI12 = 86 # macro -R_LARCH_TLS_IE_PC_HI20 = 87 # macro -R_LARCH_TLS_IE_PC_LO12 = 88 # macro -R_LARCH_TLS_IE64_PC_LO20 = 89 # macro -R_LARCH_TLS_IE64_PC_HI12 = 90 # macro -R_LARCH_TLS_IE_HI20 = 91 # macro -R_LARCH_TLS_IE_LO12 = 92 # macro -R_LARCH_TLS_IE64_LO20 = 93 # macro -R_LARCH_TLS_IE64_HI12 = 94 # macro -R_LARCH_TLS_LD_PC_HI20 = 95 # macro -R_LARCH_TLS_LD_HI20 = 96 # macro -R_LARCH_TLS_GD_PC_HI20 = 97 # macro -R_LARCH_TLS_GD_HI20 = 98 # macro -R_LARCH_32_PCREL = 99 # macro -R_LARCH_RELAX = 100 # macro -R_LARCH_DELETE = 101 # macro -R_LARCH_ALIGN = 102 # macro -R_LARCH_PCREL20_S2 = 103 # macro -R_LARCH_CFA = 104 # macro -R_LARCH_ADD6 = 105 # macro -R_LARCH_SUB6 = 106 # macro -R_LARCH_ADD_ULEB128 = 107 # macro -R_LARCH_SUB_ULEB128 = 108 # macro -R_LARCH_64_PCREL = 109 # macro -EF_ARC_MACH_MSK = 0x000000ff # macro -EF_ARC_OSABI_MSK = 0x00000f00 # macro -EF_ARC_ALL_MSK = (0x000000ff|0x00000f00) # macro -SHT_ARC_ATTRIBUTES = (0x70000000+1) # macro -R_ARC_NONE = 0x0 # macro -R_ARC_8 = 0x1 # macro -R_ARC_16 = 0x2 # macro -R_ARC_24 = 0x3 # macro -R_ARC_32 = 0x4 # macro -R_ARC_B22_PCREL = 0x6 # macro -R_ARC_H30 = 0x7 # macro -R_ARC_N8 = 0x8 # macro -R_ARC_N16 = 0x9 # macro -R_ARC_N24 = 0xA # macro -R_ARC_N32 = 0xB # macro -R_ARC_SDA = 0xC # macro -R_ARC_SECTOFF = 0xD # macro -R_ARC_S21H_PCREL = 0xE # macro -R_ARC_S21W_PCREL = 0xF # macro -R_ARC_S25H_PCREL = 0x10 # macro -R_ARC_S25W_PCREL = 0x11 # macro -R_ARC_SDA32 = 0x12 # macro -R_ARC_SDA_LDST = 0x13 # macro -R_ARC_SDA_LDST1 = 0x14 # macro -R_ARC_SDA_LDST2 = 0x15 # macro -R_ARC_SDA16_LD = 0x16 # macro -R_ARC_SDA16_LD1 = 0x17 # macro -R_ARC_SDA16_LD2 = 0x18 # macro -R_ARC_S13_PCREL = 0x19 # macro -R_ARC_W = 0x1A # macro -R_ARC_32_ME = 0x1B # macro -R_ARC_N32_ME = 0x1C # macro -R_ARC_SECTOFF_ME = 0x1D # macro -R_ARC_SDA32_ME = 0x1E # macro -R_ARC_W_ME = 0x1F # macro -R_ARC_H30_ME = 0x20 # macro -R_ARC_SECTOFF_U8 = 0x21 # macro -R_ARC_SECTOFF_S9 = 0x22 # macro -R_AC_SECTOFF_U8 = 0x23 # macro -R_AC_SECTOFF_U8_1 = 0x24 # macro -R_AC_SECTOFF_U8_2 = 0x25 # macro -R_AC_SECTOFF_S9 = 0x26 # macro -R_AC_SECTOFF_S9_1 = 0x27 # macro -R_AC_SECTOFF_S9_2 = 0x28 # macro -R_ARC_SECTOFF_ME_1 = 0x29 # macro -R_ARC_SECTOFF_ME_2 = 0x2A # macro -R_ARC_SECTOFF_1 = 0x2B # macro -R_ARC_SECTOFF_2 = 0x2C # macro -R_ARC_SDA_12 = 0x2D # macro -R_ARC_SDA16_ST2 = 0x30 # macro -R_ARC_32_PCREL = 0x31 # macro -R_ARC_PC32 = 0x32 # macro -R_ARC_GOTPC32 = 0x33 # macro -R_ARC_PLT32 = 0x34 # macro -R_ARC_COPY = 0x35 # macro -R_ARC_GLOB_DAT = 0x36 # macro -R_ARC_JMP_SLOT = 0x37 # macro -R_ARC_RELATIVE = 0x38 # macro -R_ARC_GOTOFF = 0x39 # macro -R_ARC_GOTPC = 0x3A # macro -R_ARC_GOT32 = 0x3B # macro -R_ARC_S21W_PCREL_PLT = 0x3C # macro -R_ARC_S25H_PCREL_PLT = 0x3D # macro -R_ARC_JLI_SECTOFF = 0x3F # macro -R_ARC_TLS_DTPMOD = 0x42 # macro -R_ARC_TLS_DTPOFF = 0x43 # macro -R_ARC_TLS_TPOFF = 0x44 # macro -R_ARC_TLS_GD_GOT = 0x45 # macro -R_ARC_TLS_GD_LD = 0x46 # macro -R_ARC_TLS_GD_CALL = 0x47 # macro -R_ARC_TLS_IE_GOT = 0x48 # macro -R_ARC_TLS_DTPOFF_S9 = 0x49 # macro -R_ARC_TLS_LE_S9 = 0x4A # macro -R_ARC_TLS_LE_32 = 0x4B # macro -R_ARC_S25W_PCREL_PLT = 0x4C # macro -R_ARC_S21H_PCREL_PLT = 0x4D # macro -R_ARC_NPS_CMEM16 = 0x4E # macro -R_OR1K_NONE = 0 # macro -R_OR1K_32 = 1 # macro -R_OR1K_16 = 2 # macro -R_OR1K_8 = 3 # macro -R_OR1K_LO_16_IN_INSN = 4 # macro -R_OR1K_HI_16_IN_INSN = 5 # macro -R_OR1K_INSN_REL_26 = 6 # macro -R_OR1K_GNU_VTENTRY = 7 # macro -R_OR1K_GNU_VTINHERIT = 8 # macro -R_OR1K_32_PCREL = 9 # macro -R_OR1K_16_PCREL = 10 # macro -R_OR1K_8_PCREL = 11 # macro -R_OR1K_GOTPC_HI16 = 12 # macro -R_OR1K_GOTPC_LO16 = 13 # macro -R_OR1K_GOT16 = 14 # macro -R_OR1K_PLT26 = 15 # macro -R_OR1K_GOTOFF_HI16 = 16 # macro -R_OR1K_GOTOFF_LO16 = 17 # macro -R_OR1K_COPY = 18 # macro -R_OR1K_GLOB_DAT = 19 # macro -R_OR1K_JMP_SLOT = 20 # macro -R_OR1K_RELATIVE = 21 # macro -R_OR1K_TLS_GD_HI16 = 22 # macro -R_OR1K_TLS_GD_LO16 = 23 # macro -R_OR1K_TLS_LDM_HI16 = 24 # macro -R_OR1K_TLS_LDM_LO16 = 25 # macro -R_OR1K_TLS_LDO_HI16 = 26 # macro -R_OR1K_TLS_LDO_LO16 = 27 # macro -R_OR1K_TLS_IE_HI16 = 28 # macro -R_OR1K_TLS_IE_LO16 = 29 # macro -R_OR1K_TLS_LE_HI16 = 30 # macro -R_OR1K_TLS_LE_LO16 = 31 # macro -R_OR1K_TLS_TPOFF = 32 # macro -R_OR1K_TLS_DTPOFF = 33 # macro -R_OR1K_TLS_DTPMOD = 34 # macro +# extern int strcoll_l(const char *__s1, const char *__s2, locale_t __l) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2, 3))) +try: (strcoll_l:=dll.strcoll_l).restype, strcoll_l.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), locale_t] +except AttributeError: pass + +# extern size_t strxfrm_l(char *__dest, const char *__src, size_t __n, locale_t __l) __attribute__((nothrow)) __attribute__((nonnull(2, 4))) +try: (strxfrm_l:=dll.strxfrm_l).restype, strxfrm_l.argtypes = size_t, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t, locale_t] +except AttributeError: pass + +# extern char *strdup(const char *__s) __attribute__((nothrow)) __attribute__((malloc)) __attribute__((nonnull(1))) +try: (strdup:=dll.strdup).restype, strdup.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strndup(const char *__string, size_t __n) __attribute__((nothrow)) __attribute__((malloc)) __attribute__((nonnull(1))) +try: (strndup:=dll.strndup).restype, strndup.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern char *strchr(const char *__s, int __c) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1))) +try: (strchr:=dll.strchr).restype, strchr.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern char *strrchr(const char *__s, int __c) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1))) +try: (strrchr:=dll.strrchr).restype, strrchr.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern char *strchrnul(const char *__s, int __c) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1))) +try: (strchrnul:=dll.strchrnul).restype, strchrnul.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern unsigned long strcspn(const char *__s, const char *__reject) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strcspn:=dll.strcspn).restype, strcspn.argtypes = ctypes.c_uint64, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern unsigned long strspn(const char *__s, const char *__accept) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strspn:=dll.strspn).restype, strspn.argtypes = ctypes.c_uint64, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strpbrk(const char *__s, const char *__accept) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strpbrk:=dll.strpbrk).restype, strpbrk.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strstr(const char *__haystack, const char *__needle) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strstr:=dll.strstr).restype, strstr.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strtok(char *restrict __s, const char *restrict __delim) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (strtok:=dll.strtok).restype, strtok.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *__strtok_r(char *restrict __s, const char *restrict __delim, char **restrict __save_ptr) __attribute__((nothrow)) __attribute__((nonnull(2, 3))) +try: (__strtok_r:=dll.__strtok_r).restype, __strtok_r.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.POINTER(ctypes.c_char))] +except AttributeError: pass + +# extern char *strtok_r(char *restrict __s, const char *restrict __delim, char **restrict __save_ptr) __attribute__((nothrow)) __attribute__((nonnull(2, 3))) +try: (strtok_r:=dll.strtok_r).restype, strtok_r.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.POINTER(ctypes.c_char))] +except AttributeError: pass + +# extern char *strcasestr(const char *__haystack, const char *__needle) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 2))) +try: (strcasestr:=dll.strcasestr).restype, strcasestr.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern void *memmem(const void *__haystack, size_t __haystacklen, const void *__needle, size_t __needlelen) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1, 3))) +try: (memmem:=dll.memmem).restype, memmem.argtypes = ctypes.c_void_p, [ctypes.c_void_p, size_t, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern void *__mempcpy(void *restrict __dest, const void *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (__mempcpy:=dll.__mempcpy).restype, __mempcpy.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern void *mempcpy(void *restrict __dest, const void *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (mempcpy:=dll.mempcpy).restype, mempcpy.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern unsigned long strlen(const char *__s) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1))) +try: (strlen:=dll.strlen).restype, strlen.argtypes = ctypes.c_uint64, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern size_t strnlen(const char *__string, size_t __maxlen) __attribute__((nothrow)) __attribute__((pure)) __attribute__((nonnull(1))) +try: (strnlen:=dll.strnlen).restype, strnlen.argtypes = size_t, [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern char *strerror(int __errnum) __attribute__((nothrow)) +try: (strerror:=dll.strerror).restype, strerror.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.c_int32] +except AttributeError: pass + +# extern int strerror_r(int __errnum, char *__buf, size_t __buflen) asm("__xpg_strerror_r") __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (strerror_r:=dll.strerror_r).restype, strerror_r.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern char *strerror_l(int __errnum, locale_t __l) __attribute__((nothrow)) +try: (strerror_l:=dll.strerror_l).restype, strerror_l.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.c_int32, locale_t] +except AttributeError: pass + +# extern void explicit_bzero(void *__s, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (explicit_bzero:=dll.explicit_bzero).restype, explicit_bzero.argtypes = None, [ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern char *strsep(char **restrict __stringp, const char *restrict __delim) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strsep:=dll.strsep).restype, strsep.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *strsignal(int __sig) __attribute__((nothrow)) +try: (strsignal:=dll.strsignal).restype, strsignal.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.c_int32] +except AttributeError: pass + +# extern char *__stpcpy(char *restrict __dest, const char *restrict __src) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (__stpcpy:=dll.__stpcpy).restype, __stpcpy.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *stpcpy(char *restrict __dest, const char *restrict __src) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (stpcpy:=dll.stpcpy).restype, stpcpy.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *__stpncpy(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (__stpncpy:=dll.__stpncpy).restype, __stpncpy.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern char *stpncpy(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (stpncpy:=dll.stpncpy).restype, stpncpy.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern size_t strlcpy(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strlcpy:=dll.strlcpy).restype, strlcpy.argtypes = size_t, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern size_t strlcat(char *restrict __dest, const char *restrict __src, size_t __n) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (strlcat:=dll.strlcat).restype, strlcat.argtypes = size_t, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + Elf32_Half = ctypes.c_uint16 Elf64_Half = ctypes.c_uint16 Elf32_Word = ctypes.c_uint32 Elf32_Sword = ctypes.c_int32 -def DT_EXTRATAGIDX(tag): # macro - return ((Elf32_Word)-((Elf32_Sword)(tag)<<1>>1)-1) Elf64_Word = ctypes.c_uint32 Elf64_Sword = ctypes.c_int32 Elf32_Xword = ctypes.c_uint64 Elf32_Sxword = ctypes.c_int64 Elf64_Xword = ctypes.c_uint64 -def ELF64_R_INFO(sym, type): # macro - return ((((Elf64_Xword)(sym))<<32)+(type)) Elf64_Sxword = ctypes.c_int64 Elf32_Addr = ctypes.c_uint32 Elf64_Addr = ctypes.c_uint64 @@ -3673,630 +281,358 @@ Elf32_Section = ctypes.c_uint16 Elf64_Section = ctypes.c_uint16 Elf32_Versym = ctypes.c_uint16 Elf64_Versym = ctypes.c_uint16 -class struct_c__SA_Elf32_Ehdr(Structure): - pass - -struct_c__SA_Elf32_Ehdr._pack_ = 1 # source:False -struct_c__SA_Elf32_Ehdr._fields_ = [ - ('e_ident', ctypes.c_ubyte * 16), - ('e_type', ctypes.c_uint16), - ('e_machine', ctypes.c_uint16), - ('e_version', ctypes.c_uint32), - ('e_entry', ctypes.c_uint32), - ('e_phoff', ctypes.c_uint32), - ('e_shoff', ctypes.c_uint32), - ('e_flags', ctypes.c_uint32), - ('e_ehsize', ctypes.c_uint16), - ('e_phentsize', ctypes.c_uint16), - ('e_phnum', ctypes.c_uint16), - ('e_shentsize', ctypes.c_uint16), - ('e_shnum', ctypes.c_uint16), - ('e_shstrndx', ctypes.c_uint16), +class Elf32_Ehdr(Struct): pass +Elf32_Ehdr._fields_ = [ + ('e_ident', (ctypes.c_ubyte * 16)), + ('e_type', Elf32_Half), + ('e_machine', Elf32_Half), + ('e_version', Elf32_Word), + ('e_entry', Elf32_Addr), + ('e_phoff', Elf32_Off), + ('e_shoff', Elf32_Off), + ('e_flags', Elf32_Word), + ('e_ehsize', Elf32_Half), + ('e_phentsize', Elf32_Half), + ('e_phnum', Elf32_Half), + ('e_shentsize', Elf32_Half), + ('e_shnum', Elf32_Half), + ('e_shstrndx', Elf32_Half), ] - -Elf32_Ehdr = struct_c__SA_Elf32_Ehdr -class struct_c__SA_Elf64_Ehdr(Structure): - pass - -struct_c__SA_Elf64_Ehdr._pack_ = 1 # source:False -struct_c__SA_Elf64_Ehdr._fields_ = [ - ('e_ident', ctypes.c_ubyte * 16), - ('e_type', ctypes.c_uint16), - ('e_machine', ctypes.c_uint16), - ('e_version', ctypes.c_uint32), - ('e_entry', ctypes.c_uint64), - ('e_phoff', ctypes.c_uint64), - ('e_shoff', ctypes.c_uint64), - ('e_flags', ctypes.c_uint32), - ('e_ehsize', ctypes.c_uint16), - ('e_phentsize', ctypes.c_uint16), - ('e_phnum', ctypes.c_uint16), - ('e_shentsize', ctypes.c_uint16), - ('e_shnum', ctypes.c_uint16), - ('e_shstrndx', ctypes.c_uint16), +class Elf64_Ehdr(Struct): pass +Elf64_Ehdr._fields_ = [ + ('e_ident', (ctypes.c_ubyte * 16)), + ('e_type', Elf64_Half), + ('e_machine', Elf64_Half), + ('e_version', Elf64_Word), + ('e_entry', Elf64_Addr), + ('e_phoff', Elf64_Off), + ('e_shoff', Elf64_Off), + ('e_flags', Elf64_Word), + ('e_ehsize', Elf64_Half), + ('e_phentsize', Elf64_Half), + ('e_phnum', Elf64_Half), + ('e_shentsize', Elf64_Half), + ('e_shnum', Elf64_Half), + ('e_shstrndx', Elf64_Half), ] - -Elf64_Ehdr = struct_c__SA_Elf64_Ehdr -class struct_c__SA_Elf32_Shdr(Structure): - pass - -struct_c__SA_Elf32_Shdr._pack_ = 1 # source:False -struct_c__SA_Elf32_Shdr._fields_ = [ - ('sh_name', ctypes.c_uint32), - ('sh_type', ctypes.c_uint32), - ('sh_flags', ctypes.c_uint32), - ('sh_addr', ctypes.c_uint32), - ('sh_offset', ctypes.c_uint32), - ('sh_size', ctypes.c_uint32), - ('sh_link', ctypes.c_uint32), - ('sh_info', ctypes.c_uint32), - ('sh_addralign', ctypes.c_uint32), - ('sh_entsize', ctypes.c_uint32), +class Elf32_Shdr(Struct): pass +Elf32_Shdr._fields_ = [ + ('sh_name', Elf32_Word), + ('sh_type', Elf32_Word), + ('sh_flags', Elf32_Word), + ('sh_addr', Elf32_Addr), + ('sh_offset', Elf32_Off), + ('sh_size', Elf32_Word), + ('sh_link', Elf32_Word), + ('sh_info', Elf32_Word), + ('sh_addralign', Elf32_Word), + ('sh_entsize', Elf32_Word), ] - -Elf32_Shdr = struct_c__SA_Elf32_Shdr -class struct_c__SA_Elf64_Shdr(Structure): - pass - -struct_c__SA_Elf64_Shdr._pack_ = 1 # source:False -struct_c__SA_Elf64_Shdr._fields_ = [ - ('sh_name', ctypes.c_uint32), - ('sh_type', ctypes.c_uint32), - ('sh_flags', ctypes.c_uint64), - ('sh_addr', ctypes.c_uint64), - ('sh_offset', ctypes.c_uint64), - ('sh_size', ctypes.c_uint64), - ('sh_link', ctypes.c_uint32), - ('sh_info', ctypes.c_uint32), - ('sh_addralign', ctypes.c_uint64), - ('sh_entsize', ctypes.c_uint64), +class Elf64_Shdr(Struct): pass +Elf64_Shdr._fields_ = [ + ('sh_name', Elf64_Word), + ('sh_type', Elf64_Word), + ('sh_flags', Elf64_Xword), + ('sh_addr', Elf64_Addr), + ('sh_offset', Elf64_Off), + ('sh_size', Elf64_Xword), + ('sh_link', Elf64_Word), + ('sh_info', Elf64_Word), + ('sh_addralign', Elf64_Xword), + ('sh_entsize', Elf64_Xword), ] - -Elf64_Shdr = struct_c__SA_Elf64_Shdr -class struct_c__SA_Elf32_Chdr(Structure): - pass - -struct_c__SA_Elf32_Chdr._pack_ = 1 # source:False -struct_c__SA_Elf32_Chdr._fields_ = [ - ('ch_type', ctypes.c_uint32), - ('ch_size', ctypes.c_uint32), - ('ch_addralign', ctypes.c_uint32), +class Elf32_Chdr(Struct): pass +Elf32_Chdr._fields_ = [ + ('ch_type', Elf32_Word), + ('ch_size', Elf32_Word), + ('ch_addralign', Elf32_Word), ] - -Elf32_Chdr = struct_c__SA_Elf32_Chdr -class struct_c__SA_Elf64_Chdr(Structure): - pass - -struct_c__SA_Elf64_Chdr._pack_ = 1 # source:False -struct_c__SA_Elf64_Chdr._fields_ = [ - ('ch_type', ctypes.c_uint32), - ('ch_reserved', ctypes.c_uint32), - ('ch_size', ctypes.c_uint64), - ('ch_addralign', ctypes.c_uint64), +class Elf64_Chdr(Struct): pass +Elf64_Chdr._fields_ = [ + ('ch_type', Elf64_Word), + ('ch_reserved', Elf64_Word), + ('ch_size', Elf64_Xword), + ('ch_addralign', Elf64_Xword), ] - -Elf64_Chdr = struct_c__SA_Elf64_Chdr -class struct_c__SA_Elf32_Sym(Structure): - pass - -struct_c__SA_Elf32_Sym._pack_ = 1 # source:False -struct_c__SA_Elf32_Sym._fields_ = [ - ('st_name', ctypes.c_uint32), - ('st_value', ctypes.c_uint32), - ('st_size', ctypes.c_uint32), - ('st_info', ctypes.c_ubyte), - ('st_other', ctypes.c_ubyte), - ('st_shndx', ctypes.c_uint16), +class Elf32_Sym(Struct): pass +Elf32_Sym._fields_ = [ + ('st_name', Elf32_Word), + ('st_value', Elf32_Addr), + ('st_size', Elf32_Word), + ('st_info', ctypes.c_ubyte), + ('st_other', ctypes.c_ubyte), + ('st_shndx', Elf32_Section), ] - -Elf32_Sym = struct_c__SA_Elf32_Sym -class struct_c__SA_Elf64_Sym(Structure): - pass - -struct_c__SA_Elf64_Sym._pack_ = 1 # source:False -struct_c__SA_Elf64_Sym._fields_ = [ - ('st_name', ctypes.c_uint32), - ('st_info', ctypes.c_ubyte), - ('st_other', ctypes.c_ubyte), - ('st_shndx', ctypes.c_uint16), - ('st_value', ctypes.c_uint64), - ('st_size', ctypes.c_uint64), +class Elf64_Sym(Struct): pass +Elf64_Sym._fields_ = [ + ('st_name', Elf64_Word), + ('st_info', ctypes.c_ubyte), + ('st_other', ctypes.c_ubyte), + ('st_shndx', Elf64_Section), + ('st_value', Elf64_Addr), + ('st_size', Elf64_Xword), ] - -Elf64_Sym = struct_c__SA_Elf64_Sym -class struct_c__SA_Elf32_Syminfo(Structure): - pass - -struct_c__SA_Elf32_Syminfo._pack_ = 1 # source:False -struct_c__SA_Elf32_Syminfo._fields_ = [ - ('si_boundto', ctypes.c_uint16), - ('si_flags', ctypes.c_uint16), +class Elf32_Syminfo(Struct): pass +Elf32_Syminfo._fields_ = [ + ('si_boundto', Elf32_Half), + ('si_flags', Elf32_Half), ] - -Elf32_Syminfo = struct_c__SA_Elf32_Syminfo -class struct_c__SA_Elf64_Syminfo(Structure): - pass - -struct_c__SA_Elf64_Syminfo._pack_ = 1 # source:False -struct_c__SA_Elf64_Syminfo._fields_ = [ - ('si_boundto', ctypes.c_uint16), - ('si_flags', ctypes.c_uint16), +class Elf64_Syminfo(Struct): pass +Elf64_Syminfo._fields_ = [ + ('si_boundto', Elf64_Half), + ('si_flags', Elf64_Half), ] - -Elf64_Syminfo = struct_c__SA_Elf64_Syminfo -class struct_c__SA_Elf32_Rel(Structure): - pass - -struct_c__SA_Elf32_Rel._pack_ = 1 # source:False -struct_c__SA_Elf32_Rel._fields_ = [ - ('r_offset', ctypes.c_uint32), - ('r_info', ctypes.c_uint32), +class Elf32_Rel(Struct): pass +Elf32_Rel._fields_ = [ + ('r_offset', Elf32_Addr), + ('r_info', Elf32_Word), ] - -Elf32_Rel = struct_c__SA_Elf32_Rel -class struct_c__SA_Elf64_Rel(Structure): - pass - -struct_c__SA_Elf64_Rel._pack_ = 1 # source:False -struct_c__SA_Elf64_Rel._fields_ = [ - ('r_offset', ctypes.c_uint64), - ('r_info', ctypes.c_uint64), +class Elf64_Rel(Struct): pass +Elf64_Rel._fields_ = [ + ('r_offset', Elf64_Addr), + ('r_info', Elf64_Xword), ] - -Elf64_Rel = struct_c__SA_Elf64_Rel -class struct_c__SA_Elf32_Rela(Structure): - pass - -struct_c__SA_Elf32_Rela._pack_ = 1 # source:False -struct_c__SA_Elf32_Rela._fields_ = [ - ('r_offset', ctypes.c_uint32), - ('r_info', ctypes.c_uint32), - ('r_addend', ctypes.c_int32), +class Elf32_Rela(Struct): pass +Elf32_Rela._fields_ = [ + ('r_offset', Elf32_Addr), + ('r_info', Elf32_Word), + ('r_addend', Elf32_Sword), ] - -Elf32_Rela = struct_c__SA_Elf32_Rela -class struct_c__SA_Elf64_Rela(Structure): - pass - -struct_c__SA_Elf64_Rela._pack_ = 1 # source:False -struct_c__SA_Elf64_Rela._fields_ = [ - ('r_offset', ctypes.c_uint64), - ('r_info', ctypes.c_uint64), - ('r_addend', ctypes.c_int64), +class Elf64_Rela(Struct): pass +Elf64_Rela._fields_ = [ + ('r_offset', Elf64_Addr), + ('r_info', Elf64_Xword), + ('r_addend', Elf64_Sxword), ] - -Elf64_Rela = struct_c__SA_Elf64_Rela Elf32_Relr = ctypes.c_uint32 Elf64_Relr = ctypes.c_uint64 -class struct_c__SA_Elf32_Phdr(Structure): - pass - -struct_c__SA_Elf32_Phdr._pack_ = 1 # source:False -struct_c__SA_Elf32_Phdr._fields_ = [ - ('p_type', ctypes.c_uint32), - ('p_offset', ctypes.c_uint32), - ('p_vaddr', ctypes.c_uint32), - ('p_paddr', ctypes.c_uint32), - ('p_filesz', ctypes.c_uint32), - ('p_memsz', ctypes.c_uint32), - ('p_flags', ctypes.c_uint32), - ('p_align', ctypes.c_uint32), +class Elf32_Phdr(Struct): pass +Elf32_Phdr._fields_ = [ + ('p_type', Elf32_Word), + ('p_offset', Elf32_Off), + ('p_vaddr', Elf32_Addr), + ('p_paddr', Elf32_Addr), + ('p_filesz', Elf32_Word), + ('p_memsz', Elf32_Word), + ('p_flags', Elf32_Word), + ('p_align', Elf32_Word), ] - -Elf32_Phdr = struct_c__SA_Elf32_Phdr -class struct_c__SA_Elf64_Phdr(Structure): - pass - -struct_c__SA_Elf64_Phdr._pack_ = 1 # source:False -struct_c__SA_Elf64_Phdr._fields_ = [ - ('p_type', ctypes.c_uint32), - ('p_flags', ctypes.c_uint32), - ('p_offset', ctypes.c_uint64), - ('p_vaddr', ctypes.c_uint64), - ('p_paddr', ctypes.c_uint64), - ('p_filesz', ctypes.c_uint64), - ('p_memsz', ctypes.c_uint64), - ('p_align', ctypes.c_uint64), +class Elf64_Phdr(Struct): pass +Elf64_Phdr._fields_ = [ + ('p_type', Elf64_Word), + ('p_flags', Elf64_Word), + ('p_offset', Elf64_Off), + ('p_vaddr', Elf64_Addr), + ('p_paddr', Elf64_Addr), + ('p_filesz', Elf64_Xword), + ('p_memsz', Elf64_Xword), + ('p_align', Elf64_Xword), ] - -Elf64_Phdr = struct_c__SA_Elf64_Phdr -class struct_c__SA_Elf32_Dyn(Structure): - pass - -class union_c__SA_Elf32_Dyn_d_un(Union): - pass - -union_c__SA_Elf32_Dyn_d_un._pack_ = 1 # source:False -union_c__SA_Elf32_Dyn_d_un._fields_ = [ - ('d_val', ctypes.c_uint32), - ('d_ptr', ctypes.c_uint32), +class Elf32_Dyn(Struct): pass +class Elf32_Dyn_d_un(ctypes.Union): pass +Elf32_Dyn_d_un._fields_ = [ + ('d_val', Elf32_Word), + ('d_ptr', Elf32_Addr), ] - -struct_c__SA_Elf32_Dyn._pack_ = 1 # source:False -struct_c__SA_Elf32_Dyn._fields_ = [ - ('d_tag', ctypes.c_int32), - ('d_un', union_c__SA_Elf32_Dyn_d_un), +Elf32_Dyn._fields_ = [ + ('d_tag', Elf32_Sword), + ('d_un', Elf32_Dyn_d_un), ] - -Elf32_Dyn = struct_c__SA_Elf32_Dyn -class struct_c__SA_Elf64_Dyn(Structure): - pass - -class union_c__SA_Elf64_Dyn_d_un(Union): - pass - -union_c__SA_Elf64_Dyn_d_un._pack_ = 1 # source:False -union_c__SA_Elf64_Dyn_d_un._fields_ = [ - ('d_val', ctypes.c_uint64), - ('d_ptr', ctypes.c_uint64), +class Elf64_Dyn(Struct): pass +class Elf64_Dyn_d_un(ctypes.Union): pass +Elf64_Dyn_d_un._fields_ = [ + ('d_val', Elf64_Xword), + ('d_ptr', Elf64_Addr), ] - -struct_c__SA_Elf64_Dyn._pack_ = 1 # source:False -struct_c__SA_Elf64_Dyn._fields_ = [ - ('d_tag', ctypes.c_int64), - ('d_un', union_c__SA_Elf64_Dyn_d_un), +Elf64_Dyn._fields_ = [ + ('d_tag', Elf64_Sxword), + ('d_un', Elf64_Dyn_d_un), ] - -Elf64_Dyn = struct_c__SA_Elf64_Dyn -class struct_c__SA_Elf32_Verdef(Structure): - pass - -struct_c__SA_Elf32_Verdef._pack_ = 1 # source:False -struct_c__SA_Elf32_Verdef._fields_ = [ - ('vd_version', ctypes.c_uint16), - ('vd_flags', ctypes.c_uint16), - ('vd_ndx', ctypes.c_uint16), - ('vd_cnt', ctypes.c_uint16), - ('vd_hash', ctypes.c_uint32), - ('vd_aux', ctypes.c_uint32), - ('vd_next', ctypes.c_uint32), +class Elf32_Verdef(Struct): pass +Elf32_Verdef._fields_ = [ + ('vd_version', Elf32_Half), + ('vd_flags', Elf32_Half), + ('vd_ndx', Elf32_Half), + ('vd_cnt', Elf32_Half), + ('vd_hash', Elf32_Word), + ('vd_aux', Elf32_Word), + ('vd_next', Elf32_Word), ] - -Elf32_Verdef = struct_c__SA_Elf32_Verdef -class struct_c__SA_Elf64_Verdef(Structure): - pass - -struct_c__SA_Elf64_Verdef._pack_ = 1 # source:False -struct_c__SA_Elf64_Verdef._fields_ = [ - ('vd_version', ctypes.c_uint16), - ('vd_flags', ctypes.c_uint16), - ('vd_ndx', ctypes.c_uint16), - ('vd_cnt', ctypes.c_uint16), - ('vd_hash', ctypes.c_uint32), - ('vd_aux', ctypes.c_uint32), - ('vd_next', ctypes.c_uint32), +class Elf64_Verdef(Struct): pass +Elf64_Verdef._fields_ = [ + ('vd_version', Elf64_Half), + ('vd_flags', Elf64_Half), + ('vd_ndx', Elf64_Half), + ('vd_cnt', Elf64_Half), + ('vd_hash', Elf64_Word), + ('vd_aux', Elf64_Word), + ('vd_next', Elf64_Word), ] - -Elf64_Verdef = struct_c__SA_Elf64_Verdef -class struct_c__SA_Elf32_Verdaux(Structure): - pass - -struct_c__SA_Elf32_Verdaux._pack_ = 1 # source:False -struct_c__SA_Elf32_Verdaux._fields_ = [ - ('vda_name', ctypes.c_uint32), - ('vda_next', ctypes.c_uint32), +class Elf32_Verdaux(Struct): pass +Elf32_Verdaux._fields_ = [ + ('vda_name', Elf32_Word), + ('vda_next', Elf32_Word), ] - -Elf32_Verdaux = struct_c__SA_Elf32_Verdaux -class struct_c__SA_Elf64_Verdaux(Structure): - pass - -struct_c__SA_Elf64_Verdaux._pack_ = 1 # source:False -struct_c__SA_Elf64_Verdaux._fields_ = [ - ('vda_name', ctypes.c_uint32), - ('vda_next', ctypes.c_uint32), +class Elf64_Verdaux(Struct): pass +Elf64_Verdaux._fields_ = [ + ('vda_name', Elf64_Word), + ('vda_next', Elf64_Word), ] - -Elf64_Verdaux = struct_c__SA_Elf64_Verdaux -class struct_c__SA_Elf32_Verneed(Structure): - pass - -struct_c__SA_Elf32_Verneed._pack_ = 1 # source:False -struct_c__SA_Elf32_Verneed._fields_ = [ - ('vn_version', ctypes.c_uint16), - ('vn_cnt', ctypes.c_uint16), - ('vn_file', ctypes.c_uint32), - ('vn_aux', ctypes.c_uint32), - ('vn_next', ctypes.c_uint32), +class Elf32_Verneed(Struct): pass +Elf32_Verneed._fields_ = [ + ('vn_version', Elf32_Half), + ('vn_cnt', Elf32_Half), + ('vn_file', Elf32_Word), + ('vn_aux', Elf32_Word), + ('vn_next', Elf32_Word), ] - -Elf32_Verneed = struct_c__SA_Elf32_Verneed -class struct_c__SA_Elf64_Verneed(Structure): - pass - -struct_c__SA_Elf64_Verneed._pack_ = 1 # source:False -struct_c__SA_Elf64_Verneed._fields_ = [ - ('vn_version', ctypes.c_uint16), - ('vn_cnt', ctypes.c_uint16), - ('vn_file', ctypes.c_uint32), - ('vn_aux', ctypes.c_uint32), - ('vn_next', ctypes.c_uint32), +class Elf64_Verneed(Struct): pass +Elf64_Verneed._fields_ = [ + ('vn_version', Elf64_Half), + ('vn_cnt', Elf64_Half), + ('vn_file', Elf64_Word), + ('vn_aux', Elf64_Word), + ('vn_next', Elf64_Word), ] - -Elf64_Verneed = struct_c__SA_Elf64_Verneed -class struct_c__SA_Elf32_Vernaux(Structure): - pass - -struct_c__SA_Elf32_Vernaux._pack_ = 1 # source:False -struct_c__SA_Elf32_Vernaux._fields_ = [ - ('vna_hash', ctypes.c_uint32), - ('vna_flags', ctypes.c_uint16), - ('vna_other', ctypes.c_uint16), - ('vna_name', ctypes.c_uint32), - ('vna_next', ctypes.c_uint32), +class Elf32_Vernaux(Struct): pass +Elf32_Vernaux._fields_ = [ + ('vna_hash', Elf32_Word), + ('vna_flags', Elf32_Half), + ('vna_other', Elf32_Half), + ('vna_name', Elf32_Word), + ('vna_next', Elf32_Word), ] - -Elf32_Vernaux = struct_c__SA_Elf32_Vernaux -class struct_c__SA_Elf64_Vernaux(Structure): - pass - -struct_c__SA_Elf64_Vernaux._pack_ = 1 # source:False -struct_c__SA_Elf64_Vernaux._fields_ = [ - ('vna_hash', ctypes.c_uint32), - ('vna_flags', ctypes.c_uint16), - ('vna_other', ctypes.c_uint16), - ('vna_name', ctypes.c_uint32), - ('vna_next', ctypes.c_uint32), +class Elf64_Vernaux(Struct): pass +Elf64_Vernaux._fields_ = [ + ('vna_hash', Elf64_Word), + ('vna_flags', Elf64_Half), + ('vna_other', Elf64_Half), + ('vna_name', Elf64_Word), + ('vna_next', Elf64_Word), ] - -Elf64_Vernaux = struct_c__SA_Elf64_Vernaux -class struct_c__SA_Elf32_auxv_t(Structure): - pass - -class union_c__SA_Elf32_auxv_t_a_un(Union): - pass - -union_c__SA_Elf32_auxv_t_a_un._pack_ = 1 # source:False -union_c__SA_Elf32_auxv_t_a_un._fields_ = [ - ('a_val', ctypes.c_uint32), +class Elf32_auxv_t(Struct): pass +uint32_t = ctypes.c_uint32 +class Elf32_auxv_t_a_un(ctypes.Union): pass +Elf32_auxv_t_a_un._fields_ = [ + ('a_val', uint32_t), ] - -struct_c__SA_Elf32_auxv_t._pack_ = 1 # source:False -struct_c__SA_Elf32_auxv_t._fields_ = [ - ('a_type', ctypes.c_uint32), - ('a_un', union_c__SA_Elf32_auxv_t_a_un), +Elf32_auxv_t._fields_ = [ + ('a_type', uint32_t), + ('a_un', Elf32_auxv_t_a_un), ] - -Elf32_auxv_t = struct_c__SA_Elf32_auxv_t -class struct_c__SA_Elf64_auxv_t(Structure): - pass - -class union_c__SA_Elf64_auxv_t_a_un(Union): - pass - -union_c__SA_Elf64_auxv_t_a_un._pack_ = 1 # source:False -union_c__SA_Elf64_auxv_t_a_un._fields_ = [ - ('a_val', ctypes.c_uint64), +class Elf64_auxv_t(Struct): pass +uint64_t = ctypes.c_uint64 +class Elf64_auxv_t_a_un(ctypes.Union): pass +Elf64_auxv_t_a_un._fields_ = [ + ('a_val', uint64_t), ] - -struct_c__SA_Elf64_auxv_t._pack_ = 1 # source:False -struct_c__SA_Elf64_auxv_t._fields_ = [ - ('a_type', ctypes.c_uint64), - ('a_un', union_c__SA_Elf64_auxv_t_a_un), +Elf64_auxv_t._fields_ = [ + ('a_type', uint64_t), + ('a_un', Elf64_auxv_t_a_un), ] - -Elf64_auxv_t = struct_c__SA_Elf64_auxv_t -class struct_c__SA_Elf32_Nhdr(Structure): - pass - -struct_c__SA_Elf32_Nhdr._pack_ = 1 # source:False -struct_c__SA_Elf32_Nhdr._fields_ = [ - ('n_namesz', ctypes.c_uint32), - ('n_descsz', ctypes.c_uint32), - ('n_type', ctypes.c_uint32), +class Elf32_Nhdr(Struct): pass +Elf32_Nhdr._fields_ = [ + ('n_namesz', Elf32_Word), + ('n_descsz', Elf32_Word), + ('n_type', Elf32_Word), ] - -Elf32_Nhdr = struct_c__SA_Elf32_Nhdr -class struct_c__SA_Elf64_Nhdr(Structure): - pass - -struct_c__SA_Elf64_Nhdr._pack_ = 1 # source:False -struct_c__SA_Elf64_Nhdr._fields_ = [ - ('n_namesz', ctypes.c_uint32), - ('n_descsz', ctypes.c_uint32), - ('n_type', ctypes.c_uint32), +class Elf64_Nhdr(Struct): pass +Elf64_Nhdr._fields_ = [ + ('n_namesz', Elf64_Word), + ('n_descsz', Elf64_Word), + ('n_type', Elf64_Word), ] - -Elf64_Nhdr = struct_c__SA_Elf64_Nhdr -class struct_c__SA_Elf32_Move(Structure): - pass - -struct_c__SA_Elf32_Move._pack_ = 1 # source:False -struct_c__SA_Elf32_Move._fields_ = [ - ('m_value', ctypes.c_uint64), - ('m_info', ctypes.c_uint32), - ('m_poffset', ctypes.c_uint32), - ('m_repeat', ctypes.c_uint16), - ('m_stride', ctypes.c_uint16), - ('PADDING_0', ctypes.c_ubyte * 4), +class Elf32_Move(Struct): pass +Elf32_Move._fields_ = [ + ('m_value', Elf32_Xword), + ('m_info', Elf32_Word), + ('m_poffset', Elf32_Word), + ('m_repeat', Elf32_Half), + ('m_stride', Elf32_Half), ] - -Elf32_Move = struct_c__SA_Elf32_Move -class struct_c__SA_Elf64_Move(Structure): - pass - -struct_c__SA_Elf64_Move._pack_ = 1 # source:False -struct_c__SA_Elf64_Move._fields_ = [ - ('m_value', ctypes.c_uint64), - ('m_info', ctypes.c_uint64), - ('m_poffset', ctypes.c_uint64), - ('m_repeat', ctypes.c_uint16), - ('m_stride', ctypes.c_uint16), - ('PADDING_0', ctypes.c_ubyte * 4), +class Elf64_Move(Struct): pass +Elf64_Move._fields_ = [ + ('m_value', Elf64_Xword), + ('m_info', Elf64_Xword), + ('m_poffset', Elf64_Xword), + ('m_repeat', Elf64_Half), + ('m_stride', Elf64_Half), ] - -Elf64_Move = struct_c__SA_Elf64_Move -class union_c__UA_Elf32_gptab(Union): - pass - -class struct_c__UA_Elf32_gptab_gt_header(Structure): - pass - -struct_c__UA_Elf32_gptab_gt_header._pack_ = 1 # source:False -struct_c__UA_Elf32_gptab_gt_header._fields_ = [ - ('gt_current_g_value', ctypes.c_uint32), - ('gt_unused', ctypes.c_uint32), +class Elf32_gptab(ctypes.Union): pass +class Elf32_gptab_gt_header(Struct): pass +Elf32_gptab_gt_header._fields_ = [ + ('gt_current_g_value', Elf32_Word), + ('gt_unused', Elf32_Word), ] - -class struct_c__UA_Elf32_gptab_gt_entry(Structure): - pass - -struct_c__UA_Elf32_gptab_gt_entry._pack_ = 1 # source:False -struct_c__UA_Elf32_gptab_gt_entry._fields_ = [ - ('gt_g_value', ctypes.c_uint32), - ('gt_bytes', ctypes.c_uint32), +class Elf32_gptab_gt_entry(Struct): pass +Elf32_gptab_gt_entry._fields_ = [ + ('gt_g_value', Elf32_Word), + ('gt_bytes', Elf32_Word), ] - -union_c__UA_Elf32_gptab._pack_ = 1 # source:False -union_c__UA_Elf32_gptab._fields_ = [ - ('gt_header', struct_c__UA_Elf32_gptab_gt_header), - ('gt_entry', struct_c__UA_Elf32_gptab_gt_entry), +Elf32_gptab._fields_ = [ + ('gt_header', Elf32_gptab_gt_header), + ('gt_entry', Elf32_gptab_gt_entry), ] - -Elf32_gptab = union_c__UA_Elf32_gptab -class struct_c__SA_Elf32_RegInfo(Structure): - pass - -struct_c__SA_Elf32_RegInfo._pack_ = 1 # source:False -struct_c__SA_Elf32_RegInfo._fields_ = [ - ('ri_gprmask', ctypes.c_uint32), - ('ri_cprmask', ctypes.c_uint32 * 4), - ('ri_gp_value', ctypes.c_int32), +class Elf32_RegInfo(Struct): pass +Elf32_RegInfo._fields_ = [ + ('ri_gprmask', Elf32_Word), + ('ri_cprmask', (Elf32_Word * 4)), + ('ri_gp_value', Elf32_Sword), ] - -Elf32_RegInfo = struct_c__SA_Elf32_RegInfo -class struct_c__SA_Elf_Options(Structure): - pass - -struct_c__SA_Elf_Options._pack_ = 1 # source:False -struct_c__SA_Elf_Options._fields_ = [ - ('kind', ctypes.c_ubyte), - ('size', ctypes.c_ubyte), - ('section', ctypes.c_uint16), - ('info', ctypes.c_uint32), +class Elf_Options(Struct): pass +Elf_Options._fields_ = [ + ('kind', ctypes.c_ubyte), + ('size', ctypes.c_ubyte), + ('section', Elf32_Section), + ('info', Elf32_Word), ] - -Elf_Options = struct_c__SA_Elf_Options -class struct_c__SA_Elf_Options_Hw(Structure): - pass - -struct_c__SA_Elf_Options_Hw._pack_ = 1 # source:False -struct_c__SA_Elf_Options_Hw._fields_ = [ - ('hwp_flags1', ctypes.c_uint32), - ('hwp_flags2', ctypes.c_uint32), +class Elf_Options_Hw(Struct): pass +Elf_Options_Hw._fields_ = [ + ('hwp_flags1', Elf32_Word), + ('hwp_flags2', Elf32_Word), ] - -Elf_Options_Hw = struct_c__SA_Elf_Options_Hw -class struct_c__SA_Elf32_Lib(Structure): - pass - -struct_c__SA_Elf32_Lib._pack_ = 1 # source:False -struct_c__SA_Elf32_Lib._fields_ = [ - ('l_name', ctypes.c_uint32), - ('l_time_stamp', ctypes.c_uint32), - ('l_checksum', ctypes.c_uint32), - ('l_version', ctypes.c_uint32), - ('l_flags', ctypes.c_uint32), +class Elf32_Lib(Struct): pass +Elf32_Lib._fields_ = [ + ('l_name', Elf32_Word), + ('l_time_stamp', Elf32_Word), + ('l_checksum', Elf32_Word), + ('l_version', Elf32_Word), + ('l_flags', Elf32_Word), ] - -Elf32_Lib = struct_c__SA_Elf32_Lib -class struct_c__SA_Elf64_Lib(Structure): - pass - -struct_c__SA_Elf64_Lib._pack_ = 1 # source:False -struct_c__SA_Elf64_Lib._fields_ = [ - ('l_name', ctypes.c_uint32), - ('l_time_stamp', ctypes.c_uint32), - ('l_checksum', ctypes.c_uint32), - ('l_version', ctypes.c_uint32), - ('l_flags', ctypes.c_uint32), +class Elf64_Lib(Struct): pass +Elf64_Lib._fields_ = [ + ('l_name', Elf64_Word), + ('l_time_stamp', Elf64_Word), + ('l_checksum', Elf64_Word), + ('l_version', Elf64_Word), + ('l_flags', Elf64_Word), ] - -Elf64_Lib = struct_c__SA_Elf64_Lib Elf32_Conflict = ctypes.c_uint32 -class struct_c__SA_Elf_MIPS_ABIFlags_v0(Structure): - pass - -struct_c__SA_Elf_MIPS_ABIFlags_v0._pack_ = 1 # source:False -struct_c__SA_Elf_MIPS_ABIFlags_v0._fields_ = [ - ('version', ctypes.c_uint16), - ('isa_level', ctypes.c_ubyte), - ('isa_rev', ctypes.c_ubyte), - ('gpr_size', ctypes.c_ubyte), - ('cpr1_size', ctypes.c_ubyte), - ('cpr2_size', ctypes.c_ubyte), - ('fp_abi', ctypes.c_ubyte), - ('isa_ext', ctypes.c_uint32), - ('ases', ctypes.c_uint32), - ('flags1', ctypes.c_uint32), - ('flags2', ctypes.c_uint32), +class Elf_MIPS_ABIFlags_v0(Struct): pass +Elf_MIPS_ABIFlags_v0._fields_ = [ + ('version', Elf32_Half), + ('isa_level', ctypes.c_ubyte), + ('isa_rev', ctypes.c_ubyte), + ('gpr_size', ctypes.c_ubyte), + ('cpr1_size', ctypes.c_ubyte), + ('cpr2_size', ctypes.c_ubyte), + ('fp_abi', ctypes.c_ubyte), + ('isa_ext', Elf32_Word), + ('ases', Elf32_Word), + ('flags1', Elf32_Word), + ('flags2', Elf32_Word), ] +_anonenum0 = CEnum(ctypes.c_uint32) +Val_GNU_MIPS_ABI_FP_ANY = _anonenum0.define('Val_GNU_MIPS_ABI_FP_ANY', 0) +Val_GNU_MIPS_ABI_FP_DOUBLE = _anonenum0.define('Val_GNU_MIPS_ABI_FP_DOUBLE', 1) +Val_GNU_MIPS_ABI_FP_SINGLE = _anonenum0.define('Val_GNU_MIPS_ABI_FP_SINGLE', 2) +Val_GNU_MIPS_ABI_FP_SOFT = _anonenum0.define('Val_GNU_MIPS_ABI_FP_SOFT', 3) +Val_GNU_MIPS_ABI_FP_OLD_64 = _anonenum0.define('Val_GNU_MIPS_ABI_FP_OLD_64', 4) +Val_GNU_MIPS_ABI_FP_XX = _anonenum0.define('Val_GNU_MIPS_ABI_FP_XX', 5) +Val_GNU_MIPS_ABI_FP_64 = _anonenum0.define('Val_GNU_MIPS_ABI_FP_64', 6) +Val_GNU_MIPS_ABI_FP_64A = _anonenum0.define('Val_GNU_MIPS_ABI_FP_64A', 7) +Val_GNU_MIPS_ABI_FP_MAX = _anonenum0.define('Val_GNU_MIPS_ABI_FP_MAX', 7) -Elf_MIPS_ABIFlags_v0 = struct_c__SA_Elf_MIPS_ABIFlags_v0 - -# values for enumeration 'c__Ea_Val_GNU_MIPS_ABI_FP_ANY' -c__Ea_Val_GNU_MIPS_ABI_FP_ANY__enumvalues = { - 0: 'Val_GNU_MIPS_ABI_FP_ANY', - 1: 'Val_GNU_MIPS_ABI_FP_DOUBLE', - 2: 'Val_GNU_MIPS_ABI_FP_SINGLE', - 3: 'Val_GNU_MIPS_ABI_FP_SOFT', - 4: 'Val_GNU_MIPS_ABI_FP_OLD_64', - 5: 'Val_GNU_MIPS_ABI_FP_XX', - 6: 'Val_GNU_MIPS_ABI_FP_64', - 7: 'Val_GNU_MIPS_ABI_FP_64A', - 7: 'Val_GNU_MIPS_ABI_FP_MAX', -} -Val_GNU_MIPS_ABI_FP_ANY = 0 -Val_GNU_MIPS_ABI_FP_DOUBLE = 1 -Val_GNU_MIPS_ABI_FP_SINGLE = 2 -Val_GNU_MIPS_ABI_FP_SOFT = 3 -Val_GNU_MIPS_ABI_FP_OLD_64 = 4 -Val_GNU_MIPS_ABI_FP_XX = 5 -Val_GNU_MIPS_ABI_FP_64 = 6 -Val_GNU_MIPS_ABI_FP_64A = 7 -Val_GNU_MIPS_ABI_FP_MAX = 7 -c__Ea_Val_GNU_MIPS_ABI_FP_ANY = ctypes.c_uint32 # enum -_UNISTD_H = 1 # macro -_POSIX_VERSION = 200809 # macro -__POSIX2_THIS_VERSION = 200809 # macro -_POSIX2_VERSION = 200809 # macro -_POSIX2_C_VERSION = 200809 # macro -_POSIX2_C_BIND = 200809 # macro -_POSIX2_C_DEV = 200809 # macro -_POSIX2_SW_DEV = 200809 # macro -_POSIX2_LOCALEDEF = 200809 # macro -_XOPEN_VERSION = 700 # macro -_XOPEN_XCU_VERSION = 4 # macro -_XOPEN_XPG2 = 1 # macro -_XOPEN_XPG3 = 1 # macro -_XOPEN_XPG4 = 1 # macro -_XOPEN_UNIX = 1 # macro -_XOPEN_ENH_I18N = 1 # macro -_XOPEN_LEGACY = 1 # macro -STDIN_FILENO = 0 # macro -STDOUT_FILENO = 1 # macro -STDERR_FILENO = 2 # macro -__ssize_t_defined = True # macro -__gid_t_defined = True # macro -__uid_t_defined = True # macro -__useconds_t_defined = True # macro -__pid_t_defined = True # macro -__intptr_t_defined = True # macro -__socklen_t_defined = True # macro -R_OK = 4 # macro -W_OK = 2 # macro -X_OK = 1 # macro -F_OK = 0 # macro -SEEK_SET = 0 # macro -SEEK_CUR = 1 # macro -SEEK_END = 2 # macro -L_SET = 0 # macro -L_INCR = 1 # macro -L_XTND = 2 # macro -F_ULOCK = 0 # macro -F_LOCK = 1 # macro -F_TLOCK = 2 # macro -F_TEST = 3 # macro ssize_t = ctypes.c_int64 gid_t = ctypes.c_uint32 uid_t = ctypes.c_uint32 @@ -4304,1887 +640,3606 @@ useconds_t = ctypes.c_uint32 pid_t = ctypes.c_int32 intptr_t = ctypes.c_int64 socklen_t = ctypes.c_uint32 -try: - access = _libraries['libc'].access - access.restype = ctypes.c_int32 - access.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - faccessat = _libraries['libc'].faccessat - faccessat.restype = ctypes.c_int32 - faccessat.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32, ctypes.c_int32] -except AttributeError: - pass -try: - lseek = _libraries['libc'].lseek - lseek.restype = __off_t - lseek.argtypes = [ctypes.c_int32, __off_t, ctypes.c_int32] -except AttributeError: - pass -try: - close = _libraries['libc'].close - close.restype = ctypes.c_int32 - close.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - closefrom = _libraries['libc'].closefrom - closefrom.restype = None - closefrom.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - read = _libraries['libc'].read - read.restype = ssize_t - read.argtypes = [ctypes.c_int32, ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - write = _libraries['libc'].write - write.restype = ssize_t - write.argtypes = [ctypes.c_int32, ctypes.POINTER(None), size_t] -except AttributeError: - pass -try: - pread = _libraries['libc'].pread - pread.restype = ssize_t - pread.argtypes = [ctypes.c_int32, ctypes.POINTER(None), size_t, __off_t] -except AttributeError: - pass -try: - pwrite = _libraries['libc'].pwrite - pwrite.restype = ssize_t - pwrite.argtypes = [ctypes.c_int32, ctypes.POINTER(None), size_t, __off_t] -except AttributeError: - pass -try: - pipe = _libraries['libc'].pipe - pipe.restype = ctypes.c_int32 - pipe.argtypes = [ctypes.c_int32 * 2] -except AttributeError: - pass -try: - alarm = _libraries['libc'].alarm - alarm.restype = ctypes.c_uint32 - alarm.argtypes = [ctypes.c_uint32] -except AttributeError: - pass -try: - sleep = _libraries['libc'].sleep - sleep.restype = ctypes.c_uint32 - sleep.argtypes = [ctypes.c_uint32] -except AttributeError: - pass +# extern int access(const char *__name, int __type) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (access:=dll.access).restype, access.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern int faccessat(int __fd, const char *__file, int __type, int __flag) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (faccessat:=dll.faccessat).restype, faccessat.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32, ctypes.c_int32] +except AttributeError: pass + +# extern __off_t lseek(int __fd, __off_t __offset, int __whence) __attribute__((nothrow)) +try: (lseek:=dll.lseek).restype, lseek.argtypes = ctypes.c_int64, [ctypes.c_int32, ctypes.c_int64, ctypes.c_int32] +except AttributeError: pass + +# extern int close(int __fd) +try: (close:=dll.close).restype, close.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern void closefrom(int __lowfd) __attribute__((nothrow)) +try: (closefrom:=dll.closefrom).restype, closefrom.argtypes = None, [ctypes.c_int32] +except AttributeError: pass + +# extern ssize_t read(int __fd, void *__buf, size_t __nbytes) +try: (read:=dll.read).restype, read.argtypes = ssize_t, [ctypes.c_int32, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern ssize_t write(int __fd, const void *__buf, size_t __n) +try: (write:=dll.write).restype, write.argtypes = ssize_t, [ctypes.c_int32, ctypes.c_void_p, size_t] +except AttributeError: pass + +# extern ssize_t pread(int __fd, void *__buf, size_t __nbytes, __off_t __offset) +try: (pread:=dll.pread).restype, pread.argtypes = ssize_t, [ctypes.c_int32, ctypes.c_void_p, size_t, ctypes.c_int64] +except AttributeError: pass + +# extern ssize_t pwrite(int __fd, const void *__buf, size_t __n, __off_t __offset) +try: (pwrite:=dll.pwrite).restype, pwrite.argtypes = ssize_t, [ctypes.c_int32, ctypes.c_void_p, size_t, ctypes.c_int64] +except AttributeError: pass + +# extern int pipe(int __pipedes[2]) __attribute__((nothrow)) +try: (pipe:=dll.pipe).restype, pipe.argtypes = ctypes.c_int32, [(ctypes.c_int32 * 2)] +except AttributeError: pass + +# extern unsigned int alarm(unsigned int __seconds) __attribute__((nothrow)) +try: (alarm:=dll.alarm).restype, alarm.argtypes = ctypes.c_uint32, [ctypes.c_uint32] +except AttributeError: pass + +# extern unsigned int sleep(unsigned int __seconds) +try: (sleep:=dll.sleep).restype, sleep.argtypes = ctypes.c_uint32, [ctypes.c_uint32] +except AttributeError: pass + __useconds_t = ctypes.c_uint32 -try: - ualarm = _libraries['libc'].ualarm - ualarm.restype = __useconds_t - ualarm.argtypes = [__useconds_t, __useconds_t] -except AttributeError: - pass -try: - usleep = _libraries['libc'].usleep - usleep.restype = ctypes.c_int32 - usleep.argtypes = [__useconds_t] -except AttributeError: - pass -try: - pause = _libraries['libc'].pause - pause.restype = ctypes.c_int32 - pause.argtypes = [] -except AttributeError: - pass +# extern __useconds_t ualarm(__useconds_t __value, __useconds_t __interval) __attribute__((nothrow)) +try: (ualarm:=dll.ualarm).restype, ualarm.argtypes = ctypes.c_uint32, [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: pass + +# extern int usleep(__useconds_t __useconds) +try: (usleep:=dll.usleep).restype, usleep.argtypes = ctypes.c_int32, [ctypes.c_uint32] +except AttributeError: pass + +# extern int pause(void) +try: (pause:=dll.pause).restype, pause.argtypes = ctypes.c_int32, [] +except AttributeError: pass + __uid_t = ctypes.c_uint32 __gid_t = ctypes.c_uint32 -try: - chown = _libraries['libc'].chown - chown.restype = ctypes.c_int32 - chown.argtypes = [ctypes.POINTER(ctypes.c_char), __uid_t, __gid_t] -except AttributeError: - pass -try: - fchown = _libraries['libc'].fchown - fchown.restype = ctypes.c_int32 - fchown.argtypes = [ctypes.c_int32, __uid_t, __gid_t] -except AttributeError: - pass -try: - lchown = _libraries['libc'].lchown - lchown.restype = ctypes.c_int32 - lchown.argtypes = [ctypes.POINTER(ctypes.c_char), __uid_t, __gid_t] -except AttributeError: - pass -try: - fchownat = _libraries['libc'].fchownat - fchownat.restype = ctypes.c_int32 - fchownat.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), __uid_t, __gid_t, ctypes.c_int32] -except AttributeError: - pass -try: - chdir = _libraries['libc'].chdir - chdir.restype = ctypes.c_int32 - chdir.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - fchdir = _libraries['libc'].fchdir - fchdir.restype = ctypes.c_int32 - fchdir.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - getcwd = _libraries['libc'].getcwd - getcwd.restype = ctypes.POINTER(ctypes.c_char) - getcwd.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - getwd = _libraries['libc'].getwd - getwd.restype = ctypes.POINTER(ctypes.c_char) - getwd.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - dup = _libraries['libc'].dup - dup.restype = ctypes.c_int32 - dup.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - dup2 = _libraries['libc'].dup2 - dup2.restype = ctypes.c_int32 - dup2.argtypes = [ctypes.c_int32, ctypes.c_int32] -except AttributeError: - pass -__environ = ctypes.POINTER(ctypes.POINTER(ctypes.c_char))() # Variable ctypes.POINTER(ctypes.POINTER(ctypes.c_char)) -try: - execve = _libraries['libc'].execve - execve.restype = ctypes.c_int32 - execve.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char) * 0, ctypes.POINTER(ctypes.c_char) * 0] -except AttributeError: - pass -try: - fexecve = _libraries['libc'].fexecve - fexecve.restype = ctypes.c_int32 - fexecve.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char) * 0, ctypes.POINTER(ctypes.c_char) * 0] -except AttributeError: - pass -try: - execv = _libraries['libc'].execv - execv.restype = ctypes.c_int32 - execv.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char) * 0] -except AttributeError: - pass -try: - execle = _libraries['libc'].execle - execle.restype = ctypes.c_int32 - execle.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - execl = _libraries['libc'].execl - execl.restype = ctypes.c_int32 - execl.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - execvp = _libraries['libc'].execvp - execvp.restype = ctypes.c_int32 - execvp.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char) * 0] -except AttributeError: - pass -try: - execlp = _libraries['libc'].execlp - execlp.restype = ctypes.c_int32 - execlp.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - nice = _libraries['libc'].nice - nice.restype = ctypes.c_int32 - nice.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - _exit = _libraries['libc']._exit - _exit.restype = None - _exit.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - pathconf = _libraries['libc'].pathconf - pathconf.restype = ctypes.c_int64 - pathconf.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - fpathconf = _libraries['libc'].fpathconf - fpathconf.restype = ctypes.c_int64 - fpathconf.argtypes = [ctypes.c_int32, ctypes.c_int32] -except AttributeError: - pass -try: - sysconf = _libraries['libc'].sysconf - sysconf.restype = ctypes.c_int64 - sysconf.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - confstr = _libraries['libc'].confstr - confstr.restype = size_t - confstr.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass +# extern int chown(const char *__file, __uid_t __owner, __gid_t __group) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (chown:=dll.chown).restype, chown.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: pass + +# extern int fchown(int __fd, __uid_t __owner, __gid_t __group) __attribute__((nothrow)) +try: (fchown:=dll.fchown).restype, fchown.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: pass + +# extern int lchown(const char *__file, __uid_t __owner, __gid_t __group) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (lchown:=dll.lchown).restype, lchown.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: pass + +# extern int fchownat(int __fd, const char *__file, __uid_t __owner, __gid_t __group, int __flag) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (fchownat:=dll.fchownat).restype, fchownat.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_int32] +except AttributeError: pass + +# extern int chdir(const char *__path) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (chdir:=dll.chdir).restype, chdir.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int fchdir(int __fd) __attribute__((nothrow)) +try: (fchdir:=dll.fchdir).restype, fchdir.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern char *getcwd(char *__buf, size_t __size) __attribute__((nothrow)) +try: (getcwd:=dll.getcwd).restype, getcwd.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern char *getwd(char *__buf) __attribute__((nothrow)) __attribute__((nonnull(1))) __attribute__((deprecated(""))) +try: (getwd:=dll.getwd).restype, getwd.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int dup(int __fd) __attribute__((nothrow)) +try: (dup:=dll.dup).restype, dup.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern int dup2(int __fd, int __fd2) __attribute__((nothrow)) +try: (dup2:=dll.dup2).restype, dup2.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_int32] +except AttributeError: pass + +try: __environ = ctypes.POINTER(ctypes.POINTER(ctypes.c_char)).in_dll(dll, '__environ') +except (ValueError,AttributeError): pass +# extern int execve(const char *__path, char *const __argv[], char *const __envp[]) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (execve:=dll.execve).restype, execve.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), (ctypes.POINTER(ctypes.c_char) * 0), (ctypes.POINTER(ctypes.c_char) * 0)] +except AttributeError: pass + +# extern int fexecve(int __fd, char *const __argv[], char *const __envp[]) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (fexecve:=dll.fexecve).restype, fexecve.argtypes = ctypes.c_int32, [ctypes.c_int32, (ctypes.POINTER(ctypes.c_char) * 0), (ctypes.POINTER(ctypes.c_char) * 0)] +except AttributeError: pass + +# extern int execv(const char *__path, char *const __argv[]) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (execv:=dll.execv).restype, execv.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), (ctypes.POINTER(ctypes.c_char) * 0)] +except AttributeError: pass + +# extern int execle(const char *__path, const char *__arg, ...) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (execle:=dll.execle).restype, execle.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int execl(const char *__path, const char *__arg, ...) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (execl:=dll.execl).restype, execl.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int execvp(const char *__file, char *const __argv[]) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (execvp:=dll.execvp).restype, execvp.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), (ctypes.POINTER(ctypes.c_char) * 0)] +except AttributeError: pass + +# extern int execlp(const char *__file, const char *__arg, ...) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (execlp:=dll.execlp).restype, execlp.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int nice(int __inc) __attribute__((nothrow)) +try: (nice:=dll.nice).restype, nice.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern void _exit(int __status) +try: (_exit:=dll._exit).restype, _exit.argtypes = None, [ctypes.c_int32] +except AttributeError: pass + +# extern long pathconf(const char *__path, int __name) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (pathconf:=dll.pathconf).restype, pathconf.argtypes = ctypes.c_int64, [ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern long fpathconf(int __fd, int __name) __attribute__((nothrow)) +try: (fpathconf:=dll.fpathconf).restype, fpathconf.argtypes = ctypes.c_int64, [ctypes.c_int32, ctypes.c_int32] +except AttributeError: pass + +# extern long sysconf(int __name) __attribute__((nothrow)) +try: (sysconf:=dll.sysconf).restype, sysconf.argtypes = ctypes.c_int64, [ctypes.c_int32] +except AttributeError: pass + +# extern size_t confstr(int __name, char *__buf, size_t __len) __attribute__((nothrow)) +try: (confstr:=dll.confstr).restype, confstr.argtypes = size_t, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + __pid_t = ctypes.c_int32 -try: - getpid = _libraries['libc'].getpid - getpid.restype = __pid_t - getpid.argtypes = [] -except AttributeError: - pass -try: - getppid = _libraries['libc'].getppid - getppid.restype = __pid_t - getppid.argtypes = [] -except AttributeError: - pass -try: - getpgrp = _libraries['libc'].getpgrp - getpgrp.restype = __pid_t - getpgrp.argtypes = [] -except AttributeError: - pass -try: - __getpgid = _libraries['libc'].__getpgid - __getpgid.restype = __pid_t - __getpgid.argtypes = [__pid_t] -except AttributeError: - pass -try: - getpgid = _libraries['libc'].getpgid - getpgid.restype = __pid_t - getpgid.argtypes = [__pid_t] -except AttributeError: - pass -try: - setpgid = _libraries['libc'].setpgid - setpgid.restype = ctypes.c_int32 - setpgid.argtypes = [__pid_t, __pid_t] -except AttributeError: - pass -try: - setpgrp = _libraries['libc'].setpgrp - setpgrp.restype = ctypes.c_int32 - setpgrp.argtypes = [] -except AttributeError: - pass -try: - setsid = _libraries['libc'].setsid - setsid.restype = __pid_t - setsid.argtypes = [] -except AttributeError: - pass -try: - getsid = _libraries['libc'].getsid - getsid.restype = __pid_t - getsid.argtypes = [__pid_t] -except AttributeError: - pass -try: - getuid = _libraries['libc'].getuid - getuid.restype = __uid_t - getuid.argtypes = [] -except AttributeError: - pass -try: - geteuid = _libraries['libc'].geteuid - geteuid.restype = __uid_t - geteuid.argtypes = [] -except AttributeError: - pass -try: - getgid = _libraries['libc'].getgid - getgid.restype = __gid_t - getgid.argtypes = [] -except AttributeError: - pass -try: - getegid = _libraries['libc'].getegid - getegid.restype = __gid_t - getegid.argtypes = [] -except AttributeError: - pass -try: - getgroups = _libraries['libc'].getgroups - getgroups.restype = ctypes.c_int32 - getgroups.argtypes = [ctypes.c_int32, ctypes.c_uint32 * 0] -except AttributeError: - pass -try: - setuid = _libraries['libc'].setuid - setuid.restype = ctypes.c_int32 - setuid.argtypes = [__uid_t] -except AttributeError: - pass -try: - setreuid = _libraries['libc'].setreuid - setreuid.restype = ctypes.c_int32 - setreuid.argtypes = [__uid_t, __uid_t] -except AttributeError: - pass -try: - seteuid = _libraries['libc'].seteuid - seteuid.restype = ctypes.c_int32 - seteuid.argtypes = [__uid_t] -except AttributeError: - pass -try: - setgid = _libraries['libc'].setgid - setgid.restype = ctypes.c_int32 - setgid.argtypes = [__gid_t] -except AttributeError: - pass -try: - setregid = _libraries['libc'].setregid - setregid.restype = ctypes.c_int32 - setregid.argtypes = [__gid_t, __gid_t] -except AttributeError: - pass -try: - setegid = _libraries['libc'].setegid - setegid.restype = ctypes.c_int32 - setegid.argtypes = [__gid_t] -except AttributeError: - pass -try: - fork = _libraries['libc'].fork - fork.restype = __pid_t - fork.argtypes = [] -except AttributeError: - pass -try: - vfork = _libraries['libc'].vfork - vfork.restype = ctypes.c_int32 - vfork.argtypes = [] -except AttributeError: - pass -try: - ttyname = _libraries['libc'].ttyname - ttyname.restype = ctypes.POINTER(ctypes.c_char) - ttyname.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - ttyname_r = _libraries['libc'].ttyname_r - ttyname_r.restype = ctypes.c_int32 - ttyname_r.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - isatty = _libraries['libc'].isatty - isatty.restype = ctypes.c_int32 - isatty.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - ttyslot = _libraries['libc'].ttyslot - ttyslot.restype = ctypes.c_int32 - ttyslot.argtypes = [] -except AttributeError: - pass -try: - link = _libraries['libc'].link - link.restype = ctypes.c_int32 - link.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - linkat = _libraries['libc'].linkat - linkat.restype = ctypes.c_int32 - linkat.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - symlink = _libraries['libc'].symlink - symlink.restype = ctypes.c_int32 - symlink.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - readlink = _libraries['libc'].readlink - readlink.restype = ssize_t - readlink.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - symlinkat = _libraries['libc'].symlinkat - symlinkat.restype = ctypes.c_int32 - symlinkat.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int32, ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - readlinkat = _libraries['libc'].readlinkat - readlinkat.restype = ssize_t - readlinkat.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - unlink = _libraries['libc'].unlink - unlink.restype = ctypes.c_int32 - unlink.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - unlinkat = _libraries['libc'].unlinkat - unlinkat.restype = ctypes.c_int32 - unlinkat.argtypes = [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32] -except AttributeError: - pass -try: - rmdir = _libraries['libc'].rmdir - rmdir.restype = ctypes.c_int32 - rmdir.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - tcgetpgrp = _libraries['libc'].tcgetpgrp - tcgetpgrp.restype = __pid_t - tcgetpgrp.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - tcsetpgrp = _libraries['libc'].tcsetpgrp - tcsetpgrp.restype = ctypes.c_int32 - tcsetpgrp.argtypes = [ctypes.c_int32, __pid_t] -except AttributeError: - pass -try: - getlogin = _libraries['libc'].getlogin - getlogin.restype = ctypes.POINTER(ctypes.c_char) - getlogin.argtypes = [] -except AttributeError: - pass -try: - getlogin_r = _libraries['libc'].getlogin_r - getlogin_r.restype = ctypes.c_int32 - getlogin_r.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - setlogin = _libraries['libc'].setlogin - setlogin.restype = ctypes.c_int32 - setlogin.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - gethostname = _libraries['libc'].gethostname - gethostname.restype = ctypes.c_int32 - gethostname.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - sethostname = _libraries['libc'].sethostname - sethostname.restype = ctypes.c_int32 - sethostname.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - sethostid = _libraries['libc'].sethostid - sethostid.restype = ctypes.c_int32 - sethostid.argtypes = [ctypes.c_int64] -except AttributeError: - pass -try: - getdomainname = _libraries['libc'].getdomainname - getdomainname.restype = ctypes.c_int32 - getdomainname.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - setdomainname = _libraries['libc'].setdomainname - setdomainname.restype = ctypes.c_int32 - setdomainname.argtypes = [ctypes.POINTER(ctypes.c_char), size_t] -except AttributeError: - pass -try: - vhangup = _libraries['libc'].vhangup - vhangup.restype = ctypes.c_int32 - vhangup.argtypes = [] -except AttributeError: - pass -try: - revoke = _libraries['libc'].revoke - revoke.restype = ctypes.c_int32 - revoke.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - profil = _libraries['libc'].profil - profil.restype = ctypes.c_int32 - profil.argtypes = [ctypes.POINTER(ctypes.c_uint16), size_t, size_t, ctypes.c_uint32] -except AttributeError: - pass -try: - acct = _libraries['libc'].acct - acct.restype = ctypes.c_int32 - acct.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - getusershell = _libraries['libc'].getusershell - getusershell.restype = ctypes.POINTER(ctypes.c_char) - getusershell.argtypes = [] -except AttributeError: - pass -try: - endusershell = _libraries['libc'].endusershell - endusershell.restype = None - endusershell.argtypes = [] -except AttributeError: - pass -try: - setusershell = _libraries['libc'].setusershell - setusershell.restype = None - setusershell.argtypes = [] -except AttributeError: - pass -try: - daemon = _libraries['libc'].daemon - daemon.restype = ctypes.c_int32 - daemon.argtypes = [ctypes.c_int32, ctypes.c_int32] -except AttributeError: - pass -try: - chroot = _libraries['libc'].chroot - chroot.restype = ctypes.c_int32 - chroot.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - getpass = _libraries['libc'].getpass - getpass.restype = ctypes.POINTER(ctypes.c_char) - getpass.argtypes = [ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - fsync = _libraries['libc'].fsync - fsync.restype = ctypes.c_int32 - fsync.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - gethostid = _libraries['libc'].gethostid - gethostid.restype = ctypes.c_int64 - gethostid.argtypes = [] -except AttributeError: - pass -try: - sync = _libraries['libc'].sync - sync.restype = None - sync.argtypes = [] -except AttributeError: - pass -try: - getpagesize = _libraries['libc'].getpagesize - getpagesize.restype = ctypes.c_int32 - getpagesize.argtypes = [] -except AttributeError: - pass -try: - getdtablesize = _libraries['libc'].getdtablesize - getdtablesize.restype = ctypes.c_int32 - getdtablesize.argtypes = [] -except AttributeError: - pass -try: - truncate = _libraries['libc'].truncate - truncate.restype = ctypes.c_int32 - truncate.argtypes = [ctypes.POINTER(ctypes.c_char), __off_t] -except AttributeError: - pass -try: - ftruncate = _libraries['libc'].ftruncate - ftruncate.restype = ctypes.c_int32 - ftruncate.argtypes = [ctypes.c_int32, __off_t] -except AttributeError: - pass -try: - brk = _libraries['libc'].brk - brk.restype = ctypes.c_int32 - brk.argtypes = [ctypes.POINTER(None)] -except AttributeError: - pass -try: - sbrk = _libraries['libc'].sbrk - sbrk.restype = ctypes.POINTER(None) - sbrk.argtypes = [intptr_t] -except AttributeError: - pass -try: - syscall = _libraries['libc'].syscall - syscall.restype = ctypes.c_int64 - syscall.argtypes = [ctypes.c_int64] -except AttributeError: - pass -try: - lockf = _libraries['libc'].lockf - lockf.restype = ctypes.c_int32 - lockf.argtypes = [ctypes.c_int32, ctypes.c_int32, __off_t] -except AttributeError: - pass -try: - fdatasync = _libraries['libc'].fdatasync - fdatasync.restype = ctypes.c_int32 - fdatasync.argtypes = [ctypes.c_int32] -except AttributeError: - pass -try: - crypt = _libraries['libc'].crypt - crypt.restype = ctypes.POINTER(ctypes.c_char) - crypt.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] -except AttributeError: - pass -try: - getentropy = _libraries['libc'].getentropy - getentropy.restype = ctypes.c_int32 - getentropy.argtypes = [ctypes.POINTER(None), size_t] -except AttributeError: - pass -__ASM_GENERIC_MMAN_COMMON_H = True # macro -PROT_READ = 0x1 # macro -PROT_WRITE = 0x2 # macro -PROT_EXEC = 0x4 # macro -PROT_SEM = 0x8 # macro -PROT_NONE = 0x0 # macro -PROT_GROWSDOWN = 0x01000000 # macro -PROT_GROWSUP = 0x02000000 # macro -MAP_TYPE = 0x0f # macro -MAP_FIXED = 0x10 # macro -MAP_ANONYMOUS = 0x20 # macro -MAP_POPULATE = 0x008000 # macro -MAP_NONBLOCK = 0x010000 # macro -MAP_STACK = 0x020000 # macro -MAP_HUGETLB = 0x040000 # macro -MAP_SYNC = 0x080000 # macro -MAP_FIXED_NOREPLACE = 0x100000 # macro -MAP_UNINITIALIZED = 0x4000000 # macro -MLOCK_ONFAULT = 0x01 # macro -MS_ASYNC = 1 # macro -MS_INVALIDATE = 2 # macro -MS_SYNC = 4 # macro -MADV_NORMAL = 0 # macro -MADV_RANDOM = 1 # macro -MADV_SEQUENTIAL = 2 # macro -MADV_WILLNEED = 3 # macro -MADV_DONTNEED = 4 # macro -MADV_FREE = 8 # macro -MADV_REMOVE = 9 # macro -MADV_DONTFORK = 10 # macro -MADV_DOFORK = 11 # macro -MADV_HWPOISON = 100 # macro -MADV_SOFT_OFFLINE = 101 # macro -MADV_MERGEABLE = 12 # macro -MADV_UNMERGEABLE = 13 # macro -MADV_HUGEPAGE = 14 # macro -MADV_NOHUGEPAGE = 15 # macro -MADV_DONTDUMP = 16 # macro -MADV_DODUMP = 17 # macro -MADV_WIPEONFORK = 18 # macro -MADV_KEEPONFORK = 19 # macro -MADV_COLD = 20 # macro -MADV_PAGEOUT = 21 # macro -MADV_POPULATE_READ = 22 # macro -MADV_POPULATE_WRITE = 23 # macro -MADV_DONTNEED_LOCKED = 24 # macro -MADV_COLLAPSE = 25 # macro -MAP_FILE = 0 # macro -PKEY_DISABLE_ACCESS = 0x1 # macro -PKEY_DISABLE_WRITE = 0x2 # macro -PKEY_ACCESS_MASK = (0x1|0x2) # macro -__all__ = \ - ['AT_BASE', 'AT_BASE_PLATFORM', 'AT_CLKTCK', 'AT_DCACHEBSIZE', - 'AT_EGID', 'AT_ENTRY', 'AT_EUID', 'AT_EXECFD', 'AT_EXECFN', - 'AT_FLAGS', 'AT_FPUCW', 'AT_GID', 'AT_HWCAP', 'AT_HWCAP2', - 'AT_HWCAP3', 'AT_HWCAP4', 'AT_ICACHEBSIZE', 'AT_IGNORE', - 'AT_IGNOREPPC', 'AT_L1D_CACHEGEOMETRY', 'AT_L1D_CACHESHAPE', - 'AT_L1D_CACHESIZE', 'AT_L1I_CACHEGEOMETRY', 'AT_L1I_CACHESHAPE', - 'AT_L1I_CACHESIZE', 'AT_L2_CACHEGEOMETRY', 'AT_L2_CACHESHAPE', - 'AT_L2_CACHESIZE', 'AT_L3_CACHEGEOMETRY', 'AT_L3_CACHESHAPE', - 'AT_L3_CACHESIZE', 'AT_MINSIGSTKSZ', 'AT_NOTELF', 'AT_NULL', - 'AT_PAGESZ', 'AT_PHDR', 'AT_PHENT', 'AT_PHNUM', 'AT_PLATFORM', - 'AT_RANDOM', 'AT_RSEQ_ALIGN', 'AT_RSEQ_FEATURE_SIZE', 'AT_SECURE', - 'AT_SYSINFO', 'AT_SYSINFO_EHDR', 'AT_UCACHEBSIZE', 'AT_UID', - 'DF_1_CONFALT', 'DF_1_DIRECT', 'DF_1_DISPRELDNE', - 'DF_1_DISPRELPND', 'DF_1_EDITED', 'DF_1_ENDFILTEE', 'DF_1_GLOBAL', - 'DF_1_GLOBAUDIT', 'DF_1_GROUP', 'DF_1_IGNMULDEF', - 'DF_1_INITFIRST', 'DF_1_INTERPOSE', 'DF_1_KMOD', 'DF_1_LOADFLTR', - 'DF_1_NOCOMMON', 'DF_1_NODEFLIB', 'DF_1_NODELETE', - 'DF_1_NODIRECT', 'DF_1_NODUMP', 'DF_1_NOHDR', 'DF_1_NOKSYMS', - 'DF_1_NOOPEN', 'DF_1_NORELOC', 'DF_1_NOW', 'DF_1_ORIGIN', - 'DF_1_PIE', 'DF_1_SINGLETON', 'DF_1_STUB', 'DF_1_SYMINTPOSE', - 'DF_1_TRANS', 'DF_1_WEAKFILTER', 'DF_BIND_NOW', 'DF_ORIGIN', - 'DF_P1_GROUPPERM', 'DF_P1_LAZYLOAD', 'DF_STATIC_TLS', - 'DF_SYMBOLIC', 'DF_TEXTREL', 'DTF_1_CONFEXP', 'DTF_1_PARINIT', - 'DT_AARCH64_BTI_PLT', 'DT_AARCH64_NUM', 'DT_AARCH64_PAC_PLT', - 'DT_AARCH64_VARIANT_PCS', 'DT_ADDRNUM', 'DT_ADDRRNGHI', - 'DT_ADDRRNGLO', 'DT_ALPHA_NUM', 'DT_ALPHA_PLTRO', 'DT_AUDIT', - 'DT_AUXILIARY', 'DT_BIND_NOW', 'DT_CHECKSUM', 'DT_CONFIG', - 'DT_DEBUG', 'DT_DEPAUDIT', 'DT_ENCODING', 'DT_EXTRANUM', - 'DT_FEATURE_1', 'DT_FILTER', 'DT_FINI', 'DT_FINI_ARRAY', - 'DT_FINI_ARRAYSZ', 'DT_FLAGS', 'DT_FLAGS_1', 'DT_GNU_CONFLICT', - 'DT_GNU_CONFLICTSZ', 'DT_GNU_HASH', 'DT_GNU_LIBLIST', - 'DT_GNU_LIBLISTSZ', 'DT_GNU_PRELINKED', 'DT_HASH', 'DT_HIOS', - 'DT_HIPROC', 'DT_IA_64_NUM', 'DT_IA_64_PLT_RESERVE', 'DT_INIT', - 'DT_INIT_ARRAY', 'DT_INIT_ARRAYSZ', 'DT_JMPREL', 'DT_LOOS', - 'DT_LOPROC', 'DT_MIPS_AUX_DYNAMIC', 'DT_MIPS_BASE_ADDRESS', - 'DT_MIPS_COMPACT_SIZE', 'DT_MIPS_CONFLICT', 'DT_MIPS_CONFLICTNO', - 'DT_MIPS_CXX_FLAGS', 'DT_MIPS_DELTA_CLASS', - 'DT_MIPS_DELTA_CLASSSYM', 'DT_MIPS_DELTA_CLASSSYM_NO', - 'DT_MIPS_DELTA_CLASS_NO', 'DT_MIPS_DELTA_INSTANCE', - 'DT_MIPS_DELTA_INSTANCE_NO', 'DT_MIPS_DELTA_RELOC', - 'DT_MIPS_DELTA_RELOC_NO', 'DT_MIPS_DELTA_SYM', - 'DT_MIPS_DELTA_SYM_NO', 'DT_MIPS_DYNSTR_ALIGN', 'DT_MIPS_FLAGS', - 'DT_MIPS_GOTSYM', 'DT_MIPS_GP_VALUE', 'DT_MIPS_HIDDEN_GOTIDX', - 'DT_MIPS_HIPAGENO', 'DT_MIPS_ICHECKSUM', 'DT_MIPS_INTERFACE', - 'DT_MIPS_INTERFACE_SIZE', 'DT_MIPS_IVERSION', 'DT_MIPS_LIBLIST', - 'DT_MIPS_LIBLISTNO', 'DT_MIPS_LOCALPAGE_GOTIDX', - 'DT_MIPS_LOCAL_GOTIDX', 'DT_MIPS_LOCAL_GOTNO', 'DT_MIPS_MSYM', - 'DT_MIPS_NUM', 'DT_MIPS_OPTIONS', 'DT_MIPS_PERF_SUFFIX', - 'DT_MIPS_PIXIE_INIT', 'DT_MIPS_PLTGOT', - 'DT_MIPS_PROTECTED_GOTIDX', 'DT_MIPS_RLD_MAP', - 'DT_MIPS_RLD_MAP_REL', 'DT_MIPS_RLD_TEXT_RESOLVE_ADDR', - 'DT_MIPS_RLD_VERSION', 'DT_MIPS_RWPLT', 'DT_MIPS_SYMBOL_LIB', - 'DT_MIPS_SYMTABNO', 'DT_MIPS_TIME_STAMP', 'DT_MIPS_UNREFEXTNO', - 'DT_MIPS_XHASH', 'DT_MOVEENT', 'DT_MOVESZ', 'DT_MOVETAB', - 'DT_NEEDED', 'DT_NIOS2_GP', 'DT_NULL', 'DT_NUM', 'DT_PLTGOT', - 'DT_PLTPAD', 'DT_PLTPADSZ', 'DT_PLTREL', 'DT_PLTRELSZ', - 'DT_POSFLAG_1', 'DT_PPC64_GLINK', 'DT_PPC64_NUM', 'DT_PPC64_OPD', - 'DT_PPC64_OPDSZ', 'DT_PPC64_OPT', 'DT_PPC_GOT', 'DT_PPC_NUM', - 'DT_PPC_OPT', 'DT_PREINIT_ARRAY', 'DT_PREINIT_ARRAYSZ', - 'DT_PROCNUM', 'DT_REL', 'DT_RELA', 'DT_RELACOUNT', 'DT_RELAENT', - 'DT_RELASZ', 'DT_RELCOUNT', 'DT_RELENT', 'DT_RELR', 'DT_RELRENT', - 'DT_RELRSZ', 'DT_RELSZ', 'DT_RISCV_VARIANT_CC', 'DT_RPATH', - 'DT_RUNPATH', 'DT_SONAME', 'DT_SPARC_NUM', 'DT_SPARC_REGISTER', - 'DT_STRSZ', 'DT_STRTAB', 'DT_SYMBOLIC', 'DT_SYMENT', - 'DT_SYMINENT', 'DT_SYMINFO', 'DT_SYMINSZ', 'DT_SYMTAB', - 'DT_SYMTAB_SHNDX', 'DT_TEXTREL', 'DT_TLSDESC_GOT', - 'DT_TLSDESC_PLT', 'DT_VALNUM', 'DT_VALRNGHI', 'DT_VALRNGLO', - 'DT_VERDEF', 'DT_VERDEFNUM', 'DT_VERNEED', 'DT_VERNEEDNUM', - 'DT_VERSIONTAGNUM', 'DT_VERSYM', 'DT_X86_64_NUM', 'DT_X86_64_PLT', - 'DT_X86_64_PLTENT', 'DT_X86_64_PLTSZ', 'EFA_PARISC_1_0', - 'EFA_PARISC_1_1', 'EFA_PARISC_2_0', 'EF_ALPHA_32BIT', - 'EF_ALPHA_CANRELAX', 'EF_ARC_ALL_MSK', 'EF_ARC_MACH_MSK', - 'EF_ARC_OSABI_MSK', 'EF_ARM_ABI_FLOAT_HARD', - 'EF_ARM_ABI_FLOAT_SOFT', 'EF_ARM_ALIGN8', 'EF_ARM_APCS_26', - 'EF_ARM_APCS_FLOAT', 'EF_ARM_BE8', 'EF_ARM_DYNSYMSUSESEGIDX', - 'EF_ARM_EABIMASK', 'EF_ARM_EABI_UNKNOWN', 'EF_ARM_EABI_VER1', - 'EF_ARM_EABI_VER2', 'EF_ARM_EABI_VER3', 'EF_ARM_EABI_VER4', - 'EF_ARM_EABI_VER5', 'EF_ARM_HASENTRY', 'EF_ARM_INTERWORK', - 'EF_ARM_LE8', 'EF_ARM_MAPSYMSFIRST', 'EF_ARM_MAVERICK_FLOAT', - 'EF_ARM_NEW_ABI', 'EF_ARM_OLD_ABI', 'EF_ARM_PIC', - 'EF_ARM_RELEXEC', 'EF_ARM_SOFT_FLOAT', 'EF_ARM_SYMSARESORTED', - 'EF_ARM_VFP_FLOAT', 'EF_CPU32', 'EF_CSKY_ABIMASK', - 'EF_CSKY_ABIV1', 'EF_CSKY_ABIV2', 'EF_CSKY_OTHER', - 'EF_CSKY_PROCESSOR', 'EF_IA_64_ABI64', 'EF_IA_64_ARCH', - 'EF_IA_64_MASKOS', 'EF_LARCH_ABI_DOUBLE_FLOAT', - 'EF_LARCH_ABI_MODIFIER_MASK', 'EF_LARCH_ABI_SINGLE_FLOAT', - 'EF_LARCH_ABI_SOFT_FLOAT', 'EF_LARCH_OBJABI_V1', - 'EF_MIPS_32BITMODE', 'EF_MIPS_ABI', 'EF_MIPS_ABI2', - 'EF_MIPS_ABI_EABI32', 'EF_MIPS_ABI_EABI64', 'EF_MIPS_ABI_O32', - 'EF_MIPS_ABI_O64', 'EF_MIPS_ABI_ON32', 'EF_MIPS_ARCH', - 'EF_MIPS_ARCH_1', 'EF_MIPS_ARCH_2', 'EF_MIPS_ARCH_3', - 'EF_MIPS_ARCH_32', 'EF_MIPS_ARCH_32R2', 'EF_MIPS_ARCH_32R6', - 'EF_MIPS_ARCH_4', 'EF_MIPS_ARCH_5', 'EF_MIPS_ARCH_64', - 'EF_MIPS_ARCH_64R2', 'EF_MIPS_ARCH_64R6', 'EF_MIPS_ARCH_ASE', - 'EF_MIPS_ARCH_ASE_M16', 'EF_MIPS_ARCH_ASE_MDMX', - 'EF_MIPS_ARCH_ASE_MICROMIPS', 'EF_MIPS_CPIC', 'EF_MIPS_FP64', - 'EF_MIPS_MACH', 'EF_MIPS_MACH_3900', 'EF_MIPS_MACH_4010', - 'EF_MIPS_MACH_4100', 'EF_MIPS_MACH_4111', 'EF_MIPS_MACH_4120', - 'EF_MIPS_MACH_4650', 'EF_MIPS_MACH_5400', 'EF_MIPS_MACH_5500', - 'EF_MIPS_MACH_5900', 'EF_MIPS_MACH_9000', 'EF_MIPS_MACH_ALLEGREX', - 'EF_MIPS_MACH_GS264E', 'EF_MIPS_MACH_GS464', - 'EF_MIPS_MACH_GS464E', 'EF_MIPS_MACH_IAMR2', 'EF_MIPS_MACH_LS2E', - 'EF_MIPS_MACH_LS2F', 'EF_MIPS_MACH_OCTEON', - 'EF_MIPS_MACH_OCTEON2', 'EF_MIPS_MACH_OCTEON3', - 'EF_MIPS_MACH_SB1', 'EF_MIPS_MACH_XLR', 'EF_MIPS_NAN2008', - 'EF_MIPS_NOREORDER', 'EF_MIPS_OPTIONS_FIRST', 'EF_MIPS_PIC', - 'EF_MIPS_UCODE', 'EF_MIPS_XGOT', 'EF_PARISC_ARCH', - 'EF_PARISC_EXT', 'EF_PARISC_LAZYSWAP', 'EF_PARISC_LSB', - 'EF_PARISC_NO_KABP', 'EF_PARISC_TRAPNIL', 'EF_PARISC_WIDE', - 'EF_PPC64_ABI', 'EF_PPC_EMB', 'EF_PPC_RELOCATABLE', - 'EF_PPC_RELOCATABLE_LIB', 'EF_RISCV_FLOAT_ABI', - 'EF_RISCV_FLOAT_ABI_DOUBLE', 'EF_RISCV_FLOAT_ABI_QUAD', - 'EF_RISCV_FLOAT_ABI_SINGLE', 'EF_RISCV_FLOAT_ABI_SOFT', - 'EF_RISCV_RVC', 'EF_RISCV_RVE', 'EF_RISCV_TSO', - 'EF_S390_HIGH_GPRS', 'EF_SH1', 'EF_SH2', 'EF_SH2A', - 'EF_SH2A_NOFPU', 'EF_SH2A_SH3E', 'EF_SH2A_SH3_NOFPU', - 'EF_SH2A_SH4', 'EF_SH2A_SH4_NOFPU', 'EF_SH2E', 'EF_SH3', - 'EF_SH3E', 'EF_SH3_DSP', 'EF_SH3_NOMMU', 'EF_SH4', 'EF_SH4A', - 'EF_SH4AL_DSP', 'EF_SH4A_NOFPU', 'EF_SH4_NOFPU', - 'EF_SH4_NOMMU_NOFPU', 'EF_SH_DSP', 'EF_SH_MACH_MASK', - 'EF_SH_UNKNOWN', 'EF_SPARCV9_MM', 'EF_SPARCV9_PSO', - 'EF_SPARCV9_RMO', 'EF_SPARCV9_TSO', 'EF_SPARC_32PLUS', - 'EF_SPARC_EXT_MASK', 'EF_SPARC_HAL_R1', 'EF_SPARC_LEDATA', - 'EF_SPARC_SUN_US1', 'EF_SPARC_SUN_US3', 'EI_ABIVERSION', - 'EI_CLASS', 'EI_DATA', 'EI_MAG0', 'EI_MAG1', 'EI_MAG2', 'EI_MAG3', - 'EI_NIDENT', 'EI_OSABI', 'EI_PAD', 'EI_VERSION', 'ELFCLASS32', - 'ELFCLASS64', 'ELFCLASSNONE', 'ELFCLASSNUM', 'ELFCOMPRESS_HIOS', - 'ELFCOMPRESS_HIPROC', 'ELFCOMPRESS_LOOS', 'ELFCOMPRESS_LOPROC', - 'ELFCOMPRESS_ZLIB', 'ELFCOMPRESS_ZSTD', 'ELFDATA2LSB', - 'ELFDATA2MSB', 'ELFDATANONE', 'ELFDATANUM', 'ELFMAG', 'ELFMAG0', - 'ELFMAG1', 'ELFMAG2', 'ELFMAG3', 'ELFOSABI_AIX', 'ELFOSABI_ARM', - 'ELFOSABI_ARM_AEABI', 'ELFOSABI_FREEBSD', 'ELFOSABI_GNU', - 'ELFOSABI_HPUX', 'ELFOSABI_IRIX', 'ELFOSABI_LINUX', - 'ELFOSABI_MODESTO', 'ELFOSABI_NETBSD', 'ELFOSABI_NONE', - 'ELFOSABI_OPENBSD', 'ELFOSABI_SOLARIS', 'ELFOSABI_STANDALONE', - 'ELFOSABI_SYSV', 'ELFOSABI_TRU64', 'ELF_NOTE_ABI', 'ELF_NOTE_FDO', - 'ELF_NOTE_GNU', 'ELF_NOTE_OS_FREEBSD', 'ELF_NOTE_OS_GNU', - 'ELF_NOTE_OS_LINUX', 'ELF_NOTE_OS_SOLARIS2', - 'ELF_NOTE_PAGESIZE_HINT', 'ELF_NOTE_SOLARIS', 'EM_386', - 'EM_56800EX', 'EM_68HC05', 'EM_68HC08', 'EM_68HC11', 'EM_68HC12', - 'EM_68HC16', 'EM_68K', 'EM_78KOR', 'EM_8051', 'EM_860', 'EM_88K', - 'EM_960', 'EM_AARCH64', 'EM_ALPHA', 'EM_ALTERA_NIOS2', - 'EM_AMDGPU', 'EM_ARC', 'EM_ARCA', 'EM_ARCV2', 'EM_ARC_A5', - 'EM_ARC_COMPACT', 'EM_ARM', 'EM_AVR', 'EM_AVR32', 'EM_BA1', - 'EM_BA2', 'EM_BLACKFIN', 'EM_BPF', 'EM_C166', 'EM_CDP', 'EM_CE', - 'EM_CLOUDSHIELD', 'EM_COGE', 'EM_COLDFIRE', 'EM_COOL', - 'EM_COREA_1ST', 'EM_COREA_2ND', 'EM_CR', 'EM_CR16', 'EM_CRAYNV2', - 'EM_CRIS', 'EM_CRX', 'EM_CSKY', 'EM_CSR_KALIMBA', 'EM_CUDA', - 'EM_CYPRESS_M8C', 'EM_D10V', 'EM_D30V', 'EM_DSP24', 'EM_DSPIC30F', - 'EM_DXP', 'EM_ECOG16', 'EM_ECOG1X', 'EM_ECOG2', 'EM_EMX16', - 'EM_EMX8', 'EM_ETPU', 'EM_EXCESS', 'EM_F2MC16', 'EM_FAKE_ALPHA', - 'EM_FIREPATH', 'EM_FR20', 'EM_FR30', 'EM_FT32', 'EM_FX66', - 'EM_H8S', 'EM_H8_300', 'EM_H8_300H', 'EM_H8_500', 'EM_HUANY', - 'EM_IAMCU', 'EM_IA_64', 'EM_INTELGT', 'EM_IP2K', 'EM_JAVELIN', - 'EM_K10M', 'EM_KM32', 'EM_KMX32', 'EM_KVARC', 'EM_L10M', - 'EM_LATTICEMICO32', 'EM_LOONGARCH', 'EM_M16C', 'EM_M32', - 'EM_M32C', 'EM_M32R', 'EM_MANIK', 'EM_MAX', 'EM_MAXQ30', - 'EM_MCHP_PIC', 'EM_MCST_ELBRUS', 'EM_ME16', 'EM_METAG', - 'EM_MICROBLAZE', 'EM_MIPS', 'EM_MIPS_RS3_LE', 'EM_MIPS_X', - 'EM_MMA', 'EM_MMDSP_PLUS', 'EM_MMIX', 'EM_MN10200', 'EM_MN10300', - 'EM_MOXIE', 'EM_MSP430', 'EM_NCPU', 'EM_NDR1', 'EM_NDS32', - 'EM_NONE', 'EM_NORC', 'EM_NS32K', 'EM_NUM', 'EM_OPEN8', - 'EM_OPENRISC', 'EM_PARISC', 'EM_PCP', 'EM_PDP10', 'EM_PDP11', - 'EM_PDSP', 'EM_PJ', 'EM_PPC', 'EM_PPC64', 'EM_PRISM', 'EM_QDSP6', - 'EM_R32C', 'EM_RCE', 'EM_RH32', 'EM_RISCV', 'EM_RL78', 'EM_RS08', - 'EM_RX', 'EM_S370', 'EM_S390', 'EM_SCORE7', 'EM_SEP', 'EM_SE_C17', - 'EM_SE_C33', 'EM_SH', 'EM_SHARC', 'EM_SLE9X', 'EM_SNP1K', - 'EM_SPARC', 'EM_SPARC32PLUS', 'EM_SPARCV9', 'EM_SPU', 'EM_ST100', - 'EM_ST19', 'EM_ST200', 'EM_ST7', 'EM_ST9PLUS', 'EM_STARCORE', - 'EM_STM8', 'EM_STXP7X', 'EM_SVX', 'EM_TILE64', 'EM_TILEGX', - 'EM_TILEPRO', 'EM_TINYJ', 'EM_TI_ARP32', 'EM_TI_C2000', - 'EM_TI_C5500', 'EM_TI_C6000', 'EM_TI_PRU', 'EM_TMM_GPP', 'EM_TPC', - 'EM_TRICORE', 'EM_TRIMEDIA', 'EM_TSK3000', 'EM_UNICORE', - 'EM_V800', 'EM_V850', 'EM_VAX', 'EM_VIDEOCORE', 'EM_VIDEOCORE3', - 'EM_VIDEOCORE5', 'EM_VISIUM', 'EM_VPP500', 'EM_X86_64', - 'EM_XCORE', 'EM_XGATE', 'EM_XIMO16', 'EM_XTENSA', 'EM_Z80', - 'EM_ZSP', 'ET_CORE', 'ET_DYN', 'ET_EXEC', 'ET_HIOS', 'ET_HIPROC', - 'ET_LOOS', 'ET_LOPROC', 'ET_NONE', 'ET_NUM', 'ET_REL', - 'EV_CURRENT', 'EV_NONE', 'EV_NUM', 'E_MIPS_ARCH_1', - 'E_MIPS_ARCH_2', 'E_MIPS_ARCH_3', 'E_MIPS_ARCH_32', - 'E_MIPS_ARCH_4', 'E_MIPS_ARCH_5', 'E_MIPS_ARCH_64', 'Elf32_Addr', - 'Elf32_Chdr', 'Elf32_Conflict', 'Elf32_Dyn', 'Elf32_Ehdr', - 'Elf32_Half', 'Elf32_Lib', 'Elf32_Move', 'Elf32_Nhdr', - 'Elf32_Off', 'Elf32_Phdr', 'Elf32_RegInfo', 'Elf32_Rel', - 'Elf32_Rela', 'Elf32_Relr', 'Elf32_Section', 'Elf32_Shdr', - 'Elf32_Sword', 'Elf32_Sxword', 'Elf32_Sym', 'Elf32_Syminfo', - 'Elf32_Verdaux', 'Elf32_Verdef', 'Elf32_Vernaux', 'Elf32_Verneed', - 'Elf32_Versym', 'Elf32_Word', 'Elf32_Xword', 'Elf32_auxv_t', - 'Elf32_gptab', 'Elf64_Addr', 'Elf64_Chdr', 'Elf64_Dyn', - 'Elf64_Ehdr', 'Elf64_Half', 'Elf64_Lib', 'Elf64_Move', - 'Elf64_Nhdr', 'Elf64_Off', 'Elf64_Phdr', 'Elf64_Rel', - 'Elf64_Rela', 'Elf64_Relr', 'Elf64_Section', 'Elf64_Shdr', - 'Elf64_Sword', 'Elf64_Sxword', 'Elf64_Sym', 'Elf64_Syminfo', - 'Elf64_Verdaux', 'Elf64_Verdef', 'Elf64_Vernaux', 'Elf64_Verneed', - 'Elf64_Versym', 'Elf64_Word', 'Elf64_Xword', 'Elf64_auxv_t', - 'Elf_MIPS_ABIFlags_v0', 'Elf_Options', 'Elf_Options_Hw', 'F_LOCK', - 'F_OK', 'F_TEST', 'F_TLOCK', 'F_ULOCK', 'GNU_PROPERTY_1_NEEDED', - 'GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS', - 'GNU_PROPERTY_AARCH64_FEATURE_1_AND', - 'GNU_PROPERTY_AARCH64_FEATURE_1_BTI', - 'GNU_PROPERTY_AARCH64_FEATURE_1_PAC', 'GNU_PROPERTY_HIPROC', - 'GNU_PROPERTY_HIUSER', 'GNU_PROPERTY_LOPROC', - 'GNU_PROPERTY_LOUSER', 'GNU_PROPERTY_NO_COPY_ON_PROTECTED', - 'GNU_PROPERTY_STACK_SIZE', 'GNU_PROPERTY_UINT32_AND_HI', - 'GNU_PROPERTY_UINT32_AND_LO', 'GNU_PROPERTY_UINT32_OR_HI', - 'GNU_PROPERTY_UINT32_OR_LO', 'GNU_PROPERTY_X86_FEATURE_1_AND', - 'GNU_PROPERTY_X86_FEATURE_1_IBT', - 'GNU_PROPERTY_X86_FEATURE_1_SHSTK', - 'GNU_PROPERTY_X86_ISA_1_BASELINE', - 'GNU_PROPERTY_X86_ISA_1_NEEDED', 'GNU_PROPERTY_X86_ISA_1_USED', - 'GNU_PROPERTY_X86_ISA_1_V2', 'GNU_PROPERTY_X86_ISA_1_V3', - 'GNU_PROPERTY_X86_ISA_1_V4', 'GRP_COMDAT', 'LITUSE_ALPHA_ADDR', - 'LITUSE_ALPHA_BASE', 'LITUSE_ALPHA_BYTOFF', 'LITUSE_ALPHA_JSR', - 'LITUSE_ALPHA_TLS_GD', 'LITUSE_ALPHA_TLS_LDM', 'LL_DELAY_LOAD', - 'LL_DELTA', 'LL_EXACT_MATCH', 'LL_EXPORTS', 'LL_IGNORE_INT_VER', - 'LL_NONE', 'LL_REQUIRE_MINOR', 'L_INCR', 'L_SET', 'L_XTND', - 'MADV_COLD', 'MADV_COLLAPSE', 'MADV_DODUMP', 'MADV_DOFORK', - 'MADV_DONTDUMP', 'MADV_DONTFORK', 'MADV_DONTNEED', - 'MADV_DONTNEED_LOCKED', 'MADV_FREE', 'MADV_HUGEPAGE', - 'MADV_HWPOISON', 'MADV_KEEPONFORK', 'MADV_MERGEABLE', - 'MADV_NOHUGEPAGE', 'MADV_NORMAL', 'MADV_PAGEOUT', - 'MADV_POPULATE_READ', 'MADV_POPULATE_WRITE', 'MADV_RANDOM', - 'MADV_REMOVE', 'MADV_SEQUENTIAL', 'MADV_SOFT_OFFLINE', - 'MADV_UNMERGEABLE', 'MADV_WILLNEED', 'MADV_WIPEONFORK', - 'MAP_ANONYMOUS', 'MAP_FILE', 'MAP_FIXED', 'MAP_FIXED_NOREPLACE', - 'MAP_HUGETLB', 'MAP_NONBLOCK', 'MAP_POPULATE', 'MAP_STACK', - 'MAP_SYNC', 'MAP_TYPE', 'MAP_UNINITIALIZED', 'MIPS_AFL_ASE_DSP', - 'MIPS_AFL_ASE_DSPR2', 'MIPS_AFL_ASE_EVA', 'MIPS_AFL_ASE_MASK', - 'MIPS_AFL_ASE_MCU', 'MIPS_AFL_ASE_MDMX', 'MIPS_AFL_ASE_MICROMIPS', - 'MIPS_AFL_ASE_MIPS16', 'MIPS_AFL_ASE_MIPS3D', 'MIPS_AFL_ASE_MSA', - 'MIPS_AFL_ASE_MT', 'MIPS_AFL_ASE_SMARTMIPS', 'MIPS_AFL_ASE_VIRT', - 'MIPS_AFL_ASE_XPA', 'MIPS_AFL_EXT_10000', 'MIPS_AFL_EXT_3900', - 'MIPS_AFL_EXT_4010', 'MIPS_AFL_EXT_4100', 'MIPS_AFL_EXT_4111', - 'MIPS_AFL_EXT_4120', 'MIPS_AFL_EXT_4650', 'MIPS_AFL_EXT_5400', - 'MIPS_AFL_EXT_5500', 'MIPS_AFL_EXT_5900', - 'MIPS_AFL_EXT_LOONGSON_2E', 'MIPS_AFL_EXT_LOONGSON_2F', - 'MIPS_AFL_EXT_LOONGSON_3A', 'MIPS_AFL_EXT_OCTEON', - 'MIPS_AFL_EXT_OCTEON2', 'MIPS_AFL_EXT_OCTEONP', - 'MIPS_AFL_EXT_SB1', 'MIPS_AFL_EXT_XLR', - 'MIPS_AFL_FLAGS1_ODDSPREG', 'MIPS_AFL_REG_128', 'MIPS_AFL_REG_32', - 'MIPS_AFL_REG_64', 'MIPS_AFL_REG_NONE', 'MLOCK_ONFAULT', - 'MS_ASYNC', 'MS_INVALIDATE', 'MS_SYNC', - 'NOTE_GNU_PROPERTY_SECTION_NAME', 'NT_386_IOPERM', 'NT_386_TLS', - 'NT_ARM_HW_BREAK', 'NT_ARM_HW_WATCH', 'NT_ARM_PACA_KEYS', - 'NT_ARM_PACG_KEYS', 'NT_ARM_PAC_ENABLED_KEYS', 'NT_ARM_PAC_MASK', - 'NT_ARM_SVE', 'NT_ARM_SYSTEM_CALL', 'NT_ARM_TAGGED_ADDR_CTRL', - 'NT_ARM_TLS', 'NT_ARM_VFP', 'NT_ASRS', 'NT_AUXV', - 'NT_FDO_PACKAGING_METADATA', 'NT_FILE', 'NT_FPREGSET', - 'NT_GNU_ABI_TAG', 'NT_GNU_BUILD_ID', 'NT_GNU_GOLD_VERSION', - 'NT_GNU_HWCAP', 'NT_GNU_PROPERTY_TYPE_0', 'NT_GWINDOWS', - 'NT_LOONGARCH_CPUCFG', 'NT_LOONGARCH_CSR', - 'NT_LOONGARCH_HW_BREAK', 'NT_LOONGARCH_HW_WATCH', - 'NT_LOONGARCH_LASX', 'NT_LOONGARCH_LBT', 'NT_LOONGARCH_LSX', - 'NT_LWPSINFO', 'NT_LWPSTATUS', 'NT_MIPS_DSP', 'NT_MIPS_FP_MODE', - 'NT_MIPS_MSA', 'NT_PLATFORM', 'NT_PPC_DEXCR', 'NT_PPC_DSCR', - 'NT_PPC_EBB', 'NT_PPC_HASHKEYR', 'NT_PPC_PKEY', 'NT_PPC_PMU', - 'NT_PPC_PPR', 'NT_PPC_SPE', 'NT_PPC_TAR', 'NT_PPC_TM_CDSCR', - 'NT_PPC_TM_CFPR', 'NT_PPC_TM_CGPR', 'NT_PPC_TM_CPPR', - 'NT_PPC_TM_CTAR', 'NT_PPC_TM_CVMX', 'NT_PPC_TM_CVSX', - 'NT_PPC_TM_SPR', 'NT_PPC_VMX', 'NT_PPC_VSX', 'NT_PRCRED', - 'NT_PRFPREG', 'NT_PRFPXREG', 'NT_PRPSINFO', 'NT_PRSTATUS', - 'NT_PRXFPREG', 'NT_PRXREG', 'NT_PSINFO', 'NT_PSTATUS', - 'NT_RISCV_CSR', 'NT_RISCV_VECTOR', 'NT_S390_CTRS', - 'NT_S390_GS_BC', 'NT_S390_GS_CB', 'NT_S390_HIGH_GPRS', - 'NT_S390_LAST_BREAK', 'NT_S390_PREFIX', 'NT_S390_PV_CPU_DATA', - 'NT_S390_RI_CB', 'NT_S390_SYSTEM_CALL', 'NT_S390_TDB', - 'NT_S390_TIMER', 'NT_S390_TODCMP', 'NT_S390_TODPREG', - 'NT_S390_VXRS_HIGH', 'NT_S390_VXRS_LOW', 'NT_SIGINFO', - 'NT_TASKSTRUCT', 'NT_UTSNAME', 'NT_VERSION', 'NT_VMCOREDD', - 'NT_X86_SHSTK', 'NT_X86_XSTATE', 'ODK_EXCEPTIONS', 'ODK_FILL', - 'ODK_HWAND', 'ODK_HWOR', 'ODK_HWPATCH', 'ODK_NULL', 'ODK_PAD', - 'ODK_REGINFO', 'ODK_TAGS', 'OEX_DISMISS', 'OEX_FPDBUG', - 'OEX_FPU_DIV0', 'OEX_FPU_INEX', 'OEX_FPU_INVAL', 'OEX_FPU_MAX', - 'OEX_FPU_MIN', 'OEX_FPU_OFLO', 'OEX_FPU_UFLO', 'OEX_PAGE0', - 'OEX_PRECISEFP', 'OEX_SMM', 'OHWA0_R4KEOP_CHECKED', - 'OHWA1_R4KEOP_CLEAN', 'OHW_R4KEOP', 'OHW_R5KCVTL', 'OHW_R5KEOP', - 'OHW_R8KPFETCH', 'OPAD_POSTFIX', 'OPAD_PREFIX', 'OPAD_SYMBOL', - 'PF_ARM_ABS', 'PF_ARM_PI', 'PF_ARM_SB', 'PF_HP_CODE', - 'PF_HP_FAR_SHARED', 'PF_HP_LAZYSWAP', 'PF_HP_MODIFY', - 'PF_HP_NEAR_SHARED', 'PF_HP_PAGE_SIZE', 'PF_HP_SBP', - 'PF_IA_64_NORECOV', 'PF_MASKOS', 'PF_MASKPROC', 'PF_MIPS_LOCAL', - 'PF_PARISC_SBP', 'PF_R', 'PF_W', 'PF_X', 'PKEY_ACCESS_MASK', - 'PKEY_DISABLE_ACCESS', 'PKEY_DISABLE_WRITE', 'PN_XNUM', - 'PPC64_OPT_LOCALENTRY', 'PPC64_OPT_MULTI_TOC', 'PPC64_OPT_TLS', - 'PPC_OPT_TLS', 'PROT_EXEC', 'PROT_GROWSDOWN', 'PROT_GROWSUP', - 'PROT_NONE', 'PROT_READ', 'PROT_SEM', 'PROT_WRITE', - 'PT_AARCH64_MEMTAG_MTE', 'PT_ARM_EXIDX', 'PT_DYNAMIC', - 'PT_GNU_EH_FRAME', 'PT_GNU_PROPERTY', 'PT_GNU_RELRO', - 'PT_GNU_SFRAME', 'PT_GNU_STACK', 'PT_HIOS', 'PT_HIPROC', - 'PT_HISUNW', 'PT_HP_CORE_COMM', 'PT_HP_CORE_KERNEL', - 'PT_HP_CORE_LOADABLE', 'PT_HP_CORE_MMF', 'PT_HP_CORE_NONE', - 'PT_HP_CORE_PROC', 'PT_HP_CORE_SHM', 'PT_HP_CORE_STACK', - 'PT_HP_CORE_VERSION', 'PT_HP_FASTBIND', 'PT_HP_HSL_ANNOT', - 'PT_HP_OPT_ANNOT', 'PT_HP_PARALLEL', 'PT_HP_STACK', 'PT_HP_TLS', - 'PT_IA_64_ARCHEXT', 'PT_IA_64_HP_HSL_ANOT', - 'PT_IA_64_HP_OPT_ANOT', 'PT_IA_64_HP_STACK', 'PT_IA_64_UNWIND', - 'PT_INTERP', 'PT_LOAD', 'PT_LOOS', 'PT_LOPROC', 'PT_LOSUNW', - 'PT_MIPS_ABIFLAGS', 'PT_MIPS_OPTIONS', 'PT_MIPS_REGINFO', - 'PT_MIPS_RTPROC', 'PT_NOTE', 'PT_NULL', 'PT_NUM', - 'PT_PARISC_ARCHEXT', 'PT_PARISC_UNWIND', 'PT_PHDR', - 'PT_RISCV_ATTRIBUTES', 'PT_SHLIB', 'PT_SUNWBSS', 'PT_SUNWSTACK', - 'PT_TLS', 'RHF_CORD', 'RHF_DEFAULT_DELAY_LOAD', - 'RHF_DELTA_C_PLUS_PLUS', 'RHF_GUARANTEE_INIT', - 'RHF_GUARANTEE_START_INIT', 'RHF_NONE', 'RHF_NOTPOT', - 'RHF_NO_LIBRARY_REPLACEMENT', 'RHF_NO_MOVE', 'RHF_NO_UNRES_UNDEF', - 'RHF_PIXIE', 'RHF_QUICKSTART', 'RHF_REQUICKSTART', - 'RHF_REQUICKSTARTED', 'RHF_RLD_ORDER_SAFE', 'RHF_SGI_ONLY', - 'R_386_16', 'R_386_32', 'R_386_32PLT', 'R_386_8', 'R_386_COPY', - 'R_386_GLOB_DAT', 'R_386_GOT32', 'R_386_GOT32X', 'R_386_GOTOFF', - 'R_386_GOTPC', 'R_386_IRELATIVE', 'R_386_JMP_SLOT', 'R_386_NONE', - 'R_386_NUM', 'R_386_PC16', 'R_386_PC32', 'R_386_PC8', - 'R_386_PLT32', 'R_386_RELATIVE', 'R_386_SIZE32', 'R_386_TLS_DESC', - 'R_386_TLS_DESC_CALL', 'R_386_TLS_DTPMOD32', 'R_386_TLS_DTPOFF32', - 'R_386_TLS_GD', 'R_386_TLS_GD_32', 'R_386_TLS_GD_CALL', - 'R_386_TLS_GD_POP', 'R_386_TLS_GD_PUSH', 'R_386_TLS_GOTDESC', - 'R_386_TLS_GOTIE', 'R_386_TLS_IE', 'R_386_TLS_IE_32', - 'R_386_TLS_LDM', 'R_386_TLS_LDM_32', 'R_386_TLS_LDM_CALL', - 'R_386_TLS_LDM_POP', 'R_386_TLS_LDM_PUSH', 'R_386_TLS_LDO_32', - 'R_386_TLS_LE', 'R_386_TLS_LE_32', 'R_386_TLS_TPOFF', - 'R_386_TLS_TPOFF32', 'R_390_12', 'R_390_16', 'R_390_20', - 'R_390_32', 'R_390_64', 'R_390_8', 'R_390_COPY', 'R_390_GLOB_DAT', - 'R_390_GOT12', 'R_390_GOT16', 'R_390_GOT20', 'R_390_GOT32', - 'R_390_GOT64', 'R_390_GOTENT', 'R_390_GOTOFF16', 'R_390_GOTOFF32', - 'R_390_GOTOFF64', 'R_390_GOTPC', 'R_390_GOTPCDBL', - 'R_390_GOTPLT12', 'R_390_GOTPLT16', 'R_390_GOTPLT20', - 'R_390_GOTPLT32', 'R_390_GOTPLT64', 'R_390_GOTPLTENT', - 'R_390_IRELATIVE', 'R_390_JMP_SLOT', 'R_390_NONE', 'R_390_NUM', - 'R_390_PC16', 'R_390_PC16DBL', 'R_390_PC32', 'R_390_PC32DBL', - 'R_390_PC64', 'R_390_PLT16DBL', 'R_390_PLT32', 'R_390_PLT32DBL', - 'R_390_PLT64', 'R_390_PLTOFF16', 'R_390_PLTOFF32', - 'R_390_PLTOFF64', 'R_390_RELATIVE', 'R_390_TLS_DTPMOD', - 'R_390_TLS_DTPOFF', 'R_390_TLS_GD32', 'R_390_TLS_GD64', - 'R_390_TLS_GDCALL', 'R_390_TLS_GOTIE12', 'R_390_TLS_GOTIE20', - 'R_390_TLS_GOTIE32', 'R_390_TLS_GOTIE64', 'R_390_TLS_IE32', - 'R_390_TLS_IE64', 'R_390_TLS_IEENT', 'R_390_TLS_LDCALL', - 'R_390_TLS_LDM32', 'R_390_TLS_LDM64', 'R_390_TLS_LDO32', - 'R_390_TLS_LDO64', 'R_390_TLS_LE32', 'R_390_TLS_LE64', - 'R_390_TLS_LOAD', 'R_390_TLS_TPOFF', 'R_68K_16', 'R_68K_32', - 'R_68K_8', 'R_68K_COPY', 'R_68K_GLOB_DAT', 'R_68K_GOT16', - 'R_68K_GOT16O', 'R_68K_GOT32', 'R_68K_GOT32O', 'R_68K_GOT8', - 'R_68K_GOT8O', 'R_68K_JMP_SLOT', 'R_68K_NONE', 'R_68K_NUM', - 'R_68K_PC16', 'R_68K_PC32', 'R_68K_PC8', 'R_68K_PLT16', - 'R_68K_PLT16O', 'R_68K_PLT32', 'R_68K_PLT32O', 'R_68K_PLT8', - 'R_68K_PLT8O', 'R_68K_RELATIVE', 'R_68K_TLS_DTPMOD32', - 'R_68K_TLS_DTPREL32', 'R_68K_TLS_GD16', 'R_68K_TLS_GD32', - 'R_68K_TLS_GD8', 'R_68K_TLS_IE16', 'R_68K_TLS_IE32', - 'R_68K_TLS_IE8', 'R_68K_TLS_LDM16', 'R_68K_TLS_LDM32', - 'R_68K_TLS_LDM8', 'R_68K_TLS_LDO16', 'R_68K_TLS_LDO32', - 'R_68K_TLS_LDO8', 'R_68K_TLS_LE16', 'R_68K_TLS_LE32', - 'R_68K_TLS_LE8', 'R_68K_TLS_TPREL32', 'R_AARCH64_ABS16', - 'R_AARCH64_ABS32', 'R_AARCH64_ABS64', 'R_AARCH64_ADD_ABS_LO12_NC', - 'R_AARCH64_ADR_GOT_PAGE', 'R_AARCH64_ADR_PREL_LO21', - 'R_AARCH64_ADR_PREL_PG_HI21', 'R_AARCH64_ADR_PREL_PG_HI21_NC', - 'R_AARCH64_CALL26', 'R_AARCH64_CONDBR19', 'R_AARCH64_COPY', - 'R_AARCH64_GLOB_DAT', 'R_AARCH64_GOTREL32', 'R_AARCH64_GOTREL64', - 'R_AARCH64_GOT_LD_PREL19', 'R_AARCH64_IRELATIVE', - 'R_AARCH64_JUMP26', 'R_AARCH64_JUMP_SLOT', - 'R_AARCH64_LD64_GOTOFF_LO15', 'R_AARCH64_LD64_GOTPAGE_LO15', - 'R_AARCH64_LD64_GOT_LO12_NC', 'R_AARCH64_LDST128_ABS_LO12_NC', - 'R_AARCH64_LDST16_ABS_LO12_NC', 'R_AARCH64_LDST32_ABS_LO12_NC', - 'R_AARCH64_LDST64_ABS_LO12_NC', 'R_AARCH64_LDST8_ABS_LO12_NC', - 'R_AARCH64_LD_PREL_LO19', 'R_AARCH64_MOVW_GOTOFF_G0', - 'R_AARCH64_MOVW_GOTOFF_G0_NC', 'R_AARCH64_MOVW_GOTOFF_G1', - 'R_AARCH64_MOVW_GOTOFF_G1_NC', 'R_AARCH64_MOVW_GOTOFF_G2', - 'R_AARCH64_MOVW_GOTOFF_G2_NC', 'R_AARCH64_MOVW_GOTOFF_G3', - 'R_AARCH64_MOVW_PREL_G0', 'R_AARCH64_MOVW_PREL_G0_NC', - 'R_AARCH64_MOVW_PREL_G1', 'R_AARCH64_MOVW_PREL_G1_NC', - 'R_AARCH64_MOVW_PREL_G2', 'R_AARCH64_MOVW_PREL_G2_NC', - 'R_AARCH64_MOVW_PREL_G3', 'R_AARCH64_MOVW_SABS_G0', - 'R_AARCH64_MOVW_SABS_G1', 'R_AARCH64_MOVW_SABS_G2', - 'R_AARCH64_MOVW_UABS_G0', 'R_AARCH64_MOVW_UABS_G0_NC', - 'R_AARCH64_MOVW_UABS_G1', 'R_AARCH64_MOVW_UABS_G1_NC', - 'R_AARCH64_MOVW_UABS_G2', 'R_AARCH64_MOVW_UABS_G2_NC', - 'R_AARCH64_MOVW_UABS_G3', 'R_AARCH64_NONE', 'R_AARCH64_P32_ABS32', - 'R_AARCH64_P32_COPY', 'R_AARCH64_P32_GLOB_DAT', - 'R_AARCH64_P32_IRELATIVE', 'R_AARCH64_P32_JUMP_SLOT', - 'R_AARCH64_P32_RELATIVE', 'R_AARCH64_P32_TLSDESC', - 'R_AARCH64_P32_TLS_DTPMOD', 'R_AARCH64_P32_TLS_DTPREL', - 'R_AARCH64_P32_TLS_TPREL', 'R_AARCH64_PREL16', 'R_AARCH64_PREL32', - 'R_AARCH64_PREL64', 'R_AARCH64_RELATIVE', 'R_AARCH64_TLSDESC', - 'R_AARCH64_TLSDESC_ADD', 'R_AARCH64_TLSDESC_ADD_LO12', - 'R_AARCH64_TLSDESC_ADR_PAGE21', 'R_AARCH64_TLSDESC_ADR_PREL21', - 'R_AARCH64_TLSDESC_CALL', 'R_AARCH64_TLSDESC_LD64_LO12', - 'R_AARCH64_TLSDESC_LDR', 'R_AARCH64_TLSDESC_LD_PREL19', - 'R_AARCH64_TLSDESC_OFF_G0_NC', 'R_AARCH64_TLSDESC_OFF_G1', - 'R_AARCH64_TLSGD_ADD_LO12_NC', 'R_AARCH64_TLSGD_ADR_PAGE21', - 'R_AARCH64_TLSGD_ADR_PREL21', 'R_AARCH64_TLSGD_MOVW_G0_NC', - 'R_AARCH64_TLSGD_MOVW_G1', 'R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21', - 'R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC', - 'R_AARCH64_TLSIE_LD_GOTTPREL_PREL19', - 'R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC', - 'R_AARCH64_TLSIE_MOVW_GOTTPREL_G1', - 'R_AARCH64_TLSLD_ADD_DTPREL_HI12', - 'R_AARCH64_TLSLD_ADD_DTPREL_LO12', - 'R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC', - 'R_AARCH64_TLSLD_ADD_LO12_NC', 'R_AARCH64_TLSLD_ADR_PAGE21', - 'R_AARCH64_TLSLD_ADR_PREL21', - 'R_AARCH64_TLSLD_LDST128_DTPREL_LO12', - 'R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC', - 'R_AARCH64_TLSLD_LDST16_DTPREL_LO12', - 'R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC', - 'R_AARCH64_TLSLD_LDST32_DTPREL_LO12', - 'R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC', - 'R_AARCH64_TLSLD_LDST64_DTPREL_LO12', - 'R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC', - 'R_AARCH64_TLSLD_LDST8_DTPREL_LO12', - 'R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC', - 'R_AARCH64_TLSLD_LD_PREL19', 'R_AARCH64_TLSLD_MOVW_DTPREL_G0', - 'R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC', - 'R_AARCH64_TLSLD_MOVW_DTPREL_G1', - 'R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC', - 'R_AARCH64_TLSLD_MOVW_DTPREL_G2', 'R_AARCH64_TLSLD_MOVW_G0_NC', - 'R_AARCH64_TLSLD_MOVW_G1', 'R_AARCH64_TLSLE_ADD_TPREL_HI12', - 'R_AARCH64_TLSLE_ADD_TPREL_LO12', - 'R_AARCH64_TLSLE_ADD_TPREL_LO12_NC', - 'R_AARCH64_TLSLE_LDST128_TPREL_LO12', - 'R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC', - 'R_AARCH64_TLSLE_LDST16_TPREL_LO12', - 'R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC', - 'R_AARCH64_TLSLE_LDST32_TPREL_LO12', - 'R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC', - 'R_AARCH64_TLSLE_LDST64_TPREL_LO12', - 'R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC', - 'R_AARCH64_TLSLE_LDST8_TPREL_LO12', - 'R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC', - 'R_AARCH64_TLSLE_MOVW_TPREL_G0', - 'R_AARCH64_TLSLE_MOVW_TPREL_G0_NC', - 'R_AARCH64_TLSLE_MOVW_TPREL_G1', - 'R_AARCH64_TLSLE_MOVW_TPREL_G1_NC', - 'R_AARCH64_TLSLE_MOVW_TPREL_G2', 'R_AARCH64_TLS_DTPMOD', - 'R_AARCH64_TLS_DTPREL', 'R_AARCH64_TLS_TPREL', - 'R_AARCH64_TSTBR14', 'R_AC_SECTOFF_S9', 'R_AC_SECTOFF_S9_1', - 'R_AC_SECTOFF_S9_2', 'R_AC_SECTOFF_U8', 'R_AC_SECTOFF_U8_1', - 'R_AC_SECTOFF_U8_2', 'R_ALPHA_BRADDR', 'R_ALPHA_COPY', - 'R_ALPHA_DTPMOD64', 'R_ALPHA_DTPREL16', 'R_ALPHA_DTPREL64', - 'R_ALPHA_DTPRELHI', 'R_ALPHA_DTPRELLO', 'R_ALPHA_GLOB_DAT', - 'R_ALPHA_GOTDTPREL', 'R_ALPHA_GOTTPREL', 'R_ALPHA_GPDISP', - 'R_ALPHA_GPREL16', 'R_ALPHA_GPREL32', 'R_ALPHA_GPRELHIGH', - 'R_ALPHA_GPRELLOW', 'R_ALPHA_HINT', 'R_ALPHA_JMP_SLOT', - 'R_ALPHA_LITERAL', 'R_ALPHA_LITUSE', 'R_ALPHA_NONE', - 'R_ALPHA_NUM', 'R_ALPHA_REFLONG', 'R_ALPHA_REFQUAD', - 'R_ALPHA_RELATIVE', 'R_ALPHA_SREL16', 'R_ALPHA_SREL32', - 'R_ALPHA_SREL64', 'R_ALPHA_TLSGD', 'R_ALPHA_TLS_GD_HI', - 'R_ALPHA_TLS_LDM', 'R_ALPHA_TPREL16', 'R_ALPHA_TPREL64', - 'R_ALPHA_TPRELHI', 'R_ALPHA_TPRELLO', 'R_ARC_16', 'R_ARC_24', - 'R_ARC_32', 'R_ARC_32_ME', 'R_ARC_32_PCREL', 'R_ARC_8', - 'R_ARC_B22_PCREL', 'R_ARC_COPY', 'R_ARC_GLOB_DAT', 'R_ARC_GOT32', - 'R_ARC_GOTOFF', 'R_ARC_GOTPC', 'R_ARC_GOTPC32', 'R_ARC_H30', - 'R_ARC_H30_ME', 'R_ARC_JLI_SECTOFF', 'R_ARC_JMP_SLOT', - 'R_ARC_N16', 'R_ARC_N24', 'R_ARC_N32', 'R_ARC_N32_ME', 'R_ARC_N8', - 'R_ARC_NONE', 'R_ARC_NPS_CMEM16', 'R_ARC_PC32', 'R_ARC_PLT32', - 'R_ARC_RELATIVE', 'R_ARC_S13_PCREL', 'R_ARC_S21H_PCREL', - 'R_ARC_S21H_PCREL_PLT', 'R_ARC_S21W_PCREL', - 'R_ARC_S21W_PCREL_PLT', 'R_ARC_S25H_PCREL', - 'R_ARC_S25H_PCREL_PLT', 'R_ARC_S25W_PCREL', - 'R_ARC_S25W_PCREL_PLT', 'R_ARC_SDA', 'R_ARC_SDA16_LD', - 'R_ARC_SDA16_LD1', 'R_ARC_SDA16_LD2', 'R_ARC_SDA16_ST2', - 'R_ARC_SDA32', 'R_ARC_SDA32_ME', 'R_ARC_SDA_12', 'R_ARC_SDA_LDST', - 'R_ARC_SDA_LDST1', 'R_ARC_SDA_LDST2', 'R_ARC_SECTOFF', - 'R_ARC_SECTOFF_1', 'R_ARC_SECTOFF_2', 'R_ARC_SECTOFF_ME', - 'R_ARC_SECTOFF_ME_1', 'R_ARC_SECTOFF_ME_2', 'R_ARC_SECTOFF_S9', - 'R_ARC_SECTOFF_U8', 'R_ARC_TLS_DTPMOD', 'R_ARC_TLS_DTPOFF', - 'R_ARC_TLS_DTPOFF_S9', 'R_ARC_TLS_GD_CALL', 'R_ARC_TLS_GD_GOT', - 'R_ARC_TLS_GD_LD', 'R_ARC_TLS_IE_GOT', 'R_ARC_TLS_LE_32', - 'R_ARC_TLS_LE_S9', 'R_ARC_TLS_TPOFF', 'R_ARC_W', 'R_ARC_W_ME', - 'R_ARM_ABS12', 'R_ARM_ABS16', 'R_ARM_ABS32', 'R_ARM_ABS32_NOI', - 'R_ARM_ABS8', 'R_ARM_ALU_PCREL_15_8', 'R_ARM_ALU_PCREL_23_15', - 'R_ARM_ALU_PCREL_7_0', 'R_ARM_ALU_PC_G0', 'R_ARM_ALU_PC_G0_NC', - 'R_ARM_ALU_PC_G1', 'R_ARM_ALU_PC_G1_NC', 'R_ARM_ALU_PC_G2', - 'R_ARM_ALU_SBREL_19_12', 'R_ARM_ALU_SBREL_27_20', - 'R_ARM_ALU_SB_G0', 'R_ARM_ALU_SB_G0_NC', 'R_ARM_ALU_SB_G1', - 'R_ARM_ALU_SB_G1_NC', 'R_ARM_ALU_SB_G2', 'R_ARM_AMP_VCALL9', - 'R_ARM_BASE_ABS', 'R_ARM_CALL', 'R_ARM_COPY', 'R_ARM_GLOB_DAT', - 'R_ARM_GNU_VTENTRY', 'R_ARM_GNU_VTINHERIT', 'R_ARM_GOT32', - 'R_ARM_GOTOFF', 'R_ARM_GOTOFF12', 'R_ARM_GOTPC', 'R_ARM_GOTRELAX', - 'R_ARM_GOT_ABS', 'R_ARM_GOT_BREL12', 'R_ARM_GOT_PREL', - 'R_ARM_IRELATIVE', 'R_ARM_JUMP24', 'R_ARM_JUMP_SLOT', - 'R_ARM_LDC_PC_G0', 'R_ARM_LDC_PC_G1', 'R_ARM_LDC_PC_G2', - 'R_ARM_LDC_SB_G0', 'R_ARM_LDC_SB_G1', 'R_ARM_LDC_SB_G2', - 'R_ARM_LDRS_PC_G0', 'R_ARM_LDRS_PC_G1', 'R_ARM_LDRS_PC_G2', - 'R_ARM_LDRS_SB_G0', 'R_ARM_LDRS_SB_G1', 'R_ARM_LDRS_SB_G2', - 'R_ARM_LDR_PC_G1', 'R_ARM_LDR_PC_G2', 'R_ARM_LDR_SBREL_11_0', - 'R_ARM_LDR_SB_G0', 'R_ARM_LDR_SB_G1', 'R_ARM_LDR_SB_G2', - 'R_ARM_ME_TOO', 'R_ARM_MOVT_ABS', 'R_ARM_MOVT_BREL', - 'R_ARM_MOVT_PREL', 'R_ARM_MOVW_ABS_NC', 'R_ARM_MOVW_BREL', - 'R_ARM_MOVW_BREL_NC', 'R_ARM_MOVW_PREL_NC', 'R_ARM_NONE', - 'R_ARM_NUM', 'R_ARM_PC13', 'R_ARM_PC24', 'R_ARM_PLT32', - 'R_ARM_PLT32_ABS', 'R_ARM_PREL31', 'R_ARM_RABS22', 'R_ARM_RBASE', - 'R_ARM_REL32', 'R_ARM_REL32_NOI', 'R_ARM_RELATIVE', 'R_ARM_RPC24', - 'R_ARM_RREL32', 'R_ARM_RSBREL32', 'R_ARM_RXPC25', 'R_ARM_SBREL31', - 'R_ARM_SBREL32', 'R_ARM_SWI24', 'R_ARM_TARGET1', 'R_ARM_TARGET2', - 'R_ARM_THM_ABS5', 'R_ARM_THM_ALU_PREL_11_0', - 'R_ARM_THM_GOT_BREL12', 'R_ARM_THM_JUMP19', 'R_ARM_THM_JUMP24', - 'R_ARM_THM_JUMP6', 'R_ARM_THM_MOVT_ABS', 'R_ARM_THM_MOVT_BREL', - 'R_ARM_THM_MOVT_PREL', 'R_ARM_THM_MOVW_ABS_NC', - 'R_ARM_THM_MOVW_BREL', 'R_ARM_THM_MOVW_BREL_NC', - 'R_ARM_THM_MOVW_PREL_NC', 'R_ARM_THM_PC11', 'R_ARM_THM_PC12', - 'R_ARM_THM_PC22', 'R_ARM_THM_PC8', 'R_ARM_THM_PC9', - 'R_ARM_THM_RPC22', 'R_ARM_THM_SWI8', 'R_ARM_THM_TLS_CALL', - 'R_ARM_THM_TLS_DESCSEQ', 'R_ARM_THM_TLS_DESCSEQ16', - 'R_ARM_THM_TLS_DESCSEQ32', 'R_ARM_THM_XPC22', 'R_ARM_TLS_CALL', - 'R_ARM_TLS_DESC', 'R_ARM_TLS_DESCSEQ', 'R_ARM_TLS_DTPMOD32', - 'R_ARM_TLS_DTPOFF32', 'R_ARM_TLS_GD32', 'R_ARM_TLS_GOTDESC', - 'R_ARM_TLS_IE12GP', 'R_ARM_TLS_IE32', 'R_ARM_TLS_LDM32', - 'R_ARM_TLS_LDO12', 'R_ARM_TLS_LDO32', 'R_ARM_TLS_LE12', - 'R_ARM_TLS_LE32', 'R_ARM_TLS_TPOFF32', 'R_ARM_V4BX', - 'R_ARM_XPC25', 'R_BPF_64_32', 'R_BPF_64_64', 'R_BPF_NONE', - 'R_CKCORE_ADDR32', 'R_CKCORE_ADDRGOT', 'R_CKCORE_ADDRGOT_HI16', - 'R_CKCORE_ADDRGOT_LO16', 'R_CKCORE_ADDRPLT', - 'R_CKCORE_ADDRPLT_HI16', 'R_CKCORE_ADDRPLT_LO16', - 'R_CKCORE_ADDR_HI16', 'R_CKCORE_ADDR_LO16', 'R_CKCORE_COPY', - 'R_CKCORE_DOFFSET_IMM18', 'R_CKCORE_DOFFSET_IMM18BY2', - 'R_CKCORE_DOFFSET_IMM18BY4', 'R_CKCORE_DOFFSET_LO16', - 'R_CKCORE_GLOB_DAT', 'R_CKCORE_GOT12', 'R_CKCORE_GOT32', - 'R_CKCORE_GOTOFF', 'R_CKCORE_GOTOFF_HI16', 'R_CKCORE_GOTOFF_LO16', - 'R_CKCORE_GOTPC', 'R_CKCORE_GOTPC_HI16', 'R_CKCORE_GOTPC_LO16', - 'R_CKCORE_GOT_HI16', 'R_CKCORE_GOT_IMM18BY4', 'R_CKCORE_GOT_LO16', - 'R_CKCORE_JUMP_SLOT', 'R_CKCORE_NONE', 'R_CKCORE_PCREL32', - 'R_CKCORE_PCRELIMM11BY2', 'R_CKCORE_PCRELIMM8BY4', - 'R_CKCORE_PCRELJSR_IMM11BY2', 'R_CKCORE_PCREL_IMM10BY2', - 'R_CKCORE_PCREL_IMM10BY4', 'R_CKCORE_PCREL_IMM16BY2', - 'R_CKCORE_PCREL_IMM16BY4', 'R_CKCORE_PCREL_IMM18BY2', - 'R_CKCORE_PCREL_IMM26BY2', 'R_CKCORE_PCREL_IMM7BY4', - 'R_CKCORE_PCREL_JSR_IMM26BY2', 'R_CKCORE_PLT12', 'R_CKCORE_PLT32', - 'R_CKCORE_PLT_HI16', 'R_CKCORE_PLT_IMM18BY4', 'R_CKCORE_PLT_LO16', - 'R_CKCORE_RELATIVE', 'R_CKCORE_TLS_DTPMOD32', - 'R_CKCORE_TLS_DTPOFF32', 'R_CKCORE_TLS_GD32', 'R_CKCORE_TLS_IE32', - 'R_CKCORE_TLS_LDM32', 'R_CKCORE_TLS_LDO32', 'R_CKCORE_TLS_LE32', - 'R_CKCORE_TLS_TPOFF32', 'R_CKCORE_TOFFSET_LO16', 'R_CRIS_16', - 'R_CRIS_16_GOT', 'R_CRIS_16_GOTPLT', 'R_CRIS_16_PCREL', - 'R_CRIS_32', 'R_CRIS_32_GOT', 'R_CRIS_32_GOTPLT', - 'R_CRIS_32_GOTREL', 'R_CRIS_32_PCREL', 'R_CRIS_32_PLT_GOTREL', - 'R_CRIS_32_PLT_PCREL', 'R_CRIS_8', 'R_CRIS_8_PCREL', - 'R_CRIS_COPY', 'R_CRIS_GLOB_DAT', 'R_CRIS_GNU_VTENTRY', - 'R_CRIS_GNU_VTINHERIT', 'R_CRIS_JUMP_SLOT', 'R_CRIS_NONE', - 'R_CRIS_NUM', 'R_CRIS_RELATIVE', 'R_IA64_COPY', 'R_IA64_DIR32LSB', - 'R_IA64_DIR32MSB', 'R_IA64_DIR64LSB', 'R_IA64_DIR64MSB', - 'R_IA64_DTPMOD64LSB', 'R_IA64_DTPMOD64MSB', 'R_IA64_DTPREL14', - 'R_IA64_DTPREL22', 'R_IA64_DTPREL32LSB', 'R_IA64_DTPREL32MSB', - 'R_IA64_DTPREL64I', 'R_IA64_DTPREL64LSB', 'R_IA64_DTPREL64MSB', - 'R_IA64_FPTR32LSB', 'R_IA64_FPTR32MSB', 'R_IA64_FPTR64I', - 'R_IA64_FPTR64LSB', 'R_IA64_FPTR64MSB', 'R_IA64_GPREL22', - 'R_IA64_GPREL32LSB', 'R_IA64_GPREL32MSB', 'R_IA64_GPREL64I', - 'R_IA64_GPREL64LSB', 'R_IA64_GPREL64MSB', 'R_IA64_IMM14', - 'R_IA64_IMM22', 'R_IA64_IMM64', 'R_IA64_IPLTLSB', - 'R_IA64_IPLTMSB', 'R_IA64_LDXMOV', 'R_IA64_LTOFF22', - 'R_IA64_LTOFF22X', 'R_IA64_LTOFF64I', 'R_IA64_LTOFF_DTPMOD22', - 'R_IA64_LTOFF_DTPREL22', 'R_IA64_LTOFF_FPTR22', - 'R_IA64_LTOFF_FPTR32LSB', 'R_IA64_LTOFF_FPTR32MSB', - 'R_IA64_LTOFF_FPTR64I', 'R_IA64_LTOFF_FPTR64LSB', - 'R_IA64_LTOFF_FPTR64MSB', 'R_IA64_LTOFF_TPREL22', - 'R_IA64_LTV32LSB', 'R_IA64_LTV32MSB', 'R_IA64_LTV64LSB', - 'R_IA64_LTV64MSB', 'R_IA64_NONE', 'R_IA64_PCREL21B', - 'R_IA64_PCREL21BI', 'R_IA64_PCREL21F', 'R_IA64_PCREL21M', - 'R_IA64_PCREL22', 'R_IA64_PCREL32LSB', 'R_IA64_PCREL32MSB', - 'R_IA64_PCREL60B', 'R_IA64_PCREL64I', 'R_IA64_PCREL64LSB', - 'R_IA64_PCREL64MSB', 'R_IA64_PLTOFF22', 'R_IA64_PLTOFF64I', - 'R_IA64_PLTOFF64LSB', 'R_IA64_PLTOFF64MSB', 'R_IA64_REL32LSB', - 'R_IA64_REL32MSB', 'R_IA64_REL64LSB', 'R_IA64_REL64MSB', - 'R_IA64_SECREL32LSB', 'R_IA64_SECREL32MSB', 'R_IA64_SECREL64LSB', - 'R_IA64_SECREL64MSB', 'R_IA64_SEGREL32LSB', 'R_IA64_SEGREL32MSB', - 'R_IA64_SEGREL64LSB', 'R_IA64_SEGREL64MSB', 'R_IA64_SUB', - 'R_IA64_TPREL14', 'R_IA64_TPREL22', 'R_IA64_TPREL64I', - 'R_IA64_TPREL64LSB', 'R_IA64_TPREL64MSB', 'R_LARCH_32', - 'R_LARCH_32_PCREL', 'R_LARCH_64', 'R_LARCH_64_PCREL', - 'R_LARCH_ABS64_HI12', 'R_LARCH_ABS64_LO20', 'R_LARCH_ABS_HI20', - 'R_LARCH_ABS_LO12', 'R_LARCH_ADD16', 'R_LARCH_ADD24', - 'R_LARCH_ADD32', 'R_LARCH_ADD6', 'R_LARCH_ADD64', 'R_LARCH_ADD8', - 'R_LARCH_ADD_ULEB128', 'R_LARCH_ALIGN', 'R_LARCH_B16', - 'R_LARCH_B21', 'R_LARCH_B26', 'R_LARCH_CFA', 'R_LARCH_COPY', - 'R_LARCH_DELETE', 'R_LARCH_GNU_VTENTRY', 'R_LARCH_GNU_VTINHERIT', - 'R_LARCH_GOT64_HI12', 'R_LARCH_GOT64_LO20', - 'R_LARCH_GOT64_PC_HI12', 'R_LARCH_GOT64_PC_LO20', - 'R_LARCH_GOT_HI20', 'R_LARCH_GOT_LO12', 'R_LARCH_GOT_PC_HI20', - 'R_LARCH_GOT_PC_LO12', 'R_LARCH_IRELATIVE', 'R_LARCH_JUMP_SLOT', - 'R_LARCH_MARK_LA', 'R_LARCH_MARK_PCREL', 'R_LARCH_NONE', - 'R_LARCH_PCALA64_HI12', 'R_LARCH_PCALA64_LO20', - 'R_LARCH_PCALA_HI20', 'R_LARCH_PCALA_LO12', 'R_LARCH_PCREL20_S2', - 'R_LARCH_RELATIVE', 'R_LARCH_RELAX', 'R_LARCH_SOP_ADD', - 'R_LARCH_SOP_AND', 'R_LARCH_SOP_ASSERT', 'R_LARCH_SOP_IF_ELSE', - 'R_LARCH_SOP_NOT', 'R_LARCH_SOP_POP_32_S_0_10_10_16_S2', - 'R_LARCH_SOP_POP_32_S_0_5_10_16_S2', 'R_LARCH_SOP_POP_32_S_10_12', - 'R_LARCH_SOP_POP_32_S_10_16', 'R_LARCH_SOP_POP_32_S_10_16_S2', - 'R_LARCH_SOP_POP_32_S_10_5', 'R_LARCH_SOP_POP_32_S_5_20', - 'R_LARCH_SOP_POP_32_U', 'R_LARCH_SOP_POP_32_U_10_12', - 'R_LARCH_SOP_PUSH_ABSOLUTE', 'R_LARCH_SOP_PUSH_DUP', - 'R_LARCH_SOP_PUSH_GPREL', 'R_LARCH_SOP_PUSH_PCREL', - 'R_LARCH_SOP_PUSH_PLT_PCREL', 'R_LARCH_SOP_PUSH_TLS_GD', - 'R_LARCH_SOP_PUSH_TLS_GOT', 'R_LARCH_SOP_PUSH_TLS_TPREL', - 'R_LARCH_SOP_SL', 'R_LARCH_SOP_SR', 'R_LARCH_SOP_SUB', - 'R_LARCH_SUB16', 'R_LARCH_SUB24', 'R_LARCH_SUB32', 'R_LARCH_SUB6', - 'R_LARCH_SUB64', 'R_LARCH_SUB8', 'R_LARCH_SUB_ULEB128', - 'R_LARCH_TLS_DTPMOD32', 'R_LARCH_TLS_DTPMOD64', - 'R_LARCH_TLS_DTPREL32', 'R_LARCH_TLS_DTPREL64', - 'R_LARCH_TLS_GD_HI20', 'R_LARCH_TLS_GD_PC_HI20', - 'R_LARCH_TLS_IE64_HI12', 'R_LARCH_TLS_IE64_LO20', - 'R_LARCH_TLS_IE64_PC_HI12', 'R_LARCH_TLS_IE64_PC_LO20', - 'R_LARCH_TLS_IE_HI20', 'R_LARCH_TLS_IE_LO12', - 'R_LARCH_TLS_IE_PC_HI20', 'R_LARCH_TLS_IE_PC_LO12', - 'R_LARCH_TLS_LD_HI20', 'R_LARCH_TLS_LD_PC_HI20', - 'R_LARCH_TLS_LE64_HI12', 'R_LARCH_TLS_LE64_LO20', - 'R_LARCH_TLS_LE_HI20', 'R_LARCH_TLS_LE_LO12', - 'R_LARCH_TLS_TPREL32', 'R_LARCH_TLS_TPREL64', 'R_M32R_10_PCREL', - 'R_M32R_10_PCREL_RELA', 'R_M32R_16', 'R_M32R_16_RELA', - 'R_M32R_18_PCREL', 'R_M32R_18_PCREL_RELA', 'R_M32R_24', - 'R_M32R_24_RELA', 'R_M32R_26_PCREL', 'R_M32R_26_PCREL_RELA', - 'R_M32R_26_PLTREL', 'R_M32R_32', 'R_M32R_32_RELA', 'R_M32R_COPY', - 'R_M32R_GLOB_DAT', 'R_M32R_GNU_VTENTRY', 'R_M32R_GNU_VTINHERIT', - 'R_M32R_GOT16_HI_SLO', 'R_M32R_GOT16_HI_ULO', 'R_M32R_GOT16_LO', - 'R_M32R_GOT24', 'R_M32R_GOTOFF', 'R_M32R_GOTOFF_HI_SLO', - 'R_M32R_GOTOFF_HI_ULO', 'R_M32R_GOTOFF_LO', 'R_M32R_GOTPC24', - 'R_M32R_GOTPC_HI_SLO', 'R_M32R_GOTPC_HI_ULO', 'R_M32R_GOTPC_LO', - 'R_M32R_HI16_SLO', 'R_M32R_HI16_SLO_RELA', 'R_M32R_HI16_ULO', - 'R_M32R_HI16_ULO_RELA', 'R_M32R_JMP_SLOT', 'R_M32R_LO16', - 'R_M32R_LO16_RELA', 'R_M32R_NONE', 'R_M32R_NUM', 'R_M32R_REL32', - 'R_M32R_RELATIVE', 'R_M32R_RELA_GNU_VTENTRY', - 'R_M32R_RELA_GNU_VTINHERIT', 'R_M32R_SDA16', 'R_M32R_SDA16_RELA', - 'R_METAG_ADDR32', 'R_METAG_COPY', 'R_METAG_GETSETOFF', - 'R_METAG_GETSET_GOT', 'R_METAG_GETSET_GOTOFF', 'R_METAG_GLOB_DAT', - 'R_METAG_GNU_VTENTRY', 'R_METAG_GNU_VTINHERIT', 'R_METAG_GOTOFF', - 'R_METAG_HI16_GOTOFF', 'R_METAG_HI16_GOTPC', 'R_METAG_HI16_PLT', - 'R_METAG_HIADDR16', 'R_METAG_HIOG', 'R_METAG_JMP_SLOT', - 'R_METAG_LO16_GOTOFF', 'R_METAG_LO16_GOTPC', 'R_METAG_LO16_PLT', - 'R_METAG_LOADDR16', 'R_METAG_LOOG', 'R_METAG_NONE', 'R_METAG_PLT', - 'R_METAG_REG16OP1', 'R_METAG_REG16OP2', 'R_METAG_REG16OP3', - 'R_METAG_REG32OP1', 'R_METAG_REG32OP2', 'R_METAG_REG32OP3', - 'R_METAG_REG32OP4', 'R_METAG_REL16', 'R_METAG_REL8', - 'R_METAG_RELATIVE', 'R_METAG_RELBRANCH', 'R_METAG_RELBRANCH_PLT', - 'R_METAG_TLS_DTPMOD', 'R_METAG_TLS_DTPOFF', 'R_METAG_TLS_GD', - 'R_METAG_TLS_IE', 'R_METAG_TLS_IENONPIC', - 'R_METAG_TLS_IENONPIC_HI16', 'R_METAG_TLS_IENONPIC_LO16', - 'R_METAG_TLS_LDM', 'R_METAG_TLS_LDO', 'R_METAG_TLS_LDO_HI16', - 'R_METAG_TLS_LDO_LO16', 'R_METAG_TLS_LE', 'R_METAG_TLS_LE_HI16', - 'R_METAG_TLS_LE_LO16', 'R_METAG_TLS_TPOFF', 'R_MICROBLAZE_32', - 'R_MICROBLAZE_32_LO', 'R_MICROBLAZE_32_PCREL', - 'R_MICROBLAZE_32_PCREL_LO', 'R_MICROBLAZE_32_SYM_OP_SYM', - 'R_MICROBLAZE_64', 'R_MICROBLAZE_64_NONE', - 'R_MICROBLAZE_64_PCREL', 'R_MICROBLAZE_COPY', - 'R_MICROBLAZE_GLOB_DAT', 'R_MICROBLAZE_GNU_VTENTRY', - 'R_MICROBLAZE_GNU_VTINHERIT', 'R_MICROBLAZE_GOTOFF_32', - 'R_MICROBLAZE_GOTOFF_64', 'R_MICROBLAZE_GOTPC_64', - 'R_MICROBLAZE_GOT_64', 'R_MICROBLAZE_JUMP_SLOT', - 'R_MICROBLAZE_NONE', 'R_MICROBLAZE_PLT_64', 'R_MICROBLAZE_REL', - 'R_MICROBLAZE_SRO32', 'R_MICROBLAZE_SRW32', 'R_MICROBLAZE_TLS', - 'R_MICROBLAZE_TLSDTPMOD32', 'R_MICROBLAZE_TLSDTPREL32', - 'R_MICROBLAZE_TLSDTPREL64', 'R_MICROBLAZE_TLSGD', - 'R_MICROBLAZE_TLSGOTTPREL32', 'R_MICROBLAZE_TLSLD', - 'R_MICROBLAZE_TLSTPREL32', 'R_MICROMIPS_26_S1', - 'R_MICROMIPS_CALL16', 'R_MICROMIPS_CALL_HI16', - 'R_MICROMIPS_CALL_LO16', 'R_MICROMIPS_GOT16', - 'R_MICROMIPS_GOT_DISP', 'R_MICROMIPS_GOT_HI16', - 'R_MICROMIPS_GOT_LO16', 'R_MICROMIPS_GOT_OFST', - 'R_MICROMIPS_GOT_PAGE', 'R_MICROMIPS_GPREL16', - 'R_MICROMIPS_GPREL7_S2', 'R_MICROMIPS_HI0_LO16', - 'R_MICROMIPS_HI16', 'R_MICROMIPS_HIGHER', 'R_MICROMIPS_HIGHEST', - 'R_MICROMIPS_JALR', 'R_MICROMIPS_LITERAL', 'R_MICROMIPS_LO16', - 'R_MICROMIPS_PC10_S1', 'R_MICROMIPS_PC16_S1', - 'R_MICROMIPS_PC23_S2', 'R_MICROMIPS_PC7_S1', - 'R_MICROMIPS_SCN_DISP', 'R_MICROMIPS_SUB', - 'R_MICROMIPS_TLS_DTPREL_HI16', 'R_MICROMIPS_TLS_DTPREL_LO16', - 'R_MICROMIPS_TLS_GD', 'R_MICROMIPS_TLS_GOTTPREL', - 'R_MICROMIPS_TLS_LDM', 'R_MICROMIPS_TLS_TPREL_HI16', - 'R_MICROMIPS_TLS_TPREL_LO16', 'R_MIPS16_26', 'R_MIPS16_CALL16', - 'R_MIPS16_GOT16', 'R_MIPS16_GPREL', 'R_MIPS16_HI16', - 'R_MIPS16_LO16', 'R_MIPS16_PC16_S1', 'R_MIPS16_TLS_DTPREL_HI16', - 'R_MIPS16_TLS_DTPREL_LO16', 'R_MIPS16_TLS_GD', - 'R_MIPS16_TLS_GOTTPREL', 'R_MIPS16_TLS_LDM', - 'R_MIPS16_TLS_TPREL_HI16', 'R_MIPS16_TLS_TPREL_LO16', 'R_MIPS_16', - 'R_MIPS_26', 'R_MIPS_32', 'R_MIPS_64', 'R_MIPS_ADD_IMMEDIATE', - 'R_MIPS_CALL16', 'R_MIPS_CALL_HI16', 'R_MIPS_CALL_LO16', - 'R_MIPS_COPY', 'R_MIPS_DELETE', 'R_MIPS_EH', 'R_MIPS_GLOB_DAT', - 'R_MIPS_GNU_REL16_S2', 'R_MIPS_GNU_VTENTRY', - 'R_MIPS_GNU_VTINHERIT', 'R_MIPS_GOT16', 'R_MIPS_GOT_DISP', - 'R_MIPS_GOT_HI16', 'R_MIPS_GOT_LO16', 'R_MIPS_GOT_OFST', - 'R_MIPS_GOT_PAGE', 'R_MIPS_GPREL16', 'R_MIPS_GPREL32', - 'R_MIPS_HI16', 'R_MIPS_HIGHER', 'R_MIPS_HIGHEST', - 'R_MIPS_INSERT_A', 'R_MIPS_INSERT_B', 'R_MIPS_JALR', - 'R_MIPS_JUMP_SLOT', 'R_MIPS_LITERAL', 'R_MIPS_LO16', - 'R_MIPS_NONE', 'R_MIPS_NUM', 'R_MIPS_PC16', 'R_MIPS_PC18_S3', - 'R_MIPS_PC19_S2', 'R_MIPS_PC21_S2', 'R_MIPS_PC26_S2', - 'R_MIPS_PC32', 'R_MIPS_PCHI16', 'R_MIPS_PCLO16', 'R_MIPS_PJUMP', - 'R_MIPS_REL16', 'R_MIPS_REL32', 'R_MIPS_RELATIVE', - 'R_MIPS_RELGOT', 'R_MIPS_SCN_DISP', 'R_MIPS_SHIFT5', - 'R_MIPS_SHIFT6', 'R_MIPS_SUB', 'R_MIPS_TLS_DTPMOD32', - 'R_MIPS_TLS_DTPMOD64', 'R_MIPS_TLS_DTPREL32', - 'R_MIPS_TLS_DTPREL64', 'R_MIPS_TLS_DTPREL_HI16', - 'R_MIPS_TLS_DTPREL_LO16', 'R_MIPS_TLS_GD', 'R_MIPS_TLS_GOTTPREL', - 'R_MIPS_TLS_LDM', 'R_MIPS_TLS_TPREL32', 'R_MIPS_TLS_TPREL64', - 'R_MIPS_TLS_TPREL_HI16', 'R_MIPS_TLS_TPREL_LO16', 'R_MN10300_16', - 'R_MN10300_24', 'R_MN10300_32', 'R_MN10300_8', 'R_MN10300_ALIGN', - 'R_MN10300_COPY', 'R_MN10300_GLOB_DAT', 'R_MN10300_GNU_VTENTRY', - 'R_MN10300_GNU_VTINHERIT', 'R_MN10300_GOT16', 'R_MN10300_GOT24', - 'R_MN10300_GOT32', 'R_MN10300_GOTOFF16', 'R_MN10300_GOTOFF24', - 'R_MN10300_GOTOFF32', 'R_MN10300_GOTPC16', 'R_MN10300_GOTPC32', - 'R_MN10300_JMP_SLOT', 'R_MN10300_NONE', 'R_MN10300_NUM', - 'R_MN10300_PCREL16', 'R_MN10300_PCREL32', 'R_MN10300_PCREL8', - 'R_MN10300_PLT16', 'R_MN10300_PLT32', 'R_MN10300_RELATIVE', - 'R_MN10300_SYM_DIFF', 'R_MN10300_TLS_DTPMOD', - 'R_MN10300_TLS_DTPOFF', 'R_MN10300_TLS_GD', 'R_MN10300_TLS_GOTIE', - 'R_MN10300_TLS_IE', 'R_MN10300_TLS_LD', 'R_MN10300_TLS_LDO', - 'R_MN10300_TLS_LE', 'R_MN10300_TLS_TPOFF', 'R_NDS32_32_RELA', - 'R_NDS32_COPY', 'R_NDS32_GLOB_DAT', 'R_NDS32_JMP_SLOT', - 'R_NDS32_NONE', 'R_NDS32_RELATIVE', 'R_NDS32_TLS_DESC', - 'R_NDS32_TLS_TPOFF', 'R_NIOS2_ALIGN', 'R_NIOS2_BFD_RELOC_16', - 'R_NIOS2_BFD_RELOC_32', 'R_NIOS2_BFD_RELOC_8', - 'R_NIOS2_CACHE_OPX', 'R_NIOS2_CALL16', 'R_NIOS2_CALL26', - 'R_NIOS2_CALL26_NOAT', 'R_NIOS2_CALLR', 'R_NIOS2_CALL_HA', - 'R_NIOS2_CALL_LO', 'R_NIOS2_CJMP', 'R_NIOS2_COPY', - 'R_NIOS2_GLOB_DAT', 'R_NIOS2_GNU_VTENTRY', - 'R_NIOS2_GNU_VTINHERIT', 'R_NIOS2_GOT16', 'R_NIOS2_GOTOFF', - 'R_NIOS2_GOTOFF_HA', 'R_NIOS2_GOTOFF_LO', 'R_NIOS2_GOT_HA', - 'R_NIOS2_GOT_LO', 'R_NIOS2_GPREL', 'R_NIOS2_HI16', - 'R_NIOS2_HIADJ16', 'R_NIOS2_IMM5', 'R_NIOS2_IMM6', 'R_NIOS2_IMM8', - 'R_NIOS2_JUMP_SLOT', 'R_NIOS2_LO16', 'R_NIOS2_NONE', - 'R_NIOS2_PCREL16', 'R_NIOS2_PCREL_HA', 'R_NIOS2_PCREL_LO', - 'R_NIOS2_RELATIVE', 'R_NIOS2_S16', 'R_NIOS2_TLS_DTPMOD', - 'R_NIOS2_TLS_DTPREL', 'R_NIOS2_TLS_GD16', 'R_NIOS2_TLS_IE16', - 'R_NIOS2_TLS_LDM16', 'R_NIOS2_TLS_LDO16', 'R_NIOS2_TLS_LE16', - 'R_NIOS2_TLS_TPREL', 'R_NIOS2_U16', 'R_NIOS2_UJMP', 'R_OK', - 'R_OR1K_16', 'R_OR1K_16_PCREL', 'R_OR1K_32', 'R_OR1K_32_PCREL', - 'R_OR1K_8', 'R_OR1K_8_PCREL', 'R_OR1K_COPY', 'R_OR1K_GLOB_DAT', - 'R_OR1K_GNU_VTENTRY', 'R_OR1K_GNU_VTINHERIT', 'R_OR1K_GOT16', - 'R_OR1K_GOTOFF_HI16', 'R_OR1K_GOTOFF_LO16', 'R_OR1K_GOTPC_HI16', - 'R_OR1K_GOTPC_LO16', 'R_OR1K_HI_16_IN_INSN', 'R_OR1K_INSN_REL_26', - 'R_OR1K_JMP_SLOT', 'R_OR1K_LO_16_IN_INSN', 'R_OR1K_NONE', - 'R_OR1K_PLT26', 'R_OR1K_RELATIVE', 'R_OR1K_TLS_DTPMOD', - 'R_OR1K_TLS_DTPOFF', 'R_OR1K_TLS_GD_HI16', 'R_OR1K_TLS_GD_LO16', - 'R_OR1K_TLS_IE_HI16', 'R_OR1K_TLS_IE_LO16', 'R_OR1K_TLS_LDM_HI16', - 'R_OR1K_TLS_LDM_LO16', 'R_OR1K_TLS_LDO_HI16', - 'R_OR1K_TLS_LDO_LO16', 'R_OR1K_TLS_LE_HI16', 'R_OR1K_TLS_LE_LO16', - 'R_OR1K_TLS_TPOFF', 'R_PARISC_COPY', 'R_PARISC_DIR14DR', - 'R_PARISC_DIR14R', 'R_PARISC_DIR14WR', 'R_PARISC_DIR16DF', - 'R_PARISC_DIR16F', 'R_PARISC_DIR16WF', 'R_PARISC_DIR17F', - 'R_PARISC_DIR17R', 'R_PARISC_DIR21L', 'R_PARISC_DIR32', - 'R_PARISC_DIR64', 'R_PARISC_DPREL14R', 'R_PARISC_DPREL21L', - 'R_PARISC_EPLT', 'R_PARISC_FPTR64', 'R_PARISC_GNU_VTENTRY', - 'R_PARISC_GNU_VTINHERIT', 'R_PARISC_GPREL14DR', - 'R_PARISC_GPREL14R', 'R_PARISC_GPREL14WR', 'R_PARISC_GPREL16DF', - 'R_PARISC_GPREL16F', 'R_PARISC_GPREL16WF', 'R_PARISC_GPREL21L', - 'R_PARISC_GPREL64', 'R_PARISC_HIRESERVE', 'R_PARISC_IPLT', - 'R_PARISC_LORESERVE', 'R_PARISC_LTOFF14DR', 'R_PARISC_LTOFF14R', - 'R_PARISC_LTOFF14WR', 'R_PARISC_LTOFF16DF', 'R_PARISC_LTOFF16F', - 'R_PARISC_LTOFF16WF', 'R_PARISC_LTOFF21L', 'R_PARISC_LTOFF64', - 'R_PARISC_LTOFF_FPTR14DR', 'R_PARISC_LTOFF_FPTR14R', - 'R_PARISC_LTOFF_FPTR14WR', 'R_PARISC_LTOFF_FPTR16DF', - 'R_PARISC_LTOFF_FPTR16F', 'R_PARISC_LTOFF_FPTR16WF', - 'R_PARISC_LTOFF_FPTR21L', 'R_PARISC_LTOFF_FPTR32', - 'R_PARISC_LTOFF_FPTR64', 'R_PARISC_LTOFF_TP14DR', - 'R_PARISC_LTOFF_TP14F', 'R_PARISC_LTOFF_TP14R', - 'R_PARISC_LTOFF_TP14WR', 'R_PARISC_LTOFF_TP16DF', - 'R_PARISC_LTOFF_TP16F', 'R_PARISC_LTOFF_TP16WF', - 'R_PARISC_LTOFF_TP21L', 'R_PARISC_LTOFF_TP64', 'R_PARISC_NONE', - 'R_PARISC_PCREL14DR', 'R_PARISC_PCREL14R', 'R_PARISC_PCREL14WR', - 'R_PARISC_PCREL16DF', 'R_PARISC_PCREL16F', 'R_PARISC_PCREL16WF', - 'R_PARISC_PCREL17F', 'R_PARISC_PCREL17R', 'R_PARISC_PCREL21L', - 'R_PARISC_PCREL22F', 'R_PARISC_PCREL32', 'R_PARISC_PCREL64', - 'R_PARISC_PLABEL14R', 'R_PARISC_PLABEL21L', 'R_PARISC_PLABEL32', - 'R_PARISC_PLTOFF14DR', 'R_PARISC_PLTOFF14R', - 'R_PARISC_PLTOFF14WR', 'R_PARISC_PLTOFF16DF', - 'R_PARISC_PLTOFF16F', 'R_PARISC_PLTOFF16WF', 'R_PARISC_PLTOFF21L', - 'R_PARISC_SECREL32', 'R_PARISC_SECREL64', 'R_PARISC_SEGBASE', - 'R_PARISC_SEGREL32', 'R_PARISC_SEGREL64', 'R_PARISC_TLS_DTPMOD32', - 'R_PARISC_TLS_DTPMOD64', 'R_PARISC_TLS_DTPOFF32', - 'R_PARISC_TLS_DTPOFF64', 'R_PARISC_TLS_GD14R', - 'R_PARISC_TLS_GD21L', 'R_PARISC_TLS_GDCALL', 'R_PARISC_TLS_IE14R', - 'R_PARISC_TLS_IE21L', 'R_PARISC_TLS_LDM14R', - 'R_PARISC_TLS_LDM21L', 'R_PARISC_TLS_LDMCALL', - 'R_PARISC_TLS_LDO14R', 'R_PARISC_TLS_LDO21L', - 'R_PARISC_TLS_LE14R', 'R_PARISC_TLS_LE21L', - 'R_PARISC_TLS_TPREL32', 'R_PARISC_TLS_TPREL64', - 'R_PARISC_TPREL14DR', 'R_PARISC_TPREL14R', 'R_PARISC_TPREL14WR', - 'R_PARISC_TPREL16DF', 'R_PARISC_TPREL16F', 'R_PARISC_TPREL16WF', - 'R_PARISC_TPREL21L', 'R_PARISC_TPREL32', 'R_PARISC_TPREL64', - 'R_PPC64_ADDR14', 'R_PPC64_ADDR14_BRNTAKEN', - 'R_PPC64_ADDR14_BRTAKEN', 'R_PPC64_ADDR16', 'R_PPC64_ADDR16_DS', - 'R_PPC64_ADDR16_HA', 'R_PPC64_ADDR16_HI', 'R_PPC64_ADDR16_HIGH', - 'R_PPC64_ADDR16_HIGHA', 'R_PPC64_ADDR16_HIGHER', - 'R_PPC64_ADDR16_HIGHERA', 'R_PPC64_ADDR16_HIGHEST', - 'R_PPC64_ADDR16_HIGHESTA', 'R_PPC64_ADDR16_LO', - 'R_PPC64_ADDR16_LO_DS', 'R_PPC64_ADDR24', 'R_PPC64_ADDR30', - 'R_PPC64_ADDR32', 'R_PPC64_ADDR64', 'R_PPC64_COPY', - 'R_PPC64_DTPMOD64', 'R_PPC64_DTPREL16', 'R_PPC64_DTPREL16_DS', - 'R_PPC64_DTPREL16_HA', 'R_PPC64_DTPREL16_HI', - 'R_PPC64_DTPREL16_HIGH', 'R_PPC64_DTPREL16_HIGHA', - 'R_PPC64_DTPREL16_HIGHER', 'R_PPC64_DTPREL16_HIGHERA', - 'R_PPC64_DTPREL16_HIGHEST', 'R_PPC64_DTPREL16_HIGHESTA', - 'R_PPC64_DTPREL16_LO', 'R_PPC64_DTPREL16_LO_DS', - 'R_PPC64_DTPREL64', 'R_PPC64_GLOB_DAT', 'R_PPC64_GOT16', - 'R_PPC64_GOT16_DS', 'R_PPC64_GOT16_HA', 'R_PPC64_GOT16_HI', - 'R_PPC64_GOT16_LO', 'R_PPC64_GOT16_LO_DS', - 'R_PPC64_GOT_DTPREL16_DS', 'R_PPC64_GOT_DTPREL16_HA', - 'R_PPC64_GOT_DTPREL16_HI', 'R_PPC64_GOT_DTPREL16_LO_DS', - 'R_PPC64_GOT_TLSGD16', 'R_PPC64_GOT_TLSGD16_HA', - 'R_PPC64_GOT_TLSGD16_HI', 'R_PPC64_GOT_TLSGD16_LO', - 'R_PPC64_GOT_TLSLD16', 'R_PPC64_GOT_TLSLD16_HA', - 'R_PPC64_GOT_TLSLD16_HI', 'R_PPC64_GOT_TLSLD16_LO', - 'R_PPC64_GOT_TPREL16_DS', 'R_PPC64_GOT_TPREL16_HA', - 'R_PPC64_GOT_TPREL16_HI', 'R_PPC64_GOT_TPREL16_LO_DS', - 'R_PPC64_IRELATIVE', 'R_PPC64_JMP_IREL', 'R_PPC64_JMP_SLOT', - 'R_PPC64_NONE', 'R_PPC64_PLT16_HA', 'R_PPC64_PLT16_HI', - 'R_PPC64_PLT16_LO', 'R_PPC64_PLT16_LO_DS', 'R_PPC64_PLT32', - 'R_PPC64_PLT64', 'R_PPC64_PLTGOT16', 'R_PPC64_PLTGOT16_DS', - 'R_PPC64_PLTGOT16_HA', 'R_PPC64_PLTGOT16_HI', - 'R_PPC64_PLTGOT16_LO', 'R_PPC64_PLTGOT16_LO_DS', - 'R_PPC64_PLTREL32', 'R_PPC64_PLTREL64', 'R_PPC64_REL14', - 'R_PPC64_REL14_BRNTAKEN', 'R_PPC64_REL14_BRTAKEN', - 'R_PPC64_REL16', 'R_PPC64_REL16_HA', 'R_PPC64_REL16_HI', - 'R_PPC64_REL16_LO', 'R_PPC64_REL24', 'R_PPC64_REL32', - 'R_PPC64_REL64', 'R_PPC64_RELATIVE', 'R_PPC64_SECTOFF', - 'R_PPC64_SECTOFF_DS', 'R_PPC64_SECTOFF_HA', 'R_PPC64_SECTOFF_HI', - 'R_PPC64_SECTOFF_LO', 'R_PPC64_SECTOFF_LO_DS', 'R_PPC64_TLS', - 'R_PPC64_TLSGD', 'R_PPC64_TLSLD', 'R_PPC64_TOC', 'R_PPC64_TOC16', - 'R_PPC64_TOC16_DS', 'R_PPC64_TOC16_HA', 'R_PPC64_TOC16_HI', - 'R_PPC64_TOC16_LO', 'R_PPC64_TOC16_LO_DS', 'R_PPC64_TOCSAVE', - 'R_PPC64_TPREL16', 'R_PPC64_TPREL16_DS', 'R_PPC64_TPREL16_HA', - 'R_PPC64_TPREL16_HI', 'R_PPC64_TPREL16_HIGH', - 'R_PPC64_TPREL16_HIGHA', 'R_PPC64_TPREL16_HIGHER', - 'R_PPC64_TPREL16_HIGHERA', 'R_PPC64_TPREL16_HIGHEST', - 'R_PPC64_TPREL16_HIGHESTA', 'R_PPC64_TPREL16_LO', - 'R_PPC64_TPREL16_LO_DS', 'R_PPC64_TPREL64', 'R_PPC64_UADDR16', - 'R_PPC64_UADDR32', 'R_PPC64_UADDR64', 'R_PPC_ADDR14', - 'R_PPC_ADDR14_BRNTAKEN', 'R_PPC_ADDR14_BRTAKEN', 'R_PPC_ADDR16', - 'R_PPC_ADDR16_HA', 'R_PPC_ADDR16_HI', 'R_PPC_ADDR16_LO', - 'R_PPC_ADDR24', 'R_PPC_ADDR32', 'R_PPC_COPY', - 'R_PPC_DIAB_RELSDA_HA', 'R_PPC_DIAB_RELSDA_HI', - 'R_PPC_DIAB_RELSDA_LO', 'R_PPC_DIAB_SDA21_HA', - 'R_PPC_DIAB_SDA21_HI', 'R_PPC_DIAB_SDA21_LO', 'R_PPC_DTPMOD32', - 'R_PPC_DTPREL16', 'R_PPC_DTPREL16_HA', 'R_PPC_DTPREL16_HI', - 'R_PPC_DTPREL16_LO', 'R_PPC_DTPREL32', 'R_PPC_EMB_BIT_FLD', - 'R_PPC_EMB_MRKREF', 'R_PPC_EMB_NADDR16', 'R_PPC_EMB_NADDR16_HA', - 'R_PPC_EMB_NADDR16_HI', 'R_PPC_EMB_NADDR16_LO', - 'R_PPC_EMB_NADDR32', 'R_PPC_EMB_RELSDA', 'R_PPC_EMB_RELSEC16', - 'R_PPC_EMB_RELST_HA', 'R_PPC_EMB_RELST_HI', 'R_PPC_EMB_RELST_LO', - 'R_PPC_EMB_SDA21', 'R_PPC_EMB_SDA2I16', 'R_PPC_EMB_SDA2REL', - 'R_PPC_EMB_SDAI16', 'R_PPC_GLOB_DAT', 'R_PPC_GOT16', - 'R_PPC_GOT16_HA', 'R_PPC_GOT16_HI', 'R_PPC_GOT16_LO', - 'R_PPC_GOT_DTPREL16', 'R_PPC_GOT_DTPREL16_HA', - 'R_PPC_GOT_DTPREL16_HI', 'R_PPC_GOT_DTPREL16_LO', - 'R_PPC_GOT_TLSGD16', 'R_PPC_GOT_TLSGD16_HA', - 'R_PPC_GOT_TLSGD16_HI', 'R_PPC_GOT_TLSGD16_LO', - 'R_PPC_GOT_TLSLD16', 'R_PPC_GOT_TLSLD16_HA', - 'R_PPC_GOT_TLSLD16_HI', 'R_PPC_GOT_TLSLD16_LO', - 'R_PPC_GOT_TPREL16', 'R_PPC_GOT_TPREL16_HA', - 'R_PPC_GOT_TPREL16_HI', 'R_PPC_GOT_TPREL16_LO', 'R_PPC_IRELATIVE', - 'R_PPC_JMP_SLOT', 'R_PPC_LOCAL24PC', 'R_PPC_NONE', - 'R_PPC_PLT16_HA', 'R_PPC_PLT16_HI', 'R_PPC_PLT16_LO', - 'R_PPC_PLT32', 'R_PPC_PLTREL24', 'R_PPC_PLTREL32', 'R_PPC_REL14', - 'R_PPC_REL14_BRNTAKEN', 'R_PPC_REL14_BRTAKEN', 'R_PPC_REL16', - 'R_PPC_REL16_HA', 'R_PPC_REL16_HI', 'R_PPC_REL16_LO', - 'R_PPC_REL24', 'R_PPC_REL32', 'R_PPC_RELATIVE', 'R_PPC_SDAREL16', - 'R_PPC_SECTOFF', 'R_PPC_SECTOFF_HA', 'R_PPC_SECTOFF_HI', - 'R_PPC_SECTOFF_LO', 'R_PPC_TLS', 'R_PPC_TLSGD', 'R_PPC_TLSLD', - 'R_PPC_TOC16', 'R_PPC_TPREL16', 'R_PPC_TPREL16_HA', - 'R_PPC_TPREL16_HI', 'R_PPC_TPREL16_LO', 'R_PPC_TPREL32', - 'R_PPC_UADDR16', 'R_PPC_UADDR32', 'R_RISCV_32', - 'R_RISCV_32_PCREL', 'R_RISCV_64', 'R_RISCV_ADD16', - 'R_RISCV_ADD32', 'R_RISCV_ADD64', 'R_RISCV_ADD8', 'R_RISCV_ALIGN', - 'R_RISCV_BRANCH', 'R_RISCV_CALL', 'R_RISCV_CALL_PLT', - 'R_RISCV_COPY', 'R_RISCV_GNU_VTENTRY', 'R_RISCV_GNU_VTINHERIT', - 'R_RISCV_GOT_HI20', 'R_RISCV_GPREL_I', 'R_RISCV_GPREL_S', - 'R_RISCV_HI20', 'R_RISCV_IRELATIVE', 'R_RISCV_JAL', - 'R_RISCV_JUMP_SLOT', 'R_RISCV_LO12_I', 'R_RISCV_LO12_S', - 'R_RISCV_NONE', 'R_RISCV_NUM', 'R_RISCV_PCREL_HI20', - 'R_RISCV_PCREL_LO12_I', 'R_RISCV_PCREL_LO12_S', 'R_RISCV_PLT32', - 'R_RISCV_RELATIVE', 'R_RISCV_RELAX', 'R_RISCV_RVC_BRANCH', - 'R_RISCV_RVC_JUMP', 'R_RISCV_RVC_LUI', 'R_RISCV_SET16', - 'R_RISCV_SET32', 'R_RISCV_SET6', 'R_RISCV_SET8', - 'R_RISCV_SET_ULEB128', 'R_RISCV_SUB16', 'R_RISCV_SUB32', - 'R_RISCV_SUB6', 'R_RISCV_SUB64', 'R_RISCV_SUB8', - 'R_RISCV_SUB_ULEB128', 'R_RISCV_TLS_DTPMOD32', - 'R_RISCV_TLS_DTPMOD64', 'R_RISCV_TLS_DTPREL32', - 'R_RISCV_TLS_DTPREL64', 'R_RISCV_TLS_GD_HI20', - 'R_RISCV_TLS_GOT_HI20', 'R_RISCV_TLS_TPREL32', - 'R_RISCV_TLS_TPREL64', 'R_RISCV_TPREL_ADD', 'R_RISCV_TPREL_HI20', - 'R_RISCV_TPREL_I', 'R_RISCV_TPREL_LO12_I', 'R_RISCV_TPREL_LO12_S', - 'R_RISCV_TPREL_S', 'R_SH_ALIGN', 'R_SH_CODE', 'R_SH_COPY', - 'R_SH_COUNT', 'R_SH_DATA', 'R_SH_DIR32', 'R_SH_DIR8BP', - 'R_SH_DIR8L', 'R_SH_DIR8W', 'R_SH_DIR8WPL', 'R_SH_DIR8WPN', - 'R_SH_DIR8WPZ', 'R_SH_GLOB_DAT', 'R_SH_GNU_VTENTRY', - 'R_SH_GNU_VTINHERIT', 'R_SH_GOT32', 'R_SH_GOTOFF', 'R_SH_GOTPC', - 'R_SH_IND12W', 'R_SH_JMP_SLOT', 'R_SH_LABEL', 'R_SH_NONE', - 'R_SH_NUM', 'R_SH_PLT32', 'R_SH_REL32', 'R_SH_RELATIVE', - 'R_SH_SWITCH16', 'R_SH_SWITCH32', 'R_SH_SWITCH8', - 'R_SH_TLS_DTPMOD32', 'R_SH_TLS_DTPOFF32', 'R_SH_TLS_GD_32', - 'R_SH_TLS_IE_32', 'R_SH_TLS_LDO_32', 'R_SH_TLS_LD_32', - 'R_SH_TLS_LE_32', 'R_SH_TLS_TPOFF32', 'R_SH_USES', 'R_SPARC_10', - 'R_SPARC_11', 'R_SPARC_13', 'R_SPARC_16', 'R_SPARC_22', - 'R_SPARC_32', 'R_SPARC_5', 'R_SPARC_6', 'R_SPARC_64', 'R_SPARC_7', - 'R_SPARC_8', 'R_SPARC_COPY', 'R_SPARC_DISP16', 'R_SPARC_DISP32', - 'R_SPARC_DISP64', 'R_SPARC_DISP8', 'R_SPARC_GLOB_DAT', - 'R_SPARC_GLOB_JMP', 'R_SPARC_GNU_VTENTRY', - 'R_SPARC_GNU_VTINHERIT', 'R_SPARC_GOT10', 'R_SPARC_GOT13', - 'R_SPARC_GOT22', 'R_SPARC_GOTDATA_HIX22', 'R_SPARC_GOTDATA_LOX10', - 'R_SPARC_GOTDATA_OP', 'R_SPARC_GOTDATA_OP_HIX22', - 'R_SPARC_GOTDATA_OP_LOX10', 'R_SPARC_H34', 'R_SPARC_H44', - 'R_SPARC_HH22', 'R_SPARC_HI22', 'R_SPARC_HIPLT22', - 'R_SPARC_HIX22', 'R_SPARC_HM10', 'R_SPARC_IRELATIVE', - 'R_SPARC_JMP_IREL', 'R_SPARC_JMP_SLOT', 'R_SPARC_L44', - 'R_SPARC_LM22', 'R_SPARC_LO10', 'R_SPARC_LOPLT10', - 'R_SPARC_LOX10', 'R_SPARC_M44', 'R_SPARC_NONE', 'R_SPARC_NUM', - 'R_SPARC_OLO10', 'R_SPARC_PC10', 'R_SPARC_PC22', - 'R_SPARC_PCPLT10', 'R_SPARC_PCPLT22', 'R_SPARC_PCPLT32', - 'R_SPARC_PC_HH22', 'R_SPARC_PC_HM10', 'R_SPARC_PC_LM22', - 'R_SPARC_PLT32', 'R_SPARC_PLT64', 'R_SPARC_REGISTER', - 'R_SPARC_RELATIVE', 'R_SPARC_REV32', 'R_SPARC_SIZE32', - 'R_SPARC_SIZE64', 'R_SPARC_TLS_DTPMOD32', 'R_SPARC_TLS_DTPMOD64', - 'R_SPARC_TLS_DTPOFF32', 'R_SPARC_TLS_DTPOFF64', - 'R_SPARC_TLS_GD_ADD', 'R_SPARC_TLS_GD_CALL', - 'R_SPARC_TLS_GD_HI22', 'R_SPARC_TLS_GD_LO10', - 'R_SPARC_TLS_IE_ADD', 'R_SPARC_TLS_IE_HI22', 'R_SPARC_TLS_IE_LD', - 'R_SPARC_TLS_IE_LDX', 'R_SPARC_TLS_IE_LO10', - 'R_SPARC_TLS_LDM_ADD', 'R_SPARC_TLS_LDM_CALL', - 'R_SPARC_TLS_LDM_HI22', 'R_SPARC_TLS_LDM_LO10', - 'R_SPARC_TLS_LDO_ADD', 'R_SPARC_TLS_LDO_HIX22', - 'R_SPARC_TLS_LDO_LOX10', 'R_SPARC_TLS_LE_HIX22', - 'R_SPARC_TLS_LE_LOX10', 'R_SPARC_TLS_TPOFF32', - 'R_SPARC_TLS_TPOFF64', 'R_SPARC_UA16', 'R_SPARC_UA32', - 'R_SPARC_UA64', 'R_SPARC_WDISP10', 'R_SPARC_WDISP16', - 'R_SPARC_WDISP19', 'R_SPARC_WDISP22', 'R_SPARC_WDISP30', - 'R_SPARC_WPLT30', 'R_TILEGX_16', 'R_TILEGX_16_PCREL', - 'R_TILEGX_32', 'R_TILEGX_32_PCREL', 'R_TILEGX_64', - 'R_TILEGX_64_PCREL', 'R_TILEGX_8', 'R_TILEGX_8_PCREL', - 'R_TILEGX_BROFF_X1', 'R_TILEGX_COPY', 'R_TILEGX_DEST_IMM8_X1', - 'R_TILEGX_GLOB_DAT', 'R_TILEGX_GNU_VTENTRY', - 'R_TILEGX_GNU_VTINHERIT', 'R_TILEGX_HW0', 'R_TILEGX_HW0_LAST', - 'R_TILEGX_HW1', 'R_TILEGX_HW1_LAST', 'R_TILEGX_HW2', - 'R_TILEGX_HW2_LAST', 'R_TILEGX_HW3', 'R_TILEGX_IMM16_X0_HW0', - 'R_TILEGX_IMM16_X0_HW0_GOT', 'R_TILEGX_IMM16_X0_HW0_LAST', - 'R_TILEGX_IMM16_X0_HW0_LAST_GOT', - 'R_TILEGX_IMM16_X0_HW0_LAST_PCREL', - 'R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL', - 'R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD', - 'R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE', - 'R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE', - 'R_TILEGX_IMM16_X0_HW0_PCREL', 'R_TILEGX_IMM16_X0_HW0_PLT_PCREL', - 'R_TILEGX_IMM16_X0_HW0_TLS_GD', 'R_TILEGX_IMM16_X0_HW0_TLS_IE', - 'R_TILEGX_IMM16_X0_HW0_TLS_LE', 'R_TILEGX_IMM16_X0_HW1', - 'R_TILEGX_IMM16_X0_HW1_LAST', 'R_TILEGX_IMM16_X0_HW1_LAST_GOT', - 'R_TILEGX_IMM16_X0_HW1_LAST_PCREL', - 'R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL', - 'R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD', - 'R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE', - 'R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE', - 'R_TILEGX_IMM16_X0_HW1_PCREL', 'R_TILEGX_IMM16_X0_HW1_PLT_PCREL', - 'R_TILEGX_IMM16_X0_HW2', 'R_TILEGX_IMM16_X0_HW2_LAST', - 'R_TILEGX_IMM16_X0_HW2_LAST_PCREL', - 'R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL', - 'R_TILEGX_IMM16_X0_HW2_PCREL', 'R_TILEGX_IMM16_X0_HW2_PLT_PCREL', - 'R_TILEGX_IMM16_X0_HW3', 'R_TILEGX_IMM16_X0_HW3_PCREL', - 'R_TILEGX_IMM16_X0_HW3_PLT_PCREL', 'R_TILEGX_IMM16_X1_HW0', - 'R_TILEGX_IMM16_X1_HW0_GOT', 'R_TILEGX_IMM16_X1_HW0_LAST', - 'R_TILEGX_IMM16_X1_HW0_LAST_GOT', - 'R_TILEGX_IMM16_X1_HW0_LAST_PCREL', - 'R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL', - 'R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD', - 'R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE', - 'R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE', - 'R_TILEGX_IMM16_X1_HW0_PCREL', 'R_TILEGX_IMM16_X1_HW0_PLT_PCREL', - 'R_TILEGX_IMM16_X1_HW0_TLS_GD', 'R_TILEGX_IMM16_X1_HW0_TLS_IE', - 'R_TILEGX_IMM16_X1_HW0_TLS_LE', 'R_TILEGX_IMM16_X1_HW1', - 'R_TILEGX_IMM16_X1_HW1_LAST', 'R_TILEGX_IMM16_X1_HW1_LAST_GOT', - 'R_TILEGX_IMM16_X1_HW1_LAST_PCREL', - 'R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL', - 'R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD', - 'R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE', - 'R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE', - 'R_TILEGX_IMM16_X1_HW1_PCREL', 'R_TILEGX_IMM16_X1_HW1_PLT_PCREL', - 'R_TILEGX_IMM16_X1_HW2', 'R_TILEGX_IMM16_X1_HW2_LAST', - 'R_TILEGX_IMM16_X1_HW2_LAST_PCREL', - 'R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL', - 'R_TILEGX_IMM16_X1_HW2_PCREL', 'R_TILEGX_IMM16_X1_HW2_PLT_PCREL', - 'R_TILEGX_IMM16_X1_HW3', 'R_TILEGX_IMM16_X1_HW3_PCREL', - 'R_TILEGX_IMM16_X1_HW3_PLT_PCREL', 'R_TILEGX_IMM8_X0', - 'R_TILEGX_IMM8_X0_TLS_ADD', 'R_TILEGX_IMM8_X0_TLS_GD_ADD', - 'R_TILEGX_IMM8_X1', 'R_TILEGX_IMM8_X1_TLS_ADD', - 'R_TILEGX_IMM8_X1_TLS_GD_ADD', 'R_TILEGX_IMM8_Y0', - 'R_TILEGX_IMM8_Y0_TLS_ADD', 'R_TILEGX_IMM8_Y0_TLS_GD_ADD', - 'R_TILEGX_IMM8_Y1', 'R_TILEGX_IMM8_Y1_TLS_ADD', - 'R_TILEGX_IMM8_Y1_TLS_GD_ADD', 'R_TILEGX_JMP_SLOT', - 'R_TILEGX_JUMPOFF_X1', 'R_TILEGX_JUMPOFF_X1_PLT', - 'R_TILEGX_MF_IMM14_X1', 'R_TILEGX_MMEND_X0', - 'R_TILEGX_MMSTART_X0', 'R_TILEGX_MT_IMM14_X1', 'R_TILEGX_NONE', - 'R_TILEGX_NUM', 'R_TILEGX_RELATIVE', 'R_TILEGX_SHAMT_X0', - 'R_TILEGX_SHAMT_X1', 'R_TILEGX_SHAMT_Y0', 'R_TILEGX_SHAMT_Y1', - 'R_TILEGX_TLS_DTPMOD32', 'R_TILEGX_TLS_DTPMOD64', - 'R_TILEGX_TLS_DTPOFF32', 'R_TILEGX_TLS_DTPOFF64', - 'R_TILEGX_TLS_GD_CALL', 'R_TILEGX_TLS_IE_LOAD', - 'R_TILEGX_TLS_TPOFF32', 'R_TILEGX_TLS_TPOFF64', 'R_TILEPRO_16', - 'R_TILEPRO_16_PCREL', 'R_TILEPRO_32', 'R_TILEPRO_32_PCREL', - 'R_TILEPRO_8', 'R_TILEPRO_8_PCREL', 'R_TILEPRO_BROFF_X1', - 'R_TILEPRO_COPY', 'R_TILEPRO_DEST_IMM8_X1', 'R_TILEPRO_GLOB_DAT', - 'R_TILEPRO_GNU_VTENTRY', 'R_TILEPRO_GNU_VTINHERIT', - 'R_TILEPRO_HA16', 'R_TILEPRO_HI16', 'R_TILEPRO_IMM16_X0', - 'R_TILEPRO_IMM16_X0_GOT', 'R_TILEPRO_IMM16_X0_GOT_HA', - 'R_TILEPRO_IMM16_X0_GOT_HI', 'R_TILEPRO_IMM16_X0_GOT_LO', - 'R_TILEPRO_IMM16_X0_HA', 'R_TILEPRO_IMM16_X0_HA_PCREL', - 'R_TILEPRO_IMM16_X0_HI', 'R_TILEPRO_IMM16_X0_HI_PCREL', - 'R_TILEPRO_IMM16_X0_LO', 'R_TILEPRO_IMM16_X0_LO_PCREL', - 'R_TILEPRO_IMM16_X0_PCREL', 'R_TILEPRO_IMM16_X0_TLS_GD', - 'R_TILEPRO_IMM16_X0_TLS_GD_HA', 'R_TILEPRO_IMM16_X0_TLS_GD_HI', - 'R_TILEPRO_IMM16_X0_TLS_GD_LO', 'R_TILEPRO_IMM16_X0_TLS_IE', - 'R_TILEPRO_IMM16_X0_TLS_IE_HA', 'R_TILEPRO_IMM16_X0_TLS_IE_HI', - 'R_TILEPRO_IMM16_X0_TLS_IE_LO', 'R_TILEPRO_IMM16_X0_TLS_LE', - 'R_TILEPRO_IMM16_X0_TLS_LE_HA', 'R_TILEPRO_IMM16_X0_TLS_LE_HI', - 'R_TILEPRO_IMM16_X0_TLS_LE_LO', 'R_TILEPRO_IMM16_X1', - 'R_TILEPRO_IMM16_X1_GOT', 'R_TILEPRO_IMM16_X1_GOT_HA', - 'R_TILEPRO_IMM16_X1_GOT_HI', 'R_TILEPRO_IMM16_X1_GOT_LO', - 'R_TILEPRO_IMM16_X1_HA', 'R_TILEPRO_IMM16_X1_HA_PCREL', - 'R_TILEPRO_IMM16_X1_HI', 'R_TILEPRO_IMM16_X1_HI_PCREL', - 'R_TILEPRO_IMM16_X1_LO', 'R_TILEPRO_IMM16_X1_LO_PCREL', - 'R_TILEPRO_IMM16_X1_PCREL', 'R_TILEPRO_IMM16_X1_TLS_GD', - 'R_TILEPRO_IMM16_X1_TLS_GD_HA', 'R_TILEPRO_IMM16_X1_TLS_GD_HI', - 'R_TILEPRO_IMM16_X1_TLS_GD_LO', 'R_TILEPRO_IMM16_X1_TLS_IE', - 'R_TILEPRO_IMM16_X1_TLS_IE_HA', 'R_TILEPRO_IMM16_X1_TLS_IE_HI', - 'R_TILEPRO_IMM16_X1_TLS_IE_LO', 'R_TILEPRO_IMM16_X1_TLS_LE', - 'R_TILEPRO_IMM16_X1_TLS_LE_HA', 'R_TILEPRO_IMM16_X1_TLS_LE_HI', - 'R_TILEPRO_IMM16_X1_TLS_LE_LO', 'R_TILEPRO_IMM8_X0', - 'R_TILEPRO_IMM8_X0_TLS_GD_ADD', 'R_TILEPRO_IMM8_X1', - 'R_TILEPRO_IMM8_X1_TLS_GD_ADD', 'R_TILEPRO_IMM8_Y0', - 'R_TILEPRO_IMM8_Y0_TLS_GD_ADD', 'R_TILEPRO_IMM8_Y1', - 'R_TILEPRO_IMM8_Y1_TLS_GD_ADD', 'R_TILEPRO_JMP_SLOT', - 'R_TILEPRO_JOFFLONG_X1', 'R_TILEPRO_JOFFLONG_X1_PLT', - 'R_TILEPRO_LO16', 'R_TILEPRO_MF_IMM15_X1', 'R_TILEPRO_MMEND_X0', - 'R_TILEPRO_MMEND_X1', 'R_TILEPRO_MMSTART_X0', - 'R_TILEPRO_MMSTART_X1', 'R_TILEPRO_MT_IMM15_X1', 'R_TILEPRO_NONE', - 'R_TILEPRO_NUM', 'R_TILEPRO_RELATIVE', 'R_TILEPRO_SHAMT_X0', - 'R_TILEPRO_SHAMT_X1', 'R_TILEPRO_SHAMT_Y0', 'R_TILEPRO_SHAMT_Y1', - 'R_TILEPRO_TLS_DTPMOD32', 'R_TILEPRO_TLS_DTPOFF32', - 'R_TILEPRO_TLS_GD_CALL', 'R_TILEPRO_TLS_IE_LOAD', - 'R_TILEPRO_TLS_TPOFF32', 'R_X86_64_16', 'R_X86_64_32', - 'R_X86_64_32S', 'R_X86_64_64', 'R_X86_64_8', 'R_X86_64_COPY', - 'R_X86_64_DTPMOD64', 'R_X86_64_DTPOFF32', 'R_X86_64_DTPOFF64', - 'R_X86_64_GLOB_DAT', 'R_X86_64_GOT32', 'R_X86_64_GOT64', - 'R_X86_64_GOTOFF64', 'R_X86_64_GOTPC32', - 'R_X86_64_GOTPC32_TLSDESC', 'R_X86_64_GOTPC64', - 'R_X86_64_GOTPCREL', 'R_X86_64_GOTPCREL64', 'R_X86_64_GOTPCRELX', - 'R_X86_64_GOTPLT64', 'R_X86_64_GOTTPOFF', 'R_X86_64_IRELATIVE', - 'R_X86_64_JUMP_SLOT', 'R_X86_64_NONE', 'R_X86_64_NUM', - 'R_X86_64_PC16', 'R_X86_64_PC32', 'R_X86_64_PC64', 'R_X86_64_PC8', - 'R_X86_64_PLT32', 'R_X86_64_PLTOFF64', 'R_X86_64_RELATIVE', - 'R_X86_64_RELATIVE64', 'R_X86_64_REX_GOTPCRELX', - 'R_X86_64_SIZE32', 'R_X86_64_SIZE64', 'R_X86_64_TLSDESC', - 'R_X86_64_TLSDESC_CALL', 'R_X86_64_TLSGD', 'R_X86_64_TLSLD', - 'R_X86_64_TPOFF32', 'R_X86_64_TPOFF64', 'SEEK_CUR', 'SEEK_END', - 'SEEK_SET', 'SELFMAG', 'SHF_ALLOC', 'SHF_ALPHA_GPREL', - 'SHF_ARM_COMDEF', 'SHF_ARM_ENTRYSECT', 'SHF_COMPRESSED', - 'SHF_EXCLUDE', 'SHF_EXECINSTR', 'SHF_GNU_RETAIN', 'SHF_GROUP', - 'SHF_IA_64_NORECOV', 'SHF_IA_64_SHORT', 'SHF_INFO_LINK', - 'SHF_LINK_ORDER', 'SHF_MASKOS', 'SHF_MASKPROC', 'SHF_MERGE', - 'SHF_MIPS_ADDR', 'SHF_MIPS_GPREL', 'SHF_MIPS_LOCAL', - 'SHF_MIPS_MERGE', 'SHF_MIPS_NAMES', 'SHF_MIPS_NODUPE', - 'SHF_MIPS_NOSTRIP', 'SHF_MIPS_STRINGS', 'SHF_ORDERED', - 'SHF_OS_NONCONFORMING', 'SHF_PARISC_HUGE', 'SHF_PARISC_SBP', - 'SHF_PARISC_SHORT', 'SHF_STRINGS', 'SHF_TLS', 'SHF_WRITE', - 'SHN_ABS', 'SHN_AFTER', 'SHN_BEFORE', 'SHN_COMMON', 'SHN_HIOS', - 'SHN_HIPROC', 'SHN_HIRESERVE', 'SHN_LOOS', 'SHN_LOPROC', - 'SHN_LORESERVE', 'SHN_MIPS_ACOMMON', 'SHN_MIPS_DATA', - 'SHN_MIPS_SCOMMON', 'SHN_MIPS_SUNDEFINED', 'SHN_MIPS_TEXT', - 'SHN_PARISC_ANSI_COMMON', 'SHN_PARISC_HUGE_COMMON', 'SHN_UNDEF', - 'SHN_XINDEX', 'SHT_ALPHA_DEBUG', 'SHT_ALPHA_REGINFO', - 'SHT_ARC_ATTRIBUTES', 'SHT_ARM_ATTRIBUTES', 'SHT_ARM_EXIDX', - 'SHT_ARM_PREEMPTMAP', 'SHT_CHECKSUM', 'SHT_CSKY_ATTRIBUTES', - 'SHT_DYNAMIC', 'SHT_DYNSYM', 'SHT_FINI_ARRAY', - 'SHT_GNU_ATTRIBUTES', 'SHT_GNU_HASH', 'SHT_GNU_LIBLIST', - 'SHT_GNU_verdef', 'SHT_GNU_verneed', 'SHT_GNU_versym', - 'SHT_GROUP', 'SHT_HASH', 'SHT_HIOS', 'SHT_HIPROC', 'SHT_HISUNW', - 'SHT_HIUSER', 'SHT_IA_64_EXT', 'SHT_IA_64_UNWIND', - 'SHT_INIT_ARRAY', 'SHT_LOOS', 'SHT_LOPROC', 'SHT_LOSUNW', - 'SHT_LOUSER', 'SHT_MIPS_ABIFLAGS', 'SHT_MIPS_AUXSYM', - 'SHT_MIPS_CONFLICT', 'SHT_MIPS_CONTENT', 'SHT_MIPS_DEBUG', - 'SHT_MIPS_DELTACLASS', 'SHT_MIPS_DELTADECL', 'SHT_MIPS_DELTAINST', - 'SHT_MIPS_DELTASYM', 'SHT_MIPS_DENSE', 'SHT_MIPS_DWARF', - 'SHT_MIPS_EH_REGION', 'SHT_MIPS_EVENTS', 'SHT_MIPS_EXTSYM', - 'SHT_MIPS_FDESC', 'SHT_MIPS_GPTAB', 'SHT_MIPS_IFACE', - 'SHT_MIPS_LIBLIST', 'SHT_MIPS_LINE', 'SHT_MIPS_LOCSTR', - 'SHT_MIPS_LOCSYM', 'SHT_MIPS_MSYM', 'SHT_MIPS_OPTIONS', - 'SHT_MIPS_OPTSYM', 'SHT_MIPS_PACKAGE', 'SHT_MIPS_PACKSYM', - 'SHT_MIPS_PDESC', 'SHT_MIPS_PDR_EXCEPTION', 'SHT_MIPS_PIXIE', - 'SHT_MIPS_REGINFO', 'SHT_MIPS_RELD', 'SHT_MIPS_RFDESC', - 'SHT_MIPS_SHDR', 'SHT_MIPS_SYMBOL_LIB', 'SHT_MIPS_TRANSLATE', - 'SHT_MIPS_UCODE', 'SHT_MIPS_WHIRL', 'SHT_MIPS_XHASH', - 'SHT_MIPS_XLATE', 'SHT_MIPS_XLATE_DEBUG', 'SHT_MIPS_XLATE_OLD', - 'SHT_NOBITS', 'SHT_NOTE', 'SHT_NULL', 'SHT_NUM', 'SHT_PARISC_DOC', - 'SHT_PARISC_EXT', 'SHT_PARISC_UNWIND', 'SHT_PREINIT_ARRAY', - 'SHT_PROGBITS', 'SHT_REL', 'SHT_RELA', 'SHT_RELR', - 'SHT_RISCV_ATTRIBUTES', 'SHT_SHLIB', 'SHT_STRTAB', - 'SHT_SUNW_COMDAT', 'SHT_SUNW_move', 'SHT_SUNW_syminfo', - 'SHT_SYMTAB', 'SHT_SYMTAB_SHNDX', 'SHT_X86_64_UNWIND', - 'STB_GLOBAL', 'STB_GNU_UNIQUE', 'STB_HIOS', 'STB_HIPROC', - 'STB_LOCAL', 'STB_LOOS', 'STB_LOPROC', 'STB_MIPS_SPLIT_COMMON', - 'STB_NUM', 'STB_WEAK', 'STDERR_FILENO', 'STDIN_FILENO', - 'STDOUT_FILENO', 'STN_UNDEF', 'STO_AARCH64_VARIANT_PCS', - 'STO_ALPHA_NOPV', 'STO_ALPHA_STD_GPLOAD', 'STO_MIPS_DEFAULT', - 'STO_MIPS_HIDDEN', 'STO_MIPS_INTERNAL', 'STO_MIPS_PLT', - 'STO_MIPS_PROTECTED', 'STO_MIPS_SC_ALIGN_UNUSED', - 'STO_PPC64_LOCAL_BIT', 'STO_PPC64_LOCAL_MASK', - 'STO_RISCV_VARIANT_CC', 'STT_ARM_16BIT', 'STT_ARM_TFUNC', - 'STT_COMMON', 'STT_FILE', 'STT_FUNC', 'STT_GNU_IFUNC', 'STT_HIOS', - 'STT_HIPROC', 'STT_HP_OPAQUE', 'STT_HP_STUB', 'STT_LOOS', - 'STT_LOPROC', 'STT_NOTYPE', 'STT_NUM', 'STT_OBJECT', - 'STT_PARISC_MILLICODE', 'STT_SECTION', 'STT_SPARC_REGISTER', - 'STT_TLS', 'STV_DEFAULT', 'STV_HIDDEN', 'STV_INTERNAL', - 'STV_PROTECTED', 'SYMINFO_BT_LOWRESERVE', 'SYMINFO_BT_PARENT', - 'SYMINFO_BT_SELF', 'SYMINFO_CURRENT', 'SYMINFO_FLG_COPY', - 'SYMINFO_FLG_DIRECT', 'SYMINFO_FLG_LAZYLOAD', - 'SYMINFO_FLG_PASSTHRU', 'SYMINFO_NONE', 'SYMINFO_NUM', - 'VER_DEF_CURRENT', 'VER_DEF_NONE', 'VER_DEF_NUM', 'VER_FLG_BASE', - 'VER_FLG_WEAK', 'VER_NDX_ELIMINATE', 'VER_NDX_GLOBAL', - 'VER_NDX_LOCAL', 'VER_NDX_LORESERVE', 'VER_NEED_CURRENT', - 'VER_NEED_NONE', 'VER_NEED_NUM', 'Val_GNU_MIPS_ABI_FP_64', - 'Val_GNU_MIPS_ABI_FP_64A', 'Val_GNU_MIPS_ABI_FP_ANY', - 'Val_GNU_MIPS_ABI_FP_DOUBLE', 'Val_GNU_MIPS_ABI_FP_MAX', - 'Val_GNU_MIPS_ABI_FP_OLD_64', 'Val_GNU_MIPS_ABI_FP_SINGLE', - 'Val_GNU_MIPS_ABI_FP_SOFT', 'Val_GNU_MIPS_ABI_FP_XX', 'W_OK', - 'X_OK', '_ELF_H', '_POSIX2_C_BIND', '_POSIX2_C_DEV', - '_POSIX2_C_VERSION', '_POSIX2_LOCALEDEF', '_POSIX2_SW_DEV', - '_POSIX2_VERSION', '_POSIX_VERSION', '_STRING_H', '_SYSCALL_H', - '_SYS_MMAN_H', '_UNISTD_H', '_XOPEN_ENH_I18N', '_XOPEN_LEGACY', - '_XOPEN_UNIX', '_XOPEN_VERSION', '_XOPEN_XCU_VERSION', - '_XOPEN_XPG2', '_XOPEN_XPG3', '_XOPEN_XPG4', - '__ASM_GENERIC_MMAN_COMMON_H', - '__GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION', - '__POSIX2_THIS_VERSION', '__environ', '__getpgid', '__gid_t', - '__gid_t_defined', '__intptr_t_defined', '__memcmpeq', - '__mempcpy', '__mode_t_defined', '__need_NULL', '__need_size_t', - '__off_t', '__off_t_defined', '__pid_t', '__pid_t_defined', - '__socklen_t_defined', '__ssize_t_defined', '__stpcpy', - '__stpncpy', '__strtok_r', '__uid_t', '__uid_t_defined', - '__useconds_t', '__useconds_t_defined', '_exit', 'access', 'acct', - 'alarm', 'brk', 'c__Ea_Val_GNU_MIPS_ABI_FP_ANY', 'chdir', 'chown', - 'chroot', 'close', 'closefrom', 'confstr', 'crypt', 'daemon', - 'dup', 'dup2', 'endusershell', 'execl', 'execle', 'execlp', - 'execv', 'execve', 'execvp', 'explicit_bzero', 'faccessat', - 'fchdir', 'fchown', 'fchownat', 'fdatasync', 'fexecve', 'fork', - 'fpathconf', 'fsync', 'ftruncate', 'getcwd', 'getdomainname', - 'getdtablesize', 'getegid', 'getentropy', 'geteuid', 'getgid', - 'getgroups', 'gethostid', 'gethostname', 'getlogin', 'getlogin_r', - 'getpagesize', 'getpass', 'getpgid', 'getpgrp', 'getpid', - 'getppid', 'getsid', 'getuid', 'getusershell', 'getwd', 'gid_t', - 'intptr_t', 'isatty', 'lchown', 'link', 'linkat', 'locale_t', - 'lockf', 'lseek', 'madvise', 'memccpy', 'memchr', 'memcmp', - 'memcpy', 'memmem', 'memmove', 'mempcpy', 'memset', 'mincore', - 'mlock', 'mlockall', 'mmap', 'mode_t', 'mprotect', 'msync', - 'munlock', 'munlockall', 'munmap', 'nice', 'off_t', 'pathconf', - 'pause', 'pid_t', 'pipe', 'posix_madvise', 'pread', 'profil', - 'pwrite', 'read', 'readlink', 'readlinkat', 'revoke', 'rmdir', - 'sbrk', 'setdomainname', 'setegid', 'seteuid', 'setgid', - 'sethostid', 'sethostname', 'setlogin', 'setpgid', 'setpgrp', - 'setregid', 'setreuid', 'setsid', 'setuid', 'setusershell', - 'shm_open', 'shm_unlink', 'size_t', 'sleep', 'socklen_t', - 'ssize_t', 'stpcpy', 'stpncpy', 'strcasestr', 'strcat', 'strchr', - 'strchrnul', 'strcmp', 'strcoll', 'strcoll_l', 'strcpy', - 'strcspn', 'strdup', 'strerror', 'strerror_l', 'strerror_r', - 'strlcat', 'strlcpy', 'strlen', 'strncat', 'strncmp', 'strncpy', - 'strndup', 'strnlen', 'strpbrk', 'strrchr', 'strsep', 'strsignal', - 'strspn', 'strstr', 'strtok', 'strtok_r', 'struct___locale_data', - 'struct___locale_struct', 'struct_c__SA_Elf32_Chdr', - 'struct_c__SA_Elf32_Dyn', 'struct_c__SA_Elf32_Ehdr', - 'struct_c__SA_Elf32_Lib', 'struct_c__SA_Elf32_Move', - 'struct_c__SA_Elf32_Nhdr', 'struct_c__SA_Elf32_Phdr', - 'struct_c__SA_Elf32_RegInfo', 'struct_c__SA_Elf32_Rel', - 'struct_c__SA_Elf32_Rela', 'struct_c__SA_Elf32_Shdr', - 'struct_c__SA_Elf32_Sym', 'struct_c__SA_Elf32_Syminfo', - 'struct_c__SA_Elf32_Verdaux', 'struct_c__SA_Elf32_Verdef', - 'struct_c__SA_Elf32_Vernaux', 'struct_c__SA_Elf32_Verneed', - 'struct_c__SA_Elf32_auxv_t', 'struct_c__SA_Elf64_Chdr', - 'struct_c__SA_Elf64_Dyn', 'struct_c__SA_Elf64_Ehdr', - 'struct_c__SA_Elf64_Lib', 'struct_c__SA_Elf64_Move', - 'struct_c__SA_Elf64_Nhdr', 'struct_c__SA_Elf64_Phdr', - 'struct_c__SA_Elf64_Rel', 'struct_c__SA_Elf64_Rela', - 'struct_c__SA_Elf64_Shdr', 'struct_c__SA_Elf64_Sym', - 'struct_c__SA_Elf64_Syminfo', 'struct_c__SA_Elf64_Verdaux', - 'struct_c__SA_Elf64_Verdef', 'struct_c__SA_Elf64_Vernaux', - 'struct_c__SA_Elf64_Verneed', 'struct_c__SA_Elf64_auxv_t', - 'struct_c__SA_Elf_MIPS_ABIFlags_v0', 'struct_c__SA_Elf_Options', - 'struct_c__SA_Elf_Options_Hw', - 'struct_c__UA_Elf32_gptab_gt_entry', - 'struct_c__UA_Elf32_gptab_gt_header', 'strxfrm', 'strxfrm_l', - 'symlink', 'symlinkat', 'sync', 'syscall', 'sysconf', 'tcgetpgrp', - 'tcsetpgrp', 'truncate', 'ttyname', 'ttyname_r', 'ttyslot', - 'ualarm', 'uid_t', 'union_c__SA_Elf32_Dyn_d_un', - 'union_c__SA_Elf32_auxv_t_a_un', 'union_c__SA_Elf64_Dyn_d_un', - 'union_c__SA_Elf64_auxv_t_a_un', 'union_c__UA_Elf32_gptab', - 'unlink', 'unlinkat', 'useconds_t', 'usleep', 'vfork', 'vhangup', - 'write'] +# extern __pid_t getpid(void) __attribute__((nothrow)) +try: (getpid:=dll.getpid).restype, getpid.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern __pid_t getppid(void) __attribute__((nothrow)) +try: (getppid:=dll.getppid).restype, getppid.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern __pid_t getpgrp(void) __attribute__((nothrow)) +try: (getpgrp:=dll.getpgrp).restype, getpgrp.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern __pid_t __getpgid(__pid_t __pid) __attribute__((nothrow)) +try: (__getpgid:=dll.__getpgid).restype, __getpgid.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern __pid_t getpgid(__pid_t __pid) __attribute__((nothrow)) +try: (getpgid:=dll.getpgid).restype, getpgid.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern int setpgid(__pid_t __pid, __pid_t __pgid) __attribute__((nothrow)) +try: (setpgid:=dll.setpgid).restype, setpgid.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_int32] +except AttributeError: pass + +# extern int setpgrp(void) __attribute__((nothrow)) +try: (setpgrp:=dll.setpgrp).restype, setpgrp.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern __pid_t setsid(void) __attribute__((nothrow)) +try: (setsid:=dll.setsid).restype, setsid.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern __pid_t getsid(__pid_t __pid) __attribute__((nothrow)) +try: (getsid:=dll.getsid).restype, getsid.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern __uid_t getuid(void) __attribute__((nothrow)) +try: (getuid:=dll.getuid).restype, getuid.argtypes = ctypes.c_uint32, [] +except AttributeError: pass + +# extern __uid_t geteuid(void) __attribute__((nothrow)) +try: (geteuid:=dll.geteuid).restype, geteuid.argtypes = ctypes.c_uint32, [] +except AttributeError: pass + +# extern __gid_t getgid(void) __attribute__((nothrow)) +try: (getgid:=dll.getgid).restype, getgid.argtypes = ctypes.c_uint32, [] +except AttributeError: pass + +# extern __gid_t getegid(void) __attribute__((nothrow)) +try: (getegid:=dll.getegid).restype, getegid.argtypes = ctypes.c_uint32, [] +except AttributeError: pass + +# extern int getgroups(int __size, __gid_t __list[]) __attribute__((nothrow)) +try: (getgroups:=dll.getgroups).restype, getgroups.argtypes = ctypes.c_int32, [ctypes.c_int32, (ctypes.c_uint32 * 0)] +except AttributeError: pass + +# extern int setuid(__uid_t __uid) __attribute__((nothrow)) +try: (setuid:=dll.setuid).restype, setuid.argtypes = ctypes.c_int32, [ctypes.c_uint32] +except AttributeError: pass + +# extern int setreuid(__uid_t __ruid, __uid_t __euid) __attribute__((nothrow)) +try: (setreuid:=dll.setreuid).restype, setreuid.argtypes = ctypes.c_int32, [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: pass + +# extern int seteuid(__uid_t __uid) __attribute__((nothrow)) +try: (seteuid:=dll.seteuid).restype, seteuid.argtypes = ctypes.c_int32, [ctypes.c_uint32] +except AttributeError: pass + +# extern int setgid(__gid_t __gid) __attribute__((nothrow)) +try: (setgid:=dll.setgid).restype, setgid.argtypes = ctypes.c_int32, [ctypes.c_uint32] +except AttributeError: pass + +# extern int setregid(__gid_t __rgid, __gid_t __egid) __attribute__((nothrow)) +try: (setregid:=dll.setregid).restype, setregid.argtypes = ctypes.c_int32, [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: pass + +# extern int setegid(__gid_t __gid) __attribute__((nothrow)) +try: (setegid:=dll.setegid).restype, setegid.argtypes = ctypes.c_int32, [ctypes.c_uint32] +except AttributeError: pass + +# extern __pid_t fork(void) __attribute__((nothrow)) +try: (fork:=dll.fork).restype, fork.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern int vfork(void) __attribute__((nothrow)) +try: (vfork:=dll.vfork).restype, vfork.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern char *ttyname(int __fd) __attribute__((nothrow)) +try: (ttyname:=dll.ttyname).restype, ttyname.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.c_int32] +except AttributeError: pass + +# extern int ttyname_r(int __fd, char *__buf, size_t __buflen) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (ttyname_r:=dll.ttyname_r).restype, ttyname_r.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int isatty(int __fd) __attribute__((nothrow)) +try: (isatty:=dll.isatty).restype, isatty.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern int ttyslot(void) __attribute__((nothrow)) +try: (ttyslot:=dll.ttyslot).restype, ttyslot.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern int link(const char *__from, const char *__to) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (link:=dll.link).restype, link.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int linkat(int __fromfd, const char *__from, int __tofd, const char *__to, int __flags) __attribute__((nothrow)) __attribute__((nonnull(2, 4))) +try: (linkat:=dll.linkat).restype, linkat.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern int symlink(const char *__from, const char *__to) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (symlink:=dll.symlink).restype, symlink.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern ssize_t readlink(const char *restrict __path, char *restrict __buf, size_t __len) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (readlink:=dll.readlink).restype, readlink.argtypes = ssize_t, [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int symlinkat(const char *__from, int __tofd, const char *__to) __attribute__((nothrow)) __attribute__((nonnull(1, 3))) +try: (symlinkat:=dll.symlinkat).restype, symlinkat.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.c_int32, ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern ssize_t readlinkat(int __fd, const char *restrict __path, char *restrict __buf, size_t __len) __attribute__((nothrow)) __attribute__((nonnull(2, 3))) +try: (readlinkat:=dll.readlinkat).restype, readlinkat.argtypes = ssize_t, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int unlink(const char *__name) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (unlink:=dll.unlink).restype, unlink.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int unlinkat(int __fd, const char *__name, int __flag) __attribute__((nothrow)) __attribute__((nonnull(2))) +try: (unlinkat:=dll.unlinkat).restype, unlinkat.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.POINTER(ctypes.c_char), ctypes.c_int32] +except AttributeError: pass + +# extern int rmdir(const char *__path) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (rmdir:=dll.rmdir).restype, rmdir.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern __pid_t tcgetpgrp(int __fd) __attribute__((nothrow)) +try: (tcgetpgrp:=dll.tcgetpgrp).restype, tcgetpgrp.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern int tcsetpgrp(int __fd, __pid_t __pgrp_id) __attribute__((nothrow)) +try: (tcsetpgrp:=dll.tcsetpgrp).restype, tcsetpgrp.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_int32] +except AttributeError: pass + +# extern char *getlogin(void) +try: (getlogin:=dll.getlogin).restype, getlogin.argtypes = ctypes.POINTER(ctypes.c_char), [] +except AttributeError: pass + +# extern int getlogin_r(char *__name, size_t __name_len) __attribute__((nonnull(1))) +try: (getlogin_r:=dll.getlogin_r).restype, getlogin_r.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int setlogin(const char *__name) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (setlogin:=dll.setlogin).restype, setlogin.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int gethostname(char *__name, size_t __len) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (gethostname:=dll.gethostname).restype, gethostname.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int sethostname(const char *__name, size_t __len) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (sethostname:=dll.sethostname).restype, sethostname.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int sethostid(long __id) __attribute__((nothrow)) +try: (sethostid:=dll.sethostid).restype, sethostid.argtypes = ctypes.c_int32, [ctypes.c_int64] +except AttributeError: pass + +# extern int getdomainname(char *__name, size_t __len) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (getdomainname:=dll.getdomainname).restype, getdomainname.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int setdomainname(const char *__name, size_t __len) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (setdomainname:=dll.setdomainname).restype, setdomainname.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: pass + +# extern int vhangup(void) __attribute__((nothrow)) +try: (vhangup:=dll.vhangup).restype, vhangup.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern int revoke(const char *__file) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (revoke:=dll.revoke).restype, revoke.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int profil(unsigned short *__sample_buffer, size_t __size, size_t __offset, unsigned int __scale) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (profil:=dll.profil).restype, profil.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_uint16), size_t, size_t, ctypes.c_uint32] +except AttributeError: pass + +# extern int acct(const char *__name) __attribute__((nothrow)) +try: (acct:=dll.acct).restype, acct.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *getusershell(void) __attribute__((nothrow)) +try: (getusershell:=dll.getusershell).restype, getusershell.argtypes = ctypes.POINTER(ctypes.c_char), [] +except AttributeError: pass + +# extern void endusershell(void) __attribute__((nothrow)) +try: (endusershell:=dll.endusershell).restype, endusershell.argtypes = None, [] +except AttributeError: pass + +# extern void setusershell(void) __attribute__((nothrow)) +try: (setusershell:=dll.setusershell).restype, setusershell.argtypes = None, [] +except AttributeError: pass + +# extern int daemon(int __nochdir, int __noclose) __attribute__((nothrow)) +try: (daemon:=dll.daemon).restype, daemon.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_int32] +except AttributeError: pass + +# extern int chroot(const char *__path) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (chroot:=dll.chroot).restype, chroot.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern char *getpass(const char *__prompt) __attribute__((nonnull(1))) +try: (getpass:=dll.getpass).restype, getpass.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# extern int fsync(int __fd) +try: (fsync:=dll.fsync).restype, fsync.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern long gethostid(void) +try: (gethostid:=dll.gethostid).restype, gethostid.argtypes = ctypes.c_int64, [] +except AttributeError: pass + +# extern void sync(void) __attribute__((nothrow)) +try: (sync:=dll.sync).restype, sync.argtypes = None, [] +except AttributeError: pass + +# extern int getpagesize(void) __attribute__((nothrow)) __attribute__((const)) +try: (getpagesize:=dll.getpagesize).restype, getpagesize.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern int getdtablesize(void) __attribute__((nothrow)) +try: (getdtablesize:=dll.getdtablesize).restype, getdtablesize.argtypes = ctypes.c_int32, [] +except AttributeError: pass + +# extern int truncate(const char *__file, __off_t __length) __attribute__((nothrow)) __attribute__((nonnull(1))) +try: (truncate:=dll.truncate).restype, truncate.argtypes = ctypes.c_int32, [ctypes.POINTER(ctypes.c_char), ctypes.c_int64] +except AttributeError: pass + +# extern int ftruncate(int __fd, __off_t __length) __attribute__((nothrow)) +try: (ftruncate:=dll.ftruncate).restype, ftruncate.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_int64] +except AttributeError: pass + +# extern int brk(void *__addr) __attribute__((nothrow)) +try: (brk:=dll.brk).restype, brk.argtypes = ctypes.c_int32, [ctypes.c_void_p] +except AttributeError: pass + +# extern void *sbrk(intptr_t __delta) __attribute__((nothrow)) +try: (sbrk:=dll.sbrk).restype, sbrk.argtypes = ctypes.c_void_p, [intptr_t] +except AttributeError: pass + +# extern long syscall(long __sysno, ...) __attribute__((nothrow)) +try: (syscall:=dll.syscall).restype, syscall.argtypes = ctypes.c_int64, [ctypes.c_int64] +except AttributeError: pass + +# extern int lockf(int __fd, int __cmd, __off_t __len) +try: (lockf:=dll.lockf).restype, lockf.argtypes = ctypes.c_int32, [ctypes.c_int32, ctypes.c_int32, ctypes.c_int64] +except AttributeError: pass + +# extern int fdatasync(int __fildes) +try: (fdatasync:=dll.fdatasync).restype, fdatasync.argtypes = ctypes.c_int32, [ctypes.c_int32] +except AttributeError: pass + +# extern char *crypt(const char *__key, const char *__salt) __attribute__((nothrow)) __attribute__((nonnull(1, 2))) +try: (crypt:=dll.crypt).restype, crypt.argtypes = ctypes.POINTER(ctypes.c_char), [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char)] +except AttributeError: pass + +# int getentropy(void *__buffer, size_t __length) +try: (getentropy:=dll.getentropy).restype, getentropy.argtypes = ctypes.c_int32, [ctypes.c_void_p, size_t] +except AttributeError: pass + +_SYS_MMAN_H = 1 +_SYSCALL_H = 1 +_STRING_H = 1 +_ELF_H = 1 +EI_NIDENT = (16) +EI_MAG0 = 0 +ELFMAG0 = 0x7f +EI_MAG1 = 1 +ELFMAG1 = 'E' +EI_MAG2 = 2 +ELFMAG2 = 'L' +EI_MAG3 = 3 +ELFMAG3 = 'F' +ELFMAG = "\177ELF" +SELFMAG = 4 +EI_CLASS = 4 +ELFCLASSNONE = 0 +ELFCLASS32 = 1 +ELFCLASS64 = 2 +ELFCLASSNUM = 3 +EI_DATA = 5 +ELFDATANONE = 0 +ELFDATA2LSB = 1 +ELFDATA2MSB = 2 +ELFDATANUM = 3 +EI_VERSION = 6 +EI_OSABI = 7 +ELFOSABI_NONE = 0 +ELFOSABI_SYSV = 0 +ELFOSABI_HPUX = 1 +ELFOSABI_NETBSD = 2 +ELFOSABI_GNU = 3 +ELFOSABI_LINUX = ELFOSABI_GNU +ELFOSABI_SOLARIS = 6 +ELFOSABI_AIX = 7 +ELFOSABI_IRIX = 8 +ELFOSABI_FREEBSD = 9 +ELFOSABI_TRU64 = 10 +ELFOSABI_MODESTO = 11 +ELFOSABI_OPENBSD = 12 +ELFOSABI_ARM_AEABI = 64 +ELFOSABI_ARM = 97 +ELFOSABI_STANDALONE = 255 +EI_ABIVERSION = 8 +EI_PAD = 9 +ET_NONE = 0 +ET_REL = 1 +ET_EXEC = 2 +ET_DYN = 3 +ET_CORE = 4 +ET_NUM = 5 +ET_LOOS = 0xfe00 +ET_HIOS = 0xfeff +ET_LOPROC = 0xff00 +ET_HIPROC = 0xffff +EM_NONE = 0 +EM_M32 = 1 +EM_SPARC = 2 +EM_386 = 3 +EM_68K = 4 +EM_88K = 5 +EM_IAMCU = 6 +EM_860 = 7 +EM_MIPS = 8 +EM_S370 = 9 +EM_MIPS_RS3_LE = 10 +EM_PARISC = 15 +EM_VPP500 = 17 +EM_SPARC32PLUS = 18 +EM_960 = 19 +EM_PPC = 20 +EM_PPC64 = 21 +EM_S390 = 22 +EM_SPU = 23 +EM_V800 = 36 +EM_FR20 = 37 +EM_RH32 = 38 +EM_RCE = 39 +EM_ARM = 40 +EM_FAKE_ALPHA = 41 +EM_SH = 42 +EM_SPARCV9 = 43 +EM_TRICORE = 44 +EM_ARC = 45 +EM_H8_300 = 46 +EM_H8_300H = 47 +EM_H8S = 48 +EM_H8_500 = 49 +EM_IA_64 = 50 +EM_MIPS_X = 51 +EM_COLDFIRE = 52 +EM_68HC12 = 53 +EM_MMA = 54 +EM_PCP = 55 +EM_NCPU = 56 +EM_NDR1 = 57 +EM_STARCORE = 58 +EM_ME16 = 59 +EM_ST100 = 60 +EM_TINYJ = 61 +EM_X86_64 = 62 +EM_PDSP = 63 +EM_PDP10 = 64 +EM_PDP11 = 65 +EM_FX66 = 66 +EM_ST9PLUS = 67 +EM_ST7 = 68 +EM_68HC16 = 69 +EM_68HC11 = 70 +EM_68HC08 = 71 +EM_68HC05 = 72 +EM_SVX = 73 +EM_ST19 = 74 +EM_VAX = 75 +EM_CRIS = 76 +EM_JAVELIN = 77 +EM_FIREPATH = 78 +EM_ZSP = 79 +EM_MMIX = 80 +EM_HUANY = 81 +EM_PRISM = 82 +EM_AVR = 83 +EM_FR30 = 84 +EM_D10V = 85 +EM_D30V = 86 +EM_V850 = 87 +EM_M32R = 88 +EM_MN10300 = 89 +EM_MN10200 = 90 +EM_PJ = 91 +EM_OPENRISC = 92 +EM_ARC_COMPACT = 93 +EM_XTENSA = 94 +EM_VIDEOCORE = 95 +EM_TMM_GPP = 96 +EM_NS32K = 97 +EM_TPC = 98 +EM_SNP1K = 99 +EM_ST200 = 100 +EM_IP2K = 101 +EM_MAX = 102 +EM_CR = 103 +EM_F2MC16 = 104 +EM_MSP430 = 105 +EM_BLACKFIN = 106 +EM_SE_C33 = 107 +EM_SEP = 108 +EM_ARCA = 109 +EM_UNICORE = 110 +EM_EXCESS = 111 +EM_DXP = 112 +EM_ALTERA_NIOS2 = 113 +EM_CRX = 114 +EM_XGATE = 115 +EM_C166 = 116 +EM_M16C = 117 +EM_DSPIC30F = 118 +EM_CE = 119 +EM_M32C = 120 +EM_TSK3000 = 131 +EM_RS08 = 132 +EM_SHARC = 133 +EM_ECOG2 = 134 +EM_SCORE7 = 135 +EM_DSP24 = 136 +EM_VIDEOCORE3 = 137 +EM_LATTICEMICO32 = 138 +EM_SE_C17 = 139 +EM_TI_C6000 = 140 +EM_TI_C2000 = 141 +EM_TI_C5500 = 142 +EM_TI_ARP32 = 143 +EM_TI_PRU = 144 +EM_MMDSP_PLUS = 160 +EM_CYPRESS_M8C = 161 +EM_R32C = 162 +EM_TRIMEDIA = 163 +EM_QDSP6 = 164 +EM_8051 = 165 +EM_STXP7X = 166 +EM_NDS32 = 167 +EM_ECOG1X = 168 +EM_MAXQ30 = 169 +EM_XIMO16 = 170 +EM_MANIK = 171 +EM_CRAYNV2 = 172 +EM_RX = 173 +EM_METAG = 174 +EM_MCST_ELBRUS = 175 +EM_ECOG16 = 176 +EM_CR16 = 177 +EM_ETPU = 178 +EM_SLE9X = 179 +EM_L10M = 180 +EM_K10M = 181 +EM_AARCH64 = 183 +EM_AVR32 = 185 +EM_STM8 = 186 +EM_TILE64 = 187 +EM_TILEPRO = 188 +EM_MICROBLAZE = 189 +EM_CUDA = 190 +EM_TILEGX = 191 +EM_CLOUDSHIELD = 192 +EM_COREA_1ST = 193 +EM_COREA_2ND = 194 +EM_ARCV2 = 195 +EM_OPEN8 = 196 +EM_RL78 = 197 +EM_VIDEOCORE5 = 198 +EM_78KOR = 199 +EM_56800EX = 200 +EM_BA1 = 201 +EM_BA2 = 202 +EM_XCORE = 203 +EM_MCHP_PIC = 204 +EM_INTELGT = 205 +EM_KM32 = 210 +EM_KMX32 = 211 +EM_EMX16 = 212 +EM_EMX8 = 213 +EM_KVARC = 214 +EM_CDP = 215 +EM_COGE = 216 +EM_COOL = 217 +EM_NORC = 218 +EM_CSR_KALIMBA = 219 +EM_Z80 = 220 +EM_VISIUM = 221 +EM_FT32 = 222 +EM_MOXIE = 223 +EM_AMDGPU = 224 +EM_RISCV = 243 +EM_BPF = 247 +EM_CSKY = 252 +EM_LOONGARCH = 258 +EM_NUM = 259 +EM_ARC_A5 = EM_ARC_COMPACT +EM_ALPHA = 0x9026 +EV_NONE = 0 +EV_CURRENT = 1 +EV_NUM = 2 +SHN_UNDEF = 0 +SHN_LORESERVE = 0xff00 +SHN_LOPROC = 0xff00 +SHN_BEFORE = 0xff00 +SHN_AFTER = 0xff01 +SHN_HIPROC = 0xff1f +SHN_LOOS = 0xff20 +SHN_HIOS = 0xff3f +SHN_ABS = 0xfff1 +SHN_COMMON = 0xfff2 +SHN_XINDEX = 0xffff +SHN_HIRESERVE = 0xffff +SHT_NULL = 0 +SHT_PROGBITS = 1 +SHT_SYMTAB = 2 +SHT_STRTAB = 3 +SHT_RELA = 4 +SHT_HASH = 5 +SHT_DYNAMIC = 6 +SHT_NOTE = 7 +SHT_NOBITS = 8 +SHT_REL = 9 +SHT_SHLIB = 10 +SHT_DYNSYM = 11 +SHT_INIT_ARRAY = 14 +SHT_FINI_ARRAY = 15 +SHT_PREINIT_ARRAY = 16 +SHT_GROUP = 17 +SHT_SYMTAB_SHNDX = 18 +SHT_RELR = 19 +SHT_NUM = 20 +SHT_LOOS = 0x60000000 +SHT_GNU_ATTRIBUTES = 0x6ffffff5 +SHT_GNU_HASH = 0x6ffffff6 +SHT_GNU_LIBLIST = 0x6ffffff7 +SHT_CHECKSUM = 0x6ffffff8 +SHT_LOSUNW = 0x6ffffffa +SHT_SUNW_move = 0x6ffffffa +SHT_SUNW_COMDAT = 0x6ffffffb +SHT_SUNW_syminfo = 0x6ffffffc +SHT_GNU_verdef = 0x6ffffffd +SHT_GNU_verneed = 0x6ffffffe +SHT_GNU_versym = 0x6fffffff +SHT_HISUNW = 0x6fffffff +SHT_HIOS = 0x6fffffff +SHT_LOPROC = 0x70000000 +SHT_HIPROC = 0x7fffffff +SHT_LOUSER = 0x80000000 +SHT_HIUSER = 0x8fffffff +SHF_WRITE = (1 << 0) +SHF_ALLOC = (1 << 1) +SHF_EXECINSTR = (1 << 2) +SHF_MERGE = (1 << 4) +SHF_STRINGS = (1 << 5) +SHF_INFO_LINK = (1 << 6) +SHF_LINK_ORDER = (1 << 7) +SHF_OS_NONCONFORMING = (1 << 8) +SHF_GROUP = (1 << 9) +SHF_TLS = (1 << 10) +SHF_COMPRESSED = (1 << 11) +SHF_MASKOS = 0x0ff00000 +SHF_MASKPROC = 0xf0000000 +SHF_GNU_RETAIN = (1 << 21) +SHF_ORDERED = (1 << 30) +SHF_EXCLUDE = (1 << 31) +ELFCOMPRESS_ZLIB = 1 +ELFCOMPRESS_ZSTD = 2 +ELFCOMPRESS_LOOS = 0x60000000 +ELFCOMPRESS_HIOS = 0x6fffffff +ELFCOMPRESS_LOPROC = 0x70000000 +ELFCOMPRESS_HIPROC = 0x7fffffff +GRP_COMDAT = 0x1 +SYMINFO_BT_SELF = 0xffff +SYMINFO_BT_PARENT = 0xfffe +SYMINFO_BT_LOWRESERVE = 0xff00 +SYMINFO_FLG_DIRECT = 0x0001 +SYMINFO_FLG_PASSTHRU = 0x0002 +SYMINFO_FLG_COPY = 0x0004 +SYMINFO_FLG_LAZYLOAD = 0x0008 +SYMINFO_NONE = 0 +SYMINFO_CURRENT = 1 +SYMINFO_NUM = 2 +ELF32_ST_BIND = lambda val: (( (val)) >> 4) +ELF32_ST_TYPE = lambda val: ((val) & 0xf) +ELF32_ST_INFO = lambda bind,type: (((bind) << 4) + ((type) & 0xf)) +ELF64_ST_BIND = lambda val: ELF32_ST_BIND (val) +ELF64_ST_TYPE = lambda val: ELF32_ST_TYPE (val) +ELF64_ST_INFO = lambda bind,type: ELF32_ST_INFO ((bind), (type)) +STB_LOCAL = 0 +STB_GLOBAL = 1 +STB_WEAK = 2 +STB_NUM = 3 +STB_LOOS = 10 +STB_GNU_UNIQUE = 10 +STB_HIOS = 12 +STB_LOPROC = 13 +STB_HIPROC = 15 +STT_NOTYPE = 0 +STT_OBJECT = 1 +STT_FUNC = 2 +STT_SECTION = 3 +STT_FILE = 4 +STT_COMMON = 5 +STT_TLS = 6 +STT_NUM = 7 +STT_LOOS = 10 +STT_GNU_IFUNC = 10 +STT_HIOS = 12 +STT_LOPROC = 13 +STT_HIPROC = 15 +STN_UNDEF = 0 +ELF32_ST_VISIBILITY = lambda o: ((o) & 0x03) +ELF64_ST_VISIBILITY = lambda o: ELF32_ST_VISIBILITY (o) +STV_DEFAULT = 0 +STV_INTERNAL = 1 +STV_HIDDEN = 2 +STV_PROTECTED = 3 +ELF32_R_SYM = lambda val: ((val) >> 8) +ELF32_R_TYPE = lambda val: ((val) & 0xff) +ELF32_R_INFO = lambda sym,type: (((sym) << 8) + ((type) & 0xff)) +ELF64_R_SYM = lambda i: ((i) >> 32) +ELF64_R_TYPE = lambda i: ((i) & 0xffffffff) +ELF64_R_INFO = lambda sym,type: ((((Elf64_Xword) (sym)) << 32) + (type)) +PN_XNUM = 0xffff +PT_NULL = 0 +PT_LOAD = 1 +PT_DYNAMIC = 2 +PT_INTERP = 3 +PT_NOTE = 4 +PT_SHLIB = 5 +PT_PHDR = 6 +PT_TLS = 7 +PT_NUM = 8 +PT_LOOS = 0x60000000 +PT_GNU_EH_FRAME = 0x6474e550 +PT_GNU_STACK = 0x6474e551 +PT_GNU_RELRO = 0x6474e552 +PT_GNU_PROPERTY = 0x6474e553 +PT_GNU_SFRAME = 0x6474e554 +PT_LOSUNW = 0x6ffffffa +PT_SUNWBSS = 0x6ffffffa +PT_SUNWSTACK = 0x6ffffffb +PT_HISUNW = 0x6fffffff +PT_HIOS = 0x6fffffff +PT_LOPROC = 0x70000000 +PT_HIPROC = 0x7fffffff +PF_X = (1 << 0) +PF_W = (1 << 1) +PF_R = (1 << 2) +PF_MASKOS = 0x0ff00000 +PF_MASKPROC = 0xf0000000 +NT_PRSTATUS = 1 +NT_PRFPREG = 2 +NT_FPREGSET = 2 +NT_PRPSINFO = 3 +NT_PRXREG = 4 +NT_TASKSTRUCT = 4 +NT_PLATFORM = 5 +NT_AUXV = 6 +NT_GWINDOWS = 7 +NT_ASRS = 8 +NT_PSTATUS = 10 +NT_PSINFO = 13 +NT_PRCRED = 14 +NT_UTSNAME = 15 +NT_LWPSTATUS = 16 +NT_LWPSINFO = 17 +NT_PRFPXREG = 20 +NT_SIGINFO = 0x53494749 +NT_FILE = 0x46494c45 +NT_PRXFPREG = 0x46e62b7f +NT_PPC_VMX = 0x100 +NT_PPC_SPE = 0x101 +NT_PPC_VSX = 0x102 +NT_PPC_TAR = 0x103 +NT_PPC_PPR = 0x104 +NT_PPC_DSCR = 0x105 +NT_PPC_EBB = 0x106 +NT_PPC_PMU = 0x107 +NT_PPC_TM_CGPR = 0x108 +NT_PPC_TM_CFPR = 0x109 +NT_PPC_TM_CVMX = 0x10a +NT_PPC_TM_CVSX = 0x10b +NT_PPC_TM_SPR = 0x10c +NT_PPC_TM_CTAR = 0x10d +NT_PPC_TM_CPPR = 0x10e +NT_PPC_TM_CDSCR = 0x10f +NT_PPC_PKEY = 0x110 +NT_PPC_DEXCR = 0x111 +NT_PPC_HASHKEYR = 0x112 +NT_386_TLS = 0x200 +NT_386_IOPERM = 0x201 +NT_X86_XSTATE = 0x202 +NT_X86_SHSTK = 0x204 +NT_S390_HIGH_GPRS = 0x300 +NT_S390_TIMER = 0x301 +NT_S390_TODCMP = 0x302 +NT_S390_TODPREG = 0x303 +NT_S390_CTRS = 0x304 +NT_S390_PREFIX = 0x305 +NT_S390_LAST_BREAK = 0x306 +NT_S390_SYSTEM_CALL = 0x307 +NT_S390_TDB = 0x308 +NT_S390_VXRS_LOW = 0x309 +NT_S390_VXRS_HIGH = 0x30a +NT_S390_GS_CB = 0x30b +NT_S390_GS_BC = 0x30c +NT_S390_RI_CB = 0x30d +NT_S390_PV_CPU_DATA = 0x30e +NT_ARM_VFP = 0x400 +NT_ARM_TLS = 0x401 +NT_ARM_HW_BREAK = 0x402 +NT_ARM_HW_WATCH = 0x403 +NT_ARM_SYSTEM_CALL = 0x404 +NT_ARM_SVE = 0x405 +NT_ARM_PAC_MASK = 0x406 +NT_ARM_PACA_KEYS = 0x407 +NT_ARM_PACG_KEYS = 0x408 +NT_ARM_TAGGED_ADDR_CTRL = 0x409 +NT_ARM_PAC_ENABLED_KEYS = 0x40a +NT_VMCOREDD = 0x700 +NT_MIPS_DSP = 0x800 +NT_MIPS_FP_MODE = 0x801 +NT_MIPS_MSA = 0x802 +NT_RISCV_CSR = 0x900 +NT_RISCV_VECTOR = 0x901 +NT_LOONGARCH_CPUCFG = 0xa00 +NT_LOONGARCH_CSR = 0xa01 +NT_LOONGARCH_LSX = 0xa02 +NT_LOONGARCH_LASX = 0xa03 +NT_LOONGARCH_LBT = 0xa04 +NT_LOONGARCH_HW_BREAK = 0xa05 +NT_LOONGARCH_HW_WATCH = 0xa06 +NT_VERSION = 1 +DT_NULL = 0 +DT_NEEDED = 1 +DT_PLTRELSZ = 2 +DT_PLTGOT = 3 +DT_HASH = 4 +DT_STRTAB = 5 +DT_SYMTAB = 6 +DT_RELA = 7 +DT_RELASZ = 8 +DT_RELAENT = 9 +DT_STRSZ = 10 +DT_SYMENT = 11 +DT_INIT = 12 +DT_FINI = 13 +DT_SONAME = 14 +DT_RPATH = 15 +DT_SYMBOLIC = 16 +DT_REL = 17 +DT_RELSZ = 18 +DT_RELENT = 19 +DT_PLTREL = 20 +DT_DEBUG = 21 +DT_TEXTREL = 22 +DT_JMPREL = 23 +DT_BIND_NOW = 24 +DT_INIT_ARRAY = 25 +DT_FINI_ARRAY = 26 +DT_INIT_ARRAYSZ = 27 +DT_FINI_ARRAYSZ = 28 +DT_RUNPATH = 29 +DT_FLAGS = 30 +DT_ENCODING = 32 +DT_PREINIT_ARRAY = 32 +DT_PREINIT_ARRAYSZ = 33 +DT_SYMTAB_SHNDX = 34 +DT_RELRSZ = 35 +DT_RELR = 36 +DT_RELRENT = 37 +DT_NUM = 38 +DT_LOOS = 0x6000000d +DT_HIOS = 0x6ffff000 +DT_LOPROC = 0x70000000 +DT_HIPROC = 0x7fffffff +DT_VALRNGLO = 0x6ffffd00 +DT_GNU_PRELINKED = 0x6ffffdf5 +DT_GNU_CONFLICTSZ = 0x6ffffdf6 +DT_GNU_LIBLISTSZ = 0x6ffffdf7 +DT_CHECKSUM = 0x6ffffdf8 +DT_PLTPADSZ = 0x6ffffdf9 +DT_MOVEENT = 0x6ffffdfa +DT_MOVESZ = 0x6ffffdfb +DT_FEATURE_1 = 0x6ffffdfc +DT_POSFLAG_1 = 0x6ffffdfd +DT_SYMINSZ = 0x6ffffdfe +DT_SYMINENT = 0x6ffffdff +DT_VALRNGHI = 0x6ffffdff +DT_VALTAGIDX = lambda tag: (DT_VALRNGHI - (tag)) +DT_VALNUM = 12 +DT_ADDRRNGLO = 0x6ffffe00 +DT_GNU_HASH = 0x6ffffef5 +DT_TLSDESC_PLT = 0x6ffffef6 +DT_TLSDESC_GOT = 0x6ffffef7 +DT_GNU_CONFLICT = 0x6ffffef8 +DT_GNU_LIBLIST = 0x6ffffef9 +DT_CONFIG = 0x6ffffefa +DT_DEPAUDIT = 0x6ffffefb +DT_AUDIT = 0x6ffffefc +DT_PLTPAD = 0x6ffffefd +DT_MOVETAB = 0x6ffffefe +DT_SYMINFO = 0x6ffffeff +DT_ADDRRNGHI = 0x6ffffeff +DT_ADDRTAGIDX = lambda tag: (DT_ADDRRNGHI - (tag)) +DT_ADDRNUM = 11 +DT_VERSYM = 0x6ffffff0 +DT_RELACOUNT = 0x6ffffff9 +DT_RELCOUNT = 0x6ffffffa +DT_FLAGS_1 = 0x6ffffffb +DT_VERDEF = 0x6ffffffc +DT_VERDEFNUM = 0x6ffffffd +DT_VERNEED = 0x6ffffffe +DT_VERNEEDNUM = 0x6fffffff +DT_VERSIONTAGIDX = lambda tag: (DT_VERNEEDNUM - (tag)) +DT_VERSIONTAGNUM = 16 +DT_AUXILIARY = 0x7ffffffd +DT_FILTER = 0x7fffffff +DT_EXTRATAGIDX = lambda tag: ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +DT_EXTRANUM = 3 +DF_ORIGIN = 0x00000001 +DF_SYMBOLIC = 0x00000002 +DF_TEXTREL = 0x00000004 +DF_BIND_NOW = 0x00000008 +DF_STATIC_TLS = 0x00000010 +DF_1_NOW = 0x00000001 +DF_1_GLOBAL = 0x00000002 +DF_1_GROUP = 0x00000004 +DF_1_NODELETE = 0x00000008 +DF_1_LOADFLTR = 0x00000010 +DF_1_INITFIRST = 0x00000020 +DF_1_NOOPEN = 0x00000040 +DF_1_ORIGIN = 0x00000080 +DF_1_DIRECT = 0x00000100 +DF_1_TRANS = 0x00000200 +DF_1_INTERPOSE = 0x00000400 +DF_1_NODEFLIB = 0x00000800 +DF_1_NODUMP = 0x00001000 +DF_1_CONFALT = 0x00002000 +DF_1_ENDFILTEE = 0x00004000 +DF_1_DISPRELDNE = 0x00008000 +DF_1_DISPRELPND = 0x00010000 +DF_1_NODIRECT = 0x00020000 +DF_1_IGNMULDEF = 0x00040000 +DF_1_NOKSYMS = 0x00080000 +DF_1_NOHDR = 0x00100000 +DF_1_EDITED = 0x00200000 +DF_1_NORELOC = 0x00400000 +DF_1_SYMINTPOSE = 0x00800000 +DF_1_GLOBAUDIT = 0x01000000 +DF_1_SINGLETON = 0x02000000 +DF_1_STUB = 0x04000000 +DF_1_PIE = 0x08000000 +DF_1_KMOD = 0x10000000 +DF_1_WEAKFILTER = 0x20000000 +DF_1_NOCOMMON = 0x40000000 +DTF_1_PARINIT = 0x00000001 +DTF_1_CONFEXP = 0x00000002 +DF_P1_LAZYLOAD = 0x00000001 +DF_P1_GROUPPERM = 0x00000002 +VER_DEF_NONE = 0 +VER_DEF_CURRENT = 1 +VER_DEF_NUM = 2 +VER_FLG_BASE = 0x1 +VER_FLG_WEAK = 0x2 +VER_NDX_LOCAL = 0 +VER_NDX_GLOBAL = 1 +VER_NDX_LORESERVE = 0xff00 +VER_NDX_ELIMINATE = 0xff01 +VER_NEED_NONE = 0 +VER_NEED_CURRENT = 1 +VER_NEED_NUM = 2 +AT_NULL = 0 +AT_IGNORE = 1 +AT_EXECFD = 2 +AT_PHDR = 3 +AT_PHENT = 4 +AT_PHNUM = 5 +AT_PAGESZ = 6 +AT_BASE = 7 +AT_FLAGS = 8 +AT_ENTRY = 9 +AT_NOTELF = 10 +AT_UID = 11 +AT_EUID = 12 +AT_GID = 13 +AT_EGID = 14 +AT_CLKTCK = 17 +AT_PLATFORM = 15 +AT_HWCAP = 16 +AT_FPUCW = 18 +AT_DCACHEBSIZE = 19 +AT_ICACHEBSIZE = 20 +AT_UCACHEBSIZE = 21 +AT_IGNOREPPC = 22 +AT_SECURE = 23 +AT_BASE_PLATFORM = 24 +AT_RANDOM = 25 +AT_HWCAP2 = 26 +AT_RSEQ_FEATURE_SIZE = 27 +AT_RSEQ_ALIGN = 28 +AT_HWCAP3 = 29 +AT_HWCAP4 = 30 +AT_EXECFN = 31 +AT_SYSINFO = 32 +AT_SYSINFO_EHDR = 33 +AT_L1I_CACHESHAPE = 34 +AT_L1D_CACHESHAPE = 35 +AT_L2_CACHESHAPE = 36 +AT_L3_CACHESHAPE = 37 +AT_L1I_CACHESIZE = 40 +AT_L1I_CACHEGEOMETRY = 41 +AT_L1D_CACHESIZE = 42 +AT_L1D_CACHEGEOMETRY = 43 +AT_L2_CACHESIZE = 44 +AT_L2_CACHEGEOMETRY = 45 +AT_L3_CACHESIZE = 46 +AT_L3_CACHEGEOMETRY = 47 +AT_MINSIGSTKSZ = 51 +ELF_NOTE_SOLARIS = "SUNW Solaris" +ELF_NOTE_GNU = "GNU" +ELF_NOTE_FDO = "FDO" +ELF_NOTE_PAGESIZE_HINT = 1 +NT_GNU_ABI_TAG = 1 +ELF_NOTE_ABI = NT_GNU_ABI_TAG +ELF_NOTE_OS_LINUX = 0 +ELF_NOTE_OS_GNU = 1 +ELF_NOTE_OS_SOLARIS2 = 2 +ELF_NOTE_OS_FREEBSD = 3 +NT_GNU_HWCAP = 2 +NT_GNU_BUILD_ID = 3 +NT_GNU_GOLD_VERSION = 4 +NT_GNU_PROPERTY_TYPE_0 = 5 +NT_FDO_PACKAGING_METADATA = 0xcafe1a7e +NOTE_GNU_PROPERTY_SECTION_NAME = ".note.gnu.property" +GNU_PROPERTY_STACK_SIZE = 1 +GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2 +GNU_PROPERTY_UINT32_AND_LO = 0xb0000000 +GNU_PROPERTY_UINT32_AND_HI = 0xb0007fff +GNU_PROPERTY_UINT32_OR_LO = 0xb0008000 +GNU_PROPERTY_UINT32_OR_HI = 0xb000ffff +GNU_PROPERTY_1_NEEDED = GNU_PROPERTY_UINT32_OR_LO +GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS = (1 << 0) +GNU_PROPERTY_LOPROC = 0xc0000000 +GNU_PROPERTY_HIPROC = 0xdfffffff +GNU_PROPERTY_LOUSER = 0xe0000000 +GNU_PROPERTY_HIUSER = 0xffffffff +GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000 +GNU_PROPERTY_AARCH64_FEATURE_1_BTI = (1 << 0) +GNU_PROPERTY_AARCH64_FEATURE_1_PAC = (1 << 1) +GNU_PROPERTY_X86_ISA_1_USED = 0xc0010002 +GNU_PROPERTY_X86_ISA_1_NEEDED = 0xc0008002 +GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002 +GNU_PROPERTY_X86_ISA_1_BASELINE = (1 << 0) +GNU_PROPERTY_X86_ISA_1_V2 = (1 << 1) +GNU_PROPERTY_X86_ISA_1_V3 = (1 << 2) +GNU_PROPERTY_X86_ISA_1_V4 = (1 << 3) +GNU_PROPERTY_X86_FEATURE_1_IBT = (1 << 0) +GNU_PROPERTY_X86_FEATURE_1_SHSTK = (1 << 1) +ELF32_M_SYM = lambda info: ((info) >> 8) +ELF32_M_SIZE = lambda info: ( (info)) +ELF32_M_INFO = lambda sym,size: (((sym) << 8) + (size)) +ELF64_M_SYM = lambda info: ELF32_M_SYM (info) +ELF64_M_SIZE = lambda info: ELF32_M_SIZE (info) +ELF64_M_INFO = lambda sym,size: ELF32_M_INFO (sym, size) +EF_CPU32 = 0x00810000 +R_68K_NONE = 0 +R_68K_32 = 1 +R_68K_16 = 2 +R_68K_8 = 3 +R_68K_PC32 = 4 +R_68K_PC16 = 5 +R_68K_PC8 = 6 +R_68K_GOT32 = 7 +R_68K_GOT16 = 8 +R_68K_GOT8 = 9 +R_68K_GOT32O = 10 +R_68K_GOT16O = 11 +R_68K_GOT8O = 12 +R_68K_PLT32 = 13 +R_68K_PLT16 = 14 +R_68K_PLT8 = 15 +R_68K_PLT32O = 16 +R_68K_PLT16O = 17 +R_68K_PLT8O = 18 +R_68K_COPY = 19 +R_68K_GLOB_DAT = 20 +R_68K_JMP_SLOT = 21 +R_68K_RELATIVE = 22 +R_68K_TLS_GD32 = 25 +R_68K_TLS_GD16 = 26 +R_68K_TLS_GD8 = 27 +R_68K_TLS_LDM32 = 28 +R_68K_TLS_LDM16 = 29 +R_68K_TLS_LDM8 = 30 +R_68K_TLS_LDO32 = 31 +R_68K_TLS_LDO16 = 32 +R_68K_TLS_LDO8 = 33 +R_68K_TLS_IE32 = 34 +R_68K_TLS_IE16 = 35 +R_68K_TLS_IE8 = 36 +R_68K_TLS_LE32 = 37 +R_68K_TLS_LE16 = 38 +R_68K_TLS_LE8 = 39 +R_68K_TLS_DTPMOD32 = 40 +R_68K_TLS_DTPREL32 = 41 +R_68K_TLS_TPREL32 = 42 +R_68K_NUM = 43 +R_386_NONE = 0 +R_386_32 = 1 +R_386_PC32 = 2 +R_386_GOT32 = 3 +R_386_PLT32 = 4 +R_386_COPY = 5 +R_386_GLOB_DAT = 6 +R_386_JMP_SLOT = 7 +R_386_RELATIVE = 8 +R_386_GOTOFF = 9 +R_386_GOTPC = 10 +R_386_32PLT = 11 +R_386_TLS_TPOFF = 14 +R_386_TLS_IE = 15 +R_386_TLS_GOTIE = 16 +R_386_TLS_LE = 17 +R_386_TLS_GD = 18 +R_386_TLS_LDM = 19 +R_386_16 = 20 +R_386_PC16 = 21 +R_386_8 = 22 +R_386_PC8 = 23 +R_386_TLS_GD_32 = 24 +R_386_TLS_GD_PUSH = 25 +R_386_TLS_GD_CALL = 26 +R_386_TLS_GD_POP = 27 +R_386_TLS_LDM_32 = 28 +R_386_TLS_LDM_PUSH = 29 +R_386_TLS_LDM_CALL = 30 +R_386_TLS_LDM_POP = 31 +R_386_TLS_LDO_32 = 32 +R_386_TLS_IE_32 = 33 +R_386_TLS_LE_32 = 34 +R_386_TLS_DTPMOD32 = 35 +R_386_TLS_DTPOFF32 = 36 +R_386_TLS_TPOFF32 = 37 +R_386_SIZE32 = 38 +R_386_TLS_GOTDESC = 39 +R_386_TLS_DESC_CALL = 40 +R_386_TLS_DESC = 41 +R_386_IRELATIVE = 42 +R_386_GOT32X = 43 +R_386_NUM = 44 +STT_SPARC_REGISTER = 13 +EF_SPARCV9_MM = 3 +EF_SPARCV9_TSO = 0 +EF_SPARCV9_PSO = 1 +EF_SPARCV9_RMO = 2 +EF_SPARC_LEDATA = 0x800000 +EF_SPARC_EXT_MASK = 0xFFFF00 +EF_SPARC_32PLUS = 0x000100 +EF_SPARC_SUN_US1 = 0x000200 +EF_SPARC_HAL_R1 = 0x000400 +EF_SPARC_SUN_US3 = 0x000800 +R_SPARC_NONE = 0 +R_SPARC_8 = 1 +R_SPARC_16 = 2 +R_SPARC_32 = 3 +R_SPARC_DISP8 = 4 +R_SPARC_DISP16 = 5 +R_SPARC_DISP32 = 6 +R_SPARC_WDISP30 = 7 +R_SPARC_WDISP22 = 8 +R_SPARC_HI22 = 9 +R_SPARC_22 = 10 +R_SPARC_13 = 11 +R_SPARC_LO10 = 12 +R_SPARC_GOT10 = 13 +R_SPARC_GOT13 = 14 +R_SPARC_GOT22 = 15 +R_SPARC_PC10 = 16 +R_SPARC_PC22 = 17 +R_SPARC_WPLT30 = 18 +R_SPARC_COPY = 19 +R_SPARC_GLOB_DAT = 20 +R_SPARC_JMP_SLOT = 21 +R_SPARC_RELATIVE = 22 +R_SPARC_UA32 = 23 +R_SPARC_PLT32 = 24 +R_SPARC_HIPLT22 = 25 +R_SPARC_LOPLT10 = 26 +R_SPARC_PCPLT32 = 27 +R_SPARC_PCPLT22 = 28 +R_SPARC_PCPLT10 = 29 +R_SPARC_10 = 30 +R_SPARC_11 = 31 +R_SPARC_64 = 32 +R_SPARC_OLO10 = 33 +R_SPARC_HH22 = 34 +R_SPARC_HM10 = 35 +R_SPARC_LM22 = 36 +R_SPARC_PC_HH22 = 37 +R_SPARC_PC_HM10 = 38 +R_SPARC_PC_LM22 = 39 +R_SPARC_WDISP16 = 40 +R_SPARC_WDISP19 = 41 +R_SPARC_GLOB_JMP = 42 +R_SPARC_7 = 43 +R_SPARC_5 = 44 +R_SPARC_6 = 45 +R_SPARC_DISP64 = 46 +R_SPARC_PLT64 = 47 +R_SPARC_HIX22 = 48 +R_SPARC_LOX10 = 49 +R_SPARC_H44 = 50 +R_SPARC_M44 = 51 +R_SPARC_L44 = 52 +R_SPARC_REGISTER = 53 +R_SPARC_UA64 = 54 +R_SPARC_UA16 = 55 +R_SPARC_TLS_GD_HI22 = 56 +R_SPARC_TLS_GD_LO10 = 57 +R_SPARC_TLS_GD_ADD = 58 +R_SPARC_TLS_GD_CALL = 59 +R_SPARC_TLS_LDM_HI22 = 60 +R_SPARC_TLS_LDM_LO10 = 61 +R_SPARC_TLS_LDM_ADD = 62 +R_SPARC_TLS_LDM_CALL = 63 +R_SPARC_TLS_LDO_HIX22 = 64 +R_SPARC_TLS_LDO_LOX10 = 65 +R_SPARC_TLS_LDO_ADD = 66 +R_SPARC_TLS_IE_HI22 = 67 +R_SPARC_TLS_IE_LO10 = 68 +R_SPARC_TLS_IE_LD = 69 +R_SPARC_TLS_IE_LDX = 70 +R_SPARC_TLS_IE_ADD = 71 +R_SPARC_TLS_LE_HIX22 = 72 +R_SPARC_TLS_LE_LOX10 = 73 +R_SPARC_TLS_DTPMOD32 = 74 +R_SPARC_TLS_DTPMOD64 = 75 +R_SPARC_TLS_DTPOFF32 = 76 +R_SPARC_TLS_DTPOFF64 = 77 +R_SPARC_TLS_TPOFF32 = 78 +R_SPARC_TLS_TPOFF64 = 79 +R_SPARC_GOTDATA_HIX22 = 80 +R_SPARC_GOTDATA_LOX10 = 81 +R_SPARC_GOTDATA_OP_HIX22 = 82 +R_SPARC_GOTDATA_OP_LOX10 = 83 +R_SPARC_GOTDATA_OP = 84 +R_SPARC_H34 = 85 +R_SPARC_SIZE32 = 86 +R_SPARC_SIZE64 = 87 +R_SPARC_WDISP10 = 88 +R_SPARC_JMP_IREL = 248 +R_SPARC_IRELATIVE = 249 +R_SPARC_GNU_VTINHERIT = 250 +R_SPARC_GNU_VTENTRY = 251 +R_SPARC_REV32 = 252 +R_SPARC_NUM = 253 +DT_SPARC_REGISTER = 0x70000001 +DT_SPARC_NUM = 2 +EF_MIPS_NOREORDER = 1 +EF_MIPS_PIC = 2 +EF_MIPS_CPIC = 4 +EF_MIPS_XGOT = 8 +EF_MIPS_UCODE = 16 +EF_MIPS_ABI2 = 32 +EF_MIPS_ABI_ON32 = 64 +EF_MIPS_OPTIONS_FIRST = 0x00000080 +EF_MIPS_32BITMODE = 0x00000100 +EF_MIPS_FP64 = 512 +EF_MIPS_NAN2008 = 1024 +EF_MIPS_ARCH_ASE = 0x0f000000 +EF_MIPS_ARCH_ASE_MDMX = 0x08000000 +EF_MIPS_ARCH_ASE_M16 = 0x04000000 +EF_MIPS_ARCH_ASE_MICROMIPS = 0x02000000 +EF_MIPS_ARCH = 0xf0000000 +EF_MIPS_ARCH_1 = 0x00000000 +EF_MIPS_ARCH_2 = 0x10000000 +EF_MIPS_ARCH_3 = 0x20000000 +EF_MIPS_ARCH_4 = 0x30000000 +EF_MIPS_ARCH_5 = 0x40000000 +EF_MIPS_ARCH_32 = 0x50000000 +EF_MIPS_ARCH_64 = 0x60000000 +EF_MIPS_ARCH_32R2 = 0x70000000 +EF_MIPS_ARCH_64R2 = 0x80000000 +EF_MIPS_ARCH_32R6 = 0x90000000 +EF_MIPS_ARCH_64R6 = 0xa0000000 +EF_MIPS_ABI = 0x0000F000 +EF_MIPS_ABI_O32 = 0x00001000 +EF_MIPS_ABI_O64 = 0x00002000 +EF_MIPS_ABI_EABI32 = 0x00003000 +EF_MIPS_ABI_EABI64 = 0x00004000 +EF_MIPS_MACH = 0x00FF0000 +EF_MIPS_MACH_3900 = 0x00810000 +EF_MIPS_MACH_4010 = 0x00820000 +EF_MIPS_MACH_4100 = 0x00830000 +EF_MIPS_MACH_ALLEGREX = 0x00840000 +EF_MIPS_MACH_4650 = 0x00850000 +EF_MIPS_MACH_4120 = 0x00870000 +EF_MIPS_MACH_4111 = 0x00880000 +EF_MIPS_MACH_SB1 = 0x008a0000 +EF_MIPS_MACH_OCTEON = 0x008b0000 +EF_MIPS_MACH_XLR = 0x008c0000 +EF_MIPS_MACH_OCTEON2 = 0x008d0000 +EF_MIPS_MACH_OCTEON3 = 0x008e0000 +EF_MIPS_MACH_5400 = 0x00910000 +EF_MIPS_MACH_5900 = 0x00920000 +EF_MIPS_MACH_IAMR2 = 0x00930000 +EF_MIPS_MACH_5500 = 0x00980000 +EF_MIPS_MACH_9000 = 0x00990000 +EF_MIPS_MACH_LS2E = 0x00A00000 +EF_MIPS_MACH_LS2F = 0x00A10000 +EF_MIPS_MACH_GS464 = 0x00A20000 +EF_MIPS_MACH_GS464E = 0x00A30000 +EF_MIPS_MACH_GS264E = 0x00A40000 +E_MIPS_ARCH_1 = EF_MIPS_ARCH_1 +E_MIPS_ARCH_2 = EF_MIPS_ARCH_2 +E_MIPS_ARCH_3 = EF_MIPS_ARCH_3 +E_MIPS_ARCH_4 = EF_MIPS_ARCH_4 +E_MIPS_ARCH_5 = EF_MIPS_ARCH_5 +E_MIPS_ARCH_32 = EF_MIPS_ARCH_32 +E_MIPS_ARCH_64 = EF_MIPS_ARCH_64 +SHN_MIPS_ACOMMON = 0xff00 +SHN_MIPS_TEXT = 0xff01 +SHN_MIPS_DATA = 0xff02 +SHN_MIPS_SCOMMON = 0xff03 +SHN_MIPS_SUNDEFINED = 0xff04 +SHT_MIPS_LIBLIST = 0x70000000 +SHT_MIPS_MSYM = 0x70000001 +SHT_MIPS_CONFLICT = 0x70000002 +SHT_MIPS_GPTAB = 0x70000003 +SHT_MIPS_UCODE = 0x70000004 +SHT_MIPS_DEBUG = 0x70000005 +SHT_MIPS_REGINFO = 0x70000006 +SHT_MIPS_PACKAGE = 0x70000007 +SHT_MIPS_PACKSYM = 0x70000008 +SHT_MIPS_RELD = 0x70000009 +SHT_MIPS_IFACE = 0x7000000b +SHT_MIPS_CONTENT = 0x7000000c +SHT_MIPS_OPTIONS = 0x7000000d +SHT_MIPS_SHDR = 0x70000010 +SHT_MIPS_FDESC = 0x70000011 +SHT_MIPS_EXTSYM = 0x70000012 +SHT_MIPS_DENSE = 0x70000013 +SHT_MIPS_PDESC = 0x70000014 +SHT_MIPS_LOCSYM = 0x70000015 +SHT_MIPS_AUXSYM = 0x70000016 +SHT_MIPS_OPTSYM = 0x70000017 +SHT_MIPS_LOCSTR = 0x70000018 +SHT_MIPS_LINE = 0x70000019 +SHT_MIPS_RFDESC = 0x7000001a +SHT_MIPS_DELTASYM = 0x7000001b +SHT_MIPS_DELTAINST = 0x7000001c +SHT_MIPS_DELTACLASS = 0x7000001d +SHT_MIPS_DWARF = 0x7000001e +SHT_MIPS_DELTADECL = 0x7000001f +SHT_MIPS_SYMBOL_LIB = 0x70000020 +SHT_MIPS_EVENTS = 0x70000021 +SHT_MIPS_TRANSLATE = 0x70000022 +SHT_MIPS_PIXIE = 0x70000023 +SHT_MIPS_XLATE = 0x70000024 +SHT_MIPS_XLATE_DEBUG = 0x70000025 +SHT_MIPS_WHIRL = 0x70000026 +SHT_MIPS_EH_REGION = 0x70000027 +SHT_MIPS_XLATE_OLD = 0x70000028 +SHT_MIPS_PDR_EXCEPTION = 0x70000029 +SHT_MIPS_ABIFLAGS = 0x7000002a +SHT_MIPS_XHASH = 0x7000002b +SHF_MIPS_GPREL = 0x10000000 +SHF_MIPS_MERGE = 0x20000000 +SHF_MIPS_ADDR = 0x40000000 +SHF_MIPS_STRINGS = 0x80000000 +SHF_MIPS_NOSTRIP = 0x08000000 +SHF_MIPS_LOCAL = 0x04000000 +SHF_MIPS_NAMES = 0x02000000 +SHF_MIPS_NODUPE = 0x01000000 +STO_MIPS_DEFAULT = 0x0 +STO_MIPS_INTERNAL = 0x1 +STO_MIPS_HIDDEN = 0x2 +STO_MIPS_PROTECTED = 0x3 +STO_MIPS_PLT = 0x8 +STO_MIPS_SC_ALIGN_UNUSED = 0xff +STB_MIPS_SPLIT_COMMON = 13 +ODK_NULL = 0 +ODK_REGINFO = 1 +ODK_EXCEPTIONS = 2 +ODK_PAD = 3 +ODK_HWPATCH = 4 +ODK_FILL = 5 +ODK_TAGS = 6 +ODK_HWAND = 7 +ODK_HWOR = 8 +OEX_FPU_MIN = 0x1f +OEX_FPU_MAX = 0x1f00 +OEX_PAGE0 = 0x10000 +OEX_SMM = 0x20000 +OEX_FPDBUG = 0x40000 +OEX_PRECISEFP = OEX_FPDBUG +OEX_DISMISS = 0x80000 +OEX_FPU_INVAL = 0x10 +OEX_FPU_DIV0 = 0x08 +OEX_FPU_OFLO = 0x04 +OEX_FPU_UFLO = 0x02 +OEX_FPU_INEX = 0x01 +OHW_R4KEOP = 0x1 +OHW_R8KPFETCH = 0x2 +OHW_R5KEOP = 0x4 +OHW_R5KCVTL = 0x8 +OPAD_PREFIX = 0x1 +OPAD_POSTFIX = 0x2 +OPAD_SYMBOL = 0x4 +OHWA0_R4KEOP_CHECKED = 0x00000001 +OHWA1_R4KEOP_CLEAN = 0x00000002 +R_MIPS_NONE = 0 +R_MIPS_16 = 1 +R_MIPS_32 = 2 +R_MIPS_REL32 = 3 +R_MIPS_26 = 4 +R_MIPS_HI16 = 5 +R_MIPS_LO16 = 6 +R_MIPS_GPREL16 = 7 +R_MIPS_LITERAL = 8 +R_MIPS_GOT16 = 9 +R_MIPS_PC16 = 10 +R_MIPS_CALL16 = 11 +R_MIPS_GPREL32 = 12 +R_MIPS_SHIFT5 = 16 +R_MIPS_SHIFT6 = 17 +R_MIPS_64 = 18 +R_MIPS_GOT_DISP = 19 +R_MIPS_GOT_PAGE = 20 +R_MIPS_GOT_OFST = 21 +R_MIPS_GOT_HI16 = 22 +R_MIPS_GOT_LO16 = 23 +R_MIPS_SUB = 24 +R_MIPS_INSERT_A = 25 +R_MIPS_INSERT_B = 26 +R_MIPS_DELETE = 27 +R_MIPS_HIGHER = 28 +R_MIPS_HIGHEST = 29 +R_MIPS_CALL_HI16 = 30 +R_MIPS_CALL_LO16 = 31 +R_MIPS_SCN_DISP = 32 +R_MIPS_REL16 = 33 +R_MIPS_ADD_IMMEDIATE = 34 +R_MIPS_PJUMP = 35 +R_MIPS_RELGOT = 36 +R_MIPS_JALR = 37 +R_MIPS_TLS_DTPMOD32 = 38 +R_MIPS_TLS_DTPREL32 = 39 +R_MIPS_TLS_DTPMOD64 = 40 +R_MIPS_TLS_DTPREL64 = 41 +R_MIPS_TLS_GD = 42 +R_MIPS_TLS_LDM = 43 +R_MIPS_TLS_DTPREL_HI16 = 44 +R_MIPS_TLS_DTPREL_LO16 = 45 +R_MIPS_TLS_GOTTPREL = 46 +R_MIPS_TLS_TPREL32 = 47 +R_MIPS_TLS_TPREL64 = 48 +R_MIPS_TLS_TPREL_HI16 = 49 +R_MIPS_TLS_TPREL_LO16 = 50 +R_MIPS_GLOB_DAT = 51 +R_MIPS_PC21_S2 = 60 +R_MIPS_PC26_S2 = 61 +R_MIPS_PC18_S3 = 62 +R_MIPS_PC19_S2 = 63 +R_MIPS_PCHI16 = 64 +R_MIPS_PCLO16 = 65 +R_MIPS16_26 = 100 +R_MIPS16_GPREL = 101 +R_MIPS16_GOT16 = 102 +R_MIPS16_CALL16 = 103 +R_MIPS16_HI16 = 104 +R_MIPS16_LO16 = 105 +R_MIPS16_TLS_GD = 106 +R_MIPS16_TLS_LDM = 107 +R_MIPS16_TLS_DTPREL_HI16 = 108 +R_MIPS16_TLS_DTPREL_LO16 = 109 +R_MIPS16_TLS_GOTTPREL = 110 +R_MIPS16_TLS_TPREL_HI16 = 111 +R_MIPS16_TLS_TPREL_LO16 = 112 +R_MIPS16_PC16_S1 = 113 +R_MIPS_COPY = 126 +R_MIPS_JUMP_SLOT = 127 +R_MIPS_RELATIVE = 128 +R_MICROMIPS_26_S1 = 133 +R_MICROMIPS_HI16 = 134 +R_MICROMIPS_LO16 = 135 +R_MICROMIPS_GPREL16 = 136 +R_MICROMIPS_LITERAL = 137 +R_MICROMIPS_GOT16 = 138 +R_MICROMIPS_PC7_S1 = 139 +R_MICROMIPS_PC10_S1 = 140 +R_MICROMIPS_PC16_S1 = 141 +R_MICROMIPS_CALL16 = 142 +R_MICROMIPS_GOT_DISP = 145 +R_MICROMIPS_GOT_PAGE = 146 +R_MICROMIPS_GOT_OFST = 147 +R_MICROMIPS_GOT_HI16 = 148 +R_MICROMIPS_GOT_LO16 = 149 +R_MICROMIPS_SUB = 150 +R_MICROMIPS_HIGHER = 151 +R_MICROMIPS_HIGHEST = 152 +R_MICROMIPS_CALL_HI16 = 153 +R_MICROMIPS_CALL_LO16 = 154 +R_MICROMIPS_SCN_DISP = 155 +R_MICROMIPS_JALR = 156 +R_MICROMIPS_HI0_LO16 = 157 +R_MICROMIPS_TLS_GD = 162 +R_MICROMIPS_TLS_LDM = 163 +R_MICROMIPS_TLS_DTPREL_HI16 = 164 +R_MICROMIPS_TLS_DTPREL_LO16 = 165 +R_MICROMIPS_TLS_GOTTPREL = 166 +R_MICROMIPS_TLS_TPREL_HI16 = 169 +R_MICROMIPS_TLS_TPREL_LO16 = 170 +R_MICROMIPS_GPREL7_S2 = 172 +R_MICROMIPS_PC23_S2 = 173 +R_MIPS_PC32 = 248 +R_MIPS_EH = 249 +R_MIPS_GNU_REL16_S2 = 250 +R_MIPS_GNU_VTINHERIT = 253 +R_MIPS_GNU_VTENTRY = 254 +R_MIPS_NUM = 255 +PT_MIPS_REGINFO = 0x70000000 +PT_MIPS_RTPROC = 0x70000001 +PT_MIPS_OPTIONS = 0x70000002 +PT_MIPS_ABIFLAGS = 0x70000003 +PF_MIPS_LOCAL = 0x10000000 +DT_MIPS_RLD_VERSION = 0x70000001 +DT_MIPS_TIME_STAMP = 0x70000002 +DT_MIPS_ICHECKSUM = 0x70000003 +DT_MIPS_IVERSION = 0x70000004 +DT_MIPS_FLAGS = 0x70000005 +DT_MIPS_BASE_ADDRESS = 0x70000006 +DT_MIPS_MSYM = 0x70000007 +DT_MIPS_CONFLICT = 0x70000008 +DT_MIPS_LIBLIST = 0x70000009 +DT_MIPS_LOCAL_GOTNO = 0x7000000a +DT_MIPS_CONFLICTNO = 0x7000000b +DT_MIPS_LIBLISTNO = 0x70000010 +DT_MIPS_SYMTABNO = 0x70000011 +DT_MIPS_UNREFEXTNO = 0x70000012 +DT_MIPS_GOTSYM = 0x70000013 +DT_MIPS_HIPAGENO = 0x70000014 +DT_MIPS_RLD_MAP = 0x70000016 +DT_MIPS_DELTA_CLASS = 0x70000017 +DT_MIPS_DELTA_CLASS_NO = 0x70000018 +DT_MIPS_DELTA_INSTANCE = 0x70000019 +DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a +DT_MIPS_DELTA_RELOC = 0x7000001b +DT_MIPS_DELTA_RELOC_NO = 0x7000001c +DT_MIPS_DELTA_SYM = 0x7000001d +DT_MIPS_DELTA_SYM_NO = 0x7000001e +DT_MIPS_DELTA_CLASSSYM = 0x70000020 +DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021 +DT_MIPS_CXX_FLAGS = 0x70000022 +DT_MIPS_PIXIE_INIT = 0x70000023 +DT_MIPS_SYMBOL_LIB = 0x70000024 +DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025 +DT_MIPS_LOCAL_GOTIDX = 0x70000026 +DT_MIPS_HIDDEN_GOTIDX = 0x70000027 +DT_MIPS_PROTECTED_GOTIDX = 0x70000028 +DT_MIPS_OPTIONS = 0x70000029 +DT_MIPS_INTERFACE = 0x7000002a +DT_MIPS_DYNSTR_ALIGN = 0x7000002b +DT_MIPS_INTERFACE_SIZE = 0x7000002c +DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d +DT_MIPS_PERF_SUFFIX = 0x7000002e +DT_MIPS_COMPACT_SIZE = 0x7000002f +DT_MIPS_GP_VALUE = 0x70000030 +DT_MIPS_AUX_DYNAMIC = 0x70000031 +DT_MIPS_PLTGOT = 0x70000032 +DT_MIPS_RWPLT = 0x70000034 +DT_MIPS_RLD_MAP_REL = 0x70000035 +DT_MIPS_XHASH = 0x70000036 +DT_MIPS_NUM = 0x37 +RHF_NONE = 0 +RHF_QUICKSTART = (1 << 0) +RHF_NOTPOT = (1 << 1) +RHF_NO_LIBRARY_REPLACEMENT = (1 << 2) +RHF_NO_MOVE = (1 << 3) +RHF_SGI_ONLY = (1 << 4) +RHF_GUARANTEE_INIT = (1 << 5) +RHF_DELTA_C_PLUS_PLUS = (1 << 6) +RHF_GUARANTEE_START_INIT = (1 << 7) +RHF_PIXIE = (1 << 8) +RHF_DEFAULT_DELAY_LOAD = (1 << 9) +RHF_REQUICKSTART = (1 << 10) +RHF_REQUICKSTARTED = (1 << 11) +RHF_CORD = (1 << 12) +RHF_NO_UNRES_UNDEF = (1 << 13) +RHF_RLD_ORDER_SAFE = (1 << 14) +LL_NONE = 0 +LL_EXACT_MATCH = (1 << 0) +LL_IGNORE_INT_VER = (1 << 1) +LL_REQUIRE_MINOR = (1 << 2) +LL_EXPORTS = (1 << 3) +LL_DELAY_LOAD = (1 << 4) +LL_DELTA = (1 << 5) +MIPS_AFL_REG_NONE = 0x00 +MIPS_AFL_REG_32 = 0x01 +MIPS_AFL_REG_64 = 0x02 +MIPS_AFL_REG_128 = 0x03 +MIPS_AFL_ASE_DSP = 0x00000001 +MIPS_AFL_ASE_DSPR2 = 0x00000002 +MIPS_AFL_ASE_EVA = 0x00000004 +MIPS_AFL_ASE_MCU = 0x00000008 +MIPS_AFL_ASE_MDMX = 0x00000010 +MIPS_AFL_ASE_MIPS3D = 0x00000020 +MIPS_AFL_ASE_MT = 0x00000040 +MIPS_AFL_ASE_SMARTMIPS = 0x00000080 +MIPS_AFL_ASE_VIRT = 0x00000100 +MIPS_AFL_ASE_MSA = 0x00000200 +MIPS_AFL_ASE_MIPS16 = 0x00000400 +MIPS_AFL_ASE_MICROMIPS = 0x00000800 +MIPS_AFL_ASE_XPA = 0x00001000 +MIPS_AFL_ASE_MASK = 0x00001fff +MIPS_AFL_EXT_XLR = 1 +MIPS_AFL_EXT_OCTEON2 = 2 +MIPS_AFL_EXT_OCTEONP = 3 +MIPS_AFL_EXT_LOONGSON_3A = 4 +MIPS_AFL_EXT_OCTEON = 5 +MIPS_AFL_EXT_5900 = 6 +MIPS_AFL_EXT_4650 = 7 +MIPS_AFL_EXT_4010 = 8 +MIPS_AFL_EXT_4100 = 9 +MIPS_AFL_EXT_3900 = 10 +MIPS_AFL_EXT_10000 = 11 +MIPS_AFL_EXT_SB1 = 12 +MIPS_AFL_EXT_4111 = 13 +MIPS_AFL_EXT_4120 = 14 +MIPS_AFL_EXT_5400 = 15 +MIPS_AFL_EXT_5500 = 16 +MIPS_AFL_EXT_LOONGSON_2E = 17 +MIPS_AFL_EXT_LOONGSON_2F = 18 +MIPS_AFL_FLAGS1_ODDSPREG = 1 +EF_PARISC_TRAPNIL = 0x00010000 +EF_PARISC_EXT = 0x00020000 +EF_PARISC_LSB = 0x00040000 +EF_PARISC_WIDE = 0x00080000 +EF_PARISC_NO_KABP = 0x00100000 +EF_PARISC_LAZYSWAP = 0x00400000 +EF_PARISC_ARCH = 0x0000ffff +EFA_PARISC_1_0 = 0x020b +EFA_PARISC_1_1 = 0x0210 +EFA_PARISC_2_0 = 0x0214 +SHN_PARISC_ANSI_COMMON = 0xff00 +SHN_PARISC_HUGE_COMMON = 0xff01 +SHT_PARISC_EXT = 0x70000000 +SHT_PARISC_UNWIND = 0x70000001 +SHT_PARISC_DOC = 0x70000002 +SHF_PARISC_SHORT = 0x20000000 +SHF_PARISC_HUGE = 0x40000000 +SHF_PARISC_SBP = 0x80000000 +STT_PARISC_MILLICODE = 13 +STT_HP_OPAQUE = (STT_LOOS + 0x1) +STT_HP_STUB = (STT_LOOS + 0x2) +R_PARISC_NONE = 0 +R_PARISC_DIR32 = 1 +R_PARISC_DIR21L = 2 +R_PARISC_DIR17R = 3 +R_PARISC_DIR17F = 4 +R_PARISC_DIR14R = 6 +R_PARISC_PCREL32 = 9 +R_PARISC_PCREL21L = 10 +R_PARISC_PCREL17R = 11 +R_PARISC_PCREL17F = 12 +R_PARISC_PCREL14R = 14 +R_PARISC_DPREL21L = 18 +R_PARISC_DPREL14R = 22 +R_PARISC_GPREL21L = 26 +R_PARISC_GPREL14R = 30 +R_PARISC_LTOFF21L = 34 +R_PARISC_LTOFF14R = 38 +R_PARISC_SECREL32 = 41 +R_PARISC_SEGBASE = 48 +R_PARISC_SEGREL32 = 49 +R_PARISC_PLTOFF21L = 50 +R_PARISC_PLTOFF14R = 54 +R_PARISC_LTOFF_FPTR32 = 57 +R_PARISC_LTOFF_FPTR21L = 58 +R_PARISC_LTOFF_FPTR14R = 62 +R_PARISC_FPTR64 = 64 +R_PARISC_PLABEL32 = 65 +R_PARISC_PLABEL21L = 66 +R_PARISC_PLABEL14R = 70 +R_PARISC_PCREL64 = 72 +R_PARISC_PCREL22F = 74 +R_PARISC_PCREL14WR = 75 +R_PARISC_PCREL14DR = 76 +R_PARISC_PCREL16F = 77 +R_PARISC_PCREL16WF = 78 +R_PARISC_PCREL16DF = 79 +R_PARISC_DIR64 = 80 +R_PARISC_DIR14WR = 83 +R_PARISC_DIR14DR = 84 +R_PARISC_DIR16F = 85 +R_PARISC_DIR16WF = 86 +R_PARISC_DIR16DF = 87 +R_PARISC_GPREL64 = 88 +R_PARISC_GPREL14WR = 91 +R_PARISC_GPREL14DR = 92 +R_PARISC_GPREL16F = 93 +R_PARISC_GPREL16WF = 94 +R_PARISC_GPREL16DF = 95 +R_PARISC_LTOFF64 = 96 +R_PARISC_LTOFF14WR = 99 +R_PARISC_LTOFF14DR = 100 +R_PARISC_LTOFF16F = 101 +R_PARISC_LTOFF16WF = 102 +R_PARISC_LTOFF16DF = 103 +R_PARISC_SECREL64 = 104 +R_PARISC_SEGREL64 = 112 +R_PARISC_PLTOFF14WR = 115 +R_PARISC_PLTOFF14DR = 116 +R_PARISC_PLTOFF16F = 117 +R_PARISC_PLTOFF16WF = 118 +R_PARISC_PLTOFF16DF = 119 +R_PARISC_LTOFF_FPTR64 = 120 +R_PARISC_LTOFF_FPTR14WR = 123 +R_PARISC_LTOFF_FPTR14DR = 124 +R_PARISC_LTOFF_FPTR16F = 125 +R_PARISC_LTOFF_FPTR16WF = 126 +R_PARISC_LTOFF_FPTR16DF = 127 +R_PARISC_LORESERVE = 128 +R_PARISC_COPY = 128 +R_PARISC_IPLT = 129 +R_PARISC_EPLT = 130 +R_PARISC_TPREL32 = 153 +R_PARISC_TPREL21L = 154 +R_PARISC_TPREL14R = 158 +R_PARISC_LTOFF_TP21L = 162 +R_PARISC_LTOFF_TP14R = 166 +R_PARISC_LTOFF_TP14F = 167 +R_PARISC_TPREL64 = 216 +R_PARISC_TPREL14WR = 219 +R_PARISC_TPREL14DR = 220 +R_PARISC_TPREL16F = 221 +R_PARISC_TPREL16WF = 222 +R_PARISC_TPREL16DF = 223 +R_PARISC_LTOFF_TP64 = 224 +R_PARISC_LTOFF_TP14WR = 227 +R_PARISC_LTOFF_TP14DR = 228 +R_PARISC_LTOFF_TP16F = 229 +R_PARISC_LTOFF_TP16WF = 230 +R_PARISC_LTOFF_TP16DF = 231 +R_PARISC_GNU_VTENTRY = 232 +R_PARISC_GNU_VTINHERIT = 233 +R_PARISC_TLS_GD21L = 234 +R_PARISC_TLS_GD14R = 235 +R_PARISC_TLS_GDCALL = 236 +R_PARISC_TLS_LDM21L = 237 +R_PARISC_TLS_LDM14R = 238 +R_PARISC_TLS_LDMCALL = 239 +R_PARISC_TLS_LDO21L = 240 +R_PARISC_TLS_LDO14R = 241 +R_PARISC_TLS_DTPMOD32 = 242 +R_PARISC_TLS_DTPMOD64 = 243 +R_PARISC_TLS_DTPOFF32 = 244 +R_PARISC_TLS_DTPOFF64 = 245 +R_PARISC_TLS_LE21L = R_PARISC_TPREL21L +R_PARISC_TLS_LE14R = R_PARISC_TPREL14R +R_PARISC_TLS_IE21L = R_PARISC_LTOFF_TP21L +R_PARISC_TLS_IE14R = R_PARISC_LTOFF_TP14R +R_PARISC_TLS_TPREL32 = R_PARISC_TPREL32 +R_PARISC_TLS_TPREL64 = R_PARISC_TPREL64 +R_PARISC_HIRESERVE = 255 +PT_HP_TLS = (PT_LOOS + 0x0) +PT_HP_CORE_NONE = (PT_LOOS + 0x1) +PT_HP_CORE_VERSION = (PT_LOOS + 0x2) +PT_HP_CORE_KERNEL = (PT_LOOS + 0x3) +PT_HP_CORE_COMM = (PT_LOOS + 0x4) +PT_HP_CORE_PROC = (PT_LOOS + 0x5) +PT_HP_CORE_LOADABLE = (PT_LOOS + 0x6) +PT_HP_CORE_STACK = (PT_LOOS + 0x7) +PT_HP_CORE_SHM = (PT_LOOS + 0x8) +PT_HP_CORE_MMF = (PT_LOOS + 0x9) +PT_HP_PARALLEL = (PT_LOOS + 0x10) +PT_HP_FASTBIND = (PT_LOOS + 0x11) +PT_HP_OPT_ANNOT = (PT_LOOS + 0x12) +PT_HP_HSL_ANNOT = (PT_LOOS + 0x13) +PT_HP_STACK = (PT_LOOS + 0x14) +PT_PARISC_ARCHEXT = 0x70000000 +PT_PARISC_UNWIND = 0x70000001 +PF_PARISC_SBP = 0x08000000 +PF_HP_PAGE_SIZE = 0x00100000 +PF_HP_FAR_SHARED = 0x00200000 +PF_HP_NEAR_SHARED = 0x00400000 +PF_HP_CODE = 0x01000000 +PF_HP_MODIFY = 0x02000000 +PF_HP_LAZYSWAP = 0x04000000 +PF_HP_SBP = 0x08000000 +EF_ALPHA_32BIT = 1 +EF_ALPHA_CANRELAX = 2 +SHT_ALPHA_DEBUG = 0x70000001 +SHT_ALPHA_REGINFO = 0x70000002 +SHF_ALPHA_GPREL = 0x10000000 +STO_ALPHA_NOPV = 0x80 +STO_ALPHA_STD_GPLOAD = 0x88 +R_ALPHA_NONE = 0 +R_ALPHA_REFLONG = 1 +R_ALPHA_REFQUAD = 2 +R_ALPHA_GPREL32 = 3 +R_ALPHA_LITERAL = 4 +R_ALPHA_LITUSE = 5 +R_ALPHA_GPDISP = 6 +R_ALPHA_BRADDR = 7 +R_ALPHA_HINT = 8 +R_ALPHA_SREL16 = 9 +R_ALPHA_SREL32 = 10 +R_ALPHA_SREL64 = 11 +R_ALPHA_GPRELHIGH = 17 +R_ALPHA_GPRELLOW = 18 +R_ALPHA_GPREL16 = 19 +R_ALPHA_COPY = 24 +R_ALPHA_GLOB_DAT = 25 +R_ALPHA_JMP_SLOT = 26 +R_ALPHA_RELATIVE = 27 +R_ALPHA_TLS_GD_HI = 28 +R_ALPHA_TLSGD = 29 +R_ALPHA_TLS_LDM = 30 +R_ALPHA_DTPMOD64 = 31 +R_ALPHA_GOTDTPREL = 32 +R_ALPHA_DTPREL64 = 33 +R_ALPHA_DTPRELHI = 34 +R_ALPHA_DTPRELLO = 35 +R_ALPHA_DTPREL16 = 36 +R_ALPHA_GOTTPREL = 37 +R_ALPHA_TPREL64 = 38 +R_ALPHA_TPRELHI = 39 +R_ALPHA_TPRELLO = 40 +R_ALPHA_TPREL16 = 41 +R_ALPHA_NUM = 46 +LITUSE_ALPHA_ADDR = 0 +LITUSE_ALPHA_BASE = 1 +LITUSE_ALPHA_BYTOFF = 2 +LITUSE_ALPHA_JSR = 3 +LITUSE_ALPHA_TLS_GD = 4 +LITUSE_ALPHA_TLS_LDM = 5 +DT_ALPHA_PLTRO = (DT_LOPROC + 0) +DT_ALPHA_NUM = 1 +EF_PPC_EMB = 0x80000000 +EF_PPC_RELOCATABLE = 0x00010000 +EF_PPC_RELOCATABLE_LIB = 0x00008000 +R_PPC_NONE = 0 +R_PPC_ADDR32 = 1 +R_PPC_ADDR24 = 2 +R_PPC_ADDR16 = 3 +R_PPC_ADDR16_LO = 4 +R_PPC_ADDR16_HI = 5 +R_PPC_ADDR16_HA = 6 +R_PPC_ADDR14 = 7 +R_PPC_ADDR14_BRTAKEN = 8 +R_PPC_ADDR14_BRNTAKEN = 9 +R_PPC_REL24 = 10 +R_PPC_REL14 = 11 +R_PPC_REL14_BRTAKEN = 12 +R_PPC_REL14_BRNTAKEN = 13 +R_PPC_GOT16 = 14 +R_PPC_GOT16_LO = 15 +R_PPC_GOT16_HI = 16 +R_PPC_GOT16_HA = 17 +R_PPC_PLTREL24 = 18 +R_PPC_COPY = 19 +R_PPC_GLOB_DAT = 20 +R_PPC_JMP_SLOT = 21 +R_PPC_RELATIVE = 22 +R_PPC_LOCAL24PC = 23 +R_PPC_UADDR32 = 24 +R_PPC_UADDR16 = 25 +R_PPC_REL32 = 26 +R_PPC_PLT32 = 27 +R_PPC_PLTREL32 = 28 +R_PPC_PLT16_LO = 29 +R_PPC_PLT16_HI = 30 +R_PPC_PLT16_HA = 31 +R_PPC_SDAREL16 = 32 +R_PPC_SECTOFF = 33 +R_PPC_SECTOFF_LO = 34 +R_PPC_SECTOFF_HI = 35 +R_PPC_SECTOFF_HA = 36 +R_PPC_TLS = 67 +R_PPC_DTPMOD32 = 68 +R_PPC_TPREL16 = 69 +R_PPC_TPREL16_LO = 70 +R_PPC_TPREL16_HI = 71 +R_PPC_TPREL16_HA = 72 +R_PPC_TPREL32 = 73 +R_PPC_DTPREL16 = 74 +R_PPC_DTPREL16_LO = 75 +R_PPC_DTPREL16_HI = 76 +R_PPC_DTPREL16_HA = 77 +R_PPC_DTPREL32 = 78 +R_PPC_GOT_TLSGD16 = 79 +R_PPC_GOT_TLSGD16_LO = 80 +R_PPC_GOT_TLSGD16_HI = 81 +R_PPC_GOT_TLSGD16_HA = 82 +R_PPC_GOT_TLSLD16 = 83 +R_PPC_GOT_TLSLD16_LO = 84 +R_PPC_GOT_TLSLD16_HI = 85 +R_PPC_GOT_TLSLD16_HA = 86 +R_PPC_GOT_TPREL16 = 87 +R_PPC_GOT_TPREL16_LO = 88 +R_PPC_GOT_TPREL16_HI = 89 +R_PPC_GOT_TPREL16_HA = 90 +R_PPC_GOT_DTPREL16 = 91 +R_PPC_GOT_DTPREL16_LO = 92 +R_PPC_GOT_DTPREL16_HI = 93 +R_PPC_GOT_DTPREL16_HA = 94 +R_PPC_TLSGD = 95 +R_PPC_TLSLD = 96 +R_PPC_EMB_NADDR32 = 101 +R_PPC_EMB_NADDR16 = 102 +R_PPC_EMB_NADDR16_LO = 103 +R_PPC_EMB_NADDR16_HI = 104 +R_PPC_EMB_NADDR16_HA = 105 +R_PPC_EMB_SDAI16 = 106 +R_PPC_EMB_SDA2I16 = 107 +R_PPC_EMB_SDA2REL = 108 +R_PPC_EMB_SDA21 = 109 +R_PPC_EMB_MRKREF = 110 +R_PPC_EMB_RELSEC16 = 111 +R_PPC_EMB_RELST_LO = 112 +R_PPC_EMB_RELST_HI = 113 +R_PPC_EMB_RELST_HA = 114 +R_PPC_EMB_BIT_FLD = 115 +R_PPC_EMB_RELSDA = 116 +R_PPC_DIAB_SDA21_LO = 180 +R_PPC_DIAB_SDA21_HI = 181 +R_PPC_DIAB_SDA21_HA = 182 +R_PPC_DIAB_RELSDA_LO = 183 +R_PPC_DIAB_RELSDA_HI = 184 +R_PPC_DIAB_RELSDA_HA = 185 +R_PPC_IRELATIVE = 248 +R_PPC_REL16 = 249 +R_PPC_REL16_LO = 250 +R_PPC_REL16_HI = 251 +R_PPC_REL16_HA = 252 +R_PPC_TOC16 = 255 +DT_PPC_GOT = (DT_LOPROC + 0) +DT_PPC_OPT = (DT_LOPROC + 1) +DT_PPC_NUM = 2 +PPC_OPT_TLS = 1 +R_PPC64_NONE = R_PPC_NONE +R_PPC64_ADDR32 = R_PPC_ADDR32 +R_PPC64_ADDR24 = R_PPC_ADDR24 +R_PPC64_ADDR16 = R_PPC_ADDR16 +R_PPC64_ADDR16_LO = R_PPC_ADDR16_LO +R_PPC64_ADDR16_HI = R_PPC_ADDR16_HI +R_PPC64_ADDR16_HA = R_PPC_ADDR16_HA +R_PPC64_ADDR14 = R_PPC_ADDR14 +R_PPC64_ADDR14_BRTAKEN = R_PPC_ADDR14_BRTAKEN +R_PPC64_ADDR14_BRNTAKEN = R_PPC_ADDR14_BRNTAKEN +R_PPC64_REL24 = R_PPC_REL24 +R_PPC64_REL14 = R_PPC_REL14 +R_PPC64_REL14_BRTAKEN = R_PPC_REL14_BRTAKEN +R_PPC64_REL14_BRNTAKEN = R_PPC_REL14_BRNTAKEN +R_PPC64_GOT16 = R_PPC_GOT16 +R_PPC64_GOT16_LO = R_PPC_GOT16_LO +R_PPC64_GOT16_HI = R_PPC_GOT16_HI +R_PPC64_GOT16_HA = R_PPC_GOT16_HA +R_PPC64_COPY = R_PPC_COPY +R_PPC64_GLOB_DAT = R_PPC_GLOB_DAT +R_PPC64_JMP_SLOT = R_PPC_JMP_SLOT +R_PPC64_RELATIVE = R_PPC_RELATIVE +R_PPC64_UADDR32 = R_PPC_UADDR32 +R_PPC64_UADDR16 = R_PPC_UADDR16 +R_PPC64_REL32 = R_PPC_REL32 +R_PPC64_PLT32 = R_PPC_PLT32 +R_PPC64_PLTREL32 = R_PPC_PLTREL32 +R_PPC64_PLT16_LO = R_PPC_PLT16_LO +R_PPC64_PLT16_HI = R_PPC_PLT16_HI +R_PPC64_PLT16_HA = R_PPC_PLT16_HA +R_PPC64_SECTOFF = R_PPC_SECTOFF +R_PPC64_SECTOFF_LO = R_PPC_SECTOFF_LO +R_PPC64_SECTOFF_HI = R_PPC_SECTOFF_HI +R_PPC64_SECTOFF_HA = R_PPC_SECTOFF_HA +R_PPC64_ADDR30 = 37 +R_PPC64_ADDR64 = 38 +R_PPC64_ADDR16_HIGHER = 39 +R_PPC64_ADDR16_HIGHERA = 40 +R_PPC64_ADDR16_HIGHEST = 41 +R_PPC64_ADDR16_HIGHESTA = 42 +R_PPC64_UADDR64 = 43 +R_PPC64_REL64 = 44 +R_PPC64_PLT64 = 45 +R_PPC64_PLTREL64 = 46 +R_PPC64_TOC16 = 47 +R_PPC64_TOC16_LO = 48 +R_PPC64_TOC16_HI = 49 +R_PPC64_TOC16_HA = 50 +R_PPC64_TOC = 51 +R_PPC64_PLTGOT16 = 52 +R_PPC64_PLTGOT16_LO = 53 +R_PPC64_PLTGOT16_HI = 54 +R_PPC64_PLTGOT16_HA = 55 +R_PPC64_ADDR16_DS = 56 +R_PPC64_ADDR16_LO_DS = 57 +R_PPC64_GOT16_DS = 58 +R_PPC64_GOT16_LO_DS = 59 +R_PPC64_PLT16_LO_DS = 60 +R_PPC64_SECTOFF_DS = 61 +R_PPC64_SECTOFF_LO_DS = 62 +R_PPC64_TOC16_DS = 63 +R_PPC64_TOC16_LO_DS = 64 +R_PPC64_PLTGOT16_DS = 65 +R_PPC64_PLTGOT16_LO_DS = 66 +R_PPC64_TLS = 67 +R_PPC64_DTPMOD64 = 68 +R_PPC64_TPREL16 = 69 +R_PPC64_TPREL16_LO = 70 +R_PPC64_TPREL16_HI = 71 +R_PPC64_TPREL16_HA = 72 +R_PPC64_TPREL64 = 73 +R_PPC64_DTPREL16 = 74 +R_PPC64_DTPREL16_LO = 75 +R_PPC64_DTPREL16_HI = 76 +R_PPC64_DTPREL16_HA = 77 +R_PPC64_DTPREL64 = 78 +R_PPC64_GOT_TLSGD16 = 79 +R_PPC64_GOT_TLSGD16_LO = 80 +R_PPC64_GOT_TLSGD16_HI = 81 +R_PPC64_GOT_TLSGD16_HA = 82 +R_PPC64_GOT_TLSLD16 = 83 +R_PPC64_GOT_TLSLD16_LO = 84 +R_PPC64_GOT_TLSLD16_HI = 85 +R_PPC64_GOT_TLSLD16_HA = 86 +R_PPC64_GOT_TPREL16_DS = 87 +R_PPC64_GOT_TPREL16_LO_DS = 88 +R_PPC64_GOT_TPREL16_HI = 89 +R_PPC64_GOT_TPREL16_HA = 90 +R_PPC64_GOT_DTPREL16_DS = 91 +R_PPC64_GOT_DTPREL16_LO_DS = 92 +R_PPC64_GOT_DTPREL16_HI = 93 +R_PPC64_GOT_DTPREL16_HA = 94 +R_PPC64_TPREL16_DS = 95 +R_PPC64_TPREL16_LO_DS = 96 +R_PPC64_TPREL16_HIGHER = 97 +R_PPC64_TPREL16_HIGHERA = 98 +R_PPC64_TPREL16_HIGHEST = 99 +R_PPC64_TPREL16_HIGHESTA = 100 +R_PPC64_DTPREL16_DS = 101 +R_PPC64_DTPREL16_LO_DS = 102 +R_PPC64_DTPREL16_HIGHER = 103 +R_PPC64_DTPREL16_HIGHERA = 104 +R_PPC64_DTPREL16_HIGHEST = 105 +R_PPC64_DTPREL16_HIGHESTA = 106 +R_PPC64_TLSGD = 107 +R_PPC64_TLSLD = 108 +R_PPC64_TOCSAVE = 109 +R_PPC64_ADDR16_HIGH = 110 +R_PPC64_ADDR16_HIGHA = 111 +R_PPC64_TPREL16_HIGH = 112 +R_PPC64_TPREL16_HIGHA = 113 +R_PPC64_DTPREL16_HIGH = 114 +R_PPC64_DTPREL16_HIGHA = 115 +R_PPC64_JMP_IREL = 247 +R_PPC64_IRELATIVE = 248 +R_PPC64_REL16 = 249 +R_PPC64_REL16_LO = 250 +R_PPC64_REL16_HI = 251 +R_PPC64_REL16_HA = 252 +EF_PPC64_ABI = 3 +DT_PPC64_GLINK = (DT_LOPROC + 0) +DT_PPC64_OPD = (DT_LOPROC + 1) +DT_PPC64_OPDSZ = (DT_LOPROC + 2) +DT_PPC64_OPT = (DT_LOPROC + 3) +DT_PPC64_NUM = 4 +PPC64_OPT_TLS = 1 +PPC64_OPT_MULTI_TOC = 2 +PPC64_OPT_LOCALENTRY = 4 +STO_PPC64_LOCAL_BIT = 5 +STO_PPC64_LOCAL_MASK = (7 << STO_PPC64_LOCAL_BIT) +PPC64_LOCAL_ENTRY_OFFSET = lambda other: (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) +EF_ARM_RELEXEC = 0x01 +EF_ARM_HASENTRY = 0x02 +EF_ARM_INTERWORK = 0x04 +EF_ARM_APCS_26 = 0x08 +EF_ARM_APCS_FLOAT = 0x10 +EF_ARM_PIC = 0x20 +EF_ARM_ALIGN8 = 0x40 +EF_ARM_NEW_ABI = 0x80 +EF_ARM_OLD_ABI = 0x100 +EF_ARM_SOFT_FLOAT = 0x200 +EF_ARM_VFP_FLOAT = 0x400 +EF_ARM_MAVERICK_FLOAT = 0x800 +EF_ARM_ABI_FLOAT_SOFT = 0x200 +EF_ARM_ABI_FLOAT_HARD = 0x400 +EF_ARM_SYMSARESORTED = 0x04 +EF_ARM_DYNSYMSUSESEGIDX = 0x08 +EF_ARM_MAPSYMSFIRST = 0x10 +EF_ARM_EABIMASK = 0XFF000000 +EF_ARM_BE8 = 0x00800000 +EF_ARM_LE8 = 0x00400000 +EF_ARM_EABI_VERSION = lambda flags: ((flags) & EF_ARM_EABIMASK) +EF_ARM_EABI_UNKNOWN = 0x00000000 +EF_ARM_EABI_VER1 = 0x01000000 +EF_ARM_EABI_VER2 = 0x02000000 +EF_ARM_EABI_VER3 = 0x03000000 +EF_ARM_EABI_VER4 = 0x04000000 +EF_ARM_EABI_VER5 = 0x05000000 +STT_ARM_TFUNC = STT_LOPROC +STT_ARM_16BIT = STT_HIPROC +SHF_ARM_ENTRYSECT = 0x10000000 +SHF_ARM_COMDEF = 0x80000000 +PF_ARM_SB = 0x10000000 +PF_ARM_PI = 0x20000000 +PF_ARM_ABS = 0x40000000 +PT_ARM_EXIDX = (PT_LOPROC + 1) +SHT_ARM_EXIDX = (SHT_LOPROC + 1) +SHT_ARM_PREEMPTMAP = (SHT_LOPROC + 2) +SHT_ARM_ATTRIBUTES = (SHT_LOPROC + 3) +R_AARCH64_NONE = 0 +R_AARCH64_P32_ABS32 = 1 +R_AARCH64_P32_COPY = 180 +R_AARCH64_P32_GLOB_DAT = 181 +R_AARCH64_P32_JUMP_SLOT = 182 +R_AARCH64_P32_RELATIVE = 183 +R_AARCH64_P32_TLS_DTPMOD = 184 +R_AARCH64_P32_TLS_DTPREL = 185 +R_AARCH64_P32_TLS_TPREL = 186 +R_AARCH64_P32_TLSDESC = 187 +R_AARCH64_P32_IRELATIVE = 188 +R_AARCH64_ABS64 = 257 +R_AARCH64_ABS32 = 258 +R_AARCH64_ABS16 = 259 +R_AARCH64_PREL64 = 260 +R_AARCH64_PREL32 = 261 +R_AARCH64_PREL16 = 262 +R_AARCH64_MOVW_UABS_G0 = 263 +R_AARCH64_MOVW_UABS_G0_NC = 264 +R_AARCH64_MOVW_UABS_G1 = 265 +R_AARCH64_MOVW_UABS_G1_NC = 266 +R_AARCH64_MOVW_UABS_G2 = 267 +R_AARCH64_MOVW_UABS_G2_NC = 268 +R_AARCH64_MOVW_UABS_G3 = 269 +R_AARCH64_MOVW_SABS_G0 = 270 +R_AARCH64_MOVW_SABS_G1 = 271 +R_AARCH64_MOVW_SABS_G2 = 272 +R_AARCH64_LD_PREL_LO19 = 273 +R_AARCH64_ADR_PREL_LO21 = 274 +R_AARCH64_ADR_PREL_PG_HI21 = 275 +R_AARCH64_ADR_PREL_PG_HI21_NC = 276 +R_AARCH64_ADD_ABS_LO12_NC = 277 +R_AARCH64_LDST8_ABS_LO12_NC = 278 +R_AARCH64_TSTBR14 = 279 +R_AARCH64_CONDBR19 = 280 +R_AARCH64_JUMP26 = 282 +R_AARCH64_CALL26 = 283 +R_AARCH64_LDST16_ABS_LO12_NC = 284 +R_AARCH64_LDST32_ABS_LO12_NC = 285 +R_AARCH64_LDST64_ABS_LO12_NC = 286 +R_AARCH64_MOVW_PREL_G0 = 287 +R_AARCH64_MOVW_PREL_G0_NC = 288 +R_AARCH64_MOVW_PREL_G1 = 289 +R_AARCH64_MOVW_PREL_G1_NC = 290 +R_AARCH64_MOVW_PREL_G2 = 291 +R_AARCH64_MOVW_PREL_G2_NC = 292 +R_AARCH64_MOVW_PREL_G3 = 293 +R_AARCH64_LDST128_ABS_LO12_NC = 299 +R_AARCH64_MOVW_GOTOFF_G0 = 300 +R_AARCH64_MOVW_GOTOFF_G0_NC = 301 +R_AARCH64_MOVW_GOTOFF_G1 = 302 +R_AARCH64_MOVW_GOTOFF_G1_NC = 303 +R_AARCH64_MOVW_GOTOFF_G2 = 304 +R_AARCH64_MOVW_GOTOFF_G2_NC = 305 +R_AARCH64_MOVW_GOTOFF_G3 = 306 +R_AARCH64_GOTREL64 = 307 +R_AARCH64_GOTREL32 = 308 +R_AARCH64_GOT_LD_PREL19 = 309 +R_AARCH64_LD64_GOTOFF_LO15 = 310 +R_AARCH64_ADR_GOT_PAGE = 311 +R_AARCH64_LD64_GOT_LO12_NC = 312 +R_AARCH64_LD64_GOTPAGE_LO15 = 313 +R_AARCH64_TLSGD_ADR_PREL21 = 512 +R_AARCH64_TLSGD_ADR_PAGE21 = 513 +R_AARCH64_TLSGD_ADD_LO12_NC = 514 +R_AARCH64_TLSGD_MOVW_G1 = 515 +R_AARCH64_TLSGD_MOVW_G0_NC = 516 +R_AARCH64_TLSLD_ADR_PREL21 = 517 +R_AARCH64_TLSLD_ADR_PAGE21 = 518 +R_AARCH64_TLSLD_ADD_LO12_NC = 519 +R_AARCH64_TLSLD_MOVW_G1 = 520 +R_AARCH64_TLSLD_MOVW_G0_NC = 521 +R_AARCH64_TLSLD_LD_PREL19 = 522 +R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523 +R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524 +R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525 +R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526 +R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527 +R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528 +R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529 +R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530 +R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531 +R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532 +R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533 +R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534 +R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535 +R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536 +R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537 +R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538 +R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539 +R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540 +R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541 +R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542 +R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543 +R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544 +R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545 +R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546 +R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547 +R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548 +R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549 +R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550 +R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551 +R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552 +R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553 +R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554 +R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555 +R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556 +R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557 +R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558 +R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559 +R_AARCH64_TLSDESC_LD_PREL19 = 560 +R_AARCH64_TLSDESC_ADR_PREL21 = 561 +R_AARCH64_TLSDESC_ADR_PAGE21 = 562 +R_AARCH64_TLSDESC_LD64_LO12 = 563 +R_AARCH64_TLSDESC_ADD_LO12 = 564 +R_AARCH64_TLSDESC_OFF_G1 = 565 +R_AARCH64_TLSDESC_OFF_G0_NC = 566 +R_AARCH64_TLSDESC_LDR = 567 +R_AARCH64_TLSDESC_ADD = 568 +R_AARCH64_TLSDESC_CALL = 569 +R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570 +R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571 +R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572 +R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573 +R_AARCH64_COPY = 1024 +R_AARCH64_GLOB_DAT = 1025 +R_AARCH64_JUMP_SLOT = 1026 +R_AARCH64_RELATIVE = 1027 +R_AARCH64_TLS_DTPMOD = 1028 +R_AARCH64_TLS_DTPREL = 1029 +R_AARCH64_TLS_TPREL = 1030 +R_AARCH64_TLSDESC = 1031 +R_AARCH64_IRELATIVE = 1032 +PT_AARCH64_MEMTAG_MTE = (PT_LOPROC + 2) +DT_AARCH64_BTI_PLT = (DT_LOPROC + 1) +DT_AARCH64_PAC_PLT = (DT_LOPROC + 3) +DT_AARCH64_VARIANT_PCS = (DT_LOPROC + 5) +DT_AARCH64_NUM = 6 +STO_AARCH64_VARIANT_PCS = 0x80 +R_ARM_NONE = 0 +R_ARM_PC24 = 1 +R_ARM_ABS32 = 2 +R_ARM_REL32 = 3 +R_ARM_PC13 = 4 +R_ARM_ABS16 = 5 +R_ARM_ABS12 = 6 +R_ARM_THM_ABS5 = 7 +R_ARM_ABS8 = 8 +R_ARM_SBREL32 = 9 +R_ARM_THM_PC22 = 10 +R_ARM_THM_PC8 = 11 +R_ARM_AMP_VCALL9 = 12 +R_ARM_SWI24 = 13 +R_ARM_TLS_DESC = 13 +R_ARM_THM_SWI8 = 14 +R_ARM_XPC25 = 15 +R_ARM_THM_XPC22 = 16 +R_ARM_TLS_DTPMOD32 = 17 +R_ARM_TLS_DTPOFF32 = 18 +R_ARM_TLS_TPOFF32 = 19 +R_ARM_COPY = 20 +R_ARM_GLOB_DAT = 21 +R_ARM_JUMP_SLOT = 22 +R_ARM_RELATIVE = 23 +R_ARM_GOTOFF = 24 +R_ARM_GOTPC = 25 +R_ARM_GOT32 = 26 +R_ARM_PLT32 = 27 +R_ARM_CALL = 28 +R_ARM_JUMP24 = 29 +R_ARM_THM_JUMP24 = 30 +R_ARM_BASE_ABS = 31 +R_ARM_ALU_PCREL_7_0 = 32 +R_ARM_ALU_PCREL_15_8 = 33 +R_ARM_ALU_PCREL_23_15 = 34 +R_ARM_LDR_SBREL_11_0 = 35 +R_ARM_ALU_SBREL_19_12 = 36 +R_ARM_ALU_SBREL_27_20 = 37 +R_ARM_TARGET1 = 38 +R_ARM_SBREL31 = 39 +R_ARM_V4BX = 40 +R_ARM_TARGET2 = 41 +R_ARM_PREL31 = 42 +R_ARM_MOVW_ABS_NC = 43 +R_ARM_MOVT_ABS = 44 +R_ARM_MOVW_PREL_NC = 45 +R_ARM_MOVT_PREL = 46 +R_ARM_THM_MOVW_ABS_NC = 47 +R_ARM_THM_MOVT_ABS = 48 +R_ARM_THM_MOVW_PREL_NC = 49 +R_ARM_THM_MOVT_PREL = 50 +R_ARM_THM_JUMP19 = 51 +R_ARM_THM_JUMP6 = 52 +R_ARM_THM_ALU_PREL_11_0 = 53 +R_ARM_THM_PC12 = 54 +R_ARM_ABS32_NOI = 55 +R_ARM_REL32_NOI = 56 +R_ARM_ALU_PC_G0_NC = 57 +R_ARM_ALU_PC_G0 = 58 +R_ARM_ALU_PC_G1_NC = 59 +R_ARM_ALU_PC_G1 = 60 +R_ARM_ALU_PC_G2 = 61 +R_ARM_LDR_PC_G1 = 62 +R_ARM_LDR_PC_G2 = 63 +R_ARM_LDRS_PC_G0 = 64 +R_ARM_LDRS_PC_G1 = 65 +R_ARM_LDRS_PC_G2 = 66 +R_ARM_LDC_PC_G0 = 67 +R_ARM_LDC_PC_G1 = 68 +R_ARM_LDC_PC_G2 = 69 +R_ARM_ALU_SB_G0_NC = 70 +R_ARM_ALU_SB_G0 = 71 +R_ARM_ALU_SB_G1_NC = 72 +R_ARM_ALU_SB_G1 = 73 +R_ARM_ALU_SB_G2 = 74 +R_ARM_LDR_SB_G0 = 75 +R_ARM_LDR_SB_G1 = 76 +R_ARM_LDR_SB_G2 = 77 +R_ARM_LDRS_SB_G0 = 78 +R_ARM_LDRS_SB_G1 = 79 +R_ARM_LDRS_SB_G2 = 80 +R_ARM_LDC_SB_G0 = 81 +R_ARM_LDC_SB_G1 = 82 +R_ARM_LDC_SB_G2 = 83 +R_ARM_MOVW_BREL_NC = 84 +R_ARM_MOVT_BREL = 85 +R_ARM_MOVW_BREL = 86 +R_ARM_THM_MOVW_BREL_NC = 87 +R_ARM_THM_MOVT_BREL = 88 +R_ARM_THM_MOVW_BREL = 89 +R_ARM_TLS_GOTDESC = 90 +R_ARM_TLS_CALL = 91 +R_ARM_TLS_DESCSEQ = 92 +R_ARM_THM_TLS_CALL = 93 +R_ARM_PLT32_ABS = 94 +R_ARM_GOT_ABS = 95 +R_ARM_GOT_PREL = 96 +R_ARM_GOT_BREL12 = 97 +R_ARM_GOTOFF12 = 98 +R_ARM_GOTRELAX = 99 +R_ARM_GNU_VTENTRY = 100 +R_ARM_GNU_VTINHERIT = 101 +R_ARM_THM_PC11 = 102 +R_ARM_THM_PC9 = 103 +R_ARM_TLS_GD32 = 104 +R_ARM_TLS_LDM32 = 105 +R_ARM_TLS_LDO32 = 106 +R_ARM_TLS_IE32 = 107 +R_ARM_TLS_LE32 = 108 +R_ARM_TLS_LDO12 = 109 +R_ARM_TLS_LE12 = 110 +R_ARM_TLS_IE12GP = 111 +R_ARM_ME_TOO = 128 +R_ARM_THM_TLS_DESCSEQ = 129 +R_ARM_THM_TLS_DESCSEQ16 = 129 +R_ARM_THM_TLS_DESCSEQ32 = 130 +R_ARM_THM_GOT_BREL12 = 131 +R_ARM_IRELATIVE = 160 +R_ARM_RXPC25 = 249 +R_ARM_RSBREL32 = 250 +R_ARM_THM_RPC22 = 251 +R_ARM_RREL32 = 252 +R_ARM_RABS22 = 253 +R_ARM_RPC24 = 254 +R_ARM_RBASE = 255 +R_ARM_NUM = 256 +R_CKCORE_NONE = 0 +R_CKCORE_ADDR32 = 1 +R_CKCORE_PCRELIMM8BY4 = 2 +R_CKCORE_PCRELIMM11BY2 = 3 +R_CKCORE_PCREL32 = 5 +R_CKCORE_PCRELJSR_IMM11BY2 = 6 +R_CKCORE_RELATIVE = 9 +R_CKCORE_COPY = 10 +R_CKCORE_GLOB_DAT = 11 +R_CKCORE_JUMP_SLOT = 12 +R_CKCORE_GOTOFF = 13 +R_CKCORE_GOTPC = 14 +R_CKCORE_GOT32 = 15 +R_CKCORE_PLT32 = 16 +R_CKCORE_ADDRGOT = 17 +R_CKCORE_ADDRPLT = 18 +R_CKCORE_PCREL_IMM26BY2 = 19 +R_CKCORE_PCREL_IMM16BY2 = 20 +R_CKCORE_PCREL_IMM16BY4 = 21 +R_CKCORE_PCREL_IMM10BY2 = 22 +R_CKCORE_PCREL_IMM10BY4 = 23 +R_CKCORE_ADDR_HI16 = 24 +R_CKCORE_ADDR_LO16 = 25 +R_CKCORE_GOTPC_HI16 = 26 +R_CKCORE_GOTPC_LO16 = 27 +R_CKCORE_GOTOFF_HI16 = 28 +R_CKCORE_GOTOFF_LO16 = 29 +R_CKCORE_GOT12 = 30 +R_CKCORE_GOT_HI16 = 31 +R_CKCORE_GOT_LO16 = 32 +R_CKCORE_PLT12 = 33 +R_CKCORE_PLT_HI16 = 34 +R_CKCORE_PLT_LO16 = 35 +R_CKCORE_ADDRGOT_HI16 = 36 +R_CKCORE_ADDRGOT_LO16 = 37 +R_CKCORE_ADDRPLT_HI16 = 38 +R_CKCORE_ADDRPLT_LO16 = 39 +R_CKCORE_PCREL_JSR_IMM26BY2 = 40 +R_CKCORE_TOFFSET_LO16 = 41 +R_CKCORE_DOFFSET_LO16 = 42 +R_CKCORE_PCREL_IMM18BY2 = 43 +R_CKCORE_DOFFSET_IMM18 = 44 +R_CKCORE_DOFFSET_IMM18BY2 = 45 +R_CKCORE_DOFFSET_IMM18BY4 = 46 +R_CKCORE_GOT_IMM18BY4 = 48 +R_CKCORE_PLT_IMM18BY4 = 49 +R_CKCORE_PCREL_IMM7BY4 = 50 +R_CKCORE_TLS_LE32 = 51 +R_CKCORE_TLS_IE32 = 52 +R_CKCORE_TLS_GD32 = 53 +R_CKCORE_TLS_LDM32 = 54 +R_CKCORE_TLS_LDO32 = 55 +R_CKCORE_TLS_DTPMOD32 = 56 +R_CKCORE_TLS_DTPOFF32 = 57 +R_CKCORE_TLS_TPOFF32 = 58 +EF_CSKY_ABIMASK = 0XF0000000 +EF_CSKY_OTHER = 0X0FFF0000 +EF_CSKY_PROCESSOR = 0X0000FFFF +EF_CSKY_ABIV1 = 0X10000000 +EF_CSKY_ABIV2 = 0X20000000 +SHT_CSKY_ATTRIBUTES = (SHT_LOPROC + 1) +EF_IA_64_MASKOS = 0x0000000f +EF_IA_64_ABI64 = 0x00000010 +EF_IA_64_ARCH = 0xff000000 +PT_IA_64_ARCHEXT = (PT_LOPROC + 0) +PT_IA_64_UNWIND = (PT_LOPROC + 1) +PT_IA_64_HP_OPT_ANOT = (PT_LOOS + 0x12) +PT_IA_64_HP_HSL_ANOT = (PT_LOOS + 0x13) +PT_IA_64_HP_STACK = (PT_LOOS + 0x14) +PF_IA_64_NORECOV = 0x80000000 +SHT_IA_64_EXT = (SHT_LOPROC + 0) +SHT_IA_64_UNWIND = (SHT_LOPROC + 1) +SHF_IA_64_SHORT = 0x10000000 +SHF_IA_64_NORECOV = 0x20000000 +DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0) +DT_IA_64_NUM = 1 +R_IA64_NONE = 0x00 +R_IA64_IMM14 = 0x21 +R_IA64_IMM22 = 0x22 +R_IA64_IMM64 = 0x23 +R_IA64_DIR32MSB = 0x24 +R_IA64_DIR32LSB = 0x25 +R_IA64_DIR64MSB = 0x26 +R_IA64_DIR64LSB = 0x27 +R_IA64_GPREL22 = 0x2a +R_IA64_GPREL64I = 0x2b +R_IA64_GPREL32MSB = 0x2c +R_IA64_GPREL32LSB = 0x2d +R_IA64_GPREL64MSB = 0x2e +R_IA64_GPREL64LSB = 0x2f +R_IA64_LTOFF22 = 0x32 +R_IA64_LTOFF64I = 0x33 +R_IA64_PLTOFF22 = 0x3a +R_IA64_PLTOFF64I = 0x3b +R_IA64_PLTOFF64MSB = 0x3e +R_IA64_PLTOFF64LSB = 0x3f +R_IA64_FPTR64I = 0x43 +R_IA64_FPTR32MSB = 0x44 +R_IA64_FPTR32LSB = 0x45 +R_IA64_FPTR64MSB = 0x46 +R_IA64_FPTR64LSB = 0x47 +R_IA64_PCREL60B = 0x48 +R_IA64_PCREL21B = 0x49 +R_IA64_PCREL21M = 0x4a +R_IA64_PCREL21F = 0x4b +R_IA64_PCREL32MSB = 0x4c +R_IA64_PCREL32LSB = 0x4d +R_IA64_PCREL64MSB = 0x4e +R_IA64_PCREL64LSB = 0x4f +R_IA64_LTOFF_FPTR22 = 0x52 +R_IA64_LTOFF_FPTR64I = 0x53 +R_IA64_LTOFF_FPTR32MSB = 0x54 +R_IA64_LTOFF_FPTR32LSB = 0x55 +R_IA64_LTOFF_FPTR64MSB = 0x56 +R_IA64_LTOFF_FPTR64LSB = 0x57 +R_IA64_SEGREL32MSB = 0x5c +R_IA64_SEGREL32LSB = 0x5d +R_IA64_SEGREL64MSB = 0x5e +R_IA64_SEGREL64LSB = 0x5f +R_IA64_SECREL32MSB = 0x64 +R_IA64_SECREL32LSB = 0x65 +R_IA64_SECREL64MSB = 0x66 +R_IA64_SECREL64LSB = 0x67 +R_IA64_REL32MSB = 0x6c +R_IA64_REL32LSB = 0x6d +R_IA64_REL64MSB = 0x6e +R_IA64_REL64LSB = 0x6f +R_IA64_LTV32MSB = 0x74 +R_IA64_LTV32LSB = 0x75 +R_IA64_LTV64MSB = 0x76 +R_IA64_LTV64LSB = 0x77 +R_IA64_PCREL21BI = 0x79 +R_IA64_PCREL22 = 0x7a +R_IA64_PCREL64I = 0x7b +R_IA64_IPLTMSB = 0x80 +R_IA64_IPLTLSB = 0x81 +R_IA64_COPY = 0x84 +R_IA64_SUB = 0x85 +R_IA64_LTOFF22X = 0x86 +R_IA64_LDXMOV = 0x87 +R_IA64_TPREL14 = 0x91 +R_IA64_TPREL22 = 0x92 +R_IA64_TPREL64I = 0x93 +R_IA64_TPREL64MSB = 0x96 +R_IA64_TPREL64LSB = 0x97 +R_IA64_LTOFF_TPREL22 = 0x9a +R_IA64_DTPMOD64MSB = 0xa6 +R_IA64_DTPMOD64LSB = 0xa7 +R_IA64_LTOFF_DTPMOD22 = 0xaa +R_IA64_DTPREL14 = 0xb1 +R_IA64_DTPREL22 = 0xb2 +R_IA64_DTPREL64I = 0xb3 +R_IA64_DTPREL32MSB = 0xb4 +R_IA64_DTPREL32LSB = 0xb5 +R_IA64_DTPREL64MSB = 0xb6 +R_IA64_DTPREL64LSB = 0xb7 +R_IA64_LTOFF_DTPREL22 = 0xba +EF_SH_MACH_MASK = 0x1f +EF_SH_UNKNOWN = 0x0 +EF_SH1 = 0x1 +EF_SH2 = 0x2 +EF_SH3 = 0x3 +EF_SH_DSP = 0x4 +EF_SH3_DSP = 0x5 +EF_SH4AL_DSP = 0x6 +EF_SH3E = 0x8 +EF_SH4 = 0x9 +EF_SH2E = 0xb +EF_SH4A = 0xc +EF_SH2A = 0xd +EF_SH4_NOFPU = 0x10 +EF_SH4A_NOFPU = 0x11 +EF_SH4_NOMMU_NOFPU = 0x12 +EF_SH2A_NOFPU = 0x13 +EF_SH3_NOMMU = 0x14 +EF_SH2A_SH4_NOFPU = 0x15 +EF_SH2A_SH3_NOFPU = 0x16 +EF_SH2A_SH4 = 0x17 +EF_SH2A_SH3E = 0x18 +R_SH_NONE = 0 +R_SH_DIR32 = 1 +R_SH_REL32 = 2 +R_SH_DIR8WPN = 3 +R_SH_IND12W = 4 +R_SH_DIR8WPL = 5 +R_SH_DIR8WPZ = 6 +R_SH_DIR8BP = 7 +R_SH_DIR8W = 8 +R_SH_DIR8L = 9 +R_SH_SWITCH16 = 25 +R_SH_SWITCH32 = 26 +R_SH_USES = 27 +R_SH_COUNT = 28 +R_SH_ALIGN = 29 +R_SH_CODE = 30 +R_SH_DATA = 31 +R_SH_LABEL = 32 +R_SH_SWITCH8 = 33 +R_SH_GNU_VTINHERIT = 34 +R_SH_GNU_VTENTRY = 35 +R_SH_TLS_GD_32 = 144 +R_SH_TLS_LD_32 = 145 +R_SH_TLS_LDO_32 = 146 +R_SH_TLS_IE_32 = 147 +R_SH_TLS_LE_32 = 148 +R_SH_TLS_DTPMOD32 = 149 +R_SH_TLS_DTPOFF32 = 150 +R_SH_TLS_TPOFF32 = 151 +R_SH_GOT32 = 160 +R_SH_PLT32 = 161 +R_SH_COPY = 162 +R_SH_GLOB_DAT = 163 +R_SH_JMP_SLOT = 164 +R_SH_RELATIVE = 165 +R_SH_GOTOFF = 166 +R_SH_GOTPC = 167 +R_SH_NUM = 256 +EF_S390_HIGH_GPRS = 0x00000001 +R_390_NONE = 0 +R_390_8 = 1 +R_390_12 = 2 +R_390_16 = 3 +R_390_32 = 4 +R_390_PC32 = 5 +R_390_GOT12 = 6 +R_390_GOT32 = 7 +R_390_PLT32 = 8 +R_390_COPY = 9 +R_390_GLOB_DAT = 10 +R_390_JMP_SLOT = 11 +R_390_RELATIVE = 12 +R_390_GOTOFF32 = 13 +R_390_GOTPC = 14 +R_390_GOT16 = 15 +R_390_PC16 = 16 +R_390_PC16DBL = 17 +R_390_PLT16DBL = 18 +R_390_PC32DBL = 19 +R_390_PLT32DBL = 20 +R_390_GOTPCDBL = 21 +R_390_64 = 22 +R_390_PC64 = 23 +R_390_GOT64 = 24 +R_390_PLT64 = 25 +R_390_GOTENT = 26 +R_390_GOTOFF16 = 27 +R_390_GOTOFF64 = 28 +R_390_GOTPLT12 = 29 +R_390_GOTPLT16 = 30 +R_390_GOTPLT32 = 31 +R_390_GOTPLT64 = 32 +R_390_GOTPLTENT = 33 +R_390_PLTOFF16 = 34 +R_390_PLTOFF32 = 35 +R_390_PLTOFF64 = 36 +R_390_TLS_LOAD = 37 +R_390_TLS_GDCALL = 38 +R_390_TLS_LDCALL = 39 +R_390_TLS_GD32 = 40 +R_390_TLS_GD64 = 41 +R_390_TLS_GOTIE12 = 42 +R_390_TLS_GOTIE32 = 43 +R_390_TLS_GOTIE64 = 44 +R_390_TLS_LDM32 = 45 +R_390_TLS_LDM64 = 46 +R_390_TLS_IE32 = 47 +R_390_TLS_IE64 = 48 +R_390_TLS_IEENT = 49 +R_390_TLS_LE32 = 50 +R_390_TLS_LE64 = 51 +R_390_TLS_LDO32 = 52 +R_390_TLS_LDO64 = 53 +R_390_TLS_DTPMOD = 54 +R_390_TLS_DTPOFF = 55 +R_390_TLS_TPOFF = 56 +R_390_20 = 57 +R_390_GOT20 = 58 +R_390_GOTPLT20 = 59 +R_390_TLS_GOTIE20 = 60 +R_390_IRELATIVE = 61 +R_390_NUM = 62 +R_CRIS_NONE = 0 +R_CRIS_8 = 1 +R_CRIS_16 = 2 +R_CRIS_32 = 3 +R_CRIS_8_PCREL = 4 +R_CRIS_16_PCREL = 5 +R_CRIS_32_PCREL = 6 +R_CRIS_GNU_VTINHERIT = 7 +R_CRIS_GNU_VTENTRY = 8 +R_CRIS_COPY = 9 +R_CRIS_GLOB_DAT = 10 +R_CRIS_JUMP_SLOT = 11 +R_CRIS_RELATIVE = 12 +R_CRIS_16_GOT = 13 +R_CRIS_32_GOT = 14 +R_CRIS_16_GOTPLT = 15 +R_CRIS_32_GOTPLT = 16 +R_CRIS_32_GOTREL = 17 +R_CRIS_32_PLT_GOTREL = 18 +R_CRIS_32_PLT_PCREL = 19 +R_CRIS_NUM = 20 +R_X86_64_NONE = 0 +R_X86_64_64 = 1 +R_X86_64_PC32 = 2 +R_X86_64_GOT32 = 3 +R_X86_64_PLT32 = 4 +R_X86_64_COPY = 5 +R_X86_64_GLOB_DAT = 6 +R_X86_64_JUMP_SLOT = 7 +R_X86_64_RELATIVE = 8 +R_X86_64_GOTPCREL = 9 +R_X86_64_32 = 10 +R_X86_64_32S = 11 +R_X86_64_16 = 12 +R_X86_64_PC16 = 13 +R_X86_64_8 = 14 +R_X86_64_PC8 = 15 +R_X86_64_DTPMOD64 = 16 +R_X86_64_DTPOFF64 = 17 +R_X86_64_TPOFF64 = 18 +R_X86_64_TLSGD = 19 +R_X86_64_TLSLD = 20 +R_X86_64_DTPOFF32 = 21 +R_X86_64_GOTTPOFF = 22 +R_X86_64_TPOFF32 = 23 +R_X86_64_PC64 = 24 +R_X86_64_GOTOFF64 = 25 +R_X86_64_GOTPC32 = 26 +R_X86_64_GOT64 = 27 +R_X86_64_GOTPCREL64 = 28 +R_X86_64_GOTPC64 = 29 +R_X86_64_GOTPLT64 = 30 +R_X86_64_PLTOFF64 = 31 +R_X86_64_SIZE32 = 32 +R_X86_64_SIZE64 = 33 +R_X86_64_GOTPC32_TLSDESC = 34 +R_X86_64_TLSDESC_CALL = 35 +R_X86_64_TLSDESC = 36 +R_X86_64_IRELATIVE = 37 +R_X86_64_RELATIVE64 = 38 +R_X86_64_GOTPCRELX = 41 +R_X86_64_REX_GOTPCRELX = 42 +R_X86_64_NUM = 43 +SHT_X86_64_UNWIND = 0x70000001 +DT_X86_64_PLT = (DT_LOPROC + 0) +DT_X86_64_PLTSZ = (DT_LOPROC + 1) +DT_X86_64_PLTENT = (DT_LOPROC + 3) +DT_X86_64_NUM = 4 +R_MN10300_NONE = 0 +R_MN10300_32 = 1 +R_MN10300_16 = 2 +R_MN10300_8 = 3 +R_MN10300_PCREL32 = 4 +R_MN10300_PCREL16 = 5 +R_MN10300_PCREL8 = 6 +R_MN10300_GNU_VTINHERIT = 7 +R_MN10300_GNU_VTENTRY = 8 +R_MN10300_24 = 9 +R_MN10300_GOTPC32 = 10 +R_MN10300_GOTPC16 = 11 +R_MN10300_GOTOFF32 = 12 +R_MN10300_GOTOFF24 = 13 +R_MN10300_GOTOFF16 = 14 +R_MN10300_PLT32 = 15 +R_MN10300_PLT16 = 16 +R_MN10300_GOT32 = 17 +R_MN10300_GOT24 = 18 +R_MN10300_GOT16 = 19 +R_MN10300_COPY = 20 +R_MN10300_GLOB_DAT = 21 +R_MN10300_JMP_SLOT = 22 +R_MN10300_RELATIVE = 23 +R_MN10300_TLS_GD = 24 +R_MN10300_TLS_LD = 25 +R_MN10300_TLS_LDO = 26 +R_MN10300_TLS_GOTIE = 27 +R_MN10300_TLS_IE = 28 +R_MN10300_TLS_LE = 29 +R_MN10300_TLS_DTPMOD = 30 +R_MN10300_TLS_DTPOFF = 31 +R_MN10300_TLS_TPOFF = 32 +R_MN10300_SYM_DIFF = 33 +R_MN10300_ALIGN = 34 +R_MN10300_NUM = 35 +R_M32R_NONE = 0 +R_M32R_16 = 1 +R_M32R_32 = 2 +R_M32R_24 = 3 +R_M32R_10_PCREL = 4 +R_M32R_18_PCREL = 5 +R_M32R_26_PCREL = 6 +R_M32R_HI16_ULO = 7 +R_M32R_HI16_SLO = 8 +R_M32R_LO16 = 9 +R_M32R_SDA16 = 10 +R_M32R_GNU_VTINHERIT = 11 +R_M32R_GNU_VTENTRY = 12 +R_M32R_16_RELA = 33 +R_M32R_32_RELA = 34 +R_M32R_24_RELA = 35 +R_M32R_10_PCREL_RELA = 36 +R_M32R_18_PCREL_RELA = 37 +R_M32R_26_PCREL_RELA = 38 +R_M32R_HI16_ULO_RELA = 39 +R_M32R_HI16_SLO_RELA = 40 +R_M32R_LO16_RELA = 41 +R_M32R_SDA16_RELA = 42 +R_M32R_RELA_GNU_VTINHERIT = 43 +R_M32R_RELA_GNU_VTENTRY = 44 +R_M32R_REL32 = 45 +R_M32R_GOT24 = 48 +R_M32R_26_PLTREL = 49 +R_M32R_COPY = 50 +R_M32R_GLOB_DAT = 51 +R_M32R_JMP_SLOT = 52 +R_M32R_RELATIVE = 53 +R_M32R_GOTOFF = 54 +R_M32R_GOTPC24 = 55 +R_M32R_GOT16_HI_ULO = 56 +R_M32R_GOT16_HI_SLO = 57 +R_M32R_GOT16_LO = 58 +R_M32R_GOTPC_HI_ULO = 59 +R_M32R_GOTPC_HI_SLO = 60 +R_M32R_GOTPC_LO = 61 +R_M32R_GOTOFF_HI_ULO = 62 +R_M32R_GOTOFF_HI_SLO = 63 +R_M32R_GOTOFF_LO = 64 +R_M32R_NUM = 256 +R_MICROBLAZE_NONE = 0 +R_MICROBLAZE_32 = 1 +R_MICROBLAZE_32_PCREL = 2 +R_MICROBLAZE_64_PCREL = 3 +R_MICROBLAZE_32_PCREL_LO = 4 +R_MICROBLAZE_64 = 5 +R_MICROBLAZE_32_LO = 6 +R_MICROBLAZE_SRO32 = 7 +R_MICROBLAZE_SRW32 = 8 +R_MICROBLAZE_64_NONE = 9 +R_MICROBLAZE_32_SYM_OP_SYM = 10 +R_MICROBLAZE_GNU_VTINHERIT = 11 +R_MICROBLAZE_GNU_VTENTRY = 12 +R_MICROBLAZE_GOTPC_64 = 13 +R_MICROBLAZE_GOT_64 = 14 +R_MICROBLAZE_PLT_64 = 15 +R_MICROBLAZE_REL = 16 +R_MICROBLAZE_JUMP_SLOT = 17 +R_MICROBLAZE_GLOB_DAT = 18 +R_MICROBLAZE_GOTOFF_64 = 19 +R_MICROBLAZE_GOTOFF_32 = 20 +R_MICROBLAZE_COPY = 21 +R_MICROBLAZE_TLS = 22 +R_MICROBLAZE_TLSGD = 23 +R_MICROBLAZE_TLSLD = 24 +R_MICROBLAZE_TLSDTPMOD32 = 25 +R_MICROBLAZE_TLSDTPREL32 = 26 +R_MICROBLAZE_TLSDTPREL64 = 27 +R_MICROBLAZE_TLSGOTTPREL32 = 28 +R_MICROBLAZE_TLSTPREL32 = 29 +DT_NIOS2_GP = 0x70000002 +R_NIOS2_NONE = 0 +R_NIOS2_S16 = 1 +R_NIOS2_U16 = 2 +R_NIOS2_PCREL16 = 3 +R_NIOS2_CALL26 = 4 +R_NIOS2_IMM5 = 5 +R_NIOS2_CACHE_OPX = 6 +R_NIOS2_IMM6 = 7 +R_NIOS2_IMM8 = 8 +R_NIOS2_HI16 = 9 +R_NIOS2_LO16 = 10 +R_NIOS2_HIADJ16 = 11 +R_NIOS2_BFD_RELOC_32 = 12 +R_NIOS2_BFD_RELOC_16 = 13 +R_NIOS2_BFD_RELOC_8 = 14 +R_NIOS2_GPREL = 15 +R_NIOS2_GNU_VTINHERIT = 16 +R_NIOS2_GNU_VTENTRY = 17 +R_NIOS2_UJMP = 18 +R_NIOS2_CJMP = 19 +R_NIOS2_CALLR = 20 +R_NIOS2_ALIGN = 21 +R_NIOS2_GOT16 = 22 +R_NIOS2_CALL16 = 23 +R_NIOS2_GOTOFF_LO = 24 +R_NIOS2_GOTOFF_HA = 25 +R_NIOS2_PCREL_LO = 26 +R_NIOS2_PCREL_HA = 27 +R_NIOS2_TLS_GD16 = 28 +R_NIOS2_TLS_LDM16 = 29 +R_NIOS2_TLS_LDO16 = 30 +R_NIOS2_TLS_IE16 = 31 +R_NIOS2_TLS_LE16 = 32 +R_NIOS2_TLS_DTPMOD = 33 +R_NIOS2_TLS_DTPREL = 34 +R_NIOS2_TLS_TPREL = 35 +R_NIOS2_COPY = 36 +R_NIOS2_GLOB_DAT = 37 +R_NIOS2_JUMP_SLOT = 38 +R_NIOS2_RELATIVE = 39 +R_NIOS2_GOTOFF = 40 +R_NIOS2_CALL26_NOAT = 41 +R_NIOS2_GOT_LO = 42 +R_NIOS2_GOT_HA = 43 +R_NIOS2_CALL_LO = 44 +R_NIOS2_CALL_HA = 45 +R_TILEPRO_NONE = 0 +R_TILEPRO_32 = 1 +R_TILEPRO_16 = 2 +R_TILEPRO_8 = 3 +R_TILEPRO_32_PCREL = 4 +R_TILEPRO_16_PCREL = 5 +R_TILEPRO_8_PCREL = 6 +R_TILEPRO_LO16 = 7 +R_TILEPRO_HI16 = 8 +R_TILEPRO_HA16 = 9 +R_TILEPRO_COPY = 10 +R_TILEPRO_GLOB_DAT = 11 +R_TILEPRO_JMP_SLOT = 12 +R_TILEPRO_RELATIVE = 13 +R_TILEPRO_BROFF_X1 = 14 +R_TILEPRO_JOFFLONG_X1 = 15 +R_TILEPRO_JOFFLONG_X1_PLT = 16 +R_TILEPRO_IMM8_X0 = 17 +R_TILEPRO_IMM8_Y0 = 18 +R_TILEPRO_IMM8_X1 = 19 +R_TILEPRO_IMM8_Y1 = 20 +R_TILEPRO_MT_IMM15_X1 = 21 +R_TILEPRO_MF_IMM15_X1 = 22 +R_TILEPRO_IMM16_X0 = 23 +R_TILEPRO_IMM16_X1 = 24 +R_TILEPRO_IMM16_X0_LO = 25 +R_TILEPRO_IMM16_X1_LO = 26 +R_TILEPRO_IMM16_X0_HI = 27 +R_TILEPRO_IMM16_X1_HI = 28 +R_TILEPRO_IMM16_X0_HA = 29 +R_TILEPRO_IMM16_X1_HA = 30 +R_TILEPRO_IMM16_X0_PCREL = 31 +R_TILEPRO_IMM16_X1_PCREL = 32 +R_TILEPRO_IMM16_X0_LO_PCREL = 33 +R_TILEPRO_IMM16_X1_LO_PCREL = 34 +R_TILEPRO_IMM16_X0_HI_PCREL = 35 +R_TILEPRO_IMM16_X1_HI_PCREL = 36 +R_TILEPRO_IMM16_X0_HA_PCREL = 37 +R_TILEPRO_IMM16_X1_HA_PCREL = 38 +R_TILEPRO_IMM16_X0_GOT = 39 +R_TILEPRO_IMM16_X1_GOT = 40 +R_TILEPRO_IMM16_X0_GOT_LO = 41 +R_TILEPRO_IMM16_X1_GOT_LO = 42 +R_TILEPRO_IMM16_X0_GOT_HI = 43 +R_TILEPRO_IMM16_X1_GOT_HI = 44 +R_TILEPRO_IMM16_X0_GOT_HA = 45 +R_TILEPRO_IMM16_X1_GOT_HA = 46 +R_TILEPRO_MMSTART_X0 = 47 +R_TILEPRO_MMEND_X0 = 48 +R_TILEPRO_MMSTART_X1 = 49 +R_TILEPRO_MMEND_X1 = 50 +R_TILEPRO_SHAMT_X0 = 51 +R_TILEPRO_SHAMT_X1 = 52 +R_TILEPRO_SHAMT_Y0 = 53 +R_TILEPRO_SHAMT_Y1 = 54 +R_TILEPRO_DEST_IMM8_X1 = 55 +R_TILEPRO_TLS_GD_CALL = 60 +R_TILEPRO_IMM8_X0_TLS_GD_ADD = 61 +R_TILEPRO_IMM8_X1_TLS_GD_ADD = 62 +R_TILEPRO_IMM8_Y0_TLS_GD_ADD = 63 +R_TILEPRO_IMM8_Y1_TLS_GD_ADD = 64 +R_TILEPRO_TLS_IE_LOAD = 65 +R_TILEPRO_IMM16_X0_TLS_GD = 66 +R_TILEPRO_IMM16_X1_TLS_GD = 67 +R_TILEPRO_IMM16_X0_TLS_GD_LO = 68 +R_TILEPRO_IMM16_X1_TLS_GD_LO = 69 +R_TILEPRO_IMM16_X0_TLS_GD_HI = 70 +R_TILEPRO_IMM16_X1_TLS_GD_HI = 71 +R_TILEPRO_IMM16_X0_TLS_GD_HA = 72 +R_TILEPRO_IMM16_X1_TLS_GD_HA = 73 +R_TILEPRO_IMM16_X0_TLS_IE = 74 +R_TILEPRO_IMM16_X1_TLS_IE = 75 +R_TILEPRO_IMM16_X0_TLS_IE_LO = 76 +R_TILEPRO_IMM16_X1_TLS_IE_LO = 77 +R_TILEPRO_IMM16_X0_TLS_IE_HI = 78 +R_TILEPRO_IMM16_X1_TLS_IE_HI = 79 +R_TILEPRO_IMM16_X0_TLS_IE_HA = 80 +R_TILEPRO_IMM16_X1_TLS_IE_HA = 81 +R_TILEPRO_TLS_DTPMOD32 = 82 +R_TILEPRO_TLS_DTPOFF32 = 83 +R_TILEPRO_TLS_TPOFF32 = 84 +R_TILEPRO_IMM16_X0_TLS_LE = 85 +R_TILEPRO_IMM16_X1_TLS_LE = 86 +R_TILEPRO_IMM16_X0_TLS_LE_LO = 87 +R_TILEPRO_IMM16_X1_TLS_LE_LO = 88 +R_TILEPRO_IMM16_X0_TLS_LE_HI = 89 +R_TILEPRO_IMM16_X1_TLS_LE_HI = 90 +R_TILEPRO_IMM16_X0_TLS_LE_HA = 91 +R_TILEPRO_IMM16_X1_TLS_LE_HA = 92 +R_TILEPRO_GNU_VTINHERIT = 128 +R_TILEPRO_GNU_VTENTRY = 129 +R_TILEPRO_NUM = 130 +R_TILEGX_NONE = 0 +R_TILEGX_64 = 1 +R_TILEGX_32 = 2 +R_TILEGX_16 = 3 +R_TILEGX_8 = 4 +R_TILEGX_64_PCREL = 5 +R_TILEGX_32_PCREL = 6 +R_TILEGX_16_PCREL = 7 +R_TILEGX_8_PCREL = 8 +R_TILEGX_HW0 = 9 +R_TILEGX_HW1 = 10 +R_TILEGX_HW2 = 11 +R_TILEGX_HW3 = 12 +R_TILEGX_HW0_LAST = 13 +R_TILEGX_HW1_LAST = 14 +R_TILEGX_HW2_LAST = 15 +R_TILEGX_COPY = 16 +R_TILEGX_GLOB_DAT = 17 +R_TILEGX_JMP_SLOT = 18 +R_TILEGX_RELATIVE = 19 +R_TILEGX_BROFF_X1 = 20 +R_TILEGX_JUMPOFF_X1 = 21 +R_TILEGX_JUMPOFF_X1_PLT = 22 +R_TILEGX_IMM8_X0 = 23 +R_TILEGX_IMM8_Y0 = 24 +R_TILEGX_IMM8_X1 = 25 +R_TILEGX_IMM8_Y1 = 26 +R_TILEGX_DEST_IMM8_X1 = 27 +R_TILEGX_MT_IMM14_X1 = 28 +R_TILEGX_MF_IMM14_X1 = 29 +R_TILEGX_MMSTART_X0 = 30 +R_TILEGX_MMEND_X0 = 31 +R_TILEGX_SHAMT_X0 = 32 +R_TILEGX_SHAMT_X1 = 33 +R_TILEGX_SHAMT_Y0 = 34 +R_TILEGX_SHAMT_Y1 = 35 +R_TILEGX_IMM16_X0_HW0 = 36 +R_TILEGX_IMM16_X1_HW0 = 37 +R_TILEGX_IMM16_X0_HW1 = 38 +R_TILEGX_IMM16_X1_HW1 = 39 +R_TILEGX_IMM16_X0_HW2 = 40 +R_TILEGX_IMM16_X1_HW2 = 41 +R_TILEGX_IMM16_X0_HW3 = 42 +R_TILEGX_IMM16_X1_HW3 = 43 +R_TILEGX_IMM16_X0_HW0_LAST = 44 +R_TILEGX_IMM16_X1_HW0_LAST = 45 +R_TILEGX_IMM16_X0_HW1_LAST = 46 +R_TILEGX_IMM16_X1_HW1_LAST = 47 +R_TILEGX_IMM16_X0_HW2_LAST = 48 +R_TILEGX_IMM16_X1_HW2_LAST = 49 +R_TILEGX_IMM16_X0_HW0_PCREL = 50 +R_TILEGX_IMM16_X1_HW0_PCREL = 51 +R_TILEGX_IMM16_X0_HW1_PCREL = 52 +R_TILEGX_IMM16_X1_HW1_PCREL = 53 +R_TILEGX_IMM16_X0_HW2_PCREL = 54 +R_TILEGX_IMM16_X1_HW2_PCREL = 55 +R_TILEGX_IMM16_X0_HW3_PCREL = 56 +R_TILEGX_IMM16_X1_HW3_PCREL = 57 +R_TILEGX_IMM16_X0_HW0_LAST_PCREL = 58 +R_TILEGX_IMM16_X1_HW0_LAST_PCREL = 59 +R_TILEGX_IMM16_X0_HW1_LAST_PCREL = 60 +R_TILEGX_IMM16_X1_HW1_LAST_PCREL = 61 +R_TILEGX_IMM16_X0_HW2_LAST_PCREL = 62 +R_TILEGX_IMM16_X1_HW2_LAST_PCREL = 63 +R_TILEGX_IMM16_X0_HW0_GOT = 64 +R_TILEGX_IMM16_X1_HW0_GOT = 65 +R_TILEGX_IMM16_X0_HW0_PLT_PCREL = 66 +R_TILEGX_IMM16_X1_HW0_PLT_PCREL = 67 +R_TILEGX_IMM16_X0_HW1_PLT_PCREL = 68 +R_TILEGX_IMM16_X1_HW1_PLT_PCREL = 69 +R_TILEGX_IMM16_X0_HW2_PLT_PCREL = 70 +R_TILEGX_IMM16_X1_HW2_PLT_PCREL = 71 +R_TILEGX_IMM16_X0_HW0_LAST_GOT = 72 +R_TILEGX_IMM16_X1_HW0_LAST_GOT = 73 +R_TILEGX_IMM16_X0_HW1_LAST_GOT = 74 +R_TILEGX_IMM16_X1_HW1_LAST_GOT = 75 +R_TILEGX_IMM16_X0_HW3_PLT_PCREL = 76 +R_TILEGX_IMM16_X1_HW3_PLT_PCREL = 77 +R_TILEGX_IMM16_X0_HW0_TLS_GD = 78 +R_TILEGX_IMM16_X1_HW0_TLS_GD = 79 +R_TILEGX_IMM16_X0_HW0_TLS_LE = 80 +R_TILEGX_IMM16_X1_HW0_TLS_LE = 81 +R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE = 82 +R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE = 83 +R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE = 84 +R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE = 85 +R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD = 86 +R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD = 87 +R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD = 88 +R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD = 89 +R_TILEGX_IMM16_X0_HW0_TLS_IE = 92 +R_TILEGX_IMM16_X1_HW0_TLS_IE = 93 +R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL = 94 +R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL = 95 +R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL = 96 +R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL = 97 +R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL = 98 +R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL = 99 +R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE = 100 +R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE = 101 +R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE = 102 +R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE = 103 +R_TILEGX_TLS_DTPMOD64 = 106 +R_TILEGX_TLS_DTPOFF64 = 107 +R_TILEGX_TLS_TPOFF64 = 108 +R_TILEGX_TLS_DTPMOD32 = 109 +R_TILEGX_TLS_DTPOFF32 = 110 +R_TILEGX_TLS_TPOFF32 = 111 +R_TILEGX_TLS_GD_CALL = 112 +R_TILEGX_IMM8_X0_TLS_GD_ADD = 113 +R_TILEGX_IMM8_X1_TLS_GD_ADD = 114 +R_TILEGX_IMM8_Y0_TLS_GD_ADD = 115 +R_TILEGX_IMM8_Y1_TLS_GD_ADD = 116 +R_TILEGX_TLS_IE_LOAD = 117 +R_TILEGX_IMM8_X0_TLS_ADD = 118 +R_TILEGX_IMM8_X1_TLS_ADD = 119 +R_TILEGX_IMM8_Y0_TLS_ADD = 120 +R_TILEGX_IMM8_Y1_TLS_ADD = 121 +R_TILEGX_GNU_VTINHERIT = 128 +R_TILEGX_GNU_VTENTRY = 129 +R_TILEGX_NUM = 130 +EF_RISCV_RVC = 0x0001 +EF_RISCV_FLOAT_ABI = 0x0006 +EF_RISCV_FLOAT_ABI_SOFT = 0x0000 +EF_RISCV_FLOAT_ABI_SINGLE = 0x0002 +EF_RISCV_FLOAT_ABI_DOUBLE = 0x0004 +EF_RISCV_FLOAT_ABI_QUAD = 0x0006 +EF_RISCV_RVE = 0x0008 +EF_RISCV_TSO = 0x0010 +R_RISCV_NONE = 0 +R_RISCV_32 = 1 +R_RISCV_64 = 2 +R_RISCV_RELATIVE = 3 +R_RISCV_COPY = 4 +R_RISCV_JUMP_SLOT = 5 +R_RISCV_TLS_DTPMOD32 = 6 +R_RISCV_TLS_DTPMOD64 = 7 +R_RISCV_TLS_DTPREL32 = 8 +R_RISCV_TLS_DTPREL64 = 9 +R_RISCV_TLS_TPREL32 = 10 +R_RISCV_TLS_TPREL64 = 11 +R_RISCV_BRANCH = 16 +R_RISCV_JAL = 17 +R_RISCV_CALL = 18 +R_RISCV_CALL_PLT = 19 +R_RISCV_GOT_HI20 = 20 +R_RISCV_TLS_GOT_HI20 = 21 +R_RISCV_TLS_GD_HI20 = 22 +R_RISCV_PCREL_HI20 = 23 +R_RISCV_PCREL_LO12_I = 24 +R_RISCV_PCREL_LO12_S = 25 +R_RISCV_HI20 = 26 +R_RISCV_LO12_I = 27 +R_RISCV_LO12_S = 28 +R_RISCV_TPREL_HI20 = 29 +R_RISCV_TPREL_LO12_I = 30 +R_RISCV_TPREL_LO12_S = 31 +R_RISCV_TPREL_ADD = 32 +R_RISCV_ADD8 = 33 +R_RISCV_ADD16 = 34 +R_RISCV_ADD32 = 35 +R_RISCV_ADD64 = 36 +R_RISCV_SUB8 = 37 +R_RISCV_SUB16 = 38 +R_RISCV_SUB32 = 39 +R_RISCV_SUB64 = 40 +R_RISCV_GNU_VTINHERIT = 41 +R_RISCV_GNU_VTENTRY = 42 +R_RISCV_ALIGN = 43 +R_RISCV_RVC_BRANCH = 44 +R_RISCV_RVC_JUMP = 45 +R_RISCV_RVC_LUI = 46 +R_RISCV_GPREL_I = 47 +R_RISCV_GPREL_S = 48 +R_RISCV_TPREL_I = 49 +R_RISCV_TPREL_S = 50 +R_RISCV_RELAX = 51 +R_RISCV_SUB6 = 52 +R_RISCV_SET6 = 53 +R_RISCV_SET8 = 54 +R_RISCV_SET16 = 55 +R_RISCV_SET32 = 56 +R_RISCV_32_PCREL = 57 +R_RISCV_IRELATIVE = 58 +R_RISCV_PLT32 = 59 +R_RISCV_SET_ULEB128 = 60 +R_RISCV_SUB_ULEB128 = 61 +R_RISCV_NUM = 62 +STO_RISCV_VARIANT_CC = 0x80 +SHT_RISCV_ATTRIBUTES = (SHT_LOPROC + 3) +PT_RISCV_ATTRIBUTES = (PT_LOPROC + 3) +DT_RISCV_VARIANT_CC = (DT_LOPROC + 1) +R_BPF_NONE = 0 +R_BPF_64_64 = 1 +R_BPF_64_32 = 10 +R_METAG_HIADDR16 = 0 +R_METAG_LOADDR16 = 1 +R_METAG_ADDR32 = 2 +R_METAG_NONE = 3 +R_METAG_RELBRANCH = 4 +R_METAG_GETSETOFF = 5 +R_METAG_REG32OP1 = 6 +R_METAG_REG32OP2 = 7 +R_METAG_REG32OP3 = 8 +R_METAG_REG16OP1 = 9 +R_METAG_REG16OP2 = 10 +R_METAG_REG16OP3 = 11 +R_METAG_REG32OP4 = 12 +R_METAG_HIOG = 13 +R_METAG_LOOG = 14 +R_METAG_REL8 = 15 +R_METAG_REL16 = 16 +R_METAG_GNU_VTINHERIT = 30 +R_METAG_GNU_VTENTRY = 31 +R_METAG_HI16_GOTOFF = 32 +R_METAG_LO16_GOTOFF = 33 +R_METAG_GETSET_GOTOFF = 34 +R_METAG_GETSET_GOT = 35 +R_METAG_HI16_GOTPC = 36 +R_METAG_LO16_GOTPC = 37 +R_METAG_HI16_PLT = 38 +R_METAG_LO16_PLT = 39 +R_METAG_RELBRANCH_PLT = 40 +R_METAG_GOTOFF = 41 +R_METAG_PLT = 42 +R_METAG_COPY = 43 +R_METAG_JMP_SLOT = 44 +R_METAG_RELATIVE = 45 +R_METAG_GLOB_DAT = 46 +R_METAG_TLS_GD = 47 +R_METAG_TLS_LDM = 48 +R_METAG_TLS_LDO_HI16 = 49 +R_METAG_TLS_LDO_LO16 = 50 +R_METAG_TLS_LDO = 51 +R_METAG_TLS_IE = 52 +R_METAG_TLS_IENONPIC = 53 +R_METAG_TLS_IENONPIC_HI16 = 54 +R_METAG_TLS_IENONPIC_LO16 = 55 +R_METAG_TLS_TPOFF = 56 +R_METAG_TLS_DTPMOD = 57 +R_METAG_TLS_DTPOFF = 58 +R_METAG_TLS_LE = 59 +R_METAG_TLS_LE_HI16 = 60 +R_METAG_TLS_LE_LO16 = 61 +R_NDS32_NONE = 0 +R_NDS32_32_RELA = 20 +R_NDS32_COPY = 39 +R_NDS32_GLOB_DAT = 40 +R_NDS32_JMP_SLOT = 41 +R_NDS32_RELATIVE = 42 +R_NDS32_TLS_TPOFF = 102 +R_NDS32_TLS_DESC = 119 +EF_LARCH_ABI_MODIFIER_MASK = 0x07 +EF_LARCH_ABI_SOFT_FLOAT = 0x01 +EF_LARCH_ABI_SINGLE_FLOAT = 0x02 +EF_LARCH_ABI_DOUBLE_FLOAT = 0x03 +EF_LARCH_OBJABI_V1 = 0x40 +R_LARCH_NONE = 0 +R_LARCH_32 = 1 +R_LARCH_64 = 2 +R_LARCH_RELATIVE = 3 +R_LARCH_COPY = 4 +R_LARCH_JUMP_SLOT = 5 +R_LARCH_TLS_DTPMOD32 = 6 +R_LARCH_TLS_DTPMOD64 = 7 +R_LARCH_TLS_DTPREL32 = 8 +R_LARCH_TLS_DTPREL64 = 9 +R_LARCH_TLS_TPREL32 = 10 +R_LARCH_TLS_TPREL64 = 11 +R_LARCH_IRELATIVE = 12 +R_LARCH_MARK_LA = 20 +R_LARCH_MARK_PCREL = 21 +R_LARCH_SOP_PUSH_PCREL = 22 +R_LARCH_SOP_PUSH_ABSOLUTE = 23 +R_LARCH_SOP_PUSH_DUP = 24 +R_LARCH_SOP_PUSH_GPREL = 25 +R_LARCH_SOP_PUSH_TLS_TPREL = 26 +R_LARCH_SOP_PUSH_TLS_GOT = 27 +R_LARCH_SOP_PUSH_TLS_GD = 28 +R_LARCH_SOP_PUSH_PLT_PCREL = 29 +R_LARCH_SOP_ASSERT = 30 +R_LARCH_SOP_NOT = 31 +R_LARCH_SOP_SUB = 32 +R_LARCH_SOP_SL = 33 +R_LARCH_SOP_SR = 34 +R_LARCH_SOP_ADD = 35 +R_LARCH_SOP_AND = 36 +R_LARCH_SOP_IF_ELSE = 37 +R_LARCH_SOP_POP_32_S_10_5 = 38 +R_LARCH_SOP_POP_32_U_10_12 = 39 +R_LARCH_SOP_POP_32_S_10_12 = 40 +R_LARCH_SOP_POP_32_S_10_16 = 41 +R_LARCH_SOP_POP_32_S_10_16_S2 = 42 +R_LARCH_SOP_POP_32_S_5_20 = 43 +R_LARCH_SOP_POP_32_S_0_5_10_16_S2 = 44 +R_LARCH_SOP_POP_32_S_0_10_10_16_S2 = 45 +R_LARCH_SOP_POP_32_U = 46 +R_LARCH_ADD8 = 47 +R_LARCH_ADD16 = 48 +R_LARCH_ADD24 = 49 +R_LARCH_ADD32 = 50 +R_LARCH_ADD64 = 51 +R_LARCH_SUB8 = 52 +R_LARCH_SUB16 = 53 +R_LARCH_SUB24 = 54 +R_LARCH_SUB32 = 55 +R_LARCH_SUB64 = 56 +R_LARCH_GNU_VTINHERIT = 57 +R_LARCH_GNU_VTENTRY = 58 +R_LARCH_B16 = 64 +R_LARCH_B21 = 65 +R_LARCH_B26 = 66 +R_LARCH_ABS_HI20 = 67 +R_LARCH_ABS_LO12 = 68 +R_LARCH_ABS64_LO20 = 69 +R_LARCH_ABS64_HI12 = 70 +R_LARCH_PCALA_HI20 = 71 +R_LARCH_PCALA_LO12 = 72 +R_LARCH_PCALA64_LO20 = 73 +R_LARCH_PCALA64_HI12 = 74 +R_LARCH_GOT_PC_HI20 = 75 +R_LARCH_GOT_PC_LO12 = 76 +R_LARCH_GOT64_PC_LO20 = 77 +R_LARCH_GOT64_PC_HI12 = 78 +R_LARCH_GOT_HI20 = 79 +R_LARCH_GOT_LO12 = 80 +R_LARCH_GOT64_LO20 = 81 +R_LARCH_GOT64_HI12 = 82 +R_LARCH_TLS_LE_HI20 = 83 +R_LARCH_TLS_LE_LO12 = 84 +R_LARCH_TLS_LE64_LO20 = 85 +R_LARCH_TLS_LE64_HI12 = 86 +R_LARCH_TLS_IE_PC_HI20 = 87 +R_LARCH_TLS_IE_PC_LO12 = 88 +R_LARCH_TLS_IE64_PC_LO20 = 89 +R_LARCH_TLS_IE64_PC_HI12 = 90 +R_LARCH_TLS_IE_HI20 = 91 +R_LARCH_TLS_IE_LO12 = 92 +R_LARCH_TLS_IE64_LO20 = 93 +R_LARCH_TLS_IE64_HI12 = 94 +R_LARCH_TLS_LD_PC_HI20 = 95 +R_LARCH_TLS_LD_HI20 = 96 +R_LARCH_TLS_GD_PC_HI20 = 97 +R_LARCH_TLS_GD_HI20 = 98 +R_LARCH_32_PCREL = 99 +R_LARCH_RELAX = 100 +R_LARCH_DELETE = 101 +R_LARCH_ALIGN = 102 +R_LARCH_PCREL20_S2 = 103 +R_LARCH_CFA = 104 +R_LARCH_ADD6 = 105 +R_LARCH_SUB6 = 106 +R_LARCH_ADD_ULEB128 = 107 +R_LARCH_SUB_ULEB128 = 108 +R_LARCH_64_PCREL = 109 +EF_ARC_MACH_MSK = 0x000000ff +EF_ARC_OSABI_MSK = 0x00000f00 +EF_ARC_ALL_MSK = (EF_ARC_MACH_MSK | EF_ARC_OSABI_MSK) +SHT_ARC_ATTRIBUTES = (SHT_LOPROC + 1) +R_ARC_NONE = 0x0 +R_ARC_8 = 0x1 +R_ARC_16 = 0x2 +R_ARC_24 = 0x3 +R_ARC_32 = 0x4 +R_ARC_B22_PCREL = 0x6 +R_ARC_H30 = 0x7 +R_ARC_N8 = 0x8 +R_ARC_N16 = 0x9 +R_ARC_N24 = 0xA +R_ARC_N32 = 0xB +R_ARC_SDA = 0xC +R_ARC_SECTOFF = 0xD +R_ARC_S21H_PCREL = 0xE +R_ARC_S21W_PCREL = 0xF +R_ARC_S25H_PCREL = 0x10 +R_ARC_S25W_PCREL = 0x11 +R_ARC_SDA32 = 0x12 +R_ARC_SDA_LDST = 0x13 +R_ARC_SDA_LDST1 = 0x14 +R_ARC_SDA_LDST2 = 0x15 +R_ARC_SDA16_LD = 0x16 +R_ARC_SDA16_LD1 = 0x17 +R_ARC_SDA16_LD2 = 0x18 +R_ARC_S13_PCREL = 0x19 +R_ARC_W = 0x1A +R_ARC_32_ME = 0x1B +R_ARC_N32_ME = 0x1C +R_ARC_SECTOFF_ME = 0x1D +R_ARC_SDA32_ME = 0x1E +R_ARC_W_ME = 0x1F +R_ARC_H30_ME = 0x20 +R_ARC_SECTOFF_U8 = 0x21 +R_ARC_SECTOFF_S9 = 0x22 +R_AC_SECTOFF_U8 = 0x23 +R_AC_SECTOFF_U8_1 = 0x24 +R_AC_SECTOFF_U8_2 = 0x25 +R_AC_SECTOFF_S9 = 0x26 +R_AC_SECTOFF_S9_1 = 0x27 +R_AC_SECTOFF_S9_2 = 0x28 +R_ARC_SECTOFF_ME_1 = 0x29 +R_ARC_SECTOFF_ME_2 = 0x2A +R_ARC_SECTOFF_1 = 0x2B +R_ARC_SECTOFF_2 = 0x2C +R_ARC_SDA_12 = 0x2D +R_ARC_SDA16_ST2 = 0x30 +R_ARC_32_PCREL = 0x31 +R_ARC_PC32 = 0x32 +R_ARC_GOTPC32 = 0x33 +R_ARC_PLT32 = 0x34 +R_ARC_COPY = 0x35 +R_ARC_GLOB_DAT = 0x36 +R_ARC_JMP_SLOT = 0x37 +R_ARC_RELATIVE = 0x38 +R_ARC_GOTOFF = 0x39 +R_ARC_GOTPC = 0x3A +R_ARC_GOT32 = 0x3B +R_ARC_S21W_PCREL_PLT = 0x3C +R_ARC_S25H_PCREL_PLT = 0x3D +R_ARC_JLI_SECTOFF = 0x3F +R_ARC_TLS_DTPMOD = 0x42 +R_ARC_TLS_DTPOFF = 0x43 +R_ARC_TLS_TPOFF = 0x44 +R_ARC_TLS_GD_GOT = 0x45 +R_ARC_TLS_GD_LD = 0x46 +R_ARC_TLS_GD_CALL = 0x47 +R_ARC_TLS_IE_GOT = 0x48 +R_ARC_TLS_DTPOFF_S9 = 0x49 +R_ARC_TLS_LE_S9 = 0x4A +R_ARC_TLS_LE_32 = 0x4B +R_ARC_S25W_PCREL_PLT = 0x4C +R_ARC_S21H_PCREL_PLT = 0x4D +R_ARC_NPS_CMEM16 = 0x4E +R_OR1K_NONE = 0 +R_OR1K_32 = 1 +R_OR1K_16 = 2 +R_OR1K_8 = 3 +R_OR1K_LO_16_IN_INSN = 4 +R_OR1K_HI_16_IN_INSN = 5 +R_OR1K_INSN_REL_26 = 6 +R_OR1K_GNU_VTENTRY = 7 +R_OR1K_GNU_VTINHERIT = 8 +R_OR1K_32_PCREL = 9 +R_OR1K_16_PCREL = 10 +R_OR1K_8_PCREL = 11 +R_OR1K_GOTPC_HI16 = 12 +R_OR1K_GOTPC_LO16 = 13 +R_OR1K_GOT16 = 14 +R_OR1K_PLT26 = 15 +R_OR1K_GOTOFF_HI16 = 16 +R_OR1K_GOTOFF_LO16 = 17 +R_OR1K_COPY = 18 +R_OR1K_GLOB_DAT = 19 +R_OR1K_JMP_SLOT = 20 +R_OR1K_RELATIVE = 21 +R_OR1K_TLS_GD_HI16 = 22 +R_OR1K_TLS_GD_LO16 = 23 +R_OR1K_TLS_LDM_HI16 = 24 +R_OR1K_TLS_LDM_LO16 = 25 +R_OR1K_TLS_LDO_HI16 = 26 +R_OR1K_TLS_LDO_LO16 = 27 +R_OR1K_TLS_IE_HI16 = 28 +R_OR1K_TLS_IE_LO16 = 29 +R_OR1K_TLS_LE_HI16 = 30 +R_OR1K_TLS_LE_LO16 = 31 +R_OR1K_TLS_TPOFF = 32 +R_OR1K_TLS_DTPOFF = 33 +R_OR1K_TLS_DTPMOD = 34 +_UNISTD_H = 1 +_POSIX_VERSION = 200809 +__POSIX2_THIS_VERSION = 200809 +_POSIX2_VERSION = __POSIX2_THIS_VERSION +_POSIX2_C_VERSION = __POSIX2_THIS_VERSION +_POSIX2_C_BIND = __POSIX2_THIS_VERSION +_POSIX2_C_DEV = __POSIX2_THIS_VERSION +_POSIX2_SW_DEV = __POSIX2_THIS_VERSION +_POSIX2_LOCALEDEF = __POSIX2_THIS_VERSION +_XOPEN_VERSION = 700 +_XOPEN_XCU_VERSION = 4 +_XOPEN_XPG2 = 1 +_XOPEN_XPG3 = 1 +_XOPEN_XPG4 = 1 +_XOPEN_UNIX = 1 +_XOPEN_ENH_I18N = 1 +_XOPEN_LEGACY = 1 +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 +R_OK = 4 +W_OK = 2 +X_OK = 1 +F_OK = 0 +SEEK_SET = 0 +SEEK_CUR = 1 +SEEK_END = 2 +L_SET = SEEK_SET +L_INCR = SEEK_CUR +L_XTND = SEEK_END +F_ULOCK = 0 +F_LOCK = 1 +F_TLOCK = 2 +F_TEST = 3 +PROT_READ = 0x1 +PROT_WRITE = 0x2 +PROT_EXEC = 0x4 +PROT_SEM = 0x8 +PROT_NONE = 0x0 +PROT_GROWSDOWN = 0x01000000 +PROT_GROWSUP = 0x02000000 +MAP_TYPE = 0x0f +MAP_FIXED = 0x10 +MAP_ANONYMOUS = 0x20 +MAP_POPULATE = 0x008000 +MAP_NONBLOCK = 0x010000 +MAP_STACK = 0x020000 +MAP_HUGETLB = 0x040000 +MAP_SYNC = 0x080000 +MAP_FIXED_NOREPLACE = 0x100000 +MAP_UNINITIALIZED = 0x4000000 +MLOCK_ONFAULT = 0x01 +MS_ASYNC = 1 +MS_INVALIDATE = 2 +MS_SYNC = 4 +MADV_NORMAL = 0 +MADV_RANDOM = 1 +MADV_SEQUENTIAL = 2 +MADV_WILLNEED = 3 +MADV_DONTNEED = 4 +MADV_FREE = 8 +MADV_REMOVE = 9 +MADV_DONTFORK = 10 +MADV_DOFORK = 11 +MADV_HWPOISON = 100 +MADV_SOFT_OFFLINE = 101 +MADV_MERGEABLE = 12 +MADV_UNMERGEABLE = 13 +MADV_HUGEPAGE = 14 +MADV_NOHUGEPAGE = 15 +MADV_DONTDUMP = 16 +MADV_DODUMP = 17 +MADV_WIPEONFORK = 18 +MADV_KEEPONFORK = 19 +MADV_COLD = 20 +MADV_PAGEOUT = 21 +MADV_POPULATE_READ = 22 +MADV_POPULATE_WRITE = 23 +MADV_DONTNEED_LOCKED = 24 +MADV_COLLAPSE = 25 +MAP_FILE = 0 +PKEY_DISABLE_ACCESS = 0x1 +PKEY_DISABLE_WRITE = 0x2 +PKEY_ACCESS_MASK = (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE) \ No newline at end of file diff --git a/tinygrad/runtime/autogen/libusb.py b/tinygrad/runtime/autogen/libusb.py index aa81cee87b..8911049310 100644 --- a/tinygrad/runtime/autogen/libusb.py +++ b/tinygrad/runtime/autogen/libusb.py @@ -21,6 +21,8 @@ class FunctionFactoryStub: _libraries = {} _libraries['libusb'] = None if (lib_path:=os.getenv('LIBUSB_PATH', ctypes.util.find_library('usb-1.0'))) is None else ctypes.CDLL(lib_path) # ctypes.CDLL('libusb') class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/llvm.py b/tinygrad/runtime/autogen/llvm.py index 1b50e41e49..49c0c4c837 100644 --- a/tinygrad/runtime/autogen/llvm.py +++ b/tinygrad/runtime/autogen/llvm.py @@ -10,6 +10,8 @@ import ctypes, tinygrad.runtime.support.llvm as llvm_support class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/mesa.py b/tinygrad/runtime/autogen/mesa.py new file mode 100644 index 0000000000..b70da41940 --- /dev/null +++ b/tinygrad/runtime/autogen/mesa.py @@ -0,0 +1,19881 @@ +# mypy: ignore-errors +# -*- coding: utf-8 -*- +# +# TARGET arch is: ['-DHAVE_ENDIAN_H', '-DHAVE_STRUCT_TIMESPEC', '-DHAVE_PTHREAD', '-I/tmp/mesa-mesa-25.2.4/src', '-I/tmp/mesa-mesa-25.2.4/include', '-I/tmp/mesa-mesa-25.2.4/gen', '-I/tmp/mesa-mesa-25.2.4/src/compiler/nir', '-I/tmp/mesa-mesa-25.2.4/src/gallium/auxiliary', '-I/tmp/mesa-mesa-25.2.4/src/gallium/include', '-I/usr/lib/llvm-20/include'] +# WORD_SIZE is: 8 +# POINTER_SIZE is: 8 +# LONGDOUBLE_SIZE is: 16 +# +import ctypes, ctypes.util, os, gzip, base64, subprocess, tinygrad.helpers as helpers +PATHS_TO_TRY = [ + (BASE:=os.getenv('MESA_PATH', f"/usr{'/local/' if helpers.OSX else '/'}lib"))+'/libtinymesa_cpu'+(EXT:='.dylib' if helpers.OSX else '.so'), + f'{BASE}/libtinymesa{EXT}', + '/opt/homebrew/lib/libtinymesa_cpu.dylib', + '/opt/homebrew/lib/libtinymesa.dylib', +] +def _try_dlopen_tinymesa_cpu(): + library = ctypes.util.find_library("tinymesa_cpu") + if library: + try: return ctypes.CDLL(library) + except OSError: pass + for candidate in PATHS_TO_TRY: + try: return ctypes.CDLL(candidate) + except OSError: pass + return None + + +class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' + @classmethod + def as_dict(cls, self): + result = {} + if not isinstance(self, AsDictMixin): + # not a structure, assume it's already a python object + return self + if not hasattr(cls, "_fields_"): + return result + # sys.version_info >= (3, 5) + # for (field, *_) in cls._fields_: # noqa + for field_tuple in cls._fields_: # noqa + field = field_tuple[0] + if field.startswith('PADDING_'): + continue + value = getattr(self, field) + type_ = type(value) + if hasattr(value, "_length_") and hasattr(value, "_type_"): + # array + if not hasattr(type_, "as_dict"): + value = [v for v in value] + else: + type_ = type_._type_ + value = [type_.as_dict(v) for v in value] + elif hasattr(value, "contents") and hasattr(value, "_type_"): + # pointer + try: + if not hasattr(type_, "as_dict"): + value = value.contents + else: + type_ = type_._type_ + value = type_.as_dict(value.contents) + except ValueError: + # nullptr + value = None + elif isinstance(value, AsDictMixin): + # other structure + value = type_.as_dict(value) + result[field] = value + return result + + +class Structure(ctypes.Structure, AsDictMixin): + + def __init__(self, *args, **kwds): + # We don't want to use positional arguments fill PADDING_* fields + + args = dict(zip(self.__class__._field_names_(), args)) + args.update(kwds) + super(Structure, self).__init__(**args) + + @classmethod + def _field_names_(cls): + if hasattr(cls, '_fields_'): + return (f[0] for f in cls._fields_ if not f[0].startswith('PADDING')) + else: + return () + + @classmethod + def get_type(cls, field): + for f in cls._fields_: + if f[0] == field: + return f[1] + return None + + @classmethod + def bind(cls, bound_fields): + fields = {} + for name, type_ in cls._fields_: + if hasattr(type_, "restype"): + if name in bound_fields: + if bound_fields[name] is None: + fields[name] = type_() + else: + # use a closure to capture the callback from the loop scope + fields[name] = ( + type_((lambda callback: lambda *args: callback(*args))( + bound_fields[name])) + ) + del bound_fields[name] + else: + # default callback implementation (does nothing) + try: + default_ = type_(0).restype().value + except TypeError: + default_ = None + fields[name] = type_(( + lambda default_: lambda *args: default_)(default_)) + else: + # not a callback function, use default initialization + if name in bound_fields: + fields[name] = bound_fields[name] + del bound_fields[name] + else: + fields[name] = type_() + if len(bound_fields) != 0: + raise ValueError( + "Cannot bind the following unknown callback(s) {}.{}".format( + cls.__name__, bound_fields.keys() + )) + return cls(**fields) + + +class Union(ctypes.Union, AsDictMixin): + pass + + + +def string_cast(char_pointer, encoding='utf-8', errors='strict'): + value = ctypes.cast(char_pointer, ctypes.c_char_p).value + if value is not None and encoding is not None: + value = value.decode(encoding, errors=errors) + return value + + +def char_pointer_cast(string, encoding='utf-8'): + if encoding is not None: + try: + string = string.encode(encoding) + except AttributeError: + # In Python3, bytes has no encode attribute + pass + string = ctypes.c_char_p(string) + return ctypes.cast(string, ctypes.POINTER(ctypes.c_char)) + + + +c_int128 = ctypes.c_ubyte*16 +c_uint128 = c_int128 +void = None +if ctypes.sizeof(ctypes.c_longdouble) == 16: + c_long_double_t = ctypes.c_longdouble +else: + c_long_double_t = ctypes.c_ubyte*16 + +_libraries = {} +_libraries['libtinymesa_cpu.so'] = (dll := _try_dlopen_tinymesa_cpu()) +class FunctionFactoryStub: + def __getattr__(self, _): + return ctypes.CFUNCTYPE(lambda y:y) + +# libraries['FIXME_STUB'] explanation +# As you did not list (-l libraryname.so) a library that exports this function +# This is a non-working stub instead. +# You can either re-run clan2py with -l /path/to/library.so +# Or manually fix this by comment the ctypes.CDLL loading +_libraries['FIXME_STUB'] = FunctionFactoryStub() # (dll := _try_dlopen_tinymesa_cpu()) + + +class struct_blob(Structure): + pass + +struct_blob._pack_ = 1 # source:False +struct_blob._fields_ = [ + ('data', ctypes.POINTER(ctypes.c_ubyte)), + ('allocated', ctypes.c_uint64), + ('size', ctypes.c_uint64), + ('fixed_allocation', ctypes.c_bool), + ('out_of_memory', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 6), +] + +class struct_blob_reader(Structure): + pass + +struct_blob_reader._pack_ = 1 # source:False +struct_blob_reader._fields_ = [ + ('data', ctypes.POINTER(ctypes.c_ubyte)), + ('end', ctypes.POINTER(ctypes.c_ubyte)), + ('current', ctypes.POINTER(ctypes.c_ubyte)), + ('overrun', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), +] + +try: + blob_init = _libraries['libtinymesa_cpu.so'].blob_init + blob_init.restype = None + blob_init.argtypes = [ctypes.POINTER(struct_blob)] +except AttributeError: + pass +size_t = ctypes.c_uint64 +try: + blob_init_fixed = _libraries['libtinymesa_cpu.so'].blob_init_fixed + blob_init_fixed.restype = None + blob_init_fixed.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + blob_finish = _libraries['FIXME_STUB'].blob_finish + blob_finish.restype = None + blob_finish.argtypes = [ctypes.POINTER(struct_blob)] +except AttributeError: + pass +try: + blob_finish_get_buffer = _libraries['libtinymesa_cpu.so'].blob_finish_get_buffer + blob_finish_get_buffer.restype = None + blob_finish_get_buffer.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(ctypes.POINTER(None)), ctypes.POINTER(ctypes.c_uint64)] +except AttributeError: + pass +try: + blob_align = _libraries['libtinymesa_cpu.so'].blob_align + blob_align.restype = ctypes.c_bool + blob_align.argtypes = [ctypes.POINTER(struct_blob), size_t] +except AttributeError: + pass +try: + blob_write_bytes = _libraries['libtinymesa_cpu.so'].blob_write_bytes + blob_write_bytes.restype = ctypes.c_bool + blob_write_bytes.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(None), size_t] +except AttributeError: + pass +intptr_t = ctypes.c_int64 +try: + blob_reserve_bytes = _libraries['libtinymesa_cpu.so'].blob_reserve_bytes + blob_reserve_bytes.restype = intptr_t + blob_reserve_bytes.argtypes = [ctypes.POINTER(struct_blob), size_t] +except AttributeError: + pass +try: + blob_reserve_uint32 = _libraries['libtinymesa_cpu.so'].blob_reserve_uint32 + blob_reserve_uint32.restype = intptr_t + blob_reserve_uint32.argtypes = [ctypes.POINTER(struct_blob)] +except AttributeError: + pass +try: + blob_reserve_intptr = _libraries['libtinymesa_cpu.so'].blob_reserve_intptr + blob_reserve_intptr.restype = intptr_t + blob_reserve_intptr.argtypes = [ctypes.POINTER(struct_blob)] +except AttributeError: + pass +try: + blob_overwrite_bytes = _libraries['libtinymesa_cpu.so'].blob_overwrite_bytes + blob_overwrite_bytes.restype = ctypes.c_bool + blob_overwrite_bytes.argtypes = [ctypes.POINTER(struct_blob), size_t, ctypes.POINTER(None), size_t] +except AttributeError: + pass +uint8_t = ctypes.c_uint8 +try: + blob_write_uint8 = _libraries['libtinymesa_cpu.so'].blob_write_uint8 + blob_write_uint8.restype = ctypes.c_bool + blob_write_uint8.argtypes = [ctypes.POINTER(struct_blob), uint8_t] +except AttributeError: + pass +try: + blob_overwrite_uint8 = _libraries['libtinymesa_cpu.so'].blob_overwrite_uint8 + blob_overwrite_uint8.restype = ctypes.c_bool + blob_overwrite_uint8.argtypes = [ctypes.POINTER(struct_blob), size_t, uint8_t] +except AttributeError: + pass +uint16_t = ctypes.c_uint16 +try: + blob_write_uint16 = _libraries['libtinymesa_cpu.so'].blob_write_uint16 + blob_write_uint16.restype = ctypes.c_bool + blob_write_uint16.argtypes = [ctypes.POINTER(struct_blob), uint16_t] +except AttributeError: + pass +uint32_t = ctypes.c_uint32 +try: + blob_write_uint32 = _libraries['libtinymesa_cpu.so'].blob_write_uint32 + blob_write_uint32.restype = ctypes.c_bool + blob_write_uint32.argtypes = [ctypes.POINTER(struct_blob), uint32_t] +except AttributeError: + pass +try: + blob_overwrite_uint32 = _libraries['libtinymesa_cpu.so'].blob_overwrite_uint32 + blob_overwrite_uint32.restype = ctypes.c_bool + blob_overwrite_uint32.argtypes = [ctypes.POINTER(struct_blob), size_t, uint32_t] +except AttributeError: + pass +uint64_t = ctypes.c_uint64 +try: + blob_write_uint64 = _libraries['libtinymesa_cpu.so'].blob_write_uint64 + blob_write_uint64.restype = ctypes.c_bool + blob_write_uint64.argtypes = [ctypes.POINTER(struct_blob), uint64_t] +except AttributeError: + pass +try: + blob_write_intptr = _libraries['libtinymesa_cpu.so'].blob_write_intptr + blob_write_intptr.restype = ctypes.c_bool + blob_write_intptr.argtypes = [ctypes.POINTER(struct_blob), intptr_t] +except AttributeError: + pass +try: + blob_overwrite_intptr = _libraries['libtinymesa_cpu.so'].blob_overwrite_intptr + blob_overwrite_intptr.restype = ctypes.c_bool + blob_overwrite_intptr.argtypes = [ctypes.POINTER(struct_blob), size_t, intptr_t] +except AttributeError: + pass +try: + blob_write_string = _libraries['libtinymesa_cpu.so'].blob_write_string + blob_write_string.restype = ctypes.c_bool + blob_write_string.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + blob_reader_init = _libraries['libtinymesa_cpu.so'].blob_reader_init + blob_reader_init.restype = None + blob_reader_init.argtypes = [ctypes.POINTER(struct_blob_reader), ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + blob_reader_align = _libraries['libtinymesa_cpu.so'].blob_reader_align + blob_reader_align.restype = None + blob_reader_align.argtypes = [ctypes.POINTER(struct_blob_reader), size_t] +except AttributeError: + pass +try: + blob_read_bytes = _libraries['libtinymesa_cpu.so'].blob_read_bytes + blob_read_bytes.restype = ctypes.POINTER(None) + blob_read_bytes.argtypes = [ctypes.POINTER(struct_blob_reader), size_t] +except AttributeError: + pass +try: + blob_copy_bytes = _libraries['libtinymesa_cpu.so'].blob_copy_bytes + blob_copy_bytes.restype = None + blob_copy_bytes.argtypes = [ctypes.POINTER(struct_blob_reader), ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + blob_skip_bytes = _libraries['libtinymesa_cpu.so'].blob_skip_bytes + blob_skip_bytes.restype = None + blob_skip_bytes.argtypes = [ctypes.POINTER(struct_blob_reader), size_t] +except AttributeError: + pass +try: + blob_read_uint8 = _libraries['libtinymesa_cpu.so'].blob_read_uint8 + blob_read_uint8.restype = uint8_t + blob_read_uint8.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +try: + blob_read_uint16 = _libraries['libtinymesa_cpu.so'].blob_read_uint16 + blob_read_uint16.restype = uint16_t + blob_read_uint16.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +try: + blob_read_uint32 = _libraries['libtinymesa_cpu.so'].blob_read_uint32 + blob_read_uint32.restype = uint32_t + blob_read_uint32.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +try: + blob_read_uint64 = _libraries['libtinymesa_cpu.so'].blob_read_uint64 + blob_read_uint64.restype = uint64_t + blob_read_uint64.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +try: + blob_read_intptr = _libraries['libtinymesa_cpu.so'].blob_read_intptr + blob_read_intptr.restype = intptr_t + blob_read_intptr.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +try: + blob_read_string = _libraries['libtinymesa_cpu.so'].blob_read_string + blob_read_string.restype = ctypes.POINTER(ctypes.c_char) + blob_read_string.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +class struct_glsl_type(Structure): + pass + + +# values for enumeration 'glsl_base_type' +glsl_base_type__enumvalues = { + 0: 'GLSL_TYPE_UINT', + 1: 'GLSL_TYPE_INT', + 2: 'GLSL_TYPE_FLOAT', + 3: 'GLSL_TYPE_FLOAT16', + 4: 'GLSL_TYPE_BFLOAT16', + 5: 'GLSL_TYPE_FLOAT_E4M3FN', + 6: 'GLSL_TYPE_FLOAT_E5M2', + 7: 'GLSL_TYPE_DOUBLE', + 8: 'GLSL_TYPE_UINT8', + 9: 'GLSL_TYPE_INT8', + 10: 'GLSL_TYPE_UINT16', + 11: 'GLSL_TYPE_INT16', + 12: 'GLSL_TYPE_UINT64', + 13: 'GLSL_TYPE_INT64', + 14: 'GLSL_TYPE_BOOL', + 15: 'GLSL_TYPE_COOPERATIVE_MATRIX', + 16: 'GLSL_TYPE_SAMPLER', + 17: 'GLSL_TYPE_TEXTURE', + 18: 'GLSL_TYPE_IMAGE', + 19: 'GLSL_TYPE_ATOMIC_UINT', + 20: 'GLSL_TYPE_STRUCT', + 21: 'GLSL_TYPE_INTERFACE', + 22: 'GLSL_TYPE_ARRAY', + 23: 'GLSL_TYPE_VOID', + 24: 'GLSL_TYPE_SUBROUTINE', + 25: 'GLSL_TYPE_ERROR', +} +GLSL_TYPE_UINT = 0 +GLSL_TYPE_INT = 1 +GLSL_TYPE_FLOAT = 2 +GLSL_TYPE_FLOAT16 = 3 +GLSL_TYPE_BFLOAT16 = 4 +GLSL_TYPE_FLOAT_E4M3FN = 5 +GLSL_TYPE_FLOAT_E5M2 = 6 +GLSL_TYPE_DOUBLE = 7 +GLSL_TYPE_UINT8 = 8 +GLSL_TYPE_INT8 = 9 +GLSL_TYPE_UINT16 = 10 +GLSL_TYPE_INT16 = 11 +GLSL_TYPE_UINT64 = 12 +GLSL_TYPE_INT64 = 13 +GLSL_TYPE_BOOL = 14 +GLSL_TYPE_COOPERATIVE_MATRIX = 15 +GLSL_TYPE_SAMPLER = 16 +GLSL_TYPE_TEXTURE = 17 +GLSL_TYPE_IMAGE = 18 +GLSL_TYPE_ATOMIC_UINT = 19 +GLSL_TYPE_STRUCT = 20 +GLSL_TYPE_INTERFACE = 21 +GLSL_TYPE_ARRAY = 22 +GLSL_TYPE_VOID = 23 +GLSL_TYPE_SUBROUTINE = 24 +GLSL_TYPE_ERROR = 25 +glsl_base_type = ctypes.c_uint32 # enum +class struct_glsl_cmat_description(Structure): + pass + +struct_glsl_cmat_description._pack_ = 1 # source:False +struct_glsl_cmat_description._fields_ = [ + ('element_type', ctypes.c_ubyte, 5), + ('scope', ctypes.c_ubyte, 3), + ('rows', ctypes.c_ubyte, 8), + ('cols', ctypes.c_ubyte), + ('use', ctypes.c_ubyte), +] + +class union_glsl_type_fields(Union): + pass + +class struct_glsl_struct_field(Structure): + pass + +union_glsl_type_fields._pack_ = 1 # source:False +union_glsl_type_fields._fields_ = [ + ('array', ctypes.POINTER(struct_glsl_type)), + ('structure', ctypes.POINTER(struct_glsl_struct_field)), +] + +struct_glsl_type._pack_ = 1 # source:False +struct_glsl_type._fields_ = [ + ('gl_type', ctypes.c_uint32), + ('base_type', glsl_base_type, 8), + ('sampled_type', glsl_base_type, 8), + ('sampler_dimensionality', glsl_base_type, 4), + ('sampler_shadow', glsl_base_type, 1), + ('sampler_array', glsl_base_type, 1), + ('interface_packing', glsl_base_type, 2), + ('interface_row_major', glsl_base_type, 1), + ('PADDING_0', ctypes.c_uint8, 7), + ('cmat_desc', struct_glsl_cmat_description), + ('packed', ctypes.c_uint32, 1), + ('has_builtin_name', ctypes.c_uint32, 1), + ('PADDING_1', ctypes.c_uint8, 6), + ('vector_elements', ctypes.c_uint32, 8), + ('matrix_columns', ctypes.c_ubyte), + ('PADDING_2', ctypes.c_ubyte), + ('length', ctypes.c_uint32), + ('PADDING_3', ctypes.c_ubyte * 4), + ('name_id', ctypes.c_uint64), + ('explicit_stride', ctypes.c_uint32), + ('explicit_alignment', ctypes.c_uint32), + ('fields', union_glsl_type_fields), +] + +glsl_type = struct_glsl_type + +# values for enumeration 'pipe_format' +pipe_format__enumvalues = { + 0: 'PIPE_FORMAT_NONE', + 1: 'PIPE_FORMAT_R64_UINT', + 2: 'PIPE_FORMAT_R64G64_UINT', + 3: 'PIPE_FORMAT_R64G64B64_UINT', + 4: 'PIPE_FORMAT_R64G64B64A64_UINT', + 5: 'PIPE_FORMAT_R64_SINT', + 6: 'PIPE_FORMAT_R64G64_SINT', + 7: 'PIPE_FORMAT_R64G64B64_SINT', + 8: 'PIPE_FORMAT_R64G64B64A64_SINT', + 9: 'PIPE_FORMAT_R64_FLOAT', + 10: 'PIPE_FORMAT_R64G64_FLOAT', + 11: 'PIPE_FORMAT_R64G64B64_FLOAT', + 12: 'PIPE_FORMAT_R64G64B64A64_FLOAT', + 13: 'PIPE_FORMAT_R32_FLOAT', + 14: 'PIPE_FORMAT_R32G32_FLOAT', + 15: 'PIPE_FORMAT_R32G32B32_FLOAT', + 16: 'PIPE_FORMAT_R32G32B32A32_FLOAT', + 17: 'PIPE_FORMAT_R32_UNORM', + 18: 'PIPE_FORMAT_R32G32_UNORM', + 19: 'PIPE_FORMAT_R32G32B32_UNORM', + 20: 'PIPE_FORMAT_R32G32B32A32_UNORM', + 21: 'PIPE_FORMAT_R32_USCALED', + 22: 'PIPE_FORMAT_R32G32_USCALED', + 23: 'PIPE_FORMAT_R32G32B32_USCALED', + 24: 'PIPE_FORMAT_R32G32B32A32_USCALED', + 25: 'PIPE_FORMAT_R32_SNORM', + 26: 'PIPE_FORMAT_R32G32_SNORM', + 27: 'PIPE_FORMAT_R32G32B32_SNORM', + 28: 'PIPE_FORMAT_R32G32B32A32_SNORM', + 29: 'PIPE_FORMAT_R32_SSCALED', + 30: 'PIPE_FORMAT_R32G32_SSCALED', + 31: 'PIPE_FORMAT_R32G32B32_SSCALED', + 32: 'PIPE_FORMAT_R32G32B32A32_SSCALED', + 33: 'PIPE_FORMAT_R16_UNORM', + 34: 'PIPE_FORMAT_R16G16_UNORM', + 35: 'PIPE_FORMAT_R16G16B16_UNORM', + 36: 'PIPE_FORMAT_R16G16B16A16_UNORM', + 37: 'PIPE_FORMAT_R16_USCALED', + 38: 'PIPE_FORMAT_R16G16_USCALED', + 39: 'PIPE_FORMAT_R16G16B16_USCALED', + 40: 'PIPE_FORMAT_R16G16B16A16_USCALED', + 41: 'PIPE_FORMAT_R16_SNORM', + 42: 'PIPE_FORMAT_R16G16_SNORM', + 43: 'PIPE_FORMAT_R16G16B16_SNORM', + 44: 'PIPE_FORMAT_R16G16B16A16_SNORM', + 45: 'PIPE_FORMAT_R16_SSCALED', + 46: 'PIPE_FORMAT_R16G16_SSCALED', + 47: 'PIPE_FORMAT_R16G16B16_SSCALED', + 48: 'PIPE_FORMAT_R16G16B16A16_SSCALED', + 49: 'PIPE_FORMAT_R8_UNORM', + 50: 'PIPE_FORMAT_R8G8_UNORM', + 51: 'PIPE_FORMAT_R8G8B8_UNORM', + 52: 'PIPE_FORMAT_B8G8R8_UNORM', + 53: 'PIPE_FORMAT_R8G8B8A8_UNORM', + 54: 'PIPE_FORMAT_B8G8R8A8_UNORM', + 55: 'PIPE_FORMAT_R8_USCALED', + 56: 'PIPE_FORMAT_R8G8_USCALED', + 57: 'PIPE_FORMAT_R8G8B8_USCALED', + 58: 'PIPE_FORMAT_B8G8R8_USCALED', + 59: 'PIPE_FORMAT_R8G8B8A8_USCALED', + 60: 'PIPE_FORMAT_B8G8R8A8_USCALED', + 61: 'PIPE_FORMAT_A8B8G8R8_USCALED', + 62: 'PIPE_FORMAT_R8_SNORM', + 63: 'PIPE_FORMAT_R8G8_SNORM', + 64: 'PIPE_FORMAT_R8G8B8_SNORM', + 65: 'PIPE_FORMAT_B8G8R8_SNORM', + 66: 'PIPE_FORMAT_R8G8B8A8_SNORM', + 67: 'PIPE_FORMAT_B8G8R8A8_SNORM', + 68: 'PIPE_FORMAT_R8_SSCALED', + 69: 'PIPE_FORMAT_R8G8_SSCALED', + 70: 'PIPE_FORMAT_R8G8B8_SSCALED', + 71: 'PIPE_FORMAT_B8G8R8_SSCALED', + 72: 'PIPE_FORMAT_R8G8B8A8_SSCALED', + 73: 'PIPE_FORMAT_B8G8R8A8_SSCALED', + 74: 'PIPE_FORMAT_A8B8G8R8_SSCALED', + 75: 'PIPE_FORMAT_A8R8G8B8_UNORM', + 76: 'PIPE_FORMAT_R32_FIXED', + 77: 'PIPE_FORMAT_R32G32_FIXED', + 78: 'PIPE_FORMAT_R32G32B32_FIXED', + 79: 'PIPE_FORMAT_R32G32B32A32_FIXED', + 80: 'PIPE_FORMAT_R16_FLOAT', + 81: 'PIPE_FORMAT_R16G16_FLOAT', + 82: 'PIPE_FORMAT_R16G16B16_FLOAT', + 83: 'PIPE_FORMAT_R16G16B16A16_FLOAT', + 84: 'PIPE_FORMAT_R8_UINT', + 85: 'PIPE_FORMAT_R8G8_UINT', + 86: 'PIPE_FORMAT_R8G8B8_UINT', + 87: 'PIPE_FORMAT_B8G8R8_UINT', + 88: 'PIPE_FORMAT_R8G8B8A8_UINT', + 89: 'PIPE_FORMAT_B8G8R8A8_UINT', + 90: 'PIPE_FORMAT_R8_SINT', + 91: 'PIPE_FORMAT_R8G8_SINT', + 92: 'PIPE_FORMAT_R8G8B8_SINT', + 93: 'PIPE_FORMAT_B8G8R8_SINT', + 94: 'PIPE_FORMAT_R8G8B8A8_SINT', + 95: 'PIPE_FORMAT_B8G8R8A8_SINT', + 96: 'PIPE_FORMAT_R16_UINT', + 97: 'PIPE_FORMAT_R16G16_UINT', + 98: 'PIPE_FORMAT_R16G16B16_UINT', + 99: 'PIPE_FORMAT_R16G16B16A16_UINT', + 100: 'PIPE_FORMAT_R16_SINT', + 101: 'PIPE_FORMAT_R16G16_SINT', + 102: 'PIPE_FORMAT_R16G16B16_SINT', + 103: 'PIPE_FORMAT_R16G16B16A16_SINT', + 104: 'PIPE_FORMAT_R32_UINT', + 105: 'PIPE_FORMAT_R32G32_UINT', + 106: 'PIPE_FORMAT_R32G32B32_UINT', + 107: 'PIPE_FORMAT_R32G32B32A32_UINT', + 108: 'PIPE_FORMAT_R32_SINT', + 109: 'PIPE_FORMAT_R32G32_SINT', + 110: 'PIPE_FORMAT_R32G32B32_SINT', + 111: 'PIPE_FORMAT_R32G32B32A32_SINT', + 112: 'PIPE_FORMAT_R10G10B10A2_UNORM', + 113: 'PIPE_FORMAT_R10G10B10A2_SNORM', + 114: 'PIPE_FORMAT_R10G10B10A2_USCALED', + 115: 'PIPE_FORMAT_R10G10B10A2_SSCALED', + 116: 'PIPE_FORMAT_B10G10R10A2_UNORM', + 117: 'PIPE_FORMAT_B10G10R10A2_SNORM', + 118: 'PIPE_FORMAT_B10G10R10A2_USCALED', + 119: 'PIPE_FORMAT_B10G10R10A2_SSCALED', + 120: 'PIPE_FORMAT_R11G11B10_FLOAT', + 121: 'PIPE_FORMAT_R10G10B10A2_UINT', + 122: 'PIPE_FORMAT_R10G10B10A2_SINT', + 123: 'PIPE_FORMAT_B10G10R10A2_UINT', + 124: 'PIPE_FORMAT_B10G10R10A2_SINT', + 125: 'PIPE_FORMAT_B8G8R8X8_UNORM', + 126: 'PIPE_FORMAT_X8B8G8R8_UNORM', + 127: 'PIPE_FORMAT_X8R8G8B8_UNORM', + 128: 'PIPE_FORMAT_B5G5R5A1_UNORM', + 129: 'PIPE_FORMAT_R4G4B4A4_UNORM', + 130: 'PIPE_FORMAT_B4G4R4A4_UNORM', + 131: 'PIPE_FORMAT_R5G6B5_UNORM', + 132: 'PIPE_FORMAT_B5G6R5_UNORM', + 133: 'PIPE_FORMAT_L8_UNORM', + 134: 'PIPE_FORMAT_A8_UNORM', + 135: 'PIPE_FORMAT_I8_UNORM', + 136: 'PIPE_FORMAT_L8A8_UNORM', + 137: 'PIPE_FORMAT_L16_UNORM', + 138: 'PIPE_FORMAT_UYVY', + 139: 'PIPE_FORMAT_VYUY', + 140: 'PIPE_FORMAT_YUYV', + 141: 'PIPE_FORMAT_YVYU', + 142: 'PIPE_FORMAT_Z16_UNORM', + 143: 'PIPE_FORMAT_Z16_UNORM_S8_UINT', + 144: 'PIPE_FORMAT_Z32_UNORM', + 145: 'PIPE_FORMAT_Z32_FLOAT', + 146: 'PIPE_FORMAT_Z24_UNORM_S8_UINT', + 147: 'PIPE_FORMAT_S8_UINT_Z24_UNORM', + 148: 'PIPE_FORMAT_Z24X8_UNORM', + 149: 'PIPE_FORMAT_X8Z24_UNORM', + 150: 'PIPE_FORMAT_S8_UINT', + 151: 'PIPE_FORMAT_L8_SRGB', + 152: 'PIPE_FORMAT_R8_SRGB', + 153: 'PIPE_FORMAT_L8A8_SRGB', + 154: 'PIPE_FORMAT_R8G8_SRGB', + 155: 'PIPE_FORMAT_R8G8B8_SRGB', + 156: 'PIPE_FORMAT_B8G8R8_SRGB', + 157: 'PIPE_FORMAT_A8B8G8R8_SRGB', + 158: 'PIPE_FORMAT_X8B8G8R8_SRGB', + 159: 'PIPE_FORMAT_B8G8R8A8_SRGB', + 160: 'PIPE_FORMAT_B8G8R8X8_SRGB', + 161: 'PIPE_FORMAT_A8R8G8B8_SRGB', + 162: 'PIPE_FORMAT_X8R8G8B8_SRGB', + 163: 'PIPE_FORMAT_R8G8B8A8_SRGB', + 164: 'PIPE_FORMAT_DXT1_RGB', + 165: 'PIPE_FORMAT_DXT1_RGBA', + 166: 'PIPE_FORMAT_DXT3_RGBA', + 167: 'PIPE_FORMAT_DXT5_RGBA', + 168: 'PIPE_FORMAT_DXT1_SRGB', + 169: 'PIPE_FORMAT_DXT1_SRGBA', + 170: 'PIPE_FORMAT_DXT3_SRGBA', + 171: 'PIPE_FORMAT_DXT5_SRGBA', + 172: 'PIPE_FORMAT_RGTC1_UNORM', + 173: 'PIPE_FORMAT_RGTC1_SNORM', + 174: 'PIPE_FORMAT_RGTC2_UNORM', + 175: 'PIPE_FORMAT_RGTC2_SNORM', + 176: 'PIPE_FORMAT_R8G8_B8G8_UNORM', + 177: 'PIPE_FORMAT_G8R8_G8B8_UNORM', + 178: 'PIPE_FORMAT_X6G10_X6B10X6R10_420_UNORM', + 179: 'PIPE_FORMAT_X4G12_X4B12X4R12_420_UNORM', + 180: 'PIPE_FORMAT_X6R10_UNORM', + 181: 'PIPE_FORMAT_X6R10X6G10_UNORM', + 182: 'PIPE_FORMAT_X4R12_UNORM', + 183: 'PIPE_FORMAT_X4R12X4G12_UNORM', + 184: 'PIPE_FORMAT_R8SG8SB8UX8U_NORM', + 185: 'PIPE_FORMAT_R5SG5SB6U_NORM', + 186: 'PIPE_FORMAT_A8B8G8R8_UNORM', + 187: 'PIPE_FORMAT_B5G5R5X1_UNORM', + 188: 'PIPE_FORMAT_R9G9B9E5_FLOAT', + 189: 'PIPE_FORMAT_Z32_FLOAT_S8X24_UINT', + 190: 'PIPE_FORMAT_R1_UNORM', + 191: 'PIPE_FORMAT_R10G10B10X2_USCALED', + 192: 'PIPE_FORMAT_R10G10B10X2_SNORM', + 193: 'PIPE_FORMAT_L4A4_UNORM', + 194: 'PIPE_FORMAT_A2R10G10B10_UNORM', + 195: 'PIPE_FORMAT_A2B10G10R10_UNORM', + 196: 'PIPE_FORMAT_R10SG10SB10SA2U_NORM', + 197: 'PIPE_FORMAT_R8G8Bx_SNORM', + 198: 'PIPE_FORMAT_R8G8B8X8_UNORM', + 199: 'PIPE_FORMAT_B4G4R4X4_UNORM', + 200: 'PIPE_FORMAT_X24S8_UINT', + 201: 'PIPE_FORMAT_S8X24_UINT', + 202: 'PIPE_FORMAT_X32_S8X24_UINT', + 203: 'PIPE_FORMAT_R3G3B2_UNORM', + 204: 'PIPE_FORMAT_B2G3R3_UNORM', + 205: 'PIPE_FORMAT_L16A16_UNORM', + 206: 'PIPE_FORMAT_A16_UNORM', + 207: 'PIPE_FORMAT_I16_UNORM', + 208: 'PIPE_FORMAT_LATC1_UNORM', + 209: 'PIPE_FORMAT_LATC1_SNORM', + 210: 'PIPE_FORMAT_LATC2_UNORM', + 211: 'PIPE_FORMAT_LATC2_SNORM', + 212: 'PIPE_FORMAT_A8_SNORM', + 213: 'PIPE_FORMAT_L8_SNORM', + 214: 'PIPE_FORMAT_L8A8_SNORM', + 215: 'PIPE_FORMAT_I8_SNORM', + 216: 'PIPE_FORMAT_A16_SNORM', + 217: 'PIPE_FORMAT_L16_SNORM', + 218: 'PIPE_FORMAT_L16A16_SNORM', + 219: 'PIPE_FORMAT_I16_SNORM', + 220: 'PIPE_FORMAT_A16_FLOAT', + 221: 'PIPE_FORMAT_L16_FLOAT', + 222: 'PIPE_FORMAT_L16A16_FLOAT', + 223: 'PIPE_FORMAT_I16_FLOAT', + 224: 'PIPE_FORMAT_A32_FLOAT', + 225: 'PIPE_FORMAT_L32_FLOAT', + 226: 'PIPE_FORMAT_L32A32_FLOAT', + 227: 'PIPE_FORMAT_I32_FLOAT', + 228: 'PIPE_FORMAT_YV12', + 229: 'PIPE_FORMAT_YV16', + 230: 'PIPE_FORMAT_IYUV', + 231: 'PIPE_FORMAT_NV12', + 232: 'PIPE_FORMAT_NV21', + 233: 'PIPE_FORMAT_NV16', + 234: 'PIPE_FORMAT_NV15', + 235: 'PIPE_FORMAT_NV20', + 236: 'PIPE_FORMAT_Y8_400_UNORM', + 237: 'PIPE_FORMAT_Y8_U8_V8_422_UNORM', + 238: 'PIPE_FORMAT_Y8_U8_V8_444_UNORM', + 239: 'PIPE_FORMAT_Y8_U8_V8_440_UNORM', + 240: 'PIPE_FORMAT_Y10X6_U10X6_V10X6_420_UNORM', + 241: 'PIPE_FORMAT_Y10X6_U10X6_V10X6_422_UNORM', + 242: 'PIPE_FORMAT_Y10X6_U10X6_V10X6_444_UNORM', + 243: 'PIPE_FORMAT_Y12X4_U12X4_V12X4_420_UNORM', + 244: 'PIPE_FORMAT_Y12X4_U12X4_V12X4_422_UNORM', + 245: 'PIPE_FORMAT_Y12X4_U12X4_V12X4_444_UNORM', + 246: 'PIPE_FORMAT_Y16_U16_V16_420_UNORM', + 247: 'PIPE_FORMAT_Y16_U16_V16_422_UNORM', + 248: 'PIPE_FORMAT_Y16_U16V16_422_UNORM', + 249: 'PIPE_FORMAT_Y16_U16_V16_444_UNORM', + 250: 'PIPE_FORMAT_Y8U8V8_420_UNORM_PACKED', + 251: 'PIPE_FORMAT_Y10U10V10_420_UNORM_PACKED', + 252: 'PIPE_FORMAT_A4R4_UNORM', + 253: 'PIPE_FORMAT_R4A4_UNORM', + 254: 'PIPE_FORMAT_R8A8_UNORM', + 255: 'PIPE_FORMAT_A8R8_UNORM', + 256: 'PIPE_FORMAT_A8_UINT', + 257: 'PIPE_FORMAT_I8_UINT', + 258: 'PIPE_FORMAT_L8_UINT', + 259: 'PIPE_FORMAT_L8A8_UINT', + 260: 'PIPE_FORMAT_A8_SINT', + 261: 'PIPE_FORMAT_I8_SINT', + 262: 'PIPE_FORMAT_L8_SINT', + 263: 'PIPE_FORMAT_L8A8_SINT', + 264: 'PIPE_FORMAT_A16_UINT', + 265: 'PIPE_FORMAT_I16_UINT', + 266: 'PIPE_FORMAT_L16_UINT', + 267: 'PIPE_FORMAT_L16A16_UINT', + 268: 'PIPE_FORMAT_A16_SINT', + 269: 'PIPE_FORMAT_I16_SINT', + 270: 'PIPE_FORMAT_L16_SINT', + 271: 'PIPE_FORMAT_L16A16_SINT', + 272: 'PIPE_FORMAT_A32_UINT', + 273: 'PIPE_FORMAT_I32_UINT', + 274: 'PIPE_FORMAT_L32_UINT', + 275: 'PIPE_FORMAT_L32A32_UINT', + 276: 'PIPE_FORMAT_A32_SINT', + 277: 'PIPE_FORMAT_I32_SINT', + 278: 'PIPE_FORMAT_L32_SINT', + 279: 'PIPE_FORMAT_L32A32_SINT', + 280: 'PIPE_FORMAT_A8R8G8B8_UINT', + 281: 'PIPE_FORMAT_A8B8G8R8_UINT', + 282: 'PIPE_FORMAT_A2R10G10B10_UINT', + 283: 'PIPE_FORMAT_A2B10G10R10_UINT', + 284: 'PIPE_FORMAT_R5G6B5_UINT', + 285: 'PIPE_FORMAT_B5G6R5_UINT', + 286: 'PIPE_FORMAT_R5G5B5A1_UINT', + 287: 'PIPE_FORMAT_B5G5R5A1_UINT', + 288: 'PIPE_FORMAT_A1R5G5B5_UINT', + 289: 'PIPE_FORMAT_A1B5G5R5_UINT', + 290: 'PIPE_FORMAT_R4G4B4A4_UINT', + 291: 'PIPE_FORMAT_B4G4R4A4_UINT', + 292: 'PIPE_FORMAT_A4R4G4B4_UINT', + 293: 'PIPE_FORMAT_A4B4G4R4_UINT', + 294: 'PIPE_FORMAT_R3G3B2_UINT', + 295: 'PIPE_FORMAT_B2G3R3_UINT', + 296: 'PIPE_FORMAT_ETC1_RGB8', + 297: 'PIPE_FORMAT_R8G8_R8B8_UNORM', + 298: 'PIPE_FORMAT_R8B8_R8G8_UNORM', + 299: 'PIPE_FORMAT_G8R8_B8R8_UNORM', + 300: 'PIPE_FORMAT_B8R8_G8R8_UNORM', + 301: 'PIPE_FORMAT_G8B8_G8R8_UNORM', + 302: 'PIPE_FORMAT_B8G8_R8G8_UNORM', + 303: 'PIPE_FORMAT_R8G8B8X8_SNORM', + 304: 'PIPE_FORMAT_R8G8B8X8_SRGB', + 305: 'PIPE_FORMAT_R8G8B8X8_UINT', + 306: 'PIPE_FORMAT_R8G8B8X8_SINT', + 307: 'PIPE_FORMAT_B10G10R10X2_UNORM', + 308: 'PIPE_FORMAT_R16G16B16X16_UNORM', + 309: 'PIPE_FORMAT_R16G16B16X16_SNORM', + 310: 'PIPE_FORMAT_R16G16B16X16_FLOAT', + 311: 'PIPE_FORMAT_R16G16B16X16_UINT', + 312: 'PIPE_FORMAT_R16G16B16X16_SINT', + 313: 'PIPE_FORMAT_R32G32B32X32_FLOAT', + 314: 'PIPE_FORMAT_R32G32B32X32_UINT', + 315: 'PIPE_FORMAT_R32G32B32X32_SINT', + 316: 'PIPE_FORMAT_R8A8_SNORM', + 317: 'PIPE_FORMAT_R16A16_UNORM', + 318: 'PIPE_FORMAT_R16A16_SNORM', + 319: 'PIPE_FORMAT_R16A16_FLOAT', + 320: 'PIPE_FORMAT_R32A32_FLOAT', + 321: 'PIPE_FORMAT_R8A8_UINT', + 322: 'PIPE_FORMAT_R8A8_SINT', + 323: 'PIPE_FORMAT_R16A16_UINT', + 324: 'PIPE_FORMAT_R16A16_SINT', + 325: 'PIPE_FORMAT_R32A32_UINT', + 326: 'PIPE_FORMAT_R32A32_SINT', + 327: 'PIPE_FORMAT_B5G6R5_SRGB', + 328: 'PIPE_FORMAT_BPTC_RGBA_UNORM', + 329: 'PIPE_FORMAT_BPTC_SRGBA', + 330: 'PIPE_FORMAT_BPTC_RGB_FLOAT', + 331: 'PIPE_FORMAT_BPTC_RGB_UFLOAT', + 332: 'PIPE_FORMAT_G8R8_UNORM', + 333: 'PIPE_FORMAT_G8R8_SNORM', + 334: 'PIPE_FORMAT_G16R16_UNORM', + 335: 'PIPE_FORMAT_G16R16_SNORM', + 336: 'PIPE_FORMAT_A8B8G8R8_SNORM', + 337: 'PIPE_FORMAT_X8B8G8R8_SNORM', + 338: 'PIPE_FORMAT_ETC2_RGB8', + 339: 'PIPE_FORMAT_ETC2_SRGB8', + 340: 'PIPE_FORMAT_ETC2_RGB8A1', + 341: 'PIPE_FORMAT_ETC2_SRGB8A1', + 342: 'PIPE_FORMAT_ETC2_RGBA8', + 343: 'PIPE_FORMAT_ETC2_SRGBA8', + 344: 'PIPE_FORMAT_ETC2_R11_UNORM', + 345: 'PIPE_FORMAT_ETC2_R11_SNORM', + 346: 'PIPE_FORMAT_ETC2_RG11_UNORM', + 347: 'PIPE_FORMAT_ETC2_RG11_SNORM', + 348: 'PIPE_FORMAT_ASTC_4x4', + 349: 'PIPE_FORMAT_ASTC_5x4', + 350: 'PIPE_FORMAT_ASTC_5x5', + 351: 'PIPE_FORMAT_ASTC_6x5', + 352: 'PIPE_FORMAT_ASTC_6x6', + 353: 'PIPE_FORMAT_ASTC_8x5', + 354: 'PIPE_FORMAT_ASTC_8x6', + 355: 'PIPE_FORMAT_ASTC_8x8', + 356: 'PIPE_FORMAT_ASTC_10x5', + 357: 'PIPE_FORMAT_ASTC_10x6', + 358: 'PIPE_FORMAT_ASTC_10x8', + 359: 'PIPE_FORMAT_ASTC_10x10', + 360: 'PIPE_FORMAT_ASTC_12x10', + 361: 'PIPE_FORMAT_ASTC_12x12', + 362: 'PIPE_FORMAT_ASTC_4x4_SRGB', + 363: 'PIPE_FORMAT_ASTC_5x4_SRGB', + 364: 'PIPE_FORMAT_ASTC_5x5_SRGB', + 365: 'PIPE_FORMAT_ASTC_6x5_SRGB', + 366: 'PIPE_FORMAT_ASTC_6x6_SRGB', + 367: 'PIPE_FORMAT_ASTC_8x5_SRGB', + 368: 'PIPE_FORMAT_ASTC_8x6_SRGB', + 369: 'PIPE_FORMAT_ASTC_8x8_SRGB', + 370: 'PIPE_FORMAT_ASTC_10x5_SRGB', + 371: 'PIPE_FORMAT_ASTC_10x6_SRGB', + 372: 'PIPE_FORMAT_ASTC_10x8_SRGB', + 373: 'PIPE_FORMAT_ASTC_10x10_SRGB', + 374: 'PIPE_FORMAT_ASTC_12x10_SRGB', + 375: 'PIPE_FORMAT_ASTC_12x12_SRGB', + 376: 'PIPE_FORMAT_ASTC_3x3x3', + 377: 'PIPE_FORMAT_ASTC_4x3x3', + 378: 'PIPE_FORMAT_ASTC_4x4x3', + 379: 'PIPE_FORMAT_ASTC_4x4x4', + 380: 'PIPE_FORMAT_ASTC_5x4x4', + 381: 'PIPE_FORMAT_ASTC_5x5x4', + 382: 'PIPE_FORMAT_ASTC_5x5x5', + 383: 'PIPE_FORMAT_ASTC_6x5x5', + 384: 'PIPE_FORMAT_ASTC_6x6x5', + 385: 'PIPE_FORMAT_ASTC_6x6x6', + 386: 'PIPE_FORMAT_ASTC_3x3x3_SRGB', + 387: 'PIPE_FORMAT_ASTC_4x3x3_SRGB', + 388: 'PIPE_FORMAT_ASTC_4x4x3_SRGB', + 389: 'PIPE_FORMAT_ASTC_4x4x4_SRGB', + 390: 'PIPE_FORMAT_ASTC_5x4x4_SRGB', + 391: 'PIPE_FORMAT_ASTC_5x5x4_SRGB', + 392: 'PIPE_FORMAT_ASTC_5x5x5_SRGB', + 393: 'PIPE_FORMAT_ASTC_6x5x5_SRGB', + 394: 'PIPE_FORMAT_ASTC_6x6x5_SRGB', + 395: 'PIPE_FORMAT_ASTC_6x6x6_SRGB', + 396: 'PIPE_FORMAT_ASTC_4x4_FLOAT', + 397: 'PIPE_FORMAT_ASTC_5x4_FLOAT', + 398: 'PIPE_FORMAT_ASTC_5x5_FLOAT', + 399: 'PIPE_FORMAT_ASTC_6x5_FLOAT', + 400: 'PIPE_FORMAT_ASTC_6x6_FLOAT', + 401: 'PIPE_FORMAT_ASTC_8x5_FLOAT', + 402: 'PIPE_FORMAT_ASTC_8x6_FLOAT', + 403: 'PIPE_FORMAT_ASTC_8x8_FLOAT', + 404: 'PIPE_FORMAT_ASTC_10x5_FLOAT', + 405: 'PIPE_FORMAT_ASTC_10x6_FLOAT', + 406: 'PIPE_FORMAT_ASTC_10x8_FLOAT', + 407: 'PIPE_FORMAT_ASTC_10x10_FLOAT', + 408: 'PIPE_FORMAT_ASTC_12x10_FLOAT', + 409: 'PIPE_FORMAT_ASTC_12x12_FLOAT', + 410: 'PIPE_FORMAT_FXT1_RGB', + 411: 'PIPE_FORMAT_FXT1_RGBA', + 412: 'PIPE_FORMAT_P010', + 413: 'PIPE_FORMAT_P012', + 414: 'PIPE_FORMAT_P016', + 415: 'PIPE_FORMAT_P030', + 416: 'PIPE_FORMAT_Y210', + 417: 'PIPE_FORMAT_Y212', + 418: 'PIPE_FORMAT_Y216', + 419: 'PIPE_FORMAT_Y410', + 420: 'PIPE_FORMAT_Y412', + 421: 'PIPE_FORMAT_Y416', + 422: 'PIPE_FORMAT_R10G10B10X2_UNORM', + 423: 'PIPE_FORMAT_A1R5G5B5_UNORM', + 424: 'PIPE_FORMAT_A1B5G5R5_UNORM', + 425: 'PIPE_FORMAT_X1B5G5R5_UNORM', + 426: 'PIPE_FORMAT_R5G5B5A1_UNORM', + 427: 'PIPE_FORMAT_A4R4G4B4_UNORM', + 428: 'PIPE_FORMAT_A4B4G4R4_UNORM', + 429: 'PIPE_FORMAT_G8R8_SINT', + 430: 'PIPE_FORMAT_A8B8G8R8_SINT', + 431: 'PIPE_FORMAT_X8B8G8R8_SINT', + 432: 'PIPE_FORMAT_ATC_RGB', + 433: 'PIPE_FORMAT_ATC_RGBA_EXPLICIT', + 434: 'PIPE_FORMAT_ATC_RGBA_INTERPOLATED', + 435: 'PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8', + 436: 'PIPE_FORMAT_AYUV', + 437: 'PIPE_FORMAT_XYUV', + 438: 'PIPE_FORMAT_R8G8B8_420_UNORM_PACKED', + 439: 'PIPE_FORMAT_R8_G8B8_420_UNORM', + 440: 'PIPE_FORMAT_R8_B8G8_420_UNORM', + 441: 'PIPE_FORMAT_G8_B8R8_420_UNORM', + 442: 'PIPE_FORMAT_R10G10B10_420_UNORM_PACKED', + 443: 'PIPE_FORMAT_R10_G10B10_420_UNORM', + 444: 'PIPE_FORMAT_R10_G10B10_422_UNORM', + 445: 'PIPE_FORMAT_R8_G8_B8_420_UNORM', + 446: 'PIPE_FORMAT_R8_B8_G8_420_UNORM', + 447: 'PIPE_FORMAT_G8_B8_R8_420_UNORM', + 448: 'PIPE_FORMAT_R8_G8B8_422_UNORM', + 449: 'PIPE_FORMAT_R8_B8G8_422_UNORM', + 450: 'PIPE_FORMAT_G8_B8R8_422_UNORM', + 451: 'PIPE_FORMAT_R8_G8_B8_UNORM', + 452: 'PIPE_FORMAT_Y8_UNORM', + 453: 'PIPE_FORMAT_B8G8R8X8_SNORM', + 454: 'PIPE_FORMAT_B8G8R8X8_UINT', + 455: 'PIPE_FORMAT_B8G8R8X8_SINT', + 456: 'PIPE_FORMAT_A8R8G8B8_SNORM', + 457: 'PIPE_FORMAT_A8R8G8B8_SINT', + 458: 'PIPE_FORMAT_X8R8G8B8_SNORM', + 459: 'PIPE_FORMAT_X8R8G8B8_SINT', + 460: 'PIPE_FORMAT_R5G5B5X1_UNORM', + 461: 'PIPE_FORMAT_X1R5G5B5_UNORM', + 462: 'PIPE_FORMAT_R4G4B4X4_UNORM', + 463: 'PIPE_FORMAT_B10G10R10X2_SNORM', + 464: 'PIPE_FORMAT_R5G6B5_SRGB', + 465: 'PIPE_FORMAT_R10G10B10X2_SINT', + 466: 'PIPE_FORMAT_B10G10R10X2_SINT', + 467: 'PIPE_FORMAT_G16R16_SINT', + 468: 'PIPE_FORMAT_COUNT', +} +PIPE_FORMAT_NONE = 0 +PIPE_FORMAT_R64_UINT = 1 +PIPE_FORMAT_R64G64_UINT = 2 +PIPE_FORMAT_R64G64B64_UINT = 3 +PIPE_FORMAT_R64G64B64A64_UINT = 4 +PIPE_FORMAT_R64_SINT = 5 +PIPE_FORMAT_R64G64_SINT = 6 +PIPE_FORMAT_R64G64B64_SINT = 7 +PIPE_FORMAT_R64G64B64A64_SINT = 8 +PIPE_FORMAT_R64_FLOAT = 9 +PIPE_FORMAT_R64G64_FLOAT = 10 +PIPE_FORMAT_R64G64B64_FLOAT = 11 +PIPE_FORMAT_R64G64B64A64_FLOAT = 12 +PIPE_FORMAT_R32_FLOAT = 13 +PIPE_FORMAT_R32G32_FLOAT = 14 +PIPE_FORMAT_R32G32B32_FLOAT = 15 +PIPE_FORMAT_R32G32B32A32_FLOAT = 16 +PIPE_FORMAT_R32_UNORM = 17 +PIPE_FORMAT_R32G32_UNORM = 18 +PIPE_FORMAT_R32G32B32_UNORM = 19 +PIPE_FORMAT_R32G32B32A32_UNORM = 20 +PIPE_FORMAT_R32_USCALED = 21 +PIPE_FORMAT_R32G32_USCALED = 22 +PIPE_FORMAT_R32G32B32_USCALED = 23 +PIPE_FORMAT_R32G32B32A32_USCALED = 24 +PIPE_FORMAT_R32_SNORM = 25 +PIPE_FORMAT_R32G32_SNORM = 26 +PIPE_FORMAT_R32G32B32_SNORM = 27 +PIPE_FORMAT_R32G32B32A32_SNORM = 28 +PIPE_FORMAT_R32_SSCALED = 29 +PIPE_FORMAT_R32G32_SSCALED = 30 +PIPE_FORMAT_R32G32B32_SSCALED = 31 +PIPE_FORMAT_R32G32B32A32_SSCALED = 32 +PIPE_FORMAT_R16_UNORM = 33 +PIPE_FORMAT_R16G16_UNORM = 34 +PIPE_FORMAT_R16G16B16_UNORM = 35 +PIPE_FORMAT_R16G16B16A16_UNORM = 36 +PIPE_FORMAT_R16_USCALED = 37 +PIPE_FORMAT_R16G16_USCALED = 38 +PIPE_FORMAT_R16G16B16_USCALED = 39 +PIPE_FORMAT_R16G16B16A16_USCALED = 40 +PIPE_FORMAT_R16_SNORM = 41 +PIPE_FORMAT_R16G16_SNORM = 42 +PIPE_FORMAT_R16G16B16_SNORM = 43 +PIPE_FORMAT_R16G16B16A16_SNORM = 44 +PIPE_FORMAT_R16_SSCALED = 45 +PIPE_FORMAT_R16G16_SSCALED = 46 +PIPE_FORMAT_R16G16B16_SSCALED = 47 +PIPE_FORMAT_R16G16B16A16_SSCALED = 48 +PIPE_FORMAT_R8_UNORM = 49 +PIPE_FORMAT_R8G8_UNORM = 50 +PIPE_FORMAT_R8G8B8_UNORM = 51 +PIPE_FORMAT_B8G8R8_UNORM = 52 +PIPE_FORMAT_R8G8B8A8_UNORM = 53 +PIPE_FORMAT_B8G8R8A8_UNORM = 54 +PIPE_FORMAT_R8_USCALED = 55 +PIPE_FORMAT_R8G8_USCALED = 56 +PIPE_FORMAT_R8G8B8_USCALED = 57 +PIPE_FORMAT_B8G8R8_USCALED = 58 +PIPE_FORMAT_R8G8B8A8_USCALED = 59 +PIPE_FORMAT_B8G8R8A8_USCALED = 60 +PIPE_FORMAT_A8B8G8R8_USCALED = 61 +PIPE_FORMAT_R8_SNORM = 62 +PIPE_FORMAT_R8G8_SNORM = 63 +PIPE_FORMAT_R8G8B8_SNORM = 64 +PIPE_FORMAT_B8G8R8_SNORM = 65 +PIPE_FORMAT_R8G8B8A8_SNORM = 66 +PIPE_FORMAT_B8G8R8A8_SNORM = 67 +PIPE_FORMAT_R8_SSCALED = 68 +PIPE_FORMAT_R8G8_SSCALED = 69 +PIPE_FORMAT_R8G8B8_SSCALED = 70 +PIPE_FORMAT_B8G8R8_SSCALED = 71 +PIPE_FORMAT_R8G8B8A8_SSCALED = 72 +PIPE_FORMAT_B8G8R8A8_SSCALED = 73 +PIPE_FORMAT_A8B8G8R8_SSCALED = 74 +PIPE_FORMAT_A8R8G8B8_UNORM = 75 +PIPE_FORMAT_R32_FIXED = 76 +PIPE_FORMAT_R32G32_FIXED = 77 +PIPE_FORMAT_R32G32B32_FIXED = 78 +PIPE_FORMAT_R32G32B32A32_FIXED = 79 +PIPE_FORMAT_R16_FLOAT = 80 +PIPE_FORMAT_R16G16_FLOAT = 81 +PIPE_FORMAT_R16G16B16_FLOAT = 82 +PIPE_FORMAT_R16G16B16A16_FLOAT = 83 +PIPE_FORMAT_R8_UINT = 84 +PIPE_FORMAT_R8G8_UINT = 85 +PIPE_FORMAT_R8G8B8_UINT = 86 +PIPE_FORMAT_B8G8R8_UINT = 87 +PIPE_FORMAT_R8G8B8A8_UINT = 88 +PIPE_FORMAT_B8G8R8A8_UINT = 89 +PIPE_FORMAT_R8_SINT = 90 +PIPE_FORMAT_R8G8_SINT = 91 +PIPE_FORMAT_R8G8B8_SINT = 92 +PIPE_FORMAT_B8G8R8_SINT = 93 +PIPE_FORMAT_R8G8B8A8_SINT = 94 +PIPE_FORMAT_B8G8R8A8_SINT = 95 +PIPE_FORMAT_R16_UINT = 96 +PIPE_FORMAT_R16G16_UINT = 97 +PIPE_FORMAT_R16G16B16_UINT = 98 +PIPE_FORMAT_R16G16B16A16_UINT = 99 +PIPE_FORMAT_R16_SINT = 100 +PIPE_FORMAT_R16G16_SINT = 101 +PIPE_FORMAT_R16G16B16_SINT = 102 +PIPE_FORMAT_R16G16B16A16_SINT = 103 +PIPE_FORMAT_R32_UINT = 104 +PIPE_FORMAT_R32G32_UINT = 105 +PIPE_FORMAT_R32G32B32_UINT = 106 +PIPE_FORMAT_R32G32B32A32_UINT = 107 +PIPE_FORMAT_R32_SINT = 108 +PIPE_FORMAT_R32G32_SINT = 109 +PIPE_FORMAT_R32G32B32_SINT = 110 +PIPE_FORMAT_R32G32B32A32_SINT = 111 +PIPE_FORMAT_R10G10B10A2_UNORM = 112 +PIPE_FORMAT_R10G10B10A2_SNORM = 113 +PIPE_FORMAT_R10G10B10A2_USCALED = 114 +PIPE_FORMAT_R10G10B10A2_SSCALED = 115 +PIPE_FORMAT_B10G10R10A2_UNORM = 116 +PIPE_FORMAT_B10G10R10A2_SNORM = 117 +PIPE_FORMAT_B10G10R10A2_USCALED = 118 +PIPE_FORMAT_B10G10R10A2_SSCALED = 119 +PIPE_FORMAT_R11G11B10_FLOAT = 120 +PIPE_FORMAT_R10G10B10A2_UINT = 121 +PIPE_FORMAT_R10G10B10A2_SINT = 122 +PIPE_FORMAT_B10G10R10A2_UINT = 123 +PIPE_FORMAT_B10G10R10A2_SINT = 124 +PIPE_FORMAT_B8G8R8X8_UNORM = 125 +PIPE_FORMAT_X8B8G8R8_UNORM = 126 +PIPE_FORMAT_X8R8G8B8_UNORM = 127 +PIPE_FORMAT_B5G5R5A1_UNORM = 128 +PIPE_FORMAT_R4G4B4A4_UNORM = 129 +PIPE_FORMAT_B4G4R4A4_UNORM = 130 +PIPE_FORMAT_R5G6B5_UNORM = 131 +PIPE_FORMAT_B5G6R5_UNORM = 132 +PIPE_FORMAT_L8_UNORM = 133 +PIPE_FORMAT_A8_UNORM = 134 +PIPE_FORMAT_I8_UNORM = 135 +PIPE_FORMAT_L8A8_UNORM = 136 +PIPE_FORMAT_L16_UNORM = 137 +PIPE_FORMAT_UYVY = 138 +PIPE_FORMAT_VYUY = 139 +PIPE_FORMAT_YUYV = 140 +PIPE_FORMAT_YVYU = 141 +PIPE_FORMAT_Z16_UNORM = 142 +PIPE_FORMAT_Z16_UNORM_S8_UINT = 143 +PIPE_FORMAT_Z32_UNORM = 144 +PIPE_FORMAT_Z32_FLOAT = 145 +PIPE_FORMAT_Z24_UNORM_S8_UINT = 146 +PIPE_FORMAT_S8_UINT_Z24_UNORM = 147 +PIPE_FORMAT_Z24X8_UNORM = 148 +PIPE_FORMAT_X8Z24_UNORM = 149 +PIPE_FORMAT_S8_UINT = 150 +PIPE_FORMAT_L8_SRGB = 151 +PIPE_FORMAT_R8_SRGB = 152 +PIPE_FORMAT_L8A8_SRGB = 153 +PIPE_FORMAT_R8G8_SRGB = 154 +PIPE_FORMAT_R8G8B8_SRGB = 155 +PIPE_FORMAT_B8G8R8_SRGB = 156 +PIPE_FORMAT_A8B8G8R8_SRGB = 157 +PIPE_FORMAT_X8B8G8R8_SRGB = 158 +PIPE_FORMAT_B8G8R8A8_SRGB = 159 +PIPE_FORMAT_B8G8R8X8_SRGB = 160 +PIPE_FORMAT_A8R8G8B8_SRGB = 161 +PIPE_FORMAT_X8R8G8B8_SRGB = 162 +PIPE_FORMAT_R8G8B8A8_SRGB = 163 +PIPE_FORMAT_DXT1_RGB = 164 +PIPE_FORMAT_DXT1_RGBA = 165 +PIPE_FORMAT_DXT3_RGBA = 166 +PIPE_FORMAT_DXT5_RGBA = 167 +PIPE_FORMAT_DXT1_SRGB = 168 +PIPE_FORMAT_DXT1_SRGBA = 169 +PIPE_FORMAT_DXT3_SRGBA = 170 +PIPE_FORMAT_DXT5_SRGBA = 171 +PIPE_FORMAT_RGTC1_UNORM = 172 +PIPE_FORMAT_RGTC1_SNORM = 173 +PIPE_FORMAT_RGTC2_UNORM = 174 +PIPE_FORMAT_RGTC2_SNORM = 175 +PIPE_FORMAT_R8G8_B8G8_UNORM = 176 +PIPE_FORMAT_G8R8_G8B8_UNORM = 177 +PIPE_FORMAT_X6G10_X6B10X6R10_420_UNORM = 178 +PIPE_FORMAT_X4G12_X4B12X4R12_420_UNORM = 179 +PIPE_FORMAT_X6R10_UNORM = 180 +PIPE_FORMAT_X6R10X6G10_UNORM = 181 +PIPE_FORMAT_X4R12_UNORM = 182 +PIPE_FORMAT_X4R12X4G12_UNORM = 183 +PIPE_FORMAT_R8SG8SB8UX8U_NORM = 184 +PIPE_FORMAT_R5SG5SB6U_NORM = 185 +PIPE_FORMAT_A8B8G8R8_UNORM = 186 +PIPE_FORMAT_B5G5R5X1_UNORM = 187 +PIPE_FORMAT_R9G9B9E5_FLOAT = 188 +PIPE_FORMAT_Z32_FLOAT_S8X24_UINT = 189 +PIPE_FORMAT_R1_UNORM = 190 +PIPE_FORMAT_R10G10B10X2_USCALED = 191 +PIPE_FORMAT_R10G10B10X2_SNORM = 192 +PIPE_FORMAT_L4A4_UNORM = 193 +PIPE_FORMAT_A2R10G10B10_UNORM = 194 +PIPE_FORMAT_A2B10G10R10_UNORM = 195 +PIPE_FORMAT_R10SG10SB10SA2U_NORM = 196 +PIPE_FORMAT_R8G8Bx_SNORM = 197 +PIPE_FORMAT_R8G8B8X8_UNORM = 198 +PIPE_FORMAT_B4G4R4X4_UNORM = 199 +PIPE_FORMAT_X24S8_UINT = 200 +PIPE_FORMAT_S8X24_UINT = 201 +PIPE_FORMAT_X32_S8X24_UINT = 202 +PIPE_FORMAT_R3G3B2_UNORM = 203 +PIPE_FORMAT_B2G3R3_UNORM = 204 +PIPE_FORMAT_L16A16_UNORM = 205 +PIPE_FORMAT_A16_UNORM = 206 +PIPE_FORMAT_I16_UNORM = 207 +PIPE_FORMAT_LATC1_UNORM = 208 +PIPE_FORMAT_LATC1_SNORM = 209 +PIPE_FORMAT_LATC2_UNORM = 210 +PIPE_FORMAT_LATC2_SNORM = 211 +PIPE_FORMAT_A8_SNORM = 212 +PIPE_FORMAT_L8_SNORM = 213 +PIPE_FORMAT_L8A8_SNORM = 214 +PIPE_FORMAT_I8_SNORM = 215 +PIPE_FORMAT_A16_SNORM = 216 +PIPE_FORMAT_L16_SNORM = 217 +PIPE_FORMAT_L16A16_SNORM = 218 +PIPE_FORMAT_I16_SNORM = 219 +PIPE_FORMAT_A16_FLOAT = 220 +PIPE_FORMAT_L16_FLOAT = 221 +PIPE_FORMAT_L16A16_FLOAT = 222 +PIPE_FORMAT_I16_FLOAT = 223 +PIPE_FORMAT_A32_FLOAT = 224 +PIPE_FORMAT_L32_FLOAT = 225 +PIPE_FORMAT_L32A32_FLOAT = 226 +PIPE_FORMAT_I32_FLOAT = 227 +PIPE_FORMAT_YV12 = 228 +PIPE_FORMAT_YV16 = 229 +PIPE_FORMAT_IYUV = 230 +PIPE_FORMAT_NV12 = 231 +PIPE_FORMAT_NV21 = 232 +PIPE_FORMAT_NV16 = 233 +PIPE_FORMAT_NV15 = 234 +PIPE_FORMAT_NV20 = 235 +PIPE_FORMAT_Y8_400_UNORM = 236 +PIPE_FORMAT_Y8_U8_V8_422_UNORM = 237 +PIPE_FORMAT_Y8_U8_V8_444_UNORM = 238 +PIPE_FORMAT_Y8_U8_V8_440_UNORM = 239 +PIPE_FORMAT_Y10X6_U10X6_V10X6_420_UNORM = 240 +PIPE_FORMAT_Y10X6_U10X6_V10X6_422_UNORM = 241 +PIPE_FORMAT_Y10X6_U10X6_V10X6_444_UNORM = 242 +PIPE_FORMAT_Y12X4_U12X4_V12X4_420_UNORM = 243 +PIPE_FORMAT_Y12X4_U12X4_V12X4_422_UNORM = 244 +PIPE_FORMAT_Y12X4_U12X4_V12X4_444_UNORM = 245 +PIPE_FORMAT_Y16_U16_V16_420_UNORM = 246 +PIPE_FORMAT_Y16_U16_V16_422_UNORM = 247 +PIPE_FORMAT_Y16_U16V16_422_UNORM = 248 +PIPE_FORMAT_Y16_U16_V16_444_UNORM = 249 +PIPE_FORMAT_Y8U8V8_420_UNORM_PACKED = 250 +PIPE_FORMAT_Y10U10V10_420_UNORM_PACKED = 251 +PIPE_FORMAT_A4R4_UNORM = 252 +PIPE_FORMAT_R4A4_UNORM = 253 +PIPE_FORMAT_R8A8_UNORM = 254 +PIPE_FORMAT_A8R8_UNORM = 255 +PIPE_FORMAT_A8_UINT = 256 +PIPE_FORMAT_I8_UINT = 257 +PIPE_FORMAT_L8_UINT = 258 +PIPE_FORMAT_L8A8_UINT = 259 +PIPE_FORMAT_A8_SINT = 260 +PIPE_FORMAT_I8_SINT = 261 +PIPE_FORMAT_L8_SINT = 262 +PIPE_FORMAT_L8A8_SINT = 263 +PIPE_FORMAT_A16_UINT = 264 +PIPE_FORMAT_I16_UINT = 265 +PIPE_FORMAT_L16_UINT = 266 +PIPE_FORMAT_L16A16_UINT = 267 +PIPE_FORMAT_A16_SINT = 268 +PIPE_FORMAT_I16_SINT = 269 +PIPE_FORMAT_L16_SINT = 270 +PIPE_FORMAT_L16A16_SINT = 271 +PIPE_FORMAT_A32_UINT = 272 +PIPE_FORMAT_I32_UINT = 273 +PIPE_FORMAT_L32_UINT = 274 +PIPE_FORMAT_L32A32_UINT = 275 +PIPE_FORMAT_A32_SINT = 276 +PIPE_FORMAT_I32_SINT = 277 +PIPE_FORMAT_L32_SINT = 278 +PIPE_FORMAT_L32A32_SINT = 279 +PIPE_FORMAT_A8R8G8B8_UINT = 280 +PIPE_FORMAT_A8B8G8R8_UINT = 281 +PIPE_FORMAT_A2R10G10B10_UINT = 282 +PIPE_FORMAT_A2B10G10R10_UINT = 283 +PIPE_FORMAT_R5G6B5_UINT = 284 +PIPE_FORMAT_B5G6R5_UINT = 285 +PIPE_FORMAT_R5G5B5A1_UINT = 286 +PIPE_FORMAT_B5G5R5A1_UINT = 287 +PIPE_FORMAT_A1R5G5B5_UINT = 288 +PIPE_FORMAT_A1B5G5R5_UINT = 289 +PIPE_FORMAT_R4G4B4A4_UINT = 290 +PIPE_FORMAT_B4G4R4A4_UINT = 291 +PIPE_FORMAT_A4R4G4B4_UINT = 292 +PIPE_FORMAT_A4B4G4R4_UINT = 293 +PIPE_FORMAT_R3G3B2_UINT = 294 +PIPE_FORMAT_B2G3R3_UINT = 295 +PIPE_FORMAT_ETC1_RGB8 = 296 +PIPE_FORMAT_R8G8_R8B8_UNORM = 297 +PIPE_FORMAT_R8B8_R8G8_UNORM = 298 +PIPE_FORMAT_G8R8_B8R8_UNORM = 299 +PIPE_FORMAT_B8R8_G8R8_UNORM = 300 +PIPE_FORMAT_G8B8_G8R8_UNORM = 301 +PIPE_FORMAT_B8G8_R8G8_UNORM = 302 +PIPE_FORMAT_R8G8B8X8_SNORM = 303 +PIPE_FORMAT_R8G8B8X8_SRGB = 304 +PIPE_FORMAT_R8G8B8X8_UINT = 305 +PIPE_FORMAT_R8G8B8X8_SINT = 306 +PIPE_FORMAT_B10G10R10X2_UNORM = 307 +PIPE_FORMAT_R16G16B16X16_UNORM = 308 +PIPE_FORMAT_R16G16B16X16_SNORM = 309 +PIPE_FORMAT_R16G16B16X16_FLOAT = 310 +PIPE_FORMAT_R16G16B16X16_UINT = 311 +PIPE_FORMAT_R16G16B16X16_SINT = 312 +PIPE_FORMAT_R32G32B32X32_FLOAT = 313 +PIPE_FORMAT_R32G32B32X32_UINT = 314 +PIPE_FORMAT_R32G32B32X32_SINT = 315 +PIPE_FORMAT_R8A8_SNORM = 316 +PIPE_FORMAT_R16A16_UNORM = 317 +PIPE_FORMAT_R16A16_SNORM = 318 +PIPE_FORMAT_R16A16_FLOAT = 319 +PIPE_FORMAT_R32A32_FLOAT = 320 +PIPE_FORMAT_R8A8_UINT = 321 +PIPE_FORMAT_R8A8_SINT = 322 +PIPE_FORMAT_R16A16_UINT = 323 +PIPE_FORMAT_R16A16_SINT = 324 +PIPE_FORMAT_R32A32_UINT = 325 +PIPE_FORMAT_R32A32_SINT = 326 +PIPE_FORMAT_B5G6R5_SRGB = 327 +PIPE_FORMAT_BPTC_RGBA_UNORM = 328 +PIPE_FORMAT_BPTC_SRGBA = 329 +PIPE_FORMAT_BPTC_RGB_FLOAT = 330 +PIPE_FORMAT_BPTC_RGB_UFLOAT = 331 +PIPE_FORMAT_G8R8_UNORM = 332 +PIPE_FORMAT_G8R8_SNORM = 333 +PIPE_FORMAT_G16R16_UNORM = 334 +PIPE_FORMAT_G16R16_SNORM = 335 +PIPE_FORMAT_A8B8G8R8_SNORM = 336 +PIPE_FORMAT_X8B8G8R8_SNORM = 337 +PIPE_FORMAT_ETC2_RGB8 = 338 +PIPE_FORMAT_ETC2_SRGB8 = 339 +PIPE_FORMAT_ETC2_RGB8A1 = 340 +PIPE_FORMAT_ETC2_SRGB8A1 = 341 +PIPE_FORMAT_ETC2_RGBA8 = 342 +PIPE_FORMAT_ETC2_SRGBA8 = 343 +PIPE_FORMAT_ETC2_R11_UNORM = 344 +PIPE_FORMAT_ETC2_R11_SNORM = 345 +PIPE_FORMAT_ETC2_RG11_UNORM = 346 +PIPE_FORMAT_ETC2_RG11_SNORM = 347 +PIPE_FORMAT_ASTC_4x4 = 348 +PIPE_FORMAT_ASTC_5x4 = 349 +PIPE_FORMAT_ASTC_5x5 = 350 +PIPE_FORMAT_ASTC_6x5 = 351 +PIPE_FORMAT_ASTC_6x6 = 352 +PIPE_FORMAT_ASTC_8x5 = 353 +PIPE_FORMAT_ASTC_8x6 = 354 +PIPE_FORMAT_ASTC_8x8 = 355 +PIPE_FORMAT_ASTC_10x5 = 356 +PIPE_FORMAT_ASTC_10x6 = 357 +PIPE_FORMAT_ASTC_10x8 = 358 +PIPE_FORMAT_ASTC_10x10 = 359 +PIPE_FORMAT_ASTC_12x10 = 360 +PIPE_FORMAT_ASTC_12x12 = 361 +PIPE_FORMAT_ASTC_4x4_SRGB = 362 +PIPE_FORMAT_ASTC_5x4_SRGB = 363 +PIPE_FORMAT_ASTC_5x5_SRGB = 364 +PIPE_FORMAT_ASTC_6x5_SRGB = 365 +PIPE_FORMAT_ASTC_6x6_SRGB = 366 +PIPE_FORMAT_ASTC_8x5_SRGB = 367 +PIPE_FORMAT_ASTC_8x6_SRGB = 368 +PIPE_FORMAT_ASTC_8x8_SRGB = 369 +PIPE_FORMAT_ASTC_10x5_SRGB = 370 +PIPE_FORMAT_ASTC_10x6_SRGB = 371 +PIPE_FORMAT_ASTC_10x8_SRGB = 372 +PIPE_FORMAT_ASTC_10x10_SRGB = 373 +PIPE_FORMAT_ASTC_12x10_SRGB = 374 +PIPE_FORMAT_ASTC_12x12_SRGB = 375 +PIPE_FORMAT_ASTC_3x3x3 = 376 +PIPE_FORMAT_ASTC_4x3x3 = 377 +PIPE_FORMAT_ASTC_4x4x3 = 378 +PIPE_FORMAT_ASTC_4x4x4 = 379 +PIPE_FORMAT_ASTC_5x4x4 = 380 +PIPE_FORMAT_ASTC_5x5x4 = 381 +PIPE_FORMAT_ASTC_5x5x5 = 382 +PIPE_FORMAT_ASTC_6x5x5 = 383 +PIPE_FORMAT_ASTC_6x6x5 = 384 +PIPE_FORMAT_ASTC_6x6x6 = 385 +PIPE_FORMAT_ASTC_3x3x3_SRGB = 386 +PIPE_FORMAT_ASTC_4x3x3_SRGB = 387 +PIPE_FORMAT_ASTC_4x4x3_SRGB = 388 +PIPE_FORMAT_ASTC_4x4x4_SRGB = 389 +PIPE_FORMAT_ASTC_5x4x4_SRGB = 390 +PIPE_FORMAT_ASTC_5x5x4_SRGB = 391 +PIPE_FORMAT_ASTC_5x5x5_SRGB = 392 +PIPE_FORMAT_ASTC_6x5x5_SRGB = 393 +PIPE_FORMAT_ASTC_6x6x5_SRGB = 394 +PIPE_FORMAT_ASTC_6x6x6_SRGB = 395 +PIPE_FORMAT_ASTC_4x4_FLOAT = 396 +PIPE_FORMAT_ASTC_5x4_FLOAT = 397 +PIPE_FORMAT_ASTC_5x5_FLOAT = 398 +PIPE_FORMAT_ASTC_6x5_FLOAT = 399 +PIPE_FORMAT_ASTC_6x6_FLOAT = 400 +PIPE_FORMAT_ASTC_8x5_FLOAT = 401 +PIPE_FORMAT_ASTC_8x6_FLOAT = 402 +PIPE_FORMAT_ASTC_8x8_FLOAT = 403 +PIPE_FORMAT_ASTC_10x5_FLOAT = 404 +PIPE_FORMAT_ASTC_10x6_FLOAT = 405 +PIPE_FORMAT_ASTC_10x8_FLOAT = 406 +PIPE_FORMAT_ASTC_10x10_FLOAT = 407 +PIPE_FORMAT_ASTC_12x10_FLOAT = 408 +PIPE_FORMAT_ASTC_12x12_FLOAT = 409 +PIPE_FORMAT_FXT1_RGB = 410 +PIPE_FORMAT_FXT1_RGBA = 411 +PIPE_FORMAT_P010 = 412 +PIPE_FORMAT_P012 = 413 +PIPE_FORMAT_P016 = 414 +PIPE_FORMAT_P030 = 415 +PIPE_FORMAT_Y210 = 416 +PIPE_FORMAT_Y212 = 417 +PIPE_FORMAT_Y216 = 418 +PIPE_FORMAT_Y410 = 419 +PIPE_FORMAT_Y412 = 420 +PIPE_FORMAT_Y416 = 421 +PIPE_FORMAT_R10G10B10X2_UNORM = 422 +PIPE_FORMAT_A1R5G5B5_UNORM = 423 +PIPE_FORMAT_A1B5G5R5_UNORM = 424 +PIPE_FORMAT_X1B5G5R5_UNORM = 425 +PIPE_FORMAT_R5G5B5A1_UNORM = 426 +PIPE_FORMAT_A4R4G4B4_UNORM = 427 +PIPE_FORMAT_A4B4G4R4_UNORM = 428 +PIPE_FORMAT_G8R8_SINT = 429 +PIPE_FORMAT_A8B8G8R8_SINT = 430 +PIPE_FORMAT_X8B8G8R8_SINT = 431 +PIPE_FORMAT_ATC_RGB = 432 +PIPE_FORMAT_ATC_RGBA_EXPLICIT = 433 +PIPE_FORMAT_ATC_RGBA_INTERPOLATED = 434 +PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8 = 435 +PIPE_FORMAT_AYUV = 436 +PIPE_FORMAT_XYUV = 437 +PIPE_FORMAT_R8G8B8_420_UNORM_PACKED = 438 +PIPE_FORMAT_R8_G8B8_420_UNORM = 439 +PIPE_FORMAT_R8_B8G8_420_UNORM = 440 +PIPE_FORMAT_G8_B8R8_420_UNORM = 441 +PIPE_FORMAT_R10G10B10_420_UNORM_PACKED = 442 +PIPE_FORMAT_R10_G10B10_420_UNORM = 443 +PIPE_FORMAT_R10_G10B10_422_UNORM = 444 +PIPE_FORMAT_R8_G8_B8_420_UNORM = 445 +PIPE_FORMAT_R8_B8_G8_420_UNORM = 446 +PIPE_FORMAT_G8_B8_R8_420_UNORM = 447 +PIPE_FORMAT_R8_G8B8_422_UNORM = 448 +PIPE_FORMAT_R8_B8G8_422_UNORM = 449 +PIPE_FORMAT_G8_B8R8_422_UNORM = 450 +PIPE_FORMAT_R8_G8_B8_UNORM = 451 +PIPE_FORMAT_Y8_UNORM = 452 +PIPE_FORMAT_B8G8R8X8_SNORM = 453 +PIPE_FORMAT_B8G8R8X8_UINT = 454 +PIPE_FORMAT_B8G8R8X8_SINT = 455 +PIPE_FORMAT_A8R8G8B8_SNORM = 456 +PIPE_FORMAT_A8R8G8B8_SINT = 457 +PIPE_FORMAT_X8R8G8B8_SNORM = 458 +PIPE_FORMAT_X8R8G8B8_SINT = 459 +PIPE_FORMAT_R5G5B5X1_UNORM = 460 +PIPE_FORMAT_X1R5G5B5_UNORM = 461 +PIPE_FORMAT_R4G4B4X4_UNORM = 462 +PIPE_FORMAT_B10G10R10X2_SNORM = 463 +PIPE_FORMAT_R5G6B5_SRGB = 464 +PIPE_FORMAT_R10G10B10X2_SINT = 465 +PIPE_FORMAT_B10G10R10X2_SINT = 466 +PIPE_FORMAT_G16R16_SINT = 467 +PIPE_FORMAT_COUNT = 468 +pipe_format = ctypes.c_uint32 # enum +class union_glsl_struct_field_0(Union): + pass + +class struct_glsl_struct_field_0_0(Structure): + pass + +struct_glsl_struct_field_0_0._pack_ = 1 # source:False +struct_glsl_struct_field_0_0._fields_ = [ + ('interpolation', ctypes.c_uint32, 3), + ('centroid', ctypes.c_uint32, 1), + ('sample', ctypes.c_uint32, 1), + ('matrix_layout', ctypes.c_uint32, 2), + ('patch', ctypes.c_uint32, 1), + ('precision', ctypes.c_uint32, 2), + ('memory_read_only', ctypes.c_uint32, 1), + ('memory_write_only', ctypes.c_uint32, 1), + ('memory_coherent', ctypes.c_uint32, 1), + ('memory_volatile', ctypes.c_uint32, 1), + ('memory_restrict', ctypes.c_uint32, 1), + ('explicit_xfb_buffer', ctypes.c_uint32, 1), + ('implicit_sized_array', ctypes.c_uint32, 1), + ('PADDING_0', ctypes.c_uint16, 15), +] + +union_glsl_struct_field_0._pack_ = 1 # source:False +union_glsl_struct_field_0._anonymous_ = ('_0',) +union_glsl_struct_field_0._fields_ = [ + ('_0', struct_glsl_struct_field_0_0), + ('flags', ctypes.c_uint32), +] + +struct_glsl_struct_field._pack_ = 1 # source:False +struct_glsl_struct_field._anonymous_ = ('_0',) +struct_glsl_struct_field._fields_ = [ + ('type', ctypes.POINTER(struct_glsl_type)), + ('name', ctypes.POINTER(ctypes.c_char)), + ('location', ctypes.c_int32), + ('component', ctypes.c_int32), + ('offset', ctypes.c_int32), + ('xfb_buffer', ctypes.c_int32), + ('xfb_stride', ctypes.c_int32), + ('image_format', pipe_format), + ('_0', union_glsl_struct_field_0), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +glsl_struct_field = struct_glsl_struct_field +try: + glsl_type_singleton_init_or_ref = _libraries['libtinymesa_cpu.so'].glsl_type_singleton_init_or_ref + glsl_type_singleton_init_or_ref.restype = None + glsl_type_singleton_init_or_ref.argtypes = [] +except AttributeError: + pass +try: + glsl_type_singleton_decref = _libraries['libtinymesa_cpu.so'].glsl_type_singleton_decref + glsl_type_singleton_decref.restype = None + glsl_type_singleton_decref.argtypes = [] +except AttributeError: + pass +try: + encode_type_to_blob = _libraries['libtinymesa_cpu.so'].encode_type_to_blob + encode_type_to_blob.restype = None + encode_type_to_blob.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + decode_type_from_blob = _libraries['libtinymesa_cpu.so'].decode_type_from_blob + decode_type_from_blob.restype = ctypes.POINTER(struct_glsl_type) + decode_type_from_blob.argtypes = [ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +glsl_type_size_align_func = ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)) +try: + glsl_base_type_bit_size = _libraries['FIXME_STUB'].glsl_base_type_bit_size + glsl_base_type_bit_size.restype = ctypes.c_uint32 + glsl_base_type_bit_size.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_base_type_is_16bit = _libraries['FIXME_STUB'].glsl_base_type_is_16bit + glsl_base_type_is_16bit.restype = ctypes.c_bool + glsl_base_type_is_16bit.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_base_type_is_64bit = _libraries['FIXME_STUB'].glsl_base_type_is_64bit + glsl_base_type_is_64bit.restype = ctypes.c_bool + glsl_base_type_is_64bit.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_base_type_is_integer = _libraries['FIXME_STUB'].glsl_base_type_is_integer + glsl_base_type_is_integer.restype = ctypes.c_bool + glsl_base_type_is_integer.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_base_type_is_float = _libraries['FIXME_STUB'].glsl_base_type_is_float + glsl_base_type_is_float.restype = ctypes.c_bool + glsl_base_type_is_float.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_base_type_get_bit_size = _libraries['FIXME_STUB'].glsl_base_type_get_bit_size + glsl_base_type_get_bit_size.restype = ctypes.c_uint32 + glsl_base_type_get_bit_size.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_unsigned_base_type_of = _libraries['FIXME_STUB'].glsl_unsigned_base_type_of + glsl_unsigned_base_type_of.restype = glsl_base_type + glsl_unsigned_base_type_of.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_signed_base_type_of = _libraries['FIXME_STUB'].glsl_signed_base_type_of + glsl_signed_base_type_of.restype = glsl_base_type + glsl_signed_base_type_of.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_apply_signedness_to_base_type = _libraries['libtinymesa_cpu.so'].glsl_apply_signedness_to_base_type + glsl_apply_signedness_to_base_type.restype = glsl_base_type + glsl_apply_signedness_to_base_type.argtypes = [glsl_base_type, ctypes.c_bool] +except AttributeError: + pass + +# values for enumeration 'glsl_sampler_dim' +glsl_sampler_dim__enumvalues = { + 0: 'GLSL_SAMPLER_DIM_1D', + 1: 'GLSL_SAMPLER_DIM_2D', + 2: 'GLSL_SAMPLER_DIM_3D', + 3: 'GLSL_SAMPLER_DIM_CUBE', + 4: 'GLSL_SAMPLER_DIM_RECT', + 5: 'GLSL_SAMPLER_DIM_BUF', + 6: 'GLSL_SAMPLER_DIM_EXTERNAL', + 7: 'GLSL_SAMPLER_DIM_MS', + 8: 'GLSL_SAMPLER_DIM_SUBPASS', + 9: 'GLSL_SAMPLER_DIM_SUBPASS_MS', +} +GLSL_SAMPLER_DIM_1D = 0 +GLSL_SAMPLER_DIM_2D = 1 +GLSL_SAMPLER_DIM_3D = 2 +GLSL_SAMPLER_DIM_CUBE = 3 +GLSL_SAMPLER_DIM_RECT = 4 +GLSL_SAMPLER_DIM_BUF = 5 +GLSL_SAMPLER_DIM_EXTERNAL = 6 +GLSL_SAMPLER_DIM_MS = 7 +GLSL_SAMPLER_DIM_SUBPASS = 8 +GLSL_SAMPLER_DIM_SUBPASS_MS = 9 +glsl_sampler_dim = ctypes.c_uint32 # enum +try: + glsl_get_sampler_dim_coordinate_components = _libraries['libtinymesa_cpu.so'].glsl_get_sampler_dim_coordinate_components + glsl_get_sampler_dim_coordinate_components.restype = ctypes.c_int32 + glsl_get_sampler_dim_coordinate_components.argtypes = [glsl_sampler_dim] +except AttributeError: + pass + +# values for enumeration 'glsl_matrix_layout' +glsl_matrix_layout__enumvalues = { + 0: 'GLSL_MATRIX_LAYOUT_INHERITED', + 1: 'GLSL_MATRIX_LAYOUT_COLUMN_MAJOR', + 2: 'GLSL_MATRIX_LAYOUT_ROW_MAJOR', +} +GLSL_MATRIX_LAYOUT_INHERITED = 0 +GLSL_MATRIX_LAYOUT_COLUMN_MAJOR = 1 +GLSL_MATRIX_LAYOUT_ROW_MAJOR = 2 +glsl_matrix_layout = ctypes.c_uint32 # enum + +# values for enumeration 'c__Ea_GLSL_PRECISION_NONE' +c__Ea_GLSL_PRECISION_NONE__enumvalues = { + 0: 'GLSL_PRECISION_NONE', + 1: 'GLSL_PRECISION_HIGH', + 2: 'GLSL_PRECISION_MEDIUM', + 3: 'GLSL_PRECISION_LOW', +} +GLSL_PRECISION_NONE = 0 +GLSL_PRECISION_HIGH = 1 +GLSL_PRECISION_MEDIUM = 2 +GLSL_PRECISION_LOW = 3 +c__Ea_GLSL_PRECISION_NONE = ctypes.c_uint32 # enum + +# values for enumeration 'glsl_cmat_use' +glsl_cmat_use__enumvalues = { + 0: 'GLSL_CMAT_USE_NONE', + 1: 'GLSL_CMAT_USE_A', + 2: 'GLSL_CMAT_USE_B', + 3: 'GLSL_CMAT_USE_ACCUMULATOR', +} +GLSL_CMAT_USE_NONE = 0 +GLSL_CMAT_USE_A = 1 +GLSL_CMAT_USE_B = 2 +GLSL_CMAT_USE_ACCUMULATOR = 3 +glsl_cmat_use = ctypes.c_uint32 # enum +try: + glsl_get_type_name = _libraries['libtinymesa_cpu.so'].glsl_get_type_name + glsl_get_type_name.restype = ctypes.POINTER(ctypes.c_char) + glsl_get_type_name.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_base_type = _libraries['FIXME_STUB'].glsl_get_base_type + glsl_get_base_type.restype = glsl_base_type + glsl_get_base_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_bit_size = _libraries['FIXME_STUB'].glsl_get_bit_size + glsl_get_bit_size.restype = ctypes.c_uint32 + glsl_get_bit_size.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_boolean = _libraries['FIXME_STUB'].glsl_type_is_boolean + glsl_type_is_boolean.restype = ctypes.c_bool + glsl_type_is_boolean.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_sampler = _libraries['FIXME_STUB'].glsl_type_is_sampler + glsl_type_is_sampler.restype = ctypes.c_bool + glsl_type_is_sampler.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_texture = _libraries['FIXME_STUB'].glsl_type_is_texture + glsl_type_is_texture.restype = ctypes.c_bool + glsl_type_is_texture.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_image = _libraries['FIXME_STUB'].glsl_type_is_image + glsl_type_is_image.restype = ctypes.c_bool + glsl_type_is_image.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_atomic_uint = _libraries['FIXME_STUB'].glsl_type_is_atomic_uint + glsl_type_is_atomic_uint.restype = ctypes.c_bool + glsl_type_is_atomic_uint.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_struct = _libraries['FIXME_STUB'].glsl_type_is_struct + glsl_type_is_struct.restype = ctypes.c_bool + glsl_type_is_struct.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_interface = _libraries['FIXME_STUB'].glsl_type_is_interface + glsl_type_is_interface.restype = ctypes.c_bool + glsl_type_is_interface.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_array = _libraries['FIXME_STUB'].glsl_type_is_array + glsl_type_is_array.restype = ctypes.c_bool + glsl_type_is_array.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_cmat = _libraries['FIXME_STUB'].glsl_type_is_cmat + glsl_type_is_cmat.restype = ctypes.c_bool + glsl_type_is_cmat.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_void = _libraries['FIXME_STUB'].glsl_type_is_void + glsl_type_is_void.restype = ctypes.c_bool + glsl_type_is_void.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_subroutine = _libraries['FIXME_STUB'].glsl_type_is_subroutine + glsl_type_is_subroutine.restype = ctypes.c_bool + glsl_type_is_subroutine.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_error = _libraries['FIXME_STUB'].glsl_type_is_error + glsl_type_is_error.restype = ctypes.c_bool + glsl_type_is_error.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_double = _libraries['FIXME_STUB'].glsl_type_is_double + glsl_type_is_double.restype = ctypes.c_bool + glsl_type_is_double.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_float = _libraries['FIXME_STUB'].glsl_type_is_float + glsl_type_is_float.restype = ctypes.c_bool + glsl_type_is_float.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_numeric = _libraries['FIXME_STUB'].glsl_type_is_numeric + glsl_type_is_numeric.restype = ctypes.c_bool + glsl_type_is_numeric.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer = _libraries['FIXME_STUB'].glsl_type_is_integer + glsl_type_is_integer.restype = ctypes.c_bool + glsl_type_is_integer.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_struct_or_ifc = _libraries['FIXME_STUB'].glsl_type_is_struct_or_ifc + glsl_type_is_struct_or_ifc.restype = ctypes.c_bool + glsl_type_is_struct_or_ifc.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_packed = _libraries['FIXME_STUB'].glsl_type_is_packed + glsl_type_is_packed.restype = ctypes.c_bool + glsl_type_is_packed.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_16bit = _libraries['FIXME_STUB'].glsl_type_is_16bit + glsl_type_is_16bit.restype = ctypes.c_bool + glsl_type_is_16bit.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_32bit = _libraries['FIXME_STUB'].glsl_type_is_32bit + glsl_type_is_32bit.restype = ctypes.c_bool + glsl_type_is_32bit.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_64bit = _libraries['FIXME_STUB'].glsl_type_is_64bit + glsl_type_is_64bit.restype = ctypes.c_bool + glsl_type_is_64bit.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer_16 = _libraries['FIXME_STUB'].glsl_type_is_integer_16 + glsl_type_is_integer_16.restype = ctypes.c_bool + glsl_type_is_integer_16.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer_32 = _libraries['FIXME_STUB'].glsl_type_is_integer_32 + glsl_type_is_integer_32.restype = ctypes.c_bool + glsl_type_is_integer_32.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer_64 = _libraries['FIXME_STUB'].glsl_type_is_integer_64 + glsl_type_is_integer_64.restype = ctypes.c_bool + glsl_type_is_integer_64.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer_32_64 = _libraries['FIXME_STUB'].glsl_type_is_integer_32_64 + glsl_type_is_integer_32_64.restype = ctypes.c_bool + glsl_type_is_integer_32_64.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer_16_32 = _libraries['FIXME_STUB'].glsl_type_is_integer_16_32 + glsl_type_is_integer_16_32.restype = ctypes.c_bool + glsl_type_is_integer_16_32.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_integer_16_32_64 = _libraries['FIXME_STUB'].glsl_type_is_integer_16_32_64 + glsl_type_is_integer_16_32_64.restype = ctypes.c_bool + glsl_type_is_integer_16_32_64.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_float_16 = _libraries['FIXME_STUB'].glsl_type_is_float_16 + glsl_type_is_float_16.restype = ctypes.c_bool + glsl_type_is_float_16.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_float_16_32 = _libraries['FIXME_STUB'].glsl_type_is_float_16_32 + glsl_type_is_float_16_32.restype = ctypes.c_bool + glsl_type_is_float_16_32.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_float_16_32_64 = _libraries['FIXME_STUB'].glsl_type_is_float_16_32_64 + glsl_type_is_float_16_32_64.restype = ctypes.c_bool + glsl_type_is_float_16_32_64.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_bfloat_16 = _libraries['FIXME_STUB'].glsl_type_is_bfloat_16 + glsl_type_is_bfloat_16.restype = ctypes.c_bool + glsl_type_is_bfloat_16.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_e4m3fn = _libraries['FIXME_STUB'].glsl_type_is_e4m3fn + glsl_type_is_e4m3fn.restype = ctypes.c_bool + glsl_type_is_e4m3fn.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_e5m2 = _libraries['FIXME_STUB'].glsl_type_is_e5m2 + glsl_type_is_e5m2.restype = ctypes.c_bool + glsl_type_is_e5m2.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_int_16_32_64 = _libraries['FIXME_STUB'].glsl_type_is_int_16_32_64 + glsl_type_is_int_16_32_64.restype = ctypes.c_bool + glsl_type_is_int_16_32_64.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_uint_16_32_64 = _libraries['FIXME_STUB'].glsl_type_is_uint_16_32_64 + glsl_type_is_uint_16_32_64.restype = ctypes.c_bool + glsl_type_is_uint_16_32_64.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_int_16_32 = _libraries['FIXME_STUB'].glsl_type_is_int_16_32 + glsl_type_is_int_16_32.restype = ctypes.c_bool + glsl_type_is_int_16_32.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_uint_16_32 = _libraries['FIXME_STUB'].glsl_type_is_uint_16_32 + glsl_type_is_uint_16_32.restype = ctypes.c_bool + glsl_type_is_uint_16_32.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_unsized_array = _libraries['FIXME_STUB'].glsl_type_is_unsized_array + glsl_type_is_unsized_array.restype = ctypes.c_bool + glsl_type_is_unsized_array.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_array_of_arrays = _libraries['FIXME_STUB'].glsl_type_is_array_of_arrays + glsl_type_is_array_of_arrays.restype = ctypes.c_bool + glsl_type_is_array_of_arrays.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_bare_sampler = _libraries['FIXME_STUB'].glsl_type_is_bare_sampler + glsl_type_is_bare_sampler.restype = ctypes.c_bool + glsl_type_is_bare_sampler.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_vector = _libraries['libtinymesa_cpu.so'].glsl_type_is_vector + glsl_type_is_vector.restype = ctypes.c_bool + glsl_type_is_vector.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_scalar = _libraries['libtinymesa_cpu.so'].glsl_type_is_scalar + glsl_type_is_scalar.restype = ctypes.c_bool + glsl_type_is_scalar.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_vector_or_scalar = _libraries['libtinymesa_cpu.so'].glsl_type_is_vector_or_scalar + glsl_type_is_vector_or_scalar.restype = ctypes.c_bool + glsl_type_is_vector_or_scalar.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_matrix = _libraries['libtinymesa_cpu.so'].glsl_type_is_matrix + glsl_type_is_matrix.restype = ctypes.c_bool + glsl_type_is_matrix.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_array_or_matrix = _libraries['libtinymesa_cpu.so'].glsl_type_is_array_or_matrix + glsl_type_is_array_or_matrix.restype = ctypes.c_bool + glsl_type_is_array_or_matrix.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_dual_slot = _libraries['libtinymesa_cpu.so'].glsl_type_is_dual_slot + glsl_type_is_dual_slot.restype = ctypes.c_bool + glsl_type_is_dual_slot.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_is_leaf = _libraries['libtinymesa_cpu.so'].glsl_type_is_leaf + glsl_type_is_leaf.restype = ctypes.c_bool + glsl_type_is_leaf.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_matrix_type_is_row_major = _libraries['FIXME_STUB'].glsl_matrix_type_is_row_major + glsl_matrix_type_is_row_major.restype = ctypes.c_bool + glsl_matrix_type_is_row_major.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_sampler_type_is_shadow = _libraries['FIXME_STUB'].glsl_sampler_type_is_shadow + glsl_sampler_type_is_shadow.restype = ctypes.c_bool + glsl_sampler_type_is_shadow.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_sampler_type_is_array = _libraries['FIXME_STUB'].glsl_sampler_type_is_array + glsl_sampler_type_is_array.restype = ctypes.c_bool + glsl_sampler_type_is_array.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_struct_type_is_packed = _libraries['FIXME_STUB'].glsl_struct_type_is_packed + glsl_struct_type_is_packed.restype = ctypes.c_bool + glsl_struct_type_is_packed.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_bare_type = _libraries['libtinymesa_cpu.so'].glsl_get_bare_type + glsl_get_bare_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_bare_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_scalar_type = _libraries['libtinymesa_cpu.so'].glsl_get_scalar_type + glsl_get_scalar_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_scalar_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_base_glsl_type = _libraries['libtinymesa_cpu.so'].glsl_get_base_glsl_type + glsl_get_base_glsl_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_base_glsl_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_length = _libraries['libtinymesa_cpu.so'].glsl_get_length + glsl_get_length.restype = ctypes.c_uint32 + glsl_get_length.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_vector_elements = _libraries['FIXME_STUB'].glsl_get_vector_elements + glsl_get_vector_elements.restype = ctypes.c_uint32 + glsl_get_vector_elements.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_components = _libraries['FIXME_STUB'].glsl_get_components + glsl_get_components.restype = ctypes.c_uint32 + glsl_get_components.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_matrix_columns = _libraries['FIXME_STUB'].glsl_get_matrix_columns + glsl_get_matrix_columns.restype = ctypes.c_uint32 + glsl_get_matrix_columns.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_wrap_in_arrays = _libraries['libtinymesa_cpu.so'].glsl_type_wrap_in_arrays + glsl_type_wrap_in_arrays.restype = ctypes.POINTER(struct_glsl_type) + glsl_type_wrap_in_arrays.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_array_size = _libraries['FIXME_STUB'].glsl_array_size + glsl_array_size.restype = ctypes.c_int32 + glsl_array_size.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_aoa_size = _libraries['libtinymesa_cpu.so'].glsl_get_aoa_size + glsl_get_aoa_size.restype = ctypes.c_uint32 + glsl_get_aoa_size.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_array_element = _libraries['libtinymesa_cpu.so'].glsl_get_array_element + glsl_get_array_element.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_array_element.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_without_array = _libraries['libtinymesa_cpu.so'].glsl_without_array + glsl_without_array.restype = ctypes.POINTER(struct_glsl_type) + glsl_without_array.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_without_array_or_matrix = _libraries['libtinymesa_cpu.so'].glsl_without_array_or_matrix + glsl_without_array_or_matrix.restype = ctypes.POINTER(struct_glsl_type) + glsl_without_array_or_matrix.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_cmat_element = _libraries['libtinymesa_cpu.so'].glsl_get_cmat_element + glsl_get_cmat_element.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_cmat_element.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_cmat_description = _libraries['libtinymesa_cpu.so'].glsl_get_cmat_description + glsl_get_cmat_description.restype = ctypes.POINTER(struct_glsl_cmat_description) + glsl_get_cmat_description.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_atomic_size = _libraries['libtinymesa_cpu.so'].glsl_atomic_size + glsl_atomic_size.restype = ctypes.c_uint32 + glsl_atomic_size.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_contains_32bit = _libraries['libtinymesa_cpu.so'].glsl_type_contains_32bit + glsl_type_contains_32bit.restype = ctypes.c_bool + glsl_type_contains_32bit.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_contains_64bit = _libraries['libtinymesa_cpu.so'].glsl_type_contains_64bit + glsl_type_contains_64bit.restype = ctypes.c_bool + glsl_type_contains_64bit.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_contains_image = _libraries['libtinymesa_cpu.so'].glsl_type_contains_image + glsl_type_contains_image.restype = ctypes.c_bool + glsl_type_contains_image.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_atomic = _libraries['libtinymesa_cpu.so'].glsl_contains_atomic + glsl_contains_atomic.restype = ctypes.c_bool + glsl_contains_atomic.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_double = _libraries['libtinymesa_cpu.so'].glsl_contains_double + glsl_contains_double.restype = ctypes.c_bool + glsl_contains_double.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_integer = _libraries['libtinymesa_cpu.so'].glsl_contains_integer + glsl_contains_integer.restype = ctypes.c_bool + glsl_contains_integer.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_opaque = _libraries['libtinymesa_cpu.so'].glsl_contains_opaque + glsl_contains_opaque.restype = ctypes.c_bool + glsl_contains_opaque.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_sampler = _libraries['libtinymesa_cpu.so'].glsl_contains_sampler + glsl_contains_sampler.restype = ctypes.c_bool + glsl_contains_sampler.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_array = _libraries['libtinymesa_cpu.so'].glsl_contains_array + glsl_contains_array.restype = ctypes.c_bool + glsl_contains_array.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_contains_subroutine = _libraries['libtinymesa_cpu.so'].glsl_contains_subroutine + glsl_contains_subroutine.restype = ctypes.c_bool + glsl_contains_subroutine.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_sampler_dim = _libraries['FIXME_STUB'].glsl_get_sampler_dim + glsl_get_sampler_dim.restype = glsl_sampler_dim + glsl_get_sampler_dim.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_sampler_result_type = _libraries['FIXME_STUB'].glsl_get_sampler_result_type + glsl_get_sampler_result_type.restype = glsl_base_type + glsl_get_sampler_result_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_sampler_coordinate_components = _libraries['libtinymesa_cpu.so'].glsl_get_sampler_coordinate_components + glsl_get_sampler_coordinate_components.restype = ctypes.c_int32 + glsl_get_sampler_coordinate_components.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_compare_no_precision = _libraries['libtinymesa_cpu.so'].glsl_type_compare_no_precision + glsl_type_compare_no_precision.restype = ctypes.c_bool + glsl_type_compare_no_precision.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_record_compare = _libraries['libtinymesa_cpu.so'].glsl_record_compare + glsl_record_compare.restype = ctypes.c_bool + glsl_record_compare.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(struct_glsl_type), ctypes.c_bool, ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_struct_field = _libraries['libtinymesa_cpu.so'].glsl_get_struct_field + glsl_get_struct_field.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_struct_field.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_get_struct_field_data = _libraries['libtinymesa_cpu.so'].glsl_get_struct_field_data + glsl_get_struct_field_data.restype = ctypes.POINTER(struct_glsl_struct_field) + glsl_get_struct_field_data.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_get_struct_location_offset = _libraries['libtinymesa_cpu.so'].glsl_get_struct_location_offset + glsl_get_struct_location_offset.restype = ctypes.c_uint32 + glsl_get_struct_location_offset.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_get_field_index = _libraries['libtinymesa_cpu.so'].glsl_get_field_index + glsl_get_field_index.restype = ctypes.c_int32 + glsl_get_field_index.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + glsl_get_field_type = _libraries['libtinymesa_cpu.so'].glsl_get_field_type + glsl_get_field_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_field_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + glsl_get_struct_field_offset = _libraries['FIXME_STUB'].glsl_get_struct_field_offset + glsl_get_struct_field_offset.restype = ctypes.c_int32 + glsl_get_struct_field_offset.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_get_struct_elem_name = _libraries['FIXME_STUB'].glsl_get_struct_elem_name + glsl_get_struct_elem_name.restype = ctypes.POINTER(ctypes.c_char) + glsl_get_struct_elem_name.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_void_type = _libraries['FIXME_STUB'].glsl_void_type + glsl_void_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_void_type.argtypes = [] +except AttributeError: + pass +try: + glsl_float_type = _libraries['FIXME_STUB'].glsl_float_type + glsl_float_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_float_type.argtypes = [] +except AttributeError: + pass +try: + glsl_float16_t_type = _libraries['FIXME_STUB'].glsl_float16_t_type + glsl_float16_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_float16_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_double_type = _libraries['FIXME_STUB'].glsl_double_type + glsl_double_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_double_type.argtypes = [] +except AttributeError: + pass +try: + glsl_vec2_type = _libraries['FIXME_STUB'].glsl_vec2_type + glsl_vec2_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_vec2_type.argtypes = [] +except AttributeError: + pass +try: + glsl_dvec2_type = _libraries['FIXME_STUB'].glsl_dvec2_type + glsl_dvec2_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_dvec2_type.argtypes = [] +except AttributeError: + pass +try: + glsl_uvec2_type = _libraries['FIXME_STUB'].glsl_uvec2_type + glsl_uvec2_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uvec2_type.argtypes = [] +except AttributeError: + pass +try: + glsl_ivec2_type = _libraries['FIXME_STUB'].glsl_ivec2_type + glsl_ivec2_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_ivec2_type.argtypes = [] +except AttributeError: + pass +try: + glsl_bvec2_type = _libraries['FIXME_STUB'].glsl_bvec2_type + glsl_bvec2_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bvec2_type.argtypes = [] +except AttributeError: + pass +try: + glsl_vec4_type = _libraries['FIXME_STUB'].glsl_vec4_type + glsl_vec4_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_vec4_type.argtypes = [] +except AttributeError: + pass +try: + glsl_dvec4_type = _libraries['FIXME_STUB'].glsl_dvec4_type + glsl_dvec4_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_dvec4_type.argtypes = [] +except AttributeError: + pass +try: + glsl_uvec4_type = _libraries['FIXME_STUB'].glsl_uvec4_type + glsl_uvec4_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uvec4_type.argtypes = [] +except AttributeError: + pass +try: + glsl_ivec4_type = _libraries['FIXME_STUB'].glsl_ivec4_type + glsl_ivec4_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_ivec4_type.argtypes = [] +except AttributeError: + pass +try: + glsl_bvec4_type = _libraries['FIXME_STUB'].glsl_bvec4_type + glsl_bvec4_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bvec4_type.argtypes = [] +except AttributeError: + pass +try: + glsl_int_type = _libraries['FIXME_STUB'].glsl_int_type + glsl_int_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_int_type.argtypes = [] +except AttributeError: + pass +try: + glsl_uint_type = _libraries['FIXME_STUB'].glsl_uint_type + glsl_uint_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uint_type.argtypes = [] +except AttributeError: + pass +try: + glsl_int64_t_type = _libraries['FIXME_STUB'].glsl_int64_t_type + glsl_int64_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_int64_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_uint64_t_type = _libraries['FIXME_STUB'].glsl_uint64_t_type + glsl_uint64_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uint64_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_int16_t_type = _libraries['FIXME_STUB'].glsl_int16_t_type + glsl_int16_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_int16_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_uint16_t_type = _libraries['FIXME_STUB'].glsl_uint16_t_type + glsl_uint16_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uint16_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_int8_t_type = _libraries['FIXME_STUB'].glsl_int8_t_type + glsl_int8_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_int8_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_uint8_t_type = _libraries['FIXME_STUB'].glsl_uint8_t_type + glsl_uint8_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uint8_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_bool_type = _libraries['FIXME_STUB'].glsl_bool_type + glsl_bool_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bool_type.argtypes = [] +except AttributeError: + pass +try: + glsl_atomic_uint_type = _libraries['FIXME_STUB'].glsl_atomic_uint_type + glsl_atomic_uint_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_atomic_uint_type.argtypes = [] +except AttributeError: + pass +try: + glsl_bfloat16_t_type = _libraries['FIXME_STUB'].glsl_bfloat16_t_type + glsl_bfloat16_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bfloat16_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_e4m3fn_t_type = _libraries['FIXME_STUB'].glsl_e4m3fn_t_type + glsl_e4m3fn_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_e4m3fn_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_e5m2_t_type = _libraries['FIXME_STUB'].glsl_e5m2_t_type + glsl_e5m2_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_e5m2_t_type.argtypes = [] +except AttributeError: + pass +try: + glsl_floatN_t_type = _libraries['FIXME_STUB'].glsl_floatN_t_type + glsl_floatN_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_floatN_t_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_bfloatN_t_type = _libraries['FIXME_STUB'].glsl_bfloatN_t_type + glsl_bfloatN_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bfloatN_t_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_intN_t_type = _libraries['FIXME_STUB'].glsl_intN_t_type + glsl_intN_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_intN_t_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_uintN_t_type = _libraries['FIXME_STUB'].glsl_uintN_t_type + glsl_uintN_t_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uintN_t_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_vec_type = _libraries['libtinymesa_cpu.so'].glsl_vec_type + glsl_vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_f16vec_type = _libraries['libtinymesa_cpu.so'].glsl_f16vec_type + glsl_f16vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_f16vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_bf16vec_type = _libraries['libtinymesa_cpu.so'].glsl_bf16vec_type + glsl_bf16vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bf16vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_e4m3fnvec_type = _libraries['libtinymesa_cpu.so'].glsl_e4m3fnvec_type + glsl_e4m3fnvec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_e4m3fnvec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_e5m2vec_type = _libraries['libtinymesa_cpu.so'].glsl_e5m2vec_type + glsl_e5m2vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_e5m2vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_dvec_type = _libraries['libtinymesa_cpu.so'].glsl_dvec_type + glsl_dvec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_dvec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_ivec_type = _libraries['libtinymesa_cpu.so'].glsl_ivec_type + glsl_ivec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_ivec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_uvec_type = _libraries['libtinymesa_cpu.so'].glsl_uvec_type + glsl_uvec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uvec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_bvec_type = _libraries['libtinymesa_cpu.so'].glsl_bvec_type + glsl_bvec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bvec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_i64vec_type = _libraries['libtinymesa_cpu.so'].glsl_i64vec_type + glsl_i64vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_i64vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_u64vec_type = _libraries['libtinymesa_cpu.so'].glsl_u64vec_type + glsl_u64vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_u64vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_i16vec_type = _libraries['libtinymesa_cpu.so'].glsl_i16vec_type + glsl_i16vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_i16vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_u16vec_type = _libraries['libtinymesa_cpu.so'].glsl_u16vec_type + glsl_u16vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_u16vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_i8vec_type = _libraries['libtinymesa_cpu.so'].glsl_i8vec_type + glsl_i8vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_i8vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_u8vec_type = _libraries['libtinymesa_cpu.so'].glsl_u8vec_type + glsl_u8vec_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_u8vec_type.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_simple_explicit_type = _libraries['libtinymesa_cpu.so'].glsl_simple_explicit_type + glsl_simple_explicit_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_simple_explicit_type.argtypes = [ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_bool, ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_simple_type = _libraries['FIXME_STUB'].glsl_simple_type + glsl_simple_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_simple_type.argtypes = [ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_sampler_type = _libraries['libtinymesa_cpu.so'].glsl_sampler_type + glsl_sampler_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_sampler_type.argtypes = [glsl_sampler_dim, ctypes.c_bool, ctypes.c_bool, glsl_base_type] +except AttributeError: + pass +try: + glsl_bare_sampler_type = _libraries['libtinymesa_cpu.so'].glsl_bare_sampler_type + glsl_bare_sampler_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bare_sampler_type.argtypes = [] +except AttributeError: + pass +try: + glsl_bare_shadow_sampler_type = _libraries['libtinymesa_cpu.so'].glsl_bare_shadow_sampler_type + glsl_bare_shadow_sampler_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_bare_shadow_sampler_type.argtypes = [] +except AttributeError: + pass +try: + glsl_texture_type = _libraries['libtinymesa_cpu.so'].glsl_texture_type + glsl_texture_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_texture_type.argtypes = [glsl_sampler_dim, ctypes.c_bool, glsl_base_type] +except AttributeError: + pass +try: + glsl_image_type = _libraries['libtinymesa_cpu.so'].glsl_image_type + glsl_image_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_image_type.argtypes = [glsl_sampler_dim, ctypes.c_bool, glsl_base_type] +except AttributeError: + pass +try: + glsl_array_type = _libraries['libtinymesa_cpu.so'].glsl_array_type + glsl_array_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_array_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_cmat_type = _libraries['libtinymesa_cpu.so'].glsl_cmat_type + glsl_cmat_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_cmat_type.argtypes = [ctypes.POINTER(struct_glsl_cmat_description)] +except AttributeError: + pass +try: + glsl_struct_type_with_explicit_alignment = _libraries['libtinymesa_cpu.so'].glsl_struct_type_with_explicit_alignment + glsl_struct_type_with_explicit_alignment.restype = ctypes.POINTER(struct_glsl_type) + glsl_struct_type_with_explicit_alignment.argtypes = [ctypes.POINTER(struct_glsl_struct_field), ctypes.c_uint32, ctypes.POINTER(ctypes.c_char), ctypes.c_bool, ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_struct_type = _libraries['FIXME_STUB'].glsl_struct_type + glsl_struct_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_struct_type.argtypes = [ctypes.POINTER(struct_glsl_struct_field), ctypes.c_uint32, ctypes.POINTER(ctypes.c_char), ctypes.c_bool] +except AttributeError: + pass + +# values for enumeration 'glsl_interface_packing' +glsl_interface_packing__enumvalues = { + 0: 'GLSL_INTERFACE_PACKING_STD140', + 1: 'GLSL_INTERFACE_PACKING_SHARED', + 2: 'GLSL_INTERFACE_PACKING_PACKED', + 3: 'GLSL_INTERFACE_PACKING_STD430', +} +GLSL_INTERFACE_PACKING_STD140 = 0 +GLSL_INTERFACE_PACKING_SHARED = 1 +GLSL_INTERFACE_PACKING_PACKED = 2 +GLSL_INTERFACE_PACKING_STD430 = 3 +glsl_interface_packing = ctypes.c_uint32 # enum +try: + glsl_interface_type = _libraries['libtinymesa_cpu.so'].glsl_interface_type + glsl_interface_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_interface_type.argtypes = [ctypes.POINTER(struct_glsl_struct_field), ctypes.c_uint32, glsl_interface_packing, ctypes.c_bool, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + glsl_subroutine_type = _libraries['libtinymesa_cpu.so'].glsl_subroutine_type + glsl_subroutine_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_subroutine_type.argtypes = [ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + glsl_get_row_type = _libraries['libtinymesa_cpu.so'].glsl_get_row_type + glsl_get_row_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_row_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_column_type = _libraries['libtinymesa_cpu.so'].glsl_get_column_type + glsl_get_column_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_column_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_explicit_type_for_size_align = _libraries['libtinymesa_cpu.so'].glsl_get_explicit_type_for_size_align + glsl_get_explicit_type_for_size_align.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_explicit_type_for_size_align.argtypes = [ctypes.POINTER(struct_glsl_type), glsl_type_size_align_func, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + glsl_type_replace_vec3_with_vec4 = _libraries['libtinymesa_cpu.so'].glsl_type_replace_vec3_with_vec4 + glsl_type_replace_vec3_with_vec4.restype = ctypes.POINTER(struct_glsl_type) + glsl_type_replace_vec3_with_vec4.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_float16_type = _libraries['libtinymesa_cpu.so'].glsl_float16_type + glsl_float16_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_float16_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_int16_type = _libraries['libtinymesa_cpu.so'].glsl_int16_type + glsl_int16_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_int16_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_uint16_type = _libraries['libtinymesa_cpu.so'].glsl_uint16_type + glsl_uint16_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_uint16_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_to_16bit = _libraries['libtinymesa_cpu.so'].glsl_type_to_16bit + glsl_type_to_16bit.restype = ctypes.POINTER(struct_glsl_type) + glsl_type_to_16bit.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_scalar_type = _libraries['FIXME_STUB'].glsl_scalar_type + glsl_scalar_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_scalar_type.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + glsl_vector_type = _libraries['FIXME_STUB'].glsl_vector_type + glsl_vector_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_vector_type.argtypes = [glsl_base_type, ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_matrix_type = _libraries['FIXME_STUB'].glsl_matrix_type + glsl_matrix_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_matrix_type.argtypes = [glsl_base_type, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_explicit_matrix_type = _libraries['FIXME_STUB'].glsl_explicit_matrix_type + glsl_explicit_matrix_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_explicit_matrix_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32, ctypes.c_bool] +except AttributeError: + pass +try: + glsl_transposed_type = _libraries['FIXME_STUB'].glsl_transposed_type + glsl_transposed_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_transposed_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_texture_type_to_sampler = _libraries['FIXME_STUB'].glsl_texture_type_to_sampler + glsl_texture_type_to_sampler.restype = ctypes.POINTER(struct_glsl_type) + glsl_texture_type_to_sampler.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_sampler_type_to_texture = _libraries['FIXME_STUB'].glsl_sampler_type_to_texture + glsl_sampler_type_to_texture.restype = ctypes.POINTER(struct_glsl_type) + glsl_sampler_type_to_texture.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_replace_vector_type = _libraries['libtinymesa_cpu.so'].glsl_replace_vector_type + glsl_replace_vector_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_replace_vector_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_channel_type = _libraries['libtinymesa_cpu.so'].glsl_channel_type + glsl_channel_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_channel_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_mul_type = _libraries['libtinymesa_cpu.so'].glsl_get_mul_type + glsl_get_mul_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_mul_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_get_sampler_count = _libraries['libtinymesa_cpu.so'].glsl_type_get_sampler_count + glsl_type_get_sampler_count.restype = ctypes.c_uint32 + glsl_type_get_sampler_count.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_get_texture_count = _libraries['libtinymesa_cpu.so'].glsl_type_get_texture_count + glsl_type_get_texture_count.restype = ctypes.c_uint32 + glsl_type_get_texture_count.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_get_image_count = _libraries['libtinymesa_cpu.so'].glsl_type_get_image_count + glsl_type_get_image_count.restype = ctypes.c_uint32 + glsl_type_get_image_count.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_count_vec4_slots = _libraries['libtinymesa_cpu.so'].glsl_count_vec4_slots + glsl_count_vec4_slots.restype = ctypes.c_uint32 + glsl_count_vec4_slots.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + glsl_count_dword_slots = _libraries['libtinymesa_cpu.so'].glsl_count_dword_slots + glsl_count_dword_slots.restype = ctypes.c_uint32 + glsl_count_dword_slots.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_component_slots = _libraries['libtinymesa_cpu.so'].glsl_get_component_slots + glsl_get_component_slots.restype = ctypes.c_uint32 + glsl_get_component_slots.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_component_slots_aligned = _libraries['libtinymesa_cpu.so'].glsl_get_component_slots_aligned + glsl_get_component_slots_aligned.restype = ctypes.c_uint32 + glsl_get_component_slots_aligned.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + glsl_varying_count = _libraries['libtinymesa_cpu.so'].glsl_varying_count + glsl_varying_count.restype = ctypes.c_uint32 + glsl_varying_count.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_type_uniform_locations = _libraries['libtinymesa_cpu.so'].glsl_type_uniform_locations + glsl_type_uniform_locations.restype = ctypes.c_uint32 + glsl_type_uniform_locations.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_count_attribute_slots = _libraries['FIXME_STUB'].glsl_count_attribute_slots + glsl_count_attribute_slots.restype = ctypes.c_uint32 + glsl_count_attribute_slots.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_cl_size = _libraries['libtinymesa_cpu.so'].glsl_get_cl_size + glsl_get_cl_size.restype = ctypes.c_uint32 + glsl_get_cl_size.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_cl_alignment = _libraries['libtinymesa_cpu.so'].glsl_get_cl_alignment + glsl_get_cl_alignment.restype = ctypes.c_uint32 + glsl_get_cl_alignment.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_cl_type_size_align = _libraries['libtinymesa_cpu.so'].glsl_get_cl_type_size_align + glsl_get_cl_type_size_align.restype = None + glsl_get_cl_type_size_align.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + glsl_get_internal_ifc_packing = _libraries['libtinymesa_cpu.so'].glsl_get_internal_ifc_packing + glsl_get_internal_ifc_packing.restype = glsl_interface_packing + glsl_get_internal_ifc_packing.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_ifc_packing = _libraries['FIXME_STUB'].glsl_get_ifc_packing + glsl_get_ifc_packing.restype = glsl_interface_packing + glsl_get_ifc_packing.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_std140_base_alignment = _libraries['libtinymesa_cpu.so'].glsl_get_std140_base_alignment + glsl_get_std140_base_alignment.restype = ctypes.c_uint32 + glsl_get_std140_base_alignment.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_std140_size = _libraries['libtinymesa_cpu.so'].glsl_get_std140_size + glsl_get_std140_size.restype = ctypes.c_uint32 + glsl_get_std140_size.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_std430_array_stride = _libraries['libtinymesa_cpu.so'].glsl_get_std430_array_stride + glsl_get_std430_array_stride.restype = ctypes.c_uint32 + glsl_get_std430_array_stride.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_std430_base_alignment = _libraries['libtinymesa_cpu.so'].glsl_get_std430_base_alignment + glsl_get_std430_base_alignment.restype = ctypes.c_uint32 + glsl_get_std430_base_alignment.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_std430_size = _libraries['libtinymesa_cpu.so'].glsl_get_std430_size + glsl_get_std430_size.restype = ctypes.c_uint32 + glsl_get_std430_size.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_explicit_size = _libraries['libtinymesa_cpu.so'].glsl_get_explicit_size + glsl_get_explicit_size.restype = ctypes.c_uint32 + glsl_get_explicit_size.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_explicit_stride = _libraries['FIXME_STUB'].glsl_get_explicit_stride + glsl_get_explicit_stride.restype = ctypes.c_uint32 + glsl_get_explicit_stride.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_explicit_alignment = _libraries['FIXME_STUB'].glsl_get_explicit_alignment + glsl_get_explicit_alignment.restype = ctypes.c_uint32 + glsl_get_explicit_alignment.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + glsl_get_explicit_std140_type = _libraries['libtinymesa_cpu.so'].glsl_get_explicit_std140_type + glsl_get_explicit_std140_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_explicit_std140_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_explicit_std430_type = _libraries['libtinymesa_cpu.so'].glsl_get_explicit_std430_type + glsl_get_explicit_std430_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_explicit_std430_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_get_explicit_interface_type = _libraries['FIXME_STUB'].glsl_get_explicit_interface_type + glsl_get_explicit_interface_type.restype = ctypes.POINTER(struct_glsl_type) + glsl_get_explicit_interface_type.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.c_bool] +except AttributeError: + pass +try: + glsl_size_align_handle_array_and_structs = _libraries['libtinymesa_cpu.so'].glsl_size_align_handle_array_and_structs + glsl_size_align_handle_array_and_structs.restype = None + glsl_size_align_handle_array_and_structs.argtypes = [ctypes.POINTER(struct_glsl_type), glsl_type_size_align_func, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + glsl_get_natural_size_align_bytes = _libraries['libtinymesa_cpu.so'].glsl_get_natural_size_align_bytes + glsl_get_natural_size_align_bytes.restype = None + glsl_get_natural_size_align_bytes.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + glsl_get_word_size_align_bytes = _libraries['libtinymesa_cpu.so'].glsl_get_word_size_align_bytes + glsl_get_word_size_align_bytes.restype = None + glsl_get_word_size_align_bytes.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + glsl_get_vec4_size_align_bytes = _libraries['libtinymesa_cpu.so'].glsl_get_vec4_size_align_bytes + glsl_get_vec4_size_align_bytes.restype = None + glsl_get_vec4_size_align_bytes.argtypes = [ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + ralloc_context = _libraries['libtinymesa_cpu.so'].ralloc_context + ralloc_context.restype = ctypes.POINTER(None) + ralloc_context.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + ralloc_size = _libraries['libtinymesa_cpu.so'].ralloc_size + ralloc_size.restype = ctypes.POINTER(None) + ralloc_size.argtypes = [ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + rzalloc_size = _libraries['libtinymesa_cpu.so'].rzalloc_size + rzalloc_size.restype = ctypes.POINTER(None) + rzalloc_size.argtypes = [ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + reralloc_size = _libraries['libtinymesa_cpu.so'].reralloc_size + reralloc_size.restype = ctypes.POINTER(None) + reralloc_size.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + rerzalloc_size = _libraries['libtinymesa_cpu.so'].rerzalloc_size + rerzalloc_size.restype = ctypes.POINTER(None) + rerzalloc_size.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t, size_t] +except AttributeError: + pass +try: + ralloc_array_size = _libraries['libtinymesa_cpu.so'].ralloc_array_size + ralloc_array_size.restype = ctypes.POINTER(None) + ralloc_array_size.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_uint32] +except AttributeError: + pass +try: + rzalloc_array_size = _libraries['libtinymesa_cpu.so'].rzalloc_array_size + rzalloc_array_size.restype = ctypes.POINTER(None) + rzalloc_array_size.argtypes = [ctypes.POINTER(None), size_t, ctypes.c_uint32] +except AttributeError: + pass +try: + reralloc_array_size = _libraries['libtinymesa_cpu.so'].reralloc_array_size + reralloc_array_size.restype = ctypes.POINTER(None) + reralloc_array_size.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t, ctypes.c_uint32] +except AttributeError: + pass +try: + rerzalloc_array_size = _libraries['libtinymesa_cpu.so'].rerzalloc_array_size + rerzalloc_array_size.restype = ctypes.POINTER(None) + rerzalloc_array_size.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + ralloc_free = _libraries['libtinymesa_cpu.so'].ralloc_free + ralloc_free.restype = None + ralloc_free.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + ralloc_steal = _libraries['libtinymesa_cpu.so'].ralloc_steal + ralloc_steal.restype = None + ralloc_steal.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None)] +except AttributeError: + pass +try: + ralloc_adopt = _libraries['libtinymesa_cpu.so'].ralloc_adopt + ralloc_adopt.restype = None + ralloc_adopt.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None)] +except AttributeError: + pass +try: + ralloc_parent = _libraries['libtinymesa_cpu.so'].ralloc_parent + ralloc_parent.restype = ctypes.POINTER(None) + ralloc_parent.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + ralloc_set_destructor = _libraries['libtinymesa_cpu.so'].ralloc_set_destructor + ralloc_set_destructor.restype = None + ralloc_set_destructor.argtypes = [ctypes.POINTER(None), ctypes.CFUNCTYPE(None, ctypes.POINTER(None))] +except AttributeError: + pass +try: + ralloc_memdup = _libraries['libtinymesa_cpu.so'].ralloc_memdup + ralloc_memdup.restype = ctypes.POINTER(None) + ralloc_memdup.argtypes = [ctypes.POINTER(None), ctypes.POINTER(None), size_t] +except AttributeError: + pass +try: + ralloc_strdup = _libraries['libtinymesa_cpu.so'].ralloc_strdup + ralloc_strdup.restype = ctypes.POINTER(ctypes.c_char) + ralloc_strdup.argtypes = [ctypes.POINTER(None), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + ralloc_strndup = _libraries['libtinymesa_cpu.so'].ralloc_strndup + ralloc_strndup.restype = ctypes.POINTER(ctypes.c_char) + ralloc_strndup.argtypes = [ctypes.POINTER(None), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: + pass +try: + ralloc_strcat = _libraries['libtinymesa_cpu.so'].ralloc_strcat + ralloc_strcat.restype = ctypes.c_bool + ralloc_strcat.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + ralloc_strncat = _libraries['libtinymesa_cpu.so'].ralloc_strncat + ralloc_strncat.restype = ctypes.c_bool + ralloc_strncat.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char), size_t] +except AttributeError: + pass +try: + ralloc_str_append = _libraries['libtinymesa_cpu.so'].ralloc_str_append + ralloc_str_append.restype = ctypes.c_bool + ralloc_str_append.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char), size_t, size_t] +except AttributeError: + pass +try: + ralloc_asprintf = _libraries['libtinymesa_cpu.so'].ralloc_asprintf + ralloc_asprintf.restype = ctypes.POINTER(ctypes.c_char) + ralloc_asprintf.argtypes = [ctypes.POINTER(None), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +class struct___va_list_tag(Structure): + pass + +struct___va_list_tag._pack_ = 1 # source:False +struct___va_list_tag._fields_ = [ + ('gp_offset', ctypes.c_uint32), + ('fp_offset', ctypes.c_uint32), + ('overflow_arg_area', ctypes.POINTER(None)), + ('reg_save_area', ctypes.POINTER(None)), +] + +va_list = struct___va_list_tag * 1 +try: + ralloc_vasprintf = _libraries['libtinymesa_cpu.so'].ralloc_vasprintf + ralloc_vasprintf.restype = ctypes.POINTER(ctypes.c_char) + ralloc_vasprintf.argtypes = [ctypes.POINTER(None), ctypes.POINTER(ctypes.c_char), va_list] +except AttributeError: + pass +try: + ralloc_asprintf_rewrite_tail = _libraries['libtinymesa_cpu.so'].ralloc_asprintf_rewrite_tail + ralloc_asprintf_rewrite_tail.restype = ctypes.c_bool + ralloc_asprintf_rewrite_tail.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + ralloc_vasprintf_rewrite_tail = _libraries['libtinymesa_cpu.so'].ralloc_vasprintf_rewrite_tail + ralloc_vasprintf_rewrite_tail.restype = ctypes.c_bool + ralloc_vasprintf_rewrite_tail.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_char), va_list] +except AttributeError: + pass +try: + ralloc_asprintf_append = _libraries['libtinymesa_cpu.so'].ralloc_asprintf_append + ralloc_asprintf_append.restype = ctypes.c_bool + ralloc_asprintf_append.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + ralloc_vasprintf_append = _libraries['libtinymesa_cpu.so'].ralloc_vasprintf_append + ralloc_vasprintf_append.restype = ctypes.c_bool + ralloc_vasprintf_append.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char), va_list] +except AttributeError: + pass +try: + ralloc_total_size = _libraries['libtinymesa_cpu.so'].ralloc_total_size + ralloc_total_size.restype = size_t + ralloc_total_size.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +class struct_gc_ctx(Structure): + pass + +gc_ctx = struct_gc_ctx +try: + gc_context = _libraries['libtinymesa_cpu.so'].gc_context + gc_context.restype = ctypes.POINTER(struct_gc_ctx) + gc_context.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + gc_alloc_size = _libraries['libtinymesa_cpu.so'].gc_alloc_size + gc_alloc_size.restype = ctypes.POINTER(None) + gc_alloc_size.argtypes = [ctypes.POINTER(struct_gc_ctx), size_t, size_t] +except AttributeError: + pass +try: + gc_zalloc_size = _libraries['libtinymesa_cpu.so'].gc_zalloc_size + gc_zalloc_size.restype = ctypes.POINTER(None) + gc_zalloc_size.argtypes = [ctypes.POINTER(struct_gc_ctx), size_t, size_t] +except AttributeError: + pass +try: + gc_free = _libraries['libtinymesa_cpu.so'].gc_free + gc_free.restype = None + gc_free.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + gc_get_context = _libraries['libtinymesa_cpu.so'].gc_get_context + gc_get_context.restype = ctypes.POINTER(struct_gc_ctx) + gc_get_context.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + gc_sweep_start = _libraries['libtinymesa_cpu.so'].gc_sweep_start + gc_sweep_start.restype = None + gc_sweep_start.argtypes = [ctypes.POINTER(struct_gc_ctx)] +except AttributeError: + pass +try: + gc_mark_live = _libraries['libtinymesa_cpu.so'].gc_mark_live + gc_mark_live.restype = None + gc_mark_live.argtypes = [ctypes.POINTER(struct_gc_ctx), ctypes.POINTER(None)] +except AttributeError: + pass +try: + gc_sweep_end = _libraries['libtinymesa_cpu.so'].gc_sweep_end + gc_sweep_end.restype = None + gc_sweep_end.argtypes = [ctypes.POINTER(struct_gc_ctx)] +except AttributeError: + pass +class struct_linear_ctx(Structure): + pass + +linear_ctx = struct_linear_ctx +try: + linear_alloc_child = _libraries['libtinymesa_cpu.so'].linear_alloc_child + linear_alloc_child.restype = ctypes.POINTER(None) + linear_alloc_child.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.c_uint32] +except AttributeError: + pass +class struct_c__SA_linear_opts(Structure): + pass + +struct_c__SA_linear_opts._pack_ = 1 # source:False +struct_c__SA_linear_opts._fields_ = [ + ('min_buffer_size', ctypes.c_uint32), +] + +linear_opts = struct_c__SA_linear_opts +try: + linear_context = _libraries['libtinymesa_cpu.so'].linear_context + linear_context.restype = ctypes.POINTER(struct_linear_ctx) + linear_context.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + linear_context_with_opts = _libraries['libtinymesa_cpu.so'].linear_context_with_opts + linear_context_with_opts.restype = ctypes.POINTER(struct_linear_ctx) + linear_context_with_opts.argtypes = [ctypes.POINTER(None), ctypes.POINTER(struct_c__SA_linear_opts)] +except AttributeError: + pass +try: + linear_zalloc_child = _libraries['libtinymesa_cpu.so'].linear_zalloc_child + linear_zalloc_child.restype = ctypes.POINTER(None) + linear_zalloc_child.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.c_uint32] +except AttributeError: + pass +try: + linear_free_context = _libraries['libtinymesa_cpu.so'].linear_free_context + linear_free_context.restype = None + linear_free_context.argtypes = [ctypes.POINTER(struct_linear_ctx)] +except AttributeError: + pass +try: + ralloc_steal_linear_context = _libraries['libtinymesa_cpu.so'].ralloc_steal_linear_context + ralloc_steal_linear_context.restype = None + ralloc_steal_linear_context.argtypes = [ctypes.POINTER(None), ctypes.POINTER(struct_linear_ctx)] +except AttributeError: + pass +try: + ralloc_parent_of_linear_context = _libraries['libtinymesa_cpu.so'].ralloc_parent_of_linear_context + ralloc_parent_of_linear_context.restype = ctypes.POINTER(None) + ralloc_parent_of_linear_context.argtypes = [ctypes.POINTER(struct_linear_ctx)] +except AttributeError: + pass +try: + linear_alloc_child_array = _libraries['libtinymesa_cpu.so'].linear_alloc_child_array + linear_alloc_child_array.restype = ctypes.POINTER(None) + linear_alloc_child_array.argtypes = [ctypes.POINTER(struct_linear_ctx), size_t, ctypes.c_uint32] +except AttributeError: + pass +try: + linear_zalloc_child_array = _libraries['libtinymesa_cpu.so'].linear_zalloc_child_array + linear_zalloc_child_array.restype = ctypes.POINTER(None) + linear_zalloc_child_array.argtypes = [ctypes.POINTER(struct_linear_ctx), size_t, ctypes.c_uint32] +except AttributeError: + pass +try: + linear_strdup = _libraries['libtinymesa_cpu.so'].linear_strdup + linear_strdup.restype = ctypes.POINTER(ctypes.c_char) + linear_strdup.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + linear_asprintf = _libraries['libtinymesa_cpu.so'].linear_asprintf + linear_asprintf.restype = ctypes.POINTER(ctypes.c_char) + linear_asprintf.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + linear_vasprintf = _libraries['libtinymesa_cpu.so'].linear_vasprintf + linear_vasprintf.restype = ctypes.POINTER(ctypes.c_char) + linear_vasprintf.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.c_char), va_list] +except AttributeError: + pass +try: + linear_asprintf_append = _libraries['libtinymesa_cpu.so'].linear_asprintf_append + linear_asprintf_append.restype = ctypes.c_bool + linear_asprintf_append.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + linear_vasprintf_append = _libraries['libtinymesa_cpu.so'].linear_vasprintf_append + linear_vasprintf_append.restype = ctypes.c_bool + linear_vasprintf_append.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char), va_list] +except AttributeError: + pass +try: + linear_asprintf_rewrite_tail = _libraries['libtinymesa_cpu.so'].linear_asprintf_rewrite_tail + linear_asprintf_rewrite_tail.restype = ctypes.c_bool + linear_asprintf_rewrite_tail.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + linear_vasprintf_rewrite_tail = _libraries['libtinymesa_cpu.so'].linear_vasprintf_rewrite_tail + linear_vasprintf_rewrite_tail.restype = ctypes.c_bool + linear_vasprintf_rewrite_tail.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_char), va_list] +except AttributeError: + pass +try: + linear_strcat = _libraries['libtinymesa_cpu.so'].linear_strcat + linear_strcat.restype = ctypes.c_bool + linear_strcat.argtypes = [ctypes.POINTER(struct_linear_ctx), ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass + +# values for enumeration 'c__Ea_RALLOC_PRINT_INFO_SUMMARY_ONLY' +c__Ea_RALLOC_PRINT_INFO_SUMMARY_ONLY__enumvalues = { + 1: 'RALLOC_PRINT_INFO_SUMMARY_ONLY', +} +RALLOC_PRINT_INFO_SUMMARY_ONLY = 1 +c__Ea_RALLOC_PRINT_INFO_SUMMARY_ONLY = ctypes.c_uint32 # enum +class struct__IO_FILE(Structure): + pass + +class struct__IO_marker(Structure): + pass + +class struct__IO_codecvt(Structure): + pass + +class struct__IO_wide_data(Structure): + pass + +struct__IO_FILE._pack_ = 1 # source:False +struct__IO_FILE._fields_ = [ + ('_flags', ctypes.c_int32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('_IO_read_ptr', ctypes.POINTER(ctypes.c_char)), + ('_IO_read_end', ctypes.POINTER(ctypes.c_char)), + ('_IO_read_base', ctypes.POINTER(ctypes.c_char)), + ('_IO_write_base', ctypes.POINTER(ctypes.c_char)), + ('_IO_write_ptr', ctypes.POINTER(ctypes.c_char)), + ('_IO_write_end', ctypes.POINTER(ctypes.c_char)), + ('_IO_buf_base', ctypes.POINTER(ctypes.c_char)), + ('_IO_buf_end', ctypes.POINTER(ctypes.c_char)), + ('_IO_save_base', ctypes.POINTER(ctypes.c_char)), + ('_IO_backup_base', ctypes.POINTER(ctypes.c_char)), + ('_IO_save_end', ctypes.POINTER(ctypes.c_char)), + ('_markers', ctypes.POINTER(struct__IO_marker)), + ('_chain', ctypes.POINTER(struct__IO_FILE)), + ('_fileno', ctypes.c_int32), + ('_flags2', ctypes.c_int32), + ('_old_offset', ctypes.c_int64), + ('_cur_column', ctypes.c_uint16), + ('_vtable_offset', ctypes.c_byte), + ('_shortbuf', ctypes.c_char * 1), + ('PADDING_1', ctypes.c_ubyte * 4), + ('_lock', ctypes.POINTER(None)), + ('_offset', ctypes.c_int64), + ('_codecvt', ctypes.POINTER(struct__IO_codecvt)), + ('_wide_data', ctypes.POINTER(struct__IO_wide_data)), + ('_freeres_list', ctypes.POINTER(struct__IO_FILE)), + ('_freeres_buf', ctypes.POINTER(None)), + ('__pad5', ctypes.c_uint64), + ('_mode', ctypes.c_int32), + ('_unused2', ctypes.c_char * 20), +] + +try: + ralloc_print_info = _libraries['libtinymesa_cpu.so'].ralloc_print_info + ralloc_print_info.restype = None + ralloc_print_info.argtypes = [ctypes.POINTER(struct__IO_FILE), ctypes.POINTER(None), ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_int64_options' +c__EA_nir_lower_int64_options__enumvalues = { + 1: 'nir_lower_imul64', + 2: 'nir_lower_isign64', + 4: 'nir_lower_divmod64', + 8: 'nir_lower_imul_high64', + 16: 'nir_lower_bcsel64', + 32: 'nir_lower_icmp64', + 64: 'nir_lower_iadd64', + 128: 'nir_lower_iabs64', + 256: 'nir_lower_ineg64', + 512: 'nir_lower_logic64', + 1024: 'nir_lower_minmax64', + 2048: 'nir_lower_shift64', + 4096: 'nir_lower_imul_2x32_64', + 8192: 'nir_lower_extract64', + 16384: 'nir_lower_ufind_msb64', + 32768: 'nir_lower_bit_count64', + 65536: 'nir_lower_subgroup_shuffle64', + 131072: 'nir_lower_scan_reduce_bitwise64', + 262144: 'nir_lower_scan_reduce_iadd64', + 524288: 'nir_lower_vote_ieq64', + 1048576: 'nir_lower_usub_sat64', + 2097152: 'nir_lower_iadd_sat64', + 4194304: 'nir_lower_find_lsb64', + 8388608: 'nir_lower_conv64', + 16777216: 'nir_lower_uadd_sat64', + 33554432: 'nir_lower_iadd3_64', + 67108864: 'nir_lower_bitfield_reverse64', + 134217728: 'nir_lower_bitfield_extract64', +} +nir_lower_imul64 = 1 +nir_lower_isign64 = 2 +nir_lower_divmod64 = 4 +nir_lower_imul_high64 = 8 +nir_lower_bcsel64 = 16 +nir_lower_icmp64 = 32 +nir_lower_iadd64 = 64 +nir_lower_iabs64 = 128 +nir_lower_ineg64 = 256 +nir_lower_logic64 = 512 +nir_lower_minmax64 = 1024 +nir_lower_shift64 = 2048 +nir_lower_imul_2x32_64 = 4096 +nir_lower_extract64 = 8192 +nir_lower_ufind_msb64 = 16384 +nir_lower_bit_count64 = 32768 +nir_lower_subgroup_shuffle64 = 65536 +nir_lower_scan_reduce_bitwise64 = 131072 +nir_lower_scan_reduce_iadd64 = 262144 +nir_lower_vote_ieq64 = 524288 +nir_lower_usub_sat64 = 1048576 +nir_lower_iadd_sat64 = 2097152 +nir_lower_find_lsb64 = 4194304 +nir_lower_conv64 = 8388608 +nir_lower_uadd_sat64 = 16777216 +nir_lower_iadd3_64 = 33554432 +nir_lower_bitfield_reverse64 = 67108864 +nir_lower_bitfield_extract64 = 134217728 +c__EA_nir_lower_int64_options = ctypes.c_uint32 # enum +nir_lower_int64_options = c__EA_nir_lower_int64_options +nir_lower_int64_options__enumvalues = c__EA_nir_lower_int64_options__enumvalues + +# values for enumeration 'c__EA_nir_lower_doubles_options' +c__EA_nir_lower_doubles_options__enumvalues = { + 1: 'nir_lower_drcp', + 2: 'nir_lower_dsqrt', + 4: 'nir_lower_drsq', + 8: 'nir_lower_dtrunc', + 16: 'nir_lower_dfloor', + 32: 'nir_lower_dceil', + 64: 'nir_lower_dfract', + 128: 'nir_lower_dround_even', + 256: 'nir_lower_dmod', + 512: 'nir_lower_dsub', + 1024: 'nir_lower_ddiv', + 2048: 'nir_lower_dsign', + 4096: 'nir_lower_dminmax', + 8192: 'nir_lower_dsat', + 16384: 'nir_lower_fp64_full_software', +} +nir_lower_drcp = 1 +nir_lower_dsqrt = 2 +nir_lower_drsq = 4 +nir_lower_dtrunc = 8 +nir_lower_dfloor = 16 +nir_lower_dceil = 32 +nir_lower_dfract = 64 +nir_lower_dround_even = 128 +nir_lower_dmod = 256 +nir_lower_dsub = 512 +nir_lower_ddiv = 1024 +nir_lower_dsign = 2048 +nir_lower_dminmax = 4096 +nir_lower_dsat = 8192 +nir_lower_fp64_full_software = 16384 +c__EA_nir_lower_doubles_options = ctypes.c_uint32 # enum +nir_lower_doubles_options = c__EA_nir_lower_doubles_options +nir_lower_doubles_options__enumvalues = c__EA_nir_lower_doubles_options__enumvalues + +# values for enumeration 'c__EA_nir_divergence_options' +c__EA_nir_divergence_options__enumvalues = { + 1: 'nir_divergence_single_prim_per_subgroup', + 2: 'nir_divergence_single_patch_per_tcs_subgroup', + 4: 'nir_divergence_single_patch_per_tes_subgroup', + 8: 'nir_divergence_view_index_uniform', + 16: 'nir_divergence_single_frag_shading_rate_per_subgroup', + 32: 'nir_divergence_multiple_workgroup_per_compute_subgroup', + 64: 'nir_divergence_shader_record_ptr_uniform', + 128: 'nir_divergence_uniform_load_tears', + 256: 'nir_divergence_ignore_undef_if_phi_srcs', +} +nir_divergence_single_prim_per_subgroup = 1 +nir_divergence_single_patch_per_tcs_subgroup = 2 +nir_divergence_single_patch_per_tes_subgroup = 4 +nir_divergence_view_index_uniform = 8 +nir_divergence_single_frag_shading_rate_per_subgroup = 16 +nir_divergence_multiple_workgroup_per_compute_subgroup = 32 +nir_divergence_shader_record_ptr_uniform = 64 +nir_divergence_uniform_load_tears = 128 +nir_divergence_ignore_undef_if_phi_srcs = 256 +c__EA_nir_divergence_options = ctypes.c_uint32 # enum +nir_divergence_options = c__EA_nir_divergence_options +nir_divergence_options__enumvalues = c__EA_nir_divergence_options__enumvalues +class struct_nir_instr(Structure): + pass + +class struct_nir_block(Structure): + pass + +class struct_exec_node(Structure): + pass + +struct_exec_node._pack_ = 1 # source:False +struct_exec_node._fields_ = [ + ('next', ctypes.POINTER(struct_exec_node)), + ('prev', ctypes.POINTER(struct_exec_node)), +] + +struct_nir_instr._pack_ = 1 # source:False +struct_nir_instr._fields_ = [ + ('node', struct_exec_node), + ('block', ctypes.POINTER(struct_nir_block)), + ('type', ctypes.c_ubyte), + ('pass_flags', ctypes.c_ubyte), + ('has_debug_info', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte), + ('index', ctypes.c_uint32), +] + +class struct_set(Structure): + pass + +class struct_nir_cf_node(Structure): + pass + + +# values for enumeration 'c__EA_nir_cf_node_type' +c__EA_nir_cf_node_type__enumvalues = { + 0: 'nir_cf_node_block', + 1: 'nir_cf_node_if', + 2: 'nir_cf_node_loop', + 3: 'nir_cf_node_function', +} +nir_cf_node_block = 0 +nir_cf_node_if = 1 +nir_cf_node_loop = 2 +nir_cf_node_function = 3 +c__EA_nir_cf_node_type = ctypes.c_uint32 # enum +struct_nir_cf_node._pack_ = 1 # source:False +struct_nir_cf_node._fields_ = [ + ('node', struct_exec_node), + ('type', c__EA_nir_cf_node_type), + ('PADDING_0', ctypes.c_ubyte * 4), + ('parent', ctypes.POINTER(struct_nir_cf_node)), +] + +class struct_exec_list(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('head_sentinel', struct_exec_node), + ('tail_sentinel', struct_exec_node), + ] + +struct_nir_block._pack_ = 1 # source:False +struct_nir_block._fields_ = [ + ('cf_node', struct_nir_cf_node), + ('instr_list', struct_exec_list), + ('index', ctypes.c_uint32), + ('divergent', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('successors', ctypes.POINTER(struct_nir_block) * 2), + ('predecessors', ctypes.POINTER(struct_set)), + ('imm_dom', ctypes.POINTER(struct_nir_block)), + ('num_dom_children', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('dom_children', ctypes.POINTER(ctypes.POINTER(struct_nir_block))), + ('dom_frontier', ctypes.POINTER(struct_set)), + ('dom_pre_index', ctypes.c_uint32), + ('dom_post_index', ctypes.c_uint32), + ('start_ip', ctypes.c_uint32), + ('end_ip', ctypes.c_uint32), + ('live_in', ctypes.POINTER(ctypes.c_uint32)), + ('live_out', ctypes.POINTER(ctypes.c_uint32)), +] + +class struct_set_entry(Structure): + pass + +struct_set._pack_ = 1 # source:False +struct_set._fields_ = [ + ('mem_ctx', ctypes.POINTER(None)), + ('table', ctypes.POINTER(struct_set_entry)), + ('key_hash_function', ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(None))), + ('key_equals_function', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(None), ctypes.POINTER(None))), + ('size', ctypes.c_uint32), + ('rehash', ctypes.c_uint32), + ('size_magic', ctypes.c_uint64), + ('rehash_magic', ctypes.c_uint64), + ('max_entries', ctypes.c_uint32), + ('size_index', ctypes.c_uint32), + ('entries', ctypes.c_uint32), + ('deleted_entries', ctypes.c_uint32), +] + +struct_set_entry._pack_ = 1 # source:False +struct_set_entry._fields_ = [ + ('hash', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('key', ctypes.POINTER(None)), +] + +nir_instr_filter_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)) + +# values for enumeration 'c__EA_nir_io_options' +c__EA_nir_io_options__enumvalues = { + 1: 'nir_io_has_flexible_input_interpolation_except_flat', + 2: 'nir_io_dont_use_pos_for_non_fs_varyings', + 4: 'nir_io_16bit_input_output_support', + 8: 'nir_io_mediump_is_32bit', + 16: 'nir_io_prefer_scalar_fs_inputs', + 32: 'nir_io_mix_convergent_flat_with_interpolated', + 64: 'nir_io_vectorizer_ignores_types', + 128: 'nir_io_always_interpolate_convergent_fs_inputs', + 256: 'nir_io_compaction_rotates_color_channels', + 512: 'nir_io_compaction_groups_tes_inputs_into_pos_and_var_groups', + 1024: 'nir_io_radv_intrinsic_component_workaround', + 65536: 'nir_io_has_intrinsics', + 131072: 'nir_io_separate_clip_cull_distance_arrays', +} +nir_io_has_flexible_input_interpolation_except_flat = 1 +nir_io_dont_use_pos_for_non_fs_varyings = 2 +nir_io_16bit_input_output_support = 4 +nir_io_mediump_is_32bit = 8 +nir_io_prefer_scalar_fs_inputs = 16 +nir_io_mix_convergent_flat_with_interpolated = 32 +nir_io_vectorizer_ignores_types = 64 +nir_io_always_interpolate_convergent_fs_inputs = 128 +nir_io_compaction_rotates_color_channels = 256 +nir_io_compaction_groups_tes_inputs_into_pos_and_var_groups = 512 +nir_io_radv_intrinsic_component_workaround = 1024 +nir_io_has_intrinsics = 65536 +nir_io_separate_clip_cull_distance_arrays = 131072 +c__EA_nir_io_options = ctypes.c_uint32 # enum +nir_io_options = c__EA_nir_io_options +nir_io_options__enumvalues = c__EA_nir_io_options__enumvalues + +# values for enumeration 'c__EA_nir_lower_packing_op' +c__EA_nir_lower_packing_op__enumvalues = { + 0: 'nir_lower_packing_op_pack_64_2x32', + 1: 'nir_lower_packing_op_unpack_64_2x32', + 2: 'nir_lower_packing_op_pack_64_4x16', + 3: 'nir_lower_packing_op_unpack_64_4x16', + 4: 'nir_lower_packing_op_pack_32_2x16', + 5: 'nir_lower_packing_op_unpack_32_2x16', + 6: 'nir_lower_packing_op_pack_32_4x8', + 7: 'nir_lower_packing_op_unpack_32_4x8', + 8: 'nir_lower_packing_num_ops', +} +nir_lower_packing_op_pack_64_2x32 = 0 +nir_lower_packing_op_unpack_64_2x32 = 1 +nir_lower_packing_op_pack_64_4x16 = 2 +nir_lower_packing_op_unpack_64_4x16 = 3 +nir_lower_packing_op_pack_32_2x16 = 4 +nir_lower_packing_op_unpack_32_2x16 = 5 +nir_lower_packing_op_pack_32_4x8 = 6 +nir_lower_packing_op_unpack_32_4x8 = 7 +nir_lower_packing_num_ops = 8 +c__EA_nir_lower_packing_op = ctypes.c_uint32 # enum +nir_lower_packing_op = c__EA_nir_lower_packing_op +nir_lower_packing_op__enumvalues = c__EA_nir_lower_packing_op__enumvalues +class struct_nir_shader_compiler_options(Structure): + pass + + +# values for enumeration 'c__EA_nir_variable_mode' +c__EA_nir_variable_mode__enumvalues = { + 1: 'nir_var_system_value', + 2: 'nir_var_uniform', + 4: 'nir_var_shader_in', + 8: 'nir_var_shader_out', + 16: 'nir_var_image', + 32: 'nir_var_shader_call_data', + 64: 'nir_var_ray_hit_attrib', + 128: 'nir_var_mem_ubo', + 256: 'nir_var_mem_push_const', + 512: 'nir_var_mem_ssbo', + 1024: 'nir_var_mem_constant', + 2048: 'nir_var_mem_task_payload', + 4096: 'nir_var_mem_node_payload', + 8192: 'nir_var_mem_node_payload_in', + 16384: 'nir_var_function_in', + 32768: 'nir_var_function_out', + 65536: 'nir_var_function_inout', + 131072: 'nir_var_shader_temp', + 262144: 'nir_var_function_temp', + 524288: 'nir_var_mem_shared', + 1048576: 'nir_var_mem_global', + 1966080: 'nir_var_mem_generic', + 1159: 'nir_var_read_only_modes', + 1969033: 'nir_var_vec_indexable_modes', + 21: 'nir_num_variable_modes', + 2097151: 'nir_var_all', +} +nir_var_system_value = 1 +nir_var_uniform = 2 +nir_var_shader_in = 4 +nir_var_shader_out = 8 +nir_var_image = 16 +nir_var_shader_call_data = 32 +nir_var_ray_hit_attrib = 64 +nir_var_mem_ubo = 128 +nir_var_mem_push_const = 256 +nir_var_mem_ssbo = 512 +nir_var_mem_constant = 1024 +nir_var_mem_task_payload = 2048 +nir_var_mem_node_payload = 4096 +nir_var_mem_node_payload_in = 8192 +nir_var_function_in = 16384 +nir_var_function_out = 32768 +nir_var_function_inout = 65536 +nir_var_shader_temp = 131072 +nir_var_function_temp = 262144 +nir_var_mem_shared = 524288 +nir_var_mem_global = 1048576 +nir_var_mem_generic = 1966080 +nir_var_read_only_modes = 1159 +nir_var_vec_indexable_modes = 1969033 +nir_num_variable_modes = 21 +nir_var_all = 2097151 +c__EA_nir_variable_mode = ctypes.c_uint32 # enum +class struct_nir_shader(Structure): + pass + +struct_nir_shader_compiler_options._pack_ = 1 # source:False +struct_nir_shader_compiler_options._fields_ = [ + ('lower_fdiv', ctypes.c_bool), + ('lower_ffma16', ctypes.c_bool), + ('lower_ffma32', ctypes.c_bool), + ('lower_ffma64', ctypes.c_bool), + ('fuse_ffma16', ctypes.c_bool), + ('fuse_ffma32', ctypes.c_bool), + ('fuse_ffma64', ctypes.c_bool), + ('lower_flrp16', ctypes.c_bool), + ('lower_flrp32', ctypes.c_bool), + ('lower_flrp64', ctypes.c_bool), + ('lower_fpow', ctypes.c_bool), + ('lower_fsat', ctypes.c_bool), + ('lower_fsqrt', ctypes.c_bool), + ('lower_sincos', ctypes.c_bool), + ('lower_fmod', ctypes.c_bool), + ('lower_bitfield_extract8', ctypes.c_bool), + ('lower_bitfield_extract16', ctypes.c_bool), + ('lower_bitfield_extract', ctypes.c_bool), + ('lower_bitfield_insert', ctypes.c_bool), + ('lower_bitfield_reverse', ctypes.c_bool), + ('lower_bit_count', ctypes.c_bool), + ('lower_ifind_msb', ctypes.c_bool), + ('lower_ufind_msb', ctypes.c_bool), + ('lower_find_lsb', ctypes.c_bool), + ('lower_uadd_carry', ctypes.c_bool), + ('lower_usub_borrow', ctypes.c_bool), + ('lower_mul_high', ctypes.c_bool), + ('lower_mul_high16', ctypes.c_bool), + ('lower_fneg', ctypes.c_bool), + ('lower_ineg', ctypes.c_bool), + ('lower_fisnormal', ctypes.c_bool), + ('lower_scmp', ctypes.c_bool), + ('lower_vector_cmp', ctypes.c_bool), + ('lower_bitops', ctypes.c_bool), + ('lower_isign', ctypes.c_bool), + ('lower_fsign', ctypes.c_bool), + ('lower_iabs', ctypes.c_bool), + ('lower_umax', ctypes.c_bool), + ('lower_umin', ctypes.c_bool), + ('lower_fminmax_signed_zero', ctypes.c_bool), + ('lower_fdph', ctypes.c_bool), + ('fdot_replicates', ctypes.c_bool), + ('lower_ffloor', ctypes.c_bool), + ('lower_ffract', ctypes.c_bool), + ('lower_fceil', ctypes.c_bool), + ('lower_ftrunc', ctypes.c_bool), + ('lower_fround_even', ctypes.c_bool), + ('lower_ldexp', ctypes.c_bool), + ('lower_pack_half_2x16', ctypes.c_bool), + ('lower_pack_unorm_2x16', ctypes.c_bool), + ('lower_pack_snorm_2x16', ctypes.c_bool), + ('lower_pack_unorm_4x8', ctypes.c_bool), + ('lower_pack_snorm_4x8', ctypes.c_bool), + ('lower_pack_64_2x32', ctypes.c_bool), + ('lower_pack_64_4x16', ctypes.c_bool), + ('lower_pack_32_2x16', ctypes.c_bool), + ('lower_pack_64_2x32_split', ctypes.c_bool), + ('lower_pack_32_2x16_split', ctypes.c_bool), + ('lower_unpack_half_2x16', ctypes.c_bool), + ('lower_unpack_unorm_2x16', ctypes.c_bool), + ('lower_unpack_snorm_2x16', ctypes.c_bool), + ('lower_unpack_unorm_4x8', ctypes.c_bool), + ('lower_unpack_snorm_4x8', ctypes.c_bool), + ('lower_unpack_64_2x32_split', ctypes.c_bool), + ('lower_unpack_32_2x16_split', ctypes.c_bool), + ('lower_pack_split', ctypes.c_bool), + ('lower_extract_byte', ctypes.c_bool), + ('lower_extract_word', ctypes.c_bool), + ('lower_insert_byte', ctypes.c_bool), + ('lower_insert_word', ctypes.c_bool), + ('vertex_id_zero_based', ctypes.c_bool), + ('lower_base_vertex', ctypes.c_bool), + ('instance_id_includes_base_index', ctypes.c_bool), + ('lower_helper_invocation', ctypes.c_bool), + ('optimize_sample_mask_in', ctypes.c_bool), + ('optimize_load_front_face_fsign', ctypes.c_bool), + ('optimize_quad_vote_to_reduce', ctypes.c_bool), + ('lower_cs_local_index_to_id', ctypes.c_bool), + ('lower_cs_local_id_to_index', ctypes.c_bool), + ('has_cs_global_id', ctypes.c_bool), + ('lower_device_index_to_zero', ctypes.c_bool), + ('lower_wpos_pntc', ctypes.c_bool), + ('lower_hadd', ctypes.c_bool), + ('lower_hadd64', ctypes.c_bool), + ('lower_uadd_sat', ctypes.c_bool), + ('lower_usub_sat', ctypes.c_bool), + ('lower_iadd_sat', ctypes.c_bool), + ('lower_mul_32x16', ctypes.c_bool), + ('lower_bfloat16_conversions', ctypes.c_bool), + ('vectorize_tess_levels', ctypes.c_bool), + ('lower_to_scalar', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 5), + ('lower_to_scalar_filter', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('vectorize_vec2_16bit', ctypes.c_bool), + ('unify_interfaces', ctypes.c_bool), + ('lower_interpolate_at', ctypes.c_bool), + ('lower_mul_2x32_64', ctypes.c_bool), + ('has_rotate8', ctypes.c_bool), + ('has_rotate16', ctypes.c_bool), + ('has_rotate32', ctypes.c_bool), + ('has_shfr32', ctypes.c_bool), + ('has_iadd3', ctypes.c_bool), + ('has_amul', ctypes.c_bool), + ('has_imul24', ctypes.c_bool), + ('has_umul24', ctypes.c_bool), + ('has_mul24_relaxed', ctypes.c_bool), + ('has_imad32', ctypes.c_bool), + ('has_umad24', ctypes.c_bool), + ('has_fused_comp_and_csel', ctypes.c_bool), + ('has_icsel_eqz64', ctypes.c_bool), + ('has_icsel_eqz32', ctypes.c_bool), + ('has_icsel_eqz16', ctypes.c_bool), + ('has_fneo_fcmpu', ctypes.c_bool), + ('has_ford_funord', ctypes.c_bool), + ('has_fsub', ctypes.c_bool), + ('has_isub', ctypes.c_bool), + ('has_pack_32_4x8', ctypes.c_bool), + ('has_texture_scaling', ctypes.c_bool), + ('has_sdot_4x8', ctypes.c_bool), + ('has_udot_4x8', ctypes.c_bool), + ('has_sudot_4x8', ctypes.c_bool), + ('has_sdot_4x8_sat', ctypes.c_bool), + ('has_udot_4x8_sat', ctypes.c_bool), + ('has_sudot_4x8_sat', ctypes.c_bool), + ('has_dot_2x16', ctypes.c_bool), + ('has_bfdot2_bfadd', ctypes.c_bool), + ('has_fmulz', ctypes.c_bool), + ('has_fmulz_no_denorms', ctypes.c_bool), + ('has_find_msb_rev', ctypes.c_bool), + ('has_pack_half_2x16_rtz', ctypes.c_bool), + ('has_bit_test', ctypes.c_bool), + ('has_bfe', ctypes.c_bool), + ('has_bfm', ctypes.c_bool), + ('has_bfi', ctypes.c_bool), + ('has_bitfield_select', ctypes.c_bool), + ('has_uclz', ctypes.c_bool), + ('has_msad', ctypes.c_bool), + ('has_f2e4m3fn_satfn', ctypes.c_bool), + ('has_load_global_bounded', ctypes.c_bool), + ('intel_vec4', ctypes.c_bool), + ('avoid_ternary_with_two_constants', ctypes.c_bool), + ('support_8bit_alu', ctypes.c_bool), + ('support_16bit_alu', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 2), + ('max_unroll_iterations', ctypes.c_uint32), + ('max_unroll_iterations_aggressive', ctypes.c_uint32), + ('max_unroll_iterations_fp64', ctypes.c_uint32), + ('lower_uniforms_to_ubo', ctypes.c_bool), + ('force_indirect_unrolling_sampler', ctypes.c_bool), + ('no_integers', ctypes.c_bool), + ('PADDING_2', ctypes.c_ubyte), + ('force_indirect_unrolling', c__EA_nir_variable_mode), + ('driver_functions', ctypes.c_bool), + ('late_lower_int64', ctypes.c_bool), + ('PADDING_3', ctypes.c_ubyte * 2), + ('lower_int64_options', nir_lower_int64_options), + ('lower_doubles_options', nir_lower_doubles_options), + ('divergence_analysis_options', nir_divergence_options), + ('support_indirect_inputs', ctypes.c_ubyte), + ('support_indirect_outputs', ctypes.c_ubyte), + ('lower_image_offset_to_range_base', ctypes.c_bool), + ('lower_atomic_offset_to_range_base', ctypes.c_bool), + ('preserve_mediump', ctypes.c_bool), + ('lower_fquantize2f16', ctypes.c_bool), + ('force_f2f16_rtz', ctypes.c_bool), + ('lower_layer_fs_input_to_sysval', ctypes.c_bool), + ('compact_arrays', ctypes.c_bool), + ('discard_is_demote', ctypes.c_bool), + ('has_ddx_intrinsics', ctypes.c_bool), + ('scalarize_ddx', ctypes.c_bool), + ('per_view_unique_driver_locations', ctypes.c_bool), + ('compact_view_index', ctypes.c_bool), + ('PADDING_4', ctypes.c_ubyte * 2), + ('io_options', nir_io_options), + ('skip_lower_packing_ops', ctypes.c_uint32), + ('lower_mediump_io', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_nir_shader))), + ('varying_expression_max_cost', ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader))), + ('varying_estimate_instr_cost', ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(struct_nir_instr))), + ('max_varying_expression_cost', ctypes.c_uint32), + ('PADDING_5', ctypes.c_ubyte * 4), +] + +class struct_nir_xfb_info(Structure): + pass + +class struct_u_printf_info(Structure): + pass + +class struct_shader_info(Structure): + pass + + +# values for enumeration 'pipe_shader_type' +pipe_shader_type__enumvalues = { + -1: 'MESA_SHADER_NONE', + 0: 'MESA_SHADER_VERTEX', + 0: 'PIPE_SHADER_VERTEX', + 1: 'MESA_SHADER_TESS_CTRL', + 1: 'PIPE_SHADER_TESS_CTRL', + 2: 'MESA_SHADER_TESS_EVAL', + 2: 'PIPE_SHADER_TESS_EVAL', + 3: 'MESA_SHADER_GEOMETRY', + 3: 'PIPE_SHADER_GEOMETRY', + 4: 'MESA_SHADER_FRAGMENT', + 4: 'PIPE_SHADER_FRAGMENT', + 5: 'MESA_SHADER_COMPUTE', + 5: 'PIPE_SHADER_COMPUTE', + 6: 'PIPE_SHADER_TYPES', + 6: 'MESA_SHADER_TASK', + 6: 'PIPE_SHADER_TASK', + 7: 'MESA_SHADER_MESH', + 7: 'PIPE_SHADER_MESH', + 8: 'PIPE_SHADER_MESH_TYPES', + 8: 'MESA_SHADER_RAYGEN', + 9: 'MESA_SHADER_ANY_HIT', + 10: 'MESA_SHADER_CLOSEST_HIT', + 11: 'MESA_SHADER_MISS', + 12: 'MESA_SHADER_INTERSECTION', + 13: 'MESA_SHADER_CALLABLE', + 14: 'MESA_SHADER_KERNEL', +} +MESA_SHADER_NONE = -1 +MESA_SHADER_VERTEX = 0 +PIPE_SHADER_VERTEX = 0 +MESA_SHADER_TESS_CTRL = 1 +PIPE_SHADER_TESS_CTRL = 1 +MESA_SHADER_TESS_EVAL = 2 +PIPE_SHADER_TESS_EVAL = 2 +MESA_SHADER_GEOMETRY = 3 +PIPE_SHADER_GEOMETRY = 3 +MESA_SHADER_FRAGMENT = 4 +PIPE_SHADER_FRAGMENT = 4 +MESA_SHADER_COMPUTE = 5 +PIPE_SHADER_COMPUTE = 5 +PIPE_SHADER_TYPES = 6 +MESA_SHADER_TASK = 6 +PIPE_SHADER_TASK = 6 +MESA_SHADER_MESH = 7 +PIPE_SHADER_MESH = 7 +PIPE_SHADER_MESH_TYPES = 8 +MESA_SHADER_RAYGEN = 8 +MESA_SHADER_ANY_HIT = 9 +MESA_SHADER_CLOSEST_HIT = 10 +MESA_SHADER_MISS = 11 +MESA_SHADER_INTERSECTION = 12 +MESA_SHADER_CALLABLE = 13 +MESA_SHADER_KERNEL = 14 +pipe_shader_type = ctypes.c_int32 # enum + +# values for enumeration 'gl_subgroup_size' +gl_subgroup_size__enumvalues = { + 0: 'SUBGROUP_SIZE_VARYING', + 1: 'SUBGROUP_SIZE_UNIFORM', + 2: 'SUBGROUP_SIZE_API_CONSTANT', + 3: 'SUBGROUP_SIZE_FULL_SUBGROUPS', + 4: 'SUBGROUP_SIZE_REQUIRE_4', + 8: 'SUBGROUP_SIZE_REQUIRE_8', + 16: 'SUBGROUP_SIZE_REQUIRE_16', + 32: 'SUBGROUP_SIZE_REQUIRE_32', + 64: 'SUBGROUP_SIZE_REQUIRE_64', + 128: 'SUBGROUP_SIZE_REQUIRE_128', +} +SUBGROUP_SIZE_VARYING = 0 +SUBGROUP_SIZE_UNIFORM = 1 +SUBGROUP_SIZE_API_CONSTANT = 2 +SUBGROUP_SIZE_FULL_SUBGROUPS = 3 +SUBGROUP_SIZE_REQUIRE_4 = 4 +SUBGROUP_SIZE_REQUIRE_8 = 8 +SUBGROUP_SIZE_REQUIRE_16 = 16 +SUBGROUP_SIZE_REQUIRE_32 = 32 +SUBGROUP_SIZE_REQUIRE_64 = 64 +SUBGROUP_SIZE_REQUIRE_128 = 128 +gl_subgroup_size = ctypes.c_uint32 # enum + +# values for enumeration 'gl_derivative_group' +gl_derivative_group__enumvalues = { + 0: 'DERIVATIVE_GROUP_NONE', + 1: 'DERIVATIVE_GROUP_QUADS', + 2: 'DERIVATIVE_GROUP_LINEAR', +} +DERIVATIVE_GROUP_NONE = 0 +DERIVATIVE_GROUP_QUADS = 1 +DERIVATIVE_GROUP_LINEAR = 2 +gl_derivative_group = ctypes.c_uint32 # enum +class union_shader_info_0(Union): + pass + +class struct_shader_info_0_vs(Structure): + pass + +struct_shader_info_0_vs._pack_ = 1 # source:False +struct_shader_info_0_vs._fields_ = [ + ('double_inputs', ctypes.c_uint64), + ('blit_sgprs_amd', ctypes.c_ubyte, 4), + ('tes_agx', ctypes.c_ubyte, 1), + ('window_space_position', ctypes.c_ubyte, 1), + ('needs_edge_flag', ctypes.c_ubyte, 1), + ('PADDING_0', ctypes.c_uint64, 57), +] + +class struct_shader_info_0_gs(Structure): + pass + + +# values for enumeration 'mesa_prim' +mesa_prim__enumvalues = { + 0: 'MESA_PRIM_POINTS', + 1: 'MESA_PRIM_LINES', + 2: 'MESA_PRIM_LINE_LOOP', + 3: 'MESA_PRIM_LINE_STRIP', + 4: 'MESA_PRIM_TRIANGLES', + 5: 'MESA_PRIM_TRIANGLE_STRIP', + 6: 'MESA_PRIM_TRIANGLE_FAN', + 7: 'MESA_PRIM_QUADS', + 8: 'MESA_PRIM_QUAD_STRIP', + 9: 'MESA_PRIM_POLYGON', + 10: 'MESA_PRIM_LINES_ADJACENCY', + 11: 'MESA_PRIM_LINE_STRIP_ADJACENCY', + 12: 'MESA_PRIM_TRIANGLES_ADJACENCY', + 13: 'MESA_PRIM_TRIANGLE_STRIP_ADJACENCY', + 14: 'MESA_PRIM_PATCHES', + 14: 'MESA_PRIM_MAX', + 15: 'MESA_PRIM_COUNT', + 28: 'MESA_PRIM_UNKNOWN', +} +MESA_PRIM_POINTS = 0 +MESA_PRIM_LINES = 1 +MESA_PRIM_LINE_LOOP = 2 +MESA_PRIM_LINE_STRIP = 3 +MESA_PRIM_TRIANGLES = 4 +MESA_PRIM_TRIANGLE_STRIP = 5 +MESA_PRIM_TRIANGLE_FAN = 6 +MESA_PRIM_QUADS = 7 +MESA_PRIM_QUAD_STRIP = 8 +MESA_PRIM_POLYGON = 9 +MESA_PRIM_LINES_ADJACENCY = 10 +MESA_PRIM_LINE_STRIP_ADJACENCY = 11 +MESA_PRIM_TRIANGLES_ADJACENCY = 12 +MESA_PRIM_TRIANGLE_STRIP_ADJACENCY = 13 +MESA_PRIM_PATCHES = 14 +MESA_PRIM_MAX = 14 +MESA_PRIM_COUNT = 15 +MESA_PRIM_UNKNOWN = 28 +mesa_prim = ctypes.c_uint32 # enum +struct_shader_info_0_gs._pack_ = 1 # source:False +struct_shader_info_0_gs._fields_ = [ + ('output_primitive', mesa_prim), + ('input_primitive', mesa_prim), + ('vertices_out', ctypes.c_uint16), + ('invocations', ctypes.c_ubyte), + ('vertices_in', ctypes.c_ubyte, 3), + ('uses_end_primitive', ctypes.c_ubyte, 1), + ('active_stream_mask', ctypes.c_ubyte, 4), +] + +class struct_shader_info_0_fs(Structure): + pass + + +# values for enumeration 'c_uint64' +c_uint64__enumvalues = { + 0: 'FRAG_DEPTH_LAYOUT_NONE', + 1: 'FRAG_DEPTH_LAYOUT_ANY', + 2: 'FRAG_DEPTH_LAYOUT_GREATER', + 3: 'FRAG_DEPTH_LAYOUT_LESS', + 4: 'FRAG_DEPTH_LAYOUT_UNCHANGED', +} +FRAG_DEPTH_LAYOUT_NONE = 0 +FRAG_DEPTH_LAYOUT_ANY = 1 +FRAG_DEPTH_LAYOUT_GREATER = 2 +FRAG_DEPTH_LAYOUT_LESS = 3 +FRAG_DEPTH_LAYOUT_UNCHANGED = 4 +c_uint64 = ctypes.c_uint32 # enum + +# values for enumeration 'c_bool' +c_bool__enumvalues = { + 0: 'FRAG_STENCIL_LAYOUT_NONE', + 1: 'FRAG_STENCIL_LAYOUT_ANY', + 2: 'FRAG_STENCIL_LAYOUT_GREATER', + 3: 'FRAG_STENCIL_LAYOUT_LESS', + 4: 'FRAG_STENCIL_LAYOUT_UNCHANGED', +} +FRAG_STENCIL_LAYOUT_NONE = 0 +FRAG_STENCIL_LAYOUT_ANY = 1 +FRAG_STENCIL_LAYOUT_GREATER = 2 +FRAG_STENCIL_LAYOUT_LESS = 3 +FRAG_STENCIL_LAYOUT_UNCHANGED = 4 +c_bool = ctypes.c_uint32 # enum +struct_shader_info_0_fs._pack_ = 1 # source:False +struct_shader_info_0_fs._fields_ = [ + ('uses_discard', ctypes.c_uint64, 1), + ('uses_fbfetch_output', ctypes.c_uint64, 1), + ('fbfetch_coherent', ctypes.c_uint64, 1), + ('color_is_dual_source', ctypes.c_uint64, 1), + ('require_full_quads', ctypes.c_uint64, 1), + ('quad_derivatives', ctypes.c_uint64, 1), + ('needs_coarse_quad_helper_invocations', ctypes.c_uint64, 1), + ('needs_full_quad_helper_invocations', ctypes.c_uint64, 1), + ('uses_sample_qualifier', ctypes.c_uint64, 1), + ('uses_sample_shading', ctypes.c_uint64, 1), + ('early_fragment_tests', ctypes.c_uint64, 1), + ('inner_coverage', ctypes.c_uint64, 1), + ('post_depth_coverage', ctypes.c_uint64, 1), + ('pixel_center_integer', ctypes.c_uint64, 1), + ('origin_upper_left', ctypes.c_uint64, 1), + ('pixel_interlock_ordered', ctypes.c_uint64, 1), + ('pixel_interlock_unordered', ctypes.c_uint64, 1), + ('sample_interlock_ordered', ctypes.c_uint64, 1), + ('sample_interlock_unordered', ctypes.c_uint64, 1), + ('untyped_color_outputs', ctypes.c_uint64, 1), + ('depth_layout', c_uint64, 3), + ('color0_interp', ctypes.c_uint64, 3), + ('color0_sample', ctypes.c_uint64, 1), + ('color0_centroid', ctypes.c_uint64, 1), + ('color1_interp', ctypes.c_uint64, 3), + ('color1_sample', ctypes.c_uint64, 1), + ('color1_centroid', ctypes.c_uint64, 1), + ('PADDING_0', ctypes.c_uint32, 31), + ('advanced_blend_modes', ctypes.c_uint32), + ('early_and_late_fragment_tests', ctypes.c_bool, 1), + ('stencil_front_layout', c_bool, 3), + ('stencil_back_layout', c_bool, 3), + ('PADDING_1', ctypes.c_uint32, 25), +] + +class struct_shader_info_0_cs(Structure): + pass + +struct_shader_info_0_cs._pack_ = 1 # source:False +struct_shader_info_0_cs._fields_ = [ + ('workgroup_size_hint', ctypes.c_uint16 * 3), + ('user_data_components_amd', ctypes.c_ubyte, 4), + ('has_variable_shared_mem', ctypes.c_ubyte, 1), + ('has_cooperative_matrix', ctypes.c_ubyte, 1), + ('PADDING_0', ctypes.c_uint8, 2), + ('image_block_size_per_thread_agx', ctypes.c_ubyte, 8), + ('ptr_size', ctypes.c_uint32), + ('shader_index', ctypes.c_uint32), + ('node_payloads_size', ctypes.c_uint32), + ('workgroup_count', ctypes.c_uint32 * 3), +] + +class struct_shader_info_0_tess(Structure): + pass + + +# values for enumeration 'tess_primitive_mode' +tess_primitive_mode__enumvalues = { + 0: 'TESS_PRIMITIVE_UNSPECIFIED', + 1: 'TESS_PRIMITIVE_TRIANGLES', + 2: 'TESS_PRIMITIVE_QUADS', + 3: 'TESS_PRIMITIVE_ISOLINES', +} +TESS_PRIMITIVE_UNSPECIFIED = 0 +TESS_PRIMITIVE_TRIANGLES = 1 +TESS_PRIMITIVE_QUADS = 2 +TESS_PRIMITIVE_ISOLINES = 3 +tess_primitive_mode = ctypes.c_uint32 # enum +struct_shader_info_0_tess._pack_ = 1 # source:False +struct_shader_info_0_tess._fields_ = [ + ('_primitive_mode', tess_primitive_mode), + ('tcs_vertices_out', ctypes.c_ubyte), + ('spacing', ctypes.c_uint32, 2), + ('ccw', ctypes.c_uint32, 1), + ('point_mode', ctypes.c_uint32, 1), + ('PADDING_0', ctypes.c_uint32, 20), + ('tcs_same_invocation_inputs_read', ctypes.c_uint64), + ('tcs_cross_invocation_inputs_read', ctypes.c_uint64), + ('tcs_cross_invocation_outputs_read', ctypes.c_uint64), + ('tcs_cross_invocation_outputs_written', ctypes.c_uint64), + ('tcs_outputs_read_by_tes', ctypes.c_uint64), + ('tcs_patch_outputs_read_by_tes', ctypes.c_uint32), + ('tcs_outputs_read_by_tes_16bit', ctypes.c_uint16), + ('PADDING_1', ctypes.c_ubyte * 2), +] + +class struct_shader_info_0_mesh(Structure): + pass + +struct_shader_info_0_mesh._pack_ = 1 # source:False +struct_shader_info_0_mesh._fields_ = [ + ('ms_cross_invocation_output_access', ctypes.c_uint64), + ('ts_mesh_dispatch_dimensions', ctypes.c_uint32 * 3), + ('max_vertices_out', ctypes.c_uint16), + ('max_primitives_out', ctypes.c_uint16), + ('primitive_type', mesa_prim), + ('nv', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), +] + +union_shader_info_0._pack_ = 1 # source:False +union_shader_info_0._fields_ = [ + ('vs', struct_shader_info_0_vs), + ('gs', struct_shader_info_0_gs), + ('fs', struct_shader_info_0_fs), + ('cs', struct_shader_info_0_cs), + ('tess', struct_shader_info_0_tess), + ('mesh', struct_shader_info_0_mesh), + ('PADDING_0', ctypes.c_ubyte * 24), +] + +struct_shader_info._pack_ = 1 # source:False +struct_shader_info._anonymous_ = ('_0',) +struct_shader_info._fields_ = [ + ('name', ctypes.POINTER(ctypes.c_char)), + ('label', ctypes.POINTER(ctypes.c_char)), + ('internal', ctypes.c_bool), + ('source_blake3', ctypes.c_ubyte * 32), + ('stage', ctypes.c_ubyte), + ('prev_stage', ctypes.c_ubyte), + ('next_stage', ctypes.c_ubyte), + ('prev_stage_has_xfb', ctypes.c_ubyte), + ('num_textures', ctypes.c_ubyte), + ('num_ubos', ctypes.c_ubyte), + ('num_abos', ctypes.c_ubyte), + ('num_ssbos', ctypes.c_ubyte), + ('num_images', ctypes.c_ubyte), + ('PADDING_0', ctypes.c_ubyte * 6), + ('inputs_read', ctypes.c_uint64), + ('dual_slot_inputs', ctypes.c_uint64), + ('outputs_written', ctypes.c_uint64), + ('outputs_read', ctypes.c_uint64), + ('system_values_read', ctypes.c_uint32 * 4), + ('per_primitive_inputs', ctypes.c_uint64), + ('per_primitive_outputs', ctypes.c_uint64), + ('per_view_outputs', ctypes.c_uint64), + ('view_mask', ctypes.c_uint32), + ('inputs_read_16bit', ctypes.c_uint16), + ('outputs_written_16bit', ctypes.c_uint16), + ('outputs_read_16bit', ctypes.c_uint16), + ('inputs_read_indirectly_16bit', ctypes.c_uint16), + ('outputs_read_indirectly_16bit', ctypes.c_uint16), + ('outputs_written_indirectly_16bit', ctypes.c_uint16), + ('patch_inputs_read', ctypes.c_uint32), + ('patch_outputs_written', ctypes.c_uint32), + ('patch_outputs_read', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('inputs_read_indirectly', ctypes.c_uint64), + ('outputs_read_indirectly', ctypes.c_uint64), + ('outputs_written_indirectly', ctypes.c_uint64), + ('patch_inputs_read_indirectly', ctypes.c_uint32), + ('patch_outputs_read_indirectly', ctypes.c_uint32), + ('patch_outputs_written_indirectly', ctypes.c_uint32), + ('textures_used', ctypes.c_uint32 * 4), + ('textures_used_by_txf', ctypes.c_uint32 * 4), + ('samplers_used', ctypes.c_uint32 * 1), + ('images_used', ctypes.c_uint32 * 2), + ('image_buffers', ctypes.c_uint32 * 2), + ('msaa_images', ctypes.c_uint32 * 2), + ('float_controls_execution_mode', ctypes.c_uint32), + ('shared_size', ctypes.c_uint32), + ('task_payload_size', ctypes.c_uint32), + ('ray_queries', ctypes.c_uint32), + ('workgroup_size', ctypes.c_uint16 * 3), + ('PADDING_2', ctypes.c_ubyte * 2), + ('subgroup_size', gl_subgroup_size), + ('num_subgroups', ctypes.c_ubyte), + ('uses_wide_subgroup_intrinsics', ctypes.c_bool), + ('xfb_stride', ctypes.c_ubyte * 4), + ('inlinable_uniform_dw_offsets', ctypes.c_uint16 * 4), + ('num_inlinable_uniforms', ctypes.c_ubyte, 4), + ('clip_distance_array_size', ctypes.c_ubyte, 4), + ('cull_distance_array_size', ctypes.c_ubyte, 4), + ('uses_texture_gather', ctypes.c_ubyte, 1), + ('uses_resource_info_query', ctypes.c_ubyte, 1), + ('PADDING_3', ctypes.c_uint8, 2), + ('bit_sizes_float', ctypes.c_ubyte, 8), + ('bit_sizes_int', ctypes.c_ubyte), + ('first_ubo_is_default_ubo', ctypes.c_bool, 1), + ('separate_shader', ctypes.c_bool, 1), + ('has_transform_feedback_varyings', ctypes.c_bool, 1), + ('flrp_lowered', ctypes.c_bool, 1), + ('io_lowered', ctypes.c_bool, 1), + ('var_copies_lowered', ctypes.c_bool, 1), + ('writes_memory', ctypes.c_bool, 1), + ('layer_viewport_relative', ctypes.c_bool, 1), + ('uses_control_barrier', ctypes.c_bool, 1), + ('uses_memory_barrier', ctypes.c_bool, 1), + ('uses_bindless', ctypes.c_bool, 1), + ('shared_memory_explicit_layout', ctypes.c_bool, 1), + ('zero_initialize_shared_memory', ctypes.c_bool, 1), + ('workgroup_size_variable', ctypes.c_bool, 1), + ('uses_printf', ctypes.c_bool, 1), + ('maximally_reconverges', ctypes.c_bool, 1), + ('use_aco_amd', ctypes.c_bool, 1), + ('use_lowered_image_to_global', ctypes.c_bool, 1), + ('PADDING_4', ctypes.c_uint8, 6), + ('use_legacy_math_rules', ctypes.c_bool, 8), + ('derivative_group', gl_derivative_group, 2), + ('PADDING_5', ctypes.c_uint64, 46), + ('_0', union_shader_info_0), +] + +struct_nir_shader._pack_ = 1 # source:False +struct_nir_shader._fields_ = [ + ('gctx', ctypes.POINTER(struct_gc_ctx)), + ('variables', struct_exec_list), + ('options', ctypes.POINTER(struct_nir_shader_compiler_options)), + ('info', struct_shader_info), + ('functions', struct_exec_list), + ('num_inputs', ctypes.c_uint32), + ('num_uniforms', ctypes.c_uint32), + ('num_outputs', ctypes.c_uint32), + ('global_mem_size', ctypes.c_uint32), + ('scratch_size', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('constant_data', ctypes.POINTER(None)), + ('constant_data_size', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('xfb_info', ctypes.POINTER(struct_nir_xfb_info)), + ('printf_info_count', ctypes.c_uint32), + ('PADDING_2', ctypes.c_ubyte * 4), + ('printf_info', ctypes.POINTER(struct_u_printf_info)), + ('has_debug_info', ctypes.c_bool), + ('PADDING_3', ctypes.c_ubyte * 7), +] + +nir_shader_compiler_options = struct_nir_shader_compiler_options +u_printf_info = struct_u_printf_info +nir_debug = 0 # Variable ctypes.c_uint32 +nir_debug_print_shader = [] # Variable ctypes.c_bool * 15 +nir_component_mask_t = ctypes.c_uint16 +try: + nir_round_up_components = _libraries['FIXME_STUB'].nir_round_up_components + nir_round_up_components.restype = ctypes.c_uint32 + nir_round_up_components.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + nir_round_down_components = _libraries['FIXME_STUB'].nir_round_down_components + nir_round_down_components.restype = ctypes.c_uint32 + nir_round_down_components.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + nir_component_mask = _libraries['FIXME_STUB'].nir_component_mask + nir_component_mask.restype = nir_component_mask_t + nir_component_mask.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + nir_process_debug_variable = _libraries['libtinymesa_cpu.so'].nir_process_debug_variable + nir_process_debug_variable.restype = None + nir_process_debug_variable.argtypes = [] +except AttributeError: + pass +try: + nir_component_mask_can_reinterpret = _libraries['libtinymesa_cpu.so'].nir_component_mask_can_reinterpret + nir_component_mask_can_reinterpret.restype = ctypes.c_bool + nir_component_mask_can_reinterpret.argtypes = [nir_component_mask_t, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_component_mask_reinterpret = _libraries['libtinymesa_cpu.so'].nir_component_mask_reinterpret + nir_component_mask_reinterpret.restype = nir_component_mask_t + nir_component_mask_reinterpret.argtypes = [nir_component_mask_t, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +class struct_nir_state_slot(Structure): + pass + +struct_nir_state_slot._pack_ = 1 # source:False +struct_nir_state_slot._fields_ = [ + ('tokens', ctypes.c_int16 * 4), +] + +nir_state_slot = struct_nir_state_slot + +# values for enumeration 'c__EA_nir_rounding_mode' +c__EA_nir_rounding_mode__enumvalues = { + 0: 'nir_rounding_mode_undef', + 1: 'nir_rounding_mode_rtne', + 2: 'nir_rounding_mode_ru', + 3: 'nir_rounding_mode_rd', + 4: 'nir_rounding_mode_rtz', +} +nir_rounding_mode_undef = 0 +nir_rounding_mode_rtne = 1 +nir_rounding_mode_ru = 2 +nir_rounding_mode_rd = 3 +nir_rounding_mode_rtz = 4 +c__EA_nir_rounding_mode = ctypes.c_uint32 # enum +nir_rounding_mode = c__EA_nir_rounding_mode +nir_rounding_mode__enumvalues = c__EA_nir_rounding_mode__enumvalues + +# values for enumeration 'c__EA_nir_ray_query_value' +c__EA_nir_ray_query_value__enumvalues = { + 0: 'nir_ray_query_value_intersection_type', + 1: 'nir_ray_query_value_intersection_t', + 2: 'nir_ray_query_value_intersection_instance_custom_index', + 3: 'nir_ray_query_value_intersection_instance_id', + 4: 'nir_ray_query_value_intersection_instance_sbt_index', + 5: 'nir_ray_query_value_intersection_geometry_index', + 6: 'nir_ray_query_value_intersection_primitive_index', + 7: 'nir_ray_query_value_intersection_barycentrics', + 8: 'nir_ray_query_value_intersection_front_face', + 9: 'nir_ray_query_value_intersection_object_ray_direction', + 10: 'nir_ray_query_value_intersection_object_ray_origin', + 11: 'nir_ray_query_value_intersection_object_to_world', + 12: 'nir_ray_query_value_intersection_world_to_object', + 13: 'nir_ray_query_value_intersection_candidate_aabb_opaque', + 14: 'nir_ray_query_value_tmin', + 15: 'nir_ray_query_value_flags', + 16: 'nir_ray_query_value_world_ray_direction', + 17: 'nir_ray_query_value_world_ray_origin', + 18: 'nir_ray_query_value_intersection_triangle_vertex_positions', +} +nir_ray_query_value_intersection_type = 0 +nir_ray_query_value_intersection_t = 1 +nir_ray_query_value_intersection_instance_custom_index = 2 +nir_ray_query_value_intersection_instance_id = 3 +nir_ray_query_value_intersection_instance_sbt_index = 4 +nir_ray_query_value_intersection_geometry_index = 5 +nir_ray_query_value_intersection_primitive_index = 6 +nir_ray_query_value_intersection_barycentrics = 7 +nir_ray_query_value_intersection_front_face = 8 +nir_ray_query_value_intersection_object_ray_direction = 9 +nir_ray_query_value_intersection_object_ray_origin = 10 +nir_ray_query_value_intersection_object_to_world = 11 +nir_ray_query_value_intersection_world_to_object = 12 +nir_ray_query_value_intersection_candidate_aabb_opaque = 13 +nir_ray_query_value_tmin = 14 +nir_ray_query_value_flags = 15 +nir_ray_query_value_world_ray_direction = 16 +nir_ray_query_value_world_ray_origin = 17 +nir_ray_query_value_intersection_triangle_vertex_positions = 18 +c__EA_nir_ray_query_value = ctypes.c_uint32 # enum +nir_ray_query_value = c__EA_nir_ray_query_value +nir_ray_query_value__enumvalues = c__EA_nir_ray_query_value__enumvalues + +# values for enumeration 'c__EA_nir_resource_data_intel' +c__EA_nir_resource_data_intel__enumvalues = { + 1: 'nir_resource_intel_bindless', + 2: 'nir_resource_intel_pushable', + 4: 'nir_resource_intel_sampler', + 8: 'nir_resource_intel_non_uniform', + 16: 'nir_resource_intel_sampler_embedded', +} +nir_resource_intel_bindless = 1 +nir_resource_intel_pushable = 2 +nir_resource_intel_sampler = 4 +nir_resource_intel_non_uniform = 8 +nir_resource_intel_sampler_embedded = 16 +c__EA_nir_resource_data_intel = ctypes.c_uint32 # enum +nir_resource_data_intel = c__EA_nir_resource_data_intel +nir_resource_data_intel__enumvalues = c__EA_nir_resource_data_intel__enumvalues + +# values for enumeration 'c__EA_nir_preamble_class' +c__EA_nir_preamble_class__enumvalues = { + 0: 'nir_preamble_class_general', + 1: 'nir_preamble_class_image', + 2: 'nir_preamble_num_classes', +} +nir_preamble_class_general = 0 +nir_preamble_class_image = 1 +nir_preamble_num_classes = 2 +c__EA_nir_preamble_class = ctypes.c_uint32 # enum +nir_preamble_class = c__EA_nir_preamble_class +nir_preamble_class__enumvalues = c__EA_nir_preamble_class__enumvalues + +# values for enumeration 'c__EA_nir_cmat_signed' +c__EA_nir_cmat_signed__enumvalues = { + 1: 'NIR_CMAT_A_SIGNED', + 2: 'NIR_CMAT_B_SIGNED', + 4: 'NIR_CMAT_C_SIGNED', + 8: 'NIR_CMAT_RESULT_SIGNED', +} +NIR_CMAT_A_SIGNED = 1 +NIR_CMAT_B_SIGNED = 2 +NIR_CMAT_C_SIGNED = 4 +NIR_CMAT_RESULT_SIGNED = 8 +c__EA_nir_cmat_signed = ctypes.c_uint32 # enum +nir_cmat_signed = c__EA_nir_cmat_signed +nir_cmat_signed__enumvalues = c__EA_nir_cmat_signed__enumvalues +class union_c__UA_nir_const_value(Union): + pass + +union_c__UA_nir_const_value._pack_ = 1 # source:False +union_c__UA_nir_const_value._fields_ = [ + ('b', ctypes.c_bool), + ('f32', ctypes.c_float), + ('f64', ctypes.c_double), + ('i8', ctypes.c_byte), + ('u8', ctypes.c_ubyte), + ('i16', ctypes.c_int16), + ('u16', ctypes.c_uint16), + ('i32', ctypes.c_int32), + ('u32', ctypes.c_uint32), + ('i64', ctypes.c_int64), + ('u64', ctypes.c_uint64), +] + +nir_const_value = union_c__UA_nir_const_value +try: + nir_const_value_for_raw_uint = _libraries['FIXME_STUB'].nir_const_value_for_raw_uint + nir_const_value_for_raw_uint.restype = nir_const_value + nir_const_value_for_raw_uint.argtypes = [uint64_t, ctypes.c_uint32] +except AttributeError: + pass +int64_t = ctypes.c_int64 +try: + nir_const_value_for_int = _libraries['FIXME_STUB'].nir_const_value_for_int + nir_const_value_for_int.restype = nir_const_value + nir_const_value_for_int.argtypes = [int64_t, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_for_uint = _libraries['FIXME_STUB'].nir_const_value_for_uint + nir_const_value_for_uint.restype = nir_const_value + nir_const_value_for_uint.argtypes = [uint64_t, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_for_bool = _libraries['FIXME_STUB'].nir_const_value_for_bool + nir_const_value_for_bool.restype = nir_const_value + nir_const_value_for_bool.argtypes = [ctypes.c_bool, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_for_float = _libraries['libtinymesa_cpu.so'].nir_const_value_for_float + nir_const_value_for_float.restype = nir_const_value + nir_const_value_for_float.argtypes = [ctypes.c_double, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_as_int = _libraries['FIXME_STUB'].nir_const_value_as_int + nir_const_value_as_int.restype = int64_t + nir_const_value_as_int.argtypes = [nir_const_value, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_as_uint = _libraries['FIXME_STUB'].nir_const_value_as_uint + nir_const_value_as_uint.restype = uint64_t + nir_const_value_as_uint.argtypes = [nir_const_value, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_as_bool = _libraries['FIXME_STUB'].nir_const_value_as_bool + nir_const_value_as_bool.restype = ctypes.c_bool + nir_const_value_as_bool.argtypes = [nir_const_value, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_const_value_as_float = _libraries['libtinymesa_cpu.so'].nir_const_value_as_float + nir_const_value_as_float.restype = ctypes.c_double + nir_const_value_as_float.argtypes = [nir_const_value, ctypes.c_uint32] +except AttributeError: + pass +class struct_nir_constant(Structure): + pass + +struct_nir_constant._pack_ = 1 # source:False +struct_nir_constant._fields_ = [ + ('values', union_c__UA_nir_const_value * 16), + ('is_null_constant', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('num_elements', ctypes.c_uint32), + ('elements', ctypes.POINTER(ctypes.POINTER(struct_nir_constant))), +] + +nir_constant = struct_nir_constant + +# values for enumeration 'c__EA_nir_depth_layout' +c__EA_nir_depth_layout__enumvalues = { + 0: 'nir_depth_layout_none', + 1: 'nir_depth_layout_any', + 2: 'nir_depth_layout_greater', + 3: 'nir_depth_layout_less', + 4: 'nir_depth_layout_unchanged', +} +nir_depth_layout_none = 0 +nir_depth_layout_any = 1 +nir_depth_layout_greater = 2 +nir_depth_layout_less = 3 +nir_depth_layout_unchanged = 4 +c__EA_nir_depth_layout = ctypes.c_uint32 # enum +nir_depth_layout = c__EA_nir_depth_layout +nir_depth_layout__enumvalues = c__EA_nir_depth_layout__enumvalues + +# values for enumeration 'c__EA_nir_var_declaration_type' +c__EA_nir_var_declaration_type__enumvalues = { + 0: 'nir_var_declared_normally', + 1: 'nir_var_declared_implicitly', + 2: 'nir_var_hidden', +} +nir_var_declared_normally = 0 +nir_var_declared_implicitly = 1 +nir_var_hidden = 2 +c__EA_nir_var_declaration_type = ctypes.c_uint32 # enum +nir_var_declaration_type = c__EA_nir_var_declaration_type +nir_var_declaration_type__enumvalues = c__EA_nir_var_declaration_type__enumvalues +class struct_nir_variable_data(Structure): + pass + +class union_nir_variable_data_0(Union): + pass + +class struct_nir_variable_data_0_image(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('format', pipe_format), + ] + +class struct_nir_variable_data_0_sampler(Structure): + pass + +struct_nir_variable_data_0_sampler._pack_ = 1 # source:False +struct_nir_variable_data_0_sampler._fields_ = [ + ('is_inline_sampler', ctypes.c_uint32, 1), + ('addressing_mode', ctypes.c_uint32, 3), + ('normalized_coordinates', ctypes.c_uint32, 1), + ('filter_mode', ctypes.c_uint32, 1), + ('PADDING_0', ctypes.c_uint32, 26), +] + +class struct_nir_variable_data_0_xfb(Structure): + pass + +struct_nir_variable_data_0_xfb._pack_ = 1 # source:False +struct_nir_variable_data_0_xfb._fields_ = [ + ('buffer', ctypes.c_uint16, 2), + ('PADDING_0', ctypes.c_uint16, 14), + ('stride', ctypes.c_uint16), +] + +union_nir_variable_data_0._pack_ = 1 # source:False +union_nir_variable_data_0._fields_ = [ + ('image', struct_nir_variable_data_0_image), + ('sampler', struct_nir_variable_data_0_sampler), + ('xfb', struct_nir_variable_data_0_xfb), +] + +struct_nir_variable_data._pack_ = 1 # source:False +struct_nir_variable_data._anonymous_ = ('_0',) +struct_nir_variable_data._fields_ = [ + ('mode', ctypes.c_uint64, 21), + ('read_only', ctypes.c_uint64, 1), + ('centroid', ctypes.c_uint64, 1), + ('sample', ctypes.c_uint64, 1), + ('patch', ctypes.c_uint64, 1), + ('invariant', ctypes.c_uint64, 1), + ('explicit_invariant', ctypes.c_uint64, 1), + ('ray_query', ctypes.c_uint64, 1), + ('precision', ctypes.c_uint64, 2), + ('assigned', ctypes.c_uint64, 1), + ('cannot_coalesce', ctypes.c_uint64, 1), + ('always_active_io', ctypes.c_uint64, 1), + ('interpolation', ctypes.c_uint64, 3), + ('location_frac', ctypes.c_uint64, 2), + ('compact', ctypes.c_uint64, 1), + ('fb_fetch_output', ctypes.c_uint64, 1), + ('bindless', ctypes.c_uint64, 1), + ('explicit_binding', ctypes.c_uint64, 1), + ('explicit_location', ctypes.c_uint64, 1), + ('implicit_sized_array', ctypes.c_uint64, 1), + ('PADDING_0', ctypes.c_uint32, 20), + ('max_array_access', ctypes.c_int32), + ('has_initializer', ctypes.c_uint64, 1), + ('is_implicit_initializer', ctypes.c_uint64, 1), + ('is_xfb', ctypes.c_uint64, 1), + ('is_xfb_only', ctypes.c_uint64, 1), + ('explicit_xfb_buffer', ctypes.c_uint64, 1), + ('explicit_xfb_stride', ctypes.c_uint64, 1), + ('explicit_offset', ctypes.c_uint64, 1), + ('matrix_layout', ctypes.c_uint64, 2), + ('from_named_ifc_block', ctypes.c_uint64, 1), + ('from_ssbo_unsized_array', ctypes.c_uint64, 1), + ('must_be_shader_input', ctypes.c_uint64, 1), + ('used', ctypes.c_uint64, 1), + ('how_declared', ctypes.c_uint64, 2), + ('per_view', ctypes.c_uint64, 1), + ('per_primitive', ctypes.c_uint64, 1), + ('per_vertex', ctypes.c_uint64, 1), + ('aliased_shared_memory', ctypes.c_uint64, 1), + ('depth_layout', ctypes.c_uint64, 3), + ('stream', ctypes.c_uint64, 9), + ('PADDING_1', ctypes.c_uint8, 1), + ('access', ctypes.c_uint64, 9), + ('descriptor_set', ctypes.c_uint64, 5), + ('PADDING_2', ctypes.c_uint32, 18), + ('index', ctypes.c_uint32), + ('binding', ctypes.c_uint32), + ('location', ctypes.c_int32), + ('alignment', ctypes.c_uint32), + ('driver_location', ctypes.c_uint32), + ('offset', ctypes.c_uint32), + ('_0', union_nir_variable_data_0), + ('node_name', ctypes.POINTER(ctypes.c_char)), +] + +nir_variable_data = struct_nir_variable_data +class struct_nir_variable(Structure): + pass + +struct_nir_variable._pack_ = 1 # source:False +struct_nir_variable._fields_ = [ + ('node', struct_exec_node), + ('type', ctypes.POINTER(struct_glsl_type)), + ('name', ctypes.POINTER(ctypes.c_char)), + ('data', struct_nir_variable_data), + ('index', ctypes.c_uint32), + ('num_members', ctypes.c_uint16), + ('PADDING_0', ctypes.c_ubyte * 2), + ('max_ifc_array_access', ctypes.POINTER(ctypes.c_int32)), + ('num_state_slots', ctypes.c_uint16), + ('PADDING_1', ctypes.c_ubyte * 6), + ('state_slots', ctypes.POINTER(struct_nir_state_slot)), + ('constant_initializer', ctypes.POINTER(struct_nir_constant)), + ('pointer_initializer', ctypes.POINTER(struct_nir_variable)), + ('interface_type', ctypes.POINTER(struct_glsl_type)), + ('members', ctypes.POINTER(struct_nir_variable_data)), +] + +nir_variable = struct_nir_variable +try: + _nir_shader_variable_has_mode = _libraries['FIXME_STUB']._nir_shader_variable_has_mode + _nir_shader_variable_has_mode.restype = ctypes.c_bool + _nir_shader_variable_has_mode.argtypes = [ctypes.POINTER(struct_nir_variable), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_variable_is_global = _libraries['FIXME_STUB'].nir_variable_is_global + nir_variable_is_global.restype = ctypes.c_bool + nir_variable_is_global.argtypes = [ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_instr_type' +c__EA_nir_instr_type__enumvalues = { + 0: 'nir_instr_type_alu', + 1: 'nir_instr_type_deref', + 2: 'nir_instr_type_call', + 3: 'nir_instr_type_tex', + 4: 'nir_instr_type_intrinsic', + 5: 'nir_instr_type_load_const', + 6: 'nir_instr_type_jump', + 7: 'nir_instr_type_undef', + 8: 'nir_instr_type_phi', + 9: 'nir_instr_type_parallel_copy', +} +nir_instr_type_alu = 0 +nir_instr_type_deref = 1 +nir_instr_type_call = 2 +nir_instr_type_tex = 3 +nir_instr_type_intrinsic = 4 +nir_instr_type_load_const = 5 +nir_instr_type_jump = 6 +nir_instr_type_undef = 7 +nir_instr_type_phi = 8 +nir_instr_type_parallel_copy = 9 +c__EA_nir_instr_type = ctypes.c_uint32 # enum +nir_instr_type = c__EA_nir_instr_type +nir_instr_type__enumvalues = c__EA_nir_instr_type__enumvalues +nir_instr = struct_nir_instr +try: + nir_instr_next = _libraries['FIXME_STUB'].nir_instr_next + nir_instr_next.restype = ctypes.POINTER(struct_nir_instr) + nir_instr_next.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_prev = _libraries['FIXME_STUB'].nir_instr_prev + nir_instr_prev.restype = ctypes.POINTER(struct_nir_instr) + nir_instr_prev.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_is_first = _libraries['FIXME_STUB'].nir_instr_is_first + nir_instr_is_first.restype = ctypes.c_bool + nir_instr_is_first.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_is_last = _libraries['FIXME_STUB'].nir_instr_is_last + nir_instr_is_last.restype = ctypes.c_bool + nir_instr_is_last.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +class struct_nir_def(Structure): + pass + +class struct_list_head(Structure): + pass + +struct_list_head._pack_ = 1 # source:False +struct_list_head._fields_ = [ + ('prev', ctypes.POINTER(struct_list_head)), + ('next', ctypes.POINTER(struct_list_head)), +] + +struct_nir_def._pack_ = 1 # source:False +struct_nir_def._fields_ = [ + ('parent_instr', ctypes.POINTER(struct_nir_instr)), + ('uses', struct_list_head), + ('index', ctypes.c_uint32), + ('num_components', ctypes.c_ubyte), + ('bit_size', ctypes.c_ubyte), + ('divergent', ctypes.c_bool), + ('loop_invariant', ctypes.c_bool), +] + +nir_def = struct_nir_def +class struct_nir_src(Structure): + pass + +struct_nir_src._pack_ = 1 # source:False +struct_nir_src._fields_ = [ + ('_parent', ctypes.c_uint64), + ('use_link', struct_list_head), + ('ssa', ctypes.POINTER(struct_nir_def)), +] + +nir_src = struct_nir_src +try: + nir_src_is_if = _libraries['FIXME_STUB'].nir_src_is_if + nir_src_is_if.restype = ctypes.c_bool + nir_src_is_if.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_src_parent_instr = _libraries['FIXME_STUB'].nir_src_parent_instr + nir_src_parent_instr.restype = ctypes.POINTER(struct_nir_instr) + nir_src_parent_instr.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +class struct_nir_if(Structure): + pass + + +# values for enumeration 'c__EA_nir_selection_control' +c__EA_nir_selection_control__enumvalues = { + 0: 'nir_selection_control_none', + 1: 'nir_selection_control_flatten', + 2: 'nir_selection_control_dont_flatten', + 3: 'nir_selection_control_divergent_always_taken', +} +nir_selection_control_none = 0 +nir_selection_control_flatten = 1 +nir_selection_control_dont_flatten = 2 +nir_selection_control_divergent_always_taken = 3 +c__EA_nir_selection_control = ctypes.c_uint32 # enum +struct_nir_if._pack_ = 1 # source:False +struct_nir_if._fields_ = [ + ('cf_node', struct_nir_cf_node), + ('condition', nir_src), + ('control', c__EA_nir_selection_control), + ('PADDING_0', ctypes.c_ubyte * 4), + ('then_list', struct_exec_list), + ('else_list', struct_exec_list), +] + +try: + nir_src_parent_if = _libraries['FIXME_STUB'].nir_src_parent_if + nir_src_parent_if.restype = ctypes.POINTER(struct_nir_if) + nir_src_parent_if.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + _nir_src_set_parent = _libraries['FIXME_STUB']._nir_src_set_parent + _nir_src_set_parent.restype = None + _nir_src_set_parent.argtypes = [ctypes.POINTER(struct_nir_src), ctypes.POINTER(None), ctypes.c_bool] +except AttributeError: + pass +try: + nir_src_set_parent_instr = _libraries['FIXME_STUB'].nir_src_set_parent_instr + nir_src_set_parent_instr.restype = None + nir_src_set_parent_instr.argtypes = [ctypes.POINTER(struct_nir_src), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_src_set_parent_if = _libraries['FIXME_STUB'].nir_src_set_parent_if + nir_src_set_parent_if.restype = None + nir_src_set_parent_if.argtypes = [ctypes.POINTER(struct_nir_src), ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_src_init = _libraries['FIXME_STUB'].nir_src_init + nir_src_init.restype = nir_src + nir_src_init.argtypes = [] +except AttributeError: + pass +try: + nir_def_used_by_if = _libraries['FIXME_STUB'].nir_def_used_by_if + nir_def_used_by_if.restype = ctypes.c_bool + nir_def_used_by_if.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_only_used_by_if = _libraries['FIXME_STUB'].nir_def_only_used_by_if + nir_def_only_used_by_if.restype = ctypes.c_bool + nir_def_only_used_by_if.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_src_for_ssa = _libraries['FIXME_STUB'].nir_src_for_ssa + nir_src_for_ssa.restype = nir_src + nir_src_for_ssa.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_src_bit_size = _libraries['FIXME_STUB'].nir_src_bit_size + nir_src_bit_size.restype = ctypes.c_uint32 + nir_src_bit_size.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_num_components = _libraries['FIXME_STUB'].nir_src_num_components + nir_src_num_components.restype = ctypes.c_uint32 + nir_src_num_components.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_is_const = _libraries['FIXME_STUB'].nir_src_is_const + nir_src_is_const.restype = ctypes.c_bool + nir_src_is_const.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_is_undef = _libraries['FIXME_STUB'].nir_src_is_undef + nir_src_is_undef.restype = ctypes.c_bool + nir_src_is_undef.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_is_divergent = _libraries['libtinymesa_cpu.so'].nir_src_is_divergent + nir_src_is_divergent.restype = ctypes.c_bool + nir_src_is_divergent.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_is_same_comp_swizzle = _libraries['FIXME_STUB'].nir_is_same_comp_swizzle + nir_is_same_comp_swizzle.restype = ctypes.c_bool + nir_is_same_comp_swizzle.argtypes = [ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_sequential_comp_swizzle = _libraries['FIXME_STUB'].nir_is_sequential_comp_swizzle + nir_is_sequential_comp_swizzle.restype = ctypes.c_bool + nir_is_sequential_comp_swizzle.argtypes = [ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint32] +except AttributeError: + pass +class struct_nir_alu_src(Structure): + pass + +struct_nir_alu_src._pack_ = 1 # source:False +struct_nir_alu_src._fields_ = [ + ('src', nir_src), + ('swizzle', ctypes.c_ubyte * 16), +] + +nir_alu_src = struct_nir_alu_src + +# values for enumeration 'c__EA_nir_alu_type' +c__EA_nir_alu_type__enumvalues = { + 0: 'nir_type_invalid', + 2: 'nir_type_int', + 4: 'nir_type_uint', + 6: 'nir_type_bool', + 128: 'nir_type_float', + 7: 'nir_type_bool1', + 14: 'nir_type_bool8', + 22: 'nir_type_bool16', + 38: 'nir_type_bool32', + 3: 'nir_type_int1', + 10: 'nir_type_int8', + 18: 'nir_type_int16', + 34: 'nir_type_int32', + 66: 'nir_type_int64', + 5: 'nir_type_uint1', + 12: 'nir_type_uint8', + 20: 'nir_type_uint16', + 36: 'nir_type_uint32', + 68: 'nir_type_uint64', + 144: 'nir_type_float16', + 160: 'nir_type_float32', + 192: 'nir_type_float64', +} +nir_type_invalid = 0 +nir_type_int = 2 +nir_type_uint = 4 +nir_type_bool = 6 +nir_type_float = 128 +nir_type_bool1 = 7 +nir_type_bool8 = 14 +nir_type_bool16 = 22 +nir_type_bool32 = 38 +nir_type_int1 = 3 +nir_type_int8 = 10 +nir_type_int16 = 18 +nir_type_int32 = 34 +nir_type_int64 = 66 +nir_type_uint1 = 5 +nir_type_uint8 = 12 +nir_type_uint16 = 20 +nir_type_uint32 = 36 +nir_type_uint64 = 68 +nir_type_float16 = 144 +nir_type_float32 = 160 +nir_type_float64 = 192 +c__EA_nir_alu_type = ctypes.c_uint32 # enum +nir_alu_type = c__EA_nir_alu_type +nir_alu_type__enumvalues = c__EA_nir_alu_type__enumvalues +try: + nir_get_nir_type_for_glsl_base_type = _libraries['libtinymesa_cpu.so'].nir_get_nir_type_for_glsl_base_type + nir_get_nir_type_for_glsl_base_type.restype = nir_alu_type + nir_get_nir_type_for_glsl_base_type.argtypes = [glsl_base_type] +except AttributeError: + pass +try: + nir_get_nir_type_for_glsl_type = _libraries['FIXME_STUB'].nir_get_nir_type_for_glsl_type + nir_get_nir_type_for_glsl_type.restype = nir_alu_type + nir_get_nir_type_for_glsl_type.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + nir_get_glsl_base_type_for_nir_type = _libraries['libtinymesa_cpu.so'].nir_get_glsl_base_type_for_nir_type + nir_get_glsl_base_type_for_nir_type.restype = glsl_base_type + nir_get_glsl_base_type_for_nir_type.argtypes = [nir_alu_type] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_op' +c__EA_nir_op__enumvalues = { + 0: 'nir_op_alignbyte_amd', + 1: 'nir_op_amul', + 2: 'nir_op_andg_ir3', + 3: 'nir_op_b16all_fequal16', + 4: 'nir_op_b16all_fequal2', + 5: 'nir_op_b16all_fequal3', + 6: 'nir_op_b16all_fequal4', + 7: 'nir_op_b16all_fequal5', + 8: 'nir_op_b16all_fequal8', + 9: 'nir_op_b16all_iequal16', + 10: 'nir_op_b16all_iequal2', + 11: 'nir_op_b16all_iequal3', + 12: 'nir_op_b16all_iequal4', + 13: 'nir_op_b16all_iequal5', + 14: 'nir_op_b16all_iequal8', + 15: 'nir_op_b16any_fnequal16', + 16: 'nir_op_b16any_fnequal2', + 17: 'nir_op_b16any_fnequal3', + 18: 'nir_op_b16any_fnequal4', + 19: 'nir_op_b16any_fnequal5', + 20: 'nir_op_b16any_fnequal8', + 21: 'nir_op_b16any_inequal16', + 22: 'nir_op_b16any_inequal2', + 23: 'nir_op_b16any_inequal3', + 24: 'nir_op_b16any_inequal4', + 25: 'nir_op_b16any_inequal5', + 26: 'nir_op_b16any_inequal8', + 27: 'nir_op_b16csel', + 28: 'nir_op_b2b1', + 29: 'nir_op_b2b16', + 30: 'nir_op_b2b32', + 31: 'nir_op_b2b8', + 32: 'nir_op_b2f16', + 33: 'nir_op_b2f32', + 34: 'nir_op_b2f64', + 35: 'nir_op_b2i1', + 36: 'nir_op_b2i16', + 37: 'nir_op_b2i32', + 38: 'nir_op_b2i64', + 39: 'nir_op_b2i8', + 40: 'nir_op_b32all_fequal16', + 41: 'nir_op_b32all_fequal2', + 42: 'nir_op_b32all_fequal3', + 43: 'nir_op_b32all_fequal4', + 44: 'nir_op_b32all_fequal5', + 45: 'nir_op_b32all_fequal8', + 46: 'nir_op_b32all_iequal16', + 47: 'nir_op_b32all_iequal2', + 48: 'nir_op_b32all_iequal3', + 49: 'nir_op_b32all_iequal4', + 50: 'nir_op_b32all_iequal5', + 51: 'nir_op_b32all_iequal8', + 52: 'nir_op_b32any_fnequal16', + 53: 'nir_op_b32any_fnequal2', + 54: 'nir_op_b32any_fnequal3', + 55: 'nir_op_b32any_fnequal4', + 56: 'nir_op_b32any_fnequal5', + 57: 'nir_op_b32any_fnequal8', + 58: 'nir_op_b32any_inequal16', + 59: 'nir_op_b32any_inequal2', + 60: 'nir_op_b32any_inequal3', + 61: 'nir_op_b32any_inequal4', + 62: 'nir_op_b32any_inequal5', + 63: 'nir_op_b32any_inequal8', + 64: 'nir_op_b32csel', + 65: 'nir_op_b32fcsel_mdg', + 66: 'nir_op_b8all_fequal16', + 67: 'nir_op_b8all_fequal2', + 68: 'nir_op_b8all_fequal3', + 69: 'nir_op_b8all_fequal4', + 70: 'nir_op_b8all_fequal5', + 71: 'nir_op_b8all_fequal8', + 72: 'nir_op_b8all_iequal16', + 73: 'nir_op_b8all_iequal2', + 74: 'nir_op_b8all_iequal3', + 75: 'nir_op_b8all_iequal4', + 76: 'nir_op_b8all_iequal5', + 77: 'nir_op_b8all_iequal8', + 78: 'nir_op_b8any_fnequal16', + 79: 'nir_op_b8any_fnequal2', + 80: 'nir_op_b8any_fnequal3', + 81: 'nir_op_b8any_fnequal4', + 82: 'nir_op_b8any_fnequal5', + 83: 'nir_op_b8any_fnequal8', + 84: 'nir_op_b8any_inequal16', + 85: 'nir_op_b8any_inequal2', + 86: 'nir_op_b8any_inequal3', + 87: 'nir_op_b8any_inequal4', + 88: 'nir_op_b8any_inequal5', + 89: 'nir_op_b8any_inequal8', + 90: 'nir_op_b8csel', + 91: 'nir_op_ball_fequal16', + 92: 'nir_op_ball_fequal2', + 93: 'nir_op_ball_fequal3', + 94: 'nir_op_ball_fequal4', + 95: 'nir_op_ball_fequal5', + 96: 'nir_op_ball_fequal8', + 97: 'nir_op_ball_iequal16', + 98: 'nir_op_ball_iequal2', + 99: 'nir_op_ball_iequal3', + 100: 'nir_op_ball_iequal4', + 101: 'nir_op_ball_iequal5', + 102: 'nir_op_ball_iequal8', + 103: 'nir_op_bany_fnequal16', + 104: 'nir_op_bany_fnequal2', + 105: 'nir_op_bany_fnequal3', + 106: 'nir_op_bany_fnequal4', + 107: 'nir_op_bany_fnequal5', + 108: 'nir_op_bany_fnequal8', + 109: 'nir_op_bany_inequal16', + 110: 'nir_op_bany_inequal2', + 111: 'nir_op_bany_inequal3', + 112: 'nir_op_bany_inequal4', + 113: 'nir_op_bany_inequal5', + 114: 'nir_op_bany_inequal8', + 115: 'nir_op_bcsel', + 116: 'nir_op_bf2f', + 117: 'nir_op_bfdot16', + 118: 'nir_op_bfdot2', + 119: 'nir_op_bfdot2_bfadd', + 120: 'nir_op_bfdot3', + 121: 'nir_op_bfdot4', + 122: 'nir_op_bfdot5', + 123: 'nir_op_bfdot8', + 124: 'nir_op_bffma', + 125: 'nir_op_bfi', + 126: 'nir_op_bfm', + 127: 'nir_op_bfmul', + 128: 'nir_op_bit_count', + 129: 'nir_op_bitfield_insert', + 130: 'nir_op_bitfield_reverse', + 131: 'nir_op_bitfield_select', + 132: 'nir_op_bitnz', + 133: 'nir_op_bitnz16', + 134: 'nir_op_bitnz32', + 135: 'nir_op_bitnz8', + 136: 'nir_op_bitz', + 137: 'nir_op_bitz16', + 138: 'nir_op_bitz32', + 139: 'nir_op_bitz8', + 140: 'nir_op_bounds_agx', + 141: 'nir_op_byte_perm_amd', + 142: 'nir_op_cube_amd', + 143: 'nir_op_e4m3fn2f', + 144: 'nir_op_e5m22f', + 145: 'nir_op_extr_agx', + 146: 'nir_op_extract_i16', + 147: 'nir_op_extract_i8', + 148: 'nir_op_extract_u16', + 149: 'nir_op_extract_u8', + 150: 'nir_op_f2bf', + 151: 'nir_op_f2e4m3fn', + 152: 'nir_op_f2e4m3fn_sat', + 153: 'nir_op_f2e4m3fn_satfn', + 154: 'nir_op_f2e5m2', + 155: 'nir_op_f2e5m2_sat', + 156: 'nir_op_f2f16', + 157: 'nir_op_f2f16_rtne', + 158: 'nir_op_f2f16_rtz', + 159: 'nir_op_f2f32', + 160: 'nir_op_f2f64', + 161: 'nir_op_f2fmp', + 162: 'nir_op_f2i1', + 163: 'nir_op_f2i16', + 164: 'nir_op_f2i32', + 165: 'nir_op_f2i64', + 166: 'nir_op_f2i8', + 167: 'nir_op_f2imp', + 168: 'nir_op_f2snorm_16_v3d', + 169: 'nir_op_f2u1', + 170: 'nir_op_f2u16', + 171: 'nir_op_f2u32', + 172: 'nir_op_f2u64', + 173: 'nir_op_f2u8', + 174: 'nir_op_f2ump', + 175: 'nir_op_f2unorm_16_v3d', + 176: 'nir_op_fabs', + 177: 'nir_op_fadd', + 178: 'nir_op_fall_equal16', + 179: 'nir_op_fall_equal2', + 180: 'nir_op_fall_equal3', + 181: 'nir_op_fall_equal4', + 182: 'nir_op_fall_equal5', + 183: 'nir_op_fall_equal8', + 184: 'nir_op_fany_nequal16', + 185: 'nir_op_fany_nequal2', + 186: 'nir_op_fany_nequal3', + 187: 'nir_op_fany_nequal4', + 188: 'nir_op_fany_nequal5', + 189: 'nir_op_fany_nequal8', + 190: 'nir_op_fceil', + 191: 'nir_op_fclamp_pos', + 192: 'nir_op_fcos', + 193: 'nir_op_fcos_amd', + 194: 'nir_op_fcos_mdg', + 195: 'nir_op_fcsel', + 196: 'nir_op_fcsel_ge', + 197: 'nir_op_fcsel_gt', + 198: 'nir_op_fdiv', + 199: 'nir_op_fdot16', + 200: 'nir_op_fdot16_replicated', + 201: 'nir_op_fdot2', + 202: 'nir_op_fdot2_replicated', + 203: 'nir_op_fdot3', + 204: 'nir_op_fdot3_replicated', + 205: 'nir_op_fdot4', + 206: 'nir_op_fdot4_replicated', + 207: 'nir_op_fdot5', + 208: 'nir_op_fdot5_replicated', + 209: 'nir_op_fdot8', + 210: 'nir_op_fdot8_replicated', + 211: 'nir_op_fdph', + 212: 'nir_op_fdph_replicated', + 213: 'nir_op_feq', + 214: 'nir_op_feq16', + 215: 'nir_op_feq32', + 216: 'nir_op_feq8', + 217: 'nir_op_fequ', + 218: 'nir_op_fequ16', + 219: 'nir_op_fequ32', + 220: 'nir_op_fequ8', + 221: 'nir_op_fexp2', + 222: 'nir_op_ffloor', + 223: 'nir_op_ffma', + 224: 'nir_op_ffmaz', + 225: 'nir_op_ffract', + 226: 'nir_op_fge', + 227: 'nir_op_fge16', + 228: 'nir_op_fge32', + 229: 'nir_op_fge8', + 230: 'nir_op_fgeu', + 231: 'nir_op_fgeu16', + 232: 'nir_op_fgeu32', + 233: 'nir_op_fgeu8', + 234: 'nir_op_find_lsb', + 235: 'nir_op_fisfinite', + 236: 'nir_op_fisfinite32', + 237: 'nir_op_fisnormal', + 238: 'nir_op_flog2', + 239: 'nir_op_flrp', + 240: 'nir_op_flt', + 241: 'nir_op_flt16', + 242: 'nir_op_flt32', + 243: 'nir_op_flt8', + 244: 'nir_op_fltu', + 245: 'nir_op_fltu16', + 246: 'nir_op_fltu32', + 247: 'nir_op_fltu8', + 248: 'nir_op_fmax', + 249: 'nir_op_fmax_agx', + 250: 'nir_op_fmin', + 251: 'nir_op_fmin_agx', + 252: 'nir_op_fmod', + 253: 'nir_op_fmul', + 254: 'nir_op_fmulz', + 255: 'nir_op_fneg', + 256: 'nir_op_fneo', + 257: 'nir_op_fneo16', + 258: 'nir_op_fneo32', + 259: 'nir_op_fneo8', + 260: 'nir_op_fneu', + 261: 'nir_op_fneu16', + 262: 'nir_op_fneu32', + 263: 'nir_op_fneu8', + 264: 'nir_op_ford', + 265: 'nir_op_ford16', + 266: 'nir_op_ford32', + 267: 'nir_op_ford8', + 268: 'nir_op_fpow', + 269: 'nir_op_fquantize2f16', + 270: 'nir_op_frcp', + 271: 'nir_op_frem', + 272: 'nir_op_frexp_exp', + 273: 'nir_op_frexp_sig', + 274: 'nir_op_fround_even', + 275: 'nir_op_frsq', + 276: 'nir_op_fsat', + 277: 'nir_op_fsat_signed', + 278: 'nir_op_fsign', + 279: 'nir_op_fsin', + 280: 'nir_op_fsin_agx', + 281: 'nir_op_fsin_amd', + 282: 'nir_op_fsin_mdg', + 283: 'nir_op_fsqrt', + 284: 'nir_op_fsub', + 285: 'nir_op_fsum2', + 286: 'nir_op_fsum3', + 287: 'nir_op_fsum4', + 288: 'nir_op_ftrunc', + 289: 'nir_op_funord', + 290: 'nir_op_funord16', + 291: 'nir_op_funord32', + 292: 'nir_op_funord8', + 293: 'nir_op_i2f16', + 294: 'nir_op_i2f32', + 295: 'nir_op_i2f64', + 296: 'nir_op_i2fmp', + 297: 'nir_op_i2i1', + 298: 'nir_op_i2i16', + 299: 'nir_op_i2i32', + 300: 'nir_op_i2i64', + 301: 'nir_op_i2i8', + 302: 'nir_op_i2imp', + 303: 'nir_op_i32csel_ge', + 304: 'nir_op_i32csel_gt', + 305: 'nir_op_iabs', + 306: 'nir_op_iadd', + 307: 'nir_op_iadd3', + 308: 'nir_op_iadd_sat', + 309: 'nir_op_iand', + 310: 'nir_op_ibfe', + 311: 'nir_op_ibitfield_extract', + 312: 'nir_op_icsel_eqz', + 313: 'nir_op_idiv', + 314: 'nir_op_ieq', + 315: 'nir_op_ieq16', + 316: 'nir_op_ieq32', + 317: 'nir_op_ieq8', + 318: 'nir_op_ifind_msb', + 319: 'nir_op_ifind_msb_rev', + 320: 'nir_op_ige', + 321: 'nir_op_ige16', + 322: 'nir_op_ige32', + 323: 'nir_op_ige8', + 324: 'nir_op_ihadd', + 325: 'nir_op_ilea_agx', + 326: 'nir_op_ilt', + 327: 'nir_op_ilt16', + 328: 'nir_op_ilt32', + 329: 'nir_op_ilt8', + 330: 'nir_op_imad', + 331: 'nir_op_imad24_ir3', + 332: 'nir_op_imadsh_mix16', + 333: 'nir_op_imadshl_agx', + 334: 'nir_op_imax', + 335: 'nir_op_imin', + 336: 'nir_op_imod', + 337: 'nir_op_imsubshl_agx', + 338: 'nir_op_imul', + 339: 'nir_op_imul24', + 340: 'nir_op_imul24_relaxed', + 341: 'nir_op_imul_2x32_64', + 342: 'nir_op_imul_32x16', + 343: 'nir_op_imul_high', + 344: 'nir_op_ine', + 345: 'nir_op_ine16', + 346: 'nir_op_ine32', + 347: 'nir_op_ine8', + 348: 'nir_op_ineg', + 349: 'nir_op_inot', + 350: 'nir_op_insert_u16', + 351: 'nir_op_insert_u8', + 352: 'nir_op_interleave_agx', + 353: 'nir_op_ior', + 354: 'nir_op_irem', + 355: 'nir_op_irhadd', + 356: 'nir_op_ishl', + 357: 'nir_op_ishr', + 358: 'nir_op_isign', + 359: 'nir_op_isub', + 360: 'nir_op_isub_sat', + 361: 'nir_op_ixor', + 362: 'nir_op_ldexp', + 363: 'nir_op_ldexp16_pan', + 364: 'nir_op_lea_nv', + 365: 'nir_op_mov', + 366: 'nir_op_mqsad_4x8', + 367: 'nir_op_msad_4x8', + 368: 'nir_op_pack_2x16_to_snorm_2x8_v3d', + 369: 'nir_op_pack_2x16_to_unorm_10_2_v3d', + 370: 'nir_op_pack_2x16_to_unorm_2x10_v3d', + 371: 'nir_op_pack_2x16_to_unorm_2x8_v3d', + 372: 'nir_op_pack_2x32_to_2x16_v3d', + 373: 'nir_op_pack_32_2x16', + 374: 'nir_op_pack_32_2x16_split', + 375: 'nir_op_pack_32_4x8', + 376: 'nir_op_pack_32_4x8_split', + 377: 'nir_op_pack_32_to_r11g11b10_v3d', + 378: 'nir_op_pack_4x16_to_4x8_v3d', + 379: 'nir_op_pack_64_2x32', + 380: 'nir_op_pack_64_2x32_split', + 381: 'nir_op_pack_64_4x16', + 382: 'nir_op_pack_double_2x32_dxil', + 383: 'nir_op_pack_half_2x16', + 384: 'nir_op_pack_half_2x16_rtz_split', + 385: 'nir_op_pack_half_2x16_split', + 386: 'nir_op_pack_sint_2x16', + 387: 'nir_op_pack_snorm_2x16', + 388: 'nir_op_pack_snorm_4x8', + 389: 'nir_op_pack_uint_2x16', + 390: 'nir_op_pack_uint_32_to_r10g10b10a2_v3d', + 391: 'nir_op_pack_unorm_2x16', + 392: 'nir_op_pack_unorm_4x8', + 393: 'nir_op_pack_uvec2_to_uint', + 394: 'nir_op_pack_uvec4_to_uint', + 395: 'nir_op_prmt_nv', + 396: 'nir_op_sdot_2x16_iadd', + 397: 'nir_op_sdot_2x16_iadd_sat', + 398: 'nir_op_sdot_4x8_iadd', + 399: 'nir_op_sdot_4x8_iadd_sat', + 400: 'nir_op_seq', + 401: 'nir_op_sge', + 402: 'nir_op_shfr', + 403: 'nir_op_shlg_ir3', + 404: 'nir_op_shlm_ir3', + 405: 'nir_op_shrg_ir3', + 406: 'nir_op_shrm_ir3', + 407: 'nir_op_slt', + 408: 'nir_op_sne', + 409: 'nir_op_sudot_4x8_iadd', + 410: 'nir_op_sudot_4x8_iadd_sat', + 411: 'nir_op_u2f16', + 412: 'nir_op_u2f32', + 413: 'nir_op_u2f64', + 414: 'nir_op_u2fmp', + 415: 'nir_op_u2u1', + 416: 'nir_op_u2u16', + 417: 'nir_op_u2u32', + 418: 'nir_op_u2u64', + 419: 'nir_op_u2u8', + 420: 'nir_op_uabs_isub', + 421: 'nir_op_uabs_usub', + 422: 'nir_op_uadd_carry', + 423: 'nir_op_uadd_sat', + 424: 'nir_op_ubfe', + 425: 'nir_op_ubitfield_extract', + 426: 'nir_op_uclz', + 427: 'nir_op_udiv', + 428: 'nir_op_udiv_aligned_4', + 429: 'nir_op_udot_2x16_uadd', + 430: 'nir_op_udot_2x16_uadd_sat', + 431: 'nir_op_udot_4x8_uadd', + 432: 'nir_op_udot_4x8_uadd_sat', + 433: 'nir_op_ufind_msb', + 434: 'nir_op_ufind_msb_rev', + 435: 'nir_op_uge', + 436: 'nir_op_uge16', + 437: 'nir_op_uge32', + 438: 'nir_op_uge8', + 439: 'nir_op_uhadd', + 440: 'nir_op_ulea_agx', + 441: 'nir_op_ult', + 442: 'nir_op_ult16', + 443: 'nir_op_ult32', + 444: 'nir_op_ult8', + 445: 'nir_op_umad24', + 446: 'nir_op_umad24_relaxed', + 447: 'nir_op_umax', + 448: 'nir_op_umax_4x8_vc4', + 449: 'nir_op_umin', + 450: 'nir_op_umin_4x8_vc4', + 451: 'nir_op_umod', + 452: 'nir_op_umul24', + 453: 'nir_op_umul24_relaxed', + 454: 'nir_op_umul_2x32_64', + 455: 'nir_op_umul_32x16', + 456: 'nir_op_umul_high', + 457: 'nir_op_umul_low', + 458: 'nir_op_umul_unorm_4x8_vc4', + 459: 'nir_op_unpack_32_2x16', + 460: 'nir_op_unpack_32_2x16_split_x', + 461: 'nir_op_unpack_32_2x16_split_y', + 462: 'nir_op_unpack_32_4x8', + 463: 'nir_op_unpack_64_2x32', + 464: 'nir_op_unpack_64_2x32_split_x', + 465: 'nir_op_unpack_64_2x32_split_y', + 466: 'nir_op_unpack_64_4x16', + 467: 'nir_op_unpack_double_2x32_dxil', + 468: 'nir_op_unpack_half_2x16', + 469: 'nir_op_unpack_half_2x16_split_x', + 470: 'nir_op_unpack_half_2x16_split_y', + 471: 'nir_op_unpack_snorm_2x16', + 472: 'nir_op_unpack_snorm_4x8', + 473: 'nir_op_unpack_unorm_2x16', + 474: 'nir_op_unpack_unorm_4x8', + 475: 'nir_op_urhadd', + 476: 'nir_op_urol', + 477: 'nir_op_uror', + 478: 'nir_op_usadd_4x8_vc4', + 479: 'nir_op_ushr', + 480: 'nir_op_ussub_4x8_vc4', + 481: 'nir_op_usub_borrow', + 482: 'nir_op_usub_sat', + 483: 'nir_op_vec16', + 484: 'nir_op_vec2', + 485: 'nir_op_vec3', + 486: 'nir_op_vec4', + 487: 'nir_op_vec5', + 488: 'nir_op_vec8', + 488: 'nir_last_opcode', + 489: 'nir_num_opcodes', +} +nir_op_alignbyte_amd = 0 +nir_op_amul = 1 +nir_op_andg_ir3 = 2 +nir_op_b16all_fequal16 = 3 +nir_op_b16all_fequal2 = 4 +nir_op_b16all_fequal3 = 5 +nir_op_b16all_fequal4 = 6 +nir_op_b16all_fequal5 = 7 +nir_op_b16all_fequal8 = 8 +nir_op_b16all_iequal16 = 9 +nir_op_b16all_iequal2 = 10 +nir_op_b16all_iequal3 = 11 +nir_op_b16all_iequal4 = 12 +nir_op_b16all_iequal5 = 13 +nir_op_b16all_iequal8 = 14 +nir_op_b16any_fnequal16 = 15 +nir_op_b16any_fnequal2 = 16 +nir_op_b16any_fnequal3 = 17 +nir_op_b16any_fnequal4 = 18 +nir_op_b16any_fnequal5 = 19 +nir_op_b16any_fnequal8 = 20 +nir_op_b16any_inequal16 = 21 +nir_op_b16any_inequal2 = 22 +nir_op_b16any_inequal3 = 23 +nir_op_b16any_inequal4 = 24 +nir_op_b16any_inequal5 = 25 +nir_op_b16any_inequal8 = 26 +nir_op_b16csel = 27 +nir_op_b2b1 = 28 +nir_op_b2b16 = 29 +nir_op_b2b32 = 30 +nir_op_b2b8 = 31 +nir_op_b2f16 = 32 +nir_op_b2f32 = 33 +nir_op_b2f64 = 34 +nir_op_b2i1 = 35 +nir_op_b2i16 = 36 +nir_op_b2i32 = 37 +nir_op_b2i64 = 38 +nir_op_b2i8 = 39 +nir_op_b32all_fequal16 = 40 +nir_op_b32all_fequal2 = 41 +nir_op_b32all_fequal3 = 42 +nir_op_b32all_fequal4 = 43 +nir_op_b32all_fequal5 = 44 +nir_op_b32all_fequal8 = 45 +nir_op_b32all_iequal16 = 46 +nir_op_b32all_iequal2 = 47 +nir_op_b32all_iequal3 = 48 +nir_op_b32all_iequal4 = 49 +nir_op_b32all_iequal5 = 50 +nir_op_b32all_iequal8 = 51 +nir_op_b32any_fnequal16 = 52 +nir_op_b32any_fnequal2 = 53 +nir_op_b32any_fnequal3 = 54 +nir_op_b32any_fnequal4 = 55 +nir_op_b32any_fnequal5 = 56 +nir_op_b32any_fnequal8 = 57 +nir_op_b32any_inequal16 = 58 +nir_op_b32any_inequal2 = 59 +nir_op_b32any_inequal3 = 60 +nir_op_b32any_inequal4 = 61 +nir_op_b32any_inequal5 = 62 +nir_op_b32any_inequal8 = 63 +nir_op_b32csel = 64 +nir_op_b32fcsel_mdg = 65 +nir_op_b8all_fequal16 = 66 +nir_op_b8all_fequal2 = 67 +nir_op_b8all_fequal3 = 68 +nir_op_b8all_fequal4 = 69 +nir_op_b8all_fequal5 = 70 +nir_op_b8all_fequal8 = 71 +nir_op_b8all_iequal16 = 72 +nir_op_b8all_iequal2 = 73 +nir_op_b8all_iequal3 = 74 +nir_op_b8all_iequal4 = 75 +nir_op_b8all_iequal5 = 76 +nir_op_b8all_iequal8 = 77 +nir_op_b8any_fnequal16 = 78 +nir_op_b8any_fnequal2 = 79 +nir_op_b8any_fnequal3 = 80 +nir_op_b8any_fnequal4 = 81 +nir_op_b8any_fnequal5 = 82 +nir_op_b8any_fnequal8 = 83 +nir_op_b8any_inequal16 = 84 +nir_op_b8any_inequal2 = 85 +nir_op_b8any_inequal3 = 86 +nir_op_b8any_inequal4 = 87 +nir_op_b8any_inequal5 = 88 +nir_op_b8any_inequal8 = 89 +nir_op_b8csel = 90 +nir_op_ball_fequal16 = 91 +nir_op_ball_fequal2 = 92 +nir_op_ball_fequal3 = 93 +nir_op_ball_fequal4 = 94 +nir_op_ball_fequal5 = 95 +nir_op_ball_fequal8 = 96 +nir_op_ball_iequal16 = 97 +nir_op_ball_iequal2 = 98 +nir_op_ball_iequal3 = 99 +nir_op_ball_iequal4 = 100 +nir_op_ball_iequal5 = 101 +nir_op_ball_iequal8 = 102 +nir_op_bany_fnequal16 = 103 +nir_op_bany_fnequal2 = 104 +nir_op_bany_fnequal3 = 105 +nir_op_bany_fnequal4 = 106 +nir_op_bany_fnequal5 = 107 +nir_op_bany_fnequal8 = 108 +nir_op_bany_inequal16 = 109 +nir_op_bany_inequal2 = 110 +nir_op_bany_inequal3 = 111 +nir_op_bany_inequal4 = 112 +nir_op_bany_inequal5 = 113 +nir_op_bany_inequal8 = 114 +nir_op_bcsel = 115 +nir_op_bf2f = 116 +nir_op_bfdot16 = 117 +nir_op_bfdot2 = 118 +nir_op_bfdot2_bfadd = 119 +nir_op_bfdot3 = 120 +nir_op_bfdot4 = 121 +nir_op_bfdot5 = 122 +nir_op_bfdot8 = 123 +nir_op_bffma = 124 +nir_op_bfi = 125 +nir_op_bfm = 126 +nir_op_bfmul = 127 +nir_op_bit_count = 128 +nir_op_bitfield_insert = 129 +nir_op_bitfield_reverse = 130 +nir_op_bitfield_select = 131 +nir_op_bitnz = 132 +nir_op_bitnz16 = 133 +nir_op_bitnz32 = 134 +nir_op_bitnz8 = 135 +nir_op_bitz = 136 +nir_op_bitz16 = 137 +nir_op_bitz32 = 138 +nir_op_bitz8 = 139 +nir_op_bounds_agx = 140 +nir_op_byte_perm_amd = 141 +nir_op_cube_amd = 142 +nir_op_e4m3fn2f = 143 +nir_op_e5m22f = 144 +nir_op_extr_agx = 145 +nir_op_extract_i16 = 146 +nir_op_extract_i8 = 147 +nir_op_extract_u16 = 148 +nir_op_extract_u8 = 149 +nir_op_f2bf = 150 +nir_op_f2e4m3fn = 151 +nir_op_f2e4m3fn_sat = 152 +nir_op_f2e4m3fn_satfn = 153 +nir_op_f2e5m2 = 154 +nir_op_f2e5m2_sat = 155 +nir_op_f2f16 = 156 +nir_op_f2f16_rtne = 157 +nir_op_f2f16_rtz = 158 +nir_op_f2f32 = 159 +nir_op_f2f64 = 160 +nir_op_f2fmp = 161 +nir_op_f2i1 = 162 +nir_op_f2i16 = 163 +nir_op_f2i32 = 164 +nir_op_f2i64 = 165 +nir_op_f2i8 = 166 +nir_op_f2imp = 167 +nir_op_f2snorm_16_v3d = 168 +nir_op_f2u1 = 169 +nir_op_f2u16 = 170 +nir_op_f2u32 = 171 +nir_op_f2u64 = 172 +nir_op_f2u8 = 173 +nir_op_f2ump = 174 +nir_op_f2unorm_16_v3d = 175 +nir_op_fabs = 176 +nir_op_fadd = 177 +nir_op_fall_equal16 = 178 +nir_op_fall_equal2 = 179 +nir_op_fall_equal3 = 180 +nir_op_fall_equal4 = 181 +nir_op_fall_equal5 = 182 +nir_op_fall_equal8 = 183 +nir_op_fany_nequal16 = 184 +nir_op_fany_nequal2 = 185 +nir_op_fany_nequal3 = 186 +nir_op_fany_nequal4 = 187 +nir_op_fany_nequal5 = 188 +nir_op_fany_nequal8 = 189 +nir_op_fceil = 190 +nir_op_fclamp_pos = 191 +nir_op_fcos = 192 +nir_op_fcos_amd = 193 +nir_op_fcos_mdg = 194 +nir_op_fcsel = 195 +nir_op_fcsel_ge = 196 +nir_op_fcsel_gt = 197 +nir_op_fdiv = 198 +nir_op_fdot16 = 199 +nir_op_fdot16_replicated = 200 +nir_op_fdot2 = 201 +nir_op_fdot2_replicated = 202 +nir_op_fdot3 = 203 +nir_op_fdot3_replicated = 204 +nir_op_fdot4 = 205 +nir_op_fdot4_replicated = 206 +nir_op_fdot5 = 207 +nir_op_fdot5_replicated = 208 +nir_op_fdot8 = 209 +nir_op_fdot8_replicated = 210 +nir_op_fdph = 211 +nir_op_fdph_replicated = 212 +nir_op_feq = 213 +nir_op_feq16 = 214 +nir_op_feq32 = 215 +nir_op_feq8 = 216 +nir_op_fequ = 217 +nir_op_fequ16 = 218 +nir_op_fequ32 = 219 +nir_op_fequ8 = 220 +nir_op_fexp2 = 221 +nir_op_ffloor = 222 +nir_op_ffma = 223 +nir_op_ffmaz = 224 +nir_op_ffract = 225 +nir_op_fge = 226 +nir_op_fge16 = 227 +nir_op_fge32 = 228 +nir_op_fge8 = 229 +nir_op_fgeu = 230 +nir_op_fgeu16 = 231 +nir_op_fgeu32 = 232 +nir_op_fgeu8 = 233 +nir_op_find_lsb = 234 +nir_op_fisfinite = 235 +nir_op_fisfinite32 = 236 +nir_op_fisnormal = 237 +nir_op_flog2 = 238 +nir_op_flrp = 239 +nir_op_flt = 240 +nir_op_flt16 = 241 +nir_op_flt32 = 242 +nir_op_flt8 = 243 +nir_op_fltu = 244 +nir_op_fltu16 = 245 +nir_op_fltu32 = 246 +nir_op_fltu8 = 247 +nir_op_fmax = 248 +nir_op_fmax_agx = 249 +nir_op_fmin = 250 +nir_op_fmin_agx = 251 +nir_op_fmod = 252 +nir_op_fmul = 253 +nir_op_fmulz = 254 +nir_op_fneg = 255 +nir_op_fneo = 256 +nir_op_fneo16 = 257 +nir_op_fneo32 = 258 +nir_op_fneo8 = 259 +nir_op_fneu = 260 +nir_op_fneu16 = 261 +nir_op_fneu32 = 262 +nir_op_fneu8 = 263 +nir_op_ford = 264 +nir_op_ford16 = 265 +nir_op_ford32 = 266 +nir_op_ford8 = 267 +nir_op_fpow = 268 +nir_op_fquantize2f16 = 269 +nir_op_frcp = 270 +nir_op_frem = 271 +nir_op_frexp_exp = 272 +nir_op_frexp_sig = 273 +nir_op_fround_even = 274 +nir_op_frsq = 275 +nir_op_fsat = 276 +nir_op_fsat_signed = 277 +nir_op_fsign = 278 +nir_op_fsin = 279 +nir_op_fsin_agx = 280 +nir_op_fsin_amd = 281 +nir_op_fsin_mdg = 282 +nir_op_fsqrt = 283 +nir_op_fsub = 284 +nir_op_fsum2 = 285 +nir_op_fsum3 = 286 +nir_op_fsum4 = 287 +nir_op_ftrunc = 288 +nir_op_funord = 289 +nir_op_funord16 = 290 +nir_op_funord32 = 291 +nir_op_funord8 = 292 +nir_op_i2f16 = 293 +nir_op_i2f32 = 294 +nir_op_i2f64 = 295 +nir_op_i2fmp = 296 +nir_op_i2i1 = 297 +nir_op_i2i16 = 298 +nir_op_i2i32 = 299 +nir_op_i2i64 = 300 +nir_op_i2i8 = 301 +nir_op_i2imp = 302 +nir_op_i32csel_ge = 303 +nir_op_i32csel_gt = 304 +nir_op_iabs = 305 +nir_op_iadd = 306 +nir_op_iadd3 = 307 +nir_op_iadd_sat = 308 +nir_op_iand = 309 +nir_op_ibfe = 310 +nir_op_ibitfield_extract = 311 +nir_op_icsel_eqz = 312 +nir_op_idiv = 313 +nir_op_ieq = 314 +nir_op_ieq16 = 315 +nir_op_ieq32 = 316 +nir_op_ieq8 = 317 +nir_op_ifind_msb = 318 +nir_op_ifind_msb_rev = 319 +nir_op_ige = 320 +nir_op_ige16 = 321 +nir_op_ige32 = 322 +nir_op_ige8 = 323 +nir_op_ihadd = 324 +nir_op_ilea_agx = 325 +nir_op_ilt = 326 +nir_op_ilt16 = 327 +nir_op_ilt32 = 328 +nir_op_ilt8 = 329 +nir_op_imad = 330 +nir_op_imad24_ir3 = 331 +nir_op_imadsh_mix16 = 332 +nir_op_imadshl_agx = 333 +nir_op_imax = 334 +nir_op_imin = 335 +nir_op_imod = 336 +nir_op_imsubshl_agx = 337 +nir_op_imul = 338 +nir_op_imul24 = 339 +nir_op_imul24_relaxed = 340 +nir_op_imul_2x32_64 = 341 +nir_op_imul_32x16 = 342 +nir_op_imul_high = 343 +nir_op_ine = 344 +nir_op_ine16 = 345 +nir_op_ine32 = 346 +nir_op_ine8 = 347 +nir_op_ineg = 348 +nir_op_inot = 349 +nir_op_insert_u16 = 350 +nir_op_insert_u8 = 351 +nir_op_interleave_agx = 352 +nir_op_ior = 353 +nir_op_irem = 354 +nir_op_irhadd = 355 +nir_op_ishl = 356 +nir_op_ishr = 357 +nir_op_isign = 358 +nir_op_isub = 359 +nir_op_isub_sat = 360 +nir_op_ixor = 361 +nir_op_ldexp = 362 +nir_op_ldexp16_pan = 363 +nir_op_lea_nv = 364 +nir_op_mov = 365 +nir_op_mqsad_4x8 = 366 +nir_op_msad_4x8 = 367 +nir_op_pack_2x16_to_snorm_2x8_v3d = 368 +nir_op_pack_2x16_to_unorm_10_2_v3d = 369 +nir_op_pack_2x16_to_unorm_2x10_v3d = 370 +nir_op_pack_2x16_to_unorm_2x8_v3d = 371 +nir_op_pack_2x32_to_2x16_v3d = 372 +nir_op_pack_32_2x16 = 373 +nir_op_pack_32_2x16_split = 374 +nir_op_pack_32_4x8 = 375 +nir_op_pack_32_4x8_split = 376 +nir_op_pack_32_to_r11g11b10_v3d = 377 +nir_op_pack_4x16_to_4x8_v3d = 378 +nir_op_pack_64_2x32 = 379 +nir_op_pack_64_2x32_split = 380 +nir_op_pack_64_4x16 = 381 +nir_op_pack_double_2x32_dxil = 382 +nir_op_pack_half_2x16 = 383 +nir_op_pack_half_2x16_rtz_split = 384 +nir_op_pack_half_2x16_split = 385 +nir_op_pack_sint_2x16 = 386 +nir_op_pack_snorm_2x16 = 387 +nir_op_pack_snorm_4x8 = 388 +nir_op_pack_uint_2x16 = 389 +nir_op_pack_uint_32_to_r10g10b10a2_v3d = 390 +nir_op_pack_unorm_2x16 = 391 +nir_op_pack_unorm_4x8 = 392 +nir_op_pack_uvec2_to_uint = 393 +nir_op_pack_uvec4_to_uint = 394 +nir_op_prmt_nv = 395 +nir_op_sdot_2x16_iadd = 396 +nir_op_sdot_2x16_iadd_sat = 397 +nir_op_sdot_4x8_iadd = 398 +nir_op_sdot_4x8_iadd_sat = 399 +nir_op_seq = 400 +nir_op_sge = 401 +nir_op_shfr = 402 +nir_op_shlg_ir3 = 403 +nir_op_shlm_ir3 = 404 +nir_op_shrg_ir3 = 405 +nir_op_shrm_ir3 = 406 +nir_op_slt = 407 +nir_op_sne = 408 +nir_op_sudot_4x8_iadd = 409 +nir_op_sudot_4x8_iadd_sat = 410 +nir_op_u2f16 = 411 +nir_op_u2f32 = 412 +nir_op_u2f64 = 413 +nir_op_u2fmp = 414 +nir_op_u2u1 = 415 +nir_op_u2u16 = 416 +nir_op_u2u32 = 417 +nir_op_u2u64 = 418 +nir_op_u2u8 = 419 +nir_op_uabs_isub = 420 +nir_op_uabs_usub = 421 +nir_op_uadd_carry = 422 +nir_op_uadd_sat = 423 +nir_op_ubfe = 424 +nir_op_ubitfield_extract = 425 +nir_op_uclz = 426 +nir_op_udiv = 427 +nir_op_udiv_aligned_4 = 428 +nir_op_udot_2x16_uadd = 429 +nir_op_udot_2x16_uadd_sat = 430 +nir_op_udot_4x8_uadd = 431 +nir_op_udot_4x8_uadd_sat = 432 +nir_op_ufind_msb = 433 +nir_op_ufind_msb_rev = 434 +nir_op_uge = 435 +nir_op_uge16 = 436 +nir_op_uge32 = 437 +nir_op_uge8 = 438 +nir_op_uhadd = 439 +nir_op_ulea_agx = 440 +nir_op_ult = 441 +nir_op_ult16 = 442 +nir_op_ult32 = 443 +nir_op_ult8 = 444 +nir_op_umad24 = 445 +nir_op_umad24_relaxed = 446 +nir_op_umax = 447 +nir_op_umax_4x8_vc4 = 448 +nir_op_umin = 449 +nir_op_umin_4x8_vc4 = 450 +nir_op_umod = 451 +nir_op_umul24 = 452 +nir_op_umul24_relaxed = 453 +nir_op_umul_2x32_64 = 454 +nir_op_umul_32x16 = 455 +nir_op_umul_high = 456 +nir_op_umul_low = 457 +nir_op_umul_unorm_4x8_vc4 = 458 +nir_op_unpack_32_2x16 = 459 +nir_op_unpack_32_2x16_split_x = 460 +nir_op_unpack_32_2x16_split_y = 461 +nir_op_unpack_32_4x8 = 462 +nir_op_unpack_64_2x32 = 463 +nir_op_unpack_64_2x32_split_x = 464 +nir_op_unpack_64_2x32_split_y = 465 +nir_op_unpack_64_4x16 = 466 +nir_op_unpack_double_2x32_dxil = 467 +nir_op_unpack_half_2x16 = 468 +nir_op_unpack_half_2x16_split_x = 469 +nir_op_unpack_half_2x16_split_y = 470 +nir_op_unpack_snorm_2x16 = 471 +nir_op_unpack_snorm_4x8 = 472 +nir_op_unpack_unorm_2x16 = 473 +nir_op_unpack_unorm_4x8 = 474 +nir_op_urhadd = 475 +nir_op_urol = 476 +nir_op_uror = 477 +nir_op_usadd_4x8_vc4 = 478 +nir_op_ushr = 479 +nir_op_ussub_4x8_vc4 = 480 +nir_op_usub_borrow = 481 +nir_op_usub_sat = 482 +nir_op_vec16 = 483 +nir_op_vec2 = 484 +nir_op_vec3 = 485 +nir_op_vec4 = 486 +nir_op_vec5 = 487 +nir_op_vec8 = 488 +nir_last_opcode = 488 +nir_num_opcodes = 489 +c__EA_nir_op = ctypes.c_uint32 # enum +nir_op = c__EA_nir_op +nir_op__enumvalues = c__EA_nir_op__enumvalues +try: + nir_type_conversion_op = _libraries['libtinymesa_cpu.so'].nir_type_conversion_op + nir_type_conversion_op.restype = nir_op + nir_type_conversion_op.argtypes = [nir_alu_type, nir_alu_type, nir_rounding_mode] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_atomic_op' +c__EA_nir_atomic_op__enumvalues = { + 0: 'nir_atomic_op_iadd', + 1: 'nir_atomic_op_imin', + 2: 'nir_atomic_op_umin', + 3: 'nir_atomic_op_imax', + 4: 'nir_atomic_op_umax', + 5: 'nir_atomic_op_iand', + 6: 'nir_atomic_op_ior', + 7: 'nir_atomic_op_ixor', + 8: 'nir_atomic_op_xchg', + 9: 'nir_atomic_op_fadd', + 10: 'nir_atomic_op_fmin', + 11: 'nir_atomic_op_fmax', + 12: 'nir_atomic_op_cmpxchg', + 13: 'nir_atomic_op_fcmpxchg', + 14: 'nir_atomic_op_inc_wrap', + 15: 'nir_atomic_op_dec_wrap', + 16: 'nir_atomic_op_ordered_add_gfx12_amd', +} +nir_atomic_op_iadd = 0 +nir_atomic_op_imin = 1 +nir_atomic_op_umin = 2 +nir_atomic_op_imax = 3 +nir_atomic_op_umax = 4 +nir_atomic_op_iand = 5 +nir_atomic_op_ior = 6 +nir_atomic_op_ixor = 7 +nir_atomic_op_xchg = 8 +nir_atomic_op_fadd = 9 +nir_atomic_op_fmin = 10 +nir_atomic_op_fmax = 11 +nir_atomic_op_cmpxchg = 12 +nir_atomic_op_fcmpxchg = 13 +nir_atomic_op_inc_wrap = 14 +nir_atomic_op_dec_wrap = 15 +nir_atomic_op_ordered_add_gfx12_amd = 16 +c__EA_nir_atomic_op = ctypes.c_uint32 # enum +nir_atomic_op = c__EA_nir_atomic_op +nir_atomic_op__enumvalues = c__EA_nir_atomic_op__enumvalues +try: + nir_atomic_op_type = _libraries['FIXME_STUB'].nir_atomic_op_type + nir_atomic_op_type.restype = nir_alu_type + nir_atomic_op_type.argtypes = [nir_atomic_op] +except AttributeError: + pass +try: + nir_atomic_op_to_alu = _libraries['libtinymesa_cpu.so'].nir_atomic_op_to_alu + nir_atomic_op_to_alu.restype = nir_op + nir_atomic_op_to_alu.argtypes = [nir_atomic_op] +except AttributeError: + pass +try: + nir_op_vec = _libraries['libtinymesa_cpu.so'].nir_op_vec + nir_op_vec.restype = nir_op + nir_op_vec.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + nir_op_is_vec = _libraries['libtinymesa_cpu.so'].nir_op_is_vec + nir_op_is_vec.restype = ctypes.c_bool + nir_op_is_vec.argtypes = [nir_op] +except AttributeError: + pass +try: + nir_op_is_vec_or_mov = _libraries['FIXME_STUB'].nir_op_is_vec_or_mov + nir_op_is_vec_or_mov.restype = ctypes.c_bool + nir_op_is_vec_or_mov.argtypes = [nir_op] +except AttributeError: + pass +try: + nir_is_float_control_signed_zero_preserve = _libraries['FIXME_STUB'].nir_is_float_control_signed_zero_preserve + nir_is_float_control_signed_zero_preserve.restype = ctypes.c_bool + nir_is_float_control_signed_zero_preserve.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_float_control_inf_preserve = _libraries['FIXME_STUB'].nir_is_float_control_inf_preserve + nir_is_float_control_inf_preserve.restype = ctypes.c_bool + nir_is_float_control_inf_preserve.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_float_control_nan_preserve = _libraries['FIXME_STUB'].nir_is_float_control_nan_preserve + nir_is_float_control_nan_preserve.restype = ctypes.c_bool + nir_is_float_control_nan_preserve.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_float_control_signed_zero_inf_nan_preserve = _libraries['FIXME_STUB'].nir_is_float_control_signed_zero_inf_nan_preserve + nir_is_float_control_signed_zero_inf_nan_preserve.restype = ctypes.c_bool + nir_is_float_control_signed_zero_inf_nan_preserve.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_denorm_flush_to_zero = _libraries['FIXME_STUB'].nir_is_denorm_flush_to_zero + nir_is_denorm_flush_to_zero.restype = ctypes.c_bool + nir_is_denorm_flush_to_zero.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_denorm_preserve = _libraries['FIXME_STUB'].nir_is_denorm_preserve + nir_is_denorm_preserve.restype = ctypes.c_bool + nir_is_denorm_preserve.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_rounding_mode_rtne = _libraries['FIXME_STUB'].nir_is_rounding_mode_rtne + nir_is_rounding_mode_rtne.restype = ctypes.c_bool + nir_is_rounding_mode_rtne.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_is_rounding_mode_rtz = _libraries['FIXME_STUB'].nir_is_rounding_mode_rtz + nir_is_rounding_mode_rtz.restype = ctypes.c_bool + nir_is_rounding_mode_rtz.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_has_any_rounding_mode_rtz = _libraries['FIXME_STUB'].nir_has_any_rounding_mode_rtz + nir_has_any_rounding_mode_rtz.restype = ctypes.c_bool + nir_has_any_rounding_mode_rtz.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + nir_has_any_rounding_mode_rtne = _libraries['FIXME_STUB'].nir_has_any_rounding_mode_rtne + nir_has_any_rounding_mode_rtne.restype = ctypes.c_bool + nir_has_any_rounding_mode_rtne.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + nir_get_rounding_mode_from_float_controls = _libraries['FIXME_STUB'].nir_get_rounding_mode_from_float_controls + nir_get_rounding_mode_from_float_controls.restype = nir_rounding_mode + nir_get_rounding_mode_from_float_controls.argtypes = [ctypes.c_uint32, nir_alu_type] +except AttributeError: + pass +try: + nir_has_any_rounding_mode_enabled = _libraries['FIXME_STUB'].nir_has_any_rounding_mode_enabled + nir_has_any_rounding_mode_enabled.restype = ctypes.c_bool + nir_has_any_rounding_mode_enabled.argtypes = [ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_op_algebraic_property' +c__EA_nir_op_algebraic_property__enumvalues = { + 1: 'NIR_OP_IS_2SRC_COMMUTATIVE', + 2: 'NIR_OP_IS_ASSOCIATIVE', + 4: 'NIR_OP_IS_SELECTION', +} +NIR_OP_IS_2SRC_COMMUTATIVE = 1 +NIR_OP_IS_ASSOCIATIVE = 2 +NIR_OP_IS_SELECTION = 4 +c__EA_nir_op_algebraic_property = ctypes.c_uint32 # enum +nir_op_algebraic_property = c__EA_nir_op_algebraic_property +nir_op_algebraic_property__enumvalues = c__EA_nir_op_algebraic_property__enumvalues +class struct_nir_op_info(Structure): + pass + +struct_nir_op_info._pack_ = 1 # source:False +struct_nir_op_info._fields_ = [ + ('name', ctypes.POINTER(ctypes.c_char)), + ('num_inputs', ctypes.c_ubyte), + ('output_size', ctypes.c_ubyte), + ('PADDING_0', ctypes.c_ubyte * 2), + ('output_type', nir_alu_type), + ('input_sizes', ctypes.c_ubyte * 16), + ('input_types', c__EA_nir_alu_type * 16), + ('algebraic_properties', nir_op_algebraic_property), + ('is_conversion', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 3), +] + +nir_op_info = struct_nir_op_info +try: nir_op_infos = (struct_nir_op_info * 489).in_dll(_libraries['libtinymesa_cpu.so'], 'nir_op_infos') +except (AttributeError, ValueError): pass +try: + nir_op_is_selection = _libraries['FIXME_STUB'].nir_op_is_selection + nir_op_is_selection.restype = ctypes.c_bool + nir_op_is_selection.argtypes = [nir_op] +except AttributeError: + pass +class struct_nir_alu_instr(Structure): + pass + +struct_nir_alu_instr._pack_ = 1 # source:False +struct_nir_alu_instr._fields_ = [ + ('instr', nir_instr), + ('op', nir_op), + ('exact', ctypes.c_bool, 1), + ('no_signed_wrap', ctypes.c_bool, 1), + ('no_unsigned_wrap', ctypes.c_bool, 1), + ('fp_fast_math', ctypes.c_uint32, 9), + ('PADDING_0', ctypes.c_uint32, 20), + ('def', nir_def), + ('src', struct_nir_alu_src * 0), +] + +nir_alu_instr = struct_nir_alu_instr +try: + nir_alu_instr_is_signed_zero_preserve = _libraries['FIXME_STUB'].nir_alu_instr_is_signed_zero_preserve + nir_alu_instr_is_signed_zero_preserve.restype = ctypes.c_bool + nir_alu_instr_is_signed_zero_preserve.argtypes = [ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_alu_instr_is_inf_preserve = _libraries['FIXME_STUB'].nir_alu_instr_is_inf_preserve + nir_alu_instr_is_inf_preserve.restype = ctypes.c_bool + nir_alu_instr_is_inf_preserve.argtypes = [ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_alu_instr_is_nan_preserve = _libraries['FIXME_STUB'].nir_alu_instr_is_nan_preserve + nir_alu_instr_is_nan_preserve.restype = ctypes.c_bool + nir_alu_instr_is_nan_preserve.argtypes = [ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_alu_instr_is_signed_zero_inf_nan_preserve = _libraries['FIXME_STUB'].nir_alu_instr_is_signed_zero_inf_nan_preserve + nir_alu_instr_is_signed_zero_inf_nan_preserve.restype = ctypes.c_bool + nir_alu_instr_is_signed_zero_inf_nan_preserve.argtypes = [ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_alu_src_copy = _libraries['libtinymesa_cpu.so'].nir_alu_src_copy + nir_alu_src_copy.restype = None + nir_alu_src_copy.argtypes = [ctypes.POINTER(struct_nir_alu_src), ctypes.POINTER(struct_nir_alu_src)] +except AttributeError: + pass +try: + nir_alu_instr_src_read_mask = _libraries['libtinymesa_cpu.so'].nir_alu_instr_src_read_mask + nir_alu_instr_src_read_mask.restype = nir_component_mask_t + nir_alu_instr_src_read_mask.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_ssa_alu_instr_src_components = _libraries['libtinymesa_cpu.so'].nir_ssa_alu_instr_src_components + nir_ssa_alu_instr_src_components.restype = ctypes.c_uint32 + nir_ssa_alu_instr_src_components.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_alu_instr_channel_used = _libraries['FIXME_STUB'].nir_alu_instr_channel_used + nir_alu_instr_channel_used.restype = ctypes.c_bool + nir_alu_instr_channel_used.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_alu_instr_is_comparison = _libraries['libtinymesa_cpu.so'].nir_alu_instr_is_comparison + nir_alu_instr_is_comparison.restype = ctypes.c_bool + nir_alu_instr_is_comparison.argtypes = [ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_const_value_negative_equal = _libraries['libtinymesa_cpu.so'].nir_const_value_negative_equal + nir_const_value_negative_equal.restype = ctypes.c_bool + nir_const_value_negative_equal.argtypes = [nir_const_value, nir_const_value, nir_alu_type] +except AttributeError: + pass +try: + nir_alu_srcs_equal = _libraries['libtinymesa_cpu.so'].nir_alu_srcs_equal + nir_alu_srcs_equal.restype = ctypes.c_bool + nir_alu_srcs_equal.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_alu_srcs_negative_equal_typed = _libraries['libtinymesa_cpu.so'].nir_alu_srcs_negative_equal_typed + nir_alu_srcs_negative_equal_typed.restype = ctypes.c_bool + nir_alu_srcs_negative_equal_typed.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32, ctypes.c_uint32, nir_alu_type] +except AttributeError: + pass +try: + nir_alu_srcs_negative_equal = _libraries['libtinymesa_cpu.so'].nir_alu_srcs_negative_equal + nir_alu_srcs_negative_equal.restype = ctypes.c_bool + nir_alu_srcs_negative_equal.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_alu_src_is_trivial_ssa = _libraries['libtinymesa_cpu.so'].nir_alu_src_is_trivial_ssa + nir_alu_src_is_trivial_ssa.restype = ctypes.c_bool + nir_alu_src_is_trivial_ssa.argtypes = [ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_deref_type' +c__EA_nir_deref_type__enumvalues = { + 0: 'nir_deref_type_var', + 1: 'nir_deref_type_array', + 2: 'nir_deref_type_array_wildcard', + 3: 'nir_deref_type_ptr_as_array', + 4: 'nir_deref_type_struct', + 5: 'nir_deref_type_cast', +} +nir_deref_type_var = 0 +nir_deref_type_array = 1 +nir_deref_type_array_wildcard = 2 +nir_deref_type_ptr_as_array = 3 +nir_deref_type_struct = 4 +nir_deref_type_cast = 5 +c__EA_nir_deref_type = ctypes.c_uint32 # enum +nir_deref_type = c__EA_nir_deref_type +nir_deref_type__enumvalues = c__EA_nir_deref_type__enumvalues +class struct_nir_deref_instr(Structure): + pass + +class union_nir_deref_instr_0(Union): + pass + +union_nir_deref_instr_0._pack_ = 1 # source:False +union_nir_deref_instr_0._fields_ = [ + ('var', ctypes.POINTER(struct_nir_variable)), + ('parent', nir_src), +] + +class union_nir_deref_instr_1(Union): + pass + +class struct_nir_deref_instr_1_arr(Structure): + pass + +struct_nir_deref_instr_1_arr._pack_ = 1 # source:False +struct_nir_deref_instr_1_arr._fields_ = [ + ('index', nir_src), + ('in_bounds', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), +] + +class struct_nir_deref_instr_1_strct(Structure): + pass + +struct_nir_deref_instr_1_strct._pack_ = 1 # source:False +struct_nir_deref_instr_1_strct._fields_ = [ + ('index', ctypes.c_uint32), +] + +class struct_nir_deref_instr_1_cast(Structure): + pass + +struct_nir_deref_instr_1_cast._pack_ = 1 # source:False +struct_nir_deref_instr_1_cast._fields_ = [ + ('ptr_stride', ctypes.c_uint32), + ('align_mul', ctypes.c_uint32), + ('align_offset', ctypes.c_uint32), +] + +union_nir_deref_instr_1._pack_ = 1 # source:False +union_nir_deref_instr_1._fields_ = [ + ('arr', struct_nir_deref_instr_1_arr), + ('strct', struct_nir_deref_instr_1_strct), + ('cast', struct_nir_deref_instr_1_cast), + ('PADDING_0', ctypes.c_ubyte * 28), +] + +struct_nir_deref_instr._pack_ = 1 # source:False +struct_nir_deref_instr._anonymous_ = ('_0', '_1',) +struct_nir_deref_instr._fields_ = [ + ('instr', nir_instr), + ('deref_type', nir_deref_type), + ('modes', c__EA_nir_variable_mode), + ('type', ctypes.POINTER(struct_glsl_type)), + ('_0', union_nir_deref_instr_0), + ('_1', union_nir_deref_instr_1), + ('def', nir_def), +] + +nir_deref_instr = struct_nir_deref_instr +try: + nir_deref_cast_is_trivial = _libraries['libtinymesa_cpu.so'].nir_deref_cast_is_trivial + nir_deref_cast_is_trivial.restype = ctypes.c_bool + nir_deref_cast_is_trivial.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +nir_variable_mode = c__EA_nir_variable_mode +nir_variable_mode__enumvalues = c__EA_nir_variable_mode__enumvalues +try: + nir_deref_mode_may_be = _libraries['FIXME_STUB'].nir_deref_mode_may_be + nir_deref_mode_may_be.restype = ctypes.c_bool + nir_deref_mode_may_be.argtypes = [ctypes.POINTER(struct_nir_deref_instr), nir_variable_mode] +except AttributeError: + pass +try: + nir_deref_mode_must_be = _libraries['FIXME_STUB'].nir_deref_mode_must_be + nir_deref_mode_must_be.restype = ctypes.c_bool + nir_deref_mode_must_be.argtypes = [ctypes.POINTER(struct_nir_deref_instr), nir_variable_mode] +except AttributeError: + pass +try: + nir_deref_mode_is = _libraries['FIXME_STUB'].nir_deref_mode_is + nir_deref_mode_is.restype = ctypes.c_bool + nir_deref_mode_is.argtypes = [ctypes.POINTER(struct_nir_deref_instr), nir_variable_mode] +except AttributeError: + pass +try: + nir_deref_mode_is_one_of = _libraries['FIXME_STUB'].nir_deref_mode_is_one_of + nir_deref_mode_is_one_of.restype = ctypes.c_bool + nir_deref_mode_is_one_of.argtypes = [ctypes.POINTER(struct_nir_deref_instr), nir_variable_mode] +except AttributeError: + pass +try: + nir_deref_mode_is_in_set = _libraries['FIXME_STUB'].nir_deref_mode_is_in_set + nir_deref_mode_is_in_set.restype = ctypes.c_bool + nir_deref_mode_is_in_set.argtypes = [ctypes.POINTER(struct_nir_deref_instr), nir_variable_mode] +except AttributeError: + pass +try: + nir_src_as_deref = _libraries['FIXME_STUB'].nir_src_as_deref + nir_src_as_deref.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_src_as_deref.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_deref_instr_parent = _libraries['FIXME_STUB'].nir_deref_instr_parent + nir_deref_instr_parent.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_deref_instr_parent.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_deref_instr_get_variable = _libraries['FIXME_STUB'].nir_deref_instr_get_variable + nir_deref_instr_get_variable.restype = ctypes.POINTER(struct_nir_variable) + nir_deref_instr_get_variable.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_deref_instr_has_indirect = _libraries['libtinymesa_cpu.so'].nir_deref_instr_has_indirect + nir_deref_instr_has_indirect.restype = ctypes.c_bool + nir_deref_instr_has_indirect.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_deref_instr_is_known_out_of_bounds = _libraries['libtinymesa_cpu.so'].nir_deref_instr_is_known_out_of_bounds + nir_deref_instr_is_known_out_of_bounds.restype = ctypes.c_bool + nir_deref_instr_is_known_out_of_bounds.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_deref_instr_has_complex_use_options' +c__EA_nir_deref_instr_has_complex_use_options__enumvalues = { + 1: 'nir_deref_instr_has_complex_use_allow_memcpy_src', + 2: 'nir_deref_instr_has_complex_use_allow_memcpy_dst', + 4: 'nir_deref_instr_has_complex_use_allow_atomics', +} +nir_deref_instr_has_complex_use_allow_memcpy_src = 1 +nir_deref_instr_has_complex_use_allow_memcpy_dst = 2 +nir_deref_instr_has_complex_use_allow_atomics = 4 +c__EA_nir_deref_instr_has_complex_use_options = ctypes.c_uint32 # enum +nir_deref_instr_has_complex_use_options = c__EA_nir_deref_instr_has_complex_use_options +nir_deref_instr_has_complex_use_options__enumvalues = c__EA_nir_deref_instr_has_complex_use_options__enumvalues +try: + nir_deref_instr_has_complex_use = _libraries['libtinymesa_cpu.so'].nir_deref_instr_has_complex_use + nir_deref_instr_has_complex_use.restype = ctypes.c_bool + nir_deref_instr_has_complex_use.argtypes = [ctypes.POINTER(struct_nir_deref_instr), nir_deref_instr_has_complex_use_options] +except AttributeError: + pass +try: + nir_deref_instr_remove_if_unused = _libraries['libtinymesa_cpu.so'].nir_deref_instr_remove_if_unused + nir_deref_instr_remove_if_unused.restype = ctypes.c_bool + nir_deref_instr_remove_if_unused.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_deref_instr_array_stride = _libraries['libtinymesa_cpu.so'].nir_deref_instr_array_stride + nir_deref_instr_array_stride.restype = ctypes.c_uint32 + nir_deref_instr_array_stride.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +class struct_nir_call_instr(Structure): + pass + +class struct_nir_function(Structure): + pass + +struct_nir_call_instr._pack_ = 1 # source:False +struct_nir_call_instr._fields_ = [ + ('instr', nir_instr), + ('callee', ctypes.POINTER(struct_nir_function)), + ('indirect_callee', nir_src), + ('num_params', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('params', struct_nir_src * 0), +] + +class struct_nir_parameter(Structure): + pass + +class struct_nir_function_impl(Structure): + pass + +struct_nir_function._pack_ = 1 # source:False +struct_nir_function._fields_ = [ + ('node', struct_exec_node), + ('name', ctypes.POINTER(ctypes.c_char)), + ('shader', ctypes.POINTER(struct_nir_shader)), + ('num_params', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('params', ctypes.POINTER(struct_nir_parameter)), + ('impl', ctypes.POINTER(struct_nir_function_impl)), + ('driver_attributes', ctypes.c_uint32), + ('is_entrypoint', ctypes.c_bool), + ('is_exported', ctypes.c_bool), + ('is_preamble', ctypes.c_bool), + ('should_inline', ctypes.c_bool), + ('dont_inline', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 3), + ('workgroup_size', ctypes.c_uint32 * 3), + ('is_subroutine', ctypes.c_bool), + ('is_tmp_globals_wrapper', ctypes.c_bool), + ('PADDING_2', ctypes.c_ubyte * 2), + ('num_subroutine_types', ctypes.c_int32), + ('subroutine_types', ctypes.POINTER(ctypes.POINTER(struct_glsl_type))), + ('subroutine_index', ctypes.c_int32), + ('pass_flags', ctypes.c_uint32), +] + +struct_nir_parameter._pack_ = 1 # source:False +struct_nir_parameter._fields_ = [ + ('num_components', ctypes.c_ubyte), + ('bit_size', ctypes.c_ubyte), + ('is_return', ctypes.c_bool), + ('implicit_conversion_prohibited', ctypes.c_bool), + ('is_uniform', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('mode', nir_variable_mode), + ('driver_attributes', ctypes.c_uint32), + ('type', ctypes.POINTER(struct_glsl_type)), + ('name', ctypes.POINTER(ctypes.c_char)), +] + + +# values for enumeration 'c__EA_nir_metadata' +c__EA_nir_metadata__enumvalues = { + 0: 'nir_metadata_none', + 1: 'nir_metadata_block_index', + 2: 'nir_metadata_dominance', + 4: 'nir_metadata_live_defs', + 8: 'nir_metadata_not_properly_reset', + 16: 'nir_metadata_loop_analysis', + 32: 'nir_metadata_instr_index', + 64: 'nir_metadata_divergence', + 3: 'nir_metadata_control_flow', + -9: 'nir_metadata_all', +} +nir_metadata_none = 0 +nir_metadata_block_index = 1 +nir_metadata_dominance = 2 +nir_metadata_live_defs = 4 +nir_metadata_not_properly_reset = 8 +nir_metadata_loop_analysis = 16 +nir_metadata_instr_index = 32 +nir_metadata_divergence = 64 +nir_metadata_control_flow = 3 +nir_metadata_all = -9 +c__EA_nir_metadata = ctypes.c_int32 # enum +struct_nir_function_impl._pack_ = 1 # source:False +struct_nir_function_impl._fields_ = [ + ('cf_node', struct_nir_cf_node), + ('function', ctypes.POINTER(struct_nir_function)), + ('preamble', ctypes.POINTER(struct_nir_function)), + ('body', struct_exec_list), + ('end_block', ctypes.POINTER(struct_nir_block)), + ('locals', struct_exec_list), + ('ssa_alloc', ctypes.c_uint32), + ('num_blocks', ctypes.c_uint32), + ('structured', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('valid_metadata', c__EA_nir_metadata), + ('loop_analysis_indirect_mask', nir_variable_mode), + ('loop_analysis_force_unroll_sampler_indirect', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 3), +] + +nir_call_instr = struct_nir_call_instr + +# values for enumeration 'c__EA_nir_intrinsic_op' +c__EA_nir_intrinsic_op__enumvalues = { + 0: 'nir_intrinsic_accept_ray_intersection', + 1: 'nir_intrinsic_addr_mode_is', + 2: 'nir_intrinsic_al2p_nv', + 3: 'nir_intrinsic_ald_nv', + 4: 'nir_intrinsic_alpha_to_coverage', + 5: 'nir_intrinsic_as_uniform', + 6: 'nir_intrinsic_ast_nv', + 7: 'nir_intrinsic_atomic_add_gen_prim_count_amd', + 8: 'nir_intrinsic_atomic_add_gs_emit_prim_count_amd', + 9: 'nir_intrinsic_atomic_add_shader_invocation_count_amd', + 10: 'nir_intrinsic_atomic_add_xfb_prim_count_amd', + 11: 'nir_intrinsic_atomic_counter_add', + 12: 'nir_intrinsic_atomic_counter_add_deref', + 13: 'nir_intrinsic_atomic_counter_and', + 14: 'nir_intrinsic_atomic_counter_and_deref', + 15: 'nir_intrinsic_atomic_counter_comp_swap', + 16: 'nir_intrinsic_atomic_counter_comp_swap_deref', + 17: 'nir_intrinsic_atomic_counter_exchange', + 18: 'nir_intrinsic_atomic_counter_exchange_deref', + 19: 'nir_intrinsic_atomic_counter_inc', + 20: 'nir_intrinsic_atomic_counter_inc_deref', + 21: 'nir_intrinsic_atomic_counter_max', + 22: 'nir_intrinsic_atomic_counter_max_deref', + 23: 'nir_intrinsic_atomic_counter_min', + 24: 'nir_intrinsic_atomic_counter_min_deref', + 25: 'nir_intrinsic_atomic_counter_or', + 26: 'nir_intrinsic_atomic_counter_or_deref', + 27: 'nir_intrinsic_atomic_counter_post_dec', + 28: 'nir_intrinsic_atomic_counter_post_dec_deref', + 29: 'nir_intrinsic_atomic_counter_pre_dec', + 30: 'nir_intrinsic_atomic_counter_pre_dec_deref', + 31: 'nir_intrinsic_atomic_counter_read', + 32: 'nir_intrinsic_atomic_counter_read_deref', + 33: 'nir_intrinsic_atomic_counter_xor', + 34: 'nir_intrinsic_atomic_counter_xor_deref', + 35: 'nir_intrinsic_ballot', + 36: 'nir_intrinsic_ballot_bit_count_exclusive', + 37: 'nir_intrinsic_ballot_bit_count_inclusive', + 38: 'nir_intrinsic_ballot_bit_count_reduce', + 39: 'nir_intrinsic_ballot_bitfield_extract', + 40: 'nir_intrinsic_ballot_find_lsb', + 41: 'nir_intrinsic_ballot_find_msb', + 42: 'nir_intrinsic_ballot_relaxed', + 43: 'nir_intrinsic_bar_break_nv', + 44: 'nir_intrinsic_bar_set_nv', + 45: 'nir_intrinsic_bar_sync_nv', + 46: 'nir_intrinsic_barrier', + 47: 'nir_intrinsic_begin_invocation_interlock', + 48: 'nir_intrinsic_bindgen_return', + 49: 'nir_intrinsic_bindless_image_agx', + 50: 'nir_intrinsic_bindless_image_atomic', + 51: 'nir_intrinsic_bindless_image_atomic_swap', + 52: 'nir_intrinsic_bindless_image_descriptor_amd', + 53: 'nir_intrinsic_bindless_image_format', + 54: 'nir_intrinsic_bindless_image_fragment_mask_load_amd', + 55: 'nir_intrinsic_bindless_image_levels', + 56: 'nir_intrinsic_bindless_image_load', + 57: 'nir_intrinsic_bindless_image_load_raw_intel', + 58: 'nir_intrinsic_bindless_image_order', + 59: 'nir_intrinsic_bindless_image_samples', + 60: 'nir_intrinsic_bindless_image_samples_identical', + 61: 'nir_intrinsic_bindless_image_size', + 62: 'nir_intrinsic_bindless_image_sparse_load', + 63: 'nir_intrinsic_bindless_image_store', + 64: 'nir_intrinsic_bindless_image_store_block_agx', + 65: 'nir_intrinsic_bindless_image_store_raw_intel', + 66: 'nir_intrinsic_bindless_image_texel_address', + 67: 'nir_intrinsic_bindless_resource_ir3', + 68: 'nir_intrinsic_brcst_active_ir3', + 69: 'nir_intrinsic_btd_retire_intel', + 70: 'nir_intrinsic_btd_spawn_intel', + 71: 'nir_intrinsic_btd_stack_push_intel', + 72: 'nir_intrinsic_bvh64_intersect_ray_amd', + 73: 'nir_intrinsic_bvh8_intersect_ray_amd', + 74: 'nir_intrinsic_bvh_stack_rtn_amd', + 75: 'nir_intrinsic_cmat_binary_op', + 76: 'nir_intrinsic_cmat_bitcast', + 77: 'nir_intrinsic_cmat_construct', + 78: 'nir_intrinsic_cmat_convert', + 79: 'nir_intrinsic_cmat_copy', + 80: 'nir_intrinsic_cmat_extract', + 81: 'nir_intrinsic_cmat_insert', + 82: 'nir_intrinsic_cmat_length', + 83: 'nir_intrinsic_cmat_load', + 84: 'nir_intrinsic_cmat_muladd', + 85: 'nir_intrinsic_cmat_muladd_amd', + 86: 'nir_intrinsic_cmat_muladd_nv', + 87: 'nir_intrinsic_cmat_scalar_op', + 88: 'nir_intrinsic_cmat_store', + 89: 'nir_intrinsic_cmat_transpose', + 90: 'nir_intrinsic_cmat_unary_op', + 91: 'nir_intrinsic_convert_alu_types', + 92: 'nir_intrinsic_convert_cmat_intel', + 93: 'nir_intrinsic_copy_deref', + 94: 'nir_intrinsic_copy_fs_outputs_nv', + 95: 'nir_intrinsic_copy_global_to_uniform_ir3', + 96: 'nir_intrinsic_copy_push_const_to_uniform_ir3', + 97: 'nir_intrinsic_copy_ubo_to_uniform_ir3', + 98: 'nir_intrinsic_ddx', + 99: 'nir_intrinsic_ddx_coarse', + 100: 'nir_intrinsic_ddx_fine', + 101: 'nir_intrinsic_ddy', + 102: 'nir_intrinsic_ddy_coarse', + 103: 'nir_intrinsic_ddy_fine', + 104: 'nir_intrinsic_debug_break', + 105: 'nir_intrinsic_decl_reg', + 106: 'nir_intrinsic_demote', + 107: 'nir_intrinsic_demote_if', + 108: 'nir_intrinsic_demote_samples', + 109: 'nir_intrinsic_deref_atomic', + 110: 'nir_intrinsic_deref_atomic_swap', + 111: 'nir_intrinsic_deref_buffer_array_length', + 112: 'nir_intrinsic_deref_implicit_array_length', + 113: 'nir_intrinsic_deref_mode_is', + 114: 'nir_intrinsic_deref_texture_src', + 115: 'nir_intrinsic_doorbell_agx', + 116: 'nir_intrinsic_dpas_intel', + 117: 'nir_intrinsic_dpp16_shift_amd', + 118: 'nir_intrinsic_elect', + 119: 'nir_intrinsic_elect_any_ir3', + 120: 'nir_intrinsic_emit_primitive_poly', + 121: 'nir_intrinsic_emit_vertex', + 122: 'nir_intrinsic_emit_vertex_nv', + 123: 'nir_intrinsic_emit_vertex_with_counter', + 124: 'nir_intrinsic_end_invocation_interlock', + 125: 'nir_intrinsic_end_primitive', + 126: 'nir_intrinsic_end_primitive_nv', + 127: 'nir_intrinsic_end_primitive_with_counter', + 128: 'nir_intrinsic_enqueue_node_payloads', + 129: 'nir_intrinsic_exclusive_scan', + 130: 'nir_intrinsic_exclusive_scan_clusters_ir3', + 131: 'nir_intrinsic_execute_callable', + 132: 'nir_intrinsic_execute_closest_hit_amd', + 133: 'nir_intrinsic_execute_miss_amd', + 134: 'nir_intrinsic_export_agx', + 135: 'nir_intrinsic_export_amd', + 136: 'nir_intrinsic_export_dual_src_blend_amd', + 137: 'nir_intrinsic_export_row_amd', + 138: 'nir_intrinsic_fence_helper_exit_agx', + 139: 'nir_intrinsic_fence_mem_to_tex_agx', + 140: 'nir_intrinsic_fence_pbe_to_tex_agx', + 141: 'nir_intrinsic_fence_pbe_to_tex_pixel_agx', + 142: 'nir_intrinsic_final_primitive_nv', + 143: 'nir_intrinsic_finalize_incoming_node_payload', + 144: 'nir_intrinsic_first_invocation', + 145: 'nir_intrinsic_fs_out_nv', + 146: 'nir_intrinsic_gds_atomic_add_amd', + 147: 'nir_intrinsic_get_ssbo_size', + 148: 'nir_intrinsic_get_ubo_size', + 149: 'nir_intrinsic_global_atomic', + 150: 'nir_intrinsic_global_atomic_2x32', + 151: 'nir_intrinsic_global_atomic_agx', + 152: 'nir_intrinsic_global_atomic_amd', + 153: 'nir_intrinsic_global_atomic_swap', + 154: 'nir_intrinsic_global_atomic_swap_2x32', + 155: 'nir_intrinsic_global_atomic_swap_agx', + 156: 'nir_intrinsic_global_atomic_swap_amd', + 157: 'nir_intrinsic_ignore_ray_intersection', + 158: 'nir_intrinsic_imadsp_nv', + 159: 'nir_intrinsic_image_atomic', + 160: 'nir_intrinsic_image_atomic_swap', + 161: 'nir_intrinsic_image_deref_atomic', + 162: 'nir_intrinsic_image_deref_atomic_swap', + 163: 'nir_intrinsic_image_deref_descriptor_amd', + 164: 'nir_intrinsic_image_deref_format', + 165: 'nir_intrinsic_image_deref_fragment_mask_load_amd', + 166: 'nir_intrinsic_image_deref_levels', + 167: 'nir_intrinsic_image_deref_load', + 168: 'nir_intrinsic_image_deref_load_info_nv', + 169: 'nir_intrinsic_image_deref_load_param_intel', + 170: 'nir_intrinsic_image_deref_load_raw_intel', + 171: 'nir_intrinsic_image_deref_order', + 172: 'nir_intrinsic_image_deref_samples', + 173: 'nir_intrinsic_image_deref_samples_identical', + 174: 'nir_intrinsic_image_deref_size', + 175: 'nir_intrinsic_image_deref_sparse_load', + 176: 'nir_intrinsic_image_deref_store', + 177: 'nir_intrinsic_image_deref_store_block_agx', + 178: 'nir_intrinsic_image_deref_store_raw_intel', + 179: 'nir_intrinsic_image_deref_texel_address', + 180: 'nir_intrinsic_image_descriptor_amd', + 181: 'nir_intrinsic_image_format', + 182: 'nir_intrinsic_image_fragment_mask_load_amd', + 183: 'nir_intrinsic_image_levels', + 184: 'nir_intrinsic_image_load', + 185: 'nir_intrinsic_image_load_raw_intel', + 186: 'nir_intrinsic_image_order', + 187: 'nir_intrinsic_image_samples', + 188: 'nir_intrinsic_image_samples_identical', + 189: 'nir_intrinsic_image_size', + 190: 'nir_intrinsic_image_sparse_load', + 191: 'nir_intrinsic_image_store', + 192: 'nir_intrinsic_image_store_block_agx', + 193: 'nir_intrinsic_image_store_raw_intel', + 194: 'nir_intrinsic_image_texel_address', + 195: 'nir_intrinsic_inclusive_scan', + 196: 'nir_intrinsic_inclusive_scan_clusters_ir3', + 197: 'nir_intrinsic_initialize_node_payloads', + 198: 'nir_intrinsic_interp_deref_at_centroid', + 199: 'nir_intrinsic_interp_deref_at_offset', + 200: 'nir_intrinsic_interp_deref_at_sample', + 201: 'nir_intrinsic_interp_deref_at_vertex', + 202: 'nir_intrinsic_inverse_ballot', + 203: 'nir_intrinsic_ipa_nv', + 204: 'nir_intrinsic_is_helper_invocation', + 205: 'nir_intrinsic_is_sparse_resident_zink', + 206: 'nir_intrinsic_is_sparse_texels_resident', + 207: 'nir_intrinsic_is_subgroup_invocation_lt_amd', + 208: 'nir_intrinsic_isberd_nv', + 209: 'nir_intrinsic_lane_permute_16_amd', + 210: 'nir_intrinsic_last_invocation', + 211: 'nir_intrinsic_launch_mesh_workgroups', + 212: 'nir_intrinsic_launch_mesh_workgroups_with_payload_deref', + 213: 'nir_intrinsic_ldc_nv', + 214: 'nir_intrinsic_ldcx_nv', + 215: 'nir_intrinsic_ldtram_nv', + 216: 'nir_intrinsic_load_aa_line_width', + 217: 'nir_intrinsic_load_accel_struct_amd', + 218: 'nir_intrinsic_load_active_samples_agx', + 219: 'nir_intrinsic_load_active_subgroup_count_agx', + 220: 'nir_intrinsic_load_active_subgroup_invocation_agx', + 221: 'nir_intrinsic_load_agx', + 222: 'nir_intrinsic_load_alpha_reference_amd', + 223: 'nir_intrinsic_load_api_sample_mask_agx', + 224: 'nir_intrinsic_load_attrib_clamp_agx', + 225: 'nir_intrinsic_load_attribute_pan', + 226: 'nir_intrinsic_load_back_face_agx', + 227: 'nir_intrinsic_load_barycentric_at_offset', + 228: 'nir_intrinsic_load_barycentric_at_offset_nv', + 229: 'nir_intrinsic_load_barycentric_at_sample', + 230: 'nir_intrinsic_load_barycentric_centroid', + 231: 'nir_intrinsic_load_barycentric_coord_at_offset', + 232: 'nir_intrinsic_load_barycentric_coord_at_sample', + 233: 'nir_intrinsic_load_barycentric_coord_centroid', + 234: 'nir_intrinsic_load_barycentric_coord_pixel', + 235: 'nir_intrinsic_load_barycentric_coord_sample', + 236: 'nir_intrinsic_load_barycentric_model', + 237: 'nir_intrinsic_load_barycentric_optimize_amd', + 238: 'nir_intrinsic_load_barycentric_pixel', + 239: 'nir_intrinsic_load_barycentric_sample', + 240: 'nir_intrinsic_load_base_global_invocation_id', + 241: 'nir_intrinsic_load_base_instance', + 242: 'nir_intrinsic_load_base_vertex', + 243: 'nir_intrinsic_load_base_workgroup_id', + 244: 'nir_intrinsic_load_blend_const_color_a_float', + 245: 'nir_intrinsic_load_blend_const_color_aaaa8888_unorm', + 246: 'nir_intrinsic_load_blend_const_color_b_float', + 247: 'nir_intrinsic_load_blend_const_color_g_float', + 248: 'nir_intrinsic_load_blend_const_color_r_float', + 249: 'nir_intrinsic_load_blend_const_color_rgba', + 250: 'nir_intrinsic_load_blend_const_color_rgba8888_unorm', + 251: 'nir_intrinsic_load_btd_global_arg_addr_intel', + 252: 'nir_intrinsic_load_btd_local_arg_addr_intel', + 253: 'nir_intrinsic_load_btd_resume_sbt_addr_intel', + 254: 'nir_intrinsic_load_btd_shader_type_intel', + 255: 'nir_intrinsic_load_btd_stack_id_intel', + 256: 'nir_intrinsic_load_buffer_amd', + 257: 'nir_intrinsic_load_callable_sbt_addr_intel', + 258: 'nir_intrinsic_load_callable_sbt_stride_intel', + 259: 'nir_intrinsic_load_clamp_vertex_color_amd', + 260: 'nir_intrinsic_load_clip_half_line_width_amd', + 261: 'nir_intrinsic_load_clip_z_coeff_agx', + 262: 'nir_intrinsic_load_coalesced_input_count', + 263: 'nir_intrinsic_load_coefficients_agx', + 264: 'nir_intrinsic_load_color0', + 265: 'nir_intrinsic_load_color1', + 266: 'nir_intrinsic_load_const_buf_base_addr_lvp', + 267: 'nir_intrinsic_load_const_ir3', + 268: 'nir_intrinsic_load_constant', + 269: 'nir_intrinsic_load_constant_agx', + 270: 'nir_intrinsic_load_constant_base_ptr', + 271: 'nir_intrinsic_load_converted_output_pan', + 272: 'nir_intrinsic_load_core_id_agx', + 273: 'nir_intrinsic_load_cull_any_enabled_amd', + 274: 'nir_intrinsic_load_cull_back_face_enabled_amd', + 275: 'nir_intrinsic_load_cull_ccw_amd', + 276: 'nir_intrinsic_load_cull_front_face_enabled_amd', + 277: 'nir_intrinsic_load_cull_line_viewport_xy_scale_and_offset_amd', + 278: 'nir_intrinsic_load_cull_mask', + 279: 'nir_intrinsic_load_cull_mask_and_flags_amd', + 280: 'nir_intrinsic_load_cull_small_line_precision_amd', + 281: 'nir_intrinsic_load_cull_small_lines_enabled_amd', + 282: 'nir_intrinsic_load_cull_small_triangle_precision_amd', + 283: 'nir_intrinsic_load_cull_small_triangles_enabled_amd', + 284: 'nir_intrinsic_load_cull_triangle_viewport_xy_scale_and_offset_amd', + 285: 'nir_intrinsic_load_debug_log_desc_amd', + 286: 'nir_intrinsic_load_depth_never_agx', + 287: 'nir_intrinsic_load_deref', + 288: 'nir_intrinsic_load_deref_block_intel', + 289: 'nir_intrinsic_load_draw_id', + 290: 'nir_intrinsic_load_esgs_vertex_stride_amd', + 291: 'nir_intrinsic_load_exported_agx', + 292: 'nir_intrinsic_load_fb_layers_v3d', + 293: 'nir_intrinsic_load_fbfetch_image_desc_amd', + 294: 'nir_intrinsic_load_fbfetch_image_fmask_desc_amd', + 295: 'nir_intrinsic_load_fep_w_v3d', + 296: 'nir_intrinsic_load_first_vertex', + 297: 'nir_intrinsic_load_fixed_point_size_agx', + 298: 'nir_intrinsic_load_flat_mask', + 299: 'nir_intrinsic_load_force_vrs_rates_amd', + 300: 'nir_intrinsic_load_frag_coord', + 301: 'nir_intrinsic_load_frag_coord_unscaled_ir3', + 302: 'nir_intrinsic_load_frag_coord_w', + 303: 'nir_intrinsic_load_frag_coord_z', + 304: 'nir_intrinsic_load_frag_coord_zw_pan', + 305: 'nir_intrinsic_load_frag_invocation_count', + 306: 'nir_intrinsic_load_frag_offset_ir3', + 307: 'nir_intrinsic_load_frag_shading_rate', + 308: 'nir_intrinsic_load_frag_size', + 309: 'nir_intrinsic_load_frag_size_ir3', + 310: 'nir_intrinsic_load_from_texture_handle_agx', + 311: 'nir_intrinsic_load_front_face', + 312: 'nir_intrinsic_load_front_face_fsign', + 313: 'nir_intrinsic_load_fs_input_interp_deltas', + 314: 'nir_intrinsic_load_fs_msaa_intel', + 315: 'nir_intrinsic_load_fully_covered', + 316: 'nir_intrinsic_load_geometry_param_buffer_poly', + 317: 'nir_intrinsic_load_global', + 318: 'nir_intrinsic_load_global_2x32', + 319: 'nir_intrinsic_load_global_amd', + 320: 'nir_intrinsic_load_global_base_ptr', + 321: 'nir_intrinsic_load_global_block_intel', + 322: 'nir_intrinsic_load_global_bounded', + 323: 'nir_intrinsic_load_global_constant', + 324: 'nir_intrinsic_load_global_constant_bounded', + 325: 'nir_intrinsic_load_global_constant_offset', + 326: 'nir_intrinsic_load_global_constant_uniform_block_intel', + 327: 'nir_intrinsic_load_global_etna', + 328: 'nir_intrinsic_load_global_invocation_id', + 329: 'nir_intrinsic_load_global_invocation_index', + 330: 'nir_intrinsic_load_global_ir3', + 331: 'nir_intrinsic_load_global_size', + 332: 'nir_intrinsic_load_gs_header_ir3', + 333: 'nir_intrinsic_load_gs_vertex_offset_amd', + 334: 'nir_intrinsic_load_gs_wave_id_amd', + 335: 'nir_intrinsic_load_helper_arg_hi_agx', + 336: 'nir_intrinsic_load_helper_arg_lo_agx', + 337: 'nir_intrinsic_load_helper_invocation', + 338: 'nir_intrinsic_load_helper_op_id_agx', + 339: 'nir_intrinsic_load_hit_attrib_amd', + 340: 'nir_intrinsic_load_hs_out_patch_data_offset_amd', + 341: 'nir_intrinsic_load_hs_patch_stride_ir3', + 342: 'nir_intrinsic_load_initial_edgeflags_amd', + 343: 'nir_intrinsic_load_inline_data_intel', + 344: 'nir_intrinsic_load_input', + 345: 'nir_intrinsic_load_input_assembly_buffer_poly', + 346: 'nir_intrinsic_load_input_attachment_conv_pan', + 347: 'nir_intrinsic_load_input_attachment_coord', + 348: 'nir_intrinsic_load_input_attachment_target_pan', + 349: 'nir_intrinsic_load_input_topology_poly', + 350: 'nir_intrinsic_load_input_vertex', + 351: 'nir_intrinsic_load_instance_id', + 352: 'nir_intrinsic_load_interpolated_input', + 353: 'nir_intrinsic_load_intersection_opaque_amd', + 354: 'nir_intrinsic_load_invocation_id', + 355: 'nir_intrinsic_load_is_first_fan_agx', + 356: 'nir_intrinsic_load_is_indexed_draw', + 357: 'nir_intrinsic_load_kernel_input', + 358: 'nir_intrinsic_load_layer_id', + 359: 'nir_intrinsic_load_lds_ngg_gs_out_vertex_base_amd', + 360: 'nir_intrinsic_load_leaf_opaque_intel', + 361: 'nir_intrinsic_load_leaf_procedural_intel', + 362: 'nir_intrinsic_load_line_coord', + 363: 'nir_intrinsic_load_line_width', + 364: 'nir_intrinsic_load_local_invocation_id', + 365: 'nir_intrinsic_load_local_invocation_index', + 366: 'nir_intrinsic_load_local_pixel_agx', + 367: 'nir_intrinsic_load_local_shared_r600', + 368: 'nir_intrinsic_load_lshs_vertex_stride_amd', + 369: 'nir_intrinsic_load_max_polygon_intel', + 370: 'nir_intrinsic_load_merged_wave_info_amd', + 371: 'nir_intrinsic_load_mesh_view_count', + 372: 'nir_intrinsic_load_mesh_view_indices', + 373: 'nir_intrinsic_load_multisampled_pan', + 374: 'nir_intrinsic_load_noperspective_varyings_pan', + 375: 'nir_intrinsic_load_num_subgroups', + 376: 'nir_intrinsic_load_num_vertices', + 377: 'nir_intrinsic_load_num_vertices_per_primitive_amd', + 378: 'nir_intrinsic_load_num_workgroups', + 379: 'nir_intrinsic_load_ordered_id_amd', + 380: 'nir_intrinsic_load_output', + 381: 'nir_intrinsic_load_packed_passthrough_primitive_amd', + 382: 'nir_intrinsic_load_param', + 383: 'nir_intrinsic_load_patch_vertices_in', + 384: 'nir_intrinsic_load_per_primitive_input', + 385: 'nir_intrinsic_load_per_primitive_output', + 386: 'nir_intrinsic_load_per_primitive_remap_intel', + 387: 'nir_intrinsic_load_per_vertex_input', + 388: 'nir_intrinsic_load_per_vertex_output', + 389: 'nir_intrinsic_load_per_view_output', + 390: 'nir_intrinsic_load_persp_center_rhw_ir3', + 391: 'nir_intrinsic_load_pipeline_stat_query_enabled_amd', + 392: 'nir_intrinsic_load_pixel_coord', + 393: 'nir_intrinsic_load_point_coord', + 394: 'nir_intrinsic_load_point_coord_maybe_flipped', + 395: 'nir_intrinsic_load_poly_line_smooth_enabled', + 396: 'nir_intrinsic_load_polygon_stipple_agx', + 397: 'nir_intrinsic_load_polygon_stipple_buffer_amd', + 398: 'nir_intrinsic_load_preamble', + 399: 'nir_intrinsic_load_prim_gen_query_enabled_amd', + 400: 'nir_intrinsic_load_prim_xfb_query_enabled_amd', + 401: 'nir_intrinsic_load_primitive_id', + 402: 'nir_intrinsic_load_primitive_location_ir3', + 403: 'nir_intrinsic_load_printf_buffer_address', + 404: 'nir_intrinsic_load_printf_buffer_size', + 405: 'nir_intrinsic_load_provoking_last', + 406: 'nir_intrinsic_load_provoking_vtx_amd', + 407: 'nir_intrinsic_load_provoking_vtx_in_prim_amd', + 408: 'nir_intrinsic_load_push_constant', + 409: 'nir_intrinsic_load_push_constant_zink', + 410: 'nir_intrinsic_load_r600_indirect_per_vertex_input', + 411: 'nir_intrinsic_load_rasterization_primitive_amd', + 412: 'nir_intrinsic_load_rasterization_samples_amd', + 413: 'nir_intrinsic_load_rasterization_stream', + 414: 'nir_intrinsic_load_raw_output_pan', + 415: 'nir_intrinsic_load_raw_vertex_id_pan', + 416: 'nir_intrinsic_load_raw_vertex_offset_pan', + 417: 'nir_intrinsic_load_ray_base_mem_addr_intel', + 418: 'nir_intrinsic_load_ray_flags', + 419: 'nir_intrinsic_load_ray_geometry_index', + 420: 'nir_intrinsic_load_ray_hit_kind', + 421: 'nir_intrinsic_load_ray_hit_sbt_addr_intel', + 422: 'nir_intrinsic_load_ray_hit_sbt_stride_intel', + 423: 'nir_intrinsic_load_ray_hw_stack_size_intel', + 424: 'nir_intrinsic_load_ray_instance_custom_index', + 425: 'nir_intrinsic_load_ray_launch_id', + 426: 'nir_intrinsic_load_ray_launch_size', + 427: 'nir_intrinsic_load_ray_miss_sbt_addr_intel', + 428: 'nir_intrinsic_load_ray_miss_sbt_stride_intel', + 429: 'nir_intrinsic_load_ray_num_dss_rt_stacks_intel', + 430: 'nir_intrinsic_load_ray_object_direction', + 431: 'nir_intrinsic_load_ray_object_origin', + 432: 'nir_intrinsic_load_ray_object_to_world', + 433: 'nir_intrinsic_load_ray_query_global_intel', + 434: 'nir_intrinsic_load_ray_sw_stack_size_intel', + 435: 'nir_intrinsic_load_ray_t_max', + 436: 'nir_intrinsic_load_ray_t_min', + 437: 'nir_intrinsic_load_ray_tracing_stack_base_lvp', + 438: 'nir_intrinsic_load_ray_triangle_vertex_positions', + 439: 'nir_intrinsic_load_ray_world_direction', + 440: 'nir_intrinsic_load_ray_world_origin', + 441: 'nir_intrinsic_load_ray_world_to_object', + 442: 'nir_intrinsic_load_readonly_output_pan', + 443: 'nir_intrinsic_load_reg', + 444: 'nir_intrinsic_load_reg_indirect', + 445: 'nir_intrinsic_load_rel_patch_id_ir3', + 446: 'nir_intrinsic_load_reloc_const_intel', + 447: 'nir_intrinsic_load_resume_shader_address_amd', + 448: 'nir_intrinsic_load_ring_attr_amd', + 449: 'nir_intrinsic_load_ring_attr_offset_amd', + 450: 'nir_intrinsic_load_ring_es2gs_offset_amd', + 451: 'nir_intrinsic_load_ring_esgs_amd', + 452: 'nir_intrinsic_load_ring_gs2vs_offset_amd', + 453: 'nir_intrinsic_load_ring_gsvs_amd', + 454: 'nir_intrinsic_load_ring_mesh_scratch_amd', + 455: 'nir_intrinsic_load_ring_mesh_scratch_offset_amd', + 456: 'nir_intrinsic_load_ring_task_draw_amd', + 457: 'nir_intrinsic_load_ring_task_payload_amd', + 458: 'nir_intrinsic_load_ring_tess_factors_amd', + 459: 'nir_intrinsic_load_ring_tess_factors_offset_amd', + 460: 'nir_intrinsic_load_ring_tess_offchip_amd', + 461: 'nir_intrinsic_load_ring_tess_offchip_offset_amd', + 462: 'nir_intrinsic_load_root_agx', + 463: 'nir_intrinsic_load_rt_arg_scratch_offset_amd', + 464: 'nir_intrinsic_load_rt_conversion_pan', + 465: 'nir_intrinsic_load_sample_id', + 466: 'nir_intrinsic_load_sample_id_no_per_sample', + 467: 'nir_intrinsic_load_sample_mask', + 468: 'nir_intrinsic_load_sample_mask_in', + 469: 'nir_intrinsic_load_sample_pos', + 470: 'nir_intrinsic_load_sample_pos_from_id', + 471: 'nir_intrinsic_load_sample_pos_or_center', + 472: 'nir_intrinsic_load_sample_positions_agx', + 473: 'nir_intrinsic_load_sample_positions_amd', + 474: 'nir_intrinsic_load_sample_positions_pan', + 475: 'nir_intrinsic_load_sampler_handle_agx', + 476: 'nir_intrinsic_load_sampler_lod_parameters', + 477: 'nir_intrinsic_load_samples_log2_agx', + 478: 'nir_intrinsic_load_sbt_base_amd', + 479: 'nir_intrinsic_load_sbt_offset_amd', + 480: 'nir_intrinsic_load_sbt_stride_amd', + 481: 'nir_intrinsic_load_scalar_arg_amd', + 482: 'nir_intrinsic_load_scratch', + 483: 'nir_intrinsic_load_scratch_base_ptr', + 484: 'nir_intrinsic_load_shader_call_data_offset_lvp', + 485: 'nir_intrinsic_load_shader_index', + 486: 'nir_intrinsic_load_shader_output_pan', + 487: 'nir_intrinsic_load_shader_part_tests_zs_agx', + 488: 'nir_intrinsic_load_shader_record_ptr', + 489: 'nir_intrinsic_load_shared', + 490: 'nir_intrinsic_load_shared2_amd', + 491: 'nir_intrinsic_load_shared_base_ptr', + 492: 'nir_intrinsic_load_shared_block_intel', + 493: 'nir_intrinsic_load_shared_ir3', + 494: 'nir_intrinsic_load_shared_lock_nv', + 495: 'nir_intrinsic_load_shared_uniform_block_intel', + 496: 'nir_intrinsic_load_simd_width_intel', + 497: 'nir_intrinsic_load_sm_count_nv', + 498: 'nir_intrinsic_load_sm_id_nv', + 499: 'nir_intrinsic_load_smem_amd', + 500: 'nir_intrinsic_load_ssbo', + 501: 'nir_intrinsic_load_ssbo_address', + 502: 'nir_intrinsic_load_ssbo_block_intel', + 503: 'nir_intrinsic_load_ssbo_intel', + 504: 'nir_intrinsic_load_ssbo_ir3', + 505: 'nir_intrinsic_load_ssbo_uniform_block_intel', + 506: 'nir_intrinsic_load_stack', + 507: 'nir_intrinsic_load_stat_query_address_agx', + 508: 'nir_intrinsic_load_streamout_buffer_amd', + 509: 'nir_intrinsic_load_streamout_config_amd', + 510: 'nir_intrinsic_load_streamout_offset_amd', + 511: 'nir_intrinsic_load_streamout_write_index_amd', + 512: 'nir_intrinsic_load_subgroup_eq_mask', + 513: 'nir_intrinsic_load_subgroup_ge_mask', + 514: 'nir_intrinsic_load_subgroup_gt_mask', + 515: 'nir_intrinsic_load_subgroup_id', + 516: 'nir_intrinsic_load_subgroup_id_shift_ir3', + 517: 'nir_intrinsic_load_subgroup_invocation', + 518: 'nir_intrinsic_load_subgroup_le_mask', + 519: 'nir_intrinsic_load_subgroup_lt_mask', + 520: 'nir_intrinsic_load_subgroup_size', + 521: 'nir_intrinsic_load_sysval_agx', + 522: 'nir_intrinsic_load_sysval_nv', + 523: 'nir_intrinsic_load_task_payload', + 524: 'nir_intrinsic_load_task_ring_entry_amd', + 525: 'nir_intrinsic_load_tcs_header_ir3', + 526: 'nir_intrinsic_load_tcs_in_param_base_r600', + 527: 'nir_intrinsic_load_tcs_mem_attrib_stride', + 528: 'nir_intrinsic_load_tcs_num_patches_amd', + 529: 'nir_intrinsic_load_tcs_out_param_base_r600', + 530: 'nir_intrinsic_load_tcs_primitive_mode_amd', + 531: 'nir_intrinsic_load_tcs_rel_patch_id_r600', + 532: 'nir_intrinsic_load_tcs_tess_factor_base_r600', + 533: 'nir_intrinsic_load_tcs_tess_levels_to_tes_amd', + 534: 'nir_intrinsic_load_tess_coord', + 535: 'nir_intrinsic_load_tess_coord_xy', + 536: 'nir_intrinsic_load_tess_factor_base_ir3', + 537: 'nir_intrinsic_load_tess_level_inner', + 538: 'nir_intrinsic_load_tess_level_inner_default', + 539: 'nir_intrinsic_load_tess_level_outer', + 540: 'nir_intrinsic_load_tess_level_outer_default', + 541: 'nir_intrinsic_load_tess_param_base_ir3', + 542: 'nir_intrinsic_load_tess_param_buffer_poly', + 543: 'nir_intrinsic_load_tess_rel_patch_id_amd', + 544: 'nir_intrinsic_load_tex_sprite_mask_agx', + 545: 'nir_intrinsic_load_texture_handle_agx', + 546: 'nir_intrinsic_load_texture_scale', + 547: 'nir_intrinsic_load_texture_size_etna', + 548: 'nir_intrinsic_load_tlb_color_brcm', + 549: 'nir_intrinsic_load_topology_id_intel', + 550: 'nir_intrinsic_load_typed_buffer_amd', + 551: 'nir_intrinsic_load_uav_ir3', + 552: 'nir_intrinsic_load_ubo', + 553: 'nir_intrinsic_load_ubo_uniform_block_intel', + 554: 'nir_intrinsic_load_ubo_vec4', + 555: 'nir_intrinsic_load_uniform', + 556: 'nir_intrinsic_load_user_clip_plane', + 557: 'nir_intrinsic_load_user_data_amd', + 558: 'nir_intrinsic_load_uvs_index_agx', + 559: 'nir_intrinsic_load_vbo_base_agx', + 560: 'nir_intrinsic_load_vector_arg_amd', + 561: 'nir_intrinsic_load_vertex_id', + 562: 'nir_intrinsic_load_vertex_id_zero_base', + 563: 'nir_intrinsic_load_view_index', + 564: 'nir_intrinsic_load_viewport_offset', + 565: 'nir_intrinsic_load_viewport_scale', + 566: 'nir_intrinsic_load_viewport_x_offset', + 567: 'nir_intrinsic_load_viewport_x_scale', + 568: 'nir_intrinsic_load_viewport_y_offset', + 569: 'nir_intrinsic_load_viewport_y_scale', + 570: 'nir_intrinsic_load_viewport_z_offset', + 571: 'nir_intrinsic_load_viewport_z_scale', + 572: 'nir_intrinsic_load_vs_output_buffer_poly', + 573: 'nir_intrinsic_load_vs_outputs_poly', + 574: 'nir_intrinsic_load_vs_primitive_stride_ir3', + 575: 'nir_intrinsic_load_vs_vertex_stride_ir3', + 576: 'nir_intrinsic_load_vulkan_descriptor', + 577: 'nir_intrinsic_load_warp_id_nv', + 578: 'nir_intrinsic_load_warps_per_sm_nv', + 579: 'nir_intrinsic_load_work_dim', + 580: 'nir_intrinsic_load_workgroup_id', + 581: 'nir_intrinsic_load_workgroup_index', + 582: 'nir_intrinsic_load_workgroup_num_input_primitives_amd', + 583: 'nir_intrinsic_load_workgroup_num_input_vertices_amd', + 584: 'nir_intrinsic_load_workgroup_size', + 585: 'nir_intrinsic_load_xfb_address', + 586: 'nir_intrinsic_load_xfb_index_buffer', + 587: 'nir_intrinsic_load_xfb_size', + 588: 'nir_intrinsic_load_xfb_state_address_gfx12_amd', + 589: 'nir_intrinsic_masked_swizzle_amd', + 590: 'nir_intrinsic_mbcnt_amd', + 591: 'nir_intrinsic_memcpy_deref', + 592: 'nir_intrinsic_nop', + 593: 'nir_intrinsic_nop_amd', + 594: 'nir_intrinsic_optimization_barrier_sgpr_amd', + 595: 'nir_intrinsic_optimization_barrier_vgpr_amd', + 596: 'nir_intrinsic_ordered_add_loop_gfx12_amd', + 597: 'nir_intrinsic_ordered_xfb_counter_add_gfx11_amd', + 598: 'nir_intrinsic_overwrite_tes_arguments_amd', + 599: 'nir_intrinsic_overwrite_vs_arguments_amd', + 600: 'nir_intrinsic_pin_cx_handle_nv', + 601: 'nir_intrinsic_preamble_end_ir3', + 602: 'nir_intrinsic_preamble_start_ir3', + 603: 'nir_intrinsic_prefetch_sam_ir3', + 604: 'nir_intrinsic_prefetch_tex_ir3', + 605: 'nir_intrinsic_prefetch_ubo_ir3', + 606: 'nir_intrinsic_printf', + 607: 'nir_intrinsic_printf_abort', + 608: 'nir_intrinsic_quad_ballot_agx', + 609: 'nir_intrinsic_quad_broadcast', + 610: 'nir_intrinsic_quad_swap_diagonal', + 611: 'nir_intrinsic_quad_swap_horizontal', + 612: 'nir_intrinsic_quad_swap_vertical', + 613: 'nir_intrinsic_quad_swizzle_amd', + 614: 'nir_intrinsic_quad_vote_all', + 615: 'nir_intrinsic_quad_vote_any', + 616: 'nir_intrinsic_r600_indirect_vertex_at_index', + 617: 'nir_intrinsic_ray_intersection_ir3', + 618: 'nir_intrinsic_read_attribute_payload_intel', + 619: 'nir_intrinsic_read_first_invocation', + 620: 'nir_intrinsic_read_getlast_ir3', + 621: 'nir_intrinsic_read_invocation', + 622: 'nir_intrinsic_read_invocation_cond_ir3', + 623: 'nir_intrinsic_reduce', + 624: 'nir_intrinsic_reduce_clusters_ir3', + 625: 'nir_intrinsic_report_ray_intersection', + 626: 'nir_intrinsic_resource_intel', + 627: 'nir_intrinsic_rotate', + 628: 'nir_intrinsic_rq_confirm_intersection', + 629: 'nir_intrinsic_rq_generate_intersection', + 630: 'nir_intrinsic_rq_initialize', + 631: 'nir_intrinsic_rq_load', + 632: 'nir_intrinsic_rq_proceed', + 633: 'nir_intrinsic_rq_terminate', + 634: 'nir_intrinsic_rt_execute_callable', + 635: 'nir_intrinsic_rt_resume', + 636: 'nir_intrinsic_rt_return_amd', + 637: 'nir_intrinsic_rt_trace_ray', + 638: 'nir_intrinsic_sample_mask_agx', + 639: 'nir_intrinsic_select_vertex_poly', + 640: 'nir_intrinsic_sendmsg_amd', + 641: 'nir_intrinsic_set_vertex_and_primitive_count', + 642: 'nir_intrinsic_shader_clock', + 643: 'nir_intrinsic_shared_append_amd', + 644: 'nir_intrinsic_shared_atomic', + 645: 'nir_intrinsic_shared_atomic_swap', + 646: 'nir_intrinsic_shared_consume_amd', + 647: 'nir_intrinsic_shuffle', + 648: 'nir_intrinsic_shuffle_down', + 649: 'nir_intrinsic_shuffle_down_uniform_ir3', + 650: 'nir_intrinsic_shuffle_up', + 651: 'nir_intrinsic_shuffle_up_uniform_ir3', + 652: 'nir_intrinsic_shuffle_xor', + 653: 'nir_intrinsic_shuffle_xor_uniform_ir3', + 654: 'nir_intrinsic_sleep_amd', + 655: 'nir_intrinsic_sparse_residency_code_and', + 656: 'nir_intrinsic_ssa_bar_nv', + 657: 'nir_intrinsic_ssbo_atomic', + 658: 'nir_intrinsic_ssbo_atomic_ir3', + 659: 'nir_intrinsic_ssbo_atomic_swap', + 660: 'nir_intrinsic_ssbo_atomic_swap_ir3', + 661: 'nir_intrinsic_stack_map_agx', + 662: 'nir_intrinsic_stack_unmap_agx', + 663: 'nir_intrinsic_store_agx', + 664: 'nir_intrinsic_store_buffer_amd', + 665: 'nir_intrinsic_store_combined_output_pan', + 666: 'nir_intrinsic_store_const_ir3', + 667: 'nir_intrinsic_store_deref', + 668: 'nir_intrinsic_store_deref_block_intel', + 669: 'nir_intrinsic_store_global', + 670: 'nir_intrinsic_store_global_2x32', + 671: 'nir_intrinsic_store_global_amd', + 672: 'nir_intrinsic_store_global_block_intel', + 673: 'nir_intrinsic_store_global_etna', + 674: 'nir_intrinsic_store_global_ir3', + 675: 'nir_intrinsic_store_hit_attrib_amd', + 676: 'nir_intrinsic_store_local_pixel_agx', + 677: 'nir_intrinsic_store_local_shared_r600', + 678: 'nir_intrinsic_store_output', + 679: 'nir_intrinsic_store_per_primitive_output', + 680: 'nir_intrinsic_store_per_primitive_payload_intel', + 681: 'nir_intrinsic_store_per_vertex_output', + 682: 'nir_intrinsic_store_per_view_output', + 683: 'nir_intrinsic_store_preamble', + 684: 'nir_intrinsic_store_raw_output_pan', + 685: 'nir_intrinsic_store_reg', + 686: 'nir_intrinsic_store_reg_indirect', + 687: 'nir_intrinsic_store_scalar_arg_amd', + 688: 'nir_intrinsic_store_scratch', + 689: 'nir_intrinsic_store_shared', + 690: 'nir_intrinsic_store_shared2_amd', + 691: 'nir_intrinsic_store_shared_block_intel', + 692: 'nir_intrinsic_store_shared_ir3', + 693: 'nir_intrinsic_store_shared_unlock_nv', + 694: 'nir_intrinsic_store_ssbo', + 695: 'nir_intrinsic_store_ssbo_block_intel', + 696: 'nir_intrinsic_store_ssbo_intel', + 697: 'nir_intrinsic_store_ssbo_ir3', + 698: 'nir_intrinsic_store_stack', + 699: 'nir_intrinsic_store_task_payload', + 700: 'nir_intrinsic_store_tf_r600', + 701: 'nir_intrinsic_store_tlb_sample_color_v3d', + 702: 'nir_intrinsic_store_uvs_agx', + 703: 'nir_intrinsic_store_vector_arg_amd', + 704: 'nir_intrinsic_store_zs_agx', + 705: 'nir_intrinsic_strict_wqm_coord_amd', + 706: 'nir_intrinsic_subfm_nv', + 707: 'nir_intrinsic_suclamp_nv', + 708: 'nir_intrinsic_sueau_nv', + 709: 'nir_intrinsic_suldga_nv', + 710: 'nir_intrinsic_sustga_nv', + 711: 'nir_intrinsic_task_payload_atomic', + 712: 'nir_intrinsic_task_payload_atomic_swap', + 713: 'nir_intrinsic_terminate', + 714: 'nir_intrinsic_terminate_if', + 715: 'nir_intrinsic_terminate_ray', + 716: 'nir_intrinsic_trace_ray', + 717: 'nir_intrinsic_trace_ray_intel', + 718: 'nir_intrinsic_unit_test_amd', + 719: 'nir_intrinsic_unit_test_divergent_amd', + 720: 'nir_intrinsic_unit_test_uniform_amd', + 721: 'nir_intrinsic_unpin_cx_handle_nv', + 722: 'nir_intrinsic_use', + 723: 'nir_intrinsic_vild_nv', + 724: 'nir_intrinsic_vote_all', + 725: 'nir_intrinsic_vote_any', + 726: 'nir_intrinsic_vote_feq', + 727: 'nir_intrinsic_vote_ieq', + 728: 'nir_intrinsic_vulkan_resource_index', + 729: 'nir_intrinsic_vulkan_resource_reindex', + 730: 'nir_intrinsic_write_invocation_amd', + 731: 'nir_intrinsic_xfb_counter_sub_gfx11_amd', + 731: 'nir_last_intrinsic', + 732: 'nir_num_intrinsics', +} +nir_intrinsic_accept_ray_intersection = 0 +nir_intrinsic_addr_mode_is = 1 +nir_intrinsic_al2p_nv = 2 +nir_intrinsic_ald_nv = 3 +nir_intrinsic_alpha_to_coverage = 4 +nir_intrinsic_as_uniform = 5 +nir_intrinsic_ast_nv = 6 +nir_intrinsic_atomic_add_gen_prim_count_amd = 7 +nir_intrinsic_atomic_add_gs_emit_prim_count_amd = 8 +nir_intrinsic_atomic_add_shader_invocation_count_amd = 9 +nir_intrinsic_atomic_add_xfb_prim_count_amd = 10 +nir_intrinsic_atomic_counter_add = 11 +nir_intrinsic_atomic_counter_add_deref = 12 +nir_intrinsic_atomic_counter_and = 13 +nir_intrinsic_atomic_counter_and_deref = 14 +nir_intrinsic_atomic_counter_comp_swap = 15 +nir_intrinsic_atomic_counter_comp_swap_deref = 16 +nir_intrinsic_atomic_counter_exchange = 17 +nir_intrinsic_atomic_counter_exchange_deref = 18 +nir_intrinsic_atomic_counter_inc = 19 +nir_intrinsic_atomic_counter_inc_deref = 20 +nir_intrinsic_atomic_counter_max = 21 +nir_intrinsic_atomic_counter_max_deref = 22 +nir_intrinsic_atomic_counter_min = 23 +nir_intrinsic_atomic_counter_min_deref = 24 +nir_intrinsic_atomic_counter_or = 25 +nir_intrinsic_atomic_counter_or_deref = 26 +nir_intrinsic_atomic_counter_post_dec = 27 +nir_intrinsic_atomic_counter_post_dec_deref = 28 +nir_intrinsic_atomic_counter_pre_dec = 29 +nir_intrinsic_atomic_counter_pre_dec_deref = 30 +nir_intrinsic_atomic_counter_read = 31 +nir_intrinsic_atomic_counter_read_deref = 32 +nir_intrinsic_atomic_counter_xor = 33 +nir_intrinsic_atomic_counter_xor_deref = 34 +nir_intrinsic_ballot = 35 +nir_intrinsic_ballot_bit_count_exclusive = 36 +nir_intrinsic_ballot_bit_count_inclusive = 37 +nir_intrinsic_ballot_bit_count_reduce = 38 +nir_intrinsic_ballot_bitfield_extract = 39 +nir_intrinsic_ballot_find_lsb = 40 +nir_intrinsic_ballot_find_msb = 41 +nir_intrinsic_ballot_relaxed = 42 +nir_intrinsic_bar_break_nv = 43 +nir_intrinsic_bar_set_nv = 44 +nir_intrinsic_bar_sync_nv = 45 +nir_intrinsic_barrier = 46 +nir_intrinsic_begin_invocation_interlock = 47 +nir_intrinsic_bindgen_return = 48 +nir_intrinsic_bindless_image_agx = 49 +nir_intrinsic_bindless_image_atomic = 50 +nir_intrinsic_bindless_image_atomic_swap = 51 +nir_intrinsic_bindless_image_descriptor_amd = 52 +nir_intrinsic_bindless_image_format = 53 +nir_intrinsic_bindless_image_fragment_mask_load_amd = 54 +nir_intrinsic_bindless_image_levels = 55 +nir_intrinsic_bindless_image_load = 56 +nir_intrinsic_bindless_image_load_raw_intel = 57 +nir_intrinsic_bindless_image_order = 58 +nir_intrinsic_bindless_image_samples = 59 +nir_intrinsic_bindless_image_samples_identical = 60 +nir_intrinsic_bindless_image_size = 61 +nir_intrinsic_bindless_image_sparse_load = 62 +nir_intrinsic_bindless_image_store = 63 +nir_intrinsic_bindless_image_store_block_agx = 64 +nir_intrinsic_bindless_image_store_raw_intel = 65 +nir_intrinsic_bindless_image_texel_address = 66 +nir_intrinsic_bindless_resource_ir3 = 67 +nir_intrinsic_brcst_active_ir3 = 68 +nir_intrinsic_btd_retire_intel = 69 +nir_intrinsic_btd_spawn_intel = 70 +nir_intrinsic_btd_stack_push_intel = 71 +nir_intrinsic_bvh64_intersect_ray_amd = 72 +nir_intrinsic_bvh8_intersect_ray_amd = 73 +nir_intrinsic_bvh_stack_rtn_amd = 74 +nir_intrinsic_cmat_binary_op = 75 +nir_intrinsic_cmat_bitcast = 76 +nir_intrinsic_cmat_construct = 77 +nir_intrinsic_cmat_convert = 78 +nir_intrinsic_cmat_copy = 79 +nir_intrinsic_cmat_extract = 80 +nir_intrinsic_cmat_insert = 81 +nir_intrinsic_cmat_length = 82 +nir_intrinsic_cmat_load = 83 +nir_intrinsic_cmat_muladd = 84 +nir_intrinsic_cmat_muladd_amd = 85 +nir_intrinsic_cmat_muladd_nv = 86 +nir_intrinsic_cmat_scalar_op = 87 +nir_intrinsic_cmat_store = 88 +nir_intrinsic_cmat_transpose = 89 +nir_intrinsic_cmat_unary_op = 90 +nir_intrinsic_convert_alu_types = 91 +nir_intrinsic_convert_cmat_intel = 92 +nir_intrinsic_copy_deref = 93 +nir_intrinsic_copy_fs_outputs_nv = 94 +nir_intrinsic_copy_global_to_uniform_ir3 = 95 +nir_intrinsic_copy_push_const_to_uniform_ir3 = 96 +nir_intrinsic_copy_ubo_to_uniform_ir3 = 97 +nir_intrinsic_ddx = 98 +nir_intrinsic_ddx_coarse = 99 +nir_intrinsic_ddx_fine = 100 +nir_intrinsic_ddy = 101 +nir_intrinsic_ddy_coarse = 102 +nir_intrinsic_ddy_fine = 103 +nir_intrinsic_debug_break = 104 +nir_intrinsic_decl_reg = 105 +nir_intrinsic_demote = 106 +nir_intrinsic_demote_if = 107 +nir_intrinsic_demote_samples = 108 +nir_intrinsic_deref_atomic = 109 +nir_intrinsic_deref_atomic_swap = 110 +nir_intrinsic_deref_buffer_array_length = 111 +nir_intrinsic_deref_implicit_array_length = 112 +nir_intrinsic_deref_mode_is = 113 +nir_intrinsic_deref_texture_src = 114 +nir_intrinsic_doorbell_agx = 115 +nir_intrinsic_dpas_intel = 116 +nir_intrinsic_dpp16_shift_amd = 117 +nir_intrinsic_elect = 118 +nir_intrinsic_elect_any_ir3 = 119 +nir_intrinsic_emit_primitive_poly = 120 +nir_intrinsic_emit_vertex = 121 +nir_intrinsic_emit_vertex_nv = 122 +nir_intrinsic_emit_vertex_with_counter = 123 +nir_intrinsic_end_invocation_interlock = 124 +nir_intrinsic_end_primitive = 125 +nir_intrinsic_end_primitive_nv = 126 +nir_intrinsic_end_primitive_with_counter = 127 +nir_intrinsic_enqueue_node_payloads = 128 +nir_intrinsic_exclusive_scan = 129 +nir_intrinsic_exclusive_scan_clusters_ir3 = 130 +nir_intrinsic_execute_callable = 131 +nir_intrinsic_execute_closest_hit_amd = 132 +nir_intrinsic_execute_miss_amd = 133 +nir_intrinsic_export_agx = 134 +nir_intrinsic_export_amd = 135 +nir_intrinsic_export_dual_src_blend_amd = 136 +nir_intrinsic_export_row_amd = 137 +nir_intrinsic_fence_helper_exit_agx = 138 +nir_intrinsic_fence_mem_to_tex_agx = 139 +nir_intrinsic_fence_pbe_to_tex_agx = 140 +nir_intrinsic_fence_pbe_to_tex_pixel_agx = 141 +nir_intrinsic_final_primitive_nv = 142 +nir_intrinsic_finalize_incoming_node_payload = 143 +nir_intrinsic_first_invocation = 144 +nir_intrinsic_fs_out_nv = 145 +nir_intrinsic_gds_atomic_add_amd = 146 +nir_intrinsic_get_ssbo_size = 147 +nir_intrinsic_get_ubo_size = 148 +nir_intrinsic_global_atomic = 149 +nir_intrinsic_global_atomic_2x32 = 150 +nir_intrinsic_global_atomic_agx = 151 +nir_intrinsic_global_atomic_amd = 152 +nir_intrinsic_global_atomic_swap = 153 +nir_intrinsic_global_atomic_swap_2x32 = 154 +nir_intrinsic_global_atomic_swap_agx = 155 +nir_intrinsic_global_atomic_swap_amd = 156 +nir_intrinsic_ignore_ray_intersection = 157 +nir_intrinsic_imadsp_nv = 158 +nir_intrinsic_image_atomic = 159 +nir_intrinsic_image_atomic_swap = 160 +nir_intrinsic_image_deref_atomic = 161 +nir_intrinsic_image_deref_atomic_swap = 162 +nir_intrinsic_image_deref_descriptor_amd = 163 +nir_intrinsic_image_deref_format = 164 +nir_intrinsic_image_deref_fragment_mask_load_amd = 165 +nir_intrinsic_image_deref_levels = 166 +nir_intrinsic_image_deref_load = 167 +nir_intrinsic_image_deref_load_info_nv = 168 +nir_intrinsic_image_deref_load_param_intel = 169 +nir_intrinsic_image_deref_load_raw_intel = 170 +nir_intrinsic_image_deref_order = 171 +nir_intrinsic_image_deref_samples = 172 +nir_intrinsic_image_deref_samples_identical = 173 +nir_intrinsic_image_deref_size = 174 +nir_intrinsic_image_deref_sparse_load = 175 +nir_intrinsic_image_deref_store = 176 +nir_intrinsic_image_deref_store_block_agx = 177 +nir_intrinsic_image_deref_store_raw_intel = 178 +nir_intrinsic_image_deref_texel_address = 179 +nir_intrinsic_image_descriptor_amd = 180 +nir_intrinsic_image_format = 181 +nir_intrinsic_image_fragment_mask_load_amd = 182 +nir_intrinsic_image_levels = 183 +nir_intrinsic_image_load = 184 +nir_intrinsic_image_load_raw_intel = 185 +nir_intrinsic_image_order = 186 +nir_intrinsic_image_samples = 187 +nir_intrinsic_image_samples_identical = 188 +nir_intrinsic_image_size = 189 +nir_intrinsic_image_sparse_load = 190 +nir_intrinsic_image_store = 191 +nir_intrinsic_image_store_block_agx = 192 +nir_intrinsic_image_store_raw_intel = 193 +nir_intrinsic_image_texel_address = 194 +nir_intrinsic_inclusive_scan = 195 +nir_intrinsic_inclusive_scan_clusters_ir3 = 196 +nir_intrinsic_initialize_node_payloads = 197 +nir_intrinsic_interp_deref_at_centroid = 198 +nir_intrinsic_interp_deref_at_offset = 199 +nir_intrinsic_interp_deref_at_sample = 200 +nir_intrinsic_interp_deref_at_vertex = 201 +nir_intrinsic_inverse_ballot = 202 +nir_intrinsic_ipa_nv = 203 +nir_intrinsic_is_helper_invocation = 204 +nir_intrinsic_is_sparse_resident_zink = 205 +nir_intrinsic_is_sparse_texels_resident = 206 +nir_intrinsic_is_subgroup_invocation_lt_amd = 207 +nir_intrinsic_isberd_nv = 208 +nir_intrinsic_lane_permute_16_amd = 209 +nir_intrinsic_last_invocation = 210 +nir_intrinsic_launch_mesh_workgroups = 211 +nir_intrinsic_launch_mesh_workgroups_with_payload_deref = 212 +nir_intrinsic_ldc_nv = 213 +nir_intrinsic_ldcx_nv = 214 +nir_intrinsic_ldtram_nv = 215 +nir_intrinsic_load_aa_line_width = 216 +nir_intrinsic_load_accel_struct_amd = 217 +nir_intrinsic_load_active_samples_agx = 218 +nir_intrinsic_load_active_subgroup_count_agx = 219 +nir_intrinsic_load_active_subgroup_invocation_agx = 220 +nir_intrinsic_load_agx = 221 +nir_intrinsic_load_alpha_reference_amd = 222 +nir_intrinsic_load_api_sample_mask_agx = 223 +nir_intrinsic_load_attrib_clamp_agx = 224 +nir_intrinsic_load_attribute_pan = 225 +nir_intrinsic_load_back_face_agx = 226 +nir_intrinsic_load_barycentric_at_offset = 227 +nir_intrinsic_load_barycentric_at_offset_nv = 228 +nir_intrinsic_load_barycentric_at_sample = 229 +nir_intrinsic_load_barycentric_centroid = 230 +nir_intrinsic_load_barycentric_coord_at_offset = 231 +nir_intrinsic_load_barycentric_coord_at_sample = 232 +nir_intrinsic_load_barycentric_coord_centroid = 233 +nir_intrinsic_load_barycentric_coord_pixel = 234 +nir_intrinsic_load_barycentric_coord_sample = 235 +nir_intrinsic_load_barycentric_model = 236 +nir_intrinsic_load_barycentric_optimize_amd = 237 +nir_intrinsic_load_barycentric_pixel = 238 +nir_intrinsic_load_barycentric_sample = 239 +nir_intrinsic_load_base_global_invocation_id = 240 +nir_intrinsic_load_base_instance = 241 +nir_intrinsic_load_base_vertex = 242 +nir_intrinsic_load_base_workgroup_id = 243 +nir_intrinsic_load_blend_const_color_a_float = 244 +nir_intrinsic_load_blend_const_color_aaaa8888_unorm = 245 +nir_intrinsic_load_blend_const_color_b_float = 246 +nir_intrinsic_load_blend_const_color_g_float = 247 +nir_intrinsic_load_blend_const_color_r_float = 248 +nir_intrinsic_load_blend_const_color_rgba = 249 +nir_intrinsic_load_blend_const_color_rgba8888_unorm = 250 +nir_intrinsic_load_btd_global_arg_addr_intel = 251 +nir_intrinsic_load_btd_local_arg_addr_intel = 252 +nir_intrinsic_load_btd_resume_sbt_addr_intel = 253 +nir_intrinsic_load_btd_shader_type_intel = 254 +nir_intrinsic_load_btd_stack_id_intel = 255 +nir_intrinsic_load_buffer_amd = 256 +nir_intrinsic_load_callable_sbt_addr_intel = 257 +nir_intrinsic_load_callable_sbt_stride_intel = 258 +nir_intrinsic_load_clamp_vertex_color_amd = 259 +nir_intrinsic_load_clip_half_line_width_amd = 260 +nir_intrinsic_load_clip_z_coeff_agx = 261 +nir_intrinsic_load_coalesced_input_count = 262 +nir_intrinsic_load_coefficients_agx = 263 +nir_intrinsic_load_color0 = 264 +nir_intrinsic_load_color1 = 265 +nir_intrinsic_load_const_buf_base_addr_lvp = 266 +nir_intrinsic_load_const_ir3 = 267 +nir_intrinsic_load_constant = 268 +nir_intrinsic_load_constant_agx = 269 +nir_intrinsic_load_constant_base_ptr = 270 +nir_intrinsic_load_converted_output_pan = 271 +nir_intrinsic_load_core_id_agx = 272 +nir_intrinsic_load_cull_any_enabled_amd = 273 +nir_intrinsic_load_cull_back_face_enabled_amd = 274 +nir_intrinsic_load_cull_ccw_amd = 275 +nir_intrinsic_load_cull_front_face_enabled_amd = 276 +nir_intrinsic_load_cull_line_viewport_xy_scale_and_offset_amd = 277 +nir_intrinsic_load_cull_mask = 278 +nir_intrinsic_load_cull_mask_and_flags_amd = 279 +nir_intrinsic_load_cull_small_line_precision_amd = 280 +nir_intrinsic_load_cull_small_lines_enabled_amd = 281 +nir_intrinsic_load_cull_small_triangle_precision_amd = 282 +nir_intrinsic_load_cull_small_triangles_enabled_amd = 283 +nir_intrinsic_load_cull_triangle_viewport_xy_scale_and_offset_amd = 284 +nir_intrinsic_load_debug_log_desc_amd = 285 +nir_intrinsic_load_depth_never_agx = 286 +nir_intrinsic_load_deref = 287 +nir_intrinsic_load_deref_block_intel = 288 +nir_intrinsic_load_draw_id = 289 +nir_intrinsic_load_esgs_vertex_stride_amd = 290 +nir_intrinsic_load_exported_agx = 291 +nir_intrinsic_load_fb_layers_v3d = 292 +nir_intrinsic_load_fbfetch_image_desc_amd = 293 +nir_intrinsic_load_fbfetch_image_fmask_desc_amd = 294 +nir_intrinsic_load_fep_w_v3d = 295 +nir_intrinsic_load_first_vertex = 296 +nir_intrinsic_load_fixed_point_size_agx = 297 +nir_intrinsic_load_flat_mask = 298 +nir_intrinsic_load_force_vrs_rates_amd = 299 +nir_intrinsic_load_frag_coord = 300 +nir_intrinsic_load_frag_coord_unscaled_ir3 = 301 +nir_intrinsic_load_frag_coord_w = 302 +nir_intrinsic_load_frag_coord_z = 303 +nir_intrinsic_load_frag_coord_zw_pan = 304 +nir_intrinsic_load_frag_invocation_count = 305 +nir_intrinsic_load_frag_offset_ir3 = 306 +nir_intrinsic_load_frag_shading_rate = 307 +nir_intrinsic_load_frag_size = 308 +nir_intrinsic_load_frag_size_ir3 = 309 +nir_intrinsic_load_from_texture_handle_agx = 310 +nir_intrinsic_load_front_face = 311 +nir_intrinsic_load_front_face_fsign = 312 +nir_intrinsic_load_fs_input_interp_deltas = 313 +nir_intrinsic_load_fs_msaa_intel = 314 +nir_intrinsic_load_fully_covered = 315 +nir_intrinsic_load_geometry_param_buffer_poly = 316 +nir_intrinsic_load_global = 317 +nir_intrinsic_load_global_2x32 = 318 +nir_intrinsic_load_global_amd = 319 +nir_intrinsic_load_global_base_ptr = 320 +nir_intrinsic_load_global_block_intel = 321 +nir_intrinsic_load_global_bounded = 322 +nir_intrinsic_load_global_constant = 323 +nir_intrinsic_load_global_constant_bounded = 324 +nir_intrinsic_load_global_constant_offset = 325 +nir_intrinsic_load_global_constant_uniform_block_intel = 326 +nir_intrinsic_load_global_etna = 327 +nir_intrinsic_load_global_invocation_id = 328 +nir_intrinsic_load_global_invocation_index = 329 +nir_intrinsic_load_global_ir3 = 330 +nir_intrinsic_load_global_size = 331 +nir_intrinsic_load_gs_header_ir3 = 332 +nir_intrinsic_load_gs_vertex_offset_amd = 333 +nir_intrinsic_load_gs_wave_id_amd = 334 +nir_intrinsic_load_helper_arg_hi_agx = 335 +nir_intrinsic_load_helper_arg_lo_agx = 336 +nir_intrinsic_load_helper_invocation = 337 +nir_intrinsic_load_helper_op_id_agx = 338 +nir_intrinsic_load_hit_attrib_amd = 339 +nir_intrinsic_load_hs_out_patch_data_offset_amd = 340 +nir_intrinsic_load_hs_patch_stride_ir3 = 341 +nir_intrinsic_load_initial_edgeflags_amd = 342 +nir_intrinsic_load_inline_data_intel = 343 +nir_intrinsic_load_input = 344 +nir_intrinsic_load_input_assembly_buffer_poly = 345 +nir_intrinsic_load_input_attachment_conv_pan = 346 +nir_intrinsic_load_input_attachment_coord = 347 +nir_intrinsic_load_input_attachment_target_pan = 348 +nir_intrinsic_load_input_topology_poly = 349 +nir_intrinsic_load_input_vertex = 350 +nir_intrinsic_load_instance_id = 351 +nir_intrinsic_load_interpolated_input = 352 +nir_intrinsic_load_intersection_opaque_amd = 353 +nir_intrinsic_load_invocation_id = 354 +nir_intrinsic_load_is_first_fan_agx = 355 +nir_intrinsic_load_is_indexed_draw = 356 +nir_intrinsic_load_kernel_input = 357 +nir_intrinsic_load_layer_id = 358 +nir_intrinsic_load_lds_ngg_gs_out_vertex_base_amd = 359 +nir_intrinsic_load_leaf_opaque_intel = 360 +nir_intrinsic_load_leaf_procedural_intel = 361 +nir_intrinsic_load_line_coord = 362 +nir_intrinsic_load_line_width = 363 +nir_intrinsic_load_local_invocation_id = 364 +nir_intrinsic_load_local_invocation_index = 365 +nir_intrinsic_load_local_pixel_agx = 366 +nir_intrinsic_load_local_shared_r600 = 367 +nir_intrinsic_load_lshs_vertex_stride_amd = 368 +nir_intrinsic_load_max_polygon_intel = 369 +nir_intrinsic_load_merged_wave_info_amd = 370 +nir_intrinsic_load_mesh_view_count = 371 +nir_intrinsic_load_mesh_view_indices = 372 +nir_intrinsic_load_multisampled_pan = 373 +nir_intrinsic_load_noperspective_varyings_pan = 374 +nir_intrinsic_load_num_subgroups = 375 +nir_intrinsic_load_num_vertices = 376 +nir_intrinsic_load_num_vertices_per_primitive_amd = 377 +nir_intrinsic_load_num_workgroups = 378 +nir_intrinsic_load_ordered_id_amd = 379 +nir_intrinsic_load_output = 380 +nir_intrinsic_load_packed_passthrough_primitive_amd = 381 +nir_intrinsic_load_param = 382 +nir_intrinsic_load_patch_vertices_in = 383 +nir_intrinsic_load_per_primitive_input = 384 +nir_intrinsic_load_per_primitive_output = 385 +nir_intrinsic_load_per_primitive_remap_intel = 386 +nir_intrinsic_load_per_vertex_input = 387 +nir_intrinsic_load_per_vertex_output = 388 +nir_intrinsic_load_per_view_output = 389 +nir_intrinsic_load_persp_center_rhw_ir3 = 390 +nir_intrinsic_load_pipeline_stat_query_enabled_amd = 391 +nir_intrinsic_load_pixel_coord = 392 +nir_intrinsic_load_point_coord = 393 +nir_intrinsic_load_point_coord_maybe_flipped = 394 +nir_intrinsic_load_poly_line_smooth_enabled = 395 +nir_intrinsic_load_polygon_stipple_agx = 396 +nir_intrinsic_load_polygon_stipple_buffer_amd = 397 +nir_intrinsic_load_preamble = 398 +nir_intrinsic_load_prim_gen_query_enabled_amd = 399 +nir_intrinsic_load_prim_xfb_query_enabled_amd = 400 +nir_intrinsic_load_primitive_id = 401 +nir_intrinsic_load_primitive_location_ir3 = 402 +nir_intrinsic_load_printf_buffer_address = 403 +nir_intrinsic_load_printf_buffer_size = 404 +nir_intrinsic_load_provoking_last = 405 +nir_intrinsic_load_provoking_vtx_amd = 406 +nir_intrinsic_load_provoking_vtx_in_prim_amd = 407 +nir_intrinsic_load_push_constant = 408 +nir_intrinsic_load_push_constant_zink = 409 +nir_intrinsic_load_r600_indirect_per_vertex_input = 410 +nir_intrinsic_load_rasterization_primitive_amd = 411 +nir_intrinsic_load_rasterization_samples_amd = 412 +nir_intrinsic_load_rasterization_stream = 413 +nir_intrinsic_load_raw_output_pan = 414 +nir_intrinsic_load_raw_vertex_id_pan = 415 +nir_intrinsic_load_raw_vertex_offset_pan = 416 +nir_intrinsic_load_ray_base_mem_addr_intel = 417 +nir_intrinsic_load_ray_flags = 418 +nir_intrinsic_load_ray_geometry_index = 419 +nir_intrinsic_load_ray_hit_kind = 420 +nir_intrinsic_load_ray_hit_sbt_addr_intel = 421 +nir_intrinsic_load_ray_hit_sbt_stride_intel = 422 +nir_intrinsic_load_ray_hw_stack_size_intel = 423 +nir_intrinsic_load_ray_instance_custom_index = 424 +nir_intrinsic_load_ray_launch_id = 425 +nir_intrinsic_load_ray_launch_size = 426 +nir_intrinsic_load_ray_miss_sbt_addr_intel = 427 +nir_intrinsic_load_ray_miss_sbt_stride_intel = 428 +nir_intrinsic_load_ray_num_dss_rt_stacks_intel = 429 +nir_intrinsic_load_ray_object_direction = 430 +nir_intrinsic_load_ray_object_origin = 431 +nir_intrinsic_load_ray_object_to_world = 432 +nir_intrinsic_load_ray_query_global_intel = 433 +nir_intrinsic_load_ray_sw_stack_size_intel = 434 +nir_intrinsic_load_ray_t_max = 435 +nir_intrinsic_load_ray_t_min = 436 +nir_intrinsic_load_ray_tracing_stack_base_lvp = 437 +nir_intrinsic_load_ray_triangle_vertex_positions = 438 +nir_intrinsic_load_ray_world_direction = 439 +nir_intrinsic_load_ray_world_origin = 440 +nir_intrinsic_load_ray_world_to_object = 441 +nir_intrinsic_load_readonly_output_pan = 442 +nir_intrinsic_load_reg = 443 +nir_intrinsic_load_reg_indirect = 444 +nir_intrinsic_load_rel_patch_id_ir3 = 445 +nir_intrinsic_load_reloc_const_intel = 446 +nir_intrinsic_load_resume_shader_address_amd = 447 +nir_intrinsic_load_ring_attr_amd = 448 +nir_intrinsic_load_ring_attr_offset_amd = 449 +nir_intrinsic_load_ring_es2gs_offset_amd = 450 +nir_intrinsic_load_ring_esgs_amd = 451 +nir_intrinsic_load_ring_gs2vs_offset_amd = 452 +nir_intrinsic_load_ring_gsvs_amd = 453 +nir_intrinsic_load_ring_mesh_scratch_amd = 454 +nir_intrinsic_load_ring_mesh_scratch_offset_amd = 455 +nir_intrinsic_load_ring_task_draw_amd = 456 +nir_intrinsic_load_ring_task_payload_amd = 457 +nir_intrinsic_load_ring_tess_factors_amd = 458 +nir_intrinsic_load_ring_tess_factors_offset_amd = 459 +nir_intrinsic_load_ring_tess_offchip_amd = 460 +nir_intrinsic_load_ring_tess_offchip_offset_amd = 461 +nir_intrinsic_load_root_agx = 462 +nir_intrinsic_load_rt_arg_scratch_offset_amd = 463 +nir_intrinsic_load_rt_conversion_pan = 464 +nir_intrinsic_load_sample_id = 465 +nir_intrinsic_load_sample_id_no_per_sample = 466 +nir_intrinsic_load_sample_mask = 467 +nir_intrinsic_load_sample_mask_in = 468 +nir_intrinsic_load_sample_pos = 469 +nir_intrinsic_load_sample_pos_from_id = 470 +nir_intrinsic_load_sample_pos_or_center = 471 +nir_intrinsic_load_sample_positions_agx = 472 +nir_intrinsic_load_sample_positions_amd = 473 +nir_intrinsic_load_sample_positions_pan = 474 +nir_intrinsic_load_sampler_handle_agx = 475 +nir_intrinsic_load_sampler_lod_parameters = 476 +nir_intrinsic_load_samples_log2_agx = 477 +nir_intrinsic_load_sbt_base_amd = 478 +nir_intrinsic_load_sbt_offset_amd = 479 +nir_intrinsic_load_sbt_stride_amd = 480 +nir_intrinsic_load_scalar_arg_amd = 481 +nir_intrinsic_load_scratch = 482 +nir_intrinsic_load_scratch_base_ptr = 483 +nir_intrinsic_load_shader_call_data_offset_lvp = 484 +nir_intrinsic_load_shader_index = 485 +nir_intrinsic_load_shader_output_pan = 486 +nir_intrinsic_load_shader_part_tests_zs_agx = 487 +nir_intrinsic_load_shader_record_ptr = 488 +nir_intrinsic_load_shared = 489 +nir_intrinsic_load_shared2_amd = 490 +nir_intrinsic_load_shared_base_ptr = 491 +nir_intrinsic_load_shared_block_intel = 492 +nir_intrinsic_load_shared_ir3 = 493 +nir_intrinsic_load_shared_lock_nv = 494 +nir_intrinsic_load_shared_uniform_block_intel = 495 +nir_intrinsic_load_simd_width_intel = 496 +nir_intrinsic_load_sm_count_nv = 497 +nir_intrinsic_load_sm_id_nv = 498 +nir_intrinsic_load_smem_amd = 499 +nir_intrinsic_load_ssbo = 500 +nir_intrinsic_load_ssbo_address = 501 +nir_intrinsic_load_ssbo_block_intel = 502 +nir_intrinsic_load_ssbo_intel = 503 +nir_intrinsic_load_ssbo_ir3 = 504 +nir_intrinsic_load_ssbo_uniform_block_intel = 505 +nir_intrinsic_load_stack = 506 +nir_intrinsic_load_stat_query_address_agx = 507 +nir_intrinsic_load_streamout_buffer_amd = 508 +nir_intrinsic_load_streamout_config_amd = 509 +nir_intrinsic_load_streamout_offset_amd = 510 +nir_intrinsic_load_streamout_write_index_amd = 511 +nir_intrinsic_load_subgroup_eq_mask = 512 +nir_intrinsic_load_subgroup_ge_mask = 513 +nir_intrinsic_load_subgroup_gt_mask = 514 +nir_intrinsic_load_subgroup_id = 515 +nir_intrinsic_load_subgroup_id_shift_ir3 = 516 +nir_intrinsic_load_subgroup_invocation = 517 +nir_intrinsic_load_subgroup_le_mask = 518 +nir_intrinsic_load_subgroup_lt_mask = 519 +nir_intrinsic_load_subgroup_size = 520 +nir_intrinsic_load_sysval_agx = 521 +nir_intrinsic_load_sysval_nv = 522 +nir_intrinsic_load_task_payload = 523 +nir_intrinsic_load_task_ring_entry_amd = 524 +nir_intrinsic_load_tcs_header_ir3 = 525 +nir_intrinsic_load_tcs_in_param_base_r600 = 526 +nir_intrinsic_load_tcs_mem_attrib_stride = 527 +nir_intrinsic_load_tcs_num_patches_amd = 528 +nir_intrinsic_load_tcs_out_param_base_r600 = 529 +nir_intrinsic_load_tcs_primitive_mode_amd = 530 +nir_intrinsic_load_tcs_rel_patch_id_r600 = 531 +nir_intrinsic_load_tcs_tess_factor_base_r600 = 532 +nir_intrinsic_load_tcs_tess_levels_to_tes_amd = 533 +nir_intrinsic_load_tess_coord = 534 +nir_intrinsic_load_tess_coord_xy = 535 +nir_intrinsic_load_tess_factor_base_ir3 = 536 +nir_intrinsic_load_tess_level_inner = 537 +nir_intrinsic_load_tess_level_inner_default = 538 +nir_intrinsic_load_tess_level_outer = 539 +nir_intrinsic_load_tess_level_outer_default = 540 +nir_intrinsic_load_tess_param_base_ir3 = 541 +nir_intrinsic_load_tess_param_buffer_poly = 542 +nir_intrinsic_load_tess_rel_patch_id_amd = 543 +nir_intrinsic_load_tex_sprite_mask_agx = 544 +nir_intrinsic_load_texture_handle_agx = 545 +nir_intrinsic_load_texture_scale = 546 +nir_intrinsic_load_texture_size_etna = 547 +nir_intrinsic_load_tlb_color_brcm = 548 +nir_intrinsic_load_topology_id_intel = 549 +nir_intrinsic_load_typed_buffer_amd = 550 +nir_intrinsic_load_uav_ir3 = 551 +nir_intrinsic_load_ubo = 552 +nir_intrinsic_load_ubo_uniform_block_intel = 553 +nir_intrinsic_load_ubo_vec4 = 554 +nir_intrinsic_load_uniform = 555 +nir_intrinsic_load_user_clip_plane = 556 +nir_intrinsic_load_user_data_amd = 557 +nir_intrinsic_load_uvs_index_agx = 558 +nir_intrinsic_load_vbo_base_agx = 559 +nir_intrinsic_load_vector_arg_amd = 560 +nir_intrinsic_load_vertex_id = 561 +nir_intrinsic_load_vertex_id_zero_base = 562 +nir_intrinsic_load_view_index = 563 +nir_intrinsic_load_viewport_offset = 564 +nir_intrinsic_load_viewport_scale = 565 +nir_intrinsic_load_viewport_x_offset = 566 +nir_intrinsic_load_viewport_x_scale = 567 +nir_intrinsic_load_viewport_y_offset = 568 +nir_intrinsic_load_viewport_y_scale = 569 +nir_intrinsic_load_viewport_z_offset = 570 +nir_intrinsic_load_viewport_z_scale = 571 +nir_intrinsic_load_vs_output_buffer_poly = 572 +nir_intrinsic_load_vs_outputs_poly = 573 +nir_intrinsic_load_vs_primitive_stride_ir3 = 574 +nir_intrinsic_load_vs_vertex_stride_ir3 = 575 +nir_intrinsic_load_vulkan_descriptor = 576 +nir_intrinsic_load_warp_id_nv = 577 +nir_intrinsic_load_warps_per_sm_nv = 578 +nir_intrinsic_load_work_dim = 579 +nir_intrinsic_load_workgroup_id = 580 +nir_intrinsic_load_workgroup_index = 581 +nir_intrinsic_load_workgroup_num_input_primitives_amd = 582 +nir_intrinsic_load_workgroup_num_input_vertices_amd = 583 +nir_intrinsic_load_workgroup_size = 584 +nir_intrinsic_load_xfb_address = 585 +nir_intrinsic_load_xfb_index_buffer = 586 +nir_intrinsic_load_xfb_size = 587 +nir_intrinsic_load_xfb_state_address_gfx12_amd = 588 +nir_intrinsic_masked_swizzle_amd = 589 +nir_intrinsic_mbcnt_amd = 590 +nir_intrinsic_memcpy_deref = 591 +nir_intrinsic_nop = 592 +nir_intrinsic_nop_amd = 593 +nir_intrinsic_optimization_barrier_sgpr_amd = 594 +nir_intrinsic_optimization_barrier_vgpr_amd = 595 +nir_intrinsic_ordered_add_loop_gfx12_amd = 596 +nir_intrinsic_ordered_xfb_counter_add_gfx11_amd = 597 +nir_intrinsic_overwrite_tes_arguments_amd = 598 +nir_intrinsic_overwrite_vs_arguments_amd = 599 +nir_intrinsic_pin_cx_handle_nv = 600 +nir_intrinsic_preamble_end_ir3 = 601 +nir_intrinsic_preamble_start_ir3 = 602 +nir_intrinsic_prefetch_sam_ir3 = 603 +nir_intrinsic_prefetch_tex_ir3 = 604 +nir_intrinsic_prefetch_ubo_ir3 = 605 +nir_intrinsic_printf = 606 +nir_intrinsic_printf_abort = 607 +nir_intrinsic_quad_ballot_agx = 608 +nir_intrinsic_quad_broadcast = 609 +nir_intrinsic_quad_swap_diagonal = 610 +nir_intrinsic_quad_swap_horizontal = 611 +nir_intrinsic_quad_swap_vertical = 612 +nir_intrinsic_quad_swizzle_amd = 613 +nir_intrinsic_quad_vote_all = 614 +nir_intrinsic_quad_vote_any = 615 +nir_intrinsic_r600_indirect_vertex_at_index = 616 +nir_intrinsic_ray_intersection_ir3 = 617 +nir_intrinsic_read_attribute_payload_intel = 618 +nir_intrinsic_read_first_invocation = 619 +nir_intrinsic_read_getlast_ir3 = 620 +nir_intrinsic_read_invocation = 621 +nir_intrinsic_read_invocation_cond_ir3 = 622 +nir_intrinsic_reduce = 623 +nir_intrinsic_reduce_clusters_ir3 = 624 +nir_intrinsic_report_ray_intersection = 625 +nir_intrinsic_resource_intel = 626 +nir_intrinsic_rotate = 627 +nir_intrinsic_rq_confirm_intersection = 628 +nir_intrinsic_rq_generate_intersection = 629 +nir_intrinsic_rq_initialize = 630 +nir_intrinsic_rq_load = 631 +nir_intrinsic_rq_proceed = 632 +nir_intrinsic_rq_terminate = 633 +nir_intrinsic_rt_execute_callable = 634 +nir_intrinsic_rt_resume = 635 +nir_intrinsic_rt_return_amd = 636 +nir_intrinsic_rt_trace_ray = 637 +nir_intrinsic_sample_mask_agx = 638 +nir_intrinsic_select_vertex_poly = 639 +nir_intrinsic_sendmsg_amd = 640 +nir_intrinsic_set_vertex_and_primitive_count = 641 +nir_intrinsic_shader_clock = 642 +nir_intrinsic_shared_append_amd = 643 +nir_intrinsic_shared_atomic = 644 +nir_intrinsic_shared_atomic_swap = 645 +nir_intrinsic_shared_consume_amd = 646 +nir_intrinsic_shuffle = 647 +nir_intrinsic_shuffle_down = 648 +nir_intrinsic_shuffle_down_uniform_ir3 = 649 +nir_intrinsic_shuffle_up = 650 +nir_intrinsic_shuffle_up_uniform_ir3 = 651 +nir_intrinsic_shuffle_xor = 652 +nir_intrinsic_shuffle_xor_uniform_ir3 = 653 +nir_intrinsic_sleep_amd = 654 +nir_intrinsic_sparse_residency_code_and = 655 +nir_intrinsic_ssa_bar_nv = 656 +nir_intrinsic_ssbo_atomic = 657 +nir_intrinsic_ssbo_atomic_ir3 = 658 +nir_intrinsic_ssbo_atomic_swap = 659 +nir_intrinsic_ssbo_atomic_swap_ir3 = 660 +nir_intrinsic_stack_map_agx = 661 +nir_intrinsic_stack_unmap_agx = 662 +nir_intrinsic_store_agx = 663 +nir_intrinsic_store_buffer_amd = 664 +nir_intrinsic_store_combined_output_pan = 665 +nir_intrinsic_store_const_ir3 = 666 +nir_intrinsic_store_deref = 667 +nir_intrinsic_store_deref_block_intel = 668 +nir_intrinsic_store_global = 669 +nir_intrinsic_store_global_2x32 = 670 +nir_intrinsic_store_global_amd = 671 +nir_intrinsic_store_global_block_intel = 672 +nir_intrinsic_store_global_etna = 673 +nir_intrinsic_store_global_ir3 = 674 +nir_intrinsic_store_hit_attrib_amd = 675 +nir_intrinsic_store_local_pixel_agx = 676 +nir_intrinsic_store_local_shared_r600 = 677 +nir_intrinsic_store_output = 678 +nir_intrinsic_store_per_primitive_output = 679 +nir_intrinsic_store_per_primitive_payload_intel = 680 +nir_intrinsic_store_per_vertex_output = 681 +nir_intrinsic_store_per_view_output = 682 +nir_intrinsic_store_preamble = 683 +nir_intrinsic_store_raw_output_pan = 684 +nir_intrinsic_store_reg = 685 +nir_intrinsic_store_reg_indirect = 686 +nir_intrinsic_store_scalar_arg_amd = 687 +nir_intrinsic_store_scratch = 688 +nir_intrinsic_store_shared = 689 +nir_intrinsic_store_shared2_amd = 690 +nir_intrinsic_store_shared_block_intel = 691 +nir_intrinsic_store_shared_ir3 = 692 +nir_intrinsic_store_shared_unlock_nv = 693 +nir_intrinsic_store_ssbo = 694 +nir_intrinsic_store_ssbo_block_intel = 695 +nir_intrinsic_store_ssbo_intel = 696 +nir_intrinsic_store_ssbo_ir3 = 697 +nir_intrinsic_store_stack = 698 +nir_intrinsic_store_task_payload = 699 +nir_intrinsic_store_tf_r600 = 700 +nir_intrinsic_store_tlb_sample_color_v3d = 701 +nir_intrinsic_store_uvs_agx = 702 +nir_intrinsic_store_vector_arg_amd = 703 +nir_intrinsic_store_zs_agx = 704 +nir_intrinsic_strict_wqm_coord_amd = 705 +nir_intrinsic_subfm_nv = 706 +nir_intrinsic_suclamp_nv = 707 +nir_intrinsic_sueau_nv = 708 +nir_intrinsic_suldga_nv = 709 +nir_intrinsic_sustga_nv = 710 +nir_intrinsic_task_payload_atomic = 711 +nir_intrinsic_task_payload_atomic_swap = 712 +nir_intrinsic_terminate = 713 +nir_intrinsic_terminate_if = 714 +nir_intrinsic_terminate_ray = 715 +nir_intrinsic_trace_ray = 716 +nir_intrinsic_trace_ray_intel = 717 +nir_intrinsic_unit_test_amd = 718 +nir_intrinsic_unit_test_divergent_amd = 719 +nir_intrinsic_unit_test_uniform_amd = 720 +nir_intrinsic_unpin_cx_handle_nv = 721 +nir_intrinsic_use = 722 +nir_intrinsic_vild_nv = 723 +nir_intrinsic_vote_all = 724 +nir_intrinsic_vote_any = 725 +nir_intrinsic_vote_feq = 726 +nir_intrinsic_vote_ieq = 727 +nir_intrinsic_vulkan_resource_index = 728 +nir_intrinsic_vulkan_resource_reindex = 729 +nir_intrinsic_write_invocation_amd = 730 +nir_intrinsic_xfb_counter_sub_gfx11_amd = 731 +nir_last_intrinsic = 731 +nir_num_intrinsics = 732 +c__EA_nir_intrinsic_op = ctypes.c_uint32 # enum +nir_intrinsic_op = c__EA_nir_intrinsic_op +nir_intrinsic_op__enumvalues = c__EA_nir_intrinsic_op__enumvalues + +# values for enumeration 'c__EA_nir_intrinsic_index_flag' +c__EA_nir_intrinsic_index_flag__enumvalues = { + 0: 'NIR_INTRINSIC_BASE', + 1: 'NIR_INTRINSIC_WRITE_MASK', + 2: 'NIR_INTRINSIC_STREAM_ID', + 3: 'NIR_INTRINSIC_UCP_ID', + 4: 'NIR_INTRINSIC_RANGE_BASE', + 5: 'NIR_INTRINSIC_RANGE', + 6: 'NIR_INTRINSIC_DESC_SET', + 7: 'NIR_INTRINSIC_BINDING', + 8: 'NIR_INTRINSIC_COMPONENT', + 9: 'NIR_INTRINSIC_COLUMN', + 10: 'NIR_INTRINSIC_INTERP_MODE', + 11: 'NIR_INTRINSIC_REDUCTION_OP', + 12: 'NIR_INTRINSIC_CLUSTER_SIZE', + 13: 'NIR_INTRINSIC_PARAM_IDX', + 14: 'NIR_INTRINSIC_IMAGE_DIM', + 15: 'NIR_INTRINSIC_IMAGE_ARRAY', + 16: 'NIR_INTRINSIC_FORMAT', + 17: 'NIR_INTRINSIC_ACCESS', + 18: 'NIR_INTRINSIC_CALL_IDX', + 19: 'NIR_INTRINSIC_STACK_SIZE', + 20: 'NIR_INTRINSIC_ALIGN_MUL', + 21: 'NIR_INTRINSIC_ALIGN_OFFSET', + 22: 'NIR_INTRINSIC_DESC_TYPE', + 23: 'NIR_INTRINSIC_SRC_TYPE', + 24: 'NIR_INTRINSIC_DEST_TYPE', + 25: 'NIR_INTRINSIC_SRC_BASE_TYPE', + 26: 'NIR_INTRINSIC_SRC_BASE_TYPE2', + 27: 'NIR_INTRINSIC_DEST_BASE_TYPE', + 28: 'NIR_INTRINSIC_SWIZZLE_MASK', + 29: 'NIR_INTRINSIC_FETCH_INACTIVE', + 30: 'NIR_INTRINSIC_OFFSET0', + 31: 'NIR_INTRINSIC_OFFSET1', + 32: 'NIR_INTRINSIC_ST64', + 33: 'NIR_INTRINSIC_ARG_UPPER_BOUND_U32_AMD', + 34: 'NIR_INTRINSIC_DST_ACCESS', + 35: 'NIR_INTRINSIC_SRC_ACCESS', + 36: 'NIR_INTRINSIC_DRIVER_LOCATION', + 37: 'NIR_INTRINSIC_MEMORY_SEMANTICS', + 38: 'NIR_INTRINSIC_MEMORY_MODES', + 39: 'NIR_INTRINSIC_MEMORY_SCOPE', + 40: 'NIR_INTRINSIC_EXECUTION_SCOPE', + 41: 'NIR_INTRINSIC_IO_SEMANTICS', + 42: 'NIR_INTRINSIC_IO_XFB', + 43: 'NIR_INTRINSIC_IO_XFB2', + 44: 'NIR_INTRINSIC_RAY_QUERY_VALUE', + 45: 'NIR_INTRINSIC_COMMITTED', + 46: 'NIR_INTRINSIC_ROUNDING_MODE', + 47: 'NIR_INTRINSIC_SATURATE', + 48: 'NIR_INTRINSIC_SYNCHRONOUS', + 49: 'NIR_INTRINSIC_VALUE_ID', + 50: 'NIR_INTRINSIC_SIGN_EXTEND', + 51: 'NIR_INTRINSIC_FLAGS', + 52: 'NIR_INTRINSIC_ATOMIC_OP', + 53: 'NIR_INTRINSIC_RESOURCE_BLOCK_INTEL', + 54: 'NIR_INTRINSIC_RESOURCE_ACCESS_INTEL', + 55: 'NIR_INTRINSIC_NUM_COMPONENTS', + 56: 'NIR_INTRINSIC_NUM_ARRAY_ELEMS', + 57: 'NIR_INTRINSIC_BIT_SIZE', + 58: 'NIR_INTRINSIC_DIVERGENT', + 59: 'NIR_INTRINSIC_LEGACY_FABS', + 60: 'NIR_INTRINSIC_LEGACY_FNEG', + 61: 'NIR_INTRINSIC_LEGACY_FSAT', + 62: 'NIR_INTRINSIC_CMAT_DESC', + 63: 'NIR_INTRINSIC_MATRIX_LAYOUT', + 64: 'NIR_INTRINSIC_CMAT_SIGNED_MASK', + 65: 'NIR_INTRINSIC_ALU_OP', + 66: 'NIR_INTRINSIC_NEG_LO_AMD', + 67: 'NIR_INTRINSIC_NEG_HI_AMD', + 68: 'NIR_INTRINSIC_SYSTOLIC_DEPTH', + 69: 'NIR_INTRINSIC_REPEAT_COUNT', + 70: 'NIR_INTRINSIC_DST_CMAT_DESC', + 71: 'NIR_INTRINSIC_SRC_CMAT_DESC', + 72: 'NIR_INTRINSIC_EXPLICIT_COORD', + 73: 'NIR_INTRINSIC_FMT_IDX', + 74: 'NIR_INTRINSIC_PREAMBLE_CLASS', + 75: 'NIR_INTRINSIC_NUM_INDEX_FLAGS', +} +NIR_INTRINSIC_BASE = 0 +NIR_INTRINSIC_WRITE_MASK = 1 +NIR_INTRINSIC_STREAM_ID = 2 +NIR_INTRINSIC_UCP_ID = 3 +NIR_INTRINSIC_RANGE_BASE = 4 +NIR_INTRINSIC_RANGE = 5 +NIR_INTRINSIC_DESC_SET = 6 +NIR_INTRINSIC_BINDING = 7 +NIR_INTRINSIC_COMPONENT = 8 +NIR_INTRINSIC_COLUMN = 9 +NIR_INTRINSIC_INTERP_MODE = 10 +NIR_INTRINSIC_REDUCTION_OP = 11 +NIR_INTRINSIC_CLUSTER_SIZE = 12 +NIR_INTRINSIC_PARAM_IDX = 13 +NIR_INTRINSIC_IMAGE_DIM = 14 +NIR_INTRINSIC_IMAGE_ARRAY = 15 +NIR_INTRINSIC_FORMAT = 16 +NIR_INTRINSIC_ACCESS = 17 +NIR_INTRINSIC_CALL_IDX = 18 +NIR_INTRINSIC_STACK_SIZE = 19 +NIR_INTRINSIC_ALIGN_MUL = 20 +NIR_INTRINSIC_ALIGN_OFFSET = 21 +NIR_INTRINSIC_DESC_TYPE = 22 +NIR_INTRINSIC_SRC_TYPE = 23 +NIR_INTRINSIC_DEST_TYPE = 24 +NIR_INTRINSIC_SRC_BASE_TYPE = 25 +NIR_INTRINSIC_SRC_BASE_TYPE2 = 26 +NIR_INTRINSIC_DEST_BASE_TYPE = 27 +NIR_INTRINSIC_SWIZZLE_MASK = 28 +NIR_INTRINSIC_FETCH_INACTIVE = 29 +NIR_INTRINSIC_OFFSET0 = 30 +NIR_INTRINSIC_OFFSET1 = 31 +NIR_INTRINSIC_ST64 = 32 +NIR_INTRINSIC_ARG_UPPER_BOUND_U32_AMD = 33 +NIR_INTRINSIC_DST_ACCESS = 34 +NIR_INTRINSIC_SRC_ACCESS = 35 +NIR_INTRINSIC_DRIVER_LOCATION = 36 +NIR_INTRINSIC_MEMORY_SEMANTICS = 37 +NIR_INTRINSIC_MEMORY_MODES = 38 +NIR_INTRINSIC_MEMORY_SCOPE = 39 +NIR_INTRINSIC_EXECUTION_SCOPE = 40 +NIR_INTRINSIC_IO_SEMANTICS = 41 +NIR_INTRINSIC_IO_XFB = 42 +NIR_INTRINSIC_IO_XFB2 = 43 +NIR_INTRINSIC_RAY_QUERY_VALUE = 44 +NIR_INTRINSIC_COMMITTED = 45 +NIR_INTRINSIC_ROUNDING_MODE = 46 +NIR_INTRINSIC_SATURATE = 47 +NIR_INTRINSIC_SYNCHRONOUS = 48 +NIR_INTRINSIC_VALUE_ID = 49 +NIR_INTRINSIC_SIGN_EXTEND = 50 +NIR_INTRINSIC_FLAGS = 51 +NIR_INTRINSIC_ATOMIC_OP = 52 +NIR_INTRINSIC_RESOURCE_BLOCK_INTEL = 53 +NIR_INTRINSIC_RESOURCE_ACCESS_INTEL = 54 +NIR_INTRINSIC_NUM_COMPONENTS = 55 +NIR_INTRINSIC_NUM_ARRAY_ELEMS = 56 +NIR_INTRINSIC_BIT_SIZE = 57 +NIR_INTRINSIC_DIVERGENT = 58 +NIR_INTRINSIC_LEGACY_FABS = 59 +NIR_INTRINSIC_LEGACY_FNEG = 60 +NIR_INTRINSIC_LEGACY_FSAT = 61 +NIR_INTRINSIC_CMAT_DESC = 62 +NIR_INTRINSIC_MATRIX_LAYOUT = 63 +NIR_INTRINSIC_CMAT_SIGNED_MASK = 64 +NIR_INTRINSIC_ALU_OP = 65 +NIR_INTRINSIC_NEG_LO_AMD = 66 +NIR_INTRINSIC_NEG_HI_AMD = 67 +NIR_INTRINSIC_SYSTOLIC_DEPTH = 68 +NIR_INTRINSIC_REPEAT_COUNT = 69 +NIR_INTRINSIC_DST_CMAT_DESC = 70 +NIR_INTRINSIC_SRC_CMAT_DESC = 71 +NIR_INTRINSIC_EXPLICIT_COORD = 72 +NIR_INTRINSIC_FMT_IDX = 73 +NIR_INTRINSIC_PREAMBLE_CLASS = 74 +NIR_INTRINSIC_NUM_INDEX_FLAGS = 75 +c__EA_nir_intrinsic_index_flag = ctypes.c_uint32 # enum +nir_intrinsic_index_flag = c__EA_nir_intrinsic_index_flag +nir_intrinsic_index_flag__enumvalues = c__EA_nir_intrinsic_index_flag__enumvalues +try: nir_intrinsic_index_names = (ctypes.POINTER(ctypes.c_char) * 75).in_dll(_libraries['libtinymesa_cpu.so'], 'nir_intrinsic_index_names') +except (AttributeError, ValueError): pass +class struct_nir_intrinsic_instr(Structure): + pass + +struct_nir_intrinsic_instr._pack_ = 1 # source:False +struct_nir_intrinsic_instr._fields_ = [ + ('instr', nir_instr), + ('intrinsic', nir_intrinsic_op), + ('PADDING_0', ctypes.c_ubyte * 4), + ('def', nir_def), + ('num_components', ctypes.c_ubyte), + ('PADDING_1', ctypes.c_ubyte * 3), + ('const_index', ctypes.c_int32 * 8), + ('PADDING_2', ctypes.c_ubyte * 4), + ('name', ctypes.POINTER(ctypes.c_char)), + ('src', struct_nir_src * 0), +] + +nir_intrinsic_instr = struct_nir_intrinsic_instr +try: + nir_intrinsic_get_var = _libraries['FIXME_STUB'].nir_intrinsic_get_var + nir_intrinsic_get_var.restype = ctypes.POINTER(struct_nir_variable) + nir_intrinsic_get_var.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_memory_semantics' +c__EA_nir_memory_semantics__enumvalues = { + 1: 'NIR_MEMORY_ACQUIRE', + 2: 'NIR_MEMORY_RELEASE', + 3: 'NIR_MEMORY_ACQ_REL', + 4: 'NIR_MEMORY_MAKE_AVAILABLE', + 8: 'NIR_MEMORY_MAKE_VISIBLE', +} +NIR_MEMORY_ACQUIRE = 1 +NIR_MEMORY_RELEASE = 2 +NIR_MEMORY_ACQ_REL = 3 +NIR_MEMORY_MAKE_AVAILABLE = 4 +NIR_MEMORY_MAKE_VISIBLE = 8 +c__EA_nir_memory_semantics = ctypes.c_uint32 # enum +nir_memory_semantics = c__EA_nir_memory_semantics +nir_memory_semantics__enumvalues = c__EA_nir_memory_semantics__enumvalues + +# values for enumeration 'c__EA_nir_intrinsic_semantic_flag' +c__EA_nir_intrinsic_semantic_flag__enumvalues = { + 1: 'NIR_INTRINSIC_CAN_ELIMINATE', + 2: 'NIR_INTRINSIC_CAN_REORDER', + 4: 'NIR_INTRINSIC_SUBGROUP', + 8: 'NIR_INTRINSIC_QUADGROUP', +} +NIR_INTRINSIC_CAN_ELIMINATE = 1 +NIR_INTRINSIC_CAN_REORDER = 2 +NIR_INTRINSIC_SUBGROUP = 4 +NIR_INTRINSIC_QUADGROUP = 8 +c__EA_nir_intrinsic_semantic_flag = ctypes.c_uint32 # enum +nir_intrinsic_semantic_flag = c__EA_nir_intrinsic_semantic_flag +nir_intrinsic_semantic_flag__enumvalues = c__EA_nir_intrinsic_semantic_flag__enumvalues +class struct_nir_io_semantics(Structure): + pass + +struct_nir_io_semantics._pack_ = 1 # source:False +struct_nir_io_semantics._fields_ = [ + ('location', ctypes.c_uint32, 7), + ('num_slots', ctypes.c_uint32, 6), + ('dual_source_blend_index', ctypes.c_uint32, 1), + ('fb_fetch_output', ctypes.c_uint32, 1), + ('fb_fetch_output_coherent', ctypes.c_uint32, 1), + ('gs_streams', ctypes.c_uint32, 8), + ('medium_precision', ctypes.c_uint32, 1), + ('per_view', ctypes.c_uint32, 1), + ('high_16bits', ctypes.c_uint32, 1), + ('high_dvec2', ctypes.c_uint32, 1), + ('no_varying', ctypes.c_uint32, 1), + ('no_sysval_output', ctypes.c_uint32, 1), + ('interp_explicit_strict', ctypes.c_uint32, 1), + ('_pad', ctypes.c_uint32, 1), +] + +nir_io_semantics = struct_nir_io_semantics +class struct_nir_io_xfb(Structure): + pass + +class struct_nir_io_xfb_0(Structure): + pass + +struct_nir_io_xfb_0._pack_ = 1 # source:False +struct_nir_io_xfb_0._fields_ = [ + ('num_components', ctypes.c_ubyte, 4), + ('buffer', ctypes.c_ubyte, 4), + ('offset', ctypes.c_ubyte, 8), +] + +struct_nir_io_xfb._pack_ = 1 # source:False +struct_nir_io_xfb._fields_ = [ + ('out', struct_nir_io_xfb_0 * 2), +] + +nir_io_xfb = struct_nir_io_xfb +try: + nir_instr_xfb_write_mask = _libraries['libtinymesa_cpu.so'].nir_instr_xfb_write_mask + nir_instr_xfb_write_mask.restype = ctypes.c_uint32 + nir_instr_xfb_write_mask.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +class struct_nir_intrinsic_info(Structure): + pass + +struct_nir_intrinsic_info._pack_ = 1 # source:False +struct_nir_intrinsic_info._fields_ = [ + ('name', ctypes.POINTER(ctypes.c_char)), + ('num_srcs', ctypes.c_ubyte), + ('src_components', ctypes.c_byte * 11), + ('has_dest', ctypes.c_bool), + ('dest_components', ctypes.c_ubyte), + ('dest_bit_sizes', ctypes.c_ubyte), + ('bit_size_src', ctypes.c_byte), + ('num_indices', ctypes.c_ubyte), + ('indices', ctypes.c_ubyte * 8), + ('index_map', ctypes.c_ubyte * 75), + ('flags', nir_intrinsic_semantic_flag), +] + +nir_intrinsic_info = struct_nir_intrinsic_info +try: nir_intrinsic_infos = (struct_nir_intrinsic_info * 732).in_dll(_libraries['libtinymesa_cpu.so'], 'nir_intrinsic_infos') +except (AttributeError, ValueError): pass +try: + nir_intrinsic_src_components = _libraries['libtinymesa_cpu.so'].nir_intrinsic_src_components + nir_intrinsic_src_components.restype = ctypes.c_uint32 + nir_intrinsic_src_components.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_intrinsic_dest_components = _libraries['libtinymesa_cpu.so'].nir_intrinsic_dest_components + nir_intrinsic_dest_components.restype = ctypes.c_uint32 + nir_intrinsic_dest_components.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_intrinsic_instr_src_type = _libraries['libtinymesa_cpu.so'].nir_intrinsic_instr_src_type + nir_intrinsic_instr_src_type.restype = nir_alu_type + nir_intrinsic_instr_src_type.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_intrinsic_instr_dest_type = _libraries['libtinymesa_cpu.so'].nir_intrinsic_instr_dest_type + nir_intrinsic_instr_dest_type.restype = nir_alu_type + nir_intrinsic_instr_dest_type.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_intrinsic_copy_const_indices = _libraries['libtinymesa_cpu.so'].nir_intrinsic_copy_const_indices + nir_intrinsic_copy_const_indices.restype = None + nir_intrinsic_copy_const_indices.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_intrinsic_set_align = _libraries['FIXME_STUB'].nir_intrinsic_set_align + nir_intrinsic_set_align.restype = None + nir_intrinsic_set_align.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_combined_align = _libraries['FIXME_STUB'].nir_combined_align + nir_combined_align.restype = uint32_t + nir_combined_align.argtypes = [uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_intrinsic_align = _libraries['FIXME_STUB'].nir_intrinsic_align + nir_intrinsic_align.restype = ctypes.c_uint32 + nir_intrinsic_align.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_intrinsic_has_align = _libraries['FIXME_STUB'].nir_intrinsic_has_align + nir_intrinsic_has_align.restype = ctypes.c_bool + nir_intrinsic_has_align.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_image_intrinsic_coord_components = _libraries['libtinymesa_cpu.so'].nir_image_intrinsic_coord_components + nir_image_intrinsic_coord_components.restype = ctypes.c_uint32 + nir_image_intrinsic_coord_components.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_rewrite_image_intrinsic = _libraries['libtinymesa_cpu.so'].nir_rewrite_image_intrinsic + nir_rewrite_image_intrinsic.restype = None + nir_rewrite_image_intrinsic.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_def), ctypes.c_bool] +except AttributeError: + pass +try: + nir_intrinsic_can_reorder = _libraries['libtinymesa_cpu.so'].nir_intrinsic_can_reorder + nir_intrinsic_can_reorder.restype = ctypes.c_bool + nir_intrinsic_can_reorder.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_intrinsic_writes_external_memory = _libraries['libtinymesa_cpu.so'].nir_intrinsic_writes_external_memory + nir_intrinsic_writes_external_memory.restype = ctypes.c_bool + nir_intrinsic_writes_external_memory.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_intrinsic_has_semantic = _libraries['FIXME_STUB'].nir_intrinsic_has_semantic + nir_intrinsic_has_semantic.restype = ctypes.c_bool + nir_intrinsic_has_semantic.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), nir_intrinsic_semantic_flag] +except AttributeError: + pass +try: + nir_intrinsic_is_ray_query = _libraries['FIXME_STUB'].nir_intrinsic_is_ray_query + nir_intrinsic_is_ray_query.restype = ctypes.c_bool + nir_intrinsic_is_ray_query.argtypes = [nir_intrinsic_op] +except AttributeError: + pass + +# values for enumeration 'nir_tex_src_type' +nir_tex_src_type__enumvalues = { + 0: 'nir_tex_src_coord', + 1: 'nir_tex_src_projector', + 2: 'nir_tex_src_comparator', + 3: 'nir_tex_src_offset', + 4: 'nir_tex_src_bias', + 5: 'nir_tex_src_lod', + 6: 'nir_tex_src_min_lod', + 7: 'nir_tex_src_lod_bias_min_agx', + 8: 'nir_tex_src_ms_index', + 9: 'nir_tex_src_ms_mcs_intel', + 10: 'nir_tex_src_ddx', + 11: 'nir_tex_src_ddy', + 12: 'nir_tex_src_texture_deref', + 13: 'nir_tex_src_sampler_deref', + 14: 'nir_tex_src_texture_offset', + 15: 'nir_tex_src_sampler_offset', + 16: 'nir_tex_src_texture_handle', + 17: 'nir_tex_src_sampler_handle', + 18: 'nir_tex_src_sampler_deref_intrinsic', + 19: 'nir_tex_src_texture_deref_intrinsic', + 20: 'nir_tex_src_plane', + 21: 'nir_tex_src_backend1', + 22: 'nir_tex_src_backend2', + 23: 'nir_num_tex_src_types', +} +nir_tex_src_coord = 0 +nir_tex_src_projector = 1 +nir_tex_src_comparator = 2 +nir_tex_src_offset = 3 +nir_tex_src_bias = 4 +nir_tex_src_lod = 5 +nir_tex_src_min_lod = 6 +nir_tex_src_lod_bias_min_agx = 7 +nir_tex_src_ms_index = 8 +nir_tex_src_ms_mcs_intel = 9 +nir_tex_src_ddx = 10 +nir_tex_src_ddy = 11 +nir_tex_src_texture_deref = 12 +nir_tex_src_sampler_deref = 13 +nir_tex_src_texture_offset = 14 +nir_tex_src_sampler_offset = 15 +nir_tex_src_texture_handle = 16 +nir_tex_src_sampler_handle = 17 +nir_tex_src_sampler_deref_intrinsic = 18 +nir_tex_src_texture_deref_intrinsic = 19 +nir_tex_src_plane = 20 +nir_tex_src_backend1 = 21 +nir_tex_src_backend2 = 22 +nir_num_tex_src_types = 23 +nir_tex_src_type = ctypes.c_uint32 # enum +class struct_nir_tex_src(Structure): + pass + +struct_nir_tex_src._pack_ = 1 # source:False +struct_nir_tex_src._fields_ = [ + ('src', nir_src), + ('src_type', nir_tex_src_type), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +nir_tex_src = struct_nir_tex_src + +# values for enumeration 'nir_texop' +nir_texop__enumvalues = { + 0: 'nir_texop_tex', + 1: 'nir_texop_txb', + 2: 'nir_texop_txl', + 3: 'nir_texop_txd', + 4: 'nir_texop_txf', + 5: 'nir_texop_txf_ms', + 6: 'nir_texop_txf_ms_fb', + 7: 'nir_texop_txf_ms_mcs_intel', + 8: 'nir_texop_txs', + 9: 'nir_texop_lod', + 10: 'nir_texop_tg4', + 11: 'nir_texop_query_levels', + 12: 'nir_texop_texture_samples', + 13: 'nir_texop_samples_identical', + 14: 'nir_texop_tex_prefetch', + 15: 'nir_texop_lod_bias', + 16: 'nir_texop_fragment_fetch_amd', + 17: 'nir_texop_fragment_mask_fetch_amd', + 18: 'nir_texop_descriptor_amd', + 19: 'nir_texop_sampler_descriptor_amd', + 20: 'nir_texop_image_min_lod_agx', + 21: 'nir_texop_has_custom_border_color_agx', + 22: 'nir_texop_custom_border_color_agx', + 23: 'nir_texop_hdr_dim_nv', + 24: 'nir_texop_tex_type_nv', +} +nir_texop_tex = 0 +nir_texop_txb = 1 +nir_texop_txl = 2 +nir_texop_txd = 3 +nir_texop_txf = 4 +nir_texop_txf_ms = 5 +nir_texop_txf_ms_fb = 6 +nir_texop_txf_ms_mcs_intel = 7 +nir_texop_txs = 8 +nir_texop_lod = 9 +nir_texop_tg4 = 10 +nir_texop_query_levels = 11 +nir_texop_texture_samples = 12 +nir_texop_samples_identical = 13 +nir_texop_tex_prefetch = 14 +nir_texop_lod_bias = 15 +nir_texop_fragment_fetch_amd = 16 +nir_texop_fragment_mask_fetch_amd = 17 +nir_texop_descriptor_amd = 18 +nir_texop_sampler_descriptor_amd = 19 +nir_texop_image_min_lod_agx = 20 +nir_texop_has_custom_border_color_agx = 21 +nir_texop_custom_border_color_agx = 22 +nir_texop_hdr_dim_nv = 23 +nir_texop_tex_type_nv = 24 +nir_texop = ctypes.c_uint32 # enum +class struct_nir_tex_instr(Structure): + pass + +struct_nir_tex_instr._pack_ = 1 # source:False +struct_nir_tex_instr._fields_ = [ + ('instr', nir_instr), + ('sampler_dim', glsl_sampler_dim), + ('dest_type', nir_alu_type), + ('op', nir_texop), + ('PADDING_0', ctypes.c_ubyte * 4), + ('def', nir_def), + ('src', ctypes.POINTER(struct_nir_tex_src)), + ('num_srcs', ctypes.c_uint32), + ('coord_components', ctypes.c_uint32), + ('is_array', ctypes.c_bool), + ('is_shadow', ctypes.c_bool), + ('is_new_style_shadow', ctypes.c_bool), + ('is_sparse', ctypes.c_bool), + ('component', ctypes.c_uint32, 2), + ('array_is_lowered_cube', ctypes.c_uint32, 1), + ('is_gather_implicit_lod', ctypes.c_uint32, 1), + ('skip_helpers', ctypes.c_uint32, 1), + ('PADDING_1', ctypes.c_uint8, 3), + ('tg4_offsets', ctypes.c_byte * 2 * 4), + ('texture_non_uniform', ctypes.c_bool), + ('sampler_non_uniform', ctypes.c_bool), + ('offset_non_uniform', ctypes.c_bool), + ('texture_index', ctypes.c_uint32), + ('sampler_index', ctypes.c_uint32), + ('backend_flags', ctypes.c_uint32), + ('PADDING_2', ctypes.c_ubyte * 4), +] + +nir_tex_instr = struct_nir_tex_instr +try: + nir_tex_instr_need_sampler = _libraries['libtinymesa_cpu.so'].nir_tex_instr_need_sampler + nir_tex_instr_need_sampler.restype = ctypes.c_bool + nir_tex_instr_need_sampler.argtypes = [ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +try: + nir_tex_instr_result_size = _libraries['libtinymesa_cpu.so'].nir_tex_instr_result_size + nir_tex_instr_result_size.restype = ctypes.c_uint32 + nir_tex_instr_result_size.argtypes = [ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +try: + nir_tex_instr_dest_size = _libraries['FIXME_STUB'].nir_tex_instr_dest_size + nir_tex_instr_dest_size.restype = ctypes.c_uint32 + nir_tex_instr_dest_size.argtypes = [ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +try: + nir_tex_instr_is_query = _libraries['libtinymesa_cpu.so'].nir_tex_instr_is_query + nir_tex_instr_is_query.restype = ctypes.c_bool + nir_tex_instr_is_query.argtypes = [ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +try: + nir_tex_instr_has_implicit_derivative = _libraries['libtinymesa_cpu.so'].nir_tex_instr_has_implicit_derivative + nir_tex_instr_has_implicit_derivative.restype = ctypes.c_bool + nir_tex_instr_has_implicit_derivative.argtypes = [ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +try: + nir_tex_instr_src_type = _libraries['libtinymesa_cpu.so'].nir_tex_instr_src_type + nir_tex_instr_src_type.restype = nir_alu_type + nir_tex_instr_src_type.argtypes = [ctypes.POINTER(struct_nir_tex_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_tex_instr_src_size = _libraries['libtinymesa_cpu.so'].nir_tex_instr_src_size + nir_tex_instr_src_size.restype = ctypes.c_uint32 + nir_tex_instr_src_size.argtypes = [ctypes.POINTER(struct_nir_tex_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_tex_instr_src_index = _libraries['FIXME_STUB'].nir_tex_instr_src_index + nir_tex_instr_src_index.restype = ctypes.c_int32 + nir_tex_instr_src_index.argtypes = [ctypes.POINTER(struct_nir_tex_instr), nir_tex_src_type] +except AttributeError: + pass +try: + nir_tex_instr_add_src = _libraries['libtinymesa_cpu.so'].nir_tex_instr_add_src + nir_tex_instr_add_src.restype = None + nir_tex_instr_add_src.argtypes = [ctypes.POINTER(struct_nir_tex_instr), nir_tex_src_type, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_tex_instr_remove_src = _libraries['libtinymesa_cpu.so'].nir_tex_instr_remove_src + nir_tex_instr_remove_src.restype = None + nir_tex_instr_remove_src.argtypes = [ctypes.POINTER(struct_nir_tex_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_get_tex_src = _libraries['FIXME_STUB'].nir_get_tex_src + nir_get_tex_src.restype = ctypes.POINTER(struct_nir_def) + nir_get_tex_src.argtypes = [ctypes.POINTER(struct_nir_tex_instr), nir_tex_src_type] +except AttributeError: + pass +try: + nir_get_tex_deref = _libraries['FIXME_STUB'].nir_get_tex_deref + nir_get_tex_deref.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_get_tex_deref.argtypes = [ctypes.POINTER(struct_nir_tex_instr), nir_tex_src_type] +except AttributeError: + pass +try: + nir_steal_tex_src = _libraries['FIXME_STUB'].nir_steal_tex_src + nir_steal_tex_src.restype = ctypes.POINTER(struct_nir_def) + nir_steal_tex_src.argtypes = [ctypes.POINTER(struct_nir_tex_instr), nir_tex_src_type] +except AttributeError: + pass +try: + nir_steal_tex_deref = _libraries['FIXME_STUB'].nir_steal_tex_deref + nir_steal_tex_deref.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_steal_tex_deref.argtypes = [ctypes.POINTER(struct_nir_tex_instr), nir_tex_src_type] +except AttributeError: + pass +try: + nir_tex_instr_has_explicit_tg4_offsets = _libraries['libtinymesa_cpu.so'].nir_tex_instr_has_explicit_tg4_offsets + nir_tex_instr_has_explicit_tg4_offsets.restype = ctypes.c_bool + nir_tex_instr_has_explicit_tg4_offsets.argtypes = [ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +class struct_nir_load_const_instr(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('instr', nir_instr), + ('def', nir_def), + ('value', union_c__UA_nir_const_value * 0), + ] + +nir_load_const_instr = struct_nir_load_const_instr + +# values for enumeration 'c__EA_nir_jump_type' +c__EA_nir_jump_type__enumvalues = { + 0: 'nir_jump_return', + 1: 'nir_jump_halt', + 2: 'nir_jump_break', + 3: 'nir_jump_continue', + 4: 'nir_jump_goto', + 5: 'nir_jump_goto_if', +} +nir_jump_return = 0 +nir_jump_halt = 1 +nir_jump_break = 2 +nir_jump_continue = 3 +nir_jump_goto = 4 +nir_jump_goto_if = 5 +c__EA_nir_jump_type = ctypes.c_uint32 # enum +nir_jump_type = c__EA_nir_jump_type +nir_jump_type__enumvalues = c__EA_nir_jump_type__enumvalues +class struct_nir_jump_instr(Structure): + pass + +struct_nir_jump_instr._pack_ = 1 # source:False +struct_nir_jump_instr._fields_ = [ + ('instr', nir_instr), + ('type', nir_jump_type), + ('PADDING_0', ctypes.c_ubyte * 4), + ('condition', nir_src), + ('target', ctypes.POINTER(struct_nir_block)), + ('else_target', ctypes.POINTER(struct_nir_block)), +] + +nir_jump_instr = struct_nir_jump_instr +class struct_nir_undef_instr(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('instr', nir_instr), + ('def', nir_def), + ] + +nir_undef_instr = struct_nir_undef_instr +class struct_nir_phi_src(Structure): + pass + +struct_nir_phi_src._pack_ = 1 # source:False +struct_nir_phi_src._fields_ = [ + ('node', struct_exec_node), + ('pred', ctypes.POINTER(struct_nir_block)), + ('src', nir_src), +] + +nir_phi_src = struct_nir_phi_src +class struct_nir_phi_instr(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('instr', nir_instr), + ('srcs', struct_exec_list), + ('def', nir_def), + ] + +nir_phi_instr = struct_nir_phi_instr +try: + nir_phi_get_src_from_block = _libraries['FIXME_STUB'].nir_phi_get_src_from_block + nir_phi_get_src_from_block.restype = ctypes.POINTER(struct_nir_phi_src) + nir_phi_get_src_from_block.argtypes = [ctypes.POINTER(struct_nir_phi_instr), ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +class struct_nir_parallel_copy_entry(Structure): + pass + +class union_nir_parallel_copy_entry_dest(Union): + _pack_ = 1 # source:False + _fields_ = [ + ('def', nir_def), + ('reg', nir_src), + ] + +struct_nir_parallel_copy_entry._pack_ = 1 # source:False +struct_nir_parallel_copy_entry._fields_ = [ + ('node', struct_exec_node), + ('src_is_reg', ctypes.c_bool), + ('dest_is_reg', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 6), + ('src', nir_src), + ('dest', union_nir_parallel_copy_entry_dest), +] + +nir_parallel_copy_entry = struct_nir_parallel_copy_entry +class struct_nir_parallel_copy_instr(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('instr', nir_instr), + ('entries', struct_exec_list), + ] + +nir_parallel_copy_instr = struct_nir_parallel_copy_instr +class struct_nir_instr_debug_info(Structure): + pass + +struct_nir_instr_debug_info._pack_ = 1 # source:False +struct_nir_instr_debug_info._fields_ = [ + ('filename', ctypes.POINTER(ctypes.c_char)), + ('line', ctypes.c_uint32), + ('column', ctypes.c_uint32), + ('spirv_offset', ctypes.c_uint32), + ('nir_line', ctypes.c_uint32), + ('variable_name', ctypes.POINTER(ctypes.c_char)), + ('instr', nir_instr), +] + +nir_instr_debug_info = struct_nir_instr_debug_info +try: + nir_instr_as_alu = _libraries['FIXME_STUB'].nir_instr_as_alu + nir_instr_as_alu.restype = ctypes.POINTER(struct_nir_alu_instr) + nir_instr_as_alu.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_deref = _libraries['FIXME_STUB'].nir_instr_as_deref + nir_instr_as_deref.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_instr_as_deref.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_call = _libraries['FIXME_STUB'].nir_instr_as_call + nir_instr_as_call.restype = ctypes.POINTER(struct_nir_call_instr) + nir_instr_as_call.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_jump = _libraries['FIXME_STUB'].nir_instr_as_jump + nir_instr_as_jump.restype = ctypes.POINTER(struct_nir_jump_instr) + nir_instr_as_jump.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_tex = _libraries['FIXME_STUB'].nir_instr_as_tex + nir_instr_as_tex.restype = ctypes.POINTER(struct_nir_tex_instr) + nir_instr_as_tex.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_intrinsic = _libraries['FIXME_STUB'].nir_instr_as_intrinsic + nir_instr_as_intrinsic.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_instr_as_intrinsic.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_load_const = _libraries['FIXME_STUB'].nir_instr_as_load_const + nir_instr_as_load_const.restype = ctypes.POINTER(struct_nir_load_const_instr) + nir_instr_as_load_const.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_undef = _libraries['FIXME_STUB'].nir_instr_as_undef + nir_instr_as_undef.restype = ctypes.POINTER(struct_nir_undef_instr) + nir_instr_as_undef.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_phi = _libraries['FIXME_STUB'].nir_instr_as_phi + nir_instr_as_phi.restype = ctypes.POINTER(struct_nir_phi_instr) + nir_instr_as_phi.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_as_parallel_copy = _libraries['FIXME_STUB'].nir_instr_as_parallel_copy + nir_instr_as_parallel_copy.restype = ctypes.POINTER(struct_nir_parallel_copy_instr) + nir_instr_as_parallel_copy.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_src_comp_as_int = _libraries['FIXME_STUB'].nir_src_comp_as_int + nir_src_comp_as_int.restype = int64_t + nir_src_comp_as_int.argtypes = [nir_src, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_src_as_int = _libraries['FIXME_STUB'].nir_src_as_int + nir_src_as_int.restype = int64_t + nir_src_as_int.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_comp_as_uint = _libraries['FIXME_STUB'].nir_src_comp_as_uint + nir_src_comp_as_uint.restype = uint64_t + nir_src_comp_as_uint.argtypes = [nir_src, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_src_as_uint = _libraries['FIXME_STUB'].nir_src_as_uint + nir_src_as_uint.restype = uint64_t + nir_src_as_uint.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_comp_as_bool = _libraries['FIXME_STUB'].nir_src_comp_as_bool + nir_src_comp_as_bool.restype = ctypes.c_bool + nir_src_comp_as_bool.argtypes = [nir_src, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_src_as_bool = _libraries['FIXME_STUB'].nir_src_as_bool + nir_src_as_bool.restype = ctypes.c_bool + nir_src_as_bool.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_comp_as_float = _libraries['FIXME_STUB'].nir_src_comp_as_float + nir_src_comp_as_float.restype = ctypes.c_double + nir_src_comp_as_float.argtypes = [nir_src, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_src_as_float = _libraries['FIXME_STUB'].nir_src_as_float + nir_src_as_float.restype = ctypes.c_double + nir_src_as_float.argtypes = [nir_src] +except AttributeError: + pass +class struct_nir_scalar(Structure): + pass + +struct_nir_scalar._pack_ = 1 # source:False +struct_nir_scalar._fields_ = [ + ('def', ctypes.POINTER(struct_nir_def)), + ('comp', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +nir_scalar = struct_nir_scalar +try: + nir_scalar_is_const = _libraries['FIXME_STUB'].nir_scalar_is_const + nir_scalar_is_const.restype = ctypes.c_bool + nir_scalar_is_const.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_is_undef = _libraries['FIXME_STUB'].nir_scalar_is_undef + nir_scalar_is_undef.restype = ctypes.c_bool + nir_scalar_is_undef.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_as_const_value = _libraries['FIXME_STUB'].nir_scalar_as_const_value + nir_scalar_as_const_value.restype = nir_const_value + nir_scalar_as_const_value.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_as_int = _libraries['FIXME_STUB'].nir_scalar_as_int + nir_scalar_as_int.restype = int64_t + nir_scalar_as_int.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_as_uint = _libraries['FIXME_STUB'].nir_scalar_as_uint + nir_scalar_as_uint.restype = uint64_t + nir_scalar_as_uint.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_as_bool = _libraries['FIXME_STUB'].nir_scalar_as_bool + nir_scalar_as_bool.restype = ctypes.c_bool + nir_scalar_as_bool.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_as_float = _libraries['FIXME_STUB'].nir_scalar_as_float + nir_scalar_as_float.restype = ctypes.c_double + nir_scalar_as_float.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_is_alu = _libraries['FIXME_STUB'].nir_scalar_is_alu + nir_scalar_is_alu.restype = ctypes.c_bool + nir_scalar_is_alu.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_alu_op = _libraries['FIXME_STUB'].nir_scalar_alu_op + nir_scalar_alu_op.restype = nir_op + nir_scalar_alu_op.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_is_intrinsic = _libraries['FIXME_STUB'].nir_scalar_is_intrinsic + nir_scalar_is_intrinsic.restype = ctypes.c_bool + nir_scalar_is_intrinsic.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_intrinsic_op = _libraries['FIXME_STUB'].nir_scalar_intrinsic_op + nir_scalar_intrinsic_op.restype = nir_intrinsic_op + nir_scalar_intrinsic_op.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_scalar_chase_alu_src = _libraries['FIXME_STUB'].nir_scalar_chase_alu_src + nir_scalar_chase_alu_src.restype = nir_scalar + nir_scalar_chase_alu_src.argtypes = [nir_scalar, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_scalar_chase_movs = _libraries['libtinymesa_cpu.so'].nir_scalar_chase_movs + nir_scalar_chase_movs.restype = nir_scalar + nir_scalar_chase_movs.argtypes = [nir_scalar] +except AttributeError: + pass +try: + nir_get_scalar = _libraries['FIXME_STUB'].nir_get_scalar + nir_get_scalar.restype = nir_scalar + nir_get_scalar.argtypes = [ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_scalar_resolved = _libraries['FIXME_STUB'].nir_scalar_resolved + nir_scalar_resolved.restype = nir_scalar + nir_scalar_resolved.argtypes = [ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_scalar_equal = _libraries['FIXME_STUB'].nir_scalar_equal + nir_scalar_equal.restype = ctypes.c_bool + nir_scalar_equal.argtypes = [nir_scalar, nir_scalar] +except AttributeError: + pass +try: + nir_alu_src_as_uint = _libraries['FIXME_STUB'].nir_alu_src_as_uint + nir_alu_src_as_uint.restype = uint64_t + nir_alu_src_as_uint.argtypes = [nir_alu_src] +except AttributeError: + pass +class struct_nir_binding(Structure): + pass + +struct_nir_binding._pack_ = 1 # source:False +struct_nir_binding._fields_ = [ + ('success', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), + ('var', ctypes.POINTER(struct_nir_variable)), + ('desc_set', ctypes.c_uint32), + ('binding', ctypes.c_uint32), + ('num_indices', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('indices', struct_nir_src * 4), + ('read_first_invocation', ctypes.c_bool), + ('PADDING_2', ctypes.c_ubyte * 7), +] + +nir_binding = struct_nir_binding +try: + nir_chase_binding = _libraries['libtinymesa_cpu.so'].nir_chase_binding + nir_chase_binding.restype = nir_binding + nir_chase_binding.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_get_binding_variable = _libraries['libtinymesa_cpu.so'].nir_get_binding_variable + nir_get_binding_variable.restype = ctypes.POINTER(struct_nir_variable) + nir_get_binding_variable.argtypes = [ctypes.POINTER(struct_nir_shader), nir_binding] +except AttributeError: + pass +nir_cf_node_type = c__EA_nir_cf_node_type +nir_cf_node_type__enumvalues = c__EA_nir_cf_node_type__enumvalues +nir_cf_node = struct_nir_cf_node +nir_block = struct_nir_block +try: + nir_block_is_reachable = _libraries['FIXME_STUB'].nir_block_is_reachable + nir_block_is_reachable.restype = ctypes.c_bool + nir_block_is_reachable.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_first_instr = _libraries['FIXME_STUB'].nir_block_first_instr + nir_block_first_instr.restype = ctypes.POINTER(struct_nir_instr) + nir_block_first_instr.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_last_instr = _libraries['FIXME_STUB'].nir_block_last_instr + nir_block_last_instr.restype = ctypes.POINTER(struct_nir_instr) + nir_block_last_instr.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_ends_in_jump = _libraries['FIXME_STUB'].nir_block_ends_in_jump + nir_block_ends_in_jump.restype = ctypes.c_bool + nir_block_ends_in_jump.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_ends_in_return_or_halt = _libraries['FIXME_STUB'].nir_block_ends_in_return_or_halt + nir_block_ends_in_return_or_halt.restype = ctypes.c_bool + nir_block_ends_in_return_or_halt.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_ends_in_break = _libraries['FIXME_STUB'].nir_block_ends_in_break + nir_block_ends_in_break.restype = ctypes.c_bool + nir_block_ends_in_break.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_contains_work = _libraries['libtinymesa_cpu.so'].nir_block_contains_work + nir_block_contains_work.restype = ctypes.c_bool + nir_block_contains_work.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_first_phi_in_block = _libraries['FIXME_STUB'].nir_first_phi_in_block + nir_first_phi_in_block.restype = ctypes.POINTER(struct_nir_phi_instr) + nir_first_phi_in_block.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_next_phi = _libraries['FIXME_STUB'].nir_next_phi + nir_next_phi.restype = ctypes.POINTER(struct_nir_phi_instr) + nir_next_phi.argtypes = [ctypes.POINTER(struct_nir_phi_instr)] +except AttributeError: + pass +try: + nir_block_last_phi_instr = _libraries['FIXME_STUB'].nir_block_last_phi_instr + nir_block_last_phi_instr.restype = ctypes.POINTER(struct_nir_phi_instr) + nir_block_last_phi_instr.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +nir_selection_control = c__EA_nir_selection_control +nir_selection_control__enumvalues = c__EA_nir_selection_control__enumvalues +nir_if = struct_nir_if +class struct_nir_loop_terminator(Structure): + pass + +struct_nir_loop_terminator._pack_ = 1 # source:False +struct_nir_loop_terminator._fields_ = [ + ('nif', ctypes.POINTER(struct_nir_if)), + ('conditional_instr', ctypes.POINTER(struct_nir_instr)), + ('break_block', ctypes.POINTER(struct_nir_block)), + ('continue_from_block', ctypes.POINTER(struct_nir_block)), + ('continue_from_then', ctypes.c_bool), + ('induction_rhs', ctypes.c_bool), + ('exact_trip_count_unknown', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 5), + ('loop_terminator_link', struct_list_head), +] + +nir_loop_terminator = struct_nir_loop_terminator +class struct_nir_loop_induction_variable(Structure): + pass + +struct_nir_loop_induction_variable._pack_ = 1 # source:False +struct_nir_loop_induction_variable._fields_ = [ + ('basis', ctypes.POINTER(struct_nir_def)), + ('def', ctypes.POINTER(struct_nir_def)), + ('init_src', ctypes.POINTER(struct_nir_src)), + ('update_src', ctypes.POINTER(struct_nir_alu_src)), +] + +nir_loop_induction_variable = struct_nir_loop_induction_variable +class struct_nir_loop_info(Structure): + pass + +class struct_hash_table(Structure): + pass + +struct_nir_loop_info._pack_ = 1 # source:False +struct_nir_loop_info._fields_ = [ + ('instr_cost', ctypes.c_uint32), + ('has_soft_fp64', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('guessed_trip_count', ctypes.c_uint32), + ('max_trip_count', ctypes.c_uint32), + ('exact_trip_count_known', ctypes.c_bool), + ('force_unroll', ctypes.c_bool), + ('complex_loop', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 5), + ('limiting_terminator', ctypes.POINTER(struct_nir_loop_terminator)), + ('loop_terminator_list', struct_list_head), + ('induction_vars', ctypes.POINTER(struct_hash_table)), +] + +class struct_hash_entry(Structure): + pass + +struct_hash_table._pack_ = 1 # source:False +struct_hash_table._fields_ = [ + ('table', ctypes.POINTER(struct_hash_entry)), + ('key_hash_function', ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(None))), + ('key_equals_function', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(None), ctypes.POINTER(None))), + ('deleted_key', ctypes.POINTER(None)), + ('size', ctypes.c_uint32), + ('rehash', ctypes.c_uint32), + ('size_magic', ctypes.c_uint64), + ('rehash_magic', ctypes.c_uint64), + ('max_entries', ctypes.c_uint32), + ('size_index', ctypes.c_uint32), + ('entries', ctypes.c_uint32), + ('deleted_entries', ctypes.c_uint32), +] + +struct_hash_entry._pack_ = 1 # source:False +struct_hash_entry._fields_ = [ + ('hash', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('key', ctypes.POINTER(None)), + ('data', ctypes.POINTER(None)), +] + +nir_loop_info = struct_nir_loop_info + +# values for enumeration 'c__EA_nir_loop_control' +c__EA_nir_loop_control__enumvalues = { + 0: 'nir_loop_control_none', + 1: 'nir_loop_control_unroll', + 2: 'nir_loop_control_dont_unroll', +} +nir_loop_control_none = 0 +nir_loop_control_unroll = 1 +nir_loop_control_dont_unroll = 2 +c__EA_nir_loop_control = ctypes.c_uint32 # enum +nir_loop_control = c__EA_nir_loop_control +nir_loop_control__enumvalues = c__EA_nir_loop_control__enumvalues +class struct_nir_loop(Structure): + pass + +struct_nir_loop._pack_ = 1 # source:False +struct_nir_loop._fields_ = [ + ('cf_node', nir_cf_node), + ('body', struct_exec_list), + ('continue_list', struct_exec_list), + ('info', ctypes.POINTER(struct_nir_loop_info)), + ('control', nir_loop_control), + ('partially_unrolled', ctypes.c_bool), + ('divergent_continue', ctypes.c_bool), + ('divergent_break', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte), +] + +nir_loop = struct_nir_loop +try: + nir_loop_is_divergent = _libraries['FIXME_STUB'].nir_loop_is_divergent + nir_loop_is_divergent.restype = ctypes.c_bool + nir_loop_is_divergent.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +nir_metadata = c__EA_nir_metadata +nir_metadata__enumvalues = c__EA_nir_metadata__enumvalues +nir_function_impl = struct_nir_function_impl +try: + nir_start_block = _libraries['FIXME_STUB'].nir_start_block + nir_start_block.restype = ctypes.POINTER(struct_nir_block) + nir_start_block.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_impl_last_block = _libraries['FIXME_STUB'].nir_impl_last_block + nir_impl_last_block.restype = ctypes.POINTER(struct_nir_block) + nir_impl_last_block.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_cf_node_next = _libraries['FIXME_STUB'].nir_cf_node_next + nir_cf_node_next.restype = ctypes.POINTER(struct_nir_cf_node) + nir_cf_node_next.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_prev = _libraries['FIXME_STUB'].nir_cf_node_prev + nir_cf_node_prev.restype = ctypes.POINTER(struct_nir_cf_node) + nir_cf_node_prev.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_is_first = _libraries['FIXME_STUB'].nir_cf_node_is_first + nir_cf_node_is_first.restype = ctypes.c_bool + nir_cf_node_is_first.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_is_last = _libraries['FIXME_STUB'].nir_cf_node_is_last + nir_cf_node_is_last.restype = ctypes.c_bool + nir_cf_node_is_last.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_as_block = _libraries['FIXME_STUB'].nir_cf_node_as_block + nir_cf_node_as_block.restype = ctypes.POINTER(struct_nir_block) + nir_cf_node_as_block.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_as_if = _libraries['FIXME_STUB'].nir_cf_node_as_if + nir_cf_node_as_if.restype = ctypes.POINTER(struct_nir_if) + nir_cf_node_as_if.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_as_loop = _libraries['FIXME_STUB'].nir_cf_node_as_loop + nir_cf_node_as_loop.restype = ctypes.POINTER(struct_nir_loop) + nir_cf_node_as_loop.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_as_function = _libraries['FIXME_STUB'].nir_cf_node_as_function + nir_cf_node_as_function.restype = ctypes.POINTER(struct_nir_function_impl) + nir_cf_node_as_function.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_if_first_then_block = _libraries['FIXME_STUB'].nir_if_first_then_block + nir_if_first_then_block.restype = ctypes.POINTER(struct_nir_block) + nir_if_first_then_block.argtypes = [ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_if_last_then_block = _libraries['FIXME_STUB'].nir_if_last_then_block + nir_if_last_then_block.restype = ctypes.POINTER(struct_nir_block) + nir_if_last_then_block.argtypes = [ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_if_first_else_block = _libraries['FIXME_STUB'].nir_if_first_else_block + nir_if_first_else_block.restype = ctypes.POINTER(struct_nir_block) + nir_if_first_else_block.argtypes = [ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_if_last_else_block = _libraries['FIXME_STUB'].nir_if_last_else_block + nir_if_last_else_block.restype = ctypes.POINTER(struct_nir_block) + nir_if_last_else_block.argtypes = [ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_loop_first_block = _libraries['FIXME_STUB'].nir_loop_first_block + nir_loop_first_block.restype = ctypes.POINTER(struct_nir_block) + nir_loop_first_block.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_loop_last_block = _libraries['FIXME_STUB'].nir_loop_last_block + nir_loop_last_block.restype = ctypes.POINTER(struct_nir_block) + nir_loop_last_block.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_loop_has_continue_construct = _libraries['FIXME_STUB'].nir_loop_has_continue_construct + nir_loop_has_continue_construct.restype = ctypes.c_bool + nir_loop_has_continue_construct.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_loop_first_continue_block = _libraries['FIXME_STUB'].nir_loop_first_continue_block + nir_loop_first_continue_block.restype = ctypes.POINTER(struct_nir_block) + nir_loop_first_continue_block.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_loop_last_continue_block = _libraries['FIXME_STUB'].nir_loop_last_continue_block + nir_loop_last_continue_block.restype = ctypes.POINTER(struct_nir_block) + nir_loop_last_continue_block.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_loop_continue_target = _libraries['FIXME_STUB'].nir_loop_continue_target + nir_loop_continue_target.restype = ctypes.POINTER(struct_nir_block) + nir_loop_continue_target.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_cf_list_is_empty_block = _libraries['FIXME_STUB'].nir_cf_list_is_empty_block + nir_cf_list_is_empty_block.restype = ctypes.c_bool + nir_cf_list_is_empty_block.argtypes = [ctypes.POINTER(struct_exec_list)] +except AttributeError: + pass +nir_parameter = struct_nir_parameter +nir_function = struct_nir_function +nir_intrin_filter_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None)) +nir_vectorize_cb = ctypes.CFUNCTYPE(ctypes.c_ubyte, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)) +nir_shader = struct_nir_shader +try: + nir_foreach_function_with_impl_first = _libraries['FIXME_STUB'].nir_foreach_function_with_impl_first + nir_foreach_function_with_impl_first.restype = ctypes.POINTER(struct_nir_function) + nir_foreach_function_with_impl_first.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_foreach_function_with_impl_next = _libraries['FIXME_STUB'].nir_foreach_function_with_impl_next + nir_foreach_function_with_impl_next.restype = ctypes.POINTER(struct_nir_function_impl) + nir_foreach_function_with_impl_next.argtypes = [ctypes.POINTER(ctypes.POINTER(struct_nir_function))] +except AttributeError: + pass +try: + nir_shader_get_entrypoint = _libraries['FIXME_STUB'].nir_shader_get_entrypoint + nir_shader_get_entrypoint.restype = ctypes.POINTER(struct_nir_function_impl) + nir_shader_get_entrypoint.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_shader_get_function_for_name = _libraries['FIXME_STUB'].nir_shader_get_function_for_name + nir_shader_get_function_for_name.restype = ctypes.POINTER(struct_nir_function) + nir_shader_get_function_for_name.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_remove_non_entrypoints = _libraries['libtinymesa_cpu.so'].nir_remove_non_entrypoints + nir_remove_non_entrypoints.restype = None + nir_remove_non_entrypoints.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_remove_non_exported = _libraries['libtinymesa_cpu.so'].nir_remove_non_exported + nir_remove_non_exported.restype = None + nir_remove_non_exported.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_remove_entrypoints = _libraries['libtinymesa_cpu.so'].nir_remove_entrypoints + nir_remove_entrypoints.restype = None + nir_remove_entrypoints.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_fixup_is_exported = _libraries['libtinymesa_cpu.so'].nir_fixup_is_exported + nir_fixup_is_exported.restype = None + nir_fixup_is_exported.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +gl_shader_stage = pipe_shader_type +gl_shader_stage__enumvalues = pipe_shader_type__enumvalues +try: + nir_shader_create = _libraries['libtinymesa_cpu.so'].nir_shader_create + nir_shader_create.restype = ctypes.POINTER(struct_nir_shader) + nir_shader_create.argtypes = [ctypes.POINTER(None), gl_shader_stage, ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(struct_shader_info)] +except AttributeError: + pass +try: + nir_shader_add_variable = _libraries['libtinymesa_cpu.so'].nir_shader_add_variable + nir_shader_add_variable.restype = None + nir_shader_add_variable.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_function_impl_add_variable = _libraries['FIXME_STUB'].nir_function_impl_add_variable + nir_function_impl_add_variable.restype = None + nir_function_impl_add_variable.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_variable_create = _libraries['libtinymesa_cpu.so'].nir_variable_create + nir_variable_create.restype = ctypes.POINTER(struct_nir_variable) + nir_variable_create.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_local_variable_create = _libraries['libtinymesa_cpu.so'].nir_local_variable_create + nir_local_variable_create.restype = ctypes.POINTER(struct_nir_variable) + nir_local_variable_create.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_state_variable_create = _libraries['libtinymesa_cpu.so'].nir_state_variable_create + nir_state_variable_create.restype = ctypes.POINTER(struct_nir_variable) + nir_state_variable_create.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_glsl_type), ctypes.POINTER(ctypes.c_char), ctypes.c_int16 * 4] +except AttributeError: + pass +try: + nir_get_variable_with_location = _libraries['libtinymesa_cpu.so'].nir_get_variable_with_location + nir_get_variable_with_location.restype = ctypes.POINTER(struct_nir_variable) + nir_get_variable_with_location.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.c_int32, ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + nir_create_variable_with_location = _libraries['libtinymesa_cpu.so'].nir_create_variable_with_location + nir_create_variable_with_location.restype = ctypes.POINTER(struct_nir_variable) + nir_create_variable_with_location.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.c_int32, ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + nir_find_variable_with_location = _libraries['libtinymesa_cpu.so'].nir_find_variable_with_location + nir_find_variable_with_location.restype = ctypes.POINTER(struct_nir_variable) + nir_find_variable_with_location.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_find_variable_with_driver_location = _libraries['libtinymesa_cpu.so'].nir_find_variable_with_driver_location + nir_find_variable_with_driver_location.restype = ctypes.POINTER(struct_nir_variable) + nir_find_variable_with_driver_location.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_find_state_variable = _libraries['libtinymesa_cpu.so'].nir_find_state_variable + nir_find_state_variable.restype = ctypes.POINTER(struct_nir_variable) + nir_find_state_variable.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_int16 * 4] +except AttributeError: + pass +try: + nir_find_sampler_variable_with_tex_index = _libraries['libtinymesa_cpu.so'].nir_find_sampler_variable_with_tex_index + nir_find_sampler_variable_with_tex_index.restype = ctypes.POINTER(struct_nir_variable) + nir_find_sampler_variable_with_tex_index.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_sort_variables_with_modes = _libraries['libtinymesa_cpu.so'].nir_sort_variables_with_modes + nir_sort_variables_with_modes.restype = None + nir_sort_variables_with_modes.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.CFUNCTYPE(ctypes.c_int32, ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_variable)), nir_variable_mode] +except AttributeError: + pass +try: + nir_function_create = _libraries['libtinymesa_cpu.so'].nir_function_create + nir_function_create.restype = ctypes.POINTER(struct_nir_function) + nir_function_create.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_function_set_impl = _libraries['FIXME_STUB'].nir_function_set_impl + nir_function_set_impl.restype = None + nir_function_set_impl.argtypes = [ctypes.POINTER(struct_nir_function), ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_function_impl_create = _libraries['libtinymesa_cpu.so'].nir_function_impl_create + nir_function_impl_create.restype = ctypes.POINTER(struct_nir_function_impl) + nir_function_impl_create.argtypes = [ctypes.POINTER(struct_nir_function)] +except AttributeError: + pass +try: + nir_function_impl_create_bare = _libraries['libtinymesa_cpu.so'].nir_function_impl_create_bare + nir_function_impl_create_bare.restype = ctypes.POINTER(struct_nir_function_impl) + nir_function_impl_create_bare.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_block_create = _libraries['libtinymesa_cpu.so'].nir_block_create + nir_block_create.restype = ctypes.POINTER(struct_nir_block) + nir_block_create.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_if_create = _libraries['libtinymesa_cpu.so'].nir_if_create + nir_if_create.restype = ctypes.POINTER(struct_nir_if) + nir_if_create.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_loop_create = _libraries['libtinymesa_cpu.so'].nir_loop_create + nir_loop_create.restype = ctypes.POINTER(struct_nir_loop) + nir_loop_create.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_cf_node_get_function = _libraries['libtinymesa_cpu.so'].nir_cf_node_get_function + nir_cf_node_get_function.restype = ctypes.POINTER(struct_nir_function_impl) + nir_cf_node_get_function.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_metadata_require = _libraries['libtinymesa_cpu.so'].nir_metadata_require + nir_metadata_require.restype = None + nir_metadata_require.argtypes = [ctypes.POINTER(struct_nir_function_impl), nir_metadata] +except AttributeError: + pass +try: + nir_shader_preserve_all_metadata = _libraries['libtinymesa_cpu.so'].nir_shader_preserve_all_metadata + nir_shader_preserve_all_metadata.restype = None + nir_shader_preserve_all_metadata.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_metadata_invalidate = _libraries['libtinymesa_cpu.so'].nir_metadata_invalidate + nir_metadata_invalidate.restype = None + nir_metadata_invalidate.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_progress = _libraries['libtinymesa_cpu.so'].nir_progress + nir_progress.restype = ctypes.c_bool + nir_progress.argtypes = [ctypes.c_bool, ctypes.POINTER(struct_nir_function_impl), nir_metadata] +except AttributeError: + pass +try: + nir_no_progress = _libraries['FIXME_STUB'].nir_no_progress + nir_no_progress.restype = ctypes.c_bool + nir_no_progress.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_alu_instr_create = _libraries['libtinymesa_cpu.so'].nir_alu_instr_create + nir_alu_instr_create.restype = ctypes.POINTER(struct_nir_alu_instr) + nir_alu_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), nir_op] +except AttributeError: + pass +try: + nir_deref_instr_create = _libraries['libtinymesa_cpu.so'].nir_deref_instr_create + nir_deref_instr_create.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_deref_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), nir_deref_type] +except AttributeError: + pass +try: + nir_jump_instr_create = _libraries['libtinymesa_cpu.so'].nir_jump_instr_create + nir_jump_instr_create.restype = ctypes.POINTER(struct_nir_jump_instr) + nir_jump_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), nir_jump_type] +except AttributeError: + pass +try: + nir_load_const_instr_create = _libraries['libtinymesa_cpu.so'].nir_load_const_instr_create + nir_load_const_instr_create.restype = ctypes.POINTER(struct_nir_load_const_instr) + nir_load_const_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_intrinsic_instr_create = _libraries['libtinymesa_cpu.so'].nir_intrinsic_instr_create + nir_intrinsic_instr_create.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_intrinsic_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), nir_intrinsic_op] +except AttributeError: + pass +try: + nir_call_instr_create = _libraries['libtinymesa_cpu.so'].nir_call_instr_create + nir_call_instr_create.restype = ctypes.POINTER(struct_nir_call_instr) + nir_call_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function)] +except AttributeError: + pass +try: + nir_tex_instr_create = _libraries['libtinymesa_cpu.so'].nir_tex_instr_create + nir_tex_instr_create.restype = ctypes.POINTER(struct_nir_tex_instr) + nir_tex_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_phi_instr_create = _libraries['libtinymesa_cpu.so'].nir_phi_instr_create + nir_phi_instr_create.restype = ctypes.POINTER(struct_nir_phi_instr) + nir_phi_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_phi_instr_add_src = _libraries['libtinymesa_cpu.so'].nir_phi_instr_add_src + nir_phi_instr_add_src.restype = ctypes.POINTER(struct_nir_phi_src) + nir_phi_instr_add_src.argtypes = [ctypes.POINTER(struct_nir_phi_instr), ctypes.POINTER(struct_nir_block), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_parallel_copy_instr_create = _libraries['libtinymesa_cpu.so'].nir_parallel_copy_instr_create + nir_parallel_copy_instr_create.restype = ctypes.POINTER(struct_nir_parallel_copy_instr) + nir_parallel_copy_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_undef_instr_create = _libraries['libtinymesa_cpu.so'].nir_undef_instr_create + nir_undef_instr_create.restype = ctypes.POINTER(struct_nir_undef_instr) + nir_undef_instr_create.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_alu_binop_identity = _libraries['libtinymesa_cpu.so'].nir_alu_binop_identity + nir_alu_binop_identity.restype = nir_const_value + nir_alu_binop_identity.argtypes = [nir_op, ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_cursor_option' +c__EA_nir_cursor_option__enumvalues = { + 0: 'nir_cursor_before_block', + 1: 'nir_cursor_after_block', + 2: 'nir_cursor_before_instr', + 3: 'nir_cursor_after_instr', +} +nir_cursor_before_block = 0 +nir_cursor_after_block = 1 +nir_cursor_before_instr = 2 +nir_cursor_after_instr = 3 +c__EA_nir_cursor_option = ctypes.c_uint32 # enum +nir_cursor_option = c__EA_nir_cursor_option +nir_cursor_option__enumvalues = c__EA_nir_cursor_option__enumvalues +class struct_nir_cursor(Structure): + pass + +class union_nir_cursor_0(Union): + pass + +union_nir_cursor_0._pack_ = 1 # source:False +union_nir_cursor_0._fields_ = [ + ('block', ctypes.POINTER(struct_nir_block)), + ('instr', ctypes.POINTER(struct_nir_instr)), +] + +struct_nir_cursor._pack_ = 1 # source:False +struct_nir_cursor._anonymous_ = ('_0',) +struct_nir_cursor._fields_ = [ + ('option', nir_cursor_option), + ('PADDING_0', ctypes.c_ubyte * 4), + ('_0', union_nir_cursor_0), +] + +nir_cursor = struct_nir_cursor +try: + nir_cursor_current_block = _libraries['FIXME_STUB'].nir_cursor_current_block + nir_cursor_current_block.restype = ctypes.POINTER(struct_nir_block) + nir_cursor_current_block.argtypes = [nir_cursor] +except AttributeError: + pass +try: + nir_cursors_equal = _libraries['libtinymesa_cpu.so'].nir_cursors_equal + nir_cursors_equal.restype = ctypes.c_bool + nir_cursors_equal.argtypes = [nir_cursor, nir_cursor] +except AttributeError: + pass +try: + nir_before_block = _libraries['FIXME_STUB'].nir_before_block + nir_before_block.restype = nir_cursor + nir_before_block.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_after_block = _libraries['FIXME_STUB'].nir_after_block + nir_after_block.restype = nir_cursor + nir_after_block.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_before_instr = _libraries['FIXME_STUB'].nir_before_instr + nir_before_instr.restype = nir_cursor + nir_before_instr.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_after_instr = _libraries['FIXME_STUB'].nir_after_instr + nir_after_instr.restype = nir_cursor + nir_after_instr.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_before_block_after_phis = _libraries['FIXME_STUB'].nir_before_block_after_phis + nir_before_block_after_phis.restype = nir_cursor + nir_before_block_after_phis.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_after_block_before_jump = _libraries['FIXME_STUB'].nir_after_block_before_jump + nir_after_block_before_jump.restype = nir_cursor + nir_after_block_before_jump.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_before_src = _libraries['FIXME_STUB'].nir_before_src + nir_before_src.restype = nir_cursor + nir_before_src.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_before_cf_node = _libraries['FIXME_STUB'].nir_before_cf_node + nir_before_cf_node.restype = nir_cursor + nir_before_cf_node.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_after_cf_node = _libraries['FIXME_STUB'].nir_after_cf_node + nir_after_cf_node.restype = nir_cursor + nir_after_cf_node.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_after_phis = _libraries['FIXME_STUB'].nir_after_phis + nir_after_phis.restype = nir_cursor + nir_after_phis.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_after_instr_and_phis = _libraries['FIXME_STUB'].nir_after_instr_and_phis + nir_after_instr_and_phis.restype = nir_cursor + nir_after_instr_and_phis.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_after_cf_node_and_phis = _libraries['FIXME_STUB'].nir_after_cf_node_and_phis + nir_after_cf_node_and_phis.restype = nir_cursor + nir_after_cf_node_and_phis.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_before_cf_list = _libraries['FIXME_STUB'].nir_before_cf_list + nir_before_cf_list.restype = nir_cursor + nir_before_cf_list.argtypes = [ctypes.POINTER(struct_exec_list)] +except AttributeError: + pass +try: + nir_after_cf_list = _libraries['FIXME_STUB'].nir_after_cf_list + nir_after_cf_list.restype = nir_cursor + nir_after_cf_list.argtypes = [ctypes.POINTER(struct_exec_list)] +except AttributeError: + pass +try: + nir_before_impl = _libraries['FIXME_STUB'].nir_before_impl + nir_before_impl.restype = nir_cursor + nir_before_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_after_impl = _libraries['FIXME_STUB'].nir_after_impl + nir_after_impl.restype = nir_cursor + nir_after_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_instr_insert = _libraries['libtinymesa_cpu.so'].nir_instr_insert + nir_instr_insert.restype = None + nir_instr_insert.argtypes = [nir_cursor, ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_move = _libraries['libtinymesa_cpu.so'].nir_instr_move + nir_instr_move.restype = ctypes.c_bool + nir_instr_move.argtypes = [nir_cursor, ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_before = _libraries['FIXME_STUB'].nir_instr_insert_before + nir_instr_insert_before.restype = None + nir_instr_insert_before.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_after = _libraries['FIXME_STUB'].nir_instr_insert_after + nir_instr_insert_after.restype = None + nir_instr_insert_after.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_before_block = _libraries['FIXME_STUB'].nir_instr_insert_before_block + nir_instr_insert_before_block.restype = None + nir_instr_insert_before_block.argtypes = [ctypes.POINTER(struct_nir_block), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_after_block = _libraries['FIXME_STUB'].nir_instr_insert_after_block + nir_instr_insert_after_block.restype = None + nir_instr_insert_after_block.argtypes = [ctypes.POINTER(struct_nir_block), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_before_cf = _libraries['FIXME_STUB'].nir_instr_insert_before_cf + nir_instr_insert_before_cf.restype = None + nir_instr_insert_before_cf.argtypes = [ctypes.POINTER(struct_nir_cf_node), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_after_cf = _libraries['FIXME_STUB'].nir_instr_insert_after_cf + nir_instr_insert_after_cf.restype = None + nir_instr_insert_after_cf.argtypes = [ctypes.POINTER(struct_nir_cf_node), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_before_cf_list = _libraries['FIXME_STUB'].nir_instr_insert_before_cf_list + nir_instr_insert_before_cf_list.restype = None + nir_instr_insert_before_cf_list.argtypes = [ctypes.POINTER(struct_exec_list), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_insert_after_cf_list = _libraries['FIXME_STUB'].nir_instr_insert_after_cf_list + nir_instr_insert_after_cf_list.restype = None + nir_instr_insert_after_cf_list.argtypes = [ctypes.POINTER(struct_exec_list), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_remove_v = _libraries['libtinymesa_cpu.so'].nir_instr_remove_v + nir_instr_remove_v.restype = None + nir_instr_remove_v.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_free = _libraries['libtinymesa_cpu.so'].nir_instr_free + nir_instr_free.restype = None + nir_instr_free.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_free_list = _libraries['libtinymesa_cpu.so'].nir_instr_free_list + nir_instr_free_list.restype = None + nir_instr_free_list.argtypes = [ctypes.POINTER(struct_exec_list)] +except AttributeError: + pass +try: + nir_instr_remove = _libraries['FIXME_STUB'].nir_instr_remove + nir_instr_remove.restype = nir_cursor + nir_instr_remove.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_free_and_dce = _libraries['libtinymesa_cpu.so'].nir_instr_free_and_dce + nir_instr_free_and_dce.restype = nir_cursor + nir_instr_free_and_dce.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_def = _libraries['libtinymesa_cpu.so'].nir_instr_def + nir_instr_def.restype = ctypes.POINTER(struct_nir_def) + nir_instr_def.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_get_debug_info = _libraries['FIXME_STUB'].nir_instr_get_debug_info + nir_instr_get_debug_info.restype = ctypes.POINTER(struct_nir_instr_debug_info) + nir_instr_get_debug_info.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_get_gc_pointer = _libraries['FIXME_STUB'].nir_instr_get_gc_pointer + nir_instr_get_gc_pointer.restype = ctypes.POINTER(None) + nir_instr_get_gc_pointer.argtypes = [ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +nir_foreach_def_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_def), ctypes.POINTER(None)) +nir_foreach_src_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_src), ctypes.POINTER(None)) +try: + nir_foreach_src = _libraries['FIXME_STUB'].nir_foreach_src + nir_foreach_src.restype = ctypes.c_bool + nir_foreach_src.argtypes = [ctypes.POINTER(struct_nir_instr), nir_foreach_src_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_foreach_phi_src_leaving_block = _libraries['libtinymesa_cpu.so'].nir_foreach_phi_src_leaving_block + nir_foreach_phi_src_leaving_block.restype = ctypes.c_bool + nir_foreach_phi_src_leaving_block.argtypes = [ctypes.POINTER(struct_nir_block), nir_foreach_src_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_src_as_const_value = _libraries['libtinymesa_cpu.so'].nir_src_as_const_value + nir_src_as_const_value.restype = ctypes.POINTER(union_c__UA_nir_const_value) + nir_src_as_const_value.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_as_alu_instr = _libraries['FIXME_STUB'].nir_src_as_alu_instr + nir_src_as_alu_instr.restype = ctypes.POINTER(struct_nir_alu_instr) + nir_src_as_alu_instr.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_as_intrinsic = _libraries['FIXME_STUB'].nir_src_as_intrinsic + nir_src_as_intrinsic.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_src_as_intrinsic.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_as_string = _libraries['FIXME_STUB'].nir_src_as_string + nir_src_as_string.restype = ctypes.POINTER(ctypes.c_char) + nir_src_as_string.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_src_is_always_uniform = _libraries['libtinymesa_cpu.so'].nir_src_is_always_uniform + nir_src_is_always_uniform.restype = ctypes.c_bool + nir_src_is_always_uniform.argtypes = [nir_src] +except AttributeError: + pass +try: + nir_srcs_equal = _libraries['libtinymesa_cpu.so'].nir_srcs_equal + nir_srcs_equal.restype = ctypes.c_bool + nir_srcs_equal.argtypes = [nir_src, nir_src] +except AttributeError: + pass +try: + nir_instrs_equal = _libraries['libtinymesa_cpu.so'].nir_instrs_equal + nir_instrs_equal.restype = ctypes.c_bool + nir_instrs_equal.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_src_get_block = _libraries['libtinymesa_cpu.so'].nir_src_get_block + nir_src_get_block.restype = ctypes.POINTER(struct_nir_block) + nir_src_get_block.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_src_rewrite = _libraries['FIXME_STUB'].nir_src_rewrite + nir_src_rewrite.restype = None + nir_src_rewrite.argtypes = [ctypes.POINTER(struct_nir_src), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_instr_init_src = _libraries['libtinymesa_cpu.so'].nir_instr_init_src + nir_instr_init_src.restype = None + nir_instr_init_src.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_src), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_instr_clear_src = _libraries['libtinymesa_cpu.so'].nir_instr_clear_src + nir_instr_clear_src.restype = None + nir_instr_clear_src.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_instr_move_src = _libraries['libtinymesa_cpu.so'].nir_instr_move_src + nir_instr_move_src.restype = None + nir_instr_move_src.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_src), ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_instr_is_before = _libraries['libtinymesa_cpu.so'].nir_instr_is_before + nir_instr_is_before.restype = ctypes.c_bool + nir_instr_is_before.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_def_init = _libraries['libtinymesa_cpu.so'].nir_def_init + nir_def_init.restype = None + nir_def_init.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_def_init_for_type = _libraries['FIXME_STUB'].nir_def_init_for_type + nir_def_init_for_type.restype = None + nir_def_init_for_type.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + nir_def_rewrite_uses = _libraries['libtinymesa_cpu.so'].nir_def_rewrite_uses + nir_def_rewrite_uses.restype = None + nir_def_rewrite_uses.argtypes = [ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_rewrite_uses_src = _libraries['libtinymesa_cpu.so'].nir_def_rewrite_uses_src + nir_def_rewrite_uses_src.restype = None + nir_def_rewrite_uses_src.argtypes = [ctypes.POINTER(struct_nir_def), nir_src] +except AttributeError: + pass +try: + nir_def_rewrite_uses_after = _libraries['libtinymesa_cpu.so'].nir_def_rewrite_uses_after + nir_def_rewrite_uses_after.restype = None + nir_def_rewrite_uses_after.argtypes = [ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_def_replace = _libraries['FIXME_STUB'].nir_def_replace + nir_def_replace.restype = None + nir_def_replace.argtypes = [ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_src_components_read = _libraries['libtinymesa_cpu.so'].nir_src_components_read + nir_src_components_read.restype = nir_component_mask_t + nir_src_components_read.argtypes = [ctypes.POINTER(struct_nir_src)] +except AttributeError: + pass +try: + nir_def_components_read = _libraries['libtinymesa_cpu.so'].nir_def_components_read + nir_def_components_read.restype = nir_component_mask_t + nir_def_components_read.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_all_uses_are_fsat = _libraries['libtinymesa_cpu.so'].nir_def_all_uses_are_fsat + nir_def_all_uses_are_fsat.restype = ctypes.c_bool + nir_def_all_uses_are_fsat.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_all_uses_ignore_sign_bit = _libraries['libtinymesa_cpu.so'].nir_def_all_uses_ignore_sign_bit + nir_def_all_uses_ignore_sign_bit.restype = ctypes.c_bool + nir_def_all_uses_ignore_sign_bit.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_first_component_read = _libraries['FIXME_STUB'].nir_def_first_component_read + nir_def_first_component_read.restype = ctypes.c_int32 + nir_def_first_component_read.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_last_component_read = _libraries['FIXME_STUB'].nir_def_last_component_read + nir_def_last_component_read.restype = ctypes.c_int32 + nir_def_last_component_read.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_def_is_unused = _libraries['FIXME_STUB'].nir_def_is_unused + nir_def_is_unused.restype = ctypes.c_bool + nir_def_is_unused.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_sort_unstructured_blocks = _libraries['libtinymesa_cpu.so'].nir_sort_unstructured_blocks + nir_sort_unstructured_blocks.restype = None + nir_sort_unstructured_blocks.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_block_unstructured_next = _libraries['libtinymesa_cpu.so'].nir_block_unstructured_next + nir_block_unstructured_next.restype = ctypes.POINTER(struct_nir_block) + nir_block_unstructured_next.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_unstructured_start_block = _libraries['libtinymesa_cpu.so'].nir_unstructured_start_block + nir_unstructured_start_block.restype = ctypes.POINTER(struct_nir_block) + nir_unstructured_start_block.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_block_cf_tree_next = _libraries['libtinymesa_cpu.so'].nir_block_cf_tree_next + nir_block_cf_tree_next.restype = ctypes.POINTER(struct_nir_block) + nir_block_cf_tree_next.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_cf_tree_prev = _libraries['libtinymesa_cpu.so'].nir_block_cf_tree_prev + nir_block_cf_tree_prev.restype = ctypes.POINTER(struct_nir_block) + nir_block_cf_tree_prev.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_cf_node_cf_tree_first = _libraries['libtinymesa_cpu.so'].nir_cf_node_cf_tree_first + nir_cf_node_cf_tree_first.restype = ctypes.POINTER(struct_nir_block) + nir_cf_node_cf_tree_first.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_cf_tree_last = _libraries['libtinymesa_cpu.so'].nir_cf_node_cf_tree_last + nir_cf_node_cf_tree_last.restype = ctypes.POINTER(struct_nir_block) + nir_cf_node_cf_tree_last.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_cf_tree_next = _libraries['libtinymesa_cpu.so'].nir_cf_node_cf_tree_next + nir_cf_node_cf_tree_next.restype = ctypes.POINTER(struct_nir_block) + nir_cf_node_cf_tree_next.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_cf_node_cf_tree_prev = _libraries['libtinymesa_cpu.so'].nir_cf_node_cf_tree_prev + nir_cf_node_cf_tree_prev.restype = ctypes.POINTER(struct_nir_block) + nir_cf_node_cf_tree_prev.argtypes = [ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_block_get_following_if = _libraries['libtinymesa_cpu.so'].nir_block_get_following_if + nir_block_get_following_if.restype = ctypes.POINTER(struct_nir_if) + nir_block_get_following_if.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_get_following_loop = _libraries['libtinymesa_cpu.so'].nir_block_get_following_loop + nir_block_get_following_loop.restype = ctypes.POINTER(struct_nir_loop) + nir_block_get_following_loop.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_get_predecessors_sorted = _libraries['libtinymesa_cpu.so'].nir_block_get_predecessors_sorted + nir_block_get_predecessors_sorted.restype = ctypes.POINTER(ctypes.POINTER(struct_nir_block)) + nir_block_get_predecessors_sorted.argtypes = [ctypes.POINTER(struct_nir_block), ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_index_ssa_defs = _libraries['libtinymesa_cpu.so'].nir_index_ssa_defs + nir_index_ssa_defs.restype = None + nir_index_ssa_defs.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_index_instrs = _libraries['libtinymesa_cpu.so'].nir_index_instrs + nir_index_instrs.restype = ctypes.c_uint32 + nir_index_instrs.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_index_blocks = _libraries['libtinymesa_cpu.so'].nir_index_blocks + nir_index_blocks.restype = None + nir_index_blocks.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_shader_clear_pass_flags = _libraries['libtinymesa_cpu.so'].nir_shader_clear_pass_flags + nir_shader_clear_pass_flags.restype = None + nir_shader_clear_pass_flags.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_shader_index_vars = _libraries['libtinymesa_cpu.so'].nir_shader_index_vars + nir_shader_index_vars.restype = ctypes.c_uint32 + nir_shader_index_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_function_impl_index_vars = _libraries['libtinymesa_cpu.so'].nir_function_impl_index_vars + nir_function_impl_index_vars.restype = ctypes.c_uint32 + nir_function_impl_index_vars.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_print_shader = _libraries['libtinymesa_cpu.so'].nir_print_shader + nir_print_shader.restype = None + nir_print_shader.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_print_function_body = _libraries['libtinymesa_cpu.so'].nir_print_function_body + nir_print_function_body.restype = None + nir_print_function_body.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_print_shader_annotated = _libraries['libtinymesa_cpu.so'].nir_print_shader_annotated + nir_print_shader_annotated.restype = None + nir_print_shader_annotated.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct__IO_FILE), ctypes.POINTER(struct_hash_table)] +except AttributeError: + pass +try: + nir_print_instr = _libraries['libtinymesa_cpu.so'].nir_print_instr + nir_print_instr.restype = None + nir_print_instr.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_print_deref = _libraries['libtinymesa_cpu.so'].nir_print_deref + nir_print_deref.restype = None + nir_print_deref.argtypes = [ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass + +# values for enumeration 'mesa_log_level' +mesa_log_level__enumvalues = { + 0: 'MESA_LOG_ERROR', + 1: 'MESA_LOG_WARN', + 2: 'MESA_LOG_INFO', + 3: 'MESA_LOG_DEBUG', +} +MESA_LOG_ERROR = 0 +MESA_LOG_WARN = 1 +MESA_LOG_INFO = 2 +MESA_LOG_DEBUG = 3 +mesa_log_level = ctypes.c_uint32 # enum +try: + nir_log_shader_annotated_tagged = _libraries['libtinymesa_cpu.so'].nir_log_shader_annotated_tagged + nir_log_shader_annotated_tagged.restype = None + nir_log_shader_annotated_tagged.argtypes = [mesa_log_level, ctypes.POINTER(ctypes.c_char), ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_hash_table)] +except AttributeError: + pass +try: + nir_shader_as_str = _libraries['libtinymesa_cpu.so'].nir_shader_as_str + nir_shader_as_str.restype = ctypes.POINTER(ctypes.c_char) + nir_shader_as_str.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_as_str_annotated = _libraries['libtinymesa_cpu.so'].nir_shader_as_str_annotated + nir_shader_as_str_annotated.restype = ctypes.POINTER(ctypes.c_char) + nir_shader_as_str_annotated.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_hash_table), ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_instr_as_str = _libraries['libtinymesa_cpu.so'].nir_instr_as_str + nir_instr_as_str.restype = ctypes.POINTER(ctypes.c_char) + nir_instr_as_str.argtypes = [ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_gather_debug_info = _libraries['libtinymesa_cpu.so'].nir_shader_gather_debug_info + nir_shader_gather_debug_info.restype = ctypes.POINTER(ctypes.c_char) + nir_shader_gather_debug_info.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_char), uint32_t] +except AttributeError: + pass +try: + nir_instr_clone = _libraries['libtinymesa_cpu.so'].nir_instr_clone + nir_instr_clone.restype = ctypes.POINTER(struct_nir_instr) + nir_instr_clone.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_clone_deep = _libraries['libtinymesa_cpu.so'].nir_instr_clone_deep + nir_instr_clone_deep.restype = ctypes.POINTER(struct_nir_instr) + nir_instr_clone_deep.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_hash_table)] +except AttributeError: + pass +try: + nir_alu_instr_clone = _libraries['libtinymesa_cpu.so'].nir_alu_instr_clone + nir_alu_instr_clone.restype = ctypes.POINTER(struct_nir_alu_instr) + nir_alu_instr_clone.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_shader_clone = _libraries['libtinymesa_cpu.so'].nir_shader_clone + nir_shader_clone.restype = ctypes.POINTER(struct_nir_shader) + nir_shader_clone.argtypes = [ctypes.POINTER(None), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_function_clone = _libraries['libtinymesa_cpu.so'].nir_function_clone + nir_function_clone.restype = ctypes.POINTER(struct_nir_function) + nir_function_clone.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function)] +except AttributeError: + pass +try: + nir_function_impl_clone = _libraries['libtinymesa_cpu.so'].nir_function_impl_clone + nir_function_impl_clone.restype = ctypes.POINTER(struct_nir_function_impl) + nir_function_impl_clone.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_function_impl_clone_remap_globals = _libraries['libtinymesa_cpu.so'].nir_function_impl_clone_remap_globals + nir_function_impl_clone_remap_globals.restype = ctypes.POINTER(struct_nir_function_impl) + nir_function_impl_clone_remap_globals.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct_hash_table)] +except AttributeError: + pass +try: + nir_constant_clone = _libraries['libtinymesa_cpu.so'].nir_constant_clone + nir_constant_clone.restype = ctypes.POINTER(struct_nir_constant) + nir_constant_clone.argtypes = [ctypes.POINTER(struct_nir_constant), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_variable_clone = _libraries['libtinymesa_cpu.so'].nir_variable_clone + nir_variable_clone.restype = ctypes.POINTER(struct_nir_variable) + nir_variable_clone.argtypes = [ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_shader_replace = _libraries['libtinymesa_cpu.so'].nir_shader_replace + nir_shader_replace.restype = None + nir_shader_replace.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_shader_serialize_deserialize = _libraries['libtinymesa_cpu.so'].nir_shader_serialize_deserialize + nir_shader_serialize_deserialize.restype = None + nir_shader_serialize_deserialize.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_validate_shader = _libraries['libtinymesa_cpu.so'].nir_validate_shader + nir_validate_shader.restype = None + nir_validate_shader.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_validate_ssa_dominance = _libraries['libtinymesa_cpu.so'].nir_validate_ssa_dominance + nir_validate_ssa_dominance.restype = None + nir_validate_ssa_dominance.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_metadata_set_validation_flag = _libraries['libtinymesa_cpu.so'].nir_metadata_set_validation_flag + nir_metadata_set_validation_flag.restype = None + nir_metadata_set_validation_flag.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_metadata_check_validation_flag = _libraries['libtinymesa_cpu.so'].nir_metadata_check_validation_flag + nir_metadata_check_validation_flag.restype = None + nir_metadata_check_validation_flag.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_metadata_require_all = _libraries['libtinymesa_cpu.so'].nir_metadata_require_all + nir_metadata_require_all.restype = None + nir_metadata_require_all.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + should_skip_nir = _libraries['FIXME_STUB'].should_skip_nir + should_skip_nir.restype = ctypes.c_bool + should_skip_nir.argtypes = [ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + should_print_nir = _libraries['FIXME_STUB'].should_print_nir + should_print_nir.restype = ctypes.c_bool + should_print_nir.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +nir_instr_writemask_filter_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.c_uint32, ctypes.POINTER(None)) +class struct_nir_builder(Structure): + pass + +struct_nir_builder._fields_ = [ + ('cursor', nir_cursor), + ('exact', ctypes.c_bool), + ('fp_fast_math', ctypes.c_uint32), + ('shader', ctypes.POINTER(struct_nir_shader)), + ('impl', ctypes.POINTER(struct_nir_function_impl)), +] + +nir_lower_instr_cb = ctypes.CFUNCTYPE(ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)) +try: + nir_function_impl_lower_instructions = _libraries['libtinymesa_cpu.so'].nir_function_impl_lower_instructions + nir_function_impl_lower_instructions.restype = ctypes.c_bool + nir_function_impl_lower_instructions.argtypes = [ctypes.POINTER(struct_nir_function_impl), nir_instr_filter_cb, nir_lower_instr_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_lower_instructions = _libraries['libtinymesa_cpu.so'].nir_shader_lower_instructions + nir_shader_lower_instructions.restype = ctypes.c_bool + nir_shader_lower_instructions.argtypes = [ctypes.POINTER(struct_nir_shader), nir_instr_filter_cb, nir_lower_instr_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_calc_dominance_impl = _libraries['libtinymesa_cpu.so'].nir_calc_dominance_impl + nir_calc_dominance_impl.restype = None + nir_calc_dominance_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_calc_dominance = _libraries['libtinymesa_cpu.so'].nir_calc_dominance + nir_calc_dominance.restype = None + nir_calc_dominance.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_dominance_lca = _libraries['libtinymesa_cpu.so'].nir_dominance_lca + nir_dominance_lca.restype = ctypes.POINTER(struct_nir_block) + nir_dominance_lca.argtypes = [ctypes.POINTER(struct_nir_block), ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_dominates = _libraries['libtinymesa_cpu.so'].nir_block_dominates + nir_block_dominates.restype = ctypes.c_bool + nir_block_dominates.argtypes = [ctypes.POINTER(struct_nir_block), ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_block_is_unreachable = _libraries['libtinymesa_cpu.so'].nir_block_is_unreachable + nir_block_is_unreachable.restype = ctypes.c_bool + nir_block_is_unreachable.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_dump_dom_tree_impl = _libraries['libtinymesa_cpu.so'].nir_dump_dom_tree_impl + nir_dump_dom_tree_impl.restype = None + nir_dump_dom_tree_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_dump_dom_tree = _libraries['libtinymesa_cpu.so'].nir_dump_dom_tree + nir_dump_dom_tree.restype = None + nir_dump_dom_tree.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_dump_dom_frontier_impl = _libraries['libtinymesa_cpu.so'].nir_dump_dom_frontier_impl + nir_dump_dom_frontier_impl.restype = None + nir_dump_dom_frontier_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_dump_dom_frontier = _libraries['libtinymesa_cpu.so'].nir_dump_dom_frontier + nir_dump_dom_frontier.restype = None + nir_dump_dom_frontier.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_dump_cfg_impl = _libraries['libtinymesa_cpu.so'].nir_dump_cfg_impl + nir_dump_cfg_impl.restype = None + nir_dump_cfg_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_dump_cfg = _libraries['libtinymesa_cpu.so'].nir_dump_cfg + nir_dump_cfg.restype = None + nir_dump_cfg.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +try: + nir_gs_count_vertices_and_primitives = _libraries['libtinymesa_cpu.so'].nir_gs_count_vertices_and_primitives + nir_gs_count_vertices_and_primitives.restype = None + nir_gs_count_vertices_and_primitives.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_int32), ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_load_grouping' +c__EA_nir_load_grouping__enumvalues = { + 0: 'nir_group_all', + 1: 'nir_group_same_resource_only', +} +nir_group_all = 0 +nir_group_same_resource_only = 1 +c__EA_nir_load_grouping = ctypes.c_uint32 # enum +nir_load_grouping = c__EA_nir_load_grouping +nir_load_grouping__enumvalues = c__EA_nir_load_grouping__enumvalues +try: + nir_group_loads = _libraries['libtinymesa_cpu.so'].nir_group_loads + nir_group_loads.restype = ctypes.c_bool + nir_group_loads.argtypes = [ctypes.POINTER(struct_nir_shader), nir_load_grouping, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_shrink_vec_array_vars = _libraries['libtinymesa_cpu.so'].nir_shrink_vec_array_vars + nir_shrink_vec_array_vars.restype = ctypes.c_bool + nir_shrink_vec_array_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_split_array_vars = _libraries['libtinymesa_cpu.so'].nir_split_array_vars + nir_split_array_vars.restype = ctypes.c_bool + nir_split_array_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_split_var_copies = _libraries['libtinymesa_cpu.so'].nir_split_var_copies + nir_split_var_copies.restype = ctypes.c_bool + nir_split_var_copies.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_split_per_member_structs = _libraries['libtinymesa_cpu.so'].nir_split_per_member_structs + nir_split_per_member_structs.restype = ctypes.c_bool + nir_split_per_member_structs.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_split_struct_vars = _libraries['libtinymesa_cpu.so'].nir_split_struct_vars + nir_split_struct_vars.restype = ctypes.c_bool + nir_split_struct_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_returns_impl = _libraries['libtinymesa_cpu.so'].nir_lower_returns_impl + nir_lower_returns_impl.restype = ctypes.c_bool + nir_lower_returns_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_lower_returns = _libraries['libtinymesa_cpu.so'].nir_lower_returns + nir_lower_returns.restype = ctypes.c_bool + nir_lower_returns.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_inline_function_impl = _libraries['libtinymesa_cpu.so'].nir_inline_function_impl + nir_inline_function_impl.restype = ctypes.POINTER(struct_nir_def) + nir_inline_function_impl.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(ctypes.POINTER(struct_nir_def)), ctypes.POINTER(struct_hash_table)] +except AttributeError: + pass +try: + nir_inline_functions = _libraries['libtinymesa_cpu.so'].nir_inline_functions + nir_inline_functions.restype = ctypes.c_bool + nir_inline_functions.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_cleanup_functions = _libraries['libtinymesa_cpu.so'].nir_cleanup_functions + nir_cleanup_functions.restype = None + nir_cleanup_functions.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_link_shader_functions = _libraries['libtinymesa_cpu.so'].nir_link_shader_functions + nir_link_shader_functions.restype = ctypes.c_bool + nir_link_shader_functions.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_calls_to_builtins = _libraries['libtinymesa_cpu.so'].nir_lower_calls_to_builtins + nir_lower_calls_to_builtins.restype = ctypes.c_bool + nir_lower_calls_to_builtins.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_find_inlinable_uniforms = _libraries['libtinymesa_cpu.so'].nir_find_inlinable_uniforms + nir_find_inlinable_uniforms.restype = None + nir_find_inlinable_uniforms.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_inline_uniforms = _libraries['libtinymesa_cpu.so'].nir_inline_uniforms + nir_inline_uniforms.restype = ctypes.c_bool + nir_inline_uniforms.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint16)] +except AttributeError: + pass +try: + nir_collect_src_uniforms = _libraries['libtinymesa_cpu.so'].nir_collect_src_uniforms + nir_collect_src_uniforms.restype = ctypes.c_bool + nir_collect_src_uniforms.argtypes = [ctypes.POINTER(struct_nir_src), ctypes.c_int32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_add_inlinable_uniforms = _libraries['libtinymesa_cpu.so'].nir_add_inlinable_uniforms + nir_add_inlinable_uniforms.restype = None + nir_add_inlinable_uniforms.argtypes = [ctypes.POINTER(struct_nir_src), ctypes.POINTER(struct_nir_loop_info), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_propagate_invariant = _libraries['libtinymesa_cpu.so'].nir_propagate_invariant + nir_propagate_invariant.restype = ctypes.c_bool + nir_propagate_invariant.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_var_copy_instr = _libraries['FIXME_STUB'].nir_lower_var_copy_instr + nir_lower_var_copy_instr.restype = None + nir_lower_var_copy_instr.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_deref_copy_instr = _libraries['libtinymesa_cpu.so'].nir_lower_deref_copy_instr + nir_lower_deref_copy_instr.restype = None + nir_lower_deref_copy_instr.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_lower_var_copies = _libraries['libtinymesa_cpu.so'].nir_lower_var_copies + nir_lower_var_copies.restype = ctypes.c_bool + nir_lower_var_copies.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_memcpy = _libraries['libtinymesa_cpu.so'].nir_opt_memcpy + nir_opt_memcpy.restype = ctypes.c_bool + nir_opt_memcpy.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_memcpy = _libraries['libtinymesa_cpu.so'].nir_lower_memcpy + nir_lower_memcpy.restype = ctypes.c_bool + nir_lower_memcpy.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_fixup_deref_modes = _libraries['libtinymesa_cpu.so'].nir_fixup_deref_modes + nir_fixup_deref_modes.restype = ctypes.c_bool + nir_fixup_deref_modes.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_fixup_deref_types = _libraries['libtinymesa_cpu.so'].nir_fixup_deref_types + nir_fixup_deref_types.restype = ctypes.c_bool + nir_fixup_deref_types.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_global_vars_to_local = _libraries['libtinymesa_cpu.so'].nir_lower_global_vars_to_local + nir_lower_global_vars_to_local.restype = ctypes.c_bool + nir_lower_global_vars_to_local.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_constant_to_temp = _libraries['libtinymesa_cpu.so'].nir_lower_constant_to_temp + nir_lower_constant_to_temp.restype = None + nir_lower_constant_to_temp.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_array_deref_of_vec_options' +c__EA_nir_lower_array_deref_of_vec_options__enumvalues = { + 1: 'nir_lower_direct_array_deref_of_vec_load', + 2: 'nir_lower_indirect_array_deref_of_vec_load', + 4: 'nir_lower_direct_array_deref_of_vec_store', + 8: 'nir_lower_indirect_array_deref_of_vec_store', +} +nir_lower_direct_array_deref_of_vec_load = 1 +nir_lower_indirect_array_deref_of_vec_load = 2 +nir_lower_direct_array_deref_of_vec_store = 4 +nir_lower_indirect_array_deref_of_vec_store = 8 +c__EA_nir_lower_array_deref_of_vec_options = ctypes.c_uint32 # enum +nir_lower_array_deref_of_vec_options = c__EA_nir_lower_array_deref_of_vec_options +nir_lower_array_deref_of_vec_options__enumvalues = c__EA_nir_lower_array_deref_of_vec_options__enumvalues +try: + nir_lower_array_deref_of_vec = _libraries['libtinymesa_cpu.so'].nir_lower_array_deref_of_vec + nir_lower_array_deref_of_vec.restype = ctypes.c_bool + nir_lower_array_deref_of_vec.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_variable)), nir_lower_array_deref_of_vec_options] +except AttributeError: + pass +try: + nir_lower_indirect_derefs = _libraries['libtinymesa_cpu.so'].nir_lower_indirect_derefs + nir_lower_indirect_derefs.restype = ctypes.c_bool + nir_lower_indirect_derefs.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, uint32_t] +except AttributeError: + pass +try: + nir_lower_indirect_var_derefs = _libraries['libtinymesa_cpu.so'].nir_lower_indirect_var_derefs + nir_lower_indirect_var_derefs.restype = ctypes.c_bool + nir_lower_indirect_var_derefs.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_set)] +except AttributeError: + pass +try: + nir_lower_locals_to_regs = _libraries['libtinymesa_cpu.so'].nir_lower_locals_to_regs + nir_lower_locals_to_regs.restype = ctypes.c_bool + nir_lower_locals_to_regs.argtypes = [ctypes.POINTER(struct_nir_shader), uint8_t] +except AttributeError: + pass +try: + nir_lower_io_vars_to_temporaries = _libraries['libtinymesa_cpu.so'].nir_lower_io_vars_to_temporaries + nir_lower_io_vars_to_temporaries.restype = ctypes.c_bool + nir_lower_io_vars_to_temporaries.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function_impl), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_vars_to_scratch = _libraries['libtinymesa_cpu.so'].nir_lower_vars_to_scratch + nir_lower_vars_to_scratch.restype = ctypes.c_bool + nir_lower_vars_to_scratch.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.c_int32, glsl_type_size_align_func, glsl_type_size_align_func] +except AttributeError: + pass +try: + nir_lower_scratch_to_var = _libraries['libtinymesa_cpu.so'].nir_lower_scratch_to_var + nir_lower_scratch_to_var.restype = ctypes.c_bool + nir_lower_scratch_to_var.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_clip_halfz = _libraries['libtinymesa_cpu.so'].nir_lower_clip_halfz + nir_lower_clip_halfz.restype = ctypes.c_bool + nir_lower_clip_halfz.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_shader_gather_info = _libraries['libtinymesa_cpu.so'].nir_shader_gather_info + nir_shader_gather_info.restype = None + nir_shader_gather_info.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_gather_types = _libraries['libtinymesa_cpu.so'].nir_gather_types + nir_gather_types.restype = None + nir_gather_types.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + nir_remove_unused_varyings = _libraries['libtinymesa_cpu.so'].nir_remove_unused_varyings + nir_remove_unused_varyings.restype = ctypes.c_bool + nir_remove_unused_varyings.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_remove_unused_io_vars = _libraries['libtinymesa_cpu.so'].nir_remove_unused_io_vars + nir_remove_unused_io_vars.restype = ctypes.c_bool + nir_remove_unused_io_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_uint64)] +except AttributeError: + pass +try: + nir_compact_varyings = _libraries['libtinymesa_cpu.so'].nir_compact_varyings + nir_compact_varyings.restype = None + nir_compact_varyings.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_link_xfb_varyings = _libraries['libtinymesa_cpu.so'].nir_link_xfb_varyings + nir_link_xfb_varyings.restype = None + nir_link_xfb_varyings.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_link_opt_varyings = _libraries['libtinymesa_cpu.so'].nir_link_opt_varyings + nir_link_opt_varyings.restype = ctypes.c_bool + nir_link_opt_varyings.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_link_varying_precision = _libraries['libtinymesa_cpu.so'].nir_link_varying_precision + nir_link_varying_precision.restype = None + nir_link_varying_precision.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_clone_uniform_variable = _libraries['libtinymesa_cpu.so'].nir_clone_uniform_variable + nir_clone_uniform_variable.restype = ctypes.POINTER(struct_nir_variable) + nir_clone_uniform_variable.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_variable), ctypes.c_bool] +except AttributeError: + pass +try: + nir_clone_deref_instr = _libraries['libtinymesa_cpu.so'].nir_clone_deref_instr + nir_clone_deref_instr.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_clone_deref_instr.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_opt_varyings_progress' +c__EA_nir_opt_varyings_progress__enumvalues = { + 1: 'nir_progress_producer', + 2: 'nir_progress_consumer', +} +nir_progress_producer = 1 +nir_progress_consumer = 2 +c__EA_nir_opt_varyings_progress = ctypes.c_uint32 # enum +nir_opt_varyings_progress = c__EA_nir_opt_varyings_progress +nir_opt_varyings_progress__enumvalues = c__EA_nir_opt_varyings_progress__enumvalues +try: + nir_opt_varyings = _libraries['libtinymesa_cpu.so'].nir_opt_varyings + nir_opt_varyings.restype = nir_opt_varyings_progress + nir_opt_varyings.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader), ctypes.c_bool, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_bool] +except AttributeError: + pass + +# values for enumeration 'c__EA_gl_varying_slot' +c__EA_gl_varying_slot__enumvalues = { + 0: 'VARYING_SLOT_POS', + 1: 'VARYING_SLOT_COL0', + 2: 'VARYING_SLOT_COL1', + 3: 'VARYING_SLOT_FOGC', + 4: 'VARYING_SLOT_TEX0', + 5: 'VARYING_SLOT_TEX1', + 6: 'VARYING_SLOT_TEX2', + 7: 'VARYING_SLOT_TEX3', + 8: 'VARYING_SLOT_TEX4', + 9: 'VARYING_SLOT_TEX5', + 10: 'VARYING_SLOT_TEX6', + 11: 'VARYING_SLOT_TEX7', + 12: 'VARYING_SLOT_PSIZ', + 13: 'VARYING_SLOT_BFC0', + 14: 'VARYING_SLOT_BFC1', + 15: 'VARYING_SLOT_EDGE', + 16: 'VARYING_SLOT_CLIP_VERTEX', + 17: 'VARYING_SLOT_CLIP_DIST0', + 18: 'VARYING_SLOT_CLIP_DIST1', + 19: 'VARYING_SLOT_CULL_DIST0', + 20: 'VARYING_SLOT_CULL_DIST1', + 21: 'VARYING_SLOT_PRIMITIVE_ID', + 22: 'VARYING_SLOT_LAYER', + 23: 'VARYING_SLOT_VIEWPORT', + 24: 'VARYING_SLOT_FACE', + 25: 'VARYING_SLOT_PNTC', + 26: 'VARYING_SLOT_TESS_LEVEL_OUTER', + 27: 'VARYING_SLOT_TESS_LEVEL_INNER', + 28: 'VARYING_SLOT_BOUNDING_BOX0', + 29: 'VARYING_SLOT_BOUNDING_BOX1', + 30: 'VARYING_SLOT_VIEW_INDEX', + 31: 'VARYING_SLOT_VIEWPORT_MASK', + 24: 'VARYING_SLOT_PRIMITIVE_SHADING_RATE', + 26: 'VARYING_SLOT_PRIMITIVE_COUNT', + 27: 'VARYING_SLOT_PRIMITIVE_INDICES', + 28: 'VARYING_SLOT_TASK_COUNT', + 28: 'VARYING_SLOT_CULL_PRIMITIVE', + 32: 'VARYING_SLOT_VAR0', + 33: 'VARYING_SLOT_VAR1', + 34: 'VARYING_SLOT_VAR2', + 35: 'VARYING_SLOT_VAR3', + 36: 'VARYING_SLOT_VAR4', + 37: 'VARYING_SLOT_VAR5', + 38: 'VARYING_SLOT_VAR6', + 39: 'VARYING_SLOT_VAR7', + 40: 'VARYING_SLOT_VAR8', + 41: 'VARYING_SLOT_VAR9', + 42: 'VARYING_SLOT_VAR10', + 43: 'VARYING_SLOT_VAR11', + 44: 'VARYING_SLOT_VAR12', + 45: 'VARYING_SLOT_VAR13', + 46: 'VARYING_SLOT_VAR14', + 47: 'VARYING_SLOT_VAR15', + 48: 'VARYING_SLOT_VAR16', + 49: 'VARYING_SLOT_VAR17', + 50: 'VARYING_SLOT_VAR18', + 51: 'VARYING_SLOT_VAR19', + 52: 'VARYING_SLOT_VAR20', + 53: 'VARYING_SLOT_VAR21', + 54: 'VARYING_SLOT_VAR22', + 55: 'VARYING_SLOT_VAR23', + 56: 'VARYING_SLOT_VAR24', + 57: 'VARYING_SLOT_VAR25', + 58: 'VARYING_SLOT_VAR26', + 59: 'VARYING_SLOT_VAR27', + 60: 'VARYING_SLOT_VAR28', + 61: 'VARYING_SLOT_VAR29', + 62: 'VARYING_SLOT_VAR30', + 63: 'VARYING_SLOT_VAR31', + 64: 'VARYING_SLOT_PATCH0', + 65: 'VARYING_SLOT_PATCH1', + 66: 'VARYING_SLOT_PATCH2', + 67: 'VARYING_SLOT_PATCH3', + 68: 'VARYING_SLOT_PATCH4', + 69: 'VARYING_SLOT_PATCH5', + 70: 'VARYING_SLOT_PATCH6', + 71: 'VARYING_SLOT_PATCH7', + 72: 'VARYING_SLOT_PATCH8', + 73: 'VARYING_SLOT_PATCH9', + 74: 'VARYING_SLOT_PATCH10', + 75: 'VARYING_SLOT_PATCH11', + 76: 'VARYING_SLOT_PATCH12', + 77: 'VARYING_SLOT_PATCH13', + 78: 'VARYING_SLOT_PATCH14', + 79: 'VARYING_SLOT_PATCH15', + 80: 'VARYING_SLOT_PATCH16', + 81: 'VARYING_SLOT_PATCH17', + 82: 'VARYING_SLOT_PATCH18', + 83: 'VARYING_SLOT_PATCH19', + 84: 'VARYING_SLOT_PATCH20', + 85: 'VARYING_SLOT_PATCH21', + 86: 'VARYING_SLOT_PATCH22', + 87: 'VARYING_SLOT_PATCH23', + 88: 'VARYING_SLOT_PATCH24', + 89: 'VARYING_SLOT_PATCH25', + 90: 'VARYING_SLOT_PATCH26', + 91: 'VARYING_SLOT_PATCH27', + 92: 'VARYING_SLOT_PATCH28', + 93: 'VARYING_SLOT_PATCH29', + 94: 'VARYING_SLOT_PATCH30', + 95: 'VARYING_SLOT_PATCH31', + 96: 'VARYING_SLOT_VAR0_16BIT', + 97: 'VARYING_SLOT_VAR1_16BIT', + 98: 'VARYING_SLOT_VAR2_16BIT', + 99: 'VARYING_SLOT_VAR3_16BIT', + 100: 'VARYING_SLOT_VAR4_16BIT', + 101: 'VARYING_SLOT_VAR5_16BIT', + 102: 'VARYING_SLOT_VAR6_16BIT', + 103: 'VARYING_SLOT_VAR7_16BIT', + 104: 'VARYING_SLOT_VAR8_16BIT', + 105: 'VARYING_SLOT_VAR9_16BIT', + 106: 'VARYING_SLOT_VAR10_16BIT', + 107: 'VARYING_SLOT_VAR11_16BIT', + 108: 'VARYING_SLOT_VAR12_16BIT', + 109: 'VARYING_SLOT_VAR13_16BIT', + 110: 'VARYING_SLOT_VAR14_16BIT', + 111: 'VARYING_SLOT_VAR15_16BIT', + 112: 'NUM_TOTAL_VARYING_SLOTS', +} +VARYING_SLOT_POS = 0 +VARYING_SLOT_COL0 = 1 +VARYING_SLOT_COL1 = 2 +VARYING_SLOT_FOGC = 3 +VARYING_SLOT_TEX0 = 4 +VARYING_SLOT_TEX1 = 5 +VARYING_SLOT_TEX2 = 6 +VARYING_SLOT_TEX3 = 7 +VARYING_SLOT_TEX4 = 8 +VARYING_SLOT_TEX5 = 9 +VARYING_SLOT_TEX6 = 10 +VARYING_SLOT_TEX7 = 11 +VARYING_SLOT_PSIZ = 12 +VARYING_SLOT_BFC0 = 13 +VARYING_SLOT_BFC1 = 14 +VARYING_SLOT_EDGE = 15 +VARYING_SLOT_CLIP_VERTEX = 16 +VARYING_SLOT_CLIP_DIST0 = 17 +VARYING_SLOT_CLIP_DIST1 = 18 +VARYING_SLOT_CULL_DIST0 = 19 +VARYING_SLOT_CULL_DIST1 = 20 +VARYING_SLOT_PRIMITIVE_ID = 21 +VARYING_SLOT_LAYER = 22 +VARYING_SLOT_VIEWPORT = 23 +VARYING_SLOT_FACE = 24 +VARYING_SLOT_PNTC = 25 +VARYING_SLOT_TESS_LEVEL_OUTER = 26 +VARYING_SLOT_TESS_LEVEL_INNER = 27 +VARYING_SLOT_BOUNDING_BOX0 = 28 +VARYING_SLOT_BOUNDING_BOX1 = 29 +VARYING_SLOT_VIEW_INDEX = 30 +VARYING_SLOT_VIEWPORT_MASK = 31 +VARYING_SLOT_PRIMITIVE_SHADING_RATE = 24 +VARYING_SLOT_PRIMITIVE_COUNT = 26 +VARYING_SLOT_PRIMITIVE_INDICES = 27 +VARYING_SLOT_TASK_COUNT = 28 +VARYING_SLOT_CULL_PRIMITIVE = 28 +VARYING_SLOT_VAR0 = 32 +VARYING_SLOT_VAR1 = 33 +VARYING_SLOT_VAR2 = 34 +VARYING_SLOT_VAR3 = 35 +VARYING_SLOT_VAR4 = 36 +VARYING_SLOT_VAR5 = 37 +VARYING_SLOT_VAR6 = 38 +VARYING_SLOT_VAR7 = 39 +VARYING_SLOT_VAR8 = 40 +VARYING_SLOT_VAR9 = 41 +VARYING_SLOT_VAR10 = 42 +VARYING_SLOT_VAR11 = 43 +VARYING_SLOT_VAR12 = 44 +VARYING_SLOT_VAR13 = 45 +VARYING_SLOT_VAR14 = 46 +VARYING_SLOT_VAR15 = 47 +VARYING_SLOT_VAR16 = 48 +VARYING_SLOT_VAR17 = 49 +VARYING_SLOT_VAR18 = 50 +VARYING_SLOT_VAR19 = 51 +VARYING_SLOT_VAR20 = 52 +VARYING_SLOT_VAR21 = 53 +VARYING_SLOT_VAR22 = 54 +VARYING_SLOT_VAR23 = 55 +VARYING_SLOT_VAR24 = 56 +VARYING_SLOT_VAR25 = 57 +VARYING_SLOT_VAR26 = 58 +VARYING_SLOT_VAR27 = 59 +VARYING_SLOT_VAR28 = 60 +VARYING_SLOT_VAR29 = 61 +VARYING_SLOT_VAR30 = 62 +VARYING_SLOT_VAR31 = 63 +VARYING_SLOT_PATCH0 = 64 +VARYING_SLOT_PATCH1 = 65 +VARYING_SLOT_PATCH2 = 66 +VARYING_SLOT_PATCH3 = 67 +VARYING_SLOT_PATCH4 = 68 +VARYING_SLOT_PATCH5 = 69 +VARYING_SLOT_PATCH6 = 70 +VARYING_SLOT_PATCH7 = 71 +VARYING_SLOT_PATCH8 = 72 +VARYING_SLOT_PATCH9 = 73 +VARYING_SLOT_PATCH10 = 74 +VARYING_SLOT_PATCH11 = 75 +VARYING_SLOT_PATCH12 = 76 +VARYING_SLOT_PATCH13 = 77 +VARYING_SLOT_PATCH14 = 78 +VARYING_SLOT_PATCH15 = 79 +VARYING_SLOT_PATCH16 = 80 +VARYING_SLOT_PATCH17 = 81 +VARYING_SLOT_PATCH18 = 82 +VARYING_SLOT_PATCH19 = 83 +VARYING_SLOT_PATCH20 = 84 +VARYING_SLOT_PATCH21 = 85 +VARYING_SLOT_PATCH22 = 86 +VARYING_SLOT_PATCH23 = 87 +VARYING_SLOT_PATCH24 = 88 +VARYING_SLOT_PATCH25 = 89 +VARYING_SLOT_PATCH26 = 90 +VARYING_SLOT_PATCH27 = 91 +VARYING_SLOT_PATCH28 = 92 +VARYING_SLOT_PATCH29 = 93 +VARYING_SLOT_PATCH30 = 94 +VARYING_SLOT_PATCH31 = 95 +VARYING_SLOT_VAR0_16BIT = 96 +VARYING_SLOT_VAR1_16BIT = 97 +VARYING_SLOT_VAR2_16BIT = 98 +VARYING_SLOT_VAR3_16BIT = 99 +VARYING_SLOT_VAR4_16BIT = 100 +VARYING_SLOT_VAR5_16BIT = 101 +VARYING_SLOT_VAR6_16BIT = 102 +VARYING_SLOT_VAR7_16BIT = 103 +VARYING_SLOT_VAR8_16BIT = 104 +VARYING_SLOT_VAR9_16BIT = 105 +VARYING_SLOT_VAR10_16BIT = 106 +VARYING_SLOT_VAR11_16BIT = 107 +VARYING_SLOT_VAR12_16BIT = 108 +VARYING_SLOT_VAR13_16BIT = 109 +VARYING_SLOT_VAR14_16BIT = 110 +VARYING_SLOT_VAR15_16BIT = 111 +NUM_TOTAL_VARYING_SLOTS = 112 +c__EA_gl_varying_slot = ctypes.c_uint32 # enum +gl_varying_slot = c__EA_gl_varying_slot +gl_varying_slot__enumvalues = c__EA_gl_varying_slot__enumvalues +try: + nir_slot_is_sysval_output = _libraries['libtinymesa_cpu.so'].nir_slot_is_sysval_output + nir_slot_is_sysval_output.restype = ctypes.c_bool + nir_slot_is_sysval_output.argtypes = [gl_varying_slot, gl_shader_stage] +except AttributeError: + pass +try: + nir_slot_is_varying = _libraries['libtinymesa_cpu.so'].nir_slot_is_varying + nir_slot_is_varying.restype = ctypes.c_bool + nir_slot_is_varying.argtypes = [gl_varying_slot, gl_shader_stage] +except AttributeError: + pass +try: + nir_slot_is_sysval_output_and_varying = _libraries['libtinymesa_cpu.so'].nir_slot_is_sysval_output_and_varying + nir_slot_is_sysval_output_and_varying.restype = ctypes.c_bool + nir_slot_is_sysval_output_and_varying.argtypes = [gl_varying_slot, gl_shader_stage] +except AttributeError: + pass +try: + nir_remove_varying = _libraries['libtinymesa_cpu.so'].nir_remove_varying + nir_remove_varying.restype = ctypes.c_bool + nir_remove_varying.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), gl_shader_stage] +except AttributeError: + pass +try: + nir_remove_sysval_output = _libraries['libtinymesa_cpu.so'].nir_remove_sysval_output + nir_remove_sysval_output.restype = ctypes.c_bool + nir_remove_sysval_output.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), gl_shader_stage] +except AttributeError: + pass +try: + nir_lower_amul = _libraries['libtinymesa_cpu.so'].nir_lower_amul + nir_lower_amul.restype = ctypes.c_bool + nir_lower_amul.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.CFUNCTYPE(ctypes.c_int32, ctypes.POINTER(struct_glsl_type), ctypes.c_bool)] +except AttributeError: + pass +try: + nir_lower_ubo_vec4 = _libraries['libtinymesa_cpu.so'].nir_lower_ubo_vec4 + nir_lower_ubo_vec4.restype = ctypes.c_bool + nir_lower_ubo_vec4.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_sort_variables_by_location = _libraries['libtinymesa_cpu.so'].nir_sort_variables_by_location + nir_sort_variables_by_location.restype = None + nir_sort_variables_by_location.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_assign_io_var_locations = _libraries['libtinymesa_cpu.so'].nir_assign_io_var_locations + nir_assign_io_var_locations.restype = None + nir_assign_io_var_locations.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.POINTER(ctypes.c_uint32), gl_shader_stage] +except AttributeError: + pass +try: + nir_opt_clip_cull_const = _libraries['libtinymesa_cpu.so'].nir_opt_clip_cull_const + nir_opt_clip_cull_const.restype = ctypes.c_bool + nir_opt_clip_cull_const.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_io_options' +c__EA_nir_lower_io_options__enumvalues = { + 1: 'nir_lower_io_lower_64bit_to_32', + 2: 'nir_lower_io_lower_64bit_float_to_32', + 4: 'nir_lower_io_lower_64bit_to_32_new', + 8: 'nir_lower_io_use_interpolated_input_intrinsics', +} +nir_lower_io_lower_64bit_to_32 = 1 +nir_lower_io_lower_64bit_float_to_32 = 2 +nir_lower_io_lower_64bit_to_32_new = 4 +nir_lower_io_use_interpolated_input_intrinsics = 8 +c__EA_nir_lower_io_options = ctypes.c_uint32 # enum +nir_lower_io_options = c__EA_nir_lower_io_options +nir_lower_io_options__enumvalues = c__EA_nir_lower_io_options__enumvalues +try: + nir_lower_io = _libraries['libtinymesa_cpu.so'].nir_lower_io + nir_lower_io.restype = ctypes.c_bool + nir_lower_io.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.CFUNCTYPE(ctypes.c_int32, ctypes.POINTER(struct_glsl_type), ctypes.c_bool), nir_lower_io_options] +except AttributeError: + pass +try: + nir_io_add_const_offset_to_base = _libraries['libtinymesa_cpu.so'].nir_io_add_const_offset_to_base + nir_io_add_const_offset_to_base.restype = ctypes.c_bool + nir_io_add_const_offset_to_base.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_io_passes = _libraries['libtinymesa_cpu.so'].nir_lower_io_passes + nir_lower_io_passes.restype = None + nir_lower_io_passes.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_io_add_intrinsic_xfb_info = _libraries['libtinymesa_cpu.so'].nir_io_add_intrinsic_xfb_info + nir_io_add_intrinsic_xfb_info.restype = ctypes.c_bool + nir_io_add_intrinsic_xfb_info.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_io_indirect_loads = _libraries['libtinymesa_cpu.so'].nir_lower_io_indirect_loads + nir_lower_io_indirect_loads.restype = ctypes.c_bool + nir_lower_io_indirect_loads.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_vars_to_explicit_types = _libraries['libtinymesa_cpu.so'].nir_lower_vars_to_explicit_types + nir_lower_vars_to_explicit_types.restype = ctypes.c_bool + nir_lower_vars_to_explicit_types.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, glsl_type_size_align_func] +except AttributeError: + pass +try: + nir_gather_explicit_io_initializers = _libraries['libtinymesa_cpu.so'].nir_gather_explicit_io_initializers + nir_gather_explicit_io_initializers.restype = None + nir_gather_explicit_io_initializers.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(None), size_t, nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_vec3_to_vec4 = _libraries['libtinymesa_cpu.so'].nir_lower_vec3_to_vec4 + nir_lower_vec3_to_vec4.restype = ctypes.c_bool + nir_lower_vec3_to_vec4.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_address_format' +c__EA_nir_address_format__enumvalues = { + 0: 'nir_address_format_32bit_global', + 1: 'nir_address_format_64bit_global', + 2: 'nir_address_format_2x32bit_global', + 3: 'nir_address_format_64bit_global_32bit_offset', + 4: 'nir_address_format_64bit_bounded_global', + 5: 'nir_address_format_32bit_index_offset', + 6: 'nir_address_format_32bit_index_offset_pack64', + 7: 'nir_address_format_vec2_index_32bit_offset', + 8: 'nir_address_format_62bit_generic', + 9: 'nir_address_format_32bit_offset', + 10: 'nir_address_format_32bit_offset_as_64bit', + 11: 'nir_address_format_logical', +} +nir_address_format_32bit_global = 0 +nir_address_format_64bit_global = 1 +nir_address_format_2x32bit_global = 2 +nir_address_format_64bit_global_32bit_offset = 3 +nir_address_format_64bit_bounded_global = 4 +nir_address_format_32bit_index_offset = 5 +nir_address_format_32bit_index_offset_pack64 = 6 +nir_address_format_vec2_index_32bit_offset = 7 +nir_address_format_62bit_generic = 8 +nir_address_format_32bit_offset = 9 +nir_address_format_32bit_offset_as_64bit = 10 +nir_address_format_logical = 11 +c__EA_nir_address_format = ctypes.c_uint32 # enum +nir_address_format = c__EA_nir_address_format +nir_address_format__enumvalues = c__EA_nir_address_format__enumvalues +try: + nir_address_format_bit_size = _libraries['libtinymesa_cpu.so'].nir_address_format_bit_size + nir_address_format_bit_size.restype = ctypes.c_uint32 + nir_address_format_bit_size.argtypes = [nir_address_format] +except AttributeError: + pass +try: + nir_address_format_num_components = _libraries['libtinymesa_cpu.so'].nir_address_format_num_components + nir_address_format_num_components.restype = ctypes.c_uint32 + nir_address_format_num_components.argtypes = [nir_address_format] +except AttributeError: + pass +try: + nir_address_format_to_glsl_type = _libraries['FIXME_STUB'].nir_address_format_to_glsl_type + nir_address_format_to_glsl_type.restype = ctypes.POINTER(struct_glsl_type) + nir_address_format_to_glsl_type.argtypes = [nir_address_format] +except AttributeError: + pass +try: + nir_address_format_null_value = _libraries['libtinymesa_cpu.so'].nir_address_format_null_value + nir_address_format_null_value.restype = ctypes.POINTER(union_c__UA_nir_const_value) + nir_address_format_null_value.argtypes = [nir_address_format] +except AttributeError: + pass +try: + nir_build_addr_iadd = _libraries['libtinymesa_cpu.so'].nir_build_addr_iadd + nir_build_addr_iadd.restype = ctypes.POINTER(struct_nir_def) + nir_build_addr_iadd.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_address_format, nir_variable_mode, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_addr_iadd_imm = _libraries['libtinymesa_cpu.so'].nir_build_addr_iadd_imm + nir_build_addr_iadd_imm.restype = ctypes.POINTER(struct_nir_def) + nir_build_addr_iadd_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_address_format, nir_variable_mode, int64_t] +except AttributeError: + pass +try: + nir_build_addr_ieq = _libraries['libtinymesa_cpu.so'].nir_build_addr_ieq + nir_build_addr_ieq.restype = ctypes.POINTER(struct_nir_def) + nir_build_addr_ieq.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), nir_address_format] +except AttributeError: + pass +try: + nir_build_addr_isub = _libraries['libtinymesa_cpu.so'].nir_build_addr_isub + nir_build_addr_isub.restype = ctypes.POINTER(struct_nir_def) + nir_build_addr_isub.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), nir_address_format] +except AttributeError: + pass +try: + nir_explicit_io_address_from_deref = _libraries['libtinymesa_cpu.so'].nir_explicit_io_address_from_deref + nir_explicit_io_address_from_deref.restype = ctypes.POINTER(struct_nir_def) + nir_explicit_io_address_from_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), nir_address_format] +except AttributeError: + pass +try: + nir_get_explicit_deref_align = _libraries['libtinymesa_cpu.so'].nir_get_explicit_deref_align + nir_get_explicit_deref_align.restype = ctypes.c_bool + nir_get_explicit_deref_align.argtypes = [ctypes.POINTER(struct_nir_deref_instr), ctypes.c_bool, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + nir_lower_explicit_io_instr = _libraries['libtinymesa_cpu.so'].nir_lower_explicit_io_instr + nir_lower_explicit_io_instr.restype = None + nir_lower_explicit_io_instr.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_def), nir_address_format] +except AttributeError: + pass +try: + nir_lower_explicit_io = _libraries['libtinymesa_cpu.so'].nir_lower_explicit_io + nir_lower_explicit_io.restype = ctypes.c_bool + nir_lower_explicit_io.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, nir_address_format] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_mem_access_shift_method' +c__EA_nir_mem_access_shift_method__enumvalues = { + 0: 'nir_mem_access_shift_method_scalar', + 1: 'nir_mem_access_shift_method_shift64', + 2: 'nir_mem_access_shift_method_bytealign_amd', +} +nir_mem_access_shift_method_scalar = 0 +nir_mem_access_shift_method_shift64 = 1 +nir_mem_access_shift_method_bytealign_amd = 2 +c__EA_nir_mem_access_shift_method = ctypes.c_uint32 # enum +nir_mem_access_shift_method = c__EA_nir_mem_access_shift_method +nir_mem_access_shift_method__enumvalues = c__EA_nir_mem_access_shift_method__enumvalues +class struct_nir_mem_access_size_align(Structure): + pass + +struct_nir_mem_access_size_align._pack_ = 1 # source:False +struct_nir_mem_access_size_align._fields_ = [ + ('num_components', ctypes.c_ubyte), + ('bit_size', ctypes.c_ubyte), + ('align', ctypes.c_uint16), + ('shift', nir_mem_access_shift_method), +] + +nir_mem_access_size_align = struct_nir_mem_access_size_align + +# values for enumeration 'gl_access_qualifier' +gl_access_qualifier__enumvalues = { + 1: 'ACCESS_COHERENT', + 2: 'ACCESS_RESTRICT', + 4: 'ACCESS_VOLATILE', + 8: 'ACCESS_NON_READABLE', + 16: 'ACCESS_NON_WRITEABLE', + 32: 'ACCESS_NON_UNIFORM', + 64: 'ACCESS_CAN_REORDER', + 128: 'ACCESS_NON_TEMPORAL', + 256: 'ACCESS_INCLUDE_HELPERS', + 512: 'ACCESS_IS_SWIZZLED_AMD', + 1024: 'ACCESS_USES_FORMAT_AMD', + 2048: 'ACCESS_FMASK_LOWERED_AMD', + 4096: 'ACCESS_CAN_SPECULATE', + 8192: 'ACCESS_CP_GE_COHERENT_AMD', + 16384: 'ACCESS_IN_BOUNDS', + 32768: 'ACCESS_KEEP_SCALAR', + 65536: 'ACCESS_SMEM_AMD', +} +ACCESS_COHERENT = 1 +ACCESS_RESTRICT = 2 +ACCESS_VOLATILE = 4 +ACCESS_NON_READABLE = 8 +ACCESS_NON_WRITEABLE = 16 +ACCESS_NON_UNIFORM = 32 +ACCESS_CAN_REORDER = 64 +ACCESS_NON_TEMPORAL = 128 +ACCESS_INCLUDE_HELPERS = 256 +ACCESS_IS_SWIZZLED_AMD = 512 +ACCESS_USES_FORMAT_AMD = 1024 +ACCESS_FMASK_LOWERED_AMD = 2048 +ACCESS_CAN_SPECULATE = 4096 +ACCESS_CP_GE_COHERENT_AMD = 8192 +ACCESS_IN_BOUNDS = 16384 +ACCESS_KEEP_SCALAR = 32768 +ACCESS_SMEM_AMD = 65536 +gl_access_qualifier = ctypes.c_uint32 # enum +nir_lower_mem_access_bit_sizes_cb = ctypes.CFUNCTYPE(struct_nir_mem_access_size_align, c__EA_nir_intrinsic_op, ctypes.c_ubyte, ctypes.c_ubyte, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_bool, gl_access_qualifier, ctypes.POINTER(None)) +class struct_nir_lower_mem_access_bit_sizes_options(Structure): + pass + +struct_nir_lower_mem_access_bit_sizes_options._pack_ = 1 # source:False +struct_nir_lower_mem_access_bit_sizes_options._fields_ = [ + ('callback', ctypes.CFUNCTYPE(struct_nir_mem_access_size_align, c__EA_nir_intrinsic_op, ctypes.c_ubyte, ctypes.c_ubyte, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_bool, gl_access_qualifier, ctypes.POINTER(None))), + ('modes', nir_variable_mode), + ('may_lower_unaligned_stores_to_atomics', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('cb_data', ctypes.POINTER(None)), +] + +nir_lower_mem_access_bit_sizes_options = struct_nir_lower_mem_access_bit_sizes_options +try: + nir_lower_mem_access_bit_sizes = _libraries['libtinymesa_cpu.so'].nir_lower_mem_access_bit_sizes + nir_lower_mem_access_bit_sizes.restype = ctypes.c_bool + nir_lower_mem_access_bit_sizes.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_mem_access_bit_sizes_options)] +except AttributeError: + pass +try: + nir_lower_robust_access = _libraries['libtinymesa_cpu.so'].nir_lower_robust_access + nir_lower_robust_access.restype = ctypes.c_bool + nir_lower_robust_access.argtypes = [ctypes.POINTER(struct_nir_shader), nir_intrin_filter_cb, ctypes.POINTER(None)] +except AttributeError: + pass +nir_should_vectorize_mem_func = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_int64, ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None)) +class struct_nir_load_store_vectorize_options(Structure): + pass + +struct_nir_load_store_vectorize_options._pack_ = 1 # source:False +struct_nir_load_store_vectorize_options._fields_ = [ + ('callback', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_int64, ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None))), + ('modes', nir_variable_mode), + ('robust_modes', nir_variable_mode), + ('cb_data', ctypes.POINTER(None)), + ('has_shared2_amd', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), +] + +nir_load_store_vectorize_options = struct_nir_load_store_vectorize_options +try: + nir_opt_load_store_vectorize = _libraries['libtinymesa_cpu.so'].nir_opt_load_store_vectorize + nir_opt_load_store_vectorize.restype = ctypes.c_bool + nir_opt_load_store_vectorize.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_load_store_vectorize_options)] +except AttributeError: + pass +try: + nir_opt_load_store_update_alignments = _libraries['libtinymesa_cpu.so'].nir_opt_load_store_update_alignments + nir_opt_load_store_update_alignments.restype = ctypes.c_bool + nir_opt_load_store_update_alignments.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +nir_lower_shader_calls_should_remat_func = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)) +class struct_nir_lower_shader_calls_options(Structure): + pass + +struct_nir_lower_shader_calls_options._pack_ = 1 # source:False +struct_nir_lower_shader_calls_options._fields_ = [ + ('address_format', nir_address_format), + ('stack_alignment', ctypes.c_uint32), + ('localized_loads', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), + ('vectorizer_callback', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_int64, ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None))), + ('vectorizer_data', ctypes.POINTER(None)), + ('should_remat_callback', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('should_remat_data', ctypes.POINTER(None)), +] + +nir_lower_shader_calls_options = struct_nir_lower_shader_calls_options +try: + nir_lower_shader_calls = _libraries['libtinymesa_cpu.so'].nir_lower_shader_calls + nir_lower_shader_calls.restype = ctypes.c_bool + nir_lower_shader_calls.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_shader_calls_options), ctypes.POINTER(ctypes.POINTER(ctypes.POINTER(struct_nir_shader))), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_get_io_offset_src_number = _libraries['libtinymesa_cpu.so'].nir_get_io_offset_src_number + nir_get_io_offset_src_number.restype = ctypes.c_int32 + nir_get_io_offset_src_number.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_get_io_index_src_number = _libraries['libtinymesa_cpu.so'].nir_get_io_index_src_number + nir_get_io_index_src_number.restype = ctypes.c_int32 + nir_get_io_index_src_number.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_get_io_arrayed_index_src_number = _libraries['libtinymesa_cpu.so'].nir_get_io_arrayed_index_src_number + nir_get_io_arrayed_index_src_number.restype = ctypes.c_int32 + nir_get_io_arrayed_index_src_number.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_get_io_offset_src = _libraries['libtinymesa_cpu.so'].nir_get_io_offset_src + nir_get_io_offset_src.restype = ctypes.POINTER(struct_nir_src) + nir_get_io_offset_src.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_get_io_index_src = _libraries['libtinymesa_cpu.so'].nir_get_io_index_src + nir_get_io_index_src.restype = ctypes.POINTER(struct_nir_src) + nir_get_io_index_src.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_get_io_arrayed_index_src = _libraries['libtinymesa_cpu.so'].nir_get_io_arrayed_index_src + nir_get_io_arrayed_index_src.restype = ctypes.POINTER(struct_nir_src) + nir_get_io_arrayed_index_src.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_get_shader_call_payload_src = _libraries['libtinymesa_cpu.so'].nir_get_shader_call_payload_src + nir_get_shader_call_payload_src.restype = ctypes.POINTER(struct_nir_src) + nir_get_shader_call_payload_src.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_is_output_load = _libraries['libtinymesa_cpu.so'].nir_is_output_load + nir_is_output_load.restype = ctypes.c_bool + nir_is_output_load.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_is_arrayed_io = _libraries['libtinymesa_cpu.so'].nir_is_arrayed_io + nir_is_arrayed_io.restype = ctypes.c_bool + nir_is_arrayed_io.argtypes = [ctypes.POINTER(struct_nir_variable), gl_shader_stage] +except AttributeError: + pass +try: + nir_lower_reg_intrinsics_to_ssa_impl = _libraries['libtinymesa_cpu.so'].nir_lower_reg_intrinsics_to_ssa_impl + nir_lower_reg_intrinsics_to_ssa_impl.restype = ctypes.c_bool + nir_lower_reg_intrinsics_to_ssa_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_lower_reg_intrinsics_to_ssa = _libraries['libtinymesa_cpu.so'].nir_lower_reg_intrinsics_to_ssa + nir_lower_reg_intrinsics_to_ssa.restype = ctypes.c_bool + nir_lower_reg_intrinsics_to_ssa.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_vars_to_ssa = _libraries['libtinymesa_cpu.so'].nir_lower_vars_to_ssa + nir_lower_vars_to_ssa.restype = ctypes.c_bool + nir_lower_vars_to_ssa.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_remove_dead_derefs = _libraries['libtinymesa_cpu.so'].nir_remove_dead_derefs + nir_remove_dead_derefs.restype = ctypes.c_bool + nir_remove_dead_derefs.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_remove_dead_derefs_impl = _libraries['libtinymesa_cpu.so'].nir_remove_dead_derefs_impl + nir_remove_dead_derefs_impl.restype = ctypes.c_bool + nir_remove_dead_derefs_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +class struct_nir_remove_dead_variables_options(Structure): + pass + +struct_nir_remove_dead_variables_options._pack_ = 1 # source:False +struct_nir_remove_dead_variables_options._fields_ = [ + ('can_remove_var', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_variable), ctypes.POINTER(None))), + ('can_remove_var_data', ctypes.POINTER(None)), +] + +nir_remove_dead_variables_options = struct_nir_remove_dead_variables_options +try: + nir_remove_dead_variables = _libraries['libtinymesa_cpu.so'].nir_remove_dead_variables + nir_remove_dead_variables.restype = ctypes.c_bool + nir_remove_dead_variables.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.POINTER(struct_nir_remove_dead_variables_options)] +except AttributeError: + pass +try: + nir_lower_variable_initializers = _libraries['libtinymesa_cpu.so'].nir_lower_variable_initializers + nir_lower_variable_initializers.restype = ctypes.c_bool + nir_lower_variable_initializers.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_zero_initialize_shared_memory = _libraries['libtinymesa_cpu.so'].nir_zero_initialize_shared_memory + nir_zero_initialize_shared_memory.restype = ctypes.c_bool + nir_zero_initialize_shared_memory.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_clear_shared_memory = _libraries['libtinymesa_cpu.so'].nir_clear_shared_memory + nir_clear_shared_memory.restype = ctypes.c_bool + nir_clear_shared_memory.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_opt_move_to_top_options' +c__EA_nir_opt_move_to_top_options__enumvalues = { + 1: 'nir_move_to_entry_block_only', + 2: 'nir_move_to_top_input_loads', + 4: 'nir_move_to_top_load_smem_amd', +} +nir_move_to_entry_block_only = 1 +nir_move_to_top_input_loads = 2 +nir_move_to_top_load_smem_amd = 4 +c__EA_nir_opt_move_to_top_options = ctypes.c_uint32 # enum +nir_opt_move_to_top_options = c__EA_nir_opt_move_to_top_options +nir_opt_move_to_top_options__enumvalues = c__EA_nir_opt_move_to_top_options__enumvalues +try: + nir_opt_move_to_top = _libraries['libtinymesa_cpu.so'].nir_opt_move_to_top + nir_opt_move_to_top.restype = ctypes.c_bool + nir_opt_move_to_top.argtypes = [ctypes.POINTER(struct_nir_shader), nir_opt_move_to_top_options] +except AttributeError: + pass +try: + nir_move_vec_src_uses_to_dest = _libraries['libtinymesa_cpu.so'].nir_move_vec_src_uses_to_dest + nir_move_vec_src_uses_to_dest.restype = ctypes.c_bool + nir_move_vec_src_uses_to_dest.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_move_output_stores_to_end = _libraries['libtinymesa_cpu.so'].nir_move_output_stores_to_end + nir_move_output_stores_to_end.restype = ctypes.c_bool + nir_move_output_stores_to_end.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_vec_to_regs = _libraries['libtinymesa_cpu.so'].nir_lower_vec_to_regs + nir_lower_vec_to_regs.restype = ctypes.c_bool + nir_lower_vec_to_regs.argtypes = [ctypes.POINTER(struct_nir_shader), nir_instr_writemask_filter_cb, ctypes.POINTER(None)] +except AttributeError: + pass + +# values for enumeration 'compare_func' +compare_func__enumvalues = { + 0: 'COMPARE_FUNC_NEVER', + 1: 'COMPARE_FUNC_LESS', + 2: 'COMPARE_FUNC_EQUAL', + 3: 'COMPARE_FUNC_LEQUAL', + 4: 'COMPARE_FUNC_GREATER', + 5: 'COMPARE_FUNC_NOTEQUAL', + 6: 'COMPARE_FUNC_GEQUAL', + 7: 'COMPARE_FUNC_ALWAYS', +} +COMPARE_FUNC_NEVER = 0 +COMPARE_FUNC_LESS = 1 +COMPARE_FUNC_EQUAL = 2 +COMPARE_FUNC_LEQUAL = 3 +COMPARE_FUNC_GREATER = 4 +COMPARE_FUNC_NOTEQUAL = 5 +COMPARE_FUNC_GEQUAL = 6 +COMPARE_FUNC_ALWAYS = 7 +compare_func = ctypes.c_uint32 # enum +try: + nir_lower_alpha_test = _libraries['libtinymesa_cpu.so'].nir_lower_alpha_test + nir_lower_alpha_test.restype = ctypes.c_bool + nir_lower_alpha_test.argtypes = [ctypes.POINTER(struct_nir_shader), compare_func, ctypes.c_bool, ctypes.POINTER(ctypes.c_int16)] +except AttributeError: + pass +try: + nir_lower_alpha_to_coverage = _libraries['libtinymesa_cpu.so'].nir_lower_alpha_to_coverage + nir_lower_alpha_to_coverage.restype = ctypes.c_bool + nir_lower_alpha_to_coverage.argtypes = [ctypes.POINTER(struct_nir_shader), uint8_t, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_alpha_to_one = _libraries['libtinymesa_cpu.so'].nir_lower_alpha_to_one + nir_lower_alpha_to_one.restype = ctypes.c_bool + nir_lower_alpha_to_one.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_alu = _libraries['libtinymesa_cpu.so'].nir_lower_alu + nir_lower_alu.restype = ctypes.c_bool + nir_lower_alu.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_flrp = _libraries['libtinymesa_cpu.so'].nir_lower_flrp + nir_lower_flrp.restype = ctypes.c_bool + nir_lower_flrp.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_bool] +except AttributeError: + pass +try: + nir_scale_fdiv = _libraries['libtinymesa_cpu.so'].nir_scale_fdiv + nir_scale_fdiv.restype = ctypes.c_bool + nir_scale_fdiv.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_alu_to_scalar = _libraries['libtinymesa_cpu.so'].nir_lower_alu_to_scalar + nir_lower_alu_to_scalar.restype = ctypes.c_bool + nir_lower_alu_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader), nir_instr_filter_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_alu_width = _libraries['libtinymesa_cpu.so'].nir_lower_alu_width + nir_lower_alu_width.restype = ctypes.c_bool + nir_lower_alu_width.argtypes = [ctypes.POINTER(struct_nir_shader), nir_vectorize_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_alu_vec8_16_srcs = _libraries['libtinymesa_cpu.so'].nir_lower_alu_vec8_16_srcs + nir_lower_alu_vec8_16_srcs.restype = ctypes.c_bool + nir_lower_alu_vec8_16_srcs.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_bool_to_bitsize = _libraries['libtinymesa_cpu.so'].nir_lower_bool_to_bitsize + nir_lower_bool_to_bitsize.restype = ctypes.c_bool + nir_lower_bool_to_bitsize.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_bool_to_float = _libraries['libtinymesa_cpu.so'].nir_lower_bool_to_float + nir_lower_bool_to_float.restype = ctypes.c_bool + nir_lower_bool_to_float.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_bool_to_int32 = _libraries['libtinymesa_cpu.so'].nir_lower_bool_to_int32 + nir_lower_bool_to_int32.restype = ctypes.c_bool + nir_lower_bool_to_int32.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_simplify_convert_alu_types = _libraries['libtinymesa_cpu.so'].nir_opt_simplify_convert_alu_types + nir_opt_simplify_convert_alu_types.restype = ctypes.c_bool + nir_opt_simplify_convert_alu_types.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_const_arrays_to_uniforms = _libraries['libtinymesa_cpu.so'].nir_lower_const_arrays_to_uniforms + nir_lower_const_arrays_to_uniforms.restype = ctypes.c_bool + nir_lower_const_arrays_to_uniforms.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_lower_convert_alu_types = _libraries['libtinymesa_cpu.so'].nir_lower_convert_alu_types + nir_lower_convert_alu_types.restype = ctypes.c_bool + nir_lower_convert_alu_types.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_intrinsic_instr))] +except AttributeError: + pass +try: + nir_lower_constant_convert_alu_types = _libraries['libtinymesa_cpu.so'].nir_lower_constant_convert_alu_types + nir_lower_constant_convert_alu_types.restype = ctypes.c_bool + nir_lower_constant_convert_alu_types.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_alu_conversion_to_intrinsic = _libraries['libtinymesa_cpu.so'].nir_lower_alu_conversion_to_intrinsic + nir_lower_alu_conversion_to_intrinsic.restype = ctypes.c_bool + nir_lower_alu_conversion_to_intrinsic.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_int_to_float = _libraries['libtinymesa_cpu.so'].nir_lower_int_to_float + nir_lower_int_to_float.restype = ctypes.c_bool + nir_lower_int_to_float.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_load_const_to_scalar = _libraries['libtinymesa_cpu.so'].nir_lower_load_const_to_scalar + nir_lower_load_const_to_scalar.restype = ctypes.c_bool + nir_lower_load_const_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_read_invocation_to_scalar = _libraries['FIXME_STUB'].nir_lower_read_invocation_to_scalar + nir_lower_read_invocation_to_scalar.restype = ctypes.c_bool + nir_lower_read_invocation_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_phis_to_scalar = _libraries['libtinymesa_cpu.so'].nir_lower_phis_to_scalar + nir_lower_phis_to_scalar.restype = ctypes.c_bool + nir_lower_phis_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader), nir_vectorize_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_all_phis_to_scalar = _libraries['libtinymesa_cpu.so'].nir_lower_all_phis_to_scalar + nir_lower_all_phis_to_scalar.restype = ctypes.c_bool + nir_lower_all_phis_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_io_array_vars_to_elements = _libraries['libtinymesa_cpu.so'].nir_lower_io_array_vars_to_elements + nir_lower_io_array_vars_to_elements.restype = None + nir_lower_io_array_vars_to_elements.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_io_array_vars_to_elements_no_indirects = _libraries['libtinymesa_cpu.so'].nir_lower_io_array_vars_to_elements_no_indirects + nir_lower_io_array_vars_to_elements_no_indirects.restype = ctypes.c_bool + nir_lower_io_array_vars_to_elements_no_indirects.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_io_to_scalar = _libraries['libtinymesa_cpu.so'].nir_lower_io_to_scalar + nir_lower_io_to_scalar.restype = ctypes.c_bool + nir_lower_io_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, nir_instr_filter_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_io_vars_to_scalar = _libraries['libtinymesa_cpu.so'].nir_lower_io_vars_to_scalar + nir_lower_io_vars_to_scalar.restype = ctypes.c_bool + nir_lower_io_vars_to_scalar.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_opt_vectorize_io_vars = _libraries['libtinymesa_cpu.so'].nir_opt_vectorize_io_vars + nir_opt_vectorize_io_vars.restype = ctypes.c_bool + nir_opt_vectorize_io_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_tess_level_array_vars_to_vec = _libraries['libtinymesa_cpu.so'].nir_lower_tess_level_array_vars_to_vec + nir_lower_tess_level_array_vars_to_vec.restype = ctypes.c_bool + nir_lower_tess_level_array_vars_to_vec.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_create_passthrough_tcs_impl = _libraries['libtinymesa_cpu.so'].nir_create_passthrough_tcs_impl + nir_create_passthrough_tcs_impl.restype = ctypes.POINTER(struct_nir_shader) + nir_create_passthrough_tcs_impl.argtypes = [ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint32, uint8_t] +except AttributeError: + pass +try: + nir_create_passthrough_tcs = _libraries['libtinymesa_cpu.so'].nir_create_passthrough_tcs + nir_create_passthrough_tcs.restype = ctypes.POINTER(struct_nir_shader) + nir_create_passthrough_tcs.argtypes = [ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(struct_nir_shader), uint8_t] +except AttributeError: + pass +try: + nir_create_passthrough_gs = _libraries['libtinymesa_cpu.so'].nir_create_passthrough_gs + nir_create_passthrough_gs.restype = ctypes.POINTER(struct_nir_shader) + nir_create_passthrough_gs.argtypes = [ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(struct_nir_shader), mesa_prim, mesa_prim, ctypes.c_bool, ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_fragcolor = _libraries['libtinymesa_cpu.so'].nir_lower_fragcolor + nir_lower_fragcolor.restype = ctypes.c_bool + nir_lower_fragcolor.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_lower_fragcoord_wtrans = _libraries['libtinymesa_cpu.so'].nir_lower_fragcoord_wtrans + nir_lower_fragcoord_wtrans.restype = ctypes.c_bool + nir_lower_fragcoord_wtrans.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_frag_coord_to_pixel_coord = _libraries['libtinymesa_cpu.so'].nir_opt_frag_coord_to_pixel_coord + nir_opt_frag_coord_to_pixel_coord.restype = ctypes.c_bool + nir_opt_frag_coord_to_pixel_coord.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_frag_coord_to_pixel_coord = _libraries['libtinymesa_cpu.so'].nir_lower_frag_coord_to_pixel_coord + nir_lower_frag_coord_to_pixel_coord.restype = ctypes.c_bool + nir_lower_frag_coord_to_pixel_coord.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_viewport_transform = _libraries['libtinymesa_cpu.so'].nir_lower_viewport_transform + nir_lower_viewport_transform.restype = ctypes.c_bool + nir_lower_viewport_transform.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_uniforms_to_ubo = _libraries['libtinymesa_cpu.so'].nir_lower_uniforms_to_ubo + nir_lower_uniforms_to_ubo.restype = ctypes.c_bool + nir_lower_uniforms_to_ubo.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_is_helper_invocation = _libraries['libtinymesa_cpu.so'].nir_lower_is_helper_invocation + nir_lower_is_helper_invocation.restype = ctypes.c_bool + nir_lower_is_helper_invocation.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_single_sampled = _libraries['libtinymesa_cpu.so'].nir_lower_single_sampled + nir_lower_single_sampled.restype = ctypes.c_bool + nir_lower_single_sampled.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_atomics = _libraries['libtinymesa_cpu.so'].nir_lower_atomics + nir_lower_atomics.restype = ctypes.c_bool + nir_lower_atomics.argtypes = [ctypes.POINTER(struct_nir_shader), nir_instr_filter_cb] +except AttributeError: + pass +class struct_nir_lower_subgroups_options(Structure): + pass + +struct_nir_lower_subgroups_options._pack_ = 1 # source:False +struct_nir_lower_subgroups_options._fields_ = [ + ('filter', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('filter_data', ctypes.POINTER(None)), + ('subgroup_size', ctypes.c_ubyte), + ('ballot_bit_size', ctypes.c_ubyte), + ('ballot_components', ctypes.c_ubyte), + ('lower_to_scalar', ctypes.c_bool, 1), + ('lower_vote_trivial', ctypes.c_bool, 1), + ('lower_vote_feq', ctypes.c_bool, 1), + ('lower_vote_ieq', ctypes.c_bool, 1), + ('lower_vote_bool_eq', ctypes.c_bool, 1), + ('lower_first_invocation_to_ballot', ctypes.c_bool, 1), + ('lower_read_first_invocation', ctypes.c_bool, 1), + ('lower_subgroup_masks', ctypes.c_bool, 1), + ('lower_relative_shuffle', ctypes.c_bool, 1), + ('lower_shuffle_to_32bit', ctypes.c_bool, 1), + ('lower_shuffle_to_swizzle_amd', ctypes.c_bool, 1), + ('lower_shuffle', ctypes.c_bool, 1), + ('lower_quad', ctypes.c_bool, 1), + ('lower_quad_broadcast_dynamic', ctypes.c_bool, 1), + ('lower_quad_broadcast_dynamic_to_const', ctypes.c_bool, 1), + ('lower_quad_vote', ctypes.c_bool, 1), + ('lower_elect', ctypes.c_bool, 1), + ('lower_read_invocation_to_cond', ctypes.c_bool, 1), + ('lower_rotate_to_shuffle', ctypes.c_bool, 1), + ('lower_rotate_clustered_to_shuffle', ctypes.c_bool, 1), + ('lower_ballot_bit_count_to_mbcnt_amd', ctypes.c_bool, 1), + ('lower_inverse_ballot', ctypes.c_bool, 1), + ('lower_reduce', ctypes.c_bool, 1), + ('lower_boolean_reduce', ctypes.c_bool, 1), + ('lower_boolean_shuffle', ctypes.c_bool, 1), + ('PADDING_0', ctypes.c_uint16, 15), +] + +nir_lower_subgroups_options = struct_nir_lower_subgroups_options +try: + nir_lower_subgroups = _libraries['libtinymesa_cpu.so'].nir_lower_subgroups + nir_lower_subgroups.restype = ctypes.c_bool + nir_lower_subgroups.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_subgroups_options)] +except AttributeError: + pass +try: + nir_lower_system_values = _libraries['libtinymesa_cpu.so'].nir_lower_system_values + nir_lower_system_values.restype = ctypes.c_bool + nir_lower_system_values.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_build_lowered_load_helper_invocation = _libraries['libtinymesa_cpu.so'].nir_build_lowered_load_helper_invocation + nir_build_lowered_load_helper_invocation.restype = ctypes.POINTER(struct_nir_def) + nir_build_lowered_load_helper_invocation.argtypes = [ctypes.POINTER(struct_nir_builder)] +except AttributeError: + pass +class struct_nir_lower_compute_system_values_options(Structure): + pass + +struct_nir_lower_compute_system_values_options._pack_ = 1 # source:False +struct_nir_lower_compute_system_values_options._fields_ = [ + ('has_base_global_invocation_id', ctypes.c_bool, 1), + ('has_base_workgroup_id', ctypes.c_bool, 1), + ('has_global_size', ctypes.c_bool, 1), + ('shuffle_local_ids_for_quad_derivatives', ctypes.c_bool, 1), + ('lower_local_invocation_index', ctypes.c_bool, 1), + ('lower_cs_local_id_to_index', ctypes.c_bool, 1), + ('lower_workgroup_id_to_index', ctypes.c_bool, 1), + ('global_id_is_32bit', ctypes.c_bool, 1), + ('shortcut_1d_workgroup_id', ctypes.c_bool, 1), + ('PADDING_0', ctypes.c_uint32, 23), + ('num_workgroups', ctypes.c_uint32 * 3), +] + +nir_lower_compute_system_values_options = struct_nir_lower_compute_system_values_options +try: + nir_lower_compute_system_values = _libraries['libtinymesa_cpu.so'].nir_lower_compute_system_values + nir_lower_compute_system_values.restype = ctypes.c_bool + nir_lower_compute_system_values.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_compute_system_values_options)] +except AttributeError: + pass +class struct_nir_lower_sysvals_to_varyings_options(Structure): + pass + +struct_nir_lower_sysvals_to_varyings_options._pack_ = 1 # source:False +struct_nir_lower_sysvals_to_varyings_options._fields_ = [ + ('frag_coord', ctypes.c_bool, 1), + ('front_face', ctypes.c_bool, 1), + ('point_coord', ctypes.c_bool, 1), + ('PADDING_0', ctypes.c_uint8, 5), +] + +nir_lower_sysvals_to_varyings_options = struct_nir_lower_sysvals_to_varyings_options +try: + nir_lower_sysvals_to_varyings = _libraries['libtinymesa_cpu.so'].nir_lower_sysvals_to_varyings + nir_lower_sysvals_to_varyings.restype = ctypes.c_bool + nir_lower_sysvals_to_varyings.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_sysvals_to_varyings_options)] +except AttributeError: + pass + +# values for enumeration 'nir_lower_tex_packing' +nir_lower_tex_packing__enumvalues = { + 0: 'nir_lower_tex_packing_none', + 1: 'nir_lower_tex_packing_16', + 2: 'nir_lower_tex_packing_8', +} +nir_lower_tex_packing_none = 0 +nir_lower_tex_packing_16 = 1 +nir_lower_tex_packing_8 = 2 +nir_lower_tex_packing = ctypes.c_uint32 # enum +class struct_nir_lower_tex_options(Structure): + pass + +struct_nir_lower_tex_options._pack_ = 1 # source:False +struct_nir_lower_tex_options._fields_ = [ + ('lower_txp', ctypes.c_uint32), + ('lower_txp_array', ctypes.c_bool), + ('lower_txf_offset', ctypes.c_bool), + ('lower_rect_offset', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte), + ('lower_offset_filter', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('lower_rect', ctypes.c_bool), + ('lower_1d', ctypes.c_bool), + ('lower_1d_shadow', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte), + ('lower_y_uv_external', ctypes.c_uint32), + ('lower_y_vu_external', ctypes.c_uint32), + ('lower_y_u_v_external', ctypes.c_uint32), + ('lower_yx_xuxv_external', ctypes.c_uint32), + ('lower_yx_xvxu_external', ctypes.c_uint32), + ('lower_xy_uxvx_external', ctypes.c_uint32), + ('lower_xy_vxux_external', ctypes.c_uint32), + ('lower_ayuv_external', ctypes.c_uint32), + ('lower_xyuv_external', ctypes.c_uint32), + ('lower_yuv_external', ctypes.c_uint32), + ('lower_yu_yv_external', ctypes.c_uint32), + ('lower_yv_yu_external', ctypes.c_uint32), + ('lower_y41x_external', ctypes.c_uint32), + ('lower_sx10_external', ctypes.c_uint32), + ('lower_sx12_external', ctypes.c_uint32), + ('bt709_external', ctypes.c_uint32), + ('bt2020_external', ctypes.c_uint32), + ('yuv_full_range_external', ctypes.c_uint32), + ('saturate_s', ctypes.c_uint32), + ('saturate_t', ctypes.c_uint32), + ('saturate_r', ctypes.c_uint32), + ('swizzle_result', ctypes.c_uint32), + ('swizzles', ctypes.c_ubyte * 4 * 32), + ('scale_factors', ctypes.c_float * 32), + ('lower_srgb', ctypes.c_uint32), + ('lower_txd_cube_map', ctypes.c_bool), + ('lower_txd_3d', ctypes.c_bool), + ('lower_txd_array', ctypes.c_bool), + ('lower_txd_shadow', ctypes.c_bool), + ('lower_txd', ctypes.c_bool), + ('lower_txd_clamp', ctypes.c_bool), + ('lower_txb_shadow_clamp', ctypes.c_bool), + ('lower_txd_shadow_clamp', ctypes.c_bool), + ('lower_txd_offset_clamp', ctypes.c_bool), + ('lower_txd_clamp_bindless_sampler', ctypes.c_bool), + ('lower_txd_clamp_if_sampler_index_not_lt_16', ctypes.c_bool), + ('lower_txs_lod', ctypes.c_bool), + ('lower_txs_cube_array', ctypes.c_bool), + ('lower_tg4_broadcom_swizzle', ctypes.c_bool), + ('lower_tg4_offsets', ctypes.c_bool), + ('lower_to_fragment_fetch_amd', ctypes.c_bool), + ('lower_tex_packing_cb', ctypes.CFUNCTYPE(nir_lower_tex_packing, ctypes.POINTER(struct_nir_tex_instr), ctypes.POINTER(None))), + ('lower_tex_packing_data', ctypes.POINTER(None)), + ('lower_lod_zero_width', ctypes.c_bool), + ('lower_sampler_lod_bias', ctypes.c_bool), + ('lower_invalid_implicit_lod', ctypes.c_bool), + ('lower_index_to_offset', ctypes.c_bool), + ('PADDING_2', ctypes.c_ubyte * 4), + ('callback_data', ctypes.POINTER(None)), +] + +nir_lower_tex_options = struct_nir_lower_tex_options +try: + nir_lower_tex = _libraries['libtinymesa_cpu.so'].nir_lower_tex + nir_lower_tex.restype = ctypes.c_bool + nir_lower_tex.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_tex_options)] +except AttributeError: + pass +class struct_nir_lower_tex_shadow_swizzle(Structure): + pass + +struct_nir_lower_tex_shadow_swizzle._pack_ = 1 # source:False +struct_nir_lower_tex_shadow_swizzle._fields_ = [ + ('swizzle_r', ctypes.c_uint32, 3), + ('swizzle_g', ctypes.c_uint32, 3), + ('swizzle_b', ctypes.c_uint32, 3), + ('swizzle_a', ctypes.c_uint32, 3), + ('PADDING_0', ctypes.c_uint32, 20), +] + +nir_lower_tex_shadow_swizzle = struct_nir_lower_tex_shadow_swizzle +try: + nir_lower_tex_shadow = _libraries['libtinymesa_cpu.so'].nir_lower_tex_shadow + nir_lower_tex_shadow.restype = ctypes.c_bool + nir_lower_tex_shadow.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.POINTER(compare_func), ctypes.POINTER(struct_nir_lower_tex_shadow_swizzle), ctypes.c_bool] +except AttributeError: + pass +class struct_nir_lower_image_options(Structure): + pass + +struct_nir_lower_image_options._pack_ = 1 # source:False +struct_nir_lower_image_options._fields_ = [ + ('lower_cube_size', ctypes.c_bool), + ('lower_to_fragment_mask_load_amd', ctypes.c_bool), + ('lower_image_samples_to_one', ctypes.c_bool), +] + +nir_lower_image_options = struct_nir_lower_image_options +try: + nir_lower_image = _libraries['libtinymesa_cpu.so'].nir_lower_image + nir_lower_image.restype = ctypes.c_bool + nir_lower_image.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_image_options)] +except AttributeError: + pass +try: + nir_lower_image_atomics_to_global = _libraries['libtinymesa_cpu.so'].nir_lower_image_atomics_to_global + nir_lower_image_atomics_to_global.restype = ctypes.c_bool + nir_lower_image_atomics_to_global.argtypes = [ctypes.POINTER(struct_nir_shader), nir_intrin_filter_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_readonly_images_to_tex = _libraries['libtinymesa_cpu.so'].nir_lower_readonly_images_to_tex + nir_lower_readonly_images_to_tex.restype = ctypes.c_bool + nir_lower_readonly_images_to_tex.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass + +# values for enumeration 'nir_lower_non_uniform_access_type' +nir_lower_non_uniform_access_type__enumvalues = { + 1: 'nir_lower_non_uniform_ubo_access', + 2: 'nir_lower_non_uniform_ssbo_access', + 4: 'nir_lower_non_uniform_texture_access', + 8: 'nir_lower_non_uniform_image_access', + 16: 'nir_lower_non_uniform_get_ssbo_size', + 32: 'nir_lower_non_uniform_texture_offset_access', + 6: 'nir_lower_non_uniform_access_type_count', +} +nir_lower_non_uniform_ubo_access = 1 +nir_lower_non_uniform_ssbo_access = 2 +nir_lower_non_uniform_texture_access = 4 +nir_lower_non_uniform_image_access = 8 +nir_lower_non_uniform_get_ssbo_size = 16 +nir_lower_non_uniform_texture_offset_access = 32 +nir_lower_non_uniform_access_type_count = 6 +nir_lower_non_uniform_access_type = ctypes.c_uint32 # enum +nir_lower_non_uniform_src_access_callback = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_tex_instr), ctypes.c_uint32, ctypes.POINTER(None)) +nir_lower_non_uniform_access_callback = ctypes.CFUNCTYPE(ctypes.c_uint16, ctypes.POINTER(struct_nir_src), ctypes.POINTER(None)) +class struct_nir_lower_non_uniform_access_options(Structure): + pass + +struct_nir_lower_non_uniform_access_options._pack_ = 1 # source:False +struct_nir_lower_non_uniform_access_options._fields_ = [ + ('types', nir_lower_non_uniform_access_type), + ('PADDING_0', ctypes.c_ubyte * 4), + ('tex_src_callback', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_tex_instr), ctypes.c_uint32, ctypes.POINTER(None))), + ('callback', ctypes.CFUNCTYPE(ctypes.c_uint16, ctypes.POINTER(struct_nir_src), ctypes.POINTER(None))), + ('callback_data', ctypes.POINTER(None)), +] + +nir_lower_non_uniform_access_options = struct_nir_lower_non_uniform_access_options +try: + nir_has_non_uniform_access = _libraries['libtinymesa_cpu.so'].nir_has_non_uniform_access + nir_has_non_uniform_access.restype = ctypes.c_bool + nir_has_non_uniform_access.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_non_uniform_access_type] +except AttributeError: + pass +try: + nir_opt_non_uniform_access = _libraries['libtinymesa_cpu.so'].nir_opt_non_uniform_access + nir_opt_non_uniform_access.restype = ctypes.c_bool + nir_opt_non_uniform_access.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_non_uniform_access = _libraries['libtinymesa_cpu.so'].nir_lower_non_uniform_access + nir_lower_non_uniform_access.restype = ctypes.c_bool + nir_lower_non_uniform_access.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_non_uniform_access_options)] +except AttributeError: + pass +class struct_nir_lower_idiv_options(Structure): + pass + +struct_nir_lower_idiv_options._pack_ = 1 # source:False +struct_nir_lower_idiv_options._fields_ = [ + ('allow_fp16', ctypes.c_bool), +] + +nir_lower_idiv_options = struct_nir_lower_idiv_options +try: + nir_lower_idiv = _libraries['libtinymesa_cpu.so'].nir_lower_idiv + nir_lower_idiv.restype = ctypes.c_bool + nir_lower_idiv.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_idiv_options)] +except AttributeError: + pass +class struct_nir_input_attachment_options(Structure): + pass + +struct_nir_input_attachment_options._pack_ = 1 # source:False +struct_nir_input_attachment_options._fields_ = [ + ('use_ia_coord_intrin', ctypes.c_bool), + ('use_fragcoord_sysval', ctypes.c_bool), + ('use_layer_id_sysval', ctypes.c_bool), + ('use_view_id_for_layer', ctypes.c_bool), + ('unscaled_depth_stencil_ir3', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), + ('unscaled_input_attachment_ir3', ctypes.c_uint32), +] + +nir_input_attachment_options = struct_nir_input_attachment_options +try: + nir_lower_input_attachments = _libraries['libtinymesa_cpu.so'].nir_lower_input_attachments + nir_lower_input_attachments.restype = ctypes.c_bool + nir_lower_input_attachments.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_input_attachment_options)] +except AttributeError: + pass +try: + nir_lower_clip_vs = _libraries['libtinymesa_cpu.so'].nir_lower_clip_vs + nir_lower_clip_vs.restype = ctypes.c_bool + nir_lower_clip_vs.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_bool, ctypes.c_bool, ctypes.c_int16 * 4 * 0] +except AttributeError: + pass +try: + nir_lower_clip_gs = _libraries['libtinymesa_cpu.so'].nir_lower_clip_gs + nir_lower_clip_gs.restype = ctypes.c_bool + nir_lower_clip_gs.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_bool, ctypes.c_int16 * 4 * 0] +except AttributeError: + pass +try: + nir_lower_clip_fs = _libraries['libtinymesa_cpu.so'].nir_lower_clip_fs + nir_lower_clip_fs.restype = ctypes.c_bool + nir_lower_clip_fs.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_clip_cull_distance_to_vec4s = _libraries['libtinymesa_cpu.so'].nir_lower_clip_cull_distance_to_vec4s + nir_lower_clip_cull_distance_to_vec4s.restype = ctypes.c_bool + nir_lower_clip_cull_distance_to_vec4s.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_clip_cull_distance_array_vars = _libraries['libtinymesa_cpu.so'].nir_lower_clip_cull_distance_array_vars + nir_lower_clip_cull_distance_array_vars.restype = ctypes.c_bool + nir_lower_clip_cull_distance_array_vars.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_clip_disable = _libraries['libtinymesa_cpu.so'].nir_lower_clip_disable + nir_lower_clip_disable.restype = ctypes.c_bool + nir_lower_clip_disable.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_lower_point_size_mov = _libraries['libtinymesa_cpu.so'].nir_lower_point_size_mov + nir_lower_point_size_mov.restype = ctypes.c_bool + nir_lower_point_size_mov.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(ctypes.c_int16)] +except AttributeError: + pass +try: + nir_lower_frexp = _libraries['libtinymesa_cpu.so'].nir_lower_frexp + nir_lower_frexp.restype = ctypes.c_bool + nir_lower_frexp.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_two_sided_color = _libraries['libtinymesa_cpu.so'].nir_lower_two_sided_color + nir_lower_two_sided_color.restype = ctypes.c_bool + nir_lower_two_sided_color.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_clamp_color_outputs = _libraries['libtinymesa_cpu.so'].nir_lower_clamp_color_outputs + nir_lower_clamp_color_outputs.restype = ctypes.c_bool + nir_lower_clamp_color_outputs.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_flatshade = _libraries['libtinymesa_cpu.so'].nir_lower_flatshade + nir_lower_flatshade.restype = ctypes.c_bool + nir_lower_flatshade.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_passthrough_edgeflags = _libraries['libtinymesa_cpu.so'].nir_lower_passthrough_edgeflags + nir_lower_passthrough_edgeflags.restype = ctypes.c_bool + nir_lower_passthrough_edgeflags.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_patch_vertices = _libraries['libtinymesa_cpu.so'].nir_lower_patch_vertices + nir_lower_patch_vertices.restype = ctypes.c_bool + nir_lower_patch_vertices.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.POINTER(ctypes.c_int16)] +except AttributeError: + pass +class struct_nir_lower_wpos_ytransform_options(Structure): + pass + +struct_nir_lower_wpos_ytransform_options._pack_ = 1 # source:False +struct_nir_lower_wpos_ytransform_options._fields_ = [ + ('state_tokens', ctypes.c_int16 * 4), + ('fs_coord_origin_upper_left', ctypes.c_bool, 1), + ('fs_coord_origin_lower_left', ctypes.c_bool, 1), + ('fs_coord_pixel_center_integer', ctypes.c_bool, 1), + ('fs_coord_pixel_center_half_integer', ctypes.c_bool, 1), + ('PADDING_0', ctypes.c_uint16, 12), +] + +nir_lower_wpos_ytransform_options = struct_nir_lower_wpos_ytransform_options +try: + nir_lower_wpos_ytransform = _libraries['libtinymesa_cpu.so'].nir_lower_wpos_ytransform + nir_lower_wpos_ytransform.restype = ctypes.c_bool + nir_lower_wpos_ytransform.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_wpos_ytransform_options)] +except AttributeError: + pass +try: + nir_lower_wpos_center = _libraries['libtinymesa_cpu.so'].nir_lower_wpos_center + nir_lower_wpos_center.restype = ctypes.c_bool + nir_lower_wpos_center.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_pntc_ytransform = _libraries['libtinymesa_cpu.so'].nir_lower_pntc_ytransform + nir_lower_pntc_ytransform.restype = ctypes.c_bool + nir_lower_pntc_ytransform.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_int16 * 4 * 0] +except AttributeError: + pass +try: + nir_lower_wrmasks = _libraries['libtinymesa_cpu.so'].nir_lower_wrmasks + nir_lower_wrmasks.restype = ctypes.c_bool + nir_lower_wrmasks.argtypes = [ctypes.POINTER(struct_nir_shader), nir_instr_filter_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_fb_read = _libraries['libtinymesa_cpu.so'].nir_lower_fb_read + nir_lower_fb_read.restype = ctypes.c_bool + nir_lower_fb_read.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_nir_lower_drawpixels_options(Structure): + pass + +struct_nir_lower_drawpixels_options._pack_ = 1 # source:False +struct_nir_lower_drawpixels_options._fields_ = [ + ('texcoord_state_tokens', ctypes.c_int16 * 4), + ('scale_state_tokens', ctypes.c_int16 * 4), + ('bias_state_tokens', ctypes.c_int16 * 4), + ('drawpix_sampler', ctypes.c_uint32), + ('pixelmap_sampler', ctypes.c_uint32), + ('pixel_maps', ctypes.c_bool, 1), + ('scale_and_bias', ctypes.c_bool, 1), + ('PADDING_0', ctypes.c_uint32, 30), +] + +nir_lower_drawpixels_options = struct_nir_lower_drawpixels_options +try: + nir_lower_drawpixels = _libraries['libtinymesa_cpu.so'].nir_lower_drawpixels + nir_lower_drawpixels.restype = ctypes.c_bool + nir_lower_drawpixels.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_drawpixels_options)] +except AttributeError: + pass +class struct_nir_lower_bitmap_options(Structure): + pass + +struct_nir_lower_bitmap_options._pack_ = 1 # source:False +struct_nir_lower_bitmap_options._fields_ = [ + ('sampler', ctypes.c_uint32), + ('swizzle_xxxx', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), +] + +nir_lower_bitmap_options = struct_nir_lower_bitmap_options +try: + nir_lower_bitmap = _libraries['libtinymesa_cpu.so'].nir_lower_bitmap + nir_lower_bitmap.restype = ctypes.c_bool + nir_lower_bitmap.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_bitmap_options)] +except AttributeError: + pass +try: + nir_lower_atomics_to_ssbo = _libraries['libtinymesa_cpu.so'].nir_lower_atomics_to_ssbo + nir_lower_atomics_to_ssbo.restype = ctypes.c_bool + nir_lower_atomics_to_ssbo.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_gs_intrinsics_flags' +c__EA_nir_lower_gs_intrinsics_flags__enumvalues = { + 1: 'nir_lower_gs_intrinsics_per_stream', + 2: 'nir_lower_gs_intrinsics_count_primitives', + 4: 'nir_lower_gs_intrinsics_count_vertices_per_primitive', + 8: 'nir_lower_gs_intrinsics_overwrite_incomplete', +} +nir_lower_gs_intrinsics_per_stream = 1 +nir_lower_gs_intrinsics_count_primitives = 2 +nir_lower_gs_intrinsics_count_vertices_per_primitive = 4 +nir_lower_gs_intrinsics_overwrite_incomplete = 8 +c__EA_nir_lower_gs_intrinsics_flags = ctypes.c_uint32 # enum +nir_lower_gs_intrinsics_flags = c__EA_nir_lower_gs_intrinsics_flags +nir_lower_gs_intrinsics_flags__enumvalues = c__EA_nir_lower_gs_intrinsics_flags__enumvalues +try: + nir_lower_gs_intrinsics = _libraries['libtinymesa_cpu.so'].nir_lower_gs_intrinsics + nir_lower_gs_intrinsics.restype = ctypes.c_bool + nir_lower_gs_intrinsics.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_gs_intrinsics_flags] +except AttributeError: + pass +try: + nir_lower_halt_to_return = _libraries['libtinymesa_cpu.so'].nir_lower_halt_to_return + nir_lower_halt_to_return.restype = ctypes.c_bool + nir_lower_halt_to_return.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_tess_coord_z = _libraries['libtinymesa_cpu.so'].nir_lower_tess_coord_z + nir_lower_tess_coord_z.restype = ctypes.c_bool + nir_lower_tess_coord_z.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +class struct_nir_lower_task_shader_options(Structure): + pass + +struct_nir_lower_task_shader_options._pack_ = 1 # source:False +struct_nir_lower_task_shader_options._fields_ = [ + ('payload_to_shared_for_atomics', ctypes.c_bool, 1), + ('payload_to_shared_for_small_types', ctypes.c_bool, 1), + ('PADDING_0', ctypes.c_uint32, 30), + ('payload_offset_in_bytes', ctypes.c_uint32), +] + +nir_lower_task_shader_options = struct_nir_lower_task_shader_options +try: + nir_lower_task_shader = _libraries['libtinymesa_cpu.so'].nir_lower_task_shader + nir_lower_task_shader.restype = ctypes.c_bool + nir_lower_task_shader.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_task_shader_options] +except AttributeError: + pass +nir_lower_bit_size_callback = ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)) +try: + nir_lower_bit_size = _libraries['libtinymesa_cpu.so'].nir_lower_bit_size + nir_lower_bit_size.restype = ctypes.c_bool + nir_lower_bit_size.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_bit_size_callback, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_lower_64bit_phis = _libraries['libtinymesa_cpu.so'].nir_lower_64bit_phis + nir_lower_64bit_phis.restype = ctypes.c_bool + nir_lower_64bit_phis.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_nir_split_conversions_options(Structure): + pass + +struct_nir_split_conversions_options._pack_ = 1 # source:False +struct_nir_split_conversions_options._fields_ = [ + ('callback', ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('callback_data', ctypes.POINTER(None)), + ('has_convert_alu_types', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), +] + +nir_split_conversions_options = struct_nir_split_conversions_options +try: + nir_split_conversions = _libraries['libtinymesa_cpu.so'].nir_split_conversions + nir_split_conversions.restype = ctypes.c_bool + nir_split_conversions.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_split_conversions_options)] +except AttributeError: + pass +try: + nir_split_64bit_vec3_and_vec4 = _libraries['libtinymesa_cpu.so'].nir_split_64bit_vec3_and_vec4 + nir_split_64bit_vec3_and_vec4.restype = ctypes.c_bool + nir_split_64bit_vec3_and_vec4.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_int64_op_to_options_mask = _libraries['libtinymesa_cpu.so'].nir_lower_int64_op_to_options_mask + nir_lower_int64_op_to_options_mask.restype = nir_lower_int64_options + nir_lower_int64_op_to_options_mask.argtypes = [nir_op] +except AttributeError: + pass +try: + nir_lower_int64 = _libraries['libtinymesa_cpu.so'].nir_lower_int64 + nir_lower_int64.restype = ctypes.c_bool + nir_lower_int64.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_int64_float_conversions = _libraries['libtinymesa_cpu.so'].nir_lower_int64_float_conversions + nir_lower_int64_float_conversions.restype = ctypes.c_bool + nir_lower_int64_float_conversions.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_doubles_op_to_options_mask = _libraries['libtinymesa_cpu.so'].nir_lower_doubles_op_to_options_mask + nir_lower_doubles_op_to_options_mask.restype = nir_lower_doubles_options + nir_lower_doubles_op_to_options_mask.argtypes = [nir_op] +except AttributeError: + pass +try: + nir_lower_doubles = _libraries['libtinymesa_cpu.so'].nir_lower_doubles + nir_lower_doubles.restype = ctypes.c_bool + nir_lower_doubles.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_shader), nir_lower_doubles_options] +except AttributeError: + pass +try: + nir_lower_pack = _libraries['libtinymesa_cpu.so'].nir_lower_pack + nir_lower_pack.restype = ctypes.c_bool + nir_lower_pack.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_get_io_intrinsic = _libraries['libtinymesa_cpu.so'].nir_get_io_intrinsic + nir_get_io_intrinsic.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_get_io_intrinsic.argtypes = [ctypes.POINTER(struct_nir_instr), nir_variable_mode, ctypes.POINTER(c__EA_nir_variable_mode)] +except AttributeError: + pass +try: + nir_recompute_io_bases = _libraries['libtinymesa_cpu.so'].nir_recompute_io_bases + nir_recompute_io_bases.restype = ctypes.c_bool + nir_recompute_io_bases.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_mediump_vars = _libraries['libtinymesa_cpu.so'].nir_lower_mediump_vars + nir_lower_mediump_vars.restype = ctypes.c_bool + nir_lower_mediump_vars.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_lower_mediump_io = _libraries['libtinymesa_cpu.so'].nir_lower_mediump_io + nir_lower_mediump_io.restype = ctypes.c_bool + nir_lower_mediump_io.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, uint64_t, ctypes.c_bool] +except AttributeError: + pass +try: + nir_clear_mediump_io_flag = _libraries['libtinymesa_cpu.so'].nir_clear_mediump_io_flag + nir_clear_mediump_io_flag.restype = ctypes.c_bool + nir_clear_mediump_io_flag.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_nir_opt_tex_srcs_options(Structure): + pass + +struct_nir_opt_tex_srcs_options._pack_ = 1 # source:False +struct_nir_opt_tex_srcs_options._fields_ = [ + ('sampler_dims', ctypes.c_uint32), + ('src_types', ctypes.c_uint32), +] + +nir_opt_tex_srcs_options = struct_nir_opt_tex_srcs_options +class struct_nir_opt_16bit_tex_image_options(Structure): + pass + +struct_nir_opt_16bit_tex_image_options._pack_ = 1 # source:False +struct_nir_opt_16bit_tex_image_options._fields_ = [ + ('rounding_mode', nir_rounding_mode), + ('opt_tex_dest_types', nir_alu_type), + ('opt_image_dest_types', nir_alu_type), + ('integer_dest_saturates', ctypes.c_bool), + ('opt_image_store_data', ctypes.c_bool), + ('opt_image_srcs', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte), + ('opt_srcs_options_count', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('opt_srcs_options', ctypes.POINTER(struct_nir_opt_tex_srcs_options)), +] + +nir_opt_16bit_tex_image_options = struct_nir_opt_16bit_tex_image_options +try: + nir_opt_16bit_tex_image = _libraries['libtinymesa_cpu.so'].nir_opt_16bit_tex_image + nir_opt_16bit_tex_image.restype = ctypes.c_bool + nir_opt_16bit_tex_image.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_opt_16bit_tex_image_options)] +except AttributeError: + pass +class struct_nir_tex_src_type_constraint(Structure): + pass + +struct_nir_tex_src_type_constraint._pack_ = 1 # source:False +struct_nir_tex_src_type_constraint._fields_ = [ + ('legalize_type', ctypes.c_bool), + ('bit_size', ctypes.c_ubyte), + ('PADDING_0', ctypes.c_ubyte * 2), + ('match_src', nir_tex_src_type), +] + +nir_tex_src_type_constraint = struct_nir_tex_src_type_constraint +nir_tex_src_type_constraints = struct_nir_tex_src_type_constraint * 23 +try: + nir_legalize_16bit_sampler_srcs = _libraries['libtinymesa_cpu.so'].nir_legalize_16bit_sampler_srcs + nir_legalize_16bit_sampler_srcs.restype = ctypes.c_bool + nir_legalize_16bit_sampler_srcs.argtypes = [ctypes.POINTER(struct_nir_shader), nir_tex_src_type_constraints] +except AttributeError: + pass +try: + nir_lower_point_size = _libraries['libtinymesa_cpu.so'].nir_lower_point_size + nir_lower_point_size.restype = ctypes.c_bool + nir_lower_point_size.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_float, ctypes.c_float] +except AttributeError: + pass +try: + nir_lower_default_point_size = _libraries['libtinymesa_cpu.so'].nir_lower_default_point_size + nir_lower_default_point_size.restype = ctypes.c_bool + nir_lower_default_point_size.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_texcoord_replace = _libraries['libtinymesa_cpu.so'].nir_lower_texcoord_replace + nir_lower_texcoord_replace.restype = ctypes.c_bool + nir_lower_texcoord_replace.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_texcoord_replace_late = _libraries['libtinymesa_cpu.so'].nir_lower_texcoord_replace_late + nir_lower_texcoord_replace_late.restype = ctypes.c_bool + nir_lower_texcoord_replace_late.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32, ctypes.c_bool] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_interpolation_options' +c__EA_nir_lower_interpolation_options__enumvalues = { + 2: 'nir_lower_interpolation_at_sample', + 4: 'nir_lower_interpolation_at_offset', + 8: 'nir_lower_interpolation_centroid', + 16: 'nir_lower_interpolation_pixel', + 32: 'nir_lower_interpolation_sample', +} +nir_lower_interpolation_at_sample = 2 +nir_lower_interpolation_at_offset = 4 +nir_lower_interpolation_centroid = 8 +nir_lower_interpolation_pixel = 16 +nir_lower_interpolation_sample = 32 +c__EA_nir_lower_interpolation_options = ctypes.c_uint32 # enum +nir_lower_interpolation_options = c__EA_nir_lower_interpolation_options +nir_lower_interpolation_options__enumvalues = c__EA_nir_lower_interpolation_options__enumvalues +try: + nir_lower_interpolation = _libraries['libtinymesa_cpu.so'].nir_lower_interpolation + nir_lower_interpolation.restype = ctypes.c_bool + nir_lower_interpolation.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_interpolation_options] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_discard_if_options' +c__EA_nir_lower_discard_if_options__enumvalues = { + 1: 'nir_lower_demote_if_to_cf', + 2: 'nir_lower_terminate_if_to_cf', + 4: 'nir_move_terminate_out_of_loops', +} +nir_lower_demote_if_to_cf = 1 +nir_lower_terminate_if_to_cf = 2 +nir_move_terminate_out_of_loops = 4 +c__EA_nir_lower_discard_if_options = ctypes.c_uint32 # enum +nir_lower_discard_if_options = c__EA_nir_lower_discard_if_options +nir_lower_discard_if_options__enumvalues = c__EA_nir_lower_discard_if_options__enumvalues +try: + nir_lower_discard_if = _libraries['libtinymesa_cpu.so'].nir_lower_discard_if + nir_lower_discard_if.restype = ctypes.c_bool + nir_lower_discard_if.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_discard_if_options] +except AttributeError: + pass +try: + nir_lower_terminate_to_demote = _libraries['libtinymesa_cpu.so'].nir_lower_terminate_to_demote + nir_lower_terminate_to_demote.restype = ctypes.c_bool + nir_lower_terminate_to_demote.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_memory_model = _libraries['libtinymesa_cpu.so'].nir_lower_memory_model + nir_lower_memory_model.restype = ctypes.c_bool + nir_lower_memory_model.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_goto_ifs = _libraries['libtinymesa_cpu.so'].nir_lower_goto_ifs + nir_lower_goto_ifs.restype = ctypes.c_bool + nir_lower_goto_ifs.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_continue_constructs = _libraries['libtinymesa_cpu.so'].nir_lower_continue_constructs + nir_lower_continue_constructs.restype = ctypes.c_bool + nir_lower_continue_constructs.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_nir_lower_multiview_options(Structure): + pass + +struct_nir_lower_multiview_options._pack_ = 1 # source:False +struct_nir_lower_multiview_options._fields_ = [ + ('view_mask', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('allowed_per_view_outputs', ctypes.c_uint64), +] + +nir_lower_multiview_options = struct_nir_lower_multiview_options +try: + nir_shader_uses_view_index = _libraries['libtinymesa_cpu.so'].nir_shader_uses_view_index + nir_shader_uses_view_index.restype = ctypes.c_bool + nir_shader_uses_view_index.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_can_lower_multiview = _libraries['libtinymesa_cpu.so'].nir_can_lower_multiview + nir_can_lower_multiview.restype = ctypes.c_bool + nir_can_lower_multiview.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_multiview_options] +except AttributeError: + pass +try: + nir_lower_multiview = _libraries['libtinymesa_cpu.so'].nir_lower_multiview + nir_lower_multiview.restype = ctypes.c_bool + nir_lower_multiview.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_multiview_options] +except AttributeError: + pass +try: + nir_lower_view_index_to_device_index = _libraries['libtinymesa_cpu.so'].nir_lower_view_index_to_device_index + nir_lower_view_index_to_device_index.restype = ctypes.c_bool + nir_lower_view_index_to_device_index.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_lower_fp16_cast_options' +c__EA_nir_lower_fp16_cast_options__enumvalues = { + 1: 'nir_lower_fp16_rtz', + 2: 'nir_lower_fp16_rtne', + 4: 'nir_lower_fp16_ru', + 8: 'nir_lower_fp16_rd', + 15: 'nir_lower_fp16_all', + 16: 'nir_lower_fp16_split_fp64', +} +nir_lower_fp16_rtz = 1 +nir_lower_fp16_rtne = 2 +nir_lower_fp16_ru = 4 +nir_lower_fp16_rd = 8 +nir_lower_fp16_all = 15 +nir_lower_fp16_split_fp64 = 16 +c__EA_nir_lower_fp16_cast_options = ctypes.c_uint32 # enum +nir_lower_fp16_cast_options = c__EA_nir_lower_fp16_cast_options +nir_lower_fp16_cast_options__enumvalues = c__EA_nir_lower_fp16_cast_options__enumvalues +try: + nir_lower_fp16_casts = _libraries['libtinymesa_cpu.so'].nir_lower_fp16_casts + nir_lower_fp16_casts.restype = ctypes.c_bool + nir_lower_fp16_casts.argtypes = [ctypes.POINTER(struct_nir_shader), nir_lower_fp16_cast_options] +except AttributeError: + pass +try: + nir_normalize_cubemap_coords = _libraries['libtinymesa_cpu.so'].nir_normalize_cubemap_coords + nir_normalize_cubemap_coords.restype = ctypes.c_bool + nir_normalize_cubemap_coords.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_shader_supports_implicit_lod = _libraries['libtinymesa_cpu.so'].nir_shader_supports_implicit_lod + nir_shader_supports_implicit_lod.restype = ctypes.c_bool + nir_shader_supports_implicit_lod.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_live_defs_impl = _libraries['libtinymesa_cpu.so'].nir_live_defs_impl + nir_live_defs_impl.restype = None + nir_live_defs_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_get_live_defs = _libraries['libtinymesa_cpu.so'].nir_get_live_defs + nir_get_live_defs.restype = ctypes.POINTER(ctypes.c_uint32) + nir_get_live_defs.argtypes = [nir_cursor, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_loop_analyze_impl = _libraries['libtinymesa_cpu.so'].nir_loop_analyze_impl + nir_loop_analyze_impl.restype = None + nir_loop_analyze_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl), nir_variable_mode, ctypes.c_bool] +except AttributeError: + pass +try: + nir_defs_interfere = _libraries['libtinymesa_cpu.so'].nir_defs_interfere + nir_defs_interfere.restype = ctypes.c_bool + nir_defs_interfere.argtypes = [ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_repair_ssa_impl = _libraries['libtinymesa_cpu.so'].nir_repair_ssa_impl + nir_repair_ssa_impl.restype = ctypes.c_bool + nir_repair_ssa_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_repair_ssa = _libraries['libtinymesa_cpu.so'].nir_repair_ssa + nir_repair_ssa.restype = ctypes.c_bool + nir_repair_ssa.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_convert_loop_to_lcssa = _libraries['libtinymesa_cpu.so'].nir_convert_loop_to_lcssa + nir_convert_loop_to_lcssa.restype = None + nir_convert_loop_to_lcssa.argtypes = [ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_convert_to_lcssa = _libraries['libtinymesa_cpu.so'].nir_convert_to_lcssa + nir_convert_to_lcssa.restype = ctypes.c_bool + nir_convert_to_lcssa.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_divergence_analysis_impl = _libraries['libtinymesa_cpu.so'].nir_divergence_analysis_impl + nir_divergence_analysis_impl.restype = None + nir_divergence_analysis_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl), nir_divergence_options] +except AttributeError: + pass +try: + nir_divergence_analysis = _libraries['libtinymesa_cpu.so'].nir_divergence_analysis + nir_divergence_analysis.restype = None + nir_divergence_analysis.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_vertex_divergence_analysis = _libraries['libtinymesa_cpu.so'].nir_vertex_divergence_analysis + nir_vertex_divergence_analysis.restype = None + nir_vertex_divergence_analysis.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_has_divergent_loop = _libraries['libtinymesa_cpu.so'].nir_has_divergent_loop + nir_has_divergent_loop.restype = ctypes.c_bool + nir_has_divergent_loop.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_rewrite_uses_to_load_reg = _libraries['libtinymesa_cpu.so'].nir_rewrite_uses_to_load_reg + nir_rewrite_uses_to_load_reg.restype = None + nir_rewrite_uses_to_load_reg.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_convert_from_ssa = _libraries['libtinymesa_cpu.so'].nir_convert_from_ssa + nir_convert_from_ssa.restype = ctypes.c_bool + nir_convert_from_ssa.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_phis_to_regs_block = _libraries['libtinymesa_cpu.so'].nir_lower_phis_to_regs_block + nir_lower_phis_to_regs_block.restype = ctypes.c_bool + nir_lower_phis_to_regs_block.argtypes = [ctypes.POINTER(struct_nir_block), ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_ssa_defs_to_regs_block = _libraries['libtinymesa_cpu.so'].nir_lower_ssa_defs_to_regs_block + nir_lower_ssa_defs_to_regs_block.restype = ctypes.c_bool + nir_lower_ssa_defs_to_regs_block.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_rematerialize_deref_in_use_blocks = _libraries['libtinymesa_cpu.so'].nir_rematerialize_deref_in_use_blocks + nir_rematerialize_deref_in_use_blocks.restype = ctypes.c_bool + nir_rematerialize_deref_in_use_blocks.argtypes = [ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_rematerialize_derefs_in_use_blocks_impl = _libraries['libtinymesa_cpu.so'].nir_rematerialize_derefs_in_use_blocks_impl + nir_rematerialize_derefs_in_use_blocks_impl.restype = ctypes.c_bool + nir_rematerialize_derefs_in_use_blocks_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_lower_samplers = _libraries['libtinymesa_cpu.so'].nir_lower_samplers + nir_lower_samplers.restype = ctypes.c_bool + nir_lower_samplers.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_cl_images = _libraries['libtinymesa_cpu.so'].nir_lower_cl_images + nir_lower_cl_images.restype = ctypes.c_bool + nir_lower_cl_images.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +try: + nir_dedup_inline_samplers = _libraries['libtinymesa_cpu.so'].nir_dedup_inline_samplers + nir_dedup_inline_samplers.restype = ctypes.c_bool + nir_dedup_inline_samplers.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_nir_lower_ssbo_options(Structure): + pass + +struct_nir_lower_ssbo_options._pack_ = 1 # source:False +struct_nir_lower_ssbo_options._fields_ = [ + ('native_loads', ctypes.c_bool), + ('native_offset', ctypes.c_bool), +] + +nir_lower_ssbo_options = struct_nir_lower_ssbo_options +try: + nir_lower_ssbo = _libraries['libtinymesa_cpu.so'].nir_lower_ssbo + nir_lower_ssbo.restype = ctypes.c_bool + nir_lower_ssbo.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_ssbo_options)] +except AttributeError: + pass +try: + nir_lower_helper_writes = _libraries['libtinymesa_cpu.so'].nir_lower_helper_writes + nir_lower_helper_writes.restype = ctypes.c_bool + nir_lower_helper_writes.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +class struct_nir_lower_printf_options(Structure): + pass + +struct_nir_lower_printf_options._pack_ = 1 # source:False +struct_nir_lower_printf_options._fields_ = [ + ('max_buffer_size', ctypes.c_uint32), + ('ptr_bit_size', ctypes.c_uint32), + ('hash_format_strings', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 3), +] + +nir_lower_printf_options = struct_nir_lower_printf_options +try: + nir_lower_printf = _libraries['libtinymesa_cpu.so'].nir_lower_printf + nir_lower_printf.restype = ctypes.c_bool + nir_lower_printf.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_printf_options)] +except AttributeError: + pass +try: + nir_lower_printf_buffer = _libraries['libtinymesa_cpu.so'].nir_lower_printf_buffer + nir_lower_printf_buffer.restype = ctypes.c_bool + nir_lower_printf_buffer.argtypes = [ctypes.POINTER(struct_nir_shader), uint64_t, uint32_t] +except AttributeError: + pass +try: + nir_opt_comparison_pre_impl = _libraries['libtinymesa_cpu.so'].nir_opt_comparison_pre_impl + nir_opt_comparison_pre_impl.restype = ctypes.c_bool + nir_opt_comparison_pre_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_opt_comparison_pre = _libraries['libtinymesa_cpu.so'].nir_opt_comparison_pre + nir_opt_comparison_pre.restype = ctypes.c_bool + nir_opt_comparison_pre.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_nir_opt_access_options(Structure): + pass + +struct_nir_opt_access_options._pack_ = 1 # source:False +struct_nir_opt_access_options._fields_ = [ + ('is_vulkan', ctypes.c_bool), +] + +nir_opt_access_options = struct_nir_opt_access_options +try: + nir_opt_access = _libraries['libtinymesa_cpu.so'].nir_opt_access + nir_opt_access.restype = ctypes.c_bool + nir_opt_access.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_opt_access_options)] +except AttributeError: + pass +try: + nir_opt_algebraic = _libraries['libtinymesa_cpu.so'].nir_opt_algebraic + nir_opt_algebraic.restype = ctypes.c_bool + nir_opt_algebraic.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_algebraic_before_ffma = _libraries['libtinymesa_cpu.so'].nir_opt_algebraic_before_ffma + nir_opt_algebraic_before_ffma.restype = ctypes.c_bool + nir_opt_algebraic_before_ffma.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_algebraic_before_lower_int64 = _libraries['libtinymesa_cpu.so'].nir_opt_algebraic_before_lower_int64 + nir_opt_algebraic_before_lower_int64.restype = ctypes.c_bool + nir_opt_algebraic_before_lower_int64.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_algebraic_late = _libraries['libtinymesa_cpu.so'].nir_opt_algebraic_late + nir_opt_algebraic_late.restype = ctypes.c_bool + nir_opt_algebraic_late.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_algebraic_distribute_src_mods = _libraries['libtinymesa_cpu.so'].nir_opt_algebraic_distribute_src_mods + nir_opt_algebraic_distribute_src_mods.restype = ctypes.c_bool + nir_opt_algebraic_distribute_src_mods.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_algebraic_integer_promotion = _libraries['libtinymesa_cpu.so'].nir_opt_algebraic_integer_promotion + nir_opt_algebraic_integer_promotion.restype = ctypes.c_bool + nir_opt_algebraic_integer_promotion.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_reassociate_matrix_mul = _libraries['libtinymesa_cpu.so'].nir_opt_reassociate_matrix_mul + nir_opt_reassociate_matrix_mul.restype = ctypes.c_bool + nir_opt_reassociate_matrix_mul.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_constant_folding = _libraries['libtinymesa_cpu.so'].nir_opt_constant_folding + nir_opt_constant_folding.restype = ctypes.c_bool + nir_opt_constant_folding.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +nir_combine_barrier_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None)) +try: + nir_opt_combine_barriers = _libraries['libtinymesa_cpu.so'].nir_opt_combine_barriers + nir_opt_combine_barriers.restype = ctypes.c_bool + nir_opt_combine_barriers.argtypes = [ctypes.POINTER(struct_nir_shader), nir_combine_barrier_cb, ctypes.POINTER(None)] +except AttributeError: + pass + +# values for enumeration 'c__EA_mesa_scope' +c__EA_mesa_scope__enumvalues = { + 0: 'SCOPE_NONE', + 1: 'SCOPE_INVOCATION', + 2: 'SCOPE_SUBGROUP', + 3: 'SCOPE_SHADER_CALL', + 4: 'SCOPE_WORKGROUP', + 5: 'SCOPE_QUEUE_FAMILY', + 6: 'SCOPE_DEVICE', +} +SCOPE_NONE = 0 +SCOPE_INVOCATION = 1 +SCOPE_SUBGROUP = 2 +SCOPE_SHADER_CALL = 3 +SCOPE_WORKGROUP = 4 +SCOPE_QUEUE_FAMILY = 5 +SCOPE_DEVICE = 6 +c__EA_mesa_scope = ctypes.c_uint32 # enum +mesa_scope = c__EA_mesa_scope +mesa_scope__enumvalues = c__EA_mesa_scope__enumvalues +try: + nir_opt_acquire_release_barriers = _libraries['libtinymesa_cpu.so'].nir_opt_acquire_release_barriers + nir_opt_acquire_release_barriers.restype = ctypes.c_bool + nir_opt_acquire_release_barriers.argtypes = [ctypes.POINTER(struct_nir_shader), mesa_scope] +except AttributeError: + pass +try: + nir_opt_barrier_modes = _libraries['libtinymesa_cpu.so'].nir_opt_barrier_modes + nir_opt_barrier_modes.restype = ctypes.c_bool + nir_opt_barrier_modes.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_minimize_call_live_states = _libraries['libtinymesa_cpu.so'].nir_minimize_call_live_states + nir_minimize_call_live_states.restype = ctypes.c_bool + nir_minimize_call_live_states.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_combine_stores = _libraries['libtinymesa_cpu.so'].nir_opt_combine_stores + nir_opt_combine_stores.restype = ctypes.c_bool + nir_opt_combine_stores.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode] +except AttributeError: + pass +try: + nir_copy_prop_impl = _libraries['libtinymesa_cpu.so'].nir_copy_prop_impl + nir_copy_prop_impl.restype = ctypes.c_bool + nir_copy_prop_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_copy_prop = _libraries['libtinymesa_cpu.so'].nir_copy_prop + nir_copy_prop.restype = ctypes.c_bool + nir_copy_prop.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_copy_prop_vars = _libraries['libtinymesa_cpu.so'].nir_opt_copy_prop_vars + nir_opt_copy_prop_vars.restype = ctypes.c_bool + nir_opt_copy_prop_vars.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_cse = _libraries['libtinymesa_cpu.so'].nir_opt_cse + nir_opt_cse.restype = ctypes.c_bool + nir_opt_cse.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_dce = _libraries['libtinymesa_cpu.so'].nir_opt_dce + nir_opt_dce.restype = ctypes.c_bool + nir_opt_dce.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_dead_cf = _libraries['libtinymesa_cpu.so'].nir_opt_dead_cf + nir_opt_dead_cf.restype = ctypes.c_bool + nir_opt_dead_cf.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_dead_write_vars = _libraries['libtinymesa_cpu.so'].nir_opt_dead_write_vars + nir_opt_dead_write_vars.restype = ctypes.c_bool + nir_opt_dead_write_vars.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_deref_impl = _libraries['libtinymesa_cpu.so'].nir_opt_deref_impl + nir_opt_deref_impl.restype = ctypes.c_bool + nir_opt_deref_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_opt_deref = _libraries['libtinymesa_cpu.so'].nir_opt_deref + nir_opt_deref.restype = ctypes.c_bool + nir_opt_deref.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_find_array_copies = _libraries['libtinymesa_cpu.so'].nir_opt_find_array_copies + nir_opt_find_array_copies.restype = ctypes.c_bool + nir_opt_find_array_copies.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_def_is_frag_coord_z = _libraries['libtinymesa_cpu.so'].nir_def_is_frag_coord_z + nir_def_is_frag_coord_z.restype = ctypes.c_bool + nir_def_is_frag_coord_z.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_opt_fragdepth = _libraries['libtinymesa_cpu.so'].nir_opt_fragdepth + nir_opt_fragdepth.restype = ctypes.c_bool + nir_opt_fragdepth.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_gcm = _libraries['libtinymesa_cpu.so'].nir_opt_gcm + nir_opt_gcm.restype = ctypes.c_bool + nir_opt_gcm.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_opt_generate_bfi = _libraries['libtinymesa_cpu.so'].nir_opt_generate_bfi + nir_opt_generate_bfi.restype = ctypes.c_bool + nir_opt_generate_bfi.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_idiv_const = _libraries['libtinymesa_cpu.so'].nir_opt_idiv_const + nir_opt_idiv_const.restype = ctypes.c_bool + nir_opt_idiv_const.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_opt_mqsad = _libraries['libtinymesa_cpu.so'].nir_opt_mqsad + nir_opt_mqsad.restype = ctypes.c_bool + nir_opt_mqsad.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_opt_if_options' +c__EA_nir_opt_if_options__enumvalues = { + 1: 'nir_opt_if_optimize_phi_true_false', + 2: 'nir_opt_if_avoid_64bit_phis', +} +nir_opt_if_optimize_phi_true_false = 1 +nir_opt_if_avoid_64bit_phis = 2 +c__EA_nir_opt_if_options = ctypes.c_uint32 # enum +nir_opt_if_options = c__EA_nir_opt_if_options +nir_opt_if_options__enumvalues = c__EA_nir_opt_if_options__enumvalues +try: + nir_opt_if = _libraries['libtinymesa_cpu.so'].nir_opt_if + nir_opt_if.restype = ctypes.c_bool + nir_opt_if.argtypes = [ctypes.POINTER(struct_nir_shader), nir_opt_if_options] +except AttributeError: + pass +try: + nir_opt_intrinsics = _libraries['libtinymesa_cpu.so'].nir_opt_intrinsics + nir_opt_intrinsics.restype = ctypes.c_bool + nir_opt_intrinsics.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_large_constants = _libraries['libtinymesa_cpu.so'].nir_opt_large_constants + nir_opt_large_constants.restype = ctypes.c_bool + nir_opt_large_constants.argtypes = [ctypes.POINTER(struct_nir_shader), glsl_type_size_align_func, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_opt_licm = _libraries['libtinymesa_cpu.so'].nir_opt_licm + nir_opt_licm.restype = ctypes.c_bool + nir_opt_licm.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_loop = _libraries['libtinymesa_cpu.so'].nir_opt_loop + nir_opt_loop.restype = ctypes.c_bool + nir_opt_loop.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_loop_unroll = _libraries['libtinymesa_cpu.so'].nir_opt_loop_unroll + nir_opt_loop_unroll.restype = ctypes.c_bool + nir_opt_loop_unroll.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass + +# values for enumeration 'c__EA_nir_move_options' +c__EA_nir_move_options__enumvalues = { + 1: 'nir_move_const_undef', + 2: 'nir_move_load_ubo', + 4: 'nir_move_load_input', + 8: 'nir_move_comparisons', + 16: 'nir_move_copies', + 32: 'nir_move_load_ssbo', + 64: 'nir_move_load_uniform', + 128: 'nir_move_alu', + 256: 'nir_dont_move_byte_word_vecs', +} +nir_move_const_undef = 1 +nir_move_load_ubo = 2 +nir_move_load_input = 4 +nir_move_comparisons = 8 +nir_move_copies = 16 +nir_move_load_ssbo = 32 +nir_move_load_uniform = 64 +nir_move_alu = 128 +nir_dont_move_byte_word_vecs = 256 +c__EA_nir_move_options = ctypes.c_uint32 # enum +nir_move_options = c__EA_nir_move_options +nir_move_options__enumvalues = c__EA_nir_move_options__enumvalues +try: + nir_can_move_instr = _libraries['libtinymesa_cpu.so'].nir_can_move_instr + nir_can_move_instr.restype = ctypes.c_bool + nir_can_move_instr.argtypes = [ctypes.POINTER(struct_nir_instr), nir_move_options] +except AttributeError: + pass +try: + nir_opt_sink = _libraries['libtinymesa_cpu.so'].nir_opt_sink + nir_opt_sink.restype = ctypes.c_bool + nir_opt_sink.argtypes = [ctypes.POINTER(struct_nir_shader), nir_move_options] +except AttributeError: + pass +try: + nir_opt_move = _libraries['libtinymesa_cpu.so'].nir_opt_move + nir_opt_move.restype = ctypes.c_bool + nir_opt_move.argtypes = [ctypes.POINTER(struct_nir_shader), nir_move_options] +except AttributeError: + pass +class struct_nir_opt_offsets_options(Structure): + pass + +struct_nir_opt_offsets_options._pack_ = 1 # source:False +struct_nir_opt_offsets_options._fields_ = [ + ('uniform_max', ctypes.c_uint32), + ('ubo_vec4_max', ctypes.c_uint32), + ('shared_max', ctypes.c_uint32), + ('shared_atomic_max', ctypes.c_uint32), + ('buffer_max', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('max_offset_cb', ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None))), + ('max_offset_data', ctypes.POINTER(None)), + ('allow_offset_wrap', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 7), +] + +nir_opt_offsets_options = struct_nir_opt_offsets_options +try: + nir_opt_offsets = _libraries['libtinymesa_cpu.so'].nir_opt_offsets + nir_opt_offsets.restype = ctypes.c_bool + nir_opt_offsets.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_opt_offsets_options)] +except AttributeError: + pass +class struct_nir_opt_peephole_select_options(Structure): + pass + +struct_nir_opt_peephole_select_options._pack_ = 1 # source:False +struct_nir_opt_peephole_select_options._fields_ = [ + ('limit', ctypes.c_uint32), + ('indirect_load_ok', ctypes.c_bool), + ('expensive_alu_ok', ctypes.c_bool), + ('discard_ok', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte), +] + +nir_opt_peephole_select_options = struct_nir_opt_peephole_select_options +try: + nir_opt_peephole_select = _libraries['libtinymesa_cpu.so'].nir_opt_peephole_select + nir_opt_peephole_select.restype = ctypes.c_bool + nir_opt_peephole_select.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_opt_peephole_select_options)] +except AttributeError: + pass +try: + nir_opt_reassociate_bfi = _libraries['libtinymesa_cpu.so'].nir_opt_reassociate_bfi + nir_opt_reassociate_bfi.restype = ctypes.c_bool + nir_opt_reassociate_bfi.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_rematerialize_compares = _libraries['libtinymesa_cpu.so'].nir_opt_rematerialize_compares + nir_opt_rematerialize_compares.restype = ctypes.c_bool + nir_opt_rematerialize_compares.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_remove_phis = _libraries['libtinymesa_cpu.so'].nir_opt_remove_phis + nir_opt_remove_phis.restype = ctypes.c_bool + nir_opt_remove_phis.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_remove_single_src_phis_block = _libraries['libtinymesa_cpu.so'].nir_remove_single_src_phis_block + nir_remove_single_src_phis_block.restype = ctypes.c_bool + nir_remove_single_src_phis_block.argtypes = [ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_opt_phi_precision = _libraries['libtinymesa_cpu.so'].nir_opt_phi_precision + nir_opt_phi_precision.restype = ctypes.c_bool + nir_opt_phi_precision.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_phi_to_bool = _libraries['libtinymesa_cpu.so'].nir_opt_phi_to_bool + nir_opt_phi_to_bool.restype = ctypes.c_bool + nir_opt_phi_to_bool.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_shrink_stores = _libraries['libtinymesa_cpu.so'].nir_opt_shrink_stores + nir_opt_shrink_stores.restype = ctypes.c_bool + nir_opt_shrink_stores.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_opt_shrink_vectors = _libraries['libtinymesa_cpu.so'].nir_opt_shrink_vectors + nir_opt_shrink_vectors.restype = ctypes.c_bool + nir_opt_shrink_vectors.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_opt_undef = _libraries['libtinymesa_cpu.so'].nir_opt_undef + nir_opt_undef.restype = ctypes.c_bool + nir_opt_undef.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_undef_to_zero = _libraries['libtinymesa_cpu.so'].nir_lower_undef_to_zero + nir_lower_undef_to_zero.restype = ctypes.c_bool + nir_lower_undef_to_zero.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_uniform_atomics = _libraries['libtinymesa_cpu.so'].nir_opt_uniform_atomics + nir_opt_uniform_atomics.restype = ctypes.c_bool + nir_opt_uniform_atomics.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_opt_uniform_subgroup = _libraries['libtinymesa_cpu.so'].nir_opt_uniform_subgroup + nir_opt_uniform_subgroup.restype = ctypes.c_bool + nir_opt_uniform_subgroup.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_lower_subgroups_options)] +except AttributeError: + pass +try: + nir_opt_vectorize = _libraries['libtinymesa_cpu.so'].nir_opt_vectorize + nir_opt_vectorize.restype = ctypes.c_bool + nir_opt_vectorize.argtypes = [ctypes.POINTER(struct_nir_shader), nir_vectorize_cb, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_opt_vectorize_io = _libraries['libtinymesa_cpu.so'].nir_opt_vectorize_io + nir_opt_vectorize_io.restype = ctypes.c_bool + nir_opt_vectorize_io.argtypes = [ctypes.POINTER(struct_nir_shader), nir_variable_mode, ctypes.c_bool] +except AttributeError: + pass +try: + nir_opt_move_discards_to_top = _libraries['libtinymesa_cpu.so'].nir_opt_move_discards_to_top + nir_opt_move_discards_to_top.restype = ctypes.c_bool + nir_opt_move_discards_to_top.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_ray_queries = _libraries['libtinymesa_cpu.so'].nir_opt_ray_queries + nir_opt_ray_queries.restype = ctypes.c_bool + nir_opt_ray_queries.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_ray_query_ranges = _libraries['libtinymesa_cpu.so'].nir_opt_ray_query_ranges + nir_opt_ray_query_ranges.restype = ctypes.c_bool + nir_opt_ray_query_ranges.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_opt_tex_skip_helpers = _libraries['libtinymesa_cpu.so'].nir_opt_tex_skip_helpers + nir_opt_tex_skip_helpers.restype = ctypes.c_bool + nir_opt_tex_skip_helpers.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_sweep = _libraries['libtinymesa_cpu.so'].nir_sweep + nir_sweep.restype = None + nir_sweep.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass + +# values for enumeration 'c__EA_gl_system_value' +c__EA_gl_system_value__enumvalues = { + 0: 'SYSTEM_VALUE_SUBGROUP_SIZE', + 1: 'SYSTEM_VALUE_SUBGROUP_INVOCATION', + 2: 'SYSTEM_VALUE_SUBGROUP_EQ_MASK', + 3: 'SYSTEM_VALUE_SUBGROUP_GE_MASK', + 4: 'SYSTEM_VALUE_SUBGROUP_GT_MASK', + 5: 'SYSTEM_VALUE_SUBGROUP_LE_MASK', + 6: 'SYSTEM_VALUE_SUBGROUP_LT_MASK', + 7: 'SYSTEM_VALUE_NUM_SUBGROUPS', + 8: 'SYSTEM_VALUE_SUBGROUP_ID', + 9: 'SYSTEM_VALUE_VERTEX_ID', + 10: 'SYSTEM_VALUE_INSTANCE_ID', + 11: 'SYSTEM_VALUE_INSTANCE_INDEX', + 12: 'SYSTEM_VALUE_VERTEX_ID_ZERO_BASE', + 13: 'SYSTEM_VALUE_BASE_VERTEX', + 14: 'SYSTEM_VALUE_FIRST_VERTEX', + 15: 'SYSTEM_VALUE_IS_INDEXED_DRAW', + 16: 'SYSTEM_VALUE_BASE_INSTANCE', + 17: 'SYSTEM_VALUE_DRAW_ID', + 18: 'SYSTEM_VALUE_INVOCATION_ID', + 19: 'SYSTEM_VALUE_FRAG_COORD', + 20: 'SYSTEM_VALUE_PIXEL_COORD', + 21: 'SYSTEM_VALUE_FRAG_COORD_Z', + 22: 'SYSTEM_VALUE_FRAG_COORD_W', + 23: 'SYSTEM_VALUE_POINT_COORD', + 24: 'SYSTEM_VALUE_LINE_COORD', + 25: 'SYSTEM_VALUE_FRONT_FACE', + 26: 'SYSTEM_VALUE_FRONT_FACE_FSIGN', + 27: 'SYSTEM_VALUE_SAMPLE_ID', + 28: 'SYSTEM_VALUE_SAMPLE_POS', + 29: 'SYSTEM_VALUE_SAMPLE_POS_OR_CENTER', + 30: 'SYSTEM_VALUE_SAMPLE_MASK_IN', + 31: 'SYSTEM_VALUE_LAYER_ID', + 32: 'SYSTEM_VALUE_HELPER_INVOCATION', + 33: 'SYSTEM_VALUE_COLOR0', + 34: 'SYSTEM_VALUE_COLOR1', + 35: 'SYSTEM_VALUE_TESS_COORD', + 36: 'SYSTEM_VALUE_VERTICES_IN', + 37: 'SYSTEM_VALUE_PRIMITIVE_ID', + 38: 'SYSTEM_VALUE_TESS_LEVEL_OUTER', + 39: 'SYSTEM_VALUE_TESS_LEVEL_INNER', + 40: 'SYSTEM_VALUE_TESS_LEVEL_OUTER_DEFAULT', + 41: 'SYSTEM_VALUE_TESS_LEVEL_INNER_DEFAULT', + 42: 'SYSTEM_VALUE_LOCAL_INVOCATION_ID', + 43: 'SYSTEM_VALUE_LOCAL_INVOCATION_INDEX', + 44: 'SYSTEM_VALUE_GLOBAL_INVOCATION_ID', + 45: 'SYSTEM_VALUE_BASE_GLOBAL_INVOCATION_ID', + 46: 'SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX', + 47: 'SYSTEM_VALUE_WORKGROUP_ID', + 48: 'SYSTEM_VALUE_BASE_WORKGROUP_ID', + 49: 'SYSTEM_VALUE_WORKGROUP_INDEX', + 50: 'SYSTEM_VALUE_NUM_WORKGROUPS', + 51: 'SYSTEM_VALUE_WORKGROUP_SIZE', + 52: 'SYSTEM_VALUE_GLOBAL_GROUP_SIZE', + 53: 'SYSTEM_VALUE_WORK_DIM', + 54: 'SYSTEM_VALUE_USER_DATA_AMD', + 55: 'SYSTEM_VALUE_DEVICE_INDEX', + 56: 'SYSTEM_VALUE_VIEW_INDEX', + 57: 'SYSTEM_VALUE_VERTEX_CNT', + 58: 'SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL', + 59: 'SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE', + 60: 'SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID', + 61: 'SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTER_RHW', + 62: 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL', + 63: 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID', + 64: 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_SAMPLE', + 65: 'SYSTEM_VALUE_BARYCENTRIC_PULL_MODEL', + 66: 'SYSTEM_VALUE_BARYCENTRIC_PERSP_COORD', + 67: 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_COORD', + 68: 'SYSTEM_VALUE_RAY_LAUNCH_ID', + 69: 'SYSTEM_VALUE_RAY_LAUNCH_SIZE', + 70: 'SYSTEM_VALUE_RAY_WORLD_ORIGIN', + 71: 'SYSTEM_VALUE_RAY_WORLD_DIRECTION', + 72: 'SYSTEM_VALUE_RAY_OBJECT_ORIGIN', + 73: 'SYSTEM_VALUE_RAY_OBJECT_DIRECTION', + 74: 'SYSTEM_VALUE_RAY_T_MIN', + 75: 'SYSTEM_VALUE_RAY_T_MAX', + 76: 'SYSTEM_VALUE_RAY_OBJECT_TO_WORLD', + 77: 'SYSTEM_VALUE_RAY_WORLD_TO_OBJECT', + 78: 'SYSTEM_VALUE_RAY_HIT_KIND', + 79: 'SYSTEM_VALUE_RAY_FLAGS', + 80: 'SYSTEM_VALUE_RAY_GEOMETRY_INDEX', + 81: 'SYSTEM_VALUE_RAY_INSTANCE_CUSTOM_INDEX', + 82: 'SYSTEM_VALUE_CULL_MASK', + 83: 'SYSTEM_VALUE_RAY_TRIANGLE_VERTEX_POSITIONS', + 84: 'SYSTEM_VALUE_MESH_VIEW_COUNT', + 85: 'SYSTEM_VALUE_MESH_VIEW_INDICES', + 86: 'SYSTEM_VALUE_GS_HEADER_IR3', + 87: 'SYSTEM_VALUE_TCS_HEADER_IR3', + 88: 'SYSTEM_VALUE_REL_PATCH_ID_IR3', + 89: 'SYSTEM_VALUE_FRAG_SHADING_RATE', + 90: 'SYSTEM_VALUE_FULLY_COVERED', + 91: 'SYSTEM_VALUE_FRAG_SIZE', + 92: 'SYSTEM_VALUE_FRAG_INVOCATION_COUNT', + 93: 'SYSTEM_VALUE_SHADER_INDEX', + 94: 'SYSTEM_VALUE_COALESCED_INPUT_COUNT', + 95: 'SYSTEM_VALUE_WARPS_PER_SM_NV', + 96: 'SYSTEM_VALUE_SM_COUNT_NV', + 97: 'SYSTEM_VALUE_WARP_ID_NV', + 98: 'SYSTEM_VALUE_SM_ID_NV', + 99: 'SYSTEM_VALUE_MAX', +} +SYSTEM_VALUE_SUBGROUP_SIZE = 0 +SYSTEM_VALUE_SUBGROUP_INVOCATION = 1 +SYSTEM_VALUE_SUBGROUP_EQ_MASK = 2 +SYSTEM_VALUE_SUBGROUP_GE_MASK = 3 +SYSTEM_VALUE_SUBGROUP_GT_MASK = 4 +SYSTEM_VALUE_SUBGROUP_LE_MASK = 5 +SYSTEM_VALUE_SUBGROUP_LT_MASK = 6 +SYSTEM_VALUE_NUM_SUBGROUPS = 7 +SYSTEM_VALUE_SUBGROUP_ID = 8 +SYSTEM_VALUE_VERTEX_ID = 9 +SYSTEM_VALUE_INSTANCE_ID = 10 +SYSTEM_VALUE_INSTANCE_INDEX = 11 +SYSTEM_VALUE_VERTEX_ID_ZERO_BASE = 12 +SYSTEM_VALUE_BASE_VERTEX = 13 +SYSTEM_VALUE_FIRST_VERTEX = 14 +SYSTEM_VALUE_IS_INDEXED_DRAW = 15 +SYSTEM_VALUE_BASE_INSTANCE = 16 +SYSTEM_VALUE_DRAW_ID = 17 +SYSTEM_VALUE_INVOCATION_ID = 18 +SYSTEM_VALUE_FRAG_COORD = 19 +SYSTEM_VALUE_PIXEL_COORD = 20 +SYSTEM_VALUE_FRAG_COORD_Z = 21 +SYSTEM_VALUE_FRAG_COORD_W = 22 +SYSTEM_VALUE_POINT_COORD = 23 +SYSTEM_VALUE_LINE_COORD = 24 +SYSTEM_VALUE_FRONT_FACE = 25 +SYSTEM_VALUE_FRONT_FACE_FSIGN = 26 +SYSTEM_VALUE_SAMPLE_ID = 27 +SYSTEM_VALUE_SAMPLE_POS = 28 +SYSTEM_VALUE_SAMPLE_POS_OR_CENTER = 29 +SYSTEM_VALUE_SAMPLE_MASK_IN = 30 +SYSTEM_VALUE_LAYER_ID = 31 +SYSTEM_VALUE_HELPER_INVOCATION = 32 +SYSTEM_VALUE_COLOR0 = 33 +SYSTEM_VALUE_COLOR1 = 34 +SYSTEM_VALUE_TESS_COORD = 35 +SYSTEM_VALUE_VERTICES_IN = 36 +SYSTEM_VALUE_PRIMITIVE_ID = 37 +SYSTEM_VALUE_TESS_LEVEL_OUTER = 38 +SYSTEM_VALUE_TESS_LEVEL_INNER = 39 +SYSTEM_VALUE_TESS_LEVEL_OUTER_DEFAULT = 40 +SYSTEM_VALUE_TESS_LEVEL_INNER_DEFAULT = 41 +SYSTEM_VALUE_LOCAL_INVOCATION_ID = 42 +SYSTEM_VALUE_LOCAL_INVOCATION_INDEX = 43 +SYSTEM_VALUE_GLOBAL_INVOCATION_ID = 44 +SYSTEM_VALUE_BASE_GLOBAL_INVOCATION_ID = 45 +SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX = 46 +SYSTEM_VALUE_WORKGROUP_ID = 47 +SYSTEM_VALUE_BASE_WORKGROUP_ID = 48 +SYSTEM_VALUE_WORKGROUP_INDEX = 49 +SYSTEM_VALUE_NUM_WORKGROUPS = 50 +SYSTEM_VALUE_WORKGROUP_SIZE = 51 +SYSTEM_VALUE_GLOBAL_GROUP_SIZE = 52 +SYSTEM_VALUE_WORK_DIM = 53 +SYSTEM_VALUE_USER_DATA_AMD = 54 +SYSTEM_VALUE_DEVICE_INDEX = 55 +SYSTEM_VALUE_VIEW_INDEX = 56 +SYSTEM_VALUE_VERTEX_CNT = 57 +SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL = 58 +SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE = 59 +SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID = 60 +SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTER_RHW = 61 +SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL = 62 +SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID = 63 +SYSTEM_VALUE_BARYCENTRIC_LINEAR_SAMPLE = 64 +SYSTEM_VALUE_BARYCENTRIC_PULL_MODEL = 65 +SYSTEM_VALUE_BARYCENTRIC_PERSP_COORD = 66 +SYSTEM_VALUE_BARYCENTRIC_LINEAR_COORD = 67 +SYSTEM_VALUE_RAY_LAUNCH_ID = 68 +SYSTEM_VALUE_RAY_LAUNCH_SIZE = 69 +SYSTEM_VALUE_RAY_WORLD_ORIGIN = 70 +SYSTEM_VALUE_RAY_WORLD_DIRECTION = 71 +SYSTEM_VALUE_RAY_OBJECT_ORIGIN = 72 +SYSTEM_VALUE_RAY_OBJECT_DIRECTION = 73 +SYSTEM_VALUE_RAY_T_MIN = 74 +SYSTEM_VALUE_RAY_T_MAX = 75 +SYSTEM_VALUE_RAY_OBJECT_TO_WORLD = 76 +SYSTEM_VALUE_RAY_WORLD_TO_OBJECT = 77 +SYSTEM_VALUE_RAY_HIT_KIND = 78 +SYSTEM_VALUE_RAY_FLAGS = 79 +SYSTEM_VALUE_RAY_GEOMETRY_INDEX = 80 +SYSTEM_VALUE_RAY_INSTANCE_CUSTOM_INDEX = 81 +SYSTEM_VALUE_CULL_MASK = 82 +SYSTEM_VALUE_RAY_TRIANGLE_VERTEX_POSITIONS = 83 +SYSTEM_VALUE_MESH_VIEW_COUNT = 84 +SYSTEM_VALUE_MESH_VIEW_INDICES = 85 +SYSTEM_VALUE_GS_HEADER_IR3 = 86 +SYSTEM_VALUE_TCS_HEADER_IR3 = 87 +SYSTEM_VALUE_REL_PATCH_ID_IR3 = 88 +SYSTEM_VALUE_FRAG_SHADING_RATE = 89 +SYSTEM_VALUE_FULLY_COVERED = 90 +SYSTEM_VALUE_FRAG_SIZE = 91 +SYSTEM_VALUE_FRAG_INVOCATION_COUNT = 92 +SYSTEM_VALUE_SHADER_INDEX = 93 +SYSTEM_VALUE_COALESCED_INPUT_COUNT = 94 +SYSTEM_VALUE_WARPS_PER_SM_NV = 95 +SYSTEM_VALUE_SM_COUNT_NV = 96 +SYSTEM_VALUE_WARP_ID_NV = 97 +SYSTEM_VALUE_SM_ID_NV = 98 +SYSTEM_VALUE_MAX = 99 +c__EA_gl_system_value = ctypes.c_uint32 # enum +gl_system_value = c__EA_gl_system_value +gl_system_value__enumvalues = c__EA_gl_system_value__enumvalues +try: + nir_intrinsic_from_system_value = _libraries['libtinymesa_cpu.so'].nir_intrinsic_from_system_value + nir_intrinsic_from_system_value.restype = nir_intrinsic_op + nir_intrinsic_from_system_value.argtypes = [gl_system_value] +except AttributeError: + pass +try: + nir_system_value_from_intrinsic = _libraries['libtinymesa_cpu.so'].nir_system_value_from_intrinsic + nir_system_value_from_intrinsic.restype = gl_system_value + nir_system_value_from_intrinsic.argtypes = [nir_intrinsic_op] +except AttributeError: + pass +try: + nir_variable_is_in_ubo = _libraries['FIXME_STUB'].nir_variable_is_in_ubo + nir_variable_is_in_ubo.restype = ctypes.c_bool + nir_variable_is_in_ubo.argtypes = [ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_variable_is_in_ssbo = _libraries['FIXME_STUB'].nir_variable_is_in_ssbo + nir_variable_is_in_ssbo.restype = ctypes.c_bool + nir_variable_is_in_ssbo.argtypes = [ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_variable_is_in_block = _libraries['FIXME_STUB'].nir_variable_is_in_block + nir_variable_is_in_block.restype = ctypes.c_bool + nir_variable_is_in_block.argtypes = [ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_variable_count_slots = _libraries['FIXME_STUB'].nir_variable_count_slots + nir_variable_count_slots.restype = ctypes.c_uint32 + nir_variable_count_slots.argtypes = [ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + nir_deref_count_slots = _libraries['FIXME_STUB'].nir_deref_count_slots + nir_deref_count_slots.restype = ctypes.c_uint32 + nir_deref_count_slots.argtypes = [ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +class struct_nir_unsigned_upper_bound_config(Structure): + pass + +struct_nir_unsigned_upper_bound_config._pack_ = 1 # source:False +struct_nir_unsigned_upper_bound_config._fields_ = [ + ('min_subgroup_size', ctypes.c_uint32), + ('max_subgroup_size', ctypes.c_uint32), + ('max_workgroup_invocations', ctypes.c_uint32), + ('max_workgroup_count', ctypes.c_uint32 * 3), + ('max_workgroup_size', ctypes.c_uint32 * 3), + ('vertex_attrib_max', ctypes.c_uint32 * 32), +] + +nir_unsigned_upper_bound_config = struct_nir_unsigned_upper_bound_config +try: + nir_unsigned_upper_bound = _libraries['libtinymesa_cpu.so'].nir_unsigned_upper_bound + nir_unsigned_upper_bound.restype = uint32_t + nir_unsigned_upper_bound.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_hash_table), nir_scalar, ctypes.POINTER(struct_nir_unsigned_upper_bound_config)] +except AttributeError: + pass +try: + nir_addition_might_overflow = _libraries['libtinymesa_cpu.so'].nir_addition_might_overflow + nir_addition_might_overflow.restype = ctypes.c_bool + nir_addition_might_overflow.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_hash_table), nir_scalar, ctypes.c_uint32, ctypes.POINTER(struct_nir_unsigned_upper_bound_config)] +except AttributeError: + pass +class struct_nir_opt_preamble_options(Structure): + pass + +struct_nir_opt_preamble_options._pack_ = 1 # source:False +struct_nir_opt_preamble_options._fields_ = [ + ('drawid_uniform', ctypes.c_bool), + ('subgroup_size_uniform', ctypes.c_bool), + ('load_workgroup_size_allowed', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 5), + ('def_size', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_nir_def), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(c__EA_nir_preamble_class))), + ('preamble_storage_size', ctypes.c_uint32 * 2), + ('instr_cost_cb', ctypes.CFUNCTYPE(ctypes.c_float, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('rewrite_cost_cb', ctypes.CFUNCTYPE(ctypes.c_float, ctypes.POINTER(struct_nir_def), ctypes.POINTER(None))), + ('avoid_instr_cb', ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None))), + ('cb_data', ctypes.POINTER(None)), +] + +nir_opt_preamble_options = struct_nir_opt_preamble_options +try: + nir_opt_preamble = _libraries['libtinymesa_cpu.so'].nir_opt_preamble + nir_opt_preamble.restype = ctypes.c_bool + nir_opt_preamble.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_opt_preamble_options), ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + nir_shader_get_preamble = _libraries['libtinymesa_cpu.so'].nir_shader_get_preamble + nir_shader_get_preamble.restype = ctypes.POINTER(struct_nir_function_impl) + nir_shader_get_preamble.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_lower_point_smooth = _libraries['libtinymesa_cpu.so'].nir_lower_point_smooth + nir_lower_point_smooth.restype = ctypes.c_bool + nir_lower_point_smooth.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_lower_poly_line_smooth = _libraries['libtinymesa_cpu.so'].nir_lower_poly_line_smooth + nir_lower_poly_line_smooth.restype = ctypes.c_bool + nir_lower_poly_line_smooth.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_mod_analysis = _libraries['libtinymesa_cpu.so'].nir_mod_analysis + nir_mod_analysis.restype = ctypes.c_bool + nir_mod_analysis.argtypes = [nir_scalar, nir_alu_type, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32)] +except AttributeError: + pass +try: + nir_remove_tex_shadow = _libraries['libtinymesa_cpu.so'].nir_remove_tex_shadow + nir_remove_tex_shadow.restype = ctypes.c_bool + nir_remove_tex_shadow.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_trivialize_registers = _libraries['libtinymesa_cpu.so'].nir_trivialize_registers + nir_trivialize_registers.restype = ctypes.c_bool + nir_trivialize_registers.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_static_workgroup_size = _libraries['libtinymesa_cpu.so'].nir_static_workgroup_size + nir_static_workgroup_size.restype = ctypes.c_uint32 + nir_static_workgroup_size.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_reg_get_decl = _libraries['FIXME_STUB'].nir_reg_get_decl + nir_reg_get_decl.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_reg_get_decl.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_next_decl_reg = _libraries['FIXME_STUB'].nir_next_decl_reg + nir_next_decl_reg.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_next_decl_reg.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_after_reg_decls = _libraries['FIXME_STUB'].nir_after_reg_decls + nir_after_reg_decls.restype = nir_cursor + nir_after_reg_decls.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_is_load_reg = _libraries['FIXME_STUB'].nir_is_load_reg + nir_is_load_reg.restype = ctypes.c_bool + nir_is_load_reg.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_is_store_reg = _libraries['FIXME_STUB'].nir_is_store_reg + nir_is_store_reg.restype = ctypes.c_bool + nir_is_store_reg.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + nir_load_reg_for_def = _libraries['FIXME_STUB'].nir_load_reg_for_def + nir_load_reg_for_def.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_load_reg_for_def.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_store_reg_for_def = _libraries['FIXME_STUB'].nir_store_reg_for_def + nir_store_reg_for_def.restype = ctypes.POINTER(struct_nir_intrinsic_instr) + nir_store_reg_for_def.argtypes = [ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +class struct_nir_use_dominance_state(Structure): + pass + +nir_use_dominance_state = struct_nir_use_dominance_state +try: + nir_calc_use_dominance_impl = _libraries['libtinymesa_cpu.so'].nir_calc_use_dominance_impl + nir_calc_use_dominance_impl.restype = ctypes.POINTER(struct_nir_use_dominance_state) + nir_calc_use_dominance_impl.argtypes = [ctypes.POINTER(struct_nir_function_impl), ctypes.c_bool] +except AttributeError: + pass +try: + nir_get_immediate_use_dominator = _libraries['libtinymesa_cpu.so'].nir_get_immediate_use_dominator + nir_get_immediate_use_dominator.restype = ctypes.POINTER(struct_nir_instr) + nir_get_immediate_use_dominator.argtypes = [ctypes.POINTER(struct_nir_use_dominance_state), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_use_dominance_lca = _libraries['libtinymesa_cpu.so'].nir_use_dominance_lca + nir_use_dominance_lca.restype = ctypes.POINTER(struct_nir_instr) + nir_use_dominance_lca.argtypes = [ctypes.POINTER(struct_nir_use_dominance_state), ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_instr_dominates_use = _libraries['libtinymesa_cpu.so'].nir_instr_dominates_use + nir_instr_dominates_use.restype = ctypes.c_bool + nir_instr_dominates_use.argtypes = [ctypes.POINTER(struct_nir_use_dominance_state), ctypes.POINTER(struct_nir_instr), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_print_use_dominators = _libraries['libtinymesa_cpu.so'].nir_print_use_dominators + nir_print_use_dominators.restype = None + nir_print_use_dominators.argtypes = [ctypes.POINTER(struct_nir_use_dominance_state), ctypes.POINTER(ctypes.POINTER(struct_nir_instr)), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_verts_in_output_prim = _libraries['FIXME_STUB'].nir_verts_in_output_prim + nir_verts_in_output_prim.restype = ctypes.c_uint32 + nir_verts_in_output_prim.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +class struct_c__SA_nir_output_deps(Structure): + pass + +class struct_c__SA_nir_output_deps_0(Structure): + pass + +struct_c__SA_nir_output_deps_0._pack_ = 1 # source:False +struct_c__SA_nir_output_deps_0._fields_ = [ + ('instr_list', ctypes.POINTER(ctypes.POINTER(struct_nir_instr))), + ('num_instr', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +struct_c__SA_nir_output_deps._pack_ = 1 # source:False +struct_c__SA_nir_output_deps._fields_ = [ + ('output', struct_c__SA_nir_output_deps_0 * 112), +] + +nir_output_deps = struct_c__SA_nir_output_deps +try: + nir_gather_output_dependencies = _libraries['libtinymesa_cpu.so'].nir_gather_output_dependencies + nir_gather_output_dependencies.restype = None + nir_gather_output_dependencies.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_c__SA_nir_output_deps)] +except AttributeError: + pass +try: + nir_free_output_dependencies = _libraries['libtinymesa_cpu.so'].nir_free_output_dependencies + nir_free_output_dependencies.restype = None + nir_free_output_dependencies.argtypes = [ctypes.POINTER(struct_c__SA_nir_output_deps)] +except AttributeError: + pass +class struct_c__SA_nir_input_to_output_deps(Structure): + pass + +class struct_c__SA_nir_input_to_output_deps_0(Structure): + pass + +struct_c__SA_nir_input_to_output_deps_0._pack_ = 1 # source:False +struct_c__SA_nir_input_to_output_deps_0._fields_ = [ + ('inputs', ctypes.c_uint32 * 28), + ('defined', ctypes.c_bool), + ('uses_ssbo_reads', ctypes.c_bool), + ('uses_image_reads', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte), +] + +struct_c__SA_nir_input_to_output_deps._pack_ = 1 # source:False +struct_c__SA_nir_input_to_output_deps._fields_ = [ + ('output', struct_c__SA_nir_input_to_output_deps_0 * 112), +] + +nir_input_to_output_deps = struct_c__SA_nir_input_to_output_deps +try: + nir_gather_input_to_output_dependencies = _libraries['libtinymesa_cpu.so'].nir_gather_input_to_output_dependencies + nir_gather_input_to_output_dependencies.restype = None + nir_gather_input_to_output_dependencies.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_c__SA_nir_input_to_output_deps)] +except AttributeError: + pass +try: + nir_print_input_to_output_deps = _libraries['libtinymesa_cpu.so'].nir_print_input_to_output_deps + nir_print_input_to_output_deps.restype = None + nir_print_input_to_output_deps.argtypes = [ctypes.POINTER(struct_c__SA_nir_input_to_output_deps), ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct__IO_FILE)] +except AttributeError: + pass +class struct_c__SA_nir_output_clipper_var_groups(Structure): + pass + +struct_c__SA_nir_output_clipper_var_groups._pack_ = 1 # source:False +struct_c__SA_nir_output_clipper_var_groups._fields_ = [ + ('pos_only', ctypes.c_uint32 * 28), + ('var_only', ctypes.c_uint32 * 28), + ('both', ctypes.c_uint32 * 28), +] + +nir_output_clipper_var_groups = struct_c__SA_nir_output_clipper_var_groups +try: + nir_gather_output_clipper_var_groups = _libraries['libtinymesa_cpu.so'].nir_gather_output_clipper_var_groups + nir_gather_output_clipper_var_groups.restype = None + nir_gather_output_clipper_var_groups.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_c__SA_nir_output_clipper_var_groups)] +except AttributeError: + pass +nir_builder = struct_nir_builder +try: + nir_builder_create = _libraries['FIXME_STUB'].nir_builder_create + nir_builder_create.restype = nir_builder + nir_builder_create.argtypes = [ctypes.POINTER(struct_nir_function_impl)] +except AttributeError: + pass +try: + nir_builder_at = _libraries['FIXME_STUB'].nir_builder_at + nir_builder_at.restype = nir_builder + nir_builder_at.argtypes = [nir_cursor] +except AttributeError: + pass +try: + nir_builder_init_simple_shader = _libraries['libtinymesa_cpu.so'].nir_builder_init_simple_shader + nir_builder_init_simple_shader.restype = nir_builder + nir_builder_init_simple_shader.argtypes = [gl_shader_stage, ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +nir_instr_pass_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_instr), ctypes.POINTER(None)) +nir_intrinsic_pass_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_intrinsic_instr), ctypes.POINTER(None)) +nir_alu_pass_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_alu_instr), ctypes.POINTER(None)) +nir_tex_pass_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_tex_instr), ctypes.POINTER(None)) +nir_phi_pass_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_phi_instr), ctypes.POINTER(None)) +try: + nir_function_instructions_pass = _libraries['FIXME_STUB'].nir_function_instructions_pass + nir_function_instructions_pass.restype = ctypes.c_bool + nir_function_instructions_pass.argtypes = [ctypes.POINTER(struct_nir_function_impl), nir_instr_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_instructions_pass = _libraries['FIXME_STUB'].nir_shader_instructions_pass + nir_shader_instructions_pass.restype = ctypes.c_bool + nir_shader_instructions_pass.argtypes = [ctypes.POINTER(struct_nir_shader), nir_instr_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_function_intrinsics_pass = _libraries['FIXME_STUB'].nir_function_intrinsics_pass + nir_function_intrinsics_pass.restype = ctypes.c_bool + nir_function_intrinsics_pass.argtypes = [ctypes.POINTER(struct_nir_function_impl), nir_intrinsic_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_intrinsics_pass = _libraries['FIXME_STUB'].nir_shader_intrinsics_pass + nir_shader_intrinsics_pass.restype = ctypes.c_bool + nir_shader_intrinsics_pass.argtypes = [ctypes.POINTER(struct_nir_shader), nir_intrinsic_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_alu_pass = _libraries['FIXME_STUB'].nir_shader_alu_pass + nir_shader_alu_pass.restype = ctypes.c_bool + nir_shader_alu_pass.argtypes = [ctypes.POINTER(struct_nir_shader), nir_alu_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_tex_pass = _libraries['FIXME_STUB'].nir_shader_tex_pass + nir_shader_tex_pass.restype = ctypes.c_bool + nir_shader_tex_pass.argtypes = [ctypes.POINTER(struct_nir_shader), nir_tex_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_shader_phi_pass = _libraries['FIXME_STUB'].nir_shader_phi_pass + nir_shader_phi_pass.restype = ctypes.c_bool + nir_shader_phi_pass.argtypes = [ctypes.POINTER(struct_nir_shader), nir_phi_pass_cb, nir_metadata, ctypes.POINTER(None)] +except AttributeError: + pass +try: + nir_builder_instr_insert = _libraries['libtinymesa_cpu.so'].nir_builder_instr_insert + nir_builder_instr_insert.restype = None + nir_builder_instr_insert.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_builder_instr_insert_at_top = _libraries['libtinymesa_cpu.so'].nir_builder_instr_insert_at_top + nir_builder_instr_insert_at_top.restype = None + nir_builder_instr_insert_at_top.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_instr)] +except AttributeError: + pass +try: + nir_builder_last_instr = _libraries['FIXME_STUB'].nir_builder_last_instr + nir_builder_last_instr.restype = ctypes.POINTER(struct_nir_instr) + nir_builder_last_instr.argtypes = [ctypes.POINTER(struct_nir_builder)] +except AttributeError: + pass +try: + nir_build_alu = _libraries['libtinymesa_cpu.so'].nir_build_alu + nir_build_alu.restype = ctypes.POINTER(struct_nir_def) + nir_build_alu.argtypes = [ctypes.POINTER(struct_nir_builder), nir_op, ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_alu1 = _libraries['libtinymesa_cpu.so'].nir_build_alu1 + nir_build_alu1.restype = ctypes.POINTER(struct_nir_def) + nir_build_alu1.argtypes = [ctypes.POINTER(struct_nir_builder), nir_op, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_alu2 = _libraries['libtinymesa_cpu.so'].nir_build_alu2 + nir_build_alu2.restype = ctypes.POINTER(struct_nir_def) + nir_build_alu2.argtypes = [ctypes.POINTER(struct_nir_builder), nir_op, ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_alu3 = _libraries['libtinymesa_cpu.so'].nir_build_alu3 + nir_build_alu3.restype = ctypes.POINTER(struct_nir_def) + nir_build_alu3.argtypes = [ctypes.POINTER(struct_nir_builder), nir_op, ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_alu4 = _libraries['libtinymesa_cpu.so'].nir_build_alu4 + nir_build_alu4.restype = ctypes.POINTER(struct_nir_def) + nir_build_alu4.argtypes = [ctypes.POINTER(struct_nir_builder), nir_op, ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_alu_src_arr = _libraries['libtinymesa_cpu.so'].nir_build_alu_src_arr + nir_build_alu_src_arr.restype = ctypes.POINTER(struct_nir_def) + nir_build_alu_src_arr.argtypes = [ctypes.POINTER(struct_nir_builder), nir_op, ctypes.POINTER(ctypes.POINTER(struct_nir_def))] +except AttributeError: + pass +try: + nir_build_tex_deref_instr = _libraries['libtinymesa_cpu.so'].nir_build_tex_deref_instr + nir_build_tex_deref_instr.restype = ctypes.POINTER(struct_nir_def) + nir_build_tex_deref_instr.argtypes = [ctypes.POINTER(struct_nir_builder), nir_texop, ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), ctypes.c_uint32, ctypes.POINTER(struct_nir_tex_src)] +except AttributeError: + pass +try: + nir_builder_cf_insert = _libraries['libtinymesa_cpu.so'].nir_builder_cf_insert + nir_builder_cf_insert.restype = None + nir_builder_cf_insert.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_builder_is_inside_cf = _libraries['libtinymesa_cpu.so'].nir_builder_is_inside_cf + nir_builder_is_inside_cf.restype = ctypes.c_bool + nir_builder_is_inside_cf.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_cf_node)] +except AttributeError: + pass +try: + nir_push_if = _libraries['libtinymesa_cpu.so'].nir_push_if + nir_push_if.restype = ctypes.POINTER(struct_nir_if) + nir_push_if.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_push_else = _libraries['libtinymesa_cpu.so'].nir_push_else + nir_push_else.restype = ctypes.POINTER(struct_nir_if) + nir_push_else.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_pop_if = _libraries['libtinymesa_cpu.so'].nir_pop_if + nir_pop_if.restype = None + nir_pop_if.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_if)] +except AttributeError: + pass +try: + nir_if_phi = _libraries['libtinymesa_cpu.so'].nir_if_phi + nir_if_phi.restype = ctypes.POINTER(struct_nir_def) + nir_if_phi.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_push_loop = _libraries['libtinymesa_cpu.so'].nir_push_loop + nir_push_loop.restype = ctypes.POINTER(struct_nir_loop) + nir_push_loop.argtypes = [ctypes.POINTER(struct_nir_builder)] +except AttributeError: + pass +try: + nir_push_continue = _libraries['libtinymesa_cpu.so'].nir_push_continue + nir_push_continue.restype = ctypes.POINTER(struct_nir_loop) + nir_push_continue.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_pop_loop = _libraries['libtinymesa_cpu.so'].nir_pop_loop + nir_pop_loop.restype = None + nir_pop_loop.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_loop)] +except AttributeError: + pass +try: + nir_undef = _libraries['FIXME_STUB'].nir_undef + nir_undef.restype = ctypes.POINTER(struct_nir_def) + nir_undef.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_build_imm = _libraries['FIXME_STUB'].nir_build_imm + nir_build_imm.restype = ctypes.POINTER(struct_nir_def) + nir_build_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32, ctypes.POINTER(union_c__UA_nir_const_value)] +except AttributeError: + pass +try: + nir_imm_zero = _libraries['FIXME_STUB'].nir_imm_zero + nir_imm_zero.restype = ctypes.POINTER(struct_nir_def) + nir_imm_zero.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_boolN_t = _libraries['FIXME_STUB'].nir_imm_boolN_t + nir_imm_boolN_t.restype = ctypes.POINTER(struct_nir_def) + nir_imm_boolN_t.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_bool, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_bool = _libraries['FIXME_STUB'].nir_imm_bool + nir_imm_bool.restype = ctypes.POINTER(struct_nir_def) + nir_imm_bool.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_bool] +except AttributeError: + pass +try: + nir_imm_true = _libraries['FIXME_STUB'].nir_imm_true + nir_imm_true.restype = ctypes.POINTER(struct_nir_def) + nir_imm_true.argtypes = [ctypes.POINTER(struct_nir_builder)] +except AttributeError: + pass +try: + nir_imm_false = _libraries['FIXME_STUB'].nir_imm_false + nir_imm_false.restype = ctypes.POINTER(struct_nir_def) + nir_imm_false.argtypes = [ctypes.POINTER(struct_nir_builder)] +except AttributeError: + pass +try: + nir_imm_floatN_t = _libraries['FIXME_STUB'].nir_imm_floatN_t + nir_imm_floatN_t.restype = ctypes.POINTER(struct_nir_def) + nir_imm_floatN_t.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_double, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_float16 = _libraries['FIXME_STUB'].nir_imm_float16 + nir_imm_float16.restype = ctypes.POINTER(struct_nir_def) + nir_imm_float16.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_float] +except AttributeError: + pass +try: + nir_imm_float = _libraries['FIXME_STUB'].nir_imm_float + nir_imm_float.restype = ctypes.POINTER(struct_nir_def) + nir_imm_float.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_float] +except AttributeError: + pass +try: + nir_imm_double = _libraries['FIXME_STUB'].nir_imm_double + nir_imm_double.restype = ctypes.POINTER(struct_nir_def) + nir_imm_double.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_double] +except AttributeError: + pass +try: + nir_imm_vec2 = _libraries['FIXME_STUB'].nir_imm_vec2 + nir_imm_vec2.restype = ctypes.POINTER(struct_nir_def) + nir_imm_vec2.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_float, ctypes.c_float] +except AttributeError: + pass +try: + nir_imm_vec3 = _libraries['FIXME_STUB'].nir_imm_vec3 + nir_imm_vec3.restype = ctypes.POINTER(struct_nir_def) + nir_imm_vec3.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_float, ctypes.c_float, ctypes.c_float] +except AttributeError: + pass +try: + nir_imm_vec4 = _libraries['FIXME_STUB'].nir_imm_vec4 + nir_imm_vec4.restype = ctypes.POINTER(struct_nir_def) + nir_imm_vec4.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_float, ctypes.c_float, ctypes.c_float, ctypes.c_float] +except AttributeError: + pass +try: + nir_imm_vec4_16 = _libraries['FIXME_STUB'].nir_imm_vec4_16 + nir_imm_vec4_16.restype = ctypes.POINTER(struct_nir_def) + nir_imm_vec4_16.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_float, ctypes.c_float, ctypes.c_float, ctypes.c_float] +except AttributeError: + pass +try: + nir_imm_intN_t = _libraries['FIXME_STUB'].nir_imm_intN_t + nir_imm_intN_t.restype = ctypes.POINTER(struct_nir_def) + nir_imm_intN_t.argtypes = [ctypes.POINTER(struct_nir_builder), uint64_t, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_int = _libraries['FIXME_STUB'].nir_imm_int + nir_imm_int.restype = ctypes.POINTER(struct_nir_def) + nir_imm_int.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_int32] +except AttributeError: + pass +try: + nir_imm_int64 = _libraries['FIXME_STUB'].nir_imm_int64 + nir_imm_int64.restype = ctypes.POINTER(struct_nir_def) + nir_imm_int64.argtypes = [ctypes.POINTER(struct_nir_builder), int64_t] +except AttributeError: + pass +try: + nir_imm_ivec2 = _libraries['FIXME_STUB'].nir_imm_ivec2 + nir_imm_ivec2.restype = ctypes.POINTER(struct_nir_def) + nir_imm_ivec2.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_int32, ctypes.c_int32] +except AttributeError: + pass +try: + nir_imm_ivec3_intN = _libraries['FIXME_STUB'].nir_imm_ivec3_intN + nir_imm_ivec3_intN.restype = ctypes.POINTER(struct_nir_def) + nir_imm_ivec3_intN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_uvec2_intN = _libraries['FIXME_STUB'].nir_imm_uvec2_intN + nir_imm_uvec2_intN.restype = ctypes.POINTER(struct_nir_def) + nir_imm_uvec2_intN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_uvec3_intN = _libraries['FIXME_STUB'].nir_imm_uvec3_intN + nir_imm_uvec3_intN.restype = ctypes.POINTER(struct_nir_def) + nir_imm_uvec3_intN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_ivec3 = _libraries['FIXME_STUB'].nir_imm_ivec3 + nir_imm_ivec3.restype = ctypes.POINTER(struct_nir_def) + nir_imm_ivec3.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_int32, ctypes.c_int32, ctypes.c_int32] +except AttributeError: + pass +try: + nir_imm_ivec4_intN = _libraries['FIXME_STUB'].nir_imm_ivec4_intN + nir_imm_ivec4_intN.restype = ctypes.POINTER(struct_nir_def) + nir_imm_ivec4_intN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_imm_ivec4 = _libraries['FIXME_STUB'].nir_imm_ivec4 + nir_imm_ivec4.restype = ctypes.POINTER(struct_nir_def) + nir_imm_ivec4.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_int32] +except AttributeError: + pass +try: + nir_builder_alu_instr_finish_and_insert = _libraries['libtinymesa_cpu.so'].nir_builder_alu_instr_finish_and_insert + nir_builder_alu_instr_finish_and_insert.restype = ctypes.POINTER(struct_nir_def) + nir_builder_alu_instr_finish_and_insert.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_alu_instr)] +except AttributeError: + pass +try: + nir_load_system_value = _libraries['libtinymesa_cpu.so'].nir_load_system_value + nir_load_system_value.restype = ctypes.POINTER(struct_nir_def) + nir_load_system_value.argtypes = [ctypes.POINTER(struct_nir_builder), nir_intrinsic_op, ctypes.c_int32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_type_convert = _libraries['libtinymesa_cpu.so'].nir_type_convert + nir_type_convert.restype = ctypes.POINTER(struct_nir_def) + nir_type_convert.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_alu_type, nir_alu_type, nir_rounding_mode] +except AttributeError: + pass +try: + nir_convert_to_bit_size = _libraries['FIXME_STUB'].nir_convert_to_bit_size + nir_convert_to_bit_size.restype = ctypes.POINTER(struct_nir_def) + nir_convert_to_bit_size.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_alu_type, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_i2iN = _libraries['FIXME_STUB'].nir_i2iN + nir_i2iN.restype = ctypes.POINTER(struct_nir_def) + nir_i2iN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_u2uN = _libraries['FIXME_STUB'].nir_u2uN + nir_u2uN.restype = ctypes.POINTER(struct_nir_def) + nir_u2uN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_b2bN = _libraries['FIXME_STUB'].nir_b2bN + nir_b2bN.restype = ctypes.POINTER(struct_nir_def) + nir_b2bN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_f2fN = _libraries['FIXME_STUB'].nir_f2fN + nir_f2fN.restype = ctypes.POINTER(struct_nir_def) + nir_f2fN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_i2b = _libraries['FIXME_STUB'].nir_i2b + nir_i2b.restype = ctypes.POINTER(struct_nir_def) + nir_i2b.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_b2iN = _libraries['FIXME_STUB'].nir_b2iN + nir_b2iN.restype = ctypes.POINTER(struct_nir_def) + nir_b2iN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t] +except AttributeError: + pass +try: + nir_b2fN = _libraries['FIXME_STUB'].nir_b2fN + nir_b2fN.restype = ctypes.POINTER(struct_nir_def) + nir_b2fN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t] +except AttributeError: + pass +try: + nir_i2fN = _libraries['FIXME_STUB'].nir_i2fN + nir_i2fN.restype = ctypes.POINTER(struct_nir_def) + nir_i2fN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_u2fN = _libraries['FIXME_STUB'].nir_u2fN + nir_u2fN.restype = ctypes.POINTER(struct_nir_def) + nir_u2fN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_f2uN = _libraries['FIXME_STUB'].nir_f2uN + nir_f2uN.restype = ctypes.POINTER(struct_nir_def) + nir_f2uN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_f2iN = _libraries['FIXME_STUB'].nir_f2iN + nir_f2iN.restype = ctypes.POINTER(struct_nir_def) + nir_f2iN.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_vec = _libraries['FIXME_STUB'].nir_vec + nir_vec.restype = ctypes.POINTER(struct_nir_def) + nir_vec.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(ctypes.POINTER(struct_nir_def)), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_vec_scalars = _libraries['libtinymesa_cpu.so'].nir_vec_scalars + nir_vec_scalars.restype = ctypes.POINTER(struct_nir_def) + nir_vec_scalars.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_scalar), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_mov_alu = _libraries['FIXME_STUB'].nir_mov_alu + nir_mov_alu.restype = ctypes.POINTER(struct_nir_def) + nir_mov_alu.argtypes = [ctypes.POINTER(struct_nir_builder), nir_alu_src, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_swizzle = _libraries['FIXME_STUB'].nir_swizzle + nir_swizzle.restype = ctypes.POINTER(struct_nir_def) + nir_swizzle.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_fdot = _libraries['FIXME_STUB'].nir_fdot + nir_fdot.restype = ctypes.POINTER(struct_nir_def) + nir_fdot.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_bfdot = _libraries['FIXME_STUB'].nir_bfdot + nir_bfdot.restype = ctypes.POINTER(struct_nir_def) + nir_bfdot.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ball_iequal = _libraries['FIXME_STUB'].nir_ball_iequal + nir_ball_iequal.restype = ctypes.POINTER(struct_nir_def) + nir_ball_iequal.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ball = _libraries['FIXME_STUB'].nir_ball + nir_ball.restype = ctypes.POINTER(struct_nir_def) + nir_ball.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_bany_inequal = _libraries['FIXME_STUB'].nir_bany_inequal + nir_bany_inequal.restype = ctypes.POINTER(struct_nir_def) + nir_bany_inequal.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_bany = _libraries['FIXME_STUB'].nir_bany + nir_bany.restype = ctypes.POINTER(struct_nir_def) + nir_bany.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_channel = _libraries['FIXME_STUB'].nir_channel + nir_channel.restype = ctypes.POINTER(struct_nir_def) + nir_channel.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_channel_or_undef = _libraries['FIXME_STUB'].nir_channel_or_undef + nir_channel_or_undef.restype = ctypes.POINTER(struct_nir_def) + nir_channel_or_undef.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_int32] +except AttributeError: + pass +try: + nir_channels = _libraries['FIXME_STUB'].nir_channels + nir_channels.restype = ctypes.POINTER(struct_nir_def) + nir_channels.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_component_mask_t] +except AttributeError: + pass +try: + _nir_select_from_array_helper = _libraries['FIXME_STUB']._nir_select_from_array_helper + _nir_select_from_array_helper.restype = ctypes.POINTER(struct_nir_def) + _nir_select_from_array_helper.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(ctypes.POINTER(struct_nir_def)), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_select_from_ssa_def_array = _libraries['FIXME_STUB'].nir_select_from_ssa_def_array + nir_select_from_ssa_def_array.restype = ctypes.POINTER(struct_nir_def) + nir_select_from_ssa_def_array.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(ctypes.POINTER(struct_nir_def)), ctypes.c_uint32, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_vector_extract = _libraries['FIXME_STUB'].nir_vector_extract + nir_vector_extract.restype = ctypes.POINTER(struct_nir_def) + nir_vector_extract.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_vector_insert_imm = _libraries['FIXME_STUB'].nir_vector_insert_imm + nir_vector_insert_imm.restype = ctypes.POINTER(struct_nir_def) + nir_vector_insert_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_vector_insert = _libraries['FIXME_STUB'].nir_vector_insert + nir_vector_insert.restype = ctypes.POINTER(struct_nir_def) + nir_vector_insert.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_replicate = _libraries['FIXME_STUB'].nir_replicate + nir_replicate.restype = ctypes.POINTER(struct_nir_def) + nir_replicate.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_iadd_imm = _libraries['FIXME_STUB'].nir_iadd_imm + nir_iadd_imm.restype = ctypes.POINTER(struct_nir_def) + nir_iadd_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_iadd_imm_nuw = _libraries['FIXME_STUB'].nir_iadd_imm_nuw + nir_iadd_imm_nuw.restype = ctypes.POINTER(struct_nir_def) + nir_iadd_imm_nuw.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_iadd_nuw = _libraries['FIXME_STUB'].nir_iadd_nuw + nir_iadd_nuw.restype = ctypes.POINTER(struct_nir_def) + nir_iadd_nuw.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_fgt_imm = _libraries['FIXME_STUB'].nir_fgt_imm + nir_fgt_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fgt_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_fle_imm = _libraries['FIXME_STUB'].nir_fle_imm + nir_fle_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fle_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_isub_imm = _libraries['FIXME_STUB'].nir_isub_imm + nir_isub_imm.restype = ctypes.POINTER(struct_nir_def) + nir_isub_imm.argtypes = [ctypes.POINTER(struct_nir_builder), uint64_t, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_imax_imm = _libraries['FIXME_STUB'].nir_imax_imm + nir_imax_imm.restype = ctypes.POINTER(struct_nir_def) + nir_imax_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), int64_t] +except AttributeError: + pass +try: + nir_imin_imm = _libraries['FIXME_STUB'].nir_imin_imm + nir_imin_imm.restype = ctypes.POINTER(struct_nir_def) + nir_imin_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), int64_t] +except AttributeError: + pass +try: + nir_umax_imm = _libraries['FIXME_STUB'].nir_umax_imm + nir_umax_imm.restype = ctypes.POINTER(struct_nir_def) + nir_umax_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_umin_imm = _libraries['FIXME_STUB'].nir_umin_imm + nir_umin_imm.restype = ctypes.POINTER(struct_nir_def) + nir_umin_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + _nir_mul_imm = _libraries['FIXME_STUB']._nir_mul_imm + _nir_mul_imm.restype = ctypes.POINTER(struct_nir_def) + _nir_mul_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t, ctypes.c_bool] +except AttributeError: + pass +try: + nir_imul_imm = _libraries['FIXME_STUB'].nir_imul_imm + nir_imul_imm.restype = ctypes.POINTER(struct_nir_def) + nir_imul_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_amul_imm = _libraries['FIXME_STUB'].nir_amul_imm + nir_amul_imm.restype = ctypes.POINTER(struct_nir_def) + nir_amul_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_fadd_imm = _libraries['FIXME_STUB'].nir_fadd_imm + nir_fadd_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fadd_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_fsub_imm = _libraries['FIXME_STUB'].nir_fsub_imm + nir_fsub_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fsub_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_double, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_fmul_imm = _libraries['FIXME_STUB'].nir_fmul_imm + nir_fmul_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fmul_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_fdiv_imm = _libraries['FIXME_STUB'].nir_fdiv_imm + nir_fdiv_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fdiv_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_fpow_imm = _libraries['FIXME_STUB'].nir_fpow_imm + nir_fpow_imm.restype = ctypes.POINTER(struct_nir_def) + nir_fpow_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_iand_imm = _libraries['FIXME_STUB'].nir_iand_imm + nir_iand_imm.restype = ctypes.POINTER(struct_nir_def) + nir_iand_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_test_mask = _libraries['FIXME_STUB'].nir_test_mask + nir_test_mask.restype = ctypes.POINTER(struct_nir_def) + nir_test_mask.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_ior_imm = _libraries['FIXME_STUB'].nir_ior_imm + nir_ior_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ior_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_ishl_imm = _libraries['FIXME_STUB'].nir_ishl_imm + nir_ishl_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ishl_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t] +except AttributeError: + pass +try: + nir_ishr_imm = _libraries['FIXME_STUB'].nir_ishr_imm + nir_ishr_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ishr_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t] +except AttributeError: + pass +try: + nir_ushr_imm = _libraries['FIXME_STUB'].nir_ushr_imm + nir_ushr_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ushr_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t] +except AttributeError: + pass +try: + nir_imod_imm = _libraries['FIXME_STUB'].nir_imod_imm + nir_imod_imm.restype = ctypes.POINTER(struct_nir_def) + nir_imod_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_udiv_imm = _libraries['FIXME_STUB'].nir_udiv_imm + nir_udiv_imm.restype = ctypes.POINTER(struct_nir_def) + nir_udiv_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_umod_imm = _libraries['FIXME_STUB'].nir_umod_imm + nir_umod_imm.restype = ctypes.POINTER(struct_nir_def) + nir_umod_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_align_imm = _libraries['FIXME_STUB'].nir_align_imm + nir_align_imm.restype = ctypes.POINTER(struct_nir_def) + nir_align_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t] +except AttributeError: + pass +try: + nir_ibfe_imm = _libraries['FIXME_STUB'].nir_ibfe_imm + nir_ibfe_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ibfe_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_ubfe_imm = _libraries['FIXME_STUB'].nir_ubfe_imm + nir_ubfe_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ubfe_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_ubitfield_extract_imm = _libraries['FIXME_STUB'].nir_ubitfield_extract_imm + nir_ubitfield_extract_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ubitfield_extract_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_ibitfield_extract_imm = _libraries['FIXME_STUB'].nir_ibitfield_extract_imm + nir_ibitfield_extract_imm.restype = ctypes.POINTER(struct_nir_def) + nir_ibitfield_extract_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_bitfield_insert_imm = _libraries['FIXME_STUB'].nir_bitfield_insert_imm + nir_bitfield_insert_imm.restype = ctypes.POINTER(struct_nir_def) + nir_bitfield_insert_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_extract_u8_imm = _libraries['FIXME_STUB'].nir_extract_u8_imm + nir_extract_u8_imm.restype = ctypes.POINTER(struct_nir_def) + nir_extract_u8_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_extract_i8_imm = _libraries['FIXME_STUB'].nir_extract_i8_imm + nir_extract_i8_imm.restype = ctypes.POINTER(struct_nir_def) + nir_extract_i8_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_fclamp = _libraries['FIXME_STUB'].nir_fclamp + nir_fclamp.restype = ctypes.POINTER(struct_nir_def) + nir_fclamp.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_iclamp = _libraries['FIXME_STUB'].nir_iclamp + nir_iclamp.restype = ctypes.POINTER(struct_nir_def) + nir_iclamp.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_uclamp = _libraries['FIXME_STUB'].nir_uclamp + nir_uclamp.restype = ctypes.POINTER(struct_nir_def) + nir_uclamp.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ffma_imm12 = _libraries['FIXME_STUB'].nir_ffma_imm12 + nir_ffma_imm12.restype = ctypes.POINTER(struct_nir_def) + nir_ffma_imm12.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double, ctypes.c_double] +except AttributeError: + pass +try: + nir_ffma_imm1 = _libraries['FIXME_STUB'].nir_ffma_imm1 + nir_ffma_imm1.restype = ctypes.POINTER(struct_nir_def) + nir_ffma_imm1.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_double, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ffma_imm2 = _libraries['FIXME_STUB'].nir_ffma_imm2 + nir_ffma_imm2.restype = ctypes.POINTER(struct_nir_def) + nir_ffma_imm2.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.c_double] +except AttributeError: + pass +try: + nir_a_minus_bc = _libraries['FIXME_STUB'].nir_a_minus_bc + nir_a_minus_bc.restype = ctypes.POINTER(struct_nir_def) + nir_a_minus_bc.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_pack_bits = _libraries['FIXME_STUB'].nir_pack_bits + nir_pack_bits.restype = ctypes.POINTER(struct_nir_def) + nir_pack_bits.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_unpack_bits = _libraries['FIXME_STUB'].nir_unpack_bits + nir_unpack_bits.restype = ctypes.POINTER(struct_nir_def) + nir_unpack_bits.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_extract_bits = _libraries['FIXME_STUB'].nir_extract_bits + nir_extract_bits.restype = ctypes.POINTER(struct_nir_def) + nir_extract_bits.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(ctypes.POINTER(struct_nir_def)), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_bitcast_vector = _libraries['FIXME_STUB'].nir_bitcast_vector + nir_bitcast_vector.restype = ctypes.POINTER(struct_nir_def) + nir_bitcast_vector.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_trim_vector = _libraries['FIXME_STUB'].nir_trim_vector + nir_trim_vector.restype = ctypes.POINTER(struct_nir_def) + nir_trim_vector.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_pad_vector = _libraries['FIXME_STUB'].nir_pad_vector + nir_pad_vector.restype = ctypes.POINTER(struct_nir_def) + nir_pad_vector.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_pad_vector_imm_int = _libraries['FIXME_STUB'].nir_pad_vector_imm_int + nir_pad_vector_imm_int.restype = ctypes.POINTER(struct_nir_def) + nir_pad_vector_imm_int.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), uint64_t, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_pad_vec4 = _libraries['FIXME_STUB'].nir_pad_vec4 + nir_pad_vec4.restype = ctypes.POINTER(struct_nir_def) + nir_pad_vec4.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_resize_vector = _libraries['FIXME_STUB'].nir_resize_vector + nir_resize_vector.restype = ctypes.POINTER(struct_nir_def) + nir_resize_vector.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_shift_channels = _libraries['FIXME_STUB'].nir_shift_channels + nir_shift_channels.restype = ctypes.POINTER(struct_nir_def) + nir_shift_channels.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_int32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_ssa_for_alu_src = _libraries['libtinymesa_cpu.so'].nir_ssa_for_alu_src + nir_ssa_for_alu_src.restype = ctypes.POINTER(struct_nir_def) + nir_ssa_for_alu_src.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_alu_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_get_ptr_bitsize = _libraries['FIXME_STUB'].nir_get_ptr_bitsize + nir_get_ptr_bitsize.restype = ctypes.c_uint32 + nir_get_ptr_bitsize.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + nir_build_deref_var = _libraries['FIXME_STUB'].nir_build_deref_var + nir_build_deref_var.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_var.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_build_deref_array = _libraries['FIXME_STUB'].nir_build_deref_array + nir_build_deref_array.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_array.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_deref_array_imm = _libraries['FIXME_STUB'].nir_build_deref_array_imm + nir_build_deref_array_imm.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_array_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), int64_t] +except AttributeError: + pass +try: + nir_build_deref_ptr_as_array = _libraries['FIXME_STUB'].nir_build_deref_ptr_as_array + nir_build_deref_ptr_as_array.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_ptr_as_array.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_deref_array_wildcard = _libraries['FIXME_STUB'].nir_build_deref_array_wildcard + nir_build_deref_array_wildcard.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_array_wildcard.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_build_deref_struct = _libraries['FIXME_STUB'].nir_build_deref_struct + nir_build_deref_struct.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_struct.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_build_deref_cast_with_alignment = _libraries['FIXME_STUB'].nir_build_deref_cast_with_alignment + nir_build_deref_cast_with_alignment.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_cast_with_alignment.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_variable_mode, ctypes.POINTER(struct_glsl_type), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_build_deref_cast = _libraries['FIXME_STUB'].nir_build_deref_cast + nir_build_deref_cast.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_cast.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_variable_mode, ctypes.POINTER(struct_glsl_type), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_alignment_deref_cast = _libraries['FIXME_STUB'].nir_alignment_deref_cast + nir_alignment_deref_cast.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_alignment_deref_cast.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), uint32_t, uint32_t] +except AttributeError: + pass +try: + nir_build_deref_follower = _libraries['FIXME_STUB'].nir_build_deref_follower + nir_build_deref_follower.restype = ctypes.POINTER(struct_nir_deref_instr) + nir_build_deref_follower.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_load_deref_with_access = _libraries['FIXME_STUB'].nir_load_deref_with_access + nir_load_deref_with_access.restype = ctypes.POINTER(struct_nir_def) + nir_load_deref_with_access.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), gl_access_qualifier] +except AttributeError: + pass +try: + nir_load_deref = _libraries['FIXME_STUB'].nir_load_deref + nir_load_deref.restype = ctypes.POINTER(struct_nir_def) + nir_load_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_store_deref_with_access = _libraries['FIXME_STUB'].nir_store_deref_with_access + nir_store_deref_with_access.restype = None + nir_store_deref_with_access.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, gl_access_qualifier] +except AttributeError: + pass +try: + nir_store_deref = _libraries['FIXME_STUB'].nir_store_deref + nir_store_deref.restype = None + nir_store_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_build_write_masked_store = _libraries['FIXME_STUB'].nir_build_write_masked_store + nir_build_write_masked_store.restype = None + nir_build_write_masked_store.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_build_write_masked_stores = _libraries['FIXME_STUB'].nir_build_write_masked_stores + nir_build_write_masked_stores.restype = None + nir_build_write_masked_stores.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_copy_deref_with_access = _libraries['FIXME_STUB'].nir_copy_deref_with_access + nir_copy_deref_with_access.restype = None + nir_copy_deref_with_access.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), gl_access_qualifier, gl_access_qualifier] +except AttributeError: + pass +try: + nir_copy_deref = _libraries['FIXME_STUB'].nir_copy_deref + nir_copy_deref.restype = None + nir_copy_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr)] +except AttributeError: + pass +try: + nir_memcpy_deref_with_access = _libraries['FIXME_STUB'].nir_memcpy_deref_with_access + nir_memcpy_deref_with_access.restype = None + nir_memcpy_deref_with_access.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), gl_access_qualifier, gl_access_qualifier] +except AttributeError: + pass +try: + nir_memcpy_deref = _libraries['FIXME_STUB'].nir_memcpy_deref + nir_memcpy_deref.restype = None + nir_memcpy_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_load_var = _libraries['FIXME_STUB'].nir_load_var + nir_load_var.restype = ctypes.POINTER(struct_nir_def) + nir_load_var.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_store_var = _libraries['FIXME_STUB'].nir_store_var + nir_store_var.restype = None + nir_store_var.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_copy_var = _libraries['FIXME_STUB'].nir_copy_var + nir_copy_var.restype = None + nir_copy_var.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_variable)] +except AttributeError: + pass +try: + nir_load_array_var = _libraries['FIXME_STUB'].nir_load_array_var + nir_load_array_var.restype = ctypes.POINTER(struct_nir_def) + nir_load_array_var.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_load_array_var_imm = _libraries['FIXME_STUB'].nir_load_array_var_imm + nir_load_array_var_imm.restype = ctypes.POINTER(struct_nir_def) + nir_load_array_var_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), int64_t] +except AttributeError: + pass +try: + nir_store_array_var = _libraries['FIXME_STUB'].nir_store_array_var + nir_store_array_var.restype = None + nir_store_array_var.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_store_array_var_imm = _libraries['FIXME_STUB'].nir_store_array_var_imm + nir_store_array_var_imm.restype = None + nir_store_array_var_imm.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_variable), int64_t, ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_load_global = _libraries['FIXME_STUB'].nir_load_global + nir_load_global.restype = ctypes.POINTER(struct_nir_def) + nir_load_global.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_store_global = _libraries['FIXME_STUB'].nir_store_global + nir_store_global.restype = None + nir_store_global.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, ctypes.POINTER(struct_nir_def), nir_component_mask_t] +except AttributeError: + pass +try: + nir_load_global_constant = _libraries['FIXME_STUB'].nir_load_global_constant + nir_load_global_constant.restype = ctypes.POINTER(struct_nir_def) + nir_load_global_constant.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_load_param = _libraries['FIXME_STUB'].nir_load_param + nir_load_param.restype = ctypes.POINTER(struct_nir_def) + nir_load_param.argtypes = [ctypes.POINTER(struct_nir_builder), uint32_t] +except AttributeError: + pass +try: + nir_decl_reg = _libraries['FIXME_STUB'].nir_decl_reg + nir_decl_reg.restype = ctypes.POINTER(struct_nir_def) + nir_decl_reg.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_load_reg = _libraries['FIXME_STUB'].nir_load_reg + nir_load_reg.restype = ctypes.POINTER(struct_nir_def) + nir_load_reg.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_store_reg = _libraries['FIXME_STUB'].nir_store_reg + nir_store_reg.restype = None + nir_store_reg.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_tex_src_for_ssa = _libraries['FIXME_STUB'].nir_tex_src_for_ssa + nir_tex_src_for_ssa.restype = nir_tex_src + nir_tex_src_for_ssa.argtypes = [nir_tex_src_type, ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_deriv = _libraries['FIXME_STUB'].nir_build_deriv + nir_build_deriv.restype = ctypes.POINTER(struct_nir_def) + nir_build_deriv.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), nir_intrinsic_op] +except AttributeError: + pass +try: + nir_ddx = _libraries['FIXME_STUB'].nir_ddx + nir_ddx.restype = ctypes.POINTER(struct_nir_def) + nir_ddx.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ddx_fine = _libraries['FIXME_STUB'].nir_ddx_fine + nir_ddx_fine.restype = ctypes.POINTER(struct_nir_def) + nir_ddx_fine.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ddx_coarse = _libraries['FIXME_STUB'].nir_ddx_coarse + nir_ddx_coarse.restype = ctypes.POINTER(struct_nir_def) + nir_ddx_coarse.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ddy = _libraries['FIXME_STUB'].nir_ddy + nir_ddy.restype = ctypes.POINTER(struct_nir_def) + nir_ddy.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ddy_fine = _libraries['FIXME_STUB'].nir_ddy_fine + nir_ddy_fine.restype = ctypes.POINTER(struct_nir_def) + nir_ddy_fine.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_ddy_coarse = _libraries['FIXME_STUB'].nir_ddy_coarse + nir_ddy_coarse.restype = ctypes.POINTER(struct_nir_def) + nir_ddy_coarse.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_tex_deref = _libraries['FIXME_STUB'].nir_tex_deref + nir_tex_deref.restype = ctypes.POINTER(struct_nir_def) + nir_tex_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_txl_deref = _libraries['FIXME_STUB'].nir_txl_deref + nir_txl_deref.restype = ctypes.POINTER(struct_nir_def) + nir_txl_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_txl_zero_deref = _libraries['FIXME_STUB'].nir_txl_zero_deref + nir_txl_zero_deref.restype = ctypes.POINTER(struct_nir_def) + nir_txl_zero_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_tex_type_has_lod = _libraries['FIXME_STUB'].nir_tex_type_has_lod + nir_tex_type_has_lod.restype = ctypes.c_bool + nir_tex_type_has_lod.argtypes = [ctypes.POINTER(struct_glsl_type)] +except AttributeError: + pass +try: + nir_txf_deref = _libraries['FIXME_STUB'].nir_txf_deref + nir_txf_deref.restype = ctypes.POINTER(struct_nir_def) + nir_txf_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_txf_ms_deref = _libraries['FIXME_STUB'].nir_txf_ms_deref + nir_txf_ms_deref.restype = ctypes.POINTER(struct_nir_def) + nir_txf_ms_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_txs_deref = _libraries['FIXME_STUB'].nir_txs_deref + nir_txs_deref.restype = ctypes.POINTER(struct_nir_def) + nir_txs_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_samples_identical_deref = _libraries['FIXME_STUB'].nir_samples_identical_deref + nir_samples_identical_deref.restype = ctypes.POINTER(struct_nir_def) + nir_samples_identical_deref.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_deref_instr), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_mask = _libraries['FIXME_STUB'].nir_mask + nir_mask.restype = ctypes.POINTER(struct_nir_def) + nir_mask.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.c_uint32] +except AttributeError: + pass +try: + nir_load_barycentric = _libraries['FIXME_STUB'].nir_load_barycentric + nir_load_barycentric.restype = ctypes.POINTER(struct_nir_def) + nir_load_barycentric.argtypes = [ctypes.POINTER(struct_nir_builder), nir_intrinsic_op, ctypes.c_uint32] +except AttributeError: + pass +try: + nir_jump = _libraries['FIXME_STUB'].nir_jump + nir_jump.restype = None + nir_jump.argtypes = [ctypes.POINTER(struct_nir_builder), nir_jump_type] +except AttributeError: + pass +try: + nir_goto = _libraries['FIXME_STUB'].nir_goto + nir_goto.restype = None + nir_goto.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_goto_if = _libraries['FIXME_STUB'].nir_goto_if + nir_goto_if.restype = None + nir_goto_if.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_block), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_block)] +except AttributeError: + pass +try: + nir_break_if = _libraries['FIXME_STUB'].nir_break_if + nir_break_if.restype = None + nir_break_if.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_call = _libraries['FIXME_STUB'].nir_build_call + nir_build_call.restype = None + nir_build_call.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_function), size_t, ctypes.POINTER(ctypes.POINTER(struct_nir_def))] +except AttributeError: + pass +try: + nir_build_indirect_call = _libraries['FIXME_STUB'].nir_build_indirect_call + nir_build_indirect_call.restype = None + nir_build_indirect_call.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_function), ctypes.POINTER(struct_nir_def), size_t, ctypes.POINTER(ctypes.POINTER(struct_nir_def))] +except AttributeError: + pass +try: + nir_discard = _libraries['FIXME_STUB'].nir_discard + nir_discard.restype = None + nir_discard.argtypes = [ctypes.POINTER(struct_nir_builder)] +except AttributeError: + pass +try: + nir_discard_if = _libraries['FIXME_STUB'].nir_discard_if + nir_discard_if.restype = None + nir_discard_if.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_build_string = _libraries['FIXME_STUB'].nir_build_string + nir_build_string.restype = ctypes.POINTER(struct_nir_def) + nir_build_string.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_compare_func = _libraries['libtinymesa_cpu.so'].nir_compare_func + nir_compare_func.restype = ctypes.POINTER(struct_nir_def) + nir_compare_func.argtypes = [ctypes.POINTER(struct_nir_builder), compare_func, ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_scoped_memory_barrier = _libraries['FIXME_STUB'].nir_scoped_memory_barrier + nir_scoped_memory_barrier.restype = None + nir_scoped_memory_barrier.argtypes = [ctypes.POINTER(struct_nir_builder), mesa_scope, nir_memory_semantics, nir_variable_mode] +except AttributeError: + pass +try: + nir_gen_rect_vertices = _libraries['libtinymesa_cpu.so'].nir_gen_rect_vertices + nir_gen_rect_vertices.restype = ctypes.POINTER(struct_nir_def) + nir_gen_rect_vertices.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(struct_nir_def), ctypes.POINTER(struct_nir_def)] +except AttributeError: + pass +try: + nir_printf_fmt = _libraries['libtinymesa_cpu.so'].nir_printf_fmt + nir_printf_fmt.restype = None + nir_printf_fmt.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_printf_fmt_at_px = _libraries['libtinymesa_cpu.so'].nir_printf_fmt_at_px + nir_printf_fmt_at_px.restype = None + nir_printf_fmt_at_px.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + nir_call_serialized = _libraries['libtinymesa_cpu.so'].nir_call_serialized + nir_call_serialized.restype = ctypes.POINTER(struct_nir_def) + nir_call_serialized.argtypes = [ctypes.POINTER(struct_nir_builder), ctypes.POINTER(ctypes.c_uint32), size_t, ctypes.POINTER(ctypes.POINTER(struct_nir_def))] +except AttributeError: + pass +try: + nir_serialize = _libraries['libtinymesa_cpu.so'].nir_serialize + nir_serialize.restype = None + nir_serialize.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(struct_nir_shader), ctypes.c_bool] +except AttributeError: + pass +try: + nir_deserialize = _libraries['libtinymesa_cpu.so'].nir_deserialize + nir_deserialize.restype = ctypes.POINTER(struct_nir_shader) + nir_deserialize.argtypes = [ctypes.POINTER(None), ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass +try: + nir_serialize_function = _libraries['libtinymesa_cpu.so'].nir_serialize_function + nir_serialize_function.restype = None + nir_serialize_function.argtypes = [ctypes.POINTER(struct_blob), ctypes.POINTER(struct_nir_function)] +except AttributeError: + pass +try: + nir_deserialize_function = _libraries['libtinymesa_cpu.so'].nir_deserialize_function + nir_deserialize_function.restype = ctypes.POINTER(struct_nir_function) + nir_deserialize_function.argtypes = [ctypes.POINTER(None), ctypes.POINTER(struct_nir_shader_compiler_options), ctypes.POINTER(struct_blob_reader)] +except AttributeError: + pass + +# values for enumeration 'nv_device_type' +nv_device_type__enumvalues = { + 0: 'NV_DEVICE_TYPE_IGP', + 1: 'NV_DEVICE_TYPE_DIS', + 2: 'NV_DEVICE_TYPE_SOC', +} +NV_DEVICE_TYPE_IGP = 0 +NV_DEVICE_TYPE_DIS = 1 +NV_DEVICE_TYPE_SOC = 2 +nv_device_type = ctypes.c_uint32 # enum +class struct_nv_device_info(Structure): + pass + +class struct_nv_device_info_pci(Structure): + pass + +struct_nv_device_info_pci._pack_ = 1 # source:False +struct_nv_device_info_pci._fields_ = [ + ('domain', ctypes.c_uint16), + ('bus', ctypes.c_ubyte), + ('dev', ctypes.c_ubyte), + ('func', ctypes.c_ubyte), + ('revision_id', ctypes.c_ubyte), +] + +struct_nv_device_info._pack_ = 1 # source:False +struct_nv_device_info._fields_ = [ + ('type', ctypes.c_ubyte), + ('PADDING_0', ctypes.c_ubyte), + ('device_id', ctypes.c_uint16), + ('chipset', ctypes.c_uint16), + ('device_name', ctypes.c_char * 64), + ('chipset_name', ctypes.c_char * 16), + ('pci', struct_nv_device_info_pci), + ('sm', ctypes.c_ubyte), + ('gpc_count', ctypes.c_ubyte), + ('tpc_count', ctypes.c_uint16), + ('mp_per_tpc', ctypes.c_ubyte), + ('max_warps_per_mp', ctypes.c_ubyte), + ('cls_copy', ctypes.c_uint16), + ('cls_eng2d', ctypes.c_uint16), + ('cls_eng3d', ctypes.c_uint16), + ('cls_m2mf', ctypes.c_uint16), + ('cls_compute', ctypes.c_uint16), + ('PADDING_1', ctypes.c_ubyte * 4), + ('vram_size_B', ctypes.c_uint64), + ('bar_size_B', ctypes.c_uint64), +] + +try: + nv_device_uuid = _libraries['FIXME_STUB'].nv_device_uuid + nv_device_uuid.restype = None + nv_device_uuid.argtypes = [ctypes.POINTER(struct_nv_device_info), ctypes.POINTER(ctypes.c_ubyte), size_t, ctypes.c_bool] +except AttributeError: + pass +class struct_nak_compiler(Structure): + pass + +try: + nak_compiler_create = _libraries['libtinymesa_cpu.so'].nak_compiler_create + nak_compiler_create.restype = ctypes.POINTER(struct_nak_compiler) + nak_compiler_create.argtypes = [ctypes.POINTER(struct_nv_device_info)] +except AttributeError: + pass +try: + nak_compiler_destroy = _libraries['libtinymesa_cpu.so'].nak_compiler_destroy + nak_compiler_destroy.restype = None + nak_compiler_destroy.argtypes = [ctypes.POINTER(struct_nak_compiler)] +except AttributeError: + pass +try: + nak_debug_flags = _libraries['libtinymesa_cpu.so'].nak_debug_flags + nak_debug_flags.restype = uint64_t + nak_debug_flags.argtypes = [ctypes.POINTER(struct_nak_compiler)] +except AttributeError: + pass +try: + nak_nir_options = _libraries['libtinymesa_cpu.so'].nak_nir_options + nak_nir_options.restype = ctypes.POINTER(struct_nir_shader_compiler_options) + nak_nir_options.argtypes = [ctypes.POINTER(struct_nak_compiler)] +except AttributeError: + pass +try: + nak_preprocess_nir = _libraries['libtinymesa_cpu.so'].nak_preprocess_nir + nak_preprocess_nir.restype = None + nak_preprocess_nir.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nak_compiler)] +except AttributeError: + pass +try: + nak_nir_lower_image_addrs = _libraries['FIXME_STUB'].nak_nir_lower_image_addrs + nak_nir_lower_image_addrs.restype = ctypes.c_bool + nak_nir_lower_image_addrs.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nak_compiler)] +except AttributeError: + pass +class struct_nak_sample_location(Structure): + pass + +struct_nak_sample_location._pack_ = 1 # source:False +struct_nak_sample_location._fields_ = [ + ('x_u4', ctypes.c_ubyte, 4), + ('y_u4', ctypes.c_ubyte, 4), +] + +class struct_nak_sample_mask(Structure): + pass + +struct_nak_sample_mask._pack_ = 1 # source:False +struct_nak_sample_mask._fields_ = [ + ('sample_mask', ctypes.c_uint16), +] + +class struct_nak_fs_key(Structure): + pass + +struct_nak_fs_key._pack_ = 1 # source:False +struct_nak_fs_key._fields_ = [ + ('zs_self_dep', ctypes.c_bool), + ('force_sample_shading', ctypes.c_bool), + ('uses_underestimate', ctypes.c_bool), + ('sample_info_cb', ctypes.c_ubyte), + ('sample_locations_offset', ctypes.c_uint32), + ('sample_masks_offset', ctypes.c_uint32), +] + +try: + nak_postprocess_nir = _libraries['libtinymesa_cpu.so'].nak_postprocess_nir + nak_postprocess_nir.restype = None + nak_postprocess_nir.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nak_compiler), nir_variable_mode, ctypes.POINTER(struct_nak_fs_key)] +except AttributeError: + pass + +# values for enumeration 'nak_ts_domain' +nak_ts_domain__enumvalues = { + 0: 'NAK_TS_DOMAIN_ISOLINE', + 1: 'NAK_TS_DOMAIN_TRIANGLE', + 2: 'NAK_TS_DOMAIN_QUAD', +} +NAK_TS_DOMAIN_ISOLINE = 0 +NAK_TS_DOMAIN_TRIANGLE = 1 +NAK_TS_DOMAIN_QUAD = 2 +nak_ts_domain = ctypes.c_uint32 # enum + +# values for enumeration 'nak_ts_spacing' +nak_ts_spacing__enumvalues = { + 0: 'NAK_TS_SPACING_INTEGER', + 1: 'NAK_TS_SPACING_FRACT_ODD', + 2: 'NAK_TS_SPACING_FRACT_EVEN', +} +NAK_TS_SPACING_INTEGER = 0 +NAK_TS_SPACING_FRACT_ODD = 1 +NAK_TS_SPACING_FRACT_EVEN = 2 +nak_ts_spacing = ctypes.c_uint32 # enum + +# values for enumeration 'nak_ts_prims' +nak_ts_prims__enumvalues = { + 0: 'NAK_TS_PRIMS_POINTS', + 1: 'NAK_TS_PRIMS_LINES', + 2: 'NAK_TS_PRIMS_TRIANGLES_CW', + 3: 'NAK_TS_PRIMS_TRIANGLES_CCW', +} +NAK_TS_PRIMS_POINTS = 0 +NAK_TS_PRIMS_LINES = 1 +NAK_TS_PRIMS_TRIANGLES_CW = 2 +NAK_TS_PRIMS_TRIANGLES_CCW = 3 +nak_ts_prims = ctypes.c_uint32 # enum +class struct_nak_xfb_info(Structure): + pass + +struct_nak_xfb_info._pack_ = 1 # source:False +struct_nak_xfb_info._fields_ = [ + ('stride', ctypes.c_uint32 * 4), + ('stream', ctypes.c_ubyte * 4), + ('attr_count', ctypes.c_ubyte * 4), + ('attr_index', ctypes.c_ubyte * 128 * 4), +] + +class struct_nak_shader_info(Structure): + pass + +class union_nak_shader_info_0(Union): + pass + +class struct_nak_shader_info_0_cs(Structure): + pass + +struct_nak_shader_info_0_cs._pack_ = 1 # source:False +struct_nak_shader_info_0_cs._fields_ = [ + ('local_size', ctypes.c_uint16 * 3), + ('smem_size', ctypes.c_uint16), + ('_pad', ctypes.c_ubyte * 4), +] + +class struct_nak_shader_info_0_fs(Structure): + pass + +struct_nak_shader_info_0_fs._pack_ = 1 # source:False +struct_nak_shader_info_0_fs._fields_ = [ + ('writes_depth', ctypes.c_bool), + ('reads_sample_mask', ctypes.c_bool), + ('post_depth_coverage', ctypes.c_bool), + ('uses_sample_shading', ctypes.c_bool), + ('early_fragment_tests', ctypes.c_bool), + ('_pad', ctypes.c_ubyte * 7), +] + +class struct_nak_shader_info_0_ts(Structure): + pass + +struct_nak_shader_info_0_ts._pack_ = 1 # source:False +struct_nak_shader_info_0_ts._fields_ = [ + ('domain', ctypes.c_ubyte), + ('spacing', ctypes.c_ubyte), + ('prims', ctypes.c_ubyte), + ('_pad', ctypes.c_ubyte * 9), +] + +union_nak_shader_info_0._pack_ = 1 # source:False +union_nak_shader_info_0._fields_ = [ + ('cs', struct_nak_shader_info_0_cs), + ('fs', struct_nak_shader_info_0_fs), + ('ts', struct_nak_shader_info_0_ts), + ('_pad', ctypes.c_ubyte * 12), +] + +class struct_nak_shader_info_vtg(Structure): + pass + +struct_nak_shader_info_vtg._pack_ = 1 # source:False +struct_nak_shader_info_vtg._fields_ = [ + ('writes_layer', ctypes.c_bool), + ('writes_point_size', ctypes.c_bool), + ('writes_vprs_table_index', ctypes.c_bool), + ('clip_enable', ctypes.c_ubyte), + ('cull_enable', ctypes.c_ubyte), + ('_pad', ctypes.c_ubyte * 3), + ('xfb', struct_nak_xfb_info), +] + +struct_nak_shader_info._pack_ = 1 # source:False +struct_nak_shader_info._anonymous_ = ('_0',) +struct_nak_shader_info._fields_ = [ + ('stage', gl_shader_stage), + ('sm', ctypes.c_ubyte), + ('num_gprs', ctypes.c_ubyte), + ('num_control_barriers', ctypes.c_ubyte), + ('_pad0', ctypes.c_ubyte), + ('max_warps_per_sm', ctypes.c_uint32), + ('num_instrs', ctypes.c_uint32), + ('num_static_cycles', ctypes.c_uint32), + ('num_spills_to_mem', ctypes.c_uint32), + ('num_fills_from_mem', ctypes.c_uint32), + ('num_spills_to_reg', ctypes.c_uint32), + ('num_fills_from_reg', ctypes.c_uint32), + ('slm_size', ctypes.c_uint32), + ('crs_size', ctypes.c_uint32), + ('_0', union_nak_shader_info_0), + ('vtg', struct_nak_shader_info_vtg), + ('hdr', ctypes.c_uint32 * 32), +] + +class struct_nak_shader_bin(Structure): + pass + +struct_nak_shader_bin._pack_ = 1 # source:False +struct_nak_shader_bin._fields_ = [ + ('info', struct_nak_shader_info), + ('code_size', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('code', ctypes.POINTER(None)), + ('asm_str', ctypes.POINTER(ctypes.c_char)), +] + +try: + nak_shader_bin_destroy = _libraries['libtinymesa_cpu.so'].nak_shader_bin_destroy + nak_shader_bin_destroy.restype = None + nak_shader_bin_destroy.argtypes = [ctypes.POINTER(struct_nak_shader_bin)] +except AttributeError: + pass +try: + nak_compile_shader = _libraries['libtinymesa_cpu.so'].nak_compile_shader + nak_compile_shader.restype = ctypes.POINTER(struct_nak_shader_bin) + nak_compile_shader.argtypes = [ctypes.POINTER(struct_nir_shader), ctypes.c_bool, ctypes.POINTER(struct_nak_compiler), nir_variable_mode, ctypes.POINTER(struct_nak_fs_key)] +except AttributeError: + pass +class struct_nak_qmd_cbuf(Structure): + pass + +struct_nak_qmd_cbuf._pack_ = 1 # source:False +struct_nak_qmd_cbuf._fields_ = [ + ('index', ctypes.c_uint32), + ('size', ctypes.c_uint32), + ('addr', ctypes.c_uint64), +] + +class struct_nak_qmd_info(Structure): + pass + +struct_nak_qmd_info._pack_ = 1 # source:False +struct_nak_qmd_info._fields_ = [ + ('addr', ctypes.c_uint64), + ('smem_size', ctypes.c_uint16), + ('smem_max', ctypes.c_uint16), + ('global_size', ctypes.c_uint32 * 3), + ('num_cbufs', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('cbufs', struct_nak_qmd_cbuf * 8), +] + +try: + nak_qmd_size_B = _libraries['libtinymesa_cpu.so'].nak_qmd_size_B + nak_qmd_size_B.restype = uint32_t + nak_qmd_size_B.argtypes = [ctypes.POINTER(struct_nv_device_info)] +except AttributeError: + pass +try: + nak_fill_qmd = _libraries['libtinymesa_cpu.so'].nak_fill_qmd + nak_fill_qmd.restype = None + nak_fill_qmd.argtypes = [ctypes.POINTER(struct_nv_device_info), ctypes.POINTER(struct_nak_shader_info), ctypes.POINTER(struct_nak_qmd_info), ctypes.POINTER(None), size_t] +except AttributeError: + pass +class struct_nak_qmd_dispatch_size_layout(Structure): + pass + +struct_nak_qmd_dispatch_size_layout._pack_ = 1 # source:False +struct_nak_qmd_dispatch_size_layout._fields_ = [ + ('x_start', ctypes.c_uint16), + ('x_end', ctypes.c_uint16), + ('y_start', ctypes.c_uint16), + ('y_end', ctypes.c_uint16), + ('z_start', ctypes.c_uint16), + ('z_end', ctypes.c_uint16), +] + +try: + nak_get_qmd_dispatch_size_layout = _libraries['libtinymesa_cpu.so'].nak_get_qmd_dispatch_size_layout + nak_get_qmd_dispatch_size_layout.restype = struct_nak_qmd_dispatch_size_layout + nak_get_qmd_dispatch_size_layout.argtypes = [ctypes.POINTER(struct_nv_device_info)] +except AttributeError: + pass +class struct_nak_qmd_cbuf_desc_layout(Structure): + pass + +struct_nak_qmd_cbuf_desc_layout._pack_ = 1 # source:False +struct_nak_qmd_cbuf_desc_layout._fields_ = [ + ('addr_shift', ctypes.c_uint16), + ('addr_lo_start', ctypes.c_uint16), + ('addr_lo_end', ctypes.c_uint16), + ('addr_hi_start', ctypes.c_uint16), + ('addr_hi_end', ctypes.c_uint16), +] + +try: + nak_get_qmd_cbuf_desc_layout = _libraries['libtinymesa_cpu.so'].nak_get_qmd_cbuf_desc_layout + nak_get_qmd_cbuf_desc_layout.restype = struct_nak_qmd_cbuf_desc_layout + nak_get_qmd_cbuf_desc_layout.argtypes = [ctypes.POINTER(struct_nv_device_info), uint8_t] +except AttributeError: + pass +class struct_lp_context_ref(Structure): + pass + +class struct_LLVMOpaqueContext(Structure): + pass + +struct_lp_context_ref._pack_ = 1 # source:False +struct_lp_context_ref._fields_ = [ + ('ref', ctypes.POINTER(struct_LLVMOpaqueContext)), + ('owned', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), +] + +lp_context_ref = struct_lp_context_ref +try: + lp_context_create = _libraries['FIXME_STUB'].lp_context_create + lp_context_create.restype = None + lp_context_create.argtypes = [ctypes.POINTER(struct_lp_context_ref)] +except AttributeError: + pass +try: + lp_context_destroy = _libraries['FIXME_STUB'].lp_context_destroy + lp_context_destroy.restype = None + lp_context_destroy.argtypes = [ctypes.POINTER(struct_lp_context_ref)] +except AttributeError: + pass +class struct_lp_passmgr(Structure): + pass + +class struct_LLVMOpaqueModule(Structure): + pass + +LLVMModuleRef = ctypes.POINTER(struct_LLVMOpaqueModule) +try: + lp_passmgr_create = _libraries['libtinymesa_cpu.so'].lp_passmgr_create + lp_passmgr_create.restype = ctypes.c_bool + lp_passmgr_create.argtypes = [LLVMModuleRef, ctypes.POINTER(ctypes.POINTER(struct_lp_passmgr))] +except AttributeError: + pass +class struct_LLVMOpaqueTargetMachine(Structure): + pass + +LLVMTargetMachineRef = ctypes.POINTER(struct_LLVMOpaqueTargetMachine) +try: + lp_passmgr_run = _libraries['libtinymesa_cpu.so'].lp_passmgr_run + lp_passmgr_run.restype = None + lp_passmgr_run.argtypes = [ctypes.POINTER(struct_lp_passmgr), LLVMModuleRef, LLVMTargetMachineRef, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_passmgr_dispose = _libraries['libtinymesa_cpu.so'].lp_passmgr_dispose + lp_passmgr_dispose.restype = None + lp_passmgr_dispose.argtypes = [ctypes.POINTER(struct_lp_passmgr)] +except AttributeError: + pass +class struct_lp_cached_code(Structure): + pass + +struct_lp_cached_code._pack_ = 1 # source:False +struct_lp_cached_code._fields_ = [ + ('data', ctypes.POINTER(None)), + ('data_size', ctypes.c_uint64), + ('dont_cache', ctypes.c_bool), + ('PADDING_0', ctypes.c_ubyte * 7), + ('jit_obj_cache', ctypes.POINTER(None)), +] + +class struct_lp_generated_code(Structure): + pass + +class struct_LLVMOpaqueTargetLibraryInfotData(Structure): + pass + +LLVMTargetLibraryInfoRef = ctypes.POINTER(struct_LLVMOpaqueTargetLibraryInfotData) +try: + gallivm_create_target_library_info = _libraries['libtinymesa_cpu.so'].gallivm_create_target_library_info + gallivm_create_target_library_info.restype = LLVMTargetLibraryInfoRef + gallivm_create_target_library_info.argtypes = [ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + gallivm_dispose_target_library_info = _libraries['libtinymesa_cpu.so'].gallivm_dispose_target_library_info + gallivm_dispose_target_library_info.restype = None + gallivm_dispose_target_library_info.argtypes = [LLVMTargetLibraryInfoRef] +except AttributeError: + pass +try: + lp_set_target_options = _libraries['libtinymesa_cpu.so'].lp_set_target_options + lp_set_target_options.restype = None + lp_set_target_options.argtypes = [] +except AttributeError: + pass +try: + lp_bld_init_native_targets = _libraries['libtinymesa_cpu.so'].lp_bld_init_native_targets + lp_bld_init_native_targets.restype = None + lp_bld_init_native_targets.argtypes = [] +except AttributeError: + pass +class struct_LLVMOpaqueExecutionEngine(Structure): + pass + +class struct_LLVMOpaqueMCJITMemoryManager(Structure): + pass + +LLVMMCJITMemoryManagerRef = ctypes.POINTER(struct_LLVMOpaqueMCJITMemoryManager) +try: + lp_build_create_jit_compiler_for_module = _libraries['libtinymesa_cpu.so'].lp_build_create_jit_compiler_for_module + lp_build_create_jit_compiler_for_module.restype = ctypes.c_int32 + lp_build_create_jit_compiler_for_module.argtypes = [ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueExecutionEngine)), ctypes.POINTER(ctypes.POINTER(struct_lp_generated_code)), ctypes.POINTER(struct_lp_cached_code), LLVMModuleRef, LLVMMCJITMemoryManagerRef, ctypes.c_uint32, ctypes.POINTER(ctypes.POINTER(ctypes.c_char))] +except AttributeError: + pass +try: + lp_free_generated_code = _libraries['libtinymesa_cpu.so'].lp_free_generated_code + lp_free_generated_code.restype = None + lp_free_generated_code.argtypes = [ctypes.POINTER(struct_lp_generated_code)] +except AttributeError: + pass +try: + lp_get_default_memory_manager = _libraries['libtinymesa_cpu.so'].lp_get_default_memory_manager + lp_get_default_memory_manager.restype = LLVMMCJITMemoryManagerRef + lp_get_default_memory_manager.argtypes = [] +except AttributeError: + pass +try: + lp_free_memory_manager = _libraries['libtinymesa_cpu.so'].lp_free_memory_manager + lp_free_memory_manager.restype = None + lp_free_memory_manager.argtypes = [LLVMMCJITMemoryManagerRef] +except AttributeError: + pass +class struct_LLVMOpaqueValue(Structure): + pass + +LLVMValueRef = ctypes.POINTER(struct_LLVMOpaqueValue) +try: + lp_get_called_value = _libraries['libtinymesa_cpu.so'].lp_get_called_value + lp_get_called_value.restype = LLVMValueRef + lp_get_called_value.argtypes = [LLVMValueRef] +except AttributeError: + pass +try: + lp_is_function = _libraries['libtinymesa_cpu.so'].lp_is_function + lp_is_function.restype = ctypes.c_bool + lp_is_function.argtypes = [LLVMValueRef] +except AttributeError: + pass +try: + lp_free_objcache = _libraries['libtinymesa_cpu.so'].lp_free_objcache + lp_free_objcache.restype = None + lp_free_objcache.argtypes = [ctypes.POINTER(None)] +except AttributeError: + pass +try: + lp_set_module_stack_alignment_override = _libraries['libtinymesa_cpu.so'].lp_set_module_stack_alignment_override + lp_set_module_stack_alignment_override.restype = None + lp_set_module_stack_alignment_override.argtypes = [LLVMModuleRef, ctypes.c_uint32] +except AttributeError: + pass +lp_native_vector_width = 0 # Variable ctypes.c_uint32 +class struct_lp_type(Structure): + pass + +struct_lp_type._pack_ = 1 # source:False +struct_lp_type._fields_ = [ + ('floating', ctypes.c_uint64, 1), + ('fixed', ctypes.c_uint64, 1), + ('sign', ctypes.c_uint64, 1), + ('norm', ctypes.c_uint64, 1), + ('signed_zero_preserve', ctypes.c_uint64, 1), + ('nan_preserve', ctypes.c_uint64, 1), + ('width', ctypes.c_uint64, 14), + ('PADDING_0', ctypes.c_uint16, 12), + ('length', ctypes.c_uint64, 14), + ('PADDING_1', ctypes.c_uint32, 18), +] + +class struct_lp_build_context(Structure): + pass + +class struct_gallivm_state(Structure): + pass + +class struct_LLVMOpaqueType(Structure): + pass + +struct_lp_build_context._pack_ = 1 # source:False +struct_lp_build_context._fields_ = [ + ('gallivm', ctypes.POINTER(struct_gallivm_state)), + ('type', struct_lp_type), + ('elem_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('vec_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('int_elem_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('int_vec_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('undef', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('zero', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('one', ctypes.POINTER(struct_LLVMOpaqueValue)), +] + +class struct_LLVMOpaqueTargetData(Structure): + pass + +class struct_LLVMOpaqueBuilder(Structure): + pass + +class struct_LLVMOpaqueDIBuilder(Structure): + pass + +class struct_LLVMOpaqueMetadata(Structure): + pass + +class struct_lp_jit_texture(Structure): + pass + +struct_gallivm_state._pack_ = 1 # source:False +struct_gallivm_state._fields_ = [ + ('module_name', ctypes.POINTER(ctypes.c_char)), + ('file_name', ctypes.POINTER(ctypes.c_char)), + ('module', ctypes.POINTER(struct_LLVMOpaqueModule)), + ('target', ctypes.POINTER(struct_LLVMOpaqueTargetData)), + ('engine', ctypes.POINTER(struct_LLVMOpaqueExecutionEngine)), + ('passmgr', ctypes.POINTER(struct_lp_passmgr)), + ('memorymgr', ctypes.POINTER(struct_LLVMOpaqueMCJITMemoryManager)), + ('code', ctypes.POINTER(struct_lp_generated_code)), + ('context', ctypes.POINTER(struct_LLVMOpaqueContext)), + ('builder', ctypes.POINTER(struct_LLVMOpaqueBuilder)), + ('di_builder', ctypes.POINTER(struct_LLVMOpaqueDIBuilder)), + ('cache', ctypes.POINTER(struct_lp_cached_code)), + ('compiled', ctypes.c_uint32), + ('coro_malloc_hook', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('coro_free_hook', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('debug_printf_hook', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('coro_malloc_hook_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('coro_free_hook_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('di_function', ctypes.POINTER(struct_LLVMOpaqueMetadata)), + ('file', ctypes.POINTER(struct_LLVMOpaqueMetadata)), + ('get_time_hook', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('texture_descriptor', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('texture_dynamic_state', ctypes.POINTER(struct_lp_jit_texture)), + ('sampler_descriptor', ctypes.POINTER(struct_LLVMOpaqueValue)), +] + +class struct_util_format_description(Structure): + pass + +class struct_util_format_block(Structure): + pass + +struct_util_format_block._pack_ = 1 # source:False +struct_util_format_block._fields_ = [ + ('width', ctypes.c_uint32), + ('height', ctypes.c_uint32), + ('depth', ctypes.c_uint32), + ('bits', ctypes.c_uint32), +] + + +# values for enumeration 'util_format_layout' +util_format_layout__enumvalues = { + 0: 'UTIL_FORMAT_LAYOUT_PLAIN', + 1: 'UTIL_FORMAT_LAYOUT_SUBSAMPLED', + 2: 'UTIL_FORMAT_LAYOUT_S3TC', + 3: 'UTIL_FORMAT_LAYOUT_RGTC', + 4: 'UTIL_FORMAT_LAYOUT_ETC', + 5: 'UTIL_FORMAT_LAYOUT_BPTC', + 6: 'UTIL_FORMAT_LAYOUT_ASTC', + 7: 'UTIL_FORMAT_LAYOUT_ATC', + 8: 'UTIL_FORMAT_LAYOUT_PLANAR2', + 9: 'UTIL_FORMAT_LAYOUT_PLANAR3', + 10: 'UTIL_FORMAT_LAYOUT_FXT1', + 11: 'UTIL_FORMAT_LAYOUT_OTHER', +} +UTIL_FORMAT_LAYOUT_PLAIN = 0 +UTIL_FORMAT_LAYOUT_SUBSAMPLED = 1 +UTIL_FORMAT_LAYOUT_S3TC = 2 +UTIL_FORMAT_LAYOUT_RGTC = 3 +UTIL_FORMAT_LAYOUT_ETC = 4 +UTIL_FORMAT_LAYOUT_BPTC = 5 +UTIL_FORMAT_LAYOUT_ASTC = 6 +UTIL_FORMAT_LAYOUT_ATC = 7 +UTIL_FORMAT_LAYOUT_PLANAR2 = 8 +UTIL_FORMAT_LAYOUT_PLANAR3 = 9 +UTIL_FORMAT_LAYOUT_FXT1 = 10 +UTIL_FORMAT_LAYOUT_OTHER = 11 +util_format_layout = ctypes.c_uint32 # enum +class struct_util_format_channel_description(Structure): + pass + +struct_util_format_channel_description._pack_ = 1 # source:False +struct_util_format_channel_description._fields_ = [ + ('type', ctypes.c_uint32, 5), + ('normalized', ctypes.c_uint32, 1), + ('pure_integer', ctypes.c_uint32, 1), + ('size', ctypes.c_uint32, 9), + ('shift', ctypes.c_uint32, 16), +] + + +# values for enumeration 'util_format_colorspace' +util_format_colorspace__enumvalues = { + 0: 'UTIL_FORMAT_COLORSPACE_RGB', + 1: 'UTIL_FORMAT_COLORSPACE_SRGB', + 2: 'UTIL_FORMAT_COLORSPACE_YUV', + 3: 'UTIL_FORMAT_COLORSPACE_ZS', +} +UTIL_FORMAT_COLORSPACE_RGB = 0 +UTIL_FORMAT_COLORSPACE_SRGB = 1 +UTIL_FORMAT_COLORSPACE_YUV = 2 +UTIL_FORMAT_COLORSPACE_ZS = 3 +util_format_colorspace = ctypes.c_uint32 # enum +class union_util_format_description_0(Union): + _pack_ = 1 # source:False + _fields_ = [ + ('srgb_equivalent', pipe_format), + ('linear_equivalent', pipe_format), + ] + +struct_util_format_description._pack_ = 1 # source:False +struct_util_format_description._anonymous_ = ('_0',) +struct_util_format_description._fields_ = [ + ('format', pipe_format), + ('PADDING_0', ctypes.c_ubyte * 4), + ('name', ctypes.POINTER(ctypes.c_char)), + ('short_name', ctypes.POINTER(ctypes.c_char)), + ('block', struct_util_format_block), + ('layout', util_format_layout), + ('nr_channels', ctypes.c_uint32, 3), + ('is_array', ctypes.c_uint32, 1), + ('is_bitmask', ctypes.c_uint32, 1), + ('is_mixed', ctypes.c_uint32, 1), + ('is_unorm', ctypes.c_uint32, 1), + ('is_snorm', ctypes.c_uint32, 1), + ('PADDING_1', ctypes.c_uint32, 24), + ('channel', struct_util_format_channel_description * 4), + ('swizzle', ctypes.c_ubyte * 4), + ('colorspace', util_format_colorspace), + ('_0', union_util_format_description_0), + ('PADDING_2', ctypes.c_ubyte * 4), +] + +try: + lp_type_from_format_desc = _libraries['FIXME_STUB'].lp_type_from_format_desc + lp_type_from_format_desc.restype = None + lp_type_from_format_desc.argtypes = [ctypes.POINTER(struct_lp_type), ctypes.POINTER(struct_util_format_description)] +except AttributeError: + pass +try: + lp_type_from_format = _libraries['FIXME_STUB'].lp_type_from_format + lp_type_from_format.restype = None + lp_type_from_format.argtypes = [ctypes.POINTER(struct_lp_type), pipe_format] +except AttributeError: + pass +try: + lp_type_width = _libraries['FIXME_STUB'].lp_type_width + lp_type_width.restype = ctypes.c_uint32 + lp_type_width.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_type_float = _libraries['FIXME_STUB'].lp_type_float + lp_type_float.restype = struct_lp_type + lp_type_float.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_float_vec = _libraries['FIXME_STUB'].lp_type_float_vec + lp_type_float_vec.restype = struct_lp_type + lp_type_float_vec.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_int = _libraries['FIXME_STUB'].lp_type_int + lp_type_int.restype = struct_lp_type + lp_type_int.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_int_vec = _libraries['FIXME_STUB'].lp_type_int_vec + lp_type_int_vec.restype = struct_lp_type + lp_type_int_vec.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_uint = _libraries['FIXME_STUB'].lp_type_uint + lp_type_uint.restype = struct_lp_type + lp_type_uint.argtypes = [ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_uint_vec = _libraries['FIXME_STUB'].lp_type_uint_vec + lp_type_uint_vec.restype = struct_lp_type + lp_type_uint_vec.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_unorm = _libraries['FIXME_STUB'].lp_type_unorm + lp_type_unorm.restype = struct_lp_type + lp_type_unorm.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_fixed = _libraries['FIXME_STUB'].lp_type_fixed + lp_type_fixed.restype = struct_lp_type + lp_type_fixed.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_type_ufixed = _libraries['FIXME_STUB'].lp_type_ufixed + lp_type_ufixed.restype = struct_lp_type + lp_type_ufixed.argtypes = [ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +LLVMTypeRef = ctypes.POINTER(struct_LLVMOpaqueType) +try: + lp_build_elem_type = _libraries['libtinymesa_cpu.so'].lp_build_elem_type + lp_build_elem_type.restype = LLVMTypeRef + lp_build_elem_type.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_vec_type = _libraries['libtinymesa_cpu.so'].lp_build_vec_type + lp_build_vec_type.restype = LLVMTypeRef + lp_build_vec_type.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_check_elem_type = _libraries['libtinymesa_cpu.so'].lp_check_elem_type + lp_check_elem_type.restype = ctypes.c_bool + lp_check_elem_type.argtypes = [struct_lp_type, LLVMTypeRef] +except AttributeError: + pass +try: + lp_check_vec_type = _libraries['libtinymesa_cpu.so'].lp_check_vec_type + lp_check_vec_type.restype = ctypes.c_bool + lp_check_vec_type.argtypes = [struct_lp_type, LLVMTypeRef] +except AttributeError: + pass +try: + lp_check_value = _libraries['libtinymesa_cpu.so'].lp_check_value + lp_check_value.restype = ctypes.c_bool + lp_check_value.argtypes = [struct_lp_type, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_int_elem_type = _libraries['libtinymesa_cpu.so'].lp_build_int_elem_type + lp_build_int_elem_type.restype = LLVMTypeRef + lp_build_int_elem_type.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_int_vec_type = _libraries['libtinymesa_cpu.so'].lp_build_int_vec_type + lp_build_int_vec_type.restype = LLVMTypeRef + lp_build_int_vec_type.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_float32_vec4_type = _libraries['FIXME_STUB'].lp_float32_vec4_type + lp_float32_vec4_type.restype = struct_lp_type + lp_float32_vec4_type.argtypes = [] +except AttributeError: + pass +try: + lp_int32_vec4_type = _libraries['FIXME_STUB'].lp_int32_vec4_type + lp_int32_vec4_type.restype = struct_lp_type + lp_int32_vec4_type.argtypes = [] +except AttributeError: + pass +try: + lp_unorm8_vec4_type = _libraries['FIXME_STUB'].lp_unorm8_vec4_type + lp_unorm8_vec4_type.restype = struct_lp_type + lp_unorm8_vec4_type.argtypes = [] +except AttributeError: + pass +try: + lp_elem_type = _libraries['libtinymesa_cpu.so'].lp_elem_type + lp_elem_type.restype = struct_lp_type + lp_elem_type.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_uint_type = _libraries['libtinymesa_cpu.so'].lp_uint_type + lp_uint_type.restype = struct_lp_type + lp_uint_type.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_int_type = _libraries['libtinymesa_cpu.so'].lp_int_type + lp_int_type.restype = struct_lp_type + lp_int_type.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_wider_type = _libraries['libtinymesa_cpu.so'].lp_wider_type + lp_wider_type.restype = struct_lp_type + lp_wider_type.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_sizeof_llvm_type = _libraries['libtinymesa_cpu.so'].lp_sizeof_llvm_type + lp_sizeof_llvm_type.restype = ctypes.c_uint32 + lp_sizeof_llvm_type.argtypes = [LLVMTypeRef] +except AttributeError: + pass + +# values for enumeration 'c__EA_LLVMTypeKind' +c__EA_LLVMTypeKind__enumvalues = { + 0: 'LLVMVoidTypeKind', + 1: 'LLVMHalfTypeKind', + 2: 'LLVMFloatTypeKind', + 3: 'LLVMDoubleTypeKind', + 4: 'LLVMX86_FP80TypeKind', + 5: 'LLVMFP128TypeKind', + 6: 'LLVMPPC_FP128TypeKind', + 7: 'LLVMLabelTypeKind', + 8: 'LLVMIntegerTypeKind', + 9: 'LLVMFunctionTypeKind', + 10: 'LLVMStructTypeKind', + 11: 'LLVMArrayTypeKind', + 12: 'LLVMPointerTypeKind', + 13: 'LLVMVectorTypeKind', + 14: 'LLVMMetadataTypeKind', + 16: 'LLVMTokenTypeKind', + 17: 'LLVMScalableVectorTypeKind', + 18: 'LLVMBFloatTypeKind', + 19: 'LLVMX86_AMXTypeKind', + 20: 'LLVMTargetExtTypeKind', +} +LLVMVoidTypeKind = 0 +LLVMHalfTypeKind = 1 +LLVMFloatTypeKind = 2 +LLVMDoubleTypeKind = 3 +LLVMX86_FP80TypeKind = 4 +LLVMFP128TypeKind = 5 +LLVMPPC_FP128TypeKind = 6 +LLVMLabelTypeKind = 7 +LLVMIntegerTypeKind = 8 +LLVMFunctionTypeKind = 9 +LLVMStructTypeKind = 10 +LLVMArrayTypeKind = 11 +LLVMPointerTypeKind = 12 +LLVMVectorTypeKind = 13 +LLVMMetadataTypeKind = 14 +LLVMTokenTypeKind = 16 +LLVMScalableVectorTypeKind = 17 +LLVMBFloatTypeKind = 18 +LLVMX86_AMXTypeKind = 19 +LLVMTargetExtTypeKind = 20 +c__EA_LLVMTypeKind = ctypes.c_uint32 # enum +LLVMTypeKind = c__EA_LLVMTypeKind +LLVMTypeKind__enumvalues = c__EA_LLVMTypeKind__enumvalues +try: + lp_typekind_name = _libraries['libtinymesa_cpu.so'].lp_typekind_name + lp_typekind_name.restype = ctypes.POINTER(ctypes.c_char) + lp_typekind_name.argtypes = [LLVMTypeKind] +except AttributeError: + pass +try: + lp_dump_llvmtype = _libraries['libtinymesa_cpu.so'].lp_dump_llvmtype + lp_dump_llvmtype.restype = None + lp_dump_llvmtype.argtypes = [LLVMTypeRef] +except AttributeError: + pass +try: + lp_build_context_init = _libraries['libtinymesa_cpu.so'].lp_build_context_init + lp_build_context_init.restype = None + lp_build_context_init.argtypes = [ctypes.POINTER(struct_lp_build_context), ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_count_ir_module = _libraries['libtinymesa_cpu.so'].lp_build_count_ir_module + lp_build_count_ir_module.restype = ctypes.c_uint32 + lp_build_count_ir_module.argtypes = [LLVMModuleRef] +except AttributeError: + pass +class union_lp_jit_texture_0(Union): + pass + +class struct_lp_jit_texture_0_0(Structure): + pass + +struct_lp_jit_texture_0_0._pack_ = 1 # source:False +struct_lp_jit_texture_0_0._fields_ = [ + ('row_stride', ctypes.c_uint32 * 16), + ('img_stride', ctypes.c_uint32 * 16), +] + +union_lp_jit_texture_0._pack_ = 1 # source:False +union_lp_jit_texture_0._anonymous_ = ('_0',) +union_lp_jit_texture_0._fields_ = [ + ('_0', struct_lp_jit_texture_0_0), + ('residency', ctypes.POINTER(None)), + ('PADDING_0', ctypes.c_ubyte * 120), +] + +struct_lp_jit_texture._pack_ = 1 # source:False +struct_lp_jit_texture._anonymous_ = ('_0',) +struct_lp_jit_texture._fields_ = [ + ('base', ctypes.POINTER(None)), + ('width', ctypes.c_uint32), + ('height', ctypes.c_uint16), + ('depth', ctypes.c_uint16), + ('_0', union_lp_jit_texture_0), + ('first_level', ctypes.c_ubyte), + ('last_level', ctypes.c_ubyte), + ('mip_offsets', ctypes.c_uint32 * 16), + ('sampler_index', ctypes.c_uint32), +] + +try: + lp_build_init_native_width = _libraries['libtinymesa_cpu.so'].lp_build_init_native_width + lp_build_init_native_width.restype = ctypes.c_uint32 + lp_build_init_native_width.argtypes = [] +except AttributeError: + pass +try: + lp_build_init = _libraries['libtinymesa_cpu.so'].lp_build_init + lp_build_init.restype = ctypes.c_bool + lp_build_init.argtypes = [] +except AttributeError: + pass +try: + gallivm_create = _libraries['libtinymesa_cpu.so'].gallivm_create + gallivm_create.restype = ctypes.POINTER(struct_gallivm_state) + gallivm_create.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(struct_lp_context_ref), ctypes.POINTER(struct_lp_cached_code)] +except AttributeError: + pass +try: + gallivm_destroy = _libraries['libtinymesa_cpu.so'].gallivm_destroy + gallivm_destroy.restype = None + gallivm_destroy.argtypes = [ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass +try: + gallivm_free_ir = _libraries['libtinymesa_cpu.so'].gallivm_free_ir + gallivm_free_ir.restype = None + gallivm_free_ir.argtypes = [ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass +try: + gallivm_verify_function = _libraries['libtinymesa_cpu.so'].gallivm_verify_function + gallivm_verify_function.restype = None + gallivm_verify_function.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef] +except AttributeError: + pass +try: + gallivm_add_global_mapping = _libraries['libtinymesa_cpu.so'].gallivm_add_global_mapping + gallivm_add_global_mapping.restype = None + gallivm_add_global_mapping.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef, ctypes.POINTER(None)] +except AttributeError: + pass +try: + gallivm_compile_module = _libraries['libtinymesa_cpu.so'].gallivm_compile_module + gallivm_compile_module.restype = None + gallivm_compile_module.argtypes = [ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass +func_pointer = ctypes.CFUNCTYPE(None) +try: + gallivm_jit_function = _libraries['libtinymesa_cpu.so'].gallivm_jit_function + gallivm_jit_function.restype = func_pointer + gallivm_jit_function.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + gallivm_stub_func = _libraries['libtinymesa_cpu.so'].gallivm_stub_func + gallivm_stub_func.restype = None + gallivm_stub_func.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef] +except AttributeError: + pass +try: + gallivm_get_perf_flags = _libraries['libtinymesa_cpu.so'].gallivm_get_perf_flags + gallivm_get_perf_flags.restype = ctypes.c_uint32 + gallivm_get_perf_flags.argtypes = [] +except AttributeError: + pass +try: + lp_init_clock_hook = _libraries['libtinymesa_cpu.so'].lp_init_clock_hook + lp_init_clock_hook.restype = None + lp_init_clock_hook.argtypes = [ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass +try: + lp_init_env_options = _libraries['libtinymesa_cpu.so'].lp_init_env_options + lp_init_env_options.restype = None + lp_init_env_options.argtypes = [] +except AttributeError: + pass +try: + lp_bld_ppc_disable_denorms = _libraries['FIXME_STUB'].lp_bld_ppc_disable_denorms + lp_bld_ppc_disable_denorms.restype = None + lp_bld_ppc_disable_denorms.argtypes = [] +except AttributeError: + pass +class struct_lp_build_skip_context(Structure): + pass + +class struct_LLVMOpaqueBasicBlock(Structure): + pass + +struct_lp_build_skip_context._pack_ = 1 # source:False +struct_lp_build_skip_context._fields_ = [ + ('gallivm', ctypes.POINTER(struct_gallivm_state)), + ('block', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), +] + +try: + lp_build_flow_skip_begin = _libraries['libtinymesa_cpu.so'].lp_build_flow_skip_begin + lp_build_flow_skip_begin.restype = None + lp_build_flow_skip_begin.argtypes = [ctypes.POINTER(struct_lp_build_skip_context), ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass +try: + lp_build_flow_skip_cond_break = _libraries['libtinymesa_cpu.so'].lp_build_flow_skip_cond_break + lp_build_flow_skip_cond_break.restype = None + lp_build_flow_skip_cond_break.argtypes = [ctypes.POINTER(struct_lp_build_skip_context), LLVMValueRef] +except AttributeError: + pass +try: + lp_build_flow_skip_end = _libraries['libtinymesa_cpu.so'].lp_build_flow_skip_end + lp_build_flow_skip_end.restype = None + lp_build_flow_skip_end.argtypes = [ctypes.POINTER(struct_lp_build_skip_context)] +except AttributeError: + pass +class struct_lp_build_mask_context(Structure): + pass + +struct_lp_build_mask_context._pack_ = 1 # source:False +struct_lp_build_mask_context._fields_ = [ + ('skip', struct_lp_build_skip_context), + ('reg_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('var_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('var', ctypes.POINTER(struct_LLVMOpaqueValue)), +] + +try: + lp_build_mask_begin = _libraries['libtinymesa_cpu.so'].lp_build_mask_begin + lp_build_mask_begin.restype = None + lp_build_mask_begin.argtypes = [ctypes.POINTER(struct_lp_build_mask_context), ctypes.POINTER(struct_gallivm_state), struct_lp_type, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_mask_value = _libraries['libtinymesa_cpu.so'].lp_build_mask_value + lp_build_mask_value.restype = LLVMValueRef + lp_build_mask_value.argtypes = [ctypes.POINTER(struct_lp_build_mask_context)] +except AttributeError: + pass +try: + lp_build_mask_update = _libraries['libtinymesa_cpu.so'].lp_build_mask_update + lp_build_mask_update.restype = None + lp_build_mask_update.argtypes = [ctypes.POINTER(struct_lp_build_mask_context), LLVMValueRef] +except AttributeError: + pass +try: + lp_build_mask_force = _libraries['libtinymesa_cpu.so'].lp_build_mask_force + lp_build_mask_force.restype = None + lp_build_mask_force.argtypes = [ctypes.POINTER(struct_lp_build_mask_context), LLVMValueRef] +except AttributeError: + pass +try: + lp_build_mask_check = _libraries['libtinymesa_cpu.so'].lp_build_mask_check + lp_build_mask_check.restype = None + lp_build_mask_check.argtypes = [ctypes.POINTER(struct_lp_build_mask_context)] +except AttributeError: + pass +try: + lp_build_mask_end = _libraries['libtinymesa_cpu.so'].lp_build_mask_end + lp_build_mask_end.restype = LLVMValueRef + lp_build_mask_end.argtypes = [ctypes.POINTER(struct_lp_build_mask_context)] +except AttributeError: + pass +class struct_lp_build_loop_state(Structure): + pass + +struct_lp_build_loop_state._pack_ = 1 # source:False +struct_lp_build_loop_state._fields_ = [ + ('block', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('counter_var', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('counter', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('counter_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('gallivm', ctypes.POINTER(struct_gallivm_state)), +] + +try: + lp_build_loop_begin = _libraries['libtinymesa_cpu.so'].lp_build_loop_begin + lp_build_loop_begin.restype = None + lp_build_loop_begin.argtypes = [ctypes.POINTER(struct_lp_build_loop_state), ctypes.POINTER(struct_gallivm_state), LLVMValueRef] +except AttributeError: + pass +try: + lp_build_loop_end = _libraries['libtinymesa_cpu.so'].lp_build_loop_end + lp_build_loop_end.restype = None + lp_build_loop_end.argtypes = [ctypes.POINTER(struct_lp_build_loop_state), LLVMValueRef, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_loop_force_set_counter = _libraries['libtinymesa_cpu.so'].lp_build_loop_force_set_counter + lp_build_loop_force_set_counter.restype = None + lp_build_loop_force_set_counter.argtypes = [ctypes.POINTER(struct_lp_build_loop_state), LLVMValueRef] +except AttributeError: + pass +try: + lp_build_loop_force_reload_counter = _libraries['libtinymesa_cpu.so'].lp_build_loop_force_reload_counter + lp_build_loop_force_reload_counter.restype = None + lp_build_loop_force_reload_counter.argtypes = [ctypes.POINTER(struct_lp_build_loop_state)] +except AttributeError: + pass + +# values for enumeration 'c__EA_LLVMIntPredicate' +c__EA_LLVMIntPredicate__enumvalues = { + 32: 'LLVMIntEQ', + 33: 'LLVMIntNE', + 34: 'LLVMIntUGT', + 35: 'LLVMIntUGE', + 36: 'LLVMIntULT', + 37: 'LLVMIntULE', + 38: 'LLVMIntSGT', + 39: 'LLVMIntSGE', + 40: 'LLVMIntSLT', + 41: 'LLVMIntSLE', +} +LLVMIntEQ = 32 +LLVMIntNE = 33 +LLVMIntUGT = 34 +LLVMIntUGE = 35 +LLVMIntULT = 36 +LLVMIntULE = 37 +LLVMIntSGT = 38 +LLVMIntSGE = 39 +LLVMIntSLT = 40 +LLVMIntSLE = 41 +c__EA_LLVMIntPredicate = ctypes.c_uint32 # enum +LLVMIntPredicate = c__EA_LLVMIntPredicate +LLVMIntPredicate__enumvalues = c__EA_LLVMIntPredicate__enumvalues +try: + lp_build_loop_end_cond = _libraries['libtinymesa_cpu.so'].lp_build_loop_end_cond + lp_build_loop_end_cond.restype = None + lp_build_loop_end_cond.argtypes = [ctypes.POINTER(struct_lp_build_loop_state), LLVMValueRef, LLVMValueRef, LLVMIntPredicate] +except AttributeError: + pass +class struct_lp_build_for_loop_state(Structure): + pass + +struct_lp_build_for_loop_state._pack_ = 1 # source:False +struct_lp_build_for_loop_state._fields_ = [ + ('begin', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('body', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('exit', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('counter_var', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('counter', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('counter_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('step', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('cond', LLVMIntPredicate), + ('PADDING_0', ctypes.c_ubyte * 4), + ('end', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('gallivm', ctypes.POINTER(struct_gallivm_state)), +] + +try: + lp_build_for_loop_begin = _libraries['libtinymesa_cpu.so'].lp_build_for_loop_begin + lp_build_for_loop_begin.restype = None + lp_build_for_loop_begin.argtypes = [ctypes.POINTER(struct_lp_build_for_loop_state), ctypes.POINTER(struct_gallivm_state), LLVMValueRef, LLVMIntPredicate, LLVMValueRef, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_for_loop_end = _libraries['libtinymesa_cpu.so'].lp_build_for_loop_end + lp_build_for_loop_end.restype = None + lp_build_for_loop_end.argtypes = [ctypes.POINTER(struct_lp_build_for_loop_state)] +except AttributeError: + pass +class struct_lp_build_if_state(Structure): + pass + +struct_lp_build_if_state._pack_ = 1 # source:False +struct_lp_build_if_state._fields_ = [ + ('gallivm', ctypes.POINTER(struct_gallivm_state)), + ('condition', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('entry_block', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('true_block', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('false_block', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), + ('merge_block', ctypes.POINTER(struct_LLVMOpaqueBasicBlock)), +] + +try: + lp_build_if = _libraries['libtinymesa_cpu.so'].lp_build_if + lp_build_if.restype = None + lp_build_if.argtypes = [ctypes.POINTER(struct_lp_build_if_state), ctypes.POINTER(struct_gallivm_state), LLVMValueRef] +except AttributeError: + pass +try: + lp_build_else = _libraries['libtinymesa_cpu.so'].lp_build_else + lp_build_else.restype = None + lp_build_else.argtypes = [ctypes.POINTER(struct_lp_build_if_state)] +except AttributeError: + pass +try: + lp_build_endif = _libraries['libtinymesa_cpu.so'].lp_build_endif + lp_build_endif.restype = None + lp_build_endif.argtypes = [ctypes.POINTER(struct_lp_build_if_state)] +except AttributeError: + pass +LLVMBasicBlockRef = ctypes.POINTER(struct_LLVMOpaqueBasicBlock) +try: + lp_build_insert_new_block = _libraries['libtinymesa_cpu.so'].lp_build_insert_new_block + lp_build_insert_new_block.restype = LLVMBasicBlockRef + lp_build_insert_new_block.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +LLVMBuilderRef = ctypes.POINTER(struct_LLVMOpaqueBuilder) +try: + lp_create_builder_at_entry = _libraries['libtinymesa_cpu.so'].lp_create_builder_at_entry + lp_create_builder_at_entry.restype = LLVMBuilderRef + lp_create_builder_at_entry.argtypes = [ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass +try: + lp_build_alloca = _libraries['libtinymesa_cpu.so'].lp_build_alloca + lp_build_alloca.restype = LLVMValueRef + lp_build_alloca.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_build_alloca_undef = _libraries['libtinymesa_cpu.so'].lp_build_alloca_undef + lp_build_alloca_undef.restype = LLVMValueRef + lp_build_alloca_undef.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_build_array_alloca = _libraries['libtinymesa_cpu.so'].lp_build_array_alloca + lp_build_array_alloca.restype = LLVMValueRef + lp_build_array_alloca.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, LLVMValueRef, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +class struct_lp_build_tgsi_params(Structure): + pass + +class struct_lp_bld_tgsi_system_values(Structure): + pass + +class struct_lp_build_sampler_soa(Structure): + pass + +class struct_tgsi_shader_info(Structure): + pass + +class struct_lp_build_gs_iface(Structure): + pass + +class struct_lp_build_tcs_iface(Structure): + pass + +class struct_lp_build_tes_iface(Structure): + pass + +class struct_lp_build_mesh_iface(Structure): + pass + +class struct_lp_build_image_soa(Structure): + pass + +class struct_lp_build_coro_suspend_info(Structure): + pass + +class struct_lp_build_fs_iface(Structure): + pass + +struct_lp_build_tgsi_params._pack_ = 1 # source:False +struct_lp_build_tgsi_params._fields_ = [ + ('type', struct_lp_type), + ('mask', ctypes.POINTER(struct_lp_build_mask_context)), + ('consts_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('const_sizes_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('system_values', ctypes.POINTER(struct_lp_bld_tgsi_system_values)), + ('inputs', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue) * 4)), + ('num_inputs', ctypes.c_int32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('context_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('context_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('resources_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('resources_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('thread_data_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('thread_data_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sampler', ctypes.POINTER(struct_lp_build_sampler_soa)), + ('info', ctypes.POINTER(struct_tgsi_shader_info)), + ('gs_iface', ctypes.POINTER(struct_lp_build_gs_iface)), + ('tcs_iface', ctypes.POINTER(struct_lp_build_tcs_iface)), + ('tes_iface', ctypes.POINTER(struct_lp_build_tes_iface)), + ('mesh_iface', ctypes.POINTER(struct_lp_build_mesh_iface)), + ('ssbo_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('ssbo_sizes_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('image', ctypes.POINTER(struct_lp_build_image_soa)), + ('shared_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('payload_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('coro', ctypes.POINTER(struct_lp_build_coro_suspend_info)), + ('fs_iface', ctypes.POINTER(struct_lp_build_fs_iface)), + ('gs_vertex_streams', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('current_func', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('fns', ctypes.POINTER(struct_hash_table)), + ('scratch_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('call_context_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), +] + +struct_lp_bld_tgsi_system_values._pack_ = 1 # source:False +struct_lp_bld_tgsi_system_values._fields_ = [ + ('instance_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('base_instance', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('vertex_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('vertex_id_nobase', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('prim_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('basevertex', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('firstvertex', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('invocation_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('draw_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('thread_id', ctypes.POINTER(struct_LLVMOpaqueValue) * 3), + ('block_id', ctypes.POINTER(struct_LLVMOpaqueValue) * 3), + ('grid_size', ctypes.POINTER(struct_LLVMOpaqueValue) * 3), + ('front_facing', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('work_dim', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('block_size', ctypes.POINTER(struct_LLVMOpaqueValue) * 3), + ('tess_coord', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('tess_outer', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('tess_inner', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('vertices_in', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sample_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sample_pos_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('sample_pos', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sample_mask_in', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('view_index', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('subgroup_id', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('num_subgroups', ctypes.POINTER(struct_LLVMOpaqueValue)), +] + +class struct_lp_sampler_params(Structure): + pass + +class struct_lp_sampler_size_query_params(Structure): + pass + +struct_lp_build_sampler_soa._pack_ = 1 # source:False +struct_lp_build_sampler_soa._fields_ = [ + ('emit_tex_sample', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_sampler_soa), ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_lp_sampler_params))), + ('emit_size_query', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_sampler_soa), ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_lp_sampler_size_query_params))), +] + +class struct_lp_derivatives(Structure): + pass + +struct_lp_sampler_params._pack_ = 1 # source:False +struct_lp_sampler_params._fields_ = [ + ('type', struct_lp_type), + ('texture_index', ctypes.c_uint32), + ('sampler_index', ctypes.c_uint32), + ('texture_index_offset', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sample_key', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('resources_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('resources_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('thread_data_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('thread_data_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('coords', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue))), + ('offsets', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue))), + ('ms_index', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('lod', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('min_lod', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('derivs', ctypes.POINTER(struct_lp_derivatives)), + ('texel', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue))), + ('texture_resource', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sampler_resource', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('exec_mask', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('exec_mask_nz', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 7), +] + +struct_lp_derivatives._pack_ = 1 # source:False +struct_lp_derivatives._fields_ = [ + ('ddx', ctypes.POINTER(struct_LLVMOpaqueValue) * 3), + ('ddy', ctypes.POINTER(struct_LLVMOpaqueValue) * 3), +] + + +# values for enumeration 'lp_sampler_lod_property' +lp_sampler_lod_property__enumvalues = { + 0: 'LP_SAMPLER_LOD_SCALAR', + 1: 'LP_SAMPLER_LOD_PER_ELEMENT', + 2: 'LP_SAMPLER_LOD_PER_QUAD', +} +LP_SAMPLER_LOD_SCALAR = 0 +LP_SAMPLER_LOD_PER_ELEMENT = 1 +LP_SAMPLER_LOD_PER_QUAD = 2 +lp_sampler_lod_property = ctypes.c_uint32 # enum +struct_lp_sampler_size_query_params._pack_ = 1 # source:False +struct_lp_sampler_size_query_params._fields_ = [ + ('int_type', struct_lp_type), + ('texture_unit', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('texture_unit_offset', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('target', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('resources_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('resources_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('is_sviewinfo', ctypes.c_bool), + ('samples_only', ctypes.c_bool), + ('ms', ctypes.c_bool), + ('PADDING_2', ctypes.c_ubyte), + ('lod_property', lp_sampler_lod_property), + ('explicit_lod', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('sizes_out', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue))), + ('resource', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('exec_mask', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('exec_mask_nz', ctypes.c_bool), + ('PADDING_3', ctypes.c_ubyte * 3), + ('format', pipe_format), +] + +struct_tgsi_shader_info._pack_ = 1 # source:False +struct_tgsi_shader_info._fields_ = [ + ('num_inputs', ctypes.c_ubyte), + ('num_outputs', ctypes.c_ubyte), + ('input_semantic_name', ctypes.c_ubyte * 80), + ('input_semantic_index', ctypes.c_ubyte * 80), + ('input_interpolate', ctypes.c_ubyte * 80), + ('input_interpolate_loc', ctypes.c_ubyte * 80), + ('input_usage_mask', ctypes.c_ubyte * 80), + ('output_semantic_name', ctypes.c_ubyte * 80), + ('output_semantic_index', ctypes.c_ubyte * 80), + ('output_usagemask', ctypes.c_ubyte * 80), + ('output_streams', ctypes.c_ubyte * 80), + ('num_system_values', ctypes.c_ubyte), + ('system_value_semantic_name', ctypes.c_ubyte * 80), + ('processor', ctypes.c_ubyte), + ('file_mask', ctypes.c_uint32 * 15), + ('file_count', ctypes.c_uint32 * 15), + ('file_max', ctypes.c_int32 * 15), + ('const_file_max', ctypes.c_int32 * 32), + ('const_buffers_declared', ctypes.c_uint32), + ('samplers_declared', ctypes.c_uint32), + ('sampler_targets', ctypes.c_ubyte * 128), + ('sampler_type', ctypes.c_ubyte * 128), + ('num_stream_output_components', ctypes.c_ubyte * 4), + ('input_array_first', ctypes.c_ubyte * 80), + ('output_array_first', ctypes.c_ubyte * 80), + ('immediate_count', ctypes.c_uint32), + ('num_instructions', ctypes.c_uint32), + ('opcode_count', ctypes.c_uint32 * 252), + ('reads_pervertex_outputs', ctypes.c_bool), + ('reads_perpatch_outputs', ctypes.c_bool), + ('reads_tessfactor_outputs', ctypes.c_bool), + ('reads_z', ctypes.c_bool), + ('writes_z', ctypes.c_bool), + ('writes_stencil', ctypes.c_bool), + ('writes_samplemask', ctypes.c_bool), + ('writes_edgeflag', ctypes.c_bool), + ('uses_kill', ctypes.c_bool), + ('uses_instanceid', ctypes.c_bool), + ('uses_vertexid', ctypes.c_bool), + ('uses_vertexid_nobase', ctypes.c_bool), + ('uses_basevertex', ctypes.c_bool), + ('uses_primid', ctypes.c_bool), + ('uses_frontface', ctypes.c_bool), + ('uses_invocationid', ctypes.c_bool), + ('uses_grid_size', ctypes.c_bool), + ('writes_position', ctypes.c_bool), + ('writes_psize', ctypes.c_bool), + ('writes_clipvertex', ctypes.c_bool), + ('writes_viewport_index', ctypes.c_bool), + ('writes_layer', ctypes.c_bool), + ('writes_memory', ctypes.c_bool), + ('uses_fbfetch', ctypes.c_bool), + ('num_written_culldistance', ctypes.c_uint32), + ('num_written_clipdistance', ctypes.c_uint32), + ('images_declared', ctypes.c_uint32), + ('msaa_images_declared', ctypes.c_uint32), + ('images_buffers', ctypes.c_uint32), + ('shader_buffers_declared', ctypes.c_uint32), + ('shader_buffers_load', ctypes.c_uint32), + ('shader_buffers_store', ctypes.c_uint32), + ('shader_buffers_atomic', ctypes.c_uint32), + ('hw_atomic_declared', ctypes.c_uint32), + ('indirect_files', ctypes.c_uint32), + ('dim_indirect_files', ctypes.c_uint32), + ('properties', ctypes.c_uint32 * 29), +] + +struct_lp_build_gs_iface._pack_ = 1 # source:False +struct_lp_build_gs_iface._fields_ = [ + ('fetch_input', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_gs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue))), + ('emit_vertex', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_gs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue) * 4), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue))), + ('end_primitive', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_gs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_uint32)), + ('gs_epilogue', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_gs_iface), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_uint32)), +] + +struct_lp_build_tcs_iface._pack_ = 1 # source:False +struct_lp_build_tcs_iface._fields_ = [ + ('emit_prologue', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_context))), + ('emit_epilogue', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_context))), + ('emit_barrier', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_context))), + ('emit_store_output', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_tcs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_uint32, ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue))), + ('emit_fetch_input', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_tcs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue))), + ('emit_fetch_output', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_tcs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_uint32)), +] + +struct_lp_build_tes_iface._pack_ = 1 # source:False +struct_lp_build_tes_iface._fields_ = [ + ('fetch_vertex_input', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_tes_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue))), + ('fetch_patch_input', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_tes_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue))), +] + +struct_lp_build_mesh_iface._pack_ = 1 # source:False +struct_lp_build_mesh_iface._fields_ = [ + ('emit_store_output', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_mesh_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_uint32, ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue))), + ('emit_vertex_and_primitive_count', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_mesh_iface), ctypes.POINTER(struct_lp_build_context), ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_LLVMOpaqueValue))), +] + +class struct_lp_img_params(Structure): + pass + +struct_lp_build_image_soa._pack_ = 1 # source:False +struct_lp_build_image_soa._fields_ = [ + ('emit_op', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_image_soa), ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_lp_img_params))), + ('emit_size_query', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_image_soa), ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_lp_sampler_size_query_params))), +] + + +# values for enumeration 'c__EA_LLVMAtomicRMWBinOp' +c__EA_LLVMAtomicRMWBinOp__enumvalues = { + 0: 'LLVMAtomicRMWBinOpXchg', + 1: 'LLVMAtomicRMWBinOpAdd', + 2: 'LLVMAtomicRMWBinOpSub', + 3: 'LLVMAtomicRMWBinOpAnd', + 4: 'LLVMAtomicRMWBinOpNand', + 5: 'LLVMAtomicRMWBinOpOr', + 6: 'LLVMAtomicRMWBinOpXor', + 7: 'LLVMAtomicRMWBinOpMax', + 8: 'LLVMAtomicRMWBinOpMin', + 9: 'LLVMAtomicRMWBinOpUMax', + 10: 'LLVMAtomicRMWBinOpUMin', + 11: 'LLVMAtomicRMWBinOpFAdd', + 12: 'LLVMAtomicRMWBinOpFSub', + 13: 'LLVMAtomicRMWBinOpFMax', + 14: 'LLVMAtomicRMWBinOpFMin', + 15: 'LLVMAtomicRMWBinOpUIncWrap', + 16: 'LLVMAtomicRMWBinOpUDecWrap', + 17: 'LLVMAtomicRMWBinOpUSubCond', + 18: 'LLVMAtomicRMWBinOpUSubSat', +} +LLVMAtomicRMWBinOpXchg = 0 +LLVMAtomicRMWBinOpAdd = 1 +LLVMAtomicRMWBinOpSub = 2 +LLVMAtomicRMWBinOpAnd = 3 +LLVMAtomicRMWBinOpNand = 4 +LLVMAtomicRMWBinOpOr = 5 +LLVMAtomicRMWBinOpXor = 6 +LLVMAtomicRMWBinOpMax = 7 +LLVMAtomicRMWBinOpMin = 8 +LLVMAtomicRMWBinOpUMax = 9 +LLVMAtomicRMWBinOpUMin = 10 +LLVMAtomicRMWBinOpFAdd = 11 +LLVMAtomicRMWBinOpFSub = 12 +LLVMAtomicRMWBinOpFMax = 13 +LLVMAtomicRMWBinOpFMin = 14 +LLVMAtomicRMWBinOpUIncWrap = 15 +LLVMAtomicRMWBinOpUDecWrap = 16 +LLVMAtomicRMWBinOpUSubCond = 17 +LLVMAtomicRMWBinOpUSubSat = 18 +c__EA_LLVMAtomicRMWBinOp = ctypes.c_uint32 # enum +struct_lp_img_params._pack_ = 1 # source:False +struct_lp_img_params._fields_ = [ + ('type', struct_lp_type), + ('image_index', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('image_index_offset', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('img_op', ctypes.c_uint32), + ('target', ctypes.c_uint32), + ('packed_op', ctypes.c_uint32), + ('op', c__EA_LLVMAtomicRMWBinOp), + ('exec_mask', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('exec_mask_nz', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 7), + ('resources_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('resources_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('thread_data_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('thread_data_ptr', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('coords', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue))), + ('ms_index', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('indata', ctypes.POINTER(struct_LLVMOpaqueValue) * 4), + ('indata2', ctypes.POINTER(struct_LLVMOpaqueValue) * 4), + ('outdata', ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue))), + ('resource', ctypes.POINTER(struct_LLVMOpaqueValue)), + ('format', pipe_format), + ('PADDING_2', ctypes.c_ubyte * 4), +] + +struct_lp_build_fs_iface._pack_ = 1 # source:False +struct_lp_build_fs_iface._fields_ = [ + ('interp_fn', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_fs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_uint32, ctypes.c_uint32, ctypes.c_bool, ctypes.c_bool, ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue)))), + ('fb_fetch', ctypes.CFUNCTYPE(None, ctypes.POINTER(struct_lp_build_fs_iface), ctypes.POINTER(struct_lp_build_context), ctypes.c_int32, ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue)))), +] + +try: + lp_build_nir_soa = _libraries['libtinymesa_cpu.so'].lp_build_nir_soa + lp_build_nir_soa.restype = None + lp_build_nir_soa.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_lp_build_tgsi_params), ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue) * 4)] +except AttributeError: + pass +try: + lp_build_nir_soa_func = _libraries['libtinymesa_cpu.so'].lp_build_nir_soa_func + lp_build_nir_soa_func.restype = None + lp_build_nir_soa_func.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_nir_shader), ctypes.POINTER(struct_nir_function_impl), ctypes.POINTER(struct_lp_build_tgsi_params), ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue) * 4)] +except AttributeError: + pass +class struct_lp_build_sampler_aos(Structure): + pass + + +# values for enumeration 'tgsi_texture_type' +tgsi_texture_type__enumvalues = { + 0: 'TGSI_TEXTURE_BUFFER', + 1: 'TGSI_TEXTURE_1D', + 2: 'TGSI_TEXTURE_2D', + 3: 'TGSI_TEXTURE_3D', + 4: 'TGSI_TEXTURE_CUBE', + 5: 'TGSI_TEXTURE_RECT', + 6: 'TGSI_TEXTURE_SHADOW1D', + 7: 'TGSI_TEXTURE_SHADOW2D', + 8: 'TGSI_TEXTURE_SHADOWRECT', + 9: 'TGSI_TEXTURE_1D_ARRAY', + 10: 'TGSI_TEXTURE_2D_ARRAY', + 11: 'TGSI_TEXTURE_SHADOW1D_ARRAY', + 12: 'TGSI_TEXTURE_SHADOW2D_ARRAY', + 13: 'TGSI_TEXTURE_SHADOWCUBE', + 14: 'TGSI_TEXTURE_2D_MSAA', + 15: 'TGSI_TEXTURE_2D_ARRAY_MSAA', + 16: 'TGSI_TEXTURE_CUBE_ARRAY', + 17: 'TGSI_TEXTURE_SHADOWCUBE_ARRAY', + 18: 'TGSI_TEXTURE_UNKNOWN', + 19: 'TGSI_TEXTURE_COUNT', +} +TGSI_TEXTURE_BUFFER = 0 +TGSI_TEXTURE_1D = 1 +TGSI_TEXTURE_2D = 2 +TGSI_TEXTURE_3D = 3 +TGSI_TEXTURE_CUBE = 4 +TGSI_TEXTURE_RECT = 5 +TGSI_TEXTURE_SHADOW1D = 6 +TGSI_TEXTURE_SHADOW2D = 7 +TGSI_TEXTURE_SHADOWRECT = 8 +TGSI_TEXTURE_1D_ARRAY = 9 +TGSI_TEXTURE_2D_ARRAY = 10 +TGSI_TEXTURE_SHADOW1D_ARRAY = 11 +TGSI_TEXTURE_SHADOW2D_ARRAY = 12 +TGSI_TEXTURE_SHADOWCUBE = 13 +TGSI_TEXTURE_2D_MSAA = 14 +TGSI_TEXTURE_2D_ARRAY_MSAA = 15 +TGSI_TEXTURE_CUBE_ARRAY = 16 +TGSI_TEXTURE_SHADOWCUBE_ARRAY = 17 +TGSI_TEXTURE_UNKNOWN = 18 +TGSI_TEXTURE_COUNT = 19 +tgsi_texture_type = ctypes.c_uint32 # enum + +# values for enumeration 'lp_build_tex_modifier' +lp_build_tex_modifier__enumvalues = { + 0: 'LP_BLD_TEX_MODIFIER_NONE', + 1: 'LP_BLD_TEX_MODIFIER_PROJECTED', + 2: 'LP_BLD_TEX_MODIFIER_LOD_BIAS', + 3: 'LP_BLD_TEX_MODIFIER_EXPLICIT_LOD', + 4: 'LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV', + 5: 'LP_BLD_TEX_MODIFIER_LOD_ZERO', +} +LP_BLD_TEX_MODIFIER_NONE = 0 +LP_BLD_TEX_MODIFIER_PROJECTED = 1 +LP_BLD_TEX_MODIFIER_LOD_BIAS = 2 +LP_BLD_TEX_MODIFIER_EXPLICIT_LOD = 3 +LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV = 4 +LP_BLD_TEX_MODIFIER_LOD_ZERO = 5 +lp_build_tex_modifier = ctypes.c_uint32 # enum +struct_lp_build_sampler_aos._pack_ = 1 # source:False +struct_lp_build_sampler_aos._fields_ = [ + ('emit_fetch_texel', ctypes.CFUNCTYPE(ctypes.POINTER(struct_LLVMOpaqueValue), ctypes.POINTER(struct_lp_build_sampler_aos), ctypes.POINTER(struct_lp_build_context), tgsi_texture_type, ctypes.c_uint32, ctypes.POINTER(struct_LLVMOpaqueValue), struct_lp_derivatives, lp_build_tex_modifier)), +] + +try: + lp_build_nir_aos = _libraries['FIXME_STUB'].lp_build_nir_aos + lp_build_nir_aos.restype = None + lp_build_nir_aos.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_nir_shader), struct_lp_type, ctypes.c_ubyte * 4, LLVMValueRef, ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue)), ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue)), ctypes.POINTER(struct_lp_build_sampler_aos)] +except AttributeError: + pass +class struct_lp_build_fn(Structure): + pass + +struct_lp_build_fn._pack_ = 1 # source:False +struct_lp_build_fn._fields_ = [ + ('fn_type', ctypes.POINTER(struct_LLVMOpaqueType)), + ('fn', ctypes.POINTER(struct_LLVMOpaqueValue)), +] + +try: + lp_build_nir_soa_prepasses = _libraries['libtinymesa_cpu.so'].lp_build_nir_soa_prepasses + lp_build_nir_soa_prepasses.restype = None + lp_build_nir_soa_prepasses.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + lp_build_opt_nir = _libraries['libtinymesa_cpu.so'].lp_build_opt_nir + lp_build_opt_nir.restype = None + lp_build_opt_nir.argtypes = [ctypes.POINTER(struct_nir_shader)] +except AttributeError: + pass +try: + lp_nir_array_build_gather_values = _libraries['FIXME_STUB'].lp_nir_array_build_gather_values + lp_nir_array_build_gather_values.restype = LLVMValueRef + lp_nir_array_build_gather_values.argtypes = [LLVMBuilderRef, ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueValue)), ctypes.c_uint32] +except AttributeError: + pass +LLVMAtomicRMWBinOp = c__EA_LLVMAtomicRMWBinOp +LLVMAtomicRMWBinOp__enumvalues = c__EA_LLVMAtomicRMWBinOp__enumvalues +try: + lp_translate_atomic_op = _libraries['libtinymesa_cpu.so'].lp_translate_atomic_op + lp_translate_atomic_op.restype = LLVMAtomicRMWBinOp + lp_translate_atomic_op.argtypes = [nir_atomic_op] +except AttributeError: + pass +try: + lp_build_nir_sample_key = _libraries['libtinymesa_cpu.so'].lp_build_nir_sample_key + lp_build_nir_sample_key.restype = uint32_t + lp_build_nir_sample_key.argtypes = [gl_shader_stage, ctypes.POINTER(struct_nir_tex_instr)] +except AttributeError: + pass +try: + lp_img_op_from_intrinsic = _libraries['libtinymesa_cpu.so'].lp_img_op_from_intrinsic + lp_img_op_from_intrinsic.restype = None + lp_img_op_from_intrinsic.argtypes = [ctypes.POINTER(struct_lp_img_params), ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass +try: + lp_packed_img_op_from_intrinsic = _libraries['libtinymesa_cpu.so'].lp_packed_img_op_from_intrinsic + lp_packed_img_op_from_intrinsic.restype = uint32_t + lp_packed_img_op_from_intrinsic.argtypes = [ctypes.POINTER(struct_nir_intrinsic_instr)] +except AttributeError: + pass + +# values for enumeration 'lp_nir_call_context_args' +lp_nir_call_context_args__enumvalues = { + 0: 'LP_NIR_CALL_CONTEXT_CONTEXT', + 1: 'LP_NIR_CALL_CONTEXT_RESOURCES', + 2: 'LP_NIR_CALL_CONTEXT_SHARED', + 3: 'LP_NIR_CALL_CONTEXT_SCRATCH', + 4: 'LP_NIR_CALL_CONTEXT_WORK_DIM', + 5: 'LP_NIR_CALL_CONTEXT_THREAD_ID_0', + 6: 'LP_NIR_CALL_CONTEXT_THREAD_ID_1', + 7: 'LP_NIR_CALL_CONTEXT_THREAD_ID_2', + 8: 'LP_NIR_CALL_CONTEXT_BLOCK_ID_0', + 9: 'LP_NIR_CALL_CONTEXT_BLOCK_ID_1', + 10: 'LP_NIR_CALL_CONTEXT_BLOCK_ID_2', + 11: 'LP_NIR_CALL_CONTEXT_GRID_SIZE_0', + 12: 'LP_NIR_CALL_CONTEXT_GRID_SIZE_1', + 13: 'LP_NIR_CALL_CONTEXT_GRID_SIZE_2', + 14: 'LP_NIR_CALL_CONTEXT_BLOCK_SIZE_0', + 15: 'LP_NIR_CALL_CONTEXT_BLOCK_SIZE_1', + 16: 'LP_NIR_CALL_CONTEXT_BLOCK_SIZE_2', + 17: 'LP_NIR_CALL_CONTEXT_MAX_ARGS', +} +LP_NIR_CALL_CONTEXT_CONTEXT = 0 +LP_NIR_CALL_CONTEXT_RESOURCES = 1 +LP_NIR_CALL_CONTEXT_SHARED = 2 +LP_NIR_CALL_CONTEXT_SCRATCH = 3 +LP_NIR_CALL_CONTEXT_WORK_DIM = 4 +LP_NIR_CALL_CONTEXT_THREAD_ID_0 = 5 +LP_NIR_CALL_CONTEXT_THREAD_ID_1 = 6 +LP_NIR_CALL_CONTEXT_THREAD_ID_2 = 7 +LP_NIR_CALL_CONTEXT_BLOCK_ID_0 = 8 +LP_NIR_CALL_CONTEXT_BLOCK_ID_1 = 9 +LP_NIR_CALL_CONTEXT_BLOCK_ID_2 = 10 +LP_NIR_CALL_CONTEXT_GRID_SIZE_0 = 11 +LP_NIR_CALL_CONTEXT_GRID_SIZE_1 = 12 +LP_NIR_CALL_CONTEXT_GRID_SIZE_2 = 13 +LP_NIR_CALL_CONTEXT_BLOCK_SIZE_0 = 14 +LP_NIR_CALL_CONTEXT_BLOCK_SIZE_1 = 15 +LP_NIR_CALL_CONTEXT_BLOCK_SIZE_2 = 16 +LP_NIR_CALL_CONTEXT_MAX_ARGS = 17 +lp_nir_call_context_args = ctypes.c_uint32 # enum +try: + lp_build_cs_func_call_context = _libraries['libtinymesa_cpu.so'].lp_build_cs_func_call_context + lp_build_cs_func_call_context.restype = LLVMTypeRef + lp_build_cs_func_call_context.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.c_int32, LLVMTypeRef, LLVMTypeRef] +except AttributeError: + pass +try: + lp_build_struct_get_ptr2 = _libraries['libtinymesa_cpu.so'].lp_build_struct_get_ptr2 + lp_build_struct_get_ptr2.restype = LLVMValueRef + lp_build_struct_get_ptr2.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, LLVMValueRef, ctypes.c_uint32, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_build_struct_get2 = _libraries['libtinymesa_cpu.so'].lp_build_struct_get2 + lp_build_struct_get2.restype = LLVMValueRef + lp_build_struct_get2.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, LLVMValueRef, ctypes.c_uint32, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_build_array_get_ptr2 = _libraries['libtinymesa_cpu.so'].lp_build_array_get_ptr2 + lp_build_array_get_ptr2.restype = LLVMValueRef + lp_build_array_get_ptr2.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, LLVMValueRef, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_array_get2 = _libraries['libtinymesa_cpu.so'].lp_build_array_get2 + lp_build_array_get2.restype = LLVMValueRef + lp_build_array_get2.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMTypeRef, LLVMValueRef, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_pointer_get2 = _libraries['libtinymesa_cpu.so'].lp_build_pointer_get2 + lp_build_pointer_get2.restype = LLVMValueRef + lp_build_pointer_get2.argtypes = [LLVMBuilderRef, LLVMTypeRef, LLVMValueRef, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_pointer_get_unaligned2 = _libraries['libtinymesa_cpu.so'].lp_build_pointer_get_unaligned2 + lp_build_pointer_get_unaligned2.restype = LLVMValueRef + lp_build_pointer_get_unaligned2.argtypes = [LLVMBuilderRef, LLVMTypeRef, LLVMValueRef, LLVMValueRef, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_build_pointer_set = _libraries['libtinymesa_cpu.so'].lp_build_pointer_set + lp_build_pointer_set.restype = None + lp_build_pointer_set.argtypes = [LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef] +except AttributeError: + pass +try: + lp_build_pointer_set_unaligned = _libraries['libtinymesa_cpu.so'].lp_build_pointer_set_unaligned + lp_build_pointer_set_unaligned.restype = None + lp_build_pointer_set_unaligned.argtypes = [LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, ctypes.c_uint32] +except AttributeError: + pass +class struct_lp_jit_buffer(Structure): + pass + +class union_lp_jit_buffer_0(Union): + pass + +union_lp_jit_buffer_0._pack_ = 1 # source:False +union_lp_jit_buffer_0._fields_ = [ + ('u', ctypes.POINTER(ctypes.c_uint32)), + ('f', ctypes.POINTER(ctypes.c_float)), +] + +struct_lp_jit_buffer._pack_ = 1 # source:False +struct_lp_jit_buffer._anonymous_ = ('_0',) +struct_lp_jit_buffer._fields_ = [ + ('_0', union_lp_jit_buffer_0), + ('num_elements', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), +] + + +# values for enumeration 'c__Ea_LP_JIT_BUFFER_BASE' +c__Ea_LP_JIT_BUFFER_BASE__enumvalues = { + 0: 'LP_JIT_BUFFER_BASE', + 1: 'LP_JIT_BUFFER_NUM_ELEMENTS', + 2: 'LP_JIT_BUFFER_NUM_FIELDS', +} +LP_JIT_BUFFER_BASE = 0 +LP_JIT_BUFFER_NUM_ELEMENTS = 1 +LP_JIT_BUFFER_NUM_FIELDS = 2 +c__Ea_LP_JIT_BUFFER_BASE = ctypes.c_uint32 # enum +try: + lp_llvm_descriptor_base = _libraries['libtinymesa_cpu.so'].lp_llvm_descriptor_base + lp_llvm_descriptor_base.restype = LLVMValueRef + lp_llvm_descriptor_base.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef, LLVMValueRef, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_llvm_buffer_base = _libraries['libtinymesa_cpu.so'].lp_llvm_buffer_base + lp_llvm_buffer_base.restype = LLVMValueRef + lp_llvm_buffer_base.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef, LLVMValueRef, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_llvm_buffer_num_elements = _libraries['libtinymesa_cpu.so'].lp_llvm_buffer_num_elements + lp_llvm_buffer_num_elements.restype = LLVMValueRef + lp_llvm_buffer_num_elements.argtypes = [ctypes.POINTER(struct_gallivm_state), LLVMValueRef, LLVMValueRef, ctypes.c_uint32] +except AttributeError: + pass + +# values for enumeration 'c__Ea_LP_JIT_TEXTURE_BASE' +c__Ea_LP_JIT_TEXTURE_BASE__enumvalues = { + 0: 'LP_JIT_TEXTURE_BASE', + 1: 'LP_JIT_TEXTURE_WIDTH', + 2: 'LP_JIT_TEXTURE_HEIGHT', + 3: 'LP_JIT_TEXTURE_DEPTH', + 4: 'LP_JIT_TEXTURE_ROW_STRIDE', + 5: 'LP_JIT_TEXTURE_IMG_STRIDE', + 6: 'LP_JIT_TEXTURE_FIRST_LEVEL', + 7: 'LP_JIT_TEXTURE_LAST_LEVEL', + 8: 'LP_JIT_TEXTURE_MIP_OFFSETS', + 9: 'LP_JIT_SAMPLER_INDEX_DUMMY', + 10: 'LP_JIT_TEXTURE_NUM_FIELDS', +} +LP_JIT_TEXTURE_BASE = 0 +LP_JIT_TEXTURE_WIDTH = 1 +LP_JIT_TEXTURE_HEIGHT = 2 +LP_JIT_TEXTURE_DEPTH = 3 +LP_JIT_TEXTURE_ROW_STRIDE = 4 +LP_JIT_TEXTURE_IMG_STRIDE = 5 +LP_JIT_TEXTURE_FIRST_LEVEL = 6 +LP_JIT_TEXTURE_LAST_LEVEL = 7 +LP_JIT_TEXTURE_MIP_OFFSETS = 8 +LP_JIT_SAMPLER_INDEX_DUMMY = 9 +LP_JIT_TEXTURE_NUM_FIELDS = 10 +c__Ea_LP_JIT_TEXTURE_BASE = ctypes.c_uint32 # enum +class struct_lp_jit_sampler(Structure): + pass + +struct_lp_jit_sampler._pack_ = 1 # source:False +struct_lp_jit_sampler._fields_ = [ + ('min_lod', ctypes.c_float), + ('max_lod', ctypes.c_float), + ('lod_bias', ctypes.c_float), + ('border_color', ctypes.c_float * 4), +] + + +# values for enumeration 'c__Ea_LP_JIT_SAMPLER_MIN_LOD' +c__Ea_LP_JIT_SAMPLER_MIN_LOD__enumvalues = { + 0: 'LP_JIT_SAMPLER_MIN_LOD', + 1: 'LP_JIT_SAMPLER_MAX_LOD', + 2: 'LP_JIT_SAMPLER_LOD_BIAS', + 3: 'LP_JIT_SAMPLER_BORDER_COLOR', + 4: 'LP_JIT_SAMPLER_NUM_FIELDS', +} +LP_JIT_SAMPLER_MIN_LOD = 0 +LP_JIT_SAMPLER_MAX_LOD = 1 +LP_JIT_SAMPLER_LOD_BIAS = 2 +LP_JIT_SAMPLER_BORDER_COLOR = 3 +LP_JIT_SAMPLER_NUM_FIELDS = 4 +c__Ea_LP_JIT_SAMPLER_MIN_LOD = ctypes.c_uint32 # enum +class struct_lp_jit_image(Structure): + pass + +struct_lp_jit_image._pack_ = 1 # source:False +struct_lp_jit_image._fields_ = [ + ('base', ctypes.POINTER(None)), + ('width', ctypes.c_uint32), + ('height', ctypes.c_uint16), + ('depth', ctypes.c_uint16), + ('num_samples', ctypes.c_ubyte), + ('PADDING_0', ctypes.c_ubyte * 3), + ('sample_stride', ctypes.c_uint32), + ('row_stride', ctypes.c_uint32), + ('img_stride', ctypes.c_uint32), + ('residency', ctypes.POINTER(None)), + ('base_offset', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), +] + + +# values for enumeration 'c__Ea_LP_JIT_IMAGE_BASE' +c__Ea_LP_JIT_IMAGE_BASE__enumvalues = { + 0: 'LP_JIT_IMAGE_BASE', + 1: 'LP_JIT_IMAGE_WIDTH', + 2: 'LP_JIT_IMAGE_HEIGHT', + 3: 'LP_JIT_IMAGE_DEPTH', + 4: 'LP_JIT_IMAGE_NUM_SAMPLES', + 5: 'LP_JIT_IMAGE_SAMPLE_STRIDE', + 6: 'LP_JIT_IMAGE_ROW_STRIDE', + 7: 'LP_JIT_IMAGE_IMG_STRIDE', + 8: 'LP_JIT_IMAGE_RESIDENCY', + 9: 'LP_JIT_IMAGE_BASE_OFFSET', + 10: 'LP_JIT_IMAGE_NUM_FIELDS', +} +LP_JIT_IMAGE_BASE = 0 +LP_JIT_IMAGE_WIDTH = 1 +LP_JIT_IMAGE_HEIGHT = 2 +LP_JIT_IMAGE_DEPTH = 3 +LP_JIT_IMAGE_NUM_SAMPLES = 4 +LP_JIT_IMAGE_SAMPLE_STRIDE = 5 +LP_JIT_IMAGE_ROW_STRIDE = 6 +LP_JIT_IMAGE_IMG_STRIDE = 7 +LP_JIT_IMAGE_RESIDENCY = 8 +LP_JIT_IMAGE_BASE_OFFSET = 9 +LP_JIT_IMAGE_NUM_FIELDS = 10 +c__Ea_LP_JIT_IMAGE_BASE = ctypes.c_uint32 # enum +class struct_lp_jit_resources(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('constants', struct_lp_jit_buffer * 16), + ('ssbos', struct_lp_jit_buffer * 32), + ('textures', struct_lp_jit_texture * 128), + ('samplers', struct_lp_jit_sampler * 32), + ('images', struct_lp_jit_image * 64), + ] + + +# values for enumeration 'c__Ea_LP_JIT_RES_CONSTANTS' +c__Ea_LP_JIT_RES_CONSTANTS__enumvalues = { + 0: 'LP_JIT_RES_CONSTANTS', + 1: 'LP_JIT_RES_SSBOS', + 2: 'LP_JIT_RES_TEXTURES', + 3: 'LP_JIT_RES_SAMPLERS', + 4: 'LP_JIT_RES_IMAGES', + 5: 'LP_JIT_RES_COUNT', +} +LP_JIT_RES_CONSTANTS = 0 +LP_JIT_RES_SSBOS = 1 +LP_JIT_RES_TEXTURES = 2 +LP_JIT_RES_SAMPLERS = 3 +LP_JIT_RES_IMAGES = 4 +LP_JIT_RES_COUNT = 5 +c__Ea_LP_JIT_RES_CONSTANTS = ctypes.c_uint32 # enum +try: + lp_build_jit_resources_type = _libraries['libtinymesa_cpu.so'].lp_build_jit_resources_type + lp_build_jit_resources_type.restype = LLVMTypeRef + lp_build_jit_resources_type.argtypes = [ctypes.POINTER(struct_gallivm_state)] +except AttributeError: + pass + +# values for enumeration 'c__Ea_LP_JIT_VERTEX_HEADER_VERTEX_ID' +c__Ea_LP_JIT_VERTEX_HEADER_VERTEX_ID__enumvalues = { + 0: 'LP_JIT_VERTEX_HEADER_VERTEX_ID', + 1: 'LP_JIT_VERTEX_HEADER_CLIP_POS', + 2: 'LP_JIT_VERTEX_HEADER_DATA', +} +LP_JIT_VERTEX_HEADER_VERTEX_ID = 0 +LP_JIT_VERTEX_HEADER_CLIP_POS = 1 +LP_JIT_VERTEX_HEADER_DATA = 2 +c__Ea_LP_JIT_VERTEX_HEADER_VERTEX_ID = ctypes.c_uint32 # enum +try: + lp_build_create_jit_vertex_header_type = _libraries['libtinymesa_cpu.so'].lp_build_create_jit_vertex_header_type + lp_build_create_jit_vertex_header_type.restype = LLVMTypeRef + lp_build_create_jit_vertex_header_type.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.c_int32] +except AttributeError: + pass +class struct_lp_sampler_dynamic_state(Structure): + pass + +try: + lp_build_jit_fill_sampler_dynamic_state = _libraries['libtinymesa_cpu.so'].lp_build_jit_fill_sampler_dynamic_state + lp_build_jit_fill_sampler_dynamic_state.restype = None + lp_build_jit_fill_sampler_dynamic_state.argtypes = [ctypes.POINTER(struct_lp_sampler_dynamic_state)] +except AttributeError: + pass +try: + lp_build_jit_fill_image_dynamic_state = _libraries['libtinymesa_cpu.so'].lp_build_jit_fill_image_dynamic_state + lp_build_jit_fill_image_dynamic_state.restype = None + lp_build_jit_fill_image_dynamic_state.argtypes = [ctypes.POINTER(struct_lp_sampler_dynamic_state)] +except AttributeError: + pass +try: + lp_build_sample_function_type = _libraries['libtinymesa_cpu.so'].lp_build_sample_function_type + lp_build_sample_function_type.restype = LLVMTypeRef + lp_build_sample_function_type.argtypes = [ctypes.POINTER(struct_gallivm_state), uint32_t] +except AttributeError: + pass +try: + lp_build_size_function_type = _libraries['libtinymesa_cpu.so'].lp_build_size_function_type + lp_build_size_function_type.restype = LLVMTypeRef + lp_build_size_function_type.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_lp_sampler_size_query_params)] +except AttributeError: + pass +try: + lp_build_image_function_type = _libraries['libtinymesa_cpu.so'].lp_build_image_function_type + lp_build_image_function_type.restype = LLVMTypeRef + lp_build_image_function_type.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(struct_lp_img_params), ctypes.c_bool, ctypes.c_bool] +except AttributeError: + pass +class struct_lp_texture_handle_state(Structure): + pass + +class struct_lp_static_texture_state(Structure): + pass + + +# values for enumeration 'c_uint32' +c_uint32__enumvalues = { + 0: 'PIPE_BUFFER', + 1: 'PIPE_TEXTURE_1D', + 2: 'PIPE_TEXTURE_2D', + 3: 'PIPE_TEXTURE_3D', + 4: 'PIPE_TEXTURE_CUBE', + 5: 'PIPE_TEXTURE_RECT', + 6: 'PIPE_TEXTURE_1D_ARRAY', + 7: 'PIPE_TEXTURE_2D_ARRAY', + 8: 'PIPE_TEXTURE_CUBE_ARRAY', + 9: 'PIPE_MAX_TEXTURE_TYPES', +} +PIPE_BUFFER = 0 +PIPE_TEXTURE_1D = 1 +PIPE_TEXTURE_2D = 2 +PIPE_TEXTURE_3D = 3 +PIPE_TEXTURE_CUBE = 4 +PIPE_TEXTURE_RECT = 5 +PIPE_TEXTURE_1D_ARRAY = 6 +PIPE_TEXTURE_2D_ARRAY = 7 +PIPE_TEXTURE_CUBE_ARRAY = 8 +PIPE_MAX_TEXTURE_TYPES = 9 +c_uint32 = ctypes.c_uint32 # enum +struct_lp_static_texture_state._pack_ = 1 # source:False +struct_lp_static_texture_state._fields_ = [ + ('format', pipe_format), + ('res_format', pipe_format), + ('swizzle_r', ctypes.c_uint32, 3), + ('swizzle_g', ctypes.c_uint32, 3), + ('swizzle_b', ctypes.c_uint32, 3), + ('swizzle_a', ctypes.c_uint32, 3), + ('target', c_uint32, 5), + ('res_target', c_uint32, 5), + ('pot_width', ctypes.c_uint32, 1), + ('pot_height', ctypes.c_uint32, 1), + ('pot_depth', ctypes.c_uint32, 1), + ('level_zero_only', ctypes.c_uint32, 1), + ('tiled', ctypes.c_uint32, 1), + ('tiled_samples', ctypes.c_uint32, 5), +] + +struct_lp_texture_handle_state._pack_ = 1 # source:False +struct_lp_texture_handle_state._fields_ = [ + ('static_state', struct_lp_static_texture_state), + ('PADDING_0', ctypes.c_ubyte * 4), + ('dynamic_state', struct_lp_jit_texture), +] + +class struct_lp_texture_functions(Structure): + pass + +struct_lp_texture_functions._pack_ = 1 # source:False +struct_lp_texture_functions._fields_ = [ + ('sample_functions', ctypes.POINTER(ctypes.POINTER(ctypes.POINTER(None)))), + ('sampler_count', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), + ('fetch_functions', ctypes.POINTER(ctypes.POINTER(None))), + ('size_function', ctypes.POINTER(None)), + ('samples_function', ctypes.POINTER(None)), + ('image_functions', ctypes.POINTER(ctypes.POINTER(None))), + ('state', struct_lp_texture_handle_state), + ('sampled', ctypes.c_bool), + ('storage', ctypes.c_bool), + ('PADDING_1', ctypes.c_ubyte * 6), + ('matrix', ctypes.POINTER(None)), +] + +class struct_lp_texture_handle(Structure): + pass + +struct_lp_texture_handle._pack_ = 1 # source:False +struct_lp_texture_handle._fields_ = [ + ('functions', ctypes.POINTER(None)), + ('sampler_index', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +class struct_lp_jit_bindless_texture(Structure): + pass + +struct_lp_jit_bindless_texture._pack_ = 1 # source:False +struct_lp_jit_bindless_texture._fields_ = [ + ('base', ctypes.POINTER(None)), + ('residency', ctypes.POINTER(None)), + ('sampler_index', ctypes.c_uint32), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +class struct_lp_descriptor(Structure): + pass + +class union_lp_descriptor_0(Union): + pass + +class struct_lp_descriptor_0_0(Structure): + pass + +struct_lp_descriptor_0_0._pack_ = 1 # source:False +struct_lp_descriptor_0_0._fields_ = [ + ('texture', struct_lp_jit_bindless_texture), + ('sampler', struct_lp_jit_sampler), + ('PADDING_0', ctypes.c_ubyte * 4), +] + +class struct_lp_descriptor_0_1(Structure): + _pack_ = 1 # source:False + _fields_ = [ + ('image', struct_lp_jit_image), + ] + +union_lp_descriptor_0._pack_ = 1 # source:False +union_lp_descriptor_0._anonymous_ = ('_0', '_1',) +union_lp_descriptor_0._fields_ = [ + ('_0', struct_lp_descriptor_0_0), + ('_1', struct_lp_descriptor_0_1), + ('buffer', struct_lp_jit_buffer), + ('accel_struct', ctypes.c_uint64), + ('PADDING_0', ctypes.c_ubyte * 48), +] + +struct_lp_descriptor._pack_ = 1 # source:False +struct_lp_descriptor._anonymous_ = ('_0',) +struct_lp_descriptor._fields_ = [ + ('_0', union_lp_descriptor_0), + ('functions', ctypes.POINTER(None)), +] + +try: + lp_mantissa = _libraries['libtinymesa_cpu.so'].lp_mantissa + lp_mantissa.restype = ctypes.c_uint32 + lp_mantissa.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_const_shift = _libraries['libtinymesa_cpu.so'].lp_const_shift + lp_const_shift.restype = ctypes.c_uint32 + lp_const_shift.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_const_offset = _libraries['libtinymesa_cpu.so'].lp_const_offset + lp_const_offset.restype = ctypes.c_uint32 + lp_const_offset.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_const_scale = _libraries['libtinymesa_cpu.so'].lp_const_scale + lp_const_scale.restype = ctypes.c_double + lp_const_scale.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_const_min = _libraries['libtinymesa_cpu.so'].lp_const_min + lp_const_min.restype = ctypes.c_double + lp_const_min.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_const_max = _libraries['libtinymesa_cpu.so'].lp_const_max + lp_const_max.restype = ctypes.c_double + lp_const_max.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_const_eps = _libraries['libtinymesa_cpu.so'].lp_const_eps + lp_const_eps.restype = ctypes.c_double + lp_const_eps.argtypes = [struct_lp_type] +except AttributeError: + pass +try: + lp_build_undef = _libraries['libtinymesa_cpu.so'].lp_build_undef + lp_build_undef.restype = LLVMValueRef + lp_build_undef.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_zero = _libraries['libtinymesa_cpu.so'].lp_build_zero + lp_build_zero.restype = LLVMValueRef + lp_build_zero.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_one = _libraries['libtinymesa_cpu.so'].lp_build_one + lp_build_one.restype = LLVMValueRef + lp_build_one.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_const_elem = _libraries['libtinymesa_cpu.so'].lp_build_const_elem + lp_build_const_elem.restype = LLVMValueRef + lp_build_const_elem.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type, ctypes.c_double] +except AttributeError: + pass +try: + lp_build_const_vec = _libraries['libtinymesa_cpu.so'].lp_build_const_vec + lp_build_const_vec.restype = LLVMValueRef + lp_build_const_vec.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type, ctypes.c_double] +except AttributeError: + pass +try: + lp_build_const_int_vec = _libraries['libtinymesa_cpu.so'].lp_build_const_int_vec + lp_build_const_int_vec.restype = LLVMValueRef + lp_build_const_int_vec.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type, ctypes.c_int64] +except AttributeError: + pass +try: + lp_build_const_channel_vec = _libraries['libtinymesa_cpu.so'].lp_build_const_channel_vec + lp_build_const_channel_vec.restype = LLVMValueRef + lp_build_const_channel_vec.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type] +except AttributeError: + pass +try: + lp_build_const_aos = _libraries['libtinymesa_cpu.so'].lp_build_const_aos + lp_build_const_aos.restype = LLVMValueRef + lp_build_const_aos.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type, ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.POINTER(ctypes.c_ubyte)] +except AttributeError: + pass +try: + lp_build_const_mask_aos = _libraries['libtinymesa_cpu.so'].lp_build_const_mask_aos + lp_build_const_mask_aos.restype = LLVMValueRef + lp_build_const_mask_aos.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type, ctypes.c_uint32, ctypes.c_uint32] +except AttributeError: + pass +try: + lp_build_const_mask_aos_swizzled = _libraries['libtinymesa_cpu.so'].lp_build_const_mask_aos_swizzled + lp_build_const_mask_aos_swizzled.restype = LLVMValueRef + lp_build_const_mask_aos_swizzled.argtypes = [ctypes.POINTER(struct_gallivm_state), struct_lp_type, ctypes.c_uint32, ctypes.c_uint32, ctypes.POINTER(ctypes.c_ubyte)] +except AttributeError: + pass +try: + lp_build_const_int32 = _libraries['FIXME_STUB'].lp_build_const_int32 + lp_build_const_int32.restype = LLVMValueRef + lp_build_const_int32.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.c_int32] +except AttributeError: + pass +try: + lp_build_const_int64 = _libraries['FIXME_STUB'].lp_build_const_int64 + lp_build_const_int64.restype = LLVMValueRef + lp_build_const_int64.argtypes = [ctypes.POINTER(struct_gallivm_state), int64_t] +except AttributeError: + pass +try: + lp_build_const_float = _libraries['FIXME_STUB'].lp_build_const_float + lp_build_const_float.restype = LLVMValueRef + lp_build_const_float.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.c_float] +except AttributeError: + pass +try: + lp_build_const_double = _libraries['FIXME_STUB'].lp_build_const_double + lp_build_const_double.restype = LLVMValueRef + lp_build_const_double.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.c_float] +except AttributeError: + pass +try: + lp_build_const_int_pointer = _libraries['FIXME_STUB'].lp_build_const_int_pointer + lp_build_const_int_pointer.restype = LLVMValueRef + lp_build_const_int_pointer.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(None)] +except AttributeError: + pass +try: + lp_build_const_string = _libraries['libtinymesa_cpu.so'].lp_build_const_string + lp_build_const_string.restype = LLVMValueRef + lp_build_const_string.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_build_const_func_pointer = _libraries['libtinymesa_cpu.so'].lp_build_const_func_pointer + lp_build_const_func_pointer.restype = LLVMValueRef + lp_build_const_func_pointer.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(None), LLVMTypeRef, ctypes.POINTER(ctypes.POINTER(struct_LLVMOpaqueType)), ctypes.c_uint32, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +try: + lp_build_const_func_pointer_from_type = _libraries['libtinymesa_cpu.so'].lp_build_const_func_pointer_from_type + lp_build_const_func_pointer_from_type.restype = LLVMValueRef + lp_build_const_func_pointer_from_type.argtypes = [ctypes.POINTER(struct_gallivm_state), ctypes.POINTER(None), LLVMTypeRef, ctypes.POINTER(ctypes.c_char)] +except AttributeError: + pass +__all__ = \ + ['ACCESS_CAN_REORDER', 'ACCESS_CAN_SPECULATE', 'ACCESS_COHERENT', + 'ACCESS_CP_GE_COHERENT_AMD', 'ACCESS_FMASK_LOWERED_AMD', + 'ACCESS_INCLUDE_HELPERS', 'ACCESS_IN_BOUNDS', + 'ACCESS_IS_SWIZZLED_AMD', 'ACCESS_KEEP_SCALAR', + 'ACCESS_NON_READABLE', 'ACCESS_NON_TEMPORAL', + 'ACCESS_NON_UNIFORM', 'ACCESS_NON_WRITEABLE', 'ACCESS_RESTRICT', + 'ACCESS_SMEM_AMD', 'ACCESS_USES_FORMAT_AMD', 'ACCESS_VOLATILE', + 'COMPARE_FUNC_ALWAYS', 'COMPARE_FUNC_EQUAL', + 'COMPARE_FUNC_GEQUAL', 'COMPARE_FUNC_GREATER', + 'COMPARE_FUNC_LEQUAL', 'COMPARE_FUNC_LESS', 'COMPARE_FUNC_NEVER', + 'COMPARE_FUNC_NOTEQUAL', 'DERIVATIVE_GROUP_LINEAR', + 'DERIVATIVE_GROUP_NONE', 'DERIVATIVE_GROUP_QUADS', + 'FRAG_DEPTH_LAYOUT_ANY', 'FRAG_DEPTH_LAYOUT_GREATER', + 'FRAG_DEPTH_LAYOUT_LESS', 'FRAG_DEPTH_LAYOUT_NONE', + 'FRAG_DEPTH_LAYOUT_UNCHANGED', 'FRAG_STENCIL_LAYOUT_ANY', + 'FRAG_STENCIL_LAYOUT_GREATER', 'FRAG_STENCIL_LAYOUT_LESS', + 'FRAG_STENCIL_LAYOUT_NONE', 'FRAG_STENCIL_LAYOUT_UNCHANGED', + 'GLSL_CMAT_USE_A', 'GLSL_CMAT_USE_ACCUMULATOR', 'GLSL_CMAT_USE_B', + 'GLSL_CMAT_USE_NONE', 'GLSL_INTERFACE_PACKING_PACKED', + 'GLSL_INTERFACE_PACKING_SHARED', 'GLSL_INTERFACE_PACKING_STD140', + 'GLSL_INTERFACE_PACKING_STD430', + 'GLSL_MATRIX_LAYOUT_COLUMN_MAJOR', 'GLSL_MATRIX_LAYOUT_INHERITED', + 'GLSL_MATRIX_LAYOUT_ROW_MAJOR', 'GLSL_PRECISION_HIGH', + 'GLSL_PRECISION_LOW', 'GLSL_PRECISION_MEDIUM', + 'GLSL_PRECISION_NONE', 'GLSL_SAMPLER_DIM_1D', + 'GLSL_SAMPLER_DIM_2D', 'GLSL_SAMPLER_DIM_3D', + 'GLSL_SAMPLER_DIM_BUF', 'GLSL_SAMPLER_DIM_CUBE', + 'GLSL_SAMPLER_DIM_EXTERNAL', 'GLSL_SAMPLER_DIM_MS', + 'GLSL_SAMPLER_DIM_RECT', 'GLSL_SAMPLER_DIM_SUBPASS', + 'GLSL_SAMPLER_DIM_SUBPASS_MS', 'GLSL_TYPE_ARRAY', + 'GLSL_TYPE_ATOMIC_UINT', 'GLSL_TYPE_BFLOAT16', 'GLSL_TYPE_BOOL', + 'GLSL_TYPE_COOPERATIVE_MATRIX', 'GLSL_TYPE_DOUBLE', + 'GLSL_TYPE_ERROR', 'GLSL_TYPE_FLOAT', 'GLSL_TYPE_FLOAT16', + 'GLSL_TYPE_FLOAT_E4M3FN', 'GLSL_TYPE_FLOAT_E5M2', + 'GLSL_TYPE_IMAGE', 'GLSL_TYPE_INT', 'GLSL_TYPE_INT16', + 'GLSL_TYPE_INT64', 'GLSL_TYPE_INT8', 'GLSL_TYPE_INTERFACE', + 'GLSL_TYPE_SAMPLER', 'GLSL_TYPE_STRUCT', 'GLSL_TYPE_SUBROUTINE', + 'GLSL_TYPE_TEXTURE', 'GLSL_TYPE_UINT', 'GLSL_TYPE_UINT16', + 'GLSL_TYPE_UINT64', 'GLSL_TYPE_UINT8', 'GLSL_TYPE_VOID', + 'LLVMArrayTypeKind', 'LLVMAtomicRMWBinOp', + 'LLVMAtomicRMWBinOpAdd', 'LLVMAtomicRMWBinOpAnd', + 'LLVMAtomicRMWBinOpFAdd', 'LLVMAtomicRMWBinOpFMax', + 'LLVMAtomicRMWBinOpFMin', 'LLVMAtomicRMWBinOpFSub', + 'LLVMAtomicRMWBinOpMax', 'LLVMAtomicRMWBinOpMin', + 'LLVMAtomicRMWBinOpNand', 'LLVMAtomicRMWBinOpOr', + 'LLVMAtomicRMWBinOpSub', 'LLVMAtomicRMWBinOpUDecWrap', + 'LLVMAtomicRMWBinOpUIncWrap', 'LLVMAtomicRMWBinOpUMax', + 'LLVMAtomicRMWBinOpUMin', 'LLVMAtomicRMWBinOpUSubCond', + 'LLVMAtomicRMWBinOpUSubSat', 'LLVMAtomicRMWBinOpXchg', + 'LLVMAtomicRMWBinOpXor', 'LLVMAtomicRMWBinOp__enumvalues', + 'LLVMBFloatTypeKind', 'LLVMBasicBlockRef', 'LLVMBuilderRef', + 'LLVMDoubleTypeKind', 'LLVMFP128TypeKind', 'LLVMFloatTypeKind', + 'LLVMFunctionTypeKind', 'LLVMHalfTypeKind', 'LLVMIntEQ', + 'LLVMIntNE', 'LLVMIntPredicate', 'LLVMIntPredicate__enumvalues', + 'LLVMIntSGE', 'LLVMIntSGT', 'LLVMIntSLE', 'LLVMIntSLT', + 'LLVMIntUGE', 'LLVMIntUGT', 'LLVMIntULE', 'LLVMIntULT', + 'LLVMIntegerTypeKind', 'LLVMLabelTypeKind', + 'LLVMMCJITMemoryManagerRef', 'LLVMMetadataTypeKind', + 'LLVMModuleRef', 'LLVMPPC_FP128TypeKind', 'LLVMPointerTypeKind', + 'LLVMScalableVectorTypeKind', 'LLVMStructTypeKind', + 'LLVMTargetExtTypeKind', 'LLVMTargetLibraryInfoRef', + 'LLVMTargetMachineRef', 'LLVMTokenTypeKind', 'LLVMTypeKind', + 'LLVMTypeKind__enumvalues', 'LLVMTypeRef', 'LLVMValueRef', + 'LLVMVectorTypeKind', 'LLVMVoidTypeKind', 'LLVMX86_AMXTypeKind', + 'LLVMX86_FP80TypeKind', 'LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV', + 'LP_BLD_TEX_MODIFIER_EXPLICIT_LOD', + 'LP_BLD_TEX_MODIFIER_LOD_BIAS', 'LP_BLD_TEX_MODIFIER_LOD_ZERO', + 'LP_BLD_TEX_MODIFIER_NONE', 'LP_BLD_TEX_MODIFIER_PROJECTED', + 'LP_JIT_BUFFER_BASE', 'LP_JIT_BUFFER_NUM_ELEMENTS', + 'LP_JIT_BUFFER_NUM_FIELDS', 'LP_JIT_IMAGE_BASE', + 'LP_JIT_IMAGE_BASE_OFFSET', 'LP_JIT_IMAGE_DEPTH', + 'LP_JIT_IMAGE_HEIGHT', 'LP_JIT_IMAGE_IMG_STRIDE', + 'LP_JIT_IMAGE_NUM_FIELDS', 'LP_JIT_IMAGE_NUM_SAMPLES', + 'LP_JIT_IMAGE_RESIDENCY', 'LP_JIT_IMAGE_ROW_STRIDE', + 'LP_JIT_IMAGE_SAMPLE_STRIDE', 'LP_JIT_IMAGE_WIDTH', + 'LP_JIT_RES_CONSTANTS', 'LP_JIT_RES_COUNT', 'LP_JIT_RES_IMAGES', + 'LP_JIT_RES_SAMPLERS', 'LP_JIT_RES_SSBOS', 'LP_JIT_RES_TEXTURES', + 'LP_JIT_SAMPLER_BORDER_COLOR', 'LP_JIT_SAMPLER_INDEX_DUMMY', + 'LP_JIT_SAMPLER_LOD_BIAS', 'LP_JIT_SAMPLER_MAX_LOD', + 'LP_JIT_SAMPLER_MIN_LOD', 'LP_JIT_SAMPLER_NUM_FIELDS', + 'LP_JIT_TEXTURE_BASE', 'LP_JIT_TEXTURE_DEPTH', + 'LP_JIT_TEXTURE_FIRST_LEVEL', 'LP_JIT_TEXTURE_HEIGHT', + 'LP_JIT_TEXTURE_IMG_STRIDE', 'LP_JIT_TEXTURE_LAST_LEVEL', + 'LP_JIT_TEXTURE_MIP_OFFSETS', 'LP_JIT_TEXTURE_NUM_FIELDS', + 'LP_JIT_TEXTURE_ROW_STRIDE', 'LP_JIT_TEXTURE_WIDTH', + 'LP_JIT_VERTEX_HEADER_CLIP_POS', 'LP_JIT_VERTEX_HEADER_DATA', + 'LP_JIT_VERTEX_HEADER_VERTEX_ID', + 'LP_NIR_CALL_CONTEXT_BLOCK_ID_0', + 'LP_NIR_CALL_CONTEXT_BLOCK_ID_1', + 'LP_NIR_CALL_CONTEXT_BLOCK_ID_2', + 'LP_NIR_CALL_CONTEXT_BLOCK_SIZE_0', + 'LP_NIR_CALL_CONTEXT_BLOCK_SIZE_1', + 'LP_NIR_CALL_CONTEXT_BLOCK_SIZE_2', 'LP_NIR_CALL_CONTEXT_CONTEXT', + 'LP_NIR_CALL_CONTEXT_GRID_SIZE_0', + 'LP_NIR_CALL_CONTEXT_GRID_SIZE_1', + 'LP_NIR_CALL_CONTEXT_GRID_SIZE_2', 'LP_NIR_CALL_CONTEXT_MAX_ARGS', + 'LP_NIR_CALL_CONTEXT_RESOURCES', 'LP_NIR_CALL_CONTEXT_SCRATCH', + 'LP_NIR_CALL_CONTEXT_SHARED', 'LP_NIR_CALL_CONTEXT_THREAD_ID_0', + 'LP_NIR_CALL_CONTEXT_THREAD_ID_1', + 'LP_NIR_CALL_CONTEXT_THREAD_ID_2', 'LP_NIR_CALL_CONTEXT_WORK_DIM', + 'LP_SAMPLER_LOD_PER_ELEMENT', 'LP_SAMPLER_LOD_PER_QUAD', + 'LP_SAMPLER_LOD_SCALAR', 'MESA_LOG_DEBUG', 'MESA_LOG_ERROR', + 'MESA_LOG_INFO', 'MESA_LOG_WARN', 'MESA_PRIM_COUNT', + 'MESA_PRIM_LINES', 'MESA_PRIM_LINES_ADJACENCY', + 'MESA_PRIM_LINE_LOOP', 'MESA_PRIM_LINE_STRIP', + 'MESA_PRIM_LINE_STRIP_ADJACENCY', 'MESA_PRIM_MAX', + 'MESA_PRIM_PATCHES', 'MESA_PRIM_POINTS', 'MESA_PRIM_POLYGON', + 'MESA_PRIM_QUADS', 'MESA_PRIM_QUAD_STRIP', 'MESA_PRIM_TRIANGLES', + 'MESA_PRIM_TRIANGLES_ADJACENCY', 'MESA_PRIM_TRIANGLE_FAN', + 'MESA_PRIM_TRIANGLE_STRIP', 'MESA_PRIM_TRIANGLE_STRIP_ADJACENCY', + 'MESA_PRIM_UNKNOWN', 'MESA_SHADER_ANY_HIT', + 'MESA_SHADER_CALLABLE', 'MESA_SHADER_CLOSEST_HIT', + 'MESA_SHADER_COMPUTE', 'MESA_SHADER_FRAGMENT', + 'MESA_SHADER_GEOMETRY', 'MESA_SHADER_INTERSECTION', + 'MESA_SHADER_KERNEL', 'MESA_SHADER_MESH', 'MESA_SHADER_MISS', + 'MESA_SHADER_NONE', 'MESA_SHADER_RAYGEN', 'MESA_SHADER_TASK', + 'MESA_SHADER_TESS_CTRL', 'MESA_SHADER_TESS_EVAL', + 'MESA_SHADER_VERTEX', 'NAK_TS_DOMAIN_ISOLINE', + 'NAK_TS_DOMAIN_QUAD', 'NAK_TS_DOMAIN_TRIANGLE', + 'NAK_TS_PRIMS_LINES', 'NAK_TS_PRIMS_POINTS', + 'NAK_TS_PRIMS_TRIANGLES_CCW', 'NAK_TS_PRIMS_TRIANGLES_CW', + 'NAK_TS_SPACING_FRACT_EVEN', 'NAK_TS_SPACING_FRACT_ODD', + 'NAK_TS_SPACING_INTEGER', 'NIR_CMAT_A_SIGNED', + 'NIR_CMAT_B_SIGNED', 'NIR_CMAT_C_SIGNED', + 'NIR_CMAT_RESULT_SIGNED', 'NIR_INTRINSIC_ACCESS', + 'NIR_INTRINSIC_ALIGN_MUL', 'NIR_INTRINSIC_ALIGN_OFFSET', + 'NIR_INTRINSIC_ALU_OP', 'NIR_INTRINSIC_ARG_UPPER_BOUND_U32_AMD', + 'NIR_INTRINSIC_ATOMIC_OP', 'NIR_INTRINSIC_BASE', + 'NIR_INTRINSIC_BINDING', 'NIR_INTRINSIC_BIT_SIZE', + 'NIR_INTRINSIC_CALL_IDX', 'NIR_INTRINSIC_CAN_ELIMINATE', + 'NIR_INTRINSIC_CAN_REORDER', 'NIR_INTRINSIC_CLUSTER_SIZE', + 'NIR_INTRINSIC_CMAT_DESC', 'NIR_INTRINSIC_CMAT_SIGNED_MASK', + 'NIR_INTRINSIC_COLUMN', 'NIR_INTRINSIC_COMMITTED', + 'NIR_INTRINSIC_COMPONENT', 'NIR_INTRINSIC_DESC_SET', + 'NIR_INTRINSIC_DESC_TYPE', 'NIR_INTRINSIC_DEST_BASE_TYPE', + 'NIR_INTRINSIC_DEST_TYPE', 'NIR_INTRINSIC_DIVERGENT', + 'NIR_INTRINSIC_DRIVER_LOCATION', 'NIR_INTRINSIC_DST_ACCESS', + 'NIR_INTRINSIC_DST_CMAT_DESC', 'NIR_INTRINSIC_EXECUTION_SCOPE', + 'NIR_INTRINSIC_EXPLICIT_COORD', 'NIR_INTRINSIC_FETCH_INACTIVE', + 'NIR_INTRINSIC_FLAGS', 'NIR_INTRINSIC_FMT_IDX', + 'NIR_INTRINSIC_FORMAT', 'NIR_INTRINSIC_IMAGE_ARRAY', + 'NIR_INTRINSIC_IMAGE_DIM', 'NIR_INTRINSIC_INTERP_MODE', + 'NIR_INTRINSIC_IO_SEMANTICS', 'NIR_INTRINSIC_IO_XFB', + 'NIR_INTRINSIC_IO_XFB2', 'NIR_INTRINSIC_LEGACY_FABS', + 'NIR_INTRINSIC_LEGACY_FNEG', 'NIR_INTRINSIC_LEGACY_FSAT', + 'NIR_INTRINSIC_MATRIX_LAYOUT', 'NIR_INTRINSIC_MEMORY_MODES', + 'NIR_INTRINSIC_MEMORY_SCOPE', 'NIR_INTRINSIC_MEMORY_SEMANTICS', + 'NIR_INTRINSIC_NEG_HI_AMD', 'NIR_INTRINSIC_NEG_LO_AMD', + 'NIR_INTRINSIC_NUM_ARRAY_ELEMS', 'NIR_INTRINSIC_NUM_COMPONENTS', + 'NIR_INTRINSIC_NUM_INDEX_FLAGS', 'NIR_INTRINSIC_OFFSET0', + 'NIR_INTRINSIC_OFFSET1', 'NIR_INTRINSIC_PARAM_IDX', + 'NIR_INTRINSIC_PREAMBLE_CLASS', 'NIR_INTRINSIC_QUADGROUP', + 'NIR_INTRINSIC_RANGE', 'NIR_INTRINSIC_RANGE_BASE', + 'NIR_INTRINSIC_RAY_QUERY_VALUE', 'NIR_INTRINSIC_REDUCTION_OP', + 'NIR_INTRINSIC_REPEAT_COUNT', + 'NIR_INTRINSIC_RESOURCE_ACCESS_INTEL', + 'NIR_INTRINSIC_RESOURCE_BLOCK_INTEL', + 'NIR_INTRINSIC_ROUNDING_MODE', 'NIR_INTRINSIC_SATURATE', + 'NIR_INTRINSIC_SIGN_EXTEND', 'NIR_INTRINSIC_SRC_ACCESS', + 'NIR_INTRINSIC_SRC_BASE_TYPE', 'NIR_INTRINSIC_SRC_BASE_TYPE2', + 'NIR_INTRINSIC_SRC_CMAT_DESC', 'NIR_INTRINSIC_SRC_TYPE', + 'NIR_INTRINSIC_ST64', 'NIR_INTRINSIC_STACK_SIZE', + 'NIR_INTRINSIC_STREAM_ID', 'NIR_INTRINSIC_SUBGROUP', + 'NIR_INTRINSIC_SWIZZLE_MASK', 'NIR_INTRINSIC_SYNCHRONOUS', + 'NIR_INTRINSIC_SYSTOLIC_DEPTH', 'NIR_INTRINSIC_UCP_ID', + 'NIR_INTRINSIC_VALUE_ID', 'NIR_INTRINSIC_WRITE_MASK', + 'NIR_MEMORY_ACQUIRE', 'NIR_MEMORY_ACQ_REL', + 'NIR_MEMORY_MAKE_AVAILABLE', 'NIR_MEMORY_MAKE_VISIBLE', + 'NIR_MEMORY_RELEASE', 'NIR_OP_IS_2SRC_COMMUTATIVE', + 'NIR_OP_IS_ASSOCIATIVE', 'NIR_OP_IS_SELECTION', + 'NUM_TOTAL_VARYING_SLOTS', 'NV_DEVICE_TYPE_DIS', + 'NV_DEVICE_TYPE_IGP', 'NV_DEVICE_TYPE_SOC', 'PIPE_BUFFER', + 'PIPE_FORMAT_A16_FLOAT', 'PIPE_FORMAT_A16_SINT', + 'PIPE_FORMAT_A16_SNORM', 'PIPE_FORMAT_A16_UINT', + 'PIPE_FORMAT_A16_UNORM', 'PIPE_FORMAT_A1B5G5R5_UINT', + 'PIPE_FORMAT_A1B5G5R5_UNORM', 'PIPE_FORMAT_A1R5G5B5_UINT', + 'PIPE_FORMAT_A1R5G5B5_UNORM', 'PIPE_FORMAT_A2B10G10R10_UINT', + 'PIPE_FORMAT_A2B10G10R10_UNORM', 'PIPE_FORMAT_A2R10G10B10_UINT', + 'PIPE_FORMAT_A2R10G10B10_UNORM', 'PIPE_FORMAT_A32_FLOAT', + 'PIPE_FORMAT_A32_SINT', 'PIPE_FORMAT_A32_UINT', + 'PIPE_FORMAT_A4B4G4R4_UINT', 'PIPE_FORMAT_A4B4G4R4_UNORM', + 'PIPE_FORMAT_A4R4G4B4_UINT', 'PIPE_FORMAT_A4R4G4B4_UNORM', + 'PIPE_FORMAT_A4R4_UNORM', 'PIPE_FORMAT_A8B8G8R8_SINT', + 'PIPE_FORMAT_A8B8G8R8_SNORM', 'PIPE_FORMAT_A8B8G8R8_SRGB', + 'PIPE_FORMAT_A8B8G8R8_SSCALED', 'PIPE_FORMAT_A8B8G8R8_UINT', + 'PIPE_FORMAT_A8B8G8R8_UNORM', 'PIPE_FORMAT_A8B8G8R8_USCALED', + 'PIPE_FORMAT_A8R8G8B8_SINT', 'PIPE_FORMAT_A8R8G8B8_SNORM', + 'PIPE_FORMAT_A8R8G8B8_SRGB', 'PIPE_FORMAT_A8R8G8B8_UINT', + 'PIPE_FORMAT_A8R8G8B8_UNORM', 'PIPE_FORMAT_A8R8_UNORM', + 'PIPE_FORMAT_A8_SINT', 'PIPE_FORMAT_A8_SNORM', + 'PIPE_FORMAT_A8_UINT', 'PIPE_FORMAT_A8_UNORM', + 'PIPE_FORMAT_ASTC_10x10', 'PIPE_FORMAT_ASTC_10x10_FLOAT', + 'PIPE_FORMAT_ASTC_10x10_SRGB', 'PIPE_FORMAT_ASTC_10x5', + 'PIPE_FORMAT_ASTC_10x5_FLOAT', 'PIPE_FORMAT_ASTC_10x5_SRGB', + 'PIPE_FORMAT_ASTC_10x6', 'PIPE_FORMAT_ASTC_10x6_FLOAT', + 'PIPE_FORMAT_ASTC_10x6_SRGB', 'PIPE_FORMAT_ASTC_10x8', + 'PIPE_FORMAT_ASTC_10x8_FLOAT', 'PIPE_FORMAT_ASTC_10x8_SRGB', + 'PIPE_FORMAT_ASTC_12x10', 'PIPE_FORMAT_ASTC_12x10_FLOAT', + 'PIPE_FORMAT_ASTC_12x10_SRGB', 'PIPE_FORMAT_ASTC_12x12', + 'PIPE_FORMAT_ASTC_12x12_FLOAT', 'PIPE_FORMAT_ASTC_12x12_SRGB', + 'PIPE_FORMAT_ASTC_3x3x3', 'PIPE_FORMAT_ASTC_3x3x3_SRGB', + 'PIPE_FORMAT_ASTC_4x3x3', 'PIPE_FORMAT_ASTC_4x3x3_SRGB', + 'PIPE_FORMAT_ASTC_4x4', 'PIPE_FORMAT_ASTC_4x4_FLOAT', + 'PIPE_FORMAT_ASTC_4x4_SRGB', 'PIPE_FORMAT_ASTC_4x4x3', + 'PIPE_FORMAT_ASTC_4x4x3_SRGB', 'PIPE_FORMAT_ASTC_4x4x4', + 'PIPE_FORMAT_ASTC_4x4x4_SRGB', 'PIPE_FORMAT_ASTC_5x4', + 'PIPE_FORMAT_ASTC_5x4_FLOAT', 'PIPE_FORMAT_ASTC_5x4_SRGB', + 'PIPE_FORMAT_ASTC_5x4x4', 'PIPE_FORMAT_ASTC_5x4x4_SRGB', + 'PIPE_FORMAT_ASTC_5x5', 'PIPE_FORMAT_ASTC_5x5_FLOAT', + 'PIPE_FORMAT_ASTC_5x5_SRGB', 'PIPE_FORMAT_ASTC_5x5x4', + 'PIPE_FORMAT_ASTC_5x5x4_SRGB', 'PIPE_FORMAT_ASTC_5x5x5', + 'PIPE_FORMAT_ASTC_5x5x5_SRGB', 'PIPE_FORMAT_ASTC_6x5', + 'PIPE_FORMAT_ASTC_6x5_FLOAT', 'PIPE_FORMAT_ASTC_6x5_SRGB', + 'PIPE_FORMAT_ASTC_6x5x5', 'PIPE_FORMAT_ASTC_6x5x5_SRGB', + 'PIPE_FORMAT_ASTC_6x6', 'PIPE_FORMAT_ASTC_6x6_FLOAT', + 'PIPE_FORMAT_ASTC_6x6_SRGB', 'PIPE_FORMAT_ASTC_6x6x5', + 'PIPE_FORMAT_ASTC_6x6x5_SRGB', 'PIPE_FORMAT_ASTC_6x6x6', + 'PIPE_FORMAT_ASTC_6x6x6_SRGB', 'PIPE_FORMAT_ASTC_8x5', + 'PIPE_FORMAT_ASTC_8x5_FLOAT', 'PIPE_FORMAT_ASTC_8x5_SRGB', + 'PIPE_FORMAT_ASTC_8x6', 'PIPE_FORMAT_ASTC_8x6_FLOAT', + 'PIPE_FORMAT_ASTC_8x6_SRGB', 'PIPE_FORMAT_ASTC_8x8', + 'PIPE_FORMAT_ASTC_8x8_FLOAT', 'PIPE_FORMAT_ASTC_8x8_SRGB', + 'PIPE_FORMAT_ATC_RGB', 'PIPE_FORMAT_ATC_RGBA_EXPLICIT', + 'PIPE_FORMAT_ATC_RGBA_INTERPOLATED', 'PIPE_FORMAT_AYUV', + 'PIPE_FORMAT_B10G10R10A2_SINT', 'PIPE_FORMAT_B10G10R10A2_SNORM', + 'PIPE_FORMAT_B10G10R10A2_SSCALED', 'PIPE_FORMAT_B10G10R10A2_UINT', + 'PIPE_FORMAT_B10G10R10A2_UNORM', + 'PIPE_FORMAT_B10G10R10A2_USCALED', 'PIPE_FORMAT_B10G10R10X2_SINT', + 'PIPE_FORMAT_B10G10R10X2_SNORM', 'PIPE_FORMAT_B10G10R10X2_UNORM', + 'PIPE_FORMAT_B2G3R3_UINT', 'PIPE_FORMAT_B2G3R3_UNORM', + 'PIPE_FORMAT_B4G4R4A4_UINT', 'PIPE_FORMAT_B4G4R4A4_UNORM', + 'PIPE_FORMAT_B4G4R4X4_UNORM', 'PIPE_FORMAT_B5G5R5A1_UINT', + 'PIPE_FORMAT_B5G5R5A1_UNORM', 'PIPE_FORMAT_B5G5R5X1_UNORM', + 'PIPE_FORMAT_B5G6R5_SRGB', 'PIPE_FORMAT_B5G6R5_UINT', + 'PIPE_FORMAT_B5G6R5_UNORM', 'PIPE_FORMAT_B8G8R8A8_SINT', + 'PIPE_FORMAT_B8G8R8A8_SNORM', 'PIPE_FORMAT_B8G8R8A8_SRGB', + 'PIPE_FORMAT_B8G8R8A8_SSCALED', 'PIPE_FORMAT_B8G8R8A8_UINT', + 'PIPE_FORMAT_B8G8R8A8_UNORM', 'PIPE_FORMAT_B8G8R8A8_USCALED', + 'PIPE_FORMAT_B8G8R8X8_SINT', 'PIPE_FORMAT_B8G8R8X8_SNORM', + 'PIPE_FORMAT_B8G8R8X8_SRGB', 'PIPE_FORMAT_B8G8R8X8_UINT', + 'PIPE_FORMAT_B8G8R8X8_UNORM', 'PIPE_FORMAT_B8G8R8_SINT', + 'PIPE_FORMAT_B8G8R8_SNORM', 'PIPE_FORMAT_B8G8R8_SRGB', + 'PIPE_FORMAT_B8G8R8_SSCALED', 'PIPE_FORMAT_B8G8R8_UINT', + 'PIPE_FORMAT_B8G8R8_UNORM', 'PIPE_FORMAT_B8G8R8_USCALED', + 'PIPE_FORMAT_B8G8_R8G8_UNORM', 'PIPE_FORMAT_B8R8_G8R8_UNORM', + 'PIPE_FORMAT_BPTC_RGBA_UNORM', 'PIPE_FORMAT_BPTC_RGB_FLOAT', + 'PIPE_FORMAT_BPTC_RGB_UFLOAT', 'PIPE_FORMAT_BPTC_SRGBA', + 'PIPE_FORMAT_COUNT', 'PIPE_FORMAT_DXT1_RGB', + 'PIPE_FORMAT_DXT1_RGBA', 'PIPE_FORMAT_DXT1_SRGB', + 'PIPE_FORMAT_DXT1_SRGBA', 'PIPE_FORMAT_DXT3_RGBA', + 'PIPE_FORMAT_DXT3_SRGBA', 'PIPE_FORMAT_DXT5_RGBA', + 'PIPE_FORMAT_DXT5_SRGBA', 'PIPE_FORMAT_ETC1_RGB8', + 'PIPE_FORMAT_ETC2_R11_SNORM', 'PIPE_FORMAT_ETC2_R11_UNORM', + 'PIPE_FORMAT_ETC2_RG11_SNORM', 'PIPE_FORMAT_ETC2_RG11_UNORM', + 'PIPE_FORMAT_ETC2_RGB8', 'PIPE_FORMAT_ETC2_RGB8A1', + 'PIPE_FORMAT_ETC2_RGBA8', 'PIPE_FORMAT_ETC2_SRGB8', + 'PIPE_FORMAT_ETC2_SRGB8A1', 'PIPE_FORMAT_ETC2_SRGBA8', + 'PIPE_FORMAT_FXT1_RGB', 'PIPE_FORMAT_FXT1_RGBA', + 'PIPE_FORMAT_G16R16_SINT', 'PIPE_FORMAT_G16R16_SNORM', + 'PIPE_FORMAT_G16R16_UNORM', 'PIPE_FORMAT_G8B8_G8R8_UNORM', + 'PIPE_FORMAT_G8R8_B8R8_UNORM', 'PIPE_FORMAT_G8R8_G8B8_UNORM', + 'PIPE_FORMAT_G8R8_SINT', 'PIPE_FORMAT_G8R8_SNORM', + 'PIPE_FORMAT_G8R8_UNORM', 'PIPE_FORMAT_G8_B8R8_420_UNORM', + 'PIPE_FORMAT_G8_B8R8_422_UNORM', 'PIPE_FORMAT_G8_B8_R8_420_UNORM', + 'PIPE_FORMAT_I16_FLOAT', 'PIPE_FORMAT_I16_SINT', + 'PIPE_FORMAT_I16_SNORM', 'PIPE_FORMAT_I16_UINT', + 'PIPE_FORMAT_I16_UNORM', 'PIPE_FORMAT_I32_FLOAT', + 'PIPE_FORMAT_I32_SINT', 'PIPE_FORMAT_I32_UINT', + 'PIPE_FORMAT_I8_SINT', 'PIPE_FORMAT_I8_SNORM', + 'PIPE_FORMAT_I8_UINT', 'PIPE_FORMAT_I8_UNORM', 'PIPE_FORMAT_IYUV', + 'PIPE_FORMAT_L16A16_FLOAT', 'PIPE_FORMAT_L16A16_SINT', + 'PIPE_FORMAT_L16A16_SNORM', 'PIPE_FORMAT_L16A16_UINT', + 'PIPE_FORMAT_L16A16_UNORM', 'PIPE_FORMAT_L16_FLOAT', + 'PIPE_FORMAT_L16_SINT', 'PIPE_FORMAT_L16_SNORM', + 'PIPE_FORMAT_L16_UINT', 'PIPE_FORMAT_L16_UNORM', + 'PIPE_FORMAT_L32A32_FLOAT', 'PIPE_FORMAT_L32A32_SINT', + 'PIPE_FORMAT_L32A32_UINT', 'PIPE_FORMAT_L32_FLOAT', + 'PIPE_FORMAT_L32_SINT', 'PIPE_FORMAT_L32_UINT', + 'PIPE_FORMAT_L4A4_UNORM', 'PIPE_FORMAT_L8A8_SINT', + 'PIPE_FORMAT_L8A8_SNORM', 'PIPE_FORMAT_L8A8_SRGB', + 'PIPE_FORMAT_L8A8_UINT', 'PIPE_FORMAT_L8A8_UNORM', + 'PIPE_FORMAT_L8_SINT', 'PIPE_FORMAT_L8_SNORM', + 'PIPE_FORMAT_L8_SRGB', 'PIPE_FORMAT_L8_UINT', + 'PIPE_FORMAT_L8_UNORM', 'PIPE_FORMAT_LATC1_SNORM', + 'PIPE_FORMAT_LATC1_UNORM', 'PIPE_FORMAT_LATC2_SNORM', + 'PIPE_FORMAT_LATC2_UNORM', 'PIPE_FORMAT_NONE', 'PIPE_FORMAT_NV12', + 'PIPE_FORMAT_NV15', 'PIPE_FORMAT_NV16', 'PIPE_FORMAT_NV20', + 'PIPE_FORMAT_NV21', 'PIPE_FORMAT_P010', 'PIPE_FORMAT_P012', + 'PIPE_FORMAT_P016', 'PIPE_FORMAT_P030', + 'PIPE_FORMAT_R10G10B10A2_SINT', 'PIPE_FORMAT_R10G10B10A2_SNORM', + 'PIPE_FORMAT_R10G10B10A2_SSCALED', 'PIPE_FORMAT_R10G10B10A2_UINT', + 'PIPE_FORMAT_R10G10B10A2_UNORM', + 'PIPE_FORMAT_R10G10B10A2_USCALED', 'PIPE_FORMAT_R10G10B10X2_SINT', + 'PIPE_FORMAT_R10G10B10X2_SNORM', 'PIPE_FORMAT_R10G10B10X2_UNORM', + 'PIPE_FORMAT_R10G10B10X2_USCALED', + 'PIPE_FORMAT_R10G10B10_420_UNORM_PACKED', + 'PIPE_FORMAT_R10SG10SB10SA2U_NORM', + 'PIPE_FORMAT_R10_G10B10_420_UNORM', + 'PIPE_FORMAT_R10_G10B10_422_UNORM', 'PIPE_FORMAT_R11G11B10_FLOAT', + 'PIPE_FORMAT_R16A16_FLOAT', 'PIPE_FORMAT_R16A16_SINT', + 'PIPE_FORMAT_R16A16_SNORM', 'PIPE_FORMAT_R16A16_UINT', + 'PIPE_FORMAT_R16A16_UNORM', 'PIPE_FORMAT_R16G16B16A16_FLOAT', + 'PIPE_FORMAT_R16G16B16A16_SINT', 'PIPE_FORMAT_R16G16B16A16_SNORM', + 'PIPE_FORMAT_R16G16B16A16_SSCALED', + 'PIPE_FORMAT_R16G16B16A16_UINT', 'PIPE_FORMAT_R16G16B16A16_UNORM', + 'PIPE_FORMAT_R16G16B16A16_USCALED', + 'PIPE_FORMAT_R16G16B16X16_FLOAT', 'PIPE_FORMAT_R16G16B16X16_SINT', + 'PIPE_FORMAT_R16G16B16X16_SNORM', 'PIPE_FORMAT_R16G16B16X16_UINT', + 'PIPE_FORMAT_R16G16B16X16_UNORM', 'PIPE_FORMAT_R16G16B16_FLOAT', + 'PIPE_FORMAT_R16G16B16_SINT', 'PIPE_FORMAT_R16G16B16_SNORM', + 'PIPE_FORMAT_R16G16B16_SSCALED', 'PIPE_FORMAT_R16G16B16_UINT', + 'PIPE_FORMAT_R16G16B16_UNORM', 'PIPE_FORMAT_R16G16B16_USCALED', + 'PIPE_FORMAT_R16G16_FLOAT', 'PIPE_FORMAT_R16G16_SINT', + 'PIPE_FORMAT_R16G16_SNORM', 'PIPE_FORMAT_R16G16_SSCALED', + 'PIPE_FORMAT_R16G16_UINT', 'PIPE_FORMAT_R16G16_UNORM', + 'PIPE_FORMAT_R16G16_USCALED', 'PIPE_FORMAT_R16_FLOAT', + 'PIPE_FORMAT_R16_SINT', 'PIPE_FORMAT_R16_SNORM', + 'PIPE_FORMAT_R16_SSCALED', 'PIPE_FORMAT_R16_UINT', + 'PIPE_FORMAT_R16_UNORM', 'PIPE_FORMAT_R16_USCALED', + 'PIPE_FORMAT_R1_UNORM', 'PIPE_FORMAT_R32A32_FLOAT', + 'PIPE_FORMAT_R32A32_SINT', 'PIPE_FORMAT_R32A32_UINT', + 'PIPE_FORMAT_R32G32B32A32_FIXED', + 'PIPE_FORMAT_R32G32B32A32_FLOAT', 'PIPE_FORMAT_R32G32B32A32_SINT', + 'PIPE_FORMAT_R32G32B32A32_SNORM', + 'PIPE_FORMAT_R32G32B32A32_SSCALED', + 'PIPE_FORMAT_R32G32B32A32_UINT', 'PIPE_FORMAT_R32G32B32A32_UNORM', + 'PIPE_FORMAT_R32G32B32A32_USCALED', + 'PIPE_FORMAT_R32G32B32X32_FLOAT', 'PIPE_FORMAT_R32G32B32X32_SINT', + 'PIPE_FORMAT_R32G32B32X32_UINT', 'PIPE_FORMAT_R32G32B32_FIXED', + 'PIPE_FORMAT_R32G32B32_FLOAT', 'PIPE_FORMAT_R32G32B32_SINT', + 'PIPE_FORMAT_R32G32B32_SNORM', 'PIPE_FORMAT_R32G32B32_SSCALED', + 'PIPE_FORMAT_R32G32B32_UINT', 'PIPE_FORMAT_R32G32B32_UNORM', + 'PIPE_FORMAT_R32G32B32_USCALED', 'PIPE_FORMAT_R32G32_FIXED', + 'PIPE_FORMAT_R32G32_FLOAT', 'PIPE_FORMAT_R32G32_SINT', + 'PIPE_FORMAT_R32G32_SNORM', 'PIPE_FORMAT_R32G32_SSCALED', + 'PIPE_FORMAT_R32G32_UINT', 'PIPE_FORMAT_R32G32_UNORM', + 'PIPE_FORMAT_R32G32_USCALED', 'PIPE_FORMAT_R32_FIXED', + 'PIPE_FORMAT_R32_FLOAT', 'PIPE_FORMAT_R32_SINT', + 'PIPE_FORMAT_R32_SNORM', 'PIPE_FORMAT_R32_SSCALED', + 'PIPE_FORMAT_R32_UINT', 'PIPE_FORMAT_R32_UNORM', + 'PIPE_FORMAT_R32_USCALED', 'PIPE_FORMAT_R3G3B2_UINT', + 'PIPE_FORMAT_R3G3B2_UNORM', 'PIPE_FORMAT_R4A4_UNORM', + 'PIPE_FORMAT_R4G4B4A4_UINT', 'PIPE_FORMAT_R4G4B4A4_UNORM', + 'PIPE_FORMAT_R4G4B4X4_UNORM', 'PIPE_FORMAT_R5G5B5A1_UINT', + 'PIPE_FORMAT_R5G5B5A1_UNORM', 'PIPE_FORMAT_R5G5B5X1_UNORM', + 'PIPE_FORMAT_R5G6B5_SRGB', 'PIPE_FORMAT_R5G6B5_UINT', + 'PIPE_FORMAT_R5G6B5_UNORM', 'PIPE_FORMAT_R5SG5SB6U_NORM', + 'PIPE_FORMAT_R64G64B64A64_FLOAT', 'PIPE_FORMAT_R64G64B64A64_SINT', + 'PIPE_FORMAT_R64G64B64A64_UINT', 'PIPE_FORMAT_R64G64B64_FLOAT', + 'PIPE_FORMAT_R64G64B64_SINT', 'PIPE_FORMAT_R64G64B64_UINT', + 'PIPE_FORMAT_R64G64_FLOAT', 'PIPE_FORMAT_R64G64_SINT', + 'PIPE_FORMAT_R64G64_UINT', 'PIPE_FORMAT_R64_FLOAT', + 'PIPE_FORMAT_R64_SINT', 'PIPE_FORMAT_R64_UINT', + 'PIPE_FORMAT_R8A8_SINT', 'PIPE_FORMAT_R8A8_SNORM', + 'PIPE_FORMAT_R8A8_UINT', 'PIPE_FORMAT_R8A8_UNORM', + 'PIPE_FORMAT_R8B8_R8G8_UNORM', 'PIPE_FORMAT_R8G8B8A8_SINT', + 'PIPE_FORMAT_R8G8B8A8_SNORM', 'PIPE_FORMAT_R8G8B8A8_SRGB', + 'PIPE_FORMAT_R8G8B8A8_SSCALED', 'PIPE_FORMAT_R8G8B8A8_UINT', + 'PIPE_FORMAT_R8G8B8A8_UNORM', 'PIPE_FORMAT_R8G8B8A8_USCALED', + 'PIPE_FORMAT_R8G8B8X8_SINT', 'PIPE_FORMAT_R8G8B8X8_SNORM', + 'PIPE_FORMAT_R8G8B8X8_SRGB', 'PIPE_FORMAT_R8G8B8X8_UINT', + 'PIPE_FORMAT_R8G8B8X8_UNORM', + 'PIPE_FORMAT_R8G8B8_420_UNORM_PACKED', 'PIPE_FORMAT_R8G8B8_SINT', + 'PIPE_FORMAT_R8G8B8_SNORM', 'PIPE_FORMAT_R8G8B8_SRGB', + 'PIPE_FORMAT_R8G8B8_SSCALED', 'PIPE_FORMAT_R8G8B8_UINT', + 'PIPE_FORMAT_R8G8B8_UNORM', 'PIPE_FORMAT_R8G8B8_USCALED', + 'PIPE_FORMAT_R8G8Bx_SNORM', 'PIPE_FORMAT_R8G8_B8G8_UNORM', + 'PIPE_FORMAT_R8G8_R8B8_UNORM', 'PIPE_FORMAT_R8G8_SINT', + 'PIPE_FORMAT_R8G8_SNORM', 'PIPE_FORMAT_R8G8_SRGB', + 'PIPE_FORMAT_R8G8_SSCALED', 'PIPE_FORMAT_R8G8_UINT', + 'PIPE_FORMAT_R8G8_UNORM', 'PIPE_FORMAT_R8G8_USCALED', + 'PIPE_FORMAT_R8SG8SB8UX8U_NORM', 'PIPE_FORMAT_R8_B8G8_420_UNORM', + 'PIPE_FORMAT_R8_B8G8_422_UNORM', 'PIPE_FORMAT_R8_B8_G8_420_UNORM', + 'PIPE_FORMAT_R8_G8B8_420_UNORM', 'PIPE_FORMAT_R8_G8B8_422_UNORM', + 'PIPE_FORMAT_R8_G8_B8_420_UNORM', 'PIPE_FORMAT_R8_G8_B8_UNORM', + 'PIPE_FORMAT_R8_SINT', 'PIPE_FORMAT_R8_SNORM', + 'PIPE_FORMAT_R8_SRGB', 'PIPE_FORMAT_R8_SSCALED', + 'PIPE_FORMAT_R8_UINT', 'PIPE_FORMAT_R8_UNORM', + 'PIPE_FORMAT_R8_USCALED', 'PIPE_FORMAT_R9G9B9E5_FLOAT', + 'PIPE_FORMAT_RGTC1_SNORM', 'PIPE_FORMAT_RGTC1_UNORM', + 'PIPE_FORMAT_RGTC2_SNORM', 'PIPE_FORMAT_RGTC2_UNORM', + 'PIPE_FORMAT_S8X24_UINT', 'PIPE_FORMAT_S8_UINT', + 'PIPE_FORMAT_S8_UINT_Z24_UNORM', 'PIPE_FORMAT_UYVY', + 'PIPE_FORMAT_VYUY', 'PIPE_FORMAT_X1B5G5R5_UNORM', + 'PIPE_FORMAT_X1R5G5B5_UNORM', 'PIPE_FORMAT_X24S8_UINT', + 'PIPE_FORMAT_X32_S8X24_UINT', + 'PIPE_FORMAT_X4G12_X4B12X4R12_420_UNORM', + 'PIPE_FORMAT_X4R12X4G12_UNORM', 'PIPE_FORMAT_X4R12_UNORM', + 'PIPE_FORMAT_X6G10_X6B10X6R10_420_UNORM', + 'PIPE_FORMAT_X6R10X6G10_UNORM', 'PIPE_FORMAT_X6R10_UNORM', + 'PIPE_FORMAT_X8B8G8R8_SINT', 'PIPE_FORMAT_X8B8G8R8_SNORM', + 'PIPE_FORMAT_X8B8G8R8_SRGB', 'PIPE_FORMAT_X8B8G8R8_UNORM', + 'PIPE_FORMAT_X8R8G8B8_SINT', 'PIPE_FORMAT_X8R8G8B8_SNORM', + 'PIPE_FORMAT_X8R8G8B8_SRGB', 'PIPE_FORMAT_X8R8G8B8_UNORM', + 'PIPE_FORMAT_X8Z24_UNORM', 'PIPE_FORMAT_XYUV', + 'PIPE_FORMAT_Y10U10V10_420_UNORM_PACKED', + 'PIPE_FORMAT_Y10X6_U10X6_V10X6_420_UNORM', + 'PIPE_FORMAT_Y10X6_U10X6_V10X6_422_UNORM', + 'PIPE_FORMAT_Y10X6_U10X6_V10X6_444_UNORM', + 'PIPE_FORMAT_Y12X4_U12X4_V12X4_420_UNORM', + 'PIPE_FORMAT_Y12X4_U12X4_V12X4_422_UNORM', + 'PIPE_FORMAT_Y12X4_U12X4_V12X4_444_UNORM', + 'PIPE_FORMAT_Y16_U16V16_422_UNORM', + 'PIPE_FORMAT_Y16_U16_V16_420_UNORM', + 'PIPE_FORMAT_Y16_U16_V16_422_UNORM', + 'PIPE_FORMAT_Y16_U16_V16_444_UNORM', 'PIPE_FORMAT_Y210', + 'PIPE_FORMAT_Y212', 'PIPE_FORMAT_Y216', 'PIPE_FORMAT_Y410', + 'PIPE_FORMAT_Y412', 'PIPE_FORMAT_Y416', + 'PIPE_FORMAT_Y8U8V8_420_UNORM_PACKED', 'PIPE_FORMAT_Y8_400_UNORM', + 'PIPE_FORMAT_Y8_U8_V8_422_UNORM', + 'PIPE_FORMAT_Y8_U8_V8_440_UNORM', + 'PIPE_FORMAT_Y8_U8_V8_444_UNORM', 'PIPE_FORMAT_Y8_UNORM', + 'PIPE_FORMAT_YUYV', 'PIPE_FORMAT_YV12', 'PIPE_FORMAT_YV16', + 'PIPE_FORMAT_YVYU', 'PIPE_FORMAT_Z16_UNORM', + 'PIPE_FORMAT_Z16_UNORM_S8_UINT', 'PIPE_FORMAT_Z24X8_UNORM', + 'PIPE_FORMAT_Z24_UNORM_S8_UINT', + 'PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8', + 'PIPE_FORMAT_Z32_FLOAT', 'PIPE_FORMAT_Z32_FLOAT_S8X24_UINT', + 'PIPE_FORMAT_Z32_UNORM', 'PIPE_MAX_TEXTURE_TYPES', + 'PIPE_SHADER_COMPUTE', 'PIPE_SHADER_FRAGMENT', + 'PIPE_SHADER_GEOMETRY', 'PIPE_SHADER_MESH', + 'PIPE_SHADER_MESH_TYPES', 'PIPE_SHADER_TASK', + 'PIPE_SHADER_TESS_CTRL', 'PIPE_SHADER_TESS_EVAL', + 'PIPE_SHADER_TYPES', 'PIPE_SHADER_VERTEX', 'PIPE_TEXTURE_1D', + 'PIPE_TEXTURE_1D_ARRAY', 'PIPE_TEXTURE_2D', + 'PIPE_TEXTURE_2D_ARRAY', 'PIPE_TEXTURE_3D', 'PIPE_TEXTURE_CUBE', + 'PIPE_TEXTURE_CUBE_ARRAY', 'PIPE_TEXTURE_RECT', + 'RALLOC_PRINT_INFO_SUMMARY_ONLY', 'SCOPE_DEVICE', + 'SCOPE_INVOCATION', 'SCOPE_NONE', 'SCOPE_QUEUE_FAMILY', + 'SCOPE_SHADER_CALL', 'SCOPE_SUBGROUP', 'SCOPE_WORKGROUP', + 'SUBGROUP_SIZE_API_CONSTANT', 'SUBGROUP_SIZE_FULL_SUBGROUPS', + 'SUBGROUP_SIZE_REQUIRE_128', 'SUBGROUP_SIZE_REQUIRE_16', + 'SUBGROUP_SIZE_REQUIRE_32', 'SUBGROUP_SIZE_REQUIRE_4', + 'SUBGROUP_SIZE_REQUIRE_64', 'SUBGROUP_SIZE_REQUIRE_8', + 'SUBGROUP_SIZE_UNIFORM', 'SUBGROUP_SIZE_VARYING', + 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID', + 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_COORD', + 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL', + 'SYSTEM_VALUE_BARYCENTRIC_LINEAR_SAMPLE', + 'SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTER_RHW', + 'SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID', + 'SYSTEM_VALUE_BARYCENTRIC_PERSP_COORD', + 'SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL', + 'SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE', + 'SYSTEM_VALUE_BARYCENTRIC_PULL_MODEL', + 'SYSTEM_VALUE_BASE_GLOBAL_INVOCATION_ID', + 'SYSTEM_VALUE_BASE_INSTANCE', 'SYSTEM_VALUE_BASE_VERTEX', + 'SYSTEM_VALUE_BASE_WORKGROUP_ID', + 'SYSTEM_VALUE_COALESCED_INPUT_COUNT', 'SYSTEM_VALUE_COLOR0', + 'SYSTEM_VALUE_COLOR1', 'SYSTEM_VALUE_CULL_MASK', + 'SYSTEM_VALUE_DEVICE_INDEX', 'SYSTEM_VALUE_DRAW_ID', + 'SYSTEM_VALUE_FIRST_VERTEX', 'SYSTEM_VALUE_FRAG_COORD', + 'SYSTEM_VALUE_FRAG_COORD_W', 'SYSTEM_VALUE_FRAG_COORD_Z', + 'SYSTEM_VALUE_FRAG_INVOCATION_COUNT', + 'SYSTEM_VALUE_FRAG_SHADING_RATE', 'SYSTEM_VALUE_FRAG_SIZE', + 'SYSTEM_VALUE_FRONT_FACE', 'SYSTEM_VALUE_FRONT_FACE_FSIGN', + 'SYSTEM_VALUE_FULLY_COVERED', 'SYSTEM_VALUE_GLOBAL_GROUP_SIZE', + 'SYSTEM_VALUE_GLOBAL_INVOCATION_ID', + 'SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX', + 'SYSTEM_VALUE_GS_HEADER_IR3', 'SYSTEM_VALUE_HELPER_INVOCATION', + 'SYSTEM_VALUE_INSTANCE_ID', 'SYSTEM_VALUE_INSTANCE_INDEX', + 'SYSTEM_VALUE_INVOCATION_ID', 'SYSTEM_VALUE_IS_INDEXED_DRAW', + 'SYSTEM_VALUE_LAYER_ID', 'SYSTEM_VALUE_LINE_COORD', + 'SYSTEM_VALUE_LOCAL_INVOCATION_ID', + 'SYSTEM_VALUE_LOCAL_INVOCATION_INDEX', 'SYSTEM_VALUE_MAX', + 'SYSTEM_VALUE_MESH_VIEW_COUNT', 'SYSTEM_VALUE_MESH_VIEW_INDICES', + 'SYSTEM_VALUE_NUM_SUBGROUPS', 'SYSTEM_VALUE_NUM_WORKGROUPS', + 'SYSTEM_VALUE_PIXEL_COORD', 'SYSTEM_VALUE_POINT_COORD', + 'SYSTEM_VALUE_PRIMITIVE_ID', 'SYSTEM_VALUE_RAY_FLAGS', + 'SYSTEM_VALUE_RAY_GEOMETRY_INDEX', 'SYSTEM_VALUE_RAY_HIT_KIND', + 'SYSTEM_VALUE_RAY_INSTANCE_CUSTOM_INDEX', + 'SYSTEM_VALUE_RAY_LAUNCH_ID', 'SYSTEM_VALUE_RAY_LAUNCH_SIZE', + 'SYSTEM_VALUE_RAY_OBJECT_DIRECTION', + 'SYSTEM_VALUE_RAY_OBJECT_ORIGIN', + 'SYSTEM_VALUE_RAY_OBJECT_TO_WORLD', + 'SYSTEM_VALUE_RAY_TRIANGLE_VERTEX_POSITIONS', + 'SYSTEM_VALUE_RAY_T_MAX', 'SYSTEM_VALUE_RAY_T_MIN', + 'SYSTEM_VALUE_RAY_WORLD_DIRECTION', + 'SYSTEM_VALUE_RAY_WORLD_ORIGIN', + 'SYSTEM_VALUE_RAY_WORLD_TO_OBJECT', + 'SYSTEM_VALUE_REL_PATCH_ID_IR3', 'SYSTEM_VALUE_SAMPLE_ID', + 'SYSTEM_VALUE_SAMPLE_MASK_IN', 'SYSTEM_VALUE_SAMPLE_POS', + 'SYSTEM_VALUE_SAMPLE_POS_OR_CENTER', 'SYSTEM_VALUE_SHADER_INDEX', + 'SYSTEM_VALUE_SM_COUNT_NV', 'SYSTEM_VALUE_SM_ID_NV', + 'SYSTEM_VALUE_SUBGROUP_EQ_MASK', 'SYSTEM_VALUE_SUBGROUP_GE_MASK', + 'SYSTEM_VALUE_SUBGROUP_GT_MASK', 'SYSTEM_VALUE_SUBGROUP_ID', + 'SYSTEM_VALUE_SUBGROUP_INVOCATION', + 'SYSTEM_VALUE_SUBGROUP_LE_MASK', 'SYSTEM_VALUE_SUBGROUP_LT_MASK', + 'SYSTEM_VALUE_SUBGROUP_SIZE', 'SYSTEM_VALUE_TCS_HEADER_IR3', + 'SYSTEM_VALUE_TESS_COORD', 'SYSTEM_VALUE_TESS_LEVEL_INNER', + 'SYSTEM_VALUE_TESS_LEVEL_INNER_DEFAULT', + 'SYSTEM_VALUE_TESS_LEVEL_OUTER', + 'SYSTEM_VALUE_TESS_LEVEL_OUTER_DEFAULT', + 'SYSTEM_VALUE_USER_DATA_AMD', 'SYSTEM_VALUE_VERTEX_CNT', + 'SYSTEM_VALUE_VERTEX_ID', 'SYSTEM_VALUE_VERTEX_ID_ZERO_BASE', + 'SYSTEM_VALUE_VERTICES_IN', 'SYSTEM_VALUE_VIEW_INDEX', + 'SYSTEM_VALUE_WARPS_PER_SM_NV', 'SYSTEM_VALUE_WARP_ID_NV', + 'SYSTEM_VALUE_WORKGROUP_ID', 'SYSTEM_VALUE_WORKGROUP_INDEX', + 'SYSTEM_VALUE_WORKGROUP_SIZE', 'SYSTEM_VALUE_WORK_DIM', + 'TESS_PRIMITIVE_ISOLINES', 'TESS_PRIMITIVE_QUADS', + 'TESS_PRIMITIVE_TRIANGLES', 'TESS_PRIMITIVE_UNSPECIFIED', + 'TGSI_TEXTURE_1D', 'TGSI_TEXTURE_1D_ARRAY', 'TGSI_TEXTURE_2D', + 'TGSI_TEXTURE_2D_ARRAY', 'TGSI_TEXTURE_2D_ARRAY_MSAA', + 'TGSI_TEXTURE_2D_MSAA', 'TGSI_TEXTURE_3D', 'TGSI_TEXTURE_BUFFER', + 'TGSI_TEXTURE_COUNT', 'TGSI_TEXTURE_CUBE', + 'TGSI_TEXTURE_CUBE_ARRAY', 'TGSI_TEXTURE_RECT', + 'TGSI_TEXTURE_SHADOW1D', 'TGSI_TEXTURE_SHADOW1D_ARRAY', + 'TGSI_TEXTURE_SHADOW2D', 'TGSI_TEXTURE_SHADOW2D_ARRAY', + 'TGSI_TEXTURE_SHADOWCUBE', 'TGSI_TEXTURE_SHADOWCUBE_ARRAY', + 'TGSI_TEXTURE_SHADOWRECT', 'TGSI_TEXTURE_UNKNOWN', + 'UTIL_FORMAT_COLORSPACE_RGB', 'UTIL_FORMAT_COLORSPACE_SRGB', + 'UTIL_FORMAT_COLORSPACE_YUV', 'UTIL_FORMAT_COLORSPACE_ZS', + 'UTIL_FORMAT_LAYOUT_ASTC', 'UTIL_FORMAT_LAYOUT_ATC', + 'UTIL_FORMAT_LAYOUT_BPTC', 'UTIL_FORMAT_LAYOUT_ETC', + 'UTIL_FORMAT_LAYOUT_FXT1', 'UTIL_FORMAT_LAYOUT_OTHER', + 'UTIL_FORMAT_LAYOUT_PLAIN', 'UTIL_FORMAT_LAYOUT_PLANAR2', + 'UTIL_FORMAT_LAYOUT_PLANAR3', 'UTIL_FORMAT_LAYOUT_RGTC', + 'UTIL_FORMAT_LAYOUT_S3TC', 'UTIL_FORMAT_LAYOUT_SUBSAMPLED', + 'VARYING_SLOT_BFC0', 'VARYING_SLOT_BFC1', + 'VARYING_SLOT_BOUNDING_BOX0', 'VARYING_SLOT_BOUNDING_BOX1', + 'VARYING_SLOT_CLIP_DIST0', 'VARYING_SLOT_CLIP_DIST1', + 'VARYING_SLOT_CLIP_VERTEX', 'VARYING_SLOT_COL0', + 'VARYING_SLOT_COL1', 'VARYING_SLOT_CULL_DIST0', + 'VARYING_SLOT_CULL_DIST1', 'VARYING_SLOT_CULL_PRIMITIVE', + 'VARYING_SLOT_EDGE', 'VARYING_SLOT_FACE', 'VARYING_SLOT_FOGC', + 'VARYING_SLOT_LAYER', 'VARYING_SLOT_PATCH0', + 'VARYING_SLOT_PATCH1', 'VARYING_SLOT_PATCH10', + 'VARYING_SLOT_PATCH11', 'VARYING_SLOT_PATCH12', + 'VARYING_SLOT_PATCH13', 'VARYING_SLOT_PATCH14', + 'VARYING_SLOT_PATCH15', 'VARYING_SLOT_PATCH16', + 'VARYING_SLOT_PATCH17', 'VARYING_SLOT_PATCH18', + 'VARYING_SLOT_PATCH19', 'VARYING_SLOT_PATCH2', + 'VARYING_SLOT_PATCH20', 'VARYING_SLOT_PATCH21', + 'VARYING_SLOT_PATCH22', 'VARYING_SLOT_PATCH23', + 'VARYING_SLOT_PATCH24', 'VARYING_SLOT_PATCH25', + 'VARYING_SLOT_PATCH26', 'VARYING_SLOT_PATCH27', + 'VARYING_SLOT_PATCH28', 'VARYING_SLOT_PATCH29', + 'VARYING_SLOT_PATCH3', 'VARYING_SLOT_PATCH30', + 'VARYING_SLOT_PATCH31', 'VARYING_SLOT_PATCH4', + 'VARYING_SLOT_PATCH5', 'VARYING_SLOT_PATCH6', + 'VARYING_SLOT_PATCH7', 'VARYING_SLOT_PATCH8', + 'VARYING_SLOT_PATCH9', 'VARYING_SLOT_PNTC', 'VARYING_SLOT_POS', + 'VARYING_SLOT_PRIMITIVE_COUNT', 'VARYING_SLOT_PRIMITIVE_ID', + 'VARYING_SLOT_PRIMITIVE_INDICES', + 'VARYING_SLOT_PRIMITIVE_SHADING_RATE', 'VARYING_SLOT_PSIZ', + 'VARYING_SLOT_TASK_COUNT', 'VARYING_SLOT_TESS_LEVEL_INNER', + 'VARYING_SLOT_TESS_LEVEL_OUTER', 'VARYING_SLOT_TEX0', + 'VARYING_SLOT_TEX1', 'VARYING_SLOT_TEX2', 'VARYING_SLOT_TEX3', + 'VARYING_SLOT_TEX4', 'VARYING_SLOT_TEX5', 'VARYING_SLOT_TEX6', + 'VARYING_SLOT_TEX7', 'VARYING_SLOT_VAR0', + 'VARYING_SLOT_VAR0_16BIT', 'VARYING_SLOT_VAR1', + 'VARYING_SLOT_VAR10', 'VARYING_SLOT_VAR10_16BIT', + 'VARYING_SLOT_VAR11', 'VARYING_SLOT_VAR11_16BIT', + 'VARYING_SLOT_VAR12', 'VARYING_SLOT_VAR12_16BIT', + 'VARYING_SLOT_VAR13', 'VARYING_SLOT_VAR13_16BIT', + 'VARYING_SLOT_VAR14', 'VARYING_SLOT_VAR14_16BIT', + 'VARYING_SLOT_VAR15', 'VARYING_SLOT_VAR15_16BIT', + 'VARYING_SLOT_VAR16', 'VARYING_SLOT_VAR17', 'VARYING_SLOT_VAR18', + 'VARYING_SLOT_VAR19', 'VARYING_SLOT_VAR1_16BIT', + 'VARYING_SLOT_VAR2', 'VARYING_SLOT_VAR20', 'VARYING_SLOT_VAR21', + 'VARYING_SLOT_VAR22', 'VARYING_SLOT_VAR23', 'VARYING_SLOT_VAR24', + 'VARYING_SLOT_VAR25', 'VARYING_SLOT_VAR26', 'VARYING_SLOT_VAR27', + 'VARYING_SLOT_VAR28', 'VARYING_SLOT_VAR29', + 'VARYING_SLOT_VAR2_16BIT', 'VARYING_SLOT_VAR3', + 'VARYING_SLOT_VAR30', 'VARYING_SLOT_VAR31', + 'VARYING_SLOT_VAR3_16BIT', 'VARYING_SLOT_VAR4', + 'VARYING_SLOT_VAR4_16BIT', 'VARYING_SLOT_VAR5', + 'VARYING_SLOT_VAR5_16BIT', 'VARYING_SLOT_VAR6', + 'VARYING_SLOT_VAR6_16BIT', 'VARYING_SLOT_VAR7', + 'VARYING_SLOT_VAR7_16BIT', 'VARYING_SLOT_VAR8', + 'VARYING_SLOT_VAR8_16BIT', 'VARYING_SLOT_VAR9', + 'VARYING_SLOT_VAR9_16BIT', 'VARYING_SLOT_VIEWPORT', + 'VARYING_SLOT_VIEWPORT_MASK', 'VARYING_SLOT_VIEW_INDEX', + '_nir_mul_imm', '_nir_select_from_array_helper', + '_nir_shader_variable_has_mode', '_nir_src_set_parent', + 'blob_align', 'blob_copy_bytes', 'blob_finish', + 'blob_finish_get_buffer', 'blob_init', 'blob_init_fixed', + 'blob_overwrite_bytes', 'blob_overwrite_intptr', + 'blob_overwrite_uint32', 'blob_overwrite_uint8', + 'blob_read_bytes', 'blob_read_intptr', 'blob_read_string', + 'blob_read_uint16', 'blob_read_uint32', 'blob_read_uint64', + 'blob_read_uint8', 'blob_reader_align', 'blob_reader_init', + 'blob_reserve_bytes', 'blob_reserve_intptr', + 'blob_reserve_uint32', 'blob_skip_bytes', 'blob_write_bytes', + 'blob_write_intptr', 'blob_write_string', 'blob_write_uint16', + 'blob_write_uint32', 'blob_write_uint64', 'blob_write_uint8', + 'c__EA_LLVMAtomicRMWBinOp', 'c__EA_LLVMIntPredicate', + 'c__EA_LLVMTypeKind', 'c__EA_gl_system_value', + 'c__EA_gl_varying_slot', 'c__EA_mesa_scope', + 'c__EA_nir_address_format', 'c__EA_nir_alu_type', + 'c__EA_nir_atomic_op', 'c__EA_nir_cf_node_type', + 'c__EA_nir_cmat_signed', 'c__EA_nir_cursor_option', + 'c__EA_nir_depth_layout', + 'c__EA_nir_deref_instr_has_complex_use_options', + 'c__EA_nir_deref_type', 'c__EA_nir_divergence_options', + 'c__EA_nir_instr_type', 'c__EA_nir_intrinsic_index_flag', + 'c__EA_nir_intrinsic_op', 'c__EA_nir_intrinsic_semantic_flag', + 'c__EA_nir_io_options', 'c__EA_nir_jump_type', + 'c__EA_nir_load_grouping', 'c__EA_nir_loop_control', + 'c__EA_nir_lower_array_deref_of_vec_options', + 'c__EA_nir_lower_discard_if_options', + 'c__EA_nir_lower_doubles_options', + 'c__EA_nir_lower_fp16_cast_options', + 'c__EA_nir_lower_gs_intrinsics_flags', + 'c__EA_nir_lower_int64_options', + 'c__EA_nir_lower_interpolation_options', + 'c__EA_nir_lower_io_options', 'c__EA_nir_lower_packing_op', + 'c__EA_nir_mem_access_shift_method', 'c__EA_nir_memory_semantics', + 'c__EA_nir_metadata', 'c__EA_nir_move_options', 'c__EA_nir_op', + 'c__EA_nir_op_algebraic_property', 'c__EA_nir_opt_if_options', + 'c__EA_nir_opt_move_to_top_options', + 'c__EA_nir_opt_varyings_progress', 'c__EA_nir_preamble_class', + 'c__EA_nir_ray_query_value', 'c__EA_nir_resource_data_intel', + 'c__EA_nir_rounding_mode', 'c__EA_nir_selection_control', + 'c__EA_nir_var_declaration_type', 'c__EA_nir_variable_mode', + 'c__Ea_GLSL_PRECISION_NONE', 'c__Ea_LP_JIT_BUFFER_BASE', + 'c__Ea_LP_JIT_IMAGE_BASE', 'c__Ea_LP_JIT_RES_CONSTANTS', + 'c__Ea_LP_JIT_SAMPLER_MIN_LOD', 'c__Ea_LP_JIT_TEXTURE_BASE', + 'c__Ea_LP_JIT_VERTEX_HEADER_VERTEX_ID', + 'c__Ea_RALLOC_PRINT_INFO_SUMMARY_ONLY', 'c_bool', 'c_uint32', + 'c_uint64', 'compare_func', 'decode_type_from_blob', + 'encode_type_to_blob', 'func_pointer', + 'gallivm_add_global_mapping', 'gallivm_compile_module', + 'gallivm_create', 'gallivm_create_target_library_info', + 'gallivm_destroy', 'gallivm_dispose_target_library_info', + 'gallivm_free_ir', 'gallivm_get_perf_flags', + 'gallivm_jit_function', 'gallivm_stub_func', + 'gallivm_verify_function', 'gc_alloc_size', 'gc_context', + 'gc_ctx', 'gc_free', 'gc_get_context', 'gc_mark_live', + 'gc_sweep_end', 'gc_sweep_start', 'gc_zalloc_size', + 'gl_access_qualifier', 'gl_derivative_group', 'gl_shader_stage', + 'gl_shader_stage__enumvalues', 'gl_subgroup_size', + 'gl_system_value', 'gl_system_value__enumvalues', + 'gl_varying_slot', 'gl_varying_slot__enumvalues', + 'glsl_apply_signedness_to_base_type', 'glsl_array_size', + 'glsl_array_type', 'glsl_atomic_size', 'glsl_atomic_uint_type', + 'glsl_bare_sampler_type', 'glsl_bare_shadow_sampler_type', + 'glsl_base_type', 'glsl_base_type_bit_size', + 'glsl_base_type_get_bit_size', 'glsl_base_type_is_16bit', + 'glsl_base_type_is_64bit', 'glsl_base_type_is_float', + 'glsl_base_type_is_integer', 'glsl_bf16vec_type', + 'glsl_bfloat16_t_type', 'glsl_bfloatN_t_type', 'glsl_bool_type', + 'glsl_bvec2_type', 'glsl_bvec4_type', 'glsl_bvec_type', + 'glsl_channel_type', 'glsl_cmat_type', 'glsl_cmat_use', + 'glsl_contains_array', 'glsl_contains_atomic', + 'glsl_contains_double', 'glsl_contains_integer', + 'glsl_contains_opaque', 'glsl_contains_sampler', + 'glsl_contains_subroutine', 'glsl_count_attribute_slots', + 'glsl_count_dword_slots', 'glsl_count_vec4_slots', + 'glsl_double_type', 'glsl_dvec2_type', 'glsl_dvec4_type', + 'glsl_dvec_type', 'glsl_e4m3fn_t_type', 'glsl_e4m3fnvec_type', + 'glsl_e5m2_t_type', 'glsl_e5m2vec_type', + 'glsl_explicit_matrix_type', 'glsl_f16vec_type', + 'glsl_float16_t_type', 'glsl_float16_type', 'glsl_floatN_t_type', + 'glsl_float_type', 'glsl_get_aoa_size', 'glsl_get_array_element', + 'glsl_get_bare_type', 'glsl_get_base_glsl_type', + 'glsl_get_base_type', 'glsl_get_bit_size', + 'glsl_get_cl_alignment', 'glsl_get_cl_size', + 'glsl_get_cl_type_size_align', 'glsl_get_cmat_description', + 'glsl_get_cmat_element', 'glsl_get_column_type', + 'glsl_get_component_slots', 'glsl_get_component_slots_aligned', + 'glsl_get_components', 'glsl_get_explicit_alignment', + 'glsl_get_explicit_interface_type', 'glsl_get_explicit_size', + 'glsl_get_explicit_std140_type', 'glsl_get_explicit_std430_type', + 'glsl_get_explicit_stride', + 'glsl_get_explicit_type_for_size_align', 'glsl_get_field_index', + 'glsl_get_field_type', 'glsl_get_ifc_packing', + 'glsl_get_internal_ifc_packing', 'glsl_get_length', + 'glsl_get_matrix_columns', 'glsl_get_mul_type', + 'glsl_get_natural_size_align_bytes', 'glsl_get_row_type', + 'glsl_get_sampler_coordinate_components', 'glsl_get_sampler_dim', + 'glsl_get_sampler_dim_coordinate_components', + 'glsl_get_sampler_result_type', 'glsl_get_scalar_type', + 'glsl_get_std140_base_alignment', 'glsl_get_std140_size', + 'glsl_get_std430_array_stride', 'glsl_get_std430_base_alignment', + 'glsl_get_std430_size', 'glsl_get_struct_elem_name', + 'glsl_get_struct_field', 'glsl_get_struct_field_data', + 'glsl_get_struct_field_offset', 'glsl_get_struct_location_offset', + 'glsl_get_type_name', 'glsl_get_vec4_size_align_bytes', + 'glsl_get_vector_elements', 'glsl_get_word_size_align_bytes', + 'glsl_i16vec_type', 'glsl_i64vec_type', 'glsl_i8vec_type', + 'glsl_image_type', 'glsl_int16_t_type', 'glsl_int16_type', + 'glsl_int64_t_type', 'glsl_int8_t_type', 'glsl_intN_t_type', + 'glsl_int_type', 'glsl_interface_packing', 'glsl_interface_type', + 'glsl_ivec2_type', 'glsl_ivec4_type', 'glsl_ivec_type', + 'glsl_matrix_layout', 'glsl_matrix_type', + 'glsl_matrix_type_is_row_major', 'glsl_record_compare', + 'glsl_replace_vector_type', 'glsl_sampler_dim', + 'glsl_sampler_type', 'glsl_sampler_type_is_array', + 'glsl_sampler_type_is_shadow', 'glsl_sampler_type_to_texture', + 'glsl_scalar_type', 'glsl_signed_base_type_of', + 'glsl_simple_explicit_type', 'glsl_simple_type', + 'glsl_size_align_handle_array_and_structs', 'glsl_struct_field', + 'glsl_struct_type', 'glsl_struct_type_is_packed', + 'glsl_struct_type_with_explicit_alignment', + 'glsl_subroutine_type', 'glsl_texture_type', + 'glsl_texture_type_to_sampler', 'glsl_transposed_type', + 'glsl_type', 'glsl_type_compare_no_precision', + 'glsl_type_contains_32bit', 'glsl_type_contains_64bit', + 'glsl_type_contains_image', 'glsl_type_get_image_count', + 'glsl_type_get_sampler_count', 'glsl_type_get_texture_count', + 'glsl_type_is_16bit', 'glsl_type_is_32bit', 'glsl_type_is_64bit', + 'glsl_type_is_array', 'glsl_type_is_array_of_arrays', + 'glsl_type_is_array_or_matrix', 'glsl_type_is_atomic_uint', + 'glsl_type_is_bare_sampler', 'glsl_type_is_bfloat_16', + 'glsl_type_is_boolean', 'glsl_type_is_cmat', + 'glsl_type_is_double', 'glsl_type_is_dual_slot', + 'glsl_type_is_e4m3fn', 'glsl_type_is_e5m2', 'glsl_type_is_error', + 'glsl_type_is_float', 'glsl_type_is_float_16', + 'glsl_type_is_float_16_32', 'glsl_type_is_float_16_32_64', + 'glsl_type_is_image', 'glsl_type_is_int_16_32', + 'glsl_type_is_int_16_32_64', 'glsl_type_is_integer', + 'glsl_type_is_integer_16', 'glsl_type_is_integer_16_32', + 'glsl_type_is_integer_16_32_64', 'glsl_type_is_integer_32', + 'glsl_type_is_integer_32_64', 'glsl_type_is_integer_64', + 'glsl_type_is_interface', 'glsl_type_is_leaf', + 'glsl_type_is_matrix', 'glsl_type_is_numeric', + 'glsl_type_is_packed', 'glsl_type_is_sampler', + 'glsl_type_is_scalar', 'glsl_type_is_struct', + 'glsl_type_is_struct_or_ifc', 'glsl_type_is_subroutine', + 'glsl_type_is_texture', 'glsl_type_is_uint_16_32', + 'glsl_type_is_uint_16_32_64', 'glsl_type_is_unsized_array', + 'glsl_type_is_vector', 'glsl_type_is_vector_or_scalar', + 'glsl_type_is_void', 'glsl_type_replace_vec3_with_vec4', + 'glsl_type_singleton_decref', 'glsl_type_singleton_init_or_ref', + 'glsl_type_size_align_func', 'glsl_type_to_16bit', + 'glsl_type_uniform_locations', 'glsl_type_wrap_in_arrays', + 'glsl_u16vec_type', 'glsl_u64vec_type', 'glsl_u8vec_type', + 'glsl_uint16_t_type', 'glsl_uint16_type', 'glsl_uint64_t_type', + 'glsl_uint8_t_type', 'glsl_uintN_t_type', 'glsl_uint_type', + 'glsl_unsigned_base_type_of', 'glsl_uvec2_type', + 'glsl_uvec4_type', 'glsl_uvec_type', 'glsl_varying_count', + 'glsl_vec2_type', 'glsl_vec4_type', 'glsl_vec_type', + 'glsl_vector_type', 'glsl_void_type', 'glsl_without_array', + 'glsl_without_array_or_matrix', 'int64_t', 'intptr_t', + 'linear_alloc_child', 'linear_alloc_child_array', + 'linear_asprintf', 'linear_asprintf_append', + 'linear_asprintf_rewrite_tail', 'linear_context', + 'linear_context_with_opts', 'linear_ctx', 'linear_free_context', + 'linear_opts', 'linear_strcat', 'linear_strdup', + 'linear_vasprintf', 'linear_vasprintf_append', + 'linear_vasprintf_rewrite_tail', 'linear_zalloc_child', + 'linear_zalloc_child_array', 'lp_bld_init_native_targets', + 'lp_bld_ppc_disable_denorms', 'lp_build_alloca', + 'lp_build_alloca_undef', 'lp_build_array_alloca', + 'lp_build_array_get2', 'lp_build_array_get_ptr2', + 'lp_build_const_aos', 'lp_build_const_channel_vec', + 'lp_build_const_double', 'lp_build_const_elem', + 'lp_build_const_float', 'lp_build_const_func_pointer', + 'lp_build_const_func_pointer_from_type', 'lp_build_const_int32', + 'lp_build_const_int64', 'lp_build_const_int_pointer', + 'lp_build_const_int_vec', 'lp_build_const_mask_aos', + 'lp_build_const_mask_aos_swizzled', 'lp_build_const_string', + 'lp_build_const_vec', 'lp_build_context_init', + 'lp_build_count_ir_module', + 'lp_build_create_jit_compiler_for_module', + 'lp_build_create_jit_vertex_header_type', + 'lp_build_cs_func_call_context', 'lp_build_elem_type', + 'lp_build_else', 'lp_build_endif', 'lp_build_flow_skip_begin', + 'lp_build_flow_skip_cond_break', 'lp_build_flow_skip_end', + 'lp_build_for_loop_begin', 'lp_build_for_loop_end', 'lp_build_if', + 'lp_build_image_function_type', 'lp_build_init', + 'lp_build_init_native_width', 'lp_build_insert_new_block', + 'lp_build_int_elem_type', 'lp_build_int_vec_type', + 'lp_build_jit_fill_image_dynamic_state', + 'lp_build_jit_fill_sampler_dynamic_state', + 'lp_build_jit_resources_type', 'lp_build_loop_begin', + 'lp_build_loop_end', 'lp_build_loop_end_cond', + 'lp_build_loop_force_reload_counter', + 'lp_build_loop_force_set_counter', 'lp_build_mask_begin', + 'lp_build_mask_check', 'lp_build_mask_end', 'lp_build_mask_force', + 'lp_build_mask_update', 'lp_build_mask_value', 'lp_build_nir_aos', + 'lp_build_nir_sample_key', 'lp_build_nir_soa', + 'lp_build_nir_soa_func', 'lp_build_nir_soa_prepasses', + 'lp_build_one', 'lp_build_opt_nir', 'lp_build_pointer_get2', + 'lp_build_pointer_get_unaligned2', 'lp_build_pointer_set', + 'lp_build_pointer_set_unaligned', 'lp_build_sample_function_type', + 'lp_build_size_function_type', 'lp_build_struct_get2', + 'lp_build_struct_get_ptr2', 'lp_build_tex_modifier', + 'lp_build_undef', 'lp_build_vec_type', 'lp_build_zero', + 'lp_check_elem_type', 'lp_check_value', 'lp_check_vec_type', + 'lp_const_eps', 'lp_const_max', 'lp_const_min', 'lp_const_offset', + 'lp_const_scale', 'lp_const_shift', 'lp_context_create', + 'lp_context_destroy', 'lp_context_ref', + 'lp_create_builder_at_entry', 'lp_dump_llvmtype', 'lp_elem_type', + 'lp_float32_vec4_type', 'lp_free_generated_code', + 'lp_free_memory_manager', 'lp_free_objcache', + 'lp_get_called_value', 'lp_get_default_memory_manager', + 'lp_img_op_from_intrinsic', 'lp_init_clock_hook', + 'lp_init_env_options', 'lp_int32_vec4_type', 'lp_int_type', + 'lp_is_function', 'lp_llvm_buffer_base', + 'lp_llvm_buffer_num_elements', 'lp_llvm_descriptor_base', + 'lp_mantissa', 'lp_native_vector_width', + 'lp_nir_array_build_gather_values', 'lp_nir_call_context_args', + 'lp_packed_img_op_from_intrinsic', 'lp_passmgr_create', + 'lp_passmgr_dispose', 'lp_passmgr_run', 'lp_sampler_lod_property', + 'lp_set_module_stack_alignment_override', 'lp_set_target_options', + 'lp_sizeof_llvm_type', 'lp_translate_atomic_op', 'lp_type_fixed', + 'lp_type_float', 'lp_type_float_vec', 'lp_type_from_format', + 'lp_type_from_format_desc', 'lp_type_int', 'lp_type_int_vec', + 'lp_type_ufixed', 'lp_type_uint', 'lp_type_uint_vec', + 'lp_type_unorm', 'lp_type_width', 'lp_typekind_name', + 'lp_uint_type', 'lp_unorm8_vec4_type', 'lp_wider_type', + 'mesa_log_level', 'mesa_prim', 'mesa_scope', + 'mesa_scope__enumvalues', 'nak_compile_shader', + 'nak_compiler_create', 'nak_compiler_destroy', 'nak_debug_flags', + 'nak_fill_qmd', 'nak_get_qmd_cbuf_desc_layout', + 'nak_get_qmd_dispatch_size_layout', 'nak_nir_lower_image_addrs', + 'nak_nir_options', 'nak_postprocess_nir', 'nak_preprocess_nir', + 'nak_qmd_size_B', 'nak_shader_bin_destroy', 'nak_ts_domain', + 'nak_ts_prims', 'nak_ts_spacing', 'nir_a_minus_bc', + 'nir_add_inlinable_uniforms', 'nir_addition_might_overflow', + 'nir_address_format', 'nir_address_format_2x32bit_global', + 'nir_address_format_32bit_global', + 'nir_address_format_32bit_index_offset', + 'nir_address_format_32bit_index_offset_pack64', + 'nir_address_format_32bit_offset', + 'nir_address_format_32bit_offset_as_64bit', + 'nir_address_format_62bit_generic', + 'nir_address_format_64bit_bounded_global', + 'nir_address_format_64bit_global', + 'nir_address_format_64bit_global_32bit_offset', + 'nir_address_format__enumvalues', 'nir_address_format_bit_size', + 'nir_address_format_logical', 'nir_address_format_null_value', + 'nir_address_format_num_components', + 'nir_address_format_to_glsl_type', + 'nir_address_format_vec2_index_32bit_offset', 'nir_after_block', + 'nir_after_block_before_jump', 'nir_after_cf_list', + 'nir_after_cf_node', 'nir_after_cf_node_and_phis', + 'nir_after_impl', 'nir_after_instr', 'nir_after_instr_and_phis', + 'nir_after_phis', 'nir_after_reg_decls', 'nir_align_imm', + 'nir_alignment_deref_cast', 'nir_alu_binop_identity', + 'nir_alu_instr', 'nir_alu_instr_channel_used', + 'nir_alu_instr_clone', 'nir_alu_instr_create', + 'nir_alu_instr_is_comparison', 'nir_alu_instr_is_inf_preserve', + 'nir_alu_instr_is_nan_preserve', + 'nir_alu_instr_is_signed_zero_inf_nan_preserve', + 'nir_alu_instr_is_signed_zero_preserve', + 'nir_alu_instr_src_read_mask', 'nir_alu_pass_cb', 'nir_alu_src', + 'nir_alu_src_as_uint', 'nir_alu_src_copy', + 'nir_alu_src_is_trivial_ssa', 'nir_alu_srcs_equal', + 'nir_alu_srcs_negative_equal', + 'nir_alu_srcs_negative_equal_typed', 'nir_alu_type', + 'nir_alu_type__enumvalues', 'nir_amul_imm', + 'nir_assign_io_var_locations', 'nir_atomic_op', + 'nir_atomic_op__enumvalues', 'nir_atomic_op_cmpxchg', + 'nir_atomic_op_dec_wrap', 'nir_atomic_op_fadd', + 'nir_atomic_op_fcmpxchg', 'nir_atomic_op_fmax', + 'nir_atomic_op_fmin', 'nir_atomic_op_iadd', 'nir_atomic_op_iand', + 'nir_atomic_op_imax', 'nir_atomic_op_imin', + 'nir_atomic_op_inc_wrap', 'nir_atomic_op_ior', + 'nir_atomic_op_ixor', 'nir_atomic_op_ordered_add_gfx12_amd', + 'nir_atomic_op_to_alu', 'nir_atomic_op_type', + 'nir_atomic_op_umax', 'nir_atomic_op_umin', 'nir_atomic_op_xchg', + 'nir_b2bN', 'nir_b2fN', 'nir_b2iN', 'nir_ball', 'nir_ball_iequal', + 'nir_bany', 'nir_bany_inequal', 'nir_before_block', + 'nir_before_block_after_phis', 'nir_before_cf_list', + 'nir_before_cf_node', 'nir_before_impl', 'nir_before_instr', + 'nir_before_src', 'nir_bfdot', 'nir_binding', + 'nir_bitcast_vector', 'nir_bitfield_insert_imm', 'nir_block', + 'nir_block_cf_tree_next', 'nir_block_cf_tree_prev', + 'nir_block_contains_work', 'nir_block_create', + 'nir_block_dominates', 'nir_block_ends_in_break', + 'nir_block_ends_in_jump', 'nir_block_ends_in_return_or_halt', + 'nir_block_first_instr', 'nir_block_get_following_if', + 'nir_block_get_following_loop', + 'nir_block_get_predecessors_sorted', 'nir_block_is_reachable', + 'nir_block_is_unreachable', 'nir_block_last_instr', + 'nir_block_last_phi_instr', 'nir_block_unstructured_next', + 'nir_break_if', 'nir_build_addr_iadd', 'nir_build_addr_iadd_imm', + 'nir_build_addr_ieq', 'nir_build_addr_isub', 'nir_build_alu', + 'nir_build_alu1', 'nir_build_alu2', 'nir_build_alu3', + 'nir_build_alu4', 'nir_build_alu_src_arr', 'nir_build_call', + 'nir_build_deref_array', 'nir_build_deref_array_imm', + 'nir_build_deref_array_wildcard', 'nir_build_deref_cast', + 'nir_build_deref_cast_with_alignment', 'nir_build_deref_follower', + 'nir_build_deref_ptr_as_array', 'nir_build_deref_struct', + 'nir_build_deref_var', 'nir_build_deriv', 'nir_build_imm', + 'nir_build_indirect_call', + 'nir_build_lowered_load_helper_invocation', 'nir_build_string', + 'nir_build_tex_deref_instr', 'nir_build_write_masked_store', + 'nir_build_write_masked_stores', 'nir_builder', + 'nir_builder_alu_instr_finish_and_insert', 'nir_builder_at', + 'nir_builder_cf_insert', 'nir_builder_create', + 'nir_builder_init_simple_shader', 'nir_builder_instr_insert', + 'nir_builder_instr_insert_at_top', 'nir_builder_is_inside_cf', + 'nir_builder_last_instr', 'nir_calc_dominance', + 'nir_calc_dominance_impl', 'nir_calc_use_dominance_impl', + 'nir_call_instr', 'nir_call_instr_create', 'nir_call_serialized', + 'nir_can_lower_multiview', 'nir_can_move_instr', + 'nir_cf_list_is_empty_block', 'nir_cf_node', + 'nir_cf_node_as_block', 'nir_cf_node_as_function', + 'nir_cf_node_as_if', 'nir_cf_node_as_loop', 'nir_cf_node_block', + 'nir_cf_node_cf_tree_first', 'nir_cf_node_cf_tree_last', + 'nir_cf_node_cf_tree_next', 'nir_cf_node_cf_tree_prev', + 'nir_cf_node_function', 'nir_cf_node_get_function', + 'nir_cf_node_if', 'nir_cf_node_is_first', 'nir_cf_node_is_last', + 'nir_cf_node_loop', 'nir_cf_node_next', 'nir_cf_node_prev', + 'nir_cf_node_type', 'nir_cf_node_type__enumvalues', 'nir_channel', + 'nir_channel_or_undef', 'nir_channels', 'nir_chase_binding', + 'nir_cleanup_functions', 'nir_clear_mediump_io_flag', + 'nir_clear_shared_memory', 'nir_clone_deref_instr', + 'nir_clone_uniform_variable', 'nir_cmat_signed', + 'nir_cmat_signed__enumvalues', 'nir_collect_src_uniforms', + 'nir_combine_barrier_cb', 'nir_combined_align', + 'nir_compact_varyings', 'nir_compare_func', 'nir_component_mask', + 'nir_component_mask_can_reinterpret', + 'nir_component_mask_reinterpret', 'nir_component_mask_t', + 'nir_const_value', 'nir_const_value_as_bool', + 'nir_const_value_as_float', 'nir_const_value_as_int', + 'nir_const_value_as_uint', 'nir_const_value_for_bool', + 'nir_const_value_for_float', 'nir_const_value_for_int', + 'nir_const_value_for_raw_uint', 'nir_const_value_for_uint', + 'nir_const_value_negative_equal', 'nir_constant', + 'nir_constant_clone', 'nir_convert_from_ssa', + 'nir_convert_loop_to_lcssa', 'nir_convert_to_bit_size', + 'nir_convert_to_lcssa', 'nir_copy_deref', + 'nir_copy_deref_with_access', 'nir_copy_prop', + 'nir_copy_prop_impl', 'nir_copy_var', 'nir_create_passthrough_gs', + 'nir_create_passthrough_tcs', 'nir_create_passthrough_tcs_impl', + 'nir_create_variable_with_location', 'nir_cursor', + 'nir_cursor_after_block', 'nir_cursor_after_instr', + 'nir_cursor_before_block', 'nir_cursor_before_instr', + 'nir_cursor_current_block', 'nir_cursor_option', + 'nir_cursor_option__enumvalues', 'nir_cursors_equal', 'nir_ddx', + 'nir_ddx_coarse', 'nir_ddx_fine', 'nir_ddy', 'nir_ddy_coarse', + 'nir_ddy_fine', 'nir_debug', 'nir_debug_print_shader', + 'nir_decl_reg', 'nir_dedup_inline_samplers', 'nir_def', + 'nir_def_all_uses_are_fsat', 'nir_def_all_uses_ignore_sign_bit', + 'nir_def_components_read', 'nir_def_first_component_read', + 'nir_def_init', 'nir_def_init_for_type', + 'nir_def_is_frag_coord_z', 'nir_def_is_unused', + 'nir_def_last_component_read', 'nir_def_only_used_by_if', + 'nir_def_replace', 'nir_def_rewrite_uses', + 'nir_def_rewrite_uses_after', 'nir_def_rewrite_uses_src', + 'nir_def_used_by_if', 'nir_defs_interfere', 'nir_depth_layout', + 'nir_depth_layout__enumvalues', 'nir_depth_layout_any', + 'nir_depth_layout_greater', 'nir_depth_layout_less', + 'nir_depth_layout_none', 'nir_depth_layout_unchanged', + 'nir_deref_cast_is_trivial', 'nir_deref_count_slots', + 'nir_deref_instr', 'nir_deref_instr_array_stride', + 'nir_deref_instr_create', 'nir_deref_instr_get_variable', + 'nir_deref_instr_has_complex_use', + 'nir_deref_instr_has_complex_use_allow_atomics', + 'nir_deref_instr_has_complex_use_allow_memcpy_dst', + 'nir_deref_instr_has_complex_use_allow_memcpy_src', + 'nir_deref_instr_has_complex_use_options', + 'nir_deref_instr_has_complex_use_options__enumvalues', + 'nir_deref_instr_has_indirect', + 'nir_deref_instr_is_known_out_of_bounds', + 'nir_deref_instr_parent', 'nir_deref_instr_remove_if_unused', + 'nir_deref_mode_is', 'nir_deref_mode_is_in_set', + 'nir_deref_mode_is_one_of', 'nir_deref_mode_may_be', + 'nir_deref_mode_must_be', 'nir_deref_type', + 'nir_deref_type__enumvalues', 'nir_deref_type_array', + 'nir_deref_type_array_wildcard', 'nir_deref_type_cast', + 'nir_deref_type_ptr_as_array', 'nir_deref_type_struct', + 'nir_deref_type_var', 'nir_deserialize', + 'nir_deserialize_function', 'nir_discard', 'nir_discard_if', + 'nir_divergence_analysis', 'nir_divergence_analysis_impl', + 'nir_divergence_ignore_undef_if_phi_srcs', + 'nir_divergence_multiple_workgroup_per_compute_subgroup', + 'nir_divergence_options', 'nir_divergence_options__enumvalues', + 'nir_divergence_shader_record_ptr_uniform', + 'nir_divergence_single_frag_shading_rate_per_subgroup', + 'nir_divergence_single_patch_per_tcs_subgroup', + 'nir_divergence_single_patch_per_tes_subgroup', + 'nir_divergence_single_prim_per_subgroup', + 'nir_divergence_uniform_load_tears', + 'nir_divergence_view_index_uniform', 'nir_dominance_lca', + 'nir_dont_move_byte_word_vecs', 'nir_dump_cfg', + 'nir_dump_cfg_impl', 'nir_dump_dom_frontier', + 'nir_dump_dom_frontier_impl', 'nir_dump_dom_tree', + 'nir_dump_dom_tree_impl', 'nir_explicit_io_address_from_deref', + 'nir_extract_bits', 'nir_extract_i8_imm', 'nir_extract_u8_imm', + 'nir_f2fN', 'nir_f2iN', 'nir_f2uN', 'nir_fadd_imm', 'nir_fclamp', + 'nir_fdiv_imm', 'nir_fdot', 'nir_ffma_imm1', 'nir_ffma_imm12', + 'nir_ffma_imm2', 'nir_fgt_imm', 'nir_find_inlinable_uniforms', + 'nir_find_sampler_variable_with_tex_index', + 'nir_find_state_variable', + 'nir_find_variable_with_driver_location', + 'nir_find_variable_with_location', 'nir_first_phi_in_block', + 'nir_fixup_deref_modes', 'nir_fixup_deref_types', + 'nir_fixup_is_exported', 'nir_fle_imm', 'nir_fmul_imm', + 'nir_foreach_def_cb', 'nir_foreach_function_with_impl_first', + 'nir_foreach_function_with_impl_next', + 'nir_foreach_phi_src_leaving_block', 'nir_foreach_src', + 'nir_foreach_src_cb', 'nir_fpow_imm', + 'nir_free_output_dependencies', 'nir_fsub_imm', 'nir_function', + 'nir_function_clone', 'nir_function_create', 'nir_function_impl', + 'nir_function_impl_add_variable', 'nir_function_impl_clone', + 'nir_function_impl_clone_remap_globals', + 'nir_function_impl_create', 'nir_function_impl_create_bare', + 'nir_function_impl_index_vars', + 'nir_function_impl_lower_instructions', + 'nir_function_instructions_pass', 'nir_function_intrinsics_pass', + 'nir_function_set_impl', 'nir_gather_explicit_io_initializers', + 'nir_gather_input_to_output_dependencies', + 'nir_gather_output_clipper_var_groups', + 'nir_gather_output_dependencies', 'nir_gather_types', + 'nir_gen_rect_vertices', 'nir_get_binding_variable', + 'nir_get_explicit_deref_align', + 'nir_get_glsl_base_type_for_nir_type', + 'nir_get_immediate_use_dominator', 'nir_get_io_arrayed_index_src', + 'nir_get_io_arrayed_index_src_number', 'nir_get_io_index_src', + 'nir_get_io_index_src_number', 'nir_get_io_intrinsic', + 'nir_get_io_offset_src', 'nir_get_io_offset_src_number', + 'nir_get_live_defs', 'nir_get_nir_type_for_glsl_base_type', + 'nir_get_nir_type_for_glsl_type', 'nir_get_ptr_bitsize', + 'nir_get_rounding_mode_from_float_controls', 'nir_get_scalar', + 'nir_get_shader_call_payload_src', 'nir_get_tex_deref', + 'nir_get_tex_src', 'nir_get_variable_with_location', 'nir_goto', + 'nir_goto_if', 'nir_group_all', 'nir_group_loads', + 'nir_group_same_resource_only', + 'nir_gs_count_vertices_and_primitives', + 'nir_has_any_rounding_mode_enabled', + 'nir_has_any_rounding_mode_rtne', 'nir_has_any_rounding_mode_rtz', + 'nir_has_divergent_loop', 'nir_has_non_uniform_access', 'nir_i2b', + 'nir_i2fN', 'nir_i2iN', 'nir_iadd_imm', 'nir_iadd_imm_nuw', + 'nir_iadd_nuw', 'nir_iand_imm', 'nir_ibfe_imm', + 'nir_ibitfield_extract_imm', 'nir_iclamp', 'nir_if', + 'nir_if_create', 'nir_if_first_else_block', + 'nir_if_first_then_block', 'nir_if_last_else_block', + 'nir_if_last_then_block', 'nir_if_phi', + 'nir_image_intrinsic_coord_components', 'nir_imax_imm', + 'nir_imin_imm', 'nir_imm_bool', 'nir_imm_boolN_t', + 'nir_imm_double', 'nir_imm_false', 'nir_imm_float', + 'nir_imm_float16', 'nir_imm_floatN_t', 'nir_imm_int', + 'nir_imm_int64', 'nir_imm_intN_t', 'nir_imm_ivec2', + 'nir_imm_ivec3', 'nir_imm_ivec3_intN', 'nir_imm_ivec4', + 'nir_imm_ivec4_intN', 'nir_imm_true', 'nir_imm_uvec2_intN', + 'nir_imm_uvec3_intN', 'nir_imm_vec2', 'nir_imm_vec3', + 'nir_imm_vec4', 'nir_imm_vec4_16', 'nir_imm_zero', 'nir_imod_imm', + 'nir_impl_last_block', 'nir_imul_imm', 'nir_index_blocks', + 'nir_index_instrs', 'nir_index_ssa_defs', + 'nir_inline_function_impl', 'nir_inline_functions', + 'nir_inline_uniforms', 'nir_input_attachment_options', + 'nir_input_to_output_deps', 'nir_instr', 'nir_instr_as_alu', + 'nir_instr_as_call', 'nir_instr_as_deref', + 'nir_instr_as_intrinsic', 'nir_instr_as_jump', + 'nir_instr_as_load_const', 'nir_instr_as_parallel_copy', + 'nir_instr_as_phi', 'nir_instr_as_str', 'nir_instr_as_tex', + 'nir_instr_as_undef', 'nir_instr_clear_src', 'nir_instr_clone', + 'nir_instr_clone_deep', 'nir_instr_debug_info', 'nir_instr_def', + 'nir_instr_dominates_use', 'nir_instr_filter_cb', + 'nir_instr_free', 'nir_instr_free_and_dce', 'nir_instr_free_list', + 'nir_instr_get_debug_info', 'nir_instr_get_gc_pointer', + 'nir_instr_init_src', 'nir_instr_insert', + 'nir_instr_insert_after', 'nir_instr_insert_after_block', + 'nir_instr_insert_after_cf', 'nir_instr_insert_after_cf_list', + 'nir_instr_insert_before', 'nir_instr_insert_before_block', + 'nir_instr_insert_before_cf', 'nir_instr_insert_before_cf_list', + 'nir_instr_is_before', 'nir_instr_is_first', 'nir_instr_is_last', + 'nir_instr_move', 'nir_instr_move_src', 'nir_instr_next', + 'nir_instr_pass_cb', 'nir_instr_prev', 'nir_instr_remove', + 'nir_instr_remove_v', 'nir_instr_type', + 'nir_instr_type__enumvalues', 'nir_instr_type_alu', + 'nir_instr_type_call', 'nir_instr_type_deref', + 'nir_instr_type_intrinsic', 'nir_instr_type_jump', + 'nir_instr_type_load_const', 'nir_instr_type_parallel_copy', + 'nir_instr_type_phi', 'nir_instr_type_tex', + 'nir_instr_type_undef', 'nir_instr_writemask_filter_cb', + 'nir_instr_xfb_write_mask', 'nir_instrs_equal', + 'nir_intrin_filter_cb', 'nir_intrinsic_accept_ray_intersection', + 'nir_intrinsic_addr_mode_is', 'nir_intrinsic_al2p_nv', + 'nir_intrinsic_ald_nv', 'nir_intrinsic_align', + 'nir_intrinsic_alpha_to_coverage', 'nir_intrinsic_as_uniform', + 'nir_intrinsic_ast_nv', + 'nir_intrinsic_atomic_add_gen_prim_count_amd', + 'nir_intrinsic_atomic_add_gs_emit_prim_count_amd', + 'nir_intrinsic_atomic_add_shader_invocation_count_amd', + 'nir_intrinsic_atomic_add_xfb_prim_count_amd', + 'nir_intrinsic_atomic_counter_add', + 'nir_intrinsic_atomic_counter_add_deref', + 'nir_intrinsic_atomic_counter_and', + 'nir_intrinsic_atomic_counter_and_deref', + 'nir_intrinsic_atomic_counter_comp_swap', + 'nir_intrinsic_atomic_counter_comp_swap_deref', + 'nir_intrinsic_atomic_counter_exchange', + 'nir_intrinsic_atomic_counter_exchange_deref', + 'nir_intrinsic_atomic_counter_inc', + 'nir_intrinsic_atomic_counter_inc_deref', + 'nir_intrinsic_atomic_counter_max', + 'nir_intrinsic_atomic_counter_max_deref', + 'nir_intrinsic_atomic_counter_min', + 'nir_intrinsic_atomic_counter_min_deref', + 'nir_intrinsic_atomic_counter_or', + 'nir_intrinsic_atomic_counter_or_deref', + 'nir_intrinsic_atomic_counter_post_dec', + 'nir_intrinsic_atomic_counter_post_dec_deref', + 'nir_intrinsic_atomic_counter_pre_dec', + 'nir_intrinsic_atomic_counter_pre_dec_deref', + 'nir_intrinsic_atomic_counter_read', + 'nir_intrinsic_atomic_counter_read_deref', + 'nir_intrinsic_atomic_counter_xor', + 'nir_intrinsic_atomic_counter_xor_deref', 'nir_intrinsic_ballot', + 'nir_intrinsic_ballot_bit_count_exclusive', + 'nir_intrinsic_ballot_bit_count_inclusive', + 'nir_intrinsic_ballot_bit_count_reduce', + 'nir_intrinsic_ballot_bitfield_extract', + 'nir_intrinsic_ballot_find_lsb', 'nir_intrinsic_ballot_find_msb', + 'nir_intrinsic_ballot_relaxed', 'nir_intrinsic_bar_break_nv', + 'nir_intrinsic_bar_set_nv', 'nir_intrinsic_bar_sync_nv', + 'nir_intrinsic_barrier', + 'nir_intrinsic_begin_invocation_interlock', + 'nir_intrinsic_bindgen_return', + 'nir_intrinsic_bindless_image_agx', + 'nir_intrinsic_bindless_image_atomic', + 'nir_intrinsic_bindless_image_atomic_swap', + 'nir_intrinsic_bindless_image_descriptor_amd', + 'nir_intrinsic_bindless_image_format', + 'nir_intrinsic_bindless_image_fragment_mask_load_amd', + 'nir_intrinsic_bindless_image_levels', + 'nir_intrinsic_bindless_image_load', + 'nir_intrinsic_bindless_image_load_raw_intel', + 'nir_intrinsic_bindless_image_order', + 'nir_intrinsic_bindless_image_samples', + 'nir_intrinsic_bindless_image_samples_identical', + 'nir_intrinsic_bindless_image_size', + 'nir_intrinsic_bindless_image_sparse_load', + 'nir_intrinsic_bindless_image_store', + 'nir_intrinsic_bindless_image_store_block_agx', + 'nir_intrinsic_bindless_image_store_raw_intel', + 'nir_intrinsic_bindless_image_texel_address', + 'nir_intrinsic_bindless_resource_ir3', + 'nir_intrinsic_brcst_active_ir3', + 'nir_intrinsic_btd_retire_intel', 'nir_intrinsic_btd_spawn_intel', + 'nir_intrinsic_btd_stack_push_intel', + 'nir_intrinsic_bvh64_intersect_ray_amd', + 'nir_intrinsic_bvh8_intersect_ray_amd', + 'nir_intrinsic_bvh_stack_rtn_amd', 'nir_intrinsic_can_reorder', + 'nir_intrinsic_cmat_binary_op', 'nir_intrinsic_cmat_bitcast', + 'nir_intrinsic_cmat_construct', 'nir_intrinsic_cmat_convert', + 'nir_intrinsic_cmat_copy', 'nir_intrinsic_cmat_extract', + 'nir_intrinsic_cmat_insert', 'nir_intrinsic_cmat_length', + 'nir_intrinsic_cmat_load', 'nir_intrinsic_cmat_muladd', + 'nir_intrinsic_cmat_muladd_amd', 'nir_intrinsic_cmat_muladd_nv', + 'nir_intrinsic_cmat_scalar_op', 'nir_intrinsic_cmat_store', + 'nir_intrinsic_cmat_transpose', 'nir_intrinsic_cmat_unary_op', + 'nir_intrinsic_convert_alu_types', + 'nir_intrinsic_convert_cmat_intel', + 'nir_intrinsic_copy_const_indices', 'nir_intrinsic_copy_deref', + 'nir_intrinsic_copy_fs_outputs_nv', + 'nir_intrinsic_copy_global_to_uniform_ir3', + 'nir_intrinsic_copy_push_const_to_uniform_ir3', + 'nir_intrinsic_copy_ubo_to_uniform_ir3', 'nir_intrinsic_ddx', + 'nir_intrinsic_ddx_coarse', 'nir_intrinsic_ddx_fine', + 'nir_intrinsic_ddy', 'nir_intrinsic_ddy_coarse', + 'nir_intrinsic_ddy_fine', 'nir_intrinsic_debug_break', + 'nir_intrinsic_decl_reg', 'nir_intrinsic_demote', + 'nir_intrinsic_demote_if', 'nir_intrinsic_demote_samples', + 'nir_intrinsic_deref_atomic', 'nir_intrinsic_deref_atomic_swap', + 'nir_intrinsic_deref_buffer_array_length', + 'nir_intrinsic_deref_implicit_array_length', + 'nir_intrinsic_deref_mode_is', 'nir_intrinsic_deref_texture_src', + 'nir_intrinsic_dest_components', 'nir_intrinsic_doorbell_agx', + 'nir_intrinsic_dpas_intel', 'nir_intrinsic_dpp16_shift_amd', + 'nir_intrinsic_elect', 'nir_intrinsic_elect_any_ir3', + 'nir_intrinsic_emit_primitive_poly', 'nir_intrinsic_emit_vertex', + 'nir_intrinsic_emit_vertex_nv', + 'nir_intrinsic_emit_vertex_with_counter', + 'nir_intrinsic_end_invocation_interlock', + 'nir_intrinsic_end_primitive', 'nir_intrinsic_end_primitive_nv', + 'nir_intrinsic_end_primitive_with_counter', + 'nir_intrinsic_enqueue_node_payloads', + 'nir_intrinsic_exclusive_scan', + 'nir_intrinsic_exclusive_scan_clusters_ir3', + 'nir_intrinsic_execute_callable', + 'nir_intrinsic_execute_closest_hit_amd', + 'nir_intrinsic_execute_miss_amd', 'nir_intrinsic_export_agx', + 'nir_intrinsic_export_amd', + 'nir_intrinsic_export_dual_src_blend_amd', + 'nir_intrinsic_export_row_amd', + 'nir_intrinsic_fence_helper_exit_agx', + 'nir_intrinsic_fence_mem_to_tex_agx', + 'nir_intrinsic_fence_pbe_to_tex_agx', + 'nir_intrinsic_fence_pbe_to_tex_pixel_agx', + 'nir_intrinsic_final_primitive_nv', + 'nir_intrinsic_finalize_incoming_node_payload', + 'nir_intrinsic_first_invocation', + 'nir_intrinsic_from_system_value', 'nir_intrinsic_fs_out_nv', + 'nir_intrinsic_gds_atomic_add_amd', 'nir_intrinsic_get_ssbo_size', + 'nir_intrinsic_get_ubo_size', 'nir_intrinsic_get_var', + 'nir_intrinsic_global_atomic', 'nir_intrinsic_global_atomic_2x32', + 'nir_intrinsic_global_atomic_agx', + 'nir_intrinsic_global_atomic_amd', + 'nir_intrinsic_global_atomic_swap', + 'nir_intrinsic_global_atomic_swap_2x32', + 'nir_intrinsic_global_atomic_swap_agx', + 'nir_intrinsic_global_atomic_swap_amd', 'nir_intrinsic_has_align', + 'nir_intrinsic_has_semantic', + 'nir_intrinsic_ignore_ray_intersection', + 'nir_intrinsic_imadsp_nv', 'nir_intrinsic_image_atomic', + 'nir_intrinsic_image_atomic_swap', + 'nir_intrinsic_image_deref_atomic', + 'nir_intrinsic_image_deref_atomic_swap', + 'nir_intrinsic_image_deref_descriptor_amd', + 'nir_intrinsic_image_deref_format', + 'nir_intrinsic_image_deref_fragment_mask_load_amd', + 'nir_intrinsic_image_deref_levels', + 'nir_intrinsic_image_deref_load', + 'nir_intrinsic_image_deref_load_info_nv', + 'nir_intrinsic_image_deref_load_param_intel', + 'nir_intrinsic_image_deref_load_raw_intel', + 'nir_intrinsic_image_deref_order', + 'nir_intrinsic_image_deref_samples', + 'nir_intrinsic_image_deref_samples_identical', + 'nir_intrinsic_image_deref_size', + 'nir_intrinsic_image_deref_sparse_load', + 'nir_intrinsic_image_deref_store', + 'nir_intrinsic_image_deref_store_block_agx', + 'nir_intrinsic_image_deref_store_raw_intel', + 'nir_intrinsic_image_deref_texel_address', + 'nir_intrinsic_image_descriptor_amd', + 'nir_intrinsic_image_format', + 'nir_intrinsic_image_fragment_mask_load_amd', + 'nir_intrinsic_image_levels', 'nir_intrinsic_image_load', + 'nir_intrinsic_image_load_raw_intel', 'nir_intrinsic_image_order', + 'nir_intrinsic_image_samples', + 'nir_intrinsic_image_samples_identical', + 'nir_intrinsic_image_size', 'nir_intrinsic_image_sparse_load', + 'nir_intrinsic_image_store', + 'nir_intrinsic_image_store_block_agx', + 'nir_intrinsic_image_store_raw_intel', + 'nir_intrinsic_image_texel_address', + 'nir_intrinsic_inclusive_scan', + 'nir_intrinsic_inclusive_scan_clusters_ir3', + 'nir_intrinsic_index_flag', + 'nir_intrinsic_index_flag__enumvalues', + 'nir_intrinsic_index_names', 'nir_intrinsic_info', + 'nir_intrinsic_infos', 'nir_intrinsic_initialize_node_payloads', + 'nir_intrinsic_instr', 'nir_intrinsic_instr_create', + 'nir_intrinsic_instr_dest_type', 'nir_intrinsic_instr_src_type', + 'nir_intrinsic_interp_deref_at_centroid', + 'nir_intrinsic_interp_deref_at_offset', + 'nir_intrinsic_interp_deref_at_sample', + 'nir_intrinsic_interp_deref_at_vertex', + 'nir_intrinsic_inverse_ballot', 'nir_intrinsic_ipa_nv', + 'nir_intrinsic_is_helper_invocation', + 'nir_intrinsic_is_ray_query', + 'nir_intrinsic_is_sparse_resident_zink', + 'nir_intrinsic_is_sparse_texels_resident', + 'nir_intrinsic_is_subgroup_invocation_lt_amd', + 'nir_intrinsic_isberd_nv', 'nir_intrinsic_lane_permute_16_amd', + 'nir_intrinsic_last_invocation', + 'nir_intrinsic_launch_mesh_workgroups', + 'nir_intrinsic_launch_mesh_workgroups_with_payload_deref', + 'nir_intrinsic_ldc_nv', 'nir_intrinsic_ldcx_nv', + 'nir_intrinsic_ldtram_nv', 'nir_intrinsic_load_aa_line_width', + 'nir_intrinsic_load_accel_struct_amd', + 'nir_intrinsic_load_active_samples_agx', + 'nir_intrinsic_load_active_subgroup_count_agx', + 'nir_intrinsic_load_active_subgroup_invocation_agx', + 'nir_intrinsic_load_agx', + 'nir_intrinsic_load_alpha_reference_amd', + 'nir_intrinsic_load_api_sample_mask_agx', + 'nir_intrinsic_load_attrib_clamp_agx', + 'nir_intrinsic_load_attribute_pan', + 'nir_intrinsic_load_back_face_agx', + 'nir_intrinsic_load_barycentric_at_offset', + 'nir_intrinsic_load_barycentric_at_offset_nv', + 'nir_intrinsic_load_barycentric_at_sample', + 'nir_intrinsic_load_barycentric_centroid', + 'nir_intrinsic_load_barycentric_coord_at_offset', + 'nir_intrinsic_load_barycentric_coord_at_sample', + 'nir_intrinsic_load_barycentric_coord_centroid', + 'nir_intrinsic_load_barycentric_coord_pixel', + 'nir_intrinsic_load_barycentric_coord_sample', + 'nir_intrinsic_load_barycentric_model', + 'nir_intrinsic_load_barycentric_optimize_amd', + 'nir_intrinsic_load_barycentric_pixel', + 'nir_intrinsic_load_barycentric_sample', + 'nir_intrinsic_load_base_global_invocation_id', + 'nir_intrinsic_load_base_instance', + 'nir_intrinsic_load_base_vertex', + 'nir_intrinsic_load_base_workgroup_id', + 'nir_intrinsic_load_blend_const_color_a_float', + 'nir_intrinsic_load_blend_const_color_aaaa8888_unorm', + 'nir_intrinsic_load_blend_const_color_b_float', + 'nir_intrinsic_load_blend_const_color_g_float', + 'nir_intrinsic_load_blend_const_color_r_float', + 'nir_intrinsic_load_blend_const_color_rgba', + 'nir_intrinsic_load_blend_const_color_rgba8888_unorm', + 'nir_intrinsic_load_btd_global_arg_addr_intel', + 'nir_intrinsic_load_btd_local_arg_addr_intel', + 'nir_intrinsic_load_btd_resume_sbt_addr_intel', + 'nir_intrinsic_load_btd_shader_type_intel', + 'nir_intrinsic_load_btd_stack_id_intel', + 'nir_intrinsic_load_buffer_amd', + 'nir_intrinsic_load_callable_sbt_addr_intel', + 'nir_intrinsic_load_callable_sbt_stride_intel', + 'nir_intrinsic_load_clamp_vertex_color_amd', + 'nir_intrinsic_load_clip_half_line_width_amd', + 'nir_intrinsic_load_clip_z_coeff_agx', + 'nir_intrinsic_load_coalesced_input_count', + 'nir_intrinsic_load_coefficients_agx', + 'nir_intrinsic_load_color0', 'nir_intrinsic_load_color1', + 'nir_intrinsic_load_const_buf_base_addr_lvp', + 'nir_intrinsic_load_const_ir3', 'nir_intrinsic_load_constant', + 'nir_intrinsic_load_constant_agx', + 'nir_intrinsic_load_constant_base_ptr', + 'nir_intrinsic_load_converted_output_pan', + 'nir_intrinsic_load_core_id_agx', + 'nir_intrinsic_load_cull_any_enabled_amd', + 'nir_intrinsic_load_cull_back_face_enabled_amd', + 'nir_intrinsic_load_cull_ccw_amd', + 'nir_intrinsic_load_cull_front_face_enabled_amd', + 'nir_intrinsic_load_cull_line_viewport_xy_scale_and_offset_amd', + 'nir_intrinsic_load_cull_mask', + 'nir_intrinsic_load_cull_mask_and_flags_amd', + 'nir_intrinsic_load_cull_small_line_precision_amd', + 'nir_intrinsic_load_cull_small_lines_enabled_amd', + 'nir_intrinsic_load_cull_small_triangle_precision_amd', + 'nir_intrinsic_load_cull_small_triangles_enabled_amd', + 'nir_intrinsic_load_cull_triangle_viewport_xy_scale_and_offset_amd', + 'nir_intrinsic_load_debug_log_desc_amd', + 'nir_intrinsic_load_depth_never_agx', 'nir_intrinsic_load_deref', + 'nir_intrinsic_load_deref_block_intel', + 'nir_intrinsic_load_draw_id', + 'nir_intrinsic_load_esgs_vertex_stride_amd', + 'nir_intrinsic_load_exported_agx', + 'nir_intrinsic_load_fb_layers_v3d', + 'nir_intrinsic_load_fbfetch_image_desc_amd', + 'nir_intrinsic_load_fbfetch_image_fmask_desc_amd', + 'nir_intrinsic_load_fep_w_v3d', 'nir_intrinsic_load_first_vertex', + 'nir_intrinsic_load_fixed_point_size_agx', + 'nir_intrinsic_load_flat_mask', + 'nir_intrinsic_load_force_vrs_rates_amd', + 'nir_intrinsic_load_frag_coord', + 'nir_intrinsic_load_frag_coord_unscaled_ir3', + 'nir_intrinsic_load_frag_coord_w', + 'nir_intrinsic_load_frag_coord_z', + 'nir_intrinsic_load_frag_coord_zw_pan', + 'nir_intrinsic_load_frag_invocation_count', + 'nir_intrinsic_load_frag_offset_ir3', + 'nir_intrinsic_load_frag_shading_rate', + 'nir_intrinsic_load_frag_size', + 'nir_intrinsic_load_frag_size_ir3', + 'nir_intrinsic_load_from_texture_handle_agx', + 'nir_intrinsic_load_front_face', + 'nir_intrinsic_load_front_face_fsign', + 'nir_intrinsic_load_fs_input_interp_deltas', + 'nir_intrinsic_load_fs_msaa_intel', + 'nir_intrinsic_load_fully_covered', + 'nir_intrinsic_load_geometry_param_buffer_poly', + 'nir_intrinsic_load_global', 'nir_intrinsic_load_global_2x32', + 'nir_intrinsic_load_global_amd', + 'nir_intrinsic_load_global_base_ptr', + 'nir_intrinsic_load_global_block_intel', + 'nir_intrinsic_load_global_bounded', + 'nir_intrinsic_load_global_constant', + 'nir_intrinsic_load_global_constant_bounded', + 'nir_intrinsic_load_global_constant_offset', + 'nir_intrinsic_load_global_constant_uniform_block_intel', + 'nir_intrinsic_load_global_etna', + 'nir_intrinsic_load_global_invocation_id', + 'nir_intrinsic_load_global_invocation_index', + 'nir_intrinsic_load_global_ir3', 'nir_intrinsic_load_global_size', + 'nir_intrinsic_load_gs_header_ir3', + 'nir_intrinsic_load_gs_vertex_offset_amd', + 'nir_intrinsic_load_gs_wave_id_amd', + 'nir_intrinsic_load_helper_arg_hi_agx', + 'nir_intrinsic_load_helper_arg_lo_agx', + 'nir_intrinsic_load_helper_invocation', + 'nir_intrinsic_load_helper_op_id_agx', + 'nir_intrinsic_load_hit_attrib_amd', + 'nir_intrinsic_load_hs_out_patch_data_offset_amd', + 'nir_intrinsic_load_hs_patch_stride_ir3', + 'nir_intrinsic_load_initial_edgeflags_amd', + 'nir_intrinsic_load_inline_data_intel', + 'nir_intrinsic_load_input', + 'nir_intrinsic_load_input_assembly_buffer_poly', + 'nir_intrinsic_load_input_attachment_conv_pan', + 'nir_intrinsic_load_input_attachment_coord', + 'nir_intrinsic_load_input_attachment_target_pan', + 'nir_intrinsic_load_input_topology_poly', + 'nir_intrinsic_load_input_vertex', + 'nir_intrinsic_load_instance_id', + 'nir_intrinsic_load_interpolated_input', + 'nir_intrinsic_load_intersection_opaque_amd', + 'nir_intrinsic_load_invocation_id', + 'nir_intrinsic_load_is_first_fan_agx', + 'nir_intrinsic_load_is_indexed_draw', + 'nir_intrinsic_load_kernel_input', 'nir_intrinsic_load_layer_id', + 'nir_intrinsic_load_lds_ngg_gs_out_vertex_base_amd', + 'nir_intrinsic_load_leaf_opaque_intel', + 'nir_intrinsic_load_leaf_procedural_intel', + 'nir_intrinsic_load_line_coord', 'nir_intrinsic_load_line_width', + 'nir_intrinsic_load_local_invocation_id', + 'nir_intrinsic_load_local_invocation_index', + 'nir_intrinsic_load_local_pixel_agx', + 'nir_intrinsic_load_local_shared_r600', + 'nir_intrinsic_load_lshs_vertex_stride_amd', + 'nir_intrinsic_load_max_polygon_intel', + 'nir_intrinsic_load_merged_wave_info_amd', + 'nir_intrinsic_load_mesh_view_count', + 'nir_intrinsic_load_mesh_view_indices', + 'nir_intrinsic_load_multisampled_pan', + 'nir_intrinsic_load_noperspective_varyings_pan', + 'nir_intrinsic_load_num_subgroups', + 'nir_intrinsic_load_num_vertices', + 'nir_intrinsic_load_num_vertices_per_primitive_amd', + 'nir_intrinsic_load_num_workgroups', + 'nir_intrinsic_load_ordered_id_amd', 'nir_intrinsic_load_output', + 'nir_intrinsic_load_packed_passthrough_primitive_amd', + 'nir_intrinsic_load_param', + 'nir_intrinsic_load_patch_vertices_in', + 'nir_intrinsic_load_per_primitive_input', + 'nir_intrinsic_load_per_primitive_output', + 'nir_intrinsic_load_per_primitive_remap_intel', + 'nir_intrinsic_load_per_vertex_input', + 'nir_intrinsic_load_per_vertex_output', + 'nir_intrinsic_load_per_view_output', + 'nir_intrinsic_load_persp_center_rhw_ir3', + 'nir_intrinsic_load_pipeline_stat_query_enabled_amd', + 'nir_intrinsic_load_pixel_coord', + 'nir_intrinsic_load_point_coord', + 'nir_intrinsic_load_point_coord_maybe_flipped', + 'nir_intrinsic_load_poly_line_smooth_enabled', + 'nir_intrinsic_load_polygon_stipple_agx', + 'nir_intrinsic_load_polygon_stipple_buffer_amd', + 'nir_intrinsic_load_preamble', + 'nir_intrinsic_load_prim_gen_query_enabled_amd', + 'nir_intrinsic_load_prim_xfb_query_enabled_amd', + 'nir_intrinsic_load_primitive_id', + 'nir_intrinsic_load_primitive_location_ir3', + 'nir_intrinsic_load_printf_buffer_address', + 'nir_intrinsic_load_printf_buffer_size', + 'nir_intrinsic_load_provoking_last', + 'nir_intrinsic_load_provoking_vtx_amd', + 'nir_intrinsic_load_provoking_vtx_in_prim_amd', + 'nir_intrinsic_load_push_constant', + 'nir_intrinsic_load_push_constant_zink', + 'nir_intrinsic_load_r600_indirect_per_vertex_input', + 'nir_intrinsic_load_rasterization_primitive_amd', + 'nir_intrinsic_load_rasterization_samples_amd', + 'nir_intrinsic_load_rasterization_stream', + 'nir_intrinsic_load_raw_output_pan', + 'nir_intrinsic_load_raw_vertex_id_pan', + 'nir_intrinsic_load_raw_vertex_offset_pan', + 'nir_intrinsic_load_ray_base_mem_addr_intel', + 'nir_intrinsic_load_ray_flags', + 'nir_intrinsic_load_ray_geometry_index', + 'nir_intrinsic_load_ray_hit_kind', + 'nir_intrinsic_load_ray_hit_sbt_addr_intel', + 'nir_intrinsic_load_ray_hit_sbt_stride_intel', + 'nir_intrinsic_load_ray_hw_stack_size_intel', + 'nir_intrinsic_load_ray_instance_custom_index', + 'nir_intrinsic_load_ray_launch_id', + 'nir_intrinsic_load_ray_launch_size', + 'nir_intrinsic_load_ray_miss_sbt_addr_intel', + 'nir_intrinsic_load_ray_miss_sbt_stride_intel', + 'nir_intrinsic_load_ray_num_dss_rt_stacks_intel', + 'nir_intrinsic_load_ray_object_direction', + 'nir_intrinsic_load_ray_object_origin', + 'nir_intrinsic_load_ray_object_to_world', + 'nir_intrinsic_load_ray_query_global_intel', + 'nir_intrinsic_load_ray_sw_stack_size_intel', + 'nir_intrinsic_load_ray_t_max', 'nir_intrinsic_load_ray_t_min', + 'nir_intrinsic_load_ray_tracing_stack_base_lvp', + 'nir_intrinsic_load_ray_triangle_vertex_positions', + 'nir_intrinsic_load_ray_world_direction', + 'nir_intrinsic_load_ray_world_origin', + 'nir_intrinsic_load_ray_world_to_object', + 'nir_intrinsic_load_readonly_output_pan', + 'nir_intrinsic_load_reg', 'nir_intrinsic_load_reg_indirect', + 'nir_intrinsic_load_rel_patch_id_ir3', + 'nir_intrinsic_load_reloc_const_intel', + 'nir_intrinsic_load_resume_shader_address_amd', + 'nir_intrinsic_load_ring_attr_amd', + 'nir_intrinsic_load_ring_attr_offset_amd', + 'nir_intrinsic_load_ring_es2gs_offset_amd', + 'nir_intrinsic_load_ring_esgs_amd', + 'nir_intrinsic_load_ring_gs2vs_offset_amd', + 'nir_intrinsic_load_ring_gsvs_amd', + 'nir_intrinsic_load_ring_mesh_scratch_amd', + 'nir_intrinsic_load_ring_mesh_scratch_offset_amd', + 'nir_intrinsic_load_ring_task_draw_amd', + 'nir_intrinsic_load_ring_task_payload_amd', + 'nir_intrinsic_load_ring_tess_factors_amd', + 'nir_intrinsic_load_ring_tess_factors_offset_amd', + 'nir_intrinsic_load_ring_tess_offchip_amd', + 'nir_intrinsic_load_ring_tess_offchip_offset_amd', + 'nir_intrinsic_load_root_agx', + 'nir_intrinsic_load_rt_arg_scratch_offset_amd', + 'nir_intrinsic_load_rt_conversion_pan', + 'nir_intrinsic_load_sample_id', + 'nir_intrinsic_load_sample_id_no_per_sample', + 'nir_intrinsic_load_sample_mask', + 'nir_intrinsic_load_sample_mask_in', + 'nir_intrinsic_load_sample_pos', + 'nir_intrinsic_load_sample_pos_from_id', + 'nir_intrinsic_load_sample_pos_or_center', + 'nir_intrinsic_load_sample_positions_agx', + 'nir_intrinsic_load_sample_positions_amd', + 'nir_intrinsic_load_sample_positions_pan', + 'nir_intrinsic_load_sampler_handle_agx', + 'nir_intrinsic_load_sampler_lod_parameters', + 'nir_intrinsic_load_samples_log2_agx', + 'nir_intrinsic_load_sbt_base_amd', + 'nir_intrinsic_load_sbt_offset_amd', + 'nir_intrinsic_load_sbt_stride_amd', + 'nir_intrinsic_load_scalar_arg_amd', 'nir_intrinsic_load_scratch', + 'nir_intrinsic_load_scratch_base_ptr', + 'nir_intrinsic_load_shader_call_data_offset_lvp', + 'nir_intrinsic_load_shader_index', + 'nir_intrinsic_load_shader_output_pan', + 'nir_intrinsic_load_shader_part_tests_zs_agx', + 'nir_intrinsic_load_shader_record_ptr', + 'nir_intrinsic_load_shared', 'nir_intrinsic_load_shared2_amd', + 'nir_intrinsic_load_shared_base_ptr', + 'nir_intrinsic_load_shared_block_intel', + 'nir_intrinsic_load_shared_ir3', + 'nir_intrinsic_load_shared_lock_nv', + 'nir_intrinsic_load_shared_uniform_block_intel', + 'nir_intrinsic_load_simd_width_intel', + 'nir_intrinsic_load_sm_count_nv', 'nir_intrinsic_load_sm_id_nv', + 'nir_intrinsic_load_smem_amd', 'nir_intrinsic_load_ssbo', + 'nir_intrinsic_load_ssbo_address', + 'nir_intrinsic_load_ssbo_block_intel', + 'nir_intrinsic_load_ssbo_intel', 'nir_intrinsic_load_ssbo_ir3', + 'nir_intrinsic_load_ssbo_uniform_block_intel', + 'nir_intrinsic_load_stack', + 'nir_intrinsic_load_stat_query_address_agx', + 'nir_intrinsic_load_streamout_buffer_amd', + 'nir_intrinsic_load_streamout_config_amd', + 'nir_intrinsic_load_streamout_offset_amd', + 'nir_intrinsic_load_streamout_write_index_amd', + 'nir_intrinsic_load_subgroup_eq_mask', + 'nir_intrinsic_load_subgroup_ge_mask', + 'nir_intrinsic_load_subgroup_gt_mask', + 'nir_intrinsic_load_subgroup_id', + 'nir_intrinsic_load_subgroup_id_shift_ir3', + 'nir_intrinsic_load_subgroup_invocation', + 'nir_intrinsic_load_subgroup_le_mask', + 'nir_intrinsic_load_subgroup_lt_mask', + 'nir_intrinsic_load_subgroup_size', + 'nir_intrinsic_load_sysval_agx', 'nir_intrinsic_load_sysval_nv', + 'nir_intrinsic_load_task_payload', + 'nir_intrinsic_load_task_ring_entry_amd', + 'nir_intrinsic_load_tcs_header_ir3', + 'nir_intrinsic_load_tcs_in_param_base_r600', + 'nir_intrinsic_load_tcs_mem_attrib_stride', + 'nir_intrinsic_load_tcs_num_patches_amd', + 'nir_intrinsic_load_tcs_out_param_base_r600', + 'nir_intrinsic_load_tcs_primitive_mode_amd', + 'nir_intrinsic_load_tcs_rel_patch_id_r600', + 'nir_intrinsic_load_tcs_tess_factor_base_r600', + 'nir_intrinsic_load_tcs_tess_levels_to_tes_amd', + 'nir_intrinsic_load_tess_coord', + 'nir_intrinsic_load_tess_coord_xy', + 'nir_intrinsic_load_tess_factor_base_ir3', + 'nir_intrinsic_load_tess_level_inner', + 'nir_intrinsic_load_tess_level_inner_default', + 'nir_intrinsic_load_tess_level_outer', + 'nir_intrinsic_load_tess_level_outer_default', + 'nir_intrinsic_load_tess_param_base_ir3', + 'nir_intrinsic_load_tess_param_buffer_poly', + 'nir_intrinsic_load_tess_rel_patch_id_amd', + 'nir_intrinsic_load_tex_sprite_mask_agx', + 'nir_intrinsic_load_texture_handle_agx', + 'nir_intrinsic_load_texture_scale', + 'nir_intrinsic_load_texture_size_etna', + 'nir_intrinsic_load_tlb_color_brcm', + 'nir_intrinsic_load_topology_id_intel', + 'nir_intrinsic_load_typed_buffer_amd', + 'nir_intrinsic_load_uav_ir3', 'nir_intrinsic_load_ubo', + 'nir_intrinsic_load_ubo_uniform_block_intel', + 'nir_intrinsic_load_ubo_vec4', 'nir_intrinsic_load_uniform', + 'nir_intrinsic_load_user_clip_plane', + 'nir_intrinsic_load_user_data_amd', + 'nir_intrinsic_load_uvs_index_agx', + 'nir_intrinsic_load_vbo_base_agx', + 'nir_intrinsic_load_vector_arg_amd', + 'nir_intrinsic_load_vertex_id', + 'nir_intrinsic_load_vertex_id_zero_base', + 'nir_intrinsic_load_view_index', + 'nir_intrinsic_load_viewport_offset', + 'nir_intrinsic_load_viewport_scale', + 'nir_intrinsic_load_viewport_x_offset', + 'nir_intrinsic_load_viewport_x_scale', + 'nir_intrinsic_load_viewport_y_offset', + 'nir_intrinsic_load_viewport_y_scale', + 'nir_intrinsic_load_viewport_z_offset', + 'nir_intrinsic_load_viewport_z_scale', + 'nir_intrinsic_load_vs_output_buffer_poly', + 'nir_intrinsic_load_vs_outputs_poly', + 'nir_intrinsic_load_vs_primitive_stride_ir3', + 'nir_intrinsic_load_vs_vertex_stride_ir3', + 'nir_intrinsic_load_vulkan_descriptor', + 'nir_intrinsic_load_warp_id_nv', + 'nir_intrinsic_load_warps_per_sm_nv', + 'nir_intrinsic_load_work_dim', 'nir_intrinsic_load_workgroup_id', + 'nir_intrinsic_load_workgroup_index', + 'nir_intrinsic_load_workgroup_num_input_primitives_amd', + 'nir_intrinsic_load_workgroup_num_input_vertices_amd', + 'nir_intrinsic_load_workgroup_size', + 'nir_intrinsic_load_xfb_address', + 'nir_intrinsic_load_xfb_index_buffer', + 'nir_intrinsic_load_xfb_size', + 'nir_intrinsic_load_xfb_state_address_gfx12_amd', + 'nir_intrinsic_masked_swizzle_amd', 'nir_intrinsic_mbcnt_amd', + 'nir_intrinsic_memcpy_deref', 'nir_intrinsic_nop', + 'nir_intrinsic_nop_amd', 'nir_intrinsic_op', + 'nir_intrinsic_op__enumvalues', + 'nir_intrinsic_optimization_barrier_sgpr_amd', + 'nir_intrinsic_optimization_barrier_vgpr_amd', + 'nir_intrinsic_ordered_add_loop_gfx12_amd', + 'nir_intrinsic_ordered_xfb_counter_add_gfx11_amd', + 'nir_intrinsic_overwrite_tes_arguments_amd', + 'nir_intrinsic_overwrite_vs_arguments_amd', + 'nir_intrinsic_pass_cb', 'nir_intrinsic_pin_cx_handle_nv', + 'nir_intrinsic_preamble_end_ir3', + 'nir_intrinsic_preamble_start_ir3', + 'nir_intrinsic_prefetch_sam_ir3', + 'nir_intrinsic_prefetch_tex_ir3', + 'nir_intrinsic_prefetch_ubo_ir3', 'nir_intrinsic_printf', + 'nir_intrinsic_printf_abort', 'nir_intrinsic_quad_ballot_agx', + 'nir_intrinsic_quad_broadcast', + 'nir_intrinsic_quad_swap_diagonal', + 'nir_intrinsic_quad_swap_horizontal', + 'nir_intrinsic_quad_swap_vertical', + 'nir_intrinsic_quad_swizzle_amd', 'nir_intrinsic_quad_vote_all', + 'nir_intrinsic_quad_vote_any', + 'nir_intrinsic_r600_indirect_vertex_at_index', + 'nir_intrinsic_ray_intersection_ir3', + 'nir_intrinsic_read_attribute_payload_intel', + 'nir_intrinsic_read_first_invocation', + 'nir_intrinsic_read_getlast_ir3', 'nir_intrinsic_read_invocation', + 'nir_intrinsic_read_invocation_cond_ir3', 'nir_intrinsic_reduce', + 'nir_intrinsic_reduce_clusters_ir3', + 'nir_intrinsic_report_ray_intersection', + 'nir_intrinsic_resource_intel', 'nir_intrinsic_rotate', + 'nir_intrinsic_rq_confirm_intersection', + 'nir_intrinsic_rq_generate_intersection', + 'nir_intrinsic_rq_initialize', 'nir_intrinsic_rq_load', + 'nir_intrinsic_rq_proceed', 'nir_intrinsic_rq_terminate', + 'nir_intrinsic_rt_execute_callable', 'nir_intrinsic_rt_resume', + 'nir_intrinsic_rt_return_amd', 'nir_intrinsic_rt_trace_ray', + 'nir_intrinsic_sample_mask_agx', + 'nir_intrinsic_select_vertex_poly', 'nir_intrinsic_semantic_flag', + 'nir_intrinsic_semantic_flag__enumvalues', + 'nir_intrinsic_sendmsg_amd', 'nir_intrinsic_set_align', + 'nir_intrinsic_set_vertex_and_primitive_count', + 'nir_intrinsic_shader_clock', 'nir_intrinsic_shared_append_amd', + 'nir_intrinsic_shared_atomic', 'nir_intrinsic_shared_atomic_swap', + 'nir_intrinsic_shared_consume_amd', 'nir_intrinsic_shuffle', + 'nir_intrinsic_shuffle_down', + 'nir_intrinsic_shuffle_down_uniform_ir3', + 'nir_intrinsic_shuffle_up', + 'nir_intrinsic_shuffle_up_uniform_ir3', + 'nir_intrinsic_shuffle_xor', + 'nir_intrinsic_shuffle_xor_uniform_ir3', + 'nir_intrinsic_sleep_amd', + 'nir_intrinsic_sparse_residency_code_and', + 'nir_intrinsic_src_components', 'nir_intrinsic_ssa_bar_nv', + 'nir_intrinsic_ssbo_atomic', 'nir_intrinsic_ssbo_atomic_ir3', + 'nir_intrinsic_ssbo_atomic_swap', + 'nir_intrinsic_ssbo_atomic_swap_ir3', + 'nir_intrinsic_stack_map_agx', 'nir_intrinsic_stack_unmap_agx', + 'nir_intrinsic_store_agx', 'nir_intrinsic_store_buffer_amd', + 'nir_intrinsic_store_combined_output_pan', + 'nir_intrinsic_store_const_ir3', 'nir_intrinsic_store_deref', + 'nir_intrinsic_store_deref_block_intel', + 'nir_intrinsic_store_global', 'nir_intrinsic_store_global_2x32', + 'nir_intrinsic_store_global_amd', + 'nir_intrinsic_store_global_block_intel', + 'nir_intrinsic_store_global_etna', + 'nir_intrinsic_store_global_ir3', + 'nir_intrinsic_store_hit_attrib_amd', + 'nir_intrinsic_store_local_pixel_agx', + 'nir_intrinsic_store_local_shared_r600', + 'nir_intrinsic_store_output', + 'nir_intrinsic_store_per_primitive_output', + 'nir_intrinsic_store_per_primitive_payload_intel', + 'nir_intrinsic_store_per_vertex_output', + 'nir_intrinsic_store_per_view_output', + 'nir_intrinsic_store_preamble', + 'nir_intrinsic_store_raw_output_pan', 'nir_intrinsic_store_reg', + 'nir_intrinsic_store_reg_indirect', + 'nir_intrinsic_store_scalar_arg_amd', + 'nir_intrinsic_store_scratch', 'nir_intrinsic_store_shared', + 'nir_intrinsic_store_shared2_amd', + 'nir_intrinsic_store_shared_block_intel', + 'nir_intrinsic_store_shared_ir3', + 'nir_intrinsic_store_shared_unlock_nv', + 'nir_intrinsic_store_ssbo', + 'nir_intrinsic_store_ssbo_block_intel', + 'nir_intrinsic_store_ssbo_intel', 'nir_intrinsic_store_ssbo_ir3', + 'nir_intrinsic_store_stack', 'nir_intrinsic_store_task_payload', + 'nir_intrinsic_store_tf_r600', + 'nir_intrinsic_store_tlb_sample_color_v3d', + 'nir_intrinsic_store_uvs_agx', + 'nir_intrinsic_store_vector_arg_amd', + 'nir_intrinsic_store_zs_agx', + 'nir_intrinsic_strict_wqm_coord_amd', 'nir_intrinsic_subfm_nv', + 'nir_intrinsic_suclamp_nv', 'nir_intrinsic_sueau_nv', + 'nir_intrinsic_suldga_nv', 'nir_intrinsic_sustga_nv', + 'nir_intrinsic_task_payload_atomic', + 'nir_intrinsic_task_payload_atomic_swap', + 'nir_intrinsic_terminate', 'nir_intrinsic_terminate_if', + 'nir_intrinsic_terminate_ray', 'nir_intrinsic_trace_ray', + 'nir_intrinsic_trace_ray_intel', 'nir_intrinsic_unit_test_amd', + 'nir_intrinsic_unit_test_divergent_amd', + 'nir_intrinsic_unit_test_uniform_amd', + 'nir_intrinsic_unpin_cx_handle_nv', 'nir_intrinsic_use', + 'nir_intrinsic_vild_nv', 'nir_intrinsic_vote_all', + 'nir_intrinsic_vote_any', 'nir_intrinsic_vote_feq', + 'nir_intrinsic_vote_ieq', 'nir_intrinsic_vulkan_resource_index', + 'nir_intrinsic_vulkan_resource_reindex', + 'nir_intrinsic_write_invocation_amd', + 'nir_intrinsic_writes_external_memory', + 'nir_intrinsic_xfb_counter_sub_gfx11_amd', + 'nir_io_16bit_input_output_support', + 'nir_io_add_const_offset_to_base', + 'nir_io_add_intrinsic_xfb_info', + 'nir_io_always_interpolate_convergent_fs_inputs', + 'nir_io_compaction_groups_tes_inputs_into_pos_and_var_groups', + 'nir_io_compaction_rotates_color_channels', + 'nir_io_dont_use_pos_for_non_fs_varyings', + 'nir_io_has_flexible_input_interpolation_except_flat', + 'nir_io_has_intrinsics', 'nir_io_mediump_is_32bit', + 'nir_io_mix_convergent_flat_with_interpolated', 'nir_io_options', + 'nir_io_options__enumvalues', 'nir_io_prefer_scalar_fs_inputs', + 'nir_io_radv_intrinsic_component_workaround', 'nir_io_semantics', + 'nir_io_separate_clip_cull_distance_arrays', + 'nir_io_vectorizer_ignores_types', 'nir_io_xfb', 'nir_ior_imm', + 'nir_is_arrayed_io', 'nir_is_denorm_flush_to_zero', + 'nir_is_denorm_preserve', 'nir_is_float_control_inf_preserve', + 'nir_is_float_control_nan_preserve', + 'nir_is_float_control_signed_zero_inf_nan_preserve', + 'nir_is_float_control_signed_zero_preserve', 'nir_is_load_reg', + 'nir_is_output_load', 'nir_is_rounding_mode_rtne', + 'nir_is_rounding_mode_rtz', 'nir_is_same_comp_swizzle', + 'nir_is_sequential_comp_swizzle', 'nir_is_store_reg', + 'nir_ishl_imm', 'nir_ishr_imm', 'nir_isub_imm', 'nir_jump', + 'nir_jump_break', 'nir_jump_continue', 'nir_jump_goto', + 'nir_jump_goto_if', 'nir_jump_halt', 'nir_jump_instr', + 'nir_jump_instr_create', 'nir_jump_return', 'nir_jump_type', + 'nir_jump_type__enumvalues', 'nir_last_intrinsic', + 'nir_last_opcode', 'nir_legalize_16bit_sampler_srcs', + 'nir_link_opt_varyings', 'nir_link_shader_functions', + 'nir_link_varying_precision', 'nir_link_xfb_varyings', + 'nir_live_defs_impl', 'nir_load_array_var', + 'nir_load_array_var_imm', 'nir_load_barycentric', + 'nir_load_const_instr', 'nir_load_const_instr_create', + 'nir_load_deref', 'nir_load_deref_with_access', 'nir_load_global', + 'nir_load_global_constant', 'nir_load_grouping', + 'nir_load_grouping__enumvalues', 'nir_load_param', 'nir_load_reg', + 'nir_load_reg_for_def', 'nir_load_store_vectorize_options', + 'nir_load_system_value', 'nir_load_var', + 'nir_local_variable_create', 'nir_log_shader_annotated_tagged', + 'nir_loop', 'nir_loop_analyze_impl', 'nir_loop_continue_target', + 'nir_loop_control', 'nir_loop_control__enumvalues', + 'nir_loop_control_dont_unroll', 'nir_loop_control_none', + 'nir_loop_control_unroll', 'nir_loop_create', + 'nir_loop_first_block', 'nir_loop_first_continue_block', + 'nir_loop_has_continue_construct', 'nir_loop_induction_variable', + 'nir_loop_info', 'nir_loop_is_divergent', 'nir_loop_last_block', + 'nir_loop_last_continue_block', 'nir_loop_terminator', + 'nir_lower_64bit_phis', 'nir_lower_all_phis_to_scalar', + 'nir_lower_alpha_test', 'nir_lower_alpha_to_coverage', + 'nir_lower_alpha_to_one', 'nir_lower_alu', + 'nir_lower_alu_conversion_to_intrinsic', + 'nir_lower_alu_to_scalar', 'nir_lower_alu_vec8_16_srcs', + 'nir_lower_alu_width', 'nir_lower_amul', + 'nir_lower_array_deref_of_vec', + 'nir_lower_array_deref_of_vec_options', + 'nir_lower_array_deref_of_vec_options__enumvalues', + 'nir_lower_atomics', 'nir_lower_atomics_to_ssbo', + 'nir_lower_bcsel64', 'nir_lower_bit_count64', + 'nir_lower_bit_size', 'nir_lower_bit_size_callback', + 'nir_lower_bitfield_extract64', 'nir_lower_bitfield_reverse64', + 'nir_lower_bitmap', 'nir_lower_bitmap_options', + 'nir_lower_bool_to_bitsize', 'nir_lower_bool_to_float', + 'nir_lower_bool_to_int32', 'nir_lower_calls_to_builtins', + 'nir_lower_cl_images', 'nir_lower_clamp_color_outputs', + 'nir_lower_clip_cull_distance_array_vars', + 'nir_lower_clip_cull_distance_to_vec4s', 'nir_lower_clip_disable', + 'nir_lower_clip_fs', 'nir_lower_clip_gs', 'nir_lower_clip_halfz', + 'nir_lower_clip_vs', 'nir_lower_compute_system_values', + 'nir_lower_compute_system_values_options', + 'nir_lower_const_arrays_to_uniforms', + 'nir_lower_constant_convert_alu_types', + 'nir_lower_constant_to_temp', 'nir_lower_continue_constructs', + 'nir_lower_conv64', 'nir_lower_convert_alu_types', + 'nir_lower_dceil', 'nir_lower_ddiv', + 'nir_lower_default_point_size', 'nir_lower_demote_if_to_cf', + 'nir_lower_deref_copy_instr', 'nir_lower_dfloor', + 'nir_lower_dfract', 'nir_lower_direct_array_deref_of_vec_load', + 'nir_lower_direct_array_deref_of_vec_store', + 'nir_lower_discard_if', 'nir_lower_discard_if_options', + 'nir_lower_discard_if_options__enumvalues', 'nir_lower_divmod64', + 'nir_lower_dminmax', 'nir_lower_dmod', 'nir_lower_doubles', + 'nir_lower_doubles_op_to_options_mask', + 'nir_lower_doubles_options', + 'nir_lower_doubles_options__enumvalues', 'nir_lower_drawpixels', + 'nir_lower_drawpixels_options', 'nir_lower_drcp', + 'nir_lower_dround_even', 'nir_lower_drsq', 'nir_lower_dsat', + 'nir_lower_dsign', 'nir_lower_dsqrt', 'nir_lower_dsub', + 'nir_lower_dtrunc', 'nir_lower_explicit_io', + 'nir_lower_explicit_io_instr', 'nir_lower_extract64', + 'nir_lower_fb_read', 'nir_lower_find_lsb64', + 'nir_lower_flatshade', 'nir_lower_flrp', 'nir_lower_fp16_all', + 'nir_lower_fp16_cast_options', + 'nir_lower_fp16_cast_options__enumvalues', 'nir_lower_fp16_casts', + 'nir_lower_fp16_rd', 'nir_lower_fp16_rtne', 'nir_lower_fp16_rtz', + 'nir_lower_fp16_ru', 'nir_lower_fp16_split_fp64', + 'nir_lower_fp64_full_software', + 'nir_lower_frag_coord_to_pixel_coord', 'nir_lower_fragcolor', + 'nir_lower_fragcoord_wtrans', 'nir_lower_frexp', + 'nir_lower_global_vars_to_local', 'nir_lower_goto_ifs', + 'nir_lower_gs_intrinsics', + 'nir_lower_gs_intrinsics_count_primitives', + 'nir_lower_gs_intrinsics_count_vertices_per_primitive', + 'nir_lower_gs_intrinsics_flags', + 'nir_lower_gs_intrinsics_flags__enumvalues', + 'nir_lower_gs_intrinsics_overwrite_incomplete', + 'nir_lower_gs_intrinsics_per_stream', 'nir_lower_halt_to_return', + 'nir_lower_helper_writes', 'nir_lower_iabs64', + 'nir_lower_iadd3_64', 'nir_lower_iadd64', 'nir_lower_iadd_sat64', + 'nir_lower_icmp64', 'nir_lower_idiv', 'nir_lower_idiv_options', + 'nir_lower_image', 'nir_lower_image_atomics_to_global', + 'nir_lower_image_options', 'nir_lower_imul64', + 'nir_lower_imul_2x32_64', 'nir_lower_imul_high64', + 'nir_lower_indirect_array_deref_of_vec_load', + 'nir_lower_indirect_array_deref_of_vec_store', + 'nir_lower_indirect_derefs', 'nir_lower_indirect_var_derefs', + 'nir_lower_ineg64', 'nir_lower_input_attachments', + 'nir_lower_instr_cb', 'nir_lower_int64', + 'nir_lower_int64_float_conversions', + 'nir_lower_int64_op_to_options_mask', 'nir_lower_int64_options', + 'nir_lower_int64_options__enumvalues', 'nir_lower_int_to_float', + 'nir_lower_interpolation', 'nir_lower_interpolation_at_offset', + 'nir_lower_interpolation_at_sample', + 'nir_lower_interpolation_centroid', + 'nir_lower_interpolation_options', + 'nir_lower_interpolation_options__enumvalues', + 'nir_lower_interpolation_pixel', 'nir_lower_interpolation_sample', + 'nir_lower_io', 'nir_lower_io_array_vars_to_elements', + 'nir_lower_io_array_vars_to_elements_no_indirects', + 'nir_lower_io_indirect_loads', + 'nir_lower_io_lower_64bit_float_to_32', + 'nir_lower_io_lower_64bit_to_32', + 'nir_lower_io_lower_64bit_to_32_new', 'nir_lower_io_options', + 'nir_lower_io_options__enumvalues', 'nir_lower_io_passes', + 'nir_lower_io_to_scalar', + 'nir_lower_io_use_interpolated_input_intrinsics', + 'nir_lower_io_vars_to_scalar', 'nir_lower_io_vars_to_temporaries', + 'nir_lower_is_helper_invocation', 'nir_lower_isign64', + 'nir_lower_load_const_to_scalar', 'nir_lower_locals_to_regs', + 'nir_lower_logic64', 'nir_lower_mediump_io', + 'nir_lower_mediump_vars', 'nir_lower_mem_access_bit_sizes', + 'nir_lower_mem_access_bit_sizes_cb', + 'nir_lower_mem_access_bit_sizes_options', 'nir_lower_memcpy', + 'nir_lower_memory_model', 'nir_lower_minmax64', + 'nir_lower_multiview', 'nir_lower_multiview_options', + 'nir_lower_non_uniform_access', + 'nir_lower_non_uniform_access_callback', + 'nir_lower_non_uniform_access_options', + 'nir_lower_non_uniform_access_type', + 'nir_lower_non_uniform_access_type_count', + 'nir_lower_non_uniform_get_ssbo_size', + 'nir_lower_non_uniform_image_access', + 'nir_lower_non_uniform_src_access_callback', + 'nir_lower_non_uniform_ssbo_access', + 'nir_lower_non_uniform_texture_access', + 'nir_lower_non_uniform_texture_offset_access', + 'nir_lower_non_uniform_ubo_access', 'nir_lower_pack', + 'nir_lower_packing_num_ops', 'nir_lower_packing_op', + 'nir_lower_packing_op__enumvalues', + 'nir_lower_packing_op_pack_32_2x16', + 'nir_lower_packing_op_pack_32_4x8', + 'nir_lower_packing_op_pack_64_2x32', + 'nir_lower_packing_op_pack_64_4x16', + 'nir_lower_packing_op_unpack_32_2x16', + 'nir_lower_packing_op_unpack_32_4x8', + 'nir_lower_packing_op_unpack_64_2x32', + 'nir_lower_packing_op_unpack_64_4x16', + 'nir_lower_passthrough_edgeflags', 'nir_lower_patch_vertices', + 'nir_lower_phis_to_regs_block', 'nir_lower_phis_to_scalar', + 'nir_lower_pntc_ytransform', 'nir_lower_point_size', + 'nir_lower_point_size_mov', 'nir_lower_point_smooth', + 'nir_lower_poly_line_smooth', 'nir_lower_printf', + 'nir_lower_printf_buffer', 'nir_lower_printf_options', + 'nir_lower_read_invocation_to_scalar', + 'nir_lower_readonly_images_to_tex', + 'nir_lower_reg_intrinsics_to_ssa', + 'nir_lower_reg_intrinsics_to_ssa_impl', 'nir_lower_returns', + 'nir_lower_returns_impl', 'nir_lower_robust_access', + 'nir_lower_samplers', 'nir_lower_scan_reduce_bitwise64', + 'nir_lower_scan_reduce_iadd64', 'nir_lower_scratch_to_var', + 'nir_lower_shader_calls', 'nir_lower_shader_calls_options', + 'nir_lower_shader_calls_should_remat_func', 'nir_lower_shift64', + 'nir_lower_single_sampled', 'nir_lower_ssa_defs_to_regs_block', + 'nir_lower_ssbo', 'nir_lower_ssbo_options', + 'nir_lower_subgroup_shuffle64', 'nir_lower_subgroups', + 'nir_lower_subgroups_options', 'nir_lower_system_values', + 'nir_lower_sysvals_to_varyings', + 'nir_lower_sysvals_to_varyings_options', 'nir_lower_task_shader', + 'nir_lower_task_shader_options', 'nir_lower_terminate_if_to_cf', + 'nir_lower_terminate_to_demote', 'nir_lower_tess_coord_z', + 'nir_lower_tess_level_array_vars_to_vec', 'nir_lower_tex', + 'nir_lower_tex_options', 'nir_lower_tex_packing', + 'nir_lower_tex_packing_16', 'nir_lower_tex_packing_8', + 'nir_lower_tex_packing_none', 'nir_lower_tex_shadow', + 'nir_lower_tex_shadow_swizzle', 'nir_lower_texcoord_replace', + 'nir_lower_texcoord_replace_late', 'nir_lower_two_sided_color', + 'nir_lower_uadd_sat64', 'nir_lower_ubo_vec4', + 'nir_lower_ufind_msb64', 'nir_lower_undef_to_zero', + 'nir_lower_uniforms_to_ubo', 'nir_lower_usub_sat64', + 'nir_lower_var_copies', 'nir_lower_var_copy_instr', + 'nir_lower_variable_initializers', + 'nir_lower_vars_to_explicit_types', 'nir_lower_vars_to_scratch', + 'nir_lower_vars_to_ssa', 'nir_lower_vec3_to_vec4', + 'nir_lower_vec_to_regs', 'nir_lower_view_index_to_device_index', + 'nir_lower_viewport_transform', 'nir_lower_vote_ieq64', + 'nir_lower_wpos_center', 'nir_lower_wpos_ytransform', + 'nir_lower_wpos_ytransform_options', 'nir_lower_wrmasks', + 'nir_mask', 'nir_mem_access_shift_method', + 'nir_mem_access_shift_method__enumvalues', + 'nir_mem_access_shift_method_bytealign_amd', + 'nir_mem_access_shift_method_scalar', + 'nir_mem_access_shift_method_shift64', + 'nir_mem_access_size_align', 'nir_memcpy_deref', + 'nir_memcpy_deref_with_access', 'nir_memory_semantics', + 'nir_memory_semantics__enumvalues', 'nir_metadata', + 'nir_metadata__enumvalues', 'nir_metadata_all', + 'nir_metadata_block_index', 'nir_metadata_check_validation_flag', + 'nir_metadata_control_flow', 'nir_metadata_divergence', + 'nir_metadata_dominance', 'nir_metadata_instr_index', + 'nir_metadata_invalidate', 'nir_metadata_live_defs', + 'nir_metadata_loop_analysis', 'nir_metadata_none', + 'nir_metadata_not_properly_reset', 'nir_metadata_require', + 'nir_metadata_require_all', 'nir_metadata_set_validation_flag', + 'nir_minimize_call_live_states', 'nir_mod_analysis', + 'nir_mov_alu', 'nir_move_alu', 'nir_move_comparisons', + 'nir_move_const_undef', 'nir_move_copies', 'nir_move_load_input', + 'nir_move_load_ssbo', 'nir_move_load_ubo', + 'nir_move_load_uniform', 'nir_move_options', + 'nir_move_options__enumvalues', 'nir_move_output_stores_to_end', + 'nir_move_terminate_out_of_loops', 'nir_move_to_entry_block_only', + 'nir_move_to_top_input_loads', 'nir_move_to_top_load_smem_amd', + 'nir_move_vec_src_uses_to_dest', 'nir_next_decl_reg', + 'nir_next_phi', 'nir_no_progress', 'nir_normalize_cubemap_coords', + 'nir_num_intrinsics', 'nir_num_opcodes', 'nir_num_tex_src_types', + 'nir_num_variable_modes', 'nir_op', 'nir_op__enumvalues', + 'nir_op_algebraic_property', + 'nir_op_algebraic_property__enumvalues', 'nir_op_alignbyte_amd', + 'nir_op_amul', 'nir_op_andg_ir3', 'nir_op_b16all_fequal16', + 'nir_op_b16all_fequal2', 'nir_op_b16all_fequal3', + 'nir_op_b16all_fequal4', 'nir_op_b16all_fequal5', + 'nir_op_b16all_fequal8', 'nir_op_b16all_iequal16', + 'nir_op_b16all_iequal2', 'nir_op_b16all_iequal3', + 'nir_op_b16all_iequal4', 'nir_op_b16all_iequal5', + 'nir_op_b16all_iequal8', 'nir_op_b16any_fnequal16', + 'nir_op_b16any_fnequal2', 'nir_op_b16any_fnequal3', + 'nir_op_b16any_fnequal4', 'nir_op_b16any_fnequal5', + 'nir_op_b16any_fnequal8', 'nir_op_b16any_inequal16', + 'nir_op_b16any_inequal2', 'nir_op_b16any_inequal3', + 'nir_op_b16any_inequal4', 'nir_op_b16any_inequal5', + 'nir_op_b16any_inequal8', 'nir_op_b16csel', 'nir_op_b2b1', + 'nir_op_b2b16', 'nir_op_b2b32', 'nir_op_b2b8', 'nir_op_b2f16', + 'nir_op_b2f32', 'nir_op_b2f64', 'nir_op_b2i1', 'nir_op_b2i16', + 'nir_op_b2i32', 'nir_op_b2i64', 'nir_op_b2i8', + 'nir_op_b32all_fequal16', 'nir_op_b32all_fequal2', + 'nir_op_b32all_fequal3', 'nir_op_b32all_fequal4', + 'nir_op_b32all_fequal5', 'nir_op_b32all_fequal8', + 'nir_op_b32all_iequal16', 'nir_op_b32all_iequal2', + 'nir_op_b32all_iequal3', 'nir_op_b32all_iequal4', + 'nir_op_b32all_iequal5', 'nir_op_b32all_iequal8', + 'nir_op_b32any_fnequal16', 'nir_op_b32any_fnequal2', + 'nir_op_b32any_fnequal3', 'nir_op_b32any_fnequal4', + 'nir_op_b32any_fnequal5', 'nir_op_b32any_fnequal8', + 'nir_op_b32any_inequal16', 'nir_op_b32any_inequal2', + 'nir_op_b32any_inequal3', 'nir_op_b32any_inequal4', + 'nir_op_b32any_inequal5', 'nir_op_b32any_inequal8', + 'nir_op_b32csel', 'nir_op_b32fcsel_mdg', 'nir_op_b8all_fequal16', + 'nir_op_b8all_fequal2', 'nir_op_b8all_fequal3', + 'nir_op_b8all_fequal4', 'nir_op_b8all_fequal5', + 'nir_op_b8all_fequal8', 'nir_op_b8all_iequal16', + 'nir_op_b8all_iequal2', 'nir_op_b8all_iequal3', + 'nir_op_b8all_iequal4', 'nir_op_b8all_iequal5', + 'nir_op_b8all_iequal8', 'nir_op_b8any_fnequal16', + 'nir_op_b8any_fnequal2', 'nir_op_b8any_fnequal3', + 'nir_op_b8any_fnequal4', 'nir_op_b8any_fnequal5', + 'nir_op_b8any_fnequal8', 'nir_op_b8any_inequal16', + 'nir_op_b8any_inequal2', 'nir_op_b8any_inequal3', + 'nir_op_b8any_inequal4', 'nir_op_b8any_inequal5', + 'nir_op_b8any_inequal8', 'nir_op_b8csel', 'nir_op_ball_fequal16', + 'nir_op_ball_fequal2', 'nir_op_ball_fequal3', + 'nir_op_ball_fequal4', 'nir_op_ball_fequal5', + 'nir_op_ball_fequal8', 'nir_op_ball_iequal16', + 'nir_op_ball_iequal2', 'nir_op_ball_iequal3', + 'nir_op_ball_iequal4', 'nir_op_ball_iequal5', + 'nir_op_ball_iequal8', 'nir_op_bany_fnequal16', + 'nir_op_bany_fnequal2', 'nir_op_bany_fnequal3', + 'nir_op_bany_fnequal4', 'nir_op_bany_fnequal5', + 'nir_op_bany_fnequal8', 'nir_op_bany_inequal16', + 'nir_op_bany_inequal2', 'nir_op_bany_inequal3', + 'nir_op_bany_inequal4', 'nir_op_bany_inequal5', + 'nir_op_bany_inequal8', 'nir_op_bcsel', 'nir_op_bf2f', + 'nir_op_bfdot16', 'nir_op_bfdot2', 'nir_op_bfdot2_bfadd', + 'nir_op_bfdot3', 'nir_op_bfdot4', 'nir_op_bfdot5', + 'nir_op_bfdot8', 'nir_op_bffma', 'nir_op_bfi', 'nir_op_bfm', + 'nir_op_bfmul', 'nir_op_bit_count', 'nir_op_bitfield_insert', + 'nir_op_bitfield_reverse', 'nir_op_bitfield_select', + 'nir_op_bitnz', 'nir_op_bitnz16', 'nir_op_bitnz32', + 'nir_op_bitnz8', 'nir_op_bitz', 'nir_op_bitz16', 'nir_op_bitz32', + 'nir_op_bitz8', 'nir_op_bounds_agx', 'nir_op_byte_perm_amd', + 'nir_op_cube_amd', 'nir_op_e4m3fn2f', 'nir_op_e5m22f', + 'nir_op_extr_agx', 'nir_op_extract_i16', 'nir_op_extract_i8', + 'nir_op_extract_u16', 'nir_op_extract_u8', 'nir_op_f2bf', + 'nir_op_f2e4m3fn', 'nir_op_f2e4m3fn_sat', 'nir_op_f2e4m3fn_satfn', + 'nir_op_f2e5m2', 'nir_op_f2e5m2_sat', 'nir_op_f2f16', + 'nir_op_f2f16_rtne', 'nir_op_f2f16_rtz', 'nir_op_f2f32', + 'nir_op_f2f64', 'nir_op_f2fmp', 'nir_op_f2i1', 'nir_op_f2i16', + 'nir_op_f2i32', 'nir_op_f2i64', 'nir_op_f2i8', 'nir_op_f2imp', + 'nir_op_f2snorm_16_v3d', 'nir_op_f2u1', 'nir_op_f2u16', + 'nir_op_f2u32', 'nir_op_f2u64', 'nir_op_f2u8', 'nir_op_f2ump', + 'nir_op_f2unorm_16_v3d', 'nir_op_fabs', 'nir_op_fadd', + 'nir_op_fall_equal16', 'nir_op_fall_equal2', 'nir_op_fall_equal3', + 'nir_op_fall_equal4', 'nir_op_fall_equal5', 'nir_op_fall_equal8', + 'nir_op_fany_nequal16', 'nir_op_fany_nequal2', + 'nir_op_fany_nequal3', 'nir_op_fany_nequal4', + 'nir_op_fany_nequal5', 'nir_op_fany_nequal8', 'nir_op_fceil', + 'nir_op_fclamp_pos', 'nir_op_fcos', 'nir_op_fcos_amd', + 'nir_op_fcos_mdg', 'nir_op_fcsel', 'nir_op_fcsel_ge', + 'nir_op_fcsel_gt', 'nir_op_fdiv', 'nir_op_fdot16', + 'nir_op_fdot16_replicated', 'nir_op_fdot2', + 'nir_op_fdot2_replicated', 'nir_op_fdot3', + 'nir_op_fdot3_replicated', 'nir_op_fdot4', + 'nir_op_fdot4_replicated', 'nir_op_fdot5', + 'nir_op_fdot5_replicated', 'nir_op_fdot8', + 'nir_op_fdot8_replicated', 'nir_op_fdph', + 'nir_op_fdph_replicated', 'nir_op_feq', 'nir_op_feq16', + 'nir_op_feq32', 'nir_op_feq8', 'nir_op_fequ', 'nir_op_fequ16', + 'nir_op_fequ32', 'nir_op_fequ8', 'nir_op_fexp2', 'nir_op_ffloor', + 'nir_op_ffma', 'nir_op_ffmaz', 'nir_op_ffract', 'nir_op_fge', + 'nir_op_fge16', 'nir_op_fge32', 'nir_op_fge8', 'nir_op_fgeu', + 'nir_op_fgeu16', 'nir_op_fgeu32', 'nir_op_fgeu8', + 'nir_op_find_lsb', 'nir_op_fisfinite', 'nir_op_fisfinite32', + 'nir_op_fisnormal', 'nir_op_flog2', 'nir_op_flrp', 'nir_op_flt', + 'nir_op_flt16', 'nir_op_flt32', 'nir_op_flt8', 'nir_op_fltu', + 'nir_op_fltu16', 'nir_op_fltu32', 'nir_op_fltu8', 'nir_op_fmax', + 'nir_op_fmax_agx', 'nir_op_fmin', 'nir_op_fmin_agx', + 'nir_op_fmod', 'nir_op_fmul', 'nir_op_fmulz', 'nir_op_fneg', + 'nir_op_fneo', 'nir_op_fneo16', 'nir_op_fneo32', 'nir_op_fneo8', + 'nir_op_fneu', 'nir_op_fneu16', 'nir_op_fneu32', 'nir_op_fneu8', + 'nir_op_ford', 'nir_op_ford16', 'nir_op_ford32', 'nir_op_ford8', + 'nir_op_fpow', 'nir_op_fquantize2f16', 'nir_op_frcp', + 'nir_op_frem', 'nir_op_frexp_exp', 'nir_op_frexp_sig', + 'nir_op_fround_even', 'nir_op_frsq', 'nir_op_fsat', + 'nir_op_fsat_signed', 'nir_op_fsign', 'nir_op_fsin', + 'nir_op_fsin_agx', 'nir_op_fsin_amd', 'nir_op_fsin_mdg', + 'nir_op_fsqrt', 'nir_op_fsub', 'nir_op_fsum2', 'nir_op_fsum3', + 'nir_op_fsum4', 'nir_op_ftrunc', 'nir_op_funord', + 'nir_op_funord16', 'nir_op_funord32', 'nir_op_funord8', + 'nir_op_i2f16', 'nir_op_i2f32', 'nir_op_i2f64', 'nir_op_i2fmp', + 'nir_op_i2i1', 'nir_op_i2i16', 'nir_op_i2i32', 'nir_op_i2i64', + 'nir_op_i2i8', 'nir_op_i2imp', 'nir_op_i32csel_ge', + 'nir_op_i32csel_gt', 'nir_op_iabs', 'nir_op_iadd', 'nir_op_iadd3', + 'nir_op_iadd_sat', 'nir_op_iand', 'nir_op_ibfe', + 'nir_op_ibitfield_extract', 'nir_op_icsel_eqz', 'nir_op_idiv', + 'nir_op_ieq', 'nir_op_ieq16', 'nir_op_ieq32', 'nir_op_ieq8', + 'nir_op_ifind_msb', 'nir_op_ifind_msb_rev', 'nir_op_ige', + 'nir_op_ige16', 'nir_op_ige32', 'nir_op_ige8', 'nir_op_ihadd', + 'nir_op_ilea_agx', 'nir_op_ilt', 'nir_op_ilt16', 'nir_op_ilt32', + 'nir_op_ilt8', 'nir_op_imad', 'nir_op_imad24_ir3', + 'nir_op_imadsh_mix16', 'nir_op_imadshl_agx', 'nir_op_imax', + 'nir_op_imin', 'nir_op_imod', 'nir_op_imsubshl_agx', + 'nir_op_imul', 'nir_op_imul24', 'nir_op_imul24_relaxed', + 'nir_op_imul_2x32_64', 'nir_op_imul_32x16', 'nir_op_imul_high', + 'nir_op_ine', 'nir_op_ine16', 'nir_op_ine32', 'nir_op_ine8', + 'nir_op_ineg', 'nir_op_info', 'nir_op_infos', 'nir_op_inot', + 'nir_op_insert_u16', 'nir_op_insert_u8', 'nir_op_interleave_agx', + 'nir_op_ior', 'nir_op_irem', 'nir_op_irhadd', + 'nir_op_is_selection', 'nir_op_is_vec', 'nir_op_is_vec_or_mov', + 'nir_op_ishl', 'nir_op_ishr', 'nir_op_isign', 'nir_op_isub', + 'nir_op_isub_sat', 'nir_op_ixor', 'nir_op_ldexp', + 'nir_op_ldexp16_pan', 'nir_op_lea_nv', 'nir_op_mov', + 'nir_op_mqsad_4x8', 'nir_op_msad_4x8', + 'nir_op_pack_2x16_to_snorm_2x8_v3d', + 'nir_op_pack_2x16_to_unorm_10_2_v3d', + 'nir_op_pack_2x16_to_unorm_2x10_v3d', + 'nir_op_pack_2x16_to_unorm_2x8_v3d', + 'nir_op_pack_2x32_to_2x16_v3d', 'nir_op_pack_32_2x16', + 'nir_op_pack_32_2x16_split', 'nir_op_pack_32_4x8', + 'nir_op_pack_32_4x8_split', 'nir_op_pack_32_to_r11g11b10_v3d', + 'nir_op_pack_4x16_to_4x8_v3d', 'nir_op_pack_64_2x32', + 'nir_op_pack_64_2x32_split', 'nir_op_pack_64_4x16', + 'nir_op_pack_double_2x32_dxil', 'nir_op_pack_half_2x16', + 'nir_op_pack_half_2x16_rtz_split', 'nir_op_pack_half_2x16_split', + 'nir_op_pack_sint_2x16', 'nir_op_pack_snorm_2x16', + 'nir_op_pack_snorm_4x8', 'nir_op_pack_uint_2x16', + 'nir_op_pack_uint_32_to_r10g10b10a2_v3d', + 'nir_op_pack_unorm_2x16', 'nir_op_pack_unorm_4x8', + 'nir_op_pack_uvec2_to_uint', 'nir_op_pack_uvec4_to_uint', + 'nir_op_prmt_nv', 'nir_op_sdot_2x16_iadd', + 'nir_op_sdot_2x16_iadd_sat', 'nir_op_sdot_4x8_iadd', + 'nir_op_sdot_4x8_iadd_sat', 'nir_op_seq', 'nir_op_sge', + 'nir_op_shfr', 'nir_op_shlg_ir3', 'nir_op_shlm_ir3', + 'nir_op_shrg_ir3', 'nir_op_shrm_ir3', 'nir_op_slt', 'nir_op_sne', + 'nir_op_sudot_4x8_iadd', 'nir_op_sudot_4x8_iadd_sat', + 'nir_op_u2f16', 'nir_op_u2f32', 'nir_op_u2f64', 'nir_op_u2fmp', + 'nir_op_u2u1', 'nir_op_u2u16', 'nir_op_u2u32', 'nir_op_u2u64', + 'nir_op_u2u8', 'nir_op_uabs_isub', 'nir_op_uabs_usub', + 'nir_op_uadd_carry', 'nir_op_uadd_sat', 'nir_op_ubfe', + 'nir_op_ubitfield_extract', 'nir_op_uclz', 'nir_op_udiv', + 'nir_op_udiv_aligned_4', 'nir_op_udot_2x16_uadd', + 'nir_op_udot_2x16_uadd_sat', 'nir_op_udot_4x8_uadd', + 'nir_op_udot_4x8_uadd_sat', 'nir_op_ufind_msb', + 'nir_op_ufind_msb_rev', 'nir_op_uge', 'nir_op_uge16', + 'nir_op_uge32', 'nir_op_uge8', 'nir_op_uhadd', 'nir_op_ulea_agx', + 'nir_op_ult', 'nir_op_ult16', 'nir_op_ult32', 'nir_op_ult8', + 'nir_op_umad24', 'nir_op_umad24_relaxed', 'nir_op_umax', + 'nir_op_umax_4x8_vc4', 'nir_op_umin', 'nir_op_umin_4x8_vc4', + 'nir_op_umod', 'nir_op_umul24', 'nir_op_umul24_relaxed', + 'nir_op_umul_2x32_64', 'nir_op_umul_32x16', 'nir_op_umul_high', + 'nir_op_umul_low', 'nir_op_umul_unorm_4x8_vc4', + 'nir_op_unpack_32_2x16', 'nir_op_unpack_32_2x16_split_x', + 'nir_op_unpack_32_2x16_split_y', 'nir_op_unpack_32_4x8', + 'nir_op_unpack_64_2x32', 'nir_op_unpack_64_2x32_split_x', + 'nir_op_unpack_64_2x32_split_y', 'nir_op_unpack_64_4x16', + 'nir_op_unpack_double_2x32_dxil', 'nir_op_unpack_half_2x16', + 'nir_op_unpack_half_2x16_split_x', + 'nir_op_unpack_half_2x16_split_y', 'nir_op_unpack_snorm_2x16', + 'nir_op_unpack_snorm_4x8', 'nir_op_unpack_unorm_2x16', + 'nir_op_unpack_unorm_4x8', 'nir_op_urhadd', 'nir_op_urol', + 'nir_op_uror', 'nir_op_usadd_4x8_vc4', 'nir_op_ushr', + 'nir_op_ussub_4x8_vc4', 'nir_op_usub_borrow', 'nir_op_usub_sat', + 'nir_op_vec', 'nir_op_vec16', 'nir_op_vec2', 'nir_op_vec3', + 'nir_op_vec4', 'nir_op_vec5', 'nir_op_vec8', + 'nir_opt_16bit_tex_image', 'nir_opt_16bit_tex_image_options', + 'nir_opt_access', 'nir_opt_access_options', + 'nir_opt_acquire_release_barriers', 'nir_opt_algebraic', + 'nir_opt_algebraic_before_ffma', + 'nir_opt_algebraic_before_lower_int64', + 'nir_opt_algebraic_distribute_src_mods', + 'nir_opt_algebraic_integer_promotion', 'nir_opt_algebraic_late', + 'nir_opt_barrier_modes', 'nir_opt_clip_cull_const', + 'nir_opt_combine_barriers', 'nir_opt_combine_stores', + 'nir_opt_comparison_pre', 'nir_opt_comparison_pre_impl', + 'nir_opt_constant_folding', 'nir_opt_copy_prop_vars', + 'nir_opt_cse', 'nir_opt_dce', 'nir_opt_dead_cf', + 'nir_opt_dead_write_vars', 'nir_opt_deref', 'nir_opt_deref_impl', + 'nir_opt_find_array_copies', 'nir_opt_frag_coord_to_pixel_coord', + 'nir_opt_fragdepth', 'nir_opt_gcm', 'nir_opt_generate_bfi', + 'nir_opt_idiv_const', 'nir_opt_if', 'nir_opt_if_avoid_64bit_phis', + 'nir_opt_if_optimize_phi_true_false', 'nir_opt_if_options', + 'nir_opt_if_options__enumvalues', 'nir_opt_intrinsics', + 'nir_opt_large_constants', 'nir_opt_licm', + 'nir_opt_load_store_update_alignments', + 'nir_opt_load_store_vectorize', 'nir_opt_loop', + 'nir_opt_loop_unroll', 'nir_opt_memcpy', 'nir_opt_move', + 'nir_opt_move_discards_to_top', 'nir_opt_move_to_top', + 'nir_opt_move_to_top_options', + 'nir_opt_move_to_top_options__enumvalues', 'nir_opt_mqsad', + 'nir_opt_non_uniform_access', 'nir_opt_offsets', + 'nir_opt_offsets_options', 'nir_opt_peephole_select', + 'nir_opt_peephole_select_options', 'nir_opt_phi_precision', + 'nir_opt_phi_to_bool', 'nir_opt_preamble', + 'nir_opt_preamble_options', 'nir_opt_ray_queries', + 'nir_opt_ray_query_ranges', 'nir_opt_reassociate_bfi', + 'nir_opt_reassociate_matrix_mul', + 'nir_opt_rematerialize_compares', 'nir_opt_remove_phis', + 'nir_opt_shrink_stores', 'nir_opt_shrink_vectors', + 'nir_opt_simplify_convert_alu_types', 'nir_opt_sink', + 'nir_opt_tex_skip_helpers', 'nir_opt_tex_srcs_options', + 'nir_opt_undef', 'nir_opt_uniform_atomics', + 'nir_opt_uniform_subgroup', 'nir_opt_varyings', + 'nir_opt_varyings_progress', + 'nir_opt_varyings_progress__enumvalues', 'nir_opt_vectorize', + 'nir_opt_vectorize_io', 'nir_opt_vectorize_io_vars', + 'nir_output_clipper_var_groups', 'nir_output_deps', + 'nir_pack_bits', 'nir_pad_vec4', 'nir_pad_vector', + 'nir_pad_vector_imm_int', 'nir_parallel_copy_entry', + 'nir_parallel_copy_instr', 'nir_parallel_copy_instr_create', + 'nir_parameter', 'nir_phi_get_src_from_block', 'nir_phi_instr', + 'nir_phi_instr_add_src', 'nir_phi_instr_create', + 'nir_phi_pass_cb', 'nir_phi_src', 'nir_pop_if', 'nir_pop_loop', + 'nir_preamble_class', 'nir_preamble_class__enumvalues', + 'nir_preamble_class_general', 'nir_preamble_class_image', + 'nir_preamble_num_classes', 'nir_print_deref', + 'nir_print_function_body', 'nir_print_input_to_output_deps', + 'nir_print_instr', 'nir_print_shader', + 'nir_print_shader_annotated', 'nir_print_use_dominators', + 'nir_printf_fmt', 'nir_printf_fmt_at_px', + 'nir_process_debug_variable', 'nir_progress', + 'nir_progress_consumer', 'nir_progress_producer', + 'nir_propagate_invariant', 'nir_push_continue', 'nir_push_else', + 'nir_push_if', 'nir_push_loop', 'nir_ray_query_value', + 'nir_ray_query_value__enumvalues', 'nir_ray_query_value_flags', + 'nir_ray_query_value_intersection_barycentrics', + 'nir_ray_query_value_intersection_candidate_aabb_opaque', + 'nir_ray_query_value_intersection_front_face', + 'nir_ray_query_value_intersection_geometry_index', + 'nir_ray_query_value_intersection_instance_custom_index', + 'nir_ray_query_value_intersection_instance_id', + 'nir_ray_query_value_intersection_instance_sbt_index', + 'nir_ray_query_value_intersection_object_ray_direction', + 'nir_ray_query_value_intersection_object_ray_origin', + 'nir_ray_query_value_intersection_object_to_world', + 'nir_ray_query_value_intersection_primitive_index', + 'nir_ray_query_value_intersection_t', + 'nir_ray_query_value_intersection_triangle_vertex_positions', + 'nir_ray_query_value_intersection_type', + 'nir_ray_query_value_intersection_world_to_object', + 'nir_ray_query_value_tmin', + 'nir_ray_query_value_world_ray_direction', + 'nir_ray_query_value_world_ray_origin', 'nir_recompute_io_bases', + 'nir_reg_get_decl', 'nir_rematerialize_deref_in_use_blocks', + 'nir_rematerialize_derefs_in_use_blocks_impl', + 'nir_remove_dead_derefs', 'nir_remove_dead_derefs_impl', + 'nir_remove_dead_variables', 'nir_remove_dead_variables_options', + 'nir_remove_entrypoints', 'nir_remove_non_entrypoints', + 'nir_remove_non_exported', 'nir_remove_single_src_phis_block', + 'nir_remove_sysval_output', 'nir_remove_tex_shadow', + 'nir_remove_unused_io_vars', 'nir_remove_unused_varyings', + 'nir_remove_varying', 'nir_repair_ssa', 'nir_repair_ssa_impl', + 'nir_replicate', 'nir_resize_vector', 'nir_resource_data_intel', + 'nir_resource_data_intel__enumvalues', + 'nir_resource_intel_bindless', 'nir_resource_intel_non_uniform', + 'nir_resource_intel_pushable', 'nir_resource_intel_sampler', + 'nir_resource_intel_sampler_embedded', + 'nir_rewrite_image_intrinsic', 'nir_rewrite_uses_to_load_reg', + 'nir_round_down_components', 'nir_round_up_components', + 'nir_rounding_mode', 'nir_rounding_mode__enumvalues', + 'nir_rounding_mode_rd', 'nir_rounding_mode_rtne', + 'nir_rounding_mode_rtz', 'nir_rounding_mode_ru', + 'nir_rounding_mode_undef', 'nir_samples_identical_deref', + 'nir_scalar', 'nir_scalar_alu_op', 'nir_scalar_as_bool', + 'nir_scalar_as_const_value', 'nir_scalar_as_float', + 'nir_scalar_as_int', 'nir_scalar_as_uint', + 'nir_scalar_chase_alu_src', 'nir_scalar_chase_movs', + 'nir_scalar_equal', 'nir_scalar_intrinsic_op', + 'nir_scalar_is_alu', 'nir_scalar_is_const', + 'nir_scalar_is_intrinsic', 'nir_scalar_is_undef', + 'nir_scalar_resolved', 'nir_scale_fdiv', + 'nir_scoped_memory_barrier', 'nir_select_from_ssa_def_array', + 'nir_selection_control', 'nir_selection_control__enumvalues', + 'nir_selection_control_divergent_always_taken', + 'nir_selection_control_dont_flatten', + 'nir_selection_control_flatten', 'nir_selection_control_none', + 'nir_serialize', 'nir_serialize_function', 'nir_shader', + 'nir_shader_add_variable', 'nir_shader_alu_pass', + 'nir_shader_as_str', 'nir_shader_as_str_annotated', + 'nir_shader_clear_pass_flags', 'nir_shader_clone', + 'nir_shader_compiler_options', 'nir_shader_create', + 'nir_shader_gather_debug_info', 'nir_shader_gather_info', + 'nir_shader_get_entrypoint', 'nir_shader_get_function_for_name', + 'nir_shader_get_preamble', 'nir_shader_index_vars', + 'nir_shader_instructions_pass', 'nir_shader_intrinsics_pass', + 'nir_shader_lower_instructions', 'nir_shader_phi_pass', + 'nir_shader_preserve_all_metadata', 'nir_shader_replace', + 'nir_shader_serialize_deserialize', + 'nir_shader_supports_implicit_lod', 'nir_shader_tex_pass', + 'nir_shader_uses_view_index', 'nir_shift_channels', + 'nir_should_vectorize_mem_func', 'nir_shrink_vec_array_vars', + 'nir_slot_is_sysval_output', + 'nir_slot_is_sysval_output_and_varying', 'nir_slot_is_varying', + 'nir_sort_unstructured_blocks', 'nir_sort_variables_by_location', + 'nir_sort_variables_with_modes', 'nir_split_64bit_vec3_and_vec4', + 'nir_split_array_vars', 'nir_split_conversions', + 'nir_split_conversions_options', 'nir_split_per_member_structs', + 'nir_split_struct_vars', 'nir_split_var_copies', 'nir_src', + 'nir_src_as_alu_instr', 'nir_src_as_bool', + 'nir_src_as_const_value', 'nir_src_as_deref', 'nir_src_as_float', + 'nir_src_as_int', 'nir_src_as_intrinsic', 'nir_src_as_string', + 'nir_src_as_uint', 'nir_src_bit_size', 'nir_src_comp_as_bool', + 'nir_src_comp_as_float', 'nir_src_comp_as_int', + 'nir_src_comp_as_uint', 'nir_src_components_read', + 'nir_src_for_ssa', 'nir_src_get_block', 'nir_src_init', + 'nir_src_is_always_uniform', 'nir_src_is_const', + 'nir_src_is_divergent', 'nir_src_is_if', 'nir_src_is_undef', + 'nir_src_num_components', 'nir_src_parent_if', + 'nir_src_parent_instr', 'nir_src_rewrite', + 'nir_src_set_parent_if', 'nir_src_set_parent_instr', + 'nir_srcs_equal', 'nir_ssa_alu_instr_src_components', + 'nir_ssa_for_alu_src', 'nir_start_block', 'nir_state_slot', + 'nir_state_variable_create', 'nir_static_workgroup_size', + 'nir_steal_tex_deref', 'nir_steal_tex_src', 'nir_store_array_var', + 'nir_store_array_var_imm', 'nir_store_deref', + 'nir_store_deref_with_access', 'nir_store_global', + 'nir_store_reg', 'nir_store_reg_for_def', 'nir_store_var', + 'nir_sweep', 'nir_swizzle', 'nir_system_value_from_intrinsic', + 'nir_test_mask', 'nir_tex_deref', 'nir_tex_instr', + 'nir_tex_instr_add_src', 'nir_tex_instr_create', + 'nir_tex_instr_dest_size', + 'nir_tex_instr_has_explicit_tg4_offsets', + 'nir_tex_instr_has_implicit_derivative', 'nir_tex_instr_is_query', + 'nir_tex_instr_need_sampler', 'nir_tex_instr_remove_src', + 'nir_tex_instr_result_size', 'nir_tex_instr_src_index', + 'nir_tex_instr_src_size', 'nir_tex_instr_src_type', + 'nir_tex_pass_cb', 'nir_tex_src', 'nir_tex_src_backend1', + 'nir_tex_src_backend2', 'nir_tex_src_bias', + 'nir_tex_src_comparator', 'nir_tex_src_coord', 'nir_tex_src_ddx', + 'nir_tex_src_ddy', 'nir_tex_src_for_ssa', 'nir_tex_src_lod', + 'nir_tex_src_lod_bias_min_agx', 'nir_tex_src_min_lod', + 'nir_tex_src_ms_index', 'nir_tex_src_ms_mcs_intel', + 'nir_tex_src_offset', 'nir_tex_src_plane', + 'nir_tex_src_projector', 'nir_tex_src_sampler_deref', + 'nir_tex_src_sampler_deref_intrinsic', + 'nir_tex_src_sampler_handle', 'nir_tex_src_sampler_offset', + 'nir_tex_src_texture_deref', + 'nir_tex_src_texture_deref_intrinsic', + 'nir_tex_src_texture_handle', 'nir_tex_src_texture_offset', + 'nir_tex_src_type', 'nir_tex_src_type_constraint', + 'nir_tex_src_type_constraints', 'nir_tex_type_has_lod', + 'nir_texop', 'nir_texop_custom_border_color_agx', + 'nir_texop_descriptor_amd', 'nir_texop_fragment_fetch_amd', + 'nir_texop_fragment_mask_fetch_amd', + 'nir_texop_has_custom_border_color_agx', 'nir_texop_hdr_dim_nv', + 'nir_texop_image_min_lod_agx', 'nir_texop_lod', + 'nir_texop_lod_bias', 'nir_texop_query_levels', + 'nir_texop_sampler_descriptor_amd', 'nir_texop_samples_identical', + 'nir_texop_tex', 'nir_texop_tex_prefetch', + 'nir_texop_tex_type_nv', 'nir_texop_texture_samples', + 'nir_texop_tg4', 'nir_texop_txb', 'nir_texop_txd', + 'nir_texop_txf', 'nir_texop_txf_ms', 'nir_texop_txf_ms_fb', + 'nir_texop_txf_ms_mcs_intel', 'nir_texop_txl', 'nir_texop_txs', + 'nir_trim_vector', 'nir_trivialize_registers', 'nir_txf_deref', + 'nir_txf_ms_deref', 'nir_txl_deref', 'nir_txl_zero_deref', + 'nir_txs_deref', 'nir_type_bool', 'nir_type_bool1', + 'nir_type_bool16', 'nir_type_bool32', 'nir_type_bool8', + 'nir_type_conversion_op', 'nir_type_convert', 'nir_type_float', + 'nir_type_float16', 'nir_type_float32', 'nir_type_float64', + 'nir_type_int', 'nir_type_int1', 'nir_type_int16', + 'nir_type_int32', 'nir_type_int64', 'nir_type_int8', + 'nir_type_invalid', 'nir_type_uint', 'nir_type_uint1', + 'nir_type_uint16', 'nir_type_uint32', 'nir_type_uint64', + 'nir_type_uint8', 'nir_u2fN', 'nir_u2uN', 'nir_ubfe_imm', + 'nir_ubitfield_extract_imm', 'nir_uclamp', 'nir_udiv_imm', + 'nir_umax_imm', 'nir_umin_imm', 'nir_umod_imm', 'nir_undef', + 'nir_undef_instr', 'nir_undef_instr_create', 'nir_unpack_bits', + 'nir_unsigned_upper_bound', 'nir_unsigned_upper_bound_config', + 'nir_unstructured_start_block', 'nir_use_dominance_lca', + 'nir_use_dominance_state', 'nir_ushr_imm', 'nir_validate_shader', + 'nir_validate_ssa_dominance', 'nir_var_all', + 'nir_var_declaration_type', + 'nir_var_declaration_type__enumvalues', + 'nir_var_declared_implicitly', 'nir_var_declared_normally', + 'nir_var_function_in', 'nir_var_function_inout', + 'nir_var_function_out', 'nir_var_function_temp', 'nir_var_hidden', + 'nir_var_image', 'nir_var_mem_constant', 'nir_var_mem_generic', + 'nir_var_mem_global', 'nir_var_mem_node_payload', + 'nir_var_mem_node_payload_in', 'nir_var_mem_push_const', + 'nir_var_mem_shared', 'nir_var_mem_ssbo', + 'nir_var_mem_task_payload', 'nir_var_mem_ubo', + 'nir_var_ray_hit_attrib', 'nir_var_read_only_modes', + 'nir_var_shader_call_data', 'nir_var_shader_in', + 'nir_var_shader_out', 'nir_var_shader_temp', + 'nir_var_system_value', 'nir_var_uniform', + 'nir_var_vec_indexable_modes', 'nir_variable', + 'nir_variable_clone', 'nir_variable_count_slots', + 'nir_variable_create', 'nir_variable_data', + 'nir_variable_is_global', 'nir_variable_is_in_block', + 'nir_variable_is_in_ssbo', 'nir_variable_is_in_ubo', + 'nir_variable_mode', 'nir_variable_mode__enumvalues', 'nir_vec', + 'nir_vec_scalars', 'nir_vector_extract', 'nir_vector_insert', + 'nir_vector_insert_imm', 'nir_vectorize_cb', + 'nir_vertex_divergence_analysis', 'nir_verts_in_output_prim', + 'nir_zero_initialize_shared_memory', 'nv_device_type', + 'nv_device_uuid', 'pipe_format', 'pipe_shader_type', + 'ralloc_adopt', 'ralloc_array_size', 'ralloc_asprintf', + 'ralloc_asprintf_append', 'ralloc_asprintf_rewrite_tail', + 'ralloc_context', 'ralloc_free', 'ralloc_memdup', 'ralloc_parent', + 'ralloc_parent_of_linear_context', 'ralloc_print_info', + 'ralloc_set_destructor', 'ralloc_size', 'ralloc_steal', + 'ralloc_steal_linear_context', 'ralloc_str_append', + 'ralloc_strcat', 'ralloc_strdup', 'ralloc_strncat', + 'ralloc_strndup', 'ralloc_total_size', 'ralloc_vasprintf', + 'ralloc_vasprintf_append', 'ralloc_vasprintf_rewrite_tail', + 'reralloc_array_size', 'reralloc_size', 'rerzalloc_array_size', + 'rerzalloc_size', 'rzalloc_array_size', 'rzalloc_size', + 'should_print_nir', 'should_skip_nir', 'size_t', + 'struct_LLVMOpaqueBasicBlock', 'struct_LLVMOpaqueBuilder', + 'struct_LLVMOpaqueContext', 'struct_LLVMOpaqueDIBuilder', + 'struct_LLVMOpaqueExecutionEngine', + 'struct_LLVMOpaqueMCJITMemoryManager', + 'struct_LLVMOpaqueMetadata', 'struct_LLVMOpaqueModule', + 'struct_LLVMOpaqueTargetData', + 'struct_LLVMOpaqueTargetLibraryInfotData', + 'struct_LLVMOpaqueTargetMachine', 'struct_LLVMOpaqueType', + 'struct_LLVMOpaqueValue', 'struct__IO_FILE', 'struct__IO_codecvt', + 'struct__IO_marker', 'struct__IO_wide_data', + 'struct___va_list_tag', 'struct_blob', 'struct_blob_reader', + 'struct_c__SA_linear_opts', + 'struct_c__SA_nir_input_to_output_deps', + 'struct_c__SA_nir_input_to_output_deps_0', + 'struct_c__SA_nir_output_clipper_var_groups', + 'struct_c__SA_nir_output_deps', 'struct_c__SA_nir_output_deps_0', + 'struct_exec_list', 'struct_exec_node', 'struct_gallivm_state', + 'struct_gc_ctx', 'struct_glsl_cmat_description', + 'struct_glsl_struct_field', 'struct_glsl_struct_field_0_0', + 'struct_glsl_type', 'struct_hash_entry', 'struct_hash_table', + 'struct_linear_ctx', 'struct_list_head', + 'struct_lp_bld_tgsi_system_values', 'struct_lp_build_context', + 'struct_lp_build_coro_suspend_info', 'struct_lp_build_fn', + 'struct_lp_build_for_loop_state', 'struct_lp_build_fs_iface', + 'struct_lp_build_gs_iface', 'struct_lp_build_if_state', + 'struct_lp_build_image_soa', 'struct_lp_build_loop_state', + 'struct_lp_build_mask_context', 'struct_lp_build_mesh_iface', + 'struct_lp_build_sampler_aos', 'struct_lp_build_sampler_soa', + 'struct_lp_build_skip_context', 'struct_lp_build_tcs_iface', + 'struct_lp_build_tes_iface', 'struct_lp_build_tgsi_params', + 'struct_lp_cached_code', 'struct_lp_context_ref', + 'struct_lp_derivatives', 'struct_lp_descriptor', + 'struct_lp_descriptor_0_0', 'struct_lp_descriptor_0_1', + 'struct_lp_generated_code', 'struct_lp_img_params', + 'struct_lp_jit_bindless_texture', 'struct_lp_jit_buffer', + 'struct_lp_jit_image', 'struct_lp_jit_resources', + 'struct_lp_jit_sampler', 'struct_lp_jit_texture', + 'struct_lp_jit_texture_0_0', 'struct_lp_passmgr', + 'struct_lp_sampler_dynamic_state', 'struct_lp_sampler_params', + 'struct_lp_sampler_size_query_params', + 'struct_lp_static_texture_state', 'struct_lp_texture_functions', + 'struct_lp_texture_handle', 'struct_lp_texture_handle_state', + 'struct_lp_type', 'struct_nak_compiler', 'struct_nak_fs_key', + 'struct_nak_qmd_cbuf', 'struct_nak_qmd_cbuf_desc_layout', + 'struct_nak_qmd_dispatch_size_layout', 'struct_nak_qmd_info', + 'struct_nak_sample_location', 'struct_nak_sample_mask', + 'struct_nak_shader_bin', 'struct_nak_shader_info', + 'struct_nak_shader_info_0_cs', 'struct_nak_shader_info_0_fs', + 'struct_nak_shader_info_0_ts', 'struct_nak_shader_info_vtg', + 'struct_nak_xfb_info', 'struct_nir_alu_instr', + 'struct_nir_alu_src', 'struct_nir_binding', 'struct_nir_block', + 'struct_nir_builder', 'struct_nir_call_instr', + 'struct_nir_cf_node', 'struct_nir_constant', 'struct_nir_cursor', + 'struct_nir_def', 'struct_nir_deref_instr', + 'struct_nir_deref_instr_1_arr', 'struct_nir_deref_instr_1_cast', + 'struct_nir_deref_instr_1_strct', 'struct_nir_function', + 'struct_nir_function_impl', 'struct_nir_if', + 'struct_nir_input_attachment_options', 'struct_nir_instr', + 'struct_nir_instr_debug_info', 'struct_nir_intrinsic_info', + 'struct_nir_intrinsic_instr', 'struct_nir_io_semantics', + 'struct_nir_io_xfb', 'struct_nir_io_xfb_0', + 'struct_nir_jump_instr', 'struct_nir_load_const_instr', + 'struct_nir_load_store_vectorize_options', 'struct_nir_loop', + 'struct_nir_loop_induction_variable', 'struct_nir_loop_info', + 'struct_nir_loop_terminator', 'struct_nir_lower_bitmap_options', + 'struct_nir_lower_compute_system_values_options', + 'struct_nir_lower_drawpixels_options', + 'struct_nir_lower_idiv_options', 'struct_nir_lower_image_options', + 'struct_nir_lower_mem_access_bit_sizes_options', + 'struct_nir_lower_multiview_options', + 'struct_nir_lower_non_uniform_access_options', + 'struct_nir_lower_printf_options', + 'struct_nir_lower_shader_calls_options', + 'struct_nir_lower_ssbo_options', + 'struct_nir_lower_subgroups_options', + 'struct_nir_lower_sysvals_to_varyings_options', + 'struct_nir_lower_task_shader_options', + 'struct_nir_lower_tex_options', + 'struct_nir_lower_tex_shadow_swizzle', + 'struct_nir_lower_wpos_ytransform_options', + 'struct_nir_mem_access_size_align', 'struct_nir_op_info', + 'struct_nir_opt_16bit_tex_image_options', + 'struct_nir_opt_access_options', 'struct_nir_opt_offsets_options', + 'struct_nir_opt_peephole_select_options', + 'struct_nir_opt_preamble_options', + 'struct_nir_opt_tex_srcs_options', + 'struct_nir_parallel_copy_entry', + 'struct_nir_parallel_copy_instr', 'struct_nir_parameter', + 'struct_nir_phi_instr', 'struct_nir_phi_src', + 'struct_nir_remove_dead_variables_options', 'struct_nir_scalar', + 'struct_nir_shader', 'struct_nir_shader_compiler_options', + 'struct_nir_split_conversions_options', 'struct_nir_src', + 'struct_nir_state_slot', 'struct_nir_tex_instr', + 'struct_nir_tex_src', 'struct_nir_tex_src_type_constraint', + 'struct_nir_undef_instr', + 'struct_nir_unsigned_upper_bound_config', + 'struct_nir_use_dominance_state', 'struct_nir_variable', + 'struct_nir_variable_data', 'struct_nir_variable_data_0_image', + 'struct_nir_variable_data_0_sampler', + 'struct_nir_variable_data_0_xfb', 'struct_nir_xfb_info', + 'struct_nv_device_info', 'struct_nv_device_info_pci', + 'struct_set', 'struct_set_entry', 'struct_shader_info', + 'struct_shader_info_0_cs', 'struct_shader_info_0_fs', + 'struct_shader_info_0_gs', 'struct_shader_info_0_mesh', + 'struct_shader_info_0_tess', 'struct_shader_info_0_vs', + 'struct_tgsi_shader_info', 'struct_u_printf_info', + 'struct_util_format_block', + 'struct_util_format_channel_description', + 'struct_util_format_description', 'tess_primitive_mode', + 'tgsi_texture_type', 'u_printf_info', 'uint16_t', 'uint32_t', + 'uint64_t', 'uint8_t', 'union_c__UA_nir_const_value', + 'union_glsl_struct_field_0', 'union_glsl_type_fields', + 'union_lp_descriptor_0', 'union_lp_jit_buffer_0', + 'union_lp_jit_texture_0', 'union_nak_shader_info_0', + 'union_nir_cursor_0', 'union_nir_deref_instr_0', + 'union_nir_deref_instr_1', 'union_nir_parallel_copy_entry_dest', + 'union_nir_variable_data_0', 'union_shader_info_0', + 'union_util_format_description_0', 'util_format_colorspace', + 'util_format_layout', 'va_list'] +lvp_nir_options = gzip.decompress(base64.b64decode('H4sIAAAAAAAAA2NgZGRkYGAAkYxgCsQFsxigwgwQBoxmhCqFq2WEKwIrAEGIkQxoAEMALwCqVsCiGUwLMHA0QPn29nBJkswHANb8YpH4AAAA')) +def __getattr__(nm): raise AttributeError('LLVMpipe requires tinymesa_cpu' if 'tinymesa_cpu' not in dll._name else f'attribute {nm} not found') if dll else FileNotFoundError(f'libtinymesa not found (MESA_PATH={BASE}). See https://github.com/sirhcm/tinymesa (tinymesa-32dc66c, mesa-25.2.4)') diff --git a/tinygrad/runtime/autogen/nv/nv.py b/tinygrad/runtime/autogen/nv/nv.py index fa4485ad64..0516ebd5ba 100644 --- a/tinygrad/runtime/autogen/nv/nv.py +++ b/tinygrad/runtime/autogen/nv/nv.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} @@ -7355,6 +7357,113 @@ class struct_c__SA_FWSECLIC_FRTS_CMD(Structure): ] FWSECLIC_FRTS_CMD = struct_c__SA_FWSECLIC_FRTS_CMD +PCIEXPTBL_H = True # macro +NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_BASE = 0x00 # macro +NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_EXT = 0xE0 # macro +PCI_EXP_ROM_SIGNATURE = 0xaa55 # macro +PCI_EXP_ROM_SIGNATURE_NV = 0x4e56 # macro +PCI_EXP_ROM_SIGNATURE_NV2 = 0xbb77 # macro +def IS_VALID_PCI_ROM_SIG(sig): # macro + return ((sig==0xaa55) or (sig==0x4e56) or (sig==0xbb77)) +OFFSETOF_PCI_EXP_ROM_SIG = 0x0 # macro +OFFSETOF_PCI_EXP_ROM_NBSI_DATA_OFFSET = 0x16 # macro +OFFSETOF_PCI_EXP_ROM_PCI_DATA_STRUCT_PTR = 0x18 # macro +PCI_DATA_STRUCT_SIGNATURE = 0x52494350 # macro +PCI_DATA_STRUCT_SIGNATURE_NV = 0x5344504E # macro +PCI_DATA_STRUCT_SIGNATURE_NV2 = 0x53494752 # macro +def IS_VALID_PCI_DATA_SIG(sig): # macro + return ((sig==0x52494350) or (sig==0x5344504E) or (sig==0x53494752)) +# PCI_LAST_IMAGE = NVBIT ( 7 ) # macro +PCI_ROM_IMAGE_BLOCK_SIZE = 512 # macro +OFFSETOF_PCI_DATA_STRUCT_SIG = 0x0 # macro +OFFSETOF_PCI_DATA_STRUCT_VENDOR_ID = 0x4 # macro +OFFSETOF_PCI_DATA_STRUCT_LEN = 0xa # macro +OFFSETOF_PCI_DATA_STRUCT_CLASS_CODE = 0xd # macro +OFFSETOF_PCI_DATA_STRUCT_CODE_TYPE = 0x14 # macro +OFFSETOF_PCI_DATA_STRUCT_IMAGE_LEN = 0x10 # macro +OFFSETOF_PCI_DATA_STRUCT_LAST_IMAGE = 0x15 # macro +NV_PCI_DATA_EXT_SIG = 0x4544504E # macro +NV_PCI_DATA_EXT_REV_10 = 0x100 # macro +NV_PCI_DATA_EXT_REV_11 = 0x101 # macro +OFFSETOF_PCI_DATA_EXT_STRUCT_SIG = 0x0 # macro +OFFSETOF_PCI_DATA_EXT_STRUCT_LEN = 0x6 # macro +OFFSETOF_PCI_DATA_EXT_STRUCT_REV = 0x4 # macro +OFFSETOF_PCI_DATA_EXT_STRUCT_SUBIMAGE_LEN = 0x8 # macro +OFFSETOF_PCI_DATA_EXT_STRUCT_LAST_IMAGE = 0xa # macro +OFFSETOF_PCI_DATA_EXT_STRUCT_FLAGS = 0xb # macro +PCI_DATA_EXT_STRUCT_FLAGS_CHECKSUM_DISABLED = 0x04 # macro +class struct__PCI_EXP_ROM_STANDARD(Structure): + pass + +struct__PCI_EXP_ROM_STANDARD._pack_ = 1 # source:False +struct__PCI_EXP_ROM_STANDARD._fields_ = [ + ('sig', ctypes.c_uint16), + ('reserved', ctypes.c_ubyte * 22), + ('pciDataStrucPtr', ctypes.c_uint16), + ('sizeOfBlock', ctypes.c_uint32), +] + +PCI_EXP_ROM_STANDARD = struct__PCI_EXP_ROM_STANDARD +PPCI_EXP_ROM_STANDARD = ctypes.POINTER(struct__PCI_EXP_ROM_STANDARD) +class struct__PCI_EXP_ROM_NBSI(Structure): + pass + +struct__PCI_EXP_ROM_NBSI._pack_ = 1 # source:False +struct__PCI_EXP_ROM_NBSI._fields_ = [ + ('sig', ctypes.c_uint16), + ('reserved', ctypes.c_ubyte * 20), + ('nbsiDataOffset', ctypes.c_uint16), + ('pciDataStrucPtr', ctypes.c_uint16), + ('sizeOfBlock', ctypes.c_uint32), +] + +PCI_EXP_ROM_NBSI = struct__PCI_EXP_ROM_NBSI +PPCI_EXP_ROM_NBSI = ctypes.POINTER(struct__PCI_EXP_ROM_NBSI) +class union__PCI_EXP_ROM(Union): + _pack_ = 1 # source:False + _fields_ = [ + ('standard', PCI_EXP_ROM_STANDARD), + ('nbsi', PCI_EXP_ROM_NBSI), + ] + +PCI_EXP_ROM = union__PCI_EXP_ROM +PPCI_EXP_ROM = ctypes.POINTER(union__PCI_EXP_ROM) +class struct__PCI_DATA_STRUCT(Structure): + pass + +struct__PCI_DATA_STRUCT._pack_ = 1 # source:False +struct__PCI_DATA_STRUCT._fields_ = [ + ('sig', ctypes.c_uint32), + ('vendorID', ctypes.c_uint16), + ('deviceID', ctypes.c_uint16), + ('deviceListPtr', ctypes.c_uint16), + ('pciDataStructLen', ctypes.c_uint16), + ('pciDataStructRev', ctypes.c_ubyte), + ('classCode', ctypes.c_ubyte * 3), + ('imageLen', ctypes.c_uint16), + ('vendorRomRev', ctypes.c_uint16), + ('codeType', ctypes.c_ubyte), + ('lastImage', ctypes.c_ubyte), + ('maxRunTimeImageLen', ctypes.c_uint16), +] + +PCI_DATA_STRUCT = struct__PCI_DATA_STRUCT +PPCI_DATA_STRUCT = ctypes.POINTER(struct__PCI_DATA_STRUCT) +class struct__NV_PCI_DATA_EXT_STRUCT(Structure): + pass + +struct__NV_PCI_DATA_EXT_STRUCT._pack_ = 1 # source:False +struct__NV_PCI_DATA_EXT_STRUCT._fields_ = [ + ('signature', ctypes.c_uint32), + ('nvPciDataExtRev', ctypes.c_uint16), + ('nvPciDataExtLen', ctypes.c_uint16), + ('subimageLen', ctypes.c_uint16), + ('privLastImage', ctypes.c_ubyte), + ('flags', ctypes.c_ubyte), +] + +NV_PCI_DATA_EXT_STRUCT = struct__NV_PCI_DATA_EXT_STRUCT +PNV_PCI_DATA_EXT_STRUCT = ctypes.POINTER(struct__NV_PCI_DATA_EXT_STRUCT) __all__ = \ ['ACPI_DATA', 'ACPI_DSM_CACHE', 'ACPI_DSM_FUNCTION_COUNT', 'ACPI_DSM_FUNCTION_CURRENT', 'ACPI_DSM_FUNCTION_GPS', @@ -7478,12 +7587,16 @@ __all__ = \ 'NVDM_TYPE_UEFI_XTL_DEBUG_INTR', 'NVGPU_ENGINE_CAPS_MASK_ARRAY_MAX', 'NVGPU_ENGINE_CAPS_MASK_BITS', 'NV_ACPI_GENERIC_FUNC_COUNT', + 'NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_BASE', + 'NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_EXT', 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_VERSION_AVAILABLE', 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_FLAGS_VERSION_UNAVAILABLE', 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V1', 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V2', 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V3', 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC_VERSION_V4', + 'NV_PCI_DATA_EXT_REV_10', 'NV_PCI_DATA_EXT_REV_11', + 'NV_PCI_DATA_EXT_SIG', 'NV_PCI_DATA_EXT_STRUCT', 'NV_RPC_UPDATE_PDE_BAR_1', 'NV_RPC_UPDATE_PDE_BAR_2', 'NV_RPC_UPDATE_PDE_BAR_INVALID', 'NV_RPC_UPDATE_PDE_BAR_TYPE', 'NV_RPC_UPDATE_PDE_BAR_TYPE__enumvalues', @@ -7773,8 +7886,31 @@ __all__ = \ 'NV_VGPU_PTE_64_INDEX_SHIFT', 'NV_VGPU_PTE_64_PAGE_SIZE', 'NV_VGPU_PTE_64_SIZE', 'NV_VGPU_PTE_INDEX_MASK', 'NV_VGPU_PTE_INDEX_SHIFT', 'NV_VGPU_PTE_PAGE_SIZE', - 'NV_VGPU_PTE_SIZE', 'PACKED_REGISTRY_ENTRY', - 'PACKED_REGISTRY_TABLE', 'REGISTRY_TABLE_ENTRY_TYPE_BINARY', + 'NV_VGPU_PTE_SIZE', 'OFFSETOF_PCI_DATA_EXT_STRUCT_FLAGS', + 'OFFSETOF_PCI_DATA_EXT_STRUCT_LAST_IMAGE', + 'OFFSETOF_PCI_DATA_EXT_STRUCT_LEN', + 'OFFSETOF_PCI_DATA_EXT_STRUCT_REV', + 'OFFSETOF_PCI_DATA_EXT_STRUCT_SIG', + 'OFFSETOF_PCI_DATA_EXT_STRUCT_SUBIMAGE_LEN', + 'OFFSETOF_PCI_DATA_STRUCT_CLASS_CODE', + 'OFFSETOF_PCI_DATA_STRUCT_CODE_TYPE', + 'OFFSETOF_PCI_DATA_STRUCT_IMAGE_LEN', + 'OFFSETOF_PCI_DATA_STRUCT_LAST_IMAGE', + 'OFFSETOF_PCI_DATA_STRUCT_LEN', 'OFFSETOF_PCI_DATA_STRUCT_SIG', + 'OFFSETOF_PCI_DATA_STRUCT_VENDOR_ID', + 'OFFSETOF_PCI_EXP_ROM_NBSI_DATA_OFFSET', + 'OFFSETOF_PCI_EXP_ROM_PCI_DATA_STRUCT_PTR', + 'OFFSETOF_PCI_EXP_ROM_SIG', 'PACKED_REGISTRY_ENTRY', + 'PACKED_REGISTRY_TABLE', 'PCIEXPTBL_H', + 'PCI_DATA_EXT_STRUCT_FLAGS_CHECKSUM_DISABLED', 'PCI_DATA_STRUCT', + 'PCI_DATA_STRUCT_SIGNATURE', 'PCI_DATA_STRUCT_SIGNATURE_NV', + 'PCI_DATA_STRUCT_SIGNATURE_NV2', 'PCI_EXP_ROM', + 'PCI_EXP_ROM_NBSI', 'PCI_EXP_ROM_SIGNATURE', + 'PCI_EXP_ROM_SIGNATURE_NV', 'PCI_EXP_ROM_SIGNATURE_NV2', + 'PCI_EXP_ROM_STANDARD', 'PCI_ROM_IMAGE_BLOCK_SIZE', + 'PNV_PCI_DATA_EXT_STRUCT', 'PPCI_DATA_STRUCT', 'PPCI_EXP_ROM', + 'PPCI_EXP_ROM_NBSI', 'PPCI_EXP_ROM_STANDARD', + 'REGISTRY_TABLE_ENTRY_TYPE_BINARY', 'REGISTRY_TABLE_ENTRY_TYPE_DWORD', 'REGISTRY_TABLE_ENTRY_TYPE_STRING', 'REGISTRY_TABLE_ENTRY_TYPE_UNKNOWN', 'RM_ENGINE_TYPE', @@ -8341,6 +8477,8 @@ __all__ = \ 'struct_UpdateBarPde_v15_00', 'struct_VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS', 'struct_VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS', + 'struct__NV_PCI_DATA_EXT_STRUCT', 'struct__PCI_DATA_STRUCT', + 'struct__PCI_EXP_ROM_NBSI', 'struct__PCI_EXP_ROM_STANDARD', 'struct_alloc_object_FERMI_CONTEXT_SHARE_A_v04_00', 'struct_alloc_object_FERMI_VASPACE_A_v03_00', 'struct_alloc_object_GF100_DISP_SW_v03_00', @@ -8593,7 +8731,7 @@ __all__ = \ 'union_NV2080_CTRL_FB_FS_INFO_QUERY_DATA_v26_04', 'union_NV2080_CTRL_GRMGR_GR_FS_INFO_QUERY_DATA_v1A_1D', 'union_NV2080_CTRL_INTERNAL_PFM_REQ_HNDLR_STATE_SYNC_DATA_type_v21_04', - 'union_alloc_object_params_v25_08', + 'union__PCI_EXP_ROM', 'union_alloc_object_params_v25_08', 'union_alloc_object_params_v26_00', 'union_alloc_object_params_v27_00', 'union_alloc_object_params_v29_06', 'union_c__SA_GspFwWprMeta_0', diff --git a/tinygrad/runtime/autogen/nv_gpu.py b/tinygrad/runtime/autogen/nv_gpu.py index e3962d9389..4b0fb27caf 100644 --- a/tinygrad/runtime/autogen/nv_gpu.py +++ b/tinygrad/runtime/autogen/nv_gpu.py @@ -10,6 +10,8 @@ import ctypes, os class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/nvrtc.py b/tinygrad/runtime/autogen/nvrtc.py index 6af741876b..49253c1f93 100644 --- a/tinygrad/runtime/autogen/nvrtc.py +++ b/tinygrad/runtime/autogen/nvrtc.py @@ -31,6 +31,8 @@ def char_pointer_cast(string, encoding='utf-8'): class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/opencl.py b/tinygrad/runtime/autogen/opencl.py index e2f2691c00..7c9edc01a6 100644 --- a/tinygrad/runtime/autogen/opencl.py +++ b/tinygrad/runtime/autogen/opencl.py @@ -10,6 +10,8 @@ import ctypes, ctypes.util class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/qcom_dsp.py b/tinygrad/runtime/autogen/qcom_dsp.py index fa517a5a88..73578de828 100644 --- a/tinygrad/runtime/autogen/qcom_dsp.py +++ b/tinygrad/runtime/autogen/qcom_dsp.py @@ -10,6 +10,8 @@ import ctypes class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/rocprof.py b/tinygrad/runtime/autogen/rocprof.py new file mode 100644 index 0000000000..91ad8ce817 --- /dev/null +++ b/tinygrad/runtime/autogen/rocprof.py @@ -0,0 +1,669 @@ +# pylint: skip-file +# mypy: ignore-errors +# -*- coding: utf-8 -*- +# +# TARGET arch is: [] +# WORD_SIZE is: 8 +# POINTER_SIZE is: 8 +# LONGDOUBLE_SIZE is: 16 +# +import ctypes, ctypes.util +PATHS_TO_TRY = [ + '/usr/local/lib/librocprof-trace-decoder.so', + '/usr/local/lib/librocprof-trace-decoder.dylib', +] +def _try_dlopen_rocprof_trace_decoder(): + library = ctypes.util.find_library("rocprof-trace-decoder") + if library: + try: return ctypes.CDLL(library) + except OSError: pass + for candidate in PATHS_TO_TRY: + try: return ctypes.CDLL(candidate) + except OSError: pass + return None + + +class AsDictMixin: + @classmethod + def as_dict(cls, self): + result = {} + if not isinstance(self, AsDictMixin): + # not a structure, assume it's already a python object + return self + if not hasattr(cls, "_fields_"): + return result + # sys.version_info >= (3, 5) + # for (field, *_) in cls._fields_: # noqa + for field_tuple in cls._fields_: # noqa + field = field_tuple[0] + if field.startswith('PADDING_'): + continue + value = getattr(self, field) + type_ = type(value) + if hasattr(value, "_length_") and hasattr(value, "_type_"): + # array + if not hasattr(type_, "as_dict"): + value = [v for v in value] + else: + type_ = type_._type_ + value = [type_.as_dict(v) for v in value] + elif hasattr(value, "contents") and hasattr(value, "_type_"): + # pointer + try: + if not hasattr(type_, "as_dict"): + value = value.contents + else: + type_ = type_._type_ + value = type_.as_dict(value.contents) + except ValueError: + # nullptr + value = None + elif isinstance(value, AsDictMixin): + # other structure + value = type_.as_dict(value) + result[field] = value + return result + + +class Structure(ctypes.Structure, AsDictMixin): + + def __init__(self, *args, **kwds): + # We don't want to use positional arguments fill PADDING_* fields + + args = dict(zip(self.__class__._field_names_(), args)) + args.update(kwds) + super(Structure, self).__init__(**args) + + @classmethod + def _field_names_(cls): + if hasattr(cls, '_fields_'): + return (f[0] for f in cls._fields_ if not f[0].startswith('PADDING')) + else: + return () + + @classmethod + def get_type(cls, field): + for f in cls._fields_: + if f[0] == field: + return f[1] + return None + + @classmethod + def bind(cls, bound_fields): + fields = {} + for name, type_ in cls._fields_: + if hasattr(type_, "restype"): + if name in bound_fields: + if bound_fields[name] is None: + fields[name] = type_() + else: + # use a closure to capture the callback from the loop scope + fields[name] = ( + type_((lambda callback: lambda *args: callback(*args))( + bound_fields[name])) + ) + del bound_fields[name] + else: + # default callback implementation (does nothing) + try: + default_ = type_(0).restype().value + except TypeError: + default_ = None + fields[name] = type_(( + lambda default_: lambda *args: default_)(default_)) + else: + # not a callback function, use default initialization + if name in bound_fields: + fields[name] = bound_fields[name] + del bound_fields[name] + else: + fields[name] = type_() + if len(bound_fields) != 0: + raise ValueError( + "Cannot bind the following unknown callback(s) {}.{}".format( + cls.__name__, bound_fields.keys() + )) + return cls(**fields) + + +class Union(ctypes.Union, AsDictMixin): + pass + + + +c_int128 = ctypes.c_ubyte*16 +c_uint128 = c_int128 +void = None +if ctypes.sizeof(ctypes.c_longdouble) == 16: + c_long_double_t = ctypes.c_longdouble +else: + c_long_double_t = ctypes.c_ubyte*16 + +def string_cast(char_pointer, encoding='utf-8', errors='strict'): + value = ctypes.cast(char_pointer, ctypes.c_char_p).value + if value is not None and encoding is not None: + value = value.decode(encoding, errors=errors) + return value + + +def char_pointer_cast(string, encoding='utf-8'): + if encoding is not None: + try: + string = string.encode(encoding) + except AttributeError: + # In Python3, bytes has no encode attribute + pass + string = ctypes.c_char_p(string) + return ctypes.cast(string, ctypes.POINTER(ctypes.c_char)) + + + +class FunctionFactoryStub: + def __getattr__(self, _): + return ctypes.CFUNCTYPE(lambda y:y) + +# libraries['FIXME_STUB'] explanation +# As you did not list (-l libraryname.so) a library that exports this function +# This is a non-working stub instead. +# You can either re-run clan2py with -l /path/to/library.so +# Or manually fix this by comment the ctypes.CDLL loading +_libraries = {} +_libraries['FIXME_STUB'] = _try_dlopen_rocprof_trace_decoder() # ctypes.CDLL('FIXME_STUB') + + + +# values for enumeration 'rocprofiler_thread_trace_decoder_info_t' +rocprofiler_thread_trace_decoder_info_t__enumvalues = { + 0: 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_NONE', + 1: 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_DATA_LOST', + 2: 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_STITCH_INCOMPLETE', + 3: 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_WAVE_INCOMPLETE', + 4: 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_LAST', +} +ROCPROFILER_THREAD_TRACE_DECODER_INFO_NONE = 0 +ROCPROFILER_THREAD_TRACE_DECODER_INFO_DATA_LOST = 1 +ROCPROFILER_THREAD_TRACE_DECODER_INFO_STITCH_INCOMPLETE = 2 +ROCPROFILER_THREAD_TRACE_DECODER_INFO_WAVE_INCOMPLETE = 3 +ROCPROFILER_THREAD_TRACE_DECODER_INFO_LAST = 4 +rocprofiler_thread_trace_decoder_info_t = ctypes.c_uint32 # enum +class struct_rocprofiler_thread_trace_decoder_pc_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_pc_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_pc_t._fields_ = [ + ('address', ctypes.c_uint64), + ('code_object_id', ctypes.c_uint64), +] + +rocprofiler_thread_trace_decoder_pc_t = struct_rocprofiler_thread_trace_decoder_pc_t +class struct_rocprofiler_thread_trace_decoder_perfevent_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_perfevent_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_perfevent_t._fields_ = [ + ('time', ctypes.c_int64), + ('events0', ctypes.c_uint16), + ('events1', ctypes.c_uint16), + ('events2', ctypes.c_uint16), + ('events3', ctypes.c_uint16), + ('CU', ctypes.c_ubyte), + ('bank', ctypes.c_ubyte), + ('PADDING_0', ctypes.c_ubyte * 6), +] + +rocprofiler_thread_trace_decoder_perfevent_t = struct_rocprofiler_thread_trace_decoder_perfevent_t +class struct_rocprofiler_thread_trace_decoder_occupancy_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_occupancy_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_occupancy_t._fields_ = [ + ('pc', rocprofiler_thread_trace_decoder_pc_t), + ('time', ctypes.c_uint64), + ('reserved', ctypes.c_ubyte), + ('cu', ctypes.c_ubyte), + ('simd', ctypes.c_ubyte), + ('wave_id', ctypes.c_ubyte), + ('start', ctypes.c_uint32, 1), + ('_rsvd', ctypes.c_uint32, 31), +] + +rocprofiler_thread_trace_decoder_occupancy_t = struct_rocprofiler_thread_trace_decoder_occupancy_t + +# values for enumeration 'rocprofiler_thread_trace_decoder_wstate_type_t' +rocprofiler_thread_trace_decoder_wstate_type_t__enumvalues = { + 0: 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_EMPTY', + 1: 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_IDLE', + 2: 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_EXEC', + 3: 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_WAIT', + 4: 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_STALL', + 5: 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_LAST', +} +ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_EMPTY = 0 +ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_IDLE = 1 +ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_EXEC = 2 +ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_WAIT = 3 +ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_STALL = 4 +ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_LAST = 5 +rocprofiler_thread_trace_decoder_wstate_type_t = ctypes.c_uint32 # enum +class struct_rocprofiler_thread_trace_decoder_wave_state_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_wave_state_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_wave_state_t._fields_ = [ + ('type', ctypes.c_int32), + ('duration', ctypes.c_int32), +] + +rocprofiler_thread_trace_decoder_wave_state_t = struct_rocprofiler_thread_trace_decoder_wave_state_t + +# values for enumeration 'rocprofiler_thread_trace_decoder_inst_category_t' +rocprofiler_thread_trace_decoder_inst_category_t__enumvalues = { + 0: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_NONE', + 1: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_SMEM', + 2: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_SALU', + 3: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_VMEM', + 4: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_FLAT', + 5: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_LDS', + 6: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_VALU', + 7: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_JUMP', + 8: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_NEXT', + 9: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_IMMED', + 10: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_CONTEXT', + 11: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_MESSAGE', + 12: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_BVH', + 13: 'ROCPROFILER_THREAD_TRACE_DECODER_INST_LAST', +} +ROCPROFILER_THREAD_TRACE_DECODER_INST_NONE = 0 +ROCPROFILER_THREAD_TRACE_DECODER_INST_SMEM = 1 +ROCPROFILER_THREAD_TRACE_DECODER_INST_SALU = 2 +ROCPROFILER_THREAD_TRACE_DECODER_INST_VMEM = 3 +ROCPROFILER_THREAD_TRACE_DECODER_INST_FLAT = 4 +ROCPROFILER_THREAD_TRACE_DECODER_INST_LDS = 5 +ROCPROFILER_THREAD_TRACE_DECODER_INST_VALU = 6 +ROCPROFILER_THREAD_TRACE_DECODER_INST_JUMP = 7 +ROCPROFILER_THREAD_TRACE_DECODER_INST_NEXT = 8 +ROCPROFILER_THREAD_TRACE_DECODER_INST_IMMED = 9 +ROCPROFILER_THREAD_TRACE_DECODER_INST_CONTEXT = 10 +ROCPROFILER_THREAD_TRACE_DECODER_INST_MESSAGE = 11 +ROCPROFILER_THREAD_TRACE_DECODER_INST_BVH = 12 +ROCPROFILER_THREAD_TRACE_DECODER_INST_LAST = 13 +rocprofiler_thread_trace_decoder_inst_category_t = ctypes.c_uint32 # enum +class struct_rocprofiler_thread_trace_decoder_inst_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_inst_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_inst_t._fields_ = [ + ('category', ctypes.c_uint32, 8), + ('stall', ctypes.c_uint32, 24), + ('duration', ctypes.c_int32), + ('time', ctypes.c_int64), + ('pc', rocprofiler_thread_trace_decoder_pc_t), +] + +rocprofiler_thread_trace_decoder_inst_t = struct_rocprofiler_thread_trace_decoder_inst_t +class struct_rocprofiler_thread_trace_decoder_wave_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_wave_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_wave_t._fields_ = [ + ('cu', ctypes.c_ubyte), + ('simd', ctypes.c_ubyte), + ('wave_id', ctypes.c_ubyte), + ('contexts', ctypes.c_ubyte), + ('_rsvd1', ctypes.c_uint32), + ('_rsvd2', ctypes.c_uint32), + ('_rsvd3', ctypes.c_uint32), + ('begin_time', ctypes.c_int64), + ('end_time', ctypes.c_int64), + ('timeline_size', ctypes.c_uint64), + ('instructions_size', ctypes.c_uint64), + ('timeline_array', ctypes.POINTER(struct_rocprofiler_thread_trace_decoder_wave_state_t)), + ('instructions_array', ctypes.POINTER(struct_rocprofiler_thread_trace_decoder_inst_t)), +] + +rocprofiler_thread_trace_decoder_wave_t = struct_rocprofiler_thread_trace_decoder_wave_t +class struct_rocprofiler_thread_trace_decoder_realtime_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_realtime_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_realtime_t._fields_ = [ + ('shader_clock', ctypes.c_int64), + ('realtime_clock', ctypes.c_uint64), + ('reserved', ctypes.c_uint64), +] + +rocprofiler_thread_trace_decoder_realtime_t = struct_rocprofiler_thread_trace_decoder_realtime_t + +# values for enumeration 'rocprofiler_thread_trace_decoder_shaderdata_flags_t' +rocprofiler_thread_trace_decoder_shaderdata_flags_t__enumvalues = { + 0: 'ROCPROFILER_THREAD_TRACE_DECODER_SHADERDATA_FLAGS_IMM', + 1: 'ROCPROFILER_THREAD_TRACE_DECODER_SHADERDATA_FLAGS_PRIV', +} +ROCPROFILER_THREAD_TRACE_DECODER_SHADERDATA_FLAGS_IMM = 0 +ROCPROFILER_THREAD_TRACE_DECODER_SHADERDATA_FLAGS_PRIV = 1 +rocprofiler_thread_trace_decoder_shaderdata_flags_t = ctypes.c_uint32 # enum +class struct_rocprofiler_thread_trace_decoder_shaderdata_t(Structure): + pass + +struct_rocprofiler_thread_trace_decoder_shaderdata_t._pack_ = 1 # source:False +struct_rocprofiler_thread_trace_decoder_shaderdata_t._fields_ = [ + ('time', ctypes.c_int64), + ('value', ctypes.c_uint64), + ('cu', ctypes.c_ubyte), + ('simd', ctypes.c_ubyte), + ('wave_id', ctypes.c_ubyte), + ('flags', ctypes.c_ubyte), + ('reserved', ctypes.c_uint32), +] + +rocprofiler_thread_trace_decoder_shaderdata_t = struct_rocprofiler_thread_trace_decoder_shaderdata_t + +# values for enumeration 'rocprofiler_thread_trace_decoder_record_type_t' +rocprofiler_thread_trace_decoder_record_type_t__enumvalues = { + 0: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_GFXIP', + 1: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_OCCUPANCY', + 2: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_PERFEVENT', + 3: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_WAVE', + 4: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_INFO', + 5: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_DEBUG', + 6: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_SHADERDATA', + 7: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_REALTIME', + 8: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_RT_FREQUENCY', + 9: 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_LAST', +} +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_GFXIP = 0 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_OCCUPANCY = 1 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_PERFEVENT = 2 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_WAVE = 3 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_INFO = 4 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_DEBUG = 5 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_SHADERDATA = 6 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_REALTIME = 7 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_RT_FREQUENCY = 8 +ROCPROFILER_THREAD_TRACE_DECODER_RECORD_LAST = 9 +rocprofiler_thread_trace_decoder_record_type_t = ctypes.c_uint32 # enum + +# values for enumeration 'c__EA_rocprofiler_thread_trace_decoder_status_t' +c__EA_rocprofiler_thread_trace_decoder_status_t__enumvalues = { + 0: 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS', + 1: 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR', + 2: 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES', + 3: 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_ARGUMENT', + 4: 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_SHADER_DATA', + 5: 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_LAST', +} +ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS = 0 +ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR = 1 +ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES = 2 +ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_ARGUMENT = 3 +ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_SHADER_DATA = 4 +ROCPROFILER_THREAD_TRACE_DECODER_STATUS_LAST = 5 +c__EA_rocprofiler_thread_trace_decoder_status_t = ctypes.c_uint32 # enum +rocprofiler_thread_trace_decoder_status_t = c__EA_rocprofiler_thread_trace_decoder_status_t +rocprofiler_thread_trace_decoder_status_t__enumvalues = c__EA_rocprofiler_thread_trace_decoder_status_t__enumvalues +rocprof_trace_decoder_trace_callback_t = ctypes.CFUNCTYPE(c__EA_rocprofiler_thread_trace_decoder_status_t, rocprofiler_thread_trace_decoder_record_type_t, ctypes.POINTER(None), ctypes.c_uint64, ctypes.POINTER(None)) +rocprof_trace_decoder_isa_callback_t = ctypes.CFUNCTYPE(c__EA_rocprofiler_thread_trace_decoder_status_t, ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_uint64), struct_rocprofiler_thread_trace_decoder_pc_t, ctypes.POINTER(None)) +rocprof_trace_decoder_se_data_callback_t = ctypes.CFUNCTYPE(ctypes.c_uint64, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(None)) +try: + rocprof_trace_decoder_parse_data = _libraries['FIXME_STUB'].rocprof_trace_decoder_parse_data + rocprof_trace_decoder_parse_data.restype = rocprofiler_thread_trace_decoder_status_t + rocprof_trace_decoder_parse_data.argtypes = [rocprof_trace_decoder_se_data_callback_t, rocprof_trace_decoder_trace_callback_t, rocprof_trace_decoder_isa_callback_t, ctypes.POINTER(None)] +except AttributeError: + pass +try: + rocprof_trace_decoder_get_info_string = _libraries['FIXME_STUB'].rocprof_trace_decoder_get_info_string + rocprof_trace_decoder_get_info_string.restype = ctypes.POINTER(ctypes.c_char) + rocprof_trace_decoder_get_info_string.argtypes = [rocprofiler_thread_trace_decoder_info_t] +except AttributeError: + pass +try: + rocprof_trace_decoder_get_status_string = _libraries['FIXME_STUB'].rocprof_trace_decoder_get_status_string + rocprof_trace_decoder_get_status_string.restype = ctypes.POINTER(ctypes.c_char) + rocprof_trace_decoder_get_status_string.argtypes = [rocprofiler_thread_trace_decoder_status_t] +except AttributeError: + pass +rocprofiler_thread_trace_decoder_debug_callback_t = ctypes.CFUNCTYPE(None, ctypes.c_int64, ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char), ctypes.POINTER(None)) +uint64_t = ctypes.c_uint64 +try: + rocprof_trace_decoder_dump_data = _libraries['FIXME_STUB'].rocprof_trace_decoder_dump_data + rocprof_trace_decoder_dump_data.restype = rocprofiler_thread_trace_decoder_status_t + rocprof_trace_decoder_dump_data.argtypes = [ctypes.POINTER(ctypes.c_char), uint64_t, rocprofiler_thread_trace_decoder_debug_callback_t, ctypes.POINTER(None)] +except AttributeError: + pass +class union_rocprof_trace_decoder_gfx9_header_t(Union): + pass + +class struct_rocprof_trace_decoder_gfx9_header_t_0(Structure): + pass + +struct_rocprof_trace_decoder_gfx9_header_t_0._pack_ = 1 # source:False +struct_rocprof_trace_decoder_gfx9_header_t_0._fields_ = [ + ('legacy_version', ctypes.c_uint64, 13), + ('gfx9_version2', ctypes.c_uint64, 3), + ('DSIMDM', ctypes.c_uint64, 4), + ('DCU', ctypes.c_uint64, 5), + ('reserved1', ctypes.c_uint64, 1), + ('SEID', ctypes.c_uint64, 6), + ('reserved2', ctypes.c_uint64, 32), +] + +union_rocprof_trace_decoder_gfx9_header_t._pack_ = 1 # source:False +union_rocprof_trace_decoder_gfx9_header_t._anonymous_ = ('_0',) +union_rocprof_trace_decoder_gfx9_header_t._fields_ = [ + ('_0', struct_rocprof_trace_decoder_gfx9_header_t_0), + ('raw', ctypes.c_uint64), +] + +rocprof_trace_decoder_gfx9_header_t = union_rocprof_trace_decoder_gfx9_header_t +class union_rocprof_trace_decoder_instrument_enable_t(Union): + pass + +class struct_rocprof_trace_decoder_instrument_enable_t_0(Structure): + pass + +struct_rocprof_trace_decoder_instrument_enable_t_0._pack_ = 1 # source:False +struct_rocprof_trace_decoder_instrument_enable_t_0._fields_ = [ + ('char1', ctypes.c_uint32, 8), + ('char2', ctypes.c_uint32, 8), + ('char3', ctypes.c_uint32, 8), + ('char4', ctypes.c_uint32, 8), +] + +union_rocprof_trace_decoder_instrument_enable_t._pack_ = 1 # source:False +union_rocprof_trace_decoder_instrument_enable_t._anonymous_ = ('_0',) +union_rocprof_trace_decoder_instrument_enable_t._fields_ = [ + ('_0', struct_rocprof_trace_decoder_instrument_enable_t_0), + ('u32All', ctypes.c_uint32), +] + +rocprof_trace_decoder_instrument_enable_t = union_rocprof_trace_decoder_instrument_enable_t +class union_rocprof_trace_decoder_packet_header_t(Union): + pass + +class struct_rocprof_trace_decoder_packet_header_t_0(Structure): + pass + +struct_rocprof_trace_decoder_packet_header_t_0._pack_ = 1 # source:False +struct_rocprof_trace_decoder_packet_header_t_0._fields_ = [ + ('opcode', ctypes.c_uint32, 8), + ('type', ctypes.c_uint32, 4), + ('data20', ctypes.c_uint32, 20), +] + +union_rocprof_trace_decoder_packet_header_t._pack_ = 1 # source:False +union_rocprof_trace_decoder_packet_header_t._anonymous_ = ('_0',) +union_rocprof_trace_decoder_packet_header_t._fields_ = [ + ('_0', struct_rocprof_trace_decoder_packet_header_t_0), + ('u32All', ctypes.c_uint32), +] + +rocprof_trace_decoder_packet_header_t = union_rocprof_trace_decoder_packet_header_t + +# values for enumeration 'rocprof_trace_decoder_packet_opcode_t' +rocprof_trace_decoder_packet_opcode_t__enumvalues = { + 4: 'ROCPROF_TRACE_DECODER_PACKET_OPCODE_CODEOBJ', + 5: 'ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP', + 6: 'ROCPROF_TRACE_DECODER_PACKET_OPCODE_AGENT_INFO', +} +ROCPROF_TRACE_DECODER_PACKET_OPCODE_CODEOBJ = 4 +ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP = 5 +ROCPROF_TRACE_DECODER_PACKET_OPCODE_AGENT_INFO = 6 +rocprof_trace_decoder_packet_opcode_t = ctypes.c_uint32 # enum + +# values for enumeration 'rocprof_trace_decoder_agent_info_type_t' +rocprof_trace_decoder_agent_info_type_t__enumvalues = { + 0: 'ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ', + 1: 'ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_COUNTER_INTERVAL', + 2: 'ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_LAST', +} +ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ = 0 +ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_COUNTER_INTERVAL = 1 +ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_LAST = 2 +rocprof_trace_decoder_agent_info_type_t = ctypes.c_uint32 # enum +class union_rocprof_trace_decoder_codeobj_marker_tail_t(Union): + pass + +class struct_rocprof_trace_decoder_codeobj_marker_tail_t_0(Structure): + pass + +struct_rocprof_trace_decoder_codeobj_marker_tail_t_0._pack_ = 1 # source:False +struct_rocprof_trace_decoder_codeobj_marker_tail_t_0._fields_ = [ + ('isUnload', ctypes.c_uint32, 1), + ('bFromStart', ctypes.c_uint32, 1), + ('legacy_id', ctypes.c_uint32, 30), +] + +union_rocprof_trace_decoder_codeobj_marker_tail_t._pack_ = 1 # source:False +union_rocprof_trace_decoder_codeobj_marker_tail_t._anonymous_ = ('_0',) +union_rocprof_trace_decoder_codeobj_marker_tail_t._fields_ = [ + ('_0', struct_rocprof_trace_decoder_codeobj_marker_tail_t_0), + ('raw', ctypes.c_uint32), +] + +rocprof_trace_decoder_codeobj_marker_tail_t = union_rocprof_trace_decoder_codeobj_marker_tail_t + +# values for enumeration 'rocprof_trace_decoder_codeobj_marker_type_t' +rocprof_trace_decoder_codeobj_marker_type_t__enumvalues = { + 0: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_TAIL', + 1: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_LO', + 2: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_LO', + 3: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_HI', + 4: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_HI', + 5: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_LO', + 6: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_HI', + 7: 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_LAST', +} +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_TAIL = 0 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_LO = 1 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_LO = 2 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_HI = 3 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_HI = 4 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_LO = 5 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_HI = 6 +ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_LAST = 7 +rocprof_trace_decoder_codeobj_marker_type_t = ctypes.c_uint32 # enum +__all__ = \ + ['ROCPROFILER_THREAD_TRACE_DECODER_INFO_DATA_LOST', + 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_LAST', + 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_NONE', + 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_STITCH_INCOMPLETE', + 'ROCPROFILER_THREAD_TRACE_DECODER_INFO_WAVE_INCOMPLETE', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_BVH', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_CONTEXT', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_FLAT', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_IMMED', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_JUMP', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_LAST', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_LDS', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_MESSAGE', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_NEXT', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_NONE', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_SALU', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_SMEM', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_VALU', + 'ROCPROFILER_THREAD_TRACE_DECODER_INST_VMEM', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_DEBUG', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_GFXIP', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_INFO', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_LAST', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_OCCUPANCY', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_PERFEVENT', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_REALTIME', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_RT_FREQUENCY', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_SHADERDATA', + 'ROCPROFILER_THREAD_TRACE_DECODER_RECORD_WAVE', + 'ROCPROFILER_THREAD_TRACE_DECODER_SHADERDATA_FLAGS_IMM', + 'ROCPROFILER_THREAD_TRACE_DECODER_SHADERDATA_FLAGS_PRIV', + 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR', + 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_ARGUMENT', + 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_INVALID_SHADER_DATA', + 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES', + 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_LAST', + 'ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS', + 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_EMPTY', + 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_EXEC', + 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_IDLE', + 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_LAST', + 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_STALL', + 'ROCPROFILER_THREAD_TRACE_DECODER_WSTATE_WAIT', + 'ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_COUNTER_INTERVAL', + 'ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_LAST', + 'ROCPROF_TRACE_DECODER_AGENT_INFO_TYPE_RT_FREQUENCY_KHZ', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_HI', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ADDR_LO', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_HI', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_ID_LO', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_LAST', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_HI', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_SIZE_LO', + 'ROCPROF_TRACE_DECODER_CODEOBJ_MARKER_TYPE_TAIL', + 'ROCPROF_TRACE_DECODER_PACKET_OPCODE_AGENT_INFO', + 'ROCPROF_TRACE_DECODER_PACKET_OPCODE_CODEOBJ', + 'ROCPROF_TRACE_DECODER_PACKET_OPCODE_RT_TIMESTAMP', + 'c__EA_rocprofiler_thread_trace_decoder_status_t', + 'rocprof_trace_decoder_agent_info_type_t', + 'rocprof_trace_decoder_codeobj_marker_tail_t', + 'rocprof_trace_decoder_codeobj_marker_type_t', + 'rocprof_trace_decoder_dump_data', + 'rocprof_trace_decoder_get_info_string', + 'rocprof_trace_decoder_get_status_string', + 'rocprof_trace_decoder_gfx9_header_t', + 'rocprof_trace_decoder_instrument_enable_t', + 'rocprof_trace_decoder_isa_callback_t', + 'rocprof_trace_decoder_packet_header_t', + 'rocprof_trace_decoder_packet_opcode_t', + 'rocprof_trace_decoder_parse_data', + 'rocprof_trace_decoder_se_data_callback_t', + 'rocprof_trace_decoder_trace_callback_t', + 'rocprofiler_thread_trace_decoder_debug_callback_t', + 'rocprofiler_thread_trace_decoder_info_t', + 'rocprofiler_thread_trace_decoder_inst_category_t', + 'rocprofiler_thread_trace_decoder_inst_t', + 'rocprofiler_thread_trace_decoder_occupancy_t', + 'rocprofiler_thread_trace_decoder_pc_t', + 'rocprofiler_thread_trace_decoder_perfevent_t', + 'rocprofiler_thread_trace_decoder_realtime_t', + 'rocprofiler_thread_trace_decoder_record_type_t', + 'rocprofiler_thread_trace_decoder_shaderdata_flags_t', + 'rocprofiler_thread_trace_decoder_shaderdata_t', + 'rocprofiler_thread_trace_decoder_status_t', + 'rocprofiler_thread_trace_decoder_status_t__enumvalues', + 'rocprofiler_thread_trace_decoder_wave_state_t', + 'rocprofiler_thread_trace_decoder_wave_t', + 'rocprofiler_thread_trace_decoder_wstate_type_t', + 'struct_rocprof_trace_decoder_codeobj_marker_tail_t_0', + 'struct_rocprof_trace_decoder_gfx9_header_t_0', + 'struct_rocprof_trace_decoder_instrument_enable_t_0', + 'struct_rocprof_trace_decoder_packet_header_t_0', + 'struct_rocprofiler_thread_trace_decoder_inst_t', + 'struct_rocprofiler_thread_trace_decoder_occupancy_t', + 'struct_rocprofiler_thread_trace_decoder_pc_t', + 'struct_rocprofiler_thread_trace_decoder_perfevent_t', + 'struct_rocprofiler_thread_trace_decoder_realtime_t', + 'struct_rocprofiler_thread_trace_decoder_shaderdata_t', + 'struct_rocprofiler_thread_trace_decoder_wave_state_t', + 'struct_rocprofiler_thread_trace_decoder_wave_t', 'uint64_t', + 'union_rocprof_trace_decoder_codeobj_marker_tail_t', + 'union_rocprof_trace_decoder_gfx9_header_t', + 'union_rocprof_trace_decoder_instrument_enable_t', + 'union_rocprof_trace_decoder_packet_header_t'] diff --git a/tinygrad/runtime/autogen/sqtt.py b/tinygrad/runtime/autogen/sqtt.py index 5d246bff15..422f736994 100644 --- a/tinygrad/runtime/autogen/sqtt.py +++ b/tinygrad/runtime/autogen/sqtt.py @@ -10,6 +10,8 @@ import ctypes, os class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} @@ -174,12 +176,14 @@ sqtt_version__enumvalues = { 6: 'SQTT_VERSION_2_3', 7: 'SQTT_VERSION_2_4', 11: 'SQTT_VERSION_3_2', + 12: 'SQTT_VERSION_3_3', } SQTT_VERSION_NONE = 0 SQTT_VERSION_2_2 = 5 SQTT_VERSION_2_3 = 6 SQTT_VERSION_2_4 = 7 SQTT_VERSION_3_2 = 11 +SQTT_VERSION_3_3 = 12 sqtt_version = ctypes.c_uint32 # enum # values for enumeration 'sqtt_file_chunk_type' @@ -336,6 +340,8 @@ sqtt_gfxip_level__enumvalues = { 7: 'SQTT_GFXIP_LEVEL_GFXIP_10_1', 9: 'SQTT_GFXIP_LEVEL_GFXIP_10_3', 12: 'SQTT_GFXIP_LEVEL_GFXIP_11_0', + 13: 'SQTT_GFXIP_LEVEL_GFXIP_11_5', + 16: 'SQTT_GFXIP_LEVEL_GFXIP_12', } SQTT_GFXIP_LEVEL_NONE = 0 SQTT_GFXIP_LEVEL_GFXIP_6 = 1 @@ -346,6 +352,8 @@ SQTT_GFXIP_LEVEL_GFXIP_9 = 5 SQTT_GFXIP_LEVEL_GFXIP_10_1 = 7 SQTT_GFXIP_LEVEL_GFXIP_10_3 = 9 SQTT_GFXIP_LEVEL_GFXIP_11_0 = 12 +SQTT_GFXIP_LEVEL_GFXIP_11_5 = 13 +SQTT_GFXIP_LEVEL_GFXIP_12 = 16 sqtt_gfxip_level = ctypes.c_uint32 # enum # values for enumeration 'sqtt_memory_type' @@ -806,12 +814,16 @@ elf_gfxip_level__enumvalues = { 51: 'EF_AMDGPU_MACH_AMDGCN_GFX1010', 54: 'EF_AMDGPU_MACH_AMDGCN_GFX1030', 65: 'EF_AMDGPU_MACH_AMDGCN_GFX1100', + 67: 'EF_AMDGPU_MACH_AMDGCN_GFX1150', + 78: 'EF_AMDGPU_MACH_AMDGCN_GFX1200', } EF_AMDGPU_MACH_AMDGCN_GFX801 = 40 EF_AMDGPU_MACH_AMDGCN_GFX900 = 44 EF_AMDGPU_MACH_AMDGCN_GFX1010 = 51 EF_AMDGPU_MACH_AMDGCN_GFX1030 = 54 EF_AMDGPU_MACH_AMDGCN_GFX1100 = 65 +EF_AMDGPU_MACH_AMDGCN_GFX1150 = 67 +EF_AMDGPU_MACH_AMDGCN_GFX1200 = 78 elf_gfxip_level = ctypes.c_uint32 # enum class struct_sqtt_file_chunk_spm_db(Structure): pass @@ -1607,7 +1619,8 @@ __all__ = \ 'ApiCmdUpdateBuffer', 'ApiCmdWaitEvents', 'ApiCmdWriteTimestamp', 'ApiInvalid', 'ApiRayTracingSeparateCompiled', 'EF_AMDGPU_MACH_AMDGCN_GFX1010', 'EF_AMDGPU_MACH_AMDGCN_GFX1030', - 'EF_AMDGPU_MACH_AMDGCN_GFX1100', 'EF_AMDGPU_MACH_AMDGCN_GFX801', + 'EF_AMDGPU_MACH_AMDGCN_GFX1100', 'EF_AMDGPU_MACH_AMDGCN_GFX1150', + 'EF_AMDGPU_MACH_AMDGCN_GFX1200', 'EF_AMDGPU_MACH_AMDGCN_GFX801', 'EF_AMDGPU_MACH_AMDGCN_GFX900', 'EventCmdBlitImage', 'EventCmdBuildAccelerationStructuresIndirectKHR', 'EventCmdBuildAccelerationStructuresKHR', @@ -1671,7 +1684,8 @@ __all__ = \ 'SQTT_FILE_CHUNK_TYPE_SQTT_DESC', 'SQTT_FILE_MAGIC_NUMBER', 'SQTT_FILE_VERSION_MAJOR', 'SQTT_FILE_VERSION_MINOR', 'SQTT_GFXIP_LEVEL_GFXIP_10_1', 'SQTT_GFXIP_LEVEL_GFXIP_10_3', - 'SQTT_GFXIP_LEVEL_GFXIP_11_0', 'SQTT_GFXIP_LEVEL_GFXIP_6', + 'SQTT_GFXIP_LEVEL_GFXIP_11_0', 'SQTT_GFXIP_LEVEL_GFXIP_11_5', + 'SQTT_GFXIP_LEVEL_GFXIP_12', 'SQTT_GFXIP_LEVEL_GFXIP_6', 'SQTT_GFXIP_LEVEL_GFXIP_7', 'SQTT_GFXIP_LEVEL_GFXIP_8', 'SQTT_GFXIP_LEVEL_GFXIP_8_1', 'SQTT_GFXIP_LEVEL_GFXIP_9', 'SQTT_GFXIP_LEVEL_NONE', 'SQTT_GPU_NAME_MAX_SIZE', @@ -1697,9 +1711,9 @@ __all__ = \ 'SQTT_QUEUE_TYPE_COMPUTE', 'SQTT_QUEUE_TYPE_DMA', 'SQTT_QUEUE_TYPE_UNIVERSAL', 'SQTT_QUEUE_TYPE_UNKNOWN', 'SQTT_SA_PER_SE', 'SQTT_VERSION_2_2', 'SQTT_VERSION_2_3', - 'SQTT_VERSION_2_4', 'SQTT_VERSION_3_2', 'SQTT_VERSION_NONE', - 'UserEventObjectName', 'UserEventPop', 'UserEventPush', - 'UserEventTrigger', 'elf_gfxip_level', + 'SQTT_VERSION_2_4', 'SQTT_VERSION_3_2', 'SQTT_VERSION_3_3', + 'SQTT_VERSION_NONE', 'UserEventObjectName', 'UserEventPop', + 'UserEventPush', 'UserEventTrigger', 'elf_gfxip_level', 'rgp_sqtt_marker_event_type', 'rgp_sqtt_marker_general_api_type', 'rgp_sqtt_marker_identifier', 'rgp_sqtt_marker_user_event_type', 'sqtt_api_type', 'sqtt_engine_type', diff --git a/tinygrad/runtime/autogen/vfio.py b/tinygrad/runtime/autogen/vfio.py index 2cc7377e82..7daa00d430 100644 --- a/tinygrad/runtime/autogen/vfio.py +++ b/tinygrad/runtime/autogen/vfio.py @@ -26,6 +26,8 @@ def _IOR(base, nr, type): return functools.partial(_do_ioctl, 2, ord(base) if is def _IOWR(base, nr, type): return functools.partial(_do_ioctl, 3, ord(base) if isinstance(base, str) else base, nr, type) class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/autogen/webgpu.py b/tinygrad/runtime/autogen/webgpu.py index a1bd4c7565..7edbb99d7c 100644 --- a/tinygrad/runtime/autogen/webgpu.py +++ b/tinygrad/runtime/autogen/webgpu.py @@ -10,6 +10,8 @@ import ctypes, tinygrad.runtime.support.webgpu as webgpu_support class AsDictMixin: + import sys + if sys.version_info >= (3, 14): _layout_ = 'ms' @classmethod def as_dict(cls, self): result = {} diff --git a/tinygrad/runtime/ops_amd.py b/tinygrad/runtime/ops_amd.py index b6b1776730..c16311a58e 100644 --- a/tinygrad/runtime/ops_amd.py +++ b/tinygrad/runtime/ops_amd.py @@ -1,13 +1,13 @@ from __future__ import annotations from typing import cast, ClassVar -import os, ctypes, ctypes.util, struct, hashlib, functools, importlib, mmap, errno, array, contextlib, sys, weakref +import os, ctypes, struct, hashlib, functools, importlib, mmap, errno, array, contextlib, sys, weakref, itertools, collections assert sys.platform != 'win32' from dataclasses import dataclass from tinygrad.runtime.support.hcq import HCQCompiled, HCQAllocator, HCQBuffer, HWQueue, CLikeArgsState, HCQSignal, HCQProgram, FileIOInterface -from tinygrad.runtime.support.hcq import MMIOInterface, BumpAllocator +from tinygrad.runtime.support.hcq import MMIOInterface, BumpAllocator, hcq_filter_visible_devices from tinygrad.uop.ops import sint from tinygrad.device import Compiled, DMAFdRef, BufferSpec, CompilerPairT -from tinygrad.helpers import getenv, to_mv, round_up, data64_le, DEBUG, PROFILE, ProfileEvent, suppress_finalizing, lo32, hi32 +from tinygrad.helpers import getenv, round_up, data64_le, DEBUG, PROFILE, ProfileEvent, suppress_finalizing, lo32, hi32, colored, prod, ContextVar from tinygrad.renderer.cstyle import AMDRenderer from tinygrad.renderer.llvmir import AMDLLVMRenderer from tinygrad.runtime.autogen import kfd, hsa, pci, sqtt @@ -15,11 +15,11 @@ from tinygrad.runtime.autogen.am import am from tinygrad.runtime.support.compiler_amd import HIPCompiler, AMDLLVMCompiler from tinygrad.runtime.support.elf import elf_loader from tinygrad.runtime.support.am.amdev import AMDev, AMMemoryManager -from tinygrad.runtime.support.amd import AMDReg, AMDIP, import_module, import_soc, setup_pci_bars -from tinygrad.runtime.support.system import System, PCIIfaceBase, PCIAllocationMeta, MAP_FIXED, MAP_NORESERVE -from tinygrad.runtime.support.usb import ASM24Controller, USBMMIOInterface +from tinygrad.runtime.support.amd import AMDReg, AMDIP, import_module, import_soc, import_ip_offsets, import_pmc +from tinygrad.runtime.support.system import System, PCIIfaceBase, PCIAllocationMeta, PCIDevice, USBPCIDevice, MAP_FIXED, MAP_NORESERVE if getenv("IOCTL"): import extra.hip_gpu_driver.hip_ioctl # noqa: F401 # pylint: disable=unused-import +SQTT, SQTT_ITRACE_SE_MASK, PMC = ContextVar("SQTT", 0), ContextVar("SQTT_ITRACE_SE_MASK", 0b11), ContextVar("PMC", 0) EVENT_INDEX_PARTIAL_FLUSH = 4 # based on a comment in nvd.h WAIT_REG_MEM_FUNCTION_EQ = 3 # == WAIT_REG_MEM_FUNCTION_NEQ = 4 # != @@ -27,6 +27,15 @@ WAIT_REG_MEM_FUNCTION_GEQ = 5 # >= AQL_HDR = (1 << hsa.HSA_PACKET_HEADER_BARRIER) | (hsa.HSA_FENCE_SCOPE_SYSTEM << hsa.HSA_PACKET_HEADER_SCACQUIRE_FENCE_SCOPE) \ | (hsa.HSA_FENCE_SCOPE_SYSTEM << hsa.HSA_PACKET_HEADER_SCRELEASE_FENCE_SCOPE) +@dataclass(frozen=True) +class ProfileSQTTEvent(ProfileEvent): device:str; kern:str; se:int; blob:bytes; itrace:bool # noqa: E702 + +@dataclass(frozen=True) +class PMCSample: name:str; block:str; xcc:int; inst:int; se:int; sa:int; wgp:int; off:int; size:int; regsample:str # noqa: E702 + +@dataclass(frozen=True) +class ProfilePMCEvent(ProfileEvent): device:str; kern:str; sched:list[PMCSample]; blob:bytes # noqa: E702 + class AMDSignal(HCQSignal): def __init__(self, *args, **kwargs): super().__init__(*args, **{**kwargs, 'timestamp_divider': 100}) @@ -63,11 +72,16 @@ class AMDComputeQueue(HWQueue): if self.dev.xccs > 1: self._q[prev_len-1] |= (len(self._q) - prev_len) - def wait_reg_mem(self, value, mask=0xffffffff, mem=None, reg_req=None, reg_done=None): - wrm_info_dw = self.pm4.WAIT_REG_MEM_MEM_SPACE(int(mem is not None)) | self.pm4.WAIT_REG_MEM_OPERATION(int(mem is None)) \ - | self.pm4.WAIT_REG_MEM_FUNCTION(WAIT_REG_MEM_FUNCTION_GEQ) | self.pm4.WAIT_REG_MEM_ENGINE(0) + def set_grbm(self, instance=None, se=None, sh=None, wgp=None): + instance_val = (wgp << 2 | (instance or 0)) if wgp is not None else instance + self.wreg(self.gc.regGRBM_GFX_INDEX, **{(f'{key}_broadcast_writes' if val is None else f'{key}_index'): (1 if val is None else val) + for key, val in [('instance', instance_val), ('se', se), ('sh' if self.dev.target[0] == 9 else 'sa', sh)]}) - self.pkt3(self.pm4.PACKET3_WAIT_REG_MEM, wrm_info_dw, *(data64_le(mem) if mem is not None else (reg_req, reg_done)), value, mask, 4) + def wait_reg_mem(self, value, mask=0xffffffff, mem=None, reg=None, reg_done=0, op=WAIT_REG_MEM_FUNCTION_GEQ): + wrm_info_dw = self.pm4.WAIT_REG_MEM_MEM_SPACE(int(mem is not None)) | self.pm4.WAIT_REG_MEM_OPERATION(int(mem is None and reg_done > 0)) \ + | self.pm4.WAIT_REG_MEM_FUNCTION(op) | self.pm4.WAIT_REG_MEM_ENGINE(0) + + self.pkt3(self.pm4.PACKET3_WAIT_REG_MEM, wrm_info_dw, *(data64_le(mem) if mem is not None else (reg, reg_done)), value, mask, 4) def acquire_mem(self, addr=0x0, sz=(1 << 64)-1, gli=1, glm=1, glk=1, glv=1, gl1=1, gl2=1): if self.dev.target >= (10,0,0): @@ -110,7 +124,7 @@ class AMDComputeQueue(HWQueue): def memory_barrier(self): pf = '' if self.nbio.version[0] == 2 else '0' if self.nbio.version[:2] != (7, 11) else '1' - self.wait_reg_mem(reg_req=getattr(self.nbio, f'regBIF_BX_PF{pf}_GPU_HDP_FLUSH_REQ').addr[0], + self.wait_reg_mem(reg=getattr(self.nbio, f'regBIF_BX_PF{pf}_GPU_HDP_FLUSH_REQ').addr[0], reg_done=getattr(self.nbio, f'regBIF_BX_PF{pf}_GPU_HDP_FLUSH_DONE').addr[0], value=0xffffffff) self.acquire_mem() return self @@ -119,92 +133,178 @@ class AMDComputeQueue(HWQueue): self.wreg(self.gc.regSPI_CONFIG_CNTL, ps_pkr_priority_cntl=3, exp_priority_order=3, gpr_write_priority=0x2c688, enable_sqg_bop_events=int(tracing), enable_sqg_top_events=int(tracing)) + ### PMC ### + + def pmc_reset_counters(self, en=True): + self.set_grbm() + self.wreg(self.gc.regCP_PERFMON_CNTL if self.dev.target[0] <= 11 else self.gc.regCP_PERFMON_CNTL_1, perfmon_state=0) + if en: self.wreg(self.gc.regCP_PERFMON_CNTL if self.dev.target[0] <= 11 else self.gc.regCP_PERFMON_CNTL_1, perfmon_state=1) + return self + + def pmc_start(self, counters): + self.pmc_reset_counters(en=False) + self.wreg(self.gc.regSQ_PERFCOUNTER_CTRL, cs_en=1, ps_en=1, gs_en=1, hs_en=1, **({'vmid_mask':0xffff} if (gfx9:=self.dev.target[0] == 9) else {})) + if self.dev.target[0] >= 11: self.wreg(self.gc.regSQ_PERFCOUNTER_CTRL2, force_en=1, vmid_en=0xffff) + + end_off = 0 + block2pid:dict[str, itertools.count] = collections.defaultdict(lambda: itertools.count()) + for name,block,idx in counters: + # sq block on gfx11+ goes down to wgps + inst_cnt, se_cnt, sa_cnt, wgp_cnt = {"GRBM": (1, 1, 1, 1), "GL2C": (32, 1, 1, 1), "TCC": (16, 1, 1, 1), + "SQ": (1, self.dev.se_cnt // self.dev.xccs) + ((1, 1) if gfx9 else (2, self.dev.iface.props['cu_per_simd_array'] // 2))}[block] + end_off += (rec_size:=prod((self.dev.xccs, inst_cnt, se_cnt, sa_cnt, wgp_cnt)) * 8) + + # gfx11+ and later require even-numbered SQ *_SELECT registers + regsample = f'reg{block}_PERFCOUNTER{(pcid:=next(block2pid[block]))}' + if (regsel:=getattr(self.gc, (f'reg{block}_PERFCOUNTER{(pcid*2) if self.dev.target[0]>=11 and block=="SQ" else pcid}_SELECT'), None)) is None: + raise RuntimeError(f'{block} is out of perfcounter registers: ({regsample} is not found)') + + self.wreg(regsel, perf_sel=idx, **({'simd_mask':0xf, 'sqc_bank_mask':0xf, 'sqc_client_mask':0xf} if gfx9 and block == "SQ" else {})) + self.dev.pmc_sched.append(PMCSample(name, block, self.dev.xccs, inst_cnt, se_cnt, sa_cnt, wgp_cnt, end_off-rec_size, rec_size, regsample)) + + if gfx9: self.wreg(self.gc.regSQ_PERFCOUNTER_MASK, sh0_mask=0xffff, sh1_mask=0xffff) + self.wreg(self.gc.regCOMPUTE_PERFCOUNT_ENABLE, 1) + return self.pmc_reset_counters(en=True) + + def pmc_read(self, buf, sched): + self.set_grbm() + self.wreg(self.gc.regCP_PERFMON_CNTL if self.dev.target[0] <= 11 else self.gc.regCP_PERFMON_CNTL_1, perfmon_state=1, perfmon_sample_enable=1) + + for s in sched: + offset = itertools.count(s.off, step=8) + + for xcc in range(s.xcc): + with self.pred_exec(xcc_mask=1 << xcc): + for inst, se_idx, sa_idx, wgp_idx in itertools.product(range(s.inst), range(s.se), range(s.sa), range(s.wgp)): + self.set_grbm(**({'instance':inst} if s.inst > 1 else ({'se':se_idx}|({'sh':sa_idx, 'wgp':wgp_idx} if self.dev.target[0] != 9 else {})))) + + # Copy counter to memory (src_sel = perf, dst_sel = tc_l2) + lo, hi = getattr(self.gc, f'{s.regsample}_LO'), getattr(self.gc, f'{s.regsample}_HI', None) + self.pkt3(self.pm4.PACKET3_COPY_DATA, (2 << 8) | 4, lo.addr[0], 0, *data64_le(buf.va_addr+(loff:=next(offset)))) + if hi is not None: self.pkt3(self.pm4.PACKET3_COPY_DATA, (2 << 8) | 4, hi.addr[0], 0, *data64_le(buf.va_addr+loff+4)) + + return self.pmc_reset_counters(en=True) + ### SQTT ### + def sqtt_setup_exec(self, prg, global_size): + self.sqtt_userdata(sqtt.struct_rgp_sqtt_marker_pipeline_bind( + _0=sqtt.union_rgp_sqtt_marker_pipeline_bind_0(_0=sqtt.struct_rgp_sqtt_marker_pipeline_bind_0_0( + identifier=sqtt.RGP_SQTT_MARKER_IDENTIFIER_BIND_PIPELINE, bind_point=(__BIND_POINT_COMPUTE:=1))), + _1=sqtt.union_rgp_sqtt_marker_pipeline_bind_1(api_pso_hash=data64_le(prg.libhash[0])))) + + self.sqtt_userdata(sqtt.struct_rgp_sqtt_marker_event( + _0=sqtt.union_rgp_sqtt_marker_event_0(_0=sqtt.struct_rgp_sqtt_marker_event_0_0(has_thread_dims=1)), + _2=sqtt.union_rgp_sqtt_marker_event_2(cmd_id=next(prg.dev.sqtt_next_cmd_id))), *global_size) + + se_cap = max(prod([x if isinstance(x, int) else 1 for x in global_size]) // 4, 1) // 32 + for xcc in range(self.dev.xccs): + with self.pred_exec(xcc_mask=1 << xcc): + for i in range(8 if prg.dev.target >= (11,0,0) else 4): + self.wreg(getattr(self.gc, f'regCOMPUTE_STATIC_THREAD_MGMT_SE{i}'), min(0xffffffff, (1 << (se_cap + (1 if i == 0 else 0))) - 1)) + def sqtt_userdata(self, data, *extra_dwords): data_ints = [x[0] for x in struct.iter_unpack('>12) - self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_SIZE, base_hi=buf0_hi, size=buf0s[se].size>>12) - self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_BASE, base_lo=buf0_lo) - # NOTE: SQTT can only trace instructions on one simd per se, this selects first simd in first wgp in first sa. - # For RGP to display instruction trace it has to see it on first SE. Howerver ACE/MEC/whatever does the dispatching starting with second se, - # and on amdgpu/non-AM it also does weird things with dispatch order inside se: around 7 times out of 10 it starts from the last cu, but - # sometimes not, especially if the kernel has more than one wavefront which means that kernels with small global size might get unlucky and - # be dispatched on something else and not be seen in instruction tracing tab. You can force the wavefronts of a kernel to be dispatched on the - # CUs you want to by disabling other CUs via bits in regCOMPUTE_STATIC_THREAD_MGMT_SE and trace even kernels that only have one wavefront. - self.wreg(self.gc.regSQ_THREAD_TRACE_MASK, wtype_include=self.soc.SQ_TT_WTYPE_INCLUDE_CS_BIT, simd_sel=0, wgp_sel=0, sa_sel=0) - REG_INCLUDE = self.soc.SQ_TT_TOKEN_MASK_SQDEC_BIT | self.soc.SQ_TT_TOKEN_MASK_SHDEC_BIT | self.soc.SQ_TT_TOKEN_MASK_GFXUDEC_BIT | \ - self.soc.SQ_TT_TOKEN_MASK_COMP_BIT | self.soc.SQ_TT_TOKEN_MASK_CONTEXT_BIT | self.soc.SQ_TT_TOKEN_MASK_CONTEXT_BIT - TOKEN_EXCLUDE = 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_PERF_SHIFT - if not (se_mask >> se) & 0b1: - TOKEN_EXCLUDE |= 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_VMEMEXEC_SHIFT | 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_ALUEXEC_SHIFT | \ - 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_VALUINST_SHIFT | 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_IMMEDIATE_SHIFT | \ - 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_INST_SHIFT - self.wreg(self.gc.regSQ_THREAD_TRACE_TOKEN_MASK, reg_include=REG_INCLUDE, token_exclude=TOKEN_EXCLUDE, bop_events_token_include=1) - # Enable SQTT - self.sqtt_config(tracing=True) - # Restore global broadcasting - self.wreg(self.gc.regGRBM_GFX_INDEX, se_broadcast_writes=1, sa_broadcast_writes=1, instance_broadcast_writes=1) - self.wreg(self.gc.regCOMPUTE_THREAD_TRACE_ENABLE, 1) + if self.dev.target[0] == 9: + self.set_grbm() + self.wreg(self.gc.regSQ_THREAD_TRACE_MASK, simd_en=0xf, cu_sel=0, sq_stall_en=1, spi_stall_en=1, reg_stall_en=1, vm_id_mask=0) + for se in range(len(buf0s)): + mask = (__SQTT_MISC:=1<<0) | (__SQTT_TIME:=1<<1) | (__SQTT_REG:=1<<2) | (__SQTT_WAVE_START:=1<<3) | (__SQTT_WAVE_END:=1<<6) \ + | (__SQTT_USERDATA:=1<<12) | (__SQTT_REG_CS:=1<<5) | (__SQTT_REG_CS_PRIV:=1<<15) + if (SQTT_ITRACE_SE_MASK.value >> se) & 0b1: mask |= (__SQTTINST:=1<<10) | (__SQTT_INST_PC:=1<<11) | (__SQTT_ISSUE:=1<<13) + + with self.pred_exec(xcc_mask=1<<(se // (ses_per_xcc:=(self.dev.se_cnt // self.dev.xccs)))): + self.set_grbm(se=se % ses_per_xcc, sh=0) + self.wreg(self.gc.regSQ_THREAD_TRACE_TOKEN_MASK, reg_mask=0xf, token_mask=mask) + self.wreg(self.gc.regSQ_THREAD_TRACE_TOKEN_MASK2, inst_mask=0xffffffff) + self.wreg(self.gc.regSQ_THREAD_TRACE_BASE, addr=lo32(buf0s[se].va_addr >> 12)) + self.wreg(self.gc.regSQ_THREAD_TRACE_BASE2, addr_hi=hi32(buf0s[se].va_addr >> 12)) + self.wreg(self.gc.regSQ_THREAD_TRACE_SIZE, size=buf0s[se].size >> 12) + self.wreg(self.gc.regSQ_THREAD_TRACE_CTRL, reset_buffer=1) + self.wreg(self.gc.regSQ_THREAD_TRACE_MODE, mask_cs=1, autoflush_en=1, mode=1) + else: + self.spi_config(tracing=True) + # One buffer for one SE, mesa does it with a single buffer and ac_sqtt_get_data_offset, but this is simpler and should work just as well + for se in range(len(buf0s)): + self.set_grbm(se=se, sh=0) + + buf0_lo, buf0_hi = data64_le(buf0s[se].va_addr >> 12) + if self.dev.target >= (12,0,0): + self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_SIZE, size=buf0s[se].size >> 12) + self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_BASE_LO, base_lo=buf0_lo) + self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_BASE_HI, base_hi=buf0_hi) + else: + self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_SIZE, base_hi=buf0_hi, size=buf0s[se].size >> 12) + self.wreg(self.gc.regSQ_THREAD_TRACE_BUF0_BASE, base_lo=buf0_lo) + # NOTE: SQTT can only trace instructions on one simd per se, this selects first simd in first wgp in first sa. + # For RGP to display instruction trace it has to see it on first SE. Howerver ACE/MEC/whatever does the dispatching starting with second se, + # and on amdgpu/non-AM it also does weird things with dispatch order inside se: around 7 times out of 10 it starts from the last cu, but + # sometimes not, especially if the kernel has more than one wavefront which means that kernels with small global size might get unlucky and + # be dispatched on something else and not be seen in instruction tracing tab. You can force the wavefronts of a kernel to be dispatched on the + # CUs you want to by disabling other CUs via bits in regCOMPUTE_STATIC_THREAD_MGMT_SE and trace even kernels that only have one wavefront. + cs_wtype = (1 << 6) if self.dev.target >= (12,0,0) else self.soc.SQ_TT_WTYPE_INCLUDE_CS_BIT + self.wreg(self.gc.regSQ_THREAD_TRACE_MASK, wtype_include=cs_wtype, simd_sel=0, wgp_sel=0, sa_sel=0) + reg_include = self.soc.SQ_TT_TOKEN_MASK_SQDEC_BIT | self.soc.SQ_TT_TOKEN_MASK_SHDEC_BIT | self.soc.SQ_TT_TOKEN_MASK_GFXUDEC_BIT | \ + self.soc.SQ_TT_TOKEN_MASK_COMP_BIT | self.soc.SQ_TT_TOKEN_MASK_CONTEXT_BIT + token_exclude = (1 << self.soc.SQ_TT_TOKEN_EXCLUDE_PERF_SHIFT) if self.dev.target < (12,0,0) else 0 + + # disable instr tracing + if not (SQTT_ITRACE_SE_MASK.value >> se) & 0b1: + # gfx12 doesn't have enums with all fields, so it's hardcoded, but it's the same as gfx11. + token_exclude |= (1 << self.soc.SQ_TT_TOKEN_EXCLUDE_VMEMEXEC_SHIFT | 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_ALUEXEC_SHIFT | \ + 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_VALUINST_SHIFT | 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_IMMEDIATE_SHIFT | \ + 1 << self.soc.SQ_TT_TOKEN_EXCLUDE_INST_SHIFT) if self.dev.target < (12,0,0) else 0x927 + + self.wreg(self.gc.regSQ_THREAD_TRACE_TOKEN_MASK, reg_include=reg_include, token_exclude=token_exclude, bop_events_token_include=1, + **({} if self.dev.target < (12,0,0) else {'exclude_barrier_wait': 1})) + self.sqtt_config(tracing=True) + + self.set_grbm() + if self.dev.target[0] > 9: self.wreg(self.gc.regCOMPUTE_THREAD_TRACE_ENABLE, 1) self.memory_barrier() return self # Magic values from src/amd/common/ac_sqtt.c:ac_sqtt_emit_stop and src/amd/common/ac_sqtt.c:ac_sqtt_emit_wait - def sqtt_stop(self, ses: int, wptrs: HCQBuffer): + def sqtt_stop(self, wptrs:HCQBuffer): self.memory_barrier() + self.set_grbm() + # Start shutting everything down - self.wreg(self.gc.regCOMPUTE_THREAD_TRACE_ENABLE, 0) - self.pkt3(self.pm4.PACKET3_EVENT_WRITE, self.pm4.EVENT_TYPE(self.soc.THREAD_TRACE_FINISH) | self.pm4.EVENT_INDEX(0)) + if self.dev.target[0] == 9: self.wreg(self.gc.regSQ_THREAD_TRACE_MODE, mask_cs=1, autoflush_en=1, mode=0) + else: + self.wreg(self.gc.regCOMPUTE_THREAD_TRACE_ENABLE, 0) + self.pkt3(self.pm4.PACKET3_EVENT_WRITE, self.pm4.EVENT_TYPE(self.soc.THREAD_TRACE_FINISH) | self.pm4.EVENT_INDEX(0)) + # For each SE wait for finish to complete and copy regSQ_THREAD_TRACE_WPTR to know where in the buffer trace data ends - for se in range(ses): - self.wreg(self.gc.regGRBM_GFX_INDEX, se_index=se, instance_broadcast_writes=1) - # Wait for FINISH_PENDING==0 - self.pkt3(self.pm4.PACKET3_WAIT_REG_MEM, self.pm4.WAIT_REG_MEM_FUNCTION(WAIT_REG_MEM_FUNCTION_EQ), - self.gc.regSQ_THREAD_TRACE_STATUS.addr[0], 0, 0, self.gc.regSQ_THREAD_TRACE_STATUS.fields_mask('finish_pending'), 4) - # Wait for FINISH_DONE!=0 - self.pkt3(self.pm4.PACKET3_WAIT_REG_MEM, self.pm4.WAIT_REG_MEM_FUNCTION(WAIT_REG_MEM_FUNCTION_NEQ), - self.gc.regSQ_THREAD_TRACE_STATUS.addr[0], 0, 0, self.gc.regSQ_THREAD_TRACE_STATUS.fields_mask('finish_done'), 4) - # Disable SQTT - self.sqtt_config(tracing=False) - # Wait for BUSY==0 - self.pkt3(self.pm4.PACKET3_WAIT_REG_MEM, self.pm4.WAIT_REG_MEM_FUNCTION(WAIT_REG_MEM_FUNCTION_EQ), - self.gc.regSQ_THREAD_TRACE_STATUS.addr[0], 0, 0, self.gc.regSQ_THREAD_TRACE_STATUS.fields_mask('busy'), 4) - # Copy WPTR to memory (src_sel = perf, dst_sel = tc_l2, wr_confirm = True) - self.pkt3(self.pm4.PACKET3_COPY_DATA, 1 << 20 | 2 << 8 | 4, self.gc.regSQ_THREAD_TRACE_WPTR.addr[0], 0, *data64_le(wptrs.va_addr+(se*4))) - # Restore global broadcasting - self.wreg(self.gc.regGRBM_GFX_INDEX, se_broadcast_writes=1, sa_broadcast_writes=1, instance_broadcast_writes=1) - self.spi_config(tracing=False) + for se in range(self.dev.se_cnt): + with self.pred_exec(xcc_mask=1<<(se // (ses_per_xcc:=(self.dev.se_cnt // self.dev.xccs)))): + self.set_grbm(se=se % ses_per_xcc, sh=0) + + regstatus = self.gc.regSQ_THREAD_TRACE_STATUS.addr[0] - (self.pm4.PACKET3_SET_UCONFIG_REG_START if self.dev.target[0] == 9 else 0) + if self.dev.target >= (10,0,0): + self.wait_reg_mem(reg=regstatus, mask=self.gc.regSQ_THREAD_TRACE_STATUS.fields_mask('finish_pending'), op=WAIT_REG_MEM_FUNCTION_EQ, value=0) + self.sqtt_config(tracing=False) + self.wait_reg_mem(reg=regstatus, mask=self.gc.regSQ_THREAD_TRACE_STATUS.fields_mask('busy'), op=WAIT_REG_MEM_FUNCTION_EQ, value=0) + self.pkt3(self.pm4.PACKET3_EVENT_WRITE, self.pm4.EVENT_TYPE(self.soc.CS_PARTIAL_FLUSH) | self.pm4.EVENT_INDEX(EVENT_INDEX_PARTIAL_FLUSH)) + + # Copy WPTR to memory (src_sel = perf, dst_sel = tc_l2, wr_confirm = True) + self.pkt3(self.pm4.PACKET3_COPY_DATA, 1 << 20 | 2 << 8 | 4, self.gc.regSQ_THREAD_TRACE_WPTR.addr[0], 0, *data64_le(wptrs.va_addr+(se*4))) + + self.set_grbm() + if self.dev.target[0] > 9: self.spi_config(tracing=False) self.memory_barrier() return self - def sqtt_prg_marker(self, prg:AMDProgram, global_size:tuple[sint, ...]): - BIND_POINT_COMPUTE = 1 - - self.sqtt_userdata(sqtt.struct_rgp_sqtt_marker_pipeline_bind( - _0=sqtt.union_rgp_sqtt_marker_pipeline_bind_0(_0=sqtt.struct_rgp_sqtt_marker_pipeline_bind_0_0( - identifier=sqtt.RGP_SQTT_MARKER_IDENTIFIER_BIND_PIPELINE, bind_point=BIND_POINT_COMPUTE)), - _1=sqtt.union_rgp_sqtt_marker_pipeline_bind_1(api_pso_hash=data64_le(prg.libhash[0])))) - - self.sqtt_userdata(sqtt.struct_rgp_sqtt_marker_event( - _0=sqtt.union_rgp_sqtt_marker_event_0(_0=sqtt.struct_rgp_sqtt_marker_event_0_0(has_thread_dims=1)), - _2=sqtt.union_rgp_sqtt_marker_event_2(cmd_id=prg.dev.cmd_id)), *global_size) - - prg.dev.cmd_id += 1 - def exec(self, prg:AMDProgram, args_state:CLikeArgsState, global_size:tuple[sint, ...], local_size:tuple[sint, ...]): self.bind_args_state(args_state) @@ -212,7 +312,7 @@ class AMDComputeQueue(HWQueue): user_regs = [] if prg.enable_private_segment_sgpr: - assert self.dev.xccs == 1, "Only architected flat scratch is suppored on multi-xcc" + assert self.dev.xccs == 1, "Only architected flat scratch is supported on multi-xcc" scratch_hilo = data64_le(prg.dev.scratch.va_addr) # sgpr word1 bit31 enables swizzle # sgpr word3 = 0x14 << 12 | 2 << 28 | 2 << 21 | 1 << 23 @@ -228,7 +328,7 @@ class AMDComputeQueue(HWQueue): user_regs += [*data64_le(args_state.buf.va_addr)] - if prg.dev.sqtt_enabled: self.sqtt_prg_marker(prg, global_size) + if prg.dev.sqtt_enabled: self.sqtt_setup_exec(prg, global_size) self.wreg(self.gc.regCOMPUTE_PGM_LO, *data64_le(prg.prog_addr >> 8)) self.wreg(self.gc.regCOMPUTE_PGM_RSRC1, prg.rsrc1, prg.rsrc2) @@ -244,18 +344,13 @@ class AMDComputeQueue(HWQueue): if (10,0,0) <= prg.dev.target < (11,0,0): self.wreg(self.gc.mmCP_COHER_START_DELAY, 0x20) self.wreg(self.gc.regCOMPUTE_RESTART_X, 0, 0, 0) - self.wreg(self.gc.regCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xFFFFFFFF, 0xFFFFFFFF) - self.wreg(self.gc.regCOMPUTE_STATIC_THREAD_MGMT_SE2, 0xFFFFFFFF, 0xFFFFFFFF) - if prg.dev.target >= (11,0,0): self.wreg(self.gc.regCOMPUTE_STATIC_THREAD_MGMT_SE4, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) - self.wreg(self.gc.regCOMPUTE_USER_DATA_0, *user_regs) self.wreg(self.gc.regCOMPUTE_RESOURCE_LIMITS, 0) - self.wreg(self.gc.regCOMPUTE_START_X, 0, 0, 0, *local_size, 0, 0) gfx10p = {'cs_w32_en': int(prg.wave32)} if prg.dev.target >= (10,0,0) else {} - DISPATCH_INITIATOR = self.gc.regCOMPUTE_DISPATCH_INITIATOR.encode(**gfx10p, force_start_at_000=1, compute_shader_en=1) - self.pkt3(self.pm4.PACKET3_DISPATCH_DIRECT, *global_size, DISPATCH_INITIATOR) + self.pkt3(self.pm4.PACKET3_DISPATCH_DIRECT, *global_size, + self.gc.regCOMPUTE_DISPATCH_INITIATOR.encode(**gfx10p, force_start_at_000=1, compute_shader_en=1)) if prg.dev.sqtt_enabled: self.pkt3(self.pm4.PACKET3_EVENT_WRITE, self.pm4.EVENT_TYPE(self.soc.THREAD_TRACE_MARKER) | self.pm4.EVENT_INDEX(0)) self.pkt3(self.pm4.PACKET3_EVENT_WRITE, self.pm4.EVENT_TYPE(self.soc.CS_PARTIAL_FLUSH) | self.pm4.EVENT_INDEX(EVENT_INDEX_PARTIAL_FLUSH)) @@ -268,6 +363,7 @@ class AMDComputeQueue(HWQueue): def timestamp(self, signal:AMDSignal): with self.pred_exec(xcc_mask=0b1): self.release_mem(signal.timestamp_addr, 0, self.pm4.data_sel__mec_release_mem__send_gpu_clock_counter, self.pm4.int_sel__mec_release_mem__none) + self.acquire_mem() # ensure timestamp is written return self def signal(self, signal:AMDSignal, value:sint=0): @@ -310,6 +406,7 @@ class AMDComputeQueue(HWQueue): class AMDComputeAQLQueue(AMDComputeQueue): def exec(self, prg:AMDProgram, args_state:CLikeArgsState, global_size:tuple[sint, ...], local_size:tuple[sint, ...]): self.bind_args_state(args_state) + if prg.dev.sqtt_enabled: self.sqtt_setup_exec(prg, global_size) self._q.append(pkt:=hsa.hsa_kernel_dispatch_packet_t(header=AQL_HDR | (hsa.HSA_PACKET_TYPE_KERNEL_DISPATCH << hsa.HSA_PACKET_HEADER_TYPE), setup=3<= 5: print(f'\t{self.dev.device}: SE {se} blob size {wptr:#x}') + assert wptr >= 0 and wptr <= buf.size, f"{wptr} > {buf.size}, should never happen" + + # When sqtt buffer overflows, wptr stops at the last dword + if wptr >= buf.size - 32: + print(colored(f"{self.dev.device}: Warning: SQTT buffer is full (SE {se})! Increase SQTT buffer with SQTT_BUFFER_SIZE=X (in MB)", "yellow")) + + self.dev.allocator._copyout(sqtt_mv:=memoryview(bytearray(wptr)), buf) + resbuf = (struct.pack('> se) & 1))] + return res + class AMDAllocator(HCQAllocator['AMDDevice']): def __init__(self, dev:AMDDevice): super().__init__(dev, copy_bufs=getattr(dev.iface, 'copy_bufs', None), max_copyout_size=0x1000 if dev.is_usb() else None) @@ -499,9 +625,6 @@ class AMDAllocator(HCQAllocator['AMDDevice']): def _map(self, buf:HCQBuffer): return self.dev.iface.map(buf._base if buf._base is not None else buf) -@dataclass(frozen=True) -class ProfileSQTTEvent(ProfileEvent): device:str; se:int; blob:bytes; itrace:bool # noqa: E702 - @dataclass class AMDQueueDesc: ring: MMIOInterface @@ -541,23 +664,22 @@ class KFDIface: if KFDIface.kfd is None: KFDIface.kfd = FileIOInterface("/dev/kfd", os.O_RDWR) gpus = [g for g in FileIOInterface(kfd_topo_path).listdir() if self._is_usable_gpu(FileIOInterface(f"{kfd_topo_path}/{g}/gpu_id"))] - gpus = sorted(gpus, key=lambda x: int(x.split('/')[-1])) - visible_devices = [int(x) for x in (getenv('VISIBLE_DEVICES', getenv('HIP_VISIBLE_DEVICES', ''))).split(',') if x.strip()] - KFDIface.gpus = [gpus[x] for x in visible_devices] if visible_devices else gpus + KFDIface.gpus = hcq_filter_visible_devices(sorted(gpus, key=lambda x: int(x.split('/')[-1]))) if device_id >= len(KFDIface.gpus): raise RuntimeError(f"No device found for {device_id}. Requesting more devices than the system has?") self.gpu_id = int(FileIOInterface(f"{kfd_topo_path}/{KFDIface.gpus[device_id]}/gpu_id").read()) self.props = {(p:=l.split())[0]: int(p[1]) for l in FileIOInterface(f"{kfd_topo_path}/{KFDIface.gpus[device_id]}/properties").read().splitlines()} - ip_base = f"/sys/class/drm/renderD{self.props['drm_render_minor']}/device/ip_discovery/die/0" + self.dev_sysfs_path = f"/sys/class/drm/renderD{self.props['drm_render_minor']}/device" + ip_base = f"{self.dev_sysfs_path}/ip_discovery/die/0" id2ip = {am.GC_HWID: am.GC_HWIP, am.SDMA0_HWID: am.SDMA0_HWIP, am.NBIF_HWID: am.NBIF_HWIP} ip_hw = [(id2ip[int(hwid)], int(hwid)) for hwid in FileIOInterface(ip_base).listdir() if hwid.isnumeric() and int(hwid) in id2ip] self.ip_versions = {ip:tuple(int(FileIOInterface(f'{ip_base}/{hw}/0/{part}').read()) for part in ['major','minor','revision']) for ip,hw in ip_hw} - self.ip_offsets = {ip:{int(i):tuple(int(x, 16) for x in FileIOInterface(f'{ip_base}/{hw}/{i}/base_addr').read().splitlines()) - for i in FileIOInterface(f'{ip_base}/{hw}').listdir()} for ip,hw in ip_hw } self.drm_fd = FileIOInterface(f"/dev/dri/renderD{self.props['drm_render_minor']}", os.O_RDWR) + self.kfd_ver = ((ver_st:=kfd.AMDKFD_IOC_GET_VERSION(KFDIface.kfd)).major_version, ver_st.minor_version) kfd.AMDKFD_IOC_ACQUIRE_VM(KFDIface.kfd, drm_fd=self.drm_fd.fd, gpu_id=self.gpu_id) + if self.kfd_ver >= (1,14): kfd.AMDKFD_IOC_RUNTIME_ENABLE(KFDIface.kfd, mode_mask=0) # Set these for our device. if KFDIface.event_page is None: @@ -657,23 +779,28 @@ class KFDIface: raise RuntimeError("\n".join(report)) + def is_in_profile_mode(self): + return self.dev.target[0] == 9 or FileIOInterface(f'{self.dev_sysfs_path}/power_dpm_force_performance_level').read()[:16] == 'profile_standard' + class PCIIface(PCIIfaceBase): gpus:ClassVar[list[str]] = [] def __init__(self, dev, dev_id): - super().__init__(dev, dev_id, vendor=0x1002, devices=[0x744c, 0x7480, 0x7550], bars=[0, 2, 5], vram_bar=0, + super().__init__(dev, dev_id, vendor=0x1002, devices=[(0xffff, [0x744c, 0x7480, 0x7550, 0x7590])], bars=[0, 2, 5], vram_bar=0, va_start=AMMemoryManager.va_allocator.base, va_size=AMMemoryManager.va_allocator.size) - self._setup_adev(self.pci_dev.pcibus, self.pci_dev.map_bar(0), self.pci_dev.map_bar(2, fmt='Q'), self.pci_dev.map_bar(5, fmt='I')) + self._setup_adev(self.pci_dev) self.pci_dev.write_config(pci.PCI_COMMAND, self.pci_dev.read_config(pci.PCI_COMMAND, 2) | pci.PCI_COMMAND_MASTER, 2) - def _setup_adev(self, name, vram:MMIOInterface, doorbell:MMIOInterface, mmio:MMIOInterface, dma_regions:list[tuple[int, MMIOInterface]]|None=None): - self.dev_impl:AMDev = AMDev(name, vram, doorbell, mmio, dma_regions) - self.ip_offsets, self.ip_versions = self.dev_impl.regs_offset, self.dev_impl.ip_ver + def is_in_profile_mode(self): return True + + def _setup_adev(self, pci_dev:PCIDevice, dma_regions:list[tuple[int, MMIOInterface]]|None=None): + self.dev_impl:AMDev = AMDev(pci_dev, dma_regions) + self.ip_versions = self.dev_impl.ip_ver gfxver = int(f"{self.dev_impl.ip_ver[am.GC_HWIP][0]:02d}{self.dev_impl.ip_ver[am.GC_HWIP][1]:02d}{self.dev_impl.ip_ver[am.GC_HWIP][2]:02d}") array_count = self.dev_impl.gc_info.gc_num_sa_per_se * self.dev_impl.gc_info.gc_num_se - simd_count = 2 * array_count * (self.dev_impl.gc_info.gc_num_wgp0_per_sa + self.dev_impl.gc_info.gc_num_wgp1_per_sa) - self.props = {'simd_count': 2 * simd_count, 'simd_per_cu': 2, 'array_count': array_count, 'gfx_target_version': gfxver, + self.props = {'cu_per_simd_array': (cu_per_sa:=2 * (self.dev_impl.gc_info.gc_num_wgp0_per_sa + self.dev_impl.gc_info.gc_num_wgp1_per_sa)), + 'simd_count': 2 * cu_per_sa * array_count, 'simd_per_cu': 2, 'array_count': array_count, 'gfx_target_version': gfxver, 'max_slots_scratch_cu': self.dev_impl.gc_info.gc_max_scratch_slots_per_cu, 'max_waves_per_simd': self.dev_impl.gc_info.gc_max_waves_per_simd, 'simd_arrays_per_engine': self.dev_impl.gc_info.gc_num_sa_per_se, 'lds_size_in_kb': self.dev_impl.gc_info.gc_lds_size} @@ -692,7 +819,7 @@ class PCIIface(PCIIfaceBase): read_ptrs=[gart.cpu_view().view(offset=rptr, size=8, fmt='Q')], write_ptrs=[gart.cpu_view().view(offset=wptr, size=8, fmt='Q')]) def sleep(self, timeout): - if self.pci_dev.irq_poller is not None and (events_cnt:=len(self.pci_dev.irq_poller.poll(timeout))): + if hasattr(self.pci_dev, 'irq_poller') and self.pci_dev.irq_poller is not None and (events_cnt:=len(self.pci_dev.irq_poller.poll(timeout))): self.pci_dev.irq_fd.read(8 * events_cnt) self.dev_impl.ih.interrupt_handler() @@ -704,35 +831,30 @@ class PCIIface(PCIIfaceBase): def device_fini(self): self.dev_impl.fini() class USBIface(PCIIface): - def __init__(self, dev, dev_id): - self.dev = dev - self.usb = ASM24Controller() - self.bars = setup_pci_bars(self.usb, gpu_bus=4, mem_base=0x10000000, pref_mem_base=(32 << 30)) - - self._setup_adev(f"usb:{dev_id}", USBMMIOInterface(self.usb, *self.bars[0], fmt='B'), USBMMIOInterface(self.usb, *self.bars[2], fmt='Q'), - USBMMIOInterface(self.usb, *self.bars[5], fmt='I'), dma_regions=[(0x200000, self._dma_view(0xf000, 0x80000))]) - self.usb._pci_cacheable += [self.bars[2]] # doorbell region is cacheable + def __init__(self, dev, dev_id): # pylint: disable=super-init-not-called + self.dev, self.pci_dev = dev, USBPCIDevice(dev.__class__.__name__[:2], f"usb:{dev_id}", bars=[0, 2, 5]) + self._setup_adev(self.pci_dev, dma_regions=[(0x200000, self.pci_dev.dma_view(0xf000, 0x80000))]) + self.pci_dev.usb._pci_cacheable += [(self.pci_dev.bar_info[2].addr, self.pci_dev.bar_info[2].size)] # doorbell region is cacheable # special regions self.copy_bufs = [self._dma_region(ctrl_addr=0xf000, sys_addr=0x200000, size=0x80000)] self.sys_buf, self.sys_next_off = self._dma_region(ctrl_addr=0xa000, sys_addr=0x820000, size=0x1000), 0x800 - def _dma_view(self, ctrl_addr, size): return USBMMIOInterface(self.usb, ctrl_addr, size, fmt='B', pcimem=False) def _dma_region(self, ctrl_addr, sys_addr, size): region = self.dev_impl.mm.map_range(vaddr:=self.dev_impl.mm.alloc_vaddr(size=size), size, [(sys_addr, size)], system=True, uncached=True) - return HCQBuffer(vaddr, size, meta=PCIAllocationMeta(region, has_cpu_mapping=False), view=self._dma_view(ctrl_addr, size), owner=self.dev) + return HCQBuffer(vaddr, size, meta=PCIAllocationMeta(region, has_cpu_mapping=False), view=self.pci_dev.dma_view(ctrl_addr, size), owner=self.dev) def alloc(self, size:int, host=False, uncached=False, cpu_access=False, contiguous=False, **kwargs) -> HCQBuffer: if (host or (uncached and cpu_access)) and self.sys_next_off + size < self.sys_buf.size: self.sys_next_off += size return self.sys_buf.offset(self.sys_next_off - size, size) - am_mapping = self.dev_impl.mm.valloc(size:=round_up(size, 4 << 10), uncached=uncached, contiguous=cpu_access) - return HCQBuffer(am_mapping.va_addr, size, meta=PCIAllocationMeta(am_mapping, has_cpu_mapping=False), - view=USBMMIOInterface(self.usb, self.bars[0][0] + am_mapping.paddrs[0][0], size, fmt='B') if cpu_access else None, owner=self.dev) + mapping = self.dev_impl.mm.valloc(size:=round_up(size, 4 << 10), uncached=uncached, contiguous=cpu_access) + barview = self.pci_dev.map_bar(bar=0, off=mapping.paddrs[0][0], size=mapping.size) if cpu_access else None + return HCQBuffer(mapping.va_addr, size, meta=PCIAllocationMeta(mapping, has_cpu_mapping=False), view=barview, owner=self.dev) def create_queue(self, queue_type, ring, gart, rptr, wptr, eop_buffer=None, cwsr_buffer=None, ctl_stack_size=0, ctx_save_restore_size=0, xcc_id=0): - if queue_type == kfd.KFD_IOC_QUEUE_TYPE_COMPUTE: self.usb._pci_cacheable += [(ring.cpu_view().addr, ring.size)] + if queue_type == kfd.KFD_IOC_QUEUE_TYPE_COMPUTE: self.pci_dev.usb._pci_cacheable += [(ring.cpu_view().addr, ring.size)] return super().create_queue(queue_type, ring, gart, rptr, wptr, eop_buffer, cwsr_buffer, ctl_stack_size, ctx_save_restore_size, xcc_id) def sleep(self, timeout): pass @@ -749,9 +871,10 @@ class AMDDevice(HCQCompiled): if self.target < (9,4,2) or self.target >= (13,0,0): raise RuntimeError(f"Unsupported arch: {self.arch}") if DEBUG >= 1: print(f"AMDDevice: opening {self.device_id} with target {self.target} arch {self.arch}") + self.se_cnt = self.iface.props['array_count'] // self.iface.props['simd_arrays_per_engine'] self.max_cu_id = self.iface.props['simd_count'] // self.iface.props['simd_per_cu'] // self.iface.props.get('num_xcc', 1) - 1 self.max_wave_id = (self.iface.props['max_waves_per_simd'] * self.iface.props['simd_per_cu'] - 1) if self.target >= (10,1,0) else \ - (min((self.max_cu_id+1)*40, self.iface.props['array_count'] // self.iface.props['simd_arrays_per_engine'] * 512) - 1) + (min((self.max_cu_id+1)*40, self.se_cnt * 512) - 1) self.xccs = self.iface.props.get('num_xcc', 1) if getenv("XCCS", 1) else 1 # this is what llvm refers to as "architected flat scratch" self.has_scratch_base_registers = self.target >= (11,0,0) or self.target in {(9,4,2), (9,5,0)} @@ -767,14 +890,15 @@ class AMDDevice(HCQCompiled): debug_memory_size = round_up((self.max_cu_id + 1 if self.target >= (10,1,0) else 1) * (self.max_wave_id + 1) * 32, 64) if self.target[0] == 10: ctl_stack_size = min(ctl_stack_size, 0x7000) + self.ip_off = import_ip_offsets(self.target) self.soc = import_soc(self.target) self.pm4 = importlib.import_module(f"tinygrad.runtime.autogen.am.pm4_{'nv' if self.target[0] >= 10 else 'soc15'}") self.sdma = import_module('sdma', min(self.iface.ip_versions[am.SDMA0_HWIP], (6, 0, 0))) - self.gc = AMDIP('gc', self.iface.ip_versions[am.GC_HWIP], self.iface.ip_offsets[am.GC_HWIP]) + self.gc = AMDIP('gc', self.iface.ip_versions[am.GC_HWIP], + bases={i: tuple(getattr(self.ip_off, f'GC_BASE__INST{i}_SEG{s}', 0) for s in range(6)) for i in range(6)}) - nbio_name = 'nbio' if self.target[0] < 12 else 'nbif' - nbio_pad = (0,) if self.target[0] == 9 else () - self.nbio = AMDIP(nbio_name, self.iface.ip_versions[am.NBIF_HWIP], {i:nbio_pad+x for i,x in self.iface.ip_offsets[am.NBIF_HWIP].items()}) + self.nbio = AMDIP('nbio' if self.target[0] < 12 else 'nbif', self.iface.ip_versions[am.NBIF_HWIP], + bases={i: tuple(getattr(self.ip_off, f'NBIO_BASE__INST{i}_SEG{s}', 0) for s in range(9)) for i in range(6)}) self.is_aql = getenv("AMD_AQL", int(self.xccs > 1)) if self.is_aql: @@ -788,8 +912,8 @@ class AMDDevice(HCQCompiled): max_copy_size = 0x40000000 if self.iface.ip_versions[am.SDMA0_HWIP][0] >= 5 else 0x400000 self.sdma_queue = self.create_queue(kfd.KFD_IOC_QUEUE_TYPE_SDMA, 0x200 if self.is_usb() else (16 << 20)) - compilers:list[CompilerPairT] = [(functools.partial(AMDLLVMRenderer, self.arch), functools.partial(AMDLLVMCompiler, self.arch)), - (functools.partial(AMDRenderer, self.arch), functools.partial(HIPCompiler, self.arch))] + compilers:list[CompilerPairT] = [(functools.partial(AMDRenderer, self.arch), functools.partial(HIPCompiler, self.arch)), + (functools.partial(AMDLLVMRenderer, self.arch), functools.partial(AMDLLVMCompiler, self.arch))] super().__init__(device, AMDAllocator(self), compilers, functools.partial(AMDProgram, self), AMDSignal, functools.partial(AMDComputeAQLQueue if self.is_aql else AMDComputeQueue, self), @@ -800,20 +924,33 @@ class AMDDevice(HCQCompiled): self.max_private_segment_size = 0 self._ensure_has_local_memory(128) # set default scratch size to 128 bytes per thread + self.pmc_enabled = PROFILE and PMC > 0 + if self.pmc_enabled: + if self.target[0] not in {9, 11, 12}: raise RuntimeError(f'PMC are not supported on gc:{self.target}') + if not self.iface.is_in_profile_mode(): raise RuntimeError("PMC requires stable power state: run `amd-smi set -l stable_std` for KFD iface") + + self.pmc_sched:list[PMCSample] = [] + self.pmc_counters = import_pmc(self.target) + + # validate counters + pmc_default = "TCC_HIT,TCC_MISS,SQ_LDS_BANK_CONFLICT" if self.target[0] == 9 else "GL2C_HIT,GL2C_MISS,SQC_LDS_IDX_ACTIVE,SQC_LDS_BANK_CONFLICT" + for k in (PMC_COUNTERS:=getenv("PMC_COUNTERS", pmc_default).split(",")): + if k not in self.pmc_counters: raise RuntimeError(f"PMC counter {k} is not supported. Available: {','.join(self.pmc_counters.keys())}") + + cast(AMDComputeQueue, self.hw_compute_queue_t()).pmc_start([(k, *self.pmc_counters[k]) for k in PMC_COUNTERS]).submit(self) + self.pmc_buffer = self.allocator.alloc(self.pmc_sched[-1].off + self.pmc_sched[-1].size, BufferSpec(nolru=True, uncached=True)) + self.allocator._copyin(self.pmc_buffer, memoryview(bytearray(self.pmc_buffer.size))) # zero pmc buffers, some counters have only lo part. + # SQTT is disabled by default because of runtime overhead and big file sizes (~200mb to Tensor.full() two 4096x4096 tensors and matmul them) - self.sqtt_enabled = PROFILE and bool(getenv("SQTT", 0)) + self.sqtt_enabled = PROFILE and SQTT > 0 if self.sqtt_enabled: - if self.arch != 'gfx1100': raise RuntimeError('SQ Thread Tracing is only supported on 7900XTX') - if not self.is_am() and (ppfeaturemask:=int(FileIOInterface('/sys/module/amdgpu/parameters/ppfeaturemask', os.O_RDONLY).read(), 16))&0x8000: - raise RuntimeError("SQTT can't be enabled because of hardware bug, to workaround either use AMD_IFACE=PCI or add " - f"ppfeaturemask={(ppfeaturemask&~0x8000):#x} (current {ppfeaturemask=:#x} & ~PP_GFXOFF_MASK) to amdgpu module parameters\n" - "For more information read https://github.com/tinygrad/tinygrad/blob/master/extra/sqtt/README.md") + if self.target[0] not in {9, 11, 12}: raise RuntimeError(f'SQ Thread Tracing is not supported on gc:{self.target}') + if not self.iface.is_in_profile_mode(): raise RuntimeError("SQTT requires stable power state: run `amd-smi set -l stable_std` for KFD iface") + SQTT_BUFFER_SIZE = getenv("SQTT_BUFFER_SIZE", 256) # in mb, per shader engine - SQTT_NUM = self.iface.props['array_count'] // self.iface.props['simd_arrays_per_engine'] - self.sqtt_buffers = [self.allocator.alloc(SQTT_BUFFER_SIZE*1024*1024, BufferSpec(cpu_access=True, nolru=True)) for _ in range(SQTT_NUM)] - self.sqtt_itrace_se_mask = getenv("SQTT_ITRACE_SE_MASK", 2) # -1 enable all, 0 disable all, >0 bitmask for where to enable instruction tracing - self.cmd_id = 0 - cast(AMDComputeQueue, self.hw_compute_queue_t()).sqtt_start(self.sqtt_buffers, self.sqtt_itrace_se_mask).submit(self) + self.sqtt_buffers = [self.allocator.alloc(SQTT_BUFFER_SIZE << 20, BufferSpec(nolru=True, uncached=True)) for _ in range(self.se_cnt)] + self.sqtt_wptrs = self.allocator.alloc(round_up(self.se_cnt * 4, 0x1000), BufferSpec(cpu_access=True, nolru=True)) + self.sqtt_next_cmd_id = itertools.count(0) def create_queue(self, queue_type, ring_size, ctx_save_restore_size=0, eop_buffer_size=0, ctl_stack_size=0, debug_memory_size=0): ring = self.iface.alloc(ring_size, uncached=True, cpu_access=True) @@ -824,7 +961,7 @@ class AMDDevice(HCQCompiled): read_dispatch_id_field_base_byte_offset=getattr(hsa.amd_queue_t, 'read_dispatch_id').offset, max_cu_id=self.max_cu_id, max_wave_id=self.max_wave_id) gart.cpu_view().view(fmt='B')[:ctypes.sizeof(aql_desc)] = bytes(aql_desc) - self.aql_desc = hsa.amd_queue_t.from_address(gart.va_addr) + self.aql_desc = hsa.amd_queue_t.from_address(gart.cpu_view().addr) cwsr_buffer_size = round_up((ctx_save_restore_size + debug_memory_size) * self.iface.props.get('num_xcc', 1), mmap.PAGESIZE) cwsr_buffer = self.iface.alloc(cwsr_buffer_size) if ctx_save_restore_size else None @@ -843,10 +980,9 @@ class AMDDevice(HCQCompiled): scratch_size = (self.max_cu_id+1)*self.iface.props['max_slots_scratch_cu']*wave_scratch_len # per xcc self.scratch, ok = self._realloc(getattr(self, 'scratch', None), scratch_size*self.xccs) if ok: - engines = self.iface.props['array_count'] // self.iface.props['simd_arrays_per_engine'] waves = wave_scratch_len // (256 if self.target >= (11,0,0) else 1024) # >=gfx11 wavesize is per SE - wavesize = scratch_size // ((wave_scratch_len * engines) if self.target >= (11,0,0) else wave_scratch_len) + wavesize = scratch_size // ((wave_scratch_len * self.se_cnt) if self.target >= (11,0,0) else wave_scratch_len) self.tmpring_size = waves << 12 | wavesize self.max_private_segment_size = required @@ -864,20 +1000,4 @@ class AMDDevice(HCQCompiled): def on_device_hang(self): self.iface.on_device_hang() - def _at_profile_finalize(self): - if self.sqtt_enabled: - wptrs_buf = self.allocator.alloc(round_up(len(self.sqtt_buffers), 0x1000), BufferSpec(cpu_access=True, nolru=True)) - wptrs = to_mv(wptrs_buf.va_addr, wptrs_buf.size) - cast(AMDComputeQueue, self.hw_compute_queue_t()).sqtt_stop(len(self.sqtt_buffers), wptrs_buf) \ - .signal(self.timeline_signal, self.next_timeline()).submit(self) - self.synchronize() - if DEBUG>=2: print('Saving SQTT in profile...') - for i,buf0 in enumerate(self.sqtt_buffers): - wptr = ((struct.unpack('=2: print(f'Se {i} blob size {wptr:#x}') - assert wptr >= 0 and wptr <= buf0.size, f"{wptr} > {buf0.size}, should never happen" - # When sqtt buffer overflows, wptr stops at the last dword - if wptr >= buf0.size-32: print(f"WARNING: SQTT BUFFER IS FULL (SE {i})! INCREASE SQTT BUFFER SIZE WITH SQTT_BUFFER_SIZE=X (in MB)") - self.allocator._copyout(sqtt_buf:=memoryview(bytearray(wptr)), buf0) - Compiled.profile_events += [ProfileSQTTEvent(self.device, i, bytes(sqtt_buf), bool((self.sqtt_itrace_se_mask >> i) & 0b1))] - super()._at_profile_finalize() + def device_props(self): return self.iface.props diff --git a/tinygrad/runtime/ops_cl.py b/tinygrad/runtime/ops_cl.py index 8887c97f00..b89fdedcb4 100644 --- a/tinygrad/runtime/ops_cl.py +++ b/tinygrad/runtime/ops_cl.py @@ -23,10 +23,12 @@ class CLCompiler(Compiler): build_status: int = cl.clBuildProgram(program, 1, self.dev.device_id, None, cl.clBuildProgram.argtypes[4](), None) if build_status != 0: cl.clGetProgramBuildInfo(program, self.dev.device_id, cl.CL_PROGRAM_BUILD_LOG, 0, None, log_size := ctypes.c_size_t()) - cl.clGetProgramBuildInfo(program, self.dev.device_id, cl.CL_PROGRAM_BUILD_LOG, log_size.value, mstr := ctypes.create_string_buffer(log_size.value), None) # noqa: E501 + cl.clGetProgramBuildInfo(program, self.dev.device_id, cl.CL_PROGRAM_BUILD_LOG, + log_size.value, mstr := ctypes.create_string_buffer(log_size.value), None) raise CompileError(f"OpenCL Compile Error\n\n{mstr.value.decode()}") check(cl.clGetProgramInfo(program, cl.CL_PROGRAM_BINARY_SIZES, ctypes.sizeof(ctypes.c_size_t), binary_sizes := (ctypes.c_size_t * 1)(), None)) - check(cl.clGetProgramInfo(program, cl.CL_PROGRAM_BINARIES, ctypes.sizeof(ctypes.c_void_p), (ctypes.c_void_p * 1)(ctypes.addressof(binary := ctypes.create_string_buffer(binary_sizes[0]))), None)) # noqa: E501 + check(cl.clGetProgramInfo(program, cl.CL_PROGRAM_BINARIES, ctypes.sizeof(ctypes.c_void_p), + (ctypes.c_void_p * 1)(ctypes.addressof(binary := ctypes.create_string_buffer(binary_sizes[0]))), None)) check(cl.clReleaseProgram(program)) return bytes(binary) @@ -97,16 +99,22 @@ class CLDevice(Compiled): err = cl.clGetDeviceIDs(platform_ids[0], device_type, 0, None, num_devices := ctypes.c_uint32()) if err == 0 and num_devices.value != 0: break if DEBUG >= 1: print(f"CLDevice: got {num_platforms.value} platforms and {num_devices.value} devices") - CLDevice.device_ids = init_c_var((cl.cl_device_id * num_devices.value)(), lambda x: check(cl.clGetDeviceIDs(platform_ids[0], device_type, num_devices, x, None))) # noqa: E501 + CLDevice.device_ids = init_c_var((cl.cl_device_id * num_devices.value)(), + lambda x: check(cl.clGetDeviceIDs(platform_ids[0], device_type, num_devices, x, None))) self.device_id = CLDevice.device_ids[0 if ":" not in device else int(device.split(":")[1])] - self.device_name = (cl.clGetDeviceInfo(self.device_id, cl.CL_DEVICE_NAME, 256, buf := ctypes.create_string_buffer(256), None), buf.value.decode())[1] # noqa: E501 - self.driver_version = (cl.clGetDeviceInfo(self.device_id, cl.CL_DRIVER_VERSION, 256, buf := ctypes.create_string_buffer(256), None), buf.value.decode())[1] # noqa: E501 + self.device_name = (cl.clGetDeviceInfo(self.device_id, cl.CL_DEVICE_NAME, 256, + buf:=ctypes.create_string_buffer(256), None), buf.value.decode())[1] + self.driver_version = (cl.clGetDeviceInfo(self.device_id, cl.CL_DRIVER_VERSION, 256, + buf:=ctypes.create_string_buffer(256), None), buf.value.decode())[1] if DEBUG >= 1: print(f"CLDevice: opening {self.device_name} with version {self.driver_version}") self.context = checked(cl.clCreateContext(None, 1, self.device_id, cl.clCreateContext.argtypes[3](), None, status := ctypes.c_int32()), status) self.queue = checked(cl.clCreateCommandQueue(self.context, self.device_id, cl.CL_QUEUE_PROFILING_ENABLE, status), status) self.pending_copyin: list[memoryview] = [] - self.device_exts = (cl.clGetDeviceInfo(self.device_id, cl.CL_DEVICE_EXTENSIONS, 4096, ctypes.byref(buf := ctypes.create_string_buffer(4096)), ctypes.byref(total := ctypes.c_size_t())), ctypes.string_at(buf, size=total.value).decode())[1] # noqa: E501 + self.device_exts = (cl.clGetDeviceInfo(self.device_id, cl.CL_DEVICE_EXTENSIONS, 4096, + ctypes.byref(buf := ctypes.create_string_buffer(4096)), + ctypes.byref(total := ctypes.c_size_t())), + ctypes.string_at(buf, size=total.value).decode())[1] compilers = [(IntelRenderer if "cl_intel_subgroup_matrix_multiply_accumulate" in self.device_exts else OpenCLRenderer, functools.partial(CLCompiler, self, f"compile_cl_{hashlib.md5(self.device_name.encode() + self.driver_version.encode()).hexdigest()}"))] diff --git a/tinygrad/runtime/ops_cpu.py b/tinygrad/runtime/ops_cpu.py index 012a9e729e..f2089676a0 100644 --- a/tinygrad/runtime/ops_cpu.py +++ b/tinygrad/runtime/ops_cpu.py @@ -1,11 +1,15 @@ from __future__ import annotations import platform, sys, ctypes, functools, time, mmap, threading, queue -from tinygrad.helpers import from_mv, to_mv, OSX, WIN, mv_address, wait_cond, cpu_profile, suppress_finalizing, unwrap -from tinygrad.device import BufferSpec, DMACPURef +from tinygrad.helpers import from_mv, to_mv, OSX, WIN, mv_address, wait_cond, cpu_profile, suppress_finalizing, unwrap, data64_le +from tinygrad.device import BufferSpec, DMACPURef, CompilerPairT from tinygrad.runtime.support.hcq import HCQCompiled, HCQAllocatorBase, HCQBuffer, HWQueue, HCQArgsState, HCQSignal, HCQProgram, MMIOInterface +from tinygrad.runtime.support.hcq import CLikeArgsState from tinygrad.renderer.cstyle import ClangRenderer from tinygrad.renderer.llvmir import LLVMRenderer +from tinygrad.renderer.nir import LVPRenderer from tinygrad.runtime.support.compiler_cpu import CPULLVMCompiler, ClangJITCompiler +from tinygrad.runtime.support.compiler_mesa import LVPCompiler +from tinygrad.runtime.support.elf import jit_loader from tinygrad.uop.ops import sint class CPUSignal(HCQSignal): @@ -46,12 +50,18 @@ class CPUComputeQueue(HWQueue): def memory_barrier(self): return self def exec(self, prg:CPUProgram, args_state:HCQArgsState, global_size, local_size): + if isinstance(args_state, LVPArgsState): + self.bind_args_state(args_state) + return self.cmd(self._exec, prg, 1, args_state.buf.va_addr) return self.cmd(self._exec, prg, len(args_state.bufs), *[x.va_addr for x in args_state.bufs], *args_state.vals, threads=(global_size or (1,))[0]) def wait(self, signal, value=0): return self.cmd(self._wait, signal.value_addr, value) def timestamp(self, signal): return self.cmd(self._timestamp, signal.timestamp_addr) def signal(self, signal, value:sint=0): return self.cmd(self._signal, signal.value_addr, value) def _submit(self, dev): dev.tasks.put(self._q[:]) +class LVPArgsState(CLikeArgsState): + def __init__(self, buf, prg, bufs, vals=()): super().__init__(buf, prg, bufs, vals, [*data64_le(buf.va_addr + 12), (len(bufs) + len(vals)) * 2]) + # NOTE: MAP_JIT is added to mmap module in python 3.13 MAP_JIT = 0x0800 @@ -61,6 +71,7 @@ class CPUProgram(HCQProgram): except OSError: pass def __init__(self, dev, name:str, lib:bytes): + LVP = isinstance(dev.compiler, LVPCompiler) if sys.platform == "win32": # mypy doesn't understand when WIN is used here PAGE_EXECUTE_READWRITE, MEM_COMMIT, MEM_RESERVE = 0x40, 0x1000, 0x2000 ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p @@ -76,6 +87,7 @@ class CPUProgram(HCQProgram): self.mem = mmap.mmap(-1, len(lib), mmap.MAP_ANON|mmap.MAP_PRIVATE|(MAP_JIT if OSX else 0), mmap.PROT_READ|mmap.PROT_WRITE|mmap.PROT_EXEC) if OSX: unwrap(CPUProgram.rt_lib).pthread_jit_write_protect_np(False) + if LVP: lib = jit_loader(lib, base=ctypes.addressof(ctypes.c_void_p.from_buffer(self.mem)), link_libs=['m']) self.mem.write(lib) if OSX: unwrap(CPUProgram.rt_lib).pthread_jit_write_protect_np(True) @@ -92,7 +104,7 @@ class CPUProgram(HCQProgram): self.fxn = ctypes.CFUNCTYPE(None)(mv_address(self.mem)) - super().__init__(HCQArgsState, dev, name, kernargs_alloc_size=0) + super().__init__(LVPArgsState if LVP else HCQArgsState, dev, name, kernargs_alloc_size=12+256 if LVP else 0) @suppress_finalizing def __del__(self): @@ -105,8 +117,8 @@ class CPUAllocator(HCQAllocatorBase): else: addr = mv_address(buf:=mmap.mmap(-1, size, mmap.MAP_ANON | mmap.MAP_PRIVATE, mmap.PROT_READ | mmap.PROT_WRITE)) return HCQBuffer(va:=addr, sz:=size, meta=buf, view=MMIOInterface(va, sz, fmt='B'), owner=self.dev) def _as_buffer(self, src) -> memoryview: - self.dev.synchronize() - return to_mv(src.va_addr, src.size) + self.dev.synchronize() + return to_mv(src.va_addr, src.size) def _as_dmaref(self, buf): self.dev.synchronize() return DMACPURef(buf.va_addr, buf.size) @@ -123,5 +135,5 @@ class CPUDevice(HCQCompiled): def __init__(self, device:str=""): self.tasks:queue.Queue = queue.Queue() CPUWorker(self, self.tasks, thread_id=0).start() - compilers = [(ClangRenderer, ClangJITCompiler), (LLVMRenderer, CPULLVMCompiler)] + compilers:list[CompilerPairT] = [(ClangRenderer, ClangJITCompiler), (LLVMRenderer, CPULLVMCompiler), (LVPRenderer, LVPCompiler)] super().__init__(device, CPUAllocator(self), compilers, functools.partial(CPUProgram, self), CPUSignal, CPUComputeQueue) diff --git a/tinygrad/runtime/ops_cuda.py b/tinygrad/runtime/ops_cuda.py index 440f68b56b..c20a6763da 100644 --- a/tinygrad/runtime/ops_cuda.py +++ b/tinygrad/runtime/ops_cuda.py @@ -1,16 +1,18 @@ from __future__ import annotations -import ctypes, ctypes.util, functools +import ctypes, functools from tinygrad.helpers import DEBUG, getenv, mv_address, init_c_var, init_c_struct_t, suppress_finalizing from tinygrad.device import Compiled, BufferSpec, LRUAllocator, CompilerPairT from tinygrad.renderer.cstyle import CUDARenderer from tinygrad.renderer.ptx import PTXRenderer from tinygrad.runtime.autogen import cuda -from tinygrad.runtime.support.compiler_cuda import pretty_ptx, CUDACompiler, PTXCompiler +from tinygrad.runtime.support.compiler_cuda import pretty_ptx, CUDACompiler, PTXCompiler, NVCCCompiler if getenv("IOCTL"): import extra.nv_gpu_driver.nv_ioctl # noqa: F401 # pylint: disable=unused-import if MOCKGPU:=getenv("MOCKGPU"): from test.mockgpu.cuda import cuda # type: ignore # pylint: disable=reimported def check(status): - if status != 0: raise RuntimeError(f"CUDA Error {status}, {ctypes.string_at(init_c_var(ctypes.POINTER(ctypes.c_char)(), lambda x: cuda.cuGetErrorString(status, ctypes.byref(x)))).decode()}") # noqa: E501 + if status != 0: + error = ctypes.string_at(init_c_var(ctypes.POINTER(ctypes.c_char)(), lambda x: cuda.cuGetErrorString(status, ctypes.byref(x)))).decode() + raise RuntimeError(f"CUDA Error {status}, {error}") def encode_args(args, vals) -> tuple[ctypes.Structure, ctypes.Array]: c_args = init_c_struct_t(tuple([(f'f{i}', cuda.CUdeviceptr_v2) for i in range(len(args))] + @@ -116,7 +118,8 @@ class CUDADevice(Compiled): from tinygrad.runtime.graph.cuda import CUDAGraph compilers:list[CompilerPairT] = [(functools.partial(CUDARenderer, self.arch), functools.partial(CUDACompiler, self.arch)), - (functools.partial(PTXRenderer, self.arch), functools.partial(PTXCompiler, self.arch))] + (functools.partial(PTXRenderer, self.arch), functools.partial(PTXCompiler, self.arch)), + (functools.partial(CUDARenderer, self.arch), functools.partial(NVCCCompiler, self.arch))] super().__init__(device, CUDAAllocator(self), compilers, functools.partial(CUDAProgram, self), None if MOCKGPU else CUDAGraph) def synchronize(self): diff --git a/tinygrad/runtime/ops_dsp.py b/tinygrad/runtime/ops_dsp.py index d93f14afa8..70e5d31dcc 100644 --- a/tinygrad/runtime/ops_dsp.py +++ b/tinygrad/runtime/ops_dsp.py @@ -5,7 +5,7 @@ from tinygrad.device import BufferSpec, Compiled, Allocator, Compiler from tinygrad.runtime.ops_cpu import CPUAllocator from tinygrad.dtype import dtypes, DType, PtrDType from tinygrad.uop.ops import Ops, UOp -from tinygrad.helpers import getenv, round_up, mv_address, to_mv, cpu_objdump, DEBUG +from tinygrad.helpers import getenv, round_up, mv_address, to_mv, cpu_objdump, system, DEBUG from tinygrad.renderer.cstyle import ClangRenderer from tinygrad.runtime.autogen import libc, qcom_dsp if getenv("IOCTL"): import extra.dsp.run # noqa: F401 # pylint: disable=unused-import @@ -123,10 +123,9 @@ class ClangCompiler(Compiler): def compile(self, src:str) -> bytes: # TODO: remove file write. sadly clang doesn't like the use of /dev/stdout here - with tempfile.NamedTemporaryFile(delete=True) as output_file: - subprocess.check_output([getenv("CC", 'clang'), *self.args, '-O2', '-Wall', '-Werror', '-x', 'c', '-fPIC', '-ffreestanding', '-nostdlib', - '-', '-o', str(output_file.name)], input=src.encode('utf-8')) - return pathlib.Path(output_file.name).read_bytes() + with tempfile.NamedTemporaryFile(delete=True) as f: + system(f"{getenv('CC','clang')} {' '.join(self.args)} -O2 -Wall -Werror -x c -fPIC -ffreestanding -nostdlib - -o {f.name}", input=src.encode()) + return pathlib.Path(f.name).read_bytes() def disassemble(self, lib:bytes): return cpu_objdump(lib, self.objdump_tool) diff --git a/tinygrad/runtime/ops_null.py b/tinygrad/runtime/ops_null.py index c8f5a6b59f..5ff75b2da9 100644 --- a/tinygrad/runtime/ops_null.py +++ b/tinygrad/runtime/ops_null.py @@ -1,9 +1,10 @@ import functools from tinygrad.device import Compiled, Compiler, Allocator from tinygrad.engine.jit import MultiGraphRunner -from tinygrad.renderer.cstyle import CStyleLanguage +from tinygrad.renderer.cstyle import Renderer, CStyleLanguage +from tinygrad.renderer.llvmir import AMDLLVMRenderer from tinygrad.uop.ops import Ops -from tinygrad.helpers import cpu_profile +from tinygrad.helpers import cpu_profile, EMULATE class NullRenderer(CStyleLanguage): device = "NULL" @@ -15,7 +16,7 @@ class NullRenderer(CStyleLanguage): class NullProgram: def __init__(self, device:str, name:str, lib:bytes): self.device, self.name = device, name def __call__(self, *bufs, global_size:tuple[int,int,int]=(1,1,1), local_size:tuple[int,int,int]=(1,1,1), vals:tuple[int, ...]=(), wait=False): - with cpu_profile(self.name, self.device): return 1e-4 + with cpu_profile(self.name, self.device): return 1e-3 class NullAllocator(Allocator['NullDevice']): def _alloc(self, size, options): pass @@ -26,8 +27,14 @@ class NullAllocator(Allocator['NullDevice']): def _offset(self, buf, offset:int, size:int): pass class NullGraph(MultiGraphRunner): - def __call__(self, input_rawbuffers, var_vals, wait=False) -> float|None: return 1e-3 + def __call__(self, input_rawbuffers, var_vals, wait=False) -> float|None: return 1e-1 class NullDevice(Compiled): - def __init__(self, device:str): super().__init__(device, NullAllocator(self), [(NullRenderer, Compiler)], functools.partial(NullProgram, device), - NullGraph) + def __init__(self, device:str): + renderer:functools.partial|type[Renderer] + match str(EMULATE.value): + case "AMD": renderer = functools.partial(AMDLLVMRenderer, "gfx1100") + case "AMD_RDNA4": renderer = functools.partial(AMDLLVMRenderer, "gfx1201") + case "": renderer = NullRenderer + case _: raise RuntimeError(f"can't EMULATE device: {EMULATE.value}") + super().__init__(device, NullAllocator(self), [(renderer, Compiler)], functools.partial(NullProgram, device), NullGraph) diff --git a/tinygrad/runtime/ops_nv.py b/tinygrad/runtime/ops_nv.py index 38dbb4501e..f4c0c997cf 100644 --- a/tinygrad/runtime/ops_nv.py +++ b/tinygrad/runtime/ops_nv.py @@ -4,17 +4,19 @@ assert sys.platform != 'win32' from typing import cast, ClassVar from dataclasses import dataclass from tinygrad.runtime.support.hcq import HCQCompiled, HCQAllocator, HCQBuffer, HWQueue, CLikeArgsState, HCQProgram, HCQSignal, BumpAllocator -from tinygrad.runtime.support.hcq import MMIOInterface, FileIOInterface, MOCKGPU +from tinygrad.runtime.support.hcq import MMIOInterface, FileIOInterface, MOCKGPU, hcq_filter_visible_devices from tinygrad.uop.ops import sint from tinygrad.device import BufferSpec, CompilerPairT from tinygrad.helpers import getenv, mv_address, round_up, data64, data64_le, prod, OSX, to_mv, hi32, lo32, suppress_finalizing from tinygrad.renderer.ptx import PTXRenderer from tinygrad.renderer.cstyle import NVRenderer from tinygrad.runtime.support.compiler_cuda import CUDACompiler, PTXCompiler, NVPTXCompiler, NVCompiler -from tinygrad.runtime.autogen import nv_gpu, pci +from tinygrad.runtime.support.compiler_mesa import NAKCompiler +from tinygrad.runtime.autogen import nv_gpu, pci, mesa from tinygrad.runtime.support.elf import elf_loader from tinygrad.runtime.support.nv.nvdev import NVDev, NVMemoryManager from tinygrad.runtime.support.system import System, PCIIfaceBase, MAP_FIXED +from tinygrad.renderer.nir import NAKRenderer if getenv("IOCTL"): import extra.nv_gpu_driver.nv_ioctl # noqa: F401 # pylint: disable=unused-import def get_error_str(status): return f"{status}: {nv_gpu.nv_status_codes.get(status, 'Unknown error')}" @@ -109,7 +111,7 @@ class NVCommandQueue(HWQueue[HCQSignal, 'NVDevice', 'NVProgram', 'NVArgsState']) def _submit_to_gpfifo(self, dev:NVDevice, gpfifo:GPFifo): if dev == self.binded_device: cmdq_addr = self.hw_page.va_addr else: - cmdq_addr = dev.cmdq_allocator.alloc(len(self._q) * 4) + cmdq_addr = dev.cmdq_allocator.alloc(len(self._q) * 4, 16) cmdq_wptr = (cmdq_addr - dev.cmdq_page.va_addr) // 4 dev.cmdq[cmdq_wptr : cmdq_wptr + len(self._q)] = array.array('I', self._q) @@ -133,7 +135,7 @@ class NVComputeQueue(NVCommandQueue): qmd_buf.cpu_view().view(size=prg.qmd.mv.nbytes, fmt='B')[:] = prg.qmd.mv assert qmd_buf.va_addr < (1 << 40), f"large qmd addr {qmd_buf.va_addr:x}" - qmd = QMD(dev=prg.dev, addr=cast(int, qmd_buf.va_addr)) # Save qmd for later update + qmd = QMD(dev=prg.dev, addr=qmd_buf.cpu_view().addr) # Save qmd for later update self.bind_sints_to_mem(*global_size, mem=qmd_buf.cpu_view(), fmt='I', offset=qmd.field_offset('cta_raster_width' if qmd.ver<4 else 'grid_width')) self.bind_sints_to_mem(*(local_size[:2]), mem=qmd_buf.cpu_view(), fmt='H', offset=qmd.field_offset('cta_thread_dimension0')) @@ -154,10 +156,14 @@ class NVComputeQueue(NVCommandQueue): for i in range(2): if self.active_qmd.read(f'release{i}_enable') == 0: self.active_qmd.write(**{f'release{i}_enable': 1}) - self.bind_sints_to_mem(signal.value_addr, mem=self.active_qmd_buf.cpu_view(), fmt='Q', mask=0xfffffffff, - offset=self.active_qmd.field_offset(f'release{i}_address_lower' if self.active_qmd.ver<4 else f'release_semaphore{i}_addr_lower')) - self.bind_sints_to_mem(value, mem=self.active_qmd_buf.cpu_view(), fmt='Q', - offset=self.active_qmd.field_offset(f'release{i}_payload_lower' if self.active_qmd.ver<4 else f'release_semaphore{i}_payload_lower')) + + addr_off = self.active_qmd.field_offset(f'release{i}_address_lower' if self.active_qmd.ver<4 else f'release_semaphore{i}_addr_lower') + self.bind_sints_to_mem(signal.value_addr & 0xffffffff, mem=self.active_qmd_buf.cpu_view(), fmt='I', offset=addr_off) + self.bind_sints_to_mem(signal.value_addr >> 32, mem=self.active_qmd_buf.cpu_view(), fmt='I', mask=0xf, offset=addr_off+4) + + val_off = self.active_qmd.field_offset(f'release{i}_payload_lower' if self.active_qmd.ver<4 else f'release_semaphore{i}_payload_lower') + self.bind_sints_to_mem(value & 0xffffffff, mem=self.active_qmd_buf.cpu_view(), fmt='I', offset=val_off) + self.bind_sints_to_mem(value >> 32, mem=self.active_qmd_buf.cpu_view(), fmt='I', offset=val_off+4) return self self.nvm(0, nv_gpu.NVC56F_SEM_ADDR_LO, *data64_le(signal.value_addr), *data64_le(value), @@ -185,68 +191,69 @@ class NVCopyQueue(NVCommandQueue): class NVArgsState(CLikeArgsState): def __init__(self, buf:HCQBuffer, prg:NVProgram, bufs:tuple[HCQBuffer, ...], vals:tuple[int, ...]=()): - if MOCKGPU: prg.constbuffer_0[80:82] = [len(bufs), len(vals)] - super().__init__(buf, prg, bufs, vals=vals, prefix=prg.constbuffer_0) + if MOCKGPU: prg.cbuf_0[80:82] = [len(bufs), len(vals)] + super().__init__(buf, prg, bufs, vals=vals, prefix=prg.cbuf_0 or None) class NVProgram(HCQProgram): def __init__(self, dev:NVDevice, name:str, lib:bytes): self.dev, self.name, self.lib = dev, name, lib - - # For MOCKGPU, the lib is PTX code, so some values are emulated. - cbuf0_size = 0 if not MOCKGPU else 0x160 - - if MOCKGPU: image, sections, relocs = memoryview(bytearray(lib) + b'\x00' * (4 - len(lib)%4)).cast("I"), [], [] # type: ignore - else: image, sections, relocs = elf_loader(self.lib, force_section_align=128) - - # NOTE: Ensure at least 4KB of space after the program to mitigate prefetch memory faults. - self.lib_gpu = self.dev.allocator.alloc(round_up(image.nbytes, 0x1000) + 0x1000, buf_spec:=BufferSpec(cpu_access=True)) - - self.prog_addr, self.prog_sz, self.regs_usage, self.shmem_usage, self.lcmem_usage = self.lib_gpu.va_addr, image.nbytes, 0, 0x400, 0 self.constbufs: dict[int, tuple[int, int]] = {0: (0, 0x160)} # dict[constbuf index, tuple[va_addr, size]] - for sh in sections: - if sh.name == f".nv.shared.{self.name}": self.shmem_usage = round_up(0x400 + sh.header.sh_size, 128) - if sh.name == f".text.{self.name}": self.prog_addr, self.prog_sz = self.lib_gpu.va_addr+sh.header.sh_addr, sh.header.sh_size - elif m:=re.match(r'\.nv\.constant(\d+)', sh.name): self.constbufs[int(m.group(1))] = (self.lib_gpu.va_addr+sh.header.sh_addr, sh.header.sh_size) - elif sh.name.startswith(".nv.info"): - for typ, param, data in self._parse_elf_info(sh): - if sh.name == f".nv.info.{name}" and param == 0xa: cbuf0_size = struct.unpack_from("IH", data)[1] # EIATTR_PARAM_CBANK - elif sh.name == ".nv.info" and param == 0x12: self.lcmem_usage = struct.unpack_from("II", data)[1] + 0x240 # EIATTR_MIN_STACK_SIZE - elif sh.name == ".nv.info" and param == 0x2f: self.regs_usage = struct.unpack_from("II", data)[1] # EIATTR_REGCOUNT + + if (NAK:=isinstance(dev.compiler, NAKCompiler)): + image, self.cbuf_0 = memoryview(bytearray(lib[ctypes.sizeof(info:=mesa.struct_nak_shader_info.from_buffer_copy(lib)):])), [] + self.regs_usage, self.shmem_usage, self.lcmem_usage = info.num_gprs, round_up(info.cs.smem_size, 128), round_up(info.slm_size, 16) + elif MOCKGPU: image, sections, relocs = memoryview(bytearray(lib) + b'\x00' * (4 - len(lib)%4)).cast("I"), [], [] # type: ignore + else: image, sections, relocs = elf_loader(self.lib, force_section_align=128) + # NOTE: Ensure at least 4KB of space after the program to mitigate prefetch memory faults. + self.lib_gpu = self.dev.allocator.alloc(round_up((prog_sz:=image.nbytes), 0x1000) + 0x1000, buf_spec:=BufferSpec(nolru=True)) + prog_addr = self.lib_gpu.va_addr + if not NAK: + # For MOCKGPU, the lib is PTX code, so some values are emulated. + self.regs_usage, self.shmem_usage, self.lcmem_usage, cbuf0_size = 0, 0x400, 0x240, 0 if not MOCKGPU else 0x160 + for sh in sections: # pylint: disable=possibly-used-before-assignment + if sh.name == f".nv.shared.{self.name}": self.shmem_usage = round_up(0x400 + sh.header.sh_size, 128) + if sh.name == f".text.{self.name}": prog_addr, prog_sz = self.lib_gpu.va_addr+sh.header.sh_addr, sh.header.sh_size + elif m:=re.match(r'\.nv\.constant(\d+)', sh.name): + self.constbufs[int(m.group(1))] = (self.lib_gpu.va_addr+sh.header.sh_addr, sh.header.sh_size) + elif sh.name.startswith(".nv.info"): + for typ, param, data in self._parse_elf_info(sh): + if sh.name == f".nv.info.{name}" and param == 0xa: cbuf0_size = struct.unpack_from("IH", data)[1] # EIATTR_PARAM_CBANK + elif sh.name == ".nv.info" and param == 0x12: self.lcmem_usage = struct.unpack_from("II", data)[1] + 0x240 # EIATTR_MIN_STACK_SIZE + elif sh.name == ".nv.info" and param == 0x2f: self.regs_usage = struct.unpack_from("II", data)[1] # EIATTR_REGCOUNT + + # Apply relocs + for apply_image_offset, rel_sym_offset, typ, _ in relocs: # pylint: disable=possibly-used-before-assignment + # These types are CUDA-specific, applying them here + if typ == 2: image[apply_image_offset:apply_image_offset+8] = struct.pack('> 32) + else: raise RuntimeError(f"unknown NV reloc {typ}") + + self.cbuf_0 = [0] * (cbuf0_size // 4) # Ensure device has enough local memory to run the program self.dev._ensure_has_local_memory(self.lcmem_usage) - - # Apply relocs - for apply_image_offset, rel_sym_offset, typ, _ in relocs: - # These types are CUDA-specific, applying them here - if typ == 2: image[apply_image_offset:apply_image_offset+8] = struct.pack('> 32) - else: raise RuntimeError(f"unknown NV reloc {typ}") - - ctypes.memmove(self.lib_gpu.va_addr, mv_address(image), image.nbytes) - - self.constbuffer_0 = [0] * (cbuf0_size // 4) + self.dev.allocator._copyin(self.lib_gpu, image) + self.dev.synchronize() if dev.iface.compute_class >= nv_gpu.BLACKWELL_COMPUTE_A: - self.constbuffer_0[188:192], self.constbuffer_0[223] = [*data64_le(self.dev.shared_mem_window), *data64_le(self.dev.local_mem_window)], 0xfffdc0 - qmd = {'qmd_major_version':5, 'qmd_type':nv_gpu.NVCEC0_QMDV05_00_QMD_TYPE_GRID_CTA, 'register_count':self.regs_usage, - 'program_address_upper_shifted4':hi32(self.prog_addr>>4), 'program_address_lower_shifted4':lo32(self.prog_addr>>4), - 'shared_memory_size_shifted7':self.shmem_usage>>7, 'shader_local_memory_high_size_shifted4':self.dev.slm_per_thread>>4} + if not NAK: self.cbuf_0[188:192], self.cbuf_0[223] = [*data64_le(self.dev.shared_mem_window), *data64_le(self.dev.local_mem_window)], 0xfffdc0 + qmd = {'qmd_major_version':5, 'qmd_type':nv_gpu.NVCEC0_QMDV05_00_QMD_TYPE_GRID_CTA, 'program_address_upper_shifted4':hi32(prog_addr>>4), + 'program_address_lower_shifted4':lo32(prog_addr>>4), 'register_count':self.regs_usage, 'shared_memory_size_shifted7':self.shmem_usage>>7, + 'shader_local_memory_high_size_shifted4':self.lcmem_usage>>4 if NAK else self.dev.slm_per_thread>>4} else: - self.constbuffer_0[6:12] = [*data64_le(self.dev.shared_mem_window), *data64_le(self.dev.local_mem_window), *data64_le(0xfffdc0)] - qmd = {'qmd_major_version':3, 'sm_global_caching_enable':1, 'shader_local_memory_high_size':self.dev.slm_per_thread, - 'program_address_upper':hi32(self.prog_addr), 'program_address_lower':lo32(self.prog_addr), 'shared_memory_size':self.shmem_usage, - 'register_count_v':self.regs_usage} + if not NAK: self.cbuf_0[6:12] = [*data64_le(self.dev.shared_mem_window), *data64_le(self.dev.local_mem_window), *data64_le(0xfffdc0)] + qmd = {'qmd_major_version':3, 'sm_global_caching_enable':1, 'program_address_upper':hi32(prog_addr), 'program_address_lower':lo32(prog_addr), + 'shared_memory_size':self.shmem_usage, 'register_count_v':self.regs_usage, + **({'shader_local_memory_low_size':self.lcmem_usage} if NAK else {'shader_local_memory_high_size':self.dev.slm_per_thread})} smem_cfg = min(shmem_conf * 1024 for shmem_conf in [32, 64, 100] if shmem_conf * 1024 >= self.shmem_usage) // 4096 + 1 self.qmd:QMD = QMD(dev, **qmd, qmd_group_id=0x3f, invalidate_texture_header_cache=1, invalidate_texture_sampler_cache=1, invalidate_texture_data_cache=1, invalidate_shader_data_cache=1, api_visible_call_limit=1, sampler_index=1, barrier_count=1, - cwd_membar_type=nv_gpu.NVC6C0_QMDV03_00_CWD_MEMBAR_TYPE_L1_SYSMEMBAR, constant_buffer_invalidate_0=1, - min_sm_config_shared_mem_size=smem_cfg, target_sm_config_shared_mem_size=smem_cfg, max_sm_config_shared_mem_size=0x1a, - program_prefetch_size=min(self.prog_sz>>8, 0x1ff), sass_version=dev.sass_version, - program_prefetch_addr_upper_shifted=self.prog_addr>>40, program_prefetch_addr_lower_shifted=self.prog_addr>>8) + cwd_membar_type=nv_gpu.NVC6C0_QMDV03_00_CWD_MEMBAR_TYPE_L1_SYSMEMBAR, constant_buffer_invalidate_0=1, min_sm_config_shared_mem_size=smem_cfg, + target_sm_config_shared_mem_size=smem_cfg, max_sm_config_shared_mem_size=0x1a, program_prefetch_size=min(prog_sz>>8, 0x1ff), + sass_version=dev.sass_version, program_prefetch_addr_upper_shifted=prog_addr>>40, program_prefetch_addr_lower_shifted=prog_addr>>8) for i,(addr,sz) in self.constbufs.items(): self.qmd.set_constant_buf_addr(i, addr) @@ -314,8 +321,7 @@ class NVKIface: with contextlib.suppress(RuntimeError): uvm.mm_initialize(self.fd_uvm_2, uvmFd=self.fd_uvm.fd) # this error is okay, CUDA hits it too nv_iowr(NVKIface.fd_ctl, nv_gpu.NV_ESC_CARD_INFO, gpus_info:=(nv_gpu.nv_ioctl_card_info_t*64)()) - visible_devices = [int(x) for x in (getenv('VISIBLE_DEVICES', getenv('CUDA_VISIBLE_DEVICES', ''))).split(',') if x.strip()] - NVKIface.gpus_info = [gpus_info[x] for x in visible_devices] if visible_devices else gpus_info + NVKIface.gpus_info = hcq_filter_visible_devices(gpus_info) self.dev, self.device_id = dev, device_id if self.device_id >= len(NVKIface.gpus_info) or not NVKIface.gpus_info[self.device_id].valid: @@ -381,14 +387,14 @@ class NVKIface: if made.params.status != 0: raise RuntimeError(f"_gpu_map_to_cpu returned {get_error_str(made.params.status)}") return fd_dev.mmap(target, size, mmap.PROT_READ|mmap.PROT_WRITE, mmap.MAP_SHARED | (MAP_FIXED if target is not None else 0), 0) - def alloc(self, size:int, host=False, uncached=False, cpu_access=False, contiguous=False, map_flags=0, cpu_addr=None) -> HCQBuffer: + def alloc(self, size:int, host=False, uncached=False, cpu_access=False, contiguous=False, map_flags=0, cpu_addr=None, **kwargs) -> HCQBuffer: # Uncached memory is "system". Use huge pages only for gpu memory. - page_size = (4 << (12 if OSX else 10)) if uncached or host else ((2 << 20) if size >= (8 << 20) else (4 << (12 if OSX else 10))) + page_size = mmap.PAGESIZE if uncached or host else ((2 << 20) if size >= (8 << 20) else (mmap.PAGESIZE if MOCKGPU else 4 << 10)) size = round_up(size, page_size) - va_addr = self._alloc_gpu_vaddr(size, alignment=page_size, force_low=cpu_access) + va_addr = self._alloc_gpu_vaddr(size, alignment=page_size, force_low=cpu_access) if (alloced:=cpu_addr is None) else cpu_addr if host: - va_addr = cpu_addr or FileIOInterface.anon_mmap(va_addr, size, mmap.PROT_READ|mmap.PROT_WRITE, MAP_FIXED|mmap.MAP_SHARED|mmap.MAP_ANONYMOUS, 0) + if alloced: va_addr = FileIOInterface.anon_mmap(va_addr, size, mmap.PROT_READ|mmap.PROT_WRITE, MAP_FIXED|mmap.MAP_SHARED|mmap.MAP_ANONYMOUS, 0) flags = (nv_gpu.NVOS02_FLAGS_PHYSICALITY_NONCONTIGUOUS << 4) | (nv_gpu.NVOS02_FLAGS_COHERENCY_CACHED << 12) \ | (nv_gpu.NVOS02_FLAGS_MAPPING_NO_MAP << 30) @@ -450,15 +456,13 @@ class PCIIface(PCIIfaceBase): gpus:ClassVar[list[str]] = [] def __init__(self, dev, dev_id): - super().__init__(dev, dev_id, vendor=0x10de, devices=[0x2204, 0x2684, 0x2b85], bars=[0, 1], vram_bar=1, - va_start=NVMemoryManager.va_allocator.base, va_size=NVMemoryManager.va_allocator.size) - System.reserve_hugepages(64) + super().__init__(dev, dev_id, vendor=0x10de, devices=[(0xff00, [0x2200, 0x2400, 0x2500, 0x2600, 0x2700, 0x2800, 0x2b00, 0x2c00, 0x2d00, 0x2f00])], + bars=[0, 1], vram_bar=1, va_start=NVMemoryManager.va_allocator.base, va_size=NVMemoryManager.va_allocator.size) + if not OSX: System.reserve_hugepages(64) self.pci_dev.write_config(pci.PCI_COMMAND, self.pci_dev.read_config(pci.PCI_COMMAND, 2) | pci.PCI_COMMAND_MASTER, 2) - self.dev_impl:NVDev = NVDev(self.pci_dev.pcibus, self.pci_dev.map_bar(0, fmt='I'), self.pci_dev.map_bar(1), - self.pci_dev.read_config(pci.PCI_VENDOR_ID, 4), self.pci_dev.read_config(pci.PCI_SUBSYSTEM_VENDOR_ID, 4), - self.pci_dev.read_config(pci.PCI_REVISION_ID, 1), self.pci_dev.bar_info) - self.root, self.gpu_instance, self.p2p_base_addr = 0xc1000000, 0, self.pci_dev.bar_info[1][0] + self.dev_impl:NVDev = NVDev(self.pci_dev) + self.root, self.gpu_instance = 0xc1000000, 0 self.rm_alloc(0, nv_gpu.NV01_ROOT, nv_gpu.NV0000_ALLOC_PARAMETERS()) # Setup classes for the GPU @@ -467,7 +471,7 @@ class PCIIface(PCIIfaceBase): def alloc(self, size:int, host=False, uncached=False, cpu_access=False, contiguous=False, **kwargs) -> HCQBuffer: # Force use of huge pages for large allocations. NVDev will attempt to use huge pages in any case, # but if the size is not aligned, the tail will be allocated with 4KB pages, increasing TLB pressure. - page_size = (2 << 20) if size >= (8 << 20) and not uncached and not host else (4 << 10) + page_size = mmap.PAGESIZE if uncached or host else ((2 << 20) if size >= (8 << 20) else (4 << 10)) return super().alloc(round_up(size, page_size), host=host, uncached=uncached, cpu_access=cpu_access, contiguous=contiguous, **kwargs) def setup_usermode(self): return 0xce000000, self.pci_dev.map_bar(bar=0, fmt='I', off=0xbb0000, size=0x10000) @@ -505,7 +509,7 @@ class NVDevice(HCQCompiled[HCQSignal]): channel_params = nv_gpu.NV_CHANNEL_GROUP_ALLOCATION_PARAMETERS(engineType=nv_gpu.NV2080_ENGINE_TYPE_GRAPHICS) channel_group = self.iface.rm_alloc(self.nvdevice, nv_gpu.KEPLER_CHANNEL_GROUP_A, channel_params) - gpfifo_area = self.iface.alloc(0x200000, contiguous=True, cpu_access=True, map_flags=0x10d0000) + gpfifo_area = self.iface.alloc(0x200000, contiguous=True, cpu_access=True, force_devmem=True, map_flags=0x10d0000) ctxshare_params = nv_gpu.NV_CTXSHARE_ALLOCATION_PARAMETERS(hVASpace=vaspace, flags=nv_gpu.NV_CTXSHARE_ALLOCATION_FLAGS_SUBCONTEXT_ASYNC) ctxshare = self.iface.rm_alloc(channel_group, nv_gpu.FERMI_CONTEXT_SHARE_A, ctxshare_params) @@ -516,7 +520,7 @@ class NVDevice(HCQCompiled[HCQSignal]): self.cmdq_page:HCQBuffer = self.iface.alloc(0x200000, cpu_access=True) self.cmdq_allocator = BumpAllocator(size=self.cmdq_page.size, base=cast(int, self.cmdq_page.va_addr), wrap=True) - self.cmdq = MMIOInterface(cast(int, self.cmdq_page.va_addr), 0x200000, fmt='I') + self.cmdq = self.cmdq_page.cpu_view().view(fmt='I') self.num_gpcs, self.num_tpc_per_gpc, self.num_sm_per_tpc, self.max_warps_per_sm, self.sm_version = self._query_gpu_info('num_gpcs', 'num_tpc_per_gpc', 'num_sm_per_tpc', 'max_warps_per_sm', 'sm_version') @@ -526,7 +530,8 @@ class NVDevice(HCQCompiled[HCQSignal]): self.sass_version = ((self.sm_version & 0xf00) >> 4) | (self.sm_version & 0xf) compilers:list[CompilerPairT] = [(functools.partial(NVRenderer, self.arch),functools.partial(CUDACompiler if MOCKGPU else NVCompiler, self.arch)), - (functools.partial(PTXRenderer, self.arch, device="NV"), functools.partial(PTXCompiler if MOCKGPU else NVPTXCompiler, self.arch))] + (functools.partial(PTXRenderer, self.arch, device="NV"), functools.partial(PTXCompiler if MOCKGPU else NVPTXCompiler, self.arch)), + (functools.partial(NAKRenderer, dev=self), functools.partial(NAKCompiler, self.arch, self.max_warps_per_sm))] super().__init__(device, NVAllocator(self), compilers, functools.partial(NVProgram, self), HCQSignal, NVComputeQueue, NVCopyQueue) self._setup_gpfifos() @@ -548,8 +553,8 @@ class NVDevice(HCQCompiled[HCQSignal]): nv_gpu.NVC36F_CTRL_CMD_GPFIFO_GET_WORK_SUBMIT_TOKEN_PARAMS(workSubmitToken=-1)) self.iface.setup_gpfifo_vm(gpfifo) - return GPFifo(ring=MMIOInterface(gpfifo_area.va_addr + offset, entries*8, fmt='Q'), entries_count=entries, token=ws_token_params.workSubmitToken, - controls=nv_gpu.AmpereAControlGPFifo.from_address(gpfifo_area.va_addr + offset + entries * 8)) + return GPFifo(ring=gpfifo_area.cpu_view().view(offset, entries*8, fmt='Q'), entries_count=entries, token=ws_token_params.workSubmitToken, + controls=nv_gpu.AmpereAControlGPFifo.from_address(gpfifo_area.cpu_view().addr + offset + entries * 8)) def _query_gpu_info(self, *reqs): nvrs = [getattr(nv_gpu,'NV2080_CTRL_GR_INFO_INDEX_'+r.upper(), getattr(nv_gpu,'NV2080_CTRL_GR_INFO_INDEX_LITTER_'+r.upper(), None)) for r in reqs] diff --git a/tinygrad/runtime/ops_python.py b/tinygrad/runtime/ops_python.py index 9dd145d299..6a98a23fb3 100644 --- a/tinygrad/runtime/ops_python.py +++ b/tinygrad/runtime/ops_python.py @@ -3,7 +3,7 @@ # works to test the tensor cores, and all the uops in general # this is the (living) definition of uops from typing import Any, TYPE_CHECKING, cast -import pickle, base64, itertools, time, struct, sys +import pickle, base64, itertools, time, struct, sys, functools from tinygrad.dtype import DType, dtypes, ImageDType, PtrDType, truncate, float_to_bf16, float_to_fp8, fp8_to_float from tinygrad.helpers import all_same, getenv, flatten, get_single_element, EMULATE from tinygrad.device import Compiled, Compiler, Allocator @@ -36,128 +36,128 @@ def _store(m, i, v, dtype: DType): if i < 0 or i >= len(m): raise IndexError(f"store out of bounds, size is {len(m)}, access is {i}, value is {v}") m[i] = to_storage_scalar(v, dtype) +# here are the models for the WMMA instruction on the different hardware +def generic_wmma_helper(inp, warp_size, WARP_THREADS, K, NUM_A, NUM_B, NUM_C, a_elem, b_elem, c_map): + for cc, tinp, num in zip(("A", "B", "C"), inp, (NUM_A, NUM_B, NUM_C)): + assert len(tinp) == num, f"{cc} must have {num} elements per thread, it has {len(tinp)}" + assert len(flatten(tinp)) == num * warp_size, f"WMMA must have {num * warp_size} total elements for {cc} in WMMA" + assert warp_size > 0 and warp_size % WARP_THREADS == 0, f"must have multiples of {WARP_THREADS} warp threads" + out = [inp[2][elem_idx][:] for elem_idx in range(NUM_C)] + for goff in range(0, warp_size, WARP_THREADS): + for lane_id in range(WARP_THREADS): + for elem_idx in range(NUM_C): # calculate new muls and add to acc + (c_i, c_j) = c_map(lane_id, elem_idx) + out[elem_idx][goff+lane_id] += sum(a_elem(inp[0], _k, c_j, goff) * b_elem(inp[1], c_i, _k, goff) for _k in range(K)) + return out + class PythonProgram: def __init__(self, name:str, lib:bytes): - self.uops: list[tuple[Ops, DType|None, list[int], Any]] = pickle.loads(lib) + self.uops: list[tuple[Ops, DType, list[int], Any]] = pickle.loads(lib) def __call__(self, *bufs, global_size:tuple[int,int,int]=(1,1,1), local_size:tuple[int,int,int]=(1,1,1), vals:tuple[int, ...]=(), wait=False): st = time.perf_counter() warp = list(itertools.product(*[range(x) for x in local_size[::-1]])) warp_size = len(warp) + void_ops = {Ops.END, Ops.BARRIER, Ops.IF, Ops.ENDIF, Ops.SINK, Ops.NOOP, Ops.GROUP, Ops.STORE} + loop_ends: dict[int, int] = {srcs[1]:i for i, (uop, _, srcs, _) in enumerate(self.uops) if uop == Ops.END} for idxs in itertools.product(*[range(x) for x in global_size[::-1]]): - ul: dict[int, Any] = {} - dl: dict[int, DType] = {} + values: dict[int, Any] = {} pbufs: list[memoryview] = list(bufs) pvals: list[int] = list(vals) i = 0 - loop_ends: dict[int, int] = {} while i < len(self.uops): - uop, dtype, idp, arg = self.uops[i] - void_ops = {Ops.ENDRANGE, Ops.BARRIER, Ops.IF, Ops.ENDIF, Ops.SINK, Ops.NOOP, Ops.STORE} - inp = [ul[v] for v in idp if self.uops[v][0] not in void_ops] - dtp = [dl[v] for v in idp if self.uops[v][0] not in void_ops] - if getenv("TRACE"): print(i, uop, dtype, arg, inp, dtp) - if uop is Ops.ENDRANGE: - loop_ends[idp[0]] = i - i = idp[0] + uop, dtype, srcs, arg = self.uops[i] + src_values = [values[v] for v in srcs if self.uops[v][0] not in void_ops] + src_dtypes = [self.uops[v][1] for v in srcs if self.uops[v][0] not in void_ops] + if getenv("TRACE"): print(i, uop, dtype, arg, src_values, src_dtypes) + if uop is Ops.END: + i = srcs[1] continue - if uop in (Ops.BARRIER, Ops.IF, Ops.ENDIF, Ops.SINK, Ops.NOOP): + if uop in (Ops.BARRIER, Ops.IF, Ops.ENDIF, Ops.SINK, Ops.NOOP, Ops.GROUP): # in the python emulator, the warp is always in sync i += 1 continue assert dtype is not None, f"{uop} is missing a dtype" - dl[i] = dtype if uop is Ops.STORE: - for j,val in enumerate(inp[1] if dtp[1].count > 1 else [inp[1]]): - for (m,o,g),v in zip(inp[0], val): - if g: _store(m, o+j, v, dtp[1].scalar()) + for j,val in enumerate(src_values[1] if src_dtypes[1].count > 1 else [src_values[1]]): + for (m,o,g),v in zip(src_values[0], val): + if g: _store(m, o+j, v, src_dtypes[1].scalar()) i += 1 continue - if uop in {Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_REG}: + if uop is Ops.AFTER: values[i] = src_values[0] + elif uop in {Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_REG}: assert isinstance(dtype, PtrDType), dtype storage_fmt = storage_fmt_for_dtype(dtype.base.scalar()) if storage_fmt is None: raise RuntimeError(f"{dtype=} is not supported") if TYPE_CHECKING or sys.version_info < (3, 12): assert storage_fmt != "e" if uop is Ops.DEFINE_REG: # REGs are per thread - ul[i] = [memoryview(bytearray(dtype.size*dtype.itemsize)).cast(storage_fmt) for _ in range(warp_size)] + values[i] = [memoryview(bytearray(dtype.size*dtype.itemsize)).cast(storage_fmt) for _ in range(warp_size)] else: buf = memoryview(bytearray(dtype.size*dtype.itemsize)) if uop is not Ops.DEFINE_GLOBAL else pbufs.pop(0) - ul[i] = [buf.cast(storage_fmt)] * warp_size + values[i] = [buf.cast(storage_fmt)] * warp_size elif uop is Ops.DEFINE_VAR: - ul[i] = [pvals.pop(0)] * warp_size + values[i] = [pvals.pop(0)] * warp_size elif uop is Ops.SPECIAL: - if arg[0] == 'g': ul[i] = [idxs[2-int(arg[-1])]] * warp_size - elif arg[0] == 'l': ul[i] = [x[2-int(arg[-1])] for x in warp] - elif uop is Ops.CONST: ul[i] = [arg] * warp_size + if arg[0] == 'g': values[i] = [idxs[2-int(arg[-1])]] * warp_size + elif arg[0] == 'l': values[i] = [x[2-int(arg[-1])] for x in warp] + elif uop is Ops.CONST: values[i] = [arg] * warp_size elif uop is Ops.INDEX: ret:list = [] - if isinstance(dtp[0], ImageDType): - for m,ox,oy in zip(inp[0], inp[1][0], inp[1][1]): - if ox < 0 or ox >= dtp[0].shape[1] or oy < 0 or oy >= dtp[0].shape[0]: ret.append((m, None)) - else: ret.append((m, ox*4 + oy*dtp[0].shape[1]*4)) + if isinstance(src_dtypes[0], ImageDType): + for m,ox,oy in zip(src_values[0], src_values[1][0], src_values[1][1]): + if ox < 0 or ox >= src_dtypes[0].shape[1] or oy < 0 or oy >= src_dtypes[0].shape[0]: ret.append((m, None)) + else: ret.append((m, ox*4 + oy*src_dtypes[0].shape[1]*4)) else: - for m,o in zip(inp[0], inp[1]): ret.append((m,o)) - ul[i] = [(m,o,g) for (m,o),g in zip(ret, inp[2] if len(inp) == 3 else [True]*len(ret))] # set the gate last + for m,o in zip(src_values[0], src_values[1]): ret.append((m,o)) + values[i] = [(m,o,g) for (m,o),g in zip(ret, src_values[2] if len(src_values) == 3 else [True]*len(ret))] # set the gate last elif uop is Ops.CAST and isinstance(dtype, PtrDType): - ul[i] = inp[0] + values[i] = src_values[0] elif uop is Ops.RANGE: - if i not in ul: ul[i] = [0] * warp_size + if i not in values: values[i] = [0] * warp_size else: - for j in range(len(ul[i])): - ul[i][j] += 1 - if ul[i][0] == inp[0][0]: - del ul[i] - i = loop_ends[i] + 1 - continue - elif uop is Ops.VECTORIZE: ul[i] = inp + for j in range(len(values[i])): + values[i][j] += 1 + if values[i][0] == src_values[0][0]: + del values[i] + i = loop_ends[i] + 1 + continue + elif uop is Ops.VECTORIZE: values[i] = src_values elif uop is Ops.BITCAST: - packed = struct.pack(str(warp_size) + storage_fmt_for_dtype(dtp[0].scalar()), *[to_storage_scalar(x, dtp[0].scalar()) for x in inp[0]]) - ul[i] = list(struct.unpack(str(warp_size) + storage_fmt_for_dtype(dtype.scalar()), packed)) - ul[i] = [from_storage_scalar(x, dtype.scalar()) for x in ul[i]] + packed = struct.pack(str(warp_size) + storage_fmt_for_dtype(src_dtypes[0].scalar()), + *[to_storage_scalar(x, src_dtypes[0].scalar()) for x in src_values[0]]) + values[i] = list(struct.unpack(str(warp_size) + storage_fmt_for_dtype(dtype.scalar()), packed)) + values[i] = [from_storage_scalar(x, dtype.scalar()) for x in values[i]] elif uop is Ops.CAST: - ul[i] = [truncate.get(dtype, lambda dt: dt)(dtypes.as_const(x, dtype)) for x in inp[0]] + values[i] = [truncate.get(dtype, lambda dt: dt)(dtypes.as_const(x, dtype)) for x in src_values[0]] elif uop is Ops.LOAD: if dtype.count > 1: - ul[i] = [load([inp[i][j] if i != 0 and dtp[i].count > 1 else inp[i] for i in range(len(inp))], j, dtype.scalar()) \ - for j in range(dtype.count)] + values[i] = [load([src_values[i][j] if i != 0 and src_dtypes[i].count > 1 else src_values[i] \ + for i in range(len(src_values))], j, dtype.scalar()) for j in range(dtype.count)] else: - ul[i] = load(inp, 0, dtype) - elif uop is Ops.GEP: ul[i] = inp[0][get_single_element(arg)] + values[i] = load(src_values, 0, dtype) + elif uop is Ops.GEP: values[i] = src_values[0][get_single_element(arg)] elif uop is Ops.WMMA: - # here are the models for the WMMA instruction on the different hardware - def wmma_helper(WARP_THREADS, K, NUM_A, NUM_B, NUM_C, a_elem, b_elem, c_map): - for cc, tinp, num in zip(("A", "B", "C"), inp, (NUM_A, NUM_B, NUM_C)): - assert len(tinp) == num, f"{cc} must have {num} elements per thread, it has {len(tinp)}" - assert len(flatten(tinp)) == num * warp_size, f"WMMA must have {num * warp_size} total elements for {cc} in WMMA" - assert warp_size > 0 and warp_size % WARP_THREADS == 0, f"must have multiples of {WARP_THREADS} warp threads" - out = [inp[2][elem_idx][:] for elem_idx in range(NUM_C)] - for goff in range(0, warp_size, WARP_THREADS): - for lane_id in range(WARP_THREADS): - for elem_idx in range(NUM_C): # calculate new muls and add to acc - (c_i, c_j) = c_map(lane_id, elem_idx) - out[elem_idx][goff+lane_id] += sum(a_elem(inp[0], _k, c_j, goff) * b_elem(inp[1], c_i, _k, goff) for _k in range(K)) - return out - - first_src_dtype = self.uops[idp[0]][1] + first_src_dtype = self.uops[srcs[0]][1] assert isinstance(first_src_dtype, DType) # mypy dims, dtype_in, device, threads = arg[1], first_src_dtype.scalar(), arg[4], arg[5] + wmma_helper = functools.partial(generic_wmma_helper, src_values, warp_size) # TODO: refactor these to a shared TensorCoreLayout in kernel.py if device == "METAL": # A (2 elements on 32 threads): row major def a_b_elem(x, i, j, goff): return x[(i%2)][goff+(i//2)%2+(j%4)*2+(i//4)*8+(j//4)*16] # (i, j), C, D (2 elements on 32 threads): row major same as A/B def c_map(lane, elem): return (elem + ((lane%2)*2) + ((lane//8)%2)*4, ((lane//2)%4) + (lane//16)*4) - ul[i] = wmma_helper(32, 8, 2, 2, 2, a_b_elem, a_b_elem, c_map) + values[i] = wmma_helper(32, 8, 2, 2, 2, a_b_elem, a_b_elem, c_map) elif device == "AMD" and threads == 64: - def a_elem(x, k, row, goff): return x[k%4][goff + (k//4)*16 + row] - def b_elem(x, col, k, goff): return a_elem(x, k, col, goff) # pylint: disable=arguments-out-of-order + def a_elem(x, k, row, goff): return x[k%(dims[2]//4)][goff + (k//(dims[2]//4))*16 + row] + def b_elem(x, col, k, goff): return a_elem(x, k, col, goff) # pylint: disable=arguments-out-of-order def c_map(lane, elem): return (lane%16, (lane//16)*4 + elem) - ul[i] = wmma_helper(64, 16, 4, 4, 4, a_elem, b_elem, c_map) - elif device == "AMD" and len(inp[0]) == 8: # RDNA4 + values[i] = wmma_helper(64, dims[2], len(src_values[0]), len(src_values[1]), len(src_values[2]), a_elem, b_elem, c_map) + elif device == "AMD" and len(src_values[0]) == 8: # RDNA4 def a_elem(x, k, row, goff): return x[k - [0, 4, 4, 8][k//4]][goff + row + [0, 16, 0, 16][k//4]] def b_elem(x, col, k, goff): return a_elem(x, k, col, goff) def c_map(lane, elem): return (lane%16, (lane//16)*8 + elem) - ul[i] = wmma_helper(32, 16, 8, 8, 8, a_elem, b_elem, c_map) + values[i] = wmma_helper(32, 16, 8, 8, 8, a_elem, b_elem, c_map) elif device == "AMD": # A (16 elements on 32 threads): col major, lane 16-32 == lane 0-15 def a_elem(x, k, row, goff): @@ -166,7 +166,7 @@ class PythonProgram: # B (16 elements on 32 threads): row major, lane 16-32 == lane 0-15 def b_elem(x, col, k, goff): return a_elem(x, k, col, goff) # pylint: disable=arguments-out-of-order def c_map(lane, elem): return (lane%16, lane//16+elem*2) # (i, j), C, D (8 elements on 32 threads): row major - ul[i] = wmma_helper(32, 16, 16, 16, 8, a_elem, b_elem, c_map) + values[i] = wmma_helper(32, 16, 16, 16, 8, a_elem, b_elem, c_map) elif device == "CUDA": # (col, row) given (lane, elem) for C & D (4 elements on 32 threads); shared by all tc shapes with M=16 N=8 def c_map(lane, elem): return (elem%2 + (lane%4)*2, lane//4 + (elem//2)*8) @@ -174,17 +174,22 @@ class PythonProgram: if dims == (8,16,16): def a_elem(x, k, row, goff): return x[k%2 + (row//8)*2 + (k//8)*4][goff + (k//2)%4 + (row%8)*4] def b_elem(x, col, k, goff): return x[k%2 + (k//8)*2][goff + (k//2)%4 + col*4] - ul[i] = wmma_helper(32, 16, 8, 4, 4, a_elem, b_elem, c_map) + values[i] = wmma_helper(32, 16, 8, 4, 4, a_elem, b_elem, c_map) + + elif dims == (8,16,32): + def a_elem(x, k, row, goff): return x[k%4 + (row//8)*4 + (k//16)*8][goff + (k//4)%4 + (row%8)*4] + def b_elem(x, col, k, goff): return x[k%4 + (k//16)*4][goff + (k//4)%4 + col*4] + values[i] = wmma_helper(32, 32, 16, 8, 4, a_elem, b_elem, c_map) elif dims == (8,16,8) and dtype_in == dtypes.half: def a_elem(x, k, row, goff): return x[k%2 + (row//8)*2][goff + k//2 + (row%8)*4] def b_elem(x, col, k, goff): return x[k%2][goff + k//2 + col*4] - ul[i] = wmma_helper(32, 8, 4, 2, 4, a_elem, b_elem, c_map) + values[i] = wmma_helper(32, 8, 4, 2, 4, a_elem, b_elem, c_map) elif dims == (8,16,8) and dtype_in == dtypes.float: def a_elem(x, k, row, goff): return x[(k//4)*2 + row//8][goff + k%4 + (row%8)*4] def b_elem(x, col, k, goff): return x[k//4][goff + k%4 + col*4] - ul[i] = wmma_helper(32, 8, 4, 2, 4, a_elem, b_elem, c_map) + values[i] = wmma_helper(32, 8, 4, 2, 4, a_elem, b_elem, c_map) else: raise NotImplementedError(f"unimplemented tensor core {arg}") elif device == "INTEL": @@ -194,17 +199,17 @@ class PythonProgram: def b_elem(x, col, k, goff): return x[k][goff+col] # C, D (8 elements on 8 threads) def c_map(lane, elem): return (lane, elem) - ul[i] = wmma_helper(8, 16, 16, 16, 8, a_elem, b_elem, c_map) + values[i] = wmma_helper(8, 16, 16, 16, 8, a_elem, b_elem, c_map) elif device == "CPU": def elem(x, col, row, _): return x[col+row][0] # k is always 0 - def c_map(_, elem): return (elem%16, elem//16) - ul[i] = wmma_helper(1, 1, 16, 16, 256, elem, elem, c_map) + def c_map(lane, elem): return (elem%16, elem//16) + values[i] = wmma_helper(1, 1, 16, 16, 256, elem, elem, c_map) else: raise NotImplementedError(f"unimplemented tensor core {arg}") elif uop in GroupOp.ALU: - assert all_same([len(x) for x in inp]), f"{[len(x) for x in inp]} doesn't match on {uop}" - assert all_same([dtype] + dtp) or uop in {*GroupOp.Comparison, Ops.WHERE}, f"dtype mismatch on {uop}" - ul[i] = [exec_alu(uop, dtype, p) for p in zip(*inp)] - assert i in ul, (uop, dtype, idp, arg) + assert all_same([len(x) for x in src_values]), f"{[len(x) for x in src_values]} doesn't match on {uop}" + assert all_same([dtype] + src_dtypes) or uop in {*GroupOp.Comparison, Ops.WHERE}, f"dtype mismatch on {uop}" + values[i] = [exec_alu(uop, dtype, p) for p in zip(*src_values)] + assert i in values, (uop, dtype, srcs, arg) i += 1 return time.perf_counter() - st @@ -215,10 +220,11 @@ class PythonRenderer(Renderer): match cast(str, EMULATE.value): case "METAL": self.device, self.tensor_cores = "METAL", tc.metal case "AMD": self.device, self.tensor_cores = "AMD", tc.amd_rdna3 - case "AMD_MFMA": self.device, self.tensor_cores = "AMD", tc.amd_cdna + case "AMD_MFMA": self.device, self.tensor_cores = "AMD", tc.amd_cdna4 case "AMD_RDNA4": self.device, self.tensor_cores = "AMD", tc.amd_rdna4 case "CUDA": self.device, self.tensor_cores = "CUDA", tc.cuda_sm80 case "CUDA_SM75": self.device, self.tensor_cores = "CUDA", tc.cuda_sm75 + case "CUDA_SM89": self.device, self.tensor_cores = "CUDA", tc.cuda_sm89 case "INTEL": self.device, self.suffix, self.tensor_cores = "INTEL", "INTEL", tc.intel case "AMX": self.device, self.tensor_cores = "CPU", tc.amx case "": pass diff --git a/tinygrad/runtime/ops_qcom.py b/tinygrad/runtime/ops_qcom.py index 787d349ee9..ba14457050 100644 --- a/tinygrad/runtime/ops_qcom.py +++ b/tinygrad/runtime/ops_qcom.py @@ -1,5 +1,5 @@ from __future__ import annotations -import os, ctypes, functools, mmap, struct, array, math, sys, weakref +import os, ctypes, functools, mmap, struct, array, math, sys, weakref, contextlib assert sys.platform != 'win32' from types import SimpleNamespace from typing import Any, cast @@ -9,16 +9,18 @@ from tinygrad.runtime.support.hcq import FileIOInterface, MMIOInterface from tinygrad.runtime.autogen import kgsl, adreno from tinygrad.runtime.ops_cl import CLCompiler, CLDevice from tinygrad.renderer.cstyle import QCOMRenderer -from tinygrad.helpers import getenv, mv_address, to_mv, round_up, data64_le, prod, fromimport +from tinygrad.helpers import getenv, mv_address, to_mv, round_up, data64_le, prod, fromimport, cpu_profile, lo32, PROFILE +from tinygrad.runtime.support.system import System if getenv("IOCTL"): import extra.qcom_gpu_driver.opencl_ioctl # noqa: F401 # pylint: disable=unused-import BUFTYPE_BUF, BUFTYPE_TEX, BUFTYPE_IBO = 0, 1, 2 #Parse C-style defines: ___SHIFT and ___MASK from the adreno module into the following format: # qreg.(=..., =..., ..., =...) -def _qreg_exec(reg, __val=0, **kwargs): +def _qreg_exec(__reg, __val=0, **kwargs): for k, v in kwargs.items(): - __val |= (getattr(adreno, f'{reg[4:]}_{k.upper()}') if v else 0) if type(v) is bool else (v << getattr(adreno, f'{reg[4:]}_{k.upper()}__SHIFT')) + reg_name = f"{__reg[4:]}_{k.removeprefix('_').upper()}" + __val |= (getattr(adreno, reg_name) if v else 0) if type(v) is bool else (v << getattr(adreno, f'{reg_name}__SHIFT')) return __val qreg: Any = type("QREG", (object,), {name[4:].lower(): functools.partial(_qreg_exec, name) for name in adreno.__dict__.keys() if name[:4] == 'REG_'}) @@ -45,6 +47,10 @@ class QCOMSignal(HCQSignal): kgsl.IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID(self.owner.fd, context_id=self.owner.ctx, timestamp=self.owner.last_cmd, timeout=0xffffffff) class QCOMComputeQueue(HWQueue): + def __init__(self, dev:QCOMDevice): + self.dev = dev + super().__init__() + def __del__(self): if self.binded_device is not None: self.binded_device.allocator.free(self.hw_page, self.hw_page.size, BufferSpec(cpu_access=True, nolru=True)) @@ -54,7 +60,7 @@ class QCOMComputeQueue(HWQueue): def _cache_flush(self, write_back=True, invalidate=False, sync=True, memsync=False): # TODO: 7xx support. - if write_back: self.cmd(adreno.CP_EVENT_WRITE, adreno.CACHE_FLUSH_TS, *data64_le(QCOMDevice.dummy_addr), 0) # dirty cache write-back. + if write_back: self.cmd(adreno.CP_EVENT_WRITE, adreno.CACHE_FLUSH_TS, *data64_le(self.dev.dummy_addr), 0) # dirty cache write-back. if invalidate: self.cmd(adreno.CP_EVENT_WRITE, adreno.CACHE_INVALIDATE) # invalidate cache lines (following reads from RAM). if memsync: self.cmd(adreno.CP_WAIT_MEM_WRITES) if sync: self.cmd(adreno.CP_WAIT_FOR_IDLE) @@ -63,18 +69,20 @@ class QCOMComputeQueue(HWQueue): self._cache_flush(write_back=True, invalidate=True, sync=True, memsync=True) return self - def signal(self, signal:QCOMSignal, value=0, ts=False): + def signal(self, signal:QCOMSignal, value=0): self.cmd(adreno.CP_WAIT_FOR_IDLE) - if QCOMDevice.gpu_id < 700: - self.cmd(adreno.CP_EVENT_WRITE, qreg.cp_event_write_0(event=adreno.CACHE_FLUSH_TS, timestamp=ts), - *data64_le(signal.timestamp_addr if ts else signal.value_addr), qreg.cp_event_write_3(value & 0xFFFFFFFF)) + if self.dev.gpu_id[:2] < (7, 3): + self.cmd(adreno.CP_EVENT_WRITE, qreg.cp_event_write_0(event=adreno.CACHE_FLUSH_TS), *data64_le(signal.value_addr), lo32(value)) self._cache_flush(write_back=True, invalidate=False, sync=False, memsync=False) else: # TODO: support devices starting with 8 Gen 1. Also, 700th series have convenient CP_GLOBAL_TIMESTAMP and CP_LOCAL_TIMESTAMP raise RuntimeError('CP_EVENT_WRITE7 is not supported') return self - def timestamp(self, signal:QCOMSignal): return self.signal(signal, 0, ts=True) + def timestamp(self, signal:QCOMSignal): + self.cmd(adreno.CP_WAIT_FOR_IDLE) + self.cmd(adreno.CP_REG_TO_MEM, qreg.cp_reg_to_mem_0(reg=adreno.REG_A6XX_CP_ALWAYS_ON_COUNTER, cnt=2, _64b=True),*data64_le(signal.timestamp_addr)) + return self def wait(self, signal:QCOMSignal, value=0): self.cmd(adreno.CP_WAIT_REG_MEM, qreg.cp_wait_reg_mem_0(function=adreno.WRITE_GE, poll=adreno.POLL_MEMORY),*data64_le(signal.value_addr), @@ -289,20 +297,21 @@ class QCOMAllocator(HCQAllocatorBase): buf.texture_info = QCOMTextureInfo(pitch, real_stride, desc, [desc[0] & (~0xffff), *desc[1:len(desc)]]) return buf - def _do_copy(self, src_addr, dest_addr, src_size, real_size, src_stride, dest_stride, dest_off=0, src_off=0): - while src_off < src_size: - ctypes.memmove(dest_addr+dest_off, src_addr+src_off, real_size) - src_off, dest_off = src_off+src_stride, dest_off+dest_stride + def _do_copy(self, src_addr, dest_addr, src_size, real_size, src_stride, dest_stride, prof_text, dest_off=0, src_off=0): + with cpu_profile(prof_text, self.dev.device, is_copy=True): + while src_off < src_size: + ctypes.memmove(dest_addr+dest_off, src_addr+src_off, real_size) + src_off, dest_off = src_off+src_stride, dest_off+dest_stride def _copyin(self, dest:HCQBuffer, src:memoryview): stride, pitch = (src.nbytes, src.nbytes) if (ti:=cast(QCOMTextureInfo, dest.texture_info)) is None else (ti.real_stride, ti.pitch) - self._do_copy(mv_address(src), dest.va_addr, src.nbytes, stride, stride, pitch) + self._do_copy(mv_address(src), dest.va_addr, src.nbytes, stride, stride, pitch, f"TINY -> {self.dev.device}") def _copyout(self, dest:memoryview, src:HCQBuffer): self.dev.synchronize() stride, pitch = (src.size, src.size) if (ti:=cast(QCOMTextureInfo, src.texture_info)) is None else (ti.real_stride, ti.pitch) - self._do_copy(src.va_addr, mv_address(dest), src.size, stride, pitch, stride) + self._do_copy(src.va_addr, mv_address(dest), src.size, stride, pitch, stride, f"{self.dev.device} -> TINY") def _as_buffer(self, src:HCQBuffer) -> memoryview: self.dev.synchronize() @@ -313,15 +322,12 @@ class QCOMAllocator(HCQAllocatorBase): self.dev._gpu_free(opaque) class QCOMDevice(HCQCompiled): - gpu_id: int = 0 - dummy_addr: int = 0 - def __init__(self, device:str=""): self.fd = FileIOInterface('/dev/kgsl-3d0', os.O_RDWR) - QCOMDevice.dummy_addr = cast(int, self._gpu_alloc(0x1000).va_addr) + self.dummy_addr = cast(int, self._gpu_alloc(0x1000).va_addr) flags = kgsl.KGSL_CONTEXT_PREAMBLE | kgsl.KGSL_CONTEXT_PWR_CONSTRAINT | kgsl.KGSL_CONTEXT_NO_FAULT_TOLERANCE | kgsl.KGSL_CONTEXT_NO_GMEM_ALLOC \ - | kgsl.KGSL_CONTEXT_PRIORITY(8) | kgsl.KGSL_CONTEXT_PREEMPT_STYLE(kgsl.KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) + | kgsl.KGSL_CONTEXT_PRIORITY(getenv("QCOM_PRIORITY", 8)) | kgsl.KGSL_CONTEXT_PREEMPT_STYLE(kgsl.KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) self.ctx = kgsl.IOCTL_KGSL_DRAWCTXT_CREATE(self.fd, flags=flags).drawctxt_id self.cmd_buf = self._gpu_alloc(16 << 20) @@ -338,11 +344,17 @@ class QCOMDevice(HCQCompiled): # Load info about qcom device info = kgsl.struct_kgsl_devinfo() kgsl.IOCTL_KGSL_DEVICE_GETPROPERTY(self.fd, type=kgsl.KGSL_PROP_DEVICE_INFO, value=ctypes.addressof(info), sizebytes=ctypes.sizeof(info)) - QCOMDevice.gpu_id = ((info.chip_id >> 24) & 0xFF) * 100 + ((info.chip_id >> 16) & 0xFF) * 10 + ((info.chip_id >> 8) & 0xFF) - if QCOMDevice.gpu_id >= 700: raise RuntimeError(f"Unsupported GPU: {QCOMDevice.gpu_id}") + self.gpu_id = (info.chip_id >> 24, (info.chip_id >> 16) & 0xFF, (info.chip_id >> 8) & 0xFF) + + # a7xx start with 730x or 'Cxxx', a8xx starts 'Exxx' + if self.gpu_id[:2] >= (7, 3): raise RuntimeError(f"Unsupported GPU: chip_id={info.chip_id:#x}") + + if PROFILE and self.gpu_id[:2] < (7, 3): + System.write_sysfs("/sys/class/kgsl/kgsl-3d0/idle_timer", value="4000000000", msg="Failed to disable suspend mode", expected="4294967276") compilers = [(QCOMRenderer, functools.partial(QCOMCompiler, device))] - super().__init__(device, QCOMAllocator(self), compilers, functools.partial(QCOMProgram, self), QCOMSignal, QCOMComputeQueue, None) + super().__init__(device, QCOMAllocator(self), compilers, functools.partial(QCOMProgram, self), QCOMSignal, + functools.partial(QCOMComputeQueue, self), None) def _gpu_alloc(self, size:int, flags:int=0, uncached=False, fill_zeroes=False) -> HCQBuffer: flags |= kgsl.KGSL_MEMALIGN(alignment_hint:=12) | kgsl.KGSL_MEMFLAGS_USE_CPU_MAP @@ -364,3 +376,7 @@ class QCOMDevice(HCQCompiled): self.synchronize() self._gpu_free(self._stack) self._stack = self._gpu_alloc(sz) + + def _at_profile_finalize(self): + super()._at_profile_finalize() + with contextlib.suppress(RuntimeError): System.write_sysfs("/sys/class/kgsl/kgsl-3d0/idle_timer", "10", "Failed to reenable suspend mode") diff --git a/tinygrad/runtime/ops_remote.py b/tinygrad/runtime/ops_remote.py index 147063f3ee..12c80cf255 100644 --- a/tinygrad/runtime/ops_remote.py +++ b/tinygrad/runtime/ops_remote.py @@ -176,7 +176,7 @@ class RemoteHandler: self.sessions: defaultdict[SessionKey, RemoteSession] = defaultdict(RemoteSession) try: self.ib_ctx: IBCtx|None = IBCtx(getenv("IB_DEV", 0)) - except (IndexError, AttributeError): self.ib_ctx = None + except (RuntimeError, IndexError, AttributeError): self.ib_ctx = None self.ib_lock = asyncio.Lock() self.ib_conns: dict[str, IBConn|None] = {} self.iova_cache: dict[tuple[SessionKey, int], tuple[int, int, int]] = {} @@ -424,7 +424,7 @@ class RemoteConnection: conns = RemoteConnection.all.keys() datas = {conn: conn.req.serialize() for conn in conns} reqs, hashes, hash_datas = sum(len(c.req._q) for c in conns), sum(len(c.req._h) for c in conns), sum(len(data) for data in datas.values()) - resps = [] + ret, resps = None, [] with Timing(f"*** send {reqs:-3d} requests {hashes:-3d} hashes with len {hash_datas/1024:.2f} kB in ", enabled=DEBUG>=3): for conn,data in datas.items(): conn.conn.request("POST", "/batch", data) for conn in datas.keys(): diff --git a/tinygrad/runtime/ops_tinyfs.py b/tinygrad/runtime/ops_tinyfs.py new file mode 100644 index 0000000000..2d8adde3d0 --- /dev/null +++ b/tinygrad/runtime/ops_tinyfs.py @@ -0,0 +1,128 @@ +import socket, json, asyncio, threading +from contextlib import asynccontextmanager +from tinygrad.device import Compiled, Allocator +from tinygrad.helpers import DEBUG, getenv +from tinygrad import Tensor + +TINYFS_ENDPOINT = getenv("TINYFS_ENDPOINT", "localhost:6767") + +class TinyFSDevice(Compiled): + def __init__(self, device:str): + self.op = device[len("tinyfs:"):].upper() + super().__init__(device, TinyFSAllocator(self), None, None, None) + + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.connect((TINYFS_ENDPOINT.rsplit(":", 1)[0], int(TINYFS_ENDPOINT.rsplit(":", 1)[1]))) + self.sock.settimeout(10) + self.sfile = self.sock.makefile("rwb") + + # fetch node info + self.sfile.write(b"INFO\r\n") + self.sfile.flush() + info = self.sfile.readline() + self.node_info = json.loads(info) + if DEBUG >= 2: print(f"nodes: {self.node_info}") + + # spawn thread for async copyout + self.start_event = threading.Event() + self.t = threading.Thread(target=self._start_thread, daemon=True) + self.t.start() + self.start_event.wait() + + # connection pools + self.conn_pools: dict[str, asyncio.Queue] = {} + self.conn_pools_lock = asyncio.Lock() + + def finalize(self): + self.sfile.close() + + for pool in self.conn_pools.values(): + while not pool.empty(): + _, w = pool.get_nowait() + w.close() + asyncio.run_coroutine_threadsafe(w.wait_closed(), self.loop).result() + + if hasattr(self, "loop"): + self.loop.call_soon_threadsafe(self.loop.stop) + self.t.join() + + def _start_thread(self): + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + self.start_event.set() + self.loop.run_forever() + self.loop.close() + + @asynccontextmanager + async def connection(self, loc): + if loc not in self.conn_pools: + await self.conn_pools_lock.acquire() + if loc not in self.conn_pools: + self.conn_pools[loc] = asyncio.Queue(nw:=getenv("ASYNC_COPY_WORKERS", 4)) + conn_tasks = [asyncio.open_connection(*self.node_info[loc][-1].rsplit(":", 1)) for _ in range(nw)] + connections = await asyncio.gather(*conn_tasks) + for reader, writer in connections: self.conn_pools[loc].put_nowait((reader, writer)) + self.conn_pools_lock.release() + + reader, writer = await self.conn_pools[loc].get() + try: + yield reader, writer + finally: + await self.conn_pools[loc].put((reader, writer)) + +class TinyFSBuffer: + def __init__(self, device:TinyFSDevice, size:int, offset=0, copyout_queue=None, hash_buf=None): + self.device, self.size, self.offset = device, size, offset + self.copyout_queue = copyout_queue or [] + self.hash_buf = hash_buf or bytearray() + def __repr__(self): return f"" + +class TinyFSAllocator(Allocator[TinyFSDevice]): + def _alloc(self, size, options): + return TinyFSBuffer(self.dev, size) + + def _copyin(self, dest:TinyFSBuffer, src:memoryview): + if DEBUG >= 2: print(f"Copying in {dest.size} bytes to TINYFS:{dest.device.op}") + self.dev.sfile.write(f"{dest.device.op}_IN {dest.size}\r\n".encode()) + + self.dev.sfile.write(src) + self.dev.sfile.flush() + + if dest.device.op == "LOAD": + locs = self.dev.sfile.readline() + dest.copyout_queue = json.loads(locs) + dest.hash_buf[:] = src.tobytes() + elif dest.device.op == "STORE": + expected_hashes = dest.size // Tensor.CHUNK_SIZE + dest.hash_buf = bytearray(expected_hashes * 16) + self.dev.sfile.readinto(dest.hash_buf) + + def _copyout(self, dest:memoryview, src:TinyFSBuffer): + if DEBUG >= 2: print(f"Copying out {src.size} bytes from TINYFS:{src.device.op}") + if src.device.op == "LOAD": + asyncio.run_coroutine_threadsafe(self._copyout_async(dest, src), src.device.loop).result() + elif src.device.op == "STORE": + dest[:] = src.hash_buf + + async def _copyout_async(self, dest:memoryview, src:TinyFSBuffer): + async def _worker(i, loc): + async with self.dev.connection(loc) as (reader, writer): + ptr = i * Tensor.CHUNK_SIZE + size = min(len(dest[ptr:ptr+Tensor.CHUNK_SIZE]), Tensor.CHUNK_SIZE) + + writer.write(f"CHUNK_OUT {size}\r\n".encode()) + writer.write(src.hash_buf[i*16:(i+1)*16]) + await asyncio.wait_for(writer.drain(), timeout=10) + + chunk = await asyncio.wait_for(reader.readexactly(size), timeout=10) + + view = dest[ptr:ptr+len(chunk)] + view[:] = chunk + del view + + workers = [asyncio.create_task(_worker(i, loc)) for i, loc in enumerate(src.copyout_queue)] + await asyncio.gather(*workers) + + def _offset(self, buf:TinyFSBuffer, size:int, offset:int): + return TinyFSBuffer(buf.device, size, offset, buf.copyout_queue, buf.hash_buf) diff --git a/tinygrad/runtime/support/am/amdev.py b/tinygrad/runtime/support/am/amdev.py index 7ec9b4ae85..3a8efd8a8e 100644 --- a/tinygrad/runtime/support/am/amdev.py +++ b/tinygrad/runtime/support/am/amdev.py @@ -1,11 +1,11 @@ from __future__ import annotations -import ctypes, collections, dataclasses, functools, os, hashlib +import ctypes, collections, dataclasses, functools, hashlib, array from tinygrad.helpers import mv_address, getenv, DEBUG, fetch from tinygrad.runtime.autogen.am import am from tinygrad.runtime.support.hcq import MMIOInterface from tinygrad.runtime.support.amd import AMDReg, import_module, import_asic_regs from tinygrad.runtime.support.memory import TLSFAllocator, MemoryManager -from tinygrad.runtime.support.system import System, PCIDevImplBase +from tinygrad.runtime.support.system import PCIDevice, PCIDevImplBase from tinygrad.runtime.support.am.ip import AM_SOC, AM_GMC, AM_IH, AM_PSP, AM_SMU, AM_GFX, AM_SDMA AM_DEBUG = getenv("AM_DEBUG", 0) @@ -118,9 +118,9 @@ class AMMemoryManager(MemoryManager): class AMDev(PCIDevImplBase): Version = 0xA0000006 - def __init__(self, devfmt, vram:MMIOInterface, doorbell:MMIOInterface, mmio:MMIOInterface, dma_regions:list[tuple[int, MMIOInterface]]|None=None): - self.devfmt, self.vram, self.doorbell64, self.mmio, self.dma_regions = devfmt, vram, doorbell, mmio, dma_regions - self.lock_fd = System.flock_acquire(f"am_{self.devfmt}.lock") + def __init__(self, pci_dev:PCIDevice, dma_regions:list[tuple[int, MMIOInterface]]|None=None): + self.pci_dev, self.devfmt, self.dma_regions = pci_dev, pci_dev.pcibus, dma_regions + self.vram, self.doorbell64, self.mmio = self.pci_dev.map_bar(0), self.pci_dev.map_bar(2, fmt='Q'), self.pci_dev.map_bar(5, fmt='I') self._run_discovery() self._build_regs() @@ -168,7 +168,7 @@ class AMDev(PCIDevImplBase): # Memory manager & firmware self.mm = AMMemoryManager(self, self.vram_size, boot_size=(32 << 20), pt_t=AMPageTableEntry, va_shifts=[12, 21, 30, 39], va_bits=48, first_lv=am.AMDGPU_VM_PDB2, va_base=AMMemoryManager.va_allocator.base, - palloc_ranges=[(1 << (i + 12), 0x1000) for i in range(9 * (3 - am.AMDGPU_VM_PDB2), -1, -1)]) + palloc_ranges=[(1 << (i + 12), 0x1000) for i in range(9 * (3 - am.AMDGPU_VM_PDB2), -1, -1)], reserve_ptable=not self.large_bar) self.fw = AMFirmware(self) # Initialize IP blocks @@ -188,7 +188,6 @@ class AMDev(PCIDevImplBase): for ip in [self.sdma, self.gfx]: ip.fini_hw() self.smu.set_clocks(level=0) self.ih.interrupt_handler() - os.close(self.lock_fd) def paddr2mc(self, paddr:int) -> int: return self.gmc.mc_base + paddr @@ -217,14 +216,25 @@ class AMDev(PCIDevImplBase): self.reg("regBIF_BX_PF0_RSMU_INDEX").write(reg) self.reg("regBIF_BX_PF0_RSMU_DATA").write(val) + def _read_vram(self, addr, size) -> bytes: + assert addr % 4 == 0 and size % 4 == 0, f"Invalid address {addr:#x} or size {size:#x}" + res = [] + for caddr in range(addr, addr + size, 4): + self.wreg(0x06, caddr >> 31) + self.wreg(0x00, (caddr & 0x7FFFFFFF) | 0x80000000) + res.append(self.rreg(0x01)) + return bytes(array.array('I', res)) + def _run_discovery(self): # NOTE: Fixed register to query memory size without known ip bases to find the discovery table. # The table is located at the end of VRAM - 64KB and is 10KB in size. mmRCC_CONFIG_MEMSIZE = 0xde3 self.vram_size = self.rreg(mmRCC_CONFIG_MEMSIZE) << 20 + self.large_bar = self.vram.nbytes >= self.vram_size tmr_offset, tmr_size = self.vram_size - (64 << 10), (10 << 10) - self.bhdr = am.struct_binary_header.from_buffer(bytearray(self.vram.view(tmr_offset, tmr_size)[:])) + disc_tbl = self.vram.view(tmr_offset, tmr_size)[:] if self.large_bar else self._read_vram(tmr_offset, tmr_size) + self.bhdr = am.struct_binary_header.from_buffer(bytearray(disc_tbl)) ihdr = am.struct_ip_discovery_header.from_address(ctypes.addressof(self.bhdr) + self.bhdr.table_list[am.IP_DISCOVERY].offset) assert self.bhdr.binary_signature == am.BINARY_SIGNATURE and ihdr.signature == am.DISCOVERY_TABLE_SIGNATURE, "discovery signatures mismatch" diff --git a/tinygrad/runtime/support/am/ip.py b/tinygrad/runtime/support/am/ip.py index e6ff7a24e2..39a897d79d 100644 --- a/tinygrad/runtime/support/am/ip.py +++ b/tinygrad/runtime/support/am/ip.py @@ -1,6 +1,6 @@ import ctypes, time, contextlib, functools from typing import Literal -from tinygrad.helpers import to_mv, data64, lo32, hi32, DEBUG, wait_cond +from tinygrad.helpers import to_mv, data64, lo32, hi32, DEBUG, wait_cond, pad_bytes from tinygrad.runtime.autogen.am import am from tinygrad.runtime.support.amd import import_soc @@ -113,7 +113,7 @@ class AM_GMC(AM_IP): for eng_i in range(18): self.adev.wreg_pair(f"reg{ip}VM_INVALIDATE_ENG{eng_i}_ADDR_RANGE", "_LO32", "_HI32", 0x1fffffffff) self.hub_initted[ip] = True - @functools.cache + @functools.cache # pylint: disable=method-cache-max-size-none def get_pte_flags(self, pte_lv, is_table, frag, uncached, system, snooped, valid, extra=0): extra |= (am.AMDGPU_PTE_SYSTEM * system) | (am.AMDGPU_PTE_SNOOPED * snooped) | (am.AMDGPU_PTE_VALID * valid) | am.AMDGPU_PTE_FRAG(frag) if not is_table: extra |= (am.AMDGPU_PTE_WRITEABLE | am.AMDGPU_PTE_READABLE | am.AMDGPU_PTE_EXECUTABLE) @@ -175,7 +175,7 @@ class AM_SMU(AM_IP): def _send_msg(self, msg:int, param:int, read_back_arg=False, timeout=10000, debug=False): # default timeout is 10 seconds self._smu_cmn_send_msg(msg, param, debug=debug) - wait_cond(lambda: (self.adev.mmMP1_SMN_C2PMSG_90 if not debug else self.adev.mmMP1_SMN_C2PMSG_54).read(), value=1, timeout_ms=timeout, + wait_cond((self.adev.mmMP1_SMN_C2PMSG_90 if not debug else self.adev.mmMP1_SMN_C2PMSG_54).read, value=1, timeout_ms=timeout, msg=f"SMU msg {msg:#x} timeout") return (self.adev.mmMP1_SMN_C2PMSG_82 if not debug else self.adev.mmMP1_SMN_C2PMSG_53).read() if read_back_arg else None @@ -242,6 +242,7 @@ class AM_GFX(AM_IP): cp_mqd_control=self.adev.regCP_MQD_CONTROL.encode(priv_state=1), cp_hqd_vmid=0, cp_hqd_aql_control=int(aql), cp_hqd_eop_base_addr_lo=lo32(eop_addr>>8), cp_hqd_eop_base_addr_hi=hi32(eop_addr>>8), cp_hqd_eop_control=self.adev.regCP_HQD_EOP_CONTROL.encode(eop_size=(eop_size//4).bit_length()-2)) + for se in range(8): setattr(mqd_struct, f'compute_static_thread_mgmt_se{se}', 0xffffffff) # Copy mqd into memory self.adev.vram.view(mqd.paddrs[0][0], ctypes.sizeof(mqd_struct))[:] = memoryview(mqd_struct).cast('B') @@ -271,7 +272,7 @@ class AM_GFX(AM_IP): self.adev.regSDMA0_RLC_CGCG_CTRL.update(cgcg_int_enable=1) self.adev.regSDMA1_RLC_CGCG_CTRL.update(cgcg_int_enable=1) - self.adev.regRLC_CGTT_MGCG_OVERRIDE.update(perfmon_clock_state=0, gfxip_fgcg_override=0, gfxip_repeater_fgcg_override=0, + self.adev.regRLC_CGTT_MGCG_OVERRIDE.update(perfmon_clock_state=1, gfxip_fgcg_override=0, gfxip_repeater_fgcg_override=0, grbm_cgtt_sclk_override=0, rlc_cgtt_sclk_override=0, gfxip_mgcg_override=0, gfxip_cgls_override=0, gfxip_cgcg_override=0) self.adev.regRLC_SAFE_MODE.write(message=0, cmd=1) @@ -417,7 +418,8 @@ class AM_PSP(AM_IP): def _prep_msg1(self, data:memoryview): assert len(data) <= self.msg1_view.nbytes, f"msg1 buffer is too small {len(data):#x} > {self.msg1_view.nbytes:#x}" - self.msg1_view[:len(data)+4] = bytes(data) + b'\x00' * 4 + padded_data = pad_bytes(bytes(data) + b'\x00' * 4, 16) # HACK: apple's memcpy requires 16-bytes alignment + self.msg1_view[:len(padded_data)] = padded_data self.adev.gmc.flush_hdp() def _bootloader_load_component(self, fw:int, compid:int): diff --git a/tinygrad/runtime/support/amd.py b/tinygrad/runtime/support/amd.py index bc87ddae81..63450faad0 100644 --- a/tinygrad/runtime/support/amd.py +++ b/tinygrad/runtime/support/amd.py @@ -1,9 +1,10 @@ import functools, importlib, re, urllib from collections import defaultdict from dataclasses import dataclass -from tinygrad.helpers import getbits, round_up, fetch -from tinygrad.runtime.autogen import pci -from tinygrad.runtime.support.usb import ASM24Controller +from tinygrad.helpers import getbits, fetch + +AMDGPU_URL = "https://gitlab.com/linux-kernel/linux-next/-/raw/cf6d949a409e09539477d32dbe7c954e4852e744/drivers/gpu/drm/amd" +ROCM_URL = "https://raw.githubusercontent.com/ROCm/rocm-systems/cccc350dc620e61ae2554978b62ab3532dc10bd9/projects" @dataclass class AMDReg: @@ -26,9 +27,8 @@ class AMDIP: def __getattr__(self, name:str): if name in self.regs: return self.regs[name] - - # NOTE: gfx10 gc registers always start with mm, no reg prefix - return self.regs[name.replace('reg', 'mm')] + if (name10:=name.replace('reg', 'mm')) in self.regs: return self.regs[name10] + raise AttributeError(f"{self.name.upper()} has no register {name}") def fixup_ip_version(ip:str, version:tuple[int, ...]) -> list[tuple[int, ...]]: # override versions @@ -37,19 +37,19 @@ def fixup_ip_version(ip:str, version:tuple[int, ...]) -> list[tuple[int, ...]]: if version[:len(ver)] == ver: return ovrd_ver return version - if ip in ['nbio', 'nbif']: version = _apply_ovrd({(3,3): (2,3,0)}) + if ip in ['nbio', 'nbif']: version = _apply_ovrd({(3,3): (2,3,0), (7,3): (7,2,0)}) elif ip in ['mp', 'smu']: version = _apply_ovrd({(14,0,3): (14,0,2)}) elif ip in ['gc']: version = _apply_ovrd({(9,5,0): (9,4,3)}) return [version, version[:2], version[:2]+(0,), version[:1]+(0, 0)] -def header_download(file, name=None, subdir="defines") -> str: - url = "https://gitlab.com/linux-kernel/linux-next/-/raw/cf6d949a409e09539477d32dbe7c954e4852e744/drivers/gpu/drm/amd" - return fetch(f"{url}/{file}", name=name, subdir=subdir).read_text() +def header_download(file, name=None, subdir="defines", url=AMDGPU_URL) -> str: return fetch(f"{url}/{file}", name=name, subdir=subdir).read_text() -def import_header(path:str): - t = re.sub(r'//.*|/\*.*?\*/','', header_download(path, subdir="defines"), flags=re.S) - return {k:int(v,0) for k,v in re.findall(r'\b([A-Za-z_]\w*)\s*=\s*(0x[0-9A-Fa-f]+|\d+)', t)} +def import_header(path:str, url=AMDGPU_URL): + t = re.sub(r'//.*|/\*.*?\*/','', header_download(path, subdir="defines", url=url), flags=re.S) + # TODO: refactor when clang2py is replaced + return {k:int(v,0) for k,v in re.findall(r'\b([A-Za-z_]\w*)\s*=\s*(0x[0-9A-Fa-f]+|\d+)', t) + \ + re.findall(r'^\s*#\s*define\s+([A-Za-z_0-9]\w*)\s+(0x[0-9A-Fa-f]+|\d+)', t, re.M)} def import_module(name:str, version:tuple[int, ...], version_prefix:str=""): for ver in fixup_ip_version(name, version): @@ -57,7 +57,22 @@ def import_module(name:str, version:tuple[int, ...], version_prefix:str=""): except ImportError: pass raise ImportError(f"Failed to load autogen module for {name.upper()} {'.'.join(map(str, version))}") -def import_soc(ip): return type("SOC", (object,), import_header(f"include/{({9: 'vega10', 10: 'navi10', 11: 'soc21', 12: 'soc24'}[ip[0]])}_enum.h")) +def import_soc(ip): + # rocm soc headers have more profiling enums than upstream linux + return type("SOC", (object,), import_header(f"aqlprofile/linux/{({9: 'vega10', 10: 'navi10', 11: 'soc21', 12: 'soc24'}[ip[0]])}_enum.h", ROCM_URL)) + +def import_ip_offsets(ip): return type("IPOFF", (object,), import_header(f"include/{('sienna_cichlid' if ip[0] > 9 else 'vega20')}_ip_offset.h")) + +def import_pmc(ip) -> dict[str, tuple[str, int]]: + res:dict[str, tuple[str, int]] = {} + arch = f"gfx{ip[0]}{ip[1]:x}{ip[2]:x}" + + for sec in header_download("rocprofiler-compute/src/rocprof_compute_soc/profile_configs/counter_defs.yaml", url=ROCM_URL).split('- name: ')[1:]: + for arch_spec in sec.split('- architectures:')[1:]: + if arch in arch_spec and (block:=re.search(r'block:\s*([A-Za-z0-9_]+)', arch_spec)) and (ev:=re.search(r'event:\s*(\d+)', arch_spec)): + res[sec.splitlines()[0].strip()] = (block.group(1), int(ev.group(1))) + + return res def import_asic_regs(prefix:str, version:tuple[int, ...], cls=AMDReg) -> dict[str, AMDReg]: def _split_name(name): return name[:(pos:=next((i for i,c in enumerate(name) if c.isupper()), len(name)))], name[pos:] @@ -86,53 +101,3 @@ def import_asic_regs(prefix:str, version:tuple[int, ...], cls=AMDReg) -> dict[st # NOTE: Some registers like regGFX_IMU_FUSESTRAP in gc_11_0_0 are missing base idx, just skip them return {reg:cls(name=reg, offset=off, segment=bases[reg], fields=fields[_split_name(reg)[1]]) for reg,off in offsets.items() if reg in bases} raise ImportError(f"Failed to load ASIC registers for {prefix.upper()} {'.'.join(map(str, version))}") - -def setup_pci_bars(usb:ASM24Controller, gpu_bus:int, mem_base:int, pref_mem_base:int) -> dict[int, tuple[int, int]]: - for bus in range(gpu_bus): - # All 3 values must be written at the same time. - buses = (0 << 0) | ((bus+1) << 8) | ((gpu_bus) << 16) - usb.pcie_cfg_req(pci.PCI_PRIMARY_BUS, bus=bus, dev=0, fn=0, value=buses, size=4) - - usb.pcie_cfg_req(pci.PCI_MEMORY_BASE, bus=bus, dev=0, fn=0, value=(mem_base>>16) & 0xffff, size=2) - usb.pcie_cfg_req(pci.PCI_MEMORY_LIMIT, bus=bus, dev=0, fn=0, value=0xffff, size=2) - usb.pcie_cfg_req(pci.PCI_PREF_MEMORY_BASE, bus=bus, dev=0, fn=0, value=(pref_mem_base>>16) & 0xffff, size=2) - usb.pcie_cfg_req(pci.PCI_PREF_MEMORY_LIMIT, bus=bus, dev=0, fn=0, value=0xffff, size=2) - usb.pcie_cfg_req(pci.PCI_PREF_BASE_UPPER32, bus=bus, dev=0, fn=0, value=pref_mem_base >> 32, size=4) - usb.pcie_cfg_req(pci.PCI_PREF_LIMIT_UPPER32, bus=bus, dev=0, fn=0, value=0xffffffff, size=4) - - usb.pcie_cfg_req(pci.PCI_COMMAND, bus=bus, dev=0, fn=0, value=pci.PCI_COMMAND_IO | pci.PCI_COMMAND_MEMORY | pci.PCI_COMMAND_MASTER, size=1) - - # resize bar 0 - cap_ptr = 0x100 - while cap_ptr: - if pci.PCI_EXT_CAP_ID(hdr:=usb.pcie_cfg_req(cap_ptr, bus=gpu_bus, dev=0, fn=0, size=4)) == pci.PCI_EXT_CAP_ID_REBAR: - cap = usb.pcie_cfg_req(cap_ptr + 0x04, bus=gpu_bus, dev=0, fn=0, size=4) - new_ctrl = (usb.pcie_cfg_req(cap_ptr + 0x08, bus=gpu_bus, dev=0, fn=0, size=4) & ~0x1F00) | ((int(cap >> 4).bit_length() - 1) << 8) - usb.pcie_cfg_req(cap_ptr + 0x08, bus=gpu_bus, dev=0, fn=0, value=new_ctrl, size=4) - - cap_ptr = pci.PCI_EXT_CAP_NEXT(hdr) - - mem_space_addr, bar_off, bars = [mem_base, pref_mem_base], 0, {} - while bar_off < 24: - cfg = usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, size=4) - bar_mem, bar_64 = bool(cfg & pci.PCI_BASE_ADDRESS_MEM_PREFETCH), cfg & pci.PCI_BASE_ADDRESS_MEM_TYPE_64 - - if (cfg & pci.PCI_BASE_ADDRESS_SPACE) == pci.PCI_BASE_ADDRESS_SPACE_MEMORY: - usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, value=0xffffffff, size=4) - lo = (usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, size=4) & 0xfffffff0) - - if bar_64: usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off + 4, bus=gpu_bus, dev=0, fn=0, value=0xffffffff, size=4) - hi = (usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off + 4, bus=gpu_bus, dev=0, fn=0, size=4) if bar_64 else 0) - - bar_size = ((~(((hi << 32) | lo) & ~0xf)) + 1) & (0xffffffffffffffff if bar_64 else 0xffffffff) - - usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, value=mem_space_addr[bar_mem] & 0xffffffff, size=4) - if bar_64: usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off + 4, bus=gpu_bus, dev=0, fn=0, value=mem_space_addr[bar_mem] >> 32, size=4) - - bars[bar_off // 4] = (mem_space_addr[bar_mem], bar_size) - mem_space_addr[bar_mem] += round_up(bar_size, 2 << 20) - - bar_off += 8 if bar_64 else 4 - - usb.pcie_cfg_req(pci.PCI_COMMAND, bus=gpu_bus, dev=0, fn=0, value=pci.PCI_COMMAND_IO | pci.PCI_COMMAND_MEMORY | pci.PCI_COMMAND_MASTER, size=1) - return bars diff --git a/tinygrad/runtime/support/autogen.py b/tinygrad/runtime/support/autogen.py new file mode 100644 index 0000000000..ff294e3956 --- /dev/null +++ b/tinygrad/runtime/support/autogen.py @@ -0,0 +1,126 @@ +import ctypes.util, importlib.metadata, itertools, re, functools, os +from tinygrad.helpers import flatten, unwrap +from clang.cindex import Config, Index, CursorKind as CK, TranslationUnit as TU, LinkageKind as LK, TokenKind as ToK, TypeKind as TK +from clang.cindex import PrintingPolicy as PP, PrintingPolicyProperty as PPP, SourceRange + +assert importlib.metadata.version('clang')[:2] == "20" +if not Config.loaded: Config.set_library_file(os.getenv("LIBCLANG_PATH", ctypes.util.find_library("clang-20"))) + +def fst(c): return next(c.get_children()) +def last(c): return list(c.get_children())[-1] +def readext(f, fst, snd=None): + with open(f, "r") as f: + f.seek(start:=(fst.start.offset if isinstance(fst, SourceRange) else fst)) + return f.read((fst.end.offset if isinstance(fst, SourceRange) else snd)-start) +def attrs(c): return list(filter(lambda k: (v:=k.value) >= 400 and v < 500, map(lambda c: c.kind, c.get_children()))) + +base_rules = [(r'\s*\\\n\s*', ' '), (r'\s*\n\s*', ' '), (r'//.*', ''), (r'/\*.*?\*/', ''), (r'\b(0[xX][0-9a-fA-F]+|\d+)[uUlL]+\b', r'\1'), + (r'\b0+(?=\d)', ''), (r'\s*&&\s*', r' and '), (r'\s*\|\|\s*', r' or '), (r'\s*!\s*', ' not '), + (r'(struct|union|enum)\s*([a-zA-Z_][a-zA-Z0-9_]*\b)', r'\1_\2'), + (r'\((unsigned )?(char|uint64_t)\)', ''), (r'^.*\d+:\d+.*$', ''), (r'^.*\w##\w.*$', '')] + +ints = (TK.INT, TK.UINT, TK.LONG, TK.ULONG, TK.LONGLONG, TK.ULONGLONG) + +def gen(dll, files, args=[], prolog=[], rules=[], epilog=[], recsym=False, use_errno=False, anon_names={}, types={}, parse_macros=True): + macros, lines, anoncnt, types = [], [], itertools.count().__next__, {k:(v,True) for k,v in types.items()} + def tname(t, suggested_name=None, typedef=None) -> str: + suggested_name = anon_names.get(f"{(decl:=t.get_declaration()).location.file}:{decl.location.line}", suggested_name) + nonlocal lines, types, anoncnt + tmap = {TK.VOID:"None", TK.CHAR_U:"ctypes.c_ubyte", TK.UCHAR:"ctypes.c_ubyte", TK.CHAR_S:"ctypes.c_char", TK.SCHAR:"ctypes.c_char", + **{getattr(TK, k):f"ctypes.c_{k.lower()}" for k in ["BOOL", "WCHAR", "FLOAT", "DOUBLE", "LONGDOUBLE"]}, + **{getattr(TK, k):f"ctypes.c_{'u' if 'U' in k else ''}int{sz}" for sz,k in + [(16, "USHORT"), (16, "SHORT"), (32, "UINT"), (32, "INT"), (64, "ULONG"), (64, "LONG"), (64, "ULONGLONG"), (64, "LONGLONG")]}} + + if t.kind in tmap: return tmap[t.kind] + if t.spelling in types and types[t.spelling][1]: return types[t.spelling][0] + if ((f:=t).kind in (fks:=(TK.FUNCTIONPROTO, TK.FUNCTIONNOPROTO))) or (t.kind == TK.POINTER and (f:=t.get_pointee()).kind in fks): + return f"ctypes.CFUNCTYPE({tname(f.get_result())}{(', '+', '.join(map(tname, f.argument_types()))) if f.kind==TK.FUNCTIONPROTO else ''})" + match t.kind: + case TK.POINTER: return "ctypes.c_void_p" if (ptr:=t.get_pointee()).kind == TK.VOID else f"ctypes.POINTER({tname(ptr)})" + case TK.ELABORATED: return tname(t.get_named_type(), suggested_name) + case TK.TYPEDEF if t.spelling == t.get_canonical().spelling: return tname(t.get_canonical()) + case TK.TYPEDEF: + defined, nm = (canon:=t.get_canonical()).spelling in types, tname(canon, typedef=t.spelling.replace('::', '_')) + types[t.spelling] = nm if t.spelling.startswith("__") else t.spelling.replace('::', '_'), True + # RECORDs need to handle typedefs specially to allow for self-reference + if canon.kind != TK.RECORD or defined: lines.append(f"{t.spelling.replace('::', '_')} = {nm}") + return types[t.spelling][0] + case TK.RECORD: + # TODO: packed unions + # TODO: pragma pack support + # check for forward declaration + if t.spelling in types: types[t.spelling] = (nm:=types[t.spelling][0]), len(list(t.get_fields())) != 0 + else: + if decl.is_anonymous(): + types[t.spelling] = (nm:=(suggested_name or (f"_anon{'struct' if decl.kind == CK.STRUCT_DECL else 'union'}{anoncnt()}")), True) + else: types[t.spelling] = (nm:=t.spelling.replace(' ', '_').replace('::', '_')), len(list(t.get_fields())) != 0 + lines.append(f"class {nm}({'Struct' if decl.kind==CK.STRUCT_DECL else 'ctypes.Union'}): pass") + if typedef: lines.append(f"{typedef} = {nm}") + acnt = itertools.count().__next__ + ll=[" ("+((fn:=f"'_{acnt()}'")+f", {tname(f.type, nm+fn[1:-1])}" if f.is_anonymous_record_decl() else f"'{f.spelling}', "+ + tname(f.type, f'{nm}_{f.spelling}'))+(f',{f.get_bitfield_width()}' if f.is_bitfield() else '')+")," for f in t.get_fields()] + lines.extend(([f"{nm}._anonymous_ = ["+", ".join(f"'_{i}'" for i in range(n))+"]"] if (n:=acnt()) else [])+ + ([f"{nm}._packed_ = True"] * (CK.PACKED_ATTR in attrs(decl)))+([f"{nm}._fields_ = [",*ll,"]"] if ll else [])) + return nm + case TK.ENUM: + # TODO: C++ and GNU C have forward declared enums + if decl.is_anonymous(): types[t.spelling] = suggested_name or f"_anonenum{anoncnt()}", True + else: types[t.spelling] = t.spelling.replace(' ', '_').replace('::', '_'), True + lines.append(f"{types[t.spelling][0]} = CEnum({tname(decl.enum_type)})\n" + + "\n".join(f"{e.spelling} = {types[t.spelling][0]}.define('{e.spelling}', {e.enum_value})" for e in decl.get_children() + if e.kind == CK.ENUM_CONSTANT_DECL) + "\n") + return types[t.spelling][0] + case TK.CONSTANTARRAY: + return f"({tname(t.get_array_element_type(), suggested_name.rstrip('s') if suggested_name else None)} * {t.get_array_size()})" + case TK.INCOMPLETEARRAY: return f"({tname(t.get_array_element_type(), suggested_name.rstrip('s') if suggested_name else None)} * 0)" + case _: raise NotImplementedError(f"unsupported type {t.kind}") + + for f in files: + tu = Index.create().parse(f, args, options=TU.PARSE_DETAILED_PROCESSING_RECORD) + (pp:=PP.create(tu.cursor)).set_property(PPP.TerseOutput, 1) + for c in tu.cursor.walk_preorder(): + if str(c.location.file) != str(f) and (not recsym or c.kind not in (CK.FUNCTION_DECL,)): continue + rollback = lines, types + try: + match c.kind: + case CK.FUNCTION_DECL if c.linkage == LK.EXTERNAL and dll: + # TODO: we could support name-mangling + lines.append(f"# {c.pretty_printed(pp)}\ntry: ({c.spelling}:=dll.{c.spelling}).restype, {c.spelling}.argtypes = " + f"{tname(c.result_type)}, [{', '.join(tname(arg.type) for arg in c.get_arguments())}]\nexcept AttributeError: pass\n") + case CK.STRUCT_DECL | CK.UNION_DECL | CK.TYPEDEF_DECL | CK.ENUM_DECL: tname(c.type) + case CK.MACRO_DEFINITION if parse_macros and len(toks:=list(c.get_tokens())) > 1: + if toks[1].spelling == '(' and toks[0].extent.end.column == toks[1].extent.start.column: + it = iter(toks[1:]) + _args = [t.spelling for t in itertools.takewhile(lambda t:t.spelling!=')', it) if t.kind == ToK.IDENTIFIER] + if len(body:=list(it)) == 0: continue + macros += [f"{c.spelling} = lambda {','.join(_args)}: {readext(f, body[0].location.offset, toks[-1].extent.end.offset)}"] + else: macros += [f"{c.spelling} = {readext(f, toks[1].location.offset, toks[-1].extent.end.offset)}"] + case CK.VAR_DECL if c.linkage == LK.INTERNAL: + if (c.type.kind == TK.CONSTANTARRAY and c.type.get_array_element_type().get_canonical().kind in ints and + (init:=last(c)).kind == CK.INIT_LIST_EXPR and all(re.match(r"\[.*\].*=", readext(f, c.extent)) for c in init.get_children())): + cs = init.get_children() + macros += [f"{c.spelling} = {{{','.join(f'{readext(f,next(it:=c.get_children()).extent)}:{readext(f,next(it).extent)}' for c in cs)}}}"] + elif c.type.get_canonical().kind in ints: macros += [f"{c.spelling} = {readext(f, last(c).extent)}"] + else: macros += [f"{c.spelling} = {tname(c.type)}({readext(f, last(c).extent)})"] + case CK.VAR_DECL if c.linkage == LK.EXTERNAL and dll: + lines.append(f"try: {c.spelling} = {tname(c.type)}.in_dll(dll, '{c.spelling}')\nexcept (ValueError,AttributeError): pass") + except NotImplementedError as e: + print(f"skipping {c.spelling}: {e}") + lines, types = rollback + main = (f"# mypy: ignore-errors\nimport ctypes{', os' if any('os' in s for s in dll) else ''}\n" + "from tinygrad.helpers import unwrap\nfrom tinygrad.runtime.support.c import Struct, CEnum, _IO, _IOW, _IOR, _IOWR\n" + '\n'.join([*prolog, + *(["from ctypes.util import find_library"]*any('find_library' in s for s in dll)), + *(["def dll():",*flatten([[f" try: return ctypes.CDLL(unwrap({d}){', use_errno=True' if use_errno else ''})",' except: pass'] for d in dll]), + " return None", "dll = dll()\n"]*bool(dll)), *lines]) + '\n') + macros = [r for m in macros if (r:=functools.reduce(lambda s,r:re.sub(r[0], r[1], s), rules + base_rules, m))] + while True: + try: + exec(main + '\n'.join(macros), {}) + break + except (SyntaxError, NameError, TypeError) as e: + macrono = unwrap(e.lineno if isinstance(e, SyntaxError) else unwrap(unwrap(e.__traceback__).tb_next).tb_lineno) - main.count('\n') - 1 + assert macrono >= 0 and macrono < len(macros), f"error outside macro range: {e}" + print(f"skipping {macros[macrono]}: {e}") + del macros[macrono] + except Exception as e: raise Exception("parsing failed") from e + return main + '\n'.join(macros + epilog) diff --git a/tinygrad/runtime/support/c.py b/tinygrad/runtime/support/c.py new file mode 100644 index 0000000000..b06692498c --- /dev/null +++ b/tinygrad/runtime/support/c.py @@ -0,0 +1,72 @@ +import ctypes, functools, sys +from typing import TYPE_CHECKING + +def _do_ioctl(__idir, __base, __nr, __struct, __fd, **kwargs): + import tinygrad.runtime.support.hcq as hcq, fcntl + ioctl = __fd.ioctl if isinstance(__fd, hcq.FileIOInterface) else functools.partial(fcntl.ioctl, __fd) + if (rc:=ioctl((__idir<<30)|(ctypes.sizeof(out:=__struct(**kwargs))<<16)|(__base<<8)|__nr, out)): raise RuntimeError(f"ioctl returned {rc}") + return out + +def _IO(base, nr): return functools.partial(_do_ioctl, 0, ord(base) if isinstance(base, str) else base, nr, None) +def _IOW(base, nr, typ): return functools.partial(_do_ioctl, 1, ord(base) if isinstance(base, str) else base, nr, typ) +def _IOR(base, nr, typ): return functools.partial(_do_ioctl, 2, ord(base) if isinstance(base, str) else base, nr, typ) +def _IOWR(base, nr, typ): return functools.partial(_do_ioctl, 3, ord(base) if isinstance(base, str) else base, nr, typ) + +def CEnum(typ: type[ctypes._SimpleCData]): + class _CEnum(typ): # type: ignore + _val_to_name_: dict[int,str] = {} + + @classmethod + def from_param(cls, val): return val if isinstance(val, cls) else cls(val) + @classmethod + def get(cls, val, default="unknown"): return cls._val_to_name_.get(val.value if isinstance(val, cls) else val, default) + @classmethod + def items(cls): return cls._val_to_name_.items() + @classmethod + def define(cls, name, val): + cls._val_to_name_[val] = name + return val + + def __eq__(self, other): return self.value == other + def __repr__(self): return self.get(self) if self.value in self.__class__._val_to_name_ else str(self.value) + + return _CEnum + +# supports gcc (C11) __attribute__((packed)) +if TYPE_CHECKING: Struct = ctypes.Structure +else: + class MetaStruct(type(ctypes.Structure)): + def __new__(mcs, name, bases, dct): + fields = dct.pop("_fields_", None) + cls = super().__new__(mcs, name, bases, dct) + if dct.get("_packed_", False) and fields is not None: mcs._build(cls, fields) + return cls + + def __setattr__(cls, k, v): + # NB: _fields_ must be set after _packed_ because PyCStructType_setattro marks _fields_ as final. + if k == "_fields_" and getattr(cls, "_packed_", False): type(cls)._build(cls, v) + elif k == "_packed_" and hasattr(cls, "_fields_"): type(cls)._build(cls, cls._fields_) + else: super().__setattr__(k, v) + + @staticmethod + def _build(cls, fields): + o = 0 + for n,t,b in [(f[0], f[1], f[2] if len(f) == 3 else 0) for f in fields]: + if b == 0: o = (o + 7) & ~7 + m = (1 << (sz:=ctypes.sizeof(t)*8 if b == 0 else b)) - 1 + def _s(self,v,m,s,b): self._data[:] = ((int.from_bytes(self._data,sys.byteorder)&~(m<>s)&m,m=m,s=o), + functools.partial(_s,m=m,s=o,b=b))) + o += sz + + type(ctypes.Structure).__setattr__(cls, '_fields_', [('_data', ctypes.c_ubyte * ((o + 7) // 8))]) + type(ctypes.Structure).__setattr__(cls, '_packed_', True) + setattr(cls, '_packed_fields_', fields) + + class Struct(ctypes.Structure, metaclass=MetaStruct): + def __init__(self, *args, **kwargs): + if hasattr(self, '_packed_fields_'): + for f,v in zip(self._packed_fields_, args): setattr(self, f[0], v) + for k,v in kwargs.items(): setattr(self, k, v) + else: super().__init__(*args, **kwargs) + diff --git a/tinygrad/runtime/support/compiler_amd.py b/tinygrad/runtime/support/compiler_amd.py index 88608c71bc..328c12785d 100644 --- a/tinygrad/runtime/support/compiler_amd.py +++ b/tinygrad/runtime/support/compiler_amd.py @@ -1,4 +1,5 @@ -import ctypes, subprocess +import ctypes +from tinygrad.helpers import system import tinygrad.runtime.autogen.comgr as comgr assert comgr.AMD_COMGR_LANGUAGE_HIP == 4 try: @@ -13,8 +14,9 @@ from tinygrad.runtime.support.compiler_cpu import LLVMCompiler from tinygrad.helpers import OSX, to_char_p_p def amdgpu_disassemble(lib:bytes): - asm = subprocess.check_output(["llvm-objdump" if OSX else "/opt/rocm/llvm/bin/llvm-objdump", '-d', '-'], input=lib) - print('\n'.join([x for x in asm.decode('utf-8').split("\n") if 's_code_end' not in x])) + asm = system(f"{'llvm-objdump' if OSX else '/opt/rocm/llvm/bin/llvm-objdump'} -d -", input=lib).splitlines() + while asm and ("s_nop 0" in asm[-1] or "s_code_end" in asm[-1]): asm.pop() + print("\n".join(asm)) def check(status): if status != 0: @@ -60,7 +62,11 @@ def compile_hip(prg:str, arch="gfx1100", asm=False) -> bytes: check(comgr.amd_comgr_set_data_name(data_src, b"")) check(comgr.amd_comgr_data_set_add(data_set_src, data_src)) # -include hiprtc_runtime.h was removed - check(set_options(action_info, f"-O3 -mcumode --hip-version=6.0.32830 -DHIP_VERSION_MAJOR=6 -DHIP_VERSION_MINOR=0 -DHIP_VERSION_PATCH=32830 -D__HIPCC_RTC__ -std=c++14 -nogpuinc -Wno-gnu-line-marker -Wno-missing-prototypes --offload-arch={arch} -I/opt/rocm/include -Xclang -disable-llvm-passes -Xclang -aux-triple -Xclang x86_64-unknown-linux-gnu".encode())) # noqa: E501 + options = [ + "-O3", "-mcumode", "--hip-version=6.0.32830", "-DHIP_VERSION_MAJOR=6", "-DHIP_VERSION_MINOR=0", "-DHIP_VERSION_PATCH=32830", + "-D__HIPCC_RTC__", "-std=c++14", "-nogpuinc", "-Wno-gnu-line-marker", "-Wno-missing-prototypes", f"--offload-arch={arch}", + "-I/opt/rocm/include", "-Xclang -disable-llvm-passes", "-Xclang -aux-triple", "-Xclang x86_64-unknown-linux-gnu"] + check(set_options(action_info, ' '.join(options).encode())) status = comgr.amd_comgr_do_action(comgr.AMD_COMGR_ACTION_COMPILE_SOURCE_WITH_DEVICE_LIBS_TO_BC, action_info, data_set_src, data_set_bc) if status != 0: print(_get_comgr_data(data_set_bc, comgr.AMD_COMGR_DATA_KIND_LOG).decode()) diff --git a/tinygrad/runtime/support/compiler_cpu.py b/tinygrad/runtime/support/compiler_cpu.py index f9ec8d1062..04c2987180 100644 --- a/tinygrad/runtime/support/compiler_cpu.py +++ b/tinygrad/runtime/support/compiler_cpu.py @@ -58,7 +58,7 @@ class LLVMCompiler(Compiler): self.diag_msgs.append(msg) self.handle_diag = handle_diag llvm.LLVMContextSetDiagnosticHandler(llvm.LLVMGetGlobalContext(), handle_diag, None) - super().__init__(f"compile_llvm_{self.target_arch}{'_jit' if self.jit else ''}{'_opt' if opt else ''}") + super().__init__(f"compile_llvm_{processor}_{feats}{'_jit' if self.jit else ''}{'_opt' if opt else ''}") def __del__(self): llvm.LLVMDisposePassBuilderOptions(self.pbo) diff --git a/tinygrad/runtime/support/compiler_cuda.py b/tinygrad/runtime/support/compiler_cuda.py index e10249ed26..fb493c6ab6 100644 --- a/tinygrad/runtime/support/compiler_cuda.py +++ b/tinygrad/runtime/support/compiler_cuda.py @@ -1,6 +1,6 @@ -import subprocess, hashlib, tempfile, ctypes, ctypes.util, re, pathlib +import subprocess, hashlib, tempfile, ctypes, re, pathlib from typing import Callable -from tinygrad.helpers import to_char_p_p, colored, init_c_var, getenv +from tinygrad.helpers import to_char_p_p, colored, init_c_var, getenv, system import tinygrad.runtime.autogen.nvrtc as nvrtc from tinygrad.device import Compiler, CompileError @@ -22,10 +22,12 @@ def jitlink_check(status, ctx=None): def pretty_ptx(s): # all expressions match `` and replace it with `color()` - s = re.sub(r'([!@<\[\s,\+\-;\n])((?:[_%$][\w%\$_]+(?:\.[xyz])?\:?)|(?:buf\d+))([<>\]\s,\+\-;\n\)])', lambda m:m[1]+colored(m[2], "blue")+m[3], s, flags=re.M) # identifiers # noqa: E501 + s = re.sub(r'([!@<\[\s,\+\-;\n])((?:[_%$][\w%\$_]+(?:\.[xyz])?\:?)|(?:buf\d+))([<>\]\s,\+\-;\n\)])', + lambda m:m[1]+colored(m[2], "blue")+m[3], s, flags=re.M) # identifiers s = re.sub(r'(.)((?:b|s|u|f)(?:8|16|32|64)|pred)([\.\s])', lambda m:m[1]+colored(m[2], "green")+m[3], s, flags=re.M) # types s = re.sub(r'^(\s*)([\w]+)(.*?;$)', lambda m:m[1]+colored(m[2], "yellow")+m[3], s, flags=re.M) # instructions - s = re.sub(r'([<>\[\]\s,\+\-;])((?:0[fF][0-9a-fA-F]{8})|(?:[0-9]+)|(?:0[xX][0-9a-fA-F]+))([<>\[\]\s,\+\-;])', lambda m:m[1]+colored(m[2], "yellow")+m[3], s, flags=re.M) # numbers # noqa: E501 + s = re.sub(r'([<>\[\]\s,\+\-;])((?:0[fF][0-9a-fA-F]{8})|(?:[0-9]+)|(?:0[xX][0-9a-fA-F]+))([<>\[\]\s,\+\-;])', + lambda m:m[1]+colored(m[2], "yellow")+m[3], s, flags=re.M) # numbers s = re.sub(r'(\.)(param|reg|global)', lambda m:m[1]+colored(m[2], "magenta"), s, flags=re.M) # space s = re.sub(r'(\.)(version|target|address_size|visible|entry)', lambda m:m[1]+colored(m[2], "magenta"), s, flags=re.M) # derivatives return s @@ -35,7 +37,7 @@ def cuda_disassemble(lib:bytes, arch:str): fn = (pathlib.Path(tempfile.gettempdir()) / f"tinycuda_{hashlib.md5(lib).hexdigest()}").as_posix() with open(fn, "wb") as f: f.write(lib) subprocess.run(["ptxas", f"-arch={arch}", "-o", fn, fn], check=False, stderr=subprocess.DEVNULL) # optional ptx -> sass step for CUDA=1 - print(subprocess.check_output(['nvdisasm', fn]).decode('utf-8')) + print(system(f'nvdisasm {fn}')) except Exception as e: print("Failed to generate SASS", str(e), "Make sure your PATH contains ptxas/nvdisasm binary of compatible version.") class CUDACompiler(Compiler): @@ -58,15 +60,31 @@ class NVCompiler(CUDACompiler): def __init__(self, arch:str): super().__init__(arch, cache_key="nv") def compile(self, src:str) -> bytes: return self._compile_program(src, nvrtc.nvrtcGetCUBIN, nvrtc.nvrtcGetCUBINSize) +class NVCCCompiler(Compiler): + def __init__(self, arch:str, extra_options:list[str]=[]): + self.arch, self.extra_options = arch, extra_options + super().__init__(f"compile_nvcc_{self.arch}_{hashlib.sha256(' '.join(extra_options).encode()).hexdigest()[:8]}") + def compile(self, src:str) -> bytes: + with tempfile.NamedTemporaryFile(suffix=".cu") as srcf, tempfile.NamedTemporaryFile(suffix=".ptx") as libf: + srcf.write(src.encode()) + srcf.flush() + subprocess.run(["nvcc", f"-arch={self.arch}", "-ptx", "-o", libf.name, srcf.name] + self.extra_options, + check=True) + return libf.read() + def disassemble(self, lib:bytes): cuda_disassemble(lib, self.arch) + class PTXCompiler(Compiler): def __init__(self, arch:str, cache_key="ptx"): self.arch = arch super().__init__(f"compile_{cache_key}_{self.arch}") - def compile(self, src:str) -> bytes: return src.replace("TARGET", self.arch).replace("VERSION", "7.8" if self.arch >= "sm_89" else "7.5").encode() + def compile(self, src:str) -> bytes: + return src.replace("TARGET", self.arch).replace("VERSION", "8.7" if (ver:=int(self.arch[3:]))>=120 else ("7.8" if ver>=89 else "7.5")).encode() def disassemble(self, lib:bytes): cuda_disassemble(lib, self.arch) class NVPTXCompiler(PTXCompiler): - def __init__(self, arch:str): super().__init__(arch, cache_key="nv_ptx") + def __init__(self, arch:str): + nvrtc_check(nvrtc.nvJitLinkVersion(ctypes.byref(ctypes.c_uint()), ctypes.byref(ctypes.c_uint()))) + super().__init__(arch, cache_key="nv_ptx") def compile(self, src:str) -> bytes: jitlink_check(nvrtc.nvJitLinkCreate(handle := nvrtc.nvJitLinkHandle(), 1, to_char_p_p([f'-arch={self.arch}'.encode()])), handle) jitlink_check(nvrtc.nvJitLinkAddData(handle, nvrtc.NVJITLINK_INPUT_PTX, ptxsrc:=super().compile(src), len(ptxsrc), "".encode()), handle) diff --git a/tinygrad/runtime/support/compiler_mesa.py b/tinygrad/runtime/support/compiler_mesa.py new file mode 100644 index 0000000000..62f1e40a9c --- /dev/null +++ b/tinygrad/runtime/support/compiler_mesa.py @@ -0,0 +1,86 @@ +import base64, ctypes, pathlib, tempfile, hashlib +from tinygrad.device import Compiler +from tinygrad.helpers import cpu_objdump, system +import tinygrad.runtime.autogen.mesa as mesa +from tinygrad.runtime.support.compiler_cpu import CPULLVMCompiler, expect, cerr +try: import tinygrad.runtime.autogen.llvm as llvm +except (ImportError, FileNotFoundError): llvm = None #type:ignore[assignment] + +def deserialize(enc_src, opts): + blobreader = mesa.struct_blob_reader() + mesa.blob_reader_init(blobreader, src:=base64.b64decode(enc_src), len(src)) + return mesa.nir_deserialize(None, ctypes.cast(opts, ctypes.POINTER(mesa.nir_shader_compiler_options)), blobreader) + +class NIRCompiler(Compiler): + def __init__(self, cache_key): + mesa.glsl_type_singleton_init_or_ref() + super().__init__(cache_key) + def __del__(self): mesa.glsl_type_singleton_decref() + +class LVPCompiler(CPULLVMCompiler, NIRCompiler): + def __init__(self, cache_key="lvp"): + CPULLVMCompiler.__init__(self) + NIRCompiler.__init__(self, f"compile_{cache_key}") + + def __del__(self): + NIRCompiler.__del__(self) + CPULLVMCompiler.__del__(self) + + def compile(self, src) -> bytes: + shader, ctx = deserialize(src, mesa.lvp_nir_options), llvm.LLVMGetGlobalContext() + gallivm = mesa.gallivm_create(None, mesa.lp_context_ref(ctypes.cast(ctx, ctypes.POINTER(mesa.struct_LLVMOpaqueContext)), True), None).contents + module, builder = ctypes.cast(gallivm.module, llvm.LLVMModuleRef), ctypes.cast(gallivm.builder, llvm.LLVMBuilderRef) + + params = mesa.struct_lp_build_tgsi_params(mesa.struct_lp_type(floating=True, sign=True, width=32, length=4), + resources_type=mesa.lp_build_jit_resources_type(gallivm), mask=ctypes.pointer(mesa.struct_lp_build_mask_context())) + + pt = llvm.LLVMPointerType(ctypes.cast(params.resources_type, llvm.LLVMTypeRef), 0) + fn = llvm.LLVMAddFunction(module, shader.contents.info.name, llvm.LLVMFunctionType(llvm.LLVMVoidTypeInContext(ctx), pt, 1, 0)) + llvm.LLVMPositionBuilderAtEnd(builder, llvm.LLVMAppendBasicBlockInContext(ctx, fn, b"entry")) + + params.consts_ptr = mesa.lp_build_struct_get_ptr2(gallivm, params.resources_type, + ctypes.cast(llvm.LLVMGetParam(fn, 0), mesa.LLVMValueRef), mesa.LP_JIT_RES_CONSTANTS, b"constants") + mesa.lp_build_mask_begin(params.mask, gallivm, params.type, mesa.lp_build_one(gallivm, params.type)) + mesa.lp_build_mask_end(params.mask) + + mesa.lp_build_nir_soa(gallivm, shader, params, None) + llvm.LLVMBuildRetVoid(builder) + mesa.gallivm_verify_function(gallivm, ctypes.cast(fn, mesa.LLVMValueRef)) + mesa.lp_passmgr_run(gallivm.passmgr, gallivm.module, ctypes.cast(self.target_machine, mesa.LLVMTargetMachineRef), gallivm.module_name) + obj_buf = expect(llvm.LLVMTargetMachineEmitToMemoryBuffer(self.target_machine, module, llvm.LLVMObjectFile, err:=cerr(), + ctypes.pointer(buf:=llvm.LLVMMemoryBufferRef())), err, buf) + obj = ctypes.string_at(llvm.LLVMGetBufferStart(obj_buf), llvm.LLVMGetBufferSize(obj_buf)) + + mesa.gallivm_destroy(gallivm) + mesa.ralloc_free(shader) + return obj + + def disassemble(self, lib: bytes): cpu_objdump(lib) + +class NAKCompiler(NIRCompiler): + def __init__(self, arch, warps_per_sm, cache_key="nak"): + self.arch, self.warps_per_sm = arch, warps_per_sm + self.cc = mesa.nak_compiler_create(mesa.struct_nv_device_info(sm=int(arch[3:]), max_warps_per_mp=warps_per_sm)) + self.nir_options = bytes(mesa.nak_nir_options(self.cc).contents) + super().__init__(f"compile_{cache_key}_{arch}") + + def __del__(self): + mesa.nak_compiler_destroy(self.cc) + super().__del__() + + def __reduce__(self): return NAKCompiler, (self.arch, self.warps_per_sm) + + def compile(self, src) -> bytes: + shader = deserialize(src, self.nir_options) + mesa.nak_preprocess_nir(shader, self.cc) + ret = bytes((out:=mesa.nak_compile_shader(shader, False, self.cc, 0, None).contents).info) + ctypes.string_at(out.code, out.code_size) + mesa.nak_shader_bin_destroy(out) + mesa.ralloc_free(shader) + return ret + + def disassemble(self, lib: bytes): + try: + fn = (pathlib.Path(tempfile.gettempdir()) / f"tinynak_{hashlib.md5(lib).hexdigest()}").as_posix() + with open(fn, "wb") as f: f.write(lib[ctypes.sizeof(mesa.struct_nak_shader_info):]) + print(system(f"nvdisasm -b SM{self.arch[3:]} {fn}")) + except Exception as e: print("Failed to generate SASS", str(e), "Make sure your PATH contains nvdisasm binary of compatible version.") diff --git a/tinygrad/runtime/support/elf.py b/tinygrad/runtime/support/elf.py index 3276e6adb8..3cbccbe852 100644 --- a/tinygrad/runtime/support/elf.py +++ b/tinygrad/runtime/support/elf.py @@ -1,12 +1,18 @@ -import struct +import struct, ctypes, ctypes.util from dataclasses import dataclass -from tinygrad.helpers import getbits, i2u -import tinygrad.runtime.autogen.libc as libc +from tinygrad.helpers import getbits, i2u, unwrap +from tinygrad.runtime.autogen import libc @dataclass(frozen=True) class ElfSection: name:str; header:libc.Elf64_Shdr; content:bytes # noqa: E702 -def elf_loader(blob:bytes, force_section_align:int=1) -> tuple[memoryview, list[ElfSection], list[tuple]]: +def link_sym(sym:str, libs:list[str]) -> int: + for lib in libs: + try: return unwrap(ctypes.cast(getattr(ctypes.CDLL(ctypes.util.find_library(lib)), sym), ctypes.c_void_p).value) + except (OSError, AttributeError): pass + raise RuntimeError(f'Attempting to relocate against an undefined symbol {sym}') + +def elf_loader(blob:bytes, force_section_align:int=1, link_libs:list[str]|None=None) -> tuple[memoryview, list[ElfSection], list[tuple]]: def _strtab(blob: bytes, idx: int) -> str: return blob[idx:blob.find(b'\x00', idx)].decode('utf-8') header = libc.Elf64_Ehdr.from_buffer_copy(blob) @@ -31,33 +37,42 @@ def elf_loader(blob:bytes, force_section_align:int=1) -> tuple[memoryview, list[ # Relocations relocs = [] for sh, trgt_sh_name, c_rels in rel + rela: + if trgt_sh_name == ".eh_frame": continue target_image_off = next(tsh for tsh in sections if tsh.name == trgt_sh_name).header.sh_addr rels = [(r.r_offset, symtab[libc.ELF64_R_SYM(r.r_info)], libc.ELF64_R_TYPE(r.r_info), getattr(r, "r_addend", 0)) for r in c_rels] - for roff, sym, r_type_, r_addend in rels: - if sym.st_shndx == 0: raise RuntimeError(f'Attempting to relocate against an undefined symbol {repr(_strtab(sh_strtab, sym.st_name))}') - relocs += [(target_image_off + roff, sections[sym.st_shndx].header.sh_addr + sym.st_value, rtype, raddend) for roff, sym, rtype, raddend in rels] + relocs += [(target_image_off + roff, link_sym(_strtab(sh_strtab, sym.st_name), link_libs or []) if sym.st_shndx == 0 else + sections[sym.st_shndx].header.sh_addr + sym.st_value, rtype, raddend) for roff, sym, rtype, raddend in rels] return memoryview(image), sections, relocs -def relocate(instr: int, ploc: int, tgt: int, r_type: int): - match r_type: - # https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf - case libc.R_X86_64_PC32: return i2u(32, tgt-ploc) - # https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst for definitions of relocations - # https://www.scs.stanford.edu/~zyedidia/arm64/index.html for instruction encodings - case libc.R_AARCH64_ADR_PREL_PG_HI21: - rel_pg = (tgt & ~0xFFF) - (ploc & ~0xFFF) - return instr | (getbits(rel_pg, 12, 13) << 29) | (getbits(rel_pg, 14, 32) << 5) - case libc.R_AARCH64_ADD_ABS_LO12_NC: return instr | (getbits(tgt, 0, 11) << 10) - case libc.R_AARCH64_LDST16_ABS_LO12_NC: return instr | (getbits(tgt, 1, 11) << 10) - case libc.R_AARCH64_LDST32_ABS_LO12_NC: return instr | (getbits(tgt, 2, 11) << 10) - case libc.R_AARCH64_LDST64_ABS_LO12_NC: return instr | (getbits(tgt, 3, 11) << 10) - case libc.R_AARCH64_LDST128_ABS_LO12_NC: return instr | (getbits(tgt, 4, 11) << 10) - raise NotImplementedError(f"Encountered unknown relocation type {r_type}") +def jit_loader(obj: bytes, base:int=0, link_libs:list[str]|None=None) -> bytes: + image_, _, relocs = elf_loader(obj, link_libs=link_libs) + image = bytearray(image_) + + def relocate(instr: int, base: int, ploc: int, tgt: int, r_type: int): + match r_type: + # https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf + case libc.R_X86_64_PC32: return i2u(32, tgt-ploc) + case libc.R_X86_64_PLT32: return i2u(32, tgt-ploc-base) + # https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst for definitions of relocations + # https://www.scs.stanford.edu/~zyedidia/arm64/index.html for instruction encodings + case libc.R_AARCH64_ADR_PREL_PG_HI21: + rel_pg = (tgt & ~0xFFF) - (ploc & ~0xFFF) + return instr | (getbits(rel_pg, 12, 13) << 29) | (getbits(rel_pg, 14, 32) << 5) + case libc.R_AARCH64_ADD_ABS_LO12_NC: return instr | (getbits(tgt, 0, 11) << 10) + case libc.R_AARCH64_LDST16_ABS_LO12_NC: return instr | (getbits(tgt, 1, 11) << 10) + case libc.R_AARCH64_LDST32_ABS_LO12_NC: return instr | (getbits(tgt, 2, 11) << 10) + case libc.R_AARCH64_LDST64_ABS_LO12_NC: return instr | (getbits(tgt, 3, 11) << 10) + case libc.R_AARCH64_LDST128_ABS_LO12_NC: return instr | (getbits(tgt, 4, 11) << 10) + case libc.R_AARCH64_CALL26: + if -(2**25) <= tgt-ploc-base and tgt-ploc-base <= (2**25 - 1) * 4: return instr | getbits(tgt-ploc-base, 2, 27) + nonlocal image + # create trampoline: LDR x17, 8 BR x17 + image += struct.pack(" bytes: - image, _, relocs = elf_loader(obj) # This is needed because we have an object file, not a .so that has all internal references (like loads of constants from .rodata) resolved. for ploc,tgt,r_type,r_addend in relocs: - image[ploc:ploc+4] = struct.pack(" int: - if round_up(self.ptr, alignment) + size > self.size: - if not self.wrap: raise RuntimeError("Out of memory") - self.ptr = 0 - self.ptr = (res:=round_up(self.ptr, alignment)) + size - return res + self.base - class HWQueue(Generic[SignalType, HCQDeviceType, ProgramType, ArgsStateType]): """ A base class for hardware command queues in the HCQ (Hardware Command Queue) API. @@ -269,20 +264,20 @@ class HCQSignal(Generic[HCQDeviceType]): @contextlib.contextmanager def hcq_profile(dev:HCQCompiled, enabled, desc, queue_type:Callable[[], HWQueue]|None=None, queue:HWQueue|None=None): st, en = (dev.new_signal(), dev.new_signal()) if enabled else (None, None) + assert queue is not None or queue_type is not None, "Either queue or queue_type must be provided" if enabled and queue is not None: queue.timestamp(st) - elif enabled: - assert queue_type is not None + elif enabled and queue_type is not None: queue_type().wait(dev.timeline_signal, dev.timeline_value - 1).timestamp(st).signal(dev.timeline_signal, dev.next_timeline()).submit(dev) try: yield (st, en) finally: if enabled and queue is not None: queue.timestamp(en) - elif enabled: - assert queue_type is not None + elif enabled and queue_type is not None: queue_type().wait(dev.timeline_signal, dev.timeline_value - 1).timestamp(en).signal(dev.timeline_signal, dev.next_timeline()).submit(dev) - if enabled and PROFILE: dev.sig_prof_records.append((cast(HCQSignal, st), cast(HCQSignal, en), desc, queue_type is dev.hw_copy_queue_t)) + if enabled and PROFILE: + dev.sig_prof_records.append((cast(HCQSignal, st), cast(HCQSignal, en), desc, (queue_type or type(queue)) is dev.hw_copy_queue_t)) class HCQArgsState(Generic[ProgramType]): def __init__(self, buf:HCQBuffer, prg:ProgramType, bufs:tuple[HCQBuffer, ...], vals:tuple[sint, ...]=()): @@ -318,7 +313,7 @@ class HCQProgram(Generic[HCQDeviceType]): Returns: Arguments state with the given buffers and values set for the program. """ - argsbuf = kernargs or self.dev.kernargs_buf.offset(offset=self.dev.kernargs_offset_allocator.alloc(self.kernargs_alloc_size), + argsbuf = kernargs or self.dev.kernargs_buf.offset(offset=self.dev.kernargs_offset_allocator.alloc(self.kernargs_alloc_size, 8), size=self.kernargs_alloc_size) return self.args_state_t(argsbuf, self, bufs, vals=vals) @@ -414,6 +409,8 @@ class HCQCompiled(Compiled, Generic[SignalType]): for dev in HCQCompiled.peer_groups[pg]: cast(HCQAllocator, dev.allocator).map(alc) return self.signal_t(base_buf=HCQCompiled.signal_pool[pg].pop(), owner=self, **kwargs) + def device_props(self) -> dict[str,Any]: return {} # to be overridden if needed. dict keys are backend dependent. + def _at_profile_finalize(self): self.synchronize() # Expect device to be synchronizes @@ -427,7 +424,7 @@ class HCQCompiled(Compiled, Generic[SignalType]): gpu2cpu_compute_time_diff = statistics.median([_sync(self, self.hw_compute_queue_t) for _ in range(40)]) if self.hw_copy_queue_t is None: gpu2cpu_copy_time_diff = decimal.Decimal(0) else: gpu2cpu_copy_time_diff = statistics.median([_sync(self, self.hw_copy_queue_t) for _ in range(40)]) - Compiled.profile_events += [ProfileDeviceEvent(self.device, gpu2cpu_compute_time_diff, gpu2cpu_copy_time_diff)] + Compiled.profile_events += [ProfileDeviceEvent(self.device, gpu2cpu_compute_time_diff, gpu2cpu_copy_time_diff, props=self.device_props())] def _wrap_timeline_signal(self): self.timeline_signal, self._shadow_timeline_signal, self.timeline_value = self._shadow_timeline_signal, self.timeline_signal, 1 @@ -440,19 +437,10 @@ class HCQCompiled(Compiled, Generic[SignalType]): except MemoryError: buf, realloced = self.allocator.alloc(oldbuf.size if oldbuf is not None else new_size, options=options), False return buf, realloced - def _make_no_iface_error(self, errs:str, err_short:str) -> RuntimeError: - # Keep it in a separate function to avoid creating a traceback <-> locals ref cycle - e = RuntimeError(f"No interface for {type(self).__name__[:-6]}:{self.device_id} is available") - if hasattr(e, "add_note"): e.add_note(errs + err_short) - return e - def _select_iface(self, *ifaces:Type): - errs, err_short = "", "" if val:=getenv(f'{type(self).__name__[:-6].upper()}_IFACE', ""): ifaces = tuple(x for x in ifaces if x.__name__.startswith(val.upper())) - for iface_t in ifaces: - try: return iface_t(self, self.device_id) - except Exception as e: errs, err_short = errs + f"\n{iface_t.__name__}: {traceback.format_exc()}", err_short + f"\n{iface_t.__name__}: {e}." - raise self._make_no_iface_error(errs, err_short) + return select_first_inited([functools.partial(cast(Callable, iface), self, self.device_id) for iface in ifaces], + f"No interface for {type(self).__name__[:-6]}:{self.device_id} is available") def _is_cpu(self) -> bool: return hasattr(self, 'device') and self.device.split(":")[0] == "CPU" @@ -517,7 +505,7 @@ class HCQAllocator(HCQAllocatorBase, Generic[HCQDeviceType]): self.dev.timeline_signal.wait(self.b_timeline[self.b_next]) lsize = min(self.b[self.b_next].size, src.nbytes - i) - self.b[self.b_next].cpu_view().view(size=lsize, fmt='B')[:] = src[i:i+lsize] + self.b[self.b_next].cpu_view().view(size=lsize, fmt='B')[:] = src.cast('B')[i:i+lsize] self.dev.hw_copy_queue_t().wait(self.dev.timeline_signal, self.dev.timeline_value - 1) \ .copy(dest.va_addr+i, self.b[self.b_next].va_addr, lsize) \ .signal(self.dev.timeline_signal, self.dev.next_timeline()).submit(self.dev) @@ -549,7 +537,7 @@ class HCQAllocator(HCQAllocatorBase, Generic[HCQDeviceType]): .copy(self.b[0].va_addr, src.va_addr+i, lsize:=min(cp_size, dest.nbytes-i)) \ .signal(self.dev.timeline_signal, self.dev.next_timeline()).submit(self.dev) self.dev.timeline_signal.wait(self.dev.timeline_value - 1) - dest[i:i+lsize] = self.b[0].cpu_view().view(size=lsize, fmt='B')[:] + dest.cast('B')[i:i+lsize] = self.b[0].cpu_view().view(size=lsize, fmt='B')[:] def _transfer(self, dest:HCQBuffer, src:HCQBuffer, sz:int, src_dev:HCQDeviceType, dest_dev:HCQDeviceType): cast(HCQAllocator, src_dev.allocator).map(dest) diff --git a/tinygrad/runtime/support/ib.py b/tinygrad/runtime/support/ib.py index 06c1220e42..c50f8ad03c 100644 --- a/tinygrad/runtime/support/ib.py +++ b/tinygrad/runtime/support/ib.py @@ -10,7 +10,7 @@ DEFAULT_PORT, DEFAULT_GID = getenv("DEFAULT_PORT", 1), getenv("DEFAULT_GID", 3) IOVA_ALIGN = resource.getpagesize() def checkz(x, ret=None): - assert x == 0, f'{x} != 0 (errno {ctypes.get_errno()})' + if x != 0: raise RuntimeError(f'{x} != 0 (errno {ctypes.get_errno()})') return ret @dataclass(frozen=True) diff --git a/tinygrad/runtime/support/llvm.py b/tinygrad/runtime/support/llvm.py index d20de02a67..58a95920cd 100644 --- a/tinygrad/runtime/support/llvm.py +++ b/tinygrad/runtime/support/llvm.py @@ -1,5 +1,5 @@ -import ctypes, ctypes.util, os, sys, subprocess -from tinygrad.helpers import DEBUG, OSX, getenv +import ctypes.util, os, sys +from tinygrad.helpers import DEBUG, OSX, getenv, system if sys.platform == 'win32': # Windows llvm distribution doesn't seem to add itself to PATH or anywhere else where it can be easily retrieved from. @@ -10,13 +10,13 @@ if sys.platform == 'win32': elif OSX: # Will raise FileNotFoundError if brew is not installed # `brew --prefix` will return even if formula is not installed - if not os.path.exists(brew_prefix:=subprocess.check_output(['brew', '--prefix', 'llvm@20']).decode().strip()): + if not os.path.exists(brew_prefix:=system("brew --prefix llvm@20")): raise FileNotFoundError('LLVM not found, you can install it with `brew install llvm@20`') LLVM_PATH: str|None = os.path.join(brew_prefix, 'lib', 'libLLVM.dylib') else: LLVM_PATH = ctypes.util.find_library('LLVM') # use newer LLVM if possible - for ver in reversed(range(14, 20+1)): + for ver in reversed(range(14, 21+1)): if LLVM_PATH is not None: break LLVM_PATH = ctypes.util.find_library(f'LLVM-{ver}') if LLVM_PATH is None: diff --git a/tinygrad/runtime/support/memory.py b/tinygrad/runtime/support/memory.py index 0c74ea4127..c6718fdba3 100644 --- a/tinygrad/runtime/support/memory.py +++ b/tinygrad/runtime/support/memory.py @@ -2,6 +2,15 @@ import collections, functools, dataclasses from typing import Any, ClassVar from tinygrad.helpers import round_up, getenv +class BumpAllocator: + def __init__(self, size:int, base:int=0, wrap:bool=True): self.size, self.ptr, self.base, self.wrap = size, 0, base, wrap + def alloc(self, size:int, alignment:int=1) -> int: + if round_up(self.ptr, alignment) + size > self.size: + if not self.wrap: raise RuntimeError("Out of memory") + self.ptr = 0 + self.ptr = (res:=round_up(self.ptr, alignment)) + size + return res + self.base + class TLSFAllocator: """ The allocator is based on the Two-Level Segregated Fit (TLSF) algorithm. The allocator maintains 2 level of buckets: @@ -19,12 +28,12 @@ class TLSFAllocator: # self.blocks is more like a linked list, where each entry is a contiguous block. self.blocks:dict[int, tuple[int, int|None, int|None, bool]] = {0: (size, None, None, True)} # size, next, prev, is_free - self._insert_block(0, size) + if size > 0: self._insert_block(0, size) - @functools.cache + @functools.cache # pylint: disable=method-cache-max-size-none def lv1(self, size): return size.bit_length() - @functools.cache + @functools.cache # pylint: disable=method-cache-max-size-none def lv2(self, size): return (size - (1 << (size.bit_length() - 1))) // (1 << max(0, size.bit_length() - self.l2_cnt)) def _insert_block(self, start:int, size:int, prev:int|None=None): @@ -115,7 +124,7 @@ class PageTableTraverseContext: if not pt.valid(pte_idx): assert self.create_pts, "Not allowed to create new page table" - pt.set_entry(pte_idx, self.dev.mm.palloc(0x1000, zero=True, boot=self.boot), table=True, valid=True) + pt.set_entry(pte_idx, self.dev.mm.palloc(0x1000, zero=True, boot=self.boot, ptable=True), table=True, valid=True) assert not pt.is_page(pte_idx), f"Must be table pt={pt.paddr:#x}, {pt.lv=} {pte_idx=} {pt.read_fields(pte_idx)}" child_page_table = self.dev.mm.pt_t(self.dev, pt.address(pte_idx), lv=pt.lv+1) @@ -126,7 +135,7 @@ class PageTableTraverseContext: def _try_free_pt(self) -> bool: pt, _, _ = self.pt_stack[-1] if self.free_pts and pt != self.dev.mm.root_page_table and all(not pt.valid(i) for i in range(self._pt_pte_cnt(self.pt_stack[-1][0].lv))): - self.dev.mm.pfree(pt.paddr) + self.dev.mm.pfree(pt.paddr, ptable=True) parent_pt, parent_pte_idx, _ = self.pt_stack[-2] parent_pt.set_entry(parent_pte_idx, 0x0, valid=False) return True @@ -158,13 +167,14 @@ class MemoryManager: va_allocator: ClassVar[TLSFAllocator|None] = None def __init__(self, dev, vram_size:int, boot_size:int, pt_t, va_bits:int, va_shifts:list[int], va_base:int, - palloc_ranges:list[tuple[int, int]], first_lv:int=0): + palloc_ranges:list[tuple[int, int]], first_lv:int=0, reserve_ptable=False): self.dev, self.vram_size, self.va_shifts, self.va_base, lvl_msb = dev, vram_size, va_shifts, va_base, va_shifts + [va_bits + 1] self.pte_covers, self.pte_cnt = [1 << x for x in va_shifts][::-1], [1 << (lvl_msb[i+1] - lvl_msb[i]) for i in range(len(lvl_msb) - 1)][::-1] - self.pt_t, self.palloc_ranges, self.level_cnt, self.va_bits = pt_t, palloc_ranges, len(va_shifts), va_bits + self.pt_t, self.palloc_ranges, self.level_cnt, self.va_bits, self.reserve_ptable = pt_t, palloc_ranges, len(va_shifts), va_bits, reserve_ptable - self.boot_allocator = TLSFAllocator(boot_size, base=0) # per device - self.pa_allocator = TLSFAllocator(vram_size - (64 << 20), base=self.boot_allocator.size) # per device + self.boot_allocator = TLSFAllocator(boot_size, base=0) + self.ptable_allocator = TLSFAllocator(round_up(vram_size // 512, 1 << 20) if self.reserve_ptable else 0, base=self.boot_allocator.size) + self.pa_allocator = TLSFAllocator(vram_size - (64 << 20), base=self.boot_allocator.size + self.ptable_allocator.size) self.root_page_table = pt_t(self.dev, self.palloc(0x1000, zero=not self.dev.smi_dev, boot=True), lv=first_lv) def _frag_size(self, va, sz, must_cover=True): @@ -200,7 +210,7 @@ class MemoryManager: if getenv("MM_DEBUG", 0): print(f"mm {self.dev.devfmt}: unmapping {vaddr=:#x} ({size=:#x})") ctx = PageTableTraverseContext(self.dev, self.root_page_table, vaddr, free_pts=True) - for off, pt, pte_idx, pte_cnt, pte_covers in ctx.next(size): + for _, pt, pte_idx, pte_cnt, _ in ctx.next(size): for pte_id in range(pte_idx, pte_idx + pte_cnt): assert pt.valid(pte_id), f"PTE not mapped: {pt.entry(pte_id):#x}" pt.set_entry(pte_id, paddr=0x0, valid=False) @@ -241,10 +251,11 @@ class MemoryManager: self.va_allocator.free(vm.va_addr) for paddr, _ in vm.paddrs: self.pa_allocator.free(paddr) - def palloc(self, size:int, align:int=0x1000, zero=True, boot=False) -> int: + def palloc(self, size:int, align:int=0x1000, zero=True, boot=False, ptable=False) -> int: assert self.dev.is_booting == boot, "During booting, only boot memory can be allocated" - paddr = (self.boot_allocator if boot else self.pa_allocator).alloc(round_up(size, 0x1000), align) + allocator = self.boot_allocator if boot else (self.ptable_allocator if self.reserve_ptable and ptable else self.pa_allocator) + paddr = allocator.alloc(round_up(size, 0x1000), align) if zero: self.dev.vram[paddr:paddr+size] = bytes(size) return paddr - def pfree(self, paddr:int): self.pa_allocator.free(paddr) + def pfree(self, paddr:int, ptable=False): (self.ptable_allocator if self.reserve_ptable and ptable else self.pa_allocator).free(paddr) diff --git a/tinygrad/runtime/support/nv/ip.py b/tinygrad/runtime/support/nv/ip.py index 2037960215..7bce6314c9 100644 --- a/tinygrad/runtime/support/nv/ip.py +++ b/tinygrad/runtime/support/nv/ip.py @@ -5,7 +5,7 @@ from tinygrad.runtime.autogen.nv import nv from tinygrad.helpers import to_mv, lo32, hi32, DEBUG, round_up, round_down, mv_address, fetch, wait_cond from tinygrad.runtime.support.system import System from tinygrad.runtime.support.elf import elf_loader -from tinygrad.runtime.autogen import nv_gpu +from tinygrad.runtime.autogen import nv_gpu, pci @dataclasses.dataclass(frozen=True) class GRBufDesc: size:int; virt:bool; phys:bool; local:bool=False # noqa: E702 @@ -49,8 +49,9 @@ class NVRpcQueue: self.seq += 1 self.gsp.nvdev.NV_PGSP_QUEUE_HEAD[0].write(0x0) - def wait_resp(self, cmd:int) -> memoryview: - while True: + def wait_resp(self, cmd:int, timeout=10000) -> memoryview: + start_time = int(time.perf_counter() * 1000) + while (int(time.perf_counter() * 1000) - start_time) < timeout: System.memory_barrier() if self.rx.readPtr == self.tx.writePtr: continue @@ -73,6 +74,7 @@ class NVRpcQueue: if hdr.rpc_result != 0: raise RuntimeError(f"RPC call {hdr.function} failed with result {hdr.rpc_result}") if hdr.function == cmd: return msg + raise RuntimeError(f"Timeout waiting for RPC response for command {cmd}") class NV_FLCN(NV_IP): def init_sw(self): @@ -89,10 +91,18 @@ class NV_FLCN(NV_IP): self.prep_booter() def prep_ucode(self): - expansion_rom_off, bit_addr = {"GA": 0x16600, "AD": 0x14e00}[self.nvdev.chip_name[:2]], 0x1b0 - vbios_bytes = bytes(array.array('I', self.nvdev.mmio[0x00300000//4:(0x00300000+0x98e00)//4])) + vbios_bytes, vbios_off = memoryview(bytes(array.array('I', self.nvdev.mmio[0x00300000//4:(0x00300000+0x100000)//4]))), 0 + while True: + pci_blck = vbios_bytes[vbios_off + nv.OFFSETOF_PCI_EXP_ROM_PCI_DATA_STRUCT_PTR:].cast('H')[0] + imglen = vbios_bytes[vbios_off + pci_blck + nv.OFFSETOF_PCI_DATA_STRUCT_IMAGE_LEN:].cast('H')[0] * nv.PCI_ROM_IMAGE_BLOCK_SIZE + match vbios_bytes[vbios_off + pci_blck + nv.OFFSETOF_PCI_DATA_STRUCT_CODE_TYPE]: + case nv.NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_BASE: block_size = imglen + case nv.NV_BCRT_HASH_INFO_BASE_CODE_TYPE_VBIOS_EXT: + expansion_rom_off = vbios_off - block_size + break + vbios_off += imglen - bit_header = nv.BIT_HEADER_V1_00.from_buffer_copy(vbios_bytes[bit_addr:bit_addr + ctypes.sizeof(nv.BIT_HEADER_V1_00)]) + bit_header = nv.BIT_HEADER_V1_00.from_buffer_copy(vbios_bytes[(bit_addr:=0x1b0):bit_addr + ctypes.sizeof(nv.BIT_HEADER_V1_00)]) assert bit_header.Signature == 0x00544942, f"Invalid BIT header signature {hex(bit_header.Signature)}" for i in range(bit_header.TokenEntries): @@ -124,6 +134,7 @@ class NV_FLCN(NV_IP): def __patch(cmd_id, cmd): patched_image = bytearray(image) + dmem_offset = 0 hdr = nv.FALCON_APPLICATION_INTERFACE_HEADER_V1.from_buffer_copy(image[(app_hdr_off:=self.desc_v3.IMEMLoadSize+self.desc_v3.InterfaceOffset):]) ents = (nv.FALCON_APPLICATION_INTERFACE_ENTRY_V1 * hdr.entryCount).from_buffer_copy(image[app_hdr_off + ctypes.sizeof(hdr):]) for i in range(hdr.entryCount): @@ -138,7 +149,7 @@ class NV_FLCN(NV_IP): return System.alloc_sysmem(len(patched_image), contiguous=True, data=patched_image) - self.frts_image_va, self.frts_image_sysmem = __patch(0x15, bytes(frts_cmd)) + _, self.frts_image_sysmem = __patch(0x15, bytes(frts_cmd)) def prep_booter(self): image = self.nvdev.extract_fw("kgspBinArchiveBooterLoadUcode", "image_prod_data") @@ -149,7 +160,7 @@ class NV_FLCN(NV_IP): patched_image = bytearray(image) patched_image[patch_loc:patch_loc+sig_len] = sig[:sig_len] - self.booter_image_va, self.booter_image_sysmem = System.alloc_sysmem(len(patched_image), contiguous=True, data=patched_image) + _, self.booter_image_sysmem = System.alloc_sysmem(len(patched_image), contiguous=True, data=patched_image) _, _, self.booter_data_off, self.booter_data_sz, _, self.booter_code_off, self.booter_code_sz, _, _ = struct.unpack("9I", header) def init_hw(self): @@ -326,18 +337,18 @@ class NV_GSP(NV_IP): # Alloc queues pte_cnt = ((queue_pte_cnt:=(queue_size * 2) // 0x1000)) + round_up(queue_pte_cnt * 8, 0x1000) // 0x1000 pt_size = round_up(pte_cnt * 8, 0x1000) - queues_va, queues_sysmem = System.alloc_sysmem(pt_size + queue_size * 2, contiguous=False) + queues_view, queues_sysmem = System.alloc_sysmem(pt_size + queue_size * 2, contiguous=False) # Fill up ptes - for i, sysmem in enumerate(queues_sysmem): to_mv(queues_va + i * 0x8, 0x8).cast('Q')[0] = sysmem + for i, sysmem in enumerate(queues_sysmem): queues_view.view(i * 0x8, 0x8, fmt='Q')[0] = sysmem # Fill up arguments queue_args = nv.MESSAGE_QUEUE_INIT_ARGUMENTS(sharedMemPhysAddr=queues_sysmem[0], pageTableEntryCount=pte_cnt, cmdQueueOffset=pt_size, statQueueOffset=pt_size + queue_size) - rm_args, self.rm_args_sysmem = self.nvdev._alloc_boot_struct(nv.GSP_ARGUMENTS_CACHED(bDmemStack=True, messageQueueInitArguments=queue_args)) + _, self.rm_args_sysmem = self.nvdev._alloc_boot_struct(nv.GSP_ARGUMENTS_CACHED(bDmemStack=True, messageQueueInitArguments=queue_args)) # Build command queue header - self.cmd_q_va, self.stat_q_va = queues_va + pt_size, queues_va + pt_size + queue_size + self.cmd_q_va, self.stat_q_va = queues_view.addr + pt_size, queues_view.addr + pt_size + queue_size cmd_q_tx = nv.msgqTxHeader(version=0, size=queue_size, entryOff=0x1000, msgSize=0x1000, msgCount=(queue_size - 0x1000) // 0x1000, writePtr=0, flags=1, rxHdrOff=ctypes.sizeof(nv.msgqTxHeader)) @@ -347,9 +358,9 @@ class NV_GSP(NV_IP): def init_libos_args(self): _, logbuf_sysmem = System.alloc_sysmem((2 << 20), contiguous=True) - libos_args_va, self.libos_args_sysmem = System.alloc_sysmem(0x1000, contiguous=True) + libos_args_view, self.libos_args_sysmem = System.alloc_sysmem(0x1000, contiguous=True) - libos_structs = (nv.LibosMemoryRegionInitArgument * 6).from_address(libos_args_va) + libos_structs = (nv.LibosMemoryRegionInitArgument * 6).from_address(libos_args_view.addr) for i, name in enumerate(["INIT", "INTR", "RM", "MNOC", "KRNL"]): libos_structs[i] = nv.LibosMemoryRegionInitArgument(kind=nv.LIBOS_MEMORY_REGION_CONTIGUOUS, loc=nv.LIBOS_MEMORY_REGION_LOC_SYSMEM, size=0x10000, id8=int.from_bytes(bytes(f"LOG{name}", 'utf-8'), 'big'), pa=logbuf_sysmem[0] + 0x10000 * i) @@ -369,18 +380,18 @@ class NV_GSP(NV_IP): for i in range(3, 0, -1): npages[i-1] = ((npages[i] - 1) >> (nv.LIBOS_MEMORY_REGION_RADIX_PAGE_LOG2 - 3)) + 1 offsets = [sum(npages[:i]) * 0x1000 for i in range(4)] - radix_va, self.gsp_radix3_sysmem = System.alloc_sysmem(offsets[-1] + len(self.gsp_image), contiguous=False) + radix_view, self.gsp_radix3_sysmem = System.alloc_sysmem(offsets[-1] + len(self.gsp_image), contiguous=False) # Copy image - to_mv(radix_va + offsets[-1], len(self.gsp_image))[:] = self.gsp_image + radix_view.view(offsets[-1], len(self.gsp_image))[:] = self.gsp_image # Copy level and image pages. for i in range(0, 3): cur_offset = sum(npages[:i+1]) - to_mv(radix_va + offsets[i], npages[i+1] * 8).cast('Q')[:] = array.array('Q', self.gsp_radix3_sysmem[cur_offset:cur_offset+npages[i+1]]) + radix_view.view(offsets[i], npages[i+1] * 8, fmt='Q')[:] = array.array('Q', self.gsp_radix3_sysmem[cur_offset:cur_offset+npages[i+1]]) # Copy signature - self.gsp_signature_va, self.gsp_signature_sysmem = System.alloc_sysmem(len(signature), contiguous=True, data=signature) + _, self.gsp_signature_sysmem = System.alloc_sysmem(len(signature), contiguous=True, data=signature) def init_boot_binary_image(self): self.booter_image = self.nvdev.extract_fw("kgspBinArchiveGspRmBoot", "ucode_image_prod_data") @@ -481,7 +492,7 @@ class NV_GSP(NV_IP): params.ramfcMem = nv_gpu.NV_MEMORY_DESC_PARAMS(base=ramfc_alloc.paddrs[0][0], size=0x200, addressSpace=2, cacheAttrib=0) params.instanceMem = nv_gpu.NV_MEMORY_DESC_PARAMS(base=ramfc_alloc.paddrs[0][0], size=0x1000, addressSpace=2, cacheAttrib=0) - method_va, method_sysmem = System.alloc_sysmem(0x5000, contiguous=True) + _, method_sysmem = System.alloc_sysmem(0x5000, contiguous=True) params.mthdbufMem = nv_gpu.NV_MEMORY_DESC_PARAMS(base=method_sysmem[0], size=0x5000, addressSpace=1, cacheAttrib=0) if client is not None and client != self.priv_root and params.hObjectError != 0: @@ -521,11 +532,13 @@ class NV_GSP(NV_IP): self.stat_q.wait_resp(nv.NV_VGPU_MSG_FUNCTION_SET_PAGE_DIRECTORY) def rpc_set_gsp_system_info(self): - def bdf_as_int(s): return (int(s[5:7],16)<<8) | (int(s[8:10],16)<<3) | int(s[-1],16) + def bdf_as_int(s): return 0x000 if s.startswith("usb") else (int(s[5:7],16)<<8) | (int(s[8:10],16)<<3) | int(s[-1],16) - data = nv.GspSystemInfo(gpuPhysAddr=self.nvdev.bars[0][0], gpuPhysFbAddr=self.nvdev.bars[1][0], gpuPhysInstAddr=self.nvdev.bars[3][0], + pcidev = self.nvdev.pci_dev + data = nv.GspSystemInfo(gpuPhysAddr=pcidev.bar_info[0].addr, gpuPhysFbAddr=pcidev.bar_info[1].addr, gpuPhysInstAddr=pcidev.bar_info[3].addr, pciConfigMirrorBase=[0x88000, 0x92000][self.nvdev.fmc_boot], pciConfigMirrorSize=0x1000, nvDomainBusDeviceFunc=bdf_as_int(self.nvdev.devfmt), - bIsPassthru=1, PCIDeviceID=self.nvdev.venid, PCISubDeviceID=self.nvdev.subvenid, PCIRevisionID=self.nvdev.rev, maxUserVa=0x7ffffffff000) + bIsPassthru=1, PCIDeviceID=pcidev.read_config(pci.PCI_VENDOR_ID, 4), PCISubDeviceID=pcidev.read_config(pci.PCI_SUBSYSTEM_VENDOR_ID, 4), + PCIRevisionID=pcidev.read_config(pci.PCI_REVISION_ID, 1), maxUserVa=0x7ffffffff000) self.cmd_q.send_rpc(nv.NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO, bytes(data)) def rpc_unloading_guest_driver(self): @@ -557,7 +570,7 @@ class NV_GSP(NV_IP): self.nvdev.wreg(addr, (self.nvdev.rreg(addr) & ~mask) | (val & mask)) elif op == 0x2: # reg poll addr, mask, val, _, _ = next(cmd_iter), next(cmd_iter), next(cmd_iter), next(cmd_iter), next(cmd_iter) - wait_cond(lambda: (self.nvdev.rreg(addr) & mask), value=val, msg=f"Register {addr:#x} not equal to {val:#x} after polling") + wait_cond(lambda a, m: (self.nvdev.rreg(a) & m), addr, mask, value=val, msg=f"Register {addr:#x} not equal to {val:#x} after polling") elif op == 0x3: time.sleep(next(cmd_iter) / 1e6) # delay us elif op == 0x4: # save reg addr, index = next(cmd_iter), next(cmd_iter) diff --git a/tinygrad/runtime/support/nv/nvdev.py b/tinygrad/runtime/support/nv/nvdev.py index 6831b5e8b1..c004c43b20 100644 --- a/tinygrad/runtime/support/nv/nvdev.py +++ b/tinygrad/runtime/support/nv/nvdev.py @@ -1,10 +1,9 @@ from __future__ import annotations import ctypes, time, functools, re, gzip, struct -from tinygrad.helpers import getenv, DEBUG, fetch, getbits, to_mv -from tinygrad.runtime.support.hcq import MMIOInterface +from tinygrad.helpers import getenv, DEBUG, fetch, getbits from tinygrad.runtime.support.memory import TLSFAllocator, MemoryManager from tinygrad.runtime.support.nv.ip import NV_FLCN, NV_FLCN_COT, NV_GSP -from tinygrad.runtime.support.system import System, PCIDevImplBase +from tinygrad.runtime.support.system import System, PCIDevice, PCIDevImplBase NV_DEBUG = getenv("NV_DEBUG", 0) @@ -71,9 +70,8 @@ class NVMemoryManager(MemoryManager): def on_range_mapped(self): self.dev.NV_VIRTUAL_FUNCTION_PRIV_MMU_INVALIDATE.write((1 << 0) | (1 << 1) | (1 << 6) | (1 << 31)) class NVDev(PCIDevImplBase): - def __init__(self, devfmt:str, mmio:MMIOInterface, vram:MMIOInterface, venid:int, subvenid:int, rev:int, bars:dict): - self.devfmt, self.mmio, self.vram, self.venid, self.subvenid, self.rev, self.bars = devfmt, mmio, vram, venid, subvenid, rev, bars - self.lock_fd = System.flock_acquire(f"nv_{self.devfmt}.lock") + def __init__(self, pci_dev:PCIDevice): + self.pci_dev, self.devfmt, self.mmio = pci_dev, pci_dev.pcibus, pci_dev.map_bar(0, fmt='I') self.smi_dev, self.is_booting = False, True self._early_init() @@ -87,7 +85,7 @@ class NVDev(PCIDevImplBase): # 5 PTE_64K / PTE_4K 20:16 / 20:12 bits, shifts = (56, [12, 21, 29, 38, 47, 56]) if self.mmu_ver == 3 else (48, [12, 21, 29, 38, 47]) self.mm = NVMemoryManager(self, self.vram_size, boot_size=(2 << 20), pt_t=NVPageTableEntry, va_bits=bits, va_shifts=shifts, va_base=0, - palloc_ranges=[(x, x) for x in [512 << 20, 2 << 20, 4 << 10]]) + palloc_ranges=[(x, x) for x in [512 << 20, 2 << 20, 4 << 10]], reserve_ptable=not self.large_bar) self.flcn:NV_FLCN|NV_FLCN_COT = NV_FLCN_COT(self) if self.fmc_boot else NV_FLCN(self) self.gsp:NV_GSP = NV_GSP(self) @@ -114,12 +112,13 @@ class NVDev(PCIDevImplBase): self.chip_id = self.reg("NV_PMC_BOOT_0").read() self.chip_details = self.reg("NV_PMC_BOOT_42").read_bitfields() self.chip_name = {0x17: "GA1", 0x19: "AD1", 0x1b: "GB2"}[self.chip_details['architecture']] + f"{self.chip_details['implementation']:02d}" + self.fw_name = {"GB2": "GB202", "AD1": "AD102", "GA1": "GA102"}[self.chip_name[:3]] self.mmu_ver, self.fmc_boot = (3, True) if self.chip_details['architecture'] >= 0x1a else (2, False) self.include("src/common/inc/swref/published/turing/tu102/dev_fb.h") if self.reg("NV_PFB_PRI_MMU_WPR2_ADDR_HI").read() != 0: if DEBUG >= 2: print(f"nv {self.devfmt}: WPR2 is up. Issuing a full reset.", flush=True) - System.pci_reset(self.devfmt) + self.pci_dev.reset() time.sleep(0.5) self.include("src/common/inc/swref/published/turing/tu102/dev_vm.h") @@ -134,10 +133,13 @@ class NVDev(PCIDevImplBase): self.vram_size = self.reg("NV_PGC6_AON_SECURE_SCRATCH_GROUP_42").read() << 20 + self.vram, self.mmio = self.pci_dev.map_bar(1), self.pci_dev.map_bar(0, fmt='I') + self.large_bar = self.vram.nbytes >= self.vram_size + def _alloc_boot_struct(self, struct:ctypes.Structure) -> tuple[ctypes.Structure, int]: - va, paddrs = System.alloc_sysmem(sz:=ctypes.sizeof(type(struct)), contiguous=True) - to_mv(va, sz)[:] = bytes(struct) - return type(struct).from_address(va), paddrs[0] + view, paddrs = System.alloc_sysmem(sz:=ctypes.sizeof(type(struct)), contiguous=True) + view[:sz] = bytes(struct) + return type(struct).from_address(view.addr), paddrs[0] def _download(self, file:str) -> str: url = f"https://raw.githubusercontent.com/NVIDIA/open-gpu-kernel-modules/8ec351aeb96a93a4bb69ccc12a542bf8a8df2b6f/{file}" @@ -146,12 +148,14 @@ class NVDev(PCIDevImplBase): def extract_fw(self, file:str, dname:str) -> bytes: # Extracts the firmware binary from the given header tname = file.replace("kgsp", "kgspGet") - text = self._download(f"src/nvidia/generated/g_bindata_{tname}_{self.chip_name}.c") - info, sl = text[text[:text.index(dnm:=f'{file}_{self.chip_name}_{dname}')].rindex("COMPRESSION:"):][:16], text[text.index(dnm) + len(dnm) + 7:] + text = self._download(f"src/nvidia/generated/g_bindata_{tname}_{self.fw_name}.c") + info, sl = text[text[:text.index(dnm:=f'{file}_{self.fw_name}_{dname}')].rindex("COMPRESSION:"):][:16], text[text.index(dnm) + len(dnm) + 7:] image = bytes.fromhex(sl[:sl.find("};")].strip().replace("0x", "").replace(",", "").replace(" ", "").replace("\n", "")) return gzip.decompress(struct.pack("<4BL2B", 0x1f, 0x8b, 8, 0, 0, 0, 3) + image) if "COMPRESSION: YES" in info else image def include(self, file:str): + def _do_eval(s:str): return eval(s) # pylint: disable=eval-used + regs_off = {'NV_PFALCON_FALCON': 0x0, 'NV_PGSP_FALCON': 0x0, 'NV_PSEC_FALCON': 0x0, 'NV_PRISCV_RISCV': 0x1000, 'NV_PGC6_AON': 0x0, 'NV_PFSP': 0x0, 'NV_PGC6_BSI': 0x0, 'NV_PFALCON_FBIF': 0x600, 'NV_PFALCON2_FALCON': 0x1000, 'NV_PBUS': 0x0, 'NV_PFB': 0x0, 'NV_PMC': 0x0, 'NV_PGSP_QUEUE': 0x0, 'NV_VIRTUAL_FUNCTION':0xb80000} @@ -163,13 +167,13 @@ class NVDev(PCIDevImplBase): name, hi, lo = m.groups() reg = next((r for r in self.reg_names if name.startswith(r+"_")), None) - if reg is not None: self.__dict__[reg].add_field(name[len(reg)+1:].lower(), eval(lo), eval(hi)) - else: self.reg_offsets[name] = (eval(lo), eval(hi)) + if reg is not None: self.__dict__[reg].add_field(name[len(reg)+1:].lower(), _do_eval(lo), _do_eval(hi)) + else: self.reg_offsets[name] = (_do_eval(lo), _do_eval(hi)) continue if m:=re.match(r'#define\s+(\w+)\s*\(\s*(\w+)\s*\)\s*(.+)', raw): # reg set fn = m.groups()[2].strip().rstrip('\\').split('/*')[0].rstrip() - name, value = m.groups()[0], eval(f"lambda {m.groups()[1]}: {fn}") + name, value = m.groups()[0], _do_eval(f"lambda {m.groups()[1]}: {fn}") elif m:=re.match(r'#define\s+(\w+)\s+([0-9A-Fa-fx]+)(?![^\n]*:)', raw): name, value = m.groups()[0], int(m.groups()[1], 0) # reg value else: continue diff --git a/tinygrad/runtime/support/system.py b/tinygrad/runtime/support/system.py index 66b2f78615..26599018f0 100644 --- a/tinygrad/runtime/support/system.py +++ b/tinygrad/runtime/support/system.py @@ -1,52 +1,40 @@ -import os, mmap, array, functools, ctypes, select, contextlib, dataclasses, sys, errno +import os, mmap, array, functools, ctypes, select, contextlib, dataclasses, sys, errno, itertools from typing import cast, ClassVar -from tinygrad.helpers import round_up, to_mv, getenv, OSX, temp -from tinygrad.runtime.autogen import libc, vfio -from tinygrad.runtime.support.hcq import FileIOInterface, MMIOInterface, HCQBuffer +from tinygrad.helpers import round_up, getenv, OSX, temp, ceildiv +from tinygrad.runtime.autogen import libc, vfio, pci +from tinygrad.runtime.support.hcq import FileIOInterface, MMIOInterface, HCQBuffer, hcq_filter_visible_devices from tinygrad.runtime.support.memory import MemoryManager, VirtMapping +from tinygrad.runtime.support.usb import ASM24Controller, USBMMIOInterface MAP_FIXED, MAP_LOCKED, MAP_POPULATE, MAP_NORESERVE = 0x10, 0 if OSX else 0x2000, getattr(mmap, "MAP_POPULATE", 0 if OSX else 0x008000), 0x400 +@dataclasses.dataclass(frozen=True) +class PCIBarInfo: addr:int; size:int # noqa: E702 + class _System: - def reserve_hugepages(self, cnt): os.system(f"sudo sh -c 'echo {cnt} > /proc/sys/vm/nr_hugepages'") + def write_sysfs(self, path:str, value:str, msg:str, expected:str|None=None): + if FileIOInterface(path, os.O_RDONLY).read().splitlines()[0] != (expected or value): + os.system(cmd:=f"sudo sh -c 'echo {value} > {path}'") + if FileIOInterface(path, os.O_RDONLY).read().splitlines()[0] != (expected or value): raise RuntimeError(f"{msg}. Please run {cmd} manually.") - def memory_barrier(self): lib.atomic_thread_fence(__ATOMIC_SEQ_CST:=5) if (lib:=self.atomic_lib()) is not None else None - - def lock_memory(self, addr:int, size:int): - if libc.mlock(ctypes.c_void_p(addr), size): raise RuntimeError(f"Failed to lock memory at {addr:#x} with size {size:#x}") - - def system_paddrs(self, vaddr:int, size:int) -> list[int]: - self.pagemap().seek(vaddr // mmap.PAGESIZE * 8) - return [(x & ((1<<55) - 1)) * mmap.PAGESIZE for x in array.array('Q', self.pagemap().read(size//mmap.PAGESIZE*8, binary=True))] - - def alloc_sysmem(self, size:int, vaddr:int=0, contiguous:bool=False, data:bytes|None=None) -> tuple[int, list[int]]: - assert not contiguous or size <= (2 << 20), "Contiguous allocation is only supported for sizes up to 2MB" - flags = (libc.MAP_HUGETLB if contiguous and (size:=round_up(size, mmap.PAGESIZE)) > 0x1000 else 0) | (MAP_FIXED if vaddr else 0) - va = FileIOInterface.anon_mmap(vaddr, size, mmap.PROT_READ|mmap.PROT_WRITE, mmap.MAP_SHARED|mmap.MAP_ANONYMOUS|MAP_POPULATE|MAP_LOCKED|flags, 0) - - if data is not None: to_mv(va, len(data))[:] = data - return va, self.system_paddrs(va, size) - - def pci_reset(self, gpu): os.system(f"sudo sh -c 'echo 1 > /sys/bus/pci/devices/{gpu}/reset'") - def pci_scan_bus(self, target_vendor:int, target_devices:list[int]) -> list[str]: - result = [] - for pcibus in FileIOInterface("/sys/bus/pci/devices").listdir(): - vendor = int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/vendor").read(), 16) - device = int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/device").read(), 16) - if vendor == target_vendor and device in target_devices: result.append(pcibus) - return sorted(result) - - @functools.cache + @functools.cached_property def atomic_lib(self): return ctypes.CDLL(ctypes.util.find_library('atomic')) if sys.platform == "linux" else None - @functools.cache + @functools.cached_property + def iokit(self): return ctypes.CDLL(ctypes.util.find_library("IOKit")) + + @functools.cached_property + def libsys(self): return ctypes.CDLL(ctypes.util.find_library("System")) + + @functools.cached_property + def mach_task_self(self): return ctypes.cast(self.libsys.mach_task_self_, ctypes.POINTER(ctypes.c_uint)).contents.value + + @functools.cached_property def pagemap(self) -> FileIOInterface: - if FileIOInterface(reloc_sysfs:="/proc/sys/vm/compact_unevictable_allowed", os.O_RDONLY).read()[0] != "0": - os.system(cmd:=f"sudo sh -c 'echo 0 > {reloc_sysfs}'") - assert FileIOInterface(reloc_sysfs, os.O_RDONLY).read()[0] == "0", f"Failed to disable migration of locked pages. Please run {cmd} manually." + self.write_sysfs("/proc/sys/vm/compact_unevictable_allowed", "0", "Failed to disable migration of locked pages") return FileIOInterface("/proc/self/pagemap", os.O_RDONLY) - @functools.cache + @functools.cached_property def vfio(self) -> FileIOInterface|None: try: if not FileIOInterface.exists("/sys/module/vfio"): os.system("sudo modprobe vfio-pci disable_idle_d3=1") @@ -58,6 +46,111 @@ class _System: return vfio_fd except OSError: return None + @functools.cached_property + def macos_tinygpu_conn(self): + self.iokit.IOServiceNameMatching.restype = ctypes.c_void_p # CFMutableDictionaryRef + if not (mdict:=self.iokit.IOServiceNameMatching("tinygpu".encode("utf-8"))): raise RuntimeError("IOServiceNameMatching returned NULL") + if not (service:=self.iokit.IOServiceGetMatchingService(ctypes.c_uint(0), ctypes.c_void_p(mdict))): + raise RuntimeError('Service "tinygpu" is not running') + if self.iokit.IOServiceOpen(service, self.mach_task_self, ctypes.c_uint32(0), ctypes.byref(conn:=ctypes.c_uint(0))): + raise RuntimeError("IOServiceOpen failed") + return conn + + def iokit_pci_memmap(self, typ:int): + if self.iokit.IOConnectMapMemory64(self.macos_tinygpu_conn, ctypes.c_uint32(typ), System.mach_task_self, + ctypes.byref(addr:=ctypes.c_uint64(0)), ctypes.byref(size:=ctypes.c_uint64(0)), 0x1): raise RuntimeError(f"IOConnectMapMemory64({typ=}) failed") + return MMIOInterface(addr.value, size.value) + + def iokit_pci_rpc(self, sel:int, *args:int): + in_scalars = (ctypes.c_uint64 * len(args))(*args) if args else ctypes.POINTER(ctypes.c_uint64)() + if (self.iokit.IOConnectCallMethod(self.macos_tinygpu_conn, sel, in_scalars, len(args), None, ctypes.c_size_t(0), + out_scalars:=(ctypes.c_uint64*16)(), ctypes.byref(outcnt:=ctypes.c_uint32(16)), None, ctypes.byref(ctypes.c_size_t(0)))): + raise RuntimeError(f"IOConnectCallMethod({sel=}, {args=}) failed") + return out_scalars[:outcnt.value] + + def reserve_hugepages(self, cnt): os.system(f"sudo sh -c 'echo {cnt} > /proc/sys/vm/nr_hugepages'") + + def memory_barrier(self): lib.atomic_thread_fence(__ATOMIC_SEQ_CST:=5) if (lib:=self.libsys if OSX else self.atomic_lib) is not None else None + + def lock_memory(self, addr:int, size:int): + if libc.mlock(ctypes.c_void_p(addr), size): raise RuntimeError(f"Failed to lock memory at {addr:#x} with size {size:#x}") + + def system_paddrs(self, vaddr:int, size:int) -> list[int]: + self.pagemap.seek(vaddr // mmap.PAGESIZE * 8) + return [(x & ((1<<55) - 1)) * mmap.PAGESIZE for x in array.array('Q', self.pagemap.read(size//mmap.PAGESIZE*8, binary=True))] + + def alloc_sysmem(self, size:int, vaddr:int=0, contiguous:bool=False, data:bytes|None=None) -> tuple[MMIOInterface, list[int]]: + if OSX: + sysmem_view = System.iokit_pci_memmap(round_up(size, mmap.PAGESIZE)) + paddrs = list(itertools.takewhile(lambda p: p[1] != 0, zip(sysmem_view.view(fmt='Q')[0::2], sysmem_view.view(fmt='Q')[1::2]))) + assert not contiguous or len(paddrs) == 1, "not contiguous, but required" + else: + assert not contiguous or size <= (2 << 20), "Contiguous allocation is only supported for sizes up to 2MB" + flags = (libc.MAP_HUGETLB if contiguous and (size:=round_up(size, mmap.PAGESIZE)) > mmap.PAGESIZE else 0) | (MAP_FIXED if vaddr else 0) + va = FileIOInterface.anon_mmap(vaddr, size, mmap.PROT_READ|mmap.PROT_WRITE, mmap.MAP_SHARED|mmap.MAP_ANONYMOUS|MAP_POPULATE|MAP_LOCKED|flags, 0) + sysmem_view, paddrs = MMIOInterface(va, size), [(x, mmap.PAGESIZE) for x in self.system_paddrs(va, size)] + + if data is not None: sysmem_view[:len(data)] = data + return sysmem_view, [p + i for p, sz in paddrs for i in range(0, sz, 0x1000)][:ceildiv(size, 0x1000)] + + def pci_scan_bus(self, target_vendor:int, target_devices:list[tuple[int, list[int]]]) -> list[str]: + result = [] + for pcibus in FileIOInterface("/sys/bus/pci/devices").listdir(): + vendor = int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/vendor").read(), 16) + device = int(FileIOInterface(f"/sys/bus/pci/devices/{pcibus}/device").read(), 16) + if vendor == target_vendor and any((device & mask) in devlist for mask, devlist in target_devices): result.append(pcibus) + return sorted(result) + + def pci_setup_usb_bars(self, usb:ASM24Controller, gpu_bus:int, mem_base:int, pref_mem_base:int) -> dict[int, PCIBarInfo]: + for bus in range(gpu_bus): + # All 3 values must be written at the same time. + buses = (0 << 0) | ((bus+1) << 8) | ((gpu_bus) << 16) + usb.pcie_cfg_req(pci.PCI_PRIMARY_BUS, bus=bus, dev=0, fn=0, value=buses, size=4) + + usb.pcie_cfg_req(pci.PCI_MEMORY_BASE, bus=bus, dev=0, fn=0, value=(mem_base>>16) & 0xffff, size=2) + usb.pcie_cfg_req(pci.PCI_MEMORY_LIMIT, bus=bus, dev=0, fn=0, value=0xffff, size=2) + usb.pcie_cfg_req(pci.PCI_PREF_MEMORY_BASE, bus=bus, dev=0, fn=0, value=(pref_mem_base>>16) & 0xffff, size=2) + usb.pcie_cfg_req(pci.PCI_PREF_MEMORY_LIMIT, bus=bus, dev=0, fn=0, value=0xffff, size=2) + usb.pcie_cfg_req(pci.PCI_PREF_BASE_UPPER32, bus=bus, dev=0, fn=0, value=pref_mem_base >> 32, size=4) + usb.pcie_cfg_req(pci.PCI_PREF_LIMIT_UPPER32, bus=bus, dev=0, fn=0, value=0xffffffff, size=4) + + usb.pcie_cfg_req(pci.PCI_COMMAND, bus=bus, dev=0, fn=0, value=pci.PCI_COMMAND_IO | pci.PCI_COMMAND_MEMORY | pci.PCI_COMMAND_MASTER, size=1) + + # resize bar 0 + cap_ptr = 0x100 + while cap_ptr: + if pci.PCI_EXT_CAP_ID(hdr:=usb.pcie_cfg_req(cap_ptr, bus=gpu_bus, dev=0, fn=0, size=4)) == pci.PCI_EXT_CAP_ID_REBAR: + cap = usb.pcie_cfg_req(cap_ptr + 0x04, bus=gpu_bus, dev=0, fn=0, size=4) + new_ctrl = (usb.pcie_cfg_req(cap_ptr + 0x08, bus=gpu_bus, dev=0, fn=0, size=4) & ~0x1F00) | ((int(cap >> 4).bit_length() - 1) << 8) + usb.pcie_cfg_req(cap_ptr + 0x08, bus=gpu_bus, dev=0, fn=0, value=new_ctrl, size=4) + + cap_ptr = pci.PCI_EXT_CAP_NEXT(hdr) + + mem_space_addr, bar_off, bars = [mem_base, pref_mem_base], 0, {} + while bar_off < 24: + cfg = usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, size=4) + bar_mem, bar_64 = bool(cfg & pci.PCI_BASE_ADDRESS_MEM_PREFETCH), cfg & pci.PCI_BASE_ADDRESS_MEM_TYPE_64 + + if (cfg & pci.PCI_BASE_ADDRESS_SPACE) == pci.PCI_BASE_ADDRESS_SPACE_MEMORY: + usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, value=0xffffffff, size=4) + lo = (usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, size=4) & 0xfffffff0) + + if bar_64: usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off + 4, bus=gpu_bus, dev=0, fn=0, value=0xffffffff, size=4) + hi = (usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off + 4, bus=gpu_bus, dev=0, fn=0, size=4) if bar_64 else 0) + + bar_size = ((~(((hi << 32) | lo) & ~0xf)) + 1) & (0xffffffffffffffff if bar_64 else 0xffffffff) + + usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off, bus=gpu_bus, dev=0, fn=0, value=mem_space_addr[bar_mem] & 0xffffffff, size=4) + if bar_64: usb.pcie_cfg_req(pci.PCI_BASE_ADDRESS_0 + bar_off + 4, bus=gpu_bus, dev=0, fn=0, value=mem_space_addr[bar_mem] >> 32, size=4) + + bars[bar_off // 4] = PCIBarInfo(mem_space_addr[bar_mem], bar_size) + mem_space_addr[bar_mem] += round_up(bar_size, 2 << 20) + + bar_off += 8 if bar_64 else 4 + + usb.pcie_cfg_req(pci.PCI_COMMAND, bus=gpu_bus, dev=0, fn=0, value=pci.PCI_COMMAND_IO | pci.PCI_COMMAND_MEMORY | pci.PCI_COMMAND_MASTER, size=1) + return bars + def flock_acquire(self, name:str) -> int: import fcntl # to support windows @@ -75,7 +168,8 @@ class _System: System = _System() class PCIDevice: - def __init__(self, pcibus:str, bars:list[int], resize_bars:list[int]|None=None): + def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None): + self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock") self.pcibus, self.irq_poller = pcibus, None if FileIOInterface.exists(f"/sys/bus/pci/devices/{self.pcibus}/driver"): @@ -90,7 +184,7 @@ class PCIDevice: " to allow python accessing device or run with sudo") from e raise RuntimeError(f"Cannot resize BAR {i}: {e}. Ensure the resizable BAR option is enabled on your system.") from e - if getenv("VFIO", 0) and (vfio_fd:=System.vfio()) is not None: + if getenv("VFIO", 0) and (vfio_fd:=System.vfio) is not None: FileIOInterface(f"/sys/bus/pci/devices/{self.pcibus}/driver_override", os.O_WRONLY).write("vfio-pci") FileIOInterface("/sys/bus/pci/drivers_probe", os.O_WRONLY).write(self.pcibus) iommu_group = FileIOInterface.readlink(f"/sys/bus/pci/devices/{self.pcibus}/iommu_group").split('/')[-1] @@ -113,15 +207,35 @@ class PCIDevice: self.cfg_fd = FileIOInterface(f"/sys/bus/pci/devices/{self.pcibus}/config", os.O_RDWR | os.O_SYNC | os.O_CLOEXEC) self.bar_fds = {b: FileIOInterface(f"/sys/bus/pci/devices/{self.pcibus}/resource{b}", os.O_RDWR | os.O_SYNC | os.O_CLOEXEC) for b in bars} - bar_info = FileIOInterface(f"/sys/bus/pci/devices/{self.pcibus}/resource", os.O_RDONLY).read().splitlines() - self.bar_info = {j:(int(start,16), int(end,16), int(flgs,16)) for j,(start,end,flgs) in enumerate(l.split() for l in bar_info)} + res = FileIOInterface(f"/sys/bus/pci/devices/{self.pcibus}/resource", os.O_RDONLY).read().splitlines() + self.bar_info = {j:PCIBarInfo(int(s,16), int(e,16)-int(s,16)+1) for j,(s,e,_) in enumerate(l.split() for l in res)} def read_config(self, offset:int, size:int): return int.from_bytes(self.cfg_fd.read(size, binary=True, offset=offset), byteorder='little') def write_config(self, offset:int, value:int, size:int): self.cfg_fd.write(value.to_bytes(size, byteorder='little'), binary=True, offset=offset) def map_bar(self, bar:int, off:int=0, addr:int=0, size:int|None=None, fmt='B') -> MMIOInterface: - fd, sz = self.bar_fds[bar], size or (self.bar_info[bar][1] - self.bar_info[bar][0] + 1) + fd, sz = self.bar_fds[bar], size or (self.bar_info[bar].size - off) libc.madvise(loc:=fd.mmap(addr, sz, mmap.PROT_READ | mmap.PROT_WRITE, mmap.MAP_SHARED | (MAP_FIXED if addr else 0), off), sz, libc.MADV_DONTFORK) return MMIOInterface(loc, sz, fmt=fmt) + def reset(self): os.system(f"sudo sh -c 'echo 1 > /sys/bus/pci/devices/{self.pcibus}/reset'") + +class APLPCIDevice(PCIDevice): + def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None): + self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock") + self.pcibus, self.bars = pcibus, {b: System.iokit_pci_memmap(b) for b in bars} + self.bar_info = {b:PCIBarInfo(0, self.bars[b].nbytes-1 if b in self.bars else 0) for b in range(6)} # NOTE: fake bar info for nv. + def map_bar(self, bar:int, off:int=0, addr:int=0, size:int|None=None, fmt='B') -> MMIOInterface: return self.bars[bar].view(off, size, fmt) + def read_config(self, offset:int, size:int): return System.iokit_pci_rpc(__TinyGPURPCReadCfg:=0, offset, size)[0] + def write_config(self, offset:int, value:int, size:int): System.iokit_pci_rpc(__TinyGPURPCWriteCfg:=1, offset, size, value) + def reset(self): System.iokit_pci_rpc(__TinyGPURPCReset:=2) + +class USBPCIDevice(PCIDevice): + def __init__(self, devpref:str, pcibus:str, bars:list[int], resize_bars:list[int]|None=None): + self.lock_fd = System.flock_acquire(f"{devpref.lower()}_{pcibus.lower()}.lock") + self.usb = ASM24Controller() + self.pcibus, self.bar_info = pcibus, System.pci_setup_usb_bars(self.usb, gpu_bus=4, mem_base=0x10000000, pref_mem_base=(32 << 30)) + def map_bar(self, bar, off=0, addr=0, size=None, fmt='B'): + return USBMMIOInterface(self.usb, self.bar_info[bar].addr + off, size or self.bar_info[bar].size, fmt) + def dma_view(self, ctrl_addr, size): return USBMMIOInterface(self.usb, ctrl_addr, size, fmt='B', pcimem=False) class PCIDevImplBase: mm: MemoryManager @@ -129,46 +243,52 @@ class PCIDevImplBase: @dataclasses.dataclass class PCIAllocationMeta: mapping:VirtMapping; has_cpu_mapping:bool; hMemory:int=0 # noqa: E702 -class PCIIfaceBase: +class LNXPCIIfaceBase: dev_impl:PCIDevImplBase gpus:ClassVar[list[str]] = [] - def __init__(self, dev, dev_id, vendor, devices, bars, vram_bar, va_start, va_size): + def __init__(self, dev, dev_id, vendor, devices:list[tuple[int, list[int]]], bars, vram_bar, va_start, va_size): if len((cls:=type(self)).gpus) == 0: - cls.gpus = System.pci_scan_bus(vendor, devices) - visible_devices = [int(x) for x in (getenv('VISIBLE_DEVICES', '')).split(',') if x.strip()] - cls.gpus = [cls.gpus[x] for x in visible_devices] if visible_devices else cls.gpus + cls.gpus = hcq_filter_visible_devices(System.pci_scan_bus(vendor, devices)) # Acquire va range to avoid collisions. FileIOInterface.anon_mmap(va_start, va_size, 0, mmap.MAP_PRIVATE | mmap.MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED, 0) - self.pci_dev, self.dev, self.vram_bar = PCIDevice(cls.gpus[dev_id], bars=bars, resize_bars=[vram_bar]), dev, vram_bar - self.p2p_base_addr = self.pci_dev.bar_info[vram_bar][0] + self.pci_dev, self.dev, self.vram_bar = PCIDevice(dev.__class__.__name__[:2], cls.gpus[dev_id], bars=bars, resize_bars=[vram_bar]), dev, vram_bar + self.p2p_base_addr = self.pci_dev.bar_info[vram_bar].addr - def alloc(self, size:int, host=False, uncached=False, cpu_access=False, contiguous=False, **kwargs) -> HCQBuffer: - if host or (uncached and cpu_access): # host or gtt-like memory. + def alloc(self, size:int, host=False, uncached=False, cpu_access=False, contiguous=False, force_devmem=False, **kwargs) -> HCQBuffer: + # NOTE: logic on macos is different, since bar is small + should_use_sysmem = host or ((cpu_access if OSX else (uncached and cpu_access)) and not force_devmem) + if should_use_sysmem: vaddr = self.dev_impl.mm.alloc_vaddr(size:=round_up(size, mmap.PAGESIZE), align=mmap.PAGESIZE) - paddrs = [(paddr, mmap.PAGESIZE) for paddr in System.alloc_sysmem(size, vaddr=vaddr, contiguous=contiguous)[1]] - mapping = self.dev_impl.mm.map_range(vaddr, size, paddrs, system=True, snooped=True, uncached=True) - return HCQBuffer(vaddr, size, meta=PCIAllocationMeta(mapping, has_cpu_mapping=True, hMemory=paddrs[0][0]), - view=MMIOInterface(mapping.va_addr, size, fmt='B'), owner=self.dev) + memview, paddrs = System.alloc_sysmem(size, vaddr=vaddr, contiguous=contiguous) + mapping = self.dev_impl.mm.map_range(vaddr, size, [(paddr, 0x1000) for paddr in paddrs], system=True, snooped=True, uncached=True) + return HCQBuffer(vaddr, size, meta=PCIAllocationMeta(mapping, has_cpu_mapping=True, hMemory=paddrs[0]), view=memview, owner=self.dev) - mapping = self.dev_impl.mm.valloc(size:=round_up(size, 4 << 10), uncached=uncached, contiguous=cpu_access) - if cpu_access: self.pci_dev.map_bar(bar=self.vram_bar, off=mapping.paddrs[0][0], addr=mapping.va_addr, size=mapping.size) - return HCQBuffer(mapping.va_addr, size, view=MMIOInterface(mapping.va_addr, size, fmt='B') if cpu_access else None, - meta=PCIAllocationMeta(mapping, has_cpu_mapping=cpu_access, hMemory=mapping.paddrs[0][0]), owner=self.dev) + mapping = self.dev_impl.mm.valloc(size:=round_up(size, 0x1000), uncached=uncached, contiguous=cpu_access) + barview = self.pci_dev.map_bar(bar=self.vram_bar, off=mapping.paddrs[0][0], size=mapping.size) if cpu_access else None + return HCQBuffer(mapping.va_addr, size, view=barview, meta=PCIAllocationMeta(mapping, cpu_access, hMemory=mapping.paddrs[0][0]), owner=self.dev) def free(self, b:HCQBuffer): for dev in b.mapped_devs[1:]: dev.iface.dev_impl.mm.unmap_range(b.va_addr, b.size) if not b.meta.mapping.system: self.dev_impl.mm.vfree(b.meta.mapping) - if b.owner == self.dev and b.meta.has_cpu_mapping: FileIOInterface.munmap(b.va_addr, b.size) + if b.owner == self.dev and b.meta.has_cpu_mapping and not OSX: FileIOInterface.munmap(b.va_addr, b.size) def map(self, b:HCQBuffer): if b.owner is not None and b.owner._is_cpu(): System.lock_memory(cast(int, b.va_addr), b.size) paddrs, snooped, uncached = [(x, 0x1000) for x in System.system_paddrs(cast(int, b.va_addr), round_up(b.size, 0x1000))], True, True - elif (ifa:=getattr(b.owner, "iface", None)) is not None and isinstance(ifa, PCIIfaceBase): + elif (ifa:=getattr(b.owner, "iface", None)) is not None and isinstance(ifa, LNXPCIIfaceBase): paddrs = [(paddr if b.meta.mapping.system else (paddr + ifa.p2p_base_addr), size) for paddr,size in b.meta.mapping.paddrs] snooped, uncached = b.meta.mapping.snooped, b.meta.mapping.uncached else: raise RuntimeError(f"map failed: {b.owner} -> {self.dev}") self.dev_impl.mm.map_range(cast(int, b.va_addr), round_up(b.size, 0x1000), paddrs, system=True, snooped=snooped, uncached=uncached) + +class APLPCIIfaceBase(LNXPCIIfaceBase): + def __init__(self, dev, dev_id, vendor, devices, bars, vram_bar, va_start, va_size): + self.pci_dev, self.dev, self.vram_bar = APLPCIDevice(dev.__class__.__name__[:2], pcibus=f'usb4:{dev_id}', bars=bars), dev, vram_bar + assert (read_vendor:=self.pci_dev.read_config(0x00, 2)) == vendor, f"Vendor ID mismatch: expected {vendor:#x}, got {read_vendor:#x}" + def map(self, b:HCQBuffer): raise RuntimeError(f"map failed: {b.owner} -> {self.dev}") + +PCIIfaceBase:type = APLPCIIfaceBase if OSX else LNXPCIIfaceBase diff --git a/tinygrad/runtime/support/usb.py b/tinygrad/runtime/support/usb.py index 285e3cf287..2340c944cb 100644 --- a/tinygrad/runtime/support/usb.py +++ b/tinygrad/runtime/support/usb.py @@ -229,7 +229,7 @@ class ASM24Controller: for i in range(0, len(ops), bs:=(4 if OSX else 16)): self.exec_ops(list(itertools.chain.from_iterable(ops[i:i+bs]))) class USBMMIOInterface(MMIOInterface): - def __init__(self, usb, addr, size, fmt, pcimem=True): + def __init__(self, usb, addr, size, fmt, pcimem=True): # pylint: disable=super-init-not-called self.usb, self.addr, self.nbytes, self.fmt, self.pcimem, self.el_sz = usb, addr, size, fmt, pcimem, struct.calcsize(fmt) def __getitem__(self, index): return self._access_items(index) @@ -256,13 +256,14 @@ class USBMMIOInterface(MMIOInterface): acc, acc_size = self._acc_size(sz) return bytes(array.array(acc, [self._acc_one(off + i * acc_size, acc_size) for i in range(sz // acc_size)])) - else: # write op - data = struct.pack(self.fmt, data) if isinstance(data, int) else bytes(data) - if not self.pcimem: - # Fast path for writing into buffer 0xf000 - use_cache = 0xa800 <= self.addr <= 0xb000 - return self.usb.scsi_write(bytes(data)) if self.addr == 0xf000 else self.usb.write(self.addr + off, bytes(data), ignore_cache=not use_cache) + # write op + data = struct.pack(self.fmt, data) if isinstance(data, int) else bytes(data) - _, acc_sz = self._acc_size(len(data) * struct.calcsize(self.fmt)) - self.usb.pcie_mem_write(self.addr+off, [int.from_bytes(data[i:i+acc_sz], "little") for i in range(0, len(data), acc_sz)], acc_sz) + if not self.pcimem: + # Fast path for writing into buffer 0xf000 + use_cache = 0xa800 <= self.addr <= 0xb000 + return self.usb.scsi_write(bytes(data)) if self.addr == 0xf000 else self.usb.write(self.addr + off, bytes(data), ignore_cache=not use_cache) + + _, acc_sz = self._acc_size(len(data) * struct.calcsize(self.fmt)) + self.usb.pcie_mem_write(self.addr+off, [int.from_bytes(data[i:i+acc_sz], "little") for i in range(0, len(data), acc_sz)], acc_sz) diff --git a/tinygrad/runtime/support/webgpu.py b/tinygrad/runtime/support/webgpu.py index 11c6e10386..ad1fba31b2 100644 --- a/tinygrad/runtime/support/webgpu.py +++ b/tinygrad/runtime/support/webgpu.py @@ -1,10 +1,10 @@ -import ctypes, ctypes.util, os, subprocess, platform, sysconfig -from tinygrad.helpers import OSX +import ctypes.util, os, platform, sysconfig +from tinygrad.helpers import system, OSX WEBGPU_PATH: str | None if OSX: - if not os.path.exists(brew_prefix:=subprocess.check_output(['brew', '--prefix', 'dawn']).decode().strip()): + if not os.path.exists(brew_prefix:=system("brew --prefix dawn")): raise FileNotFoundError('dawn library not found. Install it with `brew tap wpmed92/dawn && brew install dawn`') WEBGPU_PATH = os.path.join(brew_prefix, 'lib', 'libwebgpu_dawn.dylib') elif platform.system() == "Windows": diff --git a/tinygrad/schedule/grouper.py b/tinygrad/schedule/grouper.py deleted file mode 100644 index 685bc70b7a..0000000000 --- a/tinygrad/schedule/grouper.py +++ /dev/null @@ -1,119 +0,0 @@ -from tinygrad.uop.ops import Ops, UOp, resolve, can_pad, GroupOp, UPat, PatternMatcher, graph_rewrite -from tinygrad.helpers import all_int, prod, unwrap, dedup, DONT_REALIZE_EXPAND, DONT_GROUP_REDUCES, FUSE_CONV_BW -from tinygrad.shape.shapetracker import ShapeTracker - -ALWAYS_CONTIGUOUS: set[Ops] = {Ops.CONTIGUOUS, Ops.ASSIGN, Ops.COPY, Ops.BUFFER, Ops.BUFFER_VIEW, - Ops.CONST, Ops.BIND, Ops.DEVICE, Ops.MSELECT, Ops.MSTACK, Ops.DEFINE_GLOBAL, - Ops.DEFINE_LOCAL, Ops.DEFINE_REG, Ops.LOAD} - -# **** Grouper decides which of the UOps realize - -def realize(ctx:dict[UOp, None], tr:UOp) -> None: ctx[tr] = None - -def realize_parents(ctx:dict[UOp, None], rb:UOp) -> None: - for s in rb.src: - if s.op not in ALWAYS_CONTIGUOUS: ctx[s] = None - -def realize_before_view(ctx:dict[UOp, None], view:UOp, tr:UOp) -> None: - st = unwrap(view.st) - # always realize unsafe pad ops before masked view - if any(v.mask is not None for v in st.views) and not can_pad(tr, ctx): return realize(ctx, tr) - # fold simple pads - if len(st.views) == 1 and (m:=st.views[-1].mask) is not None and all_int(tr.shape) and resolve(prod(tr.shape) >= prod([y-x for x,y in m])): return - # realize before expand - if resolve(prod(tr.shape) < prod(st.shape)) and not DONT_REALIZE_EXPAND: return realize(ctx, tr) - -do_realize = PatternMatcher([ - # always realize SINK parents - (UPat(Ops.SINK, name="s"), lambda ctx,s: ctx.update((x.base, None) for x in s.src if x.base.op not in ALWAYS_CONTIGUOUS)), - # always realize ASSIGN/CONTIGUOUS/COPY/BUFFER_VIEW - (UPat({Ops.ASSIGN, Ops.CONTIGUOUS, Ops.COPY, Ops.BUFFER_VIEW}, name="tr"), realize), - # realize before expand or unsafe pad ops - (UPat(Ops.VIEW, src=(UPat(GroupOp.All-ALWAYS_CONTIGUOUS, name="tr"),), name="view"), realize_before_view), - # realize parents of COPY, MSELECT, MSTACK - (UPat((Ops.COPY, Ops.MSELECT, Ops.MSTACK), name="rb"), realize_parents), -]) - -def recursive_group(tr:UOp, st:ShapeTracker, r:UOp, children:dict[UOp, dict[UOp, None]], realizes:dict[UOp, None], - reduce_for_op:dict[UOp, UOp], group:dict[UOp, None], cache:dict[tuple[UOp, ShapeTracker], None]) -> None: - if (tr, st) in cache: return - cache.setdefault((tr, st)) - rsize = unwrap(r.st).size - if tr in realizes and tr is not r: - # can only fuse contiguous - # max one reduceop per kernel - if not st.contiguous or st.size != rsize or tr in reduce_for_op: group.setdefault(r) - return group.setdefault(tr) - for tr_next in children.get(tr, {}): - # max one reduceop per kernel - if tr_next.op is Ops.REDUCE_AXIS: return group.setdefault(r) - # can only fuse contiguous - if len(st_childs:=dedup(unwrap(x.st) for x in tr_next.src if x.base == tr)) > 1: return group.setdefault(r) - recursive_group(tr_next, st+st_childs[0], r, children, realizes, reduce_for_op, group, cache) - -def group_realizes(sink:UOp) -> dict[UOp, None]: - # start by adding uops that always realize - realizes: dict[UOp, None] = {} - sink = graph_rewrite(sink, do_realize, ctx=realizes, name="do_realize") - if DONT_GROUP_REDUCES: return realizes - - # construct children graph (only for bases) - children: dict[UOp, dict[UOp, None]] = {} - assigns: dict[UOp, None] = {} - for u in (toposort:=sink.toposort()): - if u.op in {Ops.VIEW, Ops.SINK}: continue - if u.op is Ops.ASSIGN: assigns[u.buf_uop] = None - for s in u.src: children.setdefault(s.base, {})[u] = None - - # find all reduces, and pair them to a elementwise op. if they can't be cleanly paired, force realize the reduce (or a contig child) - reduce_for_op: dict[UOp, UOp] = {} - double_reduces: list[UOp] = [] - for r in toposort: - if r.op is not Ops.REDUCE_AXIS: continue - if len(r.arg) == 3 and r.arg[2] is True: continue - if FUSE_CONV_BW and r.src[0].base.op is Ops.REDUCE_AXIS and r.src[0] is not r.src[0].base: double_reduces.append(r) - if r in realizes: continue - group: dict[UOp, None] = {} - recursive_group(r, unwrap(r.st), r, children, realizes, reduce_for_op, group, cache={}) - # max one reduceop per kernel - can_chase = all(tr not in reduce_for_op for tr in group) - for u in r.toposort(gate=lambda u: u not in realizes): - if u.op is Ops.REDUCE_AXIS and u.src[0].base.op is Ops.CONST: - can_chase = False - break - # TODO: forced_realize exists because the scheduler is incapable of checking for self-contained DAGs - forced_realize = r in group - # can only have one output - if not forced_realize and len(group) > 1: forced_realize = True - # can only fuse assign if no other assign_target is used in the kernel - if not forced_realize and (assign_targets:={x.buf_uop for x in group if x.op is Ops.ASSIGN}): - parents = [r, *group] - while parents and not forced_realize: - p = parents.pop().base - if p.op is Ops.BUFFER and p in assigns and p not in assign_targets: forced_realize, can_chase = True, False - if p in realizes: continue - parents.extend(p.src) - if forced_realize or not group: - tr = r - if can_chase: - # can chase this down to contiguous children - st = unwrap(tr.st) - while len(lst:=children.get(tr, {})) == 1: - tr_next = next(iter(lst)) - st_childs = dedup(unwrap(s.st) for s in tr_next.src if s.base is tr) - if len(st_childs) > 1: break - if st.size != st_childs[0].size: break - st = st + st_childs[0] - if not st.contiguous or tr_next.op is Ops.REDUCE_AXIS: break - tr = tr_next - # don't cast to higher size before store (tr cannot be realized if forced_realize) - if tr.op is Ops.CAST and tr.dtype.itemsize > tr.src[0].dtype.itemsize: - tr = tr.src[0].base - group = {tr: None} - realizes[tr] = None - reduce_for_op.update((tr, r) for tr in group) - # fuse double reduces with no other child - for reduceop in double_reduces: - top_reduce = reduceop.src[0].base - if len(children.get(top_reduce, {})) == 1: del realizes[top_reduce] - return realizes diff --git a/tinygrad/schedule/indexing.py b/tinygrad/schedule/indexing.py new file mode 100644 index 0000000000..0919e6a30a --- /dev/null +++ b/tinygrad/schedule/indexing.py @@ -0,0 +1,269 @@ +from typing import Iterator +import functools, operator, itertools +from dataclasses import dataclass, field +from tinygrad.dtype import dtypes, AddrSpace +from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, resolve, GroupOp, graph_rewrite, sint, AxisType, profile_matches +from tinygrad.uop.symbolic import symbolic, pm_simplify_valid, pm_drop_and_clauses +from tinygrad.helpers import argsort, all_same, cpu_profile, PCONTIG, colored + +ALWAYS_CONTIGUOUS: set[Ops] = {Ops.CONTIGUOUS, Ops.ASSIGN, Ops.COPY, Ops.BUFFER, Ops.BUFFER_VIEW, + Ops.CONST, Ops.BIND, Ops.DEVICE, Ops.MSELECT, Ops.MSTACK, Ops.DEFINE_GLOBAL, + Ops.DEFINE_LOCAL, Ops.DEFINE_REG, Ops.LOAD, Ops.KERNEL} + +def realize(ctx:dict[UOp, None], tr:UOp) -> None: ctx[tr] = None + +def realize_srcs(ctx:dict[UOp, None], rb:UOp) -> None: + for s in rb.src: + if s.base.op not in ALWAYS_CONTIGUOUS: ctx[s] = None + +def realize_assign(ctx:dict[UOp, None], a:UOp) -> None: + if a.src[1].op not in ALWAYS_CONTIGUOUS: ctx[a.src[1]] = None + # if it's a kernel, we don't realize it + if a.src[1].op is not Ops.KERNEL: ctx[a] = None + +pm_generate_realize_map = PatternMatcher([ + # always realize SINK src + (UPat(Ops.SINK, name="s"), lambda ctx,s: ctx.update((x.base, None) for x in s.src if x.base.op not in ALWAYS_CONTIGUOUS)), + # always realize COPY/BUFFER_VIEW/CONTIGUOUS + (UPat({Ops.COPY, Ops.BUFFER_VIEW, Ops.CONTIGUOUS}, name="tr"), realize), + # realize srcs of COPY, MSELECT, MSTACK + (UPat((Ops.COPY, Ops.MSELECT, Ops.MSTACK), name="rb"), realize_srcs), + # realize ASSIGN and input to assign (might be optimized out) + (UPat(Ops.ASSIGN, name="a"), realize_assign), +]) + +@dataclass(frozen=True) +class BufferizeOpts: + # on AddrSpace.LOCAL, device is the id + device: str|tuple[str, ...]|int|None + addrspace: AddrSpace = AddrSpace.GLOBAL + +@dataclass +class IndexingContext: + realize_map: dict[UOp, None|list[int]] = field(default_factory=dict) + range_map: dict[UOp, tuple[tuple[UOp, ...], tuple[UOp, ...]]] = field(default_factory=dict) + + # create ranges + range_idx: Iterator[int] = field(default_factory=itertools.count) + def new_range(self, s:sint, axistype:AxisType=AxisType.LOOP) -> UOp: + if isinstance(s, UOp) and s.op is Ops.RANGE: return s + # if a range has a 1 src, it's the same as UOp.const(dtypes.index, 0) + return UOp.range(s, next(self.range_idx), axistype) if resolve(s!=1) else UOp.const(dtypes.index, 0) + +def create_bufferize_and_index_based_on_ranges(ctx:IndexingContext, x:UOp): + if x.op in {Ops.BUFFERIZE, Ops.INDEX}: return None + if x.op is Ops.AFTER and x.src[1].op is Ops.KERNEL: return None + new_srcs = [] + for s in x.src: + new_src = s + if s.op in {Ops.BUFFER, Ops.BUFFER_VIEW, Ops.MSTACK, Ops.MSELECT} or (s.op is Ops.AFTER and s.src[1].op is Ops.KERNEL): + if x in ctx.range_map: new_src = new_src.index(*ctx.range_map[x][0]) + elif s in ctx.realize_map: + realized_ranges = ctx.realize_map[s] + assert isinstance(realized_ranges, list), "realize map must contain range list" + closed_ranges = tuple([r for i,r in enumerate(ctx.range_map[s][1]) if i in realized_ranges]) + # None in the device assigns it a number later + opts = BufferizeOpts(device=s.device) if len(ctx.range_map[s][1]) == len(realized_ranges) else BufferizeOpts(None, AddrSpace.LOCAL) + new_src = UOp(Ops.BUFFERIZE, s.dtype, src=(new_src,)+closed_ranges, arg=opts, tag=s.tag if opts.addrspace == AddrSpace.GLOBAL else None) + if x in ctx.range_map: new_src = new_src.index(*[r for i,r in enumerate(ctx.range_map[x][0]) if i in realized_ranges]) + new_srcs.append(new_src) + # NOTE: do we need this? + return x.replace(src=tns) if x.src != (tns:=tuple(new_srcs)) else None + +def convert_pad_to_where_to_keep_behavior_local(ctx:IndexingContext, x:UOp): + if x not in ctx.range_map: return None + valid: UOp = functools.reduce(operator.and_, [r.get_valid() for r in ctx.range_map[x][0]], UOp.const(dtypes.bool, True)) + ret = valid.where(x.src[0], UOp.const(x.dtype, 0)) + ctx.range_map[ret] = ctx.range_map[x] + return ret + +def convert_reduce_axis_to_reduce_with_ranges(ctx:IndexingContext, x:UOp): + # input ranges + new_ranges = [r for i,r in enumerate(ctx.range_map[x][0]) if i in x.arg[1]] + ret = UOp(Ops.REDUCE, x.dtype, src=(x.src[0],)+tuple(new_ranges), arg=x.arg[0], tag=x.tag) + ctx.range_map[ret] = ctx.range_map[x] + return ret + +def remove_movement_op_after_rangeify(ctx:IndexingContext, x:UOp): + if x in ctx.range_map or x.src[0].op is Ops.INDEX: return x.src[0] + +def add_third_op_to_assign_to_track_shape(ctx:IndexingContext, assign:UOp): + if assign.src[1].op is Ops.KERNEL: return None + to_mop = graph_rewrite(assign.src[0], PatternMatcher([(UPat(GroupOp.Movement, name="x"), lambda x: x.replace(tag=()))])) + ret = assign.replace(src=assign.src+(to_mop,)) + ctx.range_map[ret] = ctx.range_map[assign] + return ret + +pm_apply_rangeify = PatternMatcher([ + # REDUCE_AXIS -> REDUCE + (UPat(Ops.REDUCE_AXIS, name="x"), convert_reduce_axis_to_reduce_with_ranges), + # PAD -> WHERE + (UPat(Ops.PAD, name="x"), convert_pad_to_where_to_keep_behavior_local), + # add third op to assign + (UPat(Ops.ASSIGN, src=(UPat(), UPat()), name="assign"), add_third_op_to_assign_to_track_shape), + # finally, apply_rangeify + (UPat(GroupOp.All, name="x"), create_bufferize_and_index_based_on_ranges), + # remove movement op + (UPat(GroupOp.Movement, name="x"), remove_movement_op_after_rangeify), + # const/define_var shouldn't have src + (UPat((Ops.CONST, Ops.DEFINE_VAR), name="c"), lambda ctx,c: c.replace(src=()) if c in ctx.range_map else None), +]) + +# this is the definition of the movement ops +@functools.cache +def apply_movement_op(op:Ops, in_shape:tuple[sint,...], arg:tuple, rngs:tuple[UOp, ...]) -> tuple[UOp, ...]: + match op: + case Ops.SHRINK: rngs = tuple(a if ss == 0 else a+ss for a,(ss,_) in zip(rngs, arg)) + case Ops.PERMUTE: rngs = tuple(rngs[p] for p in argsort(arg)) + case Ops.FLIP: rngs = tuple(((s-1)-a) if f else a for a,s,f in zip(rngs, in_shape, arg)) + case Ops.EXPAND: rngs = tuple(a if in_sh == out_sh else a.const_like(0) for a,in_sh,out_sh in zip(rngs, in_shape, arg)) + case Ops.PAD: + # TODO: why is multiple graph_rewrites faster than one here? + # TODO: the .where(r-s, i) is not inside the graph_rewrite so that `convert_pad_to_where_to_keep_behavior_local` + # wraps the pad with only the newly added valid + rngs = tuple(r if (s == 0 and e == 0) else graph_rewrite(((r >= s) & (r < (sh+s))), + symbolic+pm_simplify_valid, name="pad").where(r-s, UOp.invalid()) for r,sh,(s,e) in zip(rngs, in_shape, arg)) + case Ops.RESHAPE: + acc = 1 + axes_in:list[UOp] = [] + for s,src in list(zip(arg, rngs))[::-1]: + axes_in.append(acc*src) + acc *= s + combined_axes = sum(axes_in, start=UOp.const(dtypes.index, 0)) + axes_out:list[UOp] = [] + for s in in_shape[::-1]: + axes_out.append(combined_axes % s) + combined_axes //= s + # this simplify is doing a lot of heavy lifting. this is the replacement for the reshape view merging code + rngs = graph_rewrite(UOp.sink(*axes_out[::-1]), symbolic+pm_simplify_valid+pm_drop_and_clauses, name="reshape").src + case _: raise RuntimeError(f"{op} is not a MovementOp") + return rngs + +@profile_matches +def run_rangeify(tsink:UOp, debug:bool=False) -> tuple[UOp, IndexingContext]: + if debug: print("**************************") + rctx = IndexingContext() + + # get ops to realize + graph_rewrite(tsink, pm_generate_realize_map, ctx=rctx.realize_map, name="get realize") + + # get the traversal order + with cpu_profile("reverse toposort", "TINY"): + tsink_reverse_toposort = tsink.reverse_toposort(consumer_map:=tsink.get_consumer_map()) + + # explicit rangeify + ending_ranges: dict[UOp, list[UOp]] = {} + for x in tsink_reverse_toposort: + if x.op in {Ops.DEVICE, Ops.UNIQUE}: continue + + # no ranges on kernels, they are internal + if x.op is Ops.KERNEL: continue + + if x.dtype.scalar() == dtypes.index: continue # TODO: why do I need this? + ending_ranges[x] = sum([ending_ranges.get(u, []) for u in consumer_map[x]], []) + + # *** the ranges on the output are + # 1. new if this op is realized + # 2. from the single consumer if this op only has one consumer + # 3. potentially new if this op has 2+ consumers + + consumer_rngs = [rctx.range_map[c][0] for c in consumer_map[x] if c in rctx.range_map] + if x in rctx.realize_map: + # if this is in the realize_map, we create new ranges (at the output) + out_rngs = tuple(rctx.new_range(s) for s in x.shape) + # all ranges are ended now + ending_ranges[x] = [] + # mark all ranges as ended + assert rctx.realize_map[x] is None + rctx.realize_map[x] = list(range(len(x.shape))) + elif x.op in {Ops.MSTACK, Ops.MSELECT}: + # treat MSTACK/MSELECT like SINK + continue + elif len(consumer_rngs) == 0: + # if no consumers have ranges and this isn't realized, this doesn't have ranges either. + continue + elif len(consumer_rngs) == 1: + # if this has one consumer, it inherits the ranges from it + out_rngs = consumer_rngs[0] + elif len(consumer_rngs) > 1: + # if this has two consumers, we have to merge the ranges and might create new ones + all_rngs: list[tuple[UOp, ...]] = list(zip(*consumer_rngs)) + rngs_valids = [] + for valid_rngs in all_rngs: + local_rngs, valids = zip(*[(r.get_idx(), r.get_valid()) for r in valid_rngs]) + rngs_valids.append((local_rngs, valids)) + + # TODO: in RANGEIFY > 1 all_all_same isn't required + all_all_same = all(all_same(local_rngs) for local_rngs,_ in rngs_valids) + _out_rngs = [] + _realize_axis = [] + for i,(local_rngs,valids) in enumerate(rngs_valids): + # we compare the ranges without their valids + if all_all_same or (PCONTIG and all_same(local_rngs)): + # the new valid is the OR of all the children valids + minimum_valid = functools.reduce(operator.or_, valids, UOp.const(dtypes.bool, False)) + _out_rngs.append(graph_rewrite(minimum_valid.where(local_rngs[0], UOp.invalid()), symbolic, name="minimum_valid")) + else: + _out_rngs.append(rctx.new_range(x.shape[i])) + _realize_axis.append(i) + out_rngs = tuple(_out_rngs) + + # we have to (partially) realize here if there's new ranges + if len(_realize_axis): rctx.realize_map[x] = _realize_axis + + # if this element is a reduce and there's ended ranges, we might have to end some other ranges + if len(ending_ranges[x]) and x.op in GroupOp.Elementwise.union({Ops.REDUCE_AXIS}): + _realize_axis = rctx.realize_map.get(x, []) or [] + for i,r in enumerate(out_rngs): + if i in _realize_axis: continue + if not (PCONTIG > 1) or any(any(rr.arg > e.arg for e in ending_ranges[x]) for rr in r.ranges): + _realize_axis.append(i) + ending_ranges[x] = [] + if len(_realize_axis): + rctx.realize_map[x] = _realize_axis + out_rngs = tuple([(rctx.new_range(x.shape[i]) if i in _realize_axis else r) for i,r in enumerate(out_rngs)]) + + # TODO: some ops don't have shape, enable this after the `.st` property is removed + #assert len(out_rngs) == len(x.shape), \ + # f"shape len mismatch {len(out_rngs)} != {len(x.shape)} on {x.op} with {len(consumer_map[x])} consumers and realize {x in realize_map}" + + # *** the ranges on the inputs are + # 1. swizzled for MovementOps + # 2. newly created for REDUCE_AXIS + # 3. passed through for everything else + + rngs = out_rngs # rngs is the input ranges # pylint: disable=possibly-used-before-assignment + + # apply movement ops + if x.op in GroupOp.Movement: rngs = apply_movement_op(x.op, x.src[0].shape, x.marg, rngs) + # if the EXPAND is used to inject a range, we don't mark it as ending_ranges. otherwise we do. + # NOTE: this doesn't actually always end a range, but this is why convs are realized, so for now we need it + if x.op is Ops.EXPAND and all(isinstance(y, int) or y.op is not Ops.RANGE for y in x.shape): + ending_ranges[x] += list(UOp.sink(*[ro for ri, ro in zip(rngs, out_rngs) if ri is not ro]).ranges.keys()) + + # REDUCE_AXIS creates ranges for the axes it is reducing + if x.op is Ops.REDUCE_AXIS: + rngs = tuple(rctx.new_range(s, axistype=AxisType.REDUCE) if i in x.arg[1] else r for i,(r,s) in enumerate(zip(rngs, x.src[0].shape))) + + if debug: + realized_ranges = rctx.realize_map.get(x, None) + if x.op is Ops.RESHAPE or len(rngs) != len(out_rngs): + disp = render_ranges(rngs, realized=realized_ranges) + " -> " + render_ranges(out_rngs, realized=realized_ranges) + else: + disp = render_ranges(rngs, out_rngs, realized=realized_ranges) + print("***" if x in rctx.realize_map else " ", + f"{len(consumer_map[x]):2d} {str(x.op):20s} {str(x._shape):35s} {len(ending_ranges[x]):2d}", disp) + + # assign to the range map. rngs are the input ranges, out_rngs are the output ranges, from the x op. + rctx.range_map[x] = (rngs, out_rngs) + + tsink = graph_rewrite(tsink, pm_apply_rangeify, ctx=rctx, bottom_up=True, name="apply rangeify") + return tsink, rctx + +def render_ranges(*rngs_list, realized) -> str: + disp = [] + for i, rs in enumerate(zip(*[[r.render() for r in rngs] for rngs in rngs_list])): + rng = rs[0] if all_same(rs) else " -> ".join(rs) + if realized is not None and i in realized: rng = colored(rng, "yellow") + disp.append("["+rng+"]") + return ''.join(disp) diff --git a/tinygrad/schedule/kernelize.py b/tinygrad/schedule/kernelize.py deleted file mode 100644 index c487fb5c9f..0000000000 --- a/tinygrad/schedule/kernelize.py +++ /dev/null @@ -1,382 +0,0 @@ -from dataclasses import dataclass -from tinygrad.uop.ops import UOp, Ops, GroupOp, PatternMatcher, UPat, graph_rewrite, graph_rewrite_map, identity_element, resolve -from tinygrad.uop.ops import track_rewrites, _substitute, KernelInfo -from tinygrad.uop.spec import type_verify, tensor_uop_spec -from tinygrad.uop.symbolic import symbolic_simple -from tinygrad.helpers import Metadata, all_int, all_same, prod, dedup, unwrap, getenv, pluralize, FUSE_ARANGE, DEBUG, SPLIT_REDUCEOP -from tinygrad.dtype import ImageDType -from tinygrad.schedule.multi import multi_pm -from tinygrad.schedule.grouper import group_realizes, ALWAYS_CONTIGUOUS -from tinygrad.codegen.opt.swizzler import merge_views, apply_swizzle, swizzle_reduceop -from tinygrad.codegen.opt import Opt - -# creation can recurse a lot -import sys -sys.setrecursionlimit(10000) - -# **** schedule simplifier - -def simplify_stride0_reduce(reduce:UOp, x:UOp): - # must be unmasked (NOTE: can be relaxed if not masked on stride 0 axis) - if any(v.mask is not None for v in unwrap(x.st).views): return None - # must have all stride 0 in the relevant axis (NOTE: can do partial) - if not all(unwrap(x.st).views[-1].strides[axis] == 0 for axis in reduce.arg[1]) or not all_int(x.shape): return None - prshape = prod(x.shape[i] for i in reduce.arg[1]) - ret = x.shrink(tuple((0,s) if i not in reduce.arg[1] else (0,1) for i,s in enumerate(x.shape))) - match reduce.arg[0]: - case Ops.ADD: return ret*prshape - case Ops.MUL: return ret.pow(prshape) - case Ops.MAX: return ret # NOTE: Ops.MAX is passthrough - -def split_reduceop(reduce:UOp, x:UOp): - if not SPLIT_REDUCEOP or not all_int(x.shape) or (prod(x.shape)//prod(reduce.shape))= 3: print(f"split {divisor}: {x.shape} -> {splitted.shape} -> {reduce.shape}") - # reduce original axes, then split - return splitted.r(*reduce.arg).r(reduce.arg[0], (len(reduce.shape),)).reshape(reduce.shape) - -def copy_reorder_view(copy:UOp, view:UOp, base:UOp): - if prod(view.shape) < prod(base.shape): return view.contiguous().copy_to_device(copy.device) - return base.copy_to_device(copy.device).view(view.arg) - -kernelize_sym = symbolic_simple+PatternMatcher([ - # UOp with size 0 is zero - (UPat(GroupOp.All-{Ops.SINK}, name="root"), lambda root: root.const_like(0) if root.base.st is not None and root.size == 0 else None), - # DETACH and CONTIGUOUS_BACKWARD are NOOPs here - (UPat((Ops.DETACH, Ops.CONTIGUOUS_BACKWARD), name="x"), lambda x: x.src[0]), - # reduce of size 0 is the identity element - (UPat(Ops.REDUCE_AXIS, name="reduce", src=(UPat.var("x"),)), - lambda reduce,x: reduce.const_like(identity_element(reduce.arg[0], reduce.dtype)) if x.size == 0 and reduce.size != 0 else None), - # reduce on stride 0 is collapsed - (UPat(Ops.REDUCE_AXIS, name="reduce", src=(UPat.var("x"),)), simplify_stride0_reduce), - # split_reduceop - (UPat(Ops.REDUCE_AXIS, name="reduce", src=(UPat.var("x"),)), split_reduceop), - # COPY(CONST) creates a new CONST on the destination device - (UPat(Ops.COPY, name="root", src=(UPat.cvar("x"), UPat(Ops.DEVICE))), lambda root,x: root.const_like(x.arg)), - # non device changing COPY is a NOOP - (UPat(Ops.COPY, name="c", src=(UPat.var("x"), UPat(Ops.DEVICE))), lambda c,x: x if c.device == x.device else None), - # store a shrink before COPY, otherwise view after the COPY - (UPat(Ops.COPY, src=(UPat(Ops.VIEW, src=(UPat.var("base"),), name="view"), UPat(Ops.DEVICE)), name="copy"), copy_reorder_view), - # remove cast to image when it's already a contiguous image - (UPat(Ops.CAST, name="cast", src=(UPat(Ops.VIEW, name="vm", src=(UPat(Ops.CONTIGUOUS, name="base"),)),)), - lambda cast,base,vm: base.view(vm.st) if isinstance(cast.dtype, ImageDType) and isinstance(base.dtype, ImageDType) else None), - # CAST before masking constants - (UPat.cvar("x").view().cast(name="c"), lambda x,c: x.cast(c.dtype).view(c.src[0].arg)), - # make things that can't be images not images - (UPat(GroupOp.All-{Ops.BUFFER, Ops.VIEW, Ops.CONST, Ops.DEVICE}, name="u"), lambda u: u.replace(dtype=dt.base) if isinstance(dt:=u.dtype,ImageDType) - and (prod(u.shape) != prod(dt.shape) or not any(u.shape[x]%4 == 0 for x in u.st.unit_stride_axes())) else None), - # remove contiguous if we can just view the buffer - (UPat(Ops.CONTIGUOUS, name="root", src=(UPat(Ops.VIEW, name="view", src=(UPat(Ops.BUFFER, name="buf"),)),)), - lambda root,view,buf: view if view.st.contiguous and view.size == buf.size else None), - # contiguous/buffer/copy/assign is already contiguous - (UPat(Ops.CONTIGUOUS, name="root", src=(UPat((Ops.CONTIGUOUS, Ops.BUFFER, Ops.COPY, Ops.ASSIGN)),)), lambda root: root.src[0]), - # substitute BITCAST/CONTIGUOUS with BUFFER_VIEW on DISK - (UPat((Ops.BITCAST, Ops.CONTIGUOUS), src=(UPat.var("x"),), name="t"), lambda x,t: UOp(Ops.BUFFER_VIEW, t.dtype, (x.base,), - (t.size, x.st.views[0].offset)).reshape(t.shape) if isinstance(x.device, str) and x.device.startswith("DISK") else None), - # double ASSIGN to same target is one ASSIGN - (UPat(Ops.ASSIGN, src=(UPat.var("t"), UPat(Ops.ASSIGN, src=(UPat.var("t"), UPat.var("x"))))), lambda x,t: t.assign(x.contiguous())), - # ASSIGN to unrealized replaces the UOp - (UPat(Ops.ASSIGN, src=(UPat.var("t"), UPat.var("x"))), lambda x,t: x.contiguous() if t.base.op not in {Ops.BUFFER, Ops.BUFFER_VIEW} and - not (t.base.op is Ops.MSTACK and all(x.op is Ops.BUFFER for x in t.base.src)) else None), - # put CAST to smaller dtype before EXPAND - (UPat(Ops.CAST, name="cast", src=(UPat(Ops.VIEW, name="vm"),)), lambda cast,vm: vm.base.cast(cast.dtype).view(vm.st) - if cast.dtype.itemsize <= vm.dtype.itemsize and resolve(prod(vm.shape) > vm.st.real_size()) else None), - # put UnaryOps before EXPANDs, if it can fuse with the input - (UPat(GroupOp.Unary, src=(UPat(Ops.VIEW, src=(UPat(GroupOp.All-ALWAYS_CONTIGUOUS, name="inp"),), name="v"),), name="alu"), - lambda inp,v,alu: inp.alu(alu.op).view(v.st) if resolve(prod(alu.shape) > v.st.real_size()) else None), -]) - -# support for using a contiguous permuted view instead of the parent view if one exists - -def found_contiguous(ctx:dict[UOp, UOp], contig:UOp, src:UOp): - if (sti:=unwrap(src.st).invert(src.base.shape)) is not None: ctx[src.base] = contig.view(sti) - -replace_contiguous = PatternMatcher([ - (UPat(Ops.CONTIGUOUS, src=(UPat(Ops.VIEW, name="src"),), name="contig"), found_contiguous), - (UPat(GroupOp.ALU, name="alu"), lambda ctx,alu: alu.replace(src=new_src) if (new_src:=tuple(ctx.get(s, s) for s in alu.src)) != alu.src else None), -]) - -# **** create kernels - -@dataclass(frozen=True) -class Kernel: - ast: UOp - metadata: tuple[Metadata, ...] = () - def __repr__(self): - ast_rep = f"SINK{tuple(s.op for s in self.ast.src)}" if self.ast.op is Ops.SINK else repr(self.ast.op) - return f"" - -def create_kernel(x:UOp, b:UOp|None=None): - if b is None: b = UOp.new_buffer(x.device, x.size, x.dtype) - kernel = UOp(Ops.KERNEL, src=(b,)+x.src, arg=Kernel(x.sink(), m if (m:=x.metadata) else ())) - buffer = b.base if b.size == b.base.size else UOp(Ops.BUFFER_VIEW, b.dtype, (b.base,), (b.size, b.arg.views[0].offset)) - # we have to shrink the buffer back to the symbolic shape - return buffer.assign(kernel).reshape(tuple(d.vmax if isinstance(d, UOp) else d for d in x.shape)).shrink(tuple((0, d) for d in x.shape)) - -DONT_PLACE_IN_KERNEL = {Ops.KERNEL, Ops.ASSIGN, Ops.BUFFER, Ops.MSELECT, Ops.MSTACK, Ops.MULTI, Ops.BIND} -def append_to_kernel(x:UOp): - new_srcs: list[UOp] = [] - metadata = x.arg.metadata - for s in x.src: - if s.op in DONT_PLACE_IN_KERNEL: new_srcs.append(s) - else: - new_srcs.extend(s.src) - # NOTE: because const and device are shared UOps they don't change metadata - # NOTE: if it's a reshape after ASSIGN we're not fusing that parent kernel - if s.base.op not in {Ops.CONST, Ops.DEVICE} and (not (s.op is Ops.RESHAPE and s.base.op is Ops.ASSIGN)) and (m:=s.metadata): metadata += m - if (new_src:=tuple(dedup(new_srcs))) != x.src: return x.replace(src=new_src, arg=Kernel(x.arg.ast, tuple(dedup(metadata)))) - -create_kernels = PatternMatcher([ - # always give assign/contiguous a kernel - (UPat.assign(UPat.var("b"), UPat(GroupOp.All-{Ops.KERNEL}), name="x"), create_kernel), - (UPat(Ops.CONTIGUOUS, name="x"), create_kernel), - # walk back the local graph until we reach a realized source - (UPat(Ops.KERNEL, name="x"), append_to_kernel), - # push RESHAPE through MSELECT - (UPat(Ops.MSELECT, src=(UPat(Ops.RESHAPE, name="r"),), name="ms"), lambda ms,r: r.src[0].mselect(ms.arg).reshape(r.arg)), - # push RESHAPE through MSTACK - (UPat(Ops.MSTACK, src=UPat(Ops.RESHAPE), name="ms"), - lambda ms: UOp(Ops.MSTACK, ms.dtype, tuple(x.src[0] for x in ms.src)).reshape(ms.src[0].arg)), -]) - -def add_stores(ctx, sink: UOp): - stores = [] - for i,x in enumerate(sink.src): - gbl = UOp(Ops.DEFINE_GLOBAL, (s:=x.base).dtype.ptr(ctx[i].size), (), i) - # if this is an assign then we already have a buffer with a view that should be the target of the store - if x.op is Ops.ASSIGN: stores.append(UOp.store(gbl.view(unwrap(s.st)), s)) - # otherwise we have to create the shapetracker and shrink it to the correct symbolic shape - else: stores.append( - UOp.store(gbl.reshape(tuple(int(d.vmax) if isinstance(d,UOp) else d for d in s.shape)).shrink(tuple((0,d) for d in s.shape)),s)) - return UOp.sink(*stores, arg=sink.arg) -# **** fix kernel AST - -def unbind_view(x:UOp): - if any(x.op is Ops.BIND for x in x.arg.vars()): return x.replace(arg=x.arg.unbind()[0]) - return None - -replace_buffers = PatternMatcher([ - # sink on contig creates a KernelInfo - (UPat(Ops.CONTIGUOUS, name="c").sink(name="s"), - lambda s,c: s.replace(src=(c.replace(arg=None),), arg=KernelInfo(opts_to_apply=c.arg)) \ - if s.arg is None and c.arg is not None and isinstance(c.arg[0], Opt) else None), - # replace ASSIGN with the target BUFFER - (UPat(Ops.ASSIGN, src=(UPat((Ops.BUFFER, Ops.LOAD)), UPat(Ops.KERNEL)), name="assign", allow_any_len=True), lambda assign: assign.src[0]), - # HACK: select the 0 branch of MSTACK (the device is wrong after this, is that okay?) - (UPat(Ops.MSTACK, name="x"), lambda x: x.src[0]), - # LOAD - (UPat(Ops.BUFFER, name="x"), lambda ctx,x: UOp(Ops.DEFINE_GLOBAL, x.dtype.ptr(x.size), (), ctx.index(x)).load()), - # no SINK for meta ops - (UPat(Ops.SINK, src=(UPat(Ops.CONTIGUOUS, src=(UPat(GroupOp.Meta, name="x"),),))), lambda x:x), - # STORE (except for meta ops) - (UPat(Ops.SINK, src=UPat(GroupOp.All-{Ops.STORE}), name="sink"), add_stores), - # remove CONTIGUOUS/DEVICE from kernel AST - (UPat((Ops.CONTIGUOUS, Ops.MSELECT), src=(UPat.var("x"),)), lambda x: x), - (UPat(Ops.VIEW, src=(UPat(Ops.DEVICE),), name="view"), lambda view: view.replace(src=())), - # passthrough ASSIGN (but let MSTACK process first) - (UPat(Ops.ASSIGN, src=(UPat(GroupOp.All-{Ops.MSTACK}), UPat()), name="x"), lambda x: x.src[1]), - # remove any BINDs from VIEWS - (UPat(Ops.VIEW, src=(UPat(), UPat((Ops.BIND, Ops.DEFINE_VAR))), allow_any_len=True, name="x"), lambda x: x.replace(src=x.src[0:1])), - # remove any BINDs from DEFINE_VARs - (UPat(Ops.BIND, name="x"), lambda x: x.src[0]), - # remove BINDs from ShapeTrackers - (UPat(Ops.VIEW, name="x"), unbind_view), -]) - -def fix_kernel_ast(k:UOp) -> UOp|None: - if k.arg.ast.op in GroupOp.Meta or all(s.op is Ops.STORE for s in k.arg.ast.src): return None - # replace buffer with define_global + add load/store last - bufs = [] - for s in k.src: - if s.op is Ops.BIND: continue - s = s.buf_uop - # traverse back through MSELECT and MSTACK. HACK: 0 branch of MSTACK only - while s.op in {Ops.MSELECT, Ops.MSTACK}: s = s.src[0] - bufs.append(s) - # replace global memory ops with the BUFFER they write to - # NOTE: merge_views is needed to unbind the reshapes - ast = graph_rewrite(k.arg.ast, merge_views+replace_buffers, bufs, bottom_up=True, name="replace buffers") - if ast.op is Ops.SINK and not all_same([x.device for x in k.src if x.op is not Ops.BIND]): - raise RuntimeError(f"all buffers must be on the same device: {tuple(b.buf_uop.buffer for b in k.src)}") - return k.replace(arg=Kernel(ast, k.arg.metadata)) - -create_ast = PatternMatcher([ - (UPat(Ops.KERNEL, name="k"), fix_kernel_ast), - (UPat(Ops.DEFINE_VAR, src=(UPat(),), allow_any_len=True, name="x"), lambda x: x.replace(src=())), -]) - -# ** add metadata of KERNEL outputs - -def append_metadata(root:UOp, k:UOp): - if not root.metadata or (new_metadata:=tuple(dedup(k.arg.metadata+root.metadata))) == k.arg.metadata: return None - return root.replace(src=(root.src[0], k.replace(arg=Kernel(k.arg.ast, new_metadata)))+root.src[2:]) - -replace_metadata = PatternMatcher([(UPat(Ops.ASSIGN, src=(UPat(), UPat(Ops.KERNEL, name="k")), name="root", allow_any_len=True), append_metadata),]) - -pm_fuse = PatternMatcher([ - # FUSE on CONTIGUOUS removes FUSE - (UPat(Ops.CONTIGUOUS, name="c").fuse(), lambda c: c), - - # FUSE triggers swizzle on reduceop - (UPat(Ops.VIEW, src=(UPat(Ops.REDUCE_AXIS, src=(UPat.var("src"),), name="r").or_casted(),), name="view").fuse(), - lambda r,src,view: ret.cast(view.dtype) if (ret:=swizzle_reduceop(r, src, view, fuse=True)) is not None else None), - - # FUSE on reduce (without view) adds fuse marker to grouper - (UPat(Ops.REDUCE_AXIS, name="r").fuse(), - lambda r: r.replace(src=(r.src[0].fuse(),), arg=r.arg+(True,)) if len(r.arg) == 2 else None), - - # remove FUSE and insert CONTIGUOUS if it's an unsafe pad - (UPat(Ops.VIEW, src=(UPat(GroupOp.UnsafePad, name="alu"),), name="view").fuse(), - lambda alu, view: alu.contiguous().view(view.st) if any(v.mask is not None for v in view.st.views) else None), - - # FUSE elementwise. - (UPat(Ops.VIEW, src=(UPat({*GroupOp.ALU, Ops.CAST}, name="alu"),), name="view").fuse(), - lambda alu, view: alu.replace(src=tuple(apply_swizzle(x.view(view.arg)).fuse() for x in alu.src))), - - # push FUSE through to srcs - (UPat(Ops.FUSE, name="x"), lambda x: x.src[0].replace(src=tuple(y.fuse() for y in x.src[0].src))), -]) - -def do_fusion(x:UOp): - found_contiguous = {} - def gate_contiguous(x): - if is_contiguous:=(x.op is Ops.CONTIGUOUS): found_contiguous[x] = x.replace(src=(UOp(Ops.VIEW, arg=x.st), UOp.unique())) - return not is_contiguous - x.toposort(gate=gate_contiguous) - del gate_contiguous - return graph_rewrite(x.substitute(found_contiguous), pm_fuse, name="local fusion").substitute({v:k for k,v in found_contiguous.items()}) - -def fuse_arange(root:UOp): - # skip if root is arange - if not FUSE_ARANGE or root.src[0].base.op is Ops.CONST: return None - # gather all local aranges (including any fused ones) - local_arange: list[UOp] = [] - def gate_reduce(u): - if u.op is Ops.REDUCE_AXIS and u.src[0].base.op is Ops.CONST: local_arange.append(u) - return u.op not in {*ALWAYS_CONTIGUOUS, Ops.REDUCE_AXIS} or u is root - toposort = root.toposort(gate=gate_reduce) - if not local_arange: return None - # fuse the nearest expand child of arange - local_children: dict[UOp, list[UOp]] = {} - for u in toposort: - for s in u.src: local_children.setdefault(s, []).append(u) - fuse_rep: dict[UOp, UOp] = {} - for r in local_arange: - # skip if already fused - if len(r.arg) > 2: continue - q = list(local_children[r]) - while q: - u = q.pop() - if not (curr_children:=local_children.get(u, [])): continue - for child in curr_children: - other_paths = {s for s in child.toposort() if s.op in {Ops.REDUCE_AXIS, Ops.BUFFER} and s not in {root, r}} - fuse_rep[child] = child.replace(src=tuple(s.fuse() if s is u else s for s in child.src)) - if other_paths: break - else: q.extend(curr_children) - return root.substitute(fuse_rep, name="fuse_arange") if fuse_rep else None - -do_fuse = PatternMatcher([ - (UPat(Ops.FUSE, name="x"), do_fusion), - (UPat(Ops.REDUCE_AXIS, name="root"), fuse_arange), -]) - -add_contiguous = PatternMatcher([(UPat(GroupOp.All-{Ops.CONTIGUOUS, Ops.ASSIGN}, name="x"), - lambda ctx,x: x.replace(tag=1).contiguous() if x in ctx and x.tag is None else None)]) - -# TODO: get this from the device through GrouperOpts -DEVICE_MAX_BUFS = {"METAL":32, "WEBGPU":8} - -def limit_bufs(root:UOp): - # check if backend has a buffer limit - device = root.device if isinstance(root.device, str) else root.device[0].split(":")[0] - if not (MAX_BUFS:=getenv("MAX_KERNEL_BUFFERS", DEVICE_MAX_BUFS.get(device, 0))): return None - # count number of unique buffers flowing into this op - bufs: set[UOp] = set() - def gate_input(u:UOp): - if (is_load:=(u.op in {Ops.BUFFER, Ops.CONTIGUOUS, Ops.ASSIGN, Ops.MSTACK, Ops.DEFINE_VAR})): bufs.add(u) - return not is_load - root.toposort(gate=gate_input) - # NOTE: this -1 is for the output buffer - if len(bufs)>=MAX_BUFS-1: - return root.replace(src=tuple(s if s.base in bufs else s.replace(tag=1).contiguous() for s in root.src)) - -def view_add_srcs(x:UOp): - if len(avars:=x.arg.vars()) and len(x.src) == 1: - return x.replace(src=x.src+tuple(avars)) - return None - -finalize_contiguous = PatternMatcher([ - # if an op takes more than one input, check combined LOADs don't exceed device limits - (UPat(set.union(GroupOp.Binary, GroupOp.Ternary), name="root"), limit_bufs), - # merge contiguous - (UPat(Ops.CONTIGUOUS, src=(UPat(Ops.CONTIGUOUS),), name="x"), lambda x: x.src[0]), - # simplify views - (UPat(Ops.VIEW, src=(UPat.var('x')), name="v"), lambda x,v: x.view(new_st) if (new_st:=v.arg.simplify()) != v.arg else None), - # vars to views srcs - (UPat(Ops.VIEW, name="x"), view_add_srcs), -]) - -remove_tags = PatternMatcher([(UPat(GroupOp.All, name="x"), lambda x: x.replace(tag=None) if x.tag is not None else None)]) - -@track_rewrites(name=lambda sink,ret: f"Schedule {pluralize('Kernel',len([u for u in ret[sink].toposort() if u.op is Ops.KERNEL]))}", replay=True) -def get_kernelize_map(sink:UOp) -> dict[UOp, UOp]: - """ - Function to transform the Tensor UOp graph into a version with Ops.KERNEL - - Args: - sink: The Ops.SINK rooting the Tensor graph. - - Returns: - Map transforming each UOp in the sink to the Ops.KERNEL graph. - """ - - # multi + merge_views + simplify - tensor_map = graph_rewrite_map(sink, multi_pm+do_fuse+merge_views+kernelize_sym+replace_contiguous, ctx={}, name="merge_views") - - # display the cleaned up tensor graph - if getenv("VIZ"): graph_rewrite(tensor_map[sink], PatternMatcher([]), name="View Tensor Graph") - - # insert contiguous in places determined by the realize map - realize_map = group_realizes(tensor_map[sink]) - tensor_map = graph_rewrite_map(tensor_map[sink], add_contiguous, ctx=realize_map, bottom_up=True, input_map=tensor_map, name="add_contiguous") - tensor_map = graph_rewrite_map(tensor_map[sink], finalize_contiguous+remove_tags, input_map=tensor_map, name="finalize_contiguous") - - # group into kernels (this is context-free) - tensor_map = graph_rewrite_map(tensor_map[sink], create_kernels, input_map=tensor_map, name="create_kernels") - - # if a kernel depends on a buffer, and that buffer is later assigned to, make the assign depend on the kernel's assign - kernel_assign: dict[UOp, UOp] = {} - assign_rep: dict[UOp, UOp] = {} - for u in tensor_map[sink].toposort(): - if u.op is not Ops.ASSIGN: continue - kernel_assign[u.buf_uop] = u - for s in u.src[1].src: - # TODO: this is probably broken for MSELECT/MSTACK - if s.op is not Ops.BUFFER or s is u.buf_uop or (a:=kernel_assign.get(s)) is None: continue - if any(x.op is Ops.ASSIGN and x.buf_uop is s for x in u.toposort()): - raise RuntimeError(f"cycle detected in graph, kernel for {u.buf_uop} must either depend on ASSIGN or BUFFER") - assign_rep[a] = kernel_assign[s] = a.replace(src=a.src+(u,)) - if assign_rep: - tensor_map = graph_rewrite_map(tensor_map[sink], _substitute, ctx=assign_rep, bottom_up=True, input_map=tensor_map, name="fix_assign") - - # finally, create the AST for kernels - tensor_map = graph_rewrite_map(tensor_map[sink], create_ast+replace_metadata, bottom_up=True, input_map=tensor_map, name="create_ast") - - # display the final graph - sched_sink = tensor_map[sink] - if getenv("VIZ"): graph_rewrite(sched_sink, PatternMatcher([]), name="View Kernel Graph") - - # verify Kernels match the spec - if __debug__: type_verify(list(sched_sink.toposort()), tensor_uop_spec) - - return tensor_map diff --git a/tinygrad/schedule/multi.py b/tinygrad/schedule/multi.py index b6623e0f14..a665bca837 100644 --- a/tinygrad/schedule/multi.py +++ b/tinygrad/schedule/multi.py @@ -1,8 +1,7 @@ -from typing import cast, TypeVar +from typing import cast import functools, itertools, operator -from tinygrad.helpers import all_same, all_int, prod, DEBUG, RING, getenv, unwrap -from tinygrad.uop.ops import Ops, UOp, sint, PatternMatcher, UPat, GroupOp, resolve, track_rewrites, graph_rewrite_map -from tinygrad.shape.shapetracker import ShapeTracker +from tinygrad.helpers import all_same, all_int, prod, DEBUG, RING, getenv +from tinygrad.uop.ops import Ops, UOp, sint, PatternMatcher, UPat, GroupOp, track_rewrites, graph_rewrite_map, graph_rewrite from tinygrad.device import Device # *** allreduce implementation *** @@ -69,7 +68,7 @@ def handle_allreduce(buf:UOp, red:UOp) -> UOp|None: # allgather copied_chunks = [] for i,c in enumerate(reduced_chunks): - this_chunk = [None] * len(buf.device) + this_chunk: list[UOp|None] = [None] * len(buf.device) this_chunk[(i+len(buf.device)-1)%n_lbs] = c for step in range(n_lbs-1): dest = (i+step)%n_lbs @@ -82,26 +81,12 @@ def handle_allreduce(buf:UOp, red:UOp) -> UOp|None: # ***** multi rewrite MSELECT/MSTACK ***** -T = TypeVar("T", bound=ShapeTracker|sint) -def _replace_dnum(st:T, val:int) -> T: - # replace dnum in ShapeTracker (or UOp) with literal const for this mselect - if not isinstance(st, int) and (dnums:=[x for x in st.vars() if x.op is Ops.DEFINE_VAR and x.arg[0] == '_device_num']): - assert len(dnums) == 1, f"view must have exactly 0 or 1 dnum, got {dnums}" - st = st.substitute({dnums[0]:dnums[0].const_like(val)}) - return st - -def mstack_reorder_view(ms:UOp): - args = [x.arg for x in ms.src] - if not all_same(args) or len([x for x in args[0].vars() if x.arg[0] == '_device_num']) != 0: return None - return UOp(Ops.MSTACK, ms.dtype, tuple(x.src[0] for x in ms.src)).view(args[0]) - -# NOTE: view path is for RANGEIFY=0, there should only be one way of doing this -def mstack_early_shrink(ms:UOp, view:UOp|None=None, shrink:UOp|None=None): - if view is not None and (resolve(prod(view.shape) >= prod(ms.shape)) or _replace_dnum(unwrap(view.st), 0) == view.st): return None - ret = [] +def mstack_early_shrink(ms:UOp, shrink:UOp): + ret:list[UOp] = [] def apply_shrink(s:UOp, i:int) -> UOp: - if view is not None: return s.view(_replace_dnum(unwrap(view.st), i)) - return s.shrink(tuple(tuple(_replace_dnum(x, i) for x in ss) for ss in unwrap(shrink).arg)) + new_arg = [tuple([x.substitute({dvar[0]:dvar[0].const_like(i)}) if isinstance(x, UOp) and + (dvar:=[v for v in x.vars() if v.op is Ops.DEFINE_VAR and v.arg[0]=='_device_num']) else x for x in ss]) for ss in shrink.marg] + return s.shrink(tuple(new_arg)) for i, x in enumerate(ms.src): if x.op is Ops.COPY: # if src device doesn't have a renderer, we have to view after the copy @@ -125,18 +110,11 @@ replace_allreduce = PatternMatcher([ x.mselect(0).copy_to_device(c.device) if isinstance(c.device, str) and isinstance(x.device, tuple) else None), # MSELECT on MSTACK is replaced with nothing (UPat(Ops.MSELECT, src=(UPat(Ops.MSTACK, name="mstack"),), name="ms"), lambda mstack, ms: mstack.src[ms.arg]), - # MSELECT must select a base, if there are views apply them after selecting the base - (UPat(Ops.MSELECT, src=(UPat(Ops.VIEW, src=(UPat.var("base"),), name="view"),), name="ms"), lambda ms, view, base: - base.mselect(ms.arg).view(_replace_dnum(unwrap(view.st), ms.arg))), - # move view through MSTACK - (UPat(Ops.MSTACK, src=UPat(Ops.VIEW), name="ms"), mstack_reorder_view), # move shrink before MSTACK - (UPat(Ops.VIEW, src=(UPat(Ops.MSTACK, name="ms"),), name="view"), mstack_early_shrink), - # *** new movement ops reordering - # move shrink before MSTACK - (UPat(Ops.SHRINK, src=(UPat(Ops.MSTACK, name="ms"),), name="shrink"), mstack_early_shrink), + (UPat(Ops.SHRINK, src=(UPat(Ops.MSTACK, name="ms"),), allow_any_len=True, name="shrink"), mstack_early_shrink), # move MSELECT before movement ops - (UPat(Ops.MSELECT, src=(UPat(GroupOp.Movement, src=(UPat.var("s"),), name="v"),), name="ms"), lambda s,v,ms: v.replace(src=(s.mselect(ms.arg),))), + (UPat(Ops.MSELECT, src=(UPat(GroupOp.Movement, src=(UPat.var("s"),), allow_any_len=True, name="v"),), name="ms"), + lambda s,v,ms: v.replace(src=(s.mselect(ms.arg),)+v.src[1:])), ]) # ***** multi functions ***** @@ -175,40 +153,40 @@ def _shape_to_single_shard(axis, shape:tuple[sint, ...], lb:UOp) -> tuple[sint, return tuple(lb.shape[axis] if a == axis else s for a,s in enumerate(shape)) def reshape_multi(root:UOp, multi:UOp): - arg = root.arg + arg = root.marg if (new_axis:=root.axis) is None: return multi.src[0].reshape(arg).multi(new_axis) assert prod(multi.shape) == prod(arg), "reshape must maintain prod(shape)" - assert prod(multi.src[0].shape[multi.axis:])%prod(arg[new_axis+1:]) == 0, f"reshape cannot move items between shards {multi.shape} -> {root.arg=}" + assert prod(multi.src[0].shape[multi.axis:])%prod(arg[new_axis+1:]) == 0, f"reshape cannot move items between shards {multi.shape} -> {arg=}" new_shape_axis = prod(multi.src[0].shape[multi.axis:]) // prod(arg[new_axis+1:]) return multi.src[0].reshape(tuple(s if a!=new_axis else new_shape_axis for a,s in enumerate(arg))).multi(new_axis) def expand_multi(root:UOp, multi:UOp): # NOTE: this assert isn't needed, sharded axis can have dim 1 - assert multi.axis is None or root.arg[multi.axis] == multi.shape[multi.axis], f"expand not supported on sharded axis {root.arg=}" - return multi.src[0].expand(_shape_to_single_shard(multi.axis, root.arg, multi.src[0])).multi(multi.axis) + assert multi.axis is None or root.marg[multi.axis] == multi.shape[multi.axis], f"expand not supported on sharded axis {root.marg=}" + return multi.src[0].expand(_shape_to_single_shard(multi.axis, root.marg, multi.src[0])).multi(multi.axis) def pad_multi(root:UOp, multi:UOp): - assert multi.axis is None or root.arg[multi.axis] == (0,0), f"padding not supported for {root.arg=}" - return multi.src[0].pad(root.arg).multi(multi.axis) + assert multi.axis is None or root.marg[multi.axis] == (0,0), f"padding not supported for {root.marg=}" + return multi.src[0].pad(root.marg).multi(multi.axis) def permute_multi(root:UOp, multi:UOp): # all permutes supported! - return multi.src[0].permute(root.arg).multi(root.axis) + return multi.src[0].permute(root.marg).multi(root.axis) def shrink_multi(root:UOp, multi:UOp): - assert multi.axis is None or root.arg[multi.axis] == (0, multi.shape[multi.axis]) or root.arg[multi.axis] in multi.bounds, \ - f"shrinking not supported for {root.arg=}" - if multi.axis is not None and root.arg[multi.axis] in multi.bounds and root.arg[multi.axis] != (0, multi.shape[multi.axis]): - assert all(root.arg[i] == (0, s) or i == multi.axis for i,s in enumerate(multi.shape)), \ + assert multi.axis is None or root.marg[multi.axis] == (0, multi.shape[multi.axis]) or root.marg[multi.axis] in multi.bounds, \ + f"shrinking not supported for {root.marg=}" + if multi.axis is not None and root.marg[multi.axis] in multi.bounds and root.marg[multi.axis] != (0, multi.shape[multi.axis]): + assert all(root.marg[i] == (0, s) or i == multi.axis for i,s in enumerate(multi.shape)), \ "cannot shrink sharded and non-sharded axis at the same time" # NOTE: shrink on the shard axis is only allowed when result is a single partition, denoted by the new real # we just copy it to all the devices, no real. this will be optimized out later - return multi.src[0].copy_to_device(multi.device, arg=multi.bounds.index(root.arg[multi.axis])) - return multi.src[0].shrink(tuple((0, multi.src[0].shape[multi.axis]) if a == multi.axis else s for a,s in enumerate(root.arg))).multi(multi.axis) + return multi.src[0].copy_to_device(multi.device, arg=multi.bounds.index(root.marg[multi.axis])) + return multi.src[0].shrink(tuple((0, multi.src[0].shape[multi.axis]) if a == multi.axis else s for a,s in enumerate(root.marg))).multi(multi.axis) def flip_multi(root:UOp, multi:UOp): - assert multi.axis is None or not root.arg[multi.axis], "flipping not supported on sharded axis" - return multi.src[0].flip(root.arg).multi(multi.axis) + assert multi.axis is None or not root.marg[multi.axis], "flipping not supported on sharded axis" + return multi.src[0].flip([i for i,x in enumerate(root.marg) if x]).multi(multi.axis) # from multiple devices -> one def copy_multi(multi:UOp, device:UOp): @@ -226,19 +204,23 @@ def passthrough_multi(root:UOp, multi:UOp): multi_pm = PatternMatcher([ (UPat(GroupOp.ALU, name="root", custom_early_reject=set([Ops.MULTI])), alu_multi), (UPat(Ops.REDUCE_AXIS, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), reduce_multi), - (UPat(Ops.RESHAPE, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), reshape_multi), - (UPat(Ops.EXPAND, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), expand_multi), - (UPat(Ops.PAD, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), pad_multi), + (UPat(Ops.RESHAPE, src=(UPat(Ops.MULTI, name="multi"), UPat()), name="root"), reshape_multi), + (UPat(Ops.EXPAND, src=(UPat(Ops.MULTI, name="multi"), UPat()), name="root"), expand_multi), + (UPat(Ops.PAD, src=(UPat(Ops.MULTI, name="multi"), UPat(), UPat()), name="root"), pad_multi), + (UPat(Ops.SHRINK, src=(UPat(Ops.MULTI, name="multi"), UPat(), UPat()), name="root"), shrink_multi), (UPat(Ops.PERMUTE, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), permute_multi), - (UPat(Ops.SHRINK, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), shrink_multi), (UPat(Ops.FLIP, src=(UPat(Ops.MULTI, name="multi"), ), name="root"), flip_multi), (UPat(Ops.ASSIGN, src=(UPat(Ops.MULTI, name="dest"), UPat(Ops.MULTI, name="src"))), assign_multi), (UPat(Ops.COPY, src=(UPat(Ops.MULTI, name="multi"), UPat(Ops.DEVICE, name="device"))), copy_multi), (UPat(Ops.ALLREDUCE, src=(UPat(Ops.MULTI, name="multi"), UPat(Ops.DEVICE, name="device")), name="red"), lambda multi,device,red: multi.src[0].allreduce(red.arg, device).multi(axis=multi.axis)), - (UPat((Ops.CAST, Ops.BITCAST, Ops.CONTIGUOUS, Ops.DETACH, Ops.CONTIGUOUS_BACKWARD, Ops.FUSE), + (UPat((Ops.CAST, Ops.BITCAST, Ops.CONTIGUOUS, Ops.DETACH, Ops.CONTIGUOUS_BACKWARD), src=(UPat(Ops.MULTI, name="multi"), ), name="root"), passthrough_multi), ])+replace_allreduce @track_rewrites() -def get_multi_map(big_sink:UOp) -> dict[UOp, UOp]: return graph_rewrite_map(big_sink, multi_pm, name="multi_pm") +def get_multi_map(big_sink:UOp) -> dict[UOp, UOp]: + if getenv("VIZ"): graph_rewrite(big_sink, PatternMatcher([]), name="View Multi AST") + ret = graph_rewrite_map(big_sink, multi_pm, name="multi_pm") + if getenv("VIZ"): graph_rewrite(ret[big_sink], PatternMatcher([]), name="View Post Multi AST") + return ret diff --git a/tinygrad/schedule/rangeify.py b/tinygrad/schedule/rangeify.py index a4b3f28f1b..c4fd7a3a4c 100644 --- a/tinygrad/schedule/rangeify.py +++ b/tinygrad/schedule/rangeify.py @@ -1,22 +1,32 @@ -from typing import Any, cast, Iterator -import functools, operator, itertools from dataclasses import dataclass, field +import itertools from tinygrad.dtype import dtypes, PtrDType, ImageDType, AddrSpace -from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, resolve, GroupOp, RewriteNotReady, _substitute, ssimplify, KernelInfo -from tinygrad.uop.symbolic import sym, symbolic_simple -from tinygrad.helpers import argsort, prod, all_same, pluralize, getenv, RANGEIFY, Context, flatten, dedup, unwrap, all_int, DEBUG, SPLIT_REDUCEOP -from tinygrad.schedule.kernelize import Kernel -from tinygrad.uop.ops import track_rewrites, graph_rewrite, identity_element, sint, AxisType -from tinygrad.codegen.simplify import pm_flatten_range, pm_reduce_unparented +from tinygrad.uop.ops import PatternMatcher, UPat, Ops, UOp, resolve, GroupOp, _substitute, ssimplify, KernelInfo +from tinygrad.uop.ops import track_rewrites, graph_rewrite, identity_element, sint, AxisType, BottomUpGate, Kernel, _remove_all_tags +from tinygrad.uop.symbolic import symbolic +from tinygrad.helpers import argsort, prod, all_same, pluralize, getenv, flatten, dedup, all_int, DEBUG, SPLIT_REDUCEOP, DEBUG_RANGEIFY +from tinygrad.helpers import PCONTIG, partition, get_single_element, unwrap, disable_gc +from tinygrad.codegen.simplify import pm_flatten_range, pm_reduce_simplify from tinygrad.codegen.opt import Opt +from tinygrad.schedule.indexing import run_rangeify, BufferizeOpts, ALWAYS_CONTIGUOUS, IndexingContext, apply_movement_op + +# creation can recurse a lot +import sys +sys.setrecursionlimit(10000) + +# movement op on INDEX as a PatternMatcher +pm_mops = PatternMatcher([ + (UPat(GroupOp.Movement, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), + lambda r,idx: r.src[0].index(*apply_movement_op(r.op, r.src[0].shape, r.marg, idx.src[1:]), dtype=idx.dtype, arg=idx.arg)), + # move movement ops after AFTER + (UPat(GroupOp.Movement, name="r").after(name="a", allow_any_len=True), + lambda r,a: UOp(r.op, r.dtype, (a.replace(src=(r.src[0],)+a.src[1:], tag=None),)+r.src[1:], r.arg, tag=a.tag)), + (UPat(GroupOp.Movement, name="r").end(name="a", allow_any_len=True), lambda r,a: a.replace(src=(r.src[0],)+a.src[1:])), +]) # ***************** # 0. do some cleanup rewrites, mostly copied from the old stuff -ALWAYS_CONTIGUOUS: set[Ops] = {Ops.CONTIGUOUS, Ops.ASSIGN, Ops.COPY, Ops.BUFFER, Ops.BUFFER_VIEW, - Ops.CONST, Ops.BIND, Ops.DEVICE, Ops.MSELECT, Ops.MSTACK, Ops.DEFINE_GLOBAL, - Ops.DEFINE_LOCAL, Ops.DEFINE_REG, Ops.LOAD, Ops.KERNEL} - def find_permutes(a:UOp, b:UOp, assign:UOp): if not (permutes:=[s for s in b.toposort(gate=lambda s:s.op not in ALWAYS_CONTIGUOUS) if s.op in GroupOp.Movement and s.op not in {Ops.RESHAPE, Ops.EXPAND, Ops.PAD, Ops.SHRINK}]): return @@ -32,9 +42,14 @@ def split_reduceop(reduce:UOp, x:UOp): # ~2**10 should be enough if GROUP is used # 256 split maximum should be "negligible reduce" for low prod(reduce.shape), 8 split minimum. # split is moved to the end to provide maximum locality for the second phase reduce. - real_strides = unwrap(x.st).real_strides(ignore_valid=True) + + # get expanded by rangeifying the UOp x + indexed = x.index(*[UOp.range(s, i) if resolve(s>1) else UOp.const(dtypes.index, 0) for i,s in enumerate(x.shape)]) + range_nums = [y.arg[0] for y in indexed.substitute({x.base:UOp(Ops.NOOP)}, extra_pm=pm_mops).ranges] + is_expanded = [i not in range_nums for i in range(len(x.shape))] + if not (split_candidates:=[(i,d) for i in reduce.arg[1] for d in range(min(256,2**getenv("REDUCEOP_SPLIT_SIZE",22)//prod(reduce.shape)),8-1,-1) - if x.shape[i]%d==0 and real_strides[i]!=0]): return None + if x.shape[i]%d==0 and not is_expanded[i]]): return None dim_to_split, divisor = split_candidates[0] splitted_shape = x.shape[:dim_to_split]+(divisor,)+(x.shape[dim_to_split]//divisor,)+x.shape[dim_to_split+1:] splitted = x.reshape(splitted_shape).permute(tuple([d for d in range(len(splitted_shape)) if d!=dim_to_split]+[dim_to_split])) @@ -42,12 +57,18 @@ def split_reduceop(reduce:UOp, x:UOp): # reduce original axes, then split return splitted.r(*reduce.arg).contiguous().r(reduce.arg[0], (len(reduce.shape),)).reshape(reduce.shape).replace(tag=reduce.tag) -earliest_rewrites = PatternMatcher([ +mop_cleanup = PatternMatcher([ + # merge adjacent RESHAPES, safe because they are not tagged + (UPat(Ops.RESHAPE, name="x2").f(Ops.RESHAPE, allow_any_len=True, name="x"), + lambda x,x2: x.replace(src=(x2.src[0], x.src[1])) if x.tag is None and x2.tag is None else None), +]) + +earliest_rewrites = mop_cleanup+PatternMatcher([ # just removing it works... - (UPat((Ops.DETACH, Ops.CONTIGUOUS_BACKWARD, Ops.FUSE), name="x"), lambda x: x.src[0]), + (UPat((Ops.DETACH, Ops.CONTIGUOUS_BACKWARD), name="x"), lambda x: x.src[0]), # remove CONTIGUOUS if the BUFFER is already contiguous - (UPat(Ops.BUFFER).f(Ops.RESHAPE, name="r").f(Ops.CONTIGUOUS, name="c"), lambda r,c: r.replace(tag=c.tag)), + (UPat(Ops.BUFFER).f(Ops.RESHAPE, allow_any_len=True, name="r").f(Ops.CONTIGUOUS, name="c"), lambda r,c: r.replace(tag=c.tag)), # split_reduceop (UPat(Ops.REDUCE_AXIS, name="reduce", src=(UPat.var("x"),)), split_reduceop), @@ -57,6 +78,9 @@ earliest_rewrites = PatternMatcher([ (UPat(Ops.REDUCE_AXIS, name="reduce", src=(UPat.var("x"),)), lambda reduce,x: reduce.const_like(identity_element(reduce.arg[0], reduce.dtype)) if x.size == 0 and reduce.size != 0 else None), + # handle size 0 + (UPat(GroupOp.All-{Ops.SINK}, name="x"), lambda x: x.const_like(0).rtag(x.tag) if x._shape is not None and x.size == 0 else None), + # remove contiguous on movement ops before a copy on disk (UPat(GroupOp.Movement-{Ops.SHRINK, Ops.RESHAPE}, name="x").f(Ops.CONTIGUOUS).f(Ops.COPY, allow_any_len=True, name="copy"), lambda x,copy: copy.replace(src=(x,)+copy.src[1:]) if isinstance(x.device, str) and x.device.startswith("DISK") else None), @@ -65,11 +89,21 @@ earliest_rewrites = PatternMatcher([ lambda x,copy: x.replace(src=(copy.replace(src=(x.src[0],)+copy.src[1:], tag=None),)+x.src[1:], tag=copy.tag) \ if isinstance(x.device, str) and x.device.startswith("DISK") else None), + # ** copy rules ** + + # early fixup const copy + (UPat(Ops.COPY, src=(UPat.var("s"), UPat()), name="c"), lambda c,s: c.const_like(ss.arg) if (ss:=s.base).op is Ops.CONST else None), + # COPY and source size need to match # TODO: expand after copy creates issues with tagging (UPat(Ops.COPY, src=(UPat(GroupOp.Movement, name="r"), UPat(name="d")), name="c"), lambda c,r,d: c.replace(src=(r.contiguous(), d)) if r.size != r.base.size else None), + # copy only to different device + (UPat(Ops.COPY, src=(UPat.var("x"), UPat()), name="copy"), lambda x,copy: x.f(Ops.NOOP, tag=copy.tag) if x.device == copy.device else None), + + # ** assign rules ** + # assign only to buffer, otherwise make it a CONTIGUOUS (UPat(Ops.ASSIGN, src=(UPat(GroupOp.All-{Ops.BUFFER}, name="target"), UPat(name="x")), name="assign"), lambda x,target,assign: x.f(Ops.CONTIGUOUS, tag=assign.tag) if ((t:=target.base).op is not Ops.BUFFER and \ @@ -77,302 +111,6 @@ earliest_rewrites = PatternMatcher([ # realize before assign if input permutes the target buffer (UPat(Ops.ASSIGN, src=(UPat.var("a"), UPat.var("b")), name="assign"), find_permutes), - - # copy only to different device - (UPat(Ops.COPY, src=(UPat.var("x"), UPat()), name="copy"), lambda x,copy: x.f(Ops.NOOP, tag=copy.tag) if x.device == copy.device else None), - - # contiguous/buffer/copy/assign is already contiguous - #(UPat(Ops.CONTIGUOUS, name="root", src=(UPat((Ops.CONTIGUOUS, Ops.BUFFER, Ops.COPY, Ops.ASSIGN)),)), lambda root: root.src[0]), -]) - -# ***************** -# 1. add realize where we have to - -def realize(ctx:dict[UOp, None], tr:UOp) -> None: ctx[tr] = None - -def realize_parents(ctx:dict[UOp, None], rb:UOp) -> None: - for s in rb.src: - if s.base.op not in ALWAYS_CONTIGUOUS: ctx[s] = None - -def realize_assign(ctx:dict[UOp, None], a:UOp) -> None: - if a.src[1].op not in ALWAYS_CONTIGUOUS: ctx[a.src[1]] = None - # if it's a kernel, we don't realize it - if a.src[1].op is not Ops.KERNEL: ctx[a] = None - -do_realize = PatternMatcher([ - # always realize SINK parents - (UPat(Ops.SINK, name="s"), lambda ctx,s: ctx.update((x.base, None) for x in s.src if x.base.op not in ALWAYS_CONTIGUOUS)), - # always realize ASSIGN/COPY/BUFFER_VIEW/CONTIGUOUS - (UPat({Ops.COPY, Ops.BUFFER_VIEW, Ops.CONTIGUOUS}, name="tr"), realize), - # realize parents of COPY, MSELECT, MSTACK - (UPat((Ops.COPY, Ops.MSELECT, Ops.MSTACK), name="rb"), realize_parents), - # realize input to assign (might be optimized out) - (UPat(Ops.ASSIGN, name="a"), realize_assign), -]) - -class WrappedContig: - def __init__(self, x): self.x = x - def __repr__(self): return f"C({self.x})" -add_contiguous = PatternMatcher([(UPat(GroupOp.All, name="x"), lambda ctx,x: x.replace(tag=WrappedContig(x.tag)).realize() if x in ctx else None),]) -remove_contig_tags = PatternMatcher([(UPat(GroupOp.All, name="x"), lambda x: x.replace(tag=x.tag.x) if isinstance(x.tag, WrappedContig) else None)]) - -# ***************** -# 2. mark all children - -@dataclass -class ChildrenContext: children: dict[UOp, list[UOp]]|None = None -def extract_children(ctx:ChildrenContext, x:UOp): - if ctx.children is not None: return - children_map = x.get_children_map() - ctx.children = {} - for k,v in children_map.items(): - non_sink_children = [u for u in v if u.op is not Ops.SINK] - if len(non_sink_children) <= 1: continue - # NOTE: this gate shouldn't be here - if k.op_in_parents(Ops.REDUCE_AXIS) and k.op_in_parents(Ops.BUFFER, Ops.CONTIGUOUS): - ctx.children[k] = non_sink_children - -def mark_children(ctx:ChildrenContext, x:UOp): - assert ctx.children is not None - new_srcs = [(UOp(Ops.CHILD, s.dtype, src=(UOp(Ops.CHILDREN, s.dtype, (s,), arg=len(ctx.children[s])),), - arg=(ctx.children[s].index(x), len(ctx.children[s]))) if s in ctx.children else s) for s in x.src] - return x.replace(src=tuple(new_srcs)) - -pm_children = PatternMatcher([ - (UPat(Ops.SINK, name="x"), extract_children), - (UPat(GroupOp.All-{Ops.CHILD, Ops.CHILDREN, Ops.SINK}, name="x"), mark_children), -]) - -# ***************** -# 3a. rangeify (movement) - -@dataclass -class RangeifyContext: - # block on parent until all children have been seen - seen_children: dict[UOp, dict[int, UOp]] = field(default_factory=dict) - seen_child: dict[UOp, Any] = field(default_factory=dict) - progress: int = 0 - - # create ranges - range_idx: Iterator[int] = field(default_factory=itertools.count) - def new_range(self, s:sint, axistype:AxisType=AxisType.LOOP): - return UOp.range(s, next(self.range_idx), axistype) if resolve(s!=1) else UOp.const(dtypes.index, 0) - -def map_reshape(idx:UOp, r:UOp): - acc = 1 - to_sum = [] - for s,src in list(zip(idx.shape, idx.src[1:]))[::-1]: - to_sum.append(acc*src) - acc *= s - mish = sum(to_sum, start=UOp.const(dtypes.index, 0)) - ret:list[UOp] = [] - for s in r.src[0].shape[::-1]: - ret.append(mish % s) # NOTE: simplify will turn this to CONST - mish //= s - tret = UOp.sink(*ret[::-1]).simplify().src - return r.src[0].index(*tret, dtype=idx.dtype, arg=idx.arg) - -def map_pad(idx:UOp, r:UOp): - ret = list(idx.src[1:]) - bigwhere = UOp.const(dtypes.bool, True) - for i,(sh,(s,e)) in enumerate(zip(r.shape, r.arg)): - if s == 0 and e == 0: continue - where = UOp.const(dtypes.bool, True) - if resolve(e > 0): where = where & (ret[i] < (sh-e)) - if resolve(s > 0): where = where & (ret[i] >= s) - bigwhere = bigwhere & where - with Context(TRACK_MATCH_STATS=0): - ret[i] = graph_rewrite(where.where(ret[i]-s, UOp.invalid()), sym) - # PAD is with 0 - return bigwhere.simplify().where(r.src[0].index(*ret, dtype=idx.dtype, arg=idx.arg), UOp.const(r.dtype, 0)) - -def map_expand(r:UOp, idx:UOp): - new_rngs = [] - ending_ranges = [] - non_ending_ranges = [] - for a,x,y in zip(idx.src[1:], r.src[0].shape, r.shape): - axis_to_range = [u for u in a.toposort() if u.op is Ops.RANGE] - if resolve(x==y, False): - non_ending_ranges.extend(axis_to_range) - new_rngs.append(a) - else: - ending_ranges.extend(axis_to_range) - new_rngs.append(a.const_like(0)) - # if RANGEIFY >= 2, we are aggressive about not ending ranges - if RANGEIFY >= 2: ending_ranges = [x.arg for x in ending_ranges if x not in non_ending_ranges] - # if RANGEIFY=1, if it's ending at all we end it - else: ending_ranges = [x.arg for x in ending_ranges] - if idx.arg is not None: ending_ranges.append(idx.arg) - return r.src[0].index(*new_rngs, arg=min(ending_ranges) if ending_ranges else None) - -pm_mops = PatternMatcher([ - # this is like the definitions of these - (UPat(Ops.SHRINK, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), - lambda r,idx: r.src[0].index(*[a+ss if resolve(ss != 0) else a for a,(ss,_) in zip(idx.src[1:], r.arg)], dtype=idx.dtype, arg=idx.arg)), - (UPat(Ops.PERMUTE, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), - lambda r,idx: r.src[0].index(*[idx.src[1+p] for p in argsort(idx.src[0].arg)], dtype=idx.dtype, arg=idx.arg)), - (UPat(Ops.FLIP, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), - lambda r,idx: r.src[0].index(*[((s-1)-a) if f else a for a,s,f in zip(idx.src[1:], r.shape, r.arg)], dtype=idx.dtype, arg=idx.arg)), - # expand needs to end ranges - (UPat(Ops.EXPAND, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), map_expand), - # reshape does a lot of symbolic stuff - (UPat(Ops.RESHAPE, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), map_reshape), - # pad adds min and max - (UPat(Ops.PAD, name="r").f(Ops.INDEX, allow_any_len=True, name="idx"), map_pad), -]) - -# ***************** -# 3b. rangeify (ops) - -# bufferization can happen in three ways -# 1. there's an explicit REALIZE in the graph -# 2. the ranges from the children don't match and we have to create a buffer (only on children) -# 3. might_end_axis triggers because we should be closing a loop to save compute - -@dataclass(frozen=True) -class BufferizeOpts: - # on AddrSpace.LOCAL, device is the id - device: str|tuple[str, ...]|int|None - addrspace: AddrSpace = AddrSpace.GLOBAL - -def map_partial_realize(ctx:RangeifyContext, x:UOp, idx:UOp): - if x.arg is None: return None # map_contiguous can handle this - # NOTE: all partial contiguous can safely be replaced by full contiguous. we should be able to match old functionality like this - if not (RANGEIFY > 1): return idx.replace(src=(x.replace(arg=None),)+idx.src[1:]) - ranges = [] - new_ranges = [] - passthrough_idx = [] - for i,s in enumerate(x.shape): - if i not in x.arg: - ranges.append(idx.src[1+i]) - continue - passthrough_idx.append(idx.src[1+i]) - ranges.append(ctx.new_range(s)) - new_ranges.append(ranges[-1]) - # TODO: this should be able to be global or local - ret = x.src[0].index(*ranges).bufferize(*[x for x in new_ranges if x.op is not Ops.CONST], - arg=BufferizeOpts(device=None, addrspace=AddrSpace.LOCAL)) - return ret.index(*passthrough_idx) - -def map_realize(ctx:RangeifyContext, x:UOp): - if x.arg is not None: return None - ranges = [ctx.new_range(s) for s in x.shape] - return x.src[0].index(*ranges).bufferize(*x.src[1:], *ranges, arg=BufferizeOpts(device=x.device), tag=x.src[0].tag) - -def map_reduce(ctx:RangeifyContext, idx:UOp, red:UOp): - rngs = list(idx.src[1:]) - new_ranges = [] - for i,s in enumerate(red.src[0].shape): - if i in red.arg[1]: - rngs[i] = ctx.new_range(s, axistype=AxisType.REDUCE) - new_ranges.append(rngs[i]) - return UOp(Ops.REDUCE, red.dtype, src=(red.src[0].index(*rngs),)+tuple(new_ranges), arg=red.arg[0], tag=red.tag) - -def index_child(ctx:RangeifyContext, c:UOp, x:UOp, idx:UOp): - if c not in ctx.seen_children: ctx.seen_children[c] = {} - # wait here until we have seen all the children - if len(ctx.seen_children[c]) != x.arg[1]: - ctx.progress += 1 - if ctx.progress > 10000: raise RuntimeError("children not making progress") - # NOTE: we mark this here - ctx.seen_children[c][x.arg[0]] = idx - raise RewriteNotReady - ctx.progress = 0 - - if c not in ctx.seen_child: - all_rngs = list(zip(*[ch.src[1:] for ch in ctx.seen_children[c].values()])) - out_rngs = [] - end_ranges = [] - idx_ranges = [] - # NOTE: locals aren't working, so we only fully bufferize here (unless RANGEIFY > 1) - rngs_valids = [] - for valid_rngs in all_rngs: - rngs, valids = zip(*[(r.get_idx(), r.get_valid()) for r in valid_rngs]) - # if a range has a 1 src, it's the same as UOp.const(dtypes.index, 0) - same_rngs = [x if x.op is not Ops.RANGE or resolve(x.src[0] != 1) else UOp.const(dtypes.index, 0) for x in rngs] - rngs_valids.append((rngs, valids, all_same(same_rngs))) - all_all_same = all(same_rngs for _,_,same_rngs in rngs_valids) - for i,(rngs,valids,same_rngs) in enumerate(rngs_valids): - # we compare the ranges without their valids - if same_rngs and (all_all_same or RANGEIFY > 1): - # the new valid is the OR of all the children valids - minimum_valid = functools.reduce(operator.or_, valids, UOp.const(dtypes.bool, False)) - out_rngs.append(minimum_valid.where(rngs[0], UOp.invalid()).simplify()) - else: - out_rngs.append(ctx.new_range(c.shape[i])) - end_ranges.append(out_rngs[-1]) - idx_ranges.append(i) - ctx.seen_child[c] = (out_rngs, idx_ranges, end_ranges) - else: - out_rngs, idx_ranges, end_ranges = ctx.seen_child[c] - for i,nr in zip(idx_ranges, end_ranges): out_rngs[i] = nr - # index based on the shared ranges - ret = c.index(*out_rngs) - # if all ranges aren't the same between children, we have to bufferize - if len(idx_ranges) > 0: - if len(idx_ranges) == len(out_rngs): - # this is a global bufferize - ret = ret.bufferize(*end_ranges, arg=BufferizeOpts(device=x.device)) - else: - assert RANGEIFY > 1, "this isn't supported with RANGEIFY=1" - ret = ret.bufferize(*end_ranges, arg=BufferizeOpts(device=None, addrspace=AddrSpace.LOCAL)) - ret = ret.index(*[idx.src[1+i] for i in idx_ranges]) - return ret - -def children_gate(ctx:RangeifyContext, idx:UOp, c:UOp): - if len(ctx.seen_children[c]) != c.arg: raise RuntimeError("all children should have been seen by now") - return idx.replace(src=(idx.src[0].src[0],)+idx.src[1:]) - -def might_end_axis(idx:UOp): - if idx.arg is None: return None - # TODO: write a proper cost function here - if not idx.op_in_parents(Ops.BUFFER, Ops.REALIZE, Ops.BUFFERIZE): return None - if not idx.op_in_parents(Ops.REDUCE_AXIS): return None - to_end_axis = [] - for i,a in enumerate(idx.src[1:]): - # in RANGEIFY=1, always realize - if not (RANGEIFY > 1) or any(x.arg > idx.arg for x in a.toposort() if x.op is Ops.RANGE): - to_end_axis.append(i) - if to_end_axis: return idx.replace(src=(idx.src[0].realize(arg=tuple(to_end_axis)),)+idx.src[1:], arg=None) - return idx.replace(arg=None) - -def unprocessed_index(x:UOp): raise RuntimeError(f"unprocessed index on {x.src[0].op}") - -pm_rangeify = pm_mops+PatternMatcher([ - # sink contigs to kick it off - (UPat(Ops.REALIZE, src=(UPat(),), name="x", allow_any_len=True), map_realize), - # if there's an INDEX it can support partial contig - (UPat(Ops.INDEX, src=(UPat(Ops.REALIZE, src=(UPat(),), name="x"),), allow_any_len=True, name="idx"), map_partial_realize), - - # if there are new ended children, tag the SINK - (UPat(Ops.INDEX, src=(UPat(Ops.CHILD, src=(UPat(name="c"), ), name="x"),), allow_any_len=True, name="idx"), index_child), - (UPat(Ops.INDEX, src=(UPat(Ops.CHILDREN, name="c"),), allow_any_len=True, name="idx"), children_gate), - - # if we come across this, remove it. it was a CHILD unused in an INDEX - (UPat(Ops.CHILD, src=(UPat(Ops.CHILDREN, src=(UPat.var("x"),)),)), lambda x: x), - - # CONST (or DEFINE_VAR) can't have axes. remove INDEX when we get here - (UPat(Ops.INDEX, src=(UPat((Ops.CONST, Ops.DEFINE_VAR), name="c"),)), lambda c: c.replace(src=())), - - # handle arg on any op with weight. old endrange stuff - (UPat(Ops.INDEX, src=(UPat(GroupOp.Elementwise.union({Ops.REDUCE_AXIS})),), allow_any_len=True, name="idx"), might_end_axis), - - # handle size 0 - (UPat(Ops.INDEX, name="x"), lambda x: x.replace(src=(x.const_like(0),)+x.src[1:]) if x.st is not None and x.size == 0 else None), - - # handle assign - (UPat(Ops.INDEX, src=(UPat(Ops.ASSIGN, name="assign"),), allow_any_len=True, name="x"), - lambda x,assign: assign.replace(src=tuple([s.index(*x.src[1:]) for s in assign.src])+(assign.src[0],)) \ - if assign.src[1].op is not Ops.KERNEL else None), - - # move MAP through elementwise ALU / reduce. these are the items with cost - (UPat(Ops.INDEX, src=(UPat(GroupOp.Elementwise.union( - {Ops.STORE, Ops.COPY, Ops.BUFFER_VIEW, Ops.DEVICE, Ops.BIND, Ops.CONTIGUOUS, Ops.NOOP})),), allow_any_len=True, name="x"), - lambda x: x.src[0].replace(src=tuple([s.index(*x.src[1:]) for s in x.src[0].src]))), - (UPat(Ops.INDEX, src=(UPat(Ops.REDUCE_AXIS, name="red"),), allow_any_len=True, name="idx"), map_reduce), - - # assert if there's any index we didn't process - (UPat(GroupOp.All-{Ops.REALIZE, Ops.BUFFERIZE, Ops.MSELECT}).f(Ops.INDEX, name="x"), unprocessed_index), ]) # ***************** @@ -393,7 +131,7 @@ def cleanup_dead_axes(b:UOp): # skip for symbolic. TODO: fix this if rng.op is Ops.RANGE and rng.src[0].op is not Ops.CONST: return None # CONSTs are already dead axes - if rng.op is Ops.CONST or (rng.op is Ops.RANGE and rng not in b.src[0].sparents): + if rng.op is Ops.CONST or (rng.op is Ops.RANGE and rng not in b.src[0].ranges): reshape.append(1) hit = True else: @@ -403,11 +141,14 @@ def cleanup_dead_axes(b:UOp): # move the tag to the expand. NOTE: this expand tag might not survive return b.replace(src=b.src[0:1]+tuple(new_rng), tag=None).reshape(tuple(reshape)).expand(b.shape).replace(tag=b.tag) +def gate_substitute(ctx, b:UOp) -> None: + if not any(r in b.ranges for r in ctx.keys()): raise BottomUpGate() +pm_gate_substitute = PatternMatcher([(UPat(GroupOp.All, name="b"), gate_substitute)], compiled=False) # if a buffer is being stored just for permutes or something, remove it # we want to reexpress the indexes of idx2 in terms of the implied b1 def remove_bufferize(src:UOp, buf:UOp, idx:UOp): # see if we can't do it, should this ever hit? - assert len(buf.src) == len(idx.src), "index on wrong bufferize" + assert len(buf.src) == len(idx.src), f"index on wrong bufferize, {len(buf.src)} != {len(idx.src)}" assert all(x.op in {Ops.RANGE, Ops.CONST} for x in buf.src[1:]) # if it's user contiguous, we never remove it @@ -418,65 +159,106 @@ def remove_bufferize(src:UOp, buf:UOp, idx:UOp): # *** here is where we compute the cost *** # if we return None, the bufferize is kept - accessed_buffers = [] + accessed_buffers: list[UOp] = [] + indexes: list[UOp] = [] + reduces: list[UOp] = [] def red_gate(x:UOp): - if x.op is Ops.INDEX: + if x.op is Ops.BUFFERIZE and x.arg.addrspace == AddrSpace.GLOBAL: accessed_buffers.append(x) return False + if x.op is Ops.BUFFER: + accessed_buffers.append(x) + if x.op is Ops.INDEX: + indexes.append(x) + if x.op is Ops.REDUCE: reduces.append(x) return True - ran = src.toposort(gate=red_gate) + src.toposort(gate=red_gate) + del red_gate + accessed_buffers = dedup(accessed_buffers) # if this is generated from multiple buffers, don't remove this buffer - if len(dedup([x.src[0] for x in accessed_buffers])) > 2: return None + if len(accessed_buffers) > 2 and not (PCONTIG > 2): return None - # const reduce is okay - # TODO: move the reduce folder to before this to prevent the need for this - def okay_reduce(x:UOp): return all(y.op not in {Ops.BUFFER, Ops.BUFFERIZE, Ops.COPY} for y in x.sparents) - - # always run this list of ops - if any(x.op is Ops.REDUCE and not okay_reduce(x) for x in ran): return None + # if any reduces access a buffer, don't remove this buffer + buffer_in_reduce = False + def buf_gate(x:UOp): + nonlocal buffer_in_reduce + if x.op in {Ops.BUFFER, Ops.BUFFERIZE}: buffer_in_reduce = True + return not buffer_in_reduce + UOp.sink(*[x.src[0] for x in reduces]).toposort(gate=buf_gate) + del buf_gate + if buffer_in_reduce: + if PCONTIG > 2: + out_in_ratio = (prod(buf.shape)+1) / (sum([x.size for x in accessed_buffers])+1) + if out_in_ratio < 10: return None + # here we have to check the indexes, we might do a partial contig here + local_indexes = [x for x in indexes if x.src[0].op is Ops.BUFFERIZE and x.src[0].arg.addrspace == AddrSpace.LOCAL] + exclude_ranges = UOp.group(*[UOp.group(*x.src[1:]) for x in local_indexes]).ranges + subs = [(k,v) for k,v in zip(buf.src[1:], idx.src[1:]) if k.op is not Ops.CONST] + # if it's bufferized or a reduce, it's pcontig + is_pcontig, is_subs = partition(subs, lambda x: x[0] in exclude_ranges or any([r.arg[-1] == AxisType.REDUCE for r in x[1].ranges])) + if not len(is_subs): + return None + if len(is_pcontig): + ret = src.substitute(dict(is_subs), extra_pm=pm_gate_substitute) + return ret.bufferize(*[x[0] for x in is_pcontig], arg=BufferizeOpts(None, AddrSpace.LOCAL)).index(*[x[1] for x in is_pcontig]) + else: + return None # if it makes it here, the bufferize is removed # this is the ranges replaced # NOTE: if buf src is a const, we don't replace it - replaces = flatten([(k,v) for k,v in zip(buf.src[1:], idx.src[1:]) if k.op is not Ops.CONST]) - return UOp(Ops.SUBSTITUTE, src=(src, UOp(Ops.NOOP, src=tuple(replaces[0::2])), UOp(Ops.NOOP, src=tuple(replaces[1::2])))) + return src.substitute({k:v for k,v in zip(buf.src[1:], idx.src[1:]) if k.op is not Ops.CONST}, extra_pm=pm_gate_substitute) -def pre_bufferize(b:UOp, x:UOp, copy:UOp): - nb = b.replace(src=(b.src[0].contiguous(),)+b.src[1:]) - return copy.replace(src=(x.replace(src=(nb,)+x.src[1:]), copy.src[1])) +def remove_noop_bufferize(idx,b2): + if idx.src[1:] != b2.src[1:] or idx.src[0].op is Ops.BUFFER_VIEW: return None + new_tag = (idx.src[0].tag or ()) + (b2.tag or ()) or None + return idx.src[0].rtag(new_tag).shrink(tuple((0, s) for s in b2.shape)) if b2.shape else idx.src[0].rtag(new_tag) -pm_cleanups = pm_mops+PatternMatcher([ +pm_const_buffer_folding = pm_mops+PatternMatcher([ (UPat(Ops.BUFFERIZE, name="b"), cleanup_dead_axes), (UPat(GroupOp.All-{Ops.BUFFERIZE, Ops.BUFFER}, name="x"), lambda x: x.replace(dtype=x.dtype.base) if isinstance(x.dtype, ImageDType) else None), (UPat((Ops.BUFFERIZE), name="x"), lambda x: x.replace(dtype=x.dtype.base) if isinstance(x.dtype, ImageDType) and (resolve(prod(x.dtype.shape)!=prod(x.shape)) or x.shape[-1]%4!=0) else None), # remove noop buffers. if we look at the next index we can remove even more of these - # NOTE: this is mostly the same case as below, but if there's no INDEX this gets more - (UPat(Ops.INDEX, name="idx").f(Ops.BUFFERIZE, allow_any_len=True, name="b2"), - lambda idx,b2: idx.src[0].replace(tag=nt if len(nt:=(idx.src[0].tag or ()) + (b2.tag or ())) else None) if idx.src[1:] == b2.src[1:] \ - and idx.src[0].op is not Ops.BUFFER_VIEW else None), - # remove reindexing with cost function - (UPat.var("src").f(Ops.BUFFERIZE, allow_any_len=True, name="buf").f(Ops.INDEX, allow_any_len=True, name="idx"), remove_bufferize), + (UPat(Ops.INDEX, name="idx").f(Ops.BUFFERIZE, allow_any_len=True, name="b2"), remove_noop_bufferize), + # dont bufferize an arange + (UPat.any((r:=UPat(dtype=dtypes.index).cast()).named("src"), r.eq(UPat()).named("src")).f(Ops.BUFFERIZE, + allow_any_len=True, name="buf").f(Ops.INDEX, allow_any_len=True, name="idx"), remove_bufferize), # no buffers for const (UPat(Ops.CONST, name='c').f(Ops.BUFFERIZE, allow_any_len=True, name="b"), lambda c,b: b.const_like(c.arg).rtag(b.tag)), + # indexing a const is a const + (UPat(Ops.INDEX, src=(UPat(Ops.CONST, name="c"),),), lambda c: c), # copy on CONST is CONST (UPat(Ops.COPY, src=(UPat.cvar("x"), UPat()), name="copy"), lambda copy,x: copy.const_like(x.arg)), - (UPat(Ops.COPY, src=(UPat(GroupOp.All-{Ops.CONTIGUOUS, Ops.COPY}).f(Ops.BUFFERIZE, allow_any_len=True, name="b") - .f(Ops.INDEX, allow_any_len=True, name="x"), UPat()), name="copy"), pre_bufferize), + # hack if a noop turned to a const + (UPat.cvar("c").f(Ops.NOOP).f(Ops.BUFFERIZE, allow_any_len=True, name="buf"), lambda c,buf: buf.replace(src=(c,)+buf.src[1:])), # mstack on CONST is CONST (UPat(Ops.MSTACK, src=(UPat.var("s"),), allow_any_len=True).f(Ops.INDEX, allow_any_len=True), lambda s: UOp.const(c.dtype, c.arg) if (c:=s.base).op is Ops.CONST else None), ]) +def pre_bufferize(b:UOp, x:UOp, copy:UOp): + nb = b.replace(src=(b.src[0].contiguous(),)+b.src[1:]) + return copy.replace(src=(x.replace(src=(nb,)+x.src[1:]), copy.src[1])) +pm_remove_bufferize = PatternMatcher([ + # hack so remove_bufferize doesnt remove the buffer before a copy + (UPat(Ops.COPY, src=(UPat(GroupOp.All-{Ops.CONTIGUOUS, Ops.COPY}).f(Ops.BUFFERIZE, allow_any_len=True, name="b") + .f(Ops.INDEX, allow_any_len=True, name="x"), UPat()), name="copy"), pre_bufferize), + # remove reindexing with cost function + (UPat.var("src").f(Ops.BUFFERIZE, allow_any_len=True, name="buf").f(Ops.INDEX, allow_any_len=True, name="idx"), remove_bufferize), +]) + def late_buffer_view(t:UOp, b:UOp): - if isinstance(b.device, str) and b.device.startswith("DISK"): - rngs = b.src[1:] - size = prod(shape := [int(r.vmax+1) for r in rngs]) + if isinstance(b.device, str) and (b.device.startswith("DISK") or b.device.startswith("TINYFS")): + shape = b.shape + size = prod(shape) # walk up for the INDEX x = t - while not any(u.op is Ops.INDEX for u in x.src): x = x.src[0] + while not any(u.op is Ops.INDEX for u in x.src): + assert x.op not in GroupOp.Elementwise, "can't buffer view elementwise" + x = x.src[0] x = next(u for u in x.src if u.op is Ops.INDEX) if len(shape) == 0: offset = x.src[1].arg @@ -490,7 +272,7 @@ to_bufferview = PatternMatcher([ ]) DEVICE_MAX_BUFS = {"METAL": 31, "WEBGPU": 8} # TODO: get from device? -def limit_bufs(ctx:RangeifyContext, root:UOp): +def limit_bufs(ctx:IndexingContext, root:UOp): if (device:=root._device) is None: return None # no device, index related calculations device = device if isinstance(device, str) else device[0].split(":")[0] if not (MAX_BUFS:=getenv("MAX_KERNEL_BUFFERS", DEVICE_MAX_BUFS.get(device, 0))): return None @@ -498,7 +280,7 @@ def limit_bufs(ctx:RangeifyContext, root:UOp): bufs: set[UOp] = set() def gate_input(u:UOp): # TODO: add cache to fix n^2 - if is_load:=(u.op in {Ops.BUFFERIZE, Ops.ASSIGN, Ops.BUFFER, Ops.MSELECT, Ops.MSTACK, Ops.DEFINE_VAR}): bufs.add(u) + if is_load:=(u.op in {Ops.BUFFERIZE, Ops.AFTER, Ops.BUFFER, Ops.MSELECT, Ops.MSTACK, Ops.DEFINE_VAR}): bufs.add(u) return not is_load root.toposort(gate=gate_input) @@ -521,11 +303,11 @@ pm_limit_bufs = PatternMatcher([(UPat(set.union(GroupOp.Binary, GroupOp.Ternary) # BUFFERIZE returns the BUFFER ready for INDEXing (doing this will make splitting a lot easier) # NOTE: this has been fixed up a bit -def bufferize_to_store(x:UOp): - rngs = x.src[1:] - shape = tuple([int(r.vmax+1) for r in rngs]) - size = prod(shape) - assert size > 0, f"no zero sized buffers {shape}" +def bufferize_to_store(ctx:itertools.count|None, x:UOp, idx:UOp, allow_locals=True): + #assert isinstance(x.tag, Flat), "bufferize must be flat" + size = prod(x.shape) + rngs = sorted(idx.ranges, key=lambda x: x.arg) + assert size > 0 and isinstance(size, int), f"no zero sized or symbolic sized buffers {size}" sdtype = x.dtype.ptr(size=size, addrspace=x.arg.addrspace) if x.src[0].op is Ops.ASSIGN: @@ -533,40 +315,53 @@ def bufferize_to_store(x:UOp): assert assign_target.op is Ops.INDEX, f"{assign_target.op} is not index" # in assign, this is the buffer size, not the bufferize size # TODO: assign_mops here - ret = assign_target.replace(dtype=sdtype).store(assign_src, *rngs, dtype=x.dtype) + do_store = assign_target.replace(dtype=sdtype).store(assign_src, tag=x.tag).end(*rngs) + ret = assign_target.src[0].after(do_store) mops = [] walk = assign_mops while walk is not assign_mops.base: - mops.append((walk.op, walk.arg)) + mops.append((walk.op, walk.marg)) walk = walk.src[0] for m in mops[::-1]: ret = ret._mop(*m) - return ret.forced_reshape(shape).replace(tag=x.tag) + return ret # NOTE: the DEFINE_LOCAL needs to be disambiguated here if sdtype.addrspace == AddrSpace.GLOBAL: buf = UOp.new_buffer(x.arg.device, size, x.dtype) - ret = buf.reshape(shape).index(*rngs, dtype=sdtype).store(x.src[0], *rngs, dtype=x.dtype) - ret = ret.forced_reshape(shape) - # TODO: is this right? what if it's offset - if any(r.op is Ops.RANGE and r.src[0].op is not Ops.CONST for r in rngs): - sym_shape = tuple([ssimplify(r.src[0]) if r.op is not Ops.CONST else 1 for r in rngs]) - ret = ret.shrink(tuple([(0,x) for x in sym_shape])) - return ret.replace(tag=x.tag) + do_store = buf.index(idx, dtype=sdtype).store(x.src[0], tag=x.tag).end(*rngs) + return buf.after(do_store) - # handle locals - tag = x.arg.device - if tag is None: tag = UOp.unique().arg # TODO: hack - buf = UOp(Ops.DEFINE_LOCAL, sdtype, arg=tag) - # store has the other dtype here - # TODO: how is this unified? - return buf.reshape(shape).index(*rngs, dtype=sdtype).store(x.src[0], *rngs, dtype=sdtype).forced_reshape(shape, dtype=x.dtype) + if allow_locals: + # handle locals + buf = UOp(Ops.DEFINE_LOCAL, sdtype, arg=next(unwrap(ctx))) + do_store = buf.broadcast(x.src[1].dtype.count).index(idx, dtype=sdtype).store(x.src[0]).end(*rngs) + return buf.after(do_store.barrier()) -pm_add_buffers = pm_mops+to_bufferview+PatternMatcher([ - (UPat(Ops.BUFFERIZE, name="x"), bufferize_to_store), +# collapse any BUFFERIZE to single input BUFFERIZE. move the tag to a reshape +def flatten_bufferize(x:UOp): + if x.tag is None and len(x.src) == 2: return None + ret = x.replace(tag=None, src=(x.src[0], get_single_element(apply_movement_op(Ops.RESHAPE, (prod(x.shape),), x.shape, x.src[1:])))) + rngs = x.src[1:] + ret = ret.forced_reshape(x.shape) + if any(r.op is Ops.RANGE and r.src[0].op is not Ops.CONST for r in rngs): + sym_shape = tuple([ssimplify(r.src[0]) if r.op is not Ops.CONST else 1 for r in rngs]) + ret = ret.shrink(tuple([(0,x) for x in sym_shape])) + return ret.rtag(x.tag) +pm_flatten_bufferize = PatternMatcher([(UPat(Ops.BUFFERIZE, name="x"), flatten_bufferize)]) + +pm_add_buffers = pm_mops+pm_flatten_bufferize+to_bufferview+PatternMatcher([ + (UPat(Ops.BUFFERIZE, src=(UPat(), UPat(name="idx")), name="x"), lambda x, idx: bufferize_to_store(None, x, idx, allow_locals=False)), # move RESHAPEs through MSELECT/MSTACK (UPat((Ops.MSELECT, Ops.MSTACK), src=UPat(Ops.RESHAPE), name="m"), - lambda m: m.replace(src=tuple([x.src[0] for x in m.src]), tag=None).reshape(m.src[0].arg).rtag(m.tag)), + lambda m: m.replace(src=tuple([x.src[0].base for x in m.src]), tag=None).reshape(m.shape).rtag(m.tag)), + + # remove any RESHAPEs on KERNEL + (UPat(Ops.KERNEL, name="k"), lambda k: k.replace(src=tuple(x.src[0] if x.op is Ops.RESHAPE else x for x in k.src))), +]) + +pm_add_buffers_local = pm_mops+pm_flatten_bufferize+to_bufferview+PatternMatcher([ + (UPat(Ops.BUFFERIZE, src=(UPat(), UPat(name="idx")), name="x"), bufferize_to_store), ]) # ***************** @@ -591,22 +386,23 @@ def unbind_kernel(ctx:LocalAddBufferContext, b:UOp): ctx.vars[b] = None return b.src[0] -def handle_assign(ctx:LocalAddBufferContext, assign:UOp): - buf = assign.as_buf() +def handle_after(ctx:LocalAddBufferContext, after:UOp): + if isinstance(after.dtype, PtrDType) and after.ptrdtype.addrspace == AddrSpace.LOCAL: return None + buf = after.as_buf() # HACK to put the buffer in the MAP instead of MSTACK/MSELECT if buf.op in {Ops.MSTACK, Ops.MSELECT}: buf = buf.src[0] assert buf not in ctx.map - ctx.map[buf] = assign + ctx.map[buf] = after return buf def renumber_range(ctx:LocalAddBufferContext, r:UOp): - if r.tag is not None: return None - ret = r.replace(arg=(ctx.range,)+r.arg[1:], tag=()) + if r.tag != (): return None + ret = r.replace(arg=(ctx.range,)+r.arg[1:], tag=None) ctx.range += 1 return ret def find_bufs(x:UOp): - idxs = [s for s in x.toposort(gate=lambda x: x.op is not Ops.ASSIGN) if s.op is Ops.INDEX] + idxs = [s for s in x.toposort(gate=lambda x: x.op is not Ops.AFTER) if s.op is Ops.INDEX] read_from: dict[UOp, Ops] = {} if any((buf:=idx.as_buf()).op is Ops.BUFFER and read_from.setdefault(buf, op:=idx.src[0].op) is not op for idx in idxs): raise RuntimeError(f"cycle detected while indexing {buf}") @@ -615,7 +411,7 @@ to_define_global = PatternMatcher([ (UPat(Ops.STORE, name="x"), find_bufs), (UPat(Ops.BUFFER, name="buf"), debuf), (UPat(Ops.BIND, name="b"), unbind_kernel), - (UPat((Ops.ASSIGN, Ops.MSTACK, Ops.MSELECT), name="assign"), handle_assign), + (UPat((Ops.MSTACK, Ops.MSELECT, Ops.AFTER), name="after"), handle_after), # HACK in case any CONSTs were replaced # this is only needed if you are using symbolic @@ -644,31 +440,36 @@ rangeify_codegen = PatternMatcher([ # add loads to non ptr indexes # TODO: this can be moved into codegen? - (UPat((Ops.DEFINE_GLOBAL, Ops.STORE), name="dg").f(Ops.INDEX, name="idx", allow_any_len=True), - lambda dg,idx: None if isinstance(idx.dtype, (PtrDType, ImageDType)) else idx.replace(dtype=dg.dtype, arg=None).load()), + #(UPat.any(UPat(Ops.DEFINE_GLOBAL, name="dg"), UPat(Ops.DEFINE_LOCAL).f(Ops.AFTER, allow_any_len=True, name="dg")) + # .f(Ops.INDEX, name="idx", allow_any_len=True), + # lambda dg,idx: None if isinstance(idx.dtype, (PtrDType, ImageDType)) else idx.replace(dtype=dg.dtype, arg=None).load()), - # TODO: this can be moved into codegen - (UPat(Ops.STORE, name="store").f(Ops.INDEX, allow_any_len=True, name="idx").f(Ops.LOAD), - lambda store,idx: idx.replace(src=(store.as_buf(),)+idx.src[1:]).load(store if idx.dtype.addrspace != AddrSpace.LOCAL else store.barrier())), - - # TODO: hack for group for reduce - (UPat(Ops.IF, src=(UPat.var("gate"), UPat(Ops.LOAD, src=(UPat.var("src"), UPat.var("barrier"))),)), - lambda src, barrier, gate: src.load(UOp(Ops.IF, src=(gate, barrier)))), + # fix broadcast dtype + (UPat(Ops.AFTER, name="a").broadcast(name="b"), lambda a,b: a.broadcast(len(b.src))), + (UPat(Ops.DEFINE_LOCAL).f(Ops.AFTER, allow_any_len=True).broadcast(name="dg").f(Ops.INDEX, name="idx", allow_any_len=True), + lambda dg,idx: None if isinstance(idx.dtype, (PtrDType, ImageDType)) else + idx.replace(dtype=dg.dtype, arg=None).load(dtype=dg.dtype.base.scalar().vec(dg.dtype.vcount))), + (UPat(Ops.AFTER, name="a").gep(name="b"), lambda a,b: a.gep(b.arg)), + (UPat(Ops.DEFINE_LOCAL).f(Ops.AFTER, allow_any_len=True).gep(name="dg").f(Ops.INDEX, name="idx", allow_any_len=True), + lambda dg,idx: None if isinstance(idx.dtype, (PtrDType, ImageDType)) else + idx.replace(dtype=dg.dtype, arg=None).load(dtype=dg.dtype.base.scalar().vec(dg.dtype.vcount))), ]) def remove_metadata_tags(ctx:LocalAddBufferContext, x:UOp): if x.tag is None or x.tag == (): return None - ctx.parent_tags += list(x.tag) + if isinstance(x.tag, tuple): ctx.parent_tags += list(x.tag) return x.replace(tag=None) pm_remove_tags = PatternMatcher([ - # remove all the tags (UPat(GroupOp.All, name="x"), remove_metadata_tags), ]) -def split_store(ctx:list[UOp], x:UOp): +pm_add_range_tags = PatternMatcher([ + (UPat(Ops.RANGE, name="x"), lambda x: x.rtag(())), +]) + +def split_store(ctx:list[UOp], x:UOp) -> UOp|None: if len(x.ranges): return None - if x.src[0].ptrdtype.addrspace is AddrSpace.LOCAL: return None # local kernel rewrite lctx = LocalAddBufferContext() @@ -678,24 +479,33 @@ def split_store(ctx:list[UOp], x:UOp): metadatas = [ctx[y].metadata for y in lctx.parent_tags] # NOTE: the hack for COPY is here - ret = ret.sink(arg=KernelInfo(opts_to_apply=lctx.opts) if lctx.opts is not None else None) \ - if ret.src[1].op not in {Ops.COPY, Ops.BUFFER_VIEW} else ret.src[1] + for u in ret.toposort(): + # TODO: this can be wrong if there's multiple of these + if u.op in {Ops.COPY, Ops.BUFFER_VIEW}: + ret = u + break + else: + ret = ret.sink(arg=KernelInfo(opts_to_apply=lctx.opts) if lctx.opts is not None else None) + kernel_arg = Kernel(ret,tuple(dedup(flatten([x for x in metadatas if x is not None])))[::-1]) kernel = UOp(Ops.KERNEL, src=tuple(lctx.map.values())+tuple(lctx.vars.keys()), arg=kernel_arg) - return x.as_buf().assign(kernel) + if ret.op is Ops.SINK and not all_same([x.device for x in kernel.src if x.op is not Ops.BIND]): + raise RuntimeError(f"all buffers must be on the same device: {tuple(b.buf_uop.buffer for b in kernel.src)}") + return kernel split_kernels = PatternMatcher([ - (UPat(Ops.STORE, name="x"), split_store), + (UPat((Ops.STORE, Ops.END), name="x"), split_store), ]) def tag_uop(ctx:list[UOp], x:UOp): if x.tag is not None: return None + if x.dtype.scalar() == dtypes.index: return None ctx.append(x) return x.replace(tag=(len(ctx)-1,)) add_tags = PatternMatcher([ # don't tag BUFFERs, they are global - (UPat(GroupOp.All-{Ops.BUFFER, Ops.CONST, Ops.DEVICE, Ops.UNIQUE, Ops.DEFINE_VAR, Ops.BIND, - Ops.MSTACK, Ops.MSELECT}.union(GroupOp.Movement), name="x"), tag_uop), + (UPat(GroupOp.All-{Ops.BUFFER, Ops.CONST, Ops.DEVICE, Ops.UNIQUE, Ops.DEFINE_VAR, Ops.BIND, Ops.KERNEL, + Ops.MSTACK, Ops.MSELECT, Ops.RANGE}.union(GroupOp.Movement), name="x"), tag_uop), (UPat({Ops.MSTACK, Ops.MSELECT}, name="x"), lambda ctx,x: None if all(s.op is Ops.BUFFER for s in x.src) else tag_uop(ctx, x)), ]) @@ -705,7 +515,7 @@ add_tags = PatternMatcher([ def found_contiguous(ctx:dict[UOp, UOp], contig:UOp, src:UOp): x = src while x is not src.base: - if x.op is Ops.PERMUTE: contig = contig.permute(argsort(x.arg)) + if x.op is Ops.PERMUTE: contig = contig.permute(argsort(x.marg)) elif x.op is Ops.RESHAPE: contig = contig.reshape(x.src[0].shape) else: return None x = x.src[0] @@ -715,75 +525,59 @@ replace_contiguous = PatternMatcher([ (UPat(GroupOp.ALU, name="alu"), lambda ctx,alu: alu.replace(src=new_src) if (new_src:=tuple(ctx.get(s, s) for s in alu.src)) != alu.src else None), ]) -def do_sub_recurse(s:UOp): - x,keys,values = s.src[0], s.src[1].src, s.src[2].src - # SUBSTITUTE applied to SUBSTITUTE runs the child SUB on the parents. though this is probably wrong in the generic case - if x.op is Ops.SUBSTITUTE: - sub_k = UOp(Ops.SUBSTITUTE, src=(x.src[1],)+s.src[1:]) - sub_v = UOp(Ops.SUBSTITUTE, src=(x.src[2],)+s.src[1:]) - return UOp(Ops.SUBSTITUTE, src=(x.src[0], sub_k, sub_v)) - # here we actually do the SUBSTITUTE - if x in keys: return values[keys.index(x)] - # we filter any keys that aren't in parents. this keeps the algorithm O(output graph size) - new_kv = {k:v for k,v in zip(keys,values) if k in x.sparents} - # if there's no SUBSTITUTEs left, we can just return x - if len(new_kv) == 0: return x - # then we add SUBSTITUTE to all parents - uop_keys, uop_values = UOp(Ops.NOOP, src=tuple(new_kv.keys())), UOp(Ops.NOOP, src=tuple(new_kv.values())) - return x.replace(src=tuple([UOp(Ops.SUBSTITUTE, src=(y,uop_keys,uop_values)) for y in x.src])) -pm_substitute_recurse = PatternMatcher([(UPat(Ops.SUBSTITUTE, src=(UPat(), UPat(Ops.NOOP), UPat(Ops.NOOP)), name="s"), do_sub_recurse)]) - +@disable_gc() @track_rewrites(lambda _,ret: f"Schedule {pluralize('Kernel', len([u for u in UOp.sink(*ret.values()).toposort() if u.op is Ops.KERNEL]))}", True) def get_rangeify_map(sink:UOp) -> dict[UOp, UOp]: + if getenv("VIZ"): graph_rewrite(sink, PatternMatcher([]), name="View Input Graph") uop_list: list[UOp] = [] tsink = graph_rewrite(sink, add_tags, ctx=uop_list, bottom_up=True, name="number the uops") - tsink = graph_rewrite(tsink, earliest_rewrites+replace_contiguous, ctx={}, name="earliest rewrites") - realize_map: dict[UOp, UOp] = {} - graph_rewrite(tsink, do_realize, ctx=realize_map, name="Input Graph") - # NOTE: we don't use contiguous here, contiguous is a user op - tsink = graph_rewrite(tsink, add_contiguous, ctx=realize_map, bottom_up=True, name="add realize") - tsink = graph_rewrite(tsink, remove_contig_tags, name="remove contiguous tags") - tsink = graph_rewrite(tsink, pm_children, ctx=ChildrenContext(), bottom_up=True, name="get children") + tsink = graph_rewrite(tsink, pm_mops+earliest_rewrites+replace_contiguous, ctx={}, name="earliest rewrites") - # rangeify - tsink = graph_rewrite(tsink, pm_rangeify, ctx=(rangeify_ctx:=RangeifyContext()), bottom_up=True, name="rangeify") - # NOTE: sym (vs symbolic_simple) breaks things here because ranges with len 1 aren't handled right - tsink = graph_rewrite(tsink, symbolic_simple+pm_reduce_unparented, name="symbolic") # this supports const folding - tsink = graph_rewrite(tsink, pm_cleanups+pm_substitute_recurse, bottom_up=True, name="remove costly buffers") - tsink = graph_rewrite(tsink, pm_limit_bufs, ctx=rangeify_ctx, name="limit buffers") + # convert movement ops to ranges + tsink, rctx = run_rangeify(tsink, DEBUG_RANGEIFY) + + tsink = graph_rewrite(tsink, symbolic+pm_reduce_simplify+pm_const_buffer_folding, name="symbolic+reduce_collapse") # this does const folding + tsink = graph_rewrite(tsink, pm_remove_bufferize, bottom_up=True, name="remove bufferize with cost function") + tsink = graph_rewrite(tsink, symbolic+pm_reduce_simplify+pm_const_buffer_folding, name="symbolic+reduce_collapse pt 2") + tsink = graph_rewrite(tsink, pm_limit_bufs, ctx=rctx, name="limit buffers") # rebuild the sink with all the BUFFERIZEs with tags, this is what's ending up in the tensor graph # MSTACK stacks multiple BUFFERIZEs in one tagged tensor # if it's not tagged by here, it's out - tsink = UOp.sink(*[x for x in tsink.parents if x.base.op in {Ops.BUFFERIZE, Ops.MSTACK, Ops.CONST, Ops.BUFFER} and x.tag is not None]) + tsink = UOp.sink(*[x for x in tsink.backward_slice if x.base.op in {Ops.BUFFERIZE, Ops.MSTACK, Ops.CONST, Ops.BUFFER, Ops.AFTER} and \ + x.tag is not None and len(x.tag)]) if getenv("VIZ"): graph_rewrite(tsink, PatternMatcher([]), name="View Tagged Rangeify") # bufferize -> store - tsink = graph_rewrite(tsink, pm_add_buffers, bottom_up=True, name="bufferize to store") + tsink = graph_rewrite(tsink, pm_add_buffers+pm_add_range_tags, bottom_up=True, name="bufferize to store") tsink = graph_rewrite(tsink, split_kernels, ctx=uop_list, name="split kernels") # if a kernel depends on a buffer, and that buffer is later assigned to, make the assign depend on the kernel's assign kernel_assign: dict[UOp, UOp] = {} assign_rep: dict[UOp, UOp] = {} for u in tsink.toposort(): - if u.op is not Ops.ASSIGN: continue + if u.op is not Ops.AFTER: continue kernel_assign[u.buf_uop] = u for s in u.src[1].src: # TODO: this is probably broken for MSELECT/MSTACK if s.op is not Ops.BUFFER or s is u.buf_uop or (a:=kernel_assign.get(s)) is None: continue - if any(x.op is Ops.ASSIGN and x.buf_uop is s for x in u.toposort()): - raise RuntimeError(f"cycle detected in graph, kernel for {u.buf_uop} must either depend on ASSIGN or BUFFER") + if any(x.op is Ops.AFTER and x.buf_uop is s for x in u.toposort()): + raise RuntimeError(f"cycle detected in graph, kernel for {u.buf_uop} must either depend on AFTER or BUFFER") assign_rep[a] = kernel_assign[s] = a.replace(src=a.src+(u,)) if assign_rep: tsink = graph_rewrite(tsink, _substitute, ctx=assign_rep, bottom_up=True, name="fix_assign") if getenv("VIZ"): graph_rewrite(tsink, PatternMatcher([]), name="View Kernel Graph") + # TODO: we can probably get this earlier + sink_tags = [s.tag for s in tsink.src] + tsink = graph_rewrite(tsink, _remove_all_tags, name="remove all tags") + becomes_map: dict[UOp, UOp] = {} - for s in tsink.src: - assert s.tag is not None - for a in s.tag: + for tag, s in zip(sink_tags, tsink.src): + assert tag is not None + for a in tag: if a is None: continue - becomes_map[uop_list[cast(int, a)]] = s.replace(tag=None) + becomes_map[uop_list[int(a)]] = s return becomes_map diff --git a/tinygrad/shape/__init__.py b/tinygrad/shape/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tinygrad/shape/shapetracker.py b/tinygrad/shape/shapetracker.py deleted file mode 100644 index dca69bbe96..0000000000 --- a/tinygrad/shape/shapetracker.py +++ /dev/null @@ -1,112 +0,0 @@ -# ShapeTracker allows movement operations to a buffer that don't require a copy to be made. -from __future__ import annotations -from dataclasses import dataclass -import functools -from typing import Callable -from tinygrad.helpers import merge_dicts, getenv -from tinygrad.shape.view import View, unravel -from tinygrad.uop.symbolic import sym -from tinygrad.uop.ops import UOp, Ops, graph_rewrite, Variable, sint, sint_to_uop, Context - -@functools.cache -def views_to_valid_uop(views: tuple[View, ...], _idxs:tuple[UOp, ...]|None=None) -> UOp: - idx = views[-1].to_valid_uop(_idxs) - for view in reversed(views[0:-1]): - view = view.minify() - idx = view.to_valid_uop([sint_to_uop(i) for i in unravel(view.shape, idx)]) - with Context(TRACK_MATCH_STATS=0): - return graph_rewrite(idx, sym, name="indexing sym @ 1") - -@functools.cache -def views_to_real_strides(views: tuple[View, ...], ignore_valid=False) -> tuple[sint|None, ...]: - # NOTE: if a stride is not always valid, it will be None - if len(views) == 1 and views[-1].mask is None: return views[-1].strides - ret: list[sint|None] = [None] * len(views[-1].shape) - idx, valid = (vidx:=views_to_valid_uop(views)).get_idx(), vidx.get_valid() - for c in idx.split_uop(Ops.ADD): - if c.op is Ops.RANGE: ret[c.arg[0]] = 1 - if c.op is Ops.MUL and c.src[0].op is Ops.RANGE and c.src[1].op is Ops.CONST: ret[c.src[0].arg[0]] = c.src[1].arg - if c.op is Ops.MUL and c.src[1].op is Ops.RANGE and c.src[0].op is Ops.CONST: ret[c.src[1].arg[0]] = c.src[0].arg - used_ranges = [x.arg[0] for x in idx.toposort() if x.op is Ops.RANGE] - ret = [x if i in used_ranges else 0 for i,x in enumerate(ret)] - if not ignore_valid: - for masked_axis in [x.arg[0] for x in valid.toposort() if x.op is Ops.RANGE]: ret[masked_axis] = None - return tuple(ret) - -@dataclass(frozen=True, order=True) -class ShapeTracker: - views: tuple[View, ...] - - def __add__(self, st:ShapeTracker) -> ShapeTracker: - ret = self - for v in st.views: ret = ShapeTracker(ret.views + (v,)).simplify() # one view at a time = better simplification - return ret - - def invert(self, out_shape:tuple[sint, ...]) -> ShapeTracker|None: - inverted_views:list[View] = [] - for v,s in zip(self.views[::-1], [x.shape for x in self.views[::-1][1:]]+[out_shape]): - if (inverted:= v.invert(s)) is None: return None - inverted_views.append(inverted) - return ShapeTracker(tuple(inverted_views)).reshape(out_shape) - - @staticmethod - def from_shape(shape:tuple[sint, ...], strides:tuple[sint, ...]|None=None) -> ShapeTracker: return ShapeTracker((View.create(shape, strides),)) - - @property - def contiguous(self) -> bool: return len(self.views) == 1 and self.views[0].contiguous - - @property - def shape(self) -> tuple[sint, ...]: return self.views[-1].shape - - @property - def size(self) -> int: return self.views[-1].size() - - def reduce(self, axis:tuple[int, ...]) -> tuple[sint, ...]: return tuple(1 if i in axis else s for i,s in enumerate(self.shape)) - - def to_valid_uop(self, _idxs:list[UOp]|tuple[UOp, ...]|None=None) -> UOp: - return views_to_valid_uop(self.views, tuple(_idxs) if _idxs is not None else None) - - # upper bound on buffer size required to fit this shapetracker - def real_size(self) -> int: - if 0 in self.shape: return 0 - view = (v.shrink(v.mask) if (v:=self.views[0]).mask else v) - idx = views_to_valid_uop((view,)).get_idx() - assert idx.vmax < 1e12, f"real_size broken for {self}" - return int(idx.vmax + 1) - - def vars(self) -> set[Variable]: return set().union(*[v.vars() for v in self.views]) - - @property - def var_vals(self) -> dict[str, int]: return merge_dicts([{(vu:=v.unbind())[0].expr:vu[1]} for v in self.vars()]) - - def unbind(self) -> tuple[ShapeTracker, dict[Variable, int]]: - unbound_views, var_vals = zip(*[v.unbind() for v in self.views]) - if all(len(x) == 0 for x in var_vals): return self, {} - return ShapeTracker(tuple(unbound_views)), merge_dicts(var_vals) - def substitute(self, dvars:dict[UOp, UOp]): return ShapeTracker(tuple(x.substitute(dvars) for x in self.views)) - - def real_strides(self, ignore_valid=False) -> tuple[sint|None, ...]: - with Context(TRACK_MATCH_STATS=0): return views_to_real_strides(self.views, ignore_valid) - def unit_stride_axes(self, ignore_valid=False) -> list[int]: return [i for i,st in enumerate(self.real_strides(ignore_valid)) if st == 1] - - def simplify(self) -> ShapeTracker: - if len(self.views) >= 2 and (new_view := self.views[-2] + self.views[-1]) is not None: - return ShapeTracker(self.views[:-2] + (new_view,)).simplify() - return self - - # *** under this line are the movement ops *** - - def pad(self, arg: tuple[tuple[sint, sint], ...]) -> ShapeTracker: return ShapeTracker(self.views[0:-1] + (self.views[-1].pad(arg), )) - def shrink(self, arg: tuple[tuple[sint, sint], ...]) -> ShapeTracker: return ShapeTracker(self.views[0:-1] + (self.views[-1].shrink(arg), )) - def expand(self, new_shape: tuple[sint, ...]) -> ShapeTracker: return ShapeTracker(self.views[0:-1] + (self.views[-1].expand(new_shape), )) - def permute(self, axis: tuple[int, ...]) -> ShapeTracker: return ShapeTracker(self.views[0:-1] + (self.views[-1].permute(axis), )) - def flip(self, mul: tuple[int, ...]) -> ShapeTracker: return ShapeTracker(self.views[0:-1] + (self.views[-1].flip(mul), )) - - def reshape(self, new_shape: tuple[sint, ...]) -> ShapeTracker: - if getenv("MERGE_VIEW", 1) and (new_view := self.views[-1].reshape(new_shape)) is not None: return ShapeTracker(self.views[0:-1] + (new_view,)) - return ShapeTracker(self.views + (View.create(new_shape), )) - - def mop(self, op, arg): return mops[op](self, arg) - -mops: dict[Ops, Callable] = {Ops.RESHAPE: ShapeTracker.reshape, Ops.PERMUTE: ShapeTracker.permute, Ops.EXPAND: ShapeTracker.expand, - Ops.SHRINK: ShapeTracker.shrink, Ops.FLIP: ShapeTracker.flip, Ops.PAD: ShapeTracker.pad} diff --git a/tinygrad/shape/view.py b/tinygrad/shape/view.py deleted file mode 100644 index 37da15642c..0000000000 --- a/tinygrad/shape/view.py +++ /dev/null @@ -1,340 +0,0 @@ -from __future__ import annotations -import functools, operator, itertools -from dataclasses import dataclass -from typing import cast, Sequence -from tinygrad.dtype import dtypes -from tinygrad.uop.ops import resolve, UOp, Variable, sint, smax, smin, sint_to_uop, Ops, ssimplify -from tinygrad.helpers import prod, all_int, argsort, flatten, ceildiv - -# returns the axes to create new_shape if new_shape can be created by combining axis from old_shape -def get_contraction(old_shape:tuple[sint, ...], new_shape:tuple[sint, ...]) -> list[list[int]]|None: - acc_old, acc_new = list(itertools.accumulate(old_shape, operator.mul)), list(itertools.accumulate(new_shape, operator.mul)) - try: split = [acc_old.index(acc)+1 if acc != 1 else 0 for acc in acc_new] - except ValueError: return None - return [list(range(st,ed)) for st,ed in zip([0]+split[:-1], split[:-1]+[len(old_shape)])] - -def get_contraction_with_reduce(old_shape:tuple[sint, ...], new_shape:tuple[sint, ...], reduce_axis:tuple[int, ...]) -> list[list[int]]|None: - if (contraction:=get_contraction(old_shape, new_shape)) is None: return None - # contraction returns the 1s as right justified as possible - # normally this contraction is good, but sometimes the reduce dim is empty. borrow from the next one, leaving one - # this ensures there's always ones available in the reduce dimension. this is also a valid contraction - for i in range(len(contraction)): - if i in reduce_axis and len(contraction[i]) == 0: - take_from = i+1 - while take_from < len(contraction) and len(contraction[take_from]) == 0: - assert new_shape[take_from] == 1 - take_from += 1 - if take_from == len(contraction) or new_shape[take_from] != 1: return None # nothing to take - for j in range(take_from, i, -1): - assert len(contraction[j]) > 0 - contraction[j-1] = contraction[j][:-1] - contraction[j] = contraction[j][-1:] - return contraction - -@functools.cache -def canonicalize_strides(shape:tuple[sint, ...], strides:tuple[sint, ...]) -> tuple[sint, ...]: - return tuple(0 if s == 1 else st for s, st in zip(shape, strides)) - -@functools.cache -def strides_for_shape(shape:tuple[sint, ...]) -> tuple[sint, ...]: - if not shape: return () - strides = tuple(itertools.accumulate(reversed(shape[1:]), operator.mul, initial=1))[::-1] - return canonicalize_strides(shape, strides) - -@functools.cache -def merge_dims(shape:tuple[int, ...], strides:tuple[int, ...], mask:tuple[tuple[int, int], ...]|None=None) -> tuple[tuple[int, int, int], ...]: - # merge contiguous sub-parts or zero strided dims - # any stride 0, masked from dim=1, or contiguous part is merged into next dim. - # stride != 0 to stride == 0 starts a new merging block - # ret = tuple[(merged_size, stride, merged size w/o zero stride), ...] - if not shape: return () - assert len(shape) == len(strides) and (mask is None or len(shape) == len(mask)) - ret = [(shape[0], strides[0], shape[0] if strides[0] != 0 else 0)] - # merge this dim to next dim if size is 1 - merging = (mask[0][1] - mask[0][0] == 1) if mask is not None else shape[0] == 1 - for i, (s, st) in enumerate(zip(shape[1:], strides[1:]), start=1): - # always merge 1 - if s == 1: continue - last_s, last_st, last_pre_expand_s = ret[-1] - # merge last dim with this dim if merging or strides matched - if merging or last_st == s * st: ret[-1] = (last_s * s, st, (s if merging else last_pre_expand_s * s)) - else: ret.append((s, st, s)) - # merge this dim to next dim if size is 1 - merging = (mask[i][1] - mask[i][0] == 1) if mask is not None else s == 1 - return tuple(ret) - -@functools.cache -def _reshape_mask(_mask:tuple[tuple[sint, sint], ...]|None, old_shape:tuple[sint, ...], new_shape:tuple[sint, ...]) \ - -> tuple[tuple[sint, sint], ...]|None: - """Returns the new mask if reshape is possible, and None if not possible.""" - if _mask is None: return tuple((0, s) for s in new_shape) - if not all_int(flatten(_mask)): return None - - new_mask: list[tuple[int, int]] = [] - # _mask is all int here - r_masks, r_shape, r_new_shape = reversed(cast(tuple[tuple[int, int], ...], _mask)), reversed(old_shape), reversed(new_shape) - curr_stride, old_dim, new_dim, mask = 1, next(r_shape, 1), next(r_new_shape, 1), next(r_masks, (0,1)) - - while len(new_mask) < len(new_shape): - (l, r), next_stride = mask, ssimplify(new_dim * curr_stride) - - # need to split mask - if old_dim == next_stride: # simply copy the mask and get next batch for merging - new_mask.append((l // curr_stride, (r - 1) // curr_stride + 1)) - curr_stride, old_dim, new_dim, mask = 1, next(r_shape, 1), next(r_new_shape, 1), next(r_masks, (0,1)) - elif old_dim > next_stride: # mask can only be splitted if reshape doesn't cut across the mask. - if old_dim % next_stride != 0: return None - if (l % next_stride != 0 or r % next_stride != 0) and l // next_stride != (r - 1) // next_stride: return None - new_mask.append((l % next_stride // curr_stride, (r - 1) % next_stride // curr_stride + 1)) - curr_stride, new_dim = next_stride, next(r_new_shape, 1) # need to get mask for next dimension - else: - next_mask = next(r_masks, (0, 1)) - # combine if the mask can unfold continuously - if mask != (0, old_dim) and l != r and next_mask[1] - next_mask[0] != 1: return None - mask, old_dim = (next_mask[0] * old_dim + l, (next_mask[1] - 1) * old_dim + r), ssimplify(old_dim * next(r_shape, 1)) - - return tuple(reversed(new_mask)) - -def unravel(shape:tuple[sint, ...], offset:sint) -> list[sint]: - # find the position of offset on each dimension based on shape - # similar to unravel_index in numpy/torch - acc, idxs = 1, [] - for d in reversed(shape): - idxs.append((offset//acc)%d) - acc *= d - return idxs[::-1] - -@dataclass(frozen=True) -class View: - shape:tuple[sint, ...] - strides:tuple[sint, ...] - offset:sint - mask:tuple[tuple[sint, sint], ...]|None - contiguous:bool - - def to_valid_uop(self, idxs:Sequence[UOp]|None=None) -> UOp: - """valid.where(idx, INVALID)""" - if idxs is None: idxs = [UOp.range(s, i) for i,s in enumerate(self.shape)] - iexpr = sint_to_uop(self.offset) - where = UOp.const(dtypes.bool, True) - for idx,sh,st,m in zip(idxs, self.shape, self.strides, self.mask if self.mask is not None else itertools.repeat(None)): - iexpr = iexpr + idx*sint_to_uop(st) - if m is not None: - if resolve(m[0] != 0): where &= (idx >= sint_to_uop(m[0])) - if resolve(m[1] != sh): where &= (idx < sint_to_uop(m[1])) - return where.where(iexpr, UOp.invalid()) - - @functools.cache # pylint: disable=method-cache-max-size-none - def size(self) -> int: - ret = prod([x.vmax if isinstance(x, UOp) else x for x in self.shape]) - assert isinstance(ret, int), f"{ret=} is not int" - return ret - - @staticmethod - @functools.cache - def create(shape:tuple[sint, ...], strides:tuple[sint, ...]|None=None, offset:sint=0, mask:tuple[tuple[sint, sint], ...]|None=None): - # TODO: resolve shouldn't be needed here - if not all(resolve(s >= 0) for s in shape): raise ValueError(f"Trying to create View with negative dimension: {shape=}") - strides = canonicalize_strides(shape, strides) if strides else strides_for_shape(shape) - # canonicalize 0 in shape - if 0 in shape: return View(shape, (0,) * len(shape), offset=0, mask=None, contiguous=True) - # canonicalize no-op mask - if mask is not None and all(m == (0,s) for m,s in zip(mask, shape)): mask = None - # if any dimension has size >1, but is masked such that only one index in the dimension is unmasked - # then its stride can also be set to 0, albeit with a corresponding adjustment required to the offset - if mask and any(elim := [not resolve(b+1 < e) for b,e in mask]): - if any(not resolve(b < e) for b,e in mask): - strides, offset, mask = (0,) * len(shape), 0, ((0,0),) * len(shape) - offset += sum((strides[i] * mask[i][0]) if e else 0 for i, e in enumerate(elim)) - strides = tuple(0 if e else st for st,e in zip(strides, elim)) - # simplify as we go - if isinstance(offset, UOp): offset = cast(sint, offset.ssimplify()) - shape = tuple(cast(sint, x.ssimplify()) if isinstance(x, UOp) else x for x in shape) - # TODO: enabling stride simplification breaks symbolic jit - """ - strides = tuple(x.ssimplify() if isinstance(x, UOp) else x for x in strides) - if mask: mask = tuple((s.ssimplify() if isinstance(s, UOp) else s, e.ssimplify() if isinstance(e, UOp) else e) for s,e in mask) - """ - contiguous = offset == 0 and mask is None and strides == strides_for_shape(shape) - return View(shape, strides, offset, mask, contiguous) - - @functools.cache # pylint: disable=method-cache-max-size-none - def vars(self) -> set[Variable]: - flatten_mask = tuple(x for m in self.mask for x in m) if self.mask is not None else tuple() - return functools.reduce(operator.or_, [x.vars() for x in self.shape+self.strides+(self.offset,)+flatten_mask if isinstance(x, UOp)], set()) - - @functools.cache # pylint: disable=method-cache-max-size-none - def unbind(self) -> tuple[View, dict[Variable, int]]: - var_unboundvar_val = [(v, v.unbind()) for v in self.vars() if v.op is Ops.BIND] - unbound_vars = {v:uv for v,(uv,_) in var_unboundvar_val} - return self.substitute(unbound_vars), dict(x[1] for x in var_unboundvar_val) - - def substitute(self, dvars:dict[UOp, UOp]): - def _substitute(x:sint): return x if isinstance(x, int) else x.substitute(dvars) - new_shape = tuple(map(_substitute, self.shape)) - new_strides = tuple(map(_substitute, self.strides)) - new_offset = _substitute(self.offset) - new_mask = tuple((_substitute(x[0]), _substitute(x[1])) for x in self.mask) if self.mask is not None else None - return View.create(new_shape, new_strides, new_offset, new_mask) - - @functools.cache # pylint: disable=method-cache-max-size-none - def __add__(self, vm1:View) -> View|None: - vm2 = self - if vm2.contiguous or vm1.size() == 0: return vm1 - if vm1.contiguous and vm1.shape == vm2.shape: return vm2 - if vm1.contiguous and vm1.size() == vm2.size() and (ret := vm2.reshape(vm1.shape)) is not None: return ret - if vm1.mask: - if (new_vm1 := vm1.shrink(vm1.mask)) == vm1 or (merged := vm2 + new_vm1) is None: return None - return merged.pad(tuple((b,s-e) for (b,e),s in zip(vm1.mask, vm1.shape))) - if not all_int(vm1.shape): - # if all strides are 0 and vm2 is unmasked, return vm1 - if all(x == 0 for x in vm2.strides+vm1.strides) and vm2.mask is None: return vm1 - # TODO: handle more cases - return None - - # Project vm1's offset and strides on to vm2. - origin = [ssimplify(o) for o in unravel(vm2.shape, vm1.offset)] - terms: list[list[tuple[int, sint]]] = [[] for _ in vm2.shape] - strides: list[sint] = [0] * len(vm1.shape) - for d1, st in enumerate(vm1.strides): - if st == 0: continue - for d2, (o, s1) in enumerate(zip(origin, unravel(vm2.shape, vm1.offset + st))): - if not resolve((s1 := s1 - o)!=0): continue # if s1 can possibly be 0 - terms[d2].append((d1, s1)) - strides[d1] += ssimplify(s1 * vm2.strides[d2]) - - # Merge dimensions in vm2 if required. - # NB: Merging too many dimensions can make it difficult to project vm2's mask, hence only combining when required. - idxs: list[UOp] = [UOp.variable(f"idx{i}", 0, s-1, dtypes.index) for i,s in enumerate(vm1.shape)] - merged_size, merged_term = 1, UOp.const(dtypes.index, 0) - extents: list[tuple[sint, UOp]] = [] - for term, s, o in zip(reversed(terms), reversed(vm2.shape), reversed(origin)): - merged_term += (sum([idxs[d1] * s1 for d1, s1 in term]) + o) * merged_size - merged_size *= s - if resolve(merged_term < merged_size, False) and resolve(0 <= merged_term, False): - extents.append((merged_size, merged_term)) - merged_size, merged_term = 1, UOp.const(dtypes.index, 0) - if resolve(merged_term != 0): return None - if (vm2_shape := tuple(s for s,_ in reversed(extents))) != vm2.shape: - if (reshaped_vm2 := vm2.reshape(vm2_shape)) is None: return None - # NOTE: this != to prevent infinite loop - if reshaped_vm2.shape != vm2.shape: return reshaped_vm2 + vm1 - - if vm2.mask: - # Try to project vm2's mask on to vm1. - newb, newe, bad = [0] * len(vm1.shape), list(vm1.shape), False - for (b, e), o, term, (_, t) in zip(vm2.mask, origin, terms, reversed(extents)): - if resolve(b <= (t := t.simplify()).vmin and t.vmax < e, False): continue - if len(term) != 1: - if not term and newe: - # t should be a constant if no terms contribute to this dimension, but it might not be simplified - if t.vmin != t.vmax: return None - newe[0] = 0 - else: bad = True - continue - d1, s1 = term[0] - newb[d1] = smax(newb[d1], ceildiv(b - o if s1 > 0 else e - o - 1, s1)) - newe[d1] = smin(newe[d1], (b - o if s1 < 0 else e - o - 1) // s1 + 1) - - # If any of vm1 was masked off, try again with that mask in place. - if any((b, e) != (0, s) for b, e, s in zip(newb, newe, vm1.shape)): - return vm2 + View.create(vm1.shape, vm1.strides, vm1.offset, tuple(zip(newb, newe))) - # Otherwise if vm2's mask was violated, then cannot merge. - if bad: return None - - return View.create(vm1.shape, tuple(strides), ssimplify(sum(o * s for o, s in zip(origin, vm2.strides)) + vm2.offset)) - - @functools.cache # pylint: disable=method-cache-max-size-none - def invert(self, out_shape:tuple[sint, ...]) -> View|None: - ret = View.create(self.shape) - if self.mask: ret = ret.shrink(self.mask) - ret = ret.flip(tuple(x < 0 for x in self.strides)).permute(argsort(tuple(-x if x > 0 else x for x in self.strides))) - return ret if prod(ret.shape) == prod(out_shape) else None # don't support shrink, expand, or stride != (-1, 1) - - @functools.cache # pylint: disable=method-cache-max-size-none - def minify(self): - min_shape = tuple(x[0] for x in merge_dims(self.shape, self.strides, self.mask)) - return nv if (nv := self.reshape(min_shape)) else self - - def __unsafe_resize(self, arg: tuple[tuple[sint, sint], ...], mask=None) -> View: - offset = sum([s * x[0] for s, x in zip(self.strides,arg)]) - if self.mask: - # move the old mask - nmask = tuple([(smax(0, smin(mx-ax,ay-ax)), smax(0, smin(my-ax,ay-ax))) for (mx,my),(ax,ay) in zip(self.mask, arg)]) - # merge the masks if we have two - mask = tuple([(smax(mx1, mx2), smin(my1, my2)) for (mx1, my1), (mx2, my2) in zip(nmask, mask)]) if mask is not None else nmask - return View.create(tuple([y-x for x,y in arg]), self.strides, self.offset+offset, mask) - - @functools.cache # pylint: disable=method-cache-max-size-none - def pad(self, arg: tuple[tuple[sint, sint], ...]) -> View: - assert len(arg) == len(self.shape), f"invalid pad {arg} for {self.shape}" - # NOTE: not checking for symbolic arg - for b,e in arg: assert not all_int([b,e]) or b>=0 and e>=0, f"invalid pad {arg} for {self.shape}" - if any(resolve(b!=0) or resolve(e!=0) for b, e in arg): - zvarg = tuple([(-b,s+e) for s,(b,e) in zip(self.shape, arg)]) - mask = tuple([(b,s+b) for s,(b,_) in zip(self.shape, arg)]) - return self.__unsafe_resize(zvarg, mask=mask) - return self - - @functools.cache # pylint: disable=method-cache-max-size-none - def shrink(self, arg: tuple[tuple[sint, sint], ...]) -> View: - assert len(arg) == len(self.shape), f"invalid shrink {arg} for {self.shape}" - # NOTE: not checking for symbolic arg - for s,(b,e) in zip(self.shape,arg): assert not all_int([s,b,e]) or (0<=b<=e<=s), f"invalid shrink {arg} for {self.shape}" - return self.__unsafe_resize(arg) - - @functools.cache # pylint: disable=method-cache-max-size-none - def expand(self, new_shape: tuple[sint, ...]) -> View: - if len(new_shape) != len(self.shape): raise ValueError(f"expand arg {new_shape=} must have same number of dimensions as shape {self.shape=}") - # NOTE: does not check multiple of symbolic shape - assert all(resolve(s == ns) or s == 1 for s,ns in zip(self.shape, new_shape)), f"can't expand {self.shape} into {new_shape}" - if 0 in self.shape: return View.create(new_shape) - # TODO: resolve may not be needed, but it's hard because vars need to be canonicalized - mask = tuple([(((0,0) if m != (0,1) else (0,ns)) if resolve(s != ns) and resolve(s == 1, False) else m) \ - for m,s,ns in zip(self.mask, self.shape, new_shape)]) if self.mask else None - return View.create(new_shape, self.strides, self.offset, mask) - - @functools.cache # pylint: disable=method-cache-max-size-none - def permute(self, axis: tuple[int, ...]) -> View: - assert sorted(axis) == list(range(len(self.shape))), f"invalid permutation {axis} of len {len(self.shape)}" - return View.create(tuple(self.shape[a] for a in axis), tuple(self.strides[a] for a in axis), self.offset, - tuple(self.mask[a] for a in axis) if self.mask is not None else None) - - @functools.cache # pylint: disable=method-cache-max-size-none - def flip(self, arg: tuple[bool, ...]) -> View: - offset = sum((s-1)*z for s,z,f in zip(self.shape, self.strides, arg) if f) - mask = tuple((s-my,s-mx) if f else (mx,my) for (mx,my),s,f in zip(self.mask, self.shape, arg)) if self.mask is not None else None - return View.create(self.shape, tuple(-z if f else z for z,f in zip(self.strides, arg)), self.offset+offset, mask) - - @functools.cache # pylint: disable=method-cache-max-size-none - def reshape(self, new_shape: tuple[sint, ...]) -> View|None: - if self.shape == new_shape: return self - - if not all(x >= 0 for x in new_shape): raise ValueError(f"shape can't contain negative numbers {new_shape}") - # check for the same size - if resolve(prod(self.shape) != prod(new_shape), True): raise ValueError(f"size mismatched, can't reshape {self.shape=} -> {new_shape=}") - - if 0 in self.shape: return View.create(new_shape) - if new_shape == () and self.mask and any(mx==my for (mx,my) in self.mask): return None - - # after the asserts, it's okay to check contiguous - if self.contiguous: return View.create(new_shape) - - r_strides, r_new_shape = [], reversed(new_shape) - for merged_size, new_stride, real_size in reversed(merge_dims(self.shape, self.strides, self.mask)): - # TODO: write with get_contraction - acc = 1 - # TODO: third resolve shouldn't be needed - while resolve(acc <= merged_size) and resolve(acc != merged_size) and resolve((new_dim := next(r_new_shape, 0)) > 0): - r_strides.append(new_stride * acc) - acc = acc * new_dim - if not resolve(acc < real_size): new_stride = 0 - if resolve(acc != merged_size): return None - new_strides = (0,) * (len(new_shape) - len(r_strides)) + tuple(r_strides[::-1]) - - if (new_mask:=_reshape_mask(self.mask, self.shape, new_shape)) is not None: - extra_offset = (sum(m[0] * s for m,s in zip(self.mask, self.strides)) if self.mask else 0) - \ - (sum(m[0] * s for m,s in zip(new_mask, new_strides))) - return View.create(new_shape, new_strides, self.offset + extra_offset, new_mask) - - return None diff --git a/tinygrad/tensor.py b/tinygrad/tensor.py index 76969ea11d..a6b86ae080 100644 --- a/tinygrad/tensor.py +++ b/tinygrad/tensor.py @@ -5,51 +5,39 @@ from contextlib import ContextDecorator from typing import Callable, ClassVar, Sequence, cast, get_args, Literal, SupportsIndex, ParamSpec, TypeVar, Generic from tinygrad.dtype import DType, DTypeLike, dtypes, ImageDType, ConstType, least_upper_float, least_upper_dtype, sum_acc_dtype, to_dtype, truncate from tinygrad.dtype import _from_np_dtype, _to_np_dtype -from tinygrad.helpers import argfix, make_tuple, flatten, prod, all_int, round_up, merge_dicts, argsort, getenv, all_same, fully_flatten, dedup -from tinygrad.helpers import IMAGE, WINO, Metadata, TRACEMETA, ceildiv, fetch, polyN, unwrap, DEBUG, is_numpy_ndarray, RANGEIFY, FUSE_ATTENTION +from tinygrad.helpers import argfix, make_tuple, flatten, prod, all_int, round_up, merge_dicts, argsort, getenv, all_same, fully_flatten +from tinygrad.helpers import IMAGE, WINO, Metadata, TRACEMETA, ceildiv, fetch, polyN, DEBUG, is_numpy_ndarray, SPEC from tinygrad.helpers import suppress_finalizing from tinygrad.gradient import compute_gradient -from tinygrad.uop.ops import smax, smin, resolve, UOp, Ops, sint, MathTrait, identity_element, all_metadata, _index_to_concrete_int, sint_to_uop, \ - srender -from tinygrad.uop.spec import tensor_uop_spec, type_verify +from tinygrad.mixin import OpMixin +from tinygrad.mixin.movement import _align_left +from tinygrad.uop.ops import smax, smin, resolve, UOp, Ops, sint, identity_element, all_metadata, _index_to_concrete_int, sint_to_uop +from tinygrad.uop.spec import type_verify, tensor_spec from tinygrad.device import Device, Buffer from tinygrad.engine.realize import run_schedule from tinygrad.engine.memory import memory_planner from tinygrad.engine.schedule import ScheduleItem, create_schedule_with_vars from tinygrad.schedule.rangeify import get_rangeify_map from tinygrad.schedule.multi import get_multi_map -from tinygrad.schedule.kernelize import get_kernelize_map + +# TODO: this should be the only usage of Device +def canonicalize_device(device:str|None) -> str: return Device.canonicalize(device) # *** all in scope Tensors are here. this gets relevant UOps *** all_tensors: dict[weakref.ref[Tensor], None] = {} -def _find_all_tensors_for_uops(all_uops: set[UOp]) -> list[Tensor]: - return [t for tref in all_tensors if (t:=tref()) is not None and t.uop in all_uops] - def _apply_map_to_tensors(applied_map:dict[UOp, UOp], name:str|None=None) -> None: - # get all children of keys in applied_map - all_uops: set[UOp] = set() - search_uops = list(applied_map) - while len(search_uops): - x = search_uops.pop() - if x in all_uops: continue - all_uops.add(x) - search_uops.extend([u for c in x.children if (u:=c()) is not None]) + scope_tensors = [t for tref in tuple(all_tensors) if (t:=tref()) is not None and + (t.uop in applied_map or len(applied_map.keys() & t.uop.backward_slice.keys()))] - # link the found UOps back to Tensors. exit early if there's no Tensors to realize - # NOTE: this uses all_tensors, but it's fast - if len(fixed_tensors := _find_all_tensors_for_uops(all_uops)): - # potentially rewrite all the discovered Tensors - sink = UOp.sink(*[t.uop for t in fixed_tensors]) - new_sink = sink.substitute(applied_map, name=name) + # get all Tensors and apply the map + sink = UOp.sink(*[t.uop for t in scope_tensors]) + new_sink = sink.substitute(applied_map, name=name) - # NOTE: you can check the Tensor graph early here - #if __debug__: type_verify(list(new_sink.toposort()), tensor_uop_spec) - - # set the relevant uop to the realized UOps - for t,s,ns in zip(fixed_tensors, sink.src, new_sink.src): - if s is ns: continue - t.uop = ns + # set the relevant uop to the realized UOps + for t,s,ns in zip(scope_tensors, sink.src, new_sink.src): + if s is ns: continue + t.uop = ns # **** Tensor helper functions **** @@ -92,10 +80,6 @@ def _apply_winograd_matrix(mat, t:Tensor, dims:int) -> Tensor: assert isinstance(ret, Tensor), "sum didn't return a Tensor" return ret -def _align_left(*shapes:tuple[sint, ...]) -> tuple[tuple[sint, ...], ...]: - # unsqueeze left to make every shape same length - max_dim = max(len(shape) for shape in shapes) - return tuple((1,) * (max_dim - len(shape)) + shape for shape in shapes) def _broadcast_shape(*shapes:tuple[sint, ...]) -> tuple[sint, ...]: return tuple(0 if 0 in nth_dim_sizes else smax(nth_dim_sizes) for nth_dim_sizes in zip(*_align_left(*shapes))) @@ -113,7 +97,7 @@ def _flat_to_grouped(padding:Sequence[sint]) -> tuple[tuple[sint, sint], ...]: r ReductionStr = Literal["mean", "sum", "none"] -class Tensor(MathTrait): +class Tensor(OpMixin): """ A `Tensor` is a multi-dimensional matrix containing elements of a single data type. @@ -128,10 +112,11 @@ class Tensor(MathTrait): training: ClassVar[bool] = False def __init__(self, data:ConstType|bytes|list|tuple|UOp|'np.ndarray'|pathlib.Path|None, # type: ignore [name-defined] # noqa: F821 - device:str|tuple|list|None=None, dtype:DTypeLike|None=None, requires_grad:bool|None=None): - if dtype is not None: dtype = to_dtype(dtype) + device:str|tuple|list|None=None, dtype:DTypeLike|None=None, requires_grad:bool|None=None, _force_unique:bool=False): if device is None and isinstance(data, pathlib.Path): device = f"DISK:{data.resolve()}" # keep it on the disk if device is None - device = tuple(Device.canonicalize(x) for x in device) if isinstance(device, (tuple, list)) else Device.canonicalize(device) + _dtype:DType|None = to_dtype(dtype) if dtype is not None else None + _device:str|tuple[str, ...] = tuple(canonicalize_device(x) for x in device) if isinstance(device, (tuple, list)) else canonicalize_device(device) + del device, dtype # tensors can have gradients if you have called .backward self.grad:Tensor|None = None @@ -142,41 +127,41 @@ class Tensor(MathTrait): # create a UOp from the different types of inputs if isinstance(data, UOp): - assert dtype is None or dtype==data.dtype, "dtype doesn't match, and casting isn't supported" + assert _dtype is None or _dtype==data.dtype, "dtype doesn't match, and casting isn't supported" # if data is dtype.index that means that this is a symbolic int and we need to lower it to something we can make a Tensor out of if data.dtype==dtypes.index: data = _index_to_concrete_int(data) if data.op is Ops.BIND: # type: ignore # mypy type narrowing is bugged here var, val = data.unbind() # type: ignore # give the bound constant a device - const = UOp.const(var.dtype, val, device, ()) + const = UOp.const(var.dtype, val, _device, ()) data = data.replace(src=(var.replace(src=const.src), const)) # type: ignore - elif data is None: data = UOp.const(dtype or dtypes.default_float, 0, device, ()) - elif isinstance(data, get_args(ConstType)): data = UOp.const(dtype or dtypes.from_py(data), data, device, ()) - elif isinstance(data, bytes): data = _frompy(data, dtypes.uint8 if dtype is None else dtype) + elif data is None: data = UOp.const(_dtype or dtypes.default_float, 0, _device, (), unique=_force_unique) + elif isinstance(data, get_args(ConstType)): data = UOp.const(_dtype or dtypes.from_py(data), data, _device, (), unique=_force_unique) + elif isinstance(data, bytes): data = _frompy(data, dtypes.uint8 if _dtype is None else _dtype) elif isinstance(data, (list, tuple)): - if dtype is None: - if (d := fully_flatten(data)) and all(isinstance(s, bool) for s in d): dtype = dtypes.bool - else: dtype = dtypes.default_int if d and all_int(d) else dtypes.default_float # NOTE: this works because all_int([True, False]) is True - if dtype in [dtypes.bfloat16, *dtypes.fp8s]: data = Tensor(_frompy(data, dtypes.float32), device=device).cast(dtype).uop - else: data = _frompy(data, dtype) + if _dtype is None: + if (d := fully_flatten(data)) and all(isinstance(s, bool) for s in d): _dtype = dtypes.bool + else: _dtype = dtypes.default_int if d and all_int(d) else dtypes.default_float # NOTE: this works because all_int([True, False]) is True + if _dtype in [dtypes.bfloat16, *dtypes.fp8s]: data = Tensor(_frompy(data, dtypes.float32), device=_device).cast(_dtype).uop + else: data = _frompy(data, _dtype) elif is_numpy_ndarray(data): import numpy as np assert isinstance(data, np.ndarray), f"expected np.ndarray, got {data}" - if data.shape == (): data = UOp.const(dtype or _from_np_dtype(data.dtype), data.item(), device, ()) - else: data = _fromnp(data.astype(npdtype) if dtype is not None and (npdtype:=_to_np_dtype(dtype)) is not None else data) # type: ignore [name-defined] + if data.shape == (): data = UOp.const(_dtype or _from_np_dtype(data.dtype), data.item(), _device, (), unique=_force_unique) + else: data = _fromnp(data.astype(npdtype) if _dtype is not None and (npdtype:=_to_np_dtype(_dtype)) is not None else data) # type: ignore [name-defined] elif isinstance(data, pathlib.Path): - dtype = dtype or dtypes.uint8 - data = UOp.new_buffer(f"DISK:{data.resolve()}", data.stat().st_size // dtype.itemsize, dtype) + _dtype = _dtype or dtypes.uint8 + data = UOp.new_buffer(f"DISK:{data.resolve()}", data.stat().st_size // _dtype.itemsize, _dtype) # by this point, it has to be a UOp if not isinstance(data, UOp): raise RuntimeError(f"can't create Tensor from {data!r} with type {type(data)}") # data might be on a different device - if isinstance(device, str): self.uop:UOp = data if data.device == device else data.copy_to_device(device) + if isinstance(_device, str): self.uop:UOp = data if data.device == _device else data.copy_to_device(_device) # if device is a tuple, we should have/construct a MultiLazyBuffer - elif isinstance(data.device, str): self.uop = Tensor(data).shard(device).uop + elif isinstance(data.device, str): self.uop = Tensor(data).shard(_device).uop else: - assert data.device == device, f"MultiLazyBuffer device mismatch, {data.device} != {device}" + assert data.device == _device, f"MultiLazyBuffer device mismatch, {data.device} != {_device}" self.uop = data # add to all_tensors after construction succeeds @@ -187,7 +172,7 @@ class Tensor(MathTrait): def _apply_uop(self, fxn:Callable, *x:Tensor, extra_args=(), **kwargs) -> Tensor: new_uop: UOp = fxn(*[t.uop for t in (self,)+x], *extra_args, **kwargs) - if (metadata:=_METADATA.get()) is not None: all_metadata[new_uop] = (metadata,) + if (metadata:=_METADATA.get()) is not None and TRACEMETA >= 1: all_metadata[new_uop] = (metadata,) needs_input_grad = [t.requires_grad for t in (self,)+x] return Tensor(new_uop, device=new_uop.device, requires_grad=True if any(needs_input_grad) else None if None in needs_input_grad else False) @@ -209,7 +194,7 @@ class Tensor(MathTrait): def __repr__(self): ld = self.uop - ld_repr = f"" + ld_repr = f"" return f"" # Python has a non moving GC, so this should be okay @@ -241,16 +226,24 @@ class Tensor(MathTrait): big_sink = UOp.sink(*[x.uop for x in (self,)+lst]) # verify Tensors match the spec - if __debug__: type_verify(list(big_sink.toposort()), tensor_uop_spec) + if SPEC: type_verify(big_sink, tensor_spec) - if RANGEIFY and any(isinstance(x._device, tuple) for x in big_sink.toposort()): + if any(isinstance(x._device, tuple) for x in big_sink.toposort()): _apply_map_to_tensors(get_multi_map(big_sink), "Apply Multi Map") big_sink = UOp.sink(*flatten([x.uop.src if x.uop.op is Ops.MULTI else [x.uop] for x in (self,)+lst])) - becomes_map = get_rangeify_map(big_sink) if RANGEIFY else get_kernelize_map(big_sink) + becomes_map = get_rangeify_map(big_sink) _apply_map_to_tensors(becomes_map, name="Apply Kernelize Map") return self + def custom_kernel(self, *lst:Tensor, fxn:Callable, grad_fxn:Callable|None=None) -> list[Tensor]: + """ + Call into a custom kernel written in UOps. Returns the Tensors after the Kernel has been applied. + + This API is alpha and may change. + """ + return [Tensor(u) for u in UOp.custom_kernel(*[t.uop for t in (self,)+lst], fxn=fxn, grad_fxn=grad_fxn)] + def schedule_with_vars(self, *lst:Tensor) -> tuple[list[ScheduleItem], dict[str, int]]: """ Creates the schedule needed to realize these Tensor(s), with Variables. @@ -261,14 +254,14 @@ class Tensor(MathTrait): self.kernelize(*lst) sink = UOp.sink(*[x.uop for x in (self,)+lst]) - # remove all ASSIGNs, after scheduling, the tensors are just buffers - remove_assign_map = {u:u.buf_uop for u in sink.toposort() if u.op is Ops.ASSIGN} - _apply_map_to_tensors(remove_assign_map, name="Remove Assigns") + # remove all AFTERs, after scheduling, the tensors are just buffers + remove_assign_map = {u:u.buf_uop for u in sink.toposort() if u.op is Ops.AFTER} + _apply_map_to_tensors(remove_assign_map, name="Remove After") # create the schedule schedule, var_vals = create_schedule_with_vars(sink) schedule = memory_planner(schedule) - if DEBUG >= 1 and len(schedule) > 1: print(f"scheduled {len(schedule)} kernels in {(time.perf_counter()-st)*1000:.2f} ms") + if (DEBUG >= 1 and len(schedule) > 1) or DEBUG >= 3: print(f"scheduled {len(schedule)} kernels in {(time.perf_counter()-st)*1000:.2f} ms") return schedule, var_vals def schedule(self, *lst:Tensor) -> list[ScheduleItem]: @@ -279,7 +272,8 @@ class Tensor(MathTrait): def realize(self, *lst:Tensor, do_update_stats=True) -> Tensor: """Triggers the computation needed to create these Tensor(s).""" - run_schedule(*self.schedule_with_vars(*lst), do_update_stats=do_update_stats) + if len(to_realize:=[x for x in (self,)+lst if not x.uop.is_contiguous()]): + run_schedule(*Tensor.schedule_with_vars(*to_realize), do_update_stats=do_update_stats) return self def replace(self, x:Tensor, allow_shape_mismatch=False) -> Tensor: @@ -305,8 +299,7 @@ class Tensor(MathTrait): assert self.shape == x.shape, f"assign shape mismatch {self.shape} != {x.shape}" assert self.device == x.device, f"assign device mismatch {self.device} != {x.device}" assert self.dtype == x.dtype, f"assign dtype mismatch {self.dtype} != {x.dtype}" - self.uop = self.uop.assign(x.uop) - return self + return self.replace(self._apply_uop(UOp.assign, x)) def detach(self) -> Tensor: """ @@ -392,7 +385,7 @@ class Tensor(MathTrait): """ Moves the tensor to the given device. """ - device = tuple(Device.canonicalize(x) for x in device) if isinstance(device, (tuple, list)) else Device.canonicalize(device) + device = tuple(canonicalize_device(x) for x in device) if isinstance(device, (tuple, list)) else canonicalize_device(device) if device == self.device: return self if not isinstance(device, str): return self.shard(device) ret = Tensor(self.uop, device, requires_grad=self.requires_grad) @@ -417,7 +410,7 @@ class Tensor(MathTrait): ``` """ assert isinstance(self.device, str), "can't shard a MultiLazyBuffer" - devices = tuple(Device.canonicalize(x) for x in devices) + devices = tuple(canonicalize_device(x) for x in devices) mlb = self.uop.shard(devices, self._resolve_dim(axis)) if axis is not None else self.uop.copy_to_device(devices) return Tensor(mlb, device=devices, requires_grad=self.requires_grad) @@ -427,6 +420,59 @@ class Tensor(MathTrait): """ return self.replace(self.shard(devices, axis)) + CHUNK_SIZE = 2**20 + def load(self, size:int) -> Tensor: + """ + Load a tensor from storage. + + self should be a tensor of the hash to load + """ + # TODO: this should work locally as well + assert self.dtype == dtypes.uint8, "hash is expected to be uint8" + h = self.contiguous().flatten() + assert h.shape[0] == 16, "expected hash" + + base_chunks = math.ceil(size / Tensor.CHUNK_SIZE) + tree_depth = math.ceil(math.log(base_chunks, Tensor.CHUNK_SIZE // 16)) + data, level_chunks = h, 0 + for i in reversed(range(tree_depth + 1)): + data = data.to("tinyfs:load") + + # if not last level, its still hashes + if i > 0 or tree_depth == 0: + level_chunks = max(1, math.ceil(base_chunks / (Tensor.CHUNK_SIZE // 16)**(i-1))) + pad_amt = 16 * level_chunks + else: pad_amt = Tensor.CHUNK_SIZE * level_chunks + if (tsize := data.shape[0]) < pad_amt: data = data.pad((0, pad_amt - tsize)) + data = data[:pad_amt].contiguous() + if i != 0: data = data.to(self.device) + + return data[:size] + + def store(self) -> Tensor: + """ + Store a tensor to storage. + """ + # TODO: this should work locally as well + data = self.contiguous().flatten().bitcast(dtypes.uint8) + + # pad to a multiple of 1mb + if (tsize := data.shape[0]) % Tensor.CHUNK_SIZE != 0: data = data.pad((0, Tensor.CHUNK_SIZE - tsize % Tensor.CHUNK_SIZE)) + size = data.shape[0] + + base_chunks = math.ceil(size / Tensor.CHUNK_SIZE) + tree_depth = math.ceil(math.log(base_chunks, Tensor.CHUNK_SIZE // 16)) + + to_device = "CPU" if isinstance(self.device, str) and self.device.startswith("DISK") else self.device + + level_chunks = base_chunks + for _ in range(tree_depth + 1): + data = data.to("tinyfs:store")[:level_chunks * 16].contiguous().to(to_device) + if (tsize := data.shape[0]) % Tensor.CHUNK_SIZE != 0: data = data.pad((0, Tensor.CHUNK_SIZE - tsize % Tensor.CHUNK_SIZE)) + level_chunks = math.ceil(data.shape[0] / Tensor.CHUNK_SIZE) + + return data[:16].contiguous() + @staticmethod def from_uop(y:UOp, **kwargs) -> Tensor: if y.op is Ops.BIND: return Tensor(y, **kwargs, requires_grad=False) @@ -453,7 +499,7 @@ class Tensor(MathTrait): dtype, shape = to_dtype(dtype) if dtype is not None else dtypes.default_float, argfix(*shape) if not isinstance(size:=prod([x.vmax if isinstance(x, UOp) else x for x in shape]), int): raise ValueError(f"size must be int {size}") # TODO: add test for multidevice tensor - device = tuple(Device.canonicalize(d) for d in device) if isinstance(device, tuple) else Device.canonicalize(device) + device = tuple(canonicalize_device(d) for d in device) if isinstance(device, tuple) else canonicalize_device(device) return Tensor(UOp.new_buffer(device, size, dtype), device, dtype, **kwargs).shrink(((0,prod(shape)),)).reshape(shape) def empty_like(self, **kwargs) -> Tensor: @@ -535,7 +581,7 @@ class Tensor(MathTrait): if not dtypes.is_float(dtype := to_dtype(dtype or dtypes.default_float)): raise ValueError(f"rand only supports float dtypes, got {dtype}") if not all_int(shape:=argfix(*shape)) or not all(s >= 0 for s in shape): raise ValueError(f"invalid input {shape=}") if device is not None and not isinstance(device, str): raise ValueError(f"rand only supports single device, got {device=}") - device = Device.canonicalize(device) + device = canonicalize_device(device) # if shape has 0, return zero tensor if (numel := prod(shape)) == 0: return Tensor.zeros(shape, device=device, dtype=dtype, **kwargs) @@ -584,7 +630,7 @@ class Tensor(MathTrait): print(Tensor.full((2, 3), False).numpy()) ``` """ - return Tensor(fill_value, **kwargs).reshape((1, )*len(new_shape := argfix(shape))).expand(new_shape) + return Tensor(fill_value, _force_unique=True, **kwargs).reshape((1, )*len(new_shape := argfix(shape))).expand(new_shape) @staticmethod def zeros(*shape, **kwargs) -> Tensor: @@ -989,102 +1035,7 @@ class Tensor(MathTrait): # ***** movement low level ops ***** - def view(self, shape:tuple[sint, ...], *args) -> Tensor: - """`.view` is an alias for `.reshape`.""" - return self.reshape(shape, *args) - - def reshape(self, shape, *args) -> Tensor: - """ - Returns a tensor with the same data as the original tensor but with a different shape. - `shape` can be passed as a tuple or as separate arguments. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.arange(6) - print(t.reshape(2, 3).numpy()) - ``` - """ - # resolve None and args - new_shape = tuple([s if s is not None else self.shape[i] for i,s in enumerate(argfix(shape, *args))]) - # resolve -1 - if (c := new_shape.count(-1)) > 1: raise RuntimeError(f"only one dimension can be inferred using -1, getting {new_shape}") - if c: new_shape = tuple([-prod(self.shape) // prod(new_shape) if s == -1 else s for s in new_shape]) - if resolve(prod(self.shape) != prod(new_shape), True): - raise ValueError(f"size mismatch, can't reshape ({', '.join(srender(d) for d in self.shape)}) -> ({', '.join(srender(d) for d in new_shape)})") - return self._apply_uop(UOp.reshape, arg=new_shape) if new_shape != self.shape else self - - def expand(self, shape, *args) -> Tensor: - """ - Returns a tensor that is expanded to the shape that is specified. - Expand can also increase the number of dimensions that a tensor has. - - Passing a `-1` or `None` to a dimension means that its size will not be changed. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor([1, 2, 3]) - print(t.expand(4, -1).numpy()) - ``` - """ - new_shape = tuple(from_ if to == -1 or to is None else to for from_, to in zip(*(_align_left(self.shape, argfix(shape, *args))))) - return self._broadcast_to(new_shape) - - def permute(self, order, *args) -> Tensor: - """ - Returns a tensor that is a permutation of the original tensor. - The new tensor has the same data as the original tensor but with the dimensions permuted according to the order specified. - `order` can be passed as a tuple or as separate arguments. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.empty(2, 3, 5) - print(t.shape) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.permute(2, 0, 1).shape) - ``` - """ - order_arg = tuple(self._resolve_dim(x) for x in argfix(order, *args)) - if sorted(order_arg) != list(range(self.ndim)): raise RuntimeError(f"order is not a valid permutation, getting {order_arg}") - return self._apply_uop(UOp.permute, arg=order_arg) - - def flip(self, axis, *args) -> Tensor: - """ - Returns a tensor that reverses the order of the original tensor along given `axis`. - `axis` can be passed as a tuple or as separate arguments. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.arange(6).reshape(2, 3) - print(t.numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.flip(0).numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.flip((0, 1)).numpy()) - ``` - """ - axis_arg = tuple(self._resolve_dim(x) for x in argfix(axis, *args)) - if len(axis_arg) != len(dedup(axis_arg)): raise RuntimeError(f"dim can appear at most once, getting {axis_arg}") - return self._apply_uop(UOp.flip, arg=tuple([i in axis_arg for i in range(len(self.shape))])) - - def shrink(self, arg:tuple[tuple[sint, sint]|None, ...]) -> Tensor: - """ - Returns a tensor that shrinks the each axis based on input arg. - `arg` must have the same length as `self.ndim`. - For each axis, it can be `None`, which means no shrink, or a tuple `(start, end)` that works the same as Python slice. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.arange(9).reshape(3, 3) - print(t.numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.shrink(((None, (1, 3)))).numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.shrink((((0, 2), (0, 2)))).numpy()) - ``` - """ - if self.ndim != len(arg): raise ValueError(f"{self.ndim=} != {len(arg)=}") - if (shrink_arg:=[x if x is not None else (0,s) for x,s in zip(arg, self.shape)]) == [(0,s) for s in self.shape]: return self - return self._apply_uop(UOp.shrink, arg=tuple(shrink_arg)) + def _mop(self, op:Ops, arg) -> Tensor: return self._apply_uop(UOp._mop, extra_args=(op,), arg=arg) def pad(self, padding:Sequence[sint]|Sequence[tuple[sint, sint]|None], mode:str="constant", value:float=0.0) -> Tensor: """ @@ -1150,8 +1101,9 @@ class Tensor(MathTrait): return X.shrink(tuple((-min(pB,0), min(pA+s,s)) for (pB,pA),s in zip(pX, X.shape))) # convenience - def pad_to(self, shape, *args): return self.pad(tuple([(0, ns-s) for s,ns in itertools.zip_longest(self.shape, argfix(shape, *args))])) - def shrink_to(self, shape, *args): return self.shrink(tuple([(0, ns) for ns in argfix(shape, *args)])) + def pad_to(self, shape, *args): + if len(new_shape := argfix(shape, *args)) != self.ndim: raise ValueError(f"dim mismatch, cannot pad {self.shape} to {new_shape}") + return self.pad(tuple([None if ns is None else (0, ns-s) for s,ns in zip(self.shape, new_shape)])) # ***** movement high level ops ***** @@ -1175,6 +1127,7 @@ class Tensor(MathTrait): match index: case Tensor(): if not dtypes.is_int(index.dtype): raise IndexError(f"index dtype {index.dtype} is not supported") + assert isinstance(size, int), "size must be an int" index = (index < 0).where(index+size, index).to(self.device) # treat negative index values case list() | tuple(): if not dtypes.is_int((ti:=Tensor(index)).dtype): raise IndexError(f"{index=} contains non-int element") @@ -1303,12 +1256,12 @@ class Tensor(MathTrait): self.realize()._getitem(indices).assign(v) return # NOTE: check that setitem target is valid first - if not unwrap(self.uop.st).contiguous: raise RuntimeError("setitem target needs to be contiguous") if isinstance(v, get_args(ConstType)): v = Tensor(v, device=self.device, dtype=self.dtype) if not isinstance(v, Tensor): raise TypeError(f"can't set a {type(v).__name__} to a Tensor") if self.requires_grad or v.requires_grad: raise NotImplementedError("setitem with requires_grad is not supported") - - res = self.realize()._getitem(indices, v) + self.realize() + if not self.uop.is_contiguous(): raise RuntimeError("setitem target needs to be contiguous") + res = self._getitem(indices, v) # if shapes match and data is not shared it's a copy and we assign to self if res.shape == self.shape and res.uop is not self.uop: self.assign(res).realize() @@ -1370,44 +1323,6 @@ class Tensor(MathTrait): # checks for shapes and number of dimensions delegated to cat return Tensor.cat(*[t.unsqueeze(dim) for t in argfix(self, *args)], dim=dim) - def repeat_interleave(self, repeats:int, dim:int|None=None) -> Tensor: - """ - Repeats elements of a tensor. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor([1, 2, 3]) - print(t.repeat_interleave(2).numpy()) - ``` - """ - x, dim = (self.flatten(), 0) if dim is None else (self, self._resolve_dim(dim)) - shp = x.shape - return x.reshape(*shp[:dim+1], 1, *shp[dim+1:]).expand(*shp[:dim+1], repeats, *shp[dim+1:]).reshape(*shp[:dim], shp[dim]*repeats, *shp[dim+1:]) - - def repeat(self, repeats, *args) -> Tensor: - """ - Repeats tensor number of times along each dimension specified by `repeats`. - `repeats` can be passed as a tuple or as separate arguments. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor([1, 2, 3]) - print(t.repeat(4, 2).numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.repeat(4, 2, 1).shape) - ``` - """ - repeats = argfix(repeats, *args) - base_shape = _align_left(self.shape, repeats)[0] - unsqueezed_shape = flatten([[1, s] for s in base_shape]) - expanded_shape = flatten([[r, s] for r,s in zip(repeats, base_shape)]) - final_shape = [r*s for r,s in zip(repeats, base_shape)] - return self.reshape(unsqueezed_shape).expand(expanded_shape).reshape(final_shape) - - def _resolve_dim(self, dim:int, *, extra:bool=False) -> int: - total = self.ndim + int(extra) - if not -max(1, total) <= dim <= max(1, total)-1: raise IndexError(f"{dim=} out of range {[-max(1, total), max(1, total)-1]}") - return dim + total if dim < 0 else dim - def split(self, sizes:int|Sequence[int], dim:int=0) -> tuple[Tensor, ...]: """ Splits the tensor into chunks along the dimension specified by `dim`. @@ -1508,96 +1423,6 @@ class Tensor(MathTrait): output_shape = _broadcast_shape(*(t.shape for t in tensors)) return tuple(t._broadcast_to(output_shape) for t in tensors) - def squeeze(self, dim:int|None=None) -> Tensor: - """ - Returns a tensor with specified dimensions of input of size 1 removed. - If `dim` is not specified, all dimensions with size 1 are removed. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.zeros(2, 1, 2, 1, 2) - print(t.squeeze().shape) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.squeeze(0).shape) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.squeeze(1).shape) - ``` - """ - if dim is None: return self.reshape(tuple(dim for dim in self.shape if dim != 1)) - dim = self._resolve_dim(dim) - return self if not self.ndim or self.shape[dim] != 1 else self.reshape(self.shape[:dim] + self.shape[dim+1:]) - - def unsqueeze(self, dim:int) -> Tensor: - """ - Returns a tensor with a new dimension of size 1 inserted at the specified `dim`. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor([1, 2, 3, 4]) - print(t.unsqueeze(0).numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.unsqueeze(1).numpy()) - ``` - """ - dim = self._resolve_dim(dim, extra=True) - return self.reshape(self.shape[:dim] + (1,) + self.shape[dim:]) - - @property - def T(self) -> Tensor: - """`.T` is an alias for `.transpose()`.""" - return self.transpose() - - def transpose(self, dim0=1, dim1=0) -> Tensor: - """ - Returns a tensor that is a transposed version of the original tensor. - The given dimensions `dim0` and `dim1` are swapped. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.arange(6).reshape(2, 3) - print(t.numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.transpose(0, 1).numpy()) - ``` - """ - order = list(range(self.ndim)) - order[dim0], order[dim1] = order[dim1], order[dim0] - return self.permute(order) - - def flatten(self, start_dim=0, end_dim=-1) -> Tensor: - """ - Flattens the tensor by reshaping it into a one-dimensional tensor. - If `start_dim` or `end_dim` are passed, only dimensions starting with `start_dim` and ending with `end_dim` are flattened. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor.arange(8).reshape(2, 2, 2) - print(t.flatten().numpy()) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(t.flatten(start_dim=1).numpy()) - ``` - """ - start_dim, end_dim = self._resolve_dim(start_dim), self._resolve_dim(end_dim) - return self.reshape(self.shape[:start_dim] + (prod(self.shape[start_dim:end_dim+1]), ) + self.shape[end_dim+1:]) - - def unflatten(self, dim:int, sizes:tuple[int,...]) -> Tensor: - """ - Unflattens dimension `dim` of the tensor into multiple dimensions specified by `sizes`. `Tensor.flatten()` is the inverse of this function. - - ```python exec="true" source="above" session="tensor" result="python" - print(Tensor.ones(3, 4, 1).unflatten(1, (2, 2)).shape) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(Tensor.ones(3, 4, 1).unflatten(1, (-1, 2)).shape) - ``` - ```python exec="true" source="above" session="tensor" result="python" - print(Tensor.ones(5, 12, 3).unflatten(-2, (2, 2, 3, 1, 1)).shape) - ``` - """ - dim = self._resolve_dim(dim) - return self.reshape(self.shape[:dim] + sizes + self.shape[dim+1:]) - def diag(self) -> Tensor: """ Returns a 2-D square tensor with the elements of input as the main diagonal. @@ -1643,46 +1468,6 @@ class Tensor(MathTrait): for dim, shift in zip(dims, shifts): slices[dim] = slice(delta:=self.shape[dim]-shift%self.shape[dim], delta+self.shape[dim]) return self.repeat(*tuple(2 if i in dims else 1 for i in range(self.ndim)))[slices] - def rearrange(self, formula:str, **sizes) -> Tensor: - """ - Rearranges input according to formula - - See: https://einops.rocks/api/rearrange/ - - ```python exec="true" source="above" session="tensor" result="python" - x = Tensor([[1, 2], [3, 4]]) - print(Tensor.rearrange(x, "batch channel -> (batch channel)").numpy()) - ``` - """ - def parse_formula(formula: str): - tokens = f" {formula} ".replace("…", "...").replace("(", " ( ").replace(")", " ) ").replace(" ", " ").replace(" 1 ", " ( ) ").split() - lparens, rparens = map(lambda x: [i for i, ch in enumerate(tokens) if ch == x], ("(", ")")) - pairs = list(zip(lparens, rparens)) - assert len(lparens) == len(rparens) and sorted(flatten(pairs)) == flatten(pairs), "bracket mismatch" - return [name for name in tokens if name not in ("(", ")")], [(s - 2*i, e - 1 - 2*i) for i, (s, e) in enumerate(pairs)] - - assert formula.count("->") == 1, 'need exactly one "->" in formula' - - (lhs, unflatten_dims), (rhs, flatten_dims) = map(parse_formula, formula.split("->")) - - for name in sizes: assert name in lhs, f"axis {name} is not used in transform" - assert sorted(lhs) == sorted(rhs) and len(lhs) == len(set(lhs)), f"name mismatch in {formula}" - for name in flatten((lhs, rhs)): assert name == "..." or (name.isidentifier() and "_" not in (name[0], name[-1])), f"invalid axis name {name}" - assert "..." not in flatten([lhs[s:e] for s, e in unflatten_dims]), f"cannot have collapsed ellipsis (...) in lhs of {formula}" - assert lhs.count("...") <= 1, f"too many ellipses in {formula}" - - # resolve ellipsis - if "..." in lhs: ell_len = len(self.shape) - len(lhs) + 1 + sum(e - s - 1 for s, e in unflatten_dims) - lhs, rhs = map(lambda l: l[:(i:=l.index("..."))] + [f"...{j}" for j in range(ell_len)] + l[i + 1:] if "..." in l else l, (lhs, rhs)) - unflatten_dims = [(s + (ell_len - 1 if "...0" in lhs[:s] else 0), e + (ell_len - 1 if "...0" in lhs[:e] else 0)) for s, e in unflatten_dims] - flatten_dims = [(s + (ell_len - 1 if "...0" in rhs[:s] else 0), e + (ell_len - 1 if "...0" in rhs[:e] else 0)) for s, e in flatten_dims] - - # apply movement ops in order unflatten -> permute -> flatten/unsqueeze - t = functools.reduce(lambda x, dims: x.unflatten(dims[0], tuple(sizes.get(lhs[d], -1) for d in range(*dims))), unflatten_dims, self) - for i, name in enumerate(lhs): assert (name not in sizes) or sizes[name] == t.shape[i], f"size provided for dimension {name} incorrect" - t = t.permute([lhs.index(name) for name in rhs]) - return functools.reduce(lambda x, dims: x.flatten(dims[0], dims[1] - 1) if dims[0] bool: + """ + Check if all self and other are close. Return True or False. + """ + return bool(self.isclose(other, rtol=rtol, atol=atol, equal_nan=equal_nan).all().item()) + def mean(self, axis:int|Sequence[int]|None=None, keepdim=False) -> Tensor: """ Returns the mean value of the tensor along the specified axis or axes. @@ -2045,7 +1836,7 @@ class Tensor(MathTrait): state = Tensor.zeros(bs, 25, device=self.device, dtype=dtypes.uint64) for k in range(int(data.shape[1])): - state = state.bitwise_xor(data[:,k].reshape(bs, 25)) + state = state ^ data.shrink((None, (k, k+1), None)).squeeze(1) for i in range(24): # f1600 # θ step p = state.reshape(bs, 5, 5).transpose(2, 1) @@ -2099,7 +1890,7 @@ class Tensor(MathTrait): e = m.exp() return m, e, e.sum(axis=axis, keepdim=True) - def softmax(self, axis=-1, dtype:DTypeLike|None=None, _single_kernel=getenv("SINGLE_KERNEL_SOFTMAX")) -> Tensor: + def softmax(self, axis=-1, dtype:DTypeLike|None=None) -> Tensor: """ Applies the softmax function to the tensor along the specified axis. @@ -2119,9 +1910,6 @@ class Tensor(MathTrait): print(t.softmax(axis=0).numpy()) ``` """ - if _single_kernel: - _, e, ss = self.contiguous()._softmax(axis, dtype) - return e.div(ss).fuse() _, e, ss = self._softmax(axis, dtype) return e.div(ss) @@ -2305,31 +2093,6 @@ class Tensor(MathTrait): # ***** processing ops ***** - def _pool(self, k_:tuple[sint, ...], stride:int|tuple[int, ...]=1, dilation:int|tuple[int, ...]=1) -> Tensor: - assert len(self.shape) >= len(k_), f"can't pool {self.shape} with {k_}" - s_, d_ = make_tuple(stride, len(k_)), make_tuple(dilation, len(k_)) - assert len(k_) == len(s_) == len(d_), f"stride/dilation mismatch kernel:{k_} stride:{s_} dilation:{d_}" - noop, i_ = [None] * (self.ndim-len(k_)), self.shape[-len(k_):] - assert all(resolve(d*(k-1)+1 <= i) for k,d,i in zip(k_,d_,i_)), "kernel size cannot be greater than actual input size" - o_ = [ceildiv(i-d*(k-1), s) for i,d,k,s in zip(i_,d_,k_,s_)] - if any(resolve(k > s) for k,s in zip(k_,s_)) or any(d != 1 for d in d_): - # input size scaling factor to make sure shrink for stride is possible - f_ = [1 + int(resolve(o*s > (i - d*(k-1)))) for o,s,i,d,k in zip(o_,s_,i_,d_,k_)] - # # repeats such that we don't need padding - x = self.repeat([1]*len(noop) + [ceildiv(k*(i*f+d),i) for k,i,d,f in zip(k_,i_,d_,f_)]) - # handle dilation - x = x.shrink(tuple(noop + [(0,k*(i*f+d)) for k,i,d,f in zip(k_,i_,d_,f_)])).reshape(noop + flatten((k,(i*f+d)) for k,i,d,f in zip(k_,i_,d_,f_))) - # handle stride - x = x.shrink(tuple(noop + flatten(((0,k), (0,o*s)) for k,o,s in zip(k_,o_,s_)))).reshape(noop + flatten((k,o,s) for k,o,s in zip(k_,o_,s_))) - x = x.shrink(tuple(noop + flatten(((0,k), (0,o), (0,1)) for k,o in zip(k_,o_)))).reshape(noop + flatten((k,o) for k,o in zip(k_,o_))) - # permute to move reduce to the end - return x.permute(*range(len(noop)), *[len(noop)+i*2+1 for i in range(len(i_))], *[len(noop)+i*2 for i in range(len(i_))]) - # TODO: once the shapetracker can optimize well, remove this alternative implementation - x = self.pad(tuple(noop + [(0, max(0,o*s-i)) for i,o,s in zip(i_,o_,s_)])).shrink(tuple(noop + [(0,o*s) for o,s in zip(o_,s_)])) - x = x.reshape(noop + flatten(((o,s) for o,s in zip(o_,s_)))) - x = x.shrink(tuple(noop + flatten(((0,o), (0,k)) for o,k in zip(o_,k_)))) - return x.permute(*range(len(noop)), *[len(noop)+i*2 for i in range(len(i_))], *[len(noop)+i*2+1 for i in range(len(i_))]) - def _resolve_pool_pads(self, padding:int|Sequence[int], dims:int) -> Sequence[int]: if not isinstance(padding, int) and not (len(padding) == 2*dims or len(padding) == dims): raise ValueError(f"Padding must be an int or a sequence of length {dims} or {2*dims}, but got {padding=} for {self.shape=} with {dims=}.") @@ -2500,17 +2263,20 @@ class Tensor(MathTrait): if IMAGE: return self.image_conv2d(weight, bias, groups, stride, dilation, padding, dtype) (bs,cin_), (cout,cin), HW = self.shape[:2], weight.shape[:2], weight.shape[2:] padding_ = self._resolve_pool_pads(padding, len(HW)) - assert groups*cin == cin_ and len(self.shape) == len(weight.shape), f"Input Tensor shape {self.shape} does not match the shape of the weights {weight.shape}. ({groups*cin} vs. {cin_})" # noqa: E501 + assert groups*cin == cin_ and len(self.shape) == len(weight.shape),\ + f"Input Tensor shape {self.shape} does not match the shape of the weights {weight.shape}. ({groups*cin} vs. {cin_})" # conv2d is a pooling op (with padding) x = self.pad(padding_)._pool(HW, stride, dilation) # (bs, groups*cin, oy, ox, H, W) rcout, oyx = cout//groups, x.shape[2:-len(HW)] if not all(x == 3 for x in HW) or stride != 1 or dilation != 1 or not WINO: # normal conv - x = x.reshape(bs, groups, cin, 1, *oyx, *HW).expand(bs, groups, cin, rcout, *oyx, *HW).permute(0,1,3,*[4+i for i in range(len(oyx))],2,*[4+len(oyx)+i for i in range(len(HW))]) # noqa: E501 + x = x.reshape(bs, groups, cin, 1, *oyx, *HW).expand(bs, groups, cin, rcout, *oyx, *HW)\ + .permute(0,1,3,*[4+i for i in range(len(oyx))],2,*[4+len(oyx)+i for i in range(len(HW))]) # conv! broadcasted to (bs, groups, rcout, *oyx, cin, *HW) - ret = (x * weight.reshape(1, groups, rcout, *[1] * len(oyx), cin, *HW)).sum([-1-i for i in range(1+len(oyx))], keepdim=True, dtype=dtype).reshape(bs, cout, *oyx) # noqa: E501 + ret = (x * weight.reshape(1, groups, rcout, *[1] * len(oyx), cin, *HW))\ + .sum([-1-i for i in range(1+len(oyx))], keepdim=True, dtype=dtype).reshape(bs, cout, *oyx) return ret if bias is None else ret.add(bias.reshape(1, -1, *[1] * len(HW))) HWI, HWO = (6,) * len(HW), (4,) * len(HW) # F(4x4,3x3) winograd tiles @@ -2521,7 +2287,8 @@ class Tensor(MathTrait): # TODO: stride == dilation # use padding to round up to 4x4 output tiles # (bs, cin_, tyx, HWI) - d = self.pad(sum([[padding_[i*2], padding_[i*2+1] + (-(dim + sum(padding_[i * 2:(i + 1) * 2]) - 2) % 4)] for i, dim in enumerate(self.shape[-len(HW):])], []))._pool(HWI, HWO) # noqa: E501 + pads = [[padding_[i*2], padding_[i*2+1] + (-(dim + sum(padding_[i * 2:(i + 1) * 2]) - 2) % 4)] for i, dim in enumerate(self.shape[-len(HW):])] + d = self.pad(sum(pads, []))._pool(HWI, HWO) # move HW to the front: # (HWI, bs, cin_, tyx) d = d.permute(*range(len(d.shape)-len(HW),len(d.shape)), *range(len(d.shape)-len(HW))) tyx = d.shape[-len(HWI):] # dim of tiling @@ -2643,7 +2410,8 @@ class Tensor(MathTrait): base = ret[..., -1]._cumalu(-1, op, _include_initial=True) base = base.unsqueeze(-1).expand(*base.shape, ret.shape[-1]) def fix(x: Tensor) -> Tensor: return x.flatten(start_dim=-2)[..., -s:].transpose(axis,-1) - return {Ops.ADD: Tensor.__add__, Ops.MAX: Tensor.maximum, Ops.MUL: Tensor.__mul__}[op](fix(ret), fix(base)) + reduce_fxns: dict[Ops, Callable[[Tensor, Tensor], Tensor]] = {Ops.ADD: Tensor.__add__, Ops.MAX: Tensor.maximum, Ops.MUL: Tensor.__mul__} + return reduce_fxns[op](fix(ret), fix(base)) def cumsum(self, axis:int=0) -> Tensor: """ @@ -2977,15 +2745,6 @@ class Tensor(MathTrait): """ return self._apply_uop(UOp.contiguous, extra_args=args, **kwargs) - def fuse(self) -> Tensor: - """ - Makes this a single kernel back to Ops.CONTIGUOUS on the inputs. - - Useful for single kernel softmax and flash attention. - Careful, this can break codegen or make kernels really slow. - """ - return self._apply_uop(UOp.fuse) - def contiguous_backward(self) -> Tensor: """ Inserts a contiguous operation in the backward pass. @@ -3570,18 +3329,8 @@ class Tensor(MathTrait): return self / (1 + self.abs()) # ***** broadcasted elementwise ops ***** - def _broadcast_to(self, new_shape:tuple[sint, ...]) -> Tensor: - if self.shape == new_shape: return self - if self.ndim > len(new_shape): raise ValueError(f"cannot broadcast tensor to fewer dimensions. shape={self.shape} to {new_shape=}") - # first unsqueeze left with 1s https://data-apis.org/array-api/latest/API_specification/broadcasting.html - shape, _ = _align_left(self.shape, new_shape) - # for each dimension, check either dim is 1, or it does not change - if not all(resolve(s == ns) or resolve(s == 1) for s,ns in zip(shape, new_shape)): - raise ValueError(f"cannot broadcast {self.shape} to {new_shape=}") - # NOTE: this cast is no-op in forward and uses sum_acc_dtype in the backward sum - return self.reshape(shape).cast(sum_acc_dtype(self.dtype))._apply_uop(UOp.expand, arg=new_shape).cast(self.dtype) - def _broadcasted(self, y:Tensor|ConstType|UOp, reverse:bool=False, match_dtype:bool=True) -> tuple[Tensor, Tensor]: + def _broadcasted(self, y:Tensor|ConstType|UOp, reverse:bool=False, match_dtype:bool=True, backward_cast:bool=True) -> tuple[Tensor, Tensor]: x: Tensor = self if not isinstance(y, Tensor): # make y a Tensor @@ -3597,8 +3346,13 @@ class Tensor(MathTrait): if reverse: x, y = y, x + # compute the output shape + out_shape = _broadcast_shape(x.shape, y.shape) + # broadcast - return x._broadcast_to(out_shape:=_broadcast_shape(x.shape, y.shape)), y._broadcast_to(out_shape) + # NOTE: the backward cast is no-op in forward and uses sum_acc_dtype in the backward sum + return x.cast(sum_acc_dtype(x.dtype) if backward_cast else x.dtype)._broadcast_to(out_shape).cast(x.dtype), \ + y.cast(sum_acc_dtype(y.dtype) if backward_cast else y.dtype)._broadcast_to(out_shape).cast(y.dtype) def sub(self, x:Tensor|ConstType, reverse=False) -> Tensor: """ @@ -3682,7 +3436,7 @@ class Tensor(MathTrait): if self.dtype != dtypes.bool and not dtypes.is_int(self.dtype): raise RuntimeError(f"{self.dtype} is not supported") return self.logical_not() if self.dtype == dtypes.bool else self ^ -1 - def lshift(self, x:int, reverse=False) -> Tensor: + def lshift(self, x:Tensor|int, reverse=False) -> Tensor: """ Computes left arithmetic shift of `self` by `x` bits. `self` must have unsigned dtype. Equivalent to `self << x`. @@ -3694,7 +3448,7 @@ class Tensor(MathTrait): assert dtypes.is_unsigned(self.dtype) and isinstance(x, int) and x >= 0 and not reverse, f"not supported {self.dtype=} {x=}" return self.mul(2 ** x, reverse) - def rshift(self, x:int, reverse=False) -> Tensor: + def rshift(self, x:Tensor|int, reverse=False) -> Tensor: """ Computes right arithmetic shift of `self` by `x` bits. `self` must have unsigned dtype. Equivalent to `self >> x`. @@ -3810,18 +3564,20 @@ class Tensor(MathTrait): def __rpow__(self, x) -> Tensor: return self.pow(x, True) def __rmatmul__(self, x) -> Tensor: return self.matmul(x, True) - def __iadd__(self, x) -> Tensor: return self.assign(self.add(x)) - def __isub__(self, x) -> Tensor: return self.assign(self.sub(x)) - def __imul__(self, x) -> Tensor: return self.assign(self.mul(x)) - def __ipow__(self, x) -> Tensor: return self.assign(self.pow(x)) - def __itruediv__(self, x) -> Tensor: return self.assign(self.div(x)) def __ifloordiv__(self, x) -> Tensor: return self.assign(self.__floordiv__(x)) + def __ipow__(self, x) -> Tensor: return self.assign(self.pow(x)) def __imatmul__(self, x) -> Tensor: return self.assign(self.matmul(x)) - def __iand__(self, x) -> Tensor: return self.assign(self.bitwise_and(x)) - def __ior__(self, x) -> Tensor: return self.assign(self.bitwise_or(x)) - def __ixor__(self, x) -> Tensor: return self.assign(self.bitwise_xor(x)) - def __ilshift__(self, x) -> Tensor: return self.assign(self.lshift(x)) - def __irshift__(self, x) -> Tensor: return self.assign(self.rshift(x)) + + # unlike Tensors, UOps are immutable, so these don't go in MathTraits + def __iadd__(self, x) -> Tensor: return self.assign(self.add(x)) # type: ignore[misc] + def __isub__(self, x) -> Tensor: return self.assign(self.sub(x)) # type: ignore[misc] + def __imul__(self, x) -> Tensor: return self.assign(self.mul(x)) # type: ignore[misc] + def __itruediv__(self, x) -> Tensor: return self.assign(self.div(x)) # type: ignore[misc] + def __iand__(self, x) -> Tensor: return self.assign(self.bitwise_and(x)) # type: ignore[misc] + def __ior__(self, x) -> Tensor: return self.assign(self.bitwise_or(x)) # type: ignore[misc] + def __ixor__(self, x) -> Tensor: return self.assign(self.bitwise_xor(x)) # type: ignore[misc] + def __ilshift__(self, x) -> Tensor: return self.assign(self.lshift(x)) # type: ignore[misc] + def __irshift__(self, x) -> Tensor: return self.assign(self.rshift(x)) # type: ignore[misc] def __lt__(self, x) -> Tensor: return self._apply_broadcasted_uop(UOp.__lt__, x, False) def __gt__(self, x) -> Tensor: return self._apply_broadcasted_uop(UOp.__lt__, x, True) @@ -3963,9 +3719,7 @@ class Tensor(MathTrait): key = key.repeat_interleave(self.shape[-3] // key.shape[-3], dim=-3) value = value.repeat_interleave(self.shape[-3] // value.shape[-3], dim=-3) - if FUSE_ATTENTION: q, key, value = self.contiguous(), key.contiguous(), value.contiguous() - else: q = self - + q = self qk = q.matmul(key.transpose(-2,-1), dtype=least_upper_dtype(q.dtype, key.dtype, dtypes.float32)) / math.sqrt(q.shape[-1]) # handle attention mask if is_causal: @@ -3974,8 +3728,7 @@ class Tensor(MathTrait): if attn_mask is not None: if attn_mask.dtype == dtypes.bool: attn_mask = attn_mask.where(0, -float("inf")) qk = qk + attn_mask - attn = qk.cast(self.dtype).softmax(-1).dropout(dropout_p) @ value - return attn.fuse() if FUSE_ATTENTION else attn + return qk.cast(self.dtype).softmax(-1).dropout(dropout_p) @ value def _do_reduction(self, reduction:ReductionStr="mean") -> Tensor: if reduction not in get_args(ReductionStr): raise ValueError(f"{reduction=} must be one of {get_args(ReductionStr)}") @@ -4097,10 +3850,10 @@ class Tensor(MathTrait): ``` """ assert self.ndim > 1, "NS only works for two or more dims" + if self.shape[-2] > self.shape[-1]: return self.transpose(-2, -1).newton_schulz(steps, params, eps).transpose(-2, -1) G = self / (self.square().sum(axis=(-2, -1), keepdim=True).sqrt() + eps) - if (swap := self.shape[-2] > self.shape[-1]): G = G.transpose(-2, -1) for _ in range(steps): G = sum(p * functools.reduce(lambda x, y: (y @ y.transpose(-2, -1)) @ x, [G]*i, G) for i,p in enumerate(params)) - return G.transpose(-2, -1) if swap else G + return G def qr(self) -> tuple[Tensor, Tensor]: assert self.ndim > 1, f"expected two or more dimensions, got {self.ndim}" @@ -4170,29 +3923,6 @@ class Tensor(MathTrait): # ***** Tensor Properties ***** - @property - def ndim(self) -> int: - """ - Returns the number of dimensions in the tensor. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor([[1, 2], [3, 4]]) - print(t.ndim) - ``` - """ - return len(self.shape) - - def numel(self) -> sint: - """ - Returns the total number of elements in the tensor. - - ```python exec="true" source="above" session="tensor" result="python" - t = Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) - print(t.numel()) - ``` - """ - return prod(self.shape) - def element_size(self) -> int: """ Returns the size in bytes of an individual element in the tensor. @@ -4362,18 +4092,17 @@ class Tensor(MathTrait): def image_dot(self, w:Tensor, dtype:DTypeLike|None=None) -> Tensor: # NOTE: we use a 1x1 conv2d to do the matmul. mxk @ kxn = (1,k,m,1).conv2d(n,k,1,1) - x, dx, dw = self, self.ndim, w.ndim - if not (dx > 0 and dw > 0): raise RuntimeError(f"both tensors need to be at least 1D, got {dx}D and {dw}D") - if x.shape[-1] != w.shape[-min(w.ndim, 2)]: raise RuntimeError(f"cannot image_dot {x.shape} and {w.shape}") + if not (self.ndim > 0 and w.ndim > 0): raise RuntimeError(f"both tensors need to be at least 1D, got {self.ndim=}, {w.ndim=}") + if self.shape[-1] != w.shape[-min(w.ndim, 2)]: raise RuntimeError(f"cannot image_dot {self.shape} and {w.shape}") bs, groups, cin, cout = prod(self.shape[0:-2]), prod(w.shape[0:-2]), w.shape[-2], w.shape[-1] - out_shape_t = self.shape[0:-2] + (cout,-1) if len(self.shape) > 1 else (cout, ) + out_shape_t = self.shape[0:-2] + (cout,-1) if len(self.shape) > 1 else (cout,) # NOTE: with NHWC we can remove the transposes # bs x groups*cin x H x W - cx = self.transpose(self.ndim-1, self.ndim-2).reshape((bs//groups, groups*cin, -1, 1)) + cx = self.transpose(self.ndim-1, self.ndim-2).reshape(bs//groups, groups*cin, -1, 1) # groups*cout x cin x H, W - cw = w.transpose(w.ndim-1, w.ndim-2).reshape((groups*cout, cin, 1, 1)) + cw = w.transpose(w.ndim-1, w.ndim-2).reshape(groups*cout, cin, 1, 1) return cx.image_conv2d(cw, groups=groups, dtype=dtype).reshape(out_shape_t).transpose(self.ndim-1, self.ndim-2) def image_conv2d(self, weight:Tensor, bias:Tensor|None=None, groups=1, stride=1, dilation=1, padding=0, dtype=None) -> Tensor: @@ -4386,10 +4115,9 @@ class Tensor(MathTrait): if cin % 4 != 0 and not (cin == 1 and groups%4 == 0): x = x.reshape(bs, groups, cin, iy, ix) # do this always? added_input_channels = 4 - (cin % 4) - w = w.pad(tuple((0, added_input_channels) if i == 2 else None for i in range(w.ndim))) - x = x.pad(tuple((0, added_input_channels) if i == 2 else None for i in range(x.ndim))) cin = cin + added_input_channels - x = x.reshape(bs, groups*cin, iy, ix) + w = w.pad_to(None, None, cin, None, None) + x = x.pad_to(None, None, cin, None, None).reshape(bs, groups*cin, iy, ix) # hack for non multiples of 4 on rcout added_output_channels = 0 @@ -4397,7 +4125,7 @@ class Tensor(MathTrait): added_output_channels = 4 - (rcout % 4) rcout += added_output_channels cout = groups * rcout - w = w.pad(tuple((0, added_output_channels) if i == 1 else None for i in range(w.ndim))) + w = w.pad_to(None, rcout, None, None, None) # packed (note: flipping bs and iy would make the auto-padding work) x = x.permute(0,2,3,1) @@ -4411,18 +4139,18 @@ class Tensor(MathTrait): x, w = x.contiguous(), w.contiguous() # expand out - rcin_hi, rcin_lo = cin//4 if cin >= 4 else 1, 4 if cin >= 4 else 1 - cout_expand = [groups//4 if cin == 1 else groups, 4 if cin == 1 else 1, rcout//4 if rcout >= 4 else 1, 4 if rcout >= 4 else 1] + rcin_hi, rcin_lo = (cin//4, 4) if cin >= 4 else (1, 1) + group_shape, rcout_expand = (groups//4, 4) if cin == 1 else (groups, 1), (rcout//4, 4) if rcout >= 4 else (1, 1) x = x.reshape(bs, iy, ix, groups, rcin_hi, rcin_lo) if cin_last: w = w.reshape(cout//4, H, rcin_hi, W, 4, rcin_lo) else: w = w.reshape(cout//4, H, rcin_hi, W, rcin_lo, 4).permute(0,1,2,3,5,4) # prepare input x = x.permute(0,3,4,5,1,2).pad(self._resolve_pool_pads(padding,2))._pool((H,W), stride, dilation)# -> (bs, groups, rcin_hi, rcin_lo, oy, ox, H, W) - x = x.permute(0,4,5,1,2,3,6,7).reshape(bs, (oy := x.shape[4]), (ox := x.shape[5]), *cout_expand[0:2], 1, 1, rcin_hi, rcin_lo, H, W) + x = x.permute(0,4,5,1,2,3,6,7).reshape(bs, (oy := x.shape[4]), (ox := x.shape[5]), *group_shape, 1, 1, rcin_hi, rcin_lo, H, W) # prepare weights - w = w.permute(0,4,2,5,1,3).reshape((1, 1, 1, *cout_expand, rcin_hi, rcin_lo, H, W)) + w = w.permute(0,4,2,5,1,3).reshape((1, 1, 1, *group_shape, *rcout_expand, rcin_hi, rcin_lo, H, W)) # the conv! ret = (x*w).cast(base_image_type((bs*oy, ox*cout//4, 4)) if IMAGE >= 2 else dtypes.float32).sum((-4, -3, -2, -1), dtype=dtype) @@ -4450,7 +4178,7 @@ _METADATA: _ContextVar[Metadata|None] = _ContextVar(default=None) def _metadata_wrapper(fn: Callable[P, T]) -> Callable[P, T]: def _wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - if _METADATA.get() is not None: return fn(*args, **kwargs) + if TRACEMETA < 1 or _METADATA.get() is not None: return fn(*args, **kwargs) if TRACEMETA >= 2: caller_frame = sys._getframe(frame := 1) diff --git a/tinygrad/uop/__init__.py b/tinygrad/uop/__init__.py index 9a67cd260f..322cd2323f 100644 --- a/tinygrad/uop/__init__.py +++ b/tinygrad/uop/__init__.py @@ -1,91 +1,105 @@ +# flake8: noqa: E702 +# allow semicolons to put multiple ops on one line from enum import auto, IntEnum, Enum # wrapper around IntEnum that preserves Enum.__str__ and makes auto() unique across all FastEnum subclasses class FastEnum(IntEnum): def __str__(self): return Enum.__str__(self) + def __repr__(x): return str(x) @staticmethod def _generate_next_value_(_, __, ___, last_values): return 1 + max([0, *last_values, *[max(c) for c in FastEnum.__subclasses__()]]) # the order of these Ops controls the order of the toposort class Ops(FastEnum): - # uops that aren't rendered - NOOP = auto(); SINK = auto(); UNIQUE = auto(); DEVICE = auto(); KERNEL = auto(); PRECAST = auto(); REWRITE_ERROR = auto() # noqa: E702 + # ** 1 -- defines/special ** - # track children - CHILD = auto(); CHILDREN = auto() # noqa: E702 - - # buffer ops - COPY = auto(); BUFFER = auto(); BUFFER_VIEW = auto(); MSELECT = auto(); MSTACK = auto() # noqa: E702 - - # create buffer - BUFFERIZE = auto() - SUBSTITUTE = auto() - - # ops that adjust the behavior of the scheduler - CONTIGUOUS = auto(); CONTIGUOUS_BACKWARD = auto(); DETACH = auto(); FUSE = auto() # noqa: E702 - REALIZE = auto() - - # blocks in linearizer (only used there) - BLOCK = auto(); BLOCKSTART = auto(); BLOCKEND = auto(); BLOCKFINAL = auto() # noqa: E702 - - # movement ops! these only exist in the tensor graph - RESHAPE = auto(); PERMUTE = auto(); EXPAND = auto(); PAD = auto(); SHRINK = auto(); FLIP = auto() # noqa: E702 - MULTI = auto() # MULTI is really a movement op - - # view is what all movement ops become - VIEW = auto() - - # TODO: remove VALID with the VIEW(CONST(DEVICE)) refactor - VALID = auto() - - # TODO: unify these ops into the levels of the memory hierarchy. depends on ASSIGN is STORE - DEFINE_GLOBAL = auto(); DEFINE_LOCAL = auto(); DEFINE_REG = auto() # noqa: E702 + # TODO: unify these ops into the levels of the memory hierarchy + DEFINE_GLOBAL = auto(); DEFINE_LOCAL = auto(); DEFINE_REG = auto() # this is for symbolic shapes - DEFINE_VAR = auto(); BIND = auto() # noqa: E702 + DEFINE_VAR = auto(); BIND = auto() # this is a RANGE for GPU dimensions, similar to symbolic shapes but not exactly SPECIAL = auto() - # reduce - REDUCE_AXIS = auto(); REDUCE = auto(); ALLREDUCE = auto() # noqa: E702 + # ** 2 -- non op uops ** - # optimization helper ops - UNROLL = auto(); CONTRACT = auto(); GEP = auto(); VECTORIZE = auto(); CAT = auto(); PTRCAT = auto() # noqa: E702 + # uops that aren't rendered + NOOP = auto(); SINK = auto(); PRECAST = auto() - # UnaryOps - CAST = auto(); BITCAST = auto(); EXP2 = auto(); LOG2 = auto(); SIN = auto(); SQRT = auto(); RECIP = auto(); NEG = auto(); TRUNC = auto() # noqa: E702 + # AFTER passes src[0] through and promises in the toposort that any consumers of the AFTER run after src[1:] + AFTER = auto() - # load/store before math - LOAD = auto(); STORE = auto() # noqa: E702 - ASSIGN = auto() # TODO: ASSIGN is STORE, remove ASSIGN + # GROUP is a NOOP that just merges things together + GROUP = auto() - # tensor core math op, not elementwise - WMMA = auto() + # vector creation / item selection + GEP = auto(); VECTORIZE = auto() + + # ** 3 -- load/store ** # INDEX is a BinaryOp similar to ADD, but it operates on pointers INDEX = auto() + # load/store before math + LOAD = auto(); STORE = auto() + + # ** 4 -- math ** + + # tensor core math op, not elementwise + WMMA = auto() + + # UnaryOps + CAST = auto(); BITCAST = auto(); EXP2 = auto(); LOG2 = auto(); SIN = auto() + SQRT = auto(); RECIPROCAL = auto(); NEG = auto(); TRUNC = auto() + # BinaryOps - ADD = auto(); MUL = auto(); SHL = auto(); SHR = auto(); IDIV = auto(); MAX = auto(); MOD = auto() # noqa: E702 - CMPLT = auto(); CMPNE = auto(); CMPEQ = auto() # noqa: E702 - XOR = auto(); OR = auto(); AND = auto() # noqa: E702 - THREEFRY = auto(); SUB = auto(); FDIV = auto(); POW = auto() # noqa: E702 + ADD = auto(); MUL = auto(); SHL = auto(); SHR = auto(); IDIV = auto(); MAX = auto(); MOD = auto() + CMPLT = auto(); CMPNE = auto(); CMPEQ = auto() + XOR = auto(); OR = auto(); AND = auto() + THREEFRY = auto(); SUB = auto(); FDIV = auto(); POW = auto() # TernaryOps - WHERE = auto(); MULACC = auto() # noqa: E702 + WHERE = auto(); MULACC = auto() + + # ** 5 -- control flow / consts / custom ** # control flow ops - BARRIER = auto(); RANGE = auto(); IF = auto(); ENDRANGE = auto(); ENDIF = auto() # noqa: E702 + BARRIER = auto(); RANGE = auto(); IF = auto(); END = auto(); ENDIF = auto() # consts. VCONST is a vectorized const - VCONST = auto(); CONST = auto() # noqa: E702 + VCONST = auto(); CONST = auto() # CUSTOM/CUSTOMI are used to output strings into codegen. the I makes the string inline - CUSTOM = auto(); CUSTOMI = auto() # noqa: E702 + CUSTOM = auto(); CUSTOMI = auto() + + # ** 6 -- ops that don't exist in programs ** + + # tensor graph ops + UNIQUE = auto(); DEVICE = auto(); KERNEL = auto() + ASSIGN = auto() + + # buffer ops + BUFFERIZE = auto(); COPY = auto(); BUFFER = auto(); BUFFER_VIEW = auto(); MSELECT = auto(); MSTACK = auto() + + # ops that adjust the behavior of the scheduler + CONTIGUOUS = auto(); CONTIGUOUS_BACKWARD = auto(); DETACH = auto() + + # movement ops! these only exist in the tensor graph + RESHAPE = auto(); PERMUTE = auto(); EXPAND = auto(); PAD = auto(); SHRINK = auto(); FLIP = auto() + MULTI = auto() # MULTI is really a movement op + + # reduce + REDUCE_AXIS = auto(); REDUCE = auto(); ALLREDUCE = auto() + + # errors/placeholders + REWRITE_ERROR = auto(); SENTINEL = auto() + + # expander ops + UNROLL = auto(); CONTRACT = auto(); CAT = auto(); PTRCAT = auto() class GroupOp: - Unary = {Ops.EXP2, Ops.LOG2, Ops.SIN, Ops.SQRT, Ops.RECIP, Ops.NEG, Ops.TRUNC} + Unary = {Ops.EXP2, Ops.LOG2, Ops.SIN, Ops.SQRT, Ops.RECIPROCAL, Ops.NEG, Ops.TRUNC} Binary = {Ops.ADD, Ops.MUL, Ops.IDIV, Ops.MAX, Ops.MOD, Ops.CMPLT, Ops.CMPNE, Ops.CMPEQ, Ops.XOR, Ops.SHL, Ops.SHR, Ops.OR, Ops.AND, Ops.THREEFRY, Ops.SUB, Ops.FDIV, Ops.POW} Ternary = {Ops.WHERE, Ops.MULACC} @@ -99,8 +113,7 @@ class GroupOp: Irreducible = {Ops.CONST, Ops.DEFINE_VAR, Ops.SPECIAL, Ops.RANGE} Movement = {Ops.RESHAPE, Ops.EXPAND, Ops.PERMUTE, Ops.PAD, Ops.SHRINK, Ops.FLIP} - Buffer = {Ops.LOAD, Ops.STORE, Ops.VALID, Ops.CONST, Ops.DEFINE_VAR} - Block = {Ops.BLOCK, Ops.BLOCKEND, Ops.BLOCKSTART} + Buffer = {Ops.LOAD, Ops.STORE, Ops.CONST, Ops.DEFINE_VAR} # BinaryOps that can be flipped Commutative = {Ops.ADD, Ops.MUL, Ops.MAX, Ops.CMPNE, Ops.CMPEQ, Ops.XOR, Ops.AND, Ops.OR} @@ -115,8 +128,6 @@ class GroupOp: Comparison = {Ops.CMPLT, Ops.CMPNE, Ops.CMPEQ} # do not preserve f(0) = 0 - UnsafePad = {Ops.RECIP, Ops.LOG2, Ops.EXP2, Ops.IDIV, Ops.POW} - - Meta = {Ops.COPY, Ops.BUFFER_VIEW} + UnsafePad = {Ops.RECIPROCAL, Ops.LOG2, Ops.EXP2, Ops.IDIV, Ops.POW} All = set(Ops) diff --git a/tinygrad/uop/decompositions.py b/tinygrad/uop/decompositions.py index cc3e5cf09f..54985c02be 100644 --- a/tinygrad/uop/decompositions.py +++ b/tinygrad/uop/decompositions.py @@ -282,7 +282,7 @@ def magicgu(vmax:int, d:int) -> tuple[int,int]: def fast_idiv(device: str, x: UOp, d: int, dont_cast=False) -> UOp|None: # If d is a power of two this is not valid for signed ints! - is_unsigned = True if x.vmin>=0 or x.dtype in dtypes.uints else False + is_unsigned = x.vmin>=0 or x.dtype in dtypes.uints assert d>0, "Sign should have been taken out of divisor" vmin,vmax = max(x.vmin, x.dtype.min), min(x.vmax, x.dtype.max) m,s = magicgu(max(vmax, abs(vmin)), d) @@ -293,7 +293,7 @@ def fast_idiv(device: str, x: UOp, d: int, dont_cast=False) -> UOp|None: if (ret:=fast_idiv(device, x//largest_factor_of_two_in_d, d//largest_factor_of_two_in_d, dont_cast=True)) is not None: return ret if dont_cast: return None # promo_lattice needs to return an unsigned type if the type is unsigned - if dtypes.is_int(next_dtype := promo_lattice[x.dtype.scalar()][-1]) and is_dtype_supported(next_dtype, None if device=='' else device): + if dtypes.is_int(next_dtype := promo_lattice[x.dtype.scalar()][-1]) and is_dtype_supported(next_dtype, device): if m*vmin >= dtypes.min(next_dtype) and m*vmax <= dtypes.max(next_dtype): return ((x.cast(next_dtype)*m) >> s).cast(x.dtype) if is_unsigned else ((x.cast(next_dtype)*m) >> s).cast(x.dtype) + (x<0).where(x.ufix(1), 0) return None @@ -318,7 +318,7 @@ def threefry2x32(x: UOp, key: UOp): powers_of_two = {2**i:i for i in range(64)} @functools.cache -def get_late_rewrite_patterns(ops:tuple[Ops, ...], force_transcendental=False): +def get_late_rewrite_patterns(ops:tuple[Ops, ...], force_transcendental): pat: list[tuple[UPat, Callable]] = [] for op,f in ((Ops.EXP2, xexp2), (Ops.LOG2, xlog2), (Ops.SIN, xsin)): if op not in ops or force_transcendental: diff --git a/tinygrad/uop/ops.py b/tinygrad/uop/ops.py index 518cc95824..027b3ea917 100644 --- a/tinygrad/uop/ops.py +++ b/tinygrad/uop/ops.py @@ -1,31 +1,30 @@ from __future__ import annotations -from typing import Any, Callable, cast, TYPE_CHECKING, Type, Sequence +from typing import Any, Callable, cast, TYPE_CHECKING, Type, Sequence, Iterable import sys, time, functools, itertools, math, operator, hashlib, os, types, pickle, pathlib, inspect, weakref, collections -from dataclasses import dataclass, field +from dataclasses import dataclass from enum import Enum, auto from tinygrad.uop import Ops, GroupOp -from tinygrad.uop.mathtraits import MathTrait -from tinygrad.dtype import ConstType, ImageDType, dtypes, DType, truncate, PtrDType, least_upper_dtype, Invalid, InvalidType +from tinygrad.dtype import ConstType, ImageDType, dtypes, DType, truncate, PtrDType, least_upper_dtype, Invalid, InvalidType, AddrSpace from tinygrad.helpers import ContextVar, all_int, prod, getenv, all_same, Context, partition, temp, unwrap, T, argfix, Metadata, flatten, TRACEMETA -from tinygrad.helpers import PICKLE_BUFFERS, PROFILE, dedup, cdiv, cmod, diskcache_put, to_function_name, cpu_profile, TracingKey, RANGEIFY, VIZ, SPEC -from tinygrad.helpers import strip_parens, make_tuple +from tinygrad.helpers import PICKLE_BUFFERS, PROFILE, dedup, cdiv, cmod, diskcache_put, to_function_name, cpu_profile, TracingKey, VIZ, SPEC, CI +from tinygrad.helpers import strip_parens, colored, ansilen, printable if TYPE_CHECKING: - from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.device import Buffer, MultiBuffer class AxisType(Enum): def __repr__(self): return str(self) GLOBAL = auto(); WARP = auto(); LOCAL = auto(); LOOP = auto(); GROUP_REDUCE = auto(); REDUCE = auto(); UPCAST = auto(); UNROLL = auto() # noqa: E702 THREAD = auto() +axis_letters = {AxisType.GLOBAL: "g", AxisType.THREAD: "t", AxisType.LOCAL: "l", AxisType.WARP: "w", AxisType.LOOP: "L", AxisType.UPCAST: "u", + AxisType.GROUP_REDUCE: "G", AxisType.REDUCE: "R", AxisType.UNROLL: "r"} +axis_colors = {AxisType.GLOBAL: "blue", AxisType.THREAD: "BLUE", AxisType.LOCAL: "cyan", AxisType.WARP: "CYAN", AxisType.LOOP: "WHITE", + AxisType.UPCAST: "yellow", AxisType.GROUP_REDUCE: "RED", AxisType.REDUCE: "red", AxisType.UNROLL: "magenta"} -range_start = {Ops.BUFFERIZE: 1, Ops.REDUCE: 1, Ops.STORE: 2, Ops.WMMA: 3} +range_start = {Ops.BUFFERIZE: 1, Ops.REDUCE: 1, Ops.STORE: 2, Ops.WMMA: 3, Ops.END: 1} # https://en.wikipedia.org/wiki/Identity_element def identity_element(op:Ops, dt:DType) -> ConstType: return dtypes.as_const({Ops.ADD:0, Ops.MUL:1, Ops.MAX:dtypes.min(dt)}[op], dt) -def can_pad(root:UOp, edges:dict[UOp, None]) -> bool: - return all(u.op not in GroupOp.UnsafePad for u in root.toposort(gate=lambda x:x not in edges)) - # With True as the default, this matches the old symbolic behavior def resolve(x:UOp|bool, default:bool=True): if isinstance(x, bool): return x @@ -37,14 +36,28 @@ def resolve(x:UOp|bool, default:bool=True): def _suop(lst, uop_fxn, python_fxn): uops, nums = partition(lst, lambda x: isinstance(x, UOp)) return ssimplify(functools.reduce(uop_fxn, uops + ([python_fxn(nums)] if nums else []))) -def smax(*lst): return _suop(argfix(*lst), UOp.maximum, max) -def smin(*lst): return _suop(argfix(*lst), UOp.minimum, min) -def srender(x) -> str: return x.render() if isinstance(x, UOp) else str(x) +def smax(*lst) -> sint: return _suop(argfix(*lst), UOp.maximum, max) +def smin(*lst) -> sint: return _suop(argfix(*lst), UOp.minimum, min) +def srender(x:sint) -> str: return x.render() if isinstance(x, UOp) else str(x) -def ssimplify(uop): return uop.ssimplify() if isinstance(uop, UOp) else uop +def ssimplify(uop:sint): return uop.ssimplify() if isinstance(uop, UOp) else uop def sym_infer(uop: UOp|int, var_vals: dict[str, int]) -> int: return uop.sym_infer(var_vals) if isinstance(uop, UOp) else uop -def range_str(u:UOp) -> str: return '_'.join([str(x) if x >= 0 else "m"+str(-x) for x in u.arg[0:-1]]) +def range_str(u:UOp, color=False) -> str: + ret = '_'.join([str(x) if x >= 0 else "m"+str(-x) for x in u.arg[0:-1]]) + return colored(ret, axis_colors[u.arg[-1]]) if color else ret + +def multirange_str(rngs:Iterable[UOp], color=False, pad=None) -> str: + ret = ','.join([range_str(x, color=color) for x in sorted(rngs, key=lambda x: x.arg)]) + if pad is not None: ret += " " * (pad-ansilen(ret)) + return ret + +def consumer_map_from_toposort(lst:Iterable[UOp]): + ret: dict[UOp, dict[UOp, None]] = {} + for u in lst: + ret[u] = {} + for s in u.src: ret[s][u] = None + return ret # used for UOp and UPat def pretty_print(x:Any, rep:Callable, srcfn=lambda x: x.src, cache=None, d=0)->str: @@ -62,15 +75,15 @@ class UOpMetaClass(type): def __call__(cls, op:Ops, dtype:DType=dtypes.void, src:tuple[UOp,...]=tuple(), arg:Any=None, tag:Any=None, metadata:tuple[Metadata,...]|None=None, _buffer:Buffer|None=None): if (wret:=UOpMetaClass.ucache.get(key:=(op, dtype, src, arg, tag), None)) is not None and (ret:=wret()) is not None: return ret - UOpMetaClass.ucache[key] = ref = weakref.ref(created:=super().__call__(*key)) - for s in src: s.children.add(ref) + UOpMetaClass.ucache[key] = weakref.ref(created:=super().__call__(*key)) if metadata is not None: all_metadata[created] = metadata # NOTE: this value is set by pickle when pickling a realized tensor if _buffer is not None: assert op is Ops.BUFFER, f"trying to set Buffer {_buffer} for {op}" buffers[created] = _buffer - if SPEC: - from tinygrad.uop.spec import full_spec + if SPEC > 1: + from tinygrad.uop.spec import full_spec, test_pyrender + if SPEC > 2: test_pyrender(created) with Context(IGNORE_OOB=1): ret = full_spec.rewrite(created) if cast(bool|None, ret) is not True: raise RuntimeError(f"SPEC ISSUE {ret}: {created}") return created @@ -79,21 +92,34 @@ class UOpMetaClass(type): buffers:weakref.WeakKeyDictionary[UOp, Buffer|MultiBuffer] = weakref.WeakKeyDictionary() # this maps BUFFER uops to their device Buffers all_metadata:weakref.WeakKeyDictionary[UOp, tuple[Metadata, ...]] = weakref.WeakKeyDictionary() # TODO: should this be here? +# recursive_property replaces functools.cached_property in recursive UOp functions to prevent RecursionError +_NOT_FOUND = object() +class recursive_property(property): + def __init__(self, fxn): + self.fxn = fxn + self.nm = "_RECURSIVE_PROPERTY_"+fxn.__name__ + self.__doc__ = fxn.__doc__ + def __get__(self, x:UOp|None, owner=None): + if x is None: return self + if (val:=x.__dict__.get(self.nm, _NOT_FOUND)) is _NOT_FOUND: + for s in x.toposort(lambda z: not hasattr(z, self.nm)): + s.__dict__[self.nm] = val = self.fxn(s) + return val + +# we import this late so we can use resolve/smax in mixins +from tinygrad.mixin import OpMixin + # NOTE: this should be frozen, but frozen is slower @dataclass(eq=False, slots=True) -class UOp(MathTrait, metaclass=UOpMetaClass): +class UOp(OpMixin, metaclass=UOpMetaClass): op:Ops dtype:DType = dtypes.void src:tuple[UOp, ...] = tuple() arg:Any = None tag:Any = None - children:set[weakref.ref[UOp]] = field(default_factory=set) def __del__(self): if Ops is not None and self.op is Ops.BUFFER and (buffer:=buffers.get(self)) is not None: buffer.ref(-1) - try: - if (ref:=UOpMetaClass.ucache.get(k:=(self.op, self.dtype, self.src, self.arg, self.tag))) is not None: - for s in self.src: s.children.discard(ref) - del UOpMetaClass.ucache[k] + try: del UOpMetaClass.ucache[(self.op, self.dtype, self.src, self.arg, self.tag)] except AttributeError: pass def __reduce__(self): args = [self.op, self.dtype, self.src, self.arg, self.tag, self.metadata] @@ -116,12 +142,14 @@ class UOp(MathTrait, metaclass=UOpMetaClass): def f(self, op, **kwargs): return UOp(op, dtype=kwargs.pop("dtype", self.dtype), src=(self,), **kwargs) @functools.cached_property - def parents(self:UOp) -> dict[UOp, None]: - ret = {s:None for s in self.src} - for s in self.src: ret.update(s.parents) - return ret + def backward_slice(self:UOp) -> dict[UOp, None]: + res: dict[UOp, None] = self.toposort() + res.pop(self) + return res + @property - def sparents(self:UOp) -> dict[UOp, None]: return {self:None, **self.parents} + def backward_slice_with_self(self:UOp) -> dict[UOp, None]: return {self:None, **self.backward_slice} + def op_in_backward_slice_with_self(self, *ops:Ops): return any(x.op in ops for x in self.backward_slice_with_self) def toposort(self, gate:Callable|None=None) -> dict[UOp, None]: ret: dict[UOp, None] = {} @@ -131,125 +159,170 @@ class UOp(MathTrait, metaclass=UOpMetaClass): if node in ret: continue if not visited: if gate is None or gate(node): - stack.append((node, True)) # push node back on stack to process after its parents - for parent in reversed(node.src): stack.append((parent, False)) # push parents on the stack + stack.append((node, True)) # push node back on stack to process after its srcs + for s in reversed(node.src): stack.append((s, False)) # push srcs on the stack else: ret[node] = None # second time i'm seeing this node, add it to returned toposort return ret - def op_in_parents(self, *ops:Ops): return any(x.op in ops for x in self.toposort()) + # returns map of UOps to their consumers in the graph rooted by self + def get_consumer_map(self) -> dict[UOp, dict[UOp, None]]: return consumer_map_from_toposort(self.toposort()) - # returns map of UOps to their children in the graph rooted by self - def get_children_map(self) -> dict[UOp, dict[UOp, None]]: - ret: dict[UOp, dict[UOp, None]] = {} - for u in self.toposort(): - ret[u] = {} - for s in u.src: ret[s][u] = None + def reverse_toposort(self, consumer_map) -> dict[UOp, None]: + ret: dict[UOp, None] = {} + stack: list[tuple[UOp, bool]] = [(x, False) for x in consumer_map if len(x.src) == 0] + while stack: + node, visited = stack.pop() + if node in ret: continue + if not visited: + stack.append((node, True)) # push node back on stack to process after its srcs + for s in consumer_map[node]: stack.append((s, False)) # push srcs on the stack + else: ret[node] = None # second time i'm seeing this node, add it to returned toposort return ret @functools.cached_property def tuplize(self:UOp) -> tuple: return (self.op.value, self.arg, self.dtype,)+tuple([x.tuplize for x in self.src]) - @functools.cached_property - def order_add(self:UOp) -> tuple: - if self.op is Ops.MUL and self.src[1].op in (Ops.CONST, Ops.VCONST): return (self.src[0].tuplize, make_tuple(self.src[1].arg, 1)) - return (self.tuplize, (0,)) - @property def ptrdtype(self) -> PtrDType: - if not isinstance(self.dtype, PtrDType): raise RuntimeError("ptrdtype called on UOp without PtrDType") + if not isinstance(self.dtype, PtrDType): raise RuntimeError(f"ptrdtype called on UOp with type {self.dtype}") return self.dtype # *** uop shape stuff *** - @functools.cached_property - def st(self) -> ShapeTracker|None: - if self.op is Ops.INDEX and self.src[0].op in {Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_REG, Ops.MSTACK, - Ops.MSELECT, Ops.BUFFER, Ops.BUFFERIZE, Ops.VECTORIZE, Ops.STORE}: - return None - if self.op is Ops.INDEX and self.src[0].op is Ops.ASSIGN and self.src[0].src[1].op is Ops.KERNEL: return None - if self.op is Ops.BARRIER: return None - if self.op in GroupOp.Block: return None - from tinygrad.shape.shapetracker import ShapeTracker - # VIEW and MovementOps define a new ShapeTracker from the arg - if self.op is Ops.VIEW: return self.arg - if self.op is Ops.BUFFERIZE: return ShapeTracker.from_shape(tuple([int(r.vmax+1) for r in self.src[1:]])) - # allow reshape from nothing - if self.op is Ops.RESHAPE and self.src[0].st is None: return ShapeTracker.from_shape(self.arg) - if self.op in GroupOp.Movement: return unwrap(self.src[0].st).mop(self.op, self.arg) - # CONST with a DEVICE has a shape of () - if self.op is Ops.CONST and len(self.src) and self.src[0].op is Ops.DEVICE: return ShapeTracker.from_shape(()) - if self.op is Ops.STORE and isinstance(self.dtype, PtrDType): return ShapeTracker.from_shape((self.dtype.size,)) - if self.op is Ops.STORE and self.dtype is not dtypes.void: return self.src[0].src[0].st - # BufferOps and ASSIGN flow ShapeTracker from a direct edge - if self.op in {Ops.STORE, Ops.ASSIGN, Ops.LOAD}: return self.src[0].st - if self.op in GroupOp.Buffer: return views[0] if (views:=[x.st for x in self.src if x.op is Ops.VIEW]) else None - - # BUFFER/BUFFER_VIEW and KERNEL only have a size - if self.op in {Ops.BUFFER, Ops.BUFFER_VIEW}: return ShapeTracker.from_shape((self.size,)) - if self.op is Ops.KERNEL: return ShapeTracker.from_shape((self.arg.ast.size,)) - if self.op in {Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL, Ops.DEFINE_REG}: - sz = self.ptrdtype.size - return ShapeTracker.from_shape((sz,)) if sz > 0 else None - - # CONTIGUOUS with RANGE - # TODO: how are these not RANGE? - if self.op is Ops.CONTIGUOUS and len(self.src) > 1 and all(x.op is Ops.RANGE for x in self.src[1:]): - return ShapeTracker.from_shape((tuple([int(x.vmax+1) for x in self.src[1:]])+self.src[0].shape)) - - # hack for PTX, CASTing the ptr loses the shape - if self.op is Ops.CAST and self.src[0].op is Ops.DEFINE_GLOBAL: return None - - # otherwise we get the shape from sources - if not (src_sts := [x.st for x in self.src if x.st is not None]): return None - assert all_same([x.shape for x in src_sts]), f"UOp sources must have the same shape {self} {[x.shape for x in src_sts]}" + @recursive_property + def _shape(self) -> tuple[sint, ...]|None: match self.op: - case Ops.MULTI: shape = tuple(self.src[0].shape[a]*len(self.device) if a == self.axis else s for a,s in enumerate(self.src[0].shape)) + # late ops don't have shape + case Ops.UNIQUE | Ops.DEVICE | Ops.RANGE | Ops.LOAD | Ops.IF | Ops.BARRIER | Ops.CUSTOM | Ops.CUSTOMI | \ + Ops.VECTORIZE | Ops.VCONST | Ops.GEP | Ops.SPECIAL | Ops.UNROLL | Ops.PRECAST | Ops.CONTRACT: + return None + + case Ops.INDEX: + # non pointer index doesn't have a shape + if not isinstance(self.dtype, PtrDType): return None + # fully indexed doesn't have a shape. TODO: remove this + if self.src[0]._shape is None or len(self.src[1:]) == len(self.src[0].shape): return None + # pointer index + return self.src[0].shape[len(self.src[1:]):] + + # some ops init the shape + case Ops.CONST | Ops.DEFINE_VAR | Ops.BIND: return () if self._device is not None else None + case Ops.BUFFER: return (self.arg,) + case Ops.BUFFER_VIEW: return (self.arg[0],) + case Ops.BUFFERIZE: return tuple([int(r.vmax+1) for r in self.src[1:]]) + case Ops.DEFINE_GLOBAL | Ops.DEFINE_LOCAL | Ops.DEFINE_REG: return (self.ptrdtype.size,) + + # passthrough ops + case Ops.REDUCE | Ops.MSTACK | Ops.MSELECT | Ops.DETACH | Ops.CONTIGUOUS | Ops.CONTIGUOUS_BACKWARD | Ops.AFTER | Ops.END: + return self.src[0]._shape + + # ops with custom handling + case Ops.KERNEL: return self.arg.ast._shape + + # TODO: disallow shape changing bitcast case Ops.BITCAST: - shape = src_sts[0].shape - if self.dtype.itemsize != (input_sz:=self.src[0].dtype.itemsize): shape = shape[:-1]+((shape[-1]*input_sz) // self.dtype.itemsize,) - case Ops.REDUCE_AXIS | Ops.WMMA: shape = src_sts[0].reduce(self.axis_arg) - case _: shape = src_sts[0].shape - return ShapeTracker.from_shape(shape) + ps = self.src[0]._shape + if ps is None: return None + if (output_sz:=self.dtype.itemsize) != (input_sz:=self.src[0].dtype.itemsize): return ps[:-1]+(ssimplify((ps[-1]*input_sz) // output_sz),) + return ps + + # TODO: disallow reshape from nothing. tested by TestOpenClip.test_multigpu_clip_score + case Ops.RESHAPE: + if self.src[0]._shape is None: return self.marg + + # movement ops change the shape. this is the logic from the old ShapeTracker + # NOTE: ssimplify is required because the shape needs to be canonical for broadcasting and same shape checking + if self.op in GroupOp.Movement.union({Ops.MULTI, Ops.REDUCE_AXIS, Ops.WMMA}): + ps = self.src[0]._shape + # TODO: WMMA is used for both axis WMMA and op WMMA. fix this and remove this hack. tested by BERT on AMD LLVM + if ps is None and self.op is Ops.WMMA: return None + if ps is None: raise RuntimeError(f"movement op {self.op} requires shape") + match self.op: + case Ops.RESHAPE: + if not all(x >= 0 for x in self.marg): raise ValueError(f"shape can't contain negative numbers {self.marg}") + if prod(ps) != prod(self.marg): raise ValueError(f"bad reshape: {ps} -> {self.marg}") + return self.marg + case Ops.EXPAND: + if len(ps) != len(self.marg) or not all(s==ns or (s==1 and ns>=0) for s,ns in zip(ps, self.marg)): + raise ValueError(f"bad expand: {ps} -> {self.marg}") + return self.marg + case Ops.PERMUTE: + if sorted(self.marg) != list(range(len(ps))): raise ValueError(f"invalid permutation {self.marg} of len {len(ps)}") + return tuple(ps[i] for i in self.marg) + case Ops.PAD: + # TODO: why do i need resolve here? + if len(ps) != len(self.marg) or not all(resolve(b>=0) and resolve(e>=0) for b,e in self.marg): raise ValueError(f"invalid pad {self.marg}") + return tuple(ssimplify(s+b+e) for s,(b,e) in zip(ps, self.marg)) + case Ops.SHRINK: + # TODO: why do i need resolve here? + if len(ps) != len(self.marg) or not all(resolve(0<=b) and resolve(b<=e) and resolve(e<=s) for s,(b,e) in zip(ps, self.marg)): + raise ValueError(f"invalid shrink {self.marg} for {ps}") + return tuple(ssimplify(e-s) for s,e in self.marg) + case Ops.FLIP: + if len(ps) != len(self.marg) or not all(isinstance(x, bool) for x in self.marg): raise ValueError(f"bad flip on {ps}, {self.marg}") + return ps + case Ops.MULTI: return tuple(s*len(self.device) if a == self.axis else s for a,s in enumerate(ps)) + case Ops.REDUCE_AXIS | Ops.WMMA: + axis_arg = self.arg[1] if self.op is Ops.REDUCE_AXIS else self.arg[7] + if not isinstance(axis_arg, tuple) or not all(isinstance(x, int) and x>=0 and x tuple[sint, ...]: - if self.op is Ops.VIEW: return self.shape - # NOTE: if a parent doesn't have st its full_shape is empty - parent_shapes = [x.full_shape for x in self.src] - return tuple(smax(x) for x in itertools.zip_longest(*parent_shapes, fillvalue=1)) @property def shape(self) -> tuple[sint, ...]: - assert self.st is not None, f"{self.op} doesn't have a shape" - return unwrap(self.st).shape + if (ret:=self._shape) is None: raise RuntimeError(f"shape requested, but {self.op} doesn't have a shape") + return ret + @property - def size(self) -> int: return self.arg[0] if self.op is Ops.BUFFER_VIEW else self.arg if self.op is Ops.BUFFER else unwrap(self.st).size + def size(self) -> int: return prod([int(x.vmax) if isinstance(x, UOp) else x for x in self.shape]) + + @functools.cached_property + def ended_ranges(self): + if self.op in range_start: return self.src[range_start[self.op]:] + return () # determine what ranges this is in - @functools.cached_property + @recursive_property def _ranges(self) -> dict[UOp, None]: ret: dict[UOp, None] = {} - if self.op in range_start.keys(): - for s in self.src[:range_start[self.op]]: ret.update(s.ranges) - for s in UOp.sink(*self.src[range_start[self.op]:]).ranges: - if s in ret: del ret[s] - else: - for s in self.src: ret.update(s.ranges) + for s in self.src: ret.update(s.ranges) + for er in self.ended_ranges: + if er.op is Ops.RANGE: + # if it's a single RANGE, we don't flow through it. + if er in ret: del ret[er] + else: + # if it's not a RANGE, we include all ranges in srcs. + # technically we shouldn't flow through these ranges either, but this is pre pm_add_control_flow so it's the same. + for s in er.ranges: + if s in ret: del ret[s] return ret @property def ranges(self) -> dict[UOp, None]: - if self.op is Ops.RANGE: return {self:None} + if self.op is Ops.RANGE: return {self:None} | self._ranges return self._ranges # *** uop evaluation *** - def simplify(self, tracked=False): + def simplify(self, tracked=False, full_symbolic=True): # late import! - from tinygrad.uop.symbolic import symbolic_flat + from tinygrad.uop.symbolic import symbolic, commutative with Context(TRACK_MATCH_STATS=0 if not tracked else TRACK_MATCH_STATS.value): - return graph_rewrite(self, symbolic_flat, name="simplify") + return graph_rewrite(self, symbolic if full_symbolic else commutative, name="simplify") def ssimplify(self) -> UOp|ConstType: return ret.arg if (ret:=self.simplify()).op is Ops.CONST else ret + def sintify(self) -> sint: return self.arg if self.op is Ops.CONST else self def _eval(self, dtype, expected_type:Type[T]) -> T: assert self.dtype in dtype, f"eval with wrong dtype {self}" vmin, vmax = (simple_self:=self.simplify())._min_max @@ -259,35 +332,47 @@ class UOp(MathTrait, metaclass=UOpMetaClass): def __bool__(self): return self._eval((dtypes.bool,), bool) def __int__(self): return self._eval(dtypes.ints, int) def __float__(self): return self._eval(dtypes.floats, float) - def substitute(self, dvars:dict[UOp, UOp], name:str|None=None): + def substitute(self, dvars:dict[UOp, UOp], name:str|None=None, extra_pm:PatternMatcher|None=None): dvars = {k:v for k,v in dvars.items() if k is not v} if len(dvars) == 0: return self with Context(TRACK_MATCH_STATS=(0 if name is None else TRACK_MATCH_STATS.value)): - return graph_rewrite(self, _substitute, dvars, bottom_up=True, name=name) + return graph_rewrite(self, (extra_pm+_substitute) if extra_pm is not None else _substitute, dvars, bottom_up=True, name=name) + + # *** uop tracing stuff *** + + @recursive_property + def trace_num(self): + num = next(ucount) + # KERNEL also has a UOp in the arg + arg = type(self.arg)(self.arg.ast.trace_num, self.arg.metadata) if self.op is Ops.KERNEL else self.arg + uop_fields[num] = (self.op, self.dtype, tuple(s.trace_num for s in self.src), arg, self.tag)+((self.metadata,) if TRACEMETA>=2 else ()) + return num # *** uop syntactic sugar *** - @property - def st_arg(self) -> ShapeTracker: - assert self.op in GroupOp.Buffer, f"st_arg called on {self.op}" - return unwrap(self.st) - @property - def axis_arg(self) -> tuple[int, ...]: - assert self.op in {Ops.REDUCE_AXIS, Ops.WMMA}, f"axis_arg called on {self.op}" - ret = self.arg[1] if self.op is Ops.REDUCE_AXIS else self.arg[7] - assert isinstance(ret, tuple) and all(isinstance(x, int) for x in ret), f"axis_arg trying to return {ret}" - return ret def sink(*srcs:UOp|None, **kwargs): # pylint: disable=no-self-argument return UOp(Ops.SINK, dtypes.void, tuple([x for x in srcs if x is not None]), **kwargs) + def group(*srcs:UOp|None): # pylint: disable=no-self-argument + if len(srcs) == 1 and isinstance(srcs[0], UOp): return srcs[0] + return UOp(Ops.GROUP, dtypes.void, tuple([x for x in srcs if x is not None])) + def vectorize(self, *srcs, **kwargs): + return UOp(Ops.VECTORIZE, self.dtype.vec(len(srcs)+1), (self,)+srcs, **kwargs) def detach(self): return UOp(Ops.DETACH, self.dtype, (self,)) - def index(self, *srcs:UOp|None, **kwargs): - return UOp(Ops.INDEX, kwargs.pop("dtype", self.dtype), (self,)+tuple([x for x in srcs if x is not None]), **kwargs) - def __getitem__(self, idx): return self.index(idx) + def index(self, *srcs:UOp|None, ptr=False, **kwargs): + return UOp(Ops.INDEX, kwargs.pop("dtype", self.dtype if ptr else self.dtype.base), (self,)+tuple([x for x in srcs if x is not None]), **kwargs) + def __getitem__(self, idx): + idx = argfix(idx) + assert len(idx) == len(self.shape), f"__getitem__ shape mismatch, indexing {self.shape} with {len(idx)} args" + if len(slice_idx:=[i for i,x in enumerate(idx) if isinstance(x, slice)]): + perm = self.permute(tuple([i for i in range(self.ndim) if i not in slice_idx] + slice_idx)) + return perm.index(*[UOp.const(dtypes.index, x) if isinstance(x, int) else x for x in idx if not isinstance(x, slice)], ptr=True) + else: + return self.index(*[UOp.const(dtypes.index, x) if isinstance(x, int) else x for x in idx]) def const_like(self, b:ConstLike): # constants can optionally have a DEVICE source - return UOp.const(self.dtype, b, device=self._device, shape=self.shape if self.st is not None else None) + return UOp.const(self.dtype, b, device=self._device, shape=self._shape) def broadcast(self, count:int): - assert self.dtype.count == 1 + assert self.dtype.vcount == 1 if count == 1: return self return UOp(Ops.VECTORIZE, self.dtype.vec(count), (self,)*count) def cast(self, dtype:DType): @@ -306,49 +391,45 @@ class UOp(MathTrait, metaclass=UOpMetaClass): i = (i,) return UOp(Ops.GEP, self.dtype.scalar().vec(len(i)) if len(i) > 1 else self.dtype.scalar(), (self,), i) def load(self, *src:UOp, **kwargs): return UOp(Ops.LOAD, dtype=kwargs.pop("dtype", self.dtype.base), src=(self,)+src, **kwargs) - def store(self, *src:UOp, **kwargs): return UOp(Ops.STORE, kwargs.pop("dtype", dtypes.void), (self,)+src, **kwargs) + def store(self, src:UOp|ConstType, **kwargs): + return UOp(Ops.STORE, kwargs.pop("dtype", dtypes.void), (self, UOp.const(self.dtype, src) if not isinstance(src, UOp) else src), **kwargs) + def end(self, *src:UOp): + if len(src) == 0: return self + return UOp(Ops.END, src=(self,)+src) + def after(self, *src:UOp, **kwargs): return UOp(Ops.AFTER, self.dtype, (self,)+src, **kwargs) def assign(self, x:UOp): return UOp(Ops.ASSIGN, self.dtype, (self, x)) def barrier(self, *src:UOp): return UOp(Ops.BARRIER, src=(self,)+src) + def contract(self, *rngs:UOp): + assert all(x.arg[-1] == AxisType.UPCAST for x in rngs), "all contract ranges must be upcast" + return UOp(Ops.CONTRACT, dtype=self.dtype.vec(prod([x.vmax+1 for x in rngs])), src=(self,), arg=tuple((x.arg[0], x.vmax+1) for x in rngs)) def alu(self, op, *src:UOp, **kwargs): out_dtype = (self, *src)[-1].dtype if op in {Ops.CMPLT, Ops.CMPNE, Ops.CMPEQ}: out_dtype = dtypes.bool.vec(out_dtype.count) if out_dtype.count > 1 else dtypes.bool return UOp(op, out_dtype, (self,)+src, **kwargs) @staticmethod - def const(dtype:DType, b:ConstLike, device:str|tuple[str, ...]|None=None, shape:tuple[sint, ...]|None=None, src=None): + def const(dtype:DType, b:ConstLike, device:str|tuple[str, ...]|None=None, shape:tuple[sint, ...]|None=None, src=None, unique:bool|int=False): if isinstance(b, UOp): return b.unbind()[0] if b.op is Ops.BIND else b if isinstance(b, tuple) and all_same(b): b = b[0] # doesn't have to be a VCONST if they are all the same + # NOTE: float('nan') != float('nan'), so we canonicalize here + if isinstance(b, float) and math.isnan(b): b = math.nan ret = UOp(Ops.VCONST if isinstance(b, tuple) else Ops.CONST, dtype, arg=dtypes.as_const(b, dtype), src=() if src is None else (src,)) - if RANGEIFY: - # VIEW on const is no longer supported in RANGEIFY - if device is not None: ret = ret.replace(src=(UOp(Ops.DEVICE, arg=device),)) - if shape is not None: ret = ret.reshape((1,)*len(shape)).expand(shape) - else: - if shape is not None: - from tinygrad.shape.shapetracker import ShapeTracker - ret = ret.replace(src=(UOp(Ops.VIEW, dtypes.void, (), ShapeTracker.from_shape(shape, (0,)*len(shape))),)) - if device is not None: - if shape is not None: ret = ret.replace(src=(UOp(Ops.DEVICE, arg=device).view(unwrap(ret.st)),)) - else: ret = ret.replace(src=(UOp(Ops.DEVICE, arg=device),)) + if device is not None: + if unique or not isinstance(unique, bool): ret = ret.replace(src=(UOp(Ops.DEVICE, arg=device), UOp.unique(None if unique is True else unique))) + else: ret = ret.replace(src=(UOp(Ops.DEVICE, arg=device),)) + elif unique or not isinstance(unique, bool): raise RuntimeError("unique consts only with DEVICE") + if shape is not None: ret = ret.reshape((1,)*len(shape)).expand(shape) return ret @staticmethod - def range(end:sint, *arg): - if len(arg) == 0: raise RuntimeError("range needs an arg") - if len(arg) == 1: arg = arg+(AxisType.LOOP,) - return UOp(Ops.RANGE, dtype=dtypes.index, src=(sint_to_uop(end),), arg=arg) + def range(end:sint, axis_id, axis_type=AxisType.LOOP, *arg, dtype=dtypes.index, src=(), **kwargs): + return UOp(Ops.RANGE, dtype=dtype, src=(sint_to_uop(end, dtype),)+src, arg=(axis_id, axis_type)+arg, **kwargs) + @staticmethod + def special(end:sint, name:str, dtype=dtypes.index): return UOp(Ops.SPECIAL, dtype=dtype, src=(sint_to_uop(end, dtype),), arg=name) def r(self, op:Ops, axis:tuple[int, ...]): axis = tuple(sorted([x for x in axis if resolve(self.shape[x] != 1)])) - if len(axis) == 0: return self - # move any non reduce axis before the first reduce axis - move_early, rest = partition(range(axis[0], len(self.shape)), lambda i: i not in axis and resolve(self.shape[i] != 1)) - permaxis = tuple(range(axis[0])) + tuple(move_early) + tuple(rest) - ret = self.permute(permaxis) - new_axis = tuple([x for x in range(axis[0]+len(move_early), len(self.shape)) if resolve(ret.shape[x] != 1)]) - assert len(axis) == len(new_axis) - ret = UOp(Ops.REDUCE_AXIS, self.dtype, (ret,), (op, new_axis)) - return ret.reshape(tuple([x if i not in axis else 1 for i,x in enumerate(self.shape)])) + return UOp(Ops.REDUCE_AXIS, self.dtype, (self,), (op, axis)) if len(axis) else self @staticmethod def invalid(count=1): return UOp(Ops.CONST, dtypes.index.vec(count), src=(), arg=Invalid) - def valid(self, cond): return cond.where(self, UOp.invalid(self.dtype.count)) + def valid(self, cond): return self if cond.op is Ops.WHERE and cond.arg else cond.where(self, UOp.invalid(self.dtype.count)) def get_idx(self) -> UOp: assert self.dtype.scalar() is dtypes.index, "Can only call get_idx on index dtype" return self.src[1] if self.op is Ops.WHERE and self.src[2].arg is Invalid else self @@ -356,11 +437,18 @@ class UOp(MathTrait, metaclass=UOpMetaClass): assert self.dtype.scalar() is dtypes.index, "Can only call get_valid on index dtype" return self.src[0] if self.op is Ops.WHERE and self.src[2].arg is Invalid else UOp.const(dtypes.bool, self.arg is not Invalid) def reduce(self, *src:UOp, **kwargs): return UOp(Ops.REDUCE, kwargs.pop('dtype', self.dtype), src=(self,)+src, **kwargs) - def contiguous(self, *args, **kwargs): return UOp(Ops.CONTIGUOUS, dtype=self.dtype, src=(self,)+args, **kwargs) - def realize(self, *args, **kwargs): return UOp(Ops.REALIZE, dtype=self.dtype, src=(self,)+args, **kwargs) + + def is_contiguous(self): + # TODO: this is is_realized + if self.op is Ops.RESHAPE: return self.src[0].is_contiguous() + return self.op is Ops.BUFFER + + def contiguous(self, *args, **kwargs): + if self.op is Ops.CONTIGUOUS: return self + if self.is_contiguous(): return self + return UOp(Ops.CONTIGUOUS, dtype=self.dtype, src=(self,)+args, **kwargs) def contiguous_backward(self): return self.alu(Ops.CONTIGUOUS_BACKWARD) def bufferize(self, *args, **kwargs): return UOp(Ops.BUFFERIZE, dtype=self.dtype, src=(self,)+args, **kwargs) - def fuse(self): return self.alu(Ops.FUSE) def allreduce(self, op, device:str|tuple[str, ...]|UOp): assert isinstance(self.device, tuple), f"allreduce must be on tuple {self.device} isn't" return UOp(Ops.ALLREDUCE, self.dtype, (self, UOp(Ops.DEVICE, arg=device) if not isinstance(device, UOp) else device), op) @@ -395,11 +483,11 @@ class UOp(MathTrait, metaclass=UOpMetaClass): if self.op is Ops.REDUCE_AXIS: return None if src_axis is not None and src_axis in self.arg[1] else src_axis if self.op is Ops.RESHAPE: if src_axis is None: return None - arg_acc:list[sint] = list(itertools.accumulate(self.arg, operator.mul, initial=1)) + arg_acc:list[sint] = list(itertools.accumulate(self.marg, operator.mul, initial=1)) # new_axis is the last one that preserves prod(prior to new_axis) and must not move items between shards # TODO: what to do about shrinking to self.shape[self.axis]==1 len(self.real_lbs)==1? return len(arg_acc) - arg_acc[::-1].index(prod(self.src[0].shape[:src_axis])) - 1 - if self.op is Ops.PERMUTE: return self.arg.index(src_axis) if src_axis is not None else None + if self.op is Ops.PERMUTE: return self.marg.index(src_axis) if src_axis is not None else None return src_axis def _unshard(self, axis:int) -> UOp: @@ -429,42 +517,73 @@ class UOp(MathTrait, metaclass=UOpMetaClass): @property def base(self) -> UOp: - if (self.op is Ops.VIEW and len(self.src) != 0) or self.op in GroupOp.Movement: return self.src[0].base + if self.op in GroupOp.Movement: return self.src[0].base if self.op is Ops.MULTI: return self.src[0].base # MULTI is really a VIEW return self - def view(self, new_st:ShapeTracker) -> UOp: return UOp(Ops.VIEW, self.dtype, (self,), new_st) - def _mop(self, op:Ops, arg) -> UOp: - ret = UOp(op, self.dtype, (self,), arg) - if self.st == ret.st: return self # ignore NOOPs, also check ret.st + # like gep, but might return an integer + def sgep(self, i:int) -> sint: + match self.op: + case Ops.CONST: return self.arg + case Ops.VCONST: return self.arg[i] + case Ops.VECTORIZE: return self.src[i].sintify() + case _: raise RuntimeError(f"no sgep on {self.op}") + + @functools.cached_property + def marg(self): + match self.op: + case Ops.RESHAPE | Ops.EXPAND: return tuple(self.src[1].sgep(i) for i in range(self.src[1].dtype.count)) + case Ops.PAD | Ops.SHRINK: return tuple((self.src[1].sgep(i), self.src[2].sgep(i)) for i in range(self.src[1].dtype.count)) + case Ops.PERMUTE | Ops.FLIP: return self.arg + case _: raise RuntimeError(f"{self.op} is not a MovementOp") + + def _mop(self, op:Ops, arg, same_shape_noop:bool=False) -> UOp: + match op: + case Ops.RESHAPE | Ops.EXPAND: src_args = [arg] + case Ops.PAD | Ops.SHRINK: src_args = list(zip(*arg)) + case Ops.PERMUTE | Ops.FLIP: src_args = [] + case _: raise RuntimeError(f"{op} is not a MovementOp") + usrcs = [] + for arg in src_args: + if len(arg) == 0: usrcs.append(UOp(Ops.VECTORIZE, dtypes.index.vec(0))) + elif all(isinstance(x, int) for x in arg): usrcs.append(UOp.const(dtypes.index.vec(len(arg)), arg)) + else: usrcs.append(UOp(Ops.VECTORIZE, dtypes.index.vec(len(arg)), tuple(UOp.const(dtypes.index, x) if isinstance(x, int) else x for x in arg))) + if len(usrcs) == 0: ret = UOp(op, self.dtype, (self,), arg) + else: ret = UOp(op, self.dtype, (self,)+UOp.sink(*usrcs).simplify().src) + # for all movement ops, we check shape property + if ret.shape == self.shape and same_shape_noop: return self return ret - def forced_reshape(self, arg:tuple[sint, ...], **kwargs): return UOp(Ops.RESHAPE, kwargs.pop("dtype", self.dtype), src=(self,), arg=arg) + # in these four, if the shape doesn't change we can return self + def forced_reshape(self, arg:tuple[sint, ...]): return self._mop(Ops.RESHAPE, arg, same_shape_noop=False) + #def reshape(self, arg:tuple[sint, ...]): return self._mop(Ops.RESHAPE, arg, same_shape_noop=True) + #def expand(self, arg:tuple[sint, ...]): return self._mop(Ops.EXPAND, arg, same_shape_noop=True) + #def shrink(self, arg:tuple[tuple[sint, sint], ...]): return self._mop(Ops.SHRINK, arg, same_shape_noop=True) + def pad(self, arg:tuple[tuple[sint, sint], ...]): return self._mop(Ops.PAD, arg, same_shape_noop=True) - def reshape(self, arg:tuple[sint, ...]): return self._mop(Ops.RESHAPE, arg) - def expand(self, arg:tuple[sint, ...]): return self._mop(Ops.EXPAND, arg) - def shrink(self, arg:tuple[tuple[sint, sint], ...]): return self._mop(Ops.SHRINK, arg) - def pad(self, arg:tuple[tuple[sint, sint], ...]): return self._mop(Ops.PAD, arg) - def permute(self, arg:tuple[int, ...]): return self._mop(Ops.PERMUTE, arg) - def flip(self, arg:tuple[bool, ...]): return self._mop(Ops.FLIP, arg) + # in these two, we have custom logic to check if they are a no-op + #def permute(self, arg:tuple[int, ...]): return self._mop(Ops.PERMUTE, arg, same_shape_noop=False) if arg != tuple(range(len(self.shape))) else self + #def flip(self, arg:tuple[bool, ...]): return self._mop(Ops.FLIP, arg, same_shape_noop=False) if any(arg) and len(arg) == len(self.shape) else self # *** uop UNIQUE *** # TODO: use this in Buffer unique_num = itertools.count(0) @staticmethod - def unique(): return UOp(Ops.UNIQUE, arg=next(UOp.unique_num)) + def unique(arg:int|None=None): return UOp(Ops.UNIQUE, arg=next(UOp.unique_num) if arg is None else arg) # *** uop Buffer stuff *** @staticmethod - def new_buffer(device:str|tuple[str, ...], size:int, dtype:DType): return UOp(Ops.BUFFER, dtype, (UOp.unique(), UOp(Ops.DEVICE, arg=device)), size) + def new_buffer(device:str|tuple[str, ...], size:int, dtype:DType, num=None): + return UOp(Ops.BUFFER, dtype, (UOp.unique(num), UOp(Ops.DEVICE, arg=device)), size) @property def device(self) -> str|tuple[str, ...]: return cast(str|tuple[str, ...], unwrap(self._device)) - @functools.cached_property + @recursive_property def _device(self) -> str|tuple[str, ...]|None: if self.op is Ops.DEVICE: return self.arg if self.op is Ops.BUFFERIZE: return self.arg.device + if self.op is Ops.AFTER: return self.src[0]._device if self.op is Ops.MSELECT: assert isinstance(self.src[0].device, tuple), "mselect must be on tuple device" return self.src[0].device[self.arg] @@ -478,8 +597,8 @@ class UOp(MathTrait, metaclass=UOpMetaClass): if self.op is Ops.BUFFER: return self if self.op is Ops.MSELECT: return self.src[0].buf_uop.mselect(self.arg) if self.op is Ops.MSTACK: return UOp(Ops.MSTACK, self.dtype, src=tuple(x.buf_uop for x in self.src)) - assert self.op is Ops.ASSIGN, f"must be ASSIGN {self.op}" - return self.src[0].base + assert self.base.op is Ops.AFTER, f"must be AFTER {self.base.op}" + return self.base.src[0].buf_uop.base def as_buf(self) -> UOp: if self.op is Ops.MSELECT: return self.src[0].as_buf().mselect(self.arg) @@ -489,11 +608,21 @@ class UOp(MathTrait, metaclass=UOpMetaClass): while len(s.src) and s.op not in {Ops.BUFFER, Ops.BUFFERIZE, Ops.MSTACK}: s = s.src[0] return s + def buf_target(self) -> UOp: + # the buffer that's being loaded from or store to + match self.op: + case Ops.DEFINE_GLOBAL | Ops.DEFINE_LOCAL | Ops.DEFINE_REG: return self + case Ops.AFTER | Ops.INDEX | Ops.STORE | Ops.LOAD: return self.src[0].buf_target() + case Ops.VECTORIZE: + assert all_same(self.src) + return self.src[0].buf_target() + case _: raise RuntimeError(f"buf_target called on non load/index/store {self.op}") + @property def buffer(self) -> Buffer|MultiBuffer: from tinygrad.device import Buffer, MultiBuffer if self is not self.base: - assert unwrap(self.st).contiguous, "VIEW only works here if it's contiguous" + assert self.op is Ops.RESHAPE, f"can only be RESHAPE {self}" return self.src[0].buffer if self.op is Ops.MSELECT: ret = self.src[0].buffer @@ -537,6 +666,9 @@ class UOp(MathTrait, metaclass=UOpMetaClass): def unbind(self) -> tuple[Variable, int]: assert self.op is Ops.BIND and self.src[0].op is Ops.DEFINE_VAR and self.src[1].op is Ops.CONST, f"can't unbind {self}" return self.src[0], self.src[1].arg + def unbind_all(self) -> tuple[UOp, dict[Variable, int]]: + ret:dict[Variable, int] = {} + return graph_rewrite(self, pm_unbind, ctx=ret), ret @property def val(self) -> int: return self.unbind()[1] def vars(self) -> set[UOp]: @@ -545,8 +677,7 @@ class UOp(MathTrait, metaclass=UOpMetaClass): all_vars = set([x for x in self.toposort() if x.op is Ops.DEFINE_VAR]) return bound_vars.union(set([x for x in all_vars if x not in bound_var_base])) def variables(self) -> list[Variable]: - st_vars: list[set[Variable]] = [x.arg.vars() for x in self.toposort() if x.op is Ops.VIEW] - return sorted(set.union(*st_vars, set([x.unbind()[0] if x.op is not Ops.DEFINE_VAR else x for x in self.vars()])), key=lambda v: v.arg) + return sorted(set([x.unbind()[0] if x.op is not Ops.DEFINE_VAR else x for x in self.vars()]), key=lambda v: v.arg) # *** uop symbolic stuff *** @@ -573,32 +704,6 @@ class UOp(MathTrait, metaclass=UOpMetaClass): if (d0:=self.src[0].divides(v)) is not None: return d0 * self.src[1] if (d1:=self.src[1].divides(v)) is not None: return self.src[0] * d1 return None # generic None if we aren't sure - def factor(self, *factors: UOp) -> UOp: - # factor out expr from self if possible, might return self - # (1400*a + 2800*b + c).factor(a+2*b) -> 1400*(a+2*b) + c - if self.dtype in dtypes.floats: return self - if self.op is Ops.ADD: - factored = [] - # dict of {term: const_factor}, i.e. {a: 1, b: 2} - remainders = dict([(u.divides(f:=u.const_factor()).simplify(),f) for u in self.split_uop(Ops.ADD)]) - for fac in factors: - if fac.dtype not in (dtypes.index,)+dtypes.ints: continue - fac_terms = dict((u.divides(f:=u.const_factor()).simplify(),f) for u in fac.split_uop(Ops.ADD)) - factored_terms = {k:v for k,v in remainders.items() if k in fac_terms} - new_remainders = {k:v for k,v in remainders.items() if k not in fac_terms} - - if any(u not in factored_terms for u in fac_terms) or any(factored_terms[u]%fac_terms[u]!=0 for u in fac_terms) or not \ - all_same(mul:=[factored_terms[u]//fac_terms[u] for u in fac_terms]): - continue - - remainders = new_remainders - factored.append(fac*mul[0]) - if not factored: return self - start = functools.reduce(operator.add, factored) - return sum([k.factor(*factors)*v for k,v in remainders.items()], start=start) - - if self.op not in GroupOp.ALU|{Ops.VECTORIZE}: return self - return self.replace(src=tuple(s.factor(*factors) for s in self.src)) def pop_const(self, op=Ops.ADD) -> tuple[UOp, ConstType]: return (self.src[0], self.src[1].arg) if self.op is op and self.src[1].op is Ops.CONST else (self, identity_element(op, self.dtype)) @staticmethod @@ -608,14 +713,16 @@ class UOp(MathTrait, metaclass=UOpMetaClass): return math.prod([*count.elements(), terms[0].const_like(math.gcd(*factors))]) # put the const at the top def divide_exact(self, v:UOp) -> UOp|None: if self is v: return self.const_like(1) - if self.op is Ops.ADD: return None if (s0:=self.src[0].divide_exact(v)) is None or (s1:=self.src[1].divide_exact(v)) is None else s0+s1 if v.op is Ops.CONST: return self.divides(v.arg) + if self.op is Ops.ADD: return None if (s0:=self.src[0].divide_exact(v)) is None or (s1:=self.src[1].divide_exact(v)) is None else s0+s1 if self.op is Ops.MUL: (fac, const), (div_fac, div_const) = self.pop_const(Ops.MUL), v.pop_const(Ops.MUL) new_count = collections.Counter(fac.split_uop(Ops.MUL)) new_count.subtract(div_fac.split_uop(Ops.MUL)) if const%div_const==0 and all(v>=0 for v in new_count.values()): return math.prod([*new_count.elements(), self.const_like(const//div_const)]) return None # generic None if we aren't sure + def sum(self:UOp, *uops:UOp) -> UOp: return functools.reduce(operator.or_ if self.dtype is dtypes.bool else operator.add, uops, self) + def prod(self:UOp, *uops:UOp) -> UOp: return functools.reduce(operator.and_ if self.dtype is dtypes.bool else operator.mul, uops, self) @property def vmin(self) -> ConstType: return self._min_max[0] @property @@ -626,7 +733,7 @@ class UOp(MathTrait, metaclass=UOpMetaClass): (s0_vmin, s0_vmax), (s1_vmin, s1_vmax) = self.src[0]._min_max, self.src[1]._min_max if self.op is Ops.ADD: return s0_vmin+s1_vmin, s0_vmax+s1_vmax if self.op is Ops.SUB: return s0_vmin-s1_vmax, s0_vmax-s1_vmin - if self.op is Ops.AND and s1_vmin == s1_vmax and s0_vmin >= 0 and s1_vmin >= 0: return min(0, s0_vmin), min(s0_vmax, s1_vmax) + if self.op is Ops.AND and dtypes.is_int(self.dtype) and s1_vmin == s1_vmax >= 0 and s0_vmin >= 0: return min(0, s0_vmin), min(s0_vmax, s1_vmax) if self.op is Ops.MUL: return min(vals:=(s0_vmin*s1_vmin, s0_vmin*s1_vmax, s0_vmax*s1_vmin, s0_vmax*s1_vmax)), max(vals) # SHL/SHR on consts only if self.op is Ops.SHL and s1_vmin == s1_vmax and all_int(t:=(s0_vmin, s0_vmax, s1_vmin)): return t[0] << t[2], t[1] << t[2] @@ -641,9 +748,8 @@ class UOp(MathTrait, metaclass=UOpMetaClass): if self.op is Ops.MAX: return max(s0_vmin, s1_vmin), max(s0_vmax, s1_vmax) if self.op is Ops.CMPLT: return (s0_vmax str: - with Context(TRACK_MATCH_STATS=0, SPEC=0): - ret = graph_rewrite(self.simplify() if simplify else self, renderer if pm is None else pm) - return ret.arg if ret.op is Ops.NOOP else str(ret) + ctx: dict[UOp, str] = {} + pm = renderer if pm is None else pm + for u in (s:=self.simplify() if simplify else self).toposort(): + ctx[u] = cast(str, pm.rewrite(u, ctx=ctx)) + return ctx[s] + + def pyrender(self): return pyrender(self) + + # *** uop high level syntactic sugar *** + + @staticmethod + def placeholder(shape:tuple[int, ...], dtype:DType, slot:int, addrspace=AddrSpace.GLOBAL): + lookup = {AddrSpace.GLOBAL: Ops.DEFINE_GLOBAL, AddrSpace.LOCAL: Ops.DEFINE_LOCAL, AddrSpace.REG: Ops.DEFINE_REG} + ret = UOp(lookup[addrspace], dtype.ptr(prod(shape), addrspace), arg=slot) + if len(shape) > 1: ret = ret.reshape(shape) + return ret + def placeholder_like(self, slot:int): + assert all_int(self.shape), "no placeholder-like on symbolic shape" + return UOp.placeholder(self.shape, self.dtype, slot) + + # set is store+end+after + def set(self:UOp, val:UOp|ConstType, end:UOp|tuple[UOp, ...]|list[UOp]=()) -> UOp: + return self.src[0].after(self.store(val).end(*argfix(end))) + + def custom_kernel(*srcs:UOp, fxn:Callable, grad_fxn:Callable|None=None) -> list[UOp]: + placeholders = [UOp.placeholder_like(s, slot=i) for i,s in enumerate(srcs)] + contig_srcs = tuple(x.contiguous() for x in srcs) + kernel = UOp(Ops.KERNEL, src=tuple(x.base for x in contig_srcs), arg=Kernel(fxn(*placeholders), grad_fxn=grad_fxn)) + return [s.after(kernel) for s in contig_srcs] @dataclass(frozen=True) class KernelInfo: @@ -685,6 +817,12 @@ class KernelInfo: @property def function_name(self): return to_function_name(self.name) +@dataclass(frozen=True) +class Kernel: + ast: UOp + metadata: tuple[Metadata, ...] = () + grad_fxn: Callable|None = None + # ******** ops in python ******** def safe_exp2(x): @@ -698,7 +836,7 @@ def safe_pow(x, y): python_alu: dict[Ops, Callable] = { Ops.LOG2: lambda x: math.log2(x) if x > 0 else -math.inf if x == 0 else math.nan, Ops.EXP2: safe_exp2, - Ops.SQRT: lambda x: math.sqrt(x) if x >= 0 else math.nan, Ops.RECIP: lambda x: 1/x if x != 0 else math.copysign(math.inf, x), + Ops.SQRT: lambda x: math.sqrt(x) if x >= 0 else math.nan, Ops.RECIPROCAL: lambda x: 1/x if x != 0 else math.copysign(math.inf, x), Ops.SIN: lambda x: math.sin(x) if not math.isinf(x) else math.nan, Ops.POW: safe_pow, Ops.TRUNC: math.trunc, Ops.NEG: operator.neg, Ops.ADD: operator.add, Ops.SUB: operator.sub, Ops.MUL: operator.mul, Ops.CMPNE: operator.ne, Ops.CMPLT: operator.lt, Ops.XOR: operator.xor, Ops.OR: operator.or_, Ops.AND: operator.and_, Ops.SHR: operator.rshift, Ops.SHL: operator.lshift, Ops.MAX: max, @@ -714,9 +852,10 @@ def exec_alu(op:Ops, dtype:DType, operands, truncate_output=True): # ***** uop helpers ***** def print_uops(uops:list[UOp]): + uops_index = {u:i for i,u in enumerate(uops)} for i,u in enumerate(uops): - formatted_parents = [(uops.index(x) if x.op is not Ops.CONST else f"{x.arg}") if x in uops else "--" for x in u.src] - print(f"{i:4d} {str(u.op):20s}: {str(u.dtype):30s} " f"{str(formatted_parents):32s} {u.arg}") + formatted_srcs = [(uops_index[x] if x.op is not Ops.CONST else f"{x.arg}") if x in uops else "--" for x in u.src] + print(f"{i:4d} {str(u.op):20s}: {multirange_str(u.ranges, color=True, pad=10)} {str(u.dtype):40s} " f"{str(formatted_srcs):32s} {u.arg}") # ***** pattern matcher ***** @@ -728,15 +867,7 @@ def get_location() -> tuple[str, int]: frm = frm.f_back return frm.f_code.co_filename, frm.f_lineno -@functools.cache -def lines(fn) -> list[str]: - with open(fn) as f: return f.readlines() - -def printable(loc:tuple[str, int]) -> str: - try: return lines(loc[0])[loc[1]-1].strip() - except FileNotFoundError: return "" - -class UPat(MathTrait): +class UPat(OpMixin): __slots__ = ("op", "dtype", "arg", "name", "src") def __init__(self, op:Ops|tuple[Ops, ...]|set[Ops]|None=None, dtype:DType|tuple[DType, ...]|None=None, src:tuple[UPat, ...]|list[UPat]|UPat|None=None, arg:Any=None, @@ -772,14 +903,16 @@ class UPat(MathTrait): @staticmethod def any(*src): return UPatAny(src=src) def or_casted(self, name:str|None=None): return UPat.any(self if name is None else self.named(name), UPat(Ops.CAST, name=name, src=(self,))) + def or_after(self, name:str|None=None): + return UPat.any(self if name is None else self.named(name), UPat(Ops.AFTER, name=name, src=(self,), allow_any_len=True)) @staticmethod @functools.cache def var(name:str|None=None, dtype:DType|tuple[DType, ...]|None=None): return UPat(dtype=dtype, name=name) @staticmethod @functools.cache - def cvar(name:str|None=None, dtype:DType|tuple[DType, ...]|None=None, vec=True): - return UPat((Ops.CONST,Ops.VCONST) if vec else Ops.CONST, dtype, name=name) + def cvar(name:str|None=None, dtype:DType|tuple[DType, ...]|None=None, vec=True, arg=None): + return UPat((Ops.CONST,Ops.VCONST) if vec else Ops.CONST, dtype, name=name, arg=arg) @staticmethod def const(dtype:DType|tuple[DType, ...]|None, b:ConstType|InvalidType): return UPat(Ops.CONST, dtype=dtype, arg=b) @@ -788,8 +921,8 @@ class UPat(MathTrait): # copied from UOp def sink(self, *srcs:UPat|None, **kwargs): return UPat(Ops.SINK, dtypes.void, (self,)+tuple([x for x in srcs if x is not None]), **kwargs) - def index(self, idx:UPat, valid:UPat|None=None): return UPat(Ops.INDEX, self.dtype, (self,idx,valid) if valid is not None else (self,idx)) - def view(self, st=None, **kwargs): return UPat(Ops.VIEW, self.dtype, (self,), st, **kwargs) + def index(self, idx:UPat, valid:UPat|None=None, **kwargs): + return UPat(Ops.INDEX, self.dtype, (self,idx,valid) if valid is not None else (self,idx), **kwargs) def cast(self, dtype=None, **kwargs): return UPat(Ops.CAST, dtype, (self,), **kwargs) def bitcast(self, dtype=None): return UPat(Ops.BITCAST, dtype, (self,)) def gep(self, i:int|None=None, **kwargs): return UPat(Ops.GEP, None, (self,), (i,) if i is not None else None, **kwargs) @@ -797,23 +930,16 @@ class UPat(MathTrait): def store(self, *src:UPat, **kwargs): return UPat(Ops.STORE, self.dtype, (self,)+src, **kwargs) def assign(self, x:UPat, **kwargs): return UPat(Ops.ASSIGN, self.dtype, (self,x), **kwargs) def reduce(self, *src:UPat, **kwargs): return UPat(Ops.REDUCE, self.dtype, src=(self,)+src, **kwargs) - def fuse(self): return self.alu(Ops.FUSE) def broadcast(self, **kwargs): return UPat(Ops.VECTORIZE, self.dtype, src=self, **kwargs) - def or_broadcasted(self, **kwargs): return UPat.any(self, self.broadcast(**kwargs)) def contiguous(self, *args, **kwargs): return UPat(Ops.CONTIGUOUS, dtype=self.dtype, src=(self,)+args, **kwargs) + def after(self, *src:UPat, **kwargs): return UPat(Ops.AFTER, self.dtype, (self,)+src, **kwargs) + def end(self, *src:UPat, **kwargs): return UPat(Ops.END, self.dtype, (self,)+src, **kwargs) def const_like(self, b:ConstLike): return UPat.const(self.dtype, cast(ConstType, b)) def alu(self, op:Ops, *src:UPat): asrc = (self,)+src return UPat(op, dtypes.bool if op in {Ops.CMPLT, Ops.CMPNE} else asrc[-1].dtype, list(asrc) if op in GroupOp.Commutative else asrc) - def __repr__(self): - def rep(x): - form = "UPat(%s, %s, name=%s, dtype=%s, allow_any_len=%s, src=%s)" - return form % (None if x.op is None else ('(%s)'%', '.join(map(str, x.op))), x.arg, repr(x.name), - set(x.dtype) if x.dtype else None, not x.strict_length, "[%s]" if x.src and len(x.src)>1 else ("(%s)" if x.src else "%s")) - return pretty_print(self, rep, srcfn=lambda x:None if x.src is None else [next(x.src[0])] if isinstance(x.src[0], itertools.repeat) else x.src[0]) - def match(self:UPat, uop:UOp, store:dict[str, UOp]) -> list[dict[str, UOp]]: if (self.op is not None and uop.op not in self.op) or \ (self.name is not None and store.setdefault(self.name, uop) is not uop) or \ @@ -893,31 +1019,22 @@ class PatternMatcher: if (ret:=match(uop, ctx)) is not None and ret is not uop: return ret return None -# *** non-blocking UOp tracker *** - -ucount = itertools.count() -uop_number:weakref.WeakKeyDictionary[UOp, int] = weakref.WeakKeyDictionary() -uop_fields:dict[int, tuple] = {} -def track_uop(u:UOp): - if (cret:=uop_number.get(u)) is not None: return cret - uop_number[u] = num = next(ucount) - # KERNEL also has a UOp in the arg - arg = type(u.arg)(track_uop(u.arg.ast), u.arg.metadata) if u.op is Ops.KERNEL else u.arg - uop_fields[num] = (u.op, u.dtype, tuple(track_uop(s) for s in u.src), arg, u.tag)+((u.metadata,) if TRACEMETA>=2 else ()) - return num - # *** tracking pattern matcher *** TRACK_MATCH_STATS = ContextVar("TRACK_MATCH_STATS", 2 if VIZ else 0) match_stats:dict[UPat, list[int|float]] = dict() +# TRACK_MATCH_STATS>=2 or VIZ=1 saves all matches +ucount = itertools.count() +uop_fields:dict[int, tuple] = {} + @dataclass(frozen=True) class TrackedGraphRewrite: - loc:tuple[str, int] # location that called graph_rewrite - sink:int # the sink input to graph_rewrite - matches:list[tuple[int, int, tuple]] # before/after UOp, UPat location - name:str|None # optional name of the rewrite - depth:int # depth if it's a subrewrite + loc:tuple[str, int] # location that called graph_rewrite + sink:int # the sink input to graph_rewrite + matches:list[tuple[int, int, tuple, float]] # before/after UOp, UPat location and time + name:str # name of the rewrite + depth:int # depth if it's a subrewrite bottom_up:bool tracked_keys:list[TracingKey] = [] @@ -961,19 +1078,21 @@ def track_rewrites(name:Callable[..., str|TracingKey]|bool=True, replay:bool=Fal return _decorator active_rewrites:list[TrackedGraphRewrite] = [] -def track_matches(func): - def _track_func(*args, **kwargs): +def profile_matches(fxn:Callable): + def wrap(*args, **kwargs): + name = str(kwargs.get("name", None) or fxn.__name__) + assert args and isinstance(args[0], UOp), f"invalid match tracing inputs for {name} with {args}" if tracking:=(TRACK_MATCH_STATS >= 2): loc = ((frm:=sys._getframe(1)).f_code.co_filename, frm.f_lineno) depth = len(active_rewrites) - if not tracked_ctxs: add_trace_group(TracingKey(f"default {func.__name__}")) - tracked_ctxs[-1].append(ctx:=TrackedGraphRewrite(loc, track_uop(args[0]), [], kwargs.get("name", None), depth, kwargs.get("bottom_up", False))) + if not tracked_ctxs: add_trace_group(TracingKey(f"default {fxn.__name__}")) + tracked_ctxs[-1].append(ctx:=TrackedGraphRewrite(loc, args[0].trace_num, [], name, depth, kwargs.get("bottom_up", False))) active_rewrites.append(ctx) - with cpu_profile(kwargs.get("name", ""), "TINY", display=tracking): - ret = func(*args, **kwargs) + with cpu_profile(name, "TINY", display=tracking): + ret = fxn(*args, **kwargs) if tracking: active_rewrites.pop() return ret - return _track_func + return wrap class TrackedPatternMatcher(PatternMatcher): def rewrite(self, uop:UOp, ctx=None) -> UOp|None: @@ -987,20 +1106,23 @@ class TrackedPatternMatcher(PatternMatcher): continue match_stats[p][1] += 1 try: ret = match(uop, ctx) - except Exception as e: - if TRACK_MATCH_STATS >= 2 and active_rewrites and not isinstance(e, RewriteNotReady): - active_rewrites[-1].matches.append((track_uop(uop), track_uop(UOp(Ops.REWRITE_ERROR, src=uop.src, arg=str(sys.exc_info()[1]))), p.location)) + except Exception: + if TRACK_MATCH_STATS >= 2 and active_rewrites: + active_rewrites[-1].matches.append((uop.trace_num, UOp(Ops.REWRITE_ERROR,src=uop.src,arg=str(sys.exc_info()[1])).trace_num,p.location,0)) raise if ret is not None and ret is not uop: match_stats[p][0] += 1 match_stats[p][3] += (et:=time.perf_counter()-st) if TRACK_MATCH_STATS >= 3: print(f"{et*1e6:7.2f} us -- ", printable(p.location)) if TRACK_MATCH_STATS >= 2 and isinstance(ret, UOp) and active_rewrites: - active_rewrites[-1].matches.append((track_uop(uop), track_uop(ret), p.location)) + active_rewrites[-1].matches.append((uop.trace_num, ret.trace_num, p.location, et)) return ret match_stats[p][2] += time.perf_counter()-st return None +@dataclass(frozen=True) +class RewriteTrace: keys:list[TracingKey]; rewrites:list[list[TrackedGraphRewrite]]; uop_fields:dict[int, tuple] # noqa: E702 + if TRACK_MATCH_STATS or PROFILE: PatternMatcher = TrackedPatternMatcher # type: ignore import atexit @@ -1009,7 +1131,7 @@ if TRACK_MATCH_STATS or PROFILE: if TRACK_MATCH_STATS >= 2: with open(fn:=temp("rewrites.pkl", append_user=True), "wb") as f: print(f"rewrote {len(tracked_ctxs)} graphs and matched {sum(len(r.matches) for x in tracked_ctxs for r in x)} times, saved to {fn}") - pickle.dump([(tracked_keys, tracked_ctxs, uop_fields)], f) + pickle.dump(RewriteTrace(tracked_keys, tracked_ctxs, uop_fields), f) if VIZ: return launch_viz("VIZ", temp("rewrites.pkl", append_user=True)) if getenv("PRINT_MATCH_STATS", TRACK_MATCH_STATS.value): ret = [0,0,0.0,0.0] @@ -1023,14 +1145,15 @@ if TRACK_MATCH_STATS or PROFILE: def launch_viz(env_str:str, data:str): os.environ[env_str] = "0" os.environ[f"{env_str}_DATA"] = data - if not int(os.getenv("VIZ", "0")) and not int(os.getenv("PROFILE", "0")) and not int(os.getenv("SQTT", "0")): + if not int(os.getenv("VIZ", "0")) and not int(os.getenv("PROFILE", "0")) and not CI: args = ['--kernels', getenv("VIZ_DATA", "")] if getenv("VIZ_DATA", "") else [] args += ['--profile', getenv("PROFILE_DATA", "")] if getenv("PROFILE_DATA", "") else [] - os.execv(sys.executable, [sys.executable] + [os.path.join(os.path.dirname(__file__), "../", "viz", "serve.py")] + args) + viz_path = pathlib.Path(__file__).resolve().parent.parent / "viz" / "serve.py" + os.execv(sys.executable, [sys.executable, viz_path.as_posix()] + args) # *** simple graph rewrite engine *** -class RewriteNotReady(Exception): pass +with Context(SPEC=0): SENTINEL = UOp(Ops.SENTINEL) class BottomUpGate(Exception): pass class RewriteContext: def __init__(self, pm, bpm, ctx=None): @@ -1042,45 +1165,54 @@ class RewriteContext: self.replace: dict[UOp, UOp] = {} def cached_pm_rewrite(self, x:UOp): - if (ret:=self.pm_cache.get(x,False)) is not False: return ret + if (ret:=self.pm_cache.get(x,SENTINEL)) is not SENTINEL: return ret ret = self.pm_cache[x] = cast(PatternMatcher, self.pm).rewrite(x, self.ctx) return ret def cached_bpm_rewrite(self, x:UOp): - if (ret:=self.bpm_cache.get(x,False)) is not False: return ret + if (ret:=self.bpm_cache.get(x,SENTINEL)) is not SENTINEL: return ret ret = self.bpm_cache[x] = cast(PatternMatcher, self.bpm).rewrite(x, self.ctx) return ret def unified_rewrite(self, root:UOp) -> UOp: stack: collections.deque[tuple[UOp, int, UOp]] = collections.deque([(root, 0, root)]) on_stack = {root} # all UOps either on the stack or in self.replace, i.e. dont have to be placed again + REWRITE_STACK_LIMIT = getenv("REWRITE_STACK_LIMIT", 250000) while stack: - if len(stack) > getenv("REWRITE_STACK_LIMIT", 250000): raise RuntimeError("infinite loop in graph_rewrite (stack too big)") + if len(stack) > REWRITE_STACK_LIMIT: raise RuntimeError("infinite loop in graph_rewrite (stack too big)") n, stage, new_n = stack.pop() if n in self.replace: continue # skip any nodes we have seen - try: - if stage == 0: + if stage == 0: + # if bottom up, we rewrite this node early. in both cases, we add its srcs to the stack + if self.bpm is not None: + # apply rewrite rules until a fixed point is reached. may return `uop` itself if PatternMatcher doesn't match + test_n: UOp|None = n + seen = set() try: - # if bottom up, we rewrite this node early. in both cases, we add its parents to the stack - if self.bpm is not None: - # apply rewrite rules until a fixed point is reached. may return `uop` itself if PatternMatcher doesn't match - test_n: UOp|None = n - seen = set() - while test_n is not None: - if test_n in seen: raise RuntimeError("infinite loop in fixed_point_rewrite") - seen.add(test_n) - new_n, test_n = test_n, self.cached_bpm_rewrite(test_n) - stack.append((n, 1, new_n)) - for x in reversed(new_n.src): - if x in on_stack: continue - stack.append((x, 0, x)) - on_stack.add(x) - # if the bpm matching raised a gate, we are done with this node and dont continue down the srcs - except BottomUpGate: self.replace[n] = new_n - elif stage == 1: - try: new_src = tuple([self.replace[x] for x in new_n.src]) - except KeyError: raise RewriteNotReady - if new_src == new_n.src: + while test_n is not None: + if test_n in seen: raise RuntimeError("infinite loop in fixed_point_rewrite") + seen.add(test_n) + new_n, test_n = test_n, self.cached_bpm_rewrite(test_n) + except BottomUpGate: + # if the bpm matching raised a gate, we are done with this node and dont continue down the srcs + self.replace[n] = unwrap(test_n) + continue + stack.append((n, 1, new_n)) + for x in reversed(new_n.src): + if x in on_stack: continue + stack.append((x, 0, x)) + on_stack.add(x) + elif stage == 1: + tmp = [] + for x in new_n.src: + if (rx:=self.replace.get(x, SENTINEL)) is SENTINEL: + # if some new sources aren't ready, we try this again later. happens with on_stack, maybe should remove? + stack.appendleft((n, 1, new_n)) + break + tmp.append(rx) + else: + # in stage 1, once all srcs are rewritten, rebuild (if changed) or run top-down rewrite + if (new_src:=tuple(tmp)) == new_n.src: # if top down, do the rewrite. if no rewrite or bottom up, we are done rewriting this node so we add it to the dict if self.pm is None or (new_src_n:=self.cached_pm_rewrite(new_n)) is None: self.replace[n] = new_n @@ -1091,21 +1223,22 @@ class RewriteContext: # trigger a rewrite of new_src_n, then after that rewrite is done, link it back to n stack.append((n, 2, new_src_n)) stack.append((new_src_n, 0, new_src_n)) + else: + # in stage 2, we link the result of new_n to the result of n + if (replaced_new_n:=self.replace.get(new_n, SENTINEL)) is SENTINEL: + # not ready, try the link later + stack.appendleft((n, 2, new_n)) else: - # in stage 2, we link the result of new_n to the result of n - try: self.replace[n] = self.replace[new_n] - except KeyError: raise RewriteNotReady - except RewriteNotReady: - # retry this later - stack.appendleft((n, stage, new_n)) + # otherwise we are done + self.replace[n] = replaced_new_n return self.replace[root] -@track_matches +@profile_matches def graph_rewrite(sink:UOp, pm:PatternMatcher, ctx=None, bottom_up=False, name=None, bpm=None) -> UOp: rewrite_ctx = RewriteContext(pm if not bottom_up else None, pm if bottom_up else bpm, ctx) return rewrite_ctx.unified_rewrite(sink) -@track_matches +@profile_matches def graph_rewrite_map(sink:UOp, pm:PatternMatcher, ctx=None, bottom_up=False, name=None, bpm=None, input_map:dict[UOp, UOp]|None=None, ) -> dict[UOp, UOp]: rewrite_ctx = RewriteContext(pm if not bottom_up else None, pm if bottom_up else bpm, ctx) @@ -1117,7 +1250,7 @@ def graph_rewrite_map(sink:UOp, pm:PatternMatcher, ctx=None, bottom_up=False, na for k,v in input_map.items(): new_map[k] = new_map.get(v,v) return new_map -def sint_to_uop(x:sint) -> UOp: return UOp.const(dtypes.index, x) if isinstance(x, int) else x.cast(dtypes.index) +def sint_to_uop(x:sint, dtype=dtypes.index) -> UOp: return UOp.const(dtype, x) if isinstance(x, int) else x.cast(dtype) def select_dtype(u): return (dtypes.long if u.overflows(dtypes.int32) else dtypes.int).vec(u.dtype.count) pm_lower_index_dtype = PatternMatcher([ @@ -1136,82 +1269,155 @@ pm_lower_index_dtype = PatternMatcher([ (UPat(Ops.BIND, src=(UPat.var("var").cast(dtypes.index), UPat.cvar("val").cast(dtypes.index))), lambda var,val: var.bind(val).cast(dtypes.index)), (UPat(Ops.CAST, src=(UPat(name="x").cast(dtypes.index),), name="c"), lambda x,c: x.cast(c.dtype)), # lower Invalid - (UPat.var("buf").index(UPat.var("cond").where(UPat.var("idx"), UPat(Ops.CONST, arg=Invalid))), lambda buf,idx,cond: buf.index(idx, cond)), + (UPat.var("buf").index(UPat.var("cond").where(UPat.var("idx"), UPat(Ops.CONST, arg=Invalid))), lambda buf,idx,cond: buf.index(idx, cond, ptr=True)), # remove hanging casts - (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx", dtypes.ints).cast()),), lambda buf,idx: buf.index(idx)), - (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx", dtypes.ints).cast(), UPat.var("valid"))), lambda buf,idx,valid: buf.index(idx, valid)), + (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx", dtypes.ints).cast()),), lambda buf,idx: buf.index(idx, ptr=True)), + (UPat(Ops.INDEX, src=(UPat.var("buf"), UPat.var("idx", dtypes.ints).cast(), UPat.var("valid"))), + lambda buf,idx,valid: buf.index(idx, valid, ptr=True)), (UPat((Ops.STORE, Ops.LOAD), src=(UPat(), UPat(), UPat().cast(dtypes.index)), allow_any_len=True, name="s"), lambda s: s.replace(src=s.src[:2]+tuple(u.src[0] for u in s.src[2:]))), - (UPat((Ops.SINK, Ops.NOOP), src=UPat().cast(dtypes.index), name="n"), lambda n: n.replace(src=tuple(s.src[0] for s in n.src))), + (UPat((Ops.SINK, Ops.NOOP, Ops.END), name="n"), + lambda n: n.replace(src=tuple(s.src[0] if s.op is Ops.CAST and s.dtype == dtypes.index else s for s in n.src))), ]) def _index_to_concrete_int(u:UOp): return graph_rewrite(u.sink(), pm_lower_index_dtype).src[0] _substitute = PatternMatcher([(UPat(tuple(Ops), name="x"), lambda ctx,x: ctx.get(x,None))]) +_remove_all_tags = PatternMatcher([(UPat(GroupOp.All, name="x"), lambda x: x.replace(tag=None) if x.tag is not None else None)]) + +def do_unbind(ctx:dict[Variable, int], x:UOp): + v,i = x.unbind() + ctx[v] = i + return v +pm_unbind = PatternMatcher([(UPat(Ops.BIND, name="x"), do_unbind)]) # for debug syms = { Ops.ADD: "+", Ops.SUB: "-", Ops.IDIV: "//", Ops.MOD: "%", Ops.SHL: "<<", Ops.SHR: ">>", Ops.MUL: "*", Ops.CMPLT: "<", Ops.CMPNE: "!=", Ops.AND: "&", Ops.OR: "|", Ops.XOR: "^"} +# comparison operators are not in here because they are chained in python, not left-associative +precedence = {Ops.MUL:1, Ops.IDIV:1, Ops.MOD:1, Ops.ADD:2, Ops.SUB:2, Ops.SHL:3, Ops.SHR:3, Ops.AND:4, Ops.XOR:5, Ops.OR:6} +def strip_binary_parens(x:UOp, left:str, right:str, code_for_op) -> str: + if x.op not in precedence: return code_for_op(left, right) + return code_for_op(strip_parens(left) if precedence.get(x.src[0].op,99)<=precedence[x.op] else left, strip_parens(right) if + precedence.get(x.src[1].op,99) 1 else '')+(', dtype='+str(x.dtype) if x.dtype is not dtypes.index else '')+")"), + # TODO: index shouldn't mismatch dtype + (UPat(Ops.INDEX, src=(UPat(), UPat()), allow_any_len=True, name="x"), lambda ctx,x: + f"{ctx[x.src[0]]}.index({ctx[x.src[1]]}, "+(f"{ctx[x.src[2]]}, " if len(x.src) > 2 else "")+ + (f"dtype={x.dtype})" if x.src[0].dtype != x.dtype else "ptr=True)") if x.src[0].dtype.base != x.dtype else None), + # TODO: fix forced_reshape + (UPat(Ops.RESHAPE, name="x"), lambda ctx,x: f"{ctx[x.src[0]]}.forced_reshape({render_marg(ctx,x)})" if x.src[0].shape == x.shape else None), + (UPat(GroupOp.Movement, name="x"), lambda ctx,x: f"{ctx[x.src[0]]}.{x.op.name.lower()}({render_marg(ctx,x)})"), + # NOTE: CMPNE doesn't work cause there's no __rne__ + (UPat(set(syms.keys())-{Ops.SUB, Ops.CMPNE}, src=(UPat(Ops.CONST, name="y"), UPat(name="z")), name="x"), + lambda ctx,x,y,z: strip_binary_parens(x, str(y.arg), ctx[z], lambda a,b: f"({a}{syms[x.op]}{b})")), + # NOTE: sub doesn't work cause it's written as add/mul + (UPat(set(syms.keys())-{Ops.SUB}, src=(UPat(name="y"), UPat(Ops.CONST, name="z")), name="x"), lambda ctx,x,y,z: + strip_binary_parens(x, ctx[y], str(z.arg), lambda a,b: f"({a}{syms[x.op]}{b})")), + (UPat(set(syms.keys())-{Ops.SUB}, name="x"), lambda ctx,x: + strip_binary_parens(x, ctx[x.src[0]], ctx[x.src[1]], lambda a,b: f"({a}{syms[x.op]}{b})")), + (UPat(sugar, src=(), name="x"), lambda x: f"UOp.{x.op.name.lower()}("+', '.join(([f'arg={repr(x.arg)}'] if x.arg is not None else []))+")"), + (UPat(sugar, name="x"), lambda ctx,x: f"{ctx[x.src[0]]}.{x.op.name.lower()}("+', '.join([ctx[y] for y in x.src[1:]] + \ + ([f'arg={repr(x.arg)}'] if x.arg is not None else []))+")"), ]) -sugar = { Ops.SINK: "sink", Ops.STORE: "store", Ops.LOAD: "load", Ops.SQRT: "sqrt", Ops.INDEX: "index", Ops.REDUCE: "reduce", - Ops.WHERE: "where", Ops.RECIP: "reciprocal", Ops.EXP2: "exp2", Ops.LOG2: "log2", Ops.SIN: "sin"} -pm_pyrender = PatternMatcher([ - (UPat(Ops.CONST, src=(UPat(Ops.NOOP),), name="x"), lambda x: UOp(Ops.NOOP, arg=f"UOp.const({x.dtype}, {x.arg}, src={x.src[0].arg})")), - (UPat(Ops.CONST, name="x"), lambda x: UOp(Ops.NOOP, arg=f"UOp.const({x.dtype}, {x.arg})")), - (UPat(Ops.CAST, src=(UPat(Ops.NOOP),), name="x"), lambda x: UOp(Ops.NOOP, arg=f"{x.src[0].arg}.cast({x.dtype})")), - (UPat(Ops.BITCAST, src=(UPat(Ops.NOOP),), name="x"), lambda x: UOp(Ops.NOOP, arg=f"{x.src[0].arg}.bitcast({x.dtype})")), - (UPat({Ops.MAX, Ops.THREEFRY, Ops.CMPLT, Ops.CMPNE, Ops.POW}, src=UPat(Ops.NOOP), name="x"), - lambda x: UOp(Ops.NOOP, arg=f"{x.src[0].arg}.alu({x.op}, {x.src[1].arg})")), - (UPat(Ops.RANGE, src=(UPat(Ops.NOOP),), name="x"), lambda x: - UOp(Ops.NOOP, arg=f"UOp.range({x.src[0].arg}, {str(x.arg[0])}, {str(x.arg[1])})")), - (UPat(set(sugar.keys()), src=UPat(Ops.NOOP), name="x"), lambda x: UOp(Ops.NOOP, - arg=f"{x.src[0].arg}.{sugar[x.op]}({', '.join([y.arg for y in x.src[1:]] + ([f'arg={str(x.arg)}'] if x.arg is not None else []))})")), - (UPat(Ops.REDUCE_AXIS, src=(UPat(Ops.NOOP),), name="x"), - lambda x: UOp(Ops.NOOP, arg=f"{x.src[0].arg}.f({x.op}, arg=({', '.join([str(y) for y in x.arg])}))")), - (UPat(Ops.VALID, src=(UPat(Ops.NOOP),), name="x"), - lambda x: UOp(Ops.NOOP, arg=f"{x.src[0].arg}.f({x.op}, dtype=dtypes.bool)")), +# NOTE: you can remove pm_pyrender_extra and it'll still be correct +pm_pyrender = pm_pyrender_extra+PatternMatcher([ + (UPat(Ops.KERNEL, name="u"), lambda ctx,u: f"UOp(Ops.KERNEL, src={srcs(ctx,u.src)}, arg=Kernel({ctx[u.arg.ast]}(), {u.arg.metadata}))"), + (UPat(GroupOp.All, name="u"), lambda ctx,u: f"UOp({u.op}, {u.dtype}, {srcs(ctx,u.src)}"+(f", {repr(u.arg)})" if u.arg is not None else ")")), ]) -@Context(SPEC=0) -def pyrender(ast:UOp) -> list[str]: - cmap = ast.get_children_map() - to_render = set() - for u in ast.toposort(): - if u.op is Ops.STORE: to_render.add(u.src[1]) - if len(cmap[u]) == 1 and u.op not in {Ops.DEFINE_GLOBAL, Ops.VIEW, Ops.LOAD} or u.op in {Ops.CONST}: continue - if u.op in {Ops.SINK, Ops.VIEW}: +def pyrender(ast:UOp) -> str: + lst = list(ast.toposort()) + + cmap = consumer_map_from_toposort(lst) + not_rendered = {Ops.CONST, Ops.VCONST, Ops.DEVICE} + always_rendered = {Ops.DEFINE_GLOBAL, Ops.LOAD, Ops.SPECIAL, Ops.RANGE, Ops.CONTIGUOUS, Ops.VECTORIZE, + Ops.BUFFER, Ops.COPY, Ops.KERNEL, Ops.WHERE, Ops.END, Ops.ASSIGN} + + to_render: set[UOp] = {ast} + for u in lst: + if u.op in {Ops.SINK}: for s in u.src: to_render.add(s) + if u.op is Ops.STORE: to_render.add(u.src[1]) + if u.op in {Ops.REDUCE, Ops.REDUCE_AXIS}: to_render.add(u.src[0]) + if u.op in not_rendered: continue + # checking the consumers is not enough, you have to make sure it's not used twice by the one consumer + if len(cmap[u]) == 1 and len([x for x in list(cmap[u].keys())[0].src if x is u]) == 1 and u.op not in always_rendered: continue to_render.add(u) - ret: list[str] = [] - rep: dict[UOp, UOp] = {} - for u in ast.toposort(): - if u not in to_render: continue - ret.append(f"c{len(ret)} = {u.substitute(rep).render(simplify=False, pm=pm_pyrender+renderer)}") - rep[u] = UOp(Ops.NOOP, arg=f"c{len(ret)-1}") - return ret[0:-1] + ["ast ="+ret[-1].split("=", 1)[1]] + + kernels: dict[UOp, tuple[str, str]] = {} + r: dict[UOp, str] = {} + ret: dict[str, str] = {} + for i,u in enumerate(lst): + if u.op is Ops.KERNEL: + if u.arg.ast not in kernels: + kernels[u.arg.ast] = (f"k{len(kernels)}", f"def k{len(kernels)}():\n " + pyrender(u.arg.ast).replace('\n', '\n ') + "\n return ast\n\n") + r[u.arg.ast] = kernels[u.arg.ast][0] + ren = cast(str, pm_pyrender.rewrite(u, ctx=r)) + assert isinstance(ren, str) + if u.tag is not None: ren += f".rtag({repr(u.tag)})" + if u not in to_render: r[u] = ren + else: + r[u] = f"c{i}" if u is not lst[-1] else "ast" + ret[r[u]] = ren + return ''.join([v[1] for v in kernels.values()]) + '\n'.join([f"{k} = {strip_parens(v)}" for k,v in ret.items()]) # *** what was symbolic.py *** diff --git a/tinygrad/uop/spec.py b/tinygrad/uop/spec.py index 16415ddc9d..2c4086fc15 100644 --- a/tinygrad/uop/spec.py +++ b/tinygrad/uop/spec.py @@ -1,61 +1,64 @@ -from typing import cast, Callable -from tinygrad.uop.ops import PatternMatcher, UPat, GroupOp, Ops, UOp, print_uops, python_alu, graph_rewrite, AxisType +import math +from typing import cast, Any +from tinygrad.uop.ops import PatternMatcher, UPat, GroupOp, Ops, UOp, print_uops, AxisType, KernelInfo, pyrender, Kernel from tinygrad.dtype import DType, ImageDType, dtypes, PtrDType, AddrSpace, Invalid -from tinygrad.helpers import all_same, prod, DEBUG, IGNORE_OOB, Context, cpu_profile, RANGEIFY -from tinygrad.shape.shapetracker import ShapeTracker -try: - import z3 - # older versions of z3 dont have some operators like & overloaded - if z3.get_version() < (4, 12, 4, 0): raise ImportError +from tinygrad.helpers import DEBUG, Context, prod, SPEC, Metadata +from tinygrad.uop.validate import validate_index - # IDIV is truncated division but z3 does euclidian division (floor if b>0 ceil otherwise); mod by power of two sometimes uses Ops.AND - def z3_cdiv(a, b):return z3.If((a<0), z3.If(0= 0, z3.ToInt(a), -z3.ToInt(-a)))} - def create_bounded(name:str, vmin, vmax, solver:z3.Solver) -> z3.ArithRef: - s = z3.Int(name, ctx=solver.ctx) - solver.add(vmin <= s, s <= vmax) - return s +# four specs: +# shared_spec -- usable anywhere +# tensor_spec -- usable in tensor graph +# kernel_spec -- usable in kernel passed into codegen +# program_spec -- usable in linearized program +# full_spec -- all uops ever created - # ctx is (solver, load_number_dict) - # each uop gets rewritten to NOOP(arg=(solver, z3_object)), the arg has the solver first due to UOpMetaClass caching. z3 objects from different - # contexts can have the same hash but error on comparison - z3_renderer = PatternMatcher([ - (UPat(Ops.SPECIAL, src=UPat(Ops.NOOP), name="x"), lambda x,ctx: UOp(Ops.NOOP, arg=(ctx[0],create_bounded(x.arg, 0, x.src[0].arg[1]-1, ctx[0])))), - (UPat(Ops.DEFINE_VAR, name="x"), lambda x,ctx: UOp(Ops.NOOP, arg=(ctx[0],create_bounded(x.arg[0], x.arg[1], x.arg[2], ctx[0])))), - (UPat(Ops.RANGE, name="x"), lambda x,ctx: UOp(Ops.NOOP, arg=(ctx[0],create_bounded(f"ridx{x.arg}", 0, x.src[0].arg[1]-1, ctx[0])))), - # loaded bools become a z3 int with min max of 0-1 - (UPat(Ops.LOAD, dtypes.ints+(dtypes.bool,), name="x"), lambda x,ctx: - UOp(Ops.NOOP, arg=(ctx[0],create_bounded(f"load{ctx[1].setdefault(x, len(ctx[1]))}", x.dtype.min, x.dtype.max, ctx[0]))).cast(x.dtype)), - (UPat(Ops.CONST, dtype=dtypes.ints+(dtypes.bool,dtypes.index), name="x"), - lambda x,ctx: UOp(Ops.NOOP, arg=(ctx[0],(z3.BoolVal if dtypes.is_bool(x.dtype) else z3.IntVal)(x.arg, ctx=ctx[0].ctx)))), - # z3 can cast from bool to int automatically - (UPat(Ops.CAST, dtype=dtypes.ints+(dtypes.index,), src=UPat(Ops.NOOP), name="x"), lambda x: x.src[0]), - (UPat(Ops.CAST, dtype=dtypes.bool, src=UPat(Ops.NOOP), name="x"), lambda x,ctx: UOp(Ops.NOOP, arg=(ctx[0], x.src[0].arg[1]!=0))), - # if the source of the cast is not a noop it means that it is a float and so we create a new variable - (UPat(Ops.CAST, dtype=dtypes.ints+(dtypes.index,), name="x"), lambda x,ctx: - UOp(Ops.NOOP, arg=(ctx[0], create_bounded(f"cast{ctx[1].setdefault(x, len(ctx[1]))}", x.dtype.min, x.dtype.max, ctx[0])))), - (UPat(Ops.CAST, dtype=dtypes.bool, name="x"), lambda x,ctx: - UOp(Ops.NOOP, arg=(ctx[0], z3.Bool(f"cast{ctx[1].setdefault(x, len(ctx[1]))}",ctx=ctx[0].ctx)))), - (UPat(GroupOp.ALU, src=UPat(Ops.NOOP), name="x"), lambda x,ctx: UOp(Ops.NOOP, arg=(ctx[0], z3_alu[x.op](*(s.arg[1] for s in x.src))))), - # A comparison between floats introduces a new bool variable - (UPat(GroupOp.Comparison, src=UPat(dtype=dtypes.floats), name="x"), lambda x,ctx: - UOp(Ops.NOOP, arg=(ctx[0], z3.Bool(f"float_cmp{ctx[1].setdefault(x, len(ctx[1]))}",ctx=ctx[0].ctx)))), - ]) +# *** these uops work anywhere *** - def uops_to_z3(solver, *uops: UOp) -> 'list[z3.ExprRef]': - with Context(TRACK_MATCH_STATS=0, SPEC=0): # cant pickle z3 objects, and these UOps don't follow spec - return [s.arg[1] for s in graph_rewrite(uops[0].sink(*uops[1:]), z3_renderer, ctx=(solver, {})).src] +shared_spec = PatternMatcher([ + (UPat(Ops.SINK, dtypes.void), lambda: True), # NOTE: for testing, we let sinks be anything - z3_imported = True -except (ImportError, AttributeError): z3_imported = False + # SENTINEL should never be anywhere + (UPat(Ops.SENTINEL), lambda: False), -buffer_spec = PatternMatcher([ + # CONST/DEFINE_VAR are everywhere + (UPat(Ops.CONST, src=(), name="x"), lambda x: type(x.arg) is type(dtypes.as_const(x.arg, x.dtype))), + (UPat(Ops.DEFINE_VAR, name="x"), lambda x: isinstance(x.arg[1], int) and isinstance(x.arg[2], int)), + + # ALUs: most ALUs have all matching dtypes, except CMPLT, CMPNE, and WHERE + (UPat(Ops.WHERE, name="w", src=(UPat(dtype=dtypes.bool), UPat.var("x"), UPat.var("y"))), lambda w,x,y: w.dtype == x.dtype == y.dtype), + (UPat((Ops.CMPLT, Ops.CMPNE, Ops.CMPEQ), dtype=dtypes.bool, src=(UPat.var("x"), UPat.var("y"))), lambda x,y: x.dtype.base == y.dtype.base), + # and SHL/SHR, the shift distance can be an int + (UPat((Ops.SHL, Ops.SHR), src=(UPat.var("x"), UPat.var("y")), name="a"), lambda a,x,y: a.dtype == x.dtype and y.dtype in (x.dtype, dtypes.uint)), + (UPat((Ops.IDIV, Ops.MOD), name="x"), lambda x: None if dtypes.is_int(x.dtype) else False), + (UPat(GroupOp.ALU, name="x"), lambda x: all(x.dtype.base == y.dtype.base for y in x.src)), + + # CAST + (UPat((Ops.BITCAST, Ops.CAST), src=(UPat(),), name="x"), lambda x: x.arg is None), + + # RANGE can be in the big graph now + (UPat(Ops.RANGE, src=(UPat.var("x"),), allow_any_len=True, name="rng"), lambda rng,x: + rng.dtype == x.dtype and isinstance(rng.arg, tuple) and len(rng.arg) >= 2 and \ + all(isinstance(ra, int) for ra in rng.arg[0:-1]) and isinstance(rng.arg[-1], AxisType)), + (UPat(Ops.INDEX, src=(UPat(),), allow_any_len=True, name="x"), lambda x: all(y.dtype == dtypes.index for y in x.src[1:]) or None), +]) + +# ***** UOp spec in the Tensor graph ***** + +movement_ops = PatternMatcher([ + (UPat((Ops.RESHAPE, Ops.EXPAND), name="mv", src=(UPat.var("x"), UPat(dtype=dtypes.index))), lambda mv,x: True), + (UPat((Ops.PAD, Ops.SHRINK), name="mv", src=(UPat.var("x"), UPat(dtype=dtypes.index), UPat(dtype=dtypes.index))), lambda mv,x: True), + (UPat((Ops.PERMUTE, Ops.FLIP), name="mv", src=(UPat.var("x"),)), lambda mv,x: isinstance(mv.arg, tuple)), + + # inputs to movement ops + (UPat((Ops.VECTORIZE, Ops.VCONST), dtype=dtypes.index), lambda: True), + (UPat({Ops.ADD, Ops.MUL, Ops.IDIV}, dtype=dtypes.index), lambda: True), + + # AFTER on Movement Op + (UPat(Ops.AFTER, src=(UPat(GroupOp.Movement),), allow_any_len=True), lambda: True), +]) + +_tensor_spec = PatternMatcher([ + # buffer spec (UPat(Ops.UNIQUE, dtypes.void, ()), lambda: True), (UPat(Ops.DEVICE, dtypes.void, (), name="d"), lambda d: isinstance(d.arg, str) or (isinstance(d.arg, tuple) and all(isinstance(s, str) for s in d.arg))), @@ -64,13 +67,9 @@ buffer_spec = PatternMatcher([ (UPat(Ops.BUFFER_VIEW, src=(UPat(Ops.BUFFER),), name="buf_view"), lambda buf_view: isinstance(buf_view.arg, tuple) and len(buf_view.arg) == 2 and all(isinstance(arg, (int, UOp)) for arg in buf_view.arg)), (UPat(Ops.BUFFER_VIEW, src=(UPat(Ops.MSTACK, src=UPat(Ops.BUFFER)),)), lambda: True), - # allow VIEW here. TODO: what views specifically are allowed? does this mess with gradient? - (UPat(Ops.VIEW), lambda: True), -]) -assign_spec = PatternMatcher([ - # KERNEL can attach to an ASSIGN to describe the compute required to realize a BUFFER - (UPat(Ops.KERNEL, src=UPat((Ops.BUFFER, Ops.BUFFER_VIEW, Ops.ASSIGN, Ops.MSELECT, Ops.MSTACK, Ops.BIND))), lambda: True), + # KERNEL can attach to an AFTER to describe the compute required to realize a BUFFER + (UPat(Ops.KERNEL, src=UPat((Ops.BUFFER, Ops.BUFFER_VIEW, Ops.AFTER, Ops.MSELECT, Ops.MSTACK, Ops.BIND, Ops.CONTIGUOUS))), lambda: True), # ASSIGN has a target and a value. It can also optionally depend on other assigns (UPat(Ops.ASSIGN, name="x"), lambda x: len(x.src) >= 2 and all(s.op is Ops.ASSIGN for s in x.src[2:])), @@ -80,33 +79,17 @@ assign_spec = PatternMatcher([ # MSTACK combines buffers into multi (UPat(Ops.MSTACK, name="x"), lambda x: all(isinstance(x.device, str) for x in x.src)), -]) - -# *** this is the spec of a Tensor in UOp *** - -tensor_uop_spec = buffer_spec+assign_spec+PatternMatcher([ - (UPat(GroupOp.Movement, name="mv", src=(UPat.var("x"),)), - # naturally correct - lambda mv,x: (isinstance(mv.arg, tuple) and mv.dtype == x.dtype) or - # "make things that can't be images not images" can change the buffer dtype - # this is fine as long as it's a realized buffer and base dtypes match. - ((isinstance(mv.dtype, ImageDType) or isinstance(x.dtype, ImageDType)) and x.dtype.base == mv.dtype.base and x.base.op is Ops.BUFFER)), - (UPat(Ops.VIEW, src=(UPat.var("x"),)), lambda x: x.base.op in {Ops.BUFFER, Ops.BUFFER_VIEW, Ops.ASSIGN, Ops.CONST, Ops.DEVICE}), # Tensor variable bindings (UPat(Ops.BIND, (dtypes.int,dtypes.index,), (UPat(Ops.DEFINE_VAR), UPat.cvar(dtype=(dtypes.int,dtypes.index,))), arg=None), lambda: True), - # Tensor const has a device and an unmasked ShapeTracker of stride 0 - # NOTE: variables in shape can cause multiple views in this ShapeTracker and other issues, see TestSymbolicJit.test_ones_sum - # TODO: remove after rangeify is default - (UPat(Ops.CONST, src=(UPat.any(UPat(Ops.VIEW, src=(UPat(Ops.DEVICE),), name="st"), - UPat(Ops.VIEW, src=(UPat(Ops.DEVICE), UPat(Ops.BIND)), name="st")),)), - lambda st: len(st.st.views) == 1 and all(v.mask is None for v in st.st.views)), + # device or unique (UPat(Ops.CONST, src=(UPat(Ops.DEVICE),)), lambda: True), + (UPat(Ops.CONST, src=(UPat(Ops.DEVICE), UPat(Ops.UNIQUE))), lambda: True), # DETACH and CONTIGUOUS change how we interpret the source UOp # CONTIGUOUS ensures the source UOp realizes - (UPat((Ops.DETACH, Ops.CONTIGUOUS, Ops.CONTIGUOUS_BACKWARD, Ops.FUSE), name="root", src=(UPat.var("x"),), arg=None), + (UPat((Ops.DETACH, Ops.CONTIGUOUS, Ops.CONTIGUOUS_BACKWARD), name="root", src=(UPat.var("x"),), arg=None), lambda root,x: root.dtype == x.dtype), # CONTIGUOUS with a range @@ -117,172 +100,118 @@ tensor_uop_spec = buffer_spec+assign_spec+PatternMatcher([ (UPat(Ops.COPY, name="copy", src=(UPat.var("x"), UPat(Ops.DEVICE)), arg=None), lambda copy,x: copy.dtype == x.dtype), (UPat(Ops.ALLREDUCE, name="red", src=(UPat.var("x"), UPat(Ops.DEVICE))), lambda red,x: red.dtype == x.dtype and isinstance(red.arg, Ops)), (UPat(Ops.MULTI, name="multi"), lambda multi: all(x.dtype == multi.dtype for x in multi.src) and isinstance(multi.arg, int)), -]) -# ***** uop type spec ***** + # REDUCE_AXIS is the reduce in the tensor graph + (UPat(Ops.REDUCE_AXIS, name="x"), lambda x: isinstance(x.arg, tuple) and len(x.arg) >= 2 and x.arg[0] in {Ops.ADD, Ops.MUL, Ops.MAX}), -def validate_index(idx:UOp, gate:UOp|None=None): - if gate is None: gate = UOp.const(dtypes.bool, True) - # TODO: check for overflow - if IGNORE_OOB or isinstance(idx.dtype, ImageDType) or (sz := idx.src[0].ptrdtype.size) == -1: return True - # We can use UOp min/max to do a faster check, but it can give false positive since its not an exact bound and doesn't consider the mask - if 0<=idx.src[1].vmin and idx.src[1].vmax= 4.12.4 is required for bounds checking, try IGNORE_OOB=0 or \"pip install 'z3-solver>=4.12.4\"") - solver = z3.Solver(ctx=z3.Context()) - z3_idx, z3_mask = uops_to_z3(solver, idx.src[1], mask) - solver.add(z3_mask) - with cpu_profile("validate index with z3", "TINY"): - if solver.check((z3_idx<0)|(sz<=z3_idx)) == z3.sat: - print(f"idx={idx.src[1].render(simplify=False)}") - print(f"mask & gate={mask.render(simplify=False)}") - print(f"# OUT OF BOUNDS ACCESS: at {solver.model()} INDEX not in 0 - {sz}\nconstraints = {solver}") - return False - return True +tensor_spec = PatternMatcher([ + # no tags allowed in tensor graph + (UPat(GroupOp.All, name="x"), lambda x: None if x.tag is None else False), +])+_tensor_spec -def validate_store(idx:UOp, val:UOp, gate:UOp|None=None): - if gate is None: gate = UOp.const(dtypes.bool, True) - if gate.op is Ops.IF: gate = gate.src[0] - # we need to find the implicit gates, inverse of delete_redundant_gates - for u in val.toposort(): - if u.op is Ops.IF: gate &= u.src[0] - return validate_index(idx, gate) +# ***** UOp spec in codegen shared between kernel and program ***** -index_pat = UPat(Ops.INDEX, name="idx").or_casted() - -# this is the matcher for the final rendered UOps -# matcher functions returns True or False (or None to not match) -spec = PatternMatcher([ +shared_codegen_spec = PatternMatcher([ + # DEFINEs (UPat(Ops.DEFINE_GLOBAL, name="x"), lambda x: isinstance(x.dtype, (PtrDType, ImageDType)) and x.dtype.addrspace == AddrSpace.GLOBAL), (UPat(Ops.DEFINE_LOCAL, name="x"), lambda x: isinstance(x.dtype, PtrDType) and x.dtype.addrspace == AddrSpace.LOCAL), - (UPat(Ops.DEFINE_REG, src=()), lambda: True), - (UPat(Ops.DEFINE_VAR, name="x"), lambda x: isinstance(x.arg[1], int) and isinstance(x.arg[2], int)), + (UPat(Ops.DEFINE_REG, src=(), name="x"), lambda x: isinstance(x.arg, int)), - (UPat(Ops.RANGE, src=(UPat.var("x"),), name="rng"), lambda rng,x: rng.dtype == x.dtype and isinstance(rng.arg, tuple) and len(rng.arg) >= 2 and \ - all(isinstance(ra, int) for ra in rng.arg[0:-1]) and isinstance(rng.arg[-1], AxisType)), - (UPat(Ops.SPECIAL, src=(UPat.var("x"),), name="s"), lambda s,x: s.dtype == x.dtype == dtypes.int32 and isinstance(s.arg, str)), + # allow AFTER on buffers, GROUP anywhere + (UPat(Ops.AFTER, src=(UPat(GroupOp.Defines|{Ops.AFTER}),), allow_any_len=True), lambda: True), + (UPat(Ops.GROUP, dtypes.void), lambda: True), - (UPat(Ops.VIEW, dtypes.void, src=(), name="x"), lambda x: isinstance(x.arg, ShapeTracker)), - (UPat(Ops.VIEW, src=(UPat.var("src"),), name="x"), - lambda x,src: isinstance(x.arg, ShapeTracker) and src.op is not Ops.STORE and x.dtype.base == src.dtype.base), + # RANGE/SPECIAL define loops, END closes them + (UPat(Ops.END, src=(UPat(), UPat(Ops.RANGE)), dtype=dtypes.void), lambda: True), - (UPat(Ops.VALID, dtypes.bool, (UPat(Ops.VIEW),)), lambda: True), - (UPat(Ops.CONST, src=(), name="x"), lambda x: type(x.arg) is type(dtypes.as_const(x.arg, x.dtype))), + # WMMA has a + (UPat(Ops.WMMA, src=(UPat(), UPat(), UPat()), name="x"), lambda x: isinstance(x.arg, tuple) and len(x.arg) == 8), - # early LOAD has a - (UPat(Ops.LOAD, src=(UPat(Ops.VIEW, src=(UPat(GroupOp.Defines),)),)), lambda: True), - (UPat(Ops.LOAD, src=(UPat(Ops.VIEW, src=(UPat(GroupOp.Defines),)), UPat(Ops.STORE))), lambda: True), + # VECTORIZE/GEP + (UPat(Ops.VECTORIZE, name="x"), lambda x: len(x.src)>1 and len(x.src) == x.dtype.vcount and all(x.dtype == y.dtype.vec(len(x.src)) for y in x.src)), + (UPat(Ops.GEP, src=(UPat.var("src"),), name="gep"), lambda gep,src: gep.dtype == src.dtype.scalar()), - # early STORE has a - (UPat(Ops.STORE, src=(UPat(Ops.VIEW, src=(UPat(GroupOp.Defines),)), UPat())), lambda: True), + # LOAD(idx) / STORE(idx, val) / LOAD with alt value only exists in program_spec + # TODO: move LOAD to the program_spec + (UPat().index(UPat()).or_casted().load(), lambda: True), + (UPat(Ops.INDEX).or_casted().store(UPat()), lambda: True), - # **** new style load/store **** + # all CUSTOM + PRECAST + (UPat((Ops.CUSTOMI, Ops.CUSTOM, Ops.PRECAST)), lambda: True), + + # INDEX + (UPat(GroupOp.Defines|{Ops.AFTER}, name="buf").index(UPat.var("idx")), validate_index), + + # SPECIAL + (UPat(Ops.SPECIAL, src=(UPat.var("x", (dtypes.index, dtypes.int32)),), name="s"), lambda s,x: s.dtype == x.dtype and isinstance(s.arg, str)), + + # BARRIER (on any length) + (UPat(Ops.BARRIER, dtypes.void), lambda: True), +]) + +# ***** UOp spec in kernel graph ***** + +kernel_spec = PatternMatcher([ + # index is allowed here + (UPat(GroupOp.Elementwise|{Ops.CONST, Ops.RANGE, Ops.DEFINE_VAR}, dtype=dtypes.index), lambda: True), + + # UNROLL/CONTRACT is used here for WMMA + (UPat(Ops.CONTRACT, name="x"), lambda x: x.dtype.count == prod(y[1] for y in x.arg)), + (UPat(Ops.UNROLL, name="x"), lambda x: x.src[0].dtype.count == prod(y[1] for y in x.arg)), + + # END can end multiple axes here + (UPat(Ops.END, src=(UPat(), UPat()), allow_any_len=True, dtype=dtypes.void), lambda: True), + + # bufferize can be on anything + (UPat(Ops.BUFFERIZE, src=(UPat(),), allow_any_len=True, name="x"), lambda x: True), + + # reduce must be on ranges + (UPat(Ops.REDUCE, src=(UPat(),), allow_any_len=True, name="x"), lambda x: all(y.dtype == dtypes.index for y in x.src[1:])), +])+movement_ops+shared_codegen_spec+shared_spec + +# ***** UOp spec in linearized programs ***** + +program_spec = PatternMatcher([ + # INDEX with a gate as third src + (UPat(Ops.INDEX, src=(UPat(GroupOp.Defines|{Ops.AFTER}, name="buf"), UPat.var("idx"), UPat.var("gate", dtype=dtypes.bool))), validate_index), + + # LOAD (idx, alt_value), LOAD can have an alt value, but only if the index has a gate + (UPat().index(UPat(), UPat(dtype=dtypes.bool)).or_casted().load(UPat()), lambda: True), + + # END closes ranges + (UPat(Ops.END, src=(UPat(), UPat(Ops.RANGE)), dtype=dtypes.void), lambda: True), # make sure all index dtypes have been lowered (UPat(GroupOp.All, dtype=dtypes.index), lambda: False), (UPat(Ops.CONST, arg=Invalid), lambda: False), - (UPat(Ops.VCONST, name="x"), lambda x: all(v is not Invalid for v in x.src)), + (UPat(Ops.VCONST, name="x"), lambda x: all(v is not Invalid for v in x.arg) and len(x.arg)==x.dtype.vcount>1 and + type(x.arg) is type(dtypes.as_const(x.arg, x.dtype))), - # INDEX is used in new style load/store - # INDEX takes a - (UPat(Ops.INDEX, src=(UPat(GroupOp.Defines), UPat())), lambda: True), - (UPat(Ops.INDEX, src=(UPat(GroupOp.Defines), UPat(), UPat(dtype=dtypes.bool))), lambda: True), - - # LOAD on STORE - (UPat(Ops.LOAD, src=(UPat(Ops.STORE),), allow_any_len=True), lambda: True), - - # LOAD takes a - (UPat(Ops.LOAD, src=(index_pat, UPat(Ops.IF, name="cond")), allow_any_len=True), lambda idx,cond: validate_index(idx,cond.src[0])), - (UPat(Ops.LOAD, src=(index_pat,), allow_any_len=True), validate_index), - - # STORE takes a - (UPat(Ops.STORE, src=(index_pat, UPat(name="val"), UPat(Ops.IF, name="gate")), allow_any_len=True), validate_store), - (UPat(Ops.STORE, src=(index_pat, UPat(name="val")), allow_any_len=True), validate_store), - - # most ALUs have all matching dtypes, except CMPLT, CMPNE, and WHERE - (UPat(Ops.WHERE, name="w", src=(UPat(dtype=dtypes.bool), UPat.var("x"), UPat.var("y"))), lambda w,x,y: w.dtype == x.dtype == y.dtype), - (UPat((Ops.CMPLT, Ops.CMPNE, Ops.CMPEQ), dtype=dtypes.bool, src=(UPat.var("x"), UPat.var("y"))), lambda x,y: x.dtype.base == y.dtype.base), - # and SHL/SHR, the shift distance can be an int - (UPat((Ops.SHL, Ops.SHR), src=(UPat.var("x"), UPat.var("y")), name="a"), lambda a,x,y: a.dtype == x.dtype and y.dtype in (x.dtype, dtypes.uint)), - (UPat((Ops.IDIV, Ops.MOD), name="x"), lambda x: None if dtypes.is_int(x.dtype) else False), - (UPat(GroupOp.ALU, name="x"), lambda x: all(x.dtype.base == y.dtype.base for y in x.src)), - - (UPat(Ops.ENDRANGE, dtype=dtypes.void, src=(UPat(Ops.RANGE),)), lambda: True), - - # WMMA has a - (UPat(Ops.WMMA, src=(UPat(), UPat(), UPat()), name="x"), lambda x: isinstance(x.arg, tuple) and len(x.arg) == 8), - (UPat(Ops.CONTRACT, name="x"), lambda x: x.dtype.count == prod(y[1] for y in x.arg)), - (UPat(Ops.UNROLL, name="x"), lambda x: x.src[0].dtype.count == prod(y[1] for y in x.arg)), - - # if has a - (UPat(Ops.IF, dtype=dtypes.void, src=(UPat(),)), lambda: True), - (UPat(Ops.IF, dtype=dtypes.void, src=(UPat(), UPat(Ops.BARRIER))), lambda: True), + # if has a + (UPat(Ops.IF, dtype=dtypes.void, src=(UPat(dtype=dtypes.bool), UPat((Ops.CAST, Ops.INDEX)))), lambda: True), (UPat(Ops.ENDIF, dtype=dtypes.void, src=(UPat(Ops.IF),)), lambda: True), - - (UPat(Ops.REDUCE_AXIS, name="x"), lambda x: isinstance(x.arg, tuple) and len(x.arg) >= 2 and x.arg[0] in {Ops.ADD, Ops.MUL, Ops.MAX}), - (UPat(Ops.GEP, src=(UPat.var("src"),), name="gep"), lambda gep,src: gep.dtype == src.dtype.scalar()), - (UPat(Ops.VECTORIZE, name="x"), lambda x: len(x.src)>1 and len(x.src) == x.dtype.vcount and all(x.dtype == y.dtype.vec(len(x.src)) for y in x.src)), - (UPat((Ops.BITCAST, Ops.CAST), src=(UPat(),), name="x"), lambda x: x.arg is None), - (UPat(Ops.BARRIER, dtypes.void, src=UPat(Ops.STORE, allow_any_len=True)), lambda: True), # NOTE: all pointers must be local - (UPat(Ops.BARRIER, dtypes.void), lambda: True), # BARRIERs can also happen at the end of loops - - # NOTE: for testing, we let sinks be anything - #(UPat(Ops.SINK, src=UPat(Ops.STORE)), lambda: True), - (UPat(Ops.SINK, dtypes.void), lambda: True), - (UPat((Ops.NOOP, Ops.CUSTOMI, Ops.CUSTOM, Ops.PRECAST)), lambda: True), - - # PTX LOAD/STORE - (UPat((Ops.LOAD, Ops.STORE), src=(UPat(dtype=dtypes.int64),), allow_any_len=True), lambda: True), -]) - -# *** this is the UOp AST spec *** - -ast_spec = PatternMatcher([ - # VIEW can only exist in the edges - (UPat(Ops.VIEW, src=(UPat((Ops.DEFINE_GLOBAL, Ops.DEFINE_LOCAL),))), lambda: True), - (UPat(Ops.VIEW, name="view"), lambda view: len(view.src) == 0), - # all parent UOps must have the same shape - (UPat(GroupOp.All-{Ops.SINK}, name="root"), lambda root: all_same([x.shape for x in root.src if x.st is not None])), -]) +])+shared_codegen_spec+shared_spec # *** this spec should match all UOps ever created *** -full_non_rangeify_spec = PatternMatcher([]) if RANGEIFY else PatternMatcher([ - # in non rangeify const can still have a View, and sometimes a FUSE while propagating - (UPat((Ops.VIEW, Ops.FUSE)).f(Ops.CONST), lambda: True), -]) - full_spec = PatternMatcher([ - # Invalid must have type Index - (UPat(Ops.CONST, arg=Invalid, name="x"), lambda x: x.dtype.scalar() == dtypes.index), - # where on index in rhs position is fine - (UPat(Ops.WHERE, src=(UPat(dtype=dtypes.bool), UPat(), UPat(dtype=dtypes.index))), lambda: True), - - # all children is fine - (UPat(Ops.CHILDREN), lambda: True), - # child must have CHILDREN parent - (UPat(Ops.CHILD, src=(UPat(Ops.CHILDREN),)), lambda: True), + # NOOP in the full spec + (UPat(Ops.NOOP), lambda: True), # all rewrite error are okay (UPat(Ops.REWRITE_ERROR), lambda: True), # rangeify: buffer view with index or load is okay (UPat(Ops.BUFFER_VIEW, src=(UPat((Ops.INDEX, Ops.LOAD)),)), lambda: True), - # bufferize (must be on ranges) - (UPat(Ops.BUFFERIZE, src=(UPat(),), allow_any_len=True, name="x"), lambda x: all(y.op is Ops.RANGE for y in x.src[1:])), - # realize with one src is fine - (UPat(Ops.REALIZE, src=(UPat(),)), lambda: True), - # intermediate index - (UPat(Ops.INDEX, src=(UPat(),), allow_any_len=True, name="x"), lambda x: all(y.dtype == dtypes.index for y in x.src[1:]) or None), - (UPat(Ops.REDUCE, src=(UPat(),), allow_any_len=True, name="x"), lambda x: all(y.dtype == dtypes.index for y in x.src[1:])), - # copy on index - (UPat(Ops.COPY, src=(UPat(Ops.INDEX), UPat())), lambda: True), # assign on index. the third op is the shape - (UPat(Ops.ASSIGN, src=(UPat(Ops.INDEX), UPat(), UPat(GroupOp.Movement))), lambda: True), + (UPat(Ops.ASSIGN, src=(UPat(), UPat(), UPat())), lambda: True), # expander: unroll/contract/gep/ptrcat/cat (UPat((Ops.UNROLL, Ops.CONTRACT), src=(UPat(),)), lambda: True), @@ -296,28 +225,62 @@ full_spec = PatternMatcher([ (UPat(Ops.INDEX, src=(UPat((Ops.VECTORIZE, Ops.CAST)), UPat())), lambda: True), # linearizer: outputs + intermediate KERNELs - (UPat((Ops.BLOCKSTART, Ops.BLOCK, Ops.BLOCKFINAL, Ops.BLOCKEND, Ops.KERNEL), dtype=dtypes.void), lambda: True), + (UPat(Ops.KERNEL, dtype=dtypes.void), lambda: True), + # Invalid must have type Index + (UPat(Ops.CONST, arg=Invalid, name="x"), lambda x: x.dtype.scalar() == dtypes.index), + # where on index in rhs position is fine + (UPat(Ops.WHERE, dtype=dtypes.index, src=(UPat(dtype=dtypes.bool), UPat(), UPat(dtype=dtypes.index))), lambda: True), # allow index dtype on a restricted set of UOps - (UPat((Ops.ADD, Ops.MUL, Ops.MOD, Ops.IDIV, Ops.MAX, Ops.WHERE, + (UPat((Ops.ADD, Ops.MUL, Ops.MOD, Ops.IDIV, Ops.MAX, Ops.SPECIAL, Ops.CAST, Ops.RANGE, Ops.VCONST, Ops.VECTORIZE), dtype=dtypes.index), lambda: True), + # while BIND is being casted + (UPat(Ops.BIND, (dtypes.int, dtypes.index), (UPat(), UPat()), arg=None), lambda: True), + + # in progress MSTACK may lose device + (UPat((Ops.MSELECT, Ops.MSTACK), name="x"), lambda x: True), + + # temp VECTORIZE/INDEX during rewrite have the wrong dtype + (UPat(Ops.VECTORIZE), lambda: True), + (UPat(Ops.INDEX), lambda: True), + # all loads/stores (UPat((Ops.LOAD, Ops.STORE)), lambda: True), - # all ifs - (UPat(Ops.IF), lambda: True), - # all DEFINE_VAR to deal with the floats used in reduce collapse - (UPat(Ops.DEFINE_VAR), lambda: True), - # reshape on STORE - (UPat(Ops.RESHAPE, src=(UPat(Ops.STORE),)), lambda: True), -])+full_non_rangeify_spec+tensor_uop_spec+spec + # DEFINE_VAR to deal with the floats used in reduce collapse + (UPat(Ops.DEFINE_VAR, dtype=dtypes.floats), lambda: True), + # allow any AFTER + (UPat(Ops.AFTER, src=(UPat(),), allow_any_len=True), lambda: True), +])+_tensor_spec+kernel_spec+program_spec+shared_spec # ***** uop helpers ***** -def type_verify(uops:list[UOp], extra_spec:PatternMatcher|None=None): - check_spec = (extra_spec+spec) if extra_spec is not None else spec - for i,u in enumerate(uops): +def type_verify(ast:UOp|list[UOp], check_spec:PatternMatcher): + lst = list(ast.toposort()) if isinstance(ast, UOp) else ast + if SPEC > 1: test_pyrender(lst[-1]) # assume this is the sink + + for i,u in enumerate(lst): with Context(TRACK_MATCH_STATS=0): ret = check_spec.rewrite(u) if cast(bool|None, ret) is not True: - if DEBUG >= 3: print_uops(uops) + if DEBUG >= 3: print_uops(lst) raise RuntimeError(f"UOp verification failed at {i} on {u.op} {u.dtype} {len(u.src)} {[(x.op, x.dtype, x.arg) for x in u.src]} {u.arg}") + +# late imports to avoid circular import +from tinygrad.codegen.opt import Opt, OptOps +from tinygrad.schedule.rangeify import BufferizeOpts +glbls:dict[str, Any] = {"inf": math.inf, "nan": math.nan, "KernelInfo": KernelInfo, "Kernel": Kernel, "Metadata": Metadata, + "UOp": UOp, "dtypes": dtypes, "Ops": Ops, "AxisType": AxisType, "Invalid": Invalid, + "Opt": Opt, "OptOps": OptOps, "BufferizeOpts": BufferizeOpts, "AddrSpace": AddrSpace} +def eval_pyrender(code:str) -> UOp: + lcls:dict[str, Any] = {} + exec(code, glbls, lcls) + return lcls['ast'] + +def test_pyrender(test_ast:UOp, assert_parents=True): + code = pyrender(test_ast) + ast:UOp = eval_pyrender(code) + if ast is not test_ast: + if assert_parents: + for u in test_ast.toposort(): test_pyrender(u, assert_parents=False) + raise RuntimeError(f"PYRENDER ISSUE:\nSTR MATCH: {str(test_ast) == str(ast)}\nUOP:\n{test_ast}\nPRODUCED:\n{ast}\nCODE:\n{code}") + return code diff --git a/tinygrad/uop/symbolic.py b/tinygrad/uop/symbolic.py index 7da4767712..da920e2da8 100644 --- a/tinygrad/uop/symbolic.py +++ b/tinygrad/uop/symbolic.py @@ -1,5 +1,4 @@ # all of symbolic lives here now -from typing import cast import math, operator, struct, functools from collections import defaultdict from tinygrad.uop.ops import Ops, PatternMatcher, UPat, UOp, GroupOp, exec_alu @@ -28,6 +27,7 @@ invalid_gate = UPat.var("cond").where(UPat.var("x"), invalid_pat) propagate_invalid = PatternMatcher([ # this needs to be before symbolic so that 0*something_that_might_be_invalid doesnt become 0 # propagate invalid, push it past children + (invalid_gate.cast(name="cast"), lambda i,x,cond,cast: x.cast(cast.dtype) if cast.dtype is not dtypes.index else None), *((invalid_gate.alu(op, UPat.var("y")).named("alu"), lambda cond,x,y,alu,i: cond.where(x.alu(alu.op,y), i)) for op in GroupOp.Binary-GroupOp.Comparison), *((invalid_gate.alu(op, UPat.var("y")).named("alu"), lambda cond,x,y,alu,i: x.alu(alu.op,y)) for op in GroupOp.Comparison), @@ -37,10 +37,6 @@ propagate_invalid = PatternMatcher([ *((invalid_pat.alu(op, UPat(dtype=dtypes.index)), lambda i: UOp.const(dtypes.bool, True)) for op in GroupOp.Comparison), # a.where(b.where(c, d), d) -> (a & b).where(c, d) (UPat.var("a").where(UPat.var("b").where(UPat.var("c"), UPat.var("d")), UPat.var("d")), lambda a,b,c,d: (a&b).where(c,d)), - # order of gate&!cond matters!, and-clauses are only simplified left to right and we need to gate to be used to fold cond - (UPat.var("gate").where(invalid_gate, UPat.var("y")), lambda gate,cond,x,y,i: ((gate&cond.logical_not()).logical_not()).where(gate.where(x,y), i)), - # unswap the branches for the rule above - (UPat.var("gate").where(UPat.var("y"), invalid_gate).named("where"), lambda gate,cond,x,y,i: gate.logical_not().where(cond.where(x,i), y)) ]) symbolic_simple = propagate_invalid + PatternMatcher([ @@ -51,11 +47,11 @@ symbolic_simple = propagate_invalid + PatternMatcher([ (UPat.var("x") // UPat.var("x"), lambda x: x.const_like(1)), # x//x -> 1 (UPat.var("x") // 1, lambda x: x), # x//1 -> x (UPat.var("x") // -1, lambda x: -x), # x//-1 -> -x - (UPat.var("x") / UPat.var("x"), lambda x: x.const_like(1)), # x/x -> 1 - ((UPat.var("x") * UPat.var("x2")) / UPat.var("x2"), lambda x,x2: x), # (x*x2)/x2 -> x ((UPat.var() % UPat.var("y")).named("base") % UPat.var("y"), lambda base,y: base), # (x%y)%y = -> x%y (rewritten with base for speed) - # 4 variations of (x%c)+(x//c)*c = x TODO: add sorting to remove some variations + # variations of (x%c)+(x//c)*c = x TODO: add sorting to remove some variations (UPat.var("x")%UPat.cvar("c")+(UPat.var("x")//UPat.cvar("c"))*UPat.cvar("c"), lambda x,c: x), # (x%c)+(x//c)*c = x + ((UPat.var("x")//UPat.cvar("a"))%UPat.cvar("c")+(UPat.var("x")//UPat.cvar("b"))*UPat.cvar("c"), + lambda x,a,b,c: x//a if a.arg*c.arg==b.arg else None), # ((x//a)%c)+(x//a*c)*c = x//a. Note if a = 1 it degenerates to the one above ((UPat.var("x")//UPat.cvar("c1"))*UPat.cvar("c3")+UPat.var("x")%UPat.cvar("c1")*UPat.cvar("c2"), lambda x,c1,c2,c3: x*c2 if c1.arg*c2.arg==c3.arg else None), # (x%c1)*c2+(x//c1)*c3 = x*c2 if c1*c2==c3 ((UPat.var("y")+(UPat.var("x")//UPat.cvar("c"))*UPat.cvar("c"))+UPat.var("x")%UPat.cvar("c"), lambda y,x,c: y+x), @@ -76,10 +72,6 @@ symbolic_simple = propagate_invalid + PatternMatcher([ (UPat.var("x") % UPat.var("x"), lambda x: x.const_like(0)), # x%x -> 0 (UPat.var("x", dtype=dtypes.ints+(dtypes.bool, dtypes.index)) != UPat.var("x"), lambda x: x.const_like(False).cast(dtypes.bool.vec(x.dtype.count))), # x != x -> False (only ints) - # x*0 -> 0 or 0*x -> 0 - # if x is nan or inf it should render the nan value. - # NOTE: this can be wrong for loaded NaN - (UPat.var("x") * 0, lambda x: x.const_like(float("nan") if isinstance(x.arg, float) and (math.isnan(x.arg) or math.isinf(x.arg)) else 0)), # ** constant folding ** # TODO: add const folding for Ops.THREEFRY (UPat(GroupOp.Unary, src=(UPat((Ops.VCONST, Ops.CONST)),), name="a"), lambda a: a.const_like(exec_alu(a.op, a.dtype, [a.src[0].arg], False))), @@ -91,6 +83,17 @@ symbolic_simple = propagate_invalid + PatternMatcher([ (UPat.var('x', dtype=dtypes.bool) * UPat.var('y', dtype=dtypes.bool), lambda x,y: x&y), (UPat.var('x', dtype=dtypes.bool) + UPat.var('y', dtype=dtypes.bool), lambda x,y: x|y), (UPat.var('x', dtype=dtypes.bool).maximum(UPat.var('y', dtype=dtypes.bool)), lambda x,y: x|y), + # *** div rules *** + (UPat.cvar('x', arg=0) / 0, lambda x: x.const_like(float('nan'))), # 0/0 -> nan + ((UPat.var("x") * 0) / 0, lambda x: x.const_like(float('nan'))), # (x*0)/0 -> nan + # can be wrong if x or x2 is 0 + (UPat.var("x") / UPat.var("x"), lambda x: x.const_like(1)), # x/x -> 1 + ((UPat.var("x") * UPat.var("x2")) / UPat.var("x2"), lambda x,x2: x), # (x*x2)/x2 -> x + # x*0 -> 0 or 0*x -> 0 + # if x is nan or inf it should render the nan value. + # NOTE: this can be wrong for loaded NaN + (UPat.var("x") * 0, lambda x: x.const_like(float("nan") if x.op is Ops.CONST + and isinstance(x.arg, float) and (math.isnan(x.arg) or math.isinf(x.arg)) else 0)), # *** cast/bitcast *** (UPat(Ops.CAST, name="root", src=(UPat.cvar("c"),)), lambda root, c: root.const_like(c.arg)), (UPat((Ops.CAST, Ops.BITCAST), name="root"), lambda root: root.src[0] if root.dtype == root.src[0].dtype else None), @@ -125,7 +128,7 @@ symbolic_simple = propagate_invalid + PatternMatcher([ def lt_folding(x:UOp, c:int) -> UOp|None: p, np = partition(x.split_uop(Ops.ADD), lambda u: u.const_factor() == 1) if np and (d:=math.gcd(*[u.const_factor() for u in np], c)) > 1 and 0 <= sum(u.vmin for u in p) and sum(u.vmax for u in p) < d: - return cast(UOp, functools.reduce(operator.add, np).divides(d))<(c//d) + return unwrap(UOp.sum(*np).divides(d))<(c//d) return None def canonicalize_simplex(X:UOp) -> UOp|None: @@ -139,7 +142,7 @@ def canonicalize_simplex(X:UOp) -> UOp|None: u = u.src[0] if not (u.op in GroupOp.Irreducible and u.vmin >= 0): return None ret.append(u) - return functools.reduce(operator.add, ret) if changed else None + return UOp.sum(*ret) if changed else None def cancel_divmod(d: UOp, x: UOp, y: UOp) -> UOp|None: # simple cancel div/mod case when the range of the numerator lies within a single denominator interval @@ -162,7 +165,7 @@ def remove_nested_mod(m: UOp, x: UOp, y: UOp) -> UOp|None: something_changed = True u = u.src[0] new_xs.append(u) - new_x: UOp = functools.reduce(operator.add, new_xs) + new_x: UOp = UOp.sum(*new_xs) if something_changed and new_x.vmin>=0: return new_x % y return None @@ -172,8 +175,8 @@ def fold_binary_numerator(d: UOp, x: UOp, y: UOp) -> UOp|None: x,const = x.pop_const() terms, factors = zip(*[(u.divides(f:=u.const_factor()),f) for u in x.split_uop(Ops.ADD)]) if len(terms)==1 and (v:=terms[0]).vmax-v.vmin == 1: - y1 = cmod(factors[0]*v.vmin+const, c) if d.op is Ops.MOD else cdiv(factors[0]*v.vmin+const, c) # type: ignore - y2 = cmod(factors[0]*v.vmax+const, c) if d.op is Ops.MOD else cdiv(factors[0]*v.vmax+const, c) # type: ignore + y1 = cmod(factors[0]*v.vmin+const, c) if d.op is Ops.MOD else cdiv(factors[0]*v.vmin+const, c) + y2 = cmod(factors[0]*v.vmax+const, c) if d.op is Ops.MOD else cdiv(factors[0]*v.vmax+const, c) return (y2-y1)*(v-v.vmin) + y1 return None @@ -264,7 +267,7 @@ gep_pushing = PatternMatcher([ # push all GEPs through ALUs (fix arange stuff) (UPat((*GroupOp.ALU, Ops.CAST, Ops.BITCAST), name='alu').f(Ops.GEP, name='gep'), lambda gep,alu: UOp(alu.op, alu.dtype.scalar().vec(gep.dtype.count), tuple(x.gep(gep.arg) for x in alu.src), alu.arg) \ - if not isinstance(gep.dtype, PtrDType) else None), + if not isinstance(gep.dtype, PtrDType) and not isinstance(alu.dtype, PtrDType) else None), # CAT can't be rendered. it's a VECTORIZE on vectors, we expand to a single VECTORIZEs with GEPs (TODO: move this later) (UPat(Ops.CAT, name="x"), lambda x: UOp(Ops.VECTORIZE, x.dtype, tuple(y.gep(i) for y in x.src for i in range(y.dtype.count))) \ if not isinstance(x.dtype, PtrDType) else None), @@ -274,16 +277,10 @@ gep_pushing = PatternMatcher([ (UPat(Ops.WMMA, name="wmma").f(Ops.GEP, name="gep"), gep_through_wmma), ]) -def chain_insert(chain, b, op): - if chain.op is not op or b.order_add > chain.src[1].order_add: return chain.alu(op, b) - return chain_insert(chain.src[0], b, op).alu(op, chain.src[1]) - commutative = PatternMatcher([ # ** COMMUTATIVE flipping (only for index) ** # NOTE: this can break merging vector math by only flipping some of them - (UPat(GroupOp.Commutative-{Ops.ADD}, dtype=dtypes.index, name='x'), lambda x: - x.replace(src=x.src[::-1]) if x.src[1].tuplize < x.src[0].tuplize else None), - (UPat(Ops.ADD, dtype=dtypes.index, name="x"), lambda x: functools.reduce(operator.add, sorted(x.split_uop(Ops.ADD), key=lambda u: u.order_add))) + (UPat(GroupOp.Commutative, dtype=dtypes.index, name='x'), lambda x: x.replace(src=x.src[::-1]) if x.src[1].tuplize < x.src[0].tuplize else None), ]) symbolic = symbolic_simple+commutative+PatternMatcher([ @@ -301,6 +298,7 @@ symbolic = symbolic_simple+commutative+PatternMatcher([ ((UPat.var("y") + UPat.var("x")) + UPat.var("x"), lambda y,x: y+x*2), ((UPat.var("x") / UPat.var("x2")) / UPat.var("x3"), lambda x,x2,x3: x/(x2*x3) if x2 is not x3 else None), # (x/x2)/x3 -> x/(x2*x3) (-1 * (UPat.var("x") + UPat.cvar("c")), lambda x,c: (-x)+(-c)), # -(x+c) -> -x + -c + (UPat.cvar("y") * (UPat.var("x", dtype=dtypes.index) + UPat.cvar("c")), lambda x,y,c: (y*x)+(y*c)), # -(x+c) -> -x + -c # ** where folding ** (UPat.var("cond", dtype=dtypes.bool).logical_not().where(UPat.var("t"), UPat.var("f")), lambda cond, t, f: cond.where(f,t) if f.arg is not Invalid else None), @@ -311,7 +309,8 @@ symbolic = symbolic_simple+commutative+PatternMatcher([ ((UPat.var("y")+UPat.var("c").where(UPat.var("t"), UPat.var("f"))) + UPat.var("c").where(UPat.var("tt"), UPat.var("ff")), \ lambda y,c,t,tt,f,ff: y+c.where(t+tt, f+ff) if t.op == tt.op == Ops.CONST or f.op == ff.op == Ops.CONST else None), # ALU/variable min==max -> CONST (slow!) - (UPat(GroupOp.ALU|{Ops.DEFINE_VAR, Ops.SPECIAL, Ops.RANGE}, name="x"), lambda x: x.const_like(x.vmin) if x.vmin == x.vmax else None), + (UPat(GroupOp.ALU|{Ops.DEFINE_VAR, Ops.SPECIAL}, name="x"), lambda x: x.const_like(x.vmin) if x.vmin == x.vmax else None), + (UPat(Ops.RANGE, src=(UPat(Ops.CONST,)), name="x"), lambda x: x.const_like(x.vmin) if x.vmin == x.vmax else None), # max folding (UPat.maximum(UPat.var("x"), UPat.var("y")), lambda x,y: x if x.vmin >= y.vmax else y if x.vmax <= y.vmin else None), # TODO: why does this rule break beautiful_mnist? @@ -376,18 +375,18 @@ symbolic = symbolic_simple+commutative+PatternMatcher([ (UPat(GroupOp.Binary, src=(UPat.var("x", dtypes.long), UPat.var("y", dtypes.long)), name="u"), lambda u,x,y: x.cast(dtypes.int).alu(u.op, y.cast(dtypes.int)).cast(u.dtype) if not any(v.overflows(dtypes.int) for v in (u,x,y)) else None), ((UPat.var("x", dtypes.index) + UPat.cvar("c")).cast(dtypes.sints, name="cast"), lambda x,c,cast:x.cast(cast.dtype)+c.cast(cast.dtype)), + # only RANGE/IF/STORE/KERNEL have side effects + (UPat(Ops.AFTER, name="x"), lambda x: x.replace(src=(x.src[0],)+ + tuple(flatten([(y,) if y.op in {Ops.RANGE, Ops.STORE, Ops.KERNEL, Ops.BARRIER, Ops.END, Ops.UNROLL} else y.src for y in x.src[1:]])))), + # after with 1 src is just src[0] + (UPat(Ops.AFTER, src=(UPat.var("s"),)), lambda s: s), + # VECTORIZE/CONST + (UPat(Ops.VECTORIZE, src=UPat(Ops.CONST), name="vec"), lambda vec: UOp.const(vec.dtype, tuple(x.arg for x in vec.src))), ])+gep_pushing -symbolic_flat = symbolic+PatternMatcher([ - # ** combine terms (opinionated), can make it harder to substitute valids ** - (-1 * (UPat.var("x") + UPat.var("y")), lambda x,y: (-x)+(-y)), # -(x+y) -> -x + -y - # (x+y)*c -> x*c+y*c. only for int, float has inf*0=nan issue - ((UPat.var("x", dtypes.index) + UPat.var("y")) * UPat.cvar("c"), lambda x,y,c: x*c+y*c), -]) - # ******** we take a small aside to "simplify_valid" to rewrite valids ******** -def parse_valid(valid:UOp) -> tuple[UOp, bool, int]: +def parse_valid(valid:UOp) -> tuple[UOp, bool, int]|None: # if it's X <= c, returns X, True, c # if it's X >= c, returns X, False, c @@ -396,74 +395,66 @@ def parse_valid(valid:UOp) -> tuple[UOp, bool, int]: (s0:=valid.src[0]).op is Ops.CMPLT and dtypes.is_int(s0.src[0].dtype): return s0.src[0], False, int(s0.src[1].vmin) # X < c -> X <= c-1 if valid.op is Ops.CMPLT and dtypes.is_int(valid.src[0].dtype): return valid.src[0], True, int((valid.src[1]).vmax)-1 - raise ValueError(f"not able to parse {valid=}") + return None -def uop_given_valid(valid:UOp, uop:UOp) -> UOp|None: - # return None if valid is always False, otherwise the simplified uop (might be the same as input) +def uop_given_valid(valid:UOp, uop:UOp, try_simplex=True) -> UOp: + # return simplified uop (might be the same as input) # first, parse valid into {expr: (lower_bound, upper_bound)} bounds:defaultdict[UOp, list[ConstType|None]] = defaultdict(lambda: [None, None]) for stmt in valid.split_uop(Ops.AND): - try: expr, is_upper, c = parse_valid(stmt) - except ValueError: continue # give up if we cannot parse the valid + if (res:=parse_valid(stmt)) is None: continue + expr, is_upper, c = res bounds[expr][int(is_upper)] = c # don't simplify any other gates, can lead to OOB, we substitute them back later - uop = uop.substitute((load_subs:={u: UOp(Ops.NOOP, arg=u) for u in uop.toposort() if u.op is Ops.INDEX})) + uop = uop.substitute((load_subs:={u: UOp(Ops.NOOP, dtype=u.dtype, arg=u) for u in uop.toposort() if u.op is Ops.INDEX})) - all_candidates = [] # simplify uop given that valid is True - for i, (expr,v) in enumerate(bounds.items()): + all_candidates = [] + for i,(expr,v) in enumerate(bounds.items()): v0, v1 = (expr.vmin if v[0] is None else v[0], expr.vmax if v[1] is None else v[1]) expr = expr.substitute(load_subs) # make sure expr appears in same form in the uop - # if the expr is an add we try and factorize so its more likely to substitute - if expr.op is Ops.ADD: uop = uop.factor(expr) - # some expr has lower bound > upper bound -> valid is an empty set and we return None - if v0 > v1: return None - # whole node became a const - if v0 == v1: - uop = uop.substitute({expr:expr.const_like(v0)}).simplify() - continue - # every candidate is a set of constrained UOp based on valid, and if every item in a set simplifies the uop into a same output, we rewrite uop - candidates = [] - if expr.op is Ops.ADD and v0 == 1 and all(u.op in GroupOp.Irreducible for u in expr.split_uop(Ops.ADD)): - # if the constraint is a simplex: X0 + X1 + ... > 0, we can check if all Xi > 0 simplify into the same output - candidates.append([(Xi, UOp.variable("fake", 1, Xi.vmax, Xi.dtype)) for Xi in expr.split_uop(Ops.ADD)]) # try checking the whole clause - if expr in uop.toposort(): - candidates.append([tup:=(expr, UOp.variable(f"fake{i}", v0, v1, expr.dtype))]) - all_candidates.append(tup) + all_candidates.append((expr, UOp.variable(f"fake{i}", v0, v1, expr.dtype))) - for candidate in candidates: - # if every branch in candidate gives the same simplified uop, we can rewrite the uop - newuops = [uop.substitute({X:newX}).simplify().substitute({newX:X}).simplify() for X,newX in candidate] - if uop.op is Ops.VECTORIZE and len(uop.src) == 2: - if all_same([uops.src[0] for uops in newuops]): uop = uop.replace(src=(newuops[0].src[0], uop.src[1])) - if all_same([uops.src[1] for uops in newuops]): uop = uop.replace(src=(uop.src[0], newuops[0].src[1])) - elif all_same(newuops): uop = newuops[0] + if try_simplex: + # every candidate is a set of constrained UOp based on valid, and if every item in a set simplifies the uop into a same output, we rewrite uop + candidates = [[all_candidates[-1]]] + if expr.op is Ops.ADD and v0 == 1 and all(u.op in GroupOp.Irreducible for u in expr.split_uop(Ops.ADD)): + # if the constraint is a simplex: X0 + X1 + ... > 0, we can check if all Xi > 0 simplify into the same output + candidates.append([(Xi, UOp.variable(f"fake{i}", 1, Xi.vmax, Xi.dtype)) for Xi in expr.split_uop(Ops.ADD)]) - uop = uop.factor(*(e[0] for e in all_candidates)) - uop = uop.substitute(sub_dict:=dict(all_candidates)).simplify().substitute({newX:X for X,newX in sub_dict.items()}).simplify() + for candidate in candidates: + # if every branch in candidate gives the same simplified uop, we can rewrite the uop + newuops = [uop.substitute({X:newX}) for X,newX in candidate] + if any(u is uop for u in newuops): continue # if any branch doesnt appear in uop, skip + newuops = [u.simplify().substitute({newX:X}).simplify(full_symbolic=False) for (X,newX),u in zip(candidate,newuops)] + if all_same(newuops): uop = newuops[0] + elif uop.op is Ops.VECTORIZE and len(uop.src) == 2: + if all_same([uops.src[0] for uops in newuops]): uop = uop.replace(src=(newuops[0].src[0], uop.src[1])) + if all_same([uops.src[1] for uops in newuops]): uop = uop.replace(src=(uop.src[0], newuops[0].src[1])) + # try all the valids together (but only the whole expressions) + if (s_uop:=uop.substitute(sub_dict:=dict(all_candidates))) is not uop: + uop = s_uop.simplify().substitute({newX:X for X,newX in sub_dict.items()}).simplify(full_symbolic=False) # put the loads back in uop = uop.substitute({v:k for k,v in load_subs.items()}) return uop def _valid_priority(v: UOp, valids:list[UOp]): # we want valid that's in other valids' parents to be first, so it's more likely the other valids get simplified - try: return sum(-1 if parse_valid(v)[0] in other.toposort() else 0 for other in valids) - except ValueError: return 0 + return sum(-1 if (res:=parse_valid(v)) is not None and res[0] in other.toposort() else 0 for other in valids) def simplify_valid(valid:UOp) -> UOp|None: + if valid.op_in_backward_slice_with_self(Ops.INDEX): return None # this should only be for indexing, skip if there's a INDEX ret:list[UOp] = [] something_changed = False valids = list(valid.split_uop(Ops.AND)) for stmt in sorted(valids, key=lambda v: _valid_priority(v, valids)): - # TODO: root cause this and test_simplify_valid_from_div - if stmt.op is Ops.CAST: return None - ret.append(newstmt if ret and (newstmt:=uop_given_valid(functools.reduce(operator.and_, ret), stmt)) is not None else stmt) + ret.append(uop_given_valid(UOp.prod(*ret), stmt) if ret else stmt) if ret[-1] is not stmt: something_changed = True - return functools.reduce(operator.and_, ret) if something_changed else None + return UOp.prod(*ret) if something_changed else None # ******** phase 3 is the complete symbolic, and deals with very complex things like loop rewriting and threefry transform ******** @@ -478,28 +469,49 @@ def reduce_mul_chain(r:UOp): if len(outside) == 0: return None return r.replace(src=(prod(inside) if len(inside) else r.src[0].const_like(1),)+r.src[1:])*prod(outside) -# this is symbolic 2.0 -REMOVE_FROM_SINK = {Ops.SINK, Ops.UNROLL, Ops.PTRCAT, Ops.CAT, Ops.NOOP} -REMOVE_FROM_BARRIER = {Ops.VECTORIZE, Ops.SINK, Ops.CAT, Ops.PTRCAT, Ops.NOOP} -sym = symbolic_flat+PatternMatcher([ +def drop_and_clauses(cond:UOp, x:UOp, i:UOp) -> UOp|None: + if not (dropped_clauses:=[c for c in cond.split_uop(Ops.AND) if not any(r in x.ranges for r in c.ranges)]): return None + return UOp.const(dtypes.bool, True).prod(*[c for c in cond.split_uop(Ops.AND) if c not in dropped_clauses]).where(x, i) +pm_drop_and_clauses = PatternMatcher([(UPat.var("cond").where(UPat.var("x", dtype=dtypes.index), invalid_pat), drop_and_clauses)]) + +def where_on_load(c1, buf, x): + c2 = x.get_valid() + duplicate_clauses = [c for c in c1.split_uop(Ops.AND) if c in c2.split_uop(Ops.AND)] + # we move the condition from the where to the load _as long as_ the condtition doesn't have some range that would place it inside of a new range + # also no data dependent loads! + moved_clauses = [c for c in c1.split_uop(Ops.AND) if c not in duplicate_clauses and all(r in x.ranges for r in c.ranges) + and all(u in x.backward_slice_with_self for u in c.backward_slice_with_self if u.op is Ops.INDEX)] + if not (removed:=moved_clauses+duplicate_clauses): return None + # aditionally we can drop the clause on the where if it already exists in the load + remaining_clause = UOp.const(dtypes.bool, True).prod(*[c for c in c1.split_uop(Ops.AND) if c not in removed]) + return remaining_clause.where(buf.index(x.get_idx().valid(functools.reduce(operator.and_, moved_clauses, c2))), 0) +pm_move_where_on_load = PatternMatcher([ + (UPat.var("c1").where(UPat.var("buf").index(UPat.var("x")), 0), where_on_load), + (UPat.var("c1").where(0, UPat.var("buf").index(UPat.var("x"))), lambda c1,buf,x: where_on_load(c1.logical_not(),buf,x)), +]) + +pm_simplify_valid = PatternMatcher([ # simplify valid (UPat(Ops.AND, name="valid"), simplify_valid), - (UPat.var("cond").where(UPat.var("x", dtype=dtypes.index), invalid_pat), lambda cond,x,i: cond.where(newx, i) if - (newx:=uop_given_valid(cond, x)) is not x else None), + # TODO: this regressed openpilot, not having this regressed cifar + # (UPat.var("c").where(UPat.var("x", dtype=dtypes.index), invalid_pat), lambda c,x,i: c.where(uop_given_valid(c, x, try_simplex=False), i)), +]) + +# this is symbolic 2.0 +REMOVE_FROM_SINK_LIKE = {Ops.UNROLL, Ops.NOOP, Ops.VECTORIZE, Ops.SINK} +sym = symbolic+pm_simplify_valid+PatternMatcher([ # LOAD/STORE -> NOOP (UPat.var('x').store(UPat.var('x').load(), allow_any_len=True), lambda x: None if x.dtype.addrspace != AddrSpace.REG else x.src[0].src[0]), (UPat(Ops.LOAD, src=(UPat.cvar('c'))), lambda c: c), - # VECTORIZE/CONST, VECTORIZE/GEP - (UPat(Ops.VECTORIZE, src=UPat(Ops.CONST), name="vec"), lambda vec: UOp.const(vec.dtype, tuple(x.arg for x in vec.src))), + # VECTORIZE/GEP (UPat(Ops.VECTORIZE, src=UPat(Ops.GEP, src=(UPat.var("x"),)), name="vec"), lambda vec,x: x.gep(tuple(y.arg[0] for y in vec.src))), # reorder ALU/VECTORIZE (UPat(GroupOp.ALU, src=(UPat(Ops.VECTORIZE, src=UPat(name='x')), UPat(Ops.VECTORIZE, src=UPat(name='y'))), name='alu'), lambda x,y,alu: UOp(Ops.VECTORIZE, alu.dtype, (UOp(alu.op, alu.dtype.scalar(), (x,y)),)*alu.dtype.count)), # VECTORIZE of a single element is just that element (UPat(Ops.VECTORIZE, src=(UPat(name='x'),)), lambda x: x), - # VECTORIZE void is SINK - (UPat(Ops.VECTORIZE, dtype=dtypes.void, src=UPat(Ops.BARRIER, name='b')), lambda b: b), - (UPat(Ops.VECTORIZE, dtype=dtypes.void, name='x'), lambda x: UOp(Ops.SINK, dtypes.void, x.src)), + # VECTORIZE void is GROUP + (UPat(Ops.VECTORIZE, dtype=dtypes.void, name='x'), lambda x: UOp.group(*x.src)), # tensor core with a 0 input is acc (UPat(Ops.WMMA, src=(UPat.const(None, 0.0), UPat.var(), UPat.var("acc"))), lambda acc: acc), (UPat(Ops.WMMA, src=(UPat.var(), UPat.const(None, 0.0), UPat.var("acc"))), lambda acc: acc), @@ -519,13 +531,7 @@ sym = symbolic_flat+PatternMatcher([ # fold gated LOAD/STORE (UPat((Ops.LOAD, Ops.STORE), src=(UPat().index(UPat.const(dtypes.index, Invalid)).or_casted(),), allow_any_len=True, name="x"), lambda x: UOp(Ops.NOOP) if x.op is Ops.STORE else x.const_like(0)), # invalid store does nothing. invalid load produces 0 - # remove VECTORIZE from SINK/BARRIER. TODO: SINK/BARRIER are really the same thing at GLOBAL/LOCAL levels - (UPat(Ops.BARRIER, name="root"), - lambda root: UOp(Ops.BARRIER, root.dtype, tuple(flatten(x.src if x.op in REMOVE_FROM_BARRIER else (x,) for x in root.src)), root.arg) - if any(x.op in REMOVE_FROM_BARRIER for x in root.src) else None), - (UPat(Ops.SINK, name="root"), - lambda root: UOp(Ops.SINK, root.dtype, tuple(flatten(x.src if x.op in REMOVE_FROM_SINK else (x,) for x in root.src)), root.arg) - if any(x.op in REMOVE_FROM_SINK for x in root.src) else None), + # # Where after gated load becomes alt value, TODO: this is sort of duplicated with rules in devectorizer ((UPat.var("x") * UPat.var("x")).reciprocal(), lambda x: x.reciprocal()*x.reciprocal()), # 1/(x^c) -> (1/x)^c ((UPat.var("x") * UPat.var("x") * UPat.var("x")).reciprocal(), lambda x: x.reciprocal()*x.reciprocal()*x.reciprocal()), ((UPat.var("x") * UPat.cvar("c")).reciprocal(), lambda x,c: x.reciprocal()*c.reciprocal()), # 1/(x*c) -> (1/c)*(1/x) @@ -536,4 +542,15 @@ sym = symbolic_flat+PatternMatcher([ ((UPat.var("x")*UPat.cvar("c", vec=False)).reduce(arg=Ops.ADD, name="r", allow_any_len=True), lambda x,c,r: r.replace(src=(x,)+r.src[1:])*c.arg), # reduce mul chain, move muls after the reduce (UPat(Ops.MUL).reduce(name="r", allow_any_len=True), reduce_mul_chain), + # clean up GROUP/SINK + (UPat(Ops.GROUP, src=(UPat.var("x"),)), lambda x: x), + (UPat((Ops.SINK, Ops.GROUP), name="root"), + lambda root: UOp(root.op, root.dtype, tuple(flatten(x.src if x.op in REMOVE_FROM_SINK_LIKE else (x,) for x in root.src)), root.arg) + if any(x.op in REMOVE_FROM_SINK_LIKE for x in root.src) else None), + # remove END with empty NOOP + (UPat(Ops.END, src=(UPat(Ops.NOOP, src=(), name="noop"),), allow_any_len=True), lambda noop:noop), + # ** combine terms (opinionated) ** + (-1 * (UPat.var("x") + UPat.var("y")), lambda x,y: (-x)+(-y)), # -(x+y) -> -x + -y + # (x+y)*c -> x*c+y*c. only for int, float has inf*0=nan issue + ((UPat.var("x", dtypes.index) + UPat.var("y")) * UPat.cvar("c"), lambda x,y,c: x*c+y*c), ]) diff --git a/tinygrad/uop/validate.py b/tinygrad/uop/validate.py new file mode 100644 index 0000000000..3e0af8efc0 --- /dev/null +++ b/tinygrad/uop/validate.py @@ -0,0 +1,84 @@ +from typing import Callable, cast +from tinygrad.uop.ops import PatternMatcher, UPat, GroupOp, Ops, UOp, python_alu +from tinygrad.dtype import ImageDType, dtypes, Invalid +from tinygrad.helpers import IGNORE_OOB, cpu_profile + +try: + import z3 + # older versions of z3 dont have some operators like & overloaded + if z3.get_version() < (4, 12, 4, 0): raise ImportError + + # IDIV is truncated division but z3 does euclidian division (floor if b>0 ceil otherwise); mod by power of two sometimes uses Ops.AND + def z3_cdiv(a, b):return z3.If((a<0), z3.If(0 tuple[z3.ArithRef, z3.BoolRef]: + return (s:=z3.Int(name, ctx=solver.ctx)), (vmin <= s)&(s <= vmax) + + z3_renderer = PatternMatcher([ + (UPat.var("cond").where(UPat.var("x"), UPat.const(dtypes.index, Invalid)), lambda x,cond,ctx: (ctx[1][x], ctx[1][cond])), + # variables + (UPat(Ops.SPECIAL, name="x"), lambda x,ctx: create_bounded(x.arg, 0, ctx[1][x.src[0]]-1, ctx[0])), + (UPat(Ops.DEFINE_VAR, name="x"), lambda x,ctx: create_bounded(x.arg[0], x.arg[1], x.arg[2], ctx[0])), + (UPat(Ops.RANGE, name="x"), lambda x,ctx: create_bounded(f"r{x.arg}", 0, ctx[1][x.src[0]]-1, ctx[0])), + # loads are variables bounded by the min/max of the dtype + (UPat(Ops.LOAD, dtypes.ints+(dtypes.index,), name="x"), lambda x,ctx: create_bounded(f"load{len(ctx[1])}", x.dtype.min, x.dtype.max, ctx[0])), + (UPat(Ops.LOAD, dtypes.bool, name="x"), lambda x,ctx: (z3.Bool(f"load{len(ctx[1])}", ctx=ctx[0].ctx), None)), + # constants + (UPat(Ops.CONST, arg=Invalid, name="x"), lambda x,ctx: (z3.Int("Invalid", ctx=ctx[0].ctx), None)), + (UPat(Ops.CONST, dtypes.ints+(dtypes.index,), name="x"), lambda x,ctx: (z3.IntVal(x.arg, ctx=ctx[0].ctx), None)), + (UPat(Ops.CONST, dtypes.bool, name="x"), lambda x,ctx: (z3.BoolVal(x.arg, ctx=ctx[0].ctx), None)), + # casts from floats create new variables + (UPat(Ops.CAST, dtypes.bool, src=(UPat(dtype=dtypes.floats),), name="x"), lambda x,ctx: (z3.Bool(f"cast{len(ctx[1])}",ctx=ctx[0].ctx), None)), + (UPat(Ops.CAST, dtypes.ints+(dtypes.index,), src=(UPat(dtype=dtypes.floats),), name="x"), lambda x,ctx: + create_bounded(f"cast{len(ctx[1])}", x.dtype.min, x.dtype.max, ctx[0])), + # A comparison between floats introduces a new bool variable + (UPat(GroupOp.Comparison, src=UPat(dtype=dtypes.floats), name="x"), lambda x,ctx: (z3.Bool(f"float_cmp{len(ctx[1])}", ctx=ctx[0].ctx), None)), + # casts from bool/int to int/bool + (UPat(Ops.CAST, dtypes.ints+(dtypes.index,),src=(UPat.var("x", dtypes.bool),), name="c"), lambda x,c,ctx: (z3.If(ctx[1][x], 1, 0), None)), + (UPat(Ops.CAST, dtypes.ints+(dtypes.index,), src=(UPat.var("x", dtypes.ints+(dtypes.index,)),), name="c"), lambda x,c,ctx: (ctx[1][x], None)), + (UPat(Ops.CAST, dtypes.bool, name="x"), lambda x,ctx: (ctx[1][x.src[0]]!=0, None)), + (UPat(GroupOp.ALU, name="x"), lambda x,ctx: (z3_alu[x.op](*(ctx[1][s] for s in x.src)), None)), + ]) + + def uops_to_z3(solver, *uops: UOp) -> list[z3.ExprRef]: + lst = list(UOp.sink(*uops).toposort(gate=lambda x: x.dtype.scalar() in dtypes.ints+(dtypes.bool, dtypes.index) or x.op is Ops.SINK))[:-1] + z3map: dict[UOp, z3.ExprRef] = {} + for i,u in enumerate(lst): + new_u, constraint = cast(tuple[z3.ArithRef, z3.BoolRef|None], z3_renderer.rewrite(u, ctx=(solver, z3map))) + if constraint is not None: solver.add(constraint) + z3map[u] = new_u + assert all(u in z3map for u in uops), "UOp failed to rewrite to z3!" + return [z3map[u] for u in uops] + + z3_imported = True +except (ImportError, AttributeError): z3_imported = False + +def validate_index(buf:UOp, idx:UOp, gate:UOp|None=None): + if idx.op is Ops.CONST and idx.arg is Invalid: return True + if gate is None: gate = UOp.const(dtypes.bool, True) + # TODO: check for overflow + if IGNORE_OOB or isinstance(buf.dtype, ImageDType) or (sz := buf.ptrdtype.size) == -1: return True + # We can use UOp min/max to do a faster check, but it can give false positive since its not an exact bound and doesn't consider the mask + if 0<=idx.vmin and idx.vmax= 4.12.4 is required for bounds checking, try IGNORE_OOB=0 or \"pip install 'z3-solver>=4.12.4\"") + solver = z3.Solver(ctx=z3.Context()) + z3_idx, z3_mask = uops_to_z3(solver, idx, gate) + solver.add(z3_mask) + with cpu_profile("validate index with z3", "TINY"): + match solver.check((z3_idx<0)|(sz<=z3_idx)): + case z3.unsat: return True + case z3.sat: print(f"# OUT OF BOUNDS ACCESS: at {solver.model()} INDEX not in 0 - {sz}\nconstraints = {solver}") + case z3.unknown: print(f"# UNKNOWN RESULT FROM Z3: {solver.reason_unknown()}\nconstraints = {solver}") + print(f"idx={idx.render(simplify=False)}") + print(f"mask={gate.render(simplify=False)}") + return False diff --git a/tinygrad/viz/index.html b/tinygrad/viz/index.html index 0310c6428b..ad08c448ad 100644 --- a/tinygrad/viz/index.html +++ b/tinygrad/viz/index.html @@ -2,6 +2,7 @@ tinygrad viz + @@ -32,35 +33,58 @@ font-size: 14px; overflow: hidden; background-color: #08090e; + scrollbar-color: #686977 #151720; } + ::-webkit-scrollbar-track { background: #151720; } + ::-webkit-scrollbar-thumb { background: #686977; } a { color: #4a90e2; + text-decoration: underline; + cursor: pointer; + display: block; } ul { padding: 0; - opacity: 0.6; white-space: nowrap; cursor: pointer; } - ul.active { + ul > p { + opacity: 0.6; + } + ul.active > p { opacity: 1; } ul > ul { display: none; + margin-left: 6px; + } + ul.has-children > p::before { + content:"▸ "; + } + ul.has-children.expanded > p::before { + content:"▾ "; } ul.expanded > ul { display: block; } - ul.disabled { + ul.disabled > p { opacity: 0.4; + } + ul.disabled { pointer-events: none; } label { display: inline-flex; align-items: center; gap: 4px; + line-height: 1; + user-select: none; + cursor: pointer; } - .graph svg { + input { + outline: none; + } + #graph svg { width: 100%; height: 100%; } @@ -131,18 +155,18 @@ position: relative; height: 100%; } - .metadata > * + *, .rewrite-container > * + *, .ctx-list > * + * { + .metadata > * + *, .info > * + *, .rewrite-container > * + *, .ctx-list > * + * { margin-top: 12px; } - .ctx-list > ul > * + * { + ul > * + *, .args > * + * { margin-top: 4px; } - .graph { + #graph { position: absolute; inset: 0; z-index: 1; } - .profiler, .disasm { + #profiler, #custom { flex: 1 1 auto; min-width: 0; width: 100%; @@ -223,6 +247,9 @@ max-height: 30vh; padding: 8px; } + pre.full-height code.hljs { + max-height: none; + } #progress-message { position: absolute; z-index: 2; @@ -257,12 +284,16 @@ height: fit-content; } .raw-text { - padding: 0 8px; + padding-left: 15px; width: 100%; height: 100%; max-height: 100vh; overflow-x: auto; } + .raw-text > pre { + display: inline-block; + min-width: 100%; + } .raw-text code { max-height: none !important; } @@ -315,15 +346,6 @@ font-size: 0.95em; letter-spacing: 0.03em; } - .legend { - display: flex; - align-items: center; - } - .legend > div { - width: 0.95em; - height: 0.95em; - margin-right: 4px; - } @@ -340,9 +362,8 @@
-
-
-
+
+
@@ -356,6 +377,7 @@
+
diff --git a/tinygrad/viz/js/index.js b/tinygrad/viz/js/index.js index ab00826ce8..415aaa742e 100644 --- a/tinygrad/viz/js/index.js +++ b/tinygrad/viz/js/index.js @@ -1,8 +1,9 @@ // ** graph helpers -const displayGraph = (cls) => { - for (const e of document.getElementsByClassName("view")) e.style.display = e.classList.contains(cls) ? "flex" : "none"; +const displaySelection = (sel) => { + for (const e of document.getElementsByClassName("view")) e.style.display = e.matches(sel) ? "flex" : "none"; } +const metadata = document.querySelector(".metadata"); const darkenHex = (h, p = 0) => `#${( @@ -14,13 +15,17 @@ const darkenHex = (h, p = 0) => ).toString(16).padStart(6, '0')}`; const ANSI_COLORS = ["#b3b3b3", "#ff6666", "#66b366", "#ffff66", "#6666ff", "#ff66ff", "#66ffff", "#ffffff"]; +const ANSI_COLORS_LIGHT = ["#d9d9d9","#ff9999","#99cc99","#ffff99","#9999ff","#ff99ff","#ccffff","#ffffff"]; const parseColors = (name, defaultColor="#ffffff") => Array.from(name.matchAll(/(?:\u001b\[(\d+)m([\s\S]*?)\u001b\[0m)|([^\u001b]+)/g), - ([_, code, colored_st, st]) => ({ st: colored_st ?? st, color: code != null ? ANSI_COLORS[(parseInt(code)-30+60)%60] : defaultColor })); + ([_, code, colored_st, st]) => ({ st: colored_st ?? st, color: code != null ? (code>=90 ? ANSI_COLORS_LIGHT : ANSI_COLORS)[(parseInt(code)-30+60)%60] : defaultColor })); + +const colored = n => d3.create("span").call(s => s.selectAll("span").data(typeof n === "string" ? parseColors(n) : n).join("span") + .style("color", d => d.color).text(d => d.st)).node(); const rect = (s) => (typeof s === "string" ? document.querySelector(s) : s).getBoundingClientRect(); let timeout = null; -const updateProgress = ({ start }) => { +const updateProgress = ({ start, err }) => { clearTimeout(timeout); const msg = document.getElementById("progress-message"); msg.style.display = "none"; @@ -28,10 +33,13 @@ const updateProgress = ({ start }) => { msg.innerText = "Rendering new graph..."; timeout = setTimeout(() => { msg.style.display = "block"; }, 2000); } + d3.select("#custom").html(""); + if (err) { + displaySelection("#custom"); + d3.select("#custom").append(() => d3.create("div").classed("raw-text", true).call(s => s.append(() => codeBlock(err, "txt"))).node()); + } } -// ** UOp graph - function intersectRect(r1, r2) { const dx = r2.x-r1.x; const dy = r2.y-r1.y; @@ -47,69 +55,78 @@ function addTags(root) { root.selectAll("text").data(d => [d]).join("text").text(d => d).attr("dy", "0.35em"); } -let [workerUrl, worker] = [null, null]; +const drawGraph = (data) => { + const g = dagre.graphlib.json.read(data); + // draw nodes + d3.select("#graph-svg").on("click", () => d3.selectAll(".highlight").classed("highlight", false)); + const nodes = d3.select("#nodes").selectAll("g").data(g.nodes().map(id => g.node(id)), d => d).join("g").attr("class", d => d.className ?? "node") + .attr("transform", d => `translate(${d.x},${d.y})`).classed("clickable", d => d.ref != null).on("click", (e,d) => { + if (d.ref != null) return switchCtx(d.ref); + const parents = g.predecessors(d.id); + const children = g.successors(d.id); + if (parents == null && children == null) return; + const src = [...parents, ...children, d.id]; + nodes.classed("highlight", n => src.includes(n.id)).classed("child", n => children.includes(n.id)); + const matchEdge = (v, w) => (v===d.id && children.includes(w)) ? "highlight child " : (parents.includes(v) && w===d.id) ? "highlight " : ""; + d3.select("#edges").selectAll("path.edgePath").attr("class", e => matchEdge(e.v, e.w)+"edgePath"); + d3.select("#edge-labels").selectAll("g.port").attr("class", (_, i, n) => matchEdge(...n[i].id.split("-"))+"port"); + e.stopPropagation(); + }); + nodes.selectAll("rect").data(d => [d]).join("rect").attr("width", d => d.width).attr("height", d => d.height).attr("fill", d => d.color) + .attr("x", d => -d.width/2).attr("y", d => -d.height/2); + const STROKE_WIDTH = 1.4; + const labels = nodes.selectAll("g.label").data(d => [d]).join("g").attr("class", "label"); + const hasLabelDims = data.nodes[0]?.value.labelWidth != null; + if (hasLabelDims) labels.attr("transform", d => `translate(-${d.labelWidth/2}, -${d.labelHeight/2+STROKE_WIDTH*2})`); + labels.selectAll("text").data(d => { + const ret = [[]]; + for (const { st, color } of parseColors(d.label, defaultColor="initial")) { + const lines = st.split("\n"); + ret.at(-1).push({ st:lines[0], color }); + for (let i=1; i d).join("tspan").attr("x", "0").attr("dy", 14).selectAll("tspan").data(d => d).join("tspan") + .attr("fill", d => darkenHex(d.color, 25)).text(d => d.st).attr("xml:space", "preserve"); + // recenter after drawing texts if needed + if (!hasLabelDims) labels.attr("transform", (_,i,els) => { + const b = els[i].getBBox(); + return `translate(${-b.x-b.width/2}, ${-b.y-b.height/2})` + }); + addTags(nodes.selectAll("g.tag").data(d => d.tag != null ? [d] : []).join("g").attr("class", "tag") + .attr("transform", d => `translate(${-d.width/2+8}, ${-d.height/2+8})`).datum(e => e.tag)); + // draw edges + const line = d3.line().x(d => d.x).y(d => d.y).curve(d3.curveBasis), edges = g.edges(); + d3.select("#edges").selectAll("path.edgePath").data(edges).join("path").attr("class", "edgePath").attr("d", (e) => { + const edge = g.edge(e); + const points = edge.points.slice(1, edge.points.length-1); + points.unshift(intersectRect(g.node(e.v), points[0])); + points.push(intersectRect(g.node(e.w), points[points.length-1])); + return line(points); + }).attr("marker-end", "url(#arrowhead)"); +} + +// ** UOp graph + +let workerUrl = null, worker = null; async function initWorker() { const resp = await Promise.all(["/assets/dagrejs.github.io/project/dagre/latest/dagre.min.js","/js/worker.js"].map(u => fetch(u))); workerUrl = URL.createObjectURL(new Blob([(await Promise.all(resp.map((r) => r.text()))).join("\n")], { type: "application/javascript" })); } -function renderDag(graph, additions, recenter) { +function renderDag(graph, additions, recenter, layoutOpts) { // start calculating the new layout (non-blocking) updateProgress({ start:true }); if (worker != null) worker.terminate(); worker = new Worker(workerUrl); - worker.postMessage({graph, additions}); + worker.postMessage({graph, additions, opts:layoutOpts }); worker.onmessage = (e) => { - displayGraph("graph"); + displaySelection("#graph"); updateProgress({ start:false }); - const g = dagre.graphlib.json.read(e.data); - // draw nodes - const STROKE_WIDTH = 1.4; - d3.select("#graph-svg").on("click", () => d3.selectAll(".highlight").classed("highlight", false)); - const nodes = d3.select("#nodes").selectAll("g").data(g.nodes().map(id => g.node(id)), d => d).join("g").attr("class", d => d.className ?? "node") - .attr("transform", d => `translate(${d.x},${d.y})`).classed("clickable", d => d.ref != null).on("click", (e,d) => { - if (d.ref != null) return setCtxWithHistory(d.ref); - const parents = g.predecessors(d.id); - const children = g.successors(d.id); - if (parents == null && children == null) return; - const src = [...parents, ...children, d.id]; - nodes.classed("highlight", n => src.includes(n.id)).classed("child", n => children.includes(n.id)); - const matchEdge = (v, w) => (v===d.id && children.includes(w)) ? "highlight child " : (parents.includes(v) && w===d.id) ? "highlight " : ""; - d3.select("#edges").selectAll("path.edgePath").attr("class", e => matchEdge(e.v, e.w)+"edgePath"); - d3.select("#edge-labels").selectAll("g.port").attr("class", (_, i, n) => matchEdge(...n[i].id.split("-"))+"port"); - e.stopPropagation(); - }); - nodes.selectAll("rect").data(d => [d]).join("rect").attr("width", d => d.width).attr("height", d => d.height).attr("fill", d => d.color) - .attr("x", d => -d.width/2).attr("y", d => -d.height/2); - nodes.selectAll("g.label").data(d => [d]).join("g").attr("class", "label").attr("transform", d => { - const x = (d.width-d.padding*2)/2; - const y = (d.height-d.padding*2)/2+STROKE_WIDTH; - return `translate(-${x}, -${y})`; - }).selectAll("text").data(d => { - const ret = [[]]; - for (const { st, color } of parseColors(d.label, defaultColor="initial")) { - for (const [i, l] of st.split("\n").entries()) { - if (i > 0) ret.push([]); - ret.at(-1).push({ st:l, color }); - } - } - return [ret]; - }).join("text").selectAll("tspan").data(d => d).join("tspan").attr("x", "0").attr("dy", 14).selectAll("tspan").data(d => d).join("tspan") - .attr("fill", d => darkenHex(d.color, 25)).text(d => d.st).attr("xml:space", "preserve"); - addTags(nodes.selectAll("g.tag").data(d => d.tag != null ? [d] : []).join("g").attr("class", "tag") - .attr("transform", d => `translate(${-d.width/2+8}, ${-d.height/2+8})`).datum(e => e.tag)); - // draw edges - const line = d3.line().x(d => d.x).y(d => d.y).curve(d3.curveBasis), edges = g.edges(); - d3.select("#edges").selectAll("path.edgePath").data(edges).join("path").attr("class", "edgePath").attr("d", (e) => { - const edge = g.edge(e); - const points = edge.points.slice(1, edge.points.length-1); - points.unshift(intersectRect(g.node(e.v), points[0])); - points.push(intersectRect(g.node(e.w), points[points.length-1])); - return line(points); - }).attr("marker-end", "url(#arrowhead)"); - addTags(d3.select("#edge-labels").selectAll("g").data(edges).join("g").attr("transform", (e) => { + drawGraph(e.data); + addTags(d3.select("#edge-labels").selectAll("g").data(e.data.edges).join("g").attr("transform", (e) => { // get a point near the end - const [p1, p2] = g.edge(e).points.slice(-2); + const [p1, p2] = e.value.points.slice(-2); const dx = p2.x-p1.x; const dy = p2.y-p1.y; // normalize to the unit vector @@ -121,9 +138,13 @@ function renderDag(graph, additions, recenter) { const x = p2.x - ux * offset; const y = p2.y - uy * offset; return `translate(${x}, ${y})` - }).attr("class", e => g.edge(e).label.type).attr("id", e => `${e.v}-${e.w}`).datum(e => g.edge(e).label.text)); + }).attr("class", e => e.value.label.type).attr("id", e => `${e.v}-${e.w}`).datum(e => e.value.label.text)); if (recenter) document.getElementById("zoom-to-fit-btn").click(); }; + worker.onerror = (e) => { + e.preventDefault(); + updateProgress({ err:"Error in graph layout:\n"+e.message }); + } } // ** profiler graph @@ -137,17 +158,18 @@ const formatUnit = (d, unit="") => d3.format(".3~s")(d)+unit; const colorScheme = {TINY:["#1b5745", "#354f52", "#354f52", "#1d2e62", "#63b0cd"], DEFAULT:["#2b2e39", "#2c2f3a", "#31343f", "#323544", "#2d303a", "#2e313c", "#343746", "#353847", "#3c4050", "#404459", "#444862", "#4a4e65"], - BUFFER:["#3A57B7","#5066C1","#6277CD","#7488D8","#8A9BE3","#A3B4F2"], + BUFFER:["#342483", "#3E2E94", "#4938A4", "#5442B4", "#5E4CC2", "#674FCA"], CATEGORICAL:["#ff8080", "#F4A261", "#C8F9D4", "#8D99AE", "#F4A261", "#ffffa2", "#ffffc0", "#87CEEB"],} const cycleColors = (lst, i) => lst[i%lst.length]; const rescaleTrack = (source, tid, k) => { - for (const e of source.shapes) { - for (let i=0; i { ctx.stroke(); } -var data, focusedDevice, canvasZoom, zoomLevel = d3.zoomIdentity; +function tabulate(rows) { + const root = d3.create("div").style("display", "grid").style("grid-template-columns", `${Math.max(...rows.map(x => x[0].length), 0)}ch 1fr`).style("gap", "0.2em"); + for (const [k,v] of rows) { root.append("div").text(k); root.append("div").node().append(v); } + return root; +} + +var data, focusedDevice, focusedShape, canvasZoom, zoomLevel = d3.zoomIdentity, shapeMetadata = new Map(); +function focusShape(shape) { + saveToHistory({ shape:focusedShape }); + focusedShape = shape?.key; d3.select("#timeline").call(canvasZoom.transform, zoomLevel); + return metadata.replaceChildren(shapeMetadata.get(focusedShape) ?? ""); +} + async function renderProfiler() { - displayGraph("profiler"); - d3.select(".metadata").html(""); + displaySelection("#profiler"); + metadata.replaceChildren(shapeMetadata.get(focusedShape) ?? ""); // layout once! if (data != null) return updateProgress({ start:false }); - const profiler = d3.select(".profiler").html(""); + const profiler = d3.select("#profiler").html(""); const buf = await (await fetch("/get_profile")).arrayBuffer(); const view = new DataView(buf); let offset = 0; @@ -191,6 +225,8 @@ async function renderProfiler() { const canvasTop = rect(canvas).top; // color by key (name/device) const colorMap = new Map(); + // map shapes by event key + const shapeMap = new Map(); data = {tracks:new Map(), axes:{}}; const heightScale = d3.scaleLinear().domain([0, tracePeak]).range([4,maxheight=100]); for (let i=0; i e.st >= levelEt); const et = e.st+Math.trunc(e.dur); @@ -221,14 +257,26 @@ async function renderProfiler() { const base = colorMap.get(colorKey), s = Math.min(Math.pow(1/0.7, depth), 240 / Math.max(base.r, base.g, base.b)); const fillColor = d3.rgb(base.r*s, base.g*s, base.b*s).toString(); const label = parseColors(e.name).map(({ color, st }) => ({ color, st, width:ctx.measureText(st).width })); - if (e.ref != null) ref = {ctx:e.ref, step:0}; + let shapeRef = e.ref; + if (shapeRef != null) { ref = {ctx:e.ref, step:0}; shapeRef = ref; } else if (ref != null) { const start = ref.step>0 ? ref.step+1 : 0; const stepIdx = ctxs[ref.ctx+1].steps.findIndex((s, i) => i >= start && s.name == e.name); - ref = stepIdx === -1 ? null : {ctx:ref.ctx, step:stepIdx}; + if (stepIdx !== -1) { ref.step = stepIdx; shapeRef = ref; } } - const htmlLabel = label.map(({color, st}) => `${st}`).join(''); - const arg = { tooltipText:htmlLabel+"\n"+formatTime(e.dur)+(e.info != null ? "\n"+e.info : ""), ...ref }; + const html = d3.create("div").classed("info", true); + html.append(() => tabulate([["Name", colored(e.name)], ["Duration", formatTime(e.dur)], ["Start Time", formatTime(e.st)]]).node()); + html.append("div").classed("args", true); + if (e.info != null) html.append("p").style("white-space", "pre-wrap").text(e.info); + if (shapeRef != null) { + html.append("a").text("View codegen rewrite").on("click", () => switchCtx(shapeRef.ctx, shapeRef.step)); + html.append("a").text("View program").on("click", () => switchCtx(shapeRef.ctx, ctxs[shapeRef.ctx+1].steps.findIndex(s => s.name==="View Program"))); + } + // tiny device events go straight to the rewrite rule + const key = k.startsWith("TINY") ? null : `${k}-${j}`; + if (key != null) shapeMetadata.set(key, html.node()); + const arg = { tooltipText:colored(e.name).outerHTML+"\n"+formatTime(e.dur)+(e.info != null ? "\n"+e.info : ""), key, ...shapeRef }; + if (e.key != null) shapeMap.set(e.key, arg); // offset y by depth shapes.push({x:e.st, y:levelHeight*depth, width:e.dur, height:levelHeight, arg, label, fillColor }); } @@ -237,7 +285,7 @@ async function renderProfiler() { const peak = u64(); let x = 0, y = 0; const buf_shapes = new Map(), temp = new Map(); - const timestamps = []; + const timestamps = [], valueMap = new Map(); for (let j=0; j ({shape:shapeMap.get(u32()), repr:strings[u32()], num:u8(), mode:u8()})); + timestamps.push(ts); valueMap.set(ts, y); x += 1; y -= free.nbytes; free.x.push(x); free.y.push(free.y.at(-1)); @@ -260,29 +309,72 @@ async function renderProfiler() { } } } - for (const [_, v] of temp) { - v.x.push(x); - v.y.push(v.y.at(-1)); - } timestamps.push(dur); const height = heightScale(peak); const yscale = d3.scaleLinear().domain([0, peak]).range([height, 0]); - for (const [num, {dtype, sz, nbytes, y, x:steps}] of buf_shapes) { + for (const [num, {dtype, sz, nbytes, y, x:steps, users}] of buf_shapes) { const x = steps.map(s => timestamps[s]); const dur = x.at(-1)-x[0]; - const arg = {tooltipText:`${dtype} len:${formatUnit(sz)}\n${formatUnit(nbytes, "B")}\nnum:${num}\nalive for ${formatTime(dur)}`}; + const html = d3.create("div").classed("info", true); + const rows = [["DType", dtype], ["Len", formatUnit(sz)], ["Size", formatUnit(nbytes, "B")], ["Lifetime", formatTime(dur)]]; + if (users != null) rows.push(["Users", users.length]); + const info = html.append(() => tabulate(rows).node()); + const arg = {tooltipText:info.node().outerHTML, key:`${k}-${num}`}; + const kernels = html.append("div").classed("args", true); + for (let u=0; u colored(`[${u}] ${repr} ${bufInfo}`)); + const shapeTxt = shape?.tooltipText?.split("\n").at(-1); + if (shapeTxt != null) p.append("span").text(" "+shapeTxt); + if (shape != null) { + p.style("cursor", "pointer").on("click", () => focusShape(shape)) + const args = shapeMetadata.get(shape.key).querySelector(".args"); + const bufArg = d3.create("p").text(`${bufInfo} ${rows[2][1]}`).style("cursor", "pointer").on("click", () => { + const device = document.getElementById(k); + if (!isExpanded(device)) device.click(); + focusShape(arg); + }).node(); + bufArg.dataset.num = num; + let before = null; + for (const c of args.children) { if (+c.dataset.num > num) { before = c; break; } } + args.insertBefore(bufArg, before); + } + } + shapeMetadata.set(arg.key, html.node()) shapes.push({ x, y0:y.map(yscale), y1:y.map(y0 => yscale(y0+nbytes)), arg, fillColor:cycleColors(colorScheme.BUFFER, shapes.length) }); } - data.tracks.set(k, { shapes, visible, offsetY, height, peak, scaleFactor:maxheight*4/height }); + // generic polygon merger + const base0 = yscale(0); + const allX = Array.from(new Set(shapes.flatMap(s => s.x))).sort((a,b)=>a-b); + const idxs = new Map(allX.map((x,i) => [x, i])); + const maxY = new Map(allX.map(x => [x, base0])); + // for every [a,b) update the max y at x + for (const sh of shapes) { + for (let i=0; i { const newFocus = e.currentTarget.id === focusedDevice ? null : e.currentTarget.id; let offset = 0; for (const [tid, track] of data.tracks) { track.offsetY += offset; - if (tid === newFocus) offset += rescaleTrack(track, tid, track.scaleFactor); - else if (tid === focusedDevice) offset += rescaleTrack(track, tid, 1/track.scaleFactor); + if (tid === newFocus) { track.shapes = track.views[1]; offset += rescaleTrack(track, tid, track.scaleFactor); } + else if (tid === focusedDevice) { track.shapes = track.views[0]; offset += rescaleTrack(track, tid, 1/track.scaleFactor); } } data.axes.y = newFocus != null ? { domain:[0, (t=data.tracks.get(newFocus)).peak], range:[t.offsetY+t.height, t.offsetY], fmt:"B" } : null; + toggleCls(document.getElementById(focusedDevice), document.getElementById(newFocus), "expanded"); focusedDevice = newFocus; return resize(); }); @@ -301,47 +393,47 @@ async function renderProfiler() { const st = visibleX[0], et = visibleX[1]; xscale.domain(visibleX); // draw shapes - for (const [_, { offsetY, shapes, visible }] of data.tracks) { + const paths = []; + for (const [_, { offsetY, shapes, visible, valueMap, pcolor }] of data.tracks) { visible.length = 0; for (const e of shapes) { - // generic polygon - if (e.width == null) { + const p = new Path2D(); + if (e.width == null) { // generic polygon if (e.x[0]>et || e.x.at(-1)=0; i--) ctx.lineTo(x[i], offsetY+e.y1[i]); - ctx.closePath(); - ctx.fillStyle = e.fillColor; ctx.fill(); - continue; - } - // contiguous rect - if (e.x>et || e.x+e.width width) { - if (labelWidth !== 0) ctx.fillText("...", labelX, labelY); - break; + for (let i=x.length-1; i>=0; i--) p.lineTo(x[i], offsetY+e.y1[i]); + p.closePath(); + ctx.fillStyle = e.fillColor; ctx.fill(p); + } else { // contiguous rect + if (e.x>et || e.x+e.width width) { + if (lw>0) ctx.fillText("...", lx+lw, ly); + break; + } + ctx.textBaseline = "middle"; + ctx.fillStyle = e.label[li].color; + ctx.fillText(e.label[li].st, lx+lw, ly); + lw += e.label[li].width; } - ctx.fillStyle = l.color; - ctx.fillText(l.st, labelX, labelY); - labelWidth += l.width; - labelX += l.width; } + if (focusedShape != null && e.arg?.key === focusedShape) { paths.push([p, pcolor]); } } } // draw axes @@ -365,15 +457,17 @@ async function renderProfiler() { } } // draw markers + ctx.textBaseline = "top"; for (const m of markers) { const x = xscale(m.ts); drawLine(ctx, [x, x], [0, canvas.clientHeight], { color:m.color }); ctx.fillText(m.name, x+2, 1); } + for (const [p, color] of paths) { ctx.lineWidth = 1.4; ctx.strokeStyle = color; ctx.stroke(p); } } function resize() { - const profiler = document.querySelector(".profiler"); + const profiler = document.querySelector("#profiler"); const sideRect = rect("#device-list"); const width = profiler.clientWidth-(sideRect.width+padding), height = Math.round(sideRect.height); if (canvas.width === width*dpr && canvas.height === height*dpr) return; @@ -406,11 +500,15 @@ async function renderProfiler() { } } - canvas.addEventListener("click", e => { + const clickShape = (e) => { e.preventDefault(); const foundRect = findRectAtPosition(e.clientX, e.clientY); - if (foundRect?.step != null) return setCtxWithHistory(foundRect.ctx, foundRect.step); - }); + if (foundRect?.step != null && (foundRect?.key == null || e.type == "dblclick")) { return switchCtx(foundRect.ctx, foundRect.step); } + if (foundRect?.key != focusedShape) { focusShape(foundRect); } + } + canvas.addEventListener("click", clickShape); + + canvas.addEventListener("dblclick", clickShape); canvas.addEventListener("mousemove", e => { const foundRect = findRectAtPosition(e.clientX, e.clientY); @@ -453,38 +551,24 @@ document.getElementById("zoom-to-fit-btn").addEventListener("click", () => { // **** main VIZ interfacae +const pathLink = (fp, lineno) => d3.create("a").attr("href", "vscode://file/"+fp+":"+lineno).text(`${fp.split("/").at(-1)}:${lineno}`); function codeBlock(st, language, { loc, wrap }={}) { const code = document.createElement("code"); - code.innerHTML = hljs.highlight(st, { language }).value; + // plaintext renders like a terminal print, otherwise render with syntax highlighting + if (language === "txt") code.appendChild(colored(st)); + else code.innerHTML = hljs.highlight(st, { language }).value; code.className = "hljs"; const ret = document.createElement("pre"); if (wrap) ret.className = "wrap"; - if (loc != null) { - const link = ret.appendChild(document.createElement("a")); - link.href = "vscode://file/"+loc.join(":"); - link.textContent = `${loc[0].split("/").at(-1)}:${loc[1]}`+"\n\n"; - } + if (loc != null) ret.appendChild(pathLink(loc[0], loc[1]).style("margin-bottom", "4px").node()); ret.appendChild(code); return ret; } -function appendTd(tr, value, unit=null) { - const fmt = (typeof value === "number" && !Number.isInteger(value)) ? value.toFixed(2) : value; - tr.appendChild(document.createElement("td")).innerText = unit == "us" ? formatTime(value) : fmt+(unit ?? ""); -} - -function appendRow(table, name, value, unit=null, cls="main-row") { - const tr = table.appendChild(document.createElement("tr")); - tr.className = cls; - tr.appendChild(document.createElement("td")).innerText = name; - appendTd(tr, value, unit); - return tr; -} - -function setActive(e) { - if (e == null) return; - e.classList.add("active"); - requestAnimationFrame(() => e.scrollIntoView({ behavior: "auto", block: "nearest" })); +function toggleCls(prev, next, cls, value) { + prev?.classList.remove(cls); + next?.classList.toggle(cls, value ?? true); + requestAnimationFrame(() => next?.scrollIntoView({ behavior: "auto", block: "nearest" })); } // ** hljs extra definitions for UOps and float4 @@ -514,34 +598,49 @@ const evtSources = []; // context: collection of steps const state = {currentCtx:-1, currentStep:0, currentRewrite:0, expandSteps:false}; function setState(ns) { - const { currentCtx:prevCtx, currentStep:prevStep } = state; + const { ctx:prevCtx, step:prevStep } = select(state.currentCtx, state.currentStep); + const prevRewrite = state.currentRewrite; Object.assign(state, ns); // update element styles if needed - document.getElementById(`ctx-${state.currentCtx}`)?.classList.toggle("expanded", state.expandSteps); - if (state.currentCtx !== prevCtx) { - document.getElementById(`ctx-${prevCtx}`)?.classList.remove("active", "expanded"); - setActive(document.getElementById(`ctx-${state.currentCtx}`)); + const { ctx, step } = select(state.currentCtx, state.currentStep); + toggleCls(prevCtx, ctx, "expanded", state.expandSteps); + if (ctx?.id !== prevCtx?.id) { + saveToHistory({ currentCtx:deselect(prevCtx).ctx, currentStep:deselect(prevStep).step || 0, currentRewrite:prevRewrite, expandSteps:true }); + toggleCls(prevCtx, ctx, "active"); } - if (state.currentCtx !== prevCtx || state.currentStep !== prevStep) { - document.getElementById(`step-${prevCtx}-${prevStep}`)?.classList.remove("active"); - setActive(document.getElementById(`step-${state.currentCtx}-${state.currentStep}`)); + if (ctx?.id !== prevCtx?.id || step?.id !== prevStep?.id) { + toggleCls(prevStep, step, "active"); + // walk the tree back until all parents expanded so that the child is visible + let e = step; + while (e?.parentElement?.id.startsWith("step")) { + e.parentElement.classList.add("expanded"); + e = e.parentElement; + } } // re-render main(); } -// set a new context and keep the old one in browser history -function setCtxWithHistory(newCtx, step=0) { +const getSubrewrites = (ul) => ul.querySelectorAll(":scope > ul"); + +function saveToHistory(ns) { // NOTE: browser does a structured clone, passing a mutable object is safe. - history.replaceState(state, ""); - history.pushState(state, ""); - setState({ expandSteps:true, currentCtx:newCtx+1, currentStep:step, currentRewrite:0 }); + history.replaceState(ns, ""); + history.pushState(ns, ""); } +// switch to the start of a new graph and expand all the steps +const switchCtx = (newCtx, step) => setState({ expandSteps:true, currentCtx:newCtx+1, currentStep:step ?? 0, currentRewrite:0 }); + window.addEventListener("popstate", (e) => { + if (e.state?.shape != null) return focusShape({ key:e.state?.shape }); if (e.state != null) setState(e.state); }); +const toggleLabel = d3.create("label").text("Show indexing (r)").node(); +const toggle = d3.create("input").attr("type", "checkbox").attr("id", "show-indexing").property("checked", true).node(); +toggleLabel.prepend(toggle); + async function main() { // ** left sidebar context list if (ctxs == null) { @@ -552,19 +651,29 @@ async function main() { const ul = ctxList.appendChild(document.createElement("ul")); ul.id = `ctx-${i}`; const p = ul.appendChild(document.createElement("p")); - p.innerHTML = parseColors(name).map(c => `${c.st}`).join(""); + p.appendChild(colored(name)); p.onclick = () => { setState(i === state.currentCtx ? { expandSteps:!state.expandSteps } : { expandSteps:true, currentCtx:i, currentStep:0, currentRewrite:0 }); } + const stack = []; let list = ul; for (const [j,u] of steps.entries()) { - const inner = ul.appendChild(document.createElement("ul")); - inner.id = `step-${i}-${j}`; - inner.innerText = `${u.name ?? u.loc[0].replaceAll("\\", "/").split("/").pop()+':'+u.loc[1]}`+(u.match_count ? ` - ${u.match_count}` : ''); - inner.style.marginLeft = `${8*u.depth}px`; - inner.onclick = (e) => { + while (stack.length && stack.at(-1).depth >= u.depth) stack.pop(); + const list = stack.length > 0 ? stack.at(-1).li : ul; + u.li = list.appendChild(document.createElement("ul")); + u.li.id = `step-${i}-${j}`; + const p = u.li.appendChild(document.createElement("p")); + p.appendChild(colored(`${u.name}`+(u.match_count ? ` - ${u.match_count}` : ''))); + p.onclick = (e) => { e.stopPropagation(); + const subrewrites = getSubrewrites(e.currentTarget.parentElement); + if (subrewrites.length) { e.currentTarget.parentElement.classList.toggle("expanded"); } setState({ currentStep:j, currentCtx:i, currentRewrite:0 }); } + stack.push(u); + } + for (const l of ul.querySelectorAll("ul > ul > p")) { + const subrewrites = getSubrewrites(l.parentElement); + if (subrewrites.length > 0) { l.appendChild(d3.create("span").text(` (${subrewrites.length})`).node()); l.parentElement.classList.add("has-children"); } } } return setState({ currentCtx:-1 }); @@ -588,13 +697,11 @@ async function main() { ret = cache[ckey]; } // ** Disassembly view - if (ckey.startsWith("/disasm")) { + if (ckey.startsWith("/render")) { if (!(ckey in cache)) cache[ckey] = ret = await (await fetch(ckey)).json(); - displayGraph("disasm"); - const root = document.createElement("div"); - root.className = "raw-text"; - const metadata = document.querySelector(".metadata"); + displaySelection("#custom"); metadata.innerHTML = ""; + const root = d3.create("div").classed("raw-text", true).node(); // detailed assembly view if (ret.cols != null) { const asm = root.appendChild(document.createElement("table")); @@ -605,7 +712,7 @@ async function main() { tr.className = "main-row code-row"; for (const [i,value] of r.entries()) { // string format scalar values - if (!Array.isArray(value)) appendTd(tr, value); + if (!Array.isArray(value)) tr.appendChild(document.createElement("td")).innerText = value; // display arrays in a bar graph else { const segmentsTd = tr.appendChild(document.createElement("td")); @@ -620,19 +727,12 @@ async function main() { } } } - const summary = metadata.appendChild(document.createElement("table")); - for (const s of ret.summary) { - const tr = summary.appendChild(document.createElement("tr")); - tr.className = "main-row"; - const td = tr.appendChild(document.createElement("td")); - const div = td.appendChild(document.createElement("div")); - div.className = "legend"; - div.appendChild(document.createElement("div")).style.background = cycleColors(colorScheme.CATEGORICAL, s.idx); - div.appendChild(document.createElement("p")).textContent = s.label; - appendTd(tr, s.value); - } - } else root.appendChild(codeBlock(ret.src, "x86asm")); - return document.querySelector(".disasm").replaceChildren(root); + metadata.appendChild(tabulate(ret.summary.map(s => { + const div = d3.create("div").style("background", cycleColors(colorScheme.CATEGORICAL, s.idx)).style("width", "100%").style("height", "100%"); + return [s.label.trim(), div.text(s.value.toLocaleString()).node()]; + })).node()); + } else root.appendChild(codeBlock(ret.src, ret.lang || "txt")); + return document.querySelector("#custom").replaceChildren(root); } // ** UOp view (default) // if we don't have a complete cache yet we start streaming rewrites in this step @@ -653,19 +753,31 @@ async function main() { }; } if (ret.length === 0) return; - renderDag(ret[currentRewrite].graph, ret[currentRewrite].changed_nodes ?? [], currentRewrite === 0); + // ** center UOp graph + const render = (opts) => renderDag(ret[currentRewrite].graph, ret[currentRewrite].changed_nodes ?? [], currentRewrite === 0, opts); + render({ showIndexing:toggle.checked }); + toggle.onchange = (e) => render({ showIndexing:e.target.checked }); // ** right sidebar code blocks - const metadata = document.querySelector(".metadata"); - const [code, lang] = ctx.fmt != null ? [ctx.fmt, "cpp"] : [ret[currentRewrite].uop, "python"]; - metadata.replaceChildren(codeBlock(step.code_line, "python", { loc:step.loc, wrap:true }), codeBlock(code, lang, { wrap:false })); + const codeElement = codeBlock(ret[currentRewrite].uop, "python", { wrap:false }); + metadata.replaceChildren(toggleLabel, codeBlock(step.code_line, "python", { loc:step.loc, wrap:true }), codeElement); + if (step.trace) { + const trace = d3.create("pre").append("code").classed("hljs", true); + for (let i=step.trace.length-1; i>=0; i--) { + const [fp, lineno, fn, code] = step.trace[i]; + trace.append("div").style("margin-bottom", "2px").style("display","flex").text(fn+" ").append(() => pathLink(fp, lineno).node()); + trace.append("div").html(hljs.highlight(code, { language: "python" }).value).style("margin-bottom", "1ex"); + } + metadata.insertBefore(trace.node().parentNode, codeElement); + } // ** rewrite steps if (step.match_count >= 1) { const rewriteList = metadata.appendChild(document.createElement("div")); rewriteList.className = "rewrite-list"; for (let s=0; s<=step.match_count; s++) { const ul = rewriteList.appendChild(document.createElement("ul")); - ul.innerText = s; ul.id = `rewrite-${s}`; + const p = ul.appendChild(document.createElement("p")); + p.innerText = s; ul.onclick = () => setState({ currentRewrite:s }); ul.className = s > ret.length-1 ? "disabled" : s === currentRewrite ? "active" : ""; if (s > 0 && s === currentRewrite) { @@ -673,15 +785,13 @@ async function main() { metadata.appendChild(codeBlock(upat[1], "python", { loc:upat[0], wrap:true })); const diffCode = metadata.appendChild(document.createElement("pre")).appendChild(document.createElement("code")); for (const line of diff) { - const span = diffCode.appendChild(document.createElement("span")); - span.style.color = line.startsWith("+") ? "#3aa56d" : line.startsWith("-") ? "#d14b4b" : "#f0f0f5"; - span.innerText = line; + diffCode.appendChild(colored([{st:line, color:line.startsWith("+") ? "#3aa56d" : line.startsWith("-") ? "#d14b4b" : "#f0f0f5"}])); diffCode.appendChild(document.createElement("br")); } diffCode.className = "wrap"; } } - } + } else codeElement.classList.add("full-height"); } // **** collapse/expand @@ -722,22 +832,32 @@ appendResizer(document.querySelector(".metadata-parent"), { minWidth: 20, maxWid // **** keyboard shortcuts +const select = (ctx, step) => ({ ctx:document.getElementById(`ctx-${ctx}`), step:document.getElementById(`step-${ctx}-${step}`) }); +const deselect = (element) => { + const parts = element?.id.split("-").map(Number); + return element?.id.startsWith("ctx") ? { ctx:parts[1], step:null } : element?.id.startsWith("step") ? {ctx:parts[1], step:parts[2]} : {}; +} +const isExpanded = (el) => el?.classList.contains("expanded"); + document.addEventListener("keydown", (event) => { const { currentCtx, currentStep, currentRewrite, expandSteps } = state; // up and down change the step or context from the list const changeStep = expandSteps && ctxs[currentCtx].steps?.length; + const { step, ctx } = select(currentCtx, currentStep); if (event.key == "ArrowUp") { event.preventDefault(); if (changeStep) { - return setState({ currentRewrite:0, currentStep:Math.max(0, currentStep-1) }); + let prev = deselect(step.previousElementSibling); + if (prev.step == null && isExpanded(step.parentElement)) prev = deselect(step.parentElement); + return prev.step != null && !isExpanded(step) && setState({ currentRewrite:0, currentStep:prev.step }); } return setState({ currentStep:0, currentRewrite:0, currentCtx:Math.max(0, currentCtx-1), expandSteps:false }); } if (event.key == "ArrowDown") { event.preventDefault(); if (changeStep) { - const totalUOps = ctxs[currentCtx].steps.length-1; - return setState({ currentRewrite:0, currentStep:Math.min(totalUOps, currentStep+1) }); + const next = deselect(isExpanded(step) ? step.children[1] : step.nextElementSibling); + return next.step != null && setState({ currentRewrite:0, currentStep:next.step }); } return setState({ currentStep:0, currentRewrite:0, currentCtx:Math.min(ctxs.length-1, currentCtx+1), expandSteps:false }); } @@ -747,6 +867,7 @@ document.addEventListener("keydown", (event) => { if (currentCtx === -1) { return setState({ currentCtx:0, expandSteps:true }); } + if (expandSteps && getSubrewrites(step).length) return step.children[0].click(); return setState({ expandSteps:!expandSteps }); } // left and right go through rewrites in a single UOp @@ -764,6 +885,10 @@ document.addEventListener("keydown", (event) => { event.preventDefault() document.getElementById("zoom-to-fit-btn").click(); } + // r key toggles indexing + if (event.key === "r") { + toggle.click(); + } }); main() diff --git a/tinygrad/viz/js/worker.js b/tinygrad/viz/js/worker.js index 8c3703908b..8669244de8 100644 --- a/tinygrad/viz/js/worker.js +++ b/tinygrad/viz/js/worker.js @@ -5,10 +5,10 @@ const ctx = canvas.getContext("2d"); ctx.font = `350 ${LINE_HEIGHT}px sans-serif`; onmessage = (e) => { - const { graph, additions } = e.data; + const { graph, additions, opts } = e.data; const g = new dagre.graphlib.Graph({ compound: true }); g.setGraph({ rankdir: "LR" }).setDefaultEdgeLabel(function() { return {}; }); - if (additions.length !== 0) g.setNode("addition", {label:"", className:"overlay", padding:0}); + if (additions.length !== 0) g.setNode("addition", {label:"", labelWidth:0, labelHeight:0, className:"overlay"}); for (let [k, {label, src, ref, ...rest }] of Object.entries(graph)) { // adjust node dims by label size (excluding escape codes) + add padding let [width, height] = [0, 0]; @@ -16,14 +16,23 @@ onmessage = (e) => { width = Math.max(width, ctx.measureText(line).width); height += LINE_HEIGHT; } - g.setNode(k, {width:width+NODE_PADDING*2, height:height+NODE_PADDING*2, padding:NODE_PADDING, label, ref, id:k, ...rest}); + g.setNode(k, {width:width+NODE_PADDING*2, height:height+NODE_PADDING*2, label, labelHeight:height, labelWidth:width, ref, id:k, ...rest}); // add edges const edgeCounts = {} for (const [_, s] of src) edgeCounts[s] = (edgeCounts[s] || 0)+1; for (const [port, s] of src) g.setEdge(s, k, { label: edgeCounts[s] > 1 ? {type:"tag", text:edgeCounts[s]} : {type:"port", text:port}}); if (additions.includes(parseInt(k))) g.setParent(k, "addition"); } + // optionally hide nodes from the layuot + if (!opts.showIndexing) { + for (const n of g.nodes()) { + const node = g.node(n); + if (node.label.includes("dtypes.index")) g.removeNode(n); + } + } dagre.layout(g); + // remove additions overlay if it's empty + if (!g.node("addition")?.width) g.removeNode("addition"); postMessage(dagre.graphlib.json.write(g)); self.close(); } diff --git a/tinygrad/viz/serve.py b/tinygrad/viz/serve.py index 2dc2641f7e..8a4207f3fa 100755 --- a/tinygrad/viz/serve.py +++ b/tinygrad/viz/serve.py @@ -1,50 +1,47 @@ #!/usr/bin/env python3 import multiprocessing, pickle, difflib, os, threading, json, time, sys, webbrowser, socket, argparse, socketserver, functools, codecs, io, struct -import subprocess, ctypes, pathlib -from contextlib import redirect_stdout +import subprocess, ctypes, pathlib, traceback +from contextlib import redirect_stdout, redirect_stderr from decimal import Decimal from http.server import BaseHTTPRequestHandler from urllib.parse import parse_qs, urlparse -from typing import Any, TypedDict, Generator +from typing import Any, TypedDict, TypeVar, Generator, Callable from tinygrad.helpers import colored, getenv, tqdm, unwrap, word_wrap, TRACEMETA, ProfileEvent, ProfileRangeEvent, TracingKey, ProfilePointEvent, temp -from tinygrad.uop.ops import TrackedGraphRewrite, UOp, Ops, printable, GroupOp, srender, sint, sym_infer, range_str +from tinygrad.helpers import printable +from tinygrad.uop.ops import TrackedGraphRewrite, RewriteTrace, UOp, Ops, GroupOp, srender, sint, sym_infer, range_str, pyrender +from tinygrad.uop.ops import print_uops, range_start, multirange_str from tinygrad.device import ProfileDeviceEvent, ProfileGraphEvent, ProfileGraphEntry, Device from tinygrad.renderer import ProgramSpec from tinygrad.dtype import dtypes -from tinygrad.codegen.opt import axis_colors uops_colors = {Ops.LOAD: "#ffc0c0", Ops.STORE: "#87CEEB", Ops.CONST: "#e0e0e0", Ops.VCONST: "#e0e0e0", Ops.REDUCE: "#FF5B5B", - Ops.DEFINE_GLOBAL: "#ffe0b0", Ops.DEFINE_LOCAL: "#ffe0d0", Ops.DEFINE_REG: "#f0ffe0", Ops.REDUCE_AXIS: "#FF6B6B", + Ops.DEFINE_GLOBAL:"#cb9037", **{x:"#f2cb91" for x in {Ops.DEFINE_LOCAL, Ops.DEFINE_REG}}, Ops.REDUCE_AXIS: "#FF6B6B", Ops.RANGE: "#c8a0e0", Ops.ASSIGN: "#909090", Ops.BARRIER: "#ff8080", Ops.IF: "#c8b0c0", Ops.SPECIAL: "#c0c0ff", - Ops.INDEX: "#e8ffa0", Ops.WMMA: "#efefc0", Ops.VIEW: "#C8F9D4", Ops.MULTI: "#f6ccff", Ops.KERNEL: "#3e7f55", - **{x:"#D8F9E4" for x in GroupOp.Movement}, **{x:"#ffffc0" for x in GroupOp.ALU}, Ops.THREEFRY:"#ffff80", Ops.BUFFER_VIEW: "#E5EAFF", - Ops.BLOCK: "#C4A484", Ops.BLOCKEND: "#C4A4A4", Ops.BUFFER: "#B0BDFF", Ops.COPY: "#a040a0", Ops.FUSE: "#FFa500", - Ops.ALLREDUCE: "#ff40a0", Ops.MSELECT: "#d040a0", Ops.MSTACK: "#d040a0", Ops.CONTIGUOUS: "#FFC14D", Ops.REALIZE: "#C1C14D", - Ops.CHILDREN: "#80ffc0", Ops.CHILD: "#80fff0", Ops.BUFFERIZE: "#FF991C", Ops.REWRITE_ERROR: "#ff2e2e", - Ops.SUBSTITUTE: "#ffff00"} + Ops.INDEX: "#cef263", Ops.WMMA: "#efefc0", Ops.MULTI: "#f6ccff", Ops.KERNEL: "#3e7f55", + **{x:"#D8F9E4" for x in GroupOp.Movement}, **{x:"#ffffc0" for x in GroupOp.ALU}, Ops.THREEFRY:"#ffff80", + Ops.BUFFER_VIEW: "#E5EAFF", Ops.BUFFER: "#B0BDFF", Ops.COPY: "#a040a0", + Ops.ALLREDUCE: "#ff40a0", Ops.MSELECT: "#d040a0", Ops.MSTACK: "#d040a0", Ops.CONTIGUOUS: "#FFC14D", + Ops.BUFFERIZE: "#FF991C", Ops.REWRITE_ERROR: "#ff2e2e", Ops.AFTER: "#8A7866", Ops.END: "#524C46"} # VIZ API -# ** Metadata for a track_rewrites scope +# ** list all saved rewrites ref_map:dict[Any, int] = {} -traces:dict[int, tuple] = {} -def get_metadata(trace_bufs:list[tuple]) -> list[dict]: +def get_rewrites(t:RewriteTrace) -> list[dict]: ret = [] - for keys,contexts,uop_fields in trace_bufs: - for k,v in zip(keys, contexts): - traces[i:=len(traces)] = (k, v, uop_fields) - steps = [{"name":s.name, "loc":s.loc, "depth":s.depth, "match_count":len(s.matches), "code_line":printable(s.loc), - "query":f"/ctxs?ctx={i}&idx={j}"} for j,s in enumerate(v)] - ret.append(r:={"name":k.display_name, "steps":steps}) - # program spec metadata - if isinstance(k.ret, ProgramSpec): - steps.append({"name":"View Disassembly", "query":f"/disasm?ctx={i}"}) - r["fmt"] = k.ret.src - for key in k.keys: ref_map[key] = i + for i,(k,v) in enumerate(zip(t.keys, t.rewrites)): + steps = [{"name":s.name, "loc":s.loc, "match_count":len(s.matches), "code_line":printable(s.loc), "trace":k.tb if j == 0 else None, + "query":f"/ctxs?ctx={i}&idx={j}", "depth":s.depth} for j,s in enumerate(v)] + if isinstance(k.ret, ProgramSpec): + steps.append({"name":"View UOp List", "query":f"/render?ctx={i}&fmt=uops", "depth":0}) + steps.append({"name":"View Program", "query":f"/render?ctx={i}&fmt=src", "depth":0}) + steps.append({"name":"View Disassembly", "query":f"/render?ctx={i}&fmt=asm", "depth":0}) + for key in k.keys: ref_map[key] = i + ret.append({"name":k.display_name, "steps":steps}) return ret -# ** Complete rewrite details for a graph_rewrite call +# ** get the complete UOp graphs for one rewrite class GraphRewriteDetails(TypedDict): graph: dict # JSON serialized UOp for this rewrite step @@ -55,6 +52,9 @@ class GraphRewriteDetails(TypedDict): def shape_to_str(s:tuple[sint, ...]): return "(" + ','.join(srender(x) for x in s) + ")" def mask_to_str(s:tuple[tuple[sint, sint], ...]): return "(" + ','.join(shape_to_str(x) for x in s) + ")" +def pystr(u:UOp, i:int) -> str: + try: return pyrender(u) + except Exception: return str(u) def uop_to_json(x:UOp) -> dict[int, dict]: assert isinstance(x, UOp) @@ -63,53 +63,60 @@ def uop_to_json(x:UOp) -> dict[int, dict]: for u in (toposort:=x.toposort()): # always exclude DEVICE/CONST/UNIQUE if u.op in {Ops.DEVICE, Ops.CONST, Ops.UNIQUE} and u is not x: excluded.add(u) - # only exclude CONST VIEW source if it has no other children in the graph - if u.op is Ops.CONST and len(u.src) != 0 and all(cr.op is Ops.CONST for c in u.src[0].children if (cr:=c()) is not None and cr in toposort): - excluded.update(u.src) + if u.op is Ops.VCONST and u.dtype.scalar() == dtypes.index and u is not x: excluded.add(u) for u in toposort: if u in excluded: continue argst = codecs.decode(str(u.arg), "unicode_escape") - if u.op is Ops.VIEW: - argst = ("\n".join([f"{shape_to_str(v.shape)} / {shape_to_str(v.strides)}"+("" if v.offset == 0 else f" / {srender(v.offset)}")+ - (f"\nMASK {mask_to_str(v.mask)}" if v.mask is not None else "") for v in unwrap(u.st).views])) - if u.op in GroupOp.Movement: argst = (mask_to_str if u.op in {Ops.SHRINK, Ops.PAD} else shape_to_str)(u.arg) + if u.op in GroupOp.Movement: argst = (mask_to_str if u.op in {Ops.SHRINK, Ops.PAD} else shape_to_str)(u.marg) + if u.op is Ops.KERNEL: + ast_str = f"SINK{tuple(s.op for s in u.arg.ast.src)}" if u.arg.ast.op is Ops.SINK else repr(u.arg.ast.op) + argst = f"" label = f"{str(u.op).split('.')[1]}{(chr(10)+word_wrap(argst.replace(':', ''))) if u.arg is not None else ''}" if u.dtype != dtypes.void: label += f"\n{u.dtype}" - for idx,x in enumerate(u.src): + for idx,x in enumerate(u.src[:1] if u.op in {Ops.BUFFERIZE, Ops.INDEX} else (u.src if u.op is not Ops.END else [])): if x in excluded: arg = f"{x.arg:g}" if x.op is Ops.CONST and dtypes.is_float(x.dtype) else f"{x.arg}" label += f"\n{x.op.name}{idx} {arg}" + (f" {x.src[0].op}" if len(x.src) else "") try: if len(rngs:=u.ranges): - label += f"\n({','.join([colored(range_str(x), axis_colors[x.arg[-1]]) for x in sorted(rngs, key=lambda x: x.arg[0:-1])])})" - if u.op not in {Ops.VIEW, Ops.BUFFER, Ops.KERNEL, Ops.ASSIGN, Ops.COPY, Ops.SINK, *GroupOp.Buffer} and u.st is not None: + label += f"\n({multirange_str(rngs, color=True)})" + if u._shape is not None: label += f"\n{shape_to_str(u.shape)}" if u.op in {Ops.INDEX, Ops.BUFFERIZE}: label += f"\n{u.render()}" + ranges: list[UOp] = [] + for us in u.src[1:]: ranges += [s for s in us.toposort() if s.op in {Ops.RANGE, Ops.SPECIAL}] + if ranges: label += "\n"+' '.join([f"{s.render()}={s.vmax+1}" for s in ranges]) + if u.op in {Ops.END, Ops.REDUCE} and len(trngs:=list(UOp.sink(*u.src[range_start[u.op]:]).ranges)): + label += "\n"+' '.join([f"{range_str(s, color=True)}({s.vmax+1})" for s in trngs]) except Exception: label += "\n" if (ref:=ref_map.get(u.arg.ast) if u.op is Ops.KERNEL else None) is not None: label += f"\ncodegen@{ctxs[ref]['name']}" # NOTE: kernel already has metadata in arg - if TRACEMETA >= 2 and u.metadata is not None and u.op is not Ops.KERNEL: label += "\n"+repr(u.metadata) + if TRACEMETA >= 2 and u.metadata is not None and u.op is not Ops.KERNEL: label += "\n"+str(u.metadata) graph[id(u)] = {"label":label, "src":[(i,id(x)) for i,x in enumerate(u.src) if x not in excluded], "color":uops_colors.get(u.op, "#ffffff"), "ref":ref, "tag":repr(u.tag) if u.tag is not None else None} return graph @functools.cache -def _reconstruct(a:int, i:int): - op, dtype, src, arg, *rest = traces[i][2][a] - arg = type(arg)(_reconstruct(arg.ast, i), arg.metadata) if op is Ops.KERNEL else arg - return UOp(op, dtype, tuple(_reconstruct(s, i) for s in src), arg, *rest) +def _reconstruct(a:int): + op, dtype, src, arg, *rest = trace.uop_fields[a] + arg = type(arg)(_reconstruct(arg.ast), arg.metadata) if op is Ops.KERNEL else arg + return UOp(op, dtype, tuple(_reconstruct(s) for s in src), arg, *rest) -def get_details(ctx:TrackedGraphRewrite, i:int=0) -> Generator[GraphRewriteDetails, None, None]: - yield {"graph":uop_to_json(next_sink:=_reconstruct(ctx.sink, i)), "uop":str(next_sink), "changed_nodes":None, "diff":None, "upat":None} +def get_full_rewrite(ctx:TrackedGraphRewrite, i:int=0) -> Generator[GraphRewriteDetails, None, None]: + next_sink = _reconstruct(ctx.sink) + # in the schedule graph we don't show indexing ops (unless it's in a kernel AST or rewriting dtypes.index sink) + yield {"graph":uop_to_json(next_sink), "uop":pystr(next_sink,i), "changed_nodes":None, "diff":None, "upat":None} replaces: dict[UOp, UOp] = {} - for u0_num,u1_num,upat_loc in tqdm(ctx.matches): - replaces[u0:=_reconstruct(u0_num, i)] = u1 = _reconstruct(u1_num, i) + for u0_num,u1_num,upat_loc,dur in tqdm(ctx.matches): + replaces[u0:=_reconstruct(u0_num)] = u1 = _reconstruct(u1_num) try: new_sink = next_sink.substitute(replaces) except RuntimeError as e: new_sink = UOp(Ops.NOOP, arg=str(e)) - yield {"graph":(sink_json:=uop_to_json(new_sink)), "uop":str(new_sink), "changed_nodes":[id(x) for x in u1.toposort() if id(x) in sink_json], - "diff":list(difflib.unified_diff(str(u0).splitlines(), str(u1).splitlines())), "upat":(upat_loc, printable(upat_loc))} + match_repr = f"# {dur*1e6:.2f} us\n"+printable(upat_loc) + yield {"graph":(sink_json:=uop_to_json(new_sink)), "uop":pystr(new_sink,i), + "changed_nodes":[id(x) for x in u1.toposort() if id(x) in sink_json], + "diff":list(difflib.unified_diff(pystr(u0,i).splitlines(),pystr(u1,i).splitlines())), "upat":(upat_loc, match_repr)} if not ctx.bottom_up: next_sink = new_sink # encoder helpers @@ -140,45 +147,106 @@ def flatten_events(profile:list[ProfileEvent]) -> Generator[tuple[Decimal, Decim # normalize event timestamps and attach kernel metadata def timeline_layout(dev_events:list[tuple[int, int, float, DevEvent]], start_ts:int, scache:dict[str, int]) -> bytes|None: events:list[bytes] = [] - exec_points:dict[str, dict] = {} + exec_points:dict[str, ProfilePointEvent] = {} for st,et,dur,e in dev_events: - if isinstance(e, ProfilePointEvent) and e.name == "exec": exec_points[e.key] = e.arg + if isinstance(e, ProfilePointEvent) and e.name == "exec": exec_points[e.arg["name"]] = e if dur == 0: continue - name, info = e.name, None + name, fmt, key = e.name, [], None if (ref:=ref_map.get(name)) is not None: name = ctxs[ref]["name"] - if isinstance(p:=traces[ref][0].ret, ProgramSpec) and (ei:=exec_points.get(p.name)) is not None: - info = f"{sym_infer(p.estimates.ops, ei['var_vals'])/(t:=dur*1e3):.2f} GFLOPS {sym_infer(p.estimates.mem, ei['var_vals'])/t:4.1f}"+ \ - f"|{sym_infer(p.estimates.lds,ei['var_vals'])/t:.1f} GB/s\n{ei['metadata']}" + if isinstance(p:=trace.keys[ref].ret, ProgramSpec) and (ei:=exec_points.get(p.name)) is not None: + flops = sym_infer(p.estimates.ops, var_vals:=ei.arg['var_vals'])/(t:=dur*1e-6) + membw, ldsbw = sym_infer(p.estimates.mem, var_vals)/t, sym_infer(p.estimates.lds, var_vals)/t + fmt = [f"{flops*1e-9:.0f} GFLOPS" if flops < 1e14 else f"{flops*1e-12:.0f} TFLOPS", + (f"{membw*1e-9:.0f} GB/s" if membw < 1e13 else f"{membw*1e-12:.0f} TB/s")+" mem", + (f"{ldsbw*1e-9:.0f} GB/s" if ldsbw < 1e15 else f"{ldsbw*1e-12:.0f} TB/s")+" lds"] + if (metadata_str:=",".join([str(m) for m in (ei.arg['metadata'] or ())])): fmt.append(metadata_str) + if isinstance(e, ProfileGraphEntry): fmt.append("(batched)") + key = ei.key elif isinstance(e.name, TracingKey): name = e.name.display_name ref = next((v for k in e.name.keys if (v:=ref_map.get(k)) is not None), None) - events.append(struct.pack(" bytes: + ei_encoding:list[tuple[int, int, int, int]] = [] # <[u32, u32, u8, u8] [run id, display name, buffer number and mode (2 = r/w, 1 = w, 0 = r)] + for e in execs: + num = next(i for i,k in enumerate(e.arg["bufs"]) if k == key) + mode = 2 if (num in e.arg["inputs"] and num in e.arg["outputs"]) else 1 if (num in e.arg["outputs"]) else 0 + ei_encoding.append((e.key, enum_str(e.arg["name"], scache), num, mode)) + return struct.pack(" bytes|None: peak, mem = 0, 0 temp:dict[int, int] = {} events:list[bytes] = [] + buf_ei:dict[int, list[ProfilePointEvent]] = {} + for st,_,_,e in dev_events: if not isinstance(e, ProfilePointEvent): continue if e.name == "alloc": - events.append(struct.pack(" peak: peak = mem + if e.name == "exec" and e.arg["bufs"]: + for b in e.arg["bufs"]: buf_ei.setdefault(b, []).append(e) if e.name == "free": - events.append(struct.pack(" None: + from tinygrad.runtime.ops_amd import ProfileSQTTEvent + if not (sqtt_events:=[e for e in profile if isinstance(e, ProfileSQTTEvent)]): return None + def err(name:str, msg:str|None=None) -> None: + step = {"name":name, "data":{"src":msg or traceback.format_exc()}, "depth":0, "query":f"/render?ctx={len(ctxs)}&step=0&fmt=counters"} + return ctxs.append({"name":"Counters", "steps":[step]}) + try: from extra.sqtt.roc import decode + except Exception: return err("DECODER IMPORT ISSUE") + try: rctx = decode(profile) + except Exception: return err("DECODER ERROR") + if not rctx.inst_execs: return err("EMPTY SQTT OUTPUT", f"{len(sqtt_events)} SQTT events recorded, none got decoded") + steps:list[dict] = [] + for name,waves in rctx.inst_execs.items(): + if (r:=ref_map.get(name)): name = ctxs[r]["name"] + steps.append({"name":name, "depth":0, "query":f"/render?ctx={len(ctxs)}&step={len(steps)}&fmt=counters", + "data":{"src":trace.keys[r].ret.src if r else name, "lang":"cpp"}}) + + # Idle: The total time gap between the completion of previous instruction and the beginning of the current instruction. + # The idle time can be caused by: + # * Arbiter loss + # * Source or destination register dependency + # * Instruction cache miss + # Stall: The total number of cycles the hardware pipe couldn't issue an instruction. + # Duration: Total latency in cycles, defined as "Stall time + Issue time" for gfx9 or "Stall time + Execute time" for gfx10+. + for w in waves: + rows, prev_instr = [], w.begin_time + for i,e in enumerate(w.insts): + rows.append((e.inst, e.time, max(0, e.time-prev_instr), e.dur, e.stall, str(e.typ).split("_")[-1])) + prev_instr = max(prev_instr, e.time + e.dur) + summary = [{"label":"Total Cycles", "value":w.end_time-w.begin_time}, {"label":"CU", "value":w.cu}, + {"label":"SIMD", "value":w.simd}] + steps.append({"name":f"Wave {w.wave_id}", "depth":1, "query":f"/render?ctx={len(ctxs)}&step={len(steps)}&fmt=counters", + "data":{"rows":rows, "cols":["Instruction", "Clk", "Idle", "Duration", "Stall", "Type"], "summary":summary}}) + ctxs.append({"name":"Counters", "steps":steps}) + def get_profile(profile:list[ProfileEvent]) -> bytes|None: # start by getting the time diffs for ev in profile: if isinstance(ev,ProfileDeviceEvent): device_ts_diffs[ev.device] = (ev.comp_tdiff, ev.copy_tdiff if ev.copy_tdiff is not None else ev.comp_tdiff) + # load device specific counters + device_decoders:dict[str, Callable[[list[ProfileEvent]], None]] = {} + for device in device_ts_diffs: + d = device.split(":")[0] + if d == "AMD": device_decoders[d] = load_sqtt + for fxn in device_decoders.values(): fxn(profile) # map events per device dev_events:dict[str, list[tuple[int, int, float, DevEvent]]] = {} markers:list[ProfilePointEvent] = [] @@ -199,7 +267,8 @@ def get_profile(profile:list[ProfileEvent]) -> bytes|None: v.sort(key=lambda e:e[0]) layout[k] = timeline_layout(v, start_ts, scache) layout[f"{k} Memory"] = mem_layout(v, start_ts, unwrap(end_ts), peaks, dtype_size, scache) - ret = [b"".join([struct.pack(" dict: # disassembly output can include headers / metadata, skip if llvm-mca can't parse those lines data = json.loads(subprocess.check_output(["llvm-mca","-skip-unsupported-instructions=parse-failure","--json","-"]+target_args, input=asm.encode())) cr = data["CodeRegions"][0] - resource_labels = data["TargetInfo"]["Resources"] + resource_labels = [repr(x)[1:-1] for x in data["TargetInfo"]["Resources"]] rows:list = [[instr] for instr in cr["Instructions"]] # add scheduler estimates for info in cr["InstructionInfoView"]["InstructionList"]: rows[info["Instruction"]].append(info["Latency"]) @@ -225,21 +294,32 @@ def get_llvm_mca(asm:str, mtriple:str, mcpu:str) -> dict: for i,usage in instr_usage.items(): rows[i].append([[k, v, (v/max_usage)*100] for k,v in usage.items()]) return {"rows":rows, "cols":["Opcode", "Latency", {"title":"HW Resources", "labels":resource_labels}], "summary":summary} -def get_disassembly(ctx:list[str]): - if not isinstance(prg:=traces[int(ctx[0])][0].ret, ProgramSpec): return - lib = (compiler:=Device[prg.device].compiler).compile(prg.src) - with redirect_stdout(buf:=io.StringIO()): compiler.disassemble(lib) - disasm_str = buf.getvalue() +def get_stdout(f: Callable) -> str: + buf = io.StringIO() + try: + with redirect_stdout(buf), redirect_stderr(buf): f() + except Exception: traceback.print_exc(file=buf) + return buf.getvalue() + +def get_render(i:int, j:int, fmt:str) -> dict|None: + if fmt == "counters": return ctxs[i]["steps"][j]["data"] + if not isinstance(prg:=trace.keys[i].ret, ProgramSpec): return None + if fmt == "uops": return {"src":get_stdout(lambda: print_uops(prg.uops or [])), "lang":"txt"} + if fmt == "src": return {"src":prg.src, "lang":"cpp"} + compiler = Device[prg.device].compiler + disasm_str = get_stdout(lambda: compiler.disassemble(compiler.compile(prg.src))) from tinygrad.runtime.support.compiler_cpu import llvm, LLVMCompiler if isinstance(compiler, LLVMCompiler): mtriple = ctypes.string_at(llvm.LLVMGetTargetMachineTriple(tm:=compiler.target_machine)).decode() mcpu = ctypes.string_at(llvm.LLVMGetTargetMachineCPU(tm)).decode() ret = get_llvm_mca(disasm_str, mtriple, mcpu) - else: ret = {"src":disasm_str} - return json.dumps(ret).encode() + else: ret = {"src":disasm_str, "lang":"x86asm"} + return ret # ** HTTP server +def get_int(query:dict[str, list[str]], k:str) -> int: return int(query.get(k,["0"])[0]) + class Handler(BaseHTTPRequestHandler): def do_GET(self): ret, status_code, content_type = b"", 200, "text/html" @@ -253,10 +333,12 @@ class Handler(BaseHTTPRequestHandler): if url.path.endswith(".css"): content_type = "text/css" except FileNotFoundError: status_code = 404 elif (query:=parse_qs(url.query)): - if url.path == "/disasm": ret, content_type = get_disassembly(**query), "application/json" + if url.path == "/render": + render_src = get_render(get_int(query, "ctx"), get_int(query, "step"), query["fmt"][0]) + ret, content_type = json.dumps(render_src).encode(), "application/json" else: - try: return self.stream_json(get_details(traces[i:=int(query["ctx"][0])][1][int(query["idx"][0])], i)) - except KeyError: status_code = 404 + try: return self.stream_json(get_full_rewrite(trace.rewrites[i:=get_int(query, "ctx")][get_int(query, "idx")], i)) + except (KeyError, IndexError): status_code = 404 elif url.path == "/ctxs": ret, content_type = json.dumps(ctxs).encode(), "application/json" elif url.path == "/get_profile" and profile_ret: ret, content_type = profile_ret, "application/octet-stream" else: status_code = 404 @@ -291,8 +373,9 @@ def reloader(): os.execv(sys.executable, [sys.executable] + sys.argv) time.sleep(0.1) -def load_pickle(path:pathlib.Path|None) -> list: - if path is None or not path.exists(): return [] +T = TypeVar("T") +def load_pickle(path:pathlib.Path, default:T) -> T: + if not path.exists(): return default with path.open("rb") as f: return pickle.load(f) # NOTE: using HTTPServer forces a potentially slow socket.getfqdn @@ -312,9 +395,8 @@ if __name__ == "__main__": st = time.perf_counter() print("*** viz is starting") - ctxs = get_metadata(load_pickle(args.kernels)) - - profile_ret = get_profile(load_pickle(args.profile)) + ctxs = get_rewrites(trace:=load_pickle(args.kernels, default=RewriteTrace([], [], {}))) + profile_ret = get_profile(load_pickle(args.profile, default=[])) server = TCPServerWithReuse(('', PORT), Handler) reloader_thread = threading.Thread(target=reloader)