+ /* FALLTHROUGH */
+ default: {
+ type_t *const type = skip_typeref(expr->base.type);
+ if (is_type_complex(type)) {
+ complex_to_control_flow(expr, true_target, false_target);
+ return NULL;
+ }
+
+ dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
+ ir_mode *const mode = get_ir_mode_arithmetic(type);
+ ir_node *const val = create_conv(dbgi, expression_to_value(expr), mode);
+ ir_node *const left = val;
+ ir_node *const right = new_Const(get_mode_null(get_irn_mode(val)));
+ ir_relation const relation = ir_relation_unordered_less_greater;
+ compare_to_control_flow(expr, left, right, relation, true_target, false_target);
+ return val;
+ }
+ }
+}
+
+static complex_value complex_conv(dbg_info *dbgi, complex_value value,
+ ir_mode *mode)
+{
+ return (complex_value) {
+ create_conv(dbgi, value.real, mode),
+ create_conv(dbgi, value.imag, mode)
+ };
+}
+
+static complex_value complex_conv_to_storage(dbg_info *const dbgi,
+ complex_value const value, type_t *const type)
+{
+ ir_mode *const mode = get_complex_mode_storage(type);
+ return complex_conv(dbgi, value, mode);
+}
+
+static void store_complex(dbg_info *dbgi, ir_node *addr, type_t *type,
+ complex_value value)
+{
+ value = complex_conv_to_storage(dbgi, value, type);
+ ir_graph *const irg = current_ir_graph;
+ ir_type *const irtype = get_ir_type(type);
+ ir_node *const mem = get_store();
+ ir_node *const nomem = get_irg_no_mem(irg);
+ 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);
+ ir_node *const storer = new_d_Store(dbgi, mem, addr, real, cons_floats);
+ ir_node *const memr = new_Proj(storer, mode_M, pn_Store_M);
+ ir_mode *const muint = atomic_modes[ATOMIC_TYPE_UINT];
+ ir_node *const one = new_Const(get_mode_one(muint));
+ ir_node *const in[1] = { one };
+ ir_entity *const arrent = get_array_element_entity(irtype);
+ ir_node *const addri = new_d_Sel(dbgi, nomem, addr, 1, in, arrent);
+ ir_node *const storei = new_d_Store(dbgi, memr, addri, imag, cons_floats);
+ ir_node *const memi = new_Proj(storei, mode_M, pn_Store_M);
+ set_store(memi);
+}
+
+static ir_node *complex_to_memory(dbg_info *dbgi, type_t *type,
+ complex_value value)
+{
+ ir_graph *const irg = current_ir_graph;
+ ir_type *const frame_type = get_irg_frame_type(irg);
+ ident *const id = id_unique("cmplex_tmp.%u");
+ ir_type *const irtype = get_ir_type(type);
+ ir_entity *const tmp_storage = new_entity(frame_type, id, irtype);
+ ir_node *const frame = get_irg_frame(irg);
+ ir_node *const nomem = get_irg_no_mem(irg);
+ ir_node *const addr = new_simpleSel(nomem, frame, tmp_storage);
+ set_entity_compiler_generated(tmp_storage, 1);
+ store_complex(dbgi, addr, type, value);
+ return addr;
+}
+
+static complex_value read_localvar_complex(dbg_info *dbgi, entity_t *const entity)
+{
+ assert(entity->declaration.kind == DECLARATION_KIND_LOCAL_VARIABLE
+ || entity->declaration.kind == DECLARATION_KIND_PARAMETER);
+ type_t *const type = skip_typeref(entity->declaration.type);
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const real = get_value(entity->variable.v.value_number, mode);
+ ir_node *const imag = get_value(entity->variable.v.value_number+1, mode);
+ ir_mode *const mode_arithmetic = get_complex_mode_arithmetic(type);
+ return (complex_value) {
+ create_conv(dbgi, real, mode_arithmetic),
+ create_conv(dbgi, imag, mode_arithmetic)
+ };
+}
+
+static complex_value complex_deref_address(dbg_info *const dbgi,
+ type_t *type, ir_node *const addr,
+ ir_cons_flags flags)
+{
+ type = skip_typeref(type);
+ assert(is_type_complex(type));
+
+ if (type->base.qualifiers & TYPE_QUALIFIER_VOLATILE)
+ flags |= cons_volatile;
+ ir_mode *const mode = get_complex_mode_storage(type);
+ ir_node *const memory = get_store();
+ ir_node *const load = new_d_Load(dbgi, memory, addr, mode, flags);
+ ir_node *const load_mem = new_Proj(load, mode_M, pn_Load_M);
+ ir_node *const load_res = new_Proj(load, mode, pn_Load_res);
+
+ ir_type *const irtype = get_ir_type(type);
+ ir_mode *const mode_uint = atomic_modes[ATOMIC_TYPE_UINT];
+ ir_node *const in[1] = { new_Const(get_mode_one(mode_uint)) };
+ ir_entity *const entity = get_array_element_entity(irtype);
+ ir_node *const nomem = get_irg_no_mem(current_ir_graph);
+ ir_node *const addr2 = new_Sel(nomem, addr, 1, in, entity);
+ ir_node *const load2 = new_d_Load(dbgi, load_mem, addr2, mode, flags);
+ ir_node *const load_mem2 = new_Proj(load2, mode_M, pn_Load_M);
+ ir_node *const load_res2 = new_Proj(load2, mode, pn_Load_res);
+ set_store(load_mem2);
+
+ return (complex_value) { load_res, load_res2 };
+}
+
+static complex_value complex_reference_to_firm(const reference_expression_t *ref)
+{
+ dbg_info *const dbgi = get_dbg_info(&ref->base.pos);
+ entity_t *const entity = ref->entity;
+ assert(is_declaration(entity));
+
+ switch ((declaration_kind_t)entity->declaration.kind) {
+ case DECLARATION_KIND_LOCAL_VARIABLE:
+ case DECLARATION_KIND_PARAMETER:
+ return read_localvar_complex(dbgi, entity);
+ default: {
+ ir_node *const addr = reference_addr(ref);
+ return complex_deref_address(dbgi, entity->declaration.type, addr, cons_none);
+ }
+ }
+}
+
+static complex_value complex_select_to_firm(const select_expression_t *select)
+{
+ dbg_info *const dbgi = get_dbg_info(&select->base.pos);
+ ir_node *const addr = select_addr(select);
+ type_t *const type = skip_typeref(select->base.type);
+ return complex_deref_address(dbgi, type, addr, cons_none);
+}
+
+static complex_value complex_array_access_to_firm(
+ const array_access_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+ ir_node *addr = array_access_addr(expression);
+ type_t *type = skip_typeref(expression->base.type);
+ assert(is_type_complex(type));
+ return complex_deref_address(dbgi, type, addr, cons_none);
+}
+
+static complex_value get_complex_from_lvalue(const expression_t *expression,
+ ir_node *addr)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->base.pos);
+
+ if (expression->kind == EXPR_REFERENCE) {
+ const reference_expression_t *ref = &expression->reference;
+
+ entity_t *entity = ref->entity;
+ assert(entity->kind == ENTITY_VARIABLE
+ || entity->kind == ENTITY_PARAMETER);
+ assert(entity->declaration.kind != DECLARATION_KIND_UNKNOWN);
+ if (entity->declaration.kind == DECLARATION_KIND_LOCAL_VARIABLE ||
+ entity->declaration.kind == DECLARATION_KIND_PARAMETER) {
+ return read_localvar_complex(dbgi, entity);
+ }
+ }
+
+ assert(addr != NULL);
+ return complex_deref_address(dbgi, expression->base.type, addr, cons_none);
+}
+
+static complex_value complex_cast_to_firm(const unary_expression_t *expression)
+{
+ const expression_t *const value = expression->value;
+ dbg_info *const dbgi = get_dbg_info(&expression->base.pos);
+ 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_value cvalue = expression_to_complex(value);
+ return complex_conv(dbgi, cvalue, mode);
+ } else {
+ ir_node *const value_node = expression_to_value(value);
+ ir_node *const zero = new_Const(get_mode_null(mode));
+ ir_node *const casted = create_conv(dbgi, value_node, mode);
+ return (complex_value) { casted, zero };
+ }
+}
+
+static complex_value complex_literal_to_firm(const literal_expression_t *literal)
+{
+ type_t *type = skip_typeref(literal->base.type);
+ ir_mode *mode = get_complex_mode_storage(type);
+ ir_node *litvalue = literal_to_firm_(literal, mode);
+ ir_node *zero = new_Const(get_mode_null(mode));
+ return (complex_value) { zero, litvalue };
+}
+
+typedef complex_value (*new_complex_binop)(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode);
+
+static complex_value new_complex_add(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ return (complex_value) {
+ new_d_Add(dbgi, left.real, right.real, mode),
+ new_d_Add(dbgi, left.imag, right.imag, mode)
+ };
+}
+
+static complex_value new_complex_sub(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ return (complex_value) {
+ new_d_Sub(dbgi, left.real, right.real, mode),
+ new_d_Sub(dbgi, left.imag, right.imag, mode)
+ };
+}
+
+static complex_value new_complex_mul(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ ir_node *const op1 = new_d_Mul(dbgi, left.real, right.real, mode);
+ ir_node *const op2 = new_d_Mul(dbgi, left.imag, right.imag, mode);
+ ir_node *const op3 = new_d_Mul(dbgi, left.real, right.imag, mode);
+ ir_node *const op4 = new_d_Mul(dbgi, left.imag, right.real, mode);
+ return (complex_value) {
+ new_d_Sub(dbgi, op1, op2, mode),
+ new_d_Add(dbgi, op3, op4, mode)
+ };
+}
+
+static complex_value new_complex_div(dbg_info *dbgi, complex_value left,
+ complex_value right, ir_mode *mode)
+{
+ ir_node *const op1 = new_d_Mul(dbgi, left.real, right.real, mode);
+ ir_node *const op2 = new_d_Mul(dbgi, left.imag, right.imag, mode);
+ ir_node *const op3 = new_d_Mul(dbgi, left.imag, right.real, mode);
+ ir_node *const op4 = new_d_Mul(dbgi, left.real, right.imag, mode);
+ ir_node *const op5 = new_d_Mul(dbgi, right.real, right.real, mode);
+ ir_node *const op6 = new_d_Mul(dbgi, right.imag, right.imag, mode);
+ ir_node *const real_dividend = new_d_Add(dbgi, op1, op2, mode);
+ ir_node *const real_divisor = new_d_Add(dbgi, op5, op6, mode);
+ ir_node *const imag_dividend = new_d_Sub(dbgi, op3, op4, mode);
+ ir_node *const imag_divisor = new_d_Add(dbgi, op5, op6, mode);
+ return (complex_value) {
+ create_div(dbgi, real_dividend, real_divisor, mode),
+ create_div(dbgi, imag_dividend, imag_divisor, mode)
+ };
+}
+
+typedef complex_value (*new_complex_unop)(dbg_info *dbgi, complex_value value,
+ ir_mode *mode);
+
+static complex_value new_complex_increment(dbg_info *dbgi, complex_value value,
+ ir_mode *mode)
+{
+ ir_node *one = new_Const(get_mode_one(mode));
+ return (complex_value) {
+ new_d_Add(dbgi, value.real, one, mode),
+ value.imag
+ };
+}
+
+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;