fixed support for calling conventions:
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 16 Aug 2008 11:36:17 +0000 (11:36 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 16 Aug 2008 11:36:17 +0000 (11:36 +0000)
- add them to function type
- issue error if more than one cc is used
- show them in type info

[r21216]

ast2firm.c
parser.c
type.c

index c3c471f..7261ac8 100644 (file)
@@ -380,6 +380,34 @@ static ir_type *create_method_type(const function_type_t *function_type)
                set_method_variadicity(irtype, variadicity_variadic);
        }
 
+       unsigned cc;
+       switch (function_type->calling_convention) {
+       case CC_DEFAULT: /* unspecified calling convention, equal to one of the other, typical cdelc */
+       case CC_CDECL:
+is_cdecl:
+               cc = get_method_calling_convention(irtype);
+               set_method_calling_convention(irtype, SET_CDECL(cc));
+               break;
+       case CC_STDCALL:
+               if (function_type->variadic || function_type->unspecified_parameters)
+                       goto is_cdecl;
+
+               /* only non-variadic function can use stdcall, else use cdecl */
+               cc = get_method_calling_convention(irtype);
+               set_method_calling_convention(irtype, SET_STDCALL(cc));
+               break;
+       case CC_FASTCALL:
+               if (function_type->variadic || function_type->unspecified_parameters)
+                       goto is_cdecl;
+               /* only non-variadic function can use fastcall, else use cdecl */
+               cc = get_method_calling_convention(irtype);
+               set_method_calling_convention(irtype, SET_FASTCALL(cc));
+               break;
+       case CC_THISCALL:
+               /* Hmm, leave default, not accepted by the parser yet. */
+               warningf(&function_type->base.source_position, "THISCALL calling convention not supported yet");
+               break;
+       }
        return irtype;
 }
 
@@ -1018,14 +1046,6 @@ static ir_entity *get_function_entity(declaration_t *declaration)
        ir_type  *ir_type_method = get_ir_type(declaration->type);
        assert(is_Method_type(ir_type_method));
 
-       if (declaration->modifiers & DM_CDECL) {
-               set_method_calling_convention(ir_type_method, cc_fixed | cc_cdecl_set);
-       } else if (declaration->modifiers & DM_FASTCALL) {
-               set_method_calling_convention(ir_type_method, cc_fixed | cc_fastcall_set);
-       } else if (declaration->modifiers & DM_STDCALL) {
-               set_method_calling_convention(ir_type_method, cc_fixed | cc_stdcall_set);
-       }
-
        /* already an entity defined? */
        ir_entity *entity = entitymap_get(&entitymap, symbol);
        if (entity != NULL) {
index 5d554d6..524b039 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -391,6 +391,9 @@ static size_t get_type_struct_size(type_kind_t kind)
 /**
  * Allocate a type node of given kind and initialize all
  * fields with zero.
+ *
+ * @param kind             type kind to allocate
+ * @param source_position  the source position of the type definition
  */
 static type_t *allocate_type_zero(type_kind_t kind, const source_position_t *source_position)
 {
@@ -3607,6 +3610,40 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration)
        type_t *type;
        if (declaration != NULL) {
                type = allocate_type_zero(TYPE_FUNCTION, &declaration->source_position);
+
+               unsigned mask = declaration->modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL);
+
+               if (mask & (mask-1)) {
+                       const char *first = NULL, *second = NULL;
+
+                       /* more than one calling convention set */
+                       if (declaration->modifiers & DM_CDECL) {
+                               if (first == NULL)       first = "cdecl";
+                               else if (second == NULL) second = "cdecl";
+                       }
+                       if (declaration->modifiers & DM_STDCALL) {
+                               if (first == NULL)       first = "stdcall";
+                               else if (second == NULL) second = "stdcall";
+                       }
+                       if (declaration->modifiers & DM_FASTCALL) {
+                               if (first == NULL)       first = "faslcall";
+                               else if (second == NULL) second = "fastcall";
+                       }
+                       if (declaration->modifiers & DM_THISCALL) {
+                               if (first == NULL)       first = "thiscall";
+                               else if (second == NULL) second = "thiscall";
+                       }
+                       errorf(&declaration->source_position, "%s and %s attributes are not compatible", first, second);
+               }
+
+               if (declaration->modifiers & DM_CDECL)
+                       type->function.calling_convention = CC_CDECL;
+               else if (declaration->modifiers & DM_STDCALL)
+                       type->function.calling_convention = CC_STDCALL;
+               else if (declaration->modifiers & DM_FASTCALL)
+                       type->function.calling_convention = CC_FASTCALL;
+               else if (declaration->modifiers & DM_THISCALL)
+                       type->function.calling_convention = CC_THISCALL;
        } else {
                type = allocate_type_zero(TYPE_FUNCTION, HERE);
        }
@@ -3622,7 +3659,7 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration)
        construct_function_type->construct_type.kind = CONSTRUCT_FUNCTION;
        construct_function_type->function_type       = type;
 
-       return (construct_type_t*) construct_function_type;
+       return &construct_function_type->construct_type;
 }
 
 static void fix_declaration_type(declaration_t *declaration)
diff --git a/type.c b/type.c
index dfb83e7..37893b9 100644 (file)
--- a/type.c
+++ b/type.c
@@ -279,6 +279,23 @@ static void print_function_type_pre(const function_type_t *type, bool top)
 
        intern_print_type_pre(type->return_type, false);
 
+       switch (type->calling_convention) {
+       case CC_CDECL:
+               fputs(" __cdecl ", out);
+               break;
+       case CC_STDCALL:
+               fputs(" __stdcall ", out);
+               break;
+       case CC_FASTCALL:
+               fputs(" __fastcall ", out);
+               break;
+       case CC_THISCALL:
+               fputs(" __thiscall ", out);
+               break;
+       case CC_DEFAULT:
+               break;
+       }
+
        /* don't emit braces if we're the toplevel type... */
        if (!top)
                fputc('(', out);
@@ -922,6 +939,9 @@ static bool function_types_compatible(const function_type_t *func1,
        if (func1->variadic != func2->variadic)
                return false;
 
+       if (func1->calling_convention != func2->calling_convention)
+               return false;
+
        /* TODO: handling of unspecified parameters not correct yet */
 
        /* all argument types must be compatible */