freedreno/ir3: Add support for disasm of cat2 float32 immediates.
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4736>
This commit is contained in:
parent
292231596b
commit
4a42a50585
|
@ -88,7 +88,23 @@ struct disasm_ctx {
|
||||||
unsigned instructions;
|
unsigned instructions;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, bool r,
|
static const char *float_imms[] = {
|
||||||
|
"0.0",
|
||||||
|
"0.5",
|
||||||
|
"1.0",
|
||||||
|
"2.0",
|
||||||
|
"e",
|
||||||
|
"pi",
|
||||||
|
"1/pi",
|
||||||
|
"1/log2(e)",
|
||||||
|
"log2(e)",
|
||||||
|
"1/log2(10)",
|
||||||
|
"log2(10)",
|
||||||
|
"4.0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full,
|
||||||
|
bool is_float, bool r,
|
||||||
bool c, bool im, bool neg, bool abs, bool addr_rel)
|
bool c, bool im, bool neg, bool abs, bool addr_rel)
|
||||||
{
|
{
|
||||||
const char type = c ? 'c' : 'r';
|
const char type = c ? 'c' : 'r';
|
||||||
|
@ -107,7 +123,11 @@ static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, bool r,
|
||||||
fprintf(ctx->out, "(r)");
|
fprintf(ctx->out, "(r)");
|
||||||
|
|
||||||
if (im) {
|
if (im) {
|
||||||
fprintf(ctx->out, "%d", reg.iim_val);
|
if (is_float && full && reg.iim_val < ARRAY_SIZE(float_imms)) {
|
||||||
|
fprintf(ctx->out, "(%s)", float_imms[reg.iim_val]);
|
||||||
|
} else {
|
||||||
|
fprintf(ctx->out, "%d", reg.iim_val);
|
||||||
|
}
|
||||||
} else if (addr_rel) {
|
} else if (addr_rel) {
|
||||||
/* I would just use %+d but trying to make it diff'able with
|
/* I would just use %+d but trying to make it diff'able with
|
||||||
* libllvm-a3xx...
|
* libllvm-a3xx...
|
||||||
|
@ -146,7 +166,7 @@ static reg_t idxreg(unsigned idx)
|
||||||
static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel)
|
static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel)
|
||||||
{
|
{
|
||||||
reg = idxreg(regidx(reg) + ctx->repeatidx);
|
reg = idxreg(regidx(reg) + ctx->repeatidx);
|
||||||
print_reg(ctx, reg, full, false, false, false, false, false, addr_rel);
|
print_reg(ctx, reg, full, false, false, false, false, false, false, addr_rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO switch to using reginfo struct everywhere, since more readable
|
/* TODO switch to using reginfo struct everywhere, since more readable
|
||||||
|
@ -158,6 +178,7 @@ struct reginfo {
|
||||||
bool full;
|
bool full;
|
||||||
bool r;
|
bool r;
|
||||||
bool c;
|
bool c;
|
||||||
|
bool f; /* src reg is interpreted as float, used for printing immediates */
|
||||||
bool im;
|
bool im;
|
||||||
bool neg;
|
bool neg;
|
||||||
bool abs;
|
bool abs;
|
||||||
|
@ -171,7 +192,7 @@ static void print_src(struct disasm_ctx *ctx, struct reginfo *info)
|
||||||
if (info->r)
|
if (info->r)
|
||||||
reg = idxreg(regidx(info->reg) + ctx->repeatidx);
|
reg = idxreg(regidx(info->reg) + ctx->repeatidx);
|
||||||
|
|
||||||
print_reg(ctx, reg, info->full, info->r, info->c, info->im,
|
print_reg(ctx, reg, info->full, info->f, info->r, info->c, info->im,
|
||||||
info->neg, info->abs, info->addr_rel);
|
info->neg, info->abs, info->addr_rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,6 +294,7 @@ static void print_instr_cat1(struct disasm_ctx *ctx, instr_t *instr)
|
||||||
static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
|
static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
|
||||||
{
|
{
|
||||||
instr_cat2_t *cat2 = &instr->cat2;
|
instr_cat2_t *cat2 = &instr->cat2;
|
||||||
|
int opc = _OPC(2, cat2->opc);
|
||||||
static const char *cond[] = {
|
static const char *cond[] = {
|
||||||
"lt",
|
"lt",
|
||||||
"le",
|
"le",
|
||||||
|
@ -283,7 +305,7 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
|
||||||
"?6?",
|
"?6?",
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (_OPC(2, cat2->opc)) {
|
switch (opc) {
|
||||||
case OPC_CMPS_F:
|
case OPC_CMPS_F:
|
||||||
case OPC_CMPS_U:
|
case OPC_CMPS_U:
|
||||||
case OPC_CMPS_S:
|
case OPC_CMPS_S:
|
||||||
|
@ -303,6 +325,7 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
|
||||||
struct reginfo src1 = {
|
struct reginfo src1 = {
|
||||||
.full = cat2->full,
|
.full = cat2->full,
|
||||||
.r = cat2->repeat ? cat2->src1_r : 0,
|
.r = cat2->repeat ? cat2->src1_r : 0,
|
||||||
|
.f = is_cat2_float(opc),
|
||||||
.im = cat2->src1_im,
|
.im = cat2->src1_im,
|
||||||
.abs = cat2->src1_abs,
|
.abs = cat2->src1_abs,
|
||||||
.neg = cat2->src1_neg,
|
.neg = cat2->src1_neg,
|
||||||
|
@ -323,11 +346,12 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
|
||||||
struct reginfo src2 = {
|
struct reginfo src2 = {
|
||||||
.r = cat2->repeat ? cat2->src2_r : 0,
|
.r = cat2->repeat ? cat2->src2_r : 0,
|
||||||
.full = cat2->full,
|
.full = cat2->full,
|
||||||
|
.f = is_cat2_float(opc),
|
||||||
.abs = cat2->src2_abs,
|
.abs = cat2->src2_abs,
|
||||||
.neg = cat2->src2_neg,
|
.neg = cat2->src2_neg,
|
||||||
.im = cat2->src2_im,
|
.im = cat2->src2_im,
|
||||||
};
|
};
|
||||||
switch (_OPC(2, cat2->opc)) {
|
switch (opc) {
|
||||||
case OPC_ABSNEG_F:
|
case OPC_ABSNEG_F:
|
||||||
case OPC_ABSNEG_S:
|
case OPC_ABSNEG_S:
|
||||||
case OPC_CLZ_B:
|
case OPC_CLZ_B:
|
||||||
|
|
|
@ -1050,6 +1050,43 @@ static inline bool is_isam(opc_t opc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool is_cat2_float(opc_t opc)
|
||||||
|
{
|
||||||
|
switch (opc) {
|
||||||
|
case OPC_ADD_F:
|
||||||
|
case OPC_MIN_F:
|
||||||
|
case OPC_MAX_F:
|
||||||
|
case OPC_MUL_F:
|
||||||
|
case OPC_SIGN_F:
|
||||||
|
case OPC_CMPS_F:
|
||||||
|
case OPC_ABSNEG_F:
|
||||||
|
case OPC_CMPV_F:
|
||||||
|
case OPC_FLOOR_F:
|
||||||
|
case OPC_CEIL_F:
|
||||||
|
case OPC_RNDNE_F:
|
||||||
|
case OPC_RNDAZ_F:
|
||||||
|
case OPC_TRUNC_F:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_cat3_float(opc_t opc)
|
||||||
|
{
|
||||||
|
switch (opc) {
|
||||||
|
case OPC_MAD_F16:
|
||||||
|
case OPC_MAD_F32:
|
||||||
|
case OPC_SEL_F16:
|
||||||
|
case OPC_SEL_F32:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id);
|
int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id);
|
||||||
|
|
||||||
#endif /* INSTR_A3XX_H_ */
|
#endif /* INSTR_A3XX_H_ */
|
||||||
|
|
|
@ -957,42 +957,6 @@ static inline bool ir3_cat2_int(opc_t opc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool ir3_cat2_float(opc_t opc)
|
|
||||||
{
|
|
||||||
switch (opc) {
|
|
||||||
case OPC_ADD_F:
|
|
||||||
case OPC_MIN_F:
|
|
||||||
case OPC_MAX_F:
|
|
||||||
case OPC_MUL_F:
|
|
||||||
case OPC_SIGN_F:
|
|
||||||
case OPC_CMPS_F:
|
|
||||||
case OPC_ABSNEG_F:
|
|
||||||
case OPC_CMPV_F:
|
|
||||||
case OPC_FLOOR_F:
|
|
||||||
case OPC_CEIL_F:
|
|
||||||
case OPC_RNDNE_F:
|
|
||||||
case OPC_RNDAZ_F:
|
|
||||||
case OPC_TRUNC_F:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool ir3_cat3_float(opc_t opc)
|
|
||||||
{
|
|
||||||
switch (opc) {
|
|
||||||
case OPC_MAD_F16:
|
|
||||||
case OPC_MAD_F32:
|
|
||||||
case OPC_SEL_F16:
|
|
||||||
case OPC_SEL_F32:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* map cat2 instruction to valid abs/neg flags: */
|
/* map cat2 instruction to valid abs/neg flags: */
|
||||||
static inline unsigned ir3_cat2_absneg(opc_t opc)
|
static inline unsigned ir3_cat2_absneg(opc_t opc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -478,8 +478,8 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
|
||||||
if (!valid_flags(instr, n, new_flags)) {
|
if (!valid_flags(instr, n, new_flags)) {
|
||||||
/* See if lowering an immediate to const would help. */
|
/* See if lowering an immediate to const would help. */
|
||||||
if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
|
if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
|
||||||
bool f_opcode = (ir3_cat2_float(instr->opc) ||
|
bool f_opcode = (is_cat2_float(instr->opc) ||
|
||||||
ir3_cat3_float(instr->opc)) ? true : false;
|
is_cat3_float(instr->opc)) ? true : false;
|
||||||
|
|
||||||
debug_assert(new_flags & IR3_REG_IMMED);
|
debug_assert(new_flags & IR3_REG_IMMED);
|
||||||
|
|
||||||
|
@ -533,7 +533,7 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
|
||||||
if (src->cat1.dst_type == TYPE_F16) {
|
if (src->cat1.dst_type == TYPE_F16) {
|
||||||
if (instr->opc == OPC_MOV && !type_float(instr->cat1.src_type))
|
if (instr->opc == OPC_MOV && !type_float(instr->cat1.src_type))
|
||||||
return false;
|
return false;
|
||||||
if (!ir3_cat2_float(instr->opc) && !ir3_cat3_float(instr->opc))
|
if (!is_cat2_float(instr->opc) && !is_cat3_float(instr->opc))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,8 +594,8 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
|
} else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
|
||||||
bool f_opcode = (ir3_cat2_float(instr->opc) ||
|
bool f_opcode = (is_cat2_float(instr->opc) ||
|
||||||
ir3_cat3_float(instr->opc)) ? true : false;
|
is_cat3_float(instr->opc)) ? true : false;
|
||||||
|
|
||||||
/* See if lowering an immediate to const would help. */
|
/* See if lowering an immediate to const would help. */
|
||||||
instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
|
instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
|
||||||
|
|
|
@ -77,6 +77,20 @@ static const struct test {
|
||||||
/* discard stuff */
|
/* discard stuff */
|
||||||
INSTR_6XX(42b400f8_20010004, "cmps.s.eq p0.x, r1.x, 1"),
|
INSTR_6XX(42b400f8_20010004, "cmps.s.eq p0.x, r1.x, 1"),
|
||||||
INSTR_6XX(02800000_00000000, "kill p0.x"),
|
INSTR_6XX(02800000_00000000, "kill p0.x"),
|
||||||
|
|
||||||
|
/* Immediates */
|
||||||
|
INSTR_6XX(40100007_68000008, "add.f r1.w, r2.x, (neg)(0.0)"),
|
||||||
|
INSTR_6XX(40100007_68010008, "add.f r1.w, r2.x, (neg)(0.5)"),
|
||||||
|
INSTR_6XX(40100007_68020008, "add.f r1.w, r2.x, (neg)(1.0)"),
|
||||||
|
INSTR_6XX(40100007_68030008, "add.f r1.w, r2.x, (neg)(2.0)"),
|
||||||
|
INSTR_6XX(40100007_68040008, "add.f r1.w, r2.x, (neg)(e)"),
|
||||||
|
INSTR_6XX(40100007_68050008, "add.f r1.w, r2.x, (neg)(pi)"),
|
||||||
|
INSTR_6XX(40100007_68060008, "add.f r1.w, r2.x, (neg)(1/pi)"),
|
||||||
|
INSTR_6XX(40100007_68070008, "add.f r1.w, r2.x, (neg)(1/log2(e))"),
|
||||||
|
INSTR_6XX(40100007_68080008, "add.f r1.w, r2.x, (neg)(log2(e))"),
|
||||||
|
INSTR_6XX(40100007_68090008, "add.f r1.w, r2.x, (neg)(1/log2(10))"),
|
||||||
|
INSTR_6XX(40100007_680a0008, "add.f r1.w, r2.x, (neg)(log2(10))"),
|
||||||
|
INSTR_6XX(40100007_680b0008, "add.f r1.w, r2.x, (neg)(4.0)"),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue