aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLinus Torvalds <torvalds@home.osdl.org>2004-02-12 13:41:42 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-07 21:01:23 -0700
commitdcc3d37fdc742914668f4e37f17024a95466ed80 (patch)
tree9b2a9c2cb59f439ac82b426cb7042bb41b39586d
parent80458cde49e9fe8ea090279f94713f6410d35032 (diff)
downloadsparse-dev-dcc3d37fdc742914668f4e37f17024a95466ed80.tar.gz
Add proper linearization of switch statements.
-rw-r--r--compile-i386.c8
-rw-r--r--evaluate.c2
-rw-r--r--expand.c2
-rw-r--r--linearize.c41
-rw-r--r--parse.h7
-rw-r--r--show-parse.c17
6 files changed, 74 insertions, 3 deletions
diff --git a/compile-i386.c b/compile-i386.c
index f15362ec..dab66c05 100644
--- a/compile-i386.c
+++ b/compile-i386.c
@@ -1828,6 +1828,14 @@ static struct storage *x86_statement(struct statement *stmt)
case STMT_CONDFALSE:
printf("\tje xxx*\n");
break;
+
+ case STMT_MULTIVALUE:
+ printf("\tswitch value!!\n");
+ break;
+
+ case STMT_MULTIJMP:
+ printf("\tswitch case xxx\n");
+ break;
}
return NULL;
}
diff --git a/evaluate.c b/evaluate.c
index 353fe94b..41f36748 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1602,6 +1602,8 @@ struct symbol *evaluate_statement(struct statement *stmt)
/* These should not exist at evaluation time */
case STMT_CONDTRUE:
case STMT_CONDFALSE:
+ case STMT_MULTIVALUE:
+ case STMT_MULTIJMP:
break;
}
return NULL;
diff --git a/expand.c b/expand.c
index 0bcc219e..02c87cc9 100644
--- a/expand.c
+++ b/expand.c
@@ -588,6 +588,8 @@ static void expand_statement(struct statement *stmt)
/* Should not show up at this stage */
case STMT_CONDTRUE:
case STMT_CONDFALSE:
+ case STMT_MULTIVALUE:
+ case STMT_MULTIJMP:
break;
}
}
diff --git a/linearize.c b/linearize.c
index 39c229df..c2637c53 100644
--- a/linearize.c
+++ b/linearize.c
@@ -94,7 +94,17 @@ static struct basic_block * linearize_statement(struct symbol_list **syms,
bb = new_basic_block(bbs);
break;
- case STMT_CASE:
+ case STMT_CASE: {
+ struct basic_block *new_bb = new_basic_block(bbs);
+ struct symbol *sym = stmt->case_label;
+
+ bb->next = sym;
+ sym->bb_target = new_bb;
+
+ bb = linearize_statement(syms, bbs, new_bb, stmt->case_statement);
+ break;
+ }
+
case STMT_LABEL: {
struct basic_block *new_bb = new_basic_block(bbs);
struct symbol *sym = stmt->label_identifier;
@@ -157,10 +167,35 @@ static struct basic_block * linearize_statement(struct symbol_list **syms,
break;
}
- case STMT_SWITCH:
- add_statement(&bb->stmts, stmt);
+ case STMT_SWITCH: {
+ struct symbol *sym;
+ struct statement *switch_value;
+
+ /* Create the "head node" */
+ switch_value = alloc_statement(stmt->pos, STMT_MULTIVALUE);
+ switch_value->expression = stmt->switch_expression;
+ add_statement(&bb->stmts, switch_value);
+
+ /* Create all the sub-jumps */
+ FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
+ struct statement *case_stmt = sym->stmt;
+ struct statement *sw_bb = alloc_statement(case_stmt->pos, STMT_MULTIJMP);
+ sw_bb->multi_from = case_stmt->case_expression;
+ sw_bb->multi_to = case_stmt->case_to;
+ sw_bb->multi_target = sym;
+ add_statement(&bb->stmts, sw_bb);
+ } END_FOR_EACH_PTR;
+
+ /* And linearize the actual statement */
+ bb = linearize_statement(syms, bbs, new_basic_block(bbs), stmt->switch_statement);
+
+ /* ..then tie it all together at the end.. */
+ bb->next = stmt->switch_break;
bb = new_basic_block(bbs);
+ stmt->switch_break->bb_target = bb;
+
break;
+ }
case STMT_ITERATOR: {
struct statement *pre_statement = stmt->iterator_pre_statement;
diff --git a/parse.h b/parse.h
index 18a4bf9e..386c7855 100644
--- a/parse.h
+++ b/parse.h
@@ -27,6 +27,8 @@ enum statement_type {
/* These only show up after linearization */
STMT_CONDTRUE,
STMT_CONDFALSE,
+ STMT_MULTIVALUE,
+ STMT_MULTIJMP,
};
struct statement {
@@ -87,6 +89,11 @@ struct statement {
struct expression *bb_conditional;
struct symbol *bb_target;
};
+ struct /* multijmp */ {
+ struct expression *multi_from;
+ struct expression *multi_to;
+ struct symbol *multi_target;
+ };
};
};
diff --git a/show-parse.c b/show-parse.c
index 4e5989b7..f58b046a 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -542,6 +542,23 @@ int show_statement(struct statement *stmt)
break;
}
+ case STMT_MULTIVALUE: {
+ int val = show_expression(stmt->expression);
+ printf("\tSWITCH\t\tv%d\n", val);
+ break;
+ }
+
+ case STMT_MULTIJMP: {
+ long long from = 0, to = 0;
+ if (stmt->multi_from && stmt->multi_from->type == EXPR_VALUE)
+ from = stmt->multi_from->value;
+ to = from;
+ if (stmt->multi_to && stmt->multi_to->type == EXPR_VALUE)
+ to = stmt->multi_to->value;
+ printf("\tIF %lld..%lld goto .L%p\n", from, to, stmt->multi_target->bb_target);
+ break;
+ }
+
}
return 0;
}