diff options
author | Gert Wollny <[email protected]> | 2019-12-28 16:19:03 +0100 |
---|---|---|
committer | Marge Bot <[email protected]> | 2020-02-10 19:09:08 +0000 |
commit | 148f0ad4f9c4b4c291abcaa1722f5ae91f9c4014 (patch) | |
tree | d8c75183b1cd2a0d017188e1719eed527dc551f7 /src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp | |
parent | 90a7d2e08fbd94d443fe6aeed093e4c758b169da (diff) |
r600/sfn: Add support for atomic instructions
v2: fix compilation with gcc-6
Signed-off-by: Gert Wollny <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3225>
Diffstat (limited to 'src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp')
-rw-r--r-- | src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp b/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp new file mode 100644 index 00000000000..0b5bc5fa15d --- /dev/null +++ b/src/gallium/drivers/r600/sfn/sfn_emitssboinstruction.cpp @@ -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); +} + +} |