1/* Target Code for moxie 2 Copyright (C) 2008, 2009, 2010 Free Software Foundation 3 Contributed by Anthony Green. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published 9 by the Free Software Foundation; either version 3, or (at your 10 option) any later version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21#include "config.h" 22#include "system.h" 23#include "coretypes.h" 24#include "tm.h" 25#include "rtl.h" 26#include "regs.h" 27#include "hard-reg-set.h" 28#include "real.h" 29#include "insn-config.h" 30#include "conditions.h" 31#include "insn-flags.h" 32#include "output.h" 33#include "insn-attr.h" 34#include "flags.h" 35#include "recog.h" 36#include "reload.h" 37#include "toplev.h" 38#include "obstack.h" 39#include "tree.h" 40#include "expr.h" 41#include "optabs.h" 42#include "except.h" 43#include "function.h" 44#include "ggc.h" 45#include "target.h" 46#include "target-def.h" 47#include "tm_p.h" 48#include "langhooks.h" 49#include "df.h" 50 51#define LOSE_AND_RETURN(msgid, x) \ 52 do \ 53 { \ 54 moxie_operand_lossage (msgid, x); \ 55 return; \ 56 } while (0) 57 58/* Worker function for TARGET_RETURN_IN_MEMORY. */ 59 60static bool 61moxie_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) 62{ 63 const HOST_WIDE_INT size = int_size_in_bytes (type); 64 return (size == -1 || size > 2 * UNITS_PER_WORD); 65} 66 67/* Define how to find the value returned by a function. 68 VALTYPE is the data type of the value (as a tree). 69 If the precise function being called is known, FUNC is its 70 FUNCTION_DECL; otherwise, FUNC is 0. 71 72 We always return values in register $r0 for moxie. */ 73 74rtx 75moxie_function_value (const_tree valtype, 76 const_tree fntype_or_decl ATTRIBUTE_UNUSED, 77 bool outgoing ATTRIBUTE_UNUSED) 78{ 79 return gen_rtx_REG (TYPE_MODE (valtype), MOXIE_R0); 80} 81 82/* Emit an error message when we're in an asm, and a fatal error for 83 "normal" insns. Formatted output isn't easily implemented, since we 84 use output_operand_lossage to output the actual message and handle the 85 categorization of the error. */ 86 87static void 88moxie_operand_lossage (const char *msgid, rtx op) 89{ 90 debug_rtx (op); 91 output_operand_lossage ("%s", msgid); 92} 93 94/* The PRINT_OPERAND_ADDRESS worker. */ 95 96void 97moxie_print_operand_address (FILE *file, rtx x) 98{ 99 switch (GET_CODE (x)) 100 { 101 case REG: 102 fprintf (file, "(%s)", reg_names[REGNO (x)]); 103 break; 104 105 case PLUS: 106 switch (GET_CODE (XEXP (x, 1))) 107 { 108 case CONST_INT: 109 fprintf (file, "%ld(%s)", 110 INTVAL(XEXP (x, 1)), reg_names[REGNO (XEXP (x, 0))]); 111 break; 112 case SYMBOL_REF: 113 output_addr_const (file, XEXP (x, 1)); 114 fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]); 115 break; 116 case CONST: 117 { 118 rtx plus = XEXP (XEXP (x, 1), 0); 119 if (GET_CODE (XEXP (plus, 0)) == SYMBOL_REF 120 && CONST_INT_P (XEXP (plus, 1))) 121 { 122 output_addr_const(file, XEXP (plus, 0)); 123 fprintf (file,"+%ld(%s)", INTVAL (XEXP (plus, 1)), 124 reg_names[REGNO (XEXP (x, 0))]); 125 } 126 else 127 abort(); 128 } 129 break; 130 default: 131 abort(); 132 } 133 break; 134 135 default: 136 output_addr_const (file, x); 137 break; 138 } 139} 140 141/* The PRINT_OPERAND worker. */ 142 143void 144moxie_print_operand (FILE *file, rtx x, int code) 145{ 146 rtx operand = x; 147 148 /* New code entries should just be added to the switch below. If 149 handling is finished, just return. If handling was just a 150 modification of the operand, the modified operand should be put in 151 "operand", and then do a break to let default handling 152 (zero-modifier) output the operand. */ 153 154 switch (code) 155 { 156 case 0: 157 /* No code, print as usual. */ 158 break; 159 160 default: 161 LOSE_AND_RETURN ("invalid operand modifier letter", x); 162 } 163 164 /* Print an operand as without a modifier letter. */ 165 switch (GET_CODE (operand)) 166 { 167 case REG: 168 if (REGNO (operand) > MOXIE_R13) 169 internal_error ("internal error: bad register: %d", REGNO (operand)); 170 fprintf (file, "%s", reg_names[REGNO (operand)]); 171 return; 172 173 case MEM: 174 output_address (XEXP (operand, 0)); 175 return; 176 177 default: 178 /* No need to handle all strange variants, let output_addr_const 179 do it for us. */ 180 if (CONSTANT_P (operand)) 181 { 182 output_addr_const (file, operand); 183 return; 184 } 185 186 LOSE_AND_RETURN ("unexpected operand", x); 187 } 188} 189 190/* Per-function machine data. */ 191struct GTY(()) machine_function 192 { 193 /* Number of bytes saved on the stack for callee saved registers. */ 194 int callee_saved_reg_size; 195 196 /* Number of bytes saved on the stack for local variables. */ 197 int local_vars_size; 198 199 /* The sum of 2 sizes: locals vars and padding byte for saving the 200 * registers. Used in expand_prologue () and expand_epilogue(). */ 201 int size_for_adjusting_sp; 202 }; 203 204/* Zero initialization is OK for all current fields. */ 205 206static struct machine_function * 207moxie_init_machine_status (void) 208{ 209 return GGC_CNEW (struct machine_function); 210} 211 212 213/* The OVERRIDE_OPTIONS worker. 214 All this curently does is set init_machine_status. */ 215void 216moxie_override_options (void) 217{ 218 /* Set the per-function-data initializer. */ 219 init_machine_status = moxie_init_machine_status; 220} 221 222/* Compute the size of the local area and the size to be adjusted by the 223 * prologue and epilogue. */ 224 225static void 226moxie_compute_frame (void) 227{ 228 /* For aligning the local variables. */ 229 int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT; 230 int padding_locals; 231 int regno; 232 233 /* Padding needed for each element of the frame. */ 234 cfun->machine->local_vars_size = get_frame_size (); 235 236 /* Align to the stack alignment. */ 237 padding_locals = cfun->machine->local_vars_size % stack_alignment; 238 if (padding_locals) 239 padding_locals = stack_alignment - padding_locals; 240 241 cfun->machine->local_vars_size += padding_locals; 242 243 cfun->machine->callee_saved_reg_size = 0; 244 245 /* Save callee-saved registers. */ 246 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 247 if (df_regs_ever_live_p (regno) && (! call_used_regs[regno])) 248 cfun->machine->callee_saved_reg_size += 4; 249 250 cfun->machine->size_for_adjusting_sp = 251 crtl->args.pretend_args_size 252 + cfun->machine->local_vars_size 253 + (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0); 254} 255 256void 257moxie_expand_prologue (void) 258{ 259 int regno; 260 rtx insn; 261 262 moxie_compute_frame (); 263 264 /* Save callee-saved registers. */ 265 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 266 { 267 if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno]) 268 { 269 insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno))); 270 RTX_FRAME_RELATED_P (insn) = 1; 271 } 272 } 273 274 if (cfun->machine->size_for_adjusting_sp > 0) 275 { 276 int i = cfun->machine->size_for_adjusting_sp; 277 while (i > 255) 278 { 279 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, 280 stack_pointer_rtx, 281 GEN_INT (255))); 282 RTX_FRAME_RELATED_P (insn) = 1; 283 i -= 255; 284 } 285 if (i > 0) 286 { 287 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, 288 stack_pointer_rtx, 289 GEN_INT (i))); 290 RTX_FRAME_RELATED_P (insn) = 1; 291 } 292 } 293} 294 295void 296moxie_expand_epilogue (void) 297{ 298 int regno; 299 rtx insn, reg, cfa_restores = NULL; 300 301 if (cfun->machine->callee_saved_reg_size != 0) 302 { 303 reg = gen_rtx_REG (Pmode, MOXIE_R5); 304 if (cfun->machine->callee_saved_reg_size <= 255) 305 { 306 emit_move_insn (reg, hard_frame_pointer_rtx); 307 emit_insn (gen_subsi3 308 (reg, reg, 309 GEN_INT (cfun->machine->callee_saved_reg_size))); 310 } 311 else 312 { 313 emit_move_insn (reg, 314 GEN_INT (-cfun->machine->callee_saved_reg_size)); 315 emit_insn (gen_addsi3 (reg, reg, hard_frame_pointer_rtx)); 316 } 317 for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; ) 318 if (!fixed_regs[regno] && !call_used_regs[regno] 319 && df_regs_ever_live_p (regno)) 320 { 321 rtx preg = gen_rtx_REG (Pmode, regno); 322 insn = emit_insn (gen_movsi_pop (reg, preg)); 323 } 324 } 325 326 emit_jump_insn (gen_returner ()); 327} 328 329/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */ 330 331int 332moxie_initial_elimination_offset (int from, int to) 333{ 334 int ret; 335 336 if ((from) == FRAME_POINTER_REGNUM && (to) == HARD_FRAME_POINTER_REGNUM) 337 { 338 /* Compute this since we need to use cfun->machine->local_vars_size. */ 339 moxie_compute_frame (); 340 ret = -cfun->machine->callee_saved_reg_size; 341 } 342 else if ((from) == ARG_POINTER_REGNUM && (to) == HARD_FRAME_POINTER_REGNUM) 343 ret = 0x00; 344 else 345 abort (); 346 347 return ret; 348} 349 350/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */ 351 352static void 353moxie_setup_incoming_varargs (CUMULATIVE_ARGS *cum, 354 enum machine_mode mode ATTRIBUTE_UNUSED, 355 tree type ATTRIBUTE_UNUSED, 356 int *pretend_size, int no_rtl) 357{ 358 int regno; 359 int regs = 8 - *cum; 360 361 *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs; 362 363 if (no_rtl) 364 return; 365 366 for (regno = *cum; regno < 8; regno++) 367 { 368 rtx reg = gen_rtx_REG (SImode, regno); 369 rtx slot = gen_rtx_PLUS (Pmode, 370 gen_rtx_REG (SImode, ARG_POINTER_REGNUM), 371 GEN_INT (UNITS_PER_WORD * (3 + (regno-2)))); 372 373 emit_move_insn (gen_rtx_MEM (SImode, slot), reg); 374 } 375} 376 377 378/* Return the fixed registers used for condition codes. */ 379 380static bool 381moxie_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) 382{ 383 *p1 = CC_REG; 384 *p2 = INVALID_REGNUM; 385 return true; 386} 387 388/* Return the next register to be used to hold a function argument or 389 NULL_RTX if there's no more space. */ 390 391rtx 392moxie_function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, 393 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) 394{ 395 if (cum < 8) 396 return gen_rtx_REG (mode, cum); 397 else 398 return NULL_RTX; 399} 400 401/* Return non-zero if the function argument described by TYPE is to be 402 passed by reference. */ 403 404static bool 405moxie_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, 406 enum machine_mode mode, const_tree type, 407 bool named ATTRIBUTE_UNUSED) 408{ 409 unsigned HOST_WIDE_INT size; 410 411 if (type) 412 { 413 if (AGGREGATE_TYPE_P (type)) 414 return true; 415 size = int_size_in_bytes (type); 416 } 417 else 418 size = GET_MODE_SIZE (mode); 419 420 return size > 4*6; 421} 422 423/* Some function arguments will only partially fit in the registers 424 that hold arguments. Given a new arg, return the number of bytes 425 that fit in argument passing registers. */ 426 427static int 428moxie_arg_partial_bytes (CUMULATIVE_ARGS *cum, 429 enum machine_mode mode, 430 tree type, bool named) 431{ 432 int bytes_left, size; 433 434 if (*cum >= 8) 435 return 0; 436 437 if (moxie_pass_by_reference (cum, mode, type, named)) 438 size = 4; 439 else if (type) 440 { 441 if (AGGREGATE_TYPE_P (type)) 442 return 0; 443 size = int_size_in_bytes (type); 444 } 445 else 446 size = GET_MODE_SIZE (mode); 447 448 bytes_left = (4 * 6) - ((*cum - 2) * 4); 449 450 if (size > bytes_left) 451 return bytes_left; 452 else 453 return 0; 454} 455 456/* Worker function for TARGET_STATIC_CHAIN. */ 457 458static rtx 459moxie_static_chain (const_tree fndecl, bool incoming_p) 460{ 461 rtx addr, mem; 462 463 if (!DECL_STATIC_CHAIN (fndecl)) 464 return NULL; 465 466 if (incoming_p) 467 addr = plus_constant (arg_pointer_rtx, 2 * UNITS_PER_WORD); 468 else 469 addr = plus_constant (stack_pointer_rtx, -UNITS_PER_WORD); 470 471 mem = gen_rtx_MEM (Pmode, addr); 472 MEM_NOTRAP_P (mem) = 1; 473 474 return mem; 475} 476 477/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 478 479static void 480moxie_asm_trampoline_template (FILE *f) 481{ 482 fprintf (f, "\tpush $sp, $r0\n"); 483 fprintf (f, "\tldi.l $r0, 0x0\n"); 484 fprintf (f, "\tsto.l 0x8($fp), $r0\n"); 485 fprintf (f, "\tpop $sp, $r0\n"); 486 fprintf (f, "\tnop\n"); 487 fprintf (f, "\tjmpa 0x0\n"); 488} 489 490/* Worker function for TARGET_TRAMPOLINE_INIT. */ 491 492static void 493moxie_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) 494{ 495 rtx mem, fnaddr = XEXP (DECL_RTL (fndecl), 0); 496 497 emit_block_move (m_tramp, assemble_trampoline_template (), 498 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); 499 500 mem = adjust_address (m_tramp, SImode, 4); 501 emit_move_insn (mem, chain_value); 502 mem = adjust_address (m_tramp, SImode, 20); 503 emit_move_insn (mem, fnaddr); 504} 505 506/* The Global `targetm' Variable. */ 507 508/* Initialize the GCC target structure. */ 509 510#undef TARGET_PROMOTE_PROTOTYPES 511#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true 512 513#undef TARGET_RETURN_IN_MEMORY 514#define TARGET_RETURN_IN_MEMORY moxie_return_in_memory 515#undef TARGET_MUST_PASS_IN_STACK 516#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size 517#undef TARGET_PASS_BY_REFERENCE 518#define TARGET_PASS_BY_REFERENCE moxie_pass_by_reference 519#undef TARGET_ARG_PARTIAL_BYTES 520#define TARGET_ARG_PARTIAL_BYTES moxie_arg_partial_bytes 521 522 523#undef TARGET_SETUP_INCOMING_VARARGS 524#define TARGET_SETUP_INCOMING_VARARGS moxie_setup_incoming_varargs 525 526#undef TARGET_FIXED_CONDITION_CODE_REGS 527#define TARGET_FIXED_CONDITION_CODE_REGS moxie_fixed_condition_code_regs 528 529/* Define this to return an RTX representing the place where a 530 function returns or receives a value of data type RET_TYPE, a tree 531 node node representing a data type. */ 532#undef TARGET_FUNCTION_VALUE 533#define TARGET_FUNCTION_VALUE moxie_function_value 534 535#undef TARGET_FRAME_POINTER_REQUIRED 536#define TARGET_FRAME_POINTER_REQUIRED hook_bool_void_true 537 538#undef TARGET_STATIC_CHAIN 539#define TARGET_STATIC_CHAIN moxie_static_chain 540#undef TARGET_ASM_TRAMPOLINE_TEMPLATE 541#define TARGET_ASM_TRAMPOLINE_TEMPLATE moxie_asm_trampoline_template 542#undef TARGET_TRAMPOLINE_INIT 543#define TARGET_TRAMPOLINE_INIT moxie_trampoline_init 544 545struct gcc_target targetm = TARGET_INITIALIZER; 546 547#include "gt-moxie.h" 548