> -----Original Message-----
> From: Alessandro Di Federico <ale.q...@rev.ng>
> Sent: Saturday, June 19, 2021 3:37 AM
> To: qemu-devel@nongnu.org
> Cc: Taylor Simpson <tsimp...@quicinc.com>; Brian Cain
> <bc...@quicinc.com>; bab...@rev.ng; ni...@rev.ng; phi...@redhat.com;
> richard.hender...@linaro.org; Alessandro Di Federico <a...@rev.ng>
> Subject: [PATCH v5 10/14] target/hexagon: import parser for idef-parser
>
> From: Paolo Montesel <bab...@rev.ng>
>
> Signed-off-by: Alessandro Di Federico <a...@rev.ng>
> Signed-off-by: Paolo Montesel <bab...@rev.ng>
> ---
> diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-
> parser/idef-parser.y
> +for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')'
> + {
> + @1.last_column = @13.last_column;
> + OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
> + &$7, " < ", &$9);
> + OUT(c, &@1, "; ", &$11, "++) {\n");
Increase indent level here
> + }
> + code_block
> + {
Decrease indent level
> + OUT(c, &@1, "}\n");
> + }
> + | FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM INC IMM ')'
> + {
> + @1.last_column = @14.last_column;
> + OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ",
> + &$7, " < ", &$9);
> + OUT(c, &@1, "; ", &$11, " += ", &$13, ") {\n");
Increase indent
> + }
> + code_block
> + {
Decrease indent
> + OUT(c, &@1, "}\n");
> + }
> + ;
> +
> +fpart1_statement : PART1
> + {
> + OUT(c, &@1, "if (insn->part1) {\n");
Increase indent
> + }
> + '(' statements ')'
> + {
> + @1.last_column = @3.last_column;
Emit the return first, then decrease indent before the curly
> + OUT(c, &@1, "return; }\n");
> + }
> + ;
> + | rvalue '[' rvalue ']'
> + {
> + @1.last_column = @4.last_column;
> + if ($3.type == IMMEDIATE) {
> + $$ = gen_tmp(c, &@1, $1.bit_width);
> + OUT(c, &@1, "tcg_gen_extract_i", &$$.bit_width, "(");
> + OUT(c, &@1, &$$, ", ", &$1, ", ", &$3, ", 1);\n");
> + } else {
> + HexValue one = gen_imm_value(c, &@1, 1, $3.bit_width);
> + HexValue tmp = gen_bin_op(c, &@1, ASR_OP, &$1, &$3);
> + $$ = gen_bin_op(c, &@1, ANDB_OP, &tmp, &one);
Can this be done with a tcg_gen_extract_tl or tcg_gen_sextract_tl?
Do you need to worry about signed-ness?
> diff --git a/target/hexagon/idef-parser/parser-helpers.c
> b/target/hexagon/idef-parser/parser-helpers.c
> new file mode 100644
> +const char *creg_str[] = {"HEX_REG_SP", "HEX_REG_FP", "HEX_REG_LR",
> + "HEX_REG_GP", "HEX_REG_LC0", "HEX_REG_LC1",
> + "HEX_REG_SA0", "HEX_REG_SA1"};
SP, FP, LR shouldn't in this array.
> +void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5])
> +{
> + switch (reg->type) {
> + case GENERAL_PURPOSE:
> + reg_id[0] = 'R';
> + break;
> + case CONTROL:
> + reg_id[0] = 'C';
> + break;
> + case MODIFIER:
> + reg_id[0] = 'M';
> + break;
> + case DOTNEW:
> + /* The DOTNEW case is managed by the upper level function */
Should we raise an error if we get here?
> + break;
> + }
> + switch (reg->bit_width) {
> + case 32:
> + reg_id[1] = reg->id;
> + reg_id[2] = 'V';
> + break;
> + case 64:
> + reg_id[1] = reg->id;
> + reg_id[2] = reg->id;
> + reg_id[3] = 'V';
> + break;
> + default:
> + yyassert(c, locp, false, "Unhandled register bit width!\n");
> + }
> +}
> +
> +void reg_print(Context *c, YYLTYPE *locp, HexReg *reg)
> +{
> + if (reg->type == DOTNEW) {
> + EMIT(c, "N%cN", reg->id);
Why not handle this in reg_compose?
> + } else {
> + char reg_id[5] = { 0 };
> + reg_compose(c, locp, reg, reg_id);
> + EMIT(c, "%s", reg_id);
> + }
> +}
> +
> +void imm_print(Context *c, YYLTYPE *locp, HexImm *imm)
> +{
> + switch (imm->type) {
> + case I:
> + EMIT(c, "i");
> + break;
> + case VARIABLE:
> + EMIT(c, "%ciV", imm->id);
> + break;
> + case VALUE:
> + EMIT(c, "((int64_t)%" PRIu64 "ULL)", (int64_t)imm->value);
> + break;
> + case QEMU_TMP:
> + EMIT(c, "qemu_tmp_%" PRIu64, imm->index);
> + break;
> + case IMM_PC:
> + EMIT(c, "ctx->base.pc_next");
> + break;
> + case IMM_NPC:
> + EMIT(c, "ctx->npc");
> + break;
> + case IMM_CONSTEXT:
> + EMIT(c, "insn->extension_valid");
The extension_valid field is a bool indicating if the instruction has a
constant extender. Don't you want the actual value here?
> + break;
> +
> +static HexValue get_ternary_cond(Context *c, YYLTYPE *locp)
> +{
> + yyassert(c, locp, is_inside_ternary(c), "unexisting condition");
> + Ternary *t = &g_array_index(c->ternary, Ternary, 0);
> + HexValue cond = t->cond;
> + if (t->state == IN_RIGHT) {
> + cond = gen_rvalue_notl(c, locp, &cond);
> + }
> + for (unsigned i = 1; i < c->ternary->len; ++i) {
> + Ternary *right = &g_array_index(c->ternary, Ternary, i);
> + HexValue other = right->cond;
> + /* Invert condition if we are on the right side */
> + if (right->state == IN_RIGHT) {
> + other = gen_rvalue_notl(c, locp, &other);
> + }
> + cond = gen_bin_op(c, locp, ANDL_OP, &cond, &other);
> + }
> + return cond;
> +}
> +
> +/* Temporary values creation */
> +HexValue gen_tmp(Context *c, YYLTYPE *locp, int bit_width)
> +{
> + HexValue rvalue;
> + rvalue.type = TEMP;
> + bit_width = (bit_width == 64) ? 64 : 32;
Better to assert it's either 64 or 32
> + rvalue.bit_width = bit_width;
> + rvalue.is_unsigned = false;
> + rvalue.is_dotnew = false;
> + rvalue.is_manual = false;
> + rvalue.tmp.index = c->inst.tmp_count;
> + OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count,
> + " = tcg_temp_new_i", &bit_width, "();\n");
> + c->inst.tmp_count++;
> + return rvalue;
> +}
> +
> +
> +void rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue)
Should be called gen_rvalue_free
> +{
> + if (rvalue->type == TEMP && !rvalue->is_manual) {
> + const char *bit_suffix = (rvalue->bit_width == 64) ? "i64" : "i32";
> + OUT(c, locp, "tcg_temp_free_", bit_suffix, "(", rvalue, ");\n");
> + }
> +}
> +HexValue rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue)
Should be called gen_rvalue_extend
> +{
> + if (rvalue->type == IMMEDIATE) {
> + HexValue res = *rvalue;
> + res.bit_width = 64;
> + return res;
> + } else {
> + if (rvalue->bit_width == 32) {
> + HexValue res = gen_tmp(c, locp, 64);
> + const char *sign_suffix = (rvalue->is_unsigned) ? "u" : "";
> + OUT(c, locp, "tcg_gen_ext", sign_suffix,
> + "_i32_i64(", &res, ", ", rvalue, ");\n");
> + rvalue_free(c, locp, rvalue);
> + return res;
> + }
> + }
> + return *rvalue;
> +}
> +
> +HexValue rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue)
Should be called gen_rvalue_truncate
> +{
> + if (rvalue->type == IMMEDIATE) {
> + HexValue res = *rvalue;
> + res.bit_width = 32;
> + return res;
> + } else {
> + if (rvalue->bit_width == 64) {
> + HexValue res = gen_tmp(c, locp, 32);
> + OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", rvalue,
> ");\n");
> + rvalue_free(c, locp, rvalue);
> + return res;
> + }
> + }
> + return *rvalue;
> +}
> +
> +void varid_allocate(Context *c,
gen_varid_allocate
> + YYLTYPE *locp,
> + HexValue *varid,
> + int width,
> + bool is_unsigned)
> +{
> + varid->bit_width = width;
> + const char *bit_suffix = width == 64 ? "64" : "32";
> + int index = find_variable(c, locp, varid);
> + bool found = index != -1;
> + if (found) {
> + Var *other = &g_array_index(c->inst.allocated, Var, index);
> + varid->var.name = other->name;
> + varid->bit_width = other->bit_width;
> + varid->is_unsigned = other->is_unsigned;
> + } else {
> + EMIT_HEAD(c, "TCGv_i%s %s", bit_suffix, varid->var.name->str);
> + EMIT_HEAD(c, " = tcg_temp_local_new_i%s();\n", bit_suffix);
> + Var new_var = {
> + .name = varid->var.name,
> + .bit_width = width,
> + .is_unsigned = is_unsigned,
> + };
> + g_array_append_val(c->inst.allocated, new_var);
> + }
> +}
> +
> +void ea_free(Context *c, YYLTYPE *locp)
gen_ea_free
> +{
> + OUT(c, locp, "tcg_temp_free(EA);\n");
> +}
> +HexValue gen_bin_cmp(Context *c,
> + YYLTYPE *locp,
> + TCGCond type,
> + HexValue *op1_ptr,
> + HexValue *op2_ptr)
> +{
> + HexValue op1 = *op1_ptr;
> + HexValue op2 = *op2_ptr;
> + enum OpTypes op_types = (op1.type != IMMEDIATE) << 1
> + | (op2.type != IMMEDIATE);
> +
> + /* Find bit width of the two operands, if at least one is 64 bit use a */
> + /* 64bit operation, eventually extend 32bit operands. */
This is duplicated elsewhere (e.g., gen_bin_op) - should be pulled into a
single function.
> + bool op_is64bit = op1.bit_width == 64 || op2.bit_width == 64;
> + const char *bit_suffix = op_is64bit ? "i64" : "i32";
> + int bit_width = (op_is64bit) ? 64 : 32;
> + if (op_is64bit) {
> + switch (op_types) {
> + case IMM_IMM:
> + break;
> + case IMM_REG:
> + op2 = rvalue_extend(c, locp, &op2);
> + break;
> + case REG_IMM:
> + op1 = rvalue_extend(c, locp, &op1);
> + break;
> + case REG_REG:
> + op1 = rvalue_extend(c, locp, &op1);
> + op2 = rvalue_extend(c, locp, &op2);
> + break;
> + }
> + }
> +static void gen_mini_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> + HexValue *res, enum OpTypes op_types,
> + HexValue *op1_ptr, HexValue *op2_ptr)
> +{
> + HexValue op1 = *op1_ptr;
> + HexValue op2 = *op2_ptr;
> + const char *min = res->is_unsigned ? "tcg_gen_umin" : "tcg_gen_smin";
> + switch (op_types) {
> + case IMM_IMM:
> + OUT(c, locp, "int", &bit_width, "_t ", res, " = (", &op1, " <= ");
> + OUT(c, locp, &op2, ") ? ", &op1, " : ", &op2, ";\n");
> + break;
> + case IMM_REG:
> + op1.bit_width = bit_width;
> + op1 = rvalue_materialize(c, locp, &op1);
> + OUT(c, locp, min, "_i", &bit_width, "(");
> + OUT(c, locp, res, ", ", &op1, ", ", &op2, ");\n");
> + break;
> + case REG_IMM:
> + op2.bit_width = bit_width;
> + op2 = rvalue_materialize(c, locp, &op2);
> + /* Fallthrough */
> + case REG_REG:
> + OUT(c, locp, min, "_i", &bit_width, "(");
> + OUT(c, locp, res, ", ", &op1, ", ", &op2, ");\n");
> + break;
> + }
> + rvalue_free(c, locp, &op1);
> + rvalue_free(c, locp, &op2);
> +}
> +
> +static void gen_maxi_op(Context *c, YYLTYPE *locp, unsigned bit_width,
> + HexValue *res, enum OpTypes op_types,
> + HexValue *op1_ptr, HexValue *op2_ptr)
> +{
> + HexValue op1 = *op1_ptr;
> + HexValue op2 = *op2_ptr;
> + const char *min = res->is_unsigned ? "tcg_gen_umax" : "tcg_gen_smax";
> + switch (op_types) {
> + case IMM_IMM:
> + OUT(c, locp, "int", &bit_width, "_t ", res, " = (", &op1, " <= ");
> + OUT(c, locp, &op2, ") ? ", &op2, " : ", &op1, ";\n");
> + break;
> + case IMM_REG:
> + op1.bit_width = bit_width;
> + op1 = rvalue_materialize(c, locp, &op1);
> + OUT(c, locp, min, "_i", &bit_width, "(");
> + OUT(c, locp, res, ", ", &op1, ", ", &op2, ");\n");
> + break;
> + case REG_IMM:
> + op2.bit_width = bit_width;
> + op2 = rvalue_materialize(c, locp, &op2);
> + /* Fallthrough */
> + case REG_REG:
> + OUT(c, locp, min, "_i", &bit_width, "(");
> + OUT(c, locp, res, ", ", &op1, ", ", &op2, ");\n");
> + break;
> + }
> + rvalue_free(c, locp, &op1);
> + rvalue_free(c, locp, &op2);
> +}
These two look basically the same, create a single function with one extra are
indicating min/max.
> +HexValue gen_cast_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *source,
> + unsigned target_width) {
Don't you need to worry about signed-ness of the result?
> + if (source->bit_width == target_width) {
> + return *source;
> + } else if (source->type == IMMEDIATE) {
> + HexValue res = *source;
> + res.bit_width = target_width;
> + return res;
> + } else {
> + HexValue res = gen_tmp(c, locp, target_width);
> + /* Truncate */
> + if (source->bit_width > target_width) {
> + OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", source,
> ");\n");
> + } else {
> + if (source->is_unsigned) {
> + /* Extend unsigned */
> + OUT(c, locp, "tcg_gen_extu_i32_i64(",
> + &res, ", ", source, ");\n");
> + } else {
> + /* Extend signed */
> + OUT(c, locp, "tcg_gen_ext_i32_i64(",
> + &res, ", ", source, ");\n");
> + }
> + }
> + rvalue_free(c, locp, source);
> + return res;
> + }
> +}
> +
> +HexValue gen_extend_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *src_width_ptr,
> + HexValue *dst_width_ptr,
> + HexValue *value_ptr,
> + bool is_unsigned) {
> + HexValue src_width = *src_width_ptr;
> + HexValue dst_width = *dst_width_ptr;
> + HexValue value = *value_ptr;
> + src_width = rvalue_extend(c, locp, &src_width);
> + value = rvalue_extend(c, locp, &value);
> + src_width = rvalue_materialize(c, locp, &src_width);
> + value = rvalue_materialize(c, locp, &value);
> +
> + HexValue res = gen_tmp(c, locp, 64);
> + HexValue shift = gen_tmp_value(c, locp, "64", 64);
> + HexValue zero = gen_tmp_value(c, locp, "0", 64);
> + OUT(c, locp, "tcg_gen_sub_i64(",
> + &shift, ", ", &shift, ", ", &src_width, ");\n");
> + if (is_unsigned) {
> + HexValue mask = gen_tmp_value(c, locp, "0xffffffffffffffff", 64);
> + OUT(c, locp, "tcg_gen_shr_i64(",
> + &mask, ", ", &mask, ", ", &shift, ");\n");
> + OUT(c, locp, "tcg_gen_and_i64(",
> + &res, ", ", &value, ", ", &mask, ");\n");
> + rvalue_free(c, locp, &mask);
Can't you do this with tcg_gen_extract?
> + } else {
> + OUT(c, locp, "tcg_gen_shl_i64(",
> + &res, ", ", &value, ", ", &shift, ");\n");
> + OUT(c, locp, "tcg_gen_sar_i64(",
> + &res, ", ", &res, ", ", &shift, ");\n");
Can't you do this with get_gen_sectract?
> + }
> + OUT(c, locp, "tcg_gen_movcond_i64(TCG_COND_EQ, ", &res, ", ");
> + OUT(c, locp, &src_width, ", ", &zero, ", ", &zero, ", ", &res, ");\n");
> +
> + rvalue_free(c, locp, &src_width);
> + rvalue_free(c, locp, &dst_width);
> + rvalue_free(c, locp, &value);
> + rvalue_free(c, locp, &shift);
> + rvalue_free(c, locp, &zero);
> +
> + res.is_unsigned = is_unsigned;
> + return res;
> +}
> +
> +void gen_rdeposit_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *dest,
> + HexValue *value,
> + HexValue *begin,
> + HexValue *width)
> +{
> + HexValue dest_m = *dest;
> + dest_m.is_manual = true;
> +
> + HexValue value_m = rvalue_extend(c, locp, value);
> + HexValue begin_m = rvalue_extend(c, locp, begin);
> + HexValue width_orig = *width;
> + width_orig.is_manual = true;
> + HexValue width_m = rvalue_extend(c, locp, &width_orig);
> + width_m = rvalue_materialize(c, locp, &width_m);
> +
> + HexValue mask = gen_tmp_value(c, locp, "0xffffffffffffffffUL", 64);
> + mask.is_unsigned = true;
> + HexValue k64 = gen_tmp_value(c, locp, "64", 64);
> + k64 = gen_bin_op(c, locp, SUB_OP, &k64, &width_m);
> + mask = gen_bin_op(c, locp, LSR_OP, &mask, &k64);
> + begin_m.is_manual = true;
> + mask = gen_bin_op(c, locp, ASL_OP, &mask, &begin_m);
> + mask.is_manual = true;
> + value_m = gen_bin_op(c, locp, ASL_OP, &value_m, &begin_m);
> + value_m = gen_bin_op(c, locp, ANDB_OP, &value_m, &mask);
> +
> + OUT(c, locp, "tcg_gen_not_i64(", &mask, ", ", &mask, ");\n");
> + mask.is_manual = false;
> + HexValue res = gen_bin_op(c, locp, ANDB_OP, &dest_m, &mask);
> + res = gen_bin_op(c, locp, ORB_OP, &res, &value_m);
> +
Can't you do this with tcg_gen_deposit?
> + if (dest->bit_width != res.bit_width) {
> + res = rvalue_truncate(c, locp, &res);
> + }
> +
> + HexValue zero = gen_tmp_value(c, locp, "0", res.bit_width);
> + OUT(c, locp, "tcg_gen_movcond_i", &res.bit_width, "(TCG_COND_NE, ",
> dest);
> + OUT(c, locp, ", ", &width_orig, ", ", &zero, ", ", &res, ", ", dest,
> + ");\n");
> +
> + rvalue_free(c, locp, &zero);
> + rvalue_free(c, locp, width);
> + rvalue_free(c, locp, &res);
> +}
> +
> +void gen_deposit_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *dest,
> + HexValue *value,
> + HexValue *index,
> + HexCast *cast)
What's the difference between this and the gen_rdeposit_op above?
> +{
> + yyassert(c, locp, index->type == IMMEDIATE,
> + "Deposit index must be immediate!\n");
> + HexValue value_m = *value;
> + int bit_width = (dest->bit_width == 64) ? 64 : 32;
> + int width = cast->bit_width;
> + /* If the destination value is 32, truncate the value, otherwise extend
> */
> + if (dest->bit_width != value->bit_width) {
> + if (bit_width == 32) {
> + value_m = rvalue_truncate(c, locp, &value_m);
> + } else {
> + value_m = rvalue_extend(c, locp, &value_m);
> + }
> + }
> + value_m = rvalue_materialize(c, locp, &value_m);
> + OUT(c, locp, "tcg_gen_deposit_i", &bit_width, "(", dest, ", ", dest, ",
> ");
> + OUT(c, locp, &value_m, ", ", index, " * ", &width, ", ", &width, ");\n");
> + rvalue_free(c, locp, index);
> + rvalue_free(c, locp, &value_m);
> +}
> +
> +HexValue gen_rextract_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *source,
> + int begin,
> + int width) {
> + int bit_width = (source->bit_width == 64) ? 64 : 32;
> + HexValue res = gen_tmp(c, locp, bit_width);
> + OUT(c, locp, "tcg_gen_extract_i", &bit_width, "(", &res);
> + OUT(c, locp, ", ", source, ", ", &begin, ", ", &width, ");\n");
> + rvalue_free(c, locp, source);
> + return res;
> +}
> +
> +HexValue gen_extract_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *source,
> + HexValue *index,
> + HexExtract *extract) {
What's the difference between this ant the gen_rextract_op above?
> + yyassert(c, locp, index->type == IMMEDIATE,
> + "Extract index must be immediate!\n");
> + int bit_width = (source->bit_width == 64) ? 64 : 32;
> + const char *sign_prefix = (extract->is_unsigned) ? "" : "s";
> + int width = extract->bit_width;
> + HexValue res = gen_tmp(c, locp, bit_width);
> + res.is_unsigned = extract->is_unsigned;
> + OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &bit_width,
> + "(", &res, ", ", source);
> + OUT(c, locp, ", ", index, " * ", &width, ", ", &width, ");\n");
> +
> + /* Some extract operations have bit_width != storage_bit_width */
> + if (extract->storage_bit_width > bit_width) {
> + HexValue tmp = gen_tmp(c, locp, extract->storage_bit_width);
> + tmp.is_unsigned = extract->is_unsigned;
> + if (extract->is_unsigned) {
> + /* Extend unsigned */
> + OUT(c, locp, "tcg_gen_extu_i32_i64(",
> + &tmp, ", ", &res, ");\n");
> + } else {
> + /* Extend signed */
> + OUT(c, locp, "tcg_gen_ext_i32_i64(",
> + &tmp, ", ", &res, ");\n");
> + }
> + rvalue_free(c, locp, &res);
> + res = tmp;
> + }
> +
> + rvalue_free(c, locp, source);
> + rvalue_free(c, locp, index);
> + return res;
> +}
> +
> +HexValue gen_read_creg(Context *c, YYLTYPE *locp, HexValue *reg)
> +{
> + yyassert(c, locp, reg->type == REGISTER, "reg must be a register!");
> + if (reg->reg.id < 'a') {
What is this check telling us?
> + HexValue tmp = gen_tmp_value(c, locp, "0", 32);
> + const char *id = creg_str[(uint8_t)reg->reg.id];
> + OUT(c, locp, "READ_REG(", &tmp, ", ", id, ");\n");
Change READ_REG to gen_read_reg - that's what the macro is.
> + rvalue_free(c, locp, reg);
> + return tmp;
> + }
> + return *reg;
> +}
> +
> +/* Circular addressing mode with auto-increment */
> +void gen_circ_op(Context *c,
> + YYLTYPE *locp,
> + HexValue *addr,
> + HexValue *increment,
> + HexValue *modifier) {
> + HexValue increment_m = *increment;
> + HexValue cs = gen_tmp(c, locp, 32);
> + increment_m = rvalue_materialize(c, locp, &increment_m);
> + OUT(c, locp, "READ_REG(", &cs, ", HEX_REG_CS0 + MuN);\n");
Change READ_REG to gen_read_reg
> + OUT(c,
> + locp,
> + "gen_helper_fcircadd(",
> + addr,
> + ", ",
> + addr,
> + ", ",
> + &increment_m,
> + ", ",
> + modifier);
> + OUT(c, locp, ", ", &cs, ");\n");
> + rvalue_free(c, locp, &increment_m);
> + rvalue_free(c, locp, modifier);
> + rvalue_free(c, locp, &cs);
> +}
> +void gen_load(Context *c, YYLTYPE *locp, HexValue *num, HexValue *size,
> + bool is_unsigned, HexValue *ea, HexValue *dst)
> +{
> + /* Memop width is specified in the load macro */
> + int bit_width = (size->imm.value > 4) ? 64 : 32;
> + const char *sign_suffix = (size->imm.value > 4)
> + ? ""
> + : ((is_unsigned) ? "u" : "s");
> + char size_suffix[4] = { 0 };
> + /* Create temporary variable (if not present) */
> + if (dst->type == VARID) {
> + /* TODO: this is a common pattern, the parser should be varid-aware.
> */
> + varid_allocate(c, locp, dst, bit_width, is_unsigned);
> + }
> + snprintf(size_suffix, 4, "%" PRIu64, size->imm.value * 8);
> + if (bit_width == 32) {
> + *dst = rvalue_truncate(c, locp, dst);
> + } else {
> + *dst = rvalue_extend(c, locp, dst);
> + }
Why is the truncate/extend needed for the destination?
> + int var_id = find_variable(c, locp, ea);
> + yyassert(c, locp, var_id != -1, "Load variable must exist!\n");
> + /* We need to enforce the variable size */
> + ea->bit_width = g_array_index(c->inst.allocated, Var, var_id).bit_width;
> + if (ea->bit_width != 32) {
> + *ea = rvalue_truncate(c, locp, ea);
> + }
> + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
> + OUT(c, locp, "process_store(ctx, pkt, 1);\n");
Indent
> + OUT(c, locp, "}\n");
> + OUT(c, locp, "tcg_gen_qemu_ld", size_suffix, sign_suffix);
> + OUT(c, locp, "(", dst, ", ", ea, ", 0);\n");
> + /* If the var in EA was truncated it is now a tmp HexValue, so free it.
> */
> + rvalue_free(c, locp, ea);
> +}
> +
> +void gen_store(Context *c, YYLTYPE *locp, HexValue *num, HexValue
> *size,
> + HexValue *ea, HexValue *src)
> +{
> + /* Memop width is specified in the store macro */
> + int mem_width = size->imm.value;
> + /* Adjust operand bit width to memop bit width */
> + if (mem_width < 8) {
> + *src = rvalue_truncate(c, locp, src);
> + } else {
> + *src = rvalue_extend(c, locp, src);
> + }
Why is this needed?
> + assert(ea->type == VARID);
> + int var_id = find_variable(c, locp, ea);
> + yyassert(c, locp, var_id != -1, "Load variable must exist!\n");
> + /* We need to enforce the variable size */
> + ea->bit_width = g_array_index(c->inst.allocated, Var, var_id).bit_width;
> + if (ea->bit_width != 32) {
> + *ea = rvalue_truncate(c, locp, ea);
> + }
How can ea be not 32 bits?
> + *src = rvalue_materialize(c, locp, src);
> + OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", src);
> + OUT(c, locp, ", ctx, insn->slot);\n");
> + rvalue_free(c, locp, src);
> + /* If the var in ea was truncated it is now a tmp HexValue, so free it.
> */
> + rvalue_free(c, locp, ea);
> +}
> +
> +void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo,
> + HexValue *dst, HexValue *val)
> +{
> + yyassert(c, locp, hi->type == IMMEDIATE &&
> + hi->imm.type == VALUE &&
> + lo->type == IMMEDIATE &&
> + lo->imm.type == VALUE,
> + "Range deposit needs immediate values!\n");
> +
> + *val = rvalue_truncate(c, locp, val);
> + unsigned len = hi->imm.value + 1 - lo->imm.value;
> + HexValue tmp = gen_tmp(c, locp, 32);
> + OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", val, ");\n");
> + OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst, ", ", &tmp, ", ");
> + OUT(c, locp, lo, ", ", &len, ");\n");
This doesn't match the C semantics of fSETBITS
#define fSETBIT(N, DST, VAL) \
do { \
DST = (DST & ~(1ULL << (N))) | (((uint64_t)(VAL)) << (N)); \
} while (0)
#define fGETBIT(N, SRC) (((SRC) >> N) & 1)
#define fSETBITS(HI, LO, DST, VAL) \
do { \
int j; \
for (j = LO; j <= HI; j++) { \
fSETBIT(j, DST, VAL); \
} \
} while (0)
You need to put len copies of LSB(val), so emit something like this
TCGv zero = tcg_const_tl(0);
TCGv ones = tcg_const_tl(~0);
tcg_gen_andi_tl(tmp, val, 1);
tcg_gen_movcond_tl(TCG_COND_NE, tmp, tmp, zero, ones, zero);
tcg_gen_deposit_tl(dst, dst, tmp, lo, len);
tcg_temp_free(zero);
tcg_temp_free(ones);
> +HexValue gen_rvalue_pow(Context *c, YYLTYPE *locp, HexValue *l,
> HexValue *r)
Which instruction calls this? I don't think there is one. If not, remove the
POW token from the lexer and the associated rules from the parser.
> +HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *v)
> +{
> + const char *bit_suffix = (v->bit_width == 64) ? "i64" : "i32";
> + int bit_width = (v->bit_width == 64) ? 64 : 32;
> + HexValue res;
> + res.is_unsigned = v->is_unsigned;
> + res.is_dotnew = false;
> + res.is_manual = false;
> + if (v->type == IMMEDIATE) {
> + res.type = IMMEDIATE;
> + res.imm.type = QEMU_TMP;
> + res.imm.index = c->inst.qemu_tmp_count;
> + OUT(c, locp, "int", &bit_width, "_t ", &res, " = abs(", v, ");\n");
> + c->inst.qemu_tmp_count++;
> + } else {
> + res = gen_tmp(c, locp, bit_width);
> + HexValue zero = gen_tmp_value(c, locp, "0", bit_width);
> + OUT(c, locp, "tcg_gen_neg_", bit_suffix, "(", &res, ", ", v, ");\n");
> + OUT(c, locp, "tcg_gen_movcond_i", &bit_width);
> + OUT(c, locp, "(TCG_COND_GT, ", &res, ", ", v, ", ", &zero);
tcg_gen_abs_i<bit_width>
> + OUT(c, locp, ", ", v, ", ", &res, ");\n");
> + rvalue_free(c, locp, &zero);
> + rvalue_free(c, locp, v);
> + }
> + return res;
> +}
> +
> +HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *v)
> +{
> + yyassert(c, locp, v->bit_width <= 32,
> + "fbrev not implemented for 64-bit integers!");
> + HexValue res = gen_tmp(c, locp, v->bit_width);
> + *v = rvalue_materialize(c, locp, v);
> + OUT(c, locp, "gen_fbrev(", &res, ", ", v, ");\n");
gen_helper_fbrev
> diff --git a/target/hexagon/idef-parser/parser-helpers.h
> b/target/hexagon/idef-parser/parser-helpers.h
> new file mode 100644
> +#define OUT(c, locp, ...) FOR_EACH((c), (locp), OUT_IMPL, __VA_ARGS__)
You should be able to handle indenting here. Unfortunately, many of the C
statements generated use multiple OUT invocations.
Create two macros
OUT prints indentation, then the text
used for beginning a line of output
OUT_CONTINUE just print the text
used for continuing a line
> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index 329219463f..a2257d41a5 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -183,7 +183,7 @@ idef_parser_input_generated = custom_target(
> command: [python, files('gen_idef_parser_funcs.py'),
> semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'],
> )
>
> -idef_parser_input_generated_prep = custom_target(
> +preprocessed_idef_parser_input_generated = custom_target(
Don't change the name of this here, use the name you want in the patch where it
was introduced.