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)
{
const char type = c ? 'c' : 'r';
fprintf(ctx->out, "(r)");
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) {
/* I would just use %+d but trying to make it diff'able with
* libllvm-a3xx...
static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel)
{
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
bool full;
bool r;
bool c;
+ bool f; /* src reg is interpreted as float, used for printing immediates */
bool im;
bool neg;
bool abs;
if (info->r)
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);
}
static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
{
instr_cat2_t *cat2 = &instr->cat2;
+ int opc = _OPC(2, cat2->opc);
static const char *cond[] = {
"lt",
"le",
"?6?",
};
- switch (_OPC(2, cat2->opc)) {
+ switch (opc) {
case OPC_CMPS_F:
case OPC_CMPS_U:
case OPC_CMPS_S:
struct reginfo src1 = {
.full = cat2->full,
.r = cat2->repeat ? cat2->src1_r : 0,
+ .f = is_cat2_float(opc),
.im = cat2->src1_im,
.abs = cat2->src1_abs,
.neg = cat2->src1_neg,
struct reginfo src2 = {
.r = cat2->repeat ? cat2->src2_r : 0,
.full = cat2->full,
+ .f = is_cat2_float(opc),
.abs = cat2->src2_abs,
.neg = cat2->src2_neg,
.im = cat2->src2_im,
};
- switch (_OPC(2, cat2->opc)) {
+ switch (opc) {
case OPC_ABSNEG_F:
case OPC_ABSNEG_S:
case OPC_CLZ_B:
}
}
+
+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);
#endif /* INSTR_A3XX_H_ */
}
}
-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: */
static inline unsigned ir3_cat2_absneg(opc_t opc)
{
if (!valid_flags(instr, n, new_flags)) {
/* See if lowering an immediate to const would help. */
if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
- bool f_opcode = (ir3_cat2_float(instr->opc) ||
- ir3_cat3_float(instr->opc)) ? true : false;
+ bool f_opcode = (is_cat2_float(instr->opc) ||
+ is_cat3_float(instr->opc)) ? true : false;
debug_assert(new_flags & IR3_REG_IMMED);
if (src->cat1.dst_type == TYPE_F16) {
if (instr->opc == OPC_MOV && !type_float(instr->cat1.src_type))
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 true;
} else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
- bool f_opcode = (ir3_cat2_float(instr->opc) ||
- ir3_cat3_float(instr->opc)) ? true : false;
+ bool f_opcode = (is_cat2_float(instr->opc) ||
+ is_cat3_float(instr->opc)) ? true : false;
/* See if lowering an immediate to const would help. */
instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
/* discard stuff */
INSTR_6XX(42b400f8_20010004, "cmps.s.eq p0.x, r1.x, 1"),
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