summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatthias Braun <matze@braunis.de>2012-10-24 18:22:42 +0200
committerChristoph Mallon <christoph.mallon@gmx.de>2012-10-30 10:26:25 +0100
commit296ba6e16420b89723d1a5b1217d6ecfc2fb0c7d (patch)
treeda9c40da04b58082179e47399cb3f8da98024e27
parent5c3e782835e8105b795945ce3324ec7f07db3fdd (diff)
use ir_tarval to calculate case values
This avoids problems when handling unsigned long long case values in the parser, which formerly only used long/int. Fixes 64bit switches in combination with new libfirm.
-rw-r--r--ast2firm.c12
-rw-r--r--ast2firm.h3
-rw-r--r--ast_t.h4
m---------libfirm0
-rw-r--r--parser.c37
5 files changed, 31 insertions, 25 deletions
diff --git a/ast2firm.c b/ast2firm.c
index bc94473..43e7deb 100644
--- a/ast2firm.c
+++ b/ast2firm.c
@@ -625,9 +625,7 @@ static ir_type *create_compound_type(compound_type_t *const type, bool const inc
return irtype;
}
-static ir_tarval *fold_constant_to_tarval(expression_t const *);
-
-static void determine_enum_values(enum_type_t *const type)
+void determine_enum_values(enum_type_t *const type)
{
ir_mode *const mode = atomic_modes[type->base.akind];
ir_tarval *const one = get_mode_one(mode);
@@ -2843,7 +2841,7 @@ static ir_node *alignof_to_firm(const typeprop_expression_t *expression)
static void init_ir_types(void);
-static ir_tarval *fold_constant_to_tarval(const expression_t *expression)
+ir_tarval *fold_constant_to_tarval(const expression_t *expression)
{
assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT);
@@ -4688,11 +4686,9 @@ static ir_switch_table *create_switch_table(const switch_statement_t *statement)
}
if (l->is_empty_range)
continue;
- ir_tarval *min = fold_constant_to_tarval(l->expression);
- ir_tarval *max = min;
+ ir_tarval *min = l->first_case;
+ ir_tarval *max = l->last_case;
long pn = (long) i+1;
- if (l->end_range != NULL)
- max = fold_constant_to_tarval(l->end_range);
ir_switch_table_set(res, i++, min, max, pn);
l->pn = pn;
}
diff --git a/ast2firm.h b/ast2firm.h
index b941f3c..2271f66 100644
--- a/ast2firm.h
+++ b/ast2firm.h
@@ -36,6 +36,9 @@ typedef ident* (*create_ld_ident_func)(entity_t *entity);
void set_create_ld_ident(create_ld_ident_func func);
+ir_tarval *fold_constant_to_tarval(const expression_t *expression);
+void determine_enum_values(enum_type_t *type);
+
extern fp_model_t firm_fp_model;
extern ir_mode *atomic_modes[ATOMIC_TYPE_LAST+1];
diff --git a/ast_t.h b/ast_t.h
index 1dc06c3..516e6f7 100644
--- a/ast_t.h
+++ b/ast_t.h
@@ -552,8 +552,8 @@ struct case_label_statement_t {
expression_t *end_range; /**< For GNUC case a .. b: the end range expression, NULL else. */
case_label_statement_t *next; /**< link to the next case label in switch */
statement_t *statement;
- long first_case; /**< The folded value of expression. */
- long last_case; /**< The folded value of end_range. */
+ ir_tarval *first_case;
+ ir_tarval *last_case;
bool is_bad; /**< If set marked as bad to suppress warnings. */
bool is_empty_range; /**< If set marked this as an empty range. */
long pn;
diff --git a/libfirm b/libfirm
-Subproject 6f2df337ba40d5c7461f9459fd57efbcc0686c9
+Subproject cbc9fdd03cead0cd8d43142ae718d0460ebdfe5
diff --git a/parser.c b/parser.c
index 4e9d2f0..869cc25 100644
--- a/parser.c
+++ b/parser.c
@@ -41,6 +41,7 @@
#include "walk.h"
#include "warning.h"
#include "printer.h"
+#include "ast2firm.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
#include "adt/array.h"
@@ -4789,7 +4790,7 @@ static void check_reachable(statement_t *const stmt)
return;
if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
- long const val = fold_constant_to_int(expr);
+ ir_tarval *const val = fold_constant_to_tarval(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
if (i->expression == NULL) {
@@ -4797,7 +4798,9 @@ static void check_reachable(statement_t *const stmt)
continue;
}
- if (i->first_case <= val && val <= i->last_case) {
+ if (i->first_case == val || i->last_case == val ||
+ ((tarval_cmp(i->first_case, val) & ir_relation_less_equal)
+ && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) {
check_reachable((statement_t*)i);
return;
}
@@ -8839,7 +8842,7 @@ static statement_t *parse_case_statement(void)
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant_to_int(expression);
+ ir_tarval *val = fold_constant_to_tarval(expression);
statement->case_label.first_case = val;
statement->case_label.last_case = val;
}
@@ -8863,10 +8866,11 @@ static statement_t *parse_case_statement(void)
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant_to_int(end_range);
+ ir_tarval *val = fold_constant_to_tarval(end_range);
statement->case_label.last_case = val;
- if (val < statement->case_label.first_case) {
+ if (tarval_cmp(val, statement->case_label.first_case)
+ == ir_relation_less) {
statement->case_label.is_empty_range = true;
warningf(WARN_OTHER, pos, "empty range specified");
}
@@ -9071,28 +9075,32 @@ static void check_enum_cases(const switch_statement_t *statement)
{
if (!is_warn_on(WARN_SWITCH_ENUM))
return;
- const type_t *type = skip_typeref(statement->expression->base.type);
+ type_t *type = skip_typeref(statement->expression->base.type);
if (! is_type_enum(type))
return;
- const enum_type_t *enumt = &type->enumt;
+ enum_type_t *enumt = &type->enumt;
/* if we have a default, no warnings */
if (statement->default_label != NULL)
return;
+ determine_enum_values(enumt);
+
/* FIXME: calculation of value should be done while parsing */
/* TODO: quadratic algorithm here. Change to an n log n one */
- long last_value = -1;
- const entity_t *entry = enumt->enume->base.next;
+ const entity_t *entry = enumt->enume->base.next;
for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
entry = entry->base.next) {
- const expression_t *expression = entry->enum_value.value;
- long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
- bool found = false;
- for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+ ir_tarval *value = entry->enum_value.tv;
+ bool found = false;
+ for (const case_label_statement_t *l = statement->first_case; l != NULL;
+ l = l->next) {
if (l->expression == NULL)
continue;
- if (l->first_case <= value && value <= l->last_case) {
+ if (l->first_case == l->last_case && l->first_case != value)
+ continue;
+ if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal)
+ && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) {
found = true;
break;
}
@@ -9101,7 +9109,6 @@ static void check_enum_cases(const switch_statement_t *statement)
source_position_t const *const pos = &statement->base.source_position;
warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
}
- last_value = value;
}
}