#include <libfirm/firm.h>
#include <libfirm/adt/obst.h>
+#include <libfirm/adt/bitfiddle.h>
#include <libfirm/be.h>
#include "ast2firm.h"
static ir_type *ir_type_void;
static ir_type *ir_type_int;
-static int next_value_number_function;
-static ir_node *continue_label;
-static ir_node *break_label;
-static ir_node *current_switch_cond;
-static bool saw_default_label;
-static ir_node **imature_blocks;
-static bool constant_folding;
+static int next_value_number_function;
+static ir_node *continue_label;
+static ir_node *break_label;
+static ir_node *current_switch_cond;
+static bool saw_default_label;
+static declaration_t **all_labels;
+static declaration_t **inner_functions;
+static int inner_function_idx;
+static ir_node *ijmp_list;
+static bool constant_folding;
+
+extern bool have_const_functions;
static const declaration_t *current_function_decl;
static ir_node *current_function_name;
static ir_node *current_funcsig;
static switch_statement_t *current_switch;
+static ir_graph *current_function;
static entitymap_t entitymap;
DECLARATION_KIND_ENUM_ENTRY,
DECLARATION_KIND_COMPOUND_TYPE_INCOMPLETE,
DECLARATION_KIND_COMPOUND_TYPE_COMPLETE,
- DECLARATION_KIND_TYPE
+ DECLARATION_KIND_TYPE,
+ DECLARATION_KIND_INNER_FUNCTION
} declaration_kind_t;
static ir_type *get_ir_type(type_t *type);
static ir_type *get_ir_type_incomplete(type_t *type);
static int count_decls_in_stmts(const statement_t *stmt);
+static void enqueue_inner_function(declaration_t *declaration) {
+ if (inner_functions == NULL) {
+ inner_functions = NEW_ARR_F(declaration_t *, 16);
+ inner_functions[0] = declaration;
+ inner_function_idx = 1;
+ } else {
+ int size = ARR_LEN(inner_functions);
+ if (inner_function_idx >= size) {
+ ARR_RESIZE(declaration_t *, inner_functions, size + 16);
+ }
+ inner_functions[inner_function_idx++] = declaration;
+ }
+}
+
+static declaration_t *next_inner_function(void) {
+ if (inner_function_idx == 0)
+ return 0;
+ return inner_functions[--inner_function_idx];
+}
+
ir_node *uninitialized_local_var(ir_graph *irg, ir_mode *mode, int pos)
{
const declaration_t *declaration = get_irg_loc_description(irg, pos);
assert(base->kind == TYPE_ATOMIC || base->kind == TYPE_ENUM);
ir_type *irbase = get_ir_type(base);
- unsigned size = fold_constant(type->size);
+ unsigned size = type->bit_size;
assert(!is_type_float(base));
if (is_type_signed(base)) {
size_t base;
size_t bits_remainder;
if (entry_type->kind == TYPE_BITFIELD) {
- size_t size_bits = fold_constant(entry_type->bitfield.size);
+ size_t size_bits = entry_type->bitfield.bit_size;
size_t rest_size_bits = (entry_alignment - misalign)*8 - bit_offset;
if (size_bits > rest_size_bits) {
ir_type *firm_type = NULL;
switch (type->kind) {
case TYPE_ERROR:
- panic("error type occurred");
+ /* Happens while constant folding, when there was an error */
+ return create_atomic_type(&type_void->atomic);
+
case TYPE_ATOMIC:
firm_type = create_atomic_type(&type->atomic);
break;
__attribute__((pure)) specifier. */
set_entity_additional_property(ent, mtp_property_pure);
}
+ if (decl->modifiers & DM_CONST) {
+ set_entity_additional_property(ent, mtp_property_const);
+ have_const_functions = true;
+ }
if (decl->modifiers & DM_USED) {
/* TRUE if the declaration includes the GNU
__attribute__((used)) specifier. */
*/
static ir_entity *get_function_entity(declaration_t *declaration)
{
- if (declaration->declaration_kind == DECLARATION_KIND_FUNCTION)
+ if (declaration->declaration_kind == DECLARATION_KIND_FUNCTION ||
+ declaration->declaration_kind == DECLARATION_KIND_INNER_FUNCTION)
return declaration->v.entity;
assert(declaration->declaration_kind == DECLARATION_KIND_UNKNOWN);
return new_d_Conv(dbgi, value, dest_mode);
}
+/**
+ * Keep all memory edges of the given block.
+ */
+static void keep_all_memory(ir_node *block) {
+ ir_node *old = get_cur_block();
+
+ set_cur_block(block);
+ keep_alive(get_store());
+ /* TODO: keep all memory edges from restricted pointers */
+ set_cur_block(old);
+}
+
static ir_node *reference_expression_to_firm(const reference_expression_t *ref)
{
dbg_info *dbgi = get_dbg_info(&ref->base.source_position);
/* make sure the type is constructed */
(void) get_ir_type(type);
- switch((declaration_kind_t) declaration->declaration_kind) {
+ switch ((declaration_kind_t)declaration->declaration_kind) {
case DECLARATION_KIND_TYPE:
case DECLARATION_KIND_UNKNOWN:
break;
case DECLARATION_KIND_ENUM_ENTRY: {
ir_mode *const mode = get_ir_mode(type);
- return new_Const(mode, declaration->v.enum_val);
+ if (ref->is_outer_ref) {
+ /* reference to an outer variable */
+ panic("Outer variable reference not implemented");
+ } else {
+ return new_Const(mode, declaration->v.enum_val);
+ }
}
case DECLARATION_KIND_LOCAL_VARIABLE: {
ir_mode *const mode = get_ir_mode(type);
return create_symconst(dbgi, mode, declaration->v.entity);
}
+ case DECLARATION_KIND_INNER_FUNCTION: {
+ ir_mode *const mode = get_ir_mode(type);
+ if (! declaration->goto_to_outer && !declaration->need_closure) {
+ /* inner function not using the closure */
+ return create_symconst(dbgi, mode, declaration->v.entity);
+ } else {
+ /* TODO: need trampoline here */
+ panic("Trampoline code not implemented");
+ return create_symconst(dbgi, mode, declaration->v.entity);
+ }
+ }
case DECLARATION_KIND_GLOBAL_VARIABLE: {
ir_node *const addr = get_global_var_address(dbgi, declaration);
return deref_address(dbgi, declaration->type, addr);
/* you can store to a local variable (so we don't panic but return NULL
* as an indicator for no real address) */
return NULL;
- case DECLARATION_KIND_FUNCTION: {
- type_t *const type = skip_typeref(ref->base.type);
- ir_mode *const mode = get_ir_mode(type);
- return create_symconst(dbgi, mode, declaration->v.entity);
- }
case DECLARATION_KIND_GLOBAL_VARIABLE: {
ir_node *const addr = get_global_var_address(dbgi, declaration);
return addr;
case DECLARATION_KIND_ENUM_ENTRY:
panic("trying to reference enum entry");
+ case DECLARATION_KIND_FUNCTION: {
+ type_t *const type = skip_typeref(declaration->type);
+ ir_mode *const mode = get_ir_mode(type);
+ return create_symconst(dbgi, mode, declaration->v.entity);
+ }
+
+ case DECLARATION_KIND_INNER_FUNCTION:
case DECLARATION_KIND_COMPOUND_TYPE_INCOMPLETE:
case DECLARATION_KIND_COMPOUND_TYPE_COMPLETE:
case DECLARATION_KIND_COMPOUND_MEMBER:
return res;
}
- case T___builtin_huge_val: {
+
+ case T___builtin_huge_val:
+ case T___builtin_inf:
+ case T___builtin_inff:
+ case T___builtin_infl: {
ir_mode *mode = get_ir_mode(function_type->function.return_type);
tarval *tv = get_mode_infinite(mode);
ir_node *res = new_d_Const(dbgi, mode, tv);
}
case T___builtin_nan:
case T___builtin_nanf:
- case T___builtin_nand: {
+ case T___builtin_nanl: {
/* Ignore string for now... */
assert(is_type_function(function_type));
ir_mode *mode = get_ir_mode(function_type->function.return_type);
if (declaration->v.entity == rts_entities[rts_alloca]) {
/* handle alloca() call */
expression_t *argument = call->arguments->expression;
- ir_node *size = expression_to_firm(argument);
+ ir_node *size = expression_to_firm(argument);
- size = create_conv(dbgi, size, get_ir_mode(type_size_t));
+ size = create_conv(dbgi, size, get_ir_mode(type_size_t));
- ir_node *store = get_store();
- dbg_info *dbgi = get_dbg_info(&call->base.source_position);
- ir_node *alloca = new_d_Alloc(dbgi, store, size, firm_unknown_type,
- stack_alloc);
- ir_node *proj_m = new_Proj(alloca, mode_M, pn_Alloc_M);
+ ir_node *store = get_store();
+ dbg_info *dbgi = get_dbg_info(&call->base.source_position);
+ ir_node *alloca = new_d_Alloc(dbgi, store, size, firm_unknown_type,
+ stack_alloc);
+ ir_node *proj_m = new_Proj(alloca, mode_M, pn_Alloc_M);
set_store(proj_m);
- ir_node *res = new_Proj(alloca, mode_P_data, pn_Alloc_res);
+ ir_node *res = new_Proj(alloca, mode_P_data, pn_Alloc_res);
return res;
}
result = new_d_Proj(dbgi, resproj, mode, 0);
}
+ if (function->kind == EXPR_REFERENCE &&
+ function->reference.declaration->modifiers & DM_NORETURN) {
+ /* A dead end: Keep the Call and the Block. Also place all further
+ * nodes into a new and unreachable block. */
+ keep_alive(node);
+ keep_alive(get_cur_block());
+ new_Block(0, NULL);
+ }
+
return result;
}
return mask1;
}
-static void bitfield_store_to_firm(const select_expression_t *expression,
- ir_node *addr, ir_node *value)
+static void bitfield_store_to_firm(dbg_info *dbgi,
+ ir_entity *entity, ir_node *addr, ir_node *value, bool set_volatile)
{
- type_t *type = expression->base.type;
- ir_mode *mode = get_ir_mode(type);
-
- assert(get_irn_mode(value) == mode || is_Bad(value));
+ ir_type *entity_type = get_entity_type(entity);
+ ir_type *base_type = get_primitive_base_type(entity_type);
+ assert(base_type != NULL);
+ ir_mode *mode = get_type_mode(base_type);
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ value = create_conv(dbgi, value, mode);
/* kill upper bits of value and shift to right position */
- ir_entity *entity = expression->compound_entry->v.entity;
- int bitoffset = get_entity_offset_bits_remainder(entity);
- ir_type *entity_type = get_entity_type(entity);
- int bitsize = get_mode_size_bits(get_type_mode(entity_type));
+ int bitoffset = get_entity_offset_bits_remainder(entity);
+ int bitsize = get_mode_size_bits(get_type_mode(entity_type));
tarval *mask = create_bitfield_mask(mode, 0, bitsize);
ir_node *mask_node = new_d_Const(dbgi, mode, mask);
ir_node *store_mem = new_d_Proj(dbgi, store, mode_M, pn_Store_M);
set_store(store_mem);
- if (type->base.qualifiers & TYPE_QUALIFIER_VOLATILE) {
+ if (set_volatile) {
set_Load_volatility(load, volatility_is_volatile);
set_Store_volatility(store, volatility_is_volatile);
}
declaration_t *declaration = select->compound_entry;
if (declaration->type->kind == TYPE_BITFIELD) {
- bitfield_store_to_firm(select, addr, value);
+ ir_entity *entity = select->compound_entry->v.entity;
+ bool set_volatile
+ = select->base.type->base.qualifiers & TYPE_QUALIFIER_VOLATILE;
+ bitfield_store_to_firm(dbgi, entity, addr, value, set_volatile);
return;
}
}
mature_immBlock(one_block);
mature_immBlock(zero_block);
- ir_node *common_block = new_immBlock();
- add_immBlock_pred(common_block, jmp_one);
- add_immBlock_pred(common_block, jmp_zero);
- mature_immBlock(common_block);
+ ir_node *in_cf[2] = { jmp_one, jmp_zero };
+ new_Block(2, in_cf);
ir_node *in[2] = { one, zero };
ir_node *val = new_d_Phi(dbgi, 2, in, mode);
dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
const expression_t *left_expr = expression->left;
ir_mode *left_mode = get_ir_mode(left_expr->base.type);
+ ir_node *right = expression_to_firm(expression->right);
ir_node *left_addr = expression_to_addr(left_expr);
ir_node *left = get_value_from_lvalue(left_expr, left_addr);
- ir_node *right = expression_to_firm(expression->right);
ir_node *result = create_op(dbgi, expression, left, right);
result = create_conv(dbgi, result, left_mode);
expression_t *array_index = designator->array_index;
assert(designator->array_index != NULL);
assert(is_type_array(type));
- assert(is_type_valid(array_index->base.type));
long index = fold_constant(array_index);
ir_type *arr_type = get_ir_type(type);
long fold_constant(const expression_t *expression)
{
+ assert(is_type_valid(skip_typeref(expression->base.type)));
+
bool constant_folding_old = constant_folding;
constant_folding = true;
mature_immBlock(false_block);
/* create the common block */
- ir_node *common_block = new_immBlock();
- add_immBlock_pred(common_block, true_jmp);
- add_immBlock_pred(common_block, false_jmp);
- mature_immBlock(common_block);
+ ir_node *in_cf[2] = { true_jmp, false_jmp };
+ new_Block(2, in_cf);
/* TODO improve static semantics, so either both or no values are NULL */
if (true_val == NULL || false_val == NULL)
return NULL;
}
+static ir_node *get_label_block(declaration_t *label)
+{
+ assert(label->namespc == NAMESPACE_LABEL || label->namespc == NAMESPACE_LOCAL_LABEL);
+
+ if (label->declaration_kind == DECLARATION_KIND_LABEL_BLOCK) {
+ return label->v.block;
+ }
+ assert(label->declaration_kind == DECLARATION_KIND_UNKNOWN);
+
+ /* beware: might be called from create initializer with current_ir_graph
+ * set to const_code_irg. */
+ ir_graph *rem = current_ir_graph;
+ current_ir_graph = current_function;
+
+ ir_node *old_cur_block = get_cur_block();
+ ir_node *block = new_immBlock();
+ set_cur_block(old_cur_block);
+
+ label->declaration_kind = DECLARATION_KIND_LABEL_BLOCK;
+ label->v.block = block;
+
+ ARR_APP1(declaration_t *, all_labels, label);
+
+ current_ir_graph = rem;
+ return block;
+}
+
+/**
+ * Pointer to a label. This is used for the
+ * GNU address-of-label extension.
+ */
+static ir_node *label_address_to_firm(
+ const label_address_expression_t *label)
+{
+ ir_node *block = get_label_block(label->declaration);
+ ir_label_t nr = get_Block_label(block);
+
+ if (nr == 0) {
+ nr = get_irp_next_label_nr();
+ set_Block_label(block, nr);
+ }
+ symconst_symbol value;
+ value.label = nr;
+ return new_SymConst(mode_P_code, value, symconst_label);
+}
+
/**
* creates firm nodes for an expression. The difference between this function
* and expression_to_firm is, that this version might produce mode_b nodes
}
#endif
- switch(expression->kind) {
+ switch (expression->kind) {
case EXPR_CHARACTER_CONSTANT:
return character_constant_to_firm(&expression->conste);
case EXPR_WIDE_CHARACTER_CONSTANT:
return offsetof_to_firm(&expression->offsetofe);
case EXPR_COMPOUND_LITERAL:
return compound_literal_to_firm(&expression->compound_literal);
+ case EXPR_LABEL_ADDRESS:
+ return label_address_to_firm(&expression->label_address);
case EXPR_UNKNOWN:
case EXPR_INVALID:
dbg_info *const dbgi = get_dbg_info(&declaration->source_position);
ir_entity *const entity = new_d_entity(parent_type, id, irtype, dbgi);
+ handle_gnu_attributes_ent(entity, declaration);
+
declaration->declaration_kind = (unsigned char) declaration_kind;
declaration->v.entity = entity;
set_entity_variability(entity, variability_uninitialized);
expression_t *array_index = designator->array_index;
assert(designator->array_index != NULL);
assert(is_type_array(type));
- assert(is_type_valid(array_index->base.type));
long index = fold_constant(array_index);
assert(index >= 0);
#ifndef NDEBUG
- if (type->array.size_constant == 1) {
+ if (type->array.size_constant) {
long array_size = type->array.size;
assert(index < array_size);
}
}
static void create_dynamic_initializer_sub(ir_initializer_t *initializer,
- ir_type *type, dbg_info *dbgi, ir_node *base_addr)
+ ir_entity *entity, ir_type *type, dbg_info *dbgi, ir_node *base_addr)
{
switch(get_initializer_kind(initializer)) {
case IR_INITIALIZER_NULL: {
return;
}
case IR_INITIALIZER_CONST: {
- ir_node *node = get_initializer_const_value(initializer);
- ir_mode *mode = get_irn_mode(node);
- assert(get_type_mode(type) == mode);
+ ir_node *node = get_initializer_const_value(initializer);
+ ir_mode *mode = get_irn_mode(node);
+ ir_type *ent_type = get_entity_type(entity);
+
+ /* is it a bitfield type? */
+ if (is_Primitive_type(ent_type) &&
+ get_primitive_base_type(ent_type) != NULL) {
+ bitfield_store_to_firm(dbgi, entity, base_addr, node, false);
+ return;
+ }
- /* TODO: bitfields... */
+ assert(get_type_mode(type) == mode);
ir_node *mem = get_store();
ir_node *store = new_d_Store(dbgi, mem, base_addr, node);
ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
return;
}
case IR_INITIALIZER_TARVAL: {
- tarval *tv = get_initializer_tarval_value(initializer);
- ir_mode *mode = get_tarval_mode(tv);
- ir_node *cnst = new_d_Const(dbgi, mode, tv);
- assert(get_type_mode(type) == mode);
+ tarval *tv = get_initializer_tarval_value(initializer);
+ ir_mode *mode = get_tarval_mode(tv);
+ ir_node *cnst = new_d_Const(dbgi, mode, tv);
+ ir_type *ent_type = get_entity_type(entity);
+
+ /* is it a bitfield type? */
+ if (is_Primitive_type(ent_type) &&
+ get_primitive_base_type(ent_type) != NULL) {
+ bitfield_store_to_firm(dbgi, entity, base_addr, cnst, false);
+ return;
+ }
- /* TODO: bitfields... */
+ assert(get_type_mode(type) == mode);
ir_node *mem = get_store();
ir_node *store = new_d_Store(dbgi, mem, base_addr, cnst);
ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
panic("initializer doesn't match compound type");
for(int i = 0; i < n_members; ++i) {
- ir_node *addr;
- ir_type *irtype;
+ ir_node *addr;
+ ir_type *irtype;
+ ir_entity *sub_entity;
if (is_Array_type(type)) {
- ir_entity *entity = get_array_element_entity(type);
tarval *index_tv = new_tarval_from_long(i, mode_uint);
ir_node *cnst = new_d_Const(dbgi, mode_uint, index_tv);
ir_node *in[1] = { cnst };
- irtype = get_array_element_type(type);
- addr = new_d_Sel(dbgi, new_NoMem(), base_addr, 1, in, entity);
+ irtype = get_array_element_type(type);
+ sub_entity = get_array_element_entity(type);
+ addr = new_d_Sel(dbgi, new_NoMem(), base_addr, 1, in,
+ sub_entity);
} else {
- ir_entity *member = get_compound_member(type, i);
-
- irtype = get_entity_type(member);
- addr = new_d_simpleSel(dbgi, new_NoMem(), base_addr, member);
+ sub_entity = get_compound_member(type, i);
+ irtype = get_entity_type(sub_entity);
+ addr = new_d_simpleSel(dbgi, new_NoMem(), base_addr,
+ sub_entity);
}
ir_initializer_t *sub_init
= get_initializer_compound_value(initializer, i);
- create_dynamic_initializer_sub(sub_init, irtype, dbgi, addr);
+ create_dynamic_initializer_sub(sub_init, sub_entity, irtype, dbgi,
+ addr);
}
return;
}
ir_node *base_addr = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
ir_type *type = get_entity_type(entity);
- create_dynamic_initializer_sub(initializer, type, dbgi, base_addr);
+ create_dynamic_initializer_sub(initializer, entity, type, dbgi, base_addr);
}
static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
return;
}
- type_t *type = skip_typeref(declaration->type);
+ type_t *type = declaration->type;
+ type_qualifiers_t tq = get_type_qualifier(type, true);
if (initializer->kind == INITIALIZER_VALUE) {
initializer_value_t *initializer_value = &initializer->value;
ir_entity *entity = declaration->v.entity;
- if (type->base.qualifiers & TYPE_QUALIFIER_CONST) {
+ if (tq & TYPE_QUALIFIER_CONST) {
set_entity_variability(entity, variability_constant);
} else {
set_entity_variability(entity, variability_initialized);
set_atomic_ent_value(entity, value);
}
} else {
- assert(declaration_kind == DECLARATION_KIND_LOCAL_VARIABLE_ENTITY
- || declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE);
+ assert(declaration_kind == DECLARATION_KIND_LOCAL_VARIABLE_ENTITY ||
+ declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE);
ir_entity *entity = declaration->v.entity;
ir_initializer_t *irinitializer
= create_ir_initializer(initializer, type);
- if (type->base.qualifiers & TYPE_QUALIFIER_CONST) {
+ if (tq & TYPE_QUALIFIER_CONST) {
set_entity_variability(entity, variability_constant);
} else {
set_entity_variability(entity, variability_initialized);
case STORAGE_CLASS_REGISTER:
if (is_type_function(type)) {
if (declaration->init.statement != NULL) {
- panic("nested functions not supported yet");
+ get_function_entity(declaration);
+ declaration->declaration_kind = DECLARATION_KIND_INNER_FUNCTION;
+ enqueue_inner_function(declaration);
} else {
get_function_entity(declaration);
}
case DECLARATION_KIND_FUNCTION:
case DECLARATION_KIND_TYPE:
case DECLARATION_KIND_ENUM_ENTRY:
+ case DECLARATION_KIND_INNER_FUNCTION:
return;
case DECLARATION_KIND_UNKNOWN:
- panic("can't initialize unknwon declaration");
+ panic("can't initialize unknown declaration");
}
panic("invalid declaration kind");
}
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();
for( ; declaration != NULL; declaration = declaration->next) {
create_local_declaration(declaration);
}
- declaration = statement->scope.declarations;
- for( ; declaration != NULL; declaration = declaration->next) {
- initialize_local_declaration(declaration);
- }
if (get_cur_block() != NULL) {
+ declaration = statement->scope.declarations;
+ for( ; declaration != NULL; declaration = declaration->next) {
+ initialize_local_declaration(declaration);
+ }
+
if (statement->initialisation != NULL) {
expression_to_firm(statement->initialisation);
}
false_block);
} else {
keep_alive(header_block);
+ keep_all_memory(header_block);
jmp = new_Jmp();
add_immBlock_pred(body_block, jmp);
}
static void case_label_to_firm(const case_label_statement_t *statement)
{
- if (statement->is_empty)
+ if (statement->is_empty_range)
return;
dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
}
}
-static ir_node *get_label_block(declaration_t *label)
-{
- assert(label->namespc == NAMESPACE_LABEL);
-
- if (label->declaration_kind == DECLARATION_KIND_LABEL_BLOCK) {
- return label->v.block;
- }
- assert(label->declaration_kind == DECLARATION_KIND_UNKNOWN);
-
- ir_node *old_cur_block = get_cur_block();
- ir_node *block = new_immBlock();
- set_cur_block(old_cur_block);
-
- label->declaration_kind = DECLARATION_KIND_LABEL_BLOCK;
- label->v.block = block;
-
- ARR_APP1(ir_node *, imature_blocks, block);
-
- return block;
-}
-
static void label_to_firm(const label_statement_t *statement)
{
ir_node *block = get_label_block(statement->label);
set_cur_block(block);
keep_alive(block);
+ keep_all_memory(block);
if (statement->statement != NULL) {
statement_to_firm(statement->statement);
if (get_cur_block() == NULL)
return;
- ir_node *block = get_label_block(statement->label);
- ir_node *jmp = new_Jmp();
- add_immBlock_pred(block, jmp);
+ if (statement->expression) {
+ ir_node *irn = expression_to_firm(statement->expression);
+ dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
+ ir_node *ijmp = new_d_IJmp(dbgi, irn);
+ set_irn_link(ijmp, ijmp_list);
+ ijmp_list = ijmp;
+ } else {
+ if (statement->outer_fkt_jmp) {
+ /* TODO: this is a outer function jmp */
+ panic("outer function jump not implemented");
+ } else {
+ ir_node *block = get_label_block(statement->label);
+ ir_node *jmp = new_Jmp();
+ add_immBlock_pred(block, jmp);
+ }
+ }
set_cur_block(NULL);
}
case EXPR_BUILTIN_SYMBOL:
case EXPR_VA_START:
case EXPR_VA_ARG:
+ case EXPR_LABEL_ADDRESS:
break;
}
set_atomic_ent_value(ptr, val);
}
+/**
+ * Generate possible IJmp branches to a given label block.
+ */
+static void gen_ijmp_branches(ir_node *block) {
+ ir_node *ijmp;
+ for (ijmp = ijmp_list; ijmp != NULL; ijmp = get_irn_link(ijmp)) {
+ add_immBlock_pred(block, ijmp);
+ }
+}
+
/**
* Create code for a function.
*/
current_function_name = NULL;
current_funcsig = NULL;
- assert(imature_blocks == NULL);
- imature_blocks = NEW_ARR_F(ir_node*, 0);
+ assert(all_labels == NULL);
+ all_labels = NEW_ARR_F(declaration_t *, 0);
+ ijmp_list = NULL;
int n_local_vars = get_function_n_local_vars(declaration);
ir_graph *irg = new_ir_graph(function_entity, n_local_vars);
+ ir_graph *old_current_function = current_function;
+ current_function = irg;
+
set_irg_fp_model(irg, firm_opt.fp_model);
tarval_enable_fp_ops((firm_opt.fp_model & fp_strict_algebraic) == 0);
set_irn_dbg_info(get_irg_start_block(irg), get_entity_dbg_info(function_entity));
add_immBlock_pred(end_block, ret);
}
- for(int i = 0; i < ARR_LEN(imature_blocks); ++i) {
- mature_immBlock(imature_blocks[i]);
+ bool has_computed_gotos = false;
+ for (int i = ARR_LEN(all_labels) - 1; i >= 0; --i) {
+ declaration_t *label = all_labels[i];
+ if (label->address_taken) {
+ gen_ijmp_branches(label->v.block);
+ has_computed_gotos = true;
+ }
+ mature_immBlock(label->v.block);
+ }
+ if (has_computed_gotos) {
+ /* if we have computed goto's in the function, we cannot inline it */
+ if (get_irg_inline_property(irg) >= irg_inline_recomended) {
+ warningf(&declaration->source_position,
+ "function '%Y' can never be inlined because it contains a computed goto",
+ declaration->symbol);
+ }
+ set_irg_inline_property(irg, irg_inline_forbidden);
}
- DEL_ARR_F(imature_blocks);
- imature_blocks = NULL;
+
+ DEL_ARR_F(all_labels);
+ all_labels = NULL;
mature_immBlock(first_block);
mature_immBlock(end_block);
set_type_alignment_bytes(frame_type, align_all);
irg_vrfy(irg);
+ current_function = old_current_function;
}
static void scope_to_firm(scope_t *scope)
type_t *type = declaration->type;
if (type->kind == TYPE_FUNCTION) {
create_function(declaration);
+ declaration_t *inner;
+ for (inner = next_inner_function(); inner != NULL;
+ inner = next_inner_function())
+ create_function(inner);
} else {
assert(declaration->declaration_kind
== DECLARATION_KIND_GLOBAL_VARIABLE);
}
}
+static void set_be_option(const char *option)
+{
+ int res = firm_be_option(option);
+ assert(res);
+}
+
void init_ast2firm(void)
{
obstack_init(&asm_obst);
id_imp = new_id_from_chars("__imp_", 6);
/* OS option must be set to the backend */
- const char *s = "ia32-gasmode=linux";
switch (firm_opt.os_support) {
case OS_SUPPORT_MINGW:
create_ld_ident = create_ld_ident_win32;
- s = "ia32-gasmode=mingw";
+ set_be_option("ia32-gasmode=mingw");
break;
case OS_SUPPORT_LINUX:
create_ld_ident = create_ld_ident_linux_elf;
- s = "ia32-gasmode=elf";
+ set_be_option("ia32-gasmode=elf");
break;
case OS_SUPPORT_MACHO:
create_ld_ident = create_ld_ident_macho;
- s = "ia32-gasmode=macho";
+ set_be_option("ia32-gasmode=macho");
+ set_be_option("ia32-stackalign=4");
+ set_be_option("pic");
break;
}
- int res = firm_be_option(s);
- (void) res;
- assert(res);
/* create idents for all known runtime functions */
for (size_t i = 0; i < sizeof(rts_data) / sizeof(rts_data[0]); ++i) {
scope_to_firm(&unit->scope);
global_asm_to_firm(unit->global_asm);
+
+ current_ir_graph = NULL;
}