aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linearize.c
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 /linearize.c
parent80458cde49e9fe8ea090279f94713f6410d35032 (diff)
downloadsparse-dev-dcc3d37fdc742914668f4e37f17024a95466ed80.tar.gz
Add proper linearization of switch statements.
Diffstat (limited to 'linearize.c')
-rw-r--r--linearize.c41
1 files changed, 38 insertions, 3 deletions
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;