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