/* last input dst (for setting (ei) flag): */
struct ir3_register *last_input;
+ /* last instruction with relative addressing: */
+ struct ir3_instruction *last_rel;
+
unsigned next_inloc;
unsigned num_internal_temps;
struct tgsi_src_register internal_temps[6];
ctx->ir = so->ir;
ctx->so = so;
ctx->last_input = NULL;
+ ctx->last_rel = NULL;
ctx->next_inloc = 8;
ctx->num_internal_temps = 0;
ctx->branch_count = 0;
unsigned arg;
};
+static void
+handle_last_rel(struct fd3_compile_context *ctx)
+{
+ if (ctx->last_rel) {
+ ctx->last_rel->flags |= IR3_INSTR_UL;
+ ctx->last_rel = NULL;
+ }
+}
+
static unsigned
src_flags(struct fd3_compile_context *ctx, struct ir3_register *reg)
{
unsigned flags = 0;
+ if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED))
+ return flags;
+
if (regmask_get(ctx->needs_ss, reg)) {
flags |= IR3_INSTR_SS;
memset(ctx->needs_ss, 0, sizeof(ctx->needs_ss));
case TGSI_FILE_TEMPORARY:
num = dst->Index + ctx->base_reg[dst->File];
break;
+ case TGSI_FILE_ADDRESS:
+ num = REG_A0;
+ break;
default:
compile_error(ctx, "unsupported dst register file: %s\n",
tgsi_file_name(dst->File));
unsigned flags = 0, num = 0;
struct ir3_register *reg;
+ /* TODO we need to use a mov to temp for const >= 64.. or maybe
+ * we could use relative addressing..
+ */
+ compile_assert(ctx, src->Index < 64);
+
switch (src->File) {
case TGSI_FILE_IMMEDIATE:
/* TODO if possible, use actual immediate instead of const.. but
flags |= IR3_REG_ABS;
if (src->Negate)
flags |= IR3_REG_NEGATE;
+ if (src->Indirect)
+ flags |= IR3_REG_RELATIV;
if (ctx->so->half_precision)
flags |= IR3_REG_HALF;
reg = ir3_reg_create(instr, regid(num, chan), flags);
+ if (src->Indirect)
+ ctx->last_rel = instr;
+
instr->flags |= src_flags(ctx, reg);
return reg;
return tmp_src;
}
+/* Get internal half-precision temp src/dst to use for a sequence of
+ * instructions generated by a single TGSI op.
+ */
+static struct tgsi_src_register *
+get_internal_temp_hr(struct fd3_compile_context *ctx,
+ struct tgsi_dst_register *tmp_dst)
+{
+ struct tgsi_src_register *tmp_src;
+ int n;
+
+ if (ctx->so->half_precision)
+ return get_internal_temp(ctx, tmp_dst);
+
+ tmp_dst->File = TGSI_FILE_TEMPORARY;
+ tmp_dst->WriteMask = TGSI_WRITEMASK_XYZW;
+ tmp_dst->Indirect = 0;
+ tmp_dst->Dimension = 0;
+
+ /* assign next temporary: */
+ n = ctx->num_internal_temps++;
+ compile_assert(ctx, n < ARRAY_SIZE(ctx->internal_temps));
+ tmp_src = &ctx->internal_temps[n];
+
+ /* just use hr0 because no one else should be using half-
+ * precision regs:
+ */
+ tmp_dst->Index = 0;
+
+ src_from_dst(tmp_src, tmp_dst);
+
+ return tmp_src;
+}
+
/* same as get_internal_temp, but w/ src.xxxx (for instructions that
* replicate their results)
*/
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
struct tgsi_src_register *src = &inst->Src[i].Register;
if ((src->File == dst->File) && (src->Index == dst->Index)) {
+ if ((src->SwizzleX == TGSI_SWIZZLE_X) &&
+ (src->SwizzleY == TGSI_SWIZZLE_Y) &&
+ (src->SwizzleZ == TGSI_SWIZZLE_Z) &&
+ (src->SwizzleW == TGSI_SWIZZLE_W))
+ continue;
ctx->tmp_src = get_internal_temp(ctx, &ctx->tmp_dst);
ctx->tmp_dst.WriteMask = dst->WriteMask;
dst = &ctx->tmp_dst;
{
va_list ap;
int i, j, n = 0;
+ bool indirect = dst->Indirect;
add_dst_reg(ctx, instr, dst, 0);
reg->flags |= flags & ~IR3_REG_NEGATE;
if (flags & IR3_REG_NEGATE)
reg->flags ^= IR3_REG_NEGATE;
+ indirect |= src->Indirect;
}
va_end(ap);
cur->flags |= src_flags(ctx, cur->regs[j+1]);
}
va_end(ap);
+
+ if (indirect)
+ ctx->last_rel = cur;
}
}
tmp_src, IR3_REG_NEGATE);
}
+/* ARL(x) = x, but mova from hrN.x to a0.. */
+static void
+trans_arl(const struct instr_translater *t,
+ struct fd3_compile_context *ctx,
+ struct tgsi_full_instruction *inst)
+{
+ struct ir3_instruction *instr;
+ struct tgsi_dst_register tmp_dst;
+ struct tgsi_src_register *tmp_src;
+ struct tgsi_dst_register *dst = &inst->Dst[0].Register;
+ struct tgsi_src_register *src = &inst->Src[0].Register;
+ unsigned chan = src->SwizzleX;
+ compile_assert(ctx, dst->File == TGSI_FILE_ADDRESS);
+
+ handle_last_rel(ctx);
+
+ tmp_src = get_internal_temp_hr(ctx, &tmp_dst);
+
+
+ /* cov.{f32,f16}s16 Rtmp, Rsrc */
+ instr = ir3_instr_create(ctx->ir, 1, 0);
+ instr->cat1.src_type = get_ftype(ctx);
+ instr->cat1.dst_type = TYPE_S16;
+ add_dst_reg(ctx, instr, &tmp_dst, chan)->flags |= IR3_REG_HALF;
+ add_src_reg(ctx, instr, src, chan);
+
+ ir3_instr_create(ctx->ir, 0, OPC_NOP)->repeat = 2;
+
+ /* shl.b Rtmp, Rtmp, 2 */
+ instr = ir3_instr_create(ctx->ir, 2, OPC_SHL_B);
+ add_dst_reg(ctx, instr, &tmp_dst, chan)->flags |= IR3_REG_HALF;
+ add_src_reg(ctx, instr, tmp_src, chan)->flags |= IR3_REG_HALF;
+ ir3_reg_create(instr, 0, IR3_REG_IMMED)->iim_val = 2;
+
+ ir3_instr_create(ctx->ir, 0, OPC_NOP)->repeat = 2;
+
+ /* mova a0, Rtmp */
+ instr = ir3_instr_create(ctx->ir, 1, 0);
+ instr->cat1.src_type = TYPE_S16;
+ instr->cat1.dst_type = TYPE_S16;
+ add_dst_reg(ctx, instr, dst, 0)->flags |= IR3_REG_HALF;
+ add_src_reg(ctx, instr, tmp_src, chan)->flags |= IR3_REG_HALF;
+
+ /* need to ensure 5 instr slots before a0 is used: */
+ ir3_instr_create(ctx->ir, 0, OPC_NOP)->repeat = 5;
+}
+
/* POW(a,b) = EXP2(b * LOG2(a)) */
static void
trans_pow(const struct instr_translater *t,
INSTR(MIN, instr_cat2, .opc = OPC_MIN_F),
INSTR(MAX, instr_cat2, .opc = OPC_MAX_F),
INSTR(MAD, instr_cat3, .opc = OPC_MAD_F32, .hopc = OPC_MAD_F16),
+ INSTR(TRUNC, instr_cat2, .opc = OPC_TRUNC_F),
INSTR(LRP, trans_lrp),
INSTR(FRC, trans_frac),
INSTR(FLR, instr_cat2, .opc = OPC_FLOOR_F),
- INSTR(ARL, instr_cat2, .opc = OPC_FLOOR_F),
+ INSTR(ARL, trans_arl),
INSTR(EX2, instr_cat4, .opc = OPC_EXP2),
INSTR(LG2, instr_cat4, .opc = OPC_LOG2),
INSTR(POW, trans_pow),
if (ctx->last_input)
ctx->last_input->flags |= IR3_REG_EI;
+
+ handle_last_rel(ctx);
}
int