00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include "config.h"
00037 #include "system.h"
00038 #include "rtl.h"
00039 #include "tree.h"
00040 #include "tm_p.h"
00041 #include "regs.h"
00042 #include "hard-reg-set.h"
00043 #include "real.h"
00044 #include "insn-config.h"
00045 #include "conditions.h"
00046 #include "output.h"
00047 #include "insn-attr.h"
00048 #include "flags.h"
00049 #include "recog.h"
00050 #include "expr.h"
00051 #include "toplev.h"
00052 #include "basic-block.h"
00053 #include "function.h"
00054 #include "ggc.h"
00055 #include "reload.h"
00056 #include "target.h"
00057 #include "target-def.h"
00058
00059 static void print_options PARAMS ((FILE *));
00060 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
00061 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
00062 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
00063 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
00064 int));
00065 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
00066 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
00067 static int must_parenthesize PARAMS ((rtx));
00068 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
00069 static int m68hc11_auto_inc_p PARAMS ((rtx));
00070 static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
00071 const struct attribute_spec m68hc11_attribute_table[];
00072
00073 void create_regs_rtx PARAMS ((void));
00074 static void m68hc11_add_gc_roots PARAMS ((void));
00075
00076 static void asm_print_register PARAMS ((FILE *, int));
00077 static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
00078 static void m68hc11_asm_out_constructor PARAMS ((rtx, int));
00079 static void m68hc11_asm_out_destructor PARAMS ((rtx, int));
00080
00081 rtx m68hc11_soft_tmp_reg;
00082
00083
00084 int debug_m6811 = 0;
00085
00086 extern FILE *asm_out_file;
00087
00088 rtx ix_reg;
00089 rtx iy_reg;
00090 rtx d_reg;
00091 rtx da_reg;
00092 rtx stack_push_word;
00093 rtx stack_pop_word;
00094 static int regs_inited = 0;
00095 static rtx z_reg;
00096
00097
00098 int current_function_interrupt;
00099
00100
00101 int current_function_trap;
00102
00103
00104 HOST_WIDE_INT m68hc11_min_offset = 0;
00105
00106
00107 HOST_WIDE_INT m68hc11_max_offset = 256;
00108
00109
00110 enum reg_class m68hc11_base_reg_class = A_REGS;
00111
00112
00113 enum reg_class m68hc11_index_reg_class = NO_REGS;
00114
00115 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
00116
00117
00118
00119
00120 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
00121 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
00122
00123
00124
00125 int m68hc11_sp_correction;
00126
00127
00128 rtx m68hc11_compare_op0;
00129 rtx m68hc11_compare_op1;
00130
00131
00132 const struct processor_costs *m68hc11_cost;
00133
00134
00135 static const struct processor_costs m6811_cost = {
00136
00137 COSTS_N_INSNS (2),
00138
00139 COSTS_N_INSNS (2),
00140
00141 COSTS_N_INSNS (20),
00142
00143 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
00144 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
00145 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
00146
00147
00148 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
00149 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
00150 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
00151 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
00152 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
00153 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
00154 },
00155
00156 COSTS_N_INSNS (20),
00157
00158 COSTS_N_INSNS (20 * 4),
00159
00160 COSTS_N_INSNS (20 * 16),
00161
00162 COSTS_N_INSNS (20),
00163
00164 COSTS_N_INSNS (80),
00165
00166 COSTS_N_INSNS (100)
00167 };
00168
00169
00170 static const struct processor_costs m6812_cost = {
00171
00172 COSTS_N_INSNS (2),
00173
00174 COSTS_N_INSNS (2),
00175
00176 COSTS_N_INSNS (20),
00177
00178 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
00179 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
00180 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
00181
00182
00183 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
00184 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
00185 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
00186 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
00187 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
00188 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
00189 },
00190
00191 COSTS_N_INSNS (3),
00192
00193 COSTS_N_INSNS (3),
00194
00195 COSTS_N_INSNS (3 * 4),
00196
00197 COSTS_N_INSNS (12),
00198
00199 COSTS_N_INSNS (12),
00200
00201 COSTS_N_INSNS (100)
00202 };
00203
00204
00205
00206 const char *m68hc11_regparm_string;
00207 const char *m68hc11_reg_alloc_order;
00208 const char *m68hc11_soft_reg_count;
00209
00210 static int nb_soft_regs;
00211
00212
00213 #undef TARGET_ATTRIBUTE_TABLE
00214 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
00215
00216 #undef TARGET_ASM_ALIGNED_HI_OP
00217 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
00218
00219 #undef TARGET_ASM_FUNCTION_EPILOGUE
00220 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
00221
00222 struct gcc_target targetm = TARGET_INITIALIZER;
00223
00224 int
00225 m68hc11_override_options ()
00226 {
00227 m68hc11_add_gc_roots ();
00228
00229 memset (m68hc11_reg_valid_for_index, 0,
00230 sizeof (m68hc11_reg_valid_for_index));
00231 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
00232
00233
00234 if (flag_pic)
00235 {
00236 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
00237 (flag_pic > 1) ? "PIC" : "pic");
00238 flag_pic = 0;
00239 }
00240
00241
00242 if (TARGET_M6811)
00243 {
00244
00245
00246 if (TARGET_DEFAULT != MASK_M6811)
00247 target_flags &= ~TARGET_DEFAULT;
00248
00249 if (!TARGET_M6812)
00250 target_flags &= ~TARGET_AUTO_INC_DEC;
00251 m68hc11_cost = &m6811_cost;
00252 m68hc11_min_offset = 0;
00253 m68hc11_max_offset = 256;
00254 m68hc11_index_reg_class = NO_REGS;
00255 m68hc11_base_reg_class = A_REGS;
00256 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
00257 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
00258 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
00259 m68hc11_sp_correction = 1;
00260 m68hc11_tmp_regs_class = D_REGS;
00261 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
00262 m68hc11_soft_reg_count = "4";
00263 }
00264
00265
00266 if (TARGET_M6812)
00267 {
00268 m68hc11_cost = &m6812_cost;
00269 m68hc11_min_offset = -65536;
00270 m68hc11_max_offset = 65536;
00271 m68hc11_index_reg_class = D_REGS;
00272 m68hc11_base_reg_class = A_OR_SP_REGS;
00273 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
00274 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
00275 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
00276 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
00277 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
00278 m68hc11_sp_correction = 0;
00279 m68hc11_tmp_regs_class = TMP_REGS;
00280 target_flags &= ~MASK_M6811;
00281 target_flags |= MASK_NO_DIRECT_MODE;
00282 if (m68hc11_soft_reg_count == 0)
00283 m68hc11_soft_reg_count = "0";
00284 }
00285 return 0;
00286 }
00287
00288
00289 int
00290 m68hc11_optimization_options (level, size)
00291 int level ATTRIBUTE_UNUSED;
00292 int size;
00293 {
00294
00295
00296
00297 if (size)
00298 {
00299 flag_reorder_blocks = 0;
00300 }
00301 return 0;
00302 }
00303
00304 void
00305 m68hc11_conditional_register_usage ()
00306 {
00307 int i;
00308 int cnt = atoi (m68hc11_soft_reg_count);
00309
00310 if (cnt < 0)
00311 cnt = 0;
00312 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
00313 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
00314
00315 nb_soft_regs = cnt;
00316 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
00317 {
00318 fixed_regs[i] = 1;
00319 call_used_regs[i] = 1;
00320 }
00321
00322
00323
00324
00325 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
00326 {
00327 fixed_regs[HARD_Z_REGNUM] = 1;
00328 }
00329 }
00330
00331
00332
00333
00334 static const char *const reg_class_names[] = REG_CLASS_NAMES;
00335
00336
00337 void
00338 create_regs_rtx ()
00339 {
00340
00341 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
00342 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
00343 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
00344 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
00345 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
00346
00347 stack_push_word = gen_rtx (MEM, HImode,
00348 gen_rtx (PRE_DEC, HImode,
00349 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
00350 stack_pop_word = gen_rtx (MEM, HImode,
00351 gen_rtx (POST_INC, HImode,
00352 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
00353
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 int
00365 hard_regno_mode_ok (regno, mode)
00366 int regno;
00367 enum machine_mode mode;
00368 {
00369 switch (GET_MODE_SIZE (mode))
00370 {
00371 case 8:
00372 return S_REGNO_P (regno) && nb_soft_regs >= 4;
00373
00374 case 4:
00375 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
00376
00377 case 2:
00378 return G_REGNO_P (regno);
00379
00380 case 1:
00381
00382
00383
00384
00385
00386
00387 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
00388
00389 default:
00390 return 0;
00391 }
00392 }
00393
00394 enum reg_class
00395 preferred_reload_class (operand, class)
00396 rtx operand;
00397 enum reg_class class;
00398 {
00399 enum machine_mode mode;
00400
00401 mode = GET_MODE (operand);
00402
00403 if (debug_m6811)
00404 {
00405 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
00406 }
00407
00408 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
00409 return m68hc11_base_reg_class;
00410
00411 if (class >= S_REGS && (GET_CODE (operand) == MEM
00412 || GET_CODE (operand) == CONST_INT))
00413 {
00414
00415
00416
00417 switch (class)
00418 {
00419 default:
00420 case G_REGS:
00421 case D_OR_A_OR_S_REGS:
00422 class = A_OR_D_REGS;
00423 break;
00424 case A_OR_S_REGS:
00425 class = A_REGS;
00426 break;
00427 case D_OR_SP_OR_S_REGS:
00428 class = D_OR_SP_REGS;
00429 break;
00430 case D_OR_Y_OR_S_REGS:
00431 class = D_OR_Y_REGS;
00432 break;
00433 case D_OR_X_OR_S_REGS:
00434 class = D_OR_X_REGS;
00435 break;
00436 case SP_OR_S_REGS:
00437 class = SP_REGS;
00438 break;
00439 case Y_OR_S_REGS:
00440 class = Y_REGS;
00441 break;
00442 case X_OR_S_REGS:
00443 class = X_REGS;
00444 break;
00445 case D_OR_S_REGS:
00446 class = D_REGS;
00447 }
00448 }
00449 else if (class == Y_REGS && GET_CODE (operand) == MEM)
00450 {
00451 class = Y_REGS;
00452 }
00453 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
00454 {
00455 class = D_OR_X_REGS;
00456 }
00457 else if (class >= S_REGS && S_REG_P (operand))
00458 {
00459 switch (class)
00460 {
00461 default:
00462 case G_REGS:
00463 case D_OR_A_OR_S_REGS:
00464 class = A_OR_D_REGS;
00465 break;
00466 case A_OR_S_REGS:
00467 class = A_REGS;
00468 break;
00469 case D_OR_SP_OR_S_REGS:
00470 class = D_OR_SP_REGS;
00471 break;
00472 case D_OR_Y_OR_S_REGS:
00473 class = D_OR_Y_REGS;
00474 break;
00475 case D_OR_X_OR_S_REGS:
00476 class = D_OR_X_REGS;
00477 break;
00478 case SP_OR_S_REGS:
00479 class = SP_REGS;
00480 break;
00481 case Y_OR_S_REGS:
00482 class = Y_REGS;
00483 break;
00484 case X_OR_S_REGS:
00485 class = X_REGS;
00486 break;
00487 case D_OR_S_REGS:
00488 class = D_REGS;
00489 }
00490 }
00491 else if (class >= S_REGS)
00492 {
00493 if (debug_m6811)
00494 {
00495 printf ("Class = %s for: ", reg_class_names[class]);
00496 fflush (stdout);
00497 debug_rtx (operand);
00498 }
00499 }
00500
00501 if (debug_m6811)
00502 {
00503 printf (" => class=%s\n", reg_class_names[class]);
00504 fflush (stdout);
00505 debug_rtx (operand);
00506 }
00507
00508 return class;
00509 }
00510
00511
00512
00513
00514 static int
00515 register_indirect_p (operand, mode, strict)
00516 rtx operand;
00517 enum machine_mode mode;
00518 int strict;
00519 {
00520 rtx base, offset;
00521
00522 switch (GET_CODE (operand))
00523 {
00524 case POST_INC:
00525 case PRE_INC:
00526 case POST_DEC:
00527 case PRE_DEC:
00528 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
00529 return register_indirect_p (XEXP (operand, 0), mode, strict);
00530 return 0;
00531
00532 case PLUS:
00533 base = XEXP (operand, 0);
00534 if (GET_CODE (base) == MEM)
00535 return 0;
00536
00537 offset = XEXP (operand, 1);
00538 if (GET_CODE (offset) == MEM)
00539 return 0;
00540
00541 if (GET_CODE (base) == REG)
00542 {
00543 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
00544 return 0;
00545
00546 if (strict == 0)
00547 return 1;
00548
00549 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
00550 }
00551 if (GET_CODE (offset) == REG)
00552 {
00553 if (!VALID_CONSTANT_OFFSET_P (base, mode))
00554 return 0;
00555
00556 if (strict == 0)
00557 return 1;
00558
00559 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
00560 }
00561 return 0;
00562
00563 case REG:
00564 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
00565
00566 case CONST_INT:
00567 if (TARGET_M6811)
00568 return 0;
00569
00570 return VALID_CONSTANT_OFFSET_P (operand, mode);
00571
00572 default:
00573 return 0;
00574 }
00575 }
00576
00577
00578
00579 int
00580 m68hc11_small_indexed_indirect_p (operand, mode)
00581 rtx operand;
00582 enum machine_mode mode;
00583 {
00584 rtx base, offset;
00585
00586 if (GET_CODE (operand) == REG && reload_in_progress
00587 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
00588 && reg_equiv_memory_loc[REGNO (operand)])
00589 {
00590 operand = reg_equiv_memory_loc[REGNO (operand)];
00591 operand = eliminate_regs (operand, 0, NULL_RTX);
00592 }
00593
00594 if (GET_CODE (operand) != MEM)
00595 return 0;
00596
00597 operand = XEXP (operand, 0);
00598 if (CONSTANT_ADDRESS_P (operand))
00599 return 1;
00600
00601 if (PUSH_POP_ADDRESS_P (operand))
00602 return 1;
00603
00604 if (!register_indirect_p (operand, mode, reload_completed))
00605 return 0;
00606
00607 if (TARGET_M6812 && GET_CODE (operand) == PLUS
00608 && (reload_completed | reload_in_progress))
00609 {
00610 base = XEXP (operand, 0);
00611 offset = XEXP (operand, 1);
00612
00613
00614
00615 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
00616 return 0;
00617
00618 if (GET_CODE (base) == CONST_INT)
00619 offset = base;
00620
00621 switch (GET_MODE_SIZE (mode))
00622 {
00623 case 8:
00624 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
00625 return 0;
00626 break;
00627
00628 case 4:
00629 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
00630 return 0;
00631 break;
00632
00633 default:
00634 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
00635 return 0;
00636 break;
00637 }
00638 }
00639 return 1;
00640 }
00641
00642 int
00643 m68hc11_register_indirect_p (operand, mode)
00644 rtx operand;
00645 enum machine_mode mode;
00646 {
00647 if (GET_CODE (operand) != MEM)
00648 return 0;
00649
00650 operand = XEXP (operand, 0);
00651 return register_indirect_p (operand, mode,
00652 (reload_completed | reload_in_progress));
00653 }
00654
00655 static int
00656 go_if_legitimate_address_internal (operand, mode, strict)
00657 rtx operand;
00658 enum machine_mode mode;
00659 int strict;
00660 {
00661 if (CONSTANT_ADDRESS_P (operand))
00662 {
00663
00664
00665 if (GET_MODE_SIZE (mode) == 8)
00666 return 0;
00667
00668 return 1;
00669 }
00670 if (register_indirect_p (operand, mode, strict))
00671 {
00672 return 1;
00673 }
00674 if (PUSH_POP_ADDRESS_P (operand))
00675 {
00676 return 1;
00677 }
00678 if (symbolic_memory_operand (operand, mode))
00679 {
00680 return 1;
00681 }
00682 return 0;
00683 }
00684
00685 int
00686 m68hc11_go_if_legitimate_address (operand, mode, strict)
00687 rtx operand;
00688 enum machine_mode mode;
00689 int strict;
00690 {
00691 int result;
00692
00693 if (debug_m6811)
00694 {
00695 printf ("Checking: ");
00696 fflush (stdout);
00697 debug_rtx (operand);
00698 }
00699
00700 result = go_if_legitimate_address_internal (operand, mode, strict);
00701
00702 if (debug_m6811)
00703 {
00704 printf (" -> %s\n", result == 0 ? "NO" : "YES");
00705 }
00706
00707 if (result == 0)
00708 {
00709 if (debug_m6811)
00710 {
00711 printf ("go_if_legitimate%s, ret 0: %d:",
00712 (strict ? "_strict" : ""), mode);
00713 fflush (stdout);
00714 debug_rtx (operand);
00715 }
00716 }
00717 return result;
00718 }
00719
00720 int
00721 m68hc11_legitimize_address (operand, old_operand, mode)
00722 rtx *operand ATTRIBUTE_UNUSED;
00723 rtx old_operand ATTRIBUTE_UNUSED;
00724 enum machine_mode mode ATTRIBUTE_UNUSED;
00725 {
00726 return 0;
00727 }
00728
00729
00730 int
00731 m68hc11_reload_operands (operands)
00732 rtx operands[];
00733 {
00734 enum machine_mode mode;
00735
00736 if (regs_inited == 0)
00737 create_regs_rtx ();
00738
00739 mode = GET_MODE (operands[1]);
00740
00741
00742 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
00743 {
00744 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
00745 rtx base = XEXP (XEXP (operands[1], 0), 0);
00746
00747 if (GET_CODE (base) != REG)
00748 {
00749 rtx tmp = base;
00750 base = big_offset;
00751 big_offset = tmp;
00752 }
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
00775 {
00776 int vh, vl;
00777 rtx reg = operands[0];
00778 rtx offset;
00779 int val = INTVAL (big_offset);
00780
00781
00782
00783
00784 if (!rtx_equal_p (base, operands[0]))
00785 {
00786 emit_move_insn (reg, base);
00787 }
00788
00789 if (val > 0)
00790 {
00791 vh = val >> 8;
00792 vl = val & 0x0FF;
00793 }
00794 else
00795 {
00796 vh = (val >> 8) & 0x0FF;
00797 vl = val & 0x0FF;
00798 }
00799
00800
00801
00802 offset = GEN_INT (vl);
00803 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
00804 {
00805 emit_insn (gen_rtx (SET, VOIDmode, reg,
00806 gen_rtx (PLUS, HImode, reg, big_offset)));
00807 offset = const0_rtx;
00808 }
00809 else
00810 {
00811 emit_insn (gen_rtx (SET, VOIDmode, reg,
00812 gen_rtx (PLUS, HImode, reg,
00813 GEN_INT (vh << 8))));
00814 }
00815 emit_move_insn (operands[0],
00816 gen_rtx (MEM, GET_MODE (operands[1]),
00817 gen_rtx (PLUS, Pmode, reg, offset)));
00818 return 1;
00819 }
00820 }
00821
00822
00823 return 0;
00824 }
00825
00826 void
00827 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
00828 const char *name;
00829 enum rtx_code code;
00830 enum machine_mode dmode;
00831 enum machine_mode smode;
00832 int noperands;
00833 rtx *operands;
00834 {
00835 rtx ret;
00836 rtx insns;
00837 rtx libcall;
00838 rtx equiv;
00839
00840 start_sequence ();
00841 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
00842 switch (noperands)
00843 {
00844 case 2:
00845 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
00846 dmode, 1, operands[1], smode);
00847 equiv = gen_rtx (code, dmode, operands[1]);
00848 break;
00849
00850 case 3:
00851 ret = emit_library_call_value (libcall, NULL_RTX,
00852 LCT_CONST, dmode, 2,
00853 operands[1], smode, operands[2],
00854 smode);
00855 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
00856 break;
00857
00858 default:
00859 abort ();
00860 }
00861
00862 insns = get_insns ();
00863 end_sequence ();
00864 emit_libcall_block (insns, operands[0], ret, equiv);
00865 }
00866
00867
00868
00869
00870 static int
00871 m68hc11_auto_inc_p (x)
00872 rtx x;
00873 {
00874 return GET_CODE (x) == PRE_DEC
00875 || GET_CODE (x) == POST_INC
00876 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
00877 }
00878
00879
00880
00881
00882 int
00883 memory_reload_operand (operand, mode)
00884 rtx operand;
00885 enum machine_mode mode ATTRIBUTE_UNUSED;
00886 {
00887 return GET_CODE (operand) == MEM
00888 && GET_CODE (XEXP (operand, 0)) == PLUS
00889 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
00890 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
00891 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
00892 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
00893 }
00894
00895 int
00896 tst_operand (operand, mode)
00897 rtx operand;
00898 enum machine_mode mode;
00899 {
00900 if (GET_CODE (operand) == MEM && reload_completed == 0)
00901 {
00902 rtx addr = XEXP (operand, 0);
00903 if (m68hc11_auto_inc_p (addr))
00904 return 0;
00905 }
00906 return nonimmediate_operand (operand, mode);
00907 }
00908
00909 int
00910 cmp_operand (operand, mode)
00911 rtx operand;
00912 enum machine_mode mode;
00913 {
00914 if (GET_CODE (operand) == MEM)
00915 {
00916 rtx addr = XEXP (operand, 0);
00917 if (m68hc11_auto_inc_p (addr))
00918 return 0;
00919 }
00920 return general_operand (operand, mode);
00921 }
00922
00923 int
00924 non_push_operand (operand, mode)
00925 rtx operand;
00926 enum machine_mode mode;
00927 {
00928 if (general_operand (operand, mode) == 0)
00929 return 0;
00930
00931 if (push_operand (operand, mode) == 1)
00932 return 0;
00933 return 1;
00934 }
00935
00936 int
00937 reg_or_some_mem_operand (operand, mode)
00938 rtx operand;
00939 enum machine_mode mode;
00940 {
00941 if (GET_CODE (operand) == MEM)
00942 {
00943 rtx op = XEXP (operand, 0);
00944
00945 if (symbolic_memory_operand (op, mode))
00946 return 1;
00947
00948 if (IS_STACK_PUSH (operand))
00949 return 1;
00950
00951 if (m68hc11_register_indirect_p (operand, mode))
00952 return 1;
00953
00954 return 0;
00955 }
00956
00957 return register_operand (operand, mode);
00958 }
00959
00960 int
00961 m68hc11_symbolic_p (operand, mode)
00962 rtx operand;
00963 enum machine_mode mode;
00964 {
00965 if (GET_CODE (operand) == MEM)
00966 {
00967 rtx op = XEXP (operand, 0);
00968
00969 if (symbolic_memory_operand (op, mode))
00970 return 1;
00971 }
00972 return 0;
00973 }
00974
00975 int
00976 m68hc11_indirect_p (operand, mode)
00977 rtx operand;
00978 enum machine_mode mode;
00979 {
00980 if (GET_CODE (operand) == MEM)
00981 {
00982 rtx op = XEXP (operand, 0);
00983
00984 if (symbolic_memory_operand (op, mode))
00985 return 0;
00986
00987 if (reload_in_progress)
00988 return 1;
00989
00990 operand = XEXP (operand, 0);
00991 return register_indirect_p (operand, mode, reload_completed);
00992 }
00993 return 0;
00994 }
00995
00996 int
00997 stack_register_operand (operand, mode)
00998 rtx operand;
00999 enum machine_mode mode ATTRIBUTE_UNUSED;
01000 {
01001 return SP_REG_P (operand);
01002 }
01003
01004 int
01005 d_register_operand (operand, mode)
01006 rtx operand;
01007 enum machine_mode mode ATTRIBUTE_UNUSED;
01008 {
01009 if (GET_CODE (operand) == SUBREG)
01010 operand = XEXP (operand, 0);
01011
01012 return GET_CODE (operand) == REG
01013 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
01014 || REGNO (operand) == HARD_D_REGNUM
01015 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
01016 }
01017
01018 int
01019 hard_addr_reg_operand (operand, mode)
01020 rtx operand;
01021 enum machine_mode mode ATTRIBUTE_UNUSED;
01022 {
01023 if (GET_CODE (operand) == SUBREG)
01024 operand = XEXP (operand, 0);
01025
01026 return GET_CODE (operand) == REG
01027 && (REGNO (operand) == HARD_X_REGNUM
01028 || REGNO (operand) == HARD_Y_REGNUM
01029 || REGNO (operand) == HARD_Z_REGNUM);
01030 }
01031
01032 int
01033 hard_reg_operand (operand, mode)
01034 rtx operand;
01035 enum machine_mode mode ATTRIBUTE_UNUSED;
01036 {
01037 if (GET_CODE (operand) == SUBREG)
01038 operand = XEXP (operand, 0);
01039
01040 return GET_CODE (operand) == REG
01041 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
01042 || H_REGNO_P (REGNO (operand)));
01043 }
01044
01045 int
01046 memory_indexed_operand (operand, mode)
01047 rtx operand;
01048 enum machine_mode mode ATTRIBUTE_UNUSED;
01049 {
01050 if (GET_CODE (operand) != MEM)
01051 return 0;
01052
01053 operand = XEXP (operand, 0);
01054 if (GET_CODE (operand) == PLUS)
01055 {
01056 if (GET_CODE (XEXP (operand, 0)) == REG)
01057 operand = XEXP (operand, 0);
01058 else if (GET_CODE (XEXP (operand, 1)) == REG)
01059 operand = XEXP (operand, 1);
01060 }
01061 return GET_CODE (operand) == REG
01062 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
01063 || A_REGNO_P (REGNO (operand)));
01064 }
01065
01066 int
01067 push_pop_operand_p (operand)
01068 rtx operand;
01069 {
01070 if (GET_CODE (operand) != MEM)
01071 {
01072 return 0;
01073 }
01074 operand = XEXP (operand, 0);
01075 return PUSH_POP_ADDRESS_P (operand);
01076 }
01077
01078
01079
01080
01081 int
01082 symbolic_memory_operand (op, mode)
01083 register rtx op;
01084 enum machine_mode mode;
01085 {
01086 switch (GET_CODE (op))
01087 {
01088 case SYMBOL_REF:
01089 case LABEL_REF:
01090 return 1;
01091
01092 case CONST:
01093 op = XEXP (op, 0);
01094 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
01095 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
01096 && GET_CODE (XEXP (op, 1)) == CONST_INT);
01097
01098
01099 case CONST_DOUBLE:
01100 return GET_MODE (op) == mode;
01101
01102 case PLUS:
01103 return symbolic_memory_operand (XEXP (op, 0), mode)
01104 && symbolic_memory_operand (XEXP (op, 1), mode);
01105
01106 default:
01107 return 0;
01108 }
01109 }
01110
01111 int
01112 m68hc11_logical_operator (op, mode)
01113 register rtx op;
01114 enum machine_mode mode ATTRIBUTE_UNUSED;
01115 {
01116 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
01117 }
01118
01119 int
01120 m68hc11_arith_operator (op, mode)
01121 register rtx op;
01122 enum machine_mode mode ATTRIBUTE_UNUSED;
01123 {
01124 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
01125 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
01126 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
01127 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
01128 || GET_CODE (op) == ROTATERT;
01129 }
01130
01131 int
01132 m68hc11_non_shift_operator (op, mode)
01133 register rtx op;
01134 enum machine_mode mode ATTRIBUTE_UNUSED;
01135 {
01136 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
01137 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
01138 }
01139
01140
01141 int
01142 m68hc11_unary_operator (op, mode)
01143 register rtx op;
01144 enum machine_mode mode ATTRIBUTE_UNUSED;
01145 {
01146 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
01147 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
01148 }
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159 void
01160 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
01161 rtx tramp;
01162 rtx fnaddr;
01163 rtx cxt;
01164 {
01165 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
01166
01167
01168 if (*static_chain_reg == '*')
01169 static_chain_reg++;
01170 if (TARGET_M6811)
01171 {
01172 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
01173 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
01174 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
01175 GEN_INT (0x18df));
01176 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
01177 gen_rtx_CONST (QImode,
01178 gen_rtx_SYMBOL_REF (Pmode,
01179 static_chain_reg)));
01180 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
01181 GEN_INT (0x7e));
01182 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
01183 }
01184 else
01185 {
01186 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
01187 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
01188 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
01189 gen_rtx_CONST (HImode,
01190 gen_rtx_SYMBOL_REF (Pmode,
01191 static_chain_reg)));
01192 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
01193 GEN_INT (0x06));
01194 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
01195 }
01196 }
01197
01198
01199
01200 const struct attribute_spec m68hc11_attribute_table[] =
01201 {
01202
01203 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
01204 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
01205 { NULL, 0, 0, false, false, false, NULL }
01206 };
01207
01208
01209
01210 static tree
01211 m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
01212 tree *node;
01213 tree name;
01214 tree args ATTRIBUTE_UNUSED;
01215 int flags ATTRIBUTE_UNUSED;
01216 bool *no_add_attrs;
01217 {
01218 if (TREE_CODE (*node) != FUNCTION_TYPE
01219 && TREE_CODE (*node) != FIELD_DECL
01220 && TREE_CODE (*node) != TYPE_DECL)
01221 {
01222 warning ("`%s' attribute only applies to functions",
01223 IDENTIFIER_POINTER (name));
01224 *no_add_attrs = true;
01225 }
01226
01227 return NULL_TREE;
01228 }
01229
01230
01231
01232
01233
01234
01235
01236
01237 void
01238 m68hc11_encode_section_info (decl)
01239 tree decl;
01240 {
01241 tree func_attr;
01242 int trap_handler;
01243 rtx rtl;
01244
01245 if (TREE_CODE (decl) != FUNCTION_DECL)
01246 return;
01247
01248 rtl = DECL_RTL (decl);
01249
01250 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
01251 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
01252 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
01253 }
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263 int
01264 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
01265 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
01266 enum machine_mode mode ATTRIBUTE_UNUSED;
01267 tree type;
01268 int named ATTRIBUTE_UNUSED;
01269 {
01270 return ((type && TREE_CODE (type) == ARRAY_TYPE)
01271
01272
01273 );
01274 }
01275
01276
01277
01278
01279 int
01280 m68hc11_initial_elimination_offset (from, to)
01281 int from;
01282 int to;
01283 {
01284 int trap_handler;
01285 tree func_attr;
01286 int size;
01287 int regno;
01288
01289
01290
01291 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
01292 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
01293 if (trap_handler && from == ARG_POINTER_REGNUM)
01294 size = 7;
01295 else
01296 size = 0;
01297
01298 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
01299 {
01300
01301
01302 return get_frame_size () + 2 + m68hc11_sp_correction + size;
01303 }
01304
01305 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
01306 {
01307 return m68hc11_sp_correction;
01308 }
01309
01310
01311 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
01312 {
01313 if (regs_ever_live[regno] && !call_used_regs[regno])
01314 {
01315 size += 2;
01316 }
01317 }
01318
01319 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
01320 {
01321 return get_frame_size () + size;
01322 }
01323
01324 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
01325 {
01326 return size;
01327 }
01328 return 0;
01329 }
01330
01331
01332
01333
01334
01335 void
01336 m68hc11_init_cumulative_args (cum, fntype, libname)
01337 CUMULATIVE_ARGS *cum;
01338 tree fntype;
01339 rtx libname;
01340 {
01341 tree ret_type;
01342
01343 z_replacement_completed = 0;
01344 cum->words = 0;
01345 cum->nregs = 0;
01346
01347
01348
01349
01350
01351
01352
01353 if (fntype == 0)
01354 {
01355 const char *name;
01356 size_t len;
01357
01358 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
01359 return;
01360
01361
01362
01363 name = XSTR (libname, 0);
01364 len = strlen (name);
01365 if (len > 3
01366 && ((name[len - 2] == 'd'
01367 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
01368 || (name[len - 3] == 'd'
01369 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
01370 {
01371
01372 cum->words = 1;
01373 cum->nregs = 1;
01374 }
01375 return;
01376 }
01377
01378 ret_type = TREE_TYPE (fntype);
01379
01380 if (ret_type && aggregate_value_p (ret_type))
01381 {
01382 cum->words = 1;
01383 cum->nregs = 1;
01384 }
01385 }
01386
01387
01388
01389
01390
01391 void
01392 m68hc11_function_arg_advance (cum, mode, type, named)
01393 CUMULATIVE_ARGS *cum;
01394 enum machine_mode mode;
01395 tree type;
01396 int named ATTRIBUTE_UNUSED;
01397 {
01398 if (mode != BLKmode)
01399 {
01400 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
01401 {
01402 cum->nregs = 2;
01403 cum->words = GET_MODE_SIZE (mode);
01404 }
01405 else
01406 {
01407 cum->words += GET_MODE_SIZE (mode);
01408 if (cum->words <= HARD_REG_SIZE)
01409 cum->nregs = 1;
01410 }
01411 }
01412 else
01413 {
01414 cum->words += int_size_in_bytes (type);
01415 }
01416 return;
01417 }
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432 struct rtx_def *
01433 m68hc11_function_arg (cum, mode, type, named)
01434 const CUMULATIVE_ARGS *cum;
01435 enum machine_mode mode;
01436 tree type ATTRIBUTE_UNUSED;
01437 int named ATTRIBUTE_UNUSED;
01438 {
01439 if (cum->words != 0)
01440 {
01441 return NULL_RTX;
01442 }
01443
01444 if (mode != BLKmode)
01445 {
01446 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
01447 return gen_rtx (REG, mode, HARD_X_REGNUM);
01448
01449 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
01450 {
01451 return NULL_RTX;
01452 }
01453 return gen_rtx (REG, mode, HARD_D_REGNUM);
01454 }
01455 return NULL_RTX;
01456 }
01457
01458
01459
01460 void
01461 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
01462 int stdarg_p ATTRIBUTE_UNUSED;
01463 tree valist;
01464 rtx nextarg;
01465 {
01466 tree t;
01467
01468
01469
01470
01471 if (!stdarg_p)
01472 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
01473
01474 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
01475 make_tree (ptr_type_node, nextarg));
01476 TREE_SIDE_EFFECTS (t) = 1;
01477
01478 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01479 }
01480
01481 rtx
01482 m68hc11_va_arg (valist, type)
01483 tree valist;
01484 tree type;
01485 {
01486 tree addr_tree, t;
01487 HOST_WIDE_INT align;
01488 HOST_WIDE_INT rounded_size;
01489 rtx addr;
01490 int pad_direction;
01491
01492
01493 align = PARM_BOUNDARY / BITS_PER_UNIT;
01494 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
01495
01496
01497 addr_tree = valist;
01498 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
01499
01500 if (pad_direction == downward)
01501 {
01502
01503
01504 HOST_WIDE_INT adj;
01505 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
01506 if (rounded_size > align)
01507 adj = rounded_size;
01508
01509 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
01510 build_int_2 (rounded_size - adj, 0));
01511 }
01512
01513 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
01514 addr = copy_to_reg (addr);
01515
01516
01517 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
01518 build (PLUS_EXPR, TREE_TYPE (valist), valist,
01519 build_int_2 (rounded_size, 0)));
01520 TREE_SIDE_EFFECTS (t) = 1;
01521 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01522
01523 return addr;
01524 }
01525
01526
01527
01528
01529
01530
01531
01532 int
01533 m68hc11_function_arg_padding (mode, type)
01534 enum machine_mode mode;
01535 tree type;
01536 {
01537 if (type != 0 && AGGREGATE_TYPE_P (type))
01538 return upward;
01539
01540
01541 return (!BYTES_BIG_ENDIAN
01542 ? upward
01543 : ((mode == BLKmode
01544 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
01545 && int_size_in_bytes (type) <
01546 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
01547 PARM_BOUNDARY) ? downward : upward));
01548 }
01549
01550
01551
01552
01553
01554
01555 static void
01556 emit_move_after_reload (to, from, scratch)
01557 rtx to, from, scratch;
01558 {
01559 rtx insn;
01560
01561 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
01562 {
01563 insn = emit_move_insn (to, from);
01564 }
01565 else
01566 {
01567 emit_move_insn (scratch, from);
01568 insn = emit_move_insn (to, scratch);
01569 }
01570
01571
01572
01573 if (IS_STACK_PUSH (to))
01574 {
01575 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
01576 XEXP (XEXP (to, 0), 0),
01577 REG_NOTES (insn));
01578 }
01579 else if (IS_STACK_POP (from))
01580 {
01581 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
01582 XEXP (XEXP (from, 0), 0),
01583 REG_NOTES (insn));
01584 }
01585
01586
01587
01588
01589
01590 else if (TARGET_M6811 && SP_REG_P (from))
01591 {
01592 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
01593 from,
01594 REG_NOTES (insn));
01595 }
01596 }
01597
01598 int
01599 m68hc11_total_frame_size ()
01600 {
01601 int size;
01602 int regno;
01603
01604 size = get_frame_size ();
01605 if (current_function_interrupt)
01606 {
01607 size += 3 * HARD_REG_SIZE;
01608 }
01609 if (frame_pointer_needed)
01610 size += HARD_REG_SIZE;
01611
01612 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
01613 if (regs_ever_live[regno] && !call_used_regs[regno])
01614 size += HARD_REG_SIZE;
01615
01616 return size;
01617 }
01618
01619 static void
01620 m68hc11_output_function_epilogue (out, size)
01621 FILE *out ATTRIBUTE_UNUSED;
01622 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
01623 {
01624
01625
01626 z_replacement_completed = 0;
01627 }
01628
01629 void
01630 expand_prologue ()
01631 {
01632 tree func_attr;
01633 int size;
01634 int regno;
01635 rtx scratch;
01636
01637 if (reload_completed != 1)
01638 abort ();
01639
01640 size = get_frame_size ();
01641
01642 create_regs_rtx ();
01643
01644
01645 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
01646 current_function_interrupt = lookup_attribute ("interrupt",
01647 func_attr) != NULL_TREE;
01648 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
01649
01650
01651
01652
01653
01654 if (current_function_args_info.nregs == 2)
01655 scratch = iy_reg;
01656 else
01657 scratch = ix_reg;
01658
01659
01660
01661
01662
01663 if (current_function_interrupt)
01664 {
01665 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
01666 emit_move_after_reload (stack_push_word,
01667 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
01668 emit_move_after_reload (stack_push_word,
01669 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
01670 scratch);
01671 }
01672
01673
01674 if (frame_pointer_needed)
01675 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
01676
01677
01678 if (TARGET_M6812 && (size > 4 || size == 3))
01679 {
01680 emit_insn (gen_addhi3 (stack_pointer_rtx,
01681 stack_pointer_rtx, GEN_INT (-size)));
01682 }
01683 else if (size > 8)
01684 {
01685 rtx insn;
01686
01687 insn = gen_rtx_PARALLEL
01688 (VOIDmode,
01689 gen_rtvec (2,
01690 gen_rtx_SET (VOIDmode,
01691 stack_pointer_rtx,
01692 gen_rtx_PLUS (HImode,
01693 stack_pointer_rtx,
01694 GEN_INT (-size))),
01695 gen_rtx_CLOBBER (VOIDmode, scratch)));
01696 emit_insn (insn);
01697 }
01698 else
01699 {
01700 int i;
01701
01702
01703 for (i = 2; i <= size; i += 2)
01704 emit_move_after_reload (stack_push_word, ix_reg, 0);
01705
01706 if (size & 1)
01707 emit_insn (gen_addhi3 (stack_pointer_rtx,
01708 stack_pointer_rtx, GEN_INT (-1)));
01709 }
01710
01711
01712 if (frame_pointer_needed)
01713 emit_move_after_reload (hard_frame_pointer_rtx,
01714 stack_pointer_rtx, scratch);
01715
01716
01717 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
01718 {
01719 if (regs_ever_live[regno] && !call_used_regs[regno])
01720 {
01721 emit_move_after_reload (stack_push_word,
01722 gen_rtx (REG, HImode, regno), scratch);
01723 }
01724 }
01725 }
01726
01727 void
01728 expand_epilogue ()
01729 {
01730 int size;
01731 register int regno;
01732 int return_size;
01733 rtx scratch;
01734
01735 if (reload_completed != 1)
01736 abort ();
01737
01738 size = get_frame_size ();
01739
01740
01741
01742
01743 if (current_function_return_rtx == 0)
01744 return_size = 0;
01745 else if (GET_CODE (current_function_return_rtx) == MEM)
01746 return_size = HARD_REG_SIZE;
01747 else
01748 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
01749
01750 if (return_size > HARD_REG_SIZE)
01751 scratch = iy_reg;
01752 else
01753 scratch = ix_reg;
01754
01755
01756 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
01757 {
01758 if (regs_ever_live[regno] && !call_used_regs[regno])
01759 {
01760 emit_move_after_reload (gen_rtx (REG, HImode, regno),
01761 stack_pop_word, scratch);
01762 }
01763 }
01764
01765
01766 if (TARGET_M6812 && (size > 4 || size == 3))
01767 {
01768 emit_insn (gen_addhi3 (stack_pointer_rtx,
01769 stack_pointer_rtx, GEN_INT (size)));
01770 }
01771 else if (size > 8)
01772 {
01773 rtx insn;
01774
01775 insn = gen_rtx_PARALLEL
01776 (VOIDmode,
01777 gen_rtvec (2,
01778 gen_rtx_SET (VOIDmode,
01779 stack_pointer_rtx,
01780 gen_rtx_PLUS (HImode,
01781 stack_pointer_rtx,
01782 GEN_INT (size))),
01783 gen_rtx_CLOBBER (VOIDmode, scratch)));
01784 emit_insn (insn);
01785 }
01786 else
01787 {
01788 int i;
01789
01790 for (i = 2; i <= size; i += 2)
01791 emit_move_after_reload (scratch, stack_pop_word, scratch);
01792 if (size & 1)
01793 emit_insn (gen_addhi3 (stack_pointer_rtx,
01794 stack_pointer_rtx, GEN_INT (1)));
01795 }
01796
01797
01798 if (frame_pointer_needed)
01799 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
01800
01801
01802 if (current_function_interrupt)
01803 {
01804 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
01805 stack_pop_word, scratch);
01806 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
01807 stack_pop_word, scratch);
01808 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
01809 }
01810
01811
01812
01813
01814 else if (current_function_trap && return_size != 0)
01815 {
01816 rtx addr_reg = stack_pointer_rtx;
01817
01818 if (!TARGET_M6812)
01819 {
01820 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
01821 addr_reg = scratch;
01822 }
01823 emit_move_after_reload (gen_rtx (MEM, HImode,
01824 gen_rtx (PLUS, HImode, addr_reg,
01825 GEN_INT (1))), d_reg, 0);
01826 if (return_size > HARD_REG_SIZE)
01827 emit_move_after_reload (gen_rtx (MEM, HImode,
01828 gen_rtx (PLUS, HImode, addr_reg,
01829 GEN_INT (3))), ix_reg, 0);
01830 }
01831
01832 emit_jump_insn (gen_return ());
01833 }
01834
01835
01836
01837
01838
01839
01840 rtx
01841 m68hc11_gen_lowpart (mode, x)
01842 enum machine_mode mode;
01843 rtx x;
01844 {
01845
01846
01847
01848 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
01849 {
01850 return gen_rtx (MEM, mode, XEXP (x, 0));
01851 }
01852
01853
01854
01855
01856
01857 if (GET_CODE (x) == CONST_DOUBLE)
01858 {
01859 long l[2];
01860
01861 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
01862 {
01863 REAL_VALUE_TYPE r;
01864
01865 if (GET_MODE (x) == SFmode)
01866 {
01867 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
01868 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
01869 }
01870 else
01871 {
01872 rtx first, second;
01873
01874 split_double (x, &first, &second);
01875 return second;
01876 }
01877 if (mode == SImode)
01878 return GEN_INT (l[0]);
01879
01880 return GEN_INT (trunc_int_for_mode (l[0], HImode));
01881 }
01882 else
01883 {
01884 l[0] = CONST_DOUBLE_LOW (x);
01885 }
01886 if (mode == SImode)
01887 return GEN_INT (l[0]);
01888 else if (mode == HImode && GET_MODE (x) == SFmode)
01889 return GEN_INT (trunc_int_for_mode (l[0], HImode));
01890 else
01891 abort ();
01892 }
01893
01894 if (mode == QImode && D_REG_P (x))
01895 return gen_rtx (REG, mode, HARD_B_REGNUM);
01896
01897
01898 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
01899 {
01900 if (mode == SImode)
01901 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
01902 else if (mode == HImode)
01903 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
01904 else
01905 abort ();
01906 }
01907 x = gen_lowpart (mode, x);
01908
01909
01910
01911
01912 if (GET_CODE (x) == MEM)
01913 x = copy_rtx (x);
01914 return x;
01915 }
01916
01917 rtx
01918 m68hc11_gen_highpart (mode, x)
01919 enum machine_mode mode;
01920 rtx x;
01921 {
01922
01923
01924
01925 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
01926 {
01927 return gen_rtx (MEM, mode, XEXP (x, 0));
01928 }
01929
01930
01931
01932
01933
01934 if (GET_CODE (x) == CONST_DOUBLE)
01935 {
01936 long l[2];
01937
01938 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
01939 {
01940 REAL_VALUE_TYPE r;
01941
01942 if (GET_MODE (x) == SFmode)
01943 {
01944 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
01945 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
01946 }
01947 else
01948 {
01949 rtx first, second;
01950
01951 split_double (x, &first, &second);
01952 return first;
01953 }
01954 if (mode == SImode)
01955 return GEN_INT (l[1]);
01956
01957 return GEN_INT (trunc_int_for_mode ((l[1] >> 16), HImode));
01958 }
01959 else
01960 {
01961 l[1] = CONST_DOUBLE_HIGH (x);
01962 }
01963
01964 if (mode == SImode)
01965 return GEN_INT (l[1]);
01966 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
01967 return GEN_INT (trunc_int_for_mode ((l[0] >> 16), HImode));
01968 else
01969 abort ();
01970 }
01971 if (GET_CODE (x) == CONST_INT)
01972 {
01973 HOST_WIDE_INT val = INTVAL (x);
01974
01975 if (mode == QImode)
01976 {
01977 return GEN_INT (trunc_int_for_mode (val >> 8, QImode));
01978 }
01979 else if (mode == HImode)
01980 {
01981 return GEN_INT (trunc_int_for_mode (val >> 16, HImode));
01982 }
01983 }
01984 if (mode == QImode && D_REG_P (x))
01985 return gen_rtx (REG, mode, HARD_A_REGNUM);
01986
01987
01988
01989
01990
01991 if (mode == QImode && S_REG_P (x))
01992 {
01993 int pos;
01994
01995
01996
01997 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
01998 return gen_rtx (MEM, QImode,
01999 gen_rtx (SYMBOL_REF, Pmode,
02000 ®_names[REGNO (x)][pos]));
02001 }
02002
02003
02004 if (GET_CODE (x) == SUBREG)
02005 {
02006 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
02007 }
02008 if (GET_CODE (x) == REG)
02009 {
02010 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
02011 return gen_rtx (REG, mode, REGNO (x));
02012 else
02013 return gen_rtx_SUBREG (mode, x, 0);
02014 }
02015
02016 if (GET_CODE (x) == MEM)
02017 {
02018 x = change_address (x, mode, 0);
02019
02020
02021
02022
02023 if (GET_CODE (x) == MEM)
02024 x = copy_rtx (x);
02025 return x;
02026 }
02027 abort ();
02028 }
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038 int
02039 dead_register_here (x, reg)
02040 rtx x;
02041 rtx reg;
02042 {
02043 rtx x_reg;
02044 rtx p;
02045
02046 if (D_REG_P (reg))
02047 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
02048 else
02049 x_reg = 0;
02050
02051 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
02052 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
02053 {
02054 rtx body;
02055
02056 body = PATTERN (p);
02057
02058 if (GET_CODE (body) == CALL_INSN)
02059 break;
02060 if (GET_CODE (body) == JUMP_INSN)
02061 break;
02062
02063 if (GET_CODE (body) == SET)
02064 {
02065 rtx dst = XEXP (body, 0);
02066
02067 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
02068 break;
02069 if (x_reg && rtx_equal_p (dst, x_reg))
02070 break;
02071
02072 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
02073 return 1;
02074 }
02075 else if (reg_mentioned_p (reg, p)
02076 || (x_reg && reg_mentioned_p (x_reg, p)))
02077 break;
02078 }
02079
02080
02081
02082 for (p = x ; p; p = NEXT_INSN (p))
02083 {
02084 rtx body;
02085
02086 if (GET_CODE (p) == CODE_LABEL
02087 || GET_CODE (p) == JUMP_INSN
02088 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
02089 break;
02090
02091 if (GET_CODE (p) != INSN)
02092 continue;
02093
02094 body = PATTERN (p);
02095 if (GET_CODE (body) == SET)
02096 {
02097 rtx src = XEXP (body, 1);
02098 rtx dst = XEXP (body, 0);
02099
02100 if (GET_CODE (dst) == REG
02101 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
02102 return 1;
02103 }
02104
02105
02106 if (reg_mentioned_p (reg, p)
02107 || (x_reg != 0 && GET_MODE (p) == SImode
02108 && reg_mentioned_p (x_reg, p)))
02109 break;
02110 }
02111 return p == 0 ? 1 : 0;
02112 }
02113
02114
02115
02116
02117
02118 static void
02119 asm_print_register (file, regno)
02120 FILE *file;
02121 int regno;
02122 {
02123 const char *name = reg_names[regno];
02124
02125 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
02126 name++;
02127
02128 asm_fprintf (file, "%s", name);
02129 }
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163 void
02164 print_operand (file, op, letter)
02165 FILE *file;
02166 rtx op;
02167 int letter;
02168 {
02169 if (letter == 't')
02170 {
02171 asm_print_register (file, SOFT_TMP_REGNUM);
02172 return;
02173 }
02174 else if (letter == 'T')
02175 {
02176 asm_print_register (file, SOFT_TMP_REGNUM);
02177 asm_fprintf (file, "+1");
02178 return;
02179 }
02180 else if (letter == '#')
02181 {
02182 asm_fprintf (file, "%0I");
02183 }
02184
02185 if (GET_CODE (op) == REG)
02186 {
02187 if (letter == 'b' && S_REG_P (op))
02188 {
02189 asm_print_register (file, REGNO (op));
02190 asm_fprintf (file, "+1");
02191 }
02192 else
02193 {
02194 asm_print_register (file, REGNO (op));
02195 }
02196 return;
02197 }
02198
02199 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
02200 {
02201 if (letter == 'b')
02202 asm_fprintf (file, "%0I%%lo(");
02203 else
02204 asm_fprintf (file, "%0I%%hi(");
02205
02206 output_addr_const (file, op);
02207 asm_fprintf (file, ")");
02208 return;
02209 }
02210
02211
02212
02213 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
02214 {
02215 if (letter == 'b')
02216 {
02217 op = m68hc11_gen_lowpart (QImode, op);
02218 }
02219 else if (letter == 'h')
02220 {
02221 op = m68hc11_gen_highpart (QImode, op);
02222 }
02223 }
02224
02225 if (GET_CODE (op) == MEM)
02226 {
02227 rtx base = XEXP (op, 0);
02228 switch (GET_CODE (base))
02229 {
02230 case PRE_DEC:
02231 if (TARGET_M6812)
02232 {
02233 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
02234 asm_print_register (file, REGNO (XEXP (base, 0)));
02235 }
02236 else
02237 abort ();
02238 break;
02239
02240 case POST_DEC:
02241 if (TARGET_M6812)
02242 {
02243 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
02244 asm_print_register (file, REGNO (XEXP (base, 0)));
02245 asm_fprintf (file, "-");
02246 }
02247 else
02248 abort ();
02249 break;
02250
02251 case POST_INC:
02252 if (TARGET_M6812)
02253 {
02254 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
02255 asm_print_register (file, REGNO (XEXP (base, 0)));
02256 asm_fprintf (file, "+");
02257 }
02258 else
02259 abort ();
02260 break;
02261
02262 case PRE_INC:
02263 if (TARGET_M6812)
02264 {
02265 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
02266 asm_print_register (file, REGNO (XEXP (base, 0)));
02267 }
02268 else
02269 abort ();
02270 break;
02271
02272 default:
02273 output_address (base);
02274 break;
02275 }
02276 }
02277 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
02278 {
02279 REAL_VALUE_TYPE r;
02280 long l;
02281
02282 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
02283 REAL_VALUE_TO_TARGET_SINGLE (r, l);
02284 asm_fprintf (file, "%I0x%lx", l);
02285 }
02286 else if (GET_CODE (op) == CONST_DOUBLE
02287 && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))
02288 {
02289 REAL_VALUE_TYPE r;
02290 char dstr[30];
02291
02292 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
02293 REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);
02294 asm_fprintf (file, "%I0r%s", dstr);
02295 }
02296 else
02297 {
02298 int need_parenthesize = 0;
02299
02300 if (letter != 'i')
02301 asm_fprintf (file, "%0I");
02302 else
02303 need_parenthesize = must_parenthesize (op);
02304
02305 if (need_parenthesize)
02306 asm_fprintf (file, "(");
02307
02308 output_addr_const (file, op);
02309 if (need_parenthesize)
02310 asm_fprintf (file, ")");
02311 }
02312 }
02313
02314
02315
02316
02317 static int
02318 must_parenthesize (op)
02319 rtx op;
02320 {
02321 const char *name;
02322
02323 switch (GET_CODE (op))
02324 {
02325 case SYMBOL_REF:
02326 name = XSTR (op, 0);
02327
02328
02329 return (strcasecmp (name, "a") == 0
02330 || strcasecmp (name, "b") == 0
02331 || strcasecmp (name, "d") == 0
02332 || strcasecmp (name, "x") == 0
02333 || strcasecmp (name, "y") == 0
02334 || strcasecmp (name, "ix") == 0
02335 || strcasecmp (name, "iy") == 0
02336 || strcasecmp (name, "pc") == 0
02337 || strcasecmp (name, "sp") == 0
02338 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
02339
02340 case PLUS:
02341 case MINUS:
02342 return must_parenthesize (XEXP (op, 0))
02343 || must_parenthesize (XEXP (op, 1));
02344
02345 case MEM:
02346 case CONST:
02347 case ZERO_EXTEND:
02348 case SIGN_EXTEND:
02349 return must_parenthesize (XEXP (op, 0));
02350
02351 case CONST_DOUBLE:
02352 case CONST_INT:
02353 case LABEL_REF:
02354 case CODE_LABEL:
02355 default:
02356 return 0;
02357 }
02358 }
02359
02360
02361
02362
02363
02364 void
02365 print_operand_address (file, addr)
02366 FILE *file;
02367 rtx addr;
02368 {
02369 rtx base;
02370 rtx offset;
02371 int need_parenthesis = 0;
02372
02373 switch (GET_CODE (addr))
02374 {
02375 case REG:
02376 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
02377 abort ();
02378
02379 asm_fprintf (file, "0,");
02380 asm_print_register (file, REGNO (addr));
02381 break;
02382
02383 case MEM:
02384 base = XEXP (addr, 0);
02385 switch (GET_CODE (base))
02386 {
02387 case PRE_DEC:
02388 if (TARGET_M6812)
02389 {
02390 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
02391 asm_print_register (file, REGNO (XEXP (base, 0)));
02392 }
02393 else
02394 abort ();
02395 break;
02396
02397 case POST_DEC:
02398 if (TARGET_M6812)
02399 {
02400 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
02401 asm_print_register (file, REGNO (XEXP (base, 0)));
02402 asm_fprintf (file, "-");
02403 }
02404 else
02405 abort ();
02406 break;
02407
02408 case POST_INC:
02409 if (TARGET_M6812)
02410 {
02411 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
02412 asm_print_register (file, REGNO (XEXP (base, 0)));
02413 asm_fprintf (file, "+");
02414 }
02415 else
02416 abort ();
02417 break;
02418
02419 case PRE_INC:
02420 if (TARGET_M6812)
02421 {
02422 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
02423 asm_print_register (file, REGNO (XEXP (base, 0)));
02424 }
02425 else
02426 abort ();
02427 break;
02428
02429 default:
02430 need_parenthesis = must_parenthesize (base);
02431 if (need_parenthesis)
02432 asm_fprintf (file, "(");
02433
02434 output_addr_const (file, base);
02435 if (need_parenthesis)
02436 asm_fprintf (file, ")");
02437 break;
02438 }
02439 break;
02440
02441 case PLUS:
02442 base = XEXP (addr, 0);
02443 offset = XEXP (addr, 1);
02444 if (!G_REG_P (base) && G_REG_P (offset))
02445 {
02446 base = XEXP (addr, 1);
02447 offset = XEXP (addr, 0);
02448 }
02449 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
02450 {
02451 need_parenthesis = must_parenthesize (addr);
02452
02453 if (need_parenthesis)
02454 asm_fprintf (file, "(");
02455
02456 output_addr_const (file, base);
02457 asm_fprintf (file, "+");
02458 output_addr_const (file, offset);
02459 if (need_parenthesis)
02460 asm_fprintf (file, ")");
02461 }
02462 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
02463 {
02464 if (REG_P (offset))
02465 {
02466 if (TARGET_M6812)
02467 {
02468 asm_print_register (file, REGNO (offset));
02469 asm_fprintf (file, ",");
02470 asm_print_register (file, REGNO (base));
02471 }
02472 else
02473 abort ();
02474 }
02475 else
02476 {
02477 need_parenthesis = must_parenthesize (offset);
02478 if (need_parenthesis)
02479 asm_fprintf (file, "(");
02480
02481 output_addr_const (file, offset);
02482 if (need_parenthesis)
02483 asm_fprintf (file, ")");
02484 asm_fprintf (file, ",");
02485 asm_print_register (file, REGNO (base));
02486 }
02487 }
02488 else
02489 {
02490 abort ();
02491 }
02492 break;
02493
02494 default:
02495 if (GET_CODE (addr) == CONST_INT
02496 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
02497 {
02498 asm_fprintf (file, "%d", INTVAL (addr));
02499 }
02500 else
02501 {
02502 need_parenthesis = must_parenthesize (addr);
02503 if (need_parenthesis)
02504 asm_fprintf (file, "(");
02505
02506 output_addr_const (file, addr);
02507 if (need_parenthesis)
02508 asm_fprintf (file, ")");
02509 }
02510 break;
02511 }
02512 }
02513
02514
02515
02516
02517 static rtx
02518 m68hc11_expand_compare (code, op0, op1)
02519 enum rtx_code code;
02520 rtx op0, op1;
02521 {
02522 rtx ret = 0;
02523
02524 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
02525 abort ();
02526 else
02527 {
02528 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
02529 gen_rtx_COMPARE (VOIDmode, op0, op1)));
02530 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
02531 }
02532
02533 return ret;
02534 }
02535
02536 rtx
02537 m68hc11_expand_compare_and_branch (code, op0, op1, label)
02538 enum rtx_code code;
02539 rtx op0, op1, label;
02540 {
02541 rtx tmp;
02542
02543 switch (GET_MODE (op0))
02544 {
02545 case QImode:
02546 case HImode:
02547 tmp = m68hc11_expand_compare (code, op0, op1);
02548 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
02549 gen_rtx_LABEL_REF (VOIDmode, label),
02550 pc_rtx);
02551 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
02552 return 0;
02553 #if 0
02554
02555
02556 case SFmode:
02557 case DFmode:
02558
02559
02560 {
02561 rtvec vec;
02562 int use_fcomi;
02563
02564 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
02565 &m68hc11_compare_op1);
02566
02567 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
02568 m68hc11_compare_op0, m68hc11_compare_op1);
02569 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
02570 gen_rtx_LABEL_REF (VOIDmode, label),
02571 pc_rtx);
02572 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
02573
02574 use_fcomi = ix86_use_fcomi_compare (code);
02575 vec = rtvec_alloc (3 + !use_fcomi);
02576 RTVEC_ELT (vec, 0) = tmp;
02577 RTVEC_ELT (vec, 1)
02578 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
02579 RTVEC_ELT (vec, 2)
02580 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
02581 if (!use_fcomi)
02582 RTVEC_ELT (vec, 3)
02583 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
02584
02585 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
02586 return;
02587 }
02588 #endif
02589
02590 case SImode:
02591
02592 {
02593 rtx lo[2], hi[2], label2;
02594 enum rtx_code code1, code2, code3;
02595
02596 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
02597 {
02598 tmp = op0;
02599 op0 = op1;
02600 op1 = tmp;
02601 code = swap_condition (code);
02602 }
02603 lo[0] = m68hc11_gen_lowpart (HImode, op0);
02604 lo[1] = m68hc11_gen_lowpart (HImode, op1);
02605 hi[0] = m68hc11_gen_highpart (HImode, op0);
02606 hi[1] = m68hc11_gen_highpart (HImode, op1);
02607
02608
02609
02610
02611 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
02612 && (code == LT || code == LTU))
02613 {
02614 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
02615 label);
02616 }
02617
02618
02619
02620 label2 = gen_label_rtx ();
02621
02622 code1 = code;
02623 code2 = swap_condition (code);
02624 code3 = unsigned_condition (code);
02625
02626 switch (code)
02627 {
02628 case LT:
02629 case GT:
02630 case LTU:
02631 case GTU:
02632 break;
02633
02634 case LE:
02635 code1 = LT;
02636 code2 = GT;
02637 break;
02638 case GE:
02639 code1 = GT;
02640 code2 = LT;
02641 break;
02642 case LEU:
02643 code1 = LTU;
02644 code2 = GTU;
02645 break;
02646 case GEU:
02647 code1 = GTU;
02648 code2 = LTU;
02649 break;
02650
02651 case EQ:
02652 code1 = NIL;
02653 code2 = NE;
02654 break;
02655 case NE:
02656 code2 = NIL;
02657 break;
02658
02659 default:
02660 abort ();
02661 }
02662
02663
02664
02665
02666
02667
02668
02669
02670 if (code1 != NIL)
02671 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
02672 if (code2 != NIL)
02673 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
02674
02675 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
02676
02677 if (code2 != NIL)
02678 emit_label (label2);
02679 return 0;
02680 }
02681
02682 default:
02683 abort ();
02684 }
02685 return 0;
02686 }
02687
02688
02689
02690 static int
02691 autoinc_mode (x)
02692 rtx x;
02693 {
02694 if (GET_CODE (x) != MEM)
02695 return CONST;
02696
02697 x = XEXP (x, 0);
02698 if (GET_CODE (x) == PRE_INC
02699 || GET_CODE (x) == PRE_DEC
02700 || GET_CODE (x) == POST_INC
02701 || GET_CODE (x) == POST_DEC)
02702 return GET_CODE (x);
02703
02704 return CONST;
02705 }
02706
02707 static int
02708 m68hc11_make_autoinc_notes (x, data)
02709 rtx *x;
02710 void *data;
02711 {
02712 rtx insn;
02713
02714 switch (GET_CODE (*x))
02715 {
02716 case PRE_DEC:
02717 case PRE_INC:
02718 case POST_DEC:
02719 case POST_INC:
02720 insn = (rtx) data;
02721 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
02722 REG_NOTES (insn));
02723 return -1;
02724
02725 default:
02726 return 0;
02727 }
02728 }
02729
02730
02731
02732
02733 void
02734 m68hc11_split_move (to, from, scratch)
02735 rtx to, from, scratch;
02736 {
02737 rtx low_to, low_from;
02738 rtx high_to, high_from;
02739 rtx insn;
02740 enum machine_mode mode;
02741 int offset = 0;
02742 int autoinc_from = autoinc_mode (from);
02743 int autoinc_to = autoinc_mode (to);
02744
02745 mode = GET_MODE (to);
02746
02747
02748
02749
02750 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
02751 {
02752 rtx reg;
02753 int code;
02754
02755
02756
02757 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
02758 {
02759 code = GET_CODE (XEXP (from, 0));
02760 reg = XEXP (XEXP (from, 0), 0);
02761 offset = GET_MODE_SIZE (GET_MODE (from));
02762 if (code == POST_DEC)
02763 offset = -offset;
02764
02765 if (code == PRE_INC)
02766 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02767
02768 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
02769 if (code == POST_DEC)
02770 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02771 return;
02772 }
02773
02774
02775 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
02776 {
02777 code = GET_CODE (XEXP (to, 0));
02778 reg = XEXP (XEXP (to, 0), 0);
02779 offset = GET_MODE_SIZE (GET_MODE (to));
02780 if (code == POST_DEC)
02781 offset = -offset;
02782
02783 if (code == PRE_INC)
02784 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02785
02786 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
02787 if (code == POST_DEC)
02788 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02789 return;
02790 }
02791
02792
02793
02794 if ((autoinc_to != autoinc_from
02795 && autoinc_to != CONST && autoinc_from != CONST)
02796
02797
02798
02799 || (autoinc_to != CONST
02800 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
02801 && !IS_STACK_PUSH (to)))
02802 {
02803
02804 code = GET_CODE (XEXP (to, 0));
02805 reg = XEXP (XEXP (to, 0), 0);
02806 offset = GET_MODE_SIZE (GET_MODE (to));
02807 if (code == PRE_DEC || code == POST_DEC)
02808 offset = -offset;
02809
02810 if (code == PRE_DEC || code == PRE_INC)
02811 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02812 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
02813 if (code == POST_DEC || code == POST_INC)
02814 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02815
02816 return;
02817 }
02818
02819
02820
02821 if (autoinc_from != CONST
02822 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
02823 && !IS_STACK_PUSH (to))
02824 {
02825
02826 code = GET_CODE (XEXP (from, 0));
02827 reg = XEXP (XEXP (from, 0), 0);
02828 offset = GET_MODE_SIZE (GET_MODE (from));
02829 if (code == PRE_DEC || code == POST_DEC)
02830 offset = -offset;
02831
02832 if (code == PRE_DEC || code == PRE_INC)
02833 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02834 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
02835 if (code == POST_DEC || code == POST_INC)
02836 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
02837
02838 return;
02839 }
02840 }
02841
02842 if (GET_MODE_SIZE (mode) == 8)
02843 mode = SImode;
02844 else if (GET_MODE_SIZE (mode) == 4)
02845 mode = HImode;
02846 else
02847 mode = QImode;
02848
02849 if (TARGET_M6812
02850 && IS_STACK_PUSH (to)
02851 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
02852 {
02853 if (mode == SImode)
02854 {
02855 offset = 4;
02856 }
02857 else if (mode == HImode)
02858 {
02859 offset = 2;
02860 }
02861 else
02862 offset = 0;
02863 }
02864
02865 low_to = m68hc11_gen_lowpart (mode, to);
02866 high_to = m68hc11_gen_highpart (mode, to);
02867
02868 low_from = m68hc11_gen_lowpart (mode, from);
02869 if (mode == SImode && GET_CODE (from) == CONST_INT)
02870 {
02871 if (INTVAL (from) >= 0)
02872 high_from = const0_rtx;
02873 else
02874 high_from = constm1_rtx;
02875 }
02876 else
02877 high_from = m68hc11_gen_highpart (mode, from);
02878
02879 if (offset)
02880 {
02881 high_from = adjust_address (high_from, mode, offset);
02882 low_from = high_from;
02883 }
02884
02885
02886
02887
02888 if (TARGET_M6812
02889 && GET_MODE_SIZE (mode) >= 2
02890 && autoinc_from != autoinc_to
02891 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
02892 {
02893 rtx swap;
02894
02895 swap = low_to;
02896 low_to = high_to;
02897 high_to = swap;
02898
02899 swap = low_from;
02900 low_from = high_from;
02901 high_from = swap;
02902 }
02903 if (mode == SImode)
02904 {
02905 m68hc11_split_move (low_to, low_from, scratch);
02906 m68hc11_split_move (high_to, high_from, scratch);
02907 }
02908 else if (H_REG_P (to) || H_REG_P (from)
02909 || (low_from == const0_rtx
02910 && high_from == const0_rtx
02911 && ! push_operand (to, GET_MODE (to))
02912 && ! H_REG_P (scratch))
02913 || (TARGET_M6812
02914 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
02915 || m68hc11_small_indexed_indirect_p (from,
02916 GET_MODE (from)))
02917 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
02918 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
02919 {
02920 insn = emit_move_insn (low_to, low_from);
02921 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
02922
02923 insn = emit_move_insn (high_to, high_from);
02924 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
02925 }
02926 else
02927 {
02928 insn = emit_move_insn (scratch, low_from);
02929 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
02930 insn = emit_move_insn (low_to, scratch);
02931 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
02932
02933 insn = emit_move_insn (scratch, high_from);
02934 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
02935 insn = emit_move_insn (high_to, scratch);
02936 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
02937 }
02938 }
02939
02940 static rtx
02941 simplify_logical (mode, code, operand, result)
02942 enum machine_mode mode;
02943 int code;
02944 rtx operand;
02945 rtx *result;
02946 {
02947 int val;
02948 int mask;
02949
02950 *result = 0;
02951 if (GET_CODE (operand) != CONST_INT)
02952 return operand;
02953
02954 if (mode == HImode)
02955 mask = 0x0ffff;
02956 else
02957 mask = 0x0ff;
02958
02959 val = INTVAL (operand);
02960 switch (code)
02961 {
02962 case IOR:
02963 if ((val & mask) == 0)
02964 return 0;
02965 if ((val & mask) == mask)
02966 *result = constm1_rtx;
02967 break;
02968
02969 case AND:
02970 if ((val & mask) == 0)
02971 *result = const0_rtx;
02972 if ((val & mask) == mask)
02973 return 0;
02974 break;
02975
02976 case XOR:
02977 if ((val & mask) == 0)
02978 return 0;
02979 break;
02980 }
02981 return operand;
02982 }
02983
02984 static void
02985 m68hc11_emit_logical (mode, code, operands)
02986 enum machine_mode mode;
02987 int code;
02988 rtx *operands;
02989 {
02990 rtx result;
02991 int need_copy;
02992
02993 need_copy = (rtx_equal_p (operands[0], operands[1])
02994 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
02995
02996 operands[1] = simplify_logical (mode, code, operands[1], &result);
02997 operands[2] = simplify_logical (mode, code, operands[2], &result);
02998
02999 if (result && GET_CODE (result) == CONST_INT)
03000 {
03001 if (!H_REG_P (operands[0]) && operands[3]
03002 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
03003 {
03004 emit_move_insn (operands[3], result);
03005 emit_move_insn (operands[0], operands[3]);
03006 }
03007 else
03008 {
03009 emit_move_insn (operands[0], result);
03010 }
03011 }
03012 else if (operands[1] != 0 && operands[2] != 0)
03013 {
03014 rtx insn;
03015
03016 if (!H_REG_P (operands[0]) && operands[3])
03017 {
03018 emit_move_insn (operands[3], operands[1]);
03019 emit_insn (gen_rtx (SET, mode,
03020 operands[3],
03021 gen_rtx (code, mode,
03022 operands[3], operands[2])));
03023 insn = emit_move_insn (operands[0], operands[3]);
03024 }
03025 else
03026 {
03027 insn = emit_insn (gen_rtx (SET, mode,
03028 operands[0],
03029 gen_rtx (code, mode,
03030 operands[0], operands[2])));
03031 }
03032 }
03033
03034
03035 else if (need_copy)
03036 {
03037 rtx src;
03038
03039 if (GET_CODE (operands[1]) == CONST_INT)
03040 src = operands[2];
03041 else
03042 src = operands[1];
03043
03044 if (!H_REG_P (operands[0]) && !H_REG_P (src))
03045 {
03046 emit_move_insn (operands[3], src);
03047 emit_move_insn (operands[0], operands[3]);
03048 }
03049 else
03050 {
03051 emit_move_insn (operands[0], src);
03052 }
03053 }
03054 }
03055
03056 void
03057 m68hc11_split_logical (mode, code, operands)
03058 enum machine_mode mode;
03059 int code;
03060 rtx *operands;
03061 {
03062 rtx low[4];
03063 rtx high[4];
03064
03065 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
03066 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
03067 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
03068
03069 high[0] = m68hc11_gen_highpart (mode, operands[0]);
03070
03071 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
03072 {
03073 if (INTVAL (operands[1]) >= 0)
03074 high[1] = const0_rtx;
03075 else
03076 high[1] = constm1_rtx;
03077 }
03078 else
03079 high[1] = m68hc11_gen_highpart (mode, operands[1]);
03080
03081 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
03082 {
03083 if (INTVAL (operands[2]) >= 0)
03084 high[2] = const0_rtx;
03085 else
03086 high[2] = constm1_rtx;
03087 }
03088 else
03089 high[2] = m68hc11_gen_highpart (mode, operands[2]);
03090
03091 low[3] = operands[3];
03092 high[3] = operands[3];
03093 if (mode == SImode)
03094 {
03095 m68hc11_split_logical (HImode, code, low);
03096 m68hc11_split_logical (HImode, code, high);
03097 return;
03098 }
03099
03100 m68hc11_emit_logical (mode, code, low);
03101 m68hc11_emit_logical (mode, code, high);
03102 }
03103
03104
03105
03106
03107 void
03108 m68hc11_output_swap (insn, operands)
03109 rtx insn ATTRIBUTE_UNUSED;
03110 rtx operands[];
03111 {
03112
03113
03114
03115
03116
03117
03118 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
03119 {
03120 if (cc_prev_status.value1 != 0
03121 && (D_REG_P (cc_prev_status.value1)
03122 || X_REG_P (cc_prev_status.value1)))
03123 {
03124 cc_status = cc_prev_status;
03125 if (D_REG_P (cc_status.value1))
03126 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
03127 HARD_X_REGNUM);
03128 else
03129 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
03130 HARD_D_REGNUM);
03131 }
03132 else
03133 CC_STATUS_INIT;
03134
03135 output_asm_insn ("xgdx", operands);
03136 }
03137 else
03138 {
03139 if (cc_prev_status.value1 != 0
03140 && (D_REG_P (cc_prev_status.value1)
03141 || Y_REG_P (cc_prev_status.value1)))
03142 {
03143 cc_status = cc_prev_status;
03144 if (D_REG_P (cc_status.value1))
03145 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
03146 HARD_Y_REGNUM);
03147 else
03148 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
03149 HARD_D_REGNUM);
03150 }
03151 else
03152 CC_STATUS_INIT;
03153
03154 output_asm_insn ("xgdy", operands);
03155 }
03156 }
03157
03158
03159
03160
03161 int
03162 next_insn_test_reg (insn, reg)
03163 rtx insn;
03164 rtx reg;
03165 {
03166 rtx body;
03167
03168 insn = next_nonnote_insn (insn);
03169 if (GET_CODE (insn) != INSN)
03170 return 0;
03171
03172 body = PATTERN (insn);
03173 if (sets_cc0_p (body) != 1)
03174 return 0;
03175
03176 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
03177 return 0;
03178
03179 return 1;
03180 }
03181
03182
03183
03184 void
03185 m68hc11_gen_movhi (insn, operands)
03186 rtx insn;
03187 rtx *operands;
03188 {
03189 int reg;
03190
03191
03192
03193
03194 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
03195 {
03196 cc_status = cc_prev_status;
03197 return;
03198 }
03199
03200 if (TARGET_M6812)
03201 {
03202 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
03203 {
03204 cc_status = cc_prev_status;
03205 switch (REGNO (operands[1]))
03206 {
03207 case HARD_X_REGNUM:
03208 case HARD_Y_REGNUM:
03209 case HARD_D_REGNUM:
03210 output_asm_insn ("psh%1", operands);
03211 break;
03212 case HARD_SP_REGNUM:
03213 output_asm_insn ("sts\t-2,sp", operands);
03214 break;
03215 default:
03216 abort ();
03217 }
03218 return;
03219 }
03220 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
03221 {
03222 cc_status = cc_prev_status;
03223 switch (REGNO (operands[0]))
03224 {
03225 case HARD_X_REGNUM:
03226 case HARD_Y_REGNUM:
03227 case HARD_D_REGNUM:
03228 output_asm_insn ("pul%0", operands);
03229 break;
03230 default:
03231 abort ();
03232 }
03233 return;
03234 }
03235 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
03236 {
03237 m68hc11_notice_keep_cc (operands[0]);
03238 output_asm_insn ("tfr\t%1,%0", operands);
03239 }
03240 else if (H_REG_P (operands[0]))
03241 {
03242 if (SP_REG_P (operands[0]))
03243 output_asm_insn ("lds\t%1", operands);
03244 else
03245 output_asm_insn ("ld%0\t%1", operands);
03246 }
03247 else if (H_REG_P (operands[1]))
03248 {
03249 if (SP_REG_P (operands[1]))
03250 output_asm_insn ("sts\t%0", operands);
03251 else
03252 output_asm_insn ("st%1\t%0", operands);
03253 }
03254 else
03255 {
03256 rtx from = operands[1];
03257 rtx to = operands[0];
03258
03259 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
03260 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
03261 || (m68hc11_register_indirect_p (to, GET_MODE (to))
03262 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
03263 {
03264 rtx ops[3];
03265
03266 if (operands[2])
03267 {
03268 ops[0] = operands[2];
03269 ops[1] = from;
03270 ops[2] = 0;
03271 m68hc11_gen_movhi (insn, ops);
03272 ops[0] = to;
03273 ops[1] = operands[2];
03274 m68hc11_gen_movhi (insn, ops);
03275 }
03276 else
03277 {
03278
03279 fatal_insn ("move insn not handled", insn);
03280 }
03281 }
03282 else
03283 {
03284 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
03285 {
03286 output_asm_insn ("clr\t%h0", operands);
03287 output_asm_insn ("clr\t%b0", operands);
03288 }
03289 else
03290 {
03291 m68hc11_notice_keep_cc (operands[0]);
03292 output_asm_insn ("movw\t%1,%0", operands);
03293 }
03294 }
03295 }
03296 return;
03297 }
03298
03299 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
03300 {
03301 cc_status = cc_prev_status;
03302 switch (REGNO (operands[0]))
03303 {
03304 case HARD_X_REGNUM:
03305 case HARD_Y_REGNUM:
03306 output_asm_insn ("pul%0", operands);
03307 break;
03308 case HARD_D_REGNUM:
03309 output_asm_insn ("pula", operands);
03310 output_asm_insn ("pulb", operands);
03311 break;
03312 default:
03313 abort ();
03314 }
03315 return;
03316 }
03317
03318
03319
03320 if (H_REG_P (operands[0]))
03321 {
03322 switch (REGNO (operands[0]))
03323 {
03324 case HARD_D_REGNUM:
03325 if (X_REG_P (operands[1]))
03326 {
03327 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
03328 {
03329 m68hc11_output_swap (insn, operands);
03330 }
03331 else if (next_insn_test_reg (insn, operands[0]))
03332 {
03333 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
03334 }
03335 else
03336 {
03337 m68hc11_notice_keep_cc (operands[0]);
03338 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
03339 }
03340 }
03341 else if (Y_REG_P (operands[1]))
03342 {
03343 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
03344 {
03345 m68hc11_output_swap (insn, operands);
03346 }
03347 else
03348 {
03349
03350 output_asm_insn ("sty\t%t1", operands);
03351 output_asm_insn ("ldd\t%t1", operands);
03352 }
03353 }
03354 else if (SP_REG_P (operands[1]))
03355 {
03356 CC_STATUS_INIT;
03357 if (ix_reg == 0)
03358 create_regs_rtx ();
03359 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
03360 output_asm_insn ("xgdx", operands);
03361 output_asm_insn ("tsx", operands);
03362 output_asm_insn ("xgdx", operands);
03363 }
03364 else if (IS_STACK_POP (operands[1]))
03365 {
03366 output_asm_insn ("pula\n\tpulb", operands);
03367 }
03368 else if (GET_CODE (operands[1]) == CONST_INT
03369 && INTVAL (operands[1]) == 0)
03370 {
03371 output_asm_insn ("clra\n\tclrb", operands);
03372 }
03373 else
03374 {
03375 output_asm_insn ("ldd\t%1", operands);
03376 }
03377 break;
03378
03379 case HARD_X_REGNUM:
03380 if (D_REG_P (operands[1]))
03381 {
03382 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
03383 {
03384 m68hc11_output_swap (insn, operands);
03385 }
03386 else if (next_insn_test_reg (insn, operands[0]))
03387 {
03388 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
03389 }
03390 else
03391 {
03392 m68hc11_notice_keep_cc (operands[0]);
03393 output_asm_insn ("pshb", operands);
03394 output_asm_insn ("psha", operands);
03395 output_asm_insn ("pulx", operands);
03396 }
03397 }
03398 else if (Y_REG_P (operands[1]))
03399 {
03400
03401
03402 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
03403 && dead_register_here (insn, d_reg))
03404 {
03405 output_asm_insn ("xgdy", operands);
03406 output_asm_insn ("xgdx", operands);
03407 CC_STATUS_INIT;
03408 }
03409 else
03410 {
03411 output_asm_insn ("sty\t%t1", operands);
03412 output_asm_insn ("ldx\t%t1", operands);
03413 }
03414 }
03415 else if (SP_REG_P (operands[1]))
03416 {
03417
03418 cc_status = cc_prev_status;
03419 output_asm_insn ("tsx", operands);
03420 }
03421 else
03422 {
03423 output_asm_insn ("ldx\t%1", operands);
03424 }
03425 break;
03426
03427 case HARD_Y_REGNUM:
03428 if (D_REG_P (operands[1]))
03429 {
03430 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
03431 {
03432 m68hc11_output_swap (insn, operands);
03433 }
03434 else
03435 {
03436 output_asm_insn ("std\t%t1", operands);
03437 output_asm_insn ("ldy\t%t1", operands);
03438 }
03439 }
03440 else if (X_REG_P (operands[1]))
03441 {
03442
03443
03444 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
03445 && dead_register_here (insn, d_reg))
03446 {
03447 output_asm_insn ("xgdx", operands);
03448 output_asm_insn ("xgdy", operands);
03449 CC_STATUS_INIT;
03450 }
03451 else
03452 {
03453 output_asm_insn ("stx\t%t1", operands);
03454 output_asm_insn ("ldy\t%t1", operands);
03455 }
03456 }
03457 else if (SP_REG_P (operands[1]))
03458 {
03459
03460 cc_status = cc_prev_status;
03461 output_asm_insn ("tsy", operands);
03462 }
03463 else
03464 {
03465 output_asm_insn ("ldy\t%1", operands);
03466 }
03467 break;
03468
03469 case HARD_SP_REGNUM:
03470 if (D_REG_P (operands[1]))
03471 {
03472 m68hc11_notice_keep_cc (operands[0]);
03473 output_asm_insn ("xgdx", operands);
03474 output_asm_insn ("txs", operands);
03475 output_asm_insn ("xgdx", operands);
03476 }
03477 else if (X_REG_P (operands[1]))
03478 {
03479
03480 cc_status = cc_prev_status;
03481 output_asm_insn ("txs", operands);
03482 }
03483 else if (Y_REG_P (operands[1]))
03484 {
03485
03486 cc_status = cc_prev_status;
03487 output_asm_insn ("tys", operands);
03488 }
03489 else
03490 {
03491
03492 CC_STATUS_INIT;
03493 output_asm_insn ("lds\t%1", operands);
03494 output_asm_insn ("des", operands);
03495 }
03496 break;
03497
03498 default:
03499 fatal_insn ("invalid register in the move instruction", insn);
03500 break;
03501 }
03502 return;
03503 }
03504 if (SP_REG_P (operands[1]) && REG_P (operands[0])
03505 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
03506 {
03507 output_asm_insn ("sts\t%0", operands);
03508 return;
03509 }
03510
03511 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
03512 {
03513 cc_status = cc_prev_status;
03514 switch (REGNO (operands[1]))
03515 {
03516 case HARD_X_REGNUM:
03517 case HARD_Y_REGNUM:
03518 output_asm_insn ("psh%1", operands);
03519 break;
03520 case HARD_D_REGNUM:
03521 output_asm_insn ("pshb", operands);
03522 output_asm_insn ("psha", operands);
03523 break;
03524 default:
03525 abort ();
03526 }
03527 return;
03528 }
03529
03530
03531 if (!H_REG_P (operands[1]))
03532 {
03533 fatal_insn ("invalid operand in the instruction", insn);
03534 }
03535
03536 reg = REGNO (operands[1]);
03537 switch (reg)
03538 {
03539 case HARD_D_REGNUM:
03540 output_asm_insn ("std\t%0", operands);
03541 break;
03542
03543 case HARD_X_REGNUM:
03544 output_asm_insn ("stx\t%0", operands);
03545 break;
03546
03547 case HARD_Y_REGNUM:
03548 output_asm_insn ("sty\t%0", operands);
03549 break;
03550
03551 case HARD_SP_REGNUM:
03552 if (ix_reg == 0)
03553 create_regs_rtx ();
03554
03555 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
03556 {
03557 output_asm_insn ("pshx", operands);
03558 output_asm_insn ("tsx", operands);
03559 output_asm_insn ("inx", operands);
03560 output_asm_insn ("inx", operands);
03561 output_asm_insn ("stx\t%0", operands);
03562 output_asm_insn ("pulx", operands);
03563 }
03564
03565 else if (reg_mentioned_p (ix_reg, operands[0]))
03566 {
03567 output_asm_insn ("sty\t%t0", operands);
03568 output_asm_insn ("tsy", operands);
03569 output_asm_insn ("sty\t%0", operands);
03570 output_asm_insn ("ldy\t%t0", operands);
03571 }
03572 else
03573 {
03574 output_asm_insn ("stx\t%t0", operands);
03575 output_asm_insn ("tsx", operands);
03576 output_asm_insn ("stx\t%0", operands);
03577 output_asm_insn ("ldx\t%t0", operands);
03578 }
03579 CC_STATUS_INIT;
03580 break;
03581
03582 default:
03583 fatal_insn ("invalid register in the move instruction", insn);
03584 break;
03585 }
03586 }
03587
03588 void
03589 m68hc11_gen_movqi (insn, operands)
03590 rtx insn;
03591 rtx *operands;
03592 {
03593
03594
03595
03596 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
03597 {
03598 cc_status = cc_prev_status;
03599 return;
03600 }
03601
03602 if (TARGET_M6812)
03603 {
03604
03605 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
03606 {
03607 m68hc11_notice_keep_cc (operands[0]);
03608 output_asm_insn ("tfr\t%1,%0", operands);
03609 }
03610 else if (H_REG_P (operands[0]))
03611 {
03612 if (Q_REG_P (operands[0]))
03613 output_asm_insn ("lda%0\t%b1", operands);
03614 else if (D_REG_P (operands[0]))
03615 output_asm_insn ("ldab\t%b1", operands);
03616 else
03617 goto m6811_move;
03618 }
03619 else if (H_REG_P (operands[1]))
03620 {
03621 if (Q_REG_P (operands[1]))
03622 output_asm_insn ("sta%1\t%b0", operands);
03623 else if (D_REG_P (operands[1]))
03624 output_asm_insn ("stab\t%b0", operands);
03625 else
03626 goto m6811_move;
03627 }
03628 else
03629 {
03630 rtx from = operands[1];
03631 rtx to = operands[0];
03632
03633 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
03634 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
03635 || (m68hc11_register_indirect_p (to, GET_MODE (to))
03636 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
03637 {
03638 rtx ops[3];
03639
03640 if (operands[2])
03641 {
03642 ops[0] = operands[2];
03643 ops[1] = from;
03644 ops[2] = 0;
03645 m68hc11_gen_movqi (insn, ops);
03646 ops[0] = to;
03647 ops[1] = operands[2];
03648 m68hc11_gen_movqi (insn, ops);
03649 }
03650 else
03651 {
03652
03653 fatal_insn ("move insn not handled", insn);
03654 }
03655 }
03656 else
03657 {
03658 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
03659 {
03660 output_asm_insn ("clr\t%b0", operands);
03661 }
03662 else
03663 {
03664 m68hc11_notice_keep_cc (operands[0]);
03665 output_asm_insn ("movb\t%b1,%b0", operands);
03666 }
03667 }
03668 }
03669 return;
03670 }
03671
03672 m6811_move:
03673 if (H_REG_P (operands[0]))
03674 {
03675 switch (REGNO (operands[0]))
03676 {
03677 case HARD_B_REGNUM:
03678 case HARD_D_REGNUM:
03679 if (X_REG_P (operands[1]))
03680 {
03681 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
03682 {
03683 m68hc11_output_swap (insn, operands);
03684 }
03685 else
03686 {
03687 output_asm_insn ("stx\t%t1", operands);
03688 output_asm_insn ("ldab\t%T0", operands);
03689 }
03690 }
03691 else if (Y_REG_P (operands[1]))
03692 {
03693 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
03694 {
03695 m68hc11_output_swap (insn, operands);
03696 }
03697 else
03698 {
03699 output_asm_insn ("sty\t%t1", operands);
03700 output_asm_insn ("ldab\t%T0", operands);
03701 }
03702 }
03703 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
03704 && !DA_REG_P (operands[1]))
03705 {
03706 output_asm_insn ("ldab\t%b1", operands);
03707 }
03708 else if (DA_REG_P (operands[1]))
03709 {
03710 output_asm_insn ("tab", operands);
03711 }
03712 else
03713 {
03714 cc_status = cc_prev_status;
03715 return;
03716 }
03717 break;
03718
03719 case HARD_A_REGNUM:
03720 if (X_REG_P (operands[1]))
03721 {
03722 output_asm_insn ("stx\t%t1", operands);
03723 output_asm_insn ("ldaa\t%T0", operands);
03724 }
03725 else if (Y_REG_P (operands[1]))
03726 {
03727 output_asm_insn ("sty\t%t1", operands);
03728 output_asm_insn ("ldaa\t%T0", operands);
03729 }
03730 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
03731 && !DA_REG_P (operands[1]))
03732 {
03733 output_asm_insn ("ldaa\t%b1", operands);
03734 }
03735 else if (!DA_REG_P (operands[1]))
03736 {
03737 output_asm_insn ("tba", operands);
03738 }
03739 else
03740 {
03741 cc_status = cc_prev_status;
03742 }
03743 break;
03744
03745 case HARD_X_REGNUM:
03746 if (D_REG_P (operands[1]))
03747 {
03748 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
03749 {
03750 m68hc11_output_swap (insn, operands);
03751 }
03752 else
03753 {
03754 output_asm_insn ("stab\t%T1", operands);
03755 output_asm_insn ("ldx\t%t1", operands);
03756 }
03757 CC_STATUS_INIT;
03758 }
03759 else if (Y_REG_P (operands[1]))
03760 {
03761 output_asm_insn ("sty\t%t0", operands);
03762 output_asm_insn ("ldx\t%t0", operands);
03763 }
03764 else if (GET_CODE (operands[1]) == CONST_INT)
03765 {
03766 output_asm_insn ("ldx\t%1", operands);
03767 }
03768 else if (dead_register_here (insn, d_reg))
03769 {
03770 output_asm_insn ("ldab\t%b1", operands);
03771 output_asm_insn ("xgdx", operands);
03772 }
03773 else if (!reg_mentioned_p (operands[0], operands[1]))
03774 {
03775 output_asm_insn ("xgdx", operands);
03776 output_asm_insn ("ldab\t%b1", operands);
03777 output_asm_insn ("xgdx", operands);
03778 }
03779 else
03780 {
03781 output_asm_insn ("pshb", operands);
03782 output_asm_insn ("ldab\t%b1", operands);
03783 output_asm_insn ("stab\t%T1", operands);
03784 output_asm_insn ("ldx\t%t1", operands);
03785 output_asm_insn ("pulb", operands);
03786 CC_STATUS_INIT;
03787 }
03788 break;
03789
03790 case HARD_Y_REGNUM:
03791 if (D_REG_P (operands[1]))
03792 {
03793 output_asm_insn ("stab\t%T1", operands);
03794 output_asm_insn ("ldy\t%t1", operands);
03795 CC_STATUS_INIT;
03796 }
03797 else if (X_REG_P (operands[1]))
03798 {
03799 output_asm_insn ("stx\t%t1", operands);
03800 output_asm_insn ("ldy\t%t1", operands);
03801 CC_STATUS_INIT;
03802 }
03803 else if (GET_CODE (operands[1]) == CONST_INT)
03804 {
03805 output_asm_insn ("ldy\t%1", operands);
03806 }
03807 else if (dead_register_here (insn, d_reg))
03808 {
03809 output_asm_insn ("ldab\t%b1", operands);
03810 output_asm_insn ("xgdy", operands);
03811 }
03812 else if (!reg_mentioned_p (operands[0], operands[1]))
03813 {
03814 output_asm_insn ("xgdy", operands);
03815 output_asm_insn ("ldab\t%b1", operands);
03816 output_asm_insn ("xgdy", operands);
03817 }
03818 else
03819 {
03820 output_asm_insn ("pshb", operands);
03821 output_asm_insn ("ldab\t%b1", operands);
03822 output_asm_insn ("stab\t%T1", operands);
03823 output_asm_insn ("ldy\t%t1", operands);
03824 output_asm_insn ("pulb", operands);
03825 CC_STATUS_INIT;
03826 }
03827 break;
03828
03829 default:
03830 fatal_insn ("invalid register in the instruction", insn);
03831 break;
03832 }
03833 }
03834 else if (H_REG_P (operands[1]))
03835 {
03836 switch (REGNO (operands[1]))
03837 {
03838 case HARD_D_REGNUM:
03839 case HARD_B_REGNUM:
03840 output_asm_insn ("stab\t%b0", operands);
03841 break;
03842
03843 case HARD_A_REGNUM:
03844 output_asm_insn ("staa\t%b0", operands);
03845 break;
03846
03847 case HARD_X_REGNUM:
03848 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
03849 break;
03850
03851 case HARD_Y_REGNUM:
03852 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
03853 break;
03854
03855 default:
03856 fatal_insn ("invalid register in the move instruction", insn);
03857 break;
03858 }
03859 return;
03860 }
03861 else
03862 {
03863 fatal_insn ("operand 1 must be a hard register", insn);
03864 }
03865 }
03866
03867
03868
03869
03870 void
03871 m68hc11_gen_rotate (code, insn, operands)
03872 enum rtx_code code;
03873 rtx insn;
03874 rtx operands[];
03875 {
03876 int val;
03877
03878 if (GET_CODE (operands[2]) != CONST_INT
03879 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
03880 fatal_insn ("invalid rotate insn", insn);
03881
03882 val = INTVAL (operands[2]);
03883 if (code == ROTATERT)
03884 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
03885
03886 if (GET_MODE (operands[0]) != QImode)
03887 CC_STATUS_INIT;
03888
03889
03890 if (val >= 5 && val <= 11)
03891 {
03892 if (TARGET_M6812)
03893 output_asm_insn ("exg\ta,b", operands);
03894 else
03895 {
03896 output_asm_insn ("psha", operands);
03897 output_asm_insn ("tba", operands);
03898 output_asm_insn ("pulb", operands);
03899 }
03900 val -= 8;
03901 }
03902
03903
03904 else if (val >= 12)
03905 {
03906 val = val - 16;
03907 }
03908
03909 if (val > 0)
03910 {
03911
03912 if (GET_MODE (operands[0]) != QImode)
03913 {
03914 output_asm_insn ("asra", operands);
03915 output_asm_insn ("rola", operands);
03916 }
03917
03918 while (--val >= 0)
03919 {
03920
03921 if (D_REG_P (operands[0]))
03922 output_asm_insn ("rolb", operands);
03923
03924 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
03925 output_asm_insn ("rola", operands);
03926 }
03927 }
03928 else
03929 {
03930
03931 if (val != 0 && GET_MODE (operands[0]) != QImode)
03932 {
03933 output_asm_insn ("tap", operands);
03934 }
03935
03936 while (++val <= 0)
03937 {
03938
03939 if (D_REG_P (operands[0]))
03940 output_asm_insn ("rorb", operands);
03941
03942 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
03943 output_asm_insn ("rora", operands);
03944 }
03945 }
03946 }
03947
03948
03949
03950
03951
03952
03953
03954 void
03955 m68hc11_notice_update_cc (exp, insn)
03956 rtx exp;
03957 rtx insn ATTRIBUTE_UNUSED;
03958 {
03959
03960 if (GET_CODE (exp) == SET)
03961 {
03962
03963 if (SET_DEST (exp) == pc_rtx)
03964 ;
03965
03966
03967
03968
03969
03970
03971 else if (GET_CODE (SET_SRC (exp)) == CALL)
03972 {
03973 CC_STATUS_INIT;
03974 }
03975
03976
03977 else if (SET_DEST (exp) == cc0_rtx)
03978 {
03979 cc_status.flags = 0;
03980 cc_status.value1 = XEXP (exp, 0);
03981 cc_status.value2 = XEXP (exp, 1);
03982 }
03983 else
03984 {
03985
03986 cc_status.flags = 0;
03987 cc_status.value1 = XEXP (exp, 0);
03988 cc_status.value2 = XEXP (exp, 1);
03989 }
03990 }
03991 else
03992 {
03993
03994
03995 CC_STATUS_INIT;
03996 }
03997
03998 if (cc_status.value2 != 0)
03999 switch (GET_CODE (cc_status.value2))
04000 {
04001
04002
04003 case IOR:
04004 case XOR:
04005 case AND:
04006 break;
04007
04008
04009
04010 case NOT:
04011 if (GET_MODE (cc_status.value2) != QImode)
04012 CC_STATUS_INIT;
04013 break;
04014
04015 case PLUS:
04016 case MINUS:
04017 case MULT:
04018 case DIV:
04019 case UDIV:
04020 case MOD:
04021 case UMOD:
04022 case NEG:
04023 if (GET_MODE (cc_status.value2) != VOIDmode)
04024 cc_status.flags |= CC_NO_OVERFLOW;
04025 break;
04026
04027
04028
04029 case ASHIFT:
04030 case ROTATE:
04031 case ROTATERT:
04032 if (GET_MODE (cc_status.value2) != VOIDmode)
04033 cc_status.flags |= CC_NO_OVERFLOW;
04034 break;
04035
04036
04037 case MEM:
04038 case SYMBOL_REF:
04039 case REG:
04040 case CONST_INT:
04041 cc_status.flags |= CC_NO_OVERFLOW;
04042 break;
04043
04044 default:
04045 break;
04046 }
04047 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
04048 && cc_status.value2
04049 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
04050 cc_status.value2 = 0;
04051 }
04052
04053
04054
04055
04056 void
04057 m68hc11_notice_keep_cc (reg)
04058 rtx reg;
04059 {
04060 if (reg == 0
04061 || cc_prev_status.value1 == 0
04062 || rtx_equal_p (reg, cc_prev_status.value1)
04063 || (cc_prev_status.value2
04064 && reg_mentioned_p (reg, cc_prev_status.value2)))
04065 CC_STATUS_INIT;
04066 else
04067 cc_status = cc_prev_status;
04068 }
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085
04086
04087
04088
04089
04090
04091
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109
04110
04111 struct replace_info
04112 {
04113 rtx first;
04114 rtx replace_reg;
04115 int need_save_z;
04116 int must_load_z;
04117 int must_save_reg;
04118 int must_restore_reg;
04119 rtx last;
04120 int regno;
04121 int x_used;
04122 int y_used;
04123 int can_use_d;
04124 int found_call;
04125 int z_died;
04126 int z_set_count;
04127 rtx z_value;
04128 int must_push_reg;
04129 int save_before_last;
04130 int z_loaded_with_sp;
04131 };
04132
04133 static rtx z_reg_qi;
04134
04135 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
04136 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
04137 static void m68hc11_z_replacement PARAMS ((rtx));
04138 static void m68hc11_reassign_regs PARAMS ((rtx));
04139
04140 int z_replacement_completed = 0;
04141
04142
04143
04144
04145
04146
04147 static int
04148 m68hc11_check_z_replacement (insn, info)
04149 rtx insn;
04150 struct replace_info *info;
04151 {
04152 int this_insn_uses_ix;
04153 int this_insn_uses_iy;
04154 int this_insn_uses_z;
04155 int this_insn_uses_z_in_dst;
04156 int this_insn_uses_d;
04157 rtx body;
04158 int z_dies_here;
04159
04160
04161
04162
04163 if (GET_CODE (insn) == CALL_INSN)
04164 {
04165 body = PATTERN (insn);
04166
04167 info->can_use_d = 0;
04168
04169
04170
04171
04172 if (reg_mentioned_p (z_reg, body))
04173 {
04174 insn = NEXT_INSN (insn);
04175 info->x_used = 1;
04176 info->y_used = 0;
04177 info->found_call = 1;
04178 info->must_restore_reg = 0;
04179 info->last = NEXT_INSN (insn);
04180 }
04181 info->need_save_z = 0;
04182 return 0;
04183 }
04184 if (GET_CODE (insn) == CODE_LABEL
04185 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
04186 return 0;
04187
04188 if (GET_CODE (insn) == JUMP_INSN)
04189 {
04190 if (reg_mentioned_p (z_reg, insn) == 0)
04191 return 0;
04192
04193 info->can_use_d = 0;
04194 info->must_save_reg = 0;
04195 info->must_restore_reg = 0;
04196 info->need_save_z = 0;
04197 info->last = NEXT_INSN (insn);
04198 return 0;
04199 }
04200 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
04201 {
04202 return 1;
04203 }
04204
04205
04206 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
04207
04208 body = PATTERN (insn);
04209 if (GET_CODE (body) == SET)
04210 {
04211 rtx src = XEXP (body, 1);
04212 rtx dst = XEXP (body, 0);
04213
04214
04215
04216
04217
04218
04219 if (dst == cc0_rtx)
04220 {
04221 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
04222 || (GET_CODE (src) == COMPARE &&
04223 (rtx_equal_p (XEXP (src, 0), z_reg)
04224 || rtx_equal_p (XEXP (src, 1), z_reg))))
04225 {
04226 if (insn == info->first)
04227 {
04228 info->must_load_z = 0;
04229 info->must_save_reg = 0;
04230 info->must_restore_reg = 0;
04231 info->need_save_z = 0;
04232 info->found_call = 1;
04233 info->regno = SOFT_Z_REGNUM;
04234 info->last = insn;
04235 }
04236 return 0;
04237 }
04238 if (reg_mentioned_p (z_reg, src) == 0)
04239 {
04240 info->can_use_d = 0;
04241 return 0;
04242 }
04243
04244 if (insn != info->first)
04245 return 0;
04246
04247
04248
04249
04250 info->must_push_reg = 1;
04251 info->last = insn;
04252 }
04253
04254
04255 if (Z_REG_P (dst))
04256 {
04257 if (!reg_mentioned_p (z_reg, src))
04258 {
04259
04260
04261 if (insn != info->first)
04262 {
04263 return 0;
04264 }
04265 info->must_load_z = 0;
04266 }
04267 info->z_set_count++;
04268 info->z_value = src;
04269 if (SP_REG_P (src))
04270 info->z_loaded_with_sp = 1;
04271 }
04272 else if (reg_mentioned_p (z_reg, dst))
04273 info->can_use_d = 0;
04274
04275 this_insn_uses_d = reg_mentioned_p (d_reg, src)
04276 | reg_mentioned_p (d_reg, dst);
04277 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
04278 | reg_mentioned_p (ix_reg, dst);
04279 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
04280 | reg_mentioned_p (iy_reg, dst);
04281 this_insn_uses_z = reg_mentioned_p (z_reg, src);
04282
04283
04284
04285 if (this_insn_uses_z && !Z_REG_P (src)
04286 && !(m68hc11_arith_operator (src, GET_MODE (src))
04287 && Z_REG_P (XEXP (src, 0))
04288 && !reg_mentioned_p (z_reg, XEXP (src, 1))
04289 && insn == info->first
04290 && dead_register_here (insn, d_reg)))
04291 info->can_use_d = 0;
04292
04293 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
04294 if (TARGET_M6812 && !z_dies_here
04295 && ((this_insn_uses_z && side_effects_p (src))
04296 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
04297 {
04298 info->need_save_z = 1;
04299 info->z_set_count++;
04300 }
04301 this_insn_uses_z |= this_insn_uses_z_in_dst;
04302
04303 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
04304 {
04305 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
04306 }
04307
04308 if (this_insn_uses_d)
04309 info->can_use_d = 0;
04310
04311
04312
04313 if (this_insn_uses_ix && this_insn_uses_iy)
04314 {
04315 return 0;
04316 }
04317
04318 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
04319 info->can_use_d = 0;
04320
04321 if (info->x_used == 0 && this_insn_uses_ix)
04322 {
04323 if (info->y_used)
04324 {
04325
04326
04327
04328
04329 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
04330 {
04331 if (z_dies_here)
04332 {
04333 info->need_save_z = 0;
04334 info->z_died = 1;
04335 }
04336 info->must_save_reg = 0;
04337 info->must_restore_reg = 0;
04338 info->found_call = 1;
04339 info->can_use_d = 0;
04340 PUT_CODE (insn, NOTE);
04341 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
04342 NOTE_SOURCE_FILE (insn) = 0;
04343 info->last = NEXT_INSN (insn);
04344 return 0;
04345 }
04346
04347 if (X_REG_P (dst)
04348 && (rtx_equal_p (src, z_reg)
04349 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
04350 {
04351 if (z_dies_here)
04352 {
04353 info->need_save_z = 0;
04354 info->z_died = 1;
04355 }
04356 info->last = NEXT_INSN (insn);
04357 info->must_save_reg = 0;
04358 info->must_restore_reg = 0;
04359 }
04360 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
04361 && !reg_mentioned_p (ix_reg, src))
04362 {
04363 if (z_dies_here)
04364 {
04365 info->z_died = 1;
04366 info->need_save_z = 0;
04367 }
04368 else
04369 {
04370 info->save_before_last = 1;
04371 }
04372 info->must_restore_reg = 0;
04373 info->last = NEXT_INSN (insn);
04374 }
04375 else if (info->can_use_d)
04376 {
04377 info->last = NEXT_INSN (insn);
04378 info->x_used = 1;
04379 }
04380 return 0;
04381 }
04382 info->x_used = 1;
04383 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
04384 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
04385 {
04386 info->need_save_z = 0;
04387 info->z_died = 1;
04388 info->last = NEXT_INSN (insn);
04389 info->regno = HARD_X_REGNUM;
04390 info->must_save_reg = 0;
04391 info->must_restore_reg = 0;
04392 return 0;
04393 }
04394 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
04395 {
04396 info->regno = HARD_X_REGNUM;
04397 info->must_restore_reg = 0;
04398 info->must_save_reg = 0;
04399 return 0;
04400 }
04401 }
04402 if (info->y_used == 0 && this_insn_uses_iy)
04403 {
04404 if (info->x_used)
04405 {
04406 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
04407 {
04408 if (z_dies_here)
04409 {
04410 info->need_save_z = 0;
04411 info->z_died = 1;
04412 }
04413 info->must_save_reg = 0;
04414 info->must_restore_reg = 0;
04415 info->found_call = 1;
04416 info->can_use_d = 0;
04417 PUT_CODE (insn, NOTE);
04418 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
04419 NOTE_SOURCE_FILE (insn) = 0;
04420 info->last = NEXT_INSN (insn);
04421 return 0;
04422 }
04423
04424 if (Y_REG_P (dst)
04425 && (rtx_equal_p (src, z_reg)
04426 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
04427 {
04428 if (z_dies_here)
04429 {
04430 info->z_died = 1;
04431 info->need_save_z = 0;
04432 }
04433 info->last = NEXT_INSN (insn);
04434 info->must_save_reg = 0;
04435 info->must_restore_reg = 0;
04436 }
04437 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
04438 && !reg_mentioned_p (iy_reg, src))
04439 {
04440 if (z_dies_here)
04441 {
04442 info->z_died = 1;
04443 info->need_save_z = 0;
04444 }
04445 else
04446 {
04447 info->save_before_last = 1;
04448 }
04449 info->must_restore_reg = 0;
04450 info->last = NEXT_INSN (insn);
04451 }
04452 else if (info->can_use_d)
04453 {
04454 info->last = NEXT_INSN (insn);
04455 info->y_used = 1;
04456 }
04457
04458 return 0;
04459 }
04460 info->y_used = 1;
04461 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
04462 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
04463 {
04464 info->need_save_z = 0;
04465 info->z_died = 1;
04466 info->last = NEXT_INSN (insn);
04467 info->regno = HARD_Y_REGNUM;
04468 info->must_save_reg = 0;
04469 info->must_restore_reg = 0;
04470 return 0;
04471 }
04472 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
04473 {
04474 info->regno = HARD_Y_REGNUM;
04475 info->must_restore_reg = 0;
04476 info->must_save_reg = 0;
04477 return 0;
04478 }
04479 }
04480 if (z_dies_here)
04481 {
04482 info->need_save_z = 0;
04483 info->z_died = 1;
04484 if (info->last == 0)
04485 info->last = NEXT_INSN (insn);
04486 return 0;
04487 }
04488 return info->last != NULL_RTX ? 0 : 1;
04489 }
04490 if (GET_CODE (body) == PARALLEL)
04491 {
04492 int i;
04493 char ix_clobber = 0;
04494 char iy_clobber = 0;
04495 char z_clobber = 0;
04496 this_insn_uses_iy = 0;
04497 this_insn_uses_ix = 0;
04498 this_insn_uses_z = 0;
04499
04500 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
04501 {
04502 rtx x;
04503 int uses_ix, uses_iy, uses_z;
04504
04505 x = XVECEXP (body, 0, i);
04506
04507 if (info->can_use_d && reg_mentioned_p (d_reg, x))
04508 info->can_use_d = 0;
04509
04510 uses_ix = reg_mentioned_p (ix_reg, x);
04511 uses_iy = reg_mentioned_p (iy_reg, x);
04512 uses_z = reg_mentioned_p (z_reg, x);
04513 if (GET_CODE (x) == CLOBBER)
04514 {
04515 ix_clobber |= uses_ix;
04516 iy_clobber |= uses_iy;
04517 z_clobber |= uses_z;
04518 }
04519 else
04520 {
04521 this_insn_uses_ix |= uses_ix;
04522 this_insn_uses_iy |= uses_iy;
04523 this_insn_uses_z |= uses_z;
04524 }
04525 if (uses_z && GET_CODE (x) == SET)
04526 {
04527 rtx dst = XEXP (x, 0);
04528
04529 if (Z_REG_P (dst))
04530 info->z_set_count++;
04531 }
04532 if (TARGET_M6812 && uses_z && side_effects_p (x))
04533 info->need_save_z = 1;
04534
04535 if (z_clobber)
04536 info->need_save_z = 0;
04537 }
04538 if (debug_m6811)
04539 {
04540 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
04541 this_insn_uses_ix, this_insn_uses_iy,
04542 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
04543 debug_rtx (insn);
04544 }
04545 if (this_insn_uses_z)
04546 info->can_use_d = 0;
04547
04548 if (z_clobber && info->first != insn)
04549 {
04550 info->need_save_z = 0;
04551 info->last = insn;
04552 return 0;
04553 }
04554 if (z_clobber && info->x_used == 0 && info->y_used == 0)
04555 {
04556 if (this_insn_uses_z == 0 && insn == info->first)
04557 {
04558 info->must_load_z = 0;
04559 }
04560 if (dead_register_here (insn, d_reg))
04561 {
04562 info->regno = HARD_D_REGNUM;
04563 info->must_save_reg = 0;
04564 info->must_restore_reg = 0;
04565 }
04566 else if (dead_register_here (insn, ix_reg))
04567 {
04568 info->regno = HARD_X_REGNUM;
04569 info->must_save_reg = 0;
04570 info->must_restore_reg = 0;
04571 }
04572 else if (dead_register_here (insn, iy_reg))
04573 {
04574 info->regno = HARD_Y_REGNUM;
04575 info->must_save_reg = 0;
04576 info->must_restore_reg = 0;
04577 }
04578 if (info->regno >= 0)
04579 {
04580 info->last = NEXT_INSN (insn);
04581 return 0;
04582 }
04583 if (this_insn_uses_ix == 0)
04584 {
04585 info->regno = HARD_X_REGNUM;
04586 info->must_save_reg = 1;
04587 info->must_restore_reg = 1;
04588 }
04589 else if (this_insn_uses_iy == 0)
04590 {
04591 info->regno = HARD_Y_REGNUM;
04592 info->must_save_reg = 1;
04593 info->must_restore_reg = 1;
04594 }
04595 else
04596 {
04597 info->regno = HARD_D_REGNUM;
04598 info->must_save_reg = 1;
04599 info->must_restore_reg = 1;
04600 }
04601 info->last = NEXT_INSN (insn);
04602 return 0;
04603 }
04604
04605 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
04606 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
04607 {
04608 if (this_insn_uses_z)
04609 {
04610 if (info->y_used == 0 && iy_clobber)
04611 {
04612 info->regno = HARD_Y_REGNUM;
04613 info->must_save_reg = 0;
04614 info->must_restore_reg = 0;
04615 }
04616 if (info->first != insn
04617 && ((info->y_used && ix_clobber)
04618 || (info->x_used && iy_clobber)))
04619 info->last = insn;
04620 else
04621 info->last = NEXT_INSN (insn);
04622 info->save_before_last = 1;
04623 }
04624 return 0;
04625 }
04626 if (this_insn_uses_ix && this_insn_uses_iy)
04627 {
04628 if (this_insn_uses_z)
04629 {
04630 fatal_insn ("cannot do z-register replacement", insn);
04631 }
04632 return 0;
04633 }
04634 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
04635 {
04636 if (info->y_used)
04637 {
04638 return 0;
04639 }
04640 info->x_used = 1;
04641 if (iy_clobber || z_clobber)
04642 {
04643 info->last = NEXT_INSN (insn);
04644 info->save_before_last = 1;
04645 return 0;
04646 }
04647 }
04648
04649 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
04650 {
04651 if (info->x_used)
04652 {
04653 return 0;
04654 }
04655 info->y_used = 1;
04656 if (ix_clobber || z_clobber)
04657 {
04658 info->last = NEXT_INSN (insn);
04659 info->save_before_last = 1;
04660 return 0;
04661 }
04662 }
04663 if (z_dies_here)
04664 {
04665 info->z_died = 1;
04666 info->need_save_z = 0;
04667 }
04668 return 1;
04669 }
04670 if (GET_CODE (body) == CLOBBER)
04671 {
04672
04673
04674
04675 if (this_insn_uses_ix && this_insn_uses_iy)
04676 {
04677 return 0;
04678 }
04679 if (info->x_used == 0 && this_insn_uses_ix)
04680 {
04681 if (info->y_used)
04682 {
04683 return 0;
04684 }
04685 info->x_used = 1;
04686 }
04687 if (info->y_used == 0 && this_insn_uses_iy)
04688 {
04689 if (info->x_used)
04690 {
04691 return 0;
04692 }
04693 info->y_used = 1;
04694 }
04695 return 1;
04696 }
04697 return 1;
04698 }
04699
04700 static void
04701 m68hc11_find_z_replacement (insn, info)
04702 rtx insn;
04703 struct replace_info *info;
04704 {
04705 int reg;
04706
04707 info->replace_reg = NULL_RTX;
04708 info->must_load_z = 1;
04709 info->need_save_z = 1;
04710 info->must_save_reg = 1;
04711 info->must_restore_reg = 1;
04712 info->first = insn;
04713 info->x_used = 0;
04714 info->y_used = 0;
04715 info->can_use_d = TARGET_M6811 ? 1 : 0;
04716 info->found_call = 0;
04717 info->z_died = 0;
04718 info->last = 0;
04719 info->regno = -1;
04720 info->z_set_count = 0;
04721 info->z_value = NULL_RTX;
04722 info->must_push_reg = 0;
04723 info->save_before_last = 0;
04724 info->z_loaded_with_sp = 0;
04725
04726
04727
04728
04729
04730
04731
04732
04733 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
04734 {
04735 if (m68hc11_check_z_replacement (insn, info) == 0)
04736 break;
04737 }
04738
04739
04740
04741 if (info->z_set_count == 1)
04742 {
04743 rtx p = info->first;
04744 rtx v = 0;
04745
04746 if (info->x_used)
04747 {
04748 v = find_last_value (iy_reg, &p, insn, 1);
04749 }
04750 else if (info->y_used)
04751 {
04752 v = find_last_value (ix_reg, &p, insn, 1);
04753 }
04754 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
04755 {
04756 if (info->x_used)
04757 info->regno = HARD_Y_REGNUM;
04758 else
04759 info->regno = HARD_X_REGNUM;
04760 info->must_load_z = 0;
04761 info->must_save_reg = 0;
04762 info->must_restore_reg = 0;
04763 info->found_call = 1;
04764 }
04765 }
04766 if (info->z_set_count == 0)
04767 info->need_save_z = 0;
04768
04769 if (insn == 0)
04770 info->need_save_z = 0;
04771
04772 if (info->last == 0)
04773 info->last = insn;
04774
04775 if (info->regno >= 0)
04776 {
04777 reg = info->regno;
04778 info->replace_reg = gen_rtx (REG, HImode, reg);
04779 }
04780 else if (info->can_use_d)
04781 {
04782 reg = HARD_D_REGNUM;
04783 info->replace_reg = d_reg;
04784 }
04785 else if (info->x_used)
04786 {
04787 reg = HARD_Y_REGNUM;
04788 info->replace_reg = iy_reg;
04789 }
04790 else
04791 {
04792 reg = HARD_X_REGNUM;
04793 info->replace_reg = ix_reg;
04794 }
04795 info->regno = reg;
04796
04797 if (info->must_save_reg && info->must_restore_reg)
04798 {
04799 if (insn && dead_register_here (insn, info->replace_reg))
04800 {
04801 info->must_save_reg = 0;
04802 info->must_restore_reg = 0;
04803 }
04804 }
04805 }
04806
04807
04808
04809
04810
04811
04812
04813 static void
04814 m68hc11_z_replacement (insn)
04815 rtx insn;
04816 {
04817 rtx replace_reg_qi;
04818 rtx replace_reg;
04819 struct replace_info info;
04820
04821
04822
04823 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
04824 {
04825 rtx body = PATTERN (insn);
04826 rtx src = XEXP (body, 1);
04827 rtx dst = XEXP (body, 0);
04828
04829 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
04830 {
04831 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
04832 return;
04833 }
04834 else if (Z_REG_P (src)
04835 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
04836 {
04837 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
04838 return;
04839 }
04840 else if (D_REG_P (dst)
04841 && m68hc11_arith_operator (src, GET_MODE (src))
04842 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
04843 {
04844 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
04845 return;
04846 }
04847 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
04848 && INTVAL (src) == 0)
04849 {
04850 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
04851
04852 INSN_CODE (insn) = -1;
04853 return;
04854 }
04855 }
04856
04857 m68hc11_find_z_replacement (insn, &info);
04858
04859 replace_reg = info.replace_reg;
04860 replace_reg_qi = NULL_RTX;
04861
04862
04863 if (info.must_save_reg && !info.must_push_reg)
04864 {
04865 rtx dst;
04866
04867 if (info.must_push_reg && 0)
04868 dst = gen_rtx (MEM, HImode,
04869 gen_rtx (PRE_DEC, HImode,
04870 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
04871 else
04872 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
04873
04874 emit_insn_before (gen_movhi (dst,
04875 gen_rtx (REG, HImode, info.regno)), insn);
04876 }
04877 if (info.must_load_z && !info.must_push_reg)
04878 {
04879 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
04880 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
04881 insn);
04882 }
04883
04884
04885
04886
04887
04888
04889
04890 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
04891 {
04892 rtx body;
04893
04894 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
04895 break;
04896
04897 if (GET_CODE (insn) != INSN
04898 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
04899 continue;
04900
04901 body = PATTERN (insn);
04902 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
04903 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
04904 {
04905 rtx note;
04906
04907 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
04908 {
04909 printf ("Reg mentioned here...:\n");
04910 fflush (stdout);
04911 debug_rtx (insn);
04912 }
04913
04914
04915
04916 if (info.must_push_reg
04917 && info.z_loaded_with_sp && GET_CODE (body) == SET)
04918 {
04919 rtx src, dst;
04920
04921 src = SET_SRC (body);
04922 dst = SET_DEST (body);
04923 if (SP_REG_P (src) && Z_REG_P (dst))
04924 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
04925 }
04926
04927
04928 if (!validate_replace_rtx (z_reg, replace_reg, insn))
04929 {
04930 INSN_CODE (insn) = -1;
04931 if (!validate_replace_rtx (z_reg, replace_reg, insn))
04932 fatal_insn ("cannot do z-register replacement", insn);
04933 }
04934
04935
04936 if (reg_mentioned_p (z_reg, insn))
04937 {
04938 if (replace_reg_qi == NULL_RTX)
04939 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
04940 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
04941 }
04942
04943
04944
04945
04946
04947 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
04948 {
04949 if (REG_NOTE_KIND (note) == REG_INC
04950 && GET_CODE (XEXP (note, 0)) == REG
04951 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
04952 {
04953 XEXP (note, 0) = replace_reg;
04954 }
04955 }
04956 }
04957 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
04958 break;
04959 }
04960
04961
04962 if (insn && info.need_save_z && !info.must_push_reg)
04963 {
04964 rtx save_pos_insn = insn;
04965
04966
04967
04968 if (info.save_before_last)
04969 save_pos_insn = PREV_INSN (save_pos_insn);
04970
04971 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
04972 gen_rtx (REG, HImode, info.regno)),
04973 save_pos_insn);
04974 }
04975
04976 if (info.must_push_reg && info.last)
04977 {
04978 rtx new_body, body;
04979
04980 body = PATTERN (info.last);
04981 new_body = gen_rtx (PARALLEL, VOIDmode,
04982 gen_rtvec (3, body,
04983 gen_rtx (USE, VOIDmode,
04984 replace_reg),
04985 gen_rtx (USE, VOIDmode,
04986 gen_rtx (REG, HImode,
04987 SOFT_Z_REGNUM))));
04988 PATTERN (info.last) = new_body;
04989
04990
04991 INSN_CODE (insn) = -1;
04992
04993 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
04994 {
04995 fatal_insn ("invalid Z register replacement for insn", insn);
04996 }
04997 insn = NEXT_INSN (info.last);
04998 }
04999
05000
05001 if (insn && info.must_restore_reg && !info.must_push_reg)
05002 {
05003 rtx dst;
05004
05005 if (info.must_push_reg && 0)
05006 dst = gen_rtx (MEM, HImode,
05007 gen_rtx (POST_INC, HImode,
05008 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
05009 else
05010 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
05011
05012 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
05013 dst), insn);
05014 }
05015
05016 }
05017
05018
05019
05020
05021
05022
05023 static void
05024 m68hc11_reassign_regs (first)
05025 rtx first;
05026 {
05027 rtx insn;
05028
05029 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
05030 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
05031 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
05032 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
05033
05034
05035
05036
05037 for (insn = first; insn; insn = NEXT_INSN (insn))
05038 {
05039 rtx body;
05040
05041 if (GET_CODE (insn) == CODE_LABEL
05042 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
05043 continue;
05044
05045 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
05046 continue;
05047
05048 body = PATTERN (insn);
05049 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
05050 continue;
05051
05052 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
05053 || GET_CODE (body) == ASM_OPERANDS
05054 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
05055 continue;
05056
05057 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
05058 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
05059 {
05060
05061
05062
05063
05064
05065 if (reg_mentioned_p (z_reg, body))
05066 {
05067 m68hc11_z_replacement (insn);
05068 }
05069 }
05070 else
05071 {
05072 printf ("insn not handled by Z replacement:\n");
05073 fflush (stdout);
05074 debug_rtx (insn);
05075 }
05076 }
05077 }
05078
05079
05080 void
05081 m68hc11_reorg (first)
05082 rtx first;
05083 {
05084 int split_done = 0;
05085 rtx insn;
05086
05087 z_replacement_completed = 0;
05088 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
05089
05090
05091
05092 unshare_all_rtl_again (first);
05093
05094
05095
05096 split_all_insns_noflow ();
05097 split_done = 1;
05098
05099 z_replacement_completed = 1;
05100 m68hc11_reassign_regs (first);
05101
05102
05103
05104 if (optimize > 0 && split_done)
05105 {
05106 find_basic_blocks (first, max_reg_num (), 0);
05107 reload_cse_regs (first);
05108 }
05109
05110
05111
05112 if (optimize)
05113 {
05114
05115
05116
05117
05118
05119 for (insn = first; insn; insn = NEXT_INSN (insn))
05120 {
05121 if (INSN_P (insn))
05122 {
05123 rtx *pnote;
05124
05125 pnote = ®_NOTES (insn);
05126 while (*pnote != 0)
05127 {
05128 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
05129 *pnote = XEXP (*pnote, 1);
05130 else
05131 pnote = &XEXP (*pnote, 1);
05132 }
05133 }
05134 }
05135
05136 find_basic_blocks (first, max_reg_num (), 0);
05137 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
05138 }
05139
05140 z_replacement_completed = 2;
05141
05142
05143
05144
05145 if (optimize > 0)
05146 split_all_insns_noflow ();
05147
05148
05149
05150
05151
05152
05153
05154
05155
05156 {
05157 rtx insn;
05158
05159 for (insn = first; insn; insn = NEXT_INSN (insn))
05160 {
05161 rtx body;
05162
05163 if (INSN_DELETED_P (insn))
05164 continue;
05165 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
05166 continue;
05167
05168
05169 body = PATTERN (insn);
05170 if (GET_CODE (body) == SET
05171 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
05172 {
05173 PUT_CODE (insn, NOTE);
05174 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
05175 NOTE_SOURCE_FILE (insn) = 0;
05176 continue;
05177 }
05178 }
05179 }
05180 }
05181
05182
05183
05184
05185
05186 int
05187 m68hc11_memory_move_cost (mode, class, in)
05188 enum machine_mode mode;
05189 enum reg_class class;
05190 int in ATTRIBUTE_UNUSED;
05191 {
05192 if (class <= H_REGS && class > NO_REGS)
05193 {
05194 if (GET_MODE_SIZE (mode) <= 2)
05195 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
05196 else
05197 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
05198 }
05199 else
05200 {
05201 if (GET_MODE_SIZE (mode) <= 2)
05202 return COSTS_N_INSNS (2);
05203 else
05204 return COSTS_N_INSNS (4);
05205 }
05206 }
05207
05208
05209
05210
05211
05212
05213 int
05214 m68hc11_register_move_cost (mode, from, to)
05215 enum machine_mode mode;
05216 enum reg_class from;
05217 enum reg_class to;
05218 {
05219
05220
05221 if (from < to)
05222 {
05223 enum reg_class tmp = to;
05224 to = from, from = tmp;
05225 }
05226 if (to >= S_REGS)
05227 return m68hc11_memory_move_cost (mode, S_REGS, 0);
05228 else if (from <= S_REGS)
05229 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
05230 else
05231 return COSTS_N_INSNS (2);
05232 }
05233
05234
05235
05236
05237
05238 int
05239 m68hc11_address_cost (addr)
05240 rtx addr;
05241 {
05242 int cost = 4;
05243
05244 switch (GET_CODE (addr))
05245 {
05246 case REG:
05247
05248 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
05249 cost = 0;
05250 else
05251 cost = 1;
05252 break;
05253
05254 case SYMBOL_REF:
05255 cost = 8;
05256 break;
05257
05258 case LABEL_REF:
05259 case CONST:
05260 cost = 0;
05261 break;
05262
05263 case PLUS:
05264 {
05265 register rtx plus0 = XEXP (addr, 0);
05266 register rtx plus1 = XEXP (addr, 1);
05267
05268 if (GET_CODE (plus0) != REG)
05269 break;
05270
05271 switch (GET_CODE (plus1))
05272 {
05273 case CONST_INT:
05274 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
05275 || INTVAL (plus1) < m68hc11_min_offset)
05276 cost = 3;
05277 else if (INTVAL (plus1) >= m68hc11_max_offset)
05278 cost = 2;
05279 else
05280 cost = 1;
05281 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
05282 cost += 0;
05283 else
05284 cost += 1;
05285 break;
05286
05287 case SYMBOL_REF:
05288 cost = 8;
05289 break;
05290
05291 case CONST:
05292 case LABEL_REF:
05293 cost = 0;
05294 break;
05295
05296 default:
05297 break;
05298 }
05299 break;
05300 }
05301 case PRE_DEC:
05302 case PRE_INC:
05303 if (SP_REG_P (XEXP (addr, 0)))
05304 cost = 1;
05305 break;
05306
05307 default:
05308 break;
05309 }
05310 if (debug_m6811)
05311 {
05312 printf ("Address cost: %d for :", cost);
05313 fflush (stdout);
05314 debug_rtx (addr);
05315 }
05316
05317 return cost;
05318 }
05319
05320 static int
05321 m68hc11_shift_cost (mode, x, shift)
05322 enum machine_mode mode;
05323 rtx x;
05324 int shift;
05325 {
05326 int total;
05327
05328 total = rtx_cost (x, SET);
05329 if (mode == QImode)
05330 total += m68hc11_cost->shiftQI_const[shift % 8];
05331 else if (mode == HImode)
05332 total += m68hc11_cost->shiftHI_const[shift % 16];
05333 else if (shift == 8 || shift == 16 || shift == 32)
05334 total += m68hc11_cost->shiftHI_const[8];
05335 else if (shift != 0 && shift != 16 && shift != 32)
05336 {
05337 total += m68hc11_cost->shiftHI_const[1] * shift;
05338 }
05339
05340
05341 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
05342 total *= GET_MODE_SIZE (mode) / 2;
05343
05344
05345
05346 if (optimize_size && (shift % 8) != 0)
05347 total *= 2;
05348
05349 return total;
05350 }
05351
05352 int
05353 m68hc11_rtx_costs (x, code, outer_code)
05354 rtx x;
05355 enum rtx_code code;
05356 enum rtx_code outer_code ATTRIBUTE_UNUSED;
05357 {
05358 enum machine_mode mode = GET_MODE (x);
05359 int extra_cost = 0;
05360 int total;
05361
05362 switch (code)
05363 {
05364 case ROTATE:
05365 case ROTATERT:
05366 case ASHIFT:
05367 case LSHIFTRT:
05368 case ASHIFTRT:
05369 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
05370 {
05371 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
05372 }
05373
05374 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
05375 total += m68hc11_cost->shift_var;
05376 return total;
05377
05378 case AND:
05379 case XOR:
05380 case IOR:
05381 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
05382 total += m68hc11_cost->logical;
05383
05384
05385 total *= GET_MODE_SIZE (mode);
05386 return total;
05387
05388 case MINUS:
05389 case PLUS:
05390 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
05391 total += m68hc11_cost->add;
05392 if (GET_MODE_SIZE (mode) > 2)
05393 {
05394 total *= GET_MODE_SIZE (mode) / 2;
05395 }
05396 return total;
05397
05398 case UDIV:
05399 case DIV:
05400 case MOD:
05401 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
05402 switch (mode)
05403 {
05404 case QImode:
05405 total += m68hc11_cost->divQI;
05406 break;
05407
05408 case HImode:
05409 total += m68hc11_cost->divHI;
05410 break;
05411
05412 case SImode:
05413 default:
05414 total += m68hc11_cost->divSI;
05415 break;
05416 }
05417 return total;
05418
05419 case MULT:
05420
05421 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
05422 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
05423 return m68hc11_cost->multQI
05424 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
05425 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
05426
05427
05428 if (TARGET_M6812 && mode == SImode
05429 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
05430 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
05431 return m68hc11_cost->multHI
05432 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
05433 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
05434
05435 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
05436 switch (mode)
05437 {
05438 case QImode:
05439 total += m68hc11_cost->multQI;
05440 break;
05441
05442 case HImode:
05443 total += m68hc11_cost->multHI;
05444 break;
05445
05446 case SImode:
05447 default:
05448 total += m68hc11_cost->multSI;
05449 break;
05450 }
05451 return total;
05452
05453 case NEG:
05454 case SIGN_EXTEND:
05455 extra_cost = COSTS_N_INSNS (2);
05456
05457
05458 case NOT:
05459 case COMPARE:
05460 case ABS:
05461 case ZERO_EXTEND:
05462 total = extra_cost + rtx_cost (XEXP (x, 0), code);
05463 if (mode == QImode)
05464 {
05465 return total + COSTS_N_INSNS (1);
05466 }
05467 if (mode == HImode)
05468 {
05469 return total + COSTS_N_INSNS (2);
05470 }
05471 if (mode == SImode)
05472 {
05473 return total + COSTS_N_INSNS (4);
05474 }
05475 return total + COSTS_N_INSNS (8);
05476
05477 case IF_THEN_ELSE:
05478 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
05479 return COSTS_N_INSNS (1);
05480
05481 return COSTS_N_INSNS (1);
05482
05483 default:
05484 return COSTS_N_INSNS (4);
05485 }
05486 }
05487
05488
05489
05490
05491
05492 extern char *asm_file_name;
05493
05494 #include <time.h>
05495 #include <sys/types.h>
05496
05497 static void
05498 print_options (out)
05499 FILE *out;
05500 {
05501 const char *a_time;
05502 long c_time;
05503 int i;
05504 extern int save_argc;
05505 extern char **save_argv;
05506
05507 fprintf (out, ";;; Command:\t");
05508 for (i = 0; i < save_argc; i++)
05509 {
05510 fprintf (out, "%s", save_argv[i]);
05511 if (i + 1 < save_argc)
05512 fprintf (out, " ");
05513 }
05514 fprintf (out, "\n");
05515 c_time = time (0);
05516 a_time = ctime (&c_time);
05517 fprintf (out, ";;; Compiled:\t%s", a_time);
05518 #ifdef __GNUC__
05519 #ifndef __VERSION__
05520 #define __VERSION__ "[unknown]"
05521 #endif
05522 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
05523 #else
05524 fprintf (out, ";;; (META)compiled by CC.\n");
05525 #endif
05526 }
05527
05528 void
05529 m68hc11_asm_file_start (out, main_file)
05530 FILE *out;
05531 const char *main_file;
05532 {
05533 fprintf (out, ";;;-----------------------------------------\n");
05534 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
05535 fprintf (out, ";;; gcc compiler %s\n", version_string);
05536 print_options (out);
05537 fprintf (out, ";;;-----------------------------------------\n");
05538 output_file_directive (out, main_file);
05539 }
05540
05541
05542 static void
05543 m68hc11_add_gc_roots ()
05544 {
05545 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
05546 ggc_add_rtx_root (&ix_reg, 1);
05547 ggc_add_rtx_root (&iy_reg, 1);
05548 ggc_add_rtx_root (&d_reg, 1);
05549 ggc_add_rtx_root (&da_reg, 1);
05550 ggc_add_rtx_root (&z_reg, 1);
05551 ggc_add_rtx_root (&z_reg_qi, 1);
05552 ggc_add_rtx_root (&stack_push_word, 1);
05553 ggc_add_rtx_root (&stack_pop_word, 1);
05554 }
05555
05556 static void
05557 m68hc11_asm_out_constructor (symbol, priority)
05558 rtx symbol;
05559 int priority;
05560 {
05561 default_ctor_section_asm_out_constructor (symbol, priority);
05562 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
05563 }
05564
05565 static void
05566 m68hc11_asm_out_destructor (symbol, priority)
05567 rtx symbol;
05568 int priority;
05569 {
05570 default_dtor_section_asm_out_destructor (symbol, priority);
05571 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
05572 }