panfrost/midgard: Use a union to manipulate embedded constants
Each instruction bundle can contain up to 16 constant bytes. The meaning of those byte is instruction dependent: it depends on the instruction native type (int, uint or float) and the instruction reg_mode (8, 16, 32 or 64 bit). Those different layouts can be exposed as a union to facilitate constants manipulation. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3478>
This commit is contained in:

committed by
Marge Bot

parent
63461cb7e1
commit
15c92d158c
@@ -103,7 +103,7 @@ typedef struct midgard_instruction {
|
||||
int unit;
|
||||
|
||||
bool has_constants;
|
||||
uint32_t constants[4];
|
||||
midgard_constants constants;
|
||||
uint16_t inline_constant;
|
||||
bool has_blend_constant;
|
||||
bool has_inline_constant;
|
||||
@@ -217,7 +217,7 @@ typedef struct midgard_bundle {
|
||||
int padding;
|
||||
int control;
|
||||
bool has_embedded_constants;
|
||||
float constants[4];
|
||||
midgard_constants constants;
|
||||
bool has_blend_constant;
|
||||
bool last_writeout;
|
||||
} midgard_bundle;
|
||||
@@ -616,7 +616,7 @@ v_load_store_scratch(
|
||||
.no_spill = (1 << REG_CLASS_WORK)
|
||||
};
|
||||
|
||||
ins.constants[0] = byte;
|
||||
ins.constants.u32[0] = byte;
|
||||
|
||||
if (is_store) {
|
||||
ins.src[0] = srcdest;
|
||||
|
@@ -742,4 +742,23 @@ __attribute__((__packed__))
|
||||
}
|
||||
midgard_texture_word;
|
||||
|
||||
/* Up to 16 constant bytes can be embedded in a bundle. This union describes
|
||||
* all possible layouts.
|
||||
*/
|
||||
|
||||
typedef union midgard_constants {
|
||||
double f64[2];
|
||||
uint64_t u64[2];
|
||||
int64_t i64[2];
|
||||
float f32[4];
|
||||
uint32_t u32[4];
|
||||
int32_t i32[4];
|
||||
uint16_t f16[8];
|
||||
uint16_t u16[8];
|
||||
int16_t i16[8];
|
||||
uint8_t u8[16];
|
||||
int8_t i8[16];
|
||||
}
|
||||
midgard_constants;
|
||||
|
||||
#endif
|
||||
|
@@ -573,11 +573,33 @@ emit_load_const(compiler_context *ctx, nir_load_const_instr *instr)
|
||||
{
|
||||
nir_ssa_def def = instr->def;
|
||||
|
||||
float *v = rzalloc_array(NULL, float, 4);
|
||||
nir_const_value_to_array(v, instr->value, instr->def.num_components, f32);
|
||||
midgard_constants *consts = rzalloc(NULL, midgard_constants);
|
||||
|
||||
assert(instr->def.num_components * instr->def.bit_size <= sizeof(*consts) * 8);
|
||||
|
||||
#define RAW_CONST_COPY(bits) \
|
||||
nir_const_value_to_array(consts->u##bits, instr->value, \
|
||||
instr->def.num_components, u##bits)
|
||||
|
||||
switch (instr->def.bit_size) {
|
||||
case 64:
|
||||
RAW_CONST_COPY(64);
|
||||
break;
|
||||
case 32:
|
||||
RAW_CONST_COPY(32);
|
||||
break;
|
||||
case 16:
|
||||
RAW_CONST_COPY(16);
|
||||
break;
|
||||
case 8:
|
||||
RAW_CONST_COPY(8);
|
||||
break;
|
||||
default:
|
||||
unreachable("Invalid bit_size for load_const instruction\n");
|
||||
}
|
||||
|
||||
/* Shifted for SSA, +1 for off-by-one */
|
||||
_mesa_hash_table_u64_insert(ctx->ssa_constants, (def.index << 1) + 1, v);
|
||||
_mesa_hash_table_u64_insert(ctx->ssa_constants, (def.index << 1) + 1, consts);
|
||||
}
|
||||
|
||||
/* Normally constants are embedded implicitly, but for I/O and such we have to
|
||||
@@ -1045,13 +1067,10 @@ emit_alu(compiler_context *ctx, nir_alu_instr *instr)
|
||||
ins.src[1] = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
|
||||
ins.has_constants = true;
|
||||
|
||||
if (instr->op == nir_op_b2f32) {
|
||||
float f = 1.0f;
|
||||
memcpy(&ins.constants, &f, sizeof(float));
|
||||
} else {
|
||||
ins.constants[0] = 1;
|
||||
}
|
||||
|
||||
if (instr->op == nir_op_b2f32)
|
||||
ins.constants.f32[0] = 1.0f;
|
||||
else
|
||||
ins.constants.i32[0] = 1;
|
||||
|
||||
for (unsigned c = 0; c < 16; ++c)
|
||||
ins.swizzle[1][c] = 0;
|
||||
@@ -1060,7 +1079,7 @@ emit_alu(compiler_context *ctx, nir_alu_instr *instr)
|
||||
ins.has_inline_constant = false;
|
||||
ins.src[1] = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
|
||||
ins.has_constants = true;
|
||||
ins.constants[0] = 0;
|
||||
ins.constants.u32[0] = 0;
|
||||
|
||||
for (unsigned c = 0; c < 16; ++c)
|
||||
ins.swizzle[1][c] = 0;
|
||||
@@ -1136,7 +1155,7 @@ emit_ubo_read(
|
||||
/* TODO: half-floats */
|
||||
|
||||
midgard_instruction ins = m_ld_ubo_int4(dest, 0);
|
||||
ins.constants[0] = offset;
|
||||
ins.constants.u32[0] = offset;
|
||||
|
||||
if (instr->type == nir_instr_type_intrinsic)
|
||||
mir_set_intr_mask(instr, &ins, true);
|
||||
@@ -1346,7 +1365,7 @@ emit_fragment_store(compiler_context *ctx, unsigned src, unsigned rt)
|
||||
|
||||
/* Add dependencies */
|
||||
ins.src[0] = src;
|
||||
ins.constants[0] = rt * 0x100;
|
||||
ins.constants.u32[0] = rt * 0x100;
|
||||
|
||||
/* Emit the branch */
|
||||
midgard_instruction *br = emit_mir_instruction(ctx, ins);
|
||||
@@ -2159,16 +2178,16 @@ embedded_to_inline_constant(compiler_context *ctx, midgard_block *block)
|
||||
/* Scale constant appropriately, if we can legally */
|
||||
uint16_t scaled_constant = 0;
|
||||
|
||||
if (midgard_is_integer_op(op) || is_16) {
|
||||
unsigned int *iconstants = (unsigned int *) ins->constants;
|
||||
scaled_constant = (uint16_t) iconstants[component];
|
||||
if (is_16) {
|
||||
scaled_constant = ins->constants.u16[component];
|
||||
} else if (midgard_is_integer_op(op)) {
|
||||
scaled_constant = ins->constants.u32[component];
|
||||
|
||||
/* Constant overflow after resize */
|
||||
if (scaled_constant != iconstants[component])
|
||||
if (scaled_constant != ins->constants.u32[component])
|
||||
continue;
|
||||
} else {
|
||||
float *f = (float *) ins->constants;
|
||||
float original = f[component];
|
||||
float original = ins->constants.f32[component];
|
||||
scaled_constant = _mesa_float_to_half(original);
|
||||
|
||||
/* Check for loss of precision. If this is
|
||||
@@ -2194,8 +2213,8 @@ embedded_to_inline_constant(compiler_context *ctx, midgard_block *block)
|
||||
/* Make sure that the constant is not itself a vector
|
||||
* by checking if all accessed values are the same. */
|
||||
|
||||
uint32_t *cons = ins->constants;
|
||||
uint32_t value = cons[component];
|
||||
const midgard_constants *cons = &ins->constants;
|
||||
uint32_t value = is_16 ? cons->u16[component] : cons->u32[component];
|
||||
|
||||
bool is_vector = false;
|
||||
unsigned mask = effective_writemask(&ins->alu, ins->mask);
|
||||
@@ -2205,7 +2224,9 @@ embedded_to_inline_constant(compiler_context *ctx, midgard_block *block)
|
||||
if (!(mask & (1 << c)))
|
||||
continue;
|
||||
|
||||
uint32_t test = cons[ins->swizzle[1][c]];
|
||||
uint32_t test = is_16 ?
|
||||
cons->u16[ins->swizzle[1][c]] :
|
||||
cons->u32[ins->swizzle[1][c]];
|
||||
|
||||
if (test != value) {
|
||||
is_vector = true;
|
||||
@@ -2312,7 +2333,7 @@ emit_fragment_epilogue(compiler_context *ctx, unsigned rt)
|
||||
struct midgard_instruction ins = v_branch(false, false);
|
||||
ins.writeout = true;
|
||||
ins.branch.target_block = ctx->block_count - 1;
|
||||
ins.constants[0] = rt * 0x100;
|
||||
ins.constants.u32[0] = rt * 0x100;
|
||||
emit_mir_instruction(ctx, ins);
|
||||
|
||||
ctx->current_block->epilogue = true;
|
||||
|
@@ -369,12 +369,8 @@ emit_alu_bundle(compiler_context *ctx,
|
||||
|
||||
/* Tack on constants */
|
||||
|
||||
if (bundle->has_embedded_constants) {
|
||||
util_dynarray_append(emission, float, bundle->constants[0]);
|
||||
util_dynarray_append(emission, float, bundle->constants[1]);
|
||||
util_dynarray_append(emission, float, bundle->constants[2]);
|
||||
util_dynarray_append(emission, float, bundle->constants[3]);
|
||||
}
|
||||
if (bundle->has_embedded_constants)
|
||||
util_dynarray_append(emission, midgard_constants, bundle->constants);
|
||||
}
|
||||
|
||||
/* Shift applied to the immediate used as an offset. Probably this is papering
|
||||
@@ -425,7 +421,7 @@ emit_binary_bundle(compiler_context *ctx,
|
||||
mir_pack_swizzle_ldst(bundle->instructions[i]);
|
||||
|
||||
/* Apply a constant offset */
|
||||
unsigned offset = bundle->instructions[i]->constants[0];
|
||||
unsigned offset = bundle->instructions[i]->constants.u32[0];
|
||||
|
||||
if (offset) {
|
||||
unsigned shift = mir_ldst_imm_shift(bundle->instructions[i]->load_store.op);
|
||||
|
@@ -60,8 +60,8 @@ midgard_opt_promote_fmov(compiler_context *ctx, midgard_block *block)
|
||||
/* We found an imov with a constant. Check the constants */
|
||||
bool ok = true;
|
||||
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(ins->constants); ++i)
|
||||
ok &= mir_constant_float(ins->constants[i]);
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(ins->constants.u32); ++i)
|
||||
ok &= mir_constant_float(ins->constants.u32[i]);
|
||||
|
||||
if (!ok)
|
||||
continue;
|
||||
|
@@ -171,8 +171,8 @@ mir_print_instruction(midgard_instruction *ins)
|
||||
mir_print_swizzle(ins->swizzle[3]);
|
||||
|
||||
if (ins->has_constants) {
|
||||
uint32_t *uc = ins->constants;
|
||||
float *fc = (float *) uc;
|
||||
uint32_t *uc = ins->constants.u32;
|
||||
float *fc = ins->constants.f32;
|
||||
|
||||
if (midgard_is_integer_op(ins->alu.op))
|
||||
printf(" <0x%X, 0x%X, 0x%X, 0x%x>", uc[0], uc[1], uc[2], uc[3]);
|
||||
|
@@ -332,7 +332,7 @@ struct midgard_predicate {
|
||||
* mode, the constants array will be updated, and the instruction
|
||||
* will be adjusted to index into the constants array */
|
||||
|
||||
uint8_t *constants;
|
||||
midgard_constants *constants;
|
||||
unsigned constant_count;
|
||||
bool blend_constant;
|
||||
|
||||
@@ -378,8 +378,8 @@ mir_adjust_constants(midgard_instruction *ins,
|
||||
if (pred->constant_count)
|
||||
return false;
|
||||
|
||||
uint16_t *bundles = (uint16_t *) pred->constants;
|
||||
uint32_t *constants = (uint32_t *) ins->constants;
|
||||
uint16_t *bundles = pred->constants->u16;
|
||||
const uint16_t *constants = ins->constants.u16;
|
||||
|
||||
/* Copy them wholesale */
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
@@ -388,8 +388,8 @@ mir_adjust_constants(midgard_instruction *ins,
|
||||
pred->constant_count = 16;
|
||||
} else {
|
||||
/* Pack 32-bit constants */
|
||||
uint32_t *bundles = (uint32_t *) pred->constants;
|
||||
uint32_t *constants = (uint32_t *) ins->constants;
|
||||
uint32_t *bundles = pred->constants->u32;
|
||||
const uint32_t *constants = ins->constants.u32;
|
||||
unsigned r_constant = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
|
||||
unsigned mask = mir_from_bytemask(mir_bytemask_of_read_components(ins, r_constant), midgard_reg_mode_32);
|
||||
|
||||
@@ -864,7 +864,7 @@ mir_schedule_alu(
|
||||
.tag = TAG_ALU_4,
|
||||
.destructive = true,
|
||||
.exclude = ~0,
|
||||
.constants = (uint8_t *) bundle.constants
|
||||
.constants = &bundle.constants
|
||||
};
|
||||
|
||||
midgard_instruction *vmul = NULL;
|
||||
@@ -946,13 +946,13 @@ mir_schedule_alu(
|
||||
|
||||
/* If we have a render target reference, schedule a move for it */
|
||||
|
||||
if (branch && branch->writeout && (branch->constants[0] || ctx->is_blend)) {
|
||||
if (branch && branch->writeout && (branch->constants.u32[0] || ctx->is_blend)) {
|
||||
midgard_instruction mov = v_mov(~0, make_compiler_temp(ctx));
|
||||
sadd = mem_dup(&mov, sizeof(midgard_instruction));
|
||||
sadd->unit = UNIT_SADD;
|
||||
sadd->mask = 0x1;
|
||||
sadd->has_inline_constant = true;
|
||||
sadd->inline_constant = branch->constants[0];
|
||||
sadd->inline_constant = branch->constants.u32[0];
|
||||
branch->src[1] = mov.dest;
|
||||
/* TODO: Don't leak */
|
||||
}
|
||||
|
@@ -44,10 +44,10 @@ mir_is_promoteable_ubo(midgard_instruction *ins)
|
||||
|
||||
return (ins->type == TAG_LOAD_STORE_4) &&
|
||||
(OP_IS_UBO_READ(ins->load_store.op)) &&
|
||||
!(ins->constants[0] & 0xF) &&
|
||||
!(ins->constants.u32[0] & 0xF) &&
|
||||
!(ins->load_store.arg_1) &&
|
||||
(ins->load_store.arg_2 == 0x1E) &&
|
||||
((ins->constants[0] / 16) < 16);
|
||||
((ins->constants.u32[0] / 16) < 16);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
@@ -57,7 +57,7 @@ mir_promoteable_uniform_count(compiler_context *ctx)
|
||||
|
||||
mir_foreach_instr_global(ctx, ins) {
|
||||
if (mir_is_promoteable_ubo(ins))
|
||||
count = MAX2(count, ins->constants[0] / 16);
|
||||
count = MAX2(count, ins->constants.u32[0] / 16);
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -135,7 +135,7 @@ midgard_promote_uniforms(compiler_context *ctx)
|
||||
mir_foreach_instr_global_safe(ctx, ins) {
|
||||
if (!mir_is_promoteable_ubo(ins)) continue;
|
||||
|
||||
unsigned off = ins->constants[0];
|
||||
unsigned off = ins->constants.u32[0];
|
||||
unsigned address = off / 16;
|
||||
|
||||
/* Check if it's a promotable range */
|
||||
|
Reference in New Issue
Block a user