diff options
| -rw-r--r-- | Documentation/IR.rst | 1 | ||||
| -rw-r--r-- | linearize.c | 16 | ||||
| -rw-r--r-- | linearize.h | 4 | ||||
| -rw-r--r-- | simplify.c | 14 | ||||
| -rw-r--r-- | validation/optim/cmp-type0.c | 1 | ||||
| -rw-r--r-- | validation/optim/cmp-type1.c | 1 |
6 files changed, 30 insertions, 7 deletions
diff --git a/Documentation/IR.rst b/Documentation/IR.rst index ff5af1c5..6330ee9c 100644 --- a/Documentation/IR.rst +++ b/Documentation/IR.rst @@ -134,6 +134,7 @@ They all have the following signature: * .src1, .src2: operands (types must be compatible) * .target: result of the operation (0/1 valued integer) * .type: type of .target, must be an integral type + * .itype: type of the input operands .. op:: OP_SET_EQ Compare equal. diff --git a/linearize.c b/linearize.c index d9a3ac49..301a5d9e 100644 --- a/linearize.c +++ b/linearize.c @@ -1080,6 +1080,13 @@ static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int o return target; } +static pseudo_t add_cmp_op(struct entrypoint *ep, struct symbol *ctype, int op, struct symbol *itype, pseudo_t left, pseudo_t right) +{ + pseudo_t target = add_binary_op(ep, ctype, op, left, right); + target->def->itype = itype; + return target; +} + static pseudo_t add_setval(struct entrypoint *ep, struct symbol *ctype, struct expression *val) { struct instruction *insn = alloc_typed_instruction(OP_SETVAL, ctype); @@ -1217,7 +1224,7 @@ static pseudo_t linearize_regular_preop(struct entrypoint *ep, struct expression return pre; case '!': { pseudo_t zero = value_pseudo(0); - return add_binary_op(ep, ctype, OP_SET_EQ, pre, zero); + return add_cmp_op(ep, ctype, OP_SET_EQ, expr->unop->ctype, pre, zero); } case '~': return add_unop(ep, ctype, OP_NOT, pre); @@ -1444,7 +1451,7 @@ static inline pseudo_t add_convert_to_bool(struct entrypoint *ep, pseudo_t src, zero = value_pseudo(0); op = OP_SET_NE; } - return add_binary_op(ep, &bool_ctype, op, src, zero); + return add_cmp_op(ep, &bool_ctype, op, type, src, zero); } static pseudo_t linearize_expression_to_bool(struct entrypoint *ep, struct expression *expr) @@ -1773,10 +1780,11 @@ static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr [SPECIAL_UNSIGNED_LTE] = OP_SET_BE, [SPECIAL_UNSIGNED_GTE] = OP_SET_AE, }; - int op = opcode_float(cmpop[expr->op], expr->right->ctype); + struct symbol *itype = expr->right->ctype; + int op = opcode_float(cmpop[expr->op], itype); pseudo_t src1 = linearize_expression(ep, expr->left); pseudo_t src2 = linearize_expression(ep, expr->right); - pseudo_t dst = add_binary_op(ep, expr->ctype, op, src1, src2); + pseudo_t dst = add_cmp_op(ep, expr->ctype, op, itype, src1, src2); return dst; } diff --git a/linearize.h b/linearize.h index 57fe2035..77ae7c9a 100644 --- a/linearize.h +++ b/linearize.h @@ -123,6 +123,10 @@ struct instruction { struct /* binops and sel */ { pseudo_t src1, src2, src3; }; + struct /* compare */ { + pseudo_t _src1, _src2; // alias .src[12] + struct symbol *itype; // input operands' type + }; struct /* slice */ { pseudo_t base; unsigned from, len; @@ -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); } diff --git a/validation/optim/cmp-type0.c b/validation/optim/cmp-type0.c index ab9d53d4..15115b9f 100644 --- a/validation/optim/cmp-type0.c +++ b/validation/optim/cmp-type0.c @@ -6,7 +6,6 @@ static int foo(long long a) /* * check-name: cmp-type0 * check-command: test-linearize $file - * check-known-to-fail * * check-output-ignore * check-output-returns: 1 diff --git a/validation/optim/cmp-type1.c b/validation/optim/cmp-type1.c index ee0bd75a..6df6376b 100644 --- a/validation/optim/cmp-type1.c +++ b/validation/optim/cmp-type1.c @@ -9,7 +9,6 @@ int foo(void) /* * check-name: cmp-type1 * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-ignore * check-output-returns: 1 |
