+static void create_local_static_variable(declaration_t *declaration)
+{
+ assert(declaration->declaration_kind == DECLARATION_KIND_UNKNOWN);
+
+ type_t *const type = skip_typeref(declaration->type);
+ ir_type *const global_type = get_glob_type();
+ ir_type *const irtype = get_ir_type(type);
+ dbg_info *const dbgi = get_dbg_info(&declaration->source_position);
+
+ size_t l = strlen(declaration->symbol->string);
+ char buf[l + sizeof(".%u")];
+ snprintf(buf, sizeof(buf), "%s.%%u", declaration->symbol->string);
+ ident *const id = id_unique(buf);
+
+ ir_entity *const entity = new_d_entity(global_type, id, irtype, dbgi);
+
+ if(type->base.qualifiers & TYPE_QUALIFIER_VOLATILE) {
+ set_entity_volatility(entity, volatility_is_volatile);
+ }
+
+ declaration->declaration_kind = DECLARATION_KIND_GLOBAL_VARIABLE;
+ declaration->v.entity = entity;
+ set_entity_ld_ident(entity, create_ld_ident(entity, declaration));
+ set_entity_variability(entity, variability_uninitialized);
+ set_entity_visibility(entity, visibility_local);
+ set_entity_allocation(entity, allocation_static);
+
+ ir_graph *const old_current_ir_graph = current_ir_graph;
+ current_ir_graph = get_const_code_irg();
+
+ create_declaration_initializer(declaration);
+
+ assert(current_ir_graph == get_const_code_irg());
+ current_ir_graph = old_current_ir_graph;
+}
+
+
+
+static void return_statement_to_firm(return_statement_t *statement)
+{
+ if(get_cur_block() == NULL)
+ return;
+
+ dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
+ ir_type *func_irtype = get_ir_type(current_function_decl->type);
+
+
+ ir_node *in[1];
+ int in_len;
+ if(get_method_n_ress(func_irtype) > 0) {
+ ir_type *res_type = get_method_res_type(func_irtype, 0);
+
+ if(statement->value != NULL) {
+ ir_node *node = expression_to_firm(statement->value);
+ node = do_strict_conv(dbgi, node);
+ in[0] = node;
+ } else {
+ ir_mode *mode;
+ if(is_compound_type(res_type)) {
+ mode = mode_P_data;
+ } else {
+ mode = get_type_mode(res_type);
+ }
+ in[0] = new_Unknown(mode);
+ }
+ in_len = 1;
+ } else {
+ /* build return_value for its side effects */
+ if(statement->value != NULL) {
+ expression_to_firm(statement->value);
+ }
+ in_len = 0;
+ }
+
+ ir_node *store = get_store();
+ ir_node *ret = new_d_Return(dbgi, store, in_len, in);
+
+ ir_node *end_block = get_irg_end_block(current_ir_graph);
+ add_immBlock_pred(end_block, ret);
+
+ set_cur_block(NULL);
+}
+
+static ir_node *expression_statement_to_firm(expression_statement_t *statement)
+{
+ if(get_cur_block() == NULL)
+ return NULL;
+
+ return expression_to_firm(statement->expression);
+}
+
+static ir_node *compound_statement_to_firm(compound_statement_t *compound)
+{
+ declaration_t *declaration = compound->scope.declarations;
+ for( ; declaration != NULL; declaration = declaration->next) {
+ create_local_declaration(declaration);
+ }
+
+ ir_node *result = NULL;
+ statement_t *statement = compound->statements;
+ for( ; statement != NULL; statement = statement->base.next) {
+ if(statement->base.next == NULL
+ && statement->kind == STATEMENT_EXPRESSION) {
+ result = expression_statement_to_firm(
+ &statement->expression);
+ break;
+ }
+ statement_to_firm(statement);
+ }
+
+ return result;
+}
+
+static void create_global_variable(declaration_t *declaration)
+{
+ ir_visibility vis;
+ ir_type *var_type;
+ switch ((storage_class_tag_t)declaration->storage_class) {
+ case STORAGE_CLASS_STATIC:
+ vis = visibility_local;
+ goto global_var;
+
+ case STORAGE_CLASS_EXTERN:
+ vis = visibility_external_allocated;
+ goto global_var;
+
+ case STORAGE_CLASS_NONE:
+ vis = visibility_external_visible;
+ goto global_var;
+
+ case STORAGE_CLASS_THREAD:
+ vis = visibility_external_visible;
+ goto tls_var;
+
+ case STORAGE_CLASS_THREAD_EXTERN:
+ vis = visibility_external_allocated;
+ goto tls_var;
+
+ case STORAGE_CLASS_THREAD_STATIC:
+ vis = visibility_local;
+ goto tls_var;
+
+tls_var:
+ var_type = get_tls_type();
+ goto create_var;
+
+global_var:
+ var_type = get_glob_type();
+ goto create_var;
+
+create_var:
+ create_declaration_entity(declaration,
+ DECLARATION_KIND_GLOBAL_VARIABLE,
+ var_type);
+ set_entity_visibility(declaration->v.entity, vis);
+
+ return;
+
+ case STORAGE_CLASS_TYPEDEF:
+ case STORAGE_CLASS_AUTO:
+ case STORAGE_CLASS_REGISTER:
+ case STORAGE_CLASS_ENUM_ENTRY:
+ break;
+ }
+ panic("Invalid storage class for global variable");
+}
+
+static void create_local_declaration(declaration_t *declaration)
+{
+ if (declaration->namespc != NAMESPACE_NORMAL)
+ return;
+ /* construct type */
+ (void) get_ir_type(declaration->type);
+ if (declaration->symbol == NULL) {
+ return;
+ }
+
+ type_t *type = skip_typeref(declaration->type);
+
+ switch ((storage_class_tag_t) declaration->storage_class) {
+ case STORAGE_CLASS_STATIC:
+ create_local_static_variable(declaration);
+ return;
+ case STORAGE_CLASS_EXTERN:
+ create_global_variable(declaration);
+ create_declaration_initializer(declaration);
+ return;
+ case STORAGE_CLASS_NONE:
+ case STORAGE_CLASS_AUTO:
+ case STORAGE_CLASS_REGISTER:
+ if(is_type_function(type)) {
+ if(declaration->init.statement != NULL) {
+ panic("nested functions not supported yet");
+ } else {
+ get_function_entity(declaration);
+ }
+ } else {
+ create_local_variable(declaration);
+ }
+ return;
+ case STORAGE_CLASS_ENUM_ENTRY:
+ case STORAGE_CLASS_TYPEDEF:
+ case STORAGE_CLASS_THREAD:
+ case STORAGE_CLASS_THREAD_EXTERN:
+ case STORAGE_CLASS_THREAD_STATIC:
+ return;
+ }
+ panic("invalid storage class found");
+}
+
+static void initialize_local_declaration(declaration_t *declaration)
+{
+ if(declaration->symbol == NULL || declaration->namespc != NAMESPACE_NORMAL)
+ return;
+
+ switch ((declaration_kind_t) declaration->declaration_kind) {
+ case DECLARATION_KIND_LOCAL_VARIABLE:
+ case DECLARATION_KIND_LOCAL_VARIABLE_ENTITY:
+ create_declaration_initializer(declaration);
+ return;
+
+ case DECLARATION_KIND_LABEL_BLOCK:
+ case DECLARATION_KIND_COMPOUND_MEMBER:
+ case DECLARATION_KIND_GLOBAL_VARIABLE:
+ case DECLARATION_KIND_VARIABLE_LENGTH_ARRAY:
+ case DECLARATION_KIND_COMPOUND_TYPE_INCOMPLETE:
+ case DECLARATION_KIND_COMPOUND_TYPE_COMPLETE:
+ case DECLARATION_KIND_FUNCTION:
+ case DECLARATION_KIND_ENUM_ENTRY:
+ return;
+
+ case DECLARATION_KIND_UNKNOWN:
+ panic("can't initialize unknwon declaration");
+ }
+ panic("invalid declaration kind");
+}
+
+static void declaration_statement_to_firm(declaration_statement_t *statement)
+{
+ declaration_t *declaration = statement->declarations_begin;
+ declaration_t *end = statement->declarations_end->next;
+ for( ; declaration != end; declaration = declaration->next) {
+ if(declaration->namespc != NAMESPACE_NORMAL)
+ continue;
+ initialize_local_declaration(declaration);
+ }
+}
+
+static void if_statement_to_firm(if_statement_t *statement)
+{
+ ir_node *cur_block = get_cur_block();
+
+ ir_node *fallthrough_block = new_immBlock();
+
+ /* the true (blocks) */
+ ir_node *true_block;
+ 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();
+ add_immBlock_pred(fallthrough_block, jmp);
+ }
+ } else {
+ true_block = fallthrough_block;
+ }
+
+ /* the false (blocks) */
+ ir_node *false_block;
+ 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();
+ add_immBlock_pred(fallthrough_block, jmp);
+ }
+ } else {
+ false_block = fallthrough_block;
+ }
+
+ /* create the condition */
+ if(cur_block != NULL) {
+ set_cur_block(cur_block);
+ create_condition_evaluation(statement->condition, true_block,
+ false_block);
+ }
+
+ mature_immBlock(true_block);
+ if(false_block != fallthrough_block) {
+ mature_immBlock(false_block);
+ }
+ 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 false block */
+ ir_node *false_block = new_immBlock();
+
+ /* the loop body */
+ ir_node *body_block;
+ if (statement->body != NULL) {
+ ir_node *old_continue_label = continue_label;
+ ir_node *old_break_label = break_label;
+ continue_label = header_block;
+ break_label = false_block;
+
+ body_block = new_immBlock();
+ statement_to_firm(statement->body);
+
+ assert(continue_label == header_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(header_block, jmp);
+ }
+ } else {
+ body_block = header_block;
+ }
+
+ /* create the condition */
+ set_cur_block(header_block);
+
+ create_condition_evaluation(statement->condition, body_block, false_block);
+ mature_immBlock(body_block);
+ mature_immBlock(false_block);
+ mature_immBlock(header_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 false block */
+ ir_node *false_block = new_immBlock();
+
+ /* the loop body */
+ ir_node *body_block = new_immBlock();
+ if(jmp != NULL) {
+ add_immBlock_pred(body_block, jmp);
+ }
+
+ if (statement->body != NULL) {
+ ir_node *old_continue_label = continue_label;
+ ir_node *old_break_label = break_label;
+ continue_label = header_block;
+ break_label = false_block;
+
+ statement_to_firm(statement->body);
+
+ assert(continue_label == header_block);
+ assert(break_label == false_block);
+ continue_label = old_continue_label;
+ break_label = old_break_label;
+
+ if (get_cur_block() == NULL) {
+ mature_immBlock(header_block);
+ mature_immBlock(body_block);
+ mature_immBlock(false_block);
+ return;
+ }
+ }
+
+ ir_node *body_jmp = new_Jmp();
+ add_immBlock_pred(header_block, body_jmp);
+ mature_immBlock(header_block);
+
+ /* create the condition */
+ set_cur_block(header_block);
+
+ create_condition_evaluation(statement->condition, body_block, false_block);
+ mature_immBlock(body_block);
+ mature_immBlock(false_block);
+ mature_immBlock(header_block);
+
+ set_cur_block(false_block);
+}
+
+static void for_statement_to_firm(for_statement_t *statement)
+{
+ ir_node *jmp = NULL;
+ if (get_cur_block() != NULL) {
+ if(statement->initialisation != NULL) {
+ expression_to_firm(statement->initialisation);
+ }
+
+ /* create declarations */
+ declaration_t *declaration = statement->scope.declarations;
+ for( ; declaration != NULL; declaration = declaration->next) {
+ create_local_declaration(declaration);
+ initialize_local_declaration(declaration);
+ }
+
+ 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();