#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "output.h"
#include "tree.h"
#include "flags.h"
#include "tm_p.h"
#include "toplev.h"
#include "ggc.h"
static const char *
gen_stdcall_decoration (tree decl)
{
unsigned total = 0;
const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
== void_type_node)
{
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
while (TREE_VALUE (formal_type) != void_type_node
&& COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
{
unsigned parm_size
= TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
parm_size = ((parm_size + PARM_BOUNDARY - 1)
/ PARM_BOUNDARY * PARM_BOUNDARY);
total += parm_size;
formal_type = TREE_CHAIN (formal_type);
}
}
newsym = alloca (1 + strlen (asmname) + 1 + 10 + 1);
return IDENTIFIER_POINTER (get_identifier_with_length (newsym,
sprintf (newsym, "_%s@%u", asmname, total / BITS_PER_UNIT)));
}
static const char *
gen_fastcall_decoration (tree decl)
{
unsigned total = 0;
const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
== void_type_node)
{
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
while (TREE_VALUE (formal_type) != void_type_node
&& COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
{
int parm_size
= TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
parm_size = ((parm_size + PARM_BOUNDARY - 1)
/ PARM_BOUNDARY * PARM_BOUNDARY);
total += parm_size;
formal_type = TREE_CHAIN (formal_type);
}
}
newsym = alloca (1 + strlen (asmname) + 1 + 10 + 1);
return IDENTIFIER_POINTER (get_identifier_with_length (newsym,
sprintf (newsym, "%c%s@%d", FASTCALL_PREFIX, asmname,
total / BITS_PER_UNIT)));
}
static const char *
gen_regparm_prefix (tree decl, unsigned nregs)
{
unsigned total = 0;
const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
== void_type_node)
{
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
while (TREE_VALUE (formal_type) != void_type_node
&& COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
{
unsigned parm_size
= TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
parm_size = ((parm_size + PARM_BOUNDARY - 1)
/ PARM_BOUNDARY * PARM_BOUNDARY);
total += parm_size;
formal_type = TREE_CHAIN (formal_type);
}
}
if (nregs > total / BITS_PER_WORD)
nregs = total / BITS_PER_WORD;
if (nregs > 9) abort();
newsym = alloca (2 + strlen (asmname) + 1 + 1);
return IDENTIFIER_POINTER (get_identifier_with_length (newsym,
sprintf (newsym, "_%u@%s", nregs, asmname)));
}
void
i386_nlm_encode_section_info (tree decl, rtx rtl, int first)
{
default_encode_section_info (decl, rtl, first);
if (first
&& TREE_CODE (decl) == FUNCTION_DECL
&& *IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) != '*')
{
tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
rtx rtlname = XEXP (rtl, 0);
if (GET_CODE (rtlname) == MEM)
rtlname = XEXP (rtlname, 0);
if (lookup_attribute ("stdcall", type_attributes))
XSTR (rtlname, 0) = gen_stdcall_decoration (decl);
else if (lookup_attribute ("fastcall", type_attributes))
XSTR (rtlname, 0) = gen_fastcall_decoration (decl);
else
{
tree attr = lookup_attribute ("regparm", type_attributes);
if (attr)
XSTR (rtlname, 0) =
gen_regparm_prefix (decl,
TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))));
}
}
}
const char *
i386_nlm_strip_name_encoding (const char *str)
{
const char *name = default_strip_name_encoding (str);
if (*str != '*' && (*name == '_' || *name == '@'))
{
const char *p = strchr (name + 1, '@');
if (p)
{
++name;
if (ISDIGIT (p[1]))
name = ggc_alloc_string (name, p - name);
else if (!ISDIGIT (*name) || ++name != p)
abort();
}
}
return name;
}