[qfcc] Take memset/move size into account for use/def

This fixed the bogus uninitialized variable working in b648c353f
This commit is contained in:
Bill Currie 2023-09-11 00:37:53 +09:00
parent b648c353ff
commit c066e638e5
3 changed files with 79 additions and 49 deletions

View file

@ -257,15 +257,6 @@ void initialize_def (struct symbol_s *sym,
struct expr_s *init, struct defspace_s *space,
storage_class_t storage, struct symtab_s *symtab);
/** Determine if two defs overlap.
\param d1 The first def to check. May be an alias def.
\param d2 The second def to check. May be an alias def.
\return 1 if the defs overlap, 2 if \a d1 fully overlaps \a d2,
otherwise 0.
*/
int def_overlap (def_t *d1, def_t *d2) __attribute__((pure));
/** Convenience function for obtaining a def's actual offset.
Takes care of an alias def's relative offset.
@ -317,6 +308,11 @@ int def_size (def_t *def) __attribute__((pure));
*/
int def_visit_all (def_t *def, int overlap,
int (*visit) (def_t *, void *), void *data);
int def_visit_overlaps (def_t *def, int offset, int size, int overlap,
def_t *skip,
int (*visit) (def_t *, void *), void *data);
///@}
#endif//__def_h

View file

@ -690,36 +690,16 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
sym->s.def->initializer = init;
}
int
def_overlap (def_t *d1, def_t *d2)
static int
def_overlap (def_t *d, int offset, int size)
{
int offs1, size1;
int offs2, size2;
defspace_t *s1 = d1->space;
defspace_t *s2 = d2->space;
int d_offset = d->offset;
int d_size = type_size (d->type);
if (d1->alias)
s1 = d1->alias->space;
if (d2->alias)
s2 = d2->alias->space;
/// Defs in different spaces never overlap.
if (s1 != s2)
return 0;
offs1 = d1->offset;
if (d1->alias)
offs1 += d1->alias->offset;
size1 = type_size (d1->type);
offs2 = d2->offset;
if (d2->alias)
offs2 += d2->alias->offset;
size2 = type_size (d2->type);
if (offs1 <= offs2 && offs1 + size1 >= offs2 + size2)
return 2; // d1 fully overlaps d2
if (offs1 < offs2 + size2 && offs2 < offs1 + size1)
return 1; // d1 and d2 at least partially overlap
if (d_offset >= offset && d_offset + d_size <= offset + size)
return 2; // d is fully overlapped by the range
if (d_offset < offset + size && offset < d_offset + d_size)
return 1; // d is partially overlapped by the range range
return 0;
}
@ -738,6 +718,23 @@ def_size (def_t *def)
return type_size (def->type);
}
int
def_visit_overlaps (def_t *def, int offset, int size, int overlap, def_t *skip,
int (*visit) (def_t *, void *), void *data)
{
int ret;
for (def = def->alias_defs; def; def = def->next) {
if (def == skip)
continue;
if (overlap && def_overlap (def, offset, size) < overlap)
continue;
if ((ret = visit (def, data)))
return ret;
}
return 0;
}
int
def_visit_all (def_t *def, int overlap,
int (*visit) (def_t *, void *), void *data)
@ -755,13 +752,8 @@ def_visit_all (def_t *def, int overlap,
} else {
overlap = 0;
}
for (def = def->alias_defs; def; def = def->next) {
if (def == start_def)
continue;
if (overlap && def_overlap (def, start_def) < overlap)
continue;
if ((ret = visit (def, data)))
return ret;
}
return 0;
int offset = start_def->offset;
int size = start_def->type ? type_size (start_def->type) : 0;
return def_visit_overlaps (def, offset, size, overlap, start_def,
visit, data);
}

View file

@ -835,6 +835,35 @@ flow_add_op_var (set_t *set, operand_t *op, int ol)
}
}
static void
flow_add_op_var_size (set_t *set, operand_t *op, int size, int ol)
{
flowvar_t *var;
if (!set)
return;
if (!(var = flow_get_var (op)))
return;
set_add (set, var->number);
if (op->op_type == op_temp) {
//bug (0, "temp op");
tempop_visit_all (&op->tempop, ol, flow_tempop_add_aliases, set);
} else if (op->op_type == op_def) {
def_t *def = op->def;
def_t *skip = def->alias ? def : 0;
int offset = def->alias ? def->offset : 0;
if (def->alias) {
def = def->alias;
}
if (size == -1) {
size = type_size (def->type) - offset;
}
def_visit_overlaps (def, offset, size, ol, skip,
flow_def_add_aliases, set);
}
}
static int
flowvar_def_add_use (def_t *def, void *data)
{
@ -1494,6 +1523,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
operand_t *operands[FLOW_OPERANDS])
{
int i, calln = -1;
int size;
operand_t *src_op = 0;
operand_t *res_op = 0;
operand_t *aux_op1 = 0;
@ -1566,19 +1596,31 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill,
flow_add_op_var (use, s->opa, 1);
flow_add_op_var (use, s->opb, 1);
aux_op1 = s->opb;
if (s->type != st_ptrassign && s->opb->op_type == op_value) {
if (is_short (s->opb->type)) {
size = s->opb->value->v.short_val;
} else if (is_int (s->opb->type)) {
size = s->opb->value->v.int_val;
} else {
print_type (s->opb->type);
internal_error (s->expr, "unexpected type for memset/move");
}
} else {
size = -1;
}
if (!strcmp (s->opcode, "move")
|| !strcmp (s->opcode, "memset")) {
flow_add_op_var (def, s->opc, 6);
flow_add_op_var_size (def, s->opc, size, 2);
src_op = s->opa;
res_op = s->opc;
} else if (!strcmp (s->opcode, "movep")) {
flow_add_op_var (use, s->opc, 6);
flow_add_op_var_size (use, s->opc, size, 2);
aux_op3 = flow_analyze_pointer_operand (s->opa, use);
res_op = flow_analyze_pointer_operand (s->opc, def);
src_op = s->opa;
aux_op2 = s->opc;
} else if (!strcmp (s->opcode, "memsetp")) {
flow_add_op_var (use, s->opc, 6);
flow_add_op_var_size (use, s->opc, size, 2);
res_op = flow_analyze_pointer_operand (s->opc, def);
src_op = s->opa;
aux_op2 = s->opc;