r600/sfn: Add support for atomic instructions
authorGert Wollny <gert.wollny@collabora.com>
Sat, 28 Dec 2019 15:19:03 +0000 (16:19 +0100)
committerMarge Bot <eric+marge@anholt.net>
Mon, 10 Feb 2020 19:09:08 +0000 (19:09 +0000)
v2: fix compilation with gcc-6

Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3225>

src/gallium/drivers/r600/Makefile.sources
src/gallium/drivers/r600/meson.build
src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp [new file with mode: 0644]
src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.h [new file with mode: 0644]
src/gallium/drivers/r600/sfn/sfn_shader_base.cpp
src/gallium/drivers/r600/sfn/sfn_shader_base.h

index f5cf78110a4d2c157e3af5c703e9cd0b5730e5fc..a17997e6eaeb0e1b82dad213638462f4a700eb7f 100644 (file)
@@ -101,6 +101,8 @@ CXX_SOURCES = \
        sfn/sfn_emitaluinstruction.h \
        sfn/sfn_emitinstruction.cpp \
        sfn/sfn_emitinstruction.h \
+       sfn/sfn_emitssboinstruction.cpp \
+       sfn/sfn_emitssboinstruction.h \
        sfn/sfn_emittexinstruction.cpp \
        sfn/sfn_emittexinstruction.h \
        sfn/sfn_emitinstruction.h \
index 5080741c308ddb0170af46078b5c1fe654efe972..ecdf8504032e722f5caf74ffaa699a70d78c4689 100644 (file)
@@ -118,6 +118,8 @@ files_r600 = files(
   'sfn/sfn_emitaluinstruction.h',
   'sfn/sfn_emitinstruction.cpp',
   'sfn/sfn_emitinstruction.h',
+  'sfn/sfn_emitssboinstruction.cpp',
+  'sfn/sfn_emitssboinstruction.h',
   'sfn/sfn_emittexinstruction.cpp',
   'sfn/sfn_emittexinstruction.h',
   'sfn/sfn_emitinstruction.h',
diff --git a/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp b/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp
new file mode 100644 (file)
index 0000000..0b5bc5f
--- /dev/null
@@ -0,0 +1,177 @@
+#include "sfn_emitssboinstruction.h"
+
+#include "sfn_instruction_fetch.h"
+#include "sfn_instruction_gds.h"
+#include "sfn_instruction_misc.h"
+#include "../r600_pipe.h"
+
+namespace r600 {
+
+bool EmitSSBOInstruction::do_emit(nir_instr* instr)
+{
+   const nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
+   switch (intr->intrinsic) {
+   case nir_intrinsic_atomic_counter_add:
+   case nir_intrinsic_atomic_counter_and:
+   case nir_intrinsic_atomic_counter_exchange:
+   case nir_intrinsic_atomic_counter_max:
+   case nir_intrinsic_atomic_counter_min:
+   case nir_intrinsic_atomic_counter_or:
+   case nir_intrinsic_atomic_counter_xor:
+   case nir_intrinsic_atomic_counter_comp_swap:
+      return emit_atomic(intr);
+   case nir_intrinsic_atomic_counter_read:
+   case nir_intrinsic_atomic_counter_post_dec:
+      return emit_unary_atomic(intr);
+   case nir_intrinsic_atomic_counter_inc:
+      return emit_atomic_inc(intr);
+   case nir_intrinsic_atomic_counter_pre_dec:
+      return emit_atomic_pre_dec(intr);
+   default:
+      return false;
+   }
+}
+
+bool EmitSSBOInstruction::emit_atomic(const nir_intrinsic_instr* instr)
+{
+   ESDOp op = get_opcode(instr->intrinsic);
+
+   if (DS_OP_INVALID == op)
+      return false;
+
+   GPRVector dest = make_dest(instr);
+
+   int base = nir_intrinsic_base(instr);
+
+   PValue uav_id = from_nir(instr->src[0], 0);
+
+   PValue value = from_nir_with_fetch_constant(instr->src[1], 0);
+
+   GDSInstr *ir = nullptr;
+   if (instr->intrinsic == nir_intrinsic_atomic_counter_comp_swap)  {
+      PValue value2 = from_nir_with_fetch_constant(instr->src[1], 1);
+      ir = new GDSInstr(op, dest, value, value2, uav_id, base);
+   } else {
+      ir = new GDSInstr(op, dest, value, uav_id, base);
+   }
+
+   emit_instruction(ir);
+   return true;
+}
+
+bool EmitSSBOInstruction::emit_unary_atomic(const nir_intrinsic_instr* instr)
+{
+   ESDOp op = get_opcode(instr->intrinsic);
+
+   if (DS_OP_INVALID == op)
+      return false;
+
+   GPRVector dest = make_dest(instr);
+
+   PValue uav_id = from_nir(instr->src[0], 0);
+
+   auto ir = new GDSInstr(op, dest, uav_id, nir_intrinsic_base(instr));
+
+   emit_instruction(ir);
+   return true;
+}
+
+ESDOp EmitSSBOInstruction::get_opcode(const nir_intrinsic_op opcode)
+{
+   switch (opcode) {
+   case nir_intrinsic_atomic_counter_add:
+      return DS_OP_ADD_RET;
+   case nir_intrinsic_atomic_counter_and:
+      return DS_OP_AND_RET;
+   case nir_intrinsic_atomic_counter_exchange:
+      return DS_OP_XCHG_RET;
+   case nir_intrinsic_atomic_counter_inc:
+      return DS_OP_INC_RET;
+   case nir_intrinsic_atomic_counter_max:
+      return DS_OP_MAX_UINT_RET;
+   case nir_intrinsic_atomic_counter_min:
+      return DS_OP_MIN_UINT_RET;
+   case nir_intrinsic_atomic_counter_or:
+      return DS_OP_OR_RET;
+   case nir_intrinsic_atomic_counter_read:
+      return DS_OP_READ_RET;
+   case nir_intrinsic_atomic_counter_xor:
+      return DS_OP_XOR_RET;
+   case nir_intrinsic_atomic_counter_post_dec:
+      return DS_OP_DEC_RET;
+   case nir_intrinsic_atomic_counter_comp_swap:
+      return DS_OP_CMP_XCHG_RET;
+   case nir_intrinsic_atomic_counter_pre_dec:
+   default:
+      return DS_OP_INVALID;
+   }
+}
+
+
+bool EmitSSBOInstruction::emit_atomic_add(const nir_intrinsic_instr* instr)
+{
+   GPRVector dest = make_dest(instr);
+
+   PValue value = from_nir_with_fetch_constant(instr->src[1], 0);
+
+   PValue uav_id = from_nir(instr->src[0], 0);
+
+   auto ir = new GDSInstr(DS_OP_ADD_RET, dest, value, uav_id,
+                          nir_intrinsic_base(instr));
+
+   emit_instruction(ir);
+   return true;
+}
+
+bool EmitSSBOInstruction::emit_atomic_inc(const nir_intrinsic_instr* instr)
+{
+   GPRVector dest = make_dest(instr);
+
+   PValue uav_id = from_nir(instr->src[0], 0);
+
+
+   if (!m_atomic_limit) {
+      int one_tmp = allocate_temp_register();
+      m_atomic_limit = PValue(new GPRValue(one_tmp, 0));
+      emit_instruction(new AluInstruction(op1_mov, m_atomic_limit,
+                       PValue(new LiteralValue(0xffffffff)),
+                       {alu_write, alu_last_instr}));
+   }
+
+   auto ir = new GDSInstr(DS_OP_INC_RET, dest, m_atomic_limit, uav_id,
+                          nir_intrinsic_base(instr));
+   emit_instruction(ir);
+   return true;
+}
+
+bool EmitSSBOInstruction::emit_atomic_pre_dec(const nir_intrinsic_instr *instr)
+{
+   GPRVector dest = make_dest(instr);
+
+   PValue uav_id = from_nir(instr->src[0], 0);
+
+   int one_tmp = allocate_temp_register();
+   PValue value(new GPRValue(one_tmp, 0));
+   emit_instruction(new AluInstruction(op1_mov, value,  Value::one_i,
+                    {alu_write, alu_last_instr}));
+
+   auto ir = new GDSInstr(DS_OP_SUB_RET, dest, value, uav_id,
+                          nir_intrinsic_base(instr));
+   emit_instruction(ir);
+
+   ir = new GDSInstr(DS_OP_READ_RET, dest, uav_id, nir_intrinsic_base(instr));
+   emit_instruction(ir);
+
+   return true;
+}
+
+GPRVector EmitSSBOInstruction::make_dest(const nir_intrinsic_instr* ir)
+{
+   GPRVector::Values v;
+   int i;
+   for (i = 0; i < 4; ++i)
+      v[i] = from_nir(ir->dest, i);
+   return GPRVector(v);
+}
+
+}
diff --git a/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.h b/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.h
new file mode 100644 (file)
index 0000000..300f2ec
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef SFN_EMITSSBOINSTRUCTION_H
+#define SFN_EMITSSBOINSTRUCTION_H
+
+#include "sfn_emitinstruction.h"
+
+namespace r600 {
+
+class EmitSSBOInstruction: public EmitInstruction {
+public:
+   using EmitInstruction::EmitInstruction;
+private:
+   bool do_emit(nir_instr *instr);
+
+   bool emit_atomic(const nir_intrinsic_instr* instr);
+   bool emit_unary_atomic(const nir_intrinsic_instr* instr);
+   bool emit_atomic_add(const nir_intrinsic_instr* instr);
+   bool emit_atomic_inc(const nir_intrinsic_instr* instr);
+   bool emit_atomic_pre_dec(const nir_intrinsic_instr* instr);
+
+   ESDOp get_opcode(nir_intrinsic_op opcode);
+
+   GPRVector make_dest(const nir_intrinsic_instr* instr);
+
+   PValue m_atomic_limit;
+};
+
+}
+
+#endif // SFN_EMITSSBOINSTRUCTION_H
index 0ee6bbd631385192cfb10dcedeef586f3b63f539..7ea7bc69893d5dd8e459a9d944f1ac2902c81bc3 100644 (file)
@@ -62,6 +62,7 @@ ShaderFromNirProcessor::ShaderFromNirProcessor(pipe_shader_type ptype,
    m_sh_info(sh_info),
    m_tex_instr(*this),
    m_alu_instr(*this),
+   m_ssbo_instr(*this),
    m_pending_else(nullptr),
    m_scratch_size(scratch_size),
    m_next_hwatomic_loc(0),
@@ -449,6 +450,21 @@ bool ShaderFromNirProcessor::emit_intrinsic_instruction(nir_intrinsic_instr* ins
       return emit_discard_if(instr);
    case nir_intrinsic_load_ubo_r600:
       return emit_load_ubo(instr);
+   case nir_intrinsic_atomic_counter_add:
+   case nir_intrinsic_atomic_counter_and:
+   case nir_intrinsic_atomic_counter_exchange:
+   case nir_intrinsic_atomic_counter_max:
+   case nir_intrinsic_atomic_counter_min:
+   case nir_intrinsic_atomic_counter_or:
+   case nir_intrinsic_atomic_counter_xor:
+   case nir_intrinsic_atomic_counter_comp_swap:
+   case nir_intrinsic_atomic_counter_read:
+   case nir_intrinsic_atomic_counter_post_dec:
+   case nir_intrinsic_atomic_counter_inc:
+   case nir_intrinsic_atomic_counter_pre_dec:
+      m_sel.info.writes_memory = true;
+      return m_ssbo_instr.emit(&instr->instr);
+      break;
    case nir_intrinsic_copy_deref:
    case nir_intrinsic_load_constant:
    case nir_intrinsic_load_input:
index 3cd9b971e4a4656e0ee3527ad0756448a4d47f91..5b027329093a6f6e2eebefab14cf71413e0ddd93 100644 (file)
@@ -40,6 +40,7 @@
 #include "sfn_instruction_cf.h"
 #include "sfn_emittexinstruction.h"
 #include "sfn_emitaluinstruction.h"
+#include "sfn_emitssboinstruction.h"
 
 #include <vector>
 #include <set>
@@ -174,6 +175,7 @@ private:
 
    EmitTexInstruction m_tex_instr;
    EmitAluInstruction m_alu_instr;
+   EmitSSBOInstruction m_ssbo_instr;
    OutputRegisterMap m_output_register_map;
 
    IfElseInstruction *m_pending_else;