+
+ /* already an entity defined? */
+ ir_entity *irentity = entitymap_get(&entitymap, symbol);
+ bool const has_body = entity->function.statement != NULL;
+ if (irentity != NULL) {
+ if (get_entity_visibility(irentity) == visibility_external_allocated
+ && has_body) {
+ set_entity_visibility(irentity, visibility_external_visible);
+ }
+ goto entity_created;
+ }
+
+ ir_type *ir_type_method;
+ if (entity->function.need_closure)
+ ir_type_method = create_method_type(&entity->declaration.type->function, true);
+ else
+ ir_type_method = get_ir_type(entity->declaration.type);
+
+ bool nested_function = false;
+ if (owner_type == NULL)
+ owner_type = get_glob_type();
+ else
+ nested_function = true;
+
+ dbg_info *const dbgi = get_dbg_info(&entity->base.source_position);
+ irentity = new_d_entity(owner_type, id, ir_type_method, dbgi);
+
+ ident *ld_id;
+ if (nested_function)
+ ld_id = id_unique("inner.%u");
+ else
+ ld_id = create_ld_ident(entity);
+ set_entity_ld_ident(irentity, ld_id);
+
+ handle_decl_modifiers(irentity, entity);
+
+ if (! nested_function) {
+ /* static inline => local
+ * extern inline => local
+ * inline without definition => local
+ * inline with definition => external_visible */
+ storage_class_tag_t const storage_class
+ = (storage_class_tag_t) entity->declaration.storage_class;
+ bool const is_inline = entity->function.is_inline;
+
+ if (is_inline && storage_class == STORAGE_CLASS_NONE && has_body) {
+ set_entity_visibility(irentity, visibility_external_visible);
+ } else if (storage_class == STORAGE_CLASS_STATIC ||
+ (is_inline && has_body)) {
+ if (!has_body) {
+ /* this entity was declared, but is defined nowhere */
+ set_entity_peculiarity(irentity, peculiarity_description);
+ }
+ set_entity_visibility(irentity, visibility_local);
+ } else if (has_body) {
+ set_entity_visibility(irentity, visibility_external_visible);
+ } else {
+ set_entity_visibility(irentity, visibility_external_allocated);
+ }
+ } else {
+ /* nested functions are always local */
+ set_entity_visibility(irentity, visibility_local);
+ }
+ set_entity_allocation(irentity, allocation_static);
+
+ /* We should check for file scope here, but as long as we compile C only
+ this is not needed. */
+ if (! firm_opt.freestanding && !has_body) {
+ /* check for a known runtime function */
+ for (size_t i = 0; i < lengthof(rts_data); ++i) {
+ if (id != rts_idents[i])
+ continue;
+
+ /* ignore those rts functions not necessary needed for current mode */
+ if ((c_mode & rts_data[i].flags) == 0)
+ continue;
+ assert(rts_entities[rts_data[i].id] == NULL);
+ rts_entities[rts_data[i].id] = irentity;
+ }
+ }
+
+ entitymap_insert(&entitymap, symbol, irentity);
+
+entity_created:
+ entity->declaration.kind = DECLARATION_KIND_FUNCTION;
+ entity->function.irentity = irentity;
+
+ return irentity;
+}
+
+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 || is_Bad(value))
+ 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_node *proj = new_d_Proj(dbgi, cmp, mode_b, pn_Cmp_Lg);
+ return proj;
+ }
+
+ return new_d_Conv(dbgi, value, dest_mode);
+}
+
+/**
+ * Creates a Const node representing a constant.
+ */
+static ir_node *const_to_firm(const const_expression_t *cnst)
+{
+ dbg_info *dbgi = get_dbg_info(&cnst->base.source_position);
+ type_t *type = skip_typeref(cnst->base.type);
+ ir_mode *mode = get_ir_mode_storage(type);
+
+ char buf[128];
+ tarval *tv;
+ size_t len;
+ if (mode_is_float(mode)) {
+ tv = new_tarval_from_double(cnst->v.float_value, mode);
+ } else {
+ if (mode_is_signed(mode)) {
+ len = snprintf(buf, sizeof(buf), "%lld", cnst->v.int_value);
+ } else {
+ len = snprintf(buf, sizeof(buf), "%llu",
+ (unsigned long long) cnst->v.int_value);
+ }
+ tv = new_tarval_from_str(buf, len, mode);
+ }
+
+ ir_node *res = new_d_Const(dbgi, tv);
+ ir_mode *mode_arith = get_ir_mode_arithmetic(type);
+ return create_conv(dbgi, res, mode_arith);
+}
+
+/**
+ * Creates a Const node representing a character constant.
+ */
+static ir_node *character_constant_to_firm(const const_expression_t *cnst)
+{
+ dbg_info *dbgi = get_dbg_info(&cnst->base.source_position);
+ ir_mode *mode = get_ir_mode_arithmetic(cnst->base.type);
+
+ long long int v;
+ size_t const size = cnst->v.character.size;
+ if (size == 1 && char_is_signed) {
+ v = (signed char)cnst->v.character.begin[0];
+ } else {
+ v = 0;
+ for (size_t i = 0; i < size; ++i) {
+ v = (v << 8) | ((unsigned char)cnst->v.character.begin[i]);
+ }
+ }
+ char buf[128];
+ size_t len = snprintf(buf, sizeof(buf), "%lld", v);
+ tarval *tv = new_tarval_from_str(buf, len, mode);
+
+ return new_d_Const(dbgi, tv);
+}
+
+/**
+ * Creates a Const node representing a wide character constant.
+ */
+static ir_node *wide_character_constant_to_firm(const const_expression_t *cnst)
+{
+ dbg_info *dbgi = get_dbg_info(&cnst->base.source_position);
+ ir_mode *mode = get_ir_mode_arithmetic(cnst->base.type);
+
+ long long int v = cnst->v.wide_character.begin[0];
+
+ char buf[128];
+ size_t len = snprintf(buf, sizeof(buf), "%lld", v);
+ tarval *tv = new_tarval_from_str(buf, len, mode);
+
+ return new_d_Const(dbgi, tv);
+}
+
+/*
+ * Allocate an area of size bytes aligned at alignment
+ * at a frame type.
+ */
+static ir_entity *alloc_trampoline(ir_type *frame_type, int size, unsigned alignment) {
+ static unsigned area_cnt = 0;
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "trampolin%u", area_cnt++);
+ ident *name = new_id_from_str(buf);
+
+ ir_type *tp = new_type_array(id_mangle_u(get_type_ident(frame_type), name), 1, ir_type_char);
+ set_array_bounds_int(tp, 0, 0, size);
+ set_type_alignment_bytes(tp, alignment);
+
+ ir_entity *area = new_entity(frame_type, name, tp);
+
+ /* mark this entity as compiler generated */
+ set_entity_compiler_generated(area, 1);
+ return area;
+}
+
+/**
+ * Return a node representing a trampoline reagion
+ * for a given entity.
+ *
+ * @param dbgi debug info
+ * @param entity the entity
+ */
+static ir_node *get_trampoline_region(dbg_info *dbgi, ir_entity *entity)
+{
+ ir_entity *region = NULL;
+ int i;
+
+ if (current_trampolines != NULL) {
+ for (i = ARR_LEN(current_trampolines) - 1; i >= 0; --i) {
+ if (current_trampolines[i].function == entity) {
+ region = current_trampolines[i].region;
+ break;
+ }
+ }
+ } else {
+ current_trampolines = NEW_ARR_F(trampoline_region, 0);
+ }
+ ir_graph *irg = current_ir_graph;
+ if (region == NULL) {
+ /* create a new region */
+ ir_type *frame_tp = get_irg_frame_type(irg);
+ trampoline_region reg;
+ reg.function = entity;
+
+ reg.region = alloc_trampoline(frame_tp,
+ be_params->trampoline_size,
+ be_params->trampoline_align);
+ ARR_APP1(trampoline_region, current_trampolines, reg);
+ region = reg.region;
+ }
+ return new_d_simpleSel(dbgi, get_irg_no_mem(irg), get_irg_frame(irg),
+ region);
+}
+
+
+/**
+ * Creates a SymConst for a given entity.
+ *
+ * @param dbgi debug info
+ * @param mode the (reference) mode for the SymConst
+ * @param entity the entity
+ */
+static ir_node *create_symconst(dbg_info *dbgi, ir_mode *mode,
+ ir_entity *entity)