type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type) { type_t *type = skip_typeref(orig_type); /* at least: byte, word, pointer, list of machine modes * __XXX___ is interpreted as XXX */ /* This isn't really correct, the backend should provide a list of machine * specific modes (according to gcc philosophy that is...) */ attribute_argument_t *arg = attribute->a.arguments; if (arg == NULL) { errorf(&attribute->pos, "__attribute__((mode(X))) misses argument"); return orig_type; } const char *symbol_str = arg->v.symbol->string; bool sign = is_type_signed(type); atomic_type_kind_t akind; if (streq_underscore("QI", symbol_str) || streq_underscore("byte", symbol_str)) { akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR; } else if (streq_underscore("HI", symbol_str)) { akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT; } else if (streq_underscore("SI", symbol_str) || streq_underscore("word", symbol_str) || streq_underscore("pointer", symbol_str)) { akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT; } else if (streq_underscore("DI", symbol_str)) { akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG; } else { warningf(WARN_OTHER, &attribute->pos, "ignoring unknown mode '%s'", symbol_str); return orig_type; } if (type->kind == TYPE_ATOMIC || type->kind == TYPE_ENUM) { type_t *copy = duplicate_type(type); copy->atomic.akind = akind; return identify_new_type(copy); } else if (is_type_pointer(type)) { warningf(WARN_OTHER, &attribute->pos, "__attribute__((mode)) on pointers not implemented yet (ignored)"); return type; } errorf(&attribute->pos, "__attribute__((mode)) only allowed on integer, enum or pointer type"); return orig_type; }
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"); }