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 "coretypes.h"
00026 #include "tm.h"
00027 #include "rtl.h"
00028 #include "regs.h"
00029 #include "hard-reg-set.h"
00030 #include "real.h"
00031 #include "insn-config.h"
00032 #include "conditions.h"
00033 #include "insn-flags.h"
00034 #include "output.h"
00035 #include "insn-attr.h"
00036 #include "flags.h"
00037 #include "recog.h"
00038 #include "toplev.h"
00039 #include "obstack.h"
00040 #include "tree.h"
00041 #include "expr.h"
00042 #include "optabs.h"
00043 #include "except.h"
00044 #include "function.h"
00045 #include "target.h"
00046 #include "target-def.h"
00047 #include "tm_p.h"
00048 #include "langhooks.h"
00049 #include "tree-gimple.h"
00050 #include "ggc.h"
00051
00052 static rtx emit_addhi3_postreload (rtx, rtx, rtx);
00053 static void xstormy16_asm_out_constructor (rtx, int);
00054 static void xstormy16_asm_out_destructor (rtx, int);
00055 static void xstormy16_asm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
00056 HOST_WIDE_INT, tree);
00057
00058 static void xstormy16_init_builtins (void);
00059 static rtx xstormy16_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
00060 static bool xstormy16_rtx_costs (rtx, int, int, int *);
00061 static int xstormy16_address_cost (rtx);
00062 static bool xstormy16_return_in_memory (tree, tree);
00063
00064
00065
00066 struct rtx_def * xstormy16_compare_op0;
00067 struct rtx_def * xstormy16_compare_op1;
00068
00069 static GTY(()) section *bss100_section;
00070
00071
00072
00073
00074
00075 static bool
00076 xstormy16_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
00077 int *total)
00078 {
00079 switch (code)
00080 {
00081 case CONST_INT:
00082 if (INTVAL (x) < 16 && INTVAL (x) >= 0)
00083 *total = COSTS_N_INSNS (1) / 2;
00084 else if (INTVAL (x) < 256 && INTVAL (x) >= 0)
00085 *total = COSTS_N_INSNS (1);
00086 else
00087 *total = COSTS_N_INSNS (2);
00088 return true;
00089
00090 case CONST_DOUBLE:
00091 case CONST:
00092 case SYMBOL_REF:
00093 case LABEL_REF:
00094 *total = COSTS_N_INSNS(2);
00095 return true;
00096
00097 case MULT:
00098 *total = COSTS_N_INSNS (35 + 6);
00099 return true;
00100 case DIV:
00101 *total = COSTS_N_INSNS (51 - 6);
00102 return true;
00103
00104 default:
00105 return false;
00106 }
00107 }
00108
00109 static int
00110 xstormy16_address_cost (rtx x)
00111 {
00112 return (GET_CODE (x) == CONST_INT ? 2
00113 : GET_CODE (x) == PLUS ? 7
00114 : 5);
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 void
00143 xstormy16_emit_cbranch (enum rtx_code code, rtx loc)
00144 {
00145 rtx op0 = xstormy16_compare_op0;
00146 rtx op1 = xstormy16_compare_op1;
00147 rtx condition_rtx, loc_ref, branch, cy_clobber;
00148 rtvec vec;
00149 enum machine_mode mode;
00150
00151 mode = GET_MODE (op0);
00152 gcc_assert (mode == HImode || mode == SImode);
00153
00154 if (mode == SImode
00155 && (code == GT || code == LE || code == GTU || code == LEU))
00156 {
00157 int unsigned_p = (code == GTU || code == LEU);
00158 int gt_p = (code == GT || code == GTU);
00159 rtx lab = NULL_RTX;
00160
00161 if (gt_p)
00162 lab = gen_label_rtx ();
00163 xstormy16_emit_cbranch (unsigned_p ? LTU : LT, gt_p ? lab : loc);
00164
00165
00166 xstormy16_emit_cbranch (gt_p ? NE : EQ, loc);
00167 if (gt_p)
00168 emit_label (lab);
00169 return;
00170 }
00171 else if (mode == SImode
00172 && (code == NE || code == EQ)
00173 && op1 != const0_rtx)
00174 {
00175 rtx lab = NULL_RTX;
00176 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
00177 int i;
00178
00179 if (code == EQ)
00180 lab = gen_label_rtx ();
00181
00182 for (i = 0; i < num_words - 1; i++)
00183 {
00184 xstormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode,
00185 i * UNITS_PER_WORD);
00186 xstormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode,
00187 i * UNITS_PER_WORD);
00188 xstormy16_emit_cbranch (NE, code == EQ ? lab : loc);
00189 }
00190 xstormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode,
00191 i * UNITS_PER_WORD);
00192 xstormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode,
00193 i * UNITS_PER_WORD);
00194 xstormy16_emit_cbranch (code, loc);
00195
00196 if (code == EQ)
00197 emit_label (lab);
00198 return;
00199 }
00200
00201
00202
00203 if (mode != HImode)
00204 {
00205 rtx tmp;
00206 tmp = gen_reg_rtx (mode);
00207 emit_move_insn (tmp, op0);
00208 op0 = tmp;
00209 }
00210
00211 condition_rtx = gen_rtx_fmt_ee (code, mode, op0, op1);
00212 loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
00213 branch = gen_rtx_SET (VOIDmode, pc_rtx,
00214 gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
00215 loc_ref, pc_rtx));
00216
00217 cy_clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (BImode));
00218
00219 if (mode == HImode)
00220 vec = gen_rtvec (2, branch, cy_clobber);
00221 else if (code == NE || code == EQ)
00222 vec = gen_rtvec (2, branch, gen_rtx_CLOBBER (VOIDmode, op0));
00223 else
00224 {
00225 rtx sub;
00226 #if 0
00227 sub = gen_rtx_SET (VOIDmode, op0, gen_rtx_MINUS (SImode, op0, op1));
00228 #else
00229 sub = gen_rtx_CLOBBER (SImode, op0);
00230 #endif
00231 vec = gen_rtvec (3, branch, sub, cy_clobber);
00232 }
00233
00234 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
00235 }
00236
00237
00238
00239
00240
00241 void
00242 xstormy16_split_cbranch (enum machine_mode mode, rtx label, rtx comparison,
00243 rtx dest, rtx carry)
00244 {
00245 rtx op0 = XEXP (comparison, 0);
00246 rtx op1 = XEXP (comparison, 1);
00247 rtx seq, last_insn;
00248 rtx compare;
00249
00250 start_sequence ();
00251 xstormy16_expand_arith (mode, COMPARE, dest, op0, op1, carry);
00252 seq = get_insns ();
00253 end_sequence ();
00254
00255 gcc_assert (INSN_P (seq));
00256
00257 last_insn = seq;
00258 while (NEXT_INSN (last_insn) != NULL_RTX)
00259 last_insn = NEXT_INSN (last_insn);
00260
00261 compare = SET_SRC (XVECEXP (PATTERN (last_insn), 0, 0));
00262 PUT_CODE (XEXP (compare, 0), GET_CODE (comparison));
00263 XEXP (compare, 1) = gen_rtx_LABEL_REF (VOIDmode, label);
00264 emit_insn (seq);
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 char *
00278 xstormy16_output_cbranch_hi (rtx op, const char *label, int reversed, rtx insn)
00279 {
00280 static char string[64];
00281 int need_longbranch = (op != NULL_RTX
00282 ? get_attr_length (insn) == 8
00283 : get_attr_length (insn) == 4);
00284 int really_reversed = reversed ^ need_longbranch;
00285 const char *ccode;
00286 const char *template;
00287 const char *operands;
00288 enum rtx_code code;
00289
00290 if (! op)
00291 {
00292 if (need_longbranch)
00293 ccode = "jmpf";
00294 else
00295 ccode = "br";
00296 sprintf (string, "%s %s", ccode, label);
00297 return string;
00298 }
00299
00300 code = GET_CODE (op);
00301
00302 if (GET_CODE (XEXP (op, 0)) != REG)
00303 {
00304 code = swap_condition (code);
00305 operands = "%3,%2";
00306 }
00307 else
00308 operands = "%2,%3";
00309
00310
00311 if (really_reversed)
00312 code = reverse_condition (code);
00313
00314 switch (code)
00315 {
00316 case EQ: ccode = "z"; break;
00317 case NE: ccode = "nz"; break;
00318 case GE: ccode = "ge"; break;
00319 case LT: ccode = "lt"; break;
00320 case GT: ccode = "gt"; break;
00321 case LE: ccode = "le"; break;
00322 case GEU: ccode = "nc"; break;
00323 case LTU: ccode = "c"; break;
00324 case GTU: ccode = "hi"; break;
00325 case LEU: ccode = "ls"; break;
00326
00327 default:
00328 gcc_unreachable ();
00329 }
00330
00331 if (need_longbranch)
00332 template = "b%s %s,.+8 | jmpf %s";
00333 else
00334 template = "b%s %s,%s";
00335 sprintf (string, template, ccode, operands, label);
00336
00337 return string;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 char *
00351 xstormy16_output_cbranch_si (rtx op, const char *label, int reversed, rtx insn)
00352 {
00353 static char string[64];
00354 int need_longbranch = get_attr_length (insn) >= 8;
00355 int really_reversed = reversed ^ need_longbranch;
00356 const char *ccode;
00357 const char *template;
00358 char prevop[16];
00359 enum rtx_code code;
00360
00361 code = GET_CODE (op);
00362
00363
00364 if (really_reversed)
00365 code = reverse_condition (code);
00366
00367 switch (code)
00368 {
00369 case EQ: ccode = "z"; break;
00370 case NE: ccode = "nz"; break;
00371 case GE: ccode = "ge"; break;
00372 case LT: ccode = "lt"; break;
00373 case GEU: ccode = "nc"; break;
00374 case LTU: ccode = "c"; break;
00375
00376
00377 default:
00378 gcc_unreachable ();
00379 }
00380
00381 switch (code)
00382 {
00383 case EQ: case NE:
00384 {
00385 int regnum;
00386
00387 gcc_assert (GET_CODE (XEXP (op, 0)) == REG);
00388
00389 regnum = REGNO (XEXP (op, 0));
00390 sprintf (prevop, "or %s,%s", reg_names[regnum], reg_names[regnum+1]);
00391 }
00392 break;
00393
00394 case GE: case LT: case GEU: case LTU:
00395 strcpy (prevop, "sbc %2,%3");
00396 break;
00397
00398 default:
00399 gcc_unreachable ();
00400 }
00401
00402 if (need_longbranch)
00403 template = "%s | b%s .+6 | jmpf %s";
00404 else
00405 template = "%s | b%s %s";
00406 sprintf (string, template, prevop, ccode, label);
00407
00408 return string;
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
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 enum reg_class
00464 xstormy16_secondary_reload_class (enum reg_class class,
00465 enum machine_mode mode,
00466 rtx x)
00467 {
00468
00469
00470 if ((GET_CODE (x) == MEM
00471 || ((GET_CODE (x) == SUBREG || GET_CODE (x) == REG)
00472 && (true_regnum (x) == -1
00473 || true_regnum (x) >= FIRST_PSEUDO_REGISTER)))
00474 && ! reg_class_subset_p (class, EIGHT_REGS))
00475 return EIGHT_REGS;
00476
00477
00478
00479 if (xstormy16_carry_plus_operand (x, mode))
00480 return CARRY_REGS;
00481
00482 return NO_REGS;
00483 }
00484
00485
00486 int
00487 xstormy16_carry_plus_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
00488 {
00489 return (GET_CODE (x) == PLUS
00490 && GET_CODE (XEXP (x, 1)) == CONST_INT
00491 && (INTVAL (XEXP (x, 1)) < -4 || INTVAL (XEXP (x, 1)) > 4));
00492 }
00493
00494
00495 int
00496 xs_hi_general_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
00497 {
00498 if ((GET_CODE (x) == CONST_INT)
00499 && ((INTVAL (x) >= 32768) || (INTVAL (x) < -32768)))
00500 error ("constant halfword load operand out of range");
00501 return general_operand (x, mode);
00502 }
00503
00504
00505 int
00506 xs_hi_nonmemory_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
00507 {
00508 if ((GET_CODE (x) == CONST_INT)
00509 && ((INTVAL (x) >= 32768) || (INTVAL (x) < -32768)))
00510 error ("constant arithmetic operand out of range");
00511 return nonmemory_operand (x, mode);
00512 }
00513
00514 enum reg_class
00515 xstormy16_preferred_reload_class (rtx x, enum reg_class class)
00516 {
00517 if (class == GENERAL_REGS
00518 && GET_CODE (x) == MEM)
00519 return EIGHT_REGS;
00520
00521 return class;
00522 }
00523
00524
00525
00526 int
00527 xstormy16_below100_symbol (rtx x,
00528 enum machine_mode mode ATTRIBUTE_UNUSED)
00529 {
00530 if (GET_CODE (x) == CONST)
00531 x = XEXP (x, 0);
00532 if (GET_CODE (x) == PLUS
00533 && GET_CODE (XEXP (x, 1)) == CONST_INT)
00534 x = XEXP (x, 0);
00535
00536 if (GET_CODE (x) == SYMBOL_REF)
00537 return (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_XSTORMY16_BELOW100) != 0;
00538
00539 if (GET_CODE (x) == CONST_INT)
00540 {
00541 HOST_WIDE_INT i = INTVAL (x);
00542 if ((i >= 0x0000 && i <= 0x00ff)
00543 || (i >= 0x7f00 && i <= 0x7fff))
00544 return 1;
00545 }
00546 return 0;
00547 }
00548
00549
00550
00551 int
00552 xstormy16_splittable_below100_operand (rtx x, enum machine_mode mode)
00553 {
00554 if (GET_CODE (x) == MEM && MEM_VOLATILE_P (x))
00555 return 0;
00556 return xstormy16_below100_operand (x, mode);
00557 }
00558
00559
00560
00561 void
00562 xstormy16_expand_iorqi3 (rtx *operands)
00563 {
00564 rtx in, out, outsub, val;
00565
00566 out = operands[0];
00567 in = operands[1];
00568 val = operands[2];
00569
00570 if (xstormy16_onebit_set_operand (val, QImode))
00571 {
00572 if (!xstormy16_below100_or_register (in, QImode))
00573 in = copy_to_mode_reg (QImode, in);
00574 if (!xstormy16_below100_or_register (out, QImode))
00575 out = gen_reg_rtx (QImode);
00576 emit_insn (gen_iorqi3_internal (out, in, val));
00577 if (out != operands[0])
00578 emit_move_insn (operands[0], out);
00579 return;
00580 }
00581
00582 if (GET_CODE (in) != REG)
00583 in = copy_to_mode_reg (QImode, in);
00584 if (GET_CODE (val) != REG
00585 && GET_CODE (val) != CONST_INT)
00586 val = copy_to_mode_reg (QImode, val);
00587 if (GET_CODE (out) != REG)
00588 out = gen_reg_rtx (QImode);
00589
00590 in = simplify_gen_subreg (HImode, in, QImode, 0);
00591 outsub = simplify_gen_subreg (HImode, out, QImode, 0);
00592 if (GET_CODE (val) != CONST_INT)
00593 val = simplify_gen_subreg (HImode, val, QImode, 0);
00594
00595 emit_insn (gen_iorhi3 (outsub, in, val));
00596
00597 if (out != operands[0])
00598 emit_move_insn (operands[0], out);
00599 }
00600
00601
00602 void
00603 xstormy16_expand_andqi3 (rtx *operands)
00604 {
00605 rtx in, out, outsub, val;
00606
00607 out = operands[0];
00608 in = operands[1];
00609 val = operands[2];
00610
00611 if (xstormy16_onebit_clr_operand (val, QImode))
00612 {
00613 if (!xstormy16_below100_or_register (in, QImode))
00614 in = copy_to_mode_reg (QImode, in);
00615 if (!xstormy16_below100_or_register (out, QImode))
00616 out = gen_reg_rtx (QImode);
00617 emit_insn (gen_andqi3_internal (out, in, val));
00618 if (out != operands[0])
00619 emit_move_insn (operands[0], out);
00620 return;
00621 }
00622
00623 if (GET_CODE (in) != REG)
00624 in = copy_to_mode_reg (QImode, in);
00625 if (GET_CODE (val) != REG
00626 && GET_CODE (val) != CONST_INT)
00627 val = copy_to_mode_reg (QImode, val);
00628 if (GET_CODE (out) != REG)
00629 out = gen_reg_rtx (QImode);
00630
00631 in = simplify_gen_subreg (HImode, in, QImode, 0);
00632 outsub = simplify_gen_subreg (HImode, out, QImode, 0);
00633 if (GET_CODE (val) != CONST_INT)
00634 val = simplify_gen_subreg (HImode, val, QImode, 0);
00635
00636 emit_insn (gen_andhi3 (outsub, in, val));
00637
00638 if (out != operands[0])
00639 emit_move_insn (operands[0], out);
00640 }
00641
00642 #define LEGITIMATE_ADDRESS_INTEGER_P(X, OFFSET) \
00643 (GET_CODE (X) == CONST_INT \
00644 && (unsigned HOST_WIDE_INT) (INTVAL (X) + (OFFSET) + 2048) < 4096)
00645
00646 #define LEGITIMATE_ADDRESS_CONST_INT_P(X, OFFSET) \
00647 (GET_CODE (X) == CONST_INT \
00648 && INTVAL (X) + (OFFSET) >= 0 \
00649 && INTVAL (X) + (OFFSET) < 0x8000 \
00650 && (INTVAL (X) + (OFFSET) < 0x100 || INTVAL (X) + (OFFSET) >= 0x7F00))
00651
00652 int
00653 xstormy16_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
00654 rtx x, int strict)
00655 {
00656 if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0))
00657 return 1;
00658
00659 if (GET_CODE (x) == PLUS
00660 && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0))
00661 x = XEXP (x, 0);
00662
00663 if ((GET_CODE (x) == PRE_MODIFY
00664 && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
00665 || GET_CODE (x) == POST_INC
00666 || GET_CODE (x) == PRE_DEC)
00667 x = XEXP (x, 0);
00668
00669 if (GET_CODE (x) == REG && REGNO_OK_FOR_BASE_P (REGNO (x))
00670 && (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER))
00671 return 1;
00672
00673 if (xstormy16_below100_symbol(x, mode))
00674 return 1;
00675
00676 return 0;
00677 }
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 int
00696 xstormy16_mode_dependent_address_p (rtx x)
00697 {
00698 if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0)
00699 && ! LEGITIMATE_ADDRESS_CONST_INT_P (x, 6))
00700 return 1;
00701
00702 if (GET_CODE (x) == PLUS
00703 && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0)
00704 && ! LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 6))
00705 return 1;
00706
00707 if (GET_CODE (x) == PLUS)
00708 x = XEXP (x, 0);
00709
00710 if (GET_CODE (x) == POST_INC
00711 || GET_CODE (x) == PRE_DEC)
00712 return 1;
00713
00714 return 0;
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724 int
00725 xstormy16_extra_constraint_p (rtx x, int c)
00726 {
00727 switch (c)
00728 {
00729
00730 case 'Q':
00731 return (GET_CODE (x) == MEM
00732 && GET_CODE (XEXP (x, 0)) == POST_INC
00733 && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
00734
00735
00736 case 'R':
00737 return (GET_CODE (x) == MEM
00738 && GET_CODE (XEXP (x, 0)) == PRE_DEC
00739 && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
00740
00741
00742 case 'S':
00743 return (GET_CODE (x) == MEM
00744 && GET_CODE (XEXP (x, 0)) == CONST_INT
00745 && xstormy16_legitimate_address_p (VOIDmode, XEXP (x, 0), 0));
00746
00747
00748 case 'T':
00749
00750 return 0;
00751
00752
00753
00754 case 'U':
00755 return (GET_CODE (x) == CONST_INT
00756 && (INTVAL (x) < 2 || INTVAL (x) > 15));
00757
00758
00759
00760 case 'Z':
00761 return (GET_CODE (x) == CONST_INT
00762 && (INTVAL (x) == 0));
00763
00764 case 'W':
00765 return xstormy16_below100_operand(x, GET_MODE(x));
00766
00767 default:
00768 return 0;
00769 }
00770 }
00771
00772 int
00773 short_memory_operand (rtx x, enum machine_mode mode)
00774 {
00775 if (! memory_operand (x, mode))
00776 return 0;
00777 return (GET_CODE (XEXP (x, 0)) != PLUS);
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787 void
00788 xstormy16_split_move (enum machine_mode mode, rtx dest, rtx src)
00789 {
00790 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
00791 int direction, end, i;
00792 int src_modifies = 0;
00793 int dest_modifies = 0;
00794 int src_volatile = 0;
00795 int dest_volatile = 0;
00796 rtx mem_operand;
00797 rtx auto_inc_reg_rtx = NULL_RTX;
00798
00799
00800 gcc_assert (reload_completed
00801 && mode != QImode && mode != HImode
00802 && nonimmediate_operand (dest, mode)
00803 && general_operand (src, mode));
00804
00805
00806 gcc_assert (GET_CODE (dest) != MEM || GET_CODE (src) != MEM);
00807
00808
00809 gcc_assert (GET_CODE (dest) != SUBREG && GET_CODE (src) != SUBREG);
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 direction = 1;
00820
00821 if (GET_CODE (dest) == MEM)
00822 {
00823 mem_operand = XEXP (dest, 0);
00824 dest_modifies = side_effects_p (mem_operand);
00825 if (auto_inc_p (mem_operand))
00826 auto_inc_reg_rtx = XEXP (mem_operand, 0);
00827 dest_volatile = MEM_VOLATILE_P (dest);
00828 if (dest_volatile)
00829 {
00830 dest = copy_rtx (dest);
00831 MEM_VOLATILE_P (dest) = 0;
00832 }
00833 }
00834 else if (GET_CODE (src) == MEM)
00835 {
00836 mem_operand = XEXP (src, 0);
00837 src_modifies = side_effects_p (mem_operand);
00838 if (auto_inc_p (mem_operand))
00839 auto_inc_reg_rtx = XEXP (mem_operand, 0);
00840 src_volatile = MEM_VOLATILE_P (src);
00841 if (src_volatile)
00842 {
00843 src = copy_rtx (src);
00844 MEM_VOLATILE_P (src) = 0;
00845 }
00846 }
00847 else
00848 mem_operand = NULL_RTX;
00849
00850 if (mem_operand == NULL_RTX)
00851 {
00852 if (GET_CODE (src) == REG
00853 && GET_CODE (dest) == REG
00854 && reg_overlap_mentioned_p (dest, src)
00855 && REGNO (dest) > REGNO (src))
00856 direction = -1;
00857 }
00858 else if (GET_CODE (mem_operand) == PRE_DEC
00859 || (GET_CODE (mem_operand) == PLUS
00860 && GET_CODE (XEXP (mem_operand, 0)) == PRE_DEC))
00861 direction = -1;
00862 else if (GET_CODE (src) == MEM
00863 && reg_overlap_mentioned_p (dest, src))
00864 {
00865 int regno;
00866
00867 gcc_assert (GET_CODE (dest) == REG);
00868 regno = REGNO (dest);
00869
00870 gcc_assert (refers_to_regno_p (regno, regno + num_words,
00871 mem_operand, 0));
00872
00873 if (refers_to_regno_p (regno, regno + 1, mem_operand, 0))
00874 direction = -1;
00875 else if (refers_to_regno_p (regno + num_words - 1, regno + num_words,
00876 mem_operand, 0))
00877 direction = 1;
00878 else
00879
00880
00881
00882
00883 gcc_unreachable ();
00884 }
00885
00886 end = direction < 0 ? -1 : num_words;
00887 for (i = direction < 0 ? num_words - 1 : 0; i != end; i += direction)
00888 {
00889 rtx w_src, w_dest, insn;
00890
00891 if (src_modifies)
00892 w_src = gen_rtx_MEM (word_mode, mem_operand);
00893 else
00894 w_src = simplify_gen_subreg (word_mode, src, mode, i * UNITS_PER_WORD);
00895 if (src_volatile)
00896 MEM_VOLATILE_P (w_src) = 1;
00897 if (dest_modifies)
00898 w_dest = gen_rtx_MEM (word_mode, mem_operand);
00899 else
00900 w_dest = simplify_gen_subreg (word_mode, dest, mode,
00901 i * UNITS_PER_WORD);
00902 if (dest_volatile)
00903 MEM_VOLATILE_P (w_dest) = 1;
00904
00905
00906 gcc_assert (GET_CODE (w_src) != SUBREG
00907 && GET_CODE (w_dest) != SUBREG);
00908
00909 insn = emit_insn (gen_rtx_SET (VOIDmode, w_dest, w_src));
00910 if (auto_inc_reg_rtx)
00911 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC,
00912 auto_inc_reg_rtx,
00913 REG_NOTES (insn));
00914 }
00915 }
00916
00917
00918
00919
00920 void
00921 xstormy16_expand_move (enum machine_mode mode, rtx dest, rtx src)
00922 {
00923 if ((GET_CODE (dest) == MEM) && (GET_CODE (XEXP (dest, 0)) == PRE_MODIFY))
00924 {
00925 rtx pmv = XEXP (dest, 0);
00926 rtx dest_reg = XEXP (pmv, 0);
00927 rtx dest_mod = XEXP (pmv, 1);
00928 rtx set = gen_rtx_SET (Pmode, dest_reg, dest_mod);
00929 rtx clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (BImode, 16));
00930
00931 dest = gen_rtx_MEM (mode, dest_reg);
00932 emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
00933 }
00934 else if ((GET_CODE (src) == MEM) && (GET_CODE (XEXP (src, 0)) == PRE_MODIFY))
00935 {
00936 rtx pmv = XEXP (src, 0);
00937 rtx src_reg = XEXP (pmv, 0);
00938 rtx src_mod = XEXP (pmv, 1);
00939 rtx set = gen_rtx_SET (Pmode, src_reg, src_mod);
00940 rtx clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (BImode, 16));
00941
00942 src = gen_rtx_MEM (mode, src_reg);
00943 emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
00944 }
00945
00946
00947 if (! reload_in_progress
00948 && ! reload_completed
00949 && GET_CODE (dest) == MEM
00950 && (GET_CODE (XEXP (dest, 0)) != CONST_INT
00951 || ! xstormy16_legitimate_address_p (mode, XEXP (dest, 0), 0))
00952 && ! xstormy16_below100_operand (dest, mode)
00953 && GET_CODE (src) != REG
00954 && GET_CODE (src) != SUBREG)
00955 src = copy_to_mode_reg (mode, src);
00956
00957
00958 if (reload_completed
00959 && mode != HImode && mode != QImode)
00960 {
00961 xstormy16_split_move (mode, dest, src);
00962 return;
00963 }
00964
00965 emit_insn (gen_rtx_SET (VOIDmode, dest, src));
00966 }
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989 struct xstormy16_stack_layout
00990 {
00991
00992 int locals_size;
00993 int register_save_size;
00994 int stdarg_save_size;
00995
00996 int frame_size;
00997
00998 int first_local_minus_ap;
00999 int sp_minus_fp;
01000 int fp_minus_ap;
01001 };
01002
01003
01004 #define REG_NEEDS_SAVE(REGNUM, IFUN) \
01005 ((regs_ever_live[REGNUM] && ! call_used_regs[REGNUM]) \
01006 || (IFUN && ! fixed_regs[REGNUM] && call_used_regs[REGNUM] \
01007 && (REGNO_REG_CLASS (REGNUM) != CARRY_REGS) \
01008 && (regs_ever_live[REGNUM] || ! current_function_is_leaf)))
01009
01010
01011 struct xstormy16_stack_layout
01012 xstormy16_compute_stack_layout (void)
01013 {
01014 struct xstormy16_stack_layout layout;
01015 int regno;
01016 const int ifun = xstormy16_interrupt_function_p ();
01017
01018 layout.locals_size = get_frame_size ();
01019
01020 layout.register_save_size = 0;
01021 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01022 if (REG_NEEDS_SAVE (regno, ifun))
01023 layout.register_save_size += UNITS_PER_WORD;
01024
01025 if (current_function_stdarg)
01026 layout.stdarg_save_size = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
01027 else
01028 layout.stdarg_save_size = 0;
01029
01030 layout.frame_size = (layout.locals_size
01031 + layout.register_save_size
01032 + layout.stdarg_save_size);
01033
01034 if (current_function_args_size <= 2048 && current_function_args_size != -1)
01035 {
01036 if (layout.frame_size + INCOMING_FRAME_SP_OFFSET
01037 + current_function_args_size <= 2048)
01038 layout.fp_minus_ap = layout.frame_size + INCOMING_FRAME_SP_OFFSET;
01039 else
01040 layout.fp_minus_ap = 2048 - current_function_args_size;
01041 }
01042 else
01043 layout.fp_minus_ap = (layout.stdarg_save_size
01044 + layout.register_save_size
01045 + INCOMING_FRAME_SP_OFFSET);
01046 layout.sp_minus_fp = (layout.frame_size + INCOMING_FRAME_SP_OFFSET
01047 - layout.fp_minus_ap);
01048 layout.first_local_minus_ap = layout.sp_minus_fp - layout.locals_size;
01049 return layout;
01050 }
01051
01052
01053 int
01054 xstormy16_initial_elimination_offset (int from, int to)
01055 {
01056 struct xstormy16_stack_layout layout;
01057 int result;
01058
01059 layout = xstormy16_compute_stack_layout ();
01060
01061 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
01062 result = layout.sp_minus_fp - layout.locals_size;
01063 else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
01064 result = -layout.locals_size;
01065 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
01066 result = -layout.fp_minus_ap;
01067 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
01068 result = -(layout.sp_minus_fp + layout.fp_minus_ap);
01069 else
01070 gcc_unreachable ();
01071
01072 return result;
01073 }
01074
01075 static rtx
01076 emit_addhi3_postreload (rtx dest, rtx src0, rtx src1)
01077 {
01078 rtx set, clobber, insn;
01079
01080 set = gen_rtx_SET (VOIDmode, dest, gen_rtx_PLUS (HImode, src0, src1));
01081 clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (BImode, 16));
01082 insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
01083 return insn;
01084 }
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096 void
01097 xstormy16_expand_prologue (void)
01098 {
01099 struct xstormy16_stack_layout layout;
01100 int regno;
01101 rtx insn;
01102 rtx mem_push_rtx;
01103 const int ifun = xstormy16_interrupt_function_p ();
01104
01105 mem_push_rtx = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
01106 mem_push_rtx = gen_rtx_MEM (HImode, mem_push_rtx);
01107
01108 layout = xstormy16_compute_stack_layout ();
01109
01110 if (layout.locals_size >= 32768)
01111 error ("local variable memory requirements exceed capacity");
01112
01113
01114 if (layout.stdarg_save_size)
01115 for (regno = FIRST_ARGUMENT_REGISTER;
01116 regno < FIRST_ARGUMENT_REGISTER + NUM_ARGUMENT_REGISTERS;
01117 regno++)
01118 {
01119 rtx dwarf;
01120 rtx reg = gen_rtx_REG (HImode, regno);
01121
01122 insn = emit_move_insn (mem_push_rtx, reg);
01123 RTX_FRAME_RELATED_P (insn) = 1;
01124
01125 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
01126
01127 XVECEXP (dwarf, 0, 0) = gen_rtx_SET (VOIDmode,
01128 gen_rtx_MEM (Pmode, stack_pointer_rtx),
01129 reg);
01130 XVECEXP (dwarf, 0, 1) = gen_rtx_SET (Pmode, stack_pointer_rtx,
01131 plus_constant (stack_pointer_rtx,
01132 GET_MODE_SIZE (Pmode)));
01133 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
01134 dwarf,
01135 REG_NOTES (insn));
01136 RTX_FRAME_RELATED_P (XVECEXP (dwarf, 0, 0)) = 1;
01137 RTX_FRAME_RELATED_P (XVECEXP (dwarf, 0, 1)) = 1;
01138 }
01139
01140
01141 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01142 if (REG_NEEDS_SAVE (regno, ifun))
01143 {
01144 rtx dwarf;
01145 rtx reg = gen_rtx_REG (HImode, regno);
01146
01147 insn = emit_move_insn (mem_push_rtx, reg);
01148 RTX_FRAME_RELATED_P (insn) = 1;
01149
01150 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
01151
01152 XVECEXP (dwarf, 0, 0) = gen_rtx_SET (VOIDmode,
01153 gen_rtx_MEM (Pmode, stack_pointer_rtx),
01154 reg);
01155 XVECEXP (dwarf, 0, 1) = gen_rtx_SET (Pmode, stack_pointer_rtx,
01156 plus_constant (stack_pointer_rtx,
01157 GET_MODE_SIZE (Pmode)));
01158 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
01159 dwarf,
01160 REG_NOTES (insn));
01161 RTX_FRAME_RELATED_P (XVECEXP (dwarf, 0, 0)) = 1;
01162 RTX_FRAME_RELATED_P (XVECEXP (dwarf, 0, 1)) = 1;
01163 }
01164
01165
01166
01167 if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
01168 emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
01169
01170
01171 if (layout.locals_size)
01172 {
01173 insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
01174 GEN_INT (layout.locals_size));
01175 RTX_FRAME_RELATED_P (insn) = 1;
01176 }
01177
01178
01179 if (frame_pointer_needed && layout.sp_minus_fp != layout.locals_size)
01180 {
01181 insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
01182
01183 if (layout.sp_minus_fp)
01184 emit_addhi3_postreload (hard_frame_pointer_rtx,
01185 hard_frame_pointer_rtx,
01186 GEN_INT (-layout.sp_minus_fp));
01187 }
01188 }
01189
01190
01191 int
01192 direct_return (void)
01193 {
01194 return (reload_completed
01195 && xstormy16_compute_stack_layout ().frame_size == 0);
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206 void
01207 xstormy16_expand_epilogue (void)
01208 {
01209 struct xstormy16_stack_layout layout;
01210 rtx mem_pop_rtx, insn;
01211 int regno;
01212 const int ifun = xstormy16_interrupt_function_p ();
01213
01214 mem_pop_rtx = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
01215 mem_pop_rtx = gen_rtx_MEM (HImode, mem_pop_rtx);
01216
01217 layout = xstormy16_compute_stack_layout ();
01218
01219
01220 if (layout.locals_size)
01221 {
01222 if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
01223 emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
01224 else
01225 {
01226 insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
01227 GEN_INT (- layout.locals_size));
01228 RTX_FRAME_RELATED_P (insn) = 1;
01229 }
01230 }
01231
01232
01233 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
01234 if (REG_NEEDS_SAVE (regno, ifun))
01235 {
01236 rtx dwarf;
01237
01238 insn = emit_move_insn (gen_rtx_REG (HImode, regno), mem_pop_rtx);
01239 RTX_FRAME_RELATED_P (insn) = 1;
01240 dwarf = gen_rtx_SET (Pmode, stack_pointer_rtx,
01241 plus_constant (stack_pointer_rtx,
01242 -GET_MODE_SIZE (Pmode)));
01243 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
01244 dwarf,
01245 REG_NOTES (insn));
01246 }
01247
01248
01249 if (layout.stdarg_save_size)
01250 {
01251 insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
01252 GEN_INT (- layout.stdarg_save_size));
01253 RTX_FRAME_RELATED_P (insn) = 1;
01254 }
01255
01256
01257 if (ifun)
01258 emit_jump_insn (gen_return_internal_interrupt ());
01259 else
01260 emit_jump_insn (gen_return_internal ());
01261 }
01262
01263 int
01264 xstormy16_epilogue_uses (int regno)
01265 {
01266 if (reload_completed && call_used_regs[regno])
01267 {
01268 const int ifun = xstormy16_interrupt_function_p ();
01269 return REG_NEEDS_SAVE (regno, ifun);
01270 }
01271 return 0;
01272 }
01273
01274 void
01275 xstormy16_function_profiler (void)
01276 {
01277 sorry ("function_profiler support");
01278 }
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292 CUMULATIVE_ARGS
01293 xstormy16_function_arg_advance (CUMULATIVE_ARGS cum, enum machine_mode mode,
01294 tree type, int named ATTRIBUTE_UNUSED)
01295 {
01296
01297
01298
01299 if (cum < NUM_ARGUMENT_REGISTERS
01300 && cum + XSTORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS)
01301 cum = NUM_ARGUMENT_REGISTERS;
01302
01303 cum += XSTORMY16_WORD_SIZE (type, mode);
01304
01305 return cum;
01306 }
01307
01308 rtx
01309 xstormy16_function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode,
01310 tree type, int named ATTRIBUTE_UNUSED)
01311 {
01312 if (mode == VOIDmode)
01313 return const0_rtx;
01314 if (targetm.calls.must_pass_in_stack (mode, type)
01315 || cum + XSTORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS)
01316 return 0;
01317 return gen_rtx_REG (mode, cum + 2);
01318 }
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328 static tree
01329 xstormy16_build_builtin_va_list (void)
01330 {
01331 tree f_1, f_2, record, type_decl;
01332
01333 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
01334 type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
01335
01336 f_1 = build_decl (FIELD_DECL, get_identifier ("base"),
01337 ptr_type_node);
01338 f_2 = build_decl (FIELD_DECL, get_identifier ("count"),
01339 unsigned_type_node);
01340
01341 DECL_FIELD_CONTEXT (f_1) = record;
01342 DECL_FIELD_CONTEXT (f_2) = record;
01343
01344 TREE_CHAIN (record) = type_decl;
01345 TYPE_NAME (record) = type_decl;
01346 TYPE_FIELDS (record) = f_1;
01347 TREE_CHAIN (f_1) = f_2;
01348
01349 layout_type (record);
01350
01351 return record;
01352 }
01353
01354
01355
01356
01357
01358 void
01359 xstormy16_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
01360 {
01361 tree f_base, f_count;
01362 tree base, count;
01363 tree t;
01364
01365 if (xstormy16_interrupt_function_p ())
01366 error ("cannot use va_start in interrupt function");
01367
01368 f_base = TYPE_FIELDS (va_list_type_node);
01369 f_count = TREE_CHAIN (f_base);
01370
01371 base = build3 (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE);
01372 count = build3 (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
01373 NULL_TREE);
01374
01375 t = make_tree (TREE_TYPE (base), virtual_incoming_args_rtx);
01376 t = build2 (PLUS_EXPR, TREE_TYPE (base), t,
01377 build_int_cst (NULL_TREE, INCOMING_FRAME_SP_OFFSET));
01378 t = build2 (MODIFY_EXPR, TREE_TYPE (base), base, t);
01379 TREE_SIDE_EFFECTS (t) = 1;
01380 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01381
01382 t = build2 (MODIFY_EXPR, TREE_TYPE (count), count,
01383 build_int_cst (NULL_TREE,
01384 current_function_args_info * UNITS_PER_WORD));
01385 TREE_SIDE_EFFECTS (t) = 1;
01386 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
01387 }
01388
01389
01390
01391
01392
01393 static tree
01394 xstormy16_expand_builtin_va_arg (tree valist, tree type, tree *pre_p,
01395 tree *post_p ATTRIBUTE_UNUSED)
01396 {
01397 tree f_base, f_count;
01398 tree base, count;
01399 tree count_tmp, addr, t;
01400 tree lab_gotaddr, lab_fromstack;
01401 int size, size_of_reg_args, must_stack;
01402 tree size_tree;
01403
01404 f_base = TYPE_FIELDS (va_list_type_node);
01405 f_count = TREE_CHAIN (f_base);
01406
01407 base = build3 (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE);
01408 count = build3 (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
01409 NULL_TREE);
01410
01411 must_stack = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
01412 size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
01413 gimplify_expr (&size_tree, pre_p, NULL, is_gimple_val, fb_rvalue);
01414
01415 size_of_reg_args = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
01416
01417 count_tmp = get_initialized_tmp_var (count, pre_p, NULL);
01418 lab_gotaddr = create_artificial_label ();
01419 lab_fromstack = create_artificial_label ();
01420 addr = create_tmp_var (ptr_type_node, NULL);
01421
01422 if (!must_stack)
01423 {
01424 tree r;
01425
01426 t = fold_convert (TREE_TYPE (count), size_tree);
01427 t = build2 (PLUS_EXPR, TREE_TYPE (count), count_tmp, t);
01428 r = fold_convert (TREE_TYPE (count), size_int (size_of_reg_args));
01429 t = build2 (GT_EXPR, boolean_type_node, t, r);
01430 t = build3 (COND_EXPR, void_type_node, t,
01431 build1 (GOTO_EXPR, void_type_node, lab_fromstack),
01432 NULL_TREE);
01433 gimplify_and_add (t, pre_p);
01434
01435 t = fold_convert (ptr_type_node, count_tmp);
01436 t = build2 (PLUS_EXPR, ptr_type_node, base, t);
01437 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
01438 gimplify_and_add (t, pre_p);
01439
01440 t = build1 (GOTO_EXPR, void_type_node, lab_gotaddr);
01441 gimplify_and_add (t, pre_p);
01442
01443 t = build1 (LABEL_EXPR, void_type_node, lab_fromstack);
01444 gimplify_and_add (t, pre_p);
01445 }
01446
01447
01448
01449
01450 size = PUSH_ROUNDING (int_size_in_bytes (type));
01451 if (size > 2 || size < 0 || must_stack)
01452 {
01453 tree r, u;
01454
01455 r = size_int (NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD);
01456 u = build2 (MODIFY_EXPR, void_type_node, count_tmp, r);
01457
01458 t = fold_convert (TREE_TYPE (count), r);
01459 t = build2 (GE_EXPR, boolean_type_node, count_tmp, t);
01460 t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, u);
01461 gimplify_and_add (t, pre_p);
01462 }
01463
01464 t = size_int (NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD
01465 - INCOMING_FRAME_SP_OFFSET);
01466 t = fold_convert (TREE_TYPE (count), t);
01467 t = build2 (MINUS_EXPR, TREE_TYPE (count), count_tmp, t);
01468 t = build2 (PLUS_EXPR, TREE_TYPE (count), t,
01469 fold_convert (TREE_TYPE (count), size_tree));
01470 t = fold_convert (TREE_TYPE (base), fold (t));
01471 t = build2 (MINUS_EXPR, TREE_TYPE (base), base, t);
01472 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
01473 gimplify_and_add (t, pre_p);
01474
01475 t = build1 (LABEL_EXPR, void_type_node, lab_gotaddr);
01476 gimplify_and_add (t, pre_p);
01477
01478 t = fold_convert (TREE_TYPE (count), size_tree);
01479 t = build2 (PLUS_EXPR, TREE_TYPE (count), count_tmp, t);
01480 t = build2 (MODIFY_EXPR, TREE_TYPE (count), count, t);
01481 gimplify_and_add (t, pre_p);
01482
01483 addr = fold_convert (build_pointer_type (type), addr);
01484 return build_va_arg_indirect_ref (addr);
01485 }
01486
01487
01488
01489
01490
01491 void
01492 xstormy16_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
01493 {
01494 rtx reg_addr = gen_reg_rtx (Pmode);
01495 rtx temp = gen_reg_rtx (HImode);
01496 rtx reg_fnaddr = gen_reg_rtx (HImode);
01497 rtx reg_addr_mem;
01498
01499 reg_addr_mem = gen_rtx_MEM (HImode, reg_addr);
01500
01501 emit_move_insn (reg_addr, addr);
01502 emit_move_insn (temp, GEN_INT (0x3130 | STATIC_CHAIN_REGNUM));
01503 emit_move_insn (reg_addr_mem, temp);
01504 emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
01505 emit_move_insn (temp, static_chain);
01506 emit_move_insn (reg_addr_mem, temp);
01507 emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
01508 emit_move_insn (reg_fnaddr, fnaddr);
01509 emit_move_insn (temp, reg_fnaddr);
01510 emit_insn (gen_andhi3 (temp, temp, GEN_INT (0xFF)));
01511 emit_insn (gen_iorhi3 (temp, temp, GEN_INT (0x0200)));
01512 emit_move_insn (reg_addr_mem, temp);
01513 emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
01514 emit_insn (gen_lshrhi3 (reg_fnaddr, reg_fnaddr, GEN_INT (8)));
01515 emit_move_insn (reg_addr_mem, reg_fnaddr);
01516 }
01517
01518
01519
01520 rtx
01521 xstormy16_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
01522 {
01523 enum machine_mode mode;
01524 mode = TYPE_MODE (valtype);
01525 PROMOTE_MODE (mode, 0, valtype);
01526 return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
01527 }
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555 static void
01556 xstormy16_asm_output_mi_thunk (FILE *file,
01557 tree thunk_fndecl ATTRIBUTE_UNUSED,
01558 HOST_WIDE_INT delta,
01559 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
01560 tree function)
01561 {
01562 int regnum = FIRST_ARGUMENT_REGISTER;
01563
01564
01565 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
01566 regnum += 1;
01567
01568 fprintf (file, "\tadd %s,#0x%x\n", reg_names[regnum], (int) delta & 0xFFFF);
01569 fputs ("\tjmpf ", file);
01570 assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
01571 putc ('\n', file);
01572 }
01573
01574
01575
01576
01577
01578
01579
01580 void
01581 xstormy16_asm_output_aligned_common (FILE *stream,
01582 tree decl,
01583 const char *name,
01584 int size,
01585 int align,
01586 int global)
01587 {
01588 rtx mem = DECL_RTL (decl);
01589 rtx symbol;
01590
01591 if (mem != NULL_RTX
01592 && GET_CODE (mem) == MEM
01593 && GET_CODE (symbol = XEXP (mem, 0)) == SYMBOL_REF
01594 && SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_XSTORMY16_BELOW100)
01595 {
01596 const char *name2;
01597 int p2align = 0;
01598
01599 switch_to_section (bss100_section);
01600
01601 while (align > 8)
01602 {
01603 align /= 2;
01604 p2align ++;
01605 }
01606
01607 name2 = default_strip_name_encoding (name);
01608 if (global)
01609 fprintf (stream, "\t.globl\t%s\n", name2);
01610 if (p2align)
01611 fprintf (stream, "\t.p2align %d\n", p2align);
01612 fprintf (stream, "\t.type\t%s, @object\n", name2);
01613 fprintf (stream, "\t.size\t%s, %d\n", name2, size);
01614 fprintf (stream, "%s:\n\t.space\t%d\n", name2, size);
01615 return;
01616 }
01617
01618 if (!global)
01619 {
01620 fprintf (stream, "\t.local\t");
01621 assemble_name (stream, name);
01622 fprintf (stream, "\n");
01623 }
01624 fprintf (stream, "\t.comm\t");
01625 assemble_name (stream, name);
01626 fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);
01627 }
01628
01629
01630
01631 static void
01632 xstormy16_asm_init_sections (void)
01633 {
01634 bss100_section
01635 = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
01636 output_section_asm_op,
01637 "\t.section \".bss_below100\",\"aw\",@nobits");
01638 }
01639
01640
01641
01642
01643 static void
01644 xstormy16_encode_section_info (tree decl, rtx r, int first)
01645 {
01646 default_encode_section_info (decl, r, first);
01647
01648 if (TREE_CODE (decl) == VAR_DECL
01649 && (lookup_attribute ("below100", DECL_ATTRIBUTES (decl))
01650 || lookup_attribute ("BELOW100", DECL_ATTRIBUTES (decl))))
01651 {
01652 rtx symbol = XEXP (r, 0);
01653
01654 gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
01655 SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_XSTORMY16_BELOW100;
01656 }
01657 }
01658
01659
01660
01661 #undef TARGET_ASM_CONSTRUCTOR
01662 #define TARGET_ASM_CONSTRUCTOR xstormy16_asm_out_constructor
01663 #undef TARGET_ASM_DESTRUCTOR
01664 #define TARGET_ASM_DESTRUCTOR xstormy16_asm_out_destructor
01665
01666 static void
01667 xstormy16_asm_out_destructor (rtx symbol, int priority)
01668 {
01669 const char *section = ".dtors";
01670 char buf[16];
01671
01672
01673 if (priority != DEFAULT_INIT_PRIORITY)
01674 {
01675 sprintf (buf, ".dtors.%.5u",
01676
01677
01678
01679 MAX_INIT_PRIORITY - priority);
01680 section = buf;
01681 }
01682
01683 switch_to_section (get_section (section, 0, NULL));
01684 assemble_align (POINTER_SIZE);
01685 assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
01686 }
01687
01688 static void
01689 xstormy16_asm_out_constructor (rtx symbol, int priority)
01690 {
01691 const char *section = ".ctors";
01692 char buf[16];
01693
01694
01695 if (priority != DEFAULT_INIT_PRIORITY)
01696 {
01697 sprintf (buf, ".ctors.%.5u",
01698
01699
01700
01701 MAX_INIT_PRIORITY - priority);
01702 section = buf;
01703 }
01704
01705 switch_to_section (get_section (section, 0, NULL));
01706 assemble_align (POINTER_SIZE);
01707 assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
01708 }
01709
01710
01711 void
01712 xstormy16_print_operand_address (FILE *file, rtx address)
01713 {
01714 HOST_WIDE_INT offset;
01715 int pre_dec, post_inc;
01716
01717
01718 if (GET_CODE (address) == CONST_INT)
01719 {
01720 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (address) & 0xFFFF);
01721 return;
01722 }
01723
01724 if (CONSTANT_P (address) || GET_CODE (address) == CODE_LABEL)
01725 {
01726 output_addr_const (file, address);
01727 return;
01728 }
01729
01730
01731
01732
01733
01734 if (GET_CODE (address) == PLUS)
01735 {
01736 gcc_assert (GET_CODE (XEXP (address, 1)) == CONST_INT);
01737 offset = INTVAL (XEXP (address, 1));
01738 address = XEXP (address, 0);
01739 }
01740 else
01741 offset = 0;
01742
01743 pre_dec = (GET_CODE (address) == PRE_DEC);
01744 post_inc = (GET_CODE (address) == POST_INC);
01745 if (pre_dec || post_inc)
01746 address = XEXP (address, 0);
01747
01748 gcc_assert (GET_CODE (address) == REG);
01749
01750 fputc ('(', file);
01751 if (pre_dec)
01752 fputs ("--", file);
01753 fputs (reg_names [REGNO (address)], file);
01754 if (post_inc)
01755 fputs ("++", file);
01756 if (offset != 0)
01757 fprintf (file, "," HOST_WIDE_INT_PRINT_DEC, offset);
01758 fputc (')', file);
01759 }
01760
01761
01762 void
01763 xstormy16_print_operand (FILE *file, rtx x, int code)
01764 {
01765 switch (code)
01766 {
01767 case 'B':
01768
01769
01770 {
01771 static int bits_set[8] = { 0, 1, 1, 2, 1, 2, 2, 3 };
01772 HOST_WIDE_INT xx = 1;
01773 HOST_WIDE_INT l;
01774
01775 if (GET_CODE (x) == CONST_INT)
01776 xx = INTVAL (x);
01777 else
01778 output_operand_lossage ("'B' operand is not constant");
01779
01780
01781
01782
01783
01784
01785 if (bits_set[xx & 7] <= 1)
01786 {
01787
01788 if ((~xx & ~(HOST_WIDE_INT)0xff) == 0)
01789 xx &= 0xff;
01790 else if ((~xx & ~(HOST_WIDE_INT)0xffff) == 0)
01791 xx &= 0xffff;
01792 l = exact_log2 (xx);
01793 }
01794 else
01795 {
01796
01797 if ((xx & ~(HOST_WIDE_INT)0xff) == 0)
01798 xx |= ~(HOST_WIDE_INT)0xff;
01799 else if ((xx & ~(HOST_WIDE_INT)0xffff) == 0)
01800 xx |= ~(HOST_WIDE_INT)0xffff;
01801 l = exact_log2 (~xx);
01802 }
01803
01804 if (l == -1)
01805 output_operand_lossage ("'B' operand has multiple bits set");
01806
01807 fprintf (file, IMMEDIATE_PREFIX HOST_WIDE_INT_PRINT_DEC, l);
01808 return;
01809 }
01810
01811 case 'C':
01812
01813 if (GET_CODE (x) == SYMBOL_REF)
01814 assemble_name (file, XSTR (x, 0));
01815 else if (GET_CODE (x) == LABEL_REF)
01816 output_asm_label (x);
01817 else
01818 xstormy16_print_operand_address (file, x);
01819 return;
01820
01821 case 'o':
01822 case 'O':
01823
01824
01825 {
01826 HOST_WIDE_INT xx = 0;
01827
01828 if (GET_CODE (x) == CONST_INT)
01829 xx = INTVAL (x);
01830 else
01831 output_operand_lossage ("'o' operand is not constant");
01832
01833 if (code == 'O')
01834 xx = -xx;
01835
01836 fprintf (file, IMMEDIATE_PREFIX HOST_WIDE_INT_PRINT_DEC, xx - 1);
01837 return;
01838 }
01839
01840 case 'b':
01841
01842 {
01843 HOST_WIDE_INT xx = 1;
01844 HOST_WIDE_INT l;
01845
01846 if (GET_CODE (x) == CONST_INT)
01847 xx = INTVAL (x);
01848 else
01849 output_operand_lossage ("'B' operand is not constant");
01850
01851 l = 7 - xx;
01852
01853 fputs (IMMEDIATE_PREFIX, file);
01854 fprintf (file, HOST_WIDE_INT_PRINT_DEC, l);
01855 return;
01856 }
01857
01858 case 0:
01859
01860 break;
01861
01862 default:
01863 output_operand_lossage ("xstormy16_print_operand: unknown code");
01864 return;
01865 }
01866
01867 switch (GET_CODE (x))
01868 {
01869 case REG:
01870 fputs (reg_names [REGNO (x)], file);
01871 break;
01872
01873 case MEM:
01874 xstormy16_print_operand_address (file, XEXP (x, 0));
01875 break;
01876
01877 default:
01878
01879
01880 fputs (IMMEDIATE_PREFIX, file);
01881 output_addr_const (file, x);
01882 break;
01883 }
01884
01885 return;
01886 }
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899 void
01900 xstormy16_expand_casesi (rtx index, rtx lower_bound, rtx range,
01901 rtx table, rtx default_label)
01902 {
01903 HOST_WIDE_INT range_i = INTVAL (range);
01904 rtx int_index;
01905
01906
01907
01908 if (range_i >= 8192)
01909 sorry ("switch statement of size %lu entries too large",
01910 (unsigned long) range_i);
01911
01912 index = expand_binop (SImode, sub_optab, index, lower_bound, NULL_RTX, 0,
01913 OPTAB_LIB_WIDEN);
01914 emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, SImode, 1,
01915 default_label);
01916 int_index = gen_lowpart_common (HImode, index);
01917 emit_insn (gen_ashlhi3 (int_index, int_index, const2_rtx));
01918 emit_jump_insn (gen_tablejump_pcrel (int_index, table));
01919 }
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929 void
01930 xstormy16_output_addr_vec (FILE *file, rtx label ATTRIBUTE_UNUSED, rtx table)
01931 {
01932 int vlen, idx;
01933
01934 switch_to_section (current_function_section ());
01935
01936 vlen = XVECLEN (table, 0);
01937 for (idx = 0; idx < vlen; idx++)
01938 {
01939 fputs ("\tjmpf ", file);
01940 output_asm_label (XEXP (XVECEXP (table, 0, idx), 0));
01941 fputc ('\n', file);
01942 }
01943 }
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956 void
01957 xstormy16_expand_call (rtx retval, rtx dest, rtx counter)
01958 {
01959 rtx call, temp;
01960 enum machine_mode mode;
01961
01962 gcc_assert (GET_CODE (dest) == MEM);
01963 dest = XEXP (dest, 0);
01964
01965 if (! CONSTANT_P (dest)
01966 && GET_CODE (dest) != REG)
01967 dest = force_reg (Pmode, dest);
01968
01969 if (retval == NULL)
01970 mode = VOIDmode;
01971 else
01972 mode = GET_MODE (retval);
01973
01974 call = gen_rtx_CALL (mode, gen_rtx_MEM (FUNCTION_MODE, dest),
01975 counter);
01976 if (retval)
01977 call = gen_rtx_SET (VOIDmode, retval, call);
01978
01979 if (! CONSTANT_P (dest))
01980 {
01981 temp = gen_reg_rtx (HImode);
01982 emit_move_insn (temp, const0_rtx);
01983 }
01984 else
01985 temp = const0_rtx;
01986
01987 call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call,
01988 gen_rtx_USE (VOIDmode, temp)));
01989 emit_call_insn (call);
01990 }
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002 void
02003 xstormy16_expand_arith (enum machine_mode mode, enum rtx_code code,
02004 rtx dest, rtx src0, rtx src1, rtx carry)
02005 {
02006 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
02007 int i;
02008 int firstloop = 1;
02009
02010 if (code == NEG)
02011 emit_move_insn (src0, const0_rtx);
02012
02013 for (i = 0; i < num_words; i++)
02014 {
02015 rtx w_src0, w_src1, w_dest;
02016 rtx insn;
02017
02018 w_src0 = simplify_gen_subreg (word_mode, src0, mode,
02019 i * UNITS_PER_WORD);
02020 w_src1 = simplify_gen_subreg (word_mode, src1, mode, i * UNITS_PER_WORD);
02021 w_dest = simplify_gen_subreg (word_mode, dest, mode, i * UNITS_PER_WORD);
02022
02023 switch (code)
02024 {
02025 case PLUS:
02026 if (firstloop
02027 && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
02028 continue;
02029
02030 if (firstloop)
02031 insn = gen_addchi4 (w_dest, w_src0, w_src1, carry);
02032 else
02033 insn = gen_addchi5 (w_dest, w_src0, w_src1, carry, carry);
02034 break;
02035
02036 case NEG:
02037 case MINUS:
02038 case COMPARE:
02039 if (code == COMPARE && i == num_words - 1)
02040 {
02041 rtx branch, sub, clobber, sub_1;
02042
02043 sub_1 = gen_rtx_MINUS (HImode, w_src0,
02044 gen_rtx_ZERO_EXTEND (HImode, carry));
02045 sub = gen_rtx_SET (VOIDmode, w_dest,
02046 gen_rtx_MINUS (HImode, sub_1, w_src1));
02047 clobber = gen_rtx_CLOBBER (VOIDmode, carry);
02048 branch = gen_rtx_SET (VOIDmode, pc_rtx,
02049 gen_rtx_IF_THEN_ELSE (VOIDmode,
02050 gen_rtx_EQ (HImode,
02051 sub_1,
02052 w_src1),
02053 pc_rtx,
02054 pc_rtx));
02055 insn = gen_rtx_PARALLEL (VOIDmode,
02056 gen_rtvec (3, branch, sub, clobber));
02057 }
02058 else if (firstloop
02059 && code != COMPARE
02060 && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
02061 continue;
02062 else if (firstloop)
02063 insn = gen_subchi4 (w_dest, w_src0, w_src1, carry);
02064 else
02065 insn = gen_subchi5 (w_dest, w_src0, w_src1, carry, carry);
02066 break;
02067
02068 case IOR:
02069 case XOR:
02070 case AND:
02071 if (GET_CODE (w_src1) == CONST_INT
02072 && INTVAL (w_src1) == -(code == AND))
02073 continue;
02074
02075 insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_fmt_ee (code, mode,
02076 w_src0, w_src1));
02077 break;
02078
02079 case NOT:
02080 insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_NOT (mode, w_src0));
02081 break;
02082
02083 default:
02084 gcc_unreachable ();
02085 }
02086
02087 firstloop = 0;
02088 emit (insn);
02089 }
02090
02091
02092
02093 if (firstloop)
02094 emit (gen_nop ());
02095 }
02096
02097
02098
02099
02100
02101
02102
02103 const char *
02104 xstormy16_output_shift (enum machine_mode mode, enum rtx_code code,
02105 rtx x, rtx size_r, rtx temp)
02106 {
02107 HOST_WIDE_INT size;
02108 const char *r0, *r1, *rt;
02109 static char r[64];
02110
02111 gcc_assert (GET_CODE (size_r) == CONST_INT
02112 && GET_CODE (x) == REG && mode == SImode);
02113 size = INTVAL (size_r) & (GET_MODE_BITSIZE (mode) - 1);
02114
02115 if (size == 0)
02116 return "";
02117
02118 r0 = reg_names [REGNO (x)];
02119 r1 = reg_names [REGNO (x) + 1];
02120
02121
02122 if (size == 1)
02123 {
02124 switch (code)
02125 {
02126 case ASHIFT:
02127 sprintf (r, "shl %s,#1 | rlc %s,#1", r0, r1);
02128 break;
02129 case ASHIFTRT:
02130 sprintf (r, "asr %s,#1 | rrc %s,#1", r1, r0);
02131 break;
02132 case LSHIFTRT:
02133 sprintf (r, "shr %s,#1 | rrc %s,#1", r1, r0);
02134 break;
02135 default:
02136 gcc_unreachable ();
02137 }
02138 return r;
02139 }
02140
02141
02142 if (size == 16)
02143 {
02144 switch (code)
02145 {
02146 case ASHIFT:
02147 sprintf (r, "mov %s,%s | mov %s,#0", r1, r0, r0);
02148 break;
02149 case ASHIFTRT:
02150 sprintf (r, "mov %s,%s | asr %s,#15", r0, r1, r1);
02151 break;
02152 case LSHIFTRT:
02153 sprintf (r, "mov %s,%s | mov %s,#0", r0, r1, r1);
02154 break;
02155 default:
02156 gcc_unreachable ();
02157 }
02158 return r;
02159 }
02160 if (size > 16)
02161 {
02162 switch (code)
02163 {
02164 case ASHIFT:
02165 sprintf (r, "mov %s,%s | mov %s,#0 | shl %s,#%d",
02166 r1, r0, r0, r1, (int) size - 16);
02167 break;
02168 case ASHIFTRT:
02169 sprintf (r, "mov %s,%s | asr %s,#15 | asr %s,#%d",
02170 r0, r1, r1, r0, (int) size - 16);
02171 break;
02172 case LSHIFTRT:
02173 sprintf (r, "mov %s,%s | mov %s,#0 | shr %s,#%d",
02174 r0, r1, r1, r0, (int) size - 16);
02175 break;
02176 default:
02177 gcc_unreachable ();
02178 }
02179 return r;
02180 }
02181
02182
02183
02184 rt = reg_names [REGNO (temp)];
02185 switch (code)
02186 {
02187 case ASHIFT:
02188 sprintf (r,
02189 "mov %s,%s | shl %s,#%d | shl %s,#%d | shr %s,#%d | or %s,%s",
02190 rt, r0, r0, (int) size, r1, (int) size, rt, (int) (16-size),
02191 r1, rt);
02192 break;
02193 case ASHIFTRT:
02194 sprintf (r,
02195 "mov %s,%s | asr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s",
02196 rt, r1, r1, (int) size, r0, (int) size, rt, (int) (16-size),
02197 r0, rt);
02198 break;
02199 case LSHIFTRT:
02200 sprintf (r,
02201 "mov %s,%s | shr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s",
02202 rt, r1, r1, (int) size, r0, (int) size, rt, (int) (16-size),
02203 r0, rt);
02204 break;
02205 default:
02206 gcc_unreachable ();
02207 }
02208 return r;
02209 }
02210
02211
02212
02213
02214 int
02215 xstormy16_interrupt_function_p (void)
02216 {
02217 tree attributes;
02218
02219
02220
02221
02222 if (!cfun)
02223 return 0;
02224
02225 attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
02226 return lookup_attribute ("interrupt", attributes) != NULL_TREE;
02227 }
02228
02229 #undef TARGET_ATTRIBUTE_TABLE
02230 #define TARGET_ATTRIBUTE_TABLE xstormy16_attribute_table
02231 static tree xstormy16_handle_interrupt_attribute
02232 (tree *, tree, tree, int, bool *);
02233 static tree xstormy16_handle_below100_attribute
02234 (tree *, tree, tree, int, bool *);
02235
02236 static const struct attribute_spec xstormy16_attribute_table[] =
02237 {
02238
02239 { "interrupt", 0, 0, false, true, true, xstormy16_handle_interrupt_attribute },
02240 { "BELOW100", 0, 0, false, false, false, xstormy16_handle_below100_attribute },
02241 { "below100", 0, 0, false, false, false, xstormy16_handle_below100_attribute },
02242 { NULL, 0, 0, false, false, false, NULL }
02243 };
02244
02245
02246
02247 static tree
02248 xstormy16_handle_interrupt_attribute (tree *node, tree name,
02249 tree args ATTRIBUTE_UNUSED,
02250 int flags ATTRIBUTE_UNUSED,
02251 bool *no_add_attrs)
02252 {
02253 if (TREE_CODE (*node) != FUNCTION_TYPE)
02254 {
02255 warning (OPT_Wattributes, "%qs attribute only applies to functions",
02256 IDENTIFIER_POINTER (name));
02257 *no_add_attrs = true;
02258 }
02259
02260 return NULL_TREE;
02261 }
02262
02263
02264
02265 static tree
02266 xstormy16_handle_below100_attribute (tree *node,
02267 tree name ATTRIBUTE_UNUSED,
02268 tree args ATTRIBUTE_UNUSED,
02269 int flags ATTRIBUTE_UNUSED,
02270 bool *no_add_attrs)
02271 {
02272 if (TREE_CODE (*node) != VAR_DECL
02273 && TREE_CODE (*node) != POINTER_TYPE
02274 && TREE_CODE (*node) != TYPE_DECL)
02275 {
02276 warning (OPT_Wattributes,
02277 "%<__BELOW100__%> attribute only applies to variables");
02278 *no_add_attrs = true;
02279 }
02280 else if (args == NULL_TREE && TREE_CODE (*node) == VAR_DECL)
02281 {
02282 if (! (TREE_PUBLIC (*node) || TREE_STATIC (*node)))
02283 {
02284 warning (OPT_Wattributes, "__BELOW100__ attribute not allowed "
02285 "with auto storage class");
02286 *no_add_attrs = true;
02287 }
02288 }
02289
02290 return NULL_TREE;
02291 }
02292
02293 #undef TARGET_INIT_BUILTINS
02294 #define TARGET_INIT_BUILTINS xstormy16_init_builtins
02295 #undef TARGET_EXPAND_BUILTIN
02296 #define TARGET_EXPAND_BUILTIN xstormy16_expand_builtin
02297
02298 static struct {
02299 const char *name;
02300 int md_code;
02301 const char *arg_ops;
02302 const char *arg_types;
02303 } s16builtins[] = {
02304 { "__sdivlh", CODE_FOR_sdivlh, "rt01", "sls" },
02305 { "__smodlh", CODE_FOR_sdivlh, "tr01", "sls" },
02306 { "__udivlh", CODE_FOR_udivlh, "rt01", "SLS" },
02307 { "__umodlh", CODE_FOR_udivlh, "tr01", "SLS" },
02308 { 0, 0, 0, 0 }
02309 };
02310
02311 static void
02312 xstormy16_init_builtins (void)
02313 {
02314 tree args, ret_type, arg;
02315 int i, a;
02316
02317 ret_type = void_type_node;
02318
02319 for (i=0; s16builtins[i].name; i++)
02320 {
02321 args = void_list_node;
02322 for (a=strlen (s16builtins[i].arg_types)-1; a>=0; a--)
02323 {
02324 switch (s16builtins[i].arg_types[a])
02325 {
02326 case 's': arg = short_integer_type_node; break;
02327 case 'S': arg = short_unsigned_type_node; break;
02328 case 'l': arg = long_integer_type_node; break;
02329 case 'L': arg = long_unsigned_type_node; break;
02330 default: gcc_unreachable ();
02331 }
02332 if (a == 0)
02333 ret_type = arg;
02334 else
02335 args = tree_cons (NULL_TREE, arg, args);
02336 }
02337 lang_hooks.builtin_function (s16builtins[i].name,
02338 build_function_type (ret_type, args),
02339 i, BUILT_IN_MD, NULL, NULL);
02340 }
02341 }
02342
02343 static rtx
02344 xstormy16_expand_builtin(tree exp, rtx target,
02345 rtx subtarget ATTRIBUTE_UNUSED,
02346 enum machine_mode mode ATTRIBUTE_UNUSED,
02347 int ignore ATTRIBUTE_UNUSED)
02348 {
02349 rtx op[10], args[10], pat, copyto[10], retval = 0;
02350 tree fndecl, argtree;
02351 int i, a, o, code;
02352
02353 fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
02354 argtree = TREE_OPERAND (exp, 1);
02355 i = DECL_FUNCTION_CODE (fndecl);
02356 code = s16builtins[i].md_code;
02357
02358 for (a = 0; a < 10 && argtree; a++)
02359 {
02360 args[a] = expand_expr (TREE_VALUE (argtree), NULL_RTX, VOIDmode, 0);
02361 argtree = TREE_CHAIN (argtree);
02362 }
02363
02364 for (o = 0; s16builtins[i].arg_ops[o]; o++)
02365 {
02366 char ao = s16builtins[i].arg_ops[o];
02367 char c = insn_data[code].operand[o].constraint[0];
02368 int omode;
02369
02370 copyto[o] = 0;
02371
02372 omode = insn_data[code].operand[o].mode;
02373 if (ao == 'r')
02374 op[o] = target ? target : gen_reg_rtx (omode);
02375 else if (ao == 't')
02376 op[o] = gen_reg_rtx (omode);
02377 else
02378 op[o] = args[(int) hex_value (ao)];
02379
02380 if (! (*insn_data[code].operand[o].predicate) (op[o], GET_MODE (op[o])))
02381 {
02382 if (c == '+' || c == '=')
02383 {
02384 copyto[o] = op[o];
02385 op[o] = gen_reg_rtx (omode);
02386 }
02387 else
02388 op[o] = copy_to_mode_reg (omode, op[o]);
02389 }
02390
02391 if (ao == 'r')
02392 retval = op[o];
02393 }
02394
02395 pat = GEN_FCN (code) (op[0], op[1], op[2], op[3], op[4],
02396 op[5], op[6], op[7], op[8], op[9]);
02397 emit_insn (pat);
02398
02399 for (o = 0; s16builtins[i].arg_ops[o]; o++)
02400 if (copyto[o])
02401 {
02402 emit_move_insn (copyto[o], op[o]);
02403 if (op[o] == retval)
02404 retval = copyto[o];
02405 }
02406
02407 return retval;
02408 }
02409
02410
02411
02412
02413
02414 static void
02415 combine_bnp (rtx insn)
02416 {
02417 int insn_code, regno, need_extend;
02418 unsigned int mask;
02419 rtx cond, reg, and, load, qireg, mem;
02420 enum machine_mode load_mode = QImode;
02421 enum machine_mode and_mode = QImode;
02422 rtx shift = NULL_RTX;
02423
02424 insn_code = recog_memoized (insn);
02425 if (insn_code != CODE_FOR_cbranchhi
02426 && insn_code != CODE_FOR_cbranchhi_neg)
02427 return;
02428
02429 cond = XVECEXP (PATTERN (insn), 0, 0);
02430 cond = XEXP (cond, 1);
02431 cond = XEXP (cond, 0);
02432 switch (GET_CODE (cond))
02433 {
02434 case NE:
02435 case EQ:
02436 need_extend = 0;
02437 break;
02438 case LT:
02439 case GE:
02440 need_extend = 1;
02441 break;
02442 default:
02443 return;
02444 }
02445
02446 reg = XEXP (cond, 0);
02447 if (GET_CODE (reg) != REG)
02448 return;
02449 regno = REGNO (reg);
02450 if (XEXP (cond, 1) != const0_rtx)
02451 return;
02452 if (! find_regno_note (insn, REG_DEAD, regno))
02453 return;
02454 qireg = gen_rtx_REG (QImode, regno);
02455
02456 if (need_extend)
02457 {
02458
02459
02460 for (and = prev_real_insn (insn); and; and = prev_real_insn (and))
02461 {
02462 int and_code = recog_memoized (and);
02463
02464 if (and_code == CODE_FOR_extendqihi2
02465 && rtx_equal_p (SET_DEST (PATTERN (and)), reg)
02466 && rtx_equal_p (XEXP (SET_SRC (PATTERN (and)), 0), qireg))
02467 break;
02468
02469 if (and_code == CODE_FOR_movhi_internal
02470 && rtx_equal_p (SET_DEST (PATTERN (and)), reg))
02471 {
02472
02473 and = insn;
02474 break;
02475 }
02476
02477 if (reg_mentioned_p (reg, and))
02478 return;
02479
02480 if (GET_CODE (and) != NOTE
02481 && GET_CODE (and) != INSN)
02482 return;
02483 }
02484 }
02485 else
02486 {
02487
02488 for (and = prev_real_insn (insn); and; and = prev_real_insn (and))
02489 {
02490 if (recog_memoized (and) == CODE_FOR_andhi3
02491 && rtx_equal_p (SET_DEST (PATTERN (and)), reg)
02492 && rtx_equal_p (XEXP (SET_SRC (PATTERN (and)), 0), reg))
02493 break;
02494
02495 if (reg_mentioned_p (reg, and))
02496 return;
02497
02498 if (GET_CODE (and) != NOTE
02499 && GET_CODE (and) != INSN)
02500 return;
02501 }
02502
02503 if (and)
02504 {
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514 for (shift = prev_real_insn (and); shift; shift = prev_real_insn (shift))
02515 {
02516 if (recog_memoized (shift) == CODE_FOR_lshrhi3
02517 && rtx_equal_p (SET_DEST (XVECEXP (PATTERN (shift), 0, 0)), reg)
02518 && rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (shift), 0, 0)), 0), reg))
02519 break;
02520
02521 if (reg_mentioned_p (reg, shift)
02522 || (GET_CODE (shift) != NOTE
02523 && GET_CODE (shift) != INSN))
02524 {
02525 shift = NULL_RTX;
02526 break;
02527 }
02528 }
02529 }
02530 }
02531 if (!and)
02532 return;
02533
02534 for (load = shift ? prev_real_insn (shift) : prev_real_insn (and);
02535 load;
02536 load = prev_real_insn (load))
02537 {
02538 int load_code = recog_memoized (load);
02539
02540 if (load_code == CODE_FOR_movhi_internal
02541 && rtx_equal_p (SET_DEST (PATTERN (load)), reg)
02542 && xstormy16_below100_operand (SET_SRC (PATTERN (load)), HImode)
02543 && ! MEM_VOLATILE_P (SET_SRC (PATTERN (load))))
02544 {
02545 load_mode = HImode;
02546 break;
02547 }
02548
02549 if (load_code == CODE_FOR_movqi_internal
02550 && rtx_equal_p (SET_DEST (PATTERN (load)), qireg)
02551 && xstormy16_below100_operand (SET_SRC (PATTERN (load)), QImode))
02552 {
02553 load_mode = QImode;
02554 break;
02555 }
02556
02557 if (load_code == CODE_FOR_zero_extendqihi2
02558 && rtx_equal_p (SET_DEST (PATTERN (load)), reg)
02559 && xstormy16_below100_operand (XEXP (SET_SRC (PATTERN (load)), 0), QImode))
02560 {
02561 load_mode = QImode;
02562 and_mode = HImode;
02563 break;
02564 }
02565
02566 if (reg_mentioned_p (reg, load))
02567 return;
02568
02569 if (GET_CODE (load) != NOTE
02570 && GET_CODE (load) != INSN)
02571 return;
02572 }
02573 if (!load)
02574 return;
02575
02576 mem = SET_SRC (PATTERN (load));
02577
02578 if (need_extend)
02579 {
02580 mask = (load_mode == HImode) ? 0x8000 : 0x80;
02581
02582
02583
02584
02585 if (GET_CODE (mem) == ZERO_EXTEND)
02586 mem = XEXP (mem, 0);
02587 }
02588 else
02589 {
02590 if (!xstormy16_onebit_set_operand (XEXP (SET_SRC (PATTERN (and)), 1), load_mode))
02591 return;
02592
02593 mask = (int) INTVAL (XEXP (SET_SRC (PATTERN (and)), 1));
02594
02595 if (shift)
02596 mask <<= INTVAL (XEXP (SET_SRC (XVECEXP (PATTERN (shift), 0, 0)), 1));
02597 }
02598
02599 if (load_mode == HImode)
02600 {
02601 rtx addr = XEXP (mem, 0);
02602
02603 if (! (mask & 0xff))
02604 {
02605 addr = plus_constant (addr, 1);
02606 mask >>= 8;
02607 }
02608 mem = gen_rtx_MEM (QImode, addr);
02609 }
02610
02611 if (need_extend)
02612 XEXP (cond, 0) = gen_rtx_SIGN_EXTEND (HImode, mem);
02613 else
02614 XEXP (cond, 0) = gen_rtx_AND (and_mode, mem, GEN_INT (mask));
02615
02616 INSN_CODE (insn) = -1;
02617 delete_insn (load);
02618
02619 if (and != insn)
02620 delete_insn (and);
02621
02622 if (shift != NULL_RTX)
02623 delete_insn (shift);
02624 }
02625
02626 static void
02627 xstormy16_reorg (void)
02628 {
02629 rtx insn;
02630
02631 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
02632 {
02633 if (! JUMP_P (insn))
02634 continue;
02635 combine_bnp (insn);
02636 }
02637 }
02638
02639
02640
02641
02642 static bool
02643 xstormy16_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
02644 {
02645 HOST_WIDE_INT size = int_size_in_bytes (type);
02646 return (size == -1 || size > UNITS_PER_WORD * NUM_ARGUMENT_REGISTERS);
02647 }
02648
02649 #undef TARGET_ASM_ALIGNED_HI_OP
02650 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
02651 #undef TARGET_ASM_ALIGNED_SI_OP
02652 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
02653 #undef TARGET_ENCODE_SECTION_INFO
02654 #define TARGET_ENCODE_SECTION_INFO xstormy16_encode_section_info
02655
02656
02657 #undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
02658 #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
02659
02660 #undef TARGET_ASM_OUTPUT_MI_THUNK
02661 #define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk
02662 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
02663 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
02664
02665 #undef TARGET_RTX_COSTS
02666 #define TARGET_RTX_COSTS xstormy16_rtx_costs
02667 #undef TARGET_ADDRESS_COST
02668 #define TARGET_ADDRESS_COST xstormy16_address_cost
02669
02670 #undef TARGET_BUILD_BUILTIN_VA_LIST
02671 #define TARGET_BUILD_BUILTIN_VA_LIST xstormy16_build_builtin_va_list
02672 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
02673 #define TARGET_GIMPLIFY_VA_ARG_EXPR xstormy16_expand_builtin_va_arg
02674
02675 #undef TARGET_PROMOTE_FUNCTION_ARGS
02676 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
02677 #undef TARGET_PROMOTE_FUNCTION_RETURN
02678 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
02679 #undef TARGET_PROMOTE_PROTOTYPES
02680 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
02681
02682 #undef TARGET_RETURN_IN_MEMORY
02683 #define TARGET_RETURN_IN_MEMORY xstormy16_return_in_memory
02684
02685 #undef TARGET_MACHINE_DEPENDENT_REORG
02686 #define TARGET_MACHINE_DEPENDENT_REORG xstormy16_reorg
02687
02688 struct gcc_target targetm = TARGET_INITIALIZER;
02689
02690 #include "gt-stormy16.h"