aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-11-01 07:09:11 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-11-01 07:09:11 +0100
commitf680124b794b246c8a20f2cb54b2fc7ff989625d (patch)
treef480814f46fbfc9f462a1221a120ec8e406f41cb
parent0c7b00977c8826b1cd172f7e90ad14e980190467 (diff)
parent226b62bc2ee4779447ce788d83aa0b409e384ec8 (diff)
downloadsparse-f680124b794b246c8a20f2cb54b2fc7ff989625d.tar.gz
Merge branch 'typed-cmp'
* give an explicit type to compare's operands
-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-op-type.c18
-rw-r--r--validation/optim/cmp-type0.c12
-rw-r--r--validation/optim/cmp-type1.c15
7 files changed, 75 insertions, 5 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 def6cf34..c1e3455a 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-op-type.c b/validation/optim/cmp-op-type.c
new file mode 100644
index 00000000..037272f8
--- /dev/null
+++ b/validation/optim/cmp-op-type.c
@@ -0,0 +1,18 @@
+extern int get(void);
+
+static int array[8192];
+
+static int foo(void)
+{
+ int n = -1;
+ if (n < 0)
+ n = get();
+ return array[n];
+}
+
+/*
+ * check-name: cmp-op-type
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ */
diff --git a/validation/optim/cmp-type0.c b/validation/optim/cmp-type0.c
new file mode 100644
index 00000000..15115b9f
--- /dev/null
+++ b/validation/optim/cmp-type0.c
@@ -0,0 +1,12 @@
+static int foo(long long a)
+{
+ return 0LL < (0x80000000LL + (a - a));
+}
+
+/*
+ * check-name: cmp-type0
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/optim/cmp-type1.c b/validation/optim/cmp-type1.c
new file mode 100644
index 00000000..6df6376b
--- /dev/null
+++ b/validation/optim/cmp-type1.c
@@ -0,0 +1,15 @@
+int foo(void)
+{
+ int r;
+ long n;
+ n = 0;
+ return n < 2147483648U;
+}
+
+/*
+ * check-name: cmp-type1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */