implement support for complex types
authorMatthias Braun <matze@braunis.de>
Mon, 10 Dec 2012 15:35:47 +0000 (16:35 +0100)
committerMatthias Braun <matze@braunis.de>
Mon, 10 Dec 2012 22:50:15 +0000 (23:50 +0100)
Not tested that much yet, and support for statement expressions is still
missing.

ast.c
ast2firm.c
ast_t.h
libfirm
parser.c
type.c
type_t.h

diff --git a/ast.c b/ast.c
index c38c2b0..eda9b70 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -137,6 +137,8 @@ static unsigned get_expression_precedence(expression_kind_t kind)
                [EXPR_UNARY_DELETE]               = PREC_UNARY,
                [EXPR_UNARY_DELETE_ARRAY]         = PREC_UNARY,
                [EXPR_UNARY_THROW]                = PREC_ASSIGNMENT,
+               [EXPR_UNARY_IMAG]                 = PREC_UNARY,
+               [EXPR_UNARY_REAL]                 = PREC_UNARY,
 
                [EXPR_BINARY_ADD]                 = PREC_ADDITIVE,
                [EXPR_BINARY_SUB]                 = PREC_ADDITIVE,
@@ -356,16 +358,18 @@ static void print_unary_expression(const unary_expression_t *unexpr)
 {
        unsigned prec = get_expression_precedence(unexpr->base.kind);
        switch (unexpr->base.kind) {
-       case EXPR_UNARY_NEGATE:           print_char  ('-' ); break;
-       case EXPR_UNARY_PLUS:             print_char  ('+' ); break;
-       case EXPR_UNARY_NOT:              print_char  ('!' ); break;
-       case EXPR_UNARY_COMPLEMENT:       print_char  ('~' ); break;
-       case EXPR_UNARY_PREFIX_INCREMENT: print_string("++"); break;
-       case EXPR_UNARY_PREFIX_DECREMENT: print_string("--"); break;
-       case EXPR_UNARY_DEREFERENCE:      print_char  ('*' ); break;
-       case EXPR_UNARY_TAKE_ADDRESS:     print_char  ('&' ); break;
-       case EXPR_UNARY_DELETE:           print_string("delete "); break;
+       case EXPR_UNARY_NEGATE:           print_char  ('-' );         break;
+       case EXPR_UNARY_PLUS:             print_char  ('+' );         break;
+       case EXPR_UNARY_NOT:              print_char  ('!' );         break;
+       case EXPR_UNARY_COMPLEMENT:       print_char  ('~' );         break;
+       case EXPR_UNARY_PREFIX_INCREMENT: print_string("++");         break;
+       case EXPR_UNARY_PREFIX_DECREMENT: print_string("--");         break;
+       case EXPR_UNARY_DEREFERENCE:      print_char  ('*' );         break;
+       case EXPR_UNARY_TAKE_ADDRESS:     print_char  ('&' );         break;
+       case EXPR_UNARY_DELETE:           print_string("delete ");    break;
        case EXPR_UNARY_DELETE_ARRAY:     print_string("delete [] "); break;
+       case EXPR_UNARY_REAL:             print_string("__real__ ");  break;
+       case EXPR_UNARY_IMAG:             print_string("__imag__ ");  break;
 
        case EXPR_UNARY_POSTFIX_INCREMENT:
                print_expression_prec(unexpr->value, prec);
@@ -385,7 +389,6 @@ static void print_unary_expression(const unary_expression_t *unexpr)
                print_assignment_expression(unexpr->value);
                print_char(')');
                return;
-
        case EXPR_UNARY_THROW:
                if (unexpr->value == NULL) {
                        print_string("throw");
@@ -1839,9 +1842,18 @@ check_type:
        case EXPR_UNARY_NOT:
                return is_constant_expression(expression->unary.value);
 
+       case EXPR_UNARY_IMAG:
+       case EXPR_UNARY_REAL: {
+               type_t *type = skip_typeref(expression->base.type);
+               if (!is_type_valid(type))
+                       return EXPR_CLASS_ERROR;
+               return is_constant_expression(expression->unary.value);
+       }
+
+
        case EXPR_UNARY_CAST: {
                type_t *const type = skip_typeref(expression->base.type);
-               if (is_type_scalar(type))
+               if (is_type_scalar(type) || is_type_complex(type))
                        return is_constant_expression(expression->unary.value);
                if (!is_type_valid(type))
                        return EXPR_CLASS_ERROR;
index 0decc0f..2fdf3fc 100644 (file)
@@ -59,6 +59,16 @@ struct trampoline_region {
        ir_entity        *region;      /**< created region for the trampoline */
 };
 
+typedef struct complex_value {
+       ir_node *real;
+       ir_node *imag;
+} complex_value;
+
+typedef struct complex_constant {
+       ir_tarval *real;
+       ir_tarval *imag;
+} complex_constant;
+
 fp_model_t firm_fp_model = fp_model_precise;
 
 static const backend_params *be_params;
@@ -195,6 +205,7 @@ ir_mode *atomic_modes[ATOMIC_TYPE_LAST+1];
 
 static ir_node *expression_to_control_flow(expression_t const *expr, jump_target *true_target, jump_target *false_target);
 static ir_node *expression_to_value(expression_t const *expr);
+static complex_value expression_to_complex(const expression_t *expression);
 
 static unsigned decide_modulo_shift(unsigned type_size)
 {
@@ -312,6 +323,7 @@ static ir_type *create_complex_type(atomic_type_kind_t akind,
                elemsize += align - (elemsize % align);
        }
        set_type_size_bytes(irtype, n_elements * elemsize);
+       set_type_state(irtype, layout_fixed);
 
        return irtype;
 }
@@ -738,7 +750,7 @@ static ir_mode *get_ir_mode_storage(type_t *type)
        type = skip_typeref(type);
 
        /* Firm doesn't report a mode for arrays and structs/unions. */
-       if (!is_type_scalar(type)) {
+       if (!is_type_scalar(type) || is_type_complex(type)) {
                return mode_P_data;
        }
 
@@ -748,6 +760,15 @@ static ir_mode *get_ir_mode_storage(type_t *type)
        return mode;
 }
 
+static ir_mode *get_complex_mode_storage(type_t *type)
+{
+       assert(is_type_complex(skip_typeref(type)));
+       ir_type *const irtype = get_ir_type(type);
+       ir_type *const etype  = get_array_element_type(irtype);
+       ir_mode *const mode   = get_type_mode(etype);
+       return mode;
+}
+
 /*
  * get arithmetic mode for a type. This is different from get_ir_mode_storage,
  * int that it returns bigger modes for floating point on some platforms
@@ -763,6 +784,16 @@ static ir_mode *get_ir_mode_arithmetic(type_t *type)
        return mode;
 }
 
+static ir_mode *get_complex_mode_arithmetic(type_t *type)
+{
+       ir_mode *mode = get_complex_mode_storage(type);
+       if (mode_is_float(mode) && mode_float_arithmetic != NULL) {
+               return mode_float_arithmetic;
+       }
+
+       return mode;
+}
+
 /**
  * Return a node representing the size of a type.
  */
@@ -1173,7 +1204,7 @@ finish:;
 
 static bool try_create_integer(literal_expression_t *literal, type_t *type)
 {
-       assert(type->kind == TYPE_ATOMIC);
+       assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX);
        atomic_type_kind_t akind = type->atomic.akind;
 
        ir_mode    *const mode = atomic_modes[akind];
@@ -1230,10 +1261,9 @@ finished:
 /**
  * Creates a Const node representing a constant.
  */
-static ir_node *literal_to_firm(const literal_expression_t *literal)
+static ir_node *literal_to_firm_(const literal_expression_t *literal,
+                                 ir_mode *mode)
 {
-       type_t     *type   = skip_typeref(literal->base.type);
-       ir_mode    *mode   = get_ir_mode_storage(type);
        const char *string = literal->value.begin;
        size_t      size   = literal->value.size;
        ir_tarval  *tv;
@@ -1266,6 +1296,13 @@ static ir_node *literal_to_firm(const literal_expression_t *literal)
        return new_d_Const(dbgi, tv);
 }
 
+static ir_node *literal_to_firm(const literal_expression_t *literal)
+{
+       type_t  *type         = skip_typeref(literal->base.type);
+       ir_mode *mode_storage = get_ir_mode_storage(type);
+       return literal_to_firm_(literal, mode_storage);
+}
+
 /**
  * Creates a Const node representing a character constant.
  */
@@ -1648,6 +1685,9 @@ static ir_node *process_builtin_call(const call_expression_t *call)
        panic("invalid builtin");
 }
 
+static ir_node *complex_to_memory(dbg_info *dbgi, type_t *type,
+                                  complex_value value);
+
 /**
  * Transform a call expression.
  * Handles some special cases, like alloca() calls, which must be resolved
@@ -1730,9 +1770,20 @@ static ir_node *call_expression_to_firm(const call_expression_t *const call)
        const call_argument_t *argument = call->arguments;
        for (int n = 0; n < n_parameters; ++n) {
                expression_t *expression = argument->expression;
-               ir_node      *arg_node   = expression_to_value(expression);
                type_t       *arg_type   = skip_typeref(expression->base.type);
-               in[n] = conv_to_storage_type(dbgi, arg_node, arg_type);
+               ir_node      *arg_node;
+               if (is_type_complex(arg_type)) {
+                       complex_value value = expression_to_complex(expression);
+                       arg_node = complex_to_memory(dbgi, arg_type, value);
+               } else {
+                       arg_node = expression_to_value(expression);
+                       if (!is_type_compound(arg_type)) {
+                               ir_mode *const mode = get_ir_mode_storage(arg_type);
+                               arg_node = create_conv(dbgi, arg_node, mode);
+                       }
+               }
+
+               in[n] = arg_node;
 
                argument = argument->next;
        }
@@ -1770,7 +1821,7 @@ static ir_node *call_expression_to_firm(const call_expression_t *const call)
                if (!is_type_void(return_type)) {
                        ir_node *const resproj = new_Proj(node, mode_T, pn_Call_T_result);
                        ir_mode *const mode    = get_ir_mode_storage(return_type);
-                       result = new_Proj(resproj, mode, 0);
+                       result                 = new_Proj(resproj, mode, 0);
                }
        }
 
@@ -1797,7 +1848,7 @@ static void assign_value(dbg_info *dbgi, ir_node *addr, type_t *type,
 
        ir_node *memory = get_store();
 
-       if (is_type_scalar(type)) {
+       if (is_type_scalar(type) && !is_type_complex(type)) {
                ir_cons_flags flags = type->base.qualifiers & TYPE_QUALIFIER_VOLATILE
                                      ? cons_volatile : cons_none;
                ir_node  *store     = new_d_Store(dbgi, memory, addr, value, flags);
@@ -2253,6 +2304,15 @@ static ir_node *adjust_for_pointer_arithmetic(dbg_info *dbgi,
        return mul;
 }
 
+static ir_node *create_div(dbg_info *dbgi, ir_node *left, ir_node *right,
+                           ir_mode *mode)
+{
+       ir_node *pin = new_Pin(new_NoMem());
+       ir_node *op  = new_d_Div(dbgi, pin, left, right, mode,
+                                op_pin_state_floats);
+       return new_d_Proj(dbgi, op, mode, pn_Div_res);
+}
+
 static ir_node *create_op(binary_expression_t const *const expr, ir_node *left, ir_node *right)
 {
        ir_mode                *mode;
@@ -2323,6 +2383,9 @@ normal_node:
        case EXPR_BINARY_MUL_ASSIGN:
        case EXPR_BINARY_MUL:
                return new_d_Mul(dbgi, left, right, mode);
+       case EXPR_BINARY_DIV:
+       case EXPR_BINARY_DIV_ASSIGN:
+               return create_div(dbgi, left, right, mode);
        case EXPR_BINARY_BITWISE_AND:
        case EXPR_BINARY_BITWISE_AND_ASSIGN:
                return new_d_And(dbgi, left, right, mode);
@@ -2342,14 +2405,6 @@ normal_node:
                } else {
                        return new_d_Shr(dbgi, left, right, mode);
                }
-       case EXPR_BINARY_DIV:
-       case EXPR_BINARY_DIV_ASSIGN: {
-               ir_node *pin = new_Pin(new_NoMem());
-               ir_node *op  = new_d_Div(dbgi, pin, left, right, mode,
-                                        op_pin_state_floats);
-               ir_node *res = new_d_Proj(dbgi, op, mode, pn_Div_res);
-               return res;
-       }
        case EXPR_BINARY_MOD:
        case EXPR_BINARY_MOD_ASSIGN: {
                ir_node *pin = new_Pin(new_NoMem());
@@ -2481,9 +2536,21 @@ static ir_node *assign_expression_to_firm(binary_expression_t const *const expr)
        return set_value_for_expression_addr(expr->left, right, addr);
 }
 
+/** evaluate an expression and discard the result, but still produce the
+ * side-effects. */
+static void evaluate_expression_discard_result(const expression_t *expression)
+{
+       type_t *type = skip_typeref(expression->base.type);
+       if (is_type_complex(type)) {
+               expression_to_complex(expression);
+       } else {
+               expression_to_value(expression);
+       }
+}
+
 static ir_node *comma_expression_to_firm(binary_expression_t const *const expr)
 {
-       expression_to_value(expr->left);
+       evaluate_expression_discard_result(expr->left);
        return expression_to_value(expr->right);
 }
 
@@ -2720,6 +2787,38 @@ ir_tarval *fold_constant_to_tarval(const expression_t *expression)
        return get_Const_tarval(cnst);
 }
 
+static complex_constant fold_complex_constant(const expression_t *expression)
+{
+       assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT);
+
+       bool constant_folding_old = constant_folding;
+       constant_folding = true;
+       int old_optimize         = get_optimize();
+       int old_constant_folding = get_opt_constant_folding();
+       set_optimize(1);
+       set_opt_constant_folding(1);
+
+       init_ir_types();
+
+       PUSH_IRG(get_const_code_irg());
+       complex_value value = expression_to_complex(expression);
+       POP_IRG();
+
+       set_optimize(old_optimize);
+       set_opt_constant_folding(old_constant_folding);
+
+       if (!is_Const(value.real) || !is_Const(value.imag)) {
+               panic("couldn't fold constant");
+       }
+
+       constant_folding = constant_folding_old;
+
+       return (complex_constant) {
+               get_Const_tarval(value.real),
+               get_Const_tarval(value.imag)
+       };
+}
+
 /* this function is only used in parser.c, but it relies on libfirm functionality */
 bool constant_is_negative(const expression_t *expression)
 {
@@ -2739,8 +2838,14 @@ long fold_constant_to_int(const expression_t *expression)
 
 bool fold_constant_to_bool(const expression_t *expression)
 {
-       ir_tarval *tv = fold_constant_to_tarval(expression);
-       return !tarval_is_null(tv);
+       type_t *type = skip_typeref(expression->base.type);
+       if (is_type_complex(type)) {
+               complex_constant tvs = fold_complex_constant(expression);
+               return !tarval_is_null(tvs.real) || !tarval_is_null(tvs.imag);
+       } else {
+               ir_tarval *tv = fold_constant_to_tarval(expression);
+               return !tarval_is_null(tv);
+       }
 }
 
 static ir_node *conditional_to_firm(const conditional_expression_t *expression)
@@ -3107,6 +3212,7 @@ static ir_node *expression_to_value(expression_t const *const expr)
                assert(!expr->base.transformed);
                ((expression_t*)expr)->base.transformed = true;
        }
+       assert(!is_type_complex(skip_typeref(expr->base.type)));
 #endif
 
        switch (expr->kind) {
@@ -3172,6 +3278,15 @@ incdec:
                return incdec_to_firm(&expr->unary, inc, pre);
        }
 
+       case EXPR_UNARY_IMAG: {
+               complex_value irvalue = expression_to_complex(expr->unary.value);
+               return irvalue.imag;
+       }
+       case EXPR_UNARY_REAL: {
+               complex_value irvalue = expression_to_complex(expr->unary.value);
+               return irvalue.real;
+       }
+
        case EXPR_ALIGNOF:                    return alignof_to_firm(                 &expr->typeprop);
        case EXPR_ARRAY_ACCESS:               return array_access_to_firm(            &expr->array_access);
        case EXPR_BINARY_ASSIGN:              return assign_expression_to_firm(       &expr->binary);
@@ -3214,6 +3329,14 @@ incdec:
        panic("invalid expression");
 }
 
+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);
+
 /**
  * create a short-circuit expression evaluation that tries to construct
  * efficient control flow structures for &&, || and ! expressions
@@ -3244,13 +3367,14 @@ static ir_node *expression_to_control_flow(expression_t const *const expr, jump_
        }
 
        case EXPR_BINARY_COMMA:
-               expression_to_value(expr->binary.left);
+               evaluate_expression_discard_result(expr->binary.left);
                return expression_to_control_flow(expr->binary.right, true_target, false_target);
 
                ir_node    *val;
                ir_node    *left;
                ir_node    *right;
                ir_relation relation;
+
        case EXPR_BINARY_EQUAL:
        case EXPR_BINARY_GREATER:
        case EXPR_BINARY_GREATEREQUAL:
@@ -3263,13 +3387,20 @@ static ir_node *expression_to_control_flow(expression_t const *const expr, jump_
        case EXPR_BINARY_LESS:
        case EXPR_BINARY_LESSEQUAL:
        case EXPR_BINARY_NOTEQUAL: {
+               type_t *const type = skip_typeref(expr->binary.left->base.type);
+               relation = get_relation(expr->kind);
+               if (is_type_complex(type)) {
+                       complex_equality_evaluation(&expr->binary, true_target,
+                                                   false_target, relation);
+                       /* TODO return something sensible */
+                       return NULL;
+               }
+
                dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
-               type_t   *const type = skip_typeref(expr->binary.left->base.type);
                ir_mode  *const mode = get_ir_mode_arithmetic(type);
                val      = NULL;
                left     = create_conv(dbgi, expression_to_value(expr->binary.left),  mode);
                right    = create_conv(dbgi, expression_to_value(expr->binary.right), mode);
-               relation = get_relation(expr->kind);
                goto make_cmp;
        }
 
@@ -3279,8 +3410,13 @@ static ir_node *expression_to_control_flow(expression_t const *const expr, jump_
                        return NULL;
                } else {
        default:;
+                       type_t *const type = skip_typeref(expr->base.type);
+                       if (is_type_complex(type)) {
+                               create_complex_condition_evaluation(expr, true_target, false_target);
+                               return NULL;
+                       }
+
                        dbg_info *const dbgi = get_dbg_info(&expr->base.pos);
-                       type_t   *const type = skip_typeref(expr->base.type);
                        ir_mode  *const mode = get_ir_mode_arithmetic(type);
                        val      = create_conv(dbgi, expression_to_value(expr), mode);
                        left     = val;
@@ -3293,6 +3429,606 @@ make_cmp:
        }
 }
 
+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  *irg       = current_ir_graph;
+       ir_type   *irtype    = get_ir_type(type);
+       ir_node   *mem       = get_store();
+       ir_node   *nomem     = get_irg_no_mem(irg);
+       ir_mode   *mode      = get_complex_mode_storage(type);
+       ir_node   *real      = create_conv(dbgi, value.real, mode);
+       ir_node   *imag      = create_conv(dbgi, value.imag, mode);
+       ir_node   *storer    = new_d_Store(dbgi, mem, addr, real, cons_floats);
+       ir_node   *memr      = new_Proj(storer, mode_M, pn_Store_M);
+       set_store(memr);
+       ir_node   *mem2      = get_store();
+       ir_mode   *mode_uint = atomic_modes[ATOMIC_TYPE_UINT];
+       ir_node   *one       = new_Const(get_mode_one(mode_uint));
+       ir_node   *in[1]     = { one };
+       ir_entity *arrent    = get_array_element_entity(irtype);
+       ir_node   *addri     = new_d_Sel(dbgi, nomem, addr, 1, in, arrent);
+       ir_node   *storei    = new_d_Store(dbgi, mem2, addri, imag, cons_floats);
+       ir_node   *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  *irg         = current_ir_graph;
+       ir_type   *frame_type  = get_irg_frame_type(irg);
+       ident     *id          = id_unique("cmplex_tmp.%u");
+       ir_type   *irtype      = get_ir_type(type);
+       ir_entity *tmp_storage = new_entity(frame_type, id, irtype);
+       set_entity_compiler_generated(tmp_storage, 1);
+       ir_node   *frame       = get_irg_frame(irg);
+       ir_node   *nomem       = get_irg_no_mem(irg);
+       ir_node   *addr        = new_simpleSel(nomem, frame, tmp_storage);
+       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);
+       set_store(load_mem);
+
+       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 mem2      = get_store();
+       ir_node   *const load2     = new_d_Load(dbgi, mem2, 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 *dbgi = get_dbg_info(&select->base.pos);
+       ir_node  *addr = select_addr(select);
+       type_t   *type = skip_typeref(select->base.type);
+       assert(is_type_complex(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 *value     = expression->value;
+       dbg_info           *dbgi      = get_dbg_info(&expression->base.pos);
+       type_t             *from_type = skip_typeref(value->base.type);
+       type_t             *to_type   = skip_typeref(expression->base.type);
+       ir_mode            *mode      = get_complex_mode_storage(to_type);
+
+       assert(is_type_complex(to_type));
+
+       if (is_type_complex(from_type)) {
+               complex_value cvalue = expression_to_complex(value);
+               return complex_conv(dbgi, cvalue, mode);
+       } else {
+               ir_node *value_node = expression_to_value(value);
+               ir_node *zero       = new_Const(get_mode_null(mode));
+               ir_node *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 *type = skip_typeref(expression->base.type);
+       assert(is_type_complex(type));
+
+       ir_mode  *mode = get_complex_mode_storage(type);
+       ir_node  *real = create_conv(dbgi, value.real, mode);
+       ir_node  *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 create_complex_condition_evaluation(
+       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);
+       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)
+{
+       /* 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);
+       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
+                       = create_complex_condition_evaluation(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);
+
+       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;
+               }
+               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);
+               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);
+               } else {
+                       val = false_val;
+               }
+       }
+
+       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;
+       }
+       return val;
+}
+
+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: {
+               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_LITERAL_CASES:
+               return complex_literal_to_firm(&expression->literal);
+       case EXPR_CALL:
+               return complex_call_to_firm(&expression->call);
+       case EXPR_CONDITIONAL:
+               return complex_conditional_to_firm(&expression->conditional);
+
+       default:
+               break;
+       }
+       panic("complex expression not implemented yet");
+}
+
+
+
 static void create_variable_entity(entity_t *variable,
                                    declaration_kind_t declaration_kind,
                                    ir_type *parent_type)
@@ -3588,6 +4324,17 @@ static ir_initializer_t *create_ir_initializer_value(
                        return create_ir_initializer(expr->compound_literal.initializer,
                                                     type);
                }
+       } else if (is_type_complex(type)) {
+               complex_value     const value     = expression_to_complex(expr);
+               ir_mode          *const mode      = get_complex_mode_storage(type);
+               ir_node          *const real      = create_conv(NULL, value.real, mode);
+               ir_node          *const imag      = create_conv(NULL, value.imag, mode);
+               ir_initializer_t *const res       = create_initializer_compound(2);
+               ir_initializer_t *const init_real = create_initializer_const(real);
+               ir_initializer_t *const init_imag = create_initializer_const(imag);
+               set_initializer_compound_value(res, 0, init_real);
+               set_initializer_compound_value(res, 1, init_imag);
+               return res;
        }
 
        ir_node *value = expression_to_value(expr);
@@ -3956,7 +4703,31 @@ static void create_variable_initializer(entity_t *entity)
                expression_t *      value     = initializer->value.value;
                type_t       *const init_type = skip_typeref(value->base.type);
 
-               if (!is_type_scalar(init_type)) {
+               if (is_type_complex(init_type)) {
+                       complex_value nodes = expression_to_complex(value);
+                       dbg_info     *dbgi  = get_dbg_info(&entity->base.pos);
+                       ir_mode      *mode  = get_complex_mode_storage(init_type);
+                       ir_node      *real  = create_conv(dbgi, nodes.real, mode);
+                       ir_node      *imag  = create_conv(dbgi, nodes.imag, mode);
+                       if (declaration_kind == DECLARATION_KIND_LOCAL_VARIABLE) {
+                               set_value(entity->variable.v.value_number, real);
+                               set_value(entity->variable.v.value_number+1, imag);
+                       } else {
+                               assert(declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE);
+                               ir_entity *irentity = entity->variable.v.entity;
+                               if (tq & TYPE_QUALIFIER_CONST
+                                               && get_entity_owner(irentity) != get_tls_type()) {
+                                       add_entity_linkage(irentity, IR_LINKAGE_CONSTANT);
+                               }
+                               ir_initializer_t *initializer = create_initializer_compound(2);
+                               ir_initializer_t *reali = create_initializer_const(real);
+                               set_initializer_compound_value(initializer, 0, reali);
+                               ir_initializer_t *imagi = create_initializer_const(imag);
+                               set_initializer_compound_value(initializer, 1, imagi);
+                               set_entity_initializer(irentity, initializer);
+                       }
+                       return;
+               } else if (!is_type_scalar(init_type)) {
                        if (value->kind != EXPR_COMPOUND_LITERAL)
                                panic("expected non-scalar initializer to be a compound literal");
                        initializer = value->compound_literal.initializer;
@@ -4037,7 +4808,8 @@ static bool var_needs_entity(variable_t const *const var)
        if (var->address_taken)
                return true;
        type_t *const type = skip_typeref(var->base.type);
-       return !is_type_scalar(type) || type->base.qualifiers & TYPE_QUALIFIER_VOLATILE;
+       return (!is_type_scalar(type) && !is_type_complex(type))
+            || type->base.qualifiers & TYPE_QUALIFIER_VOLATILE;
 }
 
 /**
@@ -4053,6 +4825,8 @@ static void create_local_variable(entity_t *entity)
                entity->variable.v.value_number = next_value_number_function;
                set_irg_loc_description(current_ir_graph, next_value_number_function, entity);
                ++next_value_number_function;
+               if (is_type_complex(skip_typeref(entity->declaration.type)))
+                       ++next_value_number_function;
                return;
        }
 
@@ -4104,8 +4878,6 @@ static void create_local_static_variable(entity_t *entity)
        POP_IRG();
 }
 
-
-
 static ir_node *return_statement_to_firm(return_statement_t *statement)
 {
        if (!currently_reachable())
@@ -4113,21 +4885,35 @@ static ir_node *return_statement_to_firm(return_statement_t *statement)
 
        dbg_info *const dbgi = get_dbg_info(&statement->base.pos);
        type_t   *const type = skip_typeref(current_function_entity->declaration.type->function.return_type);
-       ir_node  *      res  = statement->value ? expression_to_value(statement->value) : NULL;
 
+       ir_node *in[1];
        int in_len;
-       if (!is_type_void(type)) {
-               if (res) {
-                       res = conv_to_storage_type(dbgi, res, type);
+       if (is_type_void(type)) {
+               /* just create the side effects, don't return anything */
+               if (statement->value)
+                       evaluate_expression_discard_result(statement->value);
+               in[0]  = NULL;
+               in_len = 0;
+       } else if (is_type_complex(type)) {
+               if (statement->value) {
+                       complex_value value = expression_to_complex(statement->value);
+                       in[0] = complex_to_memory(dbgi, type, value);
                } else {
-                       res = new_Unknown(get_ir_mode_storage(type));
+                       in[0] = new_Unknown(mode_P_data);
                }
                in_len = 1;
        } else {
-               in_len = 0;
+               ir_mode *const mode = get_ir_mode_storage(type);
+               if (statement->value) {
+                       ir_node *value = expression_to_value(statement->value);
+                       value = conv_to_storage_type(dbgi, value, type);
+                       in[0] = create_conv(dbgi, value, mode);
+               } else {
+                       in[0] = new_Unknown(mode);
+               }
+               in_len = 1;
        }
 
-       ir_node *const in[1] = { res };
        ir_node *const store = get_store();
        ir_node *const ret   = new_d_Return(dbgi, store, in_len, in);
 
@@ -4143,7 +4929,14 @@ static ir_node *expression_statement_to_firm(expression_statement_t *statement)
        if (!currently_reachable())
                return NULL;
 
-       return expression_to_value(statement->expression);
+       expression_t *expression = statement->expression;
+       type_t       *type       = skip_typeref(expression->base.type);
+       if (is_type_complex(type)) {
+               expression_to_complex(expression);
+               return NULL; /* TODO */
+       } else {
+               return expression_to_value(statement->expression);
+       }
 }
 
 static void create_local_declarations(entity_t*);
@@ -4863,8 +5656,11 @@ static int count_local_variables(const entity_t *entity,
        entity_t const *const end = last != NULL ? last->base.next : NULL;
        for (; entity != end; entity = entity->base.next) {
                if ((entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER) &&
-                   !var_needs_entity(&entity->variable))
+                   !var_needs_entity(&entity->variable)) {
                        ++count;
+                       if (is_type_complex(skip_typeref(entity->declaration.type)))
+                               ++count;
+               }
        }
        return count;
 }
@@ -4929,8 +5725,6 @@ static void initialize_function_parameters(entity_t *entity)
                function_irtype = get_ir_type(entity->declaration.type);
        }
 
-
-
        entity_t *parameter = entity->function.parameters.entities;
        for ( ; parameter != NULL; parameter = parameter->base.next, ++n) {
                if (parameter->kind != ENTITY_PARAMETER)
@@ -4947,21 +5741,38 @@ static void initialize_function_parameters(entity_t *entity)
                                = new_d_parameter_entity(frame_type, n, param_irtype, dbgi);
                        parameter->declaration.kind  = DECLARATION_KIND_PARAMETER_ENTITY;
                        parameter->variable.v.entity = param;
-                       continue;
+               } else if (is_type_complex(type)) {
+                       ir_type   *frame_type = get_irg_frame_type(irg);
+                       ir_entity *param
+                               = new_d_parameter_entity(frame_type, n, param_irtype, dbgi);
+                       ir_node   *nomem = get_irg_no_mem(irg);
+                       ir_node   *frame = get_irg_frame(irg);
+                       ir_node   *addr  = new_simpleSel(nomem, frame, param);
+                       complex_value value = complex_deref_address(NULL, type, addr, cons_floats);
+
+                       parameter->declaration.kind        = DECLARATION_KIND_PARAMETER;
+                       parameter->variable.v.value_number = next_value_number_function;
+                       set_irg_loc_description(irg, next_value_number_function,
+                                                                       parameter);
+                       set_irg_loc_description(irg, next_value_number_function+1,
+                                                                       parameter);
+                       set_value(next_value_number_function, value.real);
+                       set_value(next_value_number_function+1, value.imag);
+                       next_value_number_function += 2;
+               } else {
+                       ir_mode *param_mode = get_type_mode(param_irtype);
+                       long     pn         = n;
+                       ir_node *value      = new_rd_Proj(dbgi, args, param_mode, pn);
+                       value = conv_to_storage_type(dbgi, value, type);
+
+                       parameter->declaration.kind        = DECLARATION_KIND_PARAMETER;
+                       parameter->variable.v.value_number = next_value_number_function;
+                       set_irg_loc_description(irg, next_value_number_function,
+                                                                       parameter);
+                       ++next_value_number_function;
+
+                       set_value(parameter->variable.v.value_number, value);
                }
-
-               ir_mode *param_mode = get_type_mode(param_irtype);
-               long     pn         = n;
-               ir_node *value      = new_rd_Proj(dbgi, args, param_mode, pn);
-               value = conv_to_storage_type(dbgi, value, type);
-
-               parameter->declaration.kind        = DECLARATION_KIND_PARAMETER;
-               parameter->variable.v.value_number = next_value_number_function;
-               set_irg_loc_description(current_ir_graph, next_value_number_function,
-                                       parameter);
-               ++next_value_number_function;
-
-               set_value(parameter->variable.v.value_number, value);
        }
 }
 
diff --git a/ast_t.h b/ast_t.h
index 5764883..b980f90 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -106,7 +106,9 @@ typedef enum expression_kind_t {
        EXPR_UNARY_DELETE,
        EXPR_UNARY_DELETE_ARRAY,
        EXPR_UNARY_THROW,
-       EXPR_UNARY_LAST = EXPR_UNARY_THROW,
+       EXPR_UNARY_REAL,
+       EXPR_UNARY_IMAG,
+       EXPR_UNARY_LAST = EXPR_UNARY_IMAG,
 
        EXPR_BINARY_FIRST,
        EXPR_BINARY_ADD = EXPR_BINARY_FIRST,
@@ -212,7 +214,9 @@ typedef enum funcname_kind_t {
        case EXPR_UNARY_CAST:              \
        case EXPR_UNARY_ASSUME:            \
        case EXPR_UNARY_DELETE:            \
-       case EXPR_UNARY_DELETE_ARRAY
+       case EXPR_UNARY_DELETE_ARRAY:      \
+       case EXPR_UNARY_IMAG:              \
+       case EXPR_UNARY_REAL
 
 /**
  * unary expression with optional operand
diff --git a/libfirm b/libfirm
index d4cdf46..e0a97ca 160000 (submodule)
--- a/libfirm
+++ b/libfirm
@@ -1 +1 @@
-Subproject commit d4cdf468d3adc53fb444b1c43dec0fe844a5081e
+Subproject commit e0a97ca800ac2bc93c9e85891dfb362b39ca5bfb
index 57f8322..c9e35b6 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -273,7 +273,9 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_false:                     \
        case T_sizeof:                    \
        case T_throw:                     \
-       case T_true:
+       case T_true:                      \
+       case T___imag__:                  \
+       case T___real__:
 
 /**
  * Returns the size of a statement node.
@@ -843,13 +845,6 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
-static atomic_type_kind_t get_akind(const type_t *type)
-{
-       assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
-              || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
-       return type->atomic.akind;
-}
-
 /**
  * §6.3.1.1:2  Do integer promotion for a given type.
  *
@@ -858,7 +853,8 @@ static atomic_type_kind_t get_akind(const type_t *type)
  */
 static type_t *promote_integer(type_t *type)
 {
-       if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT))
+       atomic_type_kind_t akind = get_arithmetic_akind(type);
+       if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT))
                type = type_int;
 
        return type;
@@ -1447,6 +1443,8 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                case EXPR_UNARY_PREFIX_INCREMENT:
                case EXPR_UNARY_PREFIX_DECREMENT:
                case EXPR_UNARY_ASSUME:
+               case EXPR_UNARY_IMAG:
+               case EXPR_UNARY_REAL:
 unary:
                        mark_vars_read(expr->unary.value, lhs_ent);
                        return;
@@ -2861,11 +2859,19 @@ finish_specifiers:
        specifiers->attributes = parse_attributes(specifiers->attributes);
 
        if (type == NULL || (saw_error && type_specifiers != 0)) {
+               position_t const* const pos = &specifiers->pos;
                atomic_type_kind_t atomic_type;
 
                /* match valid basic types */
-               switch (type_specifiers) {
+               switch (type_specifiers & ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
                case SPECIFIER_VOID:
+                       if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
+                               if (type_specifiers & SPECIFIER_COMPLEX)
+                                       errorf(pos, "_Complex specifier is invalid for void");
+                               if (type_specifiers & SPECIFIER_IMAGINARY)
+                                       errorf(pos, "_Imaginary specifier is invalid for void");
+                               type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY);
+                       }
                        atomic_type = ATOMIC_TYPE_VOID;
                        break;
                case SPECIFIER_WCHAR_T:
@@ -2981,23 +2987,17 @@ warn_about_long_long:
                        atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
                        break;
                case SPECIFIER_BOOL:
+                       if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
+                               if (type_specifiers & SPECIFIER_COMPLEX)
+                                       errorf(pos, "_Complex specifier is invalid for _Bool");
+                               if (type_specifiers & SPECIFIER_IMAGINARY)
+                                       errorf(pos, "_Imaginary specifier is invalid for _Bool");
+                               type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY);
+                       }
                        atomic_type = ATOMIC_TYPE_BOOL;
                        break;
-               case SPECIFIER_FLOAT | SPECIFIER_COMPLEX:
-               case SPECIFIER_FLOAT | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_FLOAT;
-                       break;
-               case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-               case SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_DOUBLE;
-                       break;
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
-                       break;
                default: {
                        /* invalid specifier combination, give an error message */
-                       position_t const* const pos = &specifiers->pos;
                        if (type_specifiers == 0) {
                                if (!saw_error) {
                                        /* ISO/IEC 14882:1998(E) §C.1.5:4 */
@@ -5686,18 +5686,32 @@ static void check_integer_suffix(expression_t *const expr, char const *const suf
 {
        unsigned     spec = SPECIFIER_NONE;
        char const  *c    = suffix;
-       for (;;) {
+       while (*c != '\0') {
                specifiers_t add;
-               if (*c == 'L' || *c == 'l') {
+               switch (*c) {
+               case 'L':
+               case 'l':
                        add = SPECIFIER_LONG;
                        if (*c == c[1]) {
                                add |= SPECIFIER_LONG_LONG;
                                ++c;
                        }
-               } else if (*c == 'U' || *c == 'u') {
+                       break;
+               case 'u':
+               case 'U':
                        add = SPECIFIER_UNSIGNED;
-               } else {
                        break;
+               case 'i':
+               case 'I':
+               case 'j':
+               case 'J':
+                       if (!GNU_MODE)
+                               goto error;
+                       add = SPECIFIER_COMPLEX;
+                       break;
+
+               default:
+                       goto error;
                }
                ++c;
                if (spec & add)
@@ -5707,7 +5721,7 @@ static void check_integer_suffix(expression_t *const expr, char const *const suf
 
        if (*c == '\0') {
                type_t *type;
-               switch (spec) {
+               switch (spec & ~SPECIFIER_COMPLEX) {
                case SPECIFIER_NONE:                                            type = type_int;                break;
                case                      SPECIFIER_LONG:                       type = type_long;               break;
                case                      SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long;          break;
@@ -5719,6 +5733,10 @@ static void check_integer_suffix(expression_t *const expr, char const *const suf
                if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
                        warn_traditional_suffix(suffix);
                }
+               if (spec & SPECIFIER_COMPLEX) {
+                       assert(type->kind == TYPE_ATOMIC);
+                       type = make_complex_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+               }
                expr->base.type = type;
                /* Integer type depends on the size of the number and the size
                 * representable by the types. The backend/codegeneration has to
@@ -5733,16 +5751,32 @@ error:
 static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
 {
        type_t     *type;
-       char const *c    = suffix;
+       char const *c          = suffix;
+       bool        is_complex = false;
+next:
        switch (*c) {
        case 'F':
        case 'f': type = type_float;       ++c; break;
        case 'L':
        case 'l': type = type_long_double; ++c; break;
+       case 'i':
+       case 'I':
+       case 'j':
+       case 'J':
+               if (!GNU_MODE)
+                       break;
+               is_complex = true;
+               ++c;
+               goto next;
        default:  type = type_double;           break;
        }
 
        if (*c == '\0') {
+               if (is_complex) {
+                       assert(type->kind == TYPE_ATOMIC);
+                       type = make_complex_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+               }
+
                expr->base.type = type;
                if (suffix[0] != '\0') {
                        warn_traditional_suffix(suffix);
@@ -6147,7 +6181,8 @@ static bool semantic_cast(expression_t *cast)
        type_t     const *src_type        = skip_typeref(orig_type_right);
        position_t const *pos             = &cast->base.pos;
 
-       /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
+       /* §6.5.4 A (void) cast is explicitly permitted, more for documentation
+        * than for utility. */
        if (is_type_void(dst_type))
                return true;
 
@@ -6182,6 +6217,34 @@ static bool semantic_cast(expression_t *cast)
        return true;
 }
 
+static void semantic_complex_extract(unary_expression_t *extract)
+{
+       type_t *orig_value_type = extract->value->base.type;
+       type_t *value_type      = skip_typeref(orig_value_type);
+       if (!is_type_valid(value_type)) {
+               extract->base.type = type_error_type;
+               return;
+       }
+
+       type_t *type = value_type;
+       if (!is_type_complex(type)) {
+               if (!is_type_arithmetic(type)) {
+                       errorf(&extract->base.pos,
+                                  "%s requires an argument with complex or arithmetic type, got '%T'",
+                                  extract->base.kind == EXPR_UNARY_IMAG ? "__imag__" : "__real__",
+                                  orig_value_type);
+                       extract->base.type = type_error_type;
+                       return;
+               }
+               atomic_type_kind_t const akind = get_arithmetic_akind(type);
+               type = make_complex_type(akind, TYPE_QUALIFIER_NONE);
+               extract->value = create_implicit_cast(extract->value, type);
+       }
+       assert(type->kind == TYPE_COMPLEX);
+       type = make_atomic_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+       extract->base.type = type;
+}
+
 static expression_t *parse_compound_literal(position_t const *const pos,
                                             type_t *type)
 {
@@ -6237,6 +6300,24 @@ static expression_t *parse_cast(void)
        return cast;
 }
 
+static expression_t *parse_complex_extract_expression(void)
+{
+       expression_kind_t kind;
+       if (token.kind == T___imag__) {
+               kind = EXPR_UNARY_IMAG;
+       } else {
+               assert(token.kind == T___real__);
+               kind = EXPR_UNARY_REAL;
+       }
+       expression_t *extract = allocate_expression_zero(kind);
+       extract->base.pos = *HERE;
+       next_token();
+
+       extract->unary.value = parse_subexpression(PREC_CAST);
+       semantic_complex_extract(&extract->unary);
+       return extract;
+}
+
 /**
  * Parse a statement expression.
  */
@@ -6723,6 +6804,8 @@ static expression_t *parse_primary_expression(void)
 
        case '(':                            return parse_parenthesized_expression();
        case T___noop:                       return parse_noop_expression();
+       case T___real__:
+       case T___imag__:                     return parse_complex_extract_expression();
 
        /* Gracefully handle type names while parsing expressions. */
        case T_COLONCOLON:
@@ -7511,17 +7594,18 @@ static bool is_lvalue(const expression_t *expression)
 
 static void semantic_incdec(unary_expression_t *expression)
 {
-       type_t *const orig_type = expression->value->base.type;
-       type_t *const type      = skip_typeref(orig_type);
+       type_t *orig_type = expression->value->base.type;
+       type_t *type      = skip_typeref(orig_type);
        if (is_type_pointer(type)) {
                if (!check_pointer_arithmetic(&expression->base.pos, type, orig_type)) {
                        return;
                }
-       } else if (!is_type_real(type) && is_type_valid(type)) {
+       } else if (!is_type_real(type) &&
+                  (!GNU_MODE || !is_type_complex(type)) && is_type_valid(type)) {
                /* TODO: improve error message */
                errorf(&expression->base.pos,
                       "operation needs an arithmetic or pointer type");
-               return;
+               orig_type = type = type_error_type;
        }
        if (!is_lvalue(expression->value)) {
                /* TODO: improve error message */
@@ -7532,7 +7616,16 @@ static void semantic_incdec(unary_expression_t *expression)
 
 static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type)
 {
-       type_t *const res_type = promote_integer(type);
+       atomic_type_kind_t akind = get_arithmetic_akind(type);
+       type_t *res_type;
+       if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT)) {
+               if (type->kind == TYPE_COMPLEX)
+                       res_type = make_complex_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
+               else
+                       res_type = type_int;
+       } else {
+               res_type = type;
+       }
        expr->base.type = res_type;
        expr->value     = create_implicit_cast(expr->value, res_type);
 }
@@ -7572,14 +7665,18 @@ static void semantic_complement(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
        type_t *const type      = skip_typeref(orig_type);
-       if (!is_type_integer(type)) {
+       if (!is_type_integer(type) && (!GNU_MODE || !is_type_complex(type))) {
                if (is_type_valid(type)) {
                        errorf(&expression->base.pos, "operand of ~ must be of integer type");
                }
                return;
        }
 
-       promote_unary_int_expr(expression, type);
+       if (is_type_integer(type)) {
+               promote_unary_int_expr(expression, type);
+       } else {
+               expression->base.type = orig_type;
+       }
 }
 
 static void semantic_dereference(unary_expression_t *expression)
@@ -7701,67 +7798,78 @@ CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS,
                                        EXPR_UNARY_POSTFIX_DECREMENT,
                                        semantic_incdec)
 
-static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+static atomic_type_kind_t semantic_arithmetic_(atomic_type_kind_t kind_left,
+                                               atomic_type_kind_t kind_right)
 {
-       /* TODO: handle complex + imaginary types */
-
-       type_left  = get_unqualified_type(type_left);
-       type_right = get_unqualified_type(type_right);
-
        /* §6.3.1.8 Usual arithmetic conversions */
-       if (type_left == type_long_double || type_right == type_long_double) {
-               return type_long_double;
-       } else if (type_left == type_double || type_right == type_double) {
-               return type_double;
-       } else if (type_left == type_float || type_right == type_float) {
-               return type_float;
-       }
-
-       type_left  = promote_integer(type_left);
-       type_right = promote_integer(type_right);
-
-       if (type_left == type_right)
-               return type_left;
-
-       bool     const signed_left  = is_type_signed(type_left);
-       bool     const signed_right = is_type_signed(type_right);
-       unsigned const rank_left    = get_akind_rank(get_akind(type_left));
-       unsigned const rank_right   = get_akind_rank(get_akind(type_right));
-
+       if (kind_left == ATOMIC_TYPE_LONG_DOUBLE
+        || kind_right == ATOMIC_TYPE_LONG_DOUBLE) {
+               return ATOMIC_TYPE_LONG_DOUBLE;
+       } else if (kind_left == ATOMIC_TYPE_DOUBLE
+               || kind_right == ATOMIC_TYPE_DOUBLE) {
+           return ATOMIC_TYPE_DOUBLE;
+       } else if (kind_left == ATOMIC_TYPE_FLOAT
+               || kind_right == ATOMIC_TYPE_FLOAT) {
+               return ATOMIC_TYPE_FLOAT;
+       }
+
+       unsigned       rank_left  = get_akind_rank(kind_left);
+       unsigned       rank_right = get_akind_rank(kind_right);
+       unsigned const rank_int   = get_akind_rank(ATOMIC_TYPE_INT);
+       if (rank_left < rank_int) {
+               kind_left = ATOMIC_TYPE_INT;
+               rank_left = rank_int;
+       }
+       if (rank_right < rank_int) {
+               kind_right = ATOMIC_TYPE_INT;
+               rank_right = rank_int;
+       }
+       if (kind_left == kind_right)
+               return kind_left;
+
+       bool const signed_left  = is_akind_signed(kind_left);
+       bool const signed_right = is_akind_signed(kind_right);
        if (signed_left == signed_right)
-               return rank_left >= rank_right ? type_left : type_right;
+               return rank_left >= rank_right ? kind_left : kind_right;
 
        unsigned           s_rank;
        unsigned           u_rank;
-       atomic_type_kind_t s_akind;
-       atomic_type_kind_t u_akind;
-       type_t *s_type;
-       type_t *u_type;
+       atomic_type_kind_t s_kind;
+       atomic_type_kind_t u_kind;
        if (signed_left) {
-               s_type = type_left;
-               u_type = type_right;
+               s_kind = kind_left;
+               s_rank = rank_left;
+               u_kind = kind_right;
+               u_rank = rank_right;
        } else {
-               s_type = type_right;
-               u_type = type_left;
+               s_kind = kind_right;
+               s_rank = rank_right;
+               u_kind = kind_left;
+               u_rank = rank_left;
        }
-       s_akind = get_akind(s_type);
-       u_akind = get_akind(u_type);
-       s_rank  = get_akind_rank(s_akind);
-       u_rank  = get_akind_rank(u_akind);
-
        if (u_rank >= s_rank)
-               return u_type;
-
-       if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind))
-               return s_type;
+               return u_kind;
+       if (get_atomic_type_size(s_kind) > get_atomic_type_size(u_kind))
+               return s_kind;
+
+       switch (s_kind) {
+       case ATOMIC_TYPE_INT:      return ATOMIC_TYPE_UINT;
+       case ATOMIC_TYPE_LONG:     return ATOMIC_TYPE_ULONG;
+       case ATOMIC_TYPE_LONGLONG: return ATOMIC_TYPE_ULONGLONG;
+       default: panic("invalid atomic type");
+       }
+}
 
-       switch (s_akind) {
-       case ATOMIC_TYPE_INT:      return type_unsigned_int;
-       case ATOMIC_TYPE_LONG:     return type_unsigned_long;
-       case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
+static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+{
+       atomic_type_kind_t kind_left  = get_arithmetic_akind(type_left);
+       atomic_type_kind_t kind_right = get_arithmetic_akind(type_right);
+       atomic_type_kind_t kind_res   = semantic_arithmetic_(kind_left, kind_right);
 
-       default: panic("invalid atomic type");
+       if (type_left->kind == TYPE_COMPLEX || type_right->kind == TYPE_COMPLEX) {
+               return make_complex_type(kind_res, TYPE_QUALIFIER_NONE);
        }
+       return make_atomic_type(kind_res, TYPE_QUALIFIER_NONE);
 }
 
 /**
@@ -8382,6 +8490,8 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_UNARY_NOT:                  return false;
                case EXPR_UNARY_DEREFERENCE:          return false;
                case EXPR_UNARY_TAKE_ADDRESS:         return false;
+               case EXPR_UNARY_REAL:                 return false;
+               case EXPR_UNARY_IMAG:                 return false;
                case EXPR_UNARY_POSTFIX_INCREMENT:    return true;
                case EXPR_UNARY_POSTFIX_DECREMENT:    return true;
                case EXPR_UNARY_PREFIX_INCREMENT:     return true;
@@ -9172,7 +9282,7 @@ static statement_t *parse_switch(void)
        type_t       *      type = skip_typeref(expr->base.type);
        if (is_type_integer(type)) {
                type = promote_integer(type);
-               if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+               if (get_akind_rank(get_arithmetic_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
                        warningf(WARN_TRADITIONAL, &expr->base.pos,
                                 "'%T' switch expression not converted to '%T' in ISO C",
                                 type, type_int);
diff --git a/type.c b/type.c
index dcceaef..09b38eb 100644 (file)
--- a/type.c
+++ b/type.c
@@ -753,12 +753,8 @@ static bool test_atomic_type_flag(atomic_type_kind_t kind,
 bool is_type_integer(const type_t *type)
 {
        assert(!is_typeref(type));
-
-       if (type->kind == TYPE_ENUM)
-               return true;
-       if (type->kind != TYPE_ATOMIC)
+       if (!is_type_arithmetic(type))
                return false;
-
        return test_atomic_type_flag(type->atomic.akind, ATOMIC_TYPE_FLAG_INTEGER);
 }
 
@@ -778,16 +774,17 @@ bool is_type_float(const type_t *type)
        return test_atomic_type_flag(type->atomic.akind, ATOMIC_TYPE_FLAG_FLOAT);
 }
 
-bool is_type_signed(const type_t *type)
+bool is_type_complex(const type_t *type)
 {
        assert(!is_typeref(type));
+       return type->kind == TYPE_COMPLEX;
+}
 
-       /* enum types are int for now */
-       if (type->kind == TYPE_ENUM)
-               return true;
-       if (type->kind != TYPE_ATOMIC)
+bool is_type_signed(const type_t *type)
+{
+       assert(!is_typeref(type));
+       if (!is_type_arithmetic(type))
                return false;
-
        return test_atomic_type_flag(type->atomic.akind, ATOMIC_TYPE_FLAG_SIGNED);
 }
 
@@ -822,6 +819,7 @@ bool is_type_scalar(const type_t *type)
        case TYPE_ENUM:
                return true;
        case TYPE_ATOMIC:
+       case TYPE_COMPLEX:
        case TYPE_IMAGINARY:
                return test_atomic_type_flag(type->atomic.akind, ATOMIC_TYPE_FLAG_ARITHMETIC);
        default:
index 2b6763f..2fe19fb 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -56,7 +56,7 @@ struct type_base_t {
 };
 
 /**
- * used for atomic types, complex and imaginary
+ * used for atomic types, complex and imaginary and as base for enum
  */
 struct atomic_type_t {
        type_base_t         base;
@@ -291,6 +291,19 @@ static inline unsigned get_akind_rank(atomic_type_kind_t akind)
        return atomic_type_properties[akind].rank;
 }
 
+static inline bool is_akind_signed(atomic_type_kind_t akind)
+{
+       return atomic_type_properties[akind].flags & ATOMIC_TYPE_FLAG_SIGNED;
+}
+
+static inline atomic_type_kind_t get_arithmetic_akind(const type_t *type)
+{
+       assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
+              || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
+       /* note that atomic, complex and enum share atomic_type_t base */
+       return type->atomic.akind;
+}
+
 /**
  * Allocate a type node of given kind and initialize all
  * fields with zero.