static ir_tarval *fold_expression_to_address(expression_t const *const expr) { switch (expr->kind) { case EXPR_SELECT: { select_expression_t const *const sel = &expr->select; type_t *const type = skip_typeref(sel->compound->base.type); ir_tarval *const base_addr = is_type_pointer(type) ? fold_expression(sel->compound) : fold_expression_to_address(sel->compound); ir_mode *const mode = get_tarval_mode(base_addr); ir_mode *const mode_offset = get_reference_offset_mode(mode); ir_tarval *const offset = new_tarval_from_long(sel->compound_entry->compound_member.offset, mode_offset); return tarval_add(base_addr, offset); } case EXPR_ARRAY_ACCESS: { ir_tarval *const base_addr = fold_expression_to_address(expr->array_access.array_ref); ir_tarval *const idx = fold_expression(expr->array_access.index); ir_mode *const mode = get_ir_mode_arithmetic(type_size_t); ir_tarval *const idx_conv = tarval_convert_to(idx, mode); type_t *const elem_type = skip_typeref(expr->array_access.array_ref->base.type); ir_tarval *const elem_size = get_type_size_tarval(elem_type, mode); return tarval_add(base_addr, tarval_mul(idx_conv, elem_size)); } case EXPR_UNARY_DEREFERENCE: return fold_expression(expr->unary.value); default: panic("unexpected expression kind"); } }
int main(void) { char buf[16]; int r; ir_init(); r = ir_snprintf(buf, sizeof(buf), "hello"); assert(streq(buf, "hello")); assert(r == 5); r = ir_snprintf(buf, sizeof(buf), "nums: %d %u!", 32, 46); assert(streq(buf, "nums: 32 46!")); assert(r == 12); ir_tarval *tv = new_tarval_from_long(123, mode_Iu); r = ir_snprintf(buf, sizeof(buf), "tv: %+F\n", tv); assert(streq(buf, "tv: 0x7B\n")); assert(r == 9); r = ir_snprintf(buf, sizeof(buf), "%d %d %d %d %d %d %d", 1234, 1234, 1234, 1234, 1234, 1234, 1234); assert(streq(buf, "1234 1234 1234 ")); assert(r == 34); r = ir_snprintf(buf, 4, "%+F\n", tv); assert(streq(buf, "0x7")); assert(r == 5); r = ir_snprintf(buf, 8, "%I", new_id_from_str("Hello World")); assert(streq(buf, "Hello W")); assert(r == 11); return 0; }
static ir_tarval *alignof_to_tarval(const typeprop_expression_t *expression) { unsigned const alignment = expression->tp_expression ? get_object_alignment(expression->tp_expression) : get_type_alignment(expression->type); ir_mode *const mode = get_ir_mode_storage(expression->base.type); return new_tarval_from_long(alignment, mode); }
/** * Adjust the size of a node representing a stack alloc to a certain * stack_alignment. * * @param size the node containing the non-aligned size * @param block the block where new nodes are allocated on * @return a node representing the aligned size */ static ir_node *adjust_alloc_size(dbg_info *dbgi, ir_node *size, ir_node *block) { if (stack_alignment <= 1) return size; if (is_Const(size) && !lower_constant_sizes) return size; ir_mode *mode = get_irn_mode(size); ir_tarval *tv = new_tarval_from_long(stack_alignment-1, mode); ir_graph *irg = get_Block_irg(block); ir_node *mask = new_r_Const(irg, tv); size = new_rd_Add(dbgi, block, size, mask, mode); tv = new_tarval_from_long(-(long)stack_alignment, mode); mask = new_r_Const(irg, tv); size = new_rd_And(dbgi, block, size, mask, mode); return size; }
static ir_initializer_t *new_initializer_long(ir_mode *mode, long val) { ir_tarval *tv = new_tarval_from_long(val, mode); return create_initializer_tarval(tv); }
static ir_tarval *classify_type_to_tarval(const classify_type_expression_t *const expr) { type_t *type = expr->type_expression->base.type; /* FIXME gcc returns different values depending on whether compiling C or C++ * e.g. int x[10] is pointer_type_class in C, but array_type_class in C++ */ gcc_type_class tc; for (;;) { type = skip_typeref(type); switch (type->kind) { case TYPE_ATOMIC: { const atomic_type_t *const atomic_type = &type->atomic; switch (atomic_type->akind) { case ATOMIC_TYPE_WCHAR_T: /* gcc handles this as integer */ case ATOMIC_TYPE_CHAR: /* gcc handles this as integer */ case ATOMIC_TYPE_SCHAR: /* gcc handles this as integer */ case ATOMIC_TYPE_UCHAR: /* gcc handles this as integer */ case ATOMIC_TYPE_SHORT: case ATOMIC_TYPE_USHORT: case ATOMIC_TYPE_INT: case ATOMIC_TYPE_UINT: case ATOMIC_TYPE_LONG: case ATOMIC_TYPE_ULONG: case ATOMIC_TYPE_LONGLONG: case ATOMIC_TYPE_ULONGLONG: case ATOMIC_TYPE_BOOL: /* gcc handles this as integer */ tc = integer_type_class; goto make_const; case ATOMIC_TYPE_FLOAT: case ATOMIC_TYPE_DOUBLE: case ATOMIC_TYPE_LONG_DOUBLE: tc = real_type_class; goto make_const; } panic("Unexpected atomic type."); } case TYPE_COMPLEX: tc = complex_type_class; goto make_const; case TYPE_IMAGINARY: tc = complex_type_class; goto make_const; case TYPE_ARRAY: /* gcc handles this as pointer */ case TYPE_FUNCTION: /* gcc handles this as pointer */ case TYPE_POINTER: tc = pointer_type_class; goto make_const; case TYPE_COMPOUND_STRUCT: tc = record_type_class; goto make_const; case TYPE_COMPOUND_UNION: tc = union_type_class; goto make_const; /* gcc handles this as integer */ case TYPE_ENUM: tc = integer_type_class; goto make_const; /* gcc cannot do that */ case TYPE_VOID: tc = void_type_class; goto make_const; /* gcc classifies the referenced type */ case TYPE_REFERENCE: type = type->reference.refers_to; continue; /* typedef/typeof should be skipped already */ case TYPE_TYPEDEF: case TYPE_TYPEOF: case TYPE_ERROR: case TYPE_BUILTIN_TEMPLATE: break; } panic("unexpected type."); } make_const:; ir_mode *const mode = atomic_modes[ATOMIC_TYPE_INT]; return new_tarval_from_long(tc, mode); }
static ir_tarval *offsetof_to_tarval(offsetof_expression_t const *const expression) { ir_mode *const mode = get_ir_mode_storage(expression->base.type); long const offset = get_offsetof_offset(expression); return new_tarval_from_long(offset, mode); }
static ir_tarval *get_type_size_tarval(type_t *const type, ir_mode *const mode) { size_t const size = get_type_size(type); return new_tarval_from_long(size, mode); }
/** * Lower a Sel node. Do not touch Sels accessing entities on the frame type. */ static void lower_sel(ir_node *sel) { ir_graph *irg = get_irn_irg(sel); ir_entity *ent = get_Sel_entity(sel); ir_type *owner = get_entity_owner(ent); dbg_info *dbg = get_irn_dbg_info(sel); ir_mode *mode = get_irn_mode(sel); ir_node *bl = get_nodes_block(sel); ir_node *newn; /* we can only replace Sels when the layout of the owner type is decided. */ if (get_type_state(owner) != layout_fixed) return; if (0 < get_Sel_n_indexs(sel)) { /* an Array access */ ir_type *basetyp = get_entity_type(ent); ir_mode *basemode; ir_node *index; if (is_Primitive_type(basetyp)) basemode = get_type_mode(basetyp); else basemode = mode_P_data; assert(basemode && "no mode for lowering Sel"); assert((get_mode_size_bits(basemode) % 8 == 0) && "can not deal with unorthodox modes"); index = get_Sel_index(sel, 0); if (is_Array_type(owner)) { ir_type *arr_ty = owner; size_t dims = get_array_n_dimensions(arr_ty); size_t *map = ALLOCAN(size_t, dims); ir_mode *mode_Int = get_reference_mode_signed_eq(mode); ir_tarval *tv; ir_node *last_size; size_t i; assert(dims == (size_t)get_Sel_n_indexs(sel) && "array dimension must match number of indices of Sel node"); for (i = 0; i < dims; i++) { size_t order = get_array_order(arr_ty, i); assert(order < dims && "order of a dimension must be smaller than the arrays dim"); map[order] = i; } newn = get_Sel_ptr(sel); /* Size of the array element */ tv = new_tarval_from_long(get_type_size_bytes(basetyp), mode_Int); last_size = new_rd_Const(dbg, irg, tv); /* * We compute the offset part of dimension d_i recursively * with the the offset part of dimension d_{i-1} * * off_0 = sizeof(array_element_type); * off_i = (u_i - l_i) * off_{i-1} ; i >= 1 * * whereas u_i is the upper bound of the current dimension * and l_i the lower bound of the current dimension. */ for (i = dims; i > 0;) { size_t dim = map[--i]; ir_node *lb, *ub, *elms, *n, *ind; elms = NULL; lb = get_array_lower_bound(arr_ty, dim); ub = get_array_upper_bound(arr_ty, dim); if (! is_Unknown(lb)) lb = new_rd_Conv(dbg, bl, copy_const_value(get_irn_dbg_info(sel), lb, bl), mode_Int); else lb = NULL; if (! is_Unknown(ub)) ub = new_rd_Conv(dbg, bl, copy_const_value(get_irn_dbg_info(sel), ub, bl), mode_Int); else ub = NULL; /* * If the array has more than one dimension, lower and upper * bounds have to be set in the non-last dimension. */ if (i > 0) { assert(lb != NULL && "lower bound has to be set in multi-dim array"); assert(ub != NULL && "upper bound has to be set in multi-dim array"); /* Elements in one Dimension */ elms = new_rd_Sub(dbg, bl, ub, lb, mode_Int); } ind = new_rd_Conv(dbg, bl, get_Sel_index(sel, dim), mode_Int); /* * Normalize index, id lower bound is set, also assume * lower bound == 0 */ if (lb != NULL) ind = new_rd_Sub(dbg, bl, ind, lb, mode_Int); n = new_rd_Mul(dbg, bl, ind, last_size, mode_Int); /* * see comment above. */ if (i > 0) last_size = new_rd_Mul(dbg, bl, last_size, elms, mode_Int); newn = new_rd_Add(dbg, bl, newn, n, mode); } } else { /* no array type */ ir_mode *idx_mode = get_irn_mode(index); ir_tarval *tv = new_tarval_from_long(get_mode_size_bytes(basemode), idx_mode); newn = new_rd_Add(dbg, bl, get_Sel_ptr(sel), new_rd_Mul(dbg, bl, index, new_r_Const(irg, tv), idx_mode), mode); } } else if (is_Method_type(get_entity_type(ent)) && is_Class_type(owner)) { /* We need an additional load when accessing methods from a dispatch * table. * Matze TODO: Is this really still used? At least liboo does its own * lowering of Method-Sels... */ ir_mode *ent_mode = get_type_mode(get_entity_type(ent)); int offset = get_entity_offset(ent); ir_mode *mode_Int = get_reference_mode_signed_eq(mode); ir_tarval *tv = new_tarval_from_long(offset, mode_Int); ir_node *cnst = new_rd_Const(dbg, irg, tv); ir_node *add = new_rd_Add(dbg, bl, get_Sel_ptr(sel), cnst, mode); ir_node *mem = get_Sel_mem(sel); newn = new_rd_Load(dbg, bl, mem, add, ent_mode, cons_none); newn = new_r_Proj(newn, ent_mode, pn_Load_res); } else { int offset = get_entity_offset(ent); /* replace Sel by add(obj, const(ent.offset)) */ newn = get_Sel_ptr(sel); if (offset != 0) { ir_mode *mode_UInt = get_reference_mode_unsigned_eq(mode); ir_tarval *tv = new_tarval_from_long(offset, mode_UInt); ir_node *cnst = new_r_Const(irg, tv); newn = new_rd_Add(dbg, bl, newn, cnst, mode); } } /* run the hooks */ hook_lower(sel); exchange(sel, newn); }
ir_node *new_rd_Const_long(dbg_info *db, ir_graph *irg, ir_mode *mode, long value) { return new_rd_Const(db, irg, new_tarval_from_long(value, mode)); }