/*
* This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
*/
#include <config.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
-#include <limits.h>
#include <libfirm/firm.h>
#include <libfirm/adt/obst.h>
#include "adt/array.h"
#include "adt/strutil.h"
#include "adt/util.h"
+#include "jump_target.h"
#include "symbol_t.h"
+#include "symbol_table.h"
#include "token_t.h"
#include "type_t.h"
#include "ast_t.h"
#include "diagnostic.h"
#include "lang_features.h"
#include "types.h"
-#include "type_hash.h"
#include "mangle.h"
+#include "unicode.h"
#include "walk.h"
#include "warning.h"
#include "printer.h"
ir_entity *region; /**< created region for the trampoline */
};
+typedef struct complex_value {
+ ir_node *real;
+ ir_node *imag;
+} complex_value;
+
+typedef struct complex_constant {
+ ir_tarval *real;
+ ir_tarval *imag;
+} complex_constant;
+
fp_model_t firm_fp_model = fp_model_precise;
static const backend_params *be_params;
static ir_type *ir_type_char;
-static ir_type *ir_type_wchar_t;
/* architecture specific floating point arithmetic mode (if any) */
static ir_mode *mode_float_arithmetic;
/* alignment of stack parameters */
static unsigned stack_param_align;
-static int next_value_number_function;
-static ir_node *continue_label;
-static ir_node *break_label;
-static ir_node *current_switch;
-static bool saw_default_label;
-static label_t **all_labels;
-static entity_t **inner_functions;
-static ir_node *ijmp_list;
-static bool constant_folding;
+static int next_value_number_function;
+static jump_target continue_target;
+static jump_target break_target;
+static ir_node *current_switch;
+static bool saw_default_label;
+static entity_t **inner_functions;
+static jump_target ijmp_target;
+static ir_node **ijmp_ops;
+static ir_node **ijmp_blocks;
+static bool constant_folding;
+
+#define PUSH_BREAK(val) \
+ jump_target const old_break_target = break_target; \
+ (init_jump_target(&break_target, (val)))
+#define POP_BREAK() \
+ ((void)(break_target = old_break_target))
+
+#define PUSH_CONTINUE(val) \
+ jump_target const old_continue_target = continue_target; \
+ (init_jump_target(&continue_target, (val)))
+#define POP_CONTINUE() \
+ ((void)(continue_target = old_continue_target))
+
+#define PUSH_IRG(val) \
+ ir_graph *const old_irg = current_ir_graph; \
+ ir_graph *const new_irg = (val); \
+ ((void)(current_ir_graph = new_irg))
+
+#define POP_IRG() \
+ (assert(current_ir_graph == new_irg), (void)(current_ir_graph = old_irg))
static const entity_t *current_function_entity;
static ir_node *current_function_name;
static ir_node *uninitialized_local_var(ir_graph *irg, ir_mode *mode, int pos)
{
const entity_t *entity = get_irg_loc_description(irg, pos);
-
- if (entity != NULL) {
- source_position_t const *const pos = &entity->base.source_position;
- warningf(WARN_UNINITIALIZED, pos, "'%N' might be used uninitialized", entity);
- }
+ if (entity)
+ warningf(WARN_UNINITIALIZED, &entity->base.pos, "'%N' might be used uninitialized", entity);
return new_r_Unknown(irg, mode);
}
static src_loc_t dbg_retrieve(const dbg_info *dbg)
{
- source_position_t const *const pos = (source_position_t const*)dbg;
+ position_t const *const pos = (position_t const*)dbg;
if (pos) {
return (src_loc_t){ pos->input_name, pos->lineno, pos->colno };
} else {
}
}
-static dbg_info *get_dbg_info(const source_position_t *pos)
+static dbg_info *get_dbg_info(const position_t *pos)
{
return (dbg_info*) pos;
}
ir_mode *atomic_modes[ATOMIC_TYPE_LAST+1];
-static ir_node *_expression_to_firm(const expression_t *expression);
-static ir_node *expression_to_firm(const expression_t *expression);
+static ir_node *expression_to_control_flow(expression_t const *expr, jump_target *true_target, jump_target *false_target);
+static ir_node *expression_to_value(expression_t const *expr);
+static complex_value expression_to_complex(const expression_t *expression);
static unsigned decide_modulo_shift(unsigned type_size)
{
if (architecture_modulo_shift == 0)
return 0;
- if (type_size < architecture_modulo_shift)
- return architecture_modulo_shift;
- return type_size;
+ return MAX(type_size, architecture_modulo_shift);
}
static ir_mode *init_atomic_ir_mode(atomic_type_kind_t kind)
{
unsigned flags = get_atomic_type_flags(kind);
unsigned size = get_atomic_type_size(kind);
- if ((flags & ATOMIC_TYPE_FLAG_FLOAT)
- && !(flags & ATOMIC_TYPE_FLAG_COMPLEX)) {
+ if (flags & ATOMIC_TYPE_FLAG_FLOAT) {
switch (size) {
case 4: return get_modeF();
case 8: return get_modeD();
}
}
-ir_mode *get_atomic_mode(atomic_type_kind_t kind)
-{
- assert(kind <= ATOMIC_TYPE_LAST);
- return atomic_modes[kind];
-}
-
static ir_node *get_vla_size(array_type_t *const type)
{
ir_node *size_node = type->size_node;
if (size_node == NULL) {
- size_node = expression_to_firm(type->size_expression);
+ size_node = expression_to_value(type->size_expression);
type->size_node = size_node;
}
return size_node;
return count;
}
-/**
- * Creates a Firm type for an atomic type
- */
-static ir_type *create_atomic_type(atomic_type_kind_t akind, const type_t *type)
+static ir_type *create_primitive_irtype(atomic_type_kind_t akind,
+ type_dbg_info *dbgi)
{
ir_mode *mode = atomic_modes[akind];
- type_dbg_info *dbgi = get_type_dbg_info_(type);
ir_type *irtype = new_d_type_primitive(mode, dbgi);
- il_alignment_t alignment = get_atomic_type_alignment(akind);
+ unsigned alignment = get_atomic_type_alignment(akind);
+ unsigned size = get_atomic_type_size(akind);
- set_type_size_bytes(irtype, get_atomic_type_size(akind));
+ set_type_size_bytes(irtype, size);
set_type_alignment_bytes(irtype, alignment);
return irtype;
}
+/**
+ * Creates a Firm type for an atomic type
+ */
+static ir_type *create_atomic_type(atomic_type_kind_t akind, const type_t *type)
+{
+ type_dbg_info *dbgi = get_type_dbg_info_(type);
+ return create_primitive_irtype(akind, dbgi);
+}
+
/**
* Creates a Firm type for a complex type
*/
-static ir_type *create_complex_type(const atomic_type_t *type)
+static ir_type *create_complex_type(atomic_type_kind_t akind,
+ const type_t *type)
{
- atomic_type_kind_t kind = type->akind;
- ir_mode *mode = atomic_modes[kind];
- ident *id = get_mode_ident(mode);
+ type_dbg_info *dbgi = get_type_dbg_info_(type);
+ ir_type *etype = create_primitive_irtype(akind, NULL);
+ ir_type *irtype = new_d_type_array(1, etype, dbgi);
- (void) id;
+ int align = get_type_alignment_bytes(etype);
+ set_type_alignment_bytes(irtype, align);
+ unsigned n_elements = 2;
+ set_array_bounds_int(irtype, 0, 0, n_elements);
+ size_t elemsize = get_type_size_bytes(etype);
+ if (elemsize % align > 0) {
+ elemsize += align - (elemsize % align);
+ }
+ set_type_size_bytes(irtype, n_elements * elemsize);
+ set_type_state(irtype, layout_fixed);
- /* FIXME: finish the array */
- return NULL;
+ return irtype;
}
/**
return type;
}
+static ir_type *get_ir_type(type_t *type);
+
static ir_type *create_method_type(const function_type_t *function_type, bool for_closure)
{
type_t *return_type = skip_typeref(function_type->return_type);
mode = s_modes[size];
if (mode == NULL) {
- char name[32];
+ ir_mode *base_mode = get_type_mode(base_tp);
+ unsigned modulo_shift = get_mode_modulo_shift(base_mode);
+ char name[32];
snprintf(name, sizeof(name), "bf_I%u", size);
- mode = new_int_mode(name, irma_twos_complement, size, 1, 0);
+ mode = new_int_mode(name, irma_twos_complement, size, 1, modulo_shift);
s_modes[size] = mode;
}
mode = u_modes[size];
if (mode == NULL) {
- char name[32];
+ ir_mode *base_mode = get_type_mode(base_tp);
+ unsigned modulo_shift = get_mode_modulo_shift(base_mode);
+ char name[32];
snprintf(name, sizeof(name), "bf_U%u", size);
- mode = new_int_mode(name, irma_twos_complement, size, 0, 0);
+ mode = new_int_mode(name, irma_twos_complement, size, 0, modulo_shift);
u_modes[size] = mode;
}
symbol_t *symbol = entry->base.symbol;
type_t *entry_type = entry->declaration.type;
- ident *ident;
+ ident *member_id;
if (symbol == NULL) {
/* anonymous bitfield member, skip */
if (entry->compound_member.bitfield)
continue;
assert(is_type_compound(entry_type));
- ident = id_unique("anon.%u");
+ member_id = id_unique("anon.%u");
} else {
- ident = new_id_from_str(symbol->string);
+ member_id = new_id_from_str(symbol->string);
}
- dbg_info *dbgi = get_dbg_info(&entry->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&entry->base.pos);
ir_type *entry_irtype;
if (entry->compound_member.bitfield) {
} else {
entry_irtype = get_ir_type(entry_type);
}
- ir_entity *entity = new_d_entity(irtype, ident, entry_irtype, dbgi);
+ ir_entity *entity = new_d_entity(irtype, member_id, entry_irtype, dbgi);
set_entity_offset(entity, entry->compound_member.offset);
set_entity_offset_bits_remainder(entity,
return irtype;
}
-static ir_tarval *fold_constant_to_tarval(expression_t const *);
-
-static void determine_enum_values(enum_type_t *const type)
+void determine_enum_values(enum_type_t *const type)
{
ir_mode *const mode = atomic_modes[type->base.akind];
ir_tarval *const one = get_mode_one(mode);
}
}
-ir_type *get_ir_type(type_t *type)
+static ir_type *get_ir_type(type_t *type)
{
type = skip_typeref(type);
firm_type = create_atomic_type(type->atomic.akind, type);
break;
case TYPE_COMPLEX:
- firm_type = create_complex_type(&type->atomic);
+ firm_type = create_complex_type(type->atomic.akind, type);
break;
case TYPE_IMAGINARY:
firm_type = create_imaginary_type(&type->atomic);
type = skip_typeref(type);
/* Firm doesn't report a mode for arrays and structs/unions. */
- if (!is_type_scalar(type)) {
+ if (!is_type_scalar(type) || is_type_complex(type)) {
return mode_P_data;
}
return mode;
}
+static ir_mode *get_complex_mode_storage(type_t *type)
+{
+ assert(is_type_complex(skip_typeref(type)));
+ ir_type *const irtype = get_ir_type(type);
+ ir_type *const etype = get_array_element_type(irtype);
+ ir_mode *const mode = get_type_mode(etype);
+ return mode;
+}
+
/*
* get arithmetic mode for a type. This is different from get_ir_mode_storage,
* int that it returns bigger modes for floating point on some platforms
return mode;
}
+static ir_mode *get_complex_mode_arithmetic(type_t *type)
+{
+ ir_mode *mode = get_complex_mode_storage(type);
+ if (mode_is_float(mode) && mode_float_arithmetic != NULL) {
+ return mode_float_arithmetic;
+ }
+
+ return mode;
+}
+
/**
* Return a node representing the size of a type.
*/
static ir_node *get_type_size_node(type_t *type)
{
- unsigned size;
- ir_mode *mode = get_ir_mode_arithmetic(type_size_t);
+ ir_mode *const mode = get_ir_mode_storage(type_size_t);
type = skip_typeref(type);
if (is_type_array(type) && type->array.is_vla) {
return real_size;
}
- size = get_type_size(type);
+ unsigned const size = get_type_size(type);
return new_Const_long(mode, size);
}
switch (entity->kind) {
case ENTITY_VARIABLE:
return entity->declaration.storage_class != STORAGE_CLASS_EXTERN;
+// TODO: alias provides a definition
+// || entity->variable.alias != NULL;
case ENTITY_FUNCTION:
- return entity->function.statement != NULL;
+ return entity->function.body != NULL;
case ENTITY_PARAMETER:
case ENTITY_COMPOUND_MEMBER:
return false;
case ENTITY_LOCAL_LABEL:
break;
}
- panic("declaration_is_definition called on non-declaration");
+ panic("entity is not a declaration");
}
/**
decl_modifiers_t modifiers = entity->declaration.modifiers;
if (is_method_entity(irentity)) {
- if (modifiers & DM_PURE) {
- set_entity_additional_properties(irentity, mtp_property_pure);
- }
- if (modifiers & DM_CONST) {
+ if (modifiers & DM_PURE)
+ add_entity_additional_properties(irentity, mtp_property_pure);
+ if (modifiers & DM_CONST)
add_entity_additional_properties(irentity, mtp_property_const);
- }
+ if (modifiers & DM_NOINLINE)
+ add_entity_additional_properties(irentity, mtp_property_noinline);
+ if (modifiers & DM_FORCEINLINE)
+ add_entity_additional_properties(irentity, mtp_property_always_inline);
+ if (modifiers & DM_NAKED)
+ add_entity_additional_properties(irentity, mtp_property_naked);
+ if (entity->kind == ENTITY_FUNCTION && entity->function.is_inline)
+ add_entity_additional_properties(irentity,
+ mtp_property_inline_recommended);
}
if ((modifiers & DM_USED) && declaration_is_definition(entity)) {
add_entity_linkage(irentity, IR_LINKAGE_HIDDEN_USER);
}
- if ((modifiers & DM_WEAK) && declaration_is_definition(entity)
- && entity->declaration.storage_class != STORAGE_CLASS_EXTERN) {
+// TODO: i dont understand this logic
+// if ((modifiers & DM_WEAK) && declaration_is_definition(entity)
+// && entity->declaration.storage_class != STORAGE_CLASS_EXTERN) {
+ if (modifiers & DM_WEAK) {
add_entity_linkage(irentity, IR_LINKAGE_WEAK);
}
}
/* already an entity defined? */
ir_entity *irentity = entitymap_get(&entitymap, symbol);
- bool const has_body = entity->function.statement != NULL;
+ bool const has_body = entity->function.body != NULL;
if (irentity != NULL) {
goto entity_created;
}
else
nested_function = true;
- dbg_info *const dbgi = get_dbg_info(&entity->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&entity->base.pos);
irentity = new_d_entity(owner_type, id, ir_type_method, dbgi);
ident *ld_id;
return new_Const((v ? get_mode_one : get_mode_null)(mode));
}
-static ir_node *create_conv_from_b(dbg_info *dbgi, ir_node *value,
- ir_mode *dest_mode)
-{
- if (is_Const(value)) {
- return create_Const_from_bool(dest_mode, !is_Const_null(value));
- }
-
- ir_node *cond = new_d_Cond(dbgi, value);
- ir_node *proj_true = new_Proj(cond, mode_X, pn_Cond_true);
- ir_node *proj_false = new_Proj(cond, mode_X, pn_Cond_false);
- ir_node *tblock = new_Block(1, &proj_true);
- ir_node *fblock = new_Block(1, &proj_false);
- set_cur_block(tblock);
- ir_node *const1 = new_Const(get_mode_one(dest_mode));
- ir_node *tjump = new_Jmp();
- set_cur_block(fblock);
- ir_node *const0 = new_Const(get_mode_null(dest_mode));
- ir_node *fjump = new_Jmp();
-
- ir_node *in[2] = { tjump, fjump };
- ir_node *mergeblock = new_Block(2, in);
- set_cur_block(mergeblock);
- ir_node *phi_in[2] = { const1, const0 };
- ir_node *phi = new_Phi(2, phi_in, dest_mode);
- return phi;
-}
-
static ir_node *create_conv(dbg_info *dbgi, ir_node *value, ir_mode *dest_mode)
{
ir_mode *value_mode = get_irn_mode(value);
if (value_mode == dest_mode)
return value;
- if (dest_mode == mode_b) {
- ir_node *zero = new_Const(get_mode_null(value_mode));
- ir_node *cmp = new_d_Cmp(dbgi, value, zero, ir_relation_unordered_less_greater);
- return cmp;
- } else if (value_mode == mode_b) {
- return create_conv_from_b(dbgi, value, dest_mode);
- }
-
return new_d_Conv(dbgi, value, dest_mode);
}
+static ir_node *conv_to_storage_type(dbg_info *const dbgi, ir_node *const val, type_t *const type)
+{
+ ir_mode *const mode = get_ir_mode_storage(type);
+ return create_conv(dbgi, val, mode);
+}
+
/**
* Creates a SymConst node representing a string constant.
*
* @param id_prefix a prefix for the name of the generated string constant
* @param value the value of the string constant
*/
-static ir_node *string_to_firm(source_position_t const *const src_pos, char const *const id_prefix, string_encoding_t const enc, string_t const *const value)
+static ir_node *string_to_firm(position_t const *const src_pos, char const *const id_prefix, string_t const *const value)
{
- size_t slen;
- ir_type *elem_type;
- ir_initializer_t *initializer;
- switch (enc) {
- case STRING_ENCODING_CHAR: {
- slen = value->size + 1;
- elem_type = ir_type_char;
- initializer = create_initializer_compound(slen);
+ size_t const slen = get_string_len(value) + 1;
+ ir_initializer_t *const initializer = create_initializer_compound(slen);
+ ir_type * elem_type;
+ switch (value->encoding) {
+ case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8: {
+ elem_type = ir_type_char;
ir_mode *const mode = get_type_mode(elem_type);
char const *p = value->begin;
goto finish;
}
- case STRING_ENCODING_WIDE: {
- slen = wstrlen(value) + 1;
- elem_type = ir_type_wchar_t;
- initializer = create_initializer_compound(slen);
+ {
+ type_t *type;
+ case STRING_ENCODING_CHAR16: type = type_char16_t; goto init_wide;
+ case STRING_ENCODING_CHAR32: type = type_char32_t; goto init_wide;
+ case STRING_ENCODING_WIDE: type = type_wchar_t; goto init_wide;
+init_wide:;
+ elem_type = get_ir_type(type);
ir_mode *const mode = get_type_mode(elem_type);
char const *p = value->begin;
static bool try_create_integer(literal_expression_t *literal, type_t *type)
{
- const char *string = literal->value.begin;
- size_t size = literal->value.size;
-
- assert(type->kind == TYPE_ATOMIC);
+ assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX);
atomic_type_kind_t akind = type->atomic.akind;
- ir_mode *const mode = atomic_modes[akind];
- ir_tarval *const tv = new_tarval_from_str(string, size, mode);
+ ir_mode *const mode = atomic_modes[akind];
+ char const *const str = literal->value.begin;
+ ir_tarval *const tv = new_tarval_from_str(str, literal->suffix - str, mode);
if (tv == tarval_bad)
return false;
return true;
}
-static void create_integer_tarval(literal_expression_t *literal)
+void determine_literal_type(literal_expression_t *const literal)
{
+ assert(literal->base.kind == EXPR_LITERAL_INTEGER);
+
/* -1: signed only, 0: any, 1: unsigned only */
- int sign = literal->value.begin[0] != '0' /* decimal */ ? -1 : 0;
- unsigned ls = 0;
- const string_t *suffix = &literal->suffix;
- /* parse suffix */
- if (suffix->size > 0) {
- for (const char *c = suffix->begin; *c != '\0'; ++c) {
- if (*c == 'u' || *c == 'U') sign = 1;
- if (*c == 'l' || *c == 'L') { ++ls; }
- }
- }
+ int const sign =
+ !is_type_signed(literal->base.type) ? 1 :
+ literal->value.begin[0] == '0' ? 0 :
+ -1; /* Decimal literals only try signed types. */
tarval_int_overflow_mode_t old_mode = tarval_get_integer_overflow_mode();
+ tarval_set_integer_overflow_mode(TV_OVERFLOW_BAD);
+
+ if (try_create_integer(literal, literal->base.type))
+ goto finished;
/* now try if the constant is small enough for some types */
- tarval_set_integer_overflow_mode(TV_OVERFLOW_BAD);
- if (ls < 1) {
- if (sign <= 0 && try_create_integer(literal, type_int))
- goto finished;
- if (sign >= 0 && try_create_integer(literal, type_unsigned_int))
- goto finished;
- }
- if (ls < 2) {
- if (sign <= 0 && try_create_integer(literal, type_long))
- goto finished;
- if (sign >= 0 && try_create_integer(literal, type_unsigned_long))
- goto finished;
- }
+ if (sign >= 0 && try_create_integer(literal, type_unsigned_int))
+ goto finished;
+ if (sign <= 0 && try_create_integer(literal, type_long))
+ goto finished;
+ if (sign >= 0 && try_create_integer(literal, type_unsigned_long))
+ goto finished;
/* last try? then we should not report tarval_bad */
if (sign < 0)
tarval_set_integer_overflow_mode(TV_OVERFLOW_WRAP);
tarval_set_integer_overflow_mode(old_mode);
}
-void determine_literal_type(literal_expression_t *literal)
-{
- switch (literal->base.kind) {
- case EXPR_LITERAL_INTEGER:
- create_integer_tarval(literal);
- return;
- default:
- break;
- }
-}
-
/**
* Creates a Const node representing a constant.
*/
-static ir_node *literal_to_firm(const literal_expression_t *literal)
+static ir_node *literal_to_firm_(const literal_expression_t *literal,
+ ir_mode *mode)
{
- type_t *type = skip_typeref(literal->base.type);
- ir_mode *mode = get_ir_mode_storage(type);
const char *string = literal->value.begin;
size_t size = literal->value.size;
ir_tarval *tv;
break;
default:
- panic("Invalid literal kind found");
+ panic("invalid literal kind");
}
- dbg_info *dbgi = get_dbg_info(&literal->base.source_position);
- ir_node *res = new_d_Const(dbgi, tv);
- ir_mode *mode_arith = get_ir_mode_arithmetic(type);
- return create_conv(dbgi, res, mode_arith);
+ dbg_info *const dbgi = get_dbg_info(&literal->base.pos);
+ return new_d_Const(dbgi, tv);
+}
+
+static ir_node *literal_to_firm(const literal_expression_t *literal)
+{
+ type_t *type = skip_typeref(literal->base.type);
+ ir_mode *mode_storage = get_ir_mode_storage(type);
+ return literal_to_firm_(literal, mode_storage);
}
/**
size_t size = literal->value.size;
ir_tarval *tv;
- switch (literal->encoding) {
+ switch (literal->value.encoding) {
case STRING_ENCODING_WIDE: {
utf32 v = read_utf8_char(&string);
char buf[128];
}
default:
- panic("Invalid literal kind found");
+ panic("invalid literal kind");
}
- dbg_info *dbgi = get_dbg_info(&literal->base.source_position);
- ir_node *res = new_d_Const(dbgi, tv);
- ir_mode *mode_arith = get_ir_mode_arithmetic(type);
- return create_conv(dbgi, res, mode_arith);
+ dbg_info *const dbgi = get_dbg_info(&literal->base.pos);
+ return new_d_Const(dbgi, tv);
}
/*
ir_node *const load_res = new_d_Proj(dbgi, load, mode, pn_Load_res);
set_store(load_mem);
-
- ir_mode *const mode_arithmetic = get_ir_mode_arithmetic(skipped);
- return create_conv(dbgi, load_res, mode_arithmetic);
-}
-
-/**
- * Creates a strict Conv (to the node's mode) if necessary.
- *
- * @param dbgi debug info
- * @param node the node to strict conv
- */
-static ir_node *do_strict_conv(dbg_info *dbgi, ir_node *node)
-{
- ir_mode *mode = get_irn_mode(node);
-
- if (!(get_irg_fp_model(current_ir_graph) & fp_explicit_rounding))
- return node;
- if (!mode_is_float(mode))
- return node;
-
- /* check if there is already a Conv */
- if (is_Conv(node)) {
- /* convert it into a strict Conv */
- set_Conv_strict(node, 1);
- return node;
- }
-
- /* otherwise create a new one */
- return new_d_strictConv(dbgi, node, mode);
+ return load_res;
}
/**
}
/**
- * Keep all memory edges of the given block.
+ * Keep the current block and memory.
+ * This is necessary for all loops, because they could become infinite.
*/
-static void keep_all_memory(ir_node *block)
+static void keep_loop(void)
{
- ir_node *old = get_cur_block();
-
- set_cur_block(block);
+ keep_alive(get_cur_block());
keep_alive(get_store());
- /* TODO: keep all memory edges from restricted pointers */
- set_cur_block(old);
}
static ir_node *enum_constant_to_firm(reference_expression_t const *const ref)
static ir_node *reference_addr(const reference_expression_t *ref)
{
- dbg_info *dbgi = get_dbg_info(&ref->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&ref->base.pos);
entity_t *entity = ref->entity;
assert(is_declaration(entity));
/* for gcc compatibility we have to produce (dummy) addresses for some
* builtins which don't have entities */
if (irentity == NULL) {
- source_position_t const *const pos = &ref->base.source_position;
+ position_t const *const pos = &ref->base.pos;
warningf(WARN_OTHER, pos, "taking address of builtin '%N'", ref->entity);
/* simply create a NULL pointer */
- ir_mode *mode = get_ir_mode_arithmetic(type_void_ptr);
- ir_node *res = new_Const(get_mode_null(mode));
-
- return res;
+ ir_mode *const mode = get_ir_mode_storage(type_void_ptr);
+ return new_Const(get_mode_null(mode));
}
}
- switch((declaration_kind_t) entity->declaration.kind) {
+ switch ((declaration_kind_t) entity->declaration.kind) {
case DECLARATION_KIND_UNKNOWN:
break;
case DECLARATION_KIND_PARAMETER:
panic("not implemented reference type");
}
- panic("reference to declaration with unknown type found");
+ panic("reference to declaration with unknown type");
}
static ir_node *reference_expression_to_firm(const reference_expression_t *ref)
{
- dbg_info *const dbgi = get_dbg_info(&ref->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&ref->base.pos);
entity_t *const entity = ref->entity;
assert(is_declaration(entity));
case DECLARATION_KIND_PARAMETER: {
type_t *const type = skip_typeref(entity->declaration.type);
ir_mode *const mode = get_ir_mode_storage(type);
- ir_node *const value = get_value(entity->variable.v.value_number, mode);
- return create_conv(dbgi, value, get_ir_mode_arithmetic(type));
+ return get_value(entity->variable.v.value_number, mode);
}
default: {
*/
static ir_node *process_builtin_call(const call_expression_t *call)
{
- dbg_info *dbgi = get_dbg_info(&call->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&call->base.pos);
assert(call->function->kind == EXPR_REFERENCE);
reference_expression_t *builtin = &call->function->reference;
break;
case BUILTIN_ALLOCA: {
expression_t *argument = call->arguments->expression;
- ir_node *size = expression_to_firm(argument);
+ ir_node *size = expression_to_value(argument);
ir_node *store = get_store();
ir_node *alloca = new_d_Alloc(dbgi, store, size, get_unknown_type(),
}
case BUILTIN_INF: {
type_t *type = function_type->function.return_type;
- ir_mode *mode = get_ir_mode_arithmetic(type);
+ ir_mode *mode = get_ir_mode_storage(type);
ir_tarval *tv = get_mode_infinite(mode);
ir_node *res = new_d_Const(dbgi, tv);
return res;
/* Ignore string for now... */
assert(is_type_function(function_type));
type_t *type = function_type->function.return_type;
- ir_mode *mode = get_ir_mode_arithmetic(type);
+ ir_mode *mode = get_ir_mode_storage(type);
ir_tarval *tv = get_mode_NAN(mode);
ir_node *res = new_d_Const(dbgi, tv);
return res;
}
case BUILTIN_EXPECT: {
expression_t *argument = call->arguments->expression;
- return _expression_to_firm(argument);
+ return expression_to_value(argument);
}
case BUILTIN_VA_END:
/* evaluate the argument of va_end for its side effects */
- _expression_to_firm(call->arguments->expression);
+ expression_to_value(call->arguments->expression);
return NULL;
case BUILTIN_OBJECT_SIZE: {
/* determine value of "type" */
expression_t *type_expression = call->arguments->next->expression;
long type_val = fold_constant_to_int(type_expression);
type_t *type = function_type->function.return_type;
- ir_mode *mode = get_ir_mode_arithmetic(type);
+ ir_mode *mode = get_ir_mode_storage(type);
/* just produce a "I don't know" result */
ir_tarval *result = type_val & 2 ? get_mode_null(mode) :
get_mode_minus_one(mode);
return new_d_Const(dbgi, result);
}
case BUILTIN_ROTL: {
- ir_node *val = expression_to_firm(call->arguments->expression);
- ir_node *shf = expression_to_firm(call->arguments->next->expression);
+ ir_node *val = expression_to_value(call->arguments->expression);
+ ir_node *shf = expression_to_value(call->arguments->next->expression);
ir_mode *mode = get_irn_mode(val);
ir_mode *mode_uint = atomic_modes[ATOMIC_TYPE_UINT];
return new_d_Rotl(dbgi, val, create_conv(dbgi, shf, mode_uint), mode);
}
case BUILTIN_ROTR: {
- ir_node *val = expression_to_firm(call->arguments->expression);
- ir_node *shf = expression_to_firm(call->arguments->next->expression);
+ ir_node *val = expression_to_value(call->arguments->expression);
+ ir_node *shf = expression_to_value(call->arguments->next->expression);
ir_mode *mode = get_irn_mode(val);
ir_mode *mode_uint = atomic_modes[ATOMIC_TYPE_UINT];
ir_node *c = new_Const_long(mode_uint, get_mode_size_bits(mode));
case BUILTIN_LIBC_CHECK:
panic("builtin did not produce an entity");
}
- panic("invalid builtin found");
+ panic("invalid builtin");
}
+static ir_node *complex_to_memory(dbg_info *dbgi, type_t *type,
+ complex_value value);
+
/**
* Transform a call expression.
* Handles some special cases, like alloca() calls, which must be resolved
*/
static ir_node *call_expression_to_firm(const call_expression_t *const call)
{
- dbg_info *const dbgi = get_dbg_info(&call->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&call->base.pos);
assert(currently_reachable());
expression_t *function = call->function;
}
}
if (!firm_builtin)
- callee = expression_to_firm(function);
+ callee = expression_to_value(function);
type_t *type = skip_typeref(function->base.type);
assert(is_type_pointer(type));
const call_argument_t *argument = call->arguments;
for (int n = 0; n < n_parameters; ++n) {
expression_t *expression = argument->expression;
- ir_node *arg_node = expression_to_firm(expression);
-
- type_t *arg_type = skip_typeref(expression->base.type);
- if (!is_type_compound(arg_type)) {
- ir_mode *const mode = get_ir_mode_storage(arg_type);
- arg_node = create_conv(dbgi, arg_node, mode);
- arg_node = do_strict_conv(dbgi, arg_node);
+ type_t *const arg_type = skip_typeref(expression->base.type);
+ if (is_type_complex(arg_type)) {
+ complex_value value = expression_to_complex(expression);
+ in[n] = complex_to_memory(dbgi, arg_type, value);
+ } else {
+ in[n] = conv_to_storage_type(dbgi, expression_to_value(expression), arg_type);
}
- in[n] = arg_node;
-
argument = argument->next;
}
assert(is_type_scalar(return_type));
ir_mode *mode = get_ir_mode_storage(return_type);
result = new_Proj(node, mode, pn_Builtin_max+1);
- ir_mode *mode_arith = get_ir_mode_arithmetic(return_type);
- result = create_conv(NULL, result, mode_arith);
}
} else {
node = new_d_Call(dbgi, store, callee, n_parameters, in, ir_method_type);
}
if (!is_type_void(return_type)) {
- ir_node *const resproj = new_Proj(node, mode_T, pn_Call_T_result);
- ir_mode *const mode = get_ir_mode_storage(return_type);
- result = new_Proj(resproj, mode, 0);
- ir_mode *const mode_arith = get_ir_mode_arithmetic(return_type);
- result = create_conv(NULL, result, mode_arith);
+ ir_node *const resproj = new_Proj(node, mode_T, pn_Call_T_result);
+ ir_mode *const mode = get_ir_mode_storage(return_type);
+ result = new_Proj(resproj, mode, 0);
}
}
static ir_node *statement_to_firm(statement_t *statement);
static ir_node *compound_statement_to_firm(compound_statement_t *compound);
-
static ir_node *expression_to_addr(const expression_t *expression);
-static ir_node *create_condition_evaluation(const expression_t *expression,
- ir_node *true_block,
- ir_node *false_block);
static void assign_value(dbg_info *dbgi, ir_node *addr, type_t *type,
ir_node *value)
{
- if (!is_type_compound(type)) {
- ir_mode *mode = get_ir_mode_storage(type);
- value = create_conv(dbgi, value, mode);
- value = do_strict_conv(dbgi, value);
- }
+ value = conv_to_storage_type(dbgi, value, type);
ir_node *memory = get_store();
- if (is_type_scalar(type)) {
+ if (is_type_scalar(type) && !is_type_complex(type)) {
ir_cons_flags flags = type->base.qualifiers & TYPE_QUALIFIER_VOLATILE
? cons_volatile : cons_none;
ir_node *store = new_d_Store(dbgi, memory, addr, value, flags);
static ir_node *bitfield_extract_to_firm(const select_expression_t *expression,
ir_node *addr)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
entity_t *entity = expression->compound_entry;
type_t *base_type = entity->declaration.type;
ir_mode *mode = get_ir_mode_storage(base_type);
shiftr = new_d_Shr(dbgi, shiftl, countr, amode);
}
- type_t *type = expression->base.type;
- ir_mode *resmode = get_ir_mode_arithmetic(type);
- return create_conv(dbgi, shiftr, resmode);
+ return conv_to_storage_type(dbgi, shiftr, expression->base.type);
}
/* make sure the selected compound type is constructed */
static ir_node *set_value_for_expression_addr(const expression_t *expression,
ir_node *value, ir_node *addr)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
type_t *type = skip_typeref(expression->base.type);
-
- if (!is_type_compound(type)) {
- ir_mode *mode = get_ir_mode_storage(type);
- value = create_conv(dbgi, value, mode);
- value = do_strict_conv(dbgi, value);
- }
+ value = conv_to_storage_type(dbgi, value, type);
if (expression->kind == EXPR_REFERENCE) {
const reference_expression_t *ref = &expression->reference;
return value;
}
-static void set_value_for_expression(const expression_t *expression,
- ir_node *value)
-{
- set_value_for_expression_addr(expression, value, NULL);
-}
-
static ir_node *get_value_from_lvalue(const expression_t *expression,
ir_node *addr)
{
assert(addr == NULL);
type_t *type = skip_typeref(expression->base.type);
ir_mode *mode = get_ir_mode_storage(type);
- ir_node *res = get_value(value_number, mode);
- return create_conv(NULL, res, get_ir_mode_arithmetic(type));
+ return get_value(value_number, mode);
}
}
assert(addr != NULL);
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
ir_node *value;
if (expression->kind == EXPR_SELECT &&
return value;
}
-
-static ir_node *create_incdec(const unary_expression_t *expression)
+static ir_node *incdec_to_firm(unary_expression_t const *const expr, bool const inc, bool const pre)
{
- dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
- const expression_t *value_expr = expression->value;
- ir_node *addr = expression_to_addr(value_expr);
- ir_node *value = get_value_from_lvalue(value_expr, addr);
-
- type_t *type = skip_typeref(expression->base.type);
- ir_mode *mode = get_ir_mode_arithmetic(expression->base.type);
+ type_t *const type = skip_typeref(expr->base.type);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
ir_node *offset;
if (is_type_pointer(type)) {
- pointer_type_t *pointer_type = &type->pointer;
- offset = get_type_size_node(pointer_type->points_to);
+ offset = get_type_size_node(type->pointer.points_to);
} else {
assert(is_type_arithmetic(type));
offset = new_Const(get_mode_one(mode));
}
- ir_node *result;
- ir_node *store_value;
- switch(expression->base.kind) {
- case EXPR_UNARY_POSTFIX_INCREMENT:
- result = value;
- store_value = new_d_Add(dbgi, value, offset, mode);
- break;
- case EXPR_UNARY_POSTFIX_DECREMENT:
- result = value;
- store_value = new_d_Sub(dbgi, value, offset, mode);
- break;
- case EXPR_UNARY_PREFIX_INCREMENT:
- result = new_d_Add(dbgi, value, offset, mode);
- store_value = result;
- break;
- case EXPR_UNARY_PREFIX_DECREMENT:
- result = new_d_Sub(dbgi, value, offset, mode);
- store_value = result;
- break;
- default:
- panic("no incdec expr in create_incdec");
- }
-
- set_value_for_expression_addr(value_expr, store_value, addr);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ expression_t const *const value_expr = expr->value;
+ ir_node *const addr = expression_to_addr(value_expr);
+ ir_node *const value = get_value_from_lvalue(value_expr, addr);
+ ir_node *const value_arith = create_conv(dbgi, value, mode);
+ ir_node *const new_value = inc
+ ? new_d_Add(dbgi, value_arith, offset, mode)
+ : new_d_Sub(dbgi, value_arith, offset, mode);
- return result;
+ ir_node *const store_value = set_value_for_expression_addr(value_expr, new_value, addr);
+ return pre ? store_value : value;
}
static bool is_local_variable(expression_t *expression)
static ir_relation get_relation(const expression_kind_t kind)
{
- switch(kind) {
+ switch (kind) {
case EXPR_BINARY_EQUAL: return ir_relation_equal;
case EXPR_BINARY_ISLESSGREATER: return ir_relation_less_greater;
case EXPR_BINARY_NOTEQUAL: return ir_relation_unordered_less_greater;
}
expression_t *con = NULL;
- if (is_local_variable(op1) && is_constant_expression(op2) == EXPR_CLASS_CONSTANT) {
+ if (is_local_variable(op1) && is_constant_expression(op2) != EXPR_CLASS_VARIABLE) {
var = op1->reference.entity;
con = op2;
- } else if (is_constant_expression(op1) == EXPR_CLASS_CONSTANT && is_local_variable(op2)) {
+ } else if (is_constant_expression(op1) != EXPR_CLASS_VARIABLE && is_local_variable(op2)) {
relation = get_inversed_relation(relation);
var = op2->reference.entity;
con = op1;
ir_mode *const mode = get_ir_mode_storage(type);
res = get_value(var->variable.v.value_number, mode);
- res = new_d_Confirm(dbi, res, expression_to_firm(con), relation);
+ res = new_d_Confirm(dbi, res, expression_to_value(con), relation);
set_value(var->variable.v.value_number, res);
}
return res;
* @param dbi debug info
* @param expr the IL assume expression
*/
-static ir_node *handle_assume(dbg_info *dbi, const expression_t *expression)
+static ir_node *handle_assume(expression_t const *const expr)
{
- switch(expression->kind) {
+ switch (expr->kind) {
case EXPR_BINARY_EQUAL:
case EXPR_BINARY_NOTEQUAL:
case EXPR_BINARY_LESS:
case EXPR_BINARY_LESSEQUAL:
case EXPR_BINARY_GREATER:
- case EXPR_BINARY_GREATEREQUAL:
- return handle_assume_compare(dbi, &expression->binary);
+ case EXPR_BINARY_GREATEREQUAL: {
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ return handle_assume_compare(dbgi, &expr->binary);
+ }
+
default:
return NULL;
}
}
-static ir_node *create_cast(dbg_info *dbgi, ir_node *value_node,
- type_t *from_type, type_t *type)
+static ir_node *create_cast(unary_expression_t const *const expr)
{
- type = skip_typeref(type);
- if (is_type_void(type)) {
- /* make sure firm type is constructed */
- (void) get_ir_type(type);
+ type_t *const from_type = skip_typeref(expr->value->base.type);
+ ir_node *value = is_type_complex(from_type)
+ ? expression_to_complex(expr->value).real
+ : expression_to_value(expr->value);
+
+ type_t *const type = skip_typeref(expr->base.type);
+ if (is_type_void(type))
return NULL;
- }
- if (!is_type_scalar(type)) {
- /* make sure firm type is constructed */
- (void) get_ir_type(type);
- return value_node;
- }
- from_type = skip_typeref(from_type);
- ir_mode *mode = get_ir_mode_storage(type);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *const mode = get_ir_mode_storage(type);
/* check for conversion from / to __based types */
if (is_type_pointer(type) && is_type_pointer(from_type)) {
const variable_t *from_var = from_type->pointer.base_variable;
if (from_var != NULL) {
ir_node *const addr = create_symconst(dbgi, from_var->v.entity);
ir_node *const base = deref_address(dbgi, from_var->base.type, addr);
- value_node = new_d_Add(dbgi, value_node, base, mode);
+ value = new_d_Add(dbgi, value, base, mode);
}
if (to_var != NULL) {
ir_node *const addr = create_symconst(dbgi, to_var->v.entity);
ir_node *const base = deref_address(dbgi, to_var->base.type, addr);
- value_node = new_d_Sub(dbgi, value_node, base, mode);
+ value = new_d_Sub(dbgi, value, base, mode);
}
}
}
- if (is_type_atomic(type, ATOMIC_TYPE_BOOL)) {
- /* bool adjustments (we save a mode_Bu, but have to temporarily
- * convert to mode_b so we only get a 0/1 value */
- value_node = create_conv(dbgi, value_node, mode_b);
- }
-
- ir_mode *mode_arith = get_ir_mode_arithmetic(type);
- ir_node *node = create_conv(dbgi, value_node, mode);
- node = do_strict_conv(dbgi, node);
- node = create_conv(dbgi, node, mode_arith);
-
- return node;
+ return create_conv(dbgi, value, mode);
}
-static ir_node *unary_expression_to_firm(const unary_expression_t *expression)
+static ir_node *complement_to_firm(unary_expression_t const *const expr)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- type_t *type = skip_typeref(expression->base.type);
-
- const expression_t *value = expression->value;
-
- switch(expression->base.kind) {
- case EXPR_UNARY_TAKE_ADDRESS:
- return expression_to_addr(value);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ type_t *const type = skip_typeref(expr->base.type);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
+ ir_node *const value = create_conv(dbgi, expression_to_value(expr->value), mode);
+ return new_d_Not(dbgi, value, mode);
+}
- case EXPR_UNARY_NEGATE: {
- ir_node *value_node = expression_to_firm(value);
- ir_mode *mode = get_ir_mode_arithmetic(type);
- return new_d_Minus(dbgi, value_node, mode);
- }
- case EXPR_UNARY_PLUS:
- return expression_to_firm(value);
- case EXPR_UNARY_BITWISE_NEGATE: {
- ir_node *value_node = expression_to_firm(value);
- ir_mode *mode = get_ir_mode_arithmetic(type);
- return new_d_Not(dbgi, value_node, mode);
- }
- case EXPR_UNARY_NOT: {
- ir_node *value_node = _expression_to_firm(value);
- value_node = create_conv(dbgi, value_node, mode_b);
- ir_node *res = new_d_Not(dbgi, value_node, mode_b);
- return res;
- }
- case EXPR_UNARY_DEREFERENCE: {
- ir_node *value_node = expression_to_firm(value);
- type_t *value_type = skip_typeref(value->base.type);
- assert(is_type_pointer(value_type));
-
- /* check for __based */
- const variable_t *const base_var = value_type->pointer.base_variable;
- if (base_var != NULL) {
- ir_node *const addr = create_symconst(dbgi, base_var->v.entity);
- ir_node *const base = deref_address(dbgi, base_var->base.type, addr);
- value_node = new_d_Add(dbgi, value_node, base, get_ir_mode_storage(value_type));
- }
- type_t *points_to = value_type->pointer.points_to;
- return deref_address(dbgi, points_to, value_node);
- }
- case EXPR_UNARY_POSTFIX_INCREMENT:
- case EXPR_UNARY_POSTFIX_DECREMENT:
- case EXPR_UNARY_PREFIX_INCREMENT:
- case EXPR_UNARY_PREFIX_DECREMENT:
- return create_incdec(expression);
- case EXPR_UNARY_CAST: {
- ir_node *value_node = expression_to_firm(value);
- type_t *from_type = value->base.type;
- return create_cast(dbgi, value_node, from_type, type);
- }
- case EXPR_UNARY_ASSUME:
- return handle_assume(dbgi, value);
+static ir_node *dereference_to_firm(unary_expression_t const *const expr)
+{
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_node *value = expression_to_value(expr->value);
+ type_t *const value_type = skip_typeref(expr->value->base.type);
+ assert(is_type_pointer(value_type));
- default:
- break;
+ /* check for __based */
+ variable_t const *const base_var = value_type->pointer.base_variable;
+ if (base_var) {
+ ir_node *const addr = create_symconst(dbgi, base_var->v.entity);
+ ir_node *const base = deref_address(dbgi, base_var->base.type, addr);
+ value = new_d_Add(dbgi, value, base, get_ir_mode_storage(value_type));
}
- panic("invalid UNEXPR type found");
+ type_t *const points_to = value_type->pointer.points_to;
+ return deref_address(dbgi, points_to, value);
}
-/**
- * produces a 0/1 depending of the value of a mode_b node
- */
-static ir_node *produce_condition_result(const expression_t *expression,
- ir_mode *mode, dbg_info *dbgi)
-{
- ir_node *const one_block = new_immBlock();
- ir_node *const zero_block = new_immBlock();
- create_condition_evaluation(expression, one_block, zero_block);
- mature_immBlock(one_block);
- mature_immBlock(zero_block);
-
- ir_node *const jmp_one = new_rd_Jmp(dbgi, one_block);
- ir_node *const jmp_zero = new_rd_Jmp(dbgi, zero_block);
- ir_node *const in_cf[2] = { jmp_one, jmp_zero };
- ir_node *const block = new_Block(lengthof(in_cf), in_cf);
- set_cur_block(block);
-
- ir_node *const one = new_Const(get_mode_one(mode));
- ir_node *const zero = new_Const(get_mode_null(mode));
- ir_node *const in[2] = { one, zero };
- ir_node *const val = new_d_Phi(dbgi, lengthof(in), in, mode);
-
- return val;
+static ir_node *negate_to_firm(unary_expression_t const *const expr)
+{
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ type_t *const type = skip_typeref(expr->base.type);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
+ ir_node *const value = create_conv(dbgi, expression_to_value(expr->value), mode);
+ return new_d_Minus(dbgi, value, mode);
}
static ir_node *adjust_for_pointer_arithmetic(dbg_info *dbgi,
ir_node *value, type_t *type)
{
- ir_mode *const mode = get_ir_mode_arithmetic(type_ptrdiff_t);
+ ir_mode *const mode = get_ir_mode_storage(type_ptrdiff_t);
assert(is_type_pointer(type));
pointer_type_t *const pointer_type = &type->pointer;
type_t *const points_to = skip_typeref(pointer_type->points_to);
return mul;
}
-static ir_node *create_op(dbg_info *dbgi, const binary_expression_t *expression,
- ir_node *left, ir_node *right)
+static ir_node *create_div(dbg_info *dbgi, ir_node *left, ir_node *right,
+ ir_mode *mode)
{
- ir_mode *mode;
- type_t *type_left = skip_typeref(expression->left->base.type);
- type_t *type_right = skip_typeref(expression->right->base.type);
-
- expression_kind_t kind = expression->base.kind;
+ ir_node *pin = new_Pin(new_NoMem());
+ ir_node *op = new_d_Div(dbgi, pin, left, right, mode,
+ op_pin_state_floats);
+ return new_d_Proj(dbgi, op, mode, pn_Div_res);
+}
+static ir_node *create_op(binary_expression_t const *const expr, ir_node *left, ir_node *right)
+{
+ ir_mode *mode;
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ type_t *const type_left = skip_typeref(expr->left->base.type);
+ type_t *const type_right = skip_typeref(expr->right->base.type);
+ expression_kind_t const kind = expr->base.kind;
switch (kind) {
case EXPR_BINARY_SHIFTLEFT:
case EXPR_BINARY_SHIFTRIGHT:
case EXPR_BINARY_SHIFTLEFT_ASSIGN:
case EXPR_BINARY_SHIFTRIGHT_ASSIGN:
- mode = get_ir_mode_arithmetic(expression->base.type);
+ mode = get_ir_mode_arithmetic(expr->base.type);
+ left = create_conv(dbgi, left, mode);
right = create_conv(dbgi, right, atomic_modes[ATOMIC_TYPE_UINT]);
break;
if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
const pointer_type_t *const ptr_type = &type_left->pointer;
- mode = get_ir_mode_arithmetic(expression->base.type);
+ mode = get_ir_mode_storage(expr->base.type);
ir_node *const elem_size = get_type_size_node(ptr_type->points_to);
ir_node *const conv_size = new_d_Conv(dbgi, elem_size, mode);
ir_node *const sub = new_d_Sub(dbgi, left, right, mode);
case EXPR_BINARY_SUB_ASSIGN:
if (is_type_pointer(type_left)) {
right = adjust_for_pointer_arithmetic(dbgi, right, type_left);
- mode = get_ir_mode_arithmetic(type_left);
+ mode = get_ir_mode_storage(type_left);
break;
}
goto normal_node;
case EXPR_BINARY_ADD_ASSIGN:
if (is_type_pointer(type_left)) {
right = adjust_for_pointer_arithmetic(dbgi, right, type_left);
- mode = get_ir_mode_arithmetic(type_left);
+ mode = get_ir_mode_storage(type_left);
break;
} else if (is_type_pointer(type_right)) {
left = adjust_for_pointer_arithmetic(dbgi, left, type_right);
- mode = get_ir_mode_arithmetic(type_right);
+ mode = get_ir_mode_storage(type_right);
break;
}
goto normal_node;
default:
normal_node:
- mode = get_ir_mode_arithmetic(type_right);
- left = create_conv(dbgi, left, mode);
+ mode = get_ir_mode_arithmetic(type_right);
+ left = create_conv(dbgi, left, mode);
+ right = create_conv(dbgi, right, mode);
break;
}
case EXPR_BINARY_MUL_ASSIGN:
case EXPR_BINARY_MUL:
return new_d_Mul(dbgi, left, right, mode);
+ case EXPR_BINARY_DIV:
+ case EXPR_BINARY_DIV_ASSIGN:
+ return create_div(dbgi, left, right, mode);
case EXPR_BINARY_BITWISE_AND:
case EXPR_BINARY_BITWISE_AND_ASSIGN:
return new_d_And(dbgi, left, right, mode);
} else {
return new_d_Shr(dbgi, left, right, mode);
}
- case EXPR_BINARY_DIV:
- case EXPR_BINARY_DIV_ASSIGN: {
- ir_node *pin = new_Pin(new_NoMem());
- ir_node *op = new_d_Div(dbgi, pin, left, right, mode,
- op_pin_state_floats);
- ir_node *res = new_d_Proj(dbgi, op, mode, pn_Div_res);
- return res;
- }
case EXPR_BINARY_MOD:
case EXPR_BINARY_MOD_ASSIGN: {
ir_node *pin = new_Pin(new_NoMem());
}
}
-static ir_node *create_lazy_op(const binary_expression_t *expression)
+static ir_node *binop_to_firm(binary_expression_t const *const expr)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- type_t *type = skip_typeref(expression->base.type);
- ir_mode *mode = get_ir_mode_arithmetic(type);
-
- if (is_constant_expression(expression->left) == EXPR_CLASS_CONSTANT) {
- bool val = fold_constant_to_bool(expression->left);
- expression_kind_t ekind = expression->base.kind;
- assert(ekind == EXPR_BINARY_LOGICAL_AND || ekind == EXPR_BINARY_LOGICAL_OR);
- if (ekind == EXPR_BINARY_LOGICAL_AND) {
- if (!val) {
- return new_Const(get_mode_null(mode));
- }
+ ir_node *const left = expression_to_value(expr->left);
+ ir_node *const right = expression_to_value(expr->right);
+ return create_op(expr, left, right);
+}
+
+/**
+ * Check if a given expression is a GNU __builtin_expect() call.
+ */
+static bool is_builtin_expect(const expression_t *expression)
+{
+ if (expression->kind != EXPR_CALL)
+ return false;
+
+ expression_t *function = expression->call.function;
+ if (function->kind != EXPR_REFERENCE)
+ return false;
+ reference_expression_t *ref = &function->reference;
+ if (ref->entity->kind != ENTITY_FUNCTION ||
+ ref->entity->function.btk != BUILTIN_EXPECT)
+ return false;
+
+ return true;
+}
+
+static void compare_to_control_flow(expression_t const *const expr, ir_node *const left, ir_node *const right, ir_relation const relation, jump_target *const true_target, jump_target *const false_target)
+{
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_node *const cmp = new_d_Cmp(dbgi, left, right, relation);
+ if (is_Const(cmp)) {
+ if (tarval_is_null(get_Const_tarval(cmp))) {
+ jump_to_target(false_target);
} else {
- if (val) {
- return new_Const(get_mode_one(mode));
+ jump_to_target(true_target);
+ }
+ } else {
+ ir_node *const cond = new_d_Cond(dbgi, cmp);
+ 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);
+
+ /* set branch prediction info based on __builtin_expect */
+ if (is_builtin_expect(expr) && is_Cond(cond)) {
+ call_argument_t *const argument = expr->call.arguments->next;
+ if (is_constant_expression(argument->expression) != EXPR_CLASS_VARIABLE) {
+ bool const cnst = fold_constant_to_bool(argument->expression);
+ cond_jmp_predicate const pred = cnst ? COND_JMP_PRED_TRUE : COND_JMP_PRED_FALSE;
+ set_Cond_jmp_pred(cond, pred);
}
}
- if (is_constant_expression(expression->right) == EXPR_CLASS_CONSTANT) {
- bool valr = fold_constant_to_bool(expression->right);
- return create_Const_from_bool(mode, valr);
+ add_pred_to_jump_target(true_target, true_proj);
+ add_pred_to_jump_target(false_target, false_proj);
+ }
+ set_unreachable_now();
+}
+
+static ir_node *control_flow_to_1_0(expression_t const *const expr, jump_target *const true_target, jump_target *const false_target)
+{
+ ir_node *val = NULL;
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *const mode = get_ir_mode_storage(expr->base.type);
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
+
+ if (enter_jump_target(true_target)) {
+ jump_to_target(&exit_target);
+ val = new_d_Const(dbgi, get_mode_one(mode));
+ }
+
+ if (enter_jump_target(false_target)) {
+ jump_to_target(&exit_target);
+ ir_node *const zero = new_d_Const(dbgi, get_mode_null(mode));
+ if (val) {
+ ir_node *const in[] = { val, zero };
+ val = new_rd_Phi(dbgi, exit_target.block, lengthof(in), in, mode);
+ } else {
+ val = zero;
}
+ }
+
+ if (!enter_jump_target(&exit_target)) {
+ set_cur_block(new_Block(0, NULL));
+ val = new_d_Bad(dbgi, mode);
+ }
+ return val;
+}
+
+static ir_node *binop_assign_to_firm(binary_expression_t const *const expr)
+{
+ ir_node *const right = expression_to_value(expr->right);
+ expression_t const *const left_expr = expr->left;
+ ir_node *const addr = expression_to_addr(left_expr);
+ ir_node *const left = get_value_from_lvalue(left_expr, addr);
+ ir_node *result = create_op(expr, left, right);
- return produce_condition_result(expression->right, mode, dbgi);
+ type_t *const type = skip_typeref(expr->base.type);
+ if (is_type_atomic(type, ATOMIC_TYPE_BOOL)) {
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ ir_mode *const mode = get_irn_mode(result);
+ ir_node *const zero = new_Const(get_mode_null(mode));
+ compare_to_control_flow((expression_t const*)expr, result, zero, ir_relation_unordered_less_greater, &true_target, &false_target);
+ result = control_flow_to_1_0((expression_t const*)expr, &true_target, &false_target);
}
- return produce_condition_result((const expression_t*) expression, mode,
- dbgi);
+ return set_value_for_expression_addr(left_expr, result, addr);
}
-typedef ir_node * (*create_arithmetic_func)(dbg_info *dbgi, ir_node *left,
- ir_node *right, ir_mode *mode);
+static ir_node *assign_expression_to_firm(binary_expression_t const *const expr)
+{
+ ir_node *const addr = expression_to_addr(expr->left);
+ ir_node *const right = expression_to_value(expr->right);
+ return set_value_for_expression_addr(expr->left, right, addr);
+}
-static ir_node *create_assign_binop(const binary_expression_t *expression)
+/** evaluate an expression and discard the result, but still produce the
+ * side-effects. */
+static void evaluate_expression_discard_result(const expression_t *expression)
{
- dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
- const expression_t *left_expr = expression->left;
- type_t *type = skip_typeref(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 *result = create_op(dbgi, expression, left, right);
+ type_t *type = skip_typeref(expression->base.type);
+ if (is_type_complex(type)) {
+ expression_to_complex(expression);
+ } else {
+ expression_to_value(expression);
+ }
+}
- result = create_cast(dbgi, result, expression->right->base.type, type);
- result = do_strict_conv(dbgi, result);
+static ir_node *comma_expression_to_firm(binary_expression_t const *const expr)
+{
+ evaluate_expression_discard_result(expr->left);
+ return expression_to_value(expr->right);
+}
- result = set_value_for_expression_addr(left_expr, result, left_addr);
+static ir_node *array_access_addr(const array_access_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+ ir_node *base_addr = expression_to_value(expression->array_ref);
+ ir_node *offset = expression_to_value(expression->index);
+ type_t *ref_type = skip_typeref(expression->array_ref->base.type);
+ ir_node *real_offset = adjust_for_pointer_arithmetic(dbgi, offset, ref_type);
+ ir_node *result = new_d_Add(dbgi, base_addr, real_offset, mode_P_data);
- if (!is_type_compound(type)) {
- ir_mode *mode_arithmetic = get_ir_mode_arithmetic(type);
- result = create_conv(dbgi, result, mode_arithmetic);
- }
return result;
}
-static ir_node *binary_expression_to_firm(const binary_expression_t *expression)
+static ir_node *array_access_to_firm(
+ const array_access_expression_t *expression)
{
- expression_kind_t kind = expression->base.kind;
-
- switch(kind) {
- case EXPR_BINARY_EQUAL:
- case EXPR_BINARY_NOTEQUAL:
- case EXPR_BINARY_LESS:
- case EXPR_BINARY_LESSEQUAL:
- case EXPR_BINARY_GREATER:
- case EXPR_BINARY_GREATEREQUAL:
- case EXPR_BINARY_ISGREATER:
- case EXPR_BINARY_ISGREATEREQUAL:
- case EXPR_BINARY_ISLESS:
- case EXPR_BINARY_ISLESSEQUAL:
- case EXPR_BINARY_ISLESSGREATER:
- case EXPR_BINARY_ISUNORDERED: {
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_node *left = expression_to_firm(expression->left);
- ir_node *right = expression_to_firm(expression->right);
- ir_relation relation = get_relation(kind);
- ir_node *cmp = new_d_Cmp(dbgi, left, right, relation);
- return cmp;
- }
- case EXPR_BINARY_ASSIGN: {
- ir_node *addr = expression_to_addr(expression->left);
- ir_node *right = expression_to_firm(expression->right);
- ir_node *res
- = set_value_for_expression_addr(expression->left, right, addr);
-
- type_t *type = skip_typeref(expression->base.type);
- if (!is_type_compound(type)) {
- ir_mode *mode_arithmetic = get_ir_mode_arithmetic(type);
- res = create_conv(NULL, res, mode_arithmetic);
- }
- return res;
- }
- case EXPR_BINARY_ADD:
- case EXPR_BINARY_SUB:
- case EXPR_BINARY_MUL:
- case EXPR_BINARY_DIV:
- case EXPR_BINARY_MOD:
- case EXPR_BINARY_BITWISE_AND:
- case EXPR_BINARY_BITWISE_OR:
- case EXPR_BINARY_BITWISE_XOR:
- case EXPR_BINARY_SHIFTLEFT:
- case EXPR_BINARY_SHIFTRIGHT:
- {
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_node *left = expression_to_firm(expression->left);
- ir_node *right = expression_to_firm(expression->right);
- return create_op(dbgi, expression, left, right);
- }
- case EXPR_BINARY_LOGICAL_AND:
- case EXPR_BINARY_LOGICAL_OR:
- return create_lazy_op(expression);
- case EXPR_BINARY_COMMA:
- /* create side effects of left side */
- (void) expression_to_firm(expression->left);
- return _expression_to_firm(expression->right);
-
- case EXPR_BINARY_ADD_ASSIGN:
- case EXPR_BINARY_SUB_ASSIGN:
- case EXPR_BINARY_MUL_ASSIGN:
- case EXPR_BINARY_MOD_ASSIGN:
- case EXPR_BINARY_DIV_ASSIGN:
- case EXPR_BINARY_BITWISE_AND_ASSIGN:
- case EXPR_BINARY_BITWISE_OR_ASSIGN:
- case EXPR_BINARY_BITWISE_XOR_ASSIGN:
- case EXPR_BINARY_SHIFTLEFT_ASSIGN:
- case EXPR_BINARY_SHIFTRIGHT_ASSIGN:
- return create_assign_binop(expression);
- default:
- panic("invalid binexpr type");
- }
-}
-
-static ir_node *array_access_addr(const array_access_expression_t *expression)
-{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_node *base_addr = expression_to_firm(expression->array_ref);
- ir_node *offset = expression_to_firm(expression->index);
- type_t *ref_type = skip_typeref(expression->array_ref->base.type);
- ir_node *real_offset = adjust_for_pointer_arithmetic(dbgi, offset, ref_type);
- ir_node *result = new_d_Add(dbgi, base_addr, real_offset, mode_P_data);
-
- return result;
-}
-
-static ir_node *array_access_to_firm(
- const array_access_expression_t *expression)
-{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_node *addr = array_access_addr(expression);
- type_t *type = revert_automatic_type_conversion(
- (const expression_t*) expression);
- type = skip_typeref(type);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+ ir_node *addr = array_access_addr(expression);
+ type_t *type = revert_automatic_type_conversion(
+ (const expression_t*) expression);
+ type = skip_typeref(type);
return deref_address(dbgi, type, addr);
}
static ir_node *offsetof_to_firm(const offsetof_expression_t *expression)
{
- ir_mode *mode = get_ir_mode_arithmetic(expression->base.type);
+ ir_mode *mode = get_ir_mode_storage(expression->base.type);
long offset = get_offsetof_offset(expression);
ir_tarval *tv = new_tarval_from_long(offset, mode);
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
return new_d_Const(dbgi, tv);
}
type_t *type)
{
/* create the ir_initializer */
- ir_graph *const old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
-
+ PUSH_IRG(get_const_code_irg());
ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
-
- assert(current_ir_graph == get_const_code_irg());
- current_ir_graph = old_current_ir_graph;
+ POP_IRG();
ident *const id = id_unique("initializer.%u");
ir_type *const irtype = get_ir_type(type);
static ir_node *compound_literal_addr(compound_literal_expression_t const *const expression)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
type_t *type = expression->type;
initializer_t *initializer = expression->initializer;
- if (is_constant_initializer(initializer) == EXPR_CLASS_CONSTANT) {
+ if (expression->global_scope || (
+ type->base.qualifiers & TYPE_QUALIFIER_CONST &&
+ is_constant_initializer(initializer) != EXPR_CLASS_VARIABLE
+ )) {
ir_entity *entity = create_initializer_entity(dbgi, initializer, type);
return create_symconst(dbgi, entity);
} else {
static ir_node *compound_literal_to_firm(compound_literal_expression_t const* const expr)
{
- dbg_info *const dbgi = get_dbg_info(&expr->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
type_t *const type = expr->type;
ir_node *const addr = compound_literal_addr(expr);
return deref_address(dbgi, type, addr);
/* §6.5.3.4:2 if the type is a VLA, evaluate the expression. */
if (is_type_array(type) && type->array.is_vla
&& expression->tp_expression != NULL) {
- expression_to_firm(expression->tp_expression);
+ expression_to_value(expression->tp_expression);
}
return get_type_size_node(type);
}
-static entity_t *get_expression_entity(const expression_t *expression)
-{
- if (expression->kind != EXPR_REFERENCE)
- return NULL;
+static unsigned get_object_alignment(expression_t const *expr);
- return expression->reference.entity;
+static unsigned get_address_alignment(expression_t const *const expr)
+{
+ if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+ return get_object_alignment(expr->unary.value);
+ } else {
+ type_t *const type = skip_typeref(expr->base.type);
+ assert(is_type_pointer(type));
+ return get_type_alignment(type->pointer.points_to);
+ }
}
-static unsigned get_cparser_entity_alignment(const entity_t *entity)
+static unsigned get_object_alignment(expression_t const *const expr)
{
- switch(entity->kind) {
- case DECLARATION_KIND_CASES:
- return entity->declaration.alignment;
- case ENTITY_STRUCT:
- case ENTITY_UNION:
- return entity->compound.alignment;
- case ENTITY_TYPEDEF:
- return entity->typedefe.alignment;
- default:
- break;
+ entity_t *ent;
+ switch (expr->kind) {
+ case EXPR_ARRAY_ACCESS: return get_address_alignment(expr->array_access.array_ref);
+ case EXPR_UNARY_DEREFERENCE: return get_address_alignment(expr->unary.value);
+ case EXPR_REFERENCE: ent = expr->reference.entity; break;
+ case EXPR_SELECT: ent = expr->select.compound_entry; break;
+ default: return get_type_alignment(expr->base.type);
}
- return 0;
+ assert(is_declaration(ent));
+ return ent->declaration.alignment;
}
/**
*/
static ir_node *alignof_to_firm(const typeprop_expression_t *expression)
{
- unsigned alignment = 0;
+ unsigned const alignment = expression->tp_expression
+ ? get_object_alignment(expression->tp_expression)
+ : get_type_alignment(expression->type);
- const expression_t *tp_expression = expression->tp_expression;
- if (tp_expression != NULL) {
- entity_t *entity = get_expression_entity(tp_expression);
- if (entity != NULL) {
- alignment = get_cparser_entity_alignment(entity);
- }
- }
-
- if (alignment == 0) {
- type_t *type = expression->type;
- alignment = get_type_alignment(type);
- }
-
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_mode *mode = get_ir_mode_arithmetic(expression->base.type);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+ ir_mode *mode = get_ir_mode_storage(expression->base.type);
ir_tarval *tv = new_tarval_from_long(alignment, mode);
return new_d_Const(dbgi, tv);
}
static void init_ir_types(void);
-static ir_tarval *fold_constant_to_tarval(const expression_t *expression)
+ir_tarval *fold_constant_to_tarval(const expression_t *expression)
{
- assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT);
+ assert(is_constant_expression(expression) >= EXPR_CLASS_CONSTANT);
bool constant_folding_old = constant_folding;
constant_folding = true;
init_ir_types();
- ir_graph *old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
+ PUSH_IRG(get_const_code_irg());
+ ir_node *const cnst = expression_to_value(expression);
+ POP_IRG();
+
+ set_optimize(old_optimize);
+ set_opt_constant_folding(old_constant_folding);
+ constant_folding = constant_folding_old;
+
+ if (!is_Const(cnst))
+ panic("couldn't fold constant");
+ return get_Const_tarval(cnst);
+}
+
+static complex_constant fold_complex_constant(const expression_t *expression)
+{
+ assert(is_constant_expression(expression) >= EXPR_CLASS_CONSTANT);
+
+ bool constant_folding_old = constant_folding;
+ constant_folding = true;
+ int old_optimize = get_optimize();
+ int old_constant_folding = get_opt_constant_folding();
+ set_optimize(1);
+ set_opt_constant_folding(1);
+
+ init_ir_types();
- ir_node *const cnst = _expression_to_firm(expression);
+ PUSH_IRG(get_const_code_irg());
+ complex_value value = expression_to_complex(expression);
+ POP_IRG();
- current_ir_graph = old_current_ir_graph;
set_optimize(old_optimize);
set_opt_constant_folding(old_constant_folding);
- if (!is_Const(cnst)) {
+ if (!is_Const(value.real) || !is_Const(value.imag)) {
panic("couldn't fold constant");
}
constant_folding = constant_folding_old;
- ir_tarval *const tv = get_Const_tarval(cnst);
- ir_mode *const mode = get_ir_mode_arithmetic(skip_typeref(expression->base.type));
- return tarval_convert_to(tv, mode);
+ return (complex_constant) {
+ get_Const_tarval(value.real),
+ get_Const_tarval(value.imag)
+ };
}
/* this function is only used in parser.c, but it relies on libfirm functionality */
bool fold_constant_to_bool(const expression_t *expression)
{
- ir_tarval *tv = fold_constant_to_tarval(expression);
- return !tarval_is_null(tv);
+ type_t *type = skip_typeref(expression->base.type);
+ if (is_type_complex(type)) {
+ complex_constant tvs = fold_complex_constant(expression);
+ return !tarval_is_null(tvs.real) || !tarval_is_null(tvs.imag);
+ } else {
+ ir_tarval *tv = fold_constant_to_tarval(expression);
+ return !tarval_is_null(tv);
+ }
}
static ir_node *conditional_to_firm(const conditional_expression_t *expression)
{
- dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ ir_node *const cond_expr = expression_to_control_flow(expression->condition, &true_target, &false_target);
+
+ ir_node *val = NULL;
+ dbg_info *const dbgi = get_dbg_info(&expression->base.pos);
+ type_t *const type = skip_typeref(expression->base.type);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
+
+ if (enter_jump_target(&true_target)) {
+ if (expression->true_expression) {
+ val = expression_to_value(expression->true_expression);
+ } else if (cond_expr) {
+ val = cond_expr;
+ } else {
+ /* Condition ended with a short circuit (&&, ||, !) operation or a
+ * comparison. Generate a "1" as value for the true branch. */
+ val = new_Const(get_mode_one(mode));
+ }
+ if (val)
+ val = create_conv(dbgi, val, mode);
+ jump_to_target(&exit_target);
+ }
- /* first try to fold a constant condition */
- if (is_constant_expression(expression->condition) == EXPR_CLASS_CONSTANT) {
- bool val = fold_constant_to_bool(expression->condition);
+ if (enter_jump_target(&false_target)) {
+ ir_node *false_val = expression_to_value(expression->false_expression);
+ if (false_val)
+ false_val = create_conv(dbgi, false_val, mode);
+ jump_to_target(&exit_target);
if (val) {
- expression_t *true_expression = expression->true_expression;
- if (true_expression == NULL)
- true_expression = expression->condition;
- return expression_to_firm(true_expression);
+ ir_node *const in[] = { val, false_val };
+ val = new_rd_Phi(dbgi, exit_target.block, lengthof(in), in, get_irn_mode(val));
} else {
- return expression_to_firm(expression->false_expression);
+ val = false_val;
}
}
- ir_node *const true_block = new_immBlock();
- ir_node *const false_block = new_immBlock();
- ir_node *const cond_expr = create_condition_evaluation(expression->condition, true_block, false_block);
- mature_immBlock(true_block);
- mature_immBlock(false_block);
-
- set_cur_block(true_block);
- ir_node *true_val;
- if (expression->true_expression != NULL) {
- true_val = expression_to_firm(expression->true_expression);
- } else if (cond_expr != NULL && get_irn_mode(cond_expr) != mode_b) {
- true_val = cond_expr;
- } else {
- /* Condition ended with a short circuit (&&, ||, !) operation or a
- * comparison. Generate a "1" as value for the true branch. */
- true_val = new_Const(get_mode_one(mode_Is));
+ if (!enter_jump_target(&exit_target)) {
+ set_cur_block(new_Block(0, NULL));
+ if (!is_type_void(type))
+ val = new_Bad(mode);
}
- ir_node *const true_jmp = new_d_Jmp(dbgi);
-
- set_cur_block(false_block);
- ir_node *const false_val = expression_to_firm(expression->false_expression);
- ir_node *const false_jmp = new_d_Jmp(dbgi);
-
- /* create the common block */
- ir_node *const in_cf[2] = { true_jmp, false_jmp };
- ir_node *const block = new_Block(lengthof(in_cf), in_cf);
- set_cur_block(block);
-
- /* TODO improve static semantics, so either both or no values are NULL */
- if (true_val == NULL || false_val == NULL)
- return NULL;
-
- ir_node *const in[2] = { true_val, false_val };
- type_t *const type = skip_typeref(expression->base.type);
- ir_mode *const mode = get_ir_mode_arithmetic(type);
- ir_node *const val = new_d_Phi(dbgi, lengthof(in), in, mode);
-
return val;
}
*/
static ir_node *select_addr(const select_expression_t *expression)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
construct_select_compound(expression);
- ir_node *compound_addr = expression_to_firm(expression->compound);
+ ir_node *compound_addr = expression_to_value(expression->compound);
entity_t *entry = expression->compound_entry;
assert(entry->kind == ENTITY_COMPOUND_MEMBER);
static ir_node *select_to_firm(const select_expression_t *expression)
{
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
ir_node *addr = select_addr(expression);
type_t *type = revert_automatic_type_conversion(
(const expression_t*) expression);
case TYPE_ATOMIC: {
const atomic_type_t *const atomic_type = &type->atomic;
switch (atomic_type->akind) {
- /* should not be reached */
- case ATOMIC_TYPE_INVALID:
- tc = no_type_class;
- goto make_const;
-
/* gcc cannot do that */
case ATOMIC_TYPE_VOID:
tc = void_type_class;
tc = real_type_class;
goto make_const;
}
- panic("Unexpected atomic type in classify_type_to_firm().");
+ panic("Unexpected atomic type.");
}
case TYPE_COMPLEX: tc = complex_type_class; goto make_const;
case TYPE_ERROR:
break;
}
- panic("unexpected TYPE classify_type_to_firm().");
+ panic("unexpected type.");
}
make_const:;
- dbg_info *const dbgi = get_dbg_info(&expr->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
ir_mode *const mode = atomic_modes[ATOMIC_TYPE_INT];
ir_tarval *const tv = new_tarval_from_long(tc, mode);
return new_d_Const(dbgi, tv);
static ir_node *function_name_to_firm(
const funcname_expression_t *const expr)
{
- switch(expr->kind) {
+ switch (expr->kind) {
case FUNCNAME_FUNCTION:
case FUNCNAME_PRETTY_FUNCTION:
case FUNCNAME_FUNCDNAME:
if (current_function_name == NULL) {
- const source_position_t *const src_pos = &expr->base.source_position;
- const char *name = current_function_entity->base.symbol->string;
- const string_t string = { name, strlen(name) };
- current_function_name = string_to_firm(src_pos, "__func__.%u", STRING_ENCODING_CHAR, &string);
+ position_t const *const src_pos = &expr->base.pos;
+ char const *const name = current_function_entity->base.symbol->string;
+ string_t const string = { name, strlen(name), STRING_ENCODING_CHAR };
+ current_function_name = string_to_firm(src_pos, "__func__.%u", &string);
}
return current_function_name;
case FUNCNAME_FUNCSIG:
if (current_funcsig == NULL) {
- const source_position_t *const src_pos = &expr->base.source_position;
- ir_entity *ent = get_irg_entity(current_ir_graph);
- const char *const name = get_entity_ld_name(ent);
- const string_t string = { name, strlen(name) };
- current_funcsig = string_to_firm(src_pos, "__FUNCSIG__.%u", STRING_ENCODING_CHAR, &string);
+ position_t const *const src_pos = &expr->base.pos;
+ ir_entity *const ent = get_irg_entity(current_ir_graph);
+ char const *const name = get_entity_ld_name(ent);
+ string_t const string = { name, strlen(name), STRING_ENCODING_CHAR };
+ current_funcsig = string_to_firm(src_pos, "__FUNCSIG__.%u", &string);
}
return current_funcsig;
}
}
ir_node *const frame = get_irg_frame(current_ir_graph);
- dbg_info *const dbgi = get_dbg_info(&expr->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
ir_node *const no_mem = new_NoMem();
ir_node *const arg_sel = new_d_simpleSel(dbgi, no_mem, frame, param_ent);
- set_value_for_expression(expr->ap, arg_sel);
+ set_value_for_expression_addr(expr->ap, arg_sel, NULL);
return NULL;
}
expression_t *const ap_expr = expr->ap;
ir_node *const ap_addr = expression_to_addr(ap_expr);
ir_node *const ap = get_value_from_lvalue(ap_expr, ap_addr);
- dbg_info *const dbgi = get_dbg_info(&expr->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
ir_node *const res = deref_address(dbgi, type, ap);
ir_node *const cnst = get_type_size_node(expr->base.type);
*/
static ir_node *va_copy_expression_to_firm(const va_copy_expression_t *const expr)
{
- ir_node *const src = expression_to_firm(expr->src);
- set_value_for_expression(expr->dst, src);
+ ir_node *const src = expression_to_value(expr->src);
+ set_value_for_expression_addr(expr->dst, src, NULL);
return NULL;
}
static ir_node *dereference_addr(const unary_expression_t *const expression)
{
assert(expression->base.kind == EXPR_UNARY_DEREFERENCE);
- return expression_to_firm(expression->value);
+ return expression_to_value(expression->value);
}
/**
*/
static ir_node *expression_to_addr(const expression_t *expression)
{
- switch(expression->kind) {
+ switch (expression->kind) {
case EXPR_ARRAY_ACCESS:
return array_access_addr(&expression->array_access);
- case EXPR_CALL:
- return call_expression_to_firm(&expression->call);
case EXPR_COMPOUND_LITERAL:
return compound_literal_addr(&expression->compound_literal);
case EXPR_REFERENCE:
static ir_node *builtin_constant_to_firm(
const builtin_constant_expression_t *expression)
{
- ir_mode *const mode = get_ir_mode_arithmetic(expression->base.type);
- bool const v = is_constant_expression(expression->value) == EXPR_CLASS_CONSTANT;
+ ir_mode *const mode = get_ir_mode_storage(expression->base.type);
+ bool const v = is_constant_expression(expression->value) != EXPR_CLASS_VARIABLE;
return create_Const_from_bool(mode, v);
}
type_t *const left = get_unqualified_type(skip_typeref(expression->left));
type_t *const right = get_unqualified_type(skip_typeref(expression->right));
bool const value = types_compatible(left, right);
- ir_mode *const mode = get_ir_mode_arithmetic(expression->base.type);
+ ir_mode *const mode = get_ir_mode_storage(expression->base.type);
return create_Const_from_bool(mode, value);
}
-static ir_node *get_label_block(label_t *label)
+static void prepare_label_target(label_t *const label)
{
- if (label->block != NULL)
- return label->block;
-
- /* 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 *block = new_immBlock();
-
- label->block = block;
-
- ARR_APP1(label_t *, all_labels, label);
-
- current_ir_graph = rem;
- return block;
+ if (label->address_taken && !label->indirect_block) {
+ ir_node *const iblock = new_immBlock();
+ label->indirect_block = iblock;
+ ARR_APP1(ir_node*, ijmp_blocks, iblock);
+ jump_from_block_to_target(&label->target, iblock);
+ }
}
/**
*/
static ir_node *label_address_to_firm(const label_address_expression_t *label)
{
- dbg_info *dbgi = get_dbg_info(&label->base.source_position);
- ir_node *block = get_label_block(label->label);
- ir_entity *entity = create_Block_entity(block);
+ /* Beware: Might be called from create initializer with current_ir_graph
+ * set to const_code_irg. */
+ PUSH_IRG(current_function);
+ prepare_label_target(label->label);
+ POP_IRG();
symconst_symbol value;
- value.entity_p = entity;
+ value.entity_p = create_Block_entity(label->label->indirect_block);
+ dbg_info *const dbgi = get_dbg_info(&label->base.pos);
return new_d_SymConst(dbgi, mode_P_code, value, symconst_addr_ent);
}
-/**
- * creates firm nodes for an expression. The difference between this function
- * and expression_to_firm is, that this version might produce mode_b nodes
- * instead of mode_Is.
- */
-static ir_node *_expression_to_firm(expression_t const *const expr)
+static ir_node *expression_to_value(expression_t const *const expr)
{
#ifndef NDEBUG
if (!constant_folding) {
assert(!expr->base.transformed);
((expression_t*)expr)->base.transformed = true;
}
+ assert(!is_type_complex(skip_typeref(expr->base.type)));
#endif
switch (expr->kind) {
+ case EXPR_UNARY_CAST:
+ if (!is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_BOOL))
+ return create_cast(&expr->unary);
+ /* FALLTHROUGH */
+ case EXPR_BINARY_EQUAL:
+ case EXPR_BINARY_GREATER:
+ case EXPR_BINARY_GREATEREQUAL:
+ case EXPR_BINARY_ISGREATER:
+ case EXPR_BINARY_ISGREATEREQUAL:
+ case EXPR_BINARY_ISLESS:
+ case EXPR_BINARY_ISLESSEQUAL:
+ case EXPR_BINARY_ISLESSGREATER:
+ case EXPR_BINARY_ISUNORDERED:
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_LOGICAL_AND:
+ case EXPR_BINARY_LOGICAL_OR:
+ case EXPR_BINARY_NOTEQUAL:
+ case EXPR_UNARY_NOT: {
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ expression_to_control_flow(expr, &true_target, &false_target);
+ return control_flow_to_1_0(expr, &true_target, &false_target);
+ }
+
+ case EXPR_BINARY_ADD:
+ case EXPR_BINARY_BITWISE_AND:
+ case EXPR_BINARY_BITWISE_OR:
+ case EXPR_BINARY_BITWISE_XOR:
+ case EXPR_BINARY_DIV:
+ case EXPR_BINARY_MOD:
+ case EXPR_BINARY_MUL:
+ case EXPR_BINARY_SHIFTLEFT:
+ case EXPR_BINARY_SHIFTRIGHT:
+ case EXPR_BINARY_SUB:
+ return binop_to_firm(&expr->binary);
+
+ case EXPR_BINARY_ADD_ASSIGN:
+ case EXPR_BINARY_BITWISE_AND_ASSIGN:
+ case EXPR_BINARY_BITWISE_OR_ASSIGN:
+ case EXPR_BINARY_BITWISE_XOR_ASSIGN:
+ case EXPR_BINARY_DIV_ASSIGN:
+ case EXPR_BINARY_MOD_ASSIGN:
+ case EXPR_BINARY_MUL_ASSIGN:
+ case EXPR_BINARY_SHIFTLEFT_ASSIGN:
+ case EXPR_BINARY_SHIFTRIGHT_ASSIGN:
+ case EXPR_BINARY_SUB_ASSIGN:
+ return binop_assign_to_firm(&expr->binary);
+
+ {
+ bool inc;
+ bool pre;
+ case EXPR_UNARY_POSTFIX_DECREMENT: inc = false; pre = false; goto incdec;
+ case EXPR_UNARY_POSTFIX_INCREMENT: inc = true; pre = false; goto incdec;
+ case EXPR_UNARY_PREFIX_DECREMENT: inc = false; pre = true; goto incdec;
+ case EXPR_UNARY_PREFIX_INCREMENT: inc = true; pre = true; goto incdec;
+incdec:
+ return incdec_to_firm(&expr->unary, inc, pre);
+ }
+
+ case EXPR_UNARY_IMAG: {
+ complex_value irvalue = expression_to_complex(expr->unary.value);
+ return irvalue.imag;
+ }
+ case EXPR_UNARY_REAL: {
+ complex_value irvalue = expression_to_complex(expr->unary.value);
+ return irvalue.real;
+ }
+
case EXPR_ALIGNOF: return alignof_to_firm( &expr->typeprop);
case EXPR_ARRAY_ACCESS: return array_access_to_firm( &expr->array_access);
- case EXPR_BINARY_CASES: return binary_expression_to_firm( &expr->binary);
+ case EXPR_BINARY_ASSIGN: return assign_expression_to_firm( &expr->binary);
+ case EXPR_BINARY_COMMA: return comma_expression_to_firm( &expr->binary);
case EXPR_BUILTIN_CONSTANT_P: return builtin_constant_to_firm( &expr->builtin_constant);
case EXPR_BUILTIN_TYPES_COMPATIBLE_P: return builtin_types_compatible_to_firm(&expr->builtin_types_compatible);
case EXPR_CALL: return call_expression_to_firm( &expr->call);
case EXPR_CLASSIFY_TYPE: return classify_type_to_firm( &expr->classify_type);
case EXPR_COMPOUND_LITERAL: return compound_literal_to_firm( &expr->compound_literal);
case EXPR_CONDITIONAL: return conditional_to_firm( &expr->conditional);
+ case EXPR_ENUM_CONSTANT: return enum_constant_to_firm( &expr->reference);
case EXPR_FUNCNAME: return function_name_to_firm( &expr->funcname);
case EXPR_LABEL_ADDRESS: return label_address_to_firm( &expr->label_address);
case EXPR_LITERAL_CASES: return literal_to_firm( &expr->literal);
case EXPR_LITERAL_CHARACTER: return char_literal_to_firm( &expr->string_literal);
case EXPR_OFFSETOF: return offsetof_to_firm( &expr->offsetofe);
case EXPR_REFERENCE: return reference_expression_to_firm( &expr->reference);
- case EXPR_ENUM_CONSTANT: return enum_constant_to_firm( &expr->reference);
case EXPR_SELECT: return select_to_firm( &expr->select);
case EXPR_SIZEOF: return sizeof_to_firm( &expr->typeprop);
case EXPR_STATEMENT: return statement_expression_to_firm( &expr->statement);
- case EXPR_UNARY_CASES: return unary_expression_to_firm( &expr->unary);
+ case EXPR_STRING_LITERAL: return string_to_firm( &expr->base.pos, "str.%u", &expr->string_literal.value);
+ case EXPR_UNARY_ASSUME: return handle_assume( expr->unary.value);
+ case EXPR_UNARY_COMPLEMENT: return complement_to_firm( &expr->unary);
+ case EXPR_UNARY_DEREFERENCE: return dereference_to_firm( &expr->unary);
+ case EXPR_UNARY_NEGATE: return negate_to_firm( &expr->unary);
+ case EXPR_UNARY_PLUS: return expression_to_value( expr->unary.value);
+ case EXPR_UNARY_TAKE_ADDRESS: return expression_to_addr( expr->unary.value);
case EXPR_VA_ARG: return va_arg_expression_to_firm( &expr->va_arge);
case EXPR_VA_COPY: return va_copy_expression_to_firm( &expr->va_copye);
case EXPR_VA_START: return va_start_expression_to_firm( &expr->va_starte);
- case EXPR_STRING_LITERAL: return string_to_firm(&expr->base.source_position, "str.%u", expr->string_literal.encoding, &expr->string_literal.value);
+ case EXPR_UNARY_DELETE:
+ case EXPR_UNARY_DELETE_ARRAY:
+ case EXPR_UNARY_THROW:
+ panic("expression not implemented");
- case EXPR_ERROR: break;
+ case EXPR_ERROR:
+ break;
}
- panic("invalid expression found");
+ panic("invalid expression");
}
+static void complex_equality_evaluation(const binary_expression_t *binexpr,
+ jump_target *const true_target, jump_target *const false_target,
+ ir_relation relation);
+
+static complex_value complex_to_control_flow(const expression_t *expression,
+ jump_target *true_target,
+ jump_target *false_target);
+
/**
- * Check if a given expression is a GNU __builtin_expect() call.
+ * create a short-circuit expression evaluation that tries to construct
+ * efficient control flow structures for &&, || and ! expressions
*/
-static bool is_builtin_expect(const expression_t *expression)
+static ir_node *expression_to_control_flow(expression_t const *const expr, jump_target *const true_target, jump_target *const false_target)
{
- if (expression->kind != EXPR_CALL)
- return false;
+ switch (expr->kind) {
+ case EXPR_UNARY_NOT:
+ expression_to_control_flow(expr->unary.value, false_target, true_target);
+ return NULL;
- expression_t *function = expression->call.function;
- if (function->kind != EXPR_REFERENCE)
- return false;
- reference_expression_t *ref = &function->reference;
- if (ref->entity->kind != ENTITY_FUNCTION ||
- ref->entity->function.btk != BUILTIN_EXPECT)
- return false;
+ case EXPR_BINARY_LOGICAL_AND: {
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+ expression_to_control_flow(expr->binary.left, &extra_target, false_target);
+ if (enter_jump_target(&extra_target))
+ expression_to_control_flow(expr->binary.right, true_target, false_target);
+ return NULL;
+ }
- return true;
-}
+ case EXPR_BINARY_LOGICAL_OR: {
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+ expression_to_control_flow(expr->binary.left, true_target, &extra_target);
+ if (enter_jump_target(&extra_target))
+ expression_to_control_flow(expr->binary.right, true_target, false_target);
+ return NULL;
+ }
+
+ case EXPR_BINARY_COMMA:
+ evaluate_expression_discard_result(expr->binary.left);
+ return expression_to_control_flow(expr->binary.right, true_target, false_target);
-static bool produces_mode_b(const expression_t *expression)
-{
- switch (expression->kind) {
case EXPR_BINARY_EQUAL:
- case EXPR_BINARY_NOTEQUAL:
- case EXPR_BINARY_LESS:
- case EXPR_BINARY_LESSEQUAL:
case EXPR_BINARY_GREATER:
case EXPR_BINARY_GREATEREQUAL:
case EXPR_BINARY_ISGREATER:
case EXPR_BINARY_ISLESSEQUAL:
case EXPR_BINARY_ISLESSGREATER:
case EXPR_BINARY_ISUNORDERED:
- case EXPR_UNARY_NOT:
- return true;
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_NOTEQUAL: {
+ type_t *const type = skip_typeref(expr->binary.left->base.type);
+ ir_relation const relation = get_relation(expr->kind);
+ if (is_type_complex(type)) {
+ complex_equality_evaluation(&expr->binary, true_target,
+ false_target, relation);
+ return NULL;
+ }
- case EXPR_CALL:
- if (is_builtin_expect(expression)) {
- expression_t *argument = expression->call.arguments->expression;
- return produces_mode_b(argument);
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
+ ir_node *const left = create_conv(dbgi, expression_to_value(expr->binary.left), mode);
+ ir_node *const right = create_conv(dbgi, expression_to_value(expr->binary.right), mode);
+ compare_to_control_flow(expr, left, right, relation, true_target, false_target);
+ return NULL;
+ }
+
+ case EXPR_UNARY_CAST:
+ if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_BOOL)) {
+ expression_to_control_flow(expr->unary.value, true_target, false_target);
+ return NULL;
+ }
+ /* FALLTHROUGH */
+ default: {
+ type_t *const type = skip_typeref(expr->base.type);
+ if (is_type_complex(type)) {
+ complex_to_control_flow(expr, true_target, false_target);
+ return NULL;
}
- return false;
- case EXPR_BINARY_COMMA:
- return produces_mode_b(expression->binary.right);
- default:
- return false;
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
+ ir_node *const val = create_conv(dbgi, expression_to_value(expr), mode);
+ ir_node *const left = val;
+ ir_node *const right = new_Const(get_mode_null(get_irn_mode(val)));
+ ir_relation const relation = ir_relation_unordered_less_greater;
+ compare_to_control_flow(expr, left, right, relation, true_target, false_target);
+ return val;
+ }
}
}
-static ir_node *expression_to_firm(const expression_t *expression)
+static complex_value complex_conv(dbg_info *dbgi, complex_value value,
+ ir_mode *mode)
{
- if (!produces_mode_b(expression)) {
- ir_node *res = _expression_to_firm(expression);
- assert(res == NULL || get_irn_mode(res) != mode_b);
- return res;
+ return (complex_value) {
+ create_conv(dbgi, value.real, mode),
+ create_conv(dbgi, value.imag, mode)
+ };
+}
+
+static complex_value complex_conv_to_storage(dbg_info *const dbgi,
+ complex_value const value, type_t *const type)
+{
+ ir_mode *const mode = get_complex_mode_storage(type);
+ return complex_conv(dbgi, value, mode);
+}
+
+static void store_complex(dbg_info *dbgi, ir_node *addr, type_t *type,
+ complex_value value)
+{
+ value = complex_conv_to_storage(dbgi, value, type);
+ ir_graph *const irg = current_ir_graph;
+ ir_type *const irtype = get_ir_type(type);
+ ir_node *const mem = get_store();
+ ir_node *const nomem = get_irg_no_mem(irg);
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const real = create_conv(dbgi, value.real, mode);
+ ir_node *const imag = create_conv(dbgi, value.imag, mode);
+ ir_node *const storer = new_d_Store(dbgi, mem, addr, real, cons_floats);
+ ir_node *const memr = new_Proj(storer, mode_M, pn_Store_M);
+ ir_mode *const muint = atomic_modes[ATOMIC_TYPE_UINT];
+ ir_node *const one = new_Const(get_mode_one(muint));
+ ir_node *const in[1] = { one };
+ ir_entity *const arrent = get_array_element_entity(irtype);
+ ir_node *const addri = new_d_Sel(dbgi, nomem, addr, 1, in, arrent);
+ ir_node *const storei = new_d_Store(dbgi, memr, addri, imag, cons_floats);
+ ir_node *const memi = new_Proj(storei, mode_M, pn_Store_M);
+ set_store(memi);
+}
+
+static ir_node *complex_to_memory(dbg_info *dbgi, type_t *type,
+ complex_value value)
+{
+ ir_graph *const irg = current_ir_graph;
+ ir_type *const frame_type = get_irg_frame_type(irg);
+ ident *const id = id_unique("cmplex_tmp.%u");
+ ir_type *const irtype = get_ir_type(type);
+ ir_entity *const tmp_storage = new_entity(frame_type, id, irtype);
+ ir_node *const frame = get_irg_frame(irg);
+ ir_node *const nomem = get_irg_no_mem(irg);
+ ir_node *const addr = new_simpleSel(nomem, frame, tmp_storage);
+ set_entity_compiler_generated(tmp_storage, 1);
+ store_complex(dbgi, addr, type, value);
+ return addr;
+}
+
+static complex_value read_localvar_complex(dbg_info *dbgi, entity_t *const entity)
+{
+ assert(entity->declaration.kind == DECLARATION_KIND_LOCAL_VARIABLE
+ || entity->declaration.kind == DECLARATION_KIND_PARAMETER);
+ type_t *const type = skip_typeref(entity->declaration.type);
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const real = get_value(entity->variable.v.value_number, mode);
+ ir_node *const imag = get_value(entity->variable.v.value_number+1, mode);
+ ir_mode *const mode_arithmetic = get_complex_mode_arithmetic(type);
+ return (complex_value) {
+ create_conv(dbgi, real, mode_arithmetic),
+ create_conv(dbgi, imag, mode_arithmetic)
+ };
+}
+
+static complex_value complex_deref_address(dbg_info *const dbgi,
+ type_t *type, ir_node *const addr,
+ ir_cons_flags flags)
+{
+ type = skip_typeref(type);
+ assert(is_type_complex(type));
+
+ if (type->base.qualifiers & TYPE_QUALIFIER_VOLATILE)
+ flags |= cons_volatile;
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const memory = get_store();
+ ir_node *const load = new_d_Load(dbgi, memory, addr, mode, flags);
+ ir_node *const load_mem = new_Proj(load, mode_M, pn_Load_M);
+ ir_node *const load_res = new_Proj(load, mode, pn_Load_res);
+
+ ir_type *const irtype = get_ir_type(type);
+ ir_mode *const mode_uint = atomic_modes[ATOMIC_TYPE_UINT];
+ ir_node *const in[1] = { new_Const(get_mode_one(mode_uint)) };
+ ir_entity *const entity = get_array_element_entity(irtype);
+ ir_node *const nomem = get_irg_no_mem(current_ir_graph);
+ ir_node *const addr2 = new_Sel(nomem, addr, 1, in, entity);
+ ir_node *const load2 = new_d_Load(dbgi, load_mem, addr2, mode, flags);
+ ir_node *const load_mem2 = new_Proj(load2, mode_M, pn_Load_M);
+ ir_node *const load_res2 = new_Proj(load2, mode, pn_Load_res);
+ set_store(load_mem2);
+
+ return (complex_value) { load_res, load_res2 };
+}
+
+static complex_value complex_reference_to_firm(const reference_expression_t *ref)
+{
+ dbg_info *const dbgi = get_dbg_info(&ref->base.pos);
+ entity_t *const entity = ref->entity;
+ assert(is_declaration(entity));
+
+ switch ((declaration_kind_t)entity->declaration.kind) {
+ case DECLARATION_KIND_LOCAL_VARIABLE:
+ case DECLARATION_KIND_PARAMETER:
+ return read_localvar_complex(dbgi, entity);
+ default: {
+ ir_node *const addr = reference_addr(ref);
+ return complex_deref_address(dbgi, entity->declaration.type, addr, cons_none);
+ }
}
+}
- if (is_constant_expression(expression) == EXPR_CLASS_CONSTANT) {
- return new_Const(fold_constant_to_tarval(expression));
+static complex_value complex_select_to_firm(const select_expression_t *select)
+{
+ dbg_info *const dbgi = get_dbg_info(&select->base.pos);
+ ir_node *const addr = select_addr(select);
+ type_t *const type = skip_typeref(select->base.type);
+ return complex_deref_address(dbgi, type, addr, cons_none);
+}
+
+static complex_value complex_array_access_to_firm(
+ const array_access_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+ ir_node *addr = array_access_addr(expression);
+ type_t *type = skip_typeref(expression->base.type);
+ assert(is_type_complex(type));
+ return complex_deref_address(dbgi, type, addr, cons_none);
+}
+
+static complex_value get_complex_from_lvalue(const expression_t *expression,
+ ir_node *addr)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+
+ if (expression->kind == EXPR_REFERENCE) {
+ const reference_expression_t *ref = &expression->reference;
+
+ entity_t *entity = ref->entity;
+ assert(entity->kind == ENTITY_VARIABLE
+ || entity->kind == ENTITY_PARAMETER);
+ assert(entity->declaration.kind != DECLARATION_KIND_UNKNOWN);
+ if (entity->declaration.kind == DECLARATION_KIND_LOCAL_VARIABLE ||
+ entity->declaration.kind == DECLARATION_KIND_PARAMETER) {
+ return read_localvar_complex(dbgi, entity);
+ }
}
- /* we have to produce a 0/1 from the mode_b expression */
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_mode *mode = get_ir_mode_arithmetic(expression->base.type);
- return produce_condition_result(expression, mode, dbgi);
+ assert(addr != NULL);
+ return complex_deref_address(dbgi, expression->base.type, addr, cons_none);
}
-/**
- * create a short-circuit expression evaluation that tries to construct
- * efficient control flow structures for &&, || and ! expressions
- */
-static ir_node *create_condition_evaluation(const expression_t *expression,
- ir_node *true_block,
- ir_node *false_block)
+static complex_value complex_cast_to_firm(const unary_expression_t *expression)
{
- switch(expression->kind) {
- case EXPR_UNARY_NOT: {
- const unary_expression_t *unary_expression = &expression->unary;
- create_condition_evaluation(unary_expression->value, false_block,
- true_block);
- return NULL;
+ const expression_t *const value = expression->value;
+ dbg_info *const dbgi = get_dbg_info(&expression->base.pos);
+ type_t *const from_type = skip_typeref(value->base.type);
+ type_t *const to_type = skip_typeref(expression->base.type);
+ ir_mode *const mode = get_complex_mode_storage(to_type);
+
+ if (is_type_complex(from_type)) {
+ complex_value cvalue = expression_to_complex(value);
+ return complex_conv(dbgi, cvalue, mode);
+ } else {
+ ir_node *const value_node = expression_to_value(value);
+ ir_node *const zero = new_Const(get_mode_null(mode));
+ ir_node *const casted = create_conv(dbgi, value_node, mode);
+ return (complex_value) { casted, zero };
}
- case EXPR_BINARY_LOGICAL_AND: {
- const binary_expression_t *binary_expression = &expression->binary;
-
- ir_node *extra_block = new_immBlock();
- create_condition_evaluation(binary_expression->left, extra_block,
- false_block);
- mature_immBlock(extra_block);
- set_cur_block(extra_block);
- create_condition_evaluation(binary_expression->right, true_block,
- false_block);
- return NULL;
+}
+
+static complex_value complex_literal_to_firm(const literal_expression_t *literal)
+{
+ type_t *type = skip_typeref(literal->base.type);
+ ir_mode *mode = get_complex_mode_storage(type);
+ ir_node *litvalue = literal_to_firm_(literal, mode);
+ ir_node *zero = new_Const(get_mode_null(mode));
+ return (complex_value) { zero, litvalue };
+}
+
+typedef complex_value (*new_complex_binop)(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode);
+
+static complex_value new_complex_add(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ return (complex_value) {
+ new_d_Add(dbgi, left.real, right.real, mode),
+ new_d_Add(dbgi, left.imag, right.imag, mode)
+ };
+}
+
+static complex_value new_complex_sub(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ return (complex_value) {
+ new_d_Sub(dbgi, left.real, right.real, mode),
+ new_d_Sub(dbgi, left.imag, right.imag, mode)
+ };
+}
+
+static complex_value new_complex_mul(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ ir_node *const op1 = new_d_Mul(dbgi, left.real, right.real, mode);
+ ir_node *const op2 = new_d_Mul(dbgi, left.imag, right.imag, mode);
+ ir_node *const op3 = new_d_Mul(dbgi, left.real, right.imag, mode);
+ ir_node *const op4 = new_d_Mul(dbgi, left.imag, right.real, mode);
+ return (complex_value) {
+ new_d_Sub(dbgi, op1, op2, mode),
+ new_d_Add(dbgi, op3, op4, mode)
+ };
+}
+
+static complex_value new_complex_div(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ ir_node *const op1 = new_d_Mul(dbgi, left.real, right.real, mode);
+ ir_node *const op2 = new_d_Mul(dbgi, left.imag, right.imag, mode);
+ ir_node *const op3 = new_d_Mul(dbgi, left.imag, right.real, mode);
+ ir_node *const op4 = new_d_Mul(dbgi, left.real, right.imag, mode);
+ ir_node *const op5 = new_d_Mul(dbgi, right.real, right.real, mode);
+ ir_node *const op6 = new_d_Mul(dbgi, right.imag, right.imag, mode);
+ ir_node *const real_dividend = new_d_Add(dbgi, op1, op2, mode);
+ ir_node *const real_divisor = new_d_Add(dbgi, op5, op6, mode);
+ ir_node *const imag_dividend = new_d_Sub(dbgi, op3, op4, mode);
+ ir_node *const imag_divisor = new_d_Add(dbgi, op5, op6, mode);
+ return (complex_value) {
+ create_div(dbgi, real_dividend, real_divisor, mode),
+ create_div(dbgi, imag_dividend, imag_divisor, mode)
+ };
+}
+
+typedef complex_value (*new_complex_unop)(dbg_info *dbgi, complex_value value,
+ ir_mode *mode);
+
+static complex_value new_complex_increment(dbg_info *dbgi, complex_value value,
+ ir_mode *mode)
+{
+ ir_node *one = new_Const(get_mode_one(mode));
+ return (complex_value) {
+ new_d_Add(dbgi, value.real, one, mode),
+ value.imag
+ };
+}
+
+static complex_value new_complex_decrement(dbg_info *dbgi, complex_value value,
+ ir_mode *mode)
+{
+ ir_node *one = new_Const(get_mode_one(mode));
+ return (complex_value) {
+ new_d_Sub(dbgi, value.real, one, mode),
+ value.imag
+ };
+}
+
+static void set_complex_value_for_expression(dbg_info *dbgi,
+ const expression_t *expression,
+ complex_value value,
+ ir_node *addr)
+{
+ type_t *const type = skip_typeref(expression->base.type);
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const real = create_conv(dbgi, value.real, mode);
+ ir_node *const imag = create_conv(dbgi, value.imag, mode);
+
+ if (expression->kind == EXPR_REFERENCE) {
+ const reference_expression_t *ref = &expression->reference;
+
+ entity_t *entity = ref->entity;
+ assert(is_declaration(entity));
+ assert(entity->declaration.kind != DECLARATION_KIND_UNKNOWN);
+ if (entity->declaration.kind == DECLARATION_KIND_LOCAL_VARIABLE ||
+ entity->declaration.kind == DECLARATION_KIND_PARAMETER) {
+ set_value(entity->variable.v.value_number, real);
+ set_value(entity->variable.v.value_number+1, imag);
+ return;
+ }
}
- case EXPR_BINARY_LOGICAL_OR: {
- const binary_expression_t *binary_expression = &expression->binary;
-
- ir_node *extra_block = new_immBlock();
- create_condition_evaluation(binary_expression->left, true_block,
- extra_block);
- mature_immBlock(extra_block);
- set_cur_block(extra_block);
- create_condition_evaluation(binary_expression->right, true_block,
- false_block);
- return NULL;
+
+ if (addr == NULL)
+ addr = expression_to_addr(expression);
+ assert(addr != NULL);
+ store_complex(dbgi, addr, type, value);
+}
+
+static complex_value create_complex_assign_unop(const unary_expression_t *unop,
+ new_complex_unop constructor,
+ bool return_old)
+{
+ dbg_info *const dbgi = get_dbg_info(&unop->base.pos);
+ const expression_t *value_expr = unop->value;
+ ir_node *addr = expression_to_addr(value_expr);
+ complex_value value = get_complex_from_lvalue(value_expr, addr);
+ type_t *type = skip_typeref(unop->base.type);
+ ir_mode *mode = get_complex_mode_arithmetic(type);
+ value = complex_conv(dbgi, value, mode);
+ complex_value new_value = constructor(dbgi, value, mode);
+ set_complex_value_for_expression(dbgi, value_expr, new_value, addr);
+ return return_old ? value : new_value;
+}
+
+static complex_value complex_negate_to_firm(const unary_expression_t *expr)
+{
+ complex_value cvalue = expression_to_complex(expr->value);
+ dbg_info *dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(expr->base.type);
+ cvalue = complex_conv(dbgi, cvalue, mode);
+ return (complex_value) {
+ new_d_Minus(dbgi, cvalue.real, mode),
+ new_d_Minus(dbgi, cvalue.imag, mode)
+ };
+}
+
+static complex_value complex_complement_to_firm(const unary_expression_t *expr)
+{
+ complex_value cvalue = expression_to_complex(expr->value);
+ dbg_info *dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(expr->base.type);
+ cvalue = complex_conv(dbgi, cvalue, mode);
+ return (complex_value) {
+ cvalue.real,
+ new_d_Minus(dbgi, cvalue.imag, mode)
+ };
+}
+
+static complex_value create_complex_binop(const binary_expression_t *binexpr,
+ new_complex_binop constructor)
+{
+ dbg_info *dbgi = get_dbg_info(&binexpr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(binexpr->base.type);
+ complex_value left = expression_to_complex(binexpr->left);
+ complex_value right = expression_to_complex(binexpr->right);
+ left = complex_conv(dbgi, left, mode);
+ right = complex_conv(dbgi, right, mode);
+ return constructor(dbgi, left, right, mode);
+}
+
+static complex_value create_complex_assign_binop(const binary_expression_t *binexpr,
+ new_complex_binop constructor)
+{
+ dbg_info *dbgi = get_dbg_info(&binexpr->base.pos);
+ expression_t *lefte = binexpr->left;
+ expression_t *righte = binexpr->right;
+ ir_mode *mode = get_complex_mode_arithmetic(righte->base.type);
+ ir_node *addr = expression_to_addr(lefte);
+ complex_value left = get_complex_from_lvalue(lefte, addr);
+ complex_value right = expression_to_complex(righte);
+ left = complex_conv(dbgi, left, mode);
+ right = complex_conv(dbgi, right, mode);
+ complex_value new_value = constructor(dbgi, left, right, mode);
+ type_t *res_type = skip_typeref(binexpr->base.type);
+ set_complex_value_for_expression(dbgi, lefte, new_value, addr);
+ return complex_conv_to_storage(dbgi, new_value, res_type);
+}
+
+static complex_value complex_call_to_firm(const call_expression_t *call)
+{
+ ir_node *result = call_expression_to_firm(call);
+ expression_t *function = call->function;
+ type_t *type = skip_typeref(function->base.type);
+ assert(is_type_pointer(type));
+ pointer_type_t *pointer_type = &type->pointer;
+ type_t *points_to = skip_typeref(pointer_type->points_to);
+ assert(is_type_function(points_to));
+ function_type_t *function_type = &points_to->function;
+ type_t *return_type = skip_typeref(function_type->return_type);
+ assert(is_type_complex(return_type));
+ dbg_info *dbgi = get_dbg_info(&call->base.pos);
+ return complex_deref_address(dbgi, return_type, result, cons_floats);
+}
+
+static void complex_equality_evaluation(const binary_expression_t *binexpr,
+ jump_target *const true_target, jump_target *const false_target,
+ ir_relation relation)
+{
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+
+ complex_value left = expression_to_complex(binexpr->left);
+ complex_value right = expression_to_complex(binexpr->right);
+ dbg_info *dbgi = get_dbg_info(&binexpr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(binexpr->left->base.type);
+ left = complex_conv(dbgi, left, mode);
+ right = complex_conv(dbgi, right, mode);
+
+ ir_node *cmp_real = new_d_Cmp(dbgi, left.real, right.real, relation);
+ ir_node *cond = new_d_Cond(dbgi, cmp_real);
+ ir_node *true_proj = new_Proj(cond, mode_X, pn_Cond_true);
+ ir_node *false_proj = new_Proj(cond, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(&extra_target, true_proj);
+ add_pred_to_jump_target(false_target, false_proj);
+ if (!enter_jump_target(&extra_target))
+ return;
+
+ ir_node *cmp_imag = new_d_Cmp(dbgi, left.imag, right.imag, relation);
+ ir_node *condi = new_d_Cond(dbgi, cmp_imag);
+ ir_node *true_proj_i = new_Proj(condi, mode_X, pn_Cond_true);
+ ir_node *false_proj_i = new_Proj(condi, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(true_target, true_proj_i);
+ add_pred_to_jump_target(false_target, false_proj_i);
+ set_unreachable_now();
+}
+
+static complex_value complex_to_control_flow(
+ const expression_t *const expression, jump_target *const true_target,
+ jump_target *const false_target)
+{
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+ complex_value value = expression_to_complex(expression);
+ if (is_Const(value.real) && is_Const(value.imag)) {
+ ir_tarval *tv_real = get_Const_tarval(value.real);
+ ir_tarval *tv_imag = get_Const_tarval(value.imag);
+ if (tarval_is_null(tv_real) && tarval_is_null(tv_imag)) {
+ jump_to_target(false_target);
+ } else {
+ jump_to_target(true_target);
+ }
+ set_unreachable_now();
+ return value;
}
- default:
- break;
+
+ dbg_info *const dbgi = get_dbg_info(&expression->base.pos);
+ type_t *const type = expression->base.type;
+ ir_mode *const mode = get_complex_mode_arithmetic(type);
+ value = complex_conv(dbgi, value, mode);
+ ir_node *const zero = new_Const(get_mode_null(mode));
+ ir_node *const cmp_real =
+ new_d_Cmp(dbgi, value.real, zero, ir_relation_unordered_less_greater);
+ ir_node *const cond_real = new_d_Cond(dbgi, cmp_real);
+ ir_node *const true_real = new_Proj(cond_real, mode_X, pn_Cond_true);
+ ir_node *const false_real = new_Proj(cond_real, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(true_target, true_real);
+ add_pred_to_jump_target(&extra_target, false_real);
+ if (!enter_jump_target(&extra_target))
+ return value;
+
+ ir_node *const cmp_imag =
+ new_d_Cmp(dbgi, value.imag, zero, ir_relation_unordered_less_greater);
+ ir_node *const cond_imag = new_d_Cond(dbgi, cmp_imag);
+ ir_node *const true_imag = new_Proj(cond_imag, mode_X, pn_Cond_true);
+ ir_node *const false_imag = new_Proj(cond_imag, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(true_target, true_imag);
+ add_pred_to_jump_target(false_target, false_imag);
+ set_unreachable_now();
+
+ return value;
+}
+
+static complex_value complex_conditional_to_firm(
+ const conditional_expression_t *const expression)
+{
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ complex_value cond_val;
+ memset(&cond_val, 0, sizeof(cond_val));
+ if (expression->true_expression == NULL) {
+ assert(is_type_complex(skip_typeref(expression->condition->base.type)));
+ cond_val = complex_to_control_flow(expression->condition,
+ &true_target, &false_target);
+ } else {
+ expression_to_control_flow(expression->condition, &true_target, &false_target);
+ }
+
+ complex_value val;
+ memset(&val, 0, sizeof(val));
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
+ type_t *const type = skip_typeref(expression->base.type);
+ ir_mode *const mode = get_complex_mode_arithmetic(type);
+ dbg_info *const dbgi = get_dbg_info(&expression->base.pos);
+
+ if (enter_jump_target(&true_target)) {
+ if (expression->true_expression) {
+ val = expression_to_complex(expression->true_expression);
+ } else {
+ assert(cond_val.real != NULL);
+ val = cond_val;
+ }
+ val = complex_conv(dbgi, val, mode);
+ jump_to_target(&exit_target);
+ }
+
+ if (enter_jump_target(&false_target)) {
+ complex_value false_val
+ = expression_to_complex(expression->false_expression);
+ false_val = complex_conv(dbgi, false_val, mode);
+ jump_to_target(&exit_target);
+ if (val.real != NULL) {
+ ir_node *const inr[] = { val.real, false_val.real };
+ ir_node *const ini[] = { val.imag, false_val.imag };
+ ir_node *const block = exit_target.block;
+ val.real = new_rd_Phi(dbgi, block, lengthof(inr), inr, mode);
+ val.imag = new_rd_Phi(dbgi, block, lengthof(ini), ini, mode);
+ } else {
+ val = false_val;
+ }
+ }
+
+ if (!enter_jump_target(&exit_target)) {
+ set_cur_block(new_Block(0, NULL));
+ assert(!is_type_void(type));
+ val.real = val.imag = new_Bad(mode);
}
+ return val;
+}
+
+static void create_local_declarations(entity_t*);
+
+static complex_value compound_statement_to_firm_complex(
+ const compound_statement_t *compound)
+{
+ create_local_declarations(compound->scope.entities);
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_node *cond_expr = _expression_to_firm(expression);
- ir_node *condition = create_conv(dbgi, cond_expr, mode_b);
- ir_node *cond = new_d_Cond(dbgi, condition);
- ir_node *true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
- ir_node *false_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_false);
-
- /* set branch prediction info based on __builtin_expect */
- if (is_builtin_expect(expression) && is_Cond(cond)) {
- call_argument_t *argument = expression->call.arguments->next;
- if (is_constant_expression(argument->expression) == EXPR_CLASS_CONSTANT) {
- bool const cnst = fold_constant_to_bool(argument->expression);
- cond_jmp_predicate const pred = cnst ? COND_JMP_PRED_TRUE : COND_JMP_PRED_FALSE;
- set_Cond_jmp_pred(cond, pred);
+ complex_value result = { NULL, NULL };
+ statement_t *statement = compound->statements;
+ statement_t *next;
+ for ( ; statement != NULL; statement = next) {
+ next = statement->base.next;
+ /* last statement is the return value */
+ if (next == NULL) {
+ /* it must be an expression, otherwise we wouldn't be in the
+ * complex variant of compound_statement_to_firm */
+ if (statement->kind != STATEMENT_EXPRESSION)
+ panic("last member of complex statement expression not an expression statement");
+ expression_t *expression = statement->expression.expression;
+ assert(is_type_complex(skip_typeref(expression->base.type)));
+ result = expression_to_complex(expression);
+ } else {
+ statement_to_firm(statement);
}
}
- add_immBlock_pred(true_block, true_proj);
- add_immBlock_pred(false_block, false_proj);
+ return result;
+}
- set_unreachable_now();
- return cond_expr;
+static complex_value complex_assign_to_firm(const binary_expression_t *expr)
+{
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ complex_value const value = expression_to_complex(expr->right);
+ ir_node *const addr = expression_to_addr(expr->left);
+ set_complex_value_for_expression(dbgi, expr->left, value, addr);
+ return value;
+}
+
+static complex_value complex_statement_expression_to_firm(
+ const statement_expression_t *const expr)
+{
+ const statement_t *const statement = expr->statement;
+ assert(statement->kind == STATEMENT_COMPOUND);
+
+ return compound_statement_to_firm_complex(&statement->compound);
+}
+
+static complex_value expression_to_complex(const expression_t *expression)
+{
+ switch (expression->kind) {
+ case EXPR_REFERENCE:
+ return complex_reference_to_firm(&expression->reference);
+ case EXPR_SELECT:
+ return complex_select_to_firm(&expression->select);
+ case EXPR_ARRAY_ACCESS:
+ return complex_array_access_to_firm(&expression->array_access);
+ case EXPR_UNARY_CAST:
+ return complex_cast_to_firm(&expression->unary);
+ case EXPR_BINARY_COMMA:
+ evaluate_expression_discard_result(expression->binary.left);
+ return expression_to_complex(expression->binary.right);
+ case EXPR_BINARY_ADD:
+ return create_complex_binop(&expression->binary, new_complex_add);
+ case EXPR_BINARY_ADD_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_add);
+ case EXPR_BINARY_SUB:
+ return create_complex_binop(&expression->binary, new_complex_sub);
+ case EXPR_BINARY_SUB_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_sub);
+ case EXPR_BINARY_MUL:
+ return create_complex_binop(&expression->binary, new_complex_mul);
+ case EXPR_BINARY_MUL_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_mul);
+ case EXPR_BINARY_DIV:
+ return create_complex_binop(&expression->binary, new_complex_div);
+ case EXPR_BINARY_DIV_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_div);
+ case EXPR_UNARY_PLUS:
+ return expression_to_complex(expression->unary.value);
+ case EXPR_UNARY_PREFIX_INCREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_increment, false);
+ case EXPR_UNARY_PREFIX_DECREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_decrement, false);
+ case EXPR_UNARY_POSTFIX_INCREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_increment, true);
+ case EXPR_UNARY_POSTFIX_DECREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_decrement, true);
+ case EXPR_UNARY_NEGATE:
+ return complex_negate_to_firm(&expression->unary);
+ case EXPR_UNARY_COMPLEMENT:
+ return complex_complement_to_firm(&expression->unary);
+ case EXPR_BINARY_ASSIGN:
+ return complex_assign_to_firm(&expression->binary);
+ case EXPR_LITERAL_CASES:
+ return complex_literal_to_firm(&expression->literal);
+ case EXPR_CALL:
+ return complex_call_to_firm(&expression->call);
+ case EXPR_CONDITIONAL:
+ return complex_conditional_to_firm(&expression->conditional);
+ case EXPR_STATEMENT:
+ return complex_statement_expression_to_firm(&expression->statement);
+ default:
+ panic("unexpected complex expression");
+ }
}
+
+
static void create_variable_entity(entity_t *variable,
declaration_kind_t declaration_kind,
ir_type *parent_type)
ident *const id = new_id_from_str(variable->base.symbol->string);
ir_type *const irtype = get_ir_type(type);
- dbg_info *const dbgi = get_dbg_info(&variable->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&variable->base.pos);
ir_entity *const irentity = new_d_entity(parent_type, id, irtype, dbgi);
unsigned alignment = variable->declaration.alignment;
{
if (path->invalid) {
/* TODO: handle this... */
- panic("invalid initializer in ast2firm (excessive elements)");
+ panic("invalid initializer (excessive elements)");
}
type_path_entry_t *top = get_type_path_top(path);
static ir_initializer_t *create_ir_initializer_value(
const initializer_value_t *initializer)
{
- if (is_type_compound(initializer->value->base.type)) {
- panic("initializer creation for compounds not implemented yet");
- }
- type_t *type = initializer->value->base.type;
expression_t *expr = initializer->value;
- ir_node *value = expression_to_firm(expr);
- ir_mode *mode = get_ir_mode_storage(type);
- value = create_conv(NULL, value, mode);
+ type_t *type = skip_typeref(expr->base.type);
+
+ if (is_type_compound(type)) {
+ if (expr->kind == EXPR_UNARY_CAST) {
+ expr = expr->unary.value;
+ type = skip_typeref(expr->base.type);
+ }
+ /* must be a compound literal... */
+ if (expr->kind == EXPR_COMPOUND_LITERAL) {
+ return create_ir_initializer(expr->compound_literal.initializer,
+ type);
+ }
+ } else if (is_type_complex(type)) {
+ complex_value const value = expression_to_complex(expr);
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const real = create_conv(NULL, value.real, mode);
+ ir_node *const imag = create_conv(NULL, value.imag, mode);
+ ir_initializer_t *const res = create_initializer_compound(2);
+ ir_initializer_t *const init_real = create_initializer_const(real);
+ ir_initializer_t *const init_imag = create_initializer_const(imag);
+ set_initializer_compound_value(res, 0, init_real);
+ set_initializer_compound_value(res, 1, init_imag);
+ return res;
+ }
+
+ ir_node *value = expression_to_value(expr);
+ value = conv_to_storage_type(NULL, value, type);
return create_initializer_const(value);
}
-/** test wether type can be initialized by a string constant */
+/** Tests whether type can be initialized by a string constant */
static bool is_string_type(type_t *type)
{
- type_t *inner;
- if (is_type_pointer(type)) {
- inner = skip_typeref(type->pointer.points_to);
- } else if(is_type_array(type)) {
- inner = skip_typeref(type->array.element_type);
- } else {
+ if (!is_type_array(type))
return false;
- }
+ type_t *const inner = skip_typeref(type->array.element_type);
return is_type_integer(inner);
}
}
if (sub_initializer->kind == INITIALIZER_VALUE) {
- /* we might have to descend into types until we're at a scalar
- * type */
- while(true) {
+ const expression_t *expr = sub_initializer->value.value;
+ const type_t *expr_type = skip_typeref(expr->base.type);
+ /* we might have to descend into types until the types match */
+ while (true) {
type_t *orig_top_type = path.top_type;
type_t *top_type = skip_typeref(orig_top_type);
- if (is_type_scalar(top_type))
+ if (types_compatible(top_type, expr_type))
break;
descend_into_subtype(&path);
}
- } else if (sub_initializer->kind == INITIALIZER_STRING
- || sub_initializer->kind == INITIALIZER_WIDE_STRING) {
+ } else if (sub_initializer->kind == INITIALIZER_STRING) {
/* we might have to descend into types until we're at a scalar
* type */
while (true) {
return result;
}
-static ir_initializer_t *create_ir_initializer_string(
- const initializer_string_t *initializer, type_t *type)
+static ir_initializer_t *create_ir_initializer_string(initializer_t const *const init, type_t *type)
{
type = skip_typeref(type);
- size_t string_len = initializer->string.size;
- assert(type->kind == TYPE_ARRAY);
- assert(type->array.size_constant);
- size_t len = type->array.size;
- ir_initializer_t *irinitializer = create_initializer_compound(len);
-
- const char *string = initializer->string.begin;
- ir_mode *mode = get_ir_mode_storage(type->array.element_type);
-
- for (size_t i = 0; i < len; ++i) {
- char c = 0;
- if (i < string_len)
- c = string[i];
-
- ir_tarval *tv = new_tarval_from_long(c, mode);
- ir_initializer_t *char_initializer = create_initializer_tarval(tv);
-
- set_initializer_compound_value(irinitializer, i, char_initializer);
- }
-
- return irinitializer;
-}
-
-static ir_initializer_t *create_ir_initializer_wide_string(
- const initializer_wide_string_t *initializer, type_t *type)
-{
assert(type->kind == TYPE_ARRAY);
assert(type->array.size_constant);
- size_t len = type->array.size;
- size_t string_len = wstrlen(&initializer->string);
- ir_initializer_t *irinitializer = create_initializer_compound(len);
-
- const char *p = initializer->string.begin;
- ir_mode *mode = get_type_mode(ir_type_wchar_t);
-
- for (size_t i = 0; i < len; ++i) {
- utf32 c = 0;
- if (i < string_len) {
- c = read_utf8_char(&p);
+ string_literal_expression_t const *const str = get_init_string(init);
+ size_t const str_len = str->value.size;
+ size_t const arr_len = type->array.size;
+ ir_initializer_t *const irinit = create_initializer_compound(arr_len);
+ ir_mode *const mode = get_ir_mode_storage(type->array.element_type);
+ char const * p = str->value.begin;
+ switch (str->value.encoding) {
+ case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8:
+ for (size_t i = 0; i != arr_len; ++i) {
+ char const c = i < str_len ? *p++ : 0;
+ ir_tarval *const tv = new_tarval_from_long(c, mode);
+ ir_initializer_t *const tvinit = create_initializer_tarval(tv);
+ set_initializer_compound_value(irinit, i, tvinit);
}
- ir_tarval *tv = new_tarval_from_long(c, mode);
- ir_initializer_t *char_initializer = create_initializer_tarval(tv);
+ break;
- set_initializer_compound_value(irinitializer, i, char_initializer);
+ case STRING_ENCODING_CHAR16:
+ case STRING_ENCODING_CHAR32:
+ case STRING_ENCODING_WIDE:
+ for (size_t i = 0; i != arr_len; ++i) {
+ utf32 const c = i < str_len ? read_utf8_char(&p) : 0;
+ ir_tarval *const tv = new_tarval_from_long(c, mode);
+ ir_initializer_t *const tvinit = create_initializer_tarval(tv);
+ set_initializer_compound_value(irinit, i, tvinit);
+ }
+ break;
}
- return irinitializer;
+ return irinit;
}
static ir_initializer_t *create_ir_initializer(
const initializer_t *initializer, type_t *type)
{
- switch(initializer->kind) {
+ switch (initializer->kind) {
case INITIALIZER_STRING:
- return create_ir_initializer_string(&initializer->string, type);
-
- case INITIALIZER_WIDE_STRING:
- return create_ir_initializer_wide_string(&initializer->wide_string,
- type);
+ return create_ir_initializer_string(initializer, type);
case INITIALIZER_LIST:
return create_ir_initializer_list(&initializer->list, type);
return create_ir_initializer_value(&initializer->value);
case INITIALIZER_DESIGNATOR:
- panic("unexpected designator initializer found");
+ panic("unexpected designator initializer");
}
panic("unknown initializer");
}
static void create_dynamic_initializer_sub(ir_initializer_t *initializer,
ir_entity *entity, ir_type *type, dbg_info *dbgi, ir_node *base_addr)
{
- switch(get_initializer_kind(initializer)) {
+ switch (get_initializer_kind(initializer)) {
case IR_INITIALIZER_NULL:
create_dynamic_null_initializer(entity, dbgi, base_addr);
return;
return;
}
- assert(get_type_mode(type) == get_irn_mode(node));
- ir_node *mem = get_store();
- ir_node *store = new_d_Store(dbgi, mem, base_addr, node, cons_none);
- ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
- set_store(proj_m);
+ ir_node *mem = get_store();
+ ir_node *new_mem;
+ if (is_compound_type(ent_type)) {
+ ir_node *copyb = new_d_CopyB(dbgi, mem, base_addr, node, ent_type);
+ new_mem = new_Proj(copyb, mode_M, pn_CopyB_M);
+ } else {
+ assert(get_type_mode(type) == get_irn_mode(node));
+ ir_node *store = new_d_Store(dbgi, mem, base_addr, node, cons_none);
+ new_mem = new_Proj(store, mode_M, pn_Store_M);
+ }
+ set_store(new_mem);
return;
}
case IR_INITIALIZER_TARVAL: {
}
}
- panic("invalid IR_INITIALIZER found");
+ panic("invalid ir_initializer");
}
static void create_dynamic_initializer(ir_initializer_t *initializer,
if (initializer->kind == INITIALIZER_VALUE) {
initializer_value_t *initializer_value = &initializer->value;
- ir_node *value = expression_to_firm(initializer_value->value);
+ ir_node *value = expression_to_value(initializer_value->value);
type = skip_typeref(type);
assign_value(dbgi, addr, type, value);
return;
{
assert(entity->kind == ENTITY_VARIABLE);
initializer_t *initializer = entity->variable.initializer;
- dbg_info *dbgi = get_dbg_info(&entity->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&entity->base.pos);
ir_entity *irentity = entity->variable.v.entity;
type_t *type = entity->declaration.type;
{
assert(entity->kind == ENTITY_VARIABLE);
initializer_t *initializer = entity->variable.initializer;
+ if (entity->variable.alias != NULL) {
+ const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
+ entity_t *a = entity->variable.alias->entity;
+ for (; a != NULL; a = a->base.symbol_next) {
+ if ((namespace_tag_t)a->base.namespc == namespc)
+ break;
+ }
+ assert(a != NULL && a->kind == ENTITY_VARIABLE && a->variable.v.entity != NULL);
+ set_entity_alias(entity->variable.v.entity, a->variable.v.entity);
+ /* prevent usage assumption to be made about aliased variables */
+ add_entity_linkage(a->variable.v.entity, IR_LINKAGE_HIDDEN_USER);
+ }
if (initializer == NULL)
return;
expression_t * value = initializer->value.value;
type_t *const init_type = skip_typeref(value->base.type);
- if (!is_type_scalar(init_type)) {
- /* skip convs */
- while (value->kind == EXPR_UNARY_CAST)
- value = value->unary.value;
-
+ if (is_type_complex(init_type)) {
+ complex_value nodes = expression_to_complex(value);
+ dbg_info *dbgi = get_dbg_info(&entity->base.pos);
+ ir_mode *mode = get_complex_mode_storage(init_type);
+ ir_node *real = create_conv(dbgi, nodes.real, mode);
+ ir_node *imag = create_conv(dbgi, nodes.imag, mode);
+ if (declaration_kind == DECLARATION_KIND_LOCAL_VARIABLE) {
+ set_value(entity->variable.v.value_number, real);
+ set_value(entity->variable.v.value_number+1, imag);
+ } else {
+ assert(declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE);
+ ir_entity *irentity = entity->variable.v.entity;
+ if (tq & TYPE_QUALIFIER_CONST
+ && get_entity_owner(irentity) != get_tls_type()) {
+ add_entity_linkage(irentity, IR_LINKAGE_CONSTANT);
+ }
+ ir_initializer_t *complex_init = create_initializer_compound(2);
+ ir_initializer_t *reali = create_initializer_const(real);
+ set_initializer_compound_value(complex_init, 0, reali);
+ ir_initializer_t *imagi = create_initializer_const(imag);
+ set_initializer_compound_value(complex_init, 1, imagi);
+ set_entity_initializer(irentity, complex_init);
+ }
+ return;
+ } else if (!is_type_scalar(init_type)) {
if (value->kind != EXPR_COMPOUND_LITERAL)
panic("expected non-scalar initializer to be a compound literal");
initializer = value->compound_literal.initializer;
goto have_initializer;
}
- ir_node * node = expression_to_firm(value);
- dbg_info *const dbgi = get_dbg_info(&entity->base.source_position);
- ir_mode *const mode = get_ir_mode_storage(init_type);
- node = create_conv(dbgi, node, mode);
- node = do_strict_conv(dbgi, node);
+ ir_node * node = expression_to_value(value);
+ dbg_info *const dbgi = get_dbg_info(&entity->base.pos);
+ node = conv_to_storage_type(dbgi, node, init_type);
if (declaration_kind == DECLARATION_KIND_LOCAL_VARIABLE) {
set_value(entity->variable.v.value_number, node);
assert(entity->variable.initializer == NULL);
assert(currently_reachable());
- dbg_info *dbgi = get_dbg_info(&entity->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&entity->base.pos);
type_t *type = entity->declaration.type;
ir_type *el_type = get_ir_type(type->array.element_type);
entity->variable.v.vla_base = addr;
}
+static bool var_needs_entity(variable_t const *const var)
+{
+ if (var->address_taken)
+ return true;
+ type_t *const type = skip_typeref(var->base.type);
+ return (!is_type_scalar(type) && !is_type_complex(type))
+ || type->base.qualifiers & TYPE_QUALIFIER_VOLATILE;
+}
+
/**
* Creates a Firm local variable from a declaration.
*/
assert(entity->kind == ENTITY_VARIABLE);
assert(entity->declaration.kind == DECLARATION_KIND_UNKNOWN);
- bool needs_entity = entity->variable.address_taken;
- type_t *type = skip_typeref(entity->declaration.type);
+ if (!var_needs_entity(&entity->variable)) {
+ entity->declaration.kind = DECLARATION_KIND_LOCAL_VARIABLE;
+ entity->variable.v.value_number = next_value_number_function;
+ set_irg_loc_description(current_ir_graph, next_value_number_function, entity);
+ ++next_value_number_function;
+ if (is_type_complex(skip_typeref(entity->declaration.type)))
+ ++next_value_number_function;
+ return;
+ }
/* is it a variable length array? */
+ type_t *const type = skip_typeref(entity->declaration.type);
if (is_type_array(type) && !type->array.size_constant) {
create_variable_length_array(entity);
return;
- } else if (is_type_array(type) || is_type_compound(type)) {
- needs_entity = true;
- } else if (type->base.qualifiers & TYPE_QUALIFIER_VOLATILE) {
- needs_entity = true;
}
- if (needs_entity) {
- ir_type *frame_type = get_irg_frame_type(current_ir_graph);
- create_variable_entity(entity,
- DECLARATION_KIND_LOCAL_VARIABLE_ENTITY,
- frame_type);
- } else {
- entity->declaration.kind = DECLARATION_KIND_LOCAL_VARIABLE;
- entity->variable.v.value_number = next_value_number_function;
- set_irg_loc_description(current_ir_graph, next_value_number_function,
- entity);
- ++next_value_number_function;
- }
+ ir_type *const frame_type = get_irg_frame_type(current_ir_graph);
+ create_variable_entity(entity, DECLARATION_KIND_LOCAL_VARIABLE_ENTITY, frame_type);
}
static void create_local_static_variable(entity_t *entity)
ir_type *const var_type = entity->variable.thread_local ?
get_tls_type() : get_glob_type();
ir_type *const irtype = get_ir_type(type);
- dbg_info *const dbgi = get_dbg_info(&entity->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&entity->base.pos);
size_t l = strlen(entity->base.symbol->string);
char buf[l + sizeof(".%u")];
set_entity_initializer(irentity, null_init);
}
- ir_graph *const old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
-
+ PUSH_IRG(get_const_code_irg());
create_variable_initializer(entity);
-
- assert(current_ir_graph == get_const_code_irg());
- current_ir_graph = old_current_ir_graph;
+ POP_IRG();
}
-
-
static ir_node *return_statement_to_firm(return_statement_t *statement)
{
if (!currently_reachable())
return NULL;
- dbg_info *const dbgi = get_dbg_info(&statement->base.source_position);
+ dbg_info *const dbgi = get_dbg_info(&statement->base.pos);
type_t *const type = skip_typeref(current_function_entity->declaration.type->function.return_type);
- ir_node * res = statement->value ? expression_to_firm(statement->value) : NULL;
+ ir_node *in[1];
int in_len;
- if (!is_type_void(type)) {
- ir_mode *const mode = get_ir_mode_storage(type);
- if (res) {
- res = create_conv(dbgi, res, mode);
- res = do_strict_conv(dbgi, res);
+ if (is_type_void(type)) {
+ /* just create the side effects, don't return anything */
+ if (statement->value)
+ evaluate_expression_discard_result(statement->value);
+ in[0] = NULL;
+ in_len = 0;
+ } else if (is_type_complex(type)) {
+ if (statement->value) {
+ complex_value value = expression_to_complex(statement->value);
+ in[0] = complex_to_memory(dbgi, type, value);
} else {
- res = new_Unknown(mode);
+ in[0] = new_Unknown(mode_P_data);
}
in_len = 1;
} else {
- in_len = 0;
+ ir_mode *const mode = get_ir_mode_storage(type);
+ if (statement->value) {
+ ir_node *value = expression_to_value(statement->value);
+ value = conv_to_storage_type(dbgi, value, type);
+ in[0] = create_conv(dbgi, value, mode);
+ } else {
+ in[0] = new_Unknown(mode);
+ }
+ in_len = 1;
}
- ir_node *const in[1] = { res };
ir_node *const store = get_store();
ir_node *const ret = new_d_Return(dbgi, store, in_len, in);
if (!currently_reachable())
return NULL;
- return expression_to_firm(statement->expression);
+ expression_t *expression = statement->expression;
+ type_t *type = skip_typeref(expression->base.type);
+ if (is_type_complex(type)) {
+ expression_to_complex(expression);
+ return NULL;
+ } else {
+ return expression_to_value(statement->expression);
+ }
}
-static void create_local_declarations(entity_t*);
-
static ir_node *compound_statement_to_firm(compound_statement_t *compound)
{
create_local_declarations(compound->scope.entities);
return;
case STORAGE_CLASS_EXTERN:
if (entity->kind == ENTITY_FUNCTION) {
- assert(entity->function.statement == NULL);
+ assert(entity->function.body == NULL);
(void)get_function_entity(entity, NULL);
} else {
create_global_variable(entity);
case STORAGE_CLASS_AUTO:
case STORAGE_CLASS_REGISTER:
if (entity->kind == ENTITY_FUNCTION) {
- if (entity->function.statement != NULL) {
+ if (entity->function.body != NULL) {
ir_type *owner = get_irg_frame_type(current_ir_graph);
(void)get_function_entity(entity, owner);
entity->declaration.kind = DECLARATION_KIND_INNER_FUNCTION;
case STORAGE_CLASS_TYPEDEF:
break;
}
- panic("invalid storage class found");
+ panic("invalid storage class");
}
static void create_local_declarations(entity_t *e)
create_local_declarations(statement->scope.entities);
/* Create the condition. */
- ir_node *true_block = NULL;
- ir_node *false_block = NULL;
- if (currently_reachable()) {
- true_block = new_immBlock();
- false_block = new_immBlock();
- create_condition_evaluation(statement->condition, true_block, false_block);
- mature_immBlock(true_block);
- mature_immBlock(false_block);
- }
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ if (currently_reachable())
+ expression_to_control_flow(statement->condition, &true_target, &false_target);
+
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
/* Create the true statement. */
- set_cur_block(true_block);
+ enter_jump_target(&true_target);
statement_to_firm(statement->true_statement);
- ir_node *fallthrough_block = get_cur_block();
+ jump_to_target(&exit_target);
/* Create the false statement. */
- set_cur_block(false_block);
- if (statement->false_statement != NULL) {
+ enter_jump_target(&false_target);
+ if (statement->false_statement)
statement_to_firm(statement->false_statement);
- }
-
- /* Handle the block after the if-statement. Minor simplification and
- * optimisation: Reuse the false/true block as fallthrough block, if the
- * true/false statement does not pass control to the fallthrough block, e.g.
- * in the typical if (x) return; pattern. */
- if (fallthrough_block) {
- if (currently_reachable()) {
- ir_node *const t_jump = new_r_Jmp(fallthrough_block);
- ir_node *const f_jump = new_Jmp();
- ir_node *const in[] = { t_jump, f_jump };
- fallthrough_block = new_Block(2, in);
- }
- set_cur_block(fallthrough_block);
- }
+ jump_to_target(&exit_target);
+ enter_jump_target(&exit_target);
return NULL;
}
-/**
- * Add an unconditional jump to the target block. If the source block is not
- * reachable, then a Bad predecessor is created to prevent Phi-less unreachable
- * loops. This is necessary if the jump potentially enters a loop.
- */
-static void jump_to(ir_node *const target_block)
-{
- ir_node *const pred = currently_reachable() ? new_Jmp() : new_Bad(mode_X);
- add_immBlock_pred(target_block, pred);
-}
-
-/**
- * Add an unconditional jump to the target block, if the current block is
- * reachable and do nothing otherwise. This is only valid if the jump does not
- * enter a loop (a back edge is ok).
- */
-static void jump_if_reachable(ir_node *const target_block)
-{
- if (currently_reachable())
- add_immBlock_pred(target_block, new_Jmp());
-}
-
-static ir_node *while_statement_to_firm(while_statement_t *statement)
+static ir_node *do_while_statement_to_firm(do_while_statement_t *statement)
{
create_local_declarations(statement->scope.entities);
- /* Create the header block */
- ir_node *const header_block = new_immBlock();
- jump_to(header_block);
+ PUSH_BREAK(NULL);
+ PUSH_CONTINUE(NULL);
- /* Create the condition. */
- ir_node * body_block;
- ir_node * false_block;
expression_t *const cond = statement->condition;
- if (is_constant_expression(cond) == EXPR_CLASS_CONSTANT &&
- fold_constant_to_bool(cond)) {
- /* Shortcut for while (true). */
- body_block = header_block;
- false_block = NULL;
-
- keep_alive(header_block);
- keep_all_memory(header_block);
+ /* Avoid an explicit body block in case of do ... while (0);. */
+ if (is_constant_expression(cond) != EXPR_CLASS_VARIABLE && !fold_constant_to_bool(cond)) {
+ /* do ... while (0);. */
+ statement_to_firm(statement->body);
+ jump_to_target(&continue_target);
+ enter_jump_target(&continue_target);
+ jump_to_target(&break_target);
} else {
- body_block = new_immBlock();
- false_block = new_immBlock();
-
- set_cur_block(header_block);
- create_condition_evaluation(cond, body_block, false_block);
- mature_immBlock(body_block);
- }
-
- ir_node *const old_continue_label = continue_label;
- ir_node *const old_break_label = break_label;
- continue_label = header_block;
- break_label = false_block;
-
- /* Create the loop body. */
- set_cur_block(body_block);
- statement_to_firm(statement->body);
- jump_if_reachable(header_block);
-
- mature_immBlock(header_block);
- assert(false_block == NULL || false_block == break_label);
- false_block = break_label;
- if (false_block != NULL) {
- mature_immBlock(false_block);
- }
- set_cur_block(false_block);
-
- assert(continue_label == header_block);
- continue_label = old_continue_label;
- break_label = old_break_label;
- return NULL;
-}
-
-static ir_node *get_break_label(void)
-{
- if (break_label == NULL) {
- break_label = new_immBlock();
- }
- return break_label;
-}
-
-static ir_node *do_while_statement_to_firm(do_while_statement_t *statement)
-{
- create_local_declarations(statement->scope.entities);
-
- /* create the header block */
- ir_node *header_block = new_immBlock();
-
- /* the loop body */
- ir_node *body_block = new_immBlock();
- jump_to(body_block);
-
- ir_node *old_continue_label = continue_label;
- ir_node *old_break_label = break_label;
- continue_label = header_block;
- break_label = NULL;
-
- set_cur_block(body_block);
- statement_to_firm(statement->body);
- ir_node *const false_block = get_break_label();
-
- assert(continue_label == header_block);
- continue_label = old_continue_label;
- break_label = old_break_label;
-
- jump_if_reachable(header_block);
-
- /* create the condition */
- mature_immBlock(header_block);
- set_cur_block(header_block);
-
- create_condition_evaluation(statement->condition, body_block, false_block);
- mature_immBlock(body_block);
- mature_immBlock(false_block);
-
- set_cur_block(false_block);
+ jump_target body_target;
+ init_jump_target(&body_target, NULL);
+ jump_to_target(&body_target);
+ enter_immature_jump_target(&body_target);
+ keep_loop();
+ statement_to_firm(statement->body);
+ jump_to_target(&continue_target);
+ if (enter_jump_target(&continue_target))
+ expression_to_control_flow(statement->condition, &body_target, &break_target);
+ enter_jump_target(&body_target);
+ }
+ enter_jump_target(&break_target);
+
+ POP_CONTINUE();
+ POP_BREAK();
return NULL;
}
}
if (statement->initialisation != NULL) {
- expression_to_firm(statement->initialisation);
+ expression_to_value(statement->initialisation);
}
}
/* Create the header block */
- ir_node *const header_block = new_immBlock();
- jump_to(header_block);
-
- /* Create the condition. */
- ir_node *body_block;
- ir_node *false_block;
- if (statement->condition != NULL) {
- body_block = new_immBlock();
- false_block = new_immBlock();
-
- set_cur_block(header_block);
- create_condition_evaluation(statement->condition, body_block, false_block);
- mature_immBlock(body_block);
- } else {
- /* for-ever. */
- body_block = header_block;
- false_block = NULL;
+ jump_target header_target;
+ init_jump_target(&header_target, NULL);
+ jump_to_target(&header_target);
+ enter_immature_jump_target(&header_target);
+ keep_loop();
- keep_alive(header_block);
- keep_all_memory(header_block);
- }
+ expression_t *const step = statement->step;
+ PUSH_BREAK(NULL);
+ PUSH_CONTINUE(step ? NULL : header_target.block);
- /* Create the step block, if necessary. */
- ir_node * step_block = header_block;
- expression_t *const step = statement->step;
- if (step != NULL) {
- step_block = new_immBlock();
+ /* Create the condition. */
+ expression_t *const cond = statement->condition;
+ if (cond && (is_constant_expression(cond) == EXPR_CLASS_VARIABLE || !fold_constant_to_bool(cond))) {
+ jump_target body_target;
+ init_jump_target(&body_target, NULL);
+ expression_to_control_flow(cond, &body_target, &break_target);
+ enter_jump_target(&body_target);
}
- ir_node *const old_continue_label = continue_label;
- ir_node *const old_break_label = break_label;
- continue_label = step_block;
- break_label = false_block;
-
/* Create the loop body. */
- set_cur_block(body_block);
statement_to_firm(statement->body);
- jump_if_reachable(step_block);
+ jump_to_target(&continue_target);
/* Create the step code. */
- if (step != NULL) {
- mature_immBlock(step_block);
- set_cur_block(step_block);
- expression_to_firm(step);
- jump_if_reachable(header_block);
+ if (step && enter_jump_target(&continue_target)) {
+ expression_to_value(step);
+ jump_to_target(&header_target);
}
- mature_immBlock(header_block);
- assert(false_block == NULL || false_block == break_label);
- false_block = break_label;
- if (false_block != NULL) {
- mature_immBlock(false_block);
- }
- set_cur_block(false_block);
-
- assert(continue_label == step_block);
- continue_label = old_continue_label;
- break_label = old_break_label;
- return NULL;
-}
-
-static ir_node *create_jump_statement(const statement_t *statement, ir_node *target_block)
-{
- if (!currently_reachable())
- return NULL;
-
- dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
- ir_node *jump = new_d_Jmp(dbgi);
- add_immBlock_pred(target_block, jump);
+ enter_jump_target(&header_target);
+ enter_jump_target(&break_target);
- set_unreachable_now();
+ POP_CONTINUE();
+ POP_BREAK();
return NULL;
}
}
if (l->is_empty_range)
continue;
- ir_tarval *min = fold_constant_to_tarval(l->expression);
- ir_tarval *max = min;
+ ir_tarval *min = l->first_case;
+ ir_tarval *max = l->last_case;
long pn = (long) i+1;
- if (l->end_range != NULL)
- max = fold_constant_to_tarval(l->end_range);
ir_switch_table_set(res, i++, min, max, pn);
l->pn = pn;
}
static ir_node *switch_statement_to_firm(switch_statement_t *statement)
{
- dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&statement->base.pos);
ir_node *switch_node = NULL;
if (currently_reachable()) {
- ir_node *expression = expression_to_firm(statement->expression);
+ ir_node *expression = expression_to_value(statement->expression);
ir_switch_table *table = create_switch_table(statement);
unsigned n_outs = (unsigned)ir_switch_table_get_n_entries(table) + 1;
set_unreachable_now();
+ PUSH_BREAK(NULL);
ir_node *const old_switch = current_switch;
- ir_node *const old_break_label = break_label;
const bool old_saw_default_label = saw_default_label;
saw_default_label = false;
current_switch = switch_node;
- break_label = NULL;
statement_to_firm(statement->body);
-
- if (currently_reachable()) {
- add_immBlock_pred(get_break_label(), new_Jmp());
- }
+ jump_to_target(&break_target);
if (!saw_default_label && switch_node) {
ir_node *proj = new_d_Proj(dbgi, switch_node, mode_X, pn_Switch_default);
- add_immBlock_pred(get_break_label(), proj);
+ add_pred_to_jump_target(&break_target, proj);
}
- if (break_label != NULL) {
- mature_immBlock(break_label);
- }
- set_cur_block(break_label);
+ enter_jump_target(&break_target);
assert(current_switch == switch_node);
current_switch = old_switch;
- break_label = old_break_label;
saw_default_label = old_saw_default_label;
+ POP_BREAK();
return NULL;
}
static ir_node *case_label_to_firm(const case_label_statement_t *statement)
{
- if (statement->is_empty_range)
- return NULL;
+ if (current_switch != NULL && !statement->is_empty_range) {
+ jump_target case_target;
+ init_jump_target(&case_target, NULL);
- if (current_switch != NULL) {
- ir_node *block = new_immBlock();
/* Fallthrough from previous case */
- jump_if_reachable(block);
+ jump_to_target(&case_target);
- ir_node *const proj = new_Proj(current_switch, mode_X, statement->pn);
- add_immBlock_pred(block, proj);
+ ir_node *const proj = new_Proj(current_switch, mode_X, statement->pn);
+ add_pred_to_jump_target(&case_target, proj);
if (statement->expression == NULL)
saw_default_label = true;
- mature_immBlock(block);
- set_cur_block(block);
+ enter_jump_target(&case_target);
}
return statement_to_firm(statement->statement);
static ir_node *label_to_firm(const label_statement_t *statement)
{
- ir_node *block = get_label_block(statement->label);
- jump_to(block);
-
- set_cur_block(block);
- keep_alive(block);
- keep_all_memory(block);
+ label_t *const label = statement->label;
+ prepare_label_target(label);
+ jump_to_target(&label->target);
+ if (--label->n_users == 0) {
+ enter_jump_target(&label->target);
+ } else {
+ enter_immature_jump_target(&label->target);
+ keep_loop();
+ }
return statement_to_firm(statement->statement);
}
-static ir_node *computed_goto_to_firm(computed_goto_statement_t const *const statement)
+static ir_node *goto_statement_to_firm(goto_statement_t *const stmt)
{
- if (!currently_reachable())
- return NULL;
-
- ir_node *const irn = expression_to_firm(statement->expression);
- dbg_info *const dbgi = get_dbg_info(&statement->base.source_position);
- ir_node *const ijmp = new_d_IJmp(dbgi, irn);
-
- set_irn_link(ijmp, ijmp_list);
- ijmp_list = ijmp;
-
+ label_t *const label = stmt->label;
+ prepare_label_target(label);
+ jump_to_target(&label->target);
+ if (--label->n_users == 0)
+ enter_jump_target(&label->target);
set_unreachable_now();
return NULL;
}
-static ir_node *asm_statement_to_firm(const asm_statement_t *statement)
+static ir_node *computed_goto_to_firm(computed_goto_statement_t const *const statement)
{
- bool needs_memory = false;
-
- if (statement->is_volatile) {
- needs_memory = true;
+ if (currently_reachable()) {
+ ir_node *const op = expression_to_value(statement->expression);
+ ARR_APP1(ir_node*, ijmp_ops, op);
+ jump_to_target(&ijmp_target);
+ set_unreachable_now();
}
+ return NULL;
+}
- size_t n_clobbers = 0;
- asm_clobber_t *clobber = statement->clobbers;
+static ir_node *asm_statement_to_firm(const asm_statement_t *statement)
+{
+ bool needs_memory = statement->is_volatile;
+ size_t n_clobbers = 0;
+ asm_clobber_t *clobber = statement->clobbers;
for ( ; clobber != NULL; clobber = clobber->next) {
const char *clobber_str = clobber->clobber.begin;
if (!be_is_valid_clobber(clobber_str)) {
- errorf(&statement->base.source_position,
+ errorf(&statement->base.pos,
"invalid clobber '%s' specified", clobber->clobber);
continue;
}
= be_parse_asm_constraints(constraints);
{
- source_position_t const *const pos = &statement->base.source_position;
+ position_t const *const pos = &statement->base.pos;
if (asm_flags & ASM_CONSTRAINT_FLAG_NO_SUPPORT) {
warningf(WARN_OTHER, pos, "some constraints in '%s' are not supported", constraints);
}
constraint.mode = mode_M;
tmp_in_constraints[in_size] = constraint;
- ins[in_size] = expression_to_addr(expr);
+ ins[in_size] = expression_to_addr(expr);
++in_size;
continue;
} else {
- errorf(&statement->base.source_position,
+ errorf(&statement->base.pos,
"only modifiers but no place set in constraints '%s'",
constraints);
continue;
= be_parse_asm_constraints(constraints);
if (asm_flags & ASM_CONSTRAINT_FLAG_NO_SUPPORT) {
- errorf(&statement->base.source_position,
+ errorf(&statement->base.pos,
"some constraints in '%s' are not supported", constraints);
continue;
}
if (asm_flags & ASM_CONSTRAINT_FLAG_INVALID) {
- errorf(&statement->base.source_position,
+ errorf(&statement->base.pos,
"some constraints in '%s' are invalid", constraints);
continue;
}
if (asm_flags & ASM_CONSTRAINT_FLAG_MODIFIER_WRITE) {
- errorf(&statement->base.source_position,
+ errorf(&statement->base.pos,
"write flag specified for input constraints '%s'",
constraints);
continue;
if ( (asm_flags & ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE)
|| (asm_flags & ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER) ) {
/* we can treat this as "normal" input */
- input = expression_to_firm(argument->expression);
+ input = expression_to_value(argument->expression);
} else if (asm_flags & ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP) {
/* pure memory ops need no input (but we have to make sure we
* attach to the memory) */
needs_memory = true;
input = expression_to_addr(argument->expression);
} else {
- errorf(&statement->base.source_position,
+ errorf(&statement->base.pos,
"only modifiers but no place set in constraints '%s'",
constraints);
continue;
ins[in_size++] = input;
}
- if (needs_memory) {
- ir_asm_constraint constraint;
- constraint.pos = next_pos++;
- constraint.constraint = new_id_from_str("");
- constraint.mode = mode_M;
-
- obstack_grow(&asm_obst, &constraint, sizeof(constraint));
- ins[in_size++] = get_store();
- }
-
+ ir_node *mem = needs_memory ? get_store() : new_NoMem();
assert(obstack_object_size(&asm_obst)
== in_size * sizeof(ir_asm_constraint));
ir_asm_constraint *input_constraints = obstack_finish(&asm_obst);
/* create asm node */
- dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
+ dbg_info *dbgi = get_dbg_info(&statement->base.pos);
ident *asm_text = new_id_from_str(statement->asm_text.begin);
- ir_node *node = new_d_ASM(dbgi, in_size, ins, input_constraints,
+ ir_node *node = new_d_ASM(dbgi, mem, in_size, ins, input_constraints,
out_size, output_constraints,
n_clobbers, clobbers, asm_text);
static ir_node *ms_try_statement_to_firm(ms_try_statement_t *statement)
{
statement_to_firm(statement->try_statement);
- source_position_t const *const pos = &statement->base.source_position;
+ position_t const *const pos = &statement->base.pos;
warningf(WARN_OTHER, pos, "structured exception handling ignored");
return NULL;
}
static ir_node *leave_statement_to_firm(leave_statement_t *statement)
{
- errorf(&statement->base.source_position, "__leave not supported yet");
+ errorf(&statement->base.pos, "__leave not supported yet");
return NULL;
}
case STATEMENT_EMPTY: return NULL; /* nothing */
case STATEMENT_EXPRESSION: return expression_statement_to_firm( &stmt->expression);
case STATEMENT_FOR: return for_statement_to_firm( &stmt->fors);
+ case STATEMENT_GOTO: return goto_statement_to_firm( &stmt->gotos);
case STATEMENT_IF: return if_statement_to_firm( &stmt->ifs);
case STATEMENT_LABEL: return label_to_firm( &stmt->label);
case STATEMENT_LEAVE: return leave_statement_to_firm( &stmt->leave);
case STATEMENT_MS_TRY: return ms_try_statement_to_firm( &stmt->ms_try);
case STATEMENT_RETURN: return return_statement_to_firm( &stmt->returns);
case STATEMENT_SWITCH: return switch_statement_to_firm( &stmt->switchs);
- case STATEMENT_WHILE: return while_statement_to_firm( &stmt->whiles);
- case STATEMENT_BREAK: return create_jump_statement(stmt, get_break_label());
- case STATEMENT_CONTINUE: return create_jump_statement(stmt, continue_label);
- case STATEMENT_GOTO: return create_jump_statement(stmt, get_label_block(stmt->gotos.label));
+ {
+ jump_target *tgt;
+ case STATEMENT_BREAK: tgt = &break_target; goto jump;
+ case STATEMENT_CONTINUE: tgt = &continue_target; goto jump;
+jump:
+ jump_to_target(tgt);
+ set_unreachable_now();
+ return NULL;
+ }
- case STATEMENT_ERROR: panic("error statement found");
+ case STATEMENT_ERROR: panic("error statement");
}
panic("statement not implemented");
}
entity_t const *const end = last != NULL ? last->base.next : NULL;
for (; entity != end; entity = entity->base.next) {
if ((entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER) &&
- !entity->variable.address_taken &&
- is_type_scalar(skip_typeref(entity->declaration.type)))
- ++count;
+ !var_needs_entity(&entity->variable)) {
+ type_t *type = skip_typeref(entity->declaration.type);
+ count += is_type_complex(type) ? 2 : 1;
+ }
}
return count;
}
count += count_local_variables(function->parameters.entities, NULL);
/* count local variables declared in body */
- walk_statements(function->statement, count_local_variables_in_stmt, &count);
+ walk_statements(function->body, count_local_variables_in_stmt, &count);
return count;
}
function_irtype = get_ir_type(entity->declaration.type);
}
-
-
entity_t *parameter = entity->function.parameters.entities;
for ( ; parameter != NULL; parameter = parameter->base.next, ++n) {
if (parameter->kind != ENTITY_PARAMETER)
assert(parameter->declaration.kind == DECLARATION_KIND_UNKNOWN);
type_t *type = skip_typeref(parameter->declaration.type);
- assert(!is_type_array(type));
- bool const needs_entity = parameter->variable.address_taken || is_type_compound(type);
-
- ir_type *param_irtype = get_method_param_type(function_irtype, n);
- if (needs_entity) {
+ dbg_info *const dbgi = get_dbg_info(¶meter->base.pos);
+ ir_type *const param_irtype = get_method_param_type(function_irtype, n);
+ if (var_needs_entity(¶meter->variable)) {
ir_type *frame_type = get_irg_frame_type(irg);
ir_entity *param
- = new_parameter_entity(frame_type, n, param_irtype);
+ = new_d_parameter_entity(frame_type, n, param_irtype, dbgi);
parameter->declaration.kind = DECLARATION_KIND_PARAMETER_ENTITY;
parameter->variable.v.entity = param;
- continue;
+ } else if (is_type_complex(type)) {
+ ir_type *frame_type = get_irg_frame_type(irg);
+ ir_entity *param
+ = new_d_parameter_entity(frame_type, n, param_irtype, dbgi);
+ ir_node *nomem = get_irg_no_mem(irg);
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *addr = new_simpleSel(nomem, frame, param);
+ complex_value value = complex_deref_address(NULL, type, addr, cons_floats);
+
+ parameter->declaration.kind = DECLARATION_KIND_PARAMETER;
+ parameter->variable.v.value_number = next_value_number_function;
+ set_irg_loc_description(irg, next_value_number_function,
+ parameter);
+ set_irg_loc_description(irg, next_value_number_function+1,
+ parameter);
+ set_value(next_value_number_function, value.real);
+ set_value(next_value_number_function+1, value.imag);
+ next_value_number_function += 2;
+ } else {
+ ir_mode *param_mode = get_type_mode(param_irtype);
+ long pn = n;
+ ir_node *value = new_rd_Proj(dbgi, args, param_mode, pn);
+ value = conv_to_storage_type(dbgi, value, type);
+
+ parameter->declaration.kind = DECLARATION_KIND_PARAMETER;
+ parameter->variable.v.value_number = next_value_number_function;
+ set_irg_loc_description(irg, next_value_number_function,
+ parameter);
+ ++next_value_number_function;
+
+ set_value(parameter->variable.v.value_number, value);
}
-
- ir_mode *param_mode = get_type_mode(param_irtype);
- long pn = n;
- ir_node *value = new_r_Proj(args, param_mode, pn);
-
- ir_mode *mode = get_ir_mode_storage(type);
- value = create_conv(NULL, value, mode);
- value = do_strict_conv(NULL, value);
-
- parameter->declaration.kind = DECLARATION_KIND_PARAMETER;
- parameter->variable.v.value_number = next_value_number_function;
- set_irg_loc_description(current_ir_graph, next_value_number_function,
- parameter);
- ++next_value_number_function;
-
- set_value(parameter->variable.v.value_number, value);
- }
-}
-
-/**
- * Handle additional decl modifiers for IR-graphs
- *
- * @param irg the IR-graph
- * @param dec_modifiers additional modifiers
- */
-static void handle_decl_modifier_irg(ir_graph *irg,
- decl_modifiers_t decl_modifiers)
-{
- if (decl_modifiers & DM_NAKED) {
- /* TRUE if the declaration includes the Microsoft
- __declspec(naked) specifier. */
- add_irg_additional_properties(irg, mtp_property_naked);
- }
- if (decl_modifiers & DM_FORCEINLINE) {
- /* TRUE if the declaration includes the
- Microsoft __forceinline specifier. */
- set_irg_inline_property(irg, irg_inline_forced);
- }
- if (decl_modifiers & DM_NOINLINE) {
- /* TRUE if the declaration includes the Microsoft
- __declspec(noinline) specifier. */
- set_irg_inline_property(irg, irg_inline_forbidden);
}
}
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 and all inner functions.
*
assert(entity->kind == ENTITY_FUNCTION);
ir_entity *function_entity = get_function_entity(entity, current_outer_frame);
- if (entity->function.statement == NULL)
+ if (entity->function.alias != NULL) {
+ const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
+ entity_t *a = entity->function.alias->entity;
+ for (; a != NULL; a = a->base.symbol_next) {
+ if ((namespace_tag_t)a->base.namespc == namespc)
+ break;
+ }
+// TODO: or use entitymap
+// ir_entity *a = entitymap_get(&entitymap, entity->function.alias);
+ assert(a != NULL && a->kind == ENTITY_VARIABLE && a->function.irentity != NULL);
+ set_entity_alias(entity->function.irentity, a->function.irentity);
+ /* prevent usage assumption to be made about aliased functions */
+ add_entity_linkage(a->function.irentity, IR_LINKAGE_HIDDEN_USER);
+ }
+
+ if (entity->function.body == NULL)
return;
inner_functions = NULL;
current_function_name = NULL;
current_funcsig = NULL;
- assert(all_labels == NULL);
- all_labels = NEW_ARR_F(label_t *, 0);
- ijmp_list = NULL;
+ assert(!ijmp_ops);
+ assert(!ijmp_blocks);
+ init_jump_target(&ijmp_target, NULL);
+ ijmp_ops = NEW_ARR_F(ir_node*, 0);
+ ijmp_blocks = NEW_ARR_F(ir_node*, 0);
int n_local_vars = get_function_n_local_vars(entity);
ir_graph *irg = new_ir_graph(function_entity, n_local_vars);
current_vararg_entity = NULL;
set_irg_fp_model(irg, firm_fp_model);
- tarval_enable_fp_ops(1);
set_irn_dbg_info(get_irg_start_block(irg),
get_entity_dbg_info(function_entity));
- /* set inline flags */
- if (entity->function.is_inline)
- set_irg_inline_property(irg, irg_inline_recomended);
- handle_decl_modifier_irg(irg, entity->declaration.modifiers);
-
next_value_number_function = 0;
initialize_function_parameters(entity);
current_static_link = entity->function.static_link;
- statement_to_firm(entity->function.statement);
+ statement_to_firm(entity->function.body);
ir_node *end_block = get_irg_end_block(irg);
add_immBlock_pred(end_block, ret);
}
- for (int i = ARR_LEN(all_labels) - 1; i >= 0; --i) {
- label_t *label = all_labels[i];
- if (label->address_taken) {
- gen_ijmp_branches(label->block);
+ if (enter_jump_target(&ijmp_target)) {
+ keep_loop();
+ size_t const n = ARR_LEN(ijmp_ops);
+ ir_node *const op = n == 1 ? ijmp_ops[0] : new_Phi(n, ijmp_ops, get_irn_mode(ijmp_ops[0]));
+ ir_node *const ijmp = new_IJmp(op);
+ for (size_t i = ARR_LEN(ijmp_blocks); i-- != 0;) {
+ ir_node *const block = ijmp_blocks[i];
+ add_immBlock_pred(block, ijmp);
+ mature_immBlock(block);
}
- mature_immBlock(label->block);
}
- DEL_ARR_F(all_labels);
- all_labels = NULL;
+ DEL_ARR_F(ijmp_ops);
+ DEL_ARR_F(ijmp_blocks);
+ ijmp_ops = NULL;
+ ijmp_blocks = NULL;
irg_finalize_cons(irg);
- /* finalize the frame type */
- ir_type *frame_type = get_irg_frame_type(irg);
- int n = get_compound_n_members(frame_type);
- int align_all = 4;
- int offset = 0;
- for (int i = 0; i < n; ++i) {
- ir_entity *member = get_compound_member(frame_type, i);
- ir_type *entity_type = get_entity_type(member);
-
- int align = get_type_alignment_bytes(entity_type);
- if (align > align_all)
- align_all = align;
- int misalign = 0;
- if (align > 0) {
- misalign = offset % align;
- if (misalign > 0) {
- offset += align - misalign;
- }
- }
-
- set_entity_offset(member, offset);
- offset += get_type_size_bytes(entity_type);
- }
- set_type_size_bytes(frame_type, offset);
- set_type_alignment_bytes(frame_type, align_all);
-
irg_verify(irg, VERIFY_ENFORCE_SSA);
current_vararg_entity = old_current_vararg_entity;
current_function = old_current_function;
return;
ir_types_initialized = 1;
- ir_type_char = get_ir_type(type_char);
- ir_type_wchar_t = get_ir_type(type_wchar_t);
+ ir_type_char = get_ir_type(type_char);
be_params = be_get_backend_param();
mode_float_arithmetic = be_params->mode_float_arithmetic;
static const char *get_cwd(void)
{
static char buf[1024];
- if (buf[0] == '\0')
- getcwd(buf, sizeof(buf));
+ if (buf[0] == '\0') {
+ return getcwd(buf, sizeof(buf));
+ }
return buf;
}
} else {
be_dwarf_set_source_language(DW_LANG_C);
}
- be_dwarf_set_compilation_directory(get_cwd());
+ const char *cwd = get_cwd();
+ if (cwd != NULL) {
+ be_dwarf_set_compilation_directory(cwd);
+ }
/* initialize firm arithmetic */
tarval_set_integer_overflow_mode(TV_OVERFLOW_WRAP);
ir_set_uninitialized_local_variable_func(uninitialized_local_var);
/* just to be sure */
- continue_label = NULL;
- break_label = NULL;
+ init_jump_target(&break_target, NULL);
+ init_jump_target(&continue_target, NULL);
current_switch = NULL;
current_translation_unit = unit;