Skip to content

Commit

Permalink
IA-16: add __attribute__ ((cdecl))', __attribute__ ((stdcall))'
Browse files Browse the repository at this point in the history
As requested (#13) by
Bart Oldeman.

I also added a few test cases --- gcc.traget/ia16/rtd-{2, 3,
4, 5}.c --- to test that these attributes work properly.
  • Loading branch information
tkchia committed Feb 15, 2018
1 parent 5ce2e11 commit e6295a6
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 13 deletions.
5 changes: 5 additions & 0 deletions gcc/config/ia16/ia16-c.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ ia16_cpu_cpp_builtins (void)
def_or_undef_macro ("__IA16_FEATURE_ALLOCABLE_DS_REG",
TARGET_ALLOCABLE_DS_REG);

/* Define macros for function calling conventions available through
__attribute__ ((.)). */
cpp_define (parse_in, "__IA16_FEATURE_ATTRIBUTE_CDECL");
cpp_define (parse_in, "__IA16_FEATURE_ATTRIBUTE_STDCALL");

/* Also define a macro to give the function calling convention in use. */
def_or_undef_macro ("__IA16_CALLCVT_CDECL", ! TARGET_RTD);
def_or_undef_macro ("__IA16_CALLCVT_STDCALL", TARGET_RTD);
Expand Down
105 changes: 94 additions & 11 deletions gcc/config/ia16/ia16.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,16 @@ ia16_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t rclass)
{
/* Try to avoid roping in %ds. */
switch (rclass)
{
case SEGMENT_REGS:
return ES_REGS;
{
case SEGMENT_REGS:
return ES_REGS;

case SEG_GENERAL_REGS:
return ES_GENERAL_REGS;
case SEG_GENERAL_REGS:
return ES_GENERAL_REGS;

default:
return rclass;
}
default:
return rclass;
}
}

#undef TARGET_SECONDARY_RELOAD
Expand Down Expand Up @@ -373,15 +373,98 @@ ia16_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
/* Passing Function Arguments on the Stack */
#undef TARGET_RETURN_POPS_ARGS
#define TARGET_RETURN_POPS_ARGS ia16_return_pops_args

#define IA16_CALLCVT_CDECL 0x01
#define IA16_CALLCVT_STDCALL 0x02

static unsigned
ia16_get_callcvt (const_tree type)
{
tree attrs = TYPE_ATTRIBUTES (type);

if (attrs != NULL_TREE)
{
if (lookup_attribute ("cdecl", attrs))
return IA16_CALLCVT_CDECL;

if (lookup_attribute ("stdcall", attrs))
return IA16_CALLCVT_STDCALL;
}

return TARGET_RTD ? IA16_CALLCVT_STDCALL : IA16_CALLCVT_CDECL;
}

static int
ia16_return_pops_args (tree fundecl ATTRIBUTE_UNUSED,
tree funtype ATTRIBUTE_UNUSED, int size)
ia16_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
{
/* Note that the `-mrtd' calling convention will also be applied to libgcc
library functions (e.g. __udivdi3). This usually means that, if we
compile code using `-mrtd', we will need a libgcc multilib compiled with
`-mrtd' to link against our code. */
return TARGET_RTD && ! stdarg_p (funtype) ? size : 0;
if (ia16_get_callcvt (funtype) == IA16_CALLCVT_STDCALL
&& ! stdarg_p (funtype))
return size;

return 0;
}

/* Defining target-specific uses of __attribute__ */
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE ia16_attribute_table

static tree
ia16_handle_cconv_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
{
switch (TREE_CODE (*node))
{
case FUNCTION_TYPE:
case METHOD_TYPE:
case FIELD_DECL:
case TYPE_DECL:
break;

default:
warning (OPT_Wattributes, "%qE attribute only applies to functions",
name);
*no_add_attrs = true;
return NULL_TREE;
}

if (is_attribute_p ("stdcall", name)
&& lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
{
error ("stdcall and cdecl attributes are not compatible");
*no_add_attrs = true;
}
else if (is_attribute_p ("cdecl", name)
&& lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
{
error ("stdcall and cdecl attributes are not compatible");
*no_add_attrs = true;
}

return NULL_TREE;
}

static const struct attribute_spec ia16_attribute_table[] =
{
{ "stdcall", 0, 0, false, true, true, ia16_handle_cconv_attribute, true },
{ "cdecl", 0, 0, false, true, true, ia16_handle_cconv_attribute, true },
{ NULL, 0, 0, false, false, false, NULL, false }
};

#undef TARGET_COMP_TYPE_ATTRIBUTES
#define TARGET_COMP_TYPE_ATTRIBUTES ia16_comp_type_attributes

static int
ia16_comp_type_attributes (const_tree type1, const_tree type2)
{
if (TREE_CODE (type1) != FUNCTION_TYPE
|| TREE_CODE (type1) != METHOD_TYPE)
return 1;

return ia16_get_callcvt (type1) == ia16_get_callcvt (type2);
}

/* Addressing Modes */
Expand Down
2 changes: 1 addition & 1 deletion gcc/config/ia16/ia16.h
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ enum reg_class { /* 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
* Mode Switching Instructions
* Defining target-specific uses of __attribute__
* Maybe __attribute("far")__ some day.
* This is done in ia16.c .
* Defining coprocessor specifics for MIPS targets.
Expand Down
3 changes: 2 additions & 1 deletion gcc/testsuite/gcc.target/ia16/rtd-1.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ inc (unsigned x)
return x + 1;
}

int main (int argc, char **argv, ...)
int
main (int argc, char **argv, ...)
{
unsigned i;

Expand Down
42 changes: 42 additions & 0 deletions gcc/testsuite/gcc.target/ia16/rtd-2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* { dg-do run } */
/* { dg-options "-Os --save-temps" } */

/* Test whether `__attribute__ ((stdcall))' works correctly, and still gets
the program linked with the correct (non-stdcall) libgcc multilib. */

extern void abort (void);

volatile unsigned long long quotient = 0x55bde67343803983ull,
divisor = 0x1670107447a23170ull;

__attribute__ ((stdcall)) unsigned
inc (unsigned x)
{
return x + 1;
}

int
main (int argc, char **argv)
{
unsigned i;

/* If this code is linked against the wrong libgcc, this loop will
eventually cause a stack overflow and corrupt the data area. */
for (i = 0; i < 10000; ++i)
{
unsigned long long mod = quotient % divisor;
if (mod != 0x126db5166c99a533ull)
abort ();
}

return 0;
}

/* inc (.) should pop one shortword: */
/* { dg-final { scan-assembler "ret\[ \\t\]\\\$2" } } */

/* main (...) should _not_ pop two shortwords: */
/* { dg-final { scan-assembler-not "ret\[ \\t\]\\\$4" } } */

/* main (...) should adjust the stack after calling __umoddi3: */
/* { dg-final { scan-assembler "addw\[ \\t\]\\$.*,\[ \\t\]%sp" } } */
40 changes: 40 additions & 0 deletions gcc/testsuite/gcc.target/ia16/rtd-3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* { dg-do run } */
/* { dg-options "-mrtd -Os --save-temps" } */

/* Test whether the `-mrtd' switch in conjunction with __attribute__
((cdecl)) works correctly and links with the correct libgcc multilib. */

extern void abort (void);

volatile unsigned long long quotient = 0x55bde67343803983ull,
divisor = 0x1670107447a23170ull;

unsigned
inc (unsigned x)
{
return x + 1;
}

__attribute__ ((cdecl)) int
main (int argc, char **argv)
{
unsigned i;

for (i = 0; i < 10000; ++i)
{
unsigned long long mod = quotient % divisor;
if (mod != 0x126db5166c99a533ull)
abort ();
}

return 0;
}

/* inc (.) should pop one shortword: */
/* { dg-final { scan-assembler "ret\[ \\t\]\\\$2" } } */

/* main (...) should _not_ pop two shortwords: */
/* { dg-final { scan-assembler-not "ret\[ \\t\]\\\$4" } } */

/* main (...) should not adjust the stack after calling __umoddi3: */
/* { dg-final { scan-assembler-not "addw\[ \\t\]\\$.*,\[ \\t\]%sp" } } */
11 changes: 11 additions & 0 deletions gcc/testsuite/gcc.target/ia16/rtd-4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* { dg-do assemble } */
/* { dg-xfail-if "" *-*-* } */
/* { dg-options "-mrtd -Os --save-temps" } */

/* XFAIL: the `cdecl' and `stdcall' attributes do not mix. */

__attribute__ ((cdecl, stdcall)) unsigned
inc (unsigned x)
{
return x + 1;
}
11 changes: 11 additions & 0 deletions gcc/testsuite/gcc.target/ia16/rtd-5.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* { dg-do assemble } */
/* { dg-xfail-if "" *-*-* } */
/* { dg-options "-mrtd -Os --save-temps" } */

/* XFAIL: the `cdecl' and `stdcall' attributes do not mix. */

__attribute__ ((stdcall, cdecl)) unsigned
inc (unsigned x)
{
return x + 1;
}

2 comments on commit e6295a6

@roytam1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about Pascal call?

@tkchia
Copy link
Owner Author

@tkchia tkchia commented on e6295a6 Feb 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @roytam1 ,

Currently most other calling conventions --- including pascal, thiscall, watcall, etc. --- are unimplemented. But for now, if you need to, you can emulate the Borland Pascal calling convention by declaring a stdcall function with its arguments in reverse order.

Thank you!

Please sign in to comment.