#include "ast2firm.h"
#include "adt/error.h"
+#include "adt/array.h"
#include "token_t.h"
#include "type_t.h"
#include "ast_t.h"
static type_t *type_void;
static type_t *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 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;
typedef enum declaration_type_t {
DECLARATION_TYPE_UNKNOWN,
DECLARATION_TYPE_GLOBAL_VARIABLE,
DECLARATION_TYPE_LOCAL_VARIABLE,
DECLARATION_TYPE_LOCAL_VARIABLE_ENTITY,
- DECLARATION_TYPE_COMPOUND_MEMBER
+ DECLARATION_TYPE_COMPOUND_MEMBER,
+ DECLARATION_TYPE_LABEL_BLOCK,
} declaration_type_t;
static ir_type *get_ir_type(type_t *type);
void init_ast2firm(void)
{
type_const_char = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_CONST);
- type_void = make_atomic_type(ATOMIC_TYPE_VOID, 0);
- type_int = make_atomic_type(ATOMIC_TYPE_INT, 0);
+ type_void = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
+ type_int = make_atomic_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
ir_type_int = get_ir_type(type_int);
ir_type_const_char = get_ir_type(type_const_char);
+static long fold_constant(const expression_t *expression);
+
static ir_type *create_atomic_type(const atomic_type_t *type)
{
ir_mode *mode = get_atomic_mode(type);
type_t *element_type = type->element_type;
ir_type *ir_element_type = get_ir_type(element_type);
- /* TODO... */
- int n_elements = 0;
- panic("TODO arraytpye size not implemented yet");
+ ident *id = unique_ident("array");
+ ir_type *ir_type = new_type_array(id, 1, ir_element_type);
+
+ if(type->size != NULL) {
+ int n_elements = fold_constant(type->size);
- ir_type *ir_type = new_type_array(unique_ident("array"), 1, ir_element_type);
- set_array_bounds_int(ir_type, 0, 0, n_elements);
+ set_array_bounds_int(ir_type, 0, 0, n_elements);
- size_t elemsize = get_type_size_bytes(ir_element_type);
- int align = get_type_alignment_bytes(ir_element_type);
- if(elemsize % align > 0) {
- elemsize += align - (elemsize % align);
+ size_t elemsize = get_type_size_bytes(ir_element_type);
+ int align = get_type_alignment_bytes(ir_element_type);
+ if(elemsize % align > 0) {
+ elemsize += align - (elemsize % align);
+ }
+ set_type_size_bytes(ir_type, n_elements * elemsize);
+ set_type_alignment_bytes(ir_type, align);
+ set_type_state(ir_type, layout_fixed);
}
- set_type_size_bytes(ir_type, n_elements * elemsize);
- set_type_alignment_bytes(ir_type, align);
- set_type_state(ir_type, layout_fixed);
return ir_type;
}
static inline ir_mode *get_ir_mode(type_t *type)
{
ir_type *irtype = get_ir_type(type);
- ir_mode *mode = get_type_mode(irtype);
+
+ /* firm doesn't report a mode for arrays somehow... */
+ if(is_Array_type(irtype)) {
+ return mode_P;
+ }
+
+ ir_mode *mode = get_type_mode(irtype);
assert(mode != NULL);
return mode;
}
ir_type *ir_type_method = get_ir_type(declaration->type);
assert(is_Method_type(ir_type_method));
- type_t *type = declaration->type;
ir_entity *entity = new_entity(global_type, id, ir_type_method);
set_entity_ld_ident(entity, id);
- if(declaration->storage_class & STORAGE_CLASS_STATIC
- || type->qualifiers & TYPE_QUALIFIER_INLINE) {
+ if(declaration->storage_class == STORAGE_CLASS_STATIC
+ || declaration->is_inline) {
set_entity_visibility(entity, visibility_local);
} else if(declaration->init.statement != NULL) {
set_entity_visibility(entity, visibility_external_visible);
{
dbg_info *dbgi = get_dbg_info(&ref->expression.source_position);
declaration_t *declaration = ref->declaration;
- type_t *type = declaration->type;
- ir_mode *mode = get_ir_mode(type);
+ type_t *type = skip_typeref(declaration->type);
switch((declaration_type_t) declaration->declaration_type) {
case DECLARATION_TYPE_UNKNOWN:
break;
- case DECLARATION_TYPE_LOCAL_VARIABLE:
+ case DECLARATION_TYPE_LOCAL_VARIABLE: {
+ ir_mode *mode = get_ir_mode(type);
return get_value(declaration->v.value_number, mode);
+ }
case DECLARATION_TYPE_FUNCTION: {
return create_symconst(dbgi, declaration->v.entity);
}
case DECLARATION_TYPE_GLOBAL_VARIABLE: {
ir_entity *entity = declaration->v.entity;
ir_node *symconst = create_symconst(dbgi, entity);
- return load_from_expression_addr(type, symconst, dbgi);
+
+ if(type->type == TYPE_ARRAY) {
+ return symconst;
+ } else {
+ return load_from_expression_addr(type, symconst, dbgi);
+ }
+ }
+ case DECLARATION_TYPE_LOCAL_VARIABLE_ENTITY: {
+ ir_entity *entity = declaration->v.entity;
+ ir_node *frame = get_irg_frame(current_ir_graph);
+ ir_node *sel = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
+
+ if(type->type == TYPE_ARRAY || type->type == TYPE_COMPOUND_STRUCT
+ || type->type == TYPE_COMPOUND_UNION) {
+ return sel;
+ } else {
+ return load_from_expression_addr(type, sel, dbgi);
+ }
}
- case DECLARATION_TYPE_LOCAL_VARIABLE_ENTITY:
+
case DECLARATION_TYPE_COMPOUND_MEMBER:
+ case DECLARATION_TYPE_LABEL_BLOCK:
panic("not implemented reference type");
}
ir_node *symconst = create_symconst(dbgi, entity);
return symconst;
}
- case DECLARATION_TYPE_LOCAL_VARIABLE_ENTITY:
+ case DECLARATION_TYPE_LOCAL_VARIABLE_ENTITY: {
+ ir_entity *entity = declaration->v.entity;
+ ir_node *frame = get_irg_frame(current_ir_graph);
+ ir_node *sel = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
+
+ return sel;
+ }
case DECLARATION_TYPE_COMPOUND_MEMBER:
+ case DECLARATION_TYPE_LABEL_BLOCK:
panic("not implemented reference type");
}
return res;
}
+static ir_node *create_shift(const binary_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *left = expression_to_firm(expression->left);
+ ir_node *right = expression_to_firm(expression->right);
+ type_t *type = expression->expression.datatype;
+ ir_mode *mode = get_ir_mode(type);
+
+ /* firm always wants the shift count to be unsigned */
+ right = create_conv(dbgi, right, mode_Iu);
+
+ ir_node *res;
+
+ switch(expression->type) {
+ case BINEXPR_SHIFTLEFT:
+ res = new_d_Shl(dbgi, left, right, mode);
+ break;
+ case BINEXPR_SHIFTRIGHT: {
+ expression_t *expr_left = expression->left;
+ type_t *type_left = skip_typeref(expr_left->datatype);
+
+ if(is_type_signed(type_left)) {
+ res = new_d_Shrs(dbgi, left, right, mode);
+ } else {
+ res = new_d_Shr(dbgi, left, right, mode);
+ }
+ break;
+ }
+ default:
+ panic("create shift op called for non-shift op");
+ }
+
+ return res;
+}
+
+
static ir_node *create_divmod(const binary_expression_t *expression)
{
dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
case BINEXPR_BITWISE_XOR:
return create_arithmetic_binop(expression, new_d_Eor);
case BINEXPR_SHIFTLEFT:
- return create_arithmetic_binop(expression, new_d_Shl);
case BINEXPR_SHIFTRIGHT:
- return create_arithmetic_binop(expression, new_d_Shr);
+ return create_shift(expression);
case BINEXPR_DIV:
case BINEXPR_MOD:
return create_divmod(expression);
static ir_node *array_access_to_firm(
const array_access_expression_t *expression)
{
-
dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
ir_node *addr = array_access_addr(expression);
type_t *type = expression->expression.datatype;
return val;
}
+static ir_node *select_addr(const select_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+
+ ir_node *compound_addr = expression_to_firm(expression->compound);
+
+ declaration_t *entry = expression->compound_entry;
+ assert(entry->declaration_type == DECLARATION_TYPE_COMPOUND_MEMBER);
+ ir_entity *entity = entry->v.entity;
+
+ assert(entity != NULL);
+
+ ir_node *sel = new_d_simpleSel(dbgi, new_NoMem(), compound_addr, entity);
+
+ return sel;
+}
+
+static ir_node *select_to_firm(const select_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *addr = select_addr(expression);
+ type_t *type = expression->expression.datatype;
+
+ return load_from_expression_addr(type, addr, dbgi);
+}
+
+static ir_node *dereference_addr(const unary_expression_t *const expression)
+{
+ assert(expression->type == UNEXPR_DEREFERENCE);
+ return expression_to_firm(expression->value);
+}
+
static ir_node *expression_to_addr(const expression_t *expression)
{
switch(expression->type) {
return reference_addr((const reference_expression_t*) expression);
case EXPR_ARRAY_ACCESS:
return array_access_addr((const array_access_expression_t*) expression);
+ case EXPR_SELECT:
+ return select_addr((const select_expression_t*) expression);
+ case EXPR_UNARY: {
+ const unary_expression_t *const unary_expr =
+ (const unary_expression_t*)expression;
+ if (unary_expr->type == UNEXPR_DEREFERENCE) {
+ return dereference_addr(unary_expr);
+ }
+ break;
+ }
default:
break;
}
return sizeof_to_firm((const sizeof_expression_t*) expression);
case EXPR_CONDITIONAL:
return conditional_to_firm((const conditional_expression_t*)expression);
- default:
+ case EXPR_SELECT:
+ return select_to_firm((const select_expression_t*) expression);
+ case EXPR_FUNCTION:
+ case EXPR_OFFSETOF:
+ case EXPR_PRETTY_FUNCTION:
+ case EXPR_VA_ARG:
+ case EXPR_STATEMENT:
+ case EXPR_BUILTIN_SYMBOL:
+ panic("unimplemented expression found");
+
+ case EXPR_UNKNOWN:
+ case EXPR_INVALID:
break;
}
- panic("unsupported expression found");
+ panic("invalid expression found");
}
static ir_node *expression_to_firm(const expression_t *expression)
{
- ir_node *res = _expression_to_firm(expression);
+ ir_node *res = _expression_to_firm(expression);
- if(expression->datatype == type_void)
- return NULL;
+ if(res != NULL && get_irn_mode(res) == mode_b) {
+ ir_mode *mode = get_ir_mode(expression->datatype);
+ res = create_conv(NULL, res, mode);
+ }
- ir_mode *mode = get_ir_mode(expression->datatype);
- res = create_conv(NULL, res, mode);
return res;
}
static void return_statement_to_firm(return_statement_t *statement)
{
+ if(get_cur_block() == NULL)
+ return;
+
dbg_info *dbgi = get_dbg_info(&statement->statement.source_position);
ir_node *ret;
static void expression_statement_to_firm(expression_statement_t *statement)
{
+ if(get_cur_block() == NULL)
+ return;
+
expression_to_firm(statement->expression);
}
if(get_cur_block() == NULL) {
mature_immBlock(header_block);
mature_immBlock(body_block);
+ mature_immBlock(false_block);
return;
}
mature_immBlock(header_block);
/* create the condition */
+ set_cur_block(header_block);
ir_node *condition = expression_to_modeb(statement->condition);
ir_node *cond = new_d_Cond(dbgi, condition);
ir_node *true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
add_immBlock_pred(header_block, step_jmp);
/* create the condition */
- ir_node *const condition = expression_to_modeb(statement->condition);
- ir_node *const cond = new_d_Cond(dbgi, condition);
- ir_node *const true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
- ir_node *const false_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_false);
+ ir_node *true_proj;
+ ir_node *false_proj;
+ if (statement->condition != NULL) {
+ ir_node *const condition = expression_to_modeb(statement->condition);
+ ir_node *const cond = new_d_Cond(dbgi, condition);
+ true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
+ false_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_false);
+ } else {
+ keep_alive(header_block);
+ true_proj = new_Jmp();
+ false_proj = NULL;
+ }
/* the false block */
ir_node *const false_block = new_immBlock();
- add_immBlock_pred(false_block, false_proj);
+ if (false_proj != NULL) {
+ add_immBlock_pred(false_block, false_proj);
+ }
/* the loop body */
ir_node *const body_block = new_immBlock();
set_value(declaration->v.value_number, init_node);
} else {
ir_entity *entity = declaration->v.entity;
- ir_mode *mode = get_ir_mode(declaration->type);
- init_node = create_conv(NULL, init_node, mode);
set_entity_variability(entity, variability_initialized);
set_atomic_ent_value(entity, init_node);
static void create_local_variable(declaration_t *declaration)
{
+ assert(declaration->declaration_type == DECLARATION_TYPE_UNKNOWN);
+
bool needs_entity = declaration->address_taken;
+ type_t *type = skip_typeref(declaration->type);
- assert(declaration->declaration_type == DECLARATION_TYPE_UNKNOWN);
+ if(type->type == TYPE_ARRAY
+ || type->type == TYPE_COMPOUND_STRUCT
+ || type->type == TYPE_COMPOUND_UNION) {
+ needs_entity = true;
+ }
if(needs_entity) {
ir_type *frame_type = get_irg_frame_type(current_ir_graph);
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->source_position);
ir_node *jump = new_d_Jmp(dbgi);
add_immBlock_pred(target_block, jump);
set_cur_block(NULL);
- ir_node *old_switch_cond = current_switch_cond;
- ir_node *old_break_label = break_label;
- current_switch_cond = cond;
- break_label = break_block;
+ 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;
+ current_switch_cond = cond;
+ break_label = break_block;
statement_to_firm(statement->body);
add_immBlock_pred(break_block, jmp);
}
+ if (!saw_default_label) {
+ set_cur_block(get_nodes_block(cond));
+ ir_node *const proj = new_d_defaultProj(dbgi, cond,
+ MAGIC_DEFAULT_PN_NUMBER);
+ add_immBlock_pred(break_block, proj);
+ }
+
assert(current_switch_cond == cond);
assert(break_label == break_block);
current_switch_cond = old_switch_cond;
break_label = old_break_label;
+ saw_default_label = old_saw_default_label;
mature_immBlock(break_block);
set_cur_block(break_block);
}
+static long fold_constant(const expression_t *expression)
+{
+ ir_graph *old_current_ir_graph = current_ir_graph;
+ current_ir_graph = get_const_code_irg();
+
+ ir_node *cnst = expression_to_firm(expression);
+ if(!is_Const(cnst)) {
+ panic("couldn't fold constantl");
+ }
+ tarval *tv = get_Const_tarval(cnst);
+ if(!tarval_is_long(tv)) {
+ panic("folded constant not an integer");
+ }
+
+ long res = get_tarval_long(tv);
+
+ current_ir_graph = old_current_ir_graph;
+ return res;
+}
+
static void case_label_to_firm(const case_label_statement_t *statement)
{
dbg_info *dbgi = get_dbg_info(&statement->statement.source_position);
+ ir_node *const fallthrough = (get_cur_block() == NULL ? NULL : new_Jmp());
+
/* let's create a node and hope firm constant folding creates a Const
* node... */
ir_node *proj;
set_cur_block(get_nodes_block(current_switch_cond));
if(statement->expression) {
- ir_node *cnst = expression_to_firm(statement->expression);
- if(!is_Const(cnst)) {
- panic("couldn't fold constant for case label");
- }
- tarval *tv = get_Const_tarval(cnst);
- if(!mode_is_int(get_tarval_mode(tv))) {
- panic("case label not an integer");
- }
-
- long pn = get_tarval_long(tv);
+ long pn = fold_constant(statement->expression);
if(pn == MAGIC_DEFAULT_PN_NUMBER) {
/* oops someone detected our cheating... */
panic("magic default pn used");
}
proj = new_d_Proj(dbgi, current_switch_cond, mode_X, pn);
} else {
+ saw_default_label = true;
proj = new_d_defaultProj(dbgi, current_switch_cond,
MAGIC_DEFAULT_PN_NUMBER);
}
ir_node *block = new_immBlock();
+ if (fallthrough != NULL) {
+ add_immBlock_pred(block, fallthrough);
+ }
add_immBlock_pred(block, proj);
mature_immBlock(block);
}
+static ir_node *get_label_block(declaration_t *label)
+{
+ assert(label->namespace == NAMESPACE_LABEL);
+
+ if(label->declaration_type == DECLARATION_TYPE_LABEL_BLOCK) {
+ return label->v.block;
+ }
+ assert(label->declaration_type == DECLARATION_TYPE_UNKNOWN);
+
+ ir_node *old_cur_block = get_cur_block();
+ ir_node *block = new_immBlock();
+ set_cur_block(old_cur_block);
+
+ label->declaration_type = DECLARATION_TYPE_LABEL_BLOCK;
+ label->v.block = block;
+
+ ARR_APP1(imature_blocks, block);
+
+ return block;
+}
+
+static void label_to_firm(const label_statement_t *statement)
+{
+ ir_node *block = get_label_block(statement->label);
+
+ if(get_cur_block() != NULL) {
+ ir_node *jmp = new_Jmp();
+ add_immBlock_pred(block, jmp);
+ }
+
+ set_cur_block(block);
+ keep_alive(block);
+
+ statement_to_firm(statement->label_statement);
+}
+
+static void goto_to_firm(const goto_statement_t *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);
+
+ set_cur_block(NULL);
+}
+
static void statement_to_firm(statement_t *statement)
{
switch(statement->type) {
case STATEMENT_FOR:
for_statement_to_firm((for_statement_t*) statement);
return;
+ case STATEMENT_LABEL:
+ label_to_firm((label_statement_t*) statement);
+ return;
+ case STATEMENT_GOTO:
+ goto_to_firm((goto_statement_t*) statement);
+ return;
default:
break;
}
declaration_t *parameter = declaration->context.declarations;
for( ; parameter != NULL; parameter = parameter->next) {
assert(parameter->declaration_type == DECLARATION_TYPE_UNKNOWN);
+ type_t *type = parameter->type;
+
+ bool needs_entity = parameter->address_taken;
+ if(type->type == TYPE_COMPOUND_STRUCT
+ || type->type == TYPE_COMPOUND_UNION) {
+ needs_entity = true;
+ }
- if(parameter->address_taken) {
- panic("address take from parameter not implemented yet");
+ if(needs_entity) {
+ panic("entities for function parameters not implemented yet");
}
ir_mode *mode = get_ir_mode(parameter->type);
if(declaration->init.statement == NULL)
return;
+ assert(imature_blocks == NULL);
+ imature_blocks = NEW_ARR_F(ir_node*, 0);
+
int n_local_vars = get_function_n_local_vars(declaration);
ir_graph *irg = new_ir_graph(entity, n_local_vars);
ir_node *first_block = get_cur_block();
/* do we have a return statement yet? */
if(get_cur_block() != NULL) {
assert(declaration->type->type == TYPE_FUNCTION);
- const function_type_t* const func_type = (const function_type_t*)declaration->type;
+ const function_type_t* const func_type
+ = (const function_type_t*) declaration->type;
ir_node *ret;
if (func_type->result_type == type_void) {
ret = new_Return(get_store(), 0, NULL);
add_immBlock_pred(end_block, ret);
}
+ for(int i = 0; i < ARR_LEN(imature_blocks); ++i) {
+ mature_immBlock(imature_blocks[i]);
+ }
+ DEL_ARR_F(imature_blocks);
+ imature_blocks = NULL;
+
mature_immBlock(first_block);
mature_immBlock(end_block);
if(declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY
|| declaration->storage_class == STORAGE_CLASS_TYPEDEF)
continue;
+ if(declaration->symbol == NULL)
+ continue;
type_t *type = declaration->type;
if(type->type == TYPE_FUNCTION) {