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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [m68hc11/] [m68hc11.c] - Blame information for rev 309

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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