aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2019-12-17 01:11:52 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2019-12-17 01:11:52 +0100
commit0f49afdec53446e7af20271519ae422d8d183360 (patch)
treeadd3a0763f0bf26ea838cbe89bbb9a40285b1d12
parent1e55dbed260fffac3e392ac61604f401d64980f4 (diff)
parent0d92426b4e15d7565e1a1d45cb41e06059ed2043 (diff)
downloadsparse-0f49afdec53446e7af20271519ae422d8d183360.tar.gz
Merge branch 'expand-init' (early part) into next
* improve expansion of constant symbols
-rw-r--r--evaluate.c16
-rw-r--r--expand.c87
-rw-r--r--memops.c11
-rw-r--r--validation/eval/addressable-complex.c23
-rw-r--r--validation/eval/addressable-degen.c17
-rw-r--r--validation/expand/constant-init-array.c15
-rw-r--r--validation/expand/constant-init-nested-array.c15
-rw-r--r--validation/expand/constant-init-nested-struct.c23
-rw-r--r--validation/expand/constant-init-string.c15
-rw-r--r--validation/expand/constant-union-flt2int.c20
-rw-r--r--validation/expand/constant-union-int2flt.c19
-rw-r--r--validation/expand/constant-union-size.c (renamed from validation/bug-expand-union0.c)7
-rw-r--r--validation/expand/cost-deref-nested.c20
-rw-r--r--validation/expand/default-init-array.c16
-rw-r--r--validation/expand/default-init-struct.c22
-rw-r--r--validation/expand/union-cast.c27
-rw-r--r--validation/memops/type-punning-flt2int.c (renamed from validation/bug-expand-union1.c)5
-rw-r--r--validation/memops/type-punning-int2flt.c19
18 files changed, 355 insertions, 22 deletions
diff --git a/evaluate.c b/evaluate.c
index 4d08956e..4096566e 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1540,6 +1540,16 @@ static int compatible_argument_type(struct expression *expr, struct symbol *targ
return compatible_assignment_types(expr, target, rp, where);
}
+static void mark_addressable(struct expression *expr)
+{
+ while (expr->type == EXPR_BINOP && expr->op == '+')
+ expr = expr->left;
+ if (expr->type == EXPR_SYMBOL) {
+ struct symbol *sym = expr->symbol;
+ sym->ctype.modifiers |= MOD_ADDRESSABLE;
+ }
+}
+
static void mark_assigned(struct expression *expr)
{
struct symbol *sym;
@@ -1762,6 +1772,7 @@ static struct symbol *degenerate(struct expression *expr)
*expr = *expr->unop;
ctype = create_pointer(expr, ctype, 1);
expr->ctype = ctype;
+ mark_addressable(expr);
default:
/* nothing */;
}
@@ -1780,10 +1791,7 @@ static struct symbol *evaluate_addressof(struct expression *expr)
ctype = op->ctype;
*expr = *op->unop;
- if (expr->type == EXPR_SYMBOL) {
- struct symbol *sym = expr->symbol;
- sym->ctype.modifiers |= MOD_ADDRESSABLE;
- }
+ mark_addressable(expr);
/*
* symbol expression evaluation is lazy about the type
diff --git a/expand.c b/expand.c
index ae764153..36612c86 100644
--- a/expand.c
+++ b/expand.c
@@ -621,12 +621,70 @@ static int expand_addressof(struct expression *expr)
return expand_expression(expr->unop);
}
+///
+// lookup the type of a struct's memeber at the requested offset
+static struct symbol *find_member(struct symbol *sym, int offset)
+{
+ struct ptr_list *head, *list;
+
+ head = (struct ptr_list *) sym->symbol_list;
+ list = head;
+ if (!head)
+ return NULL;
+ do {
+ int nr = list->nr;
+ int i;
+ for (i = 0; i < nr; i++) {
+ struct symbol *ent = (struct symbol *) list->list[i];
+ int curr = ent->offset;
+ if (curr == offset)
+ return ent;
+ if (curr > offset)
+ return NULL;
+ }
+ } while ((list = list->next) != head);
+ return NULL;
+}
+
+///
+// lookup a suitable default initializer value at the requested offset
+static struct expression *default_initializer(struct symbol *sym, int offset)
+{
+ static struct expression value;
+ struct symbol *type;
+
+redo:
+ switch (sym->type) {
+ case SYM_NODE:
+ sym = sym->ctype.base_type;
+ goto redo;
+ case SYM_STRUCT:
+ type = find_member(sym, offset);
+ if (!type)
+ return NULL;
+ break;
+ case SYM_ARRAY:
+ type = sym->ctype.base_type;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (is_integral_type(type))
+ value.type = EXPR_VALUE;
+ else if (is_float_type(type))
+ value.type = EXPR_FVALUE;
+ else
+ return NULL;
+
+ value.ctype = type;
+ return &value;
+}
+
/*
* Look up a trustable initializer value at the requested offset.
*
* Return NULL if no such value can be found or statically trusted.
- *
- * FIXME!! We should check that the size is right!
*/
static struct expression *constant_symbol_value(struct symbol *sym, int offset)
{
@@ -648,10 +706,11 @@ static struct expression *constant_symbol_value(struct symbol *sym, int offset)
if (entry->init_offset < offset)
continue;
if (entry->init_offset > offset)
- return NULL;
+ break;
return entry->init_expr;
} END_FOR_EACH_PTR(entry);
- return NULL;
+
+ value = default_initializer(sym, offset);
}
return value;
}
@@ -678,22 +737,26 @@ static int expand_dereference(struct expression *expr)
* Is it "symbol" or "symbol + offset"?
*/
offset = 0;
- if (unop->type == EXPR_BINOP && unop->op == '+') {
+ while (unop->type == EXPR_BINOP && unop->op == '+') {
struct expression *right = unop->right;
- if (right->type == EXPR_VALUE) {
- offset = right->value;
- unop = unop->left;
- }
+ if (right->type != EXPR_VALUE)
+ break;
+ offset += right->value;
+ unop = unop->left;
}
if (unop->type == EXPR_SYMBOL) {
struct symbol *sym = unop->symbol;
+ struct symbol *ctype = expr->ctype;
struct expression *value = constant_symbol_value(sym, offset);
/* Const symbol with a constant initializer? */
- if (value) {
- /* FIXME! We should check that the size is right! */
+ if (value && value->ctype) {
+ if (ctype->bit_size != value->ctype->bit_size)
+ return UNSAFE;
if (value->type == EXPR_VALUE) {
+ if (!is_integral_type(ctype))
+ return UNSAFE;
if (is_bitfield_type(value->ctype))
return UNSAFE;
expr->type = EXPR_VALUE;
@@ -701,6 +764,8 @@ static int expand_dereference(struct expression *expr)
expr->taint = 0;
return 0;
} else if (value->type == EXPR_FVALUE) {
+ if (!is_float_type(ctype))
+ return UNSAFE;
expr->type = EXPR_FVALUE;
expr->fvalue = value->fvalue;
return 0;
diff --git a/memops.c b/memops.c
index 5df2c033..f071e556 100644
--- a/memops.c
+++ b/memops.c
@@ -82,6 +82,15 @@ static int local_pseudo(pseudo_t pseudo)
&& !address_taken(pseudo);
}
+static bool compatible_loads(struct instruction *a, struct instruction *b)
+{
+ if (is_integral_type(a->type) && is_float_type(b->type))
+ return false;
+ if (is_float_type(a->type) && is_integral_type(b->type))
+ return false;
+ return true;
+}
+
static void simplify_loads(struct basic_block *bb)
{
struct instruction *insn;
@@ -114,6 +123,8 @@ static void simplify_loads(struct basic_block *bb)
continue;
goto next_load;
}
+ if (!compatible_loads(insn, dom))
+ goto next_load;
/* Yeehaa! Found one! */
convert_load_instruction(insn, dom->target);
goto next_load;
diff --git a/validation/eval/addressable-complex.c b/validation/eval/addressable-complex.c
new file mode 100644
index 00000000..e3d4aca4
--- /dev/null
+++ b/validation/eval/addressable-complex.c
@@ -0,0 +1,23 @@
+extern void def(void *);
+
+struct s1 {
+ int a;
+};
+
+int use1(void)
+{
+ struct s1 s = { 3 };
+
+ def(&s.a);
+
+ return s.a;
+}
+
+/*
+ * check-name: eval/addressable-complex
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ * check-output-excludes: return\\..*\\$3
+ */
diff --git a/validation/eval/addressable-degen.c b/validation/eval/addressable-degen.c
new file mode 100644
index 00000000..d420927e
--- /dev/null
+++ b/validation/eval/addressable-degen.c
@@ -0,0 +1,17 @@
+extern void def(void *, unsigned int);
+
+static int bar(void)
+{
+ int x[2] = { 1, 2 };
+
+ def(x, sizeof(x));
+ return x[1];
+}
+
+/*
+ * check-name: eval/addressable-degen
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */
diff --git a/validation/expand/constant-init-array.c b/validation/expand/constant-init-array.c
new file mode 100644
index 00000000..94949be5
--- /dev/null
+++ b/validation/expand/constant-init-array.c
@@ -0,0 +1,15 @@
+int test_array(int i)
+{
+ static const int a[3] = { 1, 2, 3, };
+
+ return a[1];
+}
+
+/*
+ * check-name: constant-init-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-excludes: phisrc\\..*return.*\\$2
+ * check-output-contains: load\\.
+ */
diff --git a/validation/expand/constant-init-nested-array.c b/validation/expand/constant-init-nested-array.c
new file mode 100644
index 00000000..0d50d955
--- /dev/null
+++ b/validation/expand/constant-init-nested-array.c
@@ -0,0 +1,15 @@
+int foo(void)
+{
+ int a[2][3] = {{0, 1, 2},{3, 4, 5}};
+ return a[1][2];
+}
+
+/*
+ * check-name: constant-init-nested-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*\\$5
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/constant-init-nested-struct.c b/validation/expand/constant-init-nested-struct.c
new file mode 100644
index 00000000..f27de556
--- /dev/null
+++ b/validation/expand/constant-init-nested-struct.c
@@ -0,0 +1,23 @@
+struct s {
+ int a;
+ struct {
+ int b;
+ int c;
+ } s;
+};
+
+int foo(void)
+{
+ struct s s = {1, {2, 3}};
+ return s.s.c;
+}
+
+/*
+ * check-name: constant-init-nested-struct
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*\\$3
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/constant-init-string.c b/validation/expand/constant-init-string.c
new file mode 100644
index 00000000..42ae9bd3
--- /dev/null
+++ b/validation/expand/constant-init-string.c
@@ -0,0 +1,15 @@
+char foo(void)
+{
+ static const char s[] = "abc?";
+ return s[3];
+}
+
+/*
+ * check-name: constant-init-nested-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*\\$63
+ * check-output-pattern(0,1): load\\.
+ */
diff --git a/validation/expand/constant-union-flt2int.c b/validation/expand/constant-union-flt2int.c
new file mode 100644
index 00000000..5e25b592
--- /dev/null
+++ b/validation/expand/constant-union-flt2int.c
@@ -0,0 +1,20 @@
+union u {
+ int i;
+ float f;
+};
+
+static int foo(void)
+{
+ union u u = { .f = 0.123 };
+ return u.i;
+}
+
+/*
+ * check-name: constant-union-float-to-int
+ * check description: must not infer the int value from the float
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): setfval\\.
+ * check-output-pattern(1): load\\.
+ */
diff --git a/validation/expand/constant-union-int2flt.c b/validation/expand/constant-union-int2flt.c
new file mode 100644
index 00000000..16ce1c6f
--- /dev/null
+++ b/validation/expand/constant-union-int2flt.c
@@ -0,0 +1,19 @@
+union u {
+ int i;
+ float f;
+};
+
+static float foo(void)
+{
+ union u u = { .i = 3 };
+ return u.f;
+}
+
+/*
+ * check-name: constant-union-int-to-float
+ * check description: must not infer the float value from the int
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): load\\.
+ */
diff --git a/validation/bug-expand-union0.c b/validation/expand/constant-union-size.c
index dd6d60c3..8a16bf3e 100644
--- a/validation/bug-expand-union0.c
+++ b/validation/expand/constant-union-size.c
@@ -10,10 +10,9 @@ static int foo(void)
}
/*
- * check-name: bug-expand-union
- * check description: must not infer the value from the float
- * check-command: test-linearize $file
- * check-known-to-fail
+ * check-name: constant-union-size
+ * check description: the size of the initializer doesn't match
+ * check-command: test-linearize -fdump-ir $file
*
* check-output-ignore
* check-output-contains: load\\.
diff --git a/validation/expand/cost-deref-nested.c b/validation/expand/cost-deref-nested.c
new file mode 100644
index 00000000..d6b62396
--- /dev/null
+++ b/validation/expand/cost-deref-nested.c
@@ -0,0 +1,20 @@
+struct s {
+ struct {
+ int u, v;
+ } a, b;
+};
+
+static const struct s s;
+
+static int foo(int c)
+{
+ return c && s.b.v;
+}
+
+/*
+ * check-name: cost-deref-nested
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-excludes: cbr
+ */
diff --git a/validation/expand/default-init-array.c b/validation/expand/default-init-array.c
new file mode 100644
index 00000000..b372ea09
--- /dev/null
+++ b/validation/expand/default-init-array.c
@@ -0,0 +1,16 @@
+int test_array(int i)
+{
+ static const int a[3] = { [0] = 1, [2] = 3, };
+
+ return a[1];
+}
+
+/*
+ * check-name: default-init-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*return.*\\$0
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/default-init-struct.c b/validation/expand/default-init-struct.c
new file mode 100644
index 00000000..085dd2d6
--- /dev/null
+++ b/validation/expand/default-init-struct.c
@@ -0,0 +1,22 @@
+struct s {
+ int a;
+ int b;
+ int c;
+};
+
+
+int test_struct(void)
+{
+ struct s s = { .a = 1, .c = 3, };
+
+ return s.b;
+}
+
+/*
+ * check-name: default-init-struct
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*return.*\\$0
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/union-cast.c b/validation/expand/union-cast.c
new file mode 100644
index 00000000..a28d01f2
--- /dev/null
+++ b/validation/expand/union-cast.c
@@ -0,0 +1,27 @@
+union u {
+ int i;
+ struct s {
+ int a;
+ } s;
+};
+
+int foo(void)
+{
+ struct s s = { 3 };
+ union u u = (union u)s;
+ return u.s.a;
+}
+
+/*
+ * check-name: union-cast
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ *
+ * check-error-start
+union-cast.c:11:22: warning: cast to non-scalar
+union-cast.c:11:22: warning: cast from non-scalar
+ * check-error-end
+ */
diff --git a/validation/bug-expand-union1.c b/validation/memops/type-punning-flt2int.c
index 582a1f4f..fadaf687 100644
--- a/validation/bug-expand-union1.c
+++ b/validation/memops/type-punning-flt2int.c
@@ -10,10 +10,9 @@ static int foo(void)
}
/*
- * check-name: bug-expand-union
- * check description: must not infer the value from the float
+ * check-name: type-punning-float-to-int
+ * check description: must not infer the int value from the float
* check-command: test-linearize $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-contains: load\\.
diff --git a/validation/memops/type-punning-int2flt.c b/validation/memops/type-punning-int2flt.c
new file mode 100644
index 00000000..061b7423
--- /dev/null
+++ b/validation/memops/type-punning-int2flt.c
@@ -0,0 +1,19 @@
+union u {
+ int i;
+ float f;
+};
+
+static float foo(void)
+{
+ union u u = { .i = 3 };
+ return u.f;
+}
+
+/*
+ * check-name: type-punning-int-to-float
+ * check description: must not infer the float value from the int
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */