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