1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
/* Subroutines for insn-output.c for NetWare.
Contributed by Jan Beulich (jbeulich@novell.com)
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#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"
/* Return string which is the former assembler name modified with an
underscore prefix and a suffix consisting of an atsign (@) followed
by the number of bytes of arguments */
static tree
gen_stdcall_or_fastcall_decoration (tree decl, char prefix)
{
unsigned total = 0;
/* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
of DECL_ASSEMBLER_NAME. */
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)
{
/* These attributes are ignored for variadic functions in
i386.c:ix86_return_pops_args. For compatibility with MS
compiler do not add @0 suffix here. */
if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
return NULL_TREE;
/* Quit if we hit an incomplete type. Error is reported
by convert_arguments in c-typeck.c or cp/typeck.c. */
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)));
/* Must round up to include padding. This is done the same
way as in store_one_arg. */
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));
}
/* Return string which is the former assembler name modified with an
_n@ prefix where n represents the number of arguments passed in
registers */
static tree
gen_regparm_prefix (tree decl, unsigned nregs)
{
unsigned total = 0;
/* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
of DECL_ASSEMBLER_NAME. */
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)
{
/* This attribute is ignored for variadic functions. */
if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
return NULL_TREE;
/* Quit if we hit an incomplete type. Error is reported
by convert_arguments in c-typeck.c or cp/typeck.c. */
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)));
/* Must round up to include padding. This is done the same
way as in store_one_arg. */
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;
gcc_assert (nregs <= 9);
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);
/* These attributes must be present on first declaration,
change_decl_assembler_name will warn if they are added
later and the decl has been referenced, but duplicate_decls
should catch the mismatch before this is called. */
change_decl_assembler_name (decl, newid);
}
}
}
/* Strip the stdcall/fastcall/regparm pre-/suffix. */
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
{
gcc_assert (ISDIGIT (*name));
name++;
gcc_assert (name == p);
}
}
}
return name;
}
|