1/* Subroutines used for code generation on Renesas RL78 processors. 2 Copyright (C) 2011-2015 Free Software Foundation, Inc. 3 Contributed by Red Hat. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with 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 "hash-set.h" 26#include "machmode.h" 27#include "vec.h" 28#include "double-int.h" 29#include "input.h" 30#include "alias.h" 31#include "symtab.h" 32#include "wide-int.h" 33#include "inchash.h" 34#include "tree.h" 35#include "fold-const.h" 36#include "varasm.h" 37#include "stor-layout.h" 38#include "calls.h" 39#include "rtl.h" 40#include "regs.h" 41#include "hard-reg-set.h" 42#include "insn-config.h" 43#include "conditions.h" 44#include "output.h" 45#include "insn-attr.h" 46#include "flags.h" 47#include "function.h" 48#include "hashtab.h" 49#include "statistics.h" 50#include "real.h" 51#include "fixed-value.h" 52#include "expmed.h" 53#include "dojump.h" 54#include "explow.h" 55#include "emit-rtl.h" 56#include "stmt.h" 57#include "expr.h" 58#include "insn-codes.h" 59#include "optabs.h" 60#include "libfuncs.h" 61#include "recog.h" 62#include "diagnostic-core.h" 63#include "toplev.h" 64#include "reload.h" 65#include "dominance.h" 66#include "cfg.h" 67#include "cfgrtl.h" 68#include "cfganal.h" 69#include "lcm.h" 70#include "cfgbuild.h" 71#include "cfgcleanup.h" 72#include "predict.h" 73#include "basic-block.h" 74#include "df.h" 75#include "ggc.h" 76#include "tm_p.h" 77#include "debug.h" 78#include "target.h" 79#include "target-def.h" 80#include "langhooks.h" 81#include "rl78-protos.h" 82#include "dumpfile.h" 83#include "tree-pass.h" 84#include "context.h" 85#include "tm-constrs.h" /* for satisfies_constraint_*(). */ 86#include "insn-flags.h" /* for gen_*(). */ 87#include "builtins.h" 88#include "stringpool.h" 89 90static inline bool is_interrupt_func (const_tree decl); 91static inline bool is_brk_interrupt_func (const_tree decl); 92static void rl78_reorg (void); 93static const char *rl78_strip_name_encoding (const char *); 94static const char *rl78_strip_nonasm_name_encoding (const char *); 95static section * rl78_select_section (tree, int, unsigned HOST_WIDE_INT); 96 97 98/* Debugging statements are tagged with DEBUG0 only so that they can 99 be easily enabled individually, by replacing the '0' with '1' as 100 needed. */ 101#define DEBUG0 0 102#define DEBUG1 1 103 104/* REGISTER_NAMES has the names for individual 8-bit registers, but 105 these have the names we need to use when referring to 16-bit 106 register pairs. */ 107static const char * const word_regnames[] = 108{ 109 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL", 110 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 111 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 112 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", 113 "sp", "ap", "psw", "es", "cs" 114}; 115 116struct GTY(()) machine_function 117{ 118 /* If set, the rest of the fields have been computed. */ 119 int computed; 120 /* Which register pairs need to be pushed in the prologue. */ 121 int need_to_push [FIRST_PSEUDO_REGISTER / 2]; 122 123 /* These fields describe the frame layout... */ 124 /* arg pointer */ 125 /* 4 bytes for saved PC */ 126 int framesize_regs; 127 /* frame pointer */ 128 int framesize_locals; 129 int framesize_outgoing; 130 /* stack pointer */ 131 int framesize; 132 133 /* If set, recog is allowed to match against the "real" patterns. */ 134 int real_insns_ok; 135 /* If set, recog is allowed to match against the "virtual" patterns. */ 136 int virt_insns_ok; 137 /* Set if the current function needs to clean up any trampolines. */ 138 int trampolines_used; 139 /* True if the ES register is used and hence 140 needs to be saved inside interrupt handlers. */ 141 bool uses_es; 142}; 143 144/* This is our init_machine_status, as set in 145 rl78_option_override. */ 146static struct machine_function * 147rl78_init_machine_status (void) 148{ 149 struct machine_function *m; 150 151 m = ggc_cleared_alloc<machine_function> (); 152 m->virt_insns_ok = 1; 153 154 return m; 155} 156 157/* This pass converts virtual instructions using virtual registers, to 158 real instructions using real registers. Rather than run it as 159 reorg, we reschedule it before vartrack to help with debugging. */ 160namespace 161{ 162 const pass_data pass_data_rl78_devirt = 163 { 164 RTL_PASS, /* type */ 165 "devirt", /* name */ 166 OPTGROUP_NONE, /* optinfo_flags */ 167 TV_MACH_DEP, /* tv_id */ 168 0, /* properties_required */ 169 0, /* properties_provided */ 170 0, /* properties_destroyed */ 171 0, /* todo_flags_start */ 172 0, /* todo_flags_finish */ 173 }; 174 175 class pass_rl78_devirt : public rtl_opt_pass 176 { 177 public: 178 pass_rl78_devirt (gcc::context *ctxt) 179 : rtl_opt_pass (pass_data_rl78_devirt, ctxt) 180 { 181 } 182 183 /* opt_pass methods: */ 184 virtual unsigned int execute (function *) 185 { 186 rl78_reorg (); 187 return 0; 188 } 189 }; 190} // anon namespace 191 192rtl_opt_pass * 193make_pass_rl78_devirt (gcc::context *ctxt) 194{ 195 return new pass_rl78_devirt (ctxt); 196} 197 198/* Redundant move elimination pass. Must be run after the basic block 199 reordering pass for the best effect. */ 200 201static unsigned int 202move_elim_pass (void) 203{ 204 rtx_insn *insn, *ninsn; 205 rtx prev = NULL_RTX; 206 207 for (insn = get_insns (); insn; insn = ninsn) 208 { 209 rtx set; 210 211 ninsn = next_nonnote_nondebug_insn (insn); 212 213 if ((set = single_set (insn)) == NULL_RTX) 214 { 215 prev = NULL_RTX; 216 continue; 217 } 218 219 /* If we have two SET insns in a row (without anything 220 between them) and the source of the second one is the 221 destination of the first one, and vice versa, then we 222 can eliminate the second SET. */ 223 if (prev 224 && rtx_equal_p (SET_DEST (prev), SET_SRC (set)) 225 && rtx_equal_p (SET_DEST (set), SET_SRC (prev)) 226 /* ... and none of the operands are volatile. */ 227 && ! volatile_refs_p (SET_SRC (prev)) 228 && ! volatile_refs_p (SET_DEST (prev)) 229 && ! volatile_refs_p (SET_SRC (set)) 230 && ! volatile_refs_p (SET_DEST (set))) 231 { 232 if (dump_file) 233 fprintf (dump_file, " Delete insn %d because it is redundant\n", 234 INSN_UID (insn)); 235 236 delete_insn (insn); 237 prev = NULL_RTX; 238 } 239 else 240 prev = set; 241 } 242 243 if (dump_file) 244 print_rtl_with_bb (dump_file, get_insns (), 0); 245 246 return 0; 247} 248 249namespace 250{ 251 const pass_data pass_data_rl78_move_elim = 252 { 253 RTL_PASS, /* type */ 254 "move_elim", /* name */ 255 OPTGROUP_NONE, /* optinfo_flags */ 256 TV_MACH_DEP, /* tv_id */ 257 0, /* properties_required */ 258 0, /* properties_provided */ 259 0, /* properties_destroyed */ 260 0, /* todo_flags_start */ 261 0, /* todo_flags_finish */ 262 }; 263 264 class pass_rl78_move_elim : public rtl_opt_pass 265 { 266 public: 267 pass_rl78_move_elim (gcc::context *ctxt) 268 : rtl_opt_pass (pass_data_rl78_move_elim, ctxt) 269 { 270 } 271 272 /* opt_pass methods: */ 273 virtual unsigned int execute (function *) { return move_elim_pass (); } 274 }; 275} // anon namespace 276 277rtl_opt_pass * 278make_pass_rl78_move_elim (gcc::context *ctxt) 279{ 280 return new pass_rl78_move_elim (ctxt); 281} 282 283#undef TARGET_ASM_FILE_START 284#define TARGET_ASM_FILE_START rl78_asm_file_start 285 286static void 287rl78_asm_file_start (void) 288{ 289 int i; 290 291 if (TARGET_G10) 292 { 293 /* The memory used is 0xffec8 to 0xffedf; real registers are in 294 0xffee0 to 0xffee7. */ 295 for (i = 8; i < 32; i++) 296 fprintf (asm_out_file, "r%d\t=\t0x%x\n", i, 0xffec0 + i); 297 } 298 else 299 { 300 for (i = 0; i < 8; i++) 301 { 302 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 8 + i, 0xffef0 + i); 303 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 16 + i, 0xffee8 + i); 304 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 24 + i, 0xffee0 + i); 305 } 306 } 307 308 opt_pass *rl78_devirt_pass = make_pass_rl78_devirt (g); 309 struct register_pass_info rl78_devirt_info = 310 { 311 rl78_devirt_pass, 312 "pro_and_epilogue", 313 1, 314 PASS_POS_INSERT_BEFORE 315 }; 316 317 opt_pass *rl78_move_elim_pass = make_pass_rl78_move_elim (g); 318 struct register_pass_info rl78_move_elim_info = 319 { 320 rl78_move_elim_pass, 321 "bbro", 322 1, 323 PASS_POS_INSERT_AFTER 324 }; 325 326 register_pass (& rl78_devirt_info); 327 register_pass (& rl78_move_elim_info); 328} 329 330void 331rl78_output_symbol_ref (FILE * file, rtx sym) 332{ 333 tree type = SYMBOL_REF_DECL (sym); 334 const char *str = XSTR (sym, 0); 335 336 if (str[0] == '*') 337 { 338 fputs (str + 1, file); 339 } 340 else 341 { 342 str = rl78_strip_nonasm_name_encoding (str); 343 if (type && TREE_CODE (type) == FUNCTION_DECL) 344 { 345 fprintf (file, "%%code("); 346 assemble_name (file, str); 347 fprintf (file, ")"); 348 } 349 else 350 assemble_name (file, str); 351 } 352} 353 354#undef TARGET_OPTION_OVERRIDE 355#define TARGET_OPTION_OVERRIDE rl78_option_override 356 357static void 358rl78_option_override (void) 359{ 360 flag_omit_frame_pointer = 1; 361 flag_no_function_cse = 1; 362 flag_split_wide_types = 0; 363 364 init_machine_status = rl78_init_machine_status; 365 366 if (TARGET_ALLREGS) 367 { 368 int i; 369 370 for (i = 24; i < 32; i++) 371 fixed_regs[i] = 0; 372 } 373 374 if (TARGET_ES0 375 && strcmp (lang_hooks.name, "GNU C") 376 /* Compiling with -flto results in a language of GNU GIMPLE being used... */ 377 && strcmp (lang_hooks.name, "GNU GIMPLE")) 378 /* Address spaces are currently only supported by C. */ 379 error ("-mes0 can only be used with C"); 380} 381 382/* Most registers are 8 bits. Some are 16 bits because, for example, 383 gcc doesn't like dealing with $FP as a register pair (the second 384 half of $fp is also 2 to keep reload happy wrt register pairs, but 385 no register class includes it). This table maps register numbers 386 to size in bytes. */ 387static const int register_sizes[] = 388{ 389 1, 1, 1, 1, 1, 1, 1, 1, 390 1, 1, 1, 1, 1, 1, 1, 1, 391 1, 1, 1, 1, 1, 1, 2, 2, 392 1, 1, 1, 1, 1, 1, 1, 1, 393 2, 2, 1, 1, 1 394}; 395 396/* Predicates used in the MD patterns. This one is true when virtual 397 insns may be matched, which typically means before (or during) the 398 devirt pass. */ 399bool 400rl78_virt_insns_ok (void) 401{ 402 if (cfun) 403 return cfun->machine->virt_insns_ok; 404 return true; 405} 406 407/* Predicates used in the MD patterns. This one is true when real 408 insns may be matched, which typically means after (or during) the 409 devirt pass. */ 410bool 411rl78_real_insns_ok (void) 412{ 413 if (cfun) 414 return cfun->machine->real_insns_ok; 415 return false; 416} 417 418/* Implements HARD_REGNO_NREGS. */ 419int 420rl78_hard_regno_nregs (int regno, machine_mode mode) 421{ 422 int rs = register_sizes[regno]; 423 if (rs < 1) 424 rs = 1; 425 return ((GET_MODE_SIZE (mode) + rs - 1) / rs); 426} 427 428/* Implements HARD_REGNO_MODE_OK. */ 429int 430rl78_hard_regno_mode_ok (int regno, machine_mode mode) 431{ 432 int s = GET_MODE_SIZE (mode); 433 434 if (s < 1) 435 return 0; 436 /* These are not to be used by gcc. */ 437 if (regno == 23 || regno == ES_REG || regno == CS_REG) 438 return 0; 439 /* $fp can always be accessed as a 16-bit value. */ 440 if (regno == FP_REG && s == 2) 441 return 1; 442 if (regno < SP_REG) 443 { 444 /* Since a reg-reg move is really a reg-mem move, we must 445 enforce alignment. */ 446 if (s > 1 && (regno % 2)) 447 return 0; 448 return 1; 449 } 450 if (s == CC_REGNUM) 451 return (mode == BImode); 452 /* All other registers must be accessed in their natural sizes. */ 453 if (s == register_sizes [regno]) 454 return 1; 455 return 0; 456} 457 458/* Simplify_gen_subreg() doesn't handle memory references the way we 459 need it to below, so we use this function for when we must get a 460 valid subreg in a "natural" state. */ 461static rtx 462rl78_subreg (machine_mode mode, rtx r, machine_mode omode, int byte) 463{ 464 if (GET_CODE (r) == MEM) 465 return adjust_address (r, mode, byte); 466 else 467 return simplify_gen_subreg (mode, r, omode, byte); 468} 469 470/* Used by movsi. Split SImode moves into two HImode moves, using 471 appropriate patterns for the upper and lower halves of symbols. */ 472void 473rl78_expand_movsi (rtx *operands) 474{ 475 rtx op00, op02, op10, op12; 476 477 op00 = rl78_subreg (HImode, operands[0], SImode, 0); 478 op02 = rl78_subreg (HImode, operands[0], SImode, 2); 479 if (GET_CODE (operands[1]) == CONST 480 || GET_CODE (operands[1]) == SYMBOL_REF) 481 { 482 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0)); 483 op10 = gen_rtx_CONST (HImode, op10); 484 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16)); 485 op12 = gen_rtx_CONST (HImode, op12); 486 } 487 else 488 { 489 op10 = rl78_subreg (HImode, operands[1], SImode, 0); 490 op12 = rl78_subreg (HImode, operands[1], SImode, 2); 491 } 492 493 if (rtx_equal_p (operands[0], operands[1])) 494 ; 495 else if (rtx_equal_p (op00, op12)) 496 { 497 emit_move_insn (op02, op12); 498 emit_move_insn (op00, op10); 499 } 500 else 501 { 502 emit_move_insn (op00, op10); 503 emit_move_insn (op02, op12); 504 } 505} 506 507/* Generate code to move an SImode value. */ 508void 509rl78_split_movsi (rtx *operands, enum machine_mode omode) 510{ 511 rtx op00, op02, op10, op12; 512 513 op00 = rl78_subreg (HImode, operands[0], omode, 0); 514 op02 = rl78_subreg (HImode, operands[0], omode, 2); 515 516 if (GET_CODE (operands[1]) == CONST 517 || GET_CODE (operands[1]) == SYMBOL_REF) 518 { 519 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0)); 520 op10 = gen_rtx_CONST (HImode, op10); 521 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16)); 522 op12 = gen_rtx_CONST (HImode, op12); 523 } 524 else 525 { 526 op10 = rl78_subreg (HImode, operands[1], omode, 0); 527 op12 = rl78_subreg (HImode, operands[1], omode, 2); 528 } 529 530 if (rtx_equal_p (operands[0], operands[1])) 531 ; 532 else if (rtx_equal_p (op00, op12)) 533 { 534 operands[2] = op02; 535 operands[4] = op12; 536 operands[3] = op00; 537 operands[5] = op10; 538 } 539 else 540 { 541 operands[2] = op00; 542 operands[4] = op10; 543 operands[3] = op02; 544 operands[5] = op12; 545 } 546} 547 548/* Used by various two-operand expanders which cannot accept all 549 operands in the "far" namespace. Force some such operands into 550 registers so that each pattern has at most one far operand. */ 551int 552rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx)) 553{ 554 int did = 0; 555 rtx temp_reg = NULL; 556 557 /* FIXME: in the future, be smarter about only doing this if the 558 other operand is also far, assuming the devirtualizer can also 559 handle that. */ 560 if (rl78_far_p (operands[0])) 561 { 562 temp_reg = operands[0]; 563 operands[0] = gen_reg_rtx (GET_MODE (operands[0])); 564 did = 1; 565 } 566 if (!did) 567 return 0; 568 569 emit_insn (gen (operands[0], operands[1])); 570 if (temp_reg) 571 emit_move_insn (temp_reg, operands[0]); 572 return 1; 573} 574 575/* Likewise, but for three-operand expanders. */ 576int 577rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx)) 578{ 579 int did = 0; 580 rtx temp_reg = NULL; 581 582 /* As an exception, we allow two far operands if they're identical 583 and the third operand is not a MEM. This allows global variables 584 to be incremented, for example. */ 585 if (rtx_equal_p (operands[0], operands[1]) 586 && ! MEM_P (operands[2])) 587 return 0; 588 589 /* FIXME: Likewise. */ 590 if (rl78_far_p (operands[1])) 591 { 592 rtx temp_reg = gen_reg_rtx (GET_MODE (operands[1])); 593 emit_move_insn (temp_reg, operands[1]); 594 operands[1] = temp_reg; 595 did = 1; 596 } 597 if (rl78_far_p (operands[0])) 598 { 599 temp_reg = operands[0]; 600 operands[0] = gen_reg_rtx (GET_MODE (operands[0])); 601 did = 1; 602 } 603 if (!did) 604 return 0; 605 606 emit_insn (gen (operands[0], operands[1], operands[2])); 607 if (temp_reg) 608 emit_move_insn (temp_reg, operands[0]); 609 return 1; 610} 611 612#undef TARGET_CAN_ELIMINATE 613#define TARGET_CAN_ELIMINATE rl78_can_eliminate 614 615static bool 616rl78_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to ATTRIBUTE_UNUSED) 617{ 618 return true; 619} 620 621/* Returns true if the given register needs to be saved by the 622 current function. */ 623static bool 624need_to_save (unsigned int regno) 625{ 626 if (is_interrupt_func (cfun->decl)) 627 { 628 /* We don't know what devirt will need */ 629 if (regno < 8) 630 return true; 631 632 /* We don't need to save registers that have 633 been reserved for interrupt handlers. */ 634 if (regno > 23) 635 return false; 636 637 /* If the handler is a non-leaf function then it may call 638 non-interrupt aware routines which will happily clobber 639 any call_used registers, so we have to preserve them. */ 640 if (!crtl->is_leaf && call_used_regs[regno]) 641 return true; 642 643 /* Otherwise we only have to save a register, call_used 644 or not, if it is used by this handler. */ 645 return df_regs_ever_live_p (regno); 646 } 647 648 if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) 649 return true; 650 if (fixed_regs[regno]) 651 return false; 652 if (crtl->calls_eh_return) 653 return true; 654 if (df_regs_ever_live_p (regno) 655 && !call_used_regs[regno]) 656 return true; 657 return false; 658} 659 660/* We use this to wrap all emitted insns in the prologue. */ 661static rtx 662F (rtx x) 663{ 664 RTX_FRAME_RELATED_P (x) = 1; 665 return x; 666} 667 668/* Compute all the frame-related fields in our machine_function 669 structure. */ 670static void 671rl78_compute_frame_info (void) 672{ 673 int i; 674 675 cfun->machine->computed = 1; 676 cfun->machine->framesize_regs = 0; 677 cfun->machine->framesize_locals = get_frame_size (); 678 cfun->machine->framesize_outgoing = crtl->outgoing_args_size; 679 680 for (i = 0; i < 16; i ++) 681 if (need_to_save (i * 2) || need_to_save (i * 2 + 1)) 682 { 683 cfun->machine->need_to_push [i] = 1; 684 cfun->machine->framesize_regs += 2; 685 } 686 else 687 cfun->machine->need_to_push [i] = 0; 688 689 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1) 690 cfun->machine->framesize_locals ++; 691 692 cfun->machine->framesize = (cfun->machine->framesize_regs 693 + cfun->machine->framesize_locals 694 + cfun->machine->framesize_outgoing); 695} 696 697/* Returns true if the provided function has the specified attribute. */ 698static inline bool 699has_func_attr (const_tree decl, const char * func_attr) 700{ 701 if (decl == NULL_TREE) 702 decl = current_function_decl; 703 704 return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE; 705} 706 707/* Returns true if the provided function has the "interrupt" attribute. */ 708static inline bool 709is_interrupt_func (const_tree decl) 710{ 711 return has_func_attr (decl, "interrupt") || has_func_attr (decl, "brk_interrupt"); 712} 713 714/* Returns true if the provided function has the "brk_interrupt" attribute. */ 715static inline bool 716is_brk_interrupt_func (const_tree decl) 717{ 718 return has_func_attr (decl, "brk_interrupt"); 719} 720 721/* Check "interrupt" attributes. */ 722static tree 723rl78_handle_func_attribute (tree * node, 724 tree name, 725 tree args, 726 int flags ATTRIBUTE_UNUSED, 727 bool * no_add_attrs) 728{ 729 gcc_assert (DECL_P (* node)); 730 gcc_assert (args == NULL_TREE); 731 732 if (TREE_CODE (* node) != FUNCTION_DECL) 733 { 734 warning (OPT_Wattributes, "%qE attribute only applies to functions", 735 name); 736 * no_add_attrs = true; 737 } 738 739 /* FIXME: We ought to check that the interrupt and exception 740 handler attributes have been applied to void functions. */ 741 return NULL_TREE; 742} 743 744/* Check "naked" attributes. */ 745static tree 746rl78_handle_naked_attribute (tree * node, 747 tree name ATTRIBUTE_UNUSED, 748 tree args, 749 int flags ATTRIBUTE_UNUSED, 750 bool * no_add_attrs) 751{ 752 gcc_assert (DECL_P (* node)); 753 gcc_assert (args == NULL_TREE); 754 755 if (TREE_CODE (* node) != FUNCTION_DECL) 756 { 757 warning (OPT_Wattributes, "naked attribute only applies to functions"); 758 * no_add_attrs = true; 759 } 760 761 /* Disable warnings about this function - eg reaching the end without 762 seeing a return statement - because the programmer is doing things 763 that gcc does not know about. */ 764 TREE_NO_WARNING (* node) = 1; 765 766 return NULL_TREE; 767} 768 769/* Check "saddr" attributes. */ 770static tree 771rl78_handle_saddr_attribute (tree * node, 772 tree name, 773 tree args ATTRIBUTE_UNUSED, 774 int flags ATTRIBUTE_UNUSED, 775 bool * no_add_attrs) 776{ 777 gcc_assert (DECL_P (* node)); 778 779 if (TREE_CODE (* node) == FUNCTION_DECL) 780 { 781 warning (OPT_Wattributes, "%qE attribute doesn't apply to functions", 782 name); 783 * no_add_attrs = true; 784 } 785 786 return NULL_TREE; 787} 788 789#undef TARGET_ATTRIBUTE_TABLE 790#define TARGET_ATTRIBUTE_TABLE rl78_attribute_table 791 792/* Table of RL78-specific attributes. */ 793const struct attribute_spec rl78_attribute_table[] = 794{ 795 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler, 796 affects_type_identity. */ 797 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, 798 false }, 799 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, 800 false }, 801 { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute, 802 false }, 803 { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute, 804 false }, 805 { NULL, 0, 0, false, false, false, NULL, false } 806}; 807 808 809 810/* Break down an address RTX into its component base/index/addend 811 portions and return TRUE if the address is of a valid form, else 812 FALSE. */ 813static bool 814characterize_address (rtx x, rtx *base, rtx *index, rtx *addend) 815{ 816 *base = NULL_RTX; 817 *index = NULL_RTX; 818 *addend = NULL_RTX; 819 820 if (GET_CODE (x) == UNSPEC 821 && XINT (x, 1) == UNS_ES_ADDR) 822 x = XVECEXP (x, 0, 1); 823 824 if (GET_CODE (x) == REG) 825 { 826 *base = x; 827 return true; 828 } 829 830 /* We sometimes get these without the CONST wrapper */ 831 if (GET_CODE (x) == PLUS 832 && GET_CODE (XEXP (x, 0)) == SYMBOL_REF 833 && GET_CODE (XEXP (x, 1)) == CONST_INT) 834 { 835 *addend = x; 836 return true; 837 } 838 839 if (GET_CODE (x) == PLUS) 840 { 841 *base = XEXP (x, 0); 842 x = XEXP (x, 1); 843 844 if (GET_CODE (*base) == SUBREG) 845 { 846 if (GET_MODE (*base) == HImode 847 && GET_MODE (XEXP (*base, 0)) == SImode 848 && GET_CODE (XEXP (*base, 0)) == REG) 849 { 850 /* This is a throw-away rtx just to tell everyone 851 else what effective register we're using. */ 852 *base = gen_rtx_REG (HImode, REGNO (XEXP (*base, 0))); 853 } 854 } 855 856 if (GET_CODE (*base) != REG 857 && GET_CODE (x) == REG) 858 { 859 rtx tmp = *base; 860 *base = x; 861 x = tmp; 862 } 863 864 if (GET_CODE (*base) != REG) 865 return false; 866 867 if (GET_CODE (x) == ZERO_EXTEND 868 && GET_CODE (XEXP (x, 0)) == REG) 869 { 870 *index = XEXP (x, 0); 871 return false; 872 } 873 } 874 875 switch (GET_CODE (x)) 876 { 877 case PLUS: 878 if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF 879 && GET_CODE (XEXP (x, 0)) == CONST_INT) 880 { 881 *addend = x; 882 return true; 883 } 884 /* fall through */ 885 case MEM: 886 case REG: 887 return false; 888 889 case SUBREG: 890 switch (GET_CODE (XEXP (x, 0))) 891 { 892 case CONST: 893 case SYMBOL_REF: 894 case CONST_INT: 895 *addend = x; 896 return true; 897 default: 898 return false; 899 } 900 901 case CONST: 902 case SYMBOL_REF: 903 case CONST_INT: 904 *addend = x; 905 return true; 906 907 default: 908 return false; 909 } 910 911 return false; 912} 913 914/* Used by the Whb constraint. Match addresses that use HL+B or HL+C 915 addressing. */ 916bool 917rl78_hl_b_c_addr_p (rtx op) 918{ 919 rtx hl, bc; 920 921 if (GET_CODE (op) != PLUS) 922 return false; 923 hl = XEXP (op, 0); 924 bc = XEXP (op, 1); 925 if (GET_CODE (hl) == ZERO_EXTEND) 926 { 927 rtx tmp = hl; 928 hl = bc; 929 bc = tmp; 930 } 931 if (GET_CODE (hl) != REG) 932 return false; 933 if (GET_CODE (bc) != ZERO_EXTEND) 934 return false; 935 bc = XEXP (bc, 0); 936 if (GET_CODE (bc) != REG) 937 return false; 938 if (REGNO (hl) != HL_REG) 939 return false; 940 if (REGNO (bc) != B_REG && REGNO (bc) != C_REG) 941 return false; 942 943 return true; 944} 945 946#define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict))) 947 948/* Return the appropriate mode for a named address address. */ 949 950#undef TARGET_ADDR_SPACE_ADDRESS_MODE 951#define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode 952 953static enum machine_mode 954rl78_addr_space_address_mode (addr_space_t addrspace) 955{ 956 switch (addrspace) 957 { 958 case ADDR_SPACE_GENERIC: 959 return HImode; 960 case ADDR_SPACE_NEAR: 961 return HImode; 962 case ADDR_SPACE_FAR: 963 return SImode; 964 default: 965 gcc_unreachable (); 966 } 967} 968 969/* Used in various constraints and predicates to match operands in the 970 "far" address space. */ 971int 972rl78_far_p (rtx x) 973{ 974 if (! MEM_P (x)) 975 return 0; 976#if DEBUG0 977 fprintf (stderr, "\033[35mrl78_far_p: "); debug_rtx (x); 978 fprintf (stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR); 979#endif 980 981 /* Not all far addresses are legitimate, because the devirtualizer 982 can't handle them. */ 983 if (! rl78_as_legitimate_address (GET_MODE (x), XEXP (x, 0), false, ADDR_SPACE_FAR)) 984 return 0; 985 986 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x))) == 32; 987} 988 989/* Return the appropriate mode for a named address pointer. */ 990#undef TARGET_ADDR_SPACE_POINTER_MODE 991#define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode 992 993static machine_mode 994rl78_addr_space_pointer_mode (addr_space_t addrspace) 995{ 996 switch (addrspace) 997 { 998 case ADDR_SPACE_GENERIC: 999 return HImode; 1000 case ADDR_SPACE_NEAR: 1001 return HImode; 1002 case ADDR_SPACE_FAR: 1003 return SImode; 1004 default: 1005 gcc_unreachable (); 1006 } 1007} 1008 1009/* Returns TRUE for valid addresses. */ 1010#undef TARGET_VALID_POINTER_MODE 1011#define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode 1012 1013static bool 1014rl78_valid_pointer_mode (machine_mode m) 1015{ 1016 return (m == HImode || m == SImode); 1017} 1018 1019#undef TARGET_LEGITIMATE_CONSTANT_P 1020#define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant 1021 1022static bool 1023rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED) 1024{ 1025 return true; 1026} 1027 1028#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P 1029#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address 1030 1031bool 1032rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x, 1033 bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED) 1034{ 1035 rtx base, index, addend; 1036 bool is_far_addr = false; 1037 int as_bits; 1038 1039 as_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (as)); 1040 1041 if (GET_CODE (x) == UNSPEC 1042 && XINT (x, 1) == UNS_ES_ADDR) 1043 { 1044 x = XVECEXP (x, 0, 1); 1045 is_far_addr = true; 1046 } 1047 1048 if (as_bits == 16 && is_far_addr) 1049 return false; 1050 1051 if (! characterize_address (x, &base, &index, &addend)) 1052 return false; 1053 1054 /* We can't extract the high/low portions of a PLUS address 1055 involving a register during devirtualization, so make sure all 1056 such __far addresses do not have addends. This forces GCC to do 1057 the sum separately. */ 1058 if (addend && base && as_bits == 32 && GET_MODE (base) == SImode) 1059 return false; 1060 1061 if (base && index) 1062 { 1063 int ir = REGNO (index); 1064 int br = REGNO (base); 1065 1066#define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; } 1067 OK (REG_IS (br, HL_REG) && REG_IS (ir, B_REG), "[hl+b]"); 1068 OK (REG_IS (br, HL_REG) && REG_IS (ir, C_REG), "[hl+c]"); 1069 return false; 1070 } 1071 1072 if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER) 1073 return false; 1074 1075 if (! cfun->machine->virt_insns_ok && base && GET_CODE (base) == REG 1076 && REGNO (base) >= 8 && REGNO (base) <= 31) 1077 return false; 1078 1079 return true; 1080} 1081 1082/* Determine if one named address space is a subset of another. */ 1083#undef TARGET_ADDR_SPACE_SUBSET_P 1084#define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p 1085 1086static bool 1087rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset) 1088{ 1089 int subset_bits; 1090 int superset_bits; 1091 1092 subset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset)); 1093 superset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset)); 1094 1095 return (subset_bits <= superset_bits); 1096} 1097 1098#undef TARGET_ADDR_SPACE_CONVERT 1099#define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert 1100 1101/* Convert from one address space to another. */ 1102static rtx 1103rl78_addr_space_convert (rtx op, tree from_type, tree to_type) 1104{ 1105 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); 1106 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); 1107 rtx result; 1108 int to_bits; 1109 int from_bits; 1110 1111 to_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as)); 1112 from_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as)); 1113 1114 if (to_bits < from_bits) 1115 { 1116 rtx tmp; 1117 /* This is unpredictable, as we're truncating off usable address 1118 bits. */ 1119 1120 warning (OPT_Waddress, "converting far pointer to near pointer"); 1121 result = gen_reg_rtx (HImode); 1122 if (GET_CODE (op) == SYMBOL_REF 1123 || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)) 1124 tmp = gen_rtx_raw_SUBREG (HImode, op, 0); 1125 else 1126 tmp = simplify_subreg (HImode, op, SImode, 0); 1127 gcc_assert (tmp != NULL_RTX); 1128 emit_move_insn (result, tmp); 1129 return result; 1130 } 1131 else if (to_bits > from_bits) 1132 { 1133 /* This always works. */ 1134 result = gen_reg_rtx (SImode); 1135 emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op); 1136 if (TREE_CODE (from_type) == POINTER_TYPE 1137 && TREE_CODE (TREE_TYPE (from_type)) == FUNCTION_TYPE) 1138 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx); 1139 else 1140 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), GEN_INT (0x0f)); 1141 return result; 1142 } 1143 else 1144 return op; 1145 gcc_unreachable (); 1146} 1147 1148/* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */ 1149bool 1150rl78_regno_mode_code_ok_for_base_p (int regno, machine_mode mode ATTRIBUTE_UNUSED, 1151 addr_space_t address_space ATTRIBUTE_UNUSED, 1152 int outer_code ATTRIBUTE_UNUSED, int index_code) 1153{ 1154 if (regno <= SP_REG && regno >= 16) 1155 return true; 1156 if (index_code == REG) 1157 return (regno == HL_REG); 1158 if (regno == C_REG || regno == B_REG || regno == E_REG || regno == L_REG) 1159 return true; 1160 return false; 1161} 1162 1163/* Implements MODE_CODE_BASE_REG_CLASS. */ 1164enum reg_class 1165rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED, 1166 addr_space_t address_space ATTRIBUTE_UNUSED, 1167 int outer_code ATTRIBUTE_UNUSED, 1168 int index_code ATTRIBUTE_UNUSED) 1169{ 1170 return V_REGS; 1171} 1172 1173/* Typical stack layout should looks like this after the function's prologue: 1174 1175 | | 1176 -- ^ 1177 | | \ | 1178 | | arguments saved | Increasing 1179 | | on the stack | addresses 1180 PARENT arg pointer -> | | / 1181 -------------------------- ---- ------------------- 1182 CHILD |ret | return address 1183 -- 1184 | | \ 1185 | | call saved 1186 | | registers 1187 frame pointer -> | | / 1188 -- 1189 | | \ 1190 | | local 1191 | | variables 1192 | | / 1193 -- 1194 | | \ 1195 | | outgoing | Decreasing 1196 | | arguments | addresses 1197 current stack pointer -> | | / | 1198 -------------------------- ---- ------------------ V 1199 | | */ 1200 1201/* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is 1202 described in the machine_Function struct definition, above. */ 1203int 1204rl78_initial_elimination_offset (int from, int to) 1205{ 1206 int rv = 0; /* as if arg to arg */ 1207 1208 rl78_compute_frame_info (); 1209 1210 switch (to) 1211 { 1212 case STACK_POINTER_REGNUM: 1213 rv += cfun->machine->framesize_outgoing; 1214 rv += cfun->machine->framesize_locals; 1215 /* Fall through. */ 1216 case FRAME_POINTER_REGNUM: 1217 rv += cfun->machine->framesize_regs; 1218 rv += 4; 1219 break; 1220 default: 1221 gcc_unreachable (); 1222 } 1223 1224 switch (from) 1225 { 1226 case FRAME_POINTER_REGNUM: 1227 rv -= 4; 1228 rv -= cfun->machine->framesize_regs; 1229 case ARG_POINTER_REGNUM: 1230 break; 1231 default: 1232 gcc_unreachable (); 1233 } 1234 1235 return rv; 1236} 1237 1238static int 1239rl78_is_naked_func (void) 1240{ 1241 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE); 1242} 1243 1244/* Expand the function prologue (from the prologue pattern). */ 1245void 1246rl78_expand_prologue (void) 1247{ 1248 int i, fs; 1249 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM); 1250 rtx ax = gen_rtx_REG (HImode, AX_REG); 1251 int rb = 0; 1252 1253 if (rl78_is_naked_func ()) 1254 return; 1255 1256 /* Always re-compute the frame info - the register usage may have changed. */ 1257 rl78_compute_frame_info (); 1258 1259 if (flag_stack_usage_info) 1260 current_function_static_stack_size = cfun->machine->framesize; 1261 1262 if (is_interrupt_func (cfun->decl) && !TARGET_G10) 1263 for (i = 0; i < 4; i++) 1264 if (cfun->machine->need_to_push [i]) 1265 { 1266 /* Select Bank 0 if we are using any registers from Bank 0. */ 1267 emit_insn (gen_sel_rb (GEN_INT (0))); 1268 break; 1269 } 1270 1271 for (i = 0; i < 16; i++) 1272 if (cfun->machine->need_to_push [i]) 1273 { 1274 int reg = i * 2; 1275 1276 if (TARGET_G10) 1277 { 1278 if (reg >= 8) 1279 { 1280 emit_move_insn (ax, gen_rtx_REG (HImode, reg)); 1281 reg = AX_REG; 1282 } 1283 } 1284 else 1285 { 1286 int need_bank = i/4; 1287 1288 if (need_bank != rb) 1289 { 1290 emit_insn (gen_sel_rb (GEN_INT (need_bank))); 1291 rb = need_bank; 1292 } 1293 } 1294 1295 F (emit_insn (gen_push (gen_rtx_REG (HImode, reg)))); 1296 } 1297 1298 if (rb != 0) 1299 emit_insn (gen_sel_rb (GEN_INT (0))); 1300 1301 /* Save ES register inside interrupt functions if it is used. */ 1302 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es) 1303 { 1304 emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode, A_REG))); 1305 F (emit_insn (gen_push (ax))); 1306 } 1307 1308 if (frame_pointer_needed) 1309 { 1310 F (emit_move_insn (ax, sp)); 1311 F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM), ax)); 1312 } 1313 1314 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing; 1315 if (fs > 0) 1316 { 1317 /* If we need to subtract more than 254*3 then it is faster and 1318 smaller to move SP into AX and perform the subtraction there. */ 1319 if (fs > 254 * 3) 1320 { 1321 rtx insn; 1322 1323 emit_move_insn (ax, sp); 1324 emit_insn (gen_subhi3 (ax, ax, GEN_INT (fs))); 1325 insn = emit_move_insn (sp, ax); 1326 add_reg_note (insn, REG_FRAME_RELATED_EXPR, 1327 gen_rtx_SET (SImode, sp, 1328 gen_rtx_PLUS (HImode, sp, GEN_INT (-fs)))); 1329 } 1330 else 1331 { 1332 while (fs > 0) 1333 { 1334 int fs_byte = (fs > 254) ? 254 : fs; 1335 1336 F (emit_insn (gen_subhi3 (sp, sp, GEN_INT (fs_byte)))); 1337 fs -= fs_byte; 1338 } 1339 } 1340 } 1341} 1342 1343/* Expand the function epilogue (from the epilogue pattern). */ 1344void 1345rl78_expand_epilogue (void) 1346{ 1347 int i, fs; 1348 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM); 1349 rtx ax = gen_rtx_REG (HImode, AX_REG); 1350 int rb = 0; 1351 1352 if (rl78_is_naked_func ()) 1353 return; 1354 1355 if (frame_pointer_needed) 1356 { 1357 emit_move_insn (ax, gen_rtx_REG (HImode, FRAME_POINTER_REGNUM)); 1358 emit_move_insn (sp, ax); 1359 } 1360 else 1361 { 1362 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing; 1363 if (fs > 254 * 3) 1364 { 1365 emit_move_insn (ax, sp); 1366 emit_insn (gen_addhi3 (ax, ax, GEN_INT (fs))); 1367 emit_move_insn (sp, ax); 1368 } 1369 else 1370 { 1371 while (fs > 0) 1372 { 1373 int fs_byte = (fs > 254) ? 254 : fs; 1374 1375 emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte))); 1376 fs -= fs_byte; 1377 } 1378 } 1379 } 1380 1381 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es) 1382 { 1383 emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG))); 1384 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode, A_REG))); 1385 } 1386 1387 for (i = 15; i >= 0; i--) 1388 if (cfun->machine->need_to_push [i]) 1389 { 1390 rtx dest = gen_rtx_REG (HImode, i * 2); 1391 1392 if (TARGET_G10) 1393 { 1394 if (i < 8) 1395 emit_insn (gen_pop (dest)); 1396 else 1397 { 1398 emit_insn (gen_pop (ax)); 1399 emit_move_insn (dest, ax); 1400 /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */ 1401 emit_insn (gen_use (dest)); 1402 } 1403 } 1404 else 1405 { 1406 int need_bank = i / 4; 1407 1408 if (need_bank != rb) 1409 { 1410 emit_insn (gen_sel_rb (GEN_INT (need_bank))); 1411 rb = need_bank; 1412 } 1413 emit_insn (gen_pop (dest)); 1414 } 1415 } 1416 1417 if (rb != 0) 1418 emit_insn (gen_sel_rb (GEN_INT (0))); 1419 1420 if (cfun->machine->trampolines_used) 1421 emit_insn (gen_trampoline_uninit ()); 1422 1423 if (is_brk_interrupt_func (cfun->decl)) 1424 emit_jump_insn (gen_brk_interrupt_return ()); 1425 else if (is_interrupt_func (cfun->decl)) 1426 emit_jump_insn (gen_interrupt_return ()); 1427 else 1428 emit_jump_insn (gen_rl78_return ()); 1429} 1430 1431/* Likewise, for exception handlers. */ 1432void 1433rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED) 1434{ 1435 /* FIXME - replace this with an indirect jump with stack adjust. */ 1436 emit_jump_insn (gen_rl78_return ()); 1437} 1438 1439#undef TARGET_ASM_FUNCTION_PROLOGUE 1440#define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function 1441 1442/* We don't use this to actually emit the function prologue. We use 1443 this to insert a comment in the asm file describing the 1444 function. */ 1445static void 1446rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED) 1447{ 1448 int i; 1449 1450 if (cfun->machine->framesize == 0) 1451 return; 1452 fprintf (file, "\t; start of function\n"); 1453 1454 if (cfun->machine->framesize_regs) 1455 { 1456 fprintf (file, "\t; push %d:", cfun->machine->framesize_regs); 1457 for (i = 0; i < 16; i ++) 1458 if (cfun->machine->need_to_push[i]) 1459 fprintf (file, " %s", word_regnames[i*2]); 1460 fprintf (file, "\n"); 1461 } 1462 1463 if (frame_pointer_needed) 1464 fprintf (file, "\t; $fp points here (r22)\n"); 1465 1466 if (cfun->machine->framesize_locals) 1467 fprintf (file, "\t; locals: %d byte%s\n", cfun->machine->framesize_locals, 1468 cfun->machine->framesize_locals == 1 ? "" : "s"); 1469 1470 if (cfun->machine->framesize_outgoing) 1471 fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing, 1472 cfun->machine->framesize_outgoing == 1 ? "" : "s"); 1473 1474 if (cfun->machine->uses_es) 1475 fprintf (file, "\t; uses ES register\n"); 1476} 1477 1478/* Return an RTL describing where a function return value of type RET_TYPE 1479 is held. */ 1480 1481#undef TARGET_FUNCTION_VALUE 1482#define TARGET_FUNCTION_VALUE rl78_function_value 1483 1484static rtx 1485rl78_function_value (const_tree ret_type, 1486 const_tree fn_decl_or_type ATTRIBUTE_UNUSED, 1487 bool outgoing ATTRIBUTE_UNUSED) 1488{ 1489 machine_mode mode = TYPE_MODE (ret_type); 1490 1491 return gen_rtx_REG (mode, 8); 1492} 1493 1494#undef TARGET_PROMOTE_FUNCTION_MODE 1495#define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode 1496 1497static machine_mode 1498rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, 1499 machine_mode mode, 1500 int *punsignedp ATTRIBUTE_UNUSED, 1501 const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED) 1502{ 1503 return mode; 1504} 1505 1506/* Return an RTL expression describing the register holding a function 1507 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should 1508 be passed on the stack. CUM describes the previous parameters to the 1509 function and NAMED is false if the parameter is part of a variable 1510 parameter list, or the last named parameter before the start of a 1511 variable parameter list. */ 1512 1513#undef TARGET_FUNCTION_ARG 1514#define TARGET_FUNCTION_ARG rl78_function_arg 1515 1516static rtx 1517rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED, 1518 machine_mode mode ATTRIBUTE_UNUSED, 1519 const_tree type ATTRIBUTE_UNUSED, 1520 bool named ATTRIBUTE_UNUSED) 1521{ 1522 return NULL_RTX; 1523} 1524 1525#undef TARGET_FUNCTION_ARG_ADVANCE 1526#define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance 1527 1528static void 1529rl78_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, const_tree type, 1530 bool named ATTRIBUTE_UNUSED) 1531{ 1532 int rounded_size; 1533 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v); 1534 1535 rounded_size = ((mode == BLKmode) 1536 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 1537 if (rounded_size & 1) 1538 rounded_size ++; 1539 (*cum) += rounded_size; 1540} 1541 1542#undef TARGET_FUNCTION_ARG_BOUNDARY 1543#define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary 1544 1545static unsigned int 1546rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED, 1547 const_tree type ATTRIBUTE_UNUSED) 1548{ 1549 return 16; 1550} 1551 1552/* Supported modifier letters: 1553 1554 A - address of a MEM 1555 S - SADDR form of a real register 1556 v - real register corresponding to a virtual register 1557 m - minus - negative of CONST_INT value. 1558 C - inverse of a conditional (NE vs EQ for example) 1559 C - complement of an integer 1560 z - collapsed conditional 1561 s - shift count mod 8 1562 S - shift count mod 16 1563 r - reverse shift count (8-(count mod 8)) 1564 B - bit position 1565 1566 h - bottom HI of an SI 1567 H - top HI of an SI 1568 q - bottom QI of an HI 1569 Q - top QI of an HI 1570 e - third QI of an SI (i.e. where the ES register gets values from) 1571 E - fourth QI of an SI (i.e. MSB) 1572 1573*/ 1574 1575/* Implements the bulk of rl78_print_operand, below. We do it this 1576 way because we need to test for a constant at the top level and 1577 insert the '#', but not test for it anywhere else as we recurse 1578 down into the operand. */ 1579static void 1580rl78_print_operand_1 (FILE * file, rtx op, int letter) 1581{ 1582 int need_paren; 1583 1584 switch (GET_CODE (op)) 1585 { 1586 case MEM: 1587 if (letter == 'A') 1588 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1589 else 1590 { 1591 if (rl78_far_p (op)) 1592 { 1593 fprintf (file, "es:"); 1594 if (GET_CODE (XEXP (op, 0)) == UNSPEC) 1595 op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1)); 1596 } 1597 if (letter == 'H') 1598 { 1599 op = adjust_address (op, HImode, 2); 1600 letter = 0; 1601 } 1602 if (letter == 'h') 1603 { 1604 op = adjust_address (op, HImode, 0); 1605 letter = 0; 1606 } 1607 if (letter == 'Q') 1608 { 1609 op = adjust_address (op, QImode, 1); 1610 letter = 0; 1611 } 1612 if (letter == 'q') 1613 { 1614 op = adjust_address (op, QImode, 0); 1615 letter = 0; 1616 } 1617 if (letter == 'e') 1618 { 1619 op = adjust_address (op, QImode, 2); 1620 letter = 0; 1621 } 1622 if (letter == 'E') 1623 { 1624 op = adjust_address (op, QImode, 3); 1625 letter = 0; 1626 } 1627 if (CONSTANT_P (XEXP (op, 0))) 1628 { 1629 if (!rl78_saddr_p (op)) 1630 fprintf (file, "!"); 1631 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1632 } 1633 else if (GET_CODE (XEXP (op, 0)) == PLUS 1634 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF) 1635 { 1636 if (!rl78_saddr_p (op)) 1637 fprintf (file, "!"); 1638 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1639 } 1640 else if (GET_CODE (XEXP (op, 0)) == PLUS 1641 && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG 1642 && REGNO (XEXP (XEXP (op, 0), 0)) == 2) 1643 { 1644 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u'); 1645 fprintf (file, "["); 1646 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0); 1647 fprintf (file, "]"); 1648 } 1649 else 1650 { 1651 fprintf (file, "["); 1652 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1653 if (letter == 'p' && GET_CODE (XEXP (op, 0)) == REG) 1654 fprintf (file, "+0"); 1655 fprintf (file, "]"); 1656 } 1657 } 1658 break; 1659 1660 case REG: 1661 if (letter == 'Q') 1662 fprintf (file, "%s", reg_names [REGNO (op) | 1]); 1663 else if (letter == 'H') 1664 fprintf (file, "%s", reg_names [REGNO (op) + 2]); 1665 else if (letter == 'q') 1666 fprintf (file, "%s", reg_names [REGNO (op) & ~1]); 1667 else if (letter == 'e') 1668 fprintf (file, "%s", reg_names [REGNO (op) + 2]); 1669 else if (letter == 'E') 1670 fprintf (file, "%s", reg_names [REGNO (op) + 3]); 1671 else if (letter == 'S') 1672 fprintf (file, "0x%x", 0xffef8 + REGNO (op)); 1673 else if (GET_MODE (op) == HImode 1674 && ! (REGNO (op) & ~0xfe)) 1675 { 1676 if (letter == 'v') 1677 fprintf (file, "%s", word_regnames [REGNO (op) % 8]); 1678 else 1679 fprintf (file, "%s", word_regnames [REGNO (op)]); 1680 } 1681 else 1682 fprintf (file, "%s", reg_names [REGNO (op)]); 1683 break; 1684 1685 case CONST_INT: 1686 if (letter == 'Q') 1687 fprintf (file, "%ld", INTVAL (op) >> 8); 1688 else if (letter == 'H') 1689 fprintf (file, "%ld", INTVAL (op) >> 16); 1690 else if (letter == 'q') 1691 fprintf (file, "%ld", INTVAL (op) & 0xff); 1692 else if (letter == 'h') 1693 fprintf (file, "%ld", INTVAL (op) & 0xffff); 1694 else if (letter == 'e') 1695 fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff); 1696 else if (letter == 'B') 1697 { 1698 int ival = INTVAL (op); 1699 if (ival == -128) 1700 ival = 0x80; 1701 if (exact_log2 (ival) >= 0) 1702 fprintf (file, "%d", exact_log2 (ival)); 1703 else 1704 fprintf (file, "%d", exact_log2 (~ival & 0xff)); 1705 } 1706 else if (letter == 'E') 1707 fprintf (file, "%ld", (INTVAL (op) >> 24) & 0xff); 1708 else if (letter == 'm') 1709 fprintf (file, "%ld", - INTVAL (op)); 1710 else if (letter == 's') 1711 fprintf (file, "%ld", INTVAL (op) % 8); 1712 else if (letter == 'S') 1713 fprintf (file, "%ld", INTVAL (op) % 16); 1714 else if (letter == 'r') 1715 fprintf (file, "%ld", 8 - (INTVAL (op) % 8)); 1716 else if (letter == 'C') 1717 fprintf (file, "%ld", (INTVAL (op) ^ 0x8000) & 0xffff); 1718 else 1719 fprintf (file, "%ld", INTVAL (op)); 1720 break; 1721 1722 case CONST: 1723 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1724 break; 1725 1726 case ZERO_EXTRACT: 1727 { 1728 int bits = INTVAL (XEXP (op, 1)); 1729 int ofs = INTVAL (XEXP (op, 2)); 1730 if (bits == 16 && ofs == 0) 1731 fprintf (file, "%%lo16("); 1732 else if (bits == 16 && ofs == 16) 1733 fprintf (file, "%%hi16("); 1734 else if (bits == 8 && ofs == 16) 1735 fprintf (file, "%%hi8("); 1736 else 1737 gcc_unreachable (); 1738 rl78_print_operand_1 (file, XEXP (op, 0), 0); 1739 fprintf (file, ")"); 1740 } 1741 break; 1742 1743 case ZERO_EXTEND: 1744 if (GET_CODE (XEXP (op, 0)) == REG) 1745 fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]); 1746 else 1747 print_rtl (file, op); 1748 break; 1749 1750 case PLUS: 1751 need_paren = 0; 1752 if (letter == 'H') 1753 { 1754 fprintf (file, "%%hi16("); 1755 need_paren = 1; 1756 letter = 0; 1757 } 1758 if (letter == 'h') 1759 { 1760 fprintf (file, "%%lo16("); 1761 need_paren = 1; 1762 letter = 0; 1763 } 1764 if (letter == 'e') 1765 { 1766 fprintf (file, "%%hi8("); 1767 need_paren = 1; 1768 letter = 0; 1769 } 1770 if (letter == 'q' || letter == 'Q') 1771 output_operand_lossage ("q/Q modifiers invalid for symbol references"); 1772 1773 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND) 1774 { 1775 rl78_print_operand_1 (file, XEXP (op, 1), letter); 1776 fprintf (file, "+"); 1777 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1778 } 1779 else 1780 { 1781 rl78_print_operand_1 (file, XEXP (op, 0), letter); 1782 fprintf (file, "+"); 1783 rl78_print_operand_1 (file, XEXP (op, 1), letter); 1784 } 1785 if (need_paren) 1786 fprintf (file, ")"); 1787 break; 1788 1789 case SUBREG: 1790 if (GET_MODE (op) == HImode 1791 && SUBREG_BYTE (op) == 0) 1792 { 1793 fprintf (file, "%%lo16("); 1794 rl78_print_operand_1 (file, SUBREG_REG (op), 0); 1795 fprintf (file, ")"); 1796 } 1797 else if (GET_MODE (op) == HImode 1798 && SUBREG_BYTE (op) == 2) 1799 { 1800 fprintf (file, "%%hi16("); 1801 rl78_print_operand_1 (file, SUBREG_REG (op), 0); 1802 fprintf (file, ")"); 1803 } 1804 else 1805 { 1806 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op))); 1807 } 1808 break; 1809 1810 case SYMBOL_REF: 1811 need_paren = 0; 1812 if (letter == 'H') 1813 { 1814 fprintf (file, "%%hi16("); 1815 need_paren = 1; 1816 letter = 0; 1817 } 1818 if (letter == 'h') 1819 { 1820 fprintf (file, "%%lo16("); 1821 need_paren = 1; 1822 letter = 0; 1823 } 1824 if (letter == 'e') 1825 { 1826 fprintf (file, "%%hi8("); 1827 need_paren = 1; 1828 letter = 0; 1829 } 1830 if (letter == 'q' || letter == 'Q') 1831 output_operand_lossage ("q/Q modifiers invalid for symbol references"); 1832 1833 if (SYMBOL_REF_DECL (op) && TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL) 1834 { 1835 fprintf (file, "%%code("); 1836 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0))); 1837 fprintf (file, ")"); 1838 } 1839 else 1840 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0))); 1841 if (need_paren) 1842 fprintf (file, ")"); 1843 break; 1844 1845 case CODE_LABEL: 1846 case LABEL_REF: 1847 output_asm_label (op); 1848 break; 1849 1850 case LTU: 1851 if (letter == 'z') 1852 fprintf (file, "#comparison eliminated"); 1853 else 1854 fprintf (file, letter == 'C' ? "nc" : "c"); 1855 break; 1856 case LEU: 1857 if (letter == 'z') 1858 fprintf (file, "br"); 1859 else 1860 fprintf (file, letter == 'C' ? "h" : "nh"); 1861 break; 1862 case GEU: 1863 if (letter == 'z') 1864 fprintf (file, "br"); 1865 else 1866 fprintf (file, letter == 'C' ? "c" : "nc"); 1867 break; 1868 case GTU: 1869 if (letter == 'z') 1870 fprintf (file, "#comparison eliminated"); 1871 else 1872 fprintf (file, letter == 'C' ? "nh" : "h"); 1873 break; 1874 case EQ: 1875 if (letter == 'z') 1876 fprintf (file, "br"); 1877 else 1878 fprintf (file, letter == 'C' ? "nz" : "z"); 1879 break; 1880 case NE: 1881 if (letter == 'z') 1882 fprintf (file, "#comparison eliminated"); 1883 else 1884 fprintf (file, letter == 'C' ? "z" : "nz"); 1885 break; 1886 1887 /* Note: these assume appropriate adjustments were made so that 1888 unsigned comparisons, which is all this chip has, will 1889 work. */ 1890 case LT: 1891 if (letter == 'z') 1892 fprintf (file, "#comparison eliminated"); 1893 else 1894 fprintf (file, letter == 'C' ? "nc" : "c"); 1895 break; 1896 case LE: 1897 if (letter == 'z') 1898 fprintf (file, "br"); 1899 else 1900 fprintf (file, letter == 'C' ? "h" : "nh"); 1901 break; 1902 case GE: 1903 if (letter == 'z') 1904 fprintf (file, "br"); 1905 else 1906 fprintf (file, letter == 'C' ? "c" : "nc"); 1907 break; 1908 case GT: 1909 if (letter == 'z') 1910 fprintf (file, "#comparison eliminated"); 1911 else 1912 fprintf (file, letter == 'C' ? "nh" : "h"); 1913 break; 1914 1915 default: 1916 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op))); 1917 break; 1918 } 1919} 1920 1921#undef TARGET_PRINT_OPERAND 1922#define TARGET_PRINT_OPERAND rl78_print_operand 1923 1924static void 1925rl78_print_operand (FILE * file, rtx op, int letter) 1926{ 1927 if (CONSTANT_P (op) && letter != 'u' && letter != 's' && letter != 'r' && letter != 'S' && letter != 'B') 1928 fprintf (file, "#"); 1929 rl78_print_operand_1 (file, op, letter); 1930} 1931 1932#undef TARGET_TRAMPOLINE_INIT 1933#define TARGET_TRAMPOLINE_INIT rl78_trampoline_init 1934 1935/* Note that the RL78's addressing makes it very difficult to do 1936 trampolines on the stack. So, libgcc has a small pool of 1937 trampolines from which one is allocated to this task. */ 1938static void 1939rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) 1940{ 1941 rtx mov_addr, thunk_addr; 1942 rtx function = XEXP (DECL_RTL (fndecl), 0); 1943 1944 mov_addr = adjust_address (m_tramp, HImode, 0); 1945 thunk_addr = gen_reg_rtx (HImode); 1946 1947 function = force_reg (HImode, function); 1948 static_chain = force_reg (HImode, static_chain); 1949 1950 emit_insn (gen_trampoline_init (thunk_addr, function, static_chain)); 1951 emit_move_insn (mov_addr, thunk_addr); 1952 1953 cfun->machine->trampolines_used = 1; 1954} 1955 1956#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS 1957#define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address 1958 1959static rtx 1960rl78_trampoline_adjust_address (rtx m_tramp) 1961{ 1962 rtx x = gen_rtx_MEM (HImode, m_tramp); 1963 return x; 1964} 1965 1966/* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of 1967 the "normal" compares, specifically, it only has unsigned compares, 1968 so we must synthesize the missing ones. */ 1969void 1970rl78_expand_compare (rtx *operands) 1971{ 1972 if (GET_CODE (operands[2]) == MEM) 1973 operands[2] = copy_to_mode_reg (GET_MODE (operands[2]), operands[2]); 1974} 1975 1976 1977 1978/* Define this to 1 if you are debugging the peephole optimizers. */ 1979#define DEBUG_PEEP 0 1980 1981/* Predicate used to enable the peephole2 patterns in rl78-virt.md. 1982 The default "word" size is a byte so we can effectively use all the 1983 registers, but we want to do 16-bit moves whenever possible. This 1984 function determines when such a move is an option. */ 1985bool 1986rl78_peep_movhi_p (rtx *operands) 1987{ 1988 int i; 1989 rtx m, a; 1990 1991 /* (set (op0) (op1)) 1992 (set (op2) (op3)) */ 1993 1994 if (! rl78_virt_insns_ok ()) 1995 return false; 1996 1997#if DEBUG_PEEP 1998 fprintf (stderr, "\033[33m"); 1999 debug_rtx (operands[0]); 2000 debug_rtx (operands[1]); 2001 debug_rtx (operands[2]); 2002 debug_rtx (operands[3]); 2003 fprintf (stderr, "\033[0m"); 2004#endif 2005 2006 /* You can move a constant to memory as QImode, but not HImode. */ 2007 if (GET_CODE (operands[0]) == MEM 2008 && GET_CODE (operands[1]) != REG) 2009 { 2010#if DEBUG_PEEP 2011 fprintf (stderr, "no peep: move constant to memory\n"); 2012#endif 2013 return false; 2014 } 2015 2016 if (rtx_equal_p (operands[0], operands[3])) 2017 { 2018#if DEBUG_PEEP 2019 fprintf (stderr, "no peep: overlapping\n"); 2020#endif 2021 return false; 2022 } 2023 2024 for (i = 0; i < 2; i ++) 2025 { 2026 if (GET_CODE (operands[i]) != GET_CODE (operands[i+2])) 2027 { 2028#if DEBUG_PEEP 2029 fprintf (stderr, "no peep: different codes\n"); 2030#endif 2031 return false; 2032 } 2033 if (GET_MODE (operands[i]) != GET_MODE (operands[i+2])) 2034 { 2035#if DEBUG_PEEP 2036 fprintf (stderr, "no peep: different modes\n"); 2037#endif 2038 return false; 2039 } 2040 2041 switch (GET_CODE (operands[i])) 2042 { 2043 case REG: 2044 /* LSB MSB */ 2045 if (REGNO (operands[i]) + 1 != REGNO (operands[i+2]) 2046 || GET_MODE (operands[i]) != QImode) 2047 { 2048#if DEBUG_PEEP 2049 fprintf (stderr, "no peep: wrong regnos %d %d %d\n", 2050 REGNO (operands[i]), REGNO (operands[i+2]), 2051 i); 2052#endif 2053 return false; 2054 } 2055 if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode)) 2056 { 2057#if DEBUG_PEEP 2058 fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i])); 2059#endif 2060 return false; 2061 } 2062 break; 2063 2064 case CONST_INT: 2065 break; 2066 2067 case MEM: 2068 if (GET_MODE (operands[i]) != QImode) 2069 return false; 2070 if (MEM_ALIGN (operands[i]) < 16) 2071 return false; 2072 a = XEXP (operands[i], 0); 2073 if (GET_CODE (a) == CONST) 2074 a = XEXP (a, 0); 2075 if (GET_CODE (a) == PLUS) 2076 a = XEXP (a, 1); 2077 if (GET_CODE (a) == CONST_INT 2078 && INTVAL (a) & 1) 2079 { 2080#if DEBUG_PEEP 2081 fprintf (stderr, "no peep: misaligned mem %d\n", i); 2082 debug_rtx (operands[i]); 2083#endif 2084 return false; 2085 } 2086 m = adjust_address (operands[i], QImode, 1); 2087 if (! rtx_equal_p (m, operands[i+2])) 2088 { 2089#if DEBUG_PEEP 2090 fprintf (stderr, "no peep: wrong mem %d\n", i); 2091 debug_rtx (m); 2092 debug_rtx (operands[i+2]); 2093#endif 2094 return false; 2095 } 2096 break; 2097 2098 default: 2099#if DEBUG_PEEP 2100 fprintf (stderr, "no peep: wrong rtx %d\n", i); 2101#endif 2102 return false; 2103 } 2104 } 2105#if DEBUG_PEEP 2106 fprintf (stderr, "\033[32mpeep!\033[0m\n"); 2107#endif 2108 return true; 2109} 2110 2111/* Likewise, when a peephole is activated, this function helps compute 2112 the new operands. */ 2113void 2114rl78_setup_peep_movhi (rtx *operands) 2115{ 2116 int i; 2117 2118 for (i = 0; i < 2; i ++) 2119 { 2120 switch (GET_CODE (operands[i])) 2121 { 2122 case REG: 2123 operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i])); 2124 break; 2125 2126 case CONST_INT: 2127 operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char) INTVAL (operands[i+2])) * 256); 2128 break; 2129 2130 case MEM: 2131 operands[i+4] = adjust_address (operands[i], HImode, 0); 2132 break; 2133 2134 default: 2135 break; 2136 } 2137 } 2138} 2139 2140/* 2141 How Devirtualization works in the RL78 GCC port 2142 2143Background 2144 2145The RL78 is an 8-bit port with some 16-bit operations. It has 32 2146bytes of register space, in four banks, memory-mapped. One bank is 2147the "selected" bank and holds the registers used for primary 2148operations. Since the registers are memory mapped, often you can 2149still refer to the unselected banks via memory accesses. 2150 2151Virtual Registers 2152 2153The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc) 2154and refers to the other banks via their memory addresses, although 2155they're treated as regular registers internally. These "virtual" 2156registers are R8 through R23 (bank3 is reserved for asm-based 2157interrupt handlers). 2158 2159There are four machine description files: 2160 2161rl78.md - common register-independent patterns and definitions 2162rl78-expand.md - expanders 2163rl78-virt.md - patterns that match BEFORE devirtualization 2164rl78-real.md - patterns that match AFTER devirtualization 2165 2166At least through register allocation and reload, gcc is told that it 2167can do pretty much anything - but may only use the virtual registers. 2168GCC cannot properly create the varying addressing modes that the RL78 2169supports in an efficient way. 2170 2171Sometime after reload, the RL78 backend "devirtualizes" the RTL. It 2172uses the "valloc" attribute in rl78-virt.md for determining the rules 2173by which it will replace virtual registers with real registers (or 2174not) and how to make up addressing modes. For example, insns tagged 2175with "ro1" have a single read-only parameter, which may need to be 2176moved from memory/constant/vreg to a suitable real register. As part 2177of devirtualization, a flag is toggled, disabling the rl78-virt.md 2178patterns and enabling the rl78-real.md patterns. The new patterns' 2179constraints are used to determine the real registers used. NOTE: 2180patterns in rl78-virt.md essentially ignore the constrains and rely on 2181predicates, where the rl78-real.md ones essentially ignore the 2182predicates and rely on the constraints. 2183 2184The devirtualization pass is scheduled via the pass manager (despite 2185being called "rl78_reorg") so it can be scheduled prior to var-track 2186(the idea is to let gdb know about the new registers). Ideally, it 2187would be scheduled right after pro/epilogue generation, so the 2188post-reload optimizers could operate on the real registers, but when I 2189tried that there were some issues building the target libraries. 2190 2191During devirtualization, a simple register move optimizer is run. It 2192would be better to run a full CSE/propogation pass on it though, but 2193that has not yet been attempted. 2194 2195 */ 2196#define DEBUG_ALLOC 0 2197 2198#define OP(x) (*recog_data.operand_loc[x]) 2199 2200/* This array is used to hold knowledge about the contents of the 2201 real registers (A ... H), the memory-based registers (r8 ... r31) 2202 and the first NUM_STACK_LOCS words on the stack. We use this to 2203 avoid generating redundant move instructions. 2204 2205 A value in the range 0 .. 31 indicates register A .. r31. 2206 A value in the range 32 .. 63 indicates stack slot (value - 32). 2207 A value of NOT_KNOWN indicates that the contents of that location 2208 are not known. */ 2209 2210#define NUM_STACK_LOCS 32 2211#define NOT_KNOWN 127 2212 2213static unsigned char content_memory [32 + NUM_STACK_LOCS]; 2214 2215static unsigned char saved_update_index = NOT_KNOWN; 2216static unsigned char saved_update_value; 2217static machine_mode saved_update_mode; 2218 2219 2220static inline void 2221clear_content_memory (void) 2222{ 2223 memset (content_memory, NOT_KNOWN, sizeof content_memory); 2224 if (dump_file) 2225 fprintf (dump_file, " clear content memory\n"); 2226 saved_update_index = NOT_KNOWN; 2227} 2228 2229/* Convert LOC into an index into the content_memory array. 2230 If LOC cannot be converted, return NOT_KNOWN. */ 2231 2232static unsigned char 2233get_content_index (rtx loc) 2234{ 2235 machine_mode mode; 2236 2237 if (loc == NULL_RTX) 2238 return NOT_KNOWN; 2239 2240 if (REG_P (loc)) 2241 { 2242 if (REGNO (loc) < 32) 2243 return REGNO (loc); 2244 return NOT_KNOWN; 2245 } 2246 2247 mode = GET_MODE (loc); 2248 2249 if (! rl78_stack_based_mem (loc, mode)) 2250 return NOT_KNOWN; 2251 2252 loc = XEXP (loc, 0); 2253 2254 if (REG_P (loc)) 2255 /* loc = MEM (SP) */ 2256 return 32; 2257 2258 /* loc = MEM (PLUS (SP, INT)). */ 2259 loc = XEXP (loc, 1); 2260 2261 if (INTVAL (loc) < NUM_STACK_LOCS) 2262 return 32 + INTVAL (loc); 2263 2264 return NOT_KNOWN; 2265} 2266 2267/* Return a string describing content INDEX in mode MODE. 2268 WARNING: Can return a pointer to a static buffer. */ 2269static const char * 2270get_content_name (unsigned char index, machine_mode mode) 2271{ 2272 static char buffer [128]; 2273 2274 if (index == NOT_KNOWN) 2275 return "Unknown"; 2276 2277 if (index > 31) 2278 sprintf (buffer, "stack slot %d", index - 32); 2279 else if (mode == HImode) 2280 sprintf (buffer, "%s%s", 2281 reg_names [index + 1], reg_names [index]); 2282 else 2283 return reg_names [index]; 2284 2285 return buffer; 2286} 2287 2288#if DEBUG_ALLOC 2289 2290static void 2291display_content_memory (FILE * file) 2292{ 2293 unsigned int i; 2294 2295 fprintf (file, " Known memory contents:\n"); 2296 2297 for (i = 0; i < sizeof content_memory; i++) 2298 if (content_memory[i] != NOT_KNOWN) 2299 { 2300 fprintf (file, " %s contains a copy of ", get_content_name (i, QImode)); 2301 fprintf (file, "%s\n", get_content_name (content_memory [i], QImode)); 2302 } 2303} 2304#endif 2305 2306static void 2307update_content (unsigned char index, unsigned char val, machine_mode mode) 2308{ 2309 unsigned int i; 2310 2311 gcc_assert (index < sizeof content_memory); 2312 2313 content_memory [index] = val; 2314 if (val != NOT_KNOWN) 2315 content_memory [val] = index; 2316 2317 /* Make the entry in dump_file *before* VAL is increased below. */ 2318 if (dump_file) 2319 { 2320 fprintf (dump_file, " %s now contains ", get_content_name (index, mode)); 2321 if (val == NOT_KNOWN) 2322 fprintf (dump_file, "Unknown\n"); 2323 else 2324 fprintf (dump_file, "%s and vice versa\n", get_content_name (val, mode)); 2325 } 2326 2327 if (mode == HImode) 2328 { 2329 val = val == NOT_KNOWN ? val : val + 1; 2330 2331 content_memory [index + 1] = val; 2332 if (val != NOT_KNOWN) 2333 { 2334 content_memory [val] = index + 1; 2335 -- val; 2336 } 2337 } 2338 2339 /* Any other places that had INDEX recorded as their contents are now invalid. */ 2340 for (i = 0; i < sizeof content_memory; i++) 2341 { 2342 if (i == index 2343 || (val != NOT_KNOWN && i == val)) 2344 { 2345 if (mode == HImode) 2346 ++ i; 2347 continue; 2348 } 2349 2350 if (content_memory[i] == index 2351 || (val != NOT_KNOWN && content_memory[i] == val)) 2352 { 2353 content_memory[i] = NOT_KNOWN; 2354 2355 if (dump_file) 2356 fprintf (dump_file, " %s cleared\n", get_content_name (i, mode)); 2357 2358 if (mode == HImode) 2359 content_memory[++ i] = NOT_KNOWN; 2360 } 2361 } 2362} 2363 2364/* Record that LOC contains VALUE. 2365 For HImode locations record that LOC+1 contains VALUE+1. 2366 If LOC is not a register or stack slot, do nothing. 2367 If VALUE is not a register or stack slot, clear the recorded content. */ 2368 2369static void 2370record_content (rtx loc, rtx value) 2371{ 2372 machine_mode mode; 2373 unsigned char index; 2374 unsigned char val; 2375 2376 if ((index = get_content_index (loc)) == NOT_KNOWN) 2377 return; 2378 2379 val = get_content_index (value); 2380 2381 mode = GET_MODE (loc); 2382 2383 if (val == index) 2384 { 2385 if (! optimize) 2386 return; 2387 2388 /* This should not happen when optimizing. */ 2389#if 1 2390 fprintf (stderr, "ASSIGNMENT of location to itself detected! [%s]\n", 2391 get_content_name (val, mode)); 2392 return; 2393#else 2394 gcc_unreachable (); 2395#endif 2396 } 2397 2398 update_content (index, val, mode); 2399} 2400 2401/* Returns TRUE if LOC already contains a copy of VALUE. */ 2402 2403static bool 2404already_contains (rtx loc, rtx value) 2405{ 2406 unsigned char index; 2407 unsigned char val; 2408 2409 if ((index = get_content_index (loc)) == NOT_KNOWN) 2410 return false; 2411 2412 if ((val = get_content_index (value)) == NOT_KNOWN) 2413 return false; 2414 2415 if (content_memory [index] != val) 2416 return false; 2417 2418 if (GET_MODE (loc) == HImode) 2419 return content_memory [index + 1] == val + 1; 2420 2421 return true; 2422} 2423 2424bool 2425rl78_es_addr (rtx addr) 2426{ 2427 if (GET_CODE (addr) == MEM) 2428 addr = XEXP (addr, 0); 2429 if (GET_CODE (addr) != UNSPEC) 2430 return false; 2431 if (XINT (addr, 1) != UNS_ES_ADDR) 2432 return false; 2433 return true; 2434} 2435 2436rtx 2437rl78_es_base (rtx addr) 2438{ 2439 if (GET_CODE (addr) == MEM) 2440 addr = XEXP (addr, 0); 2441 addr = XVECEXP (addr, 0, 1); 2442 if (GET_CODE (addr) == CONST 2443 && GET_CODE (XEXP (addr, 0)) == ZERO_EXTRACT) 2444 addr = XEXP (XEXP (addr, 0), 0); 2445 /* Mode doesn't matter here. */ 2446 return gen_rtx_MEM (HImode, addr); 2447} 2448 2449/* Rescans an insn to see if it's recognized again. This is done 2450 carefully to ensure that all the constraint information is accurate 2451 for the newly matched insn. */ 2452static bool 2453insn_ok_now (rtx_insn * insn) 2454{ 2455 rtx pattern = PATTERN (insn); 2456 int i; 2457 2458 INSN_CODE (insn) = -1; 2459 2460 if (recog (pattern, insn, 0) > -1) 2461 { 2462 extract_insn (insn); 2463 if (constrain_operands (1, get_preferred_alternatives (insn))) 2464 { 2465#if DEBUG_ALLOC 2466 fprintf (stderr, "\033[32m"); 2467 debug_rtx (insn); 2468 fprintf (stderr, "\033[0m"); 2469#endif 2470 if (SET_P (pattern)) 2471 record_content (SET_DEST (pattern), SET_SRC (pattern)); 2472 2473 /* We need to detect far addresses that haven't been 2474 converted to es/lo16 format. */ 2475 for (i=0; i<recog_data.n_operands; i++) 2476 if (GET_CODE (OP (i)) == MEM 2477 && GET_MODE (XEXP (OP (i), 0)) == SImode 2478 && GET_CODE (XEXP (OP (i), 0)) != UNSPEC) 2479 return false; 2480 2481 return true; 2482 } 2483 } 2484 else 2485 { 2486 /* We need to re-recog the insn with virtual registers to get 2487 the operands. */ 2488 cfun->machine->virt_insns_ok = 1; 2489 if (recog (pattern, insn, 0) > -1) 2490 { 2491 extract_insn (insn); 2492 if (constrain_operands (0, get_preferred_alternatives (insn))) 2493 { 2494 cfun->machine->virt_insns_ok = 0; 2495 return false; 2496 } 2497 } 2498 2499#if DEBUG_ALLOC 2500 fprintf (stderr, "\033[41;30m Unrecognized *virtual* insn \033[0m\n"); 2501 debug_rtx (insn); 2502#endif 2503 gcc_unreachable (); 2504 } 2505 2506#if DEBUG_ALLOC 2507 fprintf (stderr, "\033[31m"); 2508 debug_rtx (insn); 2509 fprintf (stderr, "\033[0m"); 2510#endif 2511 return false; 2512} 2513 2514#if DEBUG_ALLOC 2515#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__) 2516#define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__) 2517#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable () 2518#define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; } 2519#define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED 2520#else 2521#define FAILED gcc_unreachable () 2522#define MAYBE_OK(insn) if (insn_ok_now (insn)) return; 2523#define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED 2524#endif 2525 2526/* Registers into which we move the contents of virtual registers. */ 2527#define X gen_rtx_REG (QImode, X_REG) 2528#define A gen_rtx_REG (QImode, A_REG) 2529#define C gen_rtx_REG (QImode, C_REG) 2530#define B gen_rtx_REG (QImode, B_REG) 2531#define E gen_rtx_REG (QImode, E_REG) 2532#define D gen_rtx_REG (QImode, D_REG) 2533#define L gen_rtx_REG (QImode, L_REG) 2534#define H gen_rtx_REG (QImode, H_REG) 2535 2536#define AX gen_rtx_REG (HImode, AX_REG) 2537#define BC gen_rtx_REG (HImode, BC_REG) 2538#define DE gen_rtx_REG (HImode, DE_REG) 2539#define HL gen_rtx_REG (HImode, HL_REG) 2540 2541/* Returns TRUE if R is a virtual register. */ 2542static inline bool 2543is_virtual_register (rtx r) 2544{ 2545 return (GET_CODE (r) == REG 2546 && REGNO (r) >= 8 2547 && REGNO (r) < 32); 2548} 2549 2550/* In all these alloc routines, we expect the following: the insn 2551 pattern is unshared, the insn was previously recognized and failed 2552 due to predicates or constraints, and the operand data is in 2553 recog_data. */ 2554 2555static int virt_insn_was_frame; 2556 2557/* Hook for all insns we emit. Re-mark them as FRAME_RELATED if 2558 needed. */ 2559static rtx 2560EM2 (int line ATTRIBUTE_UNUSED, rtx r) 2561{ 2562#if DEBUG_ALLOC 2563 fprintf (stderr, "\033[36m%d: ", line); 2564 debug_rtx (r); 2565 fprintf (stderr, "\033[0m"); 2566#endif 2567 /*SCHED_GROUP_P (r) = 1;*/ 2568 if (virt_insn_was_frame) 2569 RTX_FRAME_RELATED_P (r) = 1; 2570 return r; 2571} 2572 2573#define EM(x) EM2 (__LINE__, x) 2574 2575/* Return a suitable RTX for the low half of a __far address. */ 2576static rtx 2577rl78_lo16 (rtx addr) 2578{ 2579 rtx r; 2580 2581 if (GET_CODE (addr) == SYMBOL_REF 2582 || GET_CODE (addr) == CONST) 2583 { 2584 r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0)); 2585 r = gen_rtx_CONST (HImode, r); 2586 } 2587 else 2588 r = rl78_subreg (HImode, addr, SImode, 0); 2589 2590 r = gen_es_addr (r); 2591 cfun->machine->uses_es = true; 2592 2593 return r; 2594} 2595 2596/* Return a suitable RTX for the high half's lower byte of a __far address. */ 2597static rtx 2598rl78_hi8 (rtx addr) 2599{ 2600 if (GET_CODE (addr) == SYMBOL_REF 2601 || GET_CODE (addr) == CONST) 2602 { 2603 rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16)); 2604 r = gen_rtx_CONST (QImode, r); 2605 return r; 2606 } 2607 return rl78_subreg (QImode, addr, SImode, 2); 2608} 2609 2610static void 2611add_postponed_content_update (rtx to, rtx value) 2612{ 2613 unsigned char index; 2614 2615 if ((index = get_content_index (to)) == NOT_KNOWN) 2616 return; 2617 2618 gcc_assert (saved_update_index == NOT_KNOWN); 2619 saved_update_index = index; 2620 saved_update_value = get_content_index (value); 2621 saved_update_mode = GET_MODE (to); 2622} 2623 2624static void 2625process_postponed_content_update (void) 2626{ 2627 if (saved_update_index != NOT_KNOWN) 2628 { 2629 update_content (saved_update_index, saved_update_value, saved_update_mode); 2630 saved_update_index = NOT_KNOWN; 2631 } 2632} 2633 2634/* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL 2635 then if BEFORE is true then emit the insn before WHERE, otherwise emit it 2636 after WHERE. If TO already contains FROM then do nothing. Returns TO if 2637 BEFORE is true, FROM otherwise. */ 2638static rtx 2639gen_and_emit_move (rtx to, rtx from, rtx where, bool before) 2640{ 2641 machine_mode mode = GET_MODE (to); 2642 2643 if (optimize && before && already_contains (to, from)) 2644 { 2645#if DEBUG_ALLOC 2646 display_content_memory (stderr); 2647#endif 2648 if (dump_file) 2649 { 2650 fprintf (dump_file, " Omit move of %s into ", 2651 get_content_name (get_content_index (from), mode)); 2652 fprintf (dump_file, "%s as it already contains this value\n", 2653 get_content_name (get_content_index (to), mode)); 2654 } 2655 } 2656 else 2657 { 2658 rtx move = mode == QImode ? gen_movqi (to, from) : gen_movhi (to, from); 2659 2660 EM (move); 2661 2662 if (where == NULL_RTX) 2663 emit_insn (move); 2664 else if (before) 2665 emit_insn_before (move, where); 2666 else 2667 { 2668 rtx note = find_reg_note (where, REG_EH_REGION, NULL_RTX); 2669 2670 /* If necessary move REG_EH_REGION notes forward. 2671 cf. compiling gcc.dg/pr44545.c. */ 2672 if (note != NULL_RTX) 2673 { 2674 add_reg_note (move, REG_EH_REGION, XEXP (note, 0)); 2675 remove_note (where, note); 2676 } 2677 2678 emit_insn_after (move, where); 2679 } 2680 2681 if (before) 2682 record_content (to, from); 2683 else 2684 add_postponed_content_update (to, from); 2685 } 2686 2687 return before ? to : from; 2688} 2689 2690/* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then 2691 copy it into NEWBASE and return the updated MEM. Otherwise just 2692 return M. Any needed insns are emitted before BEFORE. */ 2693static rtx 2694transcode_memory_rtx (rtx m, rtx newbase, rtx before) 2695{ 2696 rtx base, index, addendr; 2697 int addend = 0; 2698 int need_es = 0; 2699 2700 if (! MEM_P (m)) 2701 return m; 2702 2703 if (GET_MODE (XEXP (m, 0)) == SImode) 2704 { 2705 rtx new_m; 2706 rtx seg = rl78_hi8 (XEXP (m, 0)); 2707 2708 if (!TARGET_ES0) 2709 { 2710 emit_insn_before (EM (gen_movqi (A, seg)), before); 2711 emit_insn_before (EM (gen_movqi_to_es (A)), before); 2712 } 2713 2714 record_content (A, NULL_RTX); 2715 2716 new_m = gen_rtx_MEM (GET_MODE (m), rl78_lo16 (XEXP (m, 0))); 2717 MEM_COPY_ATTRIBUTES (new_m, m); 2718 m = new_m; 2719 need_es = 1; 2720 } 2721 2722 characterize_address (XEXP (m, 0), & base, & index, & addendr); 2723 gcc_assert (index == NULL_RTX); 2724 2725 if (base == NULL_RTX) 2726 return m; 2727 2728 if (addendr && GET_CODE (addendr) == CONST_INT) 2729 addend = INTVAL (addendr); 2730 2731 gcc_assert (REG_P (base)); 2732 gcc_assert (REG_P (newbase)); 2733 2734 int limit = 256 - GET_MODE_SIZE (GET_MODE (m)); 2735 2736 if (REGNO (base) == SP_REG) 2737 { 2738 if (addend >= 0 && addend <= limit) 2739 return m; 2740 } 2741 2742 /* BASE should be a virtual register. We copy it to NEWBASE. If 2743 the addend is out of range for DE/HL, we use AX to compute the full 2744 address. */ 2745 2746 if (addend < 0 2747 || (addend > limit && REGNO (newbase) != BC_REG) 2748 || (addendr 2749 && (GET_CODE (addendr) != CONST_INT) 2750 && ((REGNO (newbase) != BC_REG)) 2751 )) 2752 { 2753 /* mov ax, vreg 2754 add ax, #imm 2755 mov hl, ax */ 2756 EM (emit_insn_before (gen_movhi (AX, base), before)); 2757 EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before)); 2758 EM (emit_insn_before (gen_movhi (newbase, AX), before)); 2759 record_content (AX, NULL_RTX); 2760 record_content (newbase, NULL_RTX); 2761 2762 base = newbase; 2763 addend = 0; 2764 addendr = 0; 2765 } 2766 else 2767 { 2768 base = gen_and_emit_move (newbase, base, before, true); 2769 } 2770 2771 if (addend) 2772 { 2773 record_content (base, NULL_RTX); 2774 base = gen_rtx_PLUS (HImode, base, GEN_INT (addend)); 2775 } 2776 else if (addendr) 2777 { 2778 record_content (base, NULL_RTX); 2779 base = gen_rtx_PLUS (HImode, base, addendr); 2780 } 2781 2782 if (need_es) 2783 { 2784 m = change_address (m, GET_MODE (m), gen_es_addr (base)); 2785 cfun->machine->uses_es = true; 2786 } 2787 else 2788 m = change_address (m, GET_MODE (m), base); 2789 return m; 2790} 2791 2792/* Copy SRC to accumulator (A or AX), placing any generated insns 2793 before BEFORE. Returns accumulator RTX. */ 2794static rtx 2795move_to_acc (int opno, rtx before) 2796{ 2797 rtx src = OP (opno); 2798 machine_mode mode = GET_MODE (src); 2799 2800 if (REG_P (src) && REGNO (src) < 2) 2801 return src; 2802 2803 if (mode == VOIDmode) 2804 mode = recog_data.operand_mode[opno]; 2805 2806 return gen_and_emit_move (mode == QImode ? A : AX, src, before, true); 2807} 2808 2809static void 2810force_into_acc (rtx src, rtx before) 2811{ 2812 machine_mode mode = GET_MODE (src); 2813 rtx move; 2814 2815 if (REG_P (src) && REGNO (src) < 2) 2816 return; 2817 2818 move = mode == QImode ? gen_movqi (A, src) : gen_movhi (AX, src); 2819 2820 EM (move); 2821 2822 emit_insn_before (move, before); 2823 record_content (AX, NULL_RTX); 2824} 2825 2826/* Copy accumulator (A or AX) to DEST, placing any generated insns 2827 after AFTER. Returns accumulator RTX. */ 2828static rtx 2829move_from_acc (unsigned int opno, rtx after) 2830{ 2831 rtx dest = OP (opno); 2832 machine_mode mode = GET_MODE (dest); 2833 2834 if (REG_P (dest) && REGNO (dest) < 2) 2835 return dest; 2836 2837 return gen_and_emit_move (dest, mode == QImode ? A : AX, after, false); 2838} 2839 2840/* Copy accumulator (A or AX) to REGNO, placing any generated insns 2841 before BEFORE. Returns reg RTX. */ 2842static rtx 2843move_acc_to_reg (rtx acc, int regno, rtx before) 2844{ 2845 machine_mode mode = GET_MODE (acc); 2846 rtx reg; 2847 2848 reg = gen_rtx_REG (mode, regno); 2849 2850 return gen_and_emit_move (reg, acc, before, true); 2851} 2852 2853/* Copy SRC to X, placing any generated insns before BEFORE. 2854 Returns X RTX. */ 2855static rtx 2856move_to_x (int opno, rtx before) 2857{ 2858 rtx src = OP (opno); 2859 machine_mode mode = GET_MODE (src); 2860 rtx reg; 2861 2862 if (mode == VOIDmode) 2863 mode = recog_data.operand_mode[opno]; 2864 reg = (mode == QImode) ? X : AX; 2865 2866 if (mode == QImode || ! is_virtual_register (OP (opno))) 2867 { 2868 OP (opno) = move_to_acc (opno, before); 2869 OP (opno) = move_acc_to_reg (OP (opno), X_REG, before); 2870 return reg; 2871 } 2872 2873 return gen_and_emit_move (reg, src, before, true); 2874} 2875 2876/* Copy OP (opno) to H or HL, placing any generated insns before BEFORE. 2877 Returns H/HL RTX. */ 2878static rtx 2879move_to_hl (int opno, rtx before) 2880{ 2881 rtx src = OP (opno); 2882 machine_mode mode = GET_MODE (src); 2883 rtx reg; 2884 2885 if (mode == VOIDmode) 2886 mode = recog_data.operand_mode[opno]; 2887 reg = (mode == QImode) ? L : HL; 2888 2889 if (mode == QImode || ! is_virtual_register (OP (opno))) 2890 { 2891 OP (opno) = move_to_acc (opno, before); 2892 OP (opno) = move_acc_to_reg (OP (opno), L_REG, before); 2893 return reg; 2894 } 2895 2896 return gen_and_emit_move (reg, src, before, true); 2897} 2898 2899/* Copy OP (opno) to E or DE, placing any generated insns before BEFORE. 2900 Returns E/DE RTX. */ 2901static rtx 2902move_to_de (int opno, rtx before) 2903{ 2904 rtx src = OP (opno); 2905 machine_mode mode = GET_MODE (src); 2906 rtx reg; 2907 2908 if (mode == VOIDmode) 2909 mode = recog_data.operand_mode[opno]; 2910 2911 reg = (mode == QImode) ? E : DE; 2912 2913 if (mode == QImode || ! is_virtual_register (OP (opno))) 2914 { 2915 OP (opno) = move_to_acc (opno, before); 2916 OP (opno) = move_acc_to_reg (OP (opno), E_REG, before); 2917 } 2918 else 2919 { 2920 gen_and_emit_move (reg, src, before, true); 2921 } 2922 2923 return reg; 2924} 2925 2926/* Devirtualize an insn of the form (SET (op) (unop (op))). */ 2927static void 2928rl78_alloc_physical_registers_op1 (rtx_insn * insn) 2929{ 2930 /* op[0] = func op[1] */ 2931 2932 /* We first try using A as the destination, then copying it 2933 back. */ 2934 if (rtx_equal_p (OP (0), OP (1))) 2935 { 2936 OP (0) = 2937 OP (1) = transcode_memory_rtx (OP (1), DE, insn); 2938 } 2939 else 2940 { 2941 /* If necessary, load the operands into BC and HL. 2942 Check to see if we already have OP (0) in HL 2943 and if so, swap the order. 2944 2945 It is tempting to perform this optimization when OP(0) does 2946 not hold a MEM, but this leads to bigger code in general. 2947 The problem is that if OP(1) holds a MEM then swapping it 2948 into BC means a BC-relative load is used and these are 3 2949 bytes long vs 1 byte for an HL load. */ 2950 if (MEM_P (OP (0)) 2951 && already_contains (HL, XEXP (OP (0), 0))) 2952 { 2953 OP (0) = transcode_memory_rtx (OP (0), HL, insn); 2954 OP (1) = transcode_memory_rtx (OP (1), BC, insn); 2955 } 2956 else 2957 { 2958 OP (0) = transcode_memory_rtx (OP (0), BC, insn); 2959 OP (1) = transcode_memory_rtx (OP (1), HL, insn); 2960 } 2961 } 2962 2963 MAYBE_OK (insn); 2964 2965 OP (0) = move_from_acc (0, insn); 2966 2967 MAYBE_OK (insn); 2968 2969 /* Try copying the src to acc first, then. This is for, for 2970 example, ZERO_EXTEND or NOT. */ 2971 OP (1) = move_to_acc (1, insn); 2972 2973 MUST_BE_OK (insn); 2974} 2975 2976/* Returns true if operand OPNUM contains a constraint of type CONSTRAINT. 2977 Assumes that the current insn has already been recognised and hence the 2978 constraint data has been filled in. */ 2979static bool 2980has_constraint (unsigned int opnum, enum constraint_num constraint) 2981{ 2982 const char * p = recog_data.constraints[opnum]; 2983 2984 /* No constraints means anything is accepted. */ 2985 if (p == NULL || *p == 0 || *p == ',') 2986 return true; 2987 2988 do 2989 { 2990 char c; 2991 unsigned int len; 2992 2993 c = *p; 2994 len = CONSTRAINT_LEN (c, p); 2995 gcc_assert (len > 0); 2996 2997 switch (c) 2998 { 2999 case 0: 3000 case ',': 3001 return false; 3002 default: 3003 if (lookup_constraint (p) == constraint) 3004 return true; 3005 } 3006 p += len; 3007 } 3008 while (1); 3009} 3010 3011/* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */ 3012static void 3013rl78_alloc_physical_registers_op2 (rtx_insn * insn) 3014{ 3015 rtx prev; 3016 rtx first; 3017 bool hl_used; 3018 int tmp_id; 3019 rtx saved_op1; 3020 3021 if (rtx_equal_p (OP (0), OP (1))) 3022 { 3023 if (MEM_P (OP (2))) 3024 { 3025 OP (0) = 3026 OP (1) = transcode_memory_rtx (OP (1), DE, insn); 3027 OP (2) = transcode_memory_rtx (OP (2), HL, insn); 3028 } 3029 else 3030 { 3031 OP (0) = 3032 OP (1) = transcode_memory_rtx (OP (1), HL, insn); 3033 OP (2) = transcode_memory_rtx (OP (2), DE, insn); 3034 } 3035 } 3036 else if (rtx_equal_p (OP (0), OP (2))) 3037 { 3038 OP (1) = transcode_memory_rtx (OP (1), DE, insn); 3039 OP (0) = 3040 OP (2) = transcode_memory_rtx (OP (2), HL, insn); 3041 } 3042 else 3043 { 3044 OP (0) = transcode_memory_rtx (OP (0), BC, insn); 3045 OP (1) = transcode_memory_rtx (OP (1), DE, insn); 3046 OP (2) = transcode_memory_rtx (OP (2), HL, insn); 3047 } 3048 3049 MAYBE_OK (insn); 3050 3051 prev = prev_nonnote_nondebug_insn (insn); 3052 if (recog_data.constraints[1][0] == '%' 3053 && is_virtual_register (OP (1)) 3054 && ! is_virtual_register (OP (2)) 3055 && ! CONSTANT_P (OP (2))) 3056 { 3057 rtx tmp = OP (1); 3058 OP (1) = OP (2); 3059 OP (2) = tmp; 3060 } 3061 3062 /* Make a note of whether (H)L is being used. It matters 3063 because if OP (2) also needs reloading, then we must take 3064 care not to corrupt HL. */ 3065 hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1)); 3066 3067 /* If HL is not currently being used and dest == op1 then there are 3068 some possible optimizations available by reloading one of the 3069 operands into HL, before trying to use the accumulator. */ 3070 if (optimize 3071 && ! hl_used 3072 && rtx_equal_p (OP (0), OP (1))) 3073 { 3074 /* If op0 is a Ws1 type memory address then switching the base 3075 address register to HL might allow us to perform an in-memory 3076 operation. (eg for the INCW instruction). 3077 3078 FIXME: Adding the move into HL is costly if this optimization is not 3079 going to work, so for now, make sure that we know that the new insn will 3080 match the requirements of the addhi3_real pattern. Really we ought to 3081 generate a candidate sequence, test that, and then install it if the 3082 results are good. */ 3083 if (satisfies_constraint_Ws1 (OP (0)) 3084 && has_constraint (0, CONSTRAINT_Wh1) 3085 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2)))) 3086 { 3087 rtx base, index, addend, newbase; 3088 3089 characterize_address (XEXP (OP (0), 0), & base, & index, & addend); 3090 gcc_assert (index == NULL_RTX); 3091 gcc_assert (REG_P (base) && REGNO (base) == SP_REG); 3092 3093 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */ 3094 if (addend != NULL_RTX) 3095 { 3096 newbase = gen_and_emit_move (HL, base, insn, true); 3097 record_content (newbase, NULL_RTX); 3098 newbase = gen_rtx_PLUS (HImode, newbase, addend); 3099 3100 OP (0) = OP (1) = change_address (OP (0), VOIDmode, newbase); 3101 3102 /* We do not want to fail here as this means that 3103 we have inserted useless insns into the stream. */ 3104 MUST_BE_OK (insn); 3105 } 3106 } 3107 else if (REG_P (OP (0)) 3108 && satisfies_constraint_Ws1 (OP (2)) 3109 && has_constraint (2, CONSTRAINT_Wh1)) 3110 { 3111 rtx base, index, addend, newbase; 3112 3113 characterize_address (XEXP (OP (2), 0), & base, & index, & addend); 3114 gcc_assert (index == NULL_RTX); 3115 gcc_assert (REG_P (base) && REGNO (base) == SP_REG); 3116 3117 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */ 3118 if (addend != NULL_RTX) 3119 { 3120 gen_and_emit_move (HL, base, insn, true); 3121 3122 if (REGNO (OP (0)) != X_REG) 3123 { 3124 OP (1) = move_to_acc (1, insn); 3125 OP (0) = move_from_acc (0, insn); 3126 } 3127 3128 record_content (HL, NULL_RTX); 3129 newbase = gen_rtx_PLUS (HImode, HL, addend); 3130 3131 OP (2) = change_address (OP (2), VOIDmode, newbase); 3132 3133 /* We do not want to fail here as this means that 3134 we have inserted useless insns into the stream. */ 3135 MUST_BE_OK (insn); 3136 } 3137 } 3138 } 3139 3140 OP (0) = move_from_acc (0, insn); 3141 3142 tmp_id = get_max_insn_count (); 3143 saved_op1 = OP (1); 3144 3145 if (rtx_equal_p (OP (1), OP (2))) 3146 OP (2) = OP (1) = move_to_acc (1, insn); 3147 else 3148 OP (1) = move_to_acc (1, insn); 3149 3150 MAYBE_OK (insn); 3151 3152 /* If we omitted the move of OP1 into the accumulator (because 3153 it was already there from a previous insn), then force the 3154 generation of the move instruction now. We know that we 3155 are about to emit a move into HL (or DE) via AX, and hence 3156 our optimization to remove the load of OP1 is no longer valid. */ 3157 if (tmp_id == get_max_insn_count ()) 3158 force_into_acc (saved_op1, insn); 3159 3160 /* We have to copy op2 to HL (or DE), but that involves AX, which 3161 already has a live value. Emit it before those insns. */ 3162 3163 if (prev) 3164 first = next_nonnote_nondebug_insn (prev); 3165 else 3166 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first)) 3167 ; 3168 3169 OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first); 3170 3171 MUST_BE_OK (insn); 3172} 3173 3174/* Devirtualize an insn of the form SET (PC) (MEM/REG). */ 3175static void 3176rl78_alloc_physical_registers_ro1 (rtx_insn * insn) 3177{ 3178 OP (0) = transcode_memory_rtx (OP (0), BC, insn); 3179 3180 MAYBE_OK (insn); 3181 3182 OP (0) = move_to_acc (0, insn); 3183 3184 MUST_BE_OK (insn); 3185} 3186 3187/* Devirtualize a compare insn. */ 3188static void 3189rl78_alloc_physical_registers_cmp (rtx_insn * insn) 3190{ 3191 int tmp_id; 3192 rtx saved_op1; 3193 rtx prev = prev_nonnote_nondebug_insn (insn); 3194 rtx first; 3195 3196 OP (1) = transcode_memory_rtx (OP (1), DE, insn); 3197 OP (2) = transcode_memory_rtx (OP (2), HL, insn); 3198 3199 /* HI compares have to have OP (1) in AX, but QI 3200 compares do not, so it is worth checking here. */ 3201 MAYBE_OK (insn); 3202 3203 /* For an HImode compare, OP (1) must always be in AX. 3204 But if OP (1) is a REG (and not AX), then we can avoid 3205 a reload of OP (1) if we reload OP (2) into AX and invert 3206 the comparison. */ 3207 if (REG_P (OP (1)) 3208 && REGNO (OP (1)) != AX_REG 3209 && GET_MODE (OP (1)) == HImode 3210 && MEM_P (OP (2))) 3211 { 3212 rtx cmp = XEXP (SET_SRC (PATTERN (insn)), 0); 3213 3214 OP (2) = move_to_acc (2, insn); 3215 3216 switch (GET_CODE (cmp)) 3217 { 3218 case EQ: 3219 case NE: 3220 break; 3221 case LTU: cmp = gen_rtx_GTU (HImode, OP (2), OP (1)); break; 3222 case GTU: cmp = gen_rtx_LTU (HImode, OP (2), OP (1)); break; 3223 case LEU: cmp = gen_rtx_GEU (HImode, OP (2), OP (1)); break; 3224 case GEU: cmp = gen_rtx_LEU (HImode, OP (2), OP (1)); break; 3225 3226 case LT: 3227 case GT: 3228 case LE: 3229 case GE: 3230#if DEBUG_ALLOC 3231 debug_rtx (insn); 3232#endif 3233 default: 3234 gcc_unreachable (); 3235 } 3236 3237 if (GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE) 3238 PATTERN (insn) = gen_cbranchhi4_real (cmp, OP (2), OP (1), OP (3)); 3239 else 3240 PATTERN (insn) = gen_cbranchhi4_real_inverted (cmp, OP (2), OP (1), OP (3)); 3241 3242 MUST_BE_OK (insn); 3243 } 3244 3245 /* Surprisingly, gcc can generate a comparison of a register with itself, but this 3246 should be handled by the second alternative of the cbranchhi_real pattern. */ 3247 if (rtx_equal_p (OP (1), OP (2))) 3248 { 3249 OP (1) = OP (2) = BC; 3250 MUST_BE_OK (insn); 3251 } 3252 3253 tmp_id = get_max_insn_count (); 3254 saved_op1 = OP (1); 3255 3256 OP (1) = move_to_acc (1, insn); 3257 3258 MAYBE_OK (insn); 3259 3260 /* If we omitted the move of OP1 into the accumulator (because 3261 it was already there from a previous insn), then force the 3262 generation of the move instruction now. We know that we 3263 are about to emit a move into HL via AX, and hence our 3264 optimization to remove the load of OP1 is no longer valid. */ 3265 if (tmp_id == get_max_insn_count ()) 3266 force_into_acc (saved_op1, insn); 3267 3268 /* We have to copy op2 to HL, but that involves the acc, which 3269 already has a live value. Emit it before those insns. */ 3270 if (prev) 3271 first = next_nonnote_nondebug_insn (prev); 3272 else 3273 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first)) 3274 ; 3275 OP (2) = move_to_hl (2, first); 3276 3277 MUST_BE_OK (insn); 3278} 3279 3280/* Like op2, but AX = A * X. */ 3281static void 3282rl78_alloc_physical_registers_umul (rtx_insn * insn) 3283{ 3284 rtx prev = prev_nonnote_nondebug_insn (insn); 3285 rtx first; 3286 int tmp_id; 3287 rtx saved_op1; 3288 3289 OP (0) = transcode_memory_rtx (OP (0), BC, insn); 3290 OP (1) = transcode_memory_rtx (OP (1), DE, insn); 3291 OP (2) = transcode_memory_rtx (OP (2), HL, insn); 3292 3293 MAYBE_OK (insn); 3294 3295 if (recog_data.constraints[1][0] == '%' 3296 && is_virtual_register (OP (1)) 3297 && !is_virtual_register (OP (2)) 3298 && !CONSTANT_P (OP (2))) 3299 { 3300 rtx tmp = OP (1); 3301 OP (1) = OP (2); 3302 OP (2) = tmp; 3303 } 3304 3305 OP (0) = move_from_acc (0, insn); 3306 3307 tmp_id = get_max_insn_count (); 3308 saved_op1 = OP (1); 3309 3310 if (rtx_equal_p (OP (1), OP (2))) 3311 { 3312 gcc_assert (GET_MODE (OP (2)) == QImode); 3313 /* The MULU instruction does not support duplicate arguments 3314 but we know that if we copy OP (2) to X it will do so via 3315 A and thus OP (1) will already be loaded into A. */ 3316 OP (2) = move_to_x (2, insn); 3317 OP (1) = A; 3318 } 3319 else 3320 OP (1) = move_to_acc (1, insn); 3321 3322 MAYBE_OK (insn); 3323 3324 /* If we omitted the move of OP1 into the accumulator (because 3325 it was already there from a previous insn), then force the 3326 generation of the move instruction now. We know that we 3327 are about to emit a move into HL (or DE) via AX, and hence 3328 our optimization to remove the load of OP1 is no longer valid. */ 3329 if (tmp_id == get_max_insn_count ()) 3330 force_into_acc (saved_op1, insn); 3331 3332 /* We have to copy op2 to X, but that involves the acc, which 3333 already has a live value. Emit it before those insns. */ 3334 3335 if (prev) 3336 first = next_nonnote_nondebug_insn (prev); 3337 else 3338 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first)) 3339 ; 3340 OP (2) = move_to_x (2, first); 3341 3342 MUST_BE_OK (insn); 3343} 3344 3345static void 3346rl78_alloc_address_registers_macax (rtx_insn * insn) 3347{ 3348 int which, op; 3349 bool replace_in_op0 = false; 3350 bool replace_in_op1 = false; 3351 3352 MAYBE_OK (insn); 3353 3354 /* Two different MEMs are not allowed. */ 3355 which = 0; 3356 for (op = 2; op >= 0; op --) 3357 { 3358 if (MEM_P (OP (op))) 3359 { 3360 if (op == 0 && replace_in_op0) 3361 continue; 3362 if (op == 1 && replace_in_op1) 3363 continue; 3364 3365 switch (which) 3366 { 3367 case 0: 3368 /* If we replace a MEM, make sure that we replace it for all 3369 occurrences of the same MEM in the insn. */ 3370 replace_in_op0 = (op > 0 && rtx_equal_p (OP (op), OP (0))); 3371 replace_in_op1 = (op > 1 && rtx_equal_p (OP (op), OP (1))); 3372 3373 OP (op) = transcode_memory_rtx (OP (op), HL, insn); 3374 if (op == 2 3375 && MEM_P (OP (op)) 3376 && ((GET_CODE (XEXP (OP (op), 0)) == REG 3377 && REGNO (XEXP (OP (op), 0)) == SP_REG) 3378 || (GET_CODE (XEXP (OP (op), 0)) == PLUS 3379 && REGNO (XEXP (XEXP (OP (op), 0), 0)) == SP_REG))) 3380 { 3381 emit_insn_before (gen_movhi (HL, gen_rtx_REG (HImode, SP_REG)), insn); 3382 OP (op) = replace_rtx (OP (op), gen_rtx_REG (HImode, SP_REG), HL); 3383 } 3384 if (replace_in_op0) 3385 OP (0) = OP (op); 3386 if (replace_in_op1) 3387 OP (1) = OP (op); 3388 break; 3389 case 1: 3390 OP (op) = transcode_memory_rtx (OP (op), DE, insn); 3391 break; 3392 case 2: 3393 OP (op) = transcode_memory_rtx (OP (op), BC, insn); 3394 break; 3395 } 3396 which ++; 3397 } 3398 } 3399 3400 MUST_BE_OK (insn); 3401} 3402 3403static void 3404rl78_alloc_address_registers_div (rtx_insn * insn) 3405{ 3406 MUST_BE_OK (insn); 3407} 3408 3409/* Scan all insns and devirtualize them. */ 3410static void 3411rl78_alloc_physical_registers (void) 3412{ 3413 /* During most of the compile, gcc is dealing with virtual 3414 registers. At this point, we need to assign physical registers 3415 to the vitual ones, and copy in/out as needed. */ 3416 3417 rtx_insn *insn, *curr; 3418 enum attr_valloc valloc_method; 3419 3420 for (insn = get_insns (); insn; insn = curr) 3421 { 3422 int i; 3423 3424 curr = next_nonnote_nondebug_insn (insn); 3425 3426 if (INSN_P (insn) 3427 && (GET_CODE (PATTERN (insn)) == SET 3428 || GET_CODE (PATTERN (insn)) == CALL) 3429 && INSN_CODE (insn) == -1) 3430 { 3431 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS) 3432 continue; 3433 i = recog (PATTERN (insn), insn, 0); 3434 if (i == -1) 3435 { 3436 debug_rtx (insn); 3437 gcc_unreachable (); 3438 } 3439 INSN_CODE (insn) = i; 3440 } 3441 } 3442 3443 cfun->machine->virt_insns_ok = 0; 3444 cfun->machine->real_insns_ok = 1; 3445 3446 clear_content_memory (); 3447 3448 for (insn = get_insns (); insn; insn = curr) 3449 { 3450 rtx pattern; 3451 3452 curr = insn ? next_nonnote_nondebug_insn (insn) : NULL; 3453 3454 if (!INSN_P (insn)) 3455 { 3456 if (LABEL_P (insn)) 3457 clear_content_memory (); 3458 3459 continue; 3460 } 3461 3462 if (dump_file) 3463 fprintf (dump_file, "Converting insn %d\n", INSN_UID (insn)); 3464 3465 pattern = PATTERN (insn); 3466 if (GET_CODE (pattern) == PARALLEL) 3467 pattern = XVECEXP (pattern, 0, 0); 3468 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL) 3469 clear_content_memory (); 3470 if (GET_CODE (pattern) != SET 3471 && GET_CODE (pattern) != CALL) 3472 continue; 3473 if (GET_CODE (pattern) == SET 3474 && GET_CODE (SET_SRC (pattern)) == ASM_OPERANDS) 3475 continue; 3476 3477 valloc_method = get_attr_valloc (insn); 3478 3479 PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn)); 3480 3481 if (valloc_method == VALLOC_MACAX) 3482 { 3483 record_content (AX, NULL_RTX); 3484 record_content (BC, NULL_RTX); 3485 record_content (DE, NULL_RTX); 3486 } 3487 3488 if (insn_ok_now (insn)) 3489 continue; 3490 3491 INSN_CODE (insn) = -1; 3492 3493 if (RTX_FRAME_RELATED_P (insn)) 3494 virt_insn_was_frame = 1; 3495 else 3496 virt_insn_was_frame = 0; 3497 3498 switch (valloc_method) 3499 { 3500 case VALLOC_OP1: 3501 rl78_alloc_physical_registers_op1 (insn); 3502 break; 3503 case VALLOC_OP2: 3504 rl78_alloc_physical_registers_op2 (insn); 3505 break; 3506 case VALLOC_RO1: 3507 rl78_alloc_physical_registers_ro1 (insn); 3508 break; 3509 case VALLOC_CMP: 3510 rl78_alloc_physical_registers_cmp (insn); 3511 break; 3512 case VALLOC_UMUL: 3513 rl78_alloc_physical_registers_umul (insn); 3514 break; 3515 case VALLOC_MACAX: 3516 /* Macro that clobbers AX. */ 3517 rl78_alloc_address_registers_macax (insn); 3518 record_content (AX, NULL_RTX); 3519 record_content (BC, NULL_RTX); 3520 record_content (DE, NULL_RTX); 3521 break; 3522 default: 3523 gcc_unreachable (); 3524 } 3525 3526 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL) 3527 clear_content_memory (); 3528 else 3529 process_postponed_content_update (); 3530 } 3531 3532#if DEBUG_ALLOC 3533 fprintf (stderr, "\033[0m"); 3534#endif 3535} 3536 3537/* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN. 3538 This function scans for uses of registers; the last use (i.e. first 3539 encounter when scanning backwards) triggers a REG_DEAD note if the 3540 reg was previously in DEAD[]. */ 3541static void 3542rl78_note_reg_uses (char *dead, rtx s, rtx insn) 3543{ 3544 const char *fmt; 3545 int i, r; 3546 enum rtx_code code; 3547 3548 if (!s) 3549 return; 3550 3551 code = GET_CODE (s); 3552 3553 switch (code) 3554 { 3555 /* Compare registers by number. */ 3556 case REG: 3557 r = REGNO (s); 3558 if (dump_file) 3559 { 3560 fprintf (dump_file, "note use reg %d size %d on insn %d\n", 3561 r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn)); 3562 print_rtl_single (dump_file, s); 3563 } 3564 if (dead [r]) 3565 add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r)); 3566 for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++) 3567 dead [r + i] = 0; 3568 return; 3569 3570 /* These codes have no constituent expressions 3571 and are unique. */ 3572 case SCRATCH: 3573 case CC0: 3574 case PC: 3575 return; 3576 3577 case CONST_INT: 3578 case CONST_VECTOR: 3579 case CONST_DOUBLE: 3580 case CONST_FIXED: 3581 /* These are kept unique for a given value. */ 3582 return; 3583 3584 default: 3585 break; 3586 } 3587 3588 fmt = GET_RTX_FORMAT (code); 3589 3590 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 3591 { 3592 if (fmt[i] == 'E') 3593 { 3594 int j; 3595 for (j = XVECLEN (s, i) - 1; j >= 0; j--) 3596 rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn); 3597 } 3598 else if (fmt[i] == 'e') 3599 rl78_note_reg_uses (dead, XEXP (s, i), insn); 3600 } 3601} 3602 3603/* Like the previous function, but scan for SETs instead. */ 3604static void 3605rl78_note_reg_set (char *dead, rtx d, rtx insn) 3606{ 3607 int r, i; 3608 3609 if (GET_CODE (d) == MEM) 3610 rl78_note_reg_uses (dead, XEXP (d, 0), insn); 3611 3612 if (GET_CODE (d) != REG) 3613 return; 3614 3615 r = REGNO (d); 3616 if (dead [r]) 3617 add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r)); 3618 if (dump_file) 3619 fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d))); 3620 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++) 3621 dead [r + i] = 1; 3622} 3623 3624/* This is a rather crude register death pass. Death status is reset 3625 at every jump or call insn. */ 3626static void 3627rl78_calculate_death_notes (void) 3628{ 3629 char dead[FIRST_PSEUDO_REGISTER]; 3630 rtx insn, p, s, d; 3631 int i; 3632 3633 memset (dead, 0, sizeof (dead)); 3634 3635 for (insn = get_last_insn (); 3636 insn; 3637 insn = prev_nonnote_nondebug_insn (insn)) 3638 { 3639 if (dump_file) 3640 { 3641 fprintf (dump_file, "\n--------------------------------------------------"); 3642 fprintf (dump_file, "\nDead:"); 3643 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++) 3644 if (dead[i]) 3645 fprintf (dump_file, " %s", reg_names[i]); 3646 fprintf (dump_file, "\n"); 3647 print_rtl_single (dump_file, insn); 3648 } 3649 3650 switch (GET_CODE (insn)) 3651 { 3652 case INSN: 3653 p = PATTERN (insn); 3654 if (GET_CODE (p) == PARALLEL) 3655 { 3656 rtx q = XVECEXP (p, 0 ,1); 3657 3658 /* This happens with the DIV patterns. */ 3659 if (GET_CODE (q) == SET) 3660 { 3661 s = SET_SRC (q); 3662 d = SET_DEST (q); 3663 rl78_note_reg_set (dead, d, insn); 3664 rl78_note_reg_uses (dead, s, insn); 3665 3666 } 3667 p = XVECEXP (p, 0, 0); 3668 } 3669 3670 switch (GET_CODE (p)) 3671 { 3672 case SET: 3673 s = SET_SRC (p); 3674 d = SET_DEST (p); 3675 rl78_note_reg_set (dead, d, insn); 3676 rl78_note_reg_uses (dead, s, insn); 3677 break; 3678 3679 case USE: 3680 rl78_note_reg_uses (dead, p, insn); 3681 break; 3682 3683 default: 3684 break; 3685 } 3686 break; 3687 3688 case JUMP_INSN: 3689 if (INSN_CODE (insn) == CODE_FOR_rl78_return) 3690 { 3691 memset (dead, 1, sizeof (dead)); 3692 /* We expect a USE just prior to this, which will mark 3693 the actual return registers. The USE will have a 3694 death note, but we aren't going to be modifying it 3695 after this pass. */ 3696 break; 3697 } 3698 case CALL_INSN: 3699 memset (dead, 0, sizeof (dead)); 3700 break; 3701 3702 default: 3703 break; 3704 } 3705 if (dump_file) 3706 print_rtl_single (dump_file, insn); 3707 } 3708} 3709 3710/* Helper function to reset the origins in RP and the age in AGE for 3711 all registers. */ 3712static void 3713reset_origins (int *rp, int *age) 3714{ 3715 int i; 3716 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 3717 { 3718 rp[i] = i; 3719 age[i] = 0; 3720 } 3721} 3722 3723static void 3724set_origin (rtx pat, rtx_insn * insn, int * origins, int * age) 3725{ 3726 rtx src = SET_SRC (pat); 3727 rtx dest = SET_DEST (pat); 3728 int mb = GET_MODE_SIZE (GET_MODE (dest)); 3729 int i; 3730 3731 if (GET_CODE (dest) == REG) 3732 { 3733 int dr = REGNO (dest); 3734 3735 if (GET_CODE (src) == REG) 3736 { 3737 int sr = REGNO (src); 3738 bool same = true; 3739 int best_age, best_reg; 3740 3741 /* See if the copy is not needed. */ 3742 for (i = 0; i < mb; i ++) 3743 if (origins[dr + i] != origins[sr + i]) 3744 same = false; 3745 3746 if (same) 3747 { 3748 if (dump_file) 3749 fprintf (dump_file, "deleting because dest already has correct value\n"); 3750 delete_insn (insn); 3751 return; 3752 } 3753 3754 if (dr < 8 || sr >= 8) 3755 { 3756 int ar; 3757 3758 best_age = -1; 3759 best_reg = -1; 3760 3761 /* See if the copy can be made from another 3762 bank 0 register instead, instead of the 3763 virtual src register. */ 3764 for (ar = 0; ar < 8; ar += mb) 3765 { 3766 same = true; 3767 3768 for (i = 0; i < mb; i ++) 3769 if (origins[ar + i] != origins[sr + i]) 3770 same = false; 3771 3772 /* The chip has some reg-reg move limitations. */ 3773 if (mb == 1 && dr > 3) 3774 same = false; 3775 3776 if (same) 3777 { 3778 if (best_age == -1 || best_age > age[sr + i]) 3779 { 3780 best_age = age[sr + i]; 3781 best_reg = sr; 3782 } 3783 } 3784 } 3785 3786 if (best_reg != -1) 3787 { 3788 /* FIXME: copy debug info too. */ 3789 SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg); 3790 sr = best_reg; 3791 } 3792 } 3793 3794 for (i = 0; i < mb; i++) 3795 { 3796 origins[dr + i] = origins[sr + i]; 3797 age[dr + i] = age[sr + i] + 1; 3798 } 3799 } 3800 else 3801 { 3802 /* The destination is computed, its origin is itself. */ 3803 if (dump_file) 3804 fprintf (dump_file, "resetting origin of r%d for %d byte%s\n", 3805 dr, mb, mb == 1 ? "" : "s"); 3806 3807 for (i = 0; i < mb; i ++) 3808 { 3809 origins[dr + i] = dr + i; 3810 age[dr + i] = 0; 3811 } 3812 } 3813 3814 /* Any registers marked with that reg as an origin are reset. */ 3815 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 3816 if (origins[i] >= dr && origins[i] < dr + mb) 3817 { 3818 origins[i] = i; 3819 age[i] = 0; 3820 } 3821 } 3822 3823 /* Special case - our MUL patterns uses AX and sometimes BC. */ 3824 if (get_attr_valloc (insn) == VALLOC_MACAX) 3825 { 3826 if (dump_file) 3827 fprintf (dump_file, "Resetting origin of AX/BC for MUL pattern.\n"); 3828 3829 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 3830 if (i <= 3 || origins[i] <= 3) 3831 { 3832 origins[i] = i; 3833 age[i] = 0; 3834 } 3835 } 3836 3837 if (GET_CODE (src) == ASHIFT 3838 || GET_CODE (src) == ASHIFTRT 3839 || GET_CODE (src) == LSHIFTRT) 3840 { 3841 rtx count = XEXP (src, 1); 3842 3843 if (GET_CODE (count) == REG) 3844 { 3845 /* Special case - our pattern clobbers the count register. */ 3846 int r = REGNO (count); 3847 3848 if (dump_file) 3849 fprintf (dump_file, "Resetting origin of r%d for shift.\n", r); 3850 3851 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 3852 if (i == r || origins[i] == r) 3853 { 3854 origins[i] = i; 3855 age[i] = 0; 3856 } 3857 } 3858 } 3859} 3860 3861/* The idea behind this optimization is to look for cases where we 3862 move data from A to B to C, and instead move from A to B, and A to 3863 C. If B is a virtual register or memory, this is a big win on its 3864 own. If B turns out to be unneeded after this, it's a bigger win. 3865 For each register, we try to determine where it's value originally 3866 came from, if it's propogated purely through moves (and not 3867 computes). The ORIGINS[] array has the regno for the "origin" of 3868 the value in the [regno] it's indexed by. */ 3869static void 3870rl78_propogate_register_origins (void) 3871{ 3872 int origins[FIRST_PSEUDO_REGISTER]; 3873 int age[FIRST_PSEUDO_REGISTER]; 3874 int i; 3875 rtx_insn *insn, *ninsn = NULL; 3876 rtx pat; 3877 3878 reset_origins (origins, age); 3879 3880 for (insn = get_insns (); insn; insn = ninsn) 3881 { 3882 ninsn = next_nonnote_nondebug_insn (insn); 3883 3884 if (dump_file) 3885 { 3886 fprintf (dump_file, "\n"); 3887 fprintf (dump_file, "Origins:"); 3888 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++) 3889 if (origins[i] != i) 3890 fprintf (dump_file, " r%d=r%d", i, origins[i]); 3891 fprintf (dump_file, "\n"); 3892 print_rtl_single (dump_file, insn); 3893 } 3894 3895 switch (GET_CODE (insn)) 3896 { 3897 case CODE_LABEL: 3898 case BARRIER: 3899 case CALL_INSN: 3900 case JUMP_INSN: 3901 reset_origins (origins, age); 3902 break; 3903 3904 default: 3905 break; 3906 3907 case INSN: 3908 pat = PATTERN (insn); 3909 3910 if (GET_CODE (pat) == PARALLEL) 3911 { 3912 rtx clobber = XVECEXP (pat, 0, 1); 3913 pat = XVECEXP (pat, 0, 0); 3914 if (GET_CODE (clobber) == CLOBBER 3915 && GET_CODE (XEXP (clobber, 0)) == REG) 3916 { 3917 int cr = REGNO (XEXP (clobber, 0)); 3918 int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0))); 3919 if (dump_file) 3920 fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr); 3921 for (i = 0; i < mb; i++) 3922 { 3923 origins[cr + i] = cr + i; 3924 age[cr + i] = 0; 3925 } 3926 } 3927 /* This happens with the DIV patterns. */ 3928 else if (GET_CODE (clobber) == SET) 3929 { 3930 set_origin (clobber, insn, origins, age); 3931 } 3932 else 3933 break; 3934 } 3935 3936 if (GET_CODE (pat) == SET) 3937 { 3938 set_origin (pat, insn, origins, age); 3939 } 3940 else if (GET_CODE (pat) == CLOBBER 3941 && GET_CODE (XEXP (pat, 0)) == REG) 3942 { 3943 if (REG_P (XEXP (pat, 0))) 3944 { 3945 unsigned int reg = REGNO (XEXP (pat, 0)); 3946 3947 origins[reg] = reg; 3948 age[reg] = 0; 3949 } 3950 } 3951 } 3952 } 3953} 3954 3955/* Remove any SETs where the destination is unneeded. */ 3956static void 3957rl78_remove_unused_sets (void) 3958{ 3959 rtx_insn *insn, *ninsn = NULL; 3960 rtx dest; 3961 3962 for (insn = get_insns (); insn; insn = ninsn) 3963 { 3964 ninsn = next_nonnote_nondebug_insn (insn); 3965 3966 rtx set = single_set (insn); 3967 if (set == NULL) 3968 continue; 3969 3970 dest = SET_DEST (set); 3971 3972 if (GET_CODE (dest) != REG || REGNO (dest) > 23) 3973 continue; 3974 3975 if (find_regno_note (insn, REG_UNUSED, REGNO (dest))) 3976 { 3977 if (dump_file) 3978 fprintf (dump_file, "deleting because the set register is never used.\n"); 3979 delete_insn (insn); 3980 } 3981 } 3982} 3983 3984/* This is the top of the devritualization pass. */ 3985static void 3986rl78_reorg (void) 3987{ 3988 /* split2 only happens when optimizing, but we need all movSIs to be 3989 split now. */ 3990 if (optimize <= 0) 3991 split_all_insns (); 3992 3993 rl78_alloc_physical_registers (); 3994 3995 if (dump_file) 3996 { 3997 fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n"); 3998 print_rtl_with_bb (dump_file, get_insns (), 0); 3999 } 4000 4001 rl78_propogate_register_origins (); 4002 rl78_calculate_death_notes (); 4003 4004 if (dump_file) 4005 { 4006 fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n"); 4007 print_rtl_with_bb (dump_file, get_insns (), 0); 4008 fprintf (dump_file, "\n======================================================================\n"); 4009 } 4010 4011 rl78_remove_unused_sets (); 4012 4013 /* The code after devirtualizing has changed so much that at this point 4014 we might as well just rescan everything. Note that 4015 df_rescan_all_insns is not going to help here because it does not 4016 touch the artificial uses and defs. */ 4017 df_finish_pass (true); 4018 if (optimize > 1) 4019 df_live_add_problem (); 4020 df_scan_alloc (NULL); 4021 df_scan_blocks (); 4022 4023 if (optimize) 4024 df_analyze (); 4025} 4026 4027#undef TARGET_RETURN_IN_MEMORY 4028#define TARGET_RETURN_IN_MEMORY rl78_return_in_memory 4029 4030static bool 4031rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) 4032{ 4033 const HOST_WIDE_INT size = int_size_in_bytes (type); 4034 return (size == -1 || size > 8); 4035} 4036 4037 4038#undef TARGET_RTX_COSTS 4039#define TARGET_RTX_COSTS rl78_rtx_costs 4040 4041static bool rl78_rtx_costs (rtx x, 4042 int code, 4043 int outer_code ATTRIBUTE_UNUSED, 4044 int opno ATTRIBUTE_UNUSED, 4045 int * total, 4046 bool speed ATTRIBUTE_UNUSED) 4047{ 4048 if (code == IF_THEN_ELSE) 4049 return COSTS_N_INSNS (10); 4050 if (GET_MODE (x) == SImode) 4051 { 4052 switch (code) 4053 { 4054 case MULT: 4055 if (RL78_MUL_RL78) 4056 *total = COSTS_N_INSNS (14); 4057 else if (RL78_MUL_G13) 4058 *total = COSTS_N_INSNS (29); 4059 else 4060 *total = COSTS_N_INSNS (500); 4061 return true; 4062 case PLUS: 4063 *total = COSTS_N_INSNS (8); 4064 return true; 4065 case ASHIFT: 4066 case ASHIFTRT: 4067 case LSHIFTRT: 4068 if (GET_CODE (XEXP (x, 1)) == CONST_INT) 4069 { 4070 switch (INTVAL (XEXP (x, 1))) 4071 { 4072 case 0: *total = COSTS_N_INSNS (0); break; 4073 case 1: *total = COSTS_N_INSNS (6); break; 4074 case 2: case 3: case 4: case 5: case 6: case 7: 4075 *total = COSTS_N_INSNS (10); break; 4076 case 8: *total = COSTS_N_INSNS (6); break; 4077 case 9: case 10: case 11: case 12: case 13: case 14: case 15: 4078 *total = COSTS_N_INSNS (10); break; 4079 case 16: *total = COSTS_N_INSNS (3); break; 4080 case 17: case 18: case 19: case 20: case 21: case 22: case 23: 4081 *total = COSTS_N_INSNS (4); break; 4082 case 24: *total = COSTS_N_INSNS (4); break; 4083 case 25: case 26: case 27: case 28: case 29: case 30: case 31: 4084 *total = COSTS_N_INSNS (5); break; 4085 } 4086 } 4087 else 4088 *total = COSTS_N_INSNS (10+4*16); 4089 return true; 4090 } 4091 } 4092 return false; 4093} 4094 4095 4096static GTY(()) section * saddr_section; 4097static GTY(()) section * frodata_section; 4098 4099int 4100rl78_saddr_p (rtx x) 4101{ 4102 const char * c; 4103 4104 if (MEM_P (x)) 4105 x = XEXP (x, 0); 4106 if (GET_CODE (x) == PLUS) 4107 x = XEXP (x, 0); 4108 if (GET_CODE (x) != SYMBOL_REF) 4109 return 0; 4110 4111 c = XSTR (x, 0); 4112 if (memcmp (c, "@s.", 3) == 0) 4113 return 1; 4114 4115 return 0; 4116} 4117 4118int 4119rl78_sfr_p (rtx x) 4120{ 4121 if (MEM_P (x)) 4122 x = XEXP (x, 0); 4123 if (GET_CODE (x) != CONST_INT) 4124 return 0; 4125 4126 if ((INTVAL (x) & 0xFF00) != 0xFF00) 4127 return 0; 4128 4129 return 1; 4130} 4131 4132#undef TARGET_STRIP_NAME_ENCODING 4133#define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding 4134 4135static const char * 4136rl78_strip_name_encoding (const char * sym) 4137{ 4138 while (1) 4139 { 4140 if (*sym == '*') 4141 sym++; 4142 else if (*sym == '@' && sym[2] == '.') 4143 sym += 3; 4144 else 4145 return sym; 4146 } 4147} 4148 4149/* Like rl78_strip_name_encoding, but does not strip leading asterisks. This 4150 is important if the stripped name is going to be passed to assemble_name() 4151 as that handles asterisk prefixed names in a special manner. */ 4152 4153static const char * 4154rl78_strip_nonasm_name_encoding (const char * sym) 4155{ 4156 while (1) 4157 { 4158 if (*sym == '@' && sym[2] == '.') 4159 sym += 3; 4160 else 4161 return sym; 4162 } 4163} 4164 4165 4166static int 4167rl78_attrlist_to_encoding (tree list, tree decl ATTRIBUTE_UNUSED) 4168{ 4169 while (list) 4170 { 4171 if (is_attribute_p ("saddr", TREE_PURPOSE (list))) 4172 return 's'; 4173 list = TREE_CHAIN (list); 4174 } 4175 4176 return 0; 4177} 4178 4179#define RL78_ATTRIBUTES(decl) \ 4180 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \ 4181 : DECL_ATTRIBUTES (decl) \ 4182 ? (DECL_ATTRIBUTES (decl)) \ 4183 : TYPE_ATTRIBUTES (TREE_TYPE (decl)) 4184 4185#undef TARGET_ENCODE_SECTION_INFO 4186#define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info 4187 4188static void 4189rl78_encode_section_info (tree decl, rtx rtl, int first) 4190{ 4191 rtx rtlname; 4192 const char * oldname; 4193 char encoding; 4194 char * newname; 4195 tree idp; 4196 tree type; 4197 tree rl78_attributes; 4198 4199 if (!first) 4200 return; 4201 4202 rtlname = XEXP (rtl, 0); 4203 4204 if (GET_CODE (rtlname) == SYMBOL_REF) 4205 oldname = XSTR (rtlname, 0); 4206 else if (GET_CODE (rtlname) == MEM 4207 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) 4208 oldname = XSTR (XEXP (rtlname, 0), 0); 4209 else 4210 gcc_unreachable (); 4211 4212 type = TREE_TYPE (decl); 4213 if (type == error_mark_node) 4214 return; 4215 if (! DECL_P (decl)) 4216 return; 4217 rl78_attributes = RL78_ATTRIBUTES (decl); 4218 4219 encoding = rl78_attrlist_to_encoding (rl78_attributes, decl); 4220 4221 if (encoding) 4222 { 4223 newname = (char *) alloca (strlen (oldname) + 4); 4224 sprintf (newname, "@%c.%s", encoding, oldname); 4225 idp = get_identifier (newname); 4226 XEXP (rtl, 0) = 4227 gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); 4228 SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl); 4229 SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl); 4230 } 4231} 4232 4233#undef TARGET_ASM_INIT_SECTIONS 4234#define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections 4235 4236static void 4237rl78_asm_init_sections (void) 4238{ 4239 saddr_section 4240 = get_unnamed_section (SECTION_WRITE, output_section_asm_op, 4241 "\t.section .saddr,\"aw\",@progbits"); 4242 frodata_section 4243 = get_unnamed_section (SECTION_WRITE, output_section_asm_op, 4244 "\t.section .frodata,\"aw\",@progbits"); 4245} 4246 4247#undef TARGET_ASM_SELECT_SECTION 4248#define TARGET_ASM_SELECT_SECTION rl78_select_section 4249 4250static section * 4251rl78_select_section (tree decl, 4252 int reloc ATTRIBUTE_UNUSED, 4253 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) 4254{ 4255 int readonly = 1; 4256 4257 switch (TREE_CODE (decl)) 4258 { 4259 case VAR_DECL: 4260 if (!TREE_READONLY (decl) 4261 || TREE_SIDE_EFFECTS (decl) 4262 || !DECL_INITIAL (decl) 4263 || (DECL_INITIAL (decl) != error_mark_node 4264 && !TREE_CONSTANT (DECL_INITIAL (decl)))) 4265 readonly = 0; 4266 break; 4267 case CONSTRUCTOR: 4268 if (! TREE_CONSTANT (decl)) 4269 readonly = 0; 4270 break; 4271 4272 default: 4273 break; 4274 } 4275 4276 if (TREE_CODE (decl) == VAR_DECL) 4277 { 4278 const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); 4279 4280 if (name[0] == '@' && name[2] == '.') 4281 switch (name[1]) 4282 { 4283 case 's': 4284 return saddr_section; 4285 } 4286 4287 if (TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_FAR 4288 && readonly) 4289 { 4290 return frodata_section; 4291 } 4292 } 4293 4294 if (readonly) 4295 return readonly_data_section; 4296 4297 return data_section; 4298} 4299 4300void 4301rl78_output_labelref (FILE *file, const char *str) 4302{ 4303 const char *str2; 4304 4305 str2 = targetm.strip_name_encoding (str); 4306 if (str2[0] != '.') 4307 fputs (user_label_prefix, file); 4308 fputs (str2, file); 4309} 4310 4311void 4312rl78_output_aligned_common (FILE *stream, 4313 tree decl ATTRIBUTE_UNUSED, 4314 const char *name, 4315 int size, int align, int global) 4316{ 4317 /* We intentionally don't use rl78_section_tag() here. */ 4318 if (name[0] == '@' && name[2] == '.') 4319 { 4320 const char *sec = 0; 4321 switch (name[1]) 4322 { 4323 case 's': 4324 switch_to_section (saddr_section); 4325 sec = ".saddr"; 4326 break; 4327 } 4328 if (sec) 4329 { 4330 const char *name2; 4331 int p2align = 0; 4332 4333 while (align > BITS_PER_UNIT) 4334 { 4335 align /= 2; 4336 p2align ++; 4337 } 4338 name2 = targetm.strip_name_encoding (name); 4339 if (global) 4340 fprintf (stream, "\t.global\t_%s\n", name2); 4341 fprintf (stream, "\t.p2align %d\n", p2align); 4342 fprintf (stream, "\t.type\t_%s,@object\n", name2); 4343 fprintf (stream, "\t.size\t_%s,%d\n", name2, size); 4344 fprintf (stream, "_%s:\n\t.zero\t%d\n", name2, size); 4345 return; 4346 } 4347 } 4348 4349 if (!global) 4350 { 4351 fprintf (stream, "\t.local\t"); 4352 assemble_name (stream, name); 4353 fprintf (stream, "\n"); 4354 } 4355 fprintf (stream, "\t.comm\t"); 4356 assemble_name (stream, name); 4357 fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT); 4358} 4359 4360#undef TARGET_INSERT_ATTRIBUTES 4361#define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes 4362 4363static void 4364rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED) 4365{ 4366 if (TARGET_ES0 4367 && TREE_CODE (decl) == VAR_DECL 4368 && TREE_READONLY (decl) 4369 && TREE_ADDRESSABLE (decl) 4370 && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_GENERIC) 4371 { 4372 tree type = TREE_TYPE (decl); 4373 tree attr = TYPE_ATTRIBUTES (type); 4374 int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR); 4375 4376 TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q); 4377 } 4378} 4379 4380#undef TARGET_ASM_INTEGER 4381#define TARGET_ASM_INTEGER rl78_asm_out_integer 4382 4383static bool 4384rl78_asm_out_integer (rtx x, unsigned int size, int aligned_p) 4385{ 4386 if (default_assemble_integer (x, size, aligned_p)) 4387 return true; 4388 4389 if (size == 4) 4390 { 4391 assemble_integer_with_op (".long\t", x); 4392 return true; 4393 } 4394 4395 return false; 4396} 4397 4398#undef TARGET_UNWIND_WORD_MODE 4399#define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode 4400 4401static machine_mode 4402rl78_unwind_word_mode (void) 4403{ 4404 return HImode; 4405} 4406 4407#ifndef USE_COLLECT2 4408#undef TARGET_ASM_CONSTRUCTOR 4409#define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor 4410#undef TARGET_ASM_DESTRUCTOR 4411#define TARGET_ASM_DESTRUCTOR rl78_asm_destructor 4412 4413static void 4414rl78_asm_ctor_dtor (rtx symbol, int priority, bool is_ctor) 4415{ 4416 section *sec; 4417 4418 if (priority != DEFAULT_INIT_PRIORITY) 4419 { 4420 /* This section of the function is based upon code copied 4421 from: gcc/varasm.c:get_cdtor_priority_section(). */ 4422 char buf[16]; 4423 4424 sprintf (buf, "%s.%.5u", is_ctor ? ".ctors" : ".dtors", 4425 MAX_INIT_PRIORITY - priority); 4426 sec = get_section (buf, 0, NULL); 4427 } 4428 else 4429 sec = is_ctor ? ctors_section : dtors_section; 4430 4431 assemble_addr_to_section (symbol, sec); 4432} 4433 4434static void 4435rl78_asm_constructor (rtx symbol, int priority) 4436{ 4437 rl78_asm_ctor_dtor (symbol, priority, true); 4438} 4439 4440static void 4441rl78_asm_destructor (rtx symbol, int priority) 4442{ 4443 rl78_asm_ctor_dtor (symbol, priority, false); 4444} 4445#endif /* ! USE_COLLECT2 */ 4446 4447/* Scan backwards through the insn chain looking to see if the flags 4448 have been set for a comparison of OP against OPERAND. Start with 4449 the insn *before* the current insn. */ 4450 4451bool 4452rl78_flags_already_set (rtx op, rtx operand) 4453{ 4454 /* We only track the Z flag. */ 4455 if (GET_CODE (op) != EQ && GET_CODE (op) != NE) 4456 return false; 4457 4458 /* This should not happen, but let's be paranoid. */ 4459 if (current_output_insn == NULL_RTX) 4460 return false; 4461 4462 rtx_insn *insn; 4463 bool res = false; 4464 4465 for (insn = prev_nonnote_nondebug_insn (current_output_insn); 4466 insn != NULL_RTX; 4467 insn = prev_nonnote_nondebug_insn (insn)) 4468 { 4469 if (LABEL_P (insn)) 4470 break; 4471 4472 if (! INSN_P (insn)) 4473 continue; 4474 4475 /* Make sure that the insn can be recognized. */ 4476 if (recog_memoized (insn) == -1) 4477 continue; 4478 4479 enum attr_update_Z updated = get_attr_update_Z (insn); 4480 4481 rtx set = single_set (insn); 4482 bool must_break = (set != NULL_RTX && rtx_equal_p (operand, SET_DEST (set))); 4483 4484 switch (updated) 4485 { 4486 case UPDATE_Z_NO: 4487 break; 4488 case UPDATE_Z_CLOBBER: 4489 must_break = true; 4490 break; 4491 case UPDATE_Z_UPDATE_Z: 4492 res = must_break; 4493 must_break = true; 4494 break; 4495 default: 4496 gcc_unreachable (); 4497 } 4498 4499 if (must_break) 4500 break; 4501 } 4502 4503 /* We have to re-recognize the current insn as the call(s) to 4504 get_attr_update_Z() above will have overwritten the recog_data cache. */ 4505 recog_memoized (current_output_insn); 4506 cleanup_subreg_operands (current_output_insn); 4507 constrain_operands_cached (current_output_insn, 1); 4508 4509 return res; 4510} 4511 4512struct gcc_target targetm = TARGET_INITIALIZER; 4513 4514#include "gt-rl78.h" 4515