aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-10-27 01:39:29 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-11-01 01:04:06 +0100
commit0c7b00977c8826b1cd172f7e90ad14e980190467 (patch)
tree63fe9239a0f7f57b05a66595ee70025d06ed83db
parentabfaa2dfb4d69eb0857d5af8ed082ccf8b824c46 (diff)
downloadsparse-0c7b00977c8826b1cd172f7e90ad14e980190467.tar.gz
linearize __builtin_isdigit()
As an experiment about the linearization of builtins, try this easy one (and statically expand it if the argument is constant). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--builtin.c21
-rw-r--r--linearize.c22
-rw-r--r--validation/expand/builtin_isdigit.c10
-rw-r--r--validation/linear/builtin_isdigit.c12
4 files changed, 65 insertions, 0 deletions
diff --git a/builtin.c b/builtin.c
index acc49871..5c7321ca 100644
--- a/builtin.c
+++ b/builtin.c
@@ -305,6 +305,26 @@ static struct symbol_op fp_unop_op = {
};
+static int expand_isdigit(struct expression *expr, int cost)
+{
+ struct expression *arg = first_expression(expr->args);
+ long long val = get_expression_value_silent(arg);
+
+ if (cost)
+ return cost;
+
+ expr->value = (val >= '0') && (val <= '9');
+ expr->type = EXPR_VALUE;
+ expr->taint = 0;
+ return 0;
+}
+
+static struct symbol_op isdigit_op = {
+ .evaluate = evaluate_pure_unop,
+ .expand = expand_isdigit,
+};
+
+
static int evaluate_overflow_gen(struct expression *expr, int ptr)
{
struct expression *arg;
@@ -552,6 +572,7 @@ static const struct builtin_fn builtins_common[] = {
{ "__builtin_inf", &double_ctype, 0 },
{ "__builtin_inff", &float_ctype, 0 },
{ "__builtin_infl", &ldouble_ctype, 0 },
+ { "__builtin_isdigit", &int_ctype, 0, { &int_ctype }, .op = &isdigit_op },
{ "__builtin_isfinite", &int_ctype, 1, .op = &fp_unop_op },
{ "__builtin_isgreater", &int_ctype, 0, { &float_ctype, &float_ctype }},
{ "__builtin_isgreaterequal", &int_ctype, 0, { &float_ctype, &float_ctype }},
diff --git a/linearize.c b/linearize.c
index 85b8ac60..def6cf34 100644
--- a/linearize.c
+++ b/linearize.c
@@ -2593,6 +2593,27 @@ static pseudo_t linearize_fma(struct entrypoint *ep, struct expression *expr)
return insn->target = alloc_pseudo(insn);
}
+static pseudo_t linearize_isdigit(struct entrypoint *ep, struct expression *expr)
+{
+ struct instruction *insn;
+ pseudo_t src;
+
+ insn = alloc_typed_instruction(OP_SUB, &int_ctype);
+ src = linearize_expression(ep, first_expression(expr->args));
+ use_pseudo(insn, src, &insn->src1);
+ insn->src2 = value_pseudo('0');
+ src = insn->target = alloc_pseudo(insn);
+ add_one_insn(ep, insn);
+
+ insn = alloc_typed_instruction(OP_SET_BE, &int_ctype);
+ use_pseudo(insn, src, &insn->src1);
+ insn->src2 = value_pseudo(9);
+ insn->target = alloc_pseudo(insn);
+ add_one_insn(ep, insn);
+
+ return insn->target;
+}
+
static pseudo_t linearize_unreachable(struct entrypoint *ep, struct expression *exp)
{
add_unreachable(ep);
@@ -2608,6 +2629,7 @@ static struct sym_init {
{ "__builtin_fma", linearize_fma },
{ "__builtin_fmaf", linearize_fma },
{ "__builtin_fmal", linearize_fma },
+ { "__builtin_isdigit", linearize_isdigit },
{ "__builtin_unreachable", linearize_unreachable },
{ }
};
diff --git a/validation/expand/builtin_isdigit.c b/validation/expand/builtin_isdigit.c
new file mode 100644
index 00000000..56550b38
--- /dev/null
+++ b/validation/expand/builtin_isdigit.c
@@ -0,0 +1,10 @@
+_Static_assert(__builtin_isdigit('0'));
+_Static_assert(__builtin_isdigit('9'));
+
+_Static_assert(!__builtin_isdigit(0));
+_Static_assert(!__builtin_isdigit(' '));
+_Static_assert(!__builtin_isdigit('z'));
+
+/*
+ * check-name: builtin_isdigit
+ */
diff --git a/validation/linear/builtin_isdigit.c b/validation/linear/builtin_isdigit.c
new file mode 100644
index 00000000..c1d3ea15
--- /dev/null
+++ b/validation/linear/builtin_isdigit.c
@@ -0,0 +1,12 @@
+_Bool isdigit(int c)
+{
+ return __builtin_isdigit(c) == (((unsigned) (c - '0')) <= 9);
+}
+
+/*
+ * check-name: builtin_isdigit
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */