OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [m68hc11/] [m68hc11.c] - Blame information for rev 816

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 julius
/* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2
   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
3
   Free Software Foundation, Inc.
4
   Contributed by Stephane Carrez (stcarrez@nerim.fr)
5
 
6
This file is part of GCC.
7
 
8
GCC 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 3, or (at your option)
11
any later version.
12
 
13
GCC 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 GCC; see the file COPYING3.  If not see
20
<http://www.gnu.org/licenses/>.
21
 
22
Note:
23
   A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24
   on gcc 2.6.3.  I have used it as a starting point for this port.
25
   However, this new port is a complete re-write.  Its internal
26
   design is completely different.  The generated code is not
27
   compatible with the gcc 2.6.3 port.
28
 
29
   The gcc 2.6.3 port is available at:
30
 
31
   ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
32
 
33
*/
34
 
35
#include <stdio.h>
36
#include "config.h"
37
#include "system.h"
38
#include "coretypes.h"
39
#include "tm.h"
40
#include "rtl.h"
41
#include "tree.h"
42
#include "tm_p.h"
43
#include "regs.h"
44
#include "hard-reg-set.h"
45
#include "real.h"
46
#include "insn-config.h"
47
#include "conditions.h"
48
#include "output.h"
49
#include "insn-attr.h"
50
#include "flags.h"
51
#include "recog.h"
52
#include "expr.h"
53
#include "libfuncs.h"
54
#include "toplev.h"
55
#include "basic-block.h"
56
#include "function.h"
57
#include "ggc.h"
58
#include "reload.h"
59
#include "target.h"
60
#include "target-def.h"
61
 
62
static void emit_move_after_reload (rtx, rtx, rtx);
63
static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
64
static void m68hc11_emit_logical (enum machine_mode, int, rtx *);
65
static void m68hc11_reorg (void);
66
static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);
67
static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
68
static int must_parenthesize (rtx);
69
static int m68hc11_address_cost (rtx);
70
static int m68hc11_shift_cost (enum machine_mode, rtx, int);
71
static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
72
static bool m68hc11_rtx_costs (rtx, int, int, int *);
73
static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
74
const struct attribute_spec m68hc11_attribute_table[];
75
 
76
void create_regs_rtx (void);
77
 
78
static void asm_print_register (FILE *, int);
79
static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
80
static void m68hc11_asm_out_constructor (rtx, int);
81
static void m68hc11_asm_out_destructor (rtx, int);
82
static void m68hc11_file_start (void);
83
static void m68hc11_encode_section_info (tree, rtx, int);
84
static const char *m68hc11_strip_name_encoding (const char* str);
85
static unsigned int m68hc11_section_type_flags (tree, const char*, int);
86
static int autoinc_mode (rtx);
87
static int m68hc11_make_autoinc_notes (rtx *, void *);
88
static void m68hc11_init_libfuncs (void);
89
static rtx m68hc11_struct_value_rtx (tree, int);
90
static bool m68hc11_return_in_memory (tree, tree);
91
 
92
/* Must be set to 1 to produce debug messages.  */
93
int debug_m6811 = 0;
94
 
95
extern FILE *asm_out_file;
96
 
97
rtx ix_reg;
98
rtx iy_reg;
99
rtx d_reg;
100
rtx m68hc11_soft_tmp_reg;
101
static GTY(()) rtx stack_push_word;
102
static GTY(()) rtx stack_pop_word;
103
static GTY(()) rtx z_reg;
104
static GTY(()) rtx z_reg_qi;
105
static int regs_inited = 0;
106
 
107
/* Set to 1 by expand_prologue() when the function is an interrupt handler.  */
108
int current_function_interrupt;
109
 
110
/* Set to 1 by expand_prologue() when the function is a trap handler.  */
111
int current_function_trap;
112
 
113
/* Set to 1 when the current function is placed in 68HC12 banked
114
   memory and must return with rtc.  */
115
int current_function_far;
116
 
117
/* Min offset that is valid for the indirect addressing mode.  */
118
HOST_WIDE_INT m68hc11_min_offset = 0;
119
 
120
/* Max offset that is valid for the indirect addressing mode.  */
121
HOST_WIDE_INT m68hc11_max_offset = 256;
122
 
123
/* The class value for base registers.  */
124
enum reg_class m68hc11_base_reg_class = A_REGS;
125
 
126
/* The class value for index registers.  This is NO_REGS for 68HC11.  */
127
enum reg_class m68hc11_index_reg_class = NO_REGS;
128
 
129
enum reg_class m68hc11_tmp_regs_class = NO_REGS;
130
 
131
/* Tables that tell whether a given hard register is valid for
132
   a base or an index register.  It is filled at init time depending
133
   on the target processor.  */
134
unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
135
unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
136
 
137
/* A correction offset which is applied to the stack pointer.
138
   This is 1 for 68HC11 and 0 for 68HC12.  */
139
int m68hc11_sp_correction;
140
 
141
int m68hc11_addr_mode;
142
int m68hc11_mov_addr_mode;
143
 
144
/* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns.  */
145
rtx m68hc11_compare_op0;
146
rtx m68hc11_compare_op1;
147
 
148
 
149
const struct processor_costs *m68hc11_cost;
150
 
151
/* Costs for a 68HC11.  */
152
static const struct processor_costs m6811_cost = {
153
  /* add */
154
  COSTS_N_INSNS (2),
155
  /* logical */
156
  COSTS_N_INSNS (2),
157
  /* non-constant shift */
158
  COSTS_N_INSNS (20),
159
  /* shiftQI const */
160
  { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
161
    COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
162
    COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
163
 
164
  /* shiftHI const */
165
  { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
166
    COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
167
    COSTS_N_INSNS (4), COSTS_N_INSNS (2),
168
    COSTS_N_INSNS (2), COSTS_N_INSNS (4),
169
    COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
170
    COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
171
  },
172
  /* mulQI */
173
  COSTS_N_INSNS (20),
174
  /* mulHI */
175
  COSTS_N_INSNS (20 * 4),
176
  /* mulSI */
177
  COSTS_N_INSNS (20 * 16),
178
  /* divQI */
179
  COSTS_N_INSNS (20),
180
  /* divHI */
181
  COSTS_N_INSNS (80),
182
  /* divSI */
183
  COSTS_N_INSNS (100)
184
};
185
 
186
/* Costs for a 68HC12.  */
187
static const struct processor_costs m6812_cost = {
188
  /* add */
189
  COSTS_N_INSNS (2),
190
  /* logical */
191
  COSTS_N_INSNS (2),
192
  /* non-constant shift */
193
  COSTS_N_INSNS (20),
194
  /* shiftQI const */
195
  { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
196
    COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
197
    COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
198
 
199
  /* shiftHI const */
200
  { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
201
    COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
202
    COSTS_N_INSNS (4), COSTS_N_INSNS (2),
203
    COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
204
    COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
205
    COSTS_N_INSNS (6), COSTS_N_INSNS (4)
206
  },
207
  /* mulQI */
208
  COSTS_N_INSNS (3),
209
  /* mulHI */
210
  COSTS_N_INSNS (3),
211
  /* mulSI */
212
  COSTS_N_INSNS (3 * 4),
213
  /* divQI */
214
  COSTS_N_INSNS (12),
215
  /* divHI */
216
  COSTS_N_INSNS (12),
217
  /* divSI */
218
  COSTS_N_INSNS (100)
219
};
220
 
221
/* Initialize the GCC target structure.  */
222
#undef TARGET_ATTRIBUTE_TABLE
223
#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
224
 
225
#undef TARGET_ASM_ALIGNED_HI_OP
226
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
227
 
228
#undef TARGET_ASM_FUNCTION_EPILOGUE
229
#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
230
 
231
#undef TARGET_ASM_FILE_START
232
#define TARGET_ASM_FILE_START m68hc11_file_start
233
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
234
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
235
 
236
#undef TARGET_DEFAULT_TARGET_FLAGS
237
#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
238
 
239
#undef TARGET_ENCODE_SECTION_INFO
240
#define TARGET_ENCODE_SECTION_INFO  m68hc11_encode_section_info
241
 
242
#undef TARGET_SECTION_TYPE_FLAGS
243
#define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
244
 
245
#undef TARGET_RTX_COSTS
246
#define TARGET_RTX_COSTS m68hc11_rtx_costs
247
#undef TARGET_ADDRESS_COST
248
#define TARGET_ADDRESS_COST m68hc11_address_cost
249
 
250
#undef TARGET_MACHINE_DEPENDENT_REORG
251
#define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
252
 
253
#undef TARGET_INIT_LIBFUNCS
254
#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
255
 
256
#undef TARGET_STRUCT_VALUE_RTX
257
#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
258
#undef TARGET_RETURN_IN_MEMORY
259
#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
260
#undef TARGET_CALLEE_COPIES
261
#define TARGET_CALLEE_COPIES hook_callee_copies_named
262
 
263
#undef TARGET_STRIP_NAME_ENCODING
264
#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
265
 
266
struct gcc_target targetm = TARGET_INITIALIZER;
267
 
268
int
269
m68hc11_override_options (void)
270
{
271
  memset (m68hc11_reg_valid_for_index, 0,
272
          sizeof (m68hc11_reg_valid_for_index));
273
  memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
274
 
275
  /* Compilation with -fpic generates a wrong code.  */
276
  if (flag_pic)
277
    {
278
      warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
279
               (flag_pic > 1) ? "PIC" : "pic");
280
      flag_pic = 0;
281
    }
282
 
283
  /* Do not enable -fweb because it breaks the 32-bit shift patterns
284
     by breaking the match_dup of those patterns.  The shift patterns
285
     will no longer be recognized after that.  */
286
  flag_web = 0;
287
 
288
  /* Configure for a 68hc11 processor.  */
289
  if (TARGET_M6811)
290
    {
291
      target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
292
      m68hc11_cost = &m6811_cost;
293
      m68hc11_min_offset = 0;
294
      m68hc11_max_offset = 256;
295
      m68hc11_index_reg_class = NO_REGS;
296
      m68hc11_base_reg_class = A_REGS;
297
      m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
298
      m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
299
      m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
300
      m68hc11_sp_correction = 1;
301
      m68hc11_tmp_regs_class = D_REGS;
302
      m68hc11_addr_mode = ADDR_OFFSET;
303
      m68hc11_mov_addr_mode = 0;
304
      if (m68hc11_soft_reg_count < 0)
305
        m68hc11_soft_reg_count = 4;
306
    }
307
 
308
  /* Configure for a 68hc12 processor.  */
309
  if (TARGET_M6812)
310
    {
311
      m68hc11_cost = &m6812_cost;
312
      m68hc11_min_offset = -65536;
313
      m68hc11_max_offset = 65536;
314
      m68hc11_index_reg_class = D_REGS;
315
      m68hc11_base_reg_class = A_OR_SP_REGS;
316
      m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
317
      m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
318
      m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
319
      m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
320
      m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
321
      m68hc11_sp_correction = 0;
322
      m68hc11_tmp_regs_class = TMP_REGS;
323
      m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
324
        | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
325
      m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
326
        | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
327
      target_flags |= MASK_NO_DIRECT_MODE;
328
      if (m68hc11_soft_reg_count < 0)
329
        m68hc11_soft_reg_count = 0;
330
 
331
      if (TARGET_LONG_CALLS)
332
        current_function_far = 1;
333
    }
334
  return 0;
335
}
336
 
337
 
338
void
339
m68hc11_conditional_register_usage (void)
340
{
341
  int i;
342
 
343
  if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
344
    m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
345
 
346
  for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
347
    {
348
      fixed_regs[i] = 1;
349
      call_used_regs[i] = 1;
350
    }
351
 
352
  /* For 68HC12, the Z register emulation is not necessary when the
353
     frame pointer is not used.  The frame pointer is eliminated and
354
     replaced by the stack register (which is a BASE_REG_CLASS).  */
355
  if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
356
    {
357
      fixed_regs[HARD_Z_REGNUM] = 1;
358
    }
359
}
360
 
361
 
362
/* Reload and register operations.  */
363
 
364
 
365
void
366
create_regs_rtx (void)
367
{
368
  /*  regs_inited = 1; */
369
  ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
370
  iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
371
  d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
372
  m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
373
 
374
  stack_push_word = gen_rtx_MEM (HImode,
375
                             gen_rtx_PRE_DEC (HImode,
376
                                      gen_rtx_REG (HImode, HARD_SP_REGNUM)));
377
  stack_pop_word = gen_rtx_MEM (HImode,
378
                            gen_rtx_POST_INC (HImode,
379
                                     gen_rtx_REG (HImode, HARD_SP_REGNUM)));
380
 
381
}
382
 
383
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
384
    - 8 bit values are stored anywhere (except the SP register).
385
    - 16 bit values can be stored in any register whose mode is 16
386
    - 32 bit values can be stored in D, X registers or in a soft register
387
      (except the last one because we need 2 soft registers)
388
    - Values whose size is > 32 bit are not stored in real hard
389
      registers.  They may be stored in soft registers if there are
390
      enough of them.  */
391
int
392
hard_regno_mode_ok (int regno, enum machine_mode mode)
393
{
394
  switch (GET_MODE_SIZE (mode))
395
    {
396
    case 8:
397
      return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
398
 
399
    case 4:
400
      return (X_REGNO_P (regno)
401
              || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
402
 
403
    case 2:
404
      return G_REGNO_P (regno);
405
 
406
    case 1:
407
      /* We have to accept a QImode in X or Y registers.  Otherwise, the
408
         reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
409
         in the insns.  Reload fails if the insn rejects the register class 'a'
410
         as well as if it accepts it.  Patterns that failed were
411
         zero_extend_qihi2 and iorqi3.  */
412
 
413
      return G_REGNO_P (regno) && !SP_REGNO_P (regno);
414
 
415
    default:
416
      return 0;
417
    }
418
}
419
 
420
int
421
m68hc11_hard_regno_rename_ok (int reg1, int reg2)
422
{
423
  /* Don't accept renaming to Z register.  We will replace it to
424
     X,Y or D during machine reorg pass.  */
425
  if (reg2 == HARD_Z_REGNUM)
426
    return 0;
427
 
428
  /* Don't accept renaming D,X to Y register as the code will be bigger.  */
429
  if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
430
      && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
431
    return 0;
432
 
433
  return 1;
434
}
435
 
436
enum reg_class
437
preferred_reload_class (rtx operand, enum reg_class class)
438
{
439
  enum machine_mode mode;
440
 
441
  mode = GET_MODE (operand);
442
 
443
  if (debug_m6811)
444
    {
445
      printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
446
    }
447
 
448
  if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
449
    return m68hc11_base_reg_class;
450
 
451
  if (class >= S_REGS && (GET_CODE (operand) == MEM
452
                          || GET_CODE (operand) == CONST_INT))
453
    {
454
      /* S_REGS class must not be used.  The movhi template does not
455
         work to move a memory to a soft register.
456
         Restrict to a hard reg.  */
457
      switch (class)
458
        {
459
        default:
460
        case G_REGS:
461
        case D_OR_A_OR_S_REGS:
462
          class = A_OR_D_REGS;
463
          break;
464
        case A_OR_S_REGS:
465
          class = A_REGS;
466
          break;
467
        case D_OR_SP_OR_S_REGS:
468
          class = D_OR_SP_REGS;
469
          break;
470
        case D_OR_Y_OR_S_REGS:
471
          class = D_OR_Y_REGS;
472
          break;
473
        case D_OR_X_OR_S_REGS:
474
          class = D_OR_X_REGS;
475
          break;
476
        case SP_OR_S_REGS:
477
          class = SP_REGS;
478
          break;
479
        case Y_OR_S_REGS:
480
          class = Y_REGS;
481
          break;
482
        case X_OR_S_REGS:
483
          class = X_REGS;
484
          break;
485
        case D_OR_S_REGS:
486
          class = D_REGS;
487
        }
488
    }
489
  else if (class == Y_REGS && GET_CODE (operand) == MEM)
490
    {
491
      class = Y_REGS;
492
    }
493
  else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
494
    {
495
      class = D_OR_X_REGS;
496
    }
497
  else if (class >= S_REGS && S_REG_P (operand))
498
    {
499
      switch (class)
500
        {
501
        default:
502
        case G_REGS:
503
        case D_OR_A_OR_S_REGS:
504
          class = A_OR_D_REGS;
505
          break;
506
        case A_OR_S_REGS:
507
          class = A_REGS;
508
          break;
509
        case D_OR_SP_OR_S_REGS:
510
          class = D_OR_SP_REGS;
511
          break;
512
        case D_OR_Y_OR_S_REGS:
513
          class = D_OR_Y_REGS;
514
          break;
515
        case D_OR_X_OR_S_REGS:
516
          class = D_OR_X_REGS;
517
          break;
518
        case SP_OR_S_REGS:
519
          class = SP_REGS;
520
          break;
521
        case Y_OR_S_REGS:
522
          class = Y_REGS;
523
          break;
524
        case X_OR_S_REGS:
525
          class = X_REGS;
526
          break;
527
        case D_OR_S_REGS:
528
          class = D_REGS;
529
        }
530
    }
531
  else if (class >= S_REGS)
532
    {
533
      if (debug_m6811)
534
        {
535
          printf ("Class = %s for: ", reg_class_names[class]);
536
          fflush (stdout);
537
          debug_rtx (operand);
538
        }
539
    }
540
 
541
  if (debug_m6811)
542
    {
543
      printf (" => class=%s\n", reg_class_names[class]);
544
      fflush (stdout);
545
      debug_rtx (operand);
546
    }
547
 
548
  return class;
549
}
550
 
551
/* Return 1 if the operand is a valid indexed addressing mode.
552
   For 68hc11:  n,r    with n in [0..255] and r in A_REGS class
553
   For 68hc12:  n,r    no constraint on the constant, r in A_REGS class.  */
554
int
555
m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
556
{
557
  rtx base, offset;
558
 
559
  switch (GET_CODE (operand))
560
    {
561
    case MEM:
562
      if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
563
        return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
564
                                   addr_mode & (ADDR_STRICT | ADDR_OFFSET));
565
      return 0;
566
 
567
    case POST_INC:
568
    case PRE_INC:
569
    case POST_DEC:
570
    case PRE_DEC:
571
      if (addr_mode & ADDR_INCDEC)
572
        return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
573
                                   addr_mode & ADDR_STRICT);
574
      return 0;
575
 
576
    case PLUS:
577
      base = XEXP (operand, 0);
578
      if (GET_CODE (base) == MEM)
579
        return 0;
580
 
581
      offset = XEXP (operand, 1);
582
      if (GET_CODE (offset) == MEM)
583
        return 0;
584
 
585
      /* Indexed addressing mode with 2 registers.  */
586
      if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
587
        {
588
          if (!(addr_mode & ADDR_INDEXED))
589
            return 0;
590
 
591
          addr_mode &= ADDR_STRICT;
592
          if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
593
              && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
594
            return 1;
595
 
596
          if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
597
              && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
598
            return 1;
599
 
600
          return 0;
601
        }
602
 
603
      if (!(addr_mode & ADDR_OFFSET))
604
        return 0;
605
 
606
      if (GET_CODE (base) == REG)
607
        {
608
          if (!VALID_CONSTANT_OFFSET_P (offset, mode))
609
            return 0;
610
 
611
          if (!(addr_mode & ADDR_STRICT))
612
            return 1;
613
 
614
          return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
615
        }
616
 
617
      if (GET_CODE (offset) == REG)
618
        {
619
          if (!VALID_CONSTANT_OFFSET_P (base, mode))
620
            return 0;
621
 
622
          if (!(addr_mode & ADDR_STRICT))
623
            return 1;
624
 
625
          return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
626
        }
627
      return 0;
628
 
629
    case REG:
630
      return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
631
 
632
    case CONST_INT:
633
      if (addr_mode & ADDR_CONST)
634
        return VALID_CONSTANT_OFFSET_P (operand, mode);
635
      return 0;
636
 
637
    default:
638
      return 0;
639
    }
640
}
641
 
642
/* Returns 1 if the operand fits in a 68HC11 indirect mode or in
643
   a 68HC12 1-byte index addressing mode.  */
644
int
645
m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
646
{
647
  rtx base, offset;
648
  int addr_mode;
649
 
650
  if (GET_CODE (operand) == REG && reload_in_progress
651
      && REGNO (operand) >= FIRST_PSEUDO_REGISTER
652
      && reg_equiv_memory_loc[REGNO (operand)])
653
    {
654
      operand = reg_equiv_memory_loc[REGNO (operand)];
655
      operand = eliminate_regs (operand, 0, NULL_RTX);
656
    }
657
 
658
  if (GET_CODE (operand) != MEM)
659
    return 0;
660
 
661
  operand = XEXP (operand, 0);
662
  if (CONSTANT_ADDRESS_P (operand))
663
    return 1;
664
 
665
  if (PUSH_POP_ADDRESS_P (operand))
666
    return 1;
667
 
668
  addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
669
  if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
670
    return 0;
671
 
672
  if (TARGET_M6812 && GET_CODE (operand) == PLUS
673
      && (reload_completed | reload_in_progress))
674
    {
675
      base = XEXP (operand, 0);
676
      offset = XEXP (operand, 1);
677
 
678
      /* The offset can be a symbol address and this is too big
679
         for the operand constraint.  */
680
      if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
681
        return 0;
682
 
683
      if (GET_CODE (base) == CONST_INT)
684
        offset = base;
685
 
686
      switch (GET_MODE_SIZE (mode))
687
        {
688
        case 8:
689
          if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
690
            return 0;
691
          break;
692
 
693
        case 4:
694
          if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
695
            return 0;
696
          break;
697
 
698
        default:
699
          if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
700
            return 0;
701
          break;
702
        }
703
    }
704
  return 1;
705
}
706
 
707
int
708
m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
709
{
710
  int addr_mode;
711
 
712
  if (GET_CODE (operand) == REG && reload_in_progress
713
      && REGNO (operand) >= FIRST_PSEUDO_REGISTER
714
      && reg_equiv_memory_loc[REGNO (operand)])
715
    {
716
      operand = reg_equiv_memory_loc[REGNO (operand)];
717
      operand = eliminate_regs (operand, 0, NULL_RTX);
718
    }
719
  if (GET_CODE (operand) != MEM)
720
    return 0;
721
 
722
  operand = XEXP (operand, 0);
723
  addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
724
  return m68hc11_valid_addressing_p (operand, mode, addr_mode);
725
}
726
 
727
static int
728
go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
729
                                   int strict)
730
{
731
  int addr_mode;
732
 
733
  if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
734
    {
735
      /* Reject the global variables if they are too wide.  This forces
736
         a load of their address in a register and generates smaller code.  */
737
      if (GET_MODE_SIZE (mode) == 8)
738
        return 0;
739
 
740
      return 1;
741
    }
742
  addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
743
  if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
744
    {
745
      return 1;
746
    }
747
  if (PUSH_POP_ADDRESS_P (operand))
748
    {
749
      return 1;
750
    }
751
  if (symbolic_memory_operand (operand, mode))
752
    {
753
      return 1;
754
    }
755
  return 0;
756
}
757
 
758
int
759
m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
760
                                  int strict)
761
{
762
  int result;
763
 
764
  if (debug_m6811)
765
    {
766
      printf ("Checking: ");
767
      fflush (stdout);
768
      debug_rtx (operand);
769
    }
770
 
771
  result = go_if_legitimate_address_internal (operand, mode, strict);
772
 
773
  if (debug_m6811)
774
    {
775
      printf (" -> %s\n", result == 0 ? "NO" : "YES");
776
    }
777
 
778
  if (result == 0)
779
    {
780
      if (debug_m6811)
781
        {
782
          printf ("go_if_legitimate%s, ret 0: %d:",
783
                  (strict ? "_strict" : ""), mode);
784
          fflush (stdout);
785
          debug_rtx (operand);
786
        }
787
    }
788
  return result;
789
}
790
 
791
int
792
m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
793
                            rtx old_operand ATTRIBUTE_UNUSED,
794
                            enum machine_mode mode ATTRIBUTE_UNUSED)
795
{
796
  return 0;
797
}
798
 
799
 
800
int
801
m68hc11_reload_operands (rtx operands[])
802
{
803
  enum machine_mode mode;
804
 
805
  if (regs_inited == 0)
806
    create_regs_rtx ();
807
 
808
  mode = GET_MODE (operands[1]);
809
 
810
  /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))).  */
811
  if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
812
    {
813
      rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
814
      rtx base = XEXP (XEXP (operands[1], 0), 0);
815
 
816
      if (GET_CODE (base) != REG)
817
        {
818
          rtx tmp = base;
819
          base = big_offset;
820
          big_offset = tmp;
821
        }
822
 
823
      /* If the offset is out of range, we have to compute the address
824
         with a separate add instruction.  We try to do this with an 8-bit
825
         add on the A register.  This is possible only if the lowest part
826
         of the offset (i.e., big_offset % 256) is a valid constant offset
827
         with respect to the mode.  If it's not, we have to generate a
828
         16-bit add on the D register.  From:
829
 
830
         (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
831
 
832
         we generate:
833
 
834
         [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
835
         (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
836
         [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
837
         (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
838
 
839
         (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
840
         (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
841
 
842
      */
843
      if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
844
        {
845
          int vh, vl;
846
          rtx reg = operands[0];
847
          rtx offset;
848
          int val = INTVAL (big_offset);
849
 
850
 
851
          /* We use the 'operands[0]' as a scratch register to compute the
852
             address. Make sure 'base' is in that register.  */
853
          if (!rtx_equal_p (base, operands[0]))
854
            {
855
              emit_move_insn (reg, base);
856
            }
857
 
858
          if (val > 0)
859
            {
860
              vh = val >> 8;
861
              vl = val & 0x0FF;
862
            }
863
          else
864
            {
865
              vh = (val >> 8) & 0x0FF;
866
              vl = val & 0x0FF;
867
            }
868
 
869
          /* Create the lowest part offset that still remains to be added.
870
             If it's not a valid offset, do a 16-bit add.  */
871
          offset = GEN_INT (vl);
872
          if (!VALID_CONSTANT_OFFSET_P (offset, mode))
873
            {
874
              emit_insn (gen_rtx_SET (VOIDmode, reg,
875
                                  gen_rtx_PLUS (HImode, reg, big_offset)));
876
              offset = const0_rtx;
877
            }
878
          else
879
            {
880
              emit_insn (gen_rtx_SET (VOIDmode, reg,
881
                                  gen_rtx_PLUS (HImode, reg,
882
                                           GEN_INT (vh << 8))));
883
            }
884
          emit_move_insn (operands[0],
885
                          gen_rtx_MEM (GET_MODE (operands[1]),
886
                                   gen_rtx_PLUS (Pmode, reg, offset)));
887
          return 1;
888
        }
889
    }
890
 
891
  /* Use the normal gen_movhi pattern.  */
892
  return 0;
893
}
894
 
895
void
896
m68hc11_emit_libcall (const char *name, enum rtx_code code,
897
                      enum machine_mode dmode, enum machine_mode smode,
898
                      int noperands, rtx *operands)
899
{
900
  rtx ret;
901
  rtx insns;
902
  rtx libcall;
903
  rtx equiv;
904
 
905
  start_sequence ();
906
  libcall = gen_rtx_SYMBOL_REF (Pmode, name);
907
  switch (noperands)
908
    {
909
    case 2:
910
      ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
911
                                     dmode, 1, operands[1], smode);
912
      equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
913
      break;
914
 
915
    case 3:
916
      ret = emit_library_call_value (libcall, NULL_RTX,
917
                                     LCT_CONST, dmode, 2,
918
                                     operands[1], smode, operands[2],
919
                                     smode);
920
      equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
921
      break;
922
 
923
    default:
924
      gcc_unreachable ();
925
    }
926
 
927
  insns = get_insns ();
928
  end_sequence ();
929
  emit_libcall_block (insns, operands[0], ret, equiv);
930
}
931
 
932
/* Returns true if X is a PRE/POST increment decrement
933
   (same as auto_inc_p() in rtlanal.c but do not take into
934
   account the stack).  */
935
int
936
m68hc11_auto_inc_p (rtx x)
937
{
938
  return GET_CODE (x) == PRE_DEC
939
    || GET_CODE (x) == POST_INC
940
    || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
941
}
942
 
943
 
944
/* Predicates for machine description.  */
945
 
946
int
947
memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
948
{
949
  return GET_CODE (operand) == MEM
950
    && GET_CODE (XEXP (operand, 0)) == PLUS
951
    && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
952
         && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
953
        || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
954
            && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
955
}
956
 
957
int
958
m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
959
{
960
  if (GET_CODE (operand) == MEM)
961
    {
962
      rtx op = XEXP (operand, 0);
963
 
964
      if (symbolic_memory_operand (op, mode))
965
        return 1;
966
    }
967
  return 0;
968
}
969
 
970
int
971
m68hc11_indirect_p (rtx operand, enum machine_mode mode)
972
{
973
  if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
974
    {
975
      rtx op = XEXP (operand, 0);
976
      int addr_mode;
977
 
978
      if (m68hc11_page0_symbol_p (op))
979
        return 1;
980
 
981
      if (symbolic_memory_operand (op, mode))
982
        return TARGET_M6812;
983
 
984
      if (reload_in_progress)
985
        return 1;
986
 
987
      operand = XEXP (operand, 0);
988
      addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
989
      return m68hc11_valid_addressing_p (operand, mode, addr_mode);
990
    }
991
  return 0;
992
}
993
 
994
int
995
memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
996
{
997
  if (GET_CODE (operand) != MEM)
998
    return 0;
999
 
1000
  operand = XEXP (operand, 0);
1001
  if (GET_CODE (operand) == PLUS)
1002
    {
1003
      if (GET_CODE (XEXP (operand, 0)) == REG)
1004
        operand = XEXP (operand, 0);
1005
      else if (GET_CODE (XEXP (operand, 1)) == REG)
1006
        operand = XEXP (operand, 1);
1007
    }
1008
  return GET_CODE (operand) == REG
1009
    && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1010
        || A_REGNO_P (REGNO (operand)));
1011
}
1012
 
1013
int
1014
push_pop_operand_p (rtx operand)
1015
{
1016
  if (GET_CODE (operand) != MEM)
1017
    {
1018
      return 0;
1019
    }
1020
  operand = XEXP (operand, 0);
1021
  return PUSH_POP_ADDRESS_P (operand);
1022
}
1023
 
1024
/* Returns 1 if OP is either a symbol reference or a sum of a symbol
1025
   reference and a constant.  */
1026
 
1027
int
1028
symbolic_memory_operand (rtx op, enum machine_mode mode)
1029
{
1030
  switch (GET_CODE (op))
1031
    {
1032
    case SYMBOL_REF:
1033
    case LABEL_REF:
1034
      return 1;
1035
 
1036
    case CONST:
1037
      op = XEXP (op, 0);
1038
      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1039
               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1040
              && GET_CODE (XEXP (op, 1)) == CONST_INT);
1041
 
1042
      /* ??? This clause seems to be irrelevant.  */
1043
    case CONST_DOUBLE:
1044
      return GET_MODE (op) == mode;
1045
 
1046
    case PLUS:
1047
      return symbolic_memory_operand (XEXP (op, 0), mode)
1048
        && symbolic_memory_operand (XEXP (op, 1), mode);
1049
 
1050
    default:
1051
      return 0;
1052
    }
1053
}
1054
 
1055
/* Emit the code to build the trampoline used to call a nested function.
1056
 
1057
   68HC11               68HC12
1058
 
1059
   ldy #&CXT            movw #&CXT,*_.d1
1060
   sty *_.d1            jmp FNADDR
1061
   jmp FNADDR
1062
 
1063
*/
1064
void
1065
m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1066
{
1067
  const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1068
 
1069
  /* Skip the '*'.  */
1070
  if (*static_chain_reg == '*')
1071
    static_chain_reg++;
1072
  if (TARGET_M6811)
1073
    {
1074
      emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1075
      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1076
      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1077
                      GEN_INT (0x18df));
1078
      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1079
                      gen_rtx_CONST (QImode,
1080
                                     gen_rtx_SYMBOL_REF (Pmode,
1081
                                                         static_chain_reg)));
1082
      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1083
                      GEN_INT (0x7e));
1084
      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1085
    }
1086
  else
1087
    {
1088
      emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1089
      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1090
      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1091
                      gen_rtx_CONST (HImode,
1092
                                     gen_rtx_SYMBOL_REF (Pmode,
1093
                                                         static_chain_reg)));
1094
      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1095
                      GEN_INT (0x06));
1096
      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1097
    }
1098
}
1099
 
1100
/* Declaration of types.  */
1101
 
1102
/* Handle an "tiny_data" attribute; arguments as in
1103
   struct attribute_spec.handler.  */
1104
static tree
1105
m68hc11_handle_page0_attribute (tree *node, tree name,
1106
                                tree args ATTRIBUTE_UNUSED,
1107
                                int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1108
{
1109
  tree decl = *node;
1110
 
1111
  if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1112
    {
1113
      DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1114
    }
1115
  else
1116
    {
1117
      warning (OPT_Wattributes, "%qs attribute ignored",
1118
               IDENTIFIER_POINTER (name));
1119
      *no_add_attrs = true;
1120
    }
1121
 
1122
  return NULL_TREE;
1123
}
1124
 
1125
const struct attribute_spec m68hc11_attribute_table[] =
1126
{
1127
  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1128
  { "interrupt", 0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
1129
  { "trap",      0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
1130
  { "far",       0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
1131
  { "near",      0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
1132
  { "page0",     0, 0, false, false, false, m68hc11_handle_page0_attribute },
1133
  { NULL,        0, 0, false, false, false, NULL }
1134
};
1135
 
1136
/* Keep track of the symbol which has a `trap' attribute and which uses
1137
   the `swi' calling convention.  Since there is only one trap, we only
1138
   record one such symbol.  If there are several, a warning is reported.  */
1139
static rtx trap_handler_symbol = 0;
1140
 
1141
/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1142
   arguments as in struct attribute_spec.handler.  */
1143
static tree
1144
m68hc11_handle_fntype_attribute (tree *node, tree name,
1145
                                 tree args ATTRIBUTE_UNUSED,
1146
                                 int flags ATTRIBUTE_UNUSED,
1147
                                 bool *no_add_attrs)
1148
{
1149
  if (TREE_CODE (*node) != FUNCTION_TYPE
1150
      && TREE_CODE (*node) != METHOD_TYPE
1151
      && TREE_CODE (*node) != FIELD_DECL
1152
      && TREE_CODE (*node) != TYPE_DECL)
1153
    {
1154
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
1155
               IDENTIFIER_POINTER (name));
1156
      *no_add_attrs = true;
1157
    }
1158
 
1159
  return NULL_TREE;
1160
}
1161
/* Undo the effects of the above.  */
1162
 
1163
static const char *
1164
m68hc11_strip_name_encoding (const char *str)
1165
{
1166
  return str + (*str == '*' || *str == '@' || *str == '&');
1167
}
1168
 
1169
static void
1170
m68hc11_encode_label (tree decl)
1171
{
1172
  const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1173
  int len = strlen (str);
1174
  char *newstr = alloca (len + 2);
1175
 
1176
  newstr[0] = '@';
1177
  strcpy (&newstr[1], str);
1178
 
1179
  XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1180
}
1181
 
1182
/* Return 1 if this is a symbol in page0  */
1183
int
1184
m68hc11_page0_symbol_p (rtx x)
1185
{
1186
  switch (GET_CODE (x))
1187
    {
1188
    case SYMBOL_REF:
1189
      return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1190
 
1191
    case CONST:
1192
      return m68hc11_page0_symbol_p (XEXP (x, 0));
1193
 
1194
    case PLUS:
1195
      if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1196
        return 0;
1197
 
1198
      return GET_CODE (XEXP (x, 1)) == CONST_INT
1199
        && INTVAL (XEXP (x, 1)) < 256
1200
        && INTVAL (XEXP (x, 1)) >= 0;
1201
 
1202
    default:
1203
      return 0;
1204
    }
1205
}
1206
 
1207
/* We want to recognize trap handlers so that we handle calls to traps
1208
   in a special manner (by issuing the trap).  This information is stored
1209
   in SYMBOL_REF_FLAG.  */
1210
 
1211
static void
1212
m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1213
{
1214
  tree func_attr;
1215
  int trap_handler;
1216
  int is_far = 0;
1217
 
1218
  if (TREE_CODE (decl) == VAR_DECL)
1219
    {
1220
      if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1221
        m68hc11_encode_label (decl);
1222
      return;
1223
    }
1224
 
1225
  if (TREE_CODE (decl) != FUNCTION_DECL)
1226
    return;
1227
 
1228
  func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1229
 
1230
 
1231
  if (lookup_attribute ("far", func_attr) != NULL_TREE)
1232
    is_far = 1;
1233
  else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1234
    is_far = TARGET_LONG_CALLS != 0;
1235
 
1236
  trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1237
  if (trap_handler && is_far)
1238
    {
1239
      warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1240
               "not compatible, ignoring %<far%>");
1241
      trap_handler = 0;
1242
    }
1243
  if (trap_handler)
1244
    {
1245
      if (trap_handler_symbol != 0)
1246
        warning (OPT_Wattributes, "%<trap%> attribute is already used");
1247
      else
1248
        trap_handler_symbol = XEXP (rtl, 0);
1249
    }
1250
  SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1251
}
1252
 
1253
static unsigned int
1254
m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1255
{
1256
  unsigned int flags = default_section_type_flags (decl, name, reloc);
1257
 
1258
  if (strncmp (name, ".eeprom", 7) == 0)
1259
    {
1260
      flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1261
    }
1262
 
1263
  return flags;
1264
}
1265
 
1266
int
1267
m68hc11_is_far_symbol (rtx sym)
1268
{
1269
  if (GET_CODE (sym) == MEM)
1270
    sym = XEXP (sym, 0);
1271
 
1272
  return SYMBOL_REF_FLAG (sym);
1273
}
1274
 
1275
int
1276
m68hc11_is_trap_symbol (rtx sym)
1277
{
1278
  if (GET_CODE (sym) == MEM)
1279
    sym = XEXP (sym, 0);
1280
 
1281
  return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1282
}
1283
 
1284
 
1285
/* Argument support functions.  */
1286
 
1287
/* Define the offset between two registers, one to be eliminated, and the
1288
   other its replacement, at the start of a routine.  */
1289
int
1290
m68hc11_initial_elimination_offset (int from, int to)
1291
{
1292
  int trap_handler;
1293
  tree func_attr;
1294
  int size;
1295
  int regno;
1296
 
1297
  /* For a trap handler, we must take into account the registers which
1298
     are pushed on the stack during the trap (except the PC).  */
1299
  func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1300
  current_function_interrupt = lookup_attribute ("interrupt",
1301
                                                 func_attr) != NULL_TREE;
1302
  trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1303
 
1304
  if (lookup_attribute ("far", func_attr) != 0)
1305
    current_function_far = 1;
1306
  else if (lookup_attribute ("near", func_attr) != 0)
1307
    current_function_far = 0;
1308
  else
1309
    current_function_far = (TARGET_LONG_CALLS != 0
1310
                            && !current_function_interrupt
1311
                            && !trap_handler);
1312
 
1313
  if (trap_handler && from == ARG_POINTER_REGNUM)
1314
    size = 7;
1315
 
1316
  /* For a function using 'call/rtc' we must take into account the
1317
     page register which is pushed in the call.  */
1318
  else if (current_function_far && from == ARG_POINTER_REGNUM)
1319
    size = 1;
1320
  else
1321
    size = 0;
1322
 
1323
  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1324
    {
1325
      /* 2 is for the saved frame.
1326
         1 is for the 'sts' correction when creating the frame.  */
1327
      return get_frame_size () + 2 + m68hc11_sp_correction + size;
1328
    }
1329
 
1330
  if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1331
    {
1332
      return m68hc11_sp_correction;
1333
    }
1334
 
1335
  /* Push any 2 byte pseudo hard registers that we need to save.  */
1336
  for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1337
    {
1338
      if (regs_ever_live[regno] && !call_used_regs[regno])
1339
        {
1340
          size += 2;
1341
        }
1342
    }
1343
 
1344
  if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1345
    {
1346
      return get_frame_size () + size;
1347
    }
1348
 
1349
  if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1350
    {
1351
      return size;
1352
    }
1353
  return 0;
1354
}
1355
 
1356
/* Initialize a variable CUM of type CUMULATIVE_ARGS
1357
   for a call to a function whose data type is FNTYPE.
1358
   For a library call, FNTYPE is 0.  */
1359
 
1360
void
1361
m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1362
{
1363
  tree ret_type;
1364
 
1365
  z_replacement_completed = 0;
1366
  cum->words = 0;
1367
  cum->nregs = 0;
1368
 
1369
  /* For a library call, we must find out the type of the return value.
1370
     When the return value is bigger than 4 bytes, it is returned in
1371
     memory.  In that case, the first argument of the library call is a
1372
     pointer to the memory location.  Because the first argument is passed in
1373
     register D, we have to identify this, so that the first function
1374
     parameter is not passed in D either.  */
1375
  if (fntype == 0)
1376
    {
1377
      const char *name;
1378
      size_t len;
1379
 
1380
      if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1381
        return;
1382
 
1383
      /* If the library ends in 'di' or in 'df', we assume it's
1384
         returning some DImode or some DFmode which are 64-bit wide.  */
1385
      name = XSTR (libname, 0);
1386
      len = strlen (name);
1387
      if (len > 3
1388
          && ((name[len - 2] == 'd'
1389
               && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1390
              || (name[len - 3] == 'd'
1391
                  && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1392
        {
1393
          /* We are in.  Mark the first parameter register as already used.  */
1394
          cum->words = 1;
1395
          cum->nregs = 1;
1396
        }
1397
      return;
1398
    }
1399
 
1400
  ret_type = TREE_TYPE (fntype);
1401
 
1402
  if (ret_type && aggregate_value_p (ret_type, fntype))
1403
    {
1404
      cum->words = 1;
1405
      cum->nregs = 1;
1406
    }
1407
}
1408
 
1409
/* Update the data in CUM to advance over an argument
1410
   of mode MODE and data type TYPE.
1411
   (TYPE is null for libcalls where that information may not be available.)  */
1412
 
1413
void
1414
m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1415
                              tree type, int named ATTRIBUTE_UNUSED)
1416
{
1417
  if (mode != BLKmode)
1418
    {
1419
      if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1420
        {
1421
          cum->nregs = 2;
1422
          cum->words = GET_MODE_SIZE (mode);
1423
        }
1424
      else
1425
        {
1426
          cum->words += GET_MODE_SIZE (mode);
1427
          if (cum->words <= HARD_REG_SIZE)
1428
            cum->nregs = 1;
1429
        }
1430
    }
1431
  else
1432
    {
1433
      cum->words += int_size_in_bytes (type);
1434
    }
1435
  return;
1436
}
1437
 
1438
/* Define where to put the arguments to a function.
1439
   Value is zero to push the argument on the stack,
1440
   or a hard register in which to store the argument.
1441
 
1442
   MODE is the argument's machine mode.
1443
   TYPE is the data type of the argument (as a tree).
1444
    This is null for libcalls where that information may
1445
    not be available.
1446
   CUM is a variable of type CUMULATIVE_ARGS which gives info about
1447
    the preceding args and about the function being called.
1448
   NAMED is nonzero if this argument is a named parameter
1449
    (otherwise it is an extra parameter matching an ellipsis).  */
1450
 
1451
struct rtx_def *
1452
m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1453
                      tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1454
{
1455
  if (cum->words != 0)
1456
    {
1457
      return NULL_RTX;
1458
    }
1459
 
1460
  if (mode != BLKmode)
1461
    {
1462
      if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1463
        return gen_rtx_REG (mode, HARD_X_REGNUM);
1464
 
1465
      if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1466
        {
1467
          return NULL_RTX;
1468
        }
1469
      return gen_rtx_REG (mode, HARD_D_REGNUM);
1470
    }
1471
  return NULL_RTX;
1472
}
1473
 
1474
/* If defined, a C expression which determines whether, and in which direction,
1475
   to pad out an argument with extra space.  The value should be of type
1476
   `enum direction': either `upward' to pad above the argument,
1477
   `downward' to pad below, or `none' to inhibit padding.
1478
 
1479
   Structures are stored left shifted in their argument slot.  */
1480
int
1481
m68hc11_function_arg_padding (enum machine_mode mode, tree type)
1482
{
1483
  if (type != 0 && AGGREGATE_TYPE_P (type))
1484
    return upward;
1485
 
1486
  /* Fall back to the default.  */
1487
  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1488
}
1489
 
1490
 
1491
/* Function prologue and epilogue.  */
1492
 
1493
/* Emit a move after the reload pass has completed.  This is used to
1494
   emit the prologue and epilogue.  */
1495
static void
1496
emit_move_after_reload (rtx to, rtx from, rtx scratch)
1497
{
1498
  rtx insn;
1499
 
1500
  if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1501
    {
1502
      insn = emit_move_insn (to, from);
1503
    }
1504
  else
1505
    {
1506
      emit_move_insn (scratch, from);
1507
      insn = emit_move_insn (to, scratch);
1508
    }
1509
 
1510
  /* Put a REG_INC note to tell the flow analysis that the instruction
1511
     is necessary.  */
1512
  if (IS_STACK_PUSH (to))
1513
    {
1514
      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1515
                                            XEXP (XEXP (to, 0), 0),
1516
                                            REG_NOTES (insn));
1517
    }
1518
  else if (IS_STACK_POP (from))
1519
    {
1520
      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1521
                                            XEXP (XEXP (from, 0), 0),
1522
                                            REG_NOTES (insn));
1523
    }
1524
 
1525
  /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1526
     to think that sp == _.frame and later replace a x = sp with x = _.frame.
1527
     The problem is that we are lying to gcc and use `txs' for x = sp
1528
     (which is not really true because txs is really x = sp + 1).  */
1529
  else if (TARGET_M6811 && SP_REG_P (from))
1530
    {
1531
      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1532
                                            from,
1533
                                            REG_NOTES (insn));
1534
    }
1535
}
1536
 
1537
int
1538
m68hc11_total_frame_size (void)
1539
{
1540
  int size;
1541
  int regno;
1542
 
1543
  size = get_frame_size ();
1544
  if (current_function_interrupt)
1545
    {
1546
      size += 3 * HARD_REG_SIZE;
1547
    }
1548
  if (frame_pointer_needed)
1549
    size += HARD_REG_SIZE;
1550
 
1551
  for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1552
    if (regs_ever_live[regno] && !call_used_regs[regno])
1553
      size += HARD_REG_SIZE;
1554
 
1555
  return size;
1556
}
1557
 
1558
static void
1559
m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1560
                                  HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1561
{
1562
  /* We catch the function epilogue generation to have a chance
1563
     to clear the z_replacement_completed flag.  */
1564
  z_replacement_completed = 0;
1565
}
1566
 
1567
void
1568
expand_prologue (void)
1569
{
1570
  tree func_attr;
1571
  int size;
1572
  int regno;
1573
  rtx scratch;
1574
 
1575
  gcc_assert (reload_completed == 1);
1576
 
1577
  size = get_frame_size ();
1578
 
1579
  create_regs_rtx ();
1580
 
1581
  /* Generate specific prologue for interrupt handlers.  */
1582
  func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1583
  current_function_interrupt = lookup_attribute ("interrupt",
1584
                                                 func_attr) != NULL_TREE;
1585
  current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1586
  if (lookup_attribute ("far", func_attr) != NULL_TREE)
1587
    current_function_far = 1;
1588
  else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1589
    current_function_far = 0;
1590
  else
1591
    current_function_far = (TARGET_LONG_CALLS != 0
1592
                            && !current_function_interrupt
1593
                            && !current_function_trap);
1594
 
1595
  /* Get the scratch register to build the frame and push registers.
1596
     If the first argument is a 32-bit quantity, the D+X registers
1597
     are used.  Use Y to compute the frame.  Otherwise, X is cheaper.
1598
     For 68HC12, this scratch register is not used.  */
1599
  if (current_function_args_info.nregs == 2)
1600
    scratch = iy_reg;
1601
  else
1602
    scratch = ix_reg;
1603
 
1604
  /* Save current stack frame.  */
1605
  if (frame_pointer_needed)
1606
    emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1607
 
1608
  /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1609
     Other soft registers in page0 need not to be saved because they
1610
     will be restored by C functions.  For a trap handler, we don't
1611
     need to preserve these registers because this is a synchronous call.  */
1612
  if (current_function_interrupt)
1613
    {
1614
      emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1615
      emit_move_after_reload (stack_push_word,
1616
                              gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1617
      emit_move_after_reload (stack_push_word,
1618
                              gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1619
                              scratch);
1620
    }
1621
 
1622
  /* Allocate local variables.  */
1623
  if (TARGET_M6812 && (size > 4 || size == 3))
1624
    {
1625
      emit_insn (gen_addhi3 (stack_pointer_rtx,
1626
                             stack_pointer_rtx, GEN_INT (-size)));
1627
    }
1628
  else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1629
    {
1630
      rtx insn;
1631
 
1632
      insn = gen_rtx_PARALLEL
1633
        (VOIDmode,
1634
         gen_rtvec (2,
1635
                    gen_rtx_SET (VOIDmode,
1636
                                 stack_pointer_rtx,
1637
                                 gen_rtx_PLUS (HImode,
1638
                                               stack_pointer_rtx,
1639
                                               GEN_INT (-size))),
1640
                    gen_rtx_CLOBBER (VOIDmode, scratch)));
1641
      emit_insn (insn);
1642
    }
1643
  else
1644
    {
1645
      int i;
1646
 
1647
      /* Allocate by pushing scratch values.  */
1648
      for (i = 2; i <= size; i += 2)
1649
        emit_move_after_reload (stack_push_word, ix_reg, 0);
1650
 
1651
      if (size & 1)
1652
        emit_insn (gen_addhi3 (stack_pointer_rtx,
1653
                               stack_pointer_rtx, constm1_rtx));
1654
    }
1655
 
1656
  /* Create the frame pointer.  */
1657
  if (frame_pointer_needed)
1658
    emit_move_after_reload (hard_frame_pointer_rtx,
1659
                            stack_pointer_rtx, scratch);
1660
 
1661
  /* Push any 2 byte pseudo hard registers that we need to save.  */
1662
  for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1663
    {
1664
      if (regs_ever_live[regno] && !call_used_regs[regno])
1665
        {
1666
          emit_move_after_reload (stack_push_word,
1667
                                  gen_rtx_REG (HImode, regno), scratch);
1668
        }
1669
    }
1670
}
1671
 
1672
void
1673
expand_epilogue (void)
1674
{
1675
  int size;
1676
  register int regno;
1677
  int return_size;
1678
  rtx scratch;
1679
 
1680
  gcc_assert (reload_completed == 1);
1681
 
1682
  size = get_frame_size ();
1683
 
1684
  /* If we are returning a value in two registers, we have to preserve the
1685
     X register and use the Y register to restore the stack and the saved
1686
     registers.  Otherwise, use X because it's faster (and smaller).  */
1687
  if (current_function_return_rtx == 0)
1688
    return_size = 0;
1689
  else if (GET_CODE (current_function_return_rtx) == MEM)
1690
    return_size = HARD_REG_SIZE;
1691
  else
1692
    return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1693
 
1694
  if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1695
    scratch = iy_reg;
1696
  else
1697
    scratch = ix_reg;
1698
 
1699
  /* Pop any 2 byte pseudo hard registers that we saved.  */
1700
  for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1701
    {
1702
      if (regs_ever_live[regno] && !call_used_regs[regno])
1703
        {
1704
          emit_move_after_reload (gen_rtx_REG (HImode, regno),
1705
                                  stack_pop_word, scratch);
1706
        }
1707
    }
1708
 
1709
  /* de-allocate auto variables */
1710
  if (TARGET_M6812 && (size > 4 || size == 3))
1711
    {
1712
      emit_insn (gen_addhi3 (stack_pointer_rtx,
1713
                             stack_pointer_rtx, GEN_INT (size)));
1714
    }
1715
  else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1716
    {
1717
      rtx insn;
1718
 
1719
      insn = gen_rtx_PARALLEL
1720
        (VOIDmode,
1721
         gen_rtvec (2,
1722
                    gen_rtx_SET (VOIDmode,
1723
                                 stack_pointer_rtx,
1724
                                 gen_rtx_PLUS (HImode,
1725
                                               stack_pointer_rtx,
1726
                                               GEN_INT (size))),
1727
                    gen_rtx_CLOBBER (VOIDmode, scratch)));
1728
      emit_insn (insn);
1729
    }
1730
  else
1731
    {
1732
      int i;
1733
 
1734
      for (i = 2; i <= size; i += 2)
1735
        emit_move_after_reload (scratch, stack_pop_word, scratch);
1736
      if (size & 1)
1737
        emit_insn (gen_addhi3 (stack_pointer_rtx,
1738
                               stack_pointer_rtx, const1_rtx));
1739
    }
1740
 
1741
  /* For an interrupt handler, restore ZTMP, ZREG and XYREG.  */
1742
  if (current_function_interrupt)
1743
    {
1744
      emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1745
                              stack_pop_word, scratch);
1746
      emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1747
                              stack_pop_word, scratch);
1748
      emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1749
    }
1750
 
1751
  /* Restore previous frame pointer.  */
1752
  if (frame_pointer_needed)
1753
    emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1754
 
1755
  /* If the trap handler returns some value, copy the value
1756
     in D, X onto the stack so that the rti will pop the return value
1757
     correctly.  */
1758
  else if (current_function_trap && return_size != 0)
1759
    {
1760
      rtx addr_reg = stack_pointer_rtx;
1761
 
1762
      if (!TARGET_M6812)
1763
        {
1764
          emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1765
          addr_reg = scratch;
1766
        }
1767
      emit_move_after_reload (gen_rtx_MEM (HImode,
1768
                                       gen_rtx_PLUS (HImode, addr_reg,
1769
                                                const1_rtx)), d_reg, 0);
1770
      if (return_size > HARD_REG_SIZE)
1771
        emit_move_after_reload (gen_rtx_MEM (HImode,
1772
                                         gen_rtx_PLUS (HImode, addr_reg,
1773
                                                  GEN_INT (3))), ix_reg, 0);
1774
    }
1775
 
1776
  emit_jump_insn (gen_return ());
1777
}
1778
 
1779
 
1780
/* Low and High part extraction for 68HC11.  These routines are
1781
   similar to gen_lowpart and gen_highpart but they have been
1782
   fixed to work for constants and 68HC11 specific registers.  */
1783
 
1784
rtx
1785
m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1786
{
1787
  /* We assume that the low part of an auto-inc mode is the same with
1788
     the mode changed and that the caller split the larger mode in the
1789
     correct order.  */
1790
  if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1791
    {
1792
      return gen_rtx_MEM (mode, XEXP (x, 0));
1793
    }
1794
 
1795
  /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1796
     floating-point constant.  A CONST_DOUBLE is used whenever the
1797
     constant requires more than one word in order to be adequately
1798
     represented.  */
1799
  if (GET_CODE (x) == CONST_DOUBLE)
1800
    {
1801
      long l[2];
1802
 
1803
      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1804
        {
1805
          REAL_VALUE_TYPE r;
1806
 
1807
          if (GET_MODE (x) == SFmode)
1808
            {
1809
              REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1810
              REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1811
            }
1812
          else
1813
            {
1814
              rtx first, second;
1815
 
1816
              split_double (x, &first, &second);
1817
              return second;
1818
            }
1819
          if (mode == SImode)
1820
            return GEN_INT (l[0]);
1821
 
1822
          return gen_int_mode (l[0], HImode);
1823
        }
1824
      else
1825
        {
1826
          l[0] = CONST_DOUBLE_LOW (x);
1827
        }
1828
      switch (mode)
1829
        {
1830
        case SImode:
1831
          return GEN_INT (l[0]);
1832
        case HImode:
1833
          gcc_assert (GET_MODE (x) == SFmode);
1834
          return gen_int_mode (l[0], HImode);
1835
        default:
1836
          gcc_unreachable ();
1837
        }
1838
    }
1839
 
1840
  if (mode == QImode && D_REG_P (x))
1841
    return gen_rtx_REG (mode, HARD_B_REGNUM);
1842
 
1843
  /* gen_lowpart crashes when it is called with a SUBREG.  */
1844
  if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1845
    {
1846
      switch (mode)
1847
        {
1848
        case SImode:
1849
          return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1850
        case HImode:
1851
          return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1852
        default:
1853
          gcc_unreachable ();
1854
        }
1855
    }
1856
  x = gen_lowpart (mode, x);
1857
 
1858
  /* Return a different rtx to avoid to share it in several insns
1859
     (when used by a split pattern).  Sharing addresses within
1860
     a MEM breaks the Z register replacement (and reloading).  */
1861
  if (GET_CODE (x) == MEM)
1862
    x = copy_rtx (x);
1863
  return x;
1864
}
1865
 
1866
rtx
1867
m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1868
{
1869
  /* We assume that the high part of an auto-inc mode is the same with
1870
     the mode changed and that the caller split the larger mode in the
1871
     correct order.  */
1872
  if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1873
    {
1874
      return gen_rtx_MEM (mode, XEXP (x, 0));
1875
    }
1876
 
1877
  /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1878
     floating-point constant.  A CONST_DOUBLE is used whenever the
1879
     constant requires more than one word in order to be adequately
1880
     represented.  */
1881
  if (GET_CODE (x) == CONST_DOUBLE)
1882
    {
1883
      long l[2];
1884
 
1885
      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1886
        {
1887
          REAL_VALUE_TYPE r;
1888
 
1889
          if (GET_MODE (x) == SFmode)
1890
            {
1891
              REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1892
              REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1893
            }
1894
          else
1895
            {
1896
              rtx first, second;
1897
 
1898
              split_double (x, &first, &second);
1899
              return first;
1900
            }
1901
          if (mode == SImode)
1902
            return GEN_INT (l[1]);
1903
 
1904
          return gen_int_mode ((l[1] >> 16), HImode);
1905
        }
1906
      else
1907
        {
1908
          l[1] = CONST_DOUBLE_HIGH (x);
1909
        }
1910
 
1911
      switch (mode)
1912
        {
1913
        case SImode:
1914
          return GEN_INT (l[1]);
1915
        case HImode:
1916
          gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1917
          return gen_int_mode ((l[0] >> 16), HImode);
1918
        default:
1919
          gcc_unreachable ();
1920
        }
1921
    }
1922
  if (GET_CODE (x) == CONST_INT)
1923
    {
1924
      HOST_WIDE_INT val = INTVAL (x);
1925
 
1926
      if (mode == QImode)
1927
        {
1928
          return gen_int_mode (val >> 8, QImode);
1929
        }
1930
      else if (mode == HImode)
1931
        {
1932
          return gen_int_mode (val >> 16, HImode);
1933
        }
1934
      else if (mode == SImode)
1935
       {
1936
         return gen_int_mode (val >> 32, SImode);
1937
       }
1938
    }
1939
  if (mode == QImode && D_REG_P (x))
1940
    return gen_rtx_REG (mode, HARD_A_REGNUM);
1941
 
1942
  /* There is no way in GCC to represent the upper part of a word register.
1943
     To obtain the 8-bit upper part of a soft register, we change the
1944
     reg into a mem rtx.  This is possible because they are physically
1945
     located in memory.  There is no offset because we are big-endian.  */
1946
  if (mode == QImode && S_REG_P (x))
1947
    {
1948
      int pos;
1949
 
1950
      /* Avoid the '*' for direct addressing mode when this
1951
         addressing mode is disabled.  */
1952
      pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1953
      return gen_rtx_MEM (QImode,
1954
                      gen_rtx_SYMBOL_REF (Pmode,
1955
                               &reg_names[REGNO (x)][pos]));
1956
    }
1957
 
1958
  /* gen_highpart crashes when it is called with a SUBREG.  */
1959
  switch (GET_CODE (x))
1960
    {
1961
    case SUBREG:
1962
      return gen_rtx_SUBREG (mode, XEXP (x, 0), XEXP (x, 1));
1963
    case REG:
1964
      if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1965
        return gen_rtx_REG (mode, REGNO (x));
1966
      else
1967
        return gen_rtx_SUBREG (mode, x, 0);
1968
    case MEM:
1969
      x = change_address (x, mode, 0);
1970
 
1971
      /* Return a different rtx to avoid to share it in several insns
1972
         (when used by a split pattern).  Sharing addresses within
1973
         a MEM breaks the Z register replacement (and reloading).  */
1974
      if (GET_CODE (x) == MEM)
1975
        x = copy_rtx (x);
1976
      return x;
1977
 
1978
    default:
1979
      gcc_unreachable ();
1980
    }
1981
}
1982
 
1983
 
1984
/* Obscure register manipulation.  */
1985
 
1986
/* Finds backward in the instructions to see if register 'reg' is
1987
   dead.  This is used when generating code to see if we can use 'reg'
1988
   as a scratch register.  This allows us to choose a better generation
1989
   of code when we know that some register dies or can be clobbered.  */
1990
 
1991
int
1992
dead_register_here (rtx x, rtx reg)
1993
{
1994
  rtx x_reg;
1995
  rtx p;
1996
 
1997
  if (D_REG_P (reg))
1998
    x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
1999
  else
2000
    x_reg = 0;
2001
 
2002
  for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2003
    if (INSN_P (p))
2004
      {
2005
        rtx body;
2006
 
2007
        body = PATTERN (p);
2008
 
2009
        if (GET_CODE (body) == CALL_INSN)
2010
          break;
2011
        if (GET_CODE (body) == JUMP_INSN)
2012
          break;
2013
 
2014
        if (GET_CODE (body) == SET)
2015
          {
2016
            rtx dst = XEXP (body, 0);
2017
 
2018
            if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2019
              break;
2020
            if (x_reg && rtx_equal_p (dst, x_reg))
2021
              break;
2022
 
2023
            if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2024
              return 1;
2025
          }
2026
        else if (reg_mentioned_p (reg, p)
2027
                 || (x_reg && reg_mentioned_p (x_reg, p)))
2028
          break;
2029
      }
2030
 
2031
  /* Scan forward to see if the register is set in some insns and never
2032
     used since then.  */
2033
  for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2034
    {
2035
      rtx body;
2036
 
2037
      if (GET_CODE (p) == CODE_LABEL
2038
          || GET_CODE (p) == JUMP_INSN
2039
          || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2040
        break;
2041
 
2042
      if (GET_CODE (p) != INSN)
2043
        continue;
2044
 
2045
      body = PATTERN (p);
2046
      if (GET_CODE (body) == SET)
2047
        {
2048
          rtx src = XEXP (body, 1);
2049
          rtx dst = XEXP (body, 0);
2050
 
2051
          if (GET_CODE (dst) == REG
2052
              && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2053
            return 1;
2054
        }
2055
 
2056
      /* Register is used (may be in source or in dest).  */
2057
      if (reg_mentioned_p (reg, p)
2058
          || (x_reg != 0 && GET_MODE (p) == SImode
2059
              && reg_mentioned_p (x_reg, p)))
2060
        break;
2061
    }
2062
  return p == 0 ? 1 : 0;
2063
}
2064
 
2065
 
2066
/* Code generation operations called from machine description file.  */
2067
 
2068
/* Print the name of register 'regno' in the assembly file.  */
2069
static void
2070
asm_print_register (FILE *file, int regno)
2071
{
2072
  const char *name = reg_names[regno];
2073
 
2074
  if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2075
    name++;
2076
 
2077
  fprintf (file, "%s", name);
2078
}
2079
 
2080
/* A C compound statement to output to stdio stream STREAM the
2081
   assembler syntax for an instruction operand X.  X is an RTL
2082
   expression.
2083
 
2084
   CODE is a value that can be used to specify one of several ways
2085
   of printing the operand.  It is used when identical operands
2086
   must be printed differently depending on the context.  CODE
2087
   comes from the `%' specification that was used to request
2088
   printing of the operand.  If the specification was just `%DIGIT'
2089
   then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2090
   is the ASCII code for LTR.
2091
 
2092
   If X is a register, this macro should print the register's name.
2093
   The names can be found in an array `reg_names' whose type is
2094
   `char *[]'.  `reg_names' is initialized from `REGISTER_NAMES'.
2095
 
2096
   When the machine description has a specification `%PUNCT' (a `%'
2097
   followed by a punctuation character), this macro is called with
2098
   a null pointer for X and the punctuation character for CODE.
2099
 
2100
   The M68HC11 specific codes are:
2101
 
2102
   'b' for the low part of the operand.
2103
   'h' for the high part of the operand
2104
       The 'b' or 'h' modifiers have no effect if the operand has
2105
       the QImode and is not a S_REG_P (soft register).  If the
2106
       operand is a hard register, these two modifiers have no effect.
2107
   't' generate the temporary scratch register.  The operand is
2108
       ignored.
2109
   'T' generate the low-part temporary scratch register.  The operand is
2110
       ignored.  */
2111
 
2112
void
2113
print_operand (FILE *file, rtx op, int letter)
2114
{
2115
  if (letter == 't')
2116
    {
2117
      asm_print_register (file, SOFT_TMP_REGNUM);
2118
      return;
2119
    }
2120
  else if (letter == 'T')
2121
    {
2122
      asm_print_register (file, SOFT_TMP_REGNUM);
2123
      fprintf (file, "+1");
2124
      return;
2125
    }
2126
  else if (letter == '#')
2127
    {
2128
      asm_fprintf (file, "%I");
2129
    }
2130
 
2131
  if (GET_CODE (op) == REG)
2132
    {
2133
      if (letter == 'b' && S_REG_P (op))
2134
        {
2135
          asm_print_register (file, REGNO (op));
2136
          fprintf (file, "+1");
2137
        }
2138
      else if (letter == 'b' && D_REG_P (op))
2139
        {
2140
          asm_print_register (file, HARD_B_REGNUM);
2141
        }
2142
      else
2143
        {
2144
          asm_print_register (file, REGNO (op));
2145
        }
2146
      return;
2147
    }
2148
 
2149
  if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2150
    {
2151
      if (letter == 'b')
2152
        asm_fprintf (file, "%I%%lo(");
2153
      else
2154
        asm_fprintf (file, "%I%%hi(");
2155
 
2156
      output_addr_const (file, op);
2157
      fprintf (file, ")");
2158
      return;
2159
    }
2160
 
2161
  /* Get the low or high part of the operand when 'b' or 'h' modifiers
2162
     are specified.  If we already have a QImode, there is nothing to do.  */
2163
  if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2164
    {
2165
      if (letter == 'b')
2166
        {
2167
          op = m68hc11_gen_lowpart (QImode, op);
2168
        }
2169
      else if (letter == 'h')
2170
        {
2171
          op = m68hc11_gen_highpart (QImode, op);
2172
        }
2173
    }
2174
 
2175
  if (GET_CODE (op) == MEM)
2176
    {
2177
      rtx base = XEXP (op, 0);
2178
      switch (GET_CODE (base))
2179
        {
2180
        case PRE_DEC:
2181
          gcc_assert (TARGET_M6812);
2182
          fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2183
          asm_print_register (file, REGNO (XEXP (base, 0)));
2184
          break;
2185
 
2186
        case POST_DEC:
2187
          gcc_assert (TARGET_M6812);
2188
          fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2189
          asm_print_register (file, REGNO (XEXP (base, 0)));
2190
          fprintf (file, "-");
2191
          break;
2192
 
2193
        case POST_INC:
2194
          gcc_assert (TARGET_M6812);
2195
          fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2196
          asm_print_register (file, REGNO (XEXP (base, 0)));
2197
          fprintf (file, "+");
2198
          break;
2199
 
2200
        case PRE_INC:
2201
          gcc_assert (TARGET_M6812);
2202
          fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2203
          asm_print_register (file, REGNO (XEXP (base, 0)));
2204
          break;
2205
 
2206
        case MEM:
2207
          gcc_assert (TARGET_M6812);
2208
          fprintf (file, "[");
2209
          print_operand_address (file, XEXP (base, 0));
2210
          fprintf (file, "]");
2211
          break;
2212
 
2213
        default:
2214
          if (m68hc11_page0_symbol_p (base))
2215
            fprintf (file, "*");
2216
 
2217
          output_address (base);
2218
          break;
2219
        }
2220
    }
2221
  else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2222
    {
2223
      REAL_VALUE_TYPE r;
2224
      long l;
2225
 
2226
      REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2227
      REAL_VALUE_TO_TARGET_SINGLE (r, l);
2228
      asm_fprintf (file, "%I0x%lx", l);
2229
    }
2230
  else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2231
    {
2232
      char dstr[30];
2233
 
2234
      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2235
                       sizeof (dstr), 0, 1);
2236
      asm_fprintf (file, "%I0r%s", dstr);
2237
    }
2238
  else
2239
    {
2240
      int need_parenthesize = 0;
2241
 
2242
      if (letter != 'i')
2243
        asm_fprintf (file, "%I");
2244
      else
2245
        need_parenthesize = must_parenthesize (op);
2246
 
2247
      if (need_parenthesize)
2248
        fprintf (file, "(");
2249
 
2250
      output_addr_const (file, op);
2251
      if (need_parenthesize)
2252
        fprintf (file, ")");
2253
    }
2254
}
2255
 
2256
/* Returns true if the operand 'op' must be printed with parenthesis
2257
   around it.  This must be done only if there is a symbol whose name
2258
   is a processor register.  */
2259
static int
2260
must_parenthesize (rtx op)
2261
{
2262
  const char *name;
2263
 
2264
  switch (GET_CODE (op))
2265
    {
2266
    case SYMBOL_REF:
2267
      name = XSTR (op, 0);
2268
      /* Avoid a conflict between symbol name and a possible
2269
         register.  */
2270
      return (strcasecmp (name, "a") == 0
2271
              || strcasecmp (name, "b") == 0
2272
              || strcasecmp (name, "d") == 0
2273
              || strcasecmp (name, "x") == 0
2274
              || strcasecmp (name, "y") == 0
2275
              || strcasecmp (name, "ix") == 0
2276
              || strcasecmp (name, "iy") == 0
2277
              || strcasecmp (name, "pc") == 0
2278
              || strcasecmp (name, "sp") == 0
2279
              || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2280
 
2281
    case PLUS:
2282
    case MINUS:
2283
      return must_parenthesize (XEXP (op, 0))
2284
        || must_parenthesize (XEXP (op, 1));
2285
 
2286
    case MEM:
2287
    case CONST:
2288
    case ZERO_EXTEND:
2289
    case SIGN_EXTEND:
2290
      return must_parenthesize (XEXP (op, 0));
2291
 
2292
    case CONST_DOUBLE:
2293
    case CONST_INT:
2294
    case LABEL_REF:
2295
    case CODE_LABEL:
2296
    default:
2297
      return 0;
2298
    }
2299
}
2300
 
2301
/* A C compound statement to output to stdio stream STREAM the
2302
   assembler syntax for an instruction operand that is a memory
2303
   reference whose address is ADDR.  ADDR is an RTL expression.  */
2304
 
2305
void
2306
print_operand_address (FILE *file, rtx addr)
2307
{
2308
  rtx base;
2309
  rtx offset;
2310
  int need_parenthesis = 0;
2311
 
2312
  switch (GET_CODE (addr))
2313
    {
2314
    case REG:
2315
      gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2316
 
2317
      fprintf (file, "0,");
2318
      asm_print_register (file, REGNO (addr));
2319
      break;
2320
 
2321
    case MEM:
2322
      base = XEXP (addr, 0);
2323
      switch (GET_CODE (base))
2324
        {
2325
        case PRE_DEC:
2326
          gcc_assert (TARGET_M6812);
2327
          fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2328
          asm_print_register (file, REGNO (XEXP (base, 0)));
2329
          break;
2330
 
2331
        case POST_DEC:
2332
          gcc_assert (TARGET_M6812);
2333
          fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2334
          asm_print_register (file, REGNO (XEXP (base, 0)));
2335
          fprintf (file, "-");
2336
          break;
2337
 
2338
        case POST_INC:
2339
          gcc_assert (TARGET_M6812);
2340
          fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2341
          asm_print_register (file, REGNO (XEXP (base, 0)));
2342
          fprintf (file, "+");
2343
          break;
2344
 
2345
        case PRE_INC:
2346
          gcc_assert (TARGET_M6812);
2347
          fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2348
          asm_print_register (file, REGNO (XEXP (base, 0)));
2349
          break;
2350
 
2351
        default:
2352
          need_parenthesis = must_parenthesize (base);
2353
          if (need_parenthesis)
2354
            fprintf (file, "(");
2355
 
2356
          output_addr_const (file, base);
2357
          if (need_parenthesis)
2358
            fprintf (file, ")");
2359
          break;
2360
        }
2361
      break;
2362
 
2363
    case PLUS:
2364
      base = XEXP (addr, 0);
2365
      offset = XEXP (addr, 1);
2366
      if (!G_REG_P (base) && G_REG_P (offset))
2367
        {
2368
          base = XEXP (addr, 1);
2369
          offset = XEXP (addr, 0);
2370
        }
2371
      if (CONSTANT_ADDRESS_P (base))
2372
        {
2373
          need_parenthesis = must_parenthesize (addr);
2374
 
2375
          gcc_assert (CONSTANT_ADDRESS_P (offset));
2376
          if (need_parenthesis)
2377
            fprintf (file, "(");
2378
 
2379
          output_addr_const (file, base);
2380
          fprintf (file, "+");
2381
          output_addr_const (file, offset);
2382
          if (need_parenthesis)
2383
            fprintf (file, ")");
2384
        }
2385
      else
2386
        {
2387
          gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2388
          if (REG_P (offset))
2389
            {
2390
              gcc_assert (TARGET_M6812);
2391
              asm_print_register (file, REGNO (offset));
2392
              fprintf (file, ",");
2393
              asm_print_register (file, REGNO (base));
2394
            }
2395
          else
2396
            {
2397
              need_parenthesis = must_parenthesize (offset);
2398
              if (need_parenthesis)
2399
                fprintf (file, "(");
2400
 
2401
              output_addr_const (file, offset);
2402
              if (need_parenthesis)
2403
                fprintf (file, ")");
2404
              fprintf (file, ",");
2405
              asm_print_register (file, REGNO (base));
2406
            }
2407
        }
2408
      break;
2409
 
2410
    default:
2411
      if (GET_CODE (addr) == CONST_INT
2412
          && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2413
        {
2414
          fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2415
        }
2416
      else
2417
        {
2418
          need_parenthesis = must_parenthesize (addr);
2419
          if (need_parenthesis)
2420
            fprintf (file, "(");
2421
 
2422
          output_addr_const (file, addr);
2423
          if (need_parenthesis)
2424
            fprintf (file, ")");
2425
        }
2426
      break;
2427
    }
2428
}
2429
 
2430
 
2431
/* Splitting of some instructions.  */
2432
 
2433
static rtx
2434
m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2435
{
2436
  rtx ret = 0;
2437
 
2438
  gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2439
  emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2440
                          gen_rtx_COMPARE (VOIDmode, op0, op1)));
2441
  ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2442
 
2443
  return ret;
2444
}
2445
 
2446
rtx
2447
m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2448
                                   rtx label)
2449
{
2450
  rtx tmp;
2451
 
2452
  switch (GET_MODE (op0))
2453
    {
2454
    case QImode:
2455
    case HImode:
2456
      tmp = m68hc11_expand_compare (code, op0, op1);
2457
      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2458
                                  gen_rtx_LABEL_REF (VOIDmode, label),
2459
                                  pc_rtx);
2460
      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2461
      return 0;
2462
#if 0
2463
 
2464
      /* SCz: from i386.c  */
2465
    case SFmode:
2466
    case DFmode:
2467
      /* Don't expand the comparison early, so that we get better code
2468
         when jump or whoever decides to reverse the comparison.  */
2469
      {
2470
        rtvec vec;
2471
        int use_fcomi;
2472
 
2473
        code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2474
                                                &m68hc11_compare_op1);
2475
 
2476
        tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2477
                              m68hc11_compare_op0, m68hc11_compare_op1);
2478
        tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2479
                                    gen_rtx_LABEL_REF (VOIDmode, label),
2480
                                    pc_rtx);
2481
        tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2482
 
2483
        use_fcomi = ix86_use_fcomi_compare (code);
2484
        vec = rtvec_alloc (3 + !use_fcomi);
2485
        RTVEC_ELT (vec, 0) = tmp;
2486
        RTVEC_ELT (vec, 1)
2487
          = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2488
        RTVEC_ELT (vec, 2)
2489
          = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2490
        if (!use_fcomi)
2491
          RTVEC_ELT (vec, 3)
2492
            = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2493
 
2494
        emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2495
        return;
2496
      }
2497
#endif
2498
 
2499
    case SImode:
2500
      /* Expand SImode branch into multiple compare+branch.  */
2501
      {
2502
        rtx lo[2], hi[2], label2;
2503
        enum rtx_code code1, code2, code3;
2504
 
2505
        if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2506
          {
2507
            tmp = op0;
2508
            op0 = op1;
2509
            op1 = tmp;
2510
            code = swap_condition (code);
2511
          }
2512
        lo[0] = m68hc11_gen_lowpart (HImode, op0);
2513
        lo[1] = m68hc11_gen_lowpart (HImode, op1);
2514
        hi[0] = m68hc11_gen_highpart (HImode, op0);
2515
        hi[1] = m68hc11_gen_highpart (HImode, op1);
2516
 
2517
        /* Otherwise, if we are doing less-than, op1 is a constant and the
2518
           low word is zero, then we can just examine the high word.  */
2519
 
2520
        if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2521
            && (code == LT || code == LTU))
2522
          {
2523
            return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2524
                                                      label);
2525
          }
2526
 
2527
        /* Otherwise, we need two or three jumps.  */
2528
 
2529
        label2 = gen_label_rtx ();
2530
 
2531
        code1 = code;
2532
        code2 = swap_condition (code);
2533
        code3 = unsigned_condition (code);
2534
 
2535
        switch (code)
2536
          {
2537
          case LT:
2538
          case GT:
2539
          case LTU:
2540
          case GTU:
2541
            break;
2542
 
2543
          case LE:
2544
            code1 = LT;
2545
            code2 = GT;
2546
            break;
2547
          case GE:
2548
            code1 = GT;
2549
            code2 = LT;
2550
            break;
2551
          case LEU:
2552
            code1 = LTU;
2553
            code2 = GTU;
2554
            break;
2555
          case GEU:
2556
            code1 = GTU;
2557
            code2 = LTU;
2558
            break;
2559
 
2560
          case EQ:
2561
            code1 = UNKNOWN;
2562
            code2 = NE;
2563
            break;
2564
          case NE:
2565
            code2 = UNKNOWN;
2566
            break;
2567
 
2568
          default:
2569
            gcc_unreachable ();
2570
          }
2571
 
2572
        /*
2573
         * a < b =>
2574
         *    if (hi(a) < hi(b)) goto true;
2575
         *    if (hi(a) > hi(b)) goto false;
2576
         *    if (lo(a) < lo(b)) goto true;
2577
         *  false:
2578
         */
2579
        if (code1 != UNKNOWN)
2580
          m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2581
        if (code2 != UNKNOWN)
2582
          m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2583
 
2584
        m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2585
 
2586
        if (code2 != UNKNOWN)
2587
          emit_label (label2);
2588
        return 0;
2589
      }
2590
 
2591
    default:
2592
      gcc_unreachable ();
2593
    }
2594
  return 0;
2595
}
2596
 
2597
/* Return the increment/decrement mode of a MEM if it is such.
2598
   Return CONST if it is anything else.  */
2599
static int
2600
autoinc_mode (rtx x)
2601
{
2602
  if (GET_CODE (x) != MEM)
2603
    return CONST;
2604
 
2605
  x = XEXP (x, 0);
2606
  if (GET_CODE (x) == PRE_INC
2607
      || GET_CODE (x) == PRE_DEC
2608
      || GET_CODE (x) == POST_INC
2609
      || GET_CODE (x) == POST_DEC)
2610
    return GET_CODE (x);
2611
 
2612
  return CONST;
2613
}
2614
 
2615
static int
2616
m68hc11_make_autoinc_notes (rtx *x, void *data)
2617
{
2618
  rtx insn;
2619
 
2620
  switch (GET_CODE (*x))
2621
    {
2622
    case PRE_DEC:
2623
    case PRE_INC:
2624
    case POST_DEC:
2625
    case POST_INC:
2626
      insn = (rtx) data;
2627
      REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2628
                                          REG_NOTES (insn));
2629
      return -1;
2630
 
2631
    default:
2632
      return 0;
2633
    }
2634
}
2635
 
2636
/* Split a DI, SI or HI move into several smaller move operations.
2637
   The scratch register 'scratch' is used as a temporary to load
2638
   store intermediate values.  It must be a hard register.  */
2639
void
2640
m68hc11_split_move (rtx to, rtx from, rtx scratch)
2641
{
2642
  rtx low_to, low_from;
2643
  rtx high_to, high_from;
2644
  rtx insn;
2645
  enum machine_mode mode;
2646
  int offset = 0;
2647
  int autoinc_from = autoinc_mode (from);
2648
  int autoinc_to = autoinc_mode (to);
2649
 
2650
  mode = GET_MODE (to);
2651
 
2652
  /* If the TO and FROM contain autoinc modes that are not compatible
2653
     together (one pop and the other a push), we must change one to
2654
     an offsetable operand and generate an appropriate add at the end.  */
2655
  if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2656
    {
2657
      rtx reg;
2658
      int code;
2659
 
2660
      /* The source uses an autoinc mode which is not compatible with
2661
         a split (this would result in a word swap).  */
2662
      if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2663
        {
2664
          code = GET_CODE (XEXP (from, 0));
2665
          reg = XEXP (XEXP (from, 0), 0);
2666
          offset = GET_MODE_SIZE (GET_MODE (from));
2667
          if (code == POST_DEC)
2668
            offset = -offset;
2669
 
2670
          if (code == PRE_INC)
2671
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2672
 
2673
          m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2674
          if (code == POST_DEC)
2675
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2676
          return;
2677
        }
2678
 
2679
      /* Likewise for destination.  */
2680
      if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2681
        {
2682
          code = GET_CODE (XEXP (to, 0));
2683
          reg = XEXP (XEXP (to, 0), 0);
2684
          offset = GET_MODE_SIZE (GET_MODE (to));
2685
          if (code == POST_DEC)
2686
            offset = -offset;
2687
 
2688
          if (code == PRE_INC)
2689
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2690
 
2691
          m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2692
          if (code == POST_DEC)
2693
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2694
          return;
2695
        }
2696
 
2697
      /* The source and destination auto increment modes must be compatible
2698
         with each other: same direction.  */
2699
      if ((autoinc_to != autoinc_from
2700
           && autoinc_to != CONST && autoinc_from != CONST)
2701
          /* The destination address register must not be used within
2702
             the source operand because the source address would change
2703
             while doing the copy.  */
2704
          || (autoinc_to != CONST
2705
              && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2706
              && !IS_STACK_PUSH (to)))
2707
        {
2708
          /* Must change the destination.  */
2709
          code = GET_CODE (XEXP (to, 0));
2710
          reg = XEXP (XEXP (to, 0), 0);
2711
          offset = GET_MODE_SIZE (GET_MODE (to));
2712
          if (code == PRE_DEC || code == POST_DEC)
2713
            offset = -offset;
2714
 
2715
          if (code == PRE_DEC || code == PRE_INC)
2716
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2717
          m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2718
          if (code == POST_DEC || code == POST_INC)
2719
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2720
 
2721
          return;
2722
        }
2723
 
2724
      /* Likewise, the source address register must not be used within
2725
         the destination operand.  */
2726
      if (autoinc_from != CONST
2727
          && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2728
          && !IS_STACK_PUSH (to))
2729
        {
2730
          /* Must change the source.  */
2731
          code = GET_CODE (XEXP (from, 0));
2732
          reg = XEXP (XEXP (from, 0), 0);
2733
          offset = GET_MODE_SIZE (GET_MODE (from));
2734
          if (code == PRE_DEC || code == POST_DEC)
2735
            offset = -offset;
2736
 
2737
          if (code == PRE_DEC || code == PRE_INC)
2738
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2739
          m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2740
          if (code == POST_DEC || code == POST_INC)
2741
            emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2742
 
2743
          return;
2744
        }
2745
    }
2746
 
2747
  if (GET_MODE_SIZE (mode) == 8)
2748
    mode = SImode;
2749
  else if (GET_MODE_SIZE (mode) == 4)
2750
    mode = HImode;
2751
  else
2752
    mode = QImode;
2753
 
2754
  if (TARGET_M6812
2755
      && IS_STACK_PUSH (to)
2756
      && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2757
    {
2758
      if (mode == SImode)
2759
        {
2760
          offset = 4;
2761
        }
2762
      else if (mode == HImode)
2763
        {
2764
          offset = 2;
2765
        }
2766
      else
2767
        offset = 0;
2768
    }
2769
 
2770
  low_to = m68hc11_gen_lowpart (mode, to);
2771
  high_to = m68hc11_gen_highpart (mode, to);
2772
 
2773
  low_from = m68hc11_gen_lowpart (mode, from);
2774
  high_from = m68hc11_gen_highpart (mode, from);
2775
 
2776
  if (offset)
2777
    {
2778
      high_from = adjust_address (high_from, mode, offset);
2779
      low_from = high_from;
2780
    }
2781
 
2782
  /* When copying with a POST_INC mode, we must copy the
2783
     high part and then the low part to guarantee a correct
2784
     32/64-bit copy.  */
2785
  if (TARGET_M6812
2786
      && GET_MODE_SIZE (mode) >= 2
2787
      && autoinc_from != autoinc_to
2788
      && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2789
    {
2790
      rtx swap;
2791
 
2792
      swap = low_to;
2793
      low_to = high_to;
2794
      high_to = swap;
2795
 
2796
      swap = low_from;
2797
      low_from = high_from;
2798
      high_from = swap;
2799
    }
2800
  if (mode == SImode)
2801
    {
2802
      m68hc11_split_move (low_to, low_from, scratch);
2803
      m68hc11_split_move (high_to, high_from, scratch);
2804
    }
2805
  else if (H_REG_P (to) || H_REG_P (from)
2806
           || (low_from == const0_rtx
2807
               && high_from == const0_rtx
2808
               && ! push_operand (to, GET_MODE (to))
2809
               && ! H_REG_P (scratch))
2810
           || (TARGET_M6812
2811
               && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2812
                   || m68hc11_small_indexed_indirect_p (from,
2813
                                                        GET_MODE (from)))
2814
               && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2815
                   || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2816
    {
2817
      insn = emit_move_insn (low_to, low_from);
2818
      for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2819
 
2820
      insn = emit_move_insn (high_to, high_from);
2821
      for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2822
    }
2823
  else
2824
    {
2825
      insn = emit_move_insn (scratch, low_from);
2826
      for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2827
      insn = emit_move_insn (low_to, scratch);
2828
      for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2829
 
2830
      insn = emit_move_insn (scratch, high_from);
2831
      for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2832
      insn = emit_move_insn (high_to, scratch);
2833
      for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2834
    }
2835
}
2836
 
2837
static rtx
2838
simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2839
{
2840
  int val;
2841
  int mask;
2842
 
2843
  *result = 0;
2844
  if (GET_CODE (operand) != CONST_INT)
2845
    return operand;
2846
 
2847
  if (mode == HImode)
2848
    mask = 0x0ffff;
2849
  else
2850
    mask = 0x0ff;
2851
 
2852
  val = INTVAL (operand);
2853
  switch (code)
2854
    {
2855
    case IOR:
2856
      if ((val & mask) == 0)
2857
        return 0;
2858
      if ((val & mask) == mask)
2859
        *result = constm1_rtx;
2860
      break;
2861
 
2862
    case AND:
2863
      if ((val & mask) == 0)
2864
        *result = const0_rtx;
2865
      if ((val & mask) == mask)
2866
        return 0;
2867
      break;
2868
 
2869
    case XOR:
2870
      if ((val & mask) == 0)
2871
        return 0;
2872
      break;
2873
    }
2874
  return operand;
2875
}
2876
 
2877
static void
2878
m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
2879
{
2880
  rtx result;
2881
  int need_copy;
2882
 
2883
  need_copy = (rtx_equal_p (operands[0], operands[1])
2884
               || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2885
 
2886
  operands[1] = simplify_logical (mode, code, operands[1], &result);
2887
  operands[2] = simplify_logical (mode, code, operands[2], &result);
2888
 
2889
  if (result && GET_CODE (result) == CONST_INT)
2890
    {
2891
      if (!H_REG_P (operands[0]) && operands[3]
2892
          && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2893
        {
2894
          emit_move_insn (operands[3], result);
2895
          emit_move_insn (operands[0], operands[3]);
2896
        }
2897
      else
2898
        {
2899
          emit_move_insn (operands[0], result);
2900
        }
2901
    }
2902
  else if (operands[1] != 0 && operands[2] != 0)
2903
    {
2904
      rtx insn;
2905
 
2906
      if (!H_REG_P (operands[0]) && operands[3])
2907
        {
2908
          emit_move_insn (operands[3], operands[1]);
2909
          emit_insn (gen_rtx_SET (mode,
2910
                                  operands[3],
2911
                                  gen_rtx_fmt_ee (code, mode,
2912
                                                  operands[3], operands[2])));
2913
          insn = emit_move_insn (operands[0], operands[3]);
2914
        }
2915
      else
2916
        {
2917
          insn = emit_insn (gen_rtx_SET (mode,
2918
                                         operands[0],
2919
                                         gen_rtx_fmt_ee (code, mode,
2920
                                                         operands[0],
2921
                                                         operands[2])));
2922
        }
2923
    }
2924
 
2925
  /* The logical operation is similar to a copy.  */
2926
  else if (need_copy)
2927
    {
2928
      rtx src;
2929
 
2930
      if (GET_CODE (operands[1]) == CONST_INT)
2931
        src = operands[2];
2932
      else
2933
        src = operands[1];
2934
 
2935
      if (!H_REG_P (operands[0]) && !H_REG_P (src))
2936
        {
2937
          emit_move_insn (operands[3], src);
2938
          emit_move_insn (operands[0], operands[3]);
2939
        }
2940
      else
2941
        {
2942
          emit_move_insn (operands[0], src);
2943
        }
2944
    }
2945
}
2946
 
2947
void
2948
m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
2949
{
2950
  rtx low[4];
2951
  rtx high[4];
2952
 
2953
  low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2954
  low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2955
  low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2956
 
2957
  high[0] = m68hc11_gen_highpart (mode, operands[0]);
2958
  high[1] = m68hc11_gen_highpart (mode, operands[1]);
2959
  high[2] = m68hc11_gen_highpart (mode, operands[2]);
2960
 
2961
  low[3] = operands[3];
2962
  high[3] = operands[3];
2963
  if (mode == SImode)
2964
    {
2965
      m68hc11_split_logical (HImode, code, low);
2966
      m68hc11_split_logical (HImode, code, high);
2967
      return;
2968
    }
2969
 
2970
  m68hc11_emit_logical (mode, code, low);
2971
  m68hc11_emit_logical (mode, code, high);
2972
}
2973
 
2974
 
2975
/* Code generation.  */
2976
 
2977
void
2978
m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
2979
{
2980
  /* We have to be careful with the cc_status.  An address register swap
2981
     is generated for some comparison.  The comparison is made with D
2982
     but the branch really uses the address register.  See the split
2983
     pattern for compare.  The xgdx/xgdy preserve the flags but after
2984
     the exchange, the flags will reflect to the value of X and not D.
2985
     Tell this by setting the cc_status according to the cc_prev_status.  */
2986
  if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2987
    {
2988
      if (cc_prev_status.value1 != 0
2989
          && (D_REG_P (cc_prev_status.value1)
2990
              || X_REG_P (cc_prev_status.value1)))
2991
        {
2992
          cc_status = cc_prev_status;
2993
          if (D_REG_P (cc_status.value1))
2994
            cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
2995
                                        HARD_X_REGNUM);
2996
          else
2997
            cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
2998
                                        HARD_D_REGNUM);
2999
        }
3000
      else
3001
        CC_STATUS_INIT;
3002
 
3003
      output_asm_insn ("xgdx", operands);
3004
    }
3005
  else
3006
    {
3007
      if (cc_prev_status.value1 != 0
3008
          && (D_REG_P (cc_prev_status.value1)
3009
              || Y_REG_P (cc_prev_status.value1)))
3010
        {
3011
          cc_status = cc_prev_status;
3012
          if (D_REG_P (cc_status.value1))
3013
            cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3014
                                        HARD_Y_REGNUM);
3015
          else
3016
            cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3017
                                        HARD_D_REGNUM);
3018
        }
3019
      else
3020
        CC_STATUS_INIT;
3021
 
3022
      output_asm_insn ("xgdy", operands);
3023
    }
3024
}
3025
 
3026
/* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3027
   This is used to decide whether a move that set flags should be used
3028
   instead.  */
3029
int
3030
next_insn_test_reg (rtx insn, rtx reg)
3031
{
3032
  rtx body;
3033
 
3034
  insn = next_nonnote_insn (insn);
3035
  if (GET_CODE (insn) != INSN)
3036
    return 0;
3037
 
3038
  body = PATTERN (insn);
3039
  if (sets_cc0_p (body) != 1)
3040
    return 0;
3041
 
3042
  if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3043
    return 0;
3044
 
3045
  return 1;
3046
}
3047
 
3048
/* Generate the code to move a 16-bit operand into another one.  */
3049
 
3050
void
3051
m68hc11_gen_movhi (rtx insn, rtx *operands)
3052
{
3053
  int reg;
3054
 
3055
  /* Move a register or memory to the same location.
3056
     This is possible because such insn can appear
3057
     in a non-optimizing mode.  */
3058
  if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3059
    {
3060
      cc_status = cc_prev_status;
3061
      return;
3062
    }
3063
 
3064
  if (TARGET_M6812)
3065
    {
3066
      rtx from = operands[1];
3067
      rtx to = operands[0];
3068
 
3069
      if (IS_STACK_PUSH (to) && H_REG_P (from))
3070
        {
3071
          cc_status = cc_prev_status;
3072
          switch (REGNO (from))
3073
            {
3074
            case HARD_X_REGNUM:
3075
            case HARD_Y_REGNUM:
3076
            case HARD_D_REGNUM:
3077
              output_asm_insn ("psh%1", operands);
3078
              break;
3079
            case HARD_SP_REGNUM:
3080
              output_asm_insn ("sts\t2,-sp", operands);
3081
              break;
3082
            default:
3083
              gcc_unreachable ();
3084
            }
3085
          return;
3086
        }
3087
      if (IS_STACK_POP (from) && H_REG_P (to))
3088
        {
3089
          cc_status = cc_prev_status;
3090
          switch (REGNO (to))
3091
            {
3092
            case HARD_X_REGNUM:
3093
            case HARD_Y_REGNUM:
3094
            case HARD_D_REGNUM:
3095
              output_asm_insn ("pul%0", operands);
3096
              break;
3097
            default:
3098
              gcc_unreachable ();
3099
            }
3100
          return;
3101
        }
3102
      if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3103
        {
3104
          m68hc11_notice_keep_cc (operands[0]);
3105
          output_asm_insn ("tfr\t%1,%0", operands);
3106
        }
3107
      else if (H_REG_P (operands[0]))
3108
        {
3109
          if (SP_REG_P (operands[0]))
3110
            output_asm_insn ("lds\t%1", operands);
3111
          else
3112
            output_asm_insn ("ld%0\t%1", operands);
3113
        }
3114
      else if (H_REG_P (operands[1]))
3115
        {
3116
          if (SP_REG_P (operands[1]))
3117
            output_asm_insn ("sts\t%0", operands);
3118
          else
3119
            output_asm_insn ("st%1\t%0", operands);
3120
        }
3121
 
3122
      /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3123
         instruction.  We have to use a scratch register as temporary location.
3124
         Trying to use a specific pattern or constrain failed.  */
3125
      else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3126
        {
3127
          rtx ops[4];
3128
 
3129
          ops[0] = to;
3130
          ops[2] = from;
3131
          ops[3] = 0;
3132
          if (dead_register_here (insn, d_reg))
3133
            ops[1] = d_reg;
3134
          else if (dead_register_here (insn, ix_reg))
3135
            ops[1] = ix_reg;
3136
          else if (dead_register_here (insn, iy_reg))
3137
            ops[1] = iy_reg;
3138
          else
3139
            {
3140
              ops[1] = d_reg;
3141
              ops[3] = d_reg;
3142
              output_asm_insn ("psh%3", ops);
3143
            }
3144
 
3145
          ops[0] = to;
3146
          ops[2] = from;
3147
          output_asm_insn ("ld%1\t%2", ops);
3148
          output_asm_insn ("st%1\t%0", ops);
3149
          if (ops[3])
3150
            output_asm_insn ("pul%3", ops);
3151
        }
3152
 
3153
      /* Use movw for non-null constants or when we are clearing
3154
         a volatile memory reference.  However, this is possible
3155
         only if the memory reference has a small offset or is an
3156
         absolute address.  */
3157
      else if (GET_CODE (from) == CONST_INT
3158
               && INTVAL (from) == 0
3159
               && (MEM_VOLATILE_P (to) == 0
3160
                   || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3161
        {
3162
          output_asm_insn ("clr\t%h0", operands);
3163
          output_asm_insn ("clr\t%b0", operands);
3164
        }
3165
      else
3166
        {
3167
          if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3168
               && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3169
              || (m68hc11_register_indirect_p (to, GET_MODE (to))
3170
                  && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3171
            {
3172
              rtx ops[3];
3173
 
3174
              if (operands[2])
3175
                {
3176
                  ops[0] = operands[2];
3177
                  ops[1] = from;
3178
                  ops[2] = 0;
3179
                  m68hc11_gen_movhi (insn, ops);
3180
                  ops[0] = to;
3181
                  ops[1] = operands[2];
3182
                  m68hc11_gen_movhi (insn, ops);
3183
                  return;
3184
                }
3185
              else
3186
                {
3187
                  /* !!!! SCz wrong here.  */
3188
                  fatal_insn ("move insn not handled", insn);
3189
                }
3190
            }
3191
          else
3192
            {
3193
              m68hc11_notice_keep_cc (operands[0]);
3194
              output_asm_insn ("movw\t%1,%0", operands);
3195
            }
3196
        }
3197
      return;
3198
    }
3199
 
3200
  if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3201
    {
3202
      cc_status = cc_prev_status;
3203
      switch (REGNO (operands[0]))
3204
        {
3205
        case HARD_X_REGNUM:
3206
        case HARD_Y_REGNUM:
3207
          output_asm_insn ("pul%0", operands);
3208
          break;
3209
        case HARD_D_REGNUM:
3210
          output_asm_insn ("pula", operands);
3211
          output_asm_insn ("pulb", operands);
3212
          break;
3213
        default:
3214
          gcc_unreachable ();
3215
        }
3216
      return;
3217
    }
3218
  /* Some moves to a hard register are special. Not all of them
3219
     are really supported and we have to use a temporary
3220
     location to provide them (either the stack of a temp var).  */
3221
  if (H_REG_P (operands[0]))
3222
    {
3223
      switch (REGNO (operands[0]))
3224
        {
3225
        case HARD_D_REGNUM:
3226
          if (X_REG_P (operands[1]))
3227
            {
3228
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3229
                {
3230
                  m68hc11_output_swap (insn, operands);
3231
                }
3232
              else if (next_insn_test_reg (insn, operands[0]))
3233
                {
3234
                  output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3235
                }
3236
              else
3237
                {
3238
                  m68hc11_notice_keep_cc (operands[0]);
3239
                  output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3240
                }
3241
            }
3242
          else if (Y_REG_P (operands[1]))
3243
            {
3244
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3245
                {
3246
                  m68hc11_output_swap (insn, operands);
3247
                }
3248
              else
3249
                {
3250
                  /* %t means *ZTMP scratch register.  */
3251
                  output_asm_insn ("sty\t%t1", operands);
3252
                  output_asm_insn ("ldd\t%t1", operands);
3253
                }
3254
            }
3255
          else if (SP_REG_P (operands[1]))
3256
            {
3257
              CC_STATUS_INIT;
3258
              if (ix_reg == 0)
3259
                create_regs_rtx ();
3260
              if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3261
                output_asm_insn ("xgdx", operands);
3262
              output_asm_insn ("tsx", operands);
3263
              output_asm_insn ("xgdx", operands);
3264
            }
3265
          else if (IS_STACK_POP (operands[1]))
3266
            {
3267
              output_asm_insn ("pula\n\tpulb", operands);
3268
            }
3269
          else if (GET_CODE (operands[1]) == CONST_INT
3270
                   && INTVAL (operands[1]) == 0)
3271
            {
3272
              output_asm_insn ("clra\n\tclrb", operands);
3273
            }
3274
          else
3275
            {
3276
              output_asm_insn ("ldd\t%1", operands);
3277
            }
3278
          break;
3279
 
3280
        case HARD_X_REGNUM:
3281
          if (D_REG_P (operands[1]))
3282
            {
3283
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3284
                {
3285
                  m68hc11_output_swap (insn, operands);
3286
                }
3287
              else if (next_insn_test_reg (insn, operands[0]))
3288
                {
3289
                  output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3290
                }
3291
              else
3292
                {
3293
                  m68hc11_notice_keep_cc (operands[0]);
3294
                  output_asm_insn ("pshb", operands);
3295
                  output_asm_insn ("psha", operands);
3296
                  output_asm_insn ("pulx", operands);
3297
                }
3298
            }
3299
          else if (Y_REG_P (operands[1]))
3300
            {
3301
              /* When both D and Y are dead, use the sequence xgdy, xgdx
3302
                 to move Y into X.  The D and Y registers are modified.  */
3303
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3304
                  && dead_register_here (insn, d_reg))
3305
                {
3306
                  output_asm_insn ("xgdy", operands);
3307
                  output_asm_insn ("xgdx", operands);
3308
                  CC_STATUS_INIT;
3309
                }
3310
              else if (!optimize_size)
3311
                {
3312
                  output_asm_insn ("sty\t%t1", operands);
3313
                  output_asm_insn ("ldx\t%t1", operands);
3314
                }
3315
              else
3316
                {
3317
                  CC_STATUS_INIT;
3318
                  output_asm_insn ("pshy", operands);
3319
                  output_asm_insn ("pulx", operands);
3320
                }
3321
            }
3322
          else if (SP_REG_P (operands[1]))
3323
            {
3324
              /* tsx, tsy preserve the flags */
3325
              cc_status = cc_prev_status;
3326
              output_asm_insn ("tsx", operands);
3327
            }
3328
          else
3329
            {
3330
              output_asm_insn ("ldx\t%1", operands);
3331
            }
3332
          break;
3333
 
3334
        case HARD_Y_REGNUM:
3335
          if (D_REG_P (operands[1]))
3336
            {
3337
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3338
                {
3339
                  m68hc11_output_swap (insn, operands);
3340
                }
3341
              else
3342
                {
3343
                  output_asm_insn ("std\t%t1", operands);
3344
                  output_asm_insn ("ldy\t%t1", operands);
3345
                }
3346
            }
3347
          else if (X_REG_P (operands[1]))
3348
            {
3349
              /* When both D and X are dead, use the sequence xgdx, xgdy
3350
                 to move X into Y.  The D and X registers are modified.  */
3351
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3352
                  && dead_register_here (insn, d_reg))
3353
                {
3354
                  output_asm_insn ("xgdx", operands);
3355
                  output_asm_insn ("xgdy", operands);
3356
                  CC_STATUS_INIT;
3357
                }
3358
              else if (!optimize_size)
3359
                {
3360
                  output_asm_insn ("stx\t%t1", operands);
3361
                  output_asm_insn ("ldy\t%t1", operands);
3362
                }
3363
              else
3364
                {
3365
                  CC_STATUS_INIT;
3366
                  output_asm_insn ("pshx", operands);
3367
                  output_asm_insn ("puly", operands);
3368
                }
3369
            }
3370
          else if (SP_REG_P (operands[1]))
3371
            {
3372
              /* tsx, tsy preserve the flags */
3373
              cc_status = cc_prev_status;
3374
              output_asm_insn ("tsy", operands);
3375
            }
3376
          else
3377
            {
3378
              output_asm_insn ("ldy\t%1", operands);
3379
            }
3380
          break;
3381
 
3382
        case HARD_SP_REGNUM:
3383
          if (D_REG_P (operands[1]))
3384
            {
3385
              m68hc11_notice_keep_cc (operands[0]);
3386
              output_asm_insn ("xgdx", operands);
3387
              output_asm_insn ("txs", operands);
3388
              output_asm_insn ("xgdx", operands);
3389
            }
3390
          else if (X_REG_P (operands[1]))
3391
            {
3392
              /* tys, txs preserve the flags */
3393
              cc_status = cc_prev_status;
3394
              output_asm_insn ("txs", operands);
3395
            }
3396
          else if (Y_REG_P (operands[1]))
3397
            {
3398
              /* tys, txs preserve the flags */
3399
              cc_status = cc_prev_status;
3400
              output_asm_insn ("tys", operands);
3401
            }
3402
          else
3403
            {
3404
              /* lds sets the flags but the des does not.  */
3405
              CC_STATUS_INIT;
3406
              output_asm_insn ("lds\t%1", operands);
3407
              output_asm_insn ("des", operands);
3408
            }
3409
          break;
3410
 
3411
        default:
3412
          fatal_insn ("invalid register in the move instruction", insn);
3413
          break;
3414
        }
3415
      return;
3416
    }
3417
  if (SP_REG_P (operands[1]) && REG_P (operands[0])
3418
      && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3419
    {
3420
      output_asm_insn ("sts\t%0", operands);
3421
      return;
3422
    }
3423
 
3424
  if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3425
    {
3426
      cc_status = cc_prev_status;
3427
      switch (REGNO (operands[1]))
3428
        {
3429
        case HARD_X_REGNUM:
3430
        case HARD_Y_REGNUM:
3431
          output_asm_insn ("psh%1", operands);
3432
          break;
3433
        case HARD_D_REGNUM:
3434
          output_asm_insn ("pshb", operands);
3435
          output_asm_insn ("psha", operands);
3436
          break;
3437
        default:
3438
          gcc_unreachable ();
3439
        }
3440
      return;
3441
    }
3442
 
3443
  /* Operand 1 must be a hard register.  */
3444
  if (!H_REG_P (operands[1]))
3445
    {
3446
      fatal_insn ("invalid operand in the instruction", insn);
3447
    }
3448
 
3449
  reg = REGNO (operands[1]);
3450
  switch (reg)
3451
    {
3452
    case HARD_D_REGNUM:
3453
      output_asm_insn ("std\t%0", operands);
3454
      break;
3455
 
3456
    case HARD_X_REGNUM:
3457
      output_asm_insn ("stx\t%0", operands);
3458
      break;
3459
 
3460
    case HARD_Y_REGNUM:
3461
      output_asm_insn ("sty\t%0", operands);
3462
      break;
3463
 
3464
    case HARD_SP_REGNUM:
3465
      if (ix_reg == 0)
3466
        create_regs_rtx ();
3467
 
3468
      if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3469
        {
3470
          output_asm_insn ("pshx", operands);
3471
          output_asm_insn ("tsx", operands);
3472
          output_asm_insn ("inx", operands);
3473
          output_asm_insn ("inx", operands);
3474
          output_asm_insn ("stx\t%0", operands);
3475
          output_asm_insn ("pulx", operands);
3476
        }
3477
 
3478
      else if (reg_mentioned_p (ix_reg, operands[0]))
3479
        {
3480
          output_asm_insn ("sty\t%t0", operands);
3481
          output_asm_insn ("tsy", operands);
3482
          output_asm_insn ("sty\t%0", operands);
3483
          output_asm_insn ("ldy\t%t0", operands);
3484
        }
3485
      else
3486
        {
3487
          output_asm_insn ("stx\t%t0", operands);
3488
          output_asm_insn ("tsx", operands);
3489
          output_asm_insn ("stx\t%0", operands);
3490
          output_asm_insn ("ldx\t%t0", operands);
3491
        }
3492
      CC_STATUS_INIT;
3493
      break;
3494
 
3495
    default:
3496
      fatal_insn ("invalid register in the move instruction", insn);
3497
      break;
3498
    }
3499
}
3500
 
3501
void
3502
m68hc11_gen_movqi (rtx insn, rtx *operands)
3503
{
3504
  /* Move a register or memory to the same location.
3505
     This is possible because such insn can appear
3506
     in a non-optimizing mode.  */
3507
  if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3508
    {
3509
      cc_status = cc_prev_status;
3510
      return;
3511
    }
3512
 
3513
  if (TARGET_M6812)
3514
    {
3515
 
3516
      if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3517
        {
3518
          m68hc11_notice_keep_cc (operands[0]);
3519
          output_asm_insn ("tfr\t%1,%0", operands);
3520
        }
3521
      else if (H_REG_P (operands[0]))
3522
        {
3523
          if (IS_STACK_POP (operands[1]))
3524
            output_asm_insn ("pul%b0", operands);
3525
          else if (Q_REG_P (operands[0]))
3526
            output_asm_insn ("lda%0\t%b1", operands);
3527
          else if (D_REG_P (operands[0]))
3528
            output_asm_insn ("ldab\t%b1", operands);
3529
          else
3530
            goto m6811_move;
3531
        }
3532
      else if (H_REG_P (operands[1]))
3533
        {
3534
          if (Q_REG_P (operands[1]))
3535
            output_asm_insn ("sta%1\t%b0", operands);
3536
          else if (D_REG_P (operands[1]))
3537
            output_asm_insn ("stab\t%b0", operands);
3538
          else
3539
            goto m6811_move;
3540
        }
3541
      else
3542
        {
3543
          rtx from = operands[1];
3544
          rtx to = operands[0];
3545
 
3546
          if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3547
               && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3548
              || (m68hc11_register_indirect_p (to, GET_MODE (to))
3549
                  && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3550
            {
3551
              rtx ops[3];
3552
 
3553
              if (operands[2])
3554
                {
3555
                  ops[0] = operands[2];
3556
                  ops[1] = from;
3557
                  ops[2] = 0;
3558
                  m68hc11_gen_movqi (insn, ops);
3559
                  ops[0] = to;
3560
                  ops[1] = operands[2];
3561
                  m68hc11_gen_movqi (insn, ops);
3562
                }
3563
              else
3564
                {
3565
                  /* !!!! SCz wrong here.  */
3566
                  fatal_insn ("move insn not handled", insn);
3567
                }
3568
            }
3569
          else
3570
            {
3571
              if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3572
                {
3573
                  output_asm_insn ("clr\t%b0", operands);
3574
                }
3575
              else
3576
                {
3577
                  m68hc11_notice_keep_cc (operands[0]);
3578
                  output_asm_insn ("movb\t%b1,%b0", operands);
3579
                }
3580
            }
3581
        }
3582
      return;
3583
    }
3584
 
3585
 m6811_move:
3586
  if (H_REG_P (operands[0]))
3587
    {
3588
      switch (REGNO (operands[0]))
3589
        {
3590
        case HARD_B_REGNUM:
3591
        case HARD_D_REGNUM:
3592
          if (X_REG_P (operands[1]))
3593
            {
3594
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3595
                {
3596
                  m68hc11_output_swap (insn, operands);
3597
                }
3598
              else
3599
                {
3600
                  output_asm_insn ("stx\t%t1", operands);
3601
                  output_asm_insn ("ldab\t%T0", operands);
3602
                }
3603
            }
3604
          else if (Y_REG_P (operands[1]))
3605
            {
3606
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3607
                {
3608
                  m68hc11_output_swap (insn, operands);
3609
                }
3610
              else
3611
                {
3612
                  output_asm_insn ("sty\t%t1", operands);
3613
                  output_asm_insn ("ldab\t%T0", operands);
3614
                }
3615
            }
3616
          else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3617
                   && !DA_REG_P (operands[1]))
3618
            {
3619
              output_asm_insn ("ldab\t%b1", operands);
3620
            }
3621
          else if (DA_REG_P (operands[1]))
3622
            {
3623
              output_asm_insn ("tab", operands);
3624
            }
3625
          else
3626
            {
3627
              cc_status = cc_prev_status;
3628
              return;
3629
            }
3630
          break;
3631
 
3632
        case HARD_A_REGNUM:
3633
          if (X_REG_P (operands[1]))
3634
            {
3635
              output_asm_insn ("stx\t%t1", operands);
3636
              output_asm_insn ("ldaa\t%T0", operands);
3637
            }
3638
          else if (Y_REG_P (operands[1]))
3639
            {
3640
              output_asm_insn ("sty\t%t1", operands);
3641
              output_asm_insn ("ldaa\t%T0", operands);
3642
            }
3643
          else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3644
                   && !DA_REG_P (operands[1]))
3645
            {
3646
              output_asm_insn ("ldaa\t%b1", operands);
3647
            }
3648
          else if (!DA_REG_P (operands[1]))
3649
            {
3650
              output_asm_insn ("tba", operands);
3651
            }
3652
          else
3653
            {
3654
              cc_status = cc_prev_status;
3655
            }
3656
          break;
3657
 
3658
        case HARD_X_REGNUM:
3659
          if (D_REG_P (operands[1]))
3660
            {
3661
              if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3662
                {
3663
                  m68hc11_output_swap (insn, operands);
3664
                }
3665
              else
3666
                {
3667
                  output_asm_insn ("stab\t%T1", operands);
3668
                  output_asm_insn ("ldx\t%t1", operands);
3669
                }
3670
              CC_STATUS_INIT;
3671
            }
3672
          else if (Y_REG_P (operands[1]))
3673
            {
3674
              output_asm_insn ("sty\t%t0", operands);
3675
              output_asm_insn ("ldx\t%t0", operands);
3676
            }
3677
          else if (GET_CODE (operands[1]) == CONST_INT)
3678
            {
3679
              output_asm_insn ("ldx\t%1", operands);
3680
            }
3681
          else if (dead_register_here (insn, d_reg))
3682
            {
3683
              output_asm_insn ("ldab\t%b1", operands);
3684
              output_asm_insn ("xgdx", operands);
3685
            }
3686
          else if (!reg_mentioned_p (operands[0], operands[1]))
3687
            {
3688
              output_asm_insn ("xgdx", operands);
3689
              output_asm_insn ("ldab\t%b1", operands);
3690
              output_asm_insn ("xgdx", operands);
3691
            }
3692
          else
3693
            {
3694
              output_asm_insn ("pshb", operands);
3695
              output_asm_insn ("ldab\t%b1", operands);
3696
              output_asm_insn ("stab\t%T1", operands);
3697
              output_asm_insn ("ldx\t%t1", operands);
3698
              output_asm_insn ("pulb", operands);
3699
              CC_STATUS_INIT;
3700
            }
3701
          break;
3702
 
3703
        case HARD_Y_REGNUM:
3704
          if (D_REG_P (operands[1]))
3705
            {
3706
              output_asm_insn ("stab\t%T1", operands);
3707
              output_asm_insn ("ldy\t%t1", operands);
3708
              CC_STATUS_INIT;
3709
            }
3710
          else if (X_REG_P (operands[1]))
3711
            {
3712
              output_asm_insn ("stx\t%t1", operands);
3713
              output_asm_insn ("ldy\t%t1", operands);
3714
              CC_STATUS_INIT;
3715
            }
3716
          else if (GET_CODE (operands[1]) == CONST_INT)
3717
            {
3718
              output_asm_insn ("ldy\t%1", operands);
3719
            }
3720
          else if (dead_register_here (insn, d_reg))
3721
            {
3722
              output_asm_insn ("ldab\t%b1", operands);
3723
              output_asm_insn ("xgdy", operands);
3724
            }
3725
          else if (!reg_mentioned_p (operands[0], operands[1]))
3726
            {
3727
              output_asm_insn ("xgdy", operands);
3728
              output_asm_insn ("ldab\t%b1", operands);
3729
              output_asm_insn ("xgdy", operands);
3730
            }
3731
          else
3732
            {
3733
              output_asm_insn ("pshb", operands);
3734
              output_asm_insn ("ldab\t%b1", operands);
3735
              output_asm_insn ("stab\t%T1", operands);
3736
              output_asm_insn ("ldy\t%t1", operands);
3737
              output_asm_insn ("pulb", operands);
3738
              CC_STATUS_INIT;
3739
            }
3740
          break;
3741
 
3742
        default:
3743
          fatal_insn ("invalid register in the instruction", insn);
3744
          break;
3745
        }
3746
    }
3747
  else if (H_REG_P (operands[1]))
3748
    {
3749
      switch (REGNO (operands[1]))
3750
        {
3751
        case HARD_D_REGNUM:
3752
        case HARD_B_REGNUM:
3753
          output_asm_insn ("stab\t%b0", operands);
3754
          break;
3755
 
3756
        case HARD_A_REGNUM:
3757
          output_asm_insn ("staa\t%b0", operands);
3758
          break;
3759
 
3760
        case HARD_X_REGNUM:
3761
          output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3762
          break;
3763
 
3764
        case HARD_Y_REGNUM:
3765
          output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3766
          break;
3767
 
3768
        default:
3769
          fatal_insn ("invalid register in the move instruction", insn);
3770
          break;
3771
        }
3772
      return;
3773
    }
3774
  else
3775
    {
3776
      fatal_insn ("operand 1 must be a hard register", insn);
3777
    }
3778
}
3779
 
3780
/* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3781
   The source and destination must be D or A and the shift must
3782
   be a constant.  */
3783
void
3784
m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3785
{
3786
  int val;
3787
 
3788
  if (GET_CODE (operands[2]) != CONST_INT
3789
      || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3790
    fatal_insn ("invalid rotate insn", insn);
3791
 
3792
  val = INTVAL (operands[2]);
3793
  if (code == ROTATERT)
3794
    val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3795
 
3796
  if (GET_MODE (operands[0]) != QImode)
3797
    CC_STATUS_INIT;
3798
 
3799
  /* Rotate by 8-bits if the shift is within [5..11].  */
3800
  if (val >= 5 && val <= 11)
3801
    {
3802
      if (TARGET_M6812)
3803
        output_asm_insn ("exg\ta,b", operands);
3804
      else
3805
        {
3806
          output_asm_insn ("psha", operands);
3807
          output_asm_insn ("tba", operands);
3808
          output_asm_insn ("pulb", operands);
3809
        }
3810
      val -= 8;
3811
    }
3812
 
3813
  /* If the shift is big, invert the rotation.  */
3814
  else if (val >= 12)
3815
    {
3816
      val = val - 16;
3817
    }
3818
 
3819
  if (val > 0)
3820
    {
3821
      while (--val >= 0)
3822
        {
3823
          /* Set the carry to bit-15, but don't change D yet.  */
3824
          if (GET_MODE (operands[0]) != QImode)
3825
            {
3826
              output_asm_insn ("asra", operands);
3827
              output_asm_insn ("rola", operands);
3828
            }
3829
 
3830
          /* Rotate B first to move the carry to bit-0.  */
3831
          if (D_REG_P (operands[0]))
3832
            output_asm_insn ("rolb", operands);
3833
 
3834
          if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3835
            output_asm_insn ("rola", operands);
3836
        }
3837
    }
3838
  else
3839
    {
3840
      while (++val <= 0)
3841
        {
3842
          /* Set the carry to bit-8 of D.  */
3843
          if (GET_MODE (operands[0]) != QImode)
3844
            output_asm_insn ("tap", operands);
3845
 
3846
          /* Rotate B first to move the carry to bit-7.  */
3847
          if (D_REG_P (operands[0]))
3848
            output_asm_insn ("rorb", operands);
3849
 
3850
          if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3851
            output_asm_insn ("rora", operands);
3852
        }
3853
    }
3854
}
3855
 
3856
 
3857
 
3858
/* Store in cc_status the expressions that the condition codes will
3859
   describe after execution of an instruction whose pattern is EXP.
3860
   Do not alter them if the instruction would not alter the cc's.  */
3861
 
3862
void
3863
m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3864
{
3865
  /* recognize SET insn's.  */
3866
  if (GET_CODE (exp) == SET)
3867
    {
3868
      /* Jumps do not alter the cc's.  */
3869
      if (SET_DEST (exp) == pc_rtx)
3870
        ;
3871
 
3872
      /* NOTE: most instructions don't affect the carry bit, but the
3873
         bhi/bls/bhs/blo instructions use it.  This isn't mentioned in
3874
         the conditions.h header.  */
3875
 
3876
      /* Function calls clobber the cc's.  */
3877
      else if (GET_CODE (SET_SRC (exp)) == CALL)
3878
        {
3879
          CC_STATUS_INIT;
3880
        }
3881
 
3882
      /* Tests and compares set the cc's in predictable ways.  */
3883
      else if (SET_DEST (exp) == cc0_rtx)
3884
        {
3885
          cc_status.flags = 0;
3886
          cc_status.value1 = XEXP (exp, 0);
3887
          cc_status.value2 = XEXP (exp, 1);
3888
        }
3889
      else
3890
        {
3891
          /* All other instructions affect the condition codes.  */
3892
          cc_status.flags = 0;
3893
          cc_status.value1 = XEXP (exp, 0);
3894
          cc_status.value2 = XEXP (exp, 1);
3895
        }
3896
    }
3897
  else
3898
    {
3899
      /* Default action if we haven't recognized something
3900
         and returned earlier.  */
3901
      CC_STATUS_INIT;
3902
    }
3903
 
3904
  if (cc_status.value2 != 0)
3905
    switch (GET_CODE (cc_status.value2))
3906
      {
3907
        /* These logical operations can generate several insns.
3908
           The flags are setup according to what is generated.  */
3909
      case IOR:
3910
      case XOR:
3911
      case AND:
3912
        break;
3913
 
3914
        /* The (not ...) generates several 'com' instructions for
3915
           non QImode.  We have to invalidate the flags.  */
3916
      case NOT:
3917
        if (GET_MODE (cc_status.value2) != QImode)
3918
          CC_STATUS_INIT;
3919
        break;
3920
 
3921
      case PLUS:
3922
      case MINUS:
3923
      case MULT:
3924
      case DIV:
3925
      case UDIV:
3926
      case MOD:
3927
      case UMOD:
3928
      case NEG:
3929
        if (GET_MODE (cc_status.value2) != VOIDmode)
3930
          cc_status.flags |= CC_NO_OVERFLOW;
3931
        break;
3932
 
3933
        /* The asl sets the overflow bit in such a way that this
3934
           makes the flags unusable for a next compare insn.  */
3935
      case ASHIFT:
3936
      case ROTATE:
3937
      case ROTATERT:
3938
        if (GET_MODE (cc_status.value2) != VOIDmode)
3939
          cc_status.flags |= CC_NO_OVERFLOW;
3940
        break;
3941
 
3942
        /* A load/store instruction does not affect the carry.  */
3943
      case MEM:
3944
      case SYMBOL_REF:
3945
      case REG:
3946
      case CONST_INT:
3947
        cc_status.flags |= CC_NO_OVERFLOW;
3948
        break;
3949
 
3950
      default:
3951
        break;
3952
      }
3953
  if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3954
      && cc_status.value2
3955
      && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3956
    cc_status.value2 = 0;
3957
 
3958
  else if (cc_status.value1 && side_effects_p (cc_status.value1))
3959
    cc_status.value1 = 0;
3960
 
3961
  else if (cc_status.value2 && side_effects_p (cc_status.value2))
3962
    cc_status.value2 = 0;
3963
}
3964
 
3965
/* The current instruction does not affect the flags but changes
3966
   the register 'reg'.  See if the previous flags can be kept for the
3967
   next instruction to avoid a comparison.  */
3968
void
3969
m68hc11_notice_keep_cc (rtx reg)
3970
{
3971
  if (reg == 0
3972
      || cc_prev_status.value1 == 0
3973
      || rtx_equal_p (reg, cc_prev_status.value1)
3974
      || (cc_prev_status.value2
3975
          && reg_mentioned_p (reg, cc_prev_status.value2)))
3976
    CC_STATUS_INIT;
3977
  else
3978
    cc_status = cc_prev_status;
3979
}
3980
 
3981
 
3982
 
3983
/* Machine Specific Reorg.  */
3984
 
3985
/* Z register replacement:
3986
 
3987
   GCC treats the Z register as an index base address register like
3988
   X or Y.  In general, it uses it during reload to compute the address
3989
   of some operand.  This helps the reload pass to avoid to fall into the
3990
   register spill failure.
3991
 
3992
   The Z register is in the A_REGS class.  In the machine description,
3993
   the 'A' constraint matches it.  The 'x' or 'y' constraints do not.
3994
 
3995
   It can appear everywhere an X or Y register can appear, except for
3996
   some templates in the clobber section (when a clobber of X or Y is asked).
3997
   For a given instruction, the template must ensure that no more than
3998
   2 'A' registers are used.  Otherwise, the register replacement is not
3999
   possible.
4000
 
4001
   To replace the Z register, the algorithm is not terrific:
4002
   1. Insns that do not use the Z register are not changed
4003
   2. When a Z register is used, we scan forward the insns to see
4004
   a potential register to use: either X or Y and sometimes D.
4005
   We stop when a call, a label or a branch is seen, or when we
4006
   detect that both X and Y are used (probably at different times, but it does
4007
   not matter).
4008
   3. The register that will be used for the replacement of Z is saved
4009
   in a .page0 register or on the stack.  If the first instruction that
4010
   used Z, uses Z as an input, the value is loaded from another .page0
4011
   register.  The replacement register is pushed on the stack in the
4012
   rare cases where a compare insn uses Z and we couldn't find if X/Y
4013
   are dead.
4014
   4. The Z register is replaced in all instructions until we reach
4015
   the end of the Z-block, as detected by step 2.
4016
   5. If we detect that Z is still alive, its value is saved.
4017
   If the replacement register is alive, its old value is loaded.
4018
 
4019
   The Z register can be disabled with -ffixed-z.
4020
*/
4021
 
4022
struct replace_info
4023
{
4024
  rtx first;
4025
  rtx replace_reg;
4026
  int need_save_z;
4027
  int must_load_z;
4028
  int must_save_reg;
4029
  int must_restore_reg;
4030
  rtx last;
4031
  int regno;
4032
  int x_used;
4033
  int y_used;
4034
  int can_use_d;
4035
  int found_call;
4036
  int z_died;
4037
  int z_set_count;
4038
  rtx z_value;
4039
  int must_push_reg;
4040
  int save_before_last;
4041
  int z_loaded_with_sp;
4042
};
4043
 
4044
static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4045
static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4046
static void m68hc11_z_replacement (rtx);
4047
static void m68hc11_reassign_regs (rtx);
4048
 
4049
int z_replacement_completed = 0;
4050
 
4051
/* Analyze the insn to find out which replacement register to use and
4052
   the boundaries of the replacement.
4053
   Returns 0 if we reached the last insn to be replaced, 1 if we can
4054
   continue replacement in next insns.  */
4055
 
4056
static int
4057
m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4058
{
4059
  int this_insn_uses_ix;
4060
  int this_insn_uses_iy;
4061
  int this_insn_uses_z;
4062
  int this_insn_uses_z_in_dst;
4063
  int this_insn_uses_d;
4064
  rtx body;
4065
  int z_dies_here;
4066
 
4067
  /* A call is said to clobber the Z register, we don't need
4068
     to save the value of Z.  We also don't need to restore
4069
     the replacement register (unless it is used by the call).  */
4070
  if (GET_CODE (insn) == CALL_INSN)
4071
    {
4072
      body = PATTERN (insn);
4073
 
4074
      info->can_use_d = 0;
4075
 
4076
      /* If the call is an indirect call with Z, we have to use the
4077
         Y register because X can be used as an input (D+X).
4078
         We also must not save Z nor restore Y.  */
4079
      if (reg_mentioned_p (z_reg, body))
4080
        {
4081
          insn = NEXT_INSN (insn);
4082
          info->x_used = 1;
4083
          info->y_used = 0;
4084
          info->found_call = 1;
4085
          info->must_restore_reg = 0;
4086
          info->last = NEXT_INSN (insn);
4087
        }
4088
      info->need_save_z = 0;
4089
      return 0;
4090
    }
4091
  if (GET_CODE (insn) == CODE_LABEL
4092
      || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4093
    return 0;
4094
 
4095
  if (GET_CODE (insn) == JUMP_INSN)
4096
    {
4097
      if (reg_mentioned_p (z_reg, insn) == 0)
4098
        return 0;
4099
 
4100
      info->can_use_d = 0;
4101
      info->must_save_reg = 0;
4102
      info->must_restore_reg = 0;
4103
      info->need_save_z = 0;
4104
      info->last = NEXT_INSN (insn);
4105
      return 0;
4106
    }
4107
  if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4108
    {
4109
      return 1;
4110
    }
4111
 
4112
  /* Z register dies here.  */
4113
  z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4114
 
4115
  body = PATTERN (insn);
4116
  if (GET_CODE (body) == SET)
4117
    {
4118
      rtx src = XEXP (body, 1);
4119
      rtx dst = XEXP (body, 0);
4120
 
4121
      /* Condition code is set here. We have to restore the X/Y and
4122
         save into Z before any test/compare insn because once we save/restore
4123
         we can change the condition codes. When the compare insn uses Z and
4124
         we can't use X/Y, the comparison is made with the *ZREG soft register
4125
         (this is supported by cmphi, cmpqi, tsthi, tstqi patterns).  */
4126
      if (dst == cc0_rtx)
4127
        {
4128
          if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4129
              || (GET_CODE (src) == COMPARE &&
4130
                  ((rtx_equal_p (XEXP (src, 0), z_reg)
4131
                    && H_REG_P (XEXP (src, 1)))
4132
                   || (rtx_equal_p (XEXP (src, 1), z_reg)
4133
                       && H_REG_P (XEXP (src, 0))))))
4134
            {
4135
              if (insn == info->first)
4136
                {
4137
                  info->must_load_z = 0;
4138
                  info->must_save_reg = 0;
4139
                  info->must_restore_reg = 0;
4140
                  info->need_save_z = 0;
4141
                  info->found_call = 1;
4142
                  info->regno = SOFT_Z_REGNUM;
4143
                  info->last = NEXT_INSN (insn);
4144
                }
4145
              return 0;
4146
            }
4147
          if (reg_mentioned_p (z_reg, src) == 0)
4148
            {
4149
              info->can_use_d = 0;
4150
              return 0;
4151
            }
4152
 
4153
          if (insn != info->first)
4154
            return 0;
4155
 
4156
          /* Compare insn which uses Z.  We have to save/restore the X/Y
4157
             register without modifying the condition codes.  For this
4158
             we have to use a push/pop insn.  */
4159
          info->must_push_reg = 1;
4160
          info->last = insn;
4161
        }
4162
 
4163
      /* Z reg is set to something new. We don't need to load it.  */
4164
      if (Z_REG_P (dst))
4165
        {
4166
          if (!reg_mentioned_p (z_reg, src))
4167
            {
4168
              /* Z reg is used before being set.  Treat this as
4169
                 a new sequence of Z register replacement.  */
4170
              if (insn != info->first)
4171
                {
4172
                  return 0;
4173
                }
4174
              info->must_load_z = 0;
4175
            }
4176
          info->z_set_count++;
4177
          info->z_value = src;
4178
          if (SP_REG_P (src))
4179
            info->z_loaded_with_sp = 1;
4180
        }
4181
      else if (reg_mentioned_p (z_reg, dst))
4182
        info->can_use_d = 0;
4183
 
4184
      this_insn_uses_d = reg_mentioned_p (d_reg, src)
4185
        | reg_mentioned_p (d_reg, dst);
4186
      this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4187
        | reg_mentioned_p (ix_reg, dst);
4188
      this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4189
        | reg_mentioned_p (iy_reg, dst);
4190
      this_insn_uses_z = reg_mentioned_p (z_reg, src);
4191
 
4192
      /* If z is used as an address operand (like (MEM (reg z))),
4193
         we can't replace it with d.  */
4194
      if (this_insn_uses_z && !Z_REG_P (src)
4195
          && !(m68hc11_arith_operator (src, GET_MODE (src))
4196
               && Z_REG_P (XEXP (src, 0))
4197
               && !reg_mentioned_p (z_reg, XEXP (src, 1))
4198
               && insn == info->first
4199
               && dead_register_here (insn, d_reg)))
4200
        info->can_use_d = 0;
4201
 
4202
      this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4203
      if (TARGET_M6812 && !z_dies_here
4204
          && ((this_insn_uses_z && side_effects_p (src))
4205
              || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4206
        {
4207
          info->need_save_z = 1;
4208
          info->z_set_count++;
4209
        }
4210
      this_insn_uses_z |= this_insn_uses_z_in_dst;
4211
 
4212
      if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4213
        {
4214
          fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4215
        }
4216
 
4217
      if (this_insn_uses_d)
4218
        info->can_use_d = 0;
4219
 
4220
      /* IX and IY are used at the same time, we have to restore
4221
         the value of the scratch register before this insn.  */
4222
      if (this_insn_uses_ix && this_insn_uses_iy)
4223
        {
4224
          return 0;
4225
        }
4226
 
4227
      if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4228
        info->can_use_d = 0;
4229
 
4230
      if (info->x_used == 0 && this_insn_uses_ix)
4231
        {
4232
          if (info->y_used)
4233
            {
4234
              /* We have a (set (REG:HI X) (REG:HI Z)).
4235
                 Since we use Z as the replacement register, this insn
4236
                 is no longer necessary.  We turn it into a note.  We must
4237
                 not reload the old value of X.  */
4238
              if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4239
                {
4240
                  if (z_dies_here)
4241
                    {
4242
                      info->need_save_z = 0;
4243
                      info->z_died = 1;
4244
                    }
4245
                  info->must_save_reg = 0;
4246
                  info->must_restore_reg = 0;
4247
                  info->found_call = 1;
4248
                  info->can_use_d = 0;
4249
                  PUT_CODE (insn, NOTE);
4250
                  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4251
                  NOTE_SOURCE_FILE (insn) = 0;
4252
                  info->last = NEXT_INSN (insn);
4253
                  return 0;
4254
                }
4255
 
4256
              if (X_REG_P (dst)
4257
                  && (rtx_equal_p (src, z_reg)
4258
                      || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4259
                {
4260
                  if (z_dies_here)
4261
                    {
4262
                      info->need_save_z = 0;
4263
                      info->z_died = 1;
4264
                    }
4265
                  info->last = NEXT_INSN (insn);
4266
                  info->must_save_reg = 0;
4267
                  info->must_restore_reg = 0;
4268
                }
4269
              else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4270
                       && !reg_mentioned_p (ix_reg, src))
4271
                {
4272
                  if (z_dies_here)
4273
                    {
4274
                      info->z_died = 1;
4275
                      info->need_save_z = 0;
4276
                    }
4277
                  else if (TARGET_M6812 && side_effects_p (src))
4278
                    {
4279
                      info->last = 0;
4280
                      info->must_restore_reg = 0;
4281
                      return 0;
4282
                    }
4283
                  else
4284
                    {
4285
                      info->save_before_last = 1;
4286
                    }
4287
                  info->must_restore_reg = 0;
4288
                  info->last = NEXT_INSN (insn);
4289
                }
4290
              else if (info->can_use_d)
4291
                {
4292
                  info->last = NEXT_INSN (insn);
4293
                  info->x_used = 1;
4294
                }
4295
              return 0;
4296
            }
4297
          info->x_used = 1;
4298
          if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4299
              && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4300
            {
4301
              info->need_save_z = 0;
4302
              info->z_died = 1;
4303
              info->last = NEXT_INSN (insn);
4304
              info->regno = HARD_X_REGNUM;
4305
              info->must_save_reg = 0;
4306
              info->must_restore_reg = 0;
4307
              return 0;
4308
            }
4309
          if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4310
            {
4311
              info->regno = HARD_X_REGNUM;
4312
              info->must_restore_reg = 0;
4313
              info->must_save_reg = 0;
4314
              return 0;
4315
            }
4316
        }
4317
      if (info->y_used == 0 && this_insn_uses_iy)
4318
        {
4319
          if (info->x_used)
4320
            {
4321
              if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4322
                {
4323
                  if (z_dies_here)
4324
                    {
4325
                      info->need_save_z = 0;
4326
                      info->z_died = 1;
4327
                    }
4328
                  info->must_save_reg = 0;
4329
                  info->must_restore_reg = 0;
4330
                  info->found_call = 1;
4331
                  info->can_use_d = 0;
4332
                  PUT_CODE (insn, NOTE);
4333
                  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4334
                  NOTE_SOURCE_FILE (insn) = 0;
4335
                  info->last = NEXT_INSN (insn);
4336
                  return 0;
4337
                }
4338
 
4339
              if (Y_REG_P (dst)
4340
                  && (rtx_equal_p (src, z_reg)
4341
                      || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4342
                {
4343
                  if (z_dies_here)
4344
                    {
4345
                      info->z_died = 1;
4346
                      info->need_save_z = 0;
4347
                    }
4348
                  info->last = NEXT_INSN (insn);
4349
                  info->must_save_reg = 0;
4350
                  info->must_restore_reg = 0;
4351
                }
4352
              else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4353
                       && !reg_mentioned_p (iy_reg, src))
4354
                {
4355
                  if (z_dies_here)
4356
                    {
4357
                      info->z_died = 1;
4358
                      info->need_save_z = 0;
4359
                    }
4360
                  else if (TARGET_M6812 && side_effects_p (src))
4361
                    {
4362
                      info->last = 0;
4363
                      info->must_restore_reg = 0;
4364
                      return 0;
4365
                    }
4366
                  else
4367
                    {
4368
                      info->save_before_last = 1;
4369
                    }
4370
                  info->must_restore_reg = 0;
4371
                  info->last = NEXT_INSN (insn);
4372
                }
4373
              else if (info->can_use_d)
4374
                {
4375
                  info->last = NEXT_INSN (insn);
4376
                  info->y_used = 1;
4377
                }
4378
 
4379
              return 0;
4380
            }
4381
          info->y_used = 1;
4382
          if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4383
              && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4384
            {
4385
              info->need_save_z = 0;
4386
              info->z_died = 1;
4387
              info->last = NEXT_INSN (insn);
4388
              info->regno = HARD_Y_REGNUM;
4389
              info->must_save_reg = 0;
4390
              info->must_restore_reg = 0;
4391
              return 0;
4392
            }
4393
          if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4394
            {
4395
              info->regno = HARD_Y_REGNUM;
4396
              info->must_restore_reg = 0;
4397
              info->must_save_reg = 0;
4398
              return 0;
4399
            }
4400
        }
4401
      if (z_dies_here)
4402
        {
4403
          info->need_save_z = 0;
4404
          info->z_died = 1;
4405
          if (info->last == 0)
4406
            info->last = NEXT_INSN (insn);
4407
          return 0;
4408
        }
4409
      return info->last != NULL_RTX ? 0 : 1;
4410
    }
4411
  if (GET_CODE (body) == PARALLEL)
4412
    {
4413
      int i;
4414
      char ix_clobber = 0;
4415
      char iy_clobber = 0;
4416
      char z_clobber = 0;
4417
      this_insn_uses_iy = 0;
4418
      this_insn_uses_ix = 0;
4419
      this_insn_uses_z = 0;
4420
 
4421
      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4422
        {
4423
          rtx x;
4424
          int uses_ix, uses_iy, uses_z;
4425
 
4426
          x = XVECEXP (body, 0, i);
4427
 
4428
          if (info->can_use_d && reg_mentioned_p (d_reg, x))
4429
            info->can_use_d = 0;
4430
 
4431
          uses_ix = reg_mentioned_p (ix_reg, x);
4432
          uses_iy = reg_mentioned_p (iy_reg, x);
4433
          uses_z = reg_mentioned_p (z_reg, x);
4434
          if (GET_CODE (x) == CLOBBER)
4435
            {
4436
              ix_clobber |= uses_ix;
4437
              iy_clobber |= uses_iy;
4438
              z_clobber |= uses_z;
4439
            }
4440
          else
4441
            {
4442
              this_insn_uses_ix |= uses_ix;
4443
              this_insn_uses_iy |= uses_iy;
4444
              this_insn_uses_z |= uses_z;
4445
            }
4446
          if (uses_z && GET_CODE (x) == SET)
4447
            {
4448
              rtx dst = XEXP (x, 0);
4449
 
4450
              if (Z_REG_P (dst))
4451
                info->z_set_count++;
4452
            }
4453
          if (TARGET_M6812 && uses_z && side_effects_p (x))
4454
            info->need_save_z = 1;
4455
 
4456
          if (z_clobber)
4457
            info->need_save_z = 0;
4458
        }
4459
      if (debug_m6811)
4460
        {
4461
          printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4462
                  this_insn_uses_ix, this_insn_uses_iy,
4463
                  this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4464
          debug_rtx (insn);
4465
        }
4466
      if (this_insn_uses_z)
4467
        info->can_use_d = 0;
4468
 
4469
      if (z_clobber && info->first != insn)
4470
        {
4471
          info->need_save_z = 0;
4472
          info->last = insn;
4473
          return 0;
4474
        }
4475
      if (z_clobber && info->x_used == 0 && info->y_used == 0)
4476
        {
4477
          if (this_insn_uses_z == 0 && insn == info->first)
4478
            {
4479
              info->must_load_z = 0;
4480
            }
4481
          if (dead_register_here (insn, d_reg))
4482
            {
4483
              info->regno = HARD_D_REGNUM;
4484
              info->must_save_reg = 0;
4485
              info->must_restore_reg = 0;
4486
            }
4487
          else if (dead_register_here (insn, ix_reg))
4488
            {
4489
              info->regno = HARD_X_REGNUM;
4490
              info->must_save_reg = 0;
4491
              info->must_restore_reg = 0;
4492
            }
4493
          else if (dead_register_here (insn, iy_reg))
4494
            {
4495
              info->regno = HARD_Y_REGNUM;
4496
              info->must_save_reg = 0;
4497
              info->must_restore_reg = 0;
4498
            }
4499
          if (info->regno >= 0)
4500
            {
4501
              info->last = NEXT_INSN (insn);
4502
              return 0;
4503
            }
4504
          if (this_insn_uses_ix == 0)
4505
            {
4506
              info->regno = HARD_X_REGNUM;
4507
              info->must_save_reg = 1;
4508
              info->must_restore_reg = 1;
4509
            }
4510
          else if (this_insn_uses_iy == 0)
4511
            {
4512
              info->regno = HARD_Y_REGNUM;
4513
              info->must_save_reg = 1;
4514
              info->must_restore_reg = 1;
4515
            }
4516
          else
4517
            {
4518
              info->regno = HARD_D_REGNUM;
4519
              info->must_save_reg = 1;
4520
              info->must_restore_reg = 1;
4521
            }
4522
          info->last = NEXT_INSN (insn);
4523
          return 0;
4524
        }
4525
 
4526
      if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4527
          || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4528
        {
4529
          if (this_insn_uses_z)
4530
            {
4531
              if (info->y_used == 0 && iy_clobber)
4532
                {
4533
                  info->regno = HARD_Y_REGNUM;
4534
                  info->must_save_reg = 0;
4535
                  info->must_restore_reg = 0;
4536
                }
4537
              if (info->first != insn
4538
                  && ((info->y_used && ix_clobber)
4539
                      || (info->x_used && iy_clobber)))
4540
                info->last = insn;
4541
              else
4542
                info->last = NEXT_INSN (insn);
4543
              info->save_before_last = 1;
4544
            }
4545
          return 0;
4546
        }
4547
      if (this_insn_uses_ix && this_insn_uses_iy)
4548
        {
4549
          if (this_insn_uses_z)
4550
            {
4551
              fatal_insn ("cannot do z-register replacement", insn);
4552
            }
4553
          return 0;
4554
        }
4555
      if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4556
        {
4557
          if (info->y_used)
4558
            {
4559
              return 0;
4560
            }
4561
          info->x_used = 1;
4562
          if (iy_clobber || z_clobber)
4563
            {
4564
              info->last = NEXT_INSN (insn);
4565
              info->save_before_last = 1;
4566
              return 0;
4567
            }
4568
        }
4569
 
4570
      if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4571
        {
4572
          if (info->x_used)
4573
            {
4574
              return 0;
4575
            }
4576
          info->y_used = 1;
4577
          if (ix_clobber || z_clobber)
4578
            {
4579
              info->last = NEXT_INSN (insn);
4580
              info->save_before_last = 1;
4581
              return 0;
4582
            }
4583
        }
4584
      if (z_dies_here)
4585
        {
4586
          info->z_died = 1;
4587
          info->need_save_z = 0;
4588
        }
4589
      return 1;
4590
    }
4591
  if (GET_CODE (body) == CLOBBER)
4592
    {
4593
 
4594
      /* IX and IY are used at the same time, we have to restore
4595
         the value of the scratch register before this insn.  */
4596
      if (this_insn_uses_ix && this_insn_uses_iy)
4597
        {
4598
          return 0;
4599
        }
4600
      if (info->x_used == 0 && this_insn_uses_ix)
4601
        {
4602
          if (info->y_used)
4603
            {
4604
              return 0;
4605
            }
4606
          info->x_used = 1;
4607
        }
4608
      if (info->y_used == 0 && this_insn_uses_iy)
4609
        {
4610
          if (info->x_used)
4611
            {
4612
              return 0;
4613
            }
4614
          info->y_used = 1;
4615
        }
4616
      return 1;
4617
    }
4618
  return 1;
4619
}
4620
 
4621
static void
4622
m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4623
{
4624
  int reg;
4625
 
4626
  info->replace_reg = NULL_RTX;
4627
  info->must_load_z = 1;
4628
  info->need_save_z = 1;
4629
  info->must_save_reg = 1;
4630
  info->must_restore_reg = 1;
4631
  info->first = insn;
4632
  info->x_used = 0;
4633
  info->y_used = 0;
4634
  info->can_use_d = TARGET_M6811 ? 1 : 0;
4635
  info->found_call = 0;
4636
  info->z_died = 0;
4637
  info->last = 0;
4638
  info->regno = -1;
4639
  info->z_set_count = 0;
4640
  info->z_value = NULL_RTX;
4641
  info->must_push_reg = 0;
4642
  info->save_before_last = 0;
4643
  info->z_loaded_with_sp = 0;
4644
 
4645
  /* Scan the insn forward to find an address register that is not used.
4646
     Stop when:
4647
     - the flow of the program changes,
4648
     - when we detect that both X and Y are necessary,
4649
     - when the Z register dies,
4650
     - when the condition codes are set.  */
4651
 
4652
  for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4653
    {
4654
      if (m68hc11_check_z_replacement (insn, info) == 0)
4655
        break;
4656
    }
4657
 
4658
  /* May be we can use Y or X if they contain the same value as Z.
4659
     This happens very often after the reload.  */
4660
  if (info->z_set_count == 1)
4661
    {
4662
      rtx p = info->first;
4663
      rtx v = 0;
4664
 
4665
      if (info->x_used)
4666
        {
4667
          v = find_last_value (iy_reg, &p, insn, 1);
4668
        }
4669
      else if (info->y_used)
4670
        {
4671
          v = find_last_value (ix_reg, &p, insn, 1);
4672
        }
4673
      if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4674
        {
4675
          if (info->x_used)
4676
            info->regno = HARD_Y_REGNUM;
4677
          else
4678
            info->regno = HARD_X_REGNUM;
4679
          info->must_load_z = 0;
4680
          info->must_save_reg = 0;
4681
          info->must_restore_reg = 0;
4682
          info->found_call = 1;
4683
        }
4684
    }
4685
  if (info->z_set_count == 0)
4686
    info->need_save_z = 0;
4687
 
4688
  if (insn == 0)
4689
    info->need_save_z = 0;
4690
 
4691
  if (info->last == 0)
4692
    info->last = insn;
4693
 
4694
  if (info->regno >= 0)
4695
    {
4696
      reg = info->regno;
4697
      info->replace_reg = gen_rtx_REG (HImode, reg);
4698
    }
4699
  else if (info->can_use_d)
4700
    {
4701
      reg = HARD_D_REGNUM;
4702
      info->replace_reg = d_reg;
4703
    }
4704
  else if (info->x_used)
4705
    {
4706
      reg = HARD_Y_REGNUM;
4707
      info->replace_reg = iy_reg;
4708
    }
4709
  else
4710
    {
4711
      reg = HARD_X_REGNUM;
4712
      info->replace_reg = ix_reg;
4713
    }
4714
  info->regno = reg;
4715
 
4716
  if (info->must_save_reg && info->must_restore_reg)
4717
    {
4718
      if (insn && dead_register_here (insn, info->replace_reg))
4719
        {
4720
          info->must_save_reg = 0;
4721
          info->must_restore_reg = 0;
4722
        }
4723
    }
4724
}
4725
 
4726
/* The insn uses the Z register.  Find a replacement register for it
4727
   (either X or Y) and replace it in the insn and the next ones until
4728
   the flow changes or the replacement register is used.  Instructions
4729
   are emitted before and after the Z-block to preserve the value of
4730
   Z and of the replacement register.  */
4731
 
4732
static void
4733
m68hc11_z_replacement (rtx insn)
4734
{
4735
  rtx replace_reg_qi;
4736
  rtx replace_reg;
4737
  struct replace_info info;
4738
 
4739
  /* Find trivial case where we only need to replace z with the
4740
     equivalent soft register.  */
4741
  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4742
    {
4743
      rtx body = PATTERN (insn);
4744
      rtx src = XEXP (body, 1);
4745
      rtx dst = XEXP (body, 0);
4746
 
4747
      if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4748
        {
4749
          XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4750
          return;
4751
        }
4752
      else if (Z_REG_P (src)
4753
               && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4754
        {
4755
          XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4756
          return;
4757
        }
4758
      else if (D_REG_P (dst)
4759
               && m68hc11_arith_operator (src, GET_MODE (src))
4760
               && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4761
        {
4762
          XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4763
          return;
4764
        }
4765
      else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4766
               && INTVAL (src) == 0)
4767
        {
4768
          XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4769
          /* Force it to be re-recognized.  */
4770
          INSN_CODE (insn) = -1;
4771
          return;
4772
        }
4773
    }
4774
 
4775
  m68hc11_find_z_replacement (insn, &info);
4776
 
4777
  replace_reg = info.replace_reg;
4778
  replace_reg_qi = NULL_RTX;
4779
 
4780
  /* Save the X register in a .page0 location.  */
4781
  if (info.must_save_reg && !info.must_push_reg)
4782
    {
4783
      rtx dst;
4784
 
4785
      if (info.must_push_reg && 0)
4786
        dst = gen_rtx_MEM (HImode,
4787
                       gen_rtx_PRE_DEC (HImode,
4788
                                gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4789
      else
4790
        dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4791
 
4792
      emit_insn_before (gen_movhi (dst,
4793
                                   gen_rtx_REG (HImode, info.regno)), insn);
4794
    }
4795
  if (info.must_load_z && !info.must_push_reg)
4796
    {
4797
      emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4798
                                   gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4799
                        insn);
4800
    }
4801
 
4802
 
4803
  /* Replace all occurrence of Z by replace_reg.
4804
     Stop when the last instruction to replace is reached.
4805
     Also stop when we detect a change in the flow (but it's not
4806
     necessary; just safeguard).  */
4807
 
4808
  for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4809
    {
4810
      rtx body;
4811
 
4812
      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4813
        break;
4814
 
4815
      if (GET_CODE (insn) != INSN
4816
          && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4817
        continue;
4818
 
4819
      body = PATTERN (insn);
4820
      if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4821
          || GET_CODE (body) == ASM_OPERANDS
4822
          || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4823
        {
4824
          rtx note;
4825
 
4826
          if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4827
            {
4828
              printf ("Reg mentioned here...:\n");
4829
              fflush (stdout);
4830
              debug_rtx (insn);
4831
            }
4832
 
4833
          /* Stack pointer was decremented by 2 due to the push.
4834
             Correct that by adding 2 to the destination.  */
4835
          if (info.must_push_reg
4836
              && info.z_loaded_with_sp && GET_CODE (body) == SET)
4837
            {
4838
              rtx src, dst;
4839
 
4840
              src = SET_SRC (body);
4841
              dst = SET_DEST (body);
4842
              if (SP_REG_P (src) && Z_REG_P (dst))
4843
                emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4844
            }
4845
 
4846
          /* Replace any (REG:HI Z) occurrence by either X or Y.  */
4847
          if (!validate_replace_rtx (z_reg, replace_reg, insn))
4848
            {
4849
              INSN_CODE (insn) = -1;
4850
              if (!validate_replace_rtx (z_reg, replace_reg, insn))
4851
                fatal_insn ("cannot do z-register replacement", insn);
4852
            }
4853
 
4854
          /* Likewise for (REG:QI Z).  */
4855
          if (reg_mentioned_p (z_reg, insn))
4856
            {
4857
              if (replace_reg_qi == NULL_RTX)
4858
                replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4859
              validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4860
            }
4861
 
4862
          /* If there is a REG_INC note on Z, replace it with a
4863
             REG_INC note on the replacement register.  This is necessary
4864
             to make sure that the flow pass will identify the change
4865
             and it will not remove a possible insn that saves Z.  */
4866
          for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4867
            {
4868
              if (REG_NOTE_KIND (note) == REG_INC
4869
                  && GET_CODE (XEXP (note, 0)) == REG
4870
                  && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4871
                {
4872
                  XEXP (note, 0) = replace_reg;
4873
                }
4874
            }
4875
        }
4876
      if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4877
        break;
4878
    }
4879
 
4880
  /* Save Z before restoring the old value.  */
4881
  if (insn && info.need_save_z && !info.must_push_reg)
4882
    {
4883
      rtx save_pos_insn = insn;
4884
 
4885
      /* If Z is clobber by the last insn, we have to save its value
4886
         before the last instruction.  */
4887
      if (info.save_before_last)
4888
        save_pos_insn = PREV_INSN (save_pos_insn);
4889
 
4890
      emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4891
                                   gen_rtx_REG (HImode, info.regno)),
4892
                        save_pos_insn);
4893
    }
4894
 
4895
  if (info.must_push_reg && info.last)
4896
    {
4897
      rtx new_body, body;
4898
 
4899
      body = PATTERN (info.last);
4900
      new_body = gen_rtx_PARALLEL (VOIDmode,
4901
                          gen_rtvec (3, body,
4902
                                     gen_rtx_USE (VOIDmode,
4903
                                              replace_reg),
4904
                                     gen_rtx_USE (VOIDmode,
4905
                                              gen_rtx_REG (HImode,
4906
                                                       SOFT_Z_REGNUM))));
4907
      PATTERN (info.last) = new_body;
4908
 
4909
      /* Force recognition on insn since we changed it.  */
4910
      INSN_CODE (insn) = -1;
4911
 
4912
      if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4913
        {
4914
          fatal_insn ("invalid Z register replacement for insn", insn);
4915
        }
4916
      insn = NEXT_INSN (info.last);
4917
    }
4918
 
4919
  /* Restore replacement register unless it was died.  */
4920
  if (insn && info.must_restore_reg && !info.must_push_reg)
4921
    {
4922
      rtx dst;
4923
 
4924
      if (info.must_push_reg && 0)
4925
        dst = gen_rtx_MEM (HImode,
4926
                       gen_rtx_POST_INC (HImode,
4927
                                gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4928
      else
4929
        dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4930
 
4931
      emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4932
                                   dst), insn);
4933
    }
4934
 
4935
}
4936
 
4937
 
4938
/* Scan all the insn and re-affects some registers
4939
    - The Z register (if it was used), is affected to X or Y depending
4940
      on the instruction.  */
4941
 
4942
static void
4943
m68hc11_reassign_regs (rtx first)
4944
{
4945
  rtx insn;
4946
 
4947
  ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4948
  iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4949
  z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4950
  z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4951
 
4952
  /* Scan all insns to replace Z by X or Y preserving the old value
4953
     of X/Y and restoring it afterward.  */
4954
 
4955
  for (insn = first; insn; insn = NEXT_INSN (insn))
4956
    {
4957
      rtx body;
4958
 
4959
      if (GET_CODE (insn) == CODE_LABEL
4960
          || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4961
        continue;
4962
 
4963
      if (!INSN_P (insn))
4964
        continue;
4965
 
4966
      body = PATTERN (insn);
4967
      if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4968
        continue;
4969
 
4970
      if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4971
          || GET_CODE (body) == ASM_OPERANDS
4972
          || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4973
        continue;
4974
 
4975
      if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4976
          || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4977
        {
4978
 
4979
          /* If Z appears in this insn, replace it in the current insn
4980
             and the next ones until the flow changes or we have to
4981
             restore back the replacement register.  */
4982
 
4983
          if (reg_mentioned_p (z_reg, body))
4984
            {
4985
              m68hc11_z_replacement (insn);
4986
            }
4987
        }
4988
      else
4989
        {
4990
          printf ("insn not handled by Z replacement:\n");
4991
          fflush (stdout);
4992
          debug_rtx (insn);
4993
        }
4994
    }
4995
}
4996
 
4997
 
4998
/* Machine-dependent reorg pass.
4999
   Specific optimizations are defined here:
5000
    - this pass changes the Z register into either X or Y
5001
      (it preserves X/Y previous values in a memory slot in page0).
5002
 
5003
   When this pass is finished, the global variable
5004
   'z_replacement_completed' is set to 2.  */
5005
 
5006
static void
5007
m68hc11_reorg (void)
5008
{
5009
  int split_done = 0;
5010
  rtx insn, first;
5011
 
5012
  z_replacement_completed = 0;
5013
  z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5014
  first = get_insns ();
5015
 
5016
  /* Some RTX are shared at this point.  This breaks the Z register
5017
     replacement, unshare everything.  */
5018
  unshare_all_rtl_again (first);
5019
 
5020
  /* Force a split of all splittable insn.  This is necessary for the
5021
     Z register replacement mechanism because we end up with basic insns.  */
5022
  split_all_insns_noflow ();
5023
  split_done = 1;
5024
 
5025
  z_replacement_completed = 1;
5026
  m68hc11_reassign_regs (first);
5027
 
5028
  if (optimize)
5029
    compute_bb_for_insn ();
5030
 
5031
  /* After some splitting, there are some opportunities for CSE pass.
5032
     This happens quite often when 32-bit or above patterns are split.  */
5033
  if (optimize > 0 && split_done)
5034
    {
5035
      reload_cse_regs (first);
5036
    }
5037
 
5038
  /* Re-create the REG_DEAD notes.  These notes are used in the machine
5039
     description to use the best assembly directives.  */
5040
  if (optimize)
5041
    {
5042
      /* Before recomputing the REG_DEAD notes, remove all of them.
5043
         This is necessary because the reload_cse_regs() pass can
5044
         have replaced some (MEM) with a register.  In that case,
5045
         the REG_DEAD that could exist for that register may become
5046
         wrong.  */
5047
      for (insn = first; insn; insn = NEXT_INSN (insn))
5048
        {
5049
          if (INSN_P (insn))
5050
            {
5051
              rtx *pnote;
5052
 
5053
              pnote = &REG_NOTES (insn);
5054
              while (*pnote != 0)
5055
                {
5056
                  if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5057
                    *pnote = XEXP (*pnote, 1);
5058
                  else
5059
                    pnote = &XEXP (*pnote, 1);
5060
                }
5061
            }
5062
        }
5063
 
5064
      life_analysis (PROP_REG_INFO | PROP_DEATH_NOTES);
5065
    }
5066
 
5067
  z_replacement_completed = 2;
5068
 
5069
  /* If optimizing, then go ahead and split insns that must be
5070
     split after Z register replacement.  This gives more opportunities
5071
     for peephole (in particular for consecutives xgdx/xgdy).  */
5072
  if (optimize > 0)
5073
    split_all_insns_noflow ();
5074
 
5075
  /* Once insns are split after the z_replacement_completed == 2,
5076
     we must not re-run the life_analysis.  The xgdx/xgdy patterns
5077
     are not recognized and the life_analysis pass removes some
5078
     insns because it thinks some (SETs) are noops or made to dead
5079
     stores (which is false due to the swap).
5080
 
5081
     Do a simple pass to eliminate the noop set that the final
5082
     split could generate (because it was easier for split definition).  */
5083
  {
5084
    rtx insn;
5085
 
5086
    for (insn = first; insn; insn = NEXT_INSN (insn))
5087
      {
5088
        rtx body;
5089
 
5090
        if (INSN_DELETED_P (insn))
5091
          continue;
5092
        if (!INSN_P (insn))
5093
          continue;
5094
 
5095
        /* Remove the (set (R) (R)) insns generated by some splits.  */
5096
        body = PATTERN (insn);
5097
        if (GET_CODE (body) == SET
5098
            && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5099
          {
5100
            PUT_CODE (insn, NOTE);
5101
            NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5102
            NOTE_SOURCE_FILE (insn) = 0;
5103
            continue;
5104
          }
5105
      }
5106
  }
5107
}
5108
 
5109
/* Override memcpy */
5110
 
5111
static void
5112
m68hc11_init_libfuncs (void)
5113
{
5114
  memcpy_libfunc = init_one_libfunc ("__memcpy");
5115
  memcmp_libfunc = init_one_libfunc ("__memcmp");
5116
  memset_libfunc = init_one_libfunc ("__memset");
5117
}
5118
 
5119
 
5120
 
5121
/* Cost functions.  */
5122
 
5123
/* Cost of moving memory.  */
5124
int
5125
m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
5126
                          int in ATTRIBUTE_UNUSED)
5127
{
5128
  if (class <= H_REGS && class > NO_REGS)
5129
    {
5130
      if (GET_MODE_SIZE (mode) <= 2)
5131
        return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5132
      else
5133
        return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5134
    }
5135
  else
5136
    {
5137
      if (GET_MODE_SIZE (mode) <= 2)
5138
        return COSTS_N_INSNS (3);
5139
      else
5140
        return COSTS_N_INSNS (4);
5141
    }
5142
}
5143
 
5144
 
5145
/* Cost of moving data from a register of class 'from' to on in class 'to'.
5146
   Reload does not check the constraint of set insns when the two registers
5147
   have a move cost of 2.  Setting a higher cost will force reload to check
5148
   the constraints.  */
5149
int
5150
m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5151
                            enum reg_class to)
5152
{
5153
  /* All costs are symmetric, so reduce cases by putting the
5154
     lower number class as the destination.  */
5155
  if (from < to)
5156
    {
5157
      enum reg_class tmp = to;
5158
      to = from, from = tmp;
5159
    }
5160
  if (to >= S_REGS)
5161
    return m68hc11_memory_move_cost (mode, S_REGS, 0);
5162
  else if (from <= S_REGS)
5163
    return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5164
  else
5165
    return COSTS_N_INSNS (2);
5166
}
5167
 
5168
 
5169
/* Provide the costs of an addressing mode that contains ADDR.
5170
   If ADDR is not a valid address, its cost is irrelevant.  */
5171
 
5172
static int
5173
m68hc11_address_cost (rtx addr)
5174
{
5175
  int cost = 4;
5176
 
5177
  switch (GET_CODE (addr))
5178
    {
5179
    case REG:
5180
      /* Make the cost of hard registers and specially SP, FP small.  */
5181
      if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5182
        cost = 0;
5183
      else
5184
        cost = 1;
5185
      break;
5186
 
5187
    case SYMBOL_REF:
5188
      cost = 8;
5189
      break;
5190
 
5191
    case LABEL_REF:
5192
    case CONST:
5193
      cost = 0;
5194
      break;
5195
 
5196
    case PLUS:
5197
      {
5198
        register rtx plus0 = XEXP (addr, 0);
5199
        register rtx plus1 = XEXP (addr, 1);
5200
 
5201
        if (GET_CODE (plus0) != REG)
5202
          break;
5203
 
5204
        switch (GET_CODE (plus1))
5205
          {
5206
          case CONST_INT:
5207
            if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5208
                || INTVAL (plus1) < m68hc11_min_offset)
5209
              cost = 3;
5210
            else if (INTVAL (plus1) >= m68hc11_max_offset)
5211
              cost = 2;
5212
            else
5213
              cost = 1;
5214
            if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5215
              cost += 0;
5216
            else
5217
              cost += 1;
5218
            break;
5219
 
5220
          case SYMBOL_REF:
5221
            cost = 8;
5222
            break;
5223
 
5224
          case CONST:
5225
          case LABEL_REF:
5226
            cost = 0;
5227
            break;
5228
 
5229
          default:
5230
            break;
5231
          }
5232
        break;
5233
      }
5234
    case PRE_DEC:
5235
    case PRE_INC:
5236
      if (SP_REG_P (XEXP (addr, 0)))
5237
        cost = 1;
5238
      break;
5239
 
5240
    default:
5241
      break;
5242
    }
5243
  if (debug_m6811)
5244
    {
5245
      printf ("Address cost: %d for :", cost);
5246
      fflush (stdout);
5247
      debug_rtx (addr);
5248
    }
5249
 
5250
  return cost;
5251
}
5252
 
5253
static int
5254
m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5255
{
5256
  int total;
5257
 
5258
  total = rtx_cost (x, SET);
5259
  if (mode == QImode)
5260
    total += m68hc11_cost->shiftQI_const[shift % 8];
5261
  else if (mode == HImode)
5262
    total += m68hc11_cost->shiftHI_const[shift % 16];
5263
  else if (shift == 8 || shift == 16 || shift == 32)
5264
    total += m68hc11_cost->shiftHI_const[8];
5265
  else if (shift != 0 && shift != 16 && shift != 32)
5266
    {
5267
      total += m68hc11_cost->shiftHI_const[1] * shift;
5268
    }
5269
 
5270
  /* For SI and others, the cost is higher.  */
5271
  if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5272
    total *= GET_MODE_SIZE (mode) / 2;
5273
 
5274
  /* When optimizing for size, make shift more costly so that
5275
     multiplications are preferred.  */
5276
  if (optimize_size && (shift % 8) != 0)
5277
    total *= 2;
5278
 
5279
  return total;
5280
}
5281
 
5282
static int
5283
m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5284
                     enum rtx_code outer_code ATTRIBUTE_UNUSED)
5285
{
5286
  enum machine_mode mode = GET_MODE (x);
5287
  int extra_cost = 0;
5288
  int total;
5289
 
5290
  switch (code)
5291
    {
5292
    case ROTATE:
5293
    case ROTATERT:
5294
    case ASHIFT:
5295
    case LSHIFTRT:
5296
    case ASHIFTRT:
5297
      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5298
        {
5299
          return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5300
        }
5301
 
5302
      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5303
      total += m68hc11_cost->shift_var;
5304
      return total;
5305
 
5306
    case AND:
5307
    case XOR:
5308
    case IOR:
5309
      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5310
      total += m68hc11_cost->logical;
5311
 
5312
      /* Logical instructions are byte instructions only.  */
5313
      total *= GET_MODE_SIZE (mode);
5314
      return total;
5315
 
5316
    case MINUS:
5317
    case PLUS:
5318
      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5319
      total += m68hc11_cost->add;
5320
      if (GET_MODE_SIZE (mode) > 2)
5321
        {
5322
          total *= GET_MODE_SIZE (mode) / 2;
5323
        }
5324
      return total;
5325
 
5326
    case UDIV:
5327
    case DIV:
5328
    case MOD:
5329
      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5330
      switch (mode)
5331
        {
5332
        case QImode:
5333
          total += m68hc11_cost->divQI;
5334
          break;
5335
 
5336
        case HImode:
5337
          total += m68hc11_cost->divHI;
5338
          break;
5339
 
5340
        case SImode:
5341
        default:
5342
          total += m68hc11_cost->divSI;
5343
          break;
5344
        }
5345
      return total;
5346
 
5347
    case MULT:
5348
      /* mul instruction produces 16-bit result.  */
5349
      if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5350
          && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5351
        return m68hc11_cost->multQI
5352
          + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5353
          + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5354
 
5355
      /* emul instruction produces 32-bit result for 68HC12.  */
5356
      if (TARGET_M6812 && mode == SImode
5357
          && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5358
          && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5359
        return m68hc11_cost->multHI
5360
          + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5361
          + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5362
 
5363
      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5364
      switch (mode)
5365
        {
5366
        case QImode:
5367
          total += m68hc11_cost->multQI;
5368
          break;
5369
 
5370
        case HImode:
5371
          total += m68hc11_cost->multHI;
5372
          break;
5373
 
5374
        case SImode:
5375
        default:
5376
          total += m68hc11_cost->multSI;
5377
          break;
5378
        }
5379
      return total;
5380
 
5381
    case NEG:
5382
    case SIGN_EXTEND:
5383
      extra_cost = COSTS_N_INSNS (2);
5384
 
5385
      /* Fall through */
5386
    case NOT:
5387
    case COMPARE:
5388
    case ABS:
5389
    case ZERO_EXTEND:
5390
      total = extra_cost + rtx_cost (XEXP (x, 0), code);
5391
      if (mode == QImode)
5392
        {
5393
          return total + COSTS_N_INSNS (1);
5394
        }
5395
      if (mode == HImode)
5396
        {
5397
          return total + COSTS_N_INSNS (2);
5398
        }
5399
      if (mode == SImode)
5400
        {
5401
          return total + COSTS_N_INSNS (4);
5402
        }
5403
      return total + COSTS_N_INSNS (8);
5404
 
5405
    case IF_THEN_ELSE:
5406
      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5407
        return COSTS_N_INSNS (1);
5408
 
5409
      return COSTS_N_INSNS (1);
5410
 
5411
    default:
5412
      return COSTS_N_INSNS (4);
5413
    }
5414
}
5415
 
5416
static bool
5417
m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
5418
{
5419
  switch (code)
5420
    {
5421
      /* Constants are cheap.  Moving them in registers must be avoided
5422
         because most instructions do not handle two register operands.  */
5423
    case CONST_INT:
5424
    case CONST:
5425
    case LABEL_REF:
5426
    case SYMBOL_REF:
5427
    case CONST_DOUBLE:
5428
      /* Logical and arithmetic operations with a constant operand are
5429
         better because they are not supported with two registers.  */
5430
      /* 'clr' is slow */
5431
      if (outer_code == SET && x == const0_rtx)
5432
         /* After reload, the reload_cse pass checks the cost to change
5433
            a SET into a PLUS.  Make const0 cheap then.  */
5434
        *total = 1 - reload_completed;
5435
      else
5436
        *total = 0;
5437
      return true;
5438
 
5439
    case ROTATE:
5440
    case ROTATERT:
5441
    case ASHIFT:
5442
    case LSHIFTRT:
5443
    case ASHIFTRT:
5444
    case MINUS:
5445
    case PLUS:
5446
    case AND:
5447
    case XOR:
5448
    case IOR:
5449
    case UDIV:
5450
    case DIV:
5451
    case MOD:
5452
    case MULT:
5453
    case NEG:
5454
    case SIGN_EXTEND:
5455
    case NOT:
5456
    case COMPARE:
5457
    case ZERO_EXTEND:
5458
    case IF_THEN_ELSE:
5459
      *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5460
      return true;
5461
 
5462
    default:
5463
      return false;
5464
    }
5465
}
5466
 
5467
 
5468
/* Worker function for TARGET_ASM_FILE_START.  */
5469
 
5470
static void
5471
m68hc11_file_start (void)
5472
{
5473
  default_file_start ();
5474
 
5475
  fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5476
}
5477
 
5478
 
5479
/* Worker function for TARGET_ASM_CONSTRUCTOR.  */
5480
 
5481
static void
5482
m68hc11_asm_out_constructor (rtx symbol, int priority)
5483
{
5484
  default_ctor_section_asm_out_constructor (symbol, priority);
5485
  fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5486
}
5487
 
5488
/* Worker function for TARGET_ASM_DESTRUCTOR.  */
5489
 
5490
static void
5491
m68hc11_asm_out_destructor (rtx symbol, int priority)
5492
{
5493
  default_dtor_section_asm_out_destructor (symbol, priority);
5494
  fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5495
}
5496
 
5497
/* Worker function for TARGET_STRUCT_VALUE_RTX.  */
5498
 
5499
static rtx
5500
m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5501
                          int incoming ATTRIBUTE_UNUSED)
5502
{
5503
  return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5504
}
5505
 
5506
/* Return true if type TYPE should be returned in memory.
5507
   Blocks and data types largers than 4 bytes cannot be returned
5508
   in the register (D + X = 4).  */
5509
 
5510
static bool
5511
m68hc11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
5512
{
5513
  if (TYPE_MODE (type) == BLKmode)
5514
    {
5515
      HOST_WIDE_INT size = int_size_in_bytes (type);
5516
      return (size == -1 || size > 4);
5517
    }
5518
  else
5519
    return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5520
}
5521
 
5522
#include "gt-m68hc11.h"

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.