ast2firm: Implement casting from complex to real types.
[cparser] / ast2firm.c
index 26bddff..2e85c8a 100644 (file)
@@ -1,21 +1,6 @@
 /*
  * This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
  */
 #include <config.h>
 
@@ -2222,10 +2207,13 @@ static ir_node *create_cast(unary_expression_t const *const expr)
        if (is_type_void(type))
                return NULL;
 
-       ir_node        *value     = expression_to_value(expr->value);
-       dbg_info *const dbgi      = get_dbg_info(&expr->base.pos);
-       type_t   *const from_type = skip_typeref(expr->value->base.type);
-       ir_mode  *const mode      = get_ir_mode_storage(type);
+       type_t  *const from_type = skip_typeref(expr->value->base.type);
+       ir_node       *value     = is_type_complex(from_type)
+               ? expression_to_complex(expr->value).real
+               : expression_to_value(expr->value);
+
+       dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+       ir_mode  *const mode = get_ir_mode_storage(type);
        /* check for conversion from / to __based types */
        if (is_type_pointer(type) && is_type_pointer(from_type)) {
                const variable_t *from_var = from_type->pointer.base_variable;
@@ -3326,9 +3314,9 @@ static void complex_equality_evaluation(const binary_expression_t *binexpr,
        jump_target *const true_target, jump_target *const false_target,
        ir_relation relation);
 
-static complex_value create_complex_condition_evaluation(
-       const expression_t *const expression, jump_target *const true_target,
-       jump_target *const false_target);
+static complex_value complex_to_control_flow(const expression_t *expression,
+                                             jump_target *true_target,
+                                             jump_target *false_target);
 
 /**
  * create a short-circuit expression evaluation that tries to construct
@@ -3399,7 +3387,7 @@ static ir_node *expression_to_control_flow(expression_t const *const expr, jump_
        default:;
                        type_t *const type = skip_typeref(expr->base.type);
                        if (is_type_complex(type)) {
-                               create_complex_condition_evaluation(expr, true_target, false_target);
+                               complex_to_control_flow(expr, true_target, false_target);
                                return NULL;
                        }
 
@@ -3823,13 +3811,25 @@ static void complex_equality_evaluation(const binary_expression_t *binexpr,
        set_unreachable_now();
 }
 
-static complex_value create_complex_condition_evaluation(
+static complex_value complex_to_control_flow(
        const expression_t *const expression, jump_target *const true_target,
        jump_target *const false_target)
 {
        jump_target extra_target;
        init_jump_target(&extra_target, NULL);
        complex_value       value      = expression_to_complex(expression);
+       if (is_Const(value.real) && is_Const(value.imag)) {
+               ir_tarval *tv_real = get_Const_tarval(value.real);
+               ir_tarval *tv_imag = get_Const_tarval(value.imag);
+               if (tarval_is_null(tv_real) && tarval_is_null(tv_imag)) {
+                       jump_to_target(false_target);
+               } else {
+                       jump_to_target(true_target);
+               }
+               set_unreachable_now();
+               return value;
+       }
+
        dbg_info     *const dbgi       = get_dbg_info(&expression->base.pos);
        type_t       *const type       = expression->base.type;
        ir_mode      *const mode       = get_complex_mode_arithmetic(type);
@@ -3860,23 +3860,6 @@ static complex_value create_complex_condition_evaluation(
 static complex_value complex_conditional_to_firm(
        const conditional_expression_t *const expression)
 {
-       /* first try to fold a constant condition */
-       if (is_constant_expression(expression->condition) == EXPR_CLASS_CONSTANT) {
-               bool val = fold_constant_to_bool(expression->condition);
-               if (val) {
-                       expression_t *true_expression = expression->true_expression;
-                       if (true_expression == NULL) {
-                               /* we will evaluate true_expression a second time here, but in
-                                * this case it is harmless since constant expression have no
-                                * side effects */
-                               true_expression = expression->condition;
-                       }
-                       return expression_to_complex(true_expression);
-               } else {
-                       return expression_to_complex(expression->false_expression);
-               }
-       }
-
        jump_target true_target;
        jump_target false_target;
        init_jump_target(&true_target,  NULL);
@@ -3885,17 +3868,19 @@ static complex_value complex_conditional_to_firm(
        memset(&cond_val, 0, sizeof(cond_val));
        if (expression->true_expression == NULL) {
                assert(is_type_complex(skip_typeref(expression->condition->base.type)));
-               cond_val
-                       = create_complex_condition_evaluation(expression->condition,
-                                                             &true_target, &false_target);
+               cond_val = complex_to_control_flow(expression->condition,
+                                                  &true_target, &false_target);
        } else {
                expression_to_control_flow(expression->condition, &true_target, &false_target);
        }
 
-       complex_value val;
+       complex_value  val;
        memset(&val, 0, sizeof(val));
-       jump_target   exit_target;
+       jump_target    exit_target;
        init_jump_target(&exit_target, NULL);
+       type_t   *const type = skip_typeref(expression->base.type);
+       ir_mode  *const mode = get_complex_mode_arithmetic(type);
+       dbg_info *const dbgi = get_dbg_info(&expression->base.pos);
 
        if (enter_jump_target(&true_target)) {
                if (expression->true_expression) {
@@ -3904,19 +3889,18 @@ static complex_value complex_conditional_to_firm(
                        assert(cond_val.real != NULL);
                        val = cond_val;
                }
+               val = complex_conv(dbgi, val, mode);
                jump_to_target(&exit_target);
        }
 
-       type_t *const type = skip_typeref(expression->base.type);
        if (enter_jump_target(&false_target)) {
                complex_value false_val
                        = expression_to_complex(expression->false_expression);
+               false_val = complex_conv(dbgi, false_val, mode);
                jump_to_target(&exit_target);
                if (val.real != NULL) {
                        ir_node  *const inr[] = { val.real, false_val.real };
                        ir_node  *const ini[] = { val.imag, false_val.imag };
-                       dbg_info *const dbgi  = get_dbg_info(&expression->base.pos);
-                       ir_mode  *const mode  = get_complex_mode_arithmetic(type);
                        ir_node  *const block = exit_target.block;
                        val.real = new_rd_Phi(dbgi, block, lengthof(inr), inr, mode);
                        val.imag = new_rd_Phi(dbgi, block, lengthof(ini), ini, mode);
@@ -3928,9 +3912,7 @@ static complex_value complex_conditional_to_firm(
        if (!enter_jump_target(&exit_target)) {
                set_cur_block(new_Block(0, NULL));
                assert(!is_type_void(type));
-               ir_mode *mode = get_complex_mode_arithmetic(type);
-               val.real = new_Unknown(mode);
-               val.imag = val.real;
+               val.real = val.imag = new_Bad(mode);
        }
        return val;
 }
@@ -3964,6 +3946,15 @@ static complex_value compound_statement_to_firm_complex(
        return result;
 }
 
+static complex_value complex_assign_to_firm(const binary_expression_t *expr)
+{
+       dbg_info     *const dbgi  = get_dbg_info(&expr->base.pos);
+       complex_value const value = expression_to_complex(expr->right);
+       ir_node      *const addr  = expression_to_addr(expr->left);
+       set_complex_value_for_expression(dbgi, expr->left, value, addr);
+       return value;
+}
+
 static complex_value complex_statement_expression_to_firm(
        const statement_expression_t *const expr)
 {
@@ -4021,14 +4012,8 @@ static complex_value expression_to_complex(const expression_t *expression)
                return complex_negate_to_firm(&expression->unary);
        case EXPR_UNARY_COMPLEMENT:
                return complex_complement_to_firm(&expression->unary);
-       case EXPR_BINARY_ASSIGN: {
-               const binary_expression_t *binexpr = &expression->binary;
-               dbg_info                  *dbgi   = get_dbg_info(&binexpr->base.pos);
-               complex_value value = expression_to_complex(binexpr->right);
-               ir_node      *addr  = expression_to_addr(binexpr->left);
-               set_complex_value_for_expression(dbgi, binexpr->left, value, addr);
-               return value;
-       }
+       case EXPR_BINARY_ASSIGN:
+               return complex_assign_to_firm(&expression->binary);
        case EXPR_LITERAL_CASES:
                return complex_literal_to_firm(&expression->literal);
        case EXPR_CALL: