1/* Subroutines for code generation on Motorola 68HC11 and 68HC12. 2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 3 2009 Free Software Foundation, Inc. 4 Contributed by Stephane Carrez (stcarrez@nerim.fr) 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 3, or (at your option) 11any later version. 12 13GCC is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING3. If not see 20<http://www.gnu.org/licenses/>. 21 22Note: 23 A first 68HC11 port was made by Otto Lind (otto@coactive.com) 24 on gcc 2.6.3. I have used it as a starting point for this port. 25 However, this new port is a complete re-write. Its internal 26 design is completely different. The generated code is not 27 compatible with the gcc 2.6.3 port. 28 29 The gcc 2.6.3 port is available at: 30 31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz 32 33*/ 34 35#include <stdio.h> 36#include "config.h" 37#include "system.h" 38#include "coretypes.h" 39#include "tm.h" 40#include "rtl.h" 41#include "tree.h" 42#include "expr.h" 43#include "tm_p.h" 44#include "regs.h" 45#include "hard-reg-set.h" 46#include "real.h" 47#include "insn-config.h" 48#include "conditions.h" 49#include "output.h" 50#include "insn-attr.h" 51#include "flags.h" 52#include "recog.h" 53#include "expr.h" 54#include "libfuncs.h" 55#include "toplev.h" 56#include "basic-block.h" 57#include "function.h" 58#include "ggc.h" 59#include "reload.h" 60#include "target.h" 61#include "target-def.h" 62#include "df.h" 63 64static void emit_move_after_reload (rtx, rtx, rtx); 65static rtx simplify_logical (enum machine_mode, int, rtx, rtx *); 66static void m68hc11_emit_logical (enum machine_mode, enum rtx_code, rtx *); 67static void m68hc11_reorg (void); 68static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool); 69static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool); 70static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx); 71static int must_parenthesize (rtx); 72static int m68hc11_address_cost (rtx, bool); 73static int m68hc11_shift_cost (enum machine_mode, rtx, int); 74static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code); 75static bool m68hc11_rtx_costs (rtx, int, int, int *, bool); 76static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *); 77static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *); 78 79void create_regs_rtx (void); 80 81static void asm_print_register (FILE *, int); 82static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT); 83static void m68hc11_asm_out_constructor (rtx, int); 84static void m68hc11_asm_out_destructor (rtx, int); 85static void m68hc11_file_start (void); 86static void m68hc11_encode_section_info (tree, rtx, int); 87static const char *m68hc11_strip_name_encoding (const char* str); 88static unsigned int m68hc11_section_type_flags (tree, const char*, int); 89static int autoinc_mode (rtx); 90static int m68hc11_make_autoinc_notes (rtx *, void *); 91static void m68hc11_init_libfuncs (void); 92static rtx m68hc11_struct_value_rtx (tree, int); 93static bool m68hc11_return_in_memory (const_tree, const_tree); 94static bool m68hc11_can_eliminate (const int, const int); 95static void m68hc11_trampoline_init (rtx, tree, rtx); 96 97/* Must be set to 1 to produce debug messages. */ 98int debug_m6811 = 0; 99 100extern FILE *asm_out_file; 101 102rtx ix_reg; 103rtx iy_reg; 104rtx d_reg; 105rtx m68hc11_soft_tmp_reg; 106static GTY(()) rtx stack_push_word; 107static GTY(()) rtx stack_pop_word; 108static GTY(()) rtx z_reg; 109static GTY(()) rtx z_reg_qi; 110static int regs_inited = 0; 111 112/* Set to 1 by expand_prologue() when the function is an interrupt handler. */ 113int current_function_interrupt; 114 115/* Set to 1 by expand_prologue() when the function is a trap handler. */ 116int current_function_trap; 117 118/* Set to 1 when the current function is placed in 68HC12 banked 119 memory and must return with rtc. */ 120int current_function_far; 121 122/* Min offset that is valid for the indirect addressing mode. */ 123HOST_WIDE_INT m68hc11_min_offset = 0; 124 125/* Max offset that is valid for the indirect addressing mode. */ 126HOST_WIDE_INT m68hc11_max_offset = 256; 127 128/* The class value for base registers. */ 129enum reg_class m68hc11_base_reg_class = A_REGS; 130 131/* The class value for index registers. This is NO_REGS for 68HC11. */ 132enum reg_class m68hc11_index_reg_class = NO_REGS; 133 134enum reg_class m68hc11_tmp_regs_class = NO_REGS; 135 136/* Tables that tell whether a given hard register is valid for 137 a base or an index register. It is filled at init time depending 138 on the target processor. */ 139unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER]; 140unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER]; 141 142/* A correction offset which is applied to the stack pointer. 143 This is 1 for 68HC11 and 0 for 68HC12. */ 144int m68hc11_sp_correction; 145 146int m68hc11_addr_mode; 147int m68hc11_mov_addr_mode; 148 149 150const struct processor_costs *m68hc11_cost; 151 152/* Costs for a 68HC11. */ 153static const struct processor_costs m6811_cost = { 154 /* add */ 155 COSTS_N_INSNS (2), 156 /* logical */ 157 COSTS_N_INSNS (2), 158 /* non-constant shift */ 159 COSTS_N_INSNS (20), 160 /* shiftQI const */ 161 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2), 162 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3), 163 COSTS_N_INSNS (2), COSTS_N_INSNS (1) }, 164 165 /* shiftHI const */ 166 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4), 167 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6), 168 COSTS_N_INSNS (4), COSTS_N_INSNS (2), 169 COSTS_N_INSNS (2), COSTS_N_INSNS (4), 170 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10), 171 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4) 172 }, 173 /* mulQI */ 174 COSTS_N_INSNS (20), 175 /* mulHI */ 176 COSTS_N_INSNS (20 * 4), 177 /* mulSI */ 178 COSTS_N_INSNS (20 * 16), 179 /* divQI */ 180 COSTS_N_INSNS (20), 181 /* divHI */ 182 COSTS_N_INSNS (80), 183 /* divSI */ 184 COSTS_N_INSNS (100) 185}; 186 187/* Costs for a 68HC12. */ 188static const struct processor_costs m6812_cost = { 189 /* add */ 190 COSTS_N_INSNS (2), 191 /* logical */ 192 COSTS_N_INSNS (2), 193 /* non-constant shift */ 194 COSTS_N_INSNS (20), 195 /* shiftQI const */ 196 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2), 197 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3), 198 COSTS_N_INSNS (2), COSTS_N_INSNS (1) }, 199 200 /* shiftHI const */ 201 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4), 202 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6), 203 COSTS_N_INSNS (4), COSTS_N_INSNS (2), 204 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6), 205 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8), 206 COSTS_N_INSNS (6), COSTS_N_INSNS (4) 207 }, 208 /* mulQI */ 209 COSTS_N_INSNS (3), 210 /* mulHI */ 211 COSTS_N_INSNS (3), 212 /* mulSI */ 213 COSTS_N_INSNS (3 * 4), 214 /* divQI */ 215 COSTS_N_INSNS (12), 216 /* divHI */ 217 COSTS_N_INSNS (12), 218 /* divSI */ 219 COSTS_N_INSNS (100) 220}; 221 222/* M68HC11 specific attributes. */ 223 224static const struct attribute_spec m68hc11_attribute_table[] = 225{ 226 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ 227 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, 228 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, 229 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, 230 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, 231 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute }, 232 { NULL, 0, 0, false, false, false, NULL } 233}; 234 235/* Initialize the GCC target structure. */ 236#undef TARGET_ATTRIBUTE_TABLE 237#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table 238 239#undef TARGET_ASM_ALIGNED_HI_OP 240#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" 241 242#undef TARGET_ASM_FUNCTION_EPILOGUE 243#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue 244 245#undef TARGET_ASM_FILE_START 246#define TARGET_ASM_FILE_START m68hc11_file_start 247#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE 248#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true 249 250#undef TARGET_DEFAULT_TARGET_FLAGS 251#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT 252 253#undef TARGET_ENCODE_SECTION_INFO 254#define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info 255 256#undef TARGET_SECTION_TYPE_FLAGS 257#define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags 258 259#undef TARGET_RTX_COSTS 260#define TARGET_RTX_COSTS m68hc11_rtx_costs 261#undef TARGET_ADDRESS_COST 262#define TARGET_ADDRESS_COST m68hc11_address_cost 263 264#undef TARGET_MACHINE_DEPENDENT_REORG 265#define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg 266 267#undef TARGET_INIT_LIBFUNCS 268#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs 269 270#undef TARGET_STRUCT_VALUE_RTX 271#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx 272#undef TARGET_RETURN_IN_MEMORY 273#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory 274#undef TARGET_CALLEE_COPIES 275#define TARGET_CALLEE_COPIES hook_callee_copies_named 276 277#undef TARGET_STRIP_NAME_ENCODING 278#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding 279 280#undef TARGET_LEGITIMATE_ADDRESS_P 281#define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p 282 283#undef TARGET_CAN_ELIMINATE 284#define TARGET_CAN_ELIMINATE m68hc11_can_eliminate 285 286#undef TARGET_TRAMPOLINE_INIT 287#define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init 288 289struct gcc_target targetm = TARGET_INITIALIZER; 290 291int 292m68hc11_override_options (void) 293{ 294 memset (m68hc11_reg_valid_for_index, 0, 295 sizeof (m68hc11_reg_valid_for_index)); 296 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base)); 297 298 /* Compilation with -fpic generates a wrong code. */ 299 if (flag_pic) 300 { 301 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)", 302 (flag_pic > 1) ? "PIC" : "pic"); 303 flag_pic = 0; 304 } 305 306 /* Do not enable -fweb because it breaks the 32-bit shift patterns 307 by breaking the match_dup of those patterns. The shift patterns 308 will no longer be recognized after that. */ 309 flag_web = 0; 310 311 /* Configure for a 68hc11 processor. */ 312 if (TARGET_M6811) 313 { 314 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX); 315 m68hc11_cost = &m6811_cost; 316 m68hc11_min_offset = 0; 317 m68hc11_max_offset = 256; 318 m68hc11_index_reg_class = NO_REGS; 319 m68hc11_base_reg_class = A_REGS; 320 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1; 321 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1; 322 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; 323 m68hc11_sp_correction = 1; 324 m68hc11_tmp_regs_class = D_REGS; 325 m68hc11_addr_mode = ADDR_OFFSET; 326 m68hc11_mov_addr_mode = 0; 327 if (m68hc11_soft_reg_count < 0) 328 m68hc11_soft_reg_count = 4; 329 } 330 331 /* Configure for a 68hc12 processor. */ 332 if (TARGET_M6812) 333 { 334 m68hc11_cost = &m6812_cost; 335 m68hc11_min_offset = -65536; 336 m68hc11_max_offset = 65536; 337 m68hc11_index_reg_class = D_REGS; 338 m68hc11_base_reg_class = A_OR_SP_REGS; 339 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1; 340 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1; 341 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; 342 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1; 343 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1; 344 m68hc11_sp_correction = 0; 345 m68hc11_tmp_regs_class = TMP_REGS; 346 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST 347 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); 348 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST 349 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); 350 target_flags |= MASK_NO_DIRECT_MODE; 351 if (m68hc11_soft_reg_count < 0) 352 m68hc11_soft_reg_count = 0; 353 354 if (TARGET_LONG_CALLS) 355 current_function_far = 1; 356 } 357 return 0; 358} 359 360 361void 362m68hc11_conditional_register_usage (void) 363{ 364 int i; 365 366 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST) 367 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST; 368 369 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++) 370 { 371 fixed_regs[i] = 1; 372 call_used_regs[i] = 1; 373 } 374 375 /* For 68HC12, the Z register emulation is not necessary when the 376 frame pointer is not used. The frame pointer is eliminated and 377 replaced by the stack register (which is a BASE_REG_CLASS). */ 378 if (TARGET_M6812 && flag_omit_frame_pointer && optimize) 379 { 380 fixed_regs[HARD_Z_REGNUM] = 1; 381 } 382} 383 384 385/* Reload and register operations. */ 386 387 388void 389create_regs_rtx (void) 390{ 391 /* regs_inited = 1; */ 392 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM); 393 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM); 394 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM); 395 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); 396 397 stack_push_word = gen_rtx_MEM (HImode, 398 gen_rtx_PRE_DEC (HImode, 399 gen_rtx_REG (HImode, HARD_SP_REGNUM))); 400 stack_pop_word = gen_rtx_MEM (HImode, 401 gen_rtx_POST_INC (HImode, 402 gen_rtx_REG (HImode, HARD_SP_REGNUM))); 403 404} 405 406/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. 407 - 8-bit values are stored anywhere (except the SP register). 408 - 16-bit values can be stored in any register whose mode is 16 409 - 32-bit values can be stored in D, X registers or in a soft register 410 (except the last one because we need 2 soft registers) 411 - Values whose size is > 32 bit are not stored in real hard 412 registers. They may be stored in soft registers if there are 413 enough of them. */ 414int 415hard_regno_mode_ok (int regno, enum machine_mode mode) 416{ 417 switch (GET_MODE_SIZE (mode)) 418 { 419 case 8: 420 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4; 421 422 case 4: 423 return (X_REGNO_P (regno) 424 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2)); 425 426 case 2: 427 return G_REGNO_P (regno); 428 429 case 1: 430 /* We have to accept a QImode in X or Y registers. Otherwise, the 431 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined 432 in the insns. Reload fails if the insn rejects the register class 'a' 433 as well as if it accepts it. Patterns that failed were 434 zero_extend_qihi2 and iorqi3. */ 435 436 return G_REGNO_P (regno) && !SP_REGNO_P (regno); 437 438 default: 439 return 0; 440 } 441} 442 443int 444m68hc11_hard_regno_rename_ok (int reg1, int reg2) 445{ 446 /* Don't accept renaming to Z register. We will replace it to 447 X,Y or D during machine reorg pass. */ 448 if (reg2 == HARD_Z_REGNUM) 449 return 0; 450 451 /* Don't accept renaming D,X to Y register as the code will be bigger. */ 452 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM 453 && (D_REGNO_P (reg1) || X_REGNO_P (reg1))) 454 return 0; 455 456 return 1; 457} 458 459enum reg_class 460preferred_reload_class (rtx operand, enum reg_class rclass) 461{ 462 enum machine_mode mode; 463 464 mode = GET_MODE (operand); 465 466 if (debug_m6811) 467 { 468 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]); 469 } 470 471 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand)) 472 return m68hc11_base_reg_class; 473 474 if (rclass >= S_REGS && (GET_CODE (operand) == MEM 475 || GET_CODE (operand) == CONST_INT)) 476 { 477 /* S_REGS class must not be used. The movhi template does not 478 work to move a memory to a soft register. 479 Restrict to a hard reg. */ 480 switch (rclass) 481 { 482 default: 483 case G_REGS: 484 case D_OR_A_OR_S_REGS: 485 rclass = A_OR_D_REGS; 486 break; 487 case A_OR_S_REGS: 488 rclass = A_REGS; 489 break; 490 case D_OR_SP_OR_S_REGS: 491 rclass = D_OR_SP_REGS; 492 break; 493 case D_OR_Y_OR_S_REGS: 494 rclass = D_OR_Y_REGS; 495 break; 496 case D_OR_X_OR_S_REGS: 497 rclass = D_OR_X_REGS; 498 break; 499 case SP_OR_S_REGS: 500 rclass = SP_REGS; 501 break; 502 case Y_OR_S_REGS: 503 rclass = Y_REGS; 504 break; 505 case X_OR_S_REGS: 506 rclass = X_REGS; 507 break; 508 case D_OR_S_REGS: 509 rclass = D_REGS; 510 } 511 } 512 else if (rclass == Y_REGS && GET_CODE (operand) == MEM) 513 { 514 rclass = Y_REGS; 515 } 516 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4) 517 { 518 rclass = D_OR_X_REGS; 519 } 520 else if (rclass >= S_REGS && S_REG_P (operand)) 521 { 522 switch (rclass) 523 { 524 default: 525 case G_REGS: 526 case D_OR_A_OR_S_REGS: 527 rclass = A_OR_D_REGS; 528 break; 529 case A_OR_S_REGS: 530 rclass = A_REGS; 531 break; 532 case D_OR_SP_OR_S_REGS: 533 rclass = D_OR_SP_REGS; 534 break; 535 case D_OR_Y_OR_S_REGS: 536 rclass = D_OR_Y_REGS; 537 break; 538 case D_OR_X_OR_S_REGS: 539 rclass = D_OR_X_REGS; 540 break; 541 case SP_OR_S_REGS: 542 rclass = SP_REGS; 543 break; 544 case Y_OR_S_REGS: 545 rclass = Y_REGS; 546 break; 547 case X_OR_S_REGS: 548 rclass = X_REGS; 549 break; 550 case D_OR_S_REGS: 551 rclass = D_REGS; 552 } 553 } 554 else if (rclass >= S_REGS) 555 { 556 if (debug_m6811) 557 { 558 printf ("Class = %s for: ", reg_class_names[rclass]); 559 fflush (stdout); 560 debug_rtx (operand); 561 } 562 } 563 564 if (debug_m6811) 565 { 566 printf (" => class=%s\n", reg_class_names[rclass]); 567 fflush (stdout); 568 debug_rtx (operand); 569 } 570 571 return rclass; 572} 573 574/* Return 1 if the operand is a valid indexed addressing mode. 575 For 68hc11: n,r with n in [0..255] and r in A_REGS class 576 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */ 577int 578m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode) 579{ 580 rtx base, offset; 581 582 switch (GET_CODE (operand)) 583 { 584 case MEM: 585 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2) 586 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode, 587 addr_mode & (ADDR_STRICT | ADDR_OFFSET)); 588 return 0; 589 590 case POST_INC: 591 case PRE_INC: 592 case POST_DEC: 593 case PRE_DEC: 594 if (addr_mode & ADDR_INCDEC) 595 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode, 596 addr_mode & ADDR_STRICT); 597 return 0; 598 599 case PLUS: 600 base = XEXP (operand, 0); 601 if (GET_CODE (base) == MEM) 602 return 0; 603 604 offset = XEXP (operand, 1); 605 if (GET_CODE (offset) == MEM) 606 return 0; 607 608 /* Indexed addressing mode with 2 registers. */ 609 if (GET_CODE (base) == REG && GET_CODE (offset) == REG) 610 { 611 if (!(addr_mode & ADDR_INDEXED)) 612 return 0; 613 614 addr_mode &= ADDR_STRICT; 615 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode) 616 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode)) 617 return 1; 618 619 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode) 620 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode)) 621 return 1; 622 623 return 0; 624 } 625 626 if (!(addr_mode & ADDR_OFFSET)) 627 return 0; 628 629 if (GET_CODE (base) == REG) 630 { 631 if (!VALID_CONSTANT_OFFSET_P (offset, mode)) 632 return 0; 633 634 if (!(addr_mode & ADDR_STRICT)) 635 return 1; 636 637 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1); 638 } 639 640 if (GET_CODE (offset) == REG) 641 { 642 if (!VALID_CONSTANT_OFFSET_P (base, mode)) 643 return 0; 644 645 if (!(addr_mode & ADDR_STRICT)) 646 return 1; 647 648 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1); 649 } 650 return 0; 651 652 case REG: 653 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT); 654 655 case CONST_INT: 656 if (addr_mode & ADDR_CONST) 657 return VALID_CONSTANT_OFFSET_P (operand, mode); 658 return 0; 659 660 default: 661 return 0; 662 } 663} 664 665/* Returns 1 if the operand fits in a 68HC11 indirect mode or in 666 a 68HC12 1-byte index addressing mode. */ 667int 668m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode) 669{ 670 rtx base, offset; 671 int addr_mode; 672 673 if (GET_CODE (operand) == REG && reload_in_progress 674 && REGNO (operand) >= FIRST_PSEUDO_REGISTER 675 && reg_equiv_memory_loc[REGNO (operand)]) 676 { 677 operand = reg_equiv_memory_loc[REGNO (operand)]; 678 operand = eliminate_regs (operand, VOIDmode, NULL_RTX); 679 } 680 681 if (GET_CODE (operand) != MEM) 682 return 0; 683 684 operand = XEXP (operand, 0); 685 if (CONSTANT_ADDRESS_P (operand)) 686 return 1; 687 688 if (PUSH_POP_ADDRESS_P (operand)) 689 return 1; 690 691 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0); 692 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode)) 693 return 0; 694 695 if (TARGET_M6812 && GET_CODE (operand) == PLUS 696 && (reload_completed | reload_in_progress)) 697 { 698 base = XEXP (operand, 0); 699 offset = XEXP (operand, 1); 700 701 /* The offset can be a symbol address and this is too big 702 for the operand constraint. */ 703 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT) 704 return 0; 705 706 if (GET_CODE (base) == CONST_INT) 707 offset = base; 708 709 switch (GET_MODE_SIZE (mode)) 710 { 711 case 8: 712 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6) 713 return 0; 714 break; 715 716 case 4: 717 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2) 718 return 0; 719 break; 720 721 default: 722 if (INTVAL (offset) < -16 || INTVAL (offset) > 15) 723 return 0; 724 break; 725 } 726 } 727 return 1; 728} 729 730int 731m68hc11_register_indirect_p (rtx operand, enum machine_mode mode) 732{ 733 int addr_mode; 734 735 if (GET_CODE (operand) == REG && reload_in_progress 736 && REGNO (operand) >= FIRST_PSEUDO_REGISTER 737 && reg_equiv_memory_loc[REGNO (operand)]) 738 { 739 operand = reg_equiv_memory_loc[REGNO (operand)]; 740 operand = eliminate_regs (operand, VOIDmode, NULL_RTX); 741 } 742 if (GET_CODE (operand) != MEM) 743 return 0; 744 745 operand = XEXP (operand, 0); 746 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); 747 return m68hc11_valid_addressing_p (operand, mode, addr_mode); 748} 749 750static bool 751m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand, 752 bool strict) 753{ 754 int addr_mode; 755 756 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812) 757 { 758 /* Reject the global variables if they are too wide. This forces 759 a load of their address in a register and generates smaller code. */ 760 if (GET_MODE_SIZE (mode) == 8) 761 return 0; 762 763 return 1; 764 } 765 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0); 766 if (m68hc11_valid_addressing_p (operand, mode, addr_mode)) 767 { 768 return 1; 769 } 770 if (PUSH_POP_ADDRESS_P (operand)) 771 { 772 return 1; 773 } 774 if (symbolic_memory_operand (operand, mode)) 775 { 776 return 1; 777 } 778 return 0; 779} 780 781bool 782m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand, 783 bool strict) 784{ 785 int result; 786 787 if (debug_m6811) 788 { 789 printf ("Checking: "); 790 fflush (stdout); 791 debug_rtx (operand); 792 } 793 794 result = m68hc11_legitimate_address_p_1 (mode, operand, strict); 795 796 if (debug_m6811) 797 { 798 printf (" -> %s\n", result == 0 ? "NO" : "YES"); 799 } 800 801 if (result == 0) 802 { 803 if (debug_m6811) 804 { 805 printf ("go_if_legitimate%s, ret 0: %d:", 806 (strict ? "_strict" : ""), mode); 807 fflush (stdout); 808 debug_rtx (operand); 809 } 810 } 811 return result; 812} 813 814 815int 816m68hc11_reload_operands (rtx operands[]) 817{ 818 enum machine_mode mode; 819 820 if (regs_inited == 0) 821 create_regs_rtx (); 822 823 mode = GET_MODE (operands[1]); 824 825 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */ 826 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode)) 827 { 828 rtx big_offset = XEXP (XEXP (operands[1], 0), 1); 829 rtx base = XEXP (XEXP (operands[1], 0), 0); 830 831 if (GET_CODE (base) != REG) 832 { 833 rtx tmp = base; 834 base = big_offset; 835 big_offset = tmp; 836 } 837 838 /* If the offset is out of range, we have to compute the address 839 with a separate add instruction. We try to do this with an 8-bit 840 add on the A register. This is possible only if the lowest part 841 of the offset (i.e., big_offset % 256) is a valid constant offset 842 with respect to the mode. If it's not, we have to generate a 843 16-bit add on the D register. From: 844 845 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000))))) 846 847 we generate: 848 849 [(SET (REG D) (REG X)) (SET (REG X) (REG D))] 850 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256))) 851 [(SET (REG D) (REG X)) (SET (REG X) (REG D))] 852 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))) 853 854 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256))) 855 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))) 856 857 */ 858 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode)) 859 { 860 int vh, vl; 861 rtx reg = operands[0]; 862 rtx offset; 863 int val = INTVAL (big_offset); 864 865 866 /* We use the 'operands[0]' as a scratch register to compute the 867 address. Make sure 'base' is in that register. */ 868 if (!rtx_equal_p (base, operands[0])) 869 { 870 emit_move_insn (reg, base); 871 } 872 873 if (val > 0) 874 { 875 vh = val >> 8; 876 vl = val & 0x0FF; 877 } 878 else 879 { 880 vh = (val >> 8) & 0x0FF; 881 vl = val & 0x0FF; 882 } 883 884 /* Create the lowest part offset that still remains to be added. 885 If it's not a valid offset, do a 16-bit add. */ 886 offset = GEN_INT (vl); 887 if (!VALID_CONSTANT_OFFSET_P (offset, mode)) 888 { 889 emit_insn (gen_rtx_SET (VOIDmode, reg, 890 gen_rtx_PLUS (HImode, reg, big_offset))); 891 offset = const0_rtx; 892 } 893 else 894 { 895 emit_insn (gen_rtx_SET (VOIDmode, reg, 896 gen_rtx_PLUS (HImode, reg, 897 GEN_INT (vh << 8)))); 898 } 899 emit_move_insn (operands[0], 900 gen_rtx_MEM (GET_MODE (operands[1]), 901 gen_rtx_PLUS (Pmode, reg, offset))); 902 return 1; 903 } 904 } 905 906 /* Use the normal gen_movhi pattern. */ 907 return 0; 908} 909 910void 911m68hc11_emit_libcall (const char *name, enum rtx_code code, 912 enum machine_mode dmode, enum machine_mode smode, 913 int noperands, rtx *operands) 914{ 915 rtx ret; 916 rtx insns; 917 rtx libcall; 918 rtx equiv; 919 920 start_sequence (); 921 libcall = gen_rtx_SYMBOL_REF (Pmode, name); 922 switch (noperands) 923 { 924 case 2: 925 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, 926 dmode, 1, operands[1], smode); 927 equiv = gen_rtx_fmt_e (code, dmode, operands[1]); 928 break; 929 930 case 3: 931 ret = emit_library_call_value (libcall, NULL_RTX, 932 LCT_CONST, dmode, 2, 933 operands[1], smode, operands[2], 934 smode); 935 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]); 936 break; 937 938 default: 939 gcc_unreachable (); 940 } 941 942 insns = get_insns (); 943 end_sequence (); 944 emit_libcall_block (insns, operands[0], ret, equiv); 945} 946 947/* Returns true if X is a PRE/POST increment decrement 948 (same as auto_inc_p() in rtlanal.c but do not take into 949 account the stack). */ 950int 951m68hc11_auto_inc_p (rtx x) 952{ 953 return GET_CODE (x) == PRE_DEC 954 || GET_CODE (x) == POST_INC 955 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC; 956} 957 958 959/* Predicates for machine description. */ 960 961int 962memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED) 963{ 964 return GET_CODE (operand) == MEM 965 && GET_CODE (XEXP (operand, 0)) == PLUS 966 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG 967 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT) 968 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG 969 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT)); 970} 971 972int 973m68hc11_symbolic_p (rtx operand, enum machine_mode mode) 974{ 975 if (GET_CODE (operand) == MEM) 976 { 977 rtx op = XEXP (operand, 0); 978 979 if (symbolic_memory_operand (op, mode)) 980 return 1; 981 } 982 return 0; 983} 984 985int 986m68hc11_indirect_p (rtx operand, enum machine_mode mode) 987{ 988 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode) 989 { 990 rtx op = XEXP (operand, 0); 991 int addr_mode; 992 993 if (m68hc11_page0_symbol_p (op)) 994 return 1; 995 996 if (symbolic_memory_operand (op, mode)) 997 return TARGET_M6812; 998 999 if (reload_in_progress) 1000 return 1; 1001 1002 operand = XEXP (operand, 0); 1003 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); 1004 return m68hc11_valid_addressing_p (operand, mode, addr_mode); 1005 } 1006 return 0; 1007} 1008 1009int 1010memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED) 1011{ 1012 if (GET_CODE (operand) != MEM) 1013 return 0; 1014 1015 operand = XEXP (operand, 0); 1016 if (GET_CODE (operand) == PLUS) 1017 { 1018 if (GET_CODE (XEXP (operand, 0)) == REG) 1019 operand = XEXP (operand, 0); 1020 else if (GET_CODE (XEXP (operand, 1)) == REG) 1021 operand = XEXP (operand, 1); 1022 } 1023 return GET_CODE (operand) == REG 1024 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER 1025 || A_REGNO_P (REGNO (operand))); 1026} 1027 1028int 1029push_pop_operand_p (rtx operand) 1030{ 1031 if (GET_CODE (operand) != MEM) 1032 { 1033 return 0; 1034 } 1035 operand = XEXP (operand, 0); 1036 return PUSH_POP_ADDRESS_P (operand); 1037} 1038 1039/* Returns 1 if OP is either a symbol reference or a sum of a symbol 1040 reference and a constant. */ 1041 1042int 1043symbolic_memory_operand (rtx op, enum machine_mode mode) 1044{ 1045 switch (GET_CODE (op)) 1046 { 1047 case SYMBOL_REF: 1048 case LABEL_REF: 1049 return 1; 1050 1051 case CONST: 1052 op = XEXP (op, 0); 1053 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF 1054 || GET_CODE (XEXP (op, 0)) == LABEL_REF) 1055 && GET_CODE (XEXP (op, 1)) == CONST_INT); 1056 1057 /* ??? This clause seems to be irrelevant. */ 1058 case CONST_DOUBLE: 1059 return GET_MODE (op) == mode; 1060 1061 case PLUS: 1062 return symbolic_memory_operand (XEXP (op, 0), mode) 1063 && symbolic_memory_operand (XEXP (op, 1), mode); 1064 1065 default: 1066 return 0; 1067 } 1068} 1069 1070/* Emit the code to build the trampoline used to call a nested function. 1071 1072 68HC11 68HC12 1073 1074 ldy #&CXT movw #&CXT,*_.d1 1075 sty *_.d1 jmp FNADDR 1076 jmp FNADDR 1077 1078*/ 1079static void 1080m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt) 1081{ 1082 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM]; 1083 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 1084 rtx mem; 1085 1086 /* Skip the '*'. */ 1087 if (*static_chain_reg == '*') 1088 static_chain_reg++; 1089 if (TARGET_M6811) 1090 { 1091 mem = adjust_address (m_tramp, HImode, 0); 1092 emit_move_insn (mem, GEN_INT (0x18ce)); 1093 mem = adjust_address (m_tramp, HImode, 2); 1094 emit_move_insn (mem, cxt); 1095 mem = adjust_address (m_tramp, HImode, 4); 1096 emit_move_insn (mem, GEN_INT (0x18df)); 1097 mem = adjust_address (m_tramp, QImode, 6); 1098 emit_move_insn (mem, 1099 gen_rtx_CONST (QImode, 1100 gen_rtx_SYMBOL_REF (Pmode, 1101 static_chain_reg))); 1102 mem = adjust_address (m_tramp, QImode, 7); 1103 emit_move_insn (mem, GEN_INT (0x7e)); 1104 mem = adjust_address (m_tramp, HImode, 8); 1105 emit_move_insn (mem, fnaddr); 1106 } 1107 else 1108 { 1109 mem = adjust_address (m_tramp, HImode, 0); 1110 emit_move_insn (mem, GEN_INT (0x1803)); 1111 mem = adjust_address (m_tramp, HImode, 2); 1112 emit_move_insn (mem, cxt); 1113 mem = adjust_address (m_tramp, HImode, 4); 1114 emit_move_insn (mem, 1115 gen_rtx_CONST (HImode, 1116 gen_rtx_SYMBOL_REF (Pmode, 1117 static_chain_reg))); 1118 mem = adjust_address (m_tramp, QImode, 6); 1119 emit_move_insn (mem, GEN_INT (0x06)); 1120 mem = adjust_address (m_tramp, HImode, 7); 1121 emit_move_insn (mem, fnaddr); 1122 } 1123} 1124 1125/* Declaration of types. */ 1126 1127/* Handle an "tiny_data" attribute; arguments as in 1128 struct attribute_spec.handler. */ 1129static tree 1130m68hc11_handle_page0_attribute (tree *node, tree name, 1131 tree args ATTRIBUTE_UNUSED, 1132 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) 1133{ 1134 tree decl = *node; 1135 1136 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) 1137 { 1138 DECL_SECTION_NAME (decl) = build_string (6, ".page0"); 1139 } 1140 else 1141 { 1142 warning (OPT_Wattributes, "%qE attribute ignored", 1143 name); 1144 *no_add_attrs = true; 1145 } 1146 1147 return NULL_TREE; 1148} 1149 1150/* Keep track of the symbol which has a `trap' attribute and which uses 1151 the `swi' calling convention. Since there is only one trap, we only 1152 record one such symbol. If there are several, a warning is reported. */ 1153static rtx trap_handler_symbol = 0; 1154 1155/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL; 1156 arguments as in struct attribute_spec.handler. */ 1157static tree 1158m68hc11_handle_fntype_attribute (tree *node, tree name, 1159 tree args ATTRIBUTE_UNUSED, 1160 int flags ATTRIBUTE_UNUSED, 1161 bool *no_add_attrs) 1162{ 1163 if (TREE_CODE (*node) != FUNCTION_TYPE 1164 && TREE_CODE (*node) != METHOD_TYPE 1165 && TREE_CODE (*node) != FIELD_DECL 1166 && TREE_CODE (*node) != TYPE_DECL) 1167 { 1168 warning (OPT_Wattributes, "%qE attribute only applies to functions", 1169 name); 1170 *no_add_attrs = true; 1171 } 1172 1173 return NULL_TREE; 1174} 1175/* Undo the effects of the above. */ 1176 1177static const char * 1178m68hc11_strip_name_encoding (const char *str) 1179{ 1180 return str + (*str == '*' || *str == '@' || *str == '&'); 1181} 1182 1183static void 1184m68hc11_encode_label (tree decl) 1185{ 1186 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0); 1187 int len = strlen (str); 1188 char *newstr = XALLOCAVEC (char, len + 2); 1189 1190 newstr[0] = '@'; 1191 strcpy (&newstr[1], str); 1192 1193 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1); 1194} 1195 1196/* Return 1 if this is a symbol in page0 */ 1197int 1198m68hc11_page0_symbol_p (rtx x) 1199{ 1200 switch (GET_CODE (x)) 1201 { 1202 case SYMBOL_REF: 1203 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@'; 1204 1205 case CONST: 1206 return m68hc11_page0_symbol_p (XEXP (x, 0)); 1207 1208 case PLUS: 1209 if (!m68hc11_page0_symbol_p (XEXP (x, 0))) 1210 return 0; 1211 1212 return GET_CODE (XEXP (x, 1)) == CONST_INT 1213 && INTVAL (XEXP (x, 1)) < 256 1214 && INTVAL (XEXP (x, 1)) >= 0; 1215 1216 default: 1217 return 0; 1218 } 1219} 1220 1221/* We want to recognize trap handlers so that we handle calls to traps 1222 in a special manner (by issuing the trap). This information is stored 1223 in SYMBOL_REF_FLAG. */ 1224 1225static void 1226m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) 1227{ 1228 tree func_attr; 1229 int trap_handler; 1230 int is_far = 0; 1231 1232 if (TREE_CODE (decl) == VAR_DECL) 1233 { 1234 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0) 1235 m68hc11_encode_label (decl); 1236 return; 1237 } 1238 1239 if (TREE_CODE (decl) != FUNCTION_DECL) 1240 return; 1241 1242 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl)); 1243 1244 1245 if (lookup_attribute ("far", func_attr) != NULL_TREE) 1246 is_far = 1; 1247 else if (lookup_attribute ("near", func_attr) == NULL_TREE) 1248 is_far = TARGET_LONG_CALLS != 0; 1249 1250 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; 1251 if (trap_handler && is_far) 1252 { 1253 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are " 1254 "not compatible, ignoring %<far%>"); 1255 trap_handler = 0; 1256 } 1257 if (trap_handler) 1258 { 1259 if (trap_handler_symbol != 0) 1260 warning (OPT_Wattributes, "%<trap%> attribute is already used"); 1261 else 1262 trap_handler_symbol = XEXP (rtl, 0); 1263 } 1264 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far; 1265} 1266 1267static unsigned int 1268m68hc11_section_type_flags (tree decl, const char *name, int reloc) 1269{ 1270 unsigned int flags = default_section_type_flags (decl, name, reloc); 1271 1272 if (strncmp (name, ".eeprom", 7) == 0) 1273 { 1274 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE; 1275 } 1276 1277 return flags; 1278} 1279 1280int 1281m68hc11_is_far_symbol (rtx sym) 1282{ 1283 if (GET_CODE (sym) == MEM) 1284 sym = XEXP (sym, 0); 1285 1286 return SYMBOL_REF_FLAG (sym); 1287} 1288 1289int 1290m68hc11_is_trap_symbol (rtx sym) 1291{ 1292 if (GET_CODE (sym) == MEM) 1293 sym = XEXP (sym, 0); 1294 1295 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym); 1296} 1297 1298 1299/* Argument support functions. */ 1300 1301/* Given FROM and TO register numbers, say whether this elimination is 1302 allowed. Frame pointer elimination is automatically handled. 1303 1304 All other eliminations are valid. */ 1305 1306bool 1307m68hc11_can_eliminate (const int from, const int to) 1308{ 1309 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM 1310 ? ! frame_pointer_needed 1311 : true); 1312} 1313 1314/* Define the offset between two registers, one to be eliminated, and the 1315 other its replacement, at the start of a routine. */ 1316int 1317m68hc11_initial_elimination_offset (int from, int to) 1318{ 1319 int trap_handler; 1320 tree func_attr; 1321 int size; 1322 int regno; 1323 1324 /* For a trap handler, we must take into account the registers which 1325 are pushed on the stack during the trap (except the PC). */ 1326 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); 1327 current_function_interrupt = lookup_attribute ("interrupt", 1328 func_attr) != NULL_TREE; 1329 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; 1330 1331 if (lookup_attribute ("far", func_attr) != 0) 1332 current_function_far = 1; 1333 else if (lookup_attribute ("near", func_attr) != 0) 1334 current_function_far = 0; 1335 else 1336 current_function_far = (TARGET_LONG_CALLS != 0 1337 && !current_function_interrupt 1338 && !trap_handler); 1339 1340 if (trap_handler && from == ARG_POINTER_REGNUM) 1341 size = 7; 1342 1343 /* For a function using 'call/rtc' we must take into account the 1344 page register which is pushed in the call. */ 1345 else if (current_function_far && from == ARG_POINTER_REGNUM) 1346 size = 1; 1347 else 1348 size = 0; 1349 1350 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 1351 { 1352 /* 2 is for the saved frame. 1353 1 is for the 'sts' correction when creating the frame. */ 1354 return get_frame_size () + 2 + m68hc11_sp_correction + size; 1355 } 1356 1357 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 1358 { 1359 return m68hc11_sp_correction; 1360 } 1361 1362 /* Push any 2 byte pseudo hard registers that we need to save. */ 1363 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++) 1364 { 1365 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) 1366 { 1367 size += 2; 1368 } 1369 } 1370 1371 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM) 1372 { 1373 return get_frame_size () + size; 1374 } 1375 1376 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM) 1377 { 1378 return size; 1379 } 1380 return 0; 1381} 1382 1383/* Initialize a variable CUM of type CUMULATIVE_ARGS 1384 for a call to a function whose data type is FNTYPE. 1385 For a library call, FNTYPE is 0. */ 1386 1387void 1388m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname) 1389{ 1390 tree ret_type; 1391 1392 z_replacement_completed = 0; 1393 cum->words = 0; 1394 cum->nregs = 0; 1395 1396 /* For a library call, we must find out the type of the return value. 1397 When the return value is bigger than 4 bytes, it is returned in 1398 memory. In that case, the first argument of the library call is a 1399 pointer to the memory location. Because the first argument is passed in 1400 register D, we have to identify this, so that the first function 1401 parameter is not passed in D either. */ 1402 if (fntype == 0) 1403 { 1404 const char *name; 1405 size_t len; 1406 1407 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF) 1408 return; 1409 1410 /* If the library ends in 'di' or in 'df', we assume it's 1411 returning some DImode or some DFmode which are 64-bit wide. */ 1412 name = XSTR (libname, 0); 1413 len = strlen (name); 1414 if (len > 3 1415 && ((name[len - 2] == 'd' 1416 && (name[len - 1] == 'f' || name[len - 1] == 'i')) 1417 || (name[len - 3] == 'd' 1418 && (name[len - 2] == 'i' || name[len - 2] == 'f')))) 1419 { 1420 /* We are in. Mark the first parameter register as already used. */ 1421 cum->words = 1; 1422 cum->nregs = 1; 1423 } 1424 return; 1425 } 1426 1427 ret_type = TREE_TYPE (fntype); 1428 1429 if (ret_type && aggregate_value_p (ret_type, fntype)) 1430 { 1431 cum->words = 1; 1432 cum->nregs = 1; 1433 } 1434} 1435 1436/* Update the data in CUM to advance over an argument 1437 of mode MODE and data type TYPE. 1438 (TYPE is null for libcalls where that information may not be available.) */ 1439 1440void 1441m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, 1442 tree type, int named ATTRIBUTE_UNUSED) 1443{ 1444 if (mode != BLKmode) 1445 { 1446 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4) 1447 { 1448 cum->nregs = 2; 1449 cum->words = GET_MODE_SIZE (mode); 1450 } 1451 else 1452 { 1453 cum->words += GET_MODE_SIZE (mode); 1454 if (cum->words <= HARD_REG_SIZE) 1455 cum->nregs = 1; 1456 } 1457 } 1458 else 1459 { 1460 cum->words += int_size_in_bytes (type); 1461 } 1462 return; 1463} 1464 1465/* Define where to put the arguments to a function. 1466 Value is zero to push the argument on the stack, 1467 or a hard register in which to store the argument. 1468 1469 MODE is the argument's machine mode. 1470 TYPE is the data type of the argument (as a tree). 1471 This is null for libcalls where that information may 1472 not be available. 1473 CUM is a variable of type CUMULATIVE_ARGS which gives info about 1474 the preceding args and about the function being called. 1475 NAMED is nonzero if this argument is a named parameter 1476 (otherwise it is an extra parameter matching an ellipsis). */ 1477 1478struct rtx_def * 1479m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, 1480 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) 1481{ 1482 if (cum->words != 0) 1483 { 1484 return NULL_RTX; 1485 } 1486 1487 if (mode != BLKmode) 1488 { 1489 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE) 1490 return gen_rtx_REG (mode, HARD_X_REGNUM); 1491 1492 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE) 1493 { 1494 return NULL_RTX; 1495 } 1496 return gen_rtx_REG (mode, HARD_D_REGNUM); 1497 } 1498 return NULL_RTX; 1499} 1500 1501/* If defined, a C expression which determines whether, and in which direction, 1502 to pad out an argument with extra space. The value should be of type 1503 `enum direction': either `upward' to pad above the argument, 1504 `downward' to pad below, or `none' to inhibit padding. 1505 1506 Structures are stored left shifted in their argument slot. */ 1507enum direction 1508m68hc11_function_arg_padding (enum machine_mode mode, const_tree type) 1509{ 1510 if (type != 0 && AGGREGATE_TYPE_P (type)) 1511 return upward; 1512 1513 /* Fall back to the default. */ 1514 return DEFAULT_FUNCTION_ARG_PADDING (mode, type); 1515} 1516 1517 1518/* Function prologue and epilogue. */ 1519 1520/* Emit a move after the reload pass has completed. This is used to 1521 emit the prologue and epilogue. */ 1522static void 1523emit_move_after_reload (rtx to, rtx from, rtx scratch) 1524{ 1525 rtx insn; 1526 1527 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from)) 1528 { 1529 insn = emit_move_insn (to, from); 1530 } 1531 else 1532 { 1533 emit_move_insn (scratch, from); 1534 insn = emit_move_insn (to, scratch); 1535 } 1536 1537 /* Put a REG_INC note to tell the flow analysis that the instruction 1538 is necessary. */ 1539 if (IS_STACK_PUSH (to)) 1540 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0)); 1541 else if (IS_STACK_POP (from)) 1542 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0)); 1543 1544 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg 1545 to think that sp == _.frame and later replace a x = sp with x = _.frame. 1546 The problem is that we are lying to gcc and use `txs' for x = sp 1547 (which is not really true because txs is really x = sp + 1). */ 1548 else if (TARGET_M6811 && SP_REG_P (from)) 1549 add_reg_note (insn, REG_INC, from); 1550} 1551 1552int 1553m68hc11_total_frame_size (void) 1554{ 1555 int size; 1556 int regno; 1557 1558 size = get_frame_size (); 1559 if (current_function_interrupt) 1560 { 1561 size += 3 * HARD_REG_SIZE; 1562 } 1563 if (frame_pointer_needed) 1564 size += HARD_REG_SIZE; 1565 1566 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) 1567 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) 1568 size += HARD_REG_SIZE; 1569 1570 return size; 1571} 1572 1573static void 1574m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED, 1575 HOST_WIDE_INT size ATTRIBUTE_UNUSED) 1576{ 1577 /* We catch the function epilogue generation to have a chance 1578 to clear the z_replacement_completed flag. */ 1579 z_replacement_completed = 0; 1580} 1581 1582void 1583expand_prologue (void) 1584{ 1585 tree func_attr; 1586 int size; 1587 int regno; 1588 rtx scratch; 1589 1590 gcc_assert (reload_completed == 1); 1591 1592 size = get_frame_size (); 1593 1594 create_regs_rtx (); 1595 1596 /* Generate specific prologue for interrupt handlers. */ 1597 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); 1598 current_function_interrupt = lookup_attribute ("interrupt", 1599 func_attr) != NULL_TREE; 1600 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE; 1601 if (lookup_attribute ("far", func_attr) != NULL_TREE) 1602 current_function_far = 1; 1603 else if (lookup_attribute ("near", func_attr) != NULL_TREE) 1604 current_function_far = 0; 1605 else 1606 current_function_far = (TARGET_LONG_CALLS != 0 1607 && !current_function_interrupt 1608 && !current_function_trap); 1609 1610 /* Get the scratch register to build the frame and push registers. 1611 If the first argument is a 32-bit quantity, the D+X registers 1612 are used. Use Y to compute the frame. Otherwise, X is cheaper. 1613 For 68HC12, this scratch register is not used. */ 1614 if (crtl->args.info.nregs == 2) 1615 scratch = iy_reg; 1616 else 1617 scratch = ix_reg; 1618 1619 /* Save current stack frame. */ 1620 if (frame_pointer_needed) 1621 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch); 1622 1623 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy. 1624 Other soft registers in page0 need not to be saved because they 1625 will be restored by C functions. For a trap handler, we don't 1626 need to preserve these registers because this is a synchronous call. */ 1627 if (current_function_interrupt) 1628 { 1629 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch); 1630 emit_move_after_reload (stack_push_word, 1631 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch); 1632 emit_move_after_reload (stack_push_word, 1633 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), 1634 scratch); 1635 } 1636 1637 /* Allocate local variables. */ 1638 if (TARGET_M6812 && (size > 4 || size == 3)) 1639 { 1640 emit_insn (gen_addhi3 (stack_pointer_rtx, 1641 stack_pointer_rtx, GEN_INT (-size))); 1642 } 1643 else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) 1644 { 1645 rtx insn; 1646 1647 insn = gen_rtx_PARALLEL 1648 (VOIDmode, 1649 gen_rtvec (2, 1650 gen_rtx_SET (VOIDmode, 1651 stack_pointer_rtx, 1652 gen_rtx_PLUS (HImode, 1653 stack_pointer_rtx, 1654 GEN_INT (-size))), 1655 gen_rtx_CLOBBER (VOIDmode, scratch))); 1656 emit_insn (insn); 1657 } 1658 else 1659 { 1660 int i; 1661 1662 /* Allocate by pushing scratch values. */ 1663 for (i = 2; i <= size; i += 2) 1664 emit_move_after_reload (stack_push_word, ix_reg, 0); 1665 1666 if (size & 1) 1667 emit_insn (gen_addhi3 (stack_pointer_rtx, 1668 stack_pointer_rtx, constm1_rtx)); 1669 } 1670 1671 /* Create the frame pointer. */ 1672 if (frame_pointer_needed) 1673 emit_move_after_reload (hard_frame_pointer_rtx, 1674 stack_pointer_rtx, scratch); 1675 1676 /* Push any 2 byte pseudo hard registers that we need to save. */ 1677 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) 1678 { 1679 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) 1680 { 1681 emit_move_after_reload (stack_push_word, 1682 gen_rtx_REG (HImode, regno), scratch); 1683 } 1684 } 1685} 1686 1687void 1688expand_epilogue (void) 1689{ 1690 int size; 1691 register int regno; 1692 int return_size; 1693 rtx scratch; 1694 1695 gcc_assert (reload_completed == 1); 1696 1697 size = get_frame_size (); 1698 1699 /* If we are returning a value in two registers, we have to preserve the 1700 X register and use the Y register to restore the stack and the saved 1701 registers. Otherwise, use X because it's faster (and smaller). */ 1702 if (crtl->return_rtx == 0) 1703 return_size = 0; 1704 else if (GET_CODE (crtl->return_rtx) == MEM) 1705 return_size = HARD_REG_SIZE; 1706 else 1707 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx)); 1708 1709 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE) 1710 scratch = iy_reg; 1711 else 1712 scratch = ix_reg; 1713 1714 /* Pop any 2 byte pseudo hard registers that we saved. */ 1715 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--) 1716 { 1717 if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) 1718 { 1719 emit_move_after_reload (gen_rtx_REG (HImode, regno), 1720 stack_pop_word, scratch); 1721 } 1722 } 1723 1724 /* de-allocate auto variables */ 1725 if (TARGET_M6812 && (size > 4 || size == 3)) 1726 { 1727 emit_insn (gen_addhi3 (stack_pointer_rtx, 1728 stack_pointer_rtx, GEN_INT (size))); 1729 } 1730 else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) 1731 { 1732 rtx insn; 1733 1734 insn = gen_rtx_PARALLEL 1735 (VOIDmode, 1736 gen_rtvec (2, 1737 gen_rtx_SET (VOIDmode, 1738 stack_pointer_rtx, 1739 gen_rtx_PLUS (HImode, 1740 stack_pointer_rtx, 1741 GEN_INT (size))), 1742 gen_rtx_CLOBBER (VOIDmode, scratch))); 1743 emit_insn (insn); 1744 } 1745 else 1746 { 1747 int i; 1748 1749 for (i = 2; i <= size; i += 2) 1750 emit_move_after_reload (scratch, stack_pop_word, scratch); 1751 if (size & 1) 1752 emit_insn (gen_addhi3 (stack_pointer_rtx, 1753 stack_pointer_rtx, const1_rtx)); 1754 } 1755 1756 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */ 1757 if (current_function_interrupt) 1758 { 1759 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), 1760 stack_pop_word, scratch); 1761 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM), 1762 stack_pop_word, scratch); 1763 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch); 1764 } 1765 1766 /* Restore previous frame pointer. */ 1767 if (frame_pointer_needed) 1768 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch); 1769 1770 /* If the trap handler returns some value, copy the value 1771 in D, X onto the stack so that the rti will pop the return value 1772 correctly. */ 1773 else if (current_function_trap && return_size != 0) 1774 { 1775 rtx addr_reg = stack_pointer_rtx; 1776 1777 if (!TARGET_M6812) 1778 { 1779 emit_move_after_reload (scratch, stack_pointer_rtx, 0); 1780 addr_reg = scratch; 1781 } 1782 emit_move_after_reload (gen_rtx_MEM (HImode, 1783 gen_rtx_PLUS (HImode, addr_reg, 1784 const1_rtx)), d_reg, 0); 1785 if (return_size > HARD_REG_SIZE) 1786 emit_move_after_reload (gen_rtx_MEM (HImode, 1787 gen_rtx_PLUS (HImode, addr_reg, 1788 GEN_INT (3))), ix_reg, 0); 1789 } 1790 1791 emit_jump_insn (gen_return ()); 1792} 1793 1794 1795/* Low and High part extraction for 68HC11. These routines are 1796 similar to gen_lowpart and gen_highpart but they have been 1797 fixed to work for constants and 68HC11 specific registers. */ 1798 1799rtx 1800m68hc11_gen_lowpart (enum machine_mode mode, rtx x) 1801{ 1802 /* We assume that the low part of an auto-inc mode is the same with 1803 the mode changed and that the caller split the larger mode in the 1804 correct order. */ 1805 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) 1806 { 1807 return gen_rtx_MEM (mode, XEXP (x, 0)); 1808 } 1809 1810 /* Note that a CONST_DOUBLE rtx could represent either an integer or a 1811 floating-point constant. A CONST_DOUBLE is used whenever the 1812 constant requires more than one word in order to be adequately 1813 represented. */ 1814 if (GET_CODE (x) == CONST_DOUBLE) 1815 { 1816 long l[2]; 1817 1818 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 1819 { 1820 REAL_VALUE_TYPE r; 1821 1822 if (GET_MODE (x) == SFmode) 1823 { 1824 REAL_VALUE_FROM_CONST_DOUBLE (r, x); 1825 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]); 1826 } 1827 else 1828 { 1829 rtx first, second; 1830 1831 split_double (x, &first, &second); 1832 return second; 1833 } 1834 if (mode == SImode) 1835 return GEN_INT (l[0]); 1836 1837 return gen_int_mode (l[0], HImode); 1838 } 1839 else 1840 { 1841 l[0] = CONST_DOUBLE_LOW (x); 1842 } 1843 switch (mode) 1844 { 1845 case SImode: 1846 return GEN_INT (l[0]); 1847 case HImode: 1848 gcc_assert (GET_MODE (x) == SFmode); 1849 return gen_int_mode (l[0], HImode); 1850 default: 1851 gcc_unreachable (); 1852 } 1853 } 1854 1855 if (mode == QImode && D_REG_P (x)) 1856 return gen_rtx_REG (mode, HARD_B_REGNUM); 1857 1858 /* gen_lowpart crashes when it is called with a SUBREG. */ 1859 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0) 1860 { 1861 switch (mode) 1862 { 1863 case SImode: 1864 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4); 1865 case HImode: 1866 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2); 1867 default: 1868 gcc_unreachable (); 1869 } 1870 } 1871 x = gen_lowpart (mode, x); 1872 1873 /* Return a different rtx to avoid to share it in several insns 1874 (when used by a split pattern). Sharing addresses within 1875 a MEM breaks the Z register replacement (and reloading). */ 1876 if (GET_CODE (x) == MEM) 1877 x = copy_rtx (x); 1878 return x; 1879} 1880 1881rtx 1882m68hc11_gen_highpart (enum machine_mode mode, rtx x) 1883{ 1884 /* We assume that the high part of an auto-inc mode is the same with 1885 the mode changed and that the caller split the larger mode in the 1886 correct order. */ 1887 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) 1888 { 1889 return gen_rtx_MEM (mode, XEXP (x, 0)); 1890 } 1891 1892 /* Note that a CONST_DOUBLE rtx could represent either an integer or a 1893 floating-point constant. A CONST_DOUBLE is used whenever the 1894 constant requires more than one word in order to be adequately 1895 represented. */ 1896 if (GET_CODE (x) == CONST_DOUBLE) 1897 { 1898 long l[2]; 1899 1900 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 1901 { 1902 REAL_VALUE_TYPE r; 1903 1904 if (GET_MODE (x) == SFmode) 1905 { 1906 REAL_VALUE_FROM_CONST_DOUBLE (r, x); 1907 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]); 1908 } 1909 else 1910 { 1911 rtx first, second; 1912 1913 split_double (x, &first, &second); 1914 return first; 1915 } 1916 if (mode == SImode) 1917 return GEN_INT (l[1]); 1918 1919 return gen_int_mode ((l[1] >> 16), HImode); 1920 } 1921 else 1922 { 1923 l[1] = CONST_DOUBLE_HIGH (x); 1924 } 1925 1926 switch (mode) 1927 { 1928 case SImode: 1929 return GEN_INT (l[1]); 1930 case HImode: 1931 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT); 1932 return gen_int_mode ((l[0] >> 16), HImode); 1933 default: 1934 gcc_unreachable (); 1935 } 1936 } 1937 if (GET_CODE (x) == CONST_INT) 1938 { 1939 HOST_WIDE_INT val = INTVAL (x); 1940 1941 if (mode == QImode) 1942 { 1943 return gen_int_mode (val >> 8, QImode); 1944 } 1945 else if (mode == HImode) 1946 { 1947 return gen_int_mode (val >> 16, HImode); 1948 } 1949 else if (mode == SImode) 1950 { 1951 return gen_int_mode (val >> 32, SImode); 1952 } 1953 } 1954 if (mode == QImode && D_REG_P (x)) 1955 return gen_rtx_REG (mode, HARD_A_REGNUM); 1956 1957 /* There is no way in GCC to represent the upper part of a word register. 1958 To obtain the 8-bit upper part of a soft register, we change the 1959 reg into a mem rtx. This is possible because they are physically 1960 located in memory. There is no offset because we are big-endian. */ 1961 if (mode == QImode && S_REG_P (x)) 1962 { 1963 int pos; 1964 1965 /* Avoid the '*' for direct addressing mode when this 1966 addressing mode is disabled. */ 1967 pos = TARGET_NO_DIRECT_MODE ? 1 : 0; 1968 return gen_rtx_MEM (QImode, 1969 gen_rtx_SYMBOL_REF (Pmode, 1970 ®_names[REGNO (x)][pos])); 1971 } 1972 1973 /* gen_highpart crashes when it is called with a SUBREG. */ 1974 switch (GET_CODE (x)) 1975 { 1976 case SUBREG: 1977 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1)); 1978 case REG: 1979 if (REGNO (x) < FIRST_PSEUDO_REGISTER) 1980 return gen_rtx_REG (mode, REGNO (x)); 1981 else 1982 return gen_rtx_SUBREG (mode, x, 0); 1983 case MEM: 1984 x = change_address (x, mode, 0); 1985 1986 /* Return a different rtx to avoid to share it in several insns 1987 (when used by a split pattern). Sharing addresses within 1988 a MEM breaks the Z register replacement (and reloading). */ 1989 if (GET_CODE (x) == MEM) 1990 x = copy_rtx (x); 1991 return x; 1992 1993 default: 1994 gcc_unreachable (); 1995 } 1996} 1997 1998 1999/* Obscure register manipulation. */ 2000 2001/* Finds backward in the instructions to see if register 'reg' is 2002 dead. This is used when generating code to see if we can use 'reg' 2003 as a scratch register. This allows us to choose a better generation 2004 of code when we know that some register dies or can be clobbered. */ 2005 2006int 2007dead_register_here (rtx x, rtx reg) 2008{ 2009 rtx x_reg; 2010 rtx p; 2011 2012 if (D_REG_P (reg)) 2013 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM); 2014 else 2015 x_reg = 0; 2016 2017 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p)) 2018 if (INSN_P (p)) 2019 { 2020 rtx body; 2021 2022 body = PATTERN (p); 2023 2024 if (GET_CODE (body) == CALL_INSN) 2025 break; 2026 if (GET_CODE (body) == JUMP_INSN) 2027 break; 2028 2029 if (GET_CODE (body) == SET) 2030 { 2031 rtx dst = XEXP (body, 0); 2032 2033 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg)) 2034 break; 2035 if (x_reg && rtx_equal_p (dst, x_reg)) 2036 break; 2037 2038 if (find_regno_note (p, REG_DEAD, REGNO (reg))) 2039 return 1; 2040 } 2041 else if (reg_mentioned_p (reg, p) 2042 || (x_reg && reg_mentioned_p (x_reg, p))) 2043 break; 2044 } 2045 2046 /* Scan forward to see if the register is set in some insns and never 2047 used since then. */ 2048 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p)) 2049 { 2050 rtx body; 2051 2052 if (GET_CODE (p) == CODE_LABEL 2053 || GET_CODE (p) == JUMP_INSN 2054 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER) 2055 break; 2056 2057 if (GET_CODE (p) != INSN) 2058 continue; 2059 2060 body = PATTERN (p); 2061 if (GET_CODE (body) == SET) 2062 { 2063 rtx src = XEXP (body, 1); 2064 rtx dst = XEXP (body, 0); 2065 2066 if (GET_CODE (dst) == REG 2067 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src)) 2068 return 1; 2069 } 2070 2071 /* Register is used (may be in source or in dest). */ 2072 if (reg_mentioned_p (reg, p) 2073 || (x_reg != 0 && GET_MODE (p) == SImode 2074 && reg_mentioned_p (x_reg, p))) 2075 break; 2076 } 2077 return p == 0 ? 1 : 0; 2078} 2079 2080 2081/* Code generation operations called from machine description file. */ 2082 2083/* Print the name of register 'regno' in the assembly file. */ 2084static void 2085asm_print_register (FILE *file, int regno) 2086{ 2087 const char *name = reg_names[regno]; 2088 2089 if (TARGET_NO_DIRECT_MODE && name[0] == '*') 2090 name++; 2091 2092 fprintf (file, "%s", name); 2093} 2094 2095/* A C compound statement to output to stdio stream STREAM the 2096 assembler syntax for an instruction operand X. X is an RTL 2097 expression. 2098 2099 CODE is a value that can be used to specify one of several ways 2100 of printing the operand. It is used when identical operands 2101 must be printed differently depending on the context. CODE 2102 comes from the `%' specification that was used to request 2103 printing of the operand. If the specification was just `%DIGIT' 2104 then CODE is 0; if the specification was `%LTR DIGIT' then CODE 2105 is the ASCII code for LTR. 2106 2107 If X is a register, this macro should print the register's name. 2108 The names can be found in an array `reg_names' whose type is 2109 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. 2110 2111 When the machine description has a specification `%PUNCT' (a `%' 2112 followed by a punctuation character), this macro is called with 2113 a null pointer for X and the punctuation character for CODE. 2114 2115 The M68HC11 specific codes are: 2116 2117 'b' for the low part of the operand. 2118 'h' for the high part of the operand 2119 The 'b' or 'h' modifiers have no effect if the operand has 2120 the QImode and is not a S_REG_P (soft register). If the 2121 operand is a hard register, these two modifiers have no effect. 2122 't' generate the temporary scratch register. The operand is 2123 ignored. 2124 'T' generate the low-part temporary scratch register. The operand is 2125 ignored. */ 2126 2127void 2128print_operand (FILE *file, rtx op, int letter) 2129{ 2130 if (letter == 't') 2131 { 2132 asm_print_register (file, SOFT_TMP_REGNUM); 2133 return; 2134 } 2135 else if (letter == 'T') 2136 { 2137 asm_print_register (file, SOFT_TMP_REGNUM); 2138 fprintf (file, "+1"); 2139 return; 2140 } 2141 else if (letter == '#') 2142 { 2143 asm_fprintf (file, "%I"); 2144 } 2145 2146 if (GET_CODE (op) == REG) 2147 { 2148 if (letter == 'b' && S_REG_P (op)) 2149 { 2150 asm_print_register (file, REGNO (op)); 2151 fprintf (file, "+1"); 2152 } 2153 else if (letter == 'b' && D_REG_P (op)) 2154 { 2155 asm_print_register (file, HARD_B_REGNUM); 2156 } 2157 else 2158 { 2159 asm_print_register (file, REGNO (op)); 2160 } 2161 return; 2162 } 2163 2164 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h')) 2165 { 2166 if (letter == 'b') 2167 asm_fprintf (file, "%I%%lo("); 2168 else 2169 asm_fprintf (file, "%I%%hi("); 2170 2171 output_addr_const (file, op); 2172 fprintf (file, ")"); 2173 return; 2174 } 2175 2176 /* Get the low or high part of the operand when 'b' or 'h' modifiers 2177 are specified. If we already have a QImode, there is nothing to do. */ 2178 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode) 2179 { 2180 if (letter == 'b') 2181 { 2182 op = m68hc11_gen_lowpart (QImode, op); 2183 } 2184 else if (letter == 'h') 2185 { 2186 op = m68hc11_gen_highpart (QImode, op); 2187 } 2188 } 2189 2190 if (GET_CODE (op) == MEM) 2191 { 2192 rtx base = XEXP (op, 0); 2193 switch (GET_CODE (base)) 2194 { 2195 case PRE_DEC: 2196 gcc_assert (TARGET_M6812); 2197 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op))); 2198 asm_print_register (file, REGNO (XEXP (base, 0))); 2199 break; 2200 2201 case POST_DEC: 2202 gcc_assert (TARGET_M6812); 2203 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); 2204 asm_print_register (file, REGNO (XEXP (base, 0))); 2205 fprintf (file, "-"); 2206 break; 2207 2208 case POST_INC: 2209 gcc_assert (TARGET_M6812); 2210 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); 2211 asm_print_register (file, REGNO (XEXP (base, 0))); 2212 fprintf (file, "+"); 2213 break; 2214 2215 case PRE_INC: 2216 gcc_assert (TARGET_M6812); 2217 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op))); 2218 asm_print_register (file, REGNO (XEXP (base, 0))); 2219 break; 2220 2221 case MEM: 2222 gcc_assert (TARGET_M6812); 2223 fprintf (file, "["); 2224 print_operand_address (file, XEXP (base, 0)); 2225 fprintf (file, "]"); 2226 break; 2227 2228 default: 2229 if (m68hc11_page0_symbol_p (base)) 2230 fprintf (file, "*"); 2231 2232 output_address (base); 2233 break; 2234 } 2235 } 2236 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode) 2237 { 2238 REAL_VALUE_TYPE r; 2239 long l; 2240 2241 REAL_VALUE_FROM_CONST_DOUBLE (r, op); 2242 REAL_VALUE_TO_TARGET_SINGLE (r, l); 2243 asm_fprintf (file, "%I0x%lx", l); 2244 } 2245 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode) 2246 { 2247 char dstr[30]; 2248 2249 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op), 2250 sizeof (dstr), 0, 1); 2251 asm_fprintf (file, "%I0r%s", dstr); 2252 } 2253 else 2254 { 2255 int need_parenthesize = 0; 2256 2257 if (letter != 'i') 2258 asm_fprintf (file, "%I"); 2259 else 2260 need_parenthesize = must_parenthesize (op); 2261 2262 if (need_parenthesize) 2263 fprintf (file, "("); 2264 2265 output_addr_const (file, op); 2266 if (need_parenthesize) 2267 fprintf (file, ")"); 2268 } 2269} 2270 2271/* Returns true if the operand 'op' must be printed with parenthesis 2272 around it. This must be done only if there is a symbol whose name 2273 is a processor register. */ 2274static int 2275must_parenthesize (rtx op) 2276{ 2277 const char *name; 2278 2279 switch (GET_CODE (op)) 2280 { 2281 case SYMBOL_REF: 2282 name = XSTR (op, 0); 2283 /* Avoid a conflict between symbol name and a possible 2284 register. */ 2285 return (strcasecmp (name, "a") == 0 2286 || strcasecmp (name, "b") == 0 2287 || strcasecmp (name, "d") == 0 2288 || strcasecmp (name, "x") == 0 2289 || strcasecmp (name, "y") == 0 2290 || strcasecmp (name, "ix") == 0 2291 || strcasecmp (name, "iy") == 0 2292 || strcasecmp (name, "pc") == 0 2293 || strcasecmp (name, "sp") == 0 2294 || strcasecmp (name, "ccr") == 0) ? 1 : 0; 2295 2296 case PLUS: 2297 case MINUS: 2298 return must_parenthesize (XEXP (op, 0)) 2299 || must_parenthesize (XEXP (op, 1)); 2300 2301 case MEM: 2302 case CONST: 2303 case ZERO_EXTEND: 2304 case SIGN_EXTEND: 2305 return must_parenthesize (XEXP (op, 0)); 2306 2307 case CONST_DOUBLE: 2308 case CONST_INT: 2309 case LABEL_REF: 2310 case CODE_LABEL: 2311 default: 2312 return 0; 2313 } 2314} 2315 2316/* A C compound statement to output to stdio stream STREAM the 2317 assembler syntax for an instruction operand that is a memory 2318 reference whose address is ADDR. ADDR is an RTL expression. */ 2319 2320void 2321print_operand_address (FILE *file, rtx addr) 2322{ 2323 rtx base; 2324 rtx offset; 2325 int need_parenthesis = 0; 2326 2327 switch (GET_CODE (addr)) 2328 { 2329 case REG: 2330 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr)); 2331 2332 fprintf (file, "0,"); 2333 asm_print_register (file, REGNO (addr)); 2334 break; 2335 2336 case MEM: 2337 base = XEXP (addr, 0); 2338 switch (GET_CODE (base)) 2339 { 2340 case PRE_DEC: 2341 gcc_assert (TARGET_M6812); 2342 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr))); 2343 asm_print_register (file, REGNO (XEXP (base, 0))); 2344 break; 2345 2346 case POST_DEC: 2347 gcc_assert (TARGET_M6812); 2348 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); 2349 asm_print_register (file, REGNO (XEXP (base, 0))); 2350 fprintf (file, "-"); 2351 break; 2352 2353 case POST_INC: 2354 gcc_assert (TARGET_M6812); 2355 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); 2356 asm_print_register (file, REGNO (XEXP (base, 0))); 2357 fprintf (file, "+"); 2358 break; 2359 2360 case PRE_INC: 2361 gcc_assert (TARGET_M6812); 2362 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr))); 2363 asm_print_register (file, REGNO (XEXP (base, 0))); 2364 break; 2365 2366 default: 2367 need_parenthesis = must_parenthesize (base); 2368 if (need_parenthesis) 2369 fprintf (file, "("); 2370 2371 output_addr_const (file, base); 2372 if (need_parenthesis) 2373 fprintf (file, ")"); 2374 break; 2375 } 2376 break; 2377 2378 case PLUS: 2379 base = XEXP (addr, 0); 2380 offset = XEXP (addr, 1); 2381 if (!G_REG_P (base) && G_REG_P (offset)) 2382 { 2383 base = XEXP (addr, 1); 2384 offset = XEXP (addr, 0); 2385 } 2386 if (CONSTANT_ADDRESS_P (base)) 2387 { 2388 need_parenthesis = must_parenthesize (addr); 2389 2390 gcc_assert (CONSTANT_ADDRESS_P (offset)); 2391 if (need_parenthesis) 2392 fprintf (file, "("); 2393 2394 output_addr_const (file, base); 2395 fprintf (file, "+"); 2396 output_addr_const (file, offset); 2397 if (need_parenthesis) 2398 fprintf (file, ")"); 2399 } 2400 else 2401 { 2402 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base)); 2403 if (REG_P (offset)) 2404 { 2405 gcc_assert (TARGET_M6812); 2406 asm_print_register (file, REGNO (offset)); 2407 fprintf (file, ","); 2408 asm_print_register (file, REGNO (base)); 2409 } 2410 else 2411 { 2412 need_parenthesis = must_parenthesize (offset); 2413 if (need_parenthesis) 2414 fprintf (file, "("); 2415 2416 output_addr_const (file, offset); 2417 if (need_parenthesis) 2418 fprintf (file, ")"); 2419 fprintf (file, ","); 2420 asm_print_register (file, REGNO (base)); 2421 } 2422 } 2423 break; 2424 2425 default: 2426 if (GET_CODE (addr) == CONST_INT 2427 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000) 2428 { 2429 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr)); 2430 } 2431 else 2432 { 2433 need_parenthesis = must_parenthesize (addr); 2434 if (need_parenthesis) 2435 fprintf (file, "("); 2436 2437 output_addr_const (file, addr); 2438 if (need_parenthesis) 2439 fprintf (file, ")"); 2440 } 2441 break; 2442 } 2443} 2444 2445 2446/* Splitting of some instructions. */ 2447 2448static rtx 2449m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1) 2450{ 2451 rtx ret = 0; 2452 2453 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT); 2454 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, 2455 gen_rtx_COMPARE (VOIDmode, op0, op1))); 2456 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); 2457 2458 return ret; 2459} 2460 2461rtx 2462m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1, 2463 rtx label) 2464{ 2465 rtx tmp; 2466 2467 switch (GET_MODE (op0)) 2468 { 2469 case QImode: 2470 case HImode: 2471 tmp = m68hc11_expand_compare (code, op0, op1); 2472 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, 2473 gen_rtx_LABEL_REF (VOIDmode, label), 2474 pc_rtx); 2475 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); 2476 return 0; 2477#if 0 2478 2479 /* SCz: from i386.c */ 2480 case SFmode: 2481 case DFmode: 2482 /* Don't expand the comparison early, so that we get better code 2483 when jump or whoever decides to reverse the comparison. */ 2484 { 2485 rtvec vec; 2486 int use_fcomi; 2487 2488 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0, 2489 &m68hc11_compare_op1); 2490 2491 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code), 2492 m68hc11_compare_op0, m68hc11_compare_op1); 2493 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, 2494 gen_rtx_LABEL_REF (VOIDmode, label), 2495 pc_rtx); 2496 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp); 2497 2498 use_fcomi = ix86_use_fcomi_compare (code); 2499 vec = rtvec_alloc (3 + !use_fcomi); 2500 RTVEC_ELT (vec, 0) = tmp; 2501 RTVEC_ELT (vec, 1) 2502 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18)); 2503 RTVEC_ELT (vec, 2) 2504 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17)); 2505 if (!use_fcomi) 2506 RTVEC_ELT (vec, 3) 2507 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode)); 2508 2509 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec)); 2510 return; 2511 } 2512#endif 2513 2514 case SImode: 2515 /* Expand SImode branch into multiple compare+branch. */ 2516 { 2517 rtx lo[2], hi[2], label2; 2518 enum rtx_code code1, code2, code3; 2519 2520 if (CONSTANT_P (op0) && !CONSTANT_P (op1)) 2521 { 2522 tmp = op0; 2523 op0 = op1; 2524 op1 = tmp; 2525 code = swap_condition (code); 2526 } 2527 lo[0] = m68hc11_gen_lowpart (HImode, op0); 2528 lo[1] = m68hc11_gen_lowpart (HImode, op1); 2529 hi[0] = m68hc11_gen_highpart (HImode, op0); 2530 hi[1] = m68hc11_gen_highpart (HImode, op1); 2531 2532 /* Otherwise, if we are doing less-than, op1 is a constant and the 2533 low word is zero, then we can just examine the high word. */ 2534 2535 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx 2536 && (code == LT || code == LTU)) 2537 { 2538 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1], 2539 label); 2540 } 2541 2542 /* Otherwise, we need two or three jumps. */ 2543 2544 label2 = gen_label_rtx (); 2545 2546 code1 = code; 2547 code2 = swap_condition (code); 2548 code3 = unsigned_condition (code); 2549 2550 switch (code) 2551 { 2552 case LT: 2553 case GT: 2554 case LTU: 2555 case GTU: 2556 break; 2557 2558 case LE: 2559 code1 = LT; 2560 code2 = GT; 2561 break; 2562 case GE: 2563 code1 = GT; 2564 code2 = LT; 2565 break; 2566 case LEU: 2567 code1 = LTU; 2568 code2 = GTU; 2569 break; 2570 case GEU: 2571 code1 = GTU; 2572 code2 = LTU; 2573 break; 2574 2575 case EQ: 2576 code1 = UNKNOWN; 2577 code2 = NE; 2578 break; 2579 case NE: 2580 code2 = UNKNOWN; 2581 break; 2582 2583 default: 2584 gcc_unreachable (); 2585 } 2586 2587 /* 2588 * a < b => 2589 * if (hi(a) < hi(b)) goto true; 2590 * if (hi(a) > hi(b)) goto false; 2591 * if (lo(a) < lo(b)) goto true; 2592 * false: 2593 */ 2594 if (code1 != UNKNOWN) 2595 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label); 2596 if (code2 != UNKNOWN) 2597 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2); 2598 2599 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label); 2600 2601 if (code2 != UNKNOWN) 2602 emit_label (label2); 2603 return 0; 2604 } 2605 2606 default: 2607 gcc_unreachable (); 2608 } 2609 return 0; 2610} 2611 2612/* Return the increment/decrement mode of a MEM if it is such. 2613 Return CONST if it is anything else. */ 2614static int 2615autoinc_mode (rtx x) 2616{ 2617 if (GET_CODE (x) != MEM) 2618 return CONST; 2619 2620 x = XEXP (x, 0); 2621 if (GET_CODE (x) == PRE_INC 2622 || GET_CODE (x) == PRE_DEC 2623 || GET_CODE (x) == POST_INC 2624 || GET_CODE (x) == POST_DEC) 2625 return GET_CODE (x); 2626 2627 return CONST; 2628} 2629 2630static int 2631m68hc11_make_autoinc_notes (rtx *x, void *data) 2632{ 2633 rtx insn; 2634 2635 switch (GET_CODE (*x)) 2636 { 2637 case PRE_DEC: 2638 case PRE_INC: 2639 case POST_DEC: 2640 case POST_INC: 2641 insn = (rtx) data; 2642 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0), 2643 REG_NOTES (insn)); 2644 return -1; 2645 2646 default: 2647 return 0; 2648 } 2649} 2650 2651/* Split a DI, SI or HI move into several smaller move operations. 2652 The scratch register 'scratch' is used as a temporary to load 2653 store intermediate values. It must be a hard register. */ 2654void 2655m68hc11_split_move (rtx to, rtx from, rtx scratch) 2656{ 2657 rtx low_to, low_from; 2658 rtx high_to, high_from; 2659 rtx insn; 2660 enum machine_mode mode; 2661 int offset = 0; 2662 int autoinc_from = autoinc_mode (from); 2663 int autoinc_to = autoinc_mode (to); 2664 2665 mode = GET_MODE (to); 2666 2667 /* If the TO and FROM contain autoinc modes that are not compatible 2668 together (one pop and the other a push), we must change one to 2669 an offsetable operand and generate an appropriate add at the end. */ 2670 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2) 2671 { 2672 rtx reg; 2673 int code; 2674 2675 /* The source uses an autoinc mode which is not compatible with 2676 a split (this would result in a word swap). */ 2677 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC) 2678 { 2679 code = GET_CODE (XEXP (from, 0)); 2680 reg = XEXP (XEXP (from, 0), 0); 2681 offset = GET_MODE_SIZE (GET_MODE (from)); 2682 if (code == POST_DEC) 2683 offset = -offset; 2684 2685 if (code == PRE_INC) 2686 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2687 2688 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch); 2689 if (code == POST_DEC) 2690 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2691 return; 2692 } 2693 2694 /* Likewise for destination. */ 2695 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC) 2696 { 2697 code = GET_CODE (XEXP (to, 0)); 2698 reg = XEXP (XEXP (to, 0), 0); 2699 offset = GET_MODE_SIZE (GET_MODE (to)); 2700 if (code == POST_DEC) 2701 offset = -offset; 2702 2703 if (code == PRE_INC) 2704 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2705 2706 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch); 2707 if (code == POST_DEC) 2708 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2709 return; 2710 } 2711 2712 /* The source and destination auto increment modes must be compatible 2713 with each other: same direction. */ 2714 if ((autoinc_to != autoinc_from 2715 && autoinc_to != CONST && autoinc_from != CONST) 2716 /* The destination address register must not be used within 2717 the source operand because the source address would change 2718 while doing the copy. */ 2719 || (autoinc_to != CONST 2720 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from) 2721 && !IS_STACK_PUSH (to))) 2722 { 2723 /* Must change the destination. */ 2724 code = GET_CODE (XEXP (to, 0)); 2725 reg = XEXP (XEXP (to, 0), 0); 2726 offset = GET_MODE_SIZE (GET_MODE (to)); 2727 if (code == PRE_DEC || code == POST_DEC) 2728 offset = -offset; 2729 2730 if (code == PRE_DEC || code == PRE_INC) 2731 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2732 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch); 2733 if (code == POST_DEC || code == POST_INC) 2734 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2735 2736 return; 2737 } 2738 2739 /* Likewise, the source address register must not be used within 2740 the destination operand. */ 2741 if (autoinc_from != CONST 2742 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to) 2743 && !IS_STACK_PUSH (to)) 2744 { 2745 /* Must change the source. */ 2746 code = GET_CODE (XEXP (from, 0)); 2747 reg = XEXP (XEXP (from, 0), 0); 2748 offset = GET_MODE_SIZE (GET_MODE (from)); 2749 if (code == PRE_DEC || code == POST_DEC) 2750 offset = -offset; 2751 2752 if (code == PRE_DEC || code == PRE_INC) 2753 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2754 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch); 2755 if (code == POST_DEC || code == POST_INC) 2756 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); 2757 2758 return; 2759 } 2760 } 2761 2762 if (GET_MODE_SIZE (mode) == 8) 2763 mode = SImode; 2764 else if (GET_MODE_SIZE (mode) == 4) 2765 mode = HImode; 2766 else 2767 mode = QImode; 2768 2769 if (TARGET_M6812 2770 && IS_STACK_PUSH (to) 2771 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from)) 2772 { 2773 if (mode == SImode) 2774 { 2775 offset = 4; 2776 } 2777 else if (mode == HImode) 2778 { 2779 offset = 2; 2780 } 2781 else 2782 offset = 0; 2783 } 2784 2785 low_to = m68hc11_gen_lowpart (mode, to); 2786 high_to = m68hc11_gen_highpart (mode, to); 2787 2788 low_from = m68hc11_gen_lowpart (mode, from); 2789 high_from = m68hc11_gen_highpart (mode, from); 2790 2791 if (offset) 2792 { 2793 high_from = adjust_address (high_from, mode, offset); 2794 low_from = high_from; 2795 } 2796 2797 /* When copying with a POST_INC mode, we must copy the 2798 high part and then the low part to guarantee a correct 2799 32/64-bit copy. */ 2800 if (TARGET_M6812 2801 && GET_MODE_SIZE (mode) >= 2 2802 && autoinc_from != autoinc_to 2803 && (autoinc_from == POST_INC || autoinc_to == POST_INC)) 2804 { 2805 rtx swap; 2806 2807 swap = low_to; 2808 low_to = high_to; 2809 high_to = swap; 2810 2811 swap = low_from; 2812 low_from = high_from; 2813 high_from = swap; 2814 } 2815 if (mode == SImode) 2816 { 2817 m68hc11_split_move (low_to, low_from, scratch); 2818 m68hc11_split_move (high_to, high_from, scratch); 2819 } 2820 else if (H_REG_P (to) || H_REG_P (from) 2821 || (low_from == const0_rtx 2822 && high_from == const0_rtx 2823 && ! push_operand (to, GET_MODE (to)) 2824 && ! H_REG_P (scratch)) 2825 || (TARGET_M6812 2826 && (!m68hc11_register_indirect_p (from, GET_MODE (from)) 2827 || m68hc11_small_indexed_indirect_p (from, 2828 GET_MODE (from))) 2829 && (!m68hc11_register_indirect_p (to, GET_MODE (to)) 2830 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))) 2831 { 2832 insn = emit_move_insn (low_to, low_from); 2833 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 2834 2835 insn = emit_move_insn (high_to, high_from); 2836 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 2837 } 2838 else 2839 { 2840 insn = emit_move_insn (scratch, low_from); 2841 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 2842 insn = emit_move_insn (low_to, scratch); 2843 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 2844 2845 insn = emit_move_insn (scratch, high_from); 2846 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 2847 insn = emit_move_insn (high_to, scratch); 2848 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 2849 } 2850} 2851 2852static rtx 2853simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result) 2854{ 2855 int val; 2856 int mask; 2857 2858 *result = 0; 2859 if (GET_CODE (operand) != CONST_INT) 2860 return operand; 2861 2862 if (mode == HImode) 2863 mask = 0x0ffff; 2864 else 2865 mask = 0x0ff; 2866 2867 val = INTVAL (operand); 2868 switch (code) 2869 { 2870 case IOR: 2871 if ((val & mask) == 0) 2872 return 0; 2873 if ((val & mask) == mask) 2874 *result = constm1_rtx; 2875 break; 2876 2877 case AND: 2878 if ((val & mask) == 0) 2879 *result = const0_rtx; 2880 if ((val & mask) == mask) 2881 return 0; 2882 break; 2883 2884 case XOR: 2885 if ((val & mask) == 0) 2886 return 0; 2887 break; 2888 } 2889 return operand; 2890} 2891 2892static void 2893m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands) 2894{ 2895 rtx result; 2896 int need_copy; 2897 2898 need_copy = (rtx_equal_p (operands[0], operands[1]) 2899 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1; 2900 2901 operands[1] = simplify_logical (mode, code, operands[1], &result); 2902 operands[2] = simplify_logical (mode, code, operands[2], &result); 2903 2904 if (result && GET_CODE (result) == CONST_INT) 2905 { 2906 if (!H_REG_P (operands[0]) && operands[3] 2907 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0]))) 2908 { 2909 emit_move_insn (operands[3], result); 2910 emit_move_insn (operands[0], operands[3]); 2911 } 2912 else 2913 { 2914 emit_move_insn (operands[0], result); 2915 } 2916 } 2917 else if (operands[1] != 0 && operands[2] != 0) 2918 { 2919 rtx insn; 2920 2921 if (!H_REG_P (operands[0]) && operands[3]) 2922 { 2923 emit_move_insn (operands[3], operands[1]); 2924 emit_insn (gen_rtx_SET (mode, 2925 operands[3], 2926 gen_rtx_fmt_ee (code, mode, 2927 operands[3], operands[2]))); 2928 insn = emit_move_insn (operands[0], operands[3]); 2929 } 2930 else 2931 { 2932 insn = emit_insn (gen_rtx_SET (mode, 2933 operands[0], 2934 gen_rtx_fmt_ee (code, mode, 2935 operands[0], 2936 operands[2]))); 2937 } 2938 } 2939 2940 /* The logical operation is similar to a copy. */ 2941 else if (need_copy) 2942 { 2943 rtx src; 2944 2945 if (GET_CODE (operands[1]) == CONST_INT) 2946 src = operands[2]; 2947 else 2948 src = operands[1]; 2949 2950 if (!H_REG_P (operands[0]) && !H_REG_P (src)) 2951 { 2952 emit_move_insn (operands[3], src); 2953 emit_move_insn (operands[0], operands[3]); 2954 } 2955 else 2956 { 2957 emit_move_insn (operands[0], src); 2958 } 2959 } 2960} 2961 2962void 2963m68hc11_split_logical (enum machine_mode mode, enum rtx_code code, 2964 rtx *operands) 2965{ 2966 rtx low[4]; 2967 rtx high[4]; 2968 2969 low[0] = m68hc11_gen_lowpart (mode, operands[0]); 2970 low[1] = m68hc11_gen_lowpart (mode, operands[1]); 2971 low[2] = m68hc11_gen_lowpart (mode, operands[2]); 2972 2973 high[0] = m68hc11_gen_highpart (mode, operands[0]); 2974 high[1] = m68hc11_gen_highpart (mode, operands[1]); 2975 high[2] = m68hc11_gen_highpart (mode, operands[2]); 2976 2977 low[3] = operands[3]; 2978 high[3] = operands[3]; 2979 if (mode == SImode) 2980 { 2981 m68hc11_split_logical (HImode, code, low); 2982 m68hc11_split_logical (HImode, code, high); 2983 return; 2984 } 2985 2986 m68hc11_emit_logical (mode, code, low); 2987 m68hc11_emit_logical (mode, code, high); 2988} 2989 2990 2991/* Code generation. */ 2992 2993void 2994m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[]) 2995{ 2996 /* We have to be careful with the cc_status. An address register swap 2997 is generated for some comparison. The comparison is made with D 2998 but the branch really uses the address register. See the split 2999 pattern for compare. The xgdx/xgdy preserve the flags but after 3000 the exchange, the flags will reflect to the value of X and not D. 3001 Tell this by setting the cc_status according to the cc_prev_status. */ 3002 if (X_REG_P (operands[1]) || X_REG_P (operands[0])) 3003 { 3004 if (cc_prev_status.value1 != 0 3005 && (D_REG_P (cc_prev_status.value1) 3006 || X_REG_P (cc_prev_status.value1))) 3007 { 3008 cc_status = cc_prev_status; 3009 if (D_REG_P (cc_status.value1)) 3010 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), 3011 HARD_X_REGNUM); 3012 else 3013 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), 3014 HARD_D_REGNUM); 3015 } 3016 else 3017 CC_STATUS_INIT; 3018 3019 output_asm_insn ("xgdx", operands); 3020 } 3021 else 3022 { 3023 if (cc_prev_status.value1 != 0 3024 && (D_REG_P (cc_prev_status.value1) 3025 || Y_REG_P (cc_prev_status.value1))) 3026 { 3027 cc_status = cc_prev_status; 3028 if (D_REG_P (cc_status.value1)) 3029 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), 3030 HARD_Y_REGNUM); 3031 else 3032 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), 3033 HARD_D_REGNUM); 3034 } 3035 else 3036 CC_STATUS_INIT; 3037 3038 output_asm_insn ("xgdy", operands); 3039 } 3040} 3041 3042/* Returns 1 if the next insn after 'insn' is a test of the register 'reg'. 3043 This is used to decide whether a move that set flags should be used 3044 instead. */ 3045int 3046next_insn_test_reg (rtx insn, rtx reg) 3047{ 3048 rtx body; 3049 3050 insn = next_nonnote_insn (insn); 3051 if (GET_CODE (insn) != INSN) 3052 return 0; 3053 3054 body = PATTERN (insn); 3055 if (sets_cc0_p (body) != 1) 3056 return 0; 3057 3058 if (rtx_equal_p (XEXP (body, 1), reg) == 0) 3059 return 0; 3060 3061 return 1; 3062} 3063 3064/* Generate the code to move a 16-bit operand into another one. */ 3065 3066void 3067m68hc11_gen_movhi (rtx insn, rtx *operands) 3068{ 3069 int reg; 3070 3071 /* Move a register or memory to the same location. 3072 This is possible because such insn can appear 3073 in a non-optimizing mode. */ 3074 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1])) 3075 { 3076 cc_status = cc_prev_status; 3077 return; 3078 } 3079 3080 if (TARGET_M6812) 3081 { 3082 rtx from = operands[1]; 3083 rtx to = operands[0]; 3084 3085 if (IS_STACK_PUSH (to) && H_REG_P (from)) 3086 { 3087 cc_status = cc_prev_status; 3088 switch (REGNO (from)) 3089 { 3090 case HARD_X_REGNUM: 3091 case HARD_Y_REGNUM: 3092 case HARD_D_REGNUM: 3093 output_asm_insn ("psh%1", operands); 3094 break; 3095 case HARD_SP_REGNUM: 3096 output_asm_insn ("sts\t2,-sp", operands); 3097 break; 3098 default: 3099 gcc_unreachable (); 3100 } 3101 return; 3102 } 3103 if (IS_STACK_POP (from) && H_REG_P (to)) 3104 { 3105 cc_status = cc_prev_status; 3106 switch (REGNO (to)) 3107 { 3108 case HARD_X_REGNUM: 3109 case HARD_Y_REGNUM: 3110 case HARD_D_REGNUM: 3111 output_asm_insn ("pul%0", operands); 3112 break; 3113 default: 3114 gcc_unreachable (); 3115 } 3116 return; 3117 } 3118 if (H_REG_P (operands[0]) && H_REG_P (operands[1])) 3119 { 3120 m68hc11_notice_keep_cc (operands[0]); 3121 output_asm_insn ("tfr\t%1,%0", operands); 3122 } 3123 else if (H_REG_P (operands[0])) 3124 { 3125 if (SP_REG_P (operands[0])) 3126 output_asm_insn ("lds\t%1", operands); 3127 else 3128 output_asm_insn ("ld%0\t%1", operands); 3129 } 3130 else if (H_REG_P (operands[1])) 3131 { 3132 if (SP_REG_P (operands[1])) 3133 output_asm_insn ("sts\t%0", operands); 3134 else 3135 output_asm_insn ("st%1\t%0", operands); 3136 } 3137 3138 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw 3139 instruction. We have to use a scratch register as temporary location. 3140 Trying to use a specific pattern or constrain failed. */ 3141 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM) 3142 { 3143 rtx ops[4]; 3144 3145 ops[0] = to; 3146 ops[2] = from; 3147 ops[3] = 0; 3148 if (dead_register_here (insn, d_reg)) 3149 ops[1] = d_reg; 3150 else if (dead_register_here (insn, ix_reg)) 3151 ops[1] = ix_reg; 3152 else if (dead_register_here (insn, iy_reg)) 3153 ops[1] = iy_reg; 3154 else 3155 { 3156 ops[1] = d_reg; 3157 ops[3] = d_reg; 3158 output_asm_insn ("psh%3", ops); 3159 } 3160 3161 ops[0] = to; 3162 ops[2] = from; 3163 output_asm_insn ("ld%1\t%2", ops); 3164 output_asm_insn ("st%1\t%0", ops); 3165 if (ops[3]) 3166 output_asm_insn ("pul%3", ops); 3167 } 3168 3169 /* Use movw for non-null constants or when we are clearing 3170 a volatile memory reference. However, this is possible 3171 only if the memory reference has a small offset or is an 3172 absolute address. */ 3173 else if (GET_CODE (from) == CONST_INT 3174 && INTVAL (from) == 0 3175 && (MEM_VOLATILE_P (to) == 0 3176 || m68hc11_small_indexed_indirect_p (to, HImode) == 0)) 3177 { 3178 output_asm_insn ("clr\t%h0", operands); 3179 output_asm_insn ("clr\t%b0", operands); 3180 } 3181 else 3182 { 3183 if ((m68hc11_register_indirect_p (from, GET_MODE (from)) 3184 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from))) 3185 || (m68hc11_register_indirect_p (to, GET_MODE (to)) 3186 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))) 3187 { 3188 rtx ops[3]; 3189 3190 if (operands[2]) 3191 { 3192 ops[0] = operands[2]; 3193 ops[1] = from; 3194 ops[2] = 0; 3195 m68hc11_gen_movhi (insn, ops); 3196 ops[0] = to; 3197 ops[1] = operands[2]; 3198 m68hc11_gen_movhi (insn, ops); 3199 return; 3200 } 3201 else 3202 { 3203 /* !!!! SCz wrong here. */ 3204 fatal_insn ("move insn not handled", insn); 3205 } 3206 } 3207 else 3208 { 3209 m68hc11_notice_keep_cc (operands[0]); 3210 output_asm_insn ("movw\t%1,%0", operands); 3211 } 3212 } 3213 return; 3214 } 3215 3216 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0])) 3217 { 3218 cc_status = cc_prev_status; 3219 switch (REGNO (operands[0])) 3220 { 3221 case HARD_X_REGNUM: 3222 case HARD_Y_REGNUM: 3223 output_asm_insn ("pul%0", operands); 3224 break; 3225 case HARD_D_REGNUM: 3226 output_asm_insn ("pula", operands); 3227 output_asm_insn ("pulb", operands); 3228 break; 3229 default: 3230 gcc_unreachable (); 3231 } 3232 return; 3233 } 3234 /* Some moves to a hard register are special. Not all of them 3235 are really supported and we have to use a temporary 3236 location to provide them (either the stack of a temp var). */ 3237 if (H_REG_P (operands[0])) 3238 { 3239 switch (REGNO (operands[0])) 3240 { 3241 case HARD_D_REGNUM: 3242 if (X_REG_P (operands[1])) 3243 { 3244 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)) 3245 { 3246 m68hc11_output_swap (insn, operands); 3247 } 3248 else if (next_insn_test_reg (insn, operands[0])) 3249 { 3250 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands); 3251 } 3252 else 3253 { 3254 m68hc11_notice_keep_cc (operands[0]); 3255 output_asm_insn ("pshx\n\tpula\n\tpulb", operands); 3256 } 3257 } 3258 else if (Y_REG_P (operands[1])) 3259 { 3260 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)) 3261 { 3262 m68hc11_output_swap (insn, operands); 3263 } 3264 else 3265 { 3266 /* %t means *ZTMP scratch register. */ 3267 output_asm_insn ("sty\t%t1", operands); 3268 output_asm_insn ("ldd\t%t1", operands); 3269 } 3270 } 3271 else if (SP_REG_P (operands[1])) 3272 { 3273 CC_STATUS_INIT; 3274 if (ix_reg == 0) 3275 create_regs_rtx (); 3276 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0) 3277 output_asm_insn ("xgdx", operands); 3278 output_asm_insn ("tsx", operands); 3279 output_asm_insn ("xgdx", operands); 3280 } 3281 else if (IS_STACK_POP (operands[1])) 3282 { 3283 output_asm_insn ("pula\n\tpulb", operands); 3284 } 3285 else if (GET_CODE (operands[1]) == CONST_INT 3286 && INTVAL (operands[1]) == 0) 3287 { 3288 output_asm_insn ("clra\n\tclrb", operands); 3289 } 3290 else 3291 { 3292 output_asm_insn ("ldd\t%1", operands); 3293 } 3294 break; 3295 3296 case HARD_X_REGNUM: 3297 if (D_REG_P (operands[1])) 3298 { 3299 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM)) 3300 { 3301 m68hc11_output_swap (insn, operands); 3302 } 3303 else if (next_insn_test_reg (insn, operands[0])) 3304 { 3305 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands); 3306 } 3307 else 3308 { 3309 m68hc11_notice_keep_cc (operands[0]); 3310 output_asm_insn ("pshb", operands); 3311 output_asm_insn ("psha", operands); 3312 output_asm_insn ("pulx", operands); 3313 } 3314 } 3315 else if (Y_REG_P (operands[1])) 3316 { 3317 /* When both D and Y are dead, use the sequence xgdy, xgdx 3318 to move Y into X. The D and Y registers are modified. */ 3319 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM) 3320 && dead_register_here (insn, d_reg)) 3321 { 3322 output_asm_insn ("xgdy", operands); 3323 output_asm_insn ("xgdx", operands); 3324 CC_STATUS_INIT; 3325 } 3326 else if (!optimize_size) 3327 { 3328 output_asm_insn ("sty\t%t1", operands); 3329 output_asm_insn ("ldx\t%t1", operands); 3330 } 3331 else 3332 { 3333 CC_STATUS_INIT; 3334 output_asm_insn ("pshy", operands); 3335 output_asm_insn ("pulx", operands); 3336 } 3337 } 3338 else if (SP_REG_P (operands[1])) 3339 { 3340 /* tsx, tsy preserve the flags */ 3341 cc_status = cc_prev_status; 3342 output_asm_insn ("tsx", operands); 3343 } 3344 else 3345 { 3346 output_asm_insn ("ldx\t%1", operands); 3347 } 3348 break; 3349 3350 case HARD_Y_REGNUM: 3351 if (D_REG_P (operands[1])) 3352 { 3353 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM)) 3354 { 3355 m68hc11_output_swap (insn, operands); 3356 } 3357 else 3358 { 3359 output_asm_insn ("std\t%t1", operands); 3360 output_asm_insn ("ldy\t%t1", operands); 3361 } 3362 } 3363 else if (X_REG_P (operands[1])) 3364 { 3365 /* When both D and X are dead, use the sequence xgdx, xgdy 3366 to move X into Y. The D and X registers are modified. */ 3367 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM) 3368 && dead_register_here (insn, d_reg)) 3369 { 3370 output_asm_insn ("xgdx", operands); 3371 output_asm_insn ("xgdy", operands); 3372 CC_STATUS_INIT; 3373 } 3374 else if (!optimize_size) 3375 { 3376 output_asm_insn ("stx\t%t1", operands); 3377 output_asm_insn ("ldy\t%t1", operands); 3378 } 3379 else 3380 { 3381 CC_STATUS_INIT; 3382 output_asm_insn ("pshx", operands); 3383 output_asm_insn ("puly", operands); 3384 } 3385 } 3386 else if (SP_REG_P (operands[1])) 3387 { 3388 /* tsx, tsy preserve the flags */ 3389 cc_status = cc_prev_status; 3390 output_asm_insn ("tsy", operands); 3391 } 3392 else 3393 { 3394 output_asm_insn ("ldy\t%1", operands); 3395 } 3396 break; 3397 3398 case HARD_SP_REGNUM: 3399 if (D_REG_P (operands[1])) 3400 { 3401 m68hc11_notice_keep_cc (operands[0]); 3402 output_asm_insn ("xgdx", operands); 3403 output_asm_insn ("txs", operands); 3404 output_asm_insn ("xgdx", operands); 3405 } 3406 else if (X_REG_P (operands[1])) 3407 { 3408 /* tys, txs preserve the flags */ 3409 cc_status = cc_prev_status; 3410 output_asm_insn ("txs", operands); 3411 } 3412 else if (Y_REG_P (operands[1])) 3413 { 3414 /* tys, txs preserve the flags */ 3415 cc_status = cc_prev_status; 3416 output_asm_insn ("tys", operands); 3417 } 3418 else 3419 { 3420 /* lds sets the flags but the des does not. */ 3421 CC_STATUS_INIT; 3422 output_asm_insn ("lds\t%1", operands); 3423 output_asm_insn ("des", operands); 3424 } 3425 break; 3426 3427 default: 3428 fatal_insn ("invalid register in the move instruction", insn); 3429 break; 3430 } 3431 return; 3432 } 3433 if (SP_REG_P (operands[1]) && REG_P (operands[0]) 3434 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM) 3435 { 3436 output_asm_insn ("sts\t%0", operands); 3437 return; 3438 } 3439 3440 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1])) 3441 { 3442 cc_status = cc_prev_status; 3443 switch (REGNO (operands[1])) 3444 { 3445 case HARD_X_REGNUM: 3446 case HARD_Y_REGNUM: 3447 output_asm_insn ("psh%1", operands); 3448 break; 3449 case HARD_D_REGNUM: 3450 output_asm_insn ("pshb", operands); 3451 output_asm_insn ("psha", operands); 3452 break; 3453 default: 3454 gcc_unreachable (); 3455 } 3456 return; 3457 } 3458 3459 /* Operand 1 must be a hard register. */ 3460 if (!H_REG_P (operands[1])) 3461 { 3462 fatal_insn ("invalid operand in the instruction", insn); 3463 } 3464 3465 reg = REGNO (operands[1]); 3466 switch (reg) 3467 { 3468 case HARD_D_REGNUM: 3469 output_asm_insn ("std\t%0", operands); 3470 break; 3471 3472 case HARD_X_REGNUM: 3473 output_asm_insn ("stx\t%0", operands); 3474 break; 3475 3476 case HARD_Y_REGNUM: 3477 output_asm_insn ("sty\t%0", operands); 3478 break; 3479 3480 case HARD_SP_REGNUM: 3481 if (ix_reg == 0) 3482 create_regs_rtx (); 3483 3484 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM) 3485 { 3486 output_asm_insn ("pshx", operands); 3487 output_asm_insn ("tsx", operands); 3488 output_asm_insn ("inx", operands); 3489 output_asm_insn ("inx", operands); 3490 output_asm_insn ("stx\t%0", operands); 3491 output_asm_insn ("pulx", operands); 3492 } 3493 3494 else if (reg_mentioned_p (ix_reg, operands[0])) 3495 { 3496 output_asm_insn ("sty\t%t0", operands); 3497 output_asm_insn ("tsy", operands); 3498 output_asm_insn ("sty\t%0", operands); 3499 output_asm_insn ("ldy\t%t0", operands); 3500 } 3501 else 3502 { 3503 output_asm_insn ("stx\t%t0", operands); 3504 output_asm_insn ("tsx", operands); 3505 output_asm_insn ("stx\t%0", operands); 3506 output_asm_insn ("ldx\t%t0", operands); 3507 } 3508 CC_STATUS_INIT; 3509 break; 3510 3511 default: 3512 fatal_insn ("invalid register in the move instruction", insn); 3513 break; 3514 } 3515} 3516 3517void 3518m68hc11_gen_movqi (rtx insn, rtx *operands) 3519{ 3520 /* Move a register or memory to the same location. 3521 This is possible because such insn can appear 3522 in a non-optimizing mode. */ 3523 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1])) 3524 { 3525 cc_status = cc_prev_status; 3526 return; 3527 } 3528 3529 if (TARGET_M6812) 3530 { 3531 3532 if (H_REG_P (operands[0]) && H_REG_P (operands[1])) 3533 { 3534 m68hc11_notice_keep_cc (operands[0]); 3535 output_asm_insn ("tfr\t%1,%0", operands); 3536 } 3537 else if (H_REG_P (operands[0])) 3538 { 3539 if (IS_STACK_POP (operands[1])) 3540 output_asm_insn ("pul%b0", operands); 3541 else if (Q_REG_P (operands[0])) 3542 output_asm_insn ("lda%0\t%b1", operands); 3543 else if (D_REG_P (operands[0])) 3544 output_asm_insn ("ldab\t%b1", operands); 3545 else 3546 goto m6811_move; 3547 } 3548 else if (H_REG_P (operands[1])) 3549 { 3550 if (Q_REG_P (operands[1])) 3551 output_asm_insn ("sta%1\t%b0", operands); 3552 else if (D_REG_P (operands[1])) 3553 output_asm_insn ("stab\t%b0", operands); 3554 else 3555 goto m6811_move; 3556 } 3557 else 3558 { 3559 rtx from = operands[1]; 3560 rtx to = operands[0]; 3561 3562 if ((m68hc11_register_indirect_p (from, GET_MODE (from)) 3563 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from))) 3564 || (m68hc11_register_indirect_p (to, GET_MODE (to)) 3565 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))) 3566 { 3567 rtx ops[3]; 3568 3569 if (operands[2]) 3570 { 3571 ops[0] = operands[2]; 3572 ops[1] = from; 3573 ops[2] = 0; 3574 m68hc11_gen_movqi (insn, ops); 3575 ops[0] = to; 3576 ops[1] = operands[2]; 3577 m68hc11_gen_movqi (insn, ops); 3578 } 3579 else 3580 { 3581 /* !!!! SCz wrong here. */ 3582 fatal_insn ("move insn not handled", insn); 3583 } 3584 } 3585 else 3586 { 3587 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0) 3588 { 3589 output_asm_insn ("clr\t%b0", operands); 3590 } 3591 else 3592 { 3593 m68hc11_notice_keep_cc (operands[0]); 3594 output_asm_insn ("movb\t%b1,%b0", operands); 3595 } 3596 } 3597 } 3598 return; 3599 } 3600 3601 m6811_move: 3602 if (H_REG_P (operands[0])) 3603 { 3604 switch (REGNO (operands[0])) 3605 { 3606 case HARD_B_REGNUM: 3607 case HARD_D_REGNUM: 3608 if (X_REG_P (operands[1])) 3609 { 3610 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)) 3611 { 3612 m68hc11_output_swap (insn, operands); 3613 } 3614 else 3615 { 3616 output_asm_insn ("stx\t%t1", operands); 3617 output_asm_insn ("ldab\t%T0", operands); 3618 } 3619 } 3620 else if (Y_REG_P (operands[1])) 3621 { 3622 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)) 3623 { 3624 m68hc11_output_swap (insn, operands); 3625 } 3626 else 3627 { 3628 output_asm_insn ("sty\t%t1", operands); 3629 output_asm_insn ("ldab\t%T0", operands); 3630 } 3631 } 3632 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1]) 3633 && !DA_REG_P (operands[1])) 3634 { 3635 output_asm_insn ("ldab\t%b1", operands); 3636 } 3637 else if (DA_REG_P (operands[1])) 3638 { 3639 output_asm_insn ("tab", operands); 3640 } 3641 else 3642 { 3643 cc_status = cc_prev_status; 3644 return; 3645 } 3646 break; 3647 3648 case HARD_A_REGNUM: 3649 if (X_REG_P (operands[1])) 3650 { 3651 output_asm_insn ("stx\t%t1", operands); 3652 output_asm_insn ("ldaa\t%T0", operands); 3653 } 3654 else if (Y_REG_P (operands[1])) 3655 { 3656 output_asm_insn ("sty\t%t1", operands); 3657 output_asm_insn ("ldaa\t%T0", operands); 3658 } 3659 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1]) 3660 && !DA_REG_P (operands[1])) 3661 { 3662 output_asm_insn ("ldaa\t%b1", operands); 3663 } 3664 else if (!DA_REG_P (operands[1])) 3665 { 3666 output_asm_insn ("tba", operands); 3667 } 3668 else 3669 { 3670 cc_status = cc_prev_status; 3671 } 3672 break; 3673 3674 case HARD_X_REGNUM: 3675 if (D_REG_P (operands[1])) 3676 { 3677 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM)) 3678 { 3679 m68hc11_output_swap (insn, operands); 3680 } 3681 else 3682 { 3683 output_asm_insn ("stab\t%T1", operands); 3684 output_asm_insn ("ldx\t%t1", operands); 3685 } 3686 CC_STATUS_INIT; 3687 } 3688 else if (Y_REG_P (operands[1])) 3689 { 3690 output_asm_insn ("sty\t%t0", operands); 3691 output_asm_insn ("ldx\t%t0", operands); 3692 } 3693 else if (GET_CODE (operands[1]) == CONST_INT) 3694 { 3695 output_asm_insn ("ldx\t%1", operands); 3696 } 3697 else if (dead_register_here (insn, d_reg)) 3698 { 3699 output_asm_insn ("ldab\t%b1", operands); 3700 output_asm_insn ("xgdx", operands); 3701 } 3702 else if (!reg_mentioned_p (operands[0], operands[1])) 3703 { 3704 output_asm_insn ("xgdx", operands); 3705 output_asm_insn ("ldab\t%b1", operands); 3706 output_asm_insn ("xgdx", operands); 3707 } 3708 else 3709 { 3710 output_asm_insn ("pshb", operands); 3711 output_asm_insn ("ldab\t%b1", operands); 3712 output_asm_insn ("stab\t%T1", operands); 3713 output_asm_insn ("ldx\t%t1", operands); 3714 output_asm_insn ("pulb", operands); 3715 CC_STATUS_INIT; 3716 } 3717 break; 3718 3719 case HARD_Y_REGNUM: 3720 if (D_REG_P (operands[1])) 3721 { 3722 output_asm_insn ("stab\t%T1", operands); 3723 output_asm_insn ("ldy\t%t1", operands); 3724 CC_STATUS_INIT; 3725 } 3726 else if (X_REG_P (operands[1])) 3727 { 3728 output_asm_insn ("stx\t%t1", operands); 3729 output_asm_insn ("ldy\t%t1", operands); 3730 CC_STATUS_INIT; 3731 } 3732 else if (GET_CODE (operands[1]) == CONST_INT) 3733 { 3734 output_asm_insn ("ldy\t%1", operands); 3735 } 3736 else if (dead_register_here (insn, d_reg)) 3737 { 3738 output_asm_insn ("ldab\t%b1", operands); 3739 output_asm_insn ("xgdy", operands); 3740 } 3741 else if (!reg_mentioned_p (operands[0], operands[1])) 3742 { 3743 output_asm_insn ("xgdy", operands); 3744 output_asm_insn ("ldab\t%b1", operands); 3745 output_asm_insn ("xgdy", operands); 3746 } 3747 else 3748 { 3749 output_asm_insn ("pshb", operands); 3750 output_asm_insn ("ldab\t%b1", operands); 3751 output_asm_insn ("stab\t%T1", operands); 3752 output_asm_insn ("ldy\t%t1", operands); 3753 output_asm_insn ("pulb", operands); 3754 CC_STATUS_INIT; 3755 } 3756 break; 3757 3758 default: 3759 fatal_insn ("invalid register in the instruction", insn); 3760 break; 3761 } 3762 } 3763 else if (H_REG_P (operands[1])) 3764 { 3765 switch (REGNO (operands[1])) 3766 { 3767 case HARD_D_REGNUM: 3768 case HARD_B_REGNUM: 3769 output_asm_insn ("stab\t%b0", operands); 3770 break; 3771 3772 case HARD_A_REGNUM: 3773 output_asm_insn ("staa\t%b0", operands); 3774 break; 3775 3776 case HARD_X_REGNUM: 3777 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands); 3778 break; 3779 3780 case HARD_Y_REGNUM: 3781 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands); 3782 break; 3783 3784 default: 3785 fatal_insn ("invalid register in the move instruction", insn); 3786 break; 3787 } 3788 return; 3789 } 3790 else 3791 { 3792 fatal_insn ("operand 1 must be a hard register", insn); 3793 } 3794} 3795 3796/* Generate the code for a ROTATE or ROTATERT on a QI or HI mode. 3797 The source and destination must be D or A and the shift must 3798 be a constant. */ 3799void 3800m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[]) 3801{ 3802 int val; 3803 3804 if (GET_CODE (operands[2]) != CONST_INT 3805 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0]))) 3806 fatal_insn ("invalid rotate insn", insn); 3807 3808 val = INTVAL (operands[2]); 3809 if (code == ROTATERT) 3810 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val; 3811 3812 if (GET_MODE (operands[0]) != QImode) 3813 CC_STATUS_INIT; 3814 3815 /* Rotate by 8-bits if the shift is within [5..11]. */ 3816 if (val >= 5 && val <= 11) 3817 { 3818 if (TARGET_M6812) 3819 output_asm_insn ("exg\ta,b", operands); 3820 else 3821 { 3822 output_asm_insn ("psha", operands); 3823 output_asm_insn ("tba", operands); 3824 output_asm_insn ("pulb", operands); 3825 } 3826 val -= 8; 3827 } 3828 3829 /* If the shift is big, invert the rotation. */ 3830 else if (val >= 12) 3831 { 3832 val = val - 16; 3833 } 3834 3835 if (val > 0) 3836 { 3837 while (--val >= 0) 3838 { 3839 /* Set the carry to bit-15, but don't change D yet. */ 3840 if (GET_MODE (operands[0]) != QImode) 3841 { 3842 output_asm_insn ("asra", operands); 3843 output_asm_insn ("rola", operands); 3844 } 3845 3846 /* Rotate B first to move the carry to bit-0. */ 3847 if (D_REG_P (operands[0])) 3848 output_asm_insn ("rolb", operands); 3849 3850 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0])) 3851 output_asm_insn ("rola", operands); 3852 } 3853 } 3854 else 3855 { 3856 while (++val <= 0) 3857 { 3858 /* Set the carry to bit-8 of D. */ 3859 if (GET_MODE (operands[0]) != QImode) 3860 output_asm_insn ("tap", operands); 3861 3862 /* Rotate B first to move the carry to bit-7. */ 3863 if (D_REG_P (operands[0])) 3864 output_asm_insn ("rorb", operands); 3865 3866 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0])) 3867 output_asm_insn ("rora", operands); 3868 } 3869 } 3870} 3871 3872 3873 3874/* Store in cc_status the expressions that the condition codes will 3875 describe after execution of an instruction whose pattern is EXP. 3876 Do not alter them if the instruction would not alter the cc's. */ 3877 3878void 3879m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED) 3880{ 3881 /* recognize SET insn's. */ 3882 if (GET_CODE (exp) == SET) 3883 { 3884 /* Jumps do not alter the cc's. */ 3885 if (SET_DEST (exp) == pc_rtx) 3886 ; 3887 3888 /* NOTE: most instructions don't affect the carry bit, but the 3889 bhi/bls/bhs/blo instructions use it. This isn't mentioned in 3890 the conditions.h header. */ 3891 3892 /* Function calls clobber the cc's. */ 3893 else if (GET_CODE (SET_SRC (exp)) == CALL) 3894 { 3895 CC_STATUS_INIT; 3896 } 3897 3898 /* Tests and compares set the cc's in predictable ways. */ 3899 else if (SET_DEST (exp) == cc0_rtx) 3900 { 3901 cc_status.flags = 0; 3902 cc_status.value1 = XEXP (exp, 0); 3903 if (GET_CODE (XEXP (exp, 1)) == COMPARE 3904 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0)))) 3905 cc_status.value2 = XEXP (XEXP (exp, 1), 0); 3906 else 3907 cc_status.value2 = XEXP (exp, 1); 3908 } 3909 else 3910 { 3911 /* All other instructions affect the condition codes. */ 3912 cc_status.flags = 0; 3913 cc_status.value1 = XEXP (exp, 0); 3914 cc_status.value2 = XEXP (exp, 1); 3915 } 3916 } 3917 else 3918 { 3919 /* Default action if we haven't recognized something 3920 and returned earlier. */ 3921 CC_STATUS_INIT; 3922 } 3923 3924 if (cc_status.value2 != 0) 3925 switch (GET_CODE (cc_status.value2)) 3926 { 3927 /* These logical operations can generate several insns. 3928 The flags are setup according to what is generated. */ 3929 case IOR: 3930 case XOR: 3931 case AND: 3932 break; 3933 3934 /* The (not ...) generates several 'com' instructions for 3935 non QImode. We have to invalidate the flags. */ 3936 case NOT: 3937 if (GET_MODE (cc_status.value2) != QImode) 3938 CC_STATUS_INIT; 3939 break; 3940 3941 case PLUS: 3942 case MINUS: 3943 case MULT: 3944 case DIV: 3945 case UDIV: 3946 case MOD: 3947 case UMOD: 3948 case NEG: 3949 if (GET_MODE (cc_status.value2) != VOIDmode) 3950 cc_status.flags |= CC_NO_OVERFLOW; 3951 break; 3952 3953 /* The asl sets the overflow bit in such a way that this 3954 makes the flags unusable for a next compare insn. */ 3955 case ASHIFT: 3956 case ROTATE: 3957 case ROTATERT: 3958 if (GET_MODE (cc_status.value2) != VOIDmode) 3959 cc_status.flags |= CC_NO_OVERFLOW; 3960 break; 3961 3962 /* A load/store instruction does not affect the carry. */ 3963 case MEM: 3964 case SYMBOL_REF: 3965 case REG: 3966 case CONST_INT: 3967 cc_status.flags |= CC_NO_OVERFLOW; 3968 break; 3969 3970 default: 3971 break; 3972 } 3973 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG 3974 && cc_status.value2 3975 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) 3976 cc_status.value2 = 0; 3977 3978 else if (cc_status.value1 && side_effects_p (cc_status.value1)) 3979 cc_status.value1 = 0; 3980 3981 else if (cc_status.value2 && side_effects_p (cc_status.value2)) 3982 cc_status.value2 = 0; 3983} 3984 3985/* The current instruction does not affect the flags but changes 3986 the register 'reg'. See if the previous flags can be kept for the 3987 next instruction to avoid a comparison. */ 3988void 3989m68hc11_notice_keep_cc (rtx reg) 3990{ 3991 if (reg == 0 3992 || cc_prev_status.value1 == 0 3993 || rtx_equal_p (reg, cc_prev_status.value1) 3994 || (cc_prev_status.value2 3995 && reg_mentioned_p (reg, cc_prev_status.value2))) 3996 CC_STATUS_INIT; 3997 else 3998 cc_status = cc_prev_status; 3999} 4000 4001 4002 4003/* Machine Specific Reorg. */ 4004 4005/* Z register replacement: 4006 4007 GCC treats the Z register as an index base address register like 4008 X or Y. In general, it uses it during reload to compute the address 4009 of some operand. This helps the reload pass to avoid to fall into the 4010 register spill failure. 4011 4012 The Z register is in the A_REGS class. In the machine description, 4013 the 'A' constraint matches it. The 'x' or 'y' constraints do not. 4014 4015 It can appear everywhere an X or Y register can appear, except for 4016 some templates in the clobber section (when a clobber of X or Y is asked). 4017 For a given instruction, the template must ensure that no more than 4018 2 'A' registers are used. Otherwise, the register replacement is not 4019 possible. 4020 4021 To replace the Z register, the algorithm is not terrific: 4022 1. Insns that do not use the Z register are not changed 4023 2. When a Z register is used, we scan forward the insns to see 4024 a potential register to use: either X or Y and sometimes D. 4025 We stop when a call, a label or a branch is seen, or when we 4026 detect that both X and Y are used (probably at different times, but it does 4027 not matter). 4028 3. The register that will be used for the replacement of Z is saved 4029 in a .page0 register or on the stack. If the first instruction that 4030 used Z, uses Z as an input, the value is loaded from another .page0 4031 register. The replacement register is pushed on the stack in the 4032 rare cases where a compare insn uses Z and we couldn't find if X/Y 4033 are dead. 4034 4. The Z register is replaced in all instructions until we reach 4035 the end of the Z-block, as detected by step 2. 4036 5. If we detect that Z is still alive, its value is saved. 4037 If the replacement register is alive, its old value is loaded. 4038 4039 The Z register can be disabled with -ffixed-z. 4040*/ 4041 4042struct replace_info 4043{ 4044 rtx first; 4045 rtx replace_reg; 4046 int need_save_z; 4047 int must_load_z; 4048 int must_save_reg; 4049 int must_restore_reg; 4050 rtx last; 4051 int regno; 4052 int x_used; 4053 int y_used; 4054 int can_use_d; 4055 int found_call; 4056 int z_died; 4057 int z_set_count; 4058 rtx z_value; 4059 int must_push_reg; 4060 int save_before_last; 4061 int z_loaded_with_sp; 4062}; 4063 4064static int m68hc11_check_z_replacement (rtx, struct replace_info *); 4065static void m68hc11_find_z_replacement (rtx, struct replace_info *); 4066static void m68hc11_z_replacement (rtx); 4067static void m68hc11_reassign_regs (rtx); 4068 4069int z_replacement_completed = 0; 4070 4071/* Analyze the insn to find out which replacement register to use and 4072 the boundaries of the replacement. 4073 Returns 0 if we reached the last insn to be replaced, 1 if we can 4074 continue replacement in next insns. */ 4075 4076static int 4077m68hc11_check_z_replacement (rtx insn, struct replace_info *info) 4078{ 4079 int this_insn_uses_ix; 4080 int this_insn_uses_iy; 4081 int this_insn_uses_z; 4082 int this_insn_uses_z_in_dst; 4083 int this_insn_uses_d; 4084 rtx body; 4085 int z_dies_here; 4086 4087 /* A call is said to clobber the Z register, we don't need 4088 to save the value of Z. We also don't need to restore 4089 the replacement register (unless it is used by the call). */ 4090 if (GET_CODE (insn) == CALL_INSN) 4091 { 4092 body = PATTERN (insn); 4093 4094 info->can_use_d = 0; 4095 4096 /* If the call is an indirect call with Z, we have to use the 4097 Y register because X can be used as an input (D+X). 4098 We also must not save Z nor restore Y. */ 4099 if (reg_mentioned_p (z_reg, body)) 4100 { 4101 insn = NEXT_INSN (insn); 4102 info->x_used = 1; 4103 info->y_used = 0; 4104 info->found_call = 1; 4105 info->must_restore_reg = 0; 4106 info->last = NEXT_INSN (insn); 4107 } 4108 info->need_save_z = 0; 4109 return 0; 4110 } 4111 if (GET_CODE (insn) == CODE_LABEL 4112 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT) 4113 return 0; 4114 4115 if (GET_CODE (insn) == JUMP_INSN) 4116 { 4117 if (reg_mentioned_p (z_reg, insn) == 0) 4118 return 0; 4119 4120 info->can_use_d = 0; 4121 info->must_save_reg = 0; 4122 info->must_restore_reg = 0; 4123 info->need_save_z = 0; 4124 info->last = NEXT_INSN (insn); 4125 return 0; 4126 } 4127 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN) 4128 { 4129 return 1; 4130 } 4131 4132 /* Z register dies here. */ 4133 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL; 4134 4135 body = PATTERN (insn); 4136 if (GET_CODE (body) == SET) 4137 { 4138 rtx src = XEXP (body, 1); 4139 rtx dst = XEXP (body, 0); 4140 4141 /* Condition code is set here. We have to restore the X/Y and 4142 save into Z before any test/compare insn because once we save/restore 4143 we can change the condition codes. When the compare insn uses Z and 4144 we can't use X/Y, the comparison is made with the *ZREG soft register 4145 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */ 4146 if (dst == cc0_rtx) 4147 { 4148 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM) 4149 || (GET_CODE (src) == COMPARE && 4150 ((rtx_equal_p (XEXP (src, 0), z_reg) 4151 && H_REG_P (XEXP (src, 1))) 4152 || (rtx_equal_p (XEXP (src, 1), z_reg) 4153 && H_REG_P (XEXP (src, 0)))))) 4154 { 4155 if (insn == info->first) 4156 { 4157 info->must_load_z = 0; 4158 info->must_save_reg = 0; 4159 info->must_restore_reg = 0; 4160 info->need_save_z = 0; 4161 info->found_call = 1; 4162 info->regno = SOFT_Z_REGNUM; 4163 info->last = NEXT_INSN (insn); 4164 } 4165 return 0; 4166 } 4167 if (reg_mentioned_p (z_reg, src) == 0) 4168 { 4169 info->can_use_d = 0; 4170 return 0; 4171 } 4172 4173 if (insn != info->first) 4174 return 0; 4175 4176 /* Compare insn which uses Z. We have to save/restore the X/Y 4177 register without modifying the condition codes. For this 4178 we have to use a push/pop insn. */ 4179 info->must_push_reg = 1; 4180 info->last = insn; 4181 } 4182 4183 /* Z reg is set to something new. We don't need to load it. */ 4184 if (Z_REG_P (dst)) 4185 { 4186 if (!reg_mentioned_p (z_reg, src)) 4187 { 4188 /* Z reg is used before being set. Treat this as 4189 a new sequence of Z register replacement. */ 4190 if (insn != info->first) 4191 { 4192 return 0; 4193 } 4194 info->must_load_z = 0; 4195 } 4196 info->z_set_count++; 4197 info->z_value = src; 4198 if (SP_REG_P (src)) 4199 info->z_loaded_with_sp = 1; 4200 } 4201 else if (reg_mentioned_p (z_reg, dst)) 4202 info->can_use_d = 0; 4203 4204 this_insn_uses_d = reg_mentioned_p (d_reg, src) 4205 | reg_mentioned_p (d_reg, dst); 4206 this_insn_uses_ix = reg_mentioned_p (ix_reg, src) 4207 | reg_mentioned_p (ix_reg, dst); 4208 this_insn_uses_iy = reg_mentioned_p (iy_reg, src) 4209 | reg_mentioned_p (iy_reg, dst); 4210 this_insn_uses_z = reg_mentioned_p (z_reg, src); 4211 4212 /* If z is used as an address operand (like (MEM (reg z))), 4213 we can't replace it with d. */ 4214 if (this_insn_uses_z && !Z_REG_P (src) 4215 && !(m68hc11_arith_operator (src, GET_MODE (src)) 4216 && Z_REG_P (XEXP (src, 0)) 4217 && !reg_mentioned_p (z_reg, XEXP (src, 1)) 4218 && insn == info->first 4219 && dead_register_here (insn, d_reg))) 4220 info->can_use_d = 0; 4221 4222 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst); 4223 if (TARGET_M6812 && !z_dies_here 4224 && ((this_insn_uses_z && side_effects_p (src)) 4225 || (this_insn_uses_z_in_dst && side_effects_p (dst)))) 4226 { 4227 info->need_save_z = 1; 4228 info->z_set_count++; 4229 } 4230 this_insn_uses_z |= this_insn_uses_z_in_dst; 4231 4232 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy) 4233 { 4234 fatal_insn ("registers IX, IY and Z used in the same INSN", insn); 4235 } 4236 4237 if (this_insn_uses_d) 4238 info->can_use_d = 0; 4239 4240 /* IX and IY are used at the same time, we have to restore 4241 the value of the scratch register before this insn. */ 4242 if (this_insn_uses_ix && this_insn_uses_iy) 4243 { 4244 return 0; 4245 } 4246 4247 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode) 4248 info->can_use_d = 0; 4249 4250 if (info->x_used == 0 && this_insn_uses_ix) 4251 { 4252 if (info->y_used) 4253 { 4254 /* We have a (set (REG:HI X) (REG:HI Z)). 4255 Since we use Z as the replacement register, this insn 4256 is no longer necessary. We turn it into a note. We must 4257 not reload the old value of X. */ 4258 if (X_REG_P (dst) && rtx_equal_p (src, z_reg)) 4259 { 4260 if (z_dies_here) 4261 { 4262 info->need_save_z = 0; 4263 info->z_died = 1; 4264 } 4265 info->must_save_reg = 0; 4266 info->must_restore_reg = 0; 4267 info->found_call = 1; 4268 info->can_use_d = 0; 4269 SET_INSN_DELETED (insn); 4270 info->last = NEXT_INSN (insn); 4271 return 0; 4272 } 4273 4274 if (X_REG_P (dst) 4275 && (rtx_equal_p (src, z_reg) 4276 || (z_dies_here && !reg_mentioned_p (ix_reg, src)))) 4277 { 4278 if (z_dies_here) 4279 { 4280 info->need_save_z = 0; 4281 info->z_died = 1; 4282 } 4283 info->last = NEXT_INSN (insn); 4284 info->must_save_reg = 0; 4285 info->must_restore_reg = 0; 4286 } 4287 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src) 4288 && !reg_mentioned_p (ix_reg, src)) 4289 { 4290 if (z_dies_here) 4291 { 4292 info->z_died = 1; 4293 info->need_save_z = 0; 4294 } 4295 else if (TARGET_M6812 && side_effects_p (src)) 4296 { 4297 info->last = 0; 4298 info->must_restore_reg = 0; 4299 return 0; 4300 } 4301 else 4302 { 4303 info->save_before_last = 1; 4304 } 4305 info->must_restore_reg = 0; 4306 info->last = NEXT_INSN (insn); 4307 } 4308 else if (info->can_use_d) 4309 { 4310 info->last = NEXT_INSN (insn); 4311 info->x_used = 1; 4312 } 4313 return 0; 4314 } 4315 info->x_used = 1; 4316 if (z_dies_here && !reg_mentioned_p (ix_reg, src) 4317 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM) 4318 { 4319 info->need_save_z = 0; 4320 info->z_died = 1; 4321 info->last = NEXT_INSN (insn); 4322 info->regno = HARD_X_REGNUM; 4323 info->must_save_reg = 0; 4324 info->must_restore_reg = 0; 4325 return 0; 4326 } 4327 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg)) 4328 { 4329 info->regno = HARD_X_REGNUM; 4330 info->must_restore_reg = 0; 4331 info->must_save_reg = 0; 4332 return 0; 4333 } 4334 } 4335 if (info->y_used == 0 && this_insn_uses_iy) 4336 { 4337 if (info->x_used) 4338 { 4339 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg)) 4340 { 4341 if (z_dies_here) 4342 { 4343 info->need_save_z = 0; 4344 info->z_died = 1; 4345 } 4346 info->must_save_reg = 0; 4347 info->must_restore_reg = 0; 4348 info->found_call = 1; 4349 info->can_use_d = 0; 4350 SET_INSN_DELETED (insn); 4351 info->last = NEXT_INSN (insn); 4352 return 0; 4353 } 4354 4355 if (Y_REG_P (dst) 4356 && (rtx_equal_p (src, z_reg) 4357 || (z_dies_here && !reg_mentioned_p (iy_reg, src)))) 4358 { 4359 if (z_dies_here) 4360 { 4361 info->z_died = 1; 4362 info->need_save_z = 0; 4363 } 4364 info->last = NEXT_INSN (insn); 4365 info->must_save_reg = 0; 4366 info->must_restore_reg = 0; 4367 } 4368 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src) 4369 && !reg_mentioned_p (iy_reg, src)) 4370 { 4371 if (z_dies_here) 4372 { 4373 info->z_died = 1; 4374 info->need_save_z = 0; 4375 } 4376 else if (TARGET_M6812 && side_effects_p (src)) 4377 { 4378 info->last = 0; 4379 info->must_restore_reg = 0; 4380 return 0; 4381 } 4382 else 4383 { 4384 info->save_before_last = 1; 4385 } 4386 info->must_restore_reg = 0; 4387 info->last = NEXT_INSN (insn); 4388 } 4389 else if (info->can_use_d) 4390 { 4391 info->last = NEXT_INSN (insn); 4392 info->y_used = 1; 4393 } 4394 4395 return 0; 4396 } 4397 info->y_used = 1; 4398 if (z_dies_here && !reg_mentioned_p (iy_reg, src) 4399 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM) 4400 { 4401 info->need_save_z = 0; 4402 info->z_died = 1; 4403 info->last = NEXT_INSN (insn); 4404 info->regno = HARD_Y_REGNUM; 4405 info->must_save_reg = 0; 4406 info->must_restore_reg = 0; 4407 return 0; 4408 } 4409 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg)) 4410 { 4411 info->regno = HARD_Y_REGNUM; 4412 info->must_restore_reg = 0; 4413 info->must_save_reg = 0; 4414 return 0; 4415 } 4416 } 4417 if (z_dies_here) 4418 { 4419 info->need_save_z = 0; 4420 info->z_died = 1; 4421 if (info->last == 0) 4422 info->last = NEXT_INSN (insn); 4423 return 0; 4424 } 4425 return info->last != NULL_RTX ? 0 : 1; 4426 } 4427 if (GET_CODE (body) == PARALLEL) 4428 { 4429 int i; 4430 char ix_clobber = 0; 4431 char iy_clobber = 0; 4432 char z_clobber = 0; 4433 this_insn_uses_iy = 0; 4434 this_insn_uses_ix = 0; 4435 this_insn_uses_z = 0; 4436 4437 for (i = XVECLEN (body, 0) - 1; i >= 0; i--) 4438 { 4439 rtx x; 4440 int uses_ix, uses_iy, uses_z; 4441 4442 x = XVECEXP (body, 0, i); 4443 4444 if (info->can_use_d && reg_mentioned_p (d_reg, x)) 4445 info->can_use_d = 0; 4446 4447 uses_ix = reg_mentioned_p (ix_reg, x); 4448 uses_iy = reg_mentioned_p (iy_reg, x); 4449 uses_z = reg_mentioned_p (z_reg, x); 4450 if (GET_CODE (x) == CLOBBER) 4451 { 4452 ix_clobber |= uses_ix; 4453 iy_clobber |= uses_iy; 4454 z_clobber |= uses_z; 4455 } 4456 else 4457 { 4458 this_insn_uses_ix |= uses_ix; 4459 this_insn_uses_iy |= uses_iy; 4460 this_insn_uses_z |= uses_z; 4461 } 4462 if (uses_z && GET_CODE (x) == SET) 4463 { 4464 rtx dst = XEXP (x, 0); 4465 4466 if (Z_REG_P (dst)) 4467 info->z_set_count++; 4468 } 4469 if (TARGET_M6812 && uses_z && side_effects_p (x)) 4470 info->need_save_z = 1; 4471 4472 if (z_clobber) 4473 info->need_save_z = 0; 4474 } 4475 if (debug_m6811) 4476 { 4477 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n", 4478 this_insn_uses_ix, this_insn_uses_iy, 4479 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber); 4480 debug_rtx (insn); 4481 } 4482 if (this_insn_uses_z) 4483 info->can_use_d = 0; 4484 4485 if (z_clobber && info->first != insn) 4486 { 4487 info->need_save_z = 0; 4488 info->last = insn; 4489 return 0; 4490 } 4491 if (z_clobber && info->x_used == 0 && info->y_used == 0) 4492 { 4493 if (this_insn_uses_z == 0 && insn == info->first) 4494 { 4495 info->must_load_z = 0; 4496 } 4497 if (dead_register_here (insn, d_reg)) 4498 { 4499 info->regno = HARD_D_REGNUM; 4500 info->must_save_reg = 0; 4501 info->must_restore_reg = 0; 4502 } 4503 else if (dead_register_here (insn, ix_reg)) 4504 { 4505 info->regno = HARD_X_REGNUM; 4506 info->must_save_reg = 0; 4507 info->must_restore_reg = 0; 4508 } 4509 else if (dead_register_here (insn, iy_reg)) 4510 { 4511 info->regno = HARD_Y_REGNUM; 4512 info->must_save_reg = 0; 4513 info->must_restore_reg = 0; 4514 } 4515 if (info->regno >= 0) 4516 { 4517 info->last = NEXT_INSN (insn); 4518 return 0; 4519 } 4520 if (this_insn_uses_ix == 0) 4521 { 4522 info->regno = HARD_X_REGNUM; 4523 info->must_save_reg = 1; 4524 info->must_restore_reg = 1; 4525 } 4526 else if (this_insn_uses_iy == 0) 4527 { 4528 info->regno = HARD_Y_REGNUM; 4529 info->must_save_reg = 1; 4530 info->must_restore_reg = 1; 4531 } 4532 else 4533 { 4534 info->regno = HARD_D_REGNUM; 4535 info->must_save_reg = 1; 4536 info->must_restore_reg = 1; 4537 } 4538 info->last = NEXT_INSN (insn); 4539 return 0; 4540 } 4541 4542 if (((info->x_used || this_insn_uses_ix) && iy_clobber) 4543 || ((info->y_used || this_insn_uses_iy) && ix_clobber)) 4544 { 4545 if (this_insn_uses_z) 4546 { 4547 if (info->y_used == 0 && iy_clobber) 4548 { 4549 info->regno = HARD_Y_REGNUM; 4550 info->must_save_reg = 0; 4551 info->must_restore_reg = 0; 4552 } 4553 if (info->first != insn 4554 && ((info->y_used && ix_clobber) 4555 || (info->x_used && iy_clobber))) 4556 info->last = insn; 4557 else 4558 info->last = NEXT_INSN (insn); 4559 info->save_before_last = 1; 4560 } 4561 return 0; 4562 } 4563 if (this_insn_uses_ix && this_insn_uses_iy) 4564 { 4565 if (this_insn_uses_z) 4566 { 4567 fatal_insn ("cannot do z-register replacement", insn); 4568 } 4569 return 0; 4570 } 4571 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber)) 4572 { 4573 if (info->y_used) 4574 { 4575 return 0; 4576 } 4577 info->x_used = 1; 4578 if (iy_clobber || z_clobber) 4579 { 4580 info->last = NEXT_INSN (insn); 4581 info->save_before_last = 1; 4582 return 0; 4583 } 4584 } 4585 4586 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber)) 4587 { 4588 if (info->x_used) 4589 { 4590 return 0; 4591 } 4592 info->y_used = 1; 4593 if (ix_clobber || z_clobber) 4594 { 4595 info->last = NEXT_INSN (insn); 4596 info->save_before_last = 1; 4597 return 0; 4598 } 4599 } 4600 if (z_dies_here) 4601 { 4602 info->z_died = 1; 4603 info->need_save_z = 0; 4604 } 4605 return 1; 4606 } 4607 if (GET_CODE (body) == CLOBBER) 4608 { 4609 4610 /* IX and IY are used at the same time, we have to restore 4611 the value of the scratch register before this insn. */ 4612 if (this_insn_uses_ix && this_insn_uses_iy) 4613 { 4614 return 0; 4615 } 4616 if (info->x_used == 0 && this_insn_uses_ix) 4617 { 4618 if (info->y_used) 4619 { 4620 return 0; 4621 } 4622 info->x_used = 1; 4623 } 4624 if (info->y_used == 0 && this_insn_uses_iy) 4625 { 4626 if (info->x_used) 4627 { 4628 return 0; 4629 } 4630 info->y_used = 1; 4631 } 4632 return 1; 4633 } 4634 return 1; 4635} 4636 4637static void 4638m68hc11_find_z_replacement (rtx insn, struct replace_info *info) 4639{ 4640 int reg; 4641 4642 info->replace_reg = NULL_RTX; 4643 info->must_load_z = 1; 4644 info->need_save_z = 1; 4645 info->must_save_reg = 1; 4646 info->must_restore_reg = 1; 4647 info->first = insn; 4648 info->x_used = 0; 4649 info->y_used = 0; 4650 info->can_use_d = TARGET_M6811 ? 1 : 0; 4651 info->found_call = 0; 4652 info->z_died = 0; 4653 info->last = 0; 4654 info->regno = -1; 4655 info->z_set_count = 0; 4656 info->z_value = NULL_RTX; 4657 info->must_push_reg = 0; 4658 info->save_before_last = 0; 4659 info->z_loaded_with_sp = 0; 4660 4661 /* Scan the insn forward to find an address register that is not used. 4662 Stop when: 4663 - the flow of the program changes, 4664 - when we detect that both X and Y are necessary, 4665 - when the Z register dies, 4666 - when the condition codes are set. */ 4667 4668 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn)) 4669 { 4670 if (m68hc11_check_z_replacement (insn, info) == 0) 4671 break; 4672 } 4673 4674 /* May be we can use Y or X if they contain the same value as Z. 4675 This happens very often after the reload. */ 4676 if (info->z_set_count == 1) 4677 { 4678 rtx p = info->first; 4679 rtx v = 0; 4680 4681 if (info->x_used) 4682 { 4683 v = find_last_value (iy_reg, &p, insn, 1); 4684 } 4685 else if (info->y_used) 4686 { 4687 v = find_last_value (ix_reg, &p, insn, 1); 4688 } 4689 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value)) 4690 { 4691 if (info->x_used) 4692 info->regno = HARD_Y_REGNUM; 4693 else 4694 info->regno = HARD_X_REGNUM; 4695 info->must_load_z = 0; 4696 info->must_save_reg = 0; 4697 info->must_restore_reg = 0; 4698 info->found_call = 1; 4699 } 4700 } 4701 if (info->z_set_count == 0) 4702 info->need_save_z = 0; 4703 4704 if (insn == 0) 4705 info->need_save_z = 0; 4706 4707 if (info->last == 0) 4708 info->last = insn; 4709 4710 if (info->regno >= 0) 4711 { 4712 reg = info->regno; 4713 info->replace_reg = gen_rtx_REG (HImode, reg); 4714 } 4715 else if (info->can_use_d) 4716 { 4717 reg = HARD_D_REGNUM; 4718 info->replace_reg = d_reg; 4719 } 4720 else if (info->x_used) 4721 { 4722 reg = HARD_Y_REGNUM; 4723 info->replace_reg = iy_reg; 4724 } 4725 else 4726 { 4727 reg = HARD_X_REGNUM; 4728 info->replace_reg = ix_reg; 4729 } 4730 info->regno = reg; 4731 4732 if (info->must_save_reg && info->must_restore_reg) 4733 { 4734 if (insn && dead_register_here (insn, info->replace_reg)) 4735 { 4736 info->must_save_reg = 0; 4737 info->must_restore_reg = 0; 4738 } 4739 } 4740} 4741 4742/* The insn uses the Z register. Find a replacement register for it 4743 (either X or Y) and replace it in the insn and the next ones until 4744 the flow changes or the replacement register is used. Instructions 4745 are emitted before and after the Z-block to preserve the value of 4746 Z and of the replacement register. */ 4747 4748static void 4749m68hc11_z_replacement (rtx insn) 4750{ 4751 rtx replace_reg_qi; 4752 rtx replace_reg; 4753 struct replace_info info; 4754 4755 /* Find trivial case where we only need to replace z with the 4756 equivalent soft register. */ 4757 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET) 4758 { 4759 rtx body = PATTERN (insn); 4760 rtx src = XEXP (body, 1); 4761 rtx dst = XEXP (body, 0); 4762 4763 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src))) 4764 { 4765 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM); 4766 return; 4767 } 4768 else if (Z_REG_P (src) 4769 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx)) 4770 { 4771 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM); 4772 return; 4773 } 4774 else if (D_REG_P (dst) 4775 && m68hc11_arith_operator (src, GET_MODE (src)) 4776 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1))) 4777 { 4778 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM); 4779 return; 4780 } 4781 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT 4782 && INTVAL (src) == 0) 4783 { 4784 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM); 4785 /* Force it to be re-recognized. */ 4786 INSN_CODE (insn) = -1; 4787 return; 4788 } 4789 } 4790 4791 m68hc11_find_z_replacement (insn, &info); 4792 4793 replace_reg = info.replace_reg; 4794 replace_reg_qi = NULL_RTX; 4795 4796 /* Save the X register in a .page0 location. */ 4797 if (info.must_save_reg && !info.must_push_reg) 4798 { 4799 rtx dst; 4800 4801 if (info.must_push_reg && 0) 4802 dst = gen_rtx_MEM (HImode, 4803 gen_rtx_PRE_DEC (HImode, 4804 gen_rtx_REG (HImode, HARD_SP_REGNUM))); 4805 else 4806 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM); 4807 4808 emit_insn_before (gen_movhi (dst, 4809 gen_rtx_REG (HImode, info.regno)), insn); 4810 } 4811 if (info.must_load_z && !info.must_push_reg) 4812 { 4813 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno), 4814 gen_rtx_REG (HImode, SOFT_Z_REGNUM)), 4815 insn); 4816 } 4817 4818 4819 /* Replace all occurrence of Z by replace_reg. 4820 Stop when the last instruction to replace is reached. 4821 Also stop when we detect a change in the flow (but it's not 4822 necessary; just safeguard). */ 4823 4824 for (; insn && insn != info.last; insn = NEXT_INSN (insn)) 4825 { 4826 rtx body; 4827 4828 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER) 4829 break; 4830 4831 if (GET_CODE (insn) != INSN 4832 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN) 4833 continue; 4834 4835 body = PATTERN (insn); 4836 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL 4837 || GET_CODE (body) == ASM_OPERANDS 4838 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) 4839 { 4840 rtx note; 4841 4842 if (debug_m6811 && reg_mentioned_p (replace_reg, body)) 4843 { 4844 printf ("Reg mentioned here...:\n"); 4845 fflush (stdout); 4846 debug_rtx (insn); 4847 } 4848 4849 /* Stack pointer was decremented by 2 due to the push. 4850 Correct that by adding 2 to the destination. */ 4851 if (info.must_push_reg 4852 && info.z_loaded_with_sp && GET_CODE (body) == SET) 4853 { 4854 rtx src, dst; 4855 4856 src = SET_SRC (body); 4857 dst = SET_DEST (body); 4858 if (SP_REG_P (src) && Z_REG_P (dst)) 4859 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn); 4860 } 4861 4862 /* Replace any (REG:HI Z) occurrence by either X or Y. */ 4863 if (!validate_replace_rtx (z_reg, replace_reg, insn)) 4864 { 4865 INSN_CODE (insn) = -1; 4866 if (!validate_replace_rtx (z_reg, replace_reg, insn)) 4867 fatal_insn ("cannot do z-register replacement", insn); 4868 } 4869 4870 /* Likewise for (REG:QI Z). */ 4871 if (reg_mentioned_p (z_reg, insn)) 4872 { 4873 if (replace_reg_qi == NULL_RTX) 4874 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg)); 4875 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn); 4876 } 4877 4878 /* If there is a REG_INC note on Z, replace it with a 4879 REG_INC note on the replacement register. This is necessary 4880 to make sure that the flow pass will identify the change 4881 and it will not remove a possible insn that saves Z. */ 4882 for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) 4883 { 4884 if (REG_NOTE_KIND (note) == REG_INC 4885 && GET_CODE (XEXP (note, 0)) == REG 4886 && REGNO (XEXP (note, 0)) == REGNO (z_reg)) 4887 { 4888 XEXP (note, 0) = replace_reg; 4889 } 4890 } 4891 } 4892 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) 4893 break; 4894 } 4895 4896 /* Save Z before restoring the old value. */ 4897 if (insn && info.need_save_z && !info.must_push_reg) 4898 { 4899 rtx save_pos_insn = insn; 4900 4901 /* If Z is clobber by the last insn, we have to save its value 4902 before the last instruction. */ 4903 if (info.save_before_last) 4904 save_pos_insn = PREV_INSN (save_pos_insn); 4905 4906 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM), 4907 gen_rtx_REG (HImode, info.regno)), 4908 save_pos_insn); 4909 } 4910 4911 if (info.must_push_reg && info.last) 4912 { 4913 rtx new_body, body; 4914 4915 body = PATTERN (info.last); 4916 new_body = gen_rtx_PARALLEL (VOIDmode, 4917 gen_rtvec (3, body, 4918 gen_rtx_USE (VOIDmode, 4919 replace_reg), 4920 gen_rtx_USE (VOIDmode, 4921 gen_rtx_REG (HImode, 4922 SOFT_Z_REGNUM)))); 4923 PATTERN (info.last) = new_body; 4924 4925 /* Force recognition on insn since we changed it. */ 4926 INSN_CODE (insn) = -1; 4927 4928 if (!validate_replace_rtx (z_reg, replace_reg, info.last)) 4929 { 4930 fatal_insn ("invalid Z register replacement for insn", insn); 4931 } 4932 insn = NEXT_INSN (info.last); 4933 } 4934 4935 /* Restore replacement register unless it was died. */ 4936 if (insn && info.must_restore_reg && !info.must_push_reg) 4937 { 4938 rtx dst; 4939 4940 if (info.must_push_reg && 0) 4941 dst = gen_rtx_MEM (HImode, 4942 gen_rtx_POST_INC (HImode, 4943 gen_rtx_REG (HImode, HARD_SP_REGNUM))); 4944 else 4945 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM); 4946 4947 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno), 4948 dst), insn); 4949 } 4950 4951} 4952 4953 4954/* Scan all the insn and re-affects some registers 4955 - The Z register (if it was used), is affected to X or Y depending 4956 on the instruction. */ 4957 4958static void 4959m68hc11_reassign_regs (rtx first) 4960{ 4961 rtx insn; 4962 4963 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM); 4964 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM); 4965 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM); 4966 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM); 4967 4968 /* Scan all insns to replace Z by X or Y preserving the old value 4969 of X/Y and restoring it afterward. */ 4970 4971 for (insn = first; insn; insn = NEXT_INSN (insn)) 4972 { 4973 rtx body; 4974 4975 if (GET_CODE (insn) == CODE_LABEL 4976 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER) 4977 continue; 4978 4979 if (!INSN_P (insn)) 4980 continue; 4981 4982 body = PATTERN (insn); 4983 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE) 4984 continue; 4985 4986 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT 4987 || GET_CODE (body) == ASM_OPERANDS 4988 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE) 4989 continue; 4990 4991 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL 4992 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) 4993 { 4994 4995 /* If Z appears in this insn, replace it in the current insn 4996 and the next ones until the flow changes or we have to 4997 restore back the replacement register. */ 4998 4999 if (reg_mentioned_p (z_reg, body)) 5000 { 5001 m68hc11_z_replacement (insn); 5002 } 5003 } 5004 else 5005 { 5006 printf ("insn not handled by Z replacement:\n"); 5007 fflush (stdout); 5008 debug_rtx (insn); 5009 } 5010 } 5011} 5012 5013 5014/* Machine-dependent reorg pass. 5015 Specific optimizations are defined here: 5016 - this pass changes the Z register into either X or Y 5017 (it preserves X/Y previous values in a memory slot in page0). 5018 5019 When this pass is finished, the global variable 5020 'z_replacement_completed' is set to 2. */ 5021 5022static void 5023m68hc11_reorg (void) 5024{ 5025 int split_done = 0; 5026 rtx first; 5027 5028 z_replacement_completed = 0; 5029 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM); 5030 first = get_insns (); 5031 5032 /* Some RTX are shared at this point. This breaks the Z register 5033 replacement, unshare everything. */ 5034 unshare_all_rtl_again (first); 5035 5036 /* Force a split of all splittable insn. This is necessary for the 5037 Z register replacement mechanism because we end up with basic insns. */ 5038 split_all_insns_noflow (); 5039 split_done = 1; 5040 5041 z_replacement_completed = 1; 5042 m68hc11_reassign_regs (first); 5043 5044 if (optimize) 5045 compute_bb_for_insn (); 5046 5047 /* After some splitting, there are some opportunities for CSE pass. 5048 This happens quite often when 32-bit or above patterns are split. */ 5049 if (optimize > 0 && split_done) 5050 { 5051 reload_cse_regs (first); 5052 } 5053 5054 /* Re-create the REG_DEAD notes. These notes are used in the machine 5055 description to use the best assembly directives. */ 5056 if (optimize) 5057 { 5058 df_note_add_problem (); 5059 df_analyze (); 5060 df_remove_problem (df_note); 5061 } 5062 5063 z_replacement_completed = 2; 5064 5065 /* If optimizing, then go ahead and split insns that must be 5066 split after Z register replacement. This gives more opportunities 5067 for peephole (in particular for consecutives xgdx/xgdy). */ 5068 if (optimize > 0) 5069 split_all_insns_noflow (); 5070 5071 /* Once insns are split after the z_replacement_completed == 2, 5072 we must not re-run the life_analysis. The xgdx/xgdy patterns 5073 are not recognized and the life_analysis pass removes some 5074 insns because it thinks some (SETs) are noops or made to dead 5075 stores (which is false due to the swap). 5076 5077 Do a simple pass to eliminate the noop set that the final 5078 split could generate (because it was easier for split definition). */ 5079 { 5080 rtx insn; 5081 5082 for (insn = first; insn; insn = NEXT_INSN (insn)) 5083 { 5084 rtx body; 5085 5086 if (INSN_DELETED_P (insn)) 5087 continue; 5088 if (!INSN_P (insn)) 5089 continue; 5090 5091 /* Remove the (set (R) (R)) insns generated by some splits. */ 5092 body = PATTERN (insn); 5093 if (GET_CODE (body) == SET 5094 && rtx_equal_p (SET_SRC (body), SET_DEST (body))) 5095 { 5096 SET_INSN_DELETED (insn); 5097 continue; 5098 } 5099 } 5100 } 5101} 5102 5103/* Override memcpy */ 5104 5105static void 5106m68hc11_init_libfuncs (void) 5107{ 5108 memcpy_libfunc = init_one_libfunc ("__memcpy"); 5109 memcmp_libfunc = init_one_libfunc ("__memcmp"); 5110 memset_libfunc = init_one_libfunc ("__memset"); 5111} 5112 5113 5114 5115/* Cost functions. */ 5116 5117/* Cost of moving memory. */ 5118int 5119m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass, 5120 int in ATTRIBUTE_UNUSED) 5121{ 5122 if (rclass <= H_REGS && rclass > NO_REGS) 5123 { 5124 if (GET_MODE_SIZE (mode) <= 2) 5125 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress); 5126 else 5127 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress); 5128 } 5129 else 5130 { 5131 if (GET_MODE_SIZE (mode) <= 2) 5132 return COSTS_N_INSNS (3); 5133 else 5134 return COSTS_N_INSNS (4); 5135 } 5136} 5137 5138 5139/* Cost of moving data from a register of class 'from' to on in class 'to'. 5140 Reload does not check the constraint of set insns when the two registers 5141 have a move cost of 2. Setting a higher cost will force reload to check 5142 the constraints. */ 5143int 5144m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from, 5145 enum reg_class to) 5146{ 5147 /* All costs are symmetric, so reduce cases by putting the 5148 lower number class as the destination. */ 5149 if (from < to) 5150 { 5151 enum reg_class tmp = to; 5152 to = from, from = tmp; 5153 } 5154 if (to >= S_REGS) 5155 return m68hc11_memory_move_cost (mode, S_REGS, 0); 5156 else if (from <= S_REGS) 5157 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress); 5158 else 5159 return COSTS_N_INSNS (2); 5160} 5161 5162 5163/* Provide the costs of an addressing mode that contains ADDR. 5164 If ADDR is not a valid address, its cost is irrelevant. */ 5165 5166static int 5167m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) 5168{ 5169 int cost = 4; 5170 5171 switch (GET_CODE (addr)) 5172 { 5173 case REG: 5174 /* Make the cost of hard registers and specially SP, FP small. */ 5175 if (REGNO (addr) < FIRST_PSEUDO_REGISTER) 5176 cost = 0; 5177 else 5178 cost = 1; 5179 break; 5180 5181 case SYMBOL_REF: 5182 cost = 8; 5183 break; 5184 5185 case LABEL_REF: 5186 case CONST: 5187 cost = 0; 5188 break; 5189 5190 case PLUS: 5191 { 5192 register rtx plus0 = XEXP (addr, 0); 5193 register rtx plus1 = XEXP (addr, 1); 5194 5195 if (GET_CODE (plus0) != REG) 5196 break; 5197 5198 switch (GET_CODE (plus1)) 5199 { 5200 case CONST_INT: 5201 if (INTVAL (plus1) >= 2 * m68hc11_max_offset 5202 || INTVAL (plus1) < m68hc11_min_offset) 5203 cost = 3; 5204 else if (INTVAL (plus1) >= m68hc11_max_offset) 5205 cost = 2; 5206 else 5207 cost = 1; 5208 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER) 5209 cost += 0; 5210 else 5211 cost += 1; 5212 break; 5213 5214 case SYMBOL_REF: 5215 cost = 8; 5216 break; 5217 5218 case CONST: 5219 case LABEL_REF: 5220 cost = 0; 5221 break; 5222 5223 default: 5224 break; 5225 } 5226 break; 5227 } 5228 case PRE_DEC: 5229 case PRE_INC: 5230 if (SP_REG_P (XEXP (addr, 0))) 5231 cost = 1; 5232 break; 5233 5234 default: 5235 break; 5236 } 5237 if (debug_m6811) 5238 { 5239 printf ("Address cost: %d for :", cost); 5240 fflush (stdout); 5241 debug_rtx (addr); 5242 } 5243 5244 return cost; 5245} 5246 5247static int 5248m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift) 5249{ 5250 int total; 5251 5252 total = rtx_cost (x, SET, !optimize_size); 5253 if (mode == QImode) 5254 total += m68hc11_cost->shiftQI_const[shift % 8]; 5255 else if (mode == HImode) 5256 total += m68hc11_cost->shiftHI_const[shift % 16]; 5257 else if (shift == 8 || shift == 16 || shift == 32) 5258 total += m68hc11_cost->shiftHI_const[8]; 5259 else if (shift != 0 && shift != 16 && shift != 32) 5260 { 5261 total += m68hc11_cost->shiftHI_const[1] * shift; 5262 } 5263 5264 /* For SI and others, the cost is higher. */ 5265 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0) 5266 total *= GET_MODE_SIZE (mode) / 2; 5267 5268 /* When optimizing for size, make shift more costly so that 5269 multiplications are preferred. */ 5270 if (optimize_size && (shift % 8) != 0) 5271 total *= 2; 5272 5273 return total; 5274} 5275 5276static int 5277m68hc11_rtx_costs_1 (rtx x, enum rtx_code code, 5278 enum rtx_code outer_code ATTRIBUTE_UNUSED) 5279{ 5280 enum machine_mode mode = GET_MODE (x); 5281 int extra_cost = 0; 5282 int total; 5283 5284 switch (code) 5285 { 5286 case ROTATE: 5287 case ROTATERT: 5288 case ASHIFT: 5289 case LSHIFTRT: 5290 case ASHIFTRT: 5291 if (GET_CODE (XEXP (x, 1)) == CONST_INT) 5292 { 5293 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1))); 5294 } 5295 5296 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); 5297 total += m68hc11_cost->shift_var; 5298 return total; 5299 5300 case AND: 5301 case XOR: 5302 case IOR: 5303 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); 5304 total += m68hc11_cost->logical; 5305 5306 /* Logical instructions are byte instructions only. */ 5307 total *= GET_MODE_SIZE (mode); 5308 return total; 5309 5310 case MINUS: 5311 case PLUS: 5312 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); 5313 total += m68hc11_cost->add; 5314 if (GET_MODE_SIZE (mode) > 2) 5315 { 5316 total *= GET_MODE_SIZE (mode) / 2; 5317 } 5318 return total; 5319 5320 case UDIV: 5321 case DIV: 5322 case MOD: 5323 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); 5324 switch (mode) 5325 { 5326 case QImode: 5327 total += m68hc11_cost->divQI; 5328 break; 5329 5330 case HImode: 5331 total += m68hc11_cost->divHI; 5332 break; 5333 5334 case SImode: 5335 default: 5336 total += m68hc11_cost->divSI; 5337 break; 5338 } 5339 return total; 5340 5341 case MULT: 5342 /* mul instruction produces 16-bit result. */ 5343 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND 5344 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND) 5345 return m68hc11_cost->multQI 5346 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size) 5347 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size); 5348 5349 /* emul instruction produces 32-bit result for 68HC12. */ 5350 if (TARGET_M6812 && mode == SImode 5351 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND 5352 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND) 5353 return m68hc11_cost->multHI 5354 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size) 5355 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size); 5356 5357 total = rtx_cost (XEXP (x, 0), code, !optimize_size) 5358 + rtx_cost (XEXP (x, 1), code, !optimize_size); 5359 switch (mode) 5360 { 5361 case QImode: 5362 total += m68hc11_cost->multQI; 5363 break; 5364 5365 case HImode: 5366 total += m68hc11_cost->multHI; 5367 break; 5368 5369 case SImode: 5370 default: 5371 total += m68hc11_cost->multSI; 5372 break; 5373 } 5374 return total; 5375 5376 case NEG: 5377 case SIGN_EXTEND: 5378 extra_cost = COSTS_N_INSNS (2); 5379 5380 /* Fall through */ 5381 case NOT: 5382 case COMPARE: 5383 case ABS: 5384 case ZERO_EXTEND: 5385 case ZERO_EXTRACT: 5386 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size); 5387 if (mode == QImode) 5388 { 5389 return total + COSTS_N_INSNS (1); 5390 } 5391 if (mode == HImode) 5392 { 5393 return total + COSTS_N_INSNS (2); 5394 } 5395 if (mode == SImode) 5396 { 5397 return total + COSTS_N_INSNS (4); 5398 } 5399 return total + COSTS_N_INSNS (8); 5400 5401 case IF_THEN_ELSE: 5402 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) 5403 return COSTS_N_INSNS (1); 5404 5405 return COSTS_N_INSNS (1); 5406 5407 default: 5408 return COSTS_N_INSNS (4); 5409 } 5410} 5411 5412static bool 5413m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total, 5414 bool speed ATTRIBUTE_UNUSED) 5415{ 5416 enum rtx_code code = (enum rtx_code) codearg; 5417 enum rtx_code outer_code = (enum rtx_code) outer_code_arg; 5418 5419 switch (code) 5420 { 5421 /* Constants are cheap. Moving them in registers must be avoided 5422 because most instructions do not handle two register operands. */ 5423 case CONST_INT: 5424 case CONST: 5425 case LABEL_REF: 5426 case SYMBOL_REF: 5427 case CONST_DOUBLE: 5428 /* Logical and arithmetic operations with a constant operand are 5429 better because they are not supported with two registers. */ 5430 /* 'clr' is slow */ 5431 if (outer_code == SET && x == const0_rtx) 5432 /* After reload, the reload_cse pass checks the cost to change 5433 a SET into a PLUS. Make const0 cheap then. */ 5434 *total = 1 - reload_completed; 5435 else 5436 *total = 0; 5437 return true; 5438 5439 case ZERO_EXTRACT: 5440 if (outer_code != COMPARE) 5441 return false; 5442 5443 case ROTATE: 5444 case ROTATERT: 5445 case ASHIFT: 5446 case LSHIFTRT: 5447 case ASHIFTRT: 5448 case MINUS: 5449 case PLUS: 5450 case AND: 5451 case XOR: 5452 case IOR: 5453 case UDIV: 5454 case DIV: 5455 case MOD: 5456 case MULT: 5457 case NEG: 5458 case SIGN_EXTEND: 5459 case NOT: 5460 case COMPARE: 5461 case ZERO_EXTEND: 5462 case IF_THEN_ELSE: 5463 *total = m68hc11_rtx_costs_1 (x, code, outer_code); 5464 return true; 5465 5466 default: 5467 return false; 5468 } 5469} 5470 5471 5472/* Worker function for TARGET_ASM_FILE_START. */ 5473 5474static void 5475m68hc11_file_start (void) 5476{ 5477 default_file_start (); 5478 5479 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong"); 5480} 5481 5482 5483/* Worker function for TARGET_ASM_CONSTRUCTOR. */ 5484 5485static void 5486m68hc11_asm_out_constructor (rtx symbol, int priority) 5487{ 5488 default_ctor_section_asm_out_constructor (symbol, priority); 5489 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n"); 5490} 5491 5492/* Worker function for TARGET_ASM_DESTRUCTOR. */ 5493 5494static void 5495m68hc11_asm_out_destructor (rtx symbol, int priority) 5496{ 5497 default_dtor_section_asm_out_destructor (symbol, priority); 5498 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n"); 5499} 5500 5501/* Worker function for TARGET_STRUCT_VALUE_RTX. */ 5502 5503static rtx 5504m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, 5505 int incoming ATTRIBUTE_UNUSED) 5506{ 5507 return gen_rtx_REG (Pmode, HARD_D_REGNUM); 5508} 5509 5510/* Return true if type TYPE should be returned in memory. 5511 Blocks and data types largers than 4 bytes cannot be returned 5512 in the register (D + X = 4). */ 5513 5514static bool 5515m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) 5516{ 5517 if (TYPE_MODE (type) == BLKmode) 5518 { 5519 HOST_WIDE_INT size = int_size_in_bytes (type); 5520 return (size == -1 || size > 4); 5521 } 5522 else 5523 return GET_MODE_SIZE (TYPE_MODE (type)) > 4; 5524} 5525 5526#include "gt-m68hc11.h" 5527