diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-08-23 16:43:08 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-11-01 00:40:57 +0100 |
| commit | 226b62bc2ee4779447ce788d83aa0b409e384ec8 (patch) | |
| tree | ace913c378dd4085c34112c9e8602a7b39f75c27 /simplify.c | |
| parent | 594c7389969f79919f1170693c970fb25b8bfe4d (diff) | |
| download | sparse-dev-226b62bc2ee4779447ce788d83aa0b409e384ec8.tar.gz | |
eval_insn: give an explicit type to compare's operands
The return type of IR instructions is stored in the field
::type of struct instruction and this struct has no space
to hold the type of the operand(s). This is not a problem
for most instructions because there is an easy way to get
the operands' type. For example, for binops both types
must be the same so they are used interchangeably.
However, for compare instructions both types can be different
and there is no easy way to get the type of the operands.
Currently, this is ignored and creates some errors. It
also blocks simplifications that need this type information.
But compares instructions need only 2 operands, there is
thus one 'slot' left. So, use this slot for the operands' type.
This solves the current errors, allows new simplifications
and has very little impact on existing code. Of course,
this type information needs now to be tracked and adjusted
whenever the operands change or an instruction is changed
into a compare.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'simplify.c')
| -rw-r--r-- | simplify.c | 14 |
1 files changed, 13 insertions, 1 deletions
@@ -635,6 +635,11 @@ static pseudo_t eval_op(int op, unsigned size, pseudo_t src1, pseudo_t src2) default: return NULL; } + + // Warning: this should be done with the output size which may + // be different than the input size used here. But it differs + // only for compares which are not concerned since only returning + // 0 or 1 and for casts which are not handled here. res &= bits; return value_pseudo(res); @@ -767,7 +772,11 @@ static int simplify_mask_shift(struct instruction *sh, unsigned long long mask) static pseudo_t eval_insn(struct instruction *insn) { - return eval_op(insn->opcode, insn->size, insn->src1, insn->src2); + unsigned size = insn->size; + + if (opcode_table[insn->opcode].flags & OPF_COMPARE) + size = insn->itype->bit_size; + return eval_op(insn->opcode, size, insn->src1, insn->src2); } static long long check_shift_count(struct instruction *insn, unsigned long long uval) @@ -1009,6 +1018,7 @@ static int simplify_seteq_setne(struct instruction *insn, long long value) // setcc.m %r <- %a, $b // and similar for setne/eq ... 0/1 insn->opcode = inverse ? opcode_table[opcode].negate : opcode; + insn->itype = def->itype; use_pseudo(insn, def->src1, &insn->src1); use_pseudo(insn, def->src2, &insn->src2); remove_usage(old, &insn->src1); @@ -1025,6 +1035,7 @@ static int simplify_seteq_setne(struct instruction *insn, long long value) // into: // setne.1 %s <- %a, $0 // and same for setne/eq ... 0/1 + insn->itype = def->orig_type; return replace_pseudo(insn, &insn->src1, def->src); case OP_TRUNC: if (!one_use(old)) @@ -1671,6 +1682,7 @@ static int simplify_cast(struct instruction *insn) // setcc.m %r <- %a, %b // and same for s/zext/trunc/ insn->opcode = def->opcode; + insn->itype = def->itype; use_pseudo(insn, def->src2, &insn->src2); return replace_pseudo(insn, &insn->src1, def->src1); } |
