summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/freedreno/ir3/ir3.c
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2017-04-17 11:04:00 -0400
committerRob Clark <[email protected]>2017-05-04 13:48:06 -0400
commitedde00f5f1a1a6b3f9827af0475f6ff097705c1f (patch)
tree5be67722c705b872b2e0f2df33f4d748d754a518 /src/gallium/drivers/freedreno/ir3/ir3.c
parent4d841fbaae3eac04f33f6a52f3dd829cfb1913b5 (diff)
freedreno/ir3: SSBO/atomic support
TODO cwabbott pointed out a write-after-read hazzard, which effects both this and arrays. A write needs to depend on *all* reads since the last write, not just the last read. Signed-off-by: Rob Clark <[email protected]>
Diffstat (limited to 'src/gallium/drivers/freedreno/ir3/ir3.c')
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3.c74
1 files changed, 66 insertions, 8 deletions
diff --git a/src/gallium/drivers/freedreno/ir3/ir3.c b/src/gallium/drivers/freedreno/ir3/ir3.c
index ff2c342c357..d703f4e7f38 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3.c
@@ -475,6 +475,13 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr,
struct ir3_register *dst, *src1, *src2;
instr_cat6_t *cat6 = ptr;
+ cat6->type = instr->cat6.type;
+ cat6->opc = instr->opc;
+ cat6->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
+ cat6->sync = !!(instr->flags & IR3_INSTR_SY);
+ cat6->g = !!(instr->flags & IR3_INSTR_G);
+ cat6->opc_cat = 6;
+
/* the "dst" for a store instruction is (from the perspective
* of data flow in the shader, ie. register use/def, etc) in
* fact a register that is read by the instruction, rather
@@ -500,7 +507,65 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr,
* indicate to use the src_off encoding even if offset is zero
* (but then what to do about dst_off?)
*/
- if (instr->cat6.src_offset || (instr->opc == OPC_LDG)) {
+ if ((instr->opc == OPC_LDGB) || is_atomic(instr->opc)) {
+ struct ir3_register *src3 = instr->regs[3];
+ instr_cat6ldgb_t *ldgb = ptr;
+
+ /* maybe these two bits both determine the instruction encoding? */
+ cat6->src_off = false;
+
+ ldgb->d = 4 - 1; /* always .4d ? */
+ ldgb->typed = false; /* TODO true for images */
+ ldgb->type_size = instr->cat6.iim_val - 1;
+
+ ldgb->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+
+ /* first src is src_ssbo: */
+ iassert(src1->flags & IR3_REG_IMMED);
+ ldgb->src_ssbo = src1->uim_val;
+
+ /* then next two are src1/src2: */
+ ldgb->src1 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+ ldgb->src1_im = !!(src2->flags & IR3_REG_IMMED);
+ ldgb->src2 = reg(src3, info, instr->repeat, IR3_REG_IMMED);
+ ldgb->src2_im = !!(src3->flags & IR3_REG_IMMED);
+
+ if (is_atomic(instr->opc)) {
+ struct ir3_register *src4 = instr->regs[4];
+ ldgb->src3 = reg(src4, info, instr->repeat, 0);
+ ldgb->pad0 = 0x1;
+ ldgb->pad3 = 0x3;
+ } else {
+ ldgb->pad0 = 0x0;
+ ldgb->pad3 = 0x2;
+ }
+
+ return 0;
+ } else if (instr->opc == OPC_STGB) {
+ struct ir3_register *src3 = instr->regs[4];
+ instr_cat6stgb_t *stgb = ptr;
+
+ /* maybe these two bits both determine the instruction encoding? */
+ cat6->src_off = true;
+ stgb->pad3 = 0x2;
+
+ stgb->d = 4 - 1; /* always .4d ? */
+ stgb->typed = false;
+ stgb->type_size = instr->cat6.iim_val - 1;
+
+ /* first src is dst_ssbo: */
+ iassert(dst->flags & IR3_REG_IMMED);
+ stgb->dst_ssbo = dst->uim_val;
+
+ /* then src1/src2/src3: */
+ stgb->src1 = reg(src1, info, instr->repeat, 0);
+ stgb->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+ stgb->src2_im = !!(src2->flags & IR3_REG_IMMED);
+ stgb->src3 = reg(src3, info, instr->repeat, IR3_REG_IMMED);
+ stgb->src3_im = !!(src3->flags & IR3_REG_IMMED);
+
+ return 0;
+ } else if (instr->cat6.src_offset || (instr->opc == OPC_LDG)) {
instr_cat6a_t *cat6a = ptr;
cat6->src_off = true;
@@ -536,13 +601,6 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr,
cat6d->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
}
- cat6->type = instr->cat6.type;
- cat6->opc = instr->opc;
- cat6->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
- cat6->sync = !!(instr->flags & IR3_INSTR_SY);
- cat6->g = !!(instr->flags & IR3_INSTR_G);
- cat6->opc_cat = 6;
-
return 0;
}