aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-08-23 16:43:08 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-11-01 00:40:57 +0100
commit226b62bc2ee4779447ce788d83aa0b409e384ec8 (patch)
treeace913c378dd4085c34112c9e8602a7b39f75c27
parent594c7389969f79919f1170693c970fb25b8bfe4d (diff)
downloadsparse-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>
-rw-r--r--Documentation/IR.rst1
-rw-r--r--linearize.c16
-rw-r--r--linearize.h4
-rw-r--r--simplify.c14
-rw-r--r--validation/optim/cmp-type0.c1
-rw-r--r--validation/optim/cmp-type1.c1
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;
diff --git a/simplify.c b/simplify.c
index 6f75b1ae..f2aaa52d 100644
--- a/simplify.c
+++ b/simplify.c
@@ -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