#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 tree
gen_stdcall_or_fastcall_decoration (tree decl, char prefix)
{
unsigned total = 0;
const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (formal_type != NULL_TREE)
{
if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
return NULL_TREE;
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 get_identifier_with_length (newsym,
sprintf (newsym,
"%c%s@%u",
prefix,
asmname,
total / BITS_PER_UNIT));
}
static tree
gen_regparm_prefix (tree decl, unsigned nregs)
{
unsigned total = 0;
const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (formal_type != NULL_TREE)
{
if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
return NULL_TREE;
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 (3 + strlen (asmname) + 1);
return 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)) != '*'
&& !strchr (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), '@'))
{
tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
tree newid;
if (lookup_attribute ("stdcall", type_attributes))
newid = gen_stdcall_or_fastcall_decoration (decl, '_');
else if (lookup_attribute ("fastcall", type_attributes))
newid = gen_stdcall_or_fastcall_decoration (decl, FASTCALL_PREFIX);
else if ((newid = lookup_attribute ("regparm", type_attributes)) != NULL_TREE)
newid = gen_regparm_prefix (decl,
TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (newid))));
if (newid != NULL_TREE)
{
rtx rtlname = XEXP (rtl, 0);
if (GET_CODE (rtlname) == MEM)
rtlname = XEXP (rtlname, 0);
XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid);
change_decl_assembler_name (decl, newid);
}
}
}
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;
}