bool fold_expression_to_bool(const expression_t *expression) { type_t *type = skip_typeref(expression->base.type); if (is_type_complex(type)) { complex_constant tvs = fold_complex(expression); return !tarval_is_null(tvs.real) || !tarval_is_null(tvs.imag); } else { ir_tarval *tv = fold_expression(expression); return !tarval_is_null(tv); } }
/* * Check, if the value of a node cannot represent a NULL pointer. * * - Sels are skipped * - A SymConst(entity) is NEVER a NULL pointer * - Confirms are evaluated */ int value_not_null(const ir_node *n, const ir_node **confirm) { ir_tarval *tv; *confirm = NULL; tv = value_of(n); if (tarval_is_constant(tv) && ! tarval_is_null(tv)) return 1; assert(mode_is_reference(get_irn_mode(n))); /* skip all Sel nodes */ while (is_Sel(n)) { n = get_Sel_ptr(n); } while (1) { if (is_Proj(n)) { n = get_Proj_pred(n); continue; } break; } if (is_SymConst_addr_ent(n)) { /* global references are never NULL */ return 1; } else if (n == get_irg_frame(get_irn_irg(n))) { /* local references are never NULL */ return 1; } else if (is_Alloc(n)) { /* alloc never returns NULL (it throws an exception instead) */ return 1; } else { /* check for more Confirms */ for (; is_Confirm(n); n = get_Confirm_value(n)) { if (get_Confirm_relation(n) == ir_relation_less_greater) { ir_node *bound = get_Confirm_bound(n); ir_tarval *tv = value_of(bound); if (tarval_is_null(tv)) { *confirm = n; return 1; } } } } return 0; }
static complex_constant fold_complex_conditional( conditional_expression_t const *const cond) { type_t const *const condition_type = skip_typeref(cond->condition->base.type); if (!is_type_complex(condition_type)) { bool condval = fold_expression_to_bool(cond->condition); expression_t *to_fold = condval ? cond->true_expression : cond->false_expression; return fold_complex(to_fold); } complex_constant const val = fold_complex(cond->condition); return tarval_is_null(val.real) && tarval_is_null(val.imag) ? fold_complex(cond->false_expression) : cond->true_expression ? fold_complex(cond->true_expression) : val; }
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"); }