| 1 | --- a/gcc/builtins.c |
| 2 | +++ b/gcc/builtins.c |
| 3 | @@ -11108,7 +11108,7 @@ validate_gimple_arglist (const_gimple ca |
| 4 | |
| 5 | do |
| 6 | { |
| 7 | - code = va_arg (ap, enum tree_code); |
| 8 | + code = va_arg (ap, int); |
| 9 | switch (code) |
| 10 | { |
| 11 | case 0: |
| 12 | --- a/gcc/calls.c |
| 13 | +++ b/gcc/calls.c |
| 14 | @@ -3447,7 +3447,7 @@ emit_library_call_value_1 (int retval, r |
| 15 | for (; count < nargs; count++) |
| 16 | { |
| 17 | rtx val = va_arg (p, rtx); |
| 18 | - enum machine_mode mode = va_arg (p, enum machine_mode); |
| 19 | + enum machine_mode mode = va_arg (p, int); |
| 20 | |
| 21 | /* We cannot convert the arg value to the mode the library wants here; |
| 22 | must do it earlier where we know the signedness of the arg. */ |
| 23 | --- /dev/null |
| 24 | +++ b/gcc/config/avr32/avr32.c |
| 25 | @@ -0,0 +1,8060 @@ |
| 26 | +/* |
| 27 | + Target hooks and helper functions for AVR32. |
| 28 | + Copyright 2003,2004,2005,2006,2007,2008,2009,2010 Atmel Corporation. |
| 29 | + |
| 30 | + This file is part of GCC. |
| 31 | + |
| 32 | + This program is free software; you can redistribute it and/or modify |
| 33 | + it under the terms of the GNU General Public License as published by |
| 34 | + the Free Software Foundation; either version 2 of the License, or |
| 35 | + (at your option) any later version. |
| 36 | + |
| 37 | + This program is distributed in the hope that it will be useful, |
| 38 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 39 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 40 | + GNU General Public License for more details. |
| 41 | + |
| 42 | + You should have received a copy of the GNU General Public License |
| 43 | + along with this program; if not, write to the Free Software |
| 44 | + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 45 | + |
| 46 | +#include "config.h" |
| 47 | +#include "system.h" |
| 48 | +#include "coretypes.h" |
| 49 | +#include "tm.h" |
| 50 | +#include "rtl.h" |
| 51 | +#include "tree.h" |
| 52 | +#include "obstack.h" |
| 53 | +#include "regs.h" |
| 54 | +#include "hard-reg-set.h" |
| 55 | +#include "real.h" |
| 56 | +#include "insn-config.h" |
| 57 | +#include "conditions.h" |
| 58 | +#include "output.h" |
| 59 | +#include "insn-attr.h" |
| 60 | +#include "flags.h" |
| 61 | +#include "reload.h" |
| 62 | +#include "function.h" |
| 63 | +#include "expr.h" |
| 64 | +#include "optabs.h" |
| 65 | +#include "toplev.h" |
| 66 | +#include "recog.h" |
| 67 | +#include "ggc.h" |
| 68 | +#include "except.h" |
| 69 | +#include "c-pragma.h" |
| 70 | +#include "integrate.h" |
| 71 | +#include "tm_p.h" |
| 72 | +#include "langhooks.h" |
| 73 | +#include "hooks.h" |
| 74 | +#include "df.h" |
| 75 | + |
| 76 | +#include "target.h" |
| 77 | +#include "target-def.h" |
| 78 | + |
| 79 | +#include <ctype.h> |
| 80 | + |
| 81 | + |
| 82 | + |
| 83 | +/* Global variables. */ |
| 84 | +typedef struct minipool_node Mnode; |
| 85 | +typedef struct minipool_fixup Mfix; |
| 86 | + |
| 87 | +/* Obstack for minipool constant handling. */ |
| 88 | +static struct obstack minipool_obstack; |
| 89 | +static char *minipool_startobj; |
| 90 | +static rtx minipool_vector_label; |
| 91 | + |
| 92 | +/* True if we are currently building a constant table. */ |
| 93 | +int making_const_table; |
| 94 | + |
| 95 | +tree fndecl_attribute_args = NULL_TREE; |
| 96 | + |
| 97 | + |
| 98 | +/* Function prototypes. */ |
| 99 | +static unsigned long avr32_isr_value (tree); |
| 100 | +static unsigned long avr32_compute_func_type (void); |
| 101 | +static tree avr32_handle_isr_attribute (tree *, tree, tree, int, bool *); |
| 102 | +static tree avr32_handle_acall_attribute (tree *, tree, tree, int, bool *); |
| 103 | +static tree avr32_handle_fndecl_attribute (tree * node, tree name, tree args, |
| 104 | + int flags, bool * no_add_attrs); |
| 105 | +static void avr32_reorg (void); |
| 106 | +bool avr32_return_in_msb (tree type); |
| 107 | +bool avr32_vector_mode_supported (enum machine_mode mode); |
| 108 | +static void avr32_init_libfuncs (void); |
| 109 | +static void avr32_file_end (void); |
| 110 | +static void flashvault_decl_list_add (unsigned int vector_num, const char *name); |
| 111 | + |
| 112 | + |
| 113 | + |
| 114 | +static void |
| 115 | +avr32_add_gc_roots (void) |
| 116 | +{ |
| 117 | + gcc_obstack_init (&minipool_obstack); |
| 118 | + minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0); |
| 119 | +} |
| 120 | + |
| 121 | + |
| 122 | +/* List of all known AVR32 parts */ |
| 123 | +static const struct part_type_s avr32_part_types[] = { |
| 124 | + /* name, part_type, architecture type, macro */ |
| 125 | + {"none", PART_TYPE_AVR32_NONE, ARCH_TYPE_AVR32_AP, "__AVR32__"}, |
| 126 | + {"ap7000", PART_TYPE_AVR32_AP7000, ARCH_TYPE_AVR32_AP, "__AVR32_AP7000__"}, |
| 127 | + {"ap7001", PART_TYPE_AVR32_AP7001, ARCH_TYPE_AVR32_AP, "__AVR32_AP7001__"}, |
| 128 | + {"ap7002", PART_TYPE_AVR32_AP7002, ARCH_TYPE_AVR32_AP, "__AVR32_AP7002__"}, |
| 129 | + {"ap7200", PART_TYPE_AVR32_AP7200, ARCH_TYPE_AVR32_AP, "__AVR32_AP7200__"}, |
| 130 | + {"uc3a0128", PART_TYPE_AVR32_UC3A0128, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A0128__"}, |
| 131 | + {"uc3a0256", PART_TYPE_AVR32_UC3A0256, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A0256__"}, |
| 132 | + {"uc3a0512", PART_TYPE_AVR32_UC3A0512, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A0512__"}, |
| 133 | + {"uc3a0512es", PART_TYPE_AVR32_UC3A0512ES, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3A0512ES__"}, |
| 134 | + {"uc3a1128", PART_TYPE_AVR32_UC3A1128, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A1128__"}, |
| 135 | + {"uc3a1256", PART_TYPE_AVR32_UC3A1256, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A1256__"}, |
| 136 | + {"uc3a1512", PART_TYPE_AVR32_UC3A1512, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A1512__"}, |
| 137 | + {"uc3a1512es", PART_TYPE_AVR32_UC3A1512ES, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3A1512ES__"}, |
| 138 | + {"uc3a3revd", PART_TYPE_AVR32_UC3A3REVD, ARCH_TYPE_AVR32_UCR2NOMUL, "__AVR32_UC3A3256S__"}, |
| 139 | + {"uc3a364", PART_TYPE_AVR32_UC3A364, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A364__"}, |
| 140 | + {"uc3a364s", PART_TYPE_AVR32_UC3A364S, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A364S__"}, |
| 141 | + {"uc3a3128", PART_TYPE_AVR32_UC3A3128, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A3128__"}, |
| 142 | + {"uc3a3128s", PART_TYPE_AVR32_UC3A3128S, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A3128S__"}, |
| 143 | + {"uc3a3256", PART_TYPE_AVR32_UC3A3256, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A3256__"}, |
| 144 | + {"uc3a3256s", PART_TYPE_AVR32_UC3A3256S, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A3256S__"}, |
| 145 | + {"uc3a464", PART_TYPE_AVR32_UC3A464, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A464__"}, |
| 146 | + {"uc3a464s", PART_TYPE_AVR32_UC3A464S, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A464S__"}, |
| 147 | + {"uc3a4128", PART_TYPE_AVR32_UC3A4128, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A4128__"}, |
| 148 | + {"uc3a4128s", PART_TYPE_AVR32_UC3A4128S, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A4128S__"}, |
| 149 | + {"uc3a4256", PART_TYPE_AVR32_UC3A4256, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A4256__"}, |
| 150 | + {"uc3a4256s", PART_TYPE_AVR32_UC3A4256S, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3A4256S__"}, |
| 151 | + {"uc3b064", PART_TYPE_AVR32_UC3B064, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B064__"}, |
| 152 | + {"uc3b0128", PART_TYPE_AVR32_UC3B0128, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B0128__"}, |
| 153 | + {"uc3b0256", PART_TYPE_AVR32_UC3B0256, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B0256__"}, |
| 154 | + {"uc3b0256es", PART_TYPE_AVR32_UC3B0256ES, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B0256ES__"}, |
| 155 | + {"uc3b0512", PART_TYPE_AVR32_UC3B0512, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3B0512__"}, |
| 156 | + {"uc3b0512revc", PART_TYPE_AVR32_UC3B0512REVC, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3B0512REVC__"}, |
| 157 | + {"uc3b164", PART_TYPE_AVR32_UC3B164, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B164__"}, |
| 158 | + {"uc3b1128", PART_TYPE_AVR32_UC3B1128, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B1128__"}, |
| 159 | + {"uc3b1256", PART_TYPE_AVR32_UC3B1256, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B1256__"}, |
| 160 | + {"uc3b1256es", PART_TYPE_AVR32_UC3B1256ES, ARCH_TYPE_AVR32_UCR1, "__AVR32_UC3B1256ES__"}, |
| 161 | + {"uc3b1512", PART_TYPE_AVR32_UC3B1512, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3B1512__"}, |
| 162 | + {"uc3b1512revc", PART_TYPE_AVR32_UC3B1512REVC, ARCH_TYPE_AVR32_UCR2, "__AVR32_UC3B1512REVC__"}, |
| 163 | + {"uc64d3", PART_TYPE_AVR32_UC64D3, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC64D3__"}, |
| 164 | + {"uc128d3", PART_TYPE_AVR32_UC128D3, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC128D3__"}, |
| 165 | + {"uc64d4", PART_TYPE_AVR32_UC64D4, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC64D4__"}, |
| 166 | + {"uc128d4", PART_TYPE_AVR32_UC128D4, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC128D4__"}, |
| 167 | + {"uc3c0512crevc", PART_TYPE_AVR32_UC3C0512CREVC, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3C0512CREVC__"}, |
| 168 | + {"uc3c1512crevc", PART_TYPE_AVR32_UC3C1512CREVC, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3C1512CREVC__"}, |
| 169 | + {"uc3c2512crevc", PART_TYPE_AVR32_UC3C2512CREVC, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3C2512CREVC__"}, |
| 170 | + {"uc3l0256", PART_TYPE_AVR32_UC3L0256, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3L0256__"}, |
| 171 | + {"uc3l0128", PART_TYPE_AVR32_UC3L0128, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3L0128__"}, |
| 172 | + {"uc3l064", PART_TYPE_AVR32_UC3L064, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3L064__"}, |
| 173 | + {"uc3l032", PART_TYPE_AVR32_UC3L032, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3L032__"}, |
| 174 | + {"uc3l016", PART_TYPE_AVR32_UC3L016, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3L016__"}, |
| 175 | + {"uc3l064revb", PART_TYPE_AVR32_UC3L064REVB, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC3L064REVB__"}, |
| 176 | + {"uc64l3u", PART_TYPE_AVR32_UC64L3U, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC64L3U__"}, |
| 177 | + {"uc128l3u", PART_TYPE_AVR32_UC128L3U, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC128L3U__"}, |
| 178 | + {"uc256l3u", PART_TYPE_AVR32_UC256L3U, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC256L3U__"}, |
| 179 | + {"uc64l4u", PART_TYPE_AVR32_UC64L4U, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC64L4U__"}, |
| 180 | + {"uc128l4u", PART_TYPE_AVR32_UC128L4U, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC128L4U__"}, |
| 181 | + {"uc256l4u", PART_TYPE_AVR32_UC256L4U, ARCH_TYPE_AVR32_UCR3, "__AVR32_UC256L4U__"}, |
| 182 | + {"uc3c064c", PART_TYPE_AVR32_UC3C064C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C064C__"}, |
| 183 | + {"uc3c0128c", PART_TYPE_AVR32_UC3C0128C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C0128C__"}, |
| 184 | + {"uc3c0256c", PART_TYPE_AVR32_UC3C0256C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C0256C__"}, |
| 185 | + {"uc3c0512c", PART_TYPE_AVR32_UC3C0512C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C0512C__"}, |
| 186 | + {"uc3c164c", PART_TYPE_AVR32_UC3C164C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C164C__"}, |
| 187 | + {"uc3c1128c", PART_TYPE_AVR32_UC3C1128C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C1128C__"}, |
| 188 | + {"uc3c1256c", PART_TYPE_AVR32_UC3C1256C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C1256C__"}, |
| 189 | + {"uc3c1512c", PART_TYPE_AVR32_UC3C1512C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C1512C__"}, |
| 190 | + {"uc3c264c", PART_TYPE_AVR32_UC3C264C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C264C__"}, |
| 191 | + {"uc3c2128c", PART_TYPE_AVR32_UC3C2128C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C2128C__"}, |
| 192 | + {"uc3c2256c", PART_TYPE_AVR32_UC3C2256C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C2256C__"}, |
| 193 | + {"uc3c2512c", PART_TYPE_AVR32_UC3C2512C, ARCH_TYPE_AVR32_UCR3FP, "__AVR32_UC3C2512C__"}, |
| 194 | + {"mxt768e", PART_TYPE_AVR32_MXT768E, ARCH_TYPE_AVR32_UCR3, "__AVR32_MXT768E__"}, |
| 195 | + {NULL, 0, 0, NULL} |
| 196 | +}; |
| 197 | + |
| 198 | +/* List of all known AVR32 architectures */ |
| 199 | +static const struct arch_type_s avr32_arch_types[] = { |
| 200 | + /* name, architecture type, microarchitecture type, feature flags, macro */ |
| 201 | + {"ap", ARCH_TYPE_AVR32_AP, UARCH_TYPE_AVR32B, |
| 202 | + (FLAG_AVR32_HAS_DSP |
| 203 | + | FLAG_AVR32_HAS_SIMD |
| 204 | + | FLAG_AVR32_HAS_UNALIGNED_WORD |
| 205 | + | FLAG_AVR32_HAS_BRANCH_PRED | FLAG_AVR32_HAS_RETURN_STACK |
| 206 | + | FLAG_AVR32_HAS_CACHES), |
| 207 | + "__AVR32_AP__"}, |
| 208 | + {"ucr1", ARCH_TYPE_AVR32_UCR1, UARCH_TYPE_AVR32A, |
| 209 | + (FLAG_AVR32_HAS_DSP | FLAG_AVR32_HAS_RMW), |
| 210 | + "__AVR32_UC__=1"}, |
| 211 | + {"ucr2", ARCH_TYPE_AVR32_UCR2, UARCH_TYPE_AVR32A, |
| 212 | + (FLAG_AVR32_HAS_DSP | FLAG_AVR32_HAS_RMW |
| 213 | + | FLAG_AVR32_HAS_V2_INSNS), |
| 214 | + "__AVR32_UC__=2"}, |
| 215 | + {"ucr2nomul", ARCH_TYPE_AVR32_UCR2NOMUL, UARCH_TYPE_AVR32A, |
| 216 | + (FLAG_AVR32_HAS_DSP | FLAG_AVR32_HAS_RMW |
| 217 | + | FLAG_AVR32_HAS_V2_INSNS | FLAG_AVR32_HAS_NO_MUL_INSNS), |
| 218 | + "__AVR32_UC__=2"}, |
| 219 | + {"ucr3", ARCH_TYPE_AVR32_UCR3, UARCH_TYPE_AVR32A, |
| 220 | + (FLAG_AVR32_HAS_DSP | FLAG_AVR32_HAS_RMW |
| 221 | + | FLAG_AVR32_HAS_V2_INSNS), |
| 222 | + "__AVR32_UC__=3"}, |
| 223 | + {"ucr3fp", ARCH_TYPE_AVR32_UCR3FP, UARCH_TYPE_AVR32A, |
| 224 | + (FLAG_AVR32_HAS_DSP | FLAG_AVR32_HAS_RMW | FLAG_AVR32_HAS_FPU |
| 225 | + | FLAG_AVR32_HAS_V2_INSNS), |
| 226 | + "__AVR32_UC__=3"}, |
| 227 | + {NULL, 0, 0, 0, NULL} |
| 228 | +}; |
| 229 | + |
| 230 | +/* Default arch name */ |
| 231 | +const char *avr32_arch_name = "none"; |
| 232 | +const char *avr32_part_name = "none"; |
| 233 | + |
| 234 | +const struct part_type_s *avr32_part; |
| 235 | +const struct arch_type_s *avr32_arch; |
| 236 | + |
| 237 | + |
| 238 | +/* FIXME: needs to use GC. */ |
| 239 | +struct flashvault_decl_list |
| 240 | +{ |
| 241 | + struct flashvault_decl_list *next; |
| 242 | + unsigned int vector_num; |
| 243 | + const char *name; |
| 244 | +}; |
| 245 | + |
| 246 | +static struct flashvault_decl_list *flashvault_decl_list_head = NULL; |
| 247 | + |
| 248 | + |
| 249 | +/* Set default target_flags. */ |
| 250 | +#undef TARGET_DEFAULT_TARGET_FLAGS |
| 251 | +#define TARGET_DEFAULT_TARGET_FLAGS \ |
| 252 | + (MASK_HAS_ASM_ADDR_PSEUDOS | MASK_MD_REORG_OPTIMIZATION | MASK_COND_EXEC_BEFORE_RELOAD) |
| 253 | + |
| 254 | +void |
| 255 | +avr32_optimization_options (int level, int size) |
| 256 | +{ |
| 257 | + if (AVR32_ALWAYS_PIC) |
| 258 | + flag_pic = 1; |
| 259 | + |
| 260 | + /* Enable section anchors if optimization is enabled. */ |
| 261 | + if (level > 0 || size) |
| 262 | + flag_section_anchors = 2; |
| 263 | +} |
| 264 | + |
| 265 | + |
| 266 | +/* Override command line options */ |
| 267 | +void |
| 268 | +avr32_override_options (void) |
| 269 | +{ |
| 270 | + const struct part_type_s *part; |
| 271 | + const struct arch_type_s *arch; |
| 272 | + |
| 273 | + /*Add backward compability*/ |
| 274 | + if (strcmp ("uc", avr32_arch_name)== 0) |
| 275 | + { |
| 276 | + fprintf (stderr, "Warning: Deprecated arch `%s' specified. " |
| 277 | + "Please use '-march=ucr1' instead. " |
| 278 | + "Converting to arch 'ucr1'\n", |
| 279 | + avr32_arch_name); |
| 280 | + avr32_arch_name="ucr1"; |
| 281 | + } |
| 282 | + |
| 283 | + /* Check if arch type is set. */ |
| 284 | + for (arch = avr32_arch_types; arch->name; arch++) |
| 285 | + { |
| 286 | + if (strcmp (arch->name, avr32_arch_name) == 0) |
| 287 | + break; |
| 288 | + } |
| 289 | + avr32_arch = arch; |
| 290 | + |
| 291 | + if (!arch->name && strcmp("none", avr32_arch_name) != 0) |
| 292 | + { |
| 293 | + fprintf (stderr, "Unknown arch `%s' specified\n" |
| 294 | + "Known arch names:\n" |
| 295 | + "\tuc (deprecated)\n", |
| 296 | + avr32_arch_name); |
| 297 | + for (arch = avr32_arch_types; arch->name; arch++) |
| 298 | + fprintf (stderr, "\t%s\n", arch->name); |
| 299 | + avr32_arch = &avr32_arch_types[ARCH_TYPE_AVR32_AP]; |
| 300 | + } |
| 301 | + |
| 302 | + /* Check if part type is set. */ |
| 303 | + for (part = avr32_part_types; part->name; part++) |
| 304 | + if (strcmp (part->name, avr32_part_name) == 0) |
| 305 | + break; |
| 306 | + |
| 307 | + avr32_part = part; |
| 308 | + if (!part->name) |
| 309 | + { |
| 310 | + fprintf (stderr, "Unknown part `%s' specified\nKnown part names:\n", |
| 311 | + avr32_part_name); |
| 312 | + for (part = avr32_part_types; part->name; part++) |
| 313 | + { |
| 314 | + if (strcmp("none", part->name) != 0) |
| 315 | + fprintf (stderr, "\t%s\n", part->name); |
| 316 | + } |
| 317 | + /* Set default to NONE*/ |
| 318 | + avr32_part = &avr32_part_types[PART_TYPE_AVR32_NONE]; |
| 319 | + } |
| 320 | + |
| 321 | + /* NB! option -march= overrides option -mpart |
| 322 | + * if both are used at the same time */ |
| 323 | + if (!arch->name) |
| 324 | + avr32_arch = &avr32_arch_types[avr32_part->arch_type]; |
| 325 | + |
| 326 | + /* If optimization level is two or greater, then align start of loops to a |
| 327 | + word boundary since this will allow folding the first insn of the loop. |
| 328 | + Do this only for targets supporting branch prediction. */ |
| 329 | + if (optimize >= 2 && TARGET_BRANCH_PRED) |
| 330 | + align_loops = 2; |
| 331 | + |
| 332 | + |
| 333 | + /* Enable fast-float library if unsafe math optimizations |
| 334 | + are used. */ |
| 335 | + if (flag_unsafe_math_optimizations) |
| 336 | + target_flags |= MASK_FAST_FLOAT; |
| 337 | + |
| 338 | + /* Check if we should set avr32_imm_in_const_pool |
| 339 | + based on if caches are present or not. */ |
| 340 | + if ( avr32_imm_in_const_pool == -1 ) |
| 341 | + { |
| 342 | + if ( TARGET_CACHES ) |
| 343 | + avr32_imm_in_const_pool = 1; |
| 344 | + else |
| 345 | + avr32_imm_in_const_pool = 0; |
| 346 | + } |
| 347 | + |
| 348 | + if (TARGET_NO_PIC) |
| 349 | + flag_pic = 0; |
| 350 | + avr32_add_gc_roots (); |
| 351 | +} |
| 352 | + |
| 353 | + |
| 354 | +/* |
| 355 | +If defined, a function that outputs the assembler code for entry to a |
| 356 | +function. The prologue is responsible for setting up the stack frame, |
| 357 | +initializing the frame pointer register, saving registers that must be |
| 358 | +saved, and allocating size additional bytes of storage for the |
| 359 | +local variables. size is an integer. file is a stdio |
| 360 | +stream to which the assembler code should be output. |
| 361 | + |
| 362 | +The label for the beginning of the function need not be output by this |
| 363 | +macro. That has already been done when the macro is run. |
| 364 | + |
| 365 | +To determine which registers to save, the macro can refer to the array |
| 366 | +regs_ever_live: element r is nonzero if hard register |
| 367 | +r is used anywhere within the function. This implies the function |
| 368 | +prologue should save register r, provided it is not one of the |
| 369 | +call-used registers. (TARGET_ASM_FUNCTION_EPILOGUE must likewise use |
| 370 | +regs_ever_live.) |
| 371 | + |
| 372 | +On machines that have ``register windows'', the function entry code does |
| 373 | +not save on the stack the registers that are in the windows, even if |
| 374 | +they are supposed to be preserved by function calls; instead it takes |
| 375 | +appropriate steps to ``push'' the register stack, if any non-call-used |
| 376 | +registers are used in the function. |
| 377 | + |
| 378 | +On machines where functions may or may not have frame-pointers, the |
| 379 | +function entry code must vary accordingly; it must set up the frame |
| 380 | +pointer if one is wanted, and not otherwise. To determine whether a |
| 381 | +frame pointer is in wanted, the macro can refer to the variable |
| 382 | +frame_pointer_needed. The variable's value will be 1 at run |
| 383 | +time in a function that needs a frame pointer. (see Elimination). |
| 384 | + |
| 385 | +The function entry code is responsible for allocating any stack space |
| 386 | +required for the function. This stack space consists of the regions |
| 387 | +listed below. In most cases, these regions are allocated in the |
| 388 | +order listed, with the last listed region closest to the top of the |
| 389 | +stack (the lowest address if STACK_GROWS_DOWNWARD is defined, and |
| 390 | +the highest address if it is not defined). You can use a different order |
| 391 | +for a machine if doing so is more convenient or required for |
| 392 | +compatibility reasons. Except in cases where required by standard |
| 393 | +or by a debugger, there is no reason why the stack layout used by GCC |
| 394 | +need agree with that used by other compilers for a machine. |
| 395 | +*/ |
| 396 | + |
| 397 | +#undef TARGET_ASM_FUNCTION_PROLOGUE |
| 398 | +#define TARGET_ASM_FUNCTION_PROLOGUE avr32_target_asm_function_prologue |
| 399 | + |
| 400 | +#undef TARGET_ASM_FILE_END |
| 401 | +#define TARGET_ASM_FILE_END avr32_file_end |
| 402 | + |
| 403 | +#undef TARGET_DEFAULT_SHORT_ENUMS |
| 404 | +#define TARGET_DEFAULT_SHORT_ENUMS hook_bool_void_false |
| 405 | + |
| 406 | +#undef TARGET_PROMOTE_FUNCTION_ARGS |
| 407 | +#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true |
| 408 | + |
| 409 | +#undef TARGET_PROMOTE_FUNCTION_RETURN |
| 410 | +#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true |
| 411 | + |
| 412 | +#undef TARGET_PROMOTE_PROTOTYPES |
| 413 | +#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true |
| 414 | + |
| 415 | +#undef TARGET_MUST_PASS_IN_STACK |
| 416 | +#define TARGET_MUST_PASS_IN_STACK avr32_must_pass_in_stack |
| 417 | + |
| 418 | +#undef TARGET_PASS_BY_REFERENCE |
| 419 | +#define TARGET_PASS_BY_REFERENCE avr32_pass_by_reference |
| 420 | + |
| 421 | +#undef TARGET_STRICT_ARGUMENT_NAMING |
| 422 | +#define TARGET_STRICT_ARGUMENT_NAMING avr32_strict_argument_naming |
| 423 | + |
| 424 | +#undef TARGET_VECTOR_MODE_SUPPORTED_P |
| 425 | +#define TARGET_VECTOR_MODE_SUPPORTED_P avr32_vector_mode_supported |
| 426 | + |
| 427 | +#undef TARGET_RETURN_IN_MEMORY |
| 428 | +#define TARGET_RETURN_IN_MEMORY avr32_return_in_memory |
| 429 | + |
| 430 | +#undef TARGET_RETURN_IN_MSB |
| 431 | +#define TARGET_RETURN_IN_MSB avr32_return_in_msb |
| 432 | + |
| 433 | +#undef TARGET_ENCODE_SECTION_INFO |
| 434 | +#define TARGET_ENCODE_SECTION_INFO avr32_encode_section_info |
| 435 | + |
| 436 | +#undef TARGET_ARG_PARTIAL_BYTES |
| 437 | +#define TARGET_ARG_PARTIAL_BYTES avr32_arg_partial_bytes |
| 438 | + |
| 439 | +#undef TARGET_STRIP_NAME_ENCODING |
| 440 | +#define TARGET_STRIP_NAME_ENCODING avr32_strip_name_encoding |
| 441 | + |
| 442 | +#define streq(string1, string2) (strcmp (string1, string2) == 0) |
| 443 | + |
| 444 | +#undef TARGET_NARROW_VOLATILE_BITFIELD |
| 445 | +#define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false |
| 446 | + |
| 447 | +#undef TARGET_ATTRIBUTE_TABLE |
| 448 | +#define TARGET_ATTRIBUTE_TABLE avr32_attribute_table |
| 449 | + |
| 450 | +#undef TARGET_COMP_TYPE_ATTRIBUTES |
| 451 | +#define TARGET_COMP_TYPE_ATTRIBUTES avr32_comp_type_attributes |
| 452 | + |
| 453 | + |
| 454 | +#undef TARGET_RTX_COSTS |
| 455 | +#define TARGET_RTX_COSTS avr32_rtx_costs |
| 456 | + |
| 457 | +#undef TARGET_CANNOT_FORCE_CONST_MEM |
| 458 | +#define TARGET_CANNOT_FORCE_CONST_MEM avr32_cannot_force_const_mem |
| 459 | + |
| 460 | +#undef TARGET_ASM_INTEGER |
| 461 | +#define TARGET_ASM_INTEGER avr32_assemble_integer |
| 462 | + |
| 463 | +#undef TARGET_FUNCTION_VALUE |
| 464 | +#define TARGET_FUNCTION_VALUE avr32_function_value |
| 465 | + |
| 466 | +#undef TARGET_MIN_ANCHOR_OFFSET |
| 467 | +#define TARGET_MIN_ANCHOR_OFFSET (0) |
| 468 | + |
| 469 | +#undef TARGET_MAX_ANCHOR_OFFSET |
| 470 | +#define TARGET_MAX_ANCHOR_OFFSET ((1 << 15) - 1) |
| 471 | +#undef TARGET_SECONDARY_RELOAD |
| 472 | +#define TARGET_SECONDARY_RELOAD avr32_secondary_reload |
| 473 | + |
| 474 | + |
| 475 | +/* |
| 476 | + * Defining the option, -mlist-devices to list the devices supported by gcc. |
| 477 | + * This option should be used while printing target-help to list all the |
| 478 | + * supported devices. |
| 479 | + */ |
| 480 | +#undef TARGET_HELP |
| 481 | +#define TARGET_HELP avr32_target_help |
| 482 | + |
| 483 | +void avr32_target_help () |
| 484 | +{ |
| 485 | + if (avr32_list_supported_parts) |
| 486 | + { |
| 487 | + const struct part_type_s *list; |
| 488 | + fprintf (stdout, "List of parts supported by avr32-gcc:\n"); |
| 489 | + for (list = avr32_part_types; list->name; list++) |
| 490 | + { |
| 491 | + if (strcmp("none", list->name) != 0) |
| 492 | + fprintf (stdout, "%-20s%s\n", list->name, list->macro); |
| 493 | + } |
| 494 | + fprintf (stdout, "\n\n"); |
| 495 | + } |
| 496 | +} |
| 497 | + |
| 498 | +enum reg_class |
| 499 | +avr32_secondary_reload (bool in_p, rtx x, enum reg_class class, |
| 500 | + enum machine_mode mode, secondary_reload_info *sri) |
| 501 | +{ |
| 502 | + |
| 503 | + if ( avr32_rmw_memory_operand (x, mode) ) |
| 504 | + { |
| 505 | + if (!in_p) |
| 506 | + sri->icode = CODE_FOR_reload_out_rmw_memory_operand; |
| 507 | + else |
| 508 | + sri->icode = CODE_FOR_reload_in_rmw_memory_operand; |
| 509 | + } |
| 510 | + return NO_REGS; |
| 511 | + |
| 512 | +} |
| 513 | +/* |
| 514 | + * Switches to the appropriate section for output of constant pool |
| 515 | + * entry x in mode. You can assume that x is some kind of constant in |
| 516 | + * RTL. The argument mode is redundant except in the case of a |
| 517 | + * const_int rtx. Select the section by calling readonly_data_ section |
| 518 | + * or one of the alternatives for other sections. align is the |
| 519 | + * constant alignment in bits. |
| 520 | + * |
| 521 | + * The default version of this function takes care of putting symbolic |
| 522 | + * constants in flag_ pic mode in data_section and everything else in |
| 523 | + * readonly_data_section. |
| 524 | + */ |
| 525 | +//#undef TARGET_ASM_SELECT_RTX_SECTION |
| 526 | +//#define TARGET_ASM_SELECT_RTX_SECTION avr32_select_rtx_section |
| 527 | + |
| 528 | + |
| 529 | +/* |
| 530 | + * If non-null, this hook performs a target-specific pass over the |
| 531 | + * instruction stream. The compiler will run it at all optimization |
| 532 | + * levels, just before the point at which it normally does |
| 533 | + * delayed-branch scheduling. |
| 534 | + * |
| 535 | + * The exact purpose of the hook varies from target to target. Some |
| 536 | + * use it to do transformations that are necessary for correctness, |
| 537 | + * such as laying out in-function constant pools or avoiding hardware |
| 538 | + * hazards. Others use it as an opportunity to do some |
| 539 | + * machine-dependent optimizations. |
| 540 | + * |
| 541 | + * You need not implement the hook if it has nothing to do. The |
| 542 | + * default definition is null. |
| 543 | + */ |
| 544 | +#undef TARGET_MACHINE_DEPENDENT_REORG |
| 545 | +#define TARGET_MACHINE_DEPENDENT_REORG avr32_reorg |
| 546 | + |
| 547 | +/* Target hook for assembling integer objects. |
| 548 | + Need to handle integer vectors */ |
| 549 | +static bool |
| 550 | +avr32_assemble_integer (rtx x, unsigned int size, int aligned_p) |
| 551 | +{ |
| 552 | + if (avr32_vector_mode_supported (GET_MODE (x))) |
| 553 | + { |
| 554 | + int i, units; |
| 555 | + |
| 556 | + if (GET_CODE (x) != CONST_VECTOR) |
| 557 | + abort (); |
| 558 | + |
| 559 | + units = CONST_VECTOR_NUNITS (x); |
| 560 | + |
| 561 | + switch (GET_MODE (x)) |
| 562 | + { |
| 563 | + case V2HImode: |
| 564 | + size = 2; |
| 565 | + break; |
| 566 | + case V4QImode: |
| 567 | + size = 1; |
| 568 | + break; |
| 569 | + default: |
| 570 | + abort (); |
| 571 | + } |
| 572 | + |
| 573 | + for (i = 0; i < units; i++) |
| 574 | + { |
| 575 | + rtx elt; |
| 576 | + |
| 577 | + elt = CONST_VECTOR_ELT (x, i); |
| 578 | + assemble_integer (elt, size, i == 0 ? 32 : size * BITS_PER_UNIT, 1); |
| 579 | + } |
| 580 | + |
| 581 | + return true; |
| 582 | + } |
| 583 | + |
| 584 | + return default_assemble_integer (x, size, aligned_p); |
| 585 | +} |
| 586 | + |
| 587 | + |
| 588 | +/* |
| 589 | + * This target hook describes the relative costs of RTL expressions. |
| 590 | + * |
| 591 | + * The cost may depend on the precise form of the expression, which is |
| 592 | + * available for examination in x, and the rtx code of the expression |
| 593 | + * in which it is contained, found in outer_code. code is the |
| 594 | + * expression code--redundant, since it can be obtained with GET_CODE |
| 595 | + * (x). |
| 596 | + * |
| 597 | + * In implementing this hook, you can use the construct COSTS_N_INSNS |
| 598 | + * (n) to specify a cost equal to n fast instructions. |
| 599 | + * |
| 600 | + * On entry to the hook, *total contains a default estimate for the |
| 601 | + * cost of the expression. The hook should modify this value as |
| 602 | + * necessary. Traditionally, the default costs are COSTS_N_INSNS (5) |
| 603 | + * for multiplications, COSTS_N_INSNS (7) for division and modulus |
| 604 | + * operations, and COSTS_N_INSNS (1) for all other operations. |
| 605 | + * |
| 606 | + * When optimizing for code size, i.e. when optimize_size is non-zero, |
| 607 | + * this target hook should be used to estimate the relative size cost |
| 608 | + * of an expression, again relative to COSTS_N_INSNS. |
| 609 | + * |
| 610 | + * The hook returns true when all subexpressions of x have been |
| 611 | + * processed, and false when rtx_cost should recurse. |
| 612 | + */ |
| 613 | + |
| 614 | +/* Worker routine for avr32_rtx_costs. */ |
| 615 | +static inline int |
| 616 | +avr32_rtx_costs_1 (rtx x, enum rtx_code code ATTRIBUTE_UNUSED, |
| 617 | + enum rtx_code outer ATTRIBUTE_UNUSED) |
| 618 | +{ |
| 619 | + enum machine_mode mode = GET_MODE (x); |
| 620 | + |
| 621 | + switch (GET_CODE (x)) |
| 622 | + { |
| 623 | + case MEM: |
| 624 | + /* Using pre decrement / post increment memory operations on the |
| 625 | + avr32_uc architecture means that two writebacks must be performed |
| 626 | + and hence two cycles are needed. */ |
| 627 | + if (!optimize_size |
| 628 | + && GET_MODE_SIZE (mode) <= 2 * UNITS_PER_WORD |
| 629 | + && TARGET_ARCH_UC |
| 630 | + && (GET_CODE (XEXP (x, 0)) == PRE_DEC |
| 631 | + || GET_CODE (XEXP (x, 0)) == POST_INC)) |
| 632 | + return COSTS_N_INSNS (5); |
| 633 | + |
| 634 | + /* Memory costs quite a lot for the first word, but subsequent words |
| 635 | + load at the equivalent of a single insn each. */ |
| 636 | + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) |
| 637 | + return COSTS_N_INSNS (3 + (GET_MODE_SIZE (mode) / UNITS_PER_WORD)); |
| 638 | + |
| 639 | + return COSTS_N_INSNS (4); |
| 640 | + case SYMBOL_REF: |
| 641 | + case CONST: |
| 642 | + /* These are valid for the pseudo insns: lda.w and call which operates |
| 643 | + on direct addresses. We assume that the cost of a lda.w is the same |
| 644 | + as the cost of a ld.w insn. */ |
| 645 | + return (outer == SET) ? COSTS_N_INSNS (4) : COSTS_N_INSNS (1); |
| 646 | + case DIV: |
| 647 | + case MOD: |
| 648 | + case UDIV: |
| 649 | + case UMOD: |
| 650 | + return optimize_size ? COSTS_N_INSNS (1) : COSTS_N_INSNS (16); |
| 651 | + |
| 652 | + case ROTATE: |
| 653 | + case ROTATERT: |
| 654 | + if (mode == TImode) |
| 655 | + return COSTS_N_INSNS (100); |
| 656 | + |
| 657 | + if (mode == DImode) |
| 658 | + return COSTS_N_INSNS (10); |
| 659 | + return COSTS_N_INSNS (4); |
| 660 | + case ASHIFT: |
| 661 | + case LSHIFTRT: |
| 662 | + case ASHIFTRT: |
| 663 | + case NOT: |
| 664 | + if (mode == TImode) |
| 665 | + return COSTS_N_INSNS (10); |
| 666 | + |
| 667 | + if (mode == DImode) |
| 668 | + return COSTS_N_INSNS (4); |
| 669 | + return COSTS_N_INSNS (1); |
| 670 | + case PLUS: |
| 671 | + case MINUS: |
| 672 | + case NEG: |
| 673 | + case COMPARE: |
| 674 | + case ABS: |
| 675 | + if (GET_MODE_CLASS (mode) == MODE_FLOAT) |
| 676 | + return COSTS_N_INSNS (100); |
| 677 | + |
| 678 | + if (mode == TImode) |
| 679 | + return COSTS_N_INSNS (50); |
| 680 | + |
| 681 | + if (mode == DImode) |
| 682 | + return COSTS_N_INSNS (2); |
| 683 | + return COSTS_N_INSNS (1); |
| 684 | + |
| 685 | + case MULT: |
| 686 | + { |
| 687 | + if (GET_MODE_CLASS (mode) == MODE_FLOAT) |
| 688 | + return COSTS_N_INSNS (300); |
| 689 | + |
| 690 | + if (mode == TImode) |
| 691 | + return COSTS_N_INSNS (16); |
| 692 | + |
| 693 | + if (mode == DImode) |
| 694 | + return COSTS_N_INSNS (4); |
| 695 | + |
| 696 | + if (mode == HImode) |
| 697 | + return COSTS_N_INSNS (2); |
| 698 | + |
| 699 | + return COSTS_N_INSNS (3); |
| 700 | + } |
| 701 | + case IF_THEN_ELSE: |
| 702 | + if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) |
| 703 | + return COSTS_N_INSNS (4); |
| 704 | + return COSTS_N_INSNS (1); |
| 705 | + case SIGN_EXTEND: |
| 706 | + case ZERO_EXTEND: |
| 707 | + /* Sign/Zero extensions of registers cost quite much since these |
| 708 | + instrcutions only take one register operand which means that gcc |
| 709 | + often must insert some move instrcutions */ |
| 710 | + if (mode == QImode || mode == HImode) |
| 711 | + return (COSTS_N_INSNS (GET_CODE (XEXP (x, 0)) == MEM ? 0 : 1)); |
| 712 | + return COSTS_N_INSNS (4); |
| 713 | + case UNSPEC: |
| 714 | + /* divmod operations */ |
| 715 | + if (XINT (x, 1) == UNSPEC_UDIVMODSI4_INTERNAL |
| 716 | + || XINT (x, 1) == UNSPEC_DIVMODSI4_INTERNAL) |
| 717 | + { |
| 718 | + return optimize_size ? COSTS_N_INSNS (1) : COSTS_N_INSNS (16); |
| 719 | + } |
| 720 | + /* Fallthrough */ |
| 721 | + default: |
| 722 | + return COSTS_N_INSNS (1); |
| 723 | + } |
| 724 | +} |
| 725 | + |
| 726 | + |
| 727 | +static bool |
| 728 | +avr32_rtx_costs (rtx x, int code, int outer_code, int *total) |
| 729 | +{ |
| 730 | + *total = avr32_rtx_costs_1 (x, code, outer_code); |
| 731 | + return true; |
| 732 | +} |
| 733 | + |
| 734 | + |
| 735 | +bool |
| 736 | +avr32_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED) |
| 737 | +{ |
| 738 | + /* Do not want symbols in the constant pool when compiling pic or if using |
| 739 | + address pseudo instructions. */ |
| 740 | + return ((flag_pic || TARGET_HAS_ASM_ADDR_PSEUDOS) |
| 741 | + && avr32_find_symbol (x) != NULL_RTX); |
| 742 | +} |
| 743 | + |
| 744 | + |
| 745 | +/* Table of machine attributes. */ |
| 746 | +const struct attribute_spec avr32_attribute_table[] = { |
| 747 | + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ |
| 748 | + /* Interrupt Service Routines have special prologue and epilogue |
| 749 | + requirements. */ |
| 750 | + {"isr", 0, 1, false, false, false, avr32_handle_isr_attribute}, |
| 751 | + {"interrupt", 0, 1, false, false, false, avr32_handle_isr_attribute}, |
| 752 | + {"acall", 0, 1, false, true, true, avr32_handle_acall_attribute}, |
| 753 | + {"naked", 0, 0, true, false, false, avr32_handle_fndecl_attribute}, |
| 754 | + {"rmw_addressable", 0, 0, true, false, false, NULL}, |
| 755 | + {"flashvault", 0, 1, true, false, false, avr32_handle_fndecl_attribute}, |
| 756 | + {"flashvault_impl", 0, 1, true, false, false, avr32_handle_fndecl_attribute}, |
| 757 | + {NULL, 0, 0, false, false, false, NULL} |
| 758 | +}; |
| 759 | + |
| 760 | + |
| 761 | +typedef struct |
| 762 | +{ |
| 763 | + const char *const arg; |
| 764 | + const unsigned long return_value; |
| 765 | +} |
| 766 | +isr_attribute_arg; |
| 767 | + |
| 768 | + |
| 769 | +static const isr_attribute_arg isr_attribute_args[] = { |
| 770 | + {"FULL", AVR32_FT_ISR_FULL}, |
| 771 | + {"full", AVR32_FT_ISR_FULL}, |
| 772 | + {"HALF", AVR32_FT_ISR_HALF}, |
| 773 | + {"half", AVR32_FT_ISR_HALF}, |
| 774 | + {"NONE", AVR32_FT_ISR_NONE}, |
| 775 | + {"none", AVR32_FT_ISR_NONE}, |
| 776 | + {"UNDEF", AVR32_FT_ISR_NONE}, |
| 777 | + {"undef", AVR32_FT_ISR_NONE}, |
| 778 | + {"SWI", AVR32_FT_ISR_NONE}, |
| 779 | + {"swi", AVR32_FT_ISR_NONE}, |
| 780 | + {NULL, AVR32_FT_ISR_NONE} |
| 781 | +}; |
| 782 | + |
| 783 | + |
| 784 | +/* Returns the (interrupt) function type of the current |
| 785 | + function, or AVR32_FT_UNKNOWN if the type cannot be determined. */ |
| 786 | +static unsigned long |
| 787 | +avr32_isr_value (tree argument) |
| 788 | +{ |
| 789 | + const isr_attribute_arg *ptr; |
| 790 | + const char *arg; |
| 791 | + |
| 792 | + /* No argument - default to ISR_NONE. */ |
| 793 | + if (argument == NULL_TREE) |
| 794 | + return AVR32_FT_ISR_NONE; |
| 795 | + |
| 796 | + /* Get the value of the argument. */ |
| 797 | + if (TREE_VALUE (argument) == NULL_TREE |
| 798 | + || TREE_CODE (TREE_VALUE (argument)) != STRING_CST) |
| 799 | + return AVR32_FT_UNKNOWN; |
| 800 | + |
| 801 | + arg = TREE_STRING_POINTER (TREE_VALUE (argument)); |
| 802 | + |
| 803 | + /* Check it against the list of known arguments. */ |
| 804 | + for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++) |
| 805 | + if (streq (arg, ptr->arg)) |
| 806 | + return ptr->return_value; |
| 807 | + |
| 808 | + /* An unrecognized interrupt type. */ |
| 809 | + return AVR32_FT_UNKNOWN; |
| 810 | +} |
| 811 | + |
| 812 | + |
| 813 | +/* |
| 814 | +These hooks specify assembly directives for creating certain kinds |
| 815 | +of integer object. The TARGET_ASM_BYTE_OP directive creates a |
| 816 | +byte-sized object, the TARGET_ASM_ALIGNED_HI_OP one creates an |
| 817 | +aligned two-byte object, and so on. Any of the hooks may be |
| 818 | +NULL, indicating that no suitable directive is available. |
| 819 | + |
| 820 | +The compiler will print these strings at the start of a new line, |
| 821 | +followed immediately by the object's initial value. In most cases, |
| 822 | +the string should contain a tab, a pseudo-op, and then another tab. |
| 823 | +*/ |
| 824 | +#undef TARGET_ASM_BYTE_OP |
| 825 | +#define TARGET_ASM_BYTE_OP "\t.byte\t" |
| 826 | +#undef TARGET_ASM_ALIGNED_HI_OP |
| 827 | +#define TARGET_ASM_ALIGNED_HI_OP "\t.align 1\n\t.short\t" |
| 828 | +#undef TARGET_ASM_ALIGNED_SI_OP |
| 829 | +#define TARGET_ASM_ALIGNED_SI_OP "\t.align 2\n\t.int\t" |
| 830 | +#undef TARGET_ASM_ALIGNED_DI_OP |
| 831 | +#define TARGET_ASM_ALIGNED_DI_OP NULL |
| 832 | +#undef TARGET_ASM_ALIGNED_TI_OP |
| 833 | +#define TARGET_ASM_ALIGNED_TI_OP NULL |
| 834 | +#undef TARGET_ASM_UNALIGNED_HI_OP |
| 835 | +#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t" |
| 836 | +#undef TARGET_ASM_UNALIGNED_SI_OP |
| 837 | +#define TARGET_ASM_UNALIGNED_SI_OP "\t.int\t" |
| 838 | +#undef TARGET_ASM_UNALIGNED_DI_OP |
| 839 | +#define TARGET_ASM_UNALIGNED_DI_OP NULL |
| 840 | +#undef TARGET_ASM_UNALIGNED_TI_OP |
| 841 | +#define TARGET_ASM_UNALIGNED_TI_OP NULL |
| 842 | + |
| 843 | +#undef TARGET_ASM_OUTPUT_MI_THUNK |
| 844 | +#define TARGET_ASM_OUTPUT_MI_THUNK avr32_output_mi_thunk |
| 845 | + |
| 846 | +#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK |
| 847 | +#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true |
| 848 | + |
| 849 | + |
| 850 | +static void |
| 851 | +avr32_output_mi_thunk (FILE * file, |
| 852 | + tree thunk ATTRIBUTE_UNUSED, |
| 853 | + HOST_WIDE_INT delta, |
| 854 | + HOST_WIDE_INT vcall_offset, tree function) |
| 855 | + { |
| 856 | + int mi_delta = delta; |
| 857 | + int this_regno = |
| 858 | + (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? |
| 859 | + INTERNAL_REGNUM (11) : INTERNAL_REGNUM (12)); |
| 860 | + |
| 861 | + |
| 862 | + if (!avr32_const_ok_for_constraint_p (mi_delta, 'I', "Is21") |
| 863 | + || vcall_offset) |
| 864 | + { |
| 865 | + fputs ("\tpushm\tlr\n", file); |
| 866 | + } |
| 867 | + |
| 868 | + |
| 869 | + if (mi_delta != 0) |
| 870 | + { |
| 871 | + if (avr32_const_ok_for_constraint_p (mi_delta, 'I', "Is21")) |
| 872 | + { |
| 873 | + fprintf (file, "\tsub\t%s, %d\n", reg_names[this_regno], -mi_delta); |
| 874 | + } |
| 875 | + else |
| 876 | + { |
| 877 | + /* Immediate is larger than k21 we must make us a temp register by |
| 878 | + pushing a register to the stack. */ |
| 879 | + fprintf (file, "\tmov\tlr, lo(%d)\n", mi_delta); |
| 880 | + fprintf (file, "\torh\tlr, hi(%d)\n", mi_delta); |
| 881 | + fprintf (file, "\tadd\t%s, lr\n", reg_names[this_regno]); |
| 882 | + } |
| 883 | + } |
| 884 | + |
| 885 | + |
| 886 | + if (vcall_offset != 0) |
| 887 | + { |
| 888 | + fprintf (file, "\tld.w\tlr, %s[0]\n", reg_names[this_regno]); |
| 889 | + fprintf (file, "\tld.w\tlr, lr[%i]\n", (int) vcall_offset); |
| 890 | + fprintf (file, "\tadd\t%s, lr\n", reg_names[this_regno]); |
| 891 | + } |
| 892 | + |
| 893 | + |
| 894 | + if (!avr32_const_ok_for_constraint_p (mi_delta, 'I', "Is21") |
| 895 | + || vcall_offset) |
| 896 | + { |
| 897 | + fputs ("\tpopm\tlr\n", file); |
| 898 | + } |
| 899 | + |
| 900 | + /* Jump to the function. We assume that we can use an rjmp since the |
| 901 | + function to jump to is local and probably not too far away from |
| 902 | + the thunk. If this assumption proves to be wrong we could implement |
| 903 | + this jump by calculating the offset between the jump source and destination |
| 904 | + and put this in the constant pool and then perform an add to pc. |
| 905 | + This would also be legitimate PIC code. But for now we hope that an rjmp |
| 906 | + will be sufficient... |
| 907 | + */ |
| 908 | + fputs ("\trjmp\t", file); |
| 909 | + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); |
| 910 | + fputc ('\n', file); |
| 911 | + } |
| 912 | + |
| 913 | + |
| 914 | +/* Implements target hook vector_mode_supported. */ |
| 915 | +bool |
| 916 | +avr32_vector_mode_supported (enum machine_mode mode) |
| 917 | +{ |
| 918 | + if ((mode == V2HImode) || (mode == V4QImode)) |
| 919 | + return true; |
| 920 | + |
| 921 | + return false; |
| 922 | +} |
| 923 | + |
| 924 | + |
| 925 | +#undef TARGET_INIT_LIBFUNCS |
| 926 | +#define TARGET_INIT_LIBFUNCS avr32_init_libfuncs |
| 927 | + |
| 928 | +#undef TARGET_INIT_BUILTINS |
| 929 | +#define TARGET_INIT_BUILTINS avr32_init_builtins |
| 930 | + |
| 931 | +#undef TARGET_EXPAND_BUILTIN |
| 932 | +#define TARGET_EXPAND_BUILTIN avr32_expand_builtin |
| 933 | + |
| 934 | +tree int_ftype_int, int_ftype_void, short_ftype_short, void_ftype_int_int, |
| 935 | + void_ftype_ptr_int; |
| 936 | +tree void_ftype_int, void_ftype_ulong, void_ftype_void, int_ftype_ptr_int; |
| 937 | +tree short_ftype_short, int_ftype_int_short, int_ftype_short_short, |
| 938 | + short_ftype_short_short; |
| 939 | +tree int_ftype_int_int, longlong_ftype_int_short, longlong_ftype_short_short; |
| 940 | +tree void_ftype_int_int_int_int_int, void_ftype_int_int_int; |
| 941 | +tree longlong_ftype_int_int, void_ftype_int_int_longlong; |
| 942 | +tree int_ftype_int_int_int, longlong_ftype_longlong_int_short; |
| 943 | +tree longlong_ftype_longlong_short_short, int_ftype_int_short_short; |
| 944 | + |
| 945 | +#define def_builtin(NAME, TYPE, CODE) \ |
| 946 | + add_builtin_function ((NAME), (TYPE), (CODE), \ |
| 947 | + BUILT_IN_MD, NULL, NULL_TREE) |
| 948 | + |
| 949 | +#define def_mbuiltin(MASK, NAME, TYPE, CODE) \ |
| 950 | + do \ |
| 951 | + { \ |
| 952 | + if ((MASK)) \ |
| 953 | + add_builtin_function ((NAME), (TYPE), (CODE), \ |
| 954 | + BUILT_IN_MD, NULL, NULL_TREE); \ |
| 955 | + } \ |
| 956 | + while (0) |
| 957 | + |
| 958 | +struct builtin_description |
| 959 | +{ |
| 960 | + const unsigned int mask; |
| 961 | + const enum insn_code icode; |
| 962 | + const char *const name; |
| 963 | + const int code; |
| 964 | + const enum rtx_code comparison; |
| 965 | + const unsigned int flag; |
| 966 | + const tree *ftype; |
| 967 | +}; |
| 968 | + |
| 969 | +static const struct builtin_description bdesc_2arg[] = { |
| 970 | + |
| 971 | +#define DSP_BUILTIN(code, builtin, ftype) \ |
| 972 | + { 1, CODE_FOR_##code, "__builtin_" #code , \ |
| 973 | + AVR32_BUILTIN_##builtin, 0, 0, ftype } |
| 974 | + |
| 975 | + DSP_BUILTIN (mulsathh_h, MULSATHH_H, &short_ftype_short_short), |
| 976 | + DSP_BUILTIN (mulsathh_w, MULSATHH_W, &int_ftype_short_short), |
| 977 | + DSP_BUILTIN (mulsatrndhh_h, MULSATRNDHH_H, &short_ftype_short_short), |
| 978 | + DSP_BUILTIN (mulsatrndwh_w, MULSATRNDWH_W, &int_ftype_int_short), |
| 979 | + DSP_BUILTIN (mulsatwh_w, MULSATWH_W, &int_ftype_int_short), |
| 980 | + DSP_BUILTIN (satadd_h, SATADD_H, &short_ftype_short_short), |
| 981 | + DSP_BUILTIN (satsub_h, SATSUB_H, &short_ftype_short_short), |
| 982 | + DSP_BUILTIN (satadd_w, SATADD_W, &int_ftype_int_int), |
| 983 | + DSP_BUILTIN (satsub_w, SATSUB_W, &int_ftype_int_int), |
| 984 | + DSP_BUILTIN (mulwh_d, MULWH_D, &longlong_ftype_int_short), |
| 985 | + DSP_BUILTIN (mulnwh_d, MULNWH_D, &longlong_ftype_int_short) |
| 986 | +}; |
| 987 | + |
| 988 | + |
| 989 | +void |
| 990 | +avr32_init_builtins (void) |
| 991 | +{ |
| 992 | + unsigned int i; |
| 993 | + const struct builtin_description *d; |
| 994 | + tree endlink = void_list_node; |
| 995 | + tree int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink); |
| 996 | + tree longlong_endlink = |
| 997 | + tree_cons (NULL_TREE, long_long_integer_type_node, endlink); |
| 998 | + tree short_endlink = |
| 999 | + tree_cons (NULL_TREE, short_integer_type_node, endlink); |
| 1000 | + tree void_endlink = tree_cons (NULL_TREE, void_type_node, endlink); |
| 1001 | + |
| 1002 | + /* int func (int) */ |
| 1003 | + int_ftype_int = build_function_type (integer_type_node, int_endlink); |
| 1004 | + |
| 1005 | + /* short func (short) */ |
| 1006 | + short_ftype_short |
| 1007 | + = build_function_type (short_integer_type_node, short_endlink); |
| 1008 | + |
| 1009 | + /* short func (short, short) */ |
| 1010 | + short_ftype_short_short |
| 1011 | + = build_function_type (short_integer_type_node, |
| 1012 | + tree_cons (NULL_TREE, short_integer_type_node, |
| 1013 | + short_endlink)); |
| 1014 | + |
| 1015 | + /* long long func (long long, short, short) */ |
| 1016 | + longlong_ftype_longlong_short_short |
| 1017 | + = build_function_type (long_long_integer_type_node, |
| 1018 | + tree_cons (NULL_TREE, long_long_integer_type_node, |
| 1019 | + tree_cons (NULL_TREE, |
| 1020 | + short_integer_type_node, |
| 1021 | + short_endlink))); |
| 1022 | + |
| 1023 | + /* long long func (short, short) */ |
| 1024 | + longlong_ftype_short_short |
| 1025 | + = build_function_type (long_long_integer_type_node, |
| 1026 | + tree_cons (NULL_TREE, short_integer_type_node, |
| 1027 | + short_endlink)); |
| 1028 | + |
| 1029 | + /* int func (int, int) */ |
| 1030 | + int_ftype_int_int |
| 1031 | + = build_function_type (integer_type_node, |
| 1032 | + tree_cons (NULL_TREE, integer_type_node, |
| 1033 | + int_endlink)); |
| 1034 | + |
| 1035 | + /* long long func (int, int) */ |
| 1036 | + longlong_ftype_int_int |
| 1037 | + = build_function_type (long_long_integer_type_node, |
| 1038 | + tree_cons (NULL_TREE, integer_type_node, |
| 1039 | + int_endlink)); |
| 1040 | + |
| 1041 | + /* long long int func (long long, int, short) */ |
| 1042 | + longlong_ftype_longlong_int_short |
| 1043 | + = build_function_type (long_long_integer_type_node, |
| 1044 | + tree_cons (NULL_TREE, long_long_integer_type_node, |
| 1045 | + tree_cons (NULL_TREE, integer_type_node, |
| 1046 | + short_endlink))); |
| 1047 | + |
| 1048 | + /* long long int func (int, short) */ |
| 1049 | + longlong_ftype_int_short |
| 1050 | + = build_function_type (long_long_integer_type_node, |
| 1051 | + tree_cons (NULL_TREE, integer_type_node, |
| 1052 | + short_endlink)); |
| 1053 | + |
| 1054 | + /* int func (int, short, short) */ |
| 1055 | + int_ftype_int_short_short |
| 1056 | + = build_function_type (integer_type_node, |
| 1057 | + tree_cons (NULL_TREE, integer_type_node, |
| 1058 | + tree_cons (NULL_TREE, |
| 1059 | + short_integer_type_node, |
| 1060 | + short_endlink))); |
| 1061 | + |
| 1062 | + /* int func (short, short) */ |
| 1063 | + int_ftype_short_short |
| 1064 | + = build_function_type (integer_type_node, |
| 1065 | + tree_cons (NULL_TREE, short_integer_type_node, |
| 1066 | + short_endlink)); |
| 1067 | + |
| 1068 | + /* int func (int, short) */ |
| 1069 | + int_ftype_int_short |
| 1070 | + = build_function_type (integer_type_node, |
| 1071 | + tree_cons (NULL_TREE, integer_type_node, |
| 1072 | + short_endlink)); |
| 1073 | + |
| 1074 | + /* void func (int, int) */ |
| 1075 | + void_ftype_int_int |
| 1076 | + = build_function_type (void_type_node, |
| 1077 | + tree_cons (NULL_TREE, integer_type_node, |
| 1078 | + int_endlink)); |
| 1079 | + |
| 1080 | + /* void func (int, int, int) */ |
| 1081 | + void_ftype_int_int_int |
| 1082 | + = build_function_type (void_type_node, |
| 1083 | + tree_cons (NULL_TREE, integer_type_node, |
| 1084 | + tree_cons (NULL_TREE, integer_type_node, |
| 1085 | + int_endlink))); |
| 1086 | + |
| 1087 | + /* void func (int, int, long long) */ |
| 1088 | + void_ftype_int_int_longlong |
| 1089 | + = build_function_type (void_type_node, |
| 1090 | + tree_cons (NULL_TREE, integer_type_node, |
| 1091 | + tree_cons (NULL_TREE, integer_type_node, |
| 1092 | + longlong_endlink))); |
| 1093 | + |
| 1094 | + /* void func (int, int, int, int, int) */ |
| 1095 | + void_ftype_int_int_int_int_int |
| 1096 | + = build_function_type (void_type_node, |
| 1097 | + tree_cons (NULL_TREE, integer_type_node, |
| 1098 | + tree_cons (NULL_TREE, integer_type_node, |
| 1099 | + tree_cons (NULL_TREE, |
| 1100 | + integer_type_node, |
| 1101 | + tree_cons |
| 1102 | + (NULL_TREE, |
| 1103 | + integer_type_node, |
| 1104 | + int_endlink))))); |
| 1105 | + |
| 1106 | + /* void func (void *, int) */ |
| 1107 | + void_ftype_ptr_int |
| 1108 | + = build_function_type (void_type_node, |
| 1109 | + tree_cons (NULL_TREE, ptr_type_node, int_endlink)); |
| 1110 | + |
| 1111 | + /* void func (int) */ |
| 1112 | + void_ftype_int = build_function_type (void_type_node, int_endlink); |
| 1113 | + |
| 1114 | + /* void func (ulong) */ |
| 1115 | + void_ftype_ulong = build_function_type_list (void_type_node, |
| 1116 | + long_unsigned_type_node, NULL_TREE); |
| 1117 | + |
| 1118 | + /* void func (void) */ |
| 1119 | + void_ftype_void = build_function_type (void_type_node, void_endlink); |
| 1120 | + |
| 1121 | + /* int func (void) */ |
| 1122 | + int_ftype_void = build_function_type (integer_type_node, void_endlink); |
| 1123 | + |
| 1124 | + /* int func (void *, int) */ |
| 1125 | + int_ftype_ptr_int |
| 1126 | + = build_function_type (integer_type_node, |
| 1127 | + tree_cons (NULL_TREE, ptr_type_node, int_endlink)); |
| 1128 | + |
| 1129 | + /* int func (int, int, int) */ |
| 1130 | + int_ftype_int_int_int |
| 1131 | + = build_function_type (integer_type_node, |
| 1132 | + tree_cons (NULL_TREE, integer_type_node, |
| 1133 | + tree_cons (NULL_TREE, integer_type_node, |
| 1134 | + int_endlink))); |
| 1135 | + |
| 1136 | + /* Initialize avr32 builtins. */ |
| 1137 | + def_builtin ("__builtin_mfsr", int_ftype_int, AVR32_BUILTIN_MFSR); |
| 1138 | + def_builtin ("__builtin_mtsr", void_ftype_int_int, AVR32_BUILTIN_MTSR); |
| 1139 | + def_builtin ("__builtin_mfdr", int_ftype_int, AVR32_BUILTIN_MFDR); |
| 1140 | + def_builtin ("__builtin_mtdr", void_ftype_int_int, AVR32_BUILTIN_MTDR); |
| 1141 | + def_builtin ("__builtin_cache", void_ftype_ptr_int, AVR32_BUILTIN_CACHE); |
| 1142 | + def_builtin ("__builtin_sync", void_ftype_int, AVR32_BUILTIN_SYNC); |
| 1143 | + def_builtin ("__builtin_ssrf", void_ftype_int, AVR32_BUILTIN_SSRF); |
| 1144 | + def_builtin ("__builtin_csrf", void_ftype_int, AVR32_BUILTIN_CSRF); |
| 1145 | + def_builtin ("__builtin_tlbr", void_ftype_void, AVR32_BUILTIN_TLBR); |
| 1146 | + def_builtin ("__builtin_tlbs", void_ftype_void, AVR32_BUILTIN_TLBS); |
| 1147 | + def_builtin ("__builtin_tlbw", void_ftype_void, AVR32_BUILTIN_TLBW); |
| 1148 | + def_builtin ("__builtin_breakpoint", void_ftype_void, |
| 1149 | + AVR32_BUILTIN_BREAKPOINT); |
| 1150 | + def_builtin ("__builtin_xchg", int_ftype_ptr_int, AVR32_BUILTIN_XCHG); |
| 1151 | + def_builtin ("__builtin_ldxi", int_ftype_ptr_int, AVR32_BUILTIN_LDXI); |
| 1152 | + def_builtin ("__builtin_bswap_16", short_ftype_short, |
| 1153 | + AVR32_BUILTIN_BSWAP16); |
| 1154 | + def_builtin ("__builtin_bswap_32", int_ftype_int, AVR32_BUILTIN_BSWAP32); |
| 1155 | + def_builtin ("__builtin_cop", void_ftype_int_int_int_int_int, |
| 1156 | + AVR32_BUILTIN_COP); |
| 1157 | + def_builtin ("__builtin_mvcr_w", int_ftype_int_int, AVR32_BUILTIN_MVCR_W); |
| 1158 | + def_builtin ("__builtin_mvrc_w", void_ftype_int_int_int, |
| 1159 | + AVR32_BUILTIN_MVRC_W); |
| 1160 | + def_builtin ("__builtin_mvcr_d", longlong_ftype_int_int, |
| 1161 | + AVR32_BUILTIN_MVCR_D); |
| 1162 | + def_builtin ("__builtin_mvrc_d", void_ftype_int_int_longlong, |
| 1163 | + AVR32_BUILTIN_MVRC_D); |
| 1164 | + def_builtin ("__builtin_sats", int_ftype_int_int_int, AVR32_BUILTIN_SATS); |
| 1165 | + def_builtin ("__builtin_satu", int_ftype_int_int_int, AVR32_BUILTIN_SATU); |
| 1166 | + def_builtin ("__builtin_satrnds", int_ftype_int_int_int, |
| 1167 | + AVR32_BUILTIN_SATRNDS); |
| 1168 | + def_builtin ("__builtin_satrndu", int_ftype_int_int_int, |
| 1169 | + AVR32_BUILTIN_SATRNDU); |
| 1170 | + def_builtin ("__builtin_musfr", void_ftype_int, AVR32_BUILTIN_MUSFR); |
| 1171 | + def_builtin ("__builtin_mustr", int_ftype_void, AVR32_BUILTIN_MUSTR); |
| 1172 | + def_builtin ("__builtin_macsathh_w", int_ftype_int_short_short, |
| 1173 | + AVR32_BUILTIN_MACSATHH_W); |
| 1174 | + def_builtin ("__builtin_macwh_d", longlong_ftype_longlong_int_short, |
| 1175 | + AVR32_BUILTIN_MACWH_D); |
| 1176 | + def_builtin ("__builtin_machh_d", longlong_ftype_longlong_short_short, |
| 1177 | + AVR32_BUILTIN_MACHH_D); |
| 1178 | + def_builtin ("__builtin_mems", void_ftype_ptr_int, AVR32_BUILTIN_MEMS); |
| 1179 | + def_builtin ("__builtin_memt", void_ftype_ptr_int, AVR32_BUILTIN_MEMT); |
| 1180 | + def_builtin ("__builtin_memc", void_ftype_ptr_int, AVR32_BUILTIN_MEMC); |
| 1181 | + def_builtin ("__builtin_sleep", void_ftype_int, AVR32_BUILTIN_SLEEP); |
| 1182 | + def_builtin ("__builtin_avr32_delay_cycles", void_ftype_int, AVR32_BUILTIN_DELAY_CYCLES); |
| 1183 | + |
| 1184 | + /* Add all builtins that are more or less simple operations on two |
| 1185 | + operands. */ |
| 1186 | + for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++) |
| 1187 | + { |
| 1188 | + /* Use one of the operands; the target can have a different mode for |
| 1189 | + mask-generating compares. */ |
| 1190 | + |
| 1191 | + if (d->name == 0) |
| 1192 | + continue; |
| 1193 | + |
| 1194 | + def_mbuiltin (d->mask, d->name, *(d->ftype), d->code); |
| 1195 | + } |
| 1196 | +} |
| 1197 | + |
| 1198 | + |
| 1199 | +/* Subroutine of avr32_expand_builtin to take care of binop insns. */ |
| 1200 | +static rtx |
| 1201 | +avr32_expand_binop_builtin (enum insn_code icode, tree exp, rtx target) |
| 1202 | +{ |
| 1203 | + rtx pat; |
| 1204 | + tree arg0 = CALL_EXPR_ARG (exp,0); |
| 1205 | + tree arg1 = CALL_EXPR_ARG (exp,1); |
| 1206 | + rtx op0 = expand_normal (arg0); |
| 1207 | + rtx op1 = expand_normal (arg1); |
| 1208 | + enum machine_mode tmode = insn_data[icode].operand[0].mode; |
| 1209 | + enum machine_mode mode0 = insn_data[icode].operand[1].mode; |
| 1210 | + enum machine_mode mode1 = insn_data[icode].operand[2].mode; |
| 1211 | + |
| 1212 | + if (!target |
| 1213 | + || GET_MODE (target) != tmode |
| 1214 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1215 | + target = gen_reg_rtx (tmode); |
| 1216 | + |
| 1217 | + /* In case the insn wants input operands in modes different from the |
| 1218 | + result, abort. */ |
| 1219 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1220 | + { |
| 1221 | + /* If op0 is already a reg we must cast it to the correct mode. */ |
| 1222 | + if (REG_P (op0)) |
| 1223 | + op0 = convert_to_mode (mode0, op0, 1); |
| 1224 | + else |
| 1225 | + op0 = copy_to_mode_reg (mode0, op0); |
| 1226 | + } |
| 1227 | + if (!(*insn_data[icode].operand[2].predicate) (op1, mode1)) |
| 1228 | + { |
| 1229 | + /* If op1 is already a reg we must cast it to the correct mode. */ |
| 1230 | + if (REG_P (op1)) |
| 1231 | + op1 = convert_to_mode (mode1, op1, 1); |
| 1232 | + else |
| 1233 | + op1 = copy_to_mode_reg (mode1, op1); |
| 1234 | + } |
| 1235 | + pat = GEN_FCN (icode) (target, op0, op1); |
| 1236 | + if (!pat) |
| 1237 | + return 0; |
| 1238 | + emit_insn (pat); |
| 1239 | + return target; |
| 1240 | +} |
| 1241 | + |
| 1242 | + |
| 1243 | +/* Expand an expression EXP that calls a built-in function, |
| 1244 | + with result going to TARGET if that's convenient |
| 1245 | + (and in mode MODE if that's convenient). |
| 1246 | + SUBTARGET may be used as the target for computing one of EXP's operands. |
| 1247 | + IGNORE is nonzero if the value is to be ignored. */ |
| 1248 | +rtx |
| 1249 | +avr32_expand_builtin (tree exp, |
| 1250 | + rtx target, |
| 1251 | + rtx subtarget ATTRIBUTE_UNUSED, |
| 1252 | + enum machine_mode mode ATTRIBUTE_UNUSED, |
| 1253 | + int ignore ATTRIBUTE_UNUSED) |
| 1254 | +{ |
| 1255 | + const struct builtin_description *d; |
| 1256 | + unsigned int i; |
| 1257 | + enum insn_code icode = 0; |
| 1258 | + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); |
| 1259 | + tree arg0, arg1, arg2; |
| 1260 | + rtx op0, op1, op2, pat; |
| 1261 | + enum machine_mode tmode, mode0, mode1; |
| 1262 | + enum machine_mode arg0_mode; |
| 1263 | + int fcode = DECL_FUNCTION_CODE (fndecl); |
| 1264 | + |
| 1265 | + switch (fcode) |
| 1266 | + { |
| 1267 | + default: |
| 1268 | + break; |
| 1269 | + |
| 1270 | + case AVR32_BUILTIN_SATS: |
| 1271 | + case AVR32_BUILTIN_SATU: |
| 1272 | + case AVR32_BUILTIN_SATRNDS: |
| 1273 | + case AVR32_BUILTIN_SATRNDU: |
| 1274 | + { |
| 1275 | + const char *fname; |
| 1276 | + switch (fcode) |
| 1277 | + { |
| 1278 | + default: |
| 1279 | + case AVR32_BUILTIN_SATS: |
| 1280 | + icode = CODE_FOR_sats; |
| 1281 | + fname = "sats"; |
| 1282 | + break; |
| 1283 | + case AVR32_BUILTIN_SATU: |
| 1284 | + icode = CODE_FOR_satu; |
| 1285 | + fname = "satu"; |
| 1286 | + break; |
| 1287 | + case AVR32_BUILTIN_SATRNDS: |
| 1288 | + icode = CODE_FOR_satrnds; |
| 1289 | + fname = "satrnds"; |
| 1290 | + break; |
| 1291 | + case AVR32_BUILTIN_SATRNDU: |
| 1292 | + icode = CODE_FOR_satrndu; |
| 1293 | + fname = "satrndu"; |
| 1294 | + break; |
| 1295 | + } |
| 1296 | + |
| 1297 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1298 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1299 | + arg2 = CALL_EXPR_ARG (exp,2); |
| 1300 | + op0 = expand_normal (arg0); |
| 1301 | + op1 = expand_normal (arg1); |
| 1302 | + op2 = expand_normal (arg2); |
| 1303 | + |
| 1304 | + tmode = insn_data[icode].operand[0].mode; |
| 1305 | + |
| 1306 | + |
| 1307 | + if (target == 0 |
| 1308 | + || GET_MODE (target) != tmode |
| 1309 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1310 | + target = gen_reg_rtx (tmode); |
| 1311 | + |
| 1312 | + |
| 1313 | + if (!(*insn_data[icode].operand[0].predicate) (op0, GET_MODE (op0))) |
| 1314 | + { |
| 1315 | + op0 = copy_to_mode_reg (insn_data[icode].operand[0].mode, op0); |
| 1316 | + } |
| 1317 | + |
| 1318 | + if (!(*insn_data[icode].operand[1].predicate) (op1, SImode)) |
| 1319 | + { |
| 1320 | + error ("Parameter 2 to __builtin_%s should be a constant number.", |
| 1321 | + fname); |
| 1322 | + return NULL_RTX; |
| 1323 | + } |
| 1324 | + |
| 1325 | + if (!(*insn_data[icode].operand[1].predicate) (op2, SImode)) |
| 1326 | + { |
| 1327 | + error ("Parameter 3 to __builtin_%s should be a constant number.", |
| 1328 | + fname); |
| 1329 | + return NULL_RTX; |
| 1330 | + } |
| 1331 | + |
| 1332 | + emit_move_insn (target, op0); |
| 1333 | + pat = GEN_FCN (icode) (target, op1, op2); |
| 1334 | + if (!pat) |
| 1335 | + return 0; |
| 1336 | + emit_insn (pat); |
| 1337 | + |
| 1338 | + return target; |
| 1339 | + } |
| 1340 | + case AVR32_BUILTIN_MUSTR: |
| 1341 | + icode = CODE_FOR_mustr; |
| 1342 | + tmode = insn_data[icode].operand[0].mode; |
| 1343 | + |
| 1344 | + if (target == 0 |
| 1345 | + || GET_MODE (target) != tmode |
| 1346 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1347 | + target = gen_reg_rtx (tmode); |
| 1348 | + pat = GEN_FCN (icode) (target); |
| 1349 | + if (!pat) |
| 1350 | + return 0; |
| 1351 | + emit_insn (pat); |
| 1352 | + return target; |
| 1353 | + |
| 1354 | + case AVR32_BUILTIN_MFSR: |
| 1355 | + icode = CODE_FOR_mfsr; |
| 1356 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1357 | + op0 = expand_normal (arg0); |
| 1358 | + tmode = insn_data[icode].operand[0].mode; |
| 1359 | + mode0 = insn_data[icode].operand[1].mode; |
| 1360 | + |
| 1361 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1362 | + { |
| 1363 | + error ("Parameter 1 to __builtin_mfsr must be a constant number"); |
| 1364 | + } |
| 1365 | + |
| 1366 | + if (target == 0 |
| 1367 | + || GET_MODE (target) != tmode |
| 1368 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1369 | + target = gen_reg_rtx (tmode); |
| 1370 | + pat = GEN_FCN (icode) (target, op0); |
| 1371 | + if (!pat) |
| 1372 | + return 0; |
| 1373 | + emit_insn (pat); |
| 1374 | + return target; |
| 1375 | + case AVR32_BUILTIN_MTSR: |
| 1376 | + icode = CODE_FOR_mtsr; |
| 1377 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1378 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1379 | + op0 = expand_normal (arg0); |
| 1380 | + op1 = expand_normal (arg1); |
| 1381 | + mode0 = insn_data[icode].operand[0].mode; |
| 1382 | + mode1 = insn_data[icode].operand[1].mode; |
| 1383 | + |
| 1384 | + if (!(*insn_data[icode].operand[0].predicate) (op0, mode0)) |
| 1385 | + { |
| 1386 | + error ("Parameter 1 to __builtin_mtsr must be a constant number"); |
| 1387 | + return gen_reg_rtx (mode0); |
| 1388 | + } |
| 1389 | + if (!(*insn_data[icode].operand[1].predicate) (op1, mode1)) |
| 1390 | + op1 = copy_to_mode_reg (mode1, op1); |
| 1391 | + pat = GEN_FCN (icode) (op0, op1); |
| 1392 | + if (!pat) |
| 1393 | + return 0; |
| 1394 | + emit_insn (pat); |
| 1395 | + return NULL_RTX; |
| 1396 | + case AVR32_BUILTIN_MFDR: |
| 1397 | + icode = CODE_FOR_mfdr; |
| 1398 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1399 | + op0 = expand_normal (arg0); |
| 1400 | + tmode = insn_data[icode].operand[0].mode; |
| 1401 | + mode0 = insn_data[icode].operand[1].mode; |
| 1402 | + |
| 1403 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1404 | + { |
| 1405 | + error ("Parameter 1 to __builtin_mfdr must be a constant number"); |
| 1406 | + } |
| 1407 | + |
| 1408 | + if (target == 0 |
| 1409 | + || GET_MODE (target) != tmode |
| 1410 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1411 | + target = gen_reg_rtx (tmode); |
| 1412 | + pat = GEN_FCN (icode) (target, op0); |
| 1413 | + if (!pat) |
| 1414 | + return 0; |
| 1415 | + emit_insn (pat); |
| 1416 | + return target; |
| 1417 | + case AVR32_BUILTIN_MTDR: |
| 1418 | + icode = CODE_FOR_mtdr; |
| 1419 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1420 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1421 | + op0 = expand_normal (arg0); |
| 1422 | + op1 = expand_normal (arg1); |
| 1423 | + mode0 = insn_data[icode].operand[0].mode; |
| 1424 | + mode1 = insn_data[icode].operand[1].mode; |
| 1425 | + |
| 1426 | + if (!(*insn_data[icode].operand[0].predicate) (op0, mode0)) |
| 1427 | + { |
| 1428 | + error ("Parameter 1 to __builtin_mtdr must be a constant number"); |
| 1429 | + return gen_reg_rtx (mode0); |
| 1430 | + } |
| 1431 | + if (!(*insn_data[icode].operand[1].predicate) (op1, mode1)) |
| 1432 | + op1 = copy_to_mode_reg (mode1, op1); |
| 1433 | + pat = GEN_FCN (icode) (op0, op1); |
| 1434 | + if (!pat) |
| 1435 | + return 0; |
| 1436 | + emit_insn (pat); |
| 1437 | + return NULL_RTX; |
| 1438 | + case AVR32_BUILTIN_CACHE: |
| 1439 | + icode = CODE_FOR_cache; |
| 1440 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1441 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1442 | + op0 = expand_normal (arg0); |
| 1443 | + op1 = expand_normal (arg1); |
| 1444 | + mode0 = insn_data[icode].operand[0].mode; |
| 1445 | + mode1 = insn_data[icode].operand[1].mode; |
| 1446 | + |
| 1447 | + if (!(*insn_data[icode].operand[1].predicate) (op1, mode1)) |
| 1448 | + { |
| 1449 | + error ("Parameter 2 to __builtin_cache must be a constant number"); |
| 1450 | + return gen_reg_rtx (mode1); |
| 1451 | + } |
| 1452 | + |
| 1453 | + if (!(*insn_data[icode].operand[0].predicate) (op0, mode0)) |
| 1454 | + op0 = copy_to_mode_reg (mode0, op0); |
| 1455 | + |
| 1456 | + pat = GEN_FCN (icode) (op0, op1); |
| 1457 | + if (!pat) |
| 1458 | + return 0; |
| 1459 | + emit_insn (pat); |
| 1460 | + return NULL_RTX; |
| 1461 | + case AVR32_BUILTIN_SYNC: |
| 1462 | + case AVR32_BUILTIN_MUSFR: |
| 1463 | + case AVR32_BUILTIN_SSRF: |
| 1464 | + case AVR32_BUILTIN_CSRF: |
| 1465 | + { |
| 1466 | + const char *fname; |
| 1467 | + switch (fcode) |
| 1468 | + { |
| 1469 | + default: |
| 1470 | + case AVR32_BUILTIN_SYNC: |
| 1471 | + icode = CODE_FOR_sync; |
| 1472 | + fname = "sync"; |
| 1473 | + break; |
| 1474 | + case AVR32_BUILTIN_MUSFR: |
| 1475 | + icode = CODE_FOR_musfr; |
| 1476 | + fname = "musfr"; |
| 1477 | + break; |
| 1478 | + case AVR32_BUILTIN_SSRF: |
| 1479 | + icode = CODE_FOR_ssrf; |
| 1480 | + fname = "ssrf"; |
| 1481 | + break; |
| 1482 | + case AVR32_BUILTIN_CSRF: |
| 1483 | + icode = CODE_FOR_csrf; |
| 1484 | + fname = "csrf"; |
| 1485 | + break; |
| 1486 | + } |
| 1487 | + |
| 1488 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1489 | + op0 = expand_normal (arg0); |
| 1490 | + mode0 = insn_data[icode].operand[0].mode; |
| 1491 | + |
| 1492 | + if (!(*insn_data[icode].operand[0].predicate) (op0, mode0)) |
| 1493 | + { |
| 1494 | + if (icode == CODE_FOR_musfr) |
| 1495 | + op0 = copy_to_mode_reg (mode0, op0); |
| 1496 | + else |
| 1497 | + { |
| 1498 | + error ("Parameter to __builtin_%s is illegal.", fname); |
| 1499 | + return gen_reg_rtx (mode0); |
| 1500 | + } |
| 1501 | + } |
| 1502 | + pat = GEN_FCN (icode) (op0); |
| 1503 | + if (!pat) |
| 1504 | + return 0; |
| 1505 | + emit_insn (pat); |
| 1506 | + return NULL_RTX; |
| 1507 | + } |
| 1508 | + case AVR32_BUILTIN_TLBR: |
| 1509 | + icode = CODE_FOR_tlbr; |
| 1510 | + pat = GEN_FCN (icode) (NULL_RTX); |
| 1511 | + if (!pat) |
| 1512 | + return 0; |
| 1513 | + emit_insn (pat); |
| 1514 | + return NULL_RTX; |
| 1515 | + case AVR32_BUILTIN_TLBS: |
| 1516 | + icode = CODE_FOR_tlbs; |
| 1517 | + pat = GEN_FCN (icode) (NULL_RTX); |
| 1518 | + if (!pat) |
| 1519 | + return 0; |
| 1520 | + emit_insn (pat); |
| 1521 | + return NULL_RTX; |
| 1522 | + case AVR32_BUILTIN_TLBW: |
| 1523 | + icode = CODE_FOR_tlbw; |
| 1524 | + pat = GEN_FCN (icode) (NULL_RTX); |
| 1525 | + if (!pat) |
| 1526 | + return 0; |
| 1527 | + emit_insn (pat); |
| 1528 | + return NULL_RTX; |
| 1529 | + case AVR32_BUILTIN_BREAKPOINT: |
| 1530 | + icode = CODE_FOR_breakpoint; |
| 1531 | + pat = GEN_FCN (icode) (NULL_RTX); |
| 1532 | + if (!pat) |
| 1533 | + return 0; |
| 1534 | + emit_insn (pat); |
| 1535 | + return NULL_RTX; |
| 1536 | + case AVR32_BUILTIN_XCHG: |
| 1537 | + icode = CODE_FOR_sync_lock_test_and_setsi; |
| 1538 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1539 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1540 | + op0 = expand_normal (arg0); |
| 1541 | + op1 = expand_normal (arg1); |
| 1542 | + tmode = insn_data[icode].operand[0].mode; |
| 1543 | + mode0 = insn_data[icode].operand[1].mode; |
| 1544 | + mode1 = insn_data[icode].operand[2].mode; |
| 1545 | + |
| 1546 | + if (!(*insn_data[icode].operand[2].predicate) (op1, mode1)) |
| 1547 | + { |
| 1548 | + op1 = copy_to_mode_reg (mode1, op1); |
| 1549 | + } |
| 1550 | + |
| 1551 | + op0 = force_reg (GET_MODE (op0), op0); |
| 1552 | + op0 = gen_rtx_MEM (GET_MODE (op0), op0); |
| 1553 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1554 | + { |
| 1555 | + error |
| 1556 | + ("Parameter 1 to __builtin_xchg must be a pointer to an integer."); |
| 1557 | + } |
| 1558 | + |
| 1559 | + if (target == 0 |
| 1560 | + || GET_MODE (target) != tmode |
| 1561 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1562 | + target = gen_reg_rtx (tmode); |
| 1563 | + pat = GEN_FCN (icode) (target, op0, op1); |
| 1564 | + if (!pat) |
| 1565 | + return 0; |
| 1566 | + emit_insn (pat); |
| 1567 | + return target; |
| 1568 | + case AVR32_BUILTIN_LDXI: |
| 1569 | + icode = CODE_FOR_ldxi; |
| 1570 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1571 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1572 | + arg2 = CALL_EXPR_ARG (exp,2); |
| 1573 | + op0 = expand_normal (arg0); |
| 1574 | + op1 = expand_normal (arg1); |
| 1575 | + op2 = expand_normal (arg2); |
| 1576 | + tmode = insn_data[icode].operand[0].mode; |
| 1577 | + mode0 = insn_data[icode].operand[1].mode; |
| 1578 | + mode1 = insn_data[icode].operand[2].mode; |
| 1579 | + |
| 1580 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1581 | + { |
| 1582 | + op0 = copy_to_mode_reg (mode0, op0); |
| 1583 | + } |
| 1584 | + |
| 1585 | + if (!(*insn_data[icode].operand[2].predicate) (op1, mode1)) |
| 1586 | + { |
| 1587 | + op1 = copy_to_mode_reg (mode1, op1); |
| 1588 | + } |
| 1589 | + |
| 1590 | + if (!(*insn_data[icode].operand[3].predicate) (op2, SImode)) |
| 1591 | + { |
| 1592 | + error |
| 1593 | + ("Parameter 3 to __builtin_ldxi must be a valid extract shift operand: (0|8|16|24)"); |
| 1594 | + return gen_reg_rtx (mode0); |
| 1595 | + } |
| 1596 | + |
| 1597 | + if (target == 0 |
| 1598 | + || GET_MODE (target) != tmode |
| 1599 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1600 | + target = gen_reg_rtx (tmode); |
| 1601 | + pat = GEN_FCN (icode) (target, op0, op1, op2); |
| 1602 | + if (!pat) |
| 1603 | + return 0; |
| 1604 | + emit_insn (pat); |
| 1605 | + return target; |
| 1606 | + case AVR32_BUILTIN_BSWAP16: |
| 1607 | + { |
| 1608 | + icode = CODE_FOR_bswap_16; |
| 1609 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1610 | + arg0_mode = TYPE_MODE (TREE_TYPE (arg0)); |
| 1611 | + mode0 = insn_data[icode].operand[1].mode; |
| 1612 | + if (arg0_mode != mode0) |
| 1613 | + arg0 = build1 (NOP_EXPR, |
| 1614 | + (*lang_hooks.types.type_for_mode) (mode0, 0), arg0); |
| 1615 | + |
| 1616 | + op0 = expand_expr (arg0, NULL_RTX, HImode, 0); |
| 1617 | + tmode = insn_data[icode].operand[0].mode; |
| 1618 | + |
| 1619 | + |
| 1620 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1621 | + { |
| 1622 | + if ( CONST_INT_P (op0) ) |
| 1623 | + { |
| 1624 | + HOST_WIDE_INT val = ( ((INTVAL (op0)&0x00ff) << 8) | |
| 1625 | + ((INTVAL (op0)&0xff00) >> 8) ); |
| 1626 | + /* Sign extend 16-bit value to host wide int */ |
| 1627 | + val <<= (HOST_BITS_PER_WIDE_INT - 16); |
| 1628 | + val >>= (HOST_BITS_PER_WIDE_INT - 16); |
| 1629 | + op0 = GEN_INT(val); |
| 1630 | + if (target == 0 |
| 1631 | + || GET_MODE (target) != tmode |
| 1632 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1633 | + target = gen_reg_rtx (tmode); |
| 1634 | + emit_move_insn(target, op0); |
| 1635 | + return target; |
| 1636 | + } |
| 1637 | + else |
| 1638 | + op0 = copy_to_mode_reg (mode0, op0); |
| 1639 | + } |
| 1640 | + |
| 1641 | + if (target == 0 |
| 1642 | + || GET_MODE (target) != tmode |
| 1643 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1644 | + { |
| 1645 | + target = gen_reg_rtx (tmode); |
| 1646 | + } |
| 1647 | + |
| 1648 | + |
| 1649 | + pat = GEN_FCN (icode) (target, op0); |
| 1650 | + if (!pat) |
| 1651 | + return 0; |
| 1652 | + emit_insn (pat); |
| 1653 | + |
| 1654 | + return target; |
| 1655 | + } |
| 1656 | + case AVR32_BUILTIN_BSWAP32: |
| 1657 | + { |
| 1658 | + icode = CODE_FOR_bswap_32; |
| 1659 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1660 | + op0 = expand_normal (arg0); |
| 1661 | + tmode = insn_data[icode].operand[0].mode; |
| 1662 | + mode0 = insn_data[icode].operand[1].mode; |
| 1663 | + |
| 1664 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1665 | + { |
| 1666 | + if ( CONST_INT_P (op0) ) |
| 1667 | + { |
| 1668 | + HOST_WIDE_INT val = ( ((INTVAL (op0)&0x000000ff) << 24) | |
| 1669 | + ((INTVAL (op0)&0x0000ff00) << 8) | |
| 1670 | + ((INTVAL (op0)&0x00ff0000) >> 8) | |
| 1671 | + ((INTVAL (op0)&0xff000000) >> 24) ); |
| 1672 | + /* Sign extend 32-bit value to host wide int */ |
| 1673 | + val <<= (HOST_BITS_PER_WIDE_INT - 32); |
| 1674 | + val >>= (HOST_BITS_PER_WIDE_INT - 32); |
| 1675 | + op0 = GEN_INT(val); |
| 1676 | + if (target == 0 |
| 1677 | + || GET_MODE (target) != tmode |
| 1678 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1679 | + target = gen_reg_rtx (tmode); |
| 1680 | + emit_move_insn(target, op0); |
| 1681 | + return target; |
| 1682 | + } |
| 1683 | + else |
| 1684 | + op0 = copy_to_mode_reg (mode0, op0); |
| 1685 | + } |
| 1686 | + |
| 1687 | + if (target == 0 |
| 1688 | + || GET_MODE (target) != tmode |
| 1689 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1690 | + target = gen_reg_rtx (tmode); |
| 1691 | + |
| 1692 | + |
| 1693 | + pat = GEN_FCN (icode) (target, op0); |
| 1694 | + if (!pat) |
| 1695 | + return 0; |
| 1696 | + emit_insn (pat); |
| 1697 | + |
| 1698 | + return target; |
| 1699 | + } |
| 1700 | + case AVR32_BUILTIN_MVCR_W: |
| 1701 | + case AVR32_BUILTIN_MVCR_D: |
| 1702 | + { |
| 1703 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1704 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1705 | + op0 = expand_normal (arg0); |
| 1706 | + op1 = expand_normal (arg1); |
| 1707 | + |
| 1708 | + if (fcode == AVR32_BUILTIN_MVCR_W) |
| 1709 | + icode = CODE_FOR_mvcrsi; |
| 1710 | + else |
| 1711 | + icode = CODE_FOR_mvcrdi; |
| 1712 | + |
| 1713 | + tmode = insn_data[icode].operand[0].mode; |
| 1714 | + |
| 1715 | + if (target == 0 |
| 1716 | + || GET_MODE (target) != tmode |
| 1717 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1718 | + target = gen_reg_rtx (tmode); |
| 1719 | + |
| 1720 | + if (!(*insn_data[icode].operand[1].predicate) (op0, SImode)) |
| 1721 | + { |
| 1722 | + error |
| 1723 | + ("Parameter 1 to __builtin_cop is not a valid coprocessor number."); |
| 1724 | + error ("Number should be between 0 and 7."); |
| 1725 | + return NULL_RTX; |
| 1726 | + } |
| 1727 | + |
| 1728 | + if (!(*insn_data[icode].operand[2].predicate) (op1, SImode)) |
| 1729 | + { |
| 1730 | + error |
| 1731 | + ("Parameter 2 to __builtin_cop is not a valid coprocessor register number."); |
| 1732 | + error ("Number should be between 0 and 15."); |
| 1733 | + return NULL_RTX; |
| 1734 | + } |
| 1735 | + |
| 1736 | + pat = GEN_FCN (icode) (target, op0, op1); |
| 1737 | + if (!pat) |
| 1738 | + return 0; |
| 1739 | + emit_insn (pat); |
| 1740 | + |
| 1741 | + return target; |
| 1742 | + } |
| 1743 | + case AVR32_BUILTIN_MACSATHH_W: |
| 1744 | + case AVR32_BUILTIN_MACWH_D: |
| 1745 | + case AVR32_BUILTIN_MACHH_D: |
| 1746 | + { |
| 1747 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1748 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1749 | + arg2 = CALL_EXPR_ARG (exp,2); |
| 1750 | + op0 = expand_normal (arg0); |
| 1751 | + op1 = expand_normal (arg1); |
| 1752 | + op2 = expand_normal (arg2); |
| 1753 | + |
| 1754 | + icode = ((fcode == AVR32_BUILTIN_MACSATHH_W) ? CODE_FOR_macsathh_w : |
| 1755 | + (fcode == AVR32_BUILTIN_MACWH_D) ? CODE_FOR_macwh_d : |
| 1756 | + CODE_FOR_machh_d); |
| 1757 | + |
| 1758 | + tmode = insn_data[icode].operand[0].mode; |
| 1759 | + mode0 = insn_data[icode].operand[1].mode; |
| 1760 | + mode1 = insn_data[icode].operand[2].mode; |
| 1761 | + |
| 1762 | + |
| 1763 | + if (!target |
| 1764 | + || GET_MODE (target) != tmode |
| 1765 | + || !(*insn_data[icode].operand[0].predicate) (target, tmode)) |
| 1766 | + target = gen_reg_rtx (tmode); |
| 1767 | + |
| 1768 | + if (!(*insn_data[icode].operand[0].predicate) (op0, tmode)) |
| 1769 | + { |
| 1770 | + /* If op0 is already a reg we must cast it to the correct mode. */ |
| 1771 | + if (REG_P (op0)) |
| 1772 | + op0 = convert_to_mode (tmode, op0, 1); |
| 1773 | + else |
| 1774 | + op0 = copy_to_mode_reg (tmode, op0); |
| 1775 | + } |
| 1776 | + |
| 1777 | + if (!(*insn_data[icode].operand[1].predicate) (op1, mode0)) |
| 1778 | + { |
| 1779 | + /* If op1 is already a reg we must cast it to the correct mode. */ |
| 1780 | + if (REG_P (op1)) |
| 1781 | + op1 = convert_to_mode (mode0, op1, 1); |
| 1782 | + else |
| 1783 | + op1 = copy_to_mode_reg (mode0, op1); |
| 1784 | + } |
| 1785 | + |
| 1786 | + if (!(*insn_data[icode].operand[2].predicate) (op2, mode1)) |
| 1787 | + { |
| 1788 | + /* If op1 is already a reg we must cast it to the correct mode. */ |
| 1789 | + if (REG_P (op2)) |
| 1790 | + op2 = convert_to_mode (mode1, op2, 1); |
| 1791 | + else |
| 1792 | + op2 = copy_to_mode_reg (mode1, op2); |
| 1793 | + } |
| 1794 | + |
| 1795 | + emit_move_insn (target, op0); |
| 1796 | + |
| 1797 | + pat = GEN_FCN (icode) (target, op1, op2); |
| 1798 | + if (!pat) |
| 1799 | + return 0; |
| 1800 | + emit_insn (pat); |
| 1801 | + return target; |
| 1802 | + } |
| 1803 | + case AVR32_BUILTIN_MVRC_W: |
| 1804 | + case AVR32_BUILTIN_MVRC_D: |
| 1805 | + { |
| 1806 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1807 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1808 | + arg2 = CALL_EXPR_ARG (exp,2); |
| 1809 | + op0 = expand_normal (arg0); |
| 1810 | + op1 = expand_normal (arg1); |
| 1811 | + op2 = expand_normal (arg2); |
| 1812 | + |
| 1813 | + if (fcode == AVR32_BUILTIN_MVRC_W) |
| 1814 | + icode = CODE_FOR_mvrcsi; |
| 1815 | + else |
| 1816 | + icode = CODE_FOR_mvrcdi; |
| 1817 | + |
| 1818 | + if (!(*insn_data[icode].operand[0].predicate) (op0, SImode)) |
| 1819 | + { |
| 1820 | + error ("Parameter 1 is not a valid coprocessor number."); |
| 1821 | + error ("Number should be between 0 and 7."); |
| 1822 | + return NULL_RTX; |
| 1823 | + } |
| 1824 | + |
| 1825 | + if (!(*insn_data[icode].operand[1].predicate) (op1, SImode)) |
| 1826 | + { |
| 1827 | + error ("Parameter 2 is not a valid coprocessor register number."); |
| 1828 | + error ("Number should be between 0 and 15."); |
| 1829 | + return NULL_RTX; |
| 1830 | + } |
| 1831 | + |
| 1832 | + if (GET_CODE (op2) == CONST_INT |
| 1833 | + || GET_CODE (op2) == CONST |
| 1834 | + || GET_CODE (op2) == SYMBOL_REF || GET_CODE (op2) == LABEL_REF) |
| 1835 | + { |
| 1836 | + op2 = force_const_mem (insn_data[icode].operand[2].mode, op2); |
| 1837 | + } |
| 1838 | + |
| 1839 | + if (!(*insn_data[icode].operand[2].predicate) (op2, GET_MODE (op2))) |
| 1840 | + op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); |
| 1841 | + |
| 1842 | + |
| 1843 | + pat = GEN_FCN (icode) (op0, op1, op2); |
| 1844 | + if (!pat) |
| 1845 | + return 0; |
| 1846 | + emit_insn (pat); |
| 1847 | + |
| 1848 | + return NULL_RTX; |
| 1849 | + } |
| 1850 | + case AVR32_BUILTIN_COP: |
| 1851 | + { |
| 1852 | + rtx op3, op4; |
| 1853 | + tree arg3, arg4; |
| 1854 | + icode = CODE_FOR_cop; |
| 1855 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1856 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1857 | + arg2 = CALL_EXPR_ARG (exp,2); |
| 1858 | + arg3 = CALL_EXPR_ARG (exp,3); |
| 1859 | + arg4 = CALL_EXPR_ARG (exp,4); |
| 1860 | + op0 = expand_normal (arg0); |
| 1861 | + op1 = expand_normal (arg1); |
| 1862 | + op2 = expand_normal (arg2); |
| 1863 | + op3 = expand_normal (arg3); |
| 1864 | + op4 = expand_normal (arg4); |
| 1865 | + |
| 1866 | + if (!(*insn_data[icode].operand[0].predicate) (op0, SImode)) |
| 1867 | + { |
| 1868 | + error |
| 1869 | + ("Parameter 1 to __builtin_cop is not a valid coprocessor number."); |
| 1870 | + error ("Number should be between 0 and 7."); |
| 1871 | + return NULL_RTX; |
| 1872 | + } |
| 1873 | + |
| 1874 | + if (!(*insn_data[icode].operand[1].predicate) (op1, SImode)) |
| 1875 | + { |
| 1876 | + error |
| 1877 | + ("Parameter 2 to __builtin_cop is not a valid coprocessor register number."); |
| 1878 | + error ("Number should be between 0 and 15."); |
| 1879 | + return NULL_RTX; |
| 1880 | + } |
| 1881 | + |
| 1882 | + if (!(*insn_data[icode].operand[2].predicate) (op2, SImode)) |
| 1883 | + { |
| 1884 | + error |
| 1885 | + ("Parameter 3 to __builtin_cop is not a valid coprocessor register number."); |
| 1886 | + error ("Number should be between 0 and 15."); |
| 1887 | + return NULL_RTX; |
| 1888 | + } |
| 1889 | + |
| 1890 | + if (!(*insn_data[icode].operand[3].predicate) (op3, SImode)) |
| 1891 | + { |
| 1892 | + error |
| 1893 | + ("Parameter 4 to __builtin_cop is not a valid coprocessor register number."); |
| 1894 | + error ("Number should be between 0 and 15."); |
| 1895 | + return NULL_RTX; |
| 1896 | + } |
| 1897 | + |
| 1898 | + if (!(*insn_data[icode].operand[4].predicate) (op4, SImode)) |
| 1899 | + { |
| 1900 | + error |
| 1901 | + ("Parameter 5 to __builtin_cop is not a valid coprocessor operation."); |
| 1902 | + error ("Number should be between 0 and 127."); |
| 1903 | + return NULL_RTX; |
| 1904 | + } |
| 1905 | + |
| 1906 | + pat = GEN_FCN (icode) (op0, op1, op2, op3, op4); |
| 1907 | + if (!pat) |
| 1908 | + return 0; |
| 1909 | + emit_insn (pat); |
| 1910 | + |
| 1911 | + return target; |
| 1912 | + } |
| 1913 | + |
| 1914 | + case AVR32_BUILTIN_MEMS: |
| 1915 | + case AVR32_BUILTIN_MEMC: |
| 1916 | + case AVR32_BUILTIN_MEMT: |
| 1917 | + { |
| 1918 | + if (!TARGET_RMW) |
| 1919 | + error ("Trying to use __builtin_mem(s/c/t) when target does not support RMW insns."); |
| 1920 | + |
| 1921 | + switch (fcode) { |
| 1922 | + case AVR32_BUILTIN_MEMS: |
| 1923 | + icode = CODE_FOR_iorsi3; |
| 1924 | + break; |
| 1925 | + case AVR32_BUILTIN_MEMC: |
| 1926 | + icode = CODE_FOR_andsi3; |
| 1927 | + break; |
| 1928 | + case AVR32_BUILTIN_MEMT: |
| 1929 | + icode = CODE_FOR_xorsi3; |
| 1930 | + break; |
| 1931 | + } |
| 1932 | + arg0 = CALL_EXPR_ARG (exp,0); |
| 1933 | + arg1 = CALL_EXPR_ARG (exp,1); |
| 1934 | + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); |
| 1935 | + if ( GET_CODE (op0) == SYMBOL_REF ) |
| 1936 | + // This symbol must be RMW addressable |
| 1937 | + SYMBOL_REF_FLAGS (op0) |= (1 << SYMBOL_FLAG_RMW_ADDR_SHIFT); |
| 1938 | + op0 = gen_rtx_MEM(SImode, op0); |
| 1939 | + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); |
| 1940 | + mode0 = insn_data[icode].operand[1].mode; |
| 1941 | + |
| 1942 | + |
| 1943 | + if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) |
| 1944 | + { |
| 1945 | + error ("Parameter 1 to __builtin_mem(s/c/t) must be a Ks15<<2 address or a rmw addressable symbol."); |
| 1946 | + } |
| 1947 | + |
| 1948 | + if ( !CONST_INT_P (op1) |
| 1949 | + || INTVAL (op1) > 31 |
| 1950 | + || INTVAL (op1) < 0 ) |
| 1951 | + error ("Parameter 2 to __builtin_mem(s/c/t) must be a constant between 0 and 31."); |
| 1952 | + |
| 1953 | + if ( fcode == AVR32_BUILTIN_MEMC ) |
| 1954 | + op1 = GEN_INT((~(1 << INTVAL(op1)))&0xffffffff); |
| 1955 | + else |
| 1956 | + op1 = GEN_INT((1 << INTVAL(op1))&0xffffffff); |
| 1957 | + pat = GEN_FCN (icode) (op0, op0, op1); |
| 1958 | + if (!pat) |
| 1959 | + return 0; |
| 1960 | + emit_insn (pat); |
| 1961 | + return op0; |
| 1962 | + } |
| 1963 | + |
| 1964 | + case AVR32_BUILTIN_SLEEP: |
| 1965 | + { |
| 1966 | + arg0 = CALL_EXPR_ARG (exp, 0); |
| 1967 | + op0 = expand_normal (arg0); |
| 1968 | + int intval = INTVAL(op0); |
| 1969 | + |
| 1970 | + /* Check if the argument if integer and if the value of integer |
| 1971 | + is greater than 0. */ |
| 1972 | + |
| 1973 | + if (!CONSTANT_P (op0)) |
| 1974 | + error ("Parameter 1 to __builtin_sleep() is not a valid integer."); |
| 1975 | + if (intval < 0 ) |
| 1976 | + error ("Parameter 1 to __builtin_sleep() should be an integer greater than 0."); |
| 1977 | + |
| 1978 | + int strncmpval = strncmp (avr32_part_name,"uc3l", 4); |
| 1979 | + |
| 1980 | + /* Check if op0 is less than 7 for uc3l* and less than 6 for other |
| 1981 | + devices. By this check we are avoiding if operand is less than |
| 1982 | + 256. For more devices, add more such checks. */ |
| 1983 | + |
| 1984 | + if ( strncmpval == 0 && intval >= 7) |
| 1985 | + error ("Parameter 1 to __builtin_sleep() should be less than or equal to 7."); |
| 1986 | + else if ( strncmp != 0 && intval >= 6) |
| 1987 | + error ("Parameter 1 to __builtin_sleep() should be less than or equal to 6."); |
| 1988 | + |
| 1989 | + emit_insn (gen_sleep(op0)); |
| 1990 | + return target; |
| 1991 | + |
| 1992 | + } |
| 1993 | + case AVR32_BUILTIN_DELAY_CYCLES: |
| 1994 | + { |
| 1995 | + arg0 = CALL_EXPR_ARG (exp, 0); |
| 1996 | + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); |
| 1997 | + |
| 1998 | + if (TARGET_ARCH_AP) |
| 1999 | + error (" __builtin_avr32_delay_cycles() not supported for \'%s\' architecture.", avr32_arch_name); |
| 2000 | + if (!CONSTANT_P (op0)) |
| 2001 | + error ("Parameter 1 to __builtin_avr32_delay_cycles() should be an integer."); |
| 2002 | + emit_insn (gen_delay_cycles (op0)); |
| 2003 | + return 0; |
| 2004 | + |
| 2005 | + } |
| 2006 | + |
| 2007 | + } |
| 2008 | + |
| 2009 | + for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++) |
| 2010 | + if (d->code == fcode) |
| 2011 | + return avr32_expand_binop_builtin (d->icode, exp, target); |
| 2012 | + |
| 2013 | + |
| 2014 | + /* @@@ Should really do something sensible here. */ |
| 2015 | + return NULL_RTX; |
| 2016 | +} |
| 2017 | + |
| 2018 | + |
| 2019 | +/* Handle an "interrupt" or "isr" attribute; |
| 2020 | + arguments as in struct attribute_spec.handler. */ |
| 2021 | +static tree |
| 2022 | +avr32_handle_isr_attribute (tree * node, tree name, tree args, |
| 2023 | + int flags, bool * no_add_attrs) |
| 2024 | +{ |
| 2025 | + if (DECL_P (*node)) |
| 2026 | + { |
| 2027 | + if (TREE_CODE (*node) != FUNCTION_DECL) |
| 2028 | + { |
| 2029 | + warning (OPT_Wattributes,"`%s' attribute only applies to functions", |
| 2030 | + IDENTIFIER_POINTER (name)); |
| 2031 | + *no_add_attrs = true; |
| 2032 | + } |
| 2033 | + /* FIXME: the argument if any is checked for type attributes; should it |
| 2034 | + be checked for decl ones? */ |
| 2035 | + } |
| 2036 | + else |
| 2037 | + { |
| 2038 | + if (TREE_CODE (*node) == FUNCTION_TYPE |
| 2039 | + || TREE_CODE (*node) == METHOD_TYPE) |
| 2040 | + { |
| 2041 | + if (avr32_isr_value (args) == AVR32_FT_UNKNOWN) |
| 2042 | + { |
| 2043 | + warning (OPT_Wattributes,"`%s' attribute ignored", IDENTIFIER_POINTER (name)); |
| 2044 | + *no_add_attrs = true; |
| 2045 | + } |
| 2046 | + } |
| 2047 | + else if (TREE_CODE (*node) == POINTER_TYPE |
| 2048 | + && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE |
| 2049 | + || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE) |
| 2050 | + && avr32_isr_value (args) != AVR32_FT_UNKNOWN) |
| 2051 | + { |
| 2052 | + *node = build_variant_type_copy (*node); |
| 2053 | + TREE_TYPE (*node) = build_type_attribute_variant |
| 2054 | + (TREE_TYPE (*node), |
| 2055 | + tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node)))); |
| 2056 | + *no_add_attrs = true; |
| 2057 | + } |
| 2058 | + else |
| 2059 | + { |
| 2060 | + /* Possibly pass this attribute on from the type to a decl. */ |
| 2061 | + if (flags & ((int) ATTR_FLAG_DECL_NEXT |
| 2062 | + | (int) ATTR_FLAG_FUNCTION_NEXT |
| 2063 | + | (int) ATTR_FLAG_ARRAY_NEXT)) |
| 2064 | + { |
| 2065 | + *no_add_attrs = true; |
| 2066 | + return tree_cons (name, args, NULL_TREE); |
| 2067 | + } |
| 2068 | + else |
| 2069 | + { |
| 2070 | + warning (OPT_Wattributes,"`%s' attribute ignored", IDENTIFIER_POINTER (name)); |
| 2071 | + } |
| 2072 | + } |
| 2073 | + } |
| 2074 | + |
| 2075 | + return NULL_TREE; |
| 2076 | +} |
| 2077 | + |
| 2078 | + |
| 2079 | +/* Handle an attribute requiring a FUNCTION_DECL; |
| 2080 | + arguments as in struct attribute_spec.handler. */ |
| 2081 | +static tree |
| 2082 | +avr32_handle_fndecl_attribute (tree * node, tree name, |
| 2083 | + tree args, |
| 2084 | + int flags ATTRIBUTE_UNUSED, |
| 2085 | + bool * no_add_attrs) |
| 2086 | +{ |
| 2087 | + if (TREE_CODE (*node) != FUNCTION_DECL) |
| 2088 | + { |
| 2089 | + warning (OPT_Wattributes,"%qs attribute only applies to functions", |
| 2090 | + IDENTIFIER_POINTER (name)); |
| 2091 | + *no_add_attrs = true; |
| 2092 | + return NULL_TREE; |
| 2093 | + } |
| 2094 | + |
| 2095 | + fndecl_attribute_args = args; |
| 2096 | + if (args == NULL_TREE) |
| 2097 | + return NULL_TREE; |
| 2098 | + |
| 2099 | + tree value = TREE_VALUE (args); |
| 2100 | + if (TREE_CODE (value) != INTEGER_CST) |
| 2101 | + { |
| 2102 | + warning (OPT_Wattributes, |
| 2103 | + "argument of %qs attribute is not an integer constant", |
| 2104 | + IDENTIFIER_POINTER (name)); |
| 2105 | + *no_add_attrs = true; |
| 2106 | + } |
| 2107 | + |
| 2108 | + return NULL_TREE; |
| 2109 | +} |
| 2110 | + |
| 2111 | + |
| 2112 | +/* Handle an acall attribute; |
| 2113 | + arguments as in struct attribute_spec.handler. */ |
| 2114 | + |
| 2115 | +static tree |
| 2116 | +avr32_handle_acall_attribute (tree * node, tree name, |
| 2117 | + tree args ATTRIBUTE_UNUSED, |
| 2118 | + int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) |
| 2119 | +{ |
| 2120 | + if (TREE_CODE (*node) == FUNCTION_TYPE || TREE_CODE (*node) == METHOD_TYPE) |
| 2121 | + { |
| 2122 | + warning (OPT_Wattributes,"`%s' attribute not yet supported...", |
| 2123 | + IDENTIFIER_POINTER (name)); |
| 2124 | + *no_add_attrs = true; |
| 2125 | + return NULL_TREE; |
| 2126 | + } |
| 2127 | + |
| 2128 | + warning (OPT_Wattributes,"`%s' attribute only applies to functions", |
| 2129 | + IDENTIFIER_POINTER (name)); |
| 2130 | + *no_add_attrs = true; |
| 2131 | + return NULL_TREE; |
| 2132 | +} |
| 2133 | + |
| 2134 | + |
| 2135 | +bool |
| 2136 | +avr32_flashvault_call(tree decl) |
| 2137 | +{ |
| 2138 | + tree attributes; |
| 2139 | + tree fv_attribute; |
| 2140 | + tree vector_tree; |
| 2141 | + unsigned int vector; |
| 2142 | + |
| 2143 | + if (decl && TREE_CODE (decl) == FUNCTION_DECL) |
| 2144 | + { |
| 2145 | + attributes = DECL_ATTRIBUTES(decl); |
| 2146 | + fv_attribute = lookup_attribute ("flashvault", attributes); |
| 2147 | + if (fv_attribute != NULL_TREE) |
| 2148 | + { |
| 2149 | + /* Get attribute parameter, for the function vector number. */ |
| 2150 | + /* |
| 2151 | + There is probably an easier, standard way to retrieve the |
| 2152 | + attribute parameter which needs to be done here. |
| 2153 | + */ |
| 2154 | + vector_tree = TREE_VALUE(fv_attribute); |
| 2155 | + if (vector_tree != NULL_TREE) |
| 2156 | + { |
| 2157 | + vector = (unsigned int)TREE_INT_CST_LOW(TREE_VALUE(vector_tree)); |
| 2158 | + fprintf (asm_out_file, |
| 2159 | + "\tmov\tr8, lo(%i)\t# Load vector number for sscall.\n", |
| 2160 | + vector); |
| 2161 | + } |
| 2162 | + |
| 2163 | + fprintf (asm_out_file, |
| 2164 | + "\tsscall\t# Secure system call.\n"); |
| 2165 | + |
| 2166 | + return true; |
| 2167 | + } |
| 2168 | + } |
| 2169 | + |
| 2170 | + return false; |
| 2171 | +} |
| 2172 | + |
| 2173 | + |
| 2174 | +static bool has_attribute_p (tree decl, const char *name) |
| 2175 | +{ |
| 2176 | + if (decl && TREE_CODE (decl) == FUNCTION_DECL) |
| 2177 | + { |
| 2178 | + return (lookup_attribute (name, DECL_ATTRIBUTES(decl)) != NULL_TREE); |
| 2179 | + } |
| 2180 | + return NULL_TREE; |
| 2181 | +} |
| 2182 | + |
| 2183 | + |
| 2184 | +/* Return 0 if the attributes for two types are incompatible, 1 if they |
| 2185 | + are compatible, and 2 if they are nearly compatible (which causes a |
| 2186 | + warning to be generated). */ |
| 2187 | +static int |
| 2188 | +avr32_comp_type_attributes (tree type1, tree type2) |
| 2189 | +{ |
| 2190 | + bool acall1, acall2, isr1, isr2, naked1, naked2, fv1, fv2, fvimpl1, fvimpl2; |
| 2191 | + |
| 2192 | + /* Check for mismatch of non-default calling convention. */ |
| 2193 | + if (TREE_CODE (type1) != FUNCTION_TYPE) |
| 2194 | + return 1; |
| 2195 | + |
| 2196 | + /* Check for mismatched call attributes. */ |
| 2197 | + acall1 = lookup_attribute ("acall", TYPE_ATTRIBUTES (type1)) != NULL; |
| 2198 | + acall2 = lookup_attribute ("acall", TYPE_ATTRIBUTES (type2)) != NULL; |
| 2199 | + naked1 = lookup_attribute ("naked", TYPE_ATTRIBUTES (type1)) != NULL; |
| 2200 | + naked2 = lookup_attribute ("naked", TYPE_ATTRIBUTES (type2)) != NULL; |
| 2201 | + fv1 = lookup_attribute ("flashvault", TYPE_ATTRIBUTES (type1)) != NULL; |
| 2202 | + fv2 = lookup_attribute ("flashvault", TYPE_ATTRIBUTES (type2)) != NULL; |
| 2203 | + fvimpl1 = lookup_attribute ("flashvault_impl", TYPE_ATTRIBUTES (type1)) != NULL; |
| 2204 | + fvimpl2 = lookup_attribute ("flashvault_impl", TYPE_ATTRIBUTES (type2)) != NULL; |
| 2205 | + isr1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL; |
| 2206 | + if (!isr1) |
| 2207 | + isr1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL; |
| 2208 | + |
| 2209 | + isr2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL; |
| 2210 | + if (!isr2) |
| 2211 | + isr2 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL; |
| 2212 | + |
| 2213 | + if ((acall1 && isr2) |
| 2214 | + || (acall2 && isr1) |
| 2215 | + || (naked1 && isr2) |
| 2216 | + || (naked2 && isr1) |
| 2217 | + || (fv1 && isr2) |
| 2218 | + || (fv2 && isr1) |
| 2219 | + || (fvimpl1 && isr2) |
| 2220 | + || (fvimpl2 && isr1) |
| 2221 | + || (fv1 && fvimpl2) |
| 2222 | + || (fv2 && fvimpl1) |
| 2223 | + ) |
| 2224 | + return 0; |
| 2225 | + |
| 2226 | + return 1; |
| 2227 | +} |
| 2228 | + |
| 2229 | + |
| 2230 | +/* Computes the type of the current function. */ |
| 2231 | +static unsigned long |
| 2232 | +avr32_compute_func_type (void) |
| 2233 | +{ |
| 2234 | + unsigned long type = AVR32_FT_UNKNOWN; |
| 2235 | + tree a; |
| 2236 | + tree attr; |
| 2237 | + |
| 2238 | + if (TREE_CODE (current_function_decl) != FUNCTION_DECL) |
| 2239 | + abort (); |
| 2240 | + |
| 2241 | + /* Decide if the current function is volatile. Such functions never |
| 2242 | + return, and many memory cycles can be saved by not storing register |
| 2243 | + values that will never be needed again. This optimization was added to |
| 2244 | + speed up context switching in a kernel application. */ |
| 2245 | + if (optimize > 0 |
| 2246 | + && TREE_NOTHROW (current_function_decl) |
| 2247 | + && TREE_THIS_VOLATILE (current_function_decl)) |
| 2248 | + type |= AVR32_FT_VOLATILE; |
| 2249 | + |
| 2250 | + if (cfun->static_chain_decl != NULL) |
| 2251 | + type |= AVR32_FT_NESTED; |
| 2252 | + |
| 2253 | + attr = DECL_ATTRIBUTES (current_function_decl); |
| 2254 | + |
| 2255 | + a = lookup_attribute ("isr", attr); |
| 2256 | + if (a == NULL_TREE) |
| 2257 | + a = lookup_attribute ("interrupt", attr); |
| 2258 | + |
| 2259 | + if (a == NULL_TREE) |
| 2260 | + type |= AVR32_FT_NORMAL; |
| 2261 | + else |
| 2262 | + type |= avr32_isr_value (TREE_VALUE (a)); |
| 2263 | + |
| 2264 | + |
| 2265 | + a = lookup_attribute ("acall", attr); |
| 2266 | + if (a != NULL_TREE) |
| 2267 | + type |= AVR32_FT_ACALL; |
| 2268 | + |
| 2269 | + a = lookup_attribute ("naked", attr); |
| 2270 | + if (a != NULL_TREE) |
| 2271 | + type |= AVR32_FT_NAKED; |
| 2272 | + |
| 2273 | + a = lookup_attribute ("flashvault", attr); |
| 2274 | + if (a != NULL_TREE) |
| 2275 | + type |= AVR32_FT_FLASHVAULT; |
| 2276 | + |
| 2277 | + a = lookup_attribute ("flashvault_impl", attr); |
| 2278 | + if (a != NULL_TREE) |
| 2279 | + type |= AVR32_FT_FLASHVAULT_IMPL; |
| 2280 | + |
| 2281 | + return type; |
| 2282 | +} |
| 2283 | + |
| 2284 | + |
| 2285 | +/* Returns the type of the current function. */ |
| 2286 | +static unsigned long |
| 2287 | +avr32_current_func_type (void) |
| 2288 | +{ |
| 2289 | + if (AVR32_FUNC_TYPE (cfun->machine->func_type) == AVR32_FT_UNKNOWN) |
| 2290 | + cfun->machine->func_type = avr32_compute_func_type (); |
| 2291 | + |
| 2292 | + return cfun->machine->func_type; |
| 2293 | +} |
| 2294 | + |
| 2295 | + |
| 2296 | +/* |
| 2297 | +This target hook should return true if we should not pass type solely |
| 2298 | +in registers. The file expr.h defines a definition that is usually appropriate, |
| 2299 | +refer to expr.h for additional documentation. |
| 2300 | +*/ |
| 2301 | +bool |
| 2302 | +avr32_must_pass_in_stack (enum machine_mode mode ATTRIBUTE_UNUSED, tree type) |
| 2303 | +{ |
| 2304 | + if (type && AGGREGATE_TYPE_P (type) |
| 2305 | + /* If the alignment is less than the size then pass in the struct on |
| 2306 | + the stack. */ |
| 2307 | + && ((unsigned int) TYPE_ALIGN_UNIT (type) < |
| 2308 | + (unsigned int) int_size_in_bytes (type)) |
| 2309 | + /* If we support unaligned word accesses then structs of size 4 and 8 |
| 2310 | + can have any alignment and still be passed in registers. */ |
| 2311 | + && !(TARGET_UNALIGNED_WORD |
| 2312 | + && (int_size_in_bytes (type) == 4 |
| 2313 | + || int_size_in_bytes (type) == 8)) |
| 2314 | + /* Double word structs need only a word alignment. */ |
| 2315 | + && !(int_size_in_bytes (type) == 8 && TYPE_ALIGN_UNIT (type) >= 4)) |
| 2316 | + return true; |
| 2317 | + |
| 2318 | + if (type && AGGREGATE_TYPE_P (type) |
| 2319 | + /* Structs of size 3,5,6,7 are always passed in registers. */ |
| 2320 | + && (int_size_in_bytes (type) == 3 |
| 2321 | + || int_size_in_bytes (type) == 5 |
| 2322 | + || int_size_in_bytes (type) == 6 || int_size_in_bytes (type) == 7)) |
| 2323 | + return true; |
| 2324 | + |
| 2325 | + |
| 2326 | + return (type && TREE_ADDRESSABLE (type)); |
| 2327 | +} |
| 2328 | + |
| 2329 | + |
| 2330 | +bool |
| 2331 | +avr32_strict_argument_naming (CUMULATIVE_ARGS * ca ATTRIBUTE_UNUSED) |
| 2332 | +{ |
| 2333 | + return true; |
| 2334 | +} |
| 2335 | + |
| 2336 | + |
| 2337 | +/* |
| 2338 | + This target hook should return true if an argument at the position indicated |
| 2339 | + by cum should be passed by reference. This predicate is queried after target |
| 2340 | + independent reasons for being passed by reference, such as TREE_ADDRESSABLE (type). |
| 2341 | + |
| 2342 | + If the hook returns true, a copy of that argument is made in memory and a |
| 2343 | + pointer to the argument is passed instead of the argument itself. The pointer |
| 2344 | + is passed in whatever way is appropriate for passing a pointer to that type. |
| 2345 | +*/ |
| 2346 | +bool |
| 2347 | +avr32_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED, |
| 2348 | + enum machine_mode mode ATTRIBUTE_UNUSED, |
| 2349 | + tree type, bool named ATTRIBUTE_UNUSED) |
| 2350 | +{ |
| 2351 | + return (type && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)); |
| 2352 | +} |
| 2353 | + |
| 2354 | + |
| 2355 | +static int |
| 2356 | +avr32_arg_partial_bytes (CUMULATIVE_ARGS * pcum ATTRIBUTE_UNUSED, |
| 2357 | + enum machine_mode mode ATTRIBUTE_UNUSED, |
| 2358 | + tree type ATTRIBUTE_UNUSED, |
| 2359 | + bool named ATTRIBUTE_UNUSED) |
| 2360 | +{ |
| 2361 | + return 0; |
| 2362 | +} |
| 2363 | + |
| 2364 | + |
| 2365 | +struct gcc_target targetm = TARGET_INITIALIZER; |
| 2366 | + |
| 2367 | +/* |
| 2368 | + Table used to convert from register number in the assembler instructions and |
| 2369 | + the register numbers used in gcc. |
| 2370 | +*/ |
| 2371 | +const int avr32_function_arg_reglist[] = { |
| 2372 | + INTERNAL_REGNUM (12), |
| 2373 | + INTERNAL_REGNUM (11), |
| 2374 | + INTERNAL_REGNUM (10), |
| 2375 | + INTERNAL_REGNUM (9), |
| 2376 | + INTERNAL_REGNUM (8) |
| 2377 | +}; |
| 2378 | + |
| 2379 | + |
| 2380 | +rtx avr32_compare_op0 = NULL_RTX; |
| 2381 | +rtx avr32_compare_op1 = NULL_RTX; |
| 2382 | +rtx avr32_compare_operator = NULL_RTX; |
| 2383 | +rtx avr32_acc_cache = NULL_RTX; |
| 2384 | +/* type of branch to use */ |
| 2385 | +enum avr32_cmp_type avr32_branch_type; |
| 2386 | + |
| 2387 | + |
| 2388 | +/* |
| 2389 | + Returns nonzero if it is allowed to store a value of mode mode in hard |
| 2390 | + register number regno. |
| 2391 | +*/ |
| 2392 | +int |
| 2393 | +avr32_hard_regno_mode_ok (int regnr, enum machine_mode mode) |
| 2394 | +{ |
| 2395 | + switch (mode) |
| 2396 | + { |
| 2397 | + case DImode: /* long long */ |
| 2398 | + case DFmode: /* double */ |
| 2399 | + case SCmode: /* __complex__ float */ |
| 2400 | + case CSImode: /* __complex__ int */ |
| 2401 | + if (regnr < 4) |
| 2402 | + { /* long long int not supported in r12, sp, lr or pc. */ |
| 2403 | + return 0; |
| 2404 | + } |
| 2405 | + else |
| 2406 | + { |
| 2407 | + /* long long int has to be referred in even registers. */ |
| 2408 | + if (regnr % 2) |
| 2409 | + return 0; |
| 2410 | + else |
| 2411 | + return 1; |
| 2412 | + } |
| 2413 | + case CDImode: /* __complex__ long long */ |
| 2414 | + case DCmode: /* __complex__ double */ |
| 2415 | + case TImode: /* 16 bytes */ |
| 2416 | + if (regnr < 7) |
| 2417 | + return 0; |
| 2418 | + else if (regnr % 2) |
| 2419 | + return 0; |
| 2420 | + else |
| 2421 | + return 1; |
| 2422 | + default: |
| 2423 | + return 1; |
| 2424 | + } |
| 2425 | +} |
| 2426 | + |
| 2427 | + |
| 2428 | +int |
| 2429 | +avr32_rnd_operands (rtx add, rtx shift) |
| 2430 | +{ |
| 2431 | + if (GET_CODE (shift) == CONST_INT && |
| 2432 | + GET_CODE (add) == CONST_INT && INTVAL (shift) > 0) |
| 2433 | + { |
| 2434 | + if ((1 << (INTVAL (shift) - 1)) == INTVAL (add)) |
| 2435 | + return TRUE; |
| 2436 | + } |
| 2437 | + |
| 2438 | + return FALSE; |
| 2439 | +} |
| 2440 | + |
| 2441 | + |
| 2442 | +int |
| 2443 | +avr32_const_ok_for_constraint_p (HOST_WIDE_INT value, char c, const char *str) |
| 2444 | +{ |
| 2445 | + switch (c) |
| 2446 | + { |
| 2447 | + case 'K': |
| 2448 | + case 'I': |
| 2449 | + { |
| 2450 | + HOST_WIDE_INT min_value = 0, max_value = 0; |
| 2451 | + char size_str[3]; |
| 2452 | + int const_size; |
| 2453 | + |
| 2454 | + size_str[0] = str[2]; |
| 2455 | + size_str[1] = str[3]; |
| 2456 | + size_str[2] = '\0'; |
| 2457 | + const_size = atoi (size_str); |
| 2458 | + |
| 2459 | + if (TOUPPER (str[1]) == 'U') |
| 2460 | + { |
| 2461 | + min_value = 0; |
| 2462 | + max_value = (1 << const_size) - 1; |
| 2463 | + } |
| 2464 | + else if (TOUPPER (str[1]) == 'S') |
| 2465 | + { |
| 2466 | + min_value = -(1 << (const_size - 1)); |
| 2467 | + max_value = (1 << (const_size - 1)) - 1; |
| 2468 | + } |
| 2469 | + |
| 2470 | + if (c == 'I') |
| 2471 | + { |
| 2472 | + value = -value; |
| 2473 | + } |
| 2474 | + |
| 2475 | + if (value >= min_value && value <= max_value) |
| 2476 | + { |
| 2477 | + return 1; |
| 2478 | + } |
| 2479 | + break; |
| 2480 | + } |
| 2481 | + case 'M': |
| 2482 | + return avr32_mask_upper_bits_operand (GEN_INT (value), VOIDmode); |
| 2483 | + case 'J': |
| 2484 | + return avr32_hi16_immediate_operand (GEN_INT (value), VOIDmode); |
| 2485 | + case 'O': |
| 2486 | + return one_bit_set_operand (GEN_INT (value), VOIDmode); |
| 2487 | + case 'N': |
| 2488 | + return one_bit_cleared_operand (GEN_INT (value), VOIDmode); |
| 2489 | + case 'L': |
| 2490 | + /* The lower 16-bits are set. */ |
| 2491 | + return ((value & 0xffff) == 0xffff) ; |
| 2492 | + } |
| 2493 | + |
| 2494 | + return 0; |
| 2495 | +} |
| 2496 | + |
| 2497 | + |
| 2498 | +/* Compute mask of registers which needs saving upon function entry. */ |
| 2499 | +static unsigned long |
| 2500 | +avr32_compute_save_reg_mask (int push) |
| 2501 | +{ |
| 2502 | + unsigned long func_type; |
| 2503 | + unsigned int save_reg_mask = 0; |
| 2504 | + unsigned int reg; |
| 2505 | + |
| 2506 | + func_type = avr32_current_func_type (); |
| 2507 | + |
| 2508 | + if (IS_INTERRUPT (func_type)) |
| 2509 | + { |
| 2510 | + unsigned int max_reg = 12; |
| 2511 | + |
| 2512 | + /* Get the banking scheme for the interrupt */ |
| 2513 | + switch (func_type) |
| 2514 | + { |
| 2515 | + case AVR32_FT_ISR_FULL: |
| 2516 | + max_reg = 0; |
| 2517 | + break; |
| 2518 | + case AVR32_FT_ISR_HALF: |
| 2519 | + max_reg = 7; |
| 2520 | + break; |
| 2521 | + case AVR32_FT_ISR_NONE: |
| 2522 | + max_reg = 12; |
| 2523 | + break; |
| 2524 | + } |
| 2525 | + |
| 2526 | + /* Interrupt functions must not corrupt any registers, even call |
| 2527 | + clobbered ones. If this is a leaf function we can just examine the |
| 2528 | + registers used by the RTL, but otherwise we have to assume that |
| 2529 | + whatever function is called might clobber anything, and so we have |
| 2530 | + to save all the call-clobbered registers as well. */ |
| 2531 | + |
| 2532 | + /* Need not push the registers r8-r12 for AVR32A architectures, as this |
| 2533 | + is automatially done in hardware. We also do not have any shadow |
| 2534 | + registers. */ |
| 2535 | + if (TARGET_UARCH_AVR32A) |
| 2536 | + { |
| 2537 | + max_reg = 7; |
| 2538 | + func_type = AVR32_FT_ISR_NONE; |
| 2539 | + } |
| 2540 | + |
| 2541 | + /* All registers which are used and are not shadowed must be saved. */ |
| 2542 | + for (reg = 0; reg <= max_reg; reg++) |
| 2543 | + if (df_regs_ever_live_p (INTERNAL_REGNUM (reg)) |
| 2544 | + || (!current_function_is_leaf |
| 2545 | + && call_used_regs[INTERNAL_REGNUM (reg)])) |
| 2546 | + save_reg_mask |= (1 << reg); |
| 2547 | + |
| 2548 | + /* Check LR */ |
| 2549 | + if ((df_regs_ever_live_p (LR_REGNUM) |
| 2550 | + || !current_function_is_leaf || frame_pointer_needed) |
| 2551 | + /* Only non-shadowed register models */ |
| 2552 | + && (func_type == AVR32_FT_ISR_NONE)) |
| 2553 | + save_reg_mask |= (1 << ASM_REGNUM (LR_REGNUM)); |
| 2554 | + |
| 2555 | + /* Make sure that the GOT register is pushed. */ |
| 2556 | + if (max_reg >= ASM_REGNUM (PIC_OFFSET_TABLE_REGNUM) |
| 2557 | + && crtl->uses_pic_offset_table) |
| 2558 | + save_reg_mask |= (1 << ASM_REGNUM (PIC_OFFSET_TABLE_REGNUM)); |
| 2559 | + |
| 2560 | + } |
| 2561 | + else |
| 2562 | + { |
| 2563 | + int use_pushm = optimize_size; |
| 2564 | + |
| 2565 | + /* In the normal case we only need to save those registers which are |
| 2566 | + call saved and which are used by this function. */ |
| 2567 | + for (reg = 0; reg <= 7; reg++) |
| 2568 | + if (df_regs_ever_live_p (INTERNAL_REGNUM (reg)) |
| 2569 | + && !call_used_regs[INTERNAL_REGNUM (reg)]) |
| 2570 | + save_reg_mask |= (1 << reg); |
| 2571 | + |
| 2572 | + /* Make sure that the GOT register is pushed. */ |
| 2573 | + if (crtl->uses_pic_offset_table) |
| 2574 | + save_reg_mask |= (1 << ASM_REGNUM (PIC_OFFSET_TABLE_REGNUM)); |
| 2575 | + |
| 2576 | + |
| 2577 | + /* If we optimize for size and do not have anonymous arguments: use |
| 2578 | + pushm/popm always. */ |
| 2579 | + if (use_pushm) |
| 2580 | + { |
| 2581 | + if ((save_reg_mask & (1 << 0)) |
| 2582 | + || (save_reg_mask & (1 << 1)) |
| 2583 | + || (save_reg_mask & (1 << 2)) || (save_reg_mask & (1 << 3))) |
| 2584 | + save_reg_mask |= 0xf; |
| 2585 | + |
| 2586 | + if ((save_reg_mask & (1 << 4)) |
| 2587 | + || (save_reg_mask & (1 << 5)) |
| 2588 | + || (save_reg_mask & (1 << 6)) || (save_reg_mask & (1 << 7))) |
| 2589 | + save_reg_mask |= 0xf0; |
| 2590 | + |
| 2591 | + if ((save_reg_mask & (1 << 8)) || (save_reg_mask & (1 << 9))) |
| 2592 | + save_reg_mask |= 0x300; |
| 2593 | + } |
| 2594 | + |
| 2595 | + |
| 2596 | + /* Check LR */ |
| 2597 | + if ((df_regs_ever_live_p (LR_REGNUM) |
| 2598 | + || !current_function_is_leaf |
| 2599 | + || (optimize_size |
| 2600 | + && save_reg_mask |
| 2601 | + && !crtl->calls_eh_return) |
| 2602 | + || frame_pointer_needed) |
| 2603 | + && !IS_FLASHVAULT (func_type)) |
| 2604 | + { |
| 2605 | + if (push |
| 2606 | + /* Never pop LR into PC for functions which |
| 2607 | + calls __builtin_eh_return, since we need to |
| 2608 | + fix the SP after the restoring of the registers |
| 2609 | + and before returning. */ |
| 2610 | + || crtl->calls_eh_return) |
| 2611 | + { |
| 2612 | + /* Push/Pop LR */ |
| 2613 | + save_reg_mask |= (1 << ASM_REGNUM (LR_REGNUM)); |
| 2614 | + } |
| 2615 | + else |
| 2616 | + { |
| 2617 | + /* Pop PC */ |
| 2618 | + save_reg_mask |= (1 << ASM_REGNUM (PC_REGNUM)); |
| 2619 | + } |
| 2620 | + } |
| 2621 | + } |
| 2622 | + |
| 2623 | + |
| 2624 | + /* Save registers so the exception handler can modify them. */ |
| 2625 | + if (crtl->calls_eh_return) |
| 2626 | + { |
| 2627 | + unsigned int i; |
| 2628 | + |
| 2629 | + for (i = 0;; i++) |
| 2630 | + { |
| 2631 | + reg = EH_RETURN_DATA_REGNO (i); |
| 2632 | + if (reg == INVALID_REGNUM) |
| 2633 | + break; |
| 2634 | + save_reg_mask |= 1 << ASM_REGNUM (reg); |
| 2635 | + } |
| 2636 | + } |
| 2637 | + |
| 2638 | + return save_reg_mask; |
| 2639 | +} |
| 2640 | + |
| 2641 | + |
| 2642 | +/* Compute total size in bytes of all saved registers. */ |
| 2643 | +static int |
| 2644 | +avr32_get_reg_mask_size (int reg_mask) |
| 2645 | +{ |
| 2646 | + int reg, size; |
| 2647 | + size = 0; |
| 2648 | + |
| 2649 | + for (reg = 0; reg <= 15; reg++) |
| 2650 | + if (reg_mask & (1 << reg)) |
| 2651 | + size += 4; |
| 2652 | + |
| 2653 | + return size; |
| 2654 | +} |
| 2655 | + |
| 2656 | + |
| 2657 | +/* Get a register from one of the registers which are saved onto the stack |
| 2658 | + upon function entry. */ |
| 2659 | +static int |
| 2660 | +avr32_get_saved_reg (int save_reg_mask) |
| 2661 | +{ |
| 2662 | + unsigned int reg; |
| 2663 | + |
| 2664 | + /* Find the first register which is saved in the saved_reg_mask */ |
| 2665 | + for (reg = 0; reg <= 15; reg++) |
| 2666 | + if (save_reg_mask & (1 << reg)) |
| 2667 | + return reg; |
| 2668 | + |
| 2669 | + return -1; |
| 2670 | +} |
| 2671 | + |
| 2672 | + |
| 2673 | +/* Return 1 if it is possible to return using a single instruction. */ |
| 2674 | +int |
| 2675 | +avr32_use_return_insn (int iscond) |
| 2676 | +{ |
| 2677 | + unsigned int func_type = avr32_current_func_type (); |
| 2678 | + unsigned long saved_int_regs; |
| 2679 | + |
| 2680 | + /* Never use a return instruction before reload has run. */ |
| 2681 | + if (!reload_completed) |
| 2682 | + return 0; |
| 2683 | + |
| 2684 | + /* Must adjust the stack for vararg functions. */ |
| 2685 | + if (crtl->args.info.uses_anonymous_args) |
| 2686 | + return 0; |
| 2687 | + |
| 2688 | + /* If there a stack adjstment. */ |
| 2689 | + if (get_frame_size ()) |
| 2690 | + return 0; |
| 2691 | + |
| 2692 | + saved_int_regs = avr32_compute_save_reg_mask (TRUE); |
| 2693 | + |
| 2694 | + /* Conditional returns can not be performed in one instruction if we need |
| 2695 | + to restore registers from the stack */ |
| 2696 | + if (iscond && saved_int_regs) |
| 2697 | + return 0; |
| 2698 | + |
| 2699 | + /* Conditional return can not be used for interrupt handlers. */ |
| 2700 | + if (iscond && IS_INTERRUPT (func_type)) |
| 2701 | + return 0; |
| 2702 | + |
| 2703 | + /* For interrupt handlers which needs to pop registers */ |
| 2704 | + if (saved_int_regs && IS_INTERRUPT (func_type)) |
| 2705 | + return 0; |
| 2706 | + |
| 2707 | + |
| 2708 | + /* If there are saved registers but the LR isn't saved, then we need two |
| 2709 | + instructions for the return. */ |
| 2710 | + if (saved_int_regs && !(saved_int_regs & (1 << ASM_REGNUM (LR_REGNUM)))) |
| 2711 | + return 0; |
| 2712 | + |
| 2713 | + |
| 2714 | + return 1; |
| 2715 | +} |
| 2716 | + |
| 2717 | + |
| 2718 | +/* Generate some function prologue info in the assembly file. */ |
| 2719 | +void |
| 2720 | +avr32_target_asm_function_prologue (FILE * f, HOST_WIDE_INT frame_size) |
| 2721 | +{ |
| 2722 | + unsigned long func_type = avr32_current_func_type (); |
| 2723 | + |
| 2724 | + if (IS_NAKED (func_type)) |
| 2725 | + fprintf (f, |
| 2726 | + "\t# Function is naked: Prologue and epilogue provided by programmer\n"); |
| 2727 | + |
| 2728 | + if (IS_FLASHVAULT (func_type)) |
| 2729 | + { |
| 2730 | + fprintf(f, |
| 2731 | + "\t.ident \"flashvault\"\n\t# Function is defined with flashvault attribute.\n"); |
| 2732 | + } |
| 2733 | + |
| 2734 | + if (IS_FLASHVAULT_IMPL (func_type)) |
| 2735 | + { |
| 2736 | + fprintf(f, |
| 2737 | + "\t.ident \"flashvault\"\n\t# Function is defined with flashvault_impl attribute.\n"); |
| 2738 | + |
| 2739 | + /* Save information on flashvault function declaration. */ |
| 2740 | + tree fv_attribute = lookup_attribute ("flashvault_impl", DECL_ATTRIBUTES(current_function_decl)); |
| 2741 | + if (fv_attribute != NULL_TREE) |
| 2742 | + { |
| 2743 | + tree vector_tree = TREE_VALUE(fv_attribute); |
| 2744 | + if (vector_tree != NULL_TREE) |
| 2745 | + { |
| 2746 | + unsigned int vector_num; |
| 2747 | + const char * name; |
| 2748 | + |
| 2749 | + vector_num = (unsigned int) TREE_INT_CST_LOW (TREE_VALUE (vector_tree)); |
| 2750 | + |
| 2751 | + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); |
| 2752 | + |
| 2753 | + flashvault_decl_list_add (vector_num, name); |
| 2754 | + } |
| 2755 | + } |
| 2756 | + } |
| 2757 | + |
| 2758 | + if (IS_INTERRUPT (func_type)) |
| 2759 | + { |
| 2760 | + switch (func_type) |
| 2761 | + { |
| 2762 | + case AVR32_FT_ISR_FULL: |
| 2763 | + fprintf (f, |
| 2764 | + "\t# Interrupt Function: Fully shadowed register file\n"); |
| 2765 | + break; |
| 2766 | + case AVR32_FT_ISR_HALF: |
| 2767 | + fprintf (f, |
| 2768 | + "\t# Interrupt Function: Half shadowed register file\n"); |
| 2769 | + break; |
| 2770 | + default: |
| 2771 | + case AVR32_FT_ISR_NONE: |
| 2772 | + fprintf (f, "\t# Interrupt Function: No shadowed register file\n"); |
| 2773 | + break; |
| 2774 | + } |
| 2775 | + } |
| 2776 | + |
| 2777 | + |
| 2778 | + fprintf (f, "\t# args = %i, frame = %li, pretend = %i\n", |
| 2779 | + crtl->args.size, frame_size, |
| 2780 | + crtl->args.pretend_args_size); |
| 2781 | + |
| 2782 | + fprintf (f, "\t# frame_needed = %i, leaf_function = %i\n", |
| 2783 | + frame_pointer_needed, current_function_is_leaf); |
| 2784 | + |
| 2785 | + fprintf (f, "\t# uses_anonymous_args = %i\n", |
| 2786 | + crtl->args.info.uses_anonymous_args); |
| 2787 | + |
| 2788 | + if (crtl->calls_eh_return) |
| 2789 | + fprintf (f, "\t# Calls __builtin_eh_return.\n"); |
| 2790 | + |
| 2791 | +} |
| 2792 | + |
| 2793 | + |
| 2794 | +/* Generate and emit an insn that we will recognize as a pushm or stm. |
| 2795 | + Unfortunately, since this insn does not reflect very well the actual |
| 2796 | + semantics of the operation, we need to annotate the insn for the benefit |
| 2797 | + of DWARF2 frame unwind information. */ |
| 2798 | + |
| 2799 | +int avr32_convert_to_reglist16 (int reglist8_vect); |
| 2800 | + |
| 2801 | +static rtx |
| 2802 | +emit_multi_reg_push (int reglist, int usePUSHM) |
| 2803 | +{ |
| 2804 | + rtx insn; |
| 2805 | + rtx dwarf; |
| 2806 | + rtx tmp; |
| 2807 | + rtx reg; |
| 2808 | + int i; |
| 2809 | + int nr_regs; |
| 2810 | + int index = 0; |
| 2811 | + |
| 2812 | + if (usePUSHM) |
| 2813 | + { |
| 2814 | + insn = emit_insn (gen_pushm (gen_rtx_CONST_INT (SImode, reglist))); |
| 2815 | + reglist = avr32_convert_to_reglist16 (reglist); |
| 2816 | + } |
| 2817 | + else |
| 2818 | + { |
| 2819 | + insn = emit_insn (gen_stm (stack_pointer_rtx, |
| 2820 | + gen_rtx_CONST_INT (SImode, reglist), |
| 2821 | + gen_rtx_CONST_INT (SImode, 1))); |
| 2822 | + } |
| 2823 | + |
| 2824 | + nr_regs = avr32_get_reg_mask_size (reglist) / 4; |
| 2825 | + dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (nr_regs + 1)); |
| 2826 | + |
| 2827 | + for (i = 15; i >= 0; i--) |
| 2828 | + { |
| 2829 | + if (reglist & (1 << i)) |
| 2830 | + { |
| 2831 | + reg = gen_rtx_REG (SImode, INTERNAL_REGNUM (i)); |
| 2832 | + tmp = gen_rtx_SET (VOIDmode, |
| 2833 | + gen_rtx_MEM (SImode, |
| 2834 | + plus_constant (stack_pointer_rtx, |
| 2835 | + 4 * index)), reg); |
| 2836 | + RTX_FRAME_RELATED_P (tmp) = 1; |
| 2837 | + XVECEXP (dwarf, 0, 1 + index++) = tmp; |
| 2838 | + } |
| 2839 | + } |
| 2840 | + |
| 2841 | + tmp = gen_rtx_SET (SImode, |
| 2842 | + stack_pointer_rtx, |
| 2843 | + gen_rtx_PLUS (SImode, |
| 2844 | + stack_pointer_rtx, |
| 2845 | + GEN_INT (-4 * nr_regs))); |
| 2846 | + RTX_FRAME_RELATED_P (tmp) = 1; |
| 2847 | + XVECEXP (dwarf, 0, 0) = tmp; |
| 2848 | + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, |
| 2849 | + REG_NOTES (insn)); |
| 2850 | + return insn; |
| 2851 | +} |
| 2852 | + |
| 2853 | +rtx |
| 2854 | +avr32_gen_load_multiple (rtx * regs, int count, rtx from, |
| 2855 | + int write_back, int in_struct_p, int scalar_p) |
| 2856 | +{ |
| 2857 | + |
| 2858 | + rtx result; |
| 2859 | + int i = 0, j; |
| 2860 | + |
| 2861 | + result = |
| 2862 | + gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + (write_back ? 1 : 0))); |
| 2863 | + |
| 2864 | + if (write_back) |
| 2865 | + { |
| 2866 | + XVECEXP (result, 0, 0) |
| 2867 | + = gen_rtx_SET (GET_MODE (from), from, |
| 2868 | + plus_constant (from, count * 4)); |
| 2869 | + i = 1; |
| 2870 | + count++; |
| 2871 | + } |
| 2872 | + |
| 2873 | + |
| 2874 | + for (j = 0; i < count; i++, j++) |
| 2875 | + { |
| 2876 | + rtx unspec; |
| 2877 | + rtx mem = gen_rtx_MEM (SImode, plus_constant (from, j * 4)); |
| 2878 | + MEM_IN_STRUCT_P (mem) = in_struct_p; |
| 2879 | + MEM_SCALAR_P (mem) = scalar_p; |
| 2880 | + unspec = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, mem), UNSPEC_LDM); |
| 2881 | + XVECEXP (result, 0, i) = gen_rtx_SET (VOIDmode, regs[j], unspec); |
| 2882 | + } |
| 2883 | + |
| 2884 | + return result; |
| 2885 | +} |
| 2886 | + |
| 2887 | + |
| 2888 | +rtx |
| 2889 | +avr32_gen_store_multiple (rtx * regs, int count, rtx to, |
| 2890 | + int in_struct_p, int scalar_p) |
| 2891 | +{ |
| 2892 | + rtx result; |
| 2893 | + int i = 0, j; |
| 2894 | + |
| 2895 | + result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); |
| 2896 | + |
| 2897 | + for (j = 0; i < count; i++, j++) |
| 2898 | + { |
| 2899 | + rtx mem = gen_rtx_MEM (SImode, plus_constant (to, j * 4)); |
| 2900 | + MEM_IN_STRUCT_P (mem) = in_struct_p; |
| 2901 | + MEM_SCALAR_P (mem) = scalar_p; |
| 2902 | + XVECEXP (result, 0, i) |
| 2903 | + = gen_rtx_SET (VOIDmode, mem, |
| 2904 | + gen_rtx_UNSPEC (VOIDmode, |
| 2905 | + gen_rtvec (1, regs[j]), |
| 2906 | + UNSPEC_STORE_MULTIPLE)); |
| 2907 | + } |
| 2908 | + |
| 2909 | + return result; |
| 2910 | +} |
| 2911 | + |
| 2912 | + |
| 2913 | +/* Move a block of memory if it is word aligned or we support unaligned |
| 2914 | + word memory accesses. The size must be maximum 64 bytes. */ |
| 2915 | +int |
| 2916 | +avr32_gen_movmemsi (rtx * operands) |
| 2917 | +{ |
| 2918 | + HOST_WIDE_INT bytes_to_go; |
| 2919 | + rtx src, dst; |
| 2920 | + rtx st_src, st_dst; |
| 2921 | + int src_offset = 0, dst_offset = 0; |
| 2922 | + int block_size; |
| 2923 | + int dst_in_struct_p, src_in_struct_p; |
| 2924 | + int dst_scalar_p, src_scalar_p; |
| 2925 | + int unaligned; |
| 2926 | + |
| 2927 | + if (GET_CODE (operands[2]) != CONST_INT |
| 2928 | + || GET_CODE (operands[3]) != CONST_INT |
| 2929 | + || INTVAL (operands[2]) > 64 |
| 2930 | + || ((INTVAL (operands[3]) & 3) && !TARGET_UNALIGNED_WORD)) |
| 2931 | + return 0; |
| 2932 | + |
| 2933 | + unaligned = (INTVAL (operands[3]) & 3) != 0; |
| 2934 | + |
| 2935 | + block_size = 4; |
| 2936 | + |
| 2937 | + st_dst = XEXP (operands[0], 0); |
| 2938 | + st_src = XEXP (operands[1], 0); |
| 2939 | + |
| 2940 | + dst_in_struct_p = MEM_IN_STRUCT_P (operands[0]); |
| 2941 | + dst_scalar_p = MEM_SCALAR_P (operands[0]); |
| 2942 | + src_in_struct_p = MEM_IN_STRUCT_P (operands[1]); |
| 2943 | + src_scalar_p = MEM_SCALAR_P (operands[1]); |
| 2944 | + |
| 2945 | + dst = copy_to_mode_reg (SImode, st_dst); |
| 2946 | + src = copy_to_mode_reg (SImode, st_src); |
| 2947 | + |
| 2948 | + bytes_to_go = INTVAL (operands[2]); |
| 2949 | + |
| 2950 | + while (bytes_to_go) |
| 2951 | + { |
| 2952 | + enum machine_mode move_mode; |
| 2953 | + /* (Seems to be a problem with reloads for the movti pattern so this is |
| 2954 | + disabled until that problem is resolved) |
| 2955 | + UPDATE: Problem seems to be solved now.... */ |
| 2956 | + if (bytes_to_go >= GET_MODE_SIZE (TImode) && !unaligned |
| 2957 | + /* Do not emit ldm/stm for UC3 as ld.d/st.d is more optimal. */ |
| 2958 | + && !TARGET_ARCH_UC) |
| 2959 | + move_mode = TImode; |
| 2960 | + else if ((bytes_to_go >= GET_MODE_SIZE (DImode)) && !unaligned) |
| 2961 | + move_mode = DImode; |
| 2962 | + else if (bytes_to_go >= GET_MODE_SIZE (SImode)) |
| 2963 | + move_mode = SImode; |
| 2964 | + else |
| 2965 | + move_mode = QImode; |
| 2966 | + |
| 2967 | + { |
| 2968 | + rtx src_mem; |
| 2969 | + rtx dst_mem = gen_rtx_MEM (move_mode, |
| 2970 | + gen_rtx_PLUS (SImode, dst, |
| 2971 | + GEN_INT (dst_offset))); |
| 2972 | + dst_offset += GET_MODE_SIZE (move_mode); |
| 2973 | + if ( 0 /* This causes an error in GCC. Think there is |
| 2974 | + something wrong in the gcse pass which causes REQ_EQUIV notes |
| 2975 | + to be wrong so disabling it for now. */ |
| 2976 | + && move_mode == TImode |
| 2977 | + && INTVAL (operands[2]) > GET_MODE_SIZE (TImode) ) |
| 2978 | + { |
| 2979 | + src_mem = gen_rtx_MEM (move_mode, |
| 2980 | + gen_rtx_POST_INC (SImode, src)); |
| 2981 | + } |
| 2982 | + else |
| 2983 | + { |
| 2984 | + src_mem = gen_rtx_MEM (move_mode, |
| 2985 | + gen_rtx_PLUS (SImode, src, |
| 2986 | + GEN_INT (src_offset))); |
| 2987 | + src_offset += GET_MODE_SIZE (move_mode); |
| 2988 | + } |
| 2989 | + |
| 2990 | + bytes_to_go -= GET_MODE_SIZE (move_mode); |
| 2991 | + |
| 2992 | + MEM_IN_STRUCT_P (dst_mem) = dst_in_struct_p; |
| 2993 | + MEM_SCALAR_P (dst_mem) = dst_scalar_p; |
| 2994 | + |
| 2995 | + MEM_IN_STRUCT_P (src_mem) = src_in_struct_p; |
| 2996 | + MEM_SCALAR_P (src_mem) = src_scalar_p; |
| 2997 | + emit_move_insn (dst_mem, src_mem); |
| 2998 | + |
| 2999 | + } |
| 3000 | + } |
| 3001 | + |
| 3002 | + return 1; |
| 3003 | +} |
| 3004 | + |
| 3005 | + |
| 3006 | +/* Expand the prologue instruction. */ |
| 3007 | +void |
| 3008 | +avr32_expand_prologue (void) |
| 3009 | +{ |
| 3010 | + rtx insn, dwarf; |
| 3011 | + unsigned long saved_reg_mask; |
| 3012 | + int reglist8 = 0; |
| 3013 | + |
| 3014 | + /* Naked functions do not have a prologue. */ |
| 3015 | + if (IS_NAKED (avr32_current_func_type ())) |
| 3016 | + return; |
| 3017 | + |
| 3018 | + saved_reg_mask = avr32_compute_save_reg_mask (TRUE); |
| 3019 | + |
| 3020 | + if (saved_reg_mask) |
| 3021 | + { |
| 3022 | + /* Must push used registers. */ |
| 3023 | + |
| 3024 | + /* Should we use POPM or LDM? */ |
| 3025 | + int usePUSHM = TRUE; |
| 3026 | + reglist8 = 0; |
| 3027 | + if (((saved_reg_mask & (1 << 0)) || |
| 3028 | + (saved_reg_mask & (1 << 1)) || |
| 3029 | + (saved_reg_mask & (1 << 2)) || (saved_reg_mask & (1 << 3)))) |
| 3030 | + { |
| 3031 | + /* One of R0-R3 should at least be pushed. */ |
| 3032 | + if (((saved_reg_mask & (1 << 0)) && |
| 3033 | + (saved_reg_mask & (1 << 1)) && |
| 3034 | + (saved_reg_mask & (1 << 2)) && (saved_reg_mask & (1 << 3)))) |
| 3035 | + { |
| 3036 | + /* All should be pushed. */ |
| 3037 | + reglist8 |= 0x01; |
| 3038 | + } |
| 3039 | + else |
| 3040 | + { |
| 3041 | + usePUSHM = FALSE; |
| 3042 | + } |
| 3043 | + } |
| 3044 | + |
| 3045 | + if (((saved_reg_mask & (1 << 4)) || |
| 3046 | + (saved_reg_mask & (1 << 5)) || |
| 3047 | + (saved_reg_mask & (1 << 6)) || (saved_reg_mask & (1 << 7)))) |
| 3048 | + { |
| 3049 | + /* One of R4-R7 should at least be pushed */ |
| 3050 | + if (((saved_reg_mask & (1 << 4)) && |
| 3051 | + (saved_reg_mask & (1 << 5)) && |
| 3052 | + (saved_reg_mask & (1 << 6)) && (saved_reg_mask & (1 << 7)))) |
| 3053 | + { |
| 3054 | + if (usePUSHM) |
| 3055 | + /* All should be pushed */ |
| 3056 | + reglist8 |= 0x02; |
| 3057 | + } |
| 3058 | + else |
| 3059 | + { |
| 3060 | + usePUSHM = FALSE; |
| 3061 | + } |
| 3062 | + } |
| 3063 | + |
| 3064 | + if (((saved_reg_mask & (1 << 8)) || (saved_reg_mask & (1 << 9)))) |
| 3065 | + { |
| 3066 | + /* One of R8-R9 should at least be pushed. */ |
| 3067 | + if (((saved_reg_mask & (1 << 8)) && (saved_reg_mask & (1 << 9)))) |
| 3068 | + { |
| 3069 | + if (usePUSHM) |
| 3070 | + /* All should be pushed. */ |
| 3071 | + reglist8 |= 0x04; |
| 3072 | + } |
| 3073 | + else |
| 3074 | + { |
| 3075 | + usePUSHM = FALSE; |
| 3076 | + } |
| 3077 | + } |
| 3078 | + |
| 3079 | + if (saved_reg_mask & (1 << 10)) |
| 3080 | + reglist8 |= 0x08; |
| 3081 | + |
| 3082 | + if (saved_reg_mask & (1 << 11)) |
| 3083 | + reglist8 |= 0x10; |
| 3084 | + |
| 3085 | + if (saved_reg_mask & (1 << 12)) |
| 3086 | + reglist8 |= 0x20; |
| 3087 | + |
| 3088 | + if ((saved_reg_mask & (1 << ASM_REGNUM (LR_REGNUM))) |
| 3089 | + && !IS_FLASHVAULT (avr32_current_func_type ())) |
| 3090 | + { |
| 3091 | + /* Push LR */ |
| 3092 | + reglist8 |= 0x40; |
| 3093 | + } |
| 3094 | + |
| 3095 | + if (usePUSHM) |
| 3096 | + { |
| 3097 | + insn = emit_multi_reg_push (reglist8, TRUE); |
| 3098 | + } |
| 3099 | + else |
| 3100 | + { |
| 3101 | + insn = emit_multi_reg_push (saved_reg_mask, FALSE); |
| 3102 | + } |
| 3103 | + RTX_FRAME_RELATED_P (insn) = 1; |
| 3104 | + |
| 3105 | + /* Prevent this instruction from being scheduled after any other |
| 3106 | + instructions. */ |
| 3107 | + emit_insn (gen_blockage ()); |
| 3108 | + } |
| 3109 | + |
| 3110 | + /* Set frame pointer */ |
| 3111 | + if (frame_pointer_needed) |
| 3112 | + { |
| 3113 | + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); |
| 3114 | + RTX_FRAME_RELATED_P (insn) = 1; |
| 3115 | + } |
| 3116 | + |
| 3117 | + if (get_frame_size () > 0) |
| 3118 | + { |
| 3119 | + if (avr32_const_ok_for_constraint_p (get_frame_size (), 'K', "Ks21")) |
| 3120 | + { |
| 3121 | + insn = emit_insn (gen_rtx_SET (SImode, |
| 3122 | + stack_pointer_rtx, |
| 3123 | + gen_rtx_PLUS (SImode, |
| 3124 | + stack_pointer_rtx, |
| 3125 | + gen_rtx_CONST_INT |
| 3126 | + (SImode, |
| 3127 | + -get_frame_size |
| 3128 | + ())))); |
| 3129 | + RTX_FRAME_RELATED_P (insn) = 1; |
| 3130 | + } |
| 3131 | + else |
| 3132 | + { |
| 3133 | + /* Immediate is larger than k21 We must either check if we can use |
| 3134 | + one of the pushed reegisters as temporary storage or we must |
| 3135 | + make us a temp register by pushing a register to the stack. */ |
| 3136 | + rtx temp_reg, const_pool_entry, insn; |
| 3137 | + if (saved_reg_mask) |
| 3138 | + { |
| 3139 | + temp_reg = |
| 3140 | + gen_rtx_REG (SImode, |
| 3141 | + INTERNAL_REGNUM (avr32_get_saved_reg |
| 3142 | + (saved_reg_mask))); |
| 3143 | + } |
| 3144 | + else |
| 3145 | + { |
| 3146 | + temp_reg = gen_rtx_REG (SImode, INTERNAL_REGNUM (7)); |
| 3147 | + emit_move_insn (gen_rtx_MEM |
| 3148 | + (SImode, |
| 3149 | + gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)), |
| 3150 | + temp_reg); |
| 3151 | + } |
| 3152 | + |
| 3153 | + const_pool_entry = |
| 3154 | + force_const_mem (SImode, |
| 3155 | + gen_rtx_CONST_INT (SImode, get_frame_size ())); |
| 3156 | + emit_move_insn (temp_reg, const_pool_entry); |
| 3157 | + |
| 3158 | + insn = emit_insn (gen_rtx_SET (SImode, |
| 3159 | + stack_pointer_rtx, |
| 3160 | + gen_rtx_MINUS (SImode, |
| 3161 | + stack_pointer_rtx, |
| 3162 | + temp_reg))); |
| 3163 | + |
| 3164 | + dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, |
| 3165 | + gen_rtx_PLUS (SImode, stack_pointer_rtx, |
| 3166 | + GEN_INT (-get_frame_size ()))); |
| 3167 | + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, |
| 3168 | + dwarf, REG_NOTES (insn)); |
| 3169 | + RTX_FRAME_RELATED_P (insn) = 1; |
| 3170 | + |
| 3171 | + if (!saved_reg_mask) |
| 3172 | + { |
| 3173 | + insn = |
| 3174 | + emit_move_insn (temp_reg, |
| 3175 | + gen_rtx_MEM (SImode, |
| 3176 | + gen_rtx_POST_INC (SImode, |
| 3177 | + gen_rtx_REG |
| 3178 | + (SImode, |
| 3179 | + 13)))); |
| 3180 | + } |
| 3181 | + |
| 3182 | + /* Mark the temp register as dead */ |
| 3183 | + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, temp_reg, |
| 3184 | + REG_NOTES (insn)); |
| 3185 | + |
| 3186 | + |
| 3187 | + } |
| 3188 | + |
| 3189 | + /* Prevent the the stack adjustment to be scheduled after any |
| 3190 | + instructions using the frame pointer. */ |
| 3191 | + emit_insn (gen_blockage ()); |
| 3192 | + } |
| 3193 | + |
| 3194 | + /* Load GOT */ |
| 3195 | + if (flag_pic) |
| 3196 | + { |
| 3197 | + avr32_load_pic_register (); |
| 3198 | + |
| 3199 | + /* gcc does not know that load or call instructions might use the pic |
| 3200 | + register so it might schedule these instructions before the loading |
| 3201 | + of the pic register. To avoid this emit a barrier for now. TODO! |
| 3202 | + Find out a better way to let gcc know which instructions might use |
| 3203 | + the pic register. */ |
| 3204 | + emit_insn (gen_blockage ()); |
| 3205 | + } |
| 3206 | + return; |
| 3207 | +} |
| 3208 | + |
| 3209 | + |
| 3210 | +void |
| 3211 | +avr32_set_return_address (rtx source, rtx scratch) |
| 3212 | +{ |
| 3213 | + rtx addr; |
| 3214 | + unsigned long saved_regs; |
| 3215 | + |
| 3216 | + saved_regs = avr32_compute_save_reg_mask (TRUE); |
| 3217 | + |
| 3218 | + if (!(saved_regs & (1 << ASM_REGNUM (LR_REGNUM)))) |
| 3219 | + emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source); |
| 3220 | + else |
| 3221 | + { |
| 3222 | + if (frame_pointer_needed) |
| 3223 | + addr = gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM); |
| 3224 | + else |
| 3225 | + if (avr32_const_ok_for_constraint_p (get_frame_size (), 'K', "Ks16")) |
| 3226 | + { |
| 3227 | + addr = plus_constant (stack_pointer_rtx, get_frame_size ()); |
| 3228 | + } |
| 3229 | + else |
| 3230 | + { |
| 3231 | + emit_insn (gen_movsi (scratch, GEN_INT (get_frame_size ()))); |
| 3232 | + addr = scratch; |
| 3233 | + } |
| 3234 | + emit_move_insn (gen_rtx_MEM (Pmode, addr), source); |
| 3235 | + } |
| 3236 | +} |
| 3237 | + |
| 3238 | + |
| 3239 | +/* Return the length of INSN. LENGTH is the initial length computed by |
| 3240 | + attributes in the machine-description file. */ |
| 3241 | +int |
| 3242 | +avr32_adjust_insn_length (rtx insn ATTRIBUTE_UNUSED, |
| 3243 | + int length ATTRIBUTE_UNUSED) |
| 3244 | +{ |
| 3245 | + return length; |
| 3246 | +} |
| 3247 | + |
| 3248 | + |
| 3249 | +void |
| 3250 | +avr32_output_return_instruction (int single_ret_inst ATTRIBUTE_UNUSED, |
| 3251 | + int iscond ATTRIBUTE_UNUSED, |
| 3252 | + rtx cond ATTRIBUTE_UNUSED, rtx r12_imm) |
| 3253 | +{ |
| 3254 | + |
| 3255 | + unsigned long saved_reg_mask; |
| 3256 | + int insert_ret = TRUE; |
| 3257 | + int reglist8 = 0; |
| 3258 | + int stack_adjustment = get_frame_size (); |
| 3259 | + unsigned int func_type = avr32_current_func_type (); |
| 3260 | + FILE *f = asm_out_file; |
| 3261 | + |
| 3262 | + /* Naked functions does not have an epilogue */ |
| 3263 | + if (IS_NAKED (func_type)) |
| 3264 | + return; |
| 3265 | + |
| 3266 | + saved_reg_mask = avr32_compute_save_reg_mask (FALSE); |
| 3267 | + |
| 3268 | + /* Reset frame pointer */ |
| 3269 | + if (stack_adjustment > 0) |
| 3270 | + { |
| 3271 | + if (avr32_const_ok_for_constraint_p (stack_adjustment, 'I', "Is21")) |
| 3272 | + { |
| 3273 | + fprintf (f, "\tsub\tsp, %i # Reset Frame Pointer\n", |
| 3274 | + -stack_adjustment); |
| 3275 | + } |
| 3276 | + else |
| 3277 | + { |
| 3278 | + /* TODO! Is it safe to use r8 as scratch?? */ |
| 3279 | + fprintf (f, "\tmov\tr8, lo(%i) # Reset Frame Pointer\n", |
| 3280 | + -stack_adjustment); |
| 3281 | + fprintf (f, "\torh\tr8, hi(%i) # Reset Frame Pointer\n", |
| 3282 | + -stack_adjustment); |
| 3283 | + fprintf (f, "\tadd\tsp, r8 # Reset Frame Pointer\n"); |
| 3284 | + } |
| 3285 | + } |
| 3286 | + |
| 3287 | + if (saved_reg_mask) |
| 3288 | + { |
| 3289 | + /* Must pop used registers */ |
| 3290 | + |
| 3291 | + /* Should we use POPM or LDM? */ |
| 3292 | + int usePOPM = TRUE; |
| 3293 | + if (((saved_reg_mask & (1 << 0)) || |
| 3294 | + (saved_reg_mask & (1 << 1)) || |
| 3295 | + (saved_reg_mask & (1 << 2)) || (saved_reg_mask & (1 << 3)))) |
| 3296 | + { |
| 3297 | + /* One of R0-R3 should at least be popped */ |
| 3298 | + if (((saved_reg_mask & (1 << 0)) && |
| 3299 | + (saved_reg_mask & (1 << 1)) && |
| 3300 | + (saved_reg_mask & (1 << 2)) && (saved_reg_mask & (1 << 3)))) |
| 3301 | + { |
| 3302 | + /* All should be popped */ |
| 3303 | + reglist8 |= 0x01; |
| 3304 | + } |
| 3305 | + else |
| 3306 | + { |
| 3307 | + usePOPM = FALSE; |
| 3308 | + } |
| 3309 | + } |
| 3310 | + |
| 3311 | + if (((saved_reg_mask & (1 << 4)) || |
| 3312 | + (saved_reg_mask & (1 << 5)) || |
| 3313 | + (saved_reg_mask & (1 << 6)) || (saved_reg_mask & (1 << 7)))) |
| 3314 | + { |
| 3315 | + /* One of R0-R3 should at least be popped */ |
| 3316 | + if (((saved_reg_mask & (1 << 4)) && |
| 3317 | + (saved_reg_mask & (1 << 5)) && |
| 3318 | + (saved_reg_mask & (1 << 6)) && (saved_reg_mask & (1 << 7)))) |
| 3319 | + { |
| 3320 | + if (usePOPM) |
| 3321 | + /* All should be popped */ |
| 3322 | + reglist8 |= 0x02; |
| 3323 | + } |
| 3324 | + else |
| 3325 | + { |
| 3326 | + usePOPM = FALSE; |
| 3327 | + } |
| 3328 | + } |
| 3329 | + |
| 3330 | + if (((saved_reg_mask & (1 << 8)) || (saved_reg_mask & (1 << 9)))) |
| 3331 | + { |
| 3332 | + /* One of R8-R9 should at least be pushed */ |
| 3333 | + if (((saved_reg_mask & (1 << 8)) && (saved_reg_mask & (1 << 9)))) |
| 3334 | + { |
| 3335 | + if (usePOPM) |
| 3336 | + /* All should be pushed */ |
| 3337 | + reglist8 |= 0x04; |
| 3338 | + } |
| 3339 | + else |
| 3340 | + { |
| 3341 | + usePOPM = FALSE; |
| 3342 | + } |
| 3343 | + } |
| 3344 | + |
| 3345 | + if (saved_reg_mask & (1 << 10)) |
| 3346 | + reglist8 |= 0x08; |
| 3347 | + |
| 3348 | + if (saved_reg_mask & (1 << 11)) |
| 3349 | + reglist8 |= 0x10; |
| 3350 | + |
| 3351 | + if (saved_reg_mask & (1 << 12)) |
| 3352 | + reglist8 |= 0x20; |
| 3353 | + |
| 3354 | + if (saved_reg_mask & (1 << ASM_REGNUM (LR_REGNUM))) |
| 3355 | + /* Pop LR */ |
| 3356 | + reglist8 |= 0x40; |
| 3357 | + |
| 3358 | + if ((saved_reg_mask & (1 << ASM_REGNUM (PC_REGNUM))) |
| 3359 | + && !IS_FLASHVAULT_IMPL (func_type)) |
| 3360 | + /* Pop LR into PC. */ |
| 3361 | + reglist8 |= 0x80; |
| 3362 | + |
| 3363 | + if (usePOPM) |
| 3364 | + { |
| 3365 | + char reglist[64]; /* 64 bytes should be enough... */ |
| 3366 | + avr32_make_reglist8 (reglist8, (char *) reglist); |
| 3367 | + |
| 3368 | + if (reglist8 & 0x80) |
| 3369 | + /* This instruction is also a return */ |
| 3370 | + insert_ret = FALSE; |
| 3371 | + |
| 3372 | + if (r12_imm && !insert_ret) |
| 3373 | + fprintf (f, "\tpopm\t%s, r12=%li\n", reglist, INTVAL (r12_imm)); |
| 3374 | + else |
| 3375 | + fprintf (f, "\tpopm\t%s\n", reglist); |
| 3376 | + |
| 3377 | + } |
| 3378 | + else |
| 3379 | + { |
| 3380 | + char reglist[64]; /* 64 bytes should be enough... */ |
| 3381 | + avr32_make_reglist16 (saved_reg_mask, (char *) reglist); |
| 3382 | + if (saved_reg_mask & (1 << ASM_REGNUM (PC_REGNUM))) |
| 3383 | + /* This instruction is also a return */ |
| 3384 | + insert_ret = FALSE; |
| 3385 | + |
| 3386 | + if (r12_imm && !insert_ret) |
| 3387 | + fprintf (f, "\tldm\tsp++, %s, r12=%li\n", reglist, |
| 3388 | + INTVAL (r12_imm)); |
| 3389 | + else |
| 3390 | + fprintf (f, "\tldm\tsp++, %s\n", reglist); |
| 3391 | + |
| 3392 | + } |
| 3393 | + |
| 3394 | + } |
| 3395 | + |
| 3396 | + /* Stack adjustment for exception handler. */ |
| 3397 | + if (crtl->calls_eh_return) |
| 3398 | + fprintf (f, "\tadd\tsp, r%d\n", ASM_REGNUM (EH_RETURN_STACKADJ_REGNO)); |
| 3399 | + |
| 3400 | + |
| 3401 | + if (IS_INTERRUPT (func_type)) |
| 3402 | + { |
| 3403 | + fprintf (f, "\trete\n"); |
| 3404 | + } |
| 3405 | + else if (IS_FLASHVAULT (func_type)) |
| 3406 | + { |
| 3407 | + /* Normal return from Secure System call, increment SS_RAR before |
| 3408 | + returning. Use R8 as scratch. */ |
| 3409 | + fprintf (f, |
| 3410 | + "\t# Normal return from sscall.\n" |
| 3411 | + "\t# Increment SS_RAR before returning.\n" |
| 3412 | + "\t# Use R8 as scratch.\n" |
| 3413 | + "\tmfsr\tr8, 440\n" |
| 3414 | + "\tsub\tr8, -2\n" |
| 3415 | + "\tmtsr\t440, r8\n" |
| 3416 | + "\tretss\n"); |
| 3417 | + } |
| 3418 | + else if (insert_ret) |
| 3419 | + { |
| 3420 | + if (r12_imm) |
| 3421 | + fprintf (f, "\tretal\t%li\n", INTVAL (r12_imm)); |
| 3422 | + else |
| 3423 | + fprintf (f, "\tretal\tr12\n"); |
| 3424 | + } |
| 3425 | +} |
| 3426 | + |
| 3427 | +void |
| 3428 | +avr32_make_reglist16 (int reglist16_vect, char *reglist16_string) |
| 3429 | +{ |
| 3430 | + int i; |
| 3431 | + bool first_reg = true; |
| 3432 | + /* Make sure reglist16_string is empty. */ |
| 3433 | + reglist16_string[0] = '\0'; |
| 3434 | + |
| 3435 | + for (i = 0; i < 16; ++i) |
| 3436 | + { |
| 3437 | + if (reglist16_vect & (1 << i)) |
| 3438 | + { |
| 3439 | + first_reg == true ? first_reg = false : strcat(reglist16_string,", "); |
| 3440 | + strcat (reglist16_string, reg_names[INTERNAL_REGNUM (i)]); |
| 3441 | + } |
| 3442 | + } |
| 3443 | +} |
| 3444 | + |
| 3445 | +int |
| 3446 | +avr32_convert_to_reglist16 (int reglist8_vect) |
| 3447 | +{ |
| 3448 | + int reglist16_vect = 0; |
| 3449 | + if (reglist8_vect & 0x1) |
| 3450 | + reglist16_vect |= 0xF; |
| 3451 | + if (reglist8_vect & 0x2) |
| 3452 | + reglist16_vect |= 0xF0; |
| 3453 | + if (reglist8_vect & 0x4) |
| 3454 | + reglist16_vect |= 0x300; |
| 3455 | + if (reglist8_vect & 0x8) |
| 3456 | + reglist16_vect |= 0x400; |
| 3457 | + if (reglist8_vect & 0x10) |
| 3458 | + reglist16_vect |= 0x800; |
| 3459 | + if (reglist8_vect & 0x20) |
| 3460 | + reglist16_vect |= 0x1000; |
| 3461 | + if (reglist8_vect & 0x40) |
| 3462 | + reglist16_vect |= 0x4000; |
| 3463 | + if (reglist8_vect & 0x80) |
| 3464 | + reglist16_vect |= 0x8000; |
| 3465 | + |
| 3466 | + return reglist16_vect; |
| 3467 | +} |
| 3468 | + |
| 3469 | +void |
| 3470 | +avr32_make_reglist8 (int reglist8_vect, char *reglist8_string) |
| 3471 | +{ |
| 3472 | + /* Make sure reglist8_string is empty. */ |
| 3473 | + reglist8_string[0] = '\0'; |
| 3474 | + |
| 3475 | + if (reglist8_vect & 0x1) |
| 3476 | + strcpy (reglist8_string, "r0-r3"); |
| 3477 | + if (reglist8_vect & 0x2) |
| 3478 | + strlen (reglist8_string) ? strcat (reglist8_string, ", r4-r7") : |
| 3479 | + strcpy (reglist8_string, "r4-r7"); |
| 3480 | + if (reglist8_vect & 0x4) |
| 3481 | + strlen (reglist8_string) ? strcat (reglist8_string, ", r8-r9") : |
| 3482 | + strcpy (reglist8_string, "r8-r9"); |
| 3483 | + if (reglist8_vect & 0x8) |
| 3484 | + strlen (reglist8_string) ? strcat (reglist8_string, ", r10") : |
| 3485 | + strcpy (reglist8_string, "r10"); |
| 3486 | + if (reglist8_vect & 0x10) |
| 3487 | + strlen (reglist8_string) ? strcat (reglist8_string, ", r11") : |
| 3488 | + strcpy (reglist8_string, "r11"); |
| 3489 | + if (reglist8_vect & 0x20) |
| 3490 | + strlen (reglist8_string) ? strcat (reglist8_string, ", r12") : |
| 3491 | + strcpy (reglist8_string, "r12"); |
| 3492 | + if (reglist8_vect & 0x40) |
| 3493 | + strlen (reglist8_string) ? strcat (reglist8_string, ", lr") : |
| 3494 | + strcpy (reglist8_string, "lr"); |
| 3495 | + if (reglist8_vect & 0x80) |
| 3496 | + strlen (reglist8_string) ? strcat (reglist8_string, ", pc") : |
| 3497 | + strcpy (reglist8_string, "pc"); |
| 3498 | +} |
| 3499 | + |
| 3500 | + |
| 3501 | +int |
| 3502 | +avr32_eh_return_data_regno (int n) |
| 3503 | +{ |
| 3504 | + if (n >= 0 && n <= 3) |
| 3505 | + return 8 + n; |
| 3506 | + else |
| 3507 | + return INVALID_REGNUM; |
| 3508 | +} |
| 3509 | + |
| 3510 | + |
| 3511 | +/* Compute the distance from register FROM to register TO. |
| 3512 | + These can be the arg pointer, the frame pointer or |
| 3513 | + the stack pointer. |
| 3514 | + Typical stack layout looks like this: |
| 3515 | + |
| 3516 | + old stack pointer -> | | |
| 3517 | + ---- |
| 3518 | + | | \ |
| 3519 | + | | saved arguments for |
| 3520 | + | | vararg functions |
| 3521 | + arg_pointer -> | | / |
| 3522 | + -- |
| 3523 | + | | \ |
| 3524 | + | | call saved |
| 3525 | + | | registers |
| 3526 | + | | / |
| 3527 | + frame ptr -> -- |
| 3528 | + | | \ |
| 3529 | + | | local |
| 3530 | + | | variables |
| 3531 | + stack ptr --> | | / |
| 3532 | + -- |
| 3533 | + | | \ |
| 3534 | + | | outgoing |
| 3535 | + | | arguments |
| 3536 | + | | / |
| 3537 | + -- |
| 3538 | + |
| 3539 | + For a given funciton some or all of these stack compomnents |
| 3540 | + may not be needed, giving rise to the possibility of |
| 3541 | + eliminating some of the registers. |
| 3542 | + |
| 3543 | + The values returned by this function must reflect the behaviour |
| 3544 | + of avr32_expand_prologue() and avr32_compute_save_reg_mask(). |
| 3545 | + |
| 3546 | + The sign of the number returned reflects the direction of stack |
| 3547 | + growth, so the values are positive for all eliminations except |
| 3548 | + from the soft frame pointer to the hard frame pointer. */ |
| 3549 | +int |
| 3550 | +avr32_initial_elimination_offset (int from, int to) |
| 3551 | +{ |
| 3552 | + int i; |
| 3553 | + int call_saved_regs = 0; |
| 3554 | + unsigned long saved_reg_mask; |
| 3555 | + unsigned int local_vars = get_frame_size (); |
| 3556 | + |
| 3557 | + saved_reg_mask = avr32_compute_save_reg_mask (TRUE); |
| 3558 | + |
| 3559 | + for (i = 0; i < 16; ++i) |
| 3560 | + { |
| 3561 | + if (saved_reg_mask & (1 << i)) |
| 3562 | + call_saved_regs += 4; |
| 3563 | + } |
| 3564 | + |
| 3565 | + switch (from) |
| 3566 | + { |
| 3567 | + case ARG_POINTER_REGNUM: |
| 3568 | + switch (to) |
| 3569 | + { |
| 3570 | + case STACK_POINTER_REGNUM: |
| 3571 | + return call_saved_regs + local_vars; |
| 3572 | + case FRAME_POINTER_REGNUM: |
| 3573 | + return call_saved_regs; |
| 3574 | + default: |
| 3575 | + abort (); |
| 3576 | + } |
| 3577 | + case FRAME_POINTER_REGNUM: |
| 3578 | + switch (to) |
| 3579 | + { |
| 3580 | + case STACK_POINTER_REGNUM: |
| 3581 | + return local_vars; |
| 3582 | + default: |
| 3583 | + abort (); |
| 3584 | + } |
| 3585 | + default: |
| 3586 | + abort (); |
| 3587 | + } |
| 3588 | +} |
| 3589 | + |
| 3590 | + |
| 3591 | +/* |
| 3592 | + Returns a rtx used when passing the next argument to a function. |
| 3593 | + avr32_init_cumulative_args() and avr32_function_arg_advance() sets which |
| 3594 | + register to use. |
| 3595 | +*/ |
| 3596 | +rtx |
| 3597 | +avr32_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, |
| 3598 | + tree type, int named) |
| 3599 | +{ |
| 3600 | + int index = -1; |
| 3601 | + //unsigned long func_type = avr32_current_func_type (); |
| 3602 | + //int last_reg_index = (IS_FLASHVAULT(func_type) || IS_FLASHVAULT_IMPL(func_type) || cum->flashvault_func ? LAST_CUM_REG_INDEX - 1 : LAST_CUM_REG_INDEX); |
| 3603 | + int last_reg_index = (cum->flashvault_func ? LAST_CUM_REG_INDEX - 1 : LAST_CUM_REG_INDEX); |
| 3604 | + |
| 3605 | + HOST_WIDE_INT arg_size, arg_rsize; |
| 3606 | + if (type) |
| 3607 | + { |
| 3608 | + arg_size = int_size_in_bytes (type); |
| 3609 | + } |
| 3610 | + else |
| 3611 | + { |
| 3612 | + arg_size = GET_MODE_SIZE (mode); |
| 3613 | + } |
| 3614 | + arg_rsize = PUSH_ROUNDING (arg_size); |
| 3615 | + |
| 3616 | + /* |
| 3617 | + The last time this macro is called, it is called with mode == VOIDmode, |
| 3618 | + and its result is passed to the call or call_value pattern as operands 2 |
| 3619 | + and 3 respectively. */ |
| 3620 | + if (mode == VOIDmode) |
| 3621 | + { |
| 3622 | + return gen_rtx_CONST_INT (SImode, 22); /* ToDo: fixme. */ |
| 3623 | + } |
| 3624 | + |
| 3625 | + if ((*targetm.calls.must_pass_in_stack) (mode, type) || !named) |
| 3626 | + { |
| 3627 | + return NULL_RTX; |
| 3628 | + } |
| 3629 | + |
| 3630 | + if (arg_rsize == 8) |
| 3631 | + { |
| 3632 | + /* use r11:r10 or r9:r8. */ |
| 3633 | + if (!(GET_USED_INDEX (cum, 1) || GET_USED_INDEX (cum, 2))) |
| 3634 | + index = 1; |
| 3635 | + else if ((last_reg_index == 4) && |
| 3636 | + !(GET_USED_INDEX (cum, 3) || GET_USED_INDEX (cum, 4))) |
| 3637 | + index = 3; |
| 3638 | + else |
| 3639 | + index = -1; |
| 3640 | + } |
| 3641 | + else if (arg_rsize == 4) |
| 3642 | + { /* Use first available register */ |
| 3643 | + index = 0; |
| 3644 | + while (index <= last_reg_index && GET_USED_INDEX (cum, index)) |
| 3645 | + index++; |
| 3646 | + if (index > last_reg_index) |
| 3647 | + index = -1; |
| 3648 | + } |
| 3649 | + |
| 3650 | + SET_REG_INDEX (cum, index); |
| 3651 | + |
| 3652 | + if (GET_REG_INDEX (cum) >= 0) |
| 3653 | + return gen_rtx_REG (mode, avr32_function_arg_reglist[GET_REG_INDEX (cum)]); |
| 3654 | + |
| 3655 | + return NULL_RTX; |
| 3656 | +} |
| 3657 | + |
| 3658 | + |
| 3659 | +/* Set the register used for passing the first argument to a function. */ |
| 3660 | +void |
| 3661 | +avr32_init_cumulative_args (CUMULATIVE_ARGS * cum, |
| 3662 | + tree fntype ATTRIBUTE_UNUSED, |
| 3663 | + rtx libname ATTRIBUTE_UNUSED, |
| 3664 | + tree fndecl) |
| 3665 | +{ |
| 3666 | + /* Set all registers as unused. */ |
| 3667 | + SET_INDEXES_UNUSED (cum); |
| 3668 | + |
| 3669 | + /* Reset uses_anonymous_args */ |
| 3670 | + cum->uses_anonymous_args = 0; |
| 3671 | + |
| 3672 | + /* Reset size of stack pushed arguments */ |
| 3673 | + cum->stack_pushed_args_size = 0; |
| 3674 | + |
| 3675 | + cum->flashvault_func = (fndecl && (has_attribute_p (fndecl,"flashvault") || has_attribute_p (fndecl,"flashvault_impl"))); |
| 3676 | +} |
| 3677 | + |
| 3678 | + |
| 3679 | +/* |
| 3680 | + Set register used for passing the next argument to a function. Only the |
| 3681 | + Scratch Registers are used. |
| 3682 | + |
| 3683 | + number name |
| 3684 | + 15 r15 PC |
| 3685 | + 14 r14 LR |
| 3686 | + 13 r13 _SP_________ |
| 3687 | + FIRST_CUM_REG 12 r12 _||_ |
| 3688 | + 10 r11 || |
| 3689 | + 11 r10 _||_ Scratch Registers |
| 3690 | + 8 r9 || |
| 3691 | + LAST_SCRATCH_REG 9 r8 _\/_________ |
| 3692 | + 6 r7 /\ |
| 3693 | + 7 r6 || |
| 3694 | + 4 r5 || |
| 3695 | + 5 r4 || |
| 3696 | + 2 r3 || |
| 3697 | + 3 r2 || |
| 3698 | + 0 r1 || |
| 3699 | + 1 r0 _||_________ |
| 3700 | + |
| 3701 | +*/ |
| 3702 | +void |
| 3703 | +avr32_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode, |
| 3704 | + tree type, int named ATTRIBUTE_UNUSED) |
| 3705 | +{ |
| 3706 | + HOST_WIDE_INT arg_size, arg_rsize; |
| 3707 | + |
| 3708 | + if (type) |
| 3709 | + { |
| 3710 | + arg_size = int_size_in_bytes (type); |
| 3711 | + } |
| 3712 | + else |
| 3713 | + { |
| 3714 | + arg_size = GET_MODE_SIZE (mode); |
| 3715 | + } |
| 3716 | + arg_rsize = PUSH_ROUNDING (arg_size); |
| 3717 | + |
| 3718 | + /* If the argument had to be passed in stack, no register is used. */ |
| 3719 | + if ((*targetm.calls.must_pass_in_stack) (mode, type)) |
| 3720 | + { |
| 3721 | + cum->stack_pushed_args_size += PUSH_ROUNDING (int_size_in_bytes (type)); |
| 3722 | + return; |
| 3723 | + } |
| 3724 | + |
| 3725 | + /* Mark the used registers as "used". */ |
| 3726 | + if (GET_REG_INDEX (cum) >= 0) |
| 3727 | + { |
| 3728 | + SET_USED_INDEX (cum, GET_REG_INDEX (cum)); |
| 3729 | + if (arg_rsize == 8) |
| 3730 | + { |
| 3731 | + SET_USED_INDEX (cum, (GET_REG_INDEX (cum) + 1)); |
| 3732 | + } |
| 3733 | + } |
| 3734 | + else |
| 3735 | + { |
| 3736 | + /* Had to use stack */ |
| 3737 | + cum->stack_pushed_args_size += arg_rsize; |
| 3738 | + } |
| 3739 | +} |
| 3740 | + |
| 3741 | + |
| 3742 | +/* |
| 3743 | + Defines witch direction to go to find the next register to use if the |
| 3744 | + argument is larger then one register or for arguments shorter than an |
| 3745 | + int which is not promoted, such as the last part of structures with |
| 3746 | + size not a multiple of 4. */ |
| 3747 | +enum direction |
| 3748 | +avr32_function_arg_padding (enum machine_mode mode ATTRIBUTE_UNUSED, |
| 3749 | + tree type) |
| 3750 | +{ |
| 3751 | + /* Pad upward for all aggregates except byte and halfword sized aggregates |
| 3752 | + which can be passed in registers. */ |
| 3753 | + if (type |
| 3754 | + && AGGREGATE_TYPE_P (type) |
| 3755 | + && (int_size_in_bytes (type) != 1) |
| 3756 | + && !((int_size_in_bytes (type) == 2) |
| 3757 | + && TYPE_ALIGN_UNIT (type) >= 2) |
| 3758 | + && (int_size_in_bytes (type) & 0x3)) |
| 3759 | + { |
| 3760 | + return upward; |
| 3761 | + } |
| 3762 | + |
| 3763 | + return downward; |
| 3764 | +} |
| 3765 | + |
| 3766 | + |
| 3767 | +/* Return a rtx used for the return value from a function call. */ |
| 3768 | +rtx |
| 3769 | +avr32_function_value (tree type, tree func, bool outgoing ATTRIBUTE_UNUSED) |
| 3770 | +{ |
| 3771 | + if (avr32_return_in_memory (type, func)) |
| 3772 | + return NULL_RTX; |
| 3773 | + |
| 3774 | + if (int_size_in_bytes (type) <= 4) |
| 3775 | + { |
| 3776 | + enum machine_mode mode = TYPE_MODE (type); |
| 3777 | + int unsignedp = 0; |
| 3778 | + PROMOTE_FUNCTION_MODE (mode, unsignedp, type); |
| 3779 | + return gen_rtx_REG (mode, RET_REGISTER); |
| 3780 | + } |
| 3781 | + else if (int_size_in_bytes (type) <= 8) |
| 3782 | + return gen_rtx_REG (TYPE_MODE (type), INTERNAL_REGNUM (11)); |
| 3783 | + |
| 3784 | + return NULL_RTX; |
| 3785 | +} |
| 3786 | + |
| 3787 | + |
| 3788 | +/* Return a rtx used for the return value from a library function call. */ |
| 3789 | +rtx |
| 3790 | +avr32_libcall_value (enum machine_mode mode) |
| 3791 | +{ |
| 3792 | + |
| 3793 | + if (GET_MODE_SIZE (mode) <= 4) |
| 3794 | + return gen_rtx_REG (mode, RET_REGISTER); |
| 3795 | + else if (GET_MODE_SIZE (mode) <= 8) |
| 3796 | + return gen_rtx_REG (mode, INTERNAL_REGNUM (11)); |
| 3797 | + else |
| 3798 | + return NULL_RTX; |
| 3799 | +} |
| 3800 | + |
| 3801 | + |
| 3802 | +/* Return TRUE if X references a SYMBOL_REF. */ |
| 3803 | +int |
| 3804 | +symbol_mentioned_p (rtx x) |
| 3805 | +{ |
| 3806 | + const char *fmt; |
| 3807 | + int i; |
| 3808 | + |
| 3809 | + if (GET_CODE (x) == SYMBOL_REF) |
| 3810 | + return 1; |
| 3811 | + |
| 3812 | + fmt = GET_RTX_FORMAT (GET_CODE (x)); |
| 3813 | + |
| 3814 | + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
| 3815 | + { |
| 3816 | + if (fmt[i] == 'E') |
| 3817 | + { |
| 3818 | + int j; |
| 3819 | + |
| 3820 | + for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
| 3821 | + if (symbol_mentioned_p (XVECEXP (x, i, j))) |
| 3822 | + return 1; |
| 3823 | + } |
| 3824 | + else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) |
| 3825 | + return 1; |
| 3826 | + } |
| 3827 | + |
| 3828 | + return 0; |
| 3829 | +} |
| 3830 | + |
| 3831 | + |
| 3832 | +/* Return TRUE if X references a LABEL_REF. */ |
| 3833 | +int |
| 3834 | +label_mentioned_p (rtx x) |
| 3835 | +{ |
| 3836 | + const char *fmt; |
| 3837 | + int i; |
| 3838 | + |
| 3839 | + if (GET_CODE (x) == LABEL_REF) |
| 3840 | + return 1; |
| 3841 | + |
| 3842 | + fmt = GET_RTX_FORMAT (GET_CODE (x)); |
| 3843 | + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
| 3844 | + { |
| 3845 | + if (fmt[i] == 'E') |
| 3846 | + { |
| 3847 | + int j; |
| 3848 | + |
| 3849 | + for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
| 3850 | + if (label_mentioned_p (XVECEXP (x, i, j))) |
| 3851 | + return 1; |
| 3852 | + } |
| 3853 | + else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) |
| 3854 | + return 1; |
| 3855 | + } |
| 3856 | + |
| 3857 | + return 0; |
| 3858 | +} |
| 3859 | + |
| 3860 | + |
| 3861 | +/* Return TRUE if X contains a MEM expression. */ |
| 3862 | +int |
| 3863 | +mem_mentioned_p (rtx x) |
| 3864 | +{ |
| 3865 | + const char *fmt; |
| 3866 | + int i; |
| 3867 | + |
| 3868 | + if (MEM_P (x)) |
| 3869 | + return 1; |
| 3870 | + |
| 3871 | + fmt = GET_RTX_FORMAT (GET_CODE (x)); |
| 3872 | + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
| 3873 | + { |
| 3874 | + if (fmt[i] == 'E') |
| 3875 | + { |
| 3876 | + int j; |
| 3877 | + |
| 3878 | + for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
| 3879 | + if (mem_mentioned_p (XVECEXP (x, i, j))) |
| 3880 | + return 1; |
| 3881 | + } |
| 3882 | + else if (fmt[i] == 'e' && mem_mentioned_p (XEXP (x, i))) |
| 3883 | + return 1; |
| 3884 | + } |
| 3885 | + |
| 3886 | + return 0; |
| 3887 | +} |
| 3888 | + |
| 3889 | + |
| 3890 | +int |
| 3891 | +avr32_legitimate_pic_operand_p (rtx x) |
| 3892 | +{ |
| 3893 | + |
| 3894 | + /* We can't have const, this must be broken down to a symbol. */ |
| 3895 | + if (GET_CODE (x) == CONST) |
| 3896 | + return FALSE; |
| 3897 | + |
| 3898 | + /* Can't access symbols or labels via the constant pool either */ |
| 3899 | + if ((GET_CODE (x) == SYMBOL_REF |
| 3900 | + && CONSTANT_POOL_ADDRESS_P (x) |
| 3901 | + && (symbol_mentioned_p (get_pool_constant (x)) |
| 3902 | + || label_mentioned_p (get_pool_constant (x))))) |
| 3903 | + return FALSE; |
| 3904 | + |
| 3905 | + return TRUE; |
| 3906 | +} |
| 3907 | + |
| 3908 | + |
| 3909 | +rtx |
| 3910 | +legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, |
| 3911 | + rtx reg) |
| 3912 | +{ |
| 3913 | + |
| 3914 | + if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF) |
| 3915 | + { |
| 3916 | + int subregs = 0; |
| 3917 | + |
| 3918 | + if (reg == 0) |
| 3919 | + { |
| 3920 | + if (!can_create_pseudo_p ()) |
| 3921 | + abort (); |
| 3922 | + else |
| 3923 | + reg = gen_reg_rtx (Pmode); |
| 3924 | + |
| 3925 | + subregs = 1; |
| 3926 | + } |
| 3927 | + |
| 3928 | + emit_move_insn (reg, orig); |
| 3929 | + |
| 3930 | + /* Only set current function as using pic offset table if flag_pic is |
| 3931 | + set. This is because this function is also used if |
| 3932 | + TARGET_HAS_ASM_ADDR_PSEUDOS is set. */ |
| 3933 | + if (flag_pic) |
| 3934 | + crtl->uses_pic_offset_table = 1; |
| 3935 | + |
| 3936 | + /* Put a REG_EQUAL note on this insn, so that it can be optimized by |
| 3937 | + loop. */ |
| 3938 | + return reg; |
| 3939 | + } |
| 3940 | + else if (GET_CODE (orig) == CONST) |
| 3941 | + { |
| 3942 | + rtx base, offset; |
| 3943 | + |
| 3944 | + if (flag_pic |
| 3945 | + && GET_CODE (XEXP (orig, 0)) == PLUS |
| 3946 | + && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) |
| 3947 | + return orig; |
| 3948 | + |
| 3949 | + if (reg == 0) |
| 3950 | + { |
| 3951 | + if (!can_create_pseudo_p ()) |
| 3952 | + abort (); |
| 3953 | + else |
| 3954 | + reg = gen_reg_rtx (Pmode); |
| 3955 | + } |
| 3956 | + |
| 3957 | + if (GET_CODE (XEXP (orig, 0)) == PLUS) |
| 3958 | + { |
| 3959 | + base = |
| 3960 | + legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); |
| 3961 | + offset = |
| 3962 | + legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, |
| 3963 | + base == reg ? 0 : reg); |
| 3964 | + } |
| 3965 | + else |
| 3966 | + abort (); |
| 3967 | + |
| 3968 | + if (GET_CODE (offset) == CONST_INT) |
| 3969 | + { |
| 3970 | + /* The base register doesn't really matter, we only want to test |
| 3971 | + the index for the appropriate mode. */ |
| 3972 | + if (!avr32_const_ok_for_constraint_p (INTVAL (offset), 'I', "Is21")) |
| 3973 | + { |
| 3974 | + if (can_create_pseudo_p ()) |
| 3975 | + offset = force_reg (Pmode, offset); |
| 3976 | + else |
| 3977 | + abort (); |
| 3978 | + } |
| 3979 | + |
| 3980 | + if (GET_CODE (offset) == CONST_INT) |
| 3981 | + return plus_constant (base, INTVAL (offset)); |
| 3982 | + } |
| 3983 | + |
| 3984 | + return gen_rtx_PLUS (Pmode, base, offset); |
| 3985 | + } |
| 3986 | + |
| 3987 | + return orig; |
| 3988 | +} |
| 3989 | + |
| 3990 | + |
| 3991 | +/* Generate code to load the PIC register. */ |
| 3992 | +void |
| 3993 | +avr32_load_pic_register (void) |
| 3994 | +{ |
| 3995 | + rtx l1, pic_tmp; |
| 3996 | + rtx global_offset_table; |
| 3997 | + |
| 3998 | + if ((crtl->uses_pic_offset_table == 0) || TARGET_NO_INIT_GOT) |
| 3999 | + return; |
| 4000 | + |
| 4001 | + if (!flag_pic) |
| 4002 | + abort (); |
| 4003 | + |
| 4004 | + l1 = gen_label_rtx (); |
| 4005 | + |
| 4006 | + global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); |
| 4007 | + pic_tmp = |
| 4008 | + gen_rtx_CONST (Pmode, |
| 4009 | + gen_rtx_MINUS (SImode, gen_rtx_LABEL_REF (Pmode, l1), |
| 4010 | + global_offset_table)); |
| 4011 | + emit_insn (gen_pic_load_addr |
| 4012 | + (pic_offset_table_rtx, force_const_mem (SImode, pic_tmp))); |
| 4013 | + emit_insn (gen_pic_compute_got_from_pc (pic_offset_table_rtx, l1)); |
| 4014 | + |
| 4015 | + /* Need to emit this whether or not we obey regdecls, since setjmp/longjmp |
| 4016 | + can cause life info to screw up. */ |
| 4017 | + emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); |
| 4018 | +} |
| 4019 | + |
| 4020 | + |
| 4021 | +/* This hook should return true if values of type type are returned at the most |
| 4022 | + significant end of a register (in other words, if they are padded at the |
| 4023 | + least significant end). You can assume that type is returned in a register; |
| 4024 | + the caller is required to check this. Note that the register provided by |
| 4025 | + FUNCTION_VALUE must be able to hold the complete return value. For example, |
| 4026 | + if a 1-, 2- or 3-byte structure is returned at the most significant end of a |
| 4027 | + 4-byte register, FUNCTION_VALUE should provide an SImode rtx. */ |
| 4028 | +bool |
| 4029 | +avr32_return_in_msb (tree type ATTRIBUTE_UNUSED) |
| 4030 | +{ |
| 4031 | + /* if ( AGGREGATE_TYPE_P (type) ) if ((int_size_in_bytes(type) == 1) || |
| 4032 | + ((int_size_in_bytes(type) == 2) && TYPE_ALIGN_UNIT(type) >= 2)) return |
| 4033 | + false; else return true; */ |
| 4034 | + |
| 4035 | + return false; |
| 4036 | +} |
| 4037 | + |
| 4038 | + |
| 4039 | +/* |
| 4040 | + Returns one if a certain function value is going to be returned in memory |
| 4041 | + and zero if it is going to be returned in a register. |
| 4042 | + |
| 4043 | + BLKmode and all other modes that is larger than 64 bits are returned in |
| 4044 | + memory. |
| 4045 | +*/ |
| 4046 | +bool |
| 4047 | +avr32_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) |
| 4048 | +{ |
| 4049 | + if (TYPE_MODE (type) == VOIDmode) |
| 4050 | + return false; |
| 4051 | + |
| 4052 | + if (int_size_in_bytes (type) > (2 * UNITS_PER_WORD) |
| 4053 | + || int_size_in_bytes (type) == -1) |
| 4054 | + { |
| 4055 | + return true; |
| 4056 | + } |
| 4057 | + |
| 4058 | + /* If we have an aggregate then use the same mechanism as when checking if |
| 4059 | + it should be passed on the stack. */ |
| 4060 | + if (type |
| 4061 | + && AGGREGATE_TYPE_P (type) |
| 4062 | + && (*targetm.calls.must_pass_in_stack) (TYPE_MODE (type), type)) |
| 4063 | + return true; |
| 4064 | + |
| 4065 | + return false; |
| 4066 | +} |
| 4067 | + |
| 4068 | + |
| 4069 | +/* Output the constant part of the trampoline. |
| 4070 | + lddpc r0, pc[0x8:e] ; load static chain register |
| 4071 | + lddpc pc, pc[0x8:e] ; jump to subrutine |
| 4072 | + .long 0 ; Address to static chain, |
| 4073 | + ; filled in by avr32_initialize_trampoline() |
| 4074 | + .long 0 ; Address to subrutine, |
| 4075 | + ; filled in by avr32_initialize_trampoline() |
| 4076 | +*/ |
| 4077 | +void |
| 4078 | +avr32_trampoline_template (FILE * file) |
| 4079 | +{ |
| 4080 | + fprintf (file, "\tlddpc r0, pc[8]\n"); |
| 4081 | + fprintf (file, "\tlddpc pc, pc[8]\n"); |
| 4082 | + /* make room for the address of the static chain. */ |
| 4083 | + fprintf (file, "\t.long\t0\n"); |
| 4084 | + /* make room for the address to the subrutine. */ |
| 4085 | + fprintf (file, "\t.long\t0\n"); |
| 4086 | +} |
| 4087 | + |
| 4088 | + |
| 4089 | +/* Initialize the variable parts of a trampoline. */ |
| 4090 | +void |
| 4091 | +avr32_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain) |
| 4092 | +{ |
| 4093 | + /* Store the address to the static chain. */ |
| 4094 | + emit_move_insn (gen_rtx_MEM |
| 4095 | + (SImode, plus_constant (addr, TRAMPOLINE_SIZE - 4)), |
| 4096 | + static_chain); |
| 4097 | + |
| 4098 | + /* Store the address to the function. */ |
| 4099 | + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (addr, TRAMPOLINE_SIZE)), |
| 4100 | + fnaddr); |
| 4101 | + |
| 4102 | + emit_insn (gen_cache (gen_rtx_REG (SImode, 13), |
| 4103 | + gen_rtx_CONST_INT (SImode, |
| 4104 | + AVR32_CACHE_INVALIDATE_ICACHE))); |
| 4105 | +} |
| 4106 | + |
| 4107 | + |
| 4108 | +/* Return nonzero if X is valid as an addressing register. */ |
| 4109 | +int |
| 4110 | +avr32_address_register_rtx_p (rtx x, int strict_p) |
| 4111 | +{ |
| 4112 | + int regno; |
| 4113 | + |
| 4114 | + if (!register_operand(x, GET_MODE(x))) |
| 4115 | + return 0; |
| 4116 | + |
| 4117 | + /* If strict we require the register to be a hard register. */ |
| 4118 | + if (strict_p |
| 4119 | + && !REG_P(x)) |
| 4120 | + return 0; |
| 4121 | + |
| 4122 | + regno = REGNO (x); |
| 4123 | + |
| 4124 | + if (strict_p) |
| 4125 | + return REGNO_OK_FOR_BASE_P (regno); |
| 4126 | + |
| 4127 | + return (regno <= LAST_REGNUM || regno >= FIRST_PSEUDO_REGISTER); |
| 4128 | +} |
| 4129 | + |
| 4130 | + |
| 4131 | +/* Return nonzero if INDEX is valid for an address index operand. */ |
| 4132 | +int |
| 4133 | +avr32_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p) |
| 4134 | +{ |
| 4135 | + enum rtx_code code = GET_CODE (index); |
| 4136 | + |
| 4137 | + if (GET_MODE_SIZE (mode) > 8) |
| 4138 | + return 0; |
| 4139 | + |
| 4140 | + /* Standard coprocessor addressing modes. */ |
| 4141 | + if (code == CONST_INT) |
| 4142 | + { |
| 4143 | + return CONST_OK_FOR_CONSTRAINT_P (INTVAL (index), 'K', "Ks16"); |
| 4144 | + } |
| 4145 | + |
| 4146 | + if (avr32_address_register_rtx_p (index, strict_p)) |
| 4147 | + return 1; |
| 4148 | + |
| 4149 | + if (code == MULT) |
| 4150 | + { |
| 4151 | + rtx xiop0 = XEXP (index, 0); |
| 4152 | + rtx xiop1 = XEXP (index, 1); |
| 4153 | + return ((avr32_address_register_rtx_p (xiop0, strict_p) |
| 4154 | + && power_of_two_operand (xiop1, SImode) |
| 4155 | + && (INTVAL (xiop1) <= 8)) |
| 4156 | + || (avr32_address_register_rtx_p (xiop1, strict_p) |
| 4157 | + && power_of_two_operand (xiop0, SImode) |
| 4158 | + && (INTVAL (xiop0) <= 8))); |
| 4159 | + } |
| 4160 | + else if (code == ASHIFT) |
| 4161 | + { |
| 4162 | + rtx op = XEXP (index, 1); |
| 4163 | + |
| 4164 | + return (avr32_address_register_rtx_p (XEXP (index, 0), strict_p) |
| 4165 | + && GET_CODE (op) == CONST_INT |
| 4166 | + && INTVAL (op) > 0 && INTVAL (op) <= 3); |
| 4167 | + } |
| 4168 | + |
| 4169 | + return 0; |
| 4170 | +} |
| 4171 | + |
| 4172 | + |
| 4173 | +/* |
| 4174 | + Used in the GO_IF_LEGITIMATE_ADDRESS macro. Returns a nonzero value if |
| 4175 | + the RTX x is a legitimate memory address. |
| 4176 | + |
| 4177 | + Returns NO_REGS if the address is not legatime, GENERAL_REGS or ALL_REGS |
| 4178 | + if it is. |
| 4179 | +*/ |
| 4180 | + |
| 4181 | + |
| 4182 | +/* Forward declaration */ |
| 4183 | +int is_minipool_label (rtx label); |
| 4184 | + |
| 4185 | +int |
| 4186 | +avr32_legitimate_address (enum machine_mode mode, rtx x, int strict) |
| 4187 | +{ |
| 4188 | + |
| 4189 | + switch (GET_CODE (x)) |
| 4190 | + { |
| 4191 | + case REG: |
| 4192 | + return avr32_address_register_rtx_p (x, strict); |
| 4193 | + case CONST_INT: |
| 4194 | + return ((mode==SImode) && TARGET_RMW_ADDRESSABLE_DATA |
| 4195 | + && CONST_OK_FOR_CONSTRAINT_P(INTVAL(x), 'K', "Ks17")); |
| 4196 | + case CONST: |
| 4197 | + { |
| 4198 | + rtx label = avr32_find_symbol (x); |
| 4199 | + if (label |
| 4200 | + && |
| 4201 | + (/* |
| 4202 | + If we enable (const (plus (symbol_ref ...))) type constant |
| 4203 | + pool entries we must add support for it in the predicates and |
| 4204 | + in the minipool generation in avr32_reorg(). |
| 4205 | + (CONSTANT_POOL_ADDRESS_P (label) |
| 4206 | + && !(flag_pic |
| 4207 | + && (symbol_mentioned_p (get_pool_constant (label)) |
| 4208 | + || label_mentioned_p (get_pool_constant (label))))) |
| 4209 | + ||*/ |
| 4210 | + ((GET_CODE (label) == LABEL_REF) |
| 4211 | + && GET_CODE (XEXP (label, 0)) == CODE_LABEL |
| 4212 | + && is_minipool_label (XEXP (label, 0))) |
| 4213 | + /*|| ((GET_CODE (label) == SYMBOL_REF) |
| 4214 | + && mode == SImode |
| 4215 | + && SYMBOL_REF_RMW_ADDR(label))*/)) |
| 4216 | + { |
| 4217 | + return TRUE; |
| 4218 | + } |
| 4219 | + } |
| 4220 | + break; |
| 4221 | + case LABEL_REF: |
| 4222 | + if (GET_CODE (XEXP (x, 0)) == CODE_LABEL |
| 4223 | + && is_minipool_label (XEXP (x, 0))) |
| 4224 | + { |
| 4225 | + return TRUE; |
| 4226 | + } |
| 4227 | + break; |
| 4228 | + case SYMBOL_REF: |
| 4229 | + { |
| 4230 | + if (CONSTANT_POOL_ADDRESS_P (x) |
| 4231 | + && !(flag_pic |
| 4232 | + && (symbol_mentioned_p (get_pool_constant (x)) |
| 4233 | + || label_mentioned_p (get_pool_constant (x))))) |
| 4234 | + return TRUE; |
| 4235 | + else if (SYMBOL_REF_RCALL_FUNCTION_P (x) |
| 4236 | + || (mode == SImode |
| 4237 | + && SYMBOL_REF_RMW_ADDR (x))) |
| 4238 | + return TRUE; |
| 4239 | + break; |
| 4240 | + } |
| 4241 | + case PRE_DEC: /* (pre_dec (...)) */ |
| 4242 | + case POST_INC: /* (post_inc (...)) */ |
| 4243 | + return avr32_address_register_rtx_p (XEXP (x, 0), strict); |
| 4244 | + case PLUS: /* (plus (...) (...)) */ |
| 4245 | + { |
| 4246 | + rtx xop0 = XEXP (x, 0); |
| 4247 | + rtx xop1 = XEXP (x, 1); |
| 4248 | + |
| 4249 | + return ((avr32_address_register_rtx_p (xop0, strict) |
| 4250 | + && avr32_legitimate_index_p (mode, xop1, strict)) |
| 4251 | + || (avr32_address_register_rtx_p (xop1, strict) |
| 4252 | + && avr32_legitimate_index_p (mode, xop0, strict))); |
| 4253 | + } |
| 4254 | + default: |
| 4255 | + break; |
| 4256 | + } |
| 4257 | + |
| 4258 | + return FALSE; |
| 4259 | +} |
| 4260 | + |
| 4261 | + |
| 4262 | +int |
| 4263 | +avr32_const_ok_for_move (HOST_WIDE_INT c) |
| 4264 | +{ |
| 4265 | + if ( TARGET_V2_INSNS ) |
| 4266 | + return ( avr32_const_ok_for_constraint_p (c, 'K', "Ks21") |
| 4267 | + /* movh instruction */ |
| 4268 | + || avr32_hi16_immediate_operand (GEN_INT(c), VOIDmode) ); |
| 4269 | + else |
| 4270 | + return avr32_const_ok_for_constraint_p (c, 'K', "Ks21"); |
| 4271 | +} |
| 4272 | + |
| 4273 | + |
| 4274 | +int |
| 4275 | +avr32_const_double_immediate (rtx value) |
| 4276 | +{ |
| 4277 | + HOST_WIDE_INT hi, lo; |
| 4278 | + |
| 4279 | + if (GET_CODE (value) != CONST_DOUBLE) |
| 4280 | + return FALSE; |
| 4281 | + |
| 4282 | + if (SCALAR_FLOAT_MODE_P (GET_MODE (value))) |
| 4283 | + { |
| 4284 | + HOST_WIDE_INT target_float[2]; |
| 4285 | + hi = lo = 0; |
| 4286 | + real_to_target (target_float, CONST_DOUBLE_REAL_VALUE (value), |
| 4287 | + GET_MODE (value)); |
| 4288 | + lo = target_float[0]; |
| 4289 | + hi = target_float[1]; |
| 4290 | + } |
| 4291 | + else |
| 4292 | + { |
| 4293 | + hi = CONST_DOUBLE_HIGH (value); |
| 4294 | + lo = CONST_DOUBLE_LOW (value); |
| 4295 | + } |
| 4296 | + |
| 4297 | + if (avr32_const_ok_for_constraint_p (lo, 'K', "Ks21") |
| 4298 | + && (GET_MODE (value) == SFmode |
| 4299 | + || avr32_const_ok_for_constraint_p (hi, 'K', "Ks21"))) |
| 4300 | + { |
| 4301 | + return TRUE; |
| 4302 | + } |
| 4303 | + |
| 4304 | + return FALSE; |
| 4305 | +} |
| 4306 | + |
| 4307 | + |
| 4308 | +int |
| 4309 | +avr32_legitimate_constant_p (rtx x) |
| 4310 | +{ |
| 4311 | + switch (GET_CODE (x)) |
| 4312 | + { |
| 4313 | + case CONST_INT: |
| 4314 | + /* Check if we should put large immediate into constant pool |
| 4315 | + or load them directly with mov/orh.*/ |
| 4316 | + if (!avr32_imm_in_const_pool) |
| 4317 | + return 1; |
| 4318 | + |
| 4319 | + return avr32_const_ok_for_move (INTVAL (x)); |
| 4320 | + case CONST_DOUBLE: |
| 4321 | + /* Check if we should put large immediate into constant pool |
| 4322 | + or load them directly with mov/orh.*/ |
| 4323 | + if (!avr32_imm_in_const_pool) |
| 4324 | + return 1; |
| 4325 | + |
| 4326 | + if (GET_MODE (x) == SFmode |
| 4327 | + || GET_MODE (x) == DFmode || GET_MODE (x) == DImode) |
| 4328 | + return avr32_const_double_immediate (x); |
| 4329 | + else |
| 4330 | + return 0; |
| 4331 | + case LABEL_REF: |
| 4332 | + case SYMBOL_REF: |
| 4333 | + return avr32_find_symbol (x) && (flag_pic || TARGET_HAS_ASM_ADDR_PSEUDOS); |
| 4334 | + case CONST: |
| 4335 | + case HIGH: |
| 4336 | + case CONST_VECTOR: |
| 4337 | + return 0; |
| 4338 | + default: |
| 4339 | + printf ("%s():\n", __FUNCTION__); |
| 4340 | + debug_rtx (x); |
| 4341 | + return 1; |
| 4342 | + } |
| 4343 | +} |
| 4344 | + |
| 4345 | + |
| 4346 | +/* Strip any special encoding from labels */ |
| 4347 | +const char * |
| 4348 | +avr32_strip_name_encoding (const char *name) |
| 4349 | +{ |
| 4350 | + const char *stripped = name; |
| 4351 | + |
| 4352 | + while (1) |
| 4353 | + { |
| 4354 | + switch (stripped[0]) |
| 4355 | + { |
| 4356 | + case '#': |
| 4357 | + stripped = strchr (name + 1, '#') + 1; |
| 4358 | + break; |
| 4359 | + case '*': |
| 4360 | + stripped = &stripped[1]; |
| 4361 | + break; |
| 4362 | + default: |
| 4363 | + return stripped; |
| 4364 | + } |
| 4365 | + } |
| 4366 | +} |
| 4367 | + |
| 4368 | + |
| 4369 | + |
| 4370 | +/* Do anything needed before RTL is emitted for each function. */ |
| 4371 | +static struct machine_function * |
| 4372 | +avr32_init_machine_status (void) |
| 4373 | +{ |
| 4374 | + struct machine_function *machine; |
| 4375 | + machine = |
| 4376 | + (machine_function *) ggc_alloc_cleared (sizeof (machine_function)); |
| 4377 | + |
| 4378 | +#if AVR32_FT_UNKNOWN != 0 |
| 4379 | + machine->func_type = AVR32_FT_UNKNOWN; |
| 4380 | +#endif |
| 4381 | + |
| 4382 | + machine->minipool_label_head = 0; |
| 4383 | + machine->minipool_label_tail = 0; |
| 4384 | + machine->ifcvt_after_reload = 0; |
| 4385 | + return machine; |
| 4386 | +} |
| 4387 | + |
| 4388 | + |
| 4389 | +void |
| 4390 | +avr32_init_expanders (void) |
| 4391 | +{ |
| 4392 | + /* Arrange to initialize and mark the machine per-function status. */ |
| 4393 | + init_machine_status = avr32_init_machine_status; |
| 4394 | +} |
| 4395 | + |
| 4396 | + |
| 4397 | +/* Return an RTX indicating where the return address to the |
| 4398 | + calling function can be found. */ |
| 4399 | +rtx |
| 4400 | +avr32_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) |
| 4401 | +{ |
| 4402 | + if (count != 0) |
| 4403 | + return NULL_RTX; |
| 4404 | + |
| 4405 | + return get_hard_reg_initial_val (Pmode, LR_REGNUM); |
| 4406 | +} |
| 4407 | + |
| 4408 | + |
| 4409 | +void |
| 4410 | +avr32_encode_section_info (tree decl, rtx rtl, int first) |
| 4411 | +{ |
| 4412 | + default_encode_section_info(decl, rtl, first); |
| 4413 | + |
| 4414 | + if ( TREE_CODE (decl) == VAR_DECL |
| 4415 | + && (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF) |
| 4416 | + && (lookup_attribute ("rmw_addressable", DECL_ATTRIBUTES (decl)) |
| 4417 | + || TARGET_RMW_ADDRESSABLE_DATA) ){ |
| 4418 | + if ( !TARGET_RMW || flag_pic ) |
| 4419 | + return; |
| 4420 | + // { |
| 4421 | + // warning ("Using RMW addressable data with an arch that does not support RMW instructions."); |
| 4422 | + // return; |
| 4423 | + // } |
| 4424 | + // |
| 4425 | + //if ( flag_pic ) |
| 4426 | + // { |
| 4427 | + // warning ("Using RMW addressable data with together with -fpic switch. Can not use RMW instruction when compiling with -fpic."); |
| 4428 | + // return; |
| 4429 | + // } |
| 4430 | + SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= (1 << SYMBOL_FLAG_RMW_ADDR_SHIFT); |
| 4431 | + } |
| 4432 | +} |
| 4433 | + |
| 4434 | + |
| 4435 | +void |
| 4436 | +avr32_asm_output_label (FILE * stream, const char *name) |
| 4437 | +{ |
| 4438 | + name = avr32_strip_name_encoding (name); |
| 4439 | + |
| 4440 | + /* Print the label. */ |
| 4441 | + assemble_name (stream, name); |
| 4442 | + fprintf (stream, ":\n"); |
| 4443 | +} |
| 4444 | + |
| 4445 | + |
| 4446 | +void |
| 4447 | +avr32_asm_weaken_label (FILE * stream, const char *name) |
| 4448 | +{ |
| 4449 | + fprintf (stream, "\t.weak "); |
| 4450 | + assemble_name (stream, name); |
| 4451 | + fprintf (stream, "\n"); |
| 4452 | +} |
| 4453 | + |
| 4454 | + |
| 4455 | +/* |
| 4456 | + Checks if a labelref is equal to a reserved word in the assembler. If it is, |
| 4457 | + insert a '_' before the label name. |
| 4458 | +*/ |
| 4459 | +void |
| 4460 | +avr32_asm_output_labelref (FILE * stream, const char *name) |
| 4461 | +{ |
| 4462 | + int verbatim = FALSE; |
| 4463 | + const char *stripped = name; |
| 4464 | + int strip_finished = FALSE; |
| 4465 | + |
| 4466 | + while (!strip_finished) |
| 4467 | + { |
| 4468 | + switch (stripped[0]) |
| 4469 | + { |
| 4470 | + case '#': |
| 4471 | + stripped = strchr (name + 1, '#') + 1; |
| 4472 | + break; |
| 4473 | + case '*': |
| 4474 | + stripped = &stripped[1]; |
| 4475 | + verbatim = TRUE; |
| 4476 | + break; |
| 4477 | + default: |
| 4478 | + strip_finished = TRUE; |
| 4479 | + break; |
| 4480 | + } |
| 4481 | + } |
| 4482 | + |
| 4483 | + if (verbatim) |
| 4484 | + fputs (stripped, stream); |
| 4485 | + else |
| 4486 | + asm_fprintf (stream, "%U%s", stripped); |
| 4487 | +} |
| 4488 | + |
| 4489 | + |
| 4490 | +/* |
| 4491 | + Check if the comparison in compare_exp is redundant |
| 4492 | + for the condition given in next_cond given that the |
| 4493 | + needed flags are already set by an earlier instruction. |
| 4494 | + Uses cc_prev_status to check this. |
| 4495 | + |
| 4496 | + Returns NULL_RTX if the compare is not redundant |
| 4497 | + or the new condition to use in the conditional |
| 4498 | + instruction if the compare is redundant. |
| 4499 | +*/ |
| 4500 | +static rtx |
| 4501 | +is_compare_redundant (rtx compare_exp, rtx next_cond) |
| 4502 | +{ |
| 4503 | + int z_flag_valid = FALSE; |
| 4504 | + int n_flag_valid = FALSE; |
| 4505 | + rtx new_cond; |
| 4506 | + |
| 4507 | + if (GET_CODE (compare_exp) != COMPARE |
| 4508 | + && GET_CODE (compare_exp) != AND) |
| 4509 | + return NULL_RTX; |
| 4510 | + |
| 4511 | + |
| 4512 | + if (rtx_equal_p (cc_prev_status.mdep.value, compare_exp)) |
| 4513 | + { |
| 4514 | + /* cc0 already contains the correct comparison -> delete cmp insn */ |
| 4515 | + return next_cond; |
| 4516 | + } |
| 4517 | + |
| 4518 | + if (GET_MODE (compare_exp) != SImode) |
| 4519 | + return NULL_RTX; |
| 4520 | + |
| 4521 | + switch (cc_prev_status.mdep.flags) |
| 4522 | + { |
| 4523 | + case CC_SET_VNCZ: |
| 4524 | + case CC_SET_NCZ: |
| 4525 | + n_flag_valid = TRUE; |
| 4526 | + case CC_SET_CZ: |
| 4527 | + case CC_SET_Z: |
| 4528 | + z_flag_valid = TRUE; |
| 4529 | + } |
| 4530 | + |
| 4531 | + if (cc_prev_status.mdep.value |
| 4532 | + && GET_CODE (compare_exp) == COMPARE |
| 4533 | + && REG_P (XEXP (compare_exp, 0)) |
| 4534 | + && REGNO (XEXP (compare_exp, 0)) == REGNO (cc_prev_status.mdep.value) |
| 4535 | + && GET_CODE (XEXP (compare_exp, 1)) == CONST_INT |
| 4536 | + && next_cond != NULL_RTX) |
| 4537 | + { |
| 4538 | + if (INTVAL (XEXP (compare_exp, 1)) == 0 |
| 4539 | + && z_flag_valid |
| 4540 | + && (GET_CODE (next_cond) == EQ || GET_CODE (next_cond) == NE)) |
| 4541 | + /* We can skip comparison Z flag is already reflecting ops[0] */ |
| 4542 | + return next_cond; |
| 4543 | + else if (n_flag_valid |
| 4544 | + && ((INTVAL (XEXP (compare_exp, 1)) == 0 |
| 4545 | + && (GET_CODE (next_cond) == GE |
| 4546 | + || GET_CODE (next_cond) == LT)) |
| 4547 | + || (INTVAL (XEXP (compare_exp, 1)) == -1 |
| 4548 | + && (GET_CODE (next_cond) == GT |
| 4549 | + || GET_CODE (next_cond) == LE)))) |
| 4550 | + { |
| 4551 | + /* We can skip comparison N flag is already reflecting ops[0], |
| 4552 | + which means that we can use the mi/pl conditions to check if |
| 4553 | + ops[0] is GE or LT 0. */ |
| 4554 | + if ((GET_CODE (next_cond) == GE) || (GET_CODE (next_cond) == GT)) |
| 4555 | + new_cond = |
| 4556 | + gen_rtx_UNSPEC (GET_MODE (next_cond), gen_rtvec (2, cc0_rtx, const0_rtx), |
| 4557 | + UNSPEC_COND_PL); |
| 4558 | + else |
| 4559 | + new_cond = |
| 4560 | + gen_rtx_UNSPEC (GET_MODE (next_cond), gen_rtvec (2, cc0_rtx, const0_rtx), |
| 4561 | + UNSPEC_COND_MI); |
| 4562 | + return new_cond; |
| 4563 | + } |
| 4564 | + } |
| 4565 | + return NULL_RTX; |
| 4566 | +} |
| 4567 | + |
| 4568 | + |
| 4569 | +/* Updates cc_status. */ |
| 4570 | +void |
| 4571 | +avr32_notice_update_cc (rtx exp, rtx insn) |
| 4572 | +{ |
| 4573 | + enum attr_cc attr_cc = get_attr_cc (insn); |
| 4574 | + |
| 4575 | + if ( attr_cc == CC_SET_Z_IF_NOT_V2 ) |
| 4576 | + { |
| 4577 | + if (TARGET_V2_INSNS) |
| 4578 | + attr_cc = CC_NONE; |
| 4579 | + else |
| 4580 | + attr_cc = CC_SET_Z; |
| 4581 | + } |
| 4582 | + |
| 4583 | + switch (attr_cc) |
| 4584 | + { |
| 4585 | + case CC_CALL_SET: |
| 4586 | + CC_STATUS_INIT; |
| 4587 | + /* Check if the function call returns a value in r12 */ |
| 4588 | + if (REG_P (recog_data.operand[0]) |
| 4589 | + && REGNO (recog_data.operand[0]) == RETVAL_REGNUM) |
| 4590 | + { |
| 4591 | + cc_status.flags = 0; |
| 4592 | + cc_status.mdep.value = |
| 4593 | + gen_rtx_COMPARE (SImode, recog_data.operand[0], const0_rtx); |
| 4594 | + cc_status.mdep.flags = CC_SET_VNCZ; |
| 4595 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4596 | + |
| 4597 | + } |
| 4598 | + break; |
| 4599 | + case CC_COMPARE: |
| 4600 | + { |
| 4601 | + /* Check that compare will not be optimized away if so nothing should |
| 4602 | + be done */ |
| 4603 | + rtx compare_exp = SET_SRC (exp); |
| 4604 | + /* Check if we have a tst expression. If so convert it to a |
| 4605 | + compare with 0. */ |
| 4606 | + if ( REG_P (SET_SRC (exp)) ) |
| 4607 | + compare_exp = gen_rtx_COMPARE (GET_MODE (SET_SRC (exp)), |
| 4608 | + SET_SRC (exp), |
| 4609 | + const0_rtx); |
| 4610 | + |
| 4611 | + if (!next_insn_emits_cmp (insn) |
| 4612 | + && (is_compare_redundant (compare_exp, get_next_insn_cond (insn)) == NULL_RTX)) |
| 4613 | + { |
| 4614 | + |
| 4615 | + /* Reset the nonstandard flag */ |
| 4616 | + CC_STATUS_INIT; |
| 4617 | + cc_status.flags = 0; |
| 4618 | + cc_status.mdep.value = compare_exp; |
| 4619 | + cc_status.mdep.flags = CC_SET_VNCZ; |
| 4620 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4621 | + } |
| 4622 | + } |
| 4623 | + break; |
| 4624 | + case CC_CMP_COND_INSN: |
| 4625 | + { |
| 4626 | + /* Conditional insn that emit the compare itself. */ |
| 4627 | + rtx cmp; |
| 4628 | + rtx cmp_op0, cmp_op1; |
| 4629 | + rtx cond; |
| 4630 | + rtx dest; |
| 4631 | + rtx next_insn = next_nonnote_insn (insn); |
| 4632 | + |
| 4633 | + if ( GET_CODE (exp) == COND_EXEC ) |
| 4634 | + { |
| 4635 | + cmp_op0 = XEXP (COND_EXEC_TEST (exp), 0); |
| 4636 | + cmp_op1 = XEXP (COND_EXEC_TEST (exp), 1); |
| 4637 | + cond = COND_EXEC_TEST (exp); |
| 4638 | + dest = SET_DEST (COND_EXEC_CODE (exp)); |
| 4639 | + } |
| 4640 | + else |
| 4641 | + { |
| 4642 | + /* If then else conditional. compare operands are in operands |
| 4643 | + 4 and 5. */ |
| 4644 | + cmp_op0 = recog_data.operand[4]; |
| 4645 | + cmp_op1 = recog_data.operand[5]; |
| 4646 | + cond = recog_data.operand[1]; |
| 4647 | + dest = SET_DEST (exp); |
| 4648 | + } |
| 4649 | + |
| 4650 | + if ( GET_CODE (cmp_op0) == AND ) |
| 4651 | + cmp = cmp_op0; |
| 4652 | + else |
| 4653 | + cmp = gen_rtx_COMPARE (GET_MODE (cmp_op0), |
| 4654 | + cmp_op0, |
| 4655 | + cmp_op1); |
| 4656 | + |
| 4657 | + /* Check if the conditional insns updates a register present |
| 4658 | + in the comparison, if so then we must reset the cc_status. */ |
| 4659 | + if (REG_P (dest) |
| 4660 | + && (reg_mentioned_p (dest, cmp_op0) |
| 4661 | + || reg_mentioned_p (dest, cmp_op1)) |
| 4662 | + && GET_CODE (exp) != COND_EXEC ) |
| 4663 | + { |
| 4664 | + CC_STATUS_INIT; |
| 4665 | + } |
| 4666 | + else if (is_compare_redundant (cmp, cond) == NULL_RTX) |
| 4667 | + { |
| 4668 | + /* Reset the nonstandard flag */ |
| 4669 | + CC_STATUS_INIT; |
| 4670 | + if ( GET_CODE (cmp_op0) == AND ) |
| 4671 | + { |
| 4672 | + cc_status.flags = CC_INVERTED; |
| 4673 | + cc_status.mdep.flags = CC_SET_Z; |
| 4674 | + } |
| 4675 | + else |
| 4676 | + { |
| 4677 | + cc_status.flags = 0; |
| 4678 | + cc_status.mdep.flags = CC_SET_VNCZ; |
| 4679 | + } |
| 4680 | + cc_status.mdep.value = cmp; |
| 4681 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4682 | + } |
| 4683 | + |
| 4684 | + |
| 4685 | + /* Check if we have a COND_EXEC insn which updates one |
| 4686 | + of the registers in the compare status. */ |
| 4687 | + if (REG_P (dest) |
| 4688 | + && (reg_mentioned_p (dest, cmp_op0) |
| 4689 | + || reg_mentioned_p (dest, cmp_op1)) |
| 4690 | + && GET_CODE (exp) == COND_EXEC ) |
| 4691 | + cc_status.mdep.cond_exec_cmp_clobbered = 1; |
| 4692 | + |
| 4693 | + if ( cc_status.mdep.cond_exec_cmp_clobbered |
| 4694 | + && GET_CODE (exp) == COND_EXEC |
| 4695 | + && next_insn != NULL |
| 4696 | + && INSN_P (next_insn) |
| 4697 | + && !(GET_CODE (PATTERN (next_insn)) == COND_EXEC |
| 4698 | + && rtx_equal_p (XEXP (COND_EXEC_TEST (PATTERN (next_insn)), 0), cmp_op0) |
| 4699 | + && rtx_equal_p (XEXP (COND_EXEC_TEST (PATTERN (next_insn)), 1), cmp_op1) |
| 4700 | + && (GET_CODE (COND_EXEC_TEST (PATTERN (next_insn))) == GET_CODE (cond) |
| 4701 | + || GET_CODE (COND_EXEC_TEST (PATTERN (next_insn))) == reverse_condition (GET_CODE (cond)))) ) |
| 4702 | + { |
| 4703 | + /* We have a sequence of conditional insns where the compare status has been clobbered |
| 4704 | + since the compare no longer reflects the content of the values to compare. */ |
| 4705 | + CC_STATUS_INIT; |
| 4706 | + cc_status.mdep.cond_exec_cmp_clobbered = 1; |
| 4707 | + } |
| 4708 | + |
| 4709 | + } |
| 4710 | + break; |
| 4711 | + case CC_BLD: |
| 4712 | + /* Bit load is kind of like an inverted testsi, because the Z flag is |
| 4713 | + inverted */ |
| 4714 | + CC_STATUS_INIT; |
| 4715 | + cc_status.flags = CC_INVERTED; |
| 4716 | + cc_status.mdep.value = SET_SRC (exp); |
| 4717 | + cc_status.mdep.flags = CC_SET_Z; |
| 4718 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4719 | + break; |
| 4720 | + case CC_NONE: |
| 4721 | + /* Insn does not affect CC at all. Check if the instruction updates |
| 4722 | + some of the register currently reflected in cc0 */ |
| 4723 | + |
| 4724 | + if ((GET_CODE (exp) == SET) |
| 4725 | + && (cc_status.value1 || cc_status.value2 || cc_status.mdep.value) |
| 4726 | + && (reg_mentioned_p (SET_DEST (exp), cc_status.value1) |
| 4727 | + || reg_mentioned_p (SET_DEST (exp), cc_status.value2) |
| 4728 | + || reg_mentioned_p (SET_DEST (exp), cc_status.mdep.value))) |
| 4729 | + { |
| 4730 | + CC_STATUS_INIT; |
| 4731 | + } |
| 4732 | + |
| 4733 | + /* If this is a parallel we must step through each of the parallel |
| 4734 | + expressions */ |
| 4735 | + if (GET_CODE (exp) == PARALLEL) |
| 4736 | + { |
| 4737 | + int i; |
| 4738 | + for (i = 0; i < XVECLEN (exp, 0); ++i) |
| 4739 | + { |
| 4740 | + rtx vec_exp = XVECEXP (exp, 0, i); |
| 4741 | + if ((GET_CODE (vec_exp) == SET) |
| 4742 | + && (cc_status.value1 || cc_status.value2 |
| 4743 | + || cc_status.mdep.value) |
| 4744 | + && (reg_mentioned_p (SET_DEST (vec_exp), cc_status.value1) |
| 4745 | + || reg_mentioned_p (SET_DEST (vec_exp), |
| 4746 | + cc_status.value2) |
| 4747 | + || reg_mentioned_p (SET_DEST (vec_exp), |
| 4748 | + cc_status.mdep.value))) |
| 4749 | + { |
| 4750 | + CC_STATUS_INIT; |
| 4751 | + } |
| 4752 | + } |
| 4753 | + } |
| 4754 | + |
| 4755 | + /* Check if we have memory opartions with post_inc or pre_dec on the |
| 4756 | + register currently reflected in cc0 */ |
| 4757 | + if (GET_CODE (exp) == SET |
| 4758 | + && GET_CODE (SET_SRC (exp)) == MEM |
| 4759 | + && (GET_CODE (XEXP (SET_SRC (exp), 0)) == POST_INC |
| 4760 | + || GET_CODE (XEXP (SET_SRC (exp), 0)) == PRE_DEC) |
| 4761 | + && |
| 4762 | + (reg_mentioned_p |
| 4763 | + (XEXP (XEXP (SET_SRC (exp), 0), 0), cc_status.value1) |
| 4764 | + || reg_mentioned_p (XEXP (XEXP (SET_SRC (exp), 0), 0), |
| 4765 | + cc_status.value2) |
| 4766 | + || reg_mentioned_p (XEXP (XEXP (SET_SRC (exp), 0), 0), |
| 4767 | + cc_status.mdep.value))) |
| 4768 | + CC_STATUS_INIT; |
| 4769 | + |
| 4770 | + if (GET_CODE (exp) == SET |
| 4771 | + && GET_CODE (SET_DEST (exp)) == MEM |
| 4772 | + && (GET_CODE (XEXP (SET_DEST (exp), 0)) == POST_INC |
| 4773 | + || GET_CODE (XEXP (SET_DEST (exp), 0)) == PRE_DEC) |
| 4774 | + && |
| 4775 | + (reg_mentioned_p |
| 4776 | + (XEXP (XEXP (SET_DEST (exp), 0), 0), cc_status.value1) |
| 4777 | + || reg_mentioned_p (XEXP (XEXP (SET_DEST (exp), 0), 0), |
| 4778 | + cc_status.value2) |
| 4779 | + || reg_mentioned_p (XEXP (XEXP (SET_DEST (exp), 0), 0), |
| 4780 | + cc_status.mdep.value))) |
| 4781 | + CC_STATUS_INIT; |
| 4782 | + break; |
| 4783 | + |
| 4784 | + case CC_SET_VNCZ: |
| 4785 | + CC_STATUS_INIT; |
| 4786 | + cc_status.mdep.value = recog_data.operand[0]; |
| 4787 | + cc_status.mdep.flags = CC_SET_VNCZ; |
| 4788 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4789 | + break; |
| 4790 | + |
| 4791 | + case CC_SET_NCZ: |
| 4792 | + CC_STATUS_INIT; |
| 4793 | + cc_status.mdep.value = recog_data.operand[0]; |
| 4794 | + cc_status.mdep.flags = CC_SET_NCZ; |
| 4795 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4796 | + break; |
| 4797 | + |
| 4798 | + case CC_SET_CZ: |
| 4799 | + CC_STATUS_INIT; |
| 4800 | + cc_status.mdep.value = recog_data.operand[0]; |
| 4801 | + cc_status.mdep.flags = CC_SET_CZ; |
| 4802 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4803 | + break; |
| 4804 | + |
| 4805 | + case CC_SET_Z: |
| 4806 | + CC_STATUS_INIT; |
| 4807 | + cc_status.mdep.value = recog_data.operand[0]; |
| 4808 | + cc_status.mdep.flags = CC_SET_Z; |
| 4809 | + cc_status.mdep.cond_exec_cmp_clobbered = 0; |
| 4810 | + break; |
| 4811 | + |
| 4812 | + case CC_CLOBBER: |
| 4813 | + CC_STATUS_INIT; |
| 4814 | + break; |
| 4815 | + |
| 4816 | + default: |
| 4817 | + CC_STATUS_INIT; |
| 4818 | + } |
| 4819 | +} |
| 4820 | + |
| 4821 | + |
| 4822 | +/* |
| 4823 | + Outputs to stdio stream stream the assembler syntax for an instruction |
| 4824 | + operand x. x is an RTL expression. |
| 4825 | +*/ |
| 4826 | +void |
| 4827 | +avr32_print_operand (FILE * stream, rtx x, int code) |
| 4828 | +{ |
| 4829 | + int error = 0; |
| 4830 | + |
| 4831 | + if ( code == '?' ) |
| 4832 | + { |
| 4833 | + /* Predicable instruction, print condition code */ |
| 4834 | + |
| 4835 | + /* If the insn should not be conditional then do nothing. */ |
| 4836 | + if ( current_insn_predicate == NULL_RTX ) |
| 4837 | + return; |
| 4838 | + |
| 4839 | + /* Set x to the predicate to force printing |
| 4840 | + the condition later on. */ |
| 4841 | + x = current_insn_predicate; |
| 4842 | + |
| 4843 | + /* Reverse condition if useing bld insn. */ |
| 4844 | + if ( GET_CODE (XEXP(current_insn_predicate,0)) == AND ) |
| 4845 | + x = reversed_condition (current_insn_predicate); |
| 4846 | + } |
| 4847 | + else if ( code == '!' ) |
| 4848 | + { |
| 4849 | + /* Output compare for conditional insn if needed. */ |
| 4850 | + rtx new_cond; |
| 4851 | + gcc_assert ( current_insn_predicate != NULL_RTX ); |
| 4852 | + new_cond = avr32_output_cmp(current_insn_predicate, |
| 4853 | + GET_MODE(XEXP(current_insn_predicate,0)), |
| 4854 | + XEXP(current_insn_predicate,0), |
| 4855 | + XEXP(current_insn_predicate,1)); |
| 4856 | + |
| 4857 | + /* Check if the new condition is a special avr32 condition |
| 4858 | + specified using UNSPECs. If so we must handle it differently. */ |
| 4859 | + if ( GET_CODE (new_cond) == UNSPEC ) |
| 4860 | + { |
| 4861 | + current_insn_predicate = |
| 4862 | + gen_rtx_UNSPEC (CCmode, |
| 4863 | + gen_rtvec (2, |
| 4864 | + XEXP(current_insn_predicate,0), |
| 4865 | + XEXP(current_insn_predicate,1)), |
| 4866 | + XINT (new_cond, 1)); |
| 4867 | + } |
| 4868 | + else |
| 4869 | + { |
| 4870 | + PUT_CODE(current_insn_predicate, GET_CODE(new_cond)); |
| 4871 | + } |
| 4872 | + return; |
| 4873 | + } |
| 4874 | + |
| 4875 | + switch (GET_CODE (x)) |
| 4876 | + { |
| 4877 | + case UNSPEC: |
| 4878 | + switch (XINT (x, 1)) |
| 4879 | + { |
| 4880 | + case UNSPEC_COND_PL: |
| 4881 | + if (code == 'i') |
| 4882 | + fputs ("mi", stream); |
| 4883 | + else |
| 4884 | + fputs ("pl", stream); |
| 4885 | + break; |
| 4886 | + case UNSPEC_COND_MI: |
| 4887 | + if (code == 'i') |
| 4888 | + fputs ("pl", stream); |
| 4889 | + else |
| 4890 | + fputs ("mi", stream); |
| 4891 | + break; |
| 4892 | + default: |
| 4893 | + error = 1; |
| 4894 | + } |
| 4895 | + break; |
| 4896 | + case EQ: |
| 4897 | + if (code == 'i') |
| 4898 | + fputs ("ne", stream); |
| 4899 | + else |
| 4900 | + fputs ("eq", stream); |
| 4901 | + break; |
| 4902 | + case NE: |
| 4903 | + if (code == 'i') |
| 4904 | + fputs ("eq", stream); |
| 4905 | + else |
| 4906 | + fputs ("ne", stream); |
| 4907 | + break; |
| 4908 | + case GT: |
| 4909 | + if (code == 'i') |
| 4910 | + fputs ("le", stream); |
| 4911 | + else |
| 4912 | + fputs ("gt", stream); |
| 4913 | + break; |
| 4914 | + case GTU: |
| 4915 | + if (code == 'i') |
| 4916 | + fputs ("ls", stream); |
| 4917 | + else |
| 4918 | + fputs ("hi", stream); |
| 4919 | + break; |
| 4920 | + case LT: |
| 4921 | + if (code == 'i') |
| 4922 | + fputs ("ge", stream); |
| 4923 | + else |
| 4924 | + fputs ("lt", stream); |
| 4925 | + break; |
| 4926 | + case LTU: |
| 4927 | + if (code == 'i') |
| 4928 | + fputs ("hs", stream); |
| 4929 | + else |
| 4930 | + fputs ("lo", stream); |
| 4931 | + break; |
| 4932 | + case GE: |
| 4933 | + if (code == 'i') |
| 4934 | + fputs ("lt", stream); |
| 4935 | + else |
| 4936 | + fputs ("ge", stream); |
| 4937 | + break; |
| 4938 | + case GEU: |
| 4939 | + if (code == 'i') |
| 4940 | + fputs ("lo", stream); |
| 4941 | + else |
| 4942 | + fputs ("hs", stream); |
| 4943 | + break; |
| 4944 | + case LE: |
| 4945 | + if (code == 'i') |
| 4946 | + fputs ("gt", stream); |
| 4947 | + else |
| 4948 | + fputs ("le", stream); |
| 4949 | + break; |
| 4950 | + case LEU: |
| 4951 | + if (code == 'i') |
| 4952 | + fputs ("hi", stream); |
| 4953 | + else |
| 4954 | + fputs ("ls", stream); |
| 4955 | + break; |
| 4956 | + case CONST_INT: |
| 4957 | + { |
| 4958 | + HOST_WIDE_INT value = INTVAL (x); |
| 4959 | + |
| 4960 | + switch (code) |
| 4961 | + { |
| 4962 | + case 'm': |
| 4963 | + if ( HOST_BITS_PER_WIDE_INT > BITS_PER_WORD ) |
| 4964 | + { |
| 4965 | + /* A const_int can be used to represent DImode constants. */ |
| 4966 | + value >>= BITS_PER_WORD; |
| 4967 | + } |
| 4968 | + /* We might get a const_int immediate for setting a DI register, |
| 4969 | + we then must then return the correct sign extended DI. The most |
| 4970 | + significant word is just a sign extension. */ |
| 4971 | + else if (value < 0) |
| 4972 | + value = -1; |
| 4973 | + else |
| 4974 | + value = 0; |
| 4975 | + break; |
| 4976 | + case 'i': |
| 4977 | + value++; |
| 4978 | + break; |
| 4979 | + case 'p': |
| 4980 | + { |
| 4981 | + /* Set to bit position of first bit set in immediate */ |
| 4982 | + int i, bitpos = 32; |
| 4983 | + for (i = 0; i < 32; i++) |
| 4984 | + if (value & (1 << i)) |
| 4985 | + { |
| 4986 | + bitpos = i; |
| 4987 | + break; |
| 4988 | + } |
| 4989 | + value = bitpos; |
| 4990 | + } |
| 4991 | + break; |
| 4992 | + case 'z': |
| 4993 | + { |
| 4994 | + /* Set to bit position of first bit cleared in immediate */ |
| 4995 | + int i, bitpos = 32; |
| 4996 | + for (i = 0; i < 32; i++) |
| 4997 | + if (!(value & (1 << i))) |
| 4998 | + { |
| 4999 | + bitpos = i; |
| 5000 | + break; |
| 5001 | + } |
| 5002 | + value = bitpos; |
| 5003 | + } |
| 5004 | + break; |
| 5005 | + case 'r': |
| 5006 | + { |
| 5007 | + /* Reglist 8 */ |
| 5008 | + char op[50]; |
| 5009 | + op[0] = '\0'; |
| 5010 | + |
| 5011 | + if (value & 0x01) |
| 5012 | + strcpy (op, "r0-r3"); |
| 5013 | + if (value & 0x02) |
| 5014 | + strlen (op) ? strcat (op, ", r4-r7") : strcpy (op,"r4-r7"); |
| 5015 | + if (value & 0x04) |
| 5016 | + strlen (op) ? strcat (op, ", r8-r9") : strcpy (op,"r8-r9"); |
| 5017 | + if (value & 0x08) |
| 5018 | + strlen (op) ? strcat (op, ", r10") : strcpy (op,"r10"); |
| 5019 | + if (value & 0x10) |
| 5020 | + strlen (op) ? strcat (op, ", r11") : strcpy (op,"r11"); |
| 5021 | + if (value & 0x20) |
| 5022 | + strlen (op) ? strcat (op, ", r12") : strcpy (op,"r12"); |
| 5023 | + if (value & 0x40) |
| 5024 | + strlen (op) ? strcat (op, ", lr") : strcpy (op, "lr"); |
| 5025 | + if (value & 0x80) |
| 5026 | + strlen (op) ? strcat (op, ", pc") : strcpy (op, "pc"); |
| 5027 | + |
| 5028 | + fputs (op, stream); |
| 5029 | + return; |
| 5030 | + } |
| 5031 | + case 's': |
| 5032 | + { |
| 5033 | + /* Reglist 16 */ |
| 5034 | + char reglist16_string[100]; |
| 5035 | + int i; |
| 5036 | + bool first_reg = true; |
| 5037 | + reglist16_string[0] = '\0'; |
| 5038 | + |
| 5039 | + for (i = 0; i < 16; ++i) |
| 5040 | + { |
| 5041 | + if (value & (1 << i)) |
| 5042 | + { |
| 5043 | + first_reg == true ? first_reg = false : strcat(reglist16_string,", "); |
| 5044 | + strcat(reglist16_string,reg_names[INTERNAL_REGNUM(i)]); |
| 5045 | + } |
| 5046 | + } |
| 5047 | + fputs (reglist16_string, stream); |
| 5048 | + return; |
| 5049 | + } |
| 5050 | + case 'h': |
| 5051 | + /* Print halfword part of word */ |
| 5052 | + fputs (value ? "b" : "t", stream); |
| 5053 | + return; |
| 5054 | + } |
| 5055 | + |
| 5056 | + /* Print Value */ |
| 5057 | + fprintf (stream, "%d", value); |
| 5058 | + break; |
| 5059 | + } |
| 5060 | + case CONST_DOUBLE: |
| 5061 | + { |
| 5062 | + HOST_WIDE_INT hi, lo; |
| 5063 | + if (SCALAR_FLOAT_MODE_P (GET_MODE (x))) |
| 5064 | + { |
| 5065 | + HOST_WIDE_INT target_float[2]; |
| 5066 | + hi = lo = 0; |
| 5067 | + real_to_target (target_float, CONST_DOUBLE_REAL_VALUE (x), |
| 5068 | + GET_MODE (x)); |
| 5069 | + /* For doubles the most significant part starts at index 0. */ |
| 5070 | + if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) |
| 5071 | + { |
| 5072 | + hi = target_float[0]; |
| 5073 | + lo = target_float[1]; |
| 5074 | + } |
| 5075 | + else |
| 5076 | + { |
| 5077 | + lo = target_float[0]; |
| 5078 | + } |
| 5079 | + } |
| 5080 | + else |
| 5081 | + { |
| 5082 | + hi = CONST_DOUBLE_HIGH (x); |
| 5083 | + lo = CONST_DOUBLE_LOW (x); |
| 5084 | + } |
| 5085 | + |
| 5086 | + if (code == 'm') |
| 5087 | + fprintf (stream, "%ld", hi); |
| 5088 | + else |
| 5089 | + fprintf (stream, "%ld", lo); |
| 5090 | + |
| 5091 | + break; |
| 5092 | + } |
| 5093 | + case CONST: |
| 5094 | + output_addr_const (stream, XEXP (XEXP (x, 0), 0)); |
| 5095 | + fprintf (stream, "+%ld", INTVAL (XEXP (XEXP (x, 0), 1))); |
| 5096 | + break; |
| 5097 | + case REG: |
| 5098 | + /* Swap register name if the register is DImode or DFmode. */ |
| 5099 | + if (GET_MODE (x) == DImode || GET_MODE (x) == DFmode) |
| 5100 | + { |
| 5101 | + /* Double register must have an even numbered address */ |
| 5102 | + gcc_assert (!(REGNO (x) % 2)); |
| 5103 | + if (code == 'm') |
| 5104 | + fputs (reg_names[true_regnum (x)], stream); |
| 5105 | + else |
| 5106 | + fputs (reg_names[true_regnum (x) + 1], stream); |
| 5107 | + } |
| 5108 | + else if (GET_MODE (x) == TImode) |
| 5109 | + { |
| 5110 | + switch (code) |
| 5111 | + { |
| 5112 | + case 'T': |
| 5113 | + fputs (reg_names[true_regnum (x)], stream); |
| 5114 | + break; |
| 5115 | + case 'U': |
| 5116 | + fputs (reg_names[true_regnum (x) + 1], stream); |
| 5117 | + break; |
| 5118 | + case 'L': |
| 5119 | + fputs (reg_names[true_regnum (x) + 2], stream); |
| 5120 | + break; |
| 5121 | + case 'B': |
| 5122 | + fputs (reg_names[true_regnum (x) + 3], stream); |
| 5123 | + break; |
| 5124 | + default: |
| 5125 | + fprintf (stream, "%s, %s, %s, %s", |
| 5126 | + reg_names[true_regnum (x) + 3], |
| 5127 | + reg_names[true_regnum (x) + 2], |
| 5128 | + reg_names[true_regnum (x) + 1], |
| 5129 | + reg_names[true_regnum (x)]); |
| 5130 | + break; |
| 5131 | + } |
| 5132 | + } |
| 5133 | + else |
| 5134 | + { |
| 5135 | + fputs (reg_names[true_regnum (x)], stream); |
| 5136 | + } |
| 5137 | + break; |
| 5138 | + case CODE_LABEL: |
| 5139 | + case LABEL_REF: |
| 5140 | + case SYMBOL_REF: |
| 5141 | + output_addr_const (stream, x); |
| 5142 | + break; |
| 5143 | + case MEM: |
| 5144 | + switch (GET_CODE (XEXP (x, 0))) |
| 5145 | + { |
| 5146 | + case LABEL_REF: |
| 5147 | + case SYMBOL_REF: |
| 5148 | + output_addr_const (stream, XEXP (x, 0)); |
| 5149 | + break; |
| 5150 | + case MEM: |
| 5151 | + switch (GET_CODE (XEXP (XEXP (x, 0), 0))) |
| 5152 | + { |
| 5153 | + case SYMBOL_REF: |
| 5154 | + output_addr_const (stream, XEXP (XEXP (x, 0), 0)); |
| 5155 | + break; |
| 5156 | + default: |
| 5157 | + error = 1; |
| 5158 | + break; |
| 5159 | + } |
| 5160 | + break; |
| 5161 | + case REG: |
| 5162 | + avr32_print_operand (stream, XEXP (x, 0), 0); |
| 5163 | + if (code != 'p') |
| 5164 | + fputs ("[0]", stream); |
| 5165 | + break; |
| 5166 | + case PRE_DEC: |
| 5167 | + fputs ("--", stream); |
| 5168 | + avr32_print_operand (stream, XEXP (XEXP (x, 0), 0), 0); |
| 5169 | + break; |
| 5170 | + case POST_INC: |
| 5171 | + avr32_print_operand (stream, XEXP (XEXP (x, 0), 0), 0); |
| 5172 | + fputs ("++", stream); |
| 5173 | + break; |
| 5174 | + case PLUS: |
| 5175 | + { |
| 5176 | + rtx op0 = XEXP (XEXP (x, 0), 0); |
| 5177 | + rtx op1 = XEXP (XEXP (x, 0), 1); |
| 5178 | + rtx base = NULL_RTX, offset = NULL_RTX; |
| 5179 | + |
| 5180 | + if (avr32_address_register_rtx_p (op0, 1)) |
| 5181 | + { |
| 5182 | + base = op0; |
| 5183 | + offset = op1; |
| 5184 | + } |
| 5185 | + else if (avr32_address_register_rtx_p (op1, 1)) |
| 5186 | + { |
| 5187 | + /* Operands are switched. */ |
| 5188 | + base = op1; |
| 5189 | + offset = op0; |
| 5190 | + } |
| 5191 | + |
| 5192 | + gcc_assert (base && offset |
| 5193 | + && avr32_address_register_rtx_p (base, 1) |
| 5194 | + && avr32_legitimate_index_p (GET_MODE (x), offset, |
| 5195 | + 1)); |
| 5196 | + |
| 5197 | + avr32_print_operand (stream, base, 0); |
| 5198 | + fputs ("[", stream); |
| 5199 | + avr32_print_operand (stream, offset, 0); |
| 5200 | + fputs ("]", stream); |
| 5201 | + break; |
| 5202 | + } |
| 5203 | + case CONST: |
| 5204 | + output_addr_const (stream, XEXP (XEXP (XEXP (x, 0), 0), 0)); |
| 5205 | + fprintf (stream, " + %ld", |
| 5206 | + INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))); |
| 5207 | + break; |
| 5208 | + case CONST_INT: |
| 5209 | + avr32_print_operand (stream, XEXP (x, 0), 0); |
| 5210 | + break; |
| 5211 | + default: |
| 5212 | + error = 1; |
| 5213 | + } |
| 5214 | + break; |
| 5215 | + case MULT: |
| 5216 | + { |
| 5217 | + int value = INTVAL (XEXP (x, 1)); |
| 5218 | + |
| 5219 | + /* Convert immediate in multiplication into a shift immediate */ |
| 5220 | + switch (value) |
| 5221 | + { |
| 5222 | + case 2: |
| 5223 | + value = 1; |
| 5224 | + break; |
| 5225 | + case 4: |
| 5226 | + value = 2; |
| 5227 | + break; |
| 5228 | + case 8: |
| 5229 | + value = 3; |
| 5230 | + break; |
| 5231 | + default: |
| 5232 | + value = 0; |
| 5233 | + } |
| 5234 | + fprintf (stream, "%s << %i", reg_names[true_regnum (XEXP (x, 0))], |
| 5235 | + value); |
| 5236 | + break; |
| 5237 | + } |
| 5238 | + case ASHIFT: |
| 5239 | + if (GET_CODE (XEXP (x, 1)) == CONST_INT) |
| 5240 | + fprintf (stream, "%s << %i", reg_names[true_regnum (XEXP (x, 0))], |
| 5241 | + (int) INTVAL (XEXP (x, 1))); |
| 5242 | + else if (REG_P (XEXP (x, 1))) |
| 5243 | + fprintf (stream, "%s << %s", reg_names[true_regnum (XEXP (x, 0))], |
| 5244 | + reg_names[true_regnum (XEXP (x, 1))]); |
| 5245 | + else |
| 5246 | + { |
| 5247 | + error = 1; |
| 5248 | + } |
| 5249 | + break; |
| 5250 | + case LSHIFTRT: |
| 5251 | + if (GET_CODE (XEXP (x, 1)) == CONST_INT) |
| 5252 | + fprintf (stream, "%s >> %i", reg_names[true_regnum (XEXP (x, 0))], |
| 5253 | + (int) INTVAL (XEXP (x, 1))); |
| 5254 | + else if (REG_P (XEXP (x, 1))) |
| 5255 | + fprintf (stream, "%s >> %s", reg_names[true_regnum (XEXP (x, 0))], |
| 5256 | + reg_names[true_regnum (XEXP (x, 1))]); |
| 5257 | + else |
| 5258 | + { |
| 5259 | + error = 1; |
| 5260 | + } |
| 5261 | + fprintf (stream, ">>"); |
| 5262 | + break; |
| 5263 | + case PARALLEL: |
| 5264 | + { |
| 5265 | + /* Load store multiple */ |
| 5266 | + int i; |
| 5267 | + int count = XVECLEN (x, 0); |
| 5268 | + int reglist16 = 0; |
| 5269 | + char reglist16_string[100]; |
| 5270 | + |
| 5271 | + for (i = 0; i < count; ++i) |
| 5272 | + { |
| 5273 | + rtx vec_elm = XVECEXP (x, 0, i); |
| 5274 | + if (GET_MODE (vec_elm) != SET) |
| 5275 | + { |
| 5276 | + debug_rtx (vec_elm); |
| 5277 | + internal_error ("Unknown element in parallel expression!"); |
| 5278 | + } |
| 5279 | + if (GET_MODE (XEXP (vec_elm, 0)) == REG) |
| 5280 | + { |
| 5281 | + /* Load multiple */ |
| 5282 | + reglist16 |= 1 << ASM_REGNUM (REGNO (XEXP (vec_elm, 0))); |
| 5283 | + } |
| 5284 | + else |
| 5285 | + { |
| 5286 | + /* Store multiple */ |
| 5287 | + reglist16 |= 1 << ASM_REGNUM (REGNO (XEXP (vec_elm, 1))); |
| 5288 | + } |
| 5289 | + } |
| 5290 | + |
| 5291 | + avr32_make_reglist16 (reglist16, reglist16_string); |
| 5292 | + fputs (reglist16_string, stream); |
| 5293 | + |
| 5294 | + break; |
| 5295 | + } |
| 5296 | + |
| 5297 | + case PLUS: |
| 5298 | + { |
| 5299 | + rtx op0 = XEXP (x, 0); |
| 5300 | + rtx op1 = XEXP (x, 1); |
| 5301 | + rtx base = NULL_RTX, offset = NULL_RTX; |
| 5302 | + |
| 5303 | + if (avr32_address_register_rtx_p (op0, 1)) |
| 5304 | + { |
| 5305 | + base = op0; |
| 5306 | + offset = op1; |
| 5307 | + } |
| 5308 | + else if (avr32_address_register_rtx_p (op1, 1)) |
| 5309 | + { |
| 5310 | + /* Operands are switched. */ |
| 5311 | + base = op1; |
| 5312 | + offset = op0; |
| 5313 | + } |
| 5314 | + |
| 5315 | + gcc_assert (base && offset |
| 5316 | + && avr32_address_register_rtx_p (base, 1) |
| 5317 | + && avr32_legitimate_index_p (GET_MODE (x), offset, 1)); |
| 5318 | + |
| 5319 | + avr32_print_operand (stream, base, 0); |
| 5320 | + fputs ("[", stream); |
| 5321 | + avr32_print_operand (stream, offset, 0); |
| 5322 | + fputs ("]", stream); |
| 5323 | + break; |
| 5324 | + } |
| 5325 | + |
| 5326 | + default: |
| 5327 | + error = 1; |
| 5328 | + } |
| 5329 | + |
| 5330 | + if (error) |
| 5331 | + { |
| 5332 | + debug_rtx (x); |
| 5333 | + internal_error ("Illegal expression for avr32_print_operand"); |
| 5334 | + } |
| 5335 | +} |
| 5336 | + |
| 5337 | +rtx |
| 5338 | +avr32_get_note_reg_equiv (rtx insn) |
| 5339 | +{ |
| 5340 | + rtx note; |
| 5341 | + |
| 5342 | + note = find_reg_note (insn, REG_EQUIV, NULL_RTX); |
| 5343 | + |
| 5344 | + if (note != NULL_RTX) |
| 5345 | + return XEXP (note, 0); |
| 5346 | + else |
| 5347 | + return NULL_RTX; |
| 5348 | +} |
| 5349 | + |
| 5350 | + |
| 5351 | +/* |
| 5352 | + Outputs to stdio stream stream the assembler syntax for an instruction |
| 5353 | + operand that is a memory reference whose address is x. x is an RTL |
| 5354 | + expression. |
| 5355 | + |
| 5356 | + ToDo: fixme. |
| 5357 | +*/ |
| 5358 | +void |
| 5359 | +avr32_print_operand_address (FILE * stream, rtx x) |
| 5360 | +{ |
| 5361 | + fprintf (stream, "(%d) /* address */", REGNO (x)); |
| 5362 | +} |
| 5363 | + |
| 5364 | + |
| 5365 | +/* Return true if _GLOBAL_OFFSET_TABLE_ symbol is mentioned. */ |
| 5366 | +bool |
| 5367 | +avr32_got_mentioned_p (rtx addr) |
| 5368 | +{ |
| 5369 | + if (GET_CODE (addr) == MEM) |
| 5370 | + addr = XEXP (addr, 0); |
| 5371 | + while (GET_CODE (addr) == CONST) |
| 5372 | + addr = XEXP (addr, 0); |
| 5373 | + if (GET_CODE (addr) == SYMBOL_REF) |
| 5374 | + { |
| 5375 | + return streq (XSTR (addr, 0), "_GLOBAL_OFFSET_TABLE_"); |
| 5376 | + } |
| 5377 | + if (GET_CODE (addr) == PLUS || GET_CODE (addr) == MINUS) |
| 5378 | + { |
| 5379 | + bool l1, l2; |
| 5380 | + |
| 5381 | + l1 = avr32_got_mentioned_p (XEXP (addr, 0)); |
| 5382 | + l2 = avr32_got_mentioned_p (XEXP (addr, 1)); |
| 5383 | + return l1 || l2; |
| 5384 | + } |
| 5385 | + return false; |
| 5386 | +} |
| 5387 | + |
| 5388 | + |
| 5389 | +/* Find the symbol in an address expression. */ |
| 5390 | +rtx |
| 5391 | +avr32_find_symbol (rtx addr) |
| 5392 | +{ |
| 5393 | + if (GET_CODE (addr) == MEM) |
| 5394 | + addr = XEXP (addr, 0); |
| 5395 | + |
| 5396 | + while (GET_CODE (addr) == CONST) |
| 5397 | + addr = XEXP (addr, 0); |
| 5398 | + |
| 5399 | + if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF) |
| 5400 | + return addr; |
| 5401 | + if (GET_CODE (addr) == PLUS) |
| 5402 | + { |
| 5403 | + rtx l1, l2; |
| 5404 | + |
| 5405 | + l1 = avr32_find_symbol (XEXP (addr, 0)); |
| 5406 | + l2 = avr32_find_symbol (XEXP (addr, 1)); |
| 5407 | + if (l1 != NULL_RTX && l2 == NULL_RTX) |
| 5408 | + return l1; |
| 5409 | + else if (l1 == NULL_RTX && l2 != NULL_RTX) |
| 5410 | + return l2; |
| 5411 | + } |
| 5412 | + |
| 5413 | + return NULL_RTX; |
| 5414 | +} |
| 5415 | + |
| 5416 | + |
| 5417 | +/* Routines for manipulation of the constant pool. */ |
| 5418 | + |
| 5419 | +/* AVR32 instructions cannot load a large constant directly into a |
| 5420 | + register; they have to come from a pc relative load. The constant |
| 5421 | + must therefore be placed in the addressable range of the pc |
| 5422 | + relative load. Depending on the precise pc relative load |
| 5423 | + instruction the range is somewhere between 256 bytes and 4k. This |
| 5424 | + means that we often have to dump a constant inside a function, and |
| 5425 | + generate code to branch around it. |
| 5426 | + |
| 5427 | + It is important to minimize this, since the branches will slow |
| 5428 | + things down and make the code larger. |
| 5429 | + |
| 5430 | + Normally we can hide the table after an existing unconditional |
| 5431 | + branch so that there is no interruption of the flow, but in the |
| 5432 | + worst case the code looks like this: |
| 5433 | + |
| 5434 | + lddpc rn, L1 |
| 5435 | + ... |
| 5436 | + rjmp L2 |
| 5437 | + align |
| 5438 | + L1: .long value |
| 5439 | + L2: |
| 5440 | + ... |
| 5441 | + |
| 5442 | + lddpc rn, L3 |
| 5443 | + ... |
| 5444 | + rjmp L4 |
| 5445 | + align |
| 5446 | + L3: .long value |
| 5447 | + L4: |
| 5448 | + ... |
| 5449 | + |
| 5450 | + We fix this by performing a scan after scheduling, which notices |
| 5451 | + which instructions need to have their operands fetched from the |
| 5452 | + constant table and builds the table. |
| 5453 | + |
| 5454 | + The algorithm starts by building a table of all the constants that |
| 5455 | + need fixing up and all the natural barriers in the function (places |
| 5456 | + where a constant table can be dropped without breaking the flow). |
| 5457 | + For each fixup we note how far the pc-relative replacement will be |
| 5458 | + able to reach and the offset of the instruction into the function. |
| 5459 | + |
| 5460 | + Having built the table we then group the fixes together to form |
| 5461 | + tables that are as large as possible (subject to addressing |
| 5462 | + constraints) and emit each table of constants after the last |
| 5463 | + barrier that is within range of all the instructions in the group. |
| 5464 | + If a group does not contain a barrier, then we forcibly create one |
| 5465 | + by inserting a jump instruction into the flow. Once the table has |
| 5466 | + been inserted, the insns are then modified to reference the |
| 5467 | + relevant entry in the pool. |
| 5468 | + |
| 5469 | + Possible enhancements to the algorithm (not implemented) are: |
| 5470 | + |
| 5471 | + 1) For some processors and object formats, there may be benefit in |
| 5472 | + aligning the pools to the start of cache lines; this alignment |
| 5473 | + would need to be taken into account when calculating addressability |
| 5474 | + of a pool. */ |
| 5475 | + |
| 5476 | +/* These typedefs are located at the start of this file, so that |
| 5477 | + they can be used in the prototypes there. This comment is to |
| 5478 | + remind readers of that fact so that the following structures |
| 5479 | + can be understood more easily. |
| 5480 | + |
| 5481 | + typedef struct minipool_node Mnode; |
| 5482 | + typedef struct minipool_fixup Mfix; */ |
| 5483 | + |
| 5484 | +struct minipool_node |
| 5485 | +{ |
| 5486 | + /* Doubly linked chain of entries. */ |
| 5487 | + Mnode *next; |
| 5488 | + Mnode *prev; |
| 5489 | + /* The maximum offset into the code that this entry can be placed. While |
| 5490 | + pushing fixes for forward references, all entries are sorted in order of |
| 5491 | + increasing max_address. */ |
| 5492 | + HOST_WIDE_INT max_address; |
| 5493 | + /* Similarly for an entry inserted for a backwards ref. */ |
| 5494 | + HOST_WIDE_INT min_address; |
| 5495 | + /* The number of fixes referencing this entry. This can become zero if we |
| 5496 | + "unpush" an entry. In this case we ignore the entry when we come to |
| 5497 | + emit the code. */ |
| 5498 | + int refcount; |
| 5499 | + /* The offset from the start of the minipool. */ |
| 5500 | + HOST_WIDE_INT offset; |
| 5501 | + /* The value in table. */ |
| 5502 | + rtx value; |
| 5503 | + /* The mode of value. */ |
| 5504 | + enum machine_mode mode; |
| 5505 | + /* The size of the value. */ |
| 5506 | + int fix_size; |
| 5507 | +}; |
| 5508 | + |
| 5509 | + |
| 5510 | +struct minipool_fixup |
| 5511 | +{ |
| 5512 | + Mfix *next; |
| 5513 | + rtx insn; |
| 5514 | + HOST_WIDE_INT address; |
| 5515 | + rtx *loc; |
| 5516 | + enum machine_mode mode; |
| 5517 | + int fix_size; |
| 5518 | + rtx value; |
| 5519 | + Mnode *minipool; |
| 5520 | + HOST_WIDE_INT forwards; |
| 5521 | + HOST_WIDE_INT backwards; |
| 5522 | +}; |
| 5523 | + |
| 5524 | + |
| 5525 | +/* Fixes less than a word need padding out to a word boundary. */ |
| 5526 | +#define MINIPOOL_FIX_SIZE(mode, value) \ |
| 5527 | + (IS_FORCE_MINIPOOL(value) ? 0 : \ |
| 5528 | + (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)) |
| 5529 | + |
| 5530 | +#define IS_FORCE_MINIPOOL(x) \ |
| 5531 | + (GET_CODE(x) == UNSPEC && \ |
| 5532 | + XINT(x, 1) == UNSPEC_FORCE_MINIPOOL) |
| 5533 | + |
| 5534 | +static Mnode *minipool_vector_head; |
| 5535 | +static Mnode *minipool_vector_tail; |
| 5536 | + |
| 5537 | +/* The linked list of all minipool fixes required for this function. */ |
| 5538 | +Mfix *minipool_fix_head; |
| 5539 | +Mfix *minipool_fix_tail; |
| 5540 | +/* The fix entry for the current minipool, once it has been placed. */ |
| 5541 | +Mfix *minipool_barrier; |
| 5542 | + |
| 5543 | + |
| 5544 | +/* Determines if INSN is the start of a jump table. Returns the end |
| 5545 | + of the TABLE or NULL_RTX. */ |
| 5546 | +static rtx |
| 5547 | +is_jump_table (rtx insn) |
| 5548 | +{ |
| 5549 | + rtx table; |
| 5550 | + |
| 5551 | + if (GET_CODE (insn) == JUMP_INSN |
| 5552 | + && JUMP_LABEL (insn) != NULL |
| 5553 | + && ((table = next_real_insn (JUMP_LABEL (insn))) |
| 5554 | + == next_real_insn (insn)) |
| 5555 | + && table != NULL |
| 5556 | + && GET_CODE (table) == JUMP_INSN |
| 5557 | + && (GET_CODE (PATTERN (table)) == ADDR_VEC |
| 5558 | + || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC)) |
| 5559 | + return table; |
| 5560 | + |
| 5561 | + return NULL_RTX; |
| 5562 | +} |
| 5563 | + |
| 5564 | + |
| 5565 | +static HOST_WIDE_INT |
| 5566 | +get_jump_table_size (rtx insn) |
| 5567 | +{ |
| 5568 | + /* ADDR_VECs only take room if read-only data does into the text section. */ |
| 5569 | + if (JUMP_TABLES_IN_TEXT_SECTION |
| 5570 | +#if !defined(READONLY_DATA_SECTION_ASM_OP) |
| 5571 | + || 1 |
| 5572 | +#endif |
| 5573 | + ) |
| 5574 | + { |
| 5575 | + rtx body = PATTERN (insn); |
| 5576 | + int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0; |
| 5577 | + |
| 5578 | + return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt); |
| 5579 | + } |
| 5580 | + |
| 5581 | + return 0; |
| 5582 | +} |
| 5583 | + |
| 5584 | + |
| 5585 | +/* Move a minipool fix MP from its current location to before MAX_MP. |
| 5586 | + If MAX_MP is NULL, then MP doesn't need moving, but the addressing |
| 5587 | + constraints may need updating. */ |
| 5588 | +static Mnode * |
| 5589 | +move_minipool_fix_forward_ref (Mnode * mp, Mnode * max_mp, |
| 5590 | + HOST_WIDE_INT max_address) |
| 5591 | +{ |
| 5592 | + /* This should never be true and the code below assumes these are |
| 5593 | + different. */ |
| 5594 | + if (mp == max_mp) |
| 5595 | + abort (); |
| 5596 | + |
| 5597 | + if (max_mp == NULL) |
| 5598 | + { |
| 5599 | + if (max_address < mp->max_address) |
| 5600 | + mp->max_address = max_address; |
| 5601 | + } |
| 5602 | + else |
| 5603 | + { |
| 5604 | + if (max_address > max_mp->max_address - mp->fix_size) |
| 5605 | + mp->max_address = max_mp->max_address - mp->fix_size; |
| 5606 | + else |
| 5607 | + mp->max_address = max_address; |
| 5608 | + |
| 5609 | + /* Unlink MP from its current position. Since max_mp is non-null, |
| 5610 | + mp->prev must be non-null. */ |
| 5611 | + mp->prev->next = mp->next; |
| 5612 | + if (mp->next != NULL) |
| 5613 | + mp->next->prev = mp->prev; |
| 5614 | + else |
| 5615 | + minipool_vector_tail = mp->prev; |
| 5616 | + |
| 5617 | + /* Re-insert it before MAX_MP. */ |
| 5618 | + mp->next = max_mp; |
| 5619 | + mp->prev = max_mp->prev; |
| 5620 | + max_mp->prev = mp; |
| 5621 | + |
| 5622 | + if (mp->prev != NULL) |
| 5623 | + mp->prev->next = mp; |
| 5624 | + else |
| 5625 | + minipool_vector_head = mp; |
| 5626 | + } |
| 5627 | + |
| 5628 | + /* Save the new entry. */ |
| 5629 | + max_mp = mp; |
| 5630 | + |
| 5631 | + /* Scan over the preceding entries and adjust their addresses as required. |
| 5632 | + */ |
| 5633 | + while (mp->prev != NULL |
| 5634 | + && mp->prev->max_address > mp->max_address - mp->prev->fix_size) |
| 5635 | + { |
| 5636 | + mp->prev->max_address = mp->max_address - mp->prev->fix_size; |
| 5637 | + mp = mp->prev; |
| 5638 | + } |
| 5639 | + |
| 5640 | + return max_mp; |
| 5641 | +} |
| 5642 | + |
| 5643 | + |
| 5644 | +/* Add a constant to the minipool for a forward reference. Returns the |
| 5645 | + node added or NULL if the constant will not fit in this pool. */ |
| 5646 | +static Mnode * |
| 5647 | +add_minipool_forward_ref (Mfix * fix) |
| 5648 | +{ |
| 5649 | + /* If set, max_mp is the first pool_entry that has a lower constraint than |
| 5650 | + the one we are trying to add. */ |
| 5651 | + Mnode *max_mp = NULL; |
| 5652 | + HOST_WIDE_INT max_address = fix->address + fix->forwards; |
| 5653 | + Mnode *mp; |
| 5654 | + |
| 5655 | + /* If this fix's address is greater than the address of the first entry, |
| 5656 | + then we can't put the fix in this pool. We subtract the size of the |
| 5657 | + current fix to ensure that if the table is fully packed we still have |
| 5658 | + enough room to insert this value by suffling the other fixes forwards. */ |
| 5659 | + if (minipool_vector_head && |
| 5660 | + fix->address >= minipool_vector_head->max_address - fix->fix_size) |
| 5661 | + return NULL; |
| 5662 | + |
| 5663 | + /* Scan the pool to see if a constant with the same value has already been |
| 5664 | + added. While we are doing this, also note the location where we must |
| 5665 | + insert the constant if it doesn't already exist. */ |
| 5666 | + for (mp = minipool_vector_head; mp != NULL; mp = mp->next) |
| 5667 | + { |
| 5668 | + if (GET_CODE (fix->value) == GET_CODE (mp->value) |
| 5669 | + && fix->mode == mp->mode |
| 5670 | + && (GET_CODE (fix->value) != CODE_LABEL |
| 5671 | + || (CODE_LABEL_NUMBER (fix->value) |
| 5672 | + == CODE_LABEL_NUMBER (mp->value))) |
| 5673 | + && rtx_equal_p (fix->value, mp->value)) |
| 5674 | + { |
| 5675 | + /* More than one fix references this entry. */ |
| 5676 | + mp->refcount++; |
| 5677 | + return move_minipool_fix_forward_ref (mp, max_mp, max_address); |
| 5678 | + } |
| 5679 | + |
| 5680 | + /* Note the insertion point if necessary. */ |
| 5681 | + if (max_mp == NULL && mp->max_address > max_address) |
| 5682 | + max_mp = mp; |
| 5683 | + |
| 5684 | + } |
| 5685 | + |
| 5686 | + /* The value is not currently in the minipool, so we need to create a new |
| 5687 | + entry for it. If MAX_MP is NULL, the entry will be put on the end of |
| 5688 | + the list since the placement is less constrained than any existing |
| 5689 | + entry. Otherwise, we insert the new fix before MAX_MP and, if |
| 5690 | + necessary, adjust the constraints on the other entries. */ |
| 5691 | + mp = xmalloc (sizeof (*mp)); |
| 5692 | + mp->fix_size = fix->fix_size; |
| 5693 | + mp->mode = fix->mode; |
| 5694 | + mp->value = fix->value; |
| 5695 | + mp->refcount = 1; |
| 5696 | + /* Not yet required for a backwards ref. */ |
| 5697 | + mp->min_address = -65536; |
| 5698 | + |
| 5699 | + if (max_mp == NULL) |
| 5700 | + { |
| 5701 | + mp->max_address = max_address; |
| 5702 | + mp->next = NULL; |
| 5703 | + mp->prev = minipool_vector_tail; |
| 5704 | + |
| 5705 | + if (mp->prev == NULL) |
| 5706 | + { |
| 5707 | + minipool_vector_head = mp; |
| 5708 | + minipool_vector_label = gen_label_rtx (); |
| 5709 | + } |
| 5710 | + else |
| 5711 | + mp->prev->next = mp; |
| 5712 | + |
| 5713 | + minipool_vector_tail = mp; |
| 5714 | + } |
| 5715 | + else |
| 5716 | + { |
| 5717 | + if (max_address > max_mp->max_address - mp->fix_size) |
| 5718 | + mp->max_address = max_mp->max_address - mp->fix_size; |
| 5719 | + else |
| 5720 | + mp->max_address = max_address; |
| 5721 | + |
| 5722 | + mp->next = max_mp; |
| 5723 | + mp->prev = max_mp->prev; |
| 5724 | + max_mp->prev = mp; |
| 5725 | + if (mp->prev != NULL) |
| 5726 | + mp->prev->next = mp; |
| 5727 | + else |
| 5728 | + minipool_vector_head = mp; |
| 5729 | + } |
| 5730 | + |
| 5731 | + /* Save the new entry. */ |
| 5732 | + max_mp = mp; |
| 5733 | + |
| 5734 | + /* Scan over the preceding entries and adjust their addresses as required. |
| 5735 | + */ |
| 5736 | + while (mp->prev != NULL |
| 5737 | + && mp->prev->max_address > mp->max_address - mp->prev->fix_size) |
| 5738 | + { |
| 5739 | + mp->prev->max_address = mp->max_address - mp->prev->fix_size; |
| 5740 | + mp = mp->prev; |
| 5741 | + } |
| 5742 | + |
| 5743 | + return max_mp; |
| 5744 | +} |
| 5745 | + |
| 5746 | + |
| 5747 | +static Mnode * |
| 5748 | +move_minipool_fix_backward_ref (Mnode * mp, Mnode * min_mp, |
| 5749 | + HOST_WIDE_INT min_address) |
| 5750 | +{ |
| 5751 | + HOST_WIDE_INT offset; |
| 5752 | + |
| 5753 | + /* This should never be true, and the code below assumes these are |
| 5754 | + different. */ |
| 5755 | + if (mp == min_mp) |
| 5756 | + abort (); |
| 5757 | + |
| 5758 | + if (min_mp == NULL) |
| 5759 | + { |
| 5760 | + if (min_address > mp->min_address) |
| 5761 | + mp->min_address = min_address; |
| 5762 | + } |
| 5763 | + else |
| 5764 | + { |
| 5765 | + /* We will adjust this below if it is too loose. */ |
| 5766 | + mp->min_address = min_address; |
| 5767 | + |
| 5768 | + /* Unlink MP from its current position. Since min_mp is non-null, |
| 5769 | + mp->next must be non-null. */ |
| 5770 | + mp->next->prev = mp->prev; |
| 5771 | + if (mp->prev != NULL) |
| 5772 | + mp->prev->next = mp->next; |
| 5773 | + else |
| 5774 | + minipool_vector_head = mp->next; |
| 5775 | + |
| 5776 | + /* Reinsert it after MIN_MP. */ |
| 5777 | + mp->prev = min_mp; |
| 5778 | + mp->next = min_mp->next; |
| 5779 | + min_mp->next = mp; |
| 5780 | + if (mp->next != NULL) |
| 5781 | + mp->next->prev = mp; |
| 5782 | + else |
| 5783 | + minipool_vector_tail = mp; |
| 5784 | + } |
| 5785 | + |
| 5786 | + min_mp = mp; |
| 5787 | + |
| 5788 | + offset = 0; |
| 5789 | + for (mp = minipool_vector_head; mp != NULL; mp = mp->next) |
| 5790 | + { |
| 5791 | + mp->offset = offset; |
| 5792 | + if (mp->refcount > 0) |
| 5793 | + offset += mp->fix_size; |
| 5794 | + |
| 5795 | + if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size) |
| 5796 | + mp->next->min_address = mp->min_address + mp->fix_size; |
| 5797 | + } |
| 5798 | + |
| 5799 | + return min_mp; |
| 5800 | +} |
| 5801 | + |
| 5802 | + |
| 5803 | +/* Add a constant to the minipool for a backward reference. Returns the |
| 5804 | + node added or NULL if the constant will not fit in this pool. |
| 5805 | + |
| 5806 | + Note that the code for insertion for a backwards reference can be |
| 5807 | + somewhat confusing because the calculated offsets for each fix do |
| 5808 | + not take into account the size of the pool (which is still under |
| 5809 | + construction. */ |
| 5810 | +static Mnode * |
| 5811 | +add_minipool_backward_ref (Mfix * fix) |
| 5812 | +{ |
| 5813 | + /* If set, min_mp is the last pool_entry that has a lower constraint than |
| 5814 | + the one we are trying to add. */ |
| 5815 | + Mnode *min_mp = NULL; |
| 5816 | + /* This can be negative, since it is only a constraint. */ |
| 5817 | + HOST_WIDE_INT min_address = fix->address - fix->backwards; |
| 5818 | + Mnode *mp; |
| 5819 | + |
| 5820 | + /* If we can't reach the current pool from this insn, or if we can't insert |
| 5821 | + this entry at the end of the pool without pushing other fixes out of |
| 5822 | + range, then we don't try. This ensures that we can't fail later on. */ |
| 5823 | + if (min_address >= minipool_barrier->address |
| 5824 | + || (minipool_vector_tail->min_address + fix->fix_size |
| 5825 | + >= minipool_barrier->address)) |
| 5826 | + return NULL; |
| 5827 | + |
| 5828 | + /* Scan the pool to see if a constant with the same value has already been |
| 5829 | + added. While we are doing this, also note the location where we must |
| 5830 | + insert the constant if it doesn't already exist. */ |
| 5831 | + for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev) |
| 5832 | + { |
| 5833 | + if (GET_CODE (fix->value) == GET_CODE (mp->value) |
| 5834 | + && fix->mode == mp->mode |
| 5835 | + && (GET_CODE (fix->value) != CODE_LABEL |
| 5836 | + || (CODE_LABEL_NUMBER (fix->value) |
| 5837 | + == CODE_LABEL_NUMBER (mp->value))) |
| 5838 | + && rtx_equal_p (fix->value, mp->value) |
| 5839 | + /* Check that there is enough slack to move this entry to the end |
| 5840 | + of the table (this is conservative). */ |
| 5841 | + && (mp->max_address |
| 5842 | + > (minipool_barrier->address |
| 5843 | + + minipool_vector_tail->offset |
| 5844 | + + minipool_vector_tail->fix_size))) |
| 5845 | + { |
| 5846 | + mp->refcount++; |
| 5847 | + return move_minipool_fix_backward_ref (mp, min_mp, min_address); |
| 5848 | + } |
| 5849 | + |
| 5850 | + if (min_mp != NULL) |
| 5851 | + mp->min_address += fix->fix_size; |
| 5852 | + else |
| 5853 | + { |
| 5854 | + /* Note the insertion point if necessary. */ |
| 5855 | + if (mp->min_address < min_address) |
| 5856 | + { |
| 5857 | + min_mp = mp; |
| 5858 | + } |
| 5859 | + else if (mp->max_address |
| 5860 | + < minipool_barrier->address + mp->offset + fix->fix_size) |
| 5861 | + { |
| 5862 | + /* Inserting before this entry would push the fix beyond its |
| 5863 | + maximum address (which can happen if we have re-located a |
| 5864 | + forwards fix); force the new fix to come after it. */ |
| 5865 | + min_mp = mp; |
| 5866 | + min_address = mp->min_address + fix->fix_size; |
| 5867 | + } |
| 5868 | + } |
| 5869 | + } |
| 5870 | + |
| 5871 | + /* We need to create a new entry. */ |
| 5872 | + mp = xmalloc (sizeof (*mp)); |
| 5873 | + mp->fix_size = fix->fix_size; |
| 5874 | + mp->mode = fix->mode; |
| 5875 | + mp->value = fix->value; |
| 5876 | + mp->refcount = 1; |
| 5877 | + mp->max_address = minipool_barrier->address + 65536; |
| 5878 | + |
| 5879 | + mp->min_address = min_address; |
| 5880 | + |
| 5881 | + if (min_mp == NULL) |
| 5882 | + { |
| 5883 | + mp->prev = NULL; |
| 5884 | + mp->next = minipool_vector_head; |
| 5885 | + |
| 5886 | + if (mp->next == NULL) |
| 5887 | + { |
| 5888 | + minipool_vector_tail = mp; |
| 5889 | + minipool_vector_label = gen_label_rtx (); |
| 5890 | + } |
| 5891 | + else |
| 5892 | + mp->next->prev = mp; |
| 5893 | + |
| 5894 | + minipool_vector_head = mp; |
| 5895 | + } |
| 5896 | + else |
| 5897 | + { |
| 5898 | + mp->next = min_mp->next; |
| 5899 | + mp->prev = min_mp; |
| 5900 | + min_mp->next = mp; |
| 5901 | + |
| 5902 | + if (mp->next != NULL) |
| 5903 | + mp->next->prev = mp; |
| 5904 | + else |
| 5905 | + minipool_vector_tail = mp; |
| 5906 | + } |
| 5907 | + |
| 5908 | + /* Save the new entry. */ |
| 5909 | + min_mp = mp; |
| 5910 | + |
| 5911 | + if (mp->prev) |
| 5912 | + mp = mp->prev; |
| 5913 | + else |
| 5914 | + mp->offset = 0; |
| 5915 | + |
| 5916 | + /* Scan over the following entries and adjust their offsets. */ |
| 5917 | + while (mp->next != NULL) |
| 5918 | + { |
| 5919 | + if (mp->next->min_address < mp->min_address + mp->fix_size) |
| 5920 | + mp->next->min_address = mp->min_address + mp->fix_size; |
| 5921 | + |
| 5922 | + if (mp->refcount) |
| 5923 | + mp->next->offset = mp->offset + mp->fix_size; |
| 5924 | + else |
| 5925 | + mp->next->offset = mp->offset; |
| 5926 | + |
| 5927 | + mp = mp->next; |
| 5928 | + } |
| 5929 | + |
| 5930 | + return min_mp; |
| 5931 | +} |
| 5932 | + |
| 5933 | + |
| 5934 | +static void |
| 5935 | +assign_minipool_offsets (Mfix * barrier) |
| 5936 | +{ |
| 5937 | + HOST_WIDE_INT offset = 0; |
| 5938 | + Mnode *mp; |
| 5939 | + |
| 5940 | + minipool_barrier = barrier; |
| 5941 | + |
| 5942 | + for (mp = minipool_vector_head; mp != NULL; mp = mp->next) |
| 5943 | + { |
| 5944 | + mp->offset = offset; |
| 5945 | + |
| 5946 | + if (mp->refcount > 0) |
| 5947 | + offset += mp->fix_size; |
| 5948 | + } |
| 5949 | +} |
| 5950 | + |
| 5951 | + |
| 5952 | +/* Print a symbolic form of X to the debug file, F. */ |
| 5953 | +static void |
| 5954 | +avr32_print_value (FILE * f, rtx x) |
| 5955 | +{ |
| 5956 | + switch (GET_CODE (x)) |
| 5957 | + { |
| 5958 | + case CONST_INT: |
| 5959 | + fprintf (f, "0x%x", (int) INTVAL (x)); |
| 5960 | + return; |
| 5961 | + |
| 5962 | + case CONST_DOUBLE: |
| 5963 | + fprintf (f, "<0x%lx,0x%lx>", (long) XWINT (x, 2), (long) XWINT (x, 3)); |
| 5964 | + return; |
| 5965 | + |
| 5966 | + case CONST_VECTOR: |
| 5967 | + { |
| 5968 | + int i; |
| 5969 | + |
| 5970 | + fprintf (f, "<"); |
| 5971 | + for (i = 0; i < CONST_VECTOR_NUNITS (x); i++) |
| 5972 | + { |
| 5973 | + fprintf (f, "0x%x", (int) INTVAL (CONST_VECTOR_ELT (x, i))); |
| 5974 | + if (i < (CONST_VECTOR_NUNITS (x) - 1)) |
| 5975 | + fputc (',', f); |
| 5976 | + } |
| 5977 | + fprintf (f, ">"); |
| 5978 | + } |
| 5979 | + return; |
| 5980 | + |
| 5981 | + case CONST_STRING: |
| 5982 | + fprintf (f, "\"%s\"", XSTR (x, 0)); |
| 5983 | + return; |
| 5984 | + |
| 5985 | + case SYMBOL_REF: |
| 5986 | + fprintf (f, "`%s'", XSTR (x, 0)); |
| 5987 | + return; |
| 5988 | + |
| 5989 | + case LABEL_REF: |
| 5990 | + fprintf (f, "L%d", INSN_UID (XEXP (x, 0))); |
| 5991 | + return; |
| 5992 | + |
| 5993 | + case CONST: |
| 5994 | + avr32_print_value (f, XEXP (x, 0)); |
| 5995 | + return; |
| 5996 | + |
| 5997 | + case PLUS: |
| 5998 | + avr32_print_value (f, XEXP (x, 0)); |
| 5999 | + fprintf (f, "+"); |
| 6000 | + avr32_print_value (f, XEXP (x, 1)); |
| 6001 | + return; |
| 6002 | + |
| 6003 | + case PC: |
| 6004 | + fprintf (f, "pc"); |
| 6005 | + return; |
| 6006 | + |
| 6007 | + default: |
| 6008 | + fprintf (f, "????"); |
| 6009 | + return; |
| 6010 | + } |
| 6011 | +} |
| 6012 | + |
| 6013 | + |
| 6014 | +int |
| 6015 | +is_minipool_label (rtx label) |
| 6016 | +{ |
| 6017 | + minipool_labels *cur_mp_label = cfun->machine->minipool_label_head; |
| 6018 | + |
| 6019 | + if (GET_CODE (label) != CODE_LABEL) |
| 6020 | + return FALSE; |
| 6021 | + |
| 6022 | + while (cur_mp_label) |
| 6023 | + { |
| 6024 | + if (CODE_LABEL_NUMBER (label) |
| 6025 | + == CODE_LABEL_NUMBER (cur_mp_label->label)) |
| 6026 | + return TRUE; |
| 6027 | + cur_mp_label = cur_mp_label->next; |
| 6028 | + } |
| 6029 | + return FALSE; |
| 6030 | +} |
| 6031 | + |
| 6032 | + |
| 6033 | +static void |
| 6034 | +new_minipool_label (rtx label) |
| 6035 | +{ |
| 6036 | + if (!cfun->machine->minipool_label_head) |
| 6037 | + { |
| 6038 | + cfun->machine->minipool_label_head = |
| 6039 | + ggc_alloc (sizeof (minipool_labels)); |
| 6040 | + cfun->machine->minipool_label_tail = cfun->machine->minipool_label_head; |
| 6041 | + cfun->machine->minipool_label_head->label = label; |
| 6042 | + cfun->machine->minipool_label_head->next = 0; |
| 6043 | + cfun->machine->minipool_label_head->prev = 0; |
| 6044 | + } |
| 6045 | + else |
| 6046 | + { |
| 6047 | + cfun->machine->minipool_label_tail->next = |
| 6048 | + ggc_alloc (sizeof (minipool_labels)); |
| 6049 | + cfun->machine->minipool_label_tail->next->label = label; |
| 6050 | + cfun->machine->minipool_label_tail->next->next = 0; |
| 6051 | + cfun->machine->minipool_label_tail->next->prev = |
| 6052 | + cfun->machine->minipool_label_tail; |
| 6053 | + cfun->machine->minipool_label_tail = |
| 6054 | + cfun->machine->minipool_label_tail->next; |
| 6055 | + } |
| 6056 | +} |
| 6057 | + |
| 6058 | + |
| 6059 | +/* Output the literal table */ |
| 6060 | +static void |
| 6061 | +dump_minipool (rtx scan) |
| 6062 | +{ |
| 6063 | + Mnode *mp; |
| 6064 | + Mnode *nmp; |
| 6065 | + |
| 6066 | + if (dump_file) |
| 6067 | + fprintf (dump_file, |
| 6068 | + ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n", |
| 6069 | + INSN_UID (scan), (unsigned long) minipool_barrier->address, 4); |
| 6070 | + |
| 6071 | + scan = emit_insn_after (gen_consttable_start (), scan); |
| 6072 | + scan = emit_insn_after (gen_align_4 (), scan); |
| 6073 | + scan = emit_label_after (minipool_vector_label, scan); |
| 6074 | + new_minipool_label (minipool_vector_label); |
| 6075 | + |
| 6076 | + for (mp = minipool_vector_head; mp != NULL; mp = nmp) |
| 6077 | + { |
| 6078 | + if (mp->refcount > 0) |
| 6079 | + { |
| 6080 | + if (dump_file) |
| 6081 | + { |
| 6082 | + fprintf (dump_file, |
| 6083 | + ";; Offset %u, min %ld, max %ld ", |
| 6084 | + (unsigned) mp->offset, (unsigned long) mp->min_address, |
| 6085 | + (unsigned long) mp->max_address); |
| 6086 | + avr32_print_value (dump_file, mp->value); |
| 6087 | + fputc ('\n', dump_file); |
| 6088 | + } |
| 6089 | + |
| 6090 | + switch (mp->fix_size) |
| 6091 | + { |
| 6092 | +#ifdef HAVE_consttable_4 |
| 6093 | + case 4: |
| 6094 | + scan = emit_insn_after (gen_consttable_4 (mp->value), scan); |
| 6095 | + break; |
| 6096 | + |
| 6097 | +#endif |
| 6098 | +#ifdef HAVE_consttable_8 |
| 6099 | + case 8: |
| 6100 | + scan = emit_insn_after (gen_consttable_8 (mp->value), scan); |
| 6101 | + break; |
| 6102 | + |
| 6103 | +#endif |
| 6104 | +#ifdef HAVE_consttable_16 |
| 6105 | + case 16: |
| 6106 | + scan = emit_insn_after (gen_consttable_16 (mp->value), scan); |
| 6107 | + break; |
| 6108 | + |
| 6109 | +#endif |
| 6110 | + case 0: |
| 6111 | + /* This can happen for force-minipool entries which just are |
| 6112 | + there to force the minipool to be generate. */ |
| 6113 | + break; |
| 6114 | + default: |
| 6115 | + abort (); |
| 6116 | + break; |
| 6117 | + } |
| 6118 | + } |
| 6119 | + |
| 6120 | + nmp = mp->next; |
| 6121 | + free (mp); |
| 6122 | + } |
| 6123 | + |
| 6124 | + minipool_vector_head = minipool_vector_tail = NULL; |
| 6125 | + scan = emit_insn_after (gen_consttable_end (), scan); |
| 6126 | + scan = emit_barrier_after (scan); |
| 6127 | +} |
| 6128 | + |
| 6129 | + |
| 6130 | +/* Return the cost of forcibly inserting a barrier after INSN. */ |
| 6131 | +static int |
| 6132 | +avr32_barrier_cost (rtx insn) |
| 6133 | +{ |
| 6134 | + /* Basing the location of the pool on the loop depth is preferable, but at |
| 6135 | + the moment, the basic block information seems to be corrupt by this |
| 6136 | + stage of the compilation. */ |
| 6137 | + int base_cost = 50; |
| 6138 | + rtx next = next_nonnote_insn (insn); |
| 6139 | + |
| 6140 | + if (next != NULL && GET_CODE (next) == CODE_LABEL) |
| 6141 | + base_cost -= 20; |
| 6142 | + |
| 6143 | + switch (GET_CODE (insn)) |
| 6144 | + { |
| 6145 | + case CODE_LABEL: |
| 6146 | + /* It will always be better to place the table before the label, rather |
| 6147 | + than after it. */ |
| 6148 | + return 50; |
| 6149 | + |
| 6150 | + case INSN: |
| 6151 | + case CALL_INSN: |
| 6152 | + return base_cost; |
| 6153 | + |
| 6154 | + case JUMP_INSN: |
| 6155 | + return base_cost - 10; |
| 6156 | + |
| 6157 | + default: |
| 6158 | + return base_cost + 10; |
| 6159 | + } |
| 6160 | +} |
| 6161 | + |
| 6162 | + |
| 6163 | +/* Find the best place in the insn stream in the range |
| 6164 | + (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier. |
| 6165 | + Create the barrier by inserting a jump and add a new fix entry for |
| 6166 | + it. */ |
| 6167 | +static Mfix * |
| 6168 | +create_fix_barrier (Mfix * fix, HOST_WIDE_INT max_address) |
| 6169 | +{ |
| 6170 | + HOST_WIDE_INT count = 0; |
| 6171 | + rtx barrier; |
| 6172 | + rtx from = fix->insn; |
| 6173 | + rtx selected = from; |
| 6174 | + int selected_cost; |
| 6175 | + HOST_WIDE_INT selected_address; |
| 6176 | + Mfix *new_fix; |
| 6177 | + HOST_WIDE_INT max_count = max_address - fix->address; |
| 6178 | + rtx label = gen_label_rtx (); |
| 6179 | + |
| 6180 | + selected_cost = avr32_barrier_cost (from); |
| 6181 | + selected_address = fix->address; |
| 6182 | + |
| 6183 | + while (from && count < max_count) |
| 6184 | + { |
| 6185 | + rtx tmp; |
| 6186 | + int new_cost; |
| 6187 | + |
| 6188 | + /* This code shouldn't have been called if there was a natural barrier |
| 6189 | + within range. */ |
| 6190 | + if (GET_CODE (from) == BARRIER) |
| 6191 | + abort (); |
| 6192 | + |
| 6193 | + /* Count the length of this insn. */ |
| 6194 | + count += get_attr_length (from); |
| 6195 | + |
| 6196 | + /* If there is a jump table, add its length. */ |
| 6197 | + tmp = is_jump_table (from); |
| 6198 | + if (tmp != NULL) |
| 6199 | + { |
| 6200 | + count += get_jump_table_size (tmp); |
| 6201 | + |
| 6202 | + /* Jump tables aren't in a basic block, so base the cost on the |
| 6203 | + dispatch insn. If we select this location, we will still put |
| 6204 | + the pool after the table. */ |
| 6205 | + new_cost = avr32_barrier_cost (from); |
| 6206 | + |
| 6207 | + if (count < max_count && new_cost <= selected_cost) |
| 6208 | + { |
| 6209 | + selected = tmp; |
| 6210 | + selected_cost = new_cost; |
| 6211 | + selected_address = fix->address + count; |
| 6212 | + } |
| 6213 | + |
| 6214 | + /* Continue after the dispatch table. */ |
| 6215 | + from = NEXT_INSN (tmp); |
| 6216 | + continue; |
| 6217 | + } |
| 6218 | + |
| 6219 | + new_cost = avr32_barrier_cost (from); |
| 6220 | + |
| 6221 | + if (count < max_count && new_cost <= selected_cost) |
| 6222 | + { |
| 6223 | + selected = from; |
| 6224 | + selected_cost = new_cost; |
| 6225 | + selected_address = fix->address + count; |
| 6226 | + } |
| 6227 | + |
| 6228 | + from = NEXT_INSN (from); |
| 6229 | + } |
| 6230 | + |
| 6231 | + /* Create a new JUMP_INSN that branches around a barrier. */ |
| 6232 | + from = emit_jump_insn_after (gen_jump (label), selected); |
| 6233 | + JUMP_LABEL (from) = label; |
| 6234 | + barrier = emit_barrier_after (from); |
| 6235 | + emit_label_after (label, barrier); |
| 6236 | + |
| 6237 | + /* Create a minipool barrier entry for the new barrier. */ |
| 6238 | + new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*new_fix)); |
| 6239 | + new_fix->insn = barrier; |
| 6240 | + new_fix->address = selected_address; |
| 6241 | + new_fix->next = fix->next; |
| 6242 | + fix->next = new_fix; |
| 6243 | + |
| 6244 | + return new_fix; |
| 6245 | +} |
| 6246 | + |
| 6247 | + |
| 6248 | +/* Record that there is a natural barrier in the insn stream at |
| 6249 | + ADDRESS. */ |
| 6250 | +static void |
| 6251 | +push_minipool_barrier (rtx insn, HOST_WIDE_INT address) |
| 6252 | +{ |
| 6253 | + Mfix *fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*fix)); |
| 6254 | + |
| 6255 | + fix->insn = insn; |
| 6256 | + fix->address = address; |
| 6257 | + |
| 6258 | + fix->next = NULL; |
| 6259 | + if (minipool_fix_head != NULL) |
| 6260 | + minipool_fix_tail->next = fix; |
| 6261 | + else |
| 6262 | + minipool_fix_head = fix; |
| 6263 | + |
| 6264 | + minipool_fix_tail = fix; |
| 6265 | +} |
| 6266 | + |
| 6267 | + |
| 6268 | +/* Record INSN, which will need fixing up to load a value from the |
| 6269 | + minipool. ADDRESS is the offset of the insn since the start of the |
| 6270 | + function; LOC is a pointer to the part of the insn which requires |
| 6271 | + fixing; VALUE is the constant that must be loaded, which is of type |
| 6272 | + MODE. */ |
| 6273 | +static void |
| 6274 | +push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx * loc, |
| 6275 | + enum machine_mode mode, rtx value) |
| 6276 | +{ |
| 6277 | + Mfix *fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*fix)); |
| 6278 | + rtx body = PATTERN (insn); |
| 6279 | + |
| 6280 | + fix->insn = insn; |
| 6281 | + fix->address = address; |
| 6282 | + fix->loc = loc; |
| 6283 | + fix->mode = mode; |
| 6284 | + fix->fix_size = MINIPOOL_FIX_SIZE (mode, value); |
| 6285 | + fix->value = value; |
| 6286 | + |
| 6287 | + if (GET_CODE (body) == PARALLEL) |
| 6288 | + { |
| 6289 | + /* Mcall : Ks16 << 2 */ |
| 6290 | + fix->forwards = ((1 << 15) - 1) << 2; |
| 6291 | + fix->backwards = (1 << 15) << 2; |
| 6292 | + } |
| 6293 | + else if (GET_CODE (body) == SET |
| 6294 | + && GET_MODE_SIZE (GET_MODE (SET_DEST (body))) == 4) |
| 6295 | + { |
| 6296 | + if (optimize_size) |
| 6297 | + { |
| 6298 | + /* Lddpc : Ku7 << 2 */ |
| 6299 | + fix->forwards = ((1 << 7) - 1) << 2; |
| 6300 | + fix->backwards = 0; |
| 6301 | + } |
| 6302 | + else |
| 6303 | + { |
| 6304 | + /* Ld.w : Ks16 */ |
| 6305 | + fix->forwards = ((1 << 15) - 4); |
| 6306 | + fix->backwards = (1 << 15); |
| 6307 | + } |
| 6308 | + } |
| 6309 | + else if (GET_CODE (body) == SET |
| 6310 | + && GET_MODE_SIZE (GET_MODE (SET_DEST (body))) == 8) |
| 6311 | + { |
| 6312 | + /* Ld.d : Ks16 */ |
| 6313 | + fix->forwards = ((1 << 15) - 4); |
| 6314 | + fix->backwards = (1 << 15); |
| 6315 | + } |
| 6316 | + else if (GET_CODE (body) == UNSPEC_VOLATILE |
| 6317 | + && XINT (body, 1) == VUNSPEC_MVRC) |
| 6318 | + { |
| 6319 | + /* Coprocessor load */ |
| 6320 | + /* Ldc : Ku8 << 2 */ |
| 6321 | + fix->forwards = ((1 << 8) - 1) << 2; |
| 6322 | + fix->backwards = 0; |
| 6323 | + } |
| 6324 | + else |
| 6325 | + { |
| 6326 | + /* Assume worst case which is lddpc insn. */ |
| 6327 | + fix->forwards = ((1 << 7) - 1) << 2; |
| 6328 | + fix->backwards = 0; |
| 6329 | + } |
| 6330 | + |
| 6331 | + fix->minipool = NULL; |
| 6332 | + |
| 6333 | + /* If an insn doesn't have a range defined for it, then it isn't expecting |
| 6334 | + to be reworked by this code. Better to abort now than to generate duff |
| 6335 | + assembly code. */ |
| 6336 | + if (fix->forwards == 0 && fix->backwards == 0) |
| 6337 | + abort (); |
| 6338 | + |
| 6339 | + if (dump_file) |
| 6340 | + { |
| 6341 | + fprintf (dump_file, |
| 6342 | + ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ", |
| 6343 | + GET_MODE_NAME (mode), |
| 6344 | + INSN_UID (insn), (unsigned long) address, |
| 6345 | + -1 * (long) fix->backwards, (long) fix->forwards); |
| 6346 | + avr32_print_value (dump_file, fix->value); |
| 6347 | + fprintf (dump_file, "\n"); |
| 6348 | + } |
| 6349 | + |
| 6350 | + /* Add it to the chain of fixes. */ |
| 6351 | + fix->next = NULL; |
| 6352 | + |
| 6353 | + if (minipool_fix_head != NULL) |
| 6354 | + minipool_fix_tail->next = fix; |
| 6355 | + else |
| 6356 | + minipool_fix_head = fix; |
| 6357 | + |
| 6358 | + minipool_fix_tail = fix; |
| 6359 | +} |
| 6360 | + |
| 6361 | + |
| 6362 | +/* Scan INSN and note any of its operands that need fixing. |
| 6363 | + If DO_PUSHES is false we do not actually push any of the fixups |
| 6364 | + needed. The function returns TRUE is any fixups were needed/pushed. |
| 6365 | + This is used by avr32_memory_load_p() which needs to know about loads |
| 6366 | + of constants that will be converted into minipool loads. */ |
| 6367 | +static bool |
| 6368 | +note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes) |
| 6369 | +{ |
| 6370 | + bool result = false; |
| 6371 | + int opno; |
| 6372 | + |
| 6373 | + extract_insn (insn); |
| 6374 | + |
| 6375 | + if (!constrain_operands (1)) |
| 6376 | + fatal_insn_not_found (insn); |
| 6377 | + |
| 6378 | + if (recog_data.n_alternatives == 0) |
| 6379 | + return false; |
| 6380 | + |
| 6381 | + /* Fill in recog_op_alt with information about the constraints of this |
| 6382 | + insn. */ |
| 6383 | + preprocess_constraints (); |
| 6384 | + |
| 6385 | + for (opno = 0; opno < recog_data.n_operands; opno++) |
| 6386 | + { |
| 6387 | + rtx op; |
| 6388 | + |
| 6389 | + /* Things we need to fix can only occur in inputs. */ |
| 6390 | + if (recog_data.operand_type[opno] != OP_IN) |
| 6391 | + continue; |
| 6392 | + |
| 6393 | + op = recog_data.operand[opno]; |
| 6394 | + |
| 6395 | + if (avr32_const_pool_ref_operand (op, GET_MODE (op))) |
| 6396 | + { |
| 6397 | + if (do_pushes) |
| 6398 | + { |
| 6399 | + rtx cop = avoid_constant_pool_reference (op); |
| 6400 | + |
| 6401 | + /* Casting the address of something to a mode narrower than a |
| 6402 | + word can cause avoid_constant_pool_reference() to return the |
| 6403 | + pool reference itself. That's no good to us here. Lets |
| 6404 | + just hope that we can use the constant pool value directly. |
| 6405 | + */ |
| 6406 | + if (op == cop) |
| 6407 | + cop = get_pool_constant (XEXP (op, 0)); |
| 6408 | + |
| 6409 | + push_minipool_fix (insn, address, |
| 6410 | + recog_data.operand_loc[opno], |
| 6411 | + recog_data.operand_mode[opno], cop); |
| 6412 | + } |
| 6413 | + |
| 6414 | + result = true; |
| 6415 | + } |
| 6416 | + else if (TARGET_HAS_ASM_ADDR_PSEUDOS |
| 6417 | + && avr32_address_operand (op, GET_MODE (op))) |
| 6418 | + { |
| 6419 | + /* Handle pseudo instructions using a direct address. These pseudo |
| 6420 | + instructions might need entries in the constant pool and we must |
| 6421 | + therefor create a constant pool for them, in case the |
| 6422 | + assembler/linker needs to insert entries. */ |
| 6423 | + if (do_pushes) |
| 6424 | + { |
| 6425 | + /* Push a dummy constant pool entry so that the .cpool |
| 6426 | + directive should be inserted on the appropriate place in the |
| 6427 | + code even if there are no real constant pool entries. This |
| 6428 | + is used by the assembler and linker to know where to put |
| 6429 | + generated constant pool entries. */ |
| 6430 | + push_minipool_fix (insn, address, |
| 6431 | + recog_data.operand_loc[opno], |
| 6432 | + recog_data.operand_mode[opno], |
| 6433 | + gen_rtx_UNSPEC (VOIDmode, |
| 6434 | + gen_rtvec (1, const0_rtx), |
| 6435 | + UNSPEC_FORCE_MINIPOOL)); |
| 6436 | + result = true; |
| 6437 | + } |
| 6438 | + } |
| 6439 | + } |
| 6440 | + return result; |
| 6441 | +} |
| 6442 | + |
| 6443 | + |
| 6444 | +static int |
| 6445 | +avr32_insn_is_cast (rtx insn) |
| 6446 | +{ |
| 6447 | + |
| 6448 | + if (NONJUMP_INSN_P (insn) |
| 6449 | + && GET_CODE (PATTERN (insn)) == SET |
| 6450 | + && (GET_CODE (SET_SRC (PATTERN (insn))) == ZERO_EXTEND |
| 6451 | + || GET_CODE (SET_SRC (PATTERN (insn))) == SIGN_EXTEND) |
| 6452 | + && REG_P (XEXP (SET_SRC (PATTERN (insn)), 0)) |
| 6453 | + && REG_P (SET_DEST (PATTERN (insn)))) |
| 6454 | + return true; |
| 6455 | + return false; |
| 6456 | +} |
| 6457 | + |
| 6458 | + |
| 6459 | +/* Replace all occurances of reg FROM with reg TO in X. */ |
| 6460 | +rtx |
| 6461 | +avr32_replace_reg (rtx x, rtx from, rtx to) |
| 6462 | +{ |
| 6463 | + int i, j; |
| 6464 | + const char *fmt; |
| 6465 | + |
| 6466 | + gcc_assert ( REG_P (from) && REG_P (to) ); |
| 6467 | + |
| 6468 | + /* Allow this function to make replacements in EXPR_LISTs. */ |
| 6469 | + if (x == 0) |
| 6470 | + return 0; |
| 6471 | + |
| 6472 | + if (rtx_equal_p (x, from)) |
| 6473 | + return to; |
| 6474 | + |
| 6475 | + if (GET_CODE (x) == SUBREG) |
| 6476 | + { |
| 6477 | + rtx new = avr32_replace_reg (SUBREG_REG (x), from, to); |
| 6478 | + |
| 6479 | + if (GET_CODE (new) == CONST_INT) |
| 6480 | + { |
| 6481 | + x = simplify_subreg (GET_MODE (x), new, |
| 6482 | + GET_MODE (SUBREG_REG (x)), |
| 6483 | + SUBREG_BYTE (x)); |
| 6484 | + gcc_assert (x); |
| 6485 | + } |
| 6486 | + else |
| 6487 | + SUBREG_REG (x) = new; |
| 6488 | + |
| 6489 | + return x; |
| 6490 | + } |
| 6491 | + else if (GET_CODE (x) == ZERO_EXTEND) |
| 6492 | + { |
| 6493 | + rtx new = avr32_replace_reg (XEXP (x, 0), from, to); |
| 6494 | + |
| 6495 | + if (GET_CODE (new) == CONST_INT) |
| 6496 | + { |
| 6497 | + x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x), |
| 6498 | + new, GET_MODE (XEXP (x, 0))); |
| 6499 | + gcc_assert (x); |
| 6500 | + } |
| 6501 | + else |
| 6502 | + XEXP (x, 0) = new; |
| 6503 | + |
| 6504 | + return x; |
| 6505 | + } |
| 6506 | + |
| 6507 | + fmt = GET_RTX_FORMAT (GET_CODE (x)); |
| 6508 | + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
| 6509 | + { |
| 6510 | + if (fmt[i] == 'e') |
| 6511 | + XEXP (x, i) = avr32_replace_reg (XEXP (x, i), from, to); |
| 6512 | + else if (fmt[i] == 'E') |
| 6513 | + for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
| 6514 | + XVECEXP (x, i, j) = avr32_replace_reg (XVECEXP (x, i, j), from, to); |
| 6515 | + } |
| 6516 | + |
| 6517 | + return x; |
| 6518 | +} |
| 6519 | + |
| 6520 | + |
| 6521 | +/* FIXME: The level of nesting in this function is way too deep. It needs to be |
| 6522 | + torn apart. */ |
| 6523 | +static void |
| 6524 | +avr32_reorg_optimization (void) |
| 6525 | +{ |
| 6526 | + rtx first = get_first_nonnote_insn (); |
| 6527 | + rtx insn; |
| 6528 | + |
| 6529 | + if (TARGET_MD_REORG_OPTIMIZATION && (optimize_size || (optimize > 0))) |
| 6530 | + { |
| 6531 | + |
| 6532 | + /* Scan through all insns looking for cast operations. */ |
| 6533 | + if (dump_file) |
| 6534 | + { |
| 6535 | + fprintf (dump_file, ";; Deleting redundant cast operations:\n"); |
| 6536 | + } |
| 6537 | + for (insn = first; insn; insn = NEXT_INSN (insn)) |
| 6538 | + { |
| 6539 | + rtx reg, src_reg, scan; |
| 6540 | + enum machine_mode mode; |
| 6541 | + int unused_cast; |
| 6542 | + rtx label_ref; |
| 6543 | + |
| 6544 | + if (avr32_insn_is_cast (insn) |
| 6545 | + && (GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 0)) == QImode |
| 6546 | + || GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 0)) == HImode)) |
| 6547 | + { |
| 6548 | + mode = GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 0)); |
| 6549 | + reg = SET_DEST (PATTERN (insn)); |
| 6550 | + src_reg = XEXP (SET_SRC (PATTERN (insn)), 0); |
| 6551 | + } |
| 6552 | + else |
| 6553 | + { |
| 6554 | + continue; |
| 6555 | + } |
| 6556 | + |
| 6557 | + unused_cast = false; |
| 6558 | + label_ref = NULL_RTX; |
| 6559 | + for (scan = NEXT_INSN (insn); scan; scan = NEXT_INSN (scan)) |
| 6560 | + { |
| 6561 | + /* Check if we have reached the destination of a simple |
| 6562 | + conditional jump which we have already scanned past. If so, |
| 6563 | + we can safely continue scanning. */ |
| 6564 | + if (LABEL_P (scan) && label_ref != NULL_RTX) |
| 6565 | + { |
| 6566 | + if (CODE_LABEL_NUMBER (scan) == |
| 6567 | + CODE_LABEL_NUMBER (XEXP (label_ref, 0))) |
| 6568 | + label_ref = NULL_RTX; |
| 6569 | + else |
| 6570 | + break; |
| 6571 | + } |
| 6572 | + |
| 6573 | + if (!INSN_P (scan)) |
| 6574 | + continue; |
| 6575 | + |
| 6576 | + /* For conditional jumps we can manage to keep on scanning if |
| 6577 | + we meet the destination label later on before any new jump |
| 6578 | + insns occure. */ |
| 6579 | + if (GET_CODE (scan) == JUMP_INSN) |
| 6580 | + { |
| 6581 | + if (any_condjump_p (scan) && label_ref == NULL_RTX) |
| 6582 | + label_ref = condjump_label (scan); |
| 6583 | + else |
| 6584 | + break; |
| 6585 | + } |
| 6586 | + |
| 6587 | + /* Check if we have a call and the register is used as an argument. */ |
| 6588 | + if (CALL_P (scan) |
| 6589 | + && find_reg_fusage (scan, USE, reg) ) |
| 6590 | + break; |
| 6591 | + |
| 6592 | + if (!reg_mentioned_p (reg, PATTERN (scan))) |
| 6593 | + continue; |
| 6594 | + |
| 6595 | + /* Check if casted register is used in this insn */ |
| 6596 | + if ((regno_use_in (REGNO (reg), PATTERN (scan)) != NULL_RTX) |
| 6597 | + && (GET_MODE (regno_use_in (REGNO (reg), PATTERN (scan))) == |
| 6598 | + GET_MODE (reg))) |
| 6599 | + { |
| 6600 | + /* If not used in the source to the set or in a memory |
| 6601 | + expression in the destiantion then the register is used |
| 6602 | + as a destination and is really dead. */ |
| 6603 | + if (single_set (scan) |
| 6604 | + && GET_CODE (PATTERN (scan)) == SET |
| 6605 | + && REG_P (SET_DEST (PATTERN (scan))) |
| 6606 | + && !regno_use_in (REGNO (reg), SET_SRC (PATTERN (scan))) |
| 6607 | + && label_ref == NULL_RTX) |
| 6608 | + { |
| 6609 | + unused_cast = true; |
| 6610 | + } |
| 6611 | + break; |
| 6612 | + } |
| 6613 | + |
| 6614 | + /* Check if register is dead or set in this insn */ |
| 6615 | + if (dead_or_set_p (scan, reg)) |
| 6616 | + { |
| 6617 | + unused_cast = true; |
| 6618 | + break; |
| 6619 | + } |
| 6620 | + } |
| 6621 | + |
| 6622 | + /* Check if we have unresolved conditional jumps */ |
| 6623 | + if (label_ref != NULL_RTX) |
| 6624 | + continue; |
| 6625 | + |
| 6626 | + if (unused_cast) |
| 6627 | + { |
| 6628 | + if (REGNO (reg) == REGNO (XEXP (SET_SRC (PATTERN (insn)), 0))) |
| 6629 | + { |
| 6630 | + /* One operand cast, safe to delete */ |
| 6631 | + if (dump_file) |
| 6632 | + { |
| 6633 | + fprintf (dump_file, |
| 6634 | + ";; INSN %i removed, casted register %i value not used.\n", |
| 6635 | + INSN_UID (insn), REGNO (reg)); |
| 6636 | + } |
| 6637 | + SET_INSN_DELETED (insn); |
| 6638 | + /* Force the instruction to be recognized again */ |
| 6639 | + INSN_CODE (insn) = -1; |
| 6640 | + } |
| 6641 | + else |
| 6642 | + { |
| 6643 | + /* Two operand cast, which really could be substituted with |
| 6644 | + a move, if the source register is dead after the cast |
| 6645 | + insn and then the insn which sets the source register |
| 6646 | + could instead directly set the destination register for |
| 6647 | + the cast. As long as there are no insns in between which |
| 6648 | + uses the register. */ |
| 6649 | + rtx link = NULL_RTX; |
| 6650 | + rtx set; |
| 6651 | + rtx src_reg = XEXP (SET_SRC (PATTERN (insn)), 0); |
| 6652 | + unused_cast = false; |
| 6653 | + |
| 6654 | + if (!find_reg_note (insn, REG_DEAD, src_reg)) |
| 6655 | + continue; |
| 6656 | + |
| 6657 | + /* Search for the insn which sets the source register */ |
| 6658 | + for (scan = PREV_INSN (insn); |
| 6659 | + scan && GET_CODE (scan) != CODE_LABEL; |
| 6660 | + scan = PREV_INSN (scan)) |
| 6661 | + { |
| 6662 | + if (! INSN_P (scan)) |
| 6663 | + continue; |
| 6664 | + |
| 6665 | + set = single_set (scan); |
| 6666 | + // Fix for bug #11763 : the following if condition |
| 6667 | + // has been modified and else part is included to |
| 6668 | + // set the link to NULL_RTX. |
| 6669 | + // if (set && rtx_equal_p (src_reg, SET_DEST (set))) |
| 6670 | + if (set && (REGNO(src_reg) == REGNO(SET_DEST(set)))) |
| 6671 | + { |
| 6672 | + if (rtx_equal_p (src_reg, SET_DEST (set))) |
| 6673 | + { |
| 6674 | + link = scan; |
| 6675 | + break; |
| 6676 | + } |
| 6677 | + else |
| 6678 | + { |
| 6679 | + link = NULL_RTX; |
| 6680 | + break; |
| 6681 | + } |
| 6682 | + } |
| 6683 | + } |
| 6684 | + |
| 6685 | + |
| 6686 | + /* Found no link or link is a call insn where we can not |
| 6687 | + change the destination register */ |
| 6688 | + if (link == NULL_RTX || CALL_P (link)) |
| 6689 | + continue; |
| 6690 | + |
| 6691 | + /* Scan through all insn between link and insn */ |
| 6692 | + for (scan = NEXT_INSN (link); scan; scan = NEXT_INSN (scan)) |
| 6693 | + { |
| 6694 | + /* Don't try to trace forward past a CODE_LABEL if we |
| 6695 | + haven't seen INSN yet. Ordinarily, we will only |
| 6696 | + find the setting insn in LOG_LINKS if it is in the |
| 6697 | + same basic block. However, cross-jumping can insert |
| 6698 | + code labels in between the load and the call, and |
| 6699 | + can result in situations where a single call insn |
| 6700 | + may have two targets depending on where we came |
| 6701 | + from. */ |
| 6702 | + |
| 6703 | + if (GET_CODE (scan) == CODE_LABEL) |
| 6704 | + break; |
| 6705 | + |
| 6706 | + if (!INSN_P (scan)) |
| 6707 | + continue; |
| 6708 | + |
| 6709 | + /* Don't try to trace forward past a JUMP. To optimize |
| 6710 | + safely, we would have to check that all the |
| 6711 | + instructions at the jump destination did not use REG. |
| 6712 | + */ |
| 6713 | + |
| 6714 | + if (GET_CODE (scan) == JUMP_INSN) |
| 6715 | + { |
| 6716 | + break; |
| 6717 | + } |
| 6718 | + |
| 6719 | + if (!reg_mentioned_p (src_reg, PATTERN (scan))) |
| 6720 | + continue; |
| 6721 | + |
| 6722 | + /* We have reached the cast insn */ |
| 6723 | + if (scan == insn) |
| 6724 | + { |
| 6725 | + /* We can remove cast and replace the destination |
| 6726 | + register of the link insn with the destination |
| 6727 | + of the cast */ |
| 6728 | + if (dump_file) |
| 6729 | + { |
| 6730 | + fprintf (dump_file, |
| 6731 | + ";; INSN %i removed, casted value unused. " |
| 6732 | + "Destination of removed cast operation: register %i, folded into INSN %i.\n", |
| 6733 | + INSN_UID (insn), REGNO (reg), |
| 6734 | + INSN_UID (link)); |
| 6735 | + } |
| 6736 | + /* Update link insn */ |
| 6737 | + SET_DEST (PATTERN (link)) = |
| 6738 | + gen_rtx_REG (mode, REGNO (reg)); |
| 6739 | + /* Force the instruction to be recognized again */ |
| 6740 | + INSN_CODE (link) = -1; |
| 6741 | + |
| 6742 | + /* Delete insn */ |
| 6743 | + SET_INSN_DELETED (insn); |
| 6744 | + /* Force the instruction to be recognized again */ |
| 6745 | + INSN_CODE (insn) = -1; |
| 6746 | + break; |
| 6747 | + } |
| 6748 | + } |
| 6749 | + } |
| 6750 | + } |
| 6751 | + } |
| 6752 | + } |
| 6753 | + |
| 6754 | + if (TARGET_MD_REORG_OPTIMIZATION && (optimize_size || (optimize > 0))) |
| 6755 | + { |
| 6756 | + |
| 6757 | + /* Scan through all insns looking for shifted add operations */ |
| 6758 | + if (dump_file) |
| 6759 | + { |
| 6760 | + fprintf (dump_file, |
| 6761 | + ";; Deleting redundant shifted add operations:\n"); |
| 6762 | + } |
| 6763 | + for (insn = first; insn; insn = NEXT_INSN (insn)) |
| 6764 | + { |
| 6765 | + rtx reg, mem_expr, scan, op0, op1; |
| 6766 | + int add_only_used_as_pointer; |
| 6767 | + |
| 6768 | + if (INSN_P (insn) |
| 6769 | + && GET_CODE (PATTERN (insn)) == SET |
| 6770 | + && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS |
| 6771 | + && (GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 0)) == MULT |
| 6772 | + || GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 0)) == ASHIFT) |
| 6773 | + && GET_CODE (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 1)) == |
| 6774 | + CONST_INT && REG_P (SET_DEST (PATTERN (insn))) |
| 6775 | + && REG_P (XEXP (SET_SRC (PATTERN (insn)), 1)) |
| 6776 | + && REG_P (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0))) |
| 6777 | + { |
| 6778 | + reg = SET_DEST (PATTERN (insn)); |
| 6779 | + mem_expr = SET_SRC (PATTERN (insn)); |
| 6780 | + op0 = XEXP (XEXP (mem_expr, 0), 0); |
| 6781 | + op1 = XEXP (mem_expr, 1); |
| 6782 | + } |
| 6783 | + else |
| 6784 | + { |
| 6785 | + continue; |
| 6786 | + } |
| 6787 | + |
| 6788 | + /* Scan forward the check if the result of the shifted add |
| 6789 | + operation is only used as an address in memory operations and |
| 6790 | + that the operands to the shifted add are not clobbered. */ |
| 6791 | + add_only_used_as_pointer = false; |
| 6792 | + for (scan = NEXT_INSN (insn); scan; scan = NEXT_INSN (scan)) |
| 6793 | + { |
| 6794 | + if (!INSN_P (scan)) |
| 6795 | + continue; |
| 6796 | + |
| 6797 | + /* Don't try to trace forward past a JUMP or CALL. To optimize |
| 6798 | + safely, we would have to check that all the instructions at |
| 6799 | + the jump destination did not use REG. */ |
| 6800 | + |
| 6801 | + if (GET_CODE (scan) == JUMP_INSN) |
| 6802 | + { |
| 6803 | + break; |
| 6804 | + } |
| 6805 | + |
| 6806 | + /* If used in a call insn then we cannot optimize it away */ |
| 6807 | + if (CALL_P (scan) && find_regno_fusage (scan, USE, REGNO (reg))) |
| 6808 | + break; |
| 6809 | + |
| 6810 | + /* If any of the operands of the shifted add are clobbered we |
| 6811 | + cannot optimize the shifted adda away */ |
| 6812 | + if ((reg_set_p (op0, scan) && (REGNO (op0) != REGNO (reg))) |
| 6813 | + || (reg_set_p (op1, scan) && (REGNO (op1) != REGNO (reg)))) |
| 6814 | + break; |
| 6815 | + |
| 6816 | + if (!reg_mentioned_p (reg, PATTERN (scan))) |
| 6817 | + continue; |
| 6818 | + |
| 6819 | + /* If used any other place than as a pointer or as the |
| 6820 | + destination register we failed */ |
| 6821 | + if (!(single_set (scan) |
| 6822 | + && GET_CODE (PATTERN (scan)) == SET |
| 6823 | + && ((MEM_P (SET_DEST (PATTERN (scan))) |
| 6824 | + && REG_P (XEXP (SET_DEST (PATTERN (scan)), 0)) |
| 6825 | + && REGNO (XEXP (SET_DEST (PATTERN (scan)), 0)) == REGNO (reg)) |
| 6826 | + || (MEM_P (SET_SRC (PATTERN (scan))) |
| 6827 | + && REG_P (XEXP (SET_SRC (PATTERN (scan)), 0)) |
| 6828 | + && REGNO (XEXP |
| 6829 | + (SET_SRC (PATTERN (scan)), 0)) == REGNO (reg)))) |
| 6830 | + && !(GET_CODE (PATTERN (scan)) == SET |
| 6831 | + && REG_P (SET_DEST (PATTERN (scan))) |
| 6832 | + && !regno_use_in (REGNO (reg), |
| 6833 | + SET_SRC (PATTERN (scan))))) |
| 6834 | + break; |
| 6835 | + |
| 6836 | + /* We cannot replace the pointer in TImode insns |
| 6837 | + as these has a differene addressing mode than the other |
| 6838 | + memory insns. */ |
| 6839 | + if ( GET_MODE (SET_DEST (PATTERN (scan))) == TImode ) |
| 6840 | + break; |
| 6841 | + |
| 6842 | + /* Check if register is dead or set in this insn */ |
| 6843 | + if (dead_or_set_p (scan, reg)) |
| 6844 | + { |
| 6845 | + add_only_used_as_pointer = true; |
| 6846 | + break; |
| 6847 | + } |
| 6848 | + } |
| 6849 | + |
| 6850 | + if (add_only_used_as_pointer) |
| 6851 | + { |
| 6852 | + /* Lets delete the add insn and replace all memory references |
| 6853 | + which uses the pointer with the full expression. */ |
| 6854 | + if (dump_file) |
| 6855 | + { |
| 6856 | + fprintf (dump_file, |
| 6857 | + ";; Deleting INSN %i since address expression can be folded into all " |
| 6858 | + "memory references using this expression\n", |
| 6859 | + INSN_UID (insn)); |
| 6860 | + } |
| 6861 | + SET_INSN_DELETED (insn); |
| 6862 | + /* Force the instruction to be recognized again */ |
| 6863 | + INSN_CODE (insn) = -1; |
| 6864 | + |
| 6865 | + for (scan = NEXT_INSN (insn); scan; scan = NEXT_INSN (scan)) |
| 6866 | + { |
| 6867 | + if (!INSN_P (scan)) |
| 6868 | + continue; |
| 6869 | + |
| 6870 | + if (!reg_mentioned_p (reg, PATTERN (scan))) |
| 6871 | + continue; |
| 6872 | + |
| 6873 | + /* If used any other place than as a pointer or as the |
| 6874 | + destination register we failed */ |
| 6875 | + if ((single_set (scan) |
| 6876 | + && GET_CODE (PATTERN (scan)) == SET |
| 6877 | + && ((MEM_P (SET_DEST (PATTERN (scan))) |
| 6878 | + && REG_P (XEXP (SET_DEST (PATTERN (scan)), 0)) |
| 6879 | + && REGNO (XEXP (SET_DEST (PATTERN (scan)), 0)) == |
| 6880 | + REGNO (reg)) || (MEM_P (SET_SRC (PATTERN (scan))) |
| 6881 | + && |
| 6882 | + REG_P (XEXP |
| 6883 | + (SET_SRC (PATTERN (scan)), |
| 6884 | + 0)) |
| 6885 | + && |
| 6886 | + REGNO (XEXP |
| 6887 | + (SET_SRC (PATTERN (scan)), |
| 6888 | + 0)) == REGNO (reg))))) |
| 6889 | + { |
| 6890 | + if (dump_file) |
| 6891 | + { |
| 6892 | + fprintf (dump_file, |
| 6893 | + ";; Register %i replaced by indexed address in INSN %i\n", |
| 6894 | + REGNO (reg), INSN_UID (scan)); |
| 6895 | + } |
| 6896 | + if (MEM_P (SET_DEST (PATTERN (scan)))) |
| 6897 | + XEXP (SET_DEST (PATTERN (scan)), 0) = mem_expr; |
| 6898 | + else |
| 6899 | + XEXP (SET_SRC (PATTERN (scan)), 0) = mem_expr; |
| 6900 | + } |
| 6901 | + |
| 6902 | + /* Check if register is dead or set in this insn */ |
| 6903 | + if (dead_or_set_p (scan, reg)) |
| 6904 | + { |
| 6905 | + break; |
| 6906 | + } |
| 6907 | + |
| 6908 | + } |
| 6909 | + } |
| 6910 | + } |
| 6911 | + } |
| 6912 | + |
| 6913 | + |
| 6914 | + if (TARGET_MD_REORG_OPTIMIZATION && (optimize_size || (optimize > 0))) |
| 6915 | + { |
| 6916 | + |
| 6917 | + /* Scan through all insns looking for conditional register to |
| 6918 | + register move operations */ |
| 6919 | + if (dump_file) |
| 6920 | + { |
| 6921 | + fprintf (dump_file, |
| 6922 | + ";; Folding redundant conditional move operations:\n"); |
| 6923 | + } |
| 6924 | + for (insn = first; insn; insn = next_nonnote_insn (insn)) |
| 6925 | + { |
| 6926 | + rtx src_reg, dst_reg, scan, test; |
| 6927 | + |
| 6928 | + if (INSN_P (insn) |
| 6929 | + && GET_CODE (PATTERN (insn)) == COND_EXEC |
| 6930 | + && GET_CODE (COND_EXEC_CODE (PATTERN (insn))) == SET |
| 6931 | + && REG_P (SET_SRC (COND_EXEC_CODE (PATTERN (insn)))) |
| 6932 | + && REG_P (SET_DEST (COND_EXEC_CODE (PATTERN (insn)))) |
| 6933 | + && find_reg_note (insn, REG_DEAD, SET_SRC (COND_EXEC_CODE (PATTERN (insn))))) |
| 6934 | + { |
| 6935 | + src_reg = SET_SRC (COND_EXEC_CODE (PATTERN (insn))); |
| 6936 | + dst_reg = SET_DEST (COND_EXEC_CODE (PATTERN (insn))); |
| 6937 | + test = COND_EXEC_TEST (PATTERN (insn)); |
| 6938 | + } |
| 6939 | + else |
| 6940 | + { |
| 6941 | + continue; |
| 6942 | + } |
| 6943 | + |
| 6944 | + /* Scan backward through the rest of insns in this if-then or if-else |
| 6945 | + block and check if we can fold the move into another of the conditional |
| 6946 | + insns in the same block. */ |
| 6947 | + scan = prev_nonnote_insn (insn); |
| 6948 | + while (INSN_P (scan) |
| 6949 | + && GET_CODE (PATTERN (scan)) == COND_EXEC |
| 6950 | + && rtx_equal_p (COND_EXEC_TEST (PATTERN (scan)), test)) |
| 6951 | + { |
| 6952 | + rtx pattern = COND_EXEC_CODE (PATTERN (scan)); |
| 6953 | + if ( GET_CODE (pattern) == PARALLEL ) |
| 6954 | + pattern = XVECEXP (pattern, 0, 0); |
| 6955 | + |
| 6956 | + if ( reg_set_p (src_reg, pattern) ) |
| 6957 | + { |
| 6958 | + /* Fold in the destination register for the cond. move |
| 6959 | + into this insn. */ |
| 6960 | + SET_DEST (pattern) = dst_reg; |
| 6961 | + if (dump_file) |
| 6962 | + { |
| 6963 | + fprintf (dump_file, |
| 6964 | + ";; Deleting INSN %i since this operation can be folded into INSN %i\n", |
| 6965 | + INSN_UID (insn), INSN_UID (scan)); |
| 6966 | + } |
| 6967 | + |
| 6968 | + /* Scan and check if any of the insns in between uses the src_reg. We |
| 6969 | + must then replace it with the dst_reg. */ |
| 6970 | + while ( (scan = next_nonnote_insn (scan)) != insn ){ |
| 6971 | + avr32_replace_reg (scan, src_reg, dst_reg); |
| 6972 | + } |
| 6973 | + /* Delete the insn. */ |
| 6974 | + SET_INSN_DELETED (insn); |
| 6975 | + |
| 6976 | + /* Force the instruction to be recognized again */ |
| 6977 | + INSN_CODE (insn) = -1; |
| 6978 | + break; |
| 6979 | + } |
| 6980 | + |
| 6981 | + /* If the destination register is used but not set in this insn |
| 6982 | + we cannot fold. */ |
| 6983 | + if ( reg_mentioned_p (dst_reg, pattern) ) |
| 6984 | + break; |
| 6985 | + |
| 6986 | + scan = prev_nonnote_insn (scan); |
| 6987 | + } |
| 6988 | + } |
| 6989 | + } |
| 6990 | + |
| 6991 | +} |
| 6992 | + |
| 6993 | + |
| 6994 | +/* Exported to toplev.c. |
| 6995 | + |
| 6996 | + Do a final pass over the function, just before delayed branch |
| 6997 | + scheduling. */ |
| 6998 | +static void |
| 6999 | +avr32_reorg (void) |
| 7000 | +{ |
| 7001 | + rtx insn; |
| 7002 | + HOST_WIDE_INT address = 0; |
| 7003 | + Mfix *fix; |
| 7004 | + |
| 7005 | + minipool_fix_head = minipool_fix_tail = NULL; |
| 7006 | + |
| 7007 | + /* The first insn must always be a note, or the code below won't scan it |
| 7008 | + properly. */ |
| 7009 | + insn = get_insns (); |
| 7010 | + if (GET_CODE (insn) != NOTE) |
| 7011 | + abort (); |
| 7012 | + |
| 7013 | + /* Scan all the insns and record the operands that will need fixing. */ |
| 7014 | + for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn)) |
| 7015 | + { |
| 7016 | + if (GET_CODE (insn) == BARRIER) |
| 7017 | + push_minipool_barrier (insn, address); |
| 7018 | + else if (INSN_P (insn)) |
| 7019 | + { |
| 7020 | + rtx table; |
| 7021 | + |
| 7022 | + note_invalid_constants (insn, address, true); |
| 7023 | + address += get_attr_length (insn); |
| 7024 | + |
| 7025 | + /* If the insn is a vector jump, add the size of the table and skip |
| 7026 | + the table. */ |
| 7027 | + if ((table = is_jump_table (insn)) != NULL) |
| 7028 | + { |
| 7029 | + address += get_jump_table_size (table); |
| 7030 | + insn = table; |
| 7031 | + } |
| 7032 | + } |
| 7033 | + } |
| 7034 | + |
| 7035 | + fix = minipool_fix_head; |
| 7036 | + |
| 7037 | + /* Now scan the fixups and perform the required changes. */ |
| 7038 | + while (fix) |
| 7039 | + { |
| 7040 | + Mfix *ftmp; |
| 7041 | + Mfix *fdel; |
| 7042 | + Mfix *last_added_fix; |
| 7043 | + Mfix *last_barrier = NULL; |
| 7044 | + Mfix *this_fix; |
| 7045 | + |
| 7046 | + /* Skip any further barriers before the next fix. */ |
| 7047 | + while (fix && GET_CODE (fix->insn) == BARRIER) |
| 7048 | + fix = fix->next; |
| 7049 | + |
| 7050 | + /* No more fixes. */ |
| 7051 | + if (fix == NULL) |
| 7052 | + break; |
| 7053 | + |
| 7054 | + last_added_fix = NULL; |
| 7055 | + |
| 7056 | + for (ftmp = fix; ftmp; ftmp = ftmp->next) |
| 7057 | + { |
| 7058 | + if (GET_CODE (ftmp->insn) == BARRIER) |
| 7059 | + { |
| 7060 | + if (ftmp->address >= minipool_vector_head->max_address) |
| 7061 | + break; |
| 7062 | + |
| 7063 | + last_barrier = ftmp; |
| 7064 | + } |
| 7065 | + else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL) |
| 7066 | + break; |
| 7067 | + |
| 7068 | + last_added_fix = ftmp; /* Keep track of the last fix added. |
| 7069 | + */ |
| 7070 | + } |
| 7071 | + |
| 7072 | + /* If we found a barrier, drop back to that; any fixes that we could |
| 7073 | + have reached but come after the barrier will now go in the next |
| 7074 | + mini-pool. */ |
| 7075 | + if (last_barrier != NULL) |
| 7076 | + { |
| 7077 | + /* Reduce the refcount for those fixes that won't go into this pool |
| 7078 | + after all. */ |
| 7079 | + for (fdel = last_barrier->next; |
| 7080 | + fdel && fdel != ftmp; fdel = fdel->next) |
| 7081 | + { |
| 7082 | + fdel->minipool->refcount--; |
| 7083 | + fdel->minipool = NULL; |
| 7084 | + } |
| 7085 | + |
| 7086 | + ftmp = last_barrier; |
| 7087 | + } |
| 7088 | + else |
| 7089 | + { |
| 7090 | + /* ftmp is first fix that we can't fit into this pool and there no |
| 7091 | + natural barriers that we could use. Insert a new barrier in the |
| 7092 | + code somewhere between the previous fix and this one, and |
| 7093 | + arrange to jump around it. */ |
| 7094 | + HOST_WIDE_INT max_address; |
| 7095 | + |
| 7096 | + /* The last item on the list of fixes must be a barrier, so we can |
| 7097 | + never run off the end of the list of fixes without last_barrier |
| 7098 | + being set. */ |
| 7099 | + if (ftmp == NULL) |
| 7100 | + abort (); |
| 7101 | + |
| 7102 | + max_address = minipool_vector_head->max_address; |
| 7103 | + /* Check that there isn't another fix that is in range that we |
| 7104 | + couldn't fit into this pool because the pool was already too |
| 7105 | + large: we need to put the pool before such an instruction. */ |
| 7106 | + if (ftmp->address < max_address) |
| 7107 | + max_address = ftmp->address; |
| 7108 | + |
| 7109 | + last_barrier = create_fix_barrier (last_added_fix, max_address); |
| 7110 | + } |
| 7111 | + |
| 7112 | + assign_minipool_offsets (last_barrier); |
| 7113 | + |
| 7114 | + while (ftmp) |
| 7115 | + { |
| 7116 | + if (GET_CODE (ftmp->insn) != BARRIER |
| 7117 | + && ((ftmp->minipool = add_minipool_backward_ref (ftmp)) |
| 7118 | + == NULL)) |
| 7119 | + break; |
| 7120 | + |
| 7121 | + ftmp = ftmp->next; |
| 7122 | + } |
| 7123 | + |
| 7124 | + /* Scan over the fixes we have identified for this pool, fixing them up |
| 7125 | + and adding the constants to the pool itself. */ |
| 7126 | + for (this_fix = fix; this_fix && ftmp != this_fix; |
| 7127 | + this_fix = this_fix->next) |
| 7128 | + if (GET_CODE (this_fix->insn) != BARRIER |
| 7129 | + /* Do nothing for entries present just to force the insertion of |
| 7130 | + a minipool. */ |
| 7131 | + && !IS_FORCE_MINIPOOL (this_fix->value)) |
| 7132 | + { |
| 7133 | + rtx addr = plus_constant (gen_rtx_LABEL_REF (VOIDmode, |
| 7134 | + minipool_vector_label), |
| 7135 | + this_fix->minipool->offset); |
| 7136 | + *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr); |
| 7137 | + } |
| 7138 | + |
| 7139 | + dump_minipool (last_barrier->insn); |
| 7140 | + fix = ftmp; |
| 7141 | + } |
| 7142 | + |
| 7143 | + /* Free the minipool memory. */ |
| 7144 | + obstack_free (&minipool_obstack, minipool_startobj); |
| 7145 | + |
| 7146 | + avr32_reorg_optimization (); |
| 7147 | +} |
| 7148 | + |
| 7149 | + |
| 7150 | +/* Hook for doing some final scanning of instructions. Does nothing yet...*/ |
| 7151 | +void |
| 7152 | +avr32_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED, |
| 7153 | + rtx * opvec ATTRIBUTE_UNUSED, |
| 7154 | + int noperands ATTRIBUTE_UNUSED) |
| 7155 | +{ |
| 7156 | + return; |
| 7157 | +} |
| 7158 | + |
| 7159 | + |
| 7160 | +/* Function for changing the condition on the next instruction, |
| 7161 | + should be used when emmiting compare instructions and |
| 7162 | + the condition of the next instruction needs to change. |
| 7163 | +*/ |
| 7164 | +int |
| 7165 | +set_next_insn_cond (rtx cur_insn, rtx new_cond) |
| 7166 | +{ |
| 7167 | + rtx next_insn = next_nonnote_insn (cur_insn); |
| 7168 | + if ((next_insn != NULL_RTX) |
| 7169 | + && (INSN_P (next_insn))) |
| 7170 | + { |
| 7171 | + if ((GET_CODE (PATTERN (next_insn)) == SET) |
| 7172 | + && (GET_CODE (SET_SRC (PATTERN (next_insn))) == IF_THEN_ELSE)) |
| 7173 | + { |
| 7174 | + /* Branch instructions */ |
| 7175 | + XEXP (SET_SRC (PATTERN (next_insn)), 0) = new_cond; |
| 7176 | + /* Force the instruction to be recognized again */ |
| 7177 | + INSN_CODE (next_insn) = -1; |
| 7178 | + return TRUE; |
| 7179 | + } |
| 7180 | + else if ((GET_CODE (PATTERN (next_insn)) == SET) |
| 7181 | + && avr32_comparison_operator (SET_SRC (PATTERN (next_insn)), |
| 7182 | + GET_MODE (SET_SRC (PATTERN (next_insn))))) |
| 7183 | + { |
| 7184 | + /* scc with no compare */ |
| 7185 | + SET_SRC (PATTERN (next_insn)) = new_cond; |
| 7186 | + /* Force the instruction to be recognized again */ |
| 7187 | + INSN_CODE (next_insn) = -1; |
| 7188 | + return TRUE; |
| 7189 | + } |
| 7190 | + else if (GET_CODE (PATTERN (next_insn)) == COND_EXEC) |
| 7191 | + { |
| 7192 | + if ( GET_CODE (new_cond) == UNSPEC ) |
| 7193 | + { |
| 7194 | + COND_EXEC_TEST (PATTERN (next_insn)) = |
| 7195 | + gen_rtx_UNSPEC (CCmode, |
| 7196 | + gen_rtvec (2, |
| 7197 | + XEXP (COND_EXEC_TEST (PATTERN (next_insn)), 0), |
| 7198 | + XEXP (COND_EXEC_TEST (PATTERN (next_insn)), 1)), |
| 7199 | + XINT (new_cond, 1)); |
| 7200 | + } |
| 7201 | + else |
| 7202 | + { |
| 7203 | + PUT_CODE(COND_EXEC_TEST (PATTERN (next_insn)), GET_CODE(new_cond)); |
| 7204 | + } |
| 7205 | + } |
| 7206 | + } |
| 7207 | + |
| 7208 | + return FALSE; |
| 7209 | +} |
| 7210 | + |
| 7211 | + |
| 7212 | +/* Function for obtaining the condition for the next instruction after cur_insn. |
| 7213 | +*/ |
| 7214 | +rtx |
| 7215 | +get_next_insn_cond (rtx cur_insn) |
| 7216 | +{ |
| 7217 | + rtx next_insn = next_nonnote_insn (cur_insn); |
| 7218 | + rtx cond = NULL_RTX; |
| 7219 | + if (next_insn != NULL_RTX |
| 7220 | + && INSN_P (next_insn)) |
| 7221 | + { |
| 7222 | + if ((GET_CODE (PATTERN (next_insn)) == SET) |
| 7223 | + && (GET_CODE (SET_SRC (PATTERN (next_insn))) == IF_THEN_ELSE)) |
| 7224 | + { |
| 7225 | + /* Branch and cond if then else instructions */ |
| 7226 | + cond = XEXP (SET_SRC (PATTERN (next_insn)), 0); |
| 7227 | + } |
| 7228 | + else if ((GET_CODE (PATTERN (next_insn)) == SET) |
| 7229 | + && avr32_comparison_operator (SET_SRC (PATTERN (next_insn)), |
| 7230 | + GET_MODE (SET_SRC (PATTERN (next_insn))))) |
| 7231 | + { |
| 7232 | + /* scc with no compare */ |
| 7233 | + cond = SET_SRC (PATTERN (next_insn)); |
| 7234 | + } |
| 7235 | + else if (GET_CODE (PATTERN (next_insn)) == COND_EXEC) |
| 7236 | + { |
| 7237 | + cond = COND_EXEC_TEST (PATTERN (next_insn)); |
| 7238 | + } |
| 7239 | + } |
| 7240 | + return cond; |
| 7241 | +} |
| 7242 | + |
| 7243 | + |
| 7244 | +/* Check if the next insn is a conditional insn that will emit a compare |
| 7245 | + for itself. |
| 7246 | +*/ |
| 7247 | +rtx |
| 7248 | +next_insn_emits_cmp (rtx cur_insn) |
| 7249 | +{ |
| 7250 | + rtx next_insn = next_nonnote_insn (cur_insn); |
| 7251 | + rtx cond = NULL_RTX; |
| 7252 | + if (next_insn != NULL_RTX |
| 7253 | + && INSN_P (next_insn)) |
| 7254 | + { |
| 7255 | + if ( ((GET_CODE (PATTERN (next_insn)) == SET) |
| 7256 | + && (GET_CODE (SET_SRC (PATTERN (next_insn))) == IF_THEN_ELSE) |
| 7257 | + && (XEXP (XEXP (SET_SRC (PATTERN (next_insn)), 0),0) != cc0_rtx)) |
| 7258 | + || GET_CODE (PATTERN (next_insn)) == COND_EXEC ) |
| 7259 | + return TRUE; |
| 7260 | + } |
| 7261 | + return FALSE; |
| 7262 | +} |
| 7263 | + |
| 7264 | + |
| 7265 | +rtx |
| 7266 | +avr32_output_cmp (rtx cond, enum machine_mode mode, rtx op0, rtx op1) |
| 7267 | +{ |
| 7268 | + |
| 7269 | + rtx new_cond = NULL_RTX; |
| 7270 | + rtx ops[2]; |
| 7271 | + rtx compare_pattern; |
| 7272 | + ops[0] = op0; |
| 7273 | + ops[1] = op1; |
| 7274 | + |
| 7275 | + if ( GET_CODE (op0) == AND ) |
| 7276 | + compare_pattern = op0; |
| 7277 | + else |
| 7278 | + compare_pattern = gen_rtx_COMPARE (mode, op0, op1); |
| 7279 | + |
| 7280 | + new_cond = is_compare_redundant (compare_pattern, cond); |
| 7281 | + |
| 7282 | + if (new_cond != NULL_RTX) |
| 7283 | + return new_cond; |
| 7284 | + |
| 7285 | + /* Check if we are inserting a bit-load instead of a compare. */ |
| 7286 | + if ( GET_CODE (op0) == AND ) |
| 7287 | + { |
| 7288 | + ops[0] = XEXP (op0, 0); |
| 7289 | + ops[1] = XEXP (op0, 1); |
| 7290 | + output_asm_insn ("bld\t%0, %p1", ops); |
| 7291 | + return cond; |
| 7292 | + } |
| 7293 | + |
| 7294 | + /* Insert compare */ |
| 7295 | + switch (mode) |
| 7296 | + { |
| 7297 | + case QImode: |
| 7298 | + output_asm_insn ("cp.b\t%0, %1", ops); |
| 7299 | + break; |
| 7300 | + case HImode: |
| 7301 | + output_asm_insn ("cp.h\t%0, %1", ops); |
| 7302 | + break; |
| 7303 | + case SImode: |
| 7304 | + output_asm_insn ("cp.w\t%0, %1", ops); |
| 7305 | + break; |
| 7306 | + case DImode: |
| 7307 | + if (GET_CODE (op1) != REG) |
| 7308 | + output_asm_insn ("cp.w\t%0, %1\ncpc\t%m0", ops); |
| 7309 | + else |
| 7310 | + output_asm_insn ("cp.w\t%0, %1\ncpc\t%m0, %m1", ops); |
| 7311 | + break; |
| 7312 | + default: |
| 7313 | + internal_error ("Unknown comparison mode"); |
| 7314 | + break; |
| 7315 | + } |
| 7316 | + |
| 7317 | + return cond; |
| 7318 | +} |
| 7319 | + |
| 7320 | + |
| 7321 | +int |
| 7322 | +avr32_load_multiple_operation (rtx op, |
| 7323 | + enum machine_mode mode ATTRIBUTE_UNUSED) |
| 7324 | +{ |
| 7325 | + int count = XVECLEN (op, 0); |
| 7326 | + unsigned int dest_regno; |
| 7327 | + rtx src_addr; |
| 7328 | + rtx elt; |
| 7329 | + int i = 1, base = 0; |
| 7330 | + |
| 7331 | + if (count <= 1 || GET_CODE (XVECEXP (op, 0, 0)) != SET) |
| 7332 | + return 0; |
| 7333 | + |
| 7334 | + /* Check to see if this might be a write-back. */ |
| 7335 | + if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) |
| 7336 | + { |
| 7337 | + i++; |
| 7338 | + base = 1; |
| 7339 | + |
| 7340 | + /* Now check it more carefully. */ |
| 7341 | + if (GET_CODE (SET_DEST (elt)) != REG |
| 7342 | + || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG |
| 7343 | + || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT |
| 7344 | + || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4) |
| 7345 | + return 0; |
| 7346 | + } |
| 7347 | + |
| 7348 | + /* Perform a quick check so we don't blow up below. */ |
| 7349 | + if (count <= 1 |
| 7350 | + || GET_CODE (XVECEXP (op, 0, i - 1)) != SET |
| 7351 | + || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG |
| 7352 | + || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != UNSPEC) |
| 7353 | + return 0; |
| 7354 | + |
| 7355 | + dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1))); |
| 7356 | + src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0); |
| 7357 | + |
| 7358 | + for (; i < count; i++) |
| 7359 | + { |
| 7360 | + elt = XVECEXP (op, 0, i); |
| 7361 | + |
| 7362 | + if (GET_CODE (elt) != SET |
| 7363 | + || GET_CODE (SET_DEST (elt)) != REG |
| 7364 | + || GET_MODE (SET_DEST (elt)) != SImode |
| 7365 | + || GET_CODE (SET_SRC (elt)) != UNSPEC) |
| 7366 | + return 0; |
| 7367 | + } |
| 7368 | + |
| 7369 | + return 1; |
| 7370 | +} |
| 7371 | + |
| 7372 | + |
| 7373 | +int |
| 7374 | +avr32_store_multiple_operation (rtx op, |
| 7375 | + enum machine_mode mode ATTRIBUTE_UNUSED) |
| 7376 | +{ |
| 7377 | + int count = XVECLEN (op, 0); |
| 7378 | + int src_regno; |
| 7379 | + rtx dest_addr; |
| 7380 | + rtx elt; |
| 7381 | + int i = 1; |
| 7382 | + |
| 7383 | + if (count <= 1 || GET_CODE (XVECEXP (op, 0, 0)) != SET) |
| 7384 | + return 0; |
| 7385 | + |
| 7386 | + /* Perform a quick check so we don't blow up below. */ |
| 7387 | + if (count <= i |
| 7388 | + || GET_CODE (XVECEXP (op, 0, i - 1)) != SET |
| 7389 | + || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM |
| 7390 | + || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != UNSPEC) |
| 7391 | + return 0; |
| 7392 | + |
| 7393 | + src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1))); |
| 7394 | + dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0); |
| 7395 | + |
| 7396 | + for (; i < count; i++) |
| 7397 | + { |
| 7398 | + elt = XVECEXP (op, 0, i); |
| 7399 | + |
| 7400 | + if (GET_CODE (elt) != SET |
| 7401 | + || GET_CODE (SET_DEST (elt)) != MEM |
| 7402 | + || GET_MODE (SET_DEST (elt)) != SImode |
| 7403 | + || GET_CODE (SET_SRC (elt)) != UNSPEC) |
| 7404 | + return 0; |
| 7405 | + } |
| 7406 | + |
| 7407 | + return 1; |
| 7408 | +} |
| 7409 | + |
| 7410 | + |
| 7411 | +int |
| 7412 | +avr32_valid_macmac_bypass (rtx insn_out, rtx insn_in) |
| 7413 | +{ |
| 7414 | + /* Check if they use the same accumulator */ |
| 7415 | + if (rtx_equal_p |
| 7416 | + (SET_DEST (PATTERN (insn_out)), SET_DEST (PATTERN (insn_in)))) |
| 7417 | + { |
| 7418 | + return TRUE; |
| 7419 | + } |
| 7420 | + |
| 7421 | + return FALSE; |
| 7422 | +} |
| 7423 | + |
| 7424 | + |
| 7425 | +int |
| 7426 | +avr32_valid_mulmac_bypass (rtx insn_out, rtx insn_in) |
| 7427 | +{ |
| 7428 | + /* |
| 7429 | + Check if the mul instruction produces the accumulator for the mac |
| 7430 | + instruction. */ |
| 7431 | + if (rtx_equal_p |
| 7432 | + (SET_DEST (PATTERN (insn_out)), SET_DEST (PATTERN (insn_in)))) |
| 7433 | + { |
| 7434 | + return TRUE; |
| 7435 | + } |
| 7436 | + return FALSE; |
| 7437 | +} |
| 7438 | + |
| 7439 | + |
| 7440 | +int |
| 7441 | +avr32_store_bypass (rtx insn_out, rtx insn_in) |
| 7442 | +{ |
| 7443 | + /* Only valid bypass if the output result is used as an src in the store |
| 7444 | + instruction, NOT if used as a pointer or base. */ |
| 7445 | + if (rtx_equal_p |
| 7446 | + (SET_DEST (PATTERN (insn_out)), SET_SRC (PATTERN (insn_in)))) |
| 7447 | + { |
| 7448 | + return TRUE; |
| 7449 | + } |
| 7450 | + |
| 7451 | + return FALSE; |
| 7452 | +} |
| 7453 | + |
| 7454 | + |
| 7455 | +int |
| 7456 | +avr32_mul_waw_bypass (rtx insn_out, rtx insn_in) |
| 7457 | +{ |
| 7458 | + /* Check if the register holding the result from the mul instruction is |
| 7459 | + used as a result register in the input instruction. */ |
| 7460 | + if (rtx_equal_p |
| 7461 | + (SET_DEST (PATTERN (insn_out)), SET_DEST (PATTERN (insn_in)))) |
| 7462 | + { |
| 7463 | + return TRUE; |
| 7464 | + } |
| 7465 | + |
| 7466 | + return FALSE; |
| 7467 | +} |
| 7468 | + |
| 7469 | + |
| 7470 | +int |
| 7471 | +avr32_valid_load_double_bypass (rtx insn_out, rtx insn_in) |
| 7472 | +{ |
| 7473 | + /* Check if the first loaded word in insn_out is used in insn_in. */ |
| 7474 | + rtx dst_reg; |
| 7475 | + rtx second_loaded_reg; |
| 7476 | + |
| 7477 | + /* If this is a double alu operation then the bypass is not valid */ |
| 7478 | + if ((get_attr_type (insn_in) == TYPE_ALU |
| 7479 | + || get_attr_type (insn_in) == TYPE_ALU2) |
| 7480 | + && (GET_MODE_SIZE (GET_MODE (SET_DEST (PATTERN (insn_out)))) > 4)) |
| 7481 | + return FALSE; |
| 7482 | + |
| 7483 | + /* Get the destination register in the load */ |
| 7484 | + if (!REG_P (SET_DEST (PATTERN (insn_out)))) |
| 7485 | + return FALSE; |
| 7486 | + |
| 7487 | + dst_reg = SET_DEST (PATTERN (insn_out)); |
| 7488 | + second_loaded_reg = gen_rtx_REG (SImode, REGNO (dst_reg) + 1); |
| 7489 | + |
| 7490 | + if (!reg_mentioned_p (second_loaded_reg, PATTERN (insn_in))) |
| 7491 | + return TRUE; |
| 7492 | + |
| 7493 | + return FALSE; |
| 7494 | +} |
| 7495 | + |
| 7496 | + |
| 7497 | +int |
| 7498 | +avr32_valid_load_quad_bypass (rtx insn_out, rtx insn_in) |
| 7499 | +{ |
| 7500 | + /* |
| 7501 | + Check if the two first loaded word in insn_out are used in insn_in. */ |
| 7502 | + rtx dst_reg; |
| 7503 | + rtx third_loaded_reg, fourth_loaded_reg; |
| 7504 | + |
| 7505 | + /* Get the destination register in the load */ |
| 7506 | + if (!REG_P (SET_DEST (PATTERN (insn_out)))) |
| 7507 | + return FALSE; |
| 7508 | + |
| 7509 | + dst_reg = SET_DEST (PATTERN (insn_out)); |
| 7510 | + third_loaded_reg = gen_rtx_REG (SImode, REGNO (dst_reg) + 2); |
| 7511 | + fourth_loaded_reg = gen_rtx_REG (SImode, REGNO (dst_reg) + 3); |
| 7512 | + |
| 7513 | + if (!reg_mentioned_p (third_loaded_reg, PATTERN (insn_in)) |
| 7514 | + && !reg_mentioned_p (fourth_loaded_reg, PATTERN (insn_in))) |
| 7515 | + { |
| 7516 | + return TRUE; |
| 7517 | + } |
| 7518 | + |
| 7519 | + return FALSE; |
| 7520 | +} |
| 7521 | + |
| 7522 | + |
| 7523 | +rtx |
| 7524 | +avr32_ifcvt_modify_test (ce_if_block_t *ce_info, rtx test ) |
| 7525 | +{ |
| 7526 | + rtx branch_insn; |
| 7527 | + rtx cmp_test; |
| 7528 | + rtx compare_op0; |
| 7529 | + rtx compare_op1; |
| 7530 | + |
| 7531 | + |
| 7532 | + if ( !ce_info |
| 7533 | + || test == NULL_RTX |
| 7534 | + || !reg_mentioned_p (cc0_rtx, test)) |
| 7535 | + return test; |
| 7536 | + |
| 7537 | + branch_insn = BB_END (ce_info->test_bb); |
| 7538 | + cmp_test = PATTERN(prev_nonnote_insn (branch_insn)); |
| 7539 | + |
| 7540 | + if (GET_CODE(cmp_test) != SET |
| 7541 | + || !CC0_P(XEXP(cmp_test, 0)) ) |
| 7542 | + return cmp_test; |
| 7543 | + |
| 7544 | + if ( GET_CODE(SET_SRC(cmp_test)) == COMPARE ){ |
| 7545 | + compare_op0 = XEXP(SET_SRC(cmp_test), 0); |
| 7546 | + compare_op1 = XEXP(SET_SRC(cmp_test), 1); |
| 7547 | + } else { |
| 7548 | + compare_op0 = SET_SRC(cmp_test); |
| 7549 | + compare_op1 = const0_rtx; |
| 7550 | + } |
| 7551 | + |
| 7552 | + return gen_rtx_fmt_ee (GET_CODE(test), GET_MODE (compare_op0), |
| 7553 | + compare_op0, compare_op1); |
| 7554 | +} |
| 7555 | + |
| 7556 | + |
| 7557 | +rtx |
| 7558 | +avr32_ifcvt_modify_insn (ce_if_block_t *ce_info, rtx pattern, rtx insn, |
| 7559 | + int *num_true_changes) |
| 7560 | +{ |
| 7561 | + rtx test = COND_EXEC_TEST(pattern); |
| 7562 | + rtx op = COND_EXEC_CODE(pattern); |
| 7563 | + rtx cmp_insn; |
| 7564 | + rtx cond_exec_insn; |
| 7565 | + int inputs_set_outside_ifblock = 1; |
| 7566 | + basic_block current_bb = BLOCK_FOR_INSN (insn); |
| 7567 | + rtx bb_insn ; |
| 7568 | + enum machine_mode mode = GET_MODE (XEXP (op, 0)); |
| 7569 | + |
| 7570 | + if (CC0_P(XEXP(test, 0))) |
| 7571 | + test = avr32_ifcvt_modify_test (ce_info, |
| 7572 | + test ); |
| 7573 | + |
| 7574 | + /* We do not support multiple tests. */ |
| 7575 | + if ( ce_info |
| 7576 | + && ce_info->num_multiple_test_blocks > 0 ) |
| 7577 | + return NULL_RTX; |
| 7578 | + |
| 7579 | + pattern = gen_rtx_COND_EXEC (VOIDmode, test, op); |
| 7580 | + |
| 7581 | + if ( !reload_completed ) |
| 7582 | + { |
| 7583 | + rtx start; |
| 7584 | + int num_insns; |
| 7585 | + int max_insns = MAX_CONDITIONAL_EXECUTE; |
| 7586 | + |
| 7587 | + if ( !ce_info ) |
| 7588 | + return op; |
| 7589 | + |
| 7590 | + /* Check if the insn is not suitable for conditional |
| 7591 | + execution. */ |
| 7592 | + start_sequence (); |
| 7593 | + cond_exec_insn = emit_insn (pattern); |
| 7594 | + if ( recog_memoized (cond_exec_insn) < 0 |
| 7595 | + && can_create_pseudo_p () ) |
| 7596 | + { |
| 7597 | + /* Insn is not suitable for conditional execution, try |
| 7598 | + to fix it up by using an extra scratch register or |
| 7599 | + by pulling the operation outside the if-then-else |
| 7600 | + and then emiting a conditional move inside the if-then-else. */ |
| 7601 | + end_sequence (); |
| 7602 | + if ( GET_CODE (op) != SET |
| 7603 | + || !REG_P (SET_DEST (op)) |
| 7604 | + || GET_CODE (SET_SRC (op)) == IF_THEN_ELSE |
| 7605 | + || GET_MODE_SIZE (mode) > UNITS_PER_WORD ) |
| 7606 | + return NULL_RTX; |
| 7607 | + |
| 7608 | + /* Check if any of the input operands to the insn is set inside the |
| 7609 | + current block. */ |
| 7610 | + if ( current_bb->index == ce_info->then_bb->index ) |
| 7611 | + start = PREV_INSN (BB_HEAD (ce_info->then_bb)); |
| 7612 | + else |
| 7613 | + start = PREV_INSN (BB_HEAD (ce_info->else_bb)); |
| 7614 | + |
| 7615 | + |
| 7616 | + for ( bb_insn = next_nonnote_insn (start); bb_insn != insn; bb_insn = next_nonnote_insn (bb_insn) ) |
| 7617 | + { |
| 7618 | + rtx set = single_set (bb_insn); |
| 7619 | + |
| 7620 | + if ( set && reg_mentioned_p (SET_DEST (set), SET_SRC (op))) |
| 7621 | + { |
| 7622 | + inputs_set_outside_ifblock = 0; |
| 7623 | + break; |
| 7624 | + } |
| 7625 | + } |
| 7626 | + |
| 7627 | + cmp_insn = prev_nonnote_insn (BB_END (ce_info->test_bb)); |
| 7628 | + |
| 7629 | + |
| 7630 | + /* Check if we can insert more insns. */ |
| 7631 | + num_insns = ( ce_info->num_then_insns + |
| 7632 | + ce_info->num_else_insns + |
| 7633 | + ce_info->num_cond_clobber_insns + |
| 7634 | + ce_info->num_extra_move_insns ); |
| 7635 | + |
| 7636 | + if ( ce_info->num_else_insns != 0 ) |
| 7637 | + max_insns *=2; |
| 7638 | + |
| 7639 | + if ( num_insns >= max_insns ) |
| 7640 | + return NULL_RTX; |
| 7641 | + |
| 7642 | + /* Check if we have an instruction which might be converted to |
| 7643 | + conditional form if we give it a scratch register to clobber. */ |
| 7644 | + { |
| 7645 | + rtx clobber_insn; |
| 7646 | + rtx scratch_reg = gen_reg_rtx (mode); |
| 7647 | + rtx new_pattern = copy_rtx (pattern); |
| 7648 | + rtx set_src = SET_SRC (COND_EXEC_CODE (new_pattern)); |
| 7649 | + |
| 7650 | + rtx clobber = gen_rtx_CLOBBER (mode, scratch_reg); |
| 7651 | + rtx vec[2] = { COND_EXEC_CODE (new_pattern), clobber }; |
| 7652 | + COND_EXEC_CODE (new_pattern) = gen_rtx_PARALLEL (mode, gen_rtvec_v (2, vec)); |
| 7653 | + |
| 7654 | + start_sequence (); |
| 7655 | + clobber_insn = emit_insn (new_pattern); |
| 7656 | + |
| 7657 | + if ( recog_memoized (clobber_insn) >= 0 |
| 7658 | + && ( ( GET_RTX_LENGTH (GET_CODE (set_src)) == 2 |
| 7659 | + && CONST_INT_P (XEXP (set_src, 1)) |
| 7660 | + && avr32_const_ok_for_constraint_p (INTVAL (XEXP (set_src, 1)), 'K', "Ks08") ) |
| 7661 | + || !ce_info->else_bb |
| 7662 | + || current_bb->index == ce_info->else_bb->index )) |
| 7663 | + { |
| 7664 | + end_sequence (); |
| 7665 | + /* Force the insn to be recognized again. */ |
| 7666 | + INSN_CODE (insn) = -1; |
| 7667 | + |
| 7668 | + /* If this is the first change in this IF-block then |
| 7669 | + signal that we have made a change. */ |
| 7670 | + if ( ce_info->num_cond_clobber_insns == 0 |
| 7671 | + && ce_info->num_extra_move_insns == 0 ) |
| 7672 | + *num_true_changes += 1; |
| 7673 | + |
| 7674 | + ce_info->num_cond_clobber_insns++; |
| 7675 | + |
| 7676 | + if (dump_file) |
| 7677 | + fprintf (dump_file, |
| 7678 | + "\nReplacing INSN %d with an insn using a scratch register for later ifcvt passes...\n", |
| 7679 | + INSN_UID (insn)); |
| 7680 | + |
| 7681 | + return COND_EXEC_CODE (new_pattern); |
| 7682 | + } |
| 7683 | + end_sequence (); |
| 7684 | + } |
| 7685 | + |
| 7686 | + if ( inputs_set_outside_ifblock ) |
| 7687 | + { |
| 7688 | + /* Check if the insn before the cmp is an and which used |
| 7689 | + together with the cmp can be optimized into a bld. If |
| 7690 | + so then we should try to put the insn before the and |
| 7691 | + so that we can catch the bld peephole. */ |
| 7692 | + rtx set; |
| 7693 | + rtx insn_before_cmp_insn = prev_nonnote_insn (cmp_insn); |
| 7694 | + if (insn_before_cmp_insn |
| 7695 | + && (set = single_set (insn_before_cmp_insn)) |
| 7696 | + && GET_CODE (SET_SRC (set)) == AND |
| 7697 | + && one_bit_set_operand (XEXP (SET_SRC (set), 1), SImode) |
| 7698 | + /* Also make sure that the insn does not set any |
| 7699 | + of the input operands to the insn we are pulling out. */ |
| 7700 | + && !reg_mentioned_p (SET_DEST (set), SET_SRC (op)) ) |
| 7701 | + cmp_insn = prev_nonnote_insn (cmp_insn); |
| 7702 | + |
| 7703 | + /* We can try to put the operation outside the if-then-else |
| 7704 | + blocks and insert a move. */ |
| 7705 | + if ( !insn_invalid_p (insn) |
| 7706 | + /* Do not allow conditional insns to be moved outside the |
| 7707 | + if-then-else. */ |
| 7708 | + && !reg_mentioned_p (cc0_rtx, insn) |
| 7709 | + /* We cannot move memory loads outside of the if-then-else |
| 7710 | + since the memory access should not be perfomed if the |
| 7711 | + condition is not met. */ |
| 7712 | + && !mem_mentioned_p (SET_SRC (op)) ) |
| 7713 | + { |
| 7714 | + rtx scratch_reg = gen_reg_rtx (mode); |
| 7715 | + rtx op_pattern = copy_rtx (op); |
| 7716 | + rtx new_insn, seq; |
| 7717 | + rtx link, prev_link; |
| 7718 | + op = copy_rtx (op); |
| 7719 | + /* Emit the operation to a temp reg before the compare, |
| 7720 | + and emit a move inside the if-then-else, hoping that the |
| 7721 | + whole if-then-else can be converted to conditional |
| 7722 | + execution. */ |
| 7723 | + SET_DEST (op_pattern) = scratch_reg; |
| 7724 | + start_sequence (); |
| 7725 | + new_insn = emit_insn (op_pattern); |
| 7726 | + seq = get_insns(); |
| 7727 | + end_sequence (); |
| 7728 | + |
| 7729 | + /* Check again that the insn is valid. For some insns the insn might |
| 7730 | + become invalid if the destination register is changed. Ie. for mulacc |
| 7731 | + operations. */ |
| 7732 | + if ( insn_invalid_p (new_insn) ) |
| 7733 | + return NULL_RTX; |
| 7734 | + |
| 7735 | + emit_insn_before_setloc (seq, cmp_insn, INSN_LOCATOR (insn)); |
| 7736 | + |
| 7737 | + if (dump_file) |
| 7738 | + fprintf (dump_file, |
| 7739 | + "\nMoving INSN %d out of IF-block by adding INSN %d...\n", |
| 7740 | + INSN_UID (insn), INSN_UID (new_insn)); |
| 7741 | + |
| 7742 | + ce_info->extra_move_insns[ce_info->num_extra_move_insns] = insn; |
| 7743 | + ce_info->moved_insns[ce_info->num_extra_move_insns] = new_insn; |
| 7744 | + XEXP (op, 1) = scratch_reg; |
| 7745 | + /* Force the insn to be recognized again. */ |
| 7746 | + INSN_CODE (insn) = -1; |
| 7747 | + |
| 7748 | + /* Move REG_DEAD notes to the moved insn. */ |
| 7749 | + prev_link = NULL_RTX; |
| 7750 | + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) |
| 7751 | + { |
| 7752 | + if (REG_NOTE_KIND (link) == REG_DEAD) |
| 7753 | + { |
| 7754 | + /* Add the REG_DEAD note to the new insn. */ |
| 7755 | + rtx dead_reg = XEXP (link, 0); |
| 7756 | + REG_NOTES (new_insn) = gen_rtx_EXPR_LIST (REG_DEAD, dead_reg, REG_NOTES (new_insn)); |
| 7757 | + /* Remove the REG_DEAD note from the insn we convert to a move. */ |
| 7758 | + if ( prev_link ) |
| 7759 | + XEXP (prev_link, 1) = XEXP (link, 1); |
| 7760 | + else |
| 7761 | + REG_NOTES (insn) = XEXP (link, 1); |
| 7762 | + } |
| 7763 | + else |
| 7764 | + { |
| 7765 | + prev_link = link; |
| 7766 | + } |
| 7767 | + } |
| 7768 | + /* Add a REG_DEAD note to signal that the scratch register is dead. */ |
| 7769 | + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, scratch_reg, REG_NOTES (insn)); |
| 7770 | + |
| 7771 | + /* If this is the first change in this IF-block then |
| 7772 | + signal that we have made a change. */ |
| 7773 | + if ( ce_info->num_cond_clobber_insns == 0 |
| 7774 | + && ce_info->num_extra_move_insns == 0 ) |
| 7775 | + *num_true_changes += 1; |
| 7776 | + |
| 7777 | + ce_info->num_extra_move_insns++; |
| 7778 | + return op; |
| 7779 | + } |
| 7780 | + } |
| 7781 | + |
| 7782 | + /* We failed to fixup the insns, so this if-then-else can not be made |
| 7783 | + conditional. Just return NULL_RTX so that the if-then-else conversion |
| 7784 | + for this if-then-else will be cancelled. */ |
| 7785 | + return NULL_RTX; |
| 7786 | + } |
| 7787 | + end_sequence (); |
| 7788 | + return op; |
| 7789 | + } |
| 7790 | + |
| 7791 | + /* Signal that we have started if conversion after reload, which means |
| 7792 | + that it should be safe to split all the predicable clobber insns which |
| 7793 | + did not become cond_exec back into a simpler form if possible. */ |
| 7794 | + cfun->machine->ifcvt_after_reload = 1; |
| 7795 | + |
| 7796 | + return pattern; |
| 7797 | +} |
| 7798 | + |
| 7799 | + |
| 7800 | +void |
| 7801 | +avr32_ifcvt_modify_cancel ( ce_if_block_t *ce_info, int *num_true_changes) |
| 7802 | +{ |
| 7803 | + int n; |
| 7804 | + |
| 7805 | + if ( ce_info->num_extra_move_insns > 0 |
| 7806 | + && ce_info->num_cond_clobber_insns == 0) |
| 7807 | + /* Signal that we did not do any changes after all. */ |
| 7808 | + *num_true_changes -= 1; |
| 7809 | + |
| 7810 | + /* Remove any inserted move insns. */ |
| 7811 | + for ( n = 0; n < ce_info->num_extra_move_insns; n++ ) |
| 7812 | + { |
| 7813 | + rtx link, prev_link; |
| 7814 | + |
| 7815 | + /* Remove REG_DEAD note since we are not needing the scratch register anyway. */ |
| 7816 | + prev_link = NULL_RTX; |
| 7817 | + for (link = REG_NOTES (ce_info->extra_move_insns[n]); link; link = XEXP (link, 1)) |
| 7818 | + { |
| 7819 | + if (REG_NOTE_KIND (link) == REG_DEAD) |
| 7820 | + { |
| 7821 | + if ( prev_link ) |
| 7822 | + XEXP (prev_link, 1) = XEXP (link, 1); |
| 7823 | + else |
| 7824 | + REG_NOTES (ce_info->extra_move_insns[n]) = XEXP (link, 1); |
| 7825 | + } |
| 7826 | + else |
| 7827 | + { |
| 7828 | + prev_link = link; |
| 7829 | + } |
| 7830 | + } |
| 7831 | + |
| 7832 | + /* Revert all reg_notes for the moved insn. */ |
| 7833 | + for (link = REG_NOTES (ce_info->moved_insns[n]); link; link = XEXP (link, 1)) |
| 7834 | + { |
| 7835 | + REG_NOTES (ce_info->extra_move_insns[n]) = gen_rtx_EXPR_LIST (REG_NOTE_KIND (link), |
| 7836 | + XEXP (link, 0), |
| 7837 | + REG_NOTES (ce_info->extra_move_insns[n])); |
| 7838 | + } |
| 7839 | + |
| 7840 | + /* Remove the moved insn. */ |
| 7841 | + remove_insn ( ce_info->moved_insns[n] ); |
| 7842 | + } |
| 7843 | +} |
| 7844 | + |
| 7845 | + |
| 7846 | +/* Function returning TRUE if INSN with OPERANDS is a splittable |
| 7847 | + conditional immediate clobber insn. We assume that the insn is |
| 7848 | + already a conditional immediate clobber insns and do not check |
| 7849 | + for that. */ |
| 7850 | +int |
| 7851 | +avr32_cond_imm_clobber_splittable (rtx insn, rtx operands[]) |
| 7852 | +{ |
| 7853 | + if ( REGNO (operands[0]) == REGNO (operands[1]) ) |
| 7854 | + { |
| 7855 | + if ( (GET_CODE (SET_SRC (XVECEXP (PATTERN (insn),0,0))) == PLUS |
| 7856 | + && !avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'I', "Is21")) |
| 7857 | + || (GET_CODE (SET_SRC (XVECEXP (PATTERN (insn),0,0))) == MINUS |
| 7858 | + && !avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'K', "Ks21"))) |
| 7859 | + return FALSE; |
| 7860 | + } |
| 7861 | + else if ( (logical_binary_operator (SET_SRC (XVECEXP (PATTERN (insn),0,0)), VOIDmode) |
| 7862 | + || (GET_CODE (SET_SRC (XVECEXP (PATTERN (insn),0,0))) == PLUS |
| 7863 | + && !avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'I', "Is16")) |
| 7864 | + || (GET_CODE (SET_SRC (XVECEXP (PATTERN (insn),0,0))) == MINUS |
| 7865 | + && !avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'K', "Ks16"))) ) |
| 7866 | + return FALSE; |
| 7867 | + |
| 7868 | + return TRUE; |
| 7869 | +} |
| 7870 | + |
| 7871 | + |
| 7872 | +/* Function for getting an integer value from a const_int or const_double |
| 7873 | + expression regardless of the HOST_WIDE_INT size. Each target cpu word |
| 7874 | + will be put into the val array where the LSW will be stored at the lowest |
| 7875 | + address and so forth. Assumes that const_expr is either a const_int or |
| 7876 | + const_double. Only valid for modes which have sizes that are a multiple |
| 7877 | + of the word size. |
| 7878 | +*/ |
| 7879 | +void |
| 7880 | +avr32_get_intval (enum machine_mode mode, rtx const_expr, HOST_WIDE_INT *val) |
| 7881 | +{ |
| 7882 | + int words_in_mode = GET_MODE_SIZE (mode)/UNITS_PER_WORD; |
| 7883 | + const int words_in_const_int = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; |
| 7884 | + |
| 7885 | + if ( GET_CODE(const_expr) == CONST_DOUBLE ){ |
| 7886 | + HOST_WIDE_INT hi = CONST_DOUBLE_HIGH(const_expr); |
| 7887 | + HOST_WIDE_INT lo = CONST_DOUBLE_LOW(const_expr); |
| 7888 | + /* Evaluate hi and lo values of const_double. */ |
| 7889 | + avr32_get_intval (mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0), |
| 7890 | + GEN_INT (lo), |
| 7891 | + &val[0]); |
| 7892 | + avr32_get_intval (mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0), |
| 7893 | + GEN_INT (hi), |
| 7894 | + &val[words_in_const_int]); |
| 7895 | + } else if ( GET_CODE(const_expr) == CONST_INT ){ |
| 7896 | + HOST_WIDE_INT value = INTVAL(const_expr); |
| 7897 | + int word; |
| 7898 | + for ( word = 0; (word < words_in_mode) && (word < words_in_const_int); word++ ){ |
| 7899 | + /* Shift word up to the MSW and shift down again to extract the |
| 7900 | + word and sign-extend. */ |
| 7901 | + int lshift = (words_in_const_int - word - 1) * BITS_PER_WORD; |
| 7902 | + int rshift = (words_in_const_int-1) * BITS_PER_WORD; |
| 7903 | + val[word] = (value << lshift) >> rshift; |
| 7904 | + } |
| 7905 | + |
| 7906 | + for ( ; word < words_in_mode; word++ ){ |
| 7907 | + /* Just put the sign bits in the remaining words. */ |
| 7908 | + val[word] = value < 0 ? -1 : 0; |
| 7909 | + } |
| 7910 | + } |
| 7911 | +} |
| 7912 | + |
| 7913 | + |
| 7914 | +void |
| 7915 | +avr32_split_const_expr (enum machine_mode mode, enum machine_mode new_mode, |
| 7916 | + rtx expr, rtx *split_expr) |
| 7917 | +{ |
| 7918 | + int i, word; |
| 7919 | + int words_in_intval = GET_MODE_SIZE (mode)/UNITS_PER_WORD; |
| 7920 | + int words_in_split_values = GET_MODE_SIZE (new_mode)/UNITS_PER_WORD; |
| 7921 | + const int words_in_const_int = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; |
| 7922 | + HOST_WIDE_INT *val = alloca (words_in_intval * UNITS_PER_WORD); |
| 7923 | + |
| 7924 | + avr32_get_intval (mode, expr, val); |
| 7925 | + |
| 7926 | + for ( i=0; i < (words_in_intval/words_in_split_values); i++ ) |
| 7927 | + { |
| 7928 | + HOST_WIDE_INT value_lo = 0, value_hi = 0; |
| 7929 | + for ( word = 0; word < words_in_split_values; word++ ) |
| 7930 | + { |
| 7931 | + if ( word >= words_in_const_int ) |
| 7932 | + value_hi |= ((val[i * words_in_split_values + word] & |
| 7933 | + (((HOST_WIDE_INT)1 << BITS_PER_WORD)-1)) |
| 7934 | + << (BITS_PER_WORD * (word - words_in_const_int))); |
| 7935 | + else |
| 7936 | + value_lo |= ((val[i * words_in_split_values + word] & |
| 7937 | + (((HOST_WIDE_INT)1 << BITS_PER_WORD)-1)) |
| 7938 | + << (BITS_PER_WORD * word)); |
| 7939 | + } |
| 7940 | + split_expr[i] = immed_double_const(value_lo, value_hi, new_mode); |
| 7941 | + } |
| 7942 | +} |
| 7943 | + |
| 7944 | + |
| 7945 | +/* Set up library functions to comply to AVR32 ABI */ |
| 7946 | +static void |
| 7947 | +avr32_init_libfuncs (void) |
| 7948 | +{ |
| 7949 | + /* Convert gcc run-time function names to AVR32 ABI names */ |
| 7950 | + |
| 7951 | + /* Double-precision floating-point arithmetic. */ |
| 7952 | + set_optab_libfunc (neg_optab, DFmode, NULL); |
| 7953 | + |
| 7954 | + /* Double-precision comparisons. */ |
| 7955 | + set_optab_libfunc (eq_optab, DFmode, "__avr32_f64_cmp_eq"); |
| 7956 | + set_optab_libfunc (ne_optab, DFmode, NULL); |
| 7957 | + set_optab_libfunc (lt_optab, DFmode, "__avr32_f64_cmp_lt"); |
| 7958 | + set_optab_libfunc (le_optab, DFmode, NULL); |
| 7959 | + set_optab_libfunc (ge_optab, DFmode, "__avr32_f64_cmp_ge"); |
| 7960 | + set_optab_libfunc (gt_optab, DFmode, NULL); |
| 7961 | + |
| 7962 | + /* Single-precision floating-point arithmetic. */ |
| 7963 | + set_optab_libfunc (smul_optab, SFmode, "__avr32_f32_mul"); |
| 7964 | + set_optab_libfunc (neg_optab, SFmode, NULL); |
| 7965 | + |
| 7966 | + /* Single-precision comparisons. */ |
| 7967 | + set_optab_libfunc (eq_optab, SFmode, "__avr32_f32_cmp_eq"); |
| 7968 | + set_optab_libfunc (ne_optab, SFmode, NULL); |
| 7969 | + set_optab_libfunc (lt_optab, SFmode, "__avr32_f32_cmp_lt"); |
| 7970 | + set_optab_libfunc (le_optab, SFmode, NULL); |
| 7971 | + set_optab_libfunc (ge_optab, SFmode, "__avr32_f32_cmp_ge"); |
| 7972 | + set_optab_libfunc (gt_optab, SFmode, NULL); |
| 7973 | + |
| 7974 | + /* Floating-point to integer conversions. */ |
| 7975 | + set_conv_libfunc (sfix_optab, SImode, DFmode, "__avr32_f64_to_s32"); |
| 7976 | + set_conv_libfunc (ufix_optab, SImode, DFmode, "__avr32_f64_to_u32"); |
| 7977 | + set_conv_libfunc (sfix_optab, DImode, DFmode, "__avr32_f64_to_s64"); |
| 7978 | + set_conv_libfunc (ufix_optab, DImode, DFmode, "__avr32_f64_to_u64"); |
| 7979 | + set_conv_libfunc (sfix_optab, SImode, SFmode, "__avr32_f32_to_s32"); |
| 7980 | + set_conv_libfunc (ufix_optab, SImode, SFmode, "__avr32_f32_to_u32"); |
| 7981 | + set_conv_libfunc (sfix_optab, DImode, SFmode, "__avr32_f32_to_s64"); |
| 7982 | + set_conv_libfunc (ufix_optab, DImode, SFmode, "__avr32_f32_to_u64"); |
| 7983 | + |
| 7984 | + /* Conversions between floating types. */ |
| 7985 | + set_conv_libfunc (trunc_optab, SFmode, DFmode, "__avr32_f64_to_f32"); |
| 7986 | + set_conv_libfunc (sext_optab, DFmode, SFmode, "__avr32_f32_to_f64"); |
| 7987 | + |
| 7988 | + /* Integer to floating-point conversions. Table 8. */ |
| 7989 | + set_conv_libfunc (sfloat_optab, DFmode, SImode, "__avr32_s32_to_f64"); |
| 7990 | + set_conv_libfunc (sfloat_optab, DFmode, DImode, "__avr32_s64_to_f64"); |
| 7991 | + set_conv_libfunc (sfloat_optab, SFmode, SImode, "__avr32_s32_to_f32"); |
| 7992 | + set_conv_libfunc (sfloat_optab, SFmode, DImode, "__avr32_s64_to_f32"); |
| 7993 | + set_conv_libfunc (ufloat_optab, DFmode, SImode, "__avr32_u32_to_f64"); |
| 7994 | + set_conv_libfunc (ufloat_optab, SFmode, SImode, "__avr32_u32_to_f32"); |
| 7995 | + /* TODO: Add these to gcc library functions */ |
| 7996 | + //set_conv_libfunc (ufloat_optab, DFmode, DImode, NULL); |
| 7997 | + //set_conv_libfunc (ufloat_optab, SFmode, DImode, NULL); |
| 7998 | + |
| 7999 | + /* Long long. Table 9. */ |
| 8000 | + set_optab_libfunc (smul_optab, DImode, "__avr32_mul64"); |
| 8001 | + set_optab_libfunc (sdiv_optab, DImode, "__avr32_sdiv64"); |
| 8002 | + set_optab_libfunc (udiv_optab, DImode, "__avr32_udiv64"); |
| 8003 | + set_optab_libfunc (smod_optab, DImode, "__avr32_smod64"); |
| 8004 | + set_optab_libfunc (umod_optab, DImode, "__avr32_umod64"); |
| 8005 | + set_optab_libfunc (ashl_optab, DImode, "__avr32_lsl64"); |
| 8006 | + set_optab_libfunc (lshr_optab, DImode, "__avr32_lsr64"); |
| 8007 | + set_optab_libfunc (ashr_optab, DImode, "__avr32_asr64"); |
| 8008 | + |
| 8009 | + /* Floating point library functions which have fast versions. */ |
| 8010 | + if ( TARGET_FAST_FLOAT ) |
| 8011 | + { |
| 8012 | + set_optab_libfunc (sdiv_optab, DFmode, "__avr32_f64_div_fast"); |
| 8013 | + set_optab_libfunc (smul_optab, DFmode, "__avr32_f64_mul_fast"); |
| 8014 | + set_optab_libfunc (add_optab, DFmode, "__avr32_f64_add_fast"); |
| 8015 | + set_optab_libfunc (sub_optab, DFmode, "__avr32_f64_sub_fast"); |
| 8016 | + set_optab_libfunc (add_optab, SFmode, "__avr32_f32_add_fast"); |
| 8017 | + set_optab_libfunc (sub_optab, SFmode, "__avr32_f32_sub_fast"); |
| 8018 | + set_optab_libfunc (sdiv_optab, SFmode, "__avr32_f32_div_fast"); |
| 8019 | + } |
| 8020 | + else |
| 8021 | + { |
| 8022 | + set_optab_libfunc (sdiv_optab, DFmode, "__avr32_f64_div"); |
| 8023 | + set_optab_libfunc (smul_optab, DFmode, "__avr32_f64_mul"); |
| 8024 | + set_optab_libfunc (add_optab, DFmode, "__avr32_f64_add"); |
| 8025 | + set_optab_libfunc (sub_optab, DFmode, "__avr32_f64_sub"); |
| 8026 | + set_optab_libfunc (add_optab, SFmode, "__avr32_f32_add"); |
| 8027 | + set_optab_libfunc (sub_optab, SFmode, "__avr32_f32_sub"); |
| 8028 | + set_optab_libfunc (sdiv_optab, SFmode, "__avr32_f32_div"); |
| 8029 | + } |
| 8030 | +} |
| 8031 | + |
| 8032 | + |
| 8033 | +/* Record a flashvault declaration. */ |
| 8034 | +static void |
| 8035 | +flashvault_decl_list_add (unsigned int vector_num, const char *name) |
| 8036 | +{ |
| 8037 | + struct flashvault_decl_list *p; |
| 8038 | + |
| 8039 | + p = (struct flashvault_decl_list *) |
| 8040 | + xmalloc (sizeof (struct flashvault_decl_list)); |
| 8041 | + p->next = flashvault_decl_list_head; |
| 8042 | + p->name = name; |
| 8043 | + p->vector_num = vector_num; |
| 8044 | + flashvault_decl_list_head = p; |
| 8045 | +} |
| 8046 | + |
| 8047 | + |
| 8048 | +static void |
| 8049 | +avr32_file_end (void) |
| 8050 | +{ |
| 8051 | + struct flashvault_decl_list *p; |
| 8052 | + unsigned int num_entries = 0; |
| 8053 | + |
| 8054 | + /* Check if a list of flashvault declarations exists. */ |
| 8055 | + if (flashvault_decl_list_head != NULL) |
| 8056 | + { |
| 8057 | + /* Calculate the number of entries in the table. */ |
| 8058 | + for (p = flashvault_decl_list_head; p != NULL; p = p->next) |
| 8059 | + { |
| 8060 | + num_entries++; |
| 8061 | + } |
| 8062 | + |
| 8063 | + /* Generate the beginning of the flashvault data table. */ |
| 8064 | + fputs ("\t.global __fv_table\n" |
| 8065 | + "\t.data\n" |
| 8066 | + "\t.align 2\n" |
| 8067 | + "\t.set .LFVTABLE, . + 0\n" |
| 8068 | + "\t.type __fv_table, @object\n", asm_out_file); |
| 8069 | + /* Each table entry is 8 bytes. */ |
| 8070 | + fprintf (asm_out_file, "\t.size __fv_table, %u\n", (num_entries * 8)); |
| 8071 | + |
| 8072 | + fputs("__fv_table:\n", asm_out_file); |
| 8073 | + |
| 8074 | + for (p = flashvault_decl_list_head; p != NULL; p = p->next) |
| 8075 | + { |
| 8076 | + /* Output table entry. */ |
| 8077 | + fprintf (asm_out_file, |
| 8078 | + "\t.align 2\n" |
| 8079 | + "\t.int %u\n", p->vector_num); |
| 8080 | + fprintf (asm_out_file, |
| 8081 | + "\t.align 2\n" |
| 8082 | + "\t.int %s\n", p->name); |
| 8083 | + } |
| 8084 | + } |
| 8085 | +} |
| 8086 | --- /dev/null |
| 8087 | +++ b/gcc/config/avr32/avr32-elf.h |
| 8088 | @@ -0,0 +1,91 @@ |
| 8089 | +/* |
| 8090 | + Elf specific definitions. |
| 8091 | + Copyright 2003,2004,2005,2006,2007,2008,2009 Atmel Corporation. |
| 8092 | + |
| 8093 | + This file is part of GCC. |
| 8094 | + |
| 8095 | + This program is free software; you can redistribute it and/or modify |
| 8096 | + it under the terms of the GNU General Public License as published by |
| 8097 | + the Free Software Foundation; either version 2 of the License, or |
| 8098 | + (at your option) any later version. |
| 8099 | + |
| 8100 | + This program is distributed in the hope that it will be useful, |
| 8101 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 8102 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 8103 | + GNU General Public License for more details. |
| 8104 | + |
| 8105 | + You should have received a copy of the GNU General Public License |
| 8106 | + along with this program; if not, write to the Free Software |
| 8107 | + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 8108 | + |
| 8109 | + |
| 8110 | +/***************************************************************************** |
| 8111 | + * Controlling the Compiler Driver, 'gcc' |
| 8112 | + *****************************************************************************/ |
| 8113 | + |
| 8114 | +/* Run-time Target Specification. */ |
| 8115 | +#undef TARGET_VERSION |
| 8116 | +#define TARGET_VERSION fputs (" (AVR32 GNU with ELF)", stderr); |
| 8117 | + |
| 8118 | +/* |
| 8119 | +Another C string constant used much like LINK_SPEC. The |
| 8120 | +difference between the two is that STARTFILE_SPEC is used at |
| 8121 | +the very beginning of the command given to the linker. |
| 8122 | + |
| 8123 | +If this macro is not defined, a default is provided that loads the |
| 8124 | +standard C startup file from the usual place. See gcc.c. |
| 8125 | +*/ |
| 8126 | +#if 0 |
| 8127 | +#undef STARTFILE_SPEC |
| 8128 | +#define STARTFILE_SPEC "crt0%O%s crti%O%s crtbegin%O%s" |
| 8129 | +#endif |
| 8130 | +#undef STARTFILE_SPEC |
| 8131 | +#define STARTFILE_SPEC "%{mflashvault: crtfv.o%s} %{!mflashvault: crt0.o%s} \ |
| 8132 | + crti.o%s crtbegin.o%s" |
| 8133 | + |
| 8134 | +#undef LINK_SPEC |
| 8135 | +#define LINK_SPEC "%{muse-oscall:--defsym __do_not_use_oscall_coproc__=0} %{mrelax|O*:%{mno-relax|O0|O1: ;:--relax}} %{mpart=uc3a3revd:-mavr32elf_uc3a3256s;:%{mpart=*:-mavr32elf_%*}} %{mcpu=*:-mavr32elf_%*}" |
| 8136 | + |
| 8137 | + |
| 8138 | +/* |
| 8139 | +Another C string constant used much like LINK_SPEC. The |
| 8140 | +difference between the two is that ENDFILE_SPEC is used at |
| 8141 | +the very end of the command given to the linker. |
| 8142 | + |
| 8143 | +Do not define this macro if it does not need to do anything. |
| 8144 | +*/ |
| 8145 | +#undef ENDFILE_SPEC |
| 8146 | +#define ENDFILE_SPEC "crtend%O%s crtn%O%s" |
| 8147 | + |
| 8148 | + |
| 8149 | +/* Target CPU builtins. */ |
| 8150 | +#define TARGET_CPU_CPP_BUILTINS() \ |
| 8151 | + do \ |
| 8152 | + { \ |
| 8153 | + builtin_define ("__avr32__"); \ |
| 8154 | + builtin_define ("__AVR32__"); \ |
| 8155 | + builtin_define ("__AVR32_ELF__"); \ |
| 8156 | + builtin_define (avr32_part->macro); \ |
| 8157 | + builtin_define (avr32_arch->macro); \ |
| 8158 | + if (avr32_arch->uarch_type == UARCH_TYPE_AVR32A) \ |
| 8159 | + builtin_define ("__AVR32_AVR32A__"); \ |
| 8160 | + else \ |
| 8161 | + builtin_define ("__AVR32_AVR32B__"); \ |
| 8162 | + if (TARGET_UNALIGNED_WORD) \ |
| 8163 | + builtin_define ("__AVR32_HAS_UNALIGNED_WORD__"); \ |
| 8164 | + if (TARGET_SIMD) \ |
| 8165 | + builtin_define ("__AVR32_HAS_SIMD__"); \ |
| 8166 | + if (TARGET_DSP) \ |
| 8167 | + builtin_define ("__AVR32_HAS_DSP__"); \ |
| 8168 | + if (TARGET_RMW) \ |
| 8169 | + builtin_define ("__AVR32_HAS_RMW__"); \ |
| 8170 | + if (TARGET_BRANCH_PRED) \ |
| 8171 | + builtin_define ("__AVR32_HAS_BRANCH_PRED__"); \ |
| 8172 | + if (TARGET_FAST_FLOAT) \ |
| 8173 | + builtin_define ("__AVR32_FAST_FLOAT__"); \ |
| 8174 | + if (TARGET_FLASHVAULT) \ |
| 8175 | + builtin_define ("__AVR32_FLASHVAULT__"); \ |
| 8176 | + if (TARGET_NO_MUL_INSNS) \ |
| 8177 | + builtin_define ("__AVR32_NO_MUL__"); \ |
| 8178 | + } \ |
| 8179 | + while (0) |
| 8180 | --- /dev/null |
| 8181 | +++ b/gcc/config/avr32/avr32.h |
| 8182 | @@ -0,0 +1,3316 @@ |
| 8183 | +/* |
| 8184 | + Definitions of target machine for AVR32. |
| 8185 | + Copyright 2003,2004,2005,2006,2007,2008,2009,2010 Atmel Corporation. |
| 8186 | + |
| 8187 | + This file is part of GCC. |
| 8188 | + |
| 8189 | + This program is free software; you can redistribute it and/or modify |
| 8190 | + it under the terms of the GNU General Public License as published by |
| 8191 | + the Free Software Foundation; either version 2 of the License, or |
| 8192 | + (at your option) any later version. |
| 8193 | + |
| 8194 | + This program is distributed in the hope that it will be useful, |
| 8195 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 8196 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 8197 | + GNU General Public License for more details. |
| 8198 | + |
| 8199 | + You should have received a copy of the GNU General Public License |
| 8200 | + along with this program; if not, write to the Free Software |
| 8201 | + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 8202 | + |
| 8203 | +#ifndef GCC_AVR32_H |
| 8204 | +#define GCC_AVR32_H |
| 8205 | + |
| 8206 | + |
| 8207 | +#ifndef OBJECT_FORMAT_ELF |
| 8208 | +#error avr32.h included before elfos.h |
| 8209 | +#endif |
| 8210 | + |
| 8211 | +#ifndef LOCAL_LABEL_PREFIX |
| 8212 | +#define LOCAL_LABEL_PREFIX "." |
| 8213 | +#endif |
| 8214 | + |
| 8215 | +#ifndef SUBTARGET_CPP_SPEC |
| 8216 | +#define SUBTARGET_CPP_SPEC "-D__ELF__" |
| 8217 | +#endif |
| 8218 | + |
| 8219 | + |
| 8220 | +extern struct rtx_def *avr32_compare_op0; |
| 8221 | +extern struct rtx_def *avr32_compare_op1; |
| 8222 | + |
| 8223 | +/* comparison type */ |
| 8224 | +enum avr32_cmp_type { |
| 8225 | + CMP_QI, /* 1 byte ->char */ |
| 8226 | + CMP_HI, /* 2 byte->half word */ |
| 8227 | + CMP_SI, /* four byte->word*/ |
| 8228 | + CMP_DI, /* eight byte->double word */ |
| 8229 | + CMP_SF, /* single precision floats */ |
| 8230 | + CMP_MAX /* max comparison type */ |
| 8231 | +}; |
| 8232 | + |
| 8233 | +extern enum avr32_cmp_type avr32_branch_type; /* type of branch to use */ |
| 8234 | + |
| 8235 | + |
| 8236 | +extern struct rtx_def *avr32_acc_cache; |
| 8237 | + |
| 8238 | +/* cache instruction op5 codes */ |
| 8239 | +#define AVR32_CACHE_INVALIDATE_ICACHE 1 |
| 8240 | + |
| 8241 | +/* |
| 8242 | +These bits describe the different types of function supported by the AVR32 |
| 8243 | +backend. They are exclusive, e.g. a function cannot be both a normal function |
| 8244 | +and an interworked function. Knowing the type of a function is important for |
| 8245 | +determining its prologue and epilogue sequences. Note value 7 is currently |
| 8246 | +unassigned. Also note that the interrupt function types all have bit 2 set, |
| 8247 | +so that they can be tested for easily. Note that 0 is deliberately chosen for |
| 8248 | +AVR32_FT_UNKNOWN so that when the machine_function structure is initialized |
| 8249 | +(to zero) func_type will default to unknown. This will force the first use of |
| 8250 | +avr32_current_func_type to call avr32_compute_func_type. |
| 8251 | +*/ |
| 8252 | +#define AVR32_FT_UNKNOWN 0 /* Type has not yet been determined. */ |
| 8253 | +#define AVR32_FT_NORMAL 1 /* Normal function. */ |
| 8254 | +#define AVR32_FT_ACALL 2 /* An acall function. */ |
| 8255 | +#define AVR32_FT_EXCEPTION_HANDLER 3 /* A C++ exception handler. */ |
| 8256 | +#define AVR32_FT_ISR_FULL 4 /* A fully shadowed interrupt mode. */ |
| 8257 | +#define AVR32_FT_ISR_HALF 5 /* A half shadowed interrupt mode. */ |
| 8258 | +#define AVR32_FT_ISR_NONE 6 /* No shadow registers. */ |
| 8259 | + |
| 8260 | +#define AVR32_FT_TYPE_MASK ((1 << 3) - 1) |
| 8261 | + |
| 8262 | +/* In addition functions can have several type modifiers, outlined by these bit masks: */ |
| 8263 | +#define AVR32_FT_INTERRUPT (1 << 2) /* Note overlap with FT_ISR and above. */ |
| 8264 | +#define AVR32_FT_NAKED (1 << 3) /* No prologue or epilogue. */ |
| 8265 | +#define AVR32_FT_VOLATILE (1 << 4) /* Does not return. */ |
| 8266 | +#define AVR32_FT_NESTED (1 << 5) /* Embedded inside another func. */ |
| 8267 | +#define AVR32_FT_FLASHVAULT (1 << 6) /* Flashvault function call. */ |
| 8268 | +#define AVR32_FT_FLASHVAULT_IMPL (1 << 7) /* Function definition in FlashVault. */ |
| 8269 | + |
| 8270 | + |
| 8271 | +/* Some macros to test these flags. */ |
| 8272 | +#define AVR32_FUNC_TYPE(t) (t & AVR32_FT_TYPE_MASK) |
| 8273 | +#define IS_INTERRUPT(t) (t & AVR32_FT_INTERRUPT) |
| 8274 | +#define IS_NAKED(t) (t & AVR32_FT_NAKED) |
| 8275 | +#define IS_VOLATILE(t) (t & AVR32_FT_VOLATILE) |
| 8276 | +#define IS_NESTED(t) (t & AVR32_FT_NESTED) |
| 8277 | +#define IS_FLASHVAULT(t) (t & AVR32_FT_FLASHVAULT) |
| 8278 | +#define IS_FLASHVAULT_IMPL(t) (t & AVR32_FT_FLASHVAULT_IMPL) |
| 8279 | + |
| 8280 | +#define SYMBOL_FLAG_RMW_ADDR_SHIFT SYMBOL_FLAG_MACH_DEP_SHIFT |
| 8281 | +#define SYMBOL_REF_RMW_ADDR(RTX) \ |
| 8282 | + ((SYMBOL_REF_FLAGS (RTX) & (1 << SYMBOL_FLAG_RMW_ADDR_SHIFT)) != 0) |
| 8283 | + |
| 8284 | + |
| 8285 | +typedef struct minipool_labels |
| 8286 | +GTY ((chain_next ("%h.next"), chain_prev ("%h.prev"))) |
| 8287 | +{ |
| 8288 | + rtx label; |
| 8289 | + struct minipool_labels *prev; |
| 8290 | + struct minipool_labels *next; |
| 8291 | +} minipool_labels; |
| 8292 | + |
| 8293 | +/* A C structure for machine-specific, per-function data. |
| 8294 | + This is added to the cfun structure. */ |
| 8295 | + |
| 8296 | +typedef struct machine_function |
| 8297 | +GTY (()) |
| 8298 | +{ |
| 8299 | + /* Records the type of the current function. */ |
| 8300 | + unsigned long func_type; |
| 8301 | + /* List of minipool labels, use for checking if code label is valid in a |
| 8302 | + memory expression */ |
| 8303 | + minipool_labels *minipool_label_head; |
| 8304 | + minipool_labels *minipool_label_tail; |
| 8305 | + int ifcvt_after_reload; |
| 8306 | +} machine_function; |
| 8307 | + |
| 8308 | +/* Initialize data used by insn expanders. This is called from insn_emit, |
| 8309 | + once for every function before code is generated. */ |
| 8310 | +#define INIT_EXPANDERS avr32_init_expanders () |
| 8311 | + |
| 8312 | +/****************************************************************************** |
| 8313 | + * SPECS |
| 8314 | + *****************************************************************************/ |
| 8315 | + |
| 8316 | +#ifndef ASM_SPEC |
| 8317 | +#define ASM_SPEC "%{fpic:--pic} %{mrelax|O*:%{mno-relax|O0|O1: ;:--linkrelax}} %{march=ucr2nomul:-march=ucr2;:%{march=*:-march=%*}} %{mpart=uc3a3revd:-mpart=uc3a3256s;:%{mpart=*:-mpart=%*}}" |
| 8318 | +#endif |
| 8319 | + |
| 8320 | +#ifndef MULTILIB_DEFAULTS |
| 8321 | +#define MULTILIB_DEFAULTS { "march=ap", "" } |
| 8322 | +#endif |
| 8323 | + |
| 8324 | +/****************************************************************************** |
| 8325 | + * Run-time Target Specification |
| 8326 | + *****************************************************************************/ |
| 8327 | +#ifndef TARGET_VERSION |
| 8328 | +#define TARGET_VERSION fprintf(stderr, " (AVR32, GNU assembler syntax)"); |
| 8329 | +#endif |
| 8330 | + |
| 8331 | + |
| 8332 | +/* Part types. Keep this in sync with the order of avr32_part_types in avr32.c*/ |
| 8333 | +enum part_type |
| 8334 | +{ |
| 8335 | + PART_TYPE_AVR32_NONE, |
| 8336 | + PART_TYPE_AVR32_AP7000, |
| 8337 | + PART_TYPE_AVR32_AP7001, |
| 8338 | + PART_TYPE_AVR32_AP7002, |
| 8339 | + PART_TYPE_AVR32_AP7200, |
| 8340 | + PART_TYPE_AVR32_UC3A0128, |
| 8341 | + PART_TYPE_AVR32_UC3A0256, |
| 8342 | + PART_TYPE_AVR32_UC3A0512, |
| 8343 | + PART_TYPE_AVR32_UC3A0512ES, |
| 8344 | + PART_TYPE_AVR32_UC3A1128, |
| 8345 | + PART_TYPE_AVR32_UC3A1256, |
| 8346 | + PART_TYPE_AVR32_UC3A1512, |
| 8347 | + PART_TYPE_AVR32_UC3A1512ES, |
| 8348 | + PART_TYPE_AVR32_UC3A3REVD, |
| 8349 | + PART_TYPE_AVR32_UC3A364, |
| 8350 | + PART_TYPE_AVR32_UC3A364S, |
| 8351 | + PART_TYPE_AVR32_UC3A3128, |
| 8352 | + PART_TYPE_AVR32_UC3A3128S, |
| 8353 | + PART_TYPE_AVR32_UC3A3256, |
| 8354 | + PART_TYPE_AVR32_UC3A3256S, |
| 8355 | + PART_TYPE_AVR32_UC3A464, |
| 8356 | + PART_TYPE_AVR32_UC3A464S, |
| 8357 | + PART_TYPE_AVR32_UC3A4128, |
| 8358 | + PART_TYPE_AVR32_UC3A4128S, |
| 8359 | + PART_TYPE_AVR32_UC3A4256, |
| 8360 | + PART_TYPE_AVR32_UC3A4256S, |
| 8361 | + PART_TYPE_AVR32_UC3B064, |
| 8362 | + PART_TYPE_AVR32_UC3B0128, |
| 8363 | + PART_TYPE_AVR32_UC3B0256, |
| 8364 | + PART_TYPE_AVR32_UC3B0256ES, |
| 8365 | + PART_TYPE_AVR32_UC3B0512, |
| 8366 | + PART_TYPE_AVR32_UC3B0512REVC, |
| 8367 | + PART_TYPE_AVR32_UC3B164, |
| 8368 | + PART_TYPE_AVR32_UC3B1128, |
| 8369 | + PART_TYPE_AVR32_UC3B1256, |
| 8370 | + PART_TYPE_AVR32_UC3B1256ES, |
| 8371 | + PART_TYPE_AVR32_UC3B1512, |
| 8372 | + PART_TYPE_AVR32_UC3B1512REVC, |
| 8373 | + PART_TYPE_AVR32_UC64D3, |
| 8374 | + PART_TYPE_AVR32_UC128D3, |
| 8375 | + PART_TYPE_AVR32_UC64D4, |
| 8376 | + PART_TYPE_AVR32_UC128D4, |
| 8377 | + PART_TYPE_AVR32_UC3C0512CREVC, |
| 8378 | + PART_TYPE_AVR32_UC3C1512CREVC, |
| 8379 | + PART_TYPE_AVR32_UC3C2512CREVC, |
| 8380 | + PART_TYPE_AVR32_UC3L0256, |
| 8381 | + PART_TYPE_AVR32_UC3L0128, |
| 8382 | + PART_TYPE_AVR32_UC3L064, |
| 8383 | + PART_TYPE_AVR32_UC3L032, |
| 8384 | + PART_TYPE_AVR32_UC3L016, |
| 8385 | + PART_TYPE_AVR32_UC3L064REVB, |
| 8386 | + PART_TYPE_AVR32_UC64L3U, |
| 8387 | + PART_TYPE_AVR32_UC128L3U, |
| 8388 | + PART_TYPE_AVR32_UC256L3U, |
| 8389 | + PART_TYPE_AVR32_UC64L4U, |
| 8390 | + PART_TYPE_AVR32_UC128L4U, |
| 8391 | + PART_TYPE_AVR32_UC256L4U, |
| 8392 | + PART_TYPE_AVR32_UC3C064C, |
| 8393 | + PART_TYPE_AVR32_UC3C0128C, |
| 8394 | + PART_TYPE_AVR32_UC3C0256C, |
| 8395 | + PART_TYPE_AVR32_UC3C0512C, |
| 8396 | + PART_TYPE_AVR32_UC3C164C, |
| 8397 | + PART_TYPE_AVR32_UC3C1128C, |
| 8398 | + PART_TYPE_AVR32_UC3C1256C, |
| 8399 | + PART_TYPE_AVR32_UC3C1512C, |
| 8400 | + PART_TYPE_AVR32_UC3C264C, |
| 8401 | + PART_TYPE_AVR32_UC3C2128C, |
| 8402 | + PART_TYPE_AVR32_UC3C2256C, |
| 8403 | + PART_TYPE_AVR32_UC3C2512C, |
| 8404 | + PART_TYPE_AVR32_MXT768E |
| 8405 | +}; |
| 8406 | + |
| 8407 | +/* Microarchitectures. */ |
| 8408 | +enum microarchitecture_type |
| 8409 | +{ |
| 8410 | + UARCH_TYPE_AVR32A, |
| 8411 | + UARCH_TYPE_AVR32B, |
| 8412 | + UARCH_TYPE_NONE |
| 8413 | +}; |
| 8414 | + |
| 8415 | +/* Architectures types which specifies the pipeline. |
| 8416 | + Keep this in sync with avr32_arch_types in avr32.c |
| 8417 | + and the pipeline attribute in avr32.md */ |
| 8418 | +enum architecture_type |
| 8419 | +{ |
| 8420 | + ARCH_TYPE_AVR32_AP, |
| 8421 | + ARCH_TYPE_AVR32_UCR1, |
| 8422 | + ARCH_TYPE_AVR32_UCR2, |
| 8423 | + ARCH_TYPE_AVR32_UCR2NOMUL, |
| 8424 | + ARCH_TYPE_AVR32_UCR3, |
| 8425 | + ARCH_TYPE_AVR32_UCR3FP, |
| 8426 | + ARCH_TYPE_AVR32_NONE |
| 8427 | +}; |
| 8428 | + |
| 8429 | +/* Flag specifying if the cpu has support for DSP instructions.*/ |
| 8430 | +#define FLAG_AVR32_HAS_DSP (1 << 0) |
| 8431 | +/* Flag specifying if the cpu has support for Read-Modify-Write |
| 8432 | + instructions.*/ |
| 8433 | +#define FLAG_AVR32_HAS_RMW (1 << 1) |
| 8434 | +/* Flag specifying if the cpu has support for SIMD instructions. */ |
| 8435 | +#define FLAG_AVR32_HAS_SIMD (1 << 2) |
| 8436 | +/* Flag specifying if the cpu has support for unaligned memory word access. */ |
| 8437 | +#define FLAG_AVR32_HAS_UNALIGNED_WORD (1 << 3) |
| 8438 | +/* Flag specifying if the cpu has support for branch prediction. */ |
| 8439 | +#define FLAG_AVR32_HAS_BRANCH_PRED (1 << 4) |
| 8440 | +/* Flag specifying if the cpu has support for a return stack. */ |
| 8441 | +#define FLAG_AVR32_HAS_RETURN_STACK (1 << 5) |
| 8442 | +/* Flag specifying if the cpu has caches. */ |
| 8443 | +#define FLAG_AVR32_HAS_CACHES (1 << 6) |
| 8444 | +/* Flag specifying if the cpu has support for v2 insns. */ |
| 8445 | +#define FLAG_AVR32_HAS_V2_INSNS (1 << 7) |
| 8446 | +/* Flag specifying that the cpu has buggy mul insns. */ |
| 8447 | +#define FLAG_AVR32_HAS_NO_MUL_INSNS (1 << 8) |
| 8448 | +/* Flag specifying that the device has FPU instructions according |
| 8449 | + to AVR32002 specifications*/ |
| 8450 | +#define FLAG_AVR32_HAS_FPU (1 << 9) |
| 8451 | + |
| 8452 | +/* Structure for holding information about different avr32 CPUs/parts */ |
| 8453 | +struct part_type_s |
| 8454 | +{ |
| 8455 | + const char *const name; |
| 8456 | + enum part_type part_type; |
| 8457 | + enum architecture_type arch_type; |
| 8458 | + /* Must lie outside user's namespace. NULL == no macro. */ |
| 8459 | + const char *const macro; |
| 8460 | +}; |
| 8461 | + |
| 8462 | +/* Structure for holding information about different avr32 pipeline |
| 8463 | + architectures. */ |
| 8464 | +struct arch_type_s |
| 8465 | +{ |
| 8466 | + const char *const name; |
| 8467 | + enum architecture_type arch_type; |
| 8468 | + enum microarchitecture_type uarch_type; |
| 8469 | + const unsigned long feature_flags; |
| 8470 | + /* Must lie outside user's namespace. NULL == no macro. */ |
| 8471 | + const char *const macro; |
| 8472 | +}; |
| 8473 | + |
| 8474 | +extern const struct part_type_s *avr32_part; |
| 8475 | +extern const struct arch_type_s *avr32_arch; |
| 8476 | + |
| 8477 | +#define TARGET_SIMD (avr32_arch->feature_flags & FLAG_AVR32_HAS_SIMD) |
| 8478 | +#define TARGET_DSP (avr32_arch->feature_flags & FLAG_AVR32_HAS_DSP) |
| 8479 | +#define TARGET_RMW (avr32_arch->feature_flags & FLAG_AVR32_HAS_RMW) |
| 8480 | +#define TARGET_UNALIGNED_WORD (avr32_arch->feature_flags & FLAG_AVR32_HAS_UNALIGNED_WORD) |
| 8481 | +#define TARGET_BRANCH_PRED (avr32_arch->feature_flags & FLAG_AVR32_HAS_BRANCH_PRED) |
| 8482 | +#define TARGET_RETURN_STACK (avr32_arch->feature_flags & FLAG_AVR32_HAS_RETURN_STACK) |
| 8483 | +#define TARGET_V2_INSNS (avr32_arch->feature_flags & FLAG_AVR32_HAS_V2_INSNS) |
| 8484 | +#define TARGET_CACHES (avr32_arch->feature_flags & FLAG_AVR32_HAS_CACHES) |
| 8485 | +#define TARGET_NO_MUL_INSNS (avr32_arch->feature_flags & FLAG_AVR32_HAS_NO_MUL_INSNS) |
| 8486 | +#define TARGET_ARCH_AP (avr32_arch->arch_type == ARCH_TYPE_AVR32_AP) |
| 8487 | +#define TARGET_ARCH_UCR1 (avr32_arch->arch_type == ARCH_TYPE_AVR32_UCR1) |
| 8488 | +#define TARGET_ARCH_UCR2 (avr32_arch->arch_type == ARCH_TYPE_AVR32_UCR2) |
| 8489 | +#define TARGET_ARCH_UC (TARGET_ARCH_UCR1 || TARGET_ARCH_UCR2) |
| 8490 | +#define TARGET_UARCH_AVR32A (avr32_arch->uarch_type == UARCH_TYPE_AVR32A) |
| 8491 | +#define TARGET_UARCH_AVR32B (avr32_arch->uarch_type == UARCH_TYPE_AVR32B) |
| 8492 | +#define TARGET_ARCH_FPU (avr32_arch->feature_flags & FLAG_AVR32_HAS_FPU) |
| 8493 | + |
| 8494 | +#define CAN_DEBUG_WITHOUT_FP |
| 8495 | + |
| 8496 | + |
| 8497 | + |
| 8498 | + |
| 8499 | +/****************************************************************************** |
| 8500 | + * Storage Layout |
| 8501 | + *****************************************************************************/ |
| 8502 | + |
| 8503 | +/* |
| 8504 | +Define this macro to have the value 1 if the most significant bit in a |
| 8505 | +byte has the lowest number; otherwise define it to have the value zero. |
| 8506 | +This means that bit-field instructions count from the most significant |
| 8507 | +bit. If the machine has no bit-field instructions, then this must still |
| 8508 | +be defined, but it doesn't matter which value it is defined to. This |
| 8509 | +macro need not be a constant. |
| 8510 | + |
| 8511 | +This macro does not affect the way structure fields are packed into |
| 8512 | +bytes or words; that is controlled by BYTES_BIG_ENDIAN. |
| 8513 | +*/ |
| 8514 | +#define BITS_BIG_ENDIAN 0 |
| 8515 | + |
| 8516 | +/* |
| 8517 | +Define this macro to have the value 1 if the most significant byte in a |
| 8518 | +word has the lowest number. This macro need not be a constant. |
| 8519 | +*/ |
| 8520 | +/* |
| 8521 | + Data is stored in an big-endian way. |
| 8522 | +*/ |
| 8523 | +#define BYTES_BIG_ENDIAN 1 |
| 8524 | + |
| 8525 | +/* |
| 8526 | +Define this macro to have the value 1 if, in a multiword object, the |
| 8527 | +most significant word has the lowest number. This applies to both |
| 8528 | +memory locations and registers; GCC fundamentally assumes that the |
| 8529 | +order of words in memory is the same as the order in registers. This |
| 8530 | +macro need not be a constant. |
| 8531 | +*/ |
| 8532 | +/* |
| 8533 | + Data is stored in an bin-endian way. |
| 8534 | +*/ |
| 8535 | +#define WORDS_BIG_ENDIAN 1 |
| 8536 | + |
| 8537 | +/* |
| 8538 | +Define this macro if WORDS_BIG_ENDIAN is not constant. This must be a |
| 8539 | +constant value with the same meaning as WORDS_BIG_ENDIAN, which will be |
| 8540 | +used only when compiling libgcc2.c. Typically the value will be set |
| 8541 | +based on preprocessor defines. |
| 8542 | +*/ |
| 8543 | +#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN |
| 8544 | + |
| 8545 | +/* |
| 8546 | +Define this macro to have the value 1 if DFmode, XFmode or |
| 8547 | +TFmode floating point numbers are stored in memory with the word |
| 8548 | +containing the sign bit at the lowest address; otherwise define it to |
| 8549 | +have the value 0. This macro need not be a constant. |
| 8550 | + |
| 8551 | +You need not define this macro if the ordering is the same as for |
| 8552 | +multi-word integers. |
| 8553 | +*/ |
| 8554 | +/* #define FLOAT_WORDS_BIG_ENDIAN 1 */ |
| 8555 | + |
| 8556 | +/* |
| 8557 | +Define this macro to be the number of bits in an addressable storage |
| 8558 | +unit (byte); normally 8. |
| 8559 | +*/ |
| 8560 | +#define BITS_PER_UNIT 8 |
| 8561 | + |
| 8562 | +/* |
| 8563 | +Number of bits in a word; normally 32. |
| 8564 | +*/ |
| 8565 | +#define BITS_PER_WORD 32 |
| 8566 | + |
| 8567 | +/* |
| 8568 | +Maximum number of bits in a word. If this is undefined, the default is |
| 8569 | +BITS_PER_WORD. Otherwise, it is the constant value that is the |
| 8570 | +largest value that BITS_PER_WORD can have at run-time. |
| 8571 | +*/ |
| 8572 | +/* MAX_BITS_PER_WORD not defined*/ |
| 8573 | + |
| 8574 | +/* |
| 8575 | +Number of storage units in a word; normally 4. |
| 8576 | +*/ |
| 8577 | +#define UNITS_PER_WORD 4 |
| 8578 | + |
| 8579 | +/* |
| 8580 | +Minimum number of units in a word. If this is undefined, the default is |
| 8581 | +UNITS_PER_WORD. Otherwise, it is the constant value that is the |
| 8582 | +smallest value that UNITS_PER_WORD can have at run-time. |
| 8583 | +*/ |
| 8584 | +/* MIN_UNITS_PER_WORD not defined */ |
| 8585 | + |
| 8586 | +/* |
| 8587 | +Width of a pointer, in bits. You must specify a value no wider than the |
| 8588 | +width of Pmode. If it is not equal to the width of Pmode, |
| 8589 | +you must define POINTERS_EXTEND_UNSIGNED. |
| 8590 | +*/ |
| 8591 | +#define POINTER_SIZE 32 |
| 8592 | + |
| 8593 | +/* |
| 8594 | +A C expression whose value is greater than zero if pointers that need to be |
| 8595 | +extended from being POINTER_SIZE bits wide to Pmode are to |
| 8596 | +be zero-extended and zero if they are to be sign-extended. If the value |
| 8597 | +is less then zero then there must be an "ptr_extend" instruction that |
| 8598 | +extends a pointer from POINTER_SIZE to Pmode. |
| 8599 | + |
| 8600 | +You need not define this macro if the POINTER_SIZE is equal |
| 8601 | +to the width of Pmode. |
| 8602 | +*/ |
| 8603 | +/* #define POINTERS_EXTEND_UNSIGNED */ |
| 8604 | + |
| 8605 | +/* |
| 8606 | +A Macro to update M and UNSIGNEDP when an object whose type |
| 8607 | +is TYPE and which has the specified mode and signedness is to be |
| 8608 | +stored in a register. This macro is only called when TYPE is a |
| 8609 | +scalar type. |
| 8610 | + |
| 8611 | +On most RISC machines, which only have operations that operate on a full |
| 8612 | +register, define this macro to set M to word_mode if |
| 8613 | +M is an integer mode narrower than BITS_PER_WORD. In most |
| 8614 | +cases, only integer modes should be widened because wider-precision |
| 8615 | +floating-point operations are usually more expensive than their narrower |
| 8616 | +counterparts. |
| 8617 | + |
| 8618 | +For most machines, the macro definition does not change UNSIGNEDP. |
| 8619 | +However, some machines, have instructions that preferentially handle |
| 8620 | +either signed or unsigned quantities of certain modes. For example, on |
| 8621 | +the DEC Alpha, 32-bit loads from memory and 32-bit add instructions |
| 8622 | +sign-extend the result to 64 bits. On such machines, set |
| 8623 | +UNSIGNEDP according to which kind of extension is more efficient. |
| 8624 | + |
| 8625 | +Do not define this macro if it would never modify M. |
| 8626 | +*/ |
| 8627 | +#define PROMOTE_MODE(M, UNSIGNEDP, TYPE) \ |
| 8628 | + { \ |
| 8629 | + if (!AGGREGATE_TYPE_P (TYPE) \ |
| 8630 | + && GET_MODE_CLASS (mode) == MODE_INT \ |
| 8631 | + && GET_MODE_SIZE (mode) < 4) \ |
| 8632 | + { \ |
| 8633 | + if (M == QImode) \ |
| 8634 | + (UNSIGNEDP) = 1; \ |
| 8635 | + else if (M == HImode) \ |
| 8636 | + (UNSIGNEDP) = 0; \ |
| 8637 | + (M) = SImode; \ |
| 8638 | + } \ |
| 8639 | + } |
| 8640 | + |
| 8641 | +#define PROMOTE_FUNCTION_MODE(M, UNSIGNEDP, TYPE) \ |
| 8642 | + PROMOTE_MODE(M, UNSIGNEDP, TYPE) |
| 8643 | + |
| 8644 | +/* Define if operations between registers always perform the operation |
| 8645 | + on the full register even if a narrower mode is specified. */ |
| 8646 | +#define WORD_REGISTER_OPERATIONS |
| 8647 | + |
| 8648 | +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD |
| 8649 | + will either zero-extend or sign-extend. The value of this macro should |
| 8650 | + be the code that says which one of the two operations is implicitly |
| 8651 | + done, UNKNOWN if not known. */ |
| 8652 | +#define LOAD_EXTEND_OP(MODE) \ |
| 8653 | + (((MODE) == QImode) ? ZERO_EXTEND \ |
| 8654 | + : ((MODE) == HImode) ? SIGN_EXTEND : UNKNOWN) |
| 8655 | + |
| 8656 | + |
| 8657 | +/* |
| 8658 | +Normal alignment required for function parameters on the stack, in |
| 8659 | +bits. All stack parameters receive at least this much alignment |
| 8660 | +regardless of data type. On most machines, this is the same as the |
| 8661 | +size of an integer. |
| 8662 | +*/ |
| 8663 | +#define PARM_BOUNDARY 32 |
| 8664 | + |
| 8665 | +/* |
| 8666 | +Define this macro to the minimum alignment enforced by hardware for the |
| 8667 | +stack pointer on this machine. The definition is a C expression for the |
| 8668 | +desired alignment (measured in bits). This value is used as a default |
| 8669 | +if PREFERRED_STACK_BOUNDARY is not defined. On most machines, |
| 8670 | +this should be the same as PARM_BOUNDARY. |
| 8671 | +*/ |
| 8672 | +#define STACK_BOUNDARY 32 |
| 8673 | + |
| 8674 | +/* |
| 8675 | +Define this macro if you wish to preserve a certain alignment for the |
| 8676 | +stack pointer, greater than what the hardware enforces. The definition |
| 8677 | +is a C expression for the desired alignment (measured in bits). This |
| 8678 | +macro must evaluate to a value equal to or larger than |
| 8679 | +STACK_BOUNDARY. |
| 8680 | +*/ |
| 8681 | +#define PREFERRED_STACK_BOUNDARY (TARGET_FORCE_DOUBLE_ALIGN ? 64 : 32 ) |
| 8682 | + |
| 8683 | +/* |
| 8684 | +Alignment required for a function entry point, in bits. |
| 8685 | +*/ |
| 8686 | +#define FUNCTION_BOUNDARY 16 |
| 8687 | + |
| 8688 | +/* |
| 8689 | +Biggest alignment that any data type can require on this machine, in bits. |
| 8690 | +*/ |
| 8691 | +#define BIGGEST_ALIGNMENT (TARGET_FORCE_DOUBLE_ALIGN ? 64 : 32 ) |
| 8692 | + |
| 8693 | +/* |
| 8694 | +If defined, the smallest alignment, in bits, that can be given to an |
| 8695 | +object that can be referenced in one operation, without disturbing any |
| 8696 | +nearby object. Normally, this is BITS_PER_UNIT, but may be larger |
| 8697 | +on machines that don't have byte or half-word store operations. |
| 8698 | +*/ |
| 8699 | +#define MINIMUM_ATOMIC_ALIGNMENT BITS_PER_UNIT |
| 8700 | + |
| 8701 | + |
| 8702 | +/* |
| 8703 | +An integer expression for the size in bits of the largest integer machine mode that |
| 8704 | +should actually be used. All integer machine modes of this size or smaller can be |
| 8705 | +used for structures and unions with the appropriate sizes. If this macro is undefined, |
| 8706 | +GET_MODE_BITSIZE (DImode) is assumed.*/ |
| 8707 | +#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode) |
| 8708 | + |
| 8709 | + |
| 8710 | +/* |
| 8711 | +If defined, a C expression to compute the alignment given to a constant |
| 8712 | +that is being placed in memory. CONSTANT is the constant and |
| 8713 | +BASIC_ALIGN is the alignment that the object would ordinarily |
| 8714 | +have. The value of this macro is used instead of that alignment to |
| 8715 | +align the object. |
| 8716 | + |
| 8717 | +If this macro is not defined, then BASIC_ALIGN is used. |
| 8718 | + |
| 8719 | +The typical use of this macro is to increase alignment for string |
| 8720 | +constants to be word aligned so that strcpy calls that copy |
| 8721 | +constants can be done inline. |
| 8722 | +*/ |
| 8723 | +#define CONSTANT_ALIGNMENT(CONSTANT, BASIC_ALIGN) \ |
| 8724 | + ((TREE_CODE(CONSTANT) == STRING_CST) ? BITS_PER_WORD : BASIC_ALIGN) |
| 8725 | + |
| 8726 | +/* Try to align string to a word. */ |
| 8727 | +#define DATA_ALIGNMENT(TYPE, ALIGN) \ |
| 8728 | + ({(TREE_CODE (TYPE) == ARRAY_TYPE \ |
| 8729 | + && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ |
| 8730 | + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN));}) |
| 8731 | + |
| 8732 | +/* Try to align local store strings to a word. */ |
| 8733 | +#define LOCAL_ALIGNMENT(TYPE, ALIGN) \ |
| 8734 | + ({(TREE_CODE (TYPE) == ARRAY_TYPE \ |
| 8735 | + && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ |
| 8736 | + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN));}) |
| 8737 | + |
| 8738 | +/* |
| 8739 | +Define this macro to be the value 1 if instructions will fail to work |
| 8740 | +if given data not on the nominal alignment. If instructions will merely |
| 8741 | +go slower in that case, define this macro as 0. |
| 8742 | +*/ |
| 8743 | +#define STRICT_ALIGNMENT 1 |
| 8744 | + |
| 8745 | +/* |
| 8746 | +Define this if you wish to imitate the way many other C compilers handle |
| 8747 | +alignment of bit-fields and the structures that contain them. |
| 8748 | + |
| 8749 | +The behavior is that the type written for a bit-field (int, |
| 8750 | +short, or other integer type) imposes an alignment for the |
| 8751 | +entire structure, as if the structure really did contain an ordinary |
| 8752 | +field of that type. In addition, the bit-field is placed within the |
| 8753 | +structure so that it would fit within such a field, not crossing a |
| 8754 | +boundary for it. |
| 8755 | + |
| 8756 | +Thus, on most machines, a bit-field whose type is written as int |
| 8757 | +would not cross a four-byte boundary, and would force four-byte |
| 8758 | +alignment for the whole structure. (The alignment used may not be four |
| 8759 | +bytes; it is controlled by the other alignment parameters.) |
| 8760 | + |
| 8761 | +If the macro is defined, its definition should be a C expression; |
| 8762 | +a nonzero value for the expression enables this behavior. |
| 8763 | + |
| 8764 | +Note that if this macro is not defined, or its value is zero, some |
| 8765 | +bit-fields may cross more than one alignment boundary. The compiler can |
| 8766 | +support such references if there are insv, extv, and |
| 8767 | +extzv insns that can directly reference memory. |
| 8768 | + |
| 8769 | +The other known way of making bit-fields work is to define |
| 8770 | +STRUCTURE_SIZE_BOUNDARY as large as BIGGEST_ALIGNMENT. |
| 8771 | +Then every structure can be accessed with fullwords. |
| 8772 | + |
| 8773 | +Unless the machine has bit-field instructions or you define |
| 8774 | +STRUCTURE_SIZE_BOUNDARY that way, you must define |
| 8775 | +PCC_BITFIELD_TYPE_MATTERS to have a nonzero value. |
| 8776 | + |
| 8777 | +If your aim is to make GCC use the same conventions for laying out |
| 8778 | +bit-fields as are used by another compiler, here is how to investigate |
| 8779 | +what the other compiler does. Compile and run this program: |
| 8780 | + |
| 8781 | +struct foo1 |
| 8782 | +{ |
| 8783 | + char x; |
| 8784 | + char :0; |
| 8785 | + char y; |
| 8786 | +}; |
| 8787 | + |
| 8788 | +struct foo2 |
| 8789 | +{ |
| 8790 | + char x; |
| 8791 | + int :0; |
| 8792 | + char y; |
| 8793 | +}; |
| 8794 | + |
| 8795 | +main () |
| 8796 | +{ |
| 8797 | + printf ("Size of foo1 is %d\n", |
| 8798 | + sizeof (struct foo1)); |
| 8799 | + printf ("Size of foo2 is %d\n", |
| 8800 | + sizeof (struct foo2)); |
| 8801 | + exit (0); |
| 8802 | +} |
| 8803 | + |
| 8804 | +If this prints 2 and 5, then the compiler's behavior is what you would |
| 8805 | +get from PCC_BITFIELD_TYPE_MATTERS. |
| 8806 | +*/ |
| 8807 | +#define PCC_BITFIELD_TYPE_MATTERS 1 |
| 8808 | + |
| 8809 | + |
| 8810 | +/****************************************************************************** |
| 8811 | + * Layout of Source Language Data Types |
| 8812 | + *****************************************************************************/ |
| 8813 | + |
| 8814 | +/* |
| 8815 | +A C expression for the size in bits of the type int on the |
| 8816 | +target machine. If you don't define this, the default is one word. |
| 8817 | +*/ |
| 8818 | +#define INT_TYPE_SIZE 32 |
| 8819 | + |
| 8820 | +/* |
| 8821 | +A C expression for the size in bits of the type short on the |
| 8822 | +target machine. If you don't define this, the default is half a word. (If |
| 8823 | +this would be less than one storage unit, it is rounded up to one unit.) |
| 8824 | +*/ |
| 8825 | +#define SHORT_TYPE_SIZE 16 |
| 8826 | + |
| 8827 | +/* |
| 8828 | +A C expression for the size in bits of the type long on the |
| 8829 | +target machine. If you don't define this, the default is one word. |
| 8830 | +*/ |
| 8831 | +#define LONG_TYPE_SIZE 32 |
| 8832 | + |
| 8833 | + |
| 8834 | +/* |
| 8835 | +A C expression for the size in bits of the type long long on the |
| 8836 | +target machine. If you don't define this, the default is two |
| 8837 | +words. If you want to support GNU Ada on your machine, the value of this |
| 8838 | +macro must be at least 64. |
| 8839 | +*/ |
| 8840 | +#define LONG_LONG_TYPE_SIZE 64 |
| 8841 | + |
| 8842 | +/* |
| 8843 | +A C expression for the size in bits of the type char on the |
| 8844 | +target machine. If you don't define this, the default is |
| 8845 | +BITS_PER_UNIT. |
| 8846 | +*/ |
| 8847 | +#define CHAR_TYPE_SIZE 8 |
| 8848 | + |
| 8849 | + |
| 8850 | +/* |
| 8851 | +A C expression for the size in bits of the C++ type bool and |
| 8852 | +C99 type _Bool on the target machine. If you don't define |
| 8853 | +this, and you probably shouldn't, the default is CHAR_TYPE_SIZE. |
| 8854 | +*/ |
| 8855 | +#define BOOL_TYPE_SIZE 8 |
| 8856 | + |
| 8857 | + |
| 8858 | +/* |
| 8859 | +An expression whose value is 1 or 0, according to whether the type |
| 8860 | +char should be signed or unsigned by default. The user can |
| 8861 | +always override this default with the options -fsigned-char |
| 8862 | +and -funsigned-char. |
| 8863 | +*/ |
| 8864 | +/* We are using unsigned char */ |
| 8865 | +#define DEFAULT_SIGNED_CHAR 0 |
| 8866 | + |
| 8867 | + |
| 8868 | +/* |
| 8869 | +A C expression for a string describing the name of the data type to use |
| 8870 | +for size values. The typedef name size_t is defined using the |
| 8871 | +contents of the string. |
| 8872 | + |
| 8873 | +The string can contain more than one keyword. If so, separate them with |
| 8874 | +spaces, and write first any length keyword, then unsigned if |
| 8875 | +appropriate, and finally int. The string must exactly match one |
| 8876 | +of the data type names defined in the function |
| 8877 | +init_decl_processing in the file c-decl.c. You may not |
| 8878 | +omit int or change the order - that would cause the compiler to |
| 8879 | +crash on startup. |
| 8880 | + |
| 8881 | +If you don't define this macro, the default is "long unsigned int". |
| 8882 | +*/ |
| 8883 | +#define SIZE_TYPE "long unsigned int" |
| 8884 | + |
| 8885 | +/* |
| 8886 | +A C expression for a string describing the name of the data type to use |
| 8887 | +for the result of subtracting two pointers. The typedef name |
| 8888 | +ptrdiff_t is defined using the contents of the string. See |
| 8889 | +SIZE_TYPE above for more information. |
| 8890 | + |
| 8891 | +If you don't define this macro, the default is "long int". |
| 8892 | +*/ |
| 8893 | +#define PTRDIFF_TYPE "long int" |
| 8894 | + |
| 8895 | + |
| 8896 | +/* |
| 8897 | +A C expression for the size in bits of the data type for wide |
| 8898 | +characters. This is used in cpp, which cannot make use of |
| 8899 | +WCHAR_TYPE. |
| 8900 | +*/ |
| 8901 | +#define WCHAR_TYPE_SIZE 32 |
| 8902 | + |
| 8903 | + |
| 8904 | +/* |
| 8905 | +A C expression for a string describing the name of the data type to |
| 8906 | +use for wide characters passed to printf and returned from |
| 8907 | +getwc. The typedef name wint_t is defined using the |
| 8908 | +contents of the string. See SIZE_TYPE above for more |
| 8909 | +information. |
| 8910 | + |
| 8911 | +If you don't define this macro, the default is "unsigned int". |
| 8912 | +*/ |
| 8913 | +#define WINT_TYPE "unsigned int" |
| 8914 | + |
| 8915 | +/* |
| 8916 | +A C expression for a string describing the name of the data type that |
| 8917 | +can represent any value of any standard or extended signed integer type. |
| 8918 | +The typedef name intmax_t is defined using the contents of the |
| 8919 | +string. See SIZE_TYPE above for more information. |
| 8920 | + |
| 8921 | +If you don't define this macro, the default is the first of |
| 8922 | +"int", "long int", or "long long int" that has as |
| 8923 | +much precision as long long int. |
| 8924 | +*/ |
| 8925 | +#define INTMAX_TYPE "long long int" |
| 8926 | + |
| 8927 | +/* |
| 8928 | +A C expression for a string describing the name of the data type that |
| 8929 | +can represent any value of any standard or extended unsigned integer |
| 8930 | +type. The typedef name uintmax_t is defined using the contents |
| 8931 | +of the string. See SIZE_TYPE above for more information. |
| 8932 | + |
| 8933 | +If you don't define this macro, the default is the first of |
| 8934 | +"unsigned int", "long unsigned int", or "long long unsigned int" |
| 8935 | +that has as much precision as long long unsigned int. |
| 8936 | +*/ |
| 8937 | +#define UINTMAX_TYPE "long long unsigned int" |
| 8938 | + |
| 8939 | + |
| 8940 | +/****************************************************************************** |
| 8941 | + * Register Usage |
| 8942 | + *****************************************************************************/ |
| 8943 | + |
| 8944 | +/* Convert from gcc internal register number to register number |
| 8945 | + used in assembly code */ |
| 8946 | +#define ASM_REGNUM(reg) (LAST_REGNUM - (reg)) |
| 8947 | + |
| 8948 | +/* Convert between register number used in assembly to gcc |
| 8949 | + internal register number */ |
| 8950 | +#define INTERNAL_REGNUM(reg) (LAST_REGNUM - (reg)) |
| 8951 | + |
| 8952 | +/** Basic Characteristics of Registers **/ |
| 8953 | + |
| 8954 | +/* |
| 8955 | +Number of hardware registers known to the compiler. They receive |
| 8956 | +numbers 0 through FIRST_PSEUDO_REGISTER-1; thus, the first |
| 8957 | +pseudo register's number really is assigned the number |
| 8958 | +FIRST_PSEUDO_REGISTER. |
| 8959 | +*/ |
| 8960 | +#define FIRST_PSEUDO_REGISTER (LAST_REGNUM + 1) |
| 8961 | + |
| 8962 | +#define FIRST_REGNUM 0 |
| 8963 | +#define LAST_REGNUM 15 |
| 8964 | + |
| 8965 | +/* |
| 8966 | +An initializer that says which registers are used for fixed purposes |
| 8967 | +all throughout the compiled code and are therefore not available for |
| 8968 | +general allocation. These would include the stack pointer, the frame |
| 8969 | +pointer (except on machines where that can be used as a general |
| 8970 | +register when no frame pointer is needed), the program counter on |
| 8971 | +machines where that is considered one of the addressable registers, |
| 8972 | +and any other numbered register with a standard use. |
| 8973 | + |
| 8974 | +This information is expressed as a sequence of numbers, separated by |
| 8975 | +commas and surrounded by braces. The nth number is 1 if |
| 8976 | +register n is fixed, 0 otherwise. |
| 8977 | + |
| 8978 | +The table initialized from this macro, and the table initialized by |
| 8979 | +the following one, may be overridden at run time either automatically, |
| 8980 | +by the actions of the macro CONDITIONAL_REGISTER_USAGE, or by |
| 8981 | +the user with the command options -ffixed-[reg], |
| 8982 | +-fcall-used-[reg] and -fcall-saved-[reg]. |
| 8983 | +*/ |
| 8984 | + |
| 8985 | +/* The internal gcc register numbers are reversed |
| 8986 | + compared to the real register numbers since |
| 8987 | + gcc expects data types stored over multiple |
| 8988 | + registers in the register file to be big endian |
| 8989 | + if the memory layout is big endian. But this |
| 8990 | + is not the case for avr32 so we fake a big |
| 8991 | + endian register file. */ |
| 8992 | + |
| 8993 | +#define FIXED_REGISTERS { \ |
| 8994 | + 1, /* Program Counter */ \ |
| 8995 | + 0, /* Link Register */ \ |
| 8996 | + 1, /* Stack Pointer */ \ |
| 8997 | + 0, /* r12 */ \ |
| 8998 | + 0, /* r11 */ \ |
| 8999 | + 0, /* r10 */ \ |
| 9000 | + 0, /* r9 */ \ |
| 9001 | + 0, /* r8 */ \ |
| 9002 | + 0, /* r7 */ \ |
| 9003 | + 0, /* r6 */ \ |
| 9004 | + 0, /* r5 */ \ |
| 9005 | + 0, /* r4 */ \ |
| 9006 | + 0, /* r3 */ \ |
| 9007 | + 0, /* r2 */ \ |
| 9008 | + 0, /* r1 */ \ |
| 9009 | + 0, /* r0 */ \ |
| 9010 | +} |
| 9011 | + |
| 9012 | +/* |
| 9013 | +Like FIXED_REGISTERS but has 1 for each register that is |
| 9014 | +clobbered (in general) by function calls as well as for fixed |
| 9015 | +registers. This macro therefore identifies the registers that are not |
| 9016 | +available for general allocation of values that must live across |
| 9017 | +function calls. |
| 9018 | + |
| 9019 | +If a register has 0 in CALL_USED_REGISTERS, the compiler |
| 9020 | +automatically saves it on function entry and restores it on function |
| 9021 | +exit, if the register is used within the function. |
| 9022 | +*/ |
| 9023 | +#define CALL_USED_REGISTERS { \ |
| 9024 | + 1, /* Program Counter */ \ |
| 9025 | + 0, /* Link Register */ \ |
| 9026 | + 1, /* Stack Pointer */ \ |
| 9027 | + 1, /* r12 */ \ |
| 9028 | + 1, /* r11 */ \ |
| 9029 | + 1, /* r10 */ \ |
| 9030 | + 1, /* r9 */ \ |
| 9031 | + 1, /* r8 */ \ |
| 9032 | + 0, /* r7 */ \ |
| 9033 | + 0, /* r6 */ \ |
| 9034 | + 0, /* r5 */ \ |
| 9035 | + 0, /* r4 */ \ |
| 9036 | + 0, /* r3 */ \ |
| 9037 | + 0, /* r2 */ \ |
| 9038 | + 0, /* r1 */ \ |
| 9039 | + 0, /* r0 */ \ |
| 9040 | +} |
| 9041 | + |
| 9042 | +/* Interrupt functions can only use registers that have already been |
| 9043 | + saved by the prologue, even if they would normally be |
| 9044 | + call-clobbered. */ |
| 9045 | +#define HARD_REGNO_RENAME_OK(SRC, DST) \ |
| 9046 | + (! IS_INTERRUPT (cfun->machine->func_type) || \ |
| 9047 | + df_regs_ever_live_p (DST)) |
| 9048 | + |
| 9049 | + |
| 9050 | +/* |
| 9051 | +Zero or more C statements that may conditionally modify five variables |
| 9052 | +fixed_regs, call_used_regs, global_regs, |
| 9053 | +reg_names, and reg_class_contents, to take into account |
| 9054 | +any dependence of these register sets on target flags. The first three |
| 9055 | +of these are of type char [] (interpreted as Boolean vectors). |
| 9056 | +global_regs is a const char *[], and |
| 9057 | +reg_class_contents is a HARD_REG_SET. Before the macro is |
| 9058 | +called, fixed_regs, call_used_regs, |
| 9059 | +reg_class_contents, and reg_names have been initialized |
| 9060 | +from FIXED_REGISTERS, CALL_USED_REGISTERS, |
| 9061 | +REG_CLASS_CONTENTS, and REGISTER_NAMES, respectively. |
| 9062 | +global_regs has been cleared, and any -ffixed-[reg], |
| 9063 | +-fcall-used-[reg] and -fcall-saved-[reg] |
| 9064 | +command options have been applied. |
| 9065 | + |
| 9066 | +You need not define this macro if it has no work to do. |
| 9067 | + |
| 9068 | +If the usage of an entire class of registers depends on the target |
| 9069 | +flags, you may indicate this to GCC by using this macro to modify |
| 9070 | +fixed_regs and call_used_regs to 1 for each of the |
| 9071 | +registers in the classes which should not be used by GCC. Also define |
| 9072 | +the macro REG_CLASS_FROM_LETTER to return NO_REGS if it |
| 9073 | +is called with a letter for a class that shouldn't be used. |
| 9074 | + |
| 9075 | + (However, if this class is not included in GENERAL_REGS and all |
| 9076 | +of the insn patterns whose constraints permit this class are |
| 9077 | +controlled by target switches, then GCC will automatically avoid using |
| 9078 | +these registers when the target switches are opposed to them.) |
| 9079 | +*/ |
| 9080 | +#define CONDITIONAL_REGISTER_USAGE \ |
| 9081 | + do \ |
| 9082 | + { \ |
| 9083 | + if (flag_pic) \ |
| 9084 | + { \ |
| 9085 | + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ |
| 9086 | + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ |
| 9087 | + } \ |
| 9088 | + } \ |
| 9089 | + while (0) |
| 9090 | + |
| 9091 | + |
| 9092 | +/* |
| 9093 | +If the program counter has a register number, define this as that |
| 9094 | +register number. Otherwise, do not define it. |
| 9095 | +*/ |
| 9096 | + |
| 9097 | +#define LAST_AVR32_REGNUM 16 |
| 9098 | + |
| 9099 | + |
| 9100 | +/** Order of Allocation of Registers **/ |
| 9101 | + |
| 9102 | +/* |
| 9103 | +If defined, an initializer for a vector of integers, containing the |
| 9104 | +numbers of hard registers in the order in which GCC should prefer |
| 9105 | +to use them (from most preferred to least). |
| 9106 | + |
| 9107 | +If this macro is not defined, registers are used lowest numbered first |
| 9108 | +(all else being equal). |
| 9109 | + |
| 9110 | +One use of this macro is on machines where the highest numbered |
| 9111 | +registers must always be saved and the save-multiple-registers |
| 9112 | +instruction supports only sequences of consecutive registers. On such |
| 9113 | +machines, define REG_ALLOC_ORDER to be an initializer that lists |
| 9114 | +the highest numbered allocable register first. |
| 9115 | +*/ |
| 9116 | +#define REG_ALLOC_ORDER \ |
| 9117 | +{ \ |
| 9118 | + INTERNAL_REGNUM(8), \ |
| 9119 | + INTERNAL_REGNUM(9), \ |
| 9120 | + INTERNAL_REGNUM(10), \ |
| 9121 | + INTERNAL_REGNUM(11), \ |
| 9122 | + INTERNAL_REGNUM(12), \ |
| 9123 | + LR_REGNUM, \ |
| 9124 | + INTERNAL_REGNUM(7), \ |
| 9125 | + INTERNAL_REGNUM(6), \ |
| 9126 | + INTERNAL_REGNUM(5), \ |
| 9127 | + INTERNAL_REGNUM(4), \ |
| 9128 | + INTERNAL_REGNUM(3), \ |
| 9129 | + INTERNAL_REGNUM(2), \ |
| 9130 | + INTERNAL_REGNUM(1), \ |
| 9131 | + INTERNAL_REGNUM(0), \ |
| 9132 | + SP_REGNUM, \ |
| 9133 | + PC_REGNUM \ |
| 9134 | +} |
| 9135 | + |
| 9136 | + |
| 9137 | +/** How Values Fit in Registers **/ |
| 9138 | + |
| 9139 | +/* |
| 9140 | +A C expression for the number of consecutive hard registers, starting |
| 9141 | +at register number REGNO, required to hold a value of mode |
| 9142 | +MODE. |
| 9143 | + |
| 9144 | +On a machine where all registers are exactly one word, a suitable |
| 9145 | +definition of this macro is |
| 9146 | + |
| 9147 | +#define HARD_REGNO_NREGS(REGNO, MODE) \ |
| 9148 | + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ |
| 9149 | + / UNITS_PER_WORD) |
| 9150 | +*/ |
| 9151 | +#define HARD_REGNO_NREGS(REGNO, MODE) \ |
| 9152 | + ((unsigned int)((GET_MODE_SIZE(MODE) + UNITS_PER_WORD -1 ) / UNITS_PER_WORD)) |
| 9153 | + |
| 9154 | +/* |
| 9155 | +A C expression that is nonzero if it is permissible to store a value |
| 9156 | +of mode MODE in hard register number REGNO (or in several |
| 9157 | +registers starting with that one). For a machine where all registers |
| 9158 | +are equivalent, a suitable definition is |
| 9159 | + |
| 9160 | + #define HARD_REGNO_MODE_OK(REGNO, MODE) 1 |
| 9161 | + |
| 9162 | +You need not include code to check for the numbers of fixed registers, |
| 9163 | +because the allocation mechanism considers them to be always occupied. |
| 9164 | + |
| 9165 | +On some machines, double-precision values must be kept in even/odd |
| 9166 | +register pairs. You can implement that by defining this macro to reject |
| 9167 | +odd register numbers for such modes. |
| 9168 | + |
| 9169 | +The minimum requirement for a mode to be OK in a register is that the |
| 9170 | +mov[mode] instruction pattern support moves between the |
| 9171 | +register and other hard register in the same class and that moving a |
| 9172 | +value into the register and back out not alter it. |
| 9173 | + |
| 9174 | +Since the same instruction used to move word_mode will work for |
| 9175 | +all narrower integer modes, it is not necessary on any machine for |
| 9176 | +HARD_REGNO_MODE_OK to distinguish between these modes, provided |
| 9177 | +you define patterns movhi, etc., to take advantage of this. This |
| 9178 | +is useful because of the interaction between HARD_REGNO_MODE_OK |
| 9179 | +and MODES_TIEABLE_P; it is very desirable for all integer modes |
| 9180 | +to be tieable. |
| 9181 | + |
| 9182 | +Many machines have special registers for floating point arithmetic. |
| 9183 | +Often people assume that floating point machine modes are allowed only |
| 9184 | +in floating point registers. This is not true. Any registers that |
| 9185 | +can hold integers can safely hold a floating point machine |
| 9186 | +mode, whether or not floating arithmetic can be done on it in those |
| 9187 | +registers. Integer move instructions can be used to move the values. |
| 9188 | + |
| 9189 | +On some machines, though, the converse is true: fixed-point machine |
| 9190 | +modes may not go in floating registers. This is true if the floating |
| 9191 | +registers normalize any value stored in them, because storing a |
| 9192 | +non-floating value there would garble it. In this case, |
| 9193 | +HARD_REGNO_MODE_OK should reject fixed-point machine modes in |
| 9194 | +floating registers. But if the floating registers do not automatically |
| 9195 | +normalize, if you can store any bit pattern in one and retrieve it |
| 9196 | +unchanged without a trap, then any machine mode may go in a floating |
| 9197 | +register, so you can define this macro to say so. |
| 9198 | + |
| 9199 | +The primary significance of special floating registers is rather that |
| 9200 | +they are the registers acceptable in floating point arithmetic |
| 9201 | +instructions. However, this is of no concern to |
| 9202 | +HARD_REGNO_MODE_OK. You handle it by writing the proper |
| 9203 | +constraints for those instructions. |
| 9204 | + |
| 9205 | +On some machines, the floating registers are especially slow to access, |
| 9206 | +so that it is better to store a value in a stack frame than in such a |
| 9207 | +register if floating point arithmetic is not being done. As long as the |
| 9208 | +floating registers are not in class GENERAL_REGS, they will not |
| 9209 | +be used unless some pattern's constraint asks for one. |
| 9210 | +*/ |
| 9211 | +#define HARD_REGNO_MODE_OK(REGNO, MODE) avr32_hard_regno_mode_ok(REGNO, MODE) |
| 9212 | + |
| 9213 | +/* |
| 9214 | +A C expression that is nonzero if a value of mode |
| 9215 | +MODE1 is accessible in mode MODE2 without copying. |
| 9216 | + |
| 9217 | +If HARD_REGNO_MODE_OK(R, MODE1) and |
| 9218 | +HARD_REGNO_MODE_OK(R, MODE2) are always the same for |
| 9219 | +any R, then MODES_TIEABLE_P(MODE1, MODE2) |
| 9220 | +should be nonzero. If they differ for any R, you should define |
| 9221 | +this macro to return zero unless some other mechanism ensures the |
| 9222 | +accessibility of the value in a narrower mode. |
| 9223 | + |
| 9224 | +You should define this macro to return nonzero in as many cases as |
| 9225 | +possible since doing so will allow GCC to perform better register |
| 9226 | +allocation. |
| 9227 | +*/ |
| 9228 | +#define MODES_TIEABLE_P(MODE1, MODE2) \ |
| 9229 | + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) |
| 9230 | + |
| 9231 | + |
| 9232 | + |
| 9233 | +/****************************************************************************** |
| 9234 | + * Register Classes |
| 9235 | + *****************************************************************************/ |
| 9236 | + |
| 9237 | +/* |
| 9238 | +An enumeral type that must be defined with all the register class names |
| 9239 | +as enumeral values. NO_REGS must be first. ALL_REGS |
| 9240 | +must be the last register class, followed by one more enumeral value, |
| 9241 | +LIM_REG_CLASSES, which is not a register class but rather |
| 9242 | +tells how many classes there are. |
| 9243 | + |
| 9244 | +Each register class has a number, which is the value of casting |
| 9245 | +the class name to type int. The number serves as an index |
| 9246 | +in many of the tables described below. |
| 9247 | +*/ |
| 9248 | +enum reg_class |
| 9249 | +{ |
| 9250 | + NO_REGS, |
| 9251 | + GENERAL_REGS, |
| 9252 | + ALL_REGS, |
| 9253 | + LIM_REG_CLASSES |
| 9254 | +}; |
| 9255 | + |
| 9256 | +/* |
| 9257 | +The number of distinct register classes, defined as follows: |
| 9258 | + #define N_REG_CLASSES (int) LIM_REG_CLASSES |
| 9259 | +*/ |
| 9260 | +#define N_REG_CLASSES (int)LIM_REG_CLASSES |
| 9261 | + |
| 9262 | +/* |
| 9263 | +An initializer containing the names of the register classes as C string |
| 9264 | +constants. These names are used in writing some of the debugging dumps. |
| 9265 | +*/ |
| 9266 | +#define REG_CLASS_NAMES \ |
| 9267 | +{ \ |
| 9268 | + "NO_REGS", \ |
| 9269 | + "GENERAL_REGS", \ |
| 9270 | + "ALL_REGS" \ |
| 9271 | +} |
| 9272 | + |
| 9273 | +/* |
| 9274 | +An initializer containing the contents of the register classes, as integers |
| 9275 | +which are bit masks. The nth integer specifies the contents of class |
| 9276 | +n. The way the integer mask is interpreted is that |
| 9277 | +register r is in the class if mask & (1 << r) is 1. |
| 9278 | + |
| 9279 | +When the machine has more than 32 registers, an integer does not suffice. |
| 9280 | +Then the integers are replaced by sub-initializers, braced groupings containing |
| 9281 | +several integers. Each sub-initializer must be suitable as an initializer |
| 9282 | +for the type HARD_REG_SET which is defined in hard-reg-set.h. |
| 9283 | +In this situation, the first integer in each sub-initializer corresponds to |
| 9284 | +registers 0 through 31, the second integer to registers 32 through 63, and |
| 9285 | +so on. |
| 9286 | +*/ |
| 9287 | +#define REG_CLASS_CONTENTS { \ |
| 9288 | + {0x00000000}, /* NO_REGS */ \ |
| 9289 | + {0x0000FFFF}, /* GENERAL_REGS */ \ |
| 9290 | + {0x7FFFFFFF}, /* ALL_REGS */ \ |
| 9291 | +} |
| 9292 | + |
| 9293 | + |
| 9294 | +/* |
| 9295 | +A C expression whose value is a register class containing hard register |
| 9296 | +REGNO. In general there is more than one such class; choose a class |
| 9297 | +which is minimal, meaning that no smaller class also contains the |
| 9298 | +register. |
| 9299 | +*/ |
| 9300 | +#define REGNO_REG_CLASS(REGNO) (GENERAL_REGS) |
| 9301 | + |
| 9302 | +/* |
| 9303 | +A macro whose definition is the name of the class to which a valid |
| 9304 | +base register must belong. A base register is one used in an address |
| 9305 | +which is the register value plus a displacement. |
| 9306 | +*/ |
| 9307 | +#define BASE_REG_CLASS GENERAL_REGS |
| 9308 | + |
| 9309 | +/* |
| 9310 | +This is a variation of the BASE_REG_CLASS macro which allows |
| 9311 | +the selection of a base register in a mode depenedent manner. If |
| 9312 | +mode is VOIDmode then it should return the same value as |
| 9313 | +BASE_REG_CLASS. |
| 9314 | +*/ |
| 9315 | +#define MODE_BASE_REG_CLASS(MODE) BASE_REG_CLASS |
| 9316 | + |
| 9317 | +/* |
| 9318 | +A macro whose definition is the name of the class to which a valid |
| 9319 | +index register must belong. An index register is one used in an |
| 9320 | +address where its value is either multiplied by a scale factor or |
| 9321 | +added to another register (as well as added to a displacement). |
| 9322 | +*/ |
| 9323 | +#define INDEX_REG_CLASS BASE_REG_CLASS |
| 9324 | + |
| 9325 | +/* |
| 9326 | +A C expression which defines the machine-dependent operand constraint |
| 9327 | +letters for register classes. If CHAR is such a letter, the |
| 9328 | +value should be the register class corresponding to it. Otherwise, |
| 9329 | +the value should be NO_REGS. The register letter r, |
| 9330 | +corresponding to class GENERAL_REGS, will not be passed |
| 9331 | +to this macro; you do not need to handle it. |
| 9332 | +*/ |
| 9333 | +#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS |
| 9334 | + |
| 9335 | +/* These assume that REGNO is a hard or pseudo reg number. |
| 9336 | + They give nonzero only if REGNO is a hard reg of the suitable class |
| 9337 | + or a pseudo reg currently allocated to a suitable hard reg. |
| 9338 | + Since they use reg_renumber, they are safe only once reg_renumber |
| 9339 | + has been allocated, which happens in local-alloc.c. */ |
| 9340 | +#define TEST_REGNO(R, TEST, VALUE) \ |
| 9341 | + ((R TEST VALUE) || ((unsigned) reg_renumber[R] TEST VALUE)) |
| 9342 | + |
| 9343 | +/* |
| 9344 | +A C expression which is nonzero if register number num is suitable for use as a base |
| 9345 | +register in operand addresses. It may be either a suitable hard register or a pseudo |
| 9346 | +register that has been allocated such a hard register. |
| 9347 | +*/ |
| 9348 | +#define REGNO_OK_FOR_BASE_P(NUM) TEST_REGNO(NUM, <=, LAST_REGNUM) |
| 9349 | + |
| 9350 | +/* The following macro defines cover classes for Integrated Register |
| 9351 | + Allocator. Cover classes is a set of non-intersected register |
| 9352 | + classes covering all hard registers used for register allocation |
| 9353 | + purpose. Any move between two registers of a cover class should be |
| 9354 | + cheaper than load or store of the registers. The macro value is |
| 9355 | + array of register classes with LIM_REG_CLASSES used as the end |
| 9356 | + marker. */ |
| 9357 | + |
| 9358 | +#define IRA_COVER_CLASSES \ |
| 9359 | +{ \ |
| 9360 | + GENERAL_REGS, LIM_REG_CLASSES \ |
| 9361 | +} |
| 9362 | + |
| 9363 | +/* |
| 9364 | +A C expression which is nonzero if register number NUM is |
| 9365 | +suitable for use as an index register in operand addresses. It may be |
| 9366 | +either a suitable hard register or a pseudo register that has been |
| 9367 | +allocated such a hard register. |
| 9368 | + |
| 9369 | +The difference between an index register and a base register is that |
| 9370 | +the index register may be scaled. If an address involves the sum of |
| 9371 | +two registers, neither one of them scaled, then either one may be |
| 9372 | +labeled the ``base'' and the other the ``index''; but whichever |
| 9373 | +labeling is used must fit the machine's constraints of which registers |
| 9374 | +may serve in each capacity. The compiler will try both labelings, |
| 9375 | +looking for one that is valid, and will reload one or both registers |
| 9376 | +only if neither labeling works. |
| 9377 | +*/ |
| 9378 | +#define REGNO_OK_FOR_INDEX_P(NUM) TEST_REGNO(NUM, <=, LAST_REGNUM) |
| 9379 | + |
| 9380 | +/* |
| 9381 | +A C expression that places additional restrictions on the register class |
| 9382 | +to use when it is necessary to copy value X into a register in class |
| 9383 | +CLASS. The value is a register class; perhaps CLASS, or perhaps |
| 9384 | +another, smaller class. On many machines, the following definition is |
| 9385 | +safe: #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS |
| 9386 | + |
| 9387 | +Sometimes returning a more restrictive class makes better code. For |
| 9388 | +example, on the 68000, when X is an integer constant that is in range |
| 9389 | +for a 'moveq' instruction, the value of this macro is always |
| 9390 | +DATA_REGS as long as CLASS includes the data registers. |
| 9391 | +Requiring a data register guarantees that a 'moveq' will be used. |
| 9392 | + |
| 9393 | +If X is a const_double, by returning NO_REGS |
| 9394 | +you can force X into a memory constant. This is useful on |
| 9395 | +certain machines where immediate floating values cannot be loaded into |
| 9396 | +certain kinds of registers. |
| 9397 | +*/ |
| 9398 | +#define PREFERRED_RELOAD_CLASS(X, CLASS) CLASS |
| 9399 | + |
| 9400 | + |
| 9401 | + |
| 9402 | +/* |
| 9403 | +A C expression for the maximum number of consecutive registers |
| 9404 | +of class CLASS needed to hold a value of mode MODE. |
| 9405 | + |
| 9406 | +This is closely related to the macro HARD_REGNO_NREGS. In fact, |
| 9407 | +the value of the macro CLASS_MAX_NREGS(CLASS, MODE) |
| 9408 | +should be the maximum value of HARD_REGNO_NREGS(REGNO, MODE) |
| 9409 | +for all REGNO values in the class CLASS. |
| 9410 | + |
| 9411 | +This macro helps control the handling of multiple-word values |
| 9412 | +in the reload pass. |
| 9413 | +*/ |
| 9414 | +#define CLASS_MAX_NREGS(CLASS, MODE) /* ToDo:fixme */ \ |
| 9415 | + (unsigned int)((GET_MODE_SIZE(MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) |
| 9416 | + |
| 9417 | + |
| 9418 | +/* |
| 9419 | + Using CONST_OK_FOR_CONSTRAINT_P instead of CONS_OK_FOR_LETTER_P |
| 9420 | + in order to support constraints with more than one letter. |
| 9421 | + Only two letters are then used for constant constraints, |
| 9422 | + the letter 'K' and the letter 'I'. The constraint starting with |
| 9423 | + these letters must consist of four characters. The character following |
| 9424 | + 'K' or 'I' must be either 'u' (unsigned) or 's' (signed) to specify |
| 9425 | + if the constant is zero or sign extended. The last two characters specify |
| 9426 | + the length in bits of the constant. The base constraint letter 'I' means |
| 9427 | + that this is an negated constant, meaning that actually -VAL should be |
| 9428 | + checked to lie withing the valid range instead of VAL which is used when |
| 9429 | + 'K' is the base constraint letter. |
| 9430 | + |
| 9431 | +*/ |
| 9432 | + |
| 9433 | +#define CONSTRAINT_LEN(C, STR) \ |
| 9434 | + ( ((C) == 'K' || (C) == 'I') ? 4 : \ |
| 9435 | + ((C) == 'R') ? 5 : \ |
| 9436 | + ((C) == 'P') ? -1 : \ |
| 9437 | + DEFAULT_CONSTRAINT_LEN((C), (STR)) ) |
| 9438 | + |
| 9439 | +#define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR) \ |
| 9440 | + avr32_const_ok_for_constraint_p(VALUE, C, STR) |
| 9441 | + |
| 9442 | +/* |
| 9443 | +A C expression that defines the machine-dependent operand constraint |
| 9444 | +letters that specify particular ranges of const_double values ('G' or 'H'). |
| 9445 | + |
| 9446 | +If C is one of those letters, the expression should check that |
| 9447 | +VALUE, an RTX of code const_double, is in the appropriate |
| 9448 | +range and return 1 if so, 0 otherwise. If C is not one of those |
| 9449 | +letters, the value should be 0 regardless of VALUE. |
| 9450 | + |
| 9451 | +const_double is used for all floating-point constants and for |
| 9452 | +DImode fixed-point constants. A given letter can accept either |
| 9453 | +or both kinds of values. It can use GET_MODE to distinguish |
| 9454 | +between these kinds. |
| 9455 | +*/ |
| 9456 | +#define CONST_DOUBLE_OK_FOR_LETTER_P(OP, C) \ |
| 9457 | + ((C) == 'G' ? avr32_const_double_immediate(OP) : 0) |
| 9458 | + |
| 9459 | +/* |
| 9460 | +A C expression that defines the optional machine-dependent constraint |
| 9461 | +letters that can be used to segregate specific types of operands, usually |
| 9462 | +memory references, for the target machine. Any letter that is not |
| 9463 | +elsewhere defined and not matched by REG_CLASS_FROM_LETTER |
| 9464 | +may be used. Normally this macro will not be defined. |
| 9465 | + |
| 9466 | +If it is required for a particular target machine, it should return 1 |
| 9467 | +if VALUE corresponds to the operand type represented by the |
| 9468 | +constraint letter C. If C is not defined as an extra |
| 9469 | +constraint, the value returned should be 0 regardless of VALUE. |
| 9470 | + |
| 9471 | +For example, on the ROMP, load instructions cannot have their output |
| 9472 | +in r0 if the memory reference contains a symbolic address. Constraint |
| 9473 | +letter 'Q' is defined as representing a memory address that does |
| 9474 | +not contain a symbolic address. An alternative is specified with |
| 9475 | +a 'Q' constraint on the input and 'r' on the output. The next |
| 9476 | +alternative specifies 'm' on the input and a register class that |
| 9477 | +does not include r0 on the output. |
| 9478 | +*/ |
| 9479 | +#define EXTRA_CONSTRAINT_STR(OP, C, STR) \ |
| 9480 | + ((C) == 'W' ? avr32_address_operand(OP, GET_MODE(OP)) : \ |
| 9481 | + (C) == 'R' ? (avr32_indirect_register_operand(OP, GET_MODE(OP)) || \ |
| 9482 | + (avr32_imm_disp_memory_operand(OP, GET_MODE(OP)) \ |
| 9483 | + && avr32_const_ok_for_constraint_p( \ |
| 9484 | + INTVAL(XEXP(XEXP(OP, 0), 1)), \ |
| 9485 | + (STR)[1], &(STR)[1]))) : \ |
| 9486 | + (C) == 'S' ? avr32_indexed_memory_operand(OP, GET_MODE(OP)) : \ |
| 9487 | + (C) == 'T' ? avr32_const_pool_ref_operand(OP, GET_MODE(OP)) : \ |
| 9488 | + (C) == 'U' ? SYMBOL_REF_RCALL_FUNCTION_P(OP) : \ |
| 9489 | + (C) == 'Z' ? avr32_cop_memory_operand(OP, GET_MODE(OP)) : \ |
| 9490 | + (C) == 'Q' ? avr32_non_rmw_memory_operand(OP, GET_MODE(OP)) : \ |
| 9491 | + (C) == 'Y' ? avr32_rmw_memory_operand(OP, GET_MODE(OP)) : \ |
| 9492 | + 0) |
| 9493 | + |
| 9494 | + |
| 9495 | +#define EXTRA_MEMORY_CONSTRAINT(C, STR) ( ((C) == 'R') || \ |
| 9496 | + ((C) == 'Q') || \ |
| 9497 | + ((C) == 'S') || \ |
| 9498 | + ((C) == 'Y') || \ |
| 9499 | + ((C) == 'Z') ) |
| 9500 | + |
| 9501 | + |
| 9502 | +/* Returns nonzero if op is a function SYMBOL_REF which |
| 9503 | + can be called using an rcall instruction */ |
| 9504 | +#define SYMBOL_REF_RCALL_FUNCTION_P(op) \ |
| 9505 | + ( GET_CODE(op) == SYMBOL_REF \ |
| 9506 | + && SYMBOL_REF_FUNCTION_P(op) \ |
| 9507 | + && SYMBOL_REF_LOCAL_P(op) \ |
| 9508 | + && !SYMBOL_REF_EXTERNAL_P(op) \ |
| 9509 | + && !TARGET_HAS_ASM_ADDR_PSEUDOS ) |
| 9510 | + |
| 9511 | +/****************************************************************************** |
| 9512 | + * Stack Layout and Calling Conventions |
| 9513 | + *****************************************************************************/ |
| 9514 | + |
| 9515 | +/** Basic Stack Layout **/ |
| 9516 | + |
| 9517 | +/* |
| 9518 | +Define this macro if pushing a word onto the stack moves the stack |
| 9519 | +pointer to a smaller address. |
| 9520 | + |
| 9521 | +When we say, ``define this macro if ...,'' it means that the |
| 9522 | +compiler checks this macro only with #ifdef so the precise |
| 9523 | +definition used does not matter. |
| 9524 | +*/ |
| 9525 | +/* pushm decrece SP: *(--SP) <-- Rx */ |
| 9526 | +#define STACK_GROWS_DOWNWARD |
| 9527 | + |
| 9528 | +/* |
| 9529 | +This macro defines the operation used when something is pushed |
| 9530 | +on the stack. In RTL, a push operation will be |
| 9531 | +(set (mem (STACK_PUSH_CODE (reg sp))) ...) |
| 9532 | + |
| 9533 | +The choices are PRE_DEC, POST_DEC, PRE_INC, |
| 9534 | +and POST_INC. Which of these is correct depends on |
| 9535 | +the stack direction and on whether the stack pointer points |
| 9536 | +to the last item on the stack or whether it points to the |
| 9537 | +space for the next item on the stack. |
| 9538 | + |
| 9539 | +The default is PRE_DEC when STACK_GROWS_DOWNWARD is |
| 9540 | +defined, which is almost always right, and PRE_INC otherwise, |
| 9541 | +which is often wrong. |
| 9542 | +*/ |
| 9543 | +/* pushm: *(--SP) <-- Rx */ |
| 9544 | +#define STACK_PUSH_CODE PRE_DEC |
| 9545 | + |
| 9546 | +/* Define this to nonzero if the nominal address of the stack frame |
| 9547 | + is at the high-address end of the local variables; |
| 9548 | + that is, each additional local variable allocated |
| 9549 | + goes at a more negative offset in the frame. */ |
| 9550 | +#define FRAME_GROWS_DOWNWARD 1 |
| 9551 | + |
| 9552 | + |
| 9553 | +/* |
| 9554 | +Offset from the frame pointer to the first local variable slot to be allocated. |
| 9555 | + |
| 9556 | +If FRAME_GROWS_DOWNWARD, find the next slot's offset by |
| 9557 | +subtracting the first slot's length from STARTING_FRAME_OFFSET. |
| 9558 | +Otherwise, it is found by adding the length of the first slot to the |
| 9559 | +value STARTING_FRAME_OFFSET. |
| 9560 | + (i'm not sure if the above is still correct.. had to change it to get |
| 9561 | + rid of an overfull. --mew 2feb93 ) |
| 9562 | +*/ |
| 9563 | +#define STARTING_FRAME_OFFSET 0 |
| 9564 | + |
| 9565 | +/* |
| 9566 | +Offset from the stack pointer register to the first location at which |
| 9567 | +outgoing arguments are placed. If not specified, the default value of |
| 9568 | +zero is used. This is the proper value for most machines. |
| 9569 | + |
| 9570 | +If ARGS_GROW_DOWNWARD, this is the offset to the location above |
| 9571 | +the first location at which outgoing arguments are placed. |
| 9572 | +*/ |
| 9573 | +#define STACK_POINTER_OFFSET 0 |
| 9574 | + |
| 9575 | +/* |
| 9576 | +Offset from the argument pointer register to the first argument's |
| 9577 | +address. On some machines it may depend on the data type of the |
| 9578 | +function. |
| 9579 | + |
| 9580 | +If ARGS_GROW_DOWNWARD, this is the offset to the location above |
| 9581 | +the first argument's address. |
| 9582 | +*/ |
| 9583 | +#define FIRST_PARM_OFFSET(FUNDECL) 0 |
| 9584 | + |
| 9585 | + |
| 9586 | +/* |
| 9587 | +A C expression whose value is RTL representing the address in a stack |
| 9588 | +frame where the pointer to the caller's frame is stored. Assume that |
| 9589 | +FRAMEADDR is an RTL expression for the address of the stack frame |
| 9590 | +itself. |
| 9591 | + |
| 9592 | +If you don't define this macro, the default is to return the value |
| 9593 | +of FRAMEADDR - that is, the stack frame address is also the |
| 9594 | +address of the stack word that points to the previous frame. |
| 9595 | +*/ |
| 9596 | +#define DYNAMIC_CHAIN_ADDRESS(FRAMEADDR) plus_constant ((FRAMEADDR), 4) |
| 9597 | + |
| 9598 | + |
| 9599 | +/* |
| 9600 | +A C expression whose value is RTL representing the value of the return |
| 9601 | +address for the frame COUNT steps up from the current frame, after |
| 9602 | +the prologue. FRAMEADDR is the frame pointer of the COUNT |
| 9603 | +frame, or the frame pointer of the COUNT - 1 frame if |
| 9604 | +RETURN_ADDR_IN_PREVIOUS_FRAME is defined. |
| 9605 | + |
| 9606 | +The value of the expression must always be the correct address when |
| 9607 | +COUNT is zero, but may be NULL_RTX if there is not way to |
| 9608 | +determine the return address of other frames. |
| 9609 | +*/ |
| 9610 | +#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) avr32_return_addr(COUNT, FRAMEADDR) |
| 9611 | + |
| 9612 | + |
| 9613 | +/* |
| 9614 | +A C expression whose value is RTL representing the location of the |
| 9615 | +incoming return address at the beginning of any function, before the |
| 9616 | +prologue. This RTL is either a REG, indicating that the return |
| 9617 | +value is saved in 'REG', or a MEM representing a location in |
| 9618 | +the stack. |
| 9619 | + |
| 9620 | +You only need to define this macro if you want to support call frame |
| 9621 | +debugging information like that provided by DWARF 2. |
| 9622 | + |
| 9623 | +If this RTL is a REG, you should also define |
| 9624 | +DWARF_FRAME_RETURN_COLUMN to DWARF_FRAME_REGNUM (REGNO). |
| 9625 | +*/ |
| 9626 | +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LR_REGNUM) |
| 9627 | + |
| 9628 | +/* |
| 9629 | +A C expression whose value is an integer giving the offset, in bytes, |
| 9630 | +from the value of the stack pointer register to the top of the stack |
| 9631 | +frame at the beginning of any function, before the prologue. The top of |
| 9632 | +the frame is defined to be the value of the stack pointer in the |
| 9633 | +previous frame, just before the call instruction. |
| 9634 | + |
| 9635 | +You only need to define this macro if you want to support call frame |
| 9636 | +debugging information like that provided by DWARF 2. |
| 9637 | +*/ |
| 9638 | +#define INCOMING_FRAME_SP_OFFSET 0 |
| 9639 | + |
| 9640 | + |
| 9641 | +/** Exception Handling Support **/ |
| 9642 | + |
| 9643 | +/* Use setjump/longjump for exception handling. */ |
| 9644 | +#define DWARF2_UNWIND_INFO 0 |
| 9645 | +#define MUST_USE_SJLJ_EXCEPTIONS 1 |
| 9646 | + |
| 9647 | +/* |
| 9648 | +A C expression whose value is the Nth register number used for |
| 9649 | +data by exception handlers, or INVALID_REGNUM if fewer than |
| 9650 | +N registers are usable. |
| 9651 | + |
| 9652 | +The exception handling library routines communicate with the exception |
| 9653 | +handlers via a set of agreed upon registers. Ideally these registers |
| 9654 | +should be call-clobbered; it is possible to use call-saved registers, |
| 9655 | +but may negatively impact code size. The target must support at least |
| 9656 | +2 data registers, but should define 4 if there are enough free registers. |
| 9657 | + |
| 9658 | +You must define this macro if you want to support call frame exception |
| 9659 | +handling like that provided by DWARF 2. |
| 9660 | +*/ |
| 9661 | +/* |
| 9662 | + Use r9-r11 |
| 9663 | +*/ |
| 9664 | +#define EH_RETURN_DATA_REGNO(N) \ |
| 9665 | + ((N<3) ? INTERNAL_REGNUM(N+9) : INVALID_REGNUM) |
| 9666 | + |
| 9667 | +/* |
| 9668 | +A C expression whose value is RTL representing a location in which |
| 9669 | +to store a stack adjustment to be applied before function return. |
| 9670 | +This is used to unwind the stack to an exception handler's call frame. |
| 9671 | +It will be assigned zero on code paths that return normally. |
| 9672 | + |
| 9673 | +Typically this is a call-clobbered hard register that is otherwise |
| 9674 | +untouched by the epilogue, but could also be a stack slot. |
| 9675 | + |
| 9676 | +You must define this macro if you want to support call frame exception |
| 9677 | +handling like that provided by DWARF 2. |
| 9678 | +*/ |
| 9679 | +/* |
| 9680 | + Use r8 |
| 9681 | +*/ |
| 9682 | +#define EH_RETURN_STACKADJ_REGNO INTERNAL_REGNUM(8) |
| 9683 | +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG(SImode, EH_RETURN_STACKADJ_REGNO) |
| 9684 | + |
| 9685 | +/* |
| 9686 | +A C expression whose value is RTL representing a location in which |
| 9687 | +to store the address of an exception handler to which we should |
| 9688 | +return. It will not be assigned on code paths that return normally. |
| 9689 | + |
| 9690 | +Typically this is the location in the call frame at which the normal |
| 9691 | +return address is stored. For targets that return by popping an |
| 9692 | +address off the stack, this might be a memory address just below |
| 9693 | +the target call frame rather than inside the current call |
| 9694 | +frame. EH_RETURN_STACKADJ_RTX will have already been assigned, |
| 9695 | +so it may be used to calculate the location of the target call frame. |
| 9696 | + |
| 9697 | +Some targets have more complex requirements than storing to an |
| 9698 | +address calculable during initial code generation. In that case |
| 9699 | +the eh_return instruction pattern should be used instead. |
| 9700 | + |
| 9701 | +If you want to support call frame exception handling, you must |
| 9702 | +define either this macro or the eh_return instruction pattern. |
| 9703 | +*/ |
| 9704 | +/* |
| 9705 | + We define the eh_return instruction pattern, so this isn't needed. |
| 9706 | +*/ |
| 9707 | +/* #define EH_RETURN_HANDLER_RTX gen_rtx_REG(Pmode, RET_REGISTER) */ |
| 9708 | + |
| 9709 | +/* |
| 9710 | + This macro chooses the encoding of pointers embedded in the |
| 9711 | + exception handling sections. If at all possible, this should be |
| 9712 | + defined such that the exception handling section will not require |
| 9713 | + dynamic relocations, and so may be read-only. |
| 9714 | + |
| 9715 | + code is 0 for data, 1 for code labels, 2 for function |
| 9716 | + pointers. global is true if the symbol may be affected by dynamic |
| 9717 | + relocations. The macro should return a combination of the DW_EH_PE_* |
| 9718 | + defines as found in dwarf2.h. |
| 9719 | + |
| 9720 | + If this macro is not defined, pointers will not be encoded but |
| 9721 | + represented directly. |
| 9722 | +*/ |
| 9723 | +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ |
| 9724 | + ((flag_pic && (GLOBAL) ? DW_EH_PE_indirect : 0) \ |
| 9725 | + | (flag_pic ? DW_EH_PE_pcrel : DW_EH_PE_absptr) \ |
| 9726 | + | DW_EH_PE_sdata4) |
| 9727 | + |
| 9728 | +/* ToDo: The rest of this subsection */ |
| 9729 | + |
| 9730 | +/** Specifying How Stack Checking is Done **/ |
| 9731 | +/* ToDo: All in this subsection */ |
| 9732 | + |
| 9733 | +/** Registers That Address the Stack Frame **/ |
| 9734 | + |
| 9735 | +/* |
| 9736 | +The register number of the stack pointer register, which must also be a |
| 9737 | +fixed register according to FIXED_REGISTERS. On most machines, |
| 9738 | +the hardware determines which register this is. |
| 9739 | +*/ |
| 9740 | +/* Using r13 as stack pointer. */ |
| 9741 | +#define STACK_POINTER_REGNUM INTERNAL_REGNUM(13) |
| 9742 | + |
| 9743 | +/* |
| 9744 | +The register number of the frame pointer register, which is used to |
| 9745 | +access automatic variables in the stack frame. On some machines, the |
| 9746 | +hardware determines which register this is. On other machines, you can |
| 9747 | +choose any register you wish for this purpose. |
| 9748 | +*/ |
| 9749 | +/* Use r7 */ |
| 9750 | +#define FRAME_POINTER_REGNUM INTERNAL_REGNUM(7) |
| 9751 | + |
| 9752 | +/* |
| 9753 | +The register number of the arg pointer register, which is used to access |
| 9754 | +the function's argument list. On some machines, this is the same as the |
| 9755 | +frame pointer register. On some machines, the hardware determines which |
| 9756 | +register this is. On other machines, you can choose any register you |
| 9757 | +wish for this purpose. If this is not the same register as the frame |
| 9758 | +pointer register, then you must mark it as a fixed register according to |
| 9759 | +FIXED_REGISTERS, or arrange to be able to eliminate it (see Section |
| 9760 | +10.10.5 [Elimination], page 224). |
| 9761 | +*/ |
| 9762 | +/* Using r5 */ |
| 9763 | +#define ARG_POINTER_REGNUM INTERNAL_REGNUM(4) |
| 9764 | + |
| 9765 | + |
| 9766 | +/* |
| 9767 | +Register numbers used for passing a function's static chain pointer. If |
| 9768 | +register windows are used, the register number as seen by the called |
| 9769 | +function is STATIC_CHAIN_INCOMING_REGNUM, while the register |
| 9770 | +number as seen by the calling function is STATIC_CHAIN_REGNUM. If |
| 9771 | +these registers are the same, STATIC_CHAIN_INCOMING_REGNUM need |
| 9772 | +not be defined. |
| 9773 | + |
| 9774 | +The static chain register need not be a fixed register. |
| 9775 | + |
| 9776 | +If the static chain is passed in memory, these macros should not be |
| 9777 | +defined; instead, the next two macros should be defined. |
| 9778 | +*/ |
| 9779 | +/* Using r0 */ |
| 9780 | +#define STATIC_CHAIN_REGNUM INTERNAL_REGNUM(0) |
| 9781 | + |
| 9782 | +/** Eliminating Frame Pointer and Arg Pointer **/ |
| 9783 | + |
| 9784 | +/* |
| 9785 | +A C expression which is nonzero if a function must have and use a frame |
| 9786 | +pointer. This expression is evaluated in the reload pass. If its value is |
| 9787 | +nonzero the function will have a frame pointer. |
| 9788 | + |
| 9789 | +The expression can in principle examine the current function and decide |
| 9790 | +according to the facts, but on most machines the constant 0 or the |
| 9791 | +constant 1 suffices. Use 0 when the machine allows code to be generated |
| 9792 | +with no frame pointer, and doing so saves some time or space. Use 1 |
| 9793 | +when there is no possible advantage to avoiding a frame pointer. |
| 9794 | + |
| 9795 | +In certain cases, the compiler does not know how to produce valid code |
| 9796 | +without a frame pointer. The compiler recognizes those cases and |
| 9797 | +automatically gives the function a frame pointer regardless of what |
| 9798 | +FRAME_POINTER_REQUIRED says. You don't need to worry about |
| 9799 | +them. |
| 9800 | + |
| 9801 | +In a function that does not require a frame pointer, the frame pointer |
| 9802 | +register can be allocated for ordinary usage, unless you mark it as a |
| 9803 | +fixed register. See FIXED_REGISTERS for more information. |
| 9804 | +*/ |
| 9805 | +/* We need the frame pointer when compiling for profiling */ |
| 9806 | +#define FRAME_POINTER_REQUIRED (crtl->profile) |
| 9807 | + |
| 9808 | +/* |
| 9809 | +A C statement to store in the variable DEPTH_VAR the difference |
| 9810 | +between the frame pointer and the stack pointer values immediately after |
| 9811 | +the function prologue. The value would be computed from information |
| 9812 | +such as the result of get_frame_size () and the tables of |
| 9813 | +registers regs_ever_live and call_used_regs. |
| 9814 | + |
| 9815 | +If ELIMINABLE_REGS is defined, this macro will be not be used and |
| 9816 | +need not be defined. Otherwise, it must be defined even if |
| 9817 | +FRAME_POINTER_REQUIRED is defined to always be true; in that |
| 9818 | +case, you may set DEPTH_VAR to anything. |
| 9819 | +*/ |
| 9820 | +#define INITIAL_FRAME_POINTER_OFFSET(DEPTH_VAR) ((DEPTH_VAR) = get_frame_size()) |
| 9821 | + |
| 9822 | +/* |
| 9823 | +If defined, this macro specifies a table of register pairs used to |
| 9824 | +eliminate unneeded registers that point into the stack frame. If it is not |
| 9825 | +defined, the only elimination attempted by the compiler is to replace |
| 9826 | +references to the frame pointer with references to the stack pointer. |
| 9827 | + |
| 9828 | +The definition of this macro is a list of structure initializations, each |
| 9829 | +of which specifies an original and replacement register. |
| 9830 | + |
| 9831 | +On some machines, the position of the argument pointer is not known until |
| 9832 | +the compilation is completed. In such a case, a separate hard register |
| 9833 | +must be used for the argument pointer. This register can be eliminated by |
| 9834 | +replacing it with either the frame pointer or the argument pointer, |
| 9835 | +depending on whether or not the frame pointer has been eliminated. |
| 9836 | + |
| 9837 | +In this case, you might specify: |
| 9838 | + #define ELIMINABLE_REGS \ |
| 9839 | + {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ |
| 9840 | + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ |
| 9841 | + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} |
| 9842 | + |
| 9843 | +Note that the elimination of the argument pointer with the stack pointer is |
| 9844 | +specified first since that is the preferred elimination. |
| 9845 | +*/ |
| 9846 | +#define ELIMINABLE_REGS \ |
| 9847 | +{ \ |
| 9848 | + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ |
| 9849 | + { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ |
| 9850 | + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM } \ |
| 9851 | +} |
| 9852 | + |
| 9853 | +/* |
| 9854 | +A C expression that returns nonzero if the compiler is allowed to try |
| 9855 | +to replace register number FROM with register number |
| 9856 | +TO. This macro need only be defined if ELIMINABLE_REGS |
| 9857 | +is defined, and will usually be the constant 1, since most of the cases |
| 9858 | +preventing register elimination are things that the compiler already |
| 9859 | +knows about. |
| 9860 | +*/ |
| 9861 | +#define CAN_ELIMINATE(FROM, TO) 1 |
| 9862 | + |
| 9863 | +/* |
| 9864 | +This macro is similar to INITIAL_FRAME_POINTER_OFFSET. It |
| 9865 | +specifies the initial difference between the specified pair of |
| 9866 | +registers. This macro must be defined if ELIMINABLE_REGS is |
| 9867 | +defined. |
| 9868 | +*/ |
| 9869 | +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ |
| 9870 | + ((OFFSET) = avr32_initial_elimination_offset(FROM, TO)) |
| 9871 | + |
| 9872 | +/** Passing Function Arguments on the Stack **/ |
| 9873 | + |
| 9874 | + |
| 9875 | +/* |
| 9876 | +A C expression. If nonzero, push insns will be used to pass |
| 9877 | +outgoing arguments. |
| 9878 | +If the target machine does not have a push instruction, set it to zero. |
| 9879 | +That directs GCC to use an alternate strategy: to |
| 9880 | +allocate the entire argument block and then store the arguments into |
| 9881 | +it. When PUSH_ARGS is nonzero, PUSH_ROUNDING must be defined too. |
| 9882 | +*/ |
| 9883 | +#define PUSH_ARGS 1 |
| 9884 | + |
| 9885 | +/* |
| 9886 | +A C expression that is the number of bytes actually pushed onto the |
| 9887 | +stack when an instruction attempts to push NPUSHED bytes. |
| 9888 | + |
| 9889 | +On some machines, the definition |
| 9890 | + |
| 9891 | + #define PUSH_ROUNDING(BYTES) (BYTES) |
| 9892 | + |
| 9893 | +will suffice. But on other machines, instructions that appear |
| 9894 | +to push one byte actually push two bytes in an attempt to maintain |
| 9895 | +alignment. Then the definition should be |
| 9896 | + |
| 9897 | + #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) |
| 9898 | +*/ |
| 9899 | +/* Push 4 bytes at the time. */ |
| 9900 | +#define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) |
| 9901 | + |
| 9902 | +/* |
| 9903 | +A C expression. If nonzero, the maximum amount of space required for |
| 9904 | +outgoing arguments will be computed and placed into the variable |
| 9905 | +current_function_outgoing_args_size. No space will be pushed |
| 9906 | +onto the stack for each call; instead, the function prologue should |
| 9907 | +increase the stack frame size by this amount. |
| 9908 | + |
| 9909 | +Setting both PUSH_ARGS and ACCUMULATE_OUTGOING_ARGS is not proper. |
| 9910 | +*/ |
| 9911 | +#define ACCUMULATE_OUTGOING_ARGS 0 |
| 9912 | + |
| 9913 | +/* |
| 9914 | +A C expression that should indicate the number of bytes of its own |
| 9915 | +arguments that a function pops on returning, or 0 if the |
| 9916 | +function pops no arguments and the caller must therefore pop them all |
| 9917 | +after the function returns. |
| 9918 | + |
| 9919 | +FUNDECL is a C variable whose value is a tree node that describes |
| 9920 | +the function in question. Normally it is a node of type |
| 9921 | +FUNCTION_DECL that describes the declaration of the function. |
| 9922 | +From this you can obtain the DECL_ATTRIBUTES of the function. |
| 9923 | + |
| 9924 | +FUNTYPE is a C variable whose value is a tree node that |
| 9925 | +describes the function in question. Normally it is a node of type |
| 9926 | +FUNCTION_TYPE that describes the data type of the function. |
| 9927 | +From this it is possible to obtain the data types of the value and |
| 9928 | +arguments (if known). |
| 9929 | + |
| 9930 | +When a call to a library function is being considered, FUNDECL |
| 9931 | +will contain an identifier node for the library function. Thus, if |
| 9932 | +you need to distinguish among various library functions, you can do so |
| 9933 | +by their names. Note that ``library function'' in this context means |
| 9934 | +a function used to perform arithmetic, whose name is known specially |
| 9935 | +in the compiler and was not mentioned in the C code being compiled. |
| 9936 | + |
| 9937 | +STACK_SIZE is the number of bytes of arguments passed on the |
| 9938 | +stack. If a variable number of bytes is passed, it is zero, and |
| 9939 | +argument popping will always be the responsibility of the calling function. |
| 9940 | + |
| 9941 | +On the VAX, all functions always pop their arguments, so the definition |
| 9942 | +of this macro is STACK_SIZE. On the 68000, using the standard |
| 9943 | +calling convention, no functions pop their arguments, so the value of |
| 9944 | +the macro is always 0 in this case. But an alternative calling |
| 9945 | +convention is available in which functions that take a fixed number of |
| 9946 | +arguments pop them but other functions (such as printf) pop |
| 9947 | +nothing (the caller pops all). When this convention is in use, |
| 9948 | +FUNTYPE is examined to determine whether a function takes a fixed |
| 9949 | +number of arguments. |
| 9950 | +*/ |
| 9951 | +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0 |
| 9952 | + |
| 9953 | + |
| 9954 | +/*Return true if this function can we use a single return instruction*/ |
| 9955 | +#define USE_RETURN_INSN(ISCOND) avr32_use_return_insn(ISCOND) |
| 9956 | + |
| 9957 | +/* |
| 9958 | +A C expression that should indicate the number of bytes a call sequence |
| 9959 | +pops off the stack. It is added to the value of RETURN_POPS_ARGS |
| 9960 | +when compiling a function call. |
| 9961 | + |
| 9962 | +CUM is the variable in which all arguments to the called function |
| 9963 | +have been accumulated. |
| 9964 | + |
| 9965 | +On certain architectures, such as the SH5, a call trampoline is used |
| 9966 | +that pops certain registers off the stack, depending on the arguments |
| 9967 | +that have been passed to the function. Since this is a property of the |
| 9968 | +call site, not of the called function, RETURN_POPS_ARGS is not |
| 9969 | +appropriate. |
| 9970 | +*/ |
| 9971 | +#define CALL_POPS_ARGS(CUM) 0 |
| 9972 | + |
| 9973 | +/* Passing Arguments in Registers */ |
| 9974 | + |
| 9975 | +/* |
| 9976 | +A C expression that controls whether a function argument is passed |
| 9977 | +in a register, and which register. |
| 9978 | + |
| 9979 | +The arguments are CUM, which summarizes all the previous |
| 9980 | +arguments; MODE, the machine mode of the argument; TYPE, |
| 9981 | +the data type of the argument as a tree node or 0 if that is not known |
| 9982 | +(which happens for C support library functions); and NAMED, |
| 9983 | +which is 1 for an ordinary argument and 0 for nameless arguments that |
| 9984 | +correspond to '...' in the called function's prototype. |
| 9985 | +TYPE can be an incomplete type if a syntax error has previously |
| 9986 | +occurred. |
| 9987 | + |
| 9988 | +The value of the expression is usually either a reg RTX for the |
| 9989 | +hard register in which to pass the argument, or zero to pass the |
| 9990 | +argument on the stack. |
| 9991 | + |
| 9992 | +For machines like the VAX and 68000, where normally all arguments are |
| 9993 | +pushed, zero suffices as a definition. |
| 9994 | + |
| 9995 | +The value of the expression can also be a parallel RTX. This is |
| 9996 | +used when an argument is passed in multiple locations. The mode of the |
| 9997 | +of the parallel should be the mode of the entire argument. The |
| 9998 | +parallel holds any number of expr_list pairs; each one |
| 9999 | +describes where part of the argument is passed. In each |
| 10000 | +expr_list the first operand must be a reg RTX for the hard |
| 10001 | +register in which to pass this part of the argument, and the mode of the |
| 10002 | +register RTX indicates how large this part of the argument is. The |
| 10003 | +second operand of the expr_list is a const_int which gives |
| 10004 | +the offset in bytes into the entire argument of where this part starts. |
| 10005 | +As a special exception the first expr_list in the parallel |
| 10006 | +RTX may have a first operand of zero. This indicates that the entire |
| 10007 | +argument is also stored on the stack. |
| 10008 | + |
| 10009 | +The last time this macro is called, it is called with MODE == VOIDmode, |
| 10010 | +and its result is passed to the call or call_value |
| 10011 | +pattern as operands 2 and 3 respectively. |
| 10012 | + |
| 10013 | +The usual way to make the ISO library 'stdarg.h' work on a machine |
| 10014 | +where some arguments are usually passed in registers, is to cause |
| 10015 | +nameless arguments to be passed on the stack instead. This is done |
| 10016 | +by making FUNCTION_ARG return 0 whenever NAMED is 0. |
| 10017 | + |
| 10018 | +You may use the macro MUST_PASS_IN_STACK (MODE, TYPE) |
| 10019 | +in the definition of this macro to determine if this argument is of a |
| 10020 | +type that must be passed in the stack. If REG_PARM_STACK_SPACE |
| 10021 | +is not defined and FUNCTION_ARG returns nonzero for such an |
| 10022 | +argument, the compiler will abort. If REG_PARM_STACK_SPACE is |
| 10023 | +defined, the argument will be computed in the stack and then loaded into |
| 10024 | +a register. */ |
| 10025 | + |
| 10026 | +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ |
| 10027 | + avr32_function_arg(&(CUM), MODE, TYPE, NAMED) |
| 10028 | + |
| 10029 | +/* |
| 10030 | +A C type for declaring a variable that is used as the first argument of |
| 10031 | +FUNCTION_ARG and other related values. For some target machines, |
| 10032 | +the type int suffices and can hold the number of bytes of |
| 10033 | +argument so far. |
| 10034 | + |
| 10035 | +There is no need to record in CUMULATIVE_ARGS anything about the |
| 10036 | +arguments that have been passed on the stack. The compiler has other |
| 10037 | +variables to keep track of that. For target machines on which all |
| 10038 | +arguments are passed on the stack, there is no need to store anything in |
| 10039 | +CUMULATIVE_ARGS; however, the data structure must exist and |
| 10040 | +should not be empty, so use int. |
| 10041 | +*/ |
| 10042 | +typedef struct avr32_args |
| 10043 | +{ |
| 10044 | + /* Index representing the argument register the current function argument |
| 10045 | + will occupy */ |
| 10046 | + int index; |
| 10047 | + /* A mask with bits representing the argument registers: if a bit is set |
| 10048 | + then this register is used for an argument */ |
| 10049 | + int used_index; |
| 10050 | + /* TRUE if this function has anonymous arguments */ |
| 10051 | + int uses_anonymous_args; |
| 10052 | + /* The size in bytes of the named arguments pushed on the stack */ |
| 10053 | + int stack_pushed_args_size; |
| 10054 | + /* Set to true if this function needs a Return Value Pointer */ |
| 10055 | + int use_rvp; |
| 10056 | + /* Set to true if function is a flashvault function. */ |
| 10057 | + int flashvault_func; |
| 10058 | + |
| 10059 | +} CUMULATIVE_ARGS; |
| 10060 | + |
| 10061 | + |
| 10062 | +#define FIRST_CUM_REG_INDEX 0 |
| 10063 | +#define LAST_CUM_REG_INDEX 4 |
| 10064 | +#define GET_REG_INDEX(CUM) ((CUM)->index) |
| 10065 | +#define SET_REG_INDEX(CUM, INDEX) ((CUM)->index = (INDEX)); |
| 10066 | +#define GET_USED_INDEX(CUM, INDEX) ((CUM)->used_index & (1 << (INDEX))) |
| 10067 | +#define SET_USED_INDEX(CUM, INDEX) \ |
| 10068 | + do \ |
| 10069 | + { \ |
| 10070 | + if (INDEX >= 0) \ |
| 10071 | + (CUM)->used_index |= (1 << (INDEX)); \ |
| 10072 | + } \ |
| 10073 | + while (0) |
| 10074 | +#define SET_INDEXES_UNUSED(CUM) ((CUM)->used_index = 0) |
| 10075 | + |
| 10076 | +/* |
| 10077 | + A C statement (sans semicolon) for initializing the variable cum for the |
| 10078 | + state at the beginning of the argument list. The variable has type |
| 10079 | + CUMULATIVE_ARGS. The value of FNTYPE is the tree node for the data type of |
| 10080 | + the function which will receive the args, or 0 if the args are to a compiler |
| 10081 | + support library function. For direct calls that are not libcalls, FNDECL |
| 10082 | + contain the declaration node of the function. FNDECL is also set when |
| 10083 | + INIT_CUMULATIVE_ARGS is used to find arguments for the function being |
| 10084 | + compiled. N_NAMED_ARGS is set to the number of named arguments, including a |
| 10085 | + structure return address if it is passed as a parameter, when making a call. |
| 10086 | + When processing incoming arguments, N_NAMED_ARGS is set to -1. |
| 10087 | + |
| 10088 | + When processing a call to a compiler support library function, LIBNAME |
| 10089 | + identifies which one. It is a symbol_ref rtx which contains the name of the |
| 10090 | + function, as a string. LIBNAME is 0 when an ordinary C function call is |
| 10091 | + being processed. Thus, each time this macro is called, either LIBNAME or |
| 10092 | + FNTYPE is nonzero, but never both of them at once. |
| 10093 | +*/ |
| 10094 | +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ |
| 10095 | + avr32_init_cumulative_args(&(CUM), FNTYPE, LIBNAME, FNDECL) |
| 10096 | + |
| 10097 | +/* |
| 10098 | +A C statement (sans semicolon) to update the summarizer variable |
| 10099 | +CUM to advance past an argument in the argument list. The |
| 10100 | +values MODE, TYPE and NAMED describe that argument. |
| 10101 | +Once this is done, the variable CUM is suitable for analyzing |
| 10102 | +the following argument with FUNCTION_ARG, etc. |
| 10103 | + |
| 10104 | +This macro need not do anything if the argument in question was passed |
| 10105 | +on the stack. The compiler knows how to track the amount of stack space |
| 10106 | +used for arguments without any special help. |
| 10107 | +*/ |
| 10108 | +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ |
| 10109 | + avr32_function_arg_advance(&(CUM), MODE, TYPE, NAMED) |
| 10110 | + |
| 10111 | +/* |
| 10112 | +If defined, a C expression which determines whether, and in which direction, |
| 10113 | +to pad out an argument with extra space. The value should be of type |
| 10114 | +enum direction: either 'upward' to pad above the argument, |
| 10115 | +'downward' to pad below, or 'none' to inhibit padding. |
| 10116 | + |
| 10117 | +The amount of padding is always just enough to reach the next |
| 10118 | +multiple of FUNCTION_ARG_BOUNDARY; this macro does not control |
| 10119 | +it. |
| 10120 | + |
| 10121 | +This macro has a default definition which is right for most systems. |
| 10122 | +For little-endian machines, the default is to pad upward. For |
| 10123 | +big-endian machines, the default is to pad downward for an argument of |
| 10124 | +constant size shorter than an int, and upward otherwise. |
| 10125 | +*/ |
| 10126 | +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ |
| 10127 | + avr32_function_arg_padding(MODE, TYPE) |
| 10128 | + |
| 10129 | +/* |
| 10130 | + Specify padding for the last element of a block move between registers |
| 10131 | + and memory. First is nonzero if this is the only element. Defining |
| 10132 | + this macro allows better control of register function parameters on |
| 10133 | + big-endian machines, without using PARALLEL rtl. In particular, |
| 10134 | + MUST_PASS_IN_STACK need not test padding and mode of types in registers, |
| 10135 | + as there is no longer a "wrong" part of a register; For example, a three |
| 10136 | + byte aggregate may be passed in the high part of a register if so required. |
| 10137 | +*/ |
| 10138 | +#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \ |
| 10139 | + avr32_function_arg_padding(MODE, TYPE) |
| 10140 | + |
| 10141 | +/* |
| 10142 | +If defined, a C expression which determines whether the default |
| 10143 | +implementation of va_arg will attempt to pad down before reading the |
| 10144 | +next argument, if that argument is smaller than its aligned space as |
| 10145 | +controlled by PARM_BOUNDARY. If this macro is not defined, all such |
| 10146 | +arguments are padded down if BYTES_BIG_ENDIAN is true. |
| 10147 | +*/ |
| 10148 | +#define PAD_VARARGS_DOWN \ |
| 10149 | + (FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward) |
| 10150 | + |
| 10151 | +/* |
| 10152 | +A C expression that is nonzero if REGNO is the number of a hard |
| 10153 | +register in which function arguments are sometimes passed. This does |
| 10154 | +not include implicit arguments such as the static chain and |
| 10155 | +the structure-value address. On many machines, no registers can be |
| 10156 | +used for this purpose since all function arguments are pushed on the |
| 10157 | +stack. |
| 10158 | +*/ |
| 10159 | +/* |
| 10160 | + Use r8 - r12 for function arguments. |
| 10161 | +*/ |
| 10162 | +#define FUNCTION_ARG_REGNO_P(REGNO) \ |
| 10163 | + (REGNO >= 3 && REGNO <= 7) |
| 10164 | + |
| 10165 | +/* Number of registers used for passing function arguments */ |
| 10166 | +#define NUM_ARG_REGS 5 |
| 10167 | + |
| 10168 | +/* |
| 10169 | +If defined, the order in which arguments are loaded into their |
| 10170 | +respective argument registers is reversed so that the last |
| 10171 | +argument is loaded first. This macro only affects arguments |
| 10172 | +passed in registers. |
| 10173 | +*/ |
| 10174 | +/* #define LOAD_ARGS_REVERSED */ |
| 10175 | + |
| 10176 | +/** How Scalar Function Values Are Returned **/ |
| 10177 | + |
| 10178 | +/* AVR32 is using r12 as return register. */ |
| 10179 | +#define RET_REGISTER (15 - 12) |
| 10180 | + |
| 10181 | +/* |
| 10182 | +A C expression to create an RTX representing the place where a library |
| 10183 | +function returns a value of mode MODE. If the precise function |
| 10184 | +being called is known, FUNC is a tree node |
| 10185 | +(FUNCTION_DECL) for it; otherwise, func is a null |
| 10186 | +pointer. This makes it possible to use a different value-returning |
| 10187 | +convention for specific functions when all their calls are |
| 10188 | +known. |
| 10189 | + |
| 10190 | +Note that "library function" in this context means a compiler |
| 10191 | +support routine, used to perform arithmetic, whose name is known |
| 10192 | +specially by the compiler and was not mentioned in the C code being |
| 10193 | +compiled. |
| 10194 | + |
| 10195 | +The definition of LIBRARY_VALUE need not be concerned aggregate |
| 10196 | +data types, because none of the library functions returns such types. |
| 10197 | +*/ |
| 10198 | +#define LIBCALL_VALUE(MODE) avr32_libcall_value(MODE) |
| 10199 | + |
| 10200 | +/* |
| 10201 | +A C expression that is nonzero if REGNO is the number of a hard |
| 10202 | +register in which the values of called function may come back. |
| 10203 | + |
| 10204 | +A register whose use for returning values is limited to serving as the |
| 10205 | +second of a pair (for a value of type double, say) need not be |
| 10206 | +recognized by this macro. So for most machines, this definition |
| 10207 | +suffices: |
| 10208 | + #define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) |
| 10209 | + |
| 10210 | +If the machine has register windows, so that the caller and the called |
| 10211 | +function use different registers for the return value, this macro |
| 10212 | +should recognize only the caller's register numbers. |
| 10213 | +*/ |
| 10214 | +/* |
| 10215 | + When returning a value of mode DImode, r11:r10 is used, else r12 is used. |
| 10216 | +*/ |
| 10217 | +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == RET_REGISTER \ |
| 10218 | + || (REGNO) == INTERNAL_REGNUM(11)) |
| 10219 | + |
| 10220 | + |
| 10221 | +/** How Large Values Are Returned **/ |
| 10222 | + |
| 10223 | + |
| 10224 | +/* |
| 10225 | +Define this macro to be 1 if all structure and union return values must be |
| 10226 | +in memory. Since this results in slower code, this should be defined |
| 10227 | +only if needed for compatibility with other compilers or with an ABI. |
| 10228 | +If you define this macro to be 0, then the conventions used for structure |
| 10229 | +and union return values are decided by the RETURN_IN_MEMORY macro. |
| 10230 | + |
| 10231 | +If not defined, this defaults to the value 1. |
| 10232 | +*/ |
| 10233 | +#define DEFAULT_PCC_STRUCT_RETURN 0 |
| 10234 | + |
| 10235 | + |
| 10236 | + |
| 10237 | + |
| 10238 | +/** Generating Code for Profiling **/ |
| 10239 | + |
| 10240 | +/* |
| 10241 | +A C statement or compound statement to output to FILE some |
| 10242 | +assembler code to call the profiling subroutine mcount. |
| 10243 | + |
| 10244 | +The details of how mcount expects to be called are determined by |
| 10245 | +your operating system environment, not by GCC. To figure them out, |
| 10246 | +compile a small program for profiling using the system's installed C |
| 10247 | +compiler and look at the assembler code that results. |
| 10248 | + |
| 10249 | +Older implementations of mcount expect the address of a counter |
| 10250 | +variable to be loaded into some register. The name of this variable is |
| 10251 | +'LP' followed by the number LABELNO, so you would generate |
| 10252 | +the name using 'LP%d' in a fprintf. |
| 10253 | +*/ |
| 10254 | +/* ToDo: fixme */ |
| 10255 | +#ifndef FUNCTION_PROFILER |
| 10256 | +#define FUNCTION_PROFILER(FILE, LABELNO) \ |
| 10257 | + fprintf((FILE), "/* profiler %d */", (LABELNO)) |
| 10258 | +#endif |
| 10259 | + |
| 10260 | + |
| 10261 | +/***************************************************************************** |
| 10262 | + * Trampolines for Nested Functions * |
| 10263 | + *****************************************************************************/ |
| 10264 | + |
| 10265 | +/* |
| 10266 | +A C statement to output, on the stream FILE, assembler code for a |
| 10267 | +block of data that contains the constant parts of a trampoline. This |
| 10268 | +code should not include a label - the label is taken care of |
| 10269 | +automatically. |
| 10270 | + |
| 10271 | +If you do not define this macro, it means no template is needed |
| 10272 | +for the target. Do not define this macro on systems where the block move |
| 10273 | +code to copy the trampoline into place would be larger than the code |
| 10274 | +to generate it on the spot. |
| 10275 | +*/ |
| 10276 | +/* ToDo: correct? */ |
| 10277 | +#define TRAMPOLINE_TEMPLATE(FILE) avr32_trampoline_template(FILE); |
| 10278 | + |
| 10279 | + |
| 10280 | +/* |
| 10281 | +A C expression for the size in bytes of the trampoline, as an integer. |
| 10282 | +*/ |
| 10283 | +/* ToDo: fixme */ |
| 10284 | +#define TRAMPOLINE_SIZE 0x0C |
| 10285 | + |
| 10286 | +/* |
| 10287 | +Alignment required for trampolines, in bits. |
| 10288 | + |
| 10289 | +If you don't define this macro, the value of BIGGEST_ALIGNMENT |
| 10290 | +is used for aligning trampolines. |
| 10291 | +*/ |
| 10292 | +#define TRAMPOLINE_ALIGNMENT 16 |
| 10293 | + |
| 10294 | +/* |
| 10295 | +A C statement to initialize the variable parts of a trampoline. |
| 10296 | +ADDR is an RTX for the address of the trampoline; FNADDR is |
| 10297 | +an RTX for the address of the nested function; STATIC_CHAIN is an |
| 10298 | +RTX for the static chain value that should be passed to the function |
| 10299 | +when it is called. |
| 10300 | +*/ |
| 10301 | +#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, STATIC_CHAIN) \ |
| 10302 | + avr32_initialize_trampoline(ADDR, FNADDR, STATIC_CHAIN) |
| 10303 | + |
| 10304 | + |
| 10305 | +/****************************************************************************** |
| 10306 | + * Implicit Calls to Library Routines |
| 10307 | + *****************************************************************************/ |
| 10308 | + |
| 10309 | +/* Tail calling. */ |
| 10310 | + |
| 10311 | +/* A C expression that evaluates to true if it is ok to perform a sibling |
| 10312 | + call to DECL. */ |
| 10313 | +#define FUNCTION_OK_FOR_SIBCALL(DECL) 0 |
| 10314 | + |
| 10315 | +#define OVERRIDE_OPTIONS avr32_override_options () |
| 10316 | + |
| 10317 | +#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) avr32_optimization_options (LEVEL, SIZE) |
| 10318 | + |
| 10319 | +/****************************************************************************** |
| 10320 | + * Addressing Modes |
| 10321 | + *****************************************************************************/ |
| 10322 | + |
| 10323 | +/* |
| 10324 | +A C expression that is nonzero if the machine supports pre-increment, |
| 10325 | +pre-decrement, post-increment, or post-decrement addressing respectively. |
| 10326 | +*/ |
| 10327 | +/* |
| 10328 | + AVR32 supports Rp++ and --Rp |
| 10329 | +*/ |
| 10330 | +#define HAVE_PRE_INCREMENT 0 |
| 10331 | +#define HAVE_PRE_DECREMENT 1 |
| 10332 | +#define HAVE_POST_INCREMENT 1 |
| 10333 | +#define HAVE_POST_DECREMENT 0 |
| 10334 | + |
| 10335 | +/* |
| 10336 | +A C expression that is nonzero if the machine supports pre- or |
| 10337 | +post-address side-effect generation involving constants other than |
| 10338 | +the size of the memory operand. |
| 10339 | +*/ |
| 10340 | +#define HAVE_PRE_MODIFY_DISP 0 |
| 10341 | +#define HAVE_POST_MODIFY_DISP 0 |
| 10342 | + |
| 10343 | +/* |
| 10344 | +A C expression that is nonzero if the machine supports pre- or |
| 10345 | +post-address side-effect generation involving a register displacement. |
| 10346 | +*/ |
| 10347 | +#define HAVE_PRE_MODIFY_REG 0 |
| 10348 | +#define HAVE_POST_MODIFY_REG 0 |
| 10349 | + |
| 10350 | +/* |
| 10351 | +A C expression that is 1 if the RTX X is a constant which |
| 10352 | +is a valid address. On most machines, this can be defined as |
| 10353 | +CONSTANT_P (X), but a few machines are more restrictive |
| 10354 | +in which constant addresses are supported. |
| 10355 | + |
| 10356 | +CONSTANT_P accepts integer-values expressions whose values are |
| 10357 | +not explicitly known, such as symbol_ref, label_ref, and |
| 10358 | +high expressions and const arithmetic expressions, in |
| 10359 | +addition to const_int and const_double expressions. |
| 10360 | +*/ |
| 10361 | +#define CONSTANT_ADDRESS_P(X) CONSTANT_P(X) |
| 10362 | + |
| 10363 | +/* |
| 10364 | +A number, the maximum number of registers that can appear in a valid |
| 10365 | +memory address. Note that it is up to you to specify a value equal to |
| 10366 | +the maximum number that GO_IF_LEGITIMATE_ADDRESS would ever |
| 10367 | +accept. |
| 10368 | +*/ |
| 10369 | +#define MAX_REGS_PER_ADDRESS 2 |
| 10370 | + |
| 10371 | +/* |
| 10372 | +A C compound statement with a conditional goto LABEL; |
| 10373 | +executed if X (an RTX) is a legitimate memory address on the |
| 10374 | +target machine for a memory operand of mode MODE. |
| 10375 | + |
| 10376 | +It usually pays to define several simpler macros to serve as |
| 10377 | +subroutines for this one. Otherwise it may be too complicated to |
| 10378 | +understand. |
| 10379 | + |
| 10380 | +This macro must exist in two variants: a strict variant and a |
| 10381 | +non-strict one. The strict variant is used in the reload pass. It |
| 10382 | +must be defined so that any pseudo-register that has not been |
| 10383 | +allocated a hard register is considered a memory reference. In |
| 10384 | +contexts where some kind of register is required, a pseudo-register |
| 10385 | +with no hard register must be rejected. |
| 10386 | + |
| 10387 | +The non-strict variant is used in other passes. It must be defined to |
| 10388 | +accept all pseudo-registers in every context where some kind of |
| 10389 | +register is required. |
| 10390 | + |
| 10391 | +Compiler source files that want to use the strict variant of this |
| 10392 | +macro define the macro REG_OK_STRICT. You should use an |
| 10393 | +#ifdef REG_OK_STRICT conditional to define the strict variant |
| 10394 | +in that case and the non-strict variant otherwise. |
| 10395 | + |
| 10396 | +Subroutines to check for acceptable registers for various purposes (one |
| 10397 | +for base registers, one for index registers, and so on) are typically |
| 10398 | +among the subroutines used to define GO_IF_LEGITIMATE_ADDRESS. |
| 10399 | +Then only these subroutine macros need have two variants; the higher |
| 10400 | +levels of macros may be the same whether strict or not. |
| 10401 | + |
| 10402 | +Normally, constant addresses which are the sum of a symbol_ref |
| 10403 | +and an integer are stored inside a const RTX to mark them as |
| 10404 | +constant. Therefore, there is no need to recognize such sums |
| 10405 | +specifically as legitimate addresses. Normally you would simply |
| 10406 | +recognize any const as legitimate. |
| 10407 | + |
| 10408 | +Usually PRINT_OPERAND_ADDRESS is not prepared to handle constant |
| 10409 | +sums that are not marked with const. It assumes that a naked |
| 10410 | +plus indicates indexing. If so, then you must reject such |
| 10411 | +naked constant sums as illegitimate addresses, so that none of them will |
| 10412 | +be given to PRINT_OPERAND_ADDRESS. |
| 10413 | + |
| 10414 | +On some machines, whether a symbolic address is legitimate depends on |
| 10415 | +the section that the address refers to. On these machines, define the |
| 10416 | +macro ENCODE_SECTION_INFO to store the information into the |
| 10417 | +symbol_ref, and then check for it here. When you see a |
| 10418 | +const, you will have to look inside it to find the |
| 10419 | +symbol_ref in order to determine the section. |
| 10420 | + |
| 10421 | +The best way to modify the name string is by adding text to the |
| 10422 | +beginning, with suitable punctuation to prevent any ambiguity. Allocate |
| 10423 | +the new name in saveable_obstack. You will have to modify |
| 10424 | +ASM_OUTPUT_LABELREF to remove and decode the added text and |
| 10425 | +output the name accordingly, and define STRIP_NAME_ENCODING to |
| 10426 | +access the original name string. |
| 10427 | + |
| 10428 | +You can check the information stored here into the symbol_ref in |
| 10429 | +the definitions of the macros GO_IF_LEGITIMATE_ADDRESS and |
| 10430 | +PRINT_OPERAND_ADDRESS. |
| 10431 | +*/ |
| 10432 | +#ifdef REG_OK_STRICT |
| 10433 | +# define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ |
| 10434 | + do \ |
| 10435 | + { \ |
| 10436 | + if (avr32_legitimate_address(MODE, X, 1)) \ |
| 10437 | + goto LABEL; \ |
| 10438 | + } \ |
| 10439 | + while (0) |
| 10440 | +#else |
| 10441 | +# define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ |
| 10442 | + do \ |
| 10443 | + { \ |
| 10444 | + if (avr32_legitimate_address(MODE, X, 0)) \ |
| 10445 | + goto LABEL; \ |
| 10446 | + } \ |
| 10447 | + while (0) |
| 10448 | +#endif |
| 10449 | + |
| 10450 | + |
| 10451 | + |
| 10452 | +/* |
| 10453 | +A C compound statement that attempts to replace X with a valid |
| 10454 | +memory address for an operand of mode MODE. win will be a |
| 10455 | +C statement label elsewhere in the code; the macro definition may use |
| 10456 | + |
| 10457 | + GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); |
| 10458 | + |
| 10459 | +to avoid further processing if the address has become legitimate. |
| 10460 | + |
| 10461 | +X will always be the result of a call to break_out_memory_refs, |
| 10462 | +and OLDX will be the operand that was given to that function to produce |
| 10463 | +X. |
| 10464 | + |
| 10465 | +The code generated by this macro should not alter the substructure of |
| 10466 | +X. If it transforms X into a more legitimate form, it |
| 10467 | +should assign X (which will always be a C variable) a new value. |
| 10468 | + |
| 10469 | +It is not necessary for this macro to come up with a legitimate |
| 10470 | +address. The compiler has standard ways of doing so in all cases. In |
| 10471 | +fact, it is safe for this macro to do nothing. But often a |
| 10472 | +machine-dependent strategy can generate better code. |
| 10473 | +*/ |
| 10474 | +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ |
| 10475 | + do \ |
| 10476 | + { \ |
| 10477 | + if (GET_CODE(X) == PLUS \ |
| 10478 | + && GET_CODE(XEXP(X, 0)) == REG \ |
| 10479 | + && GET_CODE(XEXP(X, 1)) == CONST_INT \ |
| 10480 | + && !CONST_OK_FOR_CONSTRAINT_P(INTVAL(XEXP(X, 1)), \ |
| 10481 | + 'K', "Ks16")) \ |
| 10482 | + { \ |
| 10483 | + rtx index = force_reg(SImode, XEXP(X, 1)); \ |
| 10484 | + X = gen_rtx_PLUS( SImode, XEXP(X, 0), index); \ |
| 10485 | + } \ |
| 10486 | + GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN); \ |
| 10487 | + } \ |
| 10488 | + while(0) |
| 10489 | + |
| 10490 | + |
| 10491 | +/* |
| 10492 | +A C statement or compound statement with a conditional |
| 10493 | +goto LABEL; executed if memory address X (an RTX) can have |
| 10494 | +different meanings depending on the machine mode of the memory |
| 10495 | +reference it is used for or if the address is valid for some modes |
| 10496 | +but not others. |
| 10497 | + |
| 10498 | +Autoincrement and autodecrement addresses typically have mode-dependent |
| 10499 | +effects because the amount of the increment or decrement is the size |
| 10500 | +of the operand being addressed. Some machines have other mode-dependent |
| 10501 | +addresses. Many RISC machines have no mode-dependent addresses. |
| 10502 | + |
| 10503 | +You may assume that ADDR is a valid address for the machine. |
| 10504 | +*/ |
| 10505 | +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ |
| 10506 | + do \ |
| 10507 | + { \ |
| 10508 | + if (GET_CODE (ADDR) == POST_INC \ |
| 10509 | + || GET_CODE (ADDR) == PRE_DEC) \ |
| 10510 | + goto LABEL; \ |
| 10511 | + } \ |
| 10512 | + while (0) |
| 10513 | + |
| 10514 | +/* |
| 10515 | +A C expression that is nonzero if X is a legitimate constant for |
| 10516 | +an immediate operand on the target machine. You can assume that |
| 10517 | +X satisfies CONSTANT_P, so you need not check this. In fact, |
| 10518 | +'1' is a suitable definition for this macro on machines where |
| 10519 | +anything CONSTANT_P is valid. |
| 10520 | +*/ |
| 10521 | +#define LEGITIMATE_CONSTANT_P(X) avr32_legitimate_constant_p(X) |
| 10522 | + |
| 10523 | + |
| 10524 | +/****************************************************************************** |
| 10525 | + * Condition Code Status |
| 10526 | + *****************************************************************************/ |
| 10527 | + |
| 10528 | +/* |
| 10529 | +C code for a data type which is used for declaring the mdep |
| 10530 | +component of cc_status. It defaults to int. |
| 10531 | + |
| 10532 | +This macro is not used on machines that do not use cc0. |
| 10533 | +*/ |
| 10534 | + |
| 10535 | +typedef struct |
| 10536 | +{ |
| 10537 | + int flags; |
| 10538 | + rtx value; |
| 10539 | + int cond_exec_cmp_clobbered; |
| 10540 | +} avr32_status_reg; |
| 10541 | + |
| 10542 | + |
| 10543 | +#define CC_STATUS_MDEP avr32_status_reg |
| 10544 | + |
| 10545 | +/* |
| 10546 | +A C expression to initialize the mdep field to "empty". |
| 10547 | +The default definition does nothing, since most machines don't use |
| 10548 | +the field anyway. If you want to use the field, you should probably |
| 10549 | +define this macro to initialize it. |
| 10550 | + |
| 10551 | +This macro is not used on machines that do not use cc0. |
| 10552 | +*/ |
| 10553 | + |
| 10554 | +#define CC_STATUS_MDEP_INIT \ |
| 10555 | + (cc_status.mdep.flags = CC_NONE , cc_status.mdep.cond_exec_cmp_clobbered = 0, cc_status.mdep.value = 0) |
| 10556 | + |
| 10557 | +/* |
| 10558 | +A C compound statement to set the components of cc_status |
| 10559 | +appropriately for an insn INSN whose body is EXP. It is |
| 10560 | +this macro's responsibility to recognize insns that set the condition |
| 10561 | +code as a byproduct of other activity as well as those that explicitly |
| 10562 | +set (cc0). |
| 10563 | + |
| 10564 | +This macro is not used on machines that do not use cc0. |
| 10565 | + |
| 10566 | +If there are insns that do not set the condition code but do alter |
| 10567 | +other machine registers, this macro must check to see whether they |
| 10568 | +invalidate the expressions that the condition code is recorded as |
| 10569 | +reflecting. For example, on the 68000, insns that store in address |
| 10570 | +registers do not set the condition code, which means that usually |
| 10571 | +NOTICE_UPDATE_CC can leave cc_status unaltered for such |
| 10572 | +insns. But suppose that the previous insn set the condition code |
| 10573 | +based on location 'a4@@(102)' and the current insn stores a new |
| 10574 | +value in 'a4'. Although the condition code is not changed by |
| 10575 | +this, it will no longer be true that it reflects the contents of |
| 10576 | +'a4@@(102)'. Therefore, NOTICE_UPDATE_CC must alter |
| 10577 | +cc_status in this case to say that nothing is known about the |
| 10578 | +condition code value. |
| 10579 | + |
| 10580 | +The definition of NOTICE_UPDATE_CC must be prepared to deal |
| 10581 | +with the results of peephole optimization: insns whose patterns are |
| 10582 | +parallel RTXs containing various reg, mem or |
| 10583 | +constants which are just the operands. The RTL structure of these |
| 10584 | +insns is not sufficient to indicate what the insns actually do. What |
| 10585 | +NOTICE_UPDATE_CC should do when it sees one is just to run |
| 10586 | +CC_STATUS_INIT. |
| 10587 | + |
| 10588 | +A possible definition of NOTICE_UPDATE_CC is to call a function |
| 10589 | +that looks at an attribute (see Insn Attributes) named, for example, |
| 10590 | +'cc'. This avoids having detailed information about patterns in |
| 10591 | +two places, the 'md' file and in NOTICE_UPDATE_CC. |
| 10592 | +*/ |
| 10593 | + |
| 10594 | +#define NOTICE_UPDATE_CC(EXP, INSN) avr32_notice_update_cc(EXP, INSN) |
| 10595 | + |
| 10596 | + |
| 10597 | + |
| 10598 | + |
| 10599 | +/****************************************************************************** |
| 10600 | + * Describing Relative Costs of Operations |
| 10601 | + *****************************************************************************/ |
| 10602 | + |
| 10603 | + |
| 10604 | + |
| 10605 | +/* |
| 10606 | +A C expression for the cost of moving data of mode MODE from a |
| 10607 | +register in class FROM to one in class TO. The classes are |
| 10608 | +expressed using the enumeration values such as GENERAL_REGS. A |
| 10609 | +value of 2 is the default; other values are interpreted relative to |
| 10610 | +that. |
| 10611 | + |
| 10612 | +It is not required that the cost always equal 2 when FROM is the |
| 10613 | +same as TO; on some machines it is expensive to move between |
| 10614 | +registers if they are not general registers. |
| 10615 | + |
| 10616 | +If reload sees an insn consisting of a single set between two |
| 10617 | +hard registers, and if REGISTER_MOVE_COST applied to their |
| 10618 | +classes returns a value of 2, reload does not check to ensure that the |
| 10619 | +constraints of the insn are met. Setting a cost of other than 2 will |
| 10620 | +allow reload to verify that the constraints are met. You should do this |
| 10621 | +if the movm pattern's constraints do not allow such copying. |
| 10622 | +*/ |
| 10623 | +#define REGISTER_MOVE_COST(MODE, FROM, TO) \ |
| 10624 | + ((GET_MODE_SIZE(MODE) <= 4) ? 2: \ |
| 10625 | + (GET_MODE_SIZE(MODE) <= 8) ? 3: \ |
| 10626 | + 4) |
| 10627 | + |
| 10628 | +/* |
| 10629 | +A C expression for the cost of moving data of mode MODE between a |
| 10630 | +register of class CLASS and memory; IN is zero if the value |
| 10631 | +is to be written to memory, nonzero if it is to be read in. This cost |
| 10632 | +is relative to those in REGISTER_MOVE_COST. If moving between |
| 10633 | +registers and memory is more expensive than between two registers, you |
| 10634 | +should define this macro to express the relative cost. |
| 10635 | + |
| 10636 | +If you do not define this macro, GCC uses a default cost of 4 plus |
| 10637 | +the cost of copying via a secondary reload register, if one is |
| 10638 | +needed. If your machine requires a secondary reload register to copy |
| 10639 | +between memory and a register of CLASS but the reload mechanism is |
| 10640 | +more complex than copying via an intermediate, define this macro to |
| 10641 | +reflect the actual cost of the move. |
| 10642 | + |
| 10643 | +GCC defines the function memory_move_secondary_cost if |
| 10644 | +secondary reloads are needed. It computes the costs due to copying via |
| 10645 | +a secondary register. If your machine copies from memory using a |
| 10646 | +secondary register in the conventional way but the default base value of |
| 10647 | +4 is not correct for your machine, define this macro to add some other |
| 10648 | +value to the result of that function. The arguments to that function |
| 10649 | +are the same as to this macro. |
| 10650 | +*/ |
| 10651 | +/* |
| 10652 | + Memory moves are costly |
| 10653 | +*/ |
| 10654 | +#define MEMORY_MOVE_COST(MODE, CLASS, IN) \ |
| 10655 | + (((IN) ? ((GET_MODE_SIZE(MODE) < 4) ? 4 : \ |
| 10656 | + (GET_MODE_SIZE(MODE) > 8) ? 6 : \ |
| 10657 | + 3) \ |
| 10658 | + : ((GET_MODE_SIZE(MODE) > 8) ? 6 : 3))) |
| 10659 | + |
| 10660 | +/* |
| 10661 | +A C expression for the cost of a branch instruction. A value of 1 is |
| 10662 | +the default; other values are interpreted relative to that. |
| 10663 | +*/ |
| 10664 | + /* Try to use conditionals as much as possible */ |
| 10665 | +#define BRANCH_COST(speed_p, predictable_p) (TARGET_BRANCH_PRED ? 3 : 4) |
| 10666 | + |
| 10667 | +/*A C expression for the maximum number of instructions to execute via conditional |
| 10668 | + execution instructions instead of a branch. A value of BRANCH_COST+1 is the default |
| 10669 | + if the machine does not use cc0, and 1 if it does use cc0.*/ |
| 10670 | +#define MAX_CONDITIONAL_EXECUTE 4 |
| 10671 | + |
| 10672 | +/* |
| 10673 | +Define this macro as a C expression which is nonzero if accessing less |
| 10674 | +than a word of memory (i.e.: a char or a short) is no |
| 10675 | +faster than accessing a word of memory, i.e., if such access |
| 10676 | +require more than one instruction or if there is no difference in cost |
| 10677 | +between byte and (aligned) word loads. |
| 10678 | + |
| 10679 | +When this macro is not defined, the compiler will access a field by |
| 10680 | +finding the smallest containing object; when it is defined, a fullword |
| 10681 | +load will be used if alignment permits. Unless bytes accesses are |
| 10682 | +faster than word accesses, using word accesses is preferable since it |
| 10683 | +may eliminate subsequent memory access if subsequent accesses occur to |
| 10684 | +other fields in the same word of the structure, but to different bytes. |
| 10685 | +*/ |
| 10686 | +#define SLOW_BYTE_ACCESS 1 |
| 10687 | + |
| 10688 | + |
| 10689 | +/* |
| 10690 | +Define this macro if it is as good or better to call a constant |
| 10691 | +function address than to call an address kept in a register. |
| 10692 | +*/ |
| 10693 | +#define NO_FUNCTION_CSE |
| 10694 | + |
| 10695 | + |
| 10696 | +/****************************************************************************** |
| 10697 | + * Adjusting the Instruction Scheduler |
| 10698 | + *****************************************************************************/ |
| 10699 | + |
| 10700 | +/***************************************************************************** |
| 10701 | + * Dividing the Output into Sections (Texts, Data, ...) * |
| 10702 | + *****************************************************************************/ |
| 10703 | + |
| 10704 | +/* |
| 10705 | +A C expression whose value is a string, including spacing, containing the |
| 10706 | +assembler operation that should precede instructions and read-only data. |
| 10707 | +Normally "\t.text" is right. |
| 10708 | +*/ |
| 10709 | +#define TEXT_SECTION_ASM_OP "\t.text" |
| 10710 | +/* |
| 10711 | +A C statement that switches to the default section containing instructions. |
| 10712 | +Normally this is not needed, as simply defining TEXT_SECTION_ASM_OP |
| 10713 | +is enough. The MIPS port uses this to sort all functions after all data |
| 10714 | +declarations. |
| 10715 | +*/ |
| 10716 | +/* #define TEXT_SECTION */ |
| 10717 | + |
| 10718 | +/* |
| 10719 | +A C expression whose value is a string, including spacing, containing the |
| 10720 | +assembler operation to identify the following data as writable initialized |
| 10721 | +data. Normally "\t.data" is right. |
| 10722 | +*/ |
| 10723 | +#define DATA_SECTION_ASM_OP "\t.data" |
| 10724 | + |
| 10725 | +/* |
| 10726 | +If defined, a C expression whose value is a string, including spacing, |
| 10727 | +containing the assembler operation to identify the following data as |
| 10728 | +shared data. If not defined, DATA_SECTION_ASM_OP will be used. |
| 10729 | +*/ |
| 10730 | + |
| 10731 | +/* |
| 10732 | +A C expression whose value is a string, including spacing, containing |
| 10733 | +the assembler operation to identify the following data as read-only |
| 10734 | +initialized data. |
| 10735 | +*/ |
| 10736 | +#undef READONLY_DATA_SECTION_ASM_OP |
| 10737 | +#define READONLY_DATA_SECTION_ASM_OP \ |
| 10738 | + ((TARGET_USE_RODATA_SECTION) ? \ |
| 10739 | + "\t.section\t.rodata" : \ |
| 10740 | + TEXT_SECTION_ASM_OP ) |
| 10741 | + |
| 10742 | + |
| 10743 | +/* |
| 10744 | +If defined, a C expression whose value is a string, including spacing, |
| 10745 | +containing the assembler operation to identify the following data as |
| 10746 | +uninitialized global data. If not defined, and neither |
| 10747 | +ASM_OUTPUT_BSS nor ASM_OUTPUT_ALIGNED_BSS are defined, |
| 10748 | +uninitialized global data will be output in the data section if |
| 10749 | +-fno-common is passed, otherwise ASM_OUTPUT_COMMON will be |
| 10750 | +used. |
| 10751 | +*/ |
| 10752 | +#define BSS_SECTION_ASM_OP "\t.section\t.bss" |
| 10753 | + |
| 10754 | +/* |
| 10755 | +If defined, a C expression whose value is a string, including spacing, |
| 10756 | +containing the assembler operation to identify the following data as |
| 10757 | +uninitialized global shared data. If not defined, and |
| 10758 | +BSS_SECTION_ASM_OP is, the latter will be used. |
| 10759 | +*/ |
| 10760 | +/*#define SHARED_BSS_SECTION_ASM_OP "\trseg\tshared_bbs_section:data:noroot(0)\n"*/ |
| 10761 | +/* |
| 10762 | +If defined, a C expression whose value is a string, including spacing, |
| 10763 | +containing the assembler operation to identify the following data as |
| 10764 | +initialization code. If not defined, GCC will assume such a section does |
| 10765 | +not exist. |
| 10766 | +*/ |
| 10767 | +#undef INIT_SECTION_ASM_OP |
| 10768 | +#define INIT_SECTION_ASM_OP "\t.section\t.init" |
| 10769 | + |
| 10770 | +/* |
| 10771 | +If defined, a C expression whose value is a string, including spacing, |
| 10772 | +containing the assembler operation to identify the following data as |
| 10773 | +finalization code. If not defined, GCC will assume such a section does |
| 10774 | +not exist. |
| 10775 | +*/ |
| 10776 | +#undef FINI_SECTION_ASM_OP |
| 10777 | +#define FINI_SECTION_ASM_OP "\t.section\t.fini" |
| 10778 | + |
| 10779 | +/* |
| 10780 | +If defined, an ASM statement that switches to a different section |
| 10781 | +via SECTION_OP, calls FUNCTION, and switches back to |
| 10782 | +the text section. This is used in crtstuff.c if |
| 10783 | +INIT_SECTION_ASM_OP or FINI_SECTION_ASM_OP to calls |
| 10784 | +to initialization and finalization functions from the init and fini |
| 10785 | +sections. By default, this macro uses a simple function call. Some |
| 10786 | +ports need hand-crafted assembly code to avoid dependencies on |
| 10787 | +registers initialized in the function prologue or to ensure that |
| 10788 | +constant pools don't end up too far way in the text section. |
| 10789 | +*/ |
| 10790 | +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ |
| 10791 | + asm ( SECTION_OP "\n" \ |
| 10792 | + "mcall r6[" USER_LABEL_PREFIX #FUNC "@got]\n" \ |
| 10793 | + TEXT_SECTION_ASM_OP); |
| 10794 | + |
| 10795 | + |
| 10796 | +/* |
| 10797 | +Define this macro to be an expression with a nonzero value if jump |
| 10798 | +tables (for tablejump insns) should be output in the text |
| 10799 | +section, along with the assembler instructions. Otherwise, the |
| 10800 | +readonly data section is used. |
| 10801 | + |
| 10802 | +This macro is irrelevant if there is no separate readonly data section. |
| 10803 | +*/ |
| 10804 | +/* Put jump tables in text section if we have caches. Otherwise assume that |
| 10805 | + loading data from code memory is slow. */ |
| 10806 | +#define JUMP_TABLES_IN_TEXT_SECTION \ |
| 10807 | + (TARGET_CACHES ? 1 : 0) |
| 10808 | + |
| 10809 | + |
| 10810 | +/****************************************************************************** |
| 10811 | + * Position Independent Code (PIC) |
| 10812 | + *****************************************************************************/ |
| 10813 | + |
| 10814 | +#ifndef AVR32_ALWAYS_PIC |
| 10815 | +#define AVR32_ALWAYS_PIC 0 |
| 10816 | +#endif |
| 10817 | + |
| 10818 | +/* GOT is set to r6 */ |
| 10819 | +#define PIC_OFFSET_TABLE_REGNUM INTERNAL_REGNUM(6) |
| 10820 | + |
| 10821 | +/* |
| 10822 | +A C expression that is nonzero if X is a legitimate immediate |
| 10823 | +operand on the target machine when generating position independent code. |
| 10824 | +You can assume that X satisfies CONSTANT_P, so you need not |
| 10825 | +check this. You can also assume flag_pic is true, so you need not |
| 10826 | +check it either. You need not define this macro if all constants |
| 10827 | +(including SYMBOL_REF) can be immediate operands when generating |
| 10828 | +position independent code. |
| 10829 | +*/ |
| 10830 | +/* We can't directly access anything that contains a symbol, |
| 10831 | + nor can we indirect via the constant pool. */ |
| 10832 | +#define LEGITIMATE_PIC_OPERAND_P(X) avr32_legitimate_pic_operand_p(X) |
| 10833 | + |
| 10834 | + |
| 10835 | +/* We need to know when we are making a constant pool; this determines |
| 10836 | + whether data needs to be in the GOT or can be referenced via a GOT |
| 10837 | + offset. */ |
| 10838 | +extern int making_const_table; |
| 10839 | + |
| 10840 | +/****************************************************************************** |
| 10841 | + * Defining the Output Assembler Language |
| 10842 | + *****************************************************************************/ |
| 10843 | + |
| 10844 | + |
| 10845 | +/* |
| 10846 | +A C string constant describing how to begin a comment in the target |
| 10847 | +assembler language. The compiler assumes that the comment will end at |
| 10848 | +the end of the line. |
| 10849 | +*/ |
| 10850 | +#define ASM_COMMENT_START "# " |
| 10851 | + |
| 10852 | +/* |
| 10853 | +A C string constant for text to be output before each asm |
| 10854 | +statement or group of consecutive ones. Normally this is |
| 10855 | +"#APP", which is a comment that has no effect on most |
| 10856 | +assemblers but tells the GNU assembler that it must check the lines |
| 10857 | +that follow for all valid assembler constructs. |
| 10858 | +*/ |
| 10859 | +#undef ASM_APP_ON |
| 10860 | +#define ASM_APP_ON "#APP\n" |
| 10861 | + |
| 10862 | +/* |
| 10863 | +A C string constant for text to be output after each asm |
| 10864 | +statement or group of consecutive ones. Normally this is |
| 10865 | +"#NO_APP", which tells the GNU assembler to resume making the |
| 10866 | +time-saving assumptions that are valid for ordinary compiler output. |
| 10867 | +*/ |
| 10868 | +#undef ASM_APP_OFF |
| 10869 | +#define ASM_APP_OFF "#NO_APP\n" |
| 10870 | + |
| 10871 | + |
| 10872 | + |
| 10873 | +#define FILE_ASM_OP "\t.file\n" |
| 10874 | +#define IDENT_ASM_OP "\t.ident\t" |
| 10875 | +#define SET_ASM_OP "\t.set\t" |
| 10876 | + |
| 10877 | + |
| 10878 | +/* |
| 10879 | + * Output assembly directives to switch to section name. The section |
| 10880 | + * should have attributes as specified by flags, which is a bit mask |
| 10881 | + * of the SECTION_* flags defined in 'output.h'. If align is nonzero, |
| 10882 | + * it contains an alignment in bytes to be used for the section, |
| 10883 | + * otherwise some target default should be used. Only targets that |
| 10884 | + * must specify an alignment within the section directive need pay |
| 10885 | + * attention to align -- we will still use ASM_OUTPUT_ALIGN. |
| 10886 | + * |
| 10887 | + * NOTE: This one must not be moved to avr32.c |
| 10888 | + */ |
| 10889 | +#undef TARGET_ASM_NAMED_SECTION |
| 10890 | +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section |
| 10891 | + |
| 10892 | + |
| 10893 | +/* |
| 10894 | +You may define this macro as a C expression. You should define the |
| 10895 | +expression to have a nonzero value if GCC should output the constant |
| 10896 | +pool for a function before the code for the function, or a zero value if |
| 10897 | +GCC should output the constant pool after the function. If you do |
| 10898 | +not define this macro, the usual case, GCC will output the constant |
| 10899 | +pool before the function. |
| 10900 | +*/ |
| 10901 | +#define CONSTANT_POOL_BEFORE_FUNCTION 0 |
| 10902 | + |
| 10903 | + |
| 10904 | +/* |
| 10905 | +Define this macro as a C expression which is nonzero if the constant |
| 10906 | +EXP, of type tree, should be output after the code for a |
| 10907 | +function. The compiler will normally output all constants before the |
| 10908 | +function; you need not define this macro if this is OK. |
| 10909 | +*/ |
| 10910 | +#define CONSTANT_AFTER_FUNCTION_P(EXP) 1 |
| 10911 | + |
| 10912 | + |
| 10913 | +/* |
| 10914 | +Define this macro as a C expression which is nonzero if C is |
| 10915 | +as a logical line separator by the assembler. STR points to the |
| 10916 | +position in the string where C was found; this can be used if a |
| 10917 | +line separator uses multiple characters. |
| 10918 | + |
| 10919 | +If you do not define this macro, the default is that only |
| 10920 | +the character ';' is treated as a logical line separator. |
| 10921 | +*/ |
| 10922 | +#define IS_ASM_LOGICAL_LINE_SEPARATOR(C,STR) (((C) == '\n') || ((C) == ';')) |
| 10923 | + |
| 10924 | + |
| 10925 | +/** Output of Uninitialized Variables **/ |
| 10926 | + |
| 10927 | +/* |
| 10928 | +A C statement (sans semicolon) to output to the stdio stream |
| 10929 | +STREAM the assembler definition of a common-label named |
| 10930 | +NAME whose size is SIZE bytes. The variable ROUNDED |
| 10931 | +is the size rounded up to whatever alignment the caller wants. |
| 10932 | + |
| 10933 | +Use the expression assemble_name(STREAM, NAME) to |
| 10934 | +output the name itself; before and after that, output the additional |
| 10935 | +assembler syntax for defining the name, and a newline. |
| 10936 | + |
| 10937 | +This macro controls how the assembler definitions of uninitialized |
| 10938 | +common global variables are output. |
| 10939 | +*/ |
| 10940 | +/* |
| 10941 | +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ |
| 10942 | + avr32_asm_output_common(STREAM, NAME, SIZE, ROUNDED) |
| 10943 | +*/ |
| 10944 | + |
| 10945 | +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ |
| 10946 | + do \ |
| 10947 | + { \ |
| 10948 | + fputs ("\t.comm ", (FILE)); \ |
| 10949 | + assemble_name ((FILE), (NAME)); \ |
| 10950 | + fprintf ((FILE), ",%d\n", (SIZE)); \ |
| 10951 | + } \ |
| 10952 | + while (0) |
| 10953 | + |
| 10954 | +/* |
| 10955 | + * Like ASM_OUTPUT_BSS except takes the required alignment as a |
| 10956 | + * separate, explicit argument. If you define this macro, it is used |
| 10957 | + * in place of ASM_OUTPUT_BSS, and gives you more flexibility in |
| 10958 | + * handling the required alignment of the variable. The alignment is |
| 10959 | + * specified as the number of bits. |
| 10960 | + * |
| 10961 | + * Try to use function asm_output_aligned_bss defined in file varasm.c |
| 10962 | + * when defining this macro. |
| 10963 | + */ |
| 10964 | +#define ASM_OUTPUT_ALIGNED_BSS(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ |
| 10965 | + asm_output_aligned_bss (STREAM, DECL, NAME, SIZE, ALIGNMENT) |
| 10966 | + |
| 10967 | +/* |
| 10968 | +A C statement (sans semicolon) to output to the stdio stream |
| 10969 | +STREAM the assembler definition of a local-common-label named |
| 10970 | +NAME whose size is SIZE bytes. The variable ROUNDED |
| 10971 | +is the size rounded up to whatever alignment the caller wants. |
| 10972 | + |
| 10973 | +Use the expression assemble_name(STREAM, NAME) to |
| 10974 | +output the name itself; before and after that, output the additional |
| 10975 | +assembler syntax for defining the name, and a newline. |
| 10976 | + |
| 10977 | +This macro controls how the assembler definitions of uninitialized |
| 10978 | +static variables are output. |
| 10979 | +*/ |
| 10980 | +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ |
| 10981 | + do \ |
| 10982 | + { \ |
| 10983 | + fputs ("\t.lcomm ", (FILE)); \ |
| 10984 | + assemble_name ((FILE), (NAME)); \ |
| 10985 | + fprintf ((FILE), ",%d, %d\n", (SIZE), 2); \ |
| 10986 | + } \ |
| 10987 | + while (0) |
| 10988 | + |
| 10989 | + |
| 10990 | +/* |
| 10991 | +A C statement (sans semicolon) to output to the stdio stream |
| 10992 | +STREAM the assembler definition of a label named NAME. |
| 10993 | +Use the expression assemble_name(STREAM, NAME) to |
| 10994 | +output the name itself; before and after that, output the additional |
| 10995 | +assembler syntax for defining the name, and a newline. |
| 10996 | +*/ |
| 10997 | +#define ASM_OUTPUT_LABEL(STREAM, NAME) avr32_asm_output_label(STREAM, NAME) |
| 10998 | + |
| 10999 | +/* A C string containing the appropriate assembler directive to |
| 11000 | + * specify the size of a symbol, without any arguments. On systems |
| 11001 | + * that use ELF, the default (in 'config/elfos.h') is '"\t.size\t"'; |
| 11002 | + * on other systems, the default is not to define this macro. |
| 11003 | + * |
| 11004 | + * Define this macro only if it is correct to use the default |
| 11005 | + * definitions of ASM_ OUTPUT_SIZE_DIRECTIVE and |
| 11006 | + * ASM_OUTPUT_MEASURED_SIZE for your system. If you need your own |
| 11007 | + * custom definitions of those macros, or if you do not need explicit |
| 11008 | + * symbol sizes at all, do not define this macro. |
| 11009 | + */ |
| 11010 | +#define SIZE_ASM_OP "\t.size\t" |
| 11011 | + |
| 11012 | + |
| 11013 | +/* |
| 11014 | +A C statement (sans semicolon) to output to the stdio stream |
| 11015 | +STREAM some commands that will make the label NAME global; |
| 11016 | +that is, available for reference from other files. Use the expression |
| 11017 | +assemble_name(STREAM, NAME) to output the name |
| 11018 | +itself; before and after that, output the additional assembler syntax |
| 11019 | +for making that name global, and a newline. |
| 11020 | +*/ |
| 11021 | +#define GLOBAL_ASM_OP "\t.global\t" |
| 11022 | + |
| 11023 | + |
| 11024 | + |
| 11025 | +/* |
| 11026 | +A C expression which evaluates to true if the target supports weak symbols. |
| 11027 | + |
| 11028 | +If you don't define this macro, defaults.h provides a default |
| 11029 | +definition. If either ASM_WEAKEN_LABEL or ASM_WEAKEN_DECL |
| 11030 | +is defined, the default definition is '1'; otherwise, it is |
| 11031 | +'0'. Define this macro if you want to control weak symbol support |
| 11032 | +with a compiler flag such as -melf. |
| 11033 | +*/ |
| 11034 | +#define SUPPORTS_WEAK 1 |
| 11035 | + |
| 11036 | +/* |
| 11037 | +A C statement (sans semicolon) to output to the stdio stream |
| 11038 | +STREAM a reference in assembler syntax to a label named |
| 11039 | +NAME. This should add '_' to the front of the name, if that |
| 11040 | +is customary on your operating system, as it is in most Berkeley Unix |
| 11041 | +systems. This macro is used in assemble_name. |
| 11042 | +*/ |
| 11043 | +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ |
| 11044 | + avr32_asm_output_labelref(STREAM, NAME) |
| 11045 | + |
| 11046 | + |
| 11047 | + |
| 11048 | +/* |
| 11049 | +A C expression to assign to OUTVAR (which is a variable of type |
| 11050 | +char *) a newly allocated string made from the string |
| 11051 | +NAME and the number NUMBER, with some suitable punctuation |
| 11052 | +added. Use alloca to get space for the string. |
| 11053 | + |
| 11054 | +The string will be used as an argument to ASM_OUTPUT_LABELREF to |
| 11055 | +produce an assembler label for an internal static variable whose name is |
| 11056 | +NAME. Therefore, the string must be such as to result in valid |
| 11057 | +assembler code. The argument NUMBER is different each time this |
| 11058 | +macro is executed; it prevents conflicts between similarly-named |
| 11059 | +internal static variables in different scopes. |
| 11060 | + |
| 11061 | +Ideally this string should not be a valid C identifier, to prevent any |
| 11062 | +conflict with the user's own symbols. Most assemblers allow periods |
| 11063 | +or percent signs in assembler symbols; putting at least one of these |
| 11064 | +between the name and the number will suffice. |
| 11065 | +*/ |
| 11066 | +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR, NAME, NUMBER) \ |
| 11067 | + do \ |
| 11068 | + { \ |
| 11069 | + (OUTVAR) = (char *) alloca (strlen ((NAME)) + 10); \ |
| 11070 | + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER)); \ |
| 11071 | + } \ |
| 11072 | + while (0) |
| 11073 | + |
| 11074 | + |
| 11075 | +/** Macros Controlling Initialization Routines **/ |
| 11076 | + |
| 11077 | + |
| 11078 | +/* |
| 11079 | +If defined, main will not call __main as described above. |
| 11080 | +This macro should be defined for systems that control start-up code |
| 11081 | +on a symbol-by-symbol basis, such as OSF/1, and should not |
| 11082 | +be defined explicitly for systems that support INIT_SECTION_ASM_OP. |
| 11083 | +*/ |
| 11084 | +/* |
| 11085 | + __main is not defined when debugging. |
| 11086 | +*/ |
| 11087 | +#define HAS_INIT_SECTION |
| 11088 | + |
| 11089 | + |
| 11090 | +/** Output of Assembler Instructions **/ |
| 11091 | + |
| 11092 | +/* |
| 11093 | +A C initializer containing the assembler's names for the machine |
| 11094 | +registers, each one as a C string constant. This is what translates |
| 11095 | +register numbers in the compiler into assembler language. |
| 11096 | +*/ |
| 11097 | + |
| 11098 | +#define REGISTER_NAMES \ |
| 11099 | +{ \ |
| 11100 | + "pc", "lr", \ |
| 11101 | + "sp", "r12", \ |
| 11102 | + "r11", "r10", \ |
| 11103 | + "r9", "r8", \ |
| 11104 | + "r7", "r6", \ |
| 11105 | + "r5", "r4", \ |
| 11106 | + "r3", "r2", \ |
| 11107 | + "r1", "r0", \ |
| 11108 | +} |
| 11109 | + |
| 11110 | +/* |
| 11111 | +A C compound statement to output to stdio stream STREAM the |
| 11112 | +assembler syntax for an instruction operand X. X is an |
| 11113 | +RTL expression. |
| 11114 | + |
| 11115 | +CODE is a value that can be used to specify one of several ways |
| 11116 | +of printing the operand. It is used when identical operands must be |
| 11117 | +printed differently depending on the context. CODE comes from |
| 11118 | +the '%' specification that was used to request printing of the |
| 11119 | +operand. If the specification was just '%digit' then |
| 11120 | +CODE is 0; if the specification was '%ltr digit' |
| 11121 | +then CODE is the ASCII code for ltr. |
| 11122 | + |
| 11123 | +If X is a register, this macro should print the register's name. |
| 11124 | +The names can be found in an array reg_names whose type is |
| 11125 | +char *[]. reg_names is initialized from REGISTER_NAMES. |
| 11126 | + |
| 11127 | +When the machine description has a specification '%punct' |
| 11128 | +(a '%' followed by a punctuation character), this macro is called |
| 11129 | +with a null pointer for X and the punctuation character for |
| 11130 | +CODE. |
| 11131 | +*/ |
| 11132 | +#define PRINT_OPERAND(STREAM, X, CODE) avr32_print_operand(STREAM, X, CODE) |
| 11133 | + |
| 11134 | +/* A C statement to be executed just prior to the output of |
| 11135 | + assembler code for INSN, to modify the extracted operands so |
| 11136 | + they will be output differently. |
| 11137 | + |
| 11138 | + Here the argument OPVEC is the vector containing the operands |
| 11139 | + extracted from INSN, and NOPERANDS is the number of elements of |
| 11140 | + the vector which contain meaningful data for this insn. |
| 11141 | + The contents of this vector are what will be used to convert the insn |
| 11142 | + template into assembler code, so you can change the assembler output |
| 11143 | + by changing the contents of the vector. */ |
| 11144 | +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ |
| 11145 | + avr32_final_prescan_insn ((INSN), (OPVEC), (NOPERANDS)) |
| 11146 | + |
| 11147 | +/* |
| 11148 | +A C expression which evaluates to true if CODE is a valid |
| 11149 | +punctuation character for use in the PRINT_OPERAND macro. If |
| 11150 | +PRINT_OPERAND_PUNCT_VALID_P is not defined, it means that no |
| 11151 | +punctuation characters (except for the standard one, '%') are used |
| 11152 | +in this way. |
| 11153 | +*/ |
| 11154 | +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ |
| 11155 | + (((CODE) == '?') \ |
| 11156 | + || ((CODE) == '!')) |
| 11157 | + |
| 11158 | +/* |
| 11159 | +A C compound statement to output to stdio stream STREAM the |
| 11160 | +assembler syntax for an instruction operand that is a memory reference |
| 11161 | +whose address is X. X is an RTL expression. |
| 11162 | + |
| 11163 | +On some machines, the syntax for a symbolic address depends on the |
| 11164 | +section that the address refers to. On these machines, define the macro |
| 11165 | +ENCODE_SECTION_INFO to store the information into the |
| 11166 | +symbol_ref, and then check for it here. (see Assembler Format.) |
| 11167 | +*/ |
| 11168 | +#define PRINT_OPERAND_ADDRESS(STREAM, X) avr32_print_operand_address(STREAM, X) |
| 11169 | + |
| 11170 | + |
| 11171 | +/** Output of Dispatch Tables **/ |
| 11172 | + |
| 11173 | +/* |
| 11174 | + * A C statement to output to the stdio stream stream an assembler |
| 11175 | + * pseudo-instruction to generate a difference between two |
| 11176 | + * labels. value and rel are the numbers of two internal labels. The |
| 11177 | + * definitions of these labels are output using |
| 11178 | + * (*targetm.asm_out.internal_label), and they must be printed in the |
| 11179 | + * same way here. For example, |
| 11180 | + * |
| 11181 | + * fprintf (stream, "\t.word L%d-L%d\n", |
| 11182 | + * value, rel) |
| 11183 | + * |
| 11184 | + * You must provide this macro on machines where the addresses in a |
| 11185 | + * dispatch table are relative to the table's own address. If defined, |
| 11186 | + * GCC will also use this macro on all machines when producing |
| 11187 | + * PIC. body is the body of the ADDR_DIFF_VEC; it is provided so that |
| 11188 | + * the mode and flags can be read. |
| 11189 | + */ |
| 11190 | +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \ |
| 11191 | + fprintf(STREAM, "\tbral\t%sL%d\n", LOCAL_LABEL_PREFIX, VALUE) |
| 11192 | + |
| 11193 | +/* |
| 11194 | +This macro should be provided on machines where the addresses |
| 11195 | +in a dispatch table are absolute. |
| 11196 | + |
| 11197 | +The definition should be a C statement to output to the stdio stream |
| 11198 | +STREAM an assembler pseudo-instruction to generate a reference to |
| 11199 | +a label. VALUE is the number of an internal label whose |
| 11200 | +definition is output using ASM_OUTPUT_INTERNAL_LABEL. |
| 11201 | +For example, |
| 11202 | + |
| 11203 | +fprintf(STREAM, "\t.word L%d\n", VALUE) |
| 11204 | +*/ |
| 11205 | + |
| 11206 | +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ |
| 11207 | + fprintf(STREAM, "\t.long %sL%d\n", LOCAL_LABEL_PREFIX, VALUE) |
| 11208 | + |
| 11209 | +/** Assembler Commands for Exception Regions */ |
| 11210 | + |
| 11211 | +/* ToDo: All of this subsection */ |
| 11212 | + |
| 11213 | +/** Assembler Commands for Alignment */ |
| 11214 | + |
| 11215 | + |
| 11216 | +/* |
| 11217 | +A C statement to output to the stdio stream STREAM an assembler |
| 11218 | +command to advance the location counter to a multiple of 2 to the |
| 11219 | +POWER bytes. POWER will be a C expression of type int. |
| 11220 | +*/ |
| 11221 | +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ |
| 11222 | + do \ |
| 11223 | + { \ |
| 11224 | + if ((POWER) != 0) \ |
| 11225 | + fprintf(STREAM, "\t.align\t%d\n", POWER); \ |
| 11226 | + } \ |
| 11227 | + while (0) |
| 11228 | + |
| 11229 | +/* |
| 11230 | +Like ASM_OUTPUT_ALIGN, except that the \nop" instruction is used for padding, if |
| 11231 | +necessary. |
| 11232 | +*/ |
| 11233 | +#define ASM_OUTPUT_ALIGN_WITH_NOP(STREAM, POWER) \ |
| 11234 | + fprintf(STREAM, "\t.balignw\t%d, 0xd703\n", (1 << POWER)) |
| 11235 | + |
| 11236 | + |
| 11237 | + |
| 11238 | +/****************************************************************************** |
| 11239 | + * Controlling Debugging Information Format |
| 11240 | + *****************************************************************************/ |
| 11241 | + |
| 11242 | +/* How to renumber registers for dbx and gdb. */ |
| 11243 | +#define DBX_REGISTER_NUMBER(REGNO) ASM_REGNUM (REGNO) |
| 11244 | + |
| 11245 | +/* The DWARF 2 CFA column which tracks the return address. */ |
| 11246 | +#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM(LR_REGNUM) |
| 11247 | + |
| 11248 | +/* |
| 11249 | +Define this macro if GCC should produce dwarf version 2 format |
| 11250 | +debugging output in response to the -g option. |
| 11251 | + |
| 11252 | +To support optional call frame debugging information, you must also |
| 11253 | +define INCOMING_RETURN_ADDR_RTX and either set |
| 11254 | +RTX_FRAME_RELATED_P on the prologue insns if you use RTL for the |
| 11255 | +prologue, or call dwarf2out_def_cfa and dwarf2out_reg_save |
| 11256 | +as appropriate from TARGET_ASM_FUNCTION_PROLOGUE if you don't. |
| 11257 | +*/ |
| 11258 | +#define DWARF2_DEBUGGING_INFO 1 |
| 11259 | + |
| 11260 | + |
| 11261 | +#define DWARF2_ASM_LINE_DEBUG_INFO 1 |
| 11262 | +#define DWARF2_FRAME_INFO 1 |
| 11263 | + |
| 11264 | + |
| 11265 | +/****************************************************************************** |
| 11266 | + * Miscellaneous Parameters |
| 11267 | + *****************************************************************************/ |
| 11268 | + |
| 11269 | +/* ToDo: a lot */ |
| 11270 | + |
| 11271 | +/* |
| 11272 | +An alias for a machine mode name. This is the machine mode that |
| 11273 | +elements of a jump-table should have. |
| 11274 | +*/ |
| 11275 | +#define CASE_VECTOR_MODE SImode |
| 11276 | + |
| 11277 | +/* |
| 11278 | +Define this macro to be a C expression to indicate when jump-tables |
| 11279 | +should contain relative addresses. If jump-tables never contain |
| 11280 | +relative addresses, then you need not define this macro. |
| 11281 | +*/ |
| 11282 | +#define CASE_VECTOR_PC_RELATIVE 0 |
| 11283 | + |
| 11284 | +/* Increase the threshold for using table jumps on the UC arch. */ |
| 11285 | +#define CASE_VALUES_THRESHOLD (TARGET_BRANCH_PRED ? 4 : 7) |
| 11286 | + |
| 11287 | +/* |
| 11288 | +The maximum number of bytes that a single instruction can move quickly |
| 11289 | +between memory and registers or between two memory locations. |
| 11290 | +*/ |
| 11291 | +#define MOVE_MAX (2*UNITS_PER_WORD) |
| 11292 | + |
| 11293 | + |
| 11294 | +/* A C expression that is nonzero if on this machine the number of bits actually used |
| 11295 | + for the count of a shift operation is equal to the number of bits needed to represent |
| 11296 | + the size of the object being shifted. When this macro is nonzero, the compiler will |
| 11297 | + assume that it is safe to omit a sign-extend, zero-extend, and certain bitwise 'and' |
| 11298 | + instructions that truncates the count of a shift operation. On machines that have |
| 11299 | + instructions that act on bit-fields at variable positions, which may include 'bit test' |
| 11300 | + 378 GNU Compiler Collection (GCC) Internals |
| 11301 | + instructions, a nonzero SHIFT_COUNT_TRUNCATED also enables deletion of truncations |
| 11302 | + of the values that serve as arguments to bit-field instructions. |
| 11303 | + If both types of instructions truncate the count (for shifts) and position (for bit-field |
| 11304 | + operations), or if no variable-position bit-field instructions exist, you should define |
| 11305 | + this macro. |
| 11306 | + However, on some machines, such as the 80386 and the 680x0, truncation only applies |
| 11307 | + to shift operations and not the (real or pretended) bit-field operations. Define SHIFT_ |
| 11308 | + COUNT_TRUNCATED to be zero on such machines. Instead, add patterns to the 'md' file |
| 11309 | + that include the implied truncation of the shift instructions. |
| 11310 | + You need not dene this macro if it would always have the value of zero. */ |
| 11311 | +#define SHIFT_COUNT_TRUNCATED 1 |
| 11312 | + |
| 11313 | +/* |
| 11314 | +A C expression which is nonzero if on this machine it is safe to |
| 11315 | +convert an integer of INPREC bits to one of OUTPREC |
| 11316 | +bits (where OUTPREC is smaller than INPREC) by merely |
| 11317 | +operating on it as if it had only OUTPREC bits. |
| 11318 | + |
| 11319 | +On many machines, this expression can be 1. |
| 11320 | + |
| 11321 | +When TRULY_NOOP_TRUNCATION returns 1 for a pair of sizes for |
| 11322 | +modes for which MODES_TIEABLE_P is 0, suboptimal code can result. |
| 11323 | +If this is the case, making TRULY_NOOP_TRUNCATION return 0 in |
| 11324 | +such cases may improve things. |
| 11325 | +*/ |
| 11326 | +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 |
| 11327 | + |
| 11328 | +/* |
| 11329 | +An alias for the machine mode for pointers. On most machines, define |
| 11330 | +this to be the integer mode corresponding to the width of a hardware |
| 11331 | +pointer; SImode on 32-bit machine or DImode on 64-bit machines. |
| 11332 | +On some machines you must define this to be one of the partial integer |
| 11333 | +modes, such as PSImode. |
| 11334 | + |
| 11335 | +The width of Pmode must be at least as large as the value of |
| 11336 | +POINTER_SIZE. If it is not equal, you must define the macro |
| 11337 | +POINTERS_EXTEND_UNSIGNED to specify how pointers are extended |
| 11338 | +to Pmode. |
| 11339 | +*/ |
| 11340 | +#define Pmode SImode |
| 11341 | + |
| 11342 | +/* |
| 11343 | +An alias for the machine mode used for memory references to functions |
| 11344 | +being called, in call RTL expressions. On most machines this |
| 11345 | +should be QImode. |
| 11346 | +*/ |
| 11347 | +#define FUNCTION_MODE SImode |
| 11348 | + |
| 11349 | + |
| 11350 | +#define REG_S_P(x) \ |
| 11351 | + (REG_P (x) || (GET_CODE (x) == SUBREG && REG_P (XEXP (x, 0)))) |
| 11352 | + |
| 11353 | + |
| 11354 | +/* If defined, modifies the length assigned to instruction INSN as a |
| 11355 | + function of the context in which it is used. LENGTH is an lvalue |
| 11356 | + that contains the initially computed length of the insn and should |
| 11357 | + be updated with the correct length of the insn. */ |
| 11358 | +#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ |
| 11359 | + ((LENGTH) = avr32_adjust_insn_length ((INSN), (LENGTH))) |
| 11360 | + |
| 11361 | + |
| 11362 | +#define CLZ_DEFINED_VALUE_AT_ZERO(mode, value) \ |
| 11363 | + (value = 32, (mode == SImode)) |
| 11364 | + |
| 11365 | +#define CTZ_DEFINED_VALUE_AT_ZERO(mode, value) \ |
| 11366 | + (value = 32, (mode == SImode)) |
| 11367 | + |
| 11368 | +#define UNITS_PER_SIMD_WORD(mode) UNITS_PER_WORD |
| 11369 | + |
| 11370 | +#define STORE_FLAG_VALUE 1 |
| 11371 | + |
| 11372 | + |
| 11373 | +/* IF-conversion macros. */ |
| 11374 | +#define IFCVT_MODIFY_INSN( CE_INFO, PATTERN, INSN ) \ |
| 11375 | + { \ |
| 11376 | + (PATTERN) = avr32_ifcvt_modify_insn (CE_INFO, PATTERN, INSN, &num_true_changes); \ |
| 11377 | + } |
| 11378 | + |
| 11379 | +#define IFCVT_EXTRA_FIELDS \ |
| 11380 | + int num_cond_clobber_insns; \ |
| 11381 | + int num_extra_move_insns; \ |
| 11382 | + rtx extra_move_insns[MAX_CONDITIONAL_EXECUTE]; \ |
| 11383 | + rtx moved_insns[MAX_CONDITIONAL_EXECUTE]; |
| 11384 | + |
| 11385 | +#define IFCVT_INIT_EXTRA_FIELDS( CE_INFO ) \ |
| 11386 | + { \ |
| 11387 | + (CE_INFO)->num_cond_clobber_insns = 0; \ |
| 11388 | + (CE_INFO)->num_extra_move_insns = 0; \ |
| 11389 | + } |
| 11390 | + |
| 11391 | + |
| 11392 | +#define IFCVT_MODIFY_CANCEL( CE_INFO ) avr32_ifcvt_modify_cancel (CE_INFO, &num_true_changes) |
| 11393 | + |
| 11394 | +#define IFCVT_ALLOW_MODIFY_TEST_IN_INSN 1 |
| 11395 | +#define IFCVT_COND_EXEC_BEFORE_RELOAD (TARGET_COND_EXEC_BEFORE_RELOAD) |
| 11396 | + |
| 11397 | +enum avr32_builtins |
| 11398 | +{ |
| 11399 | + AVR32_BUILTIN_MTSR, |
| 11400 | + AVR32_BUILTIN_MFSR, |
| 11401 | + AVR32_BUILTIN_MTDR, |
| 11402 | + AVR32_BUILTIN_MFDR, |
| 11403 | + AVR32_BUILTIN_CACHE, |
| 11404 | + AVR32_BUILTIN_SYNC, |
| 11405 | + AVR32_BUILTIN_SSRF, |
| 11406 | + AVR32_BUILTIN_CSRF, |
| 11407 | + AVR32_BUILTIN_TLBR, |
| 11408 | + AVR32_BUILTIN_TLBS, |
| 11409 | + AVR32_BUILTIN_TLBW, |
| 11410 | + AVR32_BUILTIN_BREAKPOINT, |
| 11411 | + AVR32_BUILTIN_XCHG, |
| 11412 | + AVR32_BUILTIN_LDXI, |
| 11413 | + AVR32_BUILTIN_BSWAP16, |
| 11414 | + AVR32_BUILTIN_BSWAP32, |
| 11415 | + AVR32_BUILTIN_COP, |
| 11416 | + AVR32_BUILTIN_MVCR_W, |
| 11417 | + AVR32_BUILTIN_MVRC_W, |
| 11418 | + AVR32_BUILTIN_MVCR_D, |
| 11419 | + AVR32_BUILTIN_MVRC_D, |
| 11420 | + AVR32_BUILTIN_MULSATHH_H, |
| 11421 | + AVR32_BUILTIN_MULSATHH_W, |
| 11422 | + AVR32_BUILTIN_MULSATRNDHH_H, |
| 11423 | + AVR32_BUILTIN_MULSATRNDWH_W, |
| 11424 | + AVR32_BUILTIN_MULSATWH_W, |
| 11425 | + AVR32_BUILTIN_MACSATHH_W, |
| 11426 | + AVR32_BUILTIN_SATADD_H, |
| 11427 | + AVR32_BUILTIN_SATSUB_H, |
| 11428 | + AVR32_BUILTIN_SATADD_W, |
| 11429 | + AVR32_BUILTIN_SATSUB_W, |
| 11430 | + AVR32_BUILTIN_MULWH_D, |
| 11431 | + AVR32_BUILTIN_MULNWH_D, |
| 11432 | + AVR32_BUILTIN_MACWH_D, |
| 11433 | + AVR32_BUILTIN_MACHH_D, |
| 11434 | + AVR32_BUILTIN_MUSFR, |
| 11435 | + AVR32_BUILTIN_MUSTR, |
| 11436 | + AVR32_BUILTIN_SATS, |
| 11437 | + AVR32_BUILTIN_SATU, |
| 11438 | + AVR32_BUILTIN_SATRNDS, |
| 11439 | + AVR32_BUILTIN_SATRNDU, |
| 11440 | + AVR32_BUILTIN_MEMS, |
| 11441 | + AVR32_BUILTIN_MEMC, |
| 11442 | + AVR32_BUILTIN_MEMT, |
| 11443 | + AVR32_BUILTIN_SLEEP, |
| 11444 | + AVR32_BUILTIN_DELAY_CYCLES |
| 11445 | +}; |
| 11446 | + |
| 11447 | + |
| 11448 | +#define FLOAT_LIB_COMPARE_RETURNS_BOOL(MODE, COMPARISON) \ |
| 11449 | + ((MODE == SFmode) || (MODE == DFmode)) |
| 11450 | + |
| 11451 | +#define RENAME_LIBRARY_SET ".set" |
| 11452 | + |
| 11453 | +/* Make ABI_NAME an alias for __GCC_NAME. */ |
| 11454 | +#define RENAME_LIBRARY(GCC_NAME, ABI_NAME) \ |
| 11455 | + __asm__ (".globl\t__avr32_" #ABI_NAME "\n" \ |
| 11456 | + ".set\t__avr32_" #ABI_NAME \ |
| 11457 | + ", __" #GCC_NAME "\n"); |
| 11458 | + |
| 11459 | +/* Give libgcc functions avr32 ABI name. */ |
| 11460 | +#ifdef L_muldi3 |
| 11461 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, mul64) |
| 11462 | +#endif |
| 11463 | +#ifdef L_divdi3 |
| 11464 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divdi3, sdiv64) |
| 11465 | +#endif |
| 11466 | +#ifdef L_udivdi3 |
| 11467 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (udivdi3, udiv64) |
| 11468 | +#endif |
| 11469 | +#ifdef L_moddi3 |
| 11470 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (moddi3, smod64) |
| 11471 | +#endif |
| 11472 | +#ifdef L_umoddi3 |
| 11473 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (umoddi3, umod64) |
| 11474 | +#endif |
| 11475 | +#ifdef L_ashldi3 |
| 11476 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashldi3, lsl64) |
| 11477 | +#endif |
| 11478 | +#ifdef L_lshrdi3 |
| 11479 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (lshrdi3, lsr64) |
| 11480 | +#endif |
| 11481 | +#ifdef L_ashrdi3 |
| 11482 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashrdi3, asr64) |
| 11483 | +#endif |
| 11484 | + |
| 11485 | +#ifdef L_fixsfdi |
| 11486 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfdi, f32_to_s64) |
| 11487 | +#endif |
| 11488 | +#ifdef L_fixunssfdi |
| 11489 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfdi, f32_to_u64) |
| 11490 | +#endif |
| 11491 | +#ifdef L_floatdidf |
| 11492 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdidf, s64_to_f64) |
| 11493 | +#endif |
| 11494 | +#ifdef L_floatdisf |
| 11495 | +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, s64_to_f32) |
| 11496 | +#endif |
| 11497 | + |
| 11498 | +#endif |
| 11499 | --- /dev/null |
| 11500 | +++ b/gcc/config/avr32/avr32.md |
| 11501 | @@ -0,0 +1,5198 @@ |
| 11502 | +;; AVR32 machine description file. |
| 11503 | +;; Copyright 2003,2004,2005,2006,2007,2008,2009 Atmel Corporation. |
| 11504 | +;; |
| 11505 | +;; This file is part of GCC. |
| 11506 | +;; |
| 11507 | +;; This program is free software; you can redistribute it and/or modify |
| 11508 | +;; it under the terms of the GNU General Public License as published by |
| 11509 | +;; the Free Software Foundation; either version 2 of the License, or |
| 11510 | +;; (at your option) any later version. |
| 11511 | +;; |
| 11512 | +;; This program is distributed in the hope that it will be useful, |
| 11513 | +;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11514 | +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11515 | +;; GNU General Public License for more details. |
| 11516 | +;; |
| 11517 | +;; You should have received a copy of the GNU General Public License |
| 11518 | +;; along with this program; if not, write to the Free Software |
| 11519 | +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 11520 | + |
| 11521 | +;; -*- Mode: Scheme -*- |
| 11522 | + |
| 11523 | +(define_attr "type" "alu,alu2,alu_sat,mulhh,mulwh,mulww_w,mulww_d,div,machh_w,macww_w,macww_d,branch,call,load,load_rm,store,load2,load4,store2,store4,fmul,fcmps,fcmpd,fcast,fmv,fmvcpu,fldd,fstd,flds,fsts,fstm" |
| 11524 | + (const_string "alu")) |
| 11525 | + |
| 11526 | + |
| 11527 | +(define_attr "cc" "none,set_vncz,set_ncz,set_cz,set_z,set_z_if_not_v2,bld,compare,cmp_cond_insn,clobber,call_set,fpcompare,from_fpcc" |
| 11528 | + (const_string "none")) |
| 11529 | + |
| 11530 | + |
| 11531 | +; NB! Keep this in sync with enum architecture_type in avr32.h |
| 11532 | +(define_attr "pipeline" "ap,ucr1,ucr2,ucr2nomul,ucr3,ucr3fp" |
| 11533 | + (const (symbol_ref "avr32_arch->arch_type"))) |
| 11534 | + |
| 11535 | +; Insn length in bytes |
| 11536 | +(define_attr "length" "" |
| 11537 | + (const_int 4)) |
| 11538 | + |
| 11539 | +; Signal if an insn is predicable and hence can be conditionally executed. |
| 11540 | +(define_attr "predicable" "no,yes" (const_string "no")) |
| 11541 | + |
| 11542 | +;; Uses of UNSPEC in this file: |
| 11543 | +(define_constants |
| 11544 | + [(UNSPEC_PUSHM 0) |
| 11545 | + (UNSPEC_POPM 1) |
| 11546 | + (UNSPEC_UDIVMODSI4_INTERNAL 2) |
| 11547 | + (UNSPEC_DIVMODSI4_INTERNAL 3) |
| 11548 | + (UNSPEC_STM 4) |
| 11549 | + (UNSPEC_LDM 5) |
| 11550 | + (UNSPEC_MOVSICC 6) |
| 11551 | + (UNSPEC_ADDSICC 7) |
| 11552 | + (UNSPEC_COND_MI 8) |
| 11553 | + (UNSPEC_COND_PL 9) |
| 11554 | + (UNSPEC_PIC_SYM 10) |
| 11555 | + (UNSPEC_PIC_BASE 11) |
| 11556 | + (UNSPEC_STORE_MULTIPLE 12) |
| 11557 | + (UNSPEC_STMFP 13) |
| 11558 | + (UNSPEC_FRCPA 14) |
| 11559 | + (UNSPEC_REG_TO_CC 15) |
| 11560 | + (UNSPEC_FORCE_MINIPOOL 16) |
| 11561 | + (UNSPEC_SATS 17) |
| 11562 | + (UNSPEC_SATU 18) |
| 11563 | + (UNSPEC_SATRNDS 19) |
| 11564 | + (UNSPEC_SATRNDU 20) |
| 11565 | + ]) |
| 11566 | + |
| 11567 | +(define_constants |
| 11568 | + [(VUNSPEC_EPILOGUE 0) |
| 11569 | + (VUNSPEC_CACHE 1) |
| 11570 | + (VUNSPEC_MTSR 2) |
| 11571 | + (VUNSPEC_MFSR 3) |
| 11572 | + (VUNSPEC_BLOCKAGE 4) |
| 11573 | + (VUNSPEC_SYNC 5) |
| 11574 | + (VUNSPEC_TLBR 6) |
| 11575 | + (VUNSPEC_TLBW 7) |
| 11576 | + (VUNSPEC_TLBS 8) |
| 11577 | + (VUNSPEC_BREAKPOINT 9) |
| 11578 | + (VUNSPEC_MTDR 10) |
| 11579 | + (VUNSPEC_MFDR 11) |
| 11580 | + (VUNSPEC_MVCR 12) |
| 11581 | + (VUNSPEC_MVRC 13) |
| 11582 | + (VUNSPEC_COP 14) |
| 11583 | + (VUNSPEC_ALIGN 15) |
| 11584 | + (VUNSPEC_POOL_START 16) |
| 11585 | + (VUNSPEC_POOL_END 17) |
| 11586 | + (VUNSPEC_POOL_4 18) |
| 11587 | + (VUNSPEC_POOL_8 19) |
| 11588 | + (VUNSPEC_POOL_16 20) |
| 11589 | + (VUNSPEC_MUSFR 21) |
| 11590 | + (VUNSPEC_MUSTR 22) |
| 11591 | + (VUNSPEC_SYNC_CMPXCHG 23) |
| 11592 | + (VUNSPEC_SYNC_SET_LOCK_AND_LOAD 24) |
| 11593 | + (VUNSPEC_SYNC_STORE_IF_LOCK 25) |
| 11594 | + (VUNSPEC_EH_RETURN 26) |
| 11595 | + (VUNSPEC_FRS 27) |
| 11596 | + (VUNSPEC_CSRF 28) |
| 11597 | + (VUNSPEC_SSRF 29) |
| 11598 | + (VUNSPEC_SLEEP 30) |
| 11599 | + (VUNSPEC_DELAY_CYCLES 31) |
| 11600 | + (VUNSPEC_DELAY_CYCLES_1 32) |
| 11601 | + (VUNSPEC_DELAY_CYCLES_2 33) |
| 11602 | + (VUNSPEC_NOP 34) |
| 11603 | + (VUNSPEC_NOP3 35) |
| 11604 | + ]) |
| 11605 | + |
| 11606 | +(define_constants |
| 11607 | + [ |
| 11608 | + ;; R7 = 15-7 = 8 |
| 11609 | + (FP_REGNUM 8) |
| 11610 | + ;; Return Register = R12 = 15 - 12 = 3 |
| 11611 | + (RETVAL_REGNUM 3) |
| 11612 | + ;; SP = R13 = 15 - 13 = 2 |
| 11613 | + (SP_REGNUM 2) |
| 11614 | + ;; LR = R14 = 15 - 14 = 1 |
| 11615 | + (LR_REGNUM 1) |
| 11616 | + ;; PC = R15 = 15 - 15 = 0 |
| 11617 | + (PC_REGNUM 0) |
| 11618 | + ;; FPSR = GENERAL_REGS + 1 = 17 |
| 11619 | + (FPCC_REGNUM 17) |
| 11620 | + ]) |
| 11621 | + |
| 11622 | + |
| 11623 | + |
| 11624 | + |
| 11625 | +;;****************************************************************************** |
| 11626 | +;; Macros |
| 11627 | +;;****************************************************************************** |
| 11628 | + |
| 11629 | +;; Integer Modes for basic alu insns |
| 11630 | +(define_mode_iterator INTM [SI HI QI]) |
| 11631 | +(define_mode_attr alu_cc_attr [(SI "set_vncz") (HI "clobber") (QI "clobber")]) |
| 11632 | + |
| 11633 | +;; Move word modes |
| 11634 | +(define_mode_iterator MOVM [SI V2HI V4QI]) |
| 11635 | + |
| 11636 | +;; For mov/addcc insns |
| 11637 | +(define_mode_iterator ADDCC [SI HI QI]) |
| 11638 | +(define_mode_iterator MOVCC [SF SI HI QI]) |
| 11639 | +(define_mode_iterator CMP [DI SI HI QI]) |
| 11640 | +(define_mode_attr store_postfix [(SF ".w") (SI ".w") (HI ".h") (QI ".b")]) |
| 11641 | +(define_mode_attr load_postfix [(SF ".w") (SI ".w") (HI ".sh") (QI ".ub")]) |
| 11642 | +(define_mode_attr load_postfix_s [(SI ".w") (HI ".sh") (QI ".sb")]) |
| 11643 | +(define_mode_attr load_postfix_u [(SI ".w") (HI ".uh") (QI ".ub")]) |
| 11644 | +(define_mode_attr pred_mem_constraint [(SF "RKu11") (SI "RKu11") (HI "RKu10") (QI "RKu09")]) |
| 11645 | +(define_mode_attr cmp_constraint [(DI "rKu20") (SI "rKs21") (HI "r") (QI "r")]) |
| 11646 | +(define_mode_attr cmp_predicate [(DI "register_immediate_operand") |
| 11647 | + (SI "register_const_int_operand") |
| 11648 | + (HI "register_operand") |
| 11649 | + (QI "register_operand")]) |
| 11650 | +(define_mode_attr cmp_length [(DI "6") |
| 11651 | + (SI "4") |
| 11652 | + (HI "4") |
| 11653 | + (QI "4")]) |
| 11654 | + |
| 11655 | +;; For all conditional insns |
| 11656 | +(define_code_iterator any_cond_b [ge lt geu ltu]) |
| 11657 | +(define_code_iterator any_cond [gt ge lt le gtu geu ltu leu]) |
| 11658 | +(define_code_iterator any_cond4 [gt le gtu leu]) |
| 11659 | +(define_code_attr cond [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt") (le "le") |
| 11660 | + (gtu "hi") (geu "hs") (ltu "lo") (leu "ls")]) |
| 11661 | +(define_code_attr invcond [(eq "ne") (ne "eq") (gt "le") (ge "lt") (lt "ge") (le "gt") |
| 11662 | + (gtu "ls") (geu "lo") (ltu "hs") (leu "hi")]) |
| 11663 | + |
| 11664 | +;; For logical operations |
| 11665 | +(define_code_iterator logical [and ior xor]) |
| 11666 | +(define_code_attr logical_insn [(and "and") (ior "or") (xor "eor")]) |
| 11667 | + |
| 11668 | +;; Predicable operations with three register operands |
| 11669 | +(define_code_iterator predicable_op3 [and ior xor plus minus]) |
| 11670 | +(define_code_attr predicable_insn3 [(and "and") (ior "or") (xor "eor") (plus "add") (minus "sub")]) |
| 11671 | +(define_code_attr predicable_commutative3 [(and "%") (ior "%") (xor "%") (plus "%") (minus "")]) |
| 11672 | + |
| 11673 | +;; Load the predicates |
| 11674 | +(include "predicates.md") |
| 11675 | + |
| 11676 | + |
| 11677 | +;;****************************************************************************** |
| 11678 | +;; Automaton pipeline description for avr32 |
| 11679 | +;;****************************************************************************** |
| 11680 | + |
| 11681 | +(define_automaton "avr32_ap") |
| 11682 | + |
| 11683 | + |
| 11684 | +(define_cpu_unit "is" "avr32_ap") |
| 11685 | +(define_cpu_unit "a1,m1,da" "avr32_ap") |
| 11686 | +(define_cpu_unit "a2,m2,d" "avr32_ap") |
| 11687 | + |
| 11688 | +;;Alu instructions |
| 11689 | +(define_insn_reservation "alu_op" 1 |
| 11690 | + (and (eq_attr "pipeline" "ap") |
| 11691 | + (eq_attr "type" "alu")) |
| 11692 | + "is,a1,a2") |
| 11693 | + |
| 11694 | +(define_insn_reservation "alu2_op" 2 |
| 11695 | + (and (eq_attr "pipeline" "ap") |
| 11696 | + (eq_attr "type" "alu2")) |
| 11697 | + "is,is+a1,a1+a2,a2") |
| 11698 | + |
| 11699 | +(define_insn_reservation "alu_sat_op" 2 |
| 11700 | + (and (eq_attr "pipeline" "ap") |
| 11701 | + (eq_attr "type" "alu_sat")) |
| 11702 | + "is,a1,a2") |
| 11703 | + |
| 11704 | + |
| 11705 | +;;Mul instructions |
| 11706 | +(define_insn_reservation "mulhh_op" 2 |
| 11707 | + (and (eq_attr "pipeline" "ap") |
| 11708 | + (eq_attr "type" "mulhh,mulwh")) |
| 11709 | + "is,m1,m2") |
| 11710 | + |
| 11711 | +(define_insn_reservation "mulww_w_op" 3 |
| 11712 | + (and (eq_attr "pipeline" "ap") |
| 11713 | + (eq_attr "type" "mulww_w")) |
| 11714 | + "is,m1,m1+m2,m2") |
| 11715 | + |
| 11716 | +(define_insn_reservation "mulww_d_op" 5 |
| 11717 | + (and (eq_attr "pipeline" "ap") |
| 11718 | + (eq_attr "type" "mulww_d")) |
| 11719 | + "is,m1,m1+m2,m1+m2,m2,m2") |
| 11720 | + |
| 11721 | +(define_insn_reservation "div_op" 33 |
| 11722 | + (and (eq_attr "pipeline" "ap") |
| 11723 | + (eq_attr "type" "div")) |
| 11724 | + "is,m1,m1*31 + m2*31,m2") |
| 11725 | + |
| 11726 | +(define_insn_reservation "machh_w_op" 3 |
| 11727 | + (and (eq_attr "pipeline" "ap") |
| 11728 | + (eq_attr "type" "machh_w")) |
| 11729 | + "is*2,m1,m2") |
| 11730 | + |
| 11731 | + |
| 11732 | +(define_insn_reservation "macww_w_op" 4 |
| 11733 | + (and (eq_attr "pipeline" "ap") |
| 11734 | + (eq_attr "type" "macww_w")) |
| 11735 | + "is*2,m1,m1,m2") |
| 11736 | + |
| 11737 | + |
| 11738 | +(define_insn_reservation "macww_d_op" 6 |
| 11739 | + (and (eq_attr "pipeline" "ap") |
| 11740 | + (eq_attr "type" "macww_d")) |
| 11741 | + "is*2,m1,m1+m2,m1+m2,m2") |
| 11742 | + |
| 11743 | +;;Bypasses for Mac instructions, because of accumulator cache. |
| 11744 | +;;Set latency as low as possible in order to let the compiler let |
| 11745 | +;;mul -> mac and mac -> mac combinations which use the same |
| 11746 | +;;accumulator cache be placed close together to avoid any |
| 11747 | +;;instructions which can ruin the accumulator cache come inbetween. |
| 11748 | +(define_bypass 4 "machh_w_op" "alu_op,alu2_op,alu_sat_op,load_op" "avr32_mul_waw_bypass") |
| 11749 | +(define_bypass 5 "macww_w_op" "alu_op,alu2_op,alu_sat_op,load_op" "avr32_mul_waw_bypass") |
| 11750 | +(define_bypass 7 "macww_d_op" "alu_op,alu2_op,alu_sat_op,load_op" "avr32_mul_waw_bypass") |
| 11751 | + |
| 11752 | +(define_bypass 3 "mulhh_op" "alu_op,alu2_op,alu_sat_op,load_op" "avr32_mul_waw_bypass") |
| 11753 | +(define_bypass 4 "mulww_w_op" "alu_op,alu2_op,alu_sat_op,load_op" "avr32_mul_waw_bypass") |
| 11754 | +(define_bypass 6 "mulww_d_op" "alu_op,alu2_op,alu_sat_op,load_op" "avr32_mul_waw_bypass") |
| 11755 | + |
| 11756 | + |
| 11757 | +;;Bypasses for all mul/mac instructions followed by an instruction |
| 11758 | +;;which reads the output AND writes the result to the same register. |
| 11759 | +;;This will generate an Write After Write hazard which gives an |
| 11760 | +;;extra cycle before the result is ready. |
| 11761 | +(define_bypass 0 "machh_w_op" "machh_w_op" "avr32_valid_macmac_bypass") |
| 11762 | +(define_bypass 0 "macww_w_op" "macww_w_op" "avr32_valid_macmac_bypass") |
| 11763 | +(define_bypass 0 "macww_d_op" "macww_d_op" "avr32_valid_macmac_bypass") |
| 11764 | + |
| 11765 | +(define_bypass 0 "mulhh_op" "machh_w_op" "avr32_valid_mulmac_bypass") |
| 11766 | +(define_bypass 0 "mulww_w_op" "macww_w_op" "avr32_valid_mulmac_bypass") |
| 11767 | +(define_bypass 0 "mulww_d_op" "macww_d_op" "avr32_valid_mulmac_bypass") |
| 11768 | + |
| 11769 | +;;Branch and call instructions |
| 11770 | +;;We assume that all branches and rcalls are predicted correctly :-) |
| 11771 | +;;while calls use a lot of cycles. |
| 11772 | +(define_insn_reservation "branch_op" 0 |
| 11773 | + (and (eq_attr "pipeline" "ap") |
| 11774 | + (eq_attr "type" "branch")) |
| 11775 | + "nothing") |
| 11776 | + |
| 11777 | +(define_insn_reservation "call_op" 10 |
| 11778 | + (and (eq_attr "pipeline" "ap") |
| 11779 | + (eq_attr "type" "call")) |
| 11780 | + "nothing") |
| 11781 | + |
| 11782 | + |
| 11783 | +;;Load store instructions |
| 11784 | +(define_insn_reservation "load_op" 2 |
| 11785 | + (and (eq_attr "pipeline" "ap") |
| 11786 | + (eq_attr "type" "load")) |
| 11787 | + "is,da,d") |
| 11788 | + |
| 11789 | +(define_insn_reservation "load_rm_op" 3 |
| 11790 | + (and (eq_attr "pipeline" "ap") |
| 11791 | + (eq_attr "type" "load_rm")) |
| 11792 | + "is,da,d") |
| 11793 | + |
| 11794 | + |
| 11795 | +(define_insn_reservation "store_op" 0 |
| 11796 | + (and (eq_attr "pipeline" "ap") |
| 11797 | + (eq_attr "type" "store")) |
| 11798 | + "is,da,d") |
| 11799 | + |
| 11800 | + |
| 11801 | +(define_insn_reservation "load_double_op" 3 |
| 11802 | + (and (eq_attr "pipeline" "ap") |
| 11803 | + (eq_attr "type" "load2")) |
| 11804 | + "is,da,da+d,d") |
| 11805 | + |
| 11806 | +(define_insn_reservation "load_quad_op" 4 |
| 11807 | + (and (eq_attr "pipeline" "ap") |
| 11808 | + (eq_attr "type" "load4")) |
| 11809 | + "is,da,da+d,da+d,d") |
| 11810 | + |
| 11811 | +(define_insn_reservation "store_double_op" 0 |
| 11812 | + (and (eq_attr "pipeline" "ap") |
| 11813 | + (eq_attr "type" "store2")) |
| 11814 | + "is,da,da+d,d") |
| 11815 | + |
| 11816 | + |
| 11817 | +(define_insn_reservation "store_quad_op" 0 |
| 11818 | + (and (eq_attr "pipeline" "ap") |
| 11819 | + (eq_attr "type" "store4")) |
| 11820 | + "is,da,da+d,da+d,d") |
| 11821 | + |
| 11822 | +;;For store the operand to write to memory is read in d and |
| 11823 | +;;the real latency between any instruction and a store is therefore |
| 11824 | +;;one less than for the instructions which reads the operands in the first |
| 11825 | +;;excecution stage |
| 11826 | +(define_bypass 2 "load_double_op" "store_double_op" "avr32_store_bypass") |
| 11827 | +(define_bypass 3 "load_quad_op" "store_quad_op" "avr32_store_bypass") |
| 11828 | +(define_bypass 1 "load_op" "store_op" "avr32_store_bypass") |
| 11829 | +(define_bypass 2 "load_rm_op" "store_op" "avr32_store_bypass") |
| 11830 | +(define_bypass 1 "alu_sat_op" "store_op" "avr32_store_bypass") |
| 11831 | +(define_bypass 1 "alu2_op" "store_op" "avr32_store_bypass") |
| 11832 | +(define_bypass 1 "mulhh_op" "store_op" "avr32_store_bypass") |
| 11833 | +(define_bypass 2 "mulww_w_op" "store_op" "avr32_store_bypass") |
| 11834 | +(define_bypass 4 "mulww_d_op" "store_op" "avr32_store_bypass" ) |
| 11835 | +(define_bypass 2 "machh_w_op" "store_op" "avr32_store_bypass") |
| 11836 | +(define_bypass 3 "macww_w_op" "store_op" "avr32_store_bypass") |
| 11837 | +(define_bypass 5 "macww_d_op" "store_op" "avr32_store_bypass") |
| 11838 | + |
| 11839 | + |
| 11840 | +; Bypass for load double operation. If only the first loaded word is needed |
| 11841 | +; then the latency is 2 |
| 11842 | +(define_bypass 2 "load_double_op" |
| 11843 | + "load_op,load_rm_op,alu_sat_op, alu2_op, alu_op, mulhh_op, mulww_w_op, |
| 11844 | + mulww_d_op, machh_w_op, macww_w_op, macww_d_op" |
| 11845 | + "avr32_valid_load_double_bypass") |
| 11846 | + |
| 11847 | +; Bypass for load quad operation. If only the first or second loaded word is needed |
| 11848 | +; we set the latency to 2 |
| 11849 | +(define_bypass 2 "load_quad_op" |
| 11850 | + "load_op,load_rm_op,alu_sat_op, alu2_op, alu_op, mulhh_op, mulww_w_op, |
| 11851 | + mulww_d_op, machh_w_op, macww_w_op, macww_d_op" |
| 11852 | + "avr32_valid_load_quad_bypass") |
| 11853 | + |
| 11854 | + |
| 11855 | +;;****************************************************************************** |
| 11856 | +;; End of Automaton pipeline description for avr32 |
| 11857 | +;;****************************************************************************** |
| 11858 | + |
| 11859 | +(define_cond_exec |
| 11860 | + [(match_operator 0 "avr32_comparison_operator" |
| 11861 | + [(match_operand:CMP 1 "register_operand" "r") |
| 11862 | + (match_operand:CMP 2 "<CMP:cmp_predicate>" "<CMP:cmp_constraint>")])] |
| 11863 | + "TARGET_V2_INSNS" |
| 11864 | + "%!" |
| 11865 | +) |
| 11866 | + |
| 11867 | +(define_cond_exec |
| 11868 | + [(match_operator 0 "avr32_comparison_operator" |
| 11869 | + [(and:SI (match_operand:SI 1 "register_operand" "r") |
| 11870 | + (match_operand:SI 2 "one_bit_set_operand" "i")) |
| 11871 | + (const_int 0)])] |
| 11872 | + "TARGET_V2_INSNS" |
| 11873 | + "%!" |
| 11874 | + ) |
| 11875 | + |
| 11876 | +;;============================================================================= |
| 11877 | +;; move |
| 11878 | +;;----------------------------------------------------------------------------- |
| 11879 | + |
| 11880 | + |
| 11881 | +;;== char - 8 bits ============================================================ |
| 11882 | +(define_expand "movqi" |
| 11883 | + [(set (match_operand:QI 0 "nonimmediate_operand" "") |
| 11884 | + (match_operand:QI 1 "general_operand" ""))] |
| 11885 | + "" |
| 11886 | + { |
| 11887 | + if ( can_create_pseudo_p () ){ |
| 11888 | + if (GET_CODE (operands[1]) == MEM && optimize){ |
| 11889 | + rtx reg = gen_reg_rtx (SImode); |
| 11890 | + |
| 11891 | + emit_insn (gen_zero_extendqisi2 (reg, operands[1])); |
| 11892 | + operands[1] = gen_lowpart (QImode, reg); |
| 11893 | + } |
| 11894 | + |
| 11895 | + /* One of the ops has to be in a register. */ |
| 11896 | + if (GET_CODE (operands[0]) == MEM) |
| 11897 | + operands[1] = force_reg (QImode, operands[1]); |
| 11898 | + } |
| 11899 | + |
| 11900 | + }) |
| 11901 | + |
| 11902 | +(define_insn "*movqi_internal" |
| 11903 | + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m,r") |
| 11904 | + (match_operand:QI 1 "general_operand" "rKs08,m,r,i"))] |
| 11905 | + "register_operand (operands[0], QImode) |
| 11906 | + || register_operand (operands[1], QImode)" |
| 11907 | + "@ |
| 11908 | + mov\t%0, %1 |
| 11909 | + ld.ub\t%0, %1 |
| 11910 | + st.b\t%0, %1 |
| 11911 | + mov\t%0, %1" |
| 11912 | + [(set_attr "length" "2,4,4,4") |
| 11913 | + (set_attr "type" "alu,load_rm,store,alu")]) |
| 11914 | + |
| 11915 | + |
| 11916 | + |
| 11917 | +;;== short - 16 bits ========================================================== |
| 11918 | +(define_expand "movhi" |
| 11919 | + [(set (match_operand:HI 0 "nonimmediate_operand" "") |
| 11920 | + (match_operand:HI 1 "general_operand" ""))] |
| 11921 | + "" |
| 11922 | + { |
| 11923 | + if ( can_create_pseudo_p () ){ |
| 11924 | + if (GET_CODE (operands[1]) == MEM && optimize){ |
| 11925 | + rtx reg = gen_reg_rtx (SImode); |
| 11926 | + |
| 11927 | + emit_insn (gen_extendhisi2 (reg, operands[1])); |
| 11928 | + operands[1] = gen_lowpart (HImode, reg); |
| 11929 | + } |
| 11930 | + |
| 11931 | + /* One of the ops has to be in a register. */ |
| 11932 | + if (GET_CODE (operands[0]) == MEM) |
| 11933 | + operands[1] = force_reg (HImode, operands[1]); |
| 11934 | + } |
| 11935 | + |
| 11936 | + }) |
| 11937 | + |
| 11938 | + |
| 11939 | +(define_insn "*movhi_internal" |
| 11940 | + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r") |
| 11941 | + (match_operand:HI 1 "general_operand" "rKs08,m,r,i"))] |
| 11942 | + "register_operand (operands[0], HImode) |
| 11943 | + || register_operand (operands[1], HImode)" |
| 11944 | + "@ |
| 11945 | + mov\t%0, %1 |
| 11946 | + ld.sh\t%0, %1 |
| 11947 | + st.h\t%0, %1 |
| 11948 | + mov\t%0, %1" |
| 11949 | + [(set_attr "length" "2,4,4,4") |
| 11950 | + (set_attr "type" "alu,load_rm,store,alu")]) |
| 11951 | + |
| 11952 | + |
| 11953 | +;;== int - 32 bits ============================================================ |
| 11954 | + |
| 11955 | +(define_expand "movmisalignsi" |
| 11956 | + [(set (match_operand:SI 0 "nonimmediate_operand" "") |
| 11957 | + (match_operand:SI 1 "nonimmediate_operand" ""))] |
| 11958 | + "TARGET_UNALIGNED_WORD" |
| 11959 | + { |
| 11960 | + } |
| 11961 | +) |
| 11962 | + |
| 11963 | +(define_expand "mov<mode>" |
| 11964 | + [(set (match_operand:MOVM 0 "avr32_non_rmw_nonimmediate_operand" "") |
| 11965 | + (match_operand:MOVM 1 "avr32_non_rmw_general_operand" ""))] |
| 11966 | + "" |
| 11967 | + { |
| 11968 | + |
| 11969 | + /* One of the ops has to be in a register. */ |
| 11970 | + if (GET_CODE (operands[0]) == MEM) |
| 11971 | + operands[1] = force_reg (<MODE>mode, operands[1]); |
| 11972 | + |
| 11973 | + /* Check for out of range immediate constants as these may |
| 11974 | + occur during reloading, since it seems like reload does |
| 11975 | + not check if the immediate is legitimate. Don't know if |
| 11976 | + this is a bug? */ |
| 11977 | + if ( reload_in_progress |
| 11978 | + && avr32_imm_in_const_pool |
| 11979 | + && GET_CODE(operands[1]) == CONST_INT |
| 11980 | + && !avr32_const_ok_for_constraint_p(INTVAL(operands[1]), 'K', "Ks21") ){ |
| 11981 | + operands[1] = force_const_mem(SImode, operands[1]); |
| 11982 | + } |
| 11983 | + /* Check for RMW memory operands. They are not allowed for mov operations |
| 11984 | + only the atomic memc/s/t operations */ |
| 11985 | + if ( !reload_in_progress |
| 11986 | + && avr32_rmw_memory_operand (operands[0], <MODE>mode) ){ |
| 11987 | + operands[0] = copy_rtx (operands[0]); |
| 11988 | + XEXP(operands[0], 0) = force_reg (<MODE>mode, XEXP(operands[0], 0)); |
| 11989 | + } |
| 11990 | + |
| 11991 | + if ( !reload_in_progress |
| 11992 | + && avr32_rmw_memory_operand (operands[1], <MODE>mode) ){ |
| 11993 | + operands[1] = copy_rtx (operands[1]); |
| 11994 | + XEXP(operands[1], 0) = force_reg (<MODE>mode, XEXP(operands[1], 0)); |
| 11995 | + } |
| 11996 | + if ( (flag_pic || TARGET_HAS_ASM_ADDR_PSEUDOS) |
| 11997 | + && !avr32_legitimate_pic_operand_p(operands[1]) ) |
| 11998 | + operands[1] = legitimize_pic_address (operands[1], <MODE>mode, |
| 11999 | + (can_create_pseudo_p () ? 0: operands[0])); |
| 12000 | + else if ( flag_pic && avr32_address_operand(operands[1], GET_MODE(operands[1])) ) |
| 12001 | + /* If we have an address operand then this function uses the pic register. */ |
| 12002 | + crtl->uses_pic_offset_table = 1; |
| 12003 | + }) |
| 12004 | + |
| 12005 | + |
| 12006 | +(define_insn "mov<mode>_internal" |
| 12007 | + [(set (match_operand:MOVM 0 "avr32_non_rmw_nonimmediate_operand" "=r, r, r,r,r,Q,r") |
| 12008 | + (match_operand:MOVM 1 "avr32_non_rmw_general_operand" "rKs08,Ks21,J,n,Q,r,W"))] |
| 12009 | + "(register_operand (operands[0], <MODE>mode) |
| 12010 | + || register_operand (operands[1], <MODE>mode)) |
| 12011 | + && !avr32_rmw_memory_operand (operands[0], <MODE>mode) |
| 12012 | + && !avr32_rmw_memory_operand (operands[1], <MODE>mode)" |
| 12013 | + { |
| 12014 | + switch (which_alternative) { |
| 12015 | + case 0: |
| 12016 | + case 1: return "mov\t%0, %1"; |
| 12017 | + case 2: |
| 12018 | + if ( TARGET_V2_INSNS ) |
| 12019 | + return "movh\t%0, hi(%1)"; |
| 12020 | + /* Fallthrough */ |
| 12021 | + case 3: return "mov\t%0, lo(%1)\;orh\t%0,hi(%1)"; |
| 12022 | + case 4: |
| 12023 | + if ( (REG_P(XEXP(operands[1], 0)) |
| 12024 | + && REGNO(XEXP(operands[1], 0)) == SP_REGNUM) |
| 12025 | + || (GET_CODE(XEXP(operands[1], 0)) == PLUS |
| 12026 | + && REGNO(XEXP(XEXP(operands[1], 0), 0)) == SP_REGNUM |
| 12027 | + && GET_CODE(XEXP(XEXP(operands[1], 0), 1)) == CONST_INT |
| 12028 | + && INTVAL(XEXP(XEXP(operands[1], 0), 1)) % 4 == 0 |
| 12029 | + && INTVAL(XEXP(XEXP(operands[1], 0), 1)) <= 0x1FC) ) |
| 12030 | + return "lddsp\t%0, %1"; |
| 12031 | + else if ( avr32_const_pool_ref_operand(operands[1], GET_MODE(operands[1])) ) |
| 12032 | + return "lddpc\t%0, %1"; |
| 12033 | + else |
| 12034 | + return "ld.w\t%0, %1"; |
| 12035 | + case 5: |
| 12036 | + if ( (REG_P(XEXP(operands[0], 0)) |
| 12037 | + && REGNO(XEXP(operands[0], 0)) == SP_REGNUM) |
| 12038 | + || (GET_CODE(XEXP(operands[0], 0)) == PLUS |
| 12039 | + && REGNO(XEXP(XEXP(operands[0], 0), 0)) == SP_REGNUM |
| 12040 | + && GET_CODE(XEXP(XEXP(operands[0], 0), 1)) == CONST_INT |
| 12041 | + && INTVAL(XEXP(XEXP(operands[0], 0), 1)) % 4 == 0 |
| 12042 | + && INTVAL(XEXP(XEXP(operands[0], 0), 1)) <= 0x1FC) ) |
| 12043 | + return "stdsp\t%0, %1"; |
| 12044 | + else |
| 12045 | + return "st.w\t%0, %1"; |
| 12046 | + case 6: |
| 12047 | + if ( TARGET_HAS_ASM_ADDR_PSEUDOS ) |
| 12048 | + return "lda.w\t%0, %1"; |
| 12049 | + else |
| 12050 | + return "ld.w\t%0, r6[%1@got]"; |
| 12051 | + default: |
| 12052 | + abort(); |
| 12053 | + } |
| 12054 | + } |
| 12055 | + |
| 12056 | + [(set_attr "length" "2,4,4,8,4,4,8") |
| 12057 | + (set_attr "type" "alu,alu,alu,alu2,load,store,load") |
| 12058 | + (set_attr "cc" "none,none,set_z_if_not_v2,set_z,none,none,clobber")]) |
| 12059 | + |
| 12060 | + |
| 12061 | +(define_expand "reload_out_rmw_memory_operand" |
| 12062 | + [(set (match_operand:SI 2 "register_operand" "=r") |
| 12063 | + (match_operand:SI 0 "address_operand" "")) |
| 12064 | + (set (mem:SI (match_dup 2)) |
| 12065 | + (match_operand:SI 1 "register_operand" ""))] |
| 12066 | + "" |
| 12067 | + { |
| 12068 | + operands[0] = XEXP(operands[0], 0); |
| 12069 | + } |
| 12070 | +) |
| 12071 | + |
| 12072 | +(define_expand "reload_in_rmw_memory_operand" |
| 12073 | + [(set (match_operand:SI 2 "register_operand" "=r") |
| 12074 | + (match_operand:SI 1 "address_operand" "")) |
| 12075 | + (set (match_operand:SI 0 "register_operand" "") |
| 12076 | + (mem:SI (match_dup 2)))] |
| 12077 | + "" |
| 12078 | + { |
| 12079 | + operands[1] = XEXP(operands[1], 0); |
| 12080 | + } |
| 12081 | +) |
| 12082 | + |
| 12083 | + |
| 12084 | +;; These instructions are for loading constants which cannot be loaded |
| 12085 | +;; directly from the constant pool because the offset is too large |
| 12086 | +;; high and lo_sum are used even tough for our case it should be |
| 12087 | +;; low and high sum :-) |
| 12088 | +(define_insn "mov_symbol_lo" |
| 12089 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 12090 | + (high:SI (match_operand:SI 1 "immediate_operand" "i" )))] |
| 12091 | + "" |
| 12092 | + "mov\t%0, lo(%1)" |
| 12093 | + [(set_attr "type" "alu") |
| 12094 | + (set_attr "length" "4")] |
| 12095 | +) |
| 12096 | + |
| 12097 | +(define_insn "add_symbol_hi" |
| 12098 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 12099 | + (lo_sum:SI (match_dup 0) |
| 12100 | + (match_operand:SI 1 "immediate_operand" "i" )))] |
| 12101 | + "" |
| 12102 | + "orh\t%0, hi(%1)" |
| 12103 | + [(set_attr "type" "alu") |
| 12104 | + (set_attr "length" "4")] |
| 12105 | +) |
| 12106 | + |
| 12107 | + |
| 12108 | + |
| 12109 | +;; When generating pic, we need to load the symbol offset into a register. |
| 12110 | +;; So that the optimizer does not confuse this with a normal symbol load |
| 12111 | +;; we use an unspec. The offset will be loaded from a constant pool entry, |
| 12112 | +;; since that is the only type of relocation we can use. |
| 12113 | +(define_insn "pic_load_addr" |
| 12114 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 12115 | + (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYM))] |
| 12116 | + "flag_pic && CONSTANT_POOL_ADDRESS_P(XEXP(operands[1], 0))" |
| 12117 | + "lddpc\t%0, %1" |
| 12118 | + [(set_attr "type" "load") |
| 12119 | + (set_attr "length" "4")] |
| 12120 | +) |
| 12121 | + |
| 12122 | +(define_insn "pic_compute_got_from_pc" |
| 12123 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 12124 | + (unspec:SI [(minus:SI (pc) |
| 12125 | + (match_dup 0))] UNSPEC_PIC_BASE)) |
| 12126 | + (use (label_ref (match_operand 1 "" "")))] |
| 12127 | + "flag_pic" |
| 12128 | + { |
| 12129 | + (*targetm.asm_out.internal_label) (asm_out_file, "L", |
| 12130 | + CODE_LABEL_NUMBER (operands[1])); |
| 12131 | + return \"rsub\t%0, pc\"; |
| 12132 | + } |
| 12133 | + [(set_attr "cc" "clobber") |
| 12134 | + (set_attr "length" "2")] |
| 12135 | +) |
| 12136 | + |
| 12137 | +;;== long long int - 64 bits ================================================== |
| 12138 | + |
| 12139 | +(define_expand "movdi" |
| 12140 | + [(set (match_operand:DI 0 "nonimmediate_operand" "") |
| 12141 | + (match_operand:DI 1 "general_operand" ""))] |
| 12142 | + "" |
| 12143 | + { |
| 12144 | + |
| 12145 | + /* One of the ops has to be in a register. */ |
| 12146 | + if (GET_CODE (operands[0]) != REG) |
| 12147 | + operands[1] = force_reg (DImode, operands[1]); |
| 12148 | + |
| 12149 | + }) |
| 12150 | + |
| 12151 | + |
| 12152 | +(define_insn_and_split "*movdi_internal" |
| 12153 | + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r, r, r,r,r,m") |
| 12154 | + (match_operand:DI 1 "general_operand" "r, Ks08,Ks21,G,n,m,r"))] |
| 12155 | + "register_operand (operands[0], DImode) |
| 12156 | + || register_operand (operands[1], DImode)" |
| 12157 | + { |
| 12158 | + switch (which_alternative ){ |
| 12159 | + case 0: |
| 12160 | + case 1: |
| 12161 | + case 2: |
| 12162 | + case 3: |
| 12163 | + case 4: |
| 12164 | + return "#"; |
| 12165 | + case 5: |
| 12166 | + if ( avr32_const_pool_ref_operand(operands[1], GET_MODE(operands[1]))) |
| 12167 | + return "ld.d\t%0, pc[%1 - .]"; |
| 12168 | + else |
| 12169 | + return "ld.d\t%0, %1"; |
| 12170 | + case 6: |
| 12171 | + return "st.d\t%0, %1"; |
| 12172 | + default: |
| 12173 | + abort(); |
| 12174 | + } |
| 12175 | + } |
| 12176 | +;; Lets split all reg->reg or imm->reg transfers into two SImode transfers |
| 12177 | + "reload_completed && |
| 12178 | + (REG_P (operands[0]) && |
| 12179 | + (REG_P (operands[1]) |
| 12180 | + || GET_CODE (operands[1]) == CONST_INT |
| 12181 | + || GET_CODE (operands[1]) == CONST_DOUBLE))" |
| 12182 | + [(set (match_dup 0) (match_dup 1)) |
| 12183 | + (set (match_dup 2) (match_dup 3))] |
| 12184 | + { |
| 12185 | + operands[2] = gen_highpart (SImode, operands[0]); |
| 12186 | + operands[0] = gen_lowpart (SImode, operands[0]); |
| 12187 | + if ( REG_P(operands[1]) ){ |
| 12188 | + operands[3] = gen_highpart(SImode, operands[1]); |
| 12189 | + operands[1] = gen_lowpart(SImode, operands[1]); |
| 12190 | + } else if ( GET_CODE(operands[1]) == CONST_DOUBLE |
| 12191 | + || GET_CODE(operands[1]) == CONST_INT ){ |
| 12192 | + rtx split_const[2]; |
| 12193 | + avr32_split_const_expr (DImode, SImode, operands[1], split_const); |
| 12194 | + operands[3] = split_const[1]; |
| 12195 | + operands[1] = split_const[0]; |
| 12196 | + } else { |
| 12197 | + internal_error("Illegal operand[1] for movdi split!"); |
| 12198 | + } |
| 12199 | + } |
| 12200 | + |
| 12201 | + [(set_attr "length" "*,*,*,*,*,4,4") |
| 12202 | + (set_attr "type" "*,*,*,*,*,load2,store2") |
| 12203 | + (set_attr "cc" "*,*,*,*,*,none,none")]) |
| 12204 | + |
| 12205 | + |
| 12206 | +;;== 128 bits ================================================== |
| 12207 | +(define_expand "movti" |
| 12208 | + [(set (match_operand:TI 0 "nonimmediate_operand" "") |
| 12209 | + (match_operand:TI 1 "nonimmediate_operand" ""))] |
| 12210 | + "TARGET_ARCH_AP" |
| 12211 | + { |
| 12212 | + |
| 12213 | + /* One of the ops has to be in a register. */ |
| 12214 | + if (GET_CODE (operands[0]) != REG) |
| 12215 | + operands[1] = force_reg (TImode, operands[1]); |
| 12216 | + |
| 12217 | + /* We must fix any pre_dec for loads and post_inc stores */ |
| 12218 | + if ( GET_CODE (operands[0]) == MEM |
| 12219 | + && GET_CODE (XEXP(operands[0],0)) == POST_INC ){ |
| 12220 | + emit_move_insn(gen_rtx_MEM(TImode, XEXP(XEXP(operands[0],0),0)), operands[1]); |
| 12221 | + emit_insn(gen_addsi3(XEXP(XEXP(operands[0],0),0), XEXP(XEXP(operands[0],0),0), GEN_INT(GET_MODE_SIZE(TImode)))); |
| 12222 | + DONE; |
| 12223 | + } |
| 12224 | + |
| 12225 | + if ( GET_CODE (operands[1]) == MEM |
| 12226 | + && GET_CODE (XEXP(operands[1],0)) == PRE_DEC ){ |
| 12227 | + emit_insn(gen_addsi3(XEXP(XEXP(operands[1],0),0), XEXP(XEXP(operands[1],0),0), GEN_INT(-GET_MODE_SIZE(TImode)))); |
| 12228 | + emit_move_insn(operands[0], gen_rtx_MEM(TImode, XEXP(XEXP(operands[1],0),0))); |
| 12229 | + DONE; |
| 12230 | + } |
| 12231 | + }) |
| 12232 | + |
| 12233 | + |
| 12234 | +(define_insn_and_split "*movti_internal" |
| 12235 | + [(set (match_operand:TI 0 "avr32_movti_dst_operand" "=r,&r, r, <RKu00,r,r") |
| 12236 | + (match_operand:TI 1 "avr32_movti_src_operand" " r,RKu00>,RKu00,r, n,T"))] |
| 12237 | + "(register_operand (operands[0], TImode) |
| 12238 | + || register_operand (operands[1], TImode))" |
| 12239 | + { |
| 12240 | + switch (which_alternative ){ |
| 12241 | + case 0: |
| 12242 | + case 2: |
| 12243 | + case 4: |
| 12244 | + return "#"; |
| 12245 | + case 1: |
| 12246 | + return "ldm\t%p1, %0"; |
| 12247 | + case 3: |
| 12248 | + return "stm\t%p0, %1"; |
| 12249 | + case 5: |
| 12250 | + return "ld.d\t%U0, pc[%1 - .]\;ld.d\t%B0, pc[%1 - . + 8]"; |
| 12251 | + } |
| 12252 | + } |
| 12253 | + |
| 12254 | + "reload_completed && |
| 12255 | + (REG_P (operands[0]) && |
| 12256 | + (REG_P (operands[1]) |
| 12257 | + /* If this is a load from the constant pool we split it into |
| 12258 | + two double loads. */ |
| 12259 | + || (GET_CODE (operands[1]) == MEM |
| 12260 | + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF |
| 12261 | + && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0))) |
| 12262 | + /* If this is a load where the pointer register is a part |
| 12263 | + of the register list, we must split it into two double |
| 12264 | + loads in order for it to be exception safe. */ |
| 12265 | + || (GET_CODE (operands[1]) == MEM |
| 12266 | + && register_operand (XEXP (operands[1], 0), SImode) |
| 12267 | + && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) |
| 12268 | + || GET_CODE (operands[1]) == CONST_INT |
| 12269 | + || GET_CODE (operands[1]) == CONST_DOUBLE))" |
| 12270 | + [(set (match_dup 0) (match_dup 1)) |
| 12271 | + (set (match_dup 2) (match_dup 3))] |
| 12272 | + { |
| 12273 | + operands[2] = simplify_gen_subreg ( DImode, operands[0], |
| 12274 | + TImode, 0 ); |
| 12275 | + operands[0] = simplify_gen_subreg ( DImode, operands[0], |
| 12276 | + TImode, 8 ); |
| 12277 | + if ( REG_P(operands[1]) ){ |
| 12278 | + operands[3] = simplify_gen_subreg ( DImode, operands[1], |
| 12279 | + TImode, 0 ); |
| 12280 | + operands[1] = simplify_gen_subreg ( DImode, operands[1], |
| 12281 | + TImode, 8 ); |
| 12282 | + } else if ( GET_CODE(operands[1]) == CONST_DOUBLE |
| 12283 | + || GET_CODE(operands[1]) == CONST_INT ){ |
| 12284 | + rtx split_const[2]; |
| 12285 | + avr32_split_const_expr (TImode, DImode, operands[1], split_const); |
| 12286 | + operands[3] = split_const[1]; |
| 12287 | + operands[1] = split_const[0]; |
| 12288 | + } else if (avr32_const_pool_ref_operand (operands[1], GET_MODE(operands[1]))){ |
| 12289 | + rtx split_const[2]; |
| 12290 | + rtx cop = avoid_constant_pool_reference (operands[1]); |
| 12291 | + if (operands[1] == cop) |
| 12292 | + cop = get_pool_constant (XEXP (operands[1], 0)); |
| 12293 | + avr32_split_const_expr (TImode, DImode, cop, split_const); |
| 12294 | + operands[3] = force_const_mem (DImode, split_const[1]); |
| 12295 | + operands[1] = force_const_mem (DImode, split_const[0]); |
| 12296 | + } else { |
| 12297 | + rtx ptr_reg = XEXP (operands[1], 0); |
| 12298 | + operands[1] = gen_rtx_MEM (DImode, |
| 12299 | + gen_rtx_PLUS ( SImode, |
| 12300 | + ptr_reg, |
| 12301 | + GEN_INT (8) )); |
| 12302 | + operands[3] = gen_rtx_MEM (DImode, |
| 12303 | + ptr_reg); |
| 12304 | + |
| 12305 | + /* Check if the first load will clobber the pointer. |
| 12306 | + If so, we must switch the order of the operations. */ |
| 12307 | + if ( reg_overlap_mentioned_p (operands[0], ptr_reg) ) |
| 12308 | + { |
| 12309 | + /* We need to switch the order of the operations |
| 12310 | + so that the pointer register does not get clobbered |
| 12311 | + after the first double word load. */ |
| 12312 | + rtx tmp; |
| 12313 | + tmp = operands[0]; |
| 12314 | + operands[0] = operands[2]; |
| 12315 | + operands[2] = tmp; |
| 12316 | + tmp = operands[1]; |
| 12317 | + operands[1] = operands[3]; |
| 12318 | + operands[3] = tmp; |
| 12319 | + } |
| 12320 | + |
| 12321 | + |
| 12322 | + } |
| 12323 | + } |
| 12324 | + [(set_attr "length" "*,*,4,4,*,8") |
| 12325 | + (set_attr "type" "*,*,load4,store4,*,load4")]) |
| 12326 | + |
| 12327 | + |
| 12328 | +;;== float - 32 bits ========================================================== |
| 12329 | +(define_expand "movsf" |
| 12330 | + [(set (match_operand:SF 0 "nonimmediate_operand" "") |
| 12331 | + (match_operand:SF 1 "general_operand" ""))] |
| 12332 | + "" |
| 12333 | + { |
| 12334 | + |
| 12335 | + |
| 12336 | + /* One of the ops has to be in a register. */ |
| 12337 | + if (GET_CODE (operands[0]) != REG) |
| 12338 | + operands[1] = force_reg (SFmode, operands[1]); |
| 12339 | + |
| 12340 | + }) |
| 12341 | + |
| 12342 | +(define_insn "*movsf_internal" |
| 12343 | + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,r,m") |
| 12344 | + (match_operand:SF 1 "general_operand" "r, G,F,m,r"))] |
| 12345 | + "(register_operand (operands[0], SFmode) |
| 12346 | + || register_operand (operands[1], SFmode))" |
| 12347 | + { |
| 12348 | + switch (which_alternative) { |
| 12349 | + case 0: |
| 12350 | + case 1: return "mov\t%0, %1"; |
| 12351 | + case 2: |
| 12352 | + { |
| 12353 | + HOST_WIDE_INT target_float[2]; |
| 12354 | + real_to_target (target_float, CONST_DOUBLE_REAL_VALUE (operands[1]), SFmode); |
| 12355 | + if ( TARGET_V2_INSNS |
| 12356 | + && avr32_hi16_immediate_operand (GEN_INT (target_float[0]), VOIDmode) ) |
| 12357 | + return "movh\t%0, hi(%1)"; |
| 12358 | + else |
| 12359 | + return "mov\t%0, lo(%1)\;orh\t%0, hi(%1)"; |
| 12360 | + } |
| 12361 | + case 3: |
| 12362 | + if ( (REG_P(XEXP(operands[1], 0)) |
| 12363 | + && REGNO(XEXP(operands[1], 0)) == SP_REGNUM) |
| 12364 | + || (GET_CODE(XEXP(operands[1], 0)) == PLUS |
| 12365 | + && REGNO(XEXP(XEXP(operands[1], 0), 0)) == SP_REGNUM |
| 12366 | + && GET_CODE(XEXP(XEXP(operands[1], 0), 1)) == CONST_INT |
| 12367 | + && INTVAL(XEXP(XEXP(operands[1], 0), 1)) % 4 == 0 |
| 12368 | + && INTVAL(XEXP(XEXP(operands[1], 0), 1)) <= 0x1FC) ) |
| 12369 | + return "lddsp\t%0, %1"; |
| 12370 | + else if ( avr32_const_pool_ref_operand(operands[1], GET_MODE(operands[1])) ) |
| 12371 | + return "lddpc\t%0, %1"; |
| 12372 | + else |
| 12373 | + return "ld.w\t%0, %1"; |
| 12374 | + case 4: |
| 12375 | + if ( (REG_P(XEXP(operands[0], 0)) |
| 12376 | + && REGNO(XEXP(operands[0], 0)) == SP_REGNUM) |
| 12377 | + || (GET_CODE(XEXP(operands[0], 0)) == PLUS |
| 12378 | + && REGNO(XEXP(XEXP(operands[0], 0), 0)) == SP_REGNUM |
| 12379 | + && GET_CODE(XEXP(XEXP(operands[0], 0), 1)) == CONST_INT |
| 12380 | + && INTVAL(XEXP(XEXP(operands[0], 0), 1)) % 4 == 0 |
| 12381 | + && INTVAL(XEXP(XEXP(operands[0], 0), 1)) <= 0x1FC) ) |
| 12382 | + return "stdsp\t%0, %1"; |
| 12383 | + else |
| 12384 | + return "st.w\t%0, %1"; |
| 12385 | + default: |
| 12386 | + abort(); |
| 12387 | + } |
| 12388 | + } |
| 12389 | + |
| 12390 | + [(set_attr "length" "2,4,8,4,4") |
| 12391 | + (set_attr "type" "alu,alu,alu2,load,store") |
| 12392 | + (set_attr "cc" "none,none,clobber,none,none")]) |
| 12393 | + |
| 12394 | + |
| 12395 | + |
| 12396 | +;;== double - 64 bits ========================================================= |
| 12397 | +(define_expand "movdf" |
| 12398 | + [(set (match_operand:DF 0 "nonimmediate_operand" "") |
| 12399 | + (match_operand:DF 1 "general_operand" ""))] |
| 12400 | + "" |
| 12401 | + { |
| 12402 | + /* One of the ops has to be in a register. */ |
| 12403 | + if (GET_CODE (operands[0]) != REG){ |
| 12404 | + operands[1] = force_reg (DFmode, operands[1]); |
| 12405 | + } |
| 12406 | + }) |
| 12407 | + |
| 12408 | + |
| 12409 | +(define_insn_and_split "*movdf_internal" |
| 12410 | + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,r,r,m") |
| 12411 | + (match_operand:DF 1 "general_operand" " r,G,F,m,r"))] |
| 12412 | + "(register_operand (operands[0], DFmode) |
| 12413 | + || register_operand (operands[1], DFmode))" |
| 12414 | + { |
| 12415 | + switch (which_alternative ){ |
| 12416 | + case 0: |
| 12417 | + case 1: |
| 12418 | + case 2: |
| 12419 | + return "#"; |
| 12420 | + case 3: |
| 12421 | + if ( avr32_const_pool_ref_operand(operands[1], GET_MODE(operands[1]))) |
| 12422 | + return "ld.d\t%0, pc[%1 - .]"; |
| 12423 | + else |
| 12424 | + return "ld.d\t%0, %1"; |
| 12425 | + case 4: |
| 12426 | + return "st.d\t%0, %1"; |
| 12427 | + default: |
| 12428 | + abort(); |
| 12429 | + } |
| 12430 | + } |
| 12431 | + "reload_completed |
| 12432 | + && (REG_P (operands[0]) |
| 12433 | + && (REG_P (operands[1]) |
| 12434 | + || GET_CODE (operands[1]) == CONST_DOUBLE))" |
| 12435 | + [(set (match_dup 0) (match_dup 1)) |
| 12436 | + (set (match_dup 2) (match_dup 3))] |
| 12437 | + " |
| 12438 | + { |
| 12439 | + operands[2] = gen_highpart (SImode, operands[0]); |
| 12440 | + operands[0] = gen_lowpart (SImode, operands[0]); |
| 12441 | + operands[3] = gen_highpart(SImode, operands[1]); |
| 12442 | + operands[1] = gen_lowpart(SImode, operands[1]); |
| 12443 | + } |
| 12444 | + " |
| 12445 | + |
| 12446 | + [(set_attr "length" "*,*,*,4,4") |
| 12447 | + (set_attr "type" "*,*,*,load2,store2") |
| 12448 | + (set_attr "cc" "*,*,*,none,none")]) |
| 12449 | + |
| 12450 | + |
| 12451 | +;;============================================================================= |
| 12452 | +;; Conditional Moves |
| 12453 | +;;============================================================================= |
| 12454 | +(define_insn "ld<mode>_predicable" |
| 12455 | + [(set (match_operand:MOVCC 0 "register_operand" "=r") |
| 12456 | + (match_operand:MOVCC 1 "avr32_non_rmw_memory_operand" "<MOVCC:pred_mem_constraint>"))] |
| 12457 | + "TARGET_V2_INSNS" |
| 12458 | + "ld<MOVCC:load_postfix>%?\t%0, %1" |
| 12459 | + [(set_attr "length" "4") |
| 12460 | + (set_attr "cc" "cmp_cond_insn") |
| 12461 | + (set_attr "type" "load") |
| 12462 | + (set_attr "predicable" "yes")] |
| 12463 | +) |
| 12464 | + |
| 12465 | + |
| 12466 | +(define_insn "st<mode>_predicable" |
| 12467 | + [(set (match_operand:MOVCC 0 "avr32_non_rmw_memory_operand" "=<MOVCC:pred_mem_constraint>") |
| 12468 | + (match_operand:MOVCC 1 "register_operand" "r"))] |
| 12469 | + "TARGET_V2_INSNS" |
| 12470 | + "st<MOVCC:store_postfix>%?\t%0, %1" |
| 12471 | + [(set_attr "length" "4") |
| 12472 | + (set_attr "cc" "cmp_cond_insn") |
| 12473 | + (set_attr "type" "store") |
| 12474 | + (set_attr "predicable" "yes")] |
| 12475 | +) |
| 12476 | + |
| 12477 | +(define_insn "mov<mode>_predicable" |
| 12478 | + [(set (match_operand:MOVCC 0 "register_operand" "=r") |
| 12479 | + (match_operand:MOVCC 1 "avr32_cond_register_immediate_operand" "rKs08"))] |
| 12480 | + "" |
| 12481 | + "mov%?\t%0, %1" |
| 12482 | + [(set_attr "length" "4") |
| 12483 | + (set_attr "cc" "cmp_cond_insn") |
| 12484 | + (set_attr "type" "alu") |
| 12485 | + (set_attr "predicable" "yes")] |
| 12486 | +) |
| 12487 | + |
| 12488 | + |
| 12489 | +;;============================================================================= |
| 12490 | +;; Move chunks of memory |
| 12491 | +;;============================================================================= |
| 12492 | + |
| 12493 | +(define_expand "movmemsi" |
| 12494 | + [(match_operand:BLK 0 "general_operand" "") |
| 12495 | + (match_operand:BLK 1 "general_operand" "") |
| 12496 | + (match_operand:SI 2 "const_int_operand" "") |
| 12497 | + (match_operand:SI 3 "const_int_operand" "")] |
| 12498 | + "" |
| 12499 | + " |
| 12500 | + if (avr32_gen_movmemsi (operands)) |
| 12501 | + DONE; |
| 12502 | + FAIL; |
| 12503 | + " |
| 12504 | + ) |
| 12505 | + |
| 12506 | + |
| 12507 | + |
| 12508 | + |
| 12509 | +;;============================================================================= |
| 12510 | +;; Bit field instructions |
| 12511 | +;;----------------------------------------------------------------------------- |
| 12512 | +;; Instructions to insert or extract bit-fields |
| 12513 | +;;============================================================================= |
| 12514 | + |
| 12515 | +(define_insn "insv" |
| 12516 | + [ (set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") |
| 12517 | + (match_operand:SI 1 "immediate_operand" "Ku05") |
| 12518 | + (match_operand:SI 2 "immediate_operand" "Ku05")) |
| 12519 | + (match_operand 3 "register_operand" "r"))] |
| 12520 | + "" |
| 12521 | + "bfins\t%0, %3, %2, %1" |
| 12522 | + [(set_attr "type" "alu") |
| 12523 | + (set_attr "length" "4") |
| 12524 | + (set_attr "cc" "set_ncz")]) |
| 12525 | + |
| 12526 | + |
| 12527 | + |
| 12528 | +(define_expand "extv" |
| 12529 | + [ (set (match_operand:SI 0 "register_operand" "") |
| 12530 | + (sign_extract:SI (match_operand:SI 1 "register_operand" "") |
| 12531 | + (match_operand:SI 2 "immediate_operand" "") |
| 12532 | + (match_operand:SI 3 "immediate_operand" "")))] |
| 12533 | + "" |
| 12534 | + { |
| 12535 | + if ( INTVAL(operands[2]) >= 32 ) |
| 12536 | + FAIL; |
| 12537 | + } |
| 12538 | +) |
| 12539 | + |
| 12540 | +(define_expand "extzv" |
| 12541 | + [ (set (match_operand:SI 0 "register_operand" "") |
| 12542 | + (zero_extract:SI (match_operand:SI 1 "register_operand" "") |
| 12543 | + (match_operand:SI 2 "immediate_operand" "") |
| 12544 | + (match_operand:SI 3 "immediate_operand" "")))] |
| 12545 | + "" |
| 12546 | + { |
| 12547 | + if ( INTVAL(operands[2]) >= 32 ) |
| 12548 | + FAIL; |
| 12549 | + } |
| 12550 | +) |
| 12551 | + |
| 12552 | +(define_insn "extv_internal" |
| 12553 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 12554 | + (sign_extract:SI (match_operand:SI 1 "register_operand" "r") |
| 12555 | + (match_operand:SI 2 "immediate_operand" "Ku05") |
| 12556 | + (match_operand:SI 3 "immediate_operand" "Ku05")))] |
| 12557 | + "INTVAL(operands[2]) < 32" |
| 12558 | + "bfexts\t%0, %1, %3, %2" |
| 12559 | + [(set_attr "type" "alu") |
| 12560 | + (set_attr "length" "4") |
| 12561 | + (set_attr "cc" "set_ncz")]) |
| 12562 | + |
| 12563 | + |
| 12564 | +(define_insn "extzv_internal" |
| 12565 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 12566 | + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") |
| 12567 | + (match_operand:SI 2 "immediate_operand" "Ku05") |
| 12568 | + (match_operand:SI 3 "immediate_operand" "Ku05")))] |
| 12569 | + "INTVAL(operands[2]) < 32" |
| 12570 | + "bfextu\t%0, %1, %3, %2" |
| 12571 | + [(set_attr "type" "alu") |
| 12572 | + (set_attr "length" "4") |
| 12573 | + (set_attr "cc" "set_ncz")]) |
| 12574 | + |
| 12575 | + |
| 12576 | + |
| 12577 | +;;============================================================================= |
| 12578 | +;; Some peepholes for avoiding unnecessary cast instructions |
| 12579 | +;; followed by bfins. |
| 12580 | +;;----------------------------------------------------------------------------- |
| 12581 | + |
| 12582 | +(define_peephole2 |
| 12583 | + [(set (match_operand:SI 0 "register_operand" "") |
| 12584 | + (zero_extend:SI (match_operand:QI 1 "register_operand" ""))) |
| 12585 | + (set (zero_extract:SI (match_operand 2 "register_operand" "") |
| 12586 | + (match_operand:SI 3 "immediate_operand" "") |
| 12587 | + (match_operand:SI 4 "immediate_operand" "")) |
| 12588 | + (match_dup 0))] |
| 12589 | + "((peep2_reg_dead_p(2, operands[0]) && |
| 12590 | + (INTVAL(operands[3]) <= 8)))" |
| 12591 | + [(set (zero_extract:SI (match_dup 2) |
| 12592 | + (match_dup 3) |
| 12593 | + (match_dup 4)) |
| 12594 | + (match_dup 1))] |
| 12595 | + ) |
| 12596 | + |
| 12597 | +(define_peephole2 |
| 12598 | + [(set (match_operand:SI 0 "register_operand" "") |
| 12599 | + (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) |
| 12600 | + (set (zero_extract:SI (match_operand 2 "register_operand" "") |
| 12601 | + (match_operand:SI 3 "immediate_operand" "") |
| 12602 | + (match_operand:SI 4 "immediate_operand" "")) |
| 12603 | + (match_dup 0))] |
| 12604 | + "((peep2_reg_dead_p(2, operands[0]) && |
| 12605 | + (INTVAL(operands[3]) <= 16)))" |
| 12606 | + [(set (zero_extract:SI (match_dup 2) |
| 12607 | + (match_dup 3) |
| 12608 | + (match_dup 4)) |
| 12609 | + (match_dup 1))] |
| 12610 | + ) |
| 12611 | + |
| 12612 | +;;============================================================================= |
| 12613 | +;; push bytes |
| 12614 | +;;----------------------------------------------------------------------------- |
| 12615 | +;; Implements the push instruction |
| 12616 | +;;============================================================================= |
| 12617 | +(define_insn "pushm" |
| 12618 | + [(set (mem:BLK (pre_dec:BLK (reg:SI SP_REGNUM))) |
| 12619 | + (unspec:BLK [(match_operand 0 "const_int_operand" "")] |
| 12620 | + UNSPEC_PUSHM))] |
| 12621 | + "" |
| 12622 | + { |
| 12623 | + if (INTVAL(operands[0])) { |
| 12624 | + return "pushm\t%r0"; |
| 12625 | + } else { |
| 12626 | + return ""; |
| 12627 | + } |
| 12628 | + } |
| 12629 | + [(set_attr "type" "store") |
| 12630 | + (set_attr "length" "2") |
| 12631 | + (set_attr "cc" "none")]) |
| 12632 | + |
| 12633 | +(define_insn "stm" |
| 12634 | + [(unspec [(match_operand 0 "register_operand" "r") |
| 12635 | + (match_operand 1 "const_int_operand" "") |
| 12636 | + (match_operand 2 "const_int_operand" "")] |
| 12637 | + UNSPEC_STM)] |
| 12638 | + "" |
| 12639 | + { |
| 12640 | + if (INTVAL(operands[1])) { |
| 12641 | + if (INTVAL(operands[2]) != 0) |
| 12642 | + return "stm\t--%0, %s1"; |
| 12643 | + else |
| 12644 | + return "stm\t%0, %s1"; |
| 12645 | + } else { |
| 12646 | + return ""; |
| 12647 | + } |
| 12648 | + } |
| 12649 | + [(set_attr "type" "store") |
| 12650 | + (set_attr "length" "4") |
| 12651 | + (set_attr "cc" "none")]) |
| 12652 | + |
| 12653 | + |
| 12654 | + |
| 12655 | +(define_insn "popm" |
| 12656 | + [(unspec [(match_operand 0 "const_int_operand" "")] |
| 12657 | + UNSPEC_POPM)] |
| 12658 | + "" |
| 12659 | + { |
| 12660 | + if (INTVAL(operands[0])) { |
| 12661 | + return "popm %r0"; |
| 12662 | + } else { |
| 12663 | + return ""; |
| 12664 | + } |
| 12665 | + } |
| 12666 | + [(set_attr "type" "load") |
| 12667 | + (set_attr "length" "2")]) |
| 12668 | + |
| 12669 | + |
| 12670 | + |
| 12671 | +;;============================================================================= |
| 12672 | +;; add |
| 12673 | +;;----------------------------------------------------------------------------- |
| 12674 | +;; Adds reg1 with reg2 and puts the result in reg0. |
| 12675 | +;;============================================================================= |
| 12676 | +(define_insn "add<mode>3" |
| 12677 | + [(set (match_operand:INTM 0 "register_operand" "=r,r,r,r,r") |
| 12678 | + (plus:INTM (match_operand:INTM 1 "register_operand" "%0,r,0,r,0") |
| 12679 | + (match_operand:INTM 2 "avr32_add_operand" "r,r,Is08,Is16,Is21")))] |
| 12680 | + "" |
| 12681 | + "@ |
| 12682 | + add %0, %2 |
| 12683 | + add %0, %1, %2 |
| 12684 | + sub %0, %n2 |
| 12685 | + sub %0, %1, %n2 |
| 12686 | + sub %0, %n2" |
| 12687 | + |
| 12688 | + [(set_attr "length" "2,4,2,4,4") |
| 12689 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12690 | + |
| 12691 | +(define_insn "add<mode>3_lsl" |
| 12692 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 12693 | + (plus:INTM (ashift:INTM (match_operand:INTM 1 "register_operand" "r") |
| 12694 | + (match_operand:INTM 3 "avr32_add_shift_immediate_operand" "Ku02")) |
| 12695 | + (match_operand:INTM 2 "register_operand" "r")))] |
| 12696 | + "" |
| 12697 | + "add %0, %2, %1 << %3" |
| 12698 | + [(set_attr "length" "4") |
| 12699 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12700 | + |
| 12701 | +(define_insn "add<mode>3_lsl2" |
| 12702 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 12703 | + (plus:INTM (match_operand:INTM 1 "register_operand" "r") |
| 12704 | + (ashift:INTM (match_operand:INTM 2 "register_operand" "r") |
| 12705 | + (match_operand:INTM 3 "avr32_add_shift_immediate_operand" "Ku02"))))] |
| 12706 | + "" |
| 12707 | + "add %0, %1, %2 << %3" |
| 12708 | + [(set_attr "length" "4") |
| 12709 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12710 | + |
| 12711 | + |
| 12712 | +(define_insn "add<mode>3_mul" |
| 12713 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 12714 | + (plus:INTM (mult:INTM (match_operand:INTM 1 "register_operand" "r") |
| 12715 | + (match_operand:INTM 3 "immediate_operand" "Ku04" )) |
| 12716 | + (match_operand:INTM 2 "register_operand" "r")))] |
| 12717 | + "(INTVAL(operands[3]) == 0) || (INTVAL(operands[3]) == 2) || |
| 12718 | + (INTVAL(operands[3]) == 4) || (INTVAL(operands[3]) == 8)" |
| 12719 | + "add %0, %2, %1 << %p3" |
| 12720 | + [(set_attr "length" "4") |
| 12721 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12722 | + |
| 12723 | +(define_insn "add<mode>3_mul2" |
| 12724 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 12725 | + (plus:INTM (match_operand:INTM 1 "register_operand" "r") |
| 12726 | + (mult:INTM (match_operand:INTM 2 "register_operand" "r") |
| 12727 | + (match_operand:INTM 3 "immediate_operand" "Ku04" ))))] |
| 12728 | + "(INTVAL(operands[3]) == 0) || (INTVAL(operands[3]) == 2) || |
| 12729 | + (INTVAL(operands[3]) == 4) || (INTVAL(operands[3]) == 8)" |
| 12730 | + "add %0, %1, %2 << %p3" |
| 12731 | + [(set_attr "length" "4") |
| 12732 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12733 | + |
| 12734 | + |
| 12735 | +(define_peephole2 |
| 12736 | + [(set (match_operand:SI 0 "register_operand" "") |
| 12737 | + (ashift:SI (match_operand:SI 1 "register_operand" "") |
| 12738 | + (match_operand:SI 2 "immediate_operand" ""))) |
| 12739 | + (set (match_operand:SI 3 "register_operand" "") |
| 12740 | + (plus:SI (match_dup 0) |
| 12741 | + (match_operand:SI 4 "register_operand" "")))] |
| 12742 | + "(peep2_reg_dead_p(2, operands[0]) && |
| 12743 | + (INTVAL(operands[2]) < 4 && INTVAL(operands[2]) > 0))" |
| 12744 | + [(set (match_dup 3) |
| 12745 | + (plus:SI (ashift:SI (match_dup 1) |
| 12746 | + (match_dup 2)) |
| 12747 | + (match_dup 4)))] |
| 12748 | + ) |
| 12749 | + |
| 12750 | +(define_peephole2 |
| 12751 | + [(set (match_operand:SI 0 "register_operand" "") |
| 12752 | + (ashift:SI (match_operand:SI 1 "register_operand" "") |
| 12753 | + (match_operand:SI 2 "immediate_operand" ""))) |
| 12754 | + (set (match_operand:SI 3 "register_operand" "") |
| 12755 | + (plus:SI (match_operand:SI 4 "register_operand" "") |
| 12756 | + (match_dup 0)))] |
| 12757 | + "(peep2_reg_dead_p(2, operands[0]) && |
| 12758 | + (INTVAL(operands[2]) < 4 && INTVAL(operands[2]) > 0))" |
| 12759 | + [(set (match_dup 3) |
| 12760 | + (plus:SI (ashift:SI (match_dup 1) |
| 12761 | + (match_dup 2)) |
| 12762 | + (match_dup 4)))] |
| 12763 | + ) |
| 12764 | + |
| 12765 | +(define_insn "adddi3" |
| 12766 | + [(set (match_operand:DI 0 "register_operand" "=r,r") |
| 12767 | + (plus:DI (match_operand:DI 1 "register_operand" "%0,r") |
| 12768 | + (match_operand:DI 2 "register_operand" "r,r")))] |
| 12769 | + "" |
| 12770 | + "@ |
| 12771 | + add %0, %2\;adc %m0, %m0, %m2 |
| 12772 | + add %0, %1, %2\;adc %m0, %m1, %m2" |
| 12773 | + [(set_attr "length" "6,8") |
| 12774 | + (set_attr "type" "alu2") |
| 12775 | + (set_attr "cc" "set_vncz")]) |
| 12776 | + |
| 12777 | + |
| 12778 | +(define_insn "add<mode>_imm_predicable" |
| 12779 | + [(set (match_operand:INTM 0 "register_operand" "+r") |
| 12780 | + (plus:INTM (match_dup 0) |
| 12781 | + (match_operand:INTM 1 "avr32_cond_immediate_operand" "%Is08")))] |
| 12782 | + "" |
| 12783 | + "sub%?\t%0, -%1" |
| 12784 | + [(set_attr "length" "4") |
| 12785 | + (set_attr "cc" "cmp_cond_insn") |
| 12786 | + (set_attr "predicable" "yes")] |
| 12787 | +) |
| 12788 | + |
| 12789 | +;;============================================================================= |
| 12790 | +;; subtract |
| 12791 | +;;----------------------------------------------------------------------------- |
| 12792 | +;; Subtract reg2 or immediate value from reg0 and puts the result in reg0. |
| 12793 | +;;============================================================================= |
| 12794 | + |
| 12795 | +(define_insn "sub<mode>3" |
| 12796 | + [(set (match_operand:INTM 0 "general_operand" "=r,r,r,r,r,r,r") |
| 12797 | + (minus:INTM (match_operand:INTM 1 "register_const_int_operand" "0,r,0,r,0,r,Ks08") |
| 12798 | + (match_operand:INTM 2 "register_const_int_operand" "r,r,Ks08,Ks16,Ks21,0,r")))] |
| 12799 | + "" |
| 12800 | + "@ |
| 12801 | + sub %0, %2 |
| 12802 | + sub %0, %1, %2 |
| 12803 | + sub %0, %2 |
| 12804 | + sub %0, %1, %2 |
| 12805 | + sub %0, %2 |
| 12806 | + rsub %0, %1 |
| 12807 | + rsub %0, %2, %1" |
| 12808 | + [(set_attr "length" "2,4,2,4,4,2,4") |
| 12809 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12810 | + |
| 12811 | +(define_insn "*sub<mode>3_mul" |
| 12812 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 12813 | + (minus:INTM (match_operand:INTM 1 "register_operand" "r") |
| 12814 | + (mult:INTM (match_operand:INTM 2 "register_operand" "r") |
| 12815 | + (match_operand:SI 3 "immediate_operand" "Ku04" ))))] |
| 12816 | + "(INTVAL(operands[3]) == 0) || (INTVAL(operands[3]) == 2) || |
| 12817 | + (INTVAL(operands[3]) == 4) || (INTVAL(operands[3]) == 8)" |
| 12818 | + "sub %0, %1, %2 << %p3" |
| 12819 | + [(set_attr "length" "4") |
| 12820 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12821 | + |
| 12822 | +(define_insn "*sub<mode>3_lsl" |
| 12823 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 12824 | + (minus:INTM (match_operand:INTM 1 "register_operand" "r") |
| 12825 | + (ashift:INTM (match_operand:INTM 2 "register_operand" "r") |
| 12826 | + (match_operand:SI 3 "avr32_add_shift_immediate_operand" "Ku02"))))] |
| 12827 | + "" |
| 12828 | + "sub %0, %1, %2 << %3" |
| 12829 | + [(set_attr "length" "4") |
| 12830 | + (set_attr "cc" "<INTM:alu_cc_attr>")]) |
| 12831 | + |
| 12832 | + |
| 12833 | +(define_insn "subdi3" |
| 12834 | + [(set (match_operand:DI 0 "register_operand" "=r,r") |
| 12835 | + (minus:DI (match_operand:DI 1 "register_operand" "%0,r") |
| 12836 | + (match_operand:DI 2 "register_operand" "r,r")))] |
| 12837 | + "" |
| 12838 | + "@ |
| 12839 | + sub %0, %2\;sbc %m0, %m0, %m2 |
| 12840 | + sub %0, %1, %2\;sbc %m0, %m1, %m2" |
| 12841 | + [(set_attr "length" "6,8") |
| 12842 | + (set_attr "type" "alu2") |
| 12843 | + (set_attr "cc" "set_vncz")]) |
| 12844 | + |
| 12845 | + |
| 12846 | +(define_insn "sub<mode>_imm_predicable" |
| 12847 | + [(set (match_operand:INTM 0 "register_operand" "+r") |
| 12848 | + (minus:INTM (match_dup 0) |
| 12849 | + (match_operand:INTM 1 "avr32_cond_immediate_operand" "Ks08")))] |
| 12850 | + "" |
| 12851 | + "sub%?\t%0, %1" |
| 12852 | + [(set_attr "length" "4") |
| 12853 | + (set_attr "cc" "cmp_cond_insn") |
| 12854 | + (set_attr "predicable" "yes")]) |
| 12855 | + |
| 12856 | +(define_insn "rsub<mode>_imm_predicable" |
| 12857 | + [(set (match_operand:INTM 0 "register_operand" "+r") |
| 12858 | + (minus:INTM (match_operand:INTM 1 "avr32_cond_immediate_operand" "Ks08") |
| 12859 | + (match_dup 0)))] |
| 12860 | + "" |
| 12861 | + "rsub%?\t%0, %1" |
| 12862 | + [(set_attr "length" "4") |
| 12863 | + (set_attr "cc" "cmp_cond_insn") |
| 12864 | + (set_attr "predicable" "yes")]) |
| 12865 | + |
| 12866 | +;;============================================================================= |
| 12867 | +;; multiply |
| 12868 | +;;----------------------------------------------------------------------------- |
| 12869 | +;; Multiply op1 and op2 and put the value in op0. |
| 12870 | +;;============================================================================= |
| 12871 | + |
| 12872 | + |
| 12873 | +(define_insn "mulqi3" |
| 12874 | + [(set (match_operand:QI 0 "register_operand" "=r,r,r") |
| 12875 | + (mult:QI (match_operand:QI 1 "register_operand" "%0,r,r") |
| 12876 | + (match_operand:QI 2 "avr32_mul_operand" "r,r,Ks08")))] |
| 12877 | + "!TARGET_NO_MUL_INSNS" |
| 12878 | + { |
| 12879 | + switch (which_alternative){ |
| 12880 | + case 0: |
| 12881 | + return "mul %0, %2"; |
| 12882 | + case 1: |
| 12883 | + return "mul %0, %1, %2"; |
| 12884 | + case 2: |
| 12885 | + return "mul %0, %1, %2"; |
| 12886 | + default: |
| 12887 | + gcc_unreachable(); |
| 12888 | + } |
| 12889 | + } |
| 12890 | + [(set_attr "type" "mulww_w,mulww_w,mulwh") |
| 12891 | + (set_attr "length" "2,4,4") |
| 12892 | + (set_attr "cc" "none")]) |
| 12893 | + |
| 12894 | +(define_insn "mulsi3" |
| 12895 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
| 12896 | + (mult:SI (match_operand:SI 1 "register_operand" "%0,r,r") |
| 12897 | + (match_operand:SI 2 "avr32_mul_operand" "r,r,Ks08")))] |
| 12898 | + "!TARGET_NO_MUL_INSNS" |
| 12899 | + { |
| 12900 | + switch (which_alternative){ |
| 12901 | + case 0: |
| 12902 | + return "mul %0, %2"; |
| 12903 | + case 1: |
| 12904 | + return "mul %0, %1, %2"; |
| 12905 | + case 2: |
| 12906 | + return "mul %0, %1, %2"; |
| 12907 | + default: |
| 12908 | + gcc_unreachable(); |
| 12909 | + } |
| 12910 | + } |
| 12911 | + [(set_attr "type" "mulww_w,mulww_w,mulwh") |
| 12912 | + (set_attr "length" "2,4,4") |
| 12913 | + (set_attr "cc" "none")]) |
| 12914 | + |
| 12915 | + |
| 12916 | +(define_insn "mulhisi3" |
| 12917 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 12918 | + (mult:SI |
| 12919 | + (sign_extend:SI (match_operand:HI 1 "register_operand" "%r")) |
| 12920 | + (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] |
| 12921 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 12922 | + "mulhh.w %0, %1:b, %2:b" |
| 12923 | + [(set_attr "type" "mulhh") |
| 12924 | + (set_attr "length" "4") |
| 12925 | + (set_attr "cc" "none")]) |
| 12926 | + |
| 12927 | +(define_peephole2 |
| 12928 | + [(match_scratch:DI 6 "r") |
| 12929 | + (set (match_operand:SI 0 "register_operand" "") |
| 12930 | + (mult:SI |
| 12931 | + (sign_extend:SI (match_operand:HI 1 "register_operand" "")) |
| 12932 | + (sign_extend:SI (match_operand:HI 2 "register_operand" "")))) |
| 12933 | + (set (match_operand:SI 3 "register_operand" "") |
| 12934 | + (ashiftrt:SI (match_dup 0) |
| 12935 | + (const_int 16)))] |
| 12936 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP |
| 12937 | + && (peep2_reg_dead_p(1, operands[0]) || (REGNO(operands[0]) == REGNO(operands[3])))" |
| 12938 | + [(set (match_dup 4) (sign_extend:SI (match_dup 1))) |
| 12939 | + (set (match_dup 6) |
| 12940 | + (ashift:DI (mult:DI (sign_extend:DI (match_dup 4)) |
| 12941 | + (sign_extend:DI (match_dup 2))) |
| 12942 | + (const_int 16))) |
| 12943 | + (set (match_dup 3) (match_dup 5))] |
| 12944 | + |
| 12945 | + "{ |
| 12946 | + operands[4] = gen_rtx_REG(SImode, REGNO(operands[1])); |
| 12947 | + operands[5] = gen_highpart (SImode, operands[4]); |
| 12948 | + }" |
| 12949 | + ) |
| 12950 | + |
| 12951 | +(define_insn "mulnhisi3" |
| 12952 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 12953 | + (mult:SI |
| 12954 | + (sign_extend:SI (neg:HI (match_operand:HI 1 "register_operand" "r"))) |
| 12955 | + (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] |
| 12956 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 12957 | + "mulnhh.w %0, %1:b, %2:b" |
| 12958 | + [(set_attr "type" "mulhh") |
| 12959 | + (set_attr "length" "4") |
| 12960 | + (set_attr "cc" "none")]) |
| 12961 | + |
| 12962 | +(define_insn "machisi3" |
| 12963 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 12964 | + (plus:SI (mult:SI |
| 12965 | + (sign_extend:SI (match_operand:HI 1 "register_operand" "%r")) |
| 12966 | + (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))) |
| 12967 | + (match_dup 0)))] |
| 12968 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 12969 | + "machh.w %0, %1:b, %2:b" |
| 12970 | + [(set_attr "type" "machh_w") |
| 12971 | + (set_attr "length" "4") |
| 12972 | + (set_attr "cc" "none")]) |
| 12973 | + |
| 12974 | + |
| 12975 | + |
| 12976 | +(define_insn "mulsidi3" |
| 12977 | + [(set (match_operand:DI 0 "register_operand" "=r") |
| 12978 | + (mult:DI |
| 12979 | + (sign_extend:DI (match_operand:SI 1 "register_operand" "%r")) |
| 12980 | + (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))] |
| 12981 | + "!TARGET_NO_MUL_INSNS" |
| 12982 | + "muls.d %0, %1, %2" |
| 12983 | + [(set_attr "type" "mulww_d") |
| 12984 | + (set_attr "length" "4") |
| 12985 | + (set_attr "cc" "none")]) |
| 12986 | + |
| 12987 | +(define_insn "umulsidi3" |
| 12988 | + [(set (match_operand:DI 0 "register_operand" "=r") |
| 12989 | + (mult:DI |
| 12990 | + (zero_extend:DI (match_operand:SI 1 "register_operand" "%r")) |
| 12991 | + (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))] |
| 12992 | + "!TARGET_NO_MUL_INSNS" |
| 12993 | + "mulu.d %0, %1, %2" |
| 12994 | + [(set_attr "type" "mulww_d") |
| 12995 | + (set_attr "length" "4") |
| 12996 | + (set_attr "cc" "none")]) |
| 12997 | + |
| 12998 | +(define_insn "*mulaccsi3" |
| 12999 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 13000 | + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "%r") |
| 13001 | + (match_operand:SI 2 "register_operand" "r")) |
| 13002 | + (match_dup 0)))] |
| 13003 | + "!TARGET_NO_MUL_INSNS" |
| 13004 | + "mac %0, %1, %2" |
| 13005 | + [(set_attr "type" "macww_w") |
| 13006 | + (set_attr "length" "4") |
| 13007 | + (set_attr "cc" "none")]) |
| 13008 | + |
| 13009 | +(define_insn "*mulaccsidi3" |
| 13010 | + [(set (match_operand:DI 0 "register_operand" "+r") |
| 13011 | + (plus:DI (mult:DI |
| 13012 | + (sign_extend:DI (match_operand:SI 1 "register_operand" "%r")) |
| 13013 | + (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) |
| 13014 | + (match_dup 0)))] |
| 13015 | + "!TARGET_NO_MUL_INSNS" |
| 13016 | + "macs.d %0, %1, %2" |
| 13017 | + [(set_attr "type" "macww_d") |
| 13018 | + (set_attr "length" "4") |
| 13019 | + (set_attr "cc" "none")]) |
| 13020 | + |
| 13021 | +(define_insn "*umulaccsidi3" |
| 13022 | + [(set (match_operand:DI 0 "register_operand" "+r") |
| 13023 | + (plus:DI (mult:DI |
| 13024 | + (zero_extend:DI (match_operand:SI 1 "register_operand" "%r")) |
| 13025 | + (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) |
| 13026 | + (match_dup 0)))] |
| 13027 | + "!TARGET_NO_MUL_INSNS" |
| 13028 | + "macu.d %0, %1, %2" |
| 13029 | + [(set_attr "type" "macww_d") |
| 13030 | + (set_attr "length" "4") |
| 13031 | + (set_attr "cc" "none")]) |
| 13032 | + |
| 13033 | + |
| 13034 | + |
| 13035 | +;; Try to avoid Write-After-Write hazards for mul operations |
| 13036 | +;; if it can be done |
| 13037 | +(define_peephole2 |
| 13038 | + [(set (match_operand:SI 0 "register_operand" "") |
| 13039 | + (mult:SI |
| 13040 | + (sign_extend:SI (match_operand 1 "general_operand" "")) |
| 13041 | + (sign_extend:SI (match_operand 2 "general_operand" "")))) |
| 13042 | + (set (match_dup 0) |
| 13043 | + (match_operator:SI 3 "alu_operator" [(match_dup 0) |
| 13044 | + (match_operand 4 "general_operand" "")]))] |
| 13045 | + "peep2_reg_dead_p(1, operands[2])" |
| 13046 | + [(set (match_dup 5) |
| 13047 | + (mult:SI |
| 13048 | + (sign_extend:SI (match_dup 1)) |
| 13049 | + (sign_extend:SI (match_dup 2)))) |
| 13050 | + (set (match_dup 0) |
| 13051 | + (match_op_dup 3 [(match_dup 5) |
| 13052 | + (match_dup 4)]))] |
| 13053 | + "{operands[5] = gen_rtx_REG(SImode, REGNO(operands[2]));}" |
| 13054 | + ) |
| 13055 | + |
| 13056 | + |
| 13057 | + |
| 13058 | +;;============================================================================= |
| 13059 | +;; DSP instructions |
| 13060 | +;;============================================================================= |
| 13061 | +(define_insn "mulsathh_h" |
| 13062 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 13063 | + (ss_truncate:HI (ashiftrt:SI (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%r")) |
| 13064 | + (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))) |
| 13065 | + (const_int 15))))] |
| 13066 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13067 | + "mulsathh.h\t%0, %1:b, %2:b" |
| 13068 | + [(set_attr "length" "4") |
| 13069 | + (set_attr "cc" "none") |
| 13070 | + (set_attr "type" "mulhh")]) |
| 13071 | + |
| 13072 | +(define_insn "mulsatrndhh_h" |
| 13073 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 13074 | + (ss_truncate:HI (ashiftrt:SI |
| 13075 | + (plus:SI (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%r")) |
| 13076 | + (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))) |
| 13077 | + (const_int 1073741824)) |
| 13078 | + (const_int 15))))] |
| 13079 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13080 | + "mulsatrndhh.h\t%0, %1:b, %2:b" |
| 13081 | + [(set_attr "length" "4") |
| 13082 | + (set_attr "cc" "none") |
| 13083 | + (set_attr "type" "mulhh")]) |
| 13084 | + |
| 13085 | +(define_insn "mulsathh_w" |
| 13086 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13087 | + (ss_truncate:SI (ashift:DI (mult:DI (sign_extend:DI (match_operand:HI 1 "register_operand" "%r")) |
| 13088 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13089 | + (const_int 1))))] |
| 13090 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13091 | + "mulsathh.w\t%0, %1:b, %2:b" |
| 13092 | + [(set_attr "length" "4") |
| 13093 | + (set_attr "cc" "none") |
| 13094 | + (set_attr "type" "mulhh")]) |
| 13095 | + |
| 13096 | +(define_insn "mulsatwh_w" |
| 13097 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13098 | + (ss_truncate:SI (ashiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) |
| 13099 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13100 | + (const_int 15))))] |
| 13101 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13102 | + "mulsatwh.w\t%0, %1, %2:b" |
| 13103 | + [(set_attr "length" "4") |
| 13104 | + (set_attr "cc" "none") |
| 13105 | + (set_attr "type" "mulwh")]) |
| 13106 | + |
| 13107 | +(define_insn "mulsatrndwh_w" |
| 13108 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13109 | + (ss_truncate:SI (ashiftrt:DI (plus:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) |
| 13110 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13111 | + (const_int 1073741824)) |
| 13112 | + (const_int 15))))] |
| 13113 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13114 | + "mulsatrndwh.w\t%0, %1, %2:b" |
| 13115 | + [(set_attr "length" "4") |
| 13116 | + (set_attr "cc" "none") |
| 13117 | + (set_attr "type" "mulwh")]) |
| 13118 | + |
| 13119 | +(define_insn "macsathh_w" |
| 13120 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 13121 | + (plus:SI (match_dup 0) |
| 13122 | + (ss_truncate:SI (ashift:DI (mult:DI (sign_extend:DI (match_operand:HI 1 "register_operand" "%r")) |
| 13123 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13124 | + (const_int 1)))))] |
| 13125 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13126 | + "macsathh.w\t%0, %1:b, %2:b" |
| 13127 | + [(set_attr "length" "4") |
| 13128 | + (set_attr "cc" "none") |
| 13129 | + (set_attr "type" "mulhh")]) |
| 13130 | + |
| 13131 | + |
| 13132 | +(define_insn "mulwh_d" |
| 13133 | + [(set (match_operand:DI 0 "register_operand" "=r") |
| 13134 | + (ashift:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) |
| 13135 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13136 | + (const_int 16)))] |
| 13137 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13138 | + "mulwh.d\t%0, %1, %2:b" |
| 13139 | + [(set_attr "length" "4") |
| 13140 | + (set_attr "cc" "none") |
| 13141 | + (set_attr "type" "mulwh")]) |
| 13142 | + |
| 13143 | + |
| 13144 | +(define_insn "mulnwh_d" |
| 13145 | + [(set (match_operand:DI 0 "register_operand" "=r") |
| 13146 | + (ashift:DI (mult:DI (not:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))) |
| 13147 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13148 | + (const_int 16)))] |
| 13149 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13150 | + "mulnwh.d\t%0, %1, %2:b" |
| 13151 | + [(set_attr "length" "4") |
| 13152 | + (set_attr "cc" "none") |
| 13153 | + (set_attr "type" "mulwh")]) |
| 13154 | + |
| 13155 | +(define_insn "macwh_d" |
| 13156 | + [(set (match_operand:DI 0 "register_operand" "+r") |
| 13157 | + (plus:DI (match_dup 0) |
| 13158 | + (ashift:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%r")) |
| 13159 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r"))) |
| 13160 | + (const_int 16))))] |
| 13161 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13162 | + "macwh.d\t%0, %1, %2:b" |
| 13163 | + [(set_attr "length" "4") |
| 13164 | + (set_attr "cc" "none") |
| 13165 | + (set_attr "type" "mulwh")]) |
| 13166 | + |
| 13167 | +(define_insn "machh_d" |
| 13168 | + [(set (match_operand:DI 0 "register_operand" "+r") |
| 13169 | + (plus:DI (match_dup 0) |
| 13170 | + (mult:DI (sign_extend:DI (match_operand:HI 1 "register_operand" "%r")) |
| 13171 | + (sign_extend:DI (match_operand:HI 2 "register_operand" "r")))))] |
| 13172 | + "!TARGET_NO_MUL_INSNS && TARGET_DSP" |
| 13173 | + "machh.d\t%0, %1:b, %2:b" |
| 13174 | + [(set_attr "length" "4") |
| 13175 | + (set_attr "cc" "none") |
| 13176 | + (set_attr "type" "mulwh")]) |
| 13177 | + |
| 13178 | +(define_insn "satadd_w" |
| 13179 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13180 | + (ss_plus:SI (match_operand:SI 1 "register_operand" "r") |
| 13181 | + (match_operand:SI 2 "register_operand" "r")))] |
| 13182 | + "TARGET_DSP" |
| 13183 | + "satadd.w\t%0, %1, %2" |
| 13184 | + [(set_attr "length" "4") |
| 13185 | + (set_attr "cc" "none") |
| 13186 | + (set_attr "type" "alu_sat")]) |
| 13187 | + |
| 13188 | +(define_insn "satsub_w" |
| 13189 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13190 | + (ss_minus:SI (match_operand:SI 1 "register_operand" "r") |
| 13191 | + (match_operand:SI 2 "register_operand" "r")))] |
| 13192 | + "TARGET_DSP" |
| 13193 | + "satsub.w\t%0, %1, %2" |
| 13194 | + [(set_attr "length" "4") |
| 13195 | + (set_attr "cc" "none") |
| 13196 | + (set_attr "type" "alu_sat")]) |
| 13197 | + |
| 13198 | +(define_insn "satadd_h" |
| 13199 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 13200 | + (ss_plus:HI (match_operand:HI 1 "register_operand" "r") |
| 13201 | + (match_operand:HI 2 "register_operand" "r")))] |
| 13202 | + "TARGET_DSP" |
| 13203 | + "satadd.h\t%0, %1, %2" |
| 13204 | + [(set_attr "length" "4") |
| 13205 | + (set_attr "cc" "none") |
| 13206 | + (set_attr "type" "alu_sat")]) |
| 13207 | + |
| 13208 | +(define_insn "satsub_h" |
| 13209 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 13210 | + (ss_minus:HI (match_operand:HI 1 "register_operand" "r") |
| 13211 | + (match_operand:HI 2 "register_operand" "r")))] |
| 13212 | + "TARGET_DSP" |
| 13213 | + "satsub.h\t%0, %1, %2" |
| 13214 | + [(set_attr "length" "4") |
| 13215 | + (set_attr "cc" "none") |
| 13216 | + (set_attr "type" "alu_sat")]) |
| 13217 | + |
| 13218 | + |
| 13219 | +;;============================================================================= |
| 13220 | +;; smin |
| 13221 | +;;----------------------------------------------------------------------------- |
| 13222 | +;; Set reg0 to the smallest value of reg1 and reg2. It is used for signed |
| 13223 | +;; values in the registers. |
| 13224 | +;;============================================================================= |
| 13225 | +(define_insn "sminsi3" |
| 13226 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13227 | + (smin:SI (match_operand:SI 1 "register_operand" "r") |
| 13228 | + (match_operand:SI 2 "register_operand" "r")))] |
| 13229 | + "" |
| 13230 | + "min %0, %1, %2" |
| 13231 | + [(set_attr "length" "4") |
| 13232 | + (set_attr "cc" "none")]) |
| 13233 | + |
| 13234 | +;;============================================================================= |
| 13235 | +;; smax |
| 13236 | +;;----------------------------------------------------------------------------- |
| 13237 | +;; Set reg0 to the largest value of reg1 and reg2. It is used for signed |
| 13238 | +;; values in the registers. |
| 13239 | +;;============================================================================= |
| 13240 | +(define_insn "smaxsi3" |
| 13241 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13242 | + (smax:SI (match_operand:SI 1 "register_operand" "r") |
| 13243 | + (match_operand:SI 2 "register_operand" "r")))] |
| 13244 | + "" |
| 13245 | + "max %0, %1, %2" |
| 13246 | + [(set_attr "length" "4") |
| 13247 | + (set_attr "cc" "none")]) |
| 13248 | + |
| 13249 | + |
| 13250 | + |
| 13251 | +;;============================================================================= |
| 13252 | +;; Logical operations |
| 13253 | +;;----------------------------------------------------------------------------- |
| 13254 | + |
| 13255 | + |
| 13256 | +;; Split up simple DImode logical operations. Simply perform the logical |
| 13257 | +;; operation on the upper and lower halves of the registers. |
| 13258 | +(define_split |
| 13259 | + [(set (match_operand:DI 0 "register_operand" "") |
| 13260 | + (match_operator:DI 6 "logical_binary_operator" |
| 13261 | + [(match_operand:DI 1 "register_operand" "") |
| 13262 | + (match_operand:DI 2 "register_operand" "")]))] |
| 13263 | + "reload_completed" |
| 13264 | + [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) |
| 13265 | + (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))] |
| 13266 | + " |
| 13267 | + { |
| 13268 | + operands[3] = gen_highpart (SImode, operands[0]); |
| 13269 | + operands[0] = gen_lowpart (SImode, operands[0]); |
| 13270 | + operands[4] = gen_highpart (SImode, operands[1]); |
| 13271 | + operands[1] = gen_lowpart (SImode, operands[1]); |
| 13272 | + operands[5] = gen_highpart (SImode, operands[2]); |
| 13273 | + operands[2] = gen_lowpart (SImode, operands[2]); |
| 13274 | + }" |
| 13275 | +) |
| 13276 | + |
| 13277 | +;;============================================================================= |
| 13278 | +;; Logical operations with shifted operand |
| 13279 | +;;============================================================================= |
| 13280 | +(define_insn "<code>si_lshift" |
| 13281 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13282 | + (logical:SI (match_operator:SI 4 "logical_shift_operator" |
| 13283 | + [(match_operand:SI 2 "register_operand" "r") |
| 13284 | + (match_operand:SI 3 "immediate_operand" "Ku05")]) |
| 13285 | + (match_operand:SI 1 "register_operand" "r")))] |
| 13286 | + "" |
| 13287 | + { |
| 13288 | + if ( GET_CODE(operands[4]) == ASHIFT ) |
| 13289 | + return "<logical_insn>\t%0, %1, %2 << %3"; |
| 13290 | + else |
| 13291 | + return "<logical_insn>\t%0, %1, %2 >> %3"; |
| 13292 | + } |
| 13293 | + |
| 13294 | + [(set_attr "cc" "set_z")] |
| 13295 | +) |
| 13296 | + |
| 13297 | + |
| 13298 | +;;************************************************ |
| 13299 | +;; Peepholes for detecting logical operantions |
| 13300 | +;; with shifted operands |
| 13301 | +;;************************************************ |
| 13302 | + |
| 13303 | +(define_peephole |
| 13304 | + [(set (match_operand:SI 3 "register_operand" "") |
| 13305 | + (match_operator:SI 5 "logical_shift_operator" |
| 13306 | + [(match_operand:SI 1 "register_operand" "") |
| 13307 | + (match_operand:SI 2 "immediate_operand" "")])) |
| 13308 | + (set (match_operand:SI 0 "register_operand" "") |
| 13309 | + (logical:SI (match_operand:SI 4 "register_operand" "") |
| 13310 | + (match_dup 3)))] |
| 13311 | + "(dead_or_set_p(insn, operands[3])) || (REGNO(operands[3]) == REGNO(operands[0]))" |
| 13312 | + { |
| 13313 | + if ( GET_CODE(operands[5]) == ASHIFT ) |
| 13314 | + return "<logical_insn>\t%0, %4, %1 << %2"; |
| 13315 | + else |
| 13316 | + return "<logical_insn>\t%0, %4, %1 >> %2"; |
| 13317 | + } |
| 13318 | + [(set_attr "cc" "set_z")] |
| 13319 | + ) |
| 13320 | + |
| 13321 | +(define_peephole |
| 13322 | + [(set (match_operand:SI 3 "register_operand" "") |
| 13323 | + (match_operator:SI 5 "logical_shift_operator" |
| 13324 | + [(match_operand:SI 1 "register_operand" "") |
| 13325 | + (match_operand:SI 2 "immediate_operand" "")])) |
| 13326 | + (set (match_operand:SI 0 "register_operand" "") |
| 13327 | + (logical:SI (match_dup 3) |
| 13328 | + (match_operand:SI 4 "register_operand" "")))] |
| 13329 | + "(dead_or_set_p(insn, operands[3])) || (REGNO(operands[3]) == REGNO(operands[0]))" |
| 13330 | + { |
| 13331 | + if ( GET_CODE(operands[5]) == ASHIFT ) |
| 13332 | + return "<logical_insn>\t%0, %4, %1 << %2"; |
| 13333 | + else |
| 13334 | + return "<logical_insn>\t%0, %4, %1 >> %2"; |
| 13335 | + } |
| 13336 | + [(set_attr "cc" "set_z")] |
| 13337 | + ) |
| 13338 | + |
| 13339 | + |
| 13340 | +(define_peephole2 |
| 13341 | + [(set (match_operand:SI 0 "register_operand" "") |
| 13342 | + (match_operator:SI 5 "logical_shift_operator" |
| 13343 | + [(match_operand:SI 1 "register_operand" "") |
| 13344 | + (match_operand:SI 2 "immediate_operand" "")])) |
| 13345 | + (set (match_operand:SI 3 "register_operand" "") |
| 13346 | + (logical:SI (match_operand:SI 4 "register_operand" "") |
| 13347 | + (match_dup 0)))] |
| 13348 | + "(peep2_reg_dead_p(2, operands[0])) || (REGNO(operands[3]) == REGNO(operands[0]))" |
| 13349 | + |
| 13350 | + [(set (match_dup 3) |
| 13351 | + (logical:SI (match_op_dup:SI 5 [(match_dup 1) (match_dup 2)]) |
| 13352 | + (match_dup 4)))] |
| 13353 | + |
| 13354 | + "" |
| 13355 | +) |
| 13356 | + |
| 13357 | +(define_peephole2 |
| 13358 | + [(set (match_operand:SI 0 "register_operand" "") |
| 13359 | + (match_operator:SI 5 "logical_shift_operator" |
| 13360 | + [(match_operand:SI 1 "register_operand" "") |
| 13361 | + (match_operand:SI 2 "immediate_operand" "")])) |
| 13362 | + (set (match_operand:SI 3 "register_operand" "") |
| 13363 | + (logical:SI (match_dup 0) |
| 13364 | + (match_operand:SI 4 "register_operand" "")))] |
| 13365 | + "(peep2_reg_dead_p(2, operands[0])) || (REGNO(operands[3]) == REGNO(operands[0]))" |
| 13366 | + |
| 13367 | + [(set (match_dup 3) |
| 13368 | + (logical:SI (match_op_dup:SI 5 [(match_dup 1) (match_dup 2)]) |
| 13369 | + (match_dup 4)))] |
| 13370 | + |
| 13371 | + "" |
| 13372 | +) |
| 13373 | + |
| 13374 | + |
| 13375 | +;;============================================================================= |
| 13376 | +;; and |
| 13377 | +;;----------------------------------------------------------------------------- |
| 13378 | +;; Store the result after a bitwise logical-and between reg0 and reg2 in reg0. |
| 13379 | +;;============================================================================= |
| 13380 | + |
| 13381 | +(define_insn "andnsi" |
| 13382 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 13383 | + (and:SI (match_dup 0) |
| 13384 | + (not:SI (match_operand:SI 1 "register_operand" "r"))))] |
| 13385 | + "" |
| 13386 | + "andn %0, %1" |
| 13387 | + [(set_attr "cc" "set_z") |
| 13388 | + (set_attr "length" "2")] |
| 13389 | +) |
| 13390 | + |
| 13391 | + |
| 13392 | +(define_insn "andsi3" |
| 13393 | + [(set (match_operand:SI 0 "avr32_rmw_memory_or_register_operand" "=Y,r,r,r, r, r,r,r,r,r") |
| 13394 | + (and:SI (match_operand:SI 1 "avr32_rmw_memory_or_register_operand" "%0,r,0,0, 0, 0,0,0,0,r" ) |
| 13395 | + (match_operand:SI 2 "nonmemory_operand" " N,M,N,Ku16,Ks17,J,L,r,i,r")))] |
| 13396 | + "" |
| 13397 | + "@ |
| 13398 | + memc\t%0, %z2 |
| 13399 | + bfextu\t%0, %1, 0, %z2 |
| 13400 | + cbr\t%0, %z2 |
| 13401 | + andl\t%0, %2, COH |
| 13402 | + andl\t%0, lo(%2) |
| 13403 | + andh\t%0, hi(%2), COH |
| 13404 | + andh\t%0, hi(%2) |
| 13405 | + and\t%0, %2 |
| 13406 | + andh\t%0, hi(%2)\;andl\t%0, lo(%2) |
| 13407 | + and\t%0, %1, %2" |
| 13408 | + |
| 13409 | + [(set_attr "length" "4,4,2,4,4,4,4,2,8,4") |
| 13410 | + (set_attr "cc" "none,set_z,set_z,set_z,set_z,set_z,set_z,set_z,set_z,set_z")]) |
| 13411 | + |
| 13412 | + |
| 13413 | + |
| 13414 | +(define_insn "anddi3" |
| 13415 | + [(set (match_operand:DI 0 "register_operand" "=&r,&r") |
| 13416 | + (and:DI (match_operand:DI 1 "register_operand" "%0,r") |
| 13417 | + (match_operand:DI 2 "register_operand" "r,r")))] |
| 13418 | + "" |
| 13419 | + "#" |
| 13420 | + [(set_attr "length" "8") |
| 13421 | + (set_attr "cc" "clobber")] |
| 13422 | +) |
| 13423 | + |
| 13424 | +;;============================================================================= |
| 13425 | +;; or |
| 13426 | +;;----------------------------------------------------------------------------- |
| 13427 | +;; Store the result after a bitwise inclusive-or between reg0 and reg2 in reg0. |
| 13428 | +;;============================================================================= |
| 13429 | + |
| 13430 | +(define_insn "iorsi3" |
| 13431 | + [(set (match_operand:SI 0 "avr32_rmw_memory_or_register_operand" "=Y,r,r, r,r,r,r") |
| 13432 | + (ior:SI (match_operand:SI 1 "avr32_rmw_memory_or_register_operand" "%0,0,0, 0,0,0,r" ) |
| 13433 | + (match_operand:SI 2 "nonmemory_operand" " O,O,Ku16,J,r,i,r")))] |
| 13434 | + "" |
| 13435 | + "@ |
| 13436 | + mems\t%0, %p2 |
| 13437 | + sbr\t%0, %p2 |
| 13438 | + orl\t%0, %2 |
| 13439 | + orh\t%0, hi(%2) |
| 13440 | + or\t%0, %2 |
| 13441 | + orh\t%0, hi(%2)\;orl\t%0, lo(%2) |
| 13442 | + or\t%0, %1, %2" |
| 13443 | + |
| 13444 | + [(set_attr "length" "4,2,4,4,2,8,4") |
| 13445 | + (set_attr "cc" "none,set_z,set_z,set_z,set_z,set_z,set_z")]) |
| 13446 | + |
| 13447 | + |
| 13448 | +(define_insn "iordi3" |
| 13449 | + [(set (match_operand:DI 0 "register_operand" "=&r,&r") |
| 13450 | + (ior:DI (match_operand:DI 1 "register_operand" "%0,r") |
| 13451 | + (match_operand:DI 2 "register_operand" "r,r")))] |
| 13452 | + "" |
| 13453 | + "#" |
| 13454 | + [(set_attr "length" "8") |
| 13455 | + (set_attr "cc" "clobber")] |
| 13456 | +) |
| 13457 | + |
| 13458 | +;;============================================================================= |
| 13459 | +;; xor bytes |
| 13460 | +;;----------------------------------------------------------------------------- |
| 13461 | +;; Store the result after a bitwise exclusive-or between reg0 and reg2 in reg0. |
| 13462 | +;;============================================================================= |
| 13463 | + |
| 13464 | +(define_insn "xorsi3" |
| 13465 | + [(set (match_operand:SI 0 "avr32_rmw_memory_or_register_operand" "=Y,r, r,r,r,r") |
| 13466 | + (xor:SI (match_operand:SI 1 "avr32_rmw_memory_or_register_operand" "%0,0, 0,0,0,r" ) |
| 13467 | + (match_operand:SI 2 "nonmemory_operand" " O,Ku16,J,r,i,r")))] |
| 13468 | + "" |
| 13469 | + "@ |
| 13470 | + memt\t%0, %p2 |
| 13471 | + eorl\t%0, %2 |
| 13472 | + eorh\t%0, hi(%2) |
| 13473 | + eor\t%0, %2 |
| 13474 | + eorh\t%0, hi(%2)\;eorl\t%0, lo(%2) |
| 13475 | + eor\t%0, %1, %2" |
| 13476 | + |
| 13477 | + [(set_attr "length" "4,4,4,2,8,4") |
| 13478 | + (set_attr "cc" "none,set_z,set_z,set_z,set_z,set_z")]) |
| 13479 | + |
| 13480 | +(define_insn "xordi3" |
| 13481 | + [(set (match_operand:DI 0 "register_operand" "=&r,&r") |
| 13482 | + (xor:DI (match_operand:DI 1 "register_operand" "%0,r") |
| 13483 | + (match_operand:DI 2 "register_operand" "r,r")))] |
| 13484 | + "" |
| 13485 | + "#" |
| 13486 | + [(set_attr "length" "8") |
| 13487 | + (set_attr "cc" "clobber")] |
| 13488 | +) |
| 13489 | + |
| 13490 | +;;============================================================================= |
| 13491 | +;; Three operand predicable insns |
| 13492 | +;;============================================================================= |
| 13493 | + |
| 13494 | +(define_insn "<predicable_insn3><mode>_predicable" |
| 13495 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 13496 | + (predicable_op3:INTM (match_operand:INTM 1 "register_operand" "<predicable_commutative3>r") |
| 13497 | + (match_operand:INTM 2 "register_operand" "r")))] |
| 13498 | + "TARGET_V2_INSNS" |
| 13499 | + "<predicable_insn3>%?\t%0, %1, %2" |
| 13500 | + [(set_attr "length" "4") |
| 13501 | + (set_attr "cc" "cmp_cond_insn") |
| 13502 | + (set_attr "predicable" "yes")] |
| 13503 | +) |
| 13504 | + |
| 13505 | +(define_insn_and_split "<predicable_insn3><mode>_imm_clobber_predicable" |
| 13506 | + [(parallel |
| 13507 | + [(set (match_operand:INTM 0 "register_operand" "=r") |
| 13508 | + (predicable_op3:INTM (match_operand:INTM 1 "register_operand" "<predicable_commutative3>r") |
| 13509 | + (match_operand:INTM 2 "avr32_mov_immediate_operand" "JKs21"))) |
| 13510 | + (clobber (match_operand:INTM 3 "register_operand" "=&r"))])] |
| 13511 | + "TARGET_V2_INSNS" |
| 13512 | + { |
| 13513 | + if ( current_insn_predicate != NULL_RTX ) |
| 13514 | + { |
| 13515 | + if ( avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'K', "Ks08") ) |
| 13516 | + return "%! mov%?\t%3, %2\;<predicable_insn3>%?\t%0, %1, %3"; |
| 13517 | + else if ( avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'K', "Ks21") ) |
| 13518 | + return "%! mov\t%3, %2\;<predicable_insn3>%?\t%0, %1, %3"; |
| 13519 | + else |
| 13520 | + return "%! movh\t%3, hi(%2)\;<predicable_insn3>%?\t%0, %1, %3"; |
| 13521 | + } |
| 13522 | + else |
| 13523 | + { |
| 13524 | + if ( !avr32_cond_imm_clobber_splittable (insn, operands) ) |
| 13525 | + { |
| 13526 | + if ( avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'K', "Ks08") ) |
| 13527 | + return "mov%?\t%3, %2\;<predicable_insn3>%?\t%0, %1, %3"; |
| 13528 | + else if ( avr32_const_ok_for_constraint_p (INTVAL (operands[2]), 'K', "Ks21") ) |
| 13529 | + return "mov\t%3, %2\;<predicable_insn3>%?\t%0, %1, %3"; |
| 13530 | + else |
| 13531 | + return "movh\t%3, hi(%2)\;<predicable_insn3>%?\t%0, %1, %3"; |
| 13532 | + } |
| 13533 | + return "#"; |
| 13534 | + } |
| 13535 | + |
| 13536 | + } |
| 13537 | + ;; If we find out that we could not actually do if-conversion on the block |
| 13538 | + ;; containing this insn we convert it back to normal immediate format |
| 13539 | + ;; to avoid outputing a redundant move insn |
| 13540 | + ;; Do not split until after we have checked if we can make the insn |
| 13541 | + ;; conditional. |
| 13542 | + "(GET_CODE (PATTERN (insn)) != COND_EXEC |
| 13543 | + && cfun->machine->ifcvt_after_reload |
| 13544 | + && avr32_cond_imm_clobber_splittable (insn, operands))" |
| 13545 | + [(set (match_dup 0) |
| 13546 | + (predicable_op3:INTM (match_dup 1) |
| 13547 | + (match_dup 2)))] |
| 13548 | + "" |
| 13549 | + [(set_attr "length" "8") |
| 13550 | + (set_attr "cc" "cmp_cond_insn") |
| 13551 | + (set_attr "predicable" "yes")] |
| 13552 | + ) |
| 13553 | + |
| 13554 | + |
| 13555 | +;;============================================================================= |
| 13556 | +;; Zero extend predicable insns |
| 13557 | +;;============================================================================= |
| 13558 | +(define_insn_and_split "zero_extendhisi_clobber_predicable" |
| 13559 | + [(parallel |
| 13560 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13561 | + (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))) |
| 13562 | + (clobber (match_operand:SI 2 "register_operand" "=&r"))])] |
| 13563 | + "TARGET_V2_INSNS" |
| 13564 | + { |
| 13565 | + if ( current_insn_predicate != NULL_RTX ) |
| 13566 | + { |
| 13567 | + return "%! mov\t%2, 0xffff\;and%?\t%0, %1, %2"; |
| 13568 | + } |
| 13569 | + else |
| 13570 | + { |
| 13571 | + return "#"; |
| 13572 | + } |
| 13573 | + |
| 13574 | + } |
| 13575 | + ;; If we find out that we could not actually do if-conversion on the block |
| 13576 | + ;; containing this insn we convert it back to normal immediate format |
| 13577 | + ;; to avoid outputing a redundant move insn |
| 13578 | + ;; Do not split until after we have checked if we can make the insn |
| 13579 | + ;; conditional. |
| 13580 | + "(GET_CODE (PATTERN (insn)) != COND_EXEC |
| 13581 | + && cfun->machine->ifcvt_after_reload)" |
| 13582 | + [(set (match_dup 0) |
| 13583 | + (zero_extend:SI (match_dup 1)))] |
| 13584 | + "" |
| 13585 | + [(set_attr "length" "8") |
| 13586 | + (set_attr "cc" "cmp_cond_insn") |
| 13587 | + (set_attr "predicable" "yes")] |
| 13588 | + ) |
| 13589 | + |
| 13590 | +(define_insn_and_split "zero_extendqisi_clobber_predicable" |
| 13591 | + [(parallel |
| 13592 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13593 | + (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))) |
| 13594 | + (clobber (match_operand:SI 2 "register_operand" "=&r"))])] |
| 13595 | + "TARGET_V2_INSNS" |
| 13596 | + { |
| 13597 | + if ( current_insn_predicate != NULL_RTX ) |
| 13598 | + { |
| 13599 | + return "%! mov\t%2, 0xff\;and%?\t%0, %1, %2"; |
| 13600 | + } |
| 13601 | + else |
| 13602 | + { |
| 13603 | + return "#"; |
| 13604 | + } |
| 13605 | + |
| 13606 | + } |
| 13607 | + ;; If we find out that we could not actually do if-conversion on the block |
| 13608 | + ;; containing this insn we convert it back to normal immediate format |
| 13609 | + ;; to avoid outputing a redundant move insn |
| 13610 | + ;; Do not split until after we have checked if we can make the insn |
| 13611 | + ;; conditional. |
| 13612 | + "(GET_CODE (PATTERN (insn)) != COND_EXEC |
| 13613 | + && cfun->machine->ifcvt_after_reload)" |
| 13614 | + [(set (match_dup 0) |
| 13615 | + (zero_extend:SI (match_dup 1)))] |
| 13616 | + "" |
| 13617 | + [(set_attr "length" "8") |
| 13618 | + (set_attr "cc" "cmp_cond_insn") |
| 13619 | + (set_attr "predicable" "yes")] |
| 13620 | + ) |
| 13621 | + |
| 13622 | +(define_insn_and_split "zero_extendqihi_clobber_predicable" |
| 13623 | + [(parallel |
| 13624 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 13625 | + (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))) |
| 13626 | + (clobber (match_operand:SI 2 "register_operand" "=&r"))])] |
| 13627 | + "TARGET_V2_INSNS" |
| 13628 | + { |
| 13629 | + if ( current_insn_predicate != NULL_RTX ) |
| 13630 | + { |
| 13631 | + return "%! mov\t%2, 0xff\;and%?\t%0, %1, %2"; |
| 13632 | + } |
| 13633 | + else |
| 13634 | + { |
| 13635 | + return "#"; |
| 13636 | + } |
| 13637 | + |
| 13638 | + } |
| 13639 | + ;; If we find out that we could not actually do if-conversion on the block |
| 13640 | + ;; containing this insn we convert it back to normal immediate format |
| 13641 | + ;; to avoid outputing a redundant move insn |
| 13642 | + ;; Do not split until after we have checked if we can make the insn |
| 13643 | + ;; conditional. |
| 13644 | + "(GET_CODE (PATTERN (insn)) != COND_EXEC |
| 13645 | + && cfun->machine->ifcvt_after_reload)" |
| 13646 | + [(set (match_dup 0) |
| 13647 | + (zero_extend:HI (match_dup 1)))] |
| 13648 | + "" |
| 13649 | + [(set_attr "length" "8") |
| 13650 | + (set_attr "cc" "cmp_cond_insn") |
| 13651 | + (set_attr "predicable" "yes")] |
| 13652 | + ) |
| 13653 | +;;============================================================================= |
| 13654 | +;; divmod |
| 13655 | +;;----------------------------------------------------------------------------- |
| 13656 | +;; Signed division that produces both a quotient and a remainder. |
| 13657 | +;;============================================================================= |
| 13658 | + |
| 13659 | +(define_expand "divmodsi4" |
| 13660 | + [(parallel [ |
| 13661 | + (parallel [ |
| 13662 | + (set (match_operand:SI 0 "register_operand" "=r") |
| 13663 | + (div:SI (match_operand:SI 1 "register_operand" "r") |
| 13664 | + (match_operand:SI 2 "register_operand" "r"))) |
| 13665 | + (set (match_operand:SI 3 "register_operand" "=r") |
| 13666 | + (mod:SI (match_dup 1) |
| 13667 | + (match_dup 2)))]) |
| 13668 | + (use (match_dup 4))])] |
| 13669 | + "" |
| 13670 | + { |
| 13671 | + if (can_create_pseudo_p ()) { |
| 13672 | + operands[4] = gen_reg_rtx (DImode); |
| 13673 | + emit_insn(gen_divmodsi4_internal(operands[4],operands[1],operands[2])); |
| 13674 | + emit_move_insn(operands[0], gen_rtx_SUBREG( SImode, operands[4], 4)); |
| 13675 | + emit_move_insn(operands[3], gen_rtx_SUBREG( SImode, operands[4], 0)); |
| 13676 | + DONE; |
| 13677 | + } else { |
| 13678 | + FAIL; |
| 13679 | + } |
| 13680 | + }) |
| 13681 | + |
| 13682 | + |
| 13683 | +(define_insn "divmodsi4_internal" |
| 13684 | + [(set (match_operand:DI 0 "register_operand" "=r") |
| 13685 | + (unspec:DI [(match_operand:SI 1 "register_operand" "r") |
| 13686 | + (match_operand:SI 2 "register_operand" "r")] |
| 13687 | + UNSPEC_DIVMODSI4_INTERNAL))] |
| 13688 | + "" |
| 13689 | + "divs %0, %1, %2" |
| 13690 | + [(set_attr "type" "div") |
| 13691 | + (set_attr "cc" "none")]) |
| 13692 | + |
| 13693 | + |
| 13694 | +;;============================================================================= |
| 13695 | +;; udivmod |
| 13696 | +;;----------------------------------------------------------------------------- |
| 13697 | +;; Unsigned division that produces both a quotient and a remainder. |
| 13698 | +;;============================================================================= |
| 13699 | +(define_expand "udivmodsi4" |
| 13700 | + [(parallel [ |
| 13701 | + (parallel [ |
| 13702 | + (set (match_operand:SI 0 "register_operand" "=r") |
| 13703 | + (udiv:SI (match_operand:SI 1 "register_operand" "r") |
| 13704 | + (match_operand:SI 2 "register_operand" "r"))) |
| 13705 | + (set (match_operand:SI 3 "register_operand" "=r") |
| 13706 | + (umod:SI (match_dup 1) |
| 13707 | + (match_dup 2)))]) |
| 13708 | + (use (match_dup 4))])] |
| 13709 | + "" |
| 13710 | + { |
| 13711 | + if (can_create_pseudo_p ()) { |
| 13712 | + operands[4] = gen_reg_rtx (DImode); |
| 13713 | + |
| 13714 | + emit_insn(gen_udivmodsi4_internal(operands[4],operands[1],operands[2])); |
| 13715 | + emit_move_insn(operands[0], gen_rtx_SUBREG( SImode, operands[4], 4)); |
| 13716 | + emit_move_insn(operands[3], gen_rtx_SUBREG( SImode, operands[4], 0)); |
| 13717 | + |
| 13718 | + DONE; |
| 13719 | + } else { |
| 13720 | + FAIL; |
| 13721 | + } |
| 13722 | + }) |
| 13723 | + |
| 13724 | +(define_insn "udivmodsi4_internal" |
| 13725 | + [(set (match_operand:DI 0 "register_operand" "=r") |
| 13726 | + (unspec:DI [(match_operand:SI 1 "register_operand" "r") |
| 13727 | + (match_operand:SI 2 "register_operand" "r")] |
| 13728 | + UNSPEC_UDIVMODSI4_INTERNAL))] |
| 13729 | + "" |
| 13730 | + "divu %0, %1, %2" |
| 13731 | + [(set_attr "type" "div") |
| 13732 | + (set_attr "cc" "none")]) |
| 13733 | + |
| 13734 | + |
| 13735 | +;;============================================================================= |
| 13736 | +;; Arithmetic-shift left |
| 13737 | +;;----------------------------------------------------------------------------- |
| 13738 | +;; Arithmetic-shift reg0 left by reg2 or immediate value. |
| 13739 | +;;============================================================================= |
| 13740 | + |
| 13741 | +(define_insn "ashlsi3" |
| 13742 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
| 13743 | + (ashift:SI (match_operand:SI 1 "register_operand" "r,0,r") |
| 13744 | + (match_operand:SI 2 "register_const_int_operand" "r,Ku05,Ku05")))] |
| 13745 | + "" |
| 13746 | + "@ |
| 13747 | + lsl %0, %1, %2 |
| 13748 | + lsl %0, %2 |
| 13749 | + lsl %0, %1, %2" |
| 13750 | + [(set_attr "length" "4,2,4") |
| 13751 | + (set_attr "cc" "set_ncz")]) |
| 13752 | + |
| 13753 | +;;============================================================================= |
| 13754 | +;; Arithmetic-shift right |
| 13755 | +;;----------------------------------------------------------------------------- |
| 13756 | +;; Arithmetic-shift reg0 right by an immediate value. |
| 13757 | +;;============================================================================= |
| 13758 | + |
| 13759 | +(define_insn "ashrsi3" |
| 13760 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
| 13761 | + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,0,r") |
| 13762 | + (match_operand:SI 2 "register_const_int_operand" "r,Ku05,Ku05")))] |
| 13763 | + "" |
| 13764 | + "@ |
| 13765 | + asr %0, %1, %2 |
| 13766 | + asr %0, %2 |
| 13767 | + asr %0, %1, %2" |
| 13768 | + [(set_attr "length" "4,2,4") |
| 13769 | + (set_attr "cc" "set_ncz")]) |
| 13770 | + |
| 13771 | +;;============================================================================= |
| 13772 | +;; Logical shift right |
| 13773 | +;;----------------------------------------------------------------------------- |
| 13774 | +;; Logical shift reg0 right by an immediate value. |
| 13775 | +;;============================================================================= |
| 13776 | + |
| 13777 | +(define_insn "lshrsi3" |
| 13778 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
| 13779 | + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,0,r") |
| 13780 | + (match_operand:SI 2 "register_const_int_operand" "r,Ku05,Ku05")))] |
| 13781 | + "" |
| 13782 | + "@ |
| 13783 | + lsr %0, %1, %2 |
| 13784 | + lsr %0, %2 |
| 13785 | + lsr %0, %1, %2" |
| 13786 | + [(set_attr "length" "4,2,4") |
| 13787 | + (set_attr "cc" "set_ncz")]) |
| 13788 | + |
| 13789 | + |
| 13790 | +;;============================================================================= |
| 13791 | +;; neg |
| 13792 | +;;----------------------------------------------------------------------------- |
| 13793 | +;; Negate operand 1 and store the result in operand 0. |
| 13794 | +;;============================================================================= |
| 13795 | +(define_insn "negsi2" |
| 13796 | + [(set (match_operand:SI 0 "register_operand" "=r,r") |
| 13797 | + (neg:SI (match_operand:SI 1 "register_operand" "0,r")))] |
| 13798 | + "" |
| 13799 | + "@ |
| 13800 | + neg\t%0 |
| 13801 | + rsub\t%0, %1, 0" |
| 13802 | + [(set_attr "length" "2,4") |
| 13803 | + (set_attr "cc" "set_vncz")]) |
| 13804 | + |
| 13805 | +(define_insn "negsi2_predicable" |
| 13806 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 13807 | + (neg:SI (match_dup 0)))] |
| 13808 | + "TARGET_V2_INSNS" |
| 13809 | + "rsub%?\t%0, 0" |
| 13810 | + [(set_attr "length" "4") |
| 13811 | + (set_attr "cc" "cmp_cond_insn") |
| 13812 | + (set_attr "predicable" "yes")]) |
| 13813 | + |
| 13814 | +;;============================================================================= |
| 13815 | +;; abs |
| 13816 | +;;----------------------------------------------------------------------------- |
| 13817 | +;; Store the absolute value of operand 1 into operand 0. |
| 13818 | +;;============================================================================= |
| 13819 | +(define_insn "abssi2" |
| 13820 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 13821 | + (abs:SI (match_operand:SI 1 "register_operand" "0")))] |
| 13822 | + "" |
| 13823 | + "abs\t%0" |
| 13824 | + [(set_attr "length" "2") |
| 13825 | + (set_attr "cc" "set_z")]) |
| 13826 | + |
| 13827 | + |
| 13828 | +;;============================================================================= |
| 13829 | +;; one_cmpl |
| 13830 | +;;----------------------------------------------------------------------------- |
| 13831 | +;; Store the bitwise-complement of operand 1 into operand 0. |
| 13832 | +;;============================================================================= |
| 13833 | + |
| 13834 | +(define_insn "one_cmplsi2" |
| 13835 | + [(set (match_operand:SI 0 "register_operand" "=r,r") |
| 13836 | + (not:SI (match_operand:SI 1 "register_operand" "0,r")))] |
| 13837 | + "" |
| 13838 | + "@ |
| 13839 | + com\t%0 |
| 13840 | + rsub\t%0, %1, -1" |
| 13841 | + [(set_attr "length" "2,4") |
| 13842 | + (set_attr "cc" "set_z")]) |
| 13843 | + |
| 13844 | + |
| 13845 | +(define_insn "one_cmplsi2_predicable" |
| 13846 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 13847 | + (not:SI (match_dup 0)))] |
| 13848 | + "TARGET_V2_INSNS" |
| 13849 | + "rsub%?\t%0, -1" |
| 13850 | + [(set_attr "length" "4") |
| 13851 | + (set_attr "cc" "cmp_cond_insn") |
| 13852 | + (set_attr "predicable" "yes")]) |
| 13853 | + |
| 13854 | + |
| 13855 | +;;============================================================================= |
| 13856 | +;; Bit load |
| 13857 | +;;----------------------------------------------------------------------------- |
| 13858 | +;; Load a bit into Z and C flags |
| 13859 | +;;============================================================================= |
| 13860 | +(define_insn "bldsi" |
| 13861 | + [(set (cc0) |
| 13862 | + (and:SI (match_operand:SI 0 "register_operand" "r") |
| 13863 | + (match_operand:SI 1 "one_bit_set_operand" "i")))] |
| 13864 | + "" |
| 13865 | + "bld\t%0, %p1" |
| 13866 | + [(set_attr "length" "4") |
| 13867 | + (set_attr "cc" "bld")] |
| 13868 | + ) |
| 13869 | + |
| 13870 | + |
| 13871 | +;;============================================================================= |
| 13872 | +;; Compare |
| 13873 | +;;----------------------------------------------------------------------------- |
| 13874 | +;; Compare reg0 with reg1 or an immediate value. |
| 13875 | +;;============================================================================= |
| 13876 | + |
| 13877 | +(define_expand "cmp<mode>" |
| 13878 | + [(set (cc0) |
| 13879 | + (compare:CMP |
| 13880 | + (match_operand:CMP 0 "register_operand" "") |
| 13881 | + (match_operand:CMP 1 "<CMP:cmp_predicate>" "")))] |
| 13882 | + "" |
| 13883 | + "{ |
| 13884 | + avr32_compare_op0 = operands[0]; |
| 13885 | + avr32_compare_op1 = operands[1]; |
| 13886 | + }" |
| 13887 | +) |
| 13888 | + |
| 13889 | +(define_insn "cmp<mode>_internal" |
| 13890 | + [(set (cc0) |
| 13891 | + (compare:CMP |
| 13892 | + (match_operand:CMP 0 "register_operand" "r") |
| 13893 | + (match_operand:CMP 1 "<CMP:cmp_predicate>" "<CMP:cmp_constraint>")))] |
| 13894 | + "" |
| 13895 | + { |
| 13896 | +switch(GET_MODE(operands[0])) |
| 13897 | + { |
| 13898 | + case QImode: |
| 13899 | + avr32_branch_type = CMP_QI; |
| 13900 | + break; |
| 13901 | + case HImode: |
| 13902 | + avr32_branch_type = CMP_HI; |
| 13903 | + break; |
| 13904 | + case SImode: |
| 13905 | + avr32_branch_type = CMP_SI; |
| 13906 | + break; |
| 13907 | + case DImode: |
| 13908 | + avr32_branch_type = CMP_DI; |
| 13909 | + break; |
| 13910 | + default: |
| 13911 | + abort(); |
| 13912 | + } |
| 13913 | + /* Check if the next insn already will output a compare. */ |
| 13914 | + if (!next_insn_emits_cmp (insn)) |
| 13915 | + set_next_insn_cond(insn, |
| 13916 | + avr32_output_cmp(get_next_insn_cond(insn), GET_MODE (operands[0]), operands[0], operands[1])); |
| 13917 | + return ""; |
| 13918 | + } |
| 13919 | + [(set_attr "length" "4") |
| 13920 | + (set_attr "cc" "compare")]) |
| 13921 | + |
| 13922 | +(define_expand "cmpsf" |
| 13923 | + [(set (cc0) |
| 13924 | + (compare:SF |
| 13925 | + (match_operand:SF 0 "general_operand" "") |
| 13926 | + (match_operand:SF 1 "general_operand" "")))] |
| 13927 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 13928 | + "{ |
| 13929 | + if ( !REG_P(operands[0]) ) |
| 13930 | + operands[0] = force_reg(SFmode, operands[0]); |
| 13931 | + |
| 13932 | + if ( !REG_P(operands[1]) ) |
| 13933 | + operands[1] = force_reg(SFmode, operands[1]); |
| 13934 | + |
| 13935 | + avr32_compare_op0 = operands[0]; |
| 13936 | + avr32_compare_op1 = operands[1]; |
| 13937 | + emit_insn(gen_cmpsf_internal_uc3fp(operands[0], operands[1])); |
| 13938 | + DONE; |
| 13939 | + }" |
| 13940 | +) |
| 13941 | + |
| 13942 | +;;;============================================================================= |
| 13943 | +;; Test if zero |
| 13944 | +;;----------------------------------------------------------------------------- |
| 13945 | +;; Compare reg against zero and set the condition codes. |
| 13946 | +;;============================================================================= |
| 13947 | + |
| 13948 | + |
| 13949 | +(define_expand "tstsi" |
| 13950 | + [(set (cc0) |
| 13951 | + (match_operand:SI 0 "register_operand" ""))] |
| 13952 | + "" |
| 13953 | + { |
| 13954 | + avr32_compare_op0 = operands[0]; |
| 13955 | + avr32_compare_op1 = const0_rtx; |
| 13956 | + } |
| 13957 | +) |
| 13958 | + |
| 13959 | +(define_insn "tstsi_internal" |
| 13960 | + [(set (cc0) |
| 13961 | + (match_operand:SI 0 "register_operand" "r"))] |
| 13962 | + "" |
| 13963 | + { |
| 13964 | + /* Check if the next insn already will output a compare. */ |
| 13965 | + if (!next_insn_emits_cmp (insn)) |
| 13966 | + set_next_insn_cond(insn, |
| 13967 | + avr32_output_cmp(get_next_insn_cond(insn), SImode, operands[0], const0_rtx)); |
| 13968 | + |
| 13969 | + return ""; |
| 13970 | + } |
| 13971 | + [(set_attr "length" "2") |
| 13972 | + (set_attr "cc" "compare")]) |
| 13973 | + |
| 13974 | + |
| 13975 | +(define_expand "tstdi" |
| 13976 | + [(set (cc0) |
| 13977 | + (match_operand:DI 0 "register_operand" ""))] |
| 13978 | + "" |
| 13979 | + { |
| 13980 | + avr32_compare_op0 = operands[0]; |
| 13981 | + avr32_compare_op1 = const0_rtx; |
| 13982 | + } |
| 13983 | +) |
| 13984 | + |
| 13985 | +(define_insn "tstdi_internal" |
| 13986 | + [(set (cc0) |
| 13987 | + (match_operand:DI 0 "register_operand" "r"))] |
| 13988 | + "" |
| 13989 | + { |
| 13990 | + /* Check if the next insn already will output a compare. */ |
| 13991 | + if (!next_insn_emits_cmp (insn)) |
| 13992 | + set_next_insn_cond(insn, |
| 13993 | + avr32_output_cmp(get_next_insn_cond(insn), DImode, operands[0], const0_rtx)); |
| 13994 | + return ""; |
| 13995 | + } |
| 13996 | + [(set_attr "length" "4") |
| 13997 | + (set_attr "type" "alu2") |
| 13998 | + (set_attr "cc" "compare")]) |
| 13999 | + |
| 14000 | + |
| 14001 | + |
| 14002 | +;;============================================================================= |
| 14003 | +;; Convert operands |
| 14004 | +;;----------------------------------------------------------------------------- |
| 14005 | +;; |
| 14006 | +;;============================================================================= |
| 14007 | +(define_insn "truncdisi2" |
| 14008 | + [(set (match_operand:SI 0 "general_operand" "") |
| 14009 | + (truncate:SI (match_operand:DI 1 "general_operand" "")))] |
| 14010 | + "" |
| 14011 | + "truncdisi2") |
| 14012 | + |
| 14013 | +;;============================================================================= |
| 14014 | +;; Extend |
| 14015 | +;;----------------------------------------------------------------------------- |
| 14016 | +;; |
| 14017 | +;;============================================================================= |
| 14018 | + |
| 14019 | + |
| 14020 | +(define_insn "extendhisi2" |
| 14021 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") |
| 14022 | + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r,<RKu00>,m")))] |
| 14023 | + "" |
| 14024 | + { |
| 14025 | + switch ( which_alternative ){ |
| 14026 | + case 0: |
| 14027 | + return "casts.h\t%0"; |
| 14028 | + case 1: |
| 14029 | + return "bfexts\t%0, %1, 0, 16"; |
| 14030 | + case 2: |
| 14031 | + case 3: |
| 14032 | + return "ld.sh\t%0, %1"; |
| 14033 | + default: |
| 14034 | + abort(); |
| 14035 | + } |
| 14036 | + } |
| 14037 | + [(set_attr "length" "2,4,2,4") |
| 14038 | + (set_attr "cc" "set_ncz,set_ncz,none,none") |
| 14039 | + (set_attr "type" "alu,alu,load_rm,load_rm")]) |
| 14040 | + |
| 14041 | +(define_insn "extendqisi2" |
| 14042 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") |
| 14043 | + (sign_extend:SI (match_operand:QI 1 "extendqi_operand" "0,r,RKu00,m")))] |
| 14044 | + "" |
| 14045 | + { |
| 14046 | + switch ( which_alternative ){ |
| 14047 | + case 0: |
| 14048 | + return "casts.b\t%0"; |
| 14049 | + case 1: |
| 14050 | + return "bfexts\t%0, %1, 0, 8"; |
| 14051 | + case 2: |
| 14052 | + case 3: |
| 14053 | + return "ld.sb\t%0, %1"; |
| 14054 | + default: |
| 14055 | + abort(); |
| 14056 | + } |
| 14057 | + } |
| 14058 | + [(set_attr "length" "2,4,2,4") |
| 14059 | + (set_attr "cc" "set_ncz,set_ncz,none,none") |
| 14060 | + (set_attr "type" "alu,alu,load_rm,load_rm")]) |
| 14061 | + |
| 14062 | +(define_insn "extendqihi2" |
| 14063 | + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") |
| 14064 | + (sign_extend:HI (match_operand:QI 1 "extendqi_operand" "0,r,RKu00,m")))] |
| 14065 | + "" |
| 14066 | + { |
| 14067 | + switch ( which_alternative ){ |
| 14068 | + case 0: |
| 14069 | + return "casts.b\t%0"; |
| 14070 | + case 1: |
| 14071 | + return "bfexts\t%0, %1, 0, 8"; |
| 14072 | + case 2: |
| 14073 | + case 3: |
| 14074 | + return "ld.sb\t%0, %1"; |
| 14075 | + default: |
| 14076 | + abort(); |
| 14077 | + } |
| 14078 | + } |
| 14079 | + [(set_attr "length" "2,4,2,4") |
| 14080 | + (set_attr "cc" "set_ncz,set_ncz,none,none") |
| 14081 | + (set_attr "type" "alu,alu,load_rm,load_rm")]) |
| 14082 | + |
| 14083 | + |
| 14084 | +;;============================================================================= |
| 14085 | +;; Zero-extend |
| 14086 | +;;----------------------------------------------------------------------------- |
| 14087 | +;; |
| 14088 | +;;============================================================================= |
| 14089 | + |
| 14090 | +(define_insn "zero_extendhisi2" |
| 14091 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") |
| 14092 | + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r,<RKu00>,m")))] |
| 14093 | + "" |
| 14094 | + { |
| 14095 | + switch ( which_alternative ){ |
| 14096 | + case 0: |
| 14097 | + return "castu.h\t%0"; |
| 14098 | + case 1: |
| 14099 | + return "bfextu\t%0, %1, 0, 16"; |
| 14100 | + case 2: |
| 14101 | + case 3: |
| 14102 | + return "ld.uh\t%0, %1"; |
| 14103 | + default: |
| 14104 | + abort(); |
| 14105 | + } |
| 14106 | + } |
| 14107 | + |
| 14108 | + [(set_attr "length" "2,4,2,4") |
| 14109 | + (set_attr "cc" "set_ncz,set_ncz,none,none") |
| 14110 | + (set_attr "type" "alu,alu,load_rm,load_rm")]) |
| 14111 | + |
| 14112 | +(define_insn "zero_extendqisi2" |
| 14113 | + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") |
| 14114 | + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,r,<RKu00>,m")))] |
| 14115 | + "" |
| 14116 | + { |
| 14117 | + switch ( which_alternative ){ |
| 14118 | + case 0: |
| 14119 | + return "castu.b\t%0"; |
| 14120 | + case 1: |
| 14121 | + return "bfextu\t%0, %1, 0, 8"; |
| 14122 | + case 2: |
| 14123 | + case 3: |
| 14124 | + return "ld.ub\t%0, %1"; |
| 14125 | + default: |
| 14126 | + abort(); |
| 14127 | + } |
| 14128 | + } |
| 14129 | + [(set_attr "length" "2,4,2,4") |
| 14130 | + (set_attr "cc" "set_ncz, set_ncz, none, none") |
| 14131 | + (set_attr "type" "alu, alu, load_rm, load_rm")]) |
| 14132 | + |
| 14133 | +(define_insn "zero_extendqihi2" |
| 14134 | + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") |
| 14135 | + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,r,<RKu00>,m")))] |
| 14136 | + "" |
| 14137 | + { |
| 14138 | + switch ( which_alternative ){ |
| 14139 | + case 0: |
| 14140 | + return "castu.b\t%0"; |
| 14141 | + case 1: |
| 14142 | + return "bfextu\t%0, %1, 0, 8"; |
| 14143 | + case 2: |
| 14144 | + case 3: |
| 14145 | + return "ld.ub\t%0, %1"; |
| 14146 | + default: |
| 14147 | + abort(); |
| 14148 | + } |
| 14149 | + } |
| 14150 | + [(set_attr "length" "2,4,2,4") |
| 14151 | + (set_attr "cc" "set_ncz, set_ncz, none, none") |
| 14152 | + (set_attr "type" "alu, alu, load_rm, load_rm")]) |
| 14153 | + |
| 14154 | + |
| 14155 | +;;============================================================================= |
| 14156 | +;; Conditional load and extend insns |
| 14157 | +;;============================================================================= |
| 14158 | +(define_insn "ldsi<mode>_predicable_se" |
| 14159 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 14160 | + (sign_extend:SI |
| 14161 | + (match_operand:INTM 1 "memory_operand" "<INTM:pred_mem_constraint>")))] |
| 14162 | + "TARGET_V2_INSNS" |
| 14163 | + "ld<INTM:load_postfix_s>%?\t%0, %1" |
| 14164 | + [(set_attr "length" "4") |
| 14165 | + (set_attr "cc" "cmp_cond_insn") |
| 14166 | + (set_attr "type" "load") |
| 14167 | + (set_attr "predicable" "yes")] |
| 14168 | +) |
| 14169 | + |
| 14170 | +(define_insn "ldsi<mode>_predicable_ze" |
| 14171 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 14172 | + (zero_extend:SI |
| 14173 | + (match_operand:INTM 1 "memory_operand" "<INTM:pred_mem_constraint>")))] |
| 14174 | + "TARGET_V2_INSNS" |
| 14175 | + "ld<INTM:load_postfix_u>%?\t%0, %1" |
| 14176 | + [(set_attr "length" "4") |
| 14177 | + (set_attr "cc" "cmp_cond_insn") |
| 14178 | + (set_attr "type" "load") |
| 14179 | + (set_attr "predicable" "yes")] |
| 14180 | +) |
| 14181 | + |
| 14182 | +(define_insn "ldhi_predicable_ze" |
| 14183 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 14184 | + (zero_extend:HI |
| 14185 | + (match_operand:QI 1 "memory_operand" "RKs10")))] |
| 14186 | + "TARGET_V2_INSNS" |
| 14187 | + "ld.ub%?\t%0, %1" |
| 14188 | + [(set_attr "length" "4") |
| 14189 | + (set_attr "cc" "cmp_cond_insn") |
| 14190 | + (set_attr "type" "load") |
| 14191 | + (set_attr "predicable" "yes")] |
| 14192 | +) |
| 14193 | + |
| 14194 | +(define_insn "ldhi_predicable_se" |
| 14195 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 14196 | + (sign_extend:HI |
| 14197 | + (match_operand:QI 1 "memory_operand" "RKs10")))] |
| 14198 | + "TARGET_V2_INSNS" |
| 14199 | + "ld.sb%?\t%0, %1" |
| 14200 | + [(set_attr "length" "4") |
| 14201 | + (set_attr "cc" "cmp_cond_insn") |
| 14202 | + (set_attr "type" "load") |
| 14203 | + (set_attr "predicable" "yes")] |
| 14204 | +) |
| 14205 | + |
| 14206 | +;;============================================================================= |
| 14207 | +;; Conditional set register |
| 14208 | +;; sr{cond4} rd |
| 14209 | +;;----------------------------------------------------------------------------- |
| 14210 | + |
| 14211 | +;;Because of the same issue as with conditional moves and adds we must |
| 14212 | +;;not separate the compare instrcution from the scc instruction as |
| 14213 | +;;they might be sheduled "badly". |
| 14214 | + |
| 14215 | +(define_expand "s<code>" |
| 14216 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 14217 | + (any_cond:SI (cc0) |
| 14218 | + (const_int 0)))] |
| 14219 | +"" |
| 14220 | +{ |
| 14221 | + if(TARGET_HARD_FLOAT && TARGET_ARCH_FPU) |
| 14222 | + FAIL; |
| 14223 | +}) |
| 14224 | + |
| 14225 | +(define_insn "*s<code>" |
| 14226 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 14227 | + (any_cond:SI (cc0) |
| 14228 | + (const_int 0)))] |
| 14229 | + "" |
| 14230 | +{ |
| 14231 | + return "sr<cond>\t%0"; |
| 14232 | +} |
| 14233 | +[(set_attr "length" "2") |
| 14234 | +(set_attr "cc" "none")]) |
| 14235 | + |
| 14236 | +(define_insn "seq" |
| 14237 | +[(set (match_operand:SI 0 "register_operand" "=r") |
| 14238 | +(eq:SI (cc0) |
| 14239 | + (const_int 0)))] |
| 14240 | + "" |
| 14241 | +"sreq\t%0" |
| 14242 | +[(set_attr "length" "2") |
| 14243 | +(set_attr "cc" "none")]) |
| 14244 | + |
| 14245 | +(define_insn "sne" |
| 14246 | +[(set (match_operand:SI 0 "register_operand" "=r") |
| 14247 | +(ne:SI (cc0) |
| 14248 | + (const_int 0)))] |
| 14249 | + "" |
| 14250 | +"srne\t%0" |
| 14251 | + [(set_attr "length" "2") |
| 14252 | + (set_attr "cc" "none")]) |
| 14253 | + |
| 14254 | +(define_insn "smi" |
| 14255 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 14256 | + (unspec:SI [(cc0) |
| 14257 | + (const_int 0)] UNSPEC_COND_MI))] |
| 14258 | + "" |
| 14259 | + "srmi\t%0" |
| 14260 | + [(set_attr "length" "2") |
| 14261 | + (set_attr "cc" "none")]) |
| 14262 | + |
| 14263 | +(define_insn "spl" |
| 14264 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 14265 | + (unspec:SI [(cc0) |
| 14266 | + (const_int 0)] UNSPEC_COND_PL))] |
| 14267 | + "" |
| 14268 | + "srpl\t%0" |
| 14269 | + [(set_attr "length" "2") |
| 14270 | + (set_attr "cc" "none")]) |
| 14271 | + |
| 14272 | + |
| 14273 | +;;============================================================================= |
| 14274 | +;; Conditional branch |
| 14275 | +;;----------------------------------------------------------------------------- |
| 14276 | +;; Branch to label if the specified condition codes are set. |
| 14277 | +;;============================================================================= |
| 14278 | +; branch if negative |
| 14279 | +(define_insn "bmi" |
| 14280 | + [(set (pc) |
| 14281 | + (if_then_else (unspec:CC [(cc0) (const_int 0)] UNSPEC_COND_MI) |
| 14282 | + (label_ref (match_operand 0 "" "")) |
| 14283 | + (pc)))] |
| 14284 | + "" |
| 14285 | + "brmi %0" |
| 14286 | + [(set_attr "type" "branch") |
| 14287 | + (set (attr "length") |
| 14288 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14289 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14290 | + (const_int 2)] ; use compact branch |
| 14291 | + (const_int 4))) ; use extended branch |
| 14292 | + (set_attr "cc" "none")]) |
| 14293 | + |
| 14294 | +(define_insn "*bmi-reverse" |
| 14295 | + [(set (pc) |
| 14296 | + (if_then_else (unspec:CC [(cc0) (const_int 0)] UNSPEC_COND_MI) |
| 14297 | + (pc) |
| 14298 | + (label_ref (match_operand 0 "" ""))))] |
| 14299 | + "" |
| 14300 | + "brpl %0" |
| 14301 | + [(set_attr "type" "branch") |
| 14302 | + (set (attr "length") |
| 14303 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14304 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14305 | + (const_int 2)] ; use compact branch |
| 14306 | + (const_int 4))) ; use extended branch |
| 14307 | + (set_attr "cc" "none")]) |
| 14308 | + |
| 14309 | +; branch if positive |
| 14310 | +(define_insn "bpl" |
| 14311 | + [(set (pc) |
| 14312 | + (if_then_else (unspec:CC [(cc0) (const_int 0)] UNSPEC_COND_PL) |
| 14313 | + (label_ref (match_operand 0 "" "")) |
| 14314 | + (pc)))] |
| 14315 | + "" |
| 14316 | + "brpl %0" |
| 14317 | + [(set_attr "type" "branch") |
| 14318 | + (set (attr "length") |
| 14319 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14320 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14321 | + (const_int 2)] ; use compact branch |
| 14322 | + (const_int 4))) ; use extended branch |
| 14323 | + (set_attr "cc" "none")]) |
| 14324 | + |
| 14325 | +(define_insn "*bpl-reverse" |
| 14326 | + [(set (pc) |
| 14327 | + (if_then_else (unspec:CC [(cc0) (const_int 0)] UNSPEC_COND_PL) |
| 14328 | + (pc) |
| 14329 | + (label_ref (match_operand 0 "" ""))))] |
| 14330 | + "" |
| 14331 | + "brmi %0" |
| 14332 | + [(set_attr "type" "branch") |
| 14333 | + (set (attr "length") |
| 14334 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14335 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14336 | + (const_int 2)] ; use compact branch |
| 14337 | + (const_int 4))) ; use extended branch |
| 14338 | + (set_attr "cc" "none")]) |
| 14339 | + |
| 14340 | +; branch if equal |
| 14341 | +(define_insn "b<code>" |
| 14342 | + [(set (pc) |
| 14343 | + (if_then_else (any_cond_b:CC (cc0) |
| 14344 | + (const_int 0)) |
| 14345 | + (label_ref (match_operand 0 "" "")) |
| 14346 | + (pc)))] |
| 14347 | + "" |
| 14348 | + { |
| 14349 | + if (TARGET_HARD_FLOAT && TARGET_ARCH_FPU && (avr32_branch_type == CMP_SF)) |
| 14350 | + return get_attr_length(insn) == 6 ? "brvs .+6\;br<cond> %0" : "brvs .+8\;br<cond> %0"; |
| 14351 | + else |
| 14352 | + return "br<cond> %0"; |
| 14353 | + } |
| 14354 | + [(set_attr "type" "branch") |
| 14355 | + (set (attr "length") |
| 14356 | + (if_then_else (eq (const_int 1)(symbol_ref "TARGET_HARD_FLOAT && TARGET_ARCH_FPU")) |
| 14357 | + (if_then_else |
| 14358 | + (and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14359 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14360 | + (const_int 6) |
| 14361 | + (const_int 8)) |
| 14362 | + (if_then_else |
| 14363 | + (and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14364 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14365 | + (const_int 2) |
| 14366 | + (const_int 4)))) |
| 14367 | + (set_attr "cc" "none")]) |
| 14368 | + |
| 14369 | +(define_insn "beq" |
| 14370 | + [(set (pc) |
| 14371 | + (if_then_else (eq:CC (cc0) |
| 14372 | + (const_int 0)) |
| 14373 | + (label_ref (match_operand 0 "" "")) |
| 14374 | + (pc)))] |
| 14375 | + "" |
| 14376 | + "breq %0"; |
| 14377 | + [(set_attr "type" "branch") |
| 14378 | + (set (attr "length") |
| 14379 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14380 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14381 | + (const_int 2)] ; use compact branch |
| 14382 | + (const_int 4))) ; use extended branch |
| 14383 | + (set_attr "cc" "none")]) |
| 14384 | + |
| 14385 | +(define_insn "bne" |
| 14386 | + [(set (pc) |
| 14387 | + (if_then_else (ne:CC (cc0) |
| 14388 | + (const_int 0)) |
| 14389 | + (label_ref (match_operand 0 "" "")) |
| 14390 | + (pc)))] |
| 14391 | + "" |
| 14392 | + "brne %0"; |
| 14393 | + [(set_attr "type" "branch") |
| 14394 | + (set (attr "length") |
| 14395 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14396 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14397 | + (const_int 2)] ; use compact branch |
| 14398 | + (const_int 4))) ; use extended branch |
| 14399 | + (set_attr "cc" "none")]) |
| 14400 | + |
| 14401 | +(define_insn "b<code>" |
| 14402 | + [(set (pc) |
| 14403 | + (if_then_else (any_cond4:CC (cc0) |
| 14404 | + (const_int 0)) |
| 14405 | + (label_ref (match_operand 0 "" "")) |
| 14406 | + (pc)))] |
| 14407 | + "" |
| 14408 | + { |
| 14409 | + if(TARGET_HARD_FLOAT && TARGET_ARCH_FPU && (avr32_branch_type == CMP_SF)) |
| 14410 | + return "brvs .+8\;br<cond> %l0"; |
| 14411 | + else |
| 14412 | + return "br<cond> %l0"; |
| 14413 | + } |
| 14414 | + [(set_attr "type" "branch") |
| 14415 | + (set (attr "length") |
| 14416 | + (cond [(eq (const_int 1)(symbol_ref "TARGET_HARD_FLOAT && TARGET_ARCH_FPU")) |
| 14417 | + (const_int 8)] |
| 14418 | + (const_int 4))) |
| 14419 | + (set_attr "cc" "none")]) |
| 14420 | + |
| 14421 | +(define_insn "*b<code>-reverse" |
| 14422 | + [(set (pc) |
| 14423 | + (if_then_else (any_cond_b:CC (cc0) |
| 14424 | + (const_int 0)) |
| 14425 | + (pc) |
| 14426 | + (label_ref (match_operand 0 "" ""))))] |
| 14427 | + "" |
| 14428 | + { |
| 14429 | + if (TARGET_HARD_FLOAT && TARGET_ARCH_FPU && (avr32_branch_type == CMP_SF)) |
| 14430 | + return "brvs %0\;br<invcond> %0"; |
| 14431 | + else |
| 14432 | + return "br<invcond> %0"; |
| 14433 | + } |
| 14434 | + [(set_attr "type" "branch") |
| 14435 | + (set (attr "length") |
| 14436 | + (if_then_else (eq (const_int 1)(symbol_ref "TARGET_HARD_FLOAT && TARGET_ARCH_FPU")) |
| 14437 | + (if_then_else |
| 14438 | + (and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14439 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14440 | + (const_int 6) |
| 14441 | + (const_int 8)) |
| 14442 | + (if_then_else |
| 14443 | + (and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14444 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14445 | + (const_int 2) |
| 14446 | + (const_int 4)))) |
| 14447 | + (set_attr "cc" "none")]) |
| 14448 | + |
| 14449 | +(define_insn "*beq-reverse" |
| 14450 | + [(set (pc) |
| 14451 | + (if_then_else (eq:CC (cc0) |
| 14452 | + (const_int 0)) |
| 14453 | + (pc) |
| 14454 | + (label_ref (match_operand 0 "" ""))))] |
| 14455 | + "" |
| 14456 | + "brne %0"; |
| 14457 | + [(set_attr "type" "branch") |
| 14458 | + (set (attr "length") |
| 14459 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14460 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14461 | + (const_int 2)] ; use compact branch |
| 14462 | + (const_int 4))) ; use extended branch |
| 14463 | + (set_attr "cc" "none")]) |
| 14464 | + |
| 14465 | +(define_insn "*bne-reverse" |
| 14466 | + [(set (pc) |
| 14467 | + (if_then_else (ne:CC (cc0) |
| 14468 | + (const_int 0)) |
| 14469 | + (pc) |
| 14470 | + (label_ref (match_operand 0 "" ""))))] |
| 14471 | + "" |
| 14472 | + "breq %0"; |
| 14473 | + [(set_attr "type" "branch") |
| 14474 | + (set (attr "length") |
| 14475 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) |
| 14476 | + (le (minus (pc) (match_dup 0)) (const_int 256))) |
| 14477 | + (const_int 2)] ; use compact branch |
| 14478 | + (const_int 4))) ; use extended branch |
| 14479 | + (set_attr "cc" "none")]) |
| 14480 | + |
| 14481 | +(define_insn "*b<code>-reverse" |
| 14482 | + [(set (pc) |
| 14483 | + (if_then_else (any_cond4:CC (cc0) |
| 14484 | + (const_int 0)) |
| 14485 | + (pc) |
| 14486 | + (label_ref (match_operand 0 "" ""))))] |
| 14487 | + "" |
| 14488 | + { |
| 14489 | + if (TARGET_HARD_FLOAT && TARGET_ARCH_FPU && (avr32_branch_type == CMP_SF)) |
| 14490 | + return "brvs %l0\;br<invcond> %l0"; |
| 14491 | + else |
| 14492 | + return "br<invcond> %0"; |
| 14493 | + } |
| 14494 | + [(set_attr "type" "branch") |
| 14495 | + (set (attr "length") |
| 14496 | + (cond [(eq (const_int 1)(symbol_ref "TARGET_HARD_FLOAT && TARGET_ARCH_FPU")) |
| 14497 | + (const_int 8)] |
| 14498 | + (const_int 4))) |
| 14499 | + (set_attr "cc" "none")]) |
| 14500 | + |
| 14501 | +;============================================================================= |
| 14502 | +; Conditional Add/Subtract |
| 14503 | +;----------------------------------------------------------------------------- |
| 14504 | +; sub{cond4} Rd, imm |
| 14505 | +;============================================================================= |
| 14506 | + |
| 14507 | + |
| 14508 | +(define_expand "add<mode>cc" |
| 14509 | + [(set (match_operand:ADDCC 0 "register_operand" "") |
| 14510 | + (if_then_else:ADDCC (match_operator 1 "avr32_comparison_operator" |
| 14511 | + [(match_dup 4) |
| 14512 | + (match_dup 5)]) |
| 14513 | + (match_operand:ADDCC 2 "register_operand" "") |
| 14514 | + (plus:ADDCC |
| 14515 | + (match_dup 2) |
| 14516 | + (match_operand:ADDCC 3 "" ""))))] |
| 14517 | + "" |
| 14518 | + { |
| 14519 | + if ( !(GET_CODE (operands[3]) == CONST_INT |
| 14520 | + || (TARGET_V2_INSNS && REG_P(operands[3]))) ){ |
| 14521 | + FAIL; |
| 14522 | + } |
| 14523 | + |
| 14524 | + /* Delete compare instruction as it is merged into this instruction */ |
| 14525 | + remove_insn (get_last_insn_anywhere ()); |
| 14526 | + |
| 14527 | + operands[4] = avr32_compare_op0; |
| 14528 | + operands[5] = avr32_compare_op1; |
| 14529 | + |
| 14530 | + if ( TARGET_V2_INSNS |
| 14531 | + && REG_P(operands[3]) |
| 14532 | + && REGNO(operands[0]) != REGNO(operands[2]) ){ |
| 14533 | + emit_move_insn (operands[0], operands[2]); |
| 14534 | + operands[2] = operands[0]; |
| 14535 | + } |
| 14536 | + } |
| 14537 | + ) |
| 14538 | + |
| 14539 | +(define_insn "add<ADDCC:mode>cc_cmp<CMP:mode>_reg" |
| 14540 | + [(set (match_operand:ADDCC 0 "register_operand" "=r") |
| 14541 | + (if_then_else:ADDCC (match_operator 1 "avr32_comparison_operator" |
| 14542 | + [(match_operand:CMP 4 "register_operand" "r") |
| 14543 | + (match_operand:CMP 5 "<CMP:cmp_predicate>" "<CMP:cmp_constraint>")]) |
| 14544 | + (match_dup 0) |
| 14545 | + (plus:ADDCC |
| 14546 | + (match_operand:ADDCC 2 "register_operand" "r") |
| 14547 | + (match_operand:ADDCC 3 "register_operand" "r"))))] |
| 14548 | + "TARGET_V2_INSNS" |
| 14549 | + { |
| 14550 | + operands[1] = avr32_output_cmp(operands[1], GET_MODE(operands[4]), operands[4], operands[5]); |
| 14551 | + return "add%i1\t%0, %2, %3"; |
| 14552 | + } |
| 14553 | + [(set_attr "length" "8") |
| 14554 | + (set_attr "cc" "cmp_cond_insn")]) |
| 14555 | + |
| 14556 | +(define_insn "add<ADDCC:mode>cc_cmp<CMP:mode>" |
| 14557 | + [(set (match_operand:ADDCC 0 "register_operand" "=r") |
| 14558 | + (if_then_else:ADDCC (match_operator 1 "avr32_comparison_operator" |
| 14559 | + [(match_operand:CMP 4 "register_operand" "r") |
| 14560 | + (match_operand:CMP 5 "<CMP:cmp_predicate>" "<CMP:cmp_constraint>")]) |
| 14561 | + (match_operand:ADDCC 2 "register_operand" "0") |
| 14562 | + (plus:ADDCC |
| 14563 | + (match_dup 2) |
| 14564 | + (match_operand:ADDCC 3 "avr32_cond_immediate_operand" "Is08"))))] |
| 14565 | + "" |
| 14566 | + { |
| 14567 | + operands[1] = avr32_output_cmp(operands[1], GET_MODE(operands[4]), operands[4], operands[5]); |
| 14568 | + return "sub%i1\t%0, -%3"; |
| 14569 | + } |
| 14570 | + [(set_attr "length" "8") |
| 14571 | + (set_attr "cc" "cmp_cond_insn")]) |
| 14572 | + |
| 14573 | +;============================================================================= |
| 14574 | +; Conditional Move |
| 14575 | +;----------------------------------------------------------------------------- |
| 14576 | +; mov{cond4} Rd, (Rs/imm) |
| 14577 | +;============================================================================= |
| 14578 | +(define_expand "mov<mode>cc" |
| 14579 | + [(set (match_operand:MOVCC 0 "register_operand" "") |
| 14580 | + (if_then_else:MOVCC (match_operator 1 "avr32_comparison_operator" |
| 14581 | + [(match_dup 4) |
| 14582 | + (match_dup 5)]) |
| 14583 | + (match_operand:MOVCC 2 "avr32_cond_register_immediate_operand" "") |
| 14584 | + (match_operand:MOVCC 3 "avr32_cond_register_immediate_operand" "")))] |
| 14585 | + "" |
| 14586 | + { |
| 14587 | + /* Delete compare instruction as it is merged into this instruction */ |
| 14588 | + remove_insn (get_last_insn_anywhere ()); |
| 14589 | + |
| 14590 | + operands[4] = avr32_compare_op0; |
| 14591 | + operands[5] = avr32_compare_op1; |
| 14592 | + } |
| 14593 | + ) |
| 14594 | + |
| 14595 | + |
| 14596 | +(define_insn "mov<MOVCC:mode>cc_cmp<CMP:mode>" |
| 14597 | + [(set (match_operand:MOVCC 0 "register_operand" "=r,r,r") |
| 14598 | + (if_then_else:MOVCC (match_operator 1 "avr32_comparison_operator" |
| 14599 | + [(match_operand:CMP 4 "register_operand" "r,r,r") |
| 14600 | + (match_operand:CMP 5 "<CMP:cmp_predicate>" "<CMP:cmp_constraint>,<CMP:cmp_constraint>,<CMP:cmp_constraint>")]) |
| 14601 | + (match_operand:MOVCC 2 "avr32_cond_register_immediate_operand" "0, rKs08,rKs08") |
| 14602 | + (match_operand:MOVCC 3 "avr32_cond_register_immediate_operand" "rKs08,0,rKs08")))] |
| 14603 | + "" |
| 14604 | + { |
| 14605 | + operands[1] = avr32_output_cmp(operands[1], GET_MODE(operands[4]), operands[4], operands[5]); |
| 14606 | + |
| 14607 | + switch( which_alternative ){ |
| 14608 | + case 0: |
| 14609 | + return "mov%i1 %0, %3"; |
| 14610 | + case 1: |
| 14611 | + return "mov%1 %0, %2"; |
| 14612 | + case 2: |
| 14613 | + return "mov%1 %0, %2\;mov%i1 %0, %3"; |
| 14614 | + default: |
| 14615 | + abort(); |
| 14616 | + } |
| 14617 | + |
| 14618 | + } |
| 14619 | + [(set_attr "length" "8,8,12") |
| 14620 | + (set_attr "cc" "cmp_cond_insn")]) |
| 14621 | + |
| 14622 | + |
| 14623 | + |
| 14624 | + |
| 14625 | +;;============================================================================= |
| 14626 | +;; jump |
| 14627 | +;;----------------------------------------------------------------------------- |
| 14628 | +;; Jump inside a function; an unconditional branch to a label. |
| 14629 | +;;============================================================================= |
| 14630 | +(define_insn "jump" |
| 14631 | + [(set (pc) |
| 14632 | + (label_ref (match_operand 0 "" "")))] |
| 14633 | + "" |
| 14634 | + { |
| 14635 | + if (get_attr_length(insn) > 4) |
| 14636 | + return "Can't jump this far"; |
| 14637 | + return (get_attr_length(insn) == 2 ? |
| 14638 | + "rjmp %0" : "bral %0"); |
| 14639 | + } |
| 14640 | + [(set_attr "type" "branch") |
| 14641 | + (set (attr "length") |
| 14642 | + (cond [(and (le (minus (match_dup 0) (pc)) (const_int 1022)) |
| 14643 | + (le (minus (pc) (match_dup 0)) (const_int 1024))) |
| 14644 | + (const_int 2) ; use rjmp |
| 14645 | + (le (match_dup 0) (const_int 1048575)) |
| 14646 | + (const_int 4)] ; use bral |
| 14647 | + (const_int 8))) ; do something else |
| 14648 | + (set_attr "cc" "none")]) |
| 14649 | + |
| 14650 | +;;============================================================================= |
| 14651 | +;; call |
| 14652 | +;;----------------------------------------------------------------------------- |
| 14653 | +;; Subroutine call instruction returning no value. |
| 14654 | +;;============================================================================= |
| 14655 | +(define_insn "call_internal" |
| 14656 | + [(parallel [(call (mem:SI (match_operand:SI 0 "avr32_call_operand" "r,U,T,W")) |
| 14657 | + (match_operand 1 "" "")) |
| 14658 | + (clobber (reg:SI LR_REGNUM))])] |
| 14659 | + "" |
| 14660 | + { |
| 14661 | + |
| 14662 | + /* Check for a flashvault call. */ |
| 14663 | + if (avr32_flashvault_call (SYMBOL_REF_DECL (operands[0]))) |
| 14664 | + { |
| 14665 | + /* Assembly is already emitted. */ |
| 14666 | + return ""; |
| 14667 | + } |
| 14668 | + |
| 14669 | + switch (which_alternative) { |
| 14670 | + case 0: |
| 14671 | + return "icall\t%0"; |
| 14672 | + case 1: |
| 14673 | + return "rcall\t%0"; |
| 14674 | + case 2: |
| 14675 | + return "mcall\t%0"; |
| 14676 | + case 3: |
| 14677 | + if (TARGET_HAS_ASM_ADDR_PSEUDOS) |
| 14678 | + return "call\t%0"; |
| 14679 | + else |
| 14680 | + return "mcall\tr6[%0@got]"; |
| 14681 | + default: |
| 14682 | + abort(); |
| 14683 | + } |
| 14684 | + } |
| 14685 | + [(set_attr "type" "call") |
| 14686 | + (set_attr "length" "2,4,4,10") |
| 14687 | + (set_attr "cc" "clobber")]) |
| 14688 | + |
| 14689 | + |
| 14690 | +(define_expand "call" |
| 14691 | + [(parallel [(call (match_operand:SI 0 "" "") |
| 14692 | + (match_operand 1 "" "")) |
| 14693 | + (clobber (reg:SI LR_REGNUM))])] |
| 14694 | + "" |
| 14695 | + { |
| 14696 | + rtx call_address; |
| 14697 | + if ( GET_CODE(operands[0]) != MEM ) |
| 14698 | + FAIL; |
| 14699 | + |
| 14700 | + call_address = XEXP(operands[0], 0); |
| 14701 | + |
| 14702 | + /* If assembler supports call pseudo insn and the call address is a symbol then nothing special needs to be done. */ |
| 14703 | + if (TARGET_HAS_ASM_ADDR_PSEUDOS && (GET_CODE(call_address) == SYMBOL_REF) ) |
| 14704 | + { |
| 14705 | + /* We must however mark the function as using the GOT if flag_pic is set, since the call insn might turn into a mcall using the GOT ptr register. */ |
| 14706 | + if (flag_pic) |
| 14707 | + { |
| 14708 | + crtl->uses_pic_offset_table = 1; |
| 14709 | + emit_call_insn(gen_call_internal(call_address, operands[1])); |
| 14710 | + DONE; |
| 14711 | + } |
| 14712 | + } |
| 14713 | + else |
| 14714 | + { |
| 14715 | + if (flag_pic && GET_CODE(call_address) == SYMBOL_REF ) |
| 14716 | + { |
| 14717 | + crtl->uses_pic_offset_table = 1; |
| 14718 | + emit_call_insn(gen_call_internal(call_address, operands[1])); |
| 14719 | + DONE; |
| 14720 | + } |
| 14721 | + |
| 14722 | + if (!SYMBOL_REF_RCALL_FUNCTION_P(operands[0]) ) |
| 14723 | + { |
| 14724 | + if (optimize_size && GET_CODE(call_address) == SYMBOL_REF ) |
| 14725 | + { |
| 14726 | + call_address = force_const_mem(SImode, call_address); |
| 14727 | + } |
| 14728 | + else |
| 14729 | + { |
| 14730 | + call_address = force_reg(SImode, call_address); |
| 14731 | + } |
| 14732 | + } |
| 14733 | + } |
| 14734 | + emit_call_insn(gen_call_internal(call_address, operands[1])); |
| 14735 | + DONE; |
| 14736 | + |
| 14737 | + } |
| 14738 | +) |
| 14739 | + |
| 14740 | +;;============================================================================= |
| 14741 | +;; call_value |
| 14742 | +;;----------------------------------------------------------------------------- |
| 14743 | +;; Subroutine call instruction returning a value. |
| 14744 | +;;============================================================================= |
| 14745 | +(define_expand "call_value" |
| 14746 | + [(parallel [(set (match_operand:SI 0 "" "") |
| 14747 | + (call (match_operand:SI 1 "" "") |
| 14748 | + (match_operand 2 "" ""))) |
| 14749 | + (clobber (reg:SI LR_REGNUM))])] |
| 14750 | + "" |
| 14751 | + { |
| 14752 | + rtx call_address; |
| 14753 | + if ( GET_CODE(operands[1]) != MEM ) |
| 14754 | + FAIL; |
| 14755 | + |
| 14756 | + call_address = XEXP(operands[1], 0); |
| 14757 | + |
| 14758 | + /* Check for a flashvault call. |
| 14759 | + if (GET_CODE (call_address) == SYMBOL_REF |
| 14760 | + && avr32_flashvault_call (SYMBOL_REF_DECL (call_address))) |
| 14761 | + DONE; |
| 14762 | + |
| 14763 | + */ |
| 14764 | + |
| 14765 | + /* If assembler supports call pseudo insn and the call |
| 14766 | + address is a symbol then nothing special needs to be done. */ |
| 14767 | + if ( TARGET_HAS_ASM_ADDR_PSEUDOS |
| 14768 | + && (GET_CODE(call_address) == SYMBOL_REF) ){ |
| 14769 | + /* We must however mark the function as using the GOT if |
| 14770 | + flag_pic is set, since the call insn might turn into |
| 14771 | + a mcall using the GOT ptr register. */ |
| 14772 | + if ( flag_pic ) { |
| 14773 | + crtl->uses_pic_offset_table = 1; |
| 14774 | + emit_call_insn(gen_call_value_internal(operands[0], call_address, operands[2])); |
| 14775 | + DONE; |
| 14776 | + } |
| 14777 | + } else { |
| 14778 | + if ( flag_pic && |
| 14779 | + GET_CODE(call_address) == SYMBOL_REF ){ |
| 14780 | + crtl->uses_pic_offset_table = 1; |
| 14781 | + emit_call_insn(gen_call_value_internal(operands[0], call_address, operands[2])); |
| 14782 | + DONE; |
| 14783 | + } |
| 14784 | + |
| 14785 | + if ( !SYMBOL_REF_RCALL_FUNCTION_P(operands[1]) ){ |
| 14786 | + if ( optimize_size && |
| 14787 | + GET_CODE(call_address) == SYMBOL_REF){ |
| 14788 | + call_address = force_const_mem(SImode, call_address); |
| 14789 | + } else { |
| 14790 | + call_address = force_reg(SImode, call_address); |
| 14791 | + } |
| 14792 | + } |
| 14793 | + } |
| 14794 | + emit_call_insn(gen_call_value_internal(operands[0], call_address, |
| 14795 | + operands[2])); |
| 14796 | + DONE; |
| 14797 | + |
| 14798 | + }) |
| 14799 | + |
| 14800 | +(define_insn "call_value_internal" |
| 14801 | + [(parallel [(set (match_operand 0 "register_operand" "=r,r,r,r") |
| 14802 | + (call (mem:SI (match_operand:SI 1 "avr32_call_operand" "r,U,T,W")) |
| 14803 | + (match_operand 2 "" ""))) |
| 14804 | + (clobber (reg:SI LR_REGNUM))])] |
| 14805 | + ;; Operand 2 not used on the AVR32. |
| 14806 | + "" |
| 14807 | + { |
| 14808 | + /* Check for a flashvault call. */ |
| 14809 | + if (avr32_flashvault_call (SYMBOL_REF_DECL (operands[1]))) |
| 14810 | + { |
| 14811 | + /* Assembly is already emitted. */ |
| 14812 | + return ""; |
| 14813 | + } |
| 14814 | + |
| 14815 | + |
| 14816 | + switch (which_alternative) { |
| 14817 | + case 0: |
| 14818 | + return "icall\t%1"; |
| 14819 | + case 1: |
| 14820 | + return "rcall\t%1"; |
| 14821 | + case 2: |
| 14822 | + return "mcall\t%1"; |
| 14823 | + case 3: |
| 14824 | + if ( TARGET_HAS_ASM_ADDR_PSEUDOS ) |
| 14825 | + return "call\t%1"; |
| 14826 | + else |
| 14827 | + return "mcall\tr6[%1@got]"; |
| 14828 | + default: |
| 14829 | + abort(); |
| 14830 | + } |
| 14831 | + } |
| 14832 | + [(set_attr "type" "call") |
| 14833 | + (set_attr "length" "2,4,4,10") |
| 14834 | + (set_attr "cc" "call_set")]) |
| 14835 | + |
| 14836 | + |
| 14837 | +;;============================================================================= |
| 14838 | +;; untyped_call |
| 14839 | +;;----------------------------------------------------------------------------- |
| 14840 | +;; Subrutine call instruction returning a value of any type. |
| 14841 | +;; The code is copied from m68k.md (except gen_blockage is removed) |
| 14842 | +;; Fixme! |
| 14843 | +;;============================================================================= |
| 14844 | +(define_expand "untyped_call" |
| 14845 | + [(parallel [(call (match_operand 0 "avr32_call_operand" "") |
| 14846 | + (const_int 0)) |
| 14847 | + (match_operand 1 "" "") |
| 14848 | + (match_operand 2 "" "")])] |
| 14849 | + "" |
| 14850 | + { |
| 14851 | + int i; |
| 14852 | + |
| 14853 | + emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); |
| 14854 | + |
| 14855 | + for (i = 0; i < XVECLEN (operands[2], 0); i++) { |
| 14856 | + rtx set = XVECEXP (operands[2], 0, i); |
| 14857 | + emit_move_insn (SET_DEST (set), SET_SRC (set)); |
| 14858 | + } |
| 14859 | + |
| 14860 | + /* The optimizer does not know that the call sets the function value |
| 14861 | + registers we stored in the result block. We avoid problems by |
| 14862 | + claiming that all hard registers are used and clobbered at this |
| 14863 | + point. */ |
| 14864 | + emit_insn (gen_blockage ()); |
| 14865 | + |
| 14866 | + DONE; |
| 14867 | + }) |
| 14868 | + |
| 14869 | + |
| 14870 | +;;============================================================================= |
| 14871 | +;; return |
| 14872 | +;;============================================================================= |
| 14873 | + |
| 14874 | +(define_insn "return" |
| 14875 | + [(return)] |
| 14876 | + "USE_RETURN_INSN (FALSE)" |
| 14877 | + { |
| 14878 | + avr32_output_return_instruction(TRUE, FALSE, NULL, NULL); |
| 14879 | + return ""; |
| 14880 | + } |
| 14881 | + [(set_attr "length" "4") |
| 14882 | + (set_attr "type" "call")] |
| 14883 | + ) |
| 14884 | + |
| 14885 | + |
| 14886 | +(define_insn "return_cond" |
| 14887 | + [(set (pc) |
| 14888 | + (if_then_else (match_operand 0 "avr32_comparison_operand" "") |
| 14889 | + (return) |
| 14890 | + (pc)))] |
| 14891 | + "USE_RETURN_INSN (TRUE)" |
| 14892 | + "ret%0\tr12"; |
| 14893 | + [(set_attr "type" "call")]) |
| 14894 | + |
| 14895 | +(define_insn "return_cond_predicable" |
| 14896 | + [(return)] |
| 14897 | + "USE_RETURN_INSN (TRUE)" |
| 14898 | + "ret%?\tr12"; |
| 14899 | + [(set_attr "type" "call") |
| 14900 | + (set_attr "predicable" "yes")]) |
| 14901 | + |
| 14902 | + |
| 14903 | +(define_insn "return_imm" |
| 14904 | + [(parallel [(set (reg RETVAL_REGNUM) (match_operand 0 "immediate_operand" "i")) |
| 14905 | + (use (reg RETVAL_REGNUM)) |
| 14906 | + (return)])] |
| 14907 | + "USE_RETURN_INSN (FALSE) && |
| 14908 | + ((INTVAL(operands[0]) == -1) || (INTVAL(operands[0]) == 0) || (INTVAL(operands[0]) == 1))" |
| 14909 | + { |
| 14910 | + avr32_output_return_instruction(TRUE, FALSE, NULL, operands[0]); |
| 14911 | + return ""; |
| 14912 | + } |
| 14913 | + [(set_attr "length" "4") |
| 14914 | + (set_attr "type" "call")] |
| 14915 | + ) |
| 14916 | + |
| 14917 | +(define_insn "return_imm_cond" |
| 14918 | + [(parallel [(set (reg RETVAL_REGNUM) (match_operand 0 "immediate_operand" "i")) |
| 14919 | + (use (reg RETVAL_REGNUM)) |
| 14920 | + (set (pc) |
| 14921 | + (if_then_else (match_operand 1 "avr32_comparison_operand" "") |
| 14922 | + (return) |
| 14923 | + (pc)))])] |
| 14924 | + "USE_RETURN_INSN (TRUE) && |
| 14925 | + ((INTVAL(operands[0]) == -1) || (INTVAL(operands[0]) == 0) || (INTVAL(operands[0]) == 1))" |
| 14926 | + "ret%1\t%0"; |
| 14927 | + [(set_attr "type" "call")] |
| 14928 | + ) |
| 14929 | + |
| 14930 | +(define_insn "return_imm_predicable" |
| 14931 | + [(parallel [(set (reg RETVAL_REGNUM) (match_operand 0 "immediate_operand" "i")) |
| 14932 | + (use (reg RETVAL_REGNUM)) |
| 14933 | + (return)])] |
| 14934 | + "USE_RETURN_INSN (TRUE) && |
| 14935 | + ((INTVAL(operands[0]) == -1) || (INTVAL(operands[0]) == 0) || (INTVAL(operands[0]) == 1))" |
| 14936 | + "ret%?\t%0"; |
| 14937 | + [(set_attr "type" "call") |
| 14938 | + (set_attr "predicable" "yes")]) |
| 14939 | + |
| 14940 | +(define_insn "return_<mode>reg" |
| 14941 | + [(set (reg RETVAL_REGNUM) (match_operand:MOVM 0 "register_operand" "r")) |
| 14942 | + (use (reg RETVAL_REGNUM)) |
| 14943 | + (return)] |
| 14944 | + "USE_RETURN_INSN (TRUE)" |
| 14945 | + "ret%?\t%0"; |
| 14946 | + [(set_attr "type" "call") |
| 14947 | + (set_attr "predicable" "yes")]) |
| 14948 | + |
| 14949 | +(define_insn "return_<mode>reg_cond" |
| 14950 | + [(set (reg RETVAL_REGNUM) (match_operand:MOVM 0 "register_operand" "r")) |
| 14951 | + (use (reg RETVAL_REGNUM)) |
| 14952 | + (set (pc) |
| 14953 | + (if_then_else (match_operator 1 "avr32_comparison_operator" |
| 14954 | + [(cc0) (const_int 0)]) |
| 14955 | + (return) |
| 14956 | + (pc)))] |
| 14957 | + "USE_RETURN_INSN (TRUE)" |
| 14958 | + "ret%1\t%0"; |
| 14959 | + [(set_attr "type" "call")]) |
| 14960 | + |
| 14961 | +;;============================================================================= |
| 14962 | +;; nonlocal_goto_receiver |
| 14963 | +;;----------------------------------------------------------------------------- |
| 14964 | +;; For targets with a return stack we must make sure to flush the return stack |
| 14965 | +;; since it will be corrupt after a nonlocal goto. |
| 14966 | +;;============================================================================= |
| 14967 | +(define_expand "nonlocal_goto_receiver" |
| 14968 | + [(const_int 0)] |
| 14969 | + "TARGET_RETURN_STACK" |
| 14970 | + " |
| 14971 | + { |
| 14972 | + emit_insn ( gen_frs() ); |
| 14973 | + DONE; |
| 14974 | + } |
| 14975 | + " |
| 14976 | + ) |
| 14977 | + |
| 14978 | + |
| 14979 | +;;============================================================================= |
| 14980 | +;; builtin_setjmp_receiver |
| 14981 | +;;----------------------------------------------------------------------------- |
| 14982 | +;; For pic code we need to reload the pic register. |
| 14983 | +;; For targets with a return stack we must make sure to flush the return stack |
| 14984 | +;; since it will probably be corrupted. |
| 14985 | +;;============================================================================= |
| 14986 | +(define_expand "builtin_setjmp_receiver" |
| 14987 | + [(label_ref (match_operand 0 "" ""))] |
| 14988 | + "flag_pic" |
| 14989 | + " |
| 14990 | + { |
| 14991 | + if ( TARGET_RETURN_STACK ) |
| 14992 | + emit_insn ( gen_frs() ); |
| 14993 | + |
| 14994 | + avr32_load_pic_register (); |
| 14995 | + DONE; |
| 14996 | + } |
| 14997 | + " |
| 14998 | +) |
| 14999 | + |
| 15000 | + |
| 15001 | +;;============================================================================= |
| 15002 | +;; indirect_jump |
| 15003 | +;;----------------------------------------------------------------------------- |
| 15004 | +;; Jump to an address in reg or memory. |
| 15005 | +;;============================================================================= |
| 15006 | +(define_expand "indirect_jump" |
| 15007 | + [(set (pc) |
| 15008 | + (match_operand:SI 0 "general_operand" ""))] |
| 15009 | + "" |
| 15010 | + { |
| 15011 | + /* One of the ops has to be in a register. */ |
| 15012 | + if ( (flag_pic || TARGET_HAS_ASM_ADDR_PSEUDOS ) |
| 15013 | + && !avr32_legitimate_pic_operand_p(operands[0]) ) |
| 15014 | + operands[0] = legitimize_pic_address (operands[0], SImode, 0); |
| 15015 | + else if ( flag_pic && avr32_address_operand(operands[0], GET_MODE(operands[0])) ) |
| 15016 | + /* If we have an address operand then this function uses the pic register. */ |
| 15017 | + crtl->uses_pic_offset_table = 1; |
| 15018 | + }) |
| 15019 | + |
| 15020 | + |
| 15021 | +(define_insn "indirect_jump_internal" |
| 15022 | + [(set (pc) |
| 15023 | + (match_operand:SI 0 "avr32_non_rmw_general_operand" "r,m,W"))] |
| 15024 | + "" |
| 15025 | + { |
| 15026 | + switch( which_alternative ){ |
| 15027 | + case 0: |
| 15028 | + return "mov\tpc, %0"; |
| 15029 | + case 1: |
| 15030 | + if ( avr32_const_pool_ref_operand(operands[0], GET_MODE(operands[0])) ) |
| 15031 | + return "lddpc\tpc, %0"; |
| 15032 | + else |
| 15033 | + return "ld.w\tpc, %0"; |
| 15034 | + case 2: |
| 15035 | + if ( flag_pic ) |
| 15036 | + return "ld.w\tpc, r6[%0@got]"; |
| 15037 | + else |
| 15038 | + return "lda.w\tpc, %0"; |
| 15039 | + default: |
| 15040 | + abort(); |
| 15041 | + } |
| 15042 | + } |
| 15043 | + [(set_attr "length" "2,4,8") |
| 15044 | + (set_attr "type" "call,call,call") |
| 15045 | + (set_attr "cc" "none,none,clobber")]) |
| 15046 | + |
| 15047 | + |
| 15048 | + |
| 15049 | +;;============================================================================= |
| 15050 | +;; casesi and tablejump |
| 15051 | +;;============================================================================= |
| 15052 | +(define_insn "tablejump_add" |
| 15053 | + [(set (pc) |
| 15054 | + (plus:SI (match_operand:SI 0 "register_operand" "r") |
| 15055 | + (mult:SI (match_operand:SI 1 "register_operand" "r") |
| 15056 | + (match_operand:SI 2 "immediate_operand" "Ku04" )))) |
| 15057 | + (use (label_ref (match_operand 3 "" "")))] |
| 15058 | + "flag_pic && |
| 15059 | + ((INTVAL(operands[2]) == 0) || (INTVAL(operands[2]) == 2) || |
| 15060 | + (INTVAL(operands[2]) == 4) || (INTVAL(operands[2]) == 8))" |
| 15061 | + "add\tpc, %0, %1 << %p2" |
| 15062 | + [(set_attr "length" "4") |
| 15063 | + (set_attr "cc" "clobber")]) |
| 15064 | + |
| 15065 | +(define_insn "tablejump_insn" |
| 15066 | + [(set (pc) (match_operand:SI 0 "memory_operand" "m")) |
| 15067 | + (use (label_ref (match_operand 1 "" "")))] |
| 15068 | + "!flag_pic" |
| 15069 | + "ld.w\tpc, %0" |
| 15070 | + [(set_attr "length" "4") |
| 15071 | + (set_attr "type" "call") |
| 15072 | + (set_attr "cc" "none")]) |
| 15073 | + |
| 15074 | +(define_expand "casesi" |
| 15075 | + [(match_operand:SI 0 "register_operand" "") ; index to jump on |
| 15076 | + (match_operand:SI 1 "const_int_operand" "") ; lower bound |
| 15077 | + (match_operand:SI 2 "const_int_operand" "") ; total range |
| 15078 | + (match_operand:SI 3 "" "") ; table label |
| 15079 | + (match_operand:SI 4 "" "")] ; Out of range label |
| 15080 | + "" |
| 15081 | + " |
| 15082 | + { |
| 15083 | + rtx reg; |
| 15084 | + rtx index = operands[0]; |
| 15085 | + rtx low_bound = operands[1]; |
| 15086 | + rtx range = operands[2]; |
| 15087 | + rtx table_label = operands[3]; |
| 15088 | + rtx oor_label = operands[4]; |
| 15089 | + |
| 15090 | + index = force_reg ( SImode, index ); |
| 15091 | + if (low_bound != const0_rtx) |
| 15092 | + { |
| 15093 | + if (!avr32_const_ok_for_constraint_p(INTVAL (low_bound), 'I', \"Is21\")){ |
| 15094 | + reg = force_reg(SImode, GEN_INT (INTVAL (low_bound))); |
| 15095 | + emit_insn (gen_subsi3 (reg, index, |
| 15096 | + reg)); |
| 15097 | + } else { |
| 15098 | + reg = gen_reg_rtx (SImode); |
| 15099 | + emit_insn (gen_addsi3 (reg, index, |
| 15100 | + GEN_INT (-INTVAL (low_bound)))); |
| 15101 | + } |
| 15102 | + index = reg; |
| 15103 | + } |
| 15104 | + |
| 15105 | + if (!avr32_const_ok_for_constraint_p (INTVAL (range), 'K', \"Ks21\")) |
| 15106 | + range = force_reg (SImode, range); |
| 15107 | + |
| 15108 | + emit_cmp_and_jump_insns ( index, range, GTU, NULL_RTX, SImode, 1, oor_label ); |
| 15109 | + reg = gen_reg_rtx (SImode); |
| 15110 | + emit_move_insn ( reg, gen_rtx_LABEL_REF (VOIDmode, table_label)); |
| 15111 | + |
| 15112 | + if ( flag_pic ) |
| 15113 | + emit_jump_insn ( gen_tablejump_add ( reg, index, GEN_INT(4), table_label)); |
| 15114 | + else |
| 15115 | + emit_jump_insn ( |
| 15116 | + gen_tablejump_insn ( gen_rtx_MEM ( SImode, |
| 15117 | + gen_rtx_PLUS ( SImode, |
| 15118 | + reg, |
| 15119 | + gen_rtx_MULT ( SImode, |
| 15120 | + index, |
| 15121 | + GEN_INT(4)))), |
| 15122 | + table_label)); |
| 15123 | + DONE; |
| 15124 | + }" |
| 15125 | +) |
| 15126 | + |
| 15127 | + |
| 15128 | + |
| 15129 | +(define_insn "prefetch" |
| 15130 | + [(prefetch (match_operand:SI 0 "avr32_ks16_address_operand" "p") |
| 15131 | + (match_operand 1 "const_int_operand" "") |
| 15132 | + (match_operand 2 "const_int_operand" ""))] |
| 15133 | + "" |
| 15134 | + { |
| 15135 | + return "pref\t%0"; |
| 15136 | + } |
| 15137 | + |
| 15138 | + [(set_attr "length" "4") |
| 15139 | + (set_attr "type" "load") |
| 15140 | + (set_attr "cc" "none")]) |
| 15141 | + |
| 15142 | + |
| 15143 | + |
| 15144 | +;;============================================================================= |
| 15145 | +;; prologue |
| 15146 | +;;----------------------------------------------------------------------------- |
| 15147 | +;; This pattern, if defined, emits RTL for entry to a function. The function |
| 15148 | +;; entry i responsible for setting up the stack frame, initializing the frame |
| 15149 | +;; pointer register, saving callee saved registers, etc. |
| 15150 | +;;============================================================================= |
| 15151 | +(define_expand "prologue" |
| 15152 | + [(clobber (const_int 0))] |
| 15153 | + "" |
| 15154 | + " |
| 15155 | + avr32_expand_prologue(); |
| 15156 | + DONE; |
| 15157 | + " |
| 15158 | + ) |
| 15159 | + |
| 15160 | +;;============================================================================= |
| 15161 | +;; eh_return |
| 15162 | +;;----------------------------------------------------------------------------- |
| 15163 | +;; This pattern, if defined, affects the way __builtin_eh_return, and |
| 15164 | +;; thence the call frame exception handling library routines, are |
| 15165 | +;; built. It is intended to handle non-trivial actions needed along |
| 15166 | +;; the abnormal return path. |
| 15167 | +;; |
| 15168 | +;; The address of the exception handler to which the function should |
| 15169 | +;; return is passed as operand to this pattern. It will normally need |
| 15170 | +;; to copied by the pattern to some special register or memory |
| 15171 | +;; location. If the pattern needs to determine the location of the |
| 15172 | +;; target call frame in order to do so, it may use |
| 15173 | +;; EH_RETURN_STACKADJ_RTX, if defined; it will have already been |
| 15174 | +;; assigned. |
| 15175 | +;; |
| 15176 | +;; If this pattern is not defined, the default action will be to |
| 15177 | +;; simply copy the return address to EH_RETURN_HANDLER_RTX. Either |
| 15178 | +;; that macro or this pattern needs to be defined if call frame |
| 15179 | +;; exception handling is to be used. |
| 15180 | + |
| 15181 | +;; We can't expand this before we know where the link register is stored. |
| 15182 | +(define_insn_and_split "eh_return" |
| 15183 | + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] |
| 15184 | + VUNSPEC_EH_RETURN) |
| 15185 | + (clobber (match_scratch:SI 1 "=&r"))] |
| 15186 | + "" |
| 15187 | + "#" |
| 15188 | + "reload_completed" |
| 15189 | + [(const_int 0)] |
| 15190 | + " |
| 15191 | + { |
| 15192 | + avr32_set_return_address (operands[0], operands[1]); |
| 15193 | + DONE; |
| 15194 | + }" |
| 15195 | + ) |
| 15196 | + |
| 15197 | + |
| 15198 | +;;============================================================================= |
| 15199 | +;; ffssi2 |
| 15200 | +;;----------------------------------------------------------------------------- |
| 15201 | +(define_insn "ffssi2" |
| 15202 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 15203 | + (ffs:SI (match_operand:SI 1 "register_operand" "r"))) ] |
| 15204 | + "" |
| 15205 | + "mov %0, %1 |
| 15206 | + brev %0 |
| 15207 | + clz %0, %0 |
| 15208 | + sub %0, -1 |
| 15209 | + cp %0, 33 |
| 15210 | + moveq %0, 0" |
| 15211 | + [(set_attr "length" "18") |
| 15212 | + (set_attr "cc" "clobber")] |
| 15213 | + ) |
| 15214 | + |
| 15215 | + |
| 15216 | + |
| 15217 | +;;============================================================================= |
| 15218 | +;; swap_h |
| 15219 | +;;----------------------------------------------------------------------------- |
| 15220 | +(define_insn "*swap_h" |
| 15221 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 15222 | + (ior:SI (ashift:SI (match_dup 0) (const_int 16)) |
| 15223 | + (lshiftrt:SI (match_dup 0) (const_int 16))))] |
| 15224 | + "" |
| 15225 | + "swap.h %0" |
| 15226 | + [(set_attr "length" "2")] |
| 15227 | + ) |
| 15228 | + |
| 15229 | +(define_insn_and_split "bswap_16" |
| 15230 | + [ (set (match_operand:HI 0 "avr32_bswap_operand" "=r,RKs13,r") |
| 15231 | + (ior:HI (and:HI (lshiftrt:HI (match_operand:HI 1 "avr32_bswap_operand" "r,r,RKs13") |
| 15232 | + (const_int 8)) |
| 15233 | + (const_int 255)) |
| 15234 | + (ashift:HI (and:HI (match_dup 1) |
| 15235 | + (const_int 255)) |
| 15236 | + (const_int 8))))] |
| 15237 | + "" |
| 15238 | + { |
| 15239 | + switch ( which_alternative ){ |
| 15240 | + case 0: |
| 15241 | + if ( REGNO(operands[0]) == REGNO(operands[1])) |
| 15242 | + return "swap.bh\t%0"; |
| 15243 | + else |
| 15244 | + return "mov\t%0, %1\;swap.bh\t%0"; |
| 15245 | + case 1: |
| 15246 | + return "stswp.h\t%0, %1"; |
| 15247 | + case 2: |
| 15248 | + return "ldswp.sh\t%0, %1"; |
| 15249 | + default: |
| 15250 | + abort(); |
| 15251 | + } |
| 15252 | + } |
| 15253 | + |
| 15254 | + "(reload_completed && |
| 15255 | + REG_P(operands[0]) && REG_P(operands[1]) |
| 15256 | + && (REGNO(operands[0]) != REGNO(operands[1])))" |
| 15257 | + [(set (match_dup 0) (match_dup 1)) |
| 15258 | + (set (match_dup 0) |
| 15259 | + (ior:HI (and:HI (lshiftrt:HI (match_dup 0) |
| 15260 | + (const_int 8)) |
| 15261 | + (const_int 255)) |
| 15262 | + (ashift:HI (and:HI (match_dup 0) |
| 15263 | + (const_int 255)) |
| 15264 | + (const_int 8))))] |
| 15265 | + "" |
| 15266 | + |
| 15267 | + [(set_attr "length" "4,4,4") |
| 15268 | + (set_attr "type" "alu,store,load_rm")] |
| 15269 | + ) |
| 15270 | + |
| 15271 | +(define_insn_and_split "bswap_32" |
| 15272 | + [ (set (match_operand:SI 0 "avr32_bswap_operand" "=r,RKs14,r") |
| 15273 | + (ior:SI (ior:SI (lshiftrt:SI (and:SI (match_operand:SI 1 "avr32_bswap_operand" "r,r,RKs14") |
| 15274 | + (const_int -16777216)) |
| 15275 | + (const_int 24)) |
| 15276 | + (lshiftrt:SI (and:SI (match_dup 1) |
| 15277 | + (const_int 16711680)) |
| 15278 | + (const_int 8))) |
| 15279 | + (ior:SI (ashift:SI (and:SI (match_dup 1) |
| 15280 | + (const_int 65280)) |
| 15281 | + (const_int 8)) |
| 15282 | + (ashift:SI (and:SI (match_dup 1) |
| 15283 | + (const_int 255)) |
| 15284 | + (const_int 24)))))] |
| 15285 | + "" |
| 15286 | + { |
| 15287 | + switch ( which_alternative ){ |
| 15288 | + case 0: |
| 15289 | + if ( REGNO(operands[0]) == REGNO(operands[1])) |
| 15290 | + return "swap.b\t%0"; |
| 15291 | + else |
| 15292 | + return "#"; |
| 15293 | + case 1: |
| 15294 | + return "stswp.w\t%0, %1"; |
| 15295 | + case 2: |
| 15296 | + return "ldswp.w\t%0, %1"; |
| 15297 | + default: |
| 15298 | + abort(); |
| 15299 | + } |
| 15300 | + } |
| 15301 | + "(reload_completed && |
| 15302 | + REG_P(operands[0]) && REG_P(operands[1]) |
| 15303 | + && (REGNO(operands[0]) != REGNO(operands[1])))" |
| 15304 | + [(set (match_dup 0) (match_dup 1)) |
| 15305 | + (set (match_dup 0) |
| 15306 | + (ior:SI (ior:SI (lshiftrt:SI (and:SI (match_dup 0) |
| 15307 | + (const_int -16777216)) |
| 15308 | + (const_int 24)) |
| 15309 | + (lshiftrt:SI (and:SI (match_dup 0) |
| 15310 | + (const_int 16711680)) |
| 15311 | + (const_int 8))) |
| 15312 | + (ior:SI (ashift:SI (and:SI (match_dup 0) |
| 15313 | + (const_int 65280)) |
| 15314 | + (const_int 8)) |
| 15315 | + (ashift:SI (and:SI (match_dup 0) |
| 15316 | + (const_int 255)) |
| 15317 | + (const_int 24)))))] |
| 15318 | + "" |
| 15319 | + |
| 15320 | + [(set_attr "length" "4,4,4") |
| 15321 | + (set_attr "type" "alu,store,load_rm")] |
| 15322 | + ) |
| 15323 | + |
| 15324 | + |
| 15325 | +;;============================================================================= |
| 15326 | +;; blockage |
| 15327 | +;;----------------------------------------------------------------------------- |
| 15328 | +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and |
| 15329 | +;; all of memory. This blocks insns from being moved across this point. |
| 15330 | + |
| 15331 | +(define_insn "blockage" |
| 15332 | + [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)] |
| 15333 | + "" |
| 15334 | + "" |
| 15335 | + [(set_attr "length" "0")] |
| 15336 | +) |
| 15337 | + |
| 15338 | +;;============================================================================= |
| 15339 | +;; clzsi2 |
| 15340 | +;;----------------------------------------------------------------------------- |
| 15341 | +(define_insn "clzsi2" |
| 15342 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 15343 | + (clz:SI (match_operand:SI 1 "register_operand" "r"))) ] |
| 15344 | + "" |
| 15345 | + "clz %0, %1" |
| 15346 | + [(set_attr "length" "4") |
| 15347 | + (set_attr "cc" "set_z")] |
| 15348 | + ) |
| 15349 | + |
| 15350 | +;;============================================================================= |
| 15351 | +;; ctzsi2 |
| 15352 | +;;----------------------------------------------------------------------------- |
| 15353 | +(define_insn "ctzsi2" |
| 15354 | + [ (set (match_operand:SI 0 "register_operand" "=r,r") |
| 15355 | + (ctz:SI (match_operand:SI 1 "register_operand" "0,r"))) ] |
| 15356 | + "" |
| 15357 | + "@ |
| 15358 | + brev\t%0\;clz\t%0, %0 |
| 15359 | + mov\t%0, %1\;brev\t%0\;clz\t%0, %0" |
| 15360 | + [(set_attr "length" "8") |
| 15361 | + (set_attr "cc" "set_z")] |
| 15362 | + ) |
| 15363 | + |
| 15364 | +;;============================================================================= |
| 15365 | +;; cache instructions |
| 15366 | +;;----------------------------------------------------------------------------- |
| 15367 | +(define_insn "cache" |
| 15368 | + [ (unspec_volatile [(match_operand:SI 0 "avr32_ks11_address_operand" "p") |
| 15369 | + (match_operand:SI 1 "immediate_operand" "Ku05")] VUNSPEC_CACHE)] |
| 15370 | + "" |
| 15371 | + "cache %0, %1" |
| 15372 | + [(set_attr "length" "4")] |
| 15373 | + ) |
| 15374 | + |
| 15375 | +(define_insn "sync" |
| 15376 | + [ (unspec_volatile [(match_operand:SI 0 "immediate_operand" "Ku08")] VUNSPEC_SYNC)] |
| 15377 | + "" |
| 15378 | + "sync %0" |
| 15379 | + [(set_attr "length" "4")] |
| 15380 | + ) |
| 15381 | + |
| 15382 | +;;============================================================================= |
| 15383 | +;; TLB instructions |
| 15384 | +;;----------------------------------------------------------------------------- |
| 15385 | +(define_insn "tlbr" |
| 15386 | + [ (unspec_volatile [(const_int 0)] VUNSPEC_TLBR)] |
| 15387 | + "" |
| 15388 | + "tlbr" |
| 15389 | + [(set_attr "length" "2")] |
| 15390 | + ) |
| 15391 | + |
| 15392 | +(define_insn "tlbw" |
| 15393 | + [ (unspec_volatile [(const_int 0)] VUNSPEC_TLBW)] |
| 15394 | + "" |
| 15395 | + "tlbw" |
| 15396 | + [(set_attr "length" "2")] |
| 15397 | + ) |
| 15398 | + |
| 15399 | +(define_insn "tlbs" |
| 15400 | + [ (unspec_volatile [(const_int 0)] VUNSPEC_TLBS)] |
| 15401 | + "" |
| 15402 | + "tlbs" |
| 15403 | + [(set_attr "length" "2")] |
| 15404 | + ) |
| 15405 | + |
| 15406 | +;;============================================================================= |
| 15407 | +;; Breakpoint instruction |
| 15408 | +;;----------------------------------------------------------------------------- |
| 15409 | +(define_insn "breakpoint" |
| 15410 | + [ (unspec_volatile [(const_int 0)] VUNSPEC_BREAKPOINT)] |
| 15411 | + "" |
| 15412 | + "breakpoint" |
| 15413 | + [(set_attr "length" "2")] |
| 15414 | + ) |
| 15415 | + |
| 15416 | + |
| 15417 | +;;============================================================================= |
| 15418 | +;; mtsr/mfsr instruction |
| 15419 | +;;----------------------------------------------------------------------------- |
| 15420 | +(define_insn "mtsr" |
| 15421 | + [ (unspec_volatile [(match_operand 0 "immediate_operand" "i") |
| 15422 | + (match_operand:SI 1 "register_operand" "r")] VUNSPEC_MTSR)] |
| 15423 | + "" |
| 15424 | + "mtsr\t%0, %1" |
| 15425 | + [(set_attr "length" "4")] |
| 15426 | + ) |
| 15427 | + |
| 15428 | +(define_insn "mfsr" |
| 15429 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 15430 | + (unspec_volatile:SI [(match_operand 1 "immediate_operand" "i")] VUNSPEC_MFSR)) ] |
| 15431 | + "" |
| 15432 | + "mfsr\t%0, %1" |
| 15433 | + [(set_attr "length" "4")] |
| 15434 | + ) |
| 15435 | + |
| 15436 | +;;============================================================================= |
| 15437 | +;; mtdr/mfdr instruction |
| 15438 | +;;----------------------------------------------------------------------------- |
| 15439 | +(define_insn "mtdr" |
| 15440 | + [ (unspec_volatile [(match_operand 0 "immediate_operand" "i") |
| 15441 | + (match_operand:SI 1 "register_operand" "r")] VUNSPEC_MTDR)] |
| 15442 | + "" |
| 15443 | + "mtdr\t%0, %1" |
| 15444 | + [(set_attr "length" "4")] |
| 15445 | + ) |
| 15446 | + |
| 15447 | +(define_insn "mfdr" |
| 15448 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 15449 | + (unspec_volatile:SI [(match_operand 1 "immediate_operand" "i")] VUNSPEC_MFDR)) ] |
| 15450 | + "" |
| 15451 | + "mfdr\t%0, %1" |
| 15452 | + [(set_attr "length" "4")] |
| 15453 | + ) |
| 15454 | + |
| 15455 | +;;============================================================================= |
| 15456 | +;; musfr |
| 15457 | +;;----------------------------------------------------------------------------- |
| 15458 | +(define_insn "musfr" |
| 15459 | + [ (unspec_volatile [(match_operand:SI 0 "register_operand" "r")] VUNSPEC_MUSFR)] |
| 15460 | + "" |
| 15461 | + "musfr\t%0" |
| 15462 | + [(set_attr "length" "2") |
| 15463 | + (set_attr "cc" "clobber")] |
| 15464 | + ) |
| 15465 | + |
| 15466 | +(define_insn "mustr" |
| 15467 | + [ (set (match_operand:SI 0 "register_operand" "=r") |
| 15468 | + (unspec_volatile:SI [(const_int 0)] VUNSPEC_MUSTR)) ] |
| 15469 | + "" |
| 15470 | + "mustr\t%0" |
| 15471 | + [(set_attr "length" "2")] |
| 15472 | + ) |
| 15473 | + |
| 15474 | +(define_insn "ssrf" |
| 15475 | + [ (unspec_volatile [(match_operand:SI 0 "immediate_operand" "Ku05")] VUNSPEC_SSRF)] |
| 15476 | + "" |
| 15477 | + "ssrf %0" |
| 15478 | + [(set_attr "length" "2") |
| 15479 | + (set_attr "cc" "clobber")] |
| 15480 | + ) |
| 15481 | + |
| 15482 | +(define_insn "csrf" |
| 15483 | + [ (unspec_volatile [(match_operand:SI 0 "immediate_operand" "Ku05")] VUNSPEC_CSRF)] |
| 15484 | + "" |
| 15485 | + "csrf %0" |
| 15486 | + [(set_attr "length" "2") |
| 15487 | + (set_attr "cc" "clobber")] |
| 15488 | + ) |
| 15489 | + |
| 15490 | +;;============================================================================= |
| 15491 | +;; Flush Return Stack instruction |
| 15492 | +;;----------------------------------------------------------------------------- |
| 15493 | +(define_insn "frs" |
| 15494 | + [ (unspec_volatile [(const_int 0)] VUNSPEC_FRS)] |
| 15495 | + "" |
| 15496 | + "frs" |
| 15497 | + [(set_attr "length" "2") |
| 15498 | + (set_attr "cc" "none")] |
| 15499 | + ) |
| 15500 | + |
| 15501 | + |
| 15502 | +;;============================================================================= |
| 15503 | +;; Saturation Round Scale instruction |
| 15504 | +;;----------------------------------------------------------------------------- |
| 15505 | +(define_insn "sats" |
| 15506 | + [ (set (match_operand:SI 0 "register_operand" "+r") |
| 15507 | + (unspec:SI [(match_dup 0) |
| 15508 | + (match_operand 1 "immediate_operand" "Ku05") |
| 15509 | + (match_operand 2 "immediate_operand" "Ku05")] |
| 15510 | + UNSPEC_SATS)) ] |
| 15511 | + "TARGET_DSP" |
| 15512 | + "sats\t%0 >> %1, %2" |
| 15513 | + [(set_attr "type" "alu_sat") |
| 15514 | + (set_attr "length" "4")] |
| 15515 | + ) |
| 15516 | + |
| 15517 | +(define_insn "satu" |
| 15518 | + [ (set (match_operand:SI 0 "register_operand" "+r") |
| 15519 | + (unspec:SI [(match_dup 0) |
| 15520 | + (match_operand 1 "immediate_operand" "Ku05") |
| 15521 | + (match_operand 2 "immediate_operand" "Ku05")] |
| 15522 | + UNSPEC_SATU)) ] |
| 15523 | + "TARGET_DSP" |
| 15524 | + "satu\t%0 >> %1, %2" |
| 15525 | + [(set_attr "type" "alu_sat") |
| 15526 | + (set_attr "length" "4")] |
| 15527 | + ) |
| 15528 | + |
| 15529 | +(define_insn "satrnds" |
| 15530 | + [ (set (match_operand:SI 0 "register_operand" "+r") |
| 15531 | + (unspec:SI [(match_dup 0) |
| 15532 | + (match_operand 1 "immediate_operand" "Ku05") |
| 15533 | + (match_operand 2 "immediate_operand" "Ku05")] |
| 15534 | + UNSPEC_SATRNDS)) ] |
| 15535 | + "TARGET_DSP" |
| 15536 | + "satrnds\t%0 >> %1, %2" |
| 15537 | + [(set_attr "type" "alu_sat") |
| 15538 | + (set_attr "length" "4")] |
| 15539 | + ) |
| 15540 | + |
| 15541 | +(define_insn "satrndu" |
| 15542 | + [ (set (match_operand:SI 0 "register_operand" "+r") |
| 15543 | + (unspec:SI [(match_dup 0) |
| 15544 | + (match_operand 1 "immediate_operand" "Ku05") |
| 15545 | + (match_operand 2 "immediate_operand" "Ku05")] |
| 15546 | + UNSPEC_SATRNDU)) ] |
| 15547 | + "TARGET_DSP" |
| 15548 | + "sats\t%0 >> %1, %2" |
| 15549 | + [(set_attr "type" "alu_sat") |
| 15550 | + (set_attr "length" "4")] |
| 15551 | + ) |
| 15552 | + |
| 15553 | +(define_insn "sleep" |
| 15554 | + [(unspec_volatile [(const_int 0)] VUNSPEC_SLEEP) |
| 15555 | + (match_operand:SI 0 "const_int_operand" "")] |
| 15556 | + "" |
| 15557 | + "sleep %0" |
| 15558 | + [(set_attr "length" "1") |
| 15559 | + (set_attr "cc" "none") |
| 15560 | + ]) |
| 15561 | + |
| 15562 | +(define_expand "delay_cycles" |
| 15563 | + [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i")] |
| 15564 | + VUNSPEC_DELAY_CYCLES)] |
| 15565 | + "" |
| 15566 | + " |
| 15567 | + unsigned int cycles = UINTVAL (operands[0]); |
| 15568 | + if (IN_RANGE(cycles,0x10000 ,0xFFFFFFFF)) |
| 15569 | + { |
| 15570 | + unsigned int msb = (cycles & 0xFFFF0000); |
| 15571 | + unsigned int shift = 16; |
| 15572 | + msb = (msb >> shift); |
| 15573 | + unsigned int cycles_used = (msb*0x10000); |
| 15574 | + emit_insn (gen_delay_cycles_2 (gen_int_mode (msb, SImode))); |
| 15575 | + cycles -= cycles_used; |
| 15576 | + } |
| 15577 | + if (IN_RANGE(cycles, 4, 0xFFFF)) |
| 15578 | + { |
| 15579 | + unsigned int loop_count = (cycles/ 4); |
| 15580 | + unsigned int cycles_used = (loop_count*4); |
| 15581 | + emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, SImode))); |
| 15582 | + cycles -= cycles_used; |
| 15583 | + } |
| 15584 | + while (cycles >= 3) |
| 15585 | + { |
| 15586 | + emit_insn (gen_nop3 ()); |
| 15587 | + cycles -= 3; |
| 15588 | + } |
| 15589 | + if (cycles == 1 || cycles == 2) |
| 15590 | + { |
| 15591 | + while (cycles--) |
| 15592 | + emit_insn (gen_nop ()); |
| 15593 | + } |
| 15594 | + DONE; |
| 15595 | + ") |
| 15596 | + |
| 15597 | +(define_insn "delay_cycles_1" |
| 15598 | +[(unspec_volatile [(const_int 0)] VUNSPEC_DELAY_CYCLES_1) |
| 15599 | + (match_operand:SI 0 "immediate_operand" "") |
| 15600 | + (clobber (match_scratch:SI 1 "=&r"))] |
| 15601 | + "" |
| 15602 | + "mov\t%1, %0 |
| 15603 | + 1: sub\t%1, 1 |
| 15604 | + brne\t1b |
| 15605 | + nop" |
| 15606 | +) |
| 15607 | + |
| 15608 | +(define_insn "delay_cycles_2" |
| 15609 | +[(unspec_volatile [(const_int 0)] VUNSPEC_DELAY_CYCLES_2) |
| 15610 | + (match_operand:SI 0 "immediate_operand" "") |
| 15611 | + (clobber (match_scratch:SI 1 "=&r")) |
| 15612 | + (clobber (match_scratch:SI 2 "=&r"))] |
| 15613 | + "" |
| 15614 | + "mov\t%1, %0 |
| 15615 | + 1: mov\t%2, 16383 |
| 15616 | + 2: sub\t%2, 1 |
| 15617 | + brne\t2b |
| 15618 | + nop |
| 15619 | + sub\t%1, 1 |
| 15620 | + brne\t1b |
| 15621 | + nop" |
| 15622 | +) |
| 15623 | + |
| 15624 | +;; CPU instructions |
| 15625 | + |
| 15626 | +;;============================================================================= |
| 15627 | +;; nop |
| 15628 | +;;----------------------------------------------------------------------------- |
| 15629 | +;; No-op instruction. |
| 15630 | +;;============================================================================= |
| 15631 | +(define_insn "nop" |
| 15632 | + [(unspec_volatile [(const_int 0)] VUNSPEC_NOP)] |
| 15633 | + "" |
| 15634 | + "nop" |
| 15635 | + [(set_attr "length" "1") |
| 15636 | + (set_attr "type" "alu") |
| 15637 | + (set_attr "cc" "none")]) |
| 15638 | + |
| 15639 | +;; NOP3 |
| 15640 | +(define_insn "nop3" |
| 15641 | + [(unspec_volatile [(const_int 0)] VUNSPEC_NOP3)] |
| 15642 | + "" |
| 15643 | + "rjmp\t2" |
| 15644 | + [(set_attr "length" "3") |
| 15645 | + (set_attr "type" "alu") |
| 15646 | + (set_attr "cc" "none")]) |
| 15647 | + |
| 15648 | +;; Special patterns for dealing with the constant pool |
| 15649 | + |
| 15650 | +(define_insn "align_4" |
| 15651 | + [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN)] |
| 15652 | + "" |
| 15653 | + { |
| 15654 | + assemble_align (32); |
| 15655 | + return ""; |
| 15656 | + } |
| 15657 | + [(set_attr "length" "2")] |
| 15658 | +) |
| 15659 | + |
| 15660 | + |
| 15661 | +(define_insn "consttable_start" |
| 15662 | + [(unspec_volatile [(const_int 0)] VUNSPEC_POOL_START)] |
| 15663 | + "" |
| 15664 | + { |
| 15665 | + return ".cpool"; |
| 15666 | + } |
| 15667 | + [(set_attr "length" "0")] |
| 15668 | + ) |
| 15669 | + |
| 15670 | +(define_insn "consttable_end" |
| 15671 | + [(unspec_volatile [(const_int 0)] VUNSPEC_POOL_END)] |
| 15672 | + "" |
| 15673 | + { |
| 15674 | + making_const_table = FALSE; |
| 15675 | + return ""; |
| 15676 | + } |
| 15677 | + [(set_attr "length" "0")] |
| 15678 | +) |
| 15679 | + |
| 15680 | + |
| 15681 | +(define_insn "consttable_4" |
| 15682 | + [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_4)] |
| 15683 | + "" |
| 15684 | + { |
| 15685 | + making_const_table = TRUE; |
| 15686 | + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) |
| 15687 | + { |
| 15688 | + case MODE_FLOAT: |
| 15689 | + { |
| 15690 | + REAL_VALUE_TYPE r; |
| 15691 | + char real_string[1024]; |
| 15692 | + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); |
| 15693 | + real_to_decimal(real_string, &r, 1024, 0, 1); |
| 15694 | + asm_fprintf (asm_out_file, "\t.float\t%s\n", real_string); |
| 15695 | + break; |
| 15696 | + } |
| 15697 | + default: |
| 15698 | + assemble_integer (operands[0], 4, 0, 1); |
| 15699 | + break; |
| 15700 | + } |
| 15701 | + return ""; |
| 15702 | + } |
| 15703 | + [(set_attr "length" "4")] |
| 15704 | +) |
| 15705 | + |
| 15706 | +(define_insn "consttable_8" |
| 15707 | + [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_8)] |
| 15708 | + "" |
| 15709 | + { |
| 15710 | + making_const_table = TRUE; |
| 15711 | + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) |
| 15712 | + { |
| 15713 | + case MODE_FLOAT: |
| 15714 | + { |
| 15715 | + REAL_VALUE_TYPE r; |
| 15716 | + char real_string[1024]; |
| 15717 | + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); |
| 15718 | + real_to_decimal(real_string, &r, 1024, 0, 1); |
| 15719 | + asm_fprintf (asm_out_file, "\t.double\t%s\n", real_string); |
| 15720 | + break; |
| 15721 | + } |
| 15722 | + default: |
| 15723 | + assemble_integer(operands[0], 8, 0, 1); |
| 15724 | + break; |
| 15725 | + } |
| 15726 | + return ""; |
| 15727 | + } |
| 15728 | + [(set_attr "length" "8")] |
| 15729 | +) |
| 15730 | + |
| 15731 | +(define_insn "consttable_16" |
| 15732 | + [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_16)] |
| 15733 | + "" |
| 15734 | + { |
| 15735 | + making_const_table = TRUE; |
| 15736 | + assemble_integer(operands[0], 16, 0, 1); |
| 15737 | + return ""; |
| 15738 | + } |
| 15739 | + [(set_attr "length" "16")] |
| 15740 | +) |
| 15741 | + |
| 15742 | +;;============================================================================= |
| 15743 | +;; coprocessor instructions |
| 15744 | +;;----------------------------------------------------------------------------- |
| 15745 | +(define_insn "cop" |
| 15746 | + [ (unspec_volatile [(match_operand 0 "immediate_operand" "Ku03") |
| 15747 | + (match_operand 1 "immediate_operand" "Ku04") |
| 15748 | + (match_operand 2 "immediate_operand" "Ku04") |
| 15749 | + (match_operand 3 "immediate_operand" "Ku04") |
| 15750 | + (match_operand 4 "immediate_operand" "Ku07")] VUNSPEC_COP)] |
| 15751 | + "" |
| 15752 | + "cop\tcp%0, cr%1, cr%2, cr%3, %4" |
| 15753 | + [(set_attr "length" "4")] |
| 15754 | + ) |
| 15755 | + |
| 15756 | +(define_insn "mvcrsi" |
| 15757 | + [ (set (match_operand:SI 0 "avr32_cop_move_operand" "=r,<,Z") |
| 15758 | + (unspec_volatile:SI [(match_operand 1 "immediate_operand" "Ku03,Ku03,Ku03") |
| 15759 | + (match_operand 2 "immediate_operand" "Ku04,Ku04,Ku04")] |
| 15760 | + VUNSPEC_MVCR)) ] |
| 15761 | + "" |
| 15762 | + "@ |
| 15763 | + mvcr.w\tcp%1, %0, cr%2 |
| 15764 | + stcm.w\tcp%1, %0, cr%2 |
| 15765 | + stc.w\tcp%1, %0, cr%2" |
| 15766 | + [(set_attr "length" "4")] |
| 15767 | + ) |
| 15768 | + |
| 15769 | +(define_insn "mvcrdi" |
| 15770 | + [ (set (match_operand:DI 0 "avr32_cop_move_operand" "=r,<,Z") |
| 15771 | + (unspec_volatile:DI [(match_operand 1 "immediate_operand" "Ku03,Ku03,Ku03") |
| 15772 | + (match_operand 2 "immediate_operand" "Ku04,Ku04,Ku04")] |
| 15773 | + VUNSPEC_MVCR)) ] |
| 15774 | + "" |
| 15775 | + "@ |
| 15776 | + mvcr.d\tcp%1, %0, cr%2 |
| 15777 | + stcm.d\tcp%1, %0, cr%2-cr%i2 |
| 15778 | + stc.d\tcp%1, %0, cr%2" |
| 15779 | + [(set_attr "length" "4")] |
| 15780 | + ) |
| 15781 | + |
| 15782 | +(define_insn "mvrcsi" |
| 15783 | + [ (unspec_volatile:SI [(match_operand 0 "immediate_operand" "Ku03,Ku03,Ku03") |
| 15784 | + (match_operand 1 "immediate_operand" "Ku04,Ku04,Ku04") |
| 15785 | + (match_operand:SI 2 "avr32_cop_move_operand" "r,>,Z")] |
| 15786 | + VUNSPEC_MVRC)] |
| 15787 | + "" |
| 15788 | + { |
| 15789 | + switch (which_alternative){ |
| 15790 | + case 0: |
| 15791 | + return "mvrc.w\tcp%0, cr%1, %2"; |
| 15792 | + case 1: |
| 15793 | + return "ldcm.w\tcp%0, %2, cr%1"; |
| 15794 | + case 2: |
| 15795 | + return "ldc.w\tcp%0, cr%1, %2"; |
| 15796 | + default: |
| 15797 | + abort(); |
| 15798 | + } |
| 15799 | + } |
| 15800 | + [(set_attr "length" "4")] |
| 15801 | + ) |
| 15802 | + |
| 15803 | +(define_insn "mvrcdi" |
| 15804 | + [ (unspec_volatile:DI [(match_operand 0 "immediate_operand" "Ku03,Ku03,Ku03") |
| 15805 | + (match_operand 1 "immediate_operand" "Ku04,Ku04,Ku04") |
| 15806 | + (match_operand:DI 2 "avr32_cop_move_operand" "r,>,Z")] |
| 15807 | + VUNSPEC_MVRC)] |
| 15808 | + "" |
| 15809 | + { |
| 15810 | + switch (which_alternative){ |
| 15811 | + case 0: |
| 15812 | + return "mvrc.d\tcp%0, cr%1, %2"; |
| 15813 | + case 1: |
| 15814 | + return "ldcm.d\tcp%0, %2, cr%1-cr%i1"; |
| 15815 | + case 2: |
| 15816 | + return "ldc.d\tcp%0, cr%1, %2"; |
| 15817 | + default: |
| 15818 | + abort(); |
| 15819 | + } |
| 15820 | + } |
| 15821 | + [(set_attr "length" "4")] |
| 15822 | + ) |
| 15823 | + |
| 15824 | +;;============================================================================= |
| 15825 | +;; epilogue |
| 15826 | +;;----------------------------------------------------------------------------- |
| 15827 | +;; This pattern emits RTL for exit from a function. The function exit is |
| 15828 | +;; responsible for deallocating the stack frame, restoring callee saved |
| 15829 | +;; registers and emitting the return instruction. |
| 15830 | +;; ToDo: using TARGET_ASM_FUNCTION_PROLOGUE instead. |
| 15831 | +;;============================================================================= |
| 15832 | +(define_expand "epilogue" |
| 15833 | + [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)] |
| 15834 | + "" |
| 15835 | + " |
| 15836 | + if (USE_RETURN_INSN (FALSE)){ |
| 15837 | + emit_jump_insn (gen_return ()); |
| 15838 | + DONE; |
| 15839 | + } |
| 15840 | + emit_jump_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode, |
| 15841 | + gen_rtvec (1, |
| 15842 | + gen_rtx_RETURN (VOIDmode)), |
| 15843 | + VUNSPEC_EPILOGUE)); |
| 15844 | + DONE; |
| 15845 | + " |
| 15846 | + ) |
| 15847 | + |
| 15848 | +(define_insn "*epilogue_insns" |
| 15849 | + [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)] |
| 15850 | + "" |
| 15851 | + { |
| 15852 | + avr32_output_return_instruction (FALSE, FALSE, NULL, NULL); |
| 15853 | + return ""; |
| 15854 | + } |
| 15855 | + ; Length is absolute worst case |
| 15856 | + [(set_attr "type" "branch") |
| 15857 | + (set_attr "length" "12")] |
| 15858 | + ) |
| 15859 | + |
| 15860 | +(define_insn "*epilogue_insns_ret_imm" |
| 15861 | + [(parallel [(set (reg RETVAL_REGNUM) (match_operand 0 "immediate_operand" "i")) |
| 15862 | + (use (reg RETVAL_REGNUM)) |
| 15863 | + (unspec_volatile [(return)] VUNSPEC_EPILOGUE)])] |
| 15864 | + "((INTVAL(operands[0]) == -1) || (INTVAL(operands[0]) == 0) || (INTVAL(operands[0]) == 1))" |
| 15865 | + { |
| 15866 | + avr32_output_return_instruction (FALSE, FALSE, NULL, operands[0]); |
| 15867 | + return ""; |
| 15868 | + } |
| 15869 | + ; Length is absolute worst case |
| 15870 | + [(set_attr "type" "branch") |
| 15871 | + (set_attr "length" "12")] |
| 15872 | + ) |
| 15873 | + |
| 15874 | +(define_insn "sibcall_epilogue" |
| 15875 | + [(unspec_volatile [(const_int 0)] VUNSPEC_EPILOGUE)] |
| 15876 | + "" |
| 15877 | + { |
| 15878 | + avr32_output_return_instruction (FALSE, FALSE, NULL, NULL); |
| 15879 | + return ""; |
| 15880 | + } |
| 15881 | +;; Length is absolute worst case |
| 15882 | + [(set_attr "type" "branch") |
| 15883 | + (set_attr "length" "12")] |
| 15884 | + ) |
| 15885 | + |
| 15886 | +(define_insn "*sibcall_epilogue_insns_ret_imm" |
| 15887 | + [(parallel [(set (reg RETVAL_REGNUM) (match_operand 0 "immediate_operand" "i")) |
| 15888 | + (use (reg RETVAL_REGNUM)) |
| 15889 | + (unspec_volatile [(const_int 0)] VUNSPEC_EPILOGUE)])] |
| 15890 | + "((INTVAL(operands[0]) == -1) || (INTVAL(operands[0]) == 0) || (INTVAL(operands[0]) == 1))" |
| 15891 | + { |
| 15892 | + avr32_output_return_instruction (FALSE, FALSE, NULL, operands[0]); |
| 15893 | + return ""; |
| 15894 | + } |
| 15895 | + ; Length is absolute worst case |
| 15896 | + [(set_attr "type" "branch") |
| 15897 | + (set_attr "length" "12")] |
| 15898 | + ) |
| 15899 | + |
| 15900 | +(define_insn "ldxi" |
| 15901 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 15902 | + (mem:SI (plus:SI |
| 15903 | + (match_operand:SI 1 "register_operand" "r") |
| 15904 | + (mult:SI (zero_extract:SI (match_operand:SI 2 "register_operand" "r") |
| 15905 | + (const_int 8) |
| 15906 | + (match_operand:SI 3 "immediate_operand" "Ku05")) |
| 15907 | + (const_int 4)))))] |
| 15908 | + "(INTVAL(operands[3]) == 24 || INTVAL(operands[3]) == 16 || INTVAL(operands[3]) == 8 |
| 15909 | + || INTVAL(operands[3]) == 0)" |
| 15910 | + { |
| 15911 | + switch ( INTVAL(operands[3]) ){ |
| 15912 | + case 0: |
| 15913 | + return "ld.w %0, %1[%2:b << 2]"; |
| 15914 | + case 8: |
| 15915 | + return "ld.w %0, %1[%2:l << 2]"; |
| 15916 | + case 16: |
| 15917 | + return "ld.w %0, %1[%2:u << 2]"; |
| 15918 | + case 24: |
| 15919 | + return "ld.w %0, %1[%2:t << 2]"; |
| 15920 | + default: |
| 15921 | + internal_error("illegal operand for ldxi"); |
| 15922 | + } |
| 15923 | + } |
| 15924 | + [(set_attr "type" "load") |
| 15925 | + (set_attr "length" "4") |
| 15926 | + (set_attr "cc" "none")]) |
| 15927 | + |
| 15928 | + |
| 15929 | + |
| 15930 | + |
| 15931 | + |
| 15932 | + |
| 15933 | +;;============================================================================= |
| 15934 | +;; Peephole optimizing |
| 15935 | +;;----------------------------------------------------------------------------- |
| 15936 | +;; Changing |
| 15937 | +;; sub r8, r7, 8 |
| 15938 | +;; st.w r8[0x0], r12 |
| 15939 | +;; to |
| 15940 | +;; sub r8, r7, 8 |
| 15941 | +;; st.w r7[-0x8], r12 |
| 15942 | +;;============================================================================= |
| 15943 | +; (set (reg:SI 9 r8) |
| 15944 | +; (plus:SI (reg/f:SI 6 r7) |
| 15945 | +; (const_int ...))) |
| 15946 | +; (set (mem:SI (reg:SI 9 r8)) |
| 15947 | +; (reg:SI 12 r12)) |
| 15948 | +(define_peephole2 |
| 15949 | + [(set (match_operand:SI 0 "register_operand" "") |
| 15950 | + (plus:SI (match_operand:SI 1 "register_operand" "") |
| 15951 | + (match_operand:SI 2 "immediate_operand" ""))) |
| 15952 | + (set (mem:SI (match_dup 0)) |
| 15953 | + (match_operand:SI 3 "register_operand" ""))] |
| 15954 | + "REGNO(operands[0]) != REGNO(operands[1]) && avr32_const_ok_for_constraint_p(INTVAL(operands[2]), 'K', \"Ks16\")" |
| 15955 | + [(set (match_dup 0) |
| 15956 | + (plus:SI (match_dup 1) |
| 15957 | + (match_dup 2))) |
| 15958 | + (set (mem:SI (plus:SI (match_dup 1) |
| 15959 | + (match_dup 2))) |
| 15960 | + (match_dup 3))] |
| 15961 | + "") |
| 15962 | + |
| 15963 | +;;============================================================================= |
| 15964 | +;; Peephole optimizing |
| 15965 | +;;----------------------------------------------------------------------------- |
| 15966 | +;; Changing |
| 15967 | +;; sub r6, r7, 4 |
| 15968 | +;; ld.w r6, r6[0x0] |
| 15969 | +;; to |
| 15970 | +;; sub r6, r7, 4 |
| 15971 | +;; ld.w r6, r7[-0x4] |
| 15972 | +;;============================================================================= |
| 15973 | +; (set (reg:SI 7 r6) |
| 15974 | +; (plus:SI (reg/f:SI 6 r7) |
| 15975 | +; (const_int -4 [0xfffffffc]))) |
| 15976 | +; (set (reg:SI 7 r6) |
| 15977 | +; (mem:SI (reg:SI 7 r6))) |
| 15978 | +(define_peephole2 |
| 15979 | + [(set (match_operand:SI 0 "register_operand" "") |
| 15980 | + (plus:SI (match_operand:SI 1 "register_operand" "") |
| 15981 | + (match_operand:SI 2 "immediate_operand" ""))) |
| 15982 | + (set (match_operand:SI 3 "register_operand" "") |
| 15983 | + (mem:SI (match_dup 0)))] |
| 15984 | + "REGNO(operands[0]) != REGNO(operands[1]) && avr32_const_ok_for_constraint_p(INTVAL(operands[2]), 'K', \"Ks16\")" |
| 15985 | + [(set (match_dup 0) |
| 15986 | + (plus:SI (match_dup 1) |
| 15987 | + (match_dup 2))) |
| 15988 | + (set (match_dup 3) |
| 15989 | + (mem:SI (plus:SI (match_dup 1) |
| 15990 | + (match_dup 2))))] |
| 15991 | + "") |
| 15992 | + |
| 15993 | +;;============================================================================= |
| 15994 | +;; Peephole optimizing |
| 15995 | +;;----------------------------------------------------------------------------- |
| 15996 | +;; Changing |
| 15997 | +;; ld.sb r0, r7[-0x6] |
| 15998 | +;; cashs.b r0 |
| 15999 | +;; to |
| 16000 | +;; ld.sb r0, r7[-0x6] |
| 16001 | +;;============================================================================= |
| 16002 | +(define_peephole2 |
| 16003 | + [(set (match_operand:QI 0 "register_operand" "") |
| 16004 | + (match_operand:QI 1 "load_sb_memory_operand" "")) |
| 16005 | + (set (match_operand:SI 2 "register_operand" "") |
| 16006 | + (sign_extend:SI (match_dup 0)))] |
| 16007 | + "(REGNO(operands[0]) == REGNO(operands[2]) || peep2_reg_dead_p(2, operands[0]))" |
| 16008 | + [(set (match_dup 2) |
| 16009 | + (sign_extend:SI (match_dup 1)))] |
| 16010 | + "") |
| 16011 | + |
| 16012 | +;;============================================================================= |
| 16013 | +;; Peephole optimizing |
| 16014 | +;;----------------------------------------------------------------------------- |
| 16015 | +;; Changing |
| 16016 | +;; ld.ub r0, r7[-0x6] |
| 16017 | +;; cashu.b r0 |
| 16018 | +;; to |
| 16019 | +;; ld.ub r0, r7[-0x6] |
| 16020 | +;;============================================================================= |
| 16021 | +(define_peephole2 |
| 16022 | + [(set (match_operand:QI 0 "register_operand" "") |
| 16023 | + (match_operand:QI 1 "memory_operand" "")) |
| 16024 | + (set (match_operand:SI 2 "register_operand" "") |
| 16025 | + (zero_extend:SI (match_dup 0)))] |
| 16026 | + "(REGNO(operands[0]) == REGNO(operands[2])) || peep2_reg_dead_p(2, operands[0])" |
| 16027 | + [(set (match_dup 2) |
| 16028 | + (zero_extend:SI (match_dup 1)))] |
| 16029 | + "") |
| 16030 | + |
| 16031 | +;;============================================================================= |
| 16032 | +;; Peephole optimizing |
| 16033 | +;;----------------------------------------------------------------------------- |
| 16034 | +;; Changing |
| 16035 | +;; ld.sh r0, r7[-0x6] |
| 16036 | +;; casts.h r0 |
| 16037 | +;; to |
| 16038 | +;; ld.sh r0, r7[-0x6] |
| 16039 | +;;============================================================================= |
| 16040 | +(define_peephole2 |
| 16041 | + [(set (match_operand:HI 0 "register_operand" "") |
| 16042 | + (match_operand:HI 1 "memory_operand" "")) |
| 16043 | + (set (match_operand:SI 2 "register_operand" "") |
| 16044 | + (sign_extend:SI (match_dup 0)))] |
| 16045 | + "(REGNO(operands[0]) == REGNO(operands[2])) || peep2_reg_dead_p(2, operands[0])" |
| 16046 | + [(set (match_dup 2) |
| 16047 | + (sign_extend:SI (match_dup 1)))] |
| 16048 | + "") |
| 16049 | + |
| 16050 | +;;============================================================================= |
| 16051 | +;; Peephole optimizing |
| 16052 | +;;----------------------------------------------------------------------------- |
| 16053 | +;; Changing |
| 16054 | +;; ld.uh r0, r7[-0x6] |
| 16055 | +;; castu.h r0 |
| 16056 | +;; to |
| 16057 | +;; ld.uh r0, r7[-0x6] |
| 16058 | +;;============================================================================= |
| 16059 | +(define_peephole2 |
| 16060 | + [(set (match_operand:HI 0 "register_operand" "") |
| 16061 | + (match_operand:HI 1 "memory_operand" "")) |
| 16062 | + (set (match_operand:SI 2 "register_operand" "") |
| 16063 | + (zero_extend:SI (match_dup 0)))] |
| 16064 | + "(REGNO(operands[0]) == REGNO(operands[2])) || peep2_reg_dead_p(2, operands[0])" |
| 16065 | + [(set (match_dup 2) |
| 16066 | + (zero_extend:SI (match_dup 1)))] |
| 16067 | + "") |
| 16068 | + |
| 16069 | +;;============================================================================= |
| 16070 | +;; Peephole optimizing |
| 16071 | +;;----------------------------------------------------------------------------- |
| 16072 | +;; Changing |
| 16073 | +;; mul rd, rx, ry |
| 16074 | +;; add rd2, rd |
| 16075 | +;; or |
| 16076 | +;; add rd2, rd, rd2 |
| 16077 | +;; to |
| 16078 | +;; mac rd2, rx, ry |
| 16079 | +;;============================================================================= |
| 16080 | +(define_peephole2 |
| 16081 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16082 | + (mult:SI (match_operand:SI 1 "register_operand" "") |
| 16083 | + (match_operand:SI 2 "register_operand" ""))) |
| 16084 | + (set (match_operand:SI 3 "register_operand" "") |
| 16085 | + (plus:SI (match_dup 3) |
| 16086 | + (match_dup 0)))] |
| 16087 | + "peep2_reg_dead_p(2, operands[0])" |
| 16088 | + [(set (match_dup 3) |
| 16089 | + (plus:SI (mult:SI (match_dup 1) |
| 16090 | + (match_dup 2)) |
| 16091 | + (match_dup 3)))] |
| 16092 | + "") |
| 16093 | + |
| 16094 | +(define_peephole2 |
| 16095 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16096 | + (mult:SI (match_operand:SI 1 "register_operand" "") |
| 16097 | + (match_operand:SI 2 "register_operand" ""))) |
| 16098 | + (set (match_operand:SI 3 "register_operand" "") |
| 16099 | + (plus:SI (match_dup 0) |
| 16100 | + (match_dup 3)))] |
| 16101 | + "peep2_reg_dead_p(2, operands[0])" |
| 16102 | + [(set (match_dup 3) |
| 16103 | + (plus:SI (mult:SI (match_dup 1) |
| 16104 | + (match_dup 2)) |
| 16105 | + (match_dup 3)))] |
| 16106 | + "") |
| 16107 | + |
| 16108 | + |
| 16109 | +;;============================================================================= |
| 16110 | +;; Peephole optimizing |
| 16111 | +;;----------------------------------------------------------------------------- |
| 16112 | +;; Changing |
| 16113 | +;; bfextu rd, rs, k5, 1 or and(h/l) rd, one_bit_set_mask |
| 16114 | +;; to |
| 16115 | +;; bld rs, k5 |
| 16116 | +;; |
| 16117 | +;; If rd is dead after the operation. |
| 16118 | +;;============================================================================= |
| 16119 | +(define_peephole2 |
| 16120 | + [ (set (match_operand:SI 0 "register_operand" "") |
| 16121 | + (zero_extract:SI (match_operand:SI 1 "register_operand" "") |
| 16122 | + (const_int 1) |
| 16123 | + (match_operand:SI 2 "immediate_operand" ""))) |
| 16124 | + (set (cc0) |
| 16125 | + (match_dup 0))] |
| 16126 | + "peep2_reg_dead_p(2, operands[0])" |
| 16127 | + [(set (cc0) |
| 16128 | + (and:SI (match_dup 1) |
| 16129 | + (match_dup 2)))] |
| 16130 | + "operands[2] = GEN_INT(1 << INTVAL(operands[2]));") |
| 16131 | + |
| 16132 | +(define_peephole2 |
| 16133 | + [ (set (match_operand:SI 0 "register_operand" "") |
| 16134 | + (and:SI (match_operand:SI 1 "register_operand" "") |
| 16135 | + (match_operand:SI 2 "one_bit_set_operand" ""))) |
| 16136 | + (set (cc0) |
| 16137 | + (match_dup 0))] |
| 16138 | + "peep2_reg_dead_p(2, operands[0])" |
| 16139 | + [(set (cc0) |
| 16140 | + (and:SI (match_dup 1) |
| 16141 | + (match_dup 2)))] |
| 16142 | + "") |
| 16143 | + |
| 16144 | +;;============================================================================= |
| 16145 | +;; Peephole optimizing |
| 16146 | +;;----------------------------------------------------------------------------- |
| 16147 | +;; Load with extracted index: ld.w Rd, Rb[Ri:{t/u/b/l} << 2] |
| 16148 | +;; |
| 16149 | +;;============================================================================= |
| 16150 | + |
| 16151 | + |
| 16152 | +(define_peephole |
| 16153 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16154 | + (zero_extract:SI (match_operand:SI 1 "register_operand" "") |
| 16155 | + (const_int 8) |
| 16156 | + (match_operand:SI 2 "avr32_extract_shift_operand" ""))) |
| 16157 | + (set (match_operand:SI 3 "register_operand" "") |
| 16158 | + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) |
| 16159 | + (match_operand:SI 4 "register_operand" ""))))] |
| 16160 | + |
| 16161 | + "(dead_or_set_p(insn, operands[0]))" |
| 16162 | + { |
| 16163 | + switch ( INTVAL(operands[2]) ){ |
| 16164 | + case 0: |
| 16165 | + return "ld.w %3, %4[%1:b << 2]"; |
| 16166 | + case 8: |
| 16167 | + return "ld.w %3, %4[%1:l << 2]"; |
| 16168 | + case 16: |
| 16169 | + return "ld.w %3, %4[%1:u << 2]"; |
| 16170 | + case 24: |
| 16171 | + return "ld.w %3, %4[%1:t << 2]"; |
| 16172 | + default: |
| 16173 | + internal_error("illegal operand for ldxi"); |
| 16174 | + } |
| 16175 | + } |
| 16176 | + [(set_attr "type" "load") |
| 16177 | + (set_attr "length" "4") |
| 16178 | + (set_attr "cc" "clobber")] |
| 16179 | + ) |
| 16180 | + |
| 16181 | + |
| 16182 | + |
| 16183 | +(define_peephole |
| 16184 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16185 | + (and:SI (match_operand:SI 1 "register_operand" "") (const_int 255))) |
| 16186 | + (set (match_operand:SI 2 "register_operand" "") |
| 16187 | + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) |
| 16188 | + (match_operand:SI 3 "register_operand" ""))))] |
| 16189 | + |
| 16190 | + "(dead_or_set_p(insn, operands[0]))" |
| 16191 | + |
| 16192 | + "ld.w %2, %3[%1:b << 2]" |
| 16193 | + [(set_attr "type" "load") |
| 16194 | + (set_attr "length" "4") |
| 16195 | + (set_attr "cc" "clobber")] |
| 16196 | + ) |
| 16197 | + |
| 16198 | + |
| 16199 | +(define_peephole2 |
| 16200 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16201 | + (zero_extract:SI (match_operand:SI 1 "register_operand" "") |
| 16202 | + (const_int 8) |
| 16203 | + (match_operand:SI 2 "avr32_extract_shift_operand" ""))) |
| 16204 | + (set (match_operand:SI 3 "register_operand" "") |
| 16205 | + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) |
| 16206 | + (match_operand:SI 4 "register_operand" ""))))] |
| 16207 | + |
| 16208 | + "(peep2_reg_dead_p(2, operands[0])) |
| 16209 | + || (REGNO(operands[0]) == REGNO(operands[3]))" |
| 16210 | + [(set (match_dup 3) |
| 16211 | + (mem:SI (plus:SI |
| 16212 | + (match_dup 4) |
| 16213 | + (mult:SI (zero_extract:SI (match_dup 1) |
| 16214 | + (const_int 8) |
| 16215 | + (match_dup 2)) |
| 16216 | + (const_int 4)))))] |
| 16217 | + ) |
| 16218 | + |
| 16219 | +(define_peephole2 |
| 16220 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16221 | + (zero_extend:SI (match_operand:QI 1 "register_operand" ""))) |
| 16222 | + (set (match_operand:SI 2 "register_operand" "") |
| 16223 | + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) |
| 16224 | + (match_operand:SI 3 "register_operand" ""))))] |
| 16225 | + |
| 16226 | + "(peep2_reg_dead_p(2, operands[0])) |
| 16227 | + || (REGNO(operands[0]) == REGNO(operands[2]))" |
| 16228 | + [(set (match_dup 2) |
| 16229 | + (mem:SI (plus:SI |
| 16230 | + (match_dup 3) |
| 16231 | + (mult:SI (zero_extract:SI (match_dup 1) |
| 16232 | + (const_int 8) |
| 16233 | + (const_int 0)) |
| 16234 | + (const_int 4)))))] |
| 16235 | + "operands[1] = gen_rtx_REG(SImode, REGNO(operands[1]));" |
| 16236 | + ) |
| 16237 | + |
| 16238 | + |
| 16239 | +(define_peephole2 |
| 16240 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16241 | + (and:SI (match_operand:SI 1 "register_operand" "") |
| 16242 | + (const_int 255))) |
| 16243 | + (set (match_operand:SI 2 "register_operand" "") |
| 16244 | + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) |
| 16245 | + (match_operand:SI 3 "register_operand" ""))))] |
| 16246 | + |
| 16247 | + "(peep2_reg_dead_p(2, operands[0])) |
| 16248 | + || (REGNO(operands[0]) == REGNO(operands[2]))" |
| 16249 | + [(set (match_dup 2) |
| 16250 | + (mem:SI (plus:SI |
| 16251 | + (match_dup 3) |
| 16252 | + (mult:SI (zero_extract:SI (match_dup 1) |
| 16253 | + (const_int 8) |
| 16254 | + (const_int 0)) |
| 16255 | + (const_int 4)))))] |
| 16256 | + "" |
| 16257 | + ) |
| 16258 | + |
| 16259 | + |
| 16260 | + |
| 16261 | +(define_peephole2 |
| 16262 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16263 | + (lshiftrt:SI (match_operand:SI 1 "register_operand" "") |
| 16264 | + (const_int 24))) |
| 16265 | + (set (match_operand:SI 2 "register_operand" "") |
| 16266 | + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) |
| 16267 | + (match_operand:SI 3 "register_operand" ""))))] |
| 16268 | + |
| 16269 | + "(peep2_reg_dead_p(2, operands[0])) |
| 16270 | + || (REGNO(operands[0]) == REGNO(operands[2]))" |
| 16271 | + [(set (match_dup 2) |
| 16272 | + (mem:SI (plus:SI |
| 16273 | + (match_dup 3) |
| 16274 | + (mult:SI (zero_extract:SI (match_dup 1) |
| 16275 | + (const_int 8) |
| 16276 | + (const_int 24)) |
| 16277 | + (const_int 4)))))] |
| 16278 | + "" |
| 16279 | + ) |
| 16280 | + |
| 16281 | + |
| 16282 | +;;************************************************ |
| 16283 | +;; ANDN |
| 16284 | +;; |
| 16285 | +;;************************************************ |
| 16286 | + |
| 16287 | + |
| 16288 | +(define_peephole2 |
| 16289 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16290 | + (not:SI (match_operand:SI 1 "register_operand" ""))) |
| 16291 | + (set (match_operand:SI 2 "register_operand" "") |
| 16292 | + (and:SI (match_dup 2) |
| 16293 | + (match_dup 0)))] |
| 16294 | + "peep2_reg_dead_p(2, operands[0])" |
| 16295 | + |
| 16296 | + [(set (match_dup 2) |
| 16297 | + (and:SI (match_dup 2) |
| 16298 | + (not:SI (match_dup 1)) |
| 16299 | + ))] |
| 16300 | + "" |
| 16301 | +) |
| 16302 | + |
| 16303 | +(define_peephole2 |
| 16304 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16305 | + (not:SI (match_operand:SI 1 "register_operand" ""))) |
| 16306 | + (set (match_operand:SI 2 "register_operand" "") |
| 16307 | + (and:SI (match_dup 0) |
| 16308 | + (match_dup 2) |
| 16309 | + ))] |
| 16310 | + "peep2_reg_dead_p(2, operands[0])" |
| 16311 | + |
| 16312 | + [(set (match_dup 2) |
| 16313 | + (and:SI (match_dup 2) |
| 16314 | + (not:SI (match_dup 1)) |
| 16315 | + ))] |
| 16316 | + |
| 16317 | + "" |
| 16318 | +) |
| 16319 | + |
| 16320 | + |
| 16321 | +;;================================================================= |
| 16322 | +;; Addabs peephole |
| 16323 | +;;================================================================= |
| 16324 | + |
| 16325 | +(define_peephole |
| 16326 | + [(set (match_operand:SI 2 "register_operand" "=r") |
| 16327 | + (abs:SI (match_operand:SI 1 "register_operand" "r"))) |
| 16328 | + (set (match_operand:SI 0 "register_operand" "=r") |
| 16329 | + (plus:SI (match_operand:SI 3 "register_operand" "r") |
| 16330 | + (match_dup 2)))] |
| 16331 | + "dead_or_set_p(insn, operands[2])" |
| 16332 | + "addabs %0, %3, %1" |
| 16333 | + [(set_attr "length" "4") |
| 16334 | + (set_attr "cc" "set_z")]) |
| 16335 | + |
| 16336 | +(define_peephole |
| 16337 | + [(set (match_operand:SI 2 "register_operand" "=r") |
| 16338 | + (abs:SI (match_operand:SI 1 "register_operand" "r"))) |
| 16339 | + (set (match_operand:SI 0 "register_operand" "=r") |
| 16340 | + (plus:SI (match_dup 2) |
| 16341 | + (match_operand:SI 3 "register_operand" "r")))] |
| 16342 | + "dead_or_set_p(insn, operands[2])" |
| 16343 | + "addabs %0, %3, %1" |
| 16344 | + [(set_attr "length" "4") |
| 16345 | + (set_attr "cc" "set_z")]) |
| 16346 | + |
| 16347 | + |
| 16348 | +;;================================================================= |
| 16349 | +;; Detect roundings |
| 16350 | +;;================================================================= |
| 16351 | + |
| 16352 | +(define_insn "*round" |
| 16353 | + [(set (match_operand:SI 0 "register_operand" "+r") |
| 16354 | + (ashiftrt:SI (plus:SI (match_dup 0) |
| 16355 | + (match_operand:SI 1 "immediate_operand" "i")) |
| 16356 | + (match_operand:SI 2 "immediate_operand" "i")))] |
| 16357 | + "avr32_rnd_operands(operands[1], operands[2])" |
| 16358 | + |
| 16359 | + "satrnds %0 >> %2, 31" |
| 16360 | + |
| 16361 | + [(set_attr "type" "alu_sat") |
| 16362 | + (set_attr "length" "4")] |
| 16363 | + |
| 16364 | + ) |
| 16365 | + |
| 16366 | + |
| 16367 | +(define_peephole2 |
| 16368 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16369 | + (plus:SI (match_dup 0) |
| 16370 | + (match_operand:SI 1 "immediate_operand" ""))) |
| 16371 | + (set (match_dup 0) |
| 16372 | + (ashiftrt:SI (match_dup 0) |
| 16373 | + (match_operand:SI 2 "immediate_operand" "")))] |
| 16374 | + "avr32_rnd_operands(operands[1], operands[2])" |
| 16375 | + |
| 16376 | + [(set (match_dup 0) |
| 16377 | + (ashiftrt:SI (plus:SI (match_dup 0) |
| 16378 | + (match_dup 1)) |
| 16379 | + (match_dup 2)))] |
| 16380 | + ) |
| 16381 | + |
| 16382 | +(define_peephole |
| 16383 | + [(set (match_operand:SI 0 "register_operand" "r") |
| 16384 | + (plus:SI (match_dup 0) |
| 16385 | + (match_operand:SI 1 "immediate_operand" "i"))) |
| 16386 | + (set (match_dup 0) |
| 16387 | + (ashiftrt:SI (match_dup 0) |
| 16388 | + (match_operand:SI 2 "immediate_operand" "i")))] |
| 16389 | + "avr32_rnd_operands(operands[1], operands[2])" |
| 16390 | + |
| 16391 | + "satrnds %0 >> %2, 31" |
| 16392 | + |
| 16393 | + [(set_attr "type" "alu_sat") |
| 16394 | + (set_attr "length" "4") |
| 16395 | + (set_attr "cc" "clobber")] |
| 16396 | + |
| 16397 | + ) |
| 16398 | + |
| 16399 | + |
| 16400 | +;;================================================================= |
| 16401 | +;; mcall |
| 16402 | +;;================================================================= |
| 16403 | +(define_peephole |
| 16404 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16405 | + (match_operand 1 "avr32_const_pool_ref_operand" "")) |
| 16406 | + (parallel [(call (mem:SI (match_dup 0)) |
| 16407 | + (match_operand 2 "" "")) |
| 16408 | + (clobber (reg:SI LR_REGNUM))])] |
| 16409 | + "dead_or_set_p(insn, operands[0])" |
| 16410 | + "mcall %1" |
| 16411 | + [(set_attr "type" "call") |
| 16412 | + (set_attr "length" "4") |
| 16413 | + (set_attr "cc" "clobber")] |
| 16414 | +) |
| 16415 | + |
| 16416 | +(define_peephole |
| 16417 | + [(set (match_operand:SI 2 "register_operand" "") |
| 16418 | + (match_operand 1 "avr32_const_pool_ref_operand" "")) |
| 16419 | + (parallel [(set (match_operand 0 "register_operand" "") |
| 16420 | + (call (mem:SI (match_dup 2)) |
| 16421 | + (match_operand 3 "" ""))) |
| 16422 | + (clobber (reg:SI LR_REGNUM))])] |
| 16423 | + "dead_or_set_p(insn, operands[2])" |
| 16424 | + "mcall %1" |
| 16425 | + [(set_attr "type" "call") |
| 16426 | + (set_attr "length" "4") |
| 16427 | + (set_attr "cc" "call_set")] |
| 16428 | +) |
| 16429 | + |
| 16430 | + |
| 16431 | +(define_peephole2 |
| 16432 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16433 | + (match_operand 1 "avr32_const_pool_ref_operand" "")) |
| 16434 | + (parallel [(call (mem:SI (match_dup 0)) |
| 16435 | + (match_operand 2 "" "")) |
| 16436 | + (clobber (reg:SI LR_REGNUM))])] |
| 16437 | + "peep2_reg_dead_p(2, operands[0])" |
| 16438 | + [(parallel [(call (mem:SI (match_dup 1)) |
| 16439 | + (match_dup 2)) |
| 16440 | + (clobber (reg:SI LR_REGNUM))])] |
| 16441 | + "" |
| 16442 | +) |
| 16443 | + |
| 16444 | +(define_peephole2 |
| 16445 | + [(set (match_operand:SI 0 "register_operand" "") |
| 16446 | + (match_operand 1 "avr32_const_pool_ref_operand" "")) |
| 16447 | + (parallel [(set (match_operand 2 "register_operand" "") |
| 16448 | + (call (mem:SI (match_dup 0)) |
| 16449 | + (match_operand 3 "" ""))) |
| 16450 | + (clobber (reg:SI LR_REGNUM))])] |
| 16451 | + "(peep2_reg_dead_p(2, operands[0]) || (REGNO(operands[2]) == REGNO(operands[0])))" |
| 16452 | + [(parallel [(set (match_dup 2) |
| 16453 | + (call (mem:SI (match_dup 1)) |
| 16454 | + (match_dup 3))) |
| 16455 | + (clobber (reg:SI LR_REGNUM))])] |
| 16456 | + "" |
| 16457 | +) |
| 16458 | + |
| 16459 | +;;================================================================= |
| 16460 | +;; Returning a value |
| 16461 | +;;================================================================= |
| 16462 | + |
| 16463 | + |
| 16464 | +(define_peephole |
| 16465 | + [(set (match_operand 0 "register_operand" "") |
| 16466 | + (match_operand 1 "register_operand" "")) |
| 16467 | + (return)] |
| 16468 | + "USE_RETURN_INSN (TRUE) && (REGNO(operands[0]) == RETVAL_REGNUM) |
| 16469 | + && (REGNO(operands[1]) != LR_REGNUM) |
| 16470 | + && (REGNO_REG_CLASS(REGNO(operands[1])) == GENERAL_REGS)" |
| 16471 | + "retal %1" |
| 16472 | + [(set_attr "type" "call") |
| 16473 | + (set_attr "length" "2")] |
| 16474 | + ) |
| 16475 | + |
| 16476 | + |
| 16477 | +(define_peephole |
| 16478 | + [(set (match_operand 0 "register_operand" "r") |
| 16479 | + (match_operand 1 "immediate_operand" "i")) |
| 16480 | + (return)] |
| 16481 | + "(USE_RETURN_INSN (FALSE) && (REGNO(operands[0]) == RETVAL_REGNUM) && |
| 16482 | + ((INTVAL(operands[1]) == -1) || (INTVAL(operands[1]) == 0) || (INTVAL(operands[1]) == 1)))" |
| 16483 | + { |
| 16484 | + avr32_output_return_instruction (TRUE, FALSE, NULL, operands[1]); |
| 16485 | + return ""; |
| 16486 | + } |
| 16487 | + [(set_attr "type" "call") |
| 16488 | + (set_attr "length" "4")] |
| 16489 | + ) |
| 16490 | + |
| 16491 | +(define_peephole |
| 16492 | + [(set (match_operand 0 "register_operand" "r") |
| 16493 | + (match_operand 1 "immediate_operand" "i")) |
| 16494 | + (unspec_volatile [(return)] VUNSPEC_EPILOGUE)] |
| 16495 | + "(REGNO(operands[0]) == RETVAL_REGNUM) && |
| 16496 | + ((INTVAL(operands[1]) == -1) || (INTVAL(operands[1]) == 0) || (INTVAL(operands[1]) == 1))" |
| 16497 | + { |
| 16498 | + avr32_output_return_instruction (FALSE, FALSE, NULL, operands[1]); |
| 16499 | + return ""; |
| 16500 | + } |
| 16501 | + ; Length is absolute worst case |
| 16502 | + [(set_attr "type" "branch") |
| 16503 | + (set_attr "length" "12")] |
| 16504 | + ) |
| 16505 | + |
| 16506 | +(define_peephole |
| 16507 | + [(set (match_operand 0 "register_operand" "=r") |
| 16508 | + (if_then_else (match_operator 1 "avr32_comparison_operator" |
| 16509 | + [(match_operand 4 "register_operand" "r") |
| 16510 | + (match_operand 5 "register_immediate_operand" "rKs21")]) |
| 16511 | + (match_operand 2 "avr32_cond_register_immediate_operand" "rKs08") |
| 16512 | + (match_operand 3 "avr32_cond_register_immediate_operand" "rKs08"))) |
| 16513 | + (return)] |
| 16514 | + "USE_RETURN_INSN (TRUE) && (REGNO(operands[0]) == RETVAL_REGNUM)" |
| 16515 | + { |
| 16516 | + operands[1] = avr32_output_cmp(operands[1], GET_MODE(operands[4]), operands[4], operands[5]); |
| 16517 | + |
| 16518 | + if ( GET_CODE(operands[2]) == REG |
| 16519 | + && GET_CODE(operands[3]) == REG |
| 16520 | + && REGNO(operands[2]) != LR_REGNUM |
| 16521 | + && REGNO(operands[3]) != LR_REGNUM ){ |
| 16522 | + return "ret%1 %2\;ret%i1 %3"; |
| 16523 | + } else if ( GET_CODE(operands[2]) == REG |
| 16524 | + && GET_CODE(operands[3]) == CONST_INT ){ |
| 16525 | + if ( INTVAL(operands[3]) == -1 |
| 16526 | + || INTVAL(operands[3]) == 0 |
| 16527 | + || INTVAL(operands[3]) == 1 ){ |
| 16528 | + return "ret%1 %2\;ret%i1 %d3"; |
| 16529 | + } else { |
| 16530 | + return "mov%1 r12, %2\;mov%i1 r12, %3\;retal r12"; |
| 16531 | + } |
| 16532 | + } else if ( GET_CODE(operands[2]) == CONST_INT |
| 16533 | + && GET_CODE(operands[3]) == REG ){ |
| 16534 | + if ( INTVAL(operands[2]) == -1 |
| 16535 | + || INTVAL(operands[2]) == 0 |
| 16536 | + || INTVAL(operands[2]) == 1 ){ |
| 16537 | + return "ret%1 %d2\;ret%i1 %3"; |
| 16538 | + } else { |
| 16539 | + return "mov%1 r12, %2\;mov%i1 r12, %3\;retal r12"; |
| 16540 | + } |
| 16541 | + } else { |
| 16542 | + if ( (INTVAL(operands[2]) == -1 |
| 16543 | + || INTVAL(operands[2]) == 0 |
| 16544 | + || INTVAL(operands[2]) == 1 ) |
| 16545 | + && (INTVAL(operands[3]) == -1 |
| 16546 | + || INTVAL(operands[3]) == 0 |
| 16547 | + || INTVAL(operands[3]) == 1 )){ |
| 16548 | + return "ret%1 %d2\;ret%i1 %d3"; |
| 16549 | + } else { |
| 16550 | + return "mov%1 r12, %2\;mov%i1 r12, %3\;retal r12"; |
| 16551 | + } |
| 16552 | + } |
| 16553 | + } |
| 16554 | + |
| 16555 | + [(set_attr "length" "10") |
| 16556 | + (set_attr "cc" "none") |
| 16557 | + (set_attr "type" "call")]) |
| 16558 | + |
| 16559 | + |
| 16560 | + |
| 16561 | +;;================================================================= |
| 16562 | +;; mulnhh.w |
| 16563 | +;;================================================================= |
| 16564 | + |
| 16565 | +(define_peephole2 |
| 16566 | + [(set (match_operand:HI 0 "register_operand" "") |
| 16567 | + (neg:HI (match_operand:HI 1 "register_operand" ""))) |
| 16568 | + (set (match_operand:SI 2 "register_operand" "") |
| 16569 | + (mult:SI |
| 16570 | + (sign_extend:SI (match_dup 0)) |
| 16571 | + (sign_extend:SI (match_operand:HI 3 "register_operand" ""))))] |
| 16572 | + "(peep2_reg_dead_p(2, operands[0])) || (REGNO(operands[2]) == REGNO(operands[0]))" |
| 16573 | + [ (set (match_dup 2) |
| 16574 | + (mult:SI |
| 16575 | + (sign_extend:SI (neg:HI (match_dup 1))) |
| 16576 | + (sign_extend:SI (match_dup 3))))] |
| 16577 | + "" |
| 16578 | + ) |
| 16579 | + |
| 16580 | +(define_peephole2 |
| 16581 | + [(set (match_operand:HI 0 "register_operand" "") |
| 16582 | + (neg:HI (match_operand:HI 1 "register_operand" ""))) |
| 16583 | + (set (match_operand:SI 2 "register_operand" "") |
| 16584 | + (mult:SI |
| 16585 | + (sign_extend:SI (match_operand:HI 3 "register_operand" "")) |
| 16586 | + (sign_extend:SI (match_dup 0))))] |
| 16587 | + "(peep2_reg_dead_p(2, operands[0])) || (REGNO(operands[2]) == REGNO(operands[0]))" |
| 16588 | + [ (set (match_dup 2) |
| 16589 | + (mult:SI |
| 16590 | + (sign_extend:SI (neg:HI (match_dup 1))) |
| 16591 | + (sign_extend:SI (match_dup 3))))] |
| 16592 | + "" |
| 16593 | + ) |
| 16594 | + |
| 16595 | + |
| 16596 | + |
| 16597 | +;;================================================================= |
| 16598 | +;; Vector set and extract operations |
| 16599 | +;;================================================================= |
| 16600 | +(define_insn "vec_setv2hi_hi" |
| 16601 | + [(set (match_operand:V2HI 0 "register_operand" "=r") |
| 16602 | + (vec_merge:V2HI |
| 16603 | + (match_dup 0) |
| 16604 | + (vec_duplicate:V2HI |
| 16605 | + (match_operand:HI 1 "register_operand" "r")) |
| 16606 | + (const_int 1)))] |
| 16607 | + "" |
| 16608 | + "bfins\t%0, %1, 16, 16" |
| 16609 | + [(set_attr "type" "alu") |
| 16610 | + (set_attr "length" "4") |
| 16611 | + (set_attr "cc" "clobber")]) |
| 16612 | + |
| 16613 | +(define_insn "vec_setv2hi_lo" |
| 16614 | + [(set (match_operand:V2HI 0 "register_operand" "+r") |
| 16615 | + (vec_merge:V2HI |
| 16616 | + (match_dup 0) |
| 16617 | + (vec_duplicate:V2HI |
| 16618 | + (match_operand:HI 1 "register_operand" "r")) |
| 16619 | + (const_int 2)))] |
| 16620 | + "" |
| 16621 | + "bfins\t%0, %1, 0, 16" |
| 16622 | + [(set_attr "type" "alu") |
| 16623 | + (set_attr "length" "4") |
| 16624 | + (set_attr "cc" "clobber")]) |
| 16625 | + |
| 16626 | +(define_expand "vec_setv2hi" |
| 16627 | + [(set (match_operand:V2HI 0 "register_operand" "") |
| 16628 | + (vec_merge:V2HI |
| 16629 | + (match_dup 0) |
| 16630 | + (vec_duplicate:V2HI |
| 16631 | + (match_operand:HI 1 "register_operand" "")) |
| 16632 | + (match_operand 2 "immediate_operand" "")))] |
| 16633 | + "" |
| 16634 | + { operands[2] = GEN_INT(INTVAL(operands[2]) + 1); } |
| 16635 | + ) |
| 16636 | + |
| 16637 | +(define_insn "vec_extractv2hi" |
| 16638 | + [(set (match_operand:HI 0 "register_operand" "=r") |
| 16639 | + (vec_select:HI |
| 16640 | + (match_operand:V2HI 1 "register_operand" "r") |
| 16641 | + (parallel [(match_operand:SI 2 "immediate_operand" "i")])))] |
| 16642 | + "" |
| 16643 | + { |
| 16644 | + if ( INTVAL(operands[2]) == 0 ) |
| 16645 | + return "bfextu\t%0, %1, 16, 16"; |
| 16646 | + else |
| 16647 | + return "bfextu\t%0, %1, 0, 16"; |
| 16648 | + } |
| 16649 | + [(set_attr "type" "alu") |
| 16650 | + (set_attr "length" "4") |
| 16651 | + (set_attr "cc" "clobber")]) |
| 16652 | + |
| 16653 | +(define_insn "vec_extractv4qi" |
| 16654 | + [(set (match_operand:QI 0 "register_operand" "=r") |
| 16655 | + (vec_select:QI |
| 16656 | + (match_operand:V4QI 1 "register_operand" "r") |
| 16657 | + (parallel [(match_operand:SI 2 "immediate_operand" "i")])))] |
| 16658 | + "" |
| 16659 | + { |
| 16660 | + switch ( INTVAL(operands[2]) ){ |
| 16661 | + case 0: |
| 16662 | + return "bfextu\t%0, %1, 24, 8"; |
| 16663 | + case 1: |
| 16664 | + return "bfextu\t%0, %1, 16, 8"; |
| 16665 | + case 2: |
| 16666 | + return "bfextu\t%0, %1, 8, 8"; |
| 16667 | + case 3: |
| 16668 | + return "bfextu\t%0, %1, 0, 8"; |
| 16669 | + default: |
| 16670 | + abort(); |
| 16671 | + } |
| 16672 | + } |
| 16673 | + [(set_attr "type" "alu") |
| 16674 | + (set_attr "length" "4") |
| 16675 | + (set_attr "cc" "clobber")]) |
| 16676 | + |
| 16677 | + |
| 16678 | +(define_insn "concatv2hi" |
| 16679 | + [(set (match_operand:V2HI 0 "register_operand" "=r, r, r") |
| 16680 | + (vec_concat:V2HI |
| 16681 | + (match_operand:HI 1 "register_operand" "r, r, 0") |
| 16682 | + (match_operand:HI 2 "register_operand" "r, 0, r")))] |
| 16683 | + "" |
| 16684 | + "@ |
| 16685 | + mov\t%0, %1\;bfins\t%0, %2, 0, 16 |
| 16686 | + bfins\t%0, %2, 0, 16 |
| 16687 | + bfins\t%0, %1, 16, 16" |
| 16688 | + [(set_attr "length" "6, 4, 4") |
| 16689 | + (set_attr "type" "alu")]) |
| 16690 | + |
| 16691 | + |
| 16692 | +;; Load the atomic operation description |
| 16693 | +(include "sync.md") |
| 16694 | + |
| 16695 | +;; Load the SIMD description |
| 16696 | +(include "simd.md") |
| 16697 | + |
| 16698 | +;; Include the FPU for uc3 |
| 16699 | +(include "uc3fpu.md") |
| 16700 | --- /dev/null |
| 16701 | +++ b/gcc/config/avr32/avr32-modes.def |
| 16702 | @@ -0,0 +1 @@ |
| 16703 | +VECTOR_MODES (INT, 4); /* V4QI V2HI */ |
| 16704 | --- /dev/null |
| 16705 | +++ b/gcc/config/avr32/avr32.opt |
| 16706 | @@ -0,0 +1,93 @@ |
| 16707 | +; Options for the ATMEL AVR32 port of the compiler. |
| 16708 | + |
| 16709 | +; Copyright 2007 Atmel Corporation. |
| 16710 | +; |
| 16711 | +; This file is part of GCC. |
| 16712 | +; |
| 16713 | +; GCC is free software; you can redistribute it and/or modify it under |
| 16714 | +; the terms of the GNU General Public License as published by the Free |
| 16715 | +; Software Foundation; either version 2, or (at your option) any later |
| 16716 | +; version. |
| 16717 | +; |
| 16718 | +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| 16719 | +; WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 16720 | +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 16721 | +; for more details. |
| 16722 | +; |
| 16723 | +; You should have received a copy of the GNU General Public License |
| 16724 | +; along with GCC; see the file COPYING. If not, write to the Free |
| 16725 | +; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
| 16726 | +; 02110-1301, USA. |
| 16727 | + |
| 16728 | +muse-rodata-section |
| 16729 | +Target Report Mask(USE_RODATA_SECTION) |
| 16730 | +Use section .rodata for read-only data instead of .text. |
| 16731 | + |
| 16732 | +mhard-float |
| 16733 | +Target Report Mask(HARD_FLOAT) |
| 16734 | +Use FPU instructions instead of floating point emulation. |
| 16735 | + |
| 16736 | +msoft-float |
| 16737 | +Target Report InverseMask(HARD_FLOAT, SOFT_FLOAT) |
| 16738 | +Use floating point emulation for floating point operations. |
| 16739 | + |
| 16740 | +mforce-double-align |
| 16741 | +Target Report RejectNegative Mask(FORCE_DOUBLE_ALIGN) |
| 16742 | +Force double-word alignment for double-word memory accesses. |
| 16743 | + |
| 16744 | +mno-init-got |
| 16745 | +Target Report RejectNegative Mask(NO_INIT_GOT) |
| 16746 | +Do not initialize GOT register before using it when compiling PIC code. |
| 16747 | + |
| 16748 | +mrelax |
| 16749 | +Target Report Mask(RELAX) |
| 16750 | +Let invoked assembler and linker do relaxing (Enabled by default when optimization level is >1). |
| 16751 | + |
| 16752 | +mmd-reorg-opt |
| 16753 | +Target Report Undocumented Mask(MD_REORG_OPTIMIZATION) |
| 16754 | +Perform machine dependent optimizations in reorg stage. |
| 16755 | + |
| 16756 | +masm-addr-pseudos |
| 16757 | +Target Report Mask(HAS_ASM_ADDR_PSEUDOS) |
| 16758 | +Use assembler pseudo-instructions lda.w and call for handling direct addresses. (Enabled by default) |
| 16759 | + |
| 16760 | +mpart= |
| 16761 | +Target Report RejectNegative Joined Var(avr32_part_name) |
| 16762 | +Specify the AVR32 part name |
| 16763 | + |
| 16764 | +mcpu= |
| 16765 | +Target Report RejectNegative Joined Undocumented Var(avr32_part_name) |
| 16766 | +Specify the AVR32 part name (deprecated) |
| 16767 | + |
| 16768 | +march= |
| 16769 | +Target Report RejectNegative Joined Var(avr32_arch_name) |
| 16770 | +Specify the AVR32 architecture name |
| 16771 | + |
| 16772 | +mfast-float |
| 16773 | +Target Report Mask(FAST_FLOAT) |
| 16774 | +Enable fast floating-point library. Enabled by default if the -funsafe-math-optimizations switch is specified. |
| 16775 | + |
| 16776 | +mimm-in-const-pool |
| 16777 | +Target Report Var(avr32_imm_in_const_pool) Init(-1) |
| 16778 | +Put large immediates in constant pool. This is enabled by default for archs with insn-cache. |
| 16779 | + |
| 16780 | +mno-pic |
| 16781 | +Target Report RejectNegative Mask(NO_PIC) |
| 16782 | +Do not generate position-independent code. (deprecated, use -fno-pic instead) |
| 16783 | + |
| 16784 | +mcond-exec-before-reload |
| 16785 | +Target Report Undocumented Mask(COND_EXEC_BEFORE_RELOAD) |
| 16786 | +Enable experimental conditional execution preparation before the reload stage. |
| 16787 | + |
| 16788 | +mrmw-addressable-data |
| 16789 | +Target Report Mask(RMW_ADDRESSABLE_DATA) |
| 16790 | +Signal that all data is in range for the Atomic Read-Modify-Write memory instructions, and that |
| 16791 | +gcc can safely generate these whenever possible. |
| 16792 | + |
| 16793 | +mflashvault |
| 16794 | +Target Var(TARGET_FLASHVAULT) |
| 16795 | +Generate code for flashvault |
| 16796 | + |
| 16797 | +mlist-devices |
| 16798 | +Target RejectNegative Var(avr32_list_supported_parts) |
| 16799 | +Print the list of parts supported while printing --target-help. |
| 16800 | --- /dev/null |
| 16801 | +++ b/gcc/config/avr32/avr32-protos.h |
| 16802 | @@ -0,0 +1,196 @@ |
| 16803 | +/* |
| 16804 | + Prototypes for exported functions defined in avr32.c |
| 16805 | + Copyright 2003,2004,2005,2006,2007,2008,2009 Atmel Corporation. |
| 16806 | + |
| 16807 | + This file is part of GCC. |
| 16808 | + |
| 16809 | + This program is free software; you can redistribute it and/or modify |
| 16810 | + it under the terms of the GNU General Public License as published by |
| 16811 | + the Free Software Foundation; either version 2 of the License, or |
| 16812 | + (at your option) any later version. |
| 16813 | + |
| 16814 | + This program is distributed in the hope that it will be useful, |
| 16815 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16816 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16817 | + GNU General Public License for more details. |
| 16818 | + |
| 16819 | + You should have received a copy of the GNU General Public License |
| 16820 | + along with this program; if not, write to the Free Software |
| 16821 | + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 16822 | + |
| 16823 | + |
| 16824 | +#ifndef AVR32_PROTOS_H |
| 16825 | +#define AVR32_PROTOS_H |
| 16826 | + |
| 16827 | +extern const int swap_reg[]; |
| 16828 | + |
| 16829 | +extern int avr32_valid_macmac_bypass (rtx, rtx); |
| 16830 | +extern int avr32_valid_mulmac_bypass (rtx, rtx); |
| 16831 | + |
| 16832 | +extern int avr32_decode_lcomm_symbol_offset (rtx, int *); |
| 16833 | +extern void avr32_encode_lcomm_symbol_offset (tree, char *, int); |
| 16834 | + |
| 16835 | +extern const char *avr32_strip_name_encoding (const char *); |
| 16836 | + |
| 16837 | +extern rtx avr32_get_note_reg_equiv (rtx insn); |
| 16838 | + |
| 16839 | +extern int avr32_use_return_insn (int iscond); |
| 16840 | + |
| 16841 | +extern void avr32_make_reglist16 (int reglist16_vect, char *reglist16_string); |
| 16842 | + |
| 16843 | +extern void avr32_make_reglist8 (int reglist8_vect, char *reglist8_string); |
| 16844 | +extern void avr32_make_fp_reglist_w (int reglist_mask, char *reglist_string); |
| 16845 | +extern void avr32_make_fp_reglist_d (int reglist_mask, char *reglist_string); |
| 16846 | + |
| 16847 | +extern void avr32_output_return_instruction (int single_ret_inst, |
| 16848 | + int iscond, rtx cond, |
| 16849 | + rtx r12_imm); |
| 16850 | +extern void avr32_expand_prologue (void); |
| 16851 | +extern void avr32_set_return_address (rtx source, rtx scratch); |
| 16852 | + |
| 16853 | +extern int avr32_hard_regno_mode_ok (int regno, enum machine_mode mode); |
| 16854 | +extern int avr32_extra_constraint_s (rtx value, const int strict); |
| 16855 | +extern int avr32_eh_return_data_regno (const int n); |
| 16856 | +extern int avr32_initial_elimination_offset (const int from, const int to); |
| 16857 | +extern rtx avr32_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, |
| 16858 | + tree type, int named); |
| 16859 | +extern void avr32_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, |
| 16860 | + rtx libname, tree fndecl); |
| 16861 | +extern void avr32_function_arg_advance (CUMULATIVE_ARGS * cum, |
| 16862 | + enum machine_mode mode, |
| 16863 | + tree type, int named); |
| 16864 | +#ifdef ARGS_SIZE_RTX |
| 16865 | +/* expr.h defines ARGS_SIZE_RTX and `enum direction'. */ |
| 16866 | +extern enum direction avr32_function_arg_padding (enum machine_mode mode, |
| 16867 | + tree type); |
| 16868 | +#endif /* ARGS_SIZE_RTX */ |
| 16869 | +extern rtx avr32_function_value (tree valtype, tree func, bool outgoing); |
| 16870 | +extern rtx avr32_libcall_value (enum machine_mode mode); |
| 16871 | +extern int avr32_sched_use_dfa_pipeline_interface (void); |
| 16872 | +extern bool avr32_return_in_memory (tree type, tree fntype); |
| 16873 | +extern void avr32_regs_to_save (char *operand); |
| 16874 | +extern void avr32_target_asm_function_prologue (FILE * file, |
| 16875 | + HOST_WIDE_INT size); |
| 16876 | +extern void avr32_target_asm_function_epilogue (FILE * file, |
| 16877 | + HOST_WIDE_INT size); |
| 16878 | +extern void avr32_trampoline_template (FILE * file); |
| 16879 | +extern void avr32_initialize_trampoline (rtx addr, rtx fnaddr, |
| 16880 | + rtx static_chain); |
| 16881 | +extern int avr32_legitimate_address (enum machine_mode mode, rtx x, |
| 16882 | + int strict); |
| 16883 | +extern int avr32_legitimate_constant_p (rtx x); |
| 16884 | + |
| 16885 | +extern int avr32_legitimate_pic_operand_p (rtx x); |
| 16886 | + |
| 16887 | +extern rtx avr32_find_symbol (rtx x); |
| 16888 | +extern void avr32_select_section (rtx exp, int reloc, int align); |
| 16889 | +extern void avr32_encode_section_info (tree decl, rtx rtl, int first); |
| 16890 | +extern void avr32_asm_file_end (FILE * stream); |
| 16891 | +extern void avr32_asm_output_ascii (FILE * stream, char *ptr, int len); |
| 16892 | +extern void avr32_asm_output_common (FILE * stream, const char *name, |
| 16893 | + int size, int rounded); |
| 16894 | +extern void avr32_asm_output_label (FILE * stream, const char *name); |
| 16895 | +extern void avr32_asm_declare_object_name (FILE * stream, char *name, |
| 16896 | + tree decl); |
| 16897 | +extern void avr32_asm_globalize_label (FILE * stream, const char *name); |
| 16898 | +extern void avr32_asm_weaken_label (FILE * stream, const char *name); |
| 16899 | +extern void avr32_asm_output_external (FILE * stream, tree decl, |
| 16900 | + const char *name); |
| 16901 | +extern void avr32_asm_output_external_libcall (FILE * stream, rtx symref); |
| 16902 | +extern void avr32_asm_output_labelref (FILE * stream, const char *name); |
| 16903 | +extern void avr32_notice_update_cc (rtx exp, rtx insn); |
| 16904 | +extern void avr32_print_operand (FILE * stream, rtx x, int code); |
| 16905 | +extern void avr32_print_operand_address (FILE * stream, rtx x); |
| 16906 | + |
| 16907 | +extern int avr32_symbol (rtx x); |
| 16908 | + |
| 16909 | +extern void avr32_select_rtx_section (enum machine_mode mode, rtx x, |
| 16910 | + unsigned HOST_WIDE_INT align); |
| 16911 | + |
| 16912 | +extern int avr32_load_multiple_operation (rtx op, enum machine_mode mode); |
| 16913 | +extern int avr32_store_multiple_operation (rtx op, enum machine_mode mode); |
| 16914 | + |
| 16915 | +extern int avr32_const_ok_for_constraint_p (HOST_WIDE_INT value, char c, |
| 16916 | + const char *str); |
| 16917 | + |
| 16918 | +extern bool avr32_cannot_force_const_mem (rtx x); |
| 16919 | + |
| 16920 | +extern void avr32_init_builtins (void); |
| 16921 | + |
| 16922 | +extern rtx avr32_expand_builtin (tree exp, rtx target, rtx subtarget, |
| 16923 | + enum machine_mode mode, int ignore); |
| 16924 | + |
| 16925 | +extern bool avr32_must_pass_in_stack (enum machine_mode mode, tree type); |
| 16926 | + |
| 16927 | +extern bool avr32_strict_argument_naming (CUMULATIVE_ARGS * ca); |
| 16928 | + |
| 16929 | +extern bool avr32_pass_by_reference (CUMULATIVE_ARGS * cum, |
| 16930 | + enum machine_mode mode, |
| 16931 | + tree type, bool named); |
| 16932 | + |
| 16933 | +extern rtx avr32_gen_load_multiple (rtx * regs, int count, rtx from, |
| 16934 | + int write_back, int in_struct_p, |
| 16935 | + int scalar_p); |
| 16936 | +extern rtx avr32_gen_store_multiple (rtx * regs, int count, rtx to, |
| 16937 | + int in_struct_p, int scalar_p); |
| 16938 | +extern int avr32_gen_movmemsi (rtx * operands); |
| 16939 | + |
| 16940 | +extern int avr32_rnd_operands (rtx add, rtx shift); |
| 16941 | +extern int avr32_adjust_insn_length (rtx insn, int length); |
| 16942 | + |
| 16943 | +extern int symbol_mentioned_p (rtx x); |
| 16944 | +extern int label_mentioned_p (rtx x); |
| 16945 | +extern rtx legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg); |
| 16946 | +extern int avr32_address_register_rtx_p (rtx x, int strict_p); |
| 16947 | +extern int avr32_legitimate_index_p (enum machine_mode mode, rtx index, |
| 16948 | + int strict_p); |
| 16949 | + |
| 16950 | +extern int avr32_const_double_immediate (rtx value); |
| 16951 | +extern void avr32_init_expanders (void); |
| 16952 | +extern rtx avr32_return_addr (int count, rtx frame); |
| 16953 | +extern bool avr32_got_mentioned_p (rtx addr); |
| 16954 | + |
| 16955 | +extern void avr32_final_prescan_insn (rtx insn, rtx * opvec, int noperands); |
| 16956 | + |
| 16957 | +extern int avr32_expand_movcc (enum machine_mode mode, rtx operands[]); |
| 16958 | +extern int avr32_expand_addcc (enum machine_mode mode, rtx operands[]); |
| 16959 | +#ifdef RTX_CODE |
| 16960 | +extern int avr32_expand_scc (RTX_CODE cond, rtx * operands); |
| 16961 | +#endif |
| 16962 | + |
| 16963 | +extern int avr32_store_bypass (rtx insn_out, rtx insn_in); |
| 16964 | +extern int avr32_mul_waw_bypass (rtx insn_out, rtx insn_in); |
| 16965 | +extern int avr32_valid_load_double_bypass (rtx insn_out, rtx insn_in); |
| 16966 | +extern int avr32_valid_load_quad_bypass (rtx insn_out, rtx insn_in); |
| 16967 | +extern rtx avr32_output_cmp (rtx cond, enum machine_mode mode, |
| 16968 | + rtx op0, rtx op1); |
| 16969 | + |
| 16970 | +rtx get_next_insn_cond (rtx cur_insn); |
| 16971 | +int set_next_insn_cond (rtx cur_insn, rtx cond); |
| 16972 | +rtx next_insn_emits_cmp (rtx cur_insn); |
| 16973 | +void avr32_override_options (void); |
| 16974 | +void avr32_load_pic_register (void); |
| 16975 | +#ifdef GCC_BASIC_BLOCK_H |
| 16976 | +rtx avr32_ifcvt_modify_insn (ce_if_block_t *ce_info, rtx pattern, rtx insn, |
| 16977 | + int *num_true_changes); |
| 16978 | +rtx avr32_ifcvt_modify_test (ce_if_block_t *ce_info, rtx test ); |
| 16979 | +void avr32_ifcvt_modify_cancel ( ce_if_block_t *ce_info, int *num_true_changes); |
| 16980 | +#endif |
| 16981 | +void avr32_optimization_options (int level, int size); |
| 16982 | +int avr32_const_ok_for_move (HOST_WIDE_INT c); |
| 16983 | + |
| 16984 | +void avr32_split_const_expr (enum machine_mode mode, |
| 16985 | + enum machine_mode new_mode, |
| 16986 | + rtx expr, |
| 16987 | + rtx *split_expr); |
| 16988 | +void avr32_get_intval (enum machine_mode mode, |
| 16989 | + rtx const_expr, |
| 16990 | + HOST_WIDE_INT *val); |
| 16991 | + |
| 16992 | +int avr32_cond_imm_clobber_splittable (rtx insn, |
| 16993 | + rtx operands[]); |
| 16994 | + |
| 16995 | +bool avr32_flashvault_call(tree decl); |
| 16996 | +extern void avr32_emit_swdivsf (rtx, rtx, rtx); |
| 16997 | + |
| 16998 | +#endif /* AVR32_PROTOS_H */ |
| 16999 | --- /dev/null |
| 17000 | +++ b/gcc/config/avr32/crti.asm |
| 17001 | @@ -0,0 +1,64 @@ |
| 17002 | +/* |
| 17003 | + Init/fini stuff for AVR32. |
| 17004 | + Copyright 2003-2006 Atmel Corporation. |
| 17005 | + |
| 17006 | + Written by Ronny Pedersen, Atmel Norway, <rpedersen@atmel.com> |
| 17007 | + |
| 17008 | + This file is part of GCC. |
| 17009 | + |
| 17010 | + This program is free software; you can redistribute it and/or modify |
| 17011 | + it under the terms of the GNU General Public License as published by |
| 17012 | + the Free Software Foundation; either version 2 of the License, or |
| 17013 | + (at your option) any later version. |
| 17014 | + |
| 17015 | + This program is distributed in the hope that it will be useful, |
| 17016 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17017 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17018 | + GNU General Public License for more details. |
| 17019 | + |
| 17020 | + You should have received a copy of the GNU General Public License |
| 17021 | + along with this program; if not, write to the Free Software |
| 17022 | + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 17023 | + |
| 17024 | + |
| 17025 | +/* The code in sections .init and .fini is supposed to be a single |
| 17026 | + regular function. The function in .init is called directly from |
| 17027 | + start in crt1.asm. The function in .fini is atexit()ed in crt1.asm |
| 17028 | + too. |
| 17029 | + |
| 17030 | + crti.asm contributes the prologue of a function to these sections, |
| 17031 | + and crtn.asm comes up the epilogue. STARTFILE_SPEC should list |
| 17032 | + crti.o before any other object files that might add code to .init |
| 17033 | + or .fini sections, and ENDFILE_SPEC should list crtn.o after any |
| 17034 | + such object files. */ |
| 17035 | + |
| 17036 | + .file "crti.asm" |
| 17037 | + |
| 17038 | + .section ".init" |
| 17039 | +/* Just load the GOT */ |
| 17040 | + .align 2 |
| 17041 | + .global _init |
| 17042 | +_init: |
| 17043 | + stm --sp, r6, lr |
| 17044 | + lddpc r6, 1f |
| 17045 | +0: |
| 17046 | + rsub r6, pc |
| 17047 | + rjmp 2f |
| 17048 | + .align 2 |
| 17049 | +1: .long 0b - _GLOBAL_OFFSET_TABLE_ |
| 17050 | +2: |
| 17051 | + |
| 17052 | + .section ".fini" |
| 17053 | +/* Just load the GOT */ |
| 17054 | + .align 2 |
| 17055 | + .global _fini |
| 17056 | +_fini: |
| 17057 | + stm --sp, r6, lr |
| 17058 | + lddpc r6, 1f |
| 17059 | +0: |
| 17060 | + rsub r6, pc |
| 17061 | + rjmp 2f |
| 17062 | + .align 2 |
| 17063 | +1: .long 0b - _GLOBAL_OFFSET_TABLE_ |
| 17064 | +2: |
| 17065 | + |
| 17066 | --- /dev/null |
| 17067 | +++ b/gcc/config/avr32/crtn.asm |
| 17068 | @@ -0,0 +1,44 @@ |
| 17069 | +/* Copyright (C) 2001 Free Software Foundation, Inc. |
| 17070 | + Written By Nick Clifton |
| 17071 | + |
| 17072 | + This file is free software; you can redistribute it and/or modify it |
| 17073 | + under the terms of the GNU General Public License as published by the |
| 17074 | + Free Software Foundation; either version 2, or (at your option) any |
| 17075 | + later version. |
| 17076 | + |
| 17077 | + In addition to the permissions in the GNU General Public License, the |
| 17078 | + Free Software Foundation gives you unlimited permission to link the |
| 17079 | + compiled version of this file with other programs, and to distribute |
| 17080 | + those programs without any restriction coming from the use of this |
| 17081 | + file. (The General Public License restrictions do apply in other |
| 17082 | + respects; for example, they cover modification of the file, and |
| 17083 | + distribution when not linked into another program.) |
| 17084 | + |
| 17085 | + This file is distributed in the hope that it will be useful, but |
| 17086 | + WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17087 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17088 | + General Public License for more details. |
| 17089 | + |
| 17090 | + You should have received a copy of the GNU General Public License |
| 17091 | + along with this program; see the file COPYING. If not, write to |
| 17092 | + the Free Software Foundation, 59 Temple Place - Suite 330, |
| 17093 | + Boston, MA 02111-1307, USA. |
| 17094 | + |
| 17095 | + As a special exception, if you link this library with files |
| 17096 | + compiled with GCC to produce an executable, this does not cause |
| 17097 | + the resulting executable to be covered by the GNU General Public License. |
| 17098 | + This exception does not however invalidate any other reasons why |
| 17099 | + the executable file might be covered by the GNU General Public License. |
| 17100 | +*/ |
| 17101 | + |
| 17102 | + |
| 17103 | + |
| 17104 | + |
| 17105 | + .file "crtn.asm" |
| 17106 | + |
| 17107 | + .section ".init" |
| 17108 | + ldm sp++, r6, pc |
| 17109 | + |
| 17110 | + .section ".fini" |
| 17111 | + ldm sp++, r6, pc |
| 17112 | + |
| 17113 | --- /dev/null |
| 17114 | +++ b/gcc/config/avr32/lib1funcs.S |
| 17115 | @@ -0,0 +1,2903 @@ |
| 17116 | +/* Macro for moving immediate value to register. */ |
| 17117 | +.macro mov_imm reg, imm |
| 17118 | +.if (((\imm & 0xfffff) == \imm) || ((\imm | 0xfff00000) == \imm)) |
| 17119 | + mov \reg, \imm |
| 17120 | +#if __AVR32_UC__ >= 2 |
| 17121 | +.elseif ((\imm & 0xffff) == 0) |
| 17122 | + movh \reg, hi(\imm) |
| 17123 | + |
| 17124 | +#endif |
| 17125 | +.else |
| 17126 | + mov \reg, lo(\imm) |
| 17127 | + orh \reg, hi(\imm) |
| 17128 | +.endif |
| 17129 | +.endm |
| 17130 | + |
| 17131 | + |
| 17132 | + |
| 17133 | +/* Adjust the unpacked double number if it is a subnormal number. |
| 17134 | + The exponent and mantissa pair are stored |
| 17135 | + in [mant_hi,mant_lo] and [exp]. A register with the correct sign bit in |
| 17136 | + the MSB is passed in [sign]. Needs two scratch |
| 17137 | + registers [scratch1] and [scratch2]. An adjusted and packed double float |
| 17138 | + is present in [mant_hi,mant_lo] after macro has executed */ |
| 17139 | +.macro adjust_subnormal_df exp, mant_lo, mant_hi, sign, scratch1, scratch2 |
| 17140 | + /* We have an exponent which is <=0 indicating a subnormal number |
| 17141 | + As it should be stored as if the exponent was 1 (although the |
| 17142 | + exponent field is all zeros to indicate a subnormal number) |
| 17143 | + we have to shift down the mantissa to its correct position. */ |
| 17144 | + neg \exp |
| 17145 | + sub \exp,-1 /* amount to shift down */ |
| 17146 | + cp.w \exp,54 |
| 17147 | + brlo 50f /* if more than 53 shift steps, the |
| 17148 | + entire mantissa will disappear |
| 17149 | + without any rounding to occur */ |
| 17150 | + mov \mant_hi, 0 |
| 17151 | + mov \mant_lo, 0 |
| 17152 | + rjmp 52f |
| 17153 | +50: |
| 17154 | + sub \exp,-10 /* do the shift to position the |
| 17155 | + mantissa at the same time |
| 17156 | + note! this does not include the |
| 17157 | + final 1 step shift to add the sign */ |
| 17158 | + |
| 17159 | + /* when shifting, save all shifted out bits in [scratch2]. we may need to |
| 17160 | + look at them to make correct rounding. */ |
| 17161 | + |
| 17162 | + rsub \scratch1,\exp,32 /* get inverted shift count */ |
| 17163 | + cp.w \exp,32 /* handle shifts >= 32 separately */ |
| 17164 | + brhs 51f |
| 17165 | + |
| 17166 | + /* small (<32) shift amount, both words are part of the shift */ |
| 17167 | + lsl \scratch2,\mant_lo,\scratch1 /* save bits to shift out from lsw*/ |
| 17168 | + lsl \scratch1,\mant_hi,\scratch1 /* get bits from msw destined for lsw*/ |
| 17169 | + lsr \mant_lo,\mant_lo,\exp /* shift down lsw */ |
| 17170 | + lsr \mant_hi,\mant_hi,\exp /* shift down msw */ |
| 17171 | + or \mant_hi,\scratch1 /* add bits from msw with prepared lsw */ |
| 17172 | + rjmp 50f |
| 17173 | + |
| 17174 | + /* large (>=32) shift amount, only lsw will have bits left after shift. |
| 17175 | + note that shift operations will use ((shift count) mod 32) so |
| 17176 | + we do not need to subtract 32 from shift count. */ |
| 17177 | +51: |
| 17178 | + lsl \scratch2,\mant_hi,\scratch1 /* save bits to shift out from msw */ |
| 17179 | + or \scratch2,\mant_lo /* also save all bits from lsw */ |
| 17180 | + mov \mant_lo,\mant_hi /* msw -> lsw (i.e. "shift 32 first") */ |
| 17181 | + mov \mant_hi,0 /* clear msw */ |
| 17182 | + lsr \mant_lo,\mant_lo,\exp /* make rest of shift inside lsw */ |
| 17183 | + |
| 17184 | +50: |
| 17185 | + /* result is almost ready to return, except that least significant bit |
| 17186 | + and the part we already shifted out may cause the result to be |
| 17187 | + rounded */ |
| 17188 | + bld \mant_lo,0 /* get bit to be shifted out */ |
| 17189 | + brcc 51f /* if bit was 0, no rounding */ |
| 17190 | + |
| 17191 | + /* msb of part to remove is 1, so rounding depends on rest of bits */ |
| 17192 | + tst \scratch2,\scratch2 /* get shifted out tail */ |
| 17193 | + brne 50f /* if rest > 0, do round */ |
| 17194 | + bld \mant_lo,1 /* we have to look at lsb in result */ |
| 17195 | + brcc 51f /* if lsb is 0, don't round */ |
| 17196 | + |
| 17197 | +50: |
| 17198 | + /* subnormal result requires rounding |
| 17199 | + rounding may cause subnormal to become smallest normal number |
| 17200 | + luckily, smallest normal number has exactly the representation |
| 17201 | + we got by rippling a one bit up from mantissa into exponent field. */ |
| 17202 | + sub \mant_lo,-1 |
| 17203 | + subcc \mant_hi,-1 |
| 17204 | + |
| 17205 | +51: |
| 17206 | + /* shift and return packed double with correct sign */ |
| 17207 | + rol \sign |
| 17208 | + ror \mant_hi |
| 17209 | + ror \mant_lo |
| 17210 | +52: |
| 17211 | +.endm |
| 17212 | + |
| 17213 | + |
| 17214 | +/* Adjust subnormal single float number with exponent [exp] |
| 17215 | + and mantissa [mant] and round. */ |
| 17216 | +.macro adjust_subnormal_sf sf, exp, mant, sign, scratch |
| 17217 | + /* subnormal number */ |
| 17218 | + rsub \exp,\exp, 1 /* shift amount */ |
| 17219 | + cp.w \exp, 25 |
| 17220 | + movhs \mant, 0 |
| 17221 | + brhs 90f /* Return zero */ |
| 17222 | + rsub \scratch, \exp, 32 |
| 17223 | + lsl \scratch, \mant,\scratch/* Check if there are any bits set |
| 17224 | + in the bits discarded in the mantissa */ |
| 17225 | + srne \scratch /* If so set the lsb of the shifted mantissa */ |
| 17226 | + lsr \mant,\mant,\exp /* Shift the mantissa */ |
| 17227 | + or \mant, \scratch /* Round lsb if any bits were shifted out */ |
| 17228 | + /* Rounding : For explaination, see round_sf. */ |
| 17229 | + mov \scratch, 0x7f /* Set rounding constant */ |
| 17230 | + bld \mant, 8 |
| 17231 | + subeq \scratch, -1 /* For odd numbers use rounding constant 0x80 */ |
| 17232 | + add \mant, \scratch /* Add rounding constant to mantissa */ |
| 17233 | + /* We can't overflow because mantissa is at least shifted one position |
| 17234 | + to the right so the implicit bit is zero. We can however get the implicit |
| 17235 | + bit set after rounding which means that we have the lowest normal number |
| 17236 | + but this is ok since this bit has the same position as the LSB of the |
| 17237 | + exponent */ |
| 17238 | + lsr \sf, \mant, 7 |
| 17239 | + /* Rotate in sign */ |
| 17240 | + lsl \sign, 1 |
| 17241 | + ror \sf |
| 17242 | +90: |
| 17243 | +.endm |
| 17244 | + |
| 17245 | + |
| 17246 | +/* Round the unpacked df number with exponent [exp] and |
| 17247 | + mantissa [mant_hi, mant_lo]. Uses scratch register |
| 17248 | + [scratch] */ |
| 17249 | +.macro round_df exp, mant_lo, mant_hi, scratch |
| 17250 | + mov \scratch, 0x3ff /* Rounding constant */ |
| 17251 | + bld \mant_lo,11 /* Check if lsb in the final result is |
| 17252 | + set */ |
| 17253 | + subeq \scratch, -1 /* Adjust rounding constant to 0x400 |
| 17254 | + if rounding 0.5 upwards */ |
| 17255 | + add \mant_lo, \scratch /* Round */ |
| 17256 | + acr \mant_hi /* If overflowing we know that |
| 17257 | + we have all zeros in the bits not |
| 17258 | + scaled out so we can leave them |
| 17259 | + but we must increase the exponent with |
| 17260 | + two since we had an implicit bit |
| 17261 | + which is lost + the extra overflow bit */ |
| 17262 | + subcs \exp, -2 /* Update exponent */ |
| 17263 | +.endm |
| 17264 | + |
| 17265 | +/* Round single float number stored in [mant] and [exp] */ |
| 17266 | +.macro round_sf exp, mant, scratch |
| 17267 | + /* Round: |
| 17268 | + For 0.5 we round to nearest even integer |
| 17269 | + for all other cases we round to nearest integer. |
| 17270 | + This means that if the digit left of the "point" (.) |
| 17271 | + is 1 we can add 0x80 to the mantissa since the |
| 17272 | + corner case 0x180 will round up to 0x200. If the |
| 17273 | + digit left of the "point" is 0 we will have to |
| 17274 | + add 0x7f since this will give 0xff and hence a |
| 17275 | + truncation/rounding downwards for the corner |
| 17276 | + case when the 9 lowest bits are 0x080 */ |
| 17277 | + mov \scratch, 0x7f /* Set rounding constant */ |
| 17278 | + /* Check if the mantissa is even or odd */ |
| 17279 | + bld \mant, 8 |
| 17280 | + subeq \scratch, -1 /* Rounding constant should be 0x80 */ |
| 17281 | + add \mant, \scratch |
| 17282 | + subcs \exp, -2 /* Adjust exponent if we overflowed */ |
| 17283 | +.endm |
| 17284 | + |
| 17285 | + |
| 17286 | + |
| 17287 | +/* Pack a single float number stored in [mant] and [exp] |
| 17288 | + into a single float number in [sf] */ |
| 17289 | +.macro pack_sf sf, exp, mant |
| 17290 | + bld \mant,31 /* implicit bit to z */ |
| 17291 | + subne \exp,1 /* if subnormal (implicit bit 0) |
| 17292 | + adjust exponent to storage format */ |
| 17293 | + |
| 17294 | + lsr \sf, \mant, 7 |
| 17295 | + bfins \sf, \exp, 24, 8 |
| 17296 | +.endm |
| 17297 | + |
| 17298 | +/* Pack exponent [exp] and mantissa [mant_hi, mant_lo] |
| 17299 | + into [df_hi, df_lo]. [df_hi] is shifted |
| 17300 | + one bit up so the sign bit can be shifted into it */ |
| 17301 | + |
| 17302 | +.macro pack_df exp, mant_lo, mant_hi, df_lo, df_hi |
| 17303 | + bld \mant_hi,31 /* implicit bit to z */ |
| 17304 | + subne \exp,1 /* if subnormal (implicit bit 0) |
| 17305 | + adjust exponent to storage format */ |
| 17306 | + |
| 17307 | + lsr \mant_lo,11 /* shift back lsw */ |
| 17308 | + or \df_lo,\mant_lo,\mant_hi<<21 /* combine with low bits from msw */ |
| 17309 | + lsl \mant_hi,1 /* get rid of implicit bit */ |
| 17310 | + lsr \mant_hi,11 /* shift back msw except for one step*/ |
| 17311 | + or \df_hi,\mant_hi,\exp<<21 /* combine msw with exponent */ |
| 17312 | +.endm |
| 17313 | + |
| 17314 | +/* Normalize single float number stored in [mant] and [exp] |
| 17315 | + using scratch register [scratch] */ |
| 17316 | +.macro normalize_sf exp, mant, scratch |
| 17317 | + /* Adjust exponent and mantissa */ |
| 17318 | + clz \scratch, \mant |
| 17319 | + sub \exp, \scratch |
| 17320 | + lsl \mant, \mant, \scratch |
| 17321 | +.endm |
| 17322 | + |
| 17323 | +/* Normalize the exponent and mantissa pair stored |
| 17324 | + in [mant_hi,mant_lo] and [exp]. Needs two scratch |
| 17325 | + registers [scratch1] and [scratch2]. */ |
| 17326 | +.macro normalize_df exp, mant_lo, mant_hi, scratch1, scratch2 |
| 17327 | + clz \scratch1,\mant_hi /* Check if we have zeros in high bits */ |
| 17328 | + breq 80f /* No need for scaling if no zeros in high bits */ |
| 17329 | + brcs 81f /* Check for all zeros */ |
| 17330 | + |
| 17331 | + /* shift amount is smaller than 32, and involves both msw and lsw*/ |
| 17332 | + rsub \scratch2,\scratch1,32 /* shift mantissa */ |
| 17333 | + lsl \mant_hi,\mant_hi,\scratch1 |
| 17334 | + lsr \scratch2,\mant_lo,\scratch2 |
| 17335 | + or \mant_hi,\scratch2 |
| 17336 | + lsl \mant_lo,\mant_lo,\scratch1 |
| 17337 | + sub \exp,\scratch1 /* adjust exponent */ |
| 17338 | + rjmp 80f /* Finished */ |
| 17339 | +81: |
| 17340 | + /* shift amount is greater than 32 */ |
| 17341 | + clz \scratch1,\mant_lo /* shift mantissa */ |
| 17342 | + movcs \scratch1, 0 |
| 17343 | + subcc \scratch1,-32 |
| 17344 | + lsl \mant_hi,\mant_lo,\scratch1 |
| 17345 | + mov \mant_lo,0 |
| 17346 | + sub \exp,\scratch1 /* adjust exponent */ |
| 17347 | +80: |
| 17348 | +.endm |
| 17349 | + |
| 17350 | + |
| 17351 | +/* Fast but approximate multiply of two 64-bit numbers to give a 64 bit result. |
| 17352 | + The multiplication of [al]x[bl] is discarded. |
| 17353 | + Operands in [ah], [al], [bh], [bl]. |
| 17354 | + Scratch registers in [sh], [sl]. |
| 17355 | + Returns results in registers [rh], [rl].*/ |
| 17356 | +.macro mul_approx_df ah, al, bh, bl, rh, rl, sh, sl |
| 17357 | + mulu.d \sl, \ah, \bl |
| 17358 | + macu.d \sl, \al, \bh |
| 17359 | + mulu.d \rl, \ah, \bh |
| 17360 | + add \rl, \sh |
| 17361 | + acr \rh |
| 17362 | +.endm |
| 17363 | + |
| 17364 | + |
| 17365 | + |
| 17366 | +#if defined(L_avr32_f64_mul) || defined(L_avr32_f64_mul_fast) |
| 17367 | + .align 2 |
| 17368 | +#if defined(L_avr32_f64_mul) |
| 17369 | + .global __avr32_f64_mul |
| 17370 | + .type __avr32_f64_mul,@function |
| 17371 | +__avr32_f64_mul: |
| 17372 | +#else |
| 17373 | + .global __avr32_f64_mul_fast |
| 17374 | + .type __avr32_f64_mul_fast,@function |
| 17375 | +__avr32_f64_mul_fast: |
| 17376 | +#endif |
| 17377 | + or r12, r10, r11 << 1 |
| 17378 | + breq __avr32_f64_mul_op1_zero |
| 17379 | + |
| 17380 | +#if defined(L_avr32_f64_mul) |
| 17381 | + pushm r4-r7, lr |
| 17382 | +#else |
| 17383 | + stm --sp, r5,r6,r7,lr |
| 17384 | +#endif |
| 17385 | + |
| 17386 | +#define AVR32_F64_MUL_OP1_INT_BITS 1 |
| 17387 | +#define AVR32_F64_MUL_OP2_INT_BITS 10 |
| 17388 | +#define AVR32_F64_MUL_RES_INT_BITS 11 |
| 17389 | + |
| 17390 | + /* op1 in {r11,r10}*/ |
| 17391 | + /* op2 in {r9,r8}*/ |
| 17392 | + eor lr, r11, r9 /* MSB(lr) = Sign(op1) ^ Sign(op2) */ |
| 17393 | + |
| 17394 | + /* Unpack op1 to 1.63 format*/ |
| 17395 | + /* exp: r7 */ |
| 17396 | + /* sf: r11, r10 */ |
| 17397 | + bfextu r7, r11, 20, 11 /* Extract exponent */ |
| 17398 | + |
| 17399 | + mov r5, 1 |
| 17400 | + |
| 17401 | + /* Check if normalization is needed */ |
| 17402 | + breq __avr32_f64_mul_op1_subnormal /*If number is subnormal, normalize it */ |
| 17403 | + |
| 17404 | + lsl r11, (12-AVR32_F64_MUL_OP1_INT_BITS-1) /* Extract mantissa, leave room for implicit bit */ |
| 17405 | + or r11, r11, r10>>(32-(12-AVR32_F64_MUL_OP1_INT_BITS-1)) |
| 17406 | + lsl r10, (12-AVR32_F64_MUL_OP1_INT_BITS-1) |
| 17407 | + bfins r11, r5, 32 - (1 + AVR32_F64_MUL_OP1_INT_BITS), 1 + AVR32_F64_MUL_OP1_INT_BITS /* Insert implicit bit */ |
| 17408 | + |
| 17409 | + |
| 17410 | +22: |
| 17411 | + /* Unpack op2 to 10.54 format */ |
| 17412 | + /* exp: r6 */ |
| 17413 | + /* sf: r9, r8 */ |
| 17414 | + bfextu r6, r9, 20, 11 /* Extract exponent */ |
| 17415 | + |
| 17416 | + /* Check if normalization is needed */ |
| 17417 | + breq __avr32_f64_mul_op2_subnormal /*If number is subnormal, normalize it */ |
| 17418 | + |
| 17419 | + lsl r8, 1 /* Extract mantissa, leave room for implicit bit */ |
| 17420 | + rol r9 |
| 17421 | + bfins r9, r5, 32 - (1 + AVR32_F64_MUL_OP2_INT_BITS), 1 + AVR32_F64_MUL_OP2_INT_BITS /* Insert implicit bit */ |
| 17422 | + |
| 17423 | +23: |
| 17424 | + |
| 17425 | + /* Check if any operands are NaN or INF */ |
| 17426 | + cp r7, 0x7ff |
| 17427 | + breq __avr32_f64_mul_op_nan_or_inf /* Check op1 for NaN or Inf */ |
| 17428 | + cp r6, 0x7ff |
| 17429 | + breq __avr32_f64_mul_op_nan_or_inf /* Check op2 for NaN or Inf */ |
| 17430 | + |
| 17431 | + |
| 17432 | + /* Calculate new exponent in r12*/ |
| 17433 | + add r12, r7, r6 |
| 17434 | + sub r12, (1023-1) |
| 17435 | + |
| 17436 | +#if defined(L_avr32_f64_mul) |
| 17437 | + /* Do the multiplication. |
| 17438 | + Place result in [r11, r10, r7, r6]. The result is in 11.117 format. */ |
| 17439 | + mulu.d r4, r11, r8 |
| 17440 | + macu.d r4, r10, r9 |
| 17441 | + mulu.d r6, r10, r8 |
| 17442 | + mulu.d r10, r11, r9 |
| 17443 | + add r7, r4 |
| 17444 | + adc r10, r10, r5 |
| 17445 | + acr r11 |
| 17446 | +#else |
| 17447 | + /* Do the multiplication using approximate calculation. discard the al x bl |
| 17448 | + calculation. |
| 17449 | + Place result in [r11, r10, r7]. The result is in 11.85 format. */ |
| 17450 | + |
| 17451 | + /* Do the multiplication using approximate calculation. |
| 17452 | + Place result in r11, r10. Use r7, r6 as scratch registers */ |
| 17453 | + mulu.d r6, r11, r8 |
| 17454 | + macu.d r6, r10, r9 |
| 17455 | + mulu.d r10, r11, r9 |
| 17456 | + add r10, r7 |
| 17457 | + acr r11 |
| 17458 | +#endif |
| 17459 | + /* Adjust exponent and mantissa */ |
| 17460 | + /* [r12]:exp, [r11, r10]:mant [r7, r6]:sticky bits */ |
| 17461 | + /* Mantissa may be of the format 00000000000.0xxx or 00000000000.1xxx. */ |
| 17462 | + /* In the first case, shift one pos to left.*/ |
| 17463 | + bld r11, 32-AVR32_F64_MUL_RES_INT_BITS-1 |
| 17464 | + breq 0f |
| 17465 | + lsl r7, 1 |
| 17466 | + rol r10 |
| 17467 | + rol r11 |
| 17468 | + sub r12, 1 |
| 17469 | +0: |
| 17470 | + cp r12, 0 |
| 17471 | + brle __avr32_f64_mul_res_subnormal /*Result was subnormal.*/ |
| 17472 | + |
| 17473 | + /* Check for Inf. */ |
| 17474 | + cp.w r12, 0x7ff |
| 17475 | + brge __avr32_f64_mul_res_inf |
| 17476 | + |
| 17477 | + /* Insert exponent. */ |
| 17478 | + bfins r11, r12, 20, 11 |
| 17479 | + |
| 17480 | + /* Result was not subnormal. Perform rounding. */ |
| 17481 | + /* For the fast version we discard the sticky bits and always round |
| 17482 | + the halfwaycase up. */ |
| 17483 | +24: |
| 17484 | +#if defined(L_avr32_f64_mul) |
| 17485 | + or r6, r6, r10 << 31 /* Or in parity bit into stickybits */ |
| 17486 | + or r7, r7, r6 >> 1 /* Or together sticky and still make the msb |
| 17487 | + of r7 represent the halfway bit. */ |
| 17488 | + eorh r7, 0x8000 /* Toggle halfway bit. */ |
| 17489 | + /* We should now round up by adding one for the following cases: |
| 17490 | + |
| 17491 | + halfway sticky|parity round-up |
| 17492 | + 0 x no |
| 17493 | + 1 0 no |
| 17494 | + 1 1 yes |
| 17495 | + |
| 17496 | + Since we have inverted the halfway bit we can use the satu instruction |
| 17497 | + by saturating to 1 bit to implement this. |
| 17498 | + */ |
| 17499 | + satu r7 >> 0, 1 |
| 17500 | +#else |
| 17501 | + lsr r7, 31 |
| 17502 | +#endif |
| 17503 | + add r10, r7 |
| 17504 | + acr r11 |
| 17505 | + |
| 17506 | + /* Insert sign bit*/ |
| 17507 | + bld lr, 31 |
| 17508 | + bst r11, 31 |
| 17509 | + |
| 17510 | + /* Return result in [r11,r10] */ |
| 17511 | +#if defined(L_avr32_f64_mul) |
| 17512 | + popm r4-r7, pc |
| 17513 | +#else |
| 17514 | + ldm sp++, r5, r6, r7,pc |
| 17515 | +#endif |
| 17516 | + |
| 17517 | + |
| 17518 | +__avr32_f64_mul_op1_subnormal: |
| 17519 | + andh r11, 0x000f /* Remove sign bit and exponent */ |
| 17520 | + clz r12, r10 /* Count leading zeros in lsw */ |
| 17521 | + clz r6, r11 /* Count leading zeros in msw */ |
| 17522 | + subcs r12, -32 + AVR32_F64_MUL_OP1_INT_BITS |
| 17523 | + movcs r6, r12 |
| 17524 | + subcc r6, AVR32_F64_MUL_OP1_INT_BITS |
| 17525 | + cp.w r6, 32 |
| 17526 | + brge 0f |
| 17527 | + |
| 17528 | + /* shifting involves both msw and lsw*/ |
| 17529 | + rsub r12, r6, 32 /* shift mantissa */ |
| 17530 | + lsl r11, r11, r6 |
| 17531 | + lsr r12, r10, r12 |
| 17532 | + or r11, r12 |
| 17533 | + lsl r10, r10, r6 |
| 17534 | + sub r6, 12-AVR32_F64_MUL_OP1_INT_BITS |
| 17535 | + sub r7, r6 /* adjust exponent */ |
| 17536 | + rjmp 22b /* Finished */ |
| 17537 | +0: |
| 17538 | + /* msw is zero so only need to consider lsw */ |
| 17539 | + lsl r11, r10, r6 |
| 17540 | + breq __avr32_f64_mul_res_zero |
| 17541 | + mov r10, 0 |
| 17542 | + sub r6, 12-AVR32_F64_MUL_OP1_INT_BITS |
| 17543 | + sub r7, r6 /* adjust exponent */ |
| 17544 | + rjmp 22b |
| 17545 | + |
| 17546 | + |
| 17547 | +__avr32_f64_mul_op2_subnormal: |
| 17548 | + andh r9, 0x000f /* Remove sign bit and exponent */ |
| 17549 | + clz r12, r8 /* Count leading zeros in lsw */ |
| 17550 | + clz r5, r9 /* Count leading zeros in msw */ |
| 17551 | + subcs r12, -32 + AVR32_F64_MUL_OP2_INT_BITS |
| 17552 | + movcs r5, r12 |
| 17553 | + subcc r5, AVR32_F64_MUL_OP2_INT_BITS |
| 17554 | + cp.w r5, 32 |
| 17555 | + brge 0f |
| 17556 | + |
| 17557 | + /* shifting involves both msw and lsw*/ |
| 17558 | + rsub r12, r5, 32 /* shift mantissa */ |
| 17559 | + lsl r9, r9, r5 |
| 17560 | + lsr r12, r8, r12 |
| 17561 | + or r9, r12 |
| 17562 | + lsl r8, r8, r5 |
| 17563 | + sub r5, 12 - AVR32_F64_MUL_OP2_INT_BITS |
| 17564 | + sub r6, r5 /* adjust exponent */ |
| 17565 | + rjmp 23b /* Finished */ |
| 17566 | +0: |
| 17567 | + /* msw is zero so only need to consider lsw */ |
| 17568 | + lsl r9, r8, r5 |
| 17569 | + breq __avr32_f64_mul_res_zero |
| 17570 | + mov r8, 0 |
| 17571 | + sub r5, 12 - AVR32_F64_MUL_OP2_INT_BITS |
| 17572 | + sub r6, r5 /* adjust exponent */ |
| 17573 | + rjmp 23b |
| 17574 | + |
| 17575 | + |
| 17576 | +__avr32_f64_mul_op_nan_or_inf: |
| 17577 | + /* Same code for OP1 and OP2*/ |
| 17578 | + /* Since we are here, at least one of the OPs were NaN or INF*/ |
| 17579 | + andh r9, 0x000f /* Remove sign bit and exponent */ |
| 17580 | + andh r11, 0x000f /* Remove sign bit and exponent */ |
| 17581 | + /* Merge the regs in each operand to check for zero*/ |
| 17582 | + or r11, r10 /* op1 */ |
| 17583 | + or r9, r8 /* op2 */ |
| 17584 | + /* Check if op1 is NaN or INF */ |
| 17585 | + cp r7, 0x7ff |
| 17586 | + brne __avr32_f64_mul_op1_not_naninf |
| 17587 | + /* op1 was NaN or INF.*/ |
| 17588 | + cp r11, 0 |
| 17589 | + brne __avr32_f64_mul_res_nan /* op1 was NaN. Result will be NaN*/ |
| 17590 | + /*op1 was INF. check if op2 is NaN or INF*/ |
| 17591 | + cp r6, 0x7ff |
| 17592 | + brne __avr32_f64_mul_res_inf /*op1 was INF, op2 was neither NaN nor INF*/ |
| 17593 | + /* op1 is INF, op2 is either NaN or INF*/ |
| 17594 | + cp r9, 0 |
| 17595 | + breq __avr32_f64_mul_res_inf /*op2 was also INF*/ |
| 17596 | + rjmp __avr32_f64_mul_res_nan /*op2 was NaN*/ |
| 17597 | + |
| 17598 | +__avr32_f64_mul_op1_not_naninf: |
| 17599 | + /* op1 was not NaN nor INF. Then op2 must be NaN or INF*/ |
| 17600 | + cp r9, 0 |
| 17601 | + breq __avr32_f64_mul_res_inf /*op2 was INF, return INF*/ |
| 17602 | + rjmp __avr32_f64_mul_res_nan /*else return NaN*/ |
| 17603 | + |
| 17604 | +__avr32_f64_mul_res_subnormal:/* Multiply result was subnormal. */ |
| 17605 | +#if defined(L_avr32_f64_mul) |
| 17606 | + /* Check how much we must scale down the mantissa. */ |
| 17607 | + neg r12 |
| 17608 | + sub r12, -1 /* We do no longer have an implicit bit. */ |
| 17609 | + satu r12 >> 0, 6 /* Saturate shift amount to max 63. */ |
| 17610 | + cp.w r12, 32 |
| 17611 | + brge 0f |
| 17612 | + /* Shift amount <32 */ |
| 17613 | + rsub r8, r12, 32 |
| 17614 | + or r6, r7 |
| 17615 | + lsr r7, r7, r12 |
| 17616 | + lsl r9, r10, r8 |
| 17617 | + or r7, r9 |
| 17618 | + lsr r10, r10, r12 |
| 17619 | + lsl r9, r11, r8 |
| 17620 | + or r10, r9 |
| 17621 | + lsr r11, r11, r12 |
| 17622 | + rjmp 24b |
| 17623 | +0: |
| 17624 | + /* Shift amount >=32 */ |
| 17625 | + rsub r8, r12, 32 |
| 17626 | + moveq r9, 0 |
| 17627 | + breq 0f |
| 17628 | + lsl r9, r11, r8 |
| 17629 | +0: |
| 17630 | + or r6, r7 |
| 17631 | + or r6, r6, r10 << 1 |
| 17632 | + lsr r10, r10, r12 |
| 17633 | + or r7, r9, r10 |
| 17634 | + lsr r10, r11, r12 |
| 17635 | + mov r11, 0 |
| 17636 | + rjmp 24b |
| 17637 | +#else |
| 17638 | + /* Flush to zero for the fast version. */ |
| 17639 | + mov r11, lr /*Get correct sign*/ |
| 17640 | + andh r11, 0x8000, COH |
| 17641 | + mov r10, 0 |
| 17642 | + ldm sp++, r5, r6, r7,pc |
| 17643 | +#endif |
| 17644 | + |
| 17645 | +__avr32_f64_mul_res_zero:/* Multiply result is zero. */ |
| 17646 | + mov r11, lr /*Get correct sign*/ |
| 17647 | + andh r11, 0x8000, COH |
| 17648 | + mov r10, 0 |
| 17649 | +#if defined(L_avr32_f64_mul) |
| 17650 | + popm r4-r7, pc |
| 17651 | +#else |
| 17652 | + ldm sp++, r5, r6, r7,pc |
| 17653 | +#endif |
| 17654 | + |
| 17655 | +__avr32_f64_mul_res_nan: /* Return NaN. */ |
| 17656 | + mov r11, -1 |
| 17657 | + mov r10, -1 |
| 17658 | +#if defined(L_avr32_f64_mul) |
| 17659 | + popm r4-r7, pc |
| 17660 | +#else |
| 17661 | + ldm sp++, r5, r6, r7,pc |
| 17662 | +#endif |
| 17663 | + |
| 17664 | +__avr32_f64_mul_res_inf: /* Return INF. */ |
| 17665 | + mov r11, 0xfff00000 |
| 17666 | + bld lr, 31 |
| 17667 | + bst r11, 31 |
| 17668 | + mov r10, 0 |
| 17669 | +#if defined(L_avr32_f64_mul) |
| 17670 | + popm r4-r7, pc |
| 17671 | +#else |
| 17672 | + ldm sp++, r5, r6, r7,pc |
| 17673 | +#endif |
| 17674 | + |
| 17675 | +__avr32_f64_mul_op1_zero: |
| 17676 | + /* Get sign */ |
| 17677 | + eor r11, r11, r9 |
| 17678 | + andh r11, 0x8000, COH |
| 17679 | + /* Check if op2 is Inf or NaN. */ |
| 17680 | + bfextu r12, r9, 20, 11 |
| 17681 | + cp.w r12, 0x7ff |
| 17682 | + retne r12 /* Return 0.0 */ |
| 17683 | + /* Return NaN */ |
| 17684 | + mov r10, -1 |
| 17685 | + mov r11, -1 |
| 17686 | + ret r12 |
| 17687 | + |
| 17688 | + |
| 17689 | + |
| 17690 | +#endif |
| 17691 | + |
| 17692 | + |
| 17693 | +#if defined(L_avr32_f64_addsub) || defined(L_avr32_f64_addsub_fast) |
| 17694 | + .align 2 |
| 17695 | + |
| 17696 | +__avr32_f64_sub_from_add: |
| 17697 | + /* Switch sign on op2 */ |
| 17698 | + eorh r9, 0x8000 |
| 17699 | + |
| 17700 | +#if defined(L_avr32_f64_addsub_fast) |
| 17701 | + .global __avr32_f64_sub_fast |
| 17702 | + .type __avr32_f64_sub_fast,@function |
| 17703 | +__avr32_f64_sub_fast: |
| 17704 | +#else |
| 17705 | + .global __avr32_f64_sub |
| 17706 | + .type __avr32_f64_sub,@function |
| 17707 | +__avr32_f64_sub: |
| 17708 | +#endif |
| 17709 | + |
| 17710 | + /* op1 in {r11,r10}*/ |
| 17711 | + /* op2 in {r9,r8}*/ |
| 17712 | + |
| 17713 | +#if defined(L_avr32_f64_addsub_fast) |
| 17714 | + /* If op2 is zero just return op1 */ |
| 17715 | + or r12, r8, r9 << 1 |
| 17716 | + reteq r12 |
| 17717 | +#endif |
| 17718 | + |
| 17719 | + /* Check signs */ |
| 17720 | + eor r12, r11, r9 |
| 17721 | + /* Different signs, use addition. */ |
| 17722 | + brmi __avr32_f64_add_from_sub |
| 17723 | + |
| 17724 | + stm --sp, r5, r6, r7, lr |
| 17725 | + |
| 17726 | + /* Get sign of op1 into r12 */ |
| 17727 | + mov r12, r11 |
| 17728 | + andh r12, 0x8000, COH |
| 17729 | + |
| 17730 | + /* Remove sign from operands */ |
| 17731 | + cbr r11, 31 |
| 17732 | + cbr r9, 31 |
| 17733 | + |
| 17734 | + /* Put the largest number in [r11, r10] |
| 17735 | + and the smallest number in [r9, r8] */ |
| 17736 | + cp r10, r8 |
| 17737 | + cpc r11, r9 |
| 17738 | + brhs 1f /* Skip swap if operands already correctly ordered*/ |
| 17739 | + /* Operands were not correctly ordered, swap them*/ |
| 17740 | + mov r7, r11 |
| 17741 | + mov r11, r9 |
| 17742 | + mov r9, r7 |
| 17743 | + mov r7, r10 |
| 17744 | + mov r10, r8 |
| 17745 | + mov r8, r7 |
| 17746 | + eorh r12, 0x8000 /* Invert sign in r12*/ |
| 17747 | +1: |
| 17748 | + /* Unpack largest operand - opH */ |
| 17749 | + /* exp: r7 */ |
| 17750 | + /* sf: r11, r10 */ |
| 17751 | + lsr r7, r11, 20 /* Extract exponent */ |
| 17752 | + lsl r11, 11 /* Extract mantissa, leave room for implicit bit */ |
| 17753 | + or r11, r11, r10>>21 |
| 17754 | + lsl r10, 11 |
| 17755 | + sbr r11, 31 /* Insert implicit bit */ |
| 17756 | + |
| 17757 | + |
| 17758 | + /* Unpack smallest operand - opL */ |
| 17759 | + /* exp: r6 */ |
| 17760 | + /* sf: r9, r8 */ |
| 17761 | + lsr r6, r9, 20 /* Extract exponent */ |
| 17762 | + breq __avr32_f64_sub_opL_subnormal /* If either zero or subnormal */ |
| 17763 | + lsl r9, 11 /* Extract mantissa, leave room for implicit bit */ |
| 17764 | + or r9, r9, r8>>21 |
| 17765 | + lsl r8, 11 |
| 17766 | + sbr r9, 31 /* Insert implicit bit */ |
| 17767 | + |
| 17768 | + |
| 17769 | +__avr32_f64_sub_opL_subnormal_done: |
| 17770 | + /* opH is NaN or Inf. */ |
| 17771 | + cp.w r7, 0x7ff |
| 17772 | + breq __avr32_f64_sub_opH_nan_or_inf |
| 17773 | + |
| 17774 | + /* Get shift amount to scale mantissa of op2. */ |
| 17775 | + rsub r6, r7 |
| 17776 | + breq __avr32_f64_sub_shift_done /* No need to shift, exponents are equal*/ |
| 17777 | + |
| 17778 | + /* Scale mantissa [r9, r8] with amount [r6]. |
| 17779 | + Uses scratch registers [r5] and [lr]. |
| 17780 | + In IEEE mode:Must not forget the sticky bits we intend to shift out. */ |
| 17781 | + |
| 17782 | + rsub r5,r6,32 /* get (32 - shift count) |
| 17783 | + (if shift count > 32 we get a |
| 17784 | + negative value, but that will |
| 17785 | + work as well in the code below.) */ |
| 17786 | + |
| 17787 | + cp.w r6,32 /* handle shifts >= 32 separately */ |
| 17788 | + brhs __avr32_f64_sub_longshift |
| 17789 | + |
| 17790 | + /* small (<32) shift amount, both words are part of the shift |
| 17791 | + first remember whether part that is lost contains any 1 bits ... */ |
| 17792 | + lsl lr,r8,r5 /* shift away bits that are part of |
| 17793 | + final mantissa. only part that goes |
| 17794 | + to lr are bits that will be lost */ |
| 17795 | + |
| 17796 | + /* ... and now to the actual shift */ |
| 17797 | + lsl r5,r9,r5 /* get bits from msw destined for lsw*/ |
| 17798 | + lsr r8,r8,r6 /* shift down lsw of mantissa */ |
| 17799 | + lsr r9,r9,r6 /* shift down msw of mantissa */ |
| 17800 | + or r8,r5 /* combine these bits with prepared lsw*/ |
| 17801 | +#if defined(L_avr32_f64_addsub) |
| 17802 | + cp.w lr,0 /* if any '1' bit in part we lost ...*/ |
| 17803 | + srne lr |
| 17804 | + or r8, lr /* ... we need to set sticky bit*/ |
| 17805 | +#endif |
| 17806 | + |
| 17807 | +__avr32_f64_sub_shift_done: |
| 17808 | + /* Now subtract the mantissas. */ |
| 17809 | + sub r10, r8 |
| 17810 | + sbc r11, r11, r9 |
| 17811 | + |
| 17812 | + /* Normalize the exponent and mantissa pair stored in |
| 17813 | + [r11,r10] and exponent in [r7]. Needs two scratch registers [r6] and [lr]. */ |
| 17814 | + clz r6,r11 /* Check if we have zeros in high bits */ |
| 17815 | + breq __avr32_f64_sub_longnormalize_done /* No need for scaling if no zeros in high bits */ |
| 17816 | + brcs __avr32_f64_sub_longnormalize |
| 17817 | + |
| 17818 | + |
| 17819 | + /* shift amount is smaller than 32, and involves both msw and lsw*/ |
| 17820 | + rsub lr,r6,32 /* shift mantissa */ |
| 17821 | + lsl r11,r11,r6 |
| 17822 | + lsr lr,r10,lr |
| 17823 | + or r11,lr |
| 17824 | + lsl r10,r10,r6 |
| 17825 | + |
| 17826 | + sub r7,r6 /* adjust exponent */ |
| 17827 | + brle __avr32_f64_sub_subnormal_result |
| 17828 | +__avr32_f64_sub_longnormalize_done: |
| 17829 | + |
| 17830 | +#if defined(L_avr32_f64_addsub) |
| 17831 | + /* Insert the bits we will remove from the mantissa r9[31:21] */ |
| 17832 | + lsl r9, r10, (32 - 11) |
| 17833 | +#else |
| 17834 | + /* Keep the last bit shifted out. */ |
| 17835 | + bfextu r9, r10, 10, 1 |
| 17836 | +#endif |
| 17837 | + |
| 17838 | + /* Pack final result*/ |
| 17839 | + /* Input: [r7]:exp, [r11, r10]:mant, [r12]:sign in MSB */ |
| 17840 | + /* Result in [r11,r10] */ |
| 17841 | + /* Insert mantissa */ |
| 17842 | + lsr r10, 11 |
| 17843 | + or r10, r10, r11<<21 |
| 17844 | + lsr r11, 11 |
| 17845 | + /* Insert exponent and sign bit*/ |
| 17846 | + bfins r11, r7, 20, 11 |
| 17847 | + or r11, r12 |
| 17848 | + |
| 17849 | + /* Round */ |
| 17850 | +__avr32_f64_sub_round: |
| 17851 | +#if defined(L_avr32_f64_addsub) |
| 17852 | + mov_imm r7, 0x80000000 |
| 17853 | + bld r10, 0 |
| 17854 | + subne r7, -1 |
| 17855 | + |
| 17856 | + cp.w r9, r7 |
| 17857 | + srhs r9 |
| 17858 | +#endif |
| 17859 | + add r10, r9 |
| 17860 | + acr r11 |
| 17861 | + |
| 17862 | + /* Return result in [r11,r10] */ |
| 17863 | + ldm sp++, r5, r6, r7,pc |
| 17864 | + |
| 17865 | + |
| 17866 | + |
| 17867 | +__avr32_f64_sub_opL_subnormal: |
| 17868 | + /* Extract the of mantissa */ |
| 17869 | + lsl r9, 11 /* Extract mantissa, leave room for implicit bit */ |
| 17870 | + or r9, r9, r8>>21 |
| 17871 | + lsl r8, 11 |
| 17872 | + |
| 17873 | + /* Set exponent to 1 if we do not have a zero. */ |
| 17874 | + or lr, r9, r8 |
| 17875 | + movne r6,1 |
| 17876 | + |
| 17877 | + /* Check if opH is also subnormal. If so, clear implicit bit in r11*/ |
| 17878 | + rsub lr, r7, 0 |
| 17879 | + moveq r7,1 |
| 17880 | + bst r11, 31 |
| 17881 | + |
| 17882 | + /* Check if op1 is zero, if so set exponent to 0. */ |
| 17883 | + or lr, r11, r10 |
| 17884 | + moveq r7,0 |
| 17885 | + |
| 17886 | + rjmp __avr32_f64_sub_opL_subnormal_done |
| 17887 | + |
| 17888 | +__avr32_f64_sub_opH_nan_or_inf: |
| 17889 | + /* Check if opH is NaN, if so return NaN */ |
| 17890 | + cbr r11, 31 |
| 17891 | + or lr, r11, r10 |
| 17892 | + brne __avr32_f64_sub_return_nan |
| 17893 | + |
| 17894 | + /* opH is Inf. */ |
| 17895 | + /* Check if opL is Inf. or NaN */ |
| 17896 | + cp.w r6, 0x7ff |
| 17897 | + breq __avr32_f64_sub_return_nan |
| 17898 | + /* Return infinity with correct sign. */ |
| 17899 | + or r11, r12, r7 << 20 |
| 17900 | + ldm sp++, r5, r6, r7, pc/* opL not Inf or NaN, return opH */ |
| 17901 | +__avr32_f64_sub_return_nan: |
| 17902 | + mov r10, -1 /* Generate NaN in r11, r10 */ |
| 17903 | + mov r11, -1 |
| 17904 | + ldm sp++, r5, r6, r7, pc/* opL Inf or NaN, return NaN */ |
| 17905 | + |
| 17906 | + |
| 17907 | +__avr32_f64_sub_subnormal_result: |
| 17908 | +#if defined(L_avr32_f64_addsub) |
| 17909 | + /* Check how much we must scale down the mantissa. */ |
| 17910 | + neg r7 |
| 17911 | + sub r7, -1 /* We do no longer have an implicit bit. */ |
| 17912 | + satu r7 >> 0, 6 /* Saturate shift amount to max 63. */ |
| 17913 | + cp.w r7, 32 |
| 17914 | + brge 0f |
| 17915 | + /* Shift amount <32 */ |
| 17916 | + rsub r8, r7, 32 |
| 17917 | + lsl r9, r10, r8 |
| 17918 | + srne r6 |
| 17919 | + lsr r10, r10, r7 |
| 17920 | + or r10, r6 /* Sticky bit from the |
| 17921 | + part that was shifted out. */ |
| 17922 | + lsl r9, r11, r8 |
| 17923 | + or r10, r10, r9 |
| 17924 | + lsr r11, r10, r7 |
| 17925 | + /* Set exponent */ |
| 17926 | + mov r7, 0 |
| 17927 | + rjmp __avr32_f64_sub_longnormalize_done |
| 17928 | +0: |
| 17929 | + /* Shift amount >=32 */ |
| 17930 | + rsub r8, r7, 64 |
| 17931 | + lsl r9, r11, r8 |
| 17932 | + or r9, r10 |
| 17933 | + srne r6 |
| 17934 | + lsr r10, r11, r7 |
| 17935 | + or r10, r6 /* Sticky bit from the |
| 17936 | + part that was shifted out. */ |
| 17937 | + mov r11, 0 |
| 17938 | + /* Set exponent */ |
| 17939 | + mov r7, 0 |
| 17940 | + rjmp __avr32_f64_sub_longnormalize_done |
| 17941 | +#else |
| 17942 | + /* Just flush subnormals to zero. */ |
| 17943 | + mov r10, 0 |
| 17944 | + mov r11, 0 |
| 17945 | +#endif |
| 17946 | + ldm sp++, r5, r6, r7, pc |
| 17947 | + |
| 17948 | +__avr32_f64_sub_longshift: |
| 17949 | + /* large (>=32) shift amount, only lsw will have bits left after shift. |
| 17950 | + note that shift operations will use ((shift count=r6) mod 32) so |
| 17951 | + we do not need to subtract 32 from shift count. */ |
| 17952 | + /* Saturate the shift amount to 63. If the amount |
| 17953 | + is any larger op2 is insignificant. */ |
| 17954 | + satu r6 >> 0, 6 |
| 17955 | + |
| 17956 | +#if defined(L_avr32_f64_addsub) |
| 17957 | + /* first remember whether part that is lost contains any 1 bits ... */ |
| 17958 | + moveq lr, r8 /* If shift amount is 32, no bits from msw are lost. */ |
| 17959 | + breq 0f |
| 17960 | + lsl lr,r9,r5 /* save all lost bits from msw */ |
| 17961 | + or lr,r8 /* also save lost bits (all) from lsw |
| 17962 | + now lr != 0 if we lose any bits */ |
| 17963 | +#endif |
| 17964 | +0: |
| 17965 | + /* ... and now to the actual shift */ |
| 17966 | + lsr r8,r9,r6 /* Move msw to lsw and shift. */ |
| 17967 | + mov r9,0 /* clear msw */ |
| 17968 | +#if defined(L_avr32_f64_addsub) |
| 17969 | + cp.w lr,0 /* if any '1' bit in part we lost ...*/ |
| 17970 | + srne lr |
| 17971 | + or r8, lr /* ... we need to set sticky bit*/ |
| 17972 | +#endif |
| 17973 | + rjmp __avr32_f64_sub_shift_done |
| 17974 | + |
| 17975 | +__avr32_f64_sub_longnormalize: |
| 17976 | + /* shift amount is greater than 32 */ |
| 17977 | + clz r6,r10 /* shift mantissa */ |
| 17978 | + /* If the resulting mantissa is zero the result is |
| 17979 | + zero so force exponent to zero. */ |
| 17980 | + movcs r7, 0 |
| 17981 | + movcs r6, 0 |
| 17982 | + movcs r12, 0 /* Also clear sign bit. A zero result from subtraction |
| 17983 | + always is +0.0 */ |
| 17984 | + subcc r6,-32 |
| 17985 | + lsl r11,r10,r6 |
| 17986 | + mov r10,0 |
| 17987 | + sub r7,r6 /* adjust exponent */ |
| 17988 | + brle __avr32_f64_sub_subnormal_result |
| 17989 | + rjmp __avr32_f64_sub_longnormalize_done |
| 17990 | + |
| 17991 | + |
| 17992 | + |
| 17993 | + .align 2 |
| 17994 | +__avr32_f64_add_from_sub: |
| 17995 | + /* Switch sign on op2 */ |
| 17996 | + eorh r9, 0x8000 |
| 17997 | + |
| 17998 | +#if defined(L_avr32_f64_addsub_fast) |
| 17999 | + .global __avr32_f64_add_fast |
| 18000 | + .type __avr32_f64_add_fast,@function |
| 18001 | +__avr32_f64_add_fast: |
| 18002 | +#else |
| 18003 | + .global __avr32_f64_add |
| 18004 | + .type __avr32_f64_add,@function |
| 18005 | +__avr32_f64_add: |
| 18006 | +#endif |
| 18007 | + |
| 18008 | + /* op1 in {r11,r10}*/ |
| 18009 | + /* op2 in {r9,r8}*/ |
| 18010 | + |
| 18011 | +#if defined(L_avr32_f64_addsub_fast) |
| 18012 | + /* If op2 is zero just return op1 */ |
| 18013 | + or r12, r8, r9 << 1 |
| 18014 | + reteq r12 |
| 18015 | +#endif |
| 18016 | + |
| 18017 | + /* Check signs */ |
| 18018 | + eor r12, r11, r9 |
| 18019 | + /* Different signs, use subtraction. */ |
| 18020 | + brmi __avr32_f64_sub_from_add |
| 18021 | + |
| 18022 | + stm --sp, r5, r6, r7, lr |
| 18023 | + |
| 18024 | + /* Get sign of op1 into r12 */ |
| 18025 | + mov r12, r11 |
| 18026 | + andh r12, 0x8000, COH |
| 18027 | + |
| 18028 | + /* Remove sign from operands */ |
| 18029 | + cbr r11, 31 |
| 18030 | + cbr r9, 31 |
| 18031 | + |
| 18032 | + /* Put the number with the largest exponent in [r11, r10] |
| 18033 | + and the number with the smallest exponent in [r9, r8] */ |
| 18034 | + cp r11, r9 |
| 18035 | + brhs 1f /* Skip swap if operands already correctly ordered */ |
| 18036 | + /* Operands were not correctly ordered, swap them */ |
| 18037 | + mov r7, r11 |
| 18038 | + mov r11, r9 |
| 18039 | + mov r9, r7 |
| 18040 | + mov r7, r10 |
| 18041 | + mov r10, r8 |
| 18042 | + mov r8, r7 |
| 18043 | +1: |
| 18044 | + mov lr, 0 /* Set sticky bits to zero */ |
| 18045 | + /* Unpack largest operand - opH */ |
| 18046 | + /* exp: r7 */ |
| 18047 | + /* sf: r11, r10 */ |
| 18048 | + bfextu R7, R11, 20, 11 /* Extract exponent */ |
| 18049 | + bfextu r11, r11, 0, 20 /* Extract mantissa */ |
| 18050 | + sbr r11, 20 /* Insert implicit bit */ |
| 18051 | + |
| 18052 | + /* Unpack smallest operand - opL */ |
| 18053 | + /* exp: r6 */ |
| 18054 | + /* sf: r9, r8 */ |
| 18055 | + bfextu R6, R9, 20, 11 /* Extract exponent */ |
| 18056 | + breq __avr32_f64_add_op2_subnormal |
| 18057 | + bfextu r9, r9, 0, 20 /* Extract mantissa */ |
| 18058 | + sbr r9, 20 /* Insert implicit bit */ |
| 18059 | + |
| 18060 | +2: |
| 18061 | + /* opH is NaN or Inf. */ |
| 18062 | + cp.w r7, 0x7ff |
| 18063 | + breq __avr32_f64_add_opH_nan_or_inf |
| 18064 | + |
| 18065 | + /* Get shift amount to scale mantissa of op2. */ |
| 18066 | + rsub r6, r7 |
| 18067 | + breq __avr32_f64_add_shift_done /* No need to shift, exponents are equal*/ |
| 18068 | + |
| 18069 | + /* Scale mantissa [r9, r8] with amount [r6]. |
| 18070 | + Uses scratch registers [r5] and [lr]. |
| 18071 | + In IEEE mode:Must not forget the sticky bits we intend to shift out. */ |
| 18072 | + rsub r5,r6,32 /* get (32 - shift count) |
| 18073 | + (if shift count > 32 we get a |
| 18074 | + negative value, but that will |
| 18075 | + work as well in the code below.) */ |
| 18076 | + |
| 18077 | + cp.w r6,32 /* handle shifts >= 32 separately */ |
| 18078 | + brhs __avr32_f64_add_longshift |
| 18079 | + |
| 18080 | + /* small (<32) shift amount, both words are part of the shift |
| 18081 | + first remember whether part that is lost contains any 1 bits ... */ |
| 18082 | + lsl lr,r8,r5 /* shift away bits that are part of |
| 18083 | + final mantissa. only part that goes |
| 18084 | + to lr are bits that will be lost */ |
| 18085 | + |
| 18086 | + /* ... and now to the actual shift */ |
| 18087 | + lsl r5,r9,r5 /* get bits from msw destined for lsw*/ |
| 18088 | + lsr r8,r8,r6 /* shift down lsw of mantissa */ |
| 18089 | + lsr r9,r9,r6 /* shift down msw of mantissa */ |
| 18090 | + or r8,r5 /* combine these bits with prepared lsw*/ |
| 18091 | + |
| 18092 | +__avr32_f64_add_shift_done: |
| 18093 | + /* Now add the mantissas. */ |
| 18094 | + add r10, r8 |
| 18095 | + adc r11, r11, r9 |
| 18096 | + |
| 18097 | + /* Check if we overflowed. */ |
| 18098 | + bld r11, 21 |
| 18099 | + breq __avr32_f64_add_res_of: |
| 18100 | + |
| 18101 | +__avr32_f64_add_res_of_done: |
| 18102 | + |
| 18103 | + /* Pack final result*/ |
| 18104 | + /* Input: [r7]:exp, [r11, r10]:mant, [r12]:sign in MSB */ |
| 18105 | + /* Result in [r11,r10] */ |
| 18106 | + /* Insert exponent and sign bit*/ |
| 18107 | + bfins r11, r7, 20, 11 |
| 18108 | + or r11, r12 |
| 18109 | + |
| 18110 | + /* Round */ |
| 18111 | +__avr32_f64_add_round: |
| 18112 | +#if defined(L_avr32_f64_addsub) |
| 18113 | + bfextu r12, r10, 0, 1 /* Extract parity bit.*/ |
| 18114 | + or lr, r12 /* or it together with the sticky bits. */ |
| 18115 | + eorh lr, 0x8000 /* Toggle round bit. */ |
| 18116 | + /* We should now round up by adding one for the following cases: |
| 18117 | + |
| 18118 | + halfway sticky|parity round-up |
| 18119 | + 0 x no |
| 18120 | + 1 0 no |
| 18121 | + 1 1 yes |
| 18122 | + |
| 18123 | + Since we have inverted the halfway bit we can use the satu instruction |
| 18124 | + by saturating to 1 bit to implement this. |
| 18125 | + */ |
| 18126 | + satu lr >> 0, 1 |
| 18127 | +#else |
| 18128 | + lsr lr, 31 |
| 18129 | +#endif |
| 18130 | + add r10, lr |
| 18131 | + acr r11 |
| 18132 | + |
| 18133 | + /* Return result in [r11,r10] */ |
| 18134 | + ldm sp++, r5, r6, r7,pc |
| 18135 | + |
| 18136 | + |
| 18137 | +__avr32_f64_add_opH_nan_or_inf: |
| 18138 | + /* Check if opH is NaN, if so return NaN */ |
| 18139 | + cbr r11, 20 |
| 18140 | + or lr, r11, r10 |
| 18141 | + brne __avr32_f64_add_return_nan |
| 18142 | + |
| 18143 | + /* opH is Inf. */ |
| 18144 | + /* Check if opL is Inf. or NaN */ |
| 18145 | + cp.w r6, 0x7ff |
| 18146 | + breq __avr32_f64_add_opL_nan_or_inf |
| 18147 | + ldm sp++, r5, r6, r7, pc/* opL not Inf or NaN, return opH */ |
| 18148 | +__avr32_f64_add_opL_nan_or_inf: |
| 18149 | + cbr r9, 20 |
| 18150 | + or lr, r9, r8 |
| 18151 | + brne __avr32_f64_add_return_nan |
| 18152 | + mov r10, 0 /* Generate Inf in r11, r10 */ |
| 18153 | + mov_imm r11, 0x7ff00000 |
| 18154 | + or r11, r12 /* Put sign bit back */ |
| 18155 | + ldm sp++, r5, r6, r7, pc/* opL Inf, return Inf */ |
| 18156 | +__avr32_f64_add_return_nan: |
| 18157 | + mov r10, -1 /* Generate NaN in r11, r10 */ |
| 18158 | + mov r11, -1 |
| 18159 | + ldm sp++, r5, r6, r7, pc/* opL Inf or NaN, return NaN */ |
| 18160 | + |
| 18161 | + |
| 18162 | +__avr32_f64_add_longshift: |
| 18163 | + /* large (>=32) shift amount, only lsw will have bits left after shift. |
| 18164 | + note that shift operations will use ((shift count=r6) mod 32) so |
| 18165 | + we do not need to subtract 32 from shift count. */ |
| 18166 | + /* Saturate the shift amount to 63. If the amount |
| 18167 | + is any larger op2 is insignificant. */ |
| 18168 | + satu r6 >> 0, 6 |
| 18169 | + /* If shift amount is 32 there are no bits from the msw that are lost. */ |
| 18170 | + moveq lr, r8 |
| 18171 | + breq 0f |
| 18172 | + /* first remember whether part that is lost contains any 1 bits ... */ |
| 18173 | + lsl lr,r9,r5 /* save all lost bits from msw */ |
| 18174 | +#if defined(L_avr32_f64_addsub) |
| 18175 | + cp.w r8, 0 |
| 18176 | + srne r8 |
| 18177 | + or lr,r8 /* also save lost bits (all) from lsw |
| 18178 | + now lr != 0 if we lose any bits */ |
| 18179 | +#endif |
| 18180 | +0: |
| 18181 | + /* ... and now to the actual shift */ |
| 18182 | + lsr r8,r9,r6 /* msw -> lsw and make rest of shift inside lsw*/ |
| 18183 | + mov r9,0 /* clear msw */ |
| 18184 | + rjmp __avr32_f64_add_shift_done |
| 18185 | + |
| 18186 | +__avr32_f64_add_res_of: |
| 18187 | + /* We overflowed. Scale down mantissa by shifting right one position. */ |
| 18188 | + or lr, lr, lr << 1 /* Remember stickybits*/ |
| 18189 | + lsr r11, 1 |
| 18190 | + ror r10 |
| 18191 | + ror lr |
| 18192 | + sub r7, -1 /* Increment exponent */ |
| 18193 | + |
| 18194 | + /* Clear mantissa to set result to Inf if the exponent is 255. */ |
| 18195 | + cp.w r7, 0x7ff |
| 18196 | + moveq r10, 0 |
| 18197 | + moveq r11, 0 |
| 18198 | + moveq lr, 0 |
| 18199 | + rjmp __avr32_f64_add_res_of_done |
| 18200 | + |
| 18201 | +__avr32_f64_add_op2_subnormal: |
| 18202 | + /* Set epxponent to 1 */ |
| 18203 | + mov r6, 1 |
| 18204 | + |
| 18205 | + /* Check if op2 is also subnormal. */ |
| 18206 | + cp.w r7, 0 |
| 18207 | + brne 2b |
| 18208 | + |
| 18209 | + cbr r11, 20 |
| 18210 | + /* Both operands are subnormal. Just addd the mantissas |
| 18211 | + and the exponent will automatically be set to 1 if |
| 18212 | + we overflow into a normal number. */ |
| 18213 | + add r10, r8 |
| 18214 | + adc r11, r11, r9 |
| 18215 | + |
| 18216 | + /* Add sign bit */ |
| 18217 | + or r11, r12 |
| 18218 | + |
| 18219 | + /* Return result in [r11,r10] */ |
| 18220 | + ldm sp++, r5, r6, r7,pc |
| 18221 | + |
| 18222 | + |
| 18223 | + |
| 18224 | +#endif |
| 18225 | + |
| 18226 | +#ifdef L_avr32_f64_to_u32 |
| 18227 | + /* This goes into L_fixdfsi */ |
| 18228 | +#endif |
| 18229 | + |
| 18230 | + |
| 18231 | +#ifdef L_avr32_f64_to_s32 |
| 18232 | + .global __avr32_f64_to_u32 |
| 18233 | + .type __avr32_f64_to_u32,@function |
| 18234 | +__avr32_f64_to_u32: |
| 18235 | + cp.w r11, 0 |
| 18236 | + retmi 0 /* Negative returns 0 */ |
| 18237 | + |
| 18238 | + /* Fallthrough to df to signed si conversion */ |
| 18239 | + .global __avr32_f64_to_s32 |
| 18240 | + .type __avr32_f64_to_s32,@function |
| 18241 | +__avr32_f64_to_s32: |
| 18242 | + lsl r12,r11,1 |
| 18243 | + lsr r12,21 /* extract exponent*/ |
| 18244 | + sub r12,1023 /* convert to unbiased exponent.*/ |
| 18245 | + retlo 0 /* too small exponent implies zero. */ |
| 18246 | + |
| 18247 | +1: |
| 18248 | + rsub r12,r12,31 /* shift count = 31 - exponent */ |
| 18249 | + mov r9,r11 /* save sign for later...*/ |
| 18250 | + lsl r11,11 /* remove exponent and sign*/ |
| 18251 | + sbr r11,31 /* add implicit bit*/ |
| 18252 | + or r11,r11,r10>>21 /* get rest of bits from lsw of double */ |
| 18253 | + lsr r11,r11,r12 /* shift down mantissa to final place */ |
| 18254 | + lsl r9,1 /* sign -> carry */ |
| 18255 | + retcc r11 /* if positive, we are done */ |
| 18256 | + neg r11 /* if negative float, negate result */ |
| 18257 | + ret r11 |
| 18258 | + |
| 18259 | +#endif /* L_fixdfsi*/ |
| 18260 | + |
| 18261 | +#ifdef L_avr32_f64_to_u64 |
| 18262 | + /* Actual function is in L_fixdfdi */ |
| 18263 | +#endif |
| 18264 | + |
| 18265 | +#ifdef L_avr32_f64_to_s64 |
| 18266 | + .global __avr32_f64_to_u64 |
| 18267 | + .type __avr32_f64_to_u64,@function |
| 18268 | +__avr32_f64_to_u64: |
| 18269 | + cp.w r11,0 |
| 18270 | + /* Negative numbers return zero */ |
| 18271 | + movmi r10, 0 |
| 18272 | + movmi r11, 0 |
| 18273 | + retmi r11 |
| 18274 | + |
| 18275 | + |
| 18276 | + |
| 18277 | + /* Fallthrough */ |
| 18278 | + .global __avr32_f64_to_s64 |
| 18279 | + .type __avr32_f64_to_s64,@function |
| 18280 | +__avr32_f64_to_s64: |
| 18281 | + lsl r9,r11,1 |
| 18282 | + lsr r9,21 /* get exponent*/ |
| 18283 | + sub r9,1023 /* convert to correct range*/ |
| 18284 | + /* Return zero if exponent to small */ |
| 18285 | + movlo r10, 0 |
| 18286 | + movlo r11, 0 |
| 18287 | + retlo r11 |
| 18288 | + |
| 18289 | + mov r8,r11 /* save sign for later...*/ |
| 18290 | +1: |
| 18291 | + lsl r11,11 /* remove exponent */ |
| 18292 | + sbr r11,31 /* add implicit bit*/ |
| 18293 | + or r11,r11,r10>>21 /* get rest of bits from lsw of double*/ |
| 18294 | + lsl r10,11 /* align lsw correctly as well */ |
| 18295 | + rsub r9,r9,63 /* shift count = 63 - exponent */ |
| 18296 | + breq 1f |
| 18297 | + |
| 18298 | + cp.w r9,32 /* is shift count more than one reg? */ |
| 18299 | + brhs 0f |
| 18300 | + |
| 18301 | + mov r12,r11 /* save msw */ |
| 18302 | + lsr r10,r10,r9 /* small shift count, shift down lsw */ |
| 18303 | + lsr r11,r11,r9 /* small shift count, shift down msw */ |
| 18304 | + rsub r9,r9,32 /* get 32-size of shifted out tail */ |
| 18305 | + lsl r12,r12,r9 /* align part to move from msw to lsw */ |
| 18306 | + or r10,r12 /* combine to get new lsw */ |
| 18307 | + rjmp 1f |
| 18308 | + |
| 18309 | +0: |
| 18310 | + lsr r10,r11,r9 /* large shift count,only lsw get bits |
| 18311 | + note that shift count is modulo 32*/ |
| 18312 | + mov r11,0 /* msw will be 0 */ |
| 18313 | + |
| 18314 | +1: |
| 18315 | + lsl r8,1 /* sign -> carry */ |
| 18316 | + retcc r11 /* if positive, we are done */ |
| 18317 | + |
| 18318 | + neg r11 /* if negative float, negate result */ |
| 18319 | + neg r10 |
| 18320 | + scr r11 |
| 18321 | + ret r11 |
| 18322 | + |
| 18323 | +#endif |
| 18324 | + |
| 18325 | +#ifdef L_avr32_u32_to_f64 |
| 18326 | + /* Code located in L_floatsidf */ |
| 18327 | +#endif |
| 18328 | + |
| 18329 | +#ifdef L_avr32_s32_to_f64 |
| 18330 | + .global __avr32_u32_to_f64 |
| 18331 | + .type __avr32_u32_to_f64,@function |
| 18332 | +__avr32_u32_to_f64: |
| 18333 | + sub r11, r12, 0 /* Move to r11 and force Z flag to be updated */ |
| 18334 | + mov r12, 0 /* always positive */ |
| 18335 | + rjmp 0f /* Jump to common code for floatsidf */ |
| 18336 | + |
| 18337 | + .global __avr32_s32_to_f64 |
| 18338 | + .type __avr32_s32_to_f64,@function |
| 18339 | +__avr32_s32_to_f64: |
| 18340 | + mov r11, r12 /* Keep original value in r12 for sign */ |
| 18341 | + abs r11 /* Absolute value if r12 */ |
| 18342 | +0: |
| 18343 | + mov r10,0 /* let remaining bits be zero */ |
| 18344 | + reteq r11 /* zero long will return zero float */ |
| 18345 | + |
| 18346 | + pushm lr |
| 18347 | + mov r9,31+1023 /* set exponent */ |
| 18348 | + |
| 18349 | + normalize_df r9 /*exp*/, r10, r11 /* mantissa */, r8, lr /* scratch */ |
| 18350 | + |
| 18351 | + /* Check if a subnormal result was created */ |
| 18352 | + cp.w r9, 0 |
| 18353 | + brgt 0f |
| 18354 | + |
| 18355 | + adjust_subnormal_df r9 /* exp */, r10, r11 /* Mantissa */, r12 /*sign*/, r8, lr /* scratch */ |
| 18356 | + popm pc |
| 18357 | +0: |
| 18358 | + |
| 18359 | + /* Round result */ |
| 18360 | + round_df r9 /*exp*/, r10, r11 /* Mantissa */, r8 /*scratch*/ |
| 18361 | + cp.w r9,0x7ff |
| 18362 | + brlt 0f |
| 18363 | + /*Return infinity */ |
| 18364 | + mov r10, 0 |
| 18365 | + mov_imm r11, 0xffe00000 |
| 18366 | + rjmp __floatsidf_return_op1 |
| 18367 | + |
| 18368 | +0: |
| 18369 | + |
| 18370 | + /* Pack */ |
| 18371 | + pack_df r9 /*exp*/, r10, r11 /* mantissa */, r10, r11 /* Output df number*/ |
| 18372 | +__floatsidf_return_op1: |
| 18373 | + lsl r12,1 /* shift in sign bit */ |
| 18374 | + ror r11 |
| 18375 | + |
| 18376 | + popm pc |
| 18377 | +#endif |
| 18378 | + |
| 18379 | + |
| 18380 | +#ifdef L_avr32_f32_cmp_eq |
| 18381 | + .global __avr32_f32_cmp_eq |
| 18382 | + .type __avr32_f32_cmp_eq,@function |
| 18383 | +__avr32_f32_cmp_eq: |
| 18384 | + cp.w r12, r11 |
| 18385 | + breq 0f |
| 18386 | + /* If not equal check for +/-0 */ |
| 18387 | + /* Or together the two values and shift out the sign bit. |
| 18388 | + If the result is zero, then the two values are both zero. */ |
| 18389 | + or r12, r11 |
| 18390 | + lsl r12, 1 |
| 18391 | + reteq 1 |
| 18392 | + ret 0 |
| 18393 | +0: |
| 18394 | + /* Numbers were equal. Check for NaN or Inf */ |
| 18395 | + mov_imm r11, 0xff000000 |
| 18396 | + lsl r12, 1 |
| 18397 | + cp.w r12, r11 |
| 18398 | + retls 1 /* 0 if NaN, 1 otherwise */ |
| 18399 | + ret 0 |
| 18400 | +#endif |
| 18401 | + |
| 18402 | +#if defined(L_avr32_f32_cmp_ge) || defined(L_avr32_f32_cmp_lt) |
| 18403 | +#ifdef L_avr32_f32_cmp_ge |
| 18404 | + .global __avr32_f32_cmp_ge |
| 18405 | + .type __avr32_f32_cmp_ge,@function |
| 18406 | +__avr32_f32_cmp_ge: |
| 18407 | +#endif |
| 18408 | +#ifdef L_avr32_f32_cmp_lt |
| 18409 | + .global __avr32_f32_cmp_lt |
| 18410 | + .type __avr32_f32_cmp_lt,@function |
| 18411 | +__avr32_f32_cmp_lt: |
| 18412 | +#endif |
| 18413 | + lsl r10, r12, 1 /* Remove sign bits */ |
| 18414 | + lsl r9, r11, 1 |
| 18415 | + subfeq r10, 0 |
| 18416 | +#ifdef L_avr32_f32_cmp_ge |
| 18417 | + reteq 1 /* Both number are zero. Return true. */ |
| 18418 | +#endif |
| 18419 | +#ifdef L_avr32_f32_cmp_lt |
| 18420 | + reteq 0 /* Both number are zero. Return false. */ |
| 18421 | +#endif |
| 18422 | + mov_imm r8, 0xff000000 |
| 18423 | + cp.w r10, r8 |
| 18424 | + rethi 0 /* Op0 is NaN */ |
| 18425 | + cp.w r9, r8 |
| 18426 | + rethi 0 /* Op1 is Nan */ |
| 18427 | + |
| 18428 | + eor r8, r11, r12 |
| 18429 | + bld r12, 31 |
| 18430 | +#ifdef L_avr32_f32_cmp_ge |
| 18431 | + srcc r8 /* Set result to true if op0 is positive*/ |
| 18432 | +#endif |
| 18433 | +#ifdef L_avr32_f32_cmp_lt |
| 18434 | + srcs r8 /* Set result to true if op0 is negative*/ |
| 18435 | +#endif |
| 18436 | + retmi r8 /* Return if signs are different */ |
| 18437 | + brcs 0f /* Both signs negative? */ |
| 18438 | + |
| 18439 | + /* Both signs positive */ |
| 18440 | + cp.w r12, r11 |
| 18441 | +#ifdef L_avr32_f32_cmp_ge |
| 18442 | + reths 1 |
| 18443 | + retlo 0 |
| 18444 | +#endif |
| 18445 | +#ifdef L_avr32_f32_cmp_lt |
| 18446 | + reths 0 |
| 18447 | + retlo 1 |
| 18448 | +#endif |
| 18449 | +0: |
| 18450 | + /* Both signs negative */ |
| 18451 | + cp.w r11, r12 |
| 18452 | +#ifdef L_avr32_f32_cmp_ge |
| 18453 | + reths 1 |
| 18454 | + retlo 0 |
| 18455 | +#endif |
| 18456 | +#ifdef L_avr32_f32_cmp_lt |
| 18457 | + reths 0 |
| 18458 | + retlo 1 |
| 18459 | +#endif |
| 18460 | +#endif |
| 18461 | + |
| 18462 | + |
| 18463 | +#ifdef L_avr32_f64_cmp_eq |
| 18464 | + .global __avr32_f64_cmp_eq |
| 18465 | + .type __avr32_f64_cmp_eq,@function |
| 18466 | +__avr32_f64_cmp_eq: |
| 18467 | + cp.w r10,r8 |
| 18468 | + cpc r11,r9 |
| 18469 | + breq 0f |
| 18470 | + |
| 18471 | + /* Args were not equal*/ |
| 18472 | + /* Both args could be zero with different sign bits */ |
| 18473 | + lsl r11,1 /* get rid of sign bits */ |
| 18474 | + lsl r9,1 |
| 18475 | + or r11,r10 /* Check if all bits are zero */ |
| 18476 | + or r11,r9 |
| 18477 | + or r11,r8 |
| 18478 | + reteq 1 /* If all zeros the arguments are equal |
| 18479 | + so return 1 else return 0 */ |
| 18480 | + ret 0 |
| 18481 | +0: |
| 18482 | + /* check for NaN */ |
| 18483 | + lsl r11,1 |
| 18484 | + mov_imm r12, 0xffe00000 |
| 18485 | + cp.w r10,0 |
| 18486 | + cpc r11,r12 /* check if nan or inf */ |
| 18487 | + retls 1 /* If Arg is NaN return 0 else 1*/ |
| 18488 | + ret 0 /* Return */ |
| 18489 | + |
| 18490 | +#endif |
| 18491 | + |
| 18492 | + |
| 18493 | +#if defined(L_avr32_f64_cmp_ge) || defined(L_avr32_f64_cmp_lt) |
| 18494 | + |
| 18495 | +#ifdef L_avr32_f64_cmp_ge |
| 18496 | + .global __avr32_f64_cmp_ge |
| 18497 | + .type __avr32_f64_cmp_ge,@function |
| 18498 | +__avr32_f64_cmp_ge: |
| 18499 | +#endif |
| 18500 | +#ifdef L_avr32_f64_cmp_lt |
| 18501 | + .global __avr32_f64_cmp_lt |
| 18502 | + .type __avr32_f64_cmp_lt,@function |
| 18503 | +__avr32_f64_cmp_lt: |
| 18504 | +#endif |
| 18505 | + |
| 18506 | + /* compare magnitude of op1 and op2 */ |
| 18507 | + st.w --sp, lr |
| 18508 | + st.w --sp, r7 |
| 18509 | + lsl r11,1 /* Remove sign bit of op1 */ |
| 18510 | + srcs r12 /* Sign op1 to lsb of r12*/ |
| 18511 | + lsl r9,1 /* Remove sign bit of op2 */ |
| 18512 | + srcs r7 |
| 18513 | + rol r12 /* Sign op2 to lsb of lr, sign bit op1 bit 1 of r12*/ |
| 18514 | + |
| 18515 | + |
| 18516 | + /* Check for Nan */ |
| 18517 | + mov_imm lr, 0xffe00000 |
| 18518 | + cp.w r10,0 |
| 18519 | + cpc r11,lr |
| 18520 | + brhi 0f /* We have NaN */ |
| 18521 | + cp.w r8,0 |
| 18522 | + cpc r9,lr |
| 18523 | + brhi 0f /* We have NaN */ |
| 18524 | + |
| 18525 | + cp.w r11, 0 |
| 18526 | + subfeq r10, 0 |
| 18527 | + breq 3f /* op1 zero */ |
| 18528 | + ld.w r7, sp++ |
| 18529 | + ld.w lr, sp++ |
| 18530 | + |
| 18531 | + cp.w r12,3 /* both operands negative ?*/ |
| 18532 | + breq 1f |
| 18533 | + |
| 18534 | + cp.w r12,1 /* both operands positive? */ |
| 18535 | + brlo 2f |
| 18536 | + |
| 18537 | + /* Different signs. If sign of op1 is negative the difference |
| 18538 | + between op1 and op2 will always be negative, and if op1 is |
| 18539 | + positive the difference will always be positive */ |
| 18540 | +#ifdef L_avr32_f64_cmp_ge |
| 18541 | + reteq 1 |
| 18542 | + retne 0 |
| 18543 | +#endif |
| 18544 | +#ifdef L_avr32_f64_cmp_lt |
| 18545 | + reteq 0 |
| 18546 | + retne 1 |
| 18547 | +#endif |
| 18548 | + |
| 18549 | +2: |
| 18550 | + /* Both operands positive. Just compute the difference */ |
| 18551 | + cp.w r10,r8 |
| 18552 | + cpc r11,r9 |
| 18553 | +#ifdef L_avr32_f64_cmp_ge |
| 18554 | + reths 1 |
| 18555 | + retlo 0 |
| 18556 | +#endif |
| 18557 | +#ifdef L_avr32_f64_cmp_lt |
| 18558 | + reths 0 |
| 18559 | + retlo 1 |
| 18560 | +#endif |
| 18561 | + |
| 18562 | +1: |
| 18563 | + /* Both operands negative. Compute the difference with operands switched */ |
| 18564 | + cp r8,r10 |
| 18565 | + cpc r9,r11 |
| 18566 | +#ifdef L_avr32_f64_cmp_ge |
| 18567 | + reths 1 |
| 18568 | + retlo 0 |
| 18569 | +#endif |
| 18570 | +#ifdef L_avr32_f64_cmp_lt |
| 18571 | + reths 0 |
| 18572 | + retlo 1 |
| 18573 | +#endif |
| 18574 | + |
| 18575 | +0: |
| 18576 | + ld.w r7, sp++ |
| 18577 | + popm pc, r12=0 |
| 18578 | +#endif |
| 18579 | + |
| 18580 | +3: |
| 18581 | + cp.w r7, 1 /* Check sign bit from r9 */ |
| 18582 | +#ifdef L_avr32_f64_cmp_ge |
| 18583 | + sreq r12 /* If op2 is negative then op1 >= op2. */ |
| 18584 | +#endif |
| 18585 | +#ifdef L_avr32_f64_cmp_lt |
| 18586 | + srne r12 /* If op2 is positve then op1 <= op2. */ |
| 18587 | +#endif |
| 18588 | + cp.w r9, 0 |
| 18589 | + subfeq r8, 0 |
| 18590 | + ld.w r7, sp++ |
| 18591 | + ld.w lr, sp++ |
| 18592 | +#ifdef L_avr32_f64_cmp_ge |
| 18593 | + reteq 1 /* Both operands are zero. Return true. */ |
| 18594 | +#endif |
| 18595 | +#ifdef L_avr32_f64_cmp_lt |
| 18596 | + reteq 0 /* Both operands are zero. Return false. */ |
| 18597 | +#endif |
| 18598 | + ret r12 |
| 18599 | + |
| 18600 | + |
| 18601 | +#if defined(L_avr32_f64_div) || defined(L_avr32_f64_div_fast) |
| 18602 | + .align 2 |
| 18603 | + |
| 18604 | +#if defined(L_avr32_f64_div_fast) |
| 18605 | + .global __avr32_f64_div_fast |
| 18606 | + .type __avr32_f64_div_fast,@function |
| 18607 | +__avr32_f64_div_fast: |
| 18608 | +#else |
| 18609 | + .global __avr32_f64_div |
| 18610 | + .type __avr32_f64_div,@function |
| 18611 | +__avr32_f64_div: |
| 18612 | +#endif |
| 18613 | + stm --sp, r0, r1, r2, r3, r4, r5, r6, r7,lr |
| 18614 | + /* op1 in {r11,r10}*/ |
| 18615 | + /* op2 in {r9,r8}*/ |
| 18616 | + eor lr, r11, r9 /* MSB(lr) = Sign(op1) ^ Sign(op2) */ |
| 18617 | + |
| 18618 | + |
| 18619 | + /* Unpack op1 to 2.62 format*/ |
| 18620 | + /* exp: r7 */ |
| 18621 | + /* sf: r11, r10 */ |
| 18622 | + lsr r7, r11, 20 /* Extract exponent */ |
| 18623 | + |
| 18624 | + lsl r11, 9 /* Extract mantissa, leave room for implicit bit */ |
| 18625 | + or r11, r11, r10>>23 |
| 18626 | + lsl r10, 9 |
| 18627 | + sbr r11, 29 /* Insert implicit bit */ |
| 18628 | + andh r11, 0x3fff /*Mask last part of exponent since we use 2.62 format*/ |
| 18629 | + |
| 18630 | + cbr r7, 11 /* Clear sign bit */ |
| 18631 | + /* Check if normalization is needed */ |
| 18632 | + breq 11f /*If number is subnormal, normalize it */ |
| 18633 | +22: |
| 18634 | + cp r7, 0x7ff |
| 18635 | + brge 2f /* Check op1 for NaN or Inf */ |
| 18636 | + |
| 18637 | + /* Unpack op2 to 2.62 format*/ |
| 18638 | + /* exp: r6 */ |
| 18639 | + /* sf: r9, r8 */ |
| 18640 | + lsr r6, r9, 20 /* Extract exponent */ |
| 18641 | + |
| 18642 | + lsl r9, 9 /* Extract mantissa, leave room for implicit bit */ |
| 18643 | + or r9, r9, r8>>23 |
| 18644 | + lsl r8, 9 |
| 18645 | + sbr r9, 29 /* Insert implicit bit */ |
| 18646 | + andh r9, 0x3fff /*Mask last part of exponent since we use 2.62 format*/ |
| 18647 | + |
| 18648 | + cbr r6, 11 /* Clear sign bit */ |
| 18649 | + /* Check if normalization is needed */ |
| 18650 | + breq 13f /*If number is subnormal, normalize it */ |
| 18651 | +23: |
| 18652 | + cp r6, 0x7ff |
| 18653 | + brge 3f /* Check op2 for NaN or Inf */ |
| 18654 | + |
| 18655 | + /* Calculate new exponent */ |
| 18656 | + sub r7, r6 |
| 18657 | + sub r7,-1023 |
| 18658 | + |
| 18659 | + /* Divide */ |
| 18660 | + /* Approximating 1/d with the following recurrence: */ |
| 18661 | + /* R[j+1] = R[j]*(2-R[j]*d) */ |
| 18662 | + /* Using 2.62 format */ |
| 18663 | + /* TWO: r12 */ |
| 18664 | + /* d = op2 = divisor (2.62 format): r9,r8 */ |
| 18665 | + /* Multiply result : r5, r4 */ |
| 18666 | + /* Initial guess : r3, r2 */ |
| 18667 | + /* New approximations : r3, r2 */ |
| 18668 | + /* op1 = Dividend (2.62 format) : r11, r10 */ |
| 18669 | + |
| 18670 | + mov_imm r12, 0x80000000 |
| 18671 | + |
| 18672 | + /* Load initial guess, using look-up table */ |
| 18673 | + /* Initial guess is of format 01.XY, where XY is constructed as follows: */ |
| 18674 | + /* Let d be of following format: 00.1xy....., then XY=~xy */ |
| 18675 | + /* For d=00.100 = 0,5 -> initial guess=01.11 = 1,75 */ |
| 18676 | + /* For d=00.101 = 0,625 -> initial guess=01.11 = 1,5 */ |
| 18677 | + /* For d=00.110 = 0,75 -> initial guess=01.11 = 1,25 */ |
| 18678 | + /* For d=00.111 = 0,875 -> initial guess=01.11 = 1,0 */ |
| 18679 | + /* r2 is also part of the reg pair forming initial guess, but it*/ |
| 18680 | + /* is kept uninitialized to save one cycle since it has so low significance*/ |
| 18681 | + |
| 18682 | + lsr r3, r12, 1 |
| 18683 | + bfextu r4, r9, 27, 2 |
| 18684 | + com r4 |
| 18685 | + bfins r3, r4, 28, 2 |
| 18686 | + |
| 18687 | + /* First approximation */ |
| 18688 | + /* Approximating to 32 bits */ |
| 18689 | + /* r5 = R[j]*d */ |
| 18690 | + mulu.d r4, r3, r9 |
| 18691 | + /* r5 = 2-R[j]*d */ |
| 18692 | + sub r5, r12, r5<<2 |
| 18693 | + /* r3 = R[j]*(2-R[j]*d) */ |
| 18694 | + mulu.d r4, r3, r5 |
| 18695 | + lsl r3, r5, 2 |
| 18696 | + |
| 18697 | + /* Second approximation */ |
| 18698 | + /* Approximating to 32 bits */ |
| 18699 | + /* r5 = R[j]*d */ |
| 18700 | + mulu.d r4, r3, r9 |
| 18701 | + /* r5 = 2-R[j]*d */ |
| 18702 | + sub r5, r12, r5<<2 |
| 18703 | + /* r3 = R[j]*(2-R[j]*d) */ |
| 18704 | + mulu.d r4, r3, r5 |
| 18705 | + lsl r3, r5, 2 |
| 18706 | + |
| 18707 | + /* Third approximation */ |
| 18708 | + /* Approximating to 32 bits */ |
| 18709 | + /* r5 = R[j]*d */ |
| 18710 | + mulu.d r4, r3, r9 |
| 18711 | + /* r5 = 2-R[j]*d */ |
| 18712 | + sub r5, r12, r5<<2 |
| 18713 | + /* r3 = R[j]*(2-R[j]*d) */ |
| 18714 | + mulu.d r4, r3, r5 |
| 18715 | + lsl r3, r5, 2 |
| 18716 | + |
| 18717 | + /* Fourth approximation */ |
| 18718 | + /* Approximating to 64 bits */ |
| 18719 | + /* r5,r4 = R[j]*d */ |
| 18720 | + mul_approx_df r3 /*ah*/, r2 /*al*/, r9 /*bh*/, r8 /*bl*/, r5 /*rh*/, r4 /*rl*/, r1 /*sh*/, r0 /*sl*/ |
| 18721 | + lsl r5, 2 |
| 18722 | + or r5, r5, r4>>30 |
| 18723 | + lsl r4, 2 |
| 18724 | + /* r5,r4 = 2-R[j]*d */ |
| 18725 | + neg r4 |
| 18726 | + sbc r5, r12, r5 |
| 18727 | + /* r3,r2 = R[j]*(2-R[j]*d) */ |
| 18728 | + mul_approx_df r3 /*ah*/, r2 /*al*/, r5 /*bh*/, r4 /*bl*/, r5 /*rh*/, r4 /*rl*/, r1 /*sh*/, r0 /*sl*/ |
| 18729 | + lsl r3, r5, 2 |
| 18730 | + or r3, r3, r4>>30 |
| 18731 | + lsl r2, r4, 2 |
| 18732 | + |
| 18733 | + |
| 18734 | + /* Fifth approximation */ |
| 18735 | + /* Approximating to 64 bits */ |
| 18736 | + /* r5,r4 = R[j]*d */ |
| 18737 | + mul_approx_df r3 /*ah*/, r2 /*al*/, r9 /*bh*/, r8 /*bl*/, r5 /*rh*/, r4 /*rl*/, r1 /*sh*/, r0 /*sl*/ |
| 18738 | + lsl r5, 2 |
| 18739 | + or r5, r5, r4>>30 |
| 18740 | + lsl r4, 2 |
| 18741 | + /* r5,r4 = 2-R[j]*d */ |
| 18742 | + neg r4 |
| 18743 | + sbc r5, r12, r5 |
| 18744 | + /* r3,r2 = R[j]*(2-R[j]*d) */ |
| 18745 | + mul_approx_df r3 /*ah*/, r2 /*al*/, r5 /*bh*/, r4 /*bl*/, r5 /*rh*/, r4 /*rl*/, r1 /*sh*/, r0 /*sl*/ |
| 18746 | + lsl r3, r5, 2 |
| 18747 | + or r3, r3, r4>>30 |
| 18748 | + lsl r2, r4, 2 |
| 18749 | + |
| 18750 | + |
| 18751 | + /* Multiply with dividend to get quotient */ |
| 18752 | + mul_approx_df r3 /*ah*/, r2 /*al*/, r11 /*bh*/, r10 /*bl*/, r3 /*rh*/, r2 /*rl*/, r1 /*sh*/, r0 /*sl*/ |
| 18753 | + |
| 18754 | + |
| 18755 | + /* To increase speed, this result is not corrected before final rounding.*/ |
| 18756 | + /* This may give a difference to IEEE compliant code of 1 ULP.*/ |
| 18757 | + |
| 18758 | + |
| 18759 | + /* Adjust exponent and mantissa */ |
| 18760 | + /* r7:exp, [r3, r2]:mant, [r5, r4]:scratch*/ |
| 18761 | + /* Mantissa may be of the format 0.xxxx or 1.xxxx. */ |
| 18762 | + /* In the first case, shift one pos to left.*/ |
| 18763 | + bld r3, 31-3 |
| 18764 | + breq 0f |
| 18765 | + lsl r2, 1 |
| 18766 | + rol r3 |
| 18767 | + sub r7, 1 |
| 18768 | +#if defined(L_avr32_f64_div) |
| 18769 | + /* We must scale down the dividend to 5.59 format. */ |
| 18770 | + lsr r10, 3 |
| 18771 | + or r10, r10, r11 << 29 |
| 18772 | + lsr r11, 3 |
| 18773 | + rjmp 1f |
| 18774 | +#endif |
| 18775 | +0: |
| 18776 | +#if defined(L_avr32_f64_div) |
| 18777 | + /* We must scale down the dividend to 6.58 format. */ |
| 18778 | + lsr r10, 4 |
| 18779 | + or r10, r10, r11 << 28 |
| 18780 | + lsr r11, 4 |
| 18781 | +1: |
| 18782 | +#endif |
| 18783 | + cp r7, 0 |
| 18784 | + brle __avr32_f64_div_res_subnormal /* Result was subnormal. */ |
| 18785 | + |
| 18786 | + |
| 18787 | +#if defined(L_avr32_f64_div) |
| 18788 | + /* In order to round correctly we calculate the remainder: |
| 18789 | + Remainder = dividend[11:r10] - divisor[r9:r8]*quotient[r3:r2] |
| 18790 | + for the case when the quotient is halfway between the round-up |
| 18791 | + value and the round down value. If the remainder then is negative |
| 18792 | + it means that the quotient was to big and that it should not be |
| 18793 | + rounded up, if the remainder is positive the quotient was to small |
| 18794 | + and we need to round up. If the remainder is zero it means that the |
| 18795 | + quotient is exact but since we need to remove the guard bit we should |
| 18796 | + round to even. */ |
| 18797 | + |
| 18798 | + /* Truncate and add guard bit. */ |
| 18799 | + andl r2, 0xff00 |
| 18800 | + orl r2, 0x0080 |
| 18801 | + |
| 18802 | + |
| 18803 | + /* Now do the multiplication. The quotient has the format 4.60 |
| 18804 | + while the divisor has the format 2.62 which gives a result |
| 18805 | + of 6.58 */ |
| 18806 | + mulu.d r0, r3, r8 |
| 18807 | + macu.d r0, r2, r9 |
| 18808 | + mulu.d r4, r2, r8 |
| 18809 | + mulu.d r8, r3, r9 |
| 18810 | + add r5, r0 |
| 18811 | + adc r8, r8, r1 |
| 18812 | + acr r9 |
| 18813 | + |
| 18814 | + |
| 18815 | + /* Check if remainder is positive, negative or equal. */ |
| 18816 | + bfextu r12, r2, 8, 1 /* Get parity bit into bit 0 of r0 */ |
| 18817 | + cp r4, 0 |
| 18818 | + cpc r5 |
| 18819 | +__avr32_f64_div_round_subnormal: |
| 18820 | + cpc r8, r10 |
| 18821 | + cpc r9, r11 |
| 18822 | + srlo r6 /* Remainder positive: we need to round up.*/ |
| 18823 | + moveq r6, r12 /* Remainder zero: round up if mantissa odd. */ |
| 18824 | +#else |
| 18825 | + bfextu r6, r2, 7, 1 /* Get guard bit */ |
| 18826 | +#endif |
| 18827 | + /* Final packing, scale down mantissa. */ |
| 18828 | + lsr r10, r2, 8 |
| 18829 | + or r10, r10, r3<<24 |
| 18830 | + lsr r11, r3, 8 |
| 18831 | + /* Insert exponent and sign bit*/ |
| 18832 | + bfins r11, r7, 20, 11 |
| 18833 | + bld lr, 31 |
| 18834 | + bst r11, 31 |
| 18835 | + |
| 18836 | + /* Final rounding */ |
| 18837 | + add r10, r6 |
| 18838 | + acr r11 |
| 18839 | + |
| 18840 | + /* Return result in [r11,r10] */ |
| 18841 | + ldm sp++, r0, r1, r2, r3, r4, r5, r6, r7,pc |
| 18842 | + |
| 18843 | + |
| 18844 | +2: |
| 18845 | + /* Op1 is NaN or inf */ |
| 18846 | + andh r11, 0x000f /* Extract mantissa */ |
| 18847 | + or r11, r10 |
| 18848 | + brne 16f /* Return NaN if op1 is NaN */ |
| 18849 | + /* Op1 is inf check op2 */ |
| 18850 | + lsr r6, r9, 20 /* Extract exponent */ |
| 18851 | + cbr r6, 11 /* Clear sign bit */ |
| 18852 | + cp r6, 0x7ff |
| 18853 | + brne 17f /* Inf/number gives inf, return inf */ |
| 18854 | + rjmp 16f /* The rest gives NaN*/ |
| 18855 | + |
| 18856 | +3: |
| 18857 | + /* Op1 is a valid number. Op 2 is NaN or inf */ |
| 18858 | + andh r9, 0x000f /* Extract mantissa */ |
| 18859 | + or r9, r8 |
| 18860 | + brne 16f /* Return NaN if op2 is NaN */ |
| 18861 | + rjmp 15f /* Op2 was inf, return zero*/ |
| 18862 | + |
| 18863 | +11: /* Op1 was denormal. Fix it. */ |
| 18864 | + lsl r11, 3 |
| 18865 | + or r11, r11, r10 >> 29 |
| 18866 | + lsl r10, 3 |
| 18867 | + /* Check if op1 is zero. */ |
| 18868 | + or r4, r10, r11 |
| 18869 | + breq __avr32_f64_div_op1_zero |
| 18870 | + normalize_df r7 /*exp*/, r10, r11 /*Mantissa*/, r4, r5 /*scratch*/ |
| 18871 | + lsr r10, 2 |
| 18872 | + or r10, r10, r11 << 30 |
| 18873 | + lsr r11, 2 |
| 18874 | + rjmp 22b |
| 18875 | + |
| 18876 | + |
| 18877 | +13: /* Op2 was denormal. Fix it */ |
| 18878 | + lsl r9, 3 |
| 18879 | + or r9, r9, r8 >> 29 |
| 18880 | + lsl r8, 3 |
| 18881 | + /* Check if op2 is zero. */ |
| 18882 | + or r4, r9, r8 |
| 18883 | + breq 17f /* Divisor is zero -> return Inf */ |
| 18884 | + normalize_df r6 /*exp*/, r8, r9 /*Mantissa*/, r4, r5 /*scratch*/ |
| 18885 | + lsr r8, 2 |
| 18886 | + or r8, r8, r9 << 30 |
| 18887 | + lsr r9, 2 |
| 18888 | + rjmp 23b |
| 18889 | + |
| 18890 | + |
| 18891 | +__avr32_f64_div_res_subnormal:/* Divide result was subnormal. */ |
| 18892 | +#if defined(L_avr32_f64_div) |
| 18893 | + /* Check how much we must scale down the mantissa. */ |
| 18894 | + neg r7 |
| 18895 | + sub r7, -1 /* We do no longer have an implicit bit. */ |
| 18896 | + satu r7 >> 0, 6 /* Saturate shift amount to max 63. */ |
| 18897 | + cp.w r7, 32 |
| 18898 | + brge 0f |
| 18899 | + /* Shift amount <32 */ |
| 18900 | + /* Scale down quotient */ |
| 18901 | + rsub r6, r7, 32 |
| 18902 | + lsr r2, r2, r7 |
| 18903 | + lsl r12, r3, r6 |
| 18904 | + or r2, r12 |
| 18905 | + lsr r3, r3, r7 |
| 18906 | + /* Scale down the dividend to match the scaling of the quotient. */ |
| 18907 | + lsl r1, r10, r6 |
| 18908 | + lsr r10, r10, r7 |
| 18909 | + lsl r12, r11, r6 |
| 18910 | + or r10, r12 |
| 18911 | + lsr r11, r11, r7 |
| 18912 | + mov r0, 0 |
| 18913 | + rjmp 1f |
| 18914 | +0: |
| 18915 | + /* Shift amount >=32 */ |
| 18916 | + rsub r6, r7, 32 |
| 18917 | + moveq r0, 0 |
| 18918 | + moveq r12, 0 |
| 18919 | + breq 0f |
| 18920 | + lsl r0, r10, r6 |
| 18921 | + lsl r12, r11, r6 |
| 18922 | +0: |
| 18923 | + lsr r2, r3, r7 |
| 18924 | + mov r3, 0 |
| 18925 | + /* Scale down the dividend to match the scaling of the quotient. */ |
| 18926 | + lsr r1, r10, r7 |
| 18927 | + or r1, r12 |
| 18928 | + lsr r10, r11, r7 |
| 18929 | + mov r11, 0 |
| 18930 | +1: |
| 18931 | + /* Start performing the same rounding as done for normal numbers |
| 18932 | + but this time we have scaled the quotient and dividend and hence |
| 18933 | + need a little different comparison. */ |
| 18934 | + /* Truncate and add guard bit. */ |
| 18935 | + andl r2, 0xff00 |
| 18936 | + orl r2, 0x0080 |
| 18937 | + |
| 18938 | + /* Now do the multiplication. */ |
| 18939 | + mulu.d r6, r3, r8 |
| 18940 | + macu.d r6, r2, r9 |
| 18941 | + mulu.d r4, r2, r8 |
| 18942 | + mulu.d r8, r3, r9 |
| 18943 | + add r5, r6 |
| 18944 | + adc r8, r8, r7 |
| 18945 | + acr r9 |
| 18946 | + |
| 18947 | + /* Set exponent to 0 */ |
| 18948 | + mov r7, 0 |
| 18949 | + |
| 18950 | + /* Check if remainder is positive, negative or equal. */ |
| 18951 | + bfextu r12, r2, 8, 1 /* Get parity bit into bit 0 of r0 */ |
| 18952 | + cp r4, r0 |
| 18953 | + cpc r5, r1 |
| 18954 | + /* Now the rest of the rounding is the same as for normals. */ |
| 18955 | + rjmp __avr32_f64_div_round_subnormal |
| 18956 | + |
| 18957 | +#endif |
| 18958 | +15: |
| 18959 | + /* Flush to zero for the fast version. */ |
| 18960 | + mov r11, lr /*Get correct sign*/ |
| 18961 | + andh r11, 0x8000, COH |
| 18962 | + mov r10, 0 |
| 18963 | + ldm sp++, r0, r1, r2, r3, r4, r5, r6, r7,pc |
| 18964 | + |
| 18965 | +16: /* Return NaN. */ |
| 18966 | + mov r11, -1 |
| 18967 | + mov r10, 0 |
| 18968 | + ldm sp++, r0, r1, r2, r3, r4, r5, r6, r7,pc |
| 18969 | + |
| 18970 | +17: |
| 18971 | + /* Check if op1 is zero. */ |
| 18972 | + or r4, r10, r11 |
| 18973 | + breq __avr32_f64_div_op1_zero |
| 18974 | + /* Return INF. */ |
| 18975 | + mov r11, lr /*Get correct sign*/ |
| 18976 | + andh r11, 0x8000, COH |
| 18977 | + orh r11, 0x7ff0 |
| 18978 | + mov r10, 0 |
| 18979 | + ldm sp++, r0, r1, r2, r3, r4, r5, r6, r7,pc |
| 18980 | + |
| 18981 | +__avr32_f64_div_op1_zero: |
| 18982 | + or r5, r8, r9 << 1 |
| 18983 | + breq 16b /* 0.0/0.0 -> NaN */ |
| 18984 | + bfextu r4, r9, 20, 11 |
| 18985 | + cp r4, 0x7ff |
| 18986 | + brne 15b /* Return zero */ |
| 18987 | + /* Check if divisor is Inf or NaN */ |
| 18988 | + or r5, r8, r9 << 12 |
| 18989 | + breq 15b /* Divisor is inf -> return zero */ |
| 18990 | + rjmp 16b /* Return NaN */ |
| 18991 | + |
| 18992 | + |
| 18993 | + |
| 18994 | + |
| 18995 | +#endif |
| 18996 | + |
| 18997 | +#if defined(L_avr32_f32_addsub) || defined(L_avr32_f32_addsub_fast) |
| 18998 | + |
| 18999 | + .align 2 |
| 19000 | +__avr32_f32_sub_from_add: |
| 19001 | + /* Switch sign on op2 */ |
| 19002 | + eorh r11, 0x8000 |
| 19003 | + |
| 19004 | +#if defined(L_avr32_f32_addsub_fast) |
| 19005 | + .global __avr32_f32_sub_fast |
| 19006 | + .type __avr32_f32_sub_fast,@function |
| 19007 | +__avr32_f32_sub_fast: |
| 19008 | +#else |
| 19009 | + .global __avr32_f32_sub |
| 19010 | + .type __avr32_f32_sub,@function |
| 19011 | +__avr32_f32_sub: |
| 19012 | +#endif |
| 19013 | + |
| 19014 | + /* Check signs */ |
| 19015 | + eor r8, r11, r12 |
| 19016 | + /* Different signs, use subtraction. */ |
| 19017 | + brmi __avr32_f32_add_from_sub |
| 19018 | + |
| 19019 | + /* Get sign of op1 */ |
| 19020 | + mov r8, r12 |
| 19021 | + andh r12, 0x8000, COH |
| 19022 | + |
| 19023 | + /* Remove sign from operands */ |
| 19024 | + cbr r11, 31 |
| 19025 | +#if defined(L_avr32_f32_addsub_fast) |
| 19026 | + reteq r8 /* If op2 is zero return op1 */ |
| 19027 | +#endif |
| 19028 | + cbr r8, 31 |
| 19029 | + |
| 19030 | + /* Put the number with the largest exponent in r10 |
| 19031 | + and the number with the smallest exponent in r9 */ |
| 19032 | + max r10, r8, r11 |
| 19033 | + min r9, r8, r11 |
| 19034 | + cp r10, r8 /*If largest operand (in R10) is not equal to op1*/ |
| 19035 | + subne r12, 1 /* Subtract 1 from sign, which will invert MSB of r12*/ |
| 19036 | + andh r12, 0x8000, COH /*Mask all but MSB*/ |
| 19037 | + |
| 19038 | + /* Unpack exponent and mantissa of op1 */ |
| 19039 | + lsl r8, r10, 8 |
| 19040 | + sbr r8, 31 /* Set implicit bit. */ |
| 19041 | + lsr r10, 23 |
| 19042 | + |
| 19043 | + /* op1 is NaN or Inf. */ |
| 19044 | + cp.w r10, 0xff |
| 19045 | + breq __avr32_f32_sub_op1_nan_or_inf |
| 19046 | + |
| 19047 | + /* Unpack exponent and mantissa of op2 */ |
| 19048 | + lsl r11, r9, 8 |
| 19049 | + sbr r11, 31 /* Set implicit bit. */ |
| 19050 | + lsr r9, 23 |
| 19051 | + |
| 19052 | +#if defined(L_avr32_f32_addsub) |
| 19053 | + /* Keep sticky bit for correct IEEE rounding */ |
| 19054 | + st.w --sp, r12 |
| 19055 | + |
| 19056 | + /* op2 is either zero or subnormal. */ |
| 19057 | + breq __avr32_f32_sub_op2_subnormal |
| 19058 | +0: |
| 19059 | + /* Get shift amount to scale mantissa of op2. */ |
| 19060 | + sub r12, r10, r9 |
| 19061 | + |
| 19062 | + breq __avr32_f32_sub_shift_done |
| 19063 | + |
| 19064 | + /* Saturate the shift amount to 31. If the amount |
| 19065 | + is any larger op2 is insignificant. */ |
| 19066 | + satu r12 >> 0, 5 |
| 19067 | + |
| 19068 | + /* Put the remaining bits into r9.*/ |
| 19069 | + rsub r9, r12, 32 |
| 19070 | + lsl r9, r11, r9 |
| 19071 | + |
| 19072 | + /* If the remaining bits are non-zero then we must subtract one |
| 19073 | + more from opL. */ |
| 19074 | + subne r8, 1 |
| 19075 | + srne r9 /* LSB of r9 represents sticky bits. */ |
| 19076 | + |
| 19077 | + /* Shift mantissa of op2 to same decimal point as the mantissa |
| 19078 | + of op1. */ |
| 19079 | + lsr r11, r11, r12 |
| 19080 | + |
| 19081 | + |
| 19082 | +__avr32_f32_sub_shift_done: |
| 19083 | + /* Now subtract the mantissas. */ |
| 19084 | + sub r8, r11 |
| 19085 | + |
| 19086 | + ld.w r12, sp++ |
| 19087 | + |
| 19088 | + /* Normalize resulting mantissa. */ |
| 19089 | + clz r11, r8 |
| 19090 | + |
| 19091 | + retcs 0 |
| 19092 | + lsl r8, r8, r11 |
| 19093 | + sub r10, r11 |
| 19094 | + brle __avr32_f32_sub_subnormal_result |
| 19095 | + |
| 19096 | + /* Insert the bits we will remove from the mantissa into r9[31:24] */ |
| 19097 | + or r9, r9, r8 << 24 |
| 19098 | +#else |
| 19099 | + /* Ignore sticky bit to simplify and speed up rounding */ |
| 19100 | + /* op2 is either zero or subnormal. */ |
| 19101 | + breq __avr32_f32_sub_op2_subnormal |
| 19102 | +0: |
| 19103 | + /* Get shift amount to scale mantissa of op2. */ |
| 19104 | + rsub r9, r10 |
| 19105 | + |
| 19106 | + /* Saturate the shift amount to 31. If the amount |
| 19107 | + is any larger op2 is insignificant. */ |
| 19108 | + satu r9 >> 0, 5 |
| 19109 | + |
| 19110 | + /* Shift mantissa of op2 to same decimal point as the mantissa |
| 19111 | + of op1. */ |
| 19112 | + lsr r11, r11, r9 |
| 19113 | + |
| 19114 | + /* Now subtract the mantissas. */ |
| 19115 | + sub r8, r11 |
| 19116 | + |
| 19117 | + /* Normalize resulting mantissa. */ |
| 19118 | + clz r9, r8 |
| 19119 | + retcs 0 |
| 19120 | + lsl r8, r8, r9 |
| 19121 | + sub r10, r9 |
| 19122 | + brle __avr32_f32_sub_subnormal_result |
| 19123 | +#endif |
| 19124 | + |
| 19125 | + /* Pack result. */ |
| 19126 | + or r12, r12, r8 >> 8 |
| 19127 | + bfins r12, r10, 23, 8 |
| 19128 | + |
| 19129 | + /* Round */ |
| 19130 | +__avr32_f32_sub_round: |
| 19131 | +#if defined(L_avr32_f32_addsub) |
| 19132 | + mov_imm r10, 0x80000000 |
| 19133 | + bld r12, 0 |
| 19134 | + subne r10, -1 |
| 19135 | + cp.w r9, r10 |
| 19136 | + subhs r12, -1 |
| 19137 | +#else |
| 19138 | + bld r8, 7 |
| 19139 | + acr r12 |
| 19140 | +#endif |
| 19141 | + |
| 19142 | + ret r12 |
| 19143 | + |
| 19144 | + |
| 19145 | +__avr32_f32_sub_op2_subnormal: |
| 19146 | + /* Fix implicit bit and adjust exponent of subnormals. */ |
| 19147 | + cbr r11, 31 |
| 19148 | + /* Set exponent to 1 if we do not have a zero. */ |
| 19149 | + movne r9,1 |
| 19150 | + |
| 19151 | + /* Check if op1 is also subnormal. */ |
| 19152 | + cp.w r10, 0 |
| 19153 | + brne 0b |
| 19154 | + |
| 19155 | + cbr r8, 31 |
| 19156 | + /* If op1 is not zero set exponent to 1. */ |
| 19157 | + movne r10,1 |
| 19158 | + |
| 19159 | + rjmp 0b |
| 19160 | + |
| 19161 | +__avr32_f32_sub_op1_nan_or_inf: |
| 19162 | + /* Check if op1 is NaN, if so return NaN */ |
| 19163 | + lsl r11, r8, 1 |
| 19164 | + retne -1 |
| 19165 | + |
| 19166 | + /* op1 is Inf. */ |
| 19167 | + bfins r12, r10, 23, 8 /* Generate Inf in r12 */ |
| 19168 | + |
| 19169 | + /* Check if op2 is Inf. or NaN */ |
| 19170 | + lsr r11, r9, 23 |
| 19171 | + cp.w r11, 0xff |
| 19172 | + retne r12 /* op2 not Inf or NaN, return op1 */ |
| 19173 | + |
| 19174 | + ret -1 /* op2 Inf or NaN, return NaN */ |
| 19175 | + |
| 19176 | +__avr32_f32_sub_subnormal_result: |
| 19177 | + /* Check if the number is so small that |
| 19178 | + it will be represented with zero. */ |
| 19179 | + rsub r10, r10, 9 |
| 19180 | + rsub r11, r10, 32 |
| 19181 | + retcs 0 |
| 19182 | + |
| 19183 | + /* Shift the mantissa into the correct position.*/ |
| 19184 | + lsr r10, r8, r10 |
| 19185 | + /* Add sign bit. */ |
| 19186 | + or r12, r10 |
| 19187 | + |
| 19188 | + /* Put the shifted out bits in the most significant part |
| 19189 | + of r8. */ |
| 19190 | + lsl r8, r8, r11 |
| 19191 | + |
| 19192 | +#if defined(L_avr32_f32_addsub) |
| 19193 | + /* Add all the remainder bits used for rounding into r9 */ |
| 19194 | + or r9, r8 |
| 19195 | +#else |
| 19196 | + lsr r8, 24 |
| 19197 | +#endif |
| 19198 | + rjmp __avr32_f32_sub_round |
| 19199 | + |
| 19200 | + |
| 19201 | + .align 2 |
| 19202 | + |
| 19203 | +__avr32_f32_add_from_sub: |
| 19204 | + /* Switch sign on op2 */ |
| 19205 | + eorh r11, 0x8000 |
| 19206 | + |
| 19207 | +#if defined(L_avr32_f32_addsub_fast) |
| 19208 | + .global __avr32_f32_add_fast |
| 19209 | + .type __avr32_f32_add_fast,@function |
| 19210 | +__avr32_f32_add_fast: |
| 19211 | +#else |
| 19212 | + .global __avr32_f32_add |
| 19213 | + .type __avr32_f32_add,@function |
| 19214 | +__avr32_f32_add: |
| 19215 | +#endif |
| 19216 | + |
| 19217 | + /* Check signs */ |
| 19218 | + eor r8, r11, r12 |
| 19219 | + /* Different signs, use subtraction. */ |
| 19220 | + brmi __avr32_f32_sub_from_add |
| 19221 | + |
| 19222 | + /* Get sign of op1 */ |
| 19223 | + mov r8, r12 |
| 19224 | + andh r12, 0x8000, COH |
| 19225 | + |
| 19226 | + /* Remove sign from operands */ |
| 19227 | + cbr r11, 31 |
| 19228 | +#if defined(L_avr32_f32_addsub_fast) |
| 19229 | + reteq r8 /* If op2 is zero return op1 */ |
| 19230 | +#endif |
| 19231 | + cbr r8, 31 |
| 19232 | + |
| 19233 | + /* Put the number with the largest exponent in r10 |
| 19234 | + and the number with the smallest exponent in r9 */ |
| 19235 | + max r10, r8, r11 |
| 19236 | + min r9, r8, r11 |
| 19237 | + |
| 19238 | + /* Unpack exponent and mantissa of op1 */ |
| 19239 | + lsl r8, r10, 8 |
| 19240 | + sbr r8, 31 /* Set implicit bit. */ |
| 19241 | + lsr r10, 23 |
| 19242 | + |
| 19243 | + /* op1 is NaN or Inf. */ |
| 19244 | + cp.w r10, 0xff |
| 19245 | + breq __avr32_f32_add_op1_nan_or_inf |
| 19246 | + |
| 19247 | + /* Unpack exponent and mantissa of op2 */ |
| 19248 | + lsl r11, r9, 8 |
| 19249 | + sbr r11, 31 /* Set implicit bit. */ |
| 19250 | + lsr r9, 23 |
| 19251 | + |
| 19252 | +#if defined(L_avr32_f32_addsub) |
| 19253 | + /* op2 is either zero or subnormal. */ |
| 19254 | + breq __avr32_f32_add_op2_subnormal |
| 19255 | +0: |
| 19256 | + /* Keep sticky bit for correct IEEE rounding */ |
| 19257 | + st.w --sp, r12 |
| 19258 | + |
| 19259 | + /* Get shift amount to scale mantissa of op2. */ |
| 19260 | + rsub r9, r10 |
| 19261 | + |
| 19262 | + /* Saturate the shift amount to 31. If the amount |
| 19263 | + is any larger op2 is insignificant. */ |
| 19264 | + satu r9 >> 0, 5 |
| 19265 | + |
| 19266 | + /* Shift mantissa of op2 to same decimal point as the mantissa |
| 19267 | + of op1. */ |
| 19268 | + lsr r12, r11, r9 |
| 19269 | + |
| 19270 | + /* Put the remainding bits into r11[23:..].*/ |
| 19271 | + rsub r9, r9, (32-8) |
| 19272 | + lsl r11, r11, r9 |
| 19273 | + /* Insert the bits we will remove from the mantissa into r11[31:24] */ |
| 19274 | + bfins r11, r12, 24, 8 |
| 19275 | + |
| 19276 | + /* Now add the mantissas. */ |
| 19277 | + add r8, r12 |
| 19278 | + |
| 19279 | + ld.w r12, sp++ |
| 19280 | +#else |
| 19281 | + /* Ignore sticky bit to simplify and speed up rounding */ |
| 19282 | + /* op2 is either zero or subnormal. */ |
| 19283 | + breq __avr32_f32_add_op2_subnormal |
| 19284 | +0: |
| 19285 | + /* Get shift amount to scale mantissa of op2. */ |
| 19286 | + rsub r9, r10 |
| 19287 | + |
| 19288 | + /* Saturate the shift amount to 31. If the amount |
| 19289 | + is any larger op2 is insignificant. */ |
| 19290 | + satu r9 >> 0, 5 |
| 19291 | + |
| 19292 | + /* Shift mantissa of op2 to same decimal point as the mantissa |
| 19293 | + of op1. */ |
| 19294 | + lsr r11, r11, r9 |
| 19295 | + |
| 19296 | + /* Now add the mantissas. */ |
| 19297 | + add r8, r11 |
| 19298 | + |
| 19299 | +#endif |
| 19300 | + /* Check if we overflowed. */ |
| 19301 | + brcs __avr32_f32_add_res_of |
| 19302 | +1: |
| 19303 | + /* Pack result. */ |
| 19304 | + or r12, r12, r8 >> 8 |
| 19305 | + bfins r12, r10, 23, 8 |
| 19306 | + |
| 19307 | + /* Round */ |
| 19308 | +#if defined(L_avr32_f32_addsub) |
| 19309 | + mov_imm r10, 0x80000000 |
| 19310 | + bld r12, 0 |
| 19311 | + subne r10, -1 |
| 19312 | + cp.w r11, r10 |
| 19313 | + subhs r12, -1 |
| 19314 | +#else |
| 19315 | + bld r8, 7 |
| 19316 | + acr r12 |
| 19317 | +#endif |
| 19318 | + |
| 19319 | + ret r12 |
| 19320 | + |
| 19321 | +__avr32_f32_add_op2_subnormal: |
| 19322 | + /* Fix implicit bit and adjust exponent of subnormals. */ |
| 19323 | + cbr r11, 31 |
| 19324 | + /* Set exponent to 1 if we do not have a zero. */ |
| 19325 | + movne r9,1 |
| 19326 | + |
| 19327 | + /* Check if op1 is also subnormal. */ |
| 19328 | + cp.w r10, 0 |
| 19329 | + brne 0b |
| 19330 | + /* Both operands subnormal, just add the mantissas and |
| 19331 | + pack. If the addition of the subnormal numbers results |
| 19332 | + in a normal number then the exponent will automatically |
| 19333 | + be set to 1 by the addition. */ |
| 19334 | + cbr r8, 31 |
| 19335 | + add r11, r8 |
| 19336 | + or r12, r12, r11 >> 8 |
| 19337 | + ret r12 |
| 19338 | + |
| 19339 | +__avr32_f32_add_op1_nan_or_inf: |
| 19340 | + /* Check if op1 is NaN, if so return NaN */ |
| 19341 | + lsl r11, r8, 1 |
| 19342 | + retne -1 |
| 19343 | + |
| 19344 | + /* op1 is Inf. */ |
| 19345 | + bfins r12, r10, 23, 8 /* Generate Inf in r12 */ |
| 19346 | + |
| 19347 | + /* Check if op2 is Inf. or NaN */ |
| 19348 | + lsr r11, r9, 23 |
| 19349 | + cp.w r11, 0xff |
| 19350 | + retne r12 /* op2 not Inf or NaN, return op1 */ |
| 19351 | + |
| 19352 | + lsl r9, 9 |
| 19353 | + reteq r12 /* op2 Inf return op1 */ |
| 19354 | + ret -1 /* op2 is NaN, return NaN */ |
| 19355 | + |
| 19356 | +__avr32_f32_add_res_of: |
| 19357 | + /* We overflowed. Increase exponent and shift mantissa.*/ |
| 19358 | + lsr r8, 1 |
| 19359 | + sub r10, -1 |
| 19360 | + |
| 19361 | + /* Clear mantissa to set result to Inf if the exponent is 255. */ |
| 19362 | + cp.w r10, 255 |
| 19363 | + moveq r8, 0 |
| 19364 | + moveq r11, 0 |
| 19365 | + rjmp 1b |
| 19366 | + |
| 19367 | + |
| 19368 | +#endif |
| 19369 | + |
| 19370 | + |
| 19371 | +#if defined(L_avr32_f32_div) || defined(L_avr32_f32_div_fast) |
| 19372 | + .align 2 |
| 19373 | + |
| 19374 | +#if defined(L_avr32_f32_div_fast) |
| 19375 | + .global __avr32_f32_div_fast |
| 19376 | + .type __avr32_f32_div_fast,@function |
| 19377 | +__avr32_f32_div_fast: |
| 19378 | +#else |
| 19379 | + .global __avr32_f32_div |
| 19380 | + .type __avr32_f32_div,@function |
| 19381 | +__avr32_f32_div: |
| 19382 | +#endif |
| 19383 | + |
| 19384 | + eor r8, r11, r12 /* MSB(r8) = Sign(op1) ^ Sign(op2) */ |
| 19385 | + |
| 19386 | + /* Unpack */ |
| 19387 | + lsl r12,1 |
| 19388 | + lsl r11,1 |
| 19389 | + breq 4f /* Check op2 for zero */ |
| 19390 | + |
| 19391 | + tst r12, r12 |
| 19392 | + moveq r9, 0 |
| 19393 | + breq 12f |
| 19394 | + |
| 19395 | + /* Unpack op1*/ |
| 19396 | + /* exp: r9 */ |
| 19397 | + /* sf: r12 */ |
| 19398 | + lsr r9, r12, 24 |
| 19399 | + breq 11f /*If number is subnormal*/ |
| 19400 | + cp r9, 0xff |
| 19401 | + brhs 2f /* Check op1 for NaN or Inf */ |
| 19402 | + lsl r12, 7 |
| 19403 | + sbr r12, 31 /*Implicit bit*/ |
| 19404 | +12: |
| 19405 | + |
| 19406 | + /* Unpack op2*/ |
| 19407 | + /* exp: r10 */ |
| 19408 | + /* sf: r11 */ |
| 19409 | + lsr r10, r11, 24 |
| 19410 | + breq 13f /*If number is subnormal*/ |
| 19411 | + cp r10, 0xff |
| 19412 | + brhs 3f /* Check op2 for NaN or Inf */ |
| 19413 | + lsl r11,7 |
| 19414 | + sbr r11, 31 /*Implicit bit*/ |
| 19415 | + |
| 19416 | + cp.w r9, 0 |
| 19417 | + subfeq r12, 0 |
| 19418 | + reteq 0 /* op1 is zero and op2 is not zero */ |
| 19419 | + /* or NaN so return zero */ |
| 19420 | + |
| 19421 | +14: |
| 19422 | + |
| 19423 | + /* For UC3, store with predecrement is faster than stm */ |
| 19424 | + st.w --sp, r5 |
| 19425 | + st.d --sp, r6 |
| 19426 | + |
| 19427 | + /* Calculate new exponent */ |
| 19428 | + sub r9, r10 |
| 19429 | + sub r9,-127 |
| 19430 | + |
| 19431 | + /* Divide */ |
| 19432 | + /* Approximating 1/d with the following recurrence: */ |
| 19433 | + /* R[j+1] = R[j]*(2-R[j]*d) */ |
| 19434 | + /* Using 2.30 format */ |
| 19435 | + /* TWO: r10 */ |
| 19436 | + /* d: r5 */ |
| 19437 | + /* Multiply result : r6, r7 */ |
| 19438 | + /* Initial guess : r11 */ |
| 19439 | + /* New approximations : r11 */ |
| 19440 | + /* Dividend : r12 */ |
| 19441 | + |
| 19442 | + /* Load TWO */ |
| 19443 | + mov_imm r10, 0x80000000 |
| 19444 | + |
| 19445 | + lsr r12, 2 /* Get significand of Op1 in 2.30 format */ |
| 19446 | + lsr r5, r11, 2 /* Get significand of Op2 (=d) in 2.30 format */ |
| 19447 | + |
| 19448 | + /* Load initial guess, using look-up table */ |
| 19449 | + /* Initial guess is of format 01.XY, where XY is constructed as follows: */ |
| 19450 | + /* Let d be of following format: 00.1xy....., then XY=~xy */ |
| 19451 | + /* For d=00.100 = 0,5 -> initial guess=01.11 = 1,75 */ |
| 19452 | + /* For d=00.101 = 0,625 -> initial guess=01.11 = 1,5 */ |
| 19453 | + /* For d=00.110 = 0,75 -> initial guess=01.11 = 1,25 */ |
| 19454 | + /* For d=00.111 = 0,875 -> initial guess=01.11 = 1,0 */ |
| 19455 | + |
| 19456 | + lsr r11, r10, 1 |
| 19457 | + bfextu r6, r5, 27, 2 |
| 19458 | + com r6 |
| 19459 | + bfins r11, r6, 28, 2 |
| 19460 | + |
| 19461 | + /* First approximation */ |
| 19462 | + /* r7 = R[j]*d */ |
| 19463 | + mulu.d r6, r11, r5 |
| 19464 | + /* r7 = 2-R[j]*d */ |
| 19465 | + sub r7, r10, r7<<2 |
| 19466 | + /* r11 = R[j]*(2-R[j]*d) */ |
| 19467 | + mulu.d r6, r11, r7 |
| 19468 | + lsl r11, r7, 2 |
| 19469 | + |
| 19470 | + /* Second approximation */ |
| 19471 | + /* r7 = R[j]*d */ |
| 19472 | + mulu.d r6, r11, r5 |
| 19473 | + /* r7 = 2-R[j]*d */ |
| 19474 | + sub r7, r10, r7<<2 |
| 19475 | + /* r11 = R[j]*(2-R[j]*d) */ |
| 19476 | + mulu.d r6, r11, r7 |
| 19477 | + lsl r11, r7, 2 |
| 19478 | + |
| 19479 | + /* Third approximation */ |
| 19480 | + /* r7 = R[j]*d */ |
| 19481 | + mulu.d r6, r11, r5 |
| 19482 | + /* r7 = 2-R[j]*d */ |
| 19483 | + sub r7, r10, r7<<2 |
| 19484 | + /* r11 = R[j]*(2-R[j]*d) */ |
| 19485 | + mulu.d r6, r11, r7 |
| 19486 | + lsl r11, r7, 2 |
| 19487 | + |
| 19488 | + /* Fourth approximation */ |
| 19489 | + /* r7 = R[j]*d */ |
| 19490 | + mulu.d r6, r11, r5 |
| 19491 | + /* r7 = 2-R[j]*d */ |
| 19492 | + sub r7, r10, r7<<2 |
| 19493 | + /* r11 = R[j]*(2-R[j]*d) */ |
| 19494 | + mulu.d r6, r11, r7 |
| 19495 | + lsl r11, r7, 2 |
| 19496 | + |
| 19497 | + |
| 19498 | + /* Multiply with dividend to get quotient, r7 = sf(op1)/sf(op2) */ |
| 19499 | + mulu.d r6, r11, r12 |
| 19500 | + |
| 19501 | + /* Shift by 3 to get result in 1.31 format, as required by the exponent. */ |
| 19502 | + /* Note that 1.31 format is already used by the exponent in r9, since */ |
| 19503 | + /* a bias of 127 was added to the result exponent, even though the implicit */ |
| 19504 | + /* bit was inserted. This gives the exponent an additional bias of 1, which */ |
| 19505 | + /* supports 1.31 format. */ |
| 19506 | + //lsl r10, r7, 3 |
| 19507 | + |
| 19508 | + /* Adjust exponent and mantissa in case the result is of format |
| 19509 | + 0000.1xxx to 0001.xxx*/ |
| 19510 | +#if defined(L_avr32_f32_div) |
| 19511 | + lsr r12, 4 /* Scale dividend to 6.26 format to match the |
| 19512 | + result of the multiplication of the divisor and |
| 19513 | + quotient to get the remainder. */ |
| 19514 | +#endif |
| 19515 | + bld r7, 31-3 |
| 19516 | + breq 0f |
| 19517 | + lsl r7, 1 |
| 19518 | + sub r9, 1 |
| 19519 | +#if defined(L_avr32_f32_div) |
| 19520 | + lsl r12, 1 /* Scale dividend to 5.27 format to match the |
| 19521 | + result of the multiplication of the divisor and |
| 19522 | + quotient to get the remainder. */ |
| 19523 | +#endif |
| 19524 | +0: |
| 19525 | + cp r9, 0 |
| 19526 | + brle __avr32_f32_div_res_subnormal /* Result was subnormal. */ |
| 19527 | + |
| 19528 | + |
| 19529 | +#if defined(L_avr32_f32_div) |
| 19530 | + /* In order to round correctly we calculate the remainder: |
| 19531 | + Remainder = dividend[r12] - divisor[r5]*quotient[r7] |
| 19532 | + for the case when the quotient is halfway between the round-up |
| 19533 | + value and the round down value. If the remainder then is negative |
| 19534 | + it means that the quotient was to big and that it should not be |
| 19535 | + rounded up, if the remainder is positive the quotient was to small |
| 19536 | + and we need to round up. If the remainder is zero it means that the |
| 19537 | + quotient is exact but since we need to remove the guard bit we should |
| 19538 | + round to even. */ |
| 19539 | + andl r7, 0xffe0 |
| 19540 | + orl r7, 0x0010 |
| 19541 | + |
| 19542 | + /* Now do the multiplication. The quotient has the format 4.28 |
| 19543 | + while the divisor has the format 2.30 which gives a result |
| 19544 | + of 6.26 */ |
| 19545 | + mulu.d r10, r5, r7 |
| 19546 | + |
| 19547 | + /* Check if remainder is positive, negative or equal. */ |
| 19548 | + bfextu r5, r7, 5, 1 /* Get parity bit into bit 0 of r5 */ |
| 19549 | + cp r10, 0 |
| 19550 | +__avr32_f32_div_round_subnormal: |
| 19551 | + cpc r11, r12 |
| 19552 | + srlo r11 /* Remainder positive: we need to round up.*/ |
| 19553 | + moveq r11, r5 /* Remainder zero: round up if mantissa odd. */ |
| 19554 | +#else |
| 19555 | + bfextu r11, r7, 4, 1 /* Get guard bit */ |
| 19556 | +#endif |
| 19557 | + |
| 19558 | + /* Pack final result*/ |
| 19559 | + lsr r12, r7, 5 |
| 19560 | + bfins r12, r9, 23, 8 |
| 19561 | + /* For UC3, load with postincrement is faster than ldm */ |
| 19562 | + ld.d r6, sp++ |
| 19563 | + ld.w r5, sp++ |
| 19564 | + bld r8, 31 |
| 19565 | + bst r12, 31 |
| 19566 | + /* Rounding add. */ |
| 19567 | + add r12, r11 |
| 19568 | + ret r12 |
| 19569 | + |
| 19570 | +__divsf_return_op1: |
| 19571 | + lsl r8, 1 |
| 19572 | + ror r12 |
| 19573 | + ret r12 |
| 19574 | + |
| 19575 | + |
| 19576 | +2: |
| 19577 | + /* Op1 is NaN or inf */ |
| 19578 | + retne -1 /* Return NaN if op1 is NaN */ |
| 19579 | + /* Op1 is inf check op2 */ |
| 19580 | + mov_imm r9, 0xff000000 |
| 19581 | + cp r11, r9 |
| 19582 | + brlo __divsf_return_op1 /* inf/number gives inf */ |
| 19583 | + ret -1 /* The rest gives NaN*/ |
| 19584 | +3: |
| 19585 | + /* Op2 is NaN or inf */ |
| 19586 | + reteq 0 /* Return zero if number/inf*/ |
| 19587 | + ret -1 /* Return NaN*/ |
| 19588 | +4: |
| 19589 | + /* Op1 is zero ? */ |
| 19590 | + tst r12,r12 |
| 19591 | + reteq -1 /* 0.0/0.0 is NaN */ |
| 19592 | + /* Op1 is Nan? */ |
| 19593 | + lsr r9, r12, 24 |
| 19594 | + breq 11f /*If number is subnormal*/ |
| 19595 | + cp r9, 0xff |
| 19596 | + brhs 2b /* Check op1 for NaN or Inf */ |
| 19597 | + /* Nonzero/0.0 is Inf. Sign bit will be shifted in before returning*/ |
| 19598 | + mov_imm r12, 0xff000000 |
| 19599 | + rjmp __divsf_return_op1 |
| 19600 | + |
| 19601 | +11: /* Op1 was denormal. Fix it. */ |
| 19602 | + lsl r12,7 |
| 19603 | + clz r9,r12 |
| 19604 | + lsl r12,r12,r9 |
| 19605 | + rsub r9,r9,1 |
| 19606 | + rjmp 12b |
| 19607 | + |
| 19608 | +13: /* Op2 was denormal. Fix it. */ |
| 19609 | + lsl r11,7 |
| 19610 | + clz r10,r11 |
| 19611 | + lsl r11,r11,r10 |
| 19612 | + rsub r10,r10,1 |
| 19613 | + rjmp 14b |
| 19614 | + |
| 19615 | + |
| 19616 | +__avr32_f32_div_res_subnormal: /* Divide result was subnormal */ |
| 19617 | +#if defined(L_avr32_f32_div) |
| 19618 | + /* Check how much we must scale down the mantissa. */ |
| 19619 | + neg r9 |
| 19620 | + sub r9, -1 /* We do no longer have an implicit bit. */ |
| 19621 | + satu r9 >> 0, 5 /* Saturate shift amount to max 32. */ |
| 19622 | + /* Scale down quotient */ |
| 19623 | + rsub r10, r9, 32 |
| 19624 | + lsr r7, r7, r9 |
| 19625 | + /* Scale down the dividend to match the scaling of the quotient. */ |
| 19626 | + lsl r6, r12, r10 /* Make the divident 64-bit and put the lsw in r6 */ |
| 19627 | + lsr r12, r12, r9 |
| 19628 | + |
| 19629 | + /* Start performing the same rounding as done for normal numbers |
| 19630 | + but this time we have scaled the quotient and dividend and hence |
| 19631 | + need a little different comparison. */ |
| 19632 | + andl r7, 0xffe0 |
| 19633 | + orl r7, 0x0010 |
| 19634 | + |
| 19635 | + /* Now do the multiplication. The quotient has the format 4.28 |
| 19636 | + while the divisor has the format 2.30 which gives a result |
| 19637 | + of 6.26 */ |
| 19638 | + mulu.d r10, r5, r7 |
| 19639 | + |
| 19640 | + /* Set exponent to 0 */ |
| 19641 | + mov r9, 0 |
| 19642 | + |
| 19643 | + /* Check if remainder is positive, negative or equal. */ |
| 19644 | + bfextu r5, r7, 5, 1 /* Get parity bit into bit 0 of r5 */ |
| 19645 | + cp r10, r6 |
| 19646 | + rjmp __avr32_f32_div_round_subnormal |
| 19647 | + |
| 19648 | +#else |
| 19649 | + ld.d r6, sp++ |
| 19650 | + ld.w r5, sp++ |
| 19651 | + /*Flush to zero*/ |
| 19652 | + ret 0 |
| 19653 | +#endif |
| 19654 | +#endif |
| 19655 | + |
| 19656 | +#ifdef L_avr32_f32_mul |
| 19657 | + .global __avr32_f32_mul |
| 19658 | + .type __avr32_f32_mul,@function |
| 19659 | + |
| 19660 | + |
| 19661 | +__avr32_f32_mul: |
| 19662 | + mov r8, r12 |
| 19663 | + eor r12, r11 /* MSB(r8) = Sign(op1) ^ Sign(op2) */ |
| 19664 | + andh r12, 0x8000, COH |
| 19665 | + |
| 19666 | + /* arrange operands so that that op1 >= op2 */ |
| 19667 | + cbr r8, 31 |
| 19668 | + breq __avr32_f32_mul_op1_zero |
| 19669 | + cbr r11, 31 |
| 19670 | + |
| 19671 | + /* Put the number with the largest exponent in r10 |
| 19672 | + and the number with the smallest exponent in r9 */ |
| 19673 | + max r10, r8, r11 |
| 19674 | + min r9, r8, r11 |
| 19675 | + |
| 19676 | + /* Unpack exponent and mantissa of op1 */ |
| 19677 | + lsl r8, r10, 8 |
| 19678 | + sbr r8, 31 /* Set implicit bit. */ |
| 19679 | + lsr r10, 23 |
| 19680 | + |
| 19681 | + /* op1 is NaN or Inf. */ |
| 19682 | + cp.w r10, 0xff |
| 19683 | + breq __avr32_f32_mul_op1_nan_or_inf |
| 19684 | + |
| 19685 | + /* Unpack exponent and mantissa of op2 */ |
| 19686 | + lsl r11, r9, 8 |
| 19687 | + sbr r11, 31 /* Set implicit bit. */ |
| 19688 | + lsr r9, 23 |
| 19689 | + |
| 19690 | + /* op2 is either zero or subnormal. */ |
| 19691 | + breq __avr32_f32_mul_op2_subnormal |
| 19692 | +0: |
| 19693 | + /* Calculate new exponent */ |
| 19694 | + add r9,r10 |
| 19695 | + |
| 19696 | + /* Do the multiplication */ |
| 19697 | + mulu.d r10,r8,r11 |
| 19698 | + |
| 19699 | + /* We might need to scale up by two if the MSB of the result is |
| 19700 | + zero. */ |
| 19701 | + lsl r8, r11, 1 |
| 19702 | + movcc r11, r8 |
| 19703 | + subcc r9, 1 |
| 19704 | + |
| 19705 | + /* Put the shifted out bits of the mantissa into r10 */ |
| 19706 | + lsr r10, 8 |
| 19707 | + bfins r10, r11, 24, 8 |
| 19708 | + |
| 19709 | + sub r9,(127-1) /* remove extra exponent bias */ |
| 19710 | + brle __avr32_f32_mul_res_subnormal |
| 19711 | + |
| 19712 | + /* Check for Inf. */ |
| 19713 | + cp.w r9, 0xff |
| 19714 | + brge 1f |
| 19715 | + |
| 19716 | + /* Pack result. */ |
| 19717 | + or r12, r12, r11 >> 8 |
| 19718 | + bfins r12, r9, 23, 8 |
| 19719 | + |
| 19720 | + /* Round */ |
| 19721 | +__avr32_f32_mul_round: |
| 19722 | + mov_imm r8, 0x80000000 |
| 19723 | + bld r12, 0 |
| 19724 | + subne r8, -1 |
| 19725 | + |
| 19726 | + cp.w r10, r8 |
| 19727 | + subhs r12, -1 |
| 19728 | + |
| 19729 | + ret r12 |
| 19730 | + |
| 19731 | +1: |
| 19732 | + /* Return Inf */ |
| 19733 | + orh r12, 0x7f80 |
| 19734 | + ret r12 |
| 19735 | + |
| 19736 | +__avr32_f32_mul_op2_subnormal: |
| 19737 | + cbr r11, 31 |
| 19738 | + clz r9, r11 |
| 19739 | + retcs 0 /* op2 is zero. Return 0 */ |
| 19740 | + sub r9, 8 |
| 19741 | + lsl r11, r11, r9 |
| 19742 | + rsub r9, r9, 1 |
| 19743 | + |
| 19744 | + /* Check if op2 is subnormal. */ |
| 19745 | + tst r10, r10 |
| 19746 | + brne 0b |
| 19747 | + |
| 19748 | + /* op2 is subnormal */ |
| 19749 | + cbr r8, 31 |
| 19750 | + clz r10, r11 |
| 19751 | + retcs 0 /* op1 is zero. Return 0 */ |
| 19752 | + lsl r8, r8, r10 |
| 19753 | + rsub r10, r10, 1 |
| 19754 | + |
| 19755 | + rjmp 0b |
| 19756 | + |
| 19757 | + |
| 19758 | +__avr32_f32_mul_op1_nan_or_inf: |
| 19759 | + /* Check if op1 is NaN, if so return NaN */ |
| 19760 | + lsl r11, r8, 1 |
| 19761 | + retne -1 |
| 19762 | + |
| 19763 | + /* op1 is Inf. */ |
| 19764 | + tst r9, r9 |
| 19765 | + reteq -1 /* Inf * 0 -> NaN */ |
| 19766 | + |
| 19767 | + bfins r12, r10, 23, 8 /* Generate Inf in r12 */ |
| 19768 | + |
| 19769 | + /* Check if op2 is Inf. or NaN */ |
| 19770 | + lsr r11, r9, 23 |
| 19771 | + cp.w r11, 0xff |
| 19772 | + retne r12 /* op2 not Inf or NaN, return Info */ |
| 19773 | + |
| 19774 | + lsl r9, 9 |
| 19775 | + reteq r12 /* op2 Inf return Inf */ |
| 19776 | + ret -1 /* op2 is NaN, return NaN */ |
| 19777 | + |
| 19778 | +__avr32_f32_mul_res_subnormal: |
| 19779 | + /* Check if the number is so small that |
| 19780 | + it will be represented with zero. */ |
| 19781 | + rsub r9, r9, 9 |
| 19782 | + rsub r8, r9, 32 |
| 19783 | + retcs 0 |
| 19784 | + |
| 19785 | + /* Shift the mantissa into the correct position.*/ |
| 19786 | + lsr r9, r11, r9 |
| 19787 | + /* Add sign bit. */ |
| 19788 | + or r12, r9 |
| 19789 | + /* Put the shifted out bits in the most significant part |
| 19790 | + of r8. */ |
| 19791 | + lsl r11, r11, r8 |
| 19792 | + |
| 19793 | + /* Add all the remainder bits used for rounding into r11 */ |
| 19794 | + andh r10, 0x00FF |
| 19795 | + or r10, r11 |
| 19796 | + rjmp __avr32_f32_mul_round |
| 19797 | + |
| 19798 | +__avr32_f32_mul_op1_zero: |
| 19799 | + bfextu r10, r11, 23, 8 |
| 19800 | + cp.w r10, 0xff |
| 19801 | + retne r12 |
| 19802 | + reteq -1 |
| 19803 | + |
| 19804 | +#endif |
| 19805 | + |
| 19806 | + |
| 19807 | +#ifdef L_avr32_s32_to_f32 |
| 19808 | + .global __avr32_s32_to_f32 |
| 19809 | + .type __avr32_s32_to_f32,@function |
| 19810 | +__avr32_s32_to_f32: |
| 19811 | + cp r12, 0 |
| 19812 | + reteq r12 /* If zero then return zero float */ |
| 19813 | + mov r11, r12 /* Keep the sign */ |
| 19814 | + abs r12 /* Compute the absolute value */ |
| 19815 | + mov r10, 31 + 127 /* Set the correct exponent */ |
| 19816 | + |
| 19817 | + /* Normalize */ |
| 19818 | + normalize_sf r10 /*exp*/, r12 /*mant*/, r9 /*scratch*/ |
| 19819 | + |
| 19820 | + /* Check for subnormal result */ |
| 19821 | + cp.w r10, 0 |
| 19822 | + brle __avr32_s32_to_f32_subnormal |
| 19823 | + |
| 19824 | + round_sf r10 /*exp*/, r12 /*mant*/, r9 /*scratch*/ |
| 19825 | + pack_sf r12 /*sf*/, r10 /*exp*/, r12 /*mant*/ |
| 19826 | + lsl r11, 1 |
| 19827 | + ror r12 |
| 19828 | + ret r12 |
| 19829 | + |
| 19830 | +__avr32_s32_to_f32_subnormal: |
| 19831 | + /* Adjust a subnormal result */ |
| 19832 | + adjust_subnormal_sf r12/*sf*/, r10 /*exp*/, r12 /*mant*/, r11/*sign*/, r9 /*scratch*/ |
| 19833 | + ret r12 |
| 19834 | + |
| 19835 | +#endif |
| 19836 | + |
| 19837 | +#ifdef L_avr32_u32_to_f32 |
| 19838 | + .global __avr32_u32_to_f32 |
| 19839 | + .type __avr32_u32_to_f32,@function |
| 19840 | +__avr32_u32_to_f32: |
| 19841 | + cp r12, 0 |
| 19842 | + reteq r12 /* If zero then return zero float */ |
| 19843 | + mov r10, 31 + 127 /* Set the correct exponent */ |
| 19844 | + |
| 19845 | + /* Normalize */ |
| 19846 | + normalize_sf r10 /*exp*/, r12 /*mant*/, r9 /*scratch*/ |
| 19847 | + |
| 19848 | + /* Check for subnormal result */ |
| 19849 | + cp.w r10, 0 |
| 19850 | + brle __avr32_u32_to_f32_subnormal |
| 19851 | + |
| 19852 | + round_sf r10 /*exp*/, r12 /*mant*/, r9 /*scratch*/ |
| 19853 | + pack_sf r12 /*sf*/, r10 /*exp*/, r12 /*mant*/ |
| 19854 | + lsr r12,1 /* Sign bit is 0 for unsigned int */ |
| 19855 | + ret r12 |
| 19856 | + |
| 19857 | +__avr32_u32_to_f32_subnormal: |
| 19858 | + /* Adjust a subnormal result */ |
| 19859 | + mov r8, 0 |
| 19860 | + adjust_subnormal_sf r12/*sf*/,r10 /*exp*/, r12 /*mant*/,r8/*sign*/, r9 /*scratch*/ |
| 19861 | + ret r12 |
| 19862 | + |
| 19863 | + |
| 19864 | +#endif |
| 19865 | + |
| 19866 | + |
| 19867 | +#ifdef L_avr32_f32_to_s32 |
| 19868 | + .global __avr32_f32_to_s32 |
| 19869 | + .type __avr32_f32_to_s32,@function |
| 19870 | +__avr32_f32_to_s32: |
| 19871 | + bfextu r11, r12, 23, 8 |
| 19872 | + sub r11,127 /* Fix bias */ |
| 19873 | + retlo 0 /* Negative exponent yields zero integer */ |
| 19874 | + |
| 19875 | + /* Shift mantissa into correct position */ |
| 19876 | + rsub r11,r11,31 /* Shift amount */ |
| 19877 | + lsl r10,r12,8 /* Get mantissa */ |
| 19878 | + sbr r10,31 /* Add implicit bit */ |
| 19879 | + lsr r10,r10,r11 /* Perform shift */ |
| 19880 | + lsl r12,1 /* Check sign */ |
| 19881 | + retcc r10 /* if positive, we are done */ |
| 19882 | + neg r10 /* if negative float, negate result */ |
| 19883 | + ret r10 |
| 19884 | + |
| 19885 | +#endif |
| 19886 | + |
| 19887 | +#ifdef L_avr32_f32_to_u32 |
| 19888 | + .global __avr32_f32_to_u32 |
| 19889 | + .type __avr32_f32_to_u32,@function |
| 19890 | +__avr32_f32_to_u32: |
| 19891 | + cp r12,0 |
| 19892 | + retmi 0 /* Negative numbers gives 0 */ |
| 19893 | + bfextu r11, r12, 23, 8 /* Extract exponent */ |
| 19894 | + sub r11,127 /* Fix bias */ |
| 19895 | + retlo 0 /* Negative exponent yields zero integer */ |
| 19896 | + |
| 19897 | + /* Shift mantissa into correct position */ |
| 19898 | + rsub r11,r11,31 /* Shift amount */ |
| 19899 | + lsl r12,8 /* Get mantissa */ |
| 19900 | + sbr r12,31 /* Add implicit bit */ |
| 19901 | + lsr r12,r12,r11 /* Perform shift */ |
| 19902 | + ret r12 |
| 19903 | + |
| 19904 | +#endif |
| 19905 | + |
| 19906 | +#ifdef L_avr32_f32_to_f64 |
| 19907 | + .global __avr32_f32_to_f64 |
| 19908 | + .type __avr32_f32_to_f64,@function |
| 19909 | + |
| 19910 | +__avr32_f32_to_f64: |
| 19911 | + lsl r11,r12,1 /* Remove sign bit, keep original value in r12*/ |
| 19912 | + moveq r10, 0 |
| 19913 | + reteq r11 /* Return zero if input is zero */ |
| 19914 | + |
| 19915 | + bfextu r9,r11,24,8 /* Get exponent */ |
| 19916 | + cp.w r9,0xff /* check for NaN or inf */ |
| 19917 | + breq 0f |
| 19918 | + |
| 19919 | + lsl r11,7 /* Convert sf mantissa to df format */ |
| 19920 | + mov r10,0 |
| 19921 | + |
| 19922 | + /* Check if implicit bit should be set */ |
| 19923 | + cp.w r9, 0 |
| 19924 | + subeq r9,-1 /* Adjust exponent if it was 0 */ |
| 19925 | + srne r8 |
| 19926 | + or r11, r11, r8 << 31 /* Set implicit bit if needed */ |
| 19927 | + sub r9,(127-0x3ff) /* Convert exponent to df format exponent */ |
| 19928 | + |
| 19929 | + /*We know that low register of mantissa is 0, and will be unaffected by normalization.*/ |
| 19930 | + /*We can therefore use the faster normalize_sf function instead of normalize_df.*/ |
| 19931 | + normalize_sf r9 /*exp*/, r11 /*mantissa*/, r8 /*scratch*/ |
| 19932 | + pack_df r9 /*exp*/, r10, r11 /*mantissa*/, r10, r11 /*df*/ |
| 19933 | + |
| 19934 | +__extendsfdf_return_op1: |
| 19935 | + /* Rotate in sign bit */ |
| 19936 | + lsl r12, 1 |
| 19937 | + ror r11 |
| 19938 | + ret r11 |
| 19939 | + |
| 19940 | +0: |
| 19941 | + /* Inf or NaN*/ |
| 19942 | + mov_imm r10, 0xffe00000 |
| 19943 | + lsl r11,8 /* check mantissa */ |
| 19944 | + movne r11, -1 /* Return NaN */ |
| 19945 | + moveq r11, r10 /* Return inf */ |
| 19946 | + mov r10, 0 |
| 19947 | + rjmp __extendsfdf_return_op1 |
| 19948 | +#endif |
| 19949 | + |
| 19950 | + |
| 19951 | +#ifdef L_avr32_f64_to_f32 |
| 19952 | + .global __avr32_f64_to_f32 |
| 19953 | + .type __avr32_f64_to_f32,@function |
| 19954 | + |
| 19955 | +__avr32_f64_to_f32: |
| 19956 | + /* Unpack */ |
| 19957 | + lsl r9,r11,1 /* Unpack exponent */ |
| 19958 | + lsr r9,21 |
| 19959 | + |
| 19960 | + reteq 0 /* If exponent is 0 the number is so small |
| 19961 | + that the conversion to single float gives |
| 19962 | + zero */ |
| 19963 | + |
| 19964 | + lsl r8,r11,10 /* Adjust mantissa */ |
| 19965 | + or r12,r8,r10>>22 |
| 19966 | + |
| 19967 | + lsl r10,10 /* Check if there are any remaining bits |
| 19968 | + in the low part of the mantissa.*/ |
| 19969 | + neg r10 |
| 19970 | + rol r12 /* If there were remaining bits then set lsb |
| 19971 | + of mantissa to 1 */ |
| 19972 | + |
| 19973 | + cp r9,0x7ff |
| 19974 | + breq 2f /* Check for NaN or inf */ |
| 19975 | + |
| 19976 | + sub r9,(0x3ff-127) /* Adjust bias of exponent */ |
| 19977 | + sbr r12,31 /* set the implicit bit.*/ |
| 19978 | + |
| 19979 | + cp.w r9, 0 /* Check for subnormal number */ |
| 19980 | + brle 3f |
| 19981 | + |
| 19982 | + round_sf r9 /*exp*/, r12 /*mant*/, r10 /*scratch*/ |
| 19983 | + pack_sf r12 /*sf*/, r9 /*exp*/, r12 /*mant*/ |
| 19984 | +__truncdfsf_return_op1: |
| 19985 | + /* Rotate in sign bit */ |
| 19986 | + lsl r11, 1 |
| 19987 | + ror r12 |
| 19988 | + ret r12 |
| 19989 | + |
| 19990 | +2: |
| 19991 | + /* NaN or inf */ |
| 19992 | + cbr r12,31 /* clear implicit bit */ |
| 19993 | + retne -1 /* Return NaN if mantissa not zero */ |
| 19994 | + mov_imm r12, 0x7f800000 |
| 19995 | + ret r12 /* Return inf */ |
| 19996 | + |
| 19997 | +3: /* Result is subnormal. Adjust it.*/ |
| 19998 | + adjust_subnormal_sf r12/*sf*/,r9 /*exp*/, r12 /*mant*/, r11/*sign*/, r10 /*scratch*/ |
| 19999 | + ret r12 |
| 20000 | + |
| 20001 | + |
| 20002 | +#endif |
| 20003 | + |
| 20004 | +#if defined(L_mulsi3) && defined(__AVR32_NO_MUL__) |
| 20005 | + .global __mulsi3 |
| 20006 | + .type __mulsi3,@function |
| 20007 | + |
| 20008 | +__mulsi3: |
| 20009 | + mov r9, 0 |
| 20010 | +0: |
| 20011 | + lsr r11, 1 |
| 20012 | + addcs r9, r9, r12 |
| 20013 | + breq 1f |
| 20014 | + lsl r12, 1 |
| 20015 | + rjmp 0b |
| 20016 | +1: |
| 20017 | + ret r9 |
| 20018 | +#endif |
| 20019 | --- /dev/null |
| 20020 | +++ b/gcc/config/avr32/lib2funcs.S |
| 20021 | @@ -0,0 +1,21 @@ |
| 20022 | + .align 4 |
| 20023 | + .global __nonlocal_goto |
| 20024 | + .type __nonlocal_goto,@function |
| 20025 | + |
| 20026 | +/* __nonlocal_goto: This function handles nonlocal_goto's in gcc. |
| 20027 | + |
| 20028 | + parameter 0 (r12) = New Frame Pointer |
| 20029 | + parameter 1 (r11) = Address to goto |
| 20030 | + parameter 2 (r10) = New Stack Pointer |
| 20031 | + |
| 20032 | + This function invalidates the return stack, since it returns from a |
| 20033 | + function without using a return instruction. |
| 20034 | +*/ |
| 20035 | +__nonlocal_goto: |
| 20036 | + mov r7, r12 |
| 20037 | + mov sp, r10 |
| 20038 | + frs # Flush return stack |
| 20039 | + mov pc, r11 |
| 20040 | + |
| 20041 | + |
| 20042 | + |
| 20043 | --- /dev/null |
| 20044 | +++ b/gcc/config/avr32/linux-elf.h |
| 20045 | @@ -0,0 +1,151 @@ |
| 20046 | +/* |
| 20047 | + Linux/Elf specific definitions. |
| 20048 | + Copyright 2003-2006 Atmel Corporation. |
| 20049 | + |
| 20050 | + Written by Ronny Pedersen, Atmel Norway, <rpedersen@atmel.com> |
| 20051 | + and H�vard Skinnemoen, Atmel Norway, <hskinnemoen@atmel.com> |
| 20052 | + |
| 20053 | + This file is part of GCC. |
| 20054 | + |
| 20055 | + This program is free software; you can redistribute it and/or modify |
| 20056 | + it under the terms of the GNU General Public License as published by |
| 20057 | + the Free Software Foundation; either version 2 of the License, or |
| 20058 | + (at your option) any later version. |
| 20059 | + |
| 20060 | + This program is distributed in the hope that it will be useful, |
| 20061 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20062 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20063 | + GNU General Public License for more details. |
| 20064 | + |
| 20065 | + You should have received a copy of the GNU General Public License |
| 20066 | + along with this program; if not, write to the Free Software |
| 20067 | + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 20068 | + |
| 20069 | + |
| 20070 | + |
| 20071 | +/* elfos.h should have already been included. Now just override |
| 20072 | + any conflicting definitions and add any extras. */ |
| 20073 | + |
| 20074 | +/* Run-time Target Specification. */ |
| 20075 | +#undef TARGET_VERSION |
| 20076 | +#define TARGET_VERSION fputs (" (AVR32 GNU/Linux with ELF)", stderr); |
| 20077 | + |
| 20078 | +/* Do not assume anything about header files. */ |
| 20079 | +#define NO_IMPLICIT_EXTERN_C |
| 20080 | + |
| 20081 | +/* The GNU C++ standard library requires that these macros be defined. */ |
| 20082 | +#undef CPLUSPLUS_CPP_SPEC |
| 20083 | +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)" |
| 20084 | + |
| 20085 | +/* Now we define the strings used to build the spec file. */ |
| 20086 | +#undef LIB_SPEC |
| 20087 | +#define LIB_SPEC \ |
| 20088 | + "%{pthread:-lpthread} \ |
| 20089 | + %{shared:-lc} \ |
| 20090 | + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" |
| 20091 | + |
| 20092 | +/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add |
| 20093 | + the GNU/Linux magical crtbegin.o file (see crtstuff.c) which |
| 20094 | + provides part of the support for getting C++ file-scope static |
| 20095 | + object constructed before entering `main'. */ |
| 20096 | + |
| 20097 | +#undef STARTFILE_SPEC |
| 20098 | +#define STARTFILE_SPEC \ |
| 20099 | + "%{!shared: \ |
| 20100 | + %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \ |
| 20101 | + %{!p:%{profile:gcrt1.o%s} \ |
| 20102 | + %{!profile:crt1.o%s}}}} \ |
| 20103 | + crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" |
| 20104 | + |
| 20105 | +/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on |
| 20106 | + the GNU/Linux magical crtend.o file (see crtstuff.c) which |
| 20107 | + provides part of the support for getting C++ file-scope static |
| 20108 | + object constructed before entering `main', followed by a normal |
| 20109 | + GNU/Linux "finalizer" file, `crtn.o'. */ |
| 20110 | + |
| 20111 | +#undef ENDFILE_SPEC |
| 20112 | +#define ENDFILE_SPEC \ |
| 20113 | + "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" |
| 20114 | + |
| 20115 | +#undef ASM_SPEC |
| 20116 | +#define ASM_SPEC "%{!mno-pic:%{!fno-pic:--pic}} %{mrelax|O*:%{mno-relax|O0|O1: ;:--linkrelax}} %{mcpu=*:-mcpu=%*}" |
| 20117 | + |
| 20118 | +#undef LINK_SPEC |
| 20119 | +#define LINK_SPEC "%{version:-v} \ |
| 20120 | + %{static:-Bstatic} \ |
| 20121 | + %{shared:-shared} \ |
| 20122 | + %{symbolic:-Bsymbolic} \ |
| 20123 | + %{rdynamic:-export-dynamic} \ |
| 20124 | + %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0} \ |
| 20125 | + %{mrelax|O*:%{mno-relax|O0|O1: ;:--relax}}" |
| 20126 | + |
| 20127 | +#define TARGET_OS_CPP_BUILTINS() LINUX_TARGET_OS_CPP_BUILTINS() |
| 20128 | + |
| 20129 | +/* This is how we tell the assembler that two symbols have the same value. */ |
| 20130 | +#define ASM_OUTPUT_DEF(FILE, NAME1, NAME2) \ |
| 20131 | + do \ |
| 20132 | + { \ |
| 20133 | + assemble_name (FILE, NAME1); \ |
| 20134 | + fputs (" = ", FILE); \ |
| 20135 | + assemble_name (FILE, NAME2); \ |
| 20136 | + fputc ('\n', FILE); \ |
| 20137 | + } \ |
| 20138 | + while (0) |
| 20139 | + |
| 20140 | + |
| 20141 | + |
| 20142 | +#undef CC1_SPEC |
| 20143 | +#define CC1_SPEC "%{profile:-p}" |
| 20144 | + |
| 20145 | +/* Target CPU builtins. */ |
| 20146 | +#define TARGET_CPU_CPP_BUILTINS() \ |
| 20147 | + do \ |
| 20148 | + { \ |
| 20149 | + builtin_define ("__avr32__"); \ |
| 20150 | + builtin_define ("__AVR32__"); \ |
| 20151 | + builtin_define ("__AVR32_LINUX__"); \ |
| 20152 | + builtin_define (avr32_part->macro); \ |
| 20153 | + builtin_define (avr32_arch->macro); \ |
| 20154 | + if (avr32_arch->uarch_type == UARCH_TYPE_AVR32A) \ |
| 20155 | + builtin_define ("__AVR32_AVR32A__"); \ |
| 20156 | + else \ |
| 20157 | + builtin_define ("__AVR32_AVR32B__"); \ |
| 20158 | + if (TARGET_UNALIGNED_WORD) \ |
| 20159 | + builtin_define ("__AVR32_HAS_UNALIGNED_WORD__"); \ |
| 20160 | + if (TARGET_SIMD) \ |
| 20161 | + builtin_define ("__AVR32_HAS_SIMD__"); \ |
| 20162 | + if (TARGET_DSP) \ |
| 20163 | + builtin_define ("__AVR32_HAS_DSP__"); \ |
| 20164 | + if (TARGET_RMW) \ |
| 20165 | + builtin_define ("__AVR32_HAS_RMW__"); \ |
| 20166 | + if (TARGET_BRANCH_PRED) \ |
| 20167 | + builtin_define ("__AVR32_HAS_BRANCH_PRED__"); \ |
| 20168 | + if (TARGET_FAST_FLOAT) \ |
| 20169 | + builtin_define ("__AVR32_FAST_FLOAT__"); \ |
| 20170 | + } \ |
| 20171 | + while (0) |
| 20172 | + |
| 20173 | + |
| 20174 | + |
| 20175 | +/* Call the function profiler with a given profile label. */ |
| 20176 | +#undef FUNCTION_PROFILER |
| 20177 | +#define FUNCTION_PROFILER(STREAM, LABELNO) \ |
| 20178 | + do \ |
| 20179 | + { \ |
| 20180 | + fprintf (STREAM, "\tmov\tlr, lo(mcount)\n\torh\tlr, hi(mcount)\n"); \ |
| 20181 | + fprintf (STREAM, "\ticall lr\n"); \ |
| 20182 | + } \ |
| 20183 | + while (0) |
| 20184 | + |
| 20185 | +#define NO_PROFILE_COUNTERS 1 |
| 20186 | + |
| 20187 | +/* For dynamic libraries to work */ |
| 20188 | +/* #define PLT_REG_CALL_CLOBBERED 1 */ |
| 20189 | +#define AVR32_ALWAYS_PIC 1 |
| 20190 | + |
| 20191 | +/* uclibc does not implement sinf, cosf etc. */ |
| 20192 | +#undef TARGET_C99_FUNCTIONS |
| 20193 | +#define TARGET_C99_FUNCTIONS 0 |
| 20194 | + |
| 20195 | +#define LINK_GCC_C_SEQUENCE_SPEC \ |
| 20196 | + "%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}" |
| 20197 | --- /dev/null |
| 20198 | +++ b/gcc/config/avr32/predicates.md |
| 20199 | @@ -0,0 +1,422 @@ |
| 20200 | +;; AVR32 predicates file. |
| 20201 | +;; Copyright 2003-2006 Atmel Corporation. |
| 20202 | +;; |
| 20203 | +;; Written by Ronny Pedersen, Atmel Norway, <rpedersen@atmel.com> |
| 20204 | +;; |
| 20205 | +;; This file is part of GCC. |
| 20206 | +;; |
| 20207 | +;; This program is free software; you can redistribute it and/or modify |
| 20208 | +;; it under the terms of the GNU General Public License as published by |
| 20209 | +;; the Free Software Foundation; either version 2 of the License, or |
| 20210 | +;; (at your option) any later version. |
| 20211 | +;; |
| 20212 | +;; This program is distributed in the hope that it will be useful, |
| 20213 | +;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20214 | +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20215 | +;; GNU General Public License for more details. |
| 20216 | +;; |
| 20217 | +;; You should have received a copy of the GNU General Public License |
| 20218 | +;; along with this program; if not, write to the Free Software |
| 20219 | +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 20220 | + |
| 20221 | + |
| 20222 | +;; True if the operand is a memory reference which contains an |
| 20223 | +;; Address consisting of a single pointer register |
| 20224 | +(define_predicate "avr32_indirect_register_operand" |
| 20225 | + (and (match_code "mem") |
| 20226 | + (match_test "register_operand(XEXP(op, 0), SImode)"))) |
| 20227 | + |
| 20228 | + |
| 20229 | + |
| 20230 | +;; Address expression with a base pointer offset with |
| 20231 | +;; a register displacement |
| 20232 | +(define_predicate "avr32_indexed_memory_operand" |
| 20233 | + (and (match_code "mem") |
| 20234 | + (match_test "GET_CODE(XEXP(op, 0)) == PLUS")) |
| 20235 | + { |
| 20236 | + |
| 20237 | + rtx op0 = XEXP(XEXP(op, 0), 0); |
| 20238 | + rtx op1 = XEXP(XEXP(op, 0), 1); |
| 20239 | + |
| 20240 | + return ((avr32_address_register_rtx_p (op0, 0) |
| 20241 | + && avr32_legitimate_index_p (GET_MODE(op), op1, 0)) |
| 20242 | + || (avr32_address_register_rtx_p (op1, 0) |
| 20243 | + && avr32_legitimate_index_p (GET_MODE(op), op0, 0))); |
| 20244 | + |
| 20245 | + }) |
| 20246 | + |
| 20247 | +;; Operand suitable for the ld.sb instruction |
| 20248 | +(define_predicate "load_sb_memory_operand" |
| 20249 | + (ior (match_operand 0 "avr32_indirect_register_operand") |
| 20250 | + (match_operand 0 "avr32_indexed_memory_operand"))) |
| 20251 | + |
| 20252 | + |
| 20253 | +;; Operand suitable as operand to insns sign extending QI values |
| 20254 | +(define_predicate "extendqi_operand" |
| 20255 | + (ior (match_operand 0 "load_sb_memory_operand") |
| 20256 | + (match_operand 0 "register_operand"))) |
| 20257 | + |
| 20258 | +(define_predicate "post_inc_memory_operand" |
| 20259 | + (and (match_code "mem") |
| 20260 | + (match_test "(GET_CODE(XEXP(op, 0)) == POST_INC) |
| 20261 | + && REG_P(XEXP(XEXP(op, 0), 0))"))) |
| 20262 | + |
| 20263 | +(define_predicate "pre_dec_memory_operand" |
| 20264 | + (and (match_code "mem") |
| 20265 | + (match_test "(GET_CODE(XEXP(op, 0)) == PRE_DEC) |
| 20266 | + && REG_P(XEXP(XEXP(op, 0), 0))"))) |
| 20267 | + |
| 20268 | +;; Operand suitable for add instructions |
| 20269 | +(define_predicate "avr32_add_operand" |
| 20270 | + (ior (match_operand 0 "register_operand") |
| 20271 | + (and (match_operand 0 "immediate_operand") |
| 20272 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'I', \"Is21\")")))) |
| 20273 | + |
| 20274 | +;; Operand is a power of two immediate |
| 20275 | +(define_predicate "power_of_two_operand" |
| 20276 | + (match_code "const_int") |
| 20277 | +{ |
| 20278 | + HOST_WIDE_INT value = INTVAL (op); |
| 20279 | + |
| 20280 | + return value != 0 && (value & (value - 1)) == 0; |
| 20281 | +}) |
| 20282 | + |
| 20283 | +;; Operand is a multiple of 8 immediate |
| 20284 | +(define_predicate "multiple_of_8_operand" |
| 20285 | + (match_code "const_int") |
| 20286 | +{ |
| 20287 | + HOST_WIDE_INT value = INTVAL (op); |
| 20288 | + |
| 20289 | + return (value & 0x7) == 0 ; |
| 20290 | +}) |
| 20291 | + |
| 20292 | +;; Operand is a multiple of 16 immediate |
| 20293 | +(define_predicate "multiple_of_16_operand" |
| 20294 | + (match_code "const_int") |
| 20295 | +{ |
| 20296 | + HOST_WIDE_INT value = INTVAL (op); |
| 20297 | + |
| 20298 | + return (value & 0xf) == 0 ; |
| 20299 | +}) |
| 20300 | + |
| 20301 | +;; Operand is a mask used for masking away upper bits of a reg |
| 20302 | +(define_predicate "avr32_mask_upper_bits_operand" |
| 20303 | + (match_code "const_int") |
| 20304 | +{ |
| 20305 | + HOST_WIDE_INT value = INTVAL (op) + 1; |
| 20306 | + |
| 20307 | + return value != 1 && value != 0 && (value & (value - 1)) == 0; |
| 20308 | +}) |
| 20309 | + |
| 20310 | + |
| 20311 | +;; Operand suitable for mul instructions |
| 20312 | +(define_predicate "avr32_mul_operand" |
| 20313 | + (ior (match_operand 0 "register_operand") |
| 20314 | + (and (match_operand 0 "immediate_operand") |
| 20315 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'K', \"Ks08\")")))) |
| 20316 | + |
| 20317 | +;; True for logical binary operators. |
| 20318 | +(define_predicate "logical_binary_operator" |
| 20319 | + (match_code "ior,xor,and")) |
| 20320 | + |
| 20321 | +;; True for logical shift operators |
| 20322 | +(define_predicate "logical_shift_operator" |
| 20323 | + (match_code "ashift,lshiftrt")) |
| 20324 | + |
| 20325 | +;; True for shift operand for logical and, or and eor insns |
| 20326 | +(define_predicate "avr32_logical_shift_operand" |
| 20327 | + (and (match_code "ashift,lshiftrt") |
| 20328 | + (ior (and (match_test "GET_CODE(XEXP(op, 1)) == CONST_INT") |
| 20329 | + (match_test "register_operand(XEXP(op, 0), GET_MODE(XEXP(op, 0)))")) |
| 20330 | + (and (match_test "GET_CODE(XEXP(op, 0)) == CONST_INT") |
| 20331 | + (match_test "register_operand(XEXP(op, 1), GET_MODE(XEXP(op, 1)))")))) |
| 20332 | + ) |
| 20333 | + |
| 20334 | + |
| 20335 | +;; Predicate for second operand to and, ior and xor insn patterns |
| 20336 | +(define_predicate "avr32_logical_insn_operand" |
| 20337 | + (ior (match_operand 0 "register_operand") |
| 20338 | + (match_operand 0 "avr32_logical_shift_operand")) |
| 20339 | +) |
| 20340 | + |
| 20341 | + |
| 20342 | +;; True for avr32 comparison operators |
| 20343 | +(define_predicate "avr32_comparison_operator" |
| 20344 | + (ior (match_code "eq, ne, gt, ge, lt, le, gtu, geu, ltu, leu") |
| 20345 | + (and (match_code "unspec") |
| 20346 | + (match_test "(XINT(op, 1) == UNSPEC_COND_MI) |
| 20347 | + || (XINT(op, 1) == UNSPEC_COND_PL)")))) |
| 20348 | + |
| 20349 | +(define_predicate "avr32_cond3_comparison_operator" |
| 20350 | + (ior (match_code "eq, ne, ge, lt, geu, ltu") |
| 20351 | + (and (match_code "unspec") |
| 20352 | + (match_test "(XINT(op, 1) == UNSPEC_COND_MI) |
| 20353 | + || (XINT(op, 1) == UNSPEC_COND_PL)")))) |
| 20354 | + |
| 20355 | +;; True for avr32 comparison operand |
| 20356 | +(define_predicate "avr32_comparison_operand" |
| 20357 | + (ior (and (match_code "eq, ne, gt, ge, lt, le, gtu, geu, ltu, leu") |
| 20358 | + (match_test "(CC0_P (XEXP(op,0)) && rtx_equal_p (XEXP(op,1), const0_rtx))")) |
| 20359 | + (and (match_code "unspec") |
| 20360 | + (match_test "(XINT(op, 1) == UNSPEC_COND_MI) |
| 20361 | + || (XINT(op, 1) == UNSPEC_COND_PL)")))) |
| 20362 | + |
| 20363 | +;; True if this is a const_int with one bit set |
| 20364 | +(define_predicate "one_bit_set_operand" |
| 20365 | + (match_code "const_int") |
| 20366 | + { |
| 20367 | + int i; |
| 20368 | + int value; |
| 20369 | + int ones = 0; |
| 20370 | + |
| 20371 | + value = INTVAL(op); |
| 20372 | + for ( i = 0 ; i < 32; i++ ){ |
| 20373 | + if ( value & ( 1 << i ) ){ |
| 20374 | + ones++; |
| 20375 | + } |
| 20376 | + } |
| 20377 | + |
| 20378 | + return ( ones == 1 ); |
| 20379 | + }) |
| 20380 | + |
| 20381 | + |
| 20382 | +;; True if this is a const_int with one bit cleared |
| 20383 | +(define_predicate "one_bit_cleared_operand" |
| 20384 | + (match_code "const_int") |
| 20385 | + { |
| 20386 | + int i; |
| 20387 | + int value; |
| 20388 | + int zeroes = 0; |
| 20389 | + |
| 20390 | + value = INTVAL(op); |
| 20391 | + for ( i = 0 ; i < 32; i++ ){ |
| 20392 | + if ( !(value & ( 1 << i )) ){ |
| 20393 | + zeroes++; |
| 20394 | + } |
| 20395 | + } |
| 20396 | + |
| 20397 | + return ( zeroes == 1 ); |
| 20398 | + }) |
| 20399 | + |
| 20400 | + |
| 20401 | +;; Immediate all the low 16-bits cleared |
| 20402 | +(define_predicate "avr32_hi16_immediate_operand" |
| 20403 | + (match_code "const_int") |
| 20404 | + { |
| 20405 | + /* If the low 16-bits are zero then this |
| 20406 | + is a hi16 immediate. */ |
| 20407 | + return ((INTVAL(op) & 0xffff) == 0); |
| 20408 | + } |
| 20409 | +) |
| 20410 | + |
| 20411 | +;; True if this is a register or immediate operand |
| 20412 | +(define_predicate "register_immediate_operand" |
| 20413 | + (ior (match_operand 0 "register_operand") |
| 20414 | + (match_operand 0 "immediate_operand"))) |
| 20415 | + |
| 20416 | +;; True if this is a register or const_int operand |
| 20417 | +(define_predicate "register_const_int_operand" |
| 20418 | + (ior (match_operand 0 "register_operand") |
| 20419 | + (and (match_operand 0 "const_int_operand") |
| 20420 | + (match_operand 0 "immediate_operand")))) |
| 20421 | + |
| 20422 | +;; True if this is a register or const_double operand |
| 20423 | +(define_predicate "register_const_double_operand" |
| 20424 | + (ior (match_operand 0 "register_operand") |
| 20425 | + (match_operand 0 "const_double_operand"))) |
| 20426 | + |
| 20427 | +;; True if this is an operand containing a label_ref. |
| 20428 | +(define_predicate "avr32_label_ref_operand" |
| 20429 | + (and (match_code "mem") |
| 20430 | + (match_test "avr32_find_symbol(op) |
| 20431 | + && (GET_CODE(avr32_find_symbol(op)) == LABEL_REF)"))) |
| 20432 | + |
| 20433 | +;; True if this is a valid symbol pointing to the constant pool. |
| 20434 | +(define_predicate "avr32_const_pool_operand" |
| 20435 | + (and (match_code "symbol_ref") |
| 20436 | + (match_test "CONSTANT_POOL_ADDRESS_P(op)")) |
| 20437 | + { |
| 20438 | + return (flag_pic ? (!(symbol_mentioned_p (get_pool_constant (op)) |
| 20439 | + || label_mentioned_p (get_pool_constant (op))) |
| 20440 | + || avr32_got_mentioned_p(get_pool_constant (op))) |
| 20441 | + : true); |
| 20442 | + } |
| 20443 | +) |
| 20444 | + |
| 20445 | +;; True if this is a memory reference to the constant or mini pool. |
| 20446 | +(define_predicate "avr32_const_pool_ref_operand" |
| 20447 | + (ior (match_operand 0 "avr32_label_ref_operand") |
| 20448 | + (and (match_code "mem") |
| 20449 | + (match_test "avr32_const_pool_operand(XEXP(op,0), GET_MODE(XEXP(op,0)))")))) |
| 20450 | + |
| 20451 | + |
| 20452 | +;; Legal source operand for movti insns |
| 20453 | +(define_predicate "avr32_movti_src_operand" |
| 20454 | + (ior (match_operand 0 "avr32_const_pool_ref_operand") |
| 20455 | + (ior (ior (match_operand 0 "register_immediate_operand") |
| 20456 | + (match_operand 0 "avr32_indirect_register_operand")) |
| 20457 | + (match_operand 0 "post_inc_memory_operand")))) |
| 20458 | + |
| 20459 | +;; Legal destination operand for movti insns |
| 20460 | +(define_predicate "avr32_movti_dst_operand" |
| 20461 | + (ior (ior (match_operand 0 "register_operand") |
| 20462 | + (match_operand 0 "avr32_indirect_register_operand")) |
| 20463 | + (match_operand 0 "pre_dec_memory_operand"))) |
| 20464 | + |
| 20465 | + |
| 20466 | +;; True if this is a k12 offseted memory operand. |
| 20467 | +(define_predicate "avr32_k12_memory_operand" |
| 20468 | + (and (match_code "mem") |
| 20469 | + (ior (match_test "REG_P(XEXP(op, 0))") |
| 20470 | + (match_test "GET_CODE(XEXP(op, 0)) == PLUS |
| 20471 | + && REG_P(XEXP(XEXP(op, 0), 0)) |
| 20472 | + && (GET_CODE(XEXP(XEXP(op, 0), 1)) == CONST_INT) |
| 20473 | + && (CONST_OK_FOR_CONSTRAINT_P(INTVAL(XEXP(XEXP(op, 0), 0)), |
| 20474 | + 'K', (mode == SImode) ? \"Ks14\" : ((mode == HImode) ? \"Ks13\" : \"Ks12\")))")))) |
| 20475 | + |
| 20476 | +;; True if this is a memory operand with an immediate displacement. |
| 20477 | +(define_predicate "avr32_imm_disp_memory_operand" |
| 20478 | + (and (match_code "mem") |
| 20479 | + (match_test "GET_CODE(XEXP(op, 0)) == PLUS |
| 20480 | + && REG_P(XEXP(XEXP(op, 0), 0)) |
| 20481 | + && (GET_CODE(XEXP(XEXP(op, 0), 1)) == CONST_INT)"))) |
| 20482 | + |
| 20483 | +;; True if this is a bswap operand. |
| 20484 | +(define_predicate "avr32_bswap_operand" |
| 20485 | + (ior (match_operand 0 "avr32_k12_memory_operand") |
| 20486 | + (match_operand 0 "register_operand"))) |
| 20487 | + |
| 20488 | +;; True if this is a valid coprocessor insn memory operand. |
| 20489 | +(define_predicate "avr32_cop_memory_operand" |
| 20490 | + (and (match_operand 0 "memory_operand") |
| 20491 | + (not (match_test "GET_CODE(XEXP(op, 0)) == PLUS |
| 20492 | + && REG_P(XEXP(XEXP(op, 0), 0)) |
| 20493 | + && (GET_CODE(XEXP(XEXP(op, 0), 1)) == CONST_INT) |
| 20494 | + && !(CONST_OK_FOR_CONSTRAINT_P(INTVAL(XEXP(XEXP(op, 0), 0)), 'K', \"Ku10\"))")))) |
| 20495 | + |
| 20496 | +;; True if this is a valid source/destination operand. |
| 20497 | +;; for moving values to/from a coprocessor |
| 20498 | +(define_predicate "avr32_cop_move_operand" |
| 20499 | + (ior (match_operand 0 "register_operand") |
| 20500 | + (match_operand 0 "avr32_cop_memory_operand"))) |
| 20501 | + |
| 20502 | + |
| 20503 | +;; True if this is a valid extract byte offset for use in |
| 20504 | +;; load extracted index insns. |
| 20505 | +(define_predicate "avr32_extract_shift_operand" |
| 20506 | + (and (match_operand 0 "const_int_operand") |
| 20507 | + (match_test "(INTVAL(op) == 0) || (INTVAL(op) == 8) |
| 20508 | + || (INTVAL(op) == 16) || (INTVAL(op) == 24)"))) |
| 20509 | + |
| 20510 | +;; True if this is a valid avr32 symbol operand. |
| 20511 | +(define_predicate "avr32_symbol_operand" |
| 20512 | + (and (match_code "label_ref, symbol_ref, const") |
| 20513 | + (match_test "avr32_find_symbol(op)"))) |
| 20514 | + |
| 20515 | +;; True if this is a valid operand for the lda.w and call pseudo insns. |
| 20516 | +(define_predicate "avr32_address_operand" |
| 20517 | + (and (and (match_code "label_ref, symbol_ref") |
| 20518 | + (match_test "avr32_find_symbol(op)")) |
| 20519 | + (ior (match_test "TARGET_HAS_ASM_ADDR_PSEUDOS") |
| 20520 | + (match_test "flag_pic")) )) |
| 20521 | + |
| 20522 | +;; An immediate k16 address operand |
| 20523 | +(define_predicate "avr32_ks16_address_operand" |
| 20524 | + (and (match_operand 0 "address_operand") |
| 20525 | + (ior (match_test "REG_P(op)") |
| 20526 | + (match_test "GET_CODE(op) == PLUS |
| 20527 | + && ((GET_CODE(XEXP(op,0)) == CONST_INT) |
| 20528 | + || (GET_CODE(XEXP(op,1)) == CONST_INT))")) )) |
| 20529 | + |
| 20530 | +;; An offset k16 memory operand |
| 20531 | +(define_predicate "avr32_ks16_memory_operand" |
| 20532 | + (and (match_code "mem") |
| 20533 | + (match_test "avr32_ks16_address_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))"))) |
| 20534 | + |
| 20535 | +;; An immediate k11 address operand |
| 20536 | +(define_predicate "avr32_ks11_address_operand" |
| 20537 | + (and (match_operand 0 "address_operand") |
| 20538 | + (ior (match_test "REG_P(op)") |
| 20539 | + (match_test "GET_CODE(op) == PLUS |
| 20540 | + && (((GET_CODE(XEXP(op,0)) == CONST_INT) |
| 20541 | + && avr32_const_ok_for_constraint_p(INTVAL(XEXP(op,0)), 'K', \"Ks11\")) |
| 20542 | + || ((GET_CODE(XEXP(op,1)) == CONST_INT) |
| 20543 | + && avr32_const_ok_for_constraint_p(INTVAL(XEXP(op,1)), 'K', \"Ks11\")))")) )) |
| 20544 | + |
| 20545 | +;; True if this is a avr32 call operand |
| 20546 | +(define_predicate "avr32_call_operand" |
| 20547 | + (ior (ior (match_operand 0 "register_operand") |
| 20548 | + (ior (match_operand 0 "avr32_const_pool_ref_operand") |
| 20549 | + (match_operand 0 "avr32_address_operand"))) |
| 20550 | + (match_test "SYMBOL_REF_RCALL_FUNCTION_P(op)"))) |
| 20551 | + |
| 20552 | +;; Return true for operators performing ALU operations |
| 20553 | + |
| 20554 | +(define_predicate "alu_operator" |
| 20555 | + (match_code "ior, xor, and, plus, minus, ashift, lshiftrt, ashiftrt")) |
| 20556 | + |
| 20557 | +(define_predicate "avr32_add_shift_immediate_operand" |
| 20558 | + (and (match_operand 0 "immediate_operand") |
| 20559 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'K', \"Ku02\")"))) |
| 20560 | + |
| 20561 | +(define_predicate "avr32_cond_register_immediate_operand" |
| 20562 | + (ior (match_operand 0 "register_operand") |
| 20563 | + (and (match_operand 0 "immediate_operand") |
| 20564 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'K', \"Ks08\")")))) |
| 20565 | + |
| 20566 | +(define_predicate "avr32_cond_immediate_operand" |
| 20567 | + (and (match_operand 0 "immediate_operand") |
| 20568 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'I', \"Is08\")"))) |
| 20569 | + |
| 20570 | + |
| 20571 | +(define_predicate "avr32_cond_move_operand" |
| 20572 | + (ior (ior (match_operand 0 "register_operand") |
| 20573 | + (and (match_operand 0 "immediate_operand") |
| 20574 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'K', \"Ks08\")"))) |
| 20575 | + (and (match_test "TARGET_V2_INSNS") |
| 20576 | + (match_operand 0 "memory_operand")))) |
| 20577 | + |
| 20578 | +(define_predicate "avr32_mov_immediate_operand" |
| 20579 | + (and (match_operand 0 "immediate_operand") |
| 20580 | + (match_test "avr32_const_ok_for_move(INTVAL(op))"))) |
| 20581 | + |
| 20582 | + |
| 20583 | +(define_predicate "avr32_rmw_address_operand" |
| 20584 | + (ior (and (match_code "symbol_ref") |
| 20585 | + (match_test "({rtx symbol = avr32_find_symbol(op); \ |
| 20586 | + symbol && (GET_CODE (symbol) == SYMBOL_REF) && SYMBOL_REF_RMW_ADDR(symbol);})")) |
| 20587 | + (and (match_operand 0 "immediate_operand") |
| 20588 | + (match_test "CONST_OK_FOR_CONSTRAINT_P(INTVAL(op), 'K', \"Ks17\")"))) |
| 20589 | + { |
| 20590 | + return TARGET_RMW && !flag_pic; |
| 20591 | + } |
| 20592 | +) |
| 20593 | + |
| 20594 | +(define_predicate "avr32_rmw_memory_operand" |
| 20595 | + (and (match_code "mem") |
| 20596 | + (match_test "!volatile_refs_p(op) && (GET_MODE(op) == SImode) && |
| 20597 | + avr32_rmw_address_operand(XEXP(op, 0), GET_MODE(XEXP(op, 0)))"))) |
| 20598 | + |
| 20599 | +(define_predicate "avr32_rmw_memory_or_register_operand" |
| 20600 | + (ior (match_operand 0 "avr32_rmw_memory_operand") |
| 20601 | + (match_operand 0 "register_operand"))) |
| 20602 | + |
| 20603 | +(define_predicate "avr32_non_rmw_memory_operand" |
| 20604 | + (and (not (match_operand 0 "avr32_rmw_memory_operand")) |
| 20605 | + (match_operand 0 "memory_operand"))) |
| 20606 | + |
| 20607 | +(define_predicate "avr32_non_rmw_general_operand" |
| 20608 | + (and (not (match_operand 0 "avr32_rmw_memory_operand")) |
| 20609 | + (match_operand 0 "general_operand"))) |
| 20610 | + |
| 20611 | +(define_predicate "avr32_non_rmw_nonimmediate_operand" |
| 20612 | + (and (not (match_operand 0 "avr32_rmw_memory_operand")) |
| 20613 | + (match_operand 0 "nonimmediate_operand"))) |
| 20614 | + |
| 20615 | +;; Return true if the operand is the 1.0f constant. |
| 20616 | + |
| 20617 | +(define_predicate "const_1f_operand" |
| 20618 | + (match_code "const_int,const_double") |
| 20619 | +{ |
| 20620 | + return (op == CONST1_RTX (SFmode)); |
| 20621 | +}) |
| 20622 | --- /dev/null |
| 20623 | +++ b/gcc/config/avr32/simd.md |
| 20624 | @@ -0,0 +1,145 @@ |
| 20625 | +;; AVR32 machine description file for SIMD instructions. |
| 20626 | +;; Copyright 2003-2006 Atmel Corporation. |
| 20627 | +;; |
| 20628 | +;; Written by Ronny Pedersen, Atmel Norway, <rpedersen@atmel.com> |
| 20629 | +;; |
| 20630 | +;; This file is part of GCC. |
| 20631 | +;; |
| 20632 | +;; This program is free software; you can redistribute it and/or modify |
| 20633 | +;; it under the terms of the GNU General Public License as published by |
| 20634 | +;; the Free Software Foundation; either version 2 of the License, or |
| 20635 | +;; (at your option) any later version. |
| 20636 | +;; |
| 20637 | +;; This program is distributed in the hope that it will be useful, |
| 20638 | +;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20639 | +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20640 | +;; GNU General Public License for more details. |
| 20641 | +;; |
| 20642 | +;; You should have received a copy of the GNU General Public License |
| 20643 | +;; along with this program; if not, write to the Free Software |
| 20644 | +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 20645 | + |
| 20646 | +;; -*- Mode: Scheme -*- |
| 20647 | + |
| 20648 | + |
| 20649 | +;; Vector modes |
| 20650 | +(define_mode_iterator VECM [V2HI V4QI]) |
| 20651 | +(define_mode_attr size [(V2HI "h") (V4QI "b")]) |
| 20652 | + |
| 20653 | +(define_insn "add<mode>3" |
| 20654 | + [(set (match_operand:VECM 0 "register_operand" "=r") |
| 20655 | + (plus:VECM (match_operand:VECM 1 "register_operand" "r") |
| 20656 | + (match_operand:VECM 2 "register_operand" "r")))] |
| 20657 | + "TARGET_SIMD" |
| 20658 | + "padd.<size>\t%0, %1, %2" |
| 20659 | + [(set_attr "length" "4") |
| 20660 | + (set_attr "type" "alu")]) |
| 20661 | + |
| 20662 | + |
| 20663 | +(define_insn "sub<mode>3" |
| 20664 | + [(set (match_operand:VECM 0 "register_operand" "=r") |
| 20665 | + (minus:VECM (match_operand:VECM 1 "register_operand" "r") |
| 20666 | + (match_operand:VECM 2 "register_operand" "r")))] |
| 20667 | + "TARGET_SIMD" |
| 20668 | + "psub.<size>\t%0, %1, %2" |
| 20669 | + [(set_attr "length" "4") |
| 20670 | + (set_attr "type" "alu")]) |
| 20671 | + |
| 20672 | + |
| 20673 | +(define_insn "abs<mode>2" |
| 20674 | + [(set (match_operand:VECM 0 "register_operand" "=r") |
| 20675 | + (abs:VECM (match_operand:VECM 1 "register_operand" "r")))] |
| 20676 | + "TARGET_SIMD" |
| 20677 | + "pabs.s<size>\t%0, %1" |
| 20678 | + [(set_attr "length" "4") |
| 20679 | + (set_attr "type" "alu")]) |
| 20680 | + |
| 20681 | +(define_insn "ashl<mode>3" |
| 20682 | + [(set (match_operand:VECM 0 "register_operand" "=r") |
| 20683 | + (ashift:VECM (match_operand:VECM 1 "register_operand" "r") |
| 20684 | + (match_operand:SI 2 "immediate_operand" "Ku04")))] |
| 20685 | + "TARGET_SIMD" |
| 20686 | + "plsl.<size>\t%0, %1, %2" |
| 20687 | + [(set_attr "length" "4") |
| 20688 | + (set_attr "type" "alu")]) |
| 20689 | + |
| 20690 | +(define_insn "ashr<mode>3" |
| 20691 | + [(set (match_operand:VECM 0 "register_operand" "=r") |
| 20692 | + (ashiftrt:VECM (match_operand:VECM 1 "register_operand" "r") |
| 20693 | + (match_operand:SI 2 "immediate_operand" "Ku04")))] |
| 20694 | + "TARGET_SIMD" |
| 20695 | + "pasr.<size>\t%0, %1, %2" |
| 20696 | + [(set_attr "length" "4") |
| 20697 | + (set_attr "type" "alu")]) |
| 20698 | + |
| 20699 | +(define_insn "lshr<mode>3" |
| 20700 | + [(set (match_operand:VECM 0 "register_operand" "=r") |
| 20701 | + (lshiftrt:VECM (match_operand:VECM 1 "register_operand" "r") |
| 20702 | + (match_operand:SI 2 "immediate_operand" "Ku04")))] |
| 20703 | + "TARGET_SIMD" |
| 20704 | + "plsr.<size>\t%0, %1, %2" |
| 20705 | + [(set_attr "length" "4") |
| 20706 | + (set_attr "type" "alu")]) |
| 20707 | + |
| 20708 | +(define_insn "smaxv2hi3" |
| 20709 | + [(set (match_operand:V2HI 0 "register_operand" "=r") |
| 20710 | + (smax:V2HI (match_operand:V2HI 1 "register_operand" "r") |
| 20711 | + (match_operand:V2HI 2 "register_operand" "r")))] |
| 20712 | + |
| 20713 | + "TARGET_SIMD" |
| 20714 | + "pmax.sh\t%0, %1, %2" |
| 20715 | + [(set_attr "length" "4") |
| 20716 | + (set_attr "type" "alu")]) |
| 20717 | + |
| 20718 | +(define_insn "sminv2hi3" |
| 20719 | + [(set (match_operand:V2HI 0 "register_operand" "=r") |
| 20720 | + (smin:V2HI (match_operand:V2HI 1 "register_operand" "r") |
| 20721 | + (match_operand:V2HI 2 "register_operand" "r")))] |
| 20722 | + |
| 20723 | + "TARGET_SIMD" |
| 20724 | + "pmin.sh\t%0, %1, %2" |
| 20725 | + [(set_attr "length" "4") |
| 20726 | + (set_attr "type" "alu")]) |
| 20727 | + |
| 20728 | +(define_insn "umaxv4qi3" |
| 20729 | + [(set (match_operand:V4QI 0 "register_operand" "=r") |
| 20730 | + (umax:V4QI (match_operand:V4QI 1 "register_operand" "r") |
| 20731 | + (match_operand:V4QI 2 "register_operand" "r")))] |
| 20732 | + |
| 20733 | + "TARGET_SIMD" |
| 20734 | + "pmax.ub\t%0, %1, %2" |
| 20735 | + [(set_attr "length" "4") |
| 20736 | + (set_attr "type" "alu")]) |
| 20737 | + |
| 20738 | +(define_insn "uminv4qi3" |
| 20739 | + [(set (match_operand:V4QI 0 "register_operand" "=r") |
| 20740 | + (umin:V4QI (match_operand:V4QI 1 "register_operand" "r") |
| 20741 | + (match_operand:V4QI 2 "register_operand" "r")))] |
| 20742 | + |
| 20743 | + "TARGET_SIMD" |
| 20744 | + "pmin.ub\t%0, %1, %2" |
| 20745 | + [(set_attr "length" "4") |
| 20746 | + (set_attr "type" "alu")]) |
| 20747 | + |
| 20748 | + |
| 20749 | +(define_insn "addsubv2hi" |
| 20750 | + [(set (match_operand:V2HI 0 "register_operand" "=r") |
| 20751 | + (vec_concat:V2HI |
| 20752 | + (plus:HI (match_operand:HI 1 "register_operand" "r") |
| 20753 | + (match_operand:HI 2 "register_operand" "r")) |
| 20754 | + (minus:HI (match_dup 1) (match_dup 2))))] |
| 20755 | + "TARGET_SIMD" |
| 20756 | + "paddsub.h\t%0, %1:b, %2:b" |
| 20757 | + [(set_attr "length" "4") |
| 20758 | + (set_attr "type" "alu")]) |
| 20759 | + |
| 20760 | +(define_insn "subaddv2hi" |
| 20761 | + [(set (match_operand:V2HI 0 "register_operand" "=r") |
| 20762 | + (vec_concat:V2HI |
| 20763 | + (minus:HI (match_operand:HI 1 "register_operand" "r") |
| 20764 | + (match_operand:HI 2 "register_operand" "r")) |
| 20765 | + (plus:HI (match_dup 1) (match_dup 2))))] |
| 20766 | + "TARGET_SIMD" |
| 20767 | + "psubadd.h\t%0, %1:b, %2:b" |
| 20768 | + [(set_attr "length" "4") |
| 20769 | + (set_attr "type" "alu")]) |
| 20770 | --- /dev/null |
| 20771 | +++ b/gcc/config/avr32/sync.md |
| 20772 | @@ -0,0 +1,244 @@ |
| 20773 | +;;================================================================= |
| 20774 | +;; Atomic operations |
| 20775 | +;;================================================================= |
| 20776 | + |
| 20777 | + |
| 20778 | +(define_insn "sync_compare_and_swapsi" |
| 20779 | + [(set (match_operand:SI 0 "register_operand" "=&r,&r") |
| 20780 | + (match_operand:SI 1 "memory_operand" "+RKs16,+RKs16")) |
| 20781 | + (set (match_dup 1) |
| 20782 | + (unspec_volatile:SI |
| 20783 | + [(match_dup 1) |
| 20784 | + (match_operand:SI 2 "register_immediate_operand" "r,Ks21") |
| 20785 | + (match_operand:SI 3 "register_operand" "r,r")] |
| 20786 | + VUNSPEC_SYNC_CMPXCHG)) ] |
| 20787 | + "" |
| 20788 | + "0: |
| 20789 | + ssrf\t5 |
| 20790 | + ld.w\t%0,%1 |
| 20791 | + cp.w\t%0,%2 |
| 20792 | + brne\t0f |
| 20793 | + stcond\t%1, %3 |
| 20794 | + brne\t0b |
| 20795 | + 0: |
| 20796 | + " |
| 20797 | + [(set_attr "length" "16,18") |
| 20798 | + (set_attr "cc" "clobber")] |
| 20799 | + ) |
| 20800 | + |
| 20801 | + |
| 20802 | +(define_code_iterator atomic_op [plus minus and ior xor]) |
| 20803 | +(define_code_attr atomic_asm_insn [(plus "add") (minus "sub") (and "and") (ior "or") (xor "eor")]) |
| 20804 | +(define_code_attr atomic_insn [(plus "add") (minus "sub") (and "and") (ior "ior") (xor "xor")]) |
| 20805 | + |
| 20806 | +(define_insn "sync_loadsi" |
| 20807 | + ; NB! Put an early clobber on the destination operand to |
| 20808 | + ; avoid gcc using the same register in the source and |
| 20809 | + ; destination. This is done in order to avoid gcc to |
| 20810 | + ; clobber the source operand since these instructions |
| 20811 | + ; are actually inside a "loop". |
| 20812 | + [(set (match_operand:SI 0 "register_operand" "=&r") |
| 20813 | + (unspec_volatile:SI |
| 20814 | + [(match_operand:SI 1 "avr32_ks16_memory_operand" "RKs16") |
| 20815 | + (label_ref (match_operand 2 "" ""))] |
| 20816 | + VUNSPEC_SYNC_SET_LOCK_AND_LOAD) )] |
| 20817 | + "" |
| 20818 | + "%2: |
| 20819 | + ssrf\t5 |
| 20820 | + ld.w\t%0,%1" |
| 20821 | + [(set_attr "length" "6") |
| 20822 | + (set_attr "cc" "clobber")] |
| 20823 | + ) |
| 20824 | + |
| 20825 | +(define_insn "sync_store_if_lock" |
| 20826 | + [(set (match_operand:SI 0 "avr32_ks16_memory_operand" "=RKs16") |
| 20827 | + (unspec_volatile:SI |
| 20828 | + [(match_operand:SI 1 "register_operand" "r") |
| 20829 | + (label_ref (match_operand 2 "" ""))] |
| 20830 | + VUNSPEC_SYNC_STORE_IF_LOCK) )] |
| 20831 | + "" |
| 20832 | + "stcond\t%0, %1 |
| 20833 | + brne\t%2" |
| 20834 | + [(set_attr "length" "6") |
| 20835 | + (set_attr "cc" "clobber")] |
| 20836 | + ) |
| 20837 | + |
| 20838 | + |
| 20839 | +(define_expand "sync_<atomic_insn>si" |
| 20840 | + [(set (match_dup 2) |
| 20841 | + (unspec_volatile:SI |
| 20842 | + [(match_operand:SI 0 "avr32_ks16_memory_operand" "") |
| 20843 | + (match_dup 3)] |
| 20844 | + VUNSPEC_SYNC_SET_LOCK_AND_LOAD)) |
| 20845 | + (set (match_dup 2) |
| 20846 | + (atomic_op:SI (match_dup 2) |
| 20847 | + (match_operand:SI 1 "register_immediate_operand" ""))) |
| 20848 | + (set (match_dup 0) |
| 20849 | + (unspec_volatile:SI |
| 20850 | + [(match_dup 2) |
| 20851 | + (match_dup 3)] |
| 20852 | + VUNSPEC_SYNC_STORE_IF_LOCK) ) |
| 20853 | + (use (match_dup 1)) |
| 20854 | + (use (match_dup 4))] |
| 20855 | + "" |
| 20856 | + { |
| 20857 | + rtx *mem_expr = &operands[0]; |
| 20858 | + rtx ptr_reg; |
| 20859 | + if ( !avr32_ks16_memory_operand (*mem_expr, GET_MODE (*mem_expr)) ) |
| 20860 | + { |
| 20861 | + ptr_reg = force_reg (Pmode, XEXP (*mem_expr, 0)); |
| 20862 | + XEXP (*mem_expr, 0) = ptr_reg; |
| 20863 | + } |
| 20864 | + else |
| 20865 | + { |
| 20866 | + rtx address = XEXP (*mem_expr, 0); |
| 20867 | + if ( REG_P (address) ) |
| 20868 | + ptr_reg = address; |
| 20869 | + else if ( REG_P (XEXP (address, 0)) ) |
| 20870 | + ptr_reg = XEXP (address, 0); |
| 20871 | + else |
| 20872 | + ptr_reg = XEXP (address, 1); |
| 20873 | + } |
| 20874 | + |
| 20875 | + operands[2] = gen_reg_rtx (SImode); |
| 20876 | + operands[3] = gen_rtx_LABEL_REF(Pmode, gen_label_rtx ()); |
| 20877 | + operands[4] = ptr_reg; |
| 20878 | + |
| 20879 | + } |
| 20880 | + ) |
| 20881 | + |
| 20882 | + |
| 20883 | + |
| 20884 | +(define_expand "sync_old_<atomic_insn>si" |
| 20885 | + [(set (match_operand:SI 0 "register_operand" "") |
| 20886 | + (unspec_volatile:SI |
| 20887 | + [(match_operand:SI 1 "avr32_ks16_memory_operand" "") |
| 20888 | + (match_dup 4)] |
| 20889 | + VUNSPEC_SYNC_SET_LOCK_AND_LOAD)) |
| 20890 | + (set (match_dup 3) |
| 20891 | + (atomic_op:SI (match_dup 0) |
| 20892 | + (match_operand:SI 2 "register_immediate_operand" ""))) |
| 20893 | + (set (match_dup 1) |
| 20894 | + (unspec_volatile:SI |
| 20895 | + [(match_dup 3) |
| 20896 | + (match_dup 4)] |
| 20897 | + VUNSPEC_SYNC_STORE_IF_LOCK) ) |
| 20898 | + (use (match_dup 2)) |
| 20899 | + (use (match_dup 5))] |
| 20900 | + "" |
| 20901 | + { |
| 20902 | + rtx *mem_expr = &operands[1]; |
| 20903 | + rtx ptr_reg; |
| 20904 | + if ( !avr32_ks16_memory_operand (*mem_expr, GET_MODE (*mem_expr)) ) |
| 20905 | + { |
| 20906 | + ptr_reg = force_reg (Pmode, XEXP (*mem_expr, 0)); |
| 20907 | + XEXP (*mem_expr, 0) = ptr_reg; |
| 20908 | + } |
| 20909 | + else |
| 20910 | + { |
| 20911 | + rtx address = XEXP (*mem_expr, 0); |
| 20912 | + if ( REG_P (address) ) |
| 20913 | + ptr_reg = address; |
| 20914 | + else if ( REG_P (XEXP (address, 0)) ) |
| 20915 | + ptr_reg = XEXP (address, 0); |
| 20916 | + else |
| 20917 | + ptr_reg = XEXP (address, 1); |
| 20918 | + } |
| 20919 | + |
| 20920 | + operands[3] = gen_reg_rtx (SImode); |
| 20921 | + operands[4] = gen_rtx_LABEL_REF(Pmode, gen_label_rtx ()); |
| 20922 | + operands[5] = ptr_reg; |
| 20923 | + } |
| 20924 | + ) |
| 20925 | + |
| 20926 | +(define_expand "sync_new_<atomic_insn>si" |
| 20927 | + [(set (match_operand:SI 0 "register_operand" "") |
| 20928 | + (unspec_volatile:SI |
| 20929 | + [(match_operand:SI 1 "avr32_ks16_memory_operand" "") |
| 20930 | + (match_dup 3)] |
| 20931 | + VUNSPEC_SYNC_SET_LOCK_AND_LOAD)) |
| 20932 | + (set (match_dup 0) |
| 20933 | + (atomic_op:SI (match_dup 0) |
| 20934 | + (match_operand:SI 2 "register_immediate_operand" ""))) |
| 20935 | + (set (match_dup 1) |
| 20936 | + (unspec_volatile:SI |
| 20937 | + [(match_dup 0) |
| 20938 | + (match_dup 3)] |
| 20939 | + VUNSPEC_SYNC_STORE_IF_LOCK) ) |
| 20940 | + (use (match_dup 2)) |
| 20941 | + (use (match_dup 4))] |
| 20942 | + "" |
| 20943 | + { |
| 20944 | + rtx *mem_expr = &operands[1]; |
| 20945 | + rtx ptr_reg; |
| 20946 | + if ( !avr32_ks16_memory_operand (*mem_expr, GET_MODE (*mem_expr)) ) |
| 20947 | + { |
| 20948 | + ptr_reg = force_reg (Pmode, XEXP (*mem_expr, 0)); |
| 20949 | + XEXP (*mem_expr, 0) = ptr_reg; |
| 20950 | + } |
| 20951 | + else |
| 20952 | + { |
| 20953 | + rtx address = XEXP (*mem_expr, 0); |
| 20954 | + if ( REG_P (address) ) |
| 20955 | + ptr_reg = address; |
| 20956 | + else if ( REG_P (XEXP (address, 0)) ) |
| 20957 | + ptr_reg = XEXP (address, 0); |
| 20958 | + else |
| 20959 | + ptr_reg = XEXP (address, 1); |
| 20960 | + } |
| 20961 | + |
| 20962 | + operands[3] = gen_rtx_LABEL_REF(Pmode, gen_label_rtx ()); |
| 20963 | + operands[4] = ptr_reg; |
| 20964 | + } |
| 20965 | + ) |
| 20966 | + |
| 20967 | + |
| 20968 | +;(define_insn "sync_<atomic_insn>si" |
| 20969 | +; [(set (match_operand:SI 0 "memory_operand" "+RKs16") |
| 20970 | +; (unspec_volatile:SI |
| 20971 | +; [(atomic_op:SI (match_dup 0) |
| 20972 | +; (match_operand:SI 1 "register_operand" "r"))] |
| 20973 | +; VUNSPEC_SYNC_CMPXCHG)) |
| 20974 | +; (clobber (match_scratch:SI 2 "=&r"))] |
| 20975 | +; "" |
| 20976 | +; "0: |
| 20977 | +; ssrf\t5 |
| 20978 | +; ld.w\t%2,%0 |
| 20979 | +; <atomic_asm_insn>\t%2,%1 |
| 20980 | +; stcond\t%0, %2 |
| 20981 | +; brne\t0b |
| 20982 | +; " |
| 20983 | +; [(set_attr "length" "14") |
| 20984 | +; (set_attr "cc" "clobber")] |
| 20985 | +; ) |
| 20986 | +; |
| 20987 | +;(define_insn "sync_new_<atomic_insn>si" |
| 20988 | +; [(set (match_operand:SI 1 "memory_operand" "+RKs16") |
| 20989 | +; (unspec_volatile:SI |
| 20990 | +; [(atomic_op:SI (match_dup 1) |
| 20991 | +; (match_operand:SI 2 "register_operand" "r"))] |
| 20992 | +; VUNSPEC_SYNC_CMPXCHG)) |
| 20993 | +; (set (match_operand:SI 0 "register_operand" "=&r") |
| 20994 | +; (atomic_op:SI (match_dup 1) |
| 20995 | +; (match_dup 2)))] |
| 20996 | +; "" |
| 20997 | +; "0: |
| 20998 | +; ssrf\t5 |
| 20999 | +; ld.w\t%0,%1 |
| 21000 | +; <atomic_asm_insn>\t%0,%2 |
| 21001 | +; stcond\t%1, %0 |
| 21002 | +; brne\t0b |
| 21003 | +; " |
| 21004 | +; [(set_attr "length" "14") |
| 21005 | +; (set_attr "cc" "clobber")] |
| 21006 | +; ) |
| 21007 | + |
| 21008 | +(define_insn "sync_lock_test_and_setsi" |
| 21009 | + [ (set (match_operand:SI 0 "register_operand" "=&r") |
| 21010 | + (match_operand:SI 1 "memory_operand" "+RKu00")) |
| 21011 | + (set (match_dup 1) |
| 21012 | + (match_operand:SI 2 "register_operand" "r")) ] |
| 21013 | + "" |
| 21014 | + "xchg\t%0, %p1, %2" |
| 21015 | + [(set_attr "length" "4")] |
| 21016 | + ) |
| 21017 | --- /dev/null |
| 21018 | +++ b/gcc/config/avr32/t-avr32 |
| 21019 | @@ -0,0 +1,118 @@ |
| 21020 | + |
| 21021 | +MD_INCLUDES= $(srcdir)/config/avr32/avr32.md \ |
| 21022 | + $(srcdir)/config/avr32/sync.md \ |
| 21023 | + $(srcdir)/config/avr32/simd.md \ |
| 21024 | + $(srcdir)/config/avr32/predicates.md |
| 21025 | + |
| 21026 | +s-config s-conditions s-flags s-codes s-constants s-emit s-recog s-preds \ |
| 21027 | + s-opinit s-extract s-peep s-attr s-attrtab s-output: $(MD_INCLUDES) |
| 21028 | + |
| 21029 | +# We want fine grained libraries, so use the new code |
| 21030 | +# to build the floating point emulation libraries. |
| 21031 | +FPBIT = fp-bit.c |
| 21032 | +DPBIT = dp-bit.c |
| 21033 | + |
| 21034 | +LIB1ASMSRC = avr32/lib1funcs.S |
| 21035 | +LIB1ASMFUNCS = _avr32_f64_mul _avr32_f64_mul_fast _avr32_f64_addsub _avr32_f64_addsub_fast _avr32_f64_to_u32 \ |
| 21036 | + _avr32_f64_to_s32 _avr32_f64_to_u64 _avr32_f64_to_s64 _avr32_u32_to_f64 \ |
| 21037 | + _avr32_s32_to_f64 _avr32_f64_cmp_eq _avr32_f64_cmp_ge _avr32_f64_cmp_lt \ |
| 21038 | + _avr32_f32_cmp_eq _avr32_f32_cmp_ge _avr32_f32_cmp_lt _avr32_f64_div _avr32_f64_div_fast \ |
| 21039 | + _avr32_f32_div _avr32_f32_div_fast _avr32_f32_addsub _avr32_f32_addsub_fast \ |
| 21040 | + _avr32_f32_mul _avr32_s32_to_f32 _avr32_u32_to_f32 _avr32_f32_to_s32 \ |
| 21041 | + _avr32_f32_to_u32 _avr32_f32_to_f64 _avr32_f64_to_f32 _mulsi3 |
| 21042 | + |
| 21043 | +#LIB2FUNCS_EXTRA += $(srcdir)/config/avr32/lib2funcs.S |
| 21044 | + |
| 21045 | +MULTILIB_OPTIONS = march=ap/march=ucr1/march=ucr2/march=ucr2nomul/march=ucr3/march=ucr3fp |
| 21046 | +MULTILIB_DIRNAMES = ap ucr1 ucr2 ucr2nomul ucr3 ucr3fp |
| 21047 | +MULTILIB_EXCEPTIONS = |
| 21048 | +MULTILIB_MATCHES += march?ap=mpart?ap7000 |
| 21049 | +MULTILIB_MATCHES += march?ap=mpart?ap7001 |
| 21050 | +MULTILIB_MATCHES += march?ap=mpart?ap7002 |
| 21051 | +MULTILIB_MATCHES += march?ap=mpart?ap7200 |
| 21052 | +MULTILIB_MATCHES += march?ucr1=march?uc |
| 21053 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3a0512es |
| 21054 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a0128 |
| 21055 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a0256 |
| 21056 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a0512 |
| 21057 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a1128 |
| 21058 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a1256 |
| 21059 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3a1512es |
| 21060 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a1512 |
| 21061 | +MULTILIB_MATCHES += march?ucr2nomul=mpart?uc3a3revd |
| 21062 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a364 |
| 21063 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a364s |
| 21064 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3128 |
| 21065 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3128s |
| 21066 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3256 |
| 21067 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3256s |
| 21068 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a464 |
| 21069 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a464s |
| 21070 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4128 |
| 21071 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4128s |
| 21072 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4256 |
| 21073 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4256s |
| 21074 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b064 |
| 21075 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b0128 |
| 21076 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b0256es |
| 21077 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b0256 |
| 21078 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b0512 |
| 21079 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b0512revc |
| 21080 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b164 |
| 21081 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b1128 |
| 21082 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b1256es |
| 21083 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b1256 |
| 21084 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b1512 |
| 21085 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b1512revc |
| 21086 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64d3 |
| 21087 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128d3 |
| 21088 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64d4 |
| 21089 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128d4 |
| 21090 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3c0512crevc |
| 21091 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3c1512crevc |
| 21092 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3c2512crevc |
| 21093 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l0256 |
| 21094 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l0128 |
| 21095 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l064 |
| 21096 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l032 |
| 21097 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l016 |
| 21098 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l064revb |
| 21099 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64l3u |
| 21100 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128l3u |
| 21101 | +MULTILIB_MATCHES += march?ucr3=mpart?uc256l3u |
| 21102 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64l4u |
| 21103 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128l4u |
| 21104 | +MULTILIB_MATCHES += march?ucr3=mpart?uc256l4u |
| 21105 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c064c |
| 21106 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c0128c |
| 21107 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c0256c |
| 21108 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c0512c |
| 21109 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c164c |
| 21110 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c1128c |
| 21111 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c1256c |
| 21112 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c1512c |
| 21113 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c264c |
| 21114 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c2128c |
| 21115 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c2256c |
| 21116 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c2512c |
| 21117 | +MULTILIB_MATCHES += march?ucr3=mpart?mxt768e |
| 21118 | + |
| 21119 | + |
| 21120 | +EXTRA_MULTILIB_PARTS = crtbegin.o crtbeginS.o crtend.o crtendS.o crti.o crtn.o |
| 21121 | + |
| 21122 | +CRTSTUFF_T_CFLAGS = -mrelax |
| 21123 | +CRTSTUFF_T_CFLAGS_S = -mrelax -fPIC |
| 21124 | +TARGET_LIBGCC2_CFLAGS += -mrelax |
| 21125 | + |
| 21126 | +LIBGCC = stmp-multilib |
| 21127 | +INSTALL_LIBGCC = install-multilib |
| 21128 | + |
| 21129 | +fp-bit.c: $(srcdir)/config/fp-bit.c |
| 21130 | + echo '#define FLOAT' > fp-bit.c |
| 21131 | + cat $(srcdir)/config/fp-bit.c >> fp-bit.c |
| 21132 | + |
| 21133 | +dp-bit.c: $(srcdir)/config/fp-bit.c |
| 21134 | + cat $(srcdir)/config/fp-bit.c > dp-bit.c |
| 21135 | + |
| 21136 | + |
| 21137 | + |
| 21138 | --- /dev/null |
| 21139 | +++ b/gcc/config/avr32/t-avr32-linux |
| 21140 | @@ -0,0 +1,118 @@ |
| 21141 | + |
| 21142 | +MD_INCLUDES= $(srcdir)/config/avr32/avr32.md \ |
| 21143 | + $(srcdir)/config/avr32/sync.md \ |
| 21144 | + $(srcdir)/config/avr32/simd.md \ |
| 21145 | + $(srcdir)/config/avr32/predicates.md |
| 21146 | + |
| 21147 | +s-config s-conditions s-flags s-codes s-constants s-emit s-recog s-preds \ |
| 21148 | + s-opinit s-extract s-peep s-attr s-attrtab s-output: $(MD_INCLUDES) |
| 21149 | + |
| 21150 | +# We want fine grained libraries, so use the new code |
| 21151 | +# to build the floating point emulation libraries. |
| 21152 | +FPBIT = fp-bit.c |
| 21153 | +DPBIT = dp-bit.c |
| 21154 | + |
| 21155 | +LIB1ASMSRC = avr32/lib1funcs.S |
| 21156 | +LIB1ASMFUNCS = _avr32_f64_mul _avr32_f64_mul_fast _avr32_f64_addsub _avr32_f64_addsub_fast _avr32_f64_to_u32 \ |
| 21157 | + _avr32_f64_to_s32 _avr32_f64_to_u64 _avr32_f64_to_s64 _avr32_u32_to_f64 \ |
| 21158 | + _avr32_s32_to_f64 _avr32_f64_cmp_eq _avr32_f64_cmp_ge _avr32_f64_cmp_lt \ |
| 21159 | + _avr32_f32_cmp_eq _avr32_f32_cmp_ge _avr32_f32_cmp_lt _avr32_f64_div _avr32_f64_div_fast \ |
| 21160 | + _avr32_f32_div _avr32_f32_div_fast _avr32_f32_addsub _avr32_f32_addsub_fast \ |
| 21161 | + _avr32_f32_mul _avr32_s32_to_f32 _avr32_u32_to_f32 _avr32_f32_to_s32 \ |
| 21162 | + _avr32_f32_to_u32 _avr32_f32_to_f64 _avr32_f64_to_f32 _mulsi3 |
| 21163 | + |
| 21164 | +#LIB2FUNCS_EXTRA += $(srcdir)/config/avr32/lib2funcs.S |
| 21165 | + |
| 21166 | +MULTILIB_OPTIONS = march=ap/march=ucr1/march=ucr2/march=ucr2nomul/march=ucr3/march=ucr3fp |
| 21167 | +MULTILIB_DIRNAMES = ap ucr1 ucr2 ucr2nomul ucr3 ucr3fp |
| 21168 | +MULTILIB_EXCEPTIONS = |
| 21169 | +MULTILIB_MATCHES += march?ap=mpart?ap7000 |
| 21170 | +MULTILIB_MATCHES += march?ap=mpart?ap7001 |
| 21171 | +MULTILIB_MATCHES += march?ap=mpart?ap7002 |
| 21172 | +MULTILIB_MATCHES += march?ap=mpart?ap7200 |
| 21173 | +MULTILIB_MATCHES += march?ucr1=march?uc |
| 21174 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3a0512es |
| 21175 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a0128 |
| 21176 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a0256 |
| 21177 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a0512 |
| 21178 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a1128 |
| 21179 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a1256 |
| 21180 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3a1512es |
| 21181 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a1512 |
| 21182 | +MULTILIB_MATCHES += march?ucr2nomul=mpart?uc3a3revd |
| 21183 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a364 |
| 21184 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a364s |
| 21185 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3128 |
| 21186 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3128s |
| 21187 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3256 |
| 21188 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a3256s |
| 21189 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a464 |
| 21190 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a464s |
| 21191 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4128 |
| 21192 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4128s |
| 21193 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4256 |
| 21194 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3a4256s |
| 21195 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b064 |
| 21196 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b0128 |
| 21197 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b0256es |
| 21198 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b0256 |
| 21199 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b0512 |
| 21200 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b0512revc |
| 21201 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b164 |
| 21202 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b1128 |
| 21203 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b1256es |
| 21204 | +MULTILIB_MATCHES += march?ucr1=mpart?uc3b1256 |
| 21205 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b1512 |
| 21206 | +MULTILIB_MATCHES += march?ucr2=mpart?uc3b1512revc |
| 21207 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64d3 |
| 21208 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128d3 |
| 21209 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64d4 |
| 21210 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128d4 |
| 21211 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3c0512crevc |
| 21212 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3c1512crevc |
| 21213 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3c2512crevc |
| 21214 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l0256 |
| 21215 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l0128 |
| 21216 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l064 |
| 21217 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l032 |
| 21218 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l016 |
| 21219 | +MULTILIB_MATCHES += march?ucr3=mpart?uc3l064revb |
| 21220 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64l3u |
| 21221 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128l3u |
| 21222 | +MULTILIB_MATCHES += march?ucr3=mpart?uc256l3u |
| 21223 | +MULTILIB_MATCHES += march?ucr3=mpart?uc64l4u |
| 21224 | +MULTILIB_MATCHES += march?ucr3=mpart?uc128l4u |
| 21225 | +MULTILIB_MATCHES += march?ucr3=mpart?uc256l4u |
| 21226 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c064c |
| 21227 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c0128c |
| 21228 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c0256c |
| 21229 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c0512c |
| 21230 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c164c |
| 21231 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c1128c |
| 21232 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c1256c |
| 21233 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c1512c |
| 21234 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c264c |
| 21235 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c2128c |
| 21236 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c2256c |
| 21237 | +MULTILIB_MATCHES += march?ucr3fp=mpart?uc3c2512c |
| 21238 | +MULTILIB_MATCHES += march?ucr3=mpart?mxt768e |
| 21239 | + |
| 21240 | + |
| 21241 | +EXTRA_MULTILIB_PARTS = crtbegin.o crtbeginS.o crtend.o crtendS.o |
| 21242 | + |
| 21243 | +CRTSTUFF_T_CFLAGS = -mrelax |
| 21244 | +CRTSTUFF_T_CFLAGS_S = -mrelax -fPIC |
| 21245 | +TARGET_LIBGCC2_CFLAGS += -mrelax |
| 21246 | + |
| 21247 | +LIBGCC = stmp-multilib |
| 21248 | +INSTALL_LIBGCC = install-multilib |
| 21249 | + |
| 21250 | +fp-bit.c: $(srcdir)/config/fp-bit.c |
| 21251 | + echo '#define FLOAT' > fp-bit.c |
| 21252 | + cat $(srcdir)/config/fp-bit.c >> fp-bit.c |
| 21253 | + |
| 21254 | +dp-bit.c: $(srcdir)/config/fp-bit.c |
| 21255 | + cat $(srcdir)/config/fp-bit.c > dp-bit.c |
| 21256 | + |
| 21257 | + |
| 21258 | + |
| 21259 | --- /dev/null |
| 21260 | +++ b/gcc/config/avr32/t-elf |
| 21261 | @@ -0,0 +1,16 @@ |
| 21262 | + |
| 21263 | +# Assemble startup files. |
| 21264 | +$(T)crti.o: $(srcdir)/config/avr32/crti.asm $(GCC_PASSES) |
| 21265 | + $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS) $(INCLUDES) \ |
| 21266 | + -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/avr32/crti.asm |
| 21267 | + |
| 21268 | +$(T)crtn.o: $(srcdir)/config/avr32/crtn.asm $(GCC_PASSES) |
| 21269 | + $(GCC_FOR_TARGET) $(CRTSTUFF_CFLAGS) $(CRTSTUFF_T_CFLAGS) $(INCLUDES) \ |
| 21270 | + -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/avr32/crtn.asm |
| 21271 | + |
| 21272 | + |
| 21273 | +# Build the libraries for both hard and soft floating point |
| 21274 | +EXTRA_MULTILIB_PARTS = crtbegin.o crtbeginS.o crtend.o crtendS.o crti.o crtn.o |
| 21275 | + |
| 21276 | +LIBGCC = stmp-multilib |
| 21277 | +INSTALL_LIBGCC = install-multilib |
| 21278 | --- /dev/null |
| 21279 | +++ b/gcc/config/avr32/uc3fpu.md |
| 21280 | @@ -0,0 +1,199 @@ |
| 21281 | +;; AVR32 machine description file for Floating-Point instructions. |
| 21282 | +;; Copyright 2003-2006 Atmel Corporation. |
| 21283 | +;; |
| 21284 | +;; |
| 21285 | +;; This file is part of GCC. |
| 21286 | +;; |
| 21287 | +;; This program is free software; you can redistribute it and/or modify |
| 21288 | +;; it under the terms of the GNU General Public License as published by |
| 21289 | +;; the Free Software Foundation; either version 2 of the License, or |
| 21290 | +;; (at your option) any later version. |
| 21291 | +;; |
| 21292 | +;; This program is distributed in the hope that it will be useful, |
| 21293 | +;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21294 | +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 21295 | +;; GNU General Public License for more details. |
| 21296 | +;; |
| 21297 | +;; You should have received a copy of the GNU General Public License |
| 21298 | +;; along with this program; if not, write to the Free Software |
| 21299 | +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 21300 | + |
| 21301 | +(define_insn "*movsf_uc3fp" |
| 21302 | + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,m") |
| 21303 | + (match_operand:SF 1 "general_operand" "r,G,m,r"))] |
| 21304 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21305 | + "@ |
| 21306 | + mov\t%0, %1 |
| 21307 | + mov\t%0, %1 |
| 21308 | + ld.w\t%0, %1 |
| 21309 | + st.w\t%0, %1" |
| 21310 | + [(set_attr "length" "2,4,4,4") |
| 21311 | + (set_attr "type" "alu,alu,load,store")]) |
| 21312 | + |
| 21313 | +(define_insn "mulsf3" |
| 21314 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21315 | + (mult:SF (match_operand:SF 1 "register_operand" "r") |
| 21316 | + (match_operand:SF 2 "register_operand" "r")))] |
| 21317 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21318 | + "fmul.s\t%0, %1, %2" |
| 21319 | + [(set_attr "length" "4") |
| 21320 | + (set_attr "type" "fmul")]) |
| 21321 | + |
| 21322 | +(define_insn "nmulsf3" |
| 21323 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21324 | + (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "%r") |
| 21325 | + (match_operand:SF 2 "register_operand" "r"))))] |
| 21326 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21327 | + "fnmul.s\t%0, %1, %2" |
| 21328 | + [(set_attr "length" "4") |
| 21329 | + (set_attr "type" "fmul")]) |
| 21330 | + |
| 21331 | +(define_insn "macsf3" |
| 21332 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21333 | + (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "r") |
| 21334 | + (match_operand:SF 2 "register_operand" "r")) |
| 21335 | + (match_operand:SF 3 "register_operand" "r")))] |
| 21336 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21337 | + "fmac.s\t%0, %3, %1, %2" |
| 21338 | + [(set_attr "length" "4") |
| 21339 | + (set_attr "type" "fmul")]) |
| 21340 | + |
| 21341 | +;(define_insn "nmacsf3" |
| 21342 | +; [(set (match_operand:SF 0 "register_operand" "=r") |
| 21343 | +; (plus:SF (neg:SF (match_operand:SF 1 "register_operand" "r")) |
| 21344 | +; (mult:SF(match_operand:SF 2 "register_operand" "r") |
| 21345 | +; (match_operand:SF 3 "register_operand" "r"))))] |
| 21346 | +; "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21347 | +; "fnmac.s\t%0, %1, %2, %3" |
| 21348 | +; [(set_attr "length" "4") |
| 21349 | +; (set_attr "type" "fmul")]) |
| 21350 | + |
| 21351 | +(define_insn "nmacsf3" |
| 21352 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21353 | + (minus:SF (mult:SF (match_operand:SF 2 "register_operand" "r") |
| 21354 | + (match_operand:SF 3 "register_operand" "r")) |
| 21355 | + (match_operand:SF 1 "register_operand" "r")))] |
| 21356 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21357 | + "fnmac.s\t%0, %1, %2, %3" |
| 21358 | + [(set_attr "length" "4") |
| 21359 | + (set_attr "type" "fmul")]) |
| 21360 | + |
| 21361 | +(define_insn "msubacsf3" |
| 21362 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21363 | + (minus:SF (match_operand:SF 3 "register_operand" "r") |
| 21364 | + (mult:SF (match_operand:SF 1 "register_operand" "r") |
| 21365 | + (match_operand:SF 2 "register_operand" "r"))))] |
| 21366 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21367 | + "fmsc.s\t%0, %3, %1, %2" |
| 21368 | + [(set_attr "length" "4") |
| 21369 | + (set_attr "type" "fmul")]) |
| 21370 | + |
| 21371 | +(define_insn "nmsubacsf3" |
| 21372 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21373 | + (minus:SF (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "r") |
| 21374 | + (match_operand:SF 2 "register_operand" "r"))) |
| 21375 | + (match_operand:SF 3 "register_operand" "r")))] |
| 21376 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21377 | + "fnmsc.s\t%0, %3, %1, %2" |
| 21378 | + [(set_attr "length" "4") |
| 21379 | + (set_attr "type" "fmul")]) |
| 21380 | + |
| 21381 | +(define_insn "addsf3" |
| 21382 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21383 | + (plus:SF (match_operand:SF 1 "register_operand" "%r") |
| 21384 | + (match_operand:SF 2 "register_operand" "r")))] |
| 21385 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21386 | + "fadd.s\t%0, %1, %2" |
| 21387 | + [(set_attr "length" "4") |
| 21388 | + (set_attr "type" "fmul")]) |
| 21389 | + |
| 21390 | +(define_insn "subsf3" |
| 21391 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21392 | + (minus:SF (match_operand:SF 1 "register_operand" "r") |
| 21393 | + (match_operand:SF 2 "register_operand" "r")))] |
| 21394 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21395 | + "fsub.s\t%0, %1, %2" |
| 21396 | + [(set_attr "length" "4") |
| 21397 | + (set_attr "type" "fmul")]) |
| 21398 | + |
| 21399 | +(define_insn "fixuns_truncsfsi2" |
| 21400 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 21401 | + (unsigned_fix:SI (match_operand:SF 1 "register_operand" "r")))] |
| 21402 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21403 | + "fcastrs.uw\t%0, %1" |
| 21404 | + [(set_attr "length" "4")]) |
| 21405 | + |
| 21406 | +(define_insn "fix_truncsfsi2" |
| 21407 | + [(set (match_operand:SI 0 "register_operand" "=r") |
| 21408 | + (fix:SI (match_operand:SF 1 "register_operand" "r")))] |
| 21409 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21410 | + "fcastrs.sw\t%0, %1" |
| 21411 | + [(set_attr "length" "4")]) |
| 21412 | + |
| 21413 | +(define_insn "floatunssisf2" |
| 21414 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21415 | + (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))] |
| 21416 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21417 | + "fcastuw.s\t%0, %1" |
| 21418 | + [(set_attr "length" "4")]) |
| 21419 | + |
| 21420 | +(define_insn "floatsisf2" |
| 21421 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21422 | + (float:SF (match_operand:SI 1 "register_operand" "r")))] |
| 21423 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21424 | + "fcastsw.s\t%0, %1" |
| 21425 | + [(set_attr "length" "4")]) |
| 21426 | + |
| 21427 | +(define_insn "cmpsf_internal_uc3fp" |
| 21428 | + [(set (cc0) |
| 21429 | + (compare:CC |
| 21430 | + (match_operand:SF 0 "register_operand" "r") |
| 21431 | + (match_operand:SF 1 "register_operand" "r")))] |
| 21432 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21433 | + { |
| 21434 | + avr32_branch_type = CMP_SF; |
| 21435 | + if (!rtx_equal_p(cc_prev_status.mdep.value, SET_SRC(PATTERN (insn))) ) |
| 21436 | + return "fcmp.s\t%0, %1"; |
| 21437 | + return ""; |
| 21438 | + } |
| 21439 | + [(set_attr "length" "4") |
| 21440 | + (set_attr "cc" "compare")]) |
| 21441 | + |
| 21442 | +(define_expand "divsf3" |
| 21443 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21444 | + (div:SF (match_operand:SF 1 "register_operand" "r") |
| 21445 | + (match_operand:SF 2 "register_operand" "r")))] |
| 21446 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT && flag_unsafe_math_optimizations" |
| 21447 | + "{ |
| 21448 | + emit_insn(gen_frcpa_internal(operands[0],operands[2])); |
| 21449 | + emit_insn(gen_mulsf3(operands[0],operands[0],operands[1])); |
| 21450 | + DONE; |
| 21451 | + }" |
| 21452 | +) |
| 21453 | + |
| 21454 | +(define_insn "frcpa_internal" |
| 21455 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21456 | + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FRCPA))] |
| 21457 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21458 | + "frcpa.s %0,%1" |
| 21459 | + [(set_attr "length" "4")]) |
| 21460 | + |
| 21461 | +(define_expand "sqrtsf2" |
| 21462 | + [(set (match_operand:SF 0 "register_operand" "") |
| 21463 | + (sqrt:SF (match_operand:SF 1 "register_operand" "")))] |
| 21464 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT && flag_unsafe_math_optimizations" |
| 21465 | + " |
| 21466 | +{ |
| 21467 | + rtx scratch = gen_reg_rtx (SFmode); |
| 21468 | + emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode))); |
| 21469 | + emit_insn (gen_divsf3(operands[0], force_reg (SFmode, CONST1_RTX (SFmode)), |
| 21470 | + scratch)); |
| 21471 | + DONE; |
| 21472 | +}") |
| 21473 | + |
| 21474 | +(define_insn "rsqrtsf2" |
| 21475 | + [(set (match_operand:SF 0 "register_operand" "=r") |
| 21476 | + (div:SF (match_operand:SF 2 "const_1f_operand" "F") |
| 21477 | + (sqrt:SF (match_operand:SF 1 "register_operand" "?r"))))] |
| 21478 | + "TARGET_ARCH_FPU && TARGET_HARD_FLOAT" |
| 21479 | + "frsqrta.s %1, %0") |
| 21480 | --- /dev/null |
| 21481 | +++ b/gcc/config/avr32/uclinux-elf.h |
| 21482 | @@ -0,0 +1,20 @@ |
| 21483 | + |
| 21484 | +/* Run-time Target Specification. */ |
| 21485 | +#undef TARGET_VERSION |
| 21486 | +#define TARGET_VERSION fputs (" (AVR32 uClinux with ELF)", stderr) |
| 21487 | + |
| 21488 | +/* We don't want a .jcr section on uClinux. As if this makes a difference... */ |
| 21489 | +#define TARGET_USE_JCR_SECTION 0 |
| 21490 | + |
| 21491 | +/* Here we go. Drop the crtbegin/crtend stuff completely. */ |
| 21492 | +#undef STARTFILE_SPEC |
| 21493 | +#define STARTFILE_SPEC \ |
| 21494 | + "%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s}" \ |
| 21495 | + " %{!p:%{profile:gcrt1.o%s}" \ |
| 21496 | + " %{!profile:crt1.o%s}}}} crti.o%s" |
| 21497 | + |
| 21498 | +#undef ENDFILE_SPEC |
| 21499 | +#define ENDFILE_SPEC "crtn.o%s" |
| 21500 | + |
| 21501 | +#undef TARGET_DEFAULT |
| 21502 | +#define TARGET_DEFAULT (AVR32_FLAG_NO_INIT_GOT) |
| 21503 | --- a/gcc/config/host-linux.c |
| 21504 | +++ b/gcc/config/host-linux.c |
| 21505 | @@ -25,6 +25,9 @@ |
| 21506 | #include "hosthooks.h" |
| 21507 | #include "hosthooks-def.h" |
| 21508 | |
| 21509 | +#ifndef SSIZE_MAX |
| 21510 | +#define SSIZE_MAX LONG_MAX |
| 21511 | +#endif |
| 21512 | |
| 21513 | /* Linux has a feature called exec-shield-randomize that perturbs the |
| 21514 | address of non-fixed mapped segments by a (relatively) small amount. |
| 21515 | --- a/gcc/config.gcc |
| 21516 | +++ b/gcc/config.gcc |
| 21517 | @@ -810,6 +810,24 @@ avr-*-rtems*) |
| 21518 | avr-*-*) |
| 21519 | tm_file="avr/avr.h dbxelf.h" |
| 21520 | ;; |
| 21521 | +avr32*-*-linux*) |
| 21522 | + tm_file="dbxelf.h elfos.h linux.h avr32/linux-elf.h avr32/avr32.h " |
| 21523 | + tmake_file="t-linux avr32/t-avr32-linux" |
| 21524 | + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" |
| 21525 | + extra_modes=avr32/avr32-modes.def |
| 21526 | + gnu_ld=yes |
| 21527 | + ;; |
| 21528 | +avr32*-*-uclinux*) |
| 21529 | + tm_file="dbxelf.h elfos.h linux.h avr32/linux-elf.h avr32/uclinux-elf.h avr32/avr32.h" |
| 21530 | + tmake_file="t-linux avr32/t-avr32-linux" |
| 21531 | + extra_modes=avr32/avr32-modes.def |
| 21532 | + gnu_ld=yes |
| 21533 | + ;; |
| 21534 | +avr32-*-*) |
| 21535 | + tm_file="dbxelf.h elfos.h avr32/avr32.h avr32/avr32-elf.h" |
| 21536 | + tmake_file="avr32/t-avr32 avr32/t-elf" |
| 21537 | + extra_modes=avr32/avr32-modes.def |
| 21538 | + ;; |
| 21539 | bfin*-elf*) |
| 21540 | tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h" |
| 21541 | tmake_file=bfin/t-bfin-elf |
| 21542 | @@ -2764,6 +2782,32 @@ case "${target}" in |
| 21543 | fi |
| 21544 | ;; |
| 21545 | |
| 21546 | + avr32*-*-*) |
| 21547 | + supported_defaults="part arch" |
| 21548 | + |
| 21549 | + case "$with_part" in |
| 21550 | + "" \ |
| 21551 | + | "ap7000" | "ap7010" | "ap7020" | "uc3a0256" | "uc3a0512" | "uc3a1128" | "uc3a1256" | "uc3a1512" ) |
| 21552 | + # OK |
| 21553 | + ;; |
| 21554 | + *) |
| 21555 | + echo "Unknown part used in --with-part=$with_part" 1>&2 |
| 21556 | + exit 1 |
| 21557 | + ;; |
| 21558 | + esac |
| 21559 | + |
| 21560 | + case "$with_arch" in |
| 21561 | + "" \ |
| 21562 | + | "ap" | "uc") |
| 21563 | + # OK |
| 21564 | + ;; |
| 21565 | + *) |
| 21566 | + echo "Unknown arch used in --with-arch=$with_arch" 1>&2 |
| 21567 | + exit 1 |
| 21568 | + ;; |
| 21569 | + esac |
| 21570 | + ;; |
| 21571 | + |
| 21572 | fr*-*-*linux*) |
| 21573 | supported_defaults=cpu |
| 21574 | case "$with_cpu" in |
| 21575 | --- a/gcc/configure.ac |
| 21576 | +++ b/gcc/configure.ac |
| 21577 | @@ -2240,10 +2240,9 @@ L2:], |
| 21578 | as_ver=`$gcc_cv_as --version 2>/dev/null | sed 1q` |
| 21579 | if echo "$as_ver" | grep GNU > /dev/null; then |
| 21580 | changequote(,)dnl |
| 21581 | - as_vers=`echo $as_ver | sed -n \ |
| 21582 | - -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*.*\)$,\1,p'` |
| 21583 | - as_major=`expr "$as_vers" : '\([0-9]*\)'` |
| 21584 | - as_minor=`expr "$as_vers" : '[0-9]*\.\([0-9]*\)'` |
| 21585 | + as_ver=`echo $as_ver | sed -e 's/GNU assembler\( (GNU Binutils)\)\? \([0-9.][0-9.]*\).*/\2/'` |
| 21586 | + as_major=`echo $as_ver | sed 's/\..*//'` |
| 21587 | + as_minor=`echo $as_ver | sed 's/[^.]*\.\([0-9]*\).*/\1/'` |
| 21588 | changequote([,])dnl |
| 21589 | if test $as_major -eq 2 && test $as_minor -lt 11 |
| 21590 | then : |
| 21591 | @@ -3308,7 +3307,7 @@ case "$target" in |
| 21592 | i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* \ |
| 21593 | | x86_64*-*-* | hppa*-*-* | arm*-*-* \ |
| 21594 | | xstormy16*-*-* | cris-*-* | crisv32-*-* | xtensa*-*-* | bfin-*-* | score*-*-* \ |
| 21595 | - | spu-*-* | fido*-*-* | m32c-*-*) |
| 21596 | + | spu-*-* | fido*-*-* | m32c-*-* | avr32-*-*) |
| 21597 | insn="nop" |
| 21598 | ;; |
| 21599 | ia64*-*-* | s390*-*-*) |
| 21600 | --- a/gcc/doc/extend.texi |
| 21601 | +++ b/gcc/doc/extend.texi |
| 21602 | @@ -2397,7 +2397,7 @@ This attribute is ignored for R8C target |
| 21603 | |
| 21604 | @item interrupt |
| 21605 | @cindex interrupt handler functions |
| 21606 | -Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, |
| 21607 | +Use this attribute on the ARM, AVR, AVR32, CRX, M32C, M32R/D, m68k, |
| 21608 | and Xstormy16 ports to indicate that the specified function is an |
| 21609 | interrupt handler. The compiler will generate function entry and exit |
| 21610 | sequences suitable for use in an interrupt handler when this attribute |
| 21611 | @@ -2417,6 +2417,15 @@ void f () __attribute__ ((interrupt ("IR |
| 21612 | |
| 21613 | Permissible values for this parameter are: IRQ, FIQ, SWI, ABORT and UNDEF@. |
| 21614 | |
| 21615 | +Note, for the AVR32, you can specify which banking scheme is used for |
| 21616 | +the interrupt mode this interrupt handler is used in like this: |
| 21617 | + |
| 21618 | +@smallexample |
| 21619 | +void f () __attribute__ ((interrupt ("FULL"))); |
| 21620 | +@end smallexample |
| 21621 | + |
| 21622 | +Permissible values for this parameter are: FULL, HALF, NONE and UNDEF. |
| 21623 | + |
| 21624 | On ARMv7-M the interrupt type is ignored, and the attribute means the function |
| 21625 | may be called with a word aligned stack pointer. |
| 21626 | |
| 21627 | @@ -4188,6 +4197,23 @@ placed in either the @code{.bss_below100 |
| 21628 | |
| 21629 | @end table |
| 21630 | |
| 21631 | +@subsection AVR32 Variable Attributes |
| 21632 | + |
| 21633 | +One attribute is currently defined for AVR32 configurations: |
| 21634 | +@code{rmw_addressable} |
| 21635 | + |
| 21636 | +@table @code |
| 21637 | +@item rmw_addressable |
| 21638 | +@cindex @code{rmw_addressable} attribute |
| 21639 | + |
| 21640 | +This attribute can be used to signal that a variable can be accessed |
| 21641 | +with the addressing mode of the AVR32 Atomic Read-Modify-Write memory |
| 21642 | +instructions and hence make it possible for gcc to generate these |
| 21643 | +instructions without using built-in functions or inline assembly statements. |
| 21644 | +Variables used within the AVR32 Atomic Read-Modify-Write built-in |
| 21645 | +functions will automatically get the @code{rmw_addressable} attribute. |
| 21646 | +@end table |
| 21647 | + |
| 21648 | @subsection AVR Variable Attributes |
| 21649 | |
| 21650 | @table @code |
| 21651 | @@ -7042,6 +7068,7 @@ instructions, but allow the compiler to |
| 21652 | * Alpha Built-in Functions:: |
| 21653 | * ARM iWMMXt Built-in Functions:: |
| 21654 | * ARM NEON Intrinsics:: |
| 21655 | +* AVR32 Built-in Functions:: |
| 21656 | * Blackfin Built-in Functions:: |
| 21657 | * FR-V Built-in Functions:: |
| 21658 | * X86 Built-in Functions:: |
| 21659 | @@ -7284,6 +7311,7 @@ long long __builtin_arm_wxor (long long, |
| 21660 | long long __builtin_arm_wzero () |
| 21661 | @end smallexample |
| 21662 | |
| 21663 | + |
| 21664 | @node ARM NEON Intrinsics |
| 21665 | @subsection ARM NEON Intrinsics |
| 21666 | |
| 21667 | @@ -7292,6 +7320,74 @@ when the @option{-mfpu=neon} switch is u |
| 21668 | |
| 21669 | @include arm-neon-intrinsics.texi |
| 21670 | |
| 21671 | +@node AVR32 Built-in Functions |
| 21672 | +@subsection AVR32 Built-in Functions |
| 21673 | + |
| 21674 | +Built-in functions for atomic memory (RMW) instructions. Note that these |
| 21675 | +built-ins will fail for targets where the RMW instructions are not |
| 21676 | +implemented. Also note that these instructions only that a Ks15 << 2 |
| 21677 | +memory address and will therefor not work with any runtime computed |
| 21678 | +memory addresses. The user is responsible for making sure that any |
| 21679 | +pointers used within these functions points to a valid memory address. |
| 21680 | + |
| 21681 | +@smallexample |
| 21682 | +void __builtin_mems(int */*ptr*/, int /*bit*/) |
| 21683 | +void __builtin_memc(int */*ptr*/, int /*bit*/) |
| 21684 | +void __builtin_memt(int */*ptr*/, int /*bit*/) |
| 21685 | +@end smallexample |
| 21686 | + |
| 21687 | +Built-in functions for DSP instructions. Note that these built-ins will |
| 21688 | +fail for targets where the DSP instructions are not implemented. |
| 21689 | + |
| 21690 | +@smallexample |
| 21691 | +int __builtin_sats (int /*Rd*/,int /*sa*/, int /*bn*/) |
| 21692 | +int __builtin_satu (int /*Rd*/,int /*sa*/, int /*bn*/) |
| 21693 | +int __builtin_satrnds (int /*Rd*/,int /*sa*/, int /*bn*/) |
| 21694 | +int __builtin_satrndu (int /*Rd*/,int /*sa*/, int /*bn*/) |
| 21695 | +short __builtin_mulsathh_h (short, short) |
| 21696 | +int __builtin_mulsathh_w (short, short) |
| 21697 | +short __builtin_mulsatrndhh_h (short, short) |
| 21698 | +int __builtin_mulsatrndwh_w (int, short) |
| 21699 | +int __builtin_mulsatwh_w (int, short) |
| 21700 | +int __builtin_macsathh_w (int, short, short) |
| 21701 | +short __builtin_satadd_h (short, short) |
| 21702 | +short __builtin_satsub_h (short, short) |
| 21703 | +int __builtin_satadd_w (int, int) |
| 21704 | +int __builtin_satsub_w (int, int) |
| 21705 | +long long __builtin_mulwh_d(int, short) |
| 21706 | +long long __builtin_mulnwh_d(int, short) |
| 21707 | +long long __builtin_macwh_d(long long, int, short) |
| 21708 | +long long __builtin_machh_d(long long, short, short) |
| 21709 | +@end smallexample |
| 21710 | + |
| 21711 | +Other built-in functions for instructions that cannot easily be |
| 21712 | +generated by the compiler. |
| 21713 | + |
| 21714 | +@smallexample |
| 21715 | +void __builtin_ssrf(int); |
| 21716 | +void __builtin_csrf(int); |
| 21717 | +void __builtin_musfr(int); |
| 21718 | +int __builtin_mustr(void); |
| 21719 | +int __builtin_mfsr(int /*Status Register Address*/) |
| 21720 | +void __builtin_mtsr(int /*Status Register Address*/, int /*Value*/) |
| 21721 | +int __builtin_mfdr(int /*Debug Register Address*/) |
| 21722 | +void __builtin_mtdr(int /*Debug Register Address*/, int /*Value*/) |
| 21723 | +void __builtin_cache(void * /*Address*/, int /*Cache Operation*/) |
| 21724 | +void __builtin_sync(int /*Sync Operation*/) |
| 21725 | +void __builtin_tlbr(void) |
| 21726 | +void __builtin_tlbs(void) |
| 21727 | +void __builtin_tlbw(void) |
| 21728 | +void __builtin_breakpoint(void) |
| 21729 | +int __builtin_xchg(void * /*Address*/, int /*Value*/ ) |
| 21730 | +short __builtin_bswap_16(short) |
| 21731 | +int __builtin_bswap_32(int) |
| 21732 | +void __builtin_cop(int/*cpnr*/, int/*crd*/, int/*crx*/, int/*cry*/, int/*op*/) |
| 21733 | +int __builtin_mvcr_w(int/*cpnr*/, int/*crs*/) |
| 21734 | +void __builtin_mvrc_w(int/*cpnr*/, int/*crd*/, int/*value*/) |
| 21735 | +long long __builtin_mvcr_d(int/*cpnr*/, int/*crs*/) |
| 21736 | +void __builtin_mvrc_d(int/*cpnr*/, int/*crd*/, long long/*value*/) |
| 21737 | +@end smallexample |
| 21738 | + |
| 21739 | @node Blackfin Built-in Functions |
| 21740 | @subsection Blackfin Built-in Functions |
| 21741 | |
| 21742 | --- a/gcc/doc/invoke.texi |
| 21743 | +++ b/gcc/doc/invoke.texi |
| 21744 | @@ -195,7 +195,7 @@ in the following sections. |
| 21745 | -fvisibility-ms-compat @gol |
| 21746 | -Wabi -Wctor-dtor-privacy @gol |
| 21747 | -Wnon-virtual-dtor -Wreorder @gol |
| 21748 | --Weffc++ -Wstrict-null-sentinel @gol |
| 21749 | +-Weffc++ -Wno-deprecated @gol |
| 21750 | -Wno-non-template-friend -Wold-style-cast @gol |
| 21751 | -Woverloaded-virtual -Wno-pmf-conversions @gol |
| 21752 | -Wsign-promo} |
| 21753 | @@ -641,6 +641,12 @@ Objective-C and Objective-C++ Dialects}. |
| 21754 | -mauto-incdec -minmax -mlong-calls -mshort @gol |
| 21755 | -msoft-reg-count=@var{count}} |
| 21756 | |
| 21757 | +@emph{AVR32 Options} |
| 21758 | +@gccoptlist{-muse-rodata-section -mhard-float -msoft-float -mrelax @gol |
| 21759 | +-mforce-double-align -mno-init-got -mrelax -mmd-reorg-opt -masm-addr-pseudos @gol |
| 21760 | +-mpart=@var{part} -mcpu=@var{cpu} -march=@var{arch} @gol |
| 21761 | +-mfast-float -mimm-in-const-pool} |
| 21762 | + |
| 21763 | @emph{MCore Options} |
| 21764 | @gccoptlist{-mhardlit -mno-hardlit -mdiv -mno-div -mrelax-immediates @gol |
| 21765 | -mno-relax-immediates -mwide-bitfields -mno-wide-bitfields @gol |
| 21766 | @@ -3256,13 +3262,11 @@ appears in a class without constructors. |
| 21767 | If you want to warn about code which uses the uninitialized value of the |
| 21768 | variable in its own initializer, use the @option{-Winit-self} option. |
| 21769 | |
| 21770 | -These warnings occur for individual uninitialized or clobbered |
| 21771 | -elements of structure, union or array variables as well as for |
| 21772 | -variables which are uninitialized or clobbered as a whole. They do |
| 21773 | -not occur for variables or elements declared @code{volatile}. Because |
| 21774 | -these warnings depend on optimization, the exact variables or elements |
| 21775 | -for which there are warnings will depend on the precise optimization |
| 21776 | -options and version of GCC used. |
| 21777 | +These warnings occur only for variables that are candidates for |
| 21778 | +register allocation. Therefore, they do not occur for a variable that |
| 21779 | +is declared @code{volatile}, or whose address is taken, or whose size |
| 21780 | +is other than 1, 2, 4 or 8 bytes. Also, they do not occur for |
| 21781 | +structures, unions or arrays, even when they are in registers. |
| 21782 | |
| 21783 | Note that there may be no warning about a variable that is used only |
| 21784 | to compute a value that itself is never used, because such |
| 21785 | @@ -7461,10 +7465,6 @@ If number of candidates in the set is sm |
| 21786 | we always try to remove unnecessary ivs from the set during its |
| 21787 | optimization when a new iv is added to the set. |
| 21788 | |
| 21789 | -@item scev-max-expr-size |
| 21790 | -Bound on size of expressions used in the scalar evolutions analyzer. |
| 21791 | -Large expressions slow the analyzer. |
| 21792 | - |
| 21793 | @item omega-max-vars |
| 21794 | The maximum number of variables in an Omega constraint system. |
| 21795 | The default value is 128. |
| 21796 | @@ -8860,6 +8860,7 @@ platform. |
| 21797 | * ARC Options:: |
| 21798 | * ARM Options:: |
| 21799 | * AVR Options:: |
| 21800 | +* AVR32 Options:: |
| 21801 | * Blackfin Options:: |
| 21802 | * CRIS Options:: |
| 21803 | * CRX Options:: |
| 21804 | @@ -9348,6 +9349,145 @@ comply to the C standards, but it will p |
| 21805 | size. |
| 21806 | @end table |
| 21807 | |
| 21808 | +@node AVR32 Options |
| 21809 | +@subsection AVR32 Options |
| 21810 | +@cindex AVR32 Options |
| 21811 | + |
| 21812 | +These options are defined for AVR32 implementations: |
| 21813 | + |
| 21814 | +@table @gcctabopt |
| 21815 | +@item -muse-rodata-section |
| 21816 | +@opindex muse-rodata-section |
| 21817 | +Use section @samp{.rodata} for read-only data instead of @samp{.text}. |
| 21818 | + |
| 21819 | +@item -mhard-float |
| 21820 | +@opindex mhard-float |
| 21821 | +Use floating point coprocessor instructions. |
| 21822 | + |
| 21823 | +@item -msoft-float |
| 21824 | +@opindex msoft-float |
| 21825 | +Use software floating-point library for floating-point operations. |
| 21826 | + |
| 21827 | +@item -mforce-double-align |
| 21828 | +@opindex mforce-double-align |
| 21829 | +Force double-word alignment for double-word memory accesses. |
| 21830 | + |
| 21831 | +@item -masm-addr-pseudos |
| 21832 | +@opindex masm-addr-pseudos |
| 21833 | +Use assembler pseudo-instructions lda.w and call for handling direct |
| 21834 | +addresses. (Enabled by default) |
| 21835 | + |
| 21836 | +@item -mno-init-got |
| 21837 | +@opindex mno-init-got |
| 21838 | +Do not initialize the GOT register before using it when compiling PIC |
| 21839 | +code. |
| 21840 | + |
| 21841 | +@item -mrelax |
| 21842 | +@opindex mrelax |
| 21843 | +Let invoked assembler and linker do relaxing |
| 21844 | +(Enabled by default when optimization level is >1). |
| 21845 | +This means that when the address of symbols are known at link time, |
| 21846 | +the linker can optimize @samp{icall} and @samp{mcall} |
| 21847 | +instructions into a @samp{rcall} instruction if possible. |
| 21848 | +Loading the address of a symbol can also be optimized. |
| 21849 | + |
| 21850 | +@item -mmd-reorg-opt |
| 21851 | +@opindex mmd-reorg-opt |
| 21852 | +Perform machine dependent optimizations in reorg stage. |
| 21853 | + |
| 21854 | +@item -mpart=@var{part} |
| 21855 | +@opindex mpart |
| 21856 | +Generate code for the specified part. Permissible parts are: |
| 21857 | +@samp{ap7000}, |
| 21858 | +@samp{ap7001}, |
| 21859 | +@samp{ap7002}, |
| 21860 | +@samp{ap7200}, |
| 21861 | +@samp{uc3a0128}, |
| 21862 | +@samp{uc3a0256}, |
| 21863 | +@samp{uc3a0512}, |
| 21864 | +@samp{uc3a0512es}, |
| 21865 | +@samp{uc3a1128}, |
| 21866 | +@samp{uc3a1256}, |
| 21867 | +@samp{uc3a1512}, |
| 21868 | +@samp{uc3a1512es}, |
| 21869 | +@samp{uc3a3revd}, |
| 21870 | +@samp{uc3a364}, |
| 21871 | +@samp{uc3a364s}, |
| 21872 | +@samp{uc3a3128}, |
| 21873 | +@samp{uc3a3128s}, |
| 21874 | +@samp{uc3a3256}, |
| 21875 | +@samp{uc3a3256s}, |
| 21876 | +@samp{uc3a464}, |
| 21877 | +@samp{uc3a464s}, |
| 21878 | +@samp{uc3a4128}, |
| 21879 | +@samp{uc3a4128s}, |
| 21880 | +@samp{uc3a4256}, |
| 21881 | +@samp{uc3a4256s}, |
| 21882 | +@samp{uc3b064}, |
| 21883 | +@samp{uc3b0128}, |
| 21884 | +@samp{uc3b0256}, |
| 21885 | +@samp{uc3b0256es}, |
| 21886 | +@samp{uc3b0512}, |
| 21887 | +@samp{uc3b0512revc}, |
| 21888 | +@samp{uc3b164}, |
| 21889 | +@samp{uc3b1128}, |
| 21890 | +@samp{uc3b1256}, |
| 21891 | +@samp{uc3b1256es}, |
| 21892 | +@samp{uc3b1512}, |
| 21893 | +@samp{uc3b1512revc} |
| 21894 | +@samp{uc64d3}, |
| 21895 | +@samp{uc128d3}, |
| 21896 | +@samp{uc64d4}, |
| 21897 | +@samp{uc128d4}, |
| 21898 | +@samp{uc3c0512crevc}, |
| 21899 | +@samp{uc3c1512crevc}, |
| 21900 | +@samp{uc3c2512crevc}, |
| 21901 | +@samp{uc3l0256}, |
| 21902 | +@samp{uc3l0128}, |
| 21903 | +@samp{uc3l064}, |
| 21904 | +@samp{uc3l032}, |
| 21905 | +@samp{uc3l016}, |
| 21906 | +@samp{uc3l064revb}, |
| 21907 | +@samp{uc64l3u}, |
| 21908 | +@samp{uc128l3u}, |
| 21909 | +@samp{uc256l3u}, |
| 21910 | +@samp{uc64l4u}, |
| 21911 | +@samp{uc128l4u}, |
| 21912 | +@samp{uc256l4u}, |
| 21913 | +@samp{uc3c064c}, |
| 21914 | +@samp{uc3c0128c}, |
| 21915 | +@samp{uc3c0256c}, |
| 21916 | +@samp{uc3c0512c}, |
| 21917 | +@samp{uc3c164c}, |
| 21918 | +@samp{uc3c1128c}, |
| 21919 | +@samp{uc3c1256c}, |
| 21920 | +@samp{uc3c1512c}, |
| 21921 | +@samp{uc3c264c}, |
| 21922 | +@samp{uc3c2128c}, |
| 21923 | +@samp{uc3c2256c}, |
| 21924 | +@samp{uc3c2512c}, |
| 21925 | +@samp{mxt768e}. |
| 21926 | + |
| 21927 | +@item -mcpu=@var{cpu-type} |
| 21928 | +@opindex mcpu |
| 21929 | +Same as -mpart. Obsolete. |
| 21930 | + |
| 21931 | +@item -march=@var{arch} |
| 21932 | +@opindex march |
| 21933 | +Generate code for the specified architecture. Permissible architectures are: |
| 21934 | +@samp{ap}, @samp{uc} and @samp{ucr2}. |
| 21935 | + |
| 21936 | +@item -mfast-float |
| 21937 | +@opindex mfast-float |
| 21938 | +Enable fast floating-point library that does not conform to IEEE-754 but is still good enough |
| 21939 | +for most applications. The fast floating-point library does not round to the nearest even |
| 21940 | +but away from zero. Enabled by default if the -funsafe-math-optimizations switch is specified. |
| 21941 | + |
| 21942 | +@item -mimm-in-const-pool |
| 21943 | +@opindex mimm-in-const-pool |
| 21944 | +Put large immediates in constant pool. This is enabled by default for archs with insn-cache. |
| 21945 | +@end table |
| 21946 | + |
| 21947 | @node Blackfin Options |
| 21948 | @subsection Blackfin Options |
| 21949 | @cindex Blackfin Options |
| 21950 | @@ -9403,29 +9543,12 @@ When enabled, the compiler will ensure t |
| 21951 | contain speculative loads after jump instructions. If this option is used, |
| 21952 | @code{__WORKAROUND_SPECULATIVE_LOADS} is defined. |
| 21953 | |
| 21954 | -@item -mno-specld-anomaly |
| 21955 | -@opindex mno-specld-anomaly |
| 21956 | -Don't generate extra code to prevent speculative loads from occurring. |
| 21957 | - |
| 21958 | @item -mcsync-anomaly |
| 21959 | @opindex mcsync-anomaly |
| 21960 | When enabled, the compiler will ensure that the generated code does not |
| 21961 | contain CSYNC or SSYNC instructions too soon after conditional branches. |
| 21962 | If this option is used, @code{__WORKAROUND_SPECULATIVE_SYNCS} is defined. |
| 21963 | |
| 21964 | -@item -mno-csync-anomaly |
| 21965 | -@opindex mno-csync-anomaly |
| 21966 | -Don't generate extra code to prevent CSYNC or SSYNC instructions from |
| 21967 | -occurring too soon after a conditional branch. |
| 21968 | - |
| 21969 | -@item -mlow-64k |
| 21970 | -@opindex mlow-64k |
| 21971 | -When enabled, the compiler is free to take advantage of the knowledge that |
| 21972 | -the entire program fits into the low 64k of memory. |
| 21973 | - |
| 21974 | -@item -mno-low-64k |
| 21975 | -@opindex mno-low-64k |
| 21976 | -Assume that the program is arbitrarily large. This is the default. |
| 21977 | |
| 21978 | @item -mstack-check-l1 |
| 21979 | @opindex mstack-check-l1 |
| 21980 | @@ -9439,11 +9562,6 @@ This allows for execute in place and sha |
| 21981 | without virtual memory management. This option implies @option{-fPIC}. |
| 21982 | With a @samp{bfin-elf} target, this option implies @option{-msim}. |
| 21983 | |
| 21984 | -@item -mno-id-shared-library |
| 21985 | -@opindex mno-id-shared-library |
| 21986 | -Generate code that doesn't assume ID based shared libraries are being used. |
| 21987 | -This is the default. |
| 21988 | - |
| 21989 | @item -mleaf-id-shared-library |
| 21990 | @opindex mleaf-id-shared-library |
| 21991 | Generate code that supports shared libraries via the library ID method, |
| 21992 | @@ -9485,11 +9603,6 @@ call on this register. This switch is n |
| 21993 | will lie outside of the 24 bit addressing range of the offset based |
| 21994 | version of subroutine call instruction. |
| 21995 | |
| 21996 | -This feature is not enabled by default. Specifying |
| 21997 | -@option{-mno-long-calls} will restore the default behavior. Note these |
| 21998 | -switches have no effect on how the compiler generates code to handle |
| 21999 | -function calls via function pointers. |
| 22000 | - |
| 22001 | @item -mfast-fp |
| 22002 | @opindex mfast-fp |
| 22003 | Link with the fast floating-point library. This library relaxes some of |
| 22004 | --- a/gcc/doc/md.texi |
| 22005 | +++ b/gcc/doc/md.texi |
| 22006 | @@ -4,6 +4,7 @@ |
| 22007 | @c This is part of the GCC manual. |
| 22008 | @c For copying conditions, see the file gcc.texi. |
| 22009 | |
| 22010 | + |
| 22011 | @ifset INTERNALS |
| 22012 | @node Machine Desc |
| 22013 | @chapter Machine Descriptions |
| 22014 | @@ -1685,6 +1686,58 @@ A memory reference suitable for iWMMXt l |
| 22015 | A memory reference suitable for the ARMv4 ldrsb instruction. |
| 22016 | @end table |
| 22017 | |
| 22018 | +@item AVR32 family---@file{avr32.h} |
| 22019 | +@table @code |
| 22020 | +@item f |
| 22021 | +Floating-point registers (f0 to f15) |
| 22022 | + |
| 22023 | +@item Ku@var{bits} |
| 22024 | +Unsigned constant representable with @var{bits} number of bits (Must be |
| 22025 | +two digits). I.e: An unsigned 8-bit constant is written as @samp{Ku08} |
| 22026 | + |
| 22027 | +@item Ks@var{bits} |
| 22028 | +Signed constant representable with @var{bits} number of bits (Must be |
| 22029 | +two digits). I.e: A signed 12-bit constant is written as @samp{Ks12} |
| 22030 | + |
| 22031 | +@item Is@var{bits} |
| 22032 | +The negated range of a signed constant representable with @var{bits} |
| 22033 | +number of bits. The same as @samp{Ks@var{bits}} with a negated range. |
| 22034 | +This means that the constant must be in the range @math{-2^{bits-1}-1} to @math{2^{bits-1}} |
| 22035 | + |
| 22036 | +@item G |
| 22037 | +A single/double precision floating-point immediate or 64-bit integer |
| 22038 | +immediate where the least and most significant words both can be |
| 22039 | +loaded with a move instruction. That is the the integer form of the |
| 22040 | +values in the least and most significant words both are in the range |
| 22041 | +@math{-2^{20}} to @math{2^{20}-1}. |
| 22042 | + |
| 22043 | +@item RKs@var{bits} |
| 22044 | +A memory reference where the address consists of a base register |
| 22045 | +plus a signed immediate displacement with range given by @samp{Ks@var{bits}} |
| 22046 | +which has the same format as for the signed immediate integer constraint |
| 22047 | +given above. |
| 22048 | + |
| 22049 | +@item RKu@var{bits} |
| 22050 | +A memory reference where the address consists of a base register |
| 22051 | +plus an unsigned immediate displacement with range given by @samp{Ku@var{bits}} |
| 22052 | +which has the same format as for the unsigned immediate integer constraint |
| 22053 | +given above. |
| 22054 | + |
| 22055 | +@item S |
| 22056 | +A memory reference with an immediate or register offset |
| 22057 | + |
| 22058 | +@item T |
| 22059 | +A memory reference to a constant pool entry |
| 22060 | + |
| 22061 | +@item W |
| 22062 | +A valid operand for use in the @samp{lda.w} instruction macro when |
| 22063 | +relaxing is enabled |
| 22064 | + |
| 22065 | +@item Z |
| 22066 | +A memory reference valid for coprocessor memory instructions |
| 22067 | + |
| 22068 | +@end table |
| 22069 | + |
| 22070 | @item AVR family---@file{config/avr/constraints.md} |
| 22071 | @table @code |
| 22072 | @item l |
| 22073 | --- a/gcc/expmed.c |
| 22074 | +++ b/gcc/expmed.c |
| 22075 | @@ -472,9 +472,9 @@ store_bit_field_1 (rtx str_rtx, unsigned |
| 22076 | ? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD |
| 22077 | || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)) |
| 22078 | && byte_offset % GET_MODE_SIZE (fieldmode) == 0) |
| 22079 | - : (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0)) |
| 22080 | + : ( (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0)) |
| 22081 | || (offset * BITS_PER_UNIT % bitsize == 0 |
| 22082 | - && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0)))) |
| 22083 | + && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))) |
| 22084 | { |
| 22085 | if (MEM_P (op0)) |
| 22086 | op0 = adjust_address (op0, fieldmode, offset); |
| 22087 | --- a/gcc/expr.c |
| 22088 | +++ b/gcc/expr.c |
| 22089 | @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. |
| 22090 | #include "tree-flow.h" |
| 22091 | #include "target.h" |
| 22092 | #include "timevar.h" |
| 22093 | +#include "c-common.h" |
| 22094 | #include "df.h" |
| 22095 | #include "diagnostic.h" |
| 22096 | |
| 22097 | @@ -3647,16 +3648,17 @@ emit_single_push_insn (enum machine_mode |
| 22098 | } |
| 22099 | else |
| 22100 | { |
| 22101 | + emit_move_insn (stack_pointer_rtx, |
| 22102 | + expand_binop (Pmode, |
| 22103 | #ifdef STACK_GROWS_DOWNWARD |
| 22104 | - /* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC. */ |
| 22105 | - dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, |
| 22106 | - GEN_INT (-(HOST_WIDE_INT) rounded_size)); |
| 22107 | + sub_optab, |
| 22108 | #else |
| 22109 | - /* ??? This seems wrong if STACK_PUSH_CODE == POST_INC. */ |
| 22110 | - dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, |
| 22111 | - GEN_INT (rounded_size)); |
| 22112 | + add_optab, |
| 22113 | #endif |
| 22114 | - dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr); |
| 22115 | + stack_pointer_rtx, |
| 22116 | + GEN_INT (rounded_size), |
| 22117 | + NULL_RTX, 0, OPTAB_LIB_WIDEN)); |
| 22118 | + dest_addr = stack_pointer_rtx; |
| 22119 | } |
| 22120 | |
| 22121 | dest = gen_rtx_MEM (mode, dest_addr); |
| 22122 | @@ -5775,7 +5777,8 @@ store_field (rtx target, HOST_WIDE_INT b |
| 22123 | is a bit field, we cannot use addressing to access it. |
| 22124 | Use bit-field techniques or SUBREG to store in it. */ |
| 22125 | |
| 22126 | - if (mode == VOIDmode |
| 22127 | + if ( |
| 22128 | + mode == VOIDmode |
| 22129 | || (mode != BLKmode && ! direct_store[(int) mode] |
| 22130 | && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT |
| 22131 | && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) |
| 22132 | @@ -5932,7 +5935,18 @@ get_inner_reference (tree exp, HOST_WIDE |
| 22133 | { |
| 22134 | tree field = TREE_OPERAND (exp, 1); |
| 22135 | size_tree = DECL_SIZE (field); |
| 22136 | - if (!DECL_BIT_FIELD (field)) |
| 22137 | + if (!DECL_BIT_FIELD (field) |
| 22138 | + /* Added for AVR32: |
| 22139 | + Bitfields with a size equal to a target storage |
| 22140 | + type might not cause DECL_BIT_FIELD to return |
| 22141 | + true since it can be optimized into a normal array |
| 22142 | + access operation. But for volatile bitfields we do |
| 22143 | + not allow this when targetm.narrow_volatile_bitfield () |
| 22144 | + is false. We can use DECL_C_BIT_FIELD to check if this |
| 22145 | + really is a c-bitfield. */ |
| 22146 | + && !(TREE_THIS_VOLATILE (exp) |
| 22147 | + && !targetm.narrow_volatile_bitfield () |
| 22148 | + && DECL_C_BIT_FIELD (field)) ) |
| 22149 | mode = DECL_MODE (field); |
| 22150 | else if (DECL_MODE (field) == BLKmode) |
| 22151 | blkmode_bitfield = true; |
| 22152 | @@ -7915,7 +7929,8 @@ expand_expr_real_1 (tree exp, rtx target |
| 22153 | by doing the extract into an object as wide as the field |
| 22154 | (which we know to be the width of a basic mode), then |
| 22155 | storing into memory, and changing the mode to BLKmode. */ |
| 22156 | - if (mode1 == VOIDmode |
| 22157 | + if ( |
| 22158 | + mode1 == VOIDmode |
| 22159 | || REG_P (op0) || GET_CODE (op0) == SUBREG |
| 22160 | || (mode1 != BLKmode && ! direct_load[(int) mode1] |
| 22161 | && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT |
| 22162 | --- a/gcc/function.c |
| 22163 | +++ b/gcc/function.c |
| 22164 | @@ -2810,7 +2810,11 @@ assign_parm_setup_reg (struct assign_par |
| 22165 | assign_parm_remove_parallels (data); |
| 22166 | |
| 22167 | /* Copy the value into the register. */ |
| 22168 | - if (data->nominal_mode != data->passed_mode |
| 22169 | + if ( (data->nominal_mode != data->passed_mode |
| 22170 | + /* Added for AVR32: If passed_mode is equal |
| 22171 | + to promoted nominal mode why should be convert? |
| 22172 | + The conversion should make no difference. */ |
| 22173 | + && data->passed_mode != promoted_nominal_mode) |
| 22174 | || promoted_nominal_mode != data->promoted_mode) |
| 22175 | { |
| 22176 | int save_tree_used; |
| 22177 | --- a/gcc/genemit.c |
| 22178 | +++ b/gcc/genemit.c |
| 22179 | @@ -121,6 +121,24 @@ max_operand_vec (rtx insn, int arg) |
| 22180 | } |
| 22181 | |
| 22182 | static void |
| 22183 | +gen_vararg_prologue(int operands) |
| 22184 | +{ |
| 22185 | + int i; |
| 22186 | + |
| 22187 | + if (operands > 1) |
| 22188 | + { |
| 22189 | + for (i = 1; i < operands; i++) |
| 22190 | + printf(" rtx operand%d ATTRIBUTE_UNUSED;\n", i); |
| 22191 | + |
| 22192 | + printf(" va_list args;\n\n"); |
| 22193 | + printf(" va_start(args, operand0);\n"); |
| 22194 | + for (i = 1; i < operands; i++) |
| 22195 | + printf(" operand%d = va_arg(args, rtx);\n", i); |
| 22196 | + printf(" va_end(args);\n\n"); |
| 22197 | + } |
| 22198 | +} |
| 22199 | + |
| 22200 | +static void |
| 22201 | print_code (RTX_CODE code) |
| 22202 | { |
| 22203 | const char *p1; |
| 22204 | @@ -406,18 +424,16 @@ gen_insn (rtx insn, int lineno) |
| 22205 | fatal ("match_dup operand number has no match_operand"); |
| 22206 | |
| 22207 | /* Output the function name and argument declarations. */ |
| 22208 | - printf ("rtx\ngen_%s (", XSTR (insn, 0)); |
| 22209 | + printf ("rtx\ngen_%s ", XSTR (insn, 0)); |
| 22210 | + |
| 22211 | if (operands) |
| 22212 | - for (i = 0; i < operands; i++) |
| 22213 | - if (i) |
| 22214 | - printf (",\n\trtx operand%d ATTRIBUTE_UNUSED", i); |
| 22215 | + printf("(rtx operand0 ATTRIBUTE_UNUSED, ...)\n"); |
| 22216 | else |
| 22217 | - printf ("rtx operand%d ATTRIBUTE_UNUSED", i); |
| 22218 | - else |
| 22219 | - printf ("void"); |
| 22220 | - printf (")\n"); |
| 22221 | + printf("(void)\n"); |
| 22222 | printf ("{\n"); |
| 22223 | |
| 22224 | + gen_vararg_prologue(operands); |
| 22225 | + |
| 22226 | /* Output code to construct and return the rtl for the instruction body. */ |
| 22227 | |
| 22228 | if (XVECLEN (insn, 1) == 1) |
| 22229 | @@ -461,16 +477,12 @@ gen_expand (rtx expand) |
| 22230 | operands = max_operand_vec (expand, 1); |
| 22231 | |
| 22232 | /* Output the function name and argument declarations. */ |
| 22233 | - printf ("rtx\ngen_%s (", XSTR (expand, 0)); |
| 22234 | + printf ("rtx\ngen_%s ", XSTR (expand, 0)); |
| 22235 | if (operands) |
| 22236 | - for (i = 0; i < operands; i++) |
| 22237 | - if (i) |
| 22238 | - printf (",\n\trtx operand%d", i); |
| 22239 | - else |
| 22240 | - printf ("rtx operand%d", i); |
| 22241 | + printf("(rtx operand0 ATTRIBUTE_UNUSED, ...)\n"); |
| 22242 | else |
| 22243 | - printf ("void"); |
| 22244 | - printf (")\n"); |
| 22245 | + printf("(void)\n"); |
| 22246 | + |
| 22247 | printf ("{\n"); |
| 22248 | |
| 22249 | /* If we don't have any C code to write, only one insn is being written, |
| 22250 | @@ -480,6 +492,8 @@ gen_expand (rtx expand) |
| 22251 | && operands > max_dup_opno |
| 22252 | && XVECLEN (expand, 1) == 1) |
| 22253 | { |
| 22254 | + gen_vararg_prologue(operands); |
| 22255 | + |
| 22256 | printf (" return "); |
| 22257 | gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL); |
| 22258 | printf (";\n}\n\n"); |
| 22259 | @@ -493,6 +507,7 @@ gen_expand (rtx expand) |
| 22260 | for (; i <= max_scratch_opno; i++) |
| 22261 | printf (" rtx operand%d ATTRIBUTE_UNUSED;\n", i); |
| 22262 | printf (" rtx _val = 0;\n"); |
| 22263 | + gen_vararg_prologue(operands); |
| 22264 | printf (" start_sequence ();\n"); |
| 22265 | |
| 22266 | /* The fourth operand of DEFINE_EXPAND is some code to be executed |
| 22267 | --- a/gcc/genflags.c |
| 22268 | +++ b/gcc/genflags.c |
| 22269 | @@ -127,7 +127,6 @@ static void |
| 22270 | gen_proto (rtx insn) |
| 22271 | { |
| 22272 | int num = num_operands (insn); |
| 22273 | - int i; |
| 22274 | const char *name = XSTR (insn, 0); |
| 22275 | int truth = maybe_eval_c_test (XSTR (insn, 2)); |
| 22276 | |
| 22277 | @@ -158,12 +157,7 @@ gen_proto (rtx insn) |
| 22278 | if (num == 0) |
| 22279 | fputs ("void", stdout); |
| 22280 | else |
| 22281 | - { |
| 22282 | - for (i = 1; i < num; i++) |
| 22283 | - fputs ("rtx, ", stdout); |
| 22284 | - |
| 22285 | - fputs ("rtx", stdout); |
| 22286 | - } |
| 22287 | + fputs("rtx, ...", stdout); |
| 22288 | |
| 22289 | puts (");"); |
| 22290 | |
| 22291 | @@ -173,12 +167,7 @@ gen_proto (rtx insn) |
| 22292 | { |
| 22293 | printf ("static inline rtx\ngen_%s", name); |
| 22294 | if (num > 0) |
| 22295 | - { |
| 22296 | - putchar ('('); |
| 22297 | - for (i = 0; i < num-1; i++) |
| 22298 | - printf ("rtx ARG_UNUSED (%c), ", 'a' + i); |
| 22299 | - printf ("rtx ARG_UNUSED (%c))\n", 'a' + i); |
| 22300 | - } |
| 22301 | + puts("(rtx ARG_UNUSED(a), ...)"); |
| 22302 | else |
| 22303 | puts ("(void)"); |
| 22304 | puts ("{\n return 0;\n}"); |
| 22305 | --- a/gcc/genoutput.c |
| 22306 | +++ b/gcc/genoutput.c |
| 22307 | @@ -386,7 +386,7 @@ output_insn_data (void) |
| 22308 | } |
| 22309 | |
| 22310 | if (d->name && d->name[0] != '*') |
| 22311 | - printf (" (insn_gen_fn) gen_%s,\n", d->name); |
| 22312 | + printf (" gen_%s,\n", d->name); |
| 22313 | else |
| 22314 | printf (" 0,\n"); |
| 22315 | |
| 22316 | --- a/gcc/ifcvt.c |
| 22317 | +++ b/gcc/ifcvt.c |
| 22318 | @@ -84,7 +84,7 @@ static int num_possible_if_blocks; |
| 22319 | static int num_updated_if_blocks; |
| 22320 | |
| 22321 | /* # of changes made. */ |
| 22322 | -static int num_true_changes; |
| 22323 | +int num_true_changes; |
| 22324 | |
| 22325 | /* Whether conditional execution changes were made. */ |
| 22326 | static int cond_exec_changed_p; |
| 22327 | @@ -290,6 +290,9 @@ cond_exec_process_insns (ce_if_block_t * |
| 22328 | if (must_be_last) |
| 22329 | return FALSE; |
| 22330 | |
| 22331 | +#ifdef IFCVT_ALLOW_MODIFY_TEST_IN_INSN |
| 22332 | + if ( !IFCVT_ALLOW_MODIFY_TEST_IN_INSN ) |
| 22333 | +#endif |
| 22334 | if (modified_in_p (test, insn)) |
| 22335 | { |
| 22336 | if (!mod_ok) |
| 22337 | @@ -570,15 +573,18 @@ cond_exec_process_if_block (ce_if_block_ |
| 22338 | IFCVT_MODIFY_FINAL (ce_info); |
| 22339 | #endif |
| 22340 | |
| 22341 | + /* Merge the blocks! */ |
| 22342 | + if ( reload_completed ){ |
| 22343 | /* Conversion succeeded. */ |
| 22344 | if (dump_file) |
| 22345 | fprintf (dump_file, "%d insn%s converted to conditional execution.\n", |
| 22346 | n_insns, (n_insns == 1) ? " was" : "s were"); |
| 22347 | |
| 22348 | - /* Merge the blocks! */ |
| 22349 | merge_if_block (ce_info); |
| 22350 | cond_exec_changed_p = TRUE; |
| 22351 | return TRUE; |
| 22352 | + } |
| 22353 | + return FALSE; |
| 22354 | |
| 22355 | fail: |
| 22356 | #ifdef IFCVT_MODIFY_CANCEL |
| 22357 | @@ -1087,7 +1093,11 @@ noce_try_addcc (struct noce_if_info *if_ |
| 22358 | != UNKNOWN)) |
| 22359 | { |
| 22360 | rtx cond = if_info->cond; |
| 22361 | - enum rtx_code code = reversed_comparison_code (cond, if_info->jump); |
| 22362 | + /* This generates wrong code for AVR32. The cond code need not be reversed |
| 22363 | + since the addmodecc patterns add if the condition is NOT met. */ |
| 22364 | + /* enum rtx_code code = reversed_comparison_code (cond, if_info->jump);*/ |
| 22365 | + enum rtx_code code = GET_CODE(cond); |
| 22366 | + |
| 22367 | |
| 22368 | /* First try to use addcc pattern. */ |
| 22369 | if (general_operand (XEXP (cond, 0), VOIDmode) |
| 22370 | @@ -3039,7 +3049,12 @@ find_if_header (basic_block test_bb, int |
| 22371 | && noce_find_if_block (test_bb, then_edge, else_edge, pass)) |
| 22372 | goto success; |
| 22373 | |
| 22374 | - if (HAVE_conditional_execution && reload_completed |
| 22375 | + if (HAVE_conditional_execution && |
| 22376 | +#ifdef IFCVT_COND_EXEC_BEFORE_RELOAD |
| 22377 | + (reload_completed || IFCVT_COND_EXEC_BEFORE_RELOAD) |
| 22378 | +#else |
| 22379 | + reload_completed |
| 22380 | +#endif |
| 22381 | && cond_exec_find_if_block (&ce_info)) |
| 22382 | goto success; |
| 22383 | |
| 22384 | @@ -3154,7 +3169,11 @@ cond_exec_find_if_block (struct ce_if_bl |
| 22385 | |
| 22386 | /* We only ever should get here after reload, |
| 22387 | and only if we have conditional execution. */ |
| 22388 | +#ifdef IFCVT_COND_EXEC_BEFORE_RELOAD |
| 22389 | + gcc_assert (HAVE_conditional_execution && (reload_completed||IFCVT_COND_EXEC_BEFORE_RELOAD)); |
| 22390 | +#else |
| 22391 | gcc_assert (HAVE_conditional_execution && reload_completed); |
| 22392 | +#endif |
| 22393 | |
| 22394 | /* Discover if any fall through predecessors of the current test basic block |
| 22395 | were && tests (which jump to the else block) or || tests (which jump to |
| 22396 | @@ -4259,6 +4278,14 @@ gate_handle_if_after_reload (void) |
| 22397 | static unsigned int |
| 22398 | rest_of_handle_if_after_reload (void) |
| 22399 | { |
| 22400 | + /* Hack for the AVR32 experimental ifcvt processing before reload. |
| 22401 | + The AVR32 specific ifcvt code needs to know when ifcvt after reload |
| 22402 | + has begun. */ |
| 22403 | +#ifdef IFCVT_COND_EXEC_BEFORE_RELOAD |
| 22404 | + if ( IFCVT_COND_EXEC_BEFORE_RELOAD ) |
| 22405 | + cfun->machine->ifcvt_after_reload = 1; |
| 22406 | +#endif |
| 22407 | + |
| 22408 | if_convert (); |
| 22409 | return 0; |
| 22410 | } |
| 22411 | --- a/gcc/longlong.h |
| 22412 | +++ b/gcc/longlong.h |
| 22413 | @@ -250,6 +250,41 @@ UDItype __umulsidi3 (USItype, USItype); |
| 22414 | #define COUNT_LEADING_ZEROS_0 32 |
| 22415 | #endif |
| 22416 | |
| 22417 | +#if defined (__avr32__) && W_TYPE_SIZE == 32 |
| 22418 | +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ |
| 22419 | + __asm__ ("add\t%1, %4, %5\n\tadc\t%0, %2, %3" \ |
| 22420 | + : "=r" ((USItype) (sh)), \ |
| 22421 | + "=&r" ((USItype) (sl)) \ |
| 22422 | + : "r" ((USItype) (ah)), \ |
| 22423 | + "r" ((USItype) (bh)), \ |
| 22424 | + "r" ((USItype) (al)), \ |
| 22425 | + "r" ((USItype) (bl)) __CLOBBER_CC) |
| 22426 | +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ |
| 22427 | + __asm__ ("sub\t%1, %4, %5\n\tsbc\t%0, %2, %3" \ |
| 22428 | + : "=r" ((USItype) (sh)), \ |
| 22429 | + "=&r" ((USItype) (sl)) \ |
| 22430 | + : "r" ((USItype) (ah)), \ |
| 22431 | + "r" ((USItype) (bh)), \ |
| 22432 | + "r" ((USItype) (al)), \ |
| 22433 | + "r" ((USItype) (bl)) __CLOBBER_CC) |
| 22434 | + |
| 22435 | +#if !defined (__AVR32_NO_MUL__) |
| 22436 | +#define __umulsidi3(a,b) ((UDItype)(a) * (UDItype)(b)) |
| 22437 | + |
| 22438 | +#define umul_ppmm(w1, w0, u, v) \ |
| 22439 | +{ \ |
| 22440 | + DWunion __w; \ |
| 22441 | + __w.ll = __umulsidi3 (u, v); \ |
| 22442 | + w1 = __w.s.high; \ |
| 22443 | + w0 = __w.s.low; \ |
| 22444 | +} |
| 22445 | +#endif |
| 22446 | + |
| 22447 | +#define count_leading_zeros(COUNT,X) ((COUNT) = __builtin_clz (X)) |
| 22448 | +#define count_trailing_zeros(COUNT,X) ((COUNT) = __builtin_ctz (X)) |
| 22449 | +#define COUNT_LEADING_ZEROS_0 32 |
| 22450 | +#endif |
| 22451 | + |
| 22452 | #if defined (__CRIS__) && __CRIS_arch_version >= 3 |
| 22453 | #define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X)) |
| 22454 | #if __CRIS_arch_version >= 8 |
| 22455 | --- a/gcc/optabs.h |
| 22456 | +++ b/gcc/optabs.h |
| 22457 | @@ -603,7 +603,7 @@ extern enum insn_code reload_out_optab[N |
| 22458 | extern optab code_to_optab[NUM_RTX_CODE + 1]; |
| 22459 | |
| 22460 | |
| 22461 | -typedef rtx (*rtxfun) (rtx); |
| 22462 | +typedef rtx (*rtxfun) (rtx, ...); |
| 22463 | |
| 22464 | /* Indexed by the rtx-code for a conditional (e.g. EQ, LT,...) |
| 22465 | gives the gen_function to make a branch to test that condition. */ |
| 22466 | --- a/gcc/regrename.c |
| 22467 | +++ b/gcc/regrename.c |
| 22468 | @@ -1582,6 +1582,9 @@ copyprop_hardreg_forward_1 (basic_block |
| 22469 | bool changed = false; |
| 22470 | rtx insn; |
| 22471 | |
| 22472 | + rtx prev_pred_test; |
| 22473 | + int prev_pred_insn_skipped = 0; |
| 22474 | + |
| 22475 | for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) |
| 22476 | { |
| 22477 | int n_ops, i, alt, predicated; |
| 22478 | @@ -1621,6 +1624,58 @@ copyprop_hardreg_forward_1 (basic_block |
| 22479 | recog_data.operand_type[i] = OP_INOUT; |
| 22480 | } |
| 22481 | |
| 22482 | + |
| 22483 | + /* Added for targets (AVR32) which supports test operands to be modified |
| 22484 | + in cond_exec instruction. For these targets we cannot make a change to |
| 22485 | + the test operands if one of the test operands is an output operand This beacuse |
| 22486 | + changing the test operands might cause the need for inserting a new test |
| 22487 | + insns in the middle of a sequence of cond_exec insns and if the test operands |
| 22488 | + are modified these tests will fail. |
| 22489 | + */ |
| 22490 | + if ( IFCVT_ALLOW_MODIFY_TEST_IN_INSN |
| 22491 | + && predicated ) |
| 22492 | + { |
| 22493 | + int insn_skipped = 0; |
| 22494 | + rtx test = COND_EXEC_TEST (PATTERN (insn)); |
| 22495 | + |
| 22496 | + /* Check if the previous insn was a skipped predicated insn with the same |
| 22497 | + test as this predicated insns. If so we cannot do any modification to |
| 22498 | + this insn either since we cannot emit the test insn because the operands |
| 22499 | + are clobbered. */ |
| 22500 | + if ( prev_pred_insn_skipped |
| 22501 | + && (rtx_equal_p (test, prev_pred_test) |
| 22502 | + || rtx_equal_p (test, reversed_condition (prev_pred_test))) ) |
| 22503 | + { |
| 22504 | + insn_skipped = 1; |
| 22505 | + } |
| 22506 | + else |
| 22507 | + { |
| 22508 | + /* Check if the output operand is used in the test expression. */ |
| 22509 | + for (i = 0; i < n_ops; ++i) |
| 22510 | + if ( recog_data.operand_type[i] == OP_INOUT |
| 22511 | + && reg_mentioned_p (recog_data.operand[i], test) ) |
| 22512 | + { |
| 22513 | + insn_skipped = 1; |
| 22514 | + break; |
| 22515 | + } |
| 22516 | + |
| 22517 | + } |
| 22518 | + |
| 22519 | + prev_pred_test = test; |
| 22520 | + prev_pred_insn_skipped = insn_skipped; |
| 22521 | + if ( insn_skipped ) |
| 22522 | + { |
| 22523 | + if (insn == BB_END (bb)) |
| 22524 | + break; |
| 22525 | + else |
| 22526 | + continue; |
| 22527 | + } |
| 22528 | + } |
| 22529 | + else |
| 22530 | + { |
| 22531 | + prev_pred_insn_skipped = 0; |
| 22532 | + } |
| 22533 | + |
| 22534 | /* For each earlyclobber operand, zap the value data. */ |
| 22535 | for (i = 0; i < n_ops; i++) |
| 22536 | if (recog_op_alt[i][alt].earlyclobber) |
| 22537 | --- a/gcc/sched-deps.c |
| 22538 | +++ b/gcc/sched-deps.c |
| 22539 | @@ -1473,7 +1473,14 @@ fixup_sched_groups (rtx insn) |
| 22540 | |
| 22541 | prev_nonnote = prev_nonnote_insn (insn); |
| 22542 | if (BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (prev_nonnote) |
| 22543 | - && ! sched_insns_conditions_mutex_p (insn, prev_nonnote)) |
| 22544 | + /* Modification for AVR32 by RP: Why is this here, this will |
| 22545 | + cause instruction to be without any dependencies which might |
| 22546 | + cause it to be moved anywhere. For the AVR32 we try to keep |
| 22547 | + a group of conditionals together even if they are mutual exclusive. |
| 22548 | + */ |
| 22549 | + && (! sched_insns_conditions_mutex_p (insn, prev_nonnote) |
| 22550 | + || GET_CODE (PATTERN (insn)) == COND_EXEC ) |
| 22551 | + ) |
| 22552 | add_dependence (insn, prev_nonnote, REG_DEP_ANTI); |
| 22553 | } |
| 22554 | |
| 22555 | @@ -2230,8 +2237,29 @@ sched_analyze_insn (struct deps *deps, r |
| 22556 | |
| 22557 | if (code == COND_EXEC) |
| 22558 | { |
| 22559 | +#ifdef IFCVT_ALLOW_MODIFY_TEST_IN_INSN |
| 22560 | + if (IFCVT_ALLOW_MODIFY_TEST_IN_INSN) |
| 22561 | + { |
| 22562 | + /* Check if we have a group og conditional instructions with the same test. |
| 22563 | + If so we must make sure that they are not scheduled apart in order to |
| 22564 | + avoid unnecesarry tests and if one of the registers in the test is modified |
| 22565 | + in the instruction this is needed to ensure correct code. */ |
| 22566 | + if ( prev_nonnote_insn (insn) |
| 22567 | + && INSN_P (prev_nonnote_insn (insn)) |
| 22568 | + && GET_CODE (PATTERN (prev_nonnote_insn (insn))) == COND_EXEC |
| 22569 | + && rtx_equal_p (XEXP(COND_EXEC_TEST (PATTERN (prev_nonnote_insn (insn))), 0), XEXP (COND_EXEC_TEST (x), 0)) |
| 22570 | + && rtx_equal_p (XEXP(COND_EXEC_TEST (PATTERN (prev_nonnote_insn (insn))), 1), XEXP (COND_EXEC_TEST (x), 1)) |
| 22571 | + && ( GET_CODE (COND_EXEC_TEST (PATTERN (prev_nonnote_insn (insn)))) == GET_CODE (COND_EXEC_TEST (x)) |
| 22572 | + || GET_CODE (COND_EXEC_TEST (PATTERN (prev_nonnote_insn (insn)))) == reversed_comparison_code (COND_EXEC_TEST (x), insn))) |
| 22573 | + { |
| 22574 | + SCHED_GROUP_P (insn) = 1; |
| 22575 | + //CANT_MOVE (prev_nonnote_insn (insn)) = 1; |
| 22576 | + } |
| 22577 | + } |
| 22578 | +#endif |
| 22579 | sched_analyze_2 (deps, COND_EXEC_TEST (x), insn); |
| 22580 | |
| 22581 | + |
| 22582 | /* ??? Should be recording conditions so we reduce the number of |
| 22583 | false dependencies. */ |
| 22584 | x = COND_EXEC_CODE (x); |
| 22585 | --- a/gcc/testsuite/gcc.dg/sibcall-3.c |
| 22586 | +++ b/gcc/testsuite/gcc.dg/sibcall-3.c |
| 22587 | @@ -5,7 +5,7 @@ |
| 22588 | Copyright (C) 2002 Free Software Foundation Inc. |
| 22589 | Contributed by Hans-Peter Nilsson <hp@bitrange.com> */ |
| 22590 | |
| 22591 | -/* { dg-do run { xfail { { arc-*-* avr-*-* cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* m68hc1?-*-* mcore-*-* mn10300-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ |
| 22592 | +/* { dg-do run { xfail { { arc-*-* avr-*-* avr32-*-* cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* m68hc1?-*-* mcore-*-* mn10300-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ |
| 22593 | /* -mlongcall disables sibcall patterns. */ |
| 22594 | /* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */ |
| 22595 | /* { dg-options "-O2 -foptimize-sibling-calls" } */ |
| 22596 | --- a/gcc/testsuite/gcc.dg/sibcall-4.c |
| 22597 | +++ b/gcc/testsuite/gcc.dg/sibcall-4.c |
| 22598 | @@ -5,7 +5,7 @@ |
| 22599 | Copyright (C) 2002 Free Software Foundation Inc. |
| 22600 | Contributed by Hans-Peter Nilsson <hp@bitrange.com> */ |
| 22601 | |
| 22602 | -/* { dg-do run { xfail { { arc-*-* avr-*-* cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* m68hc1?-*-* mcore-*-* mn10300-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ |
| 22603 | +/* { dg-do run { xfail { { arc-*-* avr-*-* avr32-*-* cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* m68hc1?-*-* mcore-*-* mn10300-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ |
| 22604 | /* -mlongcall disables sibcall patterns. */ |
| 22605 | /* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */ |
| 22606 | /* { dg-options "-O2 -foptimize-sibling-calls" } */ |
| 22607 | --- a/gcc/testsuite/gcc.dg/trampoline-1.c |
| 22608 | +++ b/gcc/testsuite/gcc.dg/trampoline-1.c |
| 22609 | @@ -47,6 +47,8 @@ void foo (void) |
| 22610 | |
| 22611 | int main (void) |
| 22612 | { |
| 22613 | +#ifndef NO_TRAMPOLINES |
| 22614 | foo (); |
| 22615 | +#endif |
| 22616 | return 0; |
| 22617 | } |
| 22618 | --- a/libgcc/config.host |
| 22619 | +++ b/libgcc/config.host |
| 22620 | @@ -218,6 +218,13 @@ arm*-wince-pe*) |
| 22621 | ;; |
| 22622 | arm-*-pe*) |
| 22623 | ;; |
| 22624 | +avr32-*-linux*) |
| 22625 | + # No need to build crtbeginT.o on uClibc systems. Should probably be |
| 22626 | + # moved to the OS specific section above. |
| 22627 | + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" |
| 22628 | + ;; |
| 22629 | +avr32-*-*) |
| 22630 | + ;; |
| 22631 | avr-*-rtems*) |
| 22632 | ;; |
| 22633 | avr-*-*) |
| 22634 | --- a/libstdc++-v3/config/os/gnu-linux/ctype_base.h |
| 22635 | +++ b/libstdc++-v3/config/os/gnu-linux/ctype_base.h |
| 22636 | @@ -26,6 +26,8 @@ |
| 22637 | // |
| 22638 | // ISO C++ 14882: 22.1 Locales |
| 22639 | // |
| 22640 | +#include <features.h> |
| 22641 | +#include <ctype.h> |
| 22642 | |
| 22643 | /** @file ctype_base.h |
| 22644 | * This is an internal header file, included by other library headers. |
| 22645 | @@ -40,7 +42,11 @@ _GLIBCXX_BEGIN_NAMESPACE(std) |
| 22646 | struct ctype_base |
| 22647 | { |
| 22648 | // Non-standard typedefs. |
| 22649 | +#ifdef __UCLIBC__ |
| 22650 | + typedef const __ctype_touplow_t* __to_type; |
| 22651 | +#else |
| 22652 | typedef const int* __to_type; |
| 22653 | +#endif |
| 22654 | |
| 22655 | // NB: Offsets into ctype<char>::_M_table force a particular size |
| 22656 | // on the mask type. Because of this, we don't use an enum. |
| 22657 | --- a/libstdc++-v3/include/Makefile.in |
| 22658 | +++ b/libstdc++-v3/include/Makefile.in |
| 22659 | @@ -36,6 +36,7 @@ POST_UNINSTALL = : |
| 22660 | build_triplet = @build@ |
| 22661 | host_triplet = @host@ |
| 22662 | target_triplet = @target@ |
| 22663 | +LIBOBJDIR = |
| 22664 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ |
| 22665 | $(top_srcdir)/fragment.am |
| 22666 | subdir = include |
| 22667 | --- a/libstdc++-v3/libsupc++/Makefile.in |
| 22668 | +++ b/libstdc++-v3/libsupc++/Makefile.in |
| 22669 | @@ -38,6 +38,7 @@ POST_UNINSTALL = : |
| 22670 | build_triplet = @build@ |
| 22671 | host_triplet = @host@ |
| 22672 | target_triplet = @target@ |
| 22673 | +LIBOBJDIR = |
| 22674 | DIST_COMMON = $(glibcxxinstall_HEADERS) $(srcdir)/Makefile.am \ |
| 22675 | $(srcdir)/Makefile.in $(top_srcdir)/fragment.am |
| 22676 | subdir = libsupc++ |
| 22677 | --- a/libstdc++-v3/Makefile.in |
| 22678 | +++ b/libstdc++-v3/Makefile.in |
| 22679 | @@ -36,6 +36,7 @@ POST_UNINSTALL = : |
| 22680 | build_triplet = @build@ |
| 22681 | host_triplet = @host@ |
| 22682 | target_triplet = @target@ |
| 22683 | +LIBOBJDIR = |
| 22684 | DIST_COMMON = $(top_srcdir)/fragment.am $(srcdir)/../config.guess \ |
| 22685 | $(srcdir)/../config.sub README ChangeLog $(srcdir)/Makefile.in \ |
| 22686 | $(srcdir)/Makefile.am $(top_srcdir)/configure \ |
| 22687 | --- a/libstdc++-v3/po/Makefile.in |
| 22688 | +++ b/libstdc++-v3/po/Makefile.in |
| 22689 | @@ -36,6 +36,7 @@ POST_UNINSTALL = : |
| 22690 | build_triplet = @build@ |
| 22691 | host_triplet = @host@ |
| 22692 | target_triplet = @target@ |
| 22693 | +LIBOBJDIR = |
| 22694 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ |
| 22695 | $(top_srcdir)/fragment.am |
| 22696 | subdir = po |
| 22697 | --- a/libstdc++-v3/src/Makefile.in |
| 22698 | +++ b/libstdc++-v3/src/Makefile.in |
| 22699 | @@ -37,6 +37,7 @@ POST_UNINSTALL = : |
| 22700 | build_triplet = @build@ |
| 22701 | host_triplet = @host@ |
| 22702 | target_triplet = @target@ |
| 22703 | +LIBOBJDIR = |
| 22704 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ |
| 22705 | $(top_srcdir)/fragment.am |
| 22706 | subdir = src |
| 22707 | |