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 current_function_args_size,
07470 current_function_pretend_args_size, frame_size);
07471
07472 asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
07473 frame_pointer_needed,
07474 cfun->machine->uses_anonymous_args);
07475
07476 if (cfun->machine->lr_save_eliminated)
07477 asm_fprintf (f, "\t%@ link register save eliminated.\n");
07478
07479 #ifdef AOF_ASSEMBLER
07480 if (flag_pic)
07481 asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
07482 #endif
07483
07484 return_used_this_function = 0;
07485 }
07486
07487 const char *
07488 arm_output_epilogue (really_return)
07489 int really_return;
07490 {
07491 int reg;
07492 unsigned long saved_regs_mask;
07493 unsigned long func_type;
07494
07495
07496 int floats_offset = 0;
07497 rtx operands[3];
07498 int frame_size = get_frame_size ();
07499 FILE * f = asm_out_file;
07500 rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
07501
07502
07503
07504 if (use_return_insn (FALSE) && return_used_this_function)
07505 return "";
07506
07507 func_type = arm_current_func_type ();
07508
07509 if (IS_NAKED (func_type))
07510
07511 return "";
07512
07513 if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
07514 {
07515 rtx op;
07516
07517
07518 op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
07519 assemble_external_libcall (op);
07520 output_asm_insn ("bl\t%a0", &op);
07521
07522 return "";
07523 }
07524
07525 if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
07526 && ! really_return)
07527
07528
07529 abort ();
07530
07531 saved_regs_mask = arm_compute_save_reg_mask ();
07532
07533
07534
07535
07536
07537 for (reg = 0; reg <= LAST_ARM_REGNUM; reg ++)
07538 if (saved_regs_mask & (1 << reg))
07539 floats_offset += 4;
07540
07541 if (frame_pointer_needed)
07542 {
07543 int vfp_offset = 4;
07544
07545 if (arm_fpu_arch == FP_SOFT2)
07546 {
07547 for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
07548 if (regs_ever_live[reg] && !call_used_regs[reg])
07549 {
07550 floats_offset += 12;
07551 asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
07552 reg, FP_REGNUM, floats_offset - vfp_offset);
07553 }
07554 }
07555 else
07556 {
07557 int start_reg = LAST_ARM_FP_REGNUM;
07558
07559 for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
07560 {
07561 if (regs_ever_live[reg] && !call_used_regs[reg])
07562 {
07563 floats_offset += 12;
07564
07565
07566 if (start_reg - reg == 3)
07567 {
07568 asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
07569 reg, FP_REGNUM, floats_offset - vfp_offset);
07570 start_reg = reg - 1;
07571 }
07572 }
07573 else
07574 {
07575 if (reg != start_reg)
07576 asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
07577 reg + 1, start_reg - reg,
07578 FP_REGNUM, floats_offset - vfp_offset);
07579 start_reg = reg - 1;
07580 }
07581 }
07582
07583
07584 if (reg != start_reg)
07585 asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
07586 reg + 1, start_reg - reg,
07587 FP_REGNUM, floats_offset - vfp_offset);
07588 }
07589
07590
07591
07592
07593
07594 if ((saved_regs_mask & (1 << IP_REGNUM)) == 0)
07595 abort ();
07596 saved_regs_mask &= ~ (1 << IP_REGNUM);
07597 saved_regs_mask |= (1 << SP_REGNUM);
07598
07599
07600
07601
07602
07603 if (really_return && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
07604
07605
07606 saved_regs_mask &= ~ (1 << LR_REGNUM);
07607 else
07608 saved_regs_mask &= ~ (1 << PC_REGNUM);
07609
07610 print_multi_reg (f, "ldmea\t%r", FP_REGNUM, saved_regs_mask);
07611
07612 if (IS_INTERRUPT (func_type))
07613
07614
07615 print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, 1 << IP_REGNUM);
07616 }
07617 else
07618 {
07619
07620 if (frame_size + current_function_outgoing_args_size != 0)
07621 {
07622 operands[0] = operands[1] = stack_pointer_rtx;
07623 operands[2] = GEN_INT (frame_size
07624 + current_function_outgoing_args_size);
07625 output_add_immediate (operands);
07626 }
07627
07628 if (arm_fpu_arch == FP_SOFT2)
07629 {
07630 for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
07631 if (regs_ever_live[reg] && !call_used_regs[reg])
07632 asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
07633 reg, SP_REGNUM);
07634 }
07635 else
07636 {
07637 int start_reg = FIRST_ARM_FP_REGNUM;
07638
07639 for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
07640 {
07641 if (regs_ever_live[reg] && !call_used_regs[reg])
07642 {
07643 if (reg - start_reg == 3)
07644 {
07645 asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
07646 start_reg, SP_REGNUM);
07647 start_reg = reg + 1;
07648 }
07649 }
07650 else
07651 {
07652 if (reg != start_reg)
07653 asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
07654 start_reg, reg - start_reg,
07655 SP_REGNUM);
07656
07657 start_reg = reg + 1;
07658 }
07659 }
07660
07661
07662 if (reg != start_reg)
07663 asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
07664 start_reg, reg - start_reg, SP_REGNUM);
07665 }
07666
07667
07668 if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
07669 && really_return
07670 && current_function_pretend_args_size == 0
07671 && saved_regs_mask & (1 << LR_REGNUM))
07672 {
07673 saved_regs_mask &= ~ (1 << LR_REGNUM);
07674 saved_regs_mask |= (1 << PC_REGNUM);
07675 }
07676
07677
07678
07679 if (saved_regs_mask == (1 << LR_REGNUM))
07680 {
07681
07682
07683 if (eh_ofs)
07684 asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
07685 else
07686 asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
07687 }
07688 else if (saved_regs_mask)
07689 print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
07690
07691 if (current_function_pretend_args_size)
07692 {
07693
07694 operands[0] = operands[1] = stack_pointer_rtx;
07695 operands[2] = GEN_INT (current_function_pretend_args_size);
07696 output_add_immediate (operands);
07697 }
07698 }
07699
07700 #if 0
07701 if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER)
07702
07703 asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
07704 REGNO (eh_ofs));
07705 #endif
07706
07707 if (! really_return
07708 || (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
07709 && current_function_pretend_args_size == 0
07710 && saved_regs_mask & (1 << PC_REGNUM)))
07711 return "";
07712
07713
07714 switch ((int) ARM_FUNC_TYPE (func_type))
07715 {
07716 case ARM_FT_EXCEPTION_HANDLER:
07717
07718
07719 asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, EXCEPTION_LR_REGNUM);
07720 break;
07721
07722 case ARM_FT_ISR:
07723 case ARM_FT_FIQ:
07724 asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
07725 break;
07726
07727 case ARM_FT_EXCEPTION:
07728 asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
07729 break;
07730
07731 case ARM_FT_INTERWORKED:
07732 asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
07733 break;
07734
07735 default:
07736 if (frame_pointer_needed)
07737
07738
07739
07740
07741 ;
07742 else if (current_function_pretend_args_size == 0
07743 && (saved_regs_mask & (1 << LR_REGNUM)))
07744
07745
07746 ;
07747 else if (TARGET_APCS_32)
07748 asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
07749 else
07750 asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
07751 break;
07752 }
07753
07754 return "";
07755 }
07756
07757 static void
07758 arm_output_function_epilogue (file, frame_size)
07759 FILE *file ATTRIBUTE_UNUSED;
07760 HOST_WIDE_INT frame_size;
07761 {
07762 if (TARGET_THUMB)
07763 {
07764
07765
07766
07767 return_used_this_function = 0;
07768 }
07769 else
07770 {
07771 if (use_return_insn (FALSE)
07772 && return_used_this_function
07773 && (frame_size + current_function_outgoing_args_size) != 0
07774 && !frame_pointer_needed)
07775 abort ();
07776
07777
07778 after_arm_reorg = 0;
07779 }
07780 }
07781
07782
07783
07784
07785
07786
07787 static rtx
07788 emit_multi_reg_push (mask)
07789 int mask;
07790 {
07791 int num_regs = 0;
07792 int num_dwarf_regs;
07793 int i, j;
07794 rtx par;
07795 rtx dwarf;
07796 int dwarf_par_index;
07797 rtx tmp, reg;
07798
07799 for (i = 0; i <= LAST_ARM_REGNUM; i++)
07800 if (mask & (1 << i))
07801 num_regs++;
07802
07803 if (num_regs == 0 || num_regs > 16)
07804 abort ();
07805
07806
07807 num_dwarf_regs = num_regs;
07808 if (mask & (1 << PC_REGNUM))
07809 num_dwarf_regs--;
07810
07811
07812
07813
07814
07815
07816
07817
07818
07819
07820
07821
07822
07823
07824
07825
07826
07827
07828
07829
07830
07831
07832
07833
07834
07835
07836
07837
07838
07839
07840
07841
07842
07843 par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
07844 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
07845 RTX_FRAME_RELATED_P (dwarf) = 1;
07846 dwarf_par_index = 1;
07847
07848 for (i = 0; i <= LAST_ARM_REGNUM; i++)
07849 {
07850 if (mask & (1 << i))
07851 {
07852 reg = gen_rtx_REG (SImode, i);
07853
07854 XVECEXP (par, 0, 0)
07855 = gen_rtx_SET (VOIDmode,
07856 gen_rtx_MEM (BLKmode,
07857 gen_rtx_PRE_DEC (BLKmode,
07858 stack_pointer_rtx)),
07859 gen_rtx_UNSPEC (BLKmode,
07860 gen_rtvec (1, reg),
07861 UNSPEC_PUSH_MULT));
07862
07863 if (i != PC_REGNUM)
07864 {
07865 tmp = gen_rtx_SET (VOIDmode,
07866 gen_rtx_MEM (SImode, stack_pointer_rtx),
07867 reg);
07868 RTX_FRAME_RELATED_P (tmp) = 1;
07869 XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
07870 dwarf_par_index++;
07871 }
07872
07873 break;
07874 }
07875 }
07876
07877 for (j = 1, i++; j < num_regs; i++)
07878 {
07879 if (mask & (1 << i))
07880 {
07881 reg = gen_rtx_REG (SImode, i);
07882
07883 XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
07884
07885 if (i != PC_REGNUM)
07886 {
07887 tmp = gen_rtx_SET (VOIDmode,
07888 gen_rtx_MEM (SImode,
07889 plus_constant (stack_pointer_rtx,
07890 4 * j)),
07891 reg);
07892 RTX_FRAME_RELATED_P (tmp) = 1;
07893 XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
07894 }
07895
07896 j++;
07897 }
07898 }
07899
07900 par = emit_insn (par);
07901
07902 tmp = gen_rtx_SET (SImode,
07903 stack_pointer_rtx,
07904 gen_rtx_PLUS (SImode,
07905 stack_pointer_rtx,
07906 GEN_INT (-4 * num_regs)));
07907 RTX_FRAME_RELATED_P (tmp) = 1;
07908 XVECEXP (dwarf, 0, 0) = tmp;
07909
07910 REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
07911 REG_NOTES (par));
07912 return par;
07913 }
07914
07915 static rtx
07916 emit_sfm (base_reg, count)
07917 int base_reg;
07918 int count;
07919 {
07920 rtx par;
07921 rtx dwarf;
07922 rtx tmp, reg;
07923 int i;
07924
07925 par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
07926 dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
07927 RTX_FRAME_RELATED_P (dwarf) = 1;
07928
07929 reg = gen_rtx_REG (XFmode, base_reg++);
07930
07931 XVECEXP (par, 0, 0)
07932 = gen_rtx_SET (VOIDmode,
07933 gen_rtx_MEM (BLKmode,
07934 gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
07935 gen_rtx_UNSPEC (BLKmode,
07936 gen_rtvec (1, reg),
07937 UNSPEC_PUSH_MULT));
07938 tmp
07939 = gen_rtx_SET (VOIDmode,
07940 gen_rtx_MEM (XFmode,
07941 gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
07942 reg);
07943 RTX_FRAME_RELATED_P (tmp) = 1;
07944 XVECEXP (dwarf, 0, count - 1) = tmp;
07945
07946 for (i = 1; i < count; i++)
07947 {
07948 reg = gen_rtx_REG (XFmode, base_reg++);
07949 XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
07950
07951 tmp = gen_rtx_SET (VOIDmode,
07952 gen_rtx_MEM (XFmode,
07953 gen_rtx_PRE_DEC (BLKmode,
07954 stack_pointer_rtx)),
07955 reg);
07956 RTX_FRAME_RELATED_P (tmp) = 1;
07957 XVECEXP (dwarf, 0, count - i - 1) = tmp;
07958 }
07959
07960 par = emit_insn (par);
07961 REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
07962 REG_NOTES (par));
07963 return par;
07964 }
07965
07966
07967
07968
07969
07970
07971
07972
07973
07974
07975
07976
07977
07978
07979
07980
07981
07982
07983
07984
07985
07986
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996
07997
07998
07999
08000
08001
08002
08003
08004
08005
08006
08007
08008
08009
08010 unsigned int
08011 arm_compute_initial_elimination_offset (from, to)
08012 unsigned int from;
08013 unsigned int to;
08014 {
08015 unsigned int local_vars = (get_frame_size () + 3) & ~3;
08016 unsigned int outgoing_args = current_function_outgoing_args_size;
08017 unsigned int stack_frame;
08018 unsigned int call_saved_registers;
08019 unsigned long func_type;
08020
08021 func_type = arm_current_func_type ();
08022
08023
08024
08025 call_saved_registers = 0;
08026 if (! IS_VOLATILE (func_type))
08027 {
08028 unsigned int reg_mask;
08029 unsigned int reg;
08030
08031
08032
08033
08034 reg_mask = arm_compute_save_reg0_reg12_mask ();
08035
08036
08037
08038 while (reg_mask)
08039 {
08040 call_saved_registers += 4;
08041 reg_mask = reg_mask & ~ (reg_mask & - reg_mask);
08042 }
08043
08044 if (regs_ever_live[LR_REGNUM]
08045
08046
08047
08048 && ! frame_pointer_needed)
08049 call_saved_registers += 4;
08050
08051
08052
08053
08054 for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg ++)
08055 if (regs_ever_live[reg] && ! call_used_regs[reg])
08056 call_saved_registers += 12;
08057 }
08058
08059
08060
08061
08062 stack_frame = frame_pointer_needed ? 16 : 0;
08063
08064
08065
08066
08067
08068 switch (from)
08069 {
08070 case ARG_POINTER_REGNUM:
08071 switch (to)
08072 {
08073 case THUMB_HARD_FRAME_POINTER_REGNUM:
08074 return 0;
08075
08076 case FRAME_POINTER_REGNUM:
08077
08078
08079 if (call_saved_registers == 0 && stack_frame == 0)
08080 return 0;
08081 return (call_saved_registers + stack_frame - 4);
08082
08083 case ARM_HARD_FRAME_POINTER_REGNUM:
08084
08085
08086 if (stack_frame == 0 && call_saved_registers != 0)
08087 return 0;
08088
08089 return (frame_pointer_needed
08090 && current_function_needs_context
08091 && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
08092
08093 case STACK_POINTER_REGNUM:
08094
08095
08096 return call_saved_registers + stack_frame + local_vars + outgoing_args - 4;
08097
08098 default:
08099 abort ();
08100 }
08101 break;
08102
08103 case FRAME_POINTER_REGNUM:
08104 switch (to)
08105 {
08106 case THUMB_HARD_FRAME_POINTER_REGNUM:
08107 return 0;
08108
08109 case ARM_HARD_FRAME_POINTER_REGNUM:
08110
08111
08112
08113
08114 if (call_saved_registers == 0 && stack_frame == 0)
08115 return 0;
08116 return - (call_saved_registers + stack_frame - 4);
08117
08118 case STACK_POINTER_REGNUM:
08119 return local_vars + outgoing_args;
08120
08121 default:
08122 abort ();
08123 }
08124 break;
08125
08126 default:
08127
08128
08129
08130
08131
08132 abort ();
08133 }
08134 }
08135
08136
08137
08138 void
08139 arm_expand_prologue ()
08140 {
08141 int reg;
08142 rtx amount;
08143 rtx insn;
08144 rtx ip_rtx;
08145 unsigned long live_regs_mask;
08146 unsigned long func_type;
08147 int fp_offset = 0;
08148 int saved_pretend_args = 0;
08149 unsigned int args_to_push;
08150
08151 func_type = arm_current_func_type ();
08152
08153
08154 if (IS_NAKED (func_type))
08155 return;
08156
08157
08158 args_to_push = current_function_pretend_args_size;
08159
08160
08161 live_regs_mask = arm_compute_save_reg_mask ();
08162
08163 ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
08164
08165 if (frame_pointer_needed)
08166 {
08167 if (IS_INTERRUPT (func_type))
08168 {
08169
08170
08171
08172 insn = emit_multi_reg_push (1 << IP_REGNUM);
08173
08174
08175
08176
08177
08178
08179
08180
08181
08182
08183
08184
08185 }
08186 else if (IS_NESTED (func_type))
08187 {
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204
08205 if (regs_ever_live[3] == 0)
08206 {
08207 insn = gen_rtx_REG (SImode, 3);
08208 insn = gen_rtx_SET (SImode, insn, ip_rtx);
08209 insn = emit_insn (insn);
08210 }
08211 else if (args_to_push == 0)
08212 {
08213 rtx dwarf;
08214 insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
08215 insn = gen_rtx_MEM (SImode, insn);
08216 insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
08217 insn = emit_insn (insn);
08218
08219 fp_offset = 4;
08220
08221
08222 dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
08223 gen_rtx_PLUS (SImode, stack_pointer_rtx,
08224 GEN_INT (-fp_offset)));
08225 RTX_FRAME_RELATED_P (insn) = 1;
08226 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
08227 dwarf, REG_NOTES (insn));
08228 }
08229 else
08230 {
08231
08232 if (cfun->machine->uses_anonymous_args)
08233 insn = emit_multi_reg_push
08234 ((0xf0 >> (args_to_push / 4)) & 0xf);
08235 else
08236 insn = emit_insn
08237 (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
08238 GEN_INT (- args_to_push)));
08239
08240 RTX_FRAME_RELATED_P (insn) = 1;
08241
08242 saved_pretend_args = 1;
08243 fp_offset = args_to_push;
08244 args_to_push = 0;
08245
08246
08247 insn = gen_rtx_REG (SImode, 3);
08248 insn = gen_rtx_SET (SImode, insn, ip_rtx);
08249 (void) emit_insn (insn);
08250 }
08251 }
08252
08253 if (fp_offset)
08254 {
08255 insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
08256 insn = gen_rtx_SET (SImode, ip_rtx, insn);
08257 }
08258 else
08259 insn = gen_movsi (ip_rtx, stack_pointer_rtx);
08260
08261 insn = emit_insn (insn);
08262 RTX_FRAME_RELATED_P (insn) = 1;
08263 }
08264
08265 if (args_to_push)
08266 {
08267
08268 if (cfun->machine->uses_anonymous_args)
08269 insn = emit_multi_reg_push
08270 ((0xf0 >> (args_to_push / 4)) & 0xf);
08271 else
08272 insn = emit_insn
08273 (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
08274 GEN_INT (- args_to_push)));
08275 RTX_FRAME_RELATED_P (insn) = 1;
08276 }
08277
08278
08279
08280
08281 if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
08282 && (live_regs_mask & (1 << LR_REGNUM)) != 0)
08283 {
08284 emit_insn (gen_rtx_SET (SImode,
08285 gen_rtx_REG (SImode, LR_REGNUM),
08286 gen_rtx_PLUS (SImode,
08287 gen_rtx_REG (SImode, LR_REGNUM),
08288 GEN_INT (-4))));
08289 }
08290
08291 if (live_regs_mask)
08292 {
08293 insn = emit_multi_reg_push (live_regs_mask);
08294 RTX_FRAME_RELATED_P (insn) = 1;
08295 }
08296
08297 if (! IS_VOLATILE (func_type))
08298 {
08299
08300 if (arm_fpu_arch == FP_SOFT2)
08301 {
08302 for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
08303 if (regs_ever_live[reg] && !call_used_regs[reg])
08304 {
08305 insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
08306 insn = gen_rtx_MEM (XFmode, insn);
08307 insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
08308 gen_rtx_REG (XFmode, reg)));
08309 RTX_FRAME_RELATED_P (insn) = 1;
08310 }
08311 }
08312 else
08313 {
08314 int start_reg = LAST_ARM_FP_REGNUM;
08315
08316 for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
08317 {
08318 if (regs_ever_live[reg] && !call_used_regs[reg])
08319 {
08320 if (start_reg - reg == 3)
08321 {
08322 insn = emit_sfm (reg, 4);
08323 RTX_FRAME_RELATED_P (insn) = 1;
08324 start_reg = reg - 1;
08325 }
08326 }
08327 else
08328 {
08329 if (start_reg != reg)
08330 {
08331 insn = emit_sfm (reg + 1, start_reg - reg);
08332 RTX_FRAME_RELATED_P (insn) = 1;
08333 }
08334 start_reg = reg - 1;
08335 }
08336 }
08337
08338 if (start_reg != reg)
08339 {
08340 insn = emit_sfm (reg + 1, start_reg - reg);
08341 RTX_FRAME_RELATED_P (insn) = 1;
08342 }
08343 }
08344 }
08345
08346 if (frame_pointer_needed)
08347 {
08348
08349 insn = GEN_INT (-(4 + args_to_push + fp_offset));
08350 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
08351 RTX_FRAME_RELATED_P (insn) = 1;
08352
08353 if (IS_NESTED (func_type))
08354 {
08355
08356 if (regs_ever_live [3] == 0
08357 || saved_pretend_args)
08358 insn = gen_rtx_REG (SImode, 3);
08359 else
08360 {
08361 insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
08362 insn = gen_rtx_MEM (SImode, insn);
08363 }
08364
08365 emit_insn (gen_rtx_SET (SImode, ip_rtx, insn));
08366
08367 emit_insn (gen_prologue_use (ip_rtx));
08368 }
08369 }
08370
08371 amount = GEN_INT (-(get_frame_size ()
08372 + current_function_outgoing_args_size));
08373
08374 if (amount != const0_rtx)
08375 {
08376
08377
08378 rtx last = get_last_insn ();
08379 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
08380 amount));
08381 do
08382 {
08383 last = last ? NEXT_INSN (last) : get_insns ();
08384 RTX_FRAME_RELATED_P (last) = 1;
08385 }
08386 while (last != insn);
08387
08388
08389
08390
08391 if (frame_pointer_needed)
08392 {
08393 rtx unspec = gen_rtx_UNSPEC (SImode,
08394 gen_rtvec (2, stack_pointer_rtx,
08395 hard_frame_pointer_rtx),
08396 UNSPEC_PRLG_STK);
08397
08398 insn = emit_insn (gen_rtx_CLOBBER (VOIDmode,
08399 gen_rtx_MEM (BLKmode, unspec)));
08400 }
08401 }
08402
08403
08404
08405
08406 if (current_function_profile || TARGET_NO_SCHED_PRO)
08407 emit_insn (gen_blockage ());
08408
08409
08410
08411 if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
08412 {
08413 emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
08414 cfun->machine->lr_save_eliminated = 1;
08415 }
08416 }
08417
08418
08419
08420
08421
08422
08423
08424
08425
08426
08427
08428
08429
08430
08431
08432 void
08433 arm_print_operand (stream, x, code)
08434 FILE * stream;
08435 rtx x;
08436 int code;
08437 {
08438 switch (code)
08439 {
08440 case '@':
08441 fputs (ASM_COMMENT_START, stream);
08442 return;
08443
08444 case '_':
08445 fputs (user_label_prefix, stream);
08446 return;
08447
08448 case '|':
08449 fputs (REGISTER_PREFIX, stream);
08450 return;
08451
08452 case '?':
08453 if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
08454 {
08455 if (TARGET_THUMB || current_insn_predicate != NULL)
08456 abort ();
08457
08458 fputs (arm_condition_codes[arm_current_cc], stream);
08459 }
08460 else if (current_insn_predicate)
08461 {
08462 enum arm_cond_code code;
08463
08464 if (TARGET_THUMB)
08465 abort ();
08466
08467 code = get_arm_condition_code (current_insn_predicate);
08468 fputs (arm_condition_codes[code], stream);
08469 }
08470 return;
08471
08472 case 'N':
08473 {
08474 REAL_VALUE_TYPE r;
08475 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
08476 r = REAL_VALUE_NEGATE (r);
08477 fprintf (stream, "%s", fp_const_from_val (&r));
08478 }
08479 return;
08480
08481 case 'B':
08482 if (GET_CODE (x) == CONST_INT)
08483 {
08484 HOST_WIDE_INT val;
08485 val = ARM_SIGN_EXTEND (~INTVAL (x));
08486 fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
08487 }
08488 else
08489 {
08490 putc ('~', stream);
08491 output_addr_const (stream, x);
08492 }
08493 return;
08494
08495 case 'i':
08496 fprintf (stream, "%s", arithmetic_instr (x, 1));
08497 return;
08498
08499 case 'I':
08500 fprintf (stream, "%s", arithmetic_instr (x, 0));
08501 return;
08502
08503 case 'S':
08504 {
08505 HOST_WIDE_INT val;
08506 const char * shift = shift_op (x, &val);
08507
08508 if (shift)
08509 {
08510 fprintf (stream, ", %s ", shift_op (x, &val));
08511 if (val == -1)
08512 arm_print_operand (stream, XEXP (x, 1), 0);
08513 else
08514 {
08515 fputc ('#', stream);
08516 fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
08517 }
08518 }
08519 }
08520 return;
08521
08522
08523
08524
08525
08526
08527
08528
08529
08530
08531
08532
08533
08534
08535
08536
08537
08538
08539
08540
08541
08542
08543
08544
08545
08546
08547
08548
08549 case 'Q':
08550 if (REGNO (x) > LAST_ARM_REGNUM)
08551 abort ();
08552 asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
08553 return;
08554
08555 case 'R':
08556 if (REGNO (x) > LAST_ARM_REGNUM)
08557 abort ();
08558 asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
08559 return;
08560
08561 case 'H':
08562 if (REGNO (x) > LAST_ARM_REGNUM)
08563 abort ();
08564 asm_fprintf (stream, "%r", REGNO (x) + 1);
08565 return;
08566
08567 case 'm':
08568 asm_fprintf (stream, "%r",
08569 GET_CODE (XEXP (x, 0)) == REG
08570 ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
08571 return;
08572
08573 case 'M':
08574 asm_fprintf (stream, "{%r-%r}",
08575 REGNO (x),
08576 REGNO (x) + NUM_REGS (GET_MODE (x)) - 1);
08577 return;
08578
08579 case 'd':
08580 if (!x)
08581 return;
08582
08583 if (TARGET_ARM)
08584 fputs (arm_condition_codes[get_arm_condition_code (x)],
08585 stream);
08586 else
08587 fputs (thumb_condition_code (x, 0), stream);
08588 return;
08589
08590 case 'D':
08591 if (!x)
08592 return;
08593
08594 if (TARGET_ARM)
08595 fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
08596 (get_arm_condition_code (x))],
08597 stream);
08598 else
08599 fputs (thumb_condition_code (x, 1), stream);
08600 return;
08601
08602 default:
08603 if (x == 0)
08604 abort ();
08605
08606 if (GET_CODE (x) == REG)
08607 asm_fprintf (stream, "%r", REGNO (x));
08608 else if (GET_CODE (x) == MEM)
08609 {
08610 output_memory_reference_mode = GET_MODE (x);
08611 output_address (XEXP (x, 0));
08612 }
08613 else if (GET_CODE (x) == CONST_DOUBLE)
08614 fprintf (stream, "#%s", fp_immediate_constant (x));
08615 else if (GET_CODE (x) == NEG)
08616 abort ();
08617 else
08618 {
08619 fputc ('#', stream);
08620 output_addr_const (stream, x);
08621 }
08622 }
08623 }
08624
08625 #ifndef AOF_ASSEMBLER
08626
08627
08628
08629 static bool
08630 arm_assemble_integer (x, size, aligned_p)
08631 rtx x;
08632 unsigned int size;
08633 int aligned_p;
08634 {
08635 if (size == UNITS_PER_WORD && aligned_p)
08636 {
08637 fputs ("\t.word\t", asm_out_file);
08638 output_addr_const (asm_out_file, x);
08639
08640
08641
08642 if (NEED_GOT_RELOC && flag_pic && making_const_table &&
08643 (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
08644 {
08645 if (GET_CODE (x) == SYMBOL_REF
08646 && (CONSTANT_POOL_ADDRESS_P (x)
08647 || ENCODED_SHORT_CALL_ATTR_P (XSTR (x, 0))))
08648 fputs ("(GOTOFF)", asm_out_file);
08649 else if (GET_CODE (x) == LABEL_REF)
08650 fputs ("(GOTOFF)", asm_out_file);
08651 else
08652 fputs ("(GOT)", asm_out_file);
08653 }
08654 fputc ('\n', asm_out_file);
08655 return true;
08656 }
08657
08658 return default_assemble_integer (x, size, aligned_p);
08659 }
08660 #endif
08661
08662
08663
08664
08665
08666
08667
08668
08669
08670
08671
08672
08673
08674
08675
08676
08677
08678
08679
08680
08681
08682
08683
08684
08685
08686
08687
08688
08689
08690
08691
08692
08693
08694
08695
08696
08697 static enum arm_cond_code
08698 get_arm_condition_code (comparison)
08699 rtx comparison;
08700 {
08701 enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
08702 int code;
08703 enum rtx_code comp_code = GET_CODE (comparison);
08704
08705 if (GET_MODE_CLASS (mode) != MODE_CC)
08706 mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
08707 XEXP (comparison, 1));
08708
08709 switch (mode)
08710 {
08711 case CC_DNEmode: code = ARM_NE; goto dominance;
08712 case CC_DEQmode: code = ARM_EQ; goto dominance;
08713 case CC_DGEmode: code = ARM_GE; goto dominance;
08714 case CC_DGTmode: code = ARM_GT; goto dominance;
08715 case CC_DLEmode: code = ARM_LE; goto dominance;
08716 case CC_DLTmode: code = ARM_LT; goto dominance;
08717 case CC_DGEUmode: code = ARM_CS; goto dominance;
08718 case CC_DGTUmode: code = ARM_HI; goto dominance;
08719 case CC_DLEUmode: code = ARM_LS; goto dominance;
08720 case CC_DLTUmode: code = ARM_CC;
08721
08722 dominance:
08723 if (comp_code != EQ && comp_code != NE)
08724 abort ();
08725
08726 if (comp_code == EQ)
08727 return ARM_INVERSE_CONDITION_CODE (code);
08728 return code;
08729
08730 case CC_NOOVmode:
08731 switch (comp_code)
08732 {
08733 case NE: return ARM_NE;
08734 case EQ: return ARM_EQ;
08735 case GE: return ARM_PL;
08736 case LT: return ARM_MI;
08737 default: abort ();
08738 }
08739
08740 case CC_Zmode:
08741 switch (comp_code)
08742 {
08743 case NE: return ARM_NE;
08744 case EQ: return ARM_EQ;
08745 default: abort ();
08746 }
08747
08748 case CCFPEmode:
08749 case CCFPmode:
08750
08751
08752
08753 switch (comp_code)
08754 {
08755 case GE: return ARM_GE;
08756 case GT: return ARM_GT;
08757 case LE: return ARM_LS;
08758 case LT: return ARM_MI;
08759 case NE: return ARM_NE;
08760 case EQ: return ARM_EQ;
08761 case ORDERED: return ARM_VC;
08762 case UNORDERED: return ARM_VS;
08763 case UNLT: return ARM_LT;
08764 case UNLE: return ARM_LE;
08765 case UNGT: return ARM_HI;
08766 case UNGE: return ARM_PL;
08767
08768 case UNEQ:
08769 case LTGT:
08770 default: abort ();
08771 }
08772
08773 case CC_SWPmode:
08774 switch (comp_code)
08775 {
08776 case NE: return ARM_NE;
08777 case EQ: return ARM_EQ;
08778 case GE: return ARM_LE;
08779 case GT: return ARM_LT;
08780 case LE: return ARM_GE;
08781 case LT: return ARM_GT;
08782 case GEU: return ARM_LS;
08783 case GTU: return ARM_CC;
08784 case LEU: return ARM_CS;
08785 case LTU: return ARM_HI;
08786 default: abort ();
08787 }
08788
08789 case CC_Cmode:
08790 switch (comp_code)
08791 {
08792 case LTU: return ARM_CS;
08793 case GEU: return ARM_CC;
08794 default: abort ();
08795 }
08796
08797 case CCmode:
08798 switch (comp_code)
08799 {
08800 case NE: return ARM_NE;
08801 case EQ: return ARM_EQ;
08802 case GE: return ARM_GE;
08803 case GT: return ARM_GT;
08804 case LE: return ARM_LE;
08805 case LT: return ARM_LT;
08806 case GEU: return ARM_CS;
08807 case GTU: return ARM_HI;
08808 case LEU: return ARM_LS;
08809 case LTU: return ARM_CC;
08810 default: abort ();
08811 }
08812
08813 default: abort ();
08814 }
08815
08816 abort ();
08817 }
08818
08819
08820 void
08821 arm_final_prescan_insn (insn)
08822 rtx insn;
08823 {
08824
08825 rtx body = PATTERN (insn);
08826
08827
08828
08829 int reverse = 0;
08830
08831
08832
08833
08834
08835 int jump_clobbers = 0;
08836
08837
08838 int seeking_return = 0;
08839
08840
08841
08842 rtx start_insn = insn;
08843
08844
08845
08846 if (arm_ccfsm_state == 4)
08847 {
08848 if (insn == arm_target_insn)
08849 {
08850 arm_target_insn = NULL;
08851 arm_ccfsm_state = 0;
08852 }
08853 return;
08854 }
08855
08856
08857
08858
08859
08860 if (arm_ccfsm_state == 3)
08861 {
08862 if (simplejump_p (insn))
08863 {
08864 start_insn = next_nonnote_insn (start_insn);
08865 if (GET_CODE (start_insn) == BARRIER)
08866 {
08867
08868 start_insn = next_nonnote_insn (start_insn);
08869 }
08870 if (GET_CODE (start_insn) == CODE_LABEL
08871 && CODE_LABEL_NUMBER (start_insn) == arm_target_label
08872 && LABEL_NUSES (start_insn) == 1)
08873 reverse = TRUE;
08874 else
08875 return;
08876 }
08877 else if (GET_CODE (body) == RETURN)
08878 {
08879 start_insn = next_nonnote_insn (start_insn);
08880 if (GET_CODE (start_insn) == BARRIER)
08881 start_insn = next_nonnote_insn (start_insn);
08882 if (GET_CODE (start_insn) == CODE_LABEL
08883 && CODE_LABEL_NUMBER (start_insn) == arm_target_label
08884 && LABEL_NUSES (start_insn) == 1)
08885 {
08886 reverse = TRUE;
08887 seeking_return = 1;
08888 }
08889 else
08890 return;
08891 }
08892 else
08893 return;
08894 }
08895
08896 if (arm_ccfsm_state != 0 && !reverse)
08897 abort ();
08898 if (GET_CODE (insn) != JUMP_INSN)
08899 return;
08900
08901
08902
08903 if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
08904 body = XVECEXP (body, 0, 0);
08905
08906 #if 0
08907
08908 if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
08909 && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
08910 && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN
08911 || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN))
08912 return;
08913 #endif
08914
08915 if (reverse
08916 || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
08917 && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
08918 {
08919 int insns_skipped;
08920 int fail = FALSE, succeed = FALSE;
08921
08922 int then_not_else = TRUE;
08923 rtx this_insn = start_insn, label = 0;
08924
08925
08926
08927 if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
08928 {
08929 jump_clobbers = 1;
08930 return;
08931 }
08932
08933
08934 if (reverse)
08935 {
08936 if (!seeking_return)
08937 label = XEXP (SET_SRC (body), 0);
08938 }
08939 else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
08940 label = XEXP (XEXP (SET_SRC (body), 1), 0);
08941 else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
08942 {
08943 label = XEXP (XEXP (SET_SRC (body), 2), 0);
08944 then_not_else = FALSE;
08945 }
08946 else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
08947 seeking_return = 1;
08948 else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
08949 {
08950 seeking_return = 1;
08951 then_not_else = FALSE;
08952 }
08953 else
08954 abort ();
08955
08956
08957
08958
08959 for (insns_skipped = 0;
08960 !fail && !succeed && insns_skipped++ < max_insns_skipped;)
08961 {
08962 rtx scanbody;
08963
08964 this_insn = next_nonnote_insn (this_insn);
08965 if (!this_insn)
08966 break;
08967
08968 switch (GET_CODE (this_insn))
08969 {
08970 case CODE_LABEL:
08971
08972
08973 if (this_insn == label)
08974 {
08975 if (jump_clobbers)
08976 {
08977 arm_ccfsm_state = 2;
08978 this_insn = next_nonnote_insn (this_insn);
08979 }
08980 else
08981 arm_ccfsm_state = 1;
08982 succeed = TRUE;
08983 }
08984 else
08985 fail = TRUE;
08986 break;
08987
08988 case BARRIER:
08989
08990
08991
08992
08993 this_insn = next_nonnote_insn (this_insn);
08994 if (this_insn && this_insn == label)
08995 {
08996 if (jump_clobbers)
08997 {
08998 arm_ccfsm_state = 2;
08999 this_insn = next_nonnote_insn (this_insn);
09000 }
09001 else
09002 arm_ccfsm_state = 1;
09003 succeed = TRUE;
09004 }
09005 else
09006 fail = TRUE;
09007 break;
09008
09009 case CALL_INSN:
09010
09011
09012 if (TARGET_APCS_32)
09013 {
09014
09015
09016
09017 this_insn = next_nonnote_insn (this_insn);
09018 if (this_insn && GET_CODE (this_insn) == BARRIER)
09019 this_insn = next_nonnote_insn (this_insn);
09020
09021 if (this_insn && this_insn == label
09022 && insns_skipped < max_insns_skipped)
09023 {
09024 if (jump_clobbers)
09025 {
09026 arm_ccfsm_state = 2;
09027 this_insn = next_nonnote_insn (this_insn);
09028 }
09029 else
09030 arm_ccfsm_state = 1;
09031 succeed = TRUE;
09032 }
09033 else
09034 fail = TRUE;
09035 }
09036 break;
09037
09038 case JUMP_INSN:
09039
09040
09041
09042
09043
09044 scanbody = PATTERN (this_insn);
09045 if (GET_CODE (scanbody) == SET
09046 && GET_CODE (SET_DEST (scanbody)) == PC)
09047 {
09048 if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
09049 && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
09050 {
09051 arm_ccfsm_state = 2;
09052 succeed = TRUE;
09053 }
09054 else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
09055 fail = TRUE;
09056 }
09057
09058
09059 else if (GET_CODE (scanbody) == RETURN
09060 && !use_return_insn (TRUE)
09061 && !optimize_size)
09062 fail = TRUE;
09063 else if (GET_CODE (scanbody) == RETURN
09064 && seeking_return)
09065 {
09066 arm_ccfsm_state = 2;
09067 succeed = TRUE;
09068 }
09069 else if (GET_CODE (scanbody) == PARALLEL)
09070 {
09071 switch (get_attr_conds (this_insn))
09072 {
09073 case CONDS_NOCOND:
09074 break;
09075 default:
09076 fail = TRUE;
09077 break;
09078 }
09079 }
09080 else
09081 fail = TRUE;
09082
09083 break;
09084
09085 case INSN:
09086
09087
09088 scanbody = PATTERN (this_insn);
09089 if (!(GET_CODE (scanbody) == SET
09090 || GET_CODE (scanbody) == PARALLEL)
09091 || get_attr_conds (this_insn) != CONDS_NOCOND)
09092 fail = TRUE;
09093 break;
09094
09095 default:
09096 break;
09097 }
09098 }
09099 if (succeed)
09100 {
09101 if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
09102 arm_target_label = CODE_LABEL_NUMBER (label);
09103 else if (seeking_return || arm_ccfsm_state == 2)
09104 {
09105 while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
09106 {
09107 this_insn = next_nonnote_insn (this_insn);
09108 if (this_insn && (GET_CODE (this_insn) == BARRIER
09109 || GET_CODE (this_insn) == CODE_LABEL))
09110 abort ();
09111 }
09112 if (!this_insn)
09113 {
09114
09115 recog (PATTERN (insn), insn, NULL);
09116 arm_ccfsm_state = 0;
09117 arm_target_insn = NULL;
09118 return;
09119 }
09120 arm_target_insn = this_insn;
09121 }
09122 else
09123 abort ();
09124 if (jump_clobbers)
09125 {
09126 if (reverse)
09127 abort ();
09128 arm_current_cc =
09129 get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
09130 0), 0), 1));
09131 if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
09132 arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
09133 if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
09134 arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
09135 }
09136 else
09137 {
09138
09139
09140 if (!reverse)
09141 arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
09142 0));
09143 }
09144
09145 if (reverse || then_not_else)
09146 arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
09147 }
09148
09149
09150
09151
09152
09153 recog (PATTERN (insn), insn, NULL);
09154 }
09155 }
09156
09157
09158
09159
09160 int
09161 arm_hard_regno_mode_ok (regno, mode)
09162 unsigned int regno;
09163 enum machine_mode mode;
09164 {
09165 if (GET_MODE_CLASS (mode) == MODE_CC)
09166 return regno == CC_REGNUM;
09167
09168 if (TARGET_THUMB)
09169
09170
09171
09172
09173
09174 return (NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
09175
09176 if (regno <= LAST_ARM_REGNUM)
09177
09178 return 1;
09179
09180 if ( regno == FRAME_POINTER_REGNUM
09181 || regno == ARG_POINTER_REGNUM)
09182
09183 return GET_MODE_CLASS (mode) == MODE_INT;
09184
09185
09186
09187 return GET_MODE_CLASS (mode) == MODE_FLOAT
09188 && regno >= FIRST_ARM_FP_REGNUM
09189 && regno <= LAST_ARM_FP_REGNUM;
09190 }
09191
09192 int
09193 arm_regno_class (regno)
09194 int regno;
09195 {
09196 if (TARGET_THUMB)
09197 {
09198 if (regno == STACK_POINTER_REGNUM)
09199 return STACK_REG;
09200 if (regno == CC_REGNUM)
09201 return CC_REG;
09202 if (regno < 8)
09203 return LO_REGS;
09204 return HI_REGS;
09205 }
09206
09207 if ( regno <= LAST_ARM_REGNUM
09208 || regno == FRAME_POINTER_REGNUM
09209 || regno == ARG_POINTER_REGNUM)
09210 return GENERAL_REGS;
09211
09212 if (regno == CC_REGNUM)
09213 return NO_REGS;
09214
09215 return FPU_REGS;
09216 }
09217
09218
09219
09220
09221 int
09222 arm_debugger_arg_offset (value, addr)
09223 int value;
09224 rtx addr;
09225 {
09226 rtx insn;
09227
09228
09229 if (value != 0)
09230 return 0;
09231
09232
09233 if (GET_CODE (addr) != REG)
09234 return 0;
09235
09236
09237
09238 if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
09239 return 0;
09240
09241
09242
09243 if ((TARGET_THUMB || !frame_pointer_needed)
09244 && REGNO (addr) == SP_REGNUM)
09245 return 0;
09246
09247
09248
09249
09250
09251
09252
09253
09254
09255
09256
09257
09258
09259
09260
09261
09262
09263
09264
09265
09266
09267
09268
09269
09270
09271
09272
09273
09274
09275
09276
09277 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
09278 {
09279 if ( GET_CODE (insn) == INSN
09280 && GET_CODE (PATTERN (insn)) == SET
09281 && REGNO (XEXP (PATTERN (insn), 0)) == REGNO (addr)
09282 && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
09283 && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
09284 && REGNO (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
09285 && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
09286 )
09287 {
09288 value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
09289
09290 break;
09291 }
09292 }
09293
09294 if (value == 0)
09295 {
09296 debug_rtx (addr);
09297 warning ("unable to compute real location of stacked parameter");
09298 value = 8;
09299 }
09300
09301 return value;
09302 }
09303
09304 #define def_builtin(NAME, TYPE, CODE) \
09305 builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL)
09306
09307 void
09308 arm_init_builtins ()
09309 {
09310 tree endlink = void_list_node;
09311 tree int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
09312 tree pchar_type_node = build_pointer_type (char_type_node);
09313
09314 tree int_ftype_int, void_ftype_pchar;
09315
09316
09317 void_ftype_pchar
09318 = build_function_type (void_type_node,
09319 tree_cons (NULL_TREE, pchar_type_node, endlink));
09320
09321
09322 int_ftype_int
09323 = build_function_type (integer_type_node, int_endlink);
09324
09325
09326 if (arm_arch5)
09327 def_builtin ("__builtin_clz", int_ftype_int, ARM_BUILTIN_CLZ);
09328 }
09329
09330
09331
09332
09333
09334
09335
09336 rtx
09337 arm_expand_builtin (exp, target, subtarget, mode, ignore)
09338 tree exp;
09339 rtx target;
09340 rtx subtarget ATTRIBUTE_UNUSED;
09341 enum machine_mode mode ATTRIBUTE_UNUSED;
09342 int ignore ATTRIBUTE_UNUSED;
09343 {
09344 enum insn_code icode;
09345 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
09346 tree arglist = TREE_OPERAND (exp, 1);
09347 tree arg0;
09348 rtx op0, pat;
09349 enum machine_mode tmode, mode0;
09350 int fcode = DECL_FUNCTION_CODE (fndecl);
09351
09352 switch (fcode)
09353 {
09354 default:
09355 break;
09356
09357 case ARM_BUILTIN_CLZ:
09358 icode = CODE_FOR_clz;
09359 arg0 = TREE_VALUE (arglist);
09360 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
09361 tmode = insn_data[icode].operand[0].mode;
09362 mode0 = insn_data[icode].operand[1].mode;
09363
09364 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
09365 op0 = copy_to_mode_reg (mode0, op0);
09366 if (target == 0
09367 || GET_MODE (target) != tmode
09368 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
09369 target = gen_reg_rtx (tmode);
09370 pat = GEN_FCN (icode) (target, op0);
09371 if (! pat)
09372 return 0;
09373 emit_insn (pat);
09374 return target;
09375 }
09376
09377
09378 return NULL_RTX;
09379 }
09380
09381
09382
09383
09384
09385
09386 static void
09387 replace_symbols_in_block (block, orig, new)
09388 tree block;
09389 rtx orig;
09390 rtx new;
09391 {
09392 for (; block; block = BLOCK_CHAIN (block))
09393 {
09394 tree sym;
09395
09396 if (!TREE_USED (block))
09397 continue;
09398
09399 for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym))
09400 {
09401 if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL)
09402 || DECL_IGNORED_P (sym)
09403 || TREE_CODE (sym) != VAR_DECL
09404 || DECL_EXTERNAL (sym)
09405 || !rtx_equal_p (DECL_RTL (sym), orig)
09406 )
09407 continue;
09408
09409 SET_DECL_RTL (sym, new);
09410 }
09411
09412 replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new);
09413 }
09414 }
09415
09416
09417
09418
09419 #ifdef __GNUC__
09420 inline
09421 #endif
09422 static int
09423 number_of_first_bit_set (mask)
09424 int mask;
09425 {
09426 int bit;
09427
09428 for (bit = 0;
09429 (mask & (1 << bit)) == 0;
09430 ++bit)
09431 continue;
09432
09433 return bit;
09434 }
09435
09436
09437
09438
09439 static void
09440 thumb_exit (f, reg_containing_return_addr, eh_ofs)
09441 FILE * f;
09442 int reg_containing_return_addr;
09443 rtx eh_ofs;
09444 {
09445 unsigned regs_available_for_popping;
09446 unsigned regs_to_pop;
09447 int pops_needed;
09448 unsigned available;
09449 unsigned required;
09450 int mode;
09451 int size;
09452 int restore_a4 = FALSE;
09453
09454
09455 regs_to_pop = 0;
09456 pops_needed = 0;
09457
09458
09459
09460 if (reg_containing_return_addr == -1 || eh_ofs)
09461 {
09462
09463
09464 if (eh_ofs && reg_containing_return_addr == -1)
09465 abort ();
09466
09467 regs_to_pop |= 1 << LR_REGNUM;
09468 ++pops_needed;
09469 }
09470
09471 if (TARGET_BACKTRACE)
09472 {
09473
09474 regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
09475 pops_needed += 2;
09476 }
09477
09478
09479
09480 if (pops_needed == 0)
09481 {
09482 if (eh_ofs)
09483 asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
09484
09485 asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
09486 return;
09487 }
09488
09489
09490
09491 else if (!TARGET_INTERWORK
09492 && !TARGET_BACKTRACE
09493 && !is_called_in_ARM_mode (current_function_decl))
09494 {
09495 if (eh_ofs)
09496 {
09497 asm_fprintf (f, "\tadd\t%r, #4\n", SP_REGNUM);
09498 asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
09499 asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
09500 }
09501 else
09502 asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
09503
09504 return;
09505 }
09506
09507
09508 regs_available_for_popping = 0;
09509
09510
09511
09512 if (eh_ofs)
09513 size = 12;
09514 else
09515 {
09516 #ifdef RTX_CODE
09517
09518
09519
09520
09521
09522
09523 if (current_function_return_rtx != 0)
09524 mode = GET_MODE (current_function_return_rtx);
09525 else
09526 #endif
09527 mode = DECL_MODE (DECL_RESULT (current_function_decl));
09528
09529 size = GET_MODE_SIZE (mode);
09530
09531 if (size == 0)
09532 {
09533
09534
09535
09536 if (mode == VOIDmode)
09537 regs_available_for_popping =
09538 (1 << ARG_REGISTER (1))
09539 | (1 << ARG_REGISTER (2))
09540 | (1 << ARG_REGISTER (3));
09541 else
09542 regs_available_for_popping =
09543 (1 << ARG_REGISTER (2))
09544 | (1 << ARG_REGISTER (3));
09545 }
09546 else if (size <= 4)
09547 regs_available_for_popping =
09548 (1 << ARG_REGISTER (2))
09549 | (1 << ARG_REGISTER (3));
09550 else if (size <= 8)
09551 regs_available_for_popping =
09552 (1 << ARG_REGISTER (3));
09553 }
09554
09555
09556 for (available = regs_available_for_popping,
09557 required = regs_to_pop;
09558 required != 0 && available != 0;
09559 available &= ~(available & - available),
09560 required &= ~(required & - required))
09561 -- pops_needed;
09562
09563
09564 if (available > 0)
09565 regs_available_for_popping &= ~available;
09566
09567
09568
09569 else if (pops_needed)
09570 {
09571
09572
09573 if (regs_available_for_popping == 0
09574 && reg_containing_return_addr == LAST_ARG_REGNUM)
09575 {
09576 asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
09577 reg_containing_return_addr = LR_REGNUM;
09578 }
09579 else if (size > 12)
09580 {
09581
09582
09583 restore_a4 = TRUE;
09584
09585 asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
09586 }
09587
09588 if (reg_containing_return_addr != LAST_ARG_REGNUM)
09589 {
09590
09591 regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
09592
09593 --pops_needed;
09594 }
09595 }
09596
09597
09598 thumb_pushpop (f, regs_available_for_popping, FALSE);
09599
09600
09601 if (reg_containing_return_addr == -1)
09602 {
09603
09604 regs_to_pop &= ~(1 << LR_REGNUM);
09605
09606 reg_containing_return_addr =
09607 number_of_first_bit_set (regs_available_for_popping);
09608
09609
09610
09611 regs_available_for_popping &= ~(1 << reg_containing_return_addr);
09612 }
09613
09614
09615 if (regs_available_for_popping)
09616 {
09617 int frame_pointer;
09618
09619
09620 frame_pointer = number_of_first_bit_set (regs_available_for_popping);
09621
09622
09623 asm_fprintf (f, "\tmov\t%r, %r\n",
09624 ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
09625
09626
09627 regs_available_for_popping &= ~(1 << frame_pointer);
09628 regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
09629
09630 if (regs_available_for_popping)
09631 {
09632 int stack_pointer;
09633
09634
09635
09636 stack_pointer = number_of_first_bit_set (regs_available_for_popping);
09637
09638
09639 asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
09640
09641
09642
09643
09644
09645
09646
09647
09648 }
09649 else
09650 {
09651
09652
09653
09654 regs_available_for_popping |= (1 << frame_pointer);
09655 }
09656 }
09657
09658
09659
09660
09661
09662 if (regs_available_for_popping == 0 && pops_needed > 0)
09663 {
09664 regs_available_for_popping |= 1 << reg_containing_return_addr;
09665
09666 asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
09667 reg_containing_return_addr);
09668
09669 reg_containing_return_addr = LR_REGNUM;
09670 }
09671
09672
09673
09674 if (pops_needed > 0)
09675 {
09676 int popped_into;
09677 int move_to;
09678
09679 thumb_pushpop (f, regs_available_for_popping, FALSE);
09680
09681
09682
09683 popped_into = number_of_first_bit_set (regs_available_for_popping);
09684 move_to = number_of_first_bit_set (regs_to_pop);
09685
09686 asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
09687
09688 regs_to_pop &= ~(1 << move_to);
09689
09690 --pops_needed;
09691 }
09692
09693
09694
09695 if (pops_needed > 0)
09696 {
09697 int popped_into;
09698
09699 thumb_pushpop (f, regs_available_for_popping, FALSE);
09700
09701 popped_into = number_of_first_bit_set (regs_available_for_popping);
09702
09703 asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
09704
09705
09706
09707
09708 }
09709
09710
09711 if (restore_a4)
09712 {
09713 if (reg_containing_return_addr != LR_REGNUM)
09714 {
09715 asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
09716 reg_containing_return_addr = LR_REGNUM;
09717 }
09718
09719 asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
09720 }
09721
09722 if (eh_ofs)
09723 asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
09724
09725
09726 asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
09727 }
09728
09729
09730
09731 static void
09732 thumb_pushpop (f, mask, push)
09733 FILE * f;
09734 int mask;
09735 int push;
09736 {
09737 int regno;
09738 int lo_mask = mask & 0xFF;
09739
09740 if (lo_mask == 0 && !push && (mask & (1 << 15)))
09741 {
09742
09743
09744 thumb_exit (f, -1, NULL_RTX);
09745 return;
09746 }
09747
09748 fprintf (f, "\t%s\t{", push ? "push" : "pop");
09749
09750
09751 for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
09752 {
09753 if (lo_mask & 1)
09754 {
09755 asm_fprintf (f, "%r", regno);
09756
09757 if ((lo_mask & ~1) != 0)
09758 fprintf (f, ", ");
09759 }
09760 }
09761
09762 if (push && (mask & (1 << LR_REGNUM)))
09763 {
09764
09765 if (mask & 0xFF)
09766 fprintf (f, ", ");
09767
09768 asm_fprintf (f, "%r", LR_REGNUM);
09769 }
09770 else if (!push && (mask & (1 << PC_REGNUM)))
09771 {
09772
09773 if (TARGET_INTERWORK || TARGET_BACKTRACE)
09774 {
09775
09776
09777 fprintf (f, "}\n");
09778
09779 thumb_exit (f, -1, NULL_RTX);
09780
09781 return;
09782 }
09783 else
09784 {
09785 if (mask & 0xFF)
09786 fprintf (f, ", ");
09787
09788 asm_fprintf (f, "%r", PC_REGNUM);
09789 }
09790 }
09791
09792 fprintf (f, "}\n");
09793 }
09794
09795 void
09796 thumb_final_prescan_insn (insn)
09797 rtx insn;
09798 {
09799 if (flag_print_asm_name)
09800 asm_fprintf (asm_out_file, "%@ 0x%04x\n",
09801 INSN_ADDRESSES (INSN_UID (insn)));
09802 }
09803
09804 int
09805 thumb_shiftable_const (val)
09806 unsigned HOST_WIDE_INT val;
09807 {
09808 unsigned HOST_WIDE_INT mask = 0xff;
09809 int i;
09810
09811 if (val == 0)
09812 return 0;
09813
09814 for (i = 0; i < 25; i++)
09815 if ((val & (mask << i)) == val)
09816 return 1;
09817
09818 return 0;
09819 }
09820
09821
09822
09823
09824 int
09825 thumb_far_jump_used_p (int in_prologue)
09826 {
09827 rtx insn;
09828
09829
09830
09831
09832
09833
09834
09835
09836
09837 if (cfun->machine->far_jump_used)
09838 return 1;
09839
09840
09841
09842
09843 if (!in_prologue)
09844 {
09845
09846
09847
09848
09849
09850
09851
09852
09853
09854
09855
09856
09857
09858
09859
09860
09861
09862
09863 if (regs_ever_live [ARG_POINTER_REGNUM])
09864 cfun->machine->arg_pointer_live = 1;
09865 else if (!cfun->machine->arg_pointer_live)
09866 return 0;
09867 }
09868
09869
09870
09871 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
09872 {
09873 if (GET_CODE (insn) == JUMP_INSN
09874
09875 && GET_CODE (PATTERN (insn)) != ADDR_VEC
09876 && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
09877 && get_attr_far_jump (insn) == FAR_JUMP_YES
09878 )
09879 {
09880
09881
09882 cfun->machine->far_jump_used = 1;
09883 return 1;
09884 }
09885 }
09886
09887 return 0;
09888 }
09889
09890
09891
09892 int
09893 is_called_in_ARM_mode (func)
09894 tree func;
09895 {
09896 if (TREE_CODE (func) != FUNCTION_DECL)
09897 abort ();
09898
09899
09900 if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
09901 return TRUE;
09902
09903 #ifdef ARM_PE
09904 return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
09905 #else
09906 return FALSE;
09907 #endif
09908 }
09909
09910
09911
09912 const char *
09913 thumb_unexpanded_epilogue ()
09914 {
09915 int regno;
09916 int live_regs_mask = 0;
09917 int high_regs_pushed = 0;
09918 int leaf_function = leaf_function_p ();
09919 int had_to_push_lr;
09920 rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
09921
09922 if (return_used_this_function)
09923 return "";
09924
09925 for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
09926 if (regs_ever_live[regno] && !call_used_regs[regno]
09927 && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
09928 live_regs_mask |= 1 << regno;
09929
09930 for (regno = 8; regno < 13; regno++)
09931 {
09932 if (regs_ever_live[regno] && !call_used_regs[regno]
09933 && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
09934 high_regs_pushed++;
09935 }
09936
09937
09938
09939
09940
09941
09942
09943
09944
09945
09946
09947 if (high_regs_pushed)
09948 {
09949 int mask = live_regs_mask;
09950 int next_hi_reg;
09951 int size;
09952 int mode;
09953
09954 #ifdef RTX_CODE
09955
09956
09957
09958
09959
09960 if (current_function_return_rtx != 0)
09961 mode = GET_MODE (current_function_return_rtx);
09962 else
09963 #endif
09964 mode = DECL_MODE (DECL_RESULT (current_function_decl));
09965
09966 size = GET_MODE_SIZE (mode);
09967
09968
09969
09970 if (size < 13)
09971 mask |= 1 << 3;
09972
09973 if (mask == 0)
09974
09975
09976 internal_error
09977 ("no low registers available for popping high registers");
09978
09979 for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
09980 if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg]
09981 && !(TARGET_SINGLE_PIC_BASE && (next_hi_reg == arm_pic_register)))
09982 break;
09983
09984 while (high_regs_pushed)
09985 {
09986
09987
09988 for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
09989 {
09990 if (mask & (1 << regno))
09991 high_regs_pushed--;
09992 if (high_regs_pushed == 0)
09993 break;
09994 }
09995
09996 mask &= (2 << regno) - 1;
09997
09998
09999 thumb_pushpop (asm_out_file, mask, 0);
10000
10001
10002 for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
10003 {
10004 if (mask & (1 << regno))
10005 {
10006 asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
10007 regno);
10008
10009 for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
10010 if (regs_ever_live[next_hi_reg]
10011 && !call_used_regs[next_hi_reg]
10012 && !(TARGET_SINGLE_PIC_BASE
10013 && (next_hi_reg == arm_pic_register)))
10014 break;
10015 }
10016 }
10017 }
10018 }
10019
10020 had_to_push_lr = (live_regs_mask || !leaf_function
10021 || thumb_far_jump_used_p (1));
10022
10023 if (TARGET_BACKTRACE
10024 && ((live_regs_mask & 0xFF) == 0)
10025 && regs_ever_live [LAST_ARG_REGNUM] != 0)
10026 {
10027
10028
10029
10030 live_regs_mask |= (1 << LAST_LO_REGNUM);
10031 }
10032
10033 if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
10034 {
10035 if (had_to_push_lr
10036 && !is_called_in_ARM_mode (current_function_decl)
10037 && !eh_ofs)
10038 live_regs_mask |= 1 << PC_REGNUM;
10039
10040
10041
10042
10043 if (live_regs_mask)
10044 thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
10045
10046 if (eh_ofs)
10047 thumb_exit (asm_out_file, 2, eh_ofs);
10048
10049
10050
10051
10052 else if ((live_regs_mask & (1 << PC_REGNUM)) == 0)
10053 thumb_exit (asm_out_file,
10054 (had_to_push_lr
10055 && is_called_in_ARM_mode (current_function_decl)) ?
10056 -1 : LR_REGNUM, NULL_RTX);
10057 }
10058 else
10059 {
10060
10061 live_regs_mask &= ~(1 << PC_REGNUM);
10062
10063 if (live_regs_mask)
10064 thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
10065
10066 if (had_to_push_lr)
10067
10068 thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0);
10069
10070
10071 asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
10072 SP_REGNUM, SP_REGNUM,
10073 current_function_pretend_args_size);
10074
10075 if (eh_ofs)
10076 thumb_exit (asm_out_file, 2, eh_ofs);
10077 else
10078 thumb_exit (asm_out_file,
10079 had_to_push_lr ? LAST_ARG_REGNUM : LR_REGNUM, NULL_RTX);
10080 }
10081
10082 return "";
10083 }
10084
10085
10086
10087 static void
10088 arm_mark_machine_status (p)
10089 struct function * p;
10090 {
10091 machine_function *machine = p->machine;
10092
10093 if (machine)
10094 ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
10095 }
10096
10097 static void
10098 arm_init_machine_status (p)
10099 struct function * p;
10100 {
10101 p->machine =
10102 (machine_function *) xcalloc (1, sizeof (machine_function));
10103
10104 #if ARM_FT_UNKNOWWN != 0
10105 ((machine_function *) p->machine)->func_type = ARM_FT_UNKNOWN;
10106 #endif
10107 }
10108
10109 static void
10110 arm_free_machine_status (p)
10111 struct function * p;
10112 {
10113 if (p->machine)
10114 {
10115 free (p->machine);
10116 p->machine = NULL;
10117 }
10118 }
10119
10120
10121
10122
10123 rtx
10124 arm_return_addr (count, frame)
10125 int count;
10126 rtx frame ATTRIBUTE_UNUSED;
10127 {
10128 if (count != 0)
10129 return NULL_RTX;
10130
10131 if (TARGET_APCS_32)
10132 return get_hard_reg_initial_val (Pmode, LR_REGNUM);
10133 else
10134 {
10135 rtx lr = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM),
10136 GEN_INT (RETURN_ADDR_MASK26));
10137 return get_func_hard_reg_initial_val (cfun, lr);
10138 }
10139 }
10140
10141
10142
10143 void
10144 arm_init_expanders ()
10145 {
10146
10147 init_machine_status = arm_init_machine_status;
10148 mark_machine_status = arm_mark_machine_status;
10149 free_machine_status = arm_free_machine_status;
10150 }
10151
10152
10153
10154 void
10155 thumb_expand_prologue ()
10156 {
10157 HOST_WIDE_INT amount = (get_frame_size ()
10158 + current_function_outgoing_args_size);
10159 unsigned long func_type;
10160
10161 func_type = arm_current_func_type ();
10162
10163
10164 if (IS_NAKED (func_type))
10165 return;
10166
10167 if (IS_INTERRUPT (func_type))
10168 {
10169 error ("interrupt Service Routines cannot be coded in Thumb mode");
10170 return;
10171 }
10172
10173 if (frame_pointer_needed)
10174 emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
10175
10176 if (amount)
10177 {
10178 amount = ROUND_UP (amount);
10179
10180 if (amount < 512)
10181 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10182 GEN_INT (- amount)));
10183 else
10184 {
10185 int regno;
10186 rtx reg;
10187
10188
10189
10190
10191
10192
10193
10194
10195
10196
10197
10198
10199
10200
10201
10202 for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
10203 if (regs_ever_live[regno]
10204 && !call_used_regs[regno]
10205 && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))
10206 && !(frame_pointer_needed
10207 && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
10208 break;
10209
10210 if (regno > LAST_LO_REGNUM)
10211 {
10212 rtx spare = gen_rtx (REG, SImode, IP_REGNUM);
10213
10214
10215 reg = gen_rtx (REG, SImode, LAST_LO_REGNUM);
10216
10217
10218 emit_insn (gen_movsi (spare, reg));
10219
10220 emit_insn (gen_prologue_use (spare));
10221
10222
10223 emit_insn (gen_movsi (reg, GEN_INT (- amount)));
10224 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10225 reg));
10226
10227
10228 emit_insn (gen_movsi (reg, spare));
10229
10230
10231
10232
10233
10234 emit_insn (gen_prologue_use (reg));
10235 }
10236 else
10237 {
10238 reg = gen_rtx (REG, SImode, regno);
10239
10240 emit_insn (gen_movsi (reg, GEN_INT (- amount)));
10241 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10242 reg));
10243 }
10244 }
10245 }
10246
10247 if (current_function_profile || TARGET_NO_SCHED_PRO)
10248 emit_insn (gen_blockage ());
10249 }
10250
10251 void
10252 thumb_expand_epilogue ()
10253 {
10254 HOST_WIDE_INT amount = (get_frame_size ()
10255 + current_function_outgoing_args_size);
10256
10257
10258 if (IS_NAKED (arm_current_func_type ()))
10259 return;
10260
10261 if (frame_pointer_needed)
10262 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
10263 else if (amount)
10264 {
10265 amount = ROUND_UP (amount);
10266
10267 if (amount < 512)
10268 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10269 GEN_INT (amount)));
10270 else
10271 {
10272
10273 rtx reg = gen_rtx (REG, SImode, LAST_ARG_REGNUM);
10274
10275 emit_insn (gen_movsi (reg, GEN_INT (amount)));
10276 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
10277 }
10278 }
10279
10280
10281
10282 emit_insn (gen_prologue_use (stack_pointer_rtx));
10283
10284 if (current_function_profile || TARGET_NO_SCHED_PRO)
10285 emit_insn (gen_blockage ());
10286 }
10287
10288 static void
10289 thumb_output_function_prologue (f, size)
10290 FILE * f;
10291 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
10292 {
10293 int live_regs_mask = 0;
10294 int high_regs_pushed = 0;
10295 int regno;
10296
10297 if (IS_NAKED (arm_current_func_type ()))
10298 return;
10299
10300 if (is_called_in_ARM_mode (current_function_decl))
10301 {
10302 const char * name;
10303
10304 if (GET_CODE (DECL_RTL (current_function_decl)) != MEM)
10305 abort ();
10306 if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF)
10307 abort ();
10308 name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
10309
10310
10311
10312
10313 asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
10314 asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
10315
10316
10317
10318
10319
10320
10321
10322
10323 #define STUB_NAME ".real_start_of"
10324
10325 asm_fprintf (f, "\t.code\t16\n");
10326 #ifdef ARM_PE
10327 if (arm_dllexport_name_p (name))
10328 name = arm_strip_name_encoding (name);
10329 #endif
10330 asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
10331 asm_fprintf (f, "\t.thumb_func\n");
10332 asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
10333 }
10334
10335 if (current_function_pretend_args_size)
10336 {
10337 if (cfun->machine->uses_anonymous_args)
10338 {
10339 int num_pushes;
10340
10341 asm_fprintf (f, "\tpush\t{");
10342
10343 num_pushes = NUM_INTS (current_function_pretend_args_size);
10344
10345 for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
10346 regno <= LAST_ARG_REGNUM;
10347 regno++)
10348 asm_fprintf (f, "%r%s", regno,
10349 regno == LAST_ARG_REGNUM ? "" : ", ");
10350
10351 asm_fprintf (f, "}\n");
10352 }
10353 else
10354 asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
10355 SP_REGNUM, SP_REGNUM,
10356 current_function_pretend_args_size);
10357 }
10358
10359 for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
10360 if (regs_ever_live[regno] && !call_used_regs[regno]
10361 && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
10362 live_regs_mask |= 1 << regno;
10363
10364 if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
10365 live_regs_mask |= 1 << LR_REGNUM;
10366
10367 if (TARGET_BACKTRACE)
10368 {
10369 int offset;
10370 int work_register = 0;
10371 int wr;
10372
10373
10374
10375
10376
10377
10378
10379
10380
10381
10382
10383
10384
10385
10386
10387
10388
10389
10390
10391 if ((live_regs_mask & 0xFF) == 0)
10392 {
10393
10394
10395 if (regs_ever_live [LAST_ARG_REGNUM] == 0)
10396 work_register = LAST_ARG_REGNUM;
10397 else
10398 live_regs_mask |= (1 << LAST_LO_REGNUM);
10399 }
10400
10401 if (work_register == 0)
10402 {
10403
10404
10405 for (work_register = (LAST_LO_REGNUM + 1); work_register--;)
10406 if ((1 << work_register) & live_regs_mask)
10407 break;
10408 }
10409
10410 asm_fprintf
10411 (f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
10412 SP_REGNUM, SP_REGNUM);
10413
10414 if (live_regs_mask)
10415 thumb_pushpop (f, live_regs_mask, 1);
10416
10417 for (offset = 0, wr = 1 << 15; wr != 0; wr >>= 1)
10418 if (wr & live_regs_mask)
10419 offset += 4;
10420
10421 asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
10422 offset + 16 + current_function_pretend_args_size);
10423
10424 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
10425 offset + 4);
10426
10427
10428
10429 if (live_regs_mask)
10430 {
10431 asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
10432 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
10433 offset + 12);
10434 asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
10435 ARM_HARD_FRAME_POINTER_REGNUM);
10436 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
10437 offset);
10438 }
10439 else
10440 {
10441 asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
10442 ARM_HARD_FRAME_POINTER_REGNUM);
10443 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
10444 offset);
10445 asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
10446 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
10447 offset + 12);
10448 }
10449
10450 asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
10451 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
10452 offset + 8);
10453 asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
10454 offset + 12);
10455 asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
10456 ARM_HARD_FRAME_POINTER_REGNUM, work_register);
10457 }
10458 else if (live_regs_mask)
10459 thumb_pushpop (f, live_regs_mask, 1);
10460
10461 for (regno = 8; regno < 13; regno++)
10462 {
10463 if (regs_ever_live[regno] && !call_used_regs[regno]
10464 && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
10465 high_regs_pushed++;
10466 }
10467
10468 if (high_regs_pushed)
10469 {
10470 int pushable_regs = 0;
10471 int mask = live_regs_mask & 0xff;
10472 int next_hi_reg;
10473
10474 for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
10475 {
10476 if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg]
10477 && !(TARGET_SINGLE_PIC_BASE
10478 && (next_hi_reg == arm_pic_register)))
10479 break;
10480 }
10481
10482 pushable_regs = mask;
10483
10484 if (pushable_regs == 0)
10485 {
10486
10487 if (regs_ever_live[LAST_ARG_REGNUM]
10488 || !call_used_regs[LAST_ARG_REGNUM])
10489 asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM);
10490 mask = 1 << LAST_ARG_REGNUM;
10491 }
10492
10493 while (high_regs_pushed > 0)
10494 {
10495 for (regno = LAST_LO_REGNUM; regno >= 0; regno--)
10496 {
10497 if (mask & (1 << regno))
10498 {
10499 asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
10500
10501 high_regs_pushed--;
10502
10503 if (high_regs_pushed)
10504 for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
10505 next_hi_reg--)
10506 {
10507 if (regs_ever_live[next_hi_reg]
10508 && !call_used_regs[next_hi_reg]
10509 && !(TARGET_SINGLE_PIC_BASE
10510 && (next_hi_reg == arm_pic_register)))
10511 break;
10512 }
10513 else
10514 {
10515 mask &= ~((1 << regno) - 1);
10516 break;
10517 }
10518 }
10519 }
10520
10521 thumb_pushpop (f, mask, 1);
10522 }
10523
10524 if (pushable_regs == 0
10525 && (regs_ever_live[LAST_ARG_REGNUM]
10526 || !call_used_regs[LAST_ARG_REGNUM]))
10527 asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
10528 }
10529 }
10530
10531
10532
10533
10534
10535 const char *
10536 thumb_load_double_from_address (operands)
10537 rtx *operands;
10538 {
10539 rtx addr;
10540 rtx base;
10541 rtx offset;
10542 rtx arg1;
10543 rtx arg2;
10544
10545 if (GET_CODE (operands[0]) != REG)
10546 abort ();
10547
10548 if (GET_CODE (operands[1]) != MEM)
10549 abort ();
10550
10551
10552 addr = XEXP (operands[1], 0);
10553
10554
10555 switch (GET_CODE (addr))
10556 {
10557 case REG:
10558 operands[2] = gen_rtx (MEM, SImode,
10559 plus_constant (XEXP (operands[1], 0), 4));
10560
10561 if (REGNO (operands[0]) == REGNO (addr))
10562 {
10563 output_asm_insn ("ldr\t%H0, %2", operands);
10564 output_asm_insn ("ldr\t%0, %1", operands);
10565 }
10566 else
10567 {
10568 output_asm_insn ("ldr\t%0, %1", operands);
10569 output_asm_insn ("ldr\t%H0, %2", operands);
10570 }
10571 break;
10572
10573 case CONST:
10574
10575 operands[2] = gen_rtx (MEM, SImode,
10576 plus_constant (XEXP (operands[1], 0), 4));
10577
10578 output_asm_insn ("ldr\t%0, %1", operands);
10579 output_asm_insn ("ldr\t%H0, %2", operands);
10580 break;
10581
10582 case PLUS:
10583 arg1 = XEXP (addr, 0);
10584 arg2 = XEXP (addr, 1);
10585
10586 if (CONSTANT_P (arg1))
10587 base = arg2, offset = arg1;
10588 else
10589 base = arg1, offset = arg2;
10590
10591 if (GET_CODE (base) != REG)
10592 abort ();
10593
10594
10595 if (GET_CODE (offset) == REG)
10596 {
10597 int reg_offset = REGNO (offset);
10598 int reg_base = REGNO (base);
10599 int reg_dest = REGNO (operands[0]);
10600
10601
10602
10603 asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
10604 reg_dest + 1, reg_base, reg_offset);
10605
10606
10607
10608 asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
10609 reg_dest, reg_dest + 1);
10610
10611
10612
10613 asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
10614 reg_dest + 1, reg_dest + 1);
10615 }
10616 else
10617 {
10618
10619 operands[2] = gen_rtx (MEM, SImode,
10620 plus_constant (XEXP (operands[1], 0), 4));
10621
10622
10623
10624
10625 if (REGNO (operands[0]) == REGNO (base))
10626 {
10627 output_asm_insn ("ldr\t%H0, %2", operands);
10628 output_asm_insn ("ldr\t%0, %1", operands);
10629 }
10630 else
10631 {
10632 output_asm_insn ("ldr\t%0, %1", operands);
10633 output_asm_insn ("ldr\t%H0, %2", operands);
10634 }
10635 }
10636 break;
10637
10638 case LABEL_REF:
10639
10640
10641 operands[2] = gen_rtx (MEM, SImode,
10642 plus_constant (XEXP (operands[1], 0), 4));
10643
10644 output_asm_insn ("ldr\t%H0, %2", operands);
10645 output_asm_insn ("ldr\t%0, %1", operands);
10646 break;
10647
10648 default:
10649 abort ();
10650 break;
10651 }
10652
10653 return "";
10654 }
10655
10656
10657 const char *
10658 thumb_output_move_mem_multiple (n, operands)
10659 int n;
10660 rtx * operands;
10661 {
10662 rtx tmp;
10663
10664 switch (n)
10665 {
10666 case 2:
10667 if (REGNO (operands[4]) > REGNO (operands[5]))
10668 {
10669 tmp = operands[4];
10670 operands[4] = operands[5];
10671 operands[5] = tmp;
10672 }
10673 output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
10674 output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
10675 break;
10676
10677 case 3:
10678 if (REGNO (operands[4]) > REGNO (operands[5]))
10679 {
10680 tmp = operands[4];
10681 operands[4] = operands[5];
10682 operands[5] = tmp;
10683 }
10684 if (REGNO (operands[5]) > REGNO (operands[6]))
10685 {
10686 tmp = operands[5];
10687 operands[5] = operands[6];
10688 operands[6] = tmp;
10689 }
10690 if (REGNO (operands[4]) > REGNO (operands[5]))
10691 {
10692 tmp = operands[4];
10693 operands[4] = operands[5];
10694 operands[5] = tmp;
10695 }
10696
10697 output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
10698 output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
10699 break;
10700
10701 default:
10702 abort ();
10703 }
10704
10705 return "";
10706 }
10707
10708
10709
10710 void
10711 thumb_expand_movstrqi (operands)
10712 rtx * operands;
10713 {
10714 rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
10715 rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
10716 HOST_WIDE_INT len = INTVAL (operands[2]);
10717 HOST_WIDE_INT offset = 0;
10718
10719 while (len >= 12)
10720 {
10721 emit_insn (gen_movmem12b (out, in, out, in));
10722 len -= 12;
10723 }
10724
10725 if (len >= 8)
10726 {
10727 emit_insn (gen_movmem8b (out, in, out, in));
10728 len -= 8;
10729 }
10730
10731 if (len >= 4)
10732 {
10733 rtx reg = gen_reg_rtx (SImode);
10734 emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in)));
10735 emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg));
10736 len -= 4;
10737 offset += 4;
10738 }
10739
10740 if (len >= 2)
10741 {
10742 rtx reg = gen_reg_rtx (HImode);
10743 emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode,
10744 plus_constant (in, offset))));
10745 emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)),
10746 reg));
10747 len -= 2;
10748 offset += 2;
10749 }
10750
10751 if (len)
10752 {
10753 rtx reg = gen_reg_rtx (QImode);
10754 emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode,
10755 plus_constant (in, offset))));
10756 emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)),
10757 reg));
10758 }
10759 }
10760
10761 int
10762 thumb_cmp_operand (op, mode)
10763 rtx op;
10764 enum machine_mode mode;
10765 {
10766 return ((GET_CODE (op) == CONST_INT
10767 && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256)
10768 || register_operand (op, mode));
10769 }
10770
10771 static const char *
10772 thumb_condition_code (x, invert)
10773 rtx x;
10774 int invert;
10775 {
10776 static const char * const conds[] =
10777 {
10778 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
10779 "hi", "ls", "ge", "lt", "gt", "le"
10780 };
10781 int val;
10782
10783 switch (GET_CODE (x))
10784 {
10785 case EQ: val = 0; break;
10786 case NE: val = 1; break;
10787 case GEU: val = 2; break;
10788 case LTU: val = 3; break;
10789 case GTU: val = 8; break;
10790 case LEU: val = 9; break;
10791 case GE: val = 10; break;
10792 case LT: val = 11; break;
10793 case GT: val = 12; break;
10794 case LE: val = 13; break;
10795 default:
10796 abort ();
10797 }
10798
10799 return conds[val ^ invert];
10800 }
10801
10802
10803
10804 void
10805 thumb_reload_out_hi (operands)
10806 rtx * operands;
10807 {
10808 emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
10809 }
10810
10811
10812
10813 void
10814 thumb_reload_in_hi (operands)
10815 rtx * operands ATTRIBUTE_UNUSED;
10816 {
10817 abort ();
10818 }
10819
10820
10821
10822
10823 static int
10824 arm_get_strip_length (char c)
10825 {
10826 switch (c)
10827 {
10828 ARM_NAME_ENCODING_LENGTHS
10829 default: return 0;
10830 }
10831 }
10832
10833
10834
10835
10836 const char *
10837 arm_strip_name_encoding (const char * name)
10838 {
10839 int skip;
10840
10841 while ((skip = arm_get_strip_length (* name)))
10842 name += skip;
10843
10844 return name;
10845 }
10846
10847 #ifdef AOF_ASSEMBLER
10848
10849
10850 rtx aof_pic_label = NULL_RTX;
10851 struct pic_chain
10852 {
10853 struct pic_chain * next;
10854 const char * symname;
10855 };
10856
10857 static struct pic_chain * aof_pic_chain = NULL;
10858
10859 rtx
10860 aof_pic_entry (x)
10861 rtx x;
10862 {
10863 struct pic_chain ** chainp;
10864 int offset;
10865
10866 if (aof_pic_label == NULL_RTX)
10867 {
10868
10869
10870
10871 ggc_add_rtx_root (&aof_pic_label, 1);
10872 aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
10873 }
10874
10875 for (offset = 0, chainp = &aof_pic_chain; *chainp;
10876 offset += 4, chainp = &(*chainp)->next)
10877 if ((*chainp)->symname == XSTR (x, 0))
10878 return plus_constant (aof_pic_label, offset);
10879
10880 *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
10881 (*chainp)->next = NULL;
10882 (*chainp)->symname = XSTR (x, 0);
10883 return plus_constant (aof_pic_label, offset);
10884 }
10885
10886 void
10887 aof_dump_pic_table (f)
10888 FILE * f;
10889 {
10890 struct pic_chain * chain;
10891
10892 if (aof_pic_chain == NULL)
10893 return;
10894
10895 asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
10896 PIC_OFFSET_TABLE_REGNUM,
10897 PIC_OFFSET_TABLE_REGNUM);
10898 fputs ("|x$adcons|\n", f);
10899
10900 for (chain = aof_pic_chain; chain; chain = chain->next)
10901 {
10902 fputs ("\tDCD\t", f);
10903 assemble_name (f, chain->symname);
10904 fputs ("\n", f);
10905 }
10906 }
10907
10908 int arm_text_section_count = 1;
10909
10910 char *
10911 aof_text_section ()
10912 {
10913 static char buf[100];
10914 sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY",
10915 arm_text_section_count++);
10916 if (flag_pic)
10917 strcat (buf, ", PIC, REENTRANT");
10918 return buf;
10919 }
10920
10921 static int arm_data_section_count = 1;
10922
10923 char *
10924 aof_data_section ()
10925 {
10926 static char buf[100];
10927 sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++);
10928 return buf;
10929 }
10930
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941 struct import
10942 {
10943 struct import * next;
10944 const char * name;
10945 };
10946
10947 static struct import * imports_list = NULL;
10948
10949 void
10950 aof_add_import (name)
10951 const char * name;
10952 {
10953 struct import * new;
10954
10955 for (new = imports_list; new; new = new->next)
10956 if (new->name == name)
10957 return;
10958
10959 new = (struct import *) xmalloc (sizeof (struct import));
10960 new->next = imports_list;
10961 imports_list = new;
10962 new->name = name;
10963 }
10964
10965 void
10966 aof_delete_import (name)
10967 const char * name;
10968 {
10969 struct import ** old;
10970
10971 for (old = &imports_list; *old; old = & (*old)->next)
10972 {
10973 if ((*old)->name == name)
10974 {
10975 *old = (*old)->next;
10976 return;
10977 }
10978 }
10979 }
10980
10981 int arm_main_function = 0;
10982
10983 void
10984 aof_dump_imports (f)
10985 FILE * f;
10986 {
10987
10988
10989
10990 if (arm_main_function)
10991 {
10992 text_section ();
10993 fputs ("\tIMPORT __main\n", f);
10994 fputs ("\tDCD __main\n", f);
10995 }
10996
10997
10998 while (imports_list)
10999 {
11000 fprintf (f, "\tIMPORT\t");
11001 assemble_name (f, imports_list->name);
11002 fputc ('\n', f);
11003 imports_list = imports_list->next;
11004 }
11005 }
11006 #endif
11007
11008 #ifdef OBJECT_FORMAT_ELF
11009
11010
11011
11012
11013
11014
11015
11016 static void
11017 arm_elf_asm_named_section (name, flags)
11018 const char *name;
11019 unsigned int flags;
11020 {
11021 char flagchars[8], *f = flagchars;
11022 const char *type;
11023
11024 if (!(flags & SECTION_DEBUG))
11025 *f++ = 'a';
11026 if (flags & SECTION_WRITE)
11027 *f++ = 'w';
11028 if (flags & SECTION_CODE)
11029 *f++ = 'x';
11030 if (flags & SECTION_SMALL)
11031 *f++ = 's';
11032 if (flags & SECTION_MERGE)
11033 *f++ = 'M';
11034 if (flags & SECTION_STRINGS)
11035 *f++ = 'S';
11036 *f = '\0';
11037
11038 if (flags & SECTION_BSS)
11039 type = "nobits";
11040 else
11041 type = "progbits";
11042
11043 if (flags & SECTION_ENTSIZE)
11044 fprintf (asm_out_file, "\t.section\t%s,\"%s\",%%%s,%d\n",
11045 name, flagchars, type, flags & SECTION_ENTSIZE);
11046 else
11047 fprintf (asm_out_file, "\t.section\t%s,\"%s\",%%%s\n",
11048 name, flagchars, type);
11049 }
11050 #endif