From 4df80cab40374effc40141b96bf9aa899ba554a1 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Mon, 1 Jul 2019 15:26:22 -0700 Subject: [PATCH] panfrost/midgard: Implement integer downsize ops Oh, dear. No turning back now. We begin implementing non-32-bit types, using downsizing integer type conversions as the initial instructions. We implement them naively as type-converting moves; substantially more efficient operation is possible by copypropping the type conversion modifier, but this optimization is not implemented here. Size converting modifiers on Midgard allow an instruction to write to a destination 1/2 the size, or to read from a source 1/2 the size. If we need an extreme conversion (32-bit to 8-bit, for instance), multiple type converting ops are chained together, which here is handled via an algebraic pass. Signed-off-by: Alyssa Rosenzweig --- .../panfrost/midgard/midgard_compile.c | 51 ++++++++++++++++++- .../panfrost/midgard/midgard_nir_algebraic.py | 14 ++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/gallium/drivers/panfrost/midgard/midgard_compile.c b/src/gallium/drivers/panfrost/midgard/midgard_compile.c index 2c304d9066e..109ed010d38 100644 --- a/src/gallium/drivers/panfrost/midgard/midgard_compile.c +++ b/src/gallium/drivers/panfrost/midgard/midgard_compile.c @@ -703,6 +703,29 @@ nir_is_fzero_constant(nir_src src) return true; } +/* Analyze the sizes of inputs/outputs to determine which reg mode to run an + * ALU instruction in. Right now, we just consider the size of the first + * argument. This will fail for upconverting, for instance (TODO) */ + +static midgard_reg_mode +reg_mode_for_nir(nir_alu_instr *instr) +{ + unsigned src_bitsize = nir_src_bit_size(instr->src[0].src); + + switch (src_bitsize) { + case 8: + return midgard_reg_mode_8; + case 16: + return midgard_reg_mode_16; + case 32: + return midgard_reg_mode_32; + case 64: + return midgard_reg_mode_64; + default: + unreachable("Invalid bit size"); + } +} + static void emit_alu(compiler_context *ctx, nir_alu_instr *instr) { @@ -728,6 +751,12 @@ emit_alu(compiler_context *ctx, nir_alu_instr *instr) unsigned broadcast_swizzle = 0; + /* Do we need a destination override? Used for inline + * type conversion */ + + midgard_dest_override dest_override = + midgard_dest_override_none; + switch (instr->op) { ALU_CASE(fadd, fadd); ALU_CASE(fmul, fmul); @@ -824,6 +853,20 @@ emit_alu(compiler_context *ctx, nir_alu_instr *instr) ALU_CASE(fneg, fmov); ALU_CASE(fsat, fmov); + /* For size conversion, we use a move. Ideally though we would squash + * these ops together; maybe that has to happen after in NIR as part of + * propagation...? An earlier algebraic pass ensured we step down by + * only / exactly one size */ + + case nir_op_u2u8: + case nir_op_u2u16: + case nir_op_i2i8: + case nir_op_i2i16: { + op = midgard_alu_op_imov; + dest_override = midgard_dest_override_lower; + break; + } + /* For greater-or-equal, we lower to less-or-equal and flip the * arguments */ @@ -958,8 +1001,8 @@ emit_alu(compiler_context *ctx, nir_alu_instr *instr) midgard_vector_alu alu = { .op = op, - .reg_mode = midgard_reg_mode_32, - .dest_override = midgard_dest_override_none, + .reg_mode = reg_mode_for_nir(instr), + .dest_override = dest_override, .outmod = outmod, /* Writemask only valid for non-SSA NIR */ @@ -2066,6 +2109,10 @@ mir_nontrivial_outmod(midgard_instruction *ins) bool is_int = midgard_is_integer_op(ins->alu.op); unsigned mod = ins->alu.outmod; + /* Type conversion is a sort of outmod */ + if (ins->alu.dest_override != midgard_dest_override_none) + return true; + if (is_int) return mod != midgard_outmod_int_wrap; else diff --git a/src/gallium/drivers/panfrost/midgard/midgard_nir_algebraic.py b/src/gallium/drivers/panfrost/midgard/midgard_nir_algebraic.py index df0caa26640..b05c193e507 100644 --- a/src/gallium/drivers/panfrost/midgard/midgard_nir_algebraic.py +++ b/src/gallium/drivers/panfrost/midgard/midgard_nir_algebraic.py @@ -44,6 +44,18 @@ algebraic_late = [ (('b32csel', a, 0, 'b@32'), ('iand', ('inot', a), b)), ] + +# Midgard is able to type convert down by only one "step" per instruction; if +# NIR wants more than one step, we need to break up into multiple instructions + +converts = [ + (('i2i8', 'a@32'), ('i2i8', ('i2i16', a))), + (('u2u8', 'a@32'), ('u2u8', ('u2u16', a))), + + (('i2i32', 'a@8'), ('i2i32', ('i2i16', a))), + (('u2u32', 'a@8'), ('u2u32', ('u2u16', a))) +] + # Midgard scales fsin/fcos arguments by pi. # Pass must be run only once, after the main loop @@ -66,7 +78,7 @@ def run(): print('#include "midgard_nir.h"') print(nir_algebraic.AlgebraicPass("midgard_nir_lower_algebraic_late", - algebraic_late).render()) + algebraic_late + converts).render()) print(nir_algebraic.AlgebraicPass("midgard_nir_scale_trig", scale_trig).render()) -- 2.30.2