Implement the GCC insani^Wextension __builtin_classify_type.
authorChristoph Mallon <christoph.mallon@gmx.de>
Sun, 18 Nov 2007 13:56:38 +0000 (13:56 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Sun, 18 Nov 2007 13:56:38 +0000 (13:56 +0000)
[r18485]

ast.c
ast.h
ast2firm.c
ast_t.h
parser.c
tokens.inc

diff --git a/ast.c b/ast.c
index 692de23..d61ff38 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -234,6 +234,14 @@ static void print_select(const select_expression_t *expression)
        fputs(expression->symbol->string, out);
 }
 
+static void print_classify_type_expression(
+       const classify_type_expression_t *const expr)
+{
+       fputs("__builtin_classify_type(", out);
+       print_expression(expr->type_expression);
+       fputc(')', out);
+}
+
 void print_expression(const expression_t *expression)
 {
        switch(expression->type) {
@@ -279,6 +287,9 @@ void print_expression(const expression_t *expression)
        case EXPR_SELECT:
                print_select((const select_expression_t*) expression);
                break;
+       case EXPR_CLASSIFY_TYPE:
+               print_classify_type_expression((const classify_type_expression_t*)expression);
+               break;
 
        case EXPR_OFFSETOF:
        case EXPR_STATEMENT:
diff --git a/ast.h b/ast.h
index 7751563..1b1f8d6 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -26,6 +26,7 @@ typedef struct designator_t                 designator_t;
 typedef struct offsetof_expression_t        offsetof_expression_t;
 typedef struct va_arg_expression_t          va_arg_expression_t;
 typedef struct builtin_symbol_expression_t  builtin_symbol_expression_t;
+typedef struct classify_type_expression_t   classify_type_expression_t;
 
 typedef struct initializer_t                initializer_t;
 typedef struct declaration_t                declaration_t;
index 3f90847..7bfe53d 100644 (file)
@@ -1333,6 +1333,113 @@ static ir_node *select_to_firm(const select_expression_t *expression)
        return deref_address(type, addr, dbgi);
 }
 
+/* Values returned by __builtin_classify_type. */
+typedef enum gcc_type_class
+{
+       no_type_class = -1,
+       void_type_class,
+       integer_type_class,
+       char_type_class,
+       enumeral_type_class,
+       boolean_type_class,
+       pointer_type_class,
+       reference_type_class,
+       offset_type_class,
+       real_type_class,
+       complex_type_class,
+       function_type_class,
+       method_type_class,
+       record_type_class,
+       union_type_class,
+       array_type_class,
+       string_type_class,
+       set_type_class,
+       file_type_class,
+       lang_type_class
+} gcc_type_class;
+
+static ir_node *classify_type_to_firm(const classify_type_expression_t *const expr)
+{
+       const type_t *const type = expr->type_expression->datatype;
+
+       gcc_type_class tc;
+       switch (type->type)
+       {
+               case TYPE_ATOMIC: {
+                       const atomic_type_t *const atomic_type = (const atomic_type_t*)type;
+                       switch (atomic_type->atype) {
+                               // should not be reached
+                               case ATOMIC_TYPE_INVALID:
+                                       tc = no_type_class;
+                                       break;
+
+                               // gcc cannot do that
+                               case ATOMIC_TYPE_VOID:
+                                       tc = void_type_class;
+                                       break;
+
+                               case ATOMIC_TYPE_CHAR:      // gcc handles this as integer
+                               case ATOMIC_TYPE_SCHAR:     // gcc handles this as integer
+                               case ATOMIC_TYPE_UCHAR:     // gcc handles this as integer
+                               case ATOMIC_TYPE_SHORT:
+                               case ATOMIC_TYPE_USHORT:
+                               case ATOMIC_TYPE_INT:
+                               case ATOMIC_TYPE_UINT:
+                               case ATOMIC_TYPE_LONG:
+                               case ATOMIC_TYPE_ULONG:
+                               case ATOMIC_TYPE_LONGLONG:
+                               case ATOMIC_TYPE_ULONGLONG:
+                               case ATOMIC_TYPE_BOOL:      // gcc handles this as integer
+                                       tc = integer_type_class;
+                                       break;
+
+                               case ATOMIC_TYPE_FLOAT:
+                               case ATOMIC_TYPE_DOUBLE:
+                               case ATOMIC_TYPE_LONG_DOUBLE:
+                                       tc = real_type_class;
+                                       break;
+
+#ifdef PROVIDE_COMPLEX
+                               case ATOMIC_TYPE_FLOAT_COMPLEX:
+                               case ATOMIC_TYPE_DOUBLE_COMPLEX:
+                               case ATOMIC_TYPE_LONG_DOUBLE_COMPLEX:
+                                       tc = complex_type_class;
+                                       break;
+#endif
+
+#ifdef PROVIDE_IMAGINARY
+                               case ATOMIC_TYPE_FLOAT_IMAGINARY:
+                               case ATOMIC_TYPE_DOUBLE_IMAGINARY:
+                               case ATOMIC_TYPE_LONG_DOUBLE_IMAGINARY:
+                                       tc = complex_type_class;
+                                       break;
+#endif
+
+                               default:
+                                       panic("Unimplemented case in classify_type_to_firm().");
+                       }
+                       break;
+               }
+
+               case TYPE_ARRAY:           // gcc handles this as pointer
+               case TYPE_FUNCTION:        // gcc handles this as pointer
+               case TYPE_POINTER:         tc = pointer_type_class; break;
+               case TYPE_COMPOUND_STRUCT: tc = record_type_class;  break;
+               case TYPE_COMPOUND_UNION:  tc = union_type_class;   break;
+
+               // gcc handles this as integer
+               case TYPE_ENUM:            tc = integer_type_class; break;
+
+               default:
+                       panic("Unimplemented case in classify_type_to_firm().");
+       }
+
+       dbg_info *const dbgi = get_dbg_info(&expr->expression.source_position);
+       ir_mode  *const mode = mode_Is;
+       tarval   *const tv   = new_tarval_from_long(tc, mode);
+       return new_d_Const(dbgi, mode, tv);
+}
+
 static ir_node *dereference_addr(const unary_expression_t *const expression)
 {
        assert(expression->type == UNEXPR_DEREFERENCE);
@@ -1388,6 +1495,8 @@ static ir_node *_expression_to_firm(const expression_t *expression)
                return conditional_to_firm((const conditional_expression_t*)expression);
        case EXPR_SELECT:
                return select_to_firm((const select_expression_t*) expression);
+       case EXPR_CLASSIFY_TYPE:
+               return classify_type_to_firm((const classify_type_expression_t*)expression);
        case EXPR_FUNCTION:
        case EXPR_OFFSETOF:
        case EXPR_PRETTY_FUNCTION:
diff --git a/ast_t.h b/ast_t.h
index 94c96a1..7d3fc37 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -24,6 +24,7 @@ typedef enum {
        EXPR_SELECT,
        EXPR_ARRAY_ACCESS,
        EXPR_SIZEOF,
+       EXPR_CLASSIFY_TYPE,
 
        EXPR_FUNCTION,
        EXPR_PRETTY_FUNCTION,
@@ -190,6 +191,11 @@ struct statement_expression_t {
        statement_t  *statement;
 };
 
+struct classify_type_expression_t {
+       expression_t  expression;
+       expression_t *type_expression;
+};
+
 typedef enum {
        STORAGE_CLASS_NONE,
        STORAGE_CLASS_TYPEDEF,
index f030107..1d9a9a7 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2851,6 +2851,23 @@ static expression_t *parse_extension(unsigned precedence)
        return parse_sub_expression(precedence);
 }
 
+static expression_t *parse_builtin_classify_type(const unsigned precedence)
+{
+       eat(T___builtin_classify_type);
+
+       classify_type_expression_t *const classify_type_expr =
+               allocate_ast_zero(sizeof(classify_type_expr[0]));
+       classify_type_expr->expression.type     = EXPR_CLASSIFY_TYPE;
+       classify_type_expr->expression.datatype = type_int;
+
+       expect('(');
+       expression_t *const expression = parse_sub_expression(precedence);
+       expect(')');
+       classify_type_expr->type_expression = expression;
+
+       return (expression_t*)classify_type_expr;
+}
+
 static void semantic_incdec(unary_expression_t *expression)
 {
        type_t *orig_type = expression->value->datatype;
@@ -3540,6 +3557,8 @@ static void init_expression_parsers(void)
        register_expression_parser(parse_UNEXPR_PREFIX_DECREMENT, T_MINUSMINUS, 25);
        register_expression_parser(parse_sizeof,                  T_sizeof,     25);
        register_expression_parser(parse_extension,            T___extension__, 25);
+       register_expression_parser(parse_builtin_classify_type,
+                                                    T___builtin_classify_type, 25);
 }
 
 
index 4209c2d..bed58e0 100644 (file)
@@ -45,6 +45,7 @@ S(_Imaginary)
 S(__thread)
 S(__extension__)
 S(__attribute__)
+S(__builtin_classify_type)
 S(__builtin_va_list)
 S(__builtin_expect)
 S(__builtin_offsetof)