+ switch ((declaration_kind_t) entity->declaration.kind) {
+ case DECLARATION_KIND_LOCAL_VARIABLE:
+ case DECLARATION_KIND_LOCAL_VARIABLE_ENTITY:
+ create_variable_initializer(entity);
+ return;
+
+ case DECLARATION_KIND_VARIABLE_LENGTH_ARRAY:
+ allocate_variable_length_array(entity);
+ return;
+
+ case DECLARATION_KIND_COMPOUND_MEMBER:
+ case DECLARATION_KIND_GLOBAL_VARIABLE:
+ case DECLARATION_KIND_FUNCTION:
+ case DECLARATION_KIND_INNER_FUNCTION:
+ return;
+
+ case DECLARATION_KIND_UNKNOWN:
+ panic("can't initialize unknown declaration");
+ }
+ panic("invalid declaration kind");
+}
+
+static void declaration_statement_to_firm(declaration_statement_t *statement)
+{
+ entity_t *entity = statement->declarations_begin;
+ entity_t *end = statement->declarations_end->base.next;
+ for ( ; entity != end; entity = entity->base.next) {
+ if (!is_declaration(entity))
+ continue;
+ initialize_local_declaration(entity);
+ }
+}
+
+static void if_statement_to_firm(if_statement_t *statement)
+{
+ ir_node *cur_block = get_cur_block();
+
+ ir_node *fallthrough_block = NULL;
+
+ /* the true (blocks) */
+ ir_node *true_block = NULL;
+ if (statement->true_statement != NULL) {
+ true_block = new_immBlock();
+ statement_to_firm(statement->true_statement);
+ if (get_cur_block() != NULL) {
+ ir_node *jmp = new_Jmp();
+ if (fallthrough_block == NULL)
+ fallthrough_block = new_immBlock();
+ add_immBlock_pred(fallthrough_block, jmp);
+ }
+ }
+
+ /* the false (blocks) */
+ ir_node *false_block = NULL;
+ if (statement->false_statement != NULL) {
+ false_block = new_immBlock();
+
+ statement_to_firm(statement->false_statement);
+ if (get_cur_block() != NULL) {
+ ir_node *jmp = new_Jmp();
+ if (fallthrough_block == NULL)
+ fallthrough_block = new_immBlock();
+ add_immBlock_pred(fallthrough_block, jmp);
+ }
+ }
+
+ /* create the condition */
+ if (cur_block != NULL) {
+ if (true_block == NULL || false_block == NULL) {
+ if (fallthrough_block == NULL)
+ fallthrough_block = new_immBlock();
+ if (true_block == NULL)
+ true_block = fallthrough_block;
+ if (false_block == NULL)
+ false_block = fallthrough_block;
+ }
+
+ set_cur_block(cur_block);
+ create_condition_evaluation(statement->condition, true_block,
+ false_block);
+ }
+
+ mature_immBlock(true_block);
+ if (false_block != fallthrough_block && false_block != NULL) {
+ mature_immBlock(false_block);
+ }
+ if (fallthrough_block != NULL) {
+ mature_immBlock(fallthrough_block);
+ }
+
+ set_cur_block(fallthrough_block);
+}
+
+static void while_statement_to_firm(while_statement_t *statement)
+{
+ ir_node *jmp = NULL;
+ if (get_cur_block() != NULL) {
+ jmp = new_Jmp();
+ }
+
+ /* create the header block */
+ ir_node *header_block = new_immBlock();
+ if (jmp != NULL) {
+ add_immBlock_pred(header_block, jmp);
+ }
+
+ /* the loop body */
+ ir_node *old_continue_label = continue_label;
+ ir_node *old_break_label = break_label;
+ continue_label = header_block;
+ break_label = NULL;
+
+ ir_node *body_block = new_immBlock();
+ statement_to_firm(statement->body);
+ ir_node *false_block = break_label;
+
+ assert(continue_label == header_block);
+ continue_label = old_continue_label;
+ break_label = old_break_label;
+
+ if (get_cur_block() != NULL) {
+ jmp = new_Jmp();
+ add_immBlock_pred(header_block, jmp);
+ }
+
+ /* shortcut for while(true) */
+ if (is_constant_expression(statement->condition)
+ && fold_constant(statement->condition) != 0) {
+ set_cur_block(header_block);
+ ir_node *header_jmp = new_Jmp();
+ add_immBlock_pred(body_block, header_jmp);
+
+ keep_alive(body_block);
+ keep_all_memory(body_block);
+ set_cur_block(body_block);
+ } else {
+ if (false_block == NULL) {
+ false_block = new_immBlock();
+ }
+
+ /* create the condition */
+ set_cur_block(header_block);
+
+ create_condition_evaluation(statement->condition, body_block,
+ false_block);
+ }
+
+ mature_immBlock(body_block);
+ mature_immBlock(header_block);
+ if (false_block != NULL) {
+ mature_immBlock(false_block);
+ }
+
+ set_cur_block(false_block);
+}
+
+static void do_while_statement_to_firm(do_while_statement_t *statement)
+{
+ ir_node *jmp = NULL;
+ if (get_cur_block() != NULL) {
+ jmp = new_Jmp();
+ }
+
+ /* create the header block */
+ ir_node *header_block = new_immBlock();
+
+ /* the loop body */
+ ir_node *body_block = new_immBlock();
+ if (jmp != NULL) {
+ add_immBlock_pred(body_block, jmp);
+ }
+
+ ir_node *old_continue_label = continue_label;
+ ir_node *old_break_label = break_label;
+ continue_label = header_block;
+ break_label = NULL;
+
+ statement_to_firm(statement->body);
+ ir_node *false_block = break_label;
+
+ assert(continue_label == header_block);
+ continue_label = old_continue_label;
+ break_label = old_break_label;
+
+ if (get_cur_block() != NULL) {
+ ir_node *body_jmp = new_Jmp();
+ add_immBlock_pred(header_block, body_jmp);
+ mature_immBlock(header_block);
+ }
+
+ if (false_block == NULL) {
+ false_block = new_immBlock();
+ }
+
+ /* create the condition */
+ set_cur_block(header_block);
+
+ create_condition_evaluation(statement->condition, body_block, false_block);
+ mature_immBlock(body_block);
+ mature_immBlock(header_block);
+ if (false_block != NULL) {
+ mature_immBlock(false_block);
+ }
+
+ set_cur_block(false_block);
+}
+
+static void for_statement_to_firm(for_statement_t *statement)
+{
+ ir_node *jmp = NULL;
+
+ /* create declarations */
+ entity_t *entity = statement->scope.entities;
+ for ( ; entity != NULL; entity = entity->base.next) {
+ if (!is_declaration(entity))
+ continue;
+
+ create_local_declaration(entity);
+ }
+
+ if (get_cur_block() != NULL) {
+ entity = statement->scope.entities;
+ for ( ; entity != NULL; entity = entity->base.next) {
+ if (!is_declaration(entity))
+ continue;
+
+ initialize_local_declaration(entity);
+ }
+
+ if (statement->initialisation != NULL) {
+ expression_to_firm(statement->initialisation);
+ }
+
+ jmp = new_Jmp();
+ }
+
+
+ /* create the step block */
+ ir_node *const step_block = new_immBlock();
+ if (statement->step != NULL) {
+ expression_to_firm(statement->step);
+ }
+ ir_node *const step_jmp = new_Jmp();
+
+ /* create the header block */
+ ir_node *const header_block = new_immBlock();
+ if (jmp != NULL) {
+ add_immBlock_pred(header_block, jmp);
+ }
+ add_immBlock_pred(header_block, step_jmp);
+
+ /* the false block */
+ ir_node *const false_block = new_immBlock();
+
+ /* the loop body */
+ ir_node * body_block;
+ if (statement->body != NULL) {
+ ir_node *const old_continue_label = continue_label;
+ ir_node *const old_break_label = break_label;
+ continue_label = step_block;
+ break_label = false_block;
+
+ body_block = new_immBlock();
+ statement_to_firm(statement->body);
+
+ assert(continue_label == step_block);
+ assert(break_label == false_block);
+ continue_label = old_continue_label;
+ break_label = old_break_label;
+
+ if (get_cur_block() != NULL) {
+ jmp = new_Jmp();
+ add_immBlock_pred(step_block, jmp);
+ }
+ } else {
+ body_block = step_block;
+ }
+
+ /* create the condition */
+ set_cur_block(header_block);
+ if (statement->condition != NULL) {
+ create_condition_evaluation(statement->condition, body_block,
+ false_block);
+ } else {
+ keep_alive(header_block);
+ keep_all_memory(header_block);
+ jmp = new_Jmp();
+ add_immBlock_pred(body_block, jmp);
+ }
+
+ mature_immBlock(body_block);
+ mature_immBlock(false_block);
+ mature_immBlock(step_block);
+ mature_immBlock(header_block);
+ mature_immBlock(false_block);
+
+ set_cur_block(false_block);
+}
+
+static void create_jump_statement(const statement_t *statement,
+ ir_node *target_block)
+{
+ if (get_cur_block() == NULL)
+ return;
+
+ dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
+ ir_node *jump = new_d_Jmp(dbgi);
+ add_immBlock_pred(target_block, jump);
+
+ set_cur_block(NULL);
+}
+
+static ir_node *get_break_label(void)
+{
+ if (break_label == NULL) {
+ ir_node *cur_block = get_cur_block();
+ break_label = new_immBlock();
+ set_cur_block(cur_block);
+ }
+ return break_label;
+}
+
+static void switch_statement_to_firm(switch_statement_t *statement)
+{
+ dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
+
+ ir_node *expression = expression_to_firm(statement->expression);
+ ir_node *cond = new_d_Cond(dbgi, expression);
+
+ set_cur_block(NULL);
+
+ ir_node *const old_switch_cond = current_switch_cond;
+ ir_node *const old_break_label = break_label;
+ const bool old_saw_default_label = saw_default_label;
+ saw_default_label = false;
+ current_switch_cond = cond;
+ break_label = NULL;
+ switch_statement_t *const old_switch = current_switch;
+ current_switch = statement;
+
+ /* determine a free number for the default label */
+ unsigned long num_cases = 0;
+ long def_nr = 0;
+ for (case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+ if (l->expression == NULL) {
+ /* default case */
+ continue;
+ }
+ if (l->last_case >= l->first_case)
+ num_cases += l->last_case - l->first_case + 1;
+ if (l->last_case > def_nr)
+ def_nr = l->last_case;
+ }
+
+ if (def_nr == INT_MAX) {
+ /* Bad: an overflow will occurr, we cannot be sure that the
+ * maximum + 1 is a free number. Scan the values a second
+ * time to find a free number.
+ */
+ unsigned char *bits = xmalloc((num_cases + 7) >> 3);
+
+ memset(bits, 0, (num_cases + 7) >> 3);
+ for (case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+ if (l->expression == NULL) {
+ /* default case */
+ continue;
+ }
+ unsigned long start = l->first_case > 0 ? (unsigned long)l->first_case : 0;
+ if (start < num_cases && l->last_case >= 0) {
+ unsigned long end = (unsigned long)l->last_case < num_cases ?
+ (unsigned long)l->last_case : num_cases - 1;
+ for (unsigned long cns = start; cns <= end; ++cns) {
+ bits[cns >> 3] |= (1 << (cns & 7));
+ }
+ }
+ }
+ /* We look at the first num_cases constants:
+ * Either they are densed, so we took the last (num_cases)
+ * one, or they are non densed, so we will find one free
+ * there...
+ */
+ unsigned long i;
+ for (i = 0; i < num_cases; ++i)
+ if ((bits[i >> 3] & (1 << (i & 7))) == 0)
+ break;
+
+ free(bits);
+ def_nr = i;
+ } else {
+ ++def_nr;
+ }
+ statement->default_proj_nr = def_nr;
+
+ if (statement->body != NULL) {
+ statement_to_firm(statement->body);
+ }
+
+ if (get_cur_block() != NULL) {
+ ir_node *jmp = new_Jmp();
+ add_immBlock_pred(get_break_label(), jmp);
+ }
+
+ if (!saw_default_label) {
+ set_cur_block(get_nodes_block(cond));
+ ir_node *const proj = new_d_defaultProj(dbgi, cond,
+ statement->default_proj_nr);
+ add_immBlock_pred(get_break_label(), proj);
+ }
+
+ if (break_label != NULL) {
+ mature_immBlock(break_label);
+ }
+ set_cur_block(break_label);
+
+ assert(current_switch_cond == cond);
+ current_switch = old_switch;
+ current_switch_cond = old_switch_cond;
+ break_label = old_break_label;
+ saw_default_label = old_saw_default_label;