unsigned position, psize;
uint64_t need_sync;
-
- /* current exec CF instruction */
- struct ir2_cf *cf;
};
static int
ctx->prog = prog;
ctx->so = so;
- ctx->cf = NULL;
ctx->pred_depth = 0;
ret = tgsi_parse_init(&ctx->parser, so->tokens);
tgsi_parse_free(&ctx->parser);
}
-static struct ir2_cf *
-next_exec_cf(struct fd2_compile_context *ctx)
-{
- struct ir2_cf *cf = ctx->cf;
- if (!cf || cf->exec.instrs_count >= ARRAY_SIZE(ctx->cf->exec.instrs))
- ctx->cf = cf = ir2_cf_create(ctx->so->ir, EXEC);
- return cf;
-}
-
static void
compile_vtx_fetch(struct fd2_compile_context *ctx)
{
int i;
for (i = 0; i < ctx->num_regs[TGSI_FILE_INPUT]; i++) {
struct ir2_instruction *instr = ir2_instr_create(
- next_exec_cf(ctx), IR2_FETCH);
+ ctx->so->ir, IR2_FETCH);
instr->fetch.opc = VTX_FETCH;
ctx->need_sync |= 1 << (i+1);
- ir2_reg_create(instr, i+1, "xyzw", 0);
- ir2_reg_create(instr, 0, "x", 0);
+ ir2_dst_create(instr, i+1, "xyzw", 0);
+ ir2_reg_create(instr, 0, "x", IR2_REG_INPUT);
if (i == 0)
instr->sync = true;
vfetch_instrs[i] = instr;
}
ctx->so->num_vfetch_instrs = i;
- ctx->cf = NULL;
}
/*
return num;
}
-static struct ir2_register *
+static struct ir2_dst_register *
add_dst_reg(struct fd2_compile_context *ctx, struct ir2_instruction *alu,
const struct tgsi_dst_register *dst)
{
swiz[3] = (dst->WriteMask & TGSI_WRITEMASK_W) ? 'w' : '_';
swiz[4] = '\0';
- return ir2_reg_create(alu, num, swiz, flags);
+ return ir2_dst_create(alu, num, swiz, flags);
}
-static struct ir2_register *
+static struct ir2_src_register *
add_src_reg(struct fd2_compile_context *ctx, struct ir2_instruction *alu,
const struct tgsi_src_register *src)
{
if (ctx->type == PIPE_SHADER_VERTEX) {
num = src->Index + 1;
} else {
+ flags |= IR2_REG_INPUT;
num = export_linkage(ctx,
ctx->input_export_idx[src->Index]);
}
add_vector_clamp(struct tgsi_full_instruction *inst, struct ir2_instruction *alu)
{
if (inst->Instruction.Saturate) {
- alu->alu.vector_clamp = true;
+ alu->alu_vector.clamp = true;
}
}
add_scalar_clamp(struct tgsi_full_instruction *inst, struct ir2_instruction *alu)
{
if (inst->Instruction.Saturate) {
- alu->alu.scalar_clamp = true;
+ alu->alu_scalar.clamp = true;
}
}
assert(inst->Instruction.NumDstRegs == 1);
add_dst_reg(ctx, alu, &inst->Dst[0].Register);
- /* maybe should re-arrange the syntax some day, but
- * in assembler/disassembler and what ir.c expects
- * is: MULADDv Rdst = Rsrc2 + Rsrc0 * Rscr1
- */
- add_src_reg(ctx, alu, &inst->Src[2].Register);
add_src_reg(ctx, alu, &inst->Src[0].Register);
add_src_reg(ctx, alu, &inst->Src[1].Register);
+ add_src_reg(ctx, alu, &inst->Src[2].Register);
add_vector_clamp(inst, alu);
}
-static void
-add_regs_dummy_vector(struct ir2_instruction *alu)
-{
- /* create dummy, non-written vector dst/src regs
- * for unused vector instr slot:
- */
- ir2_reg_create(alu, 0, "____", 0); /* vector dst */
- ir2_reg_create(alu, 0, NULL, 0); /* vector src1 */
- ir2_reg_create(alu, 0, NULL, 0); /* vector src2 */
-}
-
static void
add_regs_scalar_1(struct fd2_compile_context *ctx,
struct tgsi_full_instruction *inst, struct ir2_instruction *alu)
assert(inst->Instruction.NumSrcRegs == 1);
assert(inst->Instruction.NumDstRegs == 1);
- add_regs_dummy_vector(alu);
-
add_dst_reg(ctx, alu, &inst->Dst[0].Register);
add_src_reg(ctx, alu, &inst->Src[0].Register);
add_scalar_clamp(inst, alu);
struct ir2_instruction *alu;
struct tgsi_dst_register pred_dst;
- /* NOTE blob compiler seems to always puts PRED_* instrs in a CF by
- * themselves:
- */
- ctx->cf = NULL;
-
if (ctx->pred_depth == 0) {
/* assign predicate register: */
ctx->pred_reg = ctx->num_regs[TGSI_FILE_TEMPORARY];
get_predicate(ctx, &pred_dst, NULL);
- alu = ir2_instr_create_alu(next_exec_cf(ctx), ~0, PRED_SETNEs);
- add_regs_dummy_vector(alu);
+ alu = ir2_instr_create_alu_s(ctx->so->ir, PRED_SETNEs);
add_dst_reg(ctx, alu, &pred_dst);
add_src_reg(ctx, alu, src);
} else {
get_predicate(ctx, &pred_dst, &pred_src);
- alu = ir2_instr_create_alu(next_exec_cf(ctx), MULv, ~0);
+ alu = ir2_instr_create_alu_v(ctx->so->ir, MULv);
add_dst_reg(ctx, alu, &pred_dst);
add_src_reg(ctx, alu, &pred_src);
add_src_reg(ctx, alu, src);
/* save previous pred state to restore in pop_predicate(): */
ctx->pred_stack[ctx->pred_depth++] = ctx->so->ir->pred;
-
- ctx->cf = NULL;
}
static void
pop_predicate(struct fd2_compile_context *ctx)
{
- /* NOTE blob compiler seems to always puts PRED_* instrs in a CF by
- * themselves:
- */
- ctx->cf = NULL;
-
/* restore previous predicate state: */
ctx->so->ir->pred = ctx->pred_stack[--ctx->pred_depth];
get_predicate(ctx, &pred_dst, &pred_src);
- alu = ir2_instr_create_alu(next_exec_cf(ctx), ~0, PRED_SET_POPs);
- add_regs_dummy_vector(alu);
+ alu = ir2_instr_create_alu_s(ctx->so->ir, PRED_SET_POPs);
add_dst_reg(ctx, alu, &pred_dst);
add_src_reg(ctx, alu, &pred_src);
alu->pred = IR2_PRED_NONE;
/* predicate register no longer needed: */
ctx->pred_reg = -1;
}
-
- ctx->cf = NULL;
}
static void
get_internal_temp(ctx, &tmp_dst, &tmp_src);
- alu = ir2_instr_create_alu(next_exec_cf(ctx), ~0, LOG_CLAMP);
- add_regs_dummy_vector(alu);
+ alu = ir2_instr_create_alu_s(ctx->so->ir, LOG_CLAMP);
add_dst_reg(ctx, alu, &tmp_dst);
add_src_reg(ctx, alu, &inst->Src[0].Register);
- alu = ir2_instr_create_alu(next_exec_cf(ctx), MULv, ~0);
+ alu = ir2_instr_create_alu_v(ctx->so->ir, MULv);
add_dst_reg(ctx, alu, &tmp_dst);
add_src_reg(ctx, alu, &tmp_src);
add_src_reg(ctx, alu, &inst->Src[1].Register);
break;
}
- alu = ir2_instr_create_alu(next_exec_cf(ctx), ~0, EXP_IEEE);
- add_regs_dummy_vector(alu);
+ alu = ir2_instr_create_alu_s(ctx->so->ir, EXP_IEEE);
add_dst_reg(ctx, alu, &inst->Dst[0].Register);
add_src_reg(ctx, alu, &tmp_src);
add_scalar_clamp(inst, alu);
struct tgsi_full_instruction *inst, unsigned opc)
{
struct ir2_instruction *instr;
- struct ir2_register *reg;
+ struct ir2_src_register *reg;
struct tgsi_dst_register tmp_dst;
struct tgsi_src_register tmp_src;
const struct tgsi_src_register *coord;
*
* dst = texture_sample(unit, coord, bias)
*/
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MAXv, RECIP_IEEE);
- /* MAXv: */
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MAXv);
add_dst_reg(ctx, instr, &tmp_dst)->swizzle = "___w";
add_src_reg(ctx, instr, &inst->Src[0].Register);
add_src_reg(ctx, instr, &inst->Src[0].Register);
- /* RECIP_IEEE: */
+ instr = ir2_instr_create_alu_s(ctx->so->ir, RECIP_IEEE);
add_dst_reg(ctx, instr, &tmp_dst)->swizzle = "x___";
add_src_reg(ctx, instr, &inst->Src[0].Register)->swizzle =
swiz[inst->Src[0].Register.SwizzleW];
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MULv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULv);
add_dst_reg(ctx, instr, &tmp_dst)->swizzle = "xyz_";
add_src_reg(ctx, instr, &tmp_src)->swizzle = "xxxx";
add_src_reg(ctx, instr, &inst->Src[0].Register);
coord = &inst->Src[0].Register;
}
- instr = ir2_instr_create(next_exec_cf(ctx), IR2_FETCH);
+ instr = ir2_instr_create(ctx->so->ir, IR2_FETCH);
instr->fetch.opc = TEX_FETCH;
instr->fetch.is_cube = (inst->Texture.Texture == TGSI_TEXTURE_3D);
instr->fetch.is_rect = (inst->Texture.Texture == TGSI_TEXTURE_RECT);
reg->swizzle[2] = reg->swizzle[0];
/* dst register needs to be marked for sync: */
- ctx->need_sync |= 1 << instr->regs[0]->num;
+ ctx->need_sync |= 1 << instr->dst_reg.num;
/* TODO we need some way to know if the tex fetch needs to sync on alu pipe.. */
instr->sync = true;
* the texture to a temp and the use ALU instruction to move
* to output
*/
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MAXv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MAXv);
add_dst_reg(ctx, instr, &inst->Dst[0].Register);
add_src_reg(ctx, instr, &tmp_src);
get_internal_temp(ctx, &tmp_dst, &tmp_src);
- instr = ir2_instr_create_alu(next_exec_cf(ctx), ADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, ADDv);
add_dst_reg(ctx, instr, &tmp_dst);
add_src_reg(ctx, instr, &inst->Src[0].Register)->flags |= IR2_REG_NEGATE;
add_src_reg(ctx, instr, &inst->Src[1].Register);
- instr = ir2_instr_create_alu(next_exec_cf(ctx), vopc, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, vopc);
add_dst_reg(ctx, instr, &inst->Dst[0].Register);
- /* maybe should re-arrange the syntax some day, but
- * in assembler/disassembler and what ir.c expects
- * is: MULADDv Rdst = Rsrc2 + Rsrc0 * Rscr1
- */
- get_immediate(ctx, &tmp_const, fui(c0));
- add_src_reg(ctx, instr, &tmp_const);
add_src_reg(ctx, instr, &tmp_src);
get_immediate(ctx, &tmp_const, fui(c1));
add_src_reg(ctx, instr, &tmp_const);
+ get_immediate(ctx, &tmp_const, fui(c0));
+ add_src_reg(ctx, instr, &tmp_const);
}
/* LRP(a,b,c) = (a * b) + ((1 - a) * c) */
get_immediate(ctx, &tmp_const, fui(1.0));
/* tmp1 = (a * b) */
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MULv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULv);
add_dst_reg(ctx, instr, &tmp_dst1);
add_src_reg(ctx, instr, &inst->Src[0].Register);
add_src_reg(ctx, instr, &inst->Src[1].Register);
/* tmp2 = (1 - a) */
- instr = ir2_instr_create_alu(next_exec_cf(ctx), ADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, ADDv);
add_dst_reg(ctx, instr, &tmp_dst2);
add_src_reg(ctx, instr, &tmp_const);
add_src_reg(ctx, instr, &inst->Src[0].Register)->flags |= IR2_REG_NEGATE;
/* tmp2 = tmp2 * c */
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MULv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULv);
add_dst_reg(ctx, instr, &tmp_dst2);
add_src_reg(ctx, instr, &tmp_src2);
add_src_reg(ctx, instr, &inst->Src[2].Register);
/* dst = tmp1 + tmp2 */
- instr = ir2_instr_create_alu(next_exec_cf(ctx), ADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, ADDv);
add_dst_reg(ctx, instr, &inst->Dst[0].Register);
add_src_reg(ctx, instr, &tmp_src1);
add_src_reg(ctx, instr, &tmp_src2);
tmp_src.SwizzleX = tmp_src.SwizzleY =
tmp_src.SwizzleZ = tmp_src.SwizzleW = TGSI_SWIZZLE_X;
- /* maybe should re-arrange the syntax some day, but
- * in assembler/disassembler and what ir.c expects
- * is: MULADDv Rdst = Rsrc2 + Rsrc0 * Rscr1
- */
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MULADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULADDv);
add_dst_reg(ctx, instr, &tmp_dst);
- get_immediate(ctx, &tmp_const, fui(0.5));
- add_src_reg(ctx, instr, &tmp_const);
add_src_reg(ctx, instr, &inst->Src[0].Register);
get_immediate(ctx, &tmp_const, fui(0.159155));
add_src_reg(ctx, instr, &tmp_const);
+ get_immediate(ctx, &tmp_const, fui(0.5));
+ add_src_reg(ctx, instr, &tmp_const);
- instr = ir2_instr_create_alu(next_exec_cf(ctx), FRACv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, FRACv);
add_dst_reg(ctx, instr, &tmp_dst);
add_src_reg(ctx, instr, &tmp_src);
add_src_reg(ctx, instr, &tmp_src);
- instr = ir2_instr_create_alu(next_exec_cf(ctx), MULADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULADDv);
add_dst_reg(ctx, instr, &tmp_dst);
- get_immediate(ctx, &tmp_const, fui(-3.141593));
- add_src_reg(ctx, instr, &tmp_const);
add_src_reg(ctx, instr, &tmp_src);
get_immediate(ctx, &tmp_const, fui(6.283185));
add_src_reg(ctx, instr, &tmp_const);
+ get_immediate(ctx, &tmp_const, fui(-3.141593));
+ add_src_reg(ctx, instr, &tmp_const);
- instr = ir2_instr_create_alu(next_exec_cf(ctx), ~0, op);
- add_regs_dummy_vector(instr);
+ instr = ir2_instr_create_alu_s(ctx->so->ir, op);
add_dst_reg(ctx, instr, &inst->Dst[0].Register);
add_src_reg(ctx, instr, &tmp_src);
}
struct ir2_instruction *instr;
/* DP2ADD c,a,b -> dot2(a,b) + c */
/* for c we use the constant 0.0 */
- instr = ir2_instr_create_alu(next_exec_cf(ctx), DOT2ADDv, ~0);
- get_immediate(ctx, &tmp_const, fui(0.0f));
+ instr = ir2_instr_create_alu_v(ctx->so->ir, DOT2ADDv);
add_dst_reg(ctx, instr, &inst->Dst[0].Register);
- add_src_reg(ctx, instr, &tmp_const);
add_src_reg(ctx, instr, &inst->Src[0].Register);
add_src_reg(ctx, instr, &inst->Src[1].Register);
+ get_immediate(ctx, &tmp_const, fui(0.0f));
+ add_src_reg(ctx, instr, &tmp_const);
add_vector_clamp(inst, instr);
}
{
unsigned opc = inst->Instruction.Opcode;
struct ir2_instruction *instr;
- static struct ir2_cf *cf;
if (opc == TGSI_OPCODE_END)
return;
- if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT) {
- unsigned num = inst->Dst[0].Register.Index;
- /* seems like we need to ensure that position vs param/pixel
- * exports don't end up in the same EXEC clause.. easy way
- * to do this is force a new EXEC clause on first appearance
- * of an position or param/pixel export.
- */
- if ((num == ctx->position) || (num == ctx->psize)) {
- if (ctx->num_position > 0) {
- ctx->cf = NULL;
- ir2_cf_create_alloc(ctx->so->ir, SQ_POSITION,
- ctx->num_position - 1);
- ctx->num_position = 0;
- }
- } else {
- if (ctx->num_param > 0) {
- ctx->cf = NULL;
- ir2_cf_create_alloc(ctx->so->ir, SQ_PARAMETER_PIXEL,
- ctx->num_param - 1);
- ctx->num_param = 0;
- }
- }
- }
-
- cf = next_exec_cf(ctx);
-
/* TODO turn this into a table: */
switch (opc) {
case TGSI_OPCODE_MOV:
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MAXv);
add_regs_vector_1(ctx, inst, instr);
break;
case TGSI_OPCODE_RCP:
- instr = ir2_instr_create_alu(cf, ~0, RECIP_IEEE);
+ instr = ir2_instr_create_alu_s(ctx->so->ir, RECIP_IEEE);
add_regs_scalar_1(ctx, inst, instr);
break;
case TGSI_OPCODE_RSQ:
- instr = ir2_instr_create_alu(cf, ~0, RECIPSQ_IEEE);
+ instr = ir2_instr_create_alu_s(ctx->so->ir, RECIPSQ_IEEE);
add_regs_scalar_1(ctx, inst, instr);
break;
case TGSI_OPCODE_SQRT:
- instr = ir2_instr_create_alu(cf, ~0, SQRT_IEEE);
+ instr = ir2_instr_create_alu_s(ctx->so->ir, SQRT_IEEE);
add_regs_scalar_1(ctx, inst, instr);
break;
case TGSI_OPCODE_MUL:
- instr = ir2_instr_create_alu(cf, MULv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULv);
add_regs_vector_2(ctx, inst, instr);
break;
case TGSI_OPCODE_ADD:
- instr = ir2_instr_create_alu(cf, ADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, ADDv);
add_regs_vector_2(ctx, inst, instr);
break;
case TGSI_OPCODE_DP2:
translate_dp2(ctx, inst, opc);
break;
case TGSI_OPCODE_DP3:
- instr = ir2_instr_create_alu(cf, DOT3v, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, DOT3v);
add_regs_vector_2(ctx, inst, instr);
break;
case TGSI_OPCODE_DP4:
- instr = ir2_instr_create_alu(cf, DOT4v, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, DOT4v);
add_regs_vector_2(ctx, inst, instr);
break;
case TGSI_OPCODE_MIN:
- instr = ir2_instr_create_alu(cf, MINv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MINv);
add_regs_vector_2(ctx, inst, instr);
break;
case TGSI_OPCODE_MAX:
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MAXv);
add_regs_vector_2(ctx, inst, instr);
break;
case TGSI_OPCODE_SLT:
translate_sge_slt_seq_sne(ctx, inst, opc);
break;
case TGSI_OPCODE_MAD:
- instr = ir2_instr_create_alu(cf, MULADDv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, MULADDv);
add_regs_vector_3(ctx, inst, instr);
break;
case TGSI_OPCODE_LRP:
translate_lrp(ctx, inst, opc);
break;
case TGSI_OPCODE_FRC:
- instr = ir2_instr_create_alu(cf, FRACv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, FRACv);
add_regs_vector_1(ctx, inst, instr);
break;
case TGSI_OPCODE_FLR:
- instr = ir2_instr_create_alu(cf, FLOORv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, FLOORv);
add_regs_vector_1(ctx, inst, instr);
break;
case TGSI_OPCODE_EX2:
- instr = ir2_instr_create_alu(cf, ~0, EXP_IEEE);
+ instr = ir2_instr_create_alu_s(ctx->so->ir, EXP_IEEE);
add_regs_scalar_1(ctx, inst, instr);
break;
case TGSI_OPCODE_POW:
translate_tex(ctx, inst, opc);
break;
case TGSI_OPCODE_CMP:
- instr = ir2_instr_create_alu(cf, CNDGTEv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, CNDGTEv);
add_regs_vector_3(ctx, inst, instr);
- // TODO this should be src0 if regs where in sane order..
- instr->regs[2]->flags ^= IR2_REG_NEGATE; /* src1 */
+ instr->src_reg[0].flags ^= IR2_REG_NEGATE; /* src1 */
break;
case TGSI_OPCODE_IF:
push_predicate(ctx, &inst->Src[0].Register);
break;
case TGSI_OPCODE_ELSE:
ctx->so->ir->pred = IR2_PRED_NE;
- /* not sure if this is required in all cases, but blob compiler
- * won't combine EQ and NE in same CF:
- */
- ctx->cf = NULL;
break;
case TGSI_OPCODE_ENDIF:
pop_predicate(ctx);
break;
case TGSI_OPCODE_F2I:
- instr = ir2_instr_create_alu(cf, TRUNCv, ~0);
+ instr = ir2_instr_create_alu_v(ctx->so->ir, TRUNCv);
add_regs_vector_1(ctx, inst, instr);
break;
default:
break;
}
}
-
- ctx->cf->cf_type = EXEC_END;
}
int
instr->fetch.offset = elem->src_offset;
for (j = 0; j < 4; j++)
- instr->regs[0]->swizzle[j] = "xyzw01__"[desc->swizzle[j]];
+ instr->dst_reg.swizzle[j] = "xyzw01__"[desc->swizzle[j]];
assert(instr->fetch.fmt != ~0);
instr->fetch.const_idx,
instr->fetch.const_idx_sel,
elem->instance_divisor,
- instr->regs[0]->swizzle,
+ instr->dst_reg.swizzle,
instr->fetch.stride,
instr->fetch.offset);
}
create_blit_fp(void)
{
struct fd2_shader_stateobj *so = create_shader(SHADER_FRAGMENT);
- struct ir2_cf *cf;
struct ir2_instruction *instr;
if (!so)
so->ir = ir2_shader_create();
- cf = ir2_cf_create(so->ir, EXEC);
-
- instr = ir2_instr_create_tex_fetch(cf, 0);
- ir2_reg_create(instr, 0, "xyzw", 0);
- ir2_reg_create(instr, 0, "xyx", 0);
+ instr = ir2_instr_create_tex_fetch(so->ir, 0);
+ ir2_dst_create(instr, 0, "xyzw", 0);
+ ir2_reg_create(instr, 0, "xyx", IR2_REG_INPUT);
instr->sync = true;
- cf = ir2_cf_create_alloc(so->ir, SQ_PARAMETER_PIXEL, 0);
- cf = ir2_cf_create(so->ir, EXEC_END);
-
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
- ir2_reg_create(instr, 0, NULL, IR2_REG_EXPORT);
+ instr = ir2_instr_create_alu_v(so->ir, MAXv);
+ ir2_dst_create(instr, 0, NULL, IR2_REG_EXPORT);
ir2_reg_create(instr, 0, NULL, 0);
ir2_reg_create(instr, 0, NULL, 0);
create_blit_vp(void)
{
struct fd2_shader_stateobj *so = create_shader(SHADER_VERTEX);
- struct ir2_cf *cf;
struct ir2_instruction *instr;
if (!so)
so->ir = ir2_shader_create();
- cf = ir2_cf_create(so->ir, EXEC);
-
- instr = ir2_instr_create_vtx_fetch(cf, 26, 1, FMT_32_32_FLOAT, false, 8);
+ instr = ir2_instr_create_vtx_fetch(so->ir, 26, 1, FMT_32_32_FLOAT, false, 8);
instr->fetch.is_normalized = true;
- ir2_reg_create(instr, 1, "xy01", 0);
- ir2_reg_create(instr, 0, "x", 0);
+ ir2_dst_create(instr, 1, "xy01", 0);
+ ir2_reg_create(instr, 0, "x", IR2_REG_INPUT);
- instr = ir2_instr_create_vtx_fetch(cf, 26, 0, FMT_32_32_32_FLOAT, false, 12);
+ instr = ir2_instr_create_vtx_fetch(so->ir, 26, 0, FMT_32_32_32_FLOAT, false, 12);
instr->fetch.is_normalized = true;
- ir2_reg_create(instr, 2, "xyz1", 0);
- ir2_reg_create(instr, 0, "x", 0);
-
- cf = ir2_cf_create_alloc(so->ir, SQ_POSITION, 0);
- cf = ir2_cf_create(so->ir, EXEC);
+ ir2_dst_create(instr, 2, "xyz1", 0);
+ ir2_reg_create(instr, 0, "x", IR2_REG_INPUT);
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
- ir2_reg_create(instr, 62, NULL, IR2_REG_EXPORT);
+ instr = ir2_instr_create_alu_v(so->ir, MAXv);
+ ir2_dst_create(instr, 62, NULL, IR2_REG_EXPORT);
ir2_reg_create(instr, 2, NULL, 0);
ir2_reg_create(instr, 2, NULL, 0);
- cf = ir2_cf_create_alloc(so->ir, SQ_PARAMETER_PIXEL, 0);
- cf = ir2_cf_create(so->ir, EXEC_END);
-
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
- ir2_reg_create(instr, 0, NULL, IR2_REG_EXPORT);
+ instr = ir2_instr_create_alu_v(so->ir, MAXv);
+ ir2_dst_create(instr, 0, NULL, IR2_REG_EXPORT);
ir2_reg_create(instr, 1, NULL, 0);
ir2_reg_create(instr, 1, NULL, 0);
create_solid_fp(void)
{
struct fd2_shader_stateobj *so = create_shader(SHADER_FRAGMENT);
- struct ir2_cf *cf;
struct ir2_instruction *instr;
if (!so)
so->ir = ir2_shader_create();
- cf = ir2_cf_create_alloc(so->ir, SQ_PARAMETER_PIXEL, 0);
- cf = ir2_cf_create(so->ir, EXEC_END);
-
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
- ir2_reg_create(instr, 0, NULL, IR2_REG_EXPORT);
+ instr = ir2_instr_create_alu_v(so->ir, MAXv);
+ ir2_dst_create(instr, 0, NULL, IR2_REG_EXPORT);
ir2_reg_create(instr, 0, NULL, IR2_REG_CONST);
ir2_reg_create(instr, 0, NULL, IR2_REG_CONST);
create_solid_vp(void)
{
struct fd2_shader_stateobj *so = create_shader(SHADER_VERTEX);
- struct ir2_cf *cf;
struct ir2_instruction *instr;
if (!so)
so->ir = ir2_shader_create();
- cf = ir2_cf_create(so->ir, EXEC);
-
- instr = ir2_instr_create_vtx_fetch(cf, 26, 0, FMT_32_32_32_FLOAT, false, 12);
- ir2_reg_create(instr, 1, "xyz1", 0);
- ir2_reg_create(instr, 0, "x", 0);
-
- cf = ir2_cf_create_alloc(so->ir, SQ_POSITION, 0);
- cf = ir2_cf_create(so->ir, EXEC);
+ instr = ir2_instr_create_vtx_fetch(so->ir, 26, 0, FMT_32_32_32_FLOAT, false, 12);
+ ir2_dst_create(instr, 1, "xyz1", 0);
+ ir2_reg_create(instr, 0, "x", IR2_REG_INPUT);
- instr = ir2_instr_create_alu(cf, MAXv, ~0);
- ir2_reg_create(instr, 62, NULL, IR2_REG_EXPORT);
+ instr = ir2_instr_create_alu_v(so->ir, MAXv);
+ ir2_dst_create(instr, 62, NULL, IR2_REG_EXPORT);
ir2_reg_create(instr, 1, NULL, 0);
ir2_reg_create(instr, 1, NULL, 0);
- cf = ir2_cf_create_alloc(so->ir, SQ_PARAMETER_PIXEL, 0);
- cf = ir2_cf_create(so->ir, EXEC_END);
return assemble(so);
}
uint8_t const_1_rel_abs : 1;
uint8_t const_0_rel_abs : 1;
/* dword2: */
- uint8_t src3_reg : 6;
- uint8_t src3_reg_select : 1;
- uint8_t src3_reg_abs : 1;
- uint8_t src2_reg : 6;
- uint8_t src2_reg_select : 1;
- uint8_t src2_reg_abs : 1;
- uint8_t src1_reg : 6;
- uint8_t src1_reg_select : 1;
- uint8_t src1_reg_abs : 1;
+ union {
+ struct {
+ uint8_t src3_reg : 6;
+ uint8_t src3_reg_select : 1;
+ uint8_t src3_reg_abs : 1;
+ uint8_t src2_reg : 6;
+ uint8_t src2_reg_select : 1;
+ uint8_t src2_reg_abs : 1;
+ uint8_t src1_reg : 6;
+ uint8_t src1_reg_select : 1;
+ uint8_t src1_reg_abs : 1;
+ };
+ /* constants have full 8-bit index */
+ struct {
+ uint8_t src3_reg_const : 8;
+ uint8_t src2_reg_const : 8;
+ uint8_t src1_reg_const : 8;
+ };
+ };
instr_vector_opc_t vector_opc : 5;
uint8_t src3_sel : 1;
uint8_t src2_sel : 1;
#define WARN_MSG(f, ...) DBG("WARN: "f, ##__VA_ARGS__)
#define ERROR_MSG(f, ...) DBG("ERROR: "f, ##__VA_ARGS__)
-#define REG_MASK 0x3f
-
-static int cf_emit(struct ir2_cf *cf, instr_cf_t *instr);
-
static int instr_emit(struct ir2_instruction *instr, uint32_t *dwords,
uint32_t idx, struct ir2_shader_info *info);
-static void reg_update_stats(struct ir2_register *reg,
- struct ir2_shader_info *info, bool dest);
-static uint32_t reg_fetch_src_swiz(struct ir2_register *reg, uint32_t n);
-static uint32_t reg_fetch_dst_swiz(struct ir2_register *reg);
-static uint32_t reg_alu_dst_swiz(struct ir2_register *reg);
-static uint32_t reg_alu_src_swiz(struct ir2_register *reg);
+static uint32_t reg_fetch_src_swiz(struct ir2_src_register *reg, uint32_t n);
+static uint32_t reg_fetch_dst_swiz(struct ir2_dst_register *reg);
+static uint32_t reg_alu_dst_swiz(struct ir2_dst_register *reg);
+static uint32_t reg_alu_src_swiz(struct ir2_src_register *reg);
/* simple allocator to carve allocations out of an up-front allocated heap,
* so that we can free everything easily in one shot.
static void * ir2_alloc(struct ir2_shader *shader, int sz)
{
void *ptr = &shader->heap[shader->heap_idx];
- shader->heap_idx += align(sz, 4);
+ shader->heap_idx += align(sz, 4) / 4;
return ptr;
}
struct ir2_shader * ir2_shader_create(void)
{
DEBUG_MSG("");
- return calloc(1, sizeof(struct ir2_shader));
+ struct ir2_shader *shader = calloc(1, sizeof(struct ir2_shader));
+ shader->max_reg = -1;
+ return shader;
}
void ir2_shader_destroy(struct ir2_shader *shader)
free(shader);
}
-/* resolve addr/cnt/sequence fields in the individual CF's */
-static int shader_resolve(struct ir2_shader *shader, struct ir2_shader_info *info)
+/* check if an instruction is a simple MOV
+ */
+static struct ir2_instruction * simple_mov(struct ir2_instruction *instr,
+ bool output)
{
- uint32_t addr;
- unsigned i;
- int j;
-
- addr = shader->cfs_count / 2;
- for (i = 0; i < shader->cfs_count; i++) {
- struct ir2_cf *cf = shader->cfs[i];
- if ((cf->cf_type == EXEC) || (cf->cf_type == EXEC_END)) {
- uint32_t sequence = 0;
-
- if (cf->exec.addr && (cf->exec.addr != addr))
- WARN_MSG("invalid addr '%d' at CF %d", cf->exec.addr, i);
- if (cf->exec.cnt && (cf->exec.cnt != cf->exec.instrs_count))
- WARN_MSG("invalid cnt '%d' at CF %d", cf->exec.cnt, i);
-
- for (j = cf->exec.instrs_count - 1; j >= 0; j--) {
- struct ir2_instruction *instr = cf->exec.instrs[j];
- sequence <<= 2;
- if (instr->instr_type == IR2_FETCH)
- sequence |= 0x1;
- if (instr->sync)
- sequence |= 0x2;
- }
+ struct ir2_src_register *src_reg = instr->src_reg;
+ struct ir2_dst_register *dst_reg = &instr->dst_reg;
+ struct ir2_register *reg;
+ unsigned i;
+
+ /* MAXv used for MOV */
+ if (instr->instr_type != IR2_ALU_VECTOR ||
+ instr->alu_vector.opc != MAXv)
+ return NULL;
+
+ /* non identical srcs */
+ if (src_reg[0].num != src_reg[1].num)
+ return NULL;
+
+ /* flags */
+ int flags = IR2_REG_NEGATE | IR2_REG_ABS;
+ if (output)
+ flags |= IR2_REG_INPUT | IR2_REG_CONST;
+ if ((src_reg[0].flags & flags) || (src_reg[1].flags & flags))
+ return NULL;
+
+ /* clamping */
+ if (instr->alu_vector.clamp)
+ return NULL;
+
+ /* swizzling */
+ for (i = 0; i < 4; i++) {
+ char swiz = (dst_reg->swizzle ? dst_reg->swizzle : "xyzw")[i];
+ if (swiz == '_')
+ continue;
+
+ if (swiz != (src_reg[0].swizzle ? src_reg[0].swizzle : "xyzw")[i] ||
+ swiz != (src_reg[1].swizzle ? src_reg[1].swizzle : "xyzw")[i])
+ return NULL;
+ }
+
+ if (output)
+ reg = &instr->shader->reg[src_reg[0].num];
+ else
+ reg = &instr->shader->reg[dst_reg->num];
+
+ assert(reg->write_idx >= 0);
+ if (reg->write_idx != reg->write_idx2)
+ return NULL;
+
+ if (!output)
+ return instr;
+
+ instr = instr->shader->instr[reg->write_idx];
+ return instr->instr_type != IR2_ALU_VECTOR ? NULL : instr;
+}
- cf->exec.addr = addr;
- cf->exec.cnt = cf->exec.instrs_count;
- cf->exec.sequence = sequence;
+static int src_to_reg(struct ir2_instruction *instr,
+ struct ir2_src_register *reg)
+{
+ if (reg->flags & IR2_REG_CONST)
+ return reg->num;
- addr += cf->exec.instrs_count;
- }
- }
+ return instr->shader->reg[reg->num].reg;
+}
+
+static int dst_to_reg(struct ir2_instruction *instr,
+ struct ir2_dst_register *reg)
+{
+ if (reg->flags & IR2_REG_EXPORT)
+ return reg->num;
- info->sizedwords = 3 * addr;
+ return instr->shader->reg[reg->num].reg;
+}
- return 0;
+static bool mask_get(uint32_t *mask, unsigned index)
+{
+ return !!(mask[index / 32] & 1 << index % 32);
}
-void * ir2_shader_assemble(struct ir2_shader *shader, struct ir2_shader_info *info)
+static void mask_set(uint32_t *mask, struct ir2_register *reg, int index)
{
- uint32_t i, j;
- uint32_t *ptr, *dwords = NULL;
- uint32_t idx = 0;
- int ret;
-
- info->sizedwords = 0;
- info->max_reg = -1;
- info->max_input_reg = 0;
- info->regs_written = 0;
-
- /* we need an even # of CF's.. insert a NOP if needed */
- if (shader->cfs_count != align(shader->cfs_count, 2))
- ir2_cf_create(shader, NOP);
-
- /* first pass, resolve sizes and addresses: */
- ret = shader_resolve(shader, info);
- if (ret) {
- ERROR_MSG("resolve failed: %d", ret);
- goto fail;
+ if (reg) {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(reg->regmask); i++)
+ mask[i] |= reg->regmask[i];
}
+ if (index >= 0)
+ mask[index / 32] |= 1 << index % 32;
+}
- ptr = dwords = calloc(4, info->sizedwords);
+static bool sets_pred(struct ir2_instruction *instr)
+{
+ return instr->instr_type == IR2_ALU_SCALAR &&
+ instr->alu_scalar.opc >= PRED_SETEs &&
+ instr->alu_scalar.opc <= PRED_SET_RESTOREs;
+}
- /* second pass, emit CF program in pairs: */
- for (i = 0; i < shader->cfs_count; i += 2) {
- instr_cf_t *cfs = (instr_cf_t *)ptr;
- ret = cf_emit(shader->cfs[i], &cfs[0]);
- if (ret) {
- ERROR_MSG("CF emit failed: %d\n", ret);
- goto fail;
+
+
+void* ir2_shader_assemble(struct ir2_shader *shader,
+ struct ir2_shader_info *info)
+{
+ /* NOTES
+ * blob compiler seems to always puts PRED_* instrs in a CF by
+ * themselves, and wont combine EQ/NE in the same CF
+ * (not doing this - doesn't seem to make a difference)
+ *
+ * TODO: implement scheduling for combining vector+scalar instructions
+ * -some vector instructions can be replaced by scalar
+ */
+
+ /* first step:
+ * 1. remove "NOP" MOV instructions generated by TGSI for input/output:
+ * 2. track information for register allocation, and to remove
+ * the dead code when some exports are not needed
+ * 3. add additional instructions for a20x hw binning if needed
+ * NOTE: modifies the shader instrs
+ * this step could be done as instructions are added by compiler instead
+ */
+
+ /* mask of exports that must be generated
+ * used to avoid calculating ps exports with hw binning
+ */
+ uint64_t export = ~0ull;
+ /* bitmask of variables required for exports defined by "export" */
+ uint32_t export_mask[REG_MASK/32+1] = {};
+
+ unsigned idx, reg_idx;
+ unsigned max_input = 0;
+ int export_size = -1;
+
+ for (idx = 0; idx < shader->instr_count; idx++) {
+ struct ir2_instruction *instr = shader->instr[idx], *prev;
+ struct ir2_dst_register dst_reg = instr->dst_reg;
+
+ if (dst_reg.flags & IR2_REG_EXPORT) {
+ if (dst_reg.num < 32)
+ export_size++;
+
+ if ((prev = simple_mov(instr, true))) {
+ /* copy instruction but keep dst */
+ *instr = *prev;
+ instr->dst_reg = dst_reg;
+ }
}
- ret = cf_emit(shader->cfs[i+1], &cfs[1]);
- if (ret) {
- ERROR_MSG("CF emit failed: %d\n", ret);
- goto fail;
+
+ for (reg_idx = 0; reg_idx < instr->src_reg_count; reg_idx++) {
+ struct ir2_src_register *src_reg = &instr->src_reg[reg_idx];
+ struct ir2_register *reg;
+ int num;
+
+ if (src_reg->flags & IR2_REG_CONST)
+ continue;
+
+ num = src_reg->num;
+ reg = &shader->reg[num];
+ reg->read_idx = idx;
+
+ if (src_reg->flags & IR2_REG_INPUT) {
+ max_input = MAX2(max_input, num);
+ } else {
+ /* bypass simple mov used to set src_reg */
+ assert(reg->write_idx >= 0);
+ prev = shader->instr[reg->write_idx];
+ if (simple_mov(prev, false)) {
+ *src_reg = prev->src_reg[0];
+ /* process same src_reg again */
+ reg_idx -= 1;
+ continue;
+ }
+ }
+
+ /* update dependencies */
+ uint32_t *mask = (dst_reg.flags & IR2_REG_EXPORT) ?
+ export_mask : shader->reg[dst_reg.num].regmask;
+ mask_set(mask, reg, num);
+ if (sets_pred(instr))
+ mask_set(export_mask, reg, num);
}
- ptr += 3;
- assert((ptr - dwords) <= info->sizedwords);
}
- /* third pass, emit ALU/FETCH: */
- for (i = 0; i < shader->cfs_count; i++) {
- struct ir2_cf *cf = shader->cfs[i];
- if ((cf->cf_type == EXEC) || (cf->cf_type == EXEC_END)) {
- for (j = 0; j < cf->exec.instrs_count; j++) {
- ret = instr_emit(cf->exec.instrs[j], ptr, idx++, info);
- if (ret) {
- ERROR_MSG("instruction emit failed: %d", ret);
- goto fail;
- }
- ptr += 3;
- assert((ptr - dwords) <= info->sizedwords);
+ /* second step:
+ * emit instructions (with CFs) + RA
+ */
+ instr_cf_t cfs[128], *cf = cfs;
+ uint32_t alufetch[3*256], *af = alufetch;
+
+ /* RA is done on write, so inputs must be allocated here */
+ for (reg_idx = 0; reg_idx <= max_input; reg_idx++)
+ shader->reg[reg_idx].reg = reg_idx;
+ info->max_reg = max_input;
+
+ /* CF instr state */
+ instr_cf_exec_t exec = { .opc = EXEC };
+ instr_cf_alloc_t alloc = { .opc = ALLOC };
+ bool need_alloc = 0;
+ bool pos_export = 0;
+
+ export_size = MAX2(export_size, 0);
+
+ for (idx = 0; idx < shader->instr_count; idx++) {
+ struct ir2_instruction *instr = shader->instr[idx];
+ struct ir2_dst_register *dst_reg = &instr->dst_reg;
+ unsigned num = dst_reg->num;
+ struct ir2_register *reg;
+
+ /* a2xx only has 64 registers, so we can use a single 64-bit mask */
+ uint64_t regmask = 0ull;
+
+ /* compute the current regmask */
+ for (reg_idx = 0; (int) reg_idx <= shader->max_reg; reg_idx++) {
+ reg = &shader->reg[reg_idx];
+ if ((int) idx > reg->write_idx && idx < reg->read_idx)
+ regmask |= (1ull << reg->reg);
+ }
+
+ if (dst_reg->flags & IR2_REG_EXPORT) {
+ /* skip if export is not needed */
+ if (!(export & (1ull << num)))
+ continue;
+
+ /* ALLOC CF:
+ * want to alloc all < 32 at once
+ * 32/33 and 62/63 come in pairs
+ * XXX assuming all 3 types are never interleaved
+ */
+ if (num < 32) {
+ alloc.size = export_size;
+ alloc.buffer_select = SQ_PARAMETER_PIXEL;
+ need_alloc = export_size >= 0;
+ export_size = -1;
+ } else if (num == 32 || num == 33) {
+ alloc.size = 0;
+ alloc.buffer_select = SQ_MEMORY;
+ need_alloc = num != 33;
+ } else {
+ alloc.size = 0;
+ alloc.buffer_select = SQ_POSITION;
+ need_alloc = !pos_export;
+ pos_export = true;
}
+
+ } else {
+ /* skip if dst register not needed to compute exports */
+ if (!mask_get(export_mask, num))
+ continue;
+
+ /* RA on first write */
+ reg = &shader->reg[num];
+ if (reg->write_idx == idx) {
+ reg->reg = ffsll(~regmask) - 1;
+ info->max_reg = MAX2(info->max_reg, reg->reg);
+ }
+ }
+
+ if (exec.count == 6 || (exec.count && need_alloc)) {
+ *cf++ = *(instr_cf_t*) &exec;
+ exec.address += exec.count;
+ exec.serialize = 0;
+ exec.count = 0;
}
+
+ if (need_alloc) {
+ *cf++ = *(instr_cf_t*) &alloc;
+ need_alloc = false;
+ }
+
+ int ret = instr_emit(instr, af, idx, info); af += 3;
+ assert(!ret);
+
+ if (instr->instr_type == IR2_FETCH)
+ exec.serialize |= 0x1 << exec.count * 2;
+ if (instr->sync)
+ exec.serialize |= 0x2 << exec.count * 2;
+ exec.count += 1;
}
- return dwords;
-fail:
- free(dwords);
- return NULL;
-}
+ exec.opc = !export_size ? EXEC : EXEC_END;
+ *cf++ = *(instr_cf_t*) &exec;
+ exec.address += exec.count;
+ exec.serialize = 0;
+ exec.count = 0;
+ /* GPU will hang without at least one pixel alloc */
+ if (!export_size) {
+ alloc.size = 0;
+ alloc.buffer_select = SQ_PARAMETER_PIXEL;
+ *cf++ = *(instr_cf_t*) &alloc;
-struct ir2_cf * ir2_cf_create(struct ir2_shader *shader, instr_cf_opc_t cf_type)
-{
- struct ir2_cf *cf = ir2_alloc(shader, sizeof(struct ir2_cf));
- DEBUG_MSG("%d", cf_type);
- cf->shader = shader;
- cf->cf_type = cf_type;
- assert(shader->cfs_count < ARRAY_SIZE(shader->cfs));
- shader->cfs[shader->cfs_count++] = cf;
- return cf;
-}
+ exec.opc = EXEC_END;
+ *cf++ = *(instr_cf_t*) &exec;
+ }
+ unsigned num_cfs = cf - cfs;
-/*
- * CF instructions:
- */
+ /* insert nop to get an even # of CFs */
+ if (num_cfs % 2) {
+ *cf++ = (instr_cf_t) { .opc = NOP };
+ num_cfs++;
+ }
-static int cf_emit(struct ir2_cf *cf, instr_cf_t *instr)
-{
- memset(instr, 0, sizeof(*instr));
-
- instr->opc = cf->cf_type;
-
- switch (cf->cf_type) {
- case NOP:
- break;
- case EXEC:
- case EXEC_END:
- assert(cf->exec.addr <= 0x1ff);
- assert(cf->exec.cnt <= 0x6);
- assert(cf->exec.sequence <= 0xfff);
- instr->exec.address = cf->exec.addr;
- instr->exec.count = cf->exec.cnt;
- instr->exec.serialize = cf->exec.sequence;
- break;
- case ALLOC:
- assert(cf->alloc.size <= 0xf);
- instr->alloc.size = cf->alloc.size;
- switch (cf->alloc.type) {
- case SQ_POSITION:
- case SQ_PARAMETER_PIXEL:
- instr->alloc.buffer_select = cf->alloc.type;
+ /* offset cf addrs */
+ for (idx = 0; idx < num_cfs; idx++) {
+ switch (cfs[idx].opc) {
+ case EXEC:
+ case EXEC_END:
+ cfs[idx].exec.address += num_cfs / 2;
break;
default:
- ERROR_MSG("invalid alloc type: %d", cf->alloc.type);
- return -1;
+ break;
+ /* XXX and any other address using cf that gets implemented */
}
- break;
- case COND_EXEC:
- case COND_EXEC_END:
- case COND_PRED_EXEC:
- case COND_PRED_EXEC_END:
- case LOOP_START:
- case LOOP_END:
- case COND_CALL:
- case RETURN:
- case COND_JMP:
- case COND_EXEC_PRED_CLEAN:
- case COND_EXEC_PRED_CLEAN_END:
- case MARK_VS_FETCH_DONE:
- ERROR_MSG("TODO");
- return -1;
}
- return 0;
+ /* concatenate cfs+alufetchs */
+ uint32_t cfdwords = num_cfs / 2 * 3;
+ uint32_t alufetchdwords = exec.address * 3;
+ info->sizedwords = cfdwords + alufetchdwords;
+ uint32_t *dwords = malloc(info->sizedwords * 4);
+ assert(dwords);
+ memcpy(dwords, cfs, cfdwords * 4);
+ memcpy(&dwords[cfdwords], alufetch, alufetchdwords * 4);
+ return dwords;
}
-
-struct ir2_instruction * ir2_instr_create(struct ir2_cf *cf, int instr_type)
+struct ir2_instruction * ir2_instr_create(struct ir2_shader *shader,
+ int instr_type)
{
struct ir2_instruction *instr =
- ir2_alloc(cf->shader, sizeof(struct ir2_instruction));
+ ir2_alloc(shader, sizeof(struct ir2_instruction));
DEBUG_MSG("%d", instr_type);
- instr->shader = cf->shader;
- instr->pred = cf->shader->pred;
+ instr->shader = shader;
+ instr->idx = shader->instr_count;
+ instr->pred = shader->pred;
instr->instr_type = instr_type;
- assert(cf->exec.instrs_count < ARRAY_SIZE(cf->exec.instrs));
- cf->exec.instrs[cf->exec.instrs_count++] = instr;
+ shader->instr[shader->instr_count++] = instr;
return instr;
}
struct ir2_shader_info *info)
{
instr_fetch_t *fetch = (instr_fetch_t *)dwords;
- int reg = 0;
- struct ir2_register *dst_reg = instr->regs[reg++];
- struct ir2_register *src_reg = instr->regs[reg++];
+ struct ir2_dst_register *dst_reg = &instr->dst_reg;
+ struct ir2_src_register *src_reg = &instr->src_reg[0];
memset(fetch, 0, sizeof(*fetch));
- reg_update_stats(dst_reg, info, true);
- reg_update_stats(src_reg, info, false);
-
fetch->opc = instr->fetch.opc;
if (instr->fetch.opc == VTX_FETCH) {
assert(instr->fetch.const_idx <= 0x1f);
assert(instr->fetch.const_idx_sel <= 0x3);
- vtx->src_reg = src_reg->num;
+ vtx->src_reg = src_to_reg(instr, src_reg);
vtx->src_swiz = reg_fetch_src_swiz(src_reg, 1);
- vtx->dst_reg = dst_reg->num;
+ vtx->dst_reg = dst_to_reg(instr, dst_reg);
vtx->dst_swiz = reg_fetch_dst_swiz(dst_reg);
vtx->must_be_one = 1;
vtx->const_index = instr->fetch.const_idx;
assert(instr->fetch.const_idx <= 0x1f);
- tex->src_reg = src_reg->num;
+ tex->src_reg = src_to_reg(instr, src_reg);
tex->src_swiz = reg_fetch_src_swiz(src_reg, 3);
- tex->dst_reg = dst_reg->num;
+ tex->dst_reg = dst_to_reg(instr, dst_reg);
tex->dst_swiz = reg_fetch_dst_swiz(dst_reg);
tex->const_idx = instr->fetch.const_idx;
tex->mag_filter = TEX_FILTER_USE_FETCH_CONST;
* ALU instructions:
*/
-static int instr_emit_alu(struct ir2_instruction *instr, uint32_t *dwords,
+static int instr_emit_alu(struct ir2_instruction *instr_v,
+ struct ir2_instruction *instr_s, uint32_t *dwords,
struct ir2_shader_info *info)
{
- int reg = 0;
instr_alu_t *alu = (instr_alu_t *)dwords;
- struct ir2_register *dst_reg = instr->regs[reg++];
- struct ir2_register *src1_reg;
- struct ir2_register *src2_reg;
- struct ir2_register *src3_reg;
+ struct ir2_dst_register *vdst_reg, *sdst_reg;
+ struct ir2_src_register *src1_reg, *src2_reg, *src3_reg;
+ struct ir2_shader *shader = instr_v ? instr_v->shader : instr_s->shader;
+ enum ir2_pred pred = IR2_PRED_NONE;
memset(alu, 0, sizeof(*alu));
- /* handle instructions w/ 3 src operands: */
- switch (instr->alu.vector_opc) {
- case MULADDv:
- case CNDEv:
- case CNDGTEv:
- case CNDGTv:
- case DOT2ADDv:
- /* note: disassembler lists 3rd src first, ie:
- * MULADDv Rdst = Rsrc3 + (Rsrc1 * Rsrc2)
- * which is the reason for this strange ordering.
- */
- src3_reg = instr->regs[reg++];
- break;
- default:
- src3_reg = NULL;
- break;
+ vdst_reg = NULL;
+ sdst_reg = NULL;
+ src1_reg = NULL;
+ src2_reg = NULL;
+ src3_reg = NULL;
+
+ if (instr_v) {
+ vdst_reg = &instr_v->dst_reg;
+ assert(instr_v->src_reg_count >= 2);
+ src1_reg = &instr_v->src_reg[0];
+ src2_reg = &instr_v->src_reg[1];
+ if (instr_v->src_reg_count > 2)
+ src3_reg = &instr_v->src_reg[2];
+ pred = instr_v->pred;
}
- src1_reg = instr->regs[reg++];
- src2_reg = instr->regs[reg++];
-
- reg_update_stats(dst_reg, info, true);
- reg_update_stats(src1_reg, info, false);
- reg_update_stats(src2_reg, info, false);
-
- assert((dst_reg->flags & ~IR2_REG_EXPORT) == 0);
- assert(!dst_reg->swizzle || (strlen(dst_reg->swizzle) == 4));
- assert((src1_reg->flags & IR2_REG_EXPORT) == 0);
- assert(!src1_reg->swizzle || (strlen(src1_reg->swizzle) == 4));
- assert((src2_reg->flags & IR2_REG_EXPORT) == 0);
- assert(!src2_reg->swizzle || (strlen(src2_reg->swizzle) == 4));
+ if (instr_s) {
+ sdst_reg = &instr_s->dst_reg;
+ assert(instr_s->src_reg_count == 1);
+ assert(!instr_v || vdst_reg->flags == sdst_reg->flags);
+ assert(!instr_v || pred == instr_s->pred);
+ if (src3_reg) {
+ assert(src3_reg->flags == instr_s->src_reg[0].flags);
+ assert(src3_reg->num == instr_s->src_reg[0].num);
+ assert(!strcmp(src3_reg->swizzle, instr_s->src_reg[0].swizzle));
+ }
+ src3_reg = &instr_s->src_reg[0];
+ pred = instr_s->pred;
+ }
- if (instr->alu.vector_opc == (instr_vector_opc_t)~0) {
- alu->vector_opc = MAXv;
- alu->vector_write_mask = 0;
+ if (vdst_reg) {
+ assert((vdst_reg->flags & ~IR2_REG_EXPORT) == 0);
+ assert(!vdst_reg->swizzle || (strlen(vdst_reg->swizzle) == 4));
+ alu->vector_opc = instr_v->alu_vector.opc;
+ alu->vector_write_mask = reg_alu_dst_swiz(vdst_reg);
+ alu->vector_dest = dst_to_reg(instr_v, vdst_reg);
} else {
- alu->vector_opc = instr->alu.vector_opc;
- alu->vector_write_mask = reg_alu_dst_swiz(dst_reg);
+ alu->vector_opc = MAXv;
}
- alu->vector_dest = dst_reg->num;
- alu->export_data = !!(dst_reg->flags & IR2_REG_EXPORT);
-
- // TODO predicate case/condition.. need to add to parser
-
- alu->src2_reg = src2_reg->num;
- alu->src2_swiz = reg_alu_src_swiz(src2_reg);
- alu->src2_reg_negate = !!(src2_reg->flags & IR2_REG_NEGATE);
- alu->src2_reg_abs = !!(src2_reg->flags & IR2_REG_ABS);
- alu->src2_sel = !(src2_reg->flags & IR2_REG_CONST);
-
- alu->src1_reg = src1_reg->num;
- alu->src1_swiz = reg_alu_src_swiz(src1_reg);
- alu->src1_reg_negate = !!(src1_reg->flags & IR2_REG_NEGATE);
- alu->src1_reg_abs = !!(src1_reg->flags & IR2_REG_ABS);
- alu->src1_sel = !(src1_reg->flags & IR2_REG_CONST);
-
- alu->vector_clamp = instr->alu.vector_clamp;
- alu->scalar_clamp = instr->alu.scalar_clamp;
-
- if (instr->alu.scalar_opc != (instr_scalar_opc_t)~0) {
- struct ir2_register *sdst_reg = instr->regs[reg++];
-
- reg_update_stats(sdst_reg, info, true);
-
- assert(sdst_reg->flags == dst_reg->flags);
-
- if (src3_reg) {
- assert(src3_reg == instr->regs[reg]);
- reg++;
- } else {
- src3_reg = instr->regs[reg++];
- }
-
- alu->scalar_dest = sdst_reg->num;
+ if (sdst_reg) {
+ alu->scalar_opc = instr_s->alu_scalar.opc;
alu->scalar_write_mask = reg_alu_dst_swiz(sdst_reg);
- alu->scalar_opc = instr->alu.scalar_opc;
+ alu->scalar_dest = dst_to_reg(instr_s, sdst_reg);
} else {
/* not sure if this is required, but adreno compiler seems
* to always set scalar opc to MAXs if it is not used:
alu->scalar_opc = MAXs;
}
- if (src3_reg) {
- reg_update_stats(src3_reg, info, false);
+ alu->export_data =
+ !!((instr_v ? vdst_reg : sdst_reg)->flags & IR2_REG_EXPORT);
- alu->src3_reg = src3_reg->num;
+ /* export32 has this bit set.. it seems to do more than just set
+ * the base address of the constants used to zero
+ * TODO make this less of a hack
+ */
+ if (alu->export_data && alu->vector_dest == 32) {
+ assert(!instr_s);
+ alu->relative_addr = 1;
+ }
+
+ if (src1_reg) {
+ if (src1_reg->flags & IR2_REG_CONST) {
+ assert(!(src1_reg->flags & IR2_REG_ABS));
+ alu->src1_reg_const = src1_reg->num;
+ } else {
+ alu->src1_reg = shader->reg[src1_reg->num].reg;
+ alu->src1_reg_abs = !!(src1_reg->flags & IR2_REG_ABS);
+ }
+ alu->src1_swiz = reg_alu_src_swiz(src1_reg);
+ alu->src1_reg_negate = !!(src1_reg->flags & IR2_REG_NEGATE);
+ alu->src1_sel = !(src1_reg->flags & IR2_REG_CONST);
+ } else {
+ alu->src1_sel = 1;
+ }
+
+ if (src2_reg) {
+ if (src2_reg->flags & IR2_REG_CONST) {
+ assert(!(src2_reg->flags & IR2_REG_ABS));
+ alu->src2_reg_const = src2_reg->num;
+ } else {
+ alu->src2_reg = shader->reg[src2_reg->num].reg;
+ alu->src2_reg_abs = !!(src2_reg->flags & IR2_REG_ABS);
+ }
+ alu->src2_swiz = reg_alu_src_swiz(src2_reg);
+ alu->src2_reg_negate = !!(src2_reg->flags & IR2_REG_NEGATE);
+ alu->src2_sel = !(src2_reg->flags & IR2_REG_CONST);
+ } else {
+ alu->src2_sel = 1;
+ }
+
+ if (src3_reg) {
+ if (src3_reg->flags & IR2_REG_CONST) {
+ assert(!(src3_reg->flags & IR2_REG_ABS));
+ alu->src3_reg_const = src3_reg->num;
+ } else {
+ alu->src3_reg = shader->reg[src3_reg->num].reg;
+ alu->src3_reg_abs = !!(src3_reg->flags & IR2_REG_ABS);
+ }
alu->src3_swiz = reg_alu_src_swiz(src3_reg);
alu->src3_reg_negate = !!(src3_reg->flags & IR2_REG_NEGATE);
- alu->src3_reg_abs = !!(src3_reg->flags & IR2_REG_ABS);
alu->src3_sel = !(src3_reg->flags & IR2_REG_CONST);
} else {
/* not sure if this is required, but adreno compiler seems
alu->src3_sel = 1;
}
- if (instr->pred != IR2_PRED_NONE) {
- alu->pred_select = (instr->pred == IR2_PRED_EQ) ? 3 : 2;
- }
+ alu->vector_clamp = instr_v ? instr_v->alu_vector.clamp : 0;
+ alu->scalar_clamp = instr_s ? instr_s->alu_scalar.clamp : 0;
+
+ if (pred != IR2_PRED_NONE)
+ alu->pred_select = (pred == IR2_PRED_EQ) ? 3 : 2;
return 0;
}
{
switch (instr->instr_type) {
case IR2_FETCH: return instr_emit_fetch(instr, dwords, idx, info);
- case IR2_ALU: return instr_emit_alu(instr, dwords, info);
+ case IR2_ALU_VECTOR: return instr_emit_alu(instr, NULL, dwords, info);
+ case IR2_ALU_SCALAR: return instr_emit_alu(NULL, instr, dwords, info);
}
return -1;
}
-
-struct ir2_register * ir2_reg_create(struct ir2_instruction *instr,
+struct ir2_dst_register * ir2_dst_create(struct ir2_instruction *instr,
int num, const char *swizzle, int flags)
{
- struct ir2_register *reg =
- ir2_alloc(instr->shader, sizeof(struct ir2_register));
- DEBUG_MSG("%x, %d, %s", flags, num, swizzle);
- assert(num <= REG_MASK);
+ if (!(flags & IR2_REG_EXPORT)) {
+ struct ir2_register *reg = &instr->shader->reg[num];
+
+ unsigned i;
+ for (i = instr->shader->max_reg + 1; i <= num; i++)
+ instr->shader->reg[i].write_idx = -1;
+ instr->shader->max_reg = i - 1;
+
+ if (reg->write_idx < 0)
+ reg->write_idx = instr->idx;
+ reg->write_idx2 = instr->idx;
+ }
+
+ struct ir2_dst_register *reg = &instr->dst_reg;
reg->flags = flags;
reg->num = num;
reg->swizzle = ir2_strdup(instr->shader, swizzle);
- assert(instr->regs_count < ARRAY_SIZE(instr->regs));
- instr->regs[instr->regs_count++] = reg;
return reg;
}
-static void reg_update_stats(struct ir2_register *reg,
- struct ir2_shader_info *info, bool dest)
+struct ir2_src_register * ir2_reg_create(struct ir2_instruction *instr,
+ int num, const char *swizzle, int flags)
{
- if (!(reg->flags & (IR2_REG_CONST|IR2_REG_EXPORT))) {
- info->max_reg = MAX2(info->max_reg, reg->num);
-
- if (dest) {
- info->regs_written |= (1 << reg->num);
- } else if (!(info->regs_written & (1 << reg->num))) {
- /* for registers that haven't been written, they must be an
- * input register that the thread scheduler (presumably?)
- * needs to know about:
- */
- info->max_input_reg = MAX2(info->max_input_reg, reg->num);
- }
+ assert(instr->src_reg_count + 1 <= ARRAY_SIZE(instr->src_reg));
+ if (!(flags & IR2_REG_CONST)) {
+ struct ir2_register *reg = &instr->shader->reg[num];
+
+ reg->read_idx = instr->idx;
+
+ unsigned i;
+ for (i = instr->shader->max_reg + 1; i <= num; i++)
+ instr->shader->reg[i].write_idx = -1;
+ instr->shader->max_reg = i - 1;
}
+
+ struct ir2_src_register *reg = &instr->src_reg[instr->src_reg_count++];
+ reg->flags = flags;
+ reg->num = num;
+ reg->swizzle = ir2_strdup(instr->shader, swizzle);
+ return reg;
}
-static uint32_t reg_fetch_src_swiz(struct ir2_register *reg, uint32_t n)
+static uint32_t reg_fetch_src_swiz(struct ir2_src_register *reg, uint32_t n)
{
uint32_t swiz = 0;
int i;
- assert(reg->flags == 0);
+ assert((reg->flags & ~IR2_REG_INPUT) == 0);
assert(reg->swizzle);
DEBUG_MSG("fetch src R%d.%s", reg->num, reg->swizzle);
return swiz;
}
-static uint32_t reg_fetch_dst_swiz(struct ir2_register *reg)
+static uint32_t reg_fetch_dst_swiz(struct ir2_dst_register *reg)
{
uint32_t swiz = 0;
int i;
}
/* actually, a write-mask */
-static uint32_t reg_alu_dst_swiz(struct ir2_register *reg)
+static uint32_t reg_alu_dst_swiz(struct ir2_dst_register *reg)
{
uint32_t swiz = 0;
int i;
return swiz;
}
-static uint32_t reg_alu_src_swiz(struct ir2_register *reg)
+static uint32_t reg_alu_src_swiz(struct ir2_src_register *reg)
{
uint32_t swiz = 0;
int i;
- assert((reg->flags & IR2_REG_EXPORT) == 0);
assert(!reg->swizzle || (strlen(reg->swizzle) == 4));
DEBUG_MSG("vector src R%d.%s", reg->num, reg->swizzle);
struct ir2_shader;
+#define REG_MASK 0xff
+
struct ir2_shader_info {
uint16_t sizedwords;
int8_t max_reg; /* highest GPR # used by shader */
- uint8_t max_input_reg;
- uint64_t regs_written;
};
struct ir2_register {
+ int16_t write_idx, write_idx2, read_idx, reg;
+ /* bitmask of variables on which this one depends
+ * XXX: use bitmask util?
+ */
+ uint32_t regmask[REG_MASK/32+1];
+};
+
+struct ir2_src_register {
enum {
- IR2_REG_CONST = 0x1,
- IR2_REG_EXPORT = 0x2,
+ IR2_REG_INPUT = 0x1,
+ IR2_REG_CONST = 0x2,
IR2_REG_NEGATE = 0x4,
IR2_REG_ABS = 0x8,
} flags;
char *swizzle;
};
+struct ir2_dst_register {
+ enum {
+ IR2_REG_EXPORT = 0x1,
+ } flags;
+ int num;
+ char *swizzle;
+};
+
enum ir2_pred {
IR2_PRED_NONE = 0,
IR2_PRED_EQ = 1,
struct ir2_instruction {
struct ir2_shader *shader;
+ unsigned idx;
enum {
IR2_FETCH,
- IR2_ALU,
+ IR2_ALU_VECTOR,
+ IR2_ALU_SCALAR,
} instr_type;
enum ir2_pred pred;
int sync;
- unsigned regs_count;
- struct ir2_register *regs[5];
+ unsigned src_reg_count;
+ struct ir2_dst_register dst_reg;
+ struct ir2_src_register src_reg[3];
union {
/* FETCH specific: */
struct {
uint32_t stride;
uint32_t offset;
} fetch;
- /* ALU specific: */
+ /* ALU-Vector specific: */
struct {
- instr_vector_opc_t vector_opc;
- instr_scalar_opc_t scalar_opc;
- bool vector_clamp : 1;
- bool scalar_clamp : 1;
- } alu;
- };
-};
-
-struct ir2_cf {
- struct ir2_shader *shader;
- instr_cf_opc_t cf_type;
-
- union {
- /* EXEC/EXEC_END specific: */
- struct {
- unsigned instrs_count;
- struct ir2_instruction *instrs[6];
- uint32_t addr, cnt, sequence;
- } exec;
- /* ALLOC specific: */
+ instr_vector_opc_t opc;
+ bool clamp;
+ } alu_vector;
+ /* ALU-Scalar specific: */
struct {
- instr_alloc_type_t type; /* SQ_POSITION or SQ_PARAMETER_PIXEL */
- int size;
- } alloc;
+ instr_scalar_opc_t opc;
+ bool clamp;
+ } alu_scalar;
};
};
struct ir2_shader {
- unsigned cfs_count;
- struct ir2_cf *cfs[0x56];
+ unsigned instr_count;
+ int max_reg;
+ struct ir2_register reg[REG_MASK+1];
+
+ struct ir2_instruction *instr[0x200];
uint32_t heap[100 * 4096];
unsigned heap_idx;
void * ir2_shader_assemble(struct ir2_shader *shader,
struct ir2_shader_info *info);
-struct ir2_cf * ir2_cf_create(struct ir2_shader *shader, instr_cf_opc_t cf_type);
-
-struct ir2_instruction * ir2_instr_create(struct ir2_cf *cf, int instr_type);
+struct ir2_instruction * ir2_instr_create(struct ir2_shader *shader,
+ int instr_type);
-struct ir2_register * ir2_reg_create(struct ir2_instruction *instr,
+struct ir2_dst_register * ir2_dst_create(struct ir2_instruction *instr,
+ int num, const char *swizzle, int flags);
+struct ir2_src_register * ir2_reg_create(struct ir2_instruction *instr,
int num, const char *swizzle, int flags);
/* some helper fxns: */
-static inline struct ir2_cf *
-ir2_cf_create_alloc(struct ir2_shader *shader, instr_alloc_type_t type, int size)
+static inline struct ir2_instruction *
+ir2_instr_create_alu_v(struct ir2_shader *shader, instr_vector_opc_t vop)
{
- struct ir2_cf *cf = ir2_cf_create(shader, ALLOC);
- if (!cf)
- return cf;
- cf->alloc.type = type;
- cf->alloc.size = size;
- return cf;
+ struct ir2_instruction *instr = ir2_instr_create(shader, IR2_ALU_VECTOR);
+ if (!instr)
+ return instr;
+ instr->alu_vector.opc = vop;
+ return instr;
}
+
static inline struct ir2_instruction *
-ir2_instr_create_alu(struct ir2_cf *cf, instr_vector_opc_t vop, instr_scalar_opc_t sop)
+ir2_instr_create_alu_s(struct ir2_shader *shader, instr_scalar_opc_t sop)
{
- struct ir2_instruction *instr = ir2_instr_create(cf, IR2_ALU);
+ struct ir2_instruction *instr = ir2_instr_create(shader, IR2_ALU_SCALAR);
if (!instr)
return instr;
- instr->alu.vector_opc = vop;
- instr->alu.scalar_opc = sop;
+ instr->alu_scalar.opc = sop;
return instr;
}
+
static inline struct ir2_instruction *
-ir2_instr_create_vtx_fetch(struct ir2_cf *cf, int ci, int cis,
+ir2_instr_create_vtx_fetch(struct ir2_shader *shader, int ci, int cis,
enum a2xx_sq_surfaceformat fmt, bool is_signed, int stride)
{
- struct ir2_instruction *instr = ir2_instr_create(cf, IR2_FETCH);
+ struct ir2_instruction *instr = ir2_instr_create(shader, IR2_FETCH);
instr->fetch.opc = VTX_FETCH;
instr->fetch.const_idx = ci;
instr->fetch.const_idx_sel = cis;
return instr;
}
static inline struct ir2_instruction *
-ir2_instr_create_tex_fetch(struct ir2_cf *cf, int ci)
+ir2_instr_create_tex_fetch(struct ir2_shader *shader, int ci)
{
- struct ir2_instruction *instr = ir2_instr_create(cf, IR2_FETCH);
+ struct ir2_instruction *instr = ir2_instr_create(shader, IR2_FETCH);
instr->fetch.opc = TEX_FETCH;
instr->fetch.const_idx = ci;
return instr;