static ir_tarval *fold_binary_add(binary_expression_t const *const binexpr) { ir_tarval *const l = fold_expression(binexpr->left); ir_tarval *const r = fold_expression(binexpr->right); ir_tarval *ll = l; ir_tarval *rr = r; type_t *const typel = skip_typeref(binexpr->left->base.type); type_t *const typer = skip_typeref(binexpr->right->base.type); if (is_type_pointer(typel)) { type_t *const elem = skip_typeref(typel->pointer.points_to); ir_mode *const mode = get_ir_mode_arithmetic(typer); ir_tarval *const size = get_type_size_tarval(elem, mode); rr = tarval_mul(rr, size); } else if (is_type_pointer(typer)) { type_t *const elem = skip_typeref(typer->pointer.points_to); ir_mode *const mode = get_ir_mode_arithmetic(typel); ir_tarval *const size = get_type_size_tarval(elem, mode); ll = tarval_mul(ll, size); } else { type_t *const type = skip_typeref(binexpr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); ll = tarval_convert_to(l, mode); rr = tarval_convert_to(r, mode); } return tarval_add(ll, rr); }
static ir_tarval *fold_binary_sub(binary_expression_t const *const binexpr) { ir_tarval *const l = fold_expression(binexpr->left); ir_tarval *const r = fold_expression(binexpr->right); type_t *const type = skip_typeref(binexpr->base.type); ir_mode *const res_mode = get_ir_mode_arithmetic(type); type_t *const typel = skip_typeref(binexpr->left->base.type); if (is_type_pointer(typel)) { type_t *const elem = skip_typeref(typel->pointer.points_to); type_t *const typer = skip_typeref(binexpr->right->base.type); if (is_type_pointer(typer)) { ir_tarval *const size = get_type_size_tarval(elem, res_mode); ir_tarval *const diff = tarval_sub(l, r); return tarval_div(diff, size); } else { ir_mode *const mode = get_tarval_mode(r); ir_tarval *const size = get_type_size_tarval(elem, mode); ir_tarval *const rr = tarval_mul(r, size); return tarval_sub(l, rr); } } else { ir_tarval *const conv_l = tarval_convert_to(l, res_mode); ir_tarval *const conv_r = tarval_convert_to(r, res_mode); return tarval_sub(conv_l, conv_r); } }
static carry_result lower_sub_borrow(ir_node *left, ir_node *right, ir_mode *mode) { assert(!mode_is_signed(mode)); bitinfo *bi_left = get_bitinfo(left); if (!bi_left) { return can_carry; } bitinfo *bi_right = get_bitinfo(right); // If we have bitinfo for one node, we should also have it for // the other assert(bi_right); ir_tarval *lmin = tarval_convert_to(bitinfo_min(bi_left), mode); ir_tarval *rmin = tarval_convert_to(bitinfo_min(bi_right), mode); ir_tarval *lmax = tarval_convert_to(bitinfo_max(bi_left), mode); ir_tarval *rmax = tarval_convert_to(bitinfo_max(bi_right), mode); carry_result result = no_carry; int old_wrap_on_overflow = tarval_get_wrap_on_overflow(); tarval_set_wrap_on_overflow(false); if (tarval_sub(lmin, rmax) == tarval_bad) { result = can_carry; if (tarval_sub(lmax, rmin) == tarval_bad) { result = must_carry; } } tarval_set_wrap_on_overflow(old_wrap_on_overflow); return result; }
static complex_constant convert_complex_constant(const complex_constant cnst, ir_mode *mode) { if (get_tarval_mode(cnst.real) == mode) return cnst; return (complex_constant) { tarval_convert_to(cnst.real, mode), tarval_convert_to(cnst.imag, mode) }; }
static ir_tarval *fold_binary_expression_arithmetic( binary_expression_t const *const binexpr, fold_binary_func fold) { ir_tarval *const left = fold_expression(binexpr->left); ir_tarval *const right = fold_expression(binexpr->right); type_t *const type = skip_typeref(binexpr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); ir_tarval *const cleft = tarval_convert_to(left, mode); ir_tarval *const cright = tarval_convert_to(right, mode); return fold(cleft, cright); }
static ir_tarval *fold_binary_comparison( binary_expression_t const *const binexpr) { ir_tarval *const left = fold_expression(binexpr->left); ir_tarval *const right = fold_expression(binexpr->right); type_t *const atype = skip_typeref(binexpr->left->base.type); ir_mode *const amode = get_ir_mode_arithmetic(atype); assert(amode == get_ir_mode_arithmetic(skip_typeref(binexpr->right->base.type))); ir_tarval *const lefta = tarval_convert_to(left, amode); ir_tarval *const righta = tarval_convert_to(right, amode); type_t *const type = skip_typeref(binexpr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); ir_relation const rel = get_relation(binexpr->base.kind); return create_tarval_from_bool(mode, tarval_cmp(lefta, righta) & rel); }
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"); } }
static void check_mode(ir_mode *mode) { ir_tarval *zero = get_mode_null(mode); ir_tarval *minus_zero = tarval_neg(zero); ir_tarval *min = get_mode_min(mode); ir_tarval *max = get_mode_max(mode); ir_tarval *inf = get_mode_infinite(mode); ir_tarval *minus_inf = tarval_neg(inf); ir_tarval *one = get_mode_one(mode); ir_tarval *minus_one = tarval_neg(one); /* some random arithmetics */ ir_tarval *int_zero = get_mode_null(mode_Is); ir_tarval *int_one = get_mode_one(mode_Is); ir_tarval *int_minus_one = get_mode_all_one(mode_Is); ir_tarval *int_min = get_mode_min(mode_Is); ir_tarval *int_max = get_mode_max(mode_Is); assert(tarval_convert_to(zero, mode_Is) == int_zero); assert(tarval_convert_to(minus_zero, mode_Is) == int_zero); assert(tarval_convert_to(one, mode_Is) == int_one); assert(tarval_convert_to(minus_one, mode_Is) == int_minus_one); assert(tarval_convert_to(min, mode_Is) == int_min); assert(tarval_convert_to(max, mode_Is) == int_max); assert(tarval_convert_to(inf, mode_Is) == int_max); assert(tarval_convert_to(minus_inf, mode_Is) == int_min); static const char *const ints[] = { "0", "1", "-1", "12345", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "127", "2047" }; for (unsigned i = 0; i < ARRAY_SIZE(ints); ++i) { const char *str = ints[i]; ir_tarval *flt = new_tarval_from_str(str, strlen(str), mode); ir_tarval *intt = new_tarval_from_str(str, strlen(str), mode_Is); assert(tarval_convert_to(flt, mode_Is) == intt); assert(tarval_convert_to(intt, mode) == flt); } }
static complex_constant fold_complex_cast(const unary_expression_t *expression) { const expression_t *const value = expression->value; 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_constant const folded = fold_complex(value); return convert_complex_constant(folded, mode); } else { ir_tarval *const folded = fold_expression(value); ir_tarval *const casted = tarval_convert_to(folded, mode); ir_tarval *const zero = get_mode_null(mode); return (complex_constant) { casted, zero }; } }
bool enum_bitfield_big_enough(enum_t *enume, type_t *base_type, unsigned bitfield_size) { ir_mode *mode = get_ir_mode_storage(base_type); ir_tarval *max = get_mode_max(mode); ir_tarval *min = get_mode_min(mode); bool is_signed = is_type_signed(base_type); unsigned mode_size = get_mode_size_bits(mode); unsigned shift_amount = mode_size - bitfield_size + is_signed; ir_tarval *adjusted_max; ir_tarval *adjusted_min; /* corner case: signed mode with just sign bit results in shift_amount * being as big as mode_size triggering "modulo shift" which is not what * we want here. */ if (shift_amount >= mode_size) { assert(bitfield_size == 1 && mode_is_signed(mode)); adjusted_max = get_mode_null(mode); adjusted_min = get_mode_all_one(mode); } else { adjusted_max = tarval_shr_unsigned(max, shift_amount); adjusted_min = tarval_shrs_unsigned(min, shift_amount); } for (entity_t *entry = enume->first_value; entry != NULL && entry->kind == ENTITY_ENUM_VALUE; entry = entry->base.next) { ir_tarval *tv = get_enum_value(&entry->enum_value); if (tv == NULL) continue; ir_tarval *tvc = tarval_convert_to(tv, mode); if (tarval_cmp(tvc, adjusted_min) == ir_relation_less || tarval_cmp(tvc, adjusted_max) == ir_relation_greater) { return false; } } return true; }
ir_tarval *fold_expression(expression_t const *const expr) { switch (expr->kind) { case EXPR_CONDITIONAL: { conditional_expression_t const *const cond = &expr->conditional; if (cond->true_expression != NULL) { /* note that we need this if in case of a complex expression as * condition */ bool condval = fold_expression_to_bool(cond->condition); expression_t *res = condval ? cond->true_expression : cond->false_expression; return fold_expression(res); } ir_tarval *const val = fold_expression(cond->condition); return tarval_is_null(val) ? fold_expression(cond->false_expression) : cond->true_expression ? fold_expression(cond->true_expression) : val; } case EXPR_SIZEOF: { type_t *const type = skip_typeref(expr->typeprop.type); ir_mode *const mode = get_ir_mode_arithmetic(skip_typeref(expr->base.type)); return get_type_size_tarval(type, mode); } case EXPR_ALIGNOF: return alignof_to_tarval( &expr->typeprop); case EXPR_BUILTIN_CONSTANT_P: return builtin_constant_to_tarval( &expr->builtin_constant); case EXPR_BUILTIN_TYPES_COMPATIBLE_P: return builtin_types_compatible_to_tarval(&expr->builtin_types_compatible); case EXPR_CLASSIFY_TYPE: return classify_type_to_tarval( &expr->classify_type); case EXPR_ENUM_CONSTANT: return enum_constant_to_tarval( &expr->reference); case EXPR_LITERAL_CASES: return literal_to_tarval( &expr->literal); case EXPR_LITERAL_CHARACTER: return char_literal_to_tarval( &expr->string_literal); case EXPR_OFFSETOF: return offsetof_to_tarval( &expr->offsetofe); case EXPR_UNARY_TAKE_ADDRESS: return fold_expression_to_address( expr->unary.value); case EXPR_UNARY_NEGATE: return tarval_neg(fold_expression(expr->unary.value)); case EXPR_UNARY_PLUS: return fold_expression(expr->unary.value); case EXPR_UNARY_COMPLEMENT: return tarval_not(fold_expression(expr->unary.value)); case EXPR_UNARY_NOT: { type_t *const type = skip_typeref(expr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); ir_tarval *const val = fold_expression(expr->unary.value); return create_tarval_from_bool(mode, tarval_is_null(val)); } case EXPR_UNARY_CAST: { type_t *const type = skip_typeref(expr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); ir_tarval *const val = fold_expression(expr->unary.value); if (is_type_atomic(type, ATOMIC_TYPE_BOOL)) { return create_tarval_from_bool(mode, !tarval_is_null(val)); } else { return tarval_convert_to(val, mode); } } 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: return fold_binary_comparison(&expr->binary); case EXPR_BINARY_ADD: return fold_binary_add(&expr->binary); case EXPR_BINARY_SUB: return fold_binary_sub(&expr->binary); case EXPR_BINARY_MUL: return fold_binary_expression_arithmetic(&expr->binary, tarval_mul); case EXPR_BINARY_DIV: return fold_binary_expression_arithmetic(&expr->binary, tarval_div); case EXPR_BINARY_MOD: return fold_binary_expression_arithmetic(&expr->binary, tarval_mod); case EXPR_BINARY_BITWISE_OR: return fold_binary_expression_arithmetic(&expr->binary, tarval_or); case EXPR_BINARY_BITWISE_AND: return fold_binary_expression_arithmetic(&expr->binary, tarval_and); case EXPR_BINARY_BITWISE_XOR: return fold_binary_expression_arithmetic(&expr->binary, tarval_eor); case EXPR_BINARY_SHIFTLEFT: return fold_binary_expression_arithmetic(&expr->binary, tarval_shl); case EXPR_BINARY_SHIFTRIGHT: { fold_binary_func fold = is_type_signed(skip_typeref(expr->base.type)) ? tarval_shrs : tarval_shr; return fold_binary_expression_arithmetic(&expr->binary, fold); } case EXPR_BINARY_LOGICAL_AND: { bool const c = !tarval_is_null(fold_expression(expr->binary.left)) && !tarval_is_null(fold_expression(expr->binary.right)); type_t *const type = skip_typeref(expr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); return create_tarval_from_bool(mode, c); } case EXPR_BINARY_LOGICAL_OR: { bool const c = !tarval_is_null(fold_expression(expr->binary.left)) || !tarval_is_null(fold_expression(expr->binary.right)); type_t *const type = skip_typeref(expr->base.type); ir_mode *const mode = get_ir_mode_arithmetic(type); return create_tarval_from_bool(mode, c); } case EXPR_UNARY_REAL: { complex_constant cnst = fold_complex(expr->unary.value); return cnst.real; } case EXPR_UNARY_IMAG: { complex_constant cnst = fold_complex(expr->unary.value); return cnst.imag; } case EXPR_CALL: return fold_call_builtin(&expr->call); case EXPR_ARRAY_ACCESS: case EXPR_BINARY_ADD_ASSIGN: case EXPR_BINARY_ASSIGN: case EXPR_BINARY_BITWISE_AND_ASSIGN: case EXPR_BINARY_BITWISE_OR_ASSIGN: case EXPR_BINARY_BITWISE_XOR_ASSIGN: case EXPR_BINARY_COMMA: 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: case EXPR_COMPOUND_LITERAL: case EXPR_ERROR: case EXPR_FUNCNAME: case EXPR_LABEL_ADDRESS: case EXPR_REFERENCE: case EXPR_SELECT: case EXPR_STATEMENT: case EXPR_STRING_LITERAL: case EXPR_UNARY_ASSUME: case EXPR_UNARY_DELETE: case EXPR_UNARY_DELETE_ARRAY: case EXPR_UNARY_DEREFERENCE: case EXPR_UNARY_POSTFIX_DECREMENT: case EXPR_UNARY_POSTFIX_INCREMENT: case EXPR_UNARY_PREFIX_DECREMENT: case EXPR_UNARY_PREFIX_INCREMENT: case EXPR_UNARY_THROW: case EXPR_VA_ARG: case EXPR_VA_COPY: case EXPR_VA_START: panic("invalid expression kind for constant folding"); } panic("unexpected expression kind for constant folding"); }