+static complex_value new_complex_decrement(dbg_info *dbgi, complex_value value,
+ ir_mode *mode)
+{
+ ir_node *one = new_Const(get_mode_one(mode));
+ return (complex_value) {
+ new_d_Sub(dbgi, value.real, one, mode),
+ value.imag
+ };
+}
+
+static void set_complex_value_for_expression(dbg_info *dbgi,
+ const expression_t *expression,
+ complex_value value,
+ ir_node *addr)
+{
+ type_t *const type = skip_typeref(expression->base.type);
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const real = create_conv(dbgi, value.real, mode);
+ ir_node *const imag = create_conv(dbgi, value.imag, mode);
+
+ if (expression->kind == EXPR_REFERENCE) {
+ const reference_expression_t *ref = &expression->reference;
+
+ entity_t *entity = ref->entity;
+ assert(is_declaration(entity));
+ assert(entity->declaration.kind != DECLARATION_KIND_UNKNOWN);
+ if (entity->declaration.kind == DECLARATION_KIND_LOCAL_VARIABLE ||
+ entity->declaration.kind == DECLARATION_KIND_PARAMETER) {
+ set_value(entity->variable.v.value_number, real);
+ set_value(entity->variable.v.value_number+1, imag);
+ return;
+ }
+ }
+
+ if (addr == NULL)
+ addr = expression_to_addr(expression);
+ assert(addr != NULL);
+ store_complex(dbgi, addr, type, value);
+}
+
+static complex_value create_complex_assign_unop(const unary_expression_t *unop,
+ new_complex_unop constructor,
+ bool return_old)
+{
+ dbg_info *const dbgi = get_dbg_info(&unop->base.pos);
+ const expression_t *value_expr = unop->value;
+ ir_node *addr = expression_to_addr(value_expr);
+ complex_value value = get_complex_from_lvalue(value_expr, addr);
+ type_t *type = skip_typeref(unop->base.type);
+ ir_mode *mode = get_complex_mode_arithmetic(type);
+ value = complex_conv(dbgi, value, mode);
+ complex_value new_value = constructor(dbgi, value, mode);
+ set_complex_value_for_expression(dbgi, value_expr, new_value, addr);
+ return return_old ? value : new_value;
+}
+
+static complex_value complex_negate_to_firm(const unary_expression_t *expr)
+{
+ complex_value cvalue = expression_to_complex(expr->value);
+ dbg_info *dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(expr->base.type);
+ cvalue = complex_conv(dbgi, cvalue, mode);
+ return (complex_value) {
+ new_d_Minus(dbgi, cvalue.real, mode),
+ new_d_Minus(dbgi, cvalue.imag, mode)
+ };
+}
+
+static complex_value complex_complement_to_firm(const unary_expression_t *expr)
+{
+ complex_value cvalue = expression_to_complex(expr->value);
+ dbg_info *dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(expr->base.type);
+ cvalue = complex_conv(dbgi, cvalue, mode);
+ return (complex_value) {
+ cvalue.real,
+ new_d_Minus(dbgi, cvalue.imag, mode)
+ };
+}
+
+static complex_value create_complex_binop(const binary_expression_t *binexpr,
+ new_complex_binop constructor)
+{
+ dbg_info *dbgi = get_dbg_info(&binexpr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(binexpr->base.type);
+ complex_value left = expression_to_complex(binexpr->left);
+ complex_value right = expression_to_complex(binexpr->right);
+ left = complex_conv(dbgi, left, mode);
+ right = complex_conv(dbgi, right, mode);
+ return constructor(dbgi, left, right, mode);
+}
+
+static complex_value create_complex_assign_binop(const binary_expression_t *binexpr,
+ new_complex_binop constructor)
+{
+ dbg_info *dbgi = get_dbg_info(&binexpr->base.pos);
+ expression_t *lefte = binexpr->left;
+ expression_t *righte = binexpr->right;
+ ir_mode *mode = get_complex_mode_arithmetic(righte->base.type);
+ ir_node *addr = expression_to_addr(lefte);
+ complex_value left = get_complex_from_lvalue(lefte, addr);
+ complex_value right = expression_to_complex(righte);
+ left = complex_conv(dbgi, left, mode);
+ right = complex_conv(dbgi, right, mode);
+ complex_value new_value = constructor(dbgi, left, right, mode);
+ type_t *res_type = skip_typeref(binexpr->base.type);
+ set_complex_value_for_expression(dbgi, lefte, new_value, addr);
+ return complex_conv_to_storage(dbgi, new_value, res_type);
+}
+
+static complex_value complex_call_to_firm(const call_expression_t *call)
+{
+ ir_node *result = call_expression_to_firm(call);
+ expression_t *function = call->function;
+ type_t *type = skip_typeref(function->base.type);
+ assert(is_type_pointer(type));
+ pointer_type_t *pointer_type = &type->pointer;
+ type_t *points_to = skip_typeref(pointer_type->points_to);
+ assert(is_type_function(points_to));
+ function_type_t *function_type = &points_to->function;
+ type_t *return_type = skip_typeref(function_type->return_type);
+ assert(is_type_complex(return_type));
+ dbg_info *dbgi = get_dbg_info(&call->base.pos);
+ return complex_deref_address(dbgi, return_type, result, cons_floats);
+}
+
+static void complex_equality_evaluation(const binary_expression_t *binexpr,
+ jump_target *const true_target, jump_target *const false_target,
+ ir_relation relation)
+{
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+
+ complex_value left = expression_to_complex(binexpr->left);
+ complex_value right = expression_to_complex(binexpr->right);
+ dbg_info *dbgi = get_dbg_info(&binexpr->base.pos);
+ ir_mode *mode = get_complex_mode_arithmetic(binexpr->left->base.type);
+ left = complex_conv(dbgi, left, mode);
+ right = complex_conv(dbgi, right, mode);
+
+ ir_node *cmp_real = new_d_Cmp(dbgi, left.real, right.real, relation);
+ ir_node *cond = new_d_Cond(dbgi, cmp_real);
+ ir_node *true_proj = new_Proj(cond, mode_X, pn_Cond_true);
+ ir_node *false_proj = new_Proj(cond, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(&extra_target, true_proj);
+ add_pred_to_jump_target(false_target, false_proj);
+ if (!enter_jump_target(&extra_target))
+ return;
+
+ ir_node *cmp_imag = new_d_Cmp(dbgi, left.imag, right.imag, relation);
+ ir_node *condi = new_d_Cond(dbgi, cmp_imag);
+ ir_node *true_proj_i = new_Proj(condi, mode_X, pn_Cond_true);
+ ir_node *false_proj_i = new_Proj(condi, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(true_target, true_proj_i);
+ add_pred_to_jump_target(false_target, false_proj_i);
+ set_unreachable_now();
+}
+
+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);
+ value = complex_conv(dbgi, value, mode);
+ ir_node *const zero = new_Const(get_mode_null(mode));
+ ir_node *const cmp_real =
+ new_d_Cmp(dbgi, value.real, zero, ir_relation_unordered_less_greater);
+ ir_node *const cond_real = new_d_Cond(dbgi, cmp_real);
+ ir_node *const true_real = new_Proj(cond_real, mode_X, pn_Cond_true);
+ ir_node *const false_real = new_Proj(cond_real, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(true_target, true_real);
+ add_pred_to_jump_target(&extra_target, false_real);
+ if (!enter_jump_target(&extra_target))
+ return value;
+
+ ir_node *const cmp_imag =
+ new_d_Cmp(dbgi, value.imag, zero, ir_relation_unordered_less_greater);
+ ir_node *const cond_imag = new_d_Cond(dbgi, cmp_imag);
+ ir_node *const true_imag = new_Proj(cond_imag, mode_X, pn_Cond_true);
+ ir_node *const false_imag = new_Proj(cond_imag, mode_X, pn_Cond_false);
+ add_pred_to_jump_target(true_target, true_imag);
+ add_pred_to_jump_target(false_target, false_imag);
+ set_unreachable_now();
+
+ return value;
+}
+
+static complex_value complex_conditional_to_firm(
+ const conditional_expression_t *const expression)
+{
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ complex_value cond_val;
+ memset(&cond_val, 0, sizeof(cond_val));
+ if (expression->true_expression == NULL) {
+ assert(is_type_complex(skip_typeref(expression->condition->base.type)));
+ 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;
+ memset(&val, 0, sizeof(val));
+ 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) {
+ val = expression_to_complex(expression->true_expression);
+ } else {
+ assert(cond_val.real != NULL);
+ val = cond_val;
+ }
+ val = complex_conv(dbgi, val, mode);
+ jump_to_target(&exit_target);
+ }
+
+ 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 };
+ 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);
+ } else {
+ val = false_val;
+ }
+ }
+
+ if (!enter_jump_target(&exit_target)) {
+ set_cur_block(new_Block(0, NULL));
+ assert(!is_type_void(type));
+ val.real = val.imag = new_Bad(mode);
+ }
+ return val;
+}
+
+static void create_local_declarations(entity_t*);
+
+static complex_value compound_statement_to_firm_complex(
+ const compound_statement_t *compound)
+{
+ create_local_declarations(compound->scope.entities);
+
+ complex_value result = { NULL, NULL };
+ statement_t *statement = compound->statements;
+ statement_t *next;
+ for ( ; statement != NULL; statement = next) {
+ next = statement->base.next;
+ /* last statement is the return value */
+ if (next == NULL) {
+ /* it must be an expression, otherwise we wouldn't be in the
+ * complex variant of compound_statement_to_firm */
+ if (statement->kind != STATEMENT_EXPRESSION)
+ panic("last member of complex statement expression not an expression statement");
+ expression_t *expression = statement->expression.expression;
+ assert(is_type_complex(skip_typeref(expression->base.type)));
+ result = expression_to_complex(expression);
+ } else {
+ statement_to_firm(statement);
+ }
+ }
+
+ 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)
+{
+ const statement_t *const statement = expr->statement;
+ assert(statement->kind == STATEMENT_COMPOUND);
+
+ return compound_statement_to_firm_complex(&statement->compound);
+}
+
+static complex_value expression_to_complex(const expression_t *expression)
+{
+ switch (expression->kind) {
+ case EXPR_REFERENCE:
+ return complex_reference_to_firm(&expression->reference);
+ case EXPR_SELECT:
+ return complex_select_to_firm(&expression->select);
+ case EXPR_ARRAY_ACCESS:
+ return complex_array_access_to_firm(&expression->array_access);
+ case EXPR_UNARY_CAST:
+ return complex_cast_to_firm(&expression->unary);
+ case EXPR_BINARY_COMMA:
+ evaluate_expression_discard_result(expression->binary.left);
+ return expression_to_complex(expression->binary.right);
+ case EXPR_BINARY_ADD:
+ return create_complex_binop(&expression->binary, new_complex_add);
+ case EXPR_BINARY_ADD_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_add);
+ case EXPR_BINARY_SUB:
+ return create_complex_binop(&expression->binary, new_complex_sub);
+ case EXPR_BINARY_SUB_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_sub);
+ case EXPR_BINARY_MUL:
+ return create_complex_binop(&expression->binary, new_complex_mul);
+ case EXPR_BINARY_MUL_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_mul);
+ case EXPR_BINARY_DIV:
+ return create_complex_binop(&expression->binary, new_complex_div);
+ case EXPR_BINARY_DIV_ASSIGN:
+ return create_complex_assign_binop(&expression->binary, new_complex_div);
+ case EXPR_UNARY_PLUS:
+ return expression_to_complex(expression->unary.value);
+ case EXPR_UNARY_PREFIX_INCREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_increment, false);
+ case EXPR_UNARY_PREFIX_DECREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_decrement, false);
+ case EXPR_UNARY_POSTFIX_INCREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_increment, true);
+ case EXPR_UNARY_POSTFIX_DECREMENT:
+ return create_complex_assign_unop(&expression->unary,
+ new_complex_decrement, true);
+ case EXPR_UNARY_NEGATE:
+ return complex_negate_to_firm(&expression->unary);
+ case EXPR_UNARY_COMPLEMENT:
+ return complex_complement_to_firm(&expression->unary);
+ case EXPR_BINARY_ASSIGN:
+ return complex_assign_to_firm(&expression->binary);
+ case EXPR_LITERAL_CASES:
+ return complex_literal_to_firm(&expression->literal);