out.push_back(encoding);
break;
}
+ case Format::LDSDIR: {
+ LDSDIR_instruction& dir = instr->ldsdir();
+ uint32_t encoding = (0b11001110 << 24);
+ encoding |= opcode << 20;
+ encoding |= (uint32_t)dir.wait_vdst << 16;
+ encoding |= (uint32_t)dir.attr << 10;
+ encoding |= (uint32_t)dir.attr_chan << 8;
+ encoding |= reg(ctx, instr->definitions[0], 8);
+ out.push_back(encoding);
+ break;
+ }
case Format::MUBUF: {
MUBUF_instruction& mubuf = instr->mubuf();
uint32_t encoding = (0b111000 << 26);
("sopc", [Format.SOPC], 'SOPC_instruction', [(1, 2)]),
("smem", [Format.SMEM], 'SMEM_instruction', [(0, 4), (0, 3), (1, 0), (1, 3), (1, 2), (0, 0)]),
("ds", [Format.DS], 'DS_instruction', [(1, 1), (1, 2), (0, 3), (0, 4)]),
+ ("ldsdir", [Format.LDSDIR], 'LDSDIR_instruction', [(1, 1)]),
("mubuf", [Format.MUBUF], 'MUBUF_instruction', [(0, 4), (1, 3)]),
("mtbuf", [Format.MTBUF], 'MTBUF_instruction', [(0, 4), (1, 3)]),
("mimg", [Format.MIMG], 'MIMG_instruction', itertools.product([0, 1], [3, 4, 5, 6, 7])),
event_gds_gpr_lock = 1 << 9,
event_vmem_gpr_lock = 1 << 10,
event_sendmsg = 1 << 11,
- num_events = 12,
+ event_ldsdir = 1 << 12,
+ num_events = 13,
};
enum counter_type : uint8_t {
};
static const uint16_t exp_events =
- event_exp_pos | event_exp_param | event_exp_mrt_null | event_gds_gpr_lock | event_vmem_gpr_lock;
+ event_exp_pos | event_exp_param | event_exp_mrt_null | event_gds_gpr_lock | event_vmem_gpr_lock |
+ event_ldsdir;
static const uint16_t lgkm_events = event_smem | event_lds | event_gds | event_flat | event_sendmsg;
static const uint16_t vm_events = event_vmem | event_flat;
static const uint16_t vs_events = event_vmem_store;
case event_exp_param:
case event_exp_mrt_null:
case event_gds_gpr_lock:
- case event_vmem_gpr_lock: return counter_exp;
+ case event_vmem_gpr_lock:
+ case event_ldsdir: return counter_exp;
default: return 0;
}
}
if (counter == counter_exp) {
imm.exp = wait_imm::unset_counter;
- events &= ~(event_exp_pos | event_exp_param | event_exp_mrt_null | event_gds_gpr_lock |
- event_vmem_gpr_lock);
+ events &= ~exp_events;
}
if (counter == counter_vs) {
}
break;
}
+ case Format::LDSDIR: {
+ LDSDIR_instruction& ldsdir = instr->ldsdir();
+ update_counters(ctx, event_ldsdir, ldsdir.sync);
+ insert_wait_entry(ctx, instr->definitions[0], event_ldsdir);
+ break;
+ }
case Format::MUBUF:
case Format::MTBUF:
case Format::MIMG:
case Format::GLOBAL:
case Format::SCRATCH: return instr->flatlike().sync;
case Format::DS: return instr->ds().sync;
+ case Format::LDSDIR: return instr->ldsdir().sync;
default: return memory_sync_info();
}
}
SMEM = 6,
/* LDS/GDS Format */
DS = 8,
+ LDSDIR = 9,
/* Vector Memory Buffer Formats */
- MTBUF = 9,
- MUBUF = 10,
+ MTBUF = 10,
+ MUBUF = 11,
/* Vector Memory Image Format */
- MIMG = 11,
+ MIMG = 12,
/* Export Format */
- EXP = 12,
+ EXP = 13,
/* Flat Formats */
- FLAT = 13,
- GLOBAL = 14,
- SCRATCH = 15,
+ FLAT = 14,
+ GLOBAL = 15,
+ SCRATCH = 16,
- PSEUDO_BRANCH = 16,
- PSEUDO_BARRIER = 17,
- PSEUDO_REDUCTION = 18,
+ PSEUDO_BRANCH = 17,
+ PSEUDO_BARRIER = 18,
+ PSEUDO_REDUCTION = 19,
/* Vector ALU Formats */
- VOP3P = 19,
+ VOP3P = 20,
VOP1 = 1 << 8,
VOP2 = 1 << 9,
VOPC = 1 << 10,
struct SOPC_instruction;
struct SMEM_instruction;
struct DS_instruction;
+struct LDSDIR_instruction;
struct MTBUF_instruction;
struct MUBUF_instruction;
struct MIMG_instruction;
return *(DS_instruction*)this;
}
constexpr bool isDS() const noexcept { return format == Format::DS; }
+ LDSDIR_instruction& ldsdir() noexcept
+ {
+ assert(isLDSDIR());
+ return *(LDSDIR_instruction*)this;
+ }
+ const LDSDIR_instruction& ldsdir() const noexcept
+ {
+ assert(isLDSDIR());
+ return *(LDSDIR_instruction*)this;
+ }
+ constexpr bool isLDSDIR() const noexcept { return format == Format::LDSDIR; }
MTBUF_instruction& mtbuf() noexcept
{
assert(isMTBUF());
static_assert(sizeof(DS_instruction) == sizeof(Instruction) + 8, "Unexpected padding");
/**
+ * LDS Direct instructions
+ * Operand(0): M0
+ * Definition(0): VDST - Destination VGPR
+ */
+struct LDSDIR_instruction : public Instruction {
+ memory_sync_info sync;
+ uint8_t attr : 6;
+ uint8_t attr_chan : 2;
+ uint32_t wait_vdst : 4;
+ uint32_t padding : 28;
+};
+static_assert(sizeof(LDSDIR_instruction) == sizeof(Instruction) + 8, "Unexpected padding");
+
+/**
* Vector Memory Untyped-buffer Instructions
* Operand(0): SRSRC - Specifies which SGPR supplies T# (resource constant)
* Operand(1): VADDR - Address source. Can carry an index and/or offset
}
}
} else if (inst->isVMEM() || inst->isFlatLike() || inst->isDS() ||
- inst->isEXP()) {
+ inst->isEXP() || inst->isLDSDIR()) {
// TODO: GFX6-9 can use vskip
can_remove = false;
} else if (inst->isSMEM()) {
SOPC = 5
SMEM = 6
DS = 8
- MTBUF = 9
- MUBUF = 10
- MIMG = 11
- EXP = 12
- FLAT = 13
- GLOBAL = 14
- SCRATCH = 15
- PSEUDO_BRANCH = 16
- PSEUDO_BARRIER = 17
- PSEUDO_REDUCTION = 18
- VOP3P = 19
+ LDSDIR = 9
+ MTBUF = 10
+ MUBUF = 11
+ MIMG = 12
+ EXP = 13
+ FLAT = 14
+ GLOBAL = 15
+ SCRATCH = 16
+ PSEUDO_BRANCH = 17
+ PSEUDO_BARRIER = 18
+ PSEUDO_REDUCTION = 19
+ VOP3P = 20
VOP1 = 1 << 8
VOP2 = 1 << 9
VOPC = 1 << 10
return [('uint16_t', 'offset0', '0'),
('uint8_t', 'offset1', '0'),
('bool', 'gds', 'false')]
+ elif self == Format.LDSDIR:
+ return [('uint8_t', 'attr', 0),
+ ('uint8_t', 'attr_chan', 0),
+ ('memory_sync_info', 'sync', 'memory_sync_info()'),
+ ('uint8_t', 'wait_vdst', 0)]
elif self == Format.MTBUF:
return [('unsigned', 'dfmt', None),
('unsigned', 'nfmt', None),
for (gfx6, gfx7, gfx8, gfx9, gfx10, gfx11, name) in DS:
opcode(name, gfx7, gfx9, gfx10, gfx11, Format.DS, InstrClass.DS)
+
+# LDSDIR instructions:
+LDSDIR = {
+ (0x00, "lds_param_load"),
+ (0x01, "lds_direct_load"),
+}
+for (code, name) in LDSDIR:
+ opcode(name, -1, -1, -1, code, Format.LDSDIR, InstrClass.DS)
+
# MUBUF instructions:
MUBUF = {
(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, "buffer_load_format_x"),
return aD.sync == bD.sync && aD.pass_flags == bD.pass_flags && aD.gds == bD.gds &&
aD.offset0 == bD.offset0 && aD.offset1 == bD.offset1;
}
+ case Format::LDSDIR: {
+ LDSDIR_instruction& aD = a->ldsdir();
+ LDSDIR_instruction& bD = b->ldsdir();
+ return aD.sync == bD.sync && aD.attr == bD.attr && aD.attr_chan == bD.attr_chan &&
+ aD.wait_vdst == bD.wait_vdst;
+ }
case Format::MTBUF: {
MTBUF_instruction& aM = a->mtbuf();
MTBUF_instruction& bM = b->mtbuf();
print_sync(ds.sync, output);
break;
}
+ case Format::LDSDIR: {
+ const LDSDIR_instruction& ldsdir = instr->ldsdir();
+ if (instr->opcode == aco_opcode::lds_param_load)
+ fprintf(output, " attr%u.%c", ldsdir.attr, "xyzw"[ldsdir.attr_chan]);
+ if (ldsdir.wait_vdst != 15)
+ fprintf(output, " wait_vdst:%u", ldsdir.wait_vdst);
+ print_sync(ldsdir.sync, output);
+ break;
+ }
case Format::MUBUF: {
const MUBUF_instruction& mubuf = instr->mubuf();
if (mubuf.offset)
"FLAT/GLOBAL/SCRATCH data must be vgpr", instr.get());
break;
}
+ case Format::LDSDIR: {
+ check(instr->definitions.size() == 1 && instr->definitions[0].regClass() == v1, "LDSDIR must have an v1 definition", instr.get());
+ check(instr->operands.size() == 1, "LDSDIR must have an operand", instr.get());
+ if (!instr->operands.empty()) {
+ check(instr->operands[0].regClass() == s1, "LDSDIR must have an s1 operand", instr.get());
+ check(instr->operands[0].isFixed() && instr->operands[0].physReg() == m0, "LDSDIR must have an operand fixed to m0", instr.get());
+ }
+ break;
+ }
default: break;
}
}