00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026 #include "system.h"
00027 #include "rtl.h"
00028 #include "tree.h"
00029 #include "obstack.h"
00030 #include "regs.h"
00031 #include "hard-reg-set.h"
00032 #include "real.h"
00033 #include "insn-config.h"
00034 #include "conditions.h"
00035 #include "output.h"
00036 #include "insn-attr.h"
00037 #include "flags.h"
00038 #include "reload.h"
00039 #include "function.h"
00040 #include "expr.h"
00041 #include "optabs.h"
00042 #include "toplev.h"
00043 #include "recog.h"
00044 #include "ggc.h"
00045 #include "except.h"
00046 #include "c-pragma.h"
00047 #include "integrate.h"
00048 #include "tm_p.h"
00049 #include "target.h"
00050 #include "target-def.h"
00051
00052
00053 typedef struct minipool_node Mnode;
00054 typedef struct minipool_fixup Mfix;
00055
00056
00057
00058 #define Hint HOST_WIDE_INT
00059 #define Mmode enum machine_mode
00060 #define Ulong unsigned long
00061 #define Ccstar const char *
00062
00063 const struct attribute_spec arm_attribute_table[];
00064
00065
00066 static void arm_add_gc_roots PARAMS ((void));
00067 static int arm_gen_constant PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));
00068 static Ulong bit_count PARAMS ((signed int));
00069 static int const_ok_for_op PARAMS ((Hint, enum rtx_code));
00070 static int eliminate_lr2ip PARAMS ((rtx *));
00071 static rtx emit_multi_reg_push PARAMS ((int));
00072 static rtx emit_sfm PARAMS ((int, int));
00073 #ifndef AOF_ASSEMBLER
00074 static bool arm_assemble_integer PARAMS ((rtx, unsigned int, int));
00075 #endif
00076 static Ccstar fp_const_from_val PARAMS ((REAL_VALUE_TYPE *));
00077 static arm_cc get_arm_condition_code PARAMS ((rtx));
00078 static void init_fpa_table PARAMS ((void));
00079 static Hint int_log2 PARAMS ((Hint));
00080 static rtx is_jump_table PARAMS ((rtx));
00081 static Ccstar output_multi_immediate PARAMS ((rtx *, Ccstar, Ccstar, int, Hint));
00082 static void print_multi_reg PARAMS ((FILE *, Ccstar, int, int));
00083 static Mmode select_dominance_cc_mode PARAMS ((rtx, rtx, Hint));
00084 static Ccstar shift_op PARAMS ((rtx, Hint *));
00085 static void arm_init_machine_status PARAMS ((struct function *));
00086 static void arm_mark_machine_status PARAMS ((struct function *));
00087 static void arm_free_machine_status PARAMS ((struct function *));
00088 static int number_of_first_bit_set PARAMS ((int));
00089 static void replace_symbols_in_block PARAMS ((tree, rtx, rtx));
00090 static void thumb_exit PARAMS ((FILE *, int, rtx));
00091 static void thumb_pushpop PARAMS ((FILE *, int, int));
00092 static Ccstar thumb_condition_code PARAMS ((rtx, int));
00093 static rtx is_jump_table PARAMS ((rtx));
00094 static Hint get_jump_table_size PARAMS ((rtx));
00095 static Mnode * move_minipool_fix_forward_ref PARAMS ((Mnode *, Mnode *, Hint));
00096 static Mnode * add_minipool_forward_ref PARAMS ((Mfix *));
00097 static Mnode * move_minipool_fix_backward_ref PARAMS ((Mnode *, Mnode *, Hint));
00098 static Mnode * add_minipool_backward_ref PARAMS ((Mfix *));
00099 static void assign_minipool_offsets PARAMS ((Mfix *));
00100 static void arm_print_value PARAMS ((FILE *, rtx));
00101 static void dump_minipool PARAMS ((rtx));
00102 static int arm_barrier_cost PARAMS ((rtx));
00103 static Mfix * create_fix_barrier PARAMS ((Mfix *, Hint));
00104 static void push_minipool_barrier PARAMS ((rtx, Hint));
00105 static void push_minipool_fix PARAMS ((rtx, Hint, rtx *, Mmode, rtx));
00106 static void note_invalid_constants PARAMS ((rtx, Hint));
00107 static int current_file_function_operand PARAMS ((rtx));
00108 static Ulong arm_compute_save_reg0_reg12_mask PARAMS ((void));
00109 static Ulong arm_compute_save_reg_mask PARAMS ((void));
00110 static Ulong arm_isr_value PARAMS ((tree));
00111 static Ulong arm_compute_func_type PARAMS ((void));
00112 static tree arm_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
00113 static tree arm_handle_isr_attribute PARAMS ((tree *, tree, tree, int, bool *));
00114 static void arm_output_function_epilogue PARAMS ((FILE *, Hint));
00115 static void arm_output_function_prologue PARAMS ((FILE *, Hint));
00116 static void thumb_output_function_prologue PARAMS ((FILE *, Hint));
00117 static int arm_comp_type_attributes PARAMS ((tree, tree));
00118 static void arm_set_default_type_attributes PARAMS ((tree));
00119 static int arm_adjust_cost PARAMS ((rtx, rtx, rtx, int));
00120 #ifdef OBJECT_FORMAT_ELF
00121 static void arm_elf_asm_named_section PARAMS ((const char *, unsigned int));
00122 #endif
00123
00124 #undef Hint
00125 #undef Mmode
00126 #undef Ulong
00127 #undef Ccstar
00128
00129
00130 #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
00131 #undef TARGET_MERGE_DECL_ATTRIBUTES
00132 #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
00133 #endif
00134
00135 #undef TARGET_ATTRIBUTE_TABLE
00136 #define TARGET_ATTRIBUTE_TABLE arm_attribute_table
00137
00138 #ifdef AOF_ASSEMBLER
00139 #undef TARGET_ASM_BYTE_OP
00140 #define TARGET_ASM_BYTE_OP "\tDCB\t"
00141 #undef TARGET_ASM_ALIGNED_HI_OP
00142 #define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
00143 #undef TARGET_ASM_ALIGNED_SI_OP
00144 #define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
00145 #else
00146 #undef TARGET_ASM_ALIGNED_SI_OP
00147 #define TARGET_ASM_ALIGNED_SI_OP NULL
00148 #undef TARGET_ASM_INTEGER
00149 #define TARGET_ASM_INTEGER arm_assemble_integer
00150 #endif
00151
00152 #undef TARGET_ASM_FUNCTION_PROLOGUE
00153 #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
00154
00155 #undef TARGET_ASM_FUNCTION_EPILOGUE
00156 #define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
00157
00158 #undef TARGET_COMP_TYPE_ATTRIBUTES
00159 #define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
00160
00161 #undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
00162 #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
00163
00164 #undef TARGET_INIT_BUILTINS
00165 #define TARGET_INIT_BUILTINS arm_init_builtins
00166
00167 #undef TARGET_EXPAND_BUILTIN
00168 #define TARGET_EXPAND_BUILTIN arm_expand_builtin
00169
00170 #undef TARGET_SCHED_ADJUST_COST
00171 #define TARGET_SCHED_ADJUST_COST arm_adjust_cost
00172
00173 struct gcc_target targetm = TARGET_INITIALIZER;
00174
00175
00176 static struct obstack minipool_obstack;
00177 static char * minipool_startobj;
00178
00179 #define obstack_chunk_alloc xmalloc
00180 #define obstack_chunk_free free
00181
00182
00183
00184 static int max_insns_skipped = 5;
00185
00186 extern FILE * asm_out_file;
00187
00188
00189 int making_const_table;
00190
00191
00192
00193 rtx arm_compare_op0, arm_compare_op1;
00194
00195
00196 enum floating_point_type arm_fpu;
00197
00198
00199 enum floating_point_type arm_fpu_arch;
00200
00201
00202 enum prog_mode_type arm_prgmode;
00203
00204
00205 const char * target_fp_name = NULL;
00206
00207
00208 const char * structure_size_string = NULL;
00209 int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
00210
00211
00212 #define FL_CO_PROC (1 << 0)
00213 #define FL_FAST_MULT (1 << 1)
00214 #define FL_MODE26 (1 << 2)
00215 #define FL_MODE32 (1 << 3)
00216 #define FL_ARCH4 (1 << 4)
00217 #define FL_ARCH5 (1 << 5)
00218 #define FL_THUMB (1 << 6)
00219 #define FL_LDSCHED (1 << 7)
00220 #define FL_STRONG (1 << 8)
00221 #define FL_ARCH5E (1 << 9)
00222 #define FL_XSCALE (1 << 10)
00223
00224
00225
00226 static int insn_flags = 0;
00227
00228
00229
00230
00231
00232 static int tune_flags = 0;
00233
00234
00235
00236
00237
00238 int arm_fast_multiply = 0;
00239
00240
00241 int arm_arch4 = 0;
00242
00243
00244 int arm_arch5 = 0;
00245
00246
00247 int arm_arch5e = 0;
00248
00249
00250 int arm_ld_sched = 0;
00251
00252
00253 int arm_is_strong = 0;
00254
00255
00256 int arm_is_xscale = 0;
00257
00258
00259 int arm_is_6_or_7 = 0;
00260
00261
00262 int thumb_code = 0;
00263
00264
00265
00266
00267 enum machine_mode output_memory_reference_mode;
00268
00269
00270 const char * arm_pic_register_string = NULL;
00271 int arm_pic_register = INVALID_REGNUM;
00272
00273
00274
00275 int return_used_this_function;
00276
00277
00278
00279 static int after_arm_reorg = 0;
00280
00281
00282 static int arm_constant_limit = 3;
00283
00284
00285 int arm_ccfsm_state;
00286 enum arm_cond_code arm_current_cc;
00287 rtx arm_target_insn;
00288 int arm_target_label;
00289
00290
00291 static const char * const arm_condition_codes[] =
00292 {
00293 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
00294 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
00295 };
00296
00297 #define streq(string1, string2) (strcmp (string1, string2) == 0)
00298
00299
00300
00301 struct processors
00302 {
00303 const char *const name;
00304 const unsigned int flags;
00305 };
00306
00307
00308
00309 static const struct processors all_cores[] =
00310 {
00311
00312
00313 {"arm2", FL_CO_PROC | FL_MODE26 },
00314 {"arm250", FL_CO_PROC | FL_MODE26 },
00315 {"arm3", FL_CO_PROC | FL_MODE26 },
00316 {"arm6", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00317 {"arm60", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00318 {"arm600", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00319 {"arm610", FL_MODE26 | FL_MODE32 },
00320 {"arm620", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00321 {"arm7", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00322
00323
00324 {"arm7m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
00325 {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00326 {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
00327 {"arm7di", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00328 {"arm7dmi", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
00329 {"arm70", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00330 {"arm700", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00331 {"arm700i", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00332 {"arm710", FL_MODE26 | FL_MODE32 },
00333 {"arm710t", FL_MODE26 | FL_MODE32 | FL_THUMB },
00334 {"arm720", FL_MODE26 | FL_MODE32 },
00335 {"arm720t", FL_MODE26 | FL_MODE32 | FL_THUMB },
00336 {"arm740t", FL_MODE26 | FL_MODE32 | FL_THUMB },
00337 {"arm710c", FL_MODE26 | FL_MODE32 },
00338 {"arm7100", FL_MODE26 | FL_MODE32 },
00339 {"arm7500", FL_MODE26 | FL_MODE32 },
00340
00341 {"arm7500fe", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00342 {"arm7tdmi", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
00343 {"arm8", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
00344 {"arm810", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
00345 {"arm9", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
00346 {"arm920", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
00347 {"arm920t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
00348 {"arm940t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
00349 {"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
00350 {"arm9e", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
00351 {"strongarm", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
00352 {"strongarm110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
00353 {"strongarm1100", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
00354 {"strongarm1110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
00355 {"arm10tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_ARCH5 },
00356 {"arm1020t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_ARCH5 },
00357 {"xscale", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE },
00358
00359 {NULL, 0}
00360 };
00361
00362 static const struct processors all_architectures[] =
00363 {
00364
00365
00366 { "armv2", FL_CO_PROC | FL_MODE26 },
00367 { "armv2a", FL_CO_PROC | FL_MODE26 },
00368 { "armv3", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
00369 { "armv3m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
00370 { "armv4", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 },
00371
00372
00373 { "armv4t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
00374 { "armv5", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
00375 { "armv5t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
00376 { "armv5te", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
00377 { NULL, 0 }
00378 };
00379
00380
00381
00382
00383
00384 struct arm_cpu_select arm_select[] =
00385 {
00386
00387 { NULL, "-mcpu=", all_cores },
00388 { NULL, "-march=", all_architectures },
00389 { NULL, "-mtune=", all_cores }
00390 };
00391
00392
00393 static unsigned long
00394 bit_count (value)
00395 signed int value;
00396 {
00397 unsigned long count = 0;
00398
00399 while (value)
00400 {
00401 value &= ~(value & -value);
00402 ++count;
00403 }
00404
00405 return count;
00406 }
00407
00408
00409
00410 void
00411 arm_override_options ()
00412 {
00413 unsigned i;
00414
00415
00416 for (i = ARRAY_SIZE (arm_select); i--;)
00417 {
00418 struct arm_cpu_select * ptr = arm_select + i;
00419
00420 if (ptr->string != NULL && ptr->string[0] != '\0')
00421 {
00422 const struct processors * sel;
00423
00424 for (sel = ptr->processors; sel->name != NULL; sel++)
00425 if (streq (ptr->string, sel->name))
00426 {
00427 if (i == 2)
00428 tune_flags = sel->flags;
00429 else
00430 {
00431
00432
00433
00434
00435 if (insn_flags != 0 && (insn_flags ^ sel->flags))
00436 warning ("switch -mcpu=%s conflicts with -march= switch",
00437 ptr->string);
00438
00439 insn_flags = sel->flags;
00440 }
00441
00442 break;
00443 }
00444
00445 if (sel->name == NULL)
00446 error ("bad value (%s) for %s switch", ptr->string, ptr->name);
00447 }
00448 }
00449
00450
00451 if (insn_flags == 0)
00452 {
00453 const struct processors * sel;
00454 unsigned int sought;
00455 static const struct cpu_default
00456 {
00457 const int cpu;
00458 const char *const name;
00459 }
00460 cpu_defaults[] =
00461 {
00462 { TARGET_CPU_arm2, "arm2" },
00463 { TARGET_CPU_arm6, "arm6" },
00464 { TARGET_CPU_arm610, "arm610" },
00465 { TARGET_CPU_arm710, "arm710" },
00466 { TARGET_CPU_arm7m, "arm7m" },
00467 { TARGET_CPU_arm7500fe, "arm7500fe" },
00468 { TARGET_CPU_arm7tdmi, "arm7tdmi" },
00469 { TARGET_CPU_arm8, "arm8" },
00470 { TARGET_CPU_arm810, "arm810" },
00471 { TARGET_CPU_arm9, "arm9" },
00472 { TARGET_CPU_strongarm, "strongarm" },
00473 { TARGET_CPU_xscale, "xscale" },
00474 { TARGET_CPU_generic, "arm" },
00475 { 0, 0 }
00476 };
00477 const struct cpu_default * def;
00478
00479
00480 for (def = cpu_defaults; def->name; def++)
00481 if (def->cpu == TARGET_CPU_DEFAULT)
00482 break;
00483
00484
00485 if (def->name == NULL)
00486 abort ();
00487
00488
00489 for (sel = all_cores; sel->name != NULL; sel++)
00490 if (streq (def->name, sel->name))
00491 break;
00492
00493 if (sel->name == NULL)
00494 abort ();
00495
00496 insn_flags = sel->flags;
00497
00498
00499
00500 sought = 0;
00501
00502 if (TARGET_INTERWORK || TARGET_THUMB)
00503 {
00504 sought |= (FL_THUMB | FL_MODE32);
00505
00506
00507 target_flags |= ARM_FLAG_APCS_32;
00508
00509
00510
00511
00512
00513 insn_flags &= ~FL_MODE26;
00514 }
00515 else if (!TARGET_APCS_32)
00516 sought |= FL_MODE26;
00517
00518 if (sought != 0 && ((sought & insn_flags) != sought))
00519 {
00520
00521
00522
00523 for (sel = all_cores; sel->name != NULL; sel++)
00524 if ((sel->flags & sought) == (sought | insn_flags))
00525 break;
00526
00527 if (sel->name == NULL)
00528 {
00529 unsigned int current_bit_count = 0;
00530 const struct processors * best_fit = NULL;
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 for (sel = all_cores; sel->name != NULL; sel++)
00546 if ((sel->flags & sought) == sought)
00547 {
00548 unsigned int count;
00549
00550 count = bit_count (sel->flags & insn_flags);
00551
00552 if (count >= current_bit_count)
00553 {
00554 best_fit = sel;
00555 current_bit_count = count;
00556 }
00557 }
00558
00559 if (best_fit == NULL)
00560 abort ();
00561 else
00562 sel = best_fit;
00563 }
00564
00565 insn_flags = sel->flags;
00566 }
00567 }
00568
00569
00570
00571 if (tune_flags == 0)
00572 tune_flags = insn_flags;
00573
00574
00575
00576 if (TARGET_APCS_32 && !(insn_flags & FL_MODE32))
00577 {
00578
00579
00580
00581 if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0)
00582 warning ("target CPU does not support APCS-32" );
00583 target_flags &= ~ARM_FLAG_APCS_32;
00584 }
00585 else if (!TARGET_APCS_32 && !(insn_flags & FL_MODE26))
00586 {
00587 warning ("target CPU does not support APCS-26" );
00588 target_flags |= ARM_FLAG_APCS_32;
00589 }
00590
00591 if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
00592 {
00593 warning ("target CPU does not support interworking" );
00594 target_flags &= ~ARM_FLAG_INTERWORK;
00595 }
00596
00597 if (TARGET_THUMB && !(insn_flags & FL_THUMB))
00598 {
00599 warning ("target CPU does not support THUMB instructions");
00600 target_flags &= ~ARM_FLAG_THUMB;
00601 }
00602
00603 if (TARGET_APCS_FRAME && TARGET_THUMB)
00604 {
00605
00606 target_flags &= ~ARM_FLAG_APCS_FRAME;
00607 }
00608
00609
00610
00611 if ((target_flags & (THUMB_FLAG_LEAF_BACKTRACE | THUMB_FLAG_BACKTRACE))
00612 && TARGET_ARM)
00613 warning ("enabling backtrace support is only meaningful when compiling for the Thumb");
00614
00615 if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
00616 warning ("enabling callee interworking support is only meaningful when compiling for the Thumb");
00617
00618 if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
00619 warning ("enabling caller interworking support is only meaningful when compiling for the Thumb");
00620
00621
00622 if (TARGET_INTERWORK)
00623 {
00624 if (!TARGET_APCS_32)
00625 warning ("interworking forces APCS-32 to be used" );
00626 target_flags |= ARM_FLAG_APCS_32;
00627 }
00628
00629 if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
00630 {
00631 warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
00632 target_flags |= ARM_FLAG_APCS_FRAME;
00633 }
00634
00635 if (TARGET_POKE_FUNCTION_NAME)
00636 target_flags |= ARM_FLAG_APCS_FRAME;
00637
00638 if (TARGET_APCS_REENT && flag_pic)
00639 error ("-fpic and -mapcs-reent are incompatible");
00640
00641 if (TARGET_APCS_REENT)
00642 warning ("APCS reentrant code not supported. Ignored");
00643
00644
00645
00646 if (TARGET_ARM
00647 && write_symbols != NO_DEBUG
00648 && !TARGET_APCS_FRAME
00649 && (TARGET_DEFAULT & ARM_FLAG_APCS_FRAME))
00650 warning ("-g with -mno-apcs-frame may not give sensible debugging");
00651
00652
00653
00654 if (flag_pic)
00655 arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
00656
00657 if (TARGET_APCS_FLOAT)
00658 warning ("passing floating point arguments in fp regs not yet supported");
00659
00660
00661 arm_fast_multiply = (insn_flags & FL_FAST_MULT) != 0;
00662 arm_arch4 = (insn_flags & FL_ARCH4) != 0;
00663 arm_arch5 = (insn_flags & FL_ARCH5) != 0;
00664 arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
00665 arm_is_xscale = (insn_flags & FL_XSCALE) != 0;
00666
00667 arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
00668 arm_is_strong = (tune_flags & FL_STRONG) != 0;
00669 thumb_code = (TARGET_ARM == 0);
00670 arm_is_6_or_7 = (((tune_flags & (FL_MODE26 | FL_MODE32))
00671 && !(tune_flags & FL_ARCH4))) != 0;
00672
00673
00674
00675
00676
00677
00678 arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
00679
00680 if (target_fp_name)
00681 {
00682 if (streq (target_fp_name, "2"))
00683 arm_fpu_arch = FP_SOFT2;
00684 else if (streq (target_fp_name, "3"))
00685 arm_fpu_arch = FP_SOFT3;
00686 else
00687 error ("invalid floating point emulation option: -mfpe-%s",
00688 target_fp_name);
00689 }
00690 else
00691 arm_fpu_arch = FP_DEFAULT;
00692
00693 if (TARGET_FPE && arm_fpu != FP_HARD)
00694 arm_fpu = FP_SOFT2;
00695
00696
00697
00698 if ((TARGET_SOFT_FLOAT || arm_fpu != FP_HARD)
00699 && (tune_flags & FL_MODE32) == 0)
00700 flag_schedule_insns = flag_schedule_insns_after_reload = 0;
00701
00702 arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
00703
00704 if (structure_size_string != NULL)
00705 {
00706 int size = strtol (structure_size_string, NULL, 0);
00707
00708 if (size == 8 || size == 32)
00709 arm_structure_size_boundary = size;
00710 else
00711 warning ("structure size boundary can only be set to 8 or 32");
00712 }
00713
00714 if (arm_pic_register_string != NULL)
00715 {
00716 int pic_register = decode_reg_name (arm_pic_register_string);
00717
00718 if (!flag_pic)
00719 warning ("-mpic-register= is useless without -fpic");
00720
00721
00722 else if (pic_register < 0 || call_used_regs[pic_register]
00723 || pic_register == HARD_FRAME_POINTER_REGNUM
00724 || pic_register == STACK_POINTER_REGNUM
00725 || pic_register >= PC_REGNUM)
00726 error ("unable to use '%s' for PIC register", arm_pic_register_string);
00727 else
00728 arm_pic_register = pic_register;
00729 }
00730
00731 if (TARGET_THUMB && flag_schedule_insns)
00732 {
00733
00734 flag_schedule_insns = 0;
00735 }
00736
00737
00738
00739
00740 if (optimize_size || (tune_flags & FL_LDSCHED))
00741 arm_constant_limit = 1;
00742
00743 if (arm_is_xscale)
00744 arm_constant_limit = 2;
00745
00746
00747
00748
00749
00750 if (optimize_size)
00751 max_insns_skipped = 6;
00752 else if (arm_is_strong)
00753 max_insns_skipped = 3;
00754
00755
00756 arm_add_gc_roots ();
00757 }
00758
00759 static void
00760 arm_add_gc_roots ()
00761 {
00762 ggc_add_rtx_root (&arm_compare_op0, 1);
00763 ggc_add_rtx_root (&arm_compare_op1, 1);
00764 ggc_add_rtx_root (&arm_target_insn, 1);
00765
00766 gcc_obstack_init(&minipool_obstack);
00767 minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
00768 }
00769
00770
00771
00772
00773 typedef struct
00774 {
00775 const char *const arg;
00776 const unsigned long return_value;
00777 }
00778 isr_attribute_arg;
00779
00780 static const isr_attribute_arg isr_attribute_args [] =
00781 {
00782 { "IRQ", ARM_FT_ISR },
00783 { "irq", ARM_FT_ISR },
00784 { "FIQ", ARM_FT_FIQ },
00785 { "fiq", ARM_FT_FIQ },
00786 { "ABORT", ARM_FT_ISR },
00787 { "abort", ARM_FT_ISR },
00788 { "ABORT", ARM_FT_ISR },
00789 { "abort", ARM_FT_ISR },
00790 { "UNDEF", ARM_FT_EXCEPTION },
00791 { "undef", ARM_FT_EXCEPTION },
00792 { "SWI", ARM_FT_EXCEPTION },
00793 { "swi", ARM_FT_EXCEPTION },
00794 { NULL, ARM_FT_NORMAL }
00795 };
00796
00797
00798
00799
00800 static unsigned long
00801 arm_isr_value (argument)
00802 tree argument;
00803 {
00804 const isr_attribute_arg * ptr;
00805 const char * arg;
00806
00807
00808 if (argument == NULL_TREE)
00809 return ARM_FT_ISR;
00810
00811
00812 if (TREE_VALUE (argument) == NULL_TREE
00813 || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
00814 return ARM_FT_UNKNOWN;
00815
00816 arg = TREE_STRING_POINTER (TREE_VALUE (argument));
00817
00818
00819 for (ptr = isr_attribute_args; ptr->arg != NULL; ptr ++)
00820 if (streq (arg, ptr->arg))
00821 return ptr->return_value;
00822
00823
00824 return ARM_FT_UNKNOWN;
00825 }
00826
00827
00828
00829 static unsigned long
00830 arm_compute_func_type ()
00831 {
00832 unsigned long type = ARM_FT_UNKNOWN;
00833 tree a;
00834 tree attr;
00835
00836 if (TREE_CODE (current_function_decl) != FUNCTION_DECL)
00837 abort ();
00838
00839
00840
00841
00842
00843 if (optimize > 0
00844 && current_function_nothrow
00845 && TREE_THIS_VOLATILE (current_function_decl))
00846 type |= ARM_FT_VOLATILE;
00847
00848 if (current_function_needs_context)
00849 type |= ARM_FT_NESTED;
00850
00851 attr = DECL_ATTRIBUTES (current_function_decl);
00852
00853 a = lookup_attribute ("naked", attr);
00854 if (a != NULL_TREE)
00855 type |= ARM_FT_NAKED;
00856
00857 if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
00858 type |= ARM_FT_EXCEPTION_HANDLER;
00859 else
00860 {
00861 a = lookup_attribute ("isr", attr);
00862 if (a == NULL_TREE)
00863 a = lookup_attribute ("interrupt", attr);
00864
00865 if (a == NULL_TREE)
00866 type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
00867 else
00868 type |= arm_isr_value (TREE_VALUE (a));
00869 }
00870
00871 return type;
00872 }
00873
00874
00875
00876 unsigned long
00877 arm_current_func_type ()
00878 {
00879 if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
00880 cfun->machine->func_type = arm_compute_func_type ();
00881
00882 return cfun->machine->func_type;
00883 }
00884
00885
00886
00887 int
00888 use_return_insn (iscond)
00889 int iscond;
00890 {
00891 int regno;
00892 unsigned int func_type;
00893 unsigned long saved_int_regs;
00894
00895
00896 if (!reload_completed)
00897 return 0;
00898
00899 func_type = arm_current_func_type ();
00900
00901
00902
00903 if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
00904 return 0;
00905
00906
00907 if (current_function_pretend_args_size
00908 || cfun->machine->uses_anonymous_args
00909
00910 || ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
00911
00912 || ((get_frame_size () + current_function_outgoing_args_size != 0)
00913 && !frame_pointer_needed))
00914 return 0;
00915
00916 saved_int_regs = arm_compute_save_reg_mask ();
00917
00918
00919
00920 if (TARGET_INTERWORK && saved_int_regs != 0)
00921 return 0;
00922
00923
00924
00925 if (iscond && arm_is_strong)
00926 {
00927
00928
00929 if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
00930 return 0;
00931
00932 if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
00933 return 0;
00934 }
00935
00936
00937
00938 if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
00939 return 0;
00940
00941
00942
00943 if (TARGET_HARD_FLOAT)
00944 for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
00945 if (regs_ever_live[regno] && !call_used_regs[regno])
00946 return 0;
00947
00948 return 1;
00949 }
00950
00951
00952
00953 int
00954 const_ok_for_arm (i)
00955 HOST_WIDE_INT i;
00956 {
00957 unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF;
00958
00959
00960
00961 if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
00962 && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
00963 != ((~(unsigned HOST_WIDE_INT) 0)
00964 & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
00965 return FALSE;
00966
00967
00968 if ((i & (i - 1)) == 0)
00969 return TRUE;
00970
00971 do
00972 {
00973 if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
00974 return TRUE;
00975 mask =
00976 (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
00977 >> (32 - 2)) | ~(unsigned HOST_WIDE_INT) 0xffffffff;
00978 }
00979 while (mask != ~(unsigned HOST_WIDE_INT) 0xFF);
00980
00981 return FALSE;
00982 }
00983
00984
00985 static int
00986 const_ok_for_op (i, code)
00987 HOST_WIDE_INT i;
00988 enum rtx_code code;
00989 {
00990 if (const_ok_for_arm (i))
00991 return 1;
00992
00993 switch (code)
00994 {
00995 case PLUS:
00996 return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
00997
00998 case MINUS:
00999 case XOR:
01000 case IOR:
01001 return 0;
01002
01003 case AND:
01004 return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
01005
01006 default:
01007 abort ();
01008 }
01009 }
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 int
01022 arm_split_constant (code, mode, val, target, source, subtargets)
01023 enum rtx_code code;
01024 enum machine_mode mode;
01025 HOST_WIDE_INT val;
01026 rtx target;
01027 rtx source;
01028 int subtargets;
01029 {
01030 if (subtargets || code == SET
01031 || (GET_CODE (target) == REG && GET_CODE (source) == REG
01032 && REGNO (target) != REGNO (source)))
01033 {
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043 if (!after_arm_reorg
01044 && (arm_gen_constant (code, mode, val, target, source, 1, 0)
01045 > arm_constant_limit + (code != SET)))
01046 {
01047 if (code == SET)
01048 {
01049
01050
01051 emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (val)));
01052 return 1;
01053 }
01054 else
01055 {
01056 rtx temp = subtargets ? gen_reg_rtx (mode) : target;
01057
01058 emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (val)));
01059
01060
01061 if (code == MINUS)
01062 emit_insn (gen_rtx_SET (VOIDmode, target,
01063 gen_rtx_MINUS (mode, temp, source)));
01064 else
01065 emit_insn (gen_rtx_SET (VOIDmode, target,
01066 gen_rtx (code, mode, source, temp)));
01067 return 2;
01068 }
01069 }
01070 }
01071
01072 return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
01073 }
01074
01075 static int
01076 count_insns_for_constant (HOST_WIDE_INT remainder, int i)
01077 {
01078 HOST_WIDE_INT temp1;
01079 int num_insns = 0;
01080 do
01081 {
01082 int end;
01083
01084 if (i <= 0)
01085 i += 32;
01086 if (remainder & (3 << (i - 2)))
01087 {
01088 end = i - 8;
01089 if (end < 0)
01090 end += 32;
01091 temp1 = remainder & ((0x0ff << end)
01092 | ((i < end) ? (0xff >> (32 - end)) : 0));
01093 remainder &= ~temp1;
01094 num_insns++;
01095 i -= 6;
01096 }
01097 i -= 2;
01098 } while (remainder);
01099 return num_insns;
01100 }
01101
01102
01103
01104
01105 static int
01106 arm_gen_constant (code, mode, val, target, source, subtargets, generate)
01107 enum rtx_code code;
01108 enum machine_mode mode;
01109 HOST_WIDE_INT val;
01110 rtx target;
01111 rtx source;
01112 int subtargets;
01113 int generate;
01114 {
01115 int can_invert = 0;
01116 int can_negate = 0;
01117 int can_negate_initial = 0;
01118 int can_shift = 0;
01119 int i;
01120 int num_bits_set = 0;
01121 int set_sign_bit_copies = 0;
01122 int clear_sign_bit_copies = 0;
01123 int clear_zero_bit_copies = 0;
01124 int set_zero_bit_copies = 0;
01125 int insns = 0;
01126 unsigned HOST_WIDE_INT temp1, temp2;
01127 unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
01128
01129
01130
01131
01132 switch (code)
01133 {
01134 case SET:
01135 can_invert = 1;
01136 can_shift = 1;
01137 can_negate = 1;
01138 break;
01139
01140 case PLUS:
01141 can_negate = 1;
01142 can_negate_initial = 1;
01143 break;
01144
01145 case IOR:
01146 if (remainder == 0xffffffff)
01147 {
01148 if (generate)
01149 emit_insn (gen_rtx_SET (VOIDmode, target,
01150 GEN_INT (ARM_SIGN_EXTEND (val))));
01151 return 1;
01152 }
01153 if (remainder == 0)
01154 {
01155 if (reload_completed && rtx_equal_p (target, source))
01156 return 0;
01157 if (generate)
01158 emit_insn (gen_rtx_SET (VOIDmode, target, source));
01159 return 1;
01160 }
01161 break;
01162
01163 case AND:
01164 if (remainder == 0)
01165 {
01166 if (generate)
01167 emit_insn (gen_rtx_SET (VOIDmode, target, const0_rtx));
01168 return 1;
01169 }
01170 if (remainder == 0xffffffff)
01171 {
01172 if (reload_completed && rtx_equal_p (target, source))
01173 return 0;
01174 if (generate)
01175 emit_insn (gen_rtx_SET (VOIDmode, target, source));
01176 return 1;
01177 }
01178 can_invert = 1;
01179 break;
01180
01181 case XOR:
01182 if (remainder == 0)
01183 {
01184 if (reload_completed && rtx_equal_p (target, source))
01185 return 0;
01186 if (generate)
01187 emit_insn (gen_rtx_SET (VOIDmode, target, source));
01188 return 1;
01189 }
01190 if (remainder == 0xffffffff)
01191 {
01192 if (generate)
01193 emit_insn (gen_rtx_SET (VOIDmode, target,
01194 gen_rtx_NOT (mode, source)));
01195 return 1;
01196 }
01197
01198
01199 abort ();
01200
01201 case MINUS:
01202
01203
01204 if (remainder == 0)
01205 {
01206 if (generate)
01207 emit_insn (gen_rtx_SET (VOIDmode, target,
01208 gen_rtx_NEG (mode, source)));
01209 return 1;
01210 }
01211 if (const_ok_for_arm (val))
01212 {
01213 if (generate)
01214 emit_insn (gen_rtx_SET (VOIDmode, target,
01215 gen_rtx_MINUS (mode, GEN_INT (val),
01216 source)));
01217 return 1;
01218 }
01219 can_negate = 1;
01220
01221 break;
01222
01223 default:
01224 abort ();
01225 }
01226
01227
01228 if (const_ok_for_arm (val)
01229 || (can_negate_initial && const_ok_for_arm (-val))
01230 || (can_invert && const_ok_for_arm (~val)))
01231 {
01232 if (generate)
01233 emit_insn (gen_rtx_SET (VOIDmode, target,
01234 (source ? gen_rtx (code, mode, source,
01235 GEN_INT (val))
01236 : GEN_INT (val))));
01237 return 1;
01238 }
01239
01240
01241
01242 for (i = 31; i >= 0; i--)
01243 {
01244 if ((remainder & (1 << i)) == 0)
01245 clear_sign_bit_copies++;
01246 else
01247 break;
01248 }
01249
01250 for (i = 31; i >= 0; i--)
01251 {
01252 if ((remainder & (1 << i)) != 0)
01253 set_sign_bit_copies++;
01254 else
01255 break;
01256 }
01257
01258 for (i = 0; i <= 31; i++)
01259 {
01260 if ((remainder & (1 << i)) == 0)
01261 clear_zero_bit_copies++;
01262 else
01263 break;
01264 }
01265
01266 for (i = 0; i <= 31; i++)
01267 {
01268 if ((remainder & (1 << i)) != 0)
01269 set_zero_bit_copies++;
01270 else
01271 break;
01272 }
01273
01274 switch (code)
01275 {
01276 case SET:
01277
01278
01279
01280 if (set_sign_bit_copies > 1)
01281 {
01282 if (const_ok_for_arm
01283 (temp1 = ARM_SIGN_EXTEND (remainder
01284 << (set_sign_bit_copies - 1))))
01285 {
01286 if (generate)
01287 {
01288 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01289 emit_insn (gen_rtx_SET (VOIDmode, new_src,
01290 GEN_INT (temp1)));
01291 emit_insn (gen_ashrsi3 (target, new_src,
01292 GEN_INT (set_sign_bit_copies - 1)));
01293 }
01294 return 2;
01295 }
01296
01297
01298 temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
01299 if (const_ok_for_arm (~temp1))
01300 {
01301 if (generate)
01302 {
01303 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01304 emit_insn (gen_rtx_SET (VOIDmode, new_src,
01305 GEN_INT (temp1)));
01306 emit_insn (gen_ashrsi3 (target, new_src,
01307 GEN_INT (set_sign_bit_copies - 1)));
01308 }
01309 return 2;
01310 }
01311 }
01312
01313
01314
01315
01316
01317
01318 if (val & 0xffff0000)
01319 {
01320 temp1 = remainder & 0xffff0000;
01321 temp2 = remainder & 0x0000ffff;
01322
01323
01324 for (i = 9; i < 24; i++)
01325 {
01326 if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
01327 && !const_ok_for_arm (temp2))
01328 {
01329 rtx new_src = (subtargets
01330 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
01331 : target);
01332 insns = arm_gen_constant (code, mode, temp2, new_src,
01333 source, subtargets, generate);
01334 source = new_src;
01335 if (generate)
01336 emit_insn (gen_rtx_SET
01337 (VOIDmode, target,
01338 gen_rtx_IOR (mode,
01339 gen_rtx_ASHIFT (mode, source,
01340 GEN_INT (i)),
01341 source)));
01342 return insns + 1;
01343 }
01344 }
01345
01346
01347 for (i = 17; i < 24; i++)
01348 {
01349 if (((temp1 | (temp1 >> i)) == remainder)
01350 && !const_ok_for_arm (temp1))
01351 {
01352 rtx new_src = (subtargets
01353 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
01354 : target);
01355 insns = arm_gen_constant (code, mode, temp1, new_src,
01356 source, subtargets, generate);
01357 source = new_src;
01358 if (generate)
01359 emit_insn
01360 (gen_rtx_SET (VOIDmode, target,
01361 gen_rtx_IOR
01362 (mode,
01363 gen_rtx_LSHIFTRT (mode, source,
01364 GEN_INT (i)),
01365 source)));
01366 return insns + 1;
01367 }
01368 }
01369 }
01370 break;
01371
01372 case IOR:
01373 case XOR:
01374
01375
01376
01377 if (subtargets
01378
01379 || (reload_completed && !reg_mentioned_p (target, source)))
01380 {
01381 if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
01382 {
01383 if (generate)
01384 {
01385 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
01386
01387 emit_insn (gen_rtx_SET (VOIDmode, sub, GEN_INT (val)));
01388 emit_insn (gen_rtx_SET (VOIDmode, target,
01389 gen_rtx (code, mode, source, sub)));
01390 }
01391 return 2;
01392 }
01393 }
01394
01395 if (code == XOR)
01396 break;
01397
01398 if (set_sign_bit_copies > 8
01399 && (val & (-1 << (32 - set_sign_bit_copies))) == val)
01400 {
01401 if (generate)
01402 {
01403 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
01404 rtx shift = GEN_INT (set_sign_bit_copies);
01405
01406 emit_insn (gen_rtx_SET (VOIDmode, sub,
01407 gen_rtx_NOT (mode,
01408 gen_rtx_ASHIFT (mode,
01409 source,
01410 shift))));
01411 emit_insn (gen_rtx_SET (VOIDmode, target,
01412 gen_rtx_NOT (mode,
01413 gen_rtx_LSHIFTRT (mode, sub,
01414 shift))));
01415 }
01416 return 2;
01417 }
01418
01419 if (set_zero_bit_copies > 8
01420 && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
01421 {
01422 if (generate)
01423 {
01424 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
01425 rtx shift = GEN_INT (set_zero_bit_copies);
01426
01427 emit_insn (gen_rtx_SET (VOIDmode, sub,
01428 gen_rtx_NOT (mode,
01429 gen_rtx_LSHIFTRT (mode,
01430 source,
01431 shift))));
01432 emit_insn (gen_rtx_SET (VOIDmode, target,
01433 gen_rtx_NOT (mode,
01434 gen_rtx_ASHIFT (mode, sub,
01435 shift))));
01436 }
01437 return 2;
01438 }
01439
01440 if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
01441 {
01442 if (generate)
01443 {
01444 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
01445 emit_insn (gen_rtx_SET (VOIDmode, sub,
01446 gen_rtx_NOT (mode, source)));
01447 source = sub;
01448 if (subtargets)
01449 sub = gen_reg_rtx (mode);
01450 emit_insn (gen_rtx_SET (VOIDmode, sub,
01451 gen_rtx_AND (mode, source,
01452 GEN_INT (temp1))));
01453 emit_insn (gen_rtx_SET (VOIDmode, target,
01454 gen_rtx_NOT (mode, sub)));
01455 }
01456 return 3;
01457 }
01458 break;
01459
01460 case AND:
01461
01462 if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
01463 {
01464 HOST_WIDE_INT shift_mask = ((0xffffffff
01465 << (32 - clear_sign_bit_copies))
01466 & 0xffffffff);
01467
01468 if ((remainder | shift_mask) != 0xffffffff)
01469 {
01470 if (generate)
01471 {
01472 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01473 insns = arm_gen_constant (AND, mode, remainder | shift_mask,
01474 new_src, source, subtargets, 1);
01475 source = new_src;
01476 }
01477 else
01478 {
01479 rtx targ = subtargets ? NULL_RTX : target;
01480 insns = arm_gen_constant (AND, mode, remainder | shift_mask,
01481 targ, source, subtargets, 0);
01482 }
01483 }
01484
01485 if (generate)
01486 {
01487 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01488 rtx shift = GEN_INT (clear_sign_bit_copies);
01489
01490 emit_insn (gen_ashlsi3 (new_src, source, shift));
01491 emit_insn (gen_lshrsi3 (target, new_src, shift));
01492 }
01493
01494 return insns + 2;
01495 }
01496
01497 if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
01498 {
01499 HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
01500
01501 if ((remainder | shift_mask) != 0xffffffff)
01502 {
01503 if (generate)
01504 {
01505 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01506
01507 insns = arm_gen_constant (AND, mode, remainder | shift_mask,
01508 new_src, source, subtargets, 1);
01509 source = new_src;
01510 }
01511 else
01512 {
01513 rtx targ = subtargets ? NULL_RTX : target;
01514
01515 insns = arm_gen_constant (AND, mode, remainder | shift_mask,
01516 targ, source, subtargets, 0);
01517 }
01518 }
01519
01520 if (generate)
01521 {
01522 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01523 rtx shift = GEN_INT (clear_zero_bit_copies);
01524
01525 emit_insn (gen_lshrsi3 (new_src, source, shift));
01526 emit_insn (gen_ashlsi3 (target, new_src, shift));
01527 }
01528
01529 return insns + 2;
01530 }
01531
01532 break;
01533
01534 default:
01535 break;
01536 }
01537
01538 for (i = 0; i < 32; i++)
01539 if (remainder & (1 << i))
01540 num_bits_set++;
01541
01542 if (code == AND || (can_invert && num_bits_set > 16))
01543 remainder = (~remainder) & 0xffffffff;
01544 else if (code == PLUS && num_bits_set > 16)
01545 remainder = (-remainder) & 0xffffffff;
01546 else
01547 {
01548 can_invert = 0;
01549 can_negate = 0;
01550 }
01551
01552
01553
01554
01555
01556
01557
01558 {
01559 int best_start = 0;
01560 int best_consecutive_zeros = 0;
01561
01562 for (i = 0; i < 32; i += 2)
01563 {
01564 int consecutive_zeros = 0;
01565
01566 if (!(remainder & (3 << i)))
01567 {
01568 while ((i < 32) && !(remainder & (3 << i)))
01569 {
01570 consecutive_zeros += 2;
01571 i += 2;
01572 }
01573 if (consecutive_zeros > best_consecutive_zeros)
01574 {
01575 best_consecutive_zeros = consecutive_zeros;
01576 best_start = i - consecutive_zeros;
01577 }
01578 i -= 2;
01579 }
01580 }
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605 if (best_start != 0
01606 && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
01607 && (count_insns_for_constant (remainder, 0) <=
01608 count_insns_for_constant (remainder, best_start)))
01609 best_start = 0;
01610
01611
01612 i = best_start;
01613 do
01614 {
01615 int end;
01616
01617 if (i <= 0)
01618 i += 32;
01619 if (remainder & (3 << (i - 2)))
01620 {
01621 end = i - 8;
01622 if (end < 0)
01623 end += 32;
01624 temp1 = remainder & ((0x0ff << end)
01625 | ((i < end) ? (0xff >> (32 - end)) : 0));
01626 remainder &= ~temp1;
01627
01628 if (generate)
01629 {
01630 rtx new_src, temp1_rtx;
01631
01632 if (code == SET || code == MINUS)
01633 {
01634 new_src = (subtargets ? gen_reg_rtx (mode) : target);
01635 if (can_invert && code != MINUS)
01636 temp1 = ~temp1;
01637 }
01638 else
01639 {
01640 if (remainder && subtargets)
01641 new_src = gen_reg_rtx (mode);
01642 else
01643 new_src = target;
01644 if (can_invert)
01645 temp1 = ~temp1;
01646 else if (can_negate)
01647 temp1 = -temp1;
01648 }
01649
01650 temp1 = trunc_int_for_mode (temp1, mode);
01651 temp1_rtx = GEN_INT (temp1);
01652
01653 if (code == SET)
01654 ;
01655 else if (code == MINUS)
01656 temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
01657 else
01658 temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
01659
01660 emit_insn (gen_rtx_SET (VOIDmode, new_src, temp1_rtx));
01661 source = new_src;
01662 }
01663
01664 if (code == SET)
01665 {
01666 can_invert = 0;
01667 code = PLUS;
01668 }
01669 else if (code == MINUS)
01670 code = PLUS;
01671
01672 insns++;
01673 i -= 6;
01674 }
01675 i -= 2;
01676 }
01677 while (remainder);
01678 }
01679
01680 return insns;
01681 }
01682
01683
01684
01685
01686
01687 enum rtx_code
01688 arm_canonicalize_comparison (code, op1)
01689 enum rtx_code code;
01690 rtx * op1;
01691 {
01692 unsigned HOST_WIDE_INT i = INTVAL (*op1);
01693
01694 switch (code)
01695 {
01696 case EQ:
01697 case NE:
01698 return code;
01699
01700 case GT:
01701 case LE:
01702 if (i != ((((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) - 1)
01703 && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
01704 {
01705 *op1 = GEN_INT (i + 1);
01706 return code == GT ? GE : LT;
01707 }
01708 break;
01709
01710 case GE:
01711 case LT:
01712 if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1))
01713 && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
01714 {
01715 *op1 = GEN_INT (i - 1);
01716 return code == GE ? GT : LE;
01717 }
01718 break;
01719
01720 case GTU:
01721 case LEU:
01722 if (i != ~((unsigned HOST_WIDE_INT) 0)
01723 && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
01724 {
01725 *op1 = GEN_INT (i + 1);
01726 return code == GTU ? GEU : LTU;
01727 }
01728 break;
01729
01730 case GEU:
01731 case LTU:
01732 if (i != 0
01733 && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
01734 {
01735 *op1 = GEN_INT (i - 1);
01736 return code == GEU ? GTU : LEU;
01737 }
01738 break;
01739
01740 default:
01741 abort ();
01742 }
01743
01744 return code;
01745 }
01746
01747
01748
01749
01750
01751 int
01752 arm_return_in_memory (type)
01753 tree type;
01754 {
01755 if (!AGGREGATE_TYPE_P (type))
01756
01757 return 0;
01758
01759
01760
01761 #ifndef ARM_WINCE
01762
01763
01764
01765
01766 if (((unsigned int) int_size_in_bytes (type)) > UNITS_PER_WORD)
01767 return 1;
01768
01769 if (TREE_CODE (type) == RECORD_TYPE)
01770 {
01771 tree field;
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781 for (field = TYPE_FIELDS (type);
01782 field && TREE_CODE (field) != FIELD_DECL;
01783 field = TREE_CHAIN (field))
01784 continue;
01785
01786 if (field == NULL)
01787 return 0;
01788
01789
01790
01791
01792 if (FLOAT_TYPE_P (TREE_TYPE (field)))
01793 return 1;
01794
01795
01796
01797 if (RETURN_IN_MEMORY (TREE_TYPE (field)))
01798 return 1;
01799
01800
01801
01802 for (field = TREE_CHAIN (field);
01803 field;
01804 field = TREE_CHAIN (field))
01805 {
01806 if (TREE_CODE (field) != FIELD_DECL)
01807 continue;
01808
01809 if (!DECL_BIT_FIELD_TYPE (field))
01810 return 1;
01811 }
01812
01813 return 0;
01814 }
01815
01816 if (TREE_CODE (type) == UNION_TYPE)
01817 {
01818 tree field;
01819
01820
01821
01822 for (field = TYPE_FIELDS (type);
01823 field;
01824 field = TREE_CHAIN (field))
01825 {
01826 if (TREE_CODE (field) != FIELD_DECL)
01827 continue;
01828
01829 if (FLOAT_TYPE_P (TREE_TYPE (field)))
01830 return 1;
01831
01832 if (RETURN_IN_MEMORY (TREE_TYPE (field)))
01833 return 1;
01834 }
01835
01836 return 0;
01837 }
01838 #endif
01839
01840
01841 return 1;
01842 }
01843
01844
01845
01846
01847 void
01848 arm_init_cumulative_args (pcum, fntype, libname, indirect)
01849 CUMULATIVE_ARGS * pcum;
01850 tree fntype;
01851 rtx libname ATTRIBUTE_UNUSED;
01852 int indirect ATTRIBUTE_UNUSED;
01853 {
01854
01855 pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0);
01856
01857 pcum->call_cookie = CALL_NORMAL;
01858
01859 if (TARGET_LONG_CALLS)
01860 pcum->call_cookie = CALL_LONG;
01861
01862
01863
01864 if (fntype)
01865 {
01866 if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
01867 pcum->call_cookie = CALL_SHORT;
01868 else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
01869 pcum->call_cookie = CALL_LONG;
01870 }
01871 }
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886 rtx
01887 arm_function_arg (pcum, mode, type, named)
01888 CUMULATIVE_ARGS * pcum;
01889 enum machine_mode mode;
01890 tree type ATTRIBUTE_UNUSED;
01891 int named;
01892 {
01893 if (mode == VOIDmode)
01894
01895 return GEN_INT (pcum->call_cookie);
01896
01897 if (!named || pcum->nregs >= NUM_ARG_REGS)
01898 return NULL_RTX;
01899
01900 return gen_rtx_REG (mode, pcum->nregs);
01901 }
01902
01903
01904 typedef enum
01905 {
01906 OFF,
01907 LONG,
01908 SHORT
01909 } arm_pragma_enum;
01910
01911 static arm_pragma_enum arm_pragma_long_calls = OFF;
01912
01913 void
01914 arm_pr_long_calls (pfile)
01915 cpp_reader * pfile ATTRIBUTE_UNUSED;
01916 {
01917 arm_pragma_long_calls = LONG;
01918 }
01919
01920 void
01921 arm_pr_no_long_calls (pfile)
01922 cpp_reader * pfile ATTRIBUTE_UNUSED;
01923 {
01924 arm_pragma_long_calls = SHORT;
01925 }
01926
01927 void
01928 arm_pr_long_calls_off (pfile)
01929 cpp_reader * pfile ATTRIBUTE_UNUSED;
01930 {
01931 arm_pragma_long_calls = OFF;
01932 }
01933
01934
01935 const struct attribute_spec arm_attribute_table[] =
01936 {
01937
01938
01939
01940
01941 { "long_call", 0, 0, false, true, true, NULL },
01942
01943
01944 { "short_call", 0, 0, false, true, true, NULL },
01945
01946 { "isr", 0, 1, false, false, false, arm_handle_isr_attribute },
01947 { "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute },
01948 { "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute },
01949 #ifdef ARM_PE
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959 { "dllimport", 0, 0, true, false, false, NULL },
01960 { "dllexport", 0, 0, true, false, false, NULL },
01961 { "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute },
01962 #endif
01963 { NULL, 0, 0, false, false, false, NULL }
01964 };
01965
01966
01967
01968
01969 static tree
01970 arm_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
01971 tree * node;
01972 tree name;
01973 tree args ATTRIBUTE_UNUSED;
01974 int flags ATTRIBUTE_UNUSED;
01975 bool * no_add_attrs;
01976 {
01977 if (TREE_CODE (*node) != FUNCTION_DECL)
01978 {
01979 warning ("`%s' attribute only applies to functions",
01980 IDENTIFIER_POINTER (name));
01981 *no_add_attrs = true;
01982 }
01983
01984 return NULL_TREE;
01985 }
01986
01987
01988
01989
01990 static tree
01991 arm_handle_isr_attribute (node, name, args, flags, no_add_attrs)
01992 tree * node;
01993 tree name;
01994 tree args;
01995 int flags;
01996 bool * no_add_attrs;
01997 {
01998 if (DECL_P (*node))
01999 {
02000 if (TREE_CODE (*node) != FUNCTION_DECL)
02001 {
02002 warning ("`%s' attribute only applies to functions",
02003 IDENTIFIER_POINTER (name));
02004 *no_add_attrs = true;
02005 }
02006
02007
02008 }
02009 else
02010 {
02011 if (TREE_CODE (*node) == FUNCTION_TYPE
02012 || TREE_CODE (*node) == METHOD_TYPE)
02013 {
02014 if (arm_isr_value (args) == ARM_FT_UNKNOWN)
02015 {
02016 warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
02017 *no_add_attrs = true;
02018 }
02019 }
02020 else if (TREE_CODE (*node) == POINTER_TYPE
02021 && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
02022 || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
02023 && arm_isr_value (args) != ARM_FT_UNKNOWN)
02024 {
02025 *node = build_type_copy (*node);
02026 TREE_TYPE (*node) = build_type_attribute_variant
02027 (TREE_TYPE (*node),
02028 tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
02029 *no_add_attrs = true;
02030 }
02031 else
02032 {
02033
02034 if (flags & ((int) ATTR_FLAG_DECL_NEXT
02035 | (int) ATTR_FLAG_FUNCTION_NEXT
02036 | (int) ATTR_FLAG_ARRAY_NEXT))
02037 {
02038 *no_add_attrs = true;
02039 return tree_cons (name, args, NULL_TREE);
02040 }
02041 else
02042 {
02043 warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
02044 }
02045 }
02046 }
02047
02048 return NULL_TREE;
02049 }
02050
02051
02052
02053
02054
02055 static int
02056 arm_comp_type_attributes (type1, type2)
02057 tree type1;
02058 tree type2;
02059 {
02060 int l1, l2, s1, s2;
02061
02062
02063 if (TREE_CODE (type1) != FUNCTION_TYPE)
02064 return 1;
02065
02066
02067 l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
02068 l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
02069 s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
02070 s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
02071
02072
02073 if (l1 | l2 | s1 | s2)
02074 {
02075
02076 if ((l1 != l2) || (s1 != s2))
02077 return 0;
02078
02079
02080 if ((l1 & s2) || (l2 & s1))
02081 return 0;
02082 }
02083
02084
02085 l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
02086 if (! l1)
02087 l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
02088 l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
02089 if (! l2)
02090 l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
02091 if (l1 != l2)
02092 return 0;
02093
02094 return 1;
02095 }
02096
02097
02098
02099
02100 void
02101 arm_encode_call_attribute (decl, flag)
02102 tree decl;
02103 int flag;
02104 {
02105 const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
02106 int len = strlen (str);
02107 char * newstr;
02108
02109
02110 if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
02111 return;
02112
02113 newstr = alloca (len + 2);
02114 newstr[0] = flag;
02115 strcpy (newstr + 1, str);
02116
02117 newstr = (char *) ggc_alloc_string (newstr, len + 1);
02118 XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
02119 }
02120
02121
02122
02123
02124
02125 static void
02126 arm_set_default_type_attributes (type)
02127 tree type;
02128 {
02129
02130
02131
02132 if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
02133 {
02134 tree type_attr_list, attr_name;
02135 type_attr_list = TYPE_ATTRIBUTES (type);
02136
02137 if (arm_pragma_long_calls == LONG)
02138 attr_name = get_identifier ("long_call");
02139 else if (arm_pragma_long_calls == SHORT)
02140 attr_name = get_identifier ("short_call");
02141 else
02142 return;
02143
02144 type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
02145 TYPE_ATTRIBUTES (type) = type_attr_list;
02146 }
02147 }
02148
02149
02150
02151
02152
02153 static int
02154 current_file_function_operand (sym_ref)
02155 rtx sym_ref;
02156 {
02157
02158
02159
02160 if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
02161 return 1;
02162
02163
02164
02165
02166 if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
02167 && !DECL_WEAK (current_function_decl))
02168 return 1;
02169
02170
02171 return 0;
02172 }
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190
02191
02192
02193
02194
02195
02196 int
02197 arm_is_longcall_p (sym_ref, call_cookie, call_symbol)
02198 rtx sym_ref;
02199 int call_cookie;
02200 int call_symbol;
02201 {
02202 if (!call_symbol)
02203 {
02204 if (GET_CODE (sym_ref) != MEM)
02205 return 0;
02206
02207 sym_ref = XEXP (sym_ref, 0);
02208 }
02209
02210 if (GET_CODE (sym_ref) != SYMBOL_REF)
02211 return 0;
02212
02213 if (call_cookie & CALL_SHORT)
02214 return 0;
02215
02216 if (TARGET_LONG_CALLS && flag_function_sections)
02217 return 1;
02218
02219 if (current_file_function_operand (sym_ref))
02220 return 0;
02221
02222 return (call_cookie & CALL_LONG)
02223 || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
02224 || TARGET_LONG_CALLS;
02225 }
02226
02227
02228
02229 int
02230 arm_function_ok_for_sibcall (decl)
02231 tree decl;
02232 {
02233 int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
02234
02235
02236
02237 if (decl == NULL || TARGET_THUMB)
02238 return 0;
02239
02240
02241 if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
02242 call_type = CALL_SHORT;
02243 else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
02244 call_type = CALL_LONG;
02245
02246
02247
02248
02249 if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
02250 return 0;
02251
02252
02253
02254
02255 if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
02256 return 0;
02257
02258
02259 if (IS_INTERRUPT (arm_current_func_type ()))
02260 return 0;
02261
02262
02263 return 1;
02264 }
02265
02266
02267 int
02268 legitimate_pic_operand_p (x)
02269 rtx x;
02270 {
02271 if (CONSTANT_P (x)
02272 && flag_pic
02273 && (GET_CODE (x) == SYMBOL_REF
02274 || (GET_CODE (x) == CONST
02275 && GET_CODE (XEXP (x, 0)) == PLUS
02276 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)))
02277 return 0;
02278
02279 return 1;
02280 }
02281
02282 rtx
02283 legitimize_pic_address (orig, mode, reg)
02284 rtx orig;
02285 enum machine_mode mode;
02286 rtx reg;
02287 {
02288 if (GET_CODE (orig) == SYMBOL_REF
02289 || GET_CODE (orig) == LABEL_REF)
02290 {
02291 #ifndef AOF_ASSEMBLER
02292 rtx pic_ref, address;
02293 #endif
02294 rtx insn;
02295 int subregs = 0;
02296
02297 if (reg == 0)
02298 {
02299 if (no_new_pseudos)
02300 abort ();
02301 else
02302 reg = gen_reg_rtx (Pmode);
02303
02304 subregs = 1;
02305 }
02306
02307 #ifdef AOF_ASSEMBLER
02308
02309
02310 insn = emit_insn (gen_pic_load_addr_based (reg, orig));
02311 #else
02312 if (subregs)
02313 address = gen_reg_rtx (Pmode);
02314 else
02315 address = reg;
02316
02317 if (TARGET_ARM)
02318 emit_insn (gen_pic_load_addr_arm (address, orig));
02319 else
02320 emit_insn (gen_pic_load_addr_thumb (address, orig));
02321
02322 if ((GET_CODE (orig) == LABEL_REF
02323 || (GET_CODE (orig) == SYMBOL_REF &&
02324 ENCODED_SHORT_CALL_ATTR_P (XSTR (orig, 0))))
02325 && NEED_GOT_RELOC)
02326 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
02327 else
02328 {
02329 pic_ref = gen_rtx_MEM (Pmode,
02330 gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
02331 address));
02332 RTX_UNCHANGING_P (pic_ref) = 1;
02333 }
02334
02335 insn = emit_move_insn (reg, pic_ref);
02336 #endif
02337 current_function_uses_pic_offset_table = 1;
02338
02339
02340 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
02341 REG_NOTES (insn));
02342 return reg;
02343 }
02344 else if (GET_CODE (orig) == CONST)
02345 {
02346 rtx base, offset;
02347
02348 if (GET_CODE (XEXP (orig, 0)) == PLUS
02349 && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
02350 return orig;
02351
02352 if (reg == 0)
02353 {
02354 if (no_new_pseudos)
02355 abort ();
02356 else
02357 reg = gen_reg_rtx (Pmode);
02358 }
02359
02360 if (GET_CODE (XEXP (orig, 0)) == PLUS)
02361 {
02362 base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
02363 offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
02364 base == reg ? 0 : reg);
02365 }
02366 else
02367 abort ();
02368
02369 if (GET_CODE (offset) == CONST_INT)
02370 {
02371
02372
02373 ARM_GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win);
02374
02375 if (!no_new_pseudos)
02376 offset = force_reg (Pmode, offset);
02377 else
02378 abort ();
02379
02380 win:
02381 if (GET_CODE (offset) == CONST_INT)
02382 return plus_constant (base, INTVAL (offset));
02383 }
02384
02385 if (GET_MODE_SIZE (mode) > 4
02386 && (GET_MODE_CLASS (mode) == MODE_INT
02387 || TARGET_SOFT_FLOAT))
02388 {
02389 emit_insn (gen_addsi3 (reg, base, offset));
02390 return reg;
02391 }
02392
02393 return gen_rtx_PLUS (Pmode, base, offset);
02394 }
02395
02396 return orig;
02397 }
02398
02399
02400
02401
02402
02403
02404
02405 void
02406 arm_finalize_pic (prologue)
02407 int prologue ATTRIBUTE_UNUSED;
02408 {
02409 #ifndef AOF_ASSEMBLER
02410 rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
02411 rtx global_offset_table;
02412
02413 if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
02414 return;
02415
02416 if (!flag_pic)
02417 abort ();
02418
02419 start_sequence ();
02420 l1 = gen_label_rtx ();
02421
02422 global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
02423
02424
02425 pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), TARGET_ARM ? 8 : 4);
02426 if (GOT_PCREL)
02427 pic_tmp2 = gen_rtx_CONST (VOIDmode,
02428 gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
02429 else
02430 pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
02431
02432 pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
02433
02434 if (TARGET_ARM)
02435 {
02436 emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx));
02437 emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1));
02438 }
02439 else
02440 {
02441 emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx));
02442 emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
02443 }
02444
02445 seq = gen_sequence ();
02446 end_sequence ();
02447 if (prologue)
02448 emit_insn_after (seq, get_insns ());
02449 else
02450 emit_insn (seq);
02451
02452
02453
02454 emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
02455 #endif
02456 }
02457
02458 #define REG_OR_SUBREG_REG(X) \
02459 (GET_CODE (X) == REG \
02460 || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
02461
02462 #define REG_OR_SUBREG_RTX(X) \
02463 (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
02464
02465 #ifndef COSTS_N_INSNS
02466 #define COSTS_N_INSNS(N) ((N) * 4 - 2)
02467 #endif
02468
02469 int
02470 arm_rtx_costs (x, code, outer)
02471 rtx x;
02472 enum rtx_code code;
02473 enum rtx_code outer;
02474 {
02475 enum machine_mode mode = GET_MODE (x);
02476 enum rtx_code subcode;
02477 int extra_cost;
02478
02479 if (TARGET_THUMB)
02480 {
02481 switch (code)
02482 {
02483 case ASHIFT:
02484 case ASHIFTRT:
02485 case LSHIFTRT:
02486 case ROTATERT:
02487 case PLUS:
02488 case MINUS:
02489 case COMPARE:
02490 case NEG:
02491 case NOT:
02492 return COSTS_N_INSNS (1);
02493
02494 case MULT:
02495 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
02496 {
02497 int cycles = 0;
02498 unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
02499
02500 while (i)
02501 {
02502 i >>= 2;
02503 cycles++;
02504 }
02505 return COSTS_N_INSNS (2) + cycles;
02506 }
02507 return COSTS_N_INSNS (1) + 16;
02508
02509 case SET:
02510 return (COSTS_N_INSNS (1)
02511 + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
02512 + GET_CODE (SET_DEST (x)) == MEM));
02513
02514 case CONST_INT:
02515 if (outer == SET)
02516 {
02517 if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
02518 return 0;
02519 if (thumb_shiftable_const (INTVAL (x)))
02520 return COSTS_N_INSNS (2);
02521 return COSTS_N_INSNS (3);
02522 }
02523 else if (outer == PLUS
02524 && INTVAL (x) < 256 && INTVAL (x) > -256)
02525 return 0;
02526 else if (outer == COMPARE
02527 && (unsigned HOST_WIDE_INT) INTVAL (x) < 256)
02528 return 0;
02529 else if (outer == ASHIFT || outer == ASHIFTRT
02530 || outer == LSHIFTRT)
02531 return 0;
02532 return COSTS_N_INSNS (2);
02533
02534 case CONST:
02535 case CONST_DOUBLE:
02536 case LABEL_REF:
02537 case SYMBOL_REF:
02538 return COSTS_N_INSNS (3);
02539
02540 case UDIV:
02541 case UMOD:
02542 case DIV:
02543 case MOD:
02544 return 100;
02545
02546 case TRUNCATE:
02547 return 99;
02548
02549 case AND:
02550 case XOR:
02551 case IOR:
02552
02553 return 8;
02554
02555 case ADDRESSOF:
02556 case MEM:
02557
02558
02559
02560 return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
02561 + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
02562
02563 case IF_THEN_ELSE:
02564
02565 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
02566 return 14;
02567 return 2;
02568
02569 case ZERO_EXTEND:
02570
02571 switch (GET_MODE (XEXP (x, 0)))
02572 {
02573 case QImode:
02574 return (1 + (mode == DImode ? 4 : 0)
02575 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02576
02577 case HImode:
02578 return (4 + (mode == DImode ? 4 : 0)
02579 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02580
02581 case SImode:
02582 return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02583
02584 default:
02585 return 99;
02586 }
02587
02588 default:
02589 return 99;
02590 #if 0
02591 case FFS:
02592 case FLOAT:
02593 case FIX:
02594 case UNSIGNED_FIX:
02595
02596 fprintf (stderr, "unexpected code for thumb in rtx_costs: %s\n",
02597 rtx_name[code]);
02598 abort ();
02599 #endif
02600 }
02601 }
02602
02603 switch (code)
02604 {
02605 case MEM:
02606
02607
02608 return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
02609 + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
02610
02611 case DIV:
02612 case MOD:
02613 return 100;
02614
02615 case ROTATE:
02616 if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
02617 return 4;
02618
02619 case ROTATERT:
02620 if (mode != SImode)
02621 return 8;
02622
02623 case ASHIFT: case LSHIFTRT: case ASHIFTRT:
02624 if (mode == DImode)
02625 return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
02626 + ((GET_CODE (XEXP (x, 0)) == REG
02627 || (GET_CODE (XEXP (x, 0)) == SUBREG
02628 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
02629 ? 0 : 8));
02630 return (1 + ((GET_CODE (XEXP (x, 0)) == REG
02631 || (GET_CODE (XEXP (x, 0)) == SUBREG
02632 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
02633 ? 0 : 4)
02634 + ((GET_CODE (XEXP (x, 1)) == REG
02635 || (GET_CODE (XEXP (x, 1)) == SUBREG
02636 && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
02637 || (GET_CODE (XEXP (x, 1)) == CONST_INT))
02638 ? 0 : 4));
02639
02640 case MINUS:
02641 if (mode == DImode)
02642 return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
02643 + ((REG_OR_SUBREG_REG (XEXP (x, 0))
02644 || (GET_CODE (XEXP (x, 0)) == CONST_INT
02645 && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
02646 ? 0 : 8));
02647
02648 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
02649 return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
02650 || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
02651 && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
02652 ? 0 : 8)
02653 + ((REG_OR_SUBREG_REG (XEXP (x, 0))
02654 || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
02655 && const_double_rtx_ok_for_fpu (XEXP (x, 0))))
02656 ? 0 : 8));
02657
02658 if (((GET_CODE (XEXP (x, 0)) == CONST_INT
02659 && const_ok_for_arm (INTVAL (XEXP (x, 0)))
02660 && REG_OR_SUBREG_REG (XEXP (x, 1))))
02661 || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
02662 || subcode == ASHIFTRT || subcode == LSHIFTRT
02663 || subcode == ROTATE || subcode == ROTATERT
02664 || (subcode == MULT
02665 && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
02666 && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
02667 (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
02668 && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
02669 && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
02670 || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
02671 && REG_OR_SUBREG_REG (XEXP (x, 0))))
02672 return 1;
02673
02674
02675 case PLUS:
02676 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
02677 return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
02678 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
02679 || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
02680 && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
02681 ? 0 : 8));
02682
02683
02684 case AND: case XOR: case IOR:
02685 extra_cost = 0;
02686
02687
02688
02689
02690
02691
02692 if ((REG_OR_SUBREG_REG (XEXP (x, 0))
02693 && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
02694 && GET_CODE (XEXP (x, 1)) != CONST_INT)
02695 || (REG_OR_SUBREG_REG (XEXP (x, 0))
02696 && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
02697 extra_cost = 4;
02698
02699 if (mode == DImode)
02700 return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
02701 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
02702 || (GET_CODE (XEXP (x, 1)) == CONST_INT
02703 && const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
02704 ? 0 : 8));
02705
02706 if (REG_OR_SUBREG_REG (XEXP (x, 0)))
02707 return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
02708 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
02709 || (GET_CODE (XEXP (x, 1)) == CONST_INT
02710 && const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
02711 ? 0 : 4));
02712
02713 else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
02714 return (1 + extra_cost
02715 + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
02716 || subcode == LSHIFTRT || subcode == ASHIFTRT
02717 || subcode == ROTATE || subcode == ROTATERT
02718 || (subcode == MULT
02719 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
02720 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
02721 (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
02722 && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
02723 && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
02724 || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
02725 ? 0 : 4));
02726
02727 return 8;
02728
02729 case MULT:
02730
02731
02732 if (arm_fast_multiply && mode == DImode
02733 && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
02734 && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
02735 || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
02736 return 8;
02737
02738 if (GET_MODE_CLASS (mode) == MODE_FLOAT
02739 || mode == DImode)
02740 return 30;
02741
02742 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
02743 {
02744 unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
02745 & (unsigned HOST_WIDE_INT) 0xffffffff);
02746 int add_cost = const_ok_for_arm (i) ? 4 : 8;
02747 int j;
02748
02749
02750 int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
02751
02752 for (j = 0; i && j < 32; j += booth_unit_size)
02753 {
02754 i >>= booth_unit_size;
02755 add_cost += 2;
02756 }
02757
02758 return add_cost;
02759 }
02760
02761 return (((tune_flags & FL_FAST_MULT) ? 8 : 30)
02762 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
02763 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4));
02764
02765 case TRUNCATE:
02766 if (arm_fast_multiply && mode == SImode
02767 && GET_CODE (XEXP (x, 0)) == LSHIFTRT
02768 && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
02769 && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
02770 == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
02771 && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
02772 || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
02773 return 8;
02774 return 99;
02775
02776 case NEG:
02777 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
02778 return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
02779
02780 case NOT:
02781 if (mode == DImode)
02782 return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
02783
02784 return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
02785
02786 case IF_THEN_ELSE:
02787 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
02788 return 14;
02789 return 2;
02790
02791 case COMPARE:
02792 return 1;
02793
02794 case ABS:
02795 return 4 + (mode == DImode ? 4 : 0);
02796
02797 case SIGN_EXTEND:
02798 if (GET_MODE (XEXP (x, 0)) == QImode)
02799 return (4 + (mode == DImode ? 4 : 0)
02800 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02801
02802 case ZERO_EXTEND:
02803 switch (GET_MODE (XEXP (x, 0)))
02804 {
02805 case QImode:
02806 return (1 + (mode == DImode ? 4 : 0)
02807 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02808
02809 case HImode:
02810 return (4 + (mode == DImode ? 4 : 0)
02811 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02812
02813 case SImode:
02814 return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
02815
02816 default:
02817 break;
02818 }
02819 abort ();
02820
02821 case CONST_INT:
02822 if (const_ok_for_arm (INTVAL (x)))
02823 return outer == SET ? 2 : -1;
02824 else if (outer == AND
02825 && const_ok_for_arm (~INTVAL (x)))
02826 return -1;
02827 else if ((outer == COMPARE
02828 || outer == PLUS || outer == MINUS)
02829 && const_ok_for_arm (-INTVAL (x)))
02830 return -1;
02831 else
02832 return 5;
02833
02834 case CONST:
02835 case LABEL_REF:
02836 case SYMBOL_REF:
02837 return 6;
02838
02839 case CONST_DOUBLE:
02840 if (const_double_rtx_ok_for_fpu (x))
02841 return outer == SET ? 2 : -1;
02842 else if ((outer == COMPARE || outer == PLUS)
02843 && neg_const_double_rtx_ok_for_fpu (x))
02844 return -1;
02845 return 7;
02846
02847 default:
02848 return 99;
02849 }
02850 }
02851
02852 static int
02853 arm_adjust_cost (insn, link, dep, cost)
02854 rtx insn;
02855 rtx link;
02856 rtx dep;
02857 int cost;
02858 {
02859 rtx i_pat, d_pat;
02860
02861
02862
02863 if (arm_is_xscale
02864 && REG_NOTE_KIND (link) == 0
02865 && recog_memoized (insn) < 0
02866 && recog_memoized (dep) < 0)
02867 {
02868 int shift_opnum = get_attr_shift (insn);
02869 enum attr_type attr_type = get_attr_type (dep);
02870
02871
02872
02873
02874
02875 if (shift_opnum != 0 && attr_type == TYPE_NORMAL)
02876 {
02877 rtx shifted_operand;
02878 int opno;
02879
02880
02881 extract_insn (insn);
02882 shifted_operand = recog_data.operand[shift_opnum];
02883
02884
02885
02886
02887 extract_insn (dep);
02888 preprocess_constraints ();
02889 for (opno = 0; opno < recog_data.n_operands; opno++)
02890 {
02891
02892 if (recog_data.operand_type[opno] == OP_IN)
02893 continue;
02894
02895 if (reg_overlap_mentioned_p (recog_data.operand[opno],
02896 shifted_operand))
02897 return 2;
02898 }
02899 }
02900 }
02901
02902
02903 if (REG_NOTE_KIND (link) == REG_DEP_ANTI
02904 || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
02905 return 0;
02906
02907
02908 if (REG_NOTE_KIND (link) == 0
02909 && GET_CODE (insn) == CALL_INSN)
02910 return 1;
02911
02912 if ((i_pat = single_set (insn)) != NULL
02913 && GET_CODE (SET_SRC (i_pat)) == MEM
02914 && (d_pat = single_set (dep)) != NULL
02915 && GET_CODE (SET_DEST (d_pat)) == MEM)
02916 {
02917
02918
02919
02920
02921
02922 if (CONSTANT_POOL_ADDRESS_P (XEXP (SET_SRC (i_pat), 0))
02923 || reg_mentioned_p (stack_pointer_rtx, XEXP (SET_SRC (i_pat), 0))
02924 || reg_mentioned_p (frame_pointer_rtx, XEXP (SET_SRC (i_pat), 0))
02925 || reg_mentioned_p (hard_frame_pointer_rtx,
02926 XEXP (SET_SRC (i_pat), 0)))
02927 return 1;
02928 }
02929
02930 return cost;
02931 }
02932
02933
02934
02935 static int fpa_consts_inited = 0;
02936
02937 static const char * const strings_fpa[8] =
02938 {
02939 "0", "1", "2", "3",
02940 "4", "5", "0.5", "10"
02941 };
02942
02943 static REAL_VALUE_TYPE values_fpa[8];
02944
02945 static void
02946 init_fpa_table ()
02947 {
02948 int i;
02949 REAL_VALUE_TYPE r;
02950
02951 for (i = 0; i < 8; i++)
02952 {
02953 r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
02954 values_fpa[i] = r;
02955 }
02956
02957 fpa_consts_inited = 1;
02958 }
02959
02960
02961
02962 int
02963 const_double_rtx_ok_for_fpu (x)
02964 rtx x;
02965 {
02966 REAL_VALUE_TYPE r;
02967 int i;
02968
02969 if (!fpa_consts_inited)
02970 init_fpa_table ();
02971
02972 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
02973 if (REAL_VALUE_MINUS_ZERO (r))
02974 return 0;
02975
02976 for (i = 0; i < 8; i++)
02977 if (REAL_VALUES_EQUAL (r, values_fpa[i]))
02978 return 1;
02979
02980 return 0;
02981 }
02982
02983
02984
02985 int
02986 neg_const_double_rtx_ok_for_fpu (x)
02987 rtx x;
02988 {
02989 REAL_VALUE_TYPE r;
02990 int i;
02991
02992 if (!fpa_consts_inited)
02993 init_fpa_table ();
02994
02995 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
02996 r = REAL_VALUE_NEGATE (r);
02997 if (REAL_VALUE_MINUS_ZERO (r))
02998 return 0;
02999
03000 for (i = 0; i < 8; i++)
03001 if (REAL_VALUES_EQUAL (r, values_fpa[i]))
03002 return 1;
03003
03004 return 0;
03005 }
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017 int
03018 s_register_operand (op, mode)
03019 rtx op;
03020 enum machine_mode mode;
03021 {
03022 if (GET_MODE (op) != mode && mode != VOIDmode)
03023 return 0;
03024
03025 if (GET_CODE (op) == SUBREG)
03026 op = SUBREG_REG (op);
03027
03028
03029
03030
03031 return (GET_CODE (op) == REG
03032 && (REGNO (op) >= FIRST_PSEUDO_REGISTER
03033 || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
03034 }
03035
03036
03037
03038 int
03039 arm_hard_register_operand (op, mode)
03040 rtx op;
03041 enum machine_mode mode;
03042 {
03043 if (GET_MODE (op) != mode && mode != VOIDmode)
03044 return 0;
03045
03046 return (GET_CODE (op) == REG
03047 && REGNO (op) < FIRST_PSEUDO_REGISTER);
03048 }
03049
03050
03051
03052 int
03053 reg_or_int_operand (op, mode)
03054 rtx op;
03055 enum machine_mode mode;
03056 {
03057 if (GET_CODE (op) == CONST_INT)
03058 return 1;
03059
03060 if (GET_MODE (op) != mode && mode != VOIDmode)
03061 return 0;
03062
03063 if (GET_CODE (op) == SUBREG)
03064 op = SUBREG_REG (op);
03065
03066
03067
03068 return (GET_CODE (op) == REG
03069 && (REGNO (op) >= FIRST_PSEUDO_REGISTER
03070 || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
03071 }
03072
03073
03074
03075 int
03076 arm_reload_memory_operand (op, mode)
03077 rtx op;
03078 enum machine_mode mode ATTRIBUTE_UNUSED;
03079 {
03080 int regno = true_regnum (op);
03081
03082 return (!CONSTANT_P (op)
03083 && (regno == -1
03084 || (GET_CODE (op) == REG
03085 && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
03086 }
03087
03088
03089
03090
03091
03092
03093
03094
03095 int
03096 bad_signed_byte_operand (op, mode)
03097 rtx op;
03098 enum machine_mode mode ATTRIBUTE_UNUSED;
03099 {
03100 #if 0
03101 if ((mode == QImode && !memory_operand (op, mode)) || GET_CODE (op) != MEM)
03102 return 0;
03103 #endif
03104 if (GET_CODE (op) != MEM)
03105 return 0;
03106
03107 op = XEXP (op, 0);
03108
03109
03110 if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
03111 && (!s_register_operand (XEXP (op, 0), VOIDmode)
03112 || (!s_register_operand (XEXP (op, 1), VOIDmode)
03113 && GET_CODE (XEXP (op, 1)) != CONST_INT)))
03114 return 1;
03115
03116
03117 if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT
03118 && (INTVAL (XEXP (op, 1)) > 0xff
03119 || -INTVAL (XEXP (op, 1)) > 0xff))
03120 return 1;
03121
03122
03123 return 0;
03124 }
03125
03126
03127
03128 int
03129 arm_rhs_operand (op, mode)
03130 rtx op;
03131 enum machine_mode mode;
03132 {
03133 return (s_register_operand (op, mode)
03134 || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
03135 }
03136
03137
03138
03139
03140 int
03141 arm_rhsm_operand (op, mode)
03142 rtx op;
03143 enum machine_mode mode;
03144 {
03145 return (s_register_operand (op, mode)
03146 || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
03147 || memory_operand (op, mode));
03148 }
03149
03150
03151
03152
03153 int
03154 arm_add_operand (op, mode)
03155 rtx op;
03156 enum machine_mode mode;
03157 {
03158 if (TARGET_THUMB)
03159 return thumb_cmp_operand (op, mode);
03160
03161 return (s_register_operand (op, mode)
03162 || (GET_CODE (op) == CONST_INT
03163 && (const_ok_for_arm (INTVAL (op))
03164 || const_ok_for_arm (-INTVAL (op)))));
03165 }
03166
03167 int
03168 arm_not_operand (op, mode)
03169 rtx op;
03170 enum machine_mode mode;
03171 {
03172 return (s_register_operand (op, mode)
03173 || (GET_CODE (op) == CONST_INT
03174 && (const_ok_for_arm (INTVAL (op))
03175 || const_ok_for_arm (~INTVAL (op)))));
03176 }
03177
03178
03179
03180
03181 int
03182 offsettable_memory_operand (op, mode)
03183 rtx op;
03184 enum machine_mode mode;
03185 {
03186 if (mode == VOIDmode)
03187 mode = GET_MODE (op);
03188
03189 return (mode == GET_MODE (op)
03190 && GET_CODE (op) == MEM
03191 && offsettable_address_p (reload_completed | reload_in_progress,
03192 mode, XEXP (op, 0)));
03193 }
03194
03195
03196
03197
03198 int
03199 alignable_memory_operand (op, mode)
03200 rtx op;
03201 enum machine_mode mode;
03202 {
03203 rtx reg;
03204
03205 if (mode == VOIDmode)
03206 mode = GET_MODE (op);
03207
03208 if (mode != GET_MODE (op) || GET_CODE (op) != MEM)
03209 return 0;
03210
03211 op = XEXP (op, 0);
03212
03213 return ((GET_CODE (reg = op) == REG
03214 || (GET_CODE (op) == SUBREG
03215 && GET_CODE (reg = SUBREG_REG (op)) == REG)
03216 || (GET_CODE (op) == PLUS
03217 && GET_CODE (XEXP (op, 1)) == CONST_INT
03218 && (GET_CODE (reg = XEXP (op, 0)) == REG
03219 || (GET_CODE (XEXP (op, 0)) == SUBREG
03220 && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
03221 && REGNO_POINTER_ALIGN (REGNO (reg)) >= 32);
03222 }
03223
03224
03225
03226
03227 int
03228 f_register_operand (op, mode)
03229 rtx op;
03230 enum machine_mode mode;
03231 {
03232 if (GET_MODE (op) != mode && mode != VOIDmode)
03233 return 0;
03234
03235 if (GET_CODE (op) == SUBREG)
03236 op = SUBREG_REG (op);
03237
03238
03239
03240 return (GET_CODE (op) == REG
03241 && (REGNO (op) >= FIRST_PSEUDO_REGISTER
03242 || REGNO_REG_CLASS (REGNO (op)) == FPU_REGS));
03243 }
03244
03245
03246
03247 int
03248 fpu_rhs_operand (op, mode)
03249 rtx op;
03250 enum machine_mode mode;
03251 {
03252 if (s_register_operand (op, mode))
03253 return TRUE;
03254
03255 if (GET_MODE (op) != mode && mode != VOIDmode)
03256 return FALSE;
03257
03258 if (GET_CODE (op) == CONST_DOUBLE)
03259 return const_double_rtx_ok_for_fpu (op);
03260
03261 return FALSE;
03262 }
03263
03264 int
03265 fpu_add_operand (op, mode)
03266 rtx op;
03267 enum machine_mode mode;
03268 {
03269 if (s_register_operand (op, mode))
03270 return TRUE;
03271
03272 if (GET_MODE (op) != mode && mode != VOIDmode)
03273 return FALSE;
03274
03275 if (GET_CODE (op) == CONST_DOUBLE)
03276 return (const_double_rtx_ok_for_fpu (op)
03277 || neg_const_double_rtx_ok_for_fpu (op));
03278
03279 return FALSE;
03280 }
03281
03282
03283
03284 int
03285 power_of_two_operand (op, mode)
03286 rtx op;
03287 enum machine_mode mode ATTRIBUTE_UNUSED;
03288 {
03289 if (GET_CODE (op) == CONST_INT)
03290 {
03291 HOST_WIDE_INT value = INTVAL (op);
03292
03293 return value != 0 && (value & (value - 1)) == 0;
03294 }
03295
03296 return FALSE;
03297 }
03298
03299
03300
03301
03302
03303
03304 int
03305 di_operand (op, mode)
03306 rtx op;
03307 enum machine_mode mode;
03308 {
03309 if (s_register_operand (op, mode))
03310 return TRUE;
03311
03312 if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
03313 return FALSE;
03314
03315 if (GET_CODE (op) == SUBREG)
03316 op = SUBREG_REG (op);
03317
03318 switch (GET_CODE (op))
03319 {
03320 case CONST_DOUBLE:
03321 case CONST_INT:
03322 return TRUE;
03323
03324 case MEM:
03325 return memory_address_p (DImode, XEXP (op, 0));
03326
03327 default:
03328 return FALSE;
03329 }
03330 }
03331
03332
03333
03334 int
03335 nonimmediate_di_operand (op, mode)
03336 rtx op;
03337 enum machine_mode mode;
03338 {
03339 if (s_register_operand (op, mode))
03340 return TRUE;
03341
03342 if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
03343 return FALSE;
03344
03345 if (GET_CODE (op) == SUBREG)
03346 op = SUBREG_REG (op);
03347
03348 if (GET_CODE (op) == MEM)
03349 return memory_address_p (DImode, XEXP (op, 0));
03350
03351 return FALSE;
03352 }
03353
03354
03355
03356
03357
03358
03359 int
03360 soft_df_operand (op, mode)
03361 rtx op;
03362 enum machine_mode mode;
03363 {
03364 if (s_register_operand (op, mode))
03365 return TRUE;
03366
03367 if (mode != VOIDmode && GET_MODE (op) != mode)
03368 return FALSE;
03369
03370 if (GET_CODE (op) == SUBREG && CONSTANT_P (SUBREG_REG (op)))
03371 return FALSE;
03372
03373 if (GET_CODE (op) == SUBREG)
03374 op = SUBREG_REG (op);
03375
03376 switch (GET_CODE (op))
03377 {
03378 case CONST_DOUBLE:
03379 return TRUE;
03380
03381 case MEM:
03382 return memory_address_p (DFmode, XEXP (op, 0));
03383
03384 default:
03385 return FALSE;
03386 }
03387 }
03388
03389
03390
03391 int
03392 nonimmediate_soft_df_operand (op, mode)
03393 rtx op;
03394 enum machine_mode mode;
03395 {
03396 if (s_register_operand (op, mode))
03397 return TRUE;
03398
03399 if (mode != VOIDmode && GET_MODE (op) != mode)
03400 return FALSE;
03401
03402 if (GET_CODE (op) == SUBREG)
03403 op = SUBREG_REG (op);
03404
03405 if (GET_CODE (op) == MEM)
03406 return memory_address_p (DFmode, XEXP (op, 0));
03407 return FALSE;
03408 }
03409
03410
03411
03412 int
03413 index_operand (op, mode)
03414 rtx op;
03415 enum machine_mode mode;
03416 {
03417 return (s_register_operand (op, mode)
03418 || (immediate_operand (op, mode)
03419 && (GET_CODE (op) != CONST_INT
03420 || (INTVAL (op) < 4096 && INTVAL (op) > -4096))));
03421 }
03422
03423
03424
03425
03426
03427 int
03428 const_shift_operand (op, mode)
03429 rtx op;
03430 enum machine_mode mode;
03431 {
03432 return (power_of_two_operand (op, mode)
03433 || (immediate_operand (op, mode)
03434 && (GET_CODE (op) != CONST_INT
03435 || (INTVAL (op) < 32 && INTVAL (op) > 0))));
03436 }
03437
03438
03439
03440
03441 int
03442 shiftable_operator (x, mode)
03443 rtx x;
03444 enum machine_mode mode;
03445 {
03446 enum rtx_code code;
03447
03448 if (GET_MODE (x) != mode)
03449 return FALSE;
03450
03451 code = GET_CODE (x);
03452
03453 return (code == PLUS || code == MINUS
03454 || code == IOR || code == XOR || code == AND);
03455 }
03456
03457
03458
03459 int
03460 logical_binary_operator (x, mode)
03461 rtx x;
03462 enum machine_mode mode;
03463 {
03464 enum rtx_code code;
03465
03466 if (GET_MODE (x) != mode)
03467 return FALSE;
03468
03469 code = GET_CODE (x);
03470
03471 return (code == IOR || code == XOR || code == AND);
03472 }
03473
03474
03475
03476 int
03477 shift_operator (x, mode)
03478 rtx x;
03479 enum machine_mode mode;
03480 {
03481 enum rtx_code code;
03482
03483 if (GET_MODE (x) != mode)
03484 return FALSE;
03485
03486 code = GET_CODE (x);
03487
03488 if (code == MULT)
03489 return power_of_two_operand (XEXP (x, 1), mode);
03490
03491 return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT
03492 || code == ROTATERT);
03493 }
03494
03495
03496
03497 int
03498 equality_operator (x, mode)
03499 rtx x;
03500 enum machine_mode mode ATTRIBUTE_UNUSED;
03501 {
03502 return GET_CODE (x) == EQ || GET_CODE (x) == NE;
03503 }
03504
03505
03506
03507 int
03508 arm_comparison_operator (x, mode)
03509 rtx x;
03510 enum machine_mode mode;
03511 {
03512 return (comparison_operator (x, mode)
03513 && GET_CODE (x) != LTGT
03514 && GET_CODE (x) != UNEQ);
03515 }
03516
03517
03518
03519 int
03520 minmax_operator (x, mode)
03521 rtx x;
03522 enum machine_mode mode;
03523 {
03524 enum rtx_code code = GET_CODE (x);
03525
03526 if (GET_MODE (x) != mode)
03527 return FALSE;
03528
03529 return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
03530 }
03531
03532
03533
03534
03535 int
03536 cc_register (x, mode)
03537 rtx x;
03538 enum machine_mode mode;
03539 {
03540 if (mode == VOIDmode)
03541 {
03542 mode = GET_MODE (x);
03543
03544 if (GET_MODE_CLASS (mode) != MODE_CC)
03545 return FALSE;
03546 }
03547
03548 if ( GET_MODE (x) == mode
03549 && GET_CODE (x) == REG
03550 && REGNO (x) == CC_REGNUM)
03551 return TRUE;
03552
03553 return FALSE;
03554 }
03555
03556
03557
03558
03559
03560 int
03561 dominant_cc_register (x, mode)
03562 rtx x;
03563 enum machine_mode mode;
03564 {
03565 if (mode == VOIDmode)
03566 {
03567 mode = GET_MODE (x);
03568
03569 if (GET_MODE_CLASS (mode) != MODE_CC)
03570 return FALSE;
03571 }
03572
03573 if ( mode != CC_DNEmode && mode != CC_DEQmode
03574 && mode != CC_DLEmode && mode != CC_DLTmode
03575 && mode != CC_DGEmode && mode != CC_DGTmode
03576 && mode != CC_DLEUmode && mode != CC_DLTUmode
03577 && mode != CC_DGEUmode && mode != CC_DGTUmode)
03578 return FALSE;
03579
03580 return cc_register (x, mode);
03581 }
03582
03583
03584
03585 int
03586 symbol_mentioned_p (x)
03587 rtx x;
03588 {
03589 const char * fmt;
03590 int i;
03591
03592 if (GET_CODE (x) == SYMBOL_REF)
03593 return 1;
03594
03595 fmt = GET_RTX_FORMAT (GET_CODE (x));
03596
03597 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
03598 {
03599 if (fmt[i] == 'E')
03600 {
03601 int j;
03602
03603 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
03604 if (symbol_mentioned_p (XVECEXP (x, i, j)))
03605 return 1;
03606 }
03607 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
03608 return 1;
03609 }
03610
03611 return 0;
03612 }
03613
03614
03615
03616 int
03617 label_mentioned_p (x)
03618 rtx x;
03619 {
03620 const char * fmt;
03621 int i;
03622
03623 if (GET_CODE (x) == LABEL_REF)
03624 return 1;
03625
03626 fmt = GET_RTX_FORMAT (GET_CODE (x));
03627 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
03628 {
03629 if (fmt[i] == 'E')
03630 {
03631 int j;
03632
03633 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
03634 if (label_mentioned_p (XVECEXP (x, i, j)))
03635 return 1;
03636 }
03637 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
03638 return 1;
03639 }
03640
03641 return 0;
03642 }
03643
03644 enum rtx_code
03645 minmax_code (x)
03646 rtx x;
03647 {
03648 enum rtx_code code = GET_CODE (x);
03649
03650 if (code == SMAX)
03651 return GE;
03652 else if (code == SMIN)
03653 return LE;
03654 else if (code == UMIN)
03655 return LEU;
03656 else if (code == UMAX)
03657 return GEU;
03658
03659 abort ();
03660 }
03661
03662
03663
03664 int
03665 adjacent_mem_locations (a, b)
03666 rtx a, b;
03667 {
03668 if ((GET_CODE (XEXP (a, 0)) == REG
03669 || (GET_CODE (XEXP (a, 0)) == PLUS
03670 && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
03671 && (GET_CODE (XEXP (b, 0)) == REG
03672 || (GET_CODE (XEXP (b, 0)) == PLUS
03673 && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
03674 {
03675 int val0 = 0, val1 = 0;
03676 int reg0, reg1;
03677
03678 if (GET_CODE (XEXP (a, 0)) == PLUS)
03679 {
03680 reg0 = REGNO (XEXP (XEXP (a, 0), 0));
03681 val0 = INTVAL (XEXP (XEXP (a, 0), 1));
03682 }
03683 else
03684 reg0 = REGNO (XEXP (a, 0));
03685
03686 if (GET_CODE (XEXP (b, 0)) == PLUS)
03687 {
03688 reg1 = REGNO (XEXP (XEXP (b, 0), 0));
03689 val1 = INTVAL (XEXP (XEXP (b, 0), 1));
03690 }
03691 else
03692 reg1 = REGNO (XEXP (b, 0));
03693
03694 return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4);
03695 }
03696 return 0;
03697 }
03698
03699
03700
03701
03702 int
03703 load_multiple_operation (op, mode)
03704 rtx op;
03705 enum machine_mode mode ATTRIBUTE_UNUSED;
03706 {
03707 HOST_WIDE_INT count = XVECLEN (op, 0);
03708 int dest_regno;
03709 rtx src_addr;
03710 HOST_WIDE_INT i = 1, base = 0;
03711 rtx elt;
03712
03713 if (count <= 1
03714 || GET_CODE (XVECEXP (op, 0, 0)) != SET)
03715 return 0;
03716
03717
03718 if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
03719 {
03720 i++;
03721 base = 1;
03722
03723
03724 if (GET_CODE (SET_DEST (elt)) != REG
03725 || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
03726 || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
03727 || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
03728 || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
03729 return 0;
03730 }
03731
03732
03733 if (count <= i
03734 || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
03735 || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
03736 || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
03737 return 0;
03738
03739 dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
03740 src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
03741
03742 for (; i < count; i++)
03743 {
03744 elt = XVECEXP (op, 0, i);
03745
03746 if (GET_CODE (elt) != SET
03747 || GET_CODE (SET_DEST (elt)) != REG
03748 || GET_MODE (SET_DEST (elt)) != SImode
03749 || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
03750 || GET_CODE (SET_SRC (elt)) != MEM
03751 || GET_MODE (SET_SRC (elt)) != SImode
03752 || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
03753 || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
03754 || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
03755 || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
03756 return 0;
03757 }
03758
03759 return 1;
03760 }
03761
03762
03763
03764
03765 int
03766 store_multiple_operation (op, mode)
03767 rtx op;
03768 enum machine_mode mode ATTRIBUTE_UNUSED;
03769 {
03770 HOST_WIDE_INT count = XVECLEN (op, 0);
03771 int src_regno;
03772 rtx dest_addr;
03773 HOST_WIDE_INT i = 1, base = 0;
03774 rtx elt;
03775
03776 if (count <= 1
03777 || GET_CODE (XVECEXP (op, 0, 0)) != SET)
03778 return 0;
03779
03780
03781 if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
03782 {
03783 i++;
03784 base = 1;
03785
03786
03787 if (GET_CODE (SET_DEST (elt)) != REG
03788 || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
03789 || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
03790 || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
03791 || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
03792 return 0;
03793 }
03794
03795
03796 if (count <= i
03797 || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
03798 || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
03799 || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
03800 return 0;
03801
03802 src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
03803 dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
03804
03805 for (; i < count; i++)
03806 {
03807 elt = XVECEXP (op, 0, i);
03808
03809 if (GET_CODE (elt) != SET
03810 || GET_CODE (SET_SRC (elt)) != REG
03811 || GET_MODE (SET_SRC (elt)) != SImode
03812 || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
03813 || GET_CODE (SET_DEST (elt)) != MEM
03814 || GET_MODE (SET_DEST (elt)) != SImode
03815 || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
03816 || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
03817 || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
03818 || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
03819 return 0;
03820 }
03821
03822 return 1;
03823 }
03824
03825 int
03826 load_multiple_sequence (operands, nops, regs, base, load_offset)
03827 rtx * operands;
03828 int nops;
03829 int * regs;
03830 int * base;
03831 HOST_WIDE_INT * load_offset;
03832 {
03833 int unsorted_regs[4];
03834 HOST_WIDE_INT unsorted_offsets[4];
03835 int order[4];
03836 int base_reg = -1;
03837 int i;
03838
03839
03840
03841 if (nops < 2 || nops > 4)
03842 abort ();
03843
03844
03845
03846
03847
03848 for (i = 0; i < nops; i++)
03849 {
03850 rtx reg;
03851 rtx offset;
03852
03853
03854 if (GET_CODE (operands[nops + i]) == SUBREG)
03855 operands[nops + i] = alter_subreg (operands + (nops + i));
03856
03857 if (GET_CODE (operands[nops + i]) != MEM)
03858 abort ();
03859
03860
03861
03862 if (MEM_VOLATILE_P (operands[nops + i]))
03863 return 0;
03864
03865 offset = const0_rtx;
03866
03867 if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
03868 || (GET_CODE (reg) == SUBREG
03869 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
03870 || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
03871 && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
03872 == REG)
03873 || (GET_CODE (reg) == SUBREG
03874 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
03875 && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
03876 == CONST_INT)))
03877 {
03878 if (i == 0)
03879 {
03880 base_reg = REGNO (reg);
03881 unsorted_regs[0] = (GET_CODE (operands[i]) == REG
03882 ? REGNO (operands[i])
03883 : REGNO (SUBREG_REG (operands[i])));
03884 order[0] = 0;
03885 }
03886 else
03887 {
03888 if (base_reg != (int) REGNO (reg))
03889
03890 return 0;
03891
03892 unsorted_regs[i] = (GET_CODE (operands[i]) == REG
03893 ? REGNO (operands[i])
03894 : REGNO (SUBREG_REG (operands[i])));
03895 if (unsorted_regs[i] < unsorted_regs[order[0]])
03896 order[0] = i;
03897 }
03898
03899
03900
03901
03902 if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
03903 || (i != nops - 1 && unsorted_regs[i] == base_reg))
03904 return 0;
03905
03906 unsorted_offsets[i] = INTVAL (offset);
03907 }
03908 else
03909
03910 return 0;
03911 }
03912
03913
03914
03915
03916
03917
03918
03919 for (i = 1; i < nops; i++)
03920 {
03921 int j;
03922
03923 order[i] = order[i - 1];
03924 for (j = 0; j < nops; j++)
03925 if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
03926 && (order[i] == order[i - 1]
03927 || unsorted_regs[j] < unsorted_regs[order[i]]))
03928 order[i] = j;
03929
03930
03931
03932 if (order[i] == order[i - 1])
03933 return 0;
03934
03935
03936 if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
03937 return 0;
03938 }
03939
03940 if (base)
03941 {
03942 *base = base_reg;
03943
03944 for (i = 0; i < nops; i++)
03945 regs[i] = unsorted_regs[order[i]];
03946
03947 *load_offset = unsorted_offsets[order[0]];
03948 }
03949
03950 if (unsorted_offsets[order[0]] == 0)
03951 return 1;
03952
03953 if (unsorted_offsets[order[0]] == 4)
03954 return 2;
03955
03956 if (unsorted_offsets[order[nops - 1]] == 0)
03957 return 3;
03958
03959 if (unsorted_offsets[order[nops - 1]] == -4)
03960 return 4;
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991 if (nops == 2 && arm_ld_sched)
03992 return 0;
03993
03994
03995
03996 return (const_ok_for_arm (unsorted_offsets[order[0]])
03997 || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
03998 }
03999
04000 const char *
04001 emit_ldm_seq (operands, nops)
04002 rtx * operands;
04003 int nops;
04004 {
04005 int regs[4];
04006 int base_reg;
04007 HOST_WIDE_INT offset;
04008 char buf[100];
04009 int i;
04010
04011 switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
04012 {
04013 case 1:
04014 strcpy (buf, "ldm%?ia\t");
04015 break;
04016
04017 case 2:
04018 strcpy (buf, "ldm%?ib\t");
04019 break;
04020
04021 case 3:
04022 strcpy (buf, "ldm%?da\t");
04023 break;
04024
04025 case 4:
04026 strcpy (buf, "ldm%?db\t");
04027 break;
04028
04029 case 5:
04030 if (offset >= 0)
04031 sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
04032 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
04033 (long) offset);
04034 else
04035 sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
04036 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
04037 (long) -offset);
04038 output_asm_insn (buf, operands);
04039 base_reg = regs[0];
04040 strcpy (buf, "ldm%?ia\t");
04041 break;
04042
04043 default:
04044 abort ();
04045 }
04046
04047 sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
04048 reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
04049
04050 for (i = 1; i < nops; i++)
04051 sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
04052 reg_names[regs[i]]);
04053
04054 strcat (buf, "}\t%@ phole ldm");
04055
04056 output_asm_insn (buf, operands);
04057 return "";
04058 }
04059
04060 int
04061 store_multiple_sequence (operands, nops, regs, base, load_offset)
04062 rtx * operands;
04063 int nops;
04064 int * regs;
04065 int * base;
04066 HOST_WIDE_INT * load_offset;
04067 {
04068 int unsorted_regs[4];
04069 HOST_WIDE_INT unsorted_offsets[4];
04070 int order[4];
04071 int base_reg = -1;
04072 int i;
04073
04074
04075
04076 if (nops < 2 || nops > 4)
04077 abort ();
04078
04079
04080
04081
04082
04083 for (i = 0; i < nops; i++)
04084 {
04085 rtx reg;
04086 rtx offset;
04087
04088
04089 if (GET_CODE (operands[nops + i]) == SUBREG)
04090 operands[nops + i] = alter_subreg (operands + (nops + i));
04091
04092 if (GET_CODE (operands[nops + i]) != MEM)
04093 abort ();
04094
04095
04096
04097 if (MEM_VOLATILE_P (operands[nops + i]))
04098 return 0;
04099
04100 offset = const0_rtx;
04101
04102 if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
04103 || (GET_CODE (reg) == SUBREG
04104 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
04105 || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
04106 && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
04107 == REG)
04108 || (GET_CODE (reg) == SUBREG
04109 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
04110 && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
04111 == CONST_INT)))
04112 {
04113 if (i == 0)
04114 {
04115 base_reg = REGNO (reg);
04116 unsorted_regs[0] = (GET_CODE (operands[i]) == REG
04117 ? REGNO (operands[i])
04118 : REGNO (SUBREG_REG (operands[i])));
04119 order[0] = 0;
04120 }
04121 else
04122 {
04123 if (base_reg != (int) REGNO (reg))
04124
04125 return 0;
04126
04127 unsorted_regs[i] = (GET_CODE (operands[i]) == REG
04128 ? REGNO (operands[i])
04129 : REGNO (SUBREG_REG (operands[i])));
04130 if (unsorted_regs[i] < unsorted_regs[order[0]])
04131 order[0] = i;
04132 }
04133
04134
04135 if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
04136 return 0;
04137
04138 unsorted_offsets[i] = INTVAL (offset);
04139 }
04140 else
04141
04142 return 0;
04143 }
04144
04145
04146
04147
04148
04149
04150
04151 for (i = 1; i < nops; i++)
04152 {
04153 int j;
04154
04155 order[i] = order[i - 1];
04156 for (j = 0; j < nops; j++)
04157 if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
04158 && (order[i] == order[i - 1]
04159 || unsorted_regs[j] < unsorted_regs[order[i]]))
04160 order[i] = j;
04161
04162
04163
04164 if (order[i] == order[i - 1])
04165 return 0;
04166
04167
04168 if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
04169 return 0;
04170 }
04171
04172 if (base)
04173 {
04174 *base = base_reg;
04175
04176 for (i = 0; i < nops; i++)
04177 regs[i] = unsorted_regs[order[i]];
04178
04179 *load_offset = unsorted_offsets[order[0]];
04180 }
04181
04182 if (unsorted_offsets[order[0]] == 0)
04183 return 1;
04184
04185 if (unsorted_offsets[order[0]] == 4)
04186 return 2;
04187
04188 if (unsorted_offsets[order[nops - 1]] == 0)
04189 return 3;
04190
04191 if (unsorted_offsets[order[nops - 1]] == -4)
04192 return 4;
04193
04194 return 0;
04195 }
04196
04197 const char *
04198 emit_stm_seq (operands, nops)
04199 rtx * operands;
04200 int nops;
04201 {
04202 int regs[4];
04203 int base_reg;
04204 HOST_WIDE_INT offset;
04205 char buf[100];
04206 int i;
04207
04208 switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
04209 {
04210 case 1:
04211 strcpy (buf, "stm%?ia\t");
04212 break;
04213
04214 case 2:
04215 strcpy (buf, "stm%?ib\t");
04216 break;
04217
04218 case 3:
04219 strcpy (buf, "stm%?da\t");
04220 break;
04221
04222 case 4:
04223 strcpy (buf, "stm%?db\t");
04224 break;
04225
04226 default:
04227 abort ();
04228 }
04229
04230 sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
04231 reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
04232
04233 for (i = 1; i < nops; i++)
04234 sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
04235 reg_names[regs[i]]);
04236
04237 strcat (buf, "}\t%@ phole stm");
04238
04239 output_asm_insn (buf, operands);
04240 return "";
04241 }
04242
04243 int
04244 multi_register_push (op, mode)
04245 rtx op;
04246 enum machine_mode mode ATTRIBUTE_UNUSED;
04247 {
04248 if (GET_CODE (op) != PARALLEL
04249 || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
04250 || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
04251 || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
04252 return 0;
04253
04254 return 1;
04255 }
04256
04257
04258
04259 rtx
04260 arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
04261 in_struct_p, scalar_p)
04262 int base_regno;
04263 int count;
04264 rtx from;
04265 int up;
04266 int write_back;
04267 int unchanging_p;
04268 int in_struct_p;
04269 int scalar_p;
04270 {
04271 int i = 0, j;
04272 rtx result;
04273 int sign = up ? 1 : -1;
04274 rtx mem;
04275
04276
04277
04278
04279
04280
04281
04282
04283
04284
04285
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301
04302
04303
04304 if (arm_is_xscale && count <= 2 && ! optimize_size)
04305 {
04306 rtx seq;
04307
04308 start_sequence ();
04309
04310 for (i = 0; i < count; i++)
04311 {
04312 mem = gen_rtx_MEM (SImode, plus_constant (from, i * 4 * sign));
04313 RTX_UNCHANGING_P (mem) = unchanging_p;
04314 MEM_IN_STRUCT_P (mem) = in_struct_p;
04315 MEM_SCALAR_P (mem) = scalar_p;
04316 emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
04317 }
04318
04319 if (write_back)
04320 emit_move_insn (from, plus_constant (from, count * 4 * sign));
04321
04322 seq = gen_sequence ();
04323 end_sequence ();
04324
04325 return seq;
04326 }
04327
04328 result = gen_rtx_PARALLEL (VOIDmode,
04329 rtvec_alloc (count + (write_back ? 1 : 0)));
04330 if (write_back)
04331 {
04332 XVECEXP (result, 0, 0)
04333 = gen_rtx_SET (GET_MODE (from), from,
04334 plus_constant (from, count * 4 * sign));
04335 i = 1;
04336 count++;
04337 }
04338
04339 for (j = 0; i < count; i++, j++)
04340 {
04341 mem = gen_rtx_MEM (SImode, plus_constant (from, j * 4 * sign));
04342 RTX_UNCHANGING_P (mem) = unchanging_p;
04343 MEM_IN_STRUCT_P (mem) = in_struct_p;
04344 MEM_SCALAR_P (mem) = scalar_p;
04345 XVECEXP (result, 0, i)
04346 = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
04347 }
04348
04349 return result;
04350 }
04351
04352 rtx
04353 arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p,
04354 in_struct_p, scalar_p)
04355 int base_regno;
04356 int count;
04357 rtx to;
04358 int up;
04359 int write_back;
04360 int unchanging_p;
04361 int in_struct_p;
04362 int scalar_p;
04363 {
04364 int i = 0, j;
04365 rtx result;
04366 int sign = up ? 1 : -1;
04367 rtx mem;
04368
04369
04370
04371 if (arm_is_xscale && count <= 2 && ! optimize_size)
04372 {
04373 rtx seq;
04374
04375 start_sequence ();
04376
04377 for (i = 0; i < count; i++)
04378 {
04379 mem = gen_rtx_MEM (SImode, plus_constant (to, i * 4 * sign));
04380 RTX_UNCHANGING_P (mem) = unchanging_p;
04381 MEM_IN_STRUCT_P (mem) = in_struct_p;
04382 MEM_SCALAR_P (mem) = scalar_p;
04383 emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
04384 }
04385
04386 if (write_back)
04387 emit_move_insn (to, plus_constant (to, count * 4 * sign));
04388
04389 seq = gen_sequence ();
04390 end_sequence ();
04391
04392 return seq;
04393 }
04394
04395 result = gen_rtx_PARALLEL (VOIDmode,
04396 rtvec_alloc (count + (write_back ? 1 : 0)));
04397 if (write_back)
04398 {
04399 XVECEXP (result, 0, 0)
04400 = gen_rtx_SET (GET_MODE (to), to,
04401 plus_constant (to, count * 4 * sign));
04402 i = 1;
04403 count++;
04404 }
04405
04406 for (j = 0; i < count; i++, j++)
04407 {
04408 mem = gen_rtx_MEM (SImode, plus_constant (to, j * 4 * sign));
04409 RTX_UNCHANGING_P (mem) = unchanging_p;
04410 MEM_IN_STRUCT_P (mem) = in_struct_p;
04411 MEM_SCALAR_P (mem) = scalar_p;
04412
04413 XVECEXP (result, 0, i)
04414 = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
04415 }
04416
04417 return result;
04418 }
04419
04420 int
04421 arm_gen_movstrqi (operands)
04422 rtx * operands;
04423 {
04424 HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
04425 int i;
04426 rtx src, dst;
04427 rtx st_src, st_dst, fin_src, fin_dst;
04428 rtx part_bytes_reg = NULL;
04429 rtx mem;
04430 int dst_unchanging_p, dst_in_struct_p, src_unchanging_p, src_in_struct_p;
04431 int dst_scalar_p, src_scalar_p;
04432
04433 if (GET_CODE (operands[2]) != CONST_INT
04434 || GET_CODE (operands[3]) != CONST_INT
04435 || INTVAL (operands[2]) > 64
04436 || INTVAL (operands[3]) & 3)
04437 return 0;
04438
04439 st_dst = XEXP (operands[0], 0);
04440 st_src = XEXP (operands[1], 0);
04441
04442 dst_unchanging_p = RTX_UNCHANGING_P (operands[0]);
04443 dst_in_struct_p = MEM_IN_STRUCT_P (operands[0]);
04444 dst_scalar_p = MEM_SCALAR_P (operands[0]);
04445 src_unchanging_p = RTX_UNCHANGING_P (operands[1]);
04446 src_in_struct_p = MEM_IN_STRUCT_P (operands[1]);
04447 src_scalar_p = MEM_SCALAR_P (operands[1]);
04448
04449 fin_dst = dst = copy_to_mode_reg (SImode, st_dst);
04450 fin_src = src = copy_to_mode_reg (SImode, st_src);
04451
04452 in_words_to_go = NUM_INTS (INTVAL (operands[2]));
04453 out_words_to_go = INTVAL (operands[2]) / 4;
04454 last_bytes = INTVAL (operands[2]) & 3;
04455
04456 if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
04457 part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
04458
04459 for (i = 0; in_words_to_go >= 2; i+=4)
04460 {
04461 if (in_words_to_go > 4)
04462 emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
04463 src_unchanging_p,
04464 src_in_struct_p,
04465 src_scalar_p));
04466 else
04467 emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
04468 FALSE, src_unchanging_p,
04469 src_in_struct_p, src_scalar_p));
04470
04471 if (out_words_to_go)
04472 {
04473 if (out_words_to_go > 4)
04474 emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
04475 dst_unchanging_p,
04476 dst_in_struct_p,
04477 dst_scalar_p));
04478 else if (out_words_to_go != 1)
04479 emit_insn (arm_gen_store_multiple (0, out_words_to_go,
04480 dst, TRUE,
04481 (last_bytes == 0
04482 ? FALSE : TRUE),
04483 dst_unchanging_p,
04484 dst_in_struct_p,
04485 dst_scalar_p));
04486 else
04487 {
04488 mem = gen_rtx_MEM (SImode, dst);
04489 RTX_UNCHANGING_P (mem) = dst_unchanging_p;
04490 MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
04491 MEM_SCALAR_P (mem) = dst_scalar_p;
04492 emit_move_insn (mem, gen_rtx_REG (SImode, 0));
04493 if (last_bytes != 0)
04494 emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
04495 }
04496 }
04497
04498 in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
04499 out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
04500 }
04501
04502
04503 if (out_words_to_go)
04504 {
04505 rtx sreg;
04506
04507 mem = gen_rtx_MEM (SImode, src);
04508 RTX_UNCHANGING_P (mem) = src_unchanging_p;
04509 MEM_IN_STRUCT_P (mem) = src_in_struct_p;
04510 MEM_SCALAR_P (mem) = src_scalar_p;
04511 emit_move_insn (sreg = gen_reg_rtx (SImode), mem);
04512 emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4));
04513
04514 mem = gen_rtx_MEM (SImode, dst);
04515 RTX_UNCHANGING_P (mem) = dst_unchanging_p;
04516 MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
04517 MEM_SCALAR_P (mem) = dst_scalar_p;
04518 emit_move_insn (mem, sreg);
04519 emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4));
04520 in_words_to_go--;
04521
04522 if (in_words_to_go)
04523 abort ();
04524 }
04525
04526 if (in_words_to_go)
04527 {
04528 if (in_words_to_go < 0)
04529 abort ();
04530
04531 mem = gen_rtx_MEM (SImode, src);
04532 RTX_UNCHANGING_P (mem) = src_unchanging_p;
04533 MEM_IN_STRUCT_P (mem) = src_in_struct_p;
04534 MEM_SCALAR_P (mem) = src_scalar_p;
04535 part_bytes_reg = copy_to_mode_reg (SImode, mem);
04536 }
04537
04538 if (last_bytes && part_bytes_reg == NULL)
04539 abort ();
04540
04541 if (BYTES_BIG_ENDIAN && last_bytes)
04542 {
04543 rtx tmp = gen_reg_rtx (SImode);
04544
04545
04546 emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
04547 GEN_INT (8 * (4 - last_bytes))));
04548 part_bytes_reg = tmp;
04549
04550 while (last_bytes)
04551 {
04552 mem = gen_rtx_MEM (QImode, plus_constant (dst, last_bytes - 1));
04553 RTX_UNCHANGING_P (mem) = dst_unchanging_p;
04554 MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
04555 MEM_SCALAR_P (mem) = dst_scalar_p;
04556 emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
04557
04558 if (--last_bytes)
04559 {
04560 tmp = gen_reg_rtx (SImode);
04561 emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
04562 part_bytes_reg = tmp;
04563 }
04564 }
04565
04566 }
04567 else
04568 {
04569 if (last_bytes > 1)
04570 {
04571 mem = gen_rtx_MEM (HImode, dst);
04572 RTX_UNCHANGING_P (mem) = dst_unchanging_p;
04573 MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
04574 MEM_SCALAR_P (mem) = dst_scalar_p;
04575 emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
04576 last_bytes -= 2;
04577 if (last_bytes)
04578 {
04579 rtx tmp = gen_reg_rtx (SImode);
04580
04581 emit_insn (gen_addsi3 (dst, dst, GEN_INT (2)));
04582 emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
04583 part_bytes_reg = tmp;
04584 }
04585 }
04586
04587 if (last_bytes)
04588 {
04589 mem = gen_rtx_MEM (QImode, dst);
04590 RTX_UNCHANGING_P (mem) = dst_unchanging_p;
04591 MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
04592 MEM_SCALAR_P (mem) = dst_scalar_p;
04593 emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
04594 }
04595 }
04596
04597 return 1;
04598 }
04599
04600
04601
04602
04603
04604 rtx
04605 arm_gen_rotated_half_load (memref)
04606 rtx memref;
04607 {
04608 HOST_WIDE_INT offset = 0;
04609 rtx base = XEXP (memref, 0);
04610
04611 if (GET_CODE (base) == PLUS)
04612 {
04613 offset = INTVAL (XEXP (base, 1));
04614 base = XEXP (base, 0);
04615 }
04616
04617
04618 if (TARGET_MMU_TRAPS
04619 && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0)))
04620 return NULL;
04621
04622 base = gen_rtx_MEM (SImode, plus_constant (base, offset & ~2));
04623
04624 if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2))
04625 return base;
04626
04627 return gen_rtx_ROTATE (SImode, base, GEN_INT (16));
04628 }
04629
04630
04631
04632
04633
04634
04635
04636
04637
04638 static enum machine_mode
04639 select_dominance_cc_mode (x, y, cond_or)
04640 rtx x;
04641 rtx y;
04642 HOST_WIDE_INT cond_or;
04643 {
04644 enum rtx_code cond1, cond2;
04645 int swapped = 0;
04646
04647
04648
04649
04650 if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
04651 != CCmode)
04652 || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
04653 != CCmode))
04654 return CCmode;
04655
04656
04657
04658
04659 if (cond_or == 1)
04660 cond1 = reverse_condition (cond1);
04661
04662
04663
04664 if (cond1 != cond2
04665 && !comparison_dominates_p (cond1, cond2)
04666 && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
04667 return CCmode;
04668
04669 if (swapped)
04670 {
04671 enum rtx_code temp = cond1;
04672 cond1 = cond2;
04673 cond2 = temp;
04674 }
04675
04676 switch (cond1)
04677 {
04678 case EQ:
04679 if (cond2 == EQ || !cond_or)
04680 return CC_DEQmode;
04681
04682 switch (cond2)
04683 {
04684 case LE: return CC_DLEmode;
04685 case LEU: return CC_DLEUmode;
04686 case GE: return CC_DGEmode;
04687 case GEU: return CC_DGEUmode;
04688 default: break;
04689 }
04690
04691 break;
04692
04693 case LT:
04694 if (cond2 == LT || !cond_or)
04695 return CC_DLTmode;
04696 if (cond2 == LE)
04697 return CC_DLEmode;
04698 if (cond2 == NE)
04699 return CC_DNEmode;
04700 break;
04701
04702 case GT:
04703 if (cond2 == GT || !cond_or)
04704 return CC_DGTmode;
04705 if (cond2 == GE)
04706 return CC_DGEmode;
04707 if (cond2 == NE)
04708 return CC_DNEmode;
04709 break;
04710
04711 case LTU:
04712 if (cond2 == LTU || !cond_or)
04713 return CC_DLTUmode;
04714 if (cond2 == LEU)
04715 return CC_DLEUmode;
04716 if (cond2 == NE)
04717 return CC_DNEmode;
04718 break;
04719
04720 case GTU:
04721 if (cond2 == GTU || !cond_or)
04722 return CC_DGTUmode;
04723 if (cond2 == GEU)
04724 return CC_DGEUmode;
04725 if (cond2 == NE)
04726 return CC_DNEmode;
04727 break;
04728
04729
04730
04731 case NE:
04732 return CC_DNEmode;
04733
04734 case LE:
04735 return CC_DLEmode;
04736
04737 case GE:
04738 return CC_DGEmode;
04739
04740 case LEU:
04741 return CC_DLEUmode;
04742
04743 case GEU:
04744 return CC_DGEUmode;
04745
04746 default:
04747 break;
04748 }
04749
04750 abort ();
04751 }
04752
04753 enum machine_mode
04754 arm_select_cc_mode (op, x, y)
04755 enum rtx_code op;
04756 rtx x;
04757 rtx y;
04758 {
04759
04760
04761 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
04762 {
04763 switch (op)
04764 {
04765 case EQ:
04766 case NE:
04767 case UNORDERED:
04768 case ORDERED:
04769 case UNLT:
04770 case UNLE:
04771 case UNGT:
04772 case UNGE:
04773 case UNEQ:
04774 case LTGT:
04775 return CCFPmode;
04776
04777 case LT:
04778 case LE:
04779 case GT:
04780 case GE:
04781 return CCFPEmode;
04782
04783 default:
04784 abort ();
04785 }
04786 }
04787
04788
04789
04790 if (GET_MODE (y) == SImode && GET_CODE (y) == REG
04791 && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
04792 || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
04793 || GET_CODE (x) == ROTATERT))
04794 return CC_SWPmode;
04795
04796
04797
04798
04799
04800 if (GET_MODE (x) == SImode
04801 && GET_CODE (x) == ASHIFT
04802 && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
04803 && GET_CODE (XEXP (x, 0)) == SUBREG
04804 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
04805 && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
04806 && (op == EQ || op == NE
04807 || op == GEU || op == GTU || op == LTU || op == LEU)
04808 && GET_CODE (y) == CONST_INT)
04809 return CC_Zmode;
04810
04811
04812
04813
04814
04815 if (GET_CODE (x) == IF_THEN_ELSE
04816 && (XEXP (x, 2) == const0_rtx
04817 || XEXP (x, 2) == const1_rtx)
04818 && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
04819 && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
04820 return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
04821 INTVAL (XEXP (x, 2)));
04822
04823
04824 if (GET_CODE (x) == AND
04825 && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
04826 && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
04827 return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 0);
04828
04829 if (GET_CODE (x) == IOR
04830 && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
04831 && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
04832 return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 2);
04833
04834
04835
04836
04837
04838 if (GET_MODE (x) == SImode
04839 && y == const0_rtx
04840 && (op == EQ || op == NE || op == LT || op == GE)
04841 && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
04842 || GET_CODE (x) == AND || GET_CODE (x) == IOR
04843 || GET_CODE (x) == XOR || GET_CODE (x) == MULT
04844 || GET_CODE (x) == NOT || GET_CODE (x) == NEG
04845 || GET_CODE (x) == LSHIFTRT
04846 || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
04847 || GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT))
04848 return CC_NOOVmode;
04849
04850 if (GET_MODE (x) == QImode && (op == EQ || op == NE))
04851 return CC_Zmode;
04852
04853 if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
04854 && GET_CODE (x) == PLUS
04855 && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
04856 return CC_Cmode;
04857
04858 return CCmode;
04859 }
04860
04861
04862
04863
04864
04865 rtx
04866 arm_gen_compare_reg (code, x, y)
04867 enum rtx_code code;
04868 rtx x, y;
04869 {
04870 enum machine_mode mode = SELECT_CC_MODE (code, x, y);
04871 rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
04872
04873 emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
04874 gen_rtx_COMPARE (mode, x, y)));
04875
04876 return cc_reg;
04877 }
04878
04879 void
04880 arm_reload_in_hi (operands)
04881 rtx * operands;
04882 {
04883 rtx ref = operands[1];
04884 rtx base, scratch;
04885 HOST_WIDE_INT offset = 0;
04886
04887 if (GET_CODE (ref) == SUBREG)
04888 {
04889 offset = SUBREG_BYTE (ref);
04890 ref = SUBREG_REG (ref);
04891 }
04892
04893 if (GET_CODE (ref) == REG)
04894 {
04895
04896
04897
04898
04899 if (reg_equiv_mem[REGNO (ref)])
04900 {
04901 ref = reg_equiv_mem[REGNO (ref)];
04902 base = find_replacement (&XEXP (ref, 0));
04903 }
04904 else
04905
04906 base = reg_equiv_address[REGNO (ref)];
04907 }
04908 else
04909 base = find_replacement (&XEXP (ref, 0));
04910
04911
04912 if (GET_CODE (base) == MINUS
04913 || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
04914 {
04915 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
04916
04917 emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
04918 base = base_plus;
04919 }
04920 else if (GET_CODE (base) == PLUS)
04921 {
04922
04923 HOST_WIDE_INT hi, lo;
04924
04925 offset += INTVAL (XEXP (base, 1));
04926 base = XEXP (base, 0);
04927
04928
04929
04930 lo = (offset >= 0
04931 ? (offset & 0xfff)
04932 : -((-offset) & 0xfff));
04933
04934
04935
04936
04937 if (lo == 4095)
04938 lo &= 0x7ff;
04939
04940 hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
04941 ^ (HOST_WIDE_INT) 0x80000000)
04942 - (HOST_WIDE_INT) 0x80000000);
04943
04944 if (hi + lo != offset)
04945 abort ();
04946
04947 if (hi != 0)
04948 {
04949 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
04950
04951
04952
04953 emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
04954 base = base_plus;
04955 offset = lo;
04956 }
04957 }
04958
04959 scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
04960 emit_insn (gen_zero_extendqisi2 (scratch,
04961 gen_rtx_MEM (QImode,
04962 plus_constant (base,
04963 offset))));
04964 emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
04965 gen_rtx_MEM (QImode,
04966 plus_constant (base,
04967 offset + 1))));
04968 if (!BYTES_BIG_ENDIAN)
04969 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
04970 gen_rtx_IOR (SImode,
04971 gen_rtx_ASHIFT
04972 (SImode,
04973 gen_rtx_SUBREG (SImode, operands[0], 0),
04974 GEN_INT (8)),
04975 scratch)));
04976 else
04977 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
04978 gen_rtx_IOR (SImode,
04979 gen_rtx_ASHIFT (SImode, scratch,
04980 GEN_INT (8)),
04981 gen_rtx_SUBREG (SImode, operands[0],
04982 0))));
04983 }
04984
04985
04986
04987
04988
04989
04990
04991
04992 void
04993 arm_reload_out_hi (operands)
04994 rtx * operands;
04995 {
04996 rtx ref = operands[0];
04997 rtx outval = operands[1];
04998 rtx base, scratch;
04999 HOST_WIDE_INT offset = 0;
05000
05001 if (GET_CODE (ref) == SUBREG)
05002 {
05003 offset = SUBREG_BYTE (ref);
05004 ref = SUBREG_REG (ref);
05005 }
05006
05007 if (GET_CODE (ref) == REG)
05008 {
05009
05010
05011
05012
05013 if (reg_equiv_mem[REGNO (ref)])
05014 {
05015 ref = reg_equiv_mem[REGNO (ref)];
05016 base = find_replacement (&XEXP (ref, 0));
05017 }
05018 else
05019
05020 base = reg_equiv_address[REGNO (ref)];
05021 }
05022 else
05023 base = find_replacement (&XEXP (ref, 0));
05024
05025 scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
05026
05027
05028 if (GET_CODE (base) == MINUS
05029 || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
05030 {
05031 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
05032
05033
05034 if (reg_overlap_mentioned_p (base_plus, outval))
05035 {
05036
05037
05038 if (!reg_overlap_mentioned_p (scratch, outval))
05039 {
05040 rtx tmp = scratch;
05041 scratch = base_plus;
05042 base_plus = tmp;
05043 }
05044 else
05045 {
05046 rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
05047
05048
05049
05050
05051
05052
05053
05054 emit_insn (gen_movhi (scratch_hi, outval));
05055 outval = scratch_hi;
05056 }
05057 }
05058
05059 emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
05060 base = base_plus;
05061 }
05062 else if (GET_CODE (base) == PLUS)
05063 {
05064
05065 HOST_WIDE_INT hi, lo;
05066
05067 offset += INTVAL (XEXP (base, 1));
05068 base = XEXP (base, 0);
05069
05070
05071
05072 lo = (offset >= 0
05073 ? (offset & 0xfff)
05074 : -((-offset) & 0xfff));
05075
05076
05077
05078
05079 if (lo == 4095)
05080 lo &= 0x7ff;
05081
05082 hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
05083 ^ (HOST_WIDE_INT) 0x80000000)
05084 - (HOST_WIDE_INT) 0x80000000);
05085
05086 if (hi + lo != offset)
05087 abort ();
05088
05089 if (hi != 0)
05090 {
05091 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
05092
05093
05094 if (reg_overlap_mentioned_p (base_plus, outval))
05095 {
05096
05097
05098 if (!reg_overlap_mentioned_p (scratch, outval))
05099 {
05100 rtx tmp = scratch;
05101 scratch = base_plus;
05102 base_plus = tmp;
05103 }
05104 else
05105 {
05106 rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
05107
05108
05109
05110
05111
05112
05113
05114 emit_insn (gen_movhi (scratch_hi, outval));
05115 outval = scratch_hi;
05116 }
05117 }
05118
05119
05120
05121 emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
05122 base = base_plus;
05123 offset = lo;
05124 }
05125 }
05126
05127 if (BYTES_BIG_ENDIAN)
05128 {
05129 emit_insn (gen_movqi (gen_rtx_MEM (QImode,
05130 plus_constant (base, offset + 1)),
05131 gen_lowpart (QImode, outval)));
05132 emit_insn (gen_lshrsi3 (scratch,
05133 gen_rtx_SUBREG (SImode, outval, 0),
05134 GEN_INT (8)));
05135 emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
05136 gen_lowpart (QImode, scratch)));
05137 }
05138 else
05139 {
05140 emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
05141 gen_lowpart (QImode, outval)));
05142 emit_insn (gen_lshrsi3 (scratch,
05143 gen_rtx_SUBREG (SImode, outval, 0),
05144 GEN_INT (8)));
05145 emit_insn (gen_movqi (gen_rtx_MEM (QImode,
05146 plus_constant (base, offset + 1)),
05147 gen_lowpart (QImode, scratch)));
05148 }
05149 }
05150
05151
05152
05153 static void
05154 arm_print_value (f, x)
05155 FILE * f;
05156 rtx x;
05157 {
05158 switch (GET_CODE (x))
05159 {
05160 case CONST_INT:
05161 fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
05162 return;
05163
05164 case CONST_DOUBLE:
05165 fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
05166 return;
05167
05168 case CONST_STRING:
05169 fprintf (f, "\"%s\"", XSTR (x, 0));
05170 return;
05171
05172 case SYMBOL_REF:
05173 fprintf (f, "`%s'", XSTR (x, 0));
05174 return;
05175
05176 case LABEL_REF:
05177 fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
05178 return;
05179
05180 case CONST:
05181 arm_print_value (f, XEXP (x, 0));
05182 return;
05183
05184 case PLUS:
05185 arm_print_value (f, XEXP (x, 0));
05186 fprintf (f, "+");
05187 arm_print_value (f, XEXP (x, 1));
05188 return;
05189
05190 case PC:
05191 fprintf (f, "pc");
05192 return;
05193
05194 default:
05195 fprintf (f, "????");
05196 return;
05197 }
05198 }
05199
05200
05201
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218
05219
05220
05221
05222
05223
05224
05225
05226
05227
05228
05229
05230
05231
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247
05248
05249
05250
05251
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266
05267 struct minipool_node
05268 {
05269
05270 Mnode * next;
05271 Mnode * prev;
05272
05273
05274
05275 HOST_WIDE_INT max_address;
05276
05277 HOST_WIDE_INT min_address;
05278
05279
05280
05281 int refcount;
05282
05283 HOST_WIDE_INT offset;
05284
05285 rtx value;
05286
05287 enum machine_mode mode;
05288 int fix_size;
05289 };
05290
05291 struct minipool_fixup
05292 {
05293 Mfix * next;
05294 rtx insn;
05295 HOST_WIDE_INT address;
05296 rtx * loc;
05297 enum machine_mode mode;
05298 int fix_size;
05299 rtx value;
05300 Mnode * minipool;
05301 HOST_WIDE_INT forwards;
05302 HOST_WIDE_INT backwards;
05303 };
05304
05305
05306 #define MINIPOOL_FIX_SIZE(mode) \
05307 (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
05308
05309 static Mnode * minipool_vector_head;
05310 static Mnode * minipool_vector_tail;
05311 static rtx minipool_vector_label;
05312
05313
05314 Mfix * minipool_fix_head;
05315 Mfix * minipool_fix_tail;
05316
05317 Mfix * minipool_barrier;
05318
05319
05320
05321
05322 static rtx
05323 is_jump_table (insn)
05324 rtx insn;
05325 {
05326 rtx table;
05327
05328 if (GET_CODE (insn) == JUMP_INSN
05329 && JUMP_LABEL (insn) != NULL
05330 && ((table = next_real_insn (JUMP_LABEL (insn)))
05331 == next_real_insn (insn))
05332 && table != NULL
05333 && GET_CODE (table) == JUMP_INSN
05334 && (GET_CODE (PATTERN (table)) == ADDR_VEC
05335 || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
05336 return table;
05337
05338 return NULL_RTX;
05339 }
05340
05341 #ifndef JUMP_TABLES_IN_TEXT_SECTION
05342 #define JUMP_TABLES_IN_TEXT_SECTION 0
05343 #endif
05344
05345 static HOST_WIDE_INT
05346 get_jump_table_size (insn)
05347 rtx insn;
05348 {
05349
05350
05351 if (JUMP_TABLES_IN_TEXT_SECTION
05352 #if !defined(READONLY_DATA_SECTION)
05353 || 1
05354 #endif
05355 )
05356 {
05357 rtx body = PATTERN (insn);
05358 int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
05359
05360 return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
05361 }
05362
05363 return 0;
05364 }
05365
05366
05367
05368
05369
05370 static Mnode *
05371 move_minipool_fix_forward_ref (mp, max_mp, max_address)
05372 Mnode * mp;
05373 Mnode * max_mp;
05374 HOST_WIDE_INT max_address;
05375 {
05376
05377
05378 if (mp == max_mp)
05379 abort ();
05380
05381 if (max_mp == NULL)
05382 {
05383 if (max_address < mp->max_address)
05384 mp->max_address = max_address;
05385 }
05386 else
05387 {
05388 if (max_address > max_mp->max_address - mp->fix_size)
05389 mp->max_address = max_mp->max_address - mp->fix_size;
05390 else
05391 mp->max_address = max_address;
05392
05393
05394
05395 mp->prev->next = mp->next;
05396 if (mp->next != NULL)
05397 mp->next->prev = mp->prev;
05398 else
05399 minipool_vector_tail = mp->prev;
05400
05401
05402 mp->next = max_mp;
05403 mp->prev = max_mp->prev;
05404 max_mp->prev = mp;
05405
05406 if (mp->prev != NULL)
05407 mp->prev->next = mp;
05408 else
05409 minipool_vector_head = mp;
05410 }
05411
05412
05413 max_mp = mp;
05414
05415
05416
05417 while (mp->prev != NULL
05418 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
05419 {
05420 mp->prev->max_address = mp->max_address - mp->prev->fix_size;
05421 mp = mp->prev;
05422 }
05423
05424 return max_mp;
05425 }
05426
05427
05428
05429
05430 static Mnode *
05431 add_minipool_forward_ref (fix)
05432 Mfix * fix;
05433 {
05434
05435
05436 Mnode * max_mp = NULL;
05437 HOST_WIDE_INT max_address = fix->address + fix->forwards;
05438 Mnode * mp;
05439
05440
05441
05442
05443
05444
05445 if (minipool_vector_head &&
05446 fix->address >= minipool_vector_head->max_address - fix->fix_size)
05447 return NULL;
05448
05449
05450
05451
05452
05453 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
05454 {
05455 if (GET_CODE (fix->value) == GET_CODE (mp->value)
05456 && fix->mode == mp->mode
05457 && (GET_CODE (fix->value) != CODE_LABEL
05458 || (CODE_LABEL_NUMBER (fix->value)
05459 == CODE_LABEL_NUMBER (mp->value)))
05460 && rtx_equal_p (fix->value, mp->value))
05461 {
05462
05463 mp->refcount++;
05464 return move_minipool_fix_forward_ref (mp, max_mp, max_address);
05465 }
05466
05467
05468 if (max_mp == NULL
05469 && mp->max_address > max_address)
05470 max_mp = mp;
05471 }
05472
05473
05474
05475
05476
05477
05478
05479 mp = xmalloc (sizeof (* mp));
05480 mp->fix_size = fix->fix_size;
05481 mp->mode = fix->mode;
05482 mp->value = fix->value;
05483 mp->refcount = 1;
05484
05485 mp->min_address = -65536;
05486
05487 if (max_mp == NULL)
05488 {
05489 mp->max_address = max_address;
05490 mp->next = NULL;
05491 mp->prev = minipool_vector_tail;
05492
05493 if (mp->prev == NULL)
05494 {
05495 minipool_vector_head = mp;
05496 minipool_vector_label = gen_label_rtx ();
05497 }
05498 else
05499 mp->prev->next = mp;
05500
05501 minipool_vector_tail = mp;
05502 }
05503 else
05504 {
05505 if (max_address > max_mp->max_address - mp->fix_size)
05506 mp->max_address = max_mp->max_address - mp->fix_size;
05507 else
05508 mp->max_address = max_address;
05509
05510 mp->next = max_mp;
05511 mp->prev = max_mp->prev;
05512 max_mp->prev = mp;
05513 if (mp->prev != NULL)
05514 mp->prev->next = mp;
05515 else
05516 minipool_vector_head = mp;
05517 }
05518
05519
05520 max_mp = mp;
05521
05522
05523
05524 while (mp->prev != NULL
05525 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
05526 {
05527 mp->prev->max_address = mp->max_address - mp->prev->fix_size;
05528 mp = mp->prev;
05529 }
05530
05531 return max_mp;
05532 }
05533
05534 static Mnode *
05535 move_minipool_fix_backward_ref (mp, min_mp, min_address)
05536 Mnode * mp;
05537 Mnode * min_mp;
05538 HOST_WIDE_INT min_address;
05539 {
05540 HOST_WIDE_INT offset;
05541
05542
05543
05544 if (mp == min_mp)
05545 abort ();
05546
05547 if (min_mp == NULL)
05548 {
05549 if (min_address > mp->min_address)
05550 mp->min_address = min_address;
05551 }
05552 else
05553 {
05554
05555 mp->min_address = min_address;
05556
05557
05558
05559 mp->next->prev = mp->prev;
05560 if (mp->prev != NULL)
05561 mp->prev->next = mp->next;
05562 else
05563 minipool_vector_head = mp->next;
05564
05565
05566 mp->prev = min_mp;
05567 mp->next = min_mp->next;
05568 min_mp->next = mp;
05569 if (mp->next != NULL)
05570 mp->next->prev = mp;
05571 else
05572 minipool_vector_tail = mp;
05573 }
05574
05575 min_mp = mp;
05576
05577 offset = 0;
05578 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
05579 {
05580 mp->offset = offset;
05581 if (mp->refcount > 0)
05582 offset += mp->fix_size;
05583
05584 if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
05585 mp->next->min_address = mp->min_address + mp->fix_size;
05586 }
05587
05588 return min_mp;
05589 }
05590
05591
05592
05593
05594
05595
05596
05597
05598
05599 static Mnode *
05600 add_minipool_backward_ref (fix)
05601 Mfix * fix;
05602 {
05603
05604
05605 Mnode * min_mp = NULL;
05606
05607 HOST_WIDE_INT min_address = fix->address - fix->backwards;
05608 Mnode * mp;
05609
05610
05611
05612
05613
05614 if (min_address >= minipool_barrier->address
05615 || (minipool_vector_tail->min_address + fix->fix_size
05616 >= minipool_barrier->address))
05617 return NULL;
05618
05619
05620
05621
05622
05623 for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
05624 {
05625 if (GET_CODE (fix->value) == GET_CODE (mp->value)
05626 && fix->mode == mp->mode
05627 && (GET_CODE (fix->value) != CODE_LABEL
05628 || (CODE_LABEL_NUMBER (fix->value)
05629 == CODE_LABEL_NUMBER (mp->value)))
05630 && rtx_equal_p (fix->value, mp->value)
05631
05632
05633 && (mp->max_address
05634 > (minipool_barrier->address
05635 + minipool_vector_tail->offset
05636 + minipool_vector_tail->fix_size)))
05637 {
05638 mp->refcount++;
05639 return move_minipool_fix_backward_ref (mp, min_mp, min_address);
05640 }
05641
05642 if (min_mp != NULL)
05643 mp->min_address += fix->fix_size;
05644 else
05645 {
05646
05647 if (mp->min_address < min_address)
05648 min_mp = mp;
05649 else if (mp->max_address
05650 < minipool_barrier->address + mp->offset + fix->fix_size)
05651 {
05652
05653
05654
05655
05656 min_mp = mp;
05657 min_address = mp->min_address + fix->fix_size;
05658 }
05659 }
05660 }
05661
05662
05663 mp = xmalloc (sizeof (* mp));
05664 mp->fix_size = fix->fix_size;
05665 mp->mode = fix->mode;
05666 mp->value = fix->value;
05667 mp->refcount = 1;
05668 mp->max_address = minipool_barrier->address + 65536;
05669
05670 mp->min_address = min_address;
05671
05672 if (min_mp == NULL)
05673 {
05674 mp->prev = NULL;
05675 mp->next = minipool_vector_head;
05676
05677 if (mp->next == NULL)
05678 {
05679 minipool_vector_tail = mp;
05680 minipool_vector_label = gen_label_rtx ();
05681 }
05682 else
05683 mp->next->prev = mp;
05684
05685 minipool_vector_head = mp;
05686 }
05687 else
05688 {
05689 mp->next = min_mp->next;
05690 mp->prev = min_mp;
05691 min_mp->next = mp;
05692
05693 if (mp->next != NULL)
05694 mp->next->prev = mp;
05695 else
05696 minipool_vector_tail = mp;
05697 }
05698
05699
05700 min_mp = mp;
05701
05702 if (mp->prev)
05703 mp = mp->prev;
05704 else
05705 mp->offset = 0;
05706
05707
05708 while (mp->next != NULL)
05709 {
05710 if (mp->next->min_address < mp->min_address + mp->fix_size)
05711 mp->next->min_address = mp->min_address + mp->fix_size;
05712
05713 if (mp->refcount)
05714 mp->next->offset = mp->offset + mp->fix_size;
05715 else
05716 mp->next->offset = mp->offset;
05717
05718 mp = mp->next;
05719 }
05720
05721 return min_mp;
05722 }
05723
05724 static void
05725 assign_minipool_offsets (barrier)
05726 Mfix * barrier;
05727 {
05728 HOST_WIDE_INT offset = 0;
05729 Mnode * mp;
05730
05731 minipool_barrier = barrier;
05732
05733 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
05734 {
05735 mp->offset = offset;
05736
05737 if (mp->refcount > 0)
05738 offset += mp->fix_size;
05739 }
05740 }
05741
05742
05743 static void
05744 dump_minipool (scan)
05745 rtx scan;
05746 {
05747 Mnode * mp;
05748 Mnode * nmp;
05749
05750 if (rtl_dump_file)
05751 fprintf (rtl_dump_file,
05752 ";; Emitting minipool after insn %u; address %ld\n",
05753 INSN_UID (scan), (unsigned long) minipool_barrier->address);
05754
05755 scan = emit_label_after (gen_label_rtx (), scan);
05756 scan = emit_insn_after (gen_align_4 (), scan);
05757 scan = emit_label_after (minipool_vector_label, scan);
05758
05759 for (mp = minipool_vector_head; mp != NULL; mp = nmp)
05760 {
05761 if (mp->refcount > 0)
05762 {
05763 if (rtl_dump_file)
05764 {
05765 fprintf (rtl_dump_file,
05766 ";; Offset %u, min %ld, max %ld ",
05767 (unsigned) mp->offset, (unsigned long) mp->min_address,
05768 (unsigned long) mp->max_address);
05769 arm_print_value (rtl_dump_file, mp->value);
05770 fputc ('\n', rtl_dump_file);
05771 }
05772
05773 switch (mp->fix_size)
05774 {
05775 #ifdef HAVE_consttable_1
05776 case 1:
05777 scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
05778 break;
05779
05780 #endif
05781 #ifdef HAVE_consttable_2
05782 case 2:
05783 scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
05784 break;
05785
05786 #endif
05787 #ifdef HAVE_consttable_4
05788 case 4:
05789 scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
05790 break;
05791
05792 #endif
05793 #ifdef HAVE_consttable_8
05794 case 8:
05795 scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
05796 break;
05797
05798 #endif
05799 default:
05800 abort ();
05801 break;
05802 }
05803 }
05804
05805 nmp = mp->next;
05806 free (mp);
05807 }
05808
05809 minipool_vector_head = minipool_vector_tail = NULL;
05810 scan = emit_insn_after (gen_consttable_end (), scan);
05811 scan = emit_barrier_after (scan);
05812 }
05813
05814
05815
05816 static int
05817 arm_barrier_cost (insn)
05818 rtx insn;
05819 {
05820
05821
05822
05823 int base_cost = 50;
05824 rtx next = next_nonnote_insn (insn);
05825
05826 if (next != NULL && GET_CODE (next) == CODE_LABEL)
05827 base_cost -= 20;
05828
05829 switch (GET_CODE (insn))
05830 {
05831 case CODE_LABEL:
05832
05833
05834 return 50;
05835
05836 case INSN:
05837 case CALL_INSN:
05838 return base_cost;
05839
05840 case JUMP_INSN:
05841 return base_cost - 10;
05842
05843 default:
05844 return base_cost + 10;
05845 }
05846 }
05847
05848
05849
05850
05851
05852
05853 static Mfix *
05854 create_fix_barrier (fix, max_address)
05855 Mfix * fix;
05856 HOST_WIDE_INT max_address;
05857 {
05858 HOST_WIDE_INT count = 0;
05859 rtx barrier;
05860 rtx from = fix->insn;
05861 rtx selected = from;
05862 int selected_cost;
05863 HOST_WIDE_INT selected_address;
05864 Mfix * new_fix;
05865 HOST_WIDE_INT max_count = max_address - fix->address;
05866 rtx label = gen_label_rtx ();
05867
05868 selected_cost = arm_barrier_cost (from);
05869 selected_address = fix->address;
05870
05871 while (from && count < max_count)
05872 {
05873 rtx tmp;
05874 int new_cost;
05875
05876
05877
05878 if (GET_CODE (from) == BARRIER)
05879 abort ();
05880
05881
05882 count += get_attr_length (from);
05883
05884
05885 tmp = is_jump_table (from);
05886 if (tmp != NULL)
05887 {
05888 count += get_jump_table_size (tmp);
05889
05890
05891
05892
05893 new_cost = arm_barrier_cost (from);
05894
05895 if (count < max_count && new_cost <= selected_cost)
05896 {
05897 selected = tmp;
05898 selected_cost = new_cost;
05899 selected_address = fix->address + count;
05900 }
05901
05902
05903 from = NEXT_INSN (tmp);
05904 continue;
05905 }
05906
05907 new_cost = arm_barrier_cost (from);
05908
05909 if (count < max_count && new_cost <= selected_cost)
05910 {
05911 selected = from;
05912 selected_cost = new_cost;
05913 selected_address = fix->address + count;
05914 }
05915
05916 from = NEXT_INSN (from);
05917 }
05918
05919
05920 from = emit_jump_insn_after (gen_jump (label), selected);
05921 JUMP_LABEL (from) = label;
05922 barrier = emit_barrier_after (from);
05923 emit_label_after (label, barrier);
05924
05925
05926 new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
05927 new_fix->insn = barrier;
05928 new_fix->address = selected_address;
05929 new_fix->next = fix->next;
05930 fix->next = new_fix;
05931
05932 return new_fix;
05933 }
05934
05935
05936
05937 static void
05938 push_minipool_barrier (insn, address)
05939 rtx insn;
05940 HOST_WIDE_INT address;
05941 {
05942 Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
05943
05944 fix->insn = insn;
05945 fix->address = address;
05946
05947 fix->next = NULL;
05948 if (minipool_fix_head != NULL)
05949 minipool_fix_tail->next = fix;
05950 else
05951 minipool_fix_head = fix;
05952
05953 minipool_fix_tail = fix;
05954 }
05955
05956
05957
05958
05959
05960
05961 static void
05962 push_minipool_fix (insn, address, loc, mode, value)
05963 rtx insn;
05964 HOST_WIDE_INT address;
05965 rtx * loc;
05966 enum machine_mode mode;
05967 rtx value;
05968 {
05969 Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
05970
05971 #ifdef AOF_ASSEMBLER
05972
05973
05974
05975 if (flag_pic && GET_CODE (value) == SYMBOL_REF)
05976 value = aof_pic_entry (value);
05977 #endif
05978
05979 fix->insn = insn;
05980 fix->address = address;
05981 fix->loc = loc;
05982 fix->mode = mode;
05983 fix->fix_size = MINIPOOL_FIX_SIZE (mode);
05984 fix->value = value;
05985 fix->forwards = get_attr_pool_range (insn);
05986 fix->backwards = get_attr_neg_pool_range (insn);
05987 fix->minipool = NULL;
05988
05989
05990
05991
05992 if (fix->forwards == 0 && fix->backwards == 0)
05993 abort ();
05994
05995 if (rtl_dump_file)
05996 {
05997 fprintf (rtl_dump_file,
05998 ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
05999 GET_MODE_NAME (mode),
06000 INSN_UID (insn), (unsigned long) address,
06001 -1 * (long)fix->backwards, (long)fix->forwards);
06002 arm_print_value (rtl_dump_file, fix->value);
06003 fprintf (rtl_dump_file, "\n");
06004 }
06005
06006
06007 fix->next = NULL;
06008
06009 if (minipool_fix_head != NULL)
06010 minipool_fix_tail->next = fix;
06011 else
06012 minipool_fix_head = fix;
06013
06014 minipool_fix_tail = fix;
06015 }
06016
06017
06018
06019 static void
06020 note_invalid_constants (insn, address)
06021 rtx insn;
06022 HOST_WIDE_INT address;
06023 {
06024 int opno;
06025
06026 extract_insn (insn);
06027
06028 if (!constrain_operands (1))
06029 fatal_insn_not_found (insn);
06030
06031
06032
06033 preprocess_constraints ();
06034
06035 for (opno = 0; opno < recog_data.n_operands; opno++)
06036 {
06037
06038 if (recog_data.operand_type[opno] != OP_IN)
06039 continue;
06040
06041
06042
06043
06044
06045 if (recog_op_alt[opno][which_alternative].memory_ok)
06046 {
06047 rtx op = recog_data.operand[opno];
06048
06049 if (CONSTANT_P (op))
06050 push_minipool_fix (insn, address, recog_data.operand_loc[opno],
06051 recog_data.operand_mode[opno], op);
06052 #if 0
06053
06054
06055 #ifndef AOF_ASSEMBLER
06056
06057 else if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_PIC_SYM)
06058 push_minipool_fix (insn, address, recog_data.operand_loc[opno],
06059 recog_data.operand_mode[opno],
06060 XVECEXP (op, 0, 0));
06061 #endif
06062 #endif
06063 else if (GET_CODE (op) == MEM
06064 && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
06065 && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
06066 push_minipool_fix (insn, address, recog_data.operand_loc[opno],
06067 recog_data.operand_mode[opno],
06068 get_pool_constant (XEXP (op, 0)));
06069 }
06070 }
06071 }
06072
06073 void
06074 arm_reorg (first)
06075 rtx first;
06076 {
06077 rtx insn;
06078 HOST_WIDE_INT address = 0;
06079 Mfix * fix;
06080
06081 minipool_fix_head = minipool_fix_tail = NULL;
06082
06083
06084
06085 if (GET_CODE (first) != NOTE)
06086 abort ();
06087
06088
06089 for (insn = next_nonnote_insn (first); insn; insn = next_nonnote_insn (insn))
06090 {
06091 if (GET_CODE (insn) == BARRIER)
06092 push_minipool_barrier (insn, address);
06093 else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
06094 || GET_CODE (insn) == JUMP_INSN)
06095 {
06096 rtx table;
06097
06098 note_invalid_constants (insn, address);
06099 address += get_attr_length (insn);
06100
06101
06102
06103 if ((table = is_jump_table (insn)) != NULL)
06104 {
06105 address += get_jump_table_size (table);
06106 insn = table;
06107 }
06108 }
06109 }
06110
06111 fix = minipool_fix_head;
06112
06113
06114 while (fix)
06115 {
06116 Mfix * ftmp;
06117 Mfix * fdel;
06118 Mfix * last_added_fix;
06119 Mfix * last_barrier = NULL;
06120 Mfix * this_fix;
06121
06122
06123 while (fix && GET_CODE (fix->insn) == BARRIER)
06124 fix = fix->next;
06125
06126
06127 if (fix == NULL)
06128 break;
06129
06130 last_added_fix = NULL;
06131
06132 for (ftmp = fix; ftmp; ftmp = ftmp->next)
06133 {
06134 if (GET_CODE (ftmp->insn) == BARRIER)
06135 {
06136 if (ftmp->address >= minipool_vector_head->max_address)
06137 break;
06138
06139 last_barrier = ftmp;
06140 }
06141 else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
06142 break;
06143
06144 last_added_fix = ftmp;
06145 }
06146
06147
06148
06149
06150 if (last_barrier != NULL)
06151 {
06152
06153
06154 for (fdel = last_barrier->next;
06155 fdel && fdel != ftmp;
06156 fdel = fdel->next)
06157 {
06158 fdel->minipool->refcount--;
06159 fdel->minipool = NULL;
06160 }
06161
06162 ftmp = last_barrier;
06163 }
06164 else
06165 {
06166
06167
06168
06169
06170 HOST_WIDE_INT max_address;
06171
06172
06173
06174
06175 if (ftmp == NULL)
06176 abort ();
06177
06178 max_address = minipool_vector_head->max_address;
06179
06180
06181
06182
06183 if (ftmp->address < max_address)
06184 max_address = ftmp->address;
06185
06186 last_barrier = create_fix_barrier (last_added_fix, max_address);
06187 }
06188
06189 assign_minipool_offsets (last_barrier);
06190
06191 while (ftmp)
06192 {
06193 if (GET_CODE (ftmp->insn) != BARRIER
06194 && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
06195 == NULL))
06196 break;
06197
06198 ftmp = ftmp->next;
06199 }
06200
06201
06202
06203 for (this_fix = fix; this_fix && ftmp != this_fix;
06204 this_fix = this_fix->next)
06205 if (GET_CODE (this_fix->insn) != BARRIER)
06206 {
06207 rtx addr
06208 = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
06209 minipool_vector_label),
06210 this_fix->minipool->offset);
06211 *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
06212 }
06213
06214 dump_minipool (last_barrier->insn);
06215 fix = ftmp;
06216 }
06217
06218
06219
06220
06221 after_arm_reorg = 1;
06222
06223
06224 obstack_free (&minipool_obstack, minipool_startobj);
06225 }
06226
06227
06228
06229
06230
06231
06232
06233 const char *
06234 fp_immediate_constant (x)
06235 rtx x;
06236 {
06237 REAL_VALUE_TYPE r;
06238 int i;
06239
06240 if (!fpa_consts_inited)
06241 init_fpa_table ();
06242
06243 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
06244 for (i = 0; i < 8; i++)
06245 if (REAL_VALUES_EQUAL (r, values_fpa[i]))
06246 return strings_fpa[i];
06247
06248 abort ();
06249 }
06250
06251
06252
06253 static const char *
06254 fp_const_from_val (r)
06255 REAL_VALUE_TYPE * r;
06256 {
06257 int i;
06258
06259 if (!fpa_consts_inited)
06260 init_fpa_table ();
06261
06262 for (i = 0; i < 8; i++)
06263 if (REAL_VALUES_EQUAL (*r, values_fpa[i]))
06264 return strings_fpa[i];
06265
06266 abort ();
06267 }
06268
06269
06270
06271
06272
06273
06274 static void
06275 print_multi_reg (stream, instr, reg, mask)
06276 FILE * stream;
06277 const char * instr;
06278 int reg;
06279 int mask;
06280 {
06281 int i;
06282 int not_first = FALSE;
06283
06284 fputc ('\t', stream);
06285 asm_fprintf (stream, instr, reg);
06286 fputs (", {", stream);
06287
06288 for (i = 0; i <= LAST_ARM_REGNUM; i++)
06289 if (mask & (1 << i))
06290 {
06291 if (not_first)
06292 fprintf (stream, ", ");
06293
06294 asm_fprintf (stream, "%r", i);
06295 not_first = TRUE;
06296 }
06297
06298 fprintf (stream, "}%s\n", TARGET_APCS_32 ? "" : "^");
06299 }
06300
06301
06302
06303 const char *
06304 output_call (operands)
06305 rtx * operands;
06306 {
06307
06308
06309 if (REGNO (operands[0]) == LR_REGNUM)
06310 {
06311 operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
06312 output_asm_insn ("mov%?\t%0, %|lr", operands);
06313 }
06314
06315 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
06316
06317 if (TARGET_INTERWORK)
06318 output_asm_insn ("bx%?\t%0", operands);
06319 else
06320 output_asm_insn ("mov%?\t%|pc, %0", operands);
06321
06322 return "";
06323 }
06324
06325 static int
06326 eliminate_lr2ip (x)
06327 rtx * x;
06328 {
06329 int something_changed = 0;
06330 rtx x0 = * x;
06331 int code = GET_CODE (x0);
06332 int i, j;
06333 const char * fmt;
06334
06335 switch (code)
06336 {
06337 case REG:
06338 if (REGNO (x0) == LR_REGNUM)
06339 {
06340 *x = gen_rtx_REG (SImode, IP_REGNUM);
06341 return 1;
06342 }
06343 return 0;
06344 default:
06345
06346 fmt = GET_RTX_FORMAT (code);
06347
06348 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
06349 if (fmt[i] == 'e')
06350 something_changed |= eliminate_lr2ip (&XEXP (x0, i));
06351 else if (fmt[i] == 'E')
06352 for (j = 0; j < XVECLEN (x0, i); j++)
06353 something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
06354
06355 return something_changed;
06356 }
06357 }
06358
06359
06360
06361 const char *
06362 output_call_mem (operands)
06363 rtx * operands;
06364 {
06365 operands[0] = copy_rtx (operands[0]);
06366
06367 if (eliminate_lr2ip (&operands[0]))
06368 output_asm_insn ("mov%?\t%|ip, %|lr", operands);
06369
06370 if (TARGET_INTERWORK)
06371 {
06372 output_asm_insn ("ldr%?\t%|ip, %0", operands);
06373 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
06374 output_asm_insn ("bx%?\t%|ip", operands);
06375 }
06376 else
06377 {
06378 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
06379 output_asm_insn ("ldr%?\t%|pc, %0", operands);
06380 }
06381
06382 return "";
06383 }
06384
06385
06386
06387
06388
06389
06390 const char *
06391 output_mov_long_double_fpu_from_arm (operands)
06392 rtx * operands;
06393 {
06394 int arm_reg0 = REGNO (operands[1]);
06395 rtx ops[3];
06396
06397 if (arm_reg0 == IP_REGNUM)
06398 abort ();
06399
06400 ops[0] = gen_rtx_REG (SImode, arm_reg0);
06401 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
06402 ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
06403
06404 output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
06405 output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
06406
06407 return "";
06408 }
06409
06410
06411
06412
06413
06414 const char *
06415 output_mov_long_double_arm_from_fpu (operands)
06416 rtx * operands;
06417 {
06418 int arm_reg0 = REGNO (operands[0]);
06419 rtx ops[3];
06420
06421 if (arm_reg0 == IP_REGNUM)
06422 abort ();
06423
06424 ops[0] = gen_rtx_REG (SImode, arm_reg0);
06425 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
06426 ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
06427
06428 output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
06429 output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
06430 return "";
06431 }
06432
06433
06434
06435
06436
06437 const char *
06438 output_mov_long_double_arm_from_arm (operands)
06439 rtx * operands;
06440 {
06441
06442 int dest_start = REGNO (operands[0]);
06443 int src_start = REGNO (operands[1]);
06444 rtx ops[2];
06445 int i;
06446
06447 if (dest_start < src_start)
06448 {
06449 for (i = 0; i < 3; i++)
06450 {
06451 ops[0] = gen_rtx_REG (SImode, dest_start + i);
06452 ops[1] = gen_rtx_REG (SImode, src_start + i);
06453 output_asm_insn ("mov%?\t%0, %1", ops);
06454 }
06455 }
06456 else
06457 {
06458 for (i = 2; i >= 0; i--)
06459 {
06460 ops[0] = gen_rtx_REG (SImode, dest_start + i);
06461 ops[1] = gen_rtx_REG (SImode, src_start + i);
06462 output_asm_insn ("mov%?\t%0, %1", ops);
06463 }
06464 }
06465
06466 return "";
06467 }
06468
06469
06470
06471
06472
06473
06474 const char *
06475 output_mov_double_fpu_from_arm (operands)
06476 rtx * operands;
06477 {
06478 int arm_reg0 = REGNO (operands[1]);
06479 rtx ops[2];
06480
06481 if (arm_reg0 == IP_REGNUM)
06482 abort ();
06483
06484 ops[0] = gen_rtx_REG (SImode, arm_reg0);
06485 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
06486 output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
06487 output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
06488 return "";
06489 }
06490
06491
06492
06493
06494
06495 const char *
06496 output_mov_double_arm_from_fpu (operands)
06497 rtx * operands;
06498 {
06499 int arm_reg0 = REGNO (operands[0]);
06500 rtx ops[2];
06501
06502 if (arm_reg0 == IP_REGNUM)
06503 abort ();
06504
06505 ops[0] = gen_rtx_REG (SImode, arm_reg0);
06506 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
06507 output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
06508 output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
06509 return "";
06510 }
06511
06512
06513
06514
06515
06516 const char *
06517 output_move_double (operands)
06518 rtx * operands;
06519 {
06520 enum rtx_code code0 = GET_CODE (operands[0]);
06521 enum rtx_code code1 = GET_CODE (operands[1]);
06522 rtx otherops[3];
06523
06524 if (code0 == REG)
06525 {
06526 int reg0 = REGNO (operands[0]);
06527
06528 otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
06529
06530 if (code1 == REG)
06531 {
06532 int reg1 = REGNO (operands[1]);
06533 if (reg1 == IP_REGNUM)
06534 abort ();
06535
06536
06537 if (reg1 == reg0 + (WORDS_BIG_ENDIAN ? -1 : 1))
06538 output_asm_insn ("mov%?\t%Q0, %Q1\n\tmov%?\t%R0, %R1", operands);
06539 else
06540 output_asm_insn ("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands);
06541 }
06542 else if (code1 == CONST_DOUBLE)
06543 {
06544 if (GET_MODE (operands[1]) == DFmode)
06545 {
06546 long l[2];
06547 union real_extract u;
06548
06549 memcpy (&u, &CONST_DOUBLE_LOW (operands[1]), sizeof (u));
06550 REAL_VALUE_TO_TARGET_DOUBLE (u.d, l);
06551 otherops[1] = GEN_INT (l[1]);
06552 operands[1] = GEN_INT (l[0]);
06553 }
06554 else if (GET_MODE (operands[1]) != VOIDmode)
06555 abort ();
06556 else if (WORDS_BIG_ENDIAN)
06557 {
06558 otherops[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
06559 operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
06560 }
06561 else
06562 {
06563 otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
06564 operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
06565 }
06566
06567 output_mov_immediate (operands);
06568 output_mov_immediate (otherops);
06569 }
06570 else if (code1 == CONST_INT)
06571 {
06572 #if HOST_BITS_PER_WIDE_INT > 32
06573
06574
06575 if (WORDS_BIG_ENDIAN)
06576 {
06577 otherops[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
06578 operands[1] = GEN_INT (INTVAL (operands[1]) >> 32);
06579 }
06580 else
06581 {
06582 otherops[1] = GEN_INT (INTVAL (operands[1]) >> 32);
06583 operands[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
06584 }
06585 #else
06586
06587 if (WORDS_BIG_ENDIAN)
06588 {
06589 otherops[1] = operands[1];
06590 operands[1] = (INTVAL (operands[1]) < 0
06591 ? constm1_rtx : const0_rtx);
06592 }
06593 else
06594 otherops[1] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx;
06595 #endif
06596 output_mov_immediate (otherops);
06597 output_mov_immediate (operands);
06598 }
06599 else if (code1 == MEM)
06600 {
06601 switch (GET_CODE (XEXP (operands[1], 0)))
06602 {
06603 case REG:
06604 output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
06605 break;
06606
06607 case PRE_INC:
06608 abort ();
06609 break;
06610
06611 case PRE_DEC:
06612 output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
06613 break;
06614
06615 case POST_INC:
06616 output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
06617 break;
06618
06619 case POST_DEC:
06620 abort ();
06621 break;
06622
06623 case LABEL_REF:
06624 case CONST:
06625 output_asm_insn ("adr%?\t%0, %1", operands);
06626 output_asm_insn ("ldm%?ia\t%0, %M0", operands);
06627 break;
06628
06629 default:
06630 if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
06631 GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
06632 {
06633 otherops[0] = operands[0];
06634 otherops[1] = XEXP (XEXP (operands[1], 0), 0);
06635 otherops[2] = XEXP (XEXP (operands[1], 0), 1);
06636
06637 if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
06638 {
06639 if (GET_CODE (otherops[2]) == CONST_INT)
06640 {
06641 switch (INTVAL (otherops[2]))
06642 {
06643 case -8:
06644 output_asm_insn ("ldm%?db\t%1, %M0", otherops);
06645 return "";
06646 case -4:
06647 output_asm_insn ("ldm%?da\t%1, %M0", otherops);
06648 return "";
06649 case 4:
06650 output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
06651 return "";
06652 }
06653
06654 if (!(const_ok_for_arm (INTVAL (otherops[2]))))
06655 output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
06656 else
06657 output_asm_insn ("add%?\t%0, %1, %2", otherops);
06658 }
06659 else
06660 output_asm_insn ("add%?\t%0, %1, %2", otherops);
06661 }
06662 else
06663 output_asm_insn ("sub%?\t%0, %1, %2", otherops);
06664
06665 return "ldm%?ia\t%0, %M0";
06666 }
06667 else
06668 {
06669 otherops[1] = adjust_address (operands[1], VOIDmode, 4);
06670
06671 if (reg_mentioned_p (operands[0], operands[1]))
06672 {
06673 output_asm_insn ("ldr%?\t%0, %1", otherops);
06674 output_asm_insn ("ldr%?\t%0, %1", operands);
06675 }
06676 else
06677 {
06678 output_asm_insn ("ldr%?\t%0, %1", operands);
06679 output_asm_insn ("ldr%?\t%0, %1", otherops);
06680 }
06681 }
06682 }
06683 }
06684 else
06685 abort ();
06686 }
06687 else if (code0 == MEM && code1 == REG)
06688 {
06689 if (REGNO (operands[1]) == IP_REGNUM)
06690 abort ();
06691
06692 switch (GET_CODE (XEXP (operands[0], 0)))
06693 {
06694 case REG:
06695 output_asm_insn ("stm%?ia\t%m0, %M1", operands);
06696 break;
06697
06698 case PRE_INC:
06699 abort ();
06700 break;
06701
06702 case PRE_DEC:
06703 output_asm_insn ("stm%?db\t%m0!, %M1", operands);
06704 break;
06705
06706 case POST_INC:
06707 output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
06708 break;
06709
06710 case POST_DEC:
06711 abort ();
06712 break;
06713
06714 case PLUS:
06715 if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT)
06716 {
06717 switch (INTVAL (XEXP (XEXP (operands[0], 0), 1)))
06718 {
06719 case -8:
06720 output_asm_insn ("stm%?db\t%m0, %M1", operands);
06721 return "";
06722
06723 case -4:
06724 output_asm_insn ("stm%?da\t%m0, %M1", operands);
06725 return "";
06726
06727 case 4:
06728 output_asm_insn ("stm%?ib\t%m0, %M1", operands);
06729 return "";
06730 }
06731 }
06732
06733
06734 default:
06735 otherops[0] = adjust_address (operands[0], VOIDmode, 4);
06736 otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
06737 output_asm_insn ("str%?\t%1, %0", operands);
06738 output_asm_insn ("str%?\t%1, %0", otherops);
06739 }
06740 }
06741 else
06742
06743 abort ();
06744
06745 return "";
06746 }
06747
06748
06749
06750
06751
06752 const char *
06753 output_mov_immediate (operands)
06754 rtx * operands;
06755 {
06756 HOST_WIDE_INT n = INTVAL (operands[1]);
06757
06758
06759 if (const_ok_for_arm (n))
06760 output_asm_insn ("mov%?\t%0, %1", operands);
06761
06762
06763 else if (const_ok_for_arm (~n))
06764 {
06765 operands[1] = GEN_INT (~n);
06766 output_asm_insn ("mvn%?\t%0, %1", operands);
06767 }
06768 else
06769 {
06770 int n_ones = 0;
06771 int i;
06772
06773
06774 for (i = 0; i < 32; i ++)
06775 if (n & 1 << i)
06776 n_ones ++;
06777
06778 if (n_ones > 16)
06779 output_multi_immediate (operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, ~ n);
06780 else
06781 output_multi_immediate (operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, n);
06782 }
06783
06784 return "";
06785 }
06786
06787
06788
06789
06790 const char *
06791 output_add_immediate (operands)
06792 rtx * operands;
06793 {
06794 HOST_WIDE_INT n = INTVAL (operands[2]);
06795
06796 if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
06797 {
06798 if (n < 0)
06799 output_multi_immediate (operands,
06800 "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
06801 -n);
06802 else
06803 output_multi_immediate (operands,
06804 "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
06805 n);
06806 }
06807
06808 return "";
06809 }
06810
06811
06812
06813
06814
06815
06816
06817
06818 static const char *
06819 output_multi_immediate (operands, instr1, instr2, immed_op, n)
06820 rtx * operands;
06821 const char * instr1;
06822 const char * instr2;
06823 int immed_op;
06824 HOST_WIDE_INT n;
06825 {
06826 #if HOST_BITS_PER_WIDE_INT > 32
06827 n &= 0xffffffff;
06828 #endif
06829
06830 if (n == 0)
06831 {
06832
06833 operands[immed_op] = const0_rtx;
06834 output_asm_insn (instr1, operands);
06835 }
06836 else
06837 {
06838 int i;
06839 const char * instr = instr1;
06840
06841
06842 for (i = 0; i < 32; i += 2)
06843 {
06844 if (n & (3 << i))
06845 {
06846 operands[immed_op] = GEN_INT (n & (255 << i));
06847 output_asm_insn (instr, operands);
06848 instr = instr2;
06849 i += 6;
06850 }
06851 }
06852 }
06853
06854 return "";
06855 }
06856
06857
06858
06859
06860
06861
06862 const char *
06863 arithmetic_instr (op, shift_first_arg)
06864 rtx op;
06865 int shift_first_arg;
06866 {
06867 switch (GET_CODE (op))
06868 {
06869 case PLUS:
06870 return "add";
06871
06872 case MINUS:
06873 return shift_first_arg ? "rsb" : "sub";
06874
06875 case IOR:
06876 return "orr";
06877
06878 case XOR:
06879 return "eor";
06880
06881 case AND:
06882 return "and";
06883
06884 default:
06885 abort ();
06886 }
06887 }
06888
06889
06890
06891
06892
06893
06894
06895 static const char *
06896 shift_op (op, amountp)
06897 rtx op;
06898 HOST_WIDE_INT *amountp;
06899 {
06900 const char * mnem;
06901 enum rtx_code code = GET_CODE (op);
06902
06903 if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)
06904 *amountp = -1;
06905 else if (GET_CODE (XEXP (op, 1)) == CONST_INT)
06906 *amountp = INTVAL (XEXP (op, 1));
06907 else
06908 abort ();
06909
06910 switch (code)
06911 {
06912 case ASHIFT:
06913 mnem = "asl";
06914 break;
06915
06916 case ASHIFTRT:
06917 mnem = "asr";
06918 break;
06919
06920 case LSHIFTRT:
06921 mnem = "lsr";
06922 break;
06923
06924 case ROTATERT:
06925 mnem = "ror";
06926 break;
06927
06928 case MULT:
06929
06930
06931 if (*amountp != -1)
06932 *amountp = int_log2 (*amountp);
06933 else
06934 abort ();
06935 return "asl";
06936
06937 default:
06938 abort ();
06939 }
06940
06941 if (*amountp != -1)
06942 {
06943
06944
06945
06946
06947
06948
06949
06950 if (code == ROTATERT)
06951
06952 *amountp &= 31;
06953 else if (*amountp != (*amountp & 31))
06954 {
06955 if (code == ASHIFT)
06956 mnem = "lsr";
06957 *amountp = 32;
06958 }
06959
06960
06961 if (*amountp == 0)
06962 return NULL;
06963 }
06964
06965 return mnem;
06966 }
06967
06968
06969
06970 static HOST_WIDE_INT
06971 int_log2 (power)
06972 HOST_WIDE_INT power;
06973 {
06974 HOST_WIDE_INT shift = 0;
06975
06976 while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
06977 {
06978 if (shift > 31)
06979 abort ();
06980 shift ++;
06981 }
06982
06983 return shift;
06984 }
06985
06986
06987
06988 #define MAX_ASCII_LEN 51
06989
06990 void
06991 output_ascii_pseudo_op (stream, p, len)
06992 FILE * stream;
06993 const unsigned char * p;
06994 int len;
06995 {
06996 int i;
06997 int len_so_far = 0;
06998
06999 fputs ("\t.ascii\t\"", stream);
07000
07001 for (i = 0; i < len; i++)
07002 {
07003 int c = p[i];
07004
07005 if (len_so_far >= MAX_ASCII_LEN)
07006 {
07007 fputs ("\"\n\t.ascii\t\"", stream);
07008 len_so_far = 0;
07009 }
07010
07011 switch (c)
07012 {
07013 case TARGET_TAB:
07014 fputs ("\\t", stream);
07015 len_so_far += 2;
07016 break;
07017
07018 case TARGET_FF:
07019 fputs ("\\f", stream);
07020 len_so_far += 2;
07021 break;
07022
07023 case TARGET_BS:
07024 fputs ("\\b", stream);
07025 len_so_far += 2;
07026 break;
07027
07028 case TARGET_CR:
07029 fputs ("\\r", stream);
07030 len_so_far += 2;
07031 break;
07032
07033 case TARGET_NEWLINE:
07034 fputs ("\\n", stream);
07035 c = p [i + 1];
07036 if ((c >= ' ' && c <= '~')
07037 || c == TARGET_TAB)
07038
07039 len_so_far = MAX_ASCII_LEN;
07040 else
07041 len_so_far += 2;
07042 break;
07043
07044 case '\"':
07045 case '\\':
07046 putc ('\\', stream);
07047 len_so_far++;
07048
07049
07050 default:
07051 if (c >= ' ' && c <= '~')
07052 {
07053 putc (c, stream);
07054 len_so_far++;
07055 }
07056 else
07057 {
07058 fprintf (stream, "\\%03o", c);
07059 len_so_far += 4;
07060 }
07061 break;
07062 }
07063 }
07064
07065 fputs ("\"\n", stream);
07066 }
07067
07068
07069
07070
07071
07072 static unsigned long
07073 arm_compute_save_reg0_reg12_mask ()
07074 {
07075 unsigned long func_type = arm_current_func_type ();
07076 unsigned int save_reg_mask = 0;
07077 unsigned int reg;
07078
07079 if (IS_INTERRUPT (func_type))
07080 {
07081 unsigned int max_reg;
07082
07083
07084
07085
07086
07087
07088 if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
07089
07090
07091
07092
07093
07094 max_reg = 7;
07095 else
07096 max_reg = 12;
07097
07098 for (reg = 0; reg <= max_reg; reg++)
07099 if (regs_ever_live[reg]
07100 || (! current_function_is_leaf && call_used_regs [reg]))
07101 save_reg_mask |= (1 << reg);
07102 }
07103 else
07104 {
07105
07106
07107 for (reg = 0; reg <= 10; reg++)
07108 if (regs_ever_live[reg] && ! call_used_regs [reg])
07109 save_reg_mask |= (1 << reg);
07110
07111
07112 if (! TARGET_APCS_FRAME
07113 && ! frame_pointer_needed
07114 && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
07115 && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
07116 save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
07117
07118
07119
07120 if (flag_pic
07121 && ! TARGET_SINGLE_PIC_BASE
07122 && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
07123 save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
07124 }
07125
07126 return save_reg_mask;
07127 }
07128
07129
07130
07131
07132 static unsigned long
07133 arm_compute_save_reg_mask ()
07134 {
07135 unsigned int save_reg_mask = 0;
07136 unsigned long func_type = arm_current_func_type ();
07137
07138 if (IS_NAKED (func_type))
07139
07140 return 0;
07141
07142
07143
07144 if (frame_pointer_needed)
07145 save_reg_mask |=
07146 (1 << ARM_HARD_FRAME_POINTER_REGNUM)
07147 | (1 << IP_REGNUM)
07148 | (1 << LR_REGNUM)
07149 | (1 << PC_REGNUM);
07150
07151
07152
07153 if (IS_VOLATILE (func_type))
07154 return save_reg_mask;
07155
07156 save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
07157
07158
07159
07160
07161
07162
07163
07164
07165
07166
07167 if (regs_ever_live [LR_REGNUM]
07168 || (save_reg_mask
07169 && optimize_size
07170 && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL))
07171 save_reg_mask |= 1 << LR_REGNUM;
07172
07173 if (cfun->machine->lr_save_eliminated)
07174 save_reg_mask &= ~ (1 << LR_REGNUM);
07175
07176 return save_reg_mask;
07177 }
07178
07179
07180
07181
07182 const char *
07183 output_return_instruction (operand, really_return, reverse)
07184 rtx operand;
07185 int really_return;
07186 int reverse;
07187 {
07188 char conditional[10];
07189 char instr[100];
07190 int reg;
07191 unsigned long live_regs_mask;
07192 unsigned long func_type;
07193
07194 func_type = arm_current_func_type ();
07195
07196 if (IS_NAKED (func_type))
07197 return "";
07198
07199 if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
07200 {
07201
07202
07203 if (really_return)
07204 {
07205 rtx ops[2];
07206
07207
07208 ops[0] = operand;
07209 ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
07210 : "abort");
07211 assemble_external_libcall (ops[1]);
07212 output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
07213 }
07214
07215 return "";
07216 }
07217
07218 if (current_function_calls_alloca && !really_return)
07219 abort ();
07220
07221
07222 sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
07223
07224 return_used_this_function = 1;
07225
07226 live_regs_mask = arm_compute_save_reg_mask ();
07227
07228 if (live_regs_mask)
07229 {
07230 const char * return_reg;
07231
07232
07233
07234
07235 if (really_return
07236 && ! TARGET_INTERWORK)
07237 return_reg = reg_names[PC_REGNUM];
07238 else
07239 return_reg = reg_names[LR_REGNUM];
07240
07241 if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
07242
07243
07244
07245
07246 if (! IS_INTERRUPT (func_type))
07247 {
07248 live_regs_mask &= ~ (1 << IP_REGNUM);
07249 live_regs_mask |= (1 << SP_REGNUM);
07250 }
07251
07252
07253
07254
07255
07256
07257 for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
07258 {
07259 if (live_regs_mask == (unsigned int)(1 << reg))
07260 break;
07261 }
07262 if (reg <= LAST_ARM_REGNUM
07263 && (reg != LR_REGNUM
07264 || ! really_return
07265 || (TARGET_APCS_32 && ! IS_INTERRUPT (func_type))))
07266 {
07267 sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
07268 (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
07269 }
07270 else
07271 {
07272 char *p;
07273 int first = 1;
07274
07275
07276 if (frame_pointer_needed)
07277 sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
07278 else
07279 sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
07280
07281 p = instr + strlen (instr);
07282
07283 for (reg = 0; reg <= SP_REGNUM; reg++)
07284 if (live_regs_mask & (1 << reg))
07285 {
07286 int l = strlen (reg_names[reg]);
07287
07288 if (first)
07289 first = 0;
07290 else
07291 {
07292 memcpy (p, ", ", 2);
07293 p += 2;
07294 }
07295
07296 memcpy (p, "%|", 2);
07297 memcpy (p + 2, reg_names[reg], l);
07298 p += l + 2;
07299 }
07300
07301 if (live_regs_mask & (1 << LR_REGNUM))
07302 {
07303 int l = strlen (return_reg);
07304
07305 if (! first)
07306 {
07307 memcpy (p, ", ", 2);
07308 p += 2;
07309 }
07310
07311 memcpy (p, "%|", 2);
07312 memcpy (p + 2, return_reg, l);
07313 strcpy (p + 2 + l, ((TARGET_APCS_32
07314 && !IS_INTERRUPT (func_type))
07315 || !really_return)
07316 ? "}" : "}^");
07317 }
07318 else
07319 strcpy (p, "}");
07320 }
07321
07322 output_asm_insn (instr, & operand);
07323
07324
07325
07326 if (really_return
07327 && func_type != ARM_FT_INTERWORKED
07328 && (live_regs_mask & (1 << LR_REGNUM)) != 0)
07329 {
07330
07331
07332 really_return = 0;
07333 }
07334 }
07335
07336 if (really_return)
07337 {
07338 switch ((int) ARM_FUNC_TYPE (func_type))
07339 {
07340 case ARM_FT_ISR:
07341 case ARM_FT_FIQ:
07342 sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
07343 break;
07344
07345 case ARM_FT_INTERWORKED:
07346 sprintf (instr, "bx%s\t%%|lr", conditional);
07347 break;
07348
07349 case ARM_FT_EXCEPTION:
07350 sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
07351 break;
07352
07353 default:
07354
07355
07356 if ((insn_flags & FL_ARCH5) != 0 && TARGET_APCS_32)
07357 sprintf (instr, "bx%s\t%%|lr", conditional);
07358 else
07359 sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
07360 conditional, TARGET_APCS_32 ? "" : "s");
07361 break;
07362 }
07363
07364 output_asm_insn (instr, & operand);
07365 }
07366
07367 return "";
07368 }
07369
07370
07371
07372
07373
07374
07375
07376
07377
07378
07379
07380
07381
07382
07383
07384
07385
07386
07387
07388
07389
07390
07391
07392
07393
07394
07395
07396
07397 void
07398 arm_poke_function_name (stream, name)
07399 FILE * stream;
07400 const char * name;
07401 {
07402 unsigned long alignlength;
07403 unsigned long length;
07404 rtx x;
07405
07406 length = strlen (name) + 1;
07407 alignlength = ROUND_UP (length);
07408
07409 ASM_OUTPUT_ASCII (stream, name, length);
07410 ASM_OUTPUT_ALIGN (stream, 2);
07411 x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
07412 assemble_aligned_integer (UNITS_PER_WORD, x);
07413 }
07414
07415
07416
07417
07418 static void
07419 arm_output_function_prologue (f, frame_size)
07420 FILE * f;
07421 HOST_WIDE_INT frame_size;
07422 {
07423 unsigned long func_type;
07424
07425 if (!TARGET_ARM)
07426 {
07427 thumb_output_function_prologue (f, frame_size);
07428 return;
07429 }
07430
07431
07432 if (arm_ccfsm_state || arm_target_insn)
07433 abort ();
07434
07435 func_type = arm_current_func_type ();
07436
07437 switch ((int) ARM_FUNC_TYPE (func_type))
07438 {
07439 default:
07440 case ARM_FT_NORMAL:
07441 break;
07442 case ARM_FT_INTERWORKED:
07443 asm_fprintf (f, "\t%@ Function supports interworking.\n");
07444 break;
07445 case ARM_FT_EXCEPTION_HANDLER:
07446 asm_fprintf (f, "\t%@ C++ Exception Handler.\n");
07447 break;
07448 case ARM_FT_ISR:
07449 asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
07450 break;
07451 case ARM_FT_FIQ:
07452 asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
07453 break;
07454 case ARM_FT_EXCEPTION:
07455 asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
07456 break;
07457 }
07458
07459 if (IS_NAKED (func_type))
07460 asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
07461
07462 if (IS_VOLATILE (func_type))
07463 asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
07464
07465 if (IS_NESTED (func_type))
07466 asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
07467
07468 asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n",
07469