use ir_tarval to calculate case values
authorMatthias Braun <matze@braunis.de>
Wed, 24 Oct 2012 16:22:42 +0000 (18:22 +0200)
committerChristoph Mallon <christoph.mallon@gmx.de>
Tue, 30 Oct 2012 09:26:25 +0000 (10:26 +0100)
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.

ast2firm.c
ast2firm.h
ast_t.h
libfirm
parser.c

index bc94473..43e7deb 100644 (file)
@@ -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;
        }
index b941f3c..2271f66 100644 (file)
@@ -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 (file)
--- 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
index 6f2df33..cbc9fdd 160000 (submodule)
--- a/libfirm
+++ b/libfirm
@@ -1 +1 @@
-Subproject commit 6f2df337ba40d5c7461f9459fd57efbcc0686c9b
+Subproject commit cbc9fdd03cead0cd8d43142ae718d0460ebdfe5f
index 4e9d2f0..869cc25 100644 (file)
--- 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;
        }
 }