Add support for variadic arguments.
authorChristoph Mallon <christoph.mallon@gmx.de>
Fri, 30 Nov 2007 18:35:37 +0000 (18:35 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Fri, 30 Nov 2007 18:35:37 +0000 (18:35 +0000)
[r18582]

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

diff --git a/ast.c b/ast.c
index 87d490e..b89b92f 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -275,10 +275,19 @@ static void print_conditional(const conditional_expression_t *expression)
        fputs(")", out);
 }
 
+static void print_va_start(const va_start_expression_t *const expression)
+{
+       fputs("__builtin_va_start(", out);
+       print_expression(expression->ap);
+       fputs(", ", out);
+       fputs(expression->parameter->symbol->string, out);
+       fputs(")", out);
+}
+
 static void print_va_arg(const va_arg_expression_t *expression)
 {
        fputs("__builtin_va_arg(", out);
-       print_expression(expression->arg);
+       print_expression(expression->ap);
        fputs(", ", out);
        print_type(expression->expression.datatype);
        fputs(")", out);
@@ -346,6 +355,8 @@ void print_expression(const expression_t *expression)
        case EXPR_CONDITIONAL:
                print_conditional(&expression->conditional);
                break;
+       case EXPR_VA_START:
+               print_va_start(&expression->va_starte);
        case EXPR_VA_ARG:
                print_va_arg(&expression->va_arge);
                break;
diff --git a/ast.h b/ast.h
index 1c64fc8..479c184 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -25,6 +25,7 @@ typedef struct comma_expression_t               comma_expression_t;
 typedef struct statement_expression_t           statement_expression_t;
 typedef struct designator_t                     designator_t;
 typedef struct offsetof_expression_t            offsetof_expression_t;
+typedef struct va_start_expression_t            va_start_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;
index 29509cc..832c30f 100644 (file)
@@ -227,6 +227,7 @@ static unsigned get_type_size(type_t *type)
        case TYPE_ARRAY:
                return get_array_type_size(&type->array);
        case TYPE_BUILTIN:
+               return get_type_size(type->builtin.real_type);
        case TYPE_TYPEDEF:
        case TYPE_TYPEOF:
        case TYPE_INVALID:
@@ -508,6 +509,8 @@ static ir_type *get_ir_type(type_t *type)
                firm_type = create_enum_type(&type->enumt);
                break;
        case TYPE_BUILTIN:
+               firm_type = get_ir_type(type->builtin.real_type);
+               break;
        case TYPE_TYPEOF:
        case TYPE_TYPEDEF:
        case TYPE_INVALID:
@@ -859,6 +862,8 @@ static ir_node *process_builtin_call(const call_expression_t *call)
                ir_node *res  = new_d_Const(dbgi, mode, tv);
                return res;
        }
+       case T___builtin_va_end:
+               return NULL;
        default:
                panic("Unsupported builtin found\n");
        }
@@ -1708,6 +1713,42 @@ static ir_node *statement_expression_to_firm(const statement_expression_t *expr)
        return compound_statement_to_firm((compound_statement_t*) statement);
 }
 
+static ir_node *va_start_expression_to_firm(
+       const va_start_expression_t *const expr)
+{
+       ir_type   *const method_type = get_ir_type(current_function_decl->type);
+       int        const n           = get_method_n_params(method_type) - 1;
+       ir_entity *const parm_ent    = get_method_value_param_ent(method_type, n);
+       ir_node   *const arg_base    = get_irg_value_param_base(current_ir_graph);
+       dbg_info  *const dbgi        =
+               get_dbg_info(&expr->expression.source_position);
+       ir_node   *const no_mem      = new_NoMem();
+       ir_node   *const arg_sel     =
+               new_d_simpleSel(dbgi, no_mem, arg_base, parm_ent);
+
+       size_t     const parm_size   = get_type_size(expr->parameter->type);
+       ir_node   *const cnst        = new_Const_long(mode_Iu, parm_size);
+       ir_node   *const add         = new_d_Add(dbgi, arg_sel, cnst, mode_P_data);
+       set_value_for_expression(expr->ap, add);
+
+       return NULL;
+}
+
+static ir_node *va_arg_expression_to_firm(const va_arg_expression_t *const expr)
+{
+       ir_type  *const irtype = get_ir_type(expr->expression.datatype);
+       ir_node  *const ap     = expression_to_firm(expr->ap);
+       dbg_info *const dbgi   = get_dbg_info(&expr->expression.source_position);
+       ir_node  *const res    = deref_address(irtype, ap, dbgi);
+
+       size_t     const parm_size   = get_type_size(expr->expression.datatype);
+       ir_node   *const cnst        = new_Const_long(mode_Iu, parm_size);
+       ir_node   *const add         = new_d_Add(dbgi, ap, cnst, mode_P_data);
+       set_value_for_expression(expr->ap, add);
+
+       return res;
+}
+
 static ir_node *dereference_addr(const unary_expression_t *const expression)
 {
        assert(expression->type == UNEXPR_DEREFERENCE);
@@ -1770,8 +1811,11 @@ static ir_node *_expression_to_firm(const expression_t *expression)
                return function_name_to_firm(&expression->string);
        case EXPR_STATEMENT:
                return statement_expression_to_firm(&expression->statement);
-       case EXPR_OFFSETOF:
+       case EXPR_VA_START:
+               return va_start_expression_to_firm(&expression->va_starte);
        case EXPR_VA_ARG:
+               return va_arg_expression_to_firm(&expression->va_arge);
+       case EXPR_OFFSETOF:
        case EXPR_BUILTIN_SYMBOL:
                panic("unimplemented expression found");
 
diff --git a/ast_t.h b/ast_t.h
index 1f67819..2c607c6 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -32,6 +32,7 @@ typedef enum {
        EXPR_PRETTY_FUNCTION,
        EXPR_BUILTIN_SYMBOL,
        EXPR_OFFSETOF,
+       EXPR_VA_START,
        EXPR_VA_ARG,
        EXPR_STATEMENT
 } expression_type_t;
@@ -182,10 +183,15 @@ struct offsetof_expression_t {
        designator_t      *designator;
 };
 
+struct va_start_expression_t {
+       expression_base_t  expression;
+       expression_t      *ap;
+       declaration_t     *parameter;
+};
+
 struct va_arg_expression_t {
        expression_base_t  expression;
-       expression_t      *arg;
-       type_t            *type;
+       expression_t      *ap;
 };
 
 struct conditional_expression_t {
@@ -220,6 +226,7 @@ union expression_t {
        array_access_expression_t        array_access;
        sizeof_expression_t              sizeofe;
        offsetof_expression_t            offsetofe;
+       va_start_expression_t            va_starte;
        va_arg_expression_t              va_arge;
        conditional_expression_t         conditional;
        statement_expression_t           statement;
index 0c8b187..44c9298 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -55,6 +55,7 @@ static type_t         *type_char        = NULL;
 static type_t         *type_string      = NULL;
 static type_t         *type_void        = NULL;
 static type_t         *type_void_ptr    = NULL;
+static type_t         *type_valist      = NULL;
 
 type_t *type_size_t      = NULL;
 type_t *type_ptrdiff_t   = NULL;
@@ -96,22 +97,23 @@ static declaration_t *record_declaration(declaration_t *declaration);
 #define IMAGINARY_SPECIFIERS
 #endif
 
-#define TYPE_SPECIFIERS     \
-       case T_void:            \
-       case T_char:            \
-       case T_short:           \
-       case T_int:             \
-       case T_long:            \
-       case T_float:           \
-       case T_double:          \
-       case T_signed:          \
-       case T_unsigned:        \
-       case T__Bool:           \
-       case T_struct:          \
-       case T_union:           \
-       case T_enum:            \
-       case T___typeof__:      \
-       COMPLEX_SPECIFIERS      \
+#define TYPE_SPECIFIERS       \
+       case T_void:              \
+       case T_char:              \
+       case T_short:             \
+       case T_int:               \
+       case T_long:              \
+       case T_float:             \
+       case T_double:            \
+       case T_signed:            \
+       case T_unsigned:          \
+       case T__Bool:             \
+       case T_struct:            \
+       case T_union:             \
+       case T_enum:              \
+       case T___typeof__:        \
+       case T___builtin_va_list: \
+       COMPLEX_SPECIFIERS        \
        IMAGINARY_SPECIFIERS
 
 #define DECLARATION_START   \
@@ -185,6 +187,7 @@ static size_t get_expression_struct_size(expression_type_t type)
                [EXPR_PRETTY_FUNCTION]     = sizeof(string_literal_expression_t),
                [EXPR_BUILTIN_SYMBOL]      = sizeof(builtin_symbol_expression_t),
                [EXPR_OFFSETOF]            = sizeof(offsetof_expression_t),
+               [EXPR_VA_START]            = sizeof(va_start_expression_t),
                [EXPR_VA_ARG]              = sizeof(va_arg_expression_t),
                [EXPR_STATEMENT]           = sizeof(statement_expression_t)
        };
@@ -445,7 +448,7 @@ static void eat_statement(void)
        eat(';');
 }
 
-static void eat_brace(void)
+static void eat_paren(void)
 {
        if(token.type == '(')
                next_token();
@@ -457,7 +460,7 @@ static void eat_brace(void)
                        return;
                }
                if(token.type == '(') {
-                       eat_brace();
+                       eat_paren();
                        continue;
                }
                if(token.type == '{') {
@@ -1021,7 +1024,7 @@ static void parse_attributes(void)
                        if(token.type != T_STRING_LITERAL) {
                                parse_error_expected("while parsing assembler attribute",
                                                     T_STRING_LITERAL);
-                               eat_brace();
+                               eat_paren();
                                break;
                        } else {
                                parse_string_literals();
@@ -1610,14 +1613,19 @@ typedef enum {
 #endif
 } specifiers_t;
 
-static type_t *create_builtin_type(symbol_t *symbol)
+static type_t *create_builtin_type(symbol_t *const symbol,
+                                   type_t *const real_type)
 {
        type_t *type            = allocate_type_zero(TYPE_BUILTIN);
        type->builtin.symbol    = symbol;
-       /* TODO... */
-       type->builtin.real_type = type_int;
+       type->builtin.real_type = real_type;
 
-       return type;
+       type_t *result = typehash_insert(type);
+       if (type != result) {
+               free_type(type);
+       }
+
+       return result;
 }
 
 static type_t *get_typedef_type(symbol_t *symbol)
@@ -1760,7 +1768,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type = parse_typeof();
                        break;
                case T___builtin_va_list:
-                       type = create_builtin_type(token.v.symbol);
+                       type = duplicate_type(type_valist);
                        next_token();
                        break;
 
@@ -2837,7 +2845,7 @@ struct expression_parser_function_t {
 
 expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-static expression_t *make_invalid_expression(void)
+static expression_t *create_invalid_expression(void)
 {
        expression_t *expression         = allocate_expression_zero(EXPR_INVALID);
        expression->base.source_position = token.source_position;
@@ -2853,7 +2861,7 @@ static expression_t *expected_expression_error(void)
 
        next_token();
 
-       return make_invalid_expression();
+       return create_invalid_expression();
 }
 
 static expression_t *parse_string_const(void)
@@ -2962,6 +2970,8 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
                return make_function_1_type(type_float, type_string);
        case T___builtin_nand:
                return make_function_1_type(type_long_double, type_string);
+       case T___builtin_va_end:
+               return make_function_1_type(type_void, type_valist);
        default:
                panic("not implemented builtin symbol found");
        }
@@ -3211,7 +3221,7 @@ static designator_t *parse_designator(void)
        if(token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing member designator",
                                     T_IDENTIFIER, 0);
-               eat_brace();
+               eat_paren();
                return NULL;
        }
        result->symbol = token.v.symbol;
@@ -3224,7 +3234,7 @@ static designator_t *parse_designator(void)
                        if(token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing member designator",
                                                     T_IDENTIFIER, 0);
-                               eat_brace();
+                               eat_paren();
                                return NULL;
                        }
                        designator_t *designator = allocate_ast_zero(sizeof(result[0]));
@@ -3240,7 +3250,7 @@ static designator_t *parse_designator(void)
                        designator_t *designator = allocate_ast_zero(sizeof(result[0]));
                        designator->array_access = parse_expression();
                        if(designator->array_access == NULL) {
-                               eat_brace();
+                               eat_paren();
                                return NULL;
                        }
                        expect(']');
@@ -3271,6 +3281,38 @@ static expression_t *parse_offsetof(void)
        return expression;
 }
 
+static expression_t *parse_va_start(void)
+{
+       eat(T___builtin_va_start);
+
+       expression_t *expression = allocate_expression_zero(EXPR_VA_START);
+
+       expect('(');
+       expression->va_starte.ap = parse_assignment_expression();
+       expect(',');
+       if (token.type != T_IDENTIFIER) {
+               parse_error_expected("while parsing va_start", T_IDENTIFIER, 0);
+               eat_paren();
+               return create_invalid_expression();
+       }
+       expression_t *const expr = parse_reference();
+       if (expr->type == EXPR_INVALID) {
+               return create_invalid_expression();
+       }
+       assert(expr->type == EXPR_REFERENCE);
+       declaration_t *const decl = expr->reference.declaration;
+       if (decl->parent_context != &current_function->context ||
+           decl->next != NULL) {
+               parser_print_error_prefix_pos(decl->source_position);
+               fprintf(stderr, "second argument of 'va_start' must be last parameter "
+                               "of the current function\n");
+       }
+       expression->va_starte.parameter = decl;
+       expect(')');
+
+       return expression;
+}
+
 static expression_t *parse_va_arg(void)
 {
        eat(T___builtin_va_arg);
@@ -3278,7 +3320,7 @@ static expression_t *parse_va_arg(void)
        expression_t *expression = allocate_expression_zero(EXPR_VA_ARG);
 
        expect('(');
-       expression->va_arge.arg = parse_assignment_expression();
+       expression->va_arge.ap = parse_assignment_expression();
        expect(',');
        expression->base.datatype = parse_typename();
        expect(')');
@@ -3322,12 +3364,13 @@ static expression_t *parse_primary_expression(void)
                return parse_pretty_function_keyword();
        case T___builtin_offsetof:
                return parse_offsetof();
+       case T___builtin_va_start:
+               return parse_va_start();
        case T___builtin_va_arg:
                return parse_va_arg();
        case T___builtin_nanf:
        case T___builtin_alloca:
        case T___builtin_expect:
-       case T___builtin_va_start:
        case T___builtin_va_end:
                return parse_builtin_symbol();
 
@@ -3341,7 +3384,7 @@ static expression_t *parse_primary_expression(void)
        fprintf(stderr, "\n");
        eat_statement();
 
-       return make_invalid_expression();
+       return create_invalid_expression();
 }
 
 static expression_t *parse_array_expression(unsigned precedence,
@@ -3448,7 +3491,7 @@ static expression_t *parse_select_expression(unsigned precedence,
 
        type_t *orig_type = compound->base.datatype;
        if(orig_type == NULL)
-               return make_invalid_expression();
+               return create_invalid_expression();
 
        type_t *type = skip_typeref(orig_type);
 
@@ -3459,7 +3502,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                        fprintf(stderr, "left hand side of '->' is not a pointer, but ");
                        print_type_quoted(orig_type);
                        fputc('\n', stderr);
-                       return make_invalid_expression();
+                       return create_invalid_expression();
                }
                pointer_type_t *pointer_type = &type->pointer;
                type_left                    = pointer_type->points_to;
@@ -3473,7 +3516,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                        "union, but ", symbol->string);
                print_type_quoted(type_left);
                fputc('\n', stderr);
-               return make_invalid_expression();
+               return create_invalid_expression();
        }
 
        compound_type_t *compound_type = &type_left->compound;
@@ -3485,7 +3528,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                        symbol->string);
                print_type_quoted(type_left);
                fputc('\n', stderr);
-               return make_invalid_expression();
+               return create_invalid_expression();
        }
 
        declaration_t *iter = declaration->context.declarations;
@@ -3498,7 +3541,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                parser_print_error_prefix();
                print_type_quoted(type_left);
                fprintf(stderr, " has no member named '%s'\n", symbol->string);
-               return make_invalid_expression();
+               return create_invalid_expression();
        }
 
        /* we always do the auto-type conversions; the & and sizeof parser contains
@@ -5103,6 +5146,9 @@ void init_parser(void)
        type_void        = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
        type_void_ptr    = make_pointer_type(type_void, TYPE_QUALIFIER_NONE);
        type_string      = make_pointer_type(type_char, TYPE_QUALIFIER_NONE);
+
+       symbol_t *const va_list_sym = symbol_table_insert("__builtin_va_list");
+       type_valist = create_builtin_type(va_list_sym, type_void_ptr);
 }
 
 void exit_parser(void)
index 6a72d84..f640339 100644 (file)
@@ -49,7 +49,6 @@ S(__builtin_classify_type)
 S(__builtin_va_list)
 S(__builtin_expect)
 S(__builtin_offsetof)
-S(__builtin_va_start)
 S(__builtin_va_arg)
 S(__builtin_va_end)
 S(__builtin_alloca)
@@ -64,19 +63,21 @@ S(__real__)
 S(__imag__)
 #undef S
 
-T(const,               "__const",)
-T(_const,                "const", = T_const)
-T(restrict,         "__restrict",)
-T(_restrict,          "restrict", = T_restrict)
-T(asm,                     "asm",)
-T(__asm__,             "__asm__", = T_asm)
-T(volatile,           "volatile",)
-T(__volatile__,   "__volatile__", = T_volatile)
-T(inline,               "inline",)
-T(__inline,           "__inline", = T_inline)
-T(__inline__,       "__inline__", = T_inline)
-T(typeof,               "typeof",)
-T(__typeof__,       "__typeof__", = T_typeof)
+T(const,                  "__const",)
+T(_const,                 "const",                  = T_const)
+T(restrict,               "__restrict",)
+T(_restrict,              "restrict",               = T_restrict)
+T(asm,                    "asm",)
+T(__asm__,                "__asm__",                = T_asm)
+T(volatile,               "volatile",)
+T(__volatile__,           "__volatile__",           = T_volatile)
+T(inline,                 "inline",)
+T(__inline,               "__inline",               = T_inline)
+T(__inline__,             "__inline__",             = T_inline)
+T(typeof,                 "typeof",)
+T(__typeof__,             "__typeof__",             = T_typeof)
+T(__builtin_va_start,     "__builtin_va_start",)
+T(__builtin_stdarg_start, "__builtin_stdarg_start", = T___builtin_va_start)
 
 T(MINUSGREATER,             "->",)
 T(PLUSPLUS,                 "++",)
diff --git a/type.c b/type.c
index 8a6486d..8e42891 100644 (file)
--- a/type.c
+++ b/type.c
@@ -496,17 +496,20 @@ bool is_type_arithmetic(const type_t *type)
        assert(!is_typeref(type));
 
        if(is_type_integer(type) || is_type_floating(type))
-               return 1;
+               return true;
 
-       return 0;
+       return false;
 }
 
 bool is_type_scalar(const type_t *type)
 {
        assert(!is_typeref(type));
 
-       if(type->type == TYPE_POINTER)
-               return 1;
+       switch (type->type) {
+               case TYPE_POINTER: return true;
+               case TYPE_BUILTIN: return is_type_scalar(type->builtin.real_type);
+               default:           break;
+       }
 
        return is_type_arithmetic(type);
 }
@@ -531,11 +534,11 @@ bool is_type_incomplete(const type_t *type)
        case TYPE_ATOMIC:
        case TYPE_POINTER:
        case TYPE_ENUM:
+       case TYPE_BUILTIN:
                return false;
 
        case TYPE_TYPEDEF:
        case TYPE_TYPEOF:
-       case TYPE_BUILTIN:
                panic("is_type_incomplete called without typerefs skipped");
        case TYPE_INVALID:
                break;
@@ -674,11 +677,6 @@ type_t *skip_typeref(type_t *type)
                        }
                        continue;
                }
-               case TYPE_BUILTIN: {
-                       const builtin_type_t *builtin_type = &type->builtin;
-                       type = builtin_type->real_type;
-                       continue;
-               }
                default:
                        break;
                }