From bc3b6168bac39a16326c730a9d0ae97b45c7df23 Mon Sep 17 00:00:00 2001 From: Jonathan Marek Date: Wed, 8 May 2019 10:26:49 -0400 Subject: [PATCH] nir: replace lower_sincos with algebraic opt This version has less ops for the same precision. Signed-off-by: Jonathan Marek Reviewed-by: Vasily Khoruzhick Acked-by: Matt Turner --- src/compiler/Makefile.sources | 1 - src/compiler/nir/meson.build | 3 +- src/compiler/nir/nir.h | 3 +- src/compiler/nir/nir_lower_sincos.c | 138 ------------------------ src/compiler/nir/nir_opt_algebraic.py | 10 ++ src/gallium/drivers/lima/lima_program.c | 2 +- 6 files changed, 13 insertions(+), 144 deletions(-) delete mode 100644 src/compiler/nir/nir_lower_sincos.c diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index 552a7d64fea..b3a9a3cc031 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -273,7 +273,6 @@ NIR_FILES = \ nir/nir_lower_regs_to_ssa.c \ nir/nir_lower_returns.c \ nir/nir_lower_scratch.c \ - nir/nir_lower_sincos.c \ nir/nir_lower_subgroups.c \ nir/nir_lower_system_values.c \ nir/nir_lower_tex.c \ diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index 169c31aacd5..a54e899912f 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -152,7 +152,6 @@ files_libnir = files( 'nir_lower_returns.c', 'nir_lower_scratch.c', 'nir_lower_subgroups.c', - 'nir_lower_sincos.c', 'nir_lower_system_values.c', 'nir_lower_tex.c', 'nir_lower_to_source_mods.c', @@ -270,7 +269,7 @@ if with_tests include_directories : [inc_common], dependencies : [dep_thread, idep_gtest, idep_nir], link_with : libmesa_util, - ), + ), suite : ['compiler', 'nir'], ) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index e224f03ea99..31e731baa44 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -2505,6 +2505,7 @@ typedef struct nir_shader_compiler_options { bool lower_fpow; bool lower_fsat; bool lower_fsqrt; + bool lower_sincos; bool lower_fmod; /** Lowers ibitfield_extract/ubitfield_extract to ibfe/ubfe. */ bool lower_bitfield_extract; @@ -3976,8 +3977,6 @@ uint64_t nir_get_single_slot_attribs_mask(uint64_t attribs, uint64_t dual_slot); nir_intrinsic_op nir_intrinsic_from_system_value(gl_system_value val); gl_system_value nir_system_value_from_intrinsic(nir_intrinsic_op intrin); -bool nir_lower_sincos(nir_shader *shader); - static inline bool nir_variable_is_in_ubo(const nir_variable *var) { diff --git a/src/compiler/nir/nir_lower_sincos.c b/src/compiler/nir/nir_lower_sincos.c deleted file mode 100644 index 37aa97b1e96..00000000000 --- a/src/compiler/nir/nir_lower_sincos.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2014 Scott Mansell - * Copyright © 2014 Broadcom - * Copyright (c) 2019 Vasily Khoruzhick - * - * 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 (including the next - * paragraph) 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. - */ - -#include "util/u_math.h" -#include "nir.h" -#include "nir_builder.h" - -static nir_ssa_def * -shrink_input(nir_builder *b, nir_ssa_def *x) -{ - nir_ssa_def *scaled_x = nir_fmul_imm(b, x, 1.0 / (M_PI * 2)); - - nir_ssa_def *xfrac = nir_ffract(b, scaled_x); - /* Map [0.5, 1] to [-0.5, 0] */ - nir_ssa_def *xfrac_0_5_1 = nir_fadd_imm(b, xfrac, -1.0); - /* Map [-1, -0.5] to [0, 0.5] */ - nir_ssa_def *xfrac_n1_n0_5 = nir_fadd_imm(b, xfrac, 1.0); - - nir_ssa_def *geq_0_5 = nir_build_alu(b, nir_op_fge, xfrac, nir_imm_float(b, 0.5), NULL, NULL); - nir_ssa_def *less_m0_5 = nir_build_alu(b, nir_op_flt, xfrac, nir_imm_float(b, -0.5), NULL, NULL); - - nir_ssa_def *sel1 = nir_build_alu(b, nir_op_bcsel, geq_0_5, xfrac_0_5_1, xfrac, NULL ); - nir_ssa_def *sel2 = nir_build_alu(b, nir_op_bcsel, less_m0_5, xfrac_n1_n0_5, sel1, NULL); - - return sel2; -} - -static nir_ssa_def * -lower_sincos(nir_builder *b, nir_ssa_def *src, bool do_cos) -{ - /* Fast sin/cos implementation, see - * https://web.archive.org/web/20180105155939/http://forum.devmaster.net/t/fast-and-accurate-sine-cosine/9648 - */ - const float B = 8.0; //(M_PI * 2.0) * (4.0 / M_PI); - const float C = -16.0; //(M_PI * 2.0) * (M_PI * 2.0) * (-4.0 / (M_PI * M_PI)); - const float P = 0.225; - - if (do_cos) - src = nir_fadd_imm(b, src, M_PI / 2.0); - - nir_ssa_def *x = shrink_input(b, src); - - nir_ssa_def *bx = nir_fmul_imm(b, x, B); - nir_ssa_def *cx = nir_fmul_imm(b, x, C); - nir_ssa_def *absx = nir_fabs(b, x); - nir_ssa_def *cxabsx = nir_fmul(b, cx, absx); - - /* Y1 = B * x + C * x * fabs(x) */ - nir_ssa_def *y1 = nir_fadd(b, bx, cxabsx); - - /* Precision step: Y = P * (Y1 * fabs(Y1) - Y1) + Y1 */ - nir_ssa_def *y = nir_fabs(b, y1); - y = nir_fmul(b, y, y1); - y = nir_fsub(b, y, y1); - y = nir_fmul_imm(b, y, P); - y = nir_fadd(b, y, y1); - - return y; -} - -static bool -lower_sincos_impl(nir_function_impl *impl) -{ - bool progress = false; - - nir_builder b; - nir_builder_init(&b, impl); - - nir_foreach_block(block, impl) { - nir_foreach_instr_safe(instr, block) { - if (instr->type != nir_instr_type_alu) - continue; - - nir_alu_instr *alu_instr = nir_instr_as_alu(instr); - nir_ssa_def *lower; - - b.cursor = nir_before_instr(instr); - - switch (alu_instr->op) { - case nir_op_fsin: - lower = lower_sincos(&b, nir_ssa_for_alu_src(&b, alu_instr, 0), false); - break; - case nir_op_fcos: - lower = lower_sincos(&b, nir_ssa_for_alu_src(&b, alu_instr, 0), true); - break; - default: - continue; - } - - nir_ssa_def_rewrite_uses(&alu_instr->dest.dest.ssa, - nir_src_for_ssa(lower)); - nir_instr_remove(instr); - progress = true; - } - } - - if (progress) { - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - } - - return progress; -} - -bool -nir_lower_sincos(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(function, shader) { - if (function->impl) - progress |= lower_sincos_impl(function->impl); - } - - return progress; -} diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py index 00145fc80f5..951771fa37a 100644 --- a/src/compiler/nir/nir_opt_algebraic.py +++ b/src/compiler/nir/nir_opt_algebraic.py @@ -29,6 +29,7 @@ from collections import OrderedDict import nir_algebraic from nir_opcodes import type_sizes import itertools +from math import pi # Convenience variables a = 'a' @@ -74,6 +75,12 @@ e = 'e' # another condition, the two can be separated by a comma (e.g., # "(many-comm-expr,is_used_once)"). +# based on https://web.archive.org/web/20180105155939/http://forum.devmaster.net/t/fast-and-accurate-sine-cosine/9648 +def lowered_sincos(c): + x = ('fsub', ('fmul', 2.0, ('ffract', ('fadd', ('fmul', 0.5 / pi, a), c))), 1.0) + x = ('fmul', ('fsub', x, ('fmul', x, ('fabs', x))), 4.0) + return ('ffma', ('ffma', x, ('fabs', x), ('fneg', x)), 0.225, x) + optimizations = [ (('imul', a, '#b@32(is_pos_power_of_two)'), ('ishl', a, ('find_lsb', b)), '!options->lower_bitshift'), @@ -645,6 +652,9 @@ optimizations = [ (('~frcp', ('fsqrt', a)), ('frsq', a)), (('fsqrt', a), ('frcp', ('frsq', a)), 'options->lower_fsqrt'), (('~frcp', ('frsq', a)), ('fsqrt', a), '!options->lower_fsqrt'), + # Trig + (('fsin', a), lowered_sincos(0.5), 'options->lower_sincos'), + (('fcos', a), lowered_sincos(0.75), 'options->lower_sincos'), # Boolean simplifications (('i2b32(is_used_by_if)', a), ('ine32', a, 0)), (('i2b1(is_used_by_if)', a), ('ine', a, 0)), diff --git a/src/gallium/drivers/lima/lima_program.c b/src/gallium/drivers/lima/lima_program.c index cd056fb067d..61889d02ddf 100644 --- a/src/gallium/drivers/lima/lima_program.c +++ b/src/gallium/drivers/lima/lima_program.c @@ -53,6 +53,7 @@ static const nir_shader_compiler_options vs_nir_options = { .lower_fsat = true, .lower_bitshift = true, .lower_rotate = true, + .lower_sincos = true, }; static const nir_shader_compiler_options fs_nir_options = { @@ -98,7 +99,6 @@ lima_program_optimize_vs_nir(struct nir_shader *s) NIR_PASS_V(s, lima_nir_lower_uniform_to_scalar); NIR_PASS_V(s, nir_lower_io_to_scalar, nir_var_shader_in|nir_var_shader_out); - NIR_PASS_V(s, nir_lower_sincos); do { progress = false; -- 2.30.2