Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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);
	}
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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)
	};
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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");
	}
}
Ejemplo n.º 8
0
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);
	}
}
Ejemplo n.º 9
0
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 };
	}
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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");
}