| 1 | /* emx.c: Functions for emx as target system.
|
|---|
| 2 |
|
|---|
| 3 | Written by Eberhard Mattes, based on i386.c.
|
|---|
| 4 |
|
|---|
| 5 | This file is part of GNU CC.
|
|---|
| 6 |
|
|---|
| 7 | GNU CC is free software; you can redistribute it and/or modify
|
|---|
| 8 | it under the terms of the GNU General Public License as published by
|
|---|
| 9 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 10 | any later version.
|
|---|
| 11 |
|
|---|
| 12 | GNU CC is distributed in the hope that it will be useful,
|
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 15 | GNU General Public License for more details.
|
|---|
| 16 |
|
|---|
| 17 | You should have received a copy of the GNU General Public License
|
|---|
| 18 | along with GNU CC; see the file COPYING. If not, write to
|
|---|
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330,
|
|---|
| 20 | Boston, MA 02111-1307, USA. */
|
|---|
| 21 |
|
|---|
| 22 | #include "config.h"
|
|---|
| 23 | #include "system.h"
|
|---|
| 24 | #include "rtl.h"
|
|---|
| 25 | #include "regs.h"
|
|---|
| 26 | #include "hard-reg-set.h"
|
|---|
| 27 | #include "output.h"
|
|---|
| 28 | #include "tree.h"
|
|---|
| 29 | #include "toplev.h"
|
|---|
| 30 | #include "flags.h"
|
|---|
| 31 |
|
|---|
| 32 | /* The size of the target's pointer type. */
|
|---|
| 33 | #ifndef PTR_SIZE
|
|---|
| 34 | #define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
|
|---|
| 35 | #endif
|
|---|
| 36 |
|
|---|
| 37 | extern int ix86_return_pops_args (tree fundecl, tree funtype, int size);
|
|---|
| 38 |
|
|---|
| 39 | tree ix86_handle_optlink_attribute (tree *node, tree name, tree args,
|
|---|
| 40 | int flags, bool *no_add_attrs)
|
|---|
| 41 | {
|
|---|
| 42 | (void)args; (void)flags;
|
|---|
| 43 | if (TREE_CODE (*node) != FUNCTION_TYPE
|
|---|
| 44 | && TREE_CODE (*node) != METHOD_TYPE
|
|---|
| 45 | && TREE_CODE (*node) != FIELD_DECL
|
|---|
| 46 | && TREE_CODE (*node) != TYPE_DECL)
|
|---|
| 47 | {
|
|---|
| 48 | warning ("`%s' attribute only applies to functions",
|
|---|
| 49 | IDENTIFIER_POINTER (name));
|
|---|
| 50 | *no_add_attrs = true;
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | return NULL_TREE;
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | /* Value is the number of bytes of arguments automatically
|
|---|
| 57 | popped when returning from a subroutine call.
|
|---|
| 58 | FUNDECL is the declaration node of the function (as a tree),
|
|---|
| 59 | FUNTYPE is the data type of the function (as a tree),
|
|---|
| 60 | or for a library call it is an identifier node for the subroutine name.
|
|---|
| 61 | SIZE is the number of bytes of arguments passed on the stack.
|
|---|
| 62 |
|
|---|
| 63 | On the 80386, the RTD insn may be used to pop them if the number
|
|---|
| 64 | of args is fixed, but if the number is variable then the caller
|
|---|
| 65 | must pop them all. RTD can't be used for library calls now
|
|---|
| 66 | because the library is compiled with the Unix compiler.
|
|---|
| 67 | Use of RTD is a selectable option, since it is incompatible with
|
|---|
| 68 | standard Unix calling sequences. If the option is not selected,
|
|---|
| 69 | the caller must always pop the args.
|
|---|
| 70 |
|
|---|
| 71 | The attribute stdcall is equivalent to RTD on a per module basis. */
|
|---|
| 72 |
|
|---|
| 73 | int
|
|---|
| 74 | emx_return_pops_args (fundecl, funtype, size)
|
|---|
| 75 | tree fundecl;
|
|---|
| 76 | tree funtype;
|
|---|
| 77 | int size;
|
|---|
| 78 | {
|
|---|
| 79 | return ix86_return_pops_args (fundecl, funtype, size);
|
|---|
| 80 | #if 0
|
|---|
| 81 | int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
|
|---|
| 82 |
|
|---|
| 83 | /* Cdecl functions override -mrtd, and never pop the stack */
|
|---|
| 84 | if (!lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))
|
|---|
| 85 | && !lookup_attribute ("system", TYPE_ATTRIBUTES (funtype)))
|
|---|
| 86 | {
|
|---|
| 87 | /* Stdcall functions will pop the stack if not variable args */
|
|---|
| 88 | if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
|
|---|
| 89 | rtd = 1;
|
|---|
| 90 |
|
|---|
| 91 | /* `optlink' functions taking a variable number of arguments
|
|---|
| 92 | should also pop the stack, but that's not implemented.
|
|---|
| 93 | We treat `optlink' functions taking a variable number of
|
|---|
| 94 | arguments like `system' functions. */
|
|---|
| 95 | if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (funtype)))
|
|---|
| 96 | rtd = 1;
|
|---|
| 97 |
|
|---|
| 98 | if (rtd
|
|---|
| 99 | && (TYPE_ARG_TYPES (funtype) == NULL_TREE
|
|---|
| 100 | || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)))
|
|---|
| 101 | return size;
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | /* Lose any fake structure return argument */
|
|---|
| 105 | /* @@@ This makes the generated code incompatible with that generated
|
|---|
| 106 | * by 2.7.2. I think this belongs in the if (rtd) ... case. Any ideas? */
|
|---|
| 107 | if (aggregate_value_p (TREE_TYPE (funtype)))
|
|---|
| 108 | return GET_MODE_SIZE (Pmode);
|
|---|
| 109 |
|
|---|
| 110 | return 0;
|
|---|
| 111 | #endif
|
|---|
| 112 | }
|
|---|
| 113 |
|
|---|
| 114 | void
|
|---|
| 115 | emx_eh_frame_section ()
|
|---|
| 116 | {
|
|---|
| 117 | /*
|
|---|
| 118 | tree label = get_file_function_name ('F');
|
|---|
| 119 | */
|
|---|
| 120 | data_section ();
|
|---|
| 121 | ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
|
|---|
| 122 | fprintf (asm_out_file, "\t.stabs\t\"___eh_frame__\",24,0,0,Lframe1\n");
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 | /* Add a __POST$xxx label before epilogue if -mepilogue specified */
|
|---|
| 126 | void emx_output_function_begin_epilogue (FILE *f)
|
|---|
| 127 | {
|
|---|
| 128 | if (TARGET_EPILOGUE && TREE_PUBLIC (current_function_decl))
|
|---|
| 129 | {
|
|---|
| 130 | const char *func_label = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
|
|---|
| 131 | char *lbl = alloca (strlen (func_label) + 8);
|
|---|
| 132 | strcpy (lbl, "__POST$");
|
|---|
| 133 | strcat (lbl, func_label);
|
|---|
| 134 | ASM_OUTPUT_LABEL (f, lbl);
|
|---|
| 135 | }
|
|---|
| 136 | }
|
|---|
| 137 |
|
|---|
| 138 | /* Return string which is the former assembler name modified with a
|
|---|
| 139 | suffix consisting of an atsign (@) followed by the number of bytes of
|
|---|
| 140 | arguments */
|
|---|
| 141 |
|
|---|
| 142 | const char *
|
|---|
| 143 | gen_stdcall_suffix (decl)
|
|---|
| 144 | tree decl;
|
|---|
| 145 | {
|
|---|
| 146 | int total = 0;
|
|---|
| 147 | /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
|
|---|
| 148 | of DECL_ASSEMBLER_NAME. */
|
|---|
| 149 | const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
|---|
| 150 | char *newsym;
|
|---|
| 151 |
|
|---|
| 152 | if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
|
|---|
| 153 | if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
|
|---|
| 154 | == void_type_node)
|
|---|
| 155 | {
|
|---|
| 156 | tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
|---|
| 157 |
|
|---|
| 158 | while (TREE_VALUE (formal_type) != void_type_node)
|
|---|
| 159 | {
|
|---|
| 160 | int parm_size
|
|---|
| 161 | = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
|
|---|
| 162 | /* Must round up to include padding. This is done the same
|
|---|
| 163 | way as in store_one_arg. */
|
|---|
| 164 | parm_size = ((parm_size + PARM_BOUNDARY - 1)
|
|---|
| 165 | / PARM_BOUNDARY * PARM_BOUNDARY);
|
|---|
| 166 | total += parm_size;
|
|---|
| 167 | formal_type = TREE_CHAIN (formal_type);
|
|---|
| 168 | }
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | newsym = xmalloc (strlen (asmname) + 10);
|
|---|
| 172 | sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT);
|
|---|
| 173 | return IDENTIFIER_POINTER (get_identifier (newsym));
|
|---|
| 174 | }
|
|---|
| 175 |
|
|---|
| 176 | const char *
|
|---|
| 177 | emx_remove_underscore (decl)
|
|---|
| 178 | tree decl;
|
|---|
| 179 | {
|
|---|
| 180 | /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
|
|---|
| 181 | of DECL_ASSEMBLER_NAME. */
|
|---|
| 182 | const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
|---|
| 183 | char *newsym = xmalloc (strlen (asmname) + 2);
|
|---|
| 184 | sprintf (newsym, "\b%s", asmname);
|
|---|
| 185 | return IDENTIFIER_POINTER (get_identifier (newsym));
|
|---|
| 186 | }
|
|---|
| 187 |
|
|---|
| 188 | /* Cover function to implement ENCODE_SECTION_INFO. */
|
|---|
| 189 |
|
|---|
| 190 | void
|
|---|
| 191 | emx_encode_section_info (tree decl)
|
|---|
| 192 | {
|
|---|
| 193 | /* This bit is copied from i386.h. */
|
|---|
| 194 | if (optimize > 0 && TREE_CONSTANT (decl)
|
|---|
| 195 | && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
|
|---|
| 196 | {
|
|---|
| 197 | rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
|
|---|
| 198 | ? TREE_CST_RTL (decl) : DECL_RTL (decl));
|
|---|
| 199 | SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
|
|---|
| 200 | }
|
|---|
| 201 |
|
|---|
| 202 | if (TREE_CODE (decl) == FUNCTION_DECL)
|
|---|
| 203 | if (lookup_attribute ("stdcall",
|
|---|
| 204 | TYPE_ATTRIBUTES (TREE_TYPE (decl))))
|
|---|
| 205 | XEXP (DECL_RTL (decl), 0) =
|
|---|
| 206 | gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
|
|---|
| 207 | else if (lookup_attribute ("optlink",
|
|---|
| 208 | TYPE_ATTRIBUTES (TREE_TYPE (decl)))
|
|---|
| 209 | || lookup_attribute ("system",
|
|---|
| 210 | TYPE_ATTRIBUTES (TREE_TYPE (decl))))
|
|---|
| 211 | XEXP (DECL_RTL (decl), 0) =
|
|---|
| 212 | gen_rtx (SYMBOL_REF, Pmode, emx_remove_underscore (decl));
|
|---|
| 213 | }
|
|---|