OP_XCHG,
OP_NOT,
OP_CDQ,
+ OP_LODS,
OP_STOS,
OP_MOVS,
OP_CMPS,
OP_CALL,
OP_JMP,
OP_JECXZ,
- OP_JO,
- OP_JNO,
- OP_JC,
- OP_JNC,
- OP_JZ,
- OP_JNZ,
- OP_JBE,
- OP_JA,
- OP_JS,
- OP_JNS,
- OP_JP,
- OP_JNP,
- OP_JL,
- OP_JGE,
- OP_JLE,
- OP_JG,
+ OP_JCC,
+ OP_SCC,
};
enum opr_type {
enum op_op op;
struct parsed_opr operand[MAX_OPERANDS];
unsigned int flags;
- int operand_cnt;
+ unsigned char pfo;
+ unsigned char pfo_inv;
+ unsigned char operand_cnt;
+ unsigned char pad;
int regmask_src; // all referensed regs
int regmask_dst;
int pfomask; // flagop: parsed_flag_op that can't be delayed
int cc_scratch; // scratch storage during analysis
int bt_i; // branch target for branches
struct parsed_data *btj;// branch targets for jumptables
+ struct parsed_proto *pp;
void *datap;
};
// datap:
-// OP_CALL - parser proto hint (str), ptr to struct parsed_proto
+// OP_CALL - parser proto hint (str)
// (OPF_CC) - point to one of (OPF_FLAGS) that affects cc op
// OP_POP - point to OP_PUSH in push/pop pair
static const struct {
const char *name;
enum op_op op;
- unsigned int minopr;
- unsigned int maxopr;
+ unsigned short minopr;
+ unsigned short maxopr;
unsigned int flags;
+ unsigned char pfo;
+ unsigned char pfo_inv;
} op_table[] = {
{ "nop", OP_NOP, 0, 0, 0 },
{ "push", OP_PUSH, 1, 1, 0 },
{ "xchg", OP_XCHG, 2, 2, OPF_DATA },
{ "not", OP_NOT, 1, 1, OPF_DATA },
{ "cdq", OP_CDQ, 0, 0, OPF_DATA },
+ { "lodsb",OP_LODS, 0, 0, OPF_DATA },
+ { "lodsw",OP_LODS, 0, 0, OPF_DATA },
+ { "lodsd",OP_LODS, 0, 0, OPF_DATA },
{ "stosb",OP_STOS, 0, 0, OPF_DATA },
{ "stosw",OP_STOS, 0, 0, OPF_DATA },
{ "stosd",OP_STOS, 0, 0, OPF_DATA },
{ "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
{ "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
{ "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
- { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
- { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
- { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
- { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
+ { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
+ { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
+ { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
+ { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
{ "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
{ "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
{ "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
{ "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
{ "jmp", OP_JMP, 1, 1, OPF_JMP },
{ "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
- { "jo", OP_JO, 1, 1, OPF_CJMP_CC }, // 70 OF=1
- { "jno", OP_JNO, 1, 1, OPF_CJMP_CC }, // 71 OF=0
- { "jc", OP_JC, 1, 1, OPF_CJMP_CC }, // 72 CF=1
- { "jb", OP_JC, 1, 1, OPF_CJMP_CC }, // 72
- { "jnc", OP_JNC, 1, 1, OPF_CJMP_CC }, // 73 CF=0
- { "jnb", OP_JNC, 1, 1, OPF_CJMP_CC }, // 73
- { "jae", OP_JNC, 1, 1, OPF_CJMP_CC }, // 73
- { "jz", OP_JZ, 1, 1, OPF_CJMP_CC }, // 74 ZF=1
- { "je", OP_JZ, 1, 1, OPF_CJMP_CC }, // 74
- { "jnz", OP_JNZ, 1, 1, OPF_CJMP_CC }, // 75 ZF=0
- { "jne", OP_JNZ, 1, 1, OPF_CJMP_CC }, // 75
- { "jbe", OP_JBE, 1, 1, OPF_CJMP_CC }, // 76 CF=1 || ZF=1
- { "jna", OP_JBE, 1, 1, OPF_CJMP_CC }, // 76
- { "ja", OP_JA, 1, 1, OPF_CJMP_CC }, // 77 CF=0 && ZF=0
- { "jnbe", OP_JA, 1, 1, OPF_CJMP_CC }, // 77
- { "js", OP_JS, 1, 1, OPF_CJMP_CC }, // 78 SF=1
- { "jns", OP_JNS, 1, 1, OPF_CJMP_CC }, // 79 SF=0
- { "jp", OP_JP, 1, 1, OPF_CJMP_CC }, // 7a PF=1
- { "jpe", OP_JP, 1, 1, OPF_CJMP_CC }, // 7a
- { "jnp", OP_JNP, 1, 1, OPF_CJMP_CC }, // 7b PF=0
- { "jpo", OP_JNP, 1, 1, OPF_CJMP_CC }, // 7b
- { "jl", OP_JL, 1, 1, OPF_CJMP_CC }, // 7c SF!=OF
- { "jnge", OP_JL, 1, 1, OPF_CJMP_CC }, // 7c
- { "jge", OP_JGE, 1, 1, OPF_CJMP_CC }, // 7d SF=OF
- { "jnl", OP_JGE, 1, 1, OPF_CJMP_CC }, // 7d
- { "jle", OP_JLE, 1, 1, OPF_CJMP_CC }, // 7e ZF=1 || SF!=OF
- { "jng", OP_JLE, 1, 1, OPF_CJMP_CC }, // 7e
- { "jg", OP_JG, 1, 1, OPF_CJMP_CC }, // 7f ZF=0 && SF=OF
- { "jnle", OP_JG, 1, 1, OPF_CJMP_CC }, // 7f
- { "seto", OP_JO, 1, 1, OPF_DATA|OPF_CC },
- { "setno", OP_JNO, 1, 1, OPF_DATA|OPF_CC },
- { "setc", OP_JC, 1, 1, OPF_DATA|OPF_CC },
- { "setb", OP_JC, 1, 1, OPF_DATA|OPF_CC },
- { "setnc", OP_JNC, 1, 1, OPF_DATA|OPF_CC },
- { "setae", OP_JNC, 1, 1, OPF_DATA|OPF_CC },
- { "setz", OP_JZ, 1, 1, OPF_DATA|OPF_CC },
- { "sete", OP_JZ, 1, 1, OPF_DATA|OPF_CC },
- { "setnz", OP_JNZ, 1, 1, OPF_DATA|OPF_CC },
- { "setne", OP_JNZ, 1, 1, OPF_DATA|OPF_CC },
- { "setbe", OP_JBE, 1, 1, OPF_DATA|OPF_CC },
- { "setna", OP_JBE, 1, 1, OPF_DATA|OPF_CC },
- { "seta", OP_JA, 1, 1, OPF_DATA|OPF_CC },
- { "setnbe", OP_JA, 1, 1, OPF_DATA|OPF_CC },
- { "sets", OP_JS, 1, 1, OPF_DATA|OPF_CC },
- { "setns", OP_JNS, 1, 1, OPF_DATA|OPF_CC },
- { "setp", OP_JP, 1, 1, OPF_DATA|OPF_CC },
- { "setpe", OP_JP, 1, 1, OPF_DATA|OPF_CC },
- { "setnp", OP_JNP, 1, 1, OPF_DATA|OPF_CC },
- { "setpo", OP_JNP, 1, 1, OPF_DATA|OPF_CC },
- { "setl", OP_JL, 1, 1, OPF_DATA|OPF_CC },
- { "setnge", OP_JL, 1, 1, OPF_DATA|OPF_CC },
- { "setge", OP_JGE, 1, 1, OPF_DATA|OPF_CC },
- { "setnl", OP_JGE, 1, 1, OPF_DATA|OPF_CC },
- { "setle", OP_JLE, 1, 1, OPF_DATA|OPF_CC },
- { "setng", OP_JLE, 1, 1, OPF_DATA|OPF_CC },
- { "setg", OP_JG, 1, 1, OPF_DATA|OPF_CC },
- { "setnle", OP_JG, 1, 1, OPF_DATA|OPF_CC },
+ { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
+ { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
+ { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
+ { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
+ { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
+ { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
+ { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
+ { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
+ { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
+ { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
+ { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
+ { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
+ { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
+ { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
+ { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
+ { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
+ { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
+ { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
+ { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
+ { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
+ { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
+ { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
+ { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
+ { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
+ { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
+ { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
+ { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
+ { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
+ { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
+ { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
+ { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
+ { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
+ { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
+ { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
+ { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
+ { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
+ { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
+ { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
+ { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
+ { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
+ { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
+ { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
+ { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
+ { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
+ { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
+ { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
+ { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
+ { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
+ { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
+ { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
+ { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
+ { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
+ { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
+ { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
+ { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
+ { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
+ { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
+ { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
};
static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
op->op = op_table[i].op;
op->flags = op_table[i].flags | prefix_flags;
+ op->pfo = op_table[i].pfo;
+ op->pfo_inv = op_table[i].pfo_inv;
op->regmask_src = op->regmask_dst = 0;
for (opr = 0; opr < op_table[i].minopr; opr++) {
setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
break;
+ case OP_LODS:
case OP_STOS:
case OP_SCAS:
if (op->operand_cnt != 0)
else if (words[op_w][4] == 'd')
lmod = OPLM_DWORD;
op->operand_cnt = 3;
- setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
+ setup_reg_opr(&op->operand[0], op->op == OP_LODS ? xSI : xDI,
+ lmod, &op->regmask_src);
setup_reg_opr(&op->operand[1], xCX, OPLM_DWORD, &op->regmask_src);
op->regmask_dst = op->regmask_src;
- setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD, &op->regmask_src);
+ setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD,
+ op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
break;
case OP_MOVS:
case OP_XCHG:
op->regmask_src |= op->regmask_dst;
op->regmask_dst |= op->regmask_src;
- break;
+ goto check_align;
case OP_JECXZ:
op->operand_cnt = 1;
// alignment
case OP_MOV:
+ check_align:
if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
- && op->operand[0].reg == xDI && op->operand[1].reg == xDI)
+ && op->operand[0].lmod == op->operand[1].lmod
+ && op->operand[0].reg == op->operand[1].reg
+ && IS(op->operand[0].name, op->operand[1].name)) // ah, al..
{
op->flags |= OPF_RMD;
+ op->regmask_src = op->regmask_dst = 0;
}
break;
}
}
-static const char *op_name(enum op_op op)
+static const char *op_name(struct parsed_op *po)
{
+ static char buf[16];
+ char *p;
int i;
+ if (po->op == OP_JCC || po->op == OP_SCC) {
+ p = buf;
+ *p++ = (po->op == OP_JCC) ? 'j' : 's';
+ if (po->pfo_inv)
+ *p++ = 'n';
+ strcpy(p, parsed_flag_op_names[po->pfo]);
+ return buf;
+ }
+
for (i = 0; i < ARRAY_SIZE(op_table); i++)
- if (op_table[i].op == op)
+ if (op_table[i].op == po->op)
return op_table[i].name;
return "???";
if (po == NULL)
return "???";
- snprintf(out, sizeof(out), "%s", op_name(po->op));
+ snprintf(out, sizeof(out), "%s", op_name(po));
for (i = 0; i < po->operand_cnt; i++) {
p += strlen(p);
if (i > 0)
return out_src_opr(buf, buf_size, po, popr, NULL, 0);
}
-static enum parsed_flag_op split_cond(struct parsed_op *po,
- enum op_op op, int *is_inv)
-{
- *is_inv = 0;
-
- switch (op) {
- case OP_JO:
- return PFO_O;
- case OP_JC:
- return PFO_C;
- case OP_JZ:
- return PFO_Z;
- case OP_JBE:
- return PFO_BE;
- case OP_JS:
- return PFO_S;
- case OP_JP:
- return PFO_P;
- case OP_JL:
- return PFO_L;
- case OP_JLE:
- return PFO_LE;
-
- case OP_JNO:
- *is_inv = 1;
- return PFO_O;
- case OP_JNC:
- *is_inv = 1;
- return PFO_C;
- case OP_JNZ:
- *is_inv = 1;
- return PFO_Z;
- case OP_JA:
- *is_inv = 1;
- return PFO_BE;
- case OP_JNS:
- *is_inv = 1;
- return PFO_S;
- case OP_JNP:
- *is_inv = 1;
- return PFO_P;
- case OP_JGE:
- *is_inv = 1;
- return PFO_L;
- case OP_JG:
- *is_inv = 1;
- return PFO_LE;
-
- case OP_RCL:
- case OP_RCR:
- case OP_ADC:
- case OP_SBB:
- return PFO_C;
-
- default:
- ferr(po, "split_cond: bad op %d\n", op);
- return -1;
- }
-}
-
static void out_test_for_cc(char *buf, size_t buf_size,
struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
enum opr_lenmod lmod, const char *expr)
// last op in stream - unconditional branch or ret
#define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
- || ((ops[_i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP \
+ || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
&& ops[_i].op != OP_CALL))
static int scan_for_pop(int i, int opcnt, const char *reg,
static int scan_for_esp_adjust(int i, int opcnt, int *adj,
int *multipath)
{
- const struct parsed_proto *pp;
struct parsed_op *po;
int first_pop = -1;
break;
if (po->operand[0].type != OPT_LABEL)
break;
- pp = po->datap;
- if (pp != NULL && pp->is_stdcall)
+ if (po->pp != NULL && po->pp->is_stdcall)
break;
}
}
if (pp->is_unresolved)
break;
- pp_tmp = ops[j].datap;
+ pp_tmp = ops[j].pp;
if (pp_tmp == NULL)
ferr(po, "arg collect hit unparsed call '%s'\n",
ops[j].operand[0].name);
struct parsed_proto *pp, *pp_tmp;
struct parsed_data *pd;
const char *tmpname;
- enum parsed_flag_op pfo;
unsigned int uval;
int save_arg_vars = 0;
int cond_vars = 0;
int depth = 0;
int no_output;
int i, j, l;
- int dummy;
int arg;
int reg;
int ret;
check_func_pp(po, pp, "fptr var call");
if (pp->is_noreturn)
po->flags |= OPF_TAIL;
- po->datap = pp;
}
+ po->pp = pp;
continue;
}
for (l = 0; l < opcnt; l++) {
if (g_labels[l][0] && IS(po->operand[0].name, g_labels[l])) {
+ if (l == i + 1 && po->op == OP_JMP) {
+ // yet another alignment type..
+ po->flags |= OPF_RMD;
+ break;
+ }
add_label_ref(&g_label_refs[l], i);
po->bt_i = l;
break;
}
}
- if (po->bt_i != -1)
+ if (po->bt_i != -1 || (po->flags & OPF_RMD))
continue;
if (po->operand[0].type == OPT_LABEL)
if (po->op == OP_CALL)
{
tmpname = opr_name(po, 0);
- pp = po->datap;
+ pp = po->pp;
if (pp == NULL)
{
// indirect call
for (arg = 0; arg < pp->argc; arg++)
pp->arg[arg].type.name = strdup("int");
}
- po->datap = pp;
+ po->pp = pp;
}
// look for and make use of esp adjust
if (cnt > ARRAY_SIZE(setters))
ferr(po, "too many flag setters\n");
- pfo = split_cond(po, po->op, &dummy);
for (j = 0; j < cnt; j++)
{
tmp_op = &ops[setters[j]]; // flag setter
if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
{
if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
- pfomask = 1 << pfo;
+ pfomask = 1 << po->pfo;
}
else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
- pfomask = 1 << pfo;
+ pfomask = 1 << po->pfo;
}
else {
// see if we'll be able to handle based on op result
if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
- && pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
+ && po->pfo != PFO_Z && po->pfo != PFO_S
+ && po->pfo != PFO_P)
|| branched
|| scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
- pfomask = 1 << pfo;
+ {
+ pfomask = 1 << po->pfo;
+ }
- if (tmp_op->op == OP_ADD && pfo == PFO_C)
+ if (tmp_op->op == OP_ADD && po->pfo == PFO_C)
need_tmp64 = 1;
}
if (pfomask) {
|| po->op == OP_ADC || po->op == OP_SBB)
cond_vars |= 1 << PFO_C;
}
- else if (po->op == OP_CMPS || po->op == OP_SCAS) {
+
+ if (po->op == OP_CMPS || po->op == OP_SCAS) {
cond_vars |= 1 << PFO_Z;
}
else if (po->op == OP_MUL
need_tmp64 = 1;
}
else if (po->op == OP_CALL) {
- pp = po->datap;
+ pp = po->pp;
if (pp == NULL)
ferr(po, "NULL pp\n");
// might be declared already
found = 0;
for (j = 0; j < i; j++) {
- if (ops[j].op == OP_CALL && (pp_tmp = ops[j].datap)) {
+ if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
found = 1;
break;
if (po->flags & OPF_CC)
{
int is_delayed = 0;
- int is_inv = 0;
- pfo = split_cond(po, po->op, &is_inv);
tmp_op = po->datap;
// we go through all this trouble to avoid using parsed_flag_op,
// which makes generated code much nicer
if (delayed_flag_op != NULL)
{
- out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_inv);
+ out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
+ po->pfo, po->pfo_inv);
is_delayed = 1;
}
else if (last_arith_dst != NULL
- && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P
+ && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
|| (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
))
{
out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
- out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
+ out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
last_arith_dst->lmod, buf3);
is_delayed = 1;
}
else if (tmp_op != NULL) {
// use preprocessed flag calc results
- if (!(tmp_op->pfomask & (1 << pfo)))
- ferr(po, "not prepared for pfo %d\n", pfo);
+ if (!(tmp_op->pfomask & (1 << po->pfo)))
+ ferr(po, "not prepared for pfo %d\n", po->pfo);
- // note: is_inv was not yet applied
+ // note: pfo_inv was not yet applied
snprintf(buf1, sizeof(buf1), "(%scond_%s)",
- is_inv ? "!" : "", parsed_flag_op_names[pfo]);
+ po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
}
else {
ferr(po, "all methods of finding comparison failed\n");
}
if (po->flags & OPF_JMP) {
- fprintf(fout, " if %s\n", buf1);
+ fprintf(fout, " if %s", buf1);
}
else if (po->op == OP_RCL || po->op == OP_RCR
|| po->op == OP_ADC || po->op == OP_SBB)
{
if (is_delayed)
fprintf(fout, " cond_%s = %s;\n",
- parsed_flag_op_names[pfo], buf1);
+ parsed_flag_op_names[po->pfo], buf1);
}
else if (po->flags & OPF_DATA) { // SETcc
out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
strcpy(g_comment, "cdq");
break;
+ case OP_LODS:
+ assert_operand_cnt(3);
+ if (po->flags & OPF_REP) {
+ // hmh..
+ ferr(po, "TODO\n");
+ }
+ else {
+ fprintf(fout, " eax = %sedi; esi %c= %d;",
+ lmod_cast_u_ptr(po, po->operand[0].lmod),
+ (po->flags & OPF_DF) ? '-' : '+',
+ lmod_bytes(po, po->operand[0].lmod));
+ strcpy(g_comment, "lods");
+ }
+ break;
+
case OP_STOS:
assert_operand_cnt(3);
if (po->flags & OPF_REP) {
strcpy(g_comment, "rep stos");
}
else {
- fprintf(fout, " %sedi = eax; edi %c= %d;",
+ fprintf(fout, " %sedi = eax; edi %c= %d;",
lmod_cast_u_ptr(po, po->operand[0].lmod),
(po->flags & OPF_DF) ? '-' : '+',
lmod_bytes(po, po->operand[0].lmod));
strcpy(g_comment, "rep movs");
}
else {
- fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
+ fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
buf1, buf1, l, j, l, j);
strcpy(g_comment, "movs");
}
}
else {
fprintf(fout,
- " cond_z = (%sedi = %sesi); edi %c= %d; esi %c= %d;",
+ " cond_z = (%sedi = %sesi); edi %c= %d; esi %c= %d;",
buf1, buf1, l, j, l, j);
strcpy(g_comment, "cmps");
}
delayed_flag_op = po;
break;
+ case OP_SCC:
+ // SETcc - should already be handled
+ break;
+
// note: we reuse OP_Jcc for SETcc, only flags differ
- case OP_JO ... OP_JG:
- if (po->flags & OPF_JMP)
- fprintf(fout, " goto %s;", po->operand[0].name);
- // else SETcc - should already be handled
+ case OP_JCC:
+ fprintf(fout, "\n goto %s;", po->operand[0].name);
break;
case OP_JECXZ:
case OP_CALL:
assert_operand_cnt(1);
- pp = po->datap;
+ pp = po->pp;
my_assert_not(pp, NULL);
+ strcpy(buf3, " ");
+ if (po->flags & OPF_CC) {
+ // we treat conditional branch to another func
+ // (yes such code exists..) as conditional tailcall
+ strcat(buf3, " ");
+ fprintf(fout, " {\n");
+ }
+
if (pp->is_fptr && !pp->is_arg)
- fprintf(fout, " %s = %s;\n", pp->name,
+ fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
"(void *)", 0));
- fprintf(fout, " ");
+ fprintf(fout, "%s", buf3);
if (strstr(pp->ret_type.name, "int64")) {
if (po->flags & OPF_TAIL)
ferr(po, "int64 and tail?\n");
if (strstr(pp->ret_type.name, "int64")) {
fprintf(fout, "\n");
- fprintf(fout, " edx = tmp64 >> 32;\n");
- fprintf(fout, " eax = tmp64;");
+ fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
+ fprintf(fout, "%seax = tmp64;", buf3);
}
if (pp->is_unresolved) {
- snprintf(buf3, sizeof(buf3), " unresoved %dreg",
+ snprintf(buf2, sizeof(buf2), " unresoved %dreg",
pp->argc_reg);
- strcat(g_comment, buf3);
+ strcat(g_comment, buf2);
}
if (po->flags & OPF_TAIL) {
ferr(po, "int func -> void func tailcall?\n");
}
else {
- fprintf(fout, "\n return;");
+ fprintf(fout, "\n%sreturn;", buf3);
strcat(g_comment, " ^ tailcall");
}
}
strcat(g_comment, " noreturn");
if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
strcat(g_comment, " argframe");
+ if (po->flags & OPF_CC)
+ strcat(g_comment, " cond");
+
+ if (po->flags & OPF_CC)
+ fprintf(fout, "\n }");
+
delayed_flag_op = NULL;
last_arith_dst = NULL;
break;
g_label_refs[i].next = NULL;
if (ops[i].op == OP_CALL) {
- pp = ops[i].datap;
- if (pp)
- proto_release(pp);
+ if (ops[i].pp)
+ proto_release(ops[i].pp);
}
}
g_func_pp = NULL;