draw: Add lower_opcodes NIR pass

Gallivm runs shaders that are originally compiled with another backend's
compiler options, which may have optimizations that introduce opcodes
that gallivm does not support. Add a pass to lower these.

Assisted-by: Claude Opus 4.6
Signed-off-by: Benjamin Cheng <benjamin.cheng@amd.com>
Reviewed-by: Georg Lehmann <dadschoorse@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41302>
This commit is contained in:
Benjamin Cheng 2026-04-30 12:59:11 -04:00 committed by Marge Bot
parent 364b5f806c
commit a4a862a605
4 changed files with 77 additions and 0 deletions

View file

@ -0,0 +1,17 @@
/**************************************************************************
*
* Copyright 2026 Advanced Micro Devices, Inc.
*
* SPDX-License-Identifier: MIT
*
**************************************************************************/
#ifndef DRAW_NIR_H
#define DRAW_NIR_H
#include "compiler/nir/nir.h"
bool
draw_nir_lower_opcodes(struct nir_shader *shader);
#endif

View file

@ -0,0 +1,48 @@
#
# Copyright 2026 Advanced Micro Devices, Inc.
#
# SPDX-License-Identifier: MIT
import argparse
import sys
a, b, c = 'a', 'b', 'c'
# This contains lowerings for opcodes that driver-specific optimizations
# may introduce but gallivm does not support.
lower = [
(('fmulz', a, b), ('bcsel', ('ior', ('feq', a, 0.0), ('feq', b, 0.0)), 0.0, ('fmul', a, b))),
(('ffmaz', a, b, c), ('bcsel', ('ior', ('feq', a, 0.0), ('feq', b, 0.0)), c, ('ffma_weak', a, b, c))),
# draw shaders are GLSL shaders, which means we can just use ffma_weak
(('ffma', a, b, c), ('ffma_weak', a, b, c)),
(('bitfield_select', a, b, c), ('ixor', c, ('iand', a, ('ixor', b, c)))),
(('ubfe', a, b, c), ('ubitfield_extract', a, ('iand', b, 0x1f), ('iand', c, 0x1f))),
(('ibfe', a, b, c), ('ibitfield_extract', a, ('iand', b, 0x1f), ('iand', c, 0x1f))),
(('bfm', a, b), ('ishl', ('isub', ('ishl', 1, ('iand', a, 0x1f)), 1), ('iand', b, 0x1f))),
# bfi(a, b, c) -> bitfield_select(a, ishl(b, find_lsb(a)), c)
(('bfi', a, b, c), ('ixor', c, ('iand', a, ('ixor', ('ishl', b, ('find_lsb', a)), c)))),
(('ufind_msb_rev', a), ('bcsel', ('ige', ('ufind_msb', a), 0), ('isub', 31, ('ufind_msb', a)), -1)),
(('ifind_msb_rev', a), ('bcsel', ('ige', ('ifind_msb', a), 0), ('isub', 31, ('ifind_msb', a)), -1)),
# uclz(a) -> umin(32, ufind_msb_rev(a))
(('uclz', a), ('umin', 32, ('bcsel', ('ige', ('ufind_msb', a), 0), ('isub', 31, ('ufind_msb', a)), -1))),
(('shfr', a, b, c),
('bcsel', ('ieq', ('iand', c, 0x1f), 0), b,
('ior', ('ishl', a, ('iadd', 32, ('ineg', ('iand', c, 0x1f)))),
('ushr', b, ('iand', c, 0x1f))))),
]
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--import-path', required=True)
args = parser.parse_args()
sys.path.insert(0, args.import_path)
import nir_algebraic
p = nir_algebraic.AlgebraicPass("draw_nir_lower_opcodes", lower)
print('#include "draw/draw_nir.h"')
print(p.render())

View file

@ -271,6 +271,17 @@ if with_gfx_compute
'util/u_simple_shaders.c',
'util/u_tests.c',
)
files_libgallium += custom_target(
'draw_nir_lower_opcodes.c',
input : 'draw/draw_nir_lower_opcodes.py',
output : 'draw_nir_lower_opcodes.c',
command : [
prog_python, '@INPUT@', '-p', dir_compiler_nir,
],
capture : true,
depend_files : nir_algebraic_depends,
)
endif
if dep_libdrm.found()

View file

@ -52,6 +52,7 @@
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "draw/draw_context.h"
#include "draw/draw_nir.h"
#include "util/u_dump.h"
#include "util/u_memory.h"