00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024 #include "system.h"
00025 #include "rtl.h"
00026 #include "regs.h"
00027 #include "hard-reg-set.h"
00028 #include "real.h"
00029 #include "insn-config.h"
00030 #include "conditions.h"
00031 #include "insn-flags.h"
00032 #include "output.h"
00033 #include "insn-attr.h"
00034 #include "flags.h"
00035 #include "recog.h"
00036 #include "toplev.h"
00037 #include "obstack.h"
00038 #include "tree.h"
00039 #include "expr.h"
00040 #include "optabs.h"
00041 #include "output.h"
00042 #include "except.h"
00043 #include "function.h"
00044 #include "target.h"
00045 #include "target-def.h"
00046 #include "tm_p.h"
00047
00048 static rtx emit_addhi3_postreload PARAMS ((rtx, rtx, rtx));
00049 static void xstormy16_asm_out_constructor PARAMS ((rtx, int));
00050 static void xstormy16_asm_out_destructor PARAMS ((rtx, int));
00051
00052
00053
00054 struct rtx_def * xstormy16_compare_op0;
00055 struct rtx_def * xstormy16_compare_op1;
00056
00057
00058
00059 int
00060 xstormy16_ineqsi_operator (op, mode)
00061 register rtx op;
00062 enum machine_mode mode;
00063 {
00064 enum rtx_code code = GET_CODE (op);
00065
00066 return ((mode == VOIDmode || GET_MODE (op) == mode)
00067 && (code == LT || code == GE || code == LTU || code == GEU));
00068 }
00069
00070
00071
00072 int
00073 equality_operator (op, mode)
00074 register rtx op;
00075 enum machine_mode mode;
00076 {
00077 return ((mode == VOIDmode || GET_MODE (op) == mode)
00078 && (GET_CODE (op) == EQ || GET_CODE (op) == NE));
00079 }
00080
00081
00082
00083 int
00084 inequality_operator (op, mode)
00085 register rtx op;
00086 enum machine_mode mode;
00087 {
00088 return comparison_operator (op, mode) && ! equality_operator (op, mode);
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 void
00117 xstormy16_emit_cbranch (code, loc)
00118 enum rtx_code code;
00119 rtx loc;
00120 {
00121 rtx op0 = xstormy16_compare_op0;
00122 rtx op1 = xstormy16_compare_op1;
00123 rtx condition_rtx, loc_ref, branch, cy_clobber;
00124 rtvec vec;
00125 enum machine_mode mode;
00126
00127 mode = GET_MODE (op0);
00128 if (mode != HImode && mode != SImode)
00129 abort ();
00130
00131 if (mode == SImode
00132 && (code == GT || code == LE || code == GTU || code == LEU))
00133 {
00134 int unsigned_p = (code == GTU || code == LEU);
00135 int gt_p = (code == GT || code == GTU);
00136 rtx lab = NULL_RTX;
00137
00138 if (gt_p)
00139 lab = gen_label_rtx ();
00140 xstormy16_emit_cbranch (unsigned_p ? LTU : LT, gt_p ? lab : loc);
00141
00142
00143 xstormy16_emit_cbranch (gt_p ? NE : EQ, loc);
00144 if (gt_p)
00145 emit_label (lab);
00146 return;
00147 }
00148 else if (mode == SImode
00149 && (code == NE || code == EQ)
00150 && op1 != const0_rtx)
00151 {
00152 rtx lab = NULL_RTX;
00153 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
00154 int i;
00155
00156 if (code == EQ)
00157 lab = gen_label_rtx ();
00158
00159 for (i = 0; i < num_words - 1; i++)
00160 {
00161 xstormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode,
00162 i * UNITS_PER_WORD);
00163 xstormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode,
00164 i * UNITS_PER_WORD);
00165 xstormy16_emit_cbranch (NE, code == EQ ? lab : loc);
00166 }
00167 xstormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode,
00168 i * UNITS_PER_WORD);
00169 xstormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode,
00170 i * UNITS_PER_WORD);
00171 xstormy16_emit_cbranch (code, loc);
00172
00173 if (code == EQ)
00174 emit_label (lab);
00175 return;
00176 }
00177
00178
00179
00180 if (mode != HImode)
00181 {
00182 rtx tmp;
00183 tmp = gen_reg_rtx (mode);
00184 emit_move_insn (tmp, op0);
00185 op0 = tmp;
00186 }
00187
00188 condition_rtx = gen_rtx (code, mode, op0, op1);
00189 loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
00190 branch = gen_rtx_SET (VOIDmode, pc_rtx,
00191 gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
00192 loc_ref, pc_rtx));
00193
00194 cy_clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (BImode));
00195
00196 if (mode == HImode)
00197 vec = gen_rtvec (2, branch, cy_clobber);
00198 else if (code == NE || code == EQ)
00199 vec = gen_rtvec (2, branch, gen_rtx_CLOBBER (VOIDmode, op0));
00200 else
00201 {
00202 rtx sub;
00203 #if 0
00204 sub = gen_rtx_SET (VOIDmode, op0, gen_rtx_MINUS (SImode, op0, op1));
00205 #else
00206 sub = gen_rtx_CLOBBER (SImode, op0);
00207 #endif
00208 vec = gen_rtvec (3, branch, sub, cy_clobber);
00209 }
00210
00211 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
00212 }
00213
00214
00215
00216
00217
00218 void
00219 xstormy16_split_cbranch (mode, label, comparison, dest, carry)
00220 enum machine_mode mode;
00221 rtx label;
00222 rtx comparison;
00223 rtx dest;
00224 rtx carry;
00225 {
00226 rtx op0 = XEXP (comparison, 0);
00227 rtx op1 = XEXP (comparison, 1);
00228 rtx seq;
00229 rtx compare;
00230
00231 start_sequence ();
00232 xstormy16_expand_arith (mode, COMPARE, dest, op0, op1, carry);
00233 seq = gen_sequence ();
00234 end_sequence ();
00235 compare = SET_SRC (XVECEXP (PATTERN (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)),
00236 0, 0));
00237 PUT_CODE (XEXP (compare, 0), GET_CODE (comparison));
00238 XEXP (compare, 1) = gen_rtx_LABEL_REF (VOIDmode, label);
00239 emit_insn (seq);
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 char *
00253 xstormy16_output_cbranch_hi (op, label, reversed, insn)
00254 rtx op;
00255 const char * label;
00256 int reversed;
00257 rtx insn;
00258 {
00259 static char string[64];
00260 int need_longbranch = (op != NULL_RTX
00261 ? get_attr_length (insn) == 8
00262 : get_attr_length (insn) == 4);
00263 int really_reversed = reversed ^ need_longbranch;
00264 const char *ccode;
00265 const char *template;
00266 const char *operands;
00267 enum rtx_code code;
00268
00269 if (! op)
00270 {
00271 if (need_longbranch)
00272 ccode = "jmpf";
00273 else
00274 ccode = "br";
00275 sprintf (string, "%s %s", ccode, label);
00276 return string;
00277 }
00278
00279 code = GET_CODE (op);
00280
00281 if (GET_CODE (XEXP (op, 0)) != REG)
00282 {
00283 code = swap_condition (code);
00284 operands = "%3,%2";
00285 }
00286 else
00287 operands = "%2,%3";
00288
00289
00290 if (really_reversed)
00291 code = reverse_condition (code);
00292
00293 switch (code)
00294 {
00295 case EQ: ccode = "z"; break;
00296 case NE: ccode = "nz"; break;
00297 case GE: ccode = "ge"; break;
00298 case LT: ccode = "lt"; break;
00299 case GT: ccode = "gt"; break;
00300 case LE: ccode = "le"; break;
00301 case GEU: ccode = "nc"; break;
00302 case LTU: ccode = "c"; break;
00303 case GTU: ccode = "hi"; break;
00304 case LEU: ccode = "ls"; break;
00305
00306 default:
00307 abort ();
00308 }
00309
00310 if (need_longbranch)
00311 template = "b%s %s,.+8 | jmpf %s";
00312 else
00313 template = "b%s %s,%s";
00314 sprintf (string, template, ccode, operands, label);
00315
00316 return string;
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 char *
00330 xstormy16_output_cbranch_si (op, label, reversed, insn)
00331 rtx op;
00332 const char * label;
00333 int reversed;
00334 rtx insn;
00335 {
00336 static char string[64];
00337 int need_longbranch = get_attr_length (insn) >= 8;
00338 int really_reversed = reversed ^ need_longbranch;
00339 const char *ccode;
00340 const char *template;
00341 char prevop[16];
00342 enum rtx_code code;
00343
00344 code = GET_CODE (op);
00345
00346
00347 if (really_reversed)
00348 code = reverse_condition (code);
00349
00350 switch (code)
00351 {
00352 case EQ: ccode = "z"; break;
00353 case NE: ccode = "nz"; break;
00354 case GE: ccode = "ge"; break;
00355 case LT: ccode = "lt"; break;
00356 case GEU: ccode = "nc"; break;
00357 case LTU: ccode = "c"; break;
00358
00359
00360 default:
00361 abort ();
00362 }
00363
00364 switch (code)
00365 {
00366 case EQ: case NE:
00367 {
00368 int regnum;
00369
00370 if (GET_CODE (XEXP (op, 0)) != REG)
00371 abort ();
00372
00373 regnum = REGNO (XEXP (op, 0));
00374 sprintf (prevop, "or %s,%s", reg_names[regnum], reg_names[regnum+1]);
00375 }
00376 break;
00377
00378 case GE: case LT: case GEU: case LTU:
00379 strcpy (prevop, "sbc %2,%3");
00380 break;
00381
00382 default:
00383 abort ();
00384 }
00385
00386 if (need_longbranch)
00387 template = "%s | b%s .+6 | jmpf %s";
00388 else
00389 template = "%s | b%s %s";
00390 sprintf (string, template, prevop, ccode, label);
00391
00392 return string;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 enum reg_class
00448 xstormy16_secondary_reload_class (class, mode, x)
00449 enum reg_class class;
00450 enum machine_mode mode;
00451 rtx x;
00452 {
00453
00454
00455 if ((GET_CODE (x) == MEM
00456 || ((GET_CODE (x) == SUBREG || GET_CODE (x) == REG)
00457 && (true_regnum (x) == -1
00458 || true_regnum (x) >= FIRST_PSEUDO_REGISTER)))
00459 && ! reg_class_subset_p (class, EIGHT_REGS))
00460 return EIGHT_REGS;
00461
00462
00463
00464 if (xstormy16_carry_plus_operand (x, mode))
00465 return CARRY_REGS;
00466
00467 return NO_REGS;
00468 }
00469
00470
00471 int
00472 xstormy16_carry_plus_operand (x, mode)
00473 rtx x;
00474 enum machine_mode mode ATTRIBUTE_UNUSED;
00475 {
00476 return (GET_CODE (x) == PLUS
00477 && GET_CODE (XEXP (x, 1)) == CONST_INT
00478 && (INTVAL (XEXP (x, 1)) < -4 || INTVAL (XEXP (x, 1)) > 4));
00479 }
00480
00481
00482 enum reg_class
00483 xstormy16_preferred_reload_class (x, class)
00484 enum reg_class class;
00485 rtx x;
00486 {
00487 if (class == GENERAL_REGS
00488 && GET_CODE (x) == MEM)
00489 return EIGHT_REGS;
00490
00491 return class;
00492 }
00493
00494 #define LEGITIMATE_ADDRESS_INTEGER_P(X, OFFSET) \
00495 (GET_CODE (X) == CONST_INT \
00496 && (unsigned HOST_WIDE_INT) (INTVAL (X) + (OFFSET) + 2048) < 4096)
00497
00498 #define LEGITIMATE_ADDRESS_CONST_INT_P(X, OFFSET) \
00499 (GET_CODE (X) == CONST_INT \
00500 && INTVAL (X) + (OFFSET) >= 0 \
00501 && INTVAL (X) + (OFFSET) < 0x8000 \
00502 && (INTVAL (X) + (OFFSET) < 0x100 || INTVAL (X) + (OFFSET) >= 0x7F00))
00503
00504 int
00505 xstormy16_legitimate_address_p (mode, x, strict)
00506 enum machine_mode mode ATTRIBUTE_UNUSED;
00507 rtx x;
00508 int strict;
00509 {
00510 if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0))
00511 return 1;
00512
00513 if (GET_CODE (x) == PLUS
00514 && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0))
00515 x = XEXP (x, 0);
00516
00517 if (GET_CODE (x) == POST_INC
00518 || GET_CODE (x) == PRE_DEC)
00519 x = XEXP (x, 0);
00520
00521 if (GET_CODE (x) == REG && REGNO_OK_FOR_BASE_P (REGNO (x))
00522 && (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER))
00523 return 1;
00524
00525 return 0;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 int
00545 xstormy16_mode_dependent_address_p (x)
00546 rtx x;
00547 {
00548 if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0)
00549 && ! LEGITIMATE_ADDRESS_CONST_INT_P (x, 6))
00550 return 1;
00551
00552 if (GET_CODE (x) == PLUS
00553 && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0)
00554 && ! LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 6))
00555 return 1;
00556
00557 if (GET_CODE (x) == PLUS)
00558 x = XEXP (x, 0);
00559
00560 if (GET_CODE (x) == POST_INC
00561 || GET_CODE (x) == PRE_DEC)
00562 return 1;
00563
00564 return 0;
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574 int
00575 xstormy16_extra_constraint_p (x, c)
00576 rtx x;
00577 int c;
00578 {
00579 switch (c)
00580 {
00581
00582 case 'Q':
00583 return (GET_CODE (x) == MEM
00584 && GET_CODE (XEXP (x, 0)) == POST_INC
00585 && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
00586
00587
00588 case 'R':
00589 return (GET_CODE (x) == MEM
00590 && GET_CODE (XEXP (x, 0)) == PRE_DEC
00591 && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
00592
00593
00594 case 'S':
00595 return (GET_CODE (x) == MEM
00596 && GET_CODE (XEXP (x, 0)) == CONST_INT
00597 && xstormy16_legitimate_address_p (VOIDmode, XEXP (x, 0), 0));
00598
00599
00600 case 'T':
00601
00602 return 0;
00603
00604
00605
00606 case 'U':
00607 return (GET_CODE (x) == CONST_INT
00608 && (INTVAL (x) < 2 || INTVAL (x) > 15));
00609
00610 default:
00611 return 0;
00612 }
00613 }
00614
00615 int
00616 short_memory_operand (x, mode)
00617 rtx x;
00618 enum machine_mode mode;
00619 {
00620 if (! memory_operand (x, mode))
00621 return 0;
00622 return (GET_CODE (XEXP (x, 0)) != PLUS);
00623 }
00624
00625 int
00626 nonimmediate_nonstack_operand (op, mode)
00627 rtx op;
00628 enum machine_mode mode;
00629 {
00630
00631 return (nonimmediate_operand (op, mode)
00632 && ! xstormy16_extra_constraint_p (op, 'Q')
00633 && ! xstormy16_extra_constraint_p (op, 'R'));
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643 void
00644 xstormy16_split_move (mode, dest, src)
00645 enum machine_mode mode;
00646 rtx dest;
00647 rtx src;
00648 {
00649 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
00650 int direction, end, i;
00651 int src_modifies = 0;
00652 int dest_modifies = 0;
00653 int src_volatile = 0;
00654 int dest_volatile = 0;
00655 rtx mem_operand;
00656 rtx auto_inc_reg_rtx = NULL_RTX;
00657
00658
00659 if (! reload_completed
00660 || mode == QImode || mode == HImode
00661 || ! nonimmediate_operand (dest, mode)
00662 || ! general_operand (src, mode))
00663 abort ();
00664
00665
00666 if (GET_CODE (dest) == MEM
00667 && GET_CODE (src) == MEM)
00668 abort ();
00669
00670
00671 if (GET_CODE (dest) == SUBREG
00672 || GET_CODE (src) == SUBREG)
00673 abort ();
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683 direction = 1;
00684
00685 if (GET_CODE (dest) == MEM)
00686 {
00687 mem_operand = XEXP (dest, 0);
00688 dest_modifies = side_effects_p (mem_operand);
00689 if (auto_inc_p (mem_operand))
00690 auto_inc_reg_rtx = XEXP (mem_operand, 0);
00691 dest_volatile = MEM_VOLATILE_P (dest);
00692 if (dest_volatile)
00693 {
00694 dest = copy_rtx (dest);
00695 MEM_VOLATILE_P (dest) = 0;
00696 }
00697 }
00698 else if (GET_CODE (src) == MEM)
00699 {
00700 mem_operand = XEXP (src, 0);
00701 src_modifies = side_effects_p (mem_operand);
00702 if (auto_inc_p (mem_operand))
00703 auto_inc_reg_rtx = XEXP (mem_operand, 0);
00704 src_volatile = MEM_VOLATILE_P (src);
00705 if (src_volatile)
00706 {
00707 src = copy_rtx (src);
00708 MEM_VOLATILE_P (src) = 0;
00709 }
00710 }
00711 else
00712 mem_operand = NULL_RTX;
00713
00714 if (mem_operand == NULL_RTX)
00715 {
00716 if (GET_CODE (src) == REG
00717 && GET_CODE (dest) == REG
00718 && reg_overlap_mentioned_p (dest, src)
00719 && REGNO (dest) > REGNO (src))
00720 direction = -1;
00721 }
00722 else if (GET_CODE (mem_operand) == PRE_DEC
00723 || (GET_CODE (mem_operand) == PLUS
00724 && GET_CODE (XEXP (mem_operand, 0)) == PRE_DEC))
00725 direction = -1;
00726 else if (GET_CODE (src) == MEM
00727 && reg_overlap_mentioned_p (dest, src))
00728 {
00729 int regno;
00730 if (GET_CODE (dest) != REG)
00731 abort ();
00732 regno = REGNO (dest);
00733
00734 if (! refers_to_regno_p (regno, regno + num_words, mem_operand, 0))
00735 abort ();
00736
00737 if (refers_to_regno_p (regno, regno + 1, mem_operand, 0))
00738 direction = -1;
00739 else if (refers_to_regno_p (regno + num_words - 1, regno + num_words,
00740 mem_operand, 0))
00741 direction = 1;
00742 else
00743
00744
00745
00746
00747 abort ();
00748 }
00749
00750 end = direction < 0 ? -1 : num_words;
00751 for (i = direction < 0 ? num_words - 1 : 0; i != end; i += direction)
00752 {
00753 rtx w_src, w_dest, insn;
00754
00755 if (src_modifies)
00756 w_src = gen_rtx_MEM (word_mode, mem_operand);
00757 else
00758 w_src = simplify_gen_subreg (word_mode, src, mode, i * UNITS_PER_WORD);
00759 if (src_volatile)
00760 MEM_VOLATILE_P (w_src) = 1;
00761 if (dest_modifies)
00762 w_dest = gen_rtx_MEM (word_mode, mem_operand);
00763 else
00764 w_dest = simplify_gen_subreg (word_mode, dest, mode,
00765 i * UNITS_PER_WORD);
00766 if (dest_volatile)
00767 MEM_VOLATILE_P (w_dest) = 1;
00768
00769
00770 if (GET_CODE (w_src) == SUBREG
00771 || GET_CODE (w_dest) == SUBREG)
00772 abort ();
00773
00774 insn = emit_insn (gen_rtx_SET (VOIDmode, w_dest, w_src));
00775 if (auto_inc_reg_rtx)
00776 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC,
00777 auto_inc_reg_rtx,
00778 REG_NOTES (insn));
00779 }
00780 }
00781
00782
00783
00784
00785 void
00786 xstormy16_expand_move (mode, dest, src)
00787 enum machine_mode mode;
00788 rtx dest;
00789 rtx src;
00790 {
00791
00792 if (! reload_in_progress
00793 && ! reload_completed
00794 && GET_CODE (dest) == MEM
00795 && (GET_CODE (XEXP (dest, 0)) != CONST_INT
00796 || ! xstormy16_legitimate_address_p (mode, XEXP (dest, 0), 0))
00797 && GET_CODE (src) != REG
00798 && GET_CODE (src) != SUBREG)
00799 src = copy_to_mode_reg (mode, src);
00800
00801
00802 if (reload_completed
00803 && mode != HImode && mode != QImode)
00804 {
00805 xstormy16_split_move (mode, dest, src);
00806 return;
00807 }
00808
00809 emit_insn (gen_rtx_SET (VOIDmode, dest, src));
00810 }
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833 struct xstormy16_stack_layout
00834 {
00835
00836 int locals_size;
00837 int register_save_size;
00838 int stdarg_save_size;
00839
00840 int frame_size;
00841
00842 int first_local_minus_ap;
00843 int sp_minus_fp;
00844 int fp_minus_ap;
00845 };
00846
00847
00848 #define REG_NEEDS_SAVE(REGNUM, IFUN) \
00849 ((regs_ever_live[REGNUM] && ! call_used_regs[REGNUM]) \
00850 || (IFUN && ! fixed_regs[REGNUM] && call_used_regs[REGNUM] \
00851 && (regs_ever_live[REGNUM] || ! current_function_is_leaf)))
00852
00853
00854 struct xstormy16_stack_layout
00855 xstormy16_compute_stack_layout ()
00856 {
00857 struct xstormy16_stack_layout layout;
00858 int regno;
00859 const int ifun = xstormy16_interrupt_function_p ();
00860
00861 layout.locals_size = get_frame_size ();
00862
00863 layout.register_save_size = 0;
00864 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
00865 if (REG_NEEDS_SAVE (regno, ifun))
00866 layout.register_save_size += UNITS_PER_WORD;
00867
00868 if (current_function_varargs || current_function_stdarg)
00869 layout.stdarg_save_size = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
00870 else
00871 layout.stdarg_save_size = 0;
00872
00873 layout.frame_size = (layout.locals_size
00874 + layout.register_save_size
00875 + layout.stdarg_save_size);
00876
00877 if (current_function_args_size <= 2048 && current_function_args_size != -1)
00878 {
00879 if (layout.frame_size + INCOMING_FRAME_SP_OFFSET
00880 + current_function_args_size <= 2048)
00881 layout.fp_minus_ap = layout.frame_size + INCOMING_FRAME_SP_OFFSET;
00882 else
00883 layout.fp_minus_ap = 2048 - current_function_args_size;
00884 }
00885 else
00886 layout.fp_minus_ap = (layout.stdarg_save_size
00887 + layout.register_save_size
00888 + INCOMING_FRAME_SP_OFFSET);
00889 layout.sp_minus_fp = (layout.frame_size + INCOMING_FRAME_SP_OFFSET
00890 - layout.fp_minus_ap);
00891 layout.first_local_minus_ap = layout.sp_minus_fp - layout.locals_size;
00892 return layout;
00893 }
00894
00895
00896 int
00897 xstormy16_initial_elimination_offset (from, to)
00898 int from, to;
00899 {
00900 struct xstormy16_stack_layout layout;
00901 int result;
00902
00903 layout = xstormy16_compute_stack_layout ();
00904
00905 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
00906 result = layout.sp_minus_fp - layout.locals_size;
00907 else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
00908 result = -layout.locals_size;
00909 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
00910 result = -layout.fp_minus_ap;
00911 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
00912 result = -(layout.sp_minus_fp + layout.fp_minus_ap);
00913 else
00914 abort ();
00915
00916 return result;
00917 }
00918
00919 static rtx
00920 emit_addhi3_postreload (dest, src0, src1)
00921 rtx dest;
00922 rtx src0;
00923 rtx src1;
00924 {
00925 rtx set, clobber, insn;
00926
00927 set = gen_rtx_SET (VOIDmode, dest, gen_rtx_PLUS (HImode, src0, src1));
00928 clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (BImode, 16));
00929 insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
00930 return insn;
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943 void
00944 xstormy16_expand_prologue ()
00945 {
00946 struct xstormy16_stack_layout layout;
00947 int regno;
00948 rtx insn;
00949 rtx mem_push_rtx;
00950 rtx mem_fake_push_rtx;
00951 const int ifun = xstormy16_interrupt_function_p ();
00952
00953 mem_push_rtx = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
00954 mem_push_rtx = gen_rtx_MEM (HImode, mem_push_rtx);
00955 mem_fake_push_rtx = gen_rtx_PRE_INC (Pmode, stack_pointer_rtx);
00956 mem_fake_push_rtx = gen_rtx_MEM (HImode, mem_fake_push_rtx);
00957
00958 layout = xstormy16_compute_stack_layout ();
00959
00960
00961 if (layout.stdarg_save_size)
00962 for (regno = FIRST_ARGUMENT_REGISTER;
00963 regno < FIRST_ARGUMENT_REGISTER + NUM_ARGUMENT_REGISTERS;
00964 regno++)
00965 {
00966 rtx reg = gen_rtx_REG (HImode, regno);
00967 insn = emit_move_insn (mem_push_rtx, reg);
00968 RTX_FRAME_RELATED_P (insn) = 1;
00969 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
00970 gen_rtx_SET (VOIDmode,
00971 mem_fake_push_rtx,
00972 reg),
00973 REG_NOTES (insn));
00974 }
00975
00976
00977 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
00978 if (REG_NEEDS_SAVE (regno, ifun))
00979 {
00980 rtx reg = gen_rtx_REG (HImode, regno);
00981 insn = emit_move_insn (mem_push_rtx, reg);
00982 RTX_FRAME_RELATED_P (insn) = 1;
00983 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
00984 gen_rtx_SET (VOIDmode,
00985 mem_fake_push_rtx,
00986 reg),
00987 REG_NOTES (insn));
00988 }
00989
00990
00991
00992 if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
00993 {
00994 insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
00995 RTX_FRAME_RELATED_P (insn) = 1;
00996 }
00997
00998
00999 if (layout.locals_size)
01000 {
01001 insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
01002 GEN_INT (layout.locals_size));
01003 RTX_FRAME_RELATED_P (insn) = 1;
01004 }
01005
01006
01007 if (frame_pointer_needed && layout.sp_minus_fp != layout.locals_size)
01008 {
01009 insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
01010 RTX_FRAME_RELATED_P (insn) = 1;
01011 if (layout.sp_minus_fp)
01012 {
01013 insn = emit_addhi3_postreload (hard_frame_pointer_rtx,
01014 hard_frame_pointer_rtx,
01015 GEN_INT (-layout.sp_minus_fp));
01016 RTX_FRAME_RELATED_P (insn) = 1;
01017 }
01018 }
01019 }
01020
01021
01022 int
01023 direct_return ()
01024 {
01025 return (reload_completed
01026 && xstormy16_compute_stack_layout ().frame_size == 0);
01027 }
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 void
01038 xstormy16_expand_epilogue ()
01039 {
01040 struct xstormy16_stack_layout layout;
01041 rtx mem_pop_rtx;
01042 int regno;
01043 const int ifun = xstormy16_interrupt_function_p ();
01044
01045 mem_pop_rtx = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
01046 mem_pop_rtx = gen_rtx_MEM (HImode, mem_pop_rtx);
01047
01048 layout = xstormy16_compute_stack_layout ();
01049
01050
01051 if (layout.locals_size)
01052 {
01053 if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
01054 emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
01055 else
01056 emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
01057 GEN_INT (- layout.locals_size));
01058 }
01059
01060
01061 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
01062 if (REG_NEEDS_SAVE (regno, ifun))
01063 emit_move_insn (gen_rtx_REG (HImode, regno), mem_pop_rtx);
01064
01065
01066 if (layout.stdarg_save_size)
01067 emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
01068 GEN_INT (- layout.stdarg_save_size));
01069
01070
01071 if (ifun)
01072 emit_jump_insn (gen_return_internal_interrupt ());
01073 else
01074 emit_jump_insn (gen_return_internal ());
01075 }
01076
01077 int
01078 xstormy16_epilogue_uses (regno)
01079 int regno;
01080 {
01081 if (reload_completed && call_used_regs[regno])
01082 {
01083 const int ifun = xstormy16_interrupt_function_p ();
01084 return REG_NEEDS_SAVE (regno, ifun);
01085 }
01086 return 0;
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100 CUMULATIVE_ARGS
01101 xstormy16_function_arg_advance (cum, mode, type, named)
01102 CUMULATIVE_ARGS cum;
01103 enum machine_mode mode;
01104 tree type;
01105 int named ATTRIBUTE_UNUSED;
01106 {
01107
01108
01109
01110 if (cum < NUM_ARGUMENT_REGISTERS
01111 && cum + XSTORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS)
01112 cum = NUM_ARGUMENT_REGISTERS;
01113
01114 cum += XSTORMY16_WORD_SIZE (type, mode);
01115
01116 return cum;
01117 }
01118
01119
01120
01121 void
01122 xstormy16_setup_incoming_varargs (cum, int_mode, type, pretend_size)
01123 CUMULATIVE_ARGS cum ATTRIBUTE_UNUSED;
01124 int int_mode ATTRIBUTE_UNUSED;
01125 tree type ATTRIBUTE_UNUSED;
01126 int * pretend_size ATTRIBUTE_UNUSED;
01127 {
01128 }
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138 tree
01139 xstormy16_build_va_list ()
01140 {
01141 tree f_1, f_2, record, type_decl;
01142
01143 record = make_lang_type (RECORD_TYPE);
01144 type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
01145
01146 f_1 = build_decl (FIELD_DECL, get_identifier ("base"),
01147 ptr_type_node);
01148 f_2 = build_decl (FIELD_DECL, get_identifier ("count"),
01149 unsigned_type_node);
01150
01151 DECL_FIELD_CONTEXT (f_1) = record;
01152 DECL_FIELD_CONTEXT (f_2) = record;
01153
01154 TREE_CHAIN (record) = type_decl;
01155 TYPE_NAME (record) = type_decl;
01156 TYPE_FIELDS (record) = f_1;
01157 TREE_CHAIN (f_1) = f_2;
01158
01159 layout_type (record);
01160
01161 return record;
01162 }
01163
01164
01165
01166
01167
01168 void
01169 xstormy16_expand_builtin_va_start (stdarg_p, valist, nextarg)
01170 int stdarg_p ATTRIBUTE_UNUSED;
01171 tree valist;
01172 rtx nextarg ATTRIBUTE_UNUSED;
01173 {
01174 tree f_base, f_count;
01175 tree base, count;
01176 tree t;
01177
01178 if (xstormy16_interrupt_function_p ())
01179 error ("cannot use va_start in interrupt function");
01180
01181 f_base = TYPE_FIELDS (va_list_type_node);
01182 f_count = TREE_CHAIN (f_base);
01183
01184 base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
01185 count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
01186
01187 t = make_tree (TREE_TYPE (base), virtual_incoming_args_rtx);
01188 t = build (PLUS_EXPR, TREE_TYPE (base), t,
01189 build_int_2 (INCOMING_FRAME_SP_OFFSET, 0));
01190 t = build (MODIFY_EXPR, TREE_TYPE (base), base, t);
01191 TREE_SIDE_EFFECTS (t) = 1;
01192 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01193
01194 t = build (MODIFY_EXPR, TREE_TYPE (count), count,
01195 build_int_2 (current_function_args_info * UNITS_PER_WORD, 0));
01196 TREE_SIDE_EFFECTS (t) = 1;
01197 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01198 }
01199
01200
01201
01202
01203
01204 rtx
01205 xstormy16_expand_builtin_va_arg (valist, type)
01206 tree valist;
01207 tree type;
01208 {
01209 tree f_base, f_count;
01210 tree base, count;
01211 rtx count_rtx, addr_rtx, r;
01212 rtx lab_gotaddr, lab_fromstack;
01213 tree t;
01214 int size, size_of_reg_args;
01215 tree size_tree, count_plus_size;
01216 rtx count_plus_size_rtx;
01217
01218 f_base = TYPE_FIELDS (va_list_type_node);
01219 f_count = TREE_CHAIN (f_base);
01220
01221 base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
01222 count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
01223
01224 size = PUSH_ROUNDING (int_size_in_bytes (type));
01225 size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
01226
01227 size_of_reg_args = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
01228
01229 count_rtx = expand_expr (count, NULL_RTX, HImode, EXPAND_NORMAL);
01230 lab_gotaddr = gen_label_rtx ();
01231 lab_fromstack = gen_label_rtx ();
01232 addr_rtx = gen_reg_rtx (Pmode);
01233
01234 count_plus_size = build (PLUS_EXPR, TREE_TYPE (count), count, size_tree);
01235 count_plus_size_rtx = expand_expr (count_plus_size, NULL_RTX, HImode, EXPAND_NORMAL);
01236 emit_cmp_and_jump_insns (count_plus_size_rtx, GEN_INT (size_of_reg_args),
01237 GTU, const1_rtx, HImode, 1, lab_fromstack);
01238
01239 t = build (PLUS_EXPR, ptr_type_node, base, count);
01240 r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
01241 if (r != addr_rtx)
01242 emit_move_insn (addr_rtx, r);
01243
01244 emit_jump_insn (gen_jump (lab_gotaddr));
01245 emit_barrier ();
01246 emit_label (lab_fromstack);
01247
01248
01249
01250
01251 if (size > 2 || size < 0)
01252 {
01253 rtx lab_notransition = gen_label_rtx ();
01254 emit_cmp_and_jump_insns (count_rtx, GEN_INT (NUM_ARGUMENT_REGISTERS
01255 * UNITS_PER_WORD),
01256 GEU, const1_rtx, HImode, 1, lab_notransition);
01257
01258 t = build (MODIFY_EXPR, TREE_TYPE (count), count,
01259 build_int_2 (NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD, 0));
01260 TREE_SIDE_EFFECTS (t) = 1;
01261 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01262
01263 emit_label (lab_notransition);
01264 }
01265
01266 t = build (PLUS_EXPR, sizetype, size_tree,
01267 build_int_2 ((- NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD
01268 + INCOMING_FRAME_SP_OFFSET),
01269 -1));
01270 t = build (PLUS_EXPR, TREE_TYPE (count), count, fold (t));
01271 t = build (MINUS_EXPR, TREE_TYPE (base), base, t);
01272 r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
01273 if (r != addr_rtx)
01274 emit_move_insn (addr_rtx, r);
01275
01276 emit_label (lab_gotaddr);
01277
01278 count_plus_size = build (PLUS_EXPR, TREE_TYPE (count), count, size_tree);
01279 t = build (MODIFY_EXPR, TREE_TYPE (count), count, count_plus_size);
01280 TREE_SIDE_EFFECTS (t) = 1;
01281 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01282
01283 return addr_rtx;
01284 }
01285
01286
01287
01288
01289
01290 void
01291 xstormy16_initialize_trampoline (addr, fnaddr, static_chain)
01292 rtx addr;
01293 rtx fnaddr;
01294 rtx static_chain;
01295 {
01296 rtx reg_addr = gen_reg_rtx (Pmode);
01297 rtx temp = gen_reg_rtx (HImode);
01298 rtx reg_fnaddr = gen_reg_rtx (HImode);
01299 rtx reg_addr_mem;
01300
01301 reg_addr_mem = gen_rtx_MEM (HImode, reg_addr);
01302
01303 emit_move_insn (reg_addr, addr);
01304 emit_move_insn (temp, GEN_INT (0x3130 | STATIC_CHAIN_REGNUM));
01305 emit_move_insn (reg_addr_mem, temp);
01306 emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
01307 emit_move_insn (temp, static_chain);
01308 emit_move_insn (reg_addr_mem, temp);
01309 emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
01310 emit_move_insn (reg_fnaddr, fnaddr);
01311 emit_move_insn (temp, reg_fnaddr);
01312 emit_insn (gen_andhi3 (temp, temp, GEN_INT (0xFF)));
01313 emit_insn (gen_iorhi3 (temp, temp, GEN_INT (0x0200)));
01314 emit_move_insn (reg_addr_mem, temp);
01315 emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
01316 emit_insn (gen_lshrhi3 (reg_fnaddr, reg_fnaddr, GEN_INT (8)));
01317 emit_move_insn (reg_addr_mem, reg_fnaddr);
01318 }
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338 rtx
01339 xstormy16_function_value (valtype, func)
01340 tree valtype;
01341 tree func ATTRIBUTE_UNUSED;
01342 {
01343 enum machine_mode mode;
01344 mode = TYPE_MODE (valtype);
01345 PROMOTE_MODE (mode, 0, valtype);
01346 return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
01347 }
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375 void
01376 xstormy16_asm_output_mi_thunk (file, thunk_fndecl, delta, function)
01377 FILE *file;
01378 tree thunk_fndecl ATTRIBUTE_UNUSED;
01379 int delta;
01380 tree function;
01381 {
01382 int regnum = FIRST_ARGUMENT_REGISTER;
01383
01384
01385 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
01386 regnum += 1;
01387
01388 fprintf (file, "\tadd %s,#0x%x\n", reg_names[regnum], (delta) & 0xFFFF);
01389 fputs ("\tjmpf ", file);
01390 assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
01391 putc ('\n', file);
01392 }
01393
01394
01395
01396 void
01397 xstormy16_encode_section_info (decl)
01398 tree decl;
01399 {
01400 if (TREE_CODE (decl) == FUNCTION_DECL)
01401 SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
01402 }
01403
01404
01405
01406 #undef TARGET_ASM_CONSTRUCTOR
01407 #define TARGET_ASM_CONSTRUCTOR xstormy16_asm_out_constructor
01408 #undef TARGET_ASM_DESTRUCTOR
01409 #define TARGET_ASM_DESTRUCTOR xstormy16_asm_out_destructor
01410
01411 static void
01412 xstormy16_asm_out_destructor (symbol, priority)
01413 rtx symbol;
01414 int priority;
01415 {
01416 const char *section = ".dtors";
01417 char buf[16];
01418
01419
01420 if (priority != DEFAULT_INIT_PRIORITY)
01421 {
01422 sprintf (buf, ".dtors.%.5u",
01423
01424
01425
01426 MAX_INIT_PRIORITY - priority);
01427 section = buf;
01428 }
01429
01430 named_section_flags (section, 0);
01431 assemble_align (POINTER_SIZE);
01432 assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
01433 }
01434
01435 static void
01436 xstormy16_asm_out_constructor (symbol, priority)
01437 rtx symbol;
01438 int priority;
01439 {
01440 const char *section = ".ctors";
01441 char buf[16];
01442
01443
01444 if (priority != DEFAULT_INIT_PRIORITY)
01445 {
01446 sprintf (buf, ".ctors.%.5u",
01447
01448
01449
01450 MAX_INIT_PRIORITY - priority);
01451 section = buf;
01452 }
01453
01454 named_section_flags (section, 0);
01455 assemble_align (POINTER_SIZE);
01456 assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
01457 }
01458
01459
01460 void
01461 xstormy16_print_operand_address (file, address)
01462 FILE * file;
01463 rtx address;
01464 {
01465 HOST_WIDE_INT offset;
01466 int pre_dec, post_inc;
01467
01468
01469 if (GET_CODE (address) == CONST_INT)
01470 {
01471 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (address) & 0xFFFF);
01472 return;
01473 }
01474
01475 if (CONSTANT_P (address) || GET_CODE (address) == CODE_LABEL)
01476 {
01477 output_addr_const (file, address);
01478 return;
01479 }
01480
01481
01482
01483
01484
01485 if (GET_CODE (address) == PLUS)
01486 {
01487 if (GET_CODE (XEXP (address, 1)) != CONST_INT)
01488 abort ();
01489 offset = INTVAL (XEXP (address, 1));
01490 address = XEXP (address, 0);
01491 }
01492 else
01493 offset = 0;
01494
01495 pre_dec = (GET_CODE (address) == PRE_DEC);
01496 post_inc = (GET_CODE (address) == POST_INC);
01497 if (pre_dec || post_inc)
01498 address = XEXP (address, 0);
01499
01500 if (GET_CODE (address) != REG)
01501 abort ();
01502
01503 fputc ('(', file);
01504 if (pre_dec)
01505 fputs ("--", file);
01506 fputs (reg_names [REGNO (address)], file);
01507 if (post_inc)
01508 fputs ("++", file);
01509 if (offset != 0)
01510 {
01511 fputc (',', file);
01512 fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
01513 }
01514 fputc (')', file);
01515 }
01516
01517
01518 void
01519 xstormy16_print_operand (file, x, code)
01520 FILE * file;
01521 rtx x;
01522 int code;
01523 {
01524 switch (code)
01525 {
01526 case 'B':
01527
01528
01529 {
01530 HOST_WIDE_INT xx = 1;
01531 HOST_WIDE_INT l;
01532
01533 if (GET_CODE (x) == CONST_INT)
01534 xx = INTVAL (x);
01535 else
01536 output_operand_lossage ("`B' operand is not constant");
01537
01538 l = exact_log2 (xx);
01539 if (l == -1)
01540 l = exact_log2 (~xx);
01541 if (l == -1)
01542 output_operand_lossage ("`B' operand has multiple bits set");
01543
01544 fputs (IMMEDIATE_PREFIX, file);
01545 fprintf (file, HOST_WIDE_INT_PRINT_DEC, l);
01546 return;
01547 }
01548
01549 case 'C':
01550
01551 if (GET_CODE (x) == SYMBOL_REF)
01552 assemble_name (file, XSTR (x, 0));
01553 else if (GET_CODE (x) == LABEL_REF)
01554 output_asm_label (x);
01555 else
01556 xstormy16_print_operand_address (file, x);
01557 return;
01558
01559 case 'o':
01560 case 'O':
01561
01562
01563 {
01564 HOST_WIDE_INT xx = 0;
01565
01566 if (GET_CODE (x) == CONST_INT)
01567 xx = INTVAL (x);
01568 else
01569 output_operand_lossage ("`o' operand is not constant");
01570
01571 if (code == 'O')
01572 xx = -xx;
01573
01574 fputs (IMMEDIATE_PREFIX, file);
01575 fprintf (file, HOST_WIDE_INT_PRINT_DEC, xx - 1);
01576 return;
01577 }
01578
01579 case 0:
01580
01581 break;
01582
01583 default:
01584 output_operand_lossage ("xstormy16_print_operand: unknown code");
01585 return;
01586 }
01587
01588 switch (GET_CODE (x))
01589 {
01590 case REG:
01591 fputs (reg_names [REGNO (x)], file);
01592 break;
01593
01594 case MEM:
01595 xstormy16_print_operand_address (file, XEXP (x, 0));
01596 break;
01597
01598 default:
01599
01600
01601 fputs (IMMEDIATE_PREFIX, file);
01602 output_addr_const (file, x);
01603 break;
01604 }
01605
01606 return;
01607 }
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620 void
01621 xstormy16_expand_casesi (index, lower_bound, range, table, default_label)
01622 rtx index;
01623 rtx lower_bound;
01624 rtx range;
01625 rtx table;
01626 rtx default_label;
01627 {
01628 HOST_WIDE_INT range_i = INTVAL (range);
01629 rtx int_index;
01630
01631
01632
01633 if (range_i >= 8192)
01634 sorry ("switch statement of size %lu entries too large",
01635 (unsigned long) range_i);
01636
01637 index = expand_binop (SImode, sub_optab, index, lower_bound, NULL_RTX, 0,
01638 OPTAB_LIB_WIDEN);
01639 emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, SImode, 1,
01640 default_label);
01641 int_index = gen_lowpart_common (HImode, index);
01642 emit_insn (gen_ashlhi3 (int_index, int_index, GEN_INT (2)));
01643 emit_jump_insn (gen_tablejump_pcrel (int_index, table));
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654 void
01655 xstormy16_output_addr_vec (file, label, table)
01656 FILE *file;
01657 rtx label ATTRIBUTE_UNUSED;
01658 rtx table;
01659 {
01660 int vlen, idx;
01661
01662 function_section (current_function_decl);
01663
01664 vlen = XVECLEN (table, 0);
01665 for (idx = 0; idx < vlen; idx++)
01666 {
01667 fputs ("\tjmpf ", file);
01668 output_asm_label (XEXP (XVECEXP (table, 0, idx), 0));
01669 fputc ('\n', file);
01670 }
01671 }
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684 void
01685 xstormy16_expand_call (retval, dest, counter)
01686 rtx retval;
01687 rtx dest;
01688 rtx counter;
01689 {
01690 rtx call, temp;
01691 enum machine_mode mode;
01692
01693 if (GET_CODE (dest) != MEM)
01694 abort ();
01695 dest = XEXP (dest, 0);
01696
01697 if (! CONSTANT_P (dest)
01698 && GET_CODE (dest) != REG)
01699 dest = force_reg (Pmode, dest);
01700
01701 if (retval == NULL)
01702 mode = VOIDmode;
01703 else
01704 mode = GET_MODE (retval);
01705
01706 call = gen_rtx_CALL (mode, gen_rtx_MEM (FUNCTION_MODE, dest),
01707 counter);
01708 if (retval)
01709 call = gen_rtx_SET (VOIDmode, retval, call);
01710
01711 if (! CONSTANT_P (dest))
01712 {
01713 temp = gen_reg_rtx (HImode);
01714 emit_move_insn (temp, const0_rtx);
01715 }
01716 else
01717 temp = const0_rtx;
01718
01719 call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call,
01720 gen_rtx_USE (VOIDmode, temp)));
01721 emit_call_insn (call);
01722 }
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 void
01735 xstormy16_expand_arith (mode, code, dest, src0, src1, carry)
01736 enum machine_mode mode;
01737 enum rtx_code code;
01738 rtx dest;
01739 rtx src0;
01740 rtx src1;
01741 rtx carry;
01742 {
01743 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
01744 int i;
01745 int firstloop = 1;
01746
01747 if (code == NEG)
01748 {
01749 rtx zero_reg = gen_reg_rtx (word_mode);
01750 emit_move_insn (zero_reg, src0);
01751 src0 = zero_reg;
01752 }
01753
01754 for (i = 0; i < num_words; i++)
01755 {
01756 rtx w_src0, w_src1, w_dest;
01757 rtx insn;
01758
01759 if (code == NEG)
01760 w_src0 = src0;
01761 else
01762 w_src0 = simplify_gen_subreg (word_mode, src0, mode,
01763 i * UNITS_PER_WORD);
01764 w_src1 = simplify_gen_subreg (word_mode, src1, mode, i * UNITS_PER_WORD);
01765 w_dest = simplify_gen_subreg (word_mode, dest, mode, i * UNITS_PER_WORD);
01766
01767 switch (code)
01768 {
01769 case PLUS:
01770 if (firstloop
01771 && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
01772 continue;
01773
01774 if (firstloop)
01775 insn = gen_addchi4 (w_dest, w_src0, w_src1, carry);
01776 else
01777 insn = gen_addchi5 (w_dest, w_src0, w_src1, carry, carry);
01778 break;
01779
01780 case NEG:
01781 case MINUS:
01782 case COMPARE:
01783 if (code == COMPARE && i == num_words - 1)
01784 {
01785 rtx branch, sub, clobber, sub_1;
01786
01787 sub_1 = gen_rtx_MINUS (HImode, w_src0,
01788 gen_rtx_ZERO_EXTEND (HImode, carry));
01789 sub = gen_rtx_SET (VOIDmode, w_dest,
01790 gen_rtx_MINUS (HImode, sub_1, w_src1));
01791 clobber = gen_rtx_CLOBBER (VOIDmode, carry);
01792 branch = gen_rtx_SET (VOIDmode, pc_rtx,
01793 gen_rtx_IF_THEN_ELSE (VOIDmode,
01794 gen_rtx_EQ (HImode,
01795 sub_1,
01796 w_src1),
01797 pc_rtx,
01798 pc_rtx));
01799 insn = gen_rtx_PARALLEL (VOIDmode,
01800 gen_rtvec (3, branch, sub, clobber));
01801 }
01802 else if (firstloop
01803 && code != COMPARE
01804 && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
01805 continue;
01806 else if (firstloop)
01807 insn = gen_subchi4 (w_dest, w_src0, w_src1, carry);
01808 else
01809 insn = gen_subchi5 (w_dest, w_src0, w_src1, carry, carry);
01810 break;
01811
01812 case IOR:
01813 case XOR:
01814 case AND:
01815 if (GET_CODE (w_src1) == CONST_INT
01816 && INTVAL (w_src1) == -(code == AND))
01817 continue;
01818
01819 insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx (code, mode,
01820 w_src0, w_src1));
01821 break;
01822
01823 case NOT:
01824 insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_NOT (mode, w_src0));
01825 break;
01826
01827 default:
01828 abort ();
01829 }
01830
01831 firstloop = 0;
01832 emit (insn);
01833 }
01834 }
01835
01836
01837
01838 int
01839 shift_operator (op, mode)
01840 register rtx op;
01841 enum machine_mode mode ATTRIBUTE_UNUSED;
01842 {
01843 enum rtx_code code = GET_CODE (op);
01844
01845 return (code == ASHIFT
01846 || code == ASHIFTRT
01847 || code == LSHIFTRT);
01848 }
01849
01850
01851
01852
01853
01854
01855
01856 const char *
01857 xstormy16_output_shift (mode, code, x, size_r, temp)
01858 enum machine_mode mode;
01859 enum rtx_code code;
01860 rtx x;
01861 rtx size_r;
01862 rtx temp;
01863 {
01864 HOST_WIDE_INT size;
01865 const char *r0, *r1, *rt;
01866 static char r[64];
01867
01868 if (GET_CODE (size_r) != CONST_INT
01869 || GET_CODE (x) != REG
01870 || mode != SImode)
01871 abort ();
01872 size = INTVAL (size_r) & (GET_MODE_BITSIZE (mode) - 1);
01873
01874 if (size == 0)
01875 return "";
01876
01877 r0 = reg_names [REGNO (x)];
01878 r1 = reg_names [REGNO (x) + 1];
01879
01880
01881 if (size == 1)
01882 {
01883 switch (code)
01884 {
01885 case ASHIFT:
01886 sprintf (r, "shl %s,#1 | rlc %s,#1", r0, r1);
01887 break;
01888 case ASHIFTRT:
01889 sprintf (r, "asr %s,#1 | rrc %s,#1", r1, r0);
01890 break;
01891 case LSHIFTRT:
01892 sprintf (r, "shr %s,#1 | rrc %s,#1", r1, r0);
01893 break;
01894 default:
01895 abort ();
01896 }
01897 return r;
01898 }
01899
01900
01901 if (size == 16)
01902 {
01903 switch (code)
01904 {
01905 case ASHIFT:
01906 sprintf (r, "mov %s,%s | mov %s,#0", r1, r0, r0);
01907 break;
01908 case ASHIFTRT:
01909 sprintf (r, "mov %s,%s | asr %s,#15", r0, r1, r1);
01910 break;
01911 case LSHIFTRT:
01912 sprintf (r, "mov %s,%s | mov %s,#0", r0, r1, r1);
01913 break;
01914 default:
01915 abort ();
01916 }
01917 return r;
01918 }
01919 if (size > 16)
01920 {
01921 switch (code)
01922 {
01923 case ASHIFT:
01924 sprintf (r, "mov %s,%s | mov %s,#0 | shl %s,#%d",
01925 r1, r0, r0, r1, (int) size - 16);
01926 break;
01927 case ASHIFTRT:
01928 sprintf (r, "mov %s,%s | asr %s,#15 | asr %s,#%d",
01929 r0, r1, r1, r0, (int) size - 16);
01930 break;
01931 case LSHIFTRT:
01932 sprintf (r, "mov %s,%s | mov %s,#0 | shr %s,#%d",
01933 r0, r1, r1, r0, (int) size - 16);
01934 break;
01935 default:
01936 abort ();
01937 }
01938 return r;
01939 }
01940
01941
01942
01943 rt = reg_names [REGNO (temp)];
01944 switch (code)
01945 {
01946 case ASHIFT:
01947 sprintf (r,
01948 "mov %s,%s | shl %s,#%d | shl %s,#%d | shr %s,#%d | or %s,%s",
01949 rt, r0, r0, (int) size, r1, (int) size, rt, (int) 16-size,
01950 r1, rt);
01951 break;
01952 case ASHIFTRT:
01953 sprintf (r,
01954 "mov %s,%s | asr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s",
01955 rt, r1, r1, (int) size, r0, (int) size, rt, (int) 16-size,
01956 r0, rt);
01957 break;
01958 case LSHIFTRT:
01959 sprintf (r,
01960 "mov %s,%s | shr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s",
01961 rt, r1, r1, (int) size, r0, (int) size, rt, (int) 16-size,
01962 r0, rt);
01963 break;
01964 default:
01965 abort ();
01966 }
01967 return r;
01968 }
01969
01970
01971
01972
01973 int
01974 xstormy16_interrupt_function_p ()
01975 {
01976 tree attributes;
01977
01978
01979
01980
01981 if (!cfun)
01982 return 0;
01983
01984 attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
01985 return lookup_attribute ("interrupt", attributes) != NULL_TREE;
01986 }
01987
01988 #undef TARGET_ATTRIBUTE_TABLE
01989 #define TARGET_ATTRIBUTE_TABLE xstormy16_attribute_table
01990 static tree xstormy16_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
01991 static const struct attribute_spec xstormy16_attribute_table[] =
01992 {
01993
01994 { "interrupt", 0, 0, false, true, true, xstormy16_handle_interrupt_attribute },
01995 { NULL, 0, 0, false, false, false, NULL }
01996 };
01997
01998
01999
02000 static tree
02001 xstormy16_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
02002 tree *node;
02003 tree name;
02004 tree args ATTRIBUTE_UNUSED;
02005 int flags ATTRIBUTE_UNUSED;
02006 bool *no_add_attrs;
02007 {
02008 if (TREE_CODE (*node) != FUNCTION_TYPE)
02009 {
02010 warning ("`%s' attribute only applies to functions",
02011 IDENTIFIER_POINTER (name));
02012 *no_add_attrs = true;
02013 }
02014
02015 return NULL_TREE;
02016 }
02017
02018 #undef TARGET_ASM_ALIGNED_HI_OP
02019 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
02020 #undef TARGET_ASM_ALIGNED_SI_OP
02021 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
02022
02023 struct gcc_target targetm = TARGET_INITIALIZER;