OSDN Git Service

* Makefile.in (final.o): Depend on target.h.
[pf3gnuchains/gcc-fork.git] / gcc / config / clipper / clipper.c
1 /* Subroutines for insn-output.c for Clipper
2    Copyright (C) 1987, 1988, 1991, 1997, 1998,
3    1999, 2000 Free Software Foundation, Inc.
4    Contributed by Holger Teutsch (holger@hotbso.rhein-main.de)
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "output.h"
32 #include "insn-attr.h"
33 #include "tree.h"
34 #include "expr.h"
35 #include "c-tree.h"
36 #include "function.h"
37 #include "flags.h"
38 #include "recog.h"
39 #include "tm_p.h"
40 #include "target.h"
41 #include "target-def.h"
42
43 static void clipper_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
44 static void clipper_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
45
46 extern char regs_ever_live[];
47
48 extern int frame_pointer_needed;
49
50 static int frame_size;
51 \f
52 /* Initialize the GCC target structure.  */
53 #undef TARGET_ASM_FUNCTION_PROLOGUE
54 #define TARGET_ASM_FUNCTION_PROLOGUE clipper_output_function_prologue
55 #undef TARGET_ASM_FUNCTION_EPILOGUE
56 #define TARGET_ASM_FUNCTION_EPILOGUE clipper_output_function_epilogue
57
58 struct gcc_target target = TARGET_INITIALIZER;
59 \f
60 /* Compute size of a clipper stack frame where 'lsize' is the required
61    space for local variables.  */
62
63 int
64 clipper_frame_size (lsize)
65      int lsize;
66 {
67   int i, size;                          /* total size of frame */
68   int save_size;
69   save_size = 0;                        /* compute size for reg saves */
70
71   for (i = 16; i < 32; i++)
72     if (regs_ever_live[i] && !call_used_regs[i])
73       save_size += 8;
74
75   for (i = 0; i < 16; i++)
76     if (regs_ever_live[i] && !call_used_regs[i])
77       save_size += 4;
78
79   size = lsize + save_size;
80
81   size = (size + 7) & ~7;               /* align to 64 Bit */
82   return size;
83 }
84
85 /* Prologue and epilogue output
86    Function is entered with pc pushed, i.e. stack is 32 bit aligned
87
88    current_function_args_size == 0 means that the current function's args
89    are passed totally in registers i.e fp is not used as ap.
90    If frame_size is also 0 the current function does not push anything and
91    can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit
92    can be omitted.  */
93
94 static void
95 clipper_output_function_prologue (file, lsize)
96      FILE *file;
97      HOST_WIDE_INT lsize;                       /* size for locals */
98 {
99   int i, offset;
100   int size;
101
102   frame_size = size = clipper_frame_size (lsize);
103
104   if (frame_pointer_needed)
105     {
106       fputs ("\tpushw  fp,sp\n", file);
107       fputs ("\tmovw   sp,fp\n", file);
108     }
109   else if (size != 0 || current_function_args_size != 0)
110     {
111       size += 4;                        /* keep stack aligned */
112       frame_size = size;                /* must push data or access args */
113     }
114
115   if (size)
116     {
117       if (size < 16)
118         fprintf (file, "\tsubq   $%d,sp\n", size);
119       else
120         fprintf (file, "\tsubi   $%d,sp\n", size);
121
122       /* register save slots are relative to sp, because we have small positive
123          displacements and this works whether we have a frame pointer or not */
124
125       offset = 0;
126       for (i = 16; i < 32; i++)
127         if (regs_ever_live[i] && !call_used_regs[i])
128           {
129             if (offset == 0)
130               fprintf (file, "\tstord  f%d,(sp)\n", i-16);
131             else
132               fprintf (file, "\tstord  f%d,%d(sp)\n", i-16, offset);
133             offset += 8;
134           }
135
136       for (i = 0; i < 16; i++)
137         if (regs_ever_live[i] && !call_used_regs[i])
138           {
139             if (offset == 0)
140               fprintf (file, "\tstorw  r%d,(sp)\n", i);
141             else
142               fprintf (file, "\tstorw  r%d,%d(sp)\n", i, offset);
143             offset += 4;
144           }
145     }
146 }
147
148 static void
149 clipper_output_function_epilogue (file, size)
150      FILE *file;
151      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
152 {
153   int i, offset;
154
155   if (frame_pointer_needed)
156     {
157       offset = -frame_size;
158
159       for (i = 16; i < 32; i++)
160         if (regs_ever_live[i] && !call_used_regs[i])
161           {
162             fprintf (file, "\tloadd  %d(fp),f%d\n", offset, i-16);
163             offset += 8;
164           }
165
166       for (i = 0; i < 16; i++)
167         if (regs_ever_live[i] && !call_used_regs[i])
168           {
169             fprintf (file, "\tloadw  %d(fp),r%d\n", offset, i);
170             offset += 4;
171           }
172
173       fputs ("\tmovw   fp,sp\n\tpopw   sp,fp\n\tret    sp\n",
174              file);
175     }
176
177   else                                  /* no frame pointer */
178     {
179       offset = 0;
180
181       for (i = 16; i < 32; i++)
182         if (regs_ever_live[i] && !call_used_regs[i])
183           {
184             if (offset == 0)
185               fprintf (file, "\tloadd  (sp),f%d\n", i-16);
186             else
187               fprintf (file, "\tloadd  %d(sp),f%d\n", offset, i-16);
188             offset += 8;
189           }
190
191       for (i = 0; i < 16; i++)
192         if (regs_ever_live[i] && !call_used_regs[i])
193           {
194             if (offset == 0)
195               fprintf (file, "\tloadw  (sp),r%d\n", i);
196             else
197               fprintf (file, "\tloadw  %d(sp),r%d\n", offset, i);
198             offset += 4;
199           }
200
201       if (frame_size > 0)
202         {
203           if (frame_size < 16)
204             fprintf (file, "\taddq   $%d,sp\n", frame_size);
205           else
206             fprintf (file, "\taddi   $%d,sp\n", frame_size);
207         }
208
209       fputs ("\tret    sp\n", file);
210     }
211 }
212
213 /*
214  * blockmove
215  *
216  * clipper_movstr ()
217  */
218 void
219 clipper_movstr (operands)
220      rtx *operands;
221 {
222   rtx dst,src,cnt,tmp,top,bottom,xops[3];
223   int align;
224   int fixed;
225
226   extern FILE *asm_out_file;
227
228   dst = operands[0];
229   src = operands[1];
230   /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */
231   align = INTVAL (operands[3]);
232   tmp = operands[4];
233   cnt = operands[5];
234
235   if (GET_CODE (operands[2]) == CONST_INT) /* fixed size move */
236     {
237       if ((fixed = INTVAL (operands[2])) <= 0)
238         abort ();
239
240       if (fixed <16)
241         output_asm_insn ("loadq  %2,%5", operands);
242       else
243         output_asm_insn ("loadi  %2,%5", operands);
244     }
245   else
246     {
247       fixed = 0;
248       bottom = (rtx)gen_label_rtx ();   /* need a bottom label */
249       xops[0] = cnt; xops[1] = bottom;
250       output_asm_insn ("movw   %2,%5", operands); /* count is scratch reg 5 */
251       output_asm_insn ("brle   %l1", xops);
252     }
253
254
255   top = (rtx)gen_label_rtx ();          /* top of loop label */
256   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (top));
257
258
259   xops[0] = src; xops[1] = tmp; xops[2] = dst;
260
261   if (fixed && (align & 0x3) == 0)      /* word aligned move with known size */
262     {
263       if (fixed >= 4)
264         {
265           rtx xops1[2];
266           output_asm_insn(
267             "loadw  %a0,%1\n\taddq   $4,%0\n\tstorw  %1,%a2\n\taddq   $4,%2",
268                           xops);
269
270           xops1[0] = cnt; xops1[1] = top;
271           output_asm_insn ("subq   $4,%0\n\tbrgt   %l1", xops1);
272         }
273
274       if (fixed & 0x2)
275         {
276           output_asm_insn ("loadh  %a0,%1\n\tstorh  %1,%a2", xops);
277           if (fixed & 0x1)
278             output_asm_insn ("loadb  2%a0,%1\n\tstorb  %1,2%a2", xops);
279         }
280       else
281         if (fixed & 0x1)
282           output_asm_insn ("loadb  %a0,%1\n\tstorb  %1,%a2", xops);
283     }
284   else
285     {
286       output_asm_insn(
287           "loadb  %a0,%1\n\taddq   $1,%0\n\tstorb  %1,%a2\n\taddq   $1,%2",
288                       xops);
289
290       xops[0] = cnt; xops[1] = top;
291       output_asm_insn ("subq   $1,%0\n\tbrgt   %l1", xops);
292     }
293
294   if (fixed == 0)
295     ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (bottom));
296 }
297
298 \f
299 void
300 print_operand_address (file, addr)
301      FILE *file;
302      register rtx addr;
303 {
304   rtx op0,op1;
305
306   switch (GET_CODE (addr))
307     {
308     case REG:
309       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
310       break;
311
312     case PLUS:
313       /* can be 'symbol + reg' or 'reg + reg' */
314
315       op0 = XEXP (addr, 0);
316       op1 = XEXP (addr, 1);
317
318       if (GET_CODE (op0) == REG && GET_CODE (op1) == REG)
319         {
320           fprintf (file, "[%s](%s)",
321                    reg_names[REGNO (op0)], reg_names[REGNO (op1)]);
322           break;
323         }
324
325       if (GET_CODE (op0) == REG && CONSTANT_ADDRESS_P (op1))
326         {
327           output_addr_const (file, op1);
328           fprintf (file, "(%s)", reg_names[REGNO (op0)]);
329           break;
330         }
331
332       if (GET_CODE (op1) == REG && CONSTANT_ADDRESS_P (op0))
333         {
334           output_addr_const (file, op0);
335           fprintf (file, "(%s)", reg_names[REGNO (op1)]);
336           break;
337         }
338       abort ();                         /* Oh no */
339
340     default:
341       output_addr_const (file, addr);
342     }
343 }
344
345 \f
346 const char *
347 rev_cond_name (op)
348      rtx op;
349 {
350   switch (GET_CODE (op))
351     {
352     case EQ:
353       return "ne";
354     case NE:
355       return "eq";
356     case LT:
357       return "ge";
358     case LE:
359       return "gt";
360     case GT:
361       return "le";
362     case GE:
363       return "lt";
364     case LTU:
365       return "geu";
366     case LEU:
367       return "gtu";
368     case GTU:
369       return "leu";
370     case GEU:
371       return "ltu";
372
373     default:
374       abort ();
375     }
376 }
377
378 \f
379 /* Dump the argument register to the stack; return the location
380    of the block.  */
381
382 struct rtx_def *
383 clipper_builtin_saveregs ()
384 {
385   rtx block, addr, r0_addr, r1_addr, f0_addr, f1_addr, mem;
386   int set = get_varargs_alias_set ();
387
388   /* Allocate the save area for r0,r1,f0,f1 */
389
390   block = assign_stack_local (BLKmode, 6 * UNITS_PER_WORD, 2 * BITS_PER_WORD);
391
392   RTX_UNCHANGING_P (block) = 1;
393   RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
394
395   addr = XEXP (block, 0);
396
397   r0_addr = addr;
398   r1_addr = plus_constant (addr, 4);
399   f0_addr = plus_constant (addr, 8);
400   f1_addr = plus_constant (addr, 16);
401
402   /* Store int regs  */
403
404   mem = gen_rtx_MEM (SImode, r0_addr);
405   MEM_ALIAS_SET (mem) = set;
406   emit_move_insn (mem, gen_rtx_REG (SImode, 0));
407
408   mem = gen_rtx_MEM (SImode, r1_addr);
409   MEM_ALIAS_SET (mem) = set;
410   emit_move_insn (mem, gen_rtx_REG (SImode, 1));
411
412   /* Store float regs  */
413
414   mem = gen_rtx_MEM (DFmode, f0_addr);
415   MEM_ALIAS_SET (mem) = set;
416   emit_move_insn (mem, gen_rtx_REG (DFmode, 16));
417
418   mem = gen_rtx_MEM (DFmode, f1_addr);
419   MEM_ALIAS_SET (mem) = set;
420   emit_move_insn (mem, gen_rtx_REG (DFmode, 17));
421
422   if (current_function_check_memory_usage)
423     {
424       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
425                          f0_addr, ptr_mode,
426                          GEN_INT (GET_MODE_SIZE (DFmode)),
427                          TYPE_MODE (sizetype),
428                          GEN_INT (MEMORY_USE_RW),
429                          TYPE_MODE (integer_type_node));
430       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
431                          f1_addr, ptr_mode,
432                          GEN_INT (GET_MODE_SIZE (DFmode)),
433                          TYPE_MODE (sizetype),
434                          GEN_INT (MEMORY_USE_RW), 
435                          TYPE_MODE (integer_type_node));
436       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
437                          r0_addr, ptr_mode,
438                          GEN_INT (GET_MODE_SIZE (SImode)),
439                          TYPE_MODE (sizetype),
440                          GEN_INT (MEMORY_USE_RW),
441                          TYPE_MODE (integer_type_node));
442       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
443                          r1_addr, ptr_mode,
444                          GEN_INT (GET_MODE_SIZE (SImode)),
445                          TYPE_MODE (sizetype),
446                          GEN_INT (MEMORY_USE_RW),
447                          TYPE_MODE (integer_type_node));
448     }
449
450   return addr;
451 }
452
453 tree
454 clipper_build_va_list ()
455 {
456   tree record, ap, reg, num;
457
458   /*
459     struct
460     {
461       int __va_ap;              // pointer to stack args
462       void *__va_reg[4];        // pointer to r0,f0,r1,f1
463       int __va_num;             // number of args processed
464     };
465   */
466
467   record = make_node (RECORD_TYPE);
468
469   num = build_decl (FIELD_DECL, get_identifier ("__va_num"),
470                     integer_type_node);
471   DECL_FIELD_CONTEXT (num) = record;
472
473   reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"),
474                     build_array_type (ptr_type_node,
475                                       build_index_type (build_int_2 (3, 0))));
476   DECL_FIELD_CONTEXT (reg) = record;
477   TREE_CHAIN (reg) = num;
478
479   ap = build_decl (FIELD_DECL, get_identifier ("__va_ap"),
480                    integer_type_node);
481   DECL_FIELD_CONTEXT (ap) = record;
482   TREE_CHAIN (ap) = reg;
483
484   TYPE_FIELDS (record) = ap;
485   layout_type (record);
486
487   return record;
488 }
489
490 void
491 clipper_va_start (stdarg_p, valist, nextarg)
492      int stdarg_p;
493      tree valist;
494      rtx nextarg ATTRIBUTE_UNUSED;
495 {
496   tree ap_field, reg_field, num_field;
497   tree t, u, save_area;
498
499   ap_field = TYPE_FIELDS (TREE_TYPE (valist));
500   reg_field = TREE_CHAIN (ap_field);
501   num_field = TREE_CHAIN (reg_field);
502
503   ap_field = build (COMPONENT_REF, TREE_TYPE (ap_field), valist, ap_field);
504   reg_field = build (COMPONENT_REF, TREE_TYPE (reg_field), valist, reg_field);
505   num_field = build (COMPONENT_REF, TREE_TYPE (num_field), valist, num_field);
506
507   /* Call __builtin_saveregs to save r0, r1, f0, and f1 in a block.  */
508
509   save_area = make_tree (integer_type_node, expand_builtin_saveregs ());
510
511   /* Set __va_ap.  */
512
513   t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
514   if (stdarg_p && current_function_args_info.size != 0)
515     t = build (PLUS_EXPR, ptr_type_node, t,
516                build_int_2 (current_function_args_info.size, 0));
517   t = build (MODIFY_EXPR, TREE_TYPE (ap_field), ap_field, t);
518   TREE_SIDE_EFFECTS (t) = 1;
519   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
520
521   /* Set the four entries of __va_reg.  */
522
523   t = build1 (NOP_EXPR, ptr_type_node, save_area);
524   u = build (ARRAY_REF, ptr_type_node, reg_field, build_int_2 (0, 0));
525   t = build (MODIFY_EXPR, ptr_type_node, u, t);
526   TREE_SIDE_EFFECTS (t) = 1;
527   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
528
529   t = fold (build (PLUS_EXPR, integer_type_node, save_area,
530                    build_int_2 (8, 0)));
531   t = build1 (NOP_EXPR, ptr_type_node, save_area);
532   u = build (ARRAY_REF, ptr_type_node, reg_field, build_int_2 (1, 0));
533   t = build (MODIFY_EXPR, ptr_type_node, u, t);
534   TREE_SIDE_EFFECTS (t) = 1;
535   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
536
537   t = fold (build (PLUS_EXPR, integer_type_node, save_area,
538                    build_int_2 (4, 0)));
539   t = build1 (NOP_EXPR, ptr_type_node, save_area);
540   u = build (ARRAY_REF, ptr_type_node, reg_field, build_int_2 (2, 0));
541   t = build (MODIFY_EXPR, ptr_type_node, u, t);
542   TREE_SIDE_EFFECTS (t) = 1;
543   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
544
545   t = fold (build (PLUS_EXPR, integer_type_node, save_area,
546                    build_int_2 (16, 0)));
547   t = build1 (NOP_EXPR, ptr_type_node, save_area);
548   u = build (ARRAY_REF, ptr_type_node, reg_field, build_int_2 (3, 0));
549   t = build (MODIFY_EXPR, ptr_type_node, u, t);
550   TREE_SIDE_EFFECTS (t) = 1;
551   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
552
553   /* Set __va_num.  */
554
555   t = build_int_2 (current_function_args_info.num, 0);
556   t = build (MODIFY_EXPR, TREE_TYPE (num_field), num_field, t);
557   TREE_SIDE_EFFECTS (t) = 1;
558   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
559 }
560
561 rtx
562 clipper_va_arg (valist, type)
563      tree valist, type;
564 {
565   tree ap_field, reg_field, num_field;
566   tree addr, t;
567   HOST_WIDE_INT align;
568   rtx addr_rtx, over_label = NULL_RTX, tr;
569
570   /*
571     Integers:
572
573     if (VA.__va_num < 2)
574       addr = VA.__va_reg[2 * VA.__va_num];
575     else
576       addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
577     VA.__va_num++;
578
579     Floats:
580
581     if (VA.__va_num < 2)
582       addr = VA.__va_reg[2 * VA.__va_num + 1];
583     else
584       addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
585     VA.__va_num++;
586
587     Aggregates:
588
589     addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
590     VA.__va_num++;
591   */
592
593   ap_field = TYPE_FIELDS (TREE_TYPE (valist));
594   reg_field = TREE_CHAIN (ap_field);
595   num_field = TREE_CHAIN (reg_field);
596
597   ap_field = build (COMPONENT_REF, TREE_TYPE (ap_field), valist, ap_field);
598   reg_field = build (COMPONENT_REF, TREE_TYPE (reg_field), valist, reg_field);
599   num_field = build (COMPONENT_REF, TREE_TYPE (num_field), valist, num_field);
600
601   addr_rtx = gen_reg_rtx (Pmode);
602
603   if (! AGGREGATE_TYPE_P (type))
604     {
605       tree inreg;
606       rtx false_label;
607
608       over_label = gen_label_rtx ();
609       false_label = gen_label_rtx ();
610
611       emit_cmp_and_jump_insns (expand_expr (num_field, NULL_RTX, 0,
612                                             OPTAB_LIB_WIDEN),
613                                GEN_INT (2), GE, const0_rtx,
614                                TYPE_MODE (TREE_TYPE (num_field)),
615                                TREE_UNSIGNED (num_field), 0, false_label);
616
617       inreg = fold (build (MULT_EXPR, integer_type_node, num_field,
618                            build_int_2 (2, 0)));
619       if (FLOAT_TYPE_P (type))
620         inreg = fold (build (PLUS_EXPR, integer_type_node, inreg,
621                              build_int_2 (1, 0)));
622       inreg = fold (build (ARRAY_REF, ptr_type_node, reg_field, inreg));
623
624       tr = expand_expr (inreg, addr_rtx, VOIDmode, EXPAND_NORMAL);
625       if (tr != addr_rtx)
626         emit_move_insn (addr_rtx, tr);
627
628       emit_jump_insn (gen_jump (over_label));
629       emit_barrier ();
630       emit_label (false_label);
631     }
632
633   /* Round to alignment of `type', or at least integer alignment.  */
634
635   align = TYPE_ALIGN (type);
636   if (align < TYPE_ALIGN (integer_type_node))
637     align = TYPE_ALIGN (integer_type_node);
638   align /= BITS_PER_UNIT;
639
640   addr = fold (build (PLUS_EXPR, ptr_type_node, ap_field,
641                       build_int_2 (align-1, 0)));
642   addr = fold (build (BIT_AND_EXPR, ptr_type_node, addr,
643                       build_int_2 (-align, -1)));
644   addr = save_expr (addr);
645
646   tr = expand_expr (addr, addr_rtx, Pmode, EXPAND_NORMAL);
647   if (tr != addr_rtx)
648     emit_move_insn (addr_rtx, tr);
649   
650   t = build (MODIFY_EXPR, TREE_TYPE (ap_field), ap_field,
651              build (PLUS_EXPR, TREE_TYPE (ap_field), 
652                     addr, build_int_2 (int_size_in_bytes (type), 0)));
653   TREE_SIDE_EFFECTS (t) = 1;
654   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
655
656   if (over_label)
657     emit_label (over_label);
658
659   t = build (MODIFY_EXPR, TREE_TYPE (num_field), num_field,
660              build (PLUS_EXPR, TREE_TYPE (num_field), 
661                     num_field, build_int_2 (1, 0)));
662   TREE_SIDE_EFFECTS (t) = 1;
663   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
664
665   return addr_rtx;
666 }
667
668 /* Return truth value of whether OP can be used as an word register
669    operand. Reject (SUBREG:SI (REG:SF )) */
670
671 int
672 int_reg_operand (op, mode)
673      rtx op;
674      enum machine_mode mode;
675 {
676   return (register_operand (op, mode) &&
677           (GET_CODE (op) != SUBREG ||
678            GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT));
679 }
680
681 /* Return truth value of whether OP can be used as a float register
682    operand. Reject (SUBREG:SF (REG:SI )) )) */
683
684 int
685 fp_reg_operand (op, mode)
686      rtx op;
687      enum machine_mode mode;
688 {
689   return (register_operand (op, mode) &&
690           (GET_CODE (op) != SUBREG ||
691            GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_FLOAT));
692 }
693