diff options
author | Richard Henderson <rth@gcc.gnu.org> | 2001-09-11 01:52:39 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2001-09-11 01:52:39 -0700 |
commit | 30102605e710a95f8cb00ddd14303d7fcc284fae (patch) | |
tree | 89de0166f267747621eba79ef570f0cb00c9654a | |
parent | b1c4394d5db5b1c73458e8927dbcedc101874e04 (diff) | |
download | gcc-30102605e710a95f8cb00ddd14303d7fcc284fae.zip gcc-30102605e710a95f8cb00ddd14303d7fcc284fae.tar.gz gcc-30102605e710a95f8cb00ddd14303d7fcc284fae.tar.bz2 |
Cray T3E port.
From-SVN: r45539
-rw-r--r-- | gcc/ChangeLog | 90 | ||||
-rw-r--r-- | gcc/config.gcc | 8 | ||||
-rw-r--r-- | gcc/config/alpha/alpha-protos.h | 21 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.c | 1727 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.h | 17 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.md | 961 | ||||
-rw-r--r-- | gcc/config/alpha/t-unicosmk | 2 | ||||
-rw-r--r-- | gcc/config/alpha/unicosmk.h | 667 | ||||
-rw-r--r-- | gcc/fixinc/fixincl.x | 51 | ||||
-rw-r--r-- | gcc/fixinc/inclhack.def | 17 | ||||
-rw-r--r-- | gcc/ginclude/stddef.h | 6 |
11 files changed, 3228 insertions, 339 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f5f5afb..7b9891e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,93 @@ +2001-09-11 Richard Henderson <rth@redhat.com> + + * config/alpha/alpha.c: Tidy formatting. + (local_symbolic_operand): Verify mode. + (alpha_sa_mask): Ignore unicos for eh_return. + (alpha_expand_epilogue): Handle sp_adj2 zero, not NULL. + * config/alpha/alpha.md (umk divsi patterns): Remove. + (extendsfdf2): Remove unicos check. + (tablejump): Merge vms and unicos code; always use direct set + plus label_ref use. + +2001-09-11 Roman Lechtchinsky <rl@cs.tu-berlin.de> + + * config.gcc (alpha*-*-unicosmk*): New target. + + * config/alpha/alpha-protos.h (symbolic_operand, + unicosmk_add_call_info_word, unicosmk_add_extern, + unicosmk_defer_case_vector, unicosmk_unique_section, + unicosmk_output_align, unicosmk_text_section, unicosmk_data_section, + unicosmk_asm_file_start, unicosmk_asm_file_end, + unicosmk_output_common): Declare. + + * config/alpha/alpha.c (NUM_ARGS, override_options, call_operand, + direct_return, function_arg, alpha_va_start, alpha_va_arg, + alpha_does_function_need_gp, alpha_end_function): Support Cray + Unicos/Mk. + (alpha_init_machine_status, alpha_mark_machine_status, + alpha_free_machine_status, unicosmk_output_deferred_case_vectors, + unicosmk_gen_dsib, unicosmk_output_ssib, unicosmk_need_dex, + unicosmk_asm_named_section, unicosmk_insert_attributes, + unicosmk_section_type_flags, symbolic_operand, + unicosmk_output_module_name, unicosmk_output_default_externs, + unicosmk_output_dex, unicosmk_output_externs, + unicosmk_output_addr_vec, unicosmk_ssib_name, + unicosmk_initial_elimination_offset, unicosmk_asm_file_start, + unicosmk_asm_file_end, unicosmk_output_common, + unicosmk_section_type_flags, unicosmk_unique_section, + unicosmk_add_call_info_word, unicosmk_text_section, + unicosmk_data_section, unicosmk_extern_list, unicosmk_extern_head, + unicosmk_add_extern, unicosmk_dex, unicosmk_dex_list, + unicosmk_dex_count, unicosmk_special_name): New. + (TARGET_INSERT_ATTRIBUTES, TARGET_SECTION_TYPE_FLAGS): Define for + TARGET_ABI_UNICOSMK. + (get_aligned_mem, alpha_expand_unaligned_load, + alpha_expand_unaligned_store, alpha_expand_unaligned_load_words, + alpha_expand_unaligned_store_words): Support big-endian mode. + (print_operand): Likewise. New format specifier 't'. Use + TARGET_AS_SLASH_BEFORE_SUFFIX. + (alpha_is_stack_procedure): Rename from vms_is_stack_procedure. + (alpha_pv_save_size): Update with above change. + (alpha_sa_mask, alpha_sa_size, alpha_expand_prologue, + alpha_start_function, alpha_expand_epilogue): Likewise. Support Cray + Unicos/Mk. + + * config/alpha/alpha.h (TARGET_ABI_UNICOSMK): New. + (TARGET_ABI_OSF): Exclude TARGET_ABI_UNICOSMK. + (TARGET_AS_SLASH_BEFORE_SUFFIX): New. + (EXTRA_CONSTRAINT): New constraint 'U'. + (PREDICATE_CODES): Add symbolic_operand. + + * config/alpha/alpha.md (UNSPEC_UMK_LAUM, UNSPEC_UMK_LALM, + UNSPEC_UMK_LAL, UNSPEC_UMK_LOAD_CIW): New constants. + (mulsi3, *mulsi_se, mulvsi3): Disable for TARGET_ABI_UNICOSMK. + (integer division and modulus patterns): Split in default and + Unicos/Mk versions. + (*divmodsi_internal, *divmoddi_internal): Disable for + TARGET_ABI_UNICOSMK. + (unaligned_extend?idi, unaligned_load?i, unaligned_store?i): Split in + little-endian and big-endian versions. + (ext, ins, msk): Likewise. + (extv, extzv, insv): Support big-endian mode. + (call, call_value, tablejump): Support TARGET_ABI_UNICOSMK. + (call_umk, call_value_umk, *call_umk, tablejump_umk, + *tablejump_umk_internal, *call_value_umk): New. + (*movdi_nofix): Add pattern for loading an address into a register on + TARGET_ABI_UNICOSMK. + (umk_laum, umk_lal, umk_lalm, *umk_load_ciw): New. + (umk_mismatch_args, arg_home_umk): New. + (various insns): Don't use mov, fmov, nop, fnop and unop. + (realign): Support TARGET_ABI_UNICOSMK. + + * config/alpha/unicosmk.h: New file. + * config/alpha/t-unicosmk: New file. + + * fixinc/inclhack.def (unicosmk_restrict): New. + * fixinc/fixincl.x: Regenerate. + + * ginclude/stddef.h (size_t): Check for and define __SIZE_T__. + (wchar_t): Check for and define __WCHAR_T__. + 2001-09-11 Richard Sandiford <rsandifo@redhat.com> * combine.c (simplify_shift_const): Treat shifts by the mode diff --git a/gcc/config.gcc b/gcc/config.gcc index 2af51fa..00ed9b3 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -398,6 +398,14 @@ a29k-wrs-vxworks*) a29k-*-*) # Default a29k environment. use_collect2=yes ;; +alpha*-*-unicosmk*) + use_collect2=yes + tm_file="${tm_file} alpha/unicosmk.h" + + # Don't include t-ieee for now because we don't support that yet + # tmake_file="alpha/t-ieee" + tmake_file="alpha/t-unicosmk" + ;; alpha-*-interix) tm_file="${tm_file} alpha/alpha32.h interix.h alpha/alpha-interix.h" diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index be18c63..c8ff112 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -56,6 +56,7 @@ extern int input_operand PARAMS ((rtx, enum machine_mode)); extern int current_file_function_operand PARAMS ((rtx, enum machine_mode)); extern int local_symbolic_operand PARAMS ((rtx, enum machine_mode)); extern int call_operand PARAMS ((rtx, enum machine_mode)); +extern int symbolic_operand PARAMS ((rtx, enum machine_mode)); extern int alpha_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int alpha_zero_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int alpha_swapped_comparison_operator PARAMS ((rtx, enum machine_mode)); @@ -149,3 +150,23 @@ extern void alpha_start_function PARAMS ((FILE *, const char *, tree)); extern void alpha_end_function PARAMS ((FILE *, const char *, tree)); extern void alpha_encode_section_info PARAMS ((tree)); #endif /* TREE CODE */ + +#ifdef RTX_CODE +extern rtx unicosmk_add_call_info_word PARAMS ((rtx)); +#endif + +#if TARGET_ABI_UNICOSMK +#ifdef RTX_CODE +extern void unicosmk_defer_case_vector PARAMS ((rtx, rtx)); +#endif +#ifdef TREE_CODE +extern void unicosmk_unique_section PARAMS ((tree, int)); +#endif +extern void unicosmk_add_extern PARAMS ((const char *)); +extern void unicosmk_output_align PARAMS ((FILE *, int)); +extern char * unicosmk_text_section PARAMS ((void)); +extern char * unicosmk_data_section PARAMS ((void)); +extern void unicosmk_asm_file_start PARAMS ((FILE *)); +extern void unicosmk_asm_file_end PARAMS ((FILE *)); +extern void unicosmk_output_common PARAMS ((FILE *, const char *, int, int)); +#endif /* TARGET_ABI_UNICOSMK */ diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index aba3672..8ee718f 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -153,8 +153,22 @@ static int alpha_issue_rate static int alpha_variable_issue PARAMS ((FILE *, int, rtx, int)); +#if TARGET_ABI_UNICOSMK +static void alpha_init_machine_status + PARAMS ((struct function *p)); +static void alpha_mark_machine_status + PARAMS ((struct function *p)); +static void alpha_free_machine_status + PARAMS ((struct function *p)); +#endif + +static void unicosmk_output_deferred_case_vectors PARAMS ((FILE *)); +static void unicosmk_gen_dsib PARAMS ((unsigned long *imaskP)); +static void unicosmk_output_ssib PARAMS ((FILE *, const char *)); +static int unicosmk_need_dex PARAMS ((rtx)); + /* Get the number of args of a function in one of two ways. */ -#if TARGET_ABI_OPEN_VMS +#if TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK #define NUM_ARGS current_function_args_info.num_args #else #define NUM_ARGS current_function_args_info @@ -176,6 +190,17 @@ static void vms_asm_out_destructor PARAMS ((rtx, int)); # define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags #endif +#if TARGET_ABI_UNICOSMK +static void unicosmk_asm_named_section PARAMS ((const char *, unsigned int)); +static void unicosmk_insert_attributes PARAMS ((tree, tree *)); +static unsigned int unicosmk_section_type_flags PARAMS ((tree, const char *, + int)); +# undef TARGET_INSERT_ATTRIBUTES +# define TARGET_INSERT_ATTRIBUTES unicosmk_insert_attributes +# undef TARGET_SECTION_TYPE_FLAGS +# define TARGET_SECTION_TYPE_FLAGS unicosmk_section_type_flags +#endif + #undef TARGET_ASM_FUNCTION_END_PROLOGUE #define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue @@ -218,20 +243,50 @@ override_options () { 0, 0, 0 } }; + /* Unicos/Mk doesn't have shared libraries. */ + if (TARGET_ABI_UNICOSMK && flag_pic) + { + warning ("-f%s ignored for Unicos/Mk (not supported)", + (flag_pic > 1) ? "PIC" : "pic"); + flag_pic = 0; + } + + /* On Unicos/Mk, the native compiler consistenly generates /d suffices for + floating-point instructions. Make that the default for this target. */ + if (TARGET_ABI_UNICOSMK) + alpha_fprm = ALPHA_FPRM_DYN; + else + alpha_fprm = ALPHA_FPRM_NORM; + alpha_tp = ALPHA_TP_PROG; - alpha_fprm = ALPHA_FPRM_NORM; alpha_fptm = ALPHA_FPTM_N; + /* We cannot use su and sui qualifiers for conversion instructions on + Unicos/Mk. I'm not sure if this is due to assembler or hardware + limitations. Right now, we issue a warning if -mieee is specified + and then ignore it; eventually, we should either get it right or + disable the option altogether. */ + if (TARGET_IEEE) { - alpha_tp = ALPHA_TP_INSN; - alpha_fptm = ALPHA_FPTM_SU; + if (TARGET_ABI_UNICOSMK) + warning ("-mieee not supported on Unicos/Mk"); + else + { + alpha_tp = ALPHA_TP_INSN; + alpha_fptm = ALPHA_FPTM_SU; + } } if (TARGET_IEEE_WITH_INEXACT) { - alpha_tp = ALPHA_TP_INSN; - alpha_fptm = ALPHA_FPTM_SUI; + if (TARGET_ABI_UNICOSMK) + warning ("-mieee-with-inexact not supported on Unicos/Mk"); + else + { + alpha_tp = ALPHA_TP_INSN; + alpha_fptm = ALPHA_FPTM_SUI; + } } if (alpha_tp_string) @@ -308,6 +363,12 @@ override_options () /* Do some sanity checks on the above options. */ + if (TARGET_ABI_UNICOSMK && alpha_fptm != ALPHA_FPTM_N) + { + warning ("trap mode not supported on Unicos/Mk"); + alpha_fptm = ALPHA_FPTM_N; + } + if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI) && alpha_tp != ALPHA_TP_INSN && ! TARGET_CPU_EV6) { @@ -402,6 +463,15 @@ override_options () /* Acquire a unique set number for our register saves and restores. */ alpha_sr_alias_set = new_alias_set (); + + /* Register variables and functions with the garbage collector. */ + +#if TARGET_ABI_UNICOSMK + /* Set up function hooks. */ + init_machine_status = alpha_init_machine_status; + mark_machine_status = alpha_mark_machine_status; + free_machine_status = alpha_free_machine_status; +#endif } /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ @@ -774,10 +844,13 @@ current_file_function_operand (op, mode) int local_symbolic_operand (op, mode) rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; + enum machine_mode mode; { const char *str; + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) + return 0; + if (GET_CODE (op) == LABEL_REF) return 1; @@ -813,6 +886,8 @@ call_operand (op, mode) if (mode != Pmode) return 0; + if (TARGET_ABI_UNICOSMK) + return GET_CODE (op) == REG; if (GET_CODE (op) == SYMBOL_REF) return 1; if (GET_CODE (op) == REG) @@ -826,6 +901,26 @@ call_operand (op, mode) return 0; } +/* Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref, + possibly with an offset. */ + +int +symbolic_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) + return 0; + if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) + return 1; + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op,0)) == PLUS + && GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF + && GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT) + return 1; + return 0; +} + /* Return 1 if OP is a valid Alpha comparison operator. Here we know which comparisons are valid in which insn. */ @@ -1140,7 +1235,7 @@ addition_operation (op, mode) int direct_return () { - return (! TARGET_ABI_OPEN_VMS + return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK && reload_completed && alpha_sa_size () == 0 && get_frame_size () == 0 @@ -1582,7 +1677,11 @@ get_aligned_mem (ref, paligned_mem, pbitnum) data in a different alias set. */ set_mem_alias_set (*paligned_mem, 0); - *pbitnum = GEN_INT ((offset & 3) * 8); + if (WORDS_BIG_ENDIAN) + *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref)) + + (offset & 3) * 8)); + else + *pbitnum = GEN_INT ((offset & 3) * 8); } /* Similar, but just get the address. Handle the two reload cases. @@ -1912,7 +2011,7 @@ alpha_emit_set_const_1 (target, mode, c, n) /* Now try high-order 1 bits. We get that with a sign-extension. But one bit isn't enough here. Be careful to avoid shifting outside the mode and to avoid shifting outside the host wide int size. */ - + if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) - floor_log2 (~ c) - 2)) > 0) for (; bits > 0; bits--) @@ -3197,12 +3296,23 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign) set_mem_alias_set (tmp, 0); emit_move_insn (memh, tmp); - if (sign && size == 2) + if (WORDS_BIG_ENDIAN && sign && (size == 2 || size == 4)) + { + emit_move_insn (addr, plus_constant (mema, -1)); + + emit_insn (gen_extqh_be (extl, meml, addr)); + emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr)); + + addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN); + addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8), + addr, 1, OPTAB_WIDEN); + } + else if (sign && size == 2) { emit_move_insn (addr, plus_constant (mema, ofs+2)); - emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr)); - emit_insn (gen_extqh (exth, memh, addr)); + emit_insn (gen_extxl_le (extl, meml, GEN_INT (64), addr)); + emit_insn (gen_extqh_le (exth, memh, addr)); /* We must use tgt here for the target. Alpha-vms port fails if we use addr for the target, because addr is marked as a pointer and combine @@ -3213,27 +3323,55 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign) } else { - emit_move_insn (addr, plus_constant (mema, ofs)); - emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr)); - switch ((int) size) + if (WORDS_BIG_ENDIAN) { - case 2: - emit_insn (gen_extwh (exth, memh, addr)); - mode = HImode; - break; + emit_move_insn (addr, plus_constant (mema, ofs+size-1)); + switch ((int) size) + { + case 2: + emit_insn (gen_extwh_be (extl, meml, addr)); + mode = HImode; + break; - case 4: - emit_insn (gen_extlh (exth, memh, addr)); - mode = SImode; - break; + case 4: + emit_insn (gen_extlh_be (extl, meml, addr)); + mode = SImode; + break; - case 8: - emit_insn (gen_extqh (exth, memh, addr)); - mode = DImode; - break; + case 8: + emit_insn (gen_extqh_be (extl, meml, addr)); + mode = DImode; + break; - default: - abort(); + default: + abort (); + } + emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr)); + } + else + { + emit_move_insn (addr, plus_constant (mema, ofs)); + emit_insn (gen_extxl_le (extl, meml, GEN_INT (size*8), addr)); + switch ((int) size) + { + case 2: + emit_insn (gen_extwh_le (exth, memh, addr)); + mode = HImode; + break; + + case 4: + emit_insn (gen_extlh_le (exth, memh, addr)); + mode = SImode; + break; + + case 8: + emit_insn (gen_extqh_le (exth, memh, addr)); + mode = DImode; + break; + + default: + abort(); + } } addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl), @@ -3281,47 +3419,94 @@ alpha_expand_unaligned_store (dst, src, size, ofs) emit_move_insn (dsth, memh); emit_move_insn (dstl, meml); - addr = copy_addr_to_reg (plus_constant (dsta, ofs)); - - if (src != const0_rtx) + if (WORDS_BIG_ENDIAN) { - emit_insn (gen_insxh (insh, gen_lowpart (DImode, src), - GEN_INT (size*8), addr)); + addr = copy_addr_to_reg (plus_constant (dsta, ofs+size-1)); + + if (src != const0_rtx) + { + switch ((int) size) + { + case 2: + emit_insn (gen_inswl_be (insh, gen_lowpart (HImode,src), addr)); + break; + case 4: + emit_insn (gen_insll_be (insh, gen_lowpart (SImode,src), addr)); + break; + case 8: + emit_insn (gen_insql_be (insh, gen_lowpart (DImode,src), addr)); + break; + } + emit_insn (gen_insxh (insl, gen_lowpart (DImode, src), + GEN_INT (size*8), addr)); + } switch ((int) size) { case 2: - emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr)); + emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr)); break; case 4: - emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr)); + emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffffffff), addr)); break; case 8: - emit_insn (gen_insql (insl, src, addr)); + { +#if HOST_BITS_PER_WIDE_INT == 32 + rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode); +#else + rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode); +#endif + emit_insn (gen_mskxl_be (dsth, dsth, msk, addr)); + } break; } + + emit_insn (gen_mskxh (dstl, dstl, GEN_INT (size*8), addr)); } + else + { + addr = copy_addr_to_reg (plus_constant (dsta, ofs)); - emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr)); + if (src != const0_rtx) + { + emit_insn (gen_insxh (insh, gen_lowpart (DImode, src), + GEN_INT (size*8), addr)); - switch ((int) size) - { - case 2: - emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffff), addr)); - break; - case 4: - emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffffffff), addr)); - break; - case 8: - { + switch ((int) size) + { + case 2: + emit_insn (gen_inswl_le (insl, gen_lowpart (HImode, src), addr)); + break; + case 4: + emit_insn (gen_insll_le (insl, gen_lowpart (SImode, src), addr)); + break; + case 8: + emit_insn (gen_insql_le (insl, src, addr)); + break; + } + } + + emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr)); + + switch ((int) size) + { + case 2: + emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffff), addr)); + break; + case 4: + emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffffffff), addr)); + break; + case 8: + { #if HOST_BITS_PER_WIDE_INT == 32 - rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode); + rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode); #else - rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode); + rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode); #endif - emit_insn (gen_mskxl (dstl, dstl, msk, addr)); - } - break; + emit_insn (gen_mskxl_le (dstl, dstl, msk, addr)); + } + break; + } } if (src != const0_rtx) @@ -3329,10 +3514,18 @@ alpha_expand_unaligned_store (dst, src, size, ofs) dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN); dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN); } - - /* Must store high before low for degenerate case of aligned. */ - emit_move_insn (memh, dsth); - emit_move_insn (meml, dstl); + + if (WORDS_BIG_ENDIAN) + { + emit_move_insn (meml, dstl); + emit_move_insn (memh, dsth); + } + else + { + /* Must store high before low for degenerate case of aligned. */ + emit_move_insn (memh, dsth); + emit_move_insn (meml, dstl); + } } /* The block move code tries to maximize speed by separating loads and @@ -3397,11 +3590,20 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs) sreg = copy_addr_to_reg (smema); areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL, 1, OPTAB_WIDEN); + if (WORDS_BIG_ENDIAN) + emit_move_insn (sreg, plus_constant (sreg, 7)); for (i = 0; i < words; ++i) { - emit_insn (gen_extxl (data_regs[i], data_regs[i], i64, sreg)); - - emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], sreg)); + if (WORDS_BIG_ENDIAN) + { + emit_insn (gen_extqh_be (data_regs[i], data_regs[i], sreg)); + emit_insn (gen_extxl_be (ext_tmps[i], data_regs[i+1], i64, sreg)); + } + else + { + emit_insn (gen_extxl_le (data_regs[i], data_regs[i], i64, sreg)); + emit_insn (gen_extqh_le (ext_tmps[i], data_regs[i+1], sreg)); + } emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i], gen_rtx_IF_THEN_ELSE (DImode, gen_rtx_EQ (DImode, areg, @@ -3468,12 +3670,22 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs) /* Shift the input data into place. */ dreg = copy_addr_to_reg (dmema); + if (WORDS_BIG_ENDIAN) + emit_move_insn (dreg, plus_constant (dreg, 7)); if (data_regs != NULL) { for (i = words-1; i >= 0; --i) { - emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg)); - emit_insn (gen_insql (data_regs[i], data_regs[i], dreg)); + if (WORDS_BIG_ENDIAN) + { + emit_insn (gen_insql_be (ins_tmps[i], data_regs[i], dreg)); + emit_insn (gen_insxh (data_regs[i], data_regs[i], i64, dreg)); + } + else + { + emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg)); + emit_insn (gen_insql_le (data_regs[i], data_regs[i], dreg)); + } } for (i = words-1; i > 0; --i) { @@ -3484,8 +3696,16 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs) } /* Split and merge the ends with the destination data. */ - emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg)); - emit_insn (gen_mskxl (st_tmp_1, st_tmp_1, im1, dreg)); + if (WORDS_BIG_ENDIAN) + { + emit_insn (gen_mskxl_be (st_tmp_2, st_tmp_2, im1, dreg)); + emit_insn (gen_mskxh (st_tmp_1, st_tmp_1, i64, dreg)); + } + else + { + emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg)); + emit_insn (gen_mskxl_le (st_tmp_1, st_tmp_1, im1, dreg)); + } if (data_regs != NULL) { @@ -3496,17 +3716,24 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs) } /* Store it all. */ - emit_move_insn (st_addr_2, st_tmp_2); + if (WORDS_BIG_ENDIAN) + emit_move_insn (st_addr_1, st_tmp_1); + else + emit_move_insn (st_addr_2, st_tmp_2); for (i = words-1; i > 0; --i) { rtx tmp = change_address (dmem, DImode, gen_rtx_AND (DImode, - plus_constant(dmema, i*8), + plus_constant(dmema, + WORDS_BIG_ENDIAN ? i*8-1 : i*8), im8)); set_mem_alias_set (tmp, 0); emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx); } - emit_move_insn (st_addr_1, st_tmp_1); + if (WORDS_BIG_ENDIAN) + emit_move_insn (st_addr_2, st_tmp_2); + else + emit_move_insn (st_addr_1, st_tmp_1); } @@ -4312,6 +4539,45 @@ alpha_variable_issue (dump, verbose, insn, cim) } +/* Register global variables and machine-specific functions with the + garbage collector. */ + +#if TARGET_ABI_UNICOSMK +static void +alpha_init_machine_status (p) + struct function *p; +{ + p->machine = + (struct machine_function *) xcalloc (1, sizeof (struct machine_function)); + + p->machine->first_ciw = NULL_RTX; + p->machine->last_ciw = NULL_RTX; + p->machine->ciw_count = 0; + p->machine->addr_list = NULL_RTX; +} + +static void +alpha_mark_machine_status (p) + struct function *p; +{ + struct machine_function *machine = p->machine; + + if (machine) + { + ggc_mark_rtx (machine->first_ciw); + ggc_mark_rtx (machine->addr_list); + } +} + +static void +alpha_free_machine_status (p) + struct function *p; +{ + free (p->machine); + p->machine = NULL; +} +#endif /* TARGET_ABI_UNICOSMK */ + /* Functions to save and restore alpha_return_addr_rtx. */ /* Start the ball rolling with RETURN_ADDR_RTX. */ @@ -4478,8 +4744,8 @@ print_operand (file, x, code) const char *round = get_round_mode_suffix (); if (trap || round) - fprintf (file, "%s%s", (trap ? trap : ""), (round ? round : "")); - + fprintf (file, (TARGET_AS_SLASH_BEFORE_SUFFIX ? "/%s%s" : "%s%s"), + (trap ? trap : ""), (round ? round : "")); break; } @@ -4648,13 +4914,20 @@ print_operand (file, x, code) break; case 's': - /* Write the constant value divided by 8. */ + /* Write the constant value divided by 8 for little-endian mode or + (56 - value) / 8 for big-endian mode. */ + if (GET_CODE (x) != CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 - && (INTVAL (x) & 7) != 8) + || (unsigned HOST_WIDE_INT) INTVAL (x) >= (WORDS_BIG_ENDIAN + ? 56 + : 64) + || (INTVAL (x) & 7) != 0) output_operand_lossage ("invalid %%s value"); - fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, + WORDS_BIG_ENDIAN + ? (56 - INTVAL (x)) / 8 + : INTVAL (x) / 8); break; case 'S': @@ -4668,6 +4941,18 @@ print_operand (file, x, code) fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8); break; + case 't': + { + /* On Unicos/Mk systems: use a DEX expression if the symbol + clashes with a register name. */ + int dex = unicosmk_need_dex (x); + if (dex) + fprintf (file, "DEX(%d)", dex); + else + output_addr_const (file, x); + } + break; + case 'C': case 'D': case 'c': case 'd': /* Write out comparison name. */ { @@ -4878,32 +5163,106 @@ function_arg (cum, mode, type, named) int basereg; int num_args; + /* Set up defaults for FP operands passed in FP registers, and + integral operands passed in integer registers. */ + if (TARGET_FPREGS + && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + || GET_MODE_CLASS (mode) == MODE_FLOAT)) + basereg = 32 + 16; + else + basereg = 16; + + /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for + the three platforms, so we can't avoid conditional compilation. */ #if TARGET_ABI_OPEN_VMS - if (mode == VOIDmode) - return alpha_arg_info_reg_val (cum); + { + if (mode == VOIDmode) + return alpha_arg_info_reg_val (cum); - num_args = cum.num_args; - if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type)) - return NULL_RTX; + num_args = cum.num_args; + if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type)) + return NULL_RTX; + } #else - if (cum >= 6) - return NULL_RTX; - num_args = cum; +#if TARGET_ABI_UNICOSMK + { + int size; - /* VOID is passed as a special flag for "last argument". */ - if (type == void_type_node) - basereg = 16; - else if (MUST_PASS_IN_STACK (mode, type)) - return NULL_RTX; - else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named)) - basereg = 16; + /* If this is the last argument, generate the call info word (CIW). */ + /* ??? We don't include the caller's line number in the CIW because + I don't know how to determine it if debug infos are turned off. */ + if (mode == VOIDmode) + { + int i; + HOST_WIDE_INT lo; + HOST_WIDE_INT hi; + rtx ciw; + + lo = 0; + + for (i = 0; i < cum.num_reg_words && i < 5; i++) + if (cum.reg_args_type[i]) + lo |= (1 << (7 - i)); + + if (cum.num_reg_words == 6 && cum.reg_args_type[5]) + lo |= 7; + else + lo |= cum.num_reg_words; + +#if HOST_BITS_PER_WIDE_INT == 32 + hi = (cum.num_args << 20) | cum.num_arg_words; +#else + lo = lo | (cum.num_args << 52) | (cum.num_arg_words << 32); + hi = 0; +#endif + ciw = immed_double_const (lo, hi, DImode); + + return gen_rtx_UNSPEC (DImode, gen_rtvec (1, ciw), + UNSPEC_UMK_LOAD_CIW); + } + + size = ALPHA_ARG_SIZE (mode, type, named); + num_args = cum.num_reg_words; + if (MUST_PASS_IN_STACK (mode, type) + || cum.num_reg_words + size > 6 || cum.force_stack) + return NULL_RTX; + else if (type && TYPE_MODE (type) == BLKmode) + { + rtx reg1, reg2; + + reg1 = gen_rtx_REG (DImode, num_args + 16); + reg1 = gen_rtx_EXPR_LIST (DImode, reg1, const0_rtx); + + /* The argument fits in two registers. Note that we still need to + reserve a register for empty structures. */ + if (size == 0) + return NULL_RTX; + else if (size == 1) + return gen_rtx_PARALLEL (mode, gen_rtvec (1, reg1)); + else + { + reg2 = gen_rtx_REG (DImode, num_args + 17); + reg2 = gen_rtx_EXPR_LIST (DImode, reg2, GEN_INT (8)); + return gen_rtx_PARALLEL (mode, gen_rtvec (2, reg1, reg2)); + } + } + } +#else + { + if (cum >= 6) + return NULL_RTX; + num_args = cum; + + /* VOID is passed as a special flag for "last argument". */ + if (type == void_type_node) + basereg = 16; + else if (MUST_PASS_IN_STACK (mode, type)) + return NULL_RTX; + else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named)) + basereg = 16; + } +#endif /* TARGET_ABI_UNICOSMK */ #endif /* TARGET_ABI_OPEN_VMS */ - else if (TARGET_FPREGS - && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT - || GET_MODE_CLASS (mode) == MODE_FLOAT)) - basereg = 32 + 16; - else - basereg = 16; return gen_rtx_REG (mode, num_args + basereg); } @@ -4913,7 +5272,7 @@ alpha_build_va_list () { tree base, ofs, record, type_decl; - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK) return ptr_type_node; record = make_lang_type (RECORD_TYPE); @@ -4950,7 +5309,7 @@ alpha_va_start (stdarg_p, valist, nextarg) if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK) return; - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK) std_expand_builtin_va_start (stdarg_p, valist, nextarg); /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base @@ -4998,7 +5357,7 @@ alpha_va_arg (valist, type) tree wide_type, wide_ofs; int indirect = 0; - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK) return std_expand_builtin_va_arg (valist, type); tsize = ((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT + 7) / 8) * 8; @@ -5067,7 +5426,7 @@ alpha_va_arg (valist, type) descriptior to generate. */ /* Nonzero if we need a stack procedure. */ -static int vms_is_stack_procedure; +static int alpha_is_stack_procedure; /* Register number (either FP or SP) that is used to unwind the frame. */ static int vms_unwind_regno; @@ -5095,13 +5454,14 @@ alpha_sa_mask (imaskP, fmaskP) if (!current_function_is_thunk) #endif { - if (TARGET_ABI_OPEN_VMS && vms_is_stack_procedure) + if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure) imask |= (1L << HARD_FRAME_POINTER_REGNUM); /* One for every register we have to save. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (! fixed_regs[i] && ! call_used_regs[i] - && regs_ever_live[i] && i != REG_RA) + && regs_ever_live[i] && i != REG_RA + && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM)) { if (i < 32) imask |= (1L << i); @@ -5120,9 +5480,15 @@ alpha_sa_mask (imaskP, fmaskP) imask |= 1L << regno; } } - - if (imask || fmask || alpha_ra_ever_killed ()) - imask |= (1L << REG_RA); + + if (!TARGET_ABI_UNICOSMK) + { + /* If any register spilled, then spill the return address also. */ + /* ??? This is required by the Digital stack unwind specification + and isn't needed if we're doing Dwarf2 unwinding. */ + if (imask || fmask || alpha_ra_ever_killed ()) + imask |= (1L << REG_RA); + } } *imaskP = imask; @@ -5141,19 +5507,55 @@ alpha_sa_size () else #endif { - /* One for every register we have to save. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! fixed_regs[i] && ! call_used_regs[i] - && regs_ever_live[i] && i != REG_RA) - sa_size++; + if (TARGET_ABI_UNICOSMK) + { + for (i = 9; i < 15 && sa_size == 0; i++) + if (! fixed_regs[i] && ! call_used_regs[i] + && regs_ever_live[i]) + sa_size = 14; + for (i = 32 + 2; i < 32 + 10 && sa_size == 0; i++) + if (! fixed_regs[i] && ! call_used_regs[i] + && regs_ever_live[i]) + sa_size = 14; + } + else + { + /* One for every register we have to save. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (! fixed_regs[i] && ! call_used_regs[i] + && regs_ever_live[i] && i != REG_RA) + sa_size++; + } } - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_UNICOSMK) + { + /* We might not need to generate a frame if we don't make any calls + (including calls to __T3E_MISMATCH if this is a vararg function), + don't have any local variables which require stack slots, don't + use alloca and have not determined that we need a frame for other + reasons. */ + + alpha_is_stack_procedure = sa_size != 0 + || alpha_ra_ever_killed () + || get_frame_size() != 0 + || current_function_outgoing_args_size + || current_function_varargs + || current_function_stdarg + || current_function_calls_alloca + || frame_pointer_needed; + + /* Always reserve space for saving callee-saved registers if we + need a frame as required by the calling convention. */ + if (alpha_is_stack_procedure) + sa_size = 14; + } + else if (TARGET_ABI_OPEN_VMS) { /* Start by assuming we can use a register procedure if we don't make any calls (REG_RA not used) or need to save any registers and a stack procedure if we do. */ - vms_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed (); + alpha_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed (); /* Decide whether to refer to objects off our PV via FP or PV. If we need FP for something else or if we receive a nonlocal @@ -5161,7 +5563,7 @@ alpha_sa_size () Otherwise, start by assuming we can use FP. */ vms_base_regno = (frame_pointer_needed || current_function_has_nonlocal_label - || vms_is_stack_procedure + || alpha_is_stack_procedure || current_function_outgoing_args_size ? REG_PV : HARD_FRAME_POINTER_REGNUM); @@ -5175,21 +5577,21 @@ alpha_sa_size () vms_save_fp_regno = i; if (vms_save_fp_regno == -1) - vms_base_regno = REG_PV, vms_is_stack_procedure = 1; + vms_base_regno = REG_PV, alpha_is_stack_procedure = 1; /* Stack unwinding should be done via FP unless we use it for PV. */ vms_unwind_regno = (vms_base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); /* If this is a stack procedure, allow space for saving FP and RA. */ - if (vms_is_stack_procedure) + if (alpha_is_stack_procedure) sa_size += 2; } else { /* If some registers were saved but not RA, RA must also be saved, so leave space for it. */ - if (sa_size != 0 || alpha_ra_ever_killed ()) + if (!TARGET_ABI_UNICOSMK && (sa_size != 0 || alpha_ra_ever_killed ())) sa_size++; /* Our size must be even (multiple of 16 bytes). */ @@ -5204,7 +5606,7 @@ int alpha_pv_save_size () { alpha_sa_size (); - return vms_is_stack_procedure ? 8 : 0; + return alpha_is_stack_procedure ? 8 : 0; } int @@ -5243,8 +5645,8 @@ alpha_does_function_need_gp () { rtx insn; - /* We never need a GP for Windows/NT or VMS. */ - if (TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS) + /* The GP being variable is an OSF abi thing. */ + if (! TARGET_ABI_OSF) return 0; if (TARGET_PROFILING_NEEDS_GP && profile_flag) @@ -5358,9 +5760,15 @@ alpha_expand_prologue () frame_size = get_frame_size (); if (TARGET_ABI_OPEN_VMS) frame_size = ALPHA_ROUND (sa_size - + (vms_is_stack_procedure ? 8 : 0) + + (alpha_is_stack_procedure ? 8 : 0) + frame_size + current_function_pretend_args_size); + else if (TARGET_ABI_UNICOSMK) + /* We have to allocate space for the DSIB if we generate a frame. */ + frame_size = ALPHA_ROUND (sa_size + + (alpha_is_stack_procedure ? 48 : 0)) + + ALPHA_ROUND (frame_size + + current_function_outgoing_args_size); else frame_size = (ALPHA_ROUND (current_function_outgoing_args_size) + sa_size @@ -5388,7 +5796,10 @@ alpha_expand_prologue () don't represent the call as a call. */ if (TARGET_PROFILING_NEEDS_GP && profile_flag) emit_insn (gen_prologue_mcount ()); - + + if (TARGET_ABI_UNICOSMK) + unicosmk_gen_dsib (&imask); + /* Adjust the stack by the frame size. If the frame size is > 4096 bytes, we need to be sure we probe somewhere in the first and last 4096 bytes (we can probably get away without the latter test) and @@ -5405,7 +5816,9 @@ alpha_expand_prologue () int probed = 4096; do - emit_insn (gen_probe_stack (GEN_INT (-probed))); + emit_insn (gen_probe_stack (GEN_INT (TARGET_ABI_UNICOSMK + ? -probed + 64 + : -probed))); while ((probed += 8192) < frame_size); /* We only have to do this probe if we aren't saving registers. */ @@ -5415,7 +5828,9 @@ alpha_expand_prologue () if (frame_size != 0) FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-frame_size)))); + GEN_INT (TARGET_ABI_UNICOSMK + ? -frame_size + 64 + : -frame_size)))); } else { @@ -5432,7 +5847,8 @@ alpha_expand_prologue () rtx seq; emit_move_insn (count, GEN_INT (blocks)); - emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, GEN_INT (4096))); + emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, + GEN_INT (TARGET_ABI_UNICOSMK ? 4096 - 64 : 4096))); /* Because of the difficulty in emitting a new basic block this late in the compilation, generate the loop as a single insn. */ @@ -5479,66 +5895,98 @@ alpha_expand_prologue () = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, stack_pointer_rtx, gen_rtx_PLUS (Pmode, stack_pointer_rtx, - GEN_INT (-frame_size))), + GEN_INT (TARGET_ABI_UNICOSMK + ? -frame_size + 64 + : -frame_size))), REG_NOTES (seq)); } - /* Cope with very large offsets to the register save area. */ - sa_reg = stack_pointer_rtx; - if (reg_offset + sa_size > 0x8000) + if (!TARGET_ABI_UNICOSMK) { - int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; - HOST_WIDE_INT bias; + /* Cope with very large offsets to the register save area. */ + sa_reg = stack_pointer_rtx; + if (reg_offset + sa_size > 0x8000) + { + int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; + HOST_WIDE_INT bias; - if (low + sa_size <= 0x8000) - bias = reg_offset - low, reg_offset = low; - else - bias = reg_offset, reg_offset = 0; + if (low + sa_size <= 0x8000) + bias = reg_offset - low, reg_offset = low; + else + bias = reg_offset, reg_offset = 0; - sa_reg = gen_rtx_REG (DImode, 24); - FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, GEN_INT (bias)))); - } + sa_reg = gen_rtx_REG (DImode, 24); + FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, + GEN_INT (bias)))); + } - /* Save regs in stack order. Beginning with VMS PV. */ - if (TARGET_ABI_OPEN_VMS && vms_is_stack_procedure) - { - mem = gen_rtx_MEM (DImode, stack_pointer_rtx); - set_mem_alias_set (mem, alpha_sr_alias_set); - FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV))); - } + /* Save regs in stack order. Beginning with VMS PV. */ + if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure) + { + mem = gen_rtx_MEM (DImode, stack_pointer_rtx); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV))); + } - /* Save register RA next. */ - if (imask & (1L << REG_RA)) - { - mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); - set_mem_alias_set (mem, alpha_sr_alias_set); - FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA))); - imask &= ~(1L << REG_RA); - reg_offset += 8; - } + /* Save register RA next. */ + if (imask & (1L << REG_RA)) + { + mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA))); + imask &= ~(1L << REG_RA); + reg_offset += 8; + } - /* Now save any other registers required to be saved. */ - for (i = 0; i < 32; i++) - if (imask & (1L << i)) - { - mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); - set_mem_alias_set (mem, alpha_sr_alias_set); - FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i))); - reg_offset += 8; - } + /* Now save any other registers required to be saved. */ + for (i = 0; i < 32; i++) + if (imask & (1L << i)) + { + mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i))); + reg_offset += 8; + } - for (i = 0; i < 32; i++) - if (fmask & (1L << i)) - { - mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset)); - set_mem_alias_set (mem, alpha_sr_alias_set); - FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32))); - reg_offset += 8; - } + for (i = 0; i < 32; i++) + if (fmask & (1L << i)) + { + mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32))); + reg_offset += 8; + } + } + else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure) + { + /* The standard frame on the T3E includes space for saving registers. + We just have to use it. We don't have to save the return address and + the old frame pointer here - they are saved in the DSIB. */ + + reg_offset = -56; + for (i = 9; i < 15; i++) + if (imask & (1L << i)) + { + mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, + reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i))); + reg_offset -= 8; + } + for (i = 2; i < 10; i++) + if (fmask & (1L << i)) + { + mem = gen_rtx_MEM (DFmode, plus_constant (hard_frame_pointer_rtx, + reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32))); + reg_offset -= 8; + } + } if (TARGET_ABI_OPEN_VMS) { - if (!vms_is_stack_procedure) + if (!alpha_is_stack_procedure) /* Register frame procedures save the fp. */ /* ??? Ought to have a dwarf2 save for this. */ emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno), @@ -5559,7 +6007,7 @@ alpha_expand_prologue () - (ALPHA_ROUND (current_function_outgoing_args_size))))); } - else + else if (!TARGET_ABI_UNICOSMK) { /* If we need a frame pointer, set it from the stack pointer. */ if (frame_pointer_needed) @@ -5607,15 +6055,28 @@ alpha_start_function (file, fnname, decl) char *entry_label = (char *) alloca (strlen (fnname) + 6); int i; + /* Don't emit an extern directive for functions defined in the same file. */ + if (TARGET_ABI_UNICOSMK) + { + tree name_tree; + name_tree = get_identifier (fnname); + TREE_ASM_WRITTEN (name_tree) = 1; + } + alpha_fnname = fnname; sa_size = alpha_sa_size (); frame_size = get_frame_size (); if (TARGET_ABI_OPEN_VMS) frame_size = ALPHA_ROUND (sa_size - + (vms_is_stack_procedure ? 8 : 0) + + (alpha_is_stack_procedure ? 8 : 0) + frame_size + current_function_pretend_args_size); + else if (TARGET_ABI_UNICOSMK) + frame_size = ALPHA_ROUND (sa_size + + (alpha_is_stack_procedure ? 48 : 0)) + + ALPHA_ROUND (frame_size + + current_function_outgoing_args_size); else frame_size = (ALPHA_ROUND (current_function_outgoing_args_size) + sa_size @@ -5639,15 +6100,20 @@ alpha_start_function (file, fnname, decl) if (write_symbols == SDB_DEBUG) { +#ifdef ASM_OUTPUT_SOURCE_FILENAME ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl)); +#endif +#ifdef ASM_OUTPUT_SOURCE_LINE if (debug_info_level != DINFO_LEVEL_TERSE) ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl)); +#endif } /* Issue function start and label. */ - if (TARGET_ABI_OPEN_VMS || !flag_inhibit_size_directive) + if (TARGET_ABI_OPEN_VMS + || (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive)) { fputs ("\t.ent ", file); assemble_name (file, fnname); @@ -5666,13 +6132,19 @@ alpha_start_function (file, fnname, decl) strcpy (entry_label, fnname); if (TARGET_ABI_OPEN_VMS) strcat (entry_label, "..en"); + + /* For public functions, the label must be globalized by appending an + additional colon. */ + if (TARGET_ABI_UNICOSMK && TREE_PUBLIC (decl)) + strcat (entry_label, ":"); + ASM_OUTPUT_LABEL (file, entry_label); inside_function = TRUE; if (TARGET_ABI_OPEN_VMS) fprintf (file, "\t.base $%d\n", vms_base_regno); - if (!TARGET_ABI_OPEN_VMS && TARGET_IEEE_CONFORMANT + if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK && TARGET_IEEE_CONFORMANT && !flag_inhibit_size_directive) { /* Set flags in procedure descriptor to request IEEE-conformant @@ -5688,7 +6160,9 @@ alpha_start_function (file, fnname, decl) /* Describe our frame. If the frame size is larger than an integer, print it as zero to avoid an assembler error. We won't be properly describing such a frame, but that's the best we can do. */ - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_UNICOSMK) + ; + else if (TARGET_ABI_OPEN_VMS) { fprintf (file, "\t.frame $%d,", vms_unwind_regno); fprintf (file, HOST_WIDE_INT_PRINT_DEC, @@ -5708,15 +6182,17 @@ alpha_start_function (file, fnname, decl) } /* Describe which registers were spilled. */ - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_UNICOSMK) + ; + else if (TARGET_ABI_OPEN_VMS) { if (imask) - /* ??? Does VMS care if mask contains ra? The old code did'nt + /* ??? Does VMS care if mask contains ra? The old code didn't set it, so I don't here. */ fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1L << REG_RA)); if (fmask) fprintf (file, "\t.fmask 0x%lx,0\n", fmask); - if (!vms_is_stack_procedure) + if (!alpha_is_stack_procedure) fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno); } else if (!flag_inhibit_size_directive) @@ -5760,7 +6236,7 @@ alpha_start_function (file, fnname, decl) ASM_OUTPUT_LABEL (file, fnname); fprintf (file, "\t.pdesc "); assemble_name (file, fnname); - fprintf (file, "..en,%s\n", vms_is_stack_procedure ? "stack" : "reg"); + fprintf (file, "..en,%s\n", alpha_is_stack_procedure ? "stack" : "reg"); alpha_need_linkage (fnname, 1); text_section (); #endif @@ -5772,7 +6248,9 @@ static void alpha_output_function_end_prologue (file) FILE *file; { - if (TARGET_ABI_OPEN_VMS) + if (TARGET_ABI_UNICOSMK) + ; + else if (TARGET_ABI_OPEN_VMS) fputs ("\t.prologue\n", file); else if (TARGET_ABI_WINDOWS_NT) fputs ("\t.prologue 0\n", file); @@ -5811,9 +6289,14 @@ alpha_expand_epilogue () frame_size = get_frame_size (); if (TARGET_ABI_OPEN_VMS) frame_size = ALPHA_ROUND (sa_size - + (vms_is_stack_procedure ? 8 : 0) + + (alpha_is_stack_procedure ? 8 : 0) + frame_size + current_function_pretend_args_size); + else if (TARGET_ABI_UNICOSMK) + frame_size = ALPHA_ROUND (sa_size + + (alpha_is_stack_procedure ? 48 : 0)) + + ALPHA_ROUND (frame_size + + current_function_outgoing_args_size); else frame_size = (ALPHA_ROUND (current_function_outgoing_args_size) + sa_size @@ -5827,7 +6310,7 @@ alpha_expand_epilogue () alpha_sa_mask (&imask, &fmask); - fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && vms_is_stack_procedure) + fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure) || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed)); fp_offset = 0; sa_reg = stack_pointer_rtx; @@ -5837,7 +6320,7 @@ alpha_expand_epilogue () else eh_ofs = NULL_RTX; - if (sa_size) + if (!TARGET_ABI_UNICOSMK && sa_size) { /* If we have a frame pointer, restore SP from it. */ if ((TARGET_ABI_OPEN_VMS @@ -5895,6 +6378,38 @@ alpha_expand_epilogue () reg_offset += 8; } } + else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure) + { + /* Restore callee-saved general-purpose registers. */ + + reg_offset = -56; + + for (i = 9; i < 15; i++) + if (imask & (1L << i)) + { + mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, + reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem)); + reg_offset -= 8; + } + + for (i = 2; i < 10; i++) + if (fmask & (1L << i)) + { + mem = gen_rtx_MEM (DFmode, plus_constant(hard_frame_pointer_rtx, + reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem)); + reg_offset -= 8; + } + + /* Restore the return address from the DSIB. */ + + mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, -8)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem)); + } if (frame_size || eh_ofs) { @@ -5910,8 +6425,15 @@ alpha_expand_epilogue () /* If the stack size is large, begin computation into a temporary register so as not to interfere with a potential fp restore, which must be consecutive with an SP restore. */ - if (frame_size < 32768) + if (frame_size < 32768 + && ! (TARGET_ABI_UNICOSMK && current_function_calls_alloca)) sp_adj2 = GEN_INT (frame_size); + else if (TARGET_ABI_UNICOSMK) + { + sp_adj1 = gen_rtx_REG (DImode, 23); + FRP (emit_move_insn (sp_adj1, hard_frame_pointer_rtx)); + sp_adj2 = const0_rtx; + } else if (frame_size < 0x40007fffL) { int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; @@ -5944,7 +6466,15 @@ alpha_expand_epilogue () /* From now on, things must be in order. So emit blockages. */ /* Restore the frame pointer. */ - if (fp_is_frame_pointer) + if (TARGET_ABI_UNICOSMK) + { + emit_insn (gen_blockage ()); + mem = gen_rtx_MEM (DImode, + plus_constant (hard_frame_pointer_rtx, -16)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (hard_frame_pointer_rtx, mem)); + } + else if (fp_is_frame_pointer) { emit_insn (gen_blockage ()); mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, fp_offset)); @@ -5960,17 +6490,29 @@ alpha_expand_epilogue () /* Restore the stack pointer. */ emit_insn (gen_blockage ()); - FRP (emit_move_insn (stack_pointer_rtx, - gen_rtx_PLUS (DImode, sp_adj1, sp_adj2))); + if (sp_adj2 == const0_rtx) + FRP (emit_move_insn (stack_pointer_rtx, sp_adj1)); + else + FRP (emit_move_insn (stack_pointer_rtx, + gen_rtx_PLUS (DImode, sp_adj1, sp_adj2))); } else { - if (TARGET_ABI_OPEN_VMS && !vms_is_stack_procedure) + if (TARGET_ABI_OPEN_VMS && !alpha_is_stack_procedure) { emit_insn (gen_blockage ()); FRP (emit_move_insn (hard_frame_pointer_rtx, gen_rtx_REG (DImode, vms_save_fp_regno))); } + else if (TARGET_ABI_UNICOSMK && !alpha_is_stack_procedure) + { + /* Decrement the frame pointer if the function does not have a + frame. */ + + emit_insn (gen_blockage ()); + FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx, + hard_frame_pointer_rtx, GEN_INT (-1)))); + } } } @@ -5983,7 +6525,7 @@ alpha_end_function (file, fnname, decl) tree decl ATTRIBUTE_UNUSED; { /* End the function. */ - if (!flag_inhibit_size_directive) + if (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive) { fputs ("\t.end ", file); assemble_name (file, fnname); @@ -6000,6 +6542,13 @@ alpha_end_function (file, fnname, decl) if (!DECL_WEAK (current_function_decl) && (!flag_pic || !TREE_PUBLIC (current_function_decl))) SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1; + + /* Output jump tables and the static subroutine information block. */ + if (TARGET_ABI_UNICOSMK) + { + unicosmk_output_ssib (file, fnname); + unicosmk_output_deferred_case_vectors (file); + } } /* Debugging support. */ @@ -7032,7 +7581,7 @@ check_float_value (mode, d, overflow) return 0; } - + #if TARGET_ABI_OPEN_VMS /* Return the VMS argument type corresponding to MODE. */ @@ -7296,3 +7845,801 @@ alpha_need_linkage (name, is_local) } #endif /* TARGET_ABI_OPEN_VMS */ + +#if TARGET_ABI_UNICOSMK + +static void unicosmk_output_module_name PARAMS ((FILE *)); +static void unicosmk_output_default_externs PARAMS ((FILE *)); +static void unicosmk_output_dex PARAMS ((FILE *)); +static void unicosmk_output_externs PARAMS ((FILE *)); +static void unicosmk_output_addr_vec PARAMS ((FILE *, rtx)); +static const char *unicosmk_ssib_name PARAMS ((void)); + + +/* Define the offset between two registers, one to be eliminated, and the + other its replacement, at the start of a routine. */ + +int +unicosmk_initial_elimination_offset (from, to) + int from; + int to; +{ + int fixed_size; + + fixed_size = alpha_sa_size(); + if (fixed_size != 0) + fixed_size += 48; + + if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) + return -fixed_size; + else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) + return 0; + else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) + return (ALPHA_ROUND (current_function_outgoing_args_size) + + ALPHA_ROUND (get_frame_size())); + else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) + return (ALPHA_ROUND (fixed_size) + + ALPHA_ROUND (get_frame_size() + + current_function_outgoing_args_size)); + else + abort (); +} + +/* Output the module name for .ident and .end directives. We have to strip + directories and add make sure that the module name starts with a letter + or '$'. */ + +static void +unicosmk_output_module_name (file) + FILE *file; +{ + const char *name; + + /* Strip directories. */ + + name = strrchr (main_input_filename, '/'); + if (name) + ++name; + else + name = main_input_filename; + + /* CAM only accepts module names that start with a letter or '$'. We + prefix the module name with a '$' if necessary. */ + + if (!ISALPHA (*name)) + fprintf (file, "$%s", name); + else + fputs (name, file); +} + +/* Output text that to appear at the beginning of an assembler file. */ + +void +unicosmk_asm_file_start (file) + FILE *file; +{ + int i; + + fputs ("\t.ident\t", file); + unicosmk_output_module_name (file); + fputs ("\n\n", file); + + /* The Unicos/Mk assembler uses different register names. Instead of trying + to support them, we simply use micro definitions. */ + + /* CAM has different register names: rN for the integer register N and fN + for the floating-point register N. Instead of trying to use these in + alpha.md, we define the symbols $N and $fN to refer to the appropriate + register. */ + + for (i = 0; i < 32; ++i) + fprintf (file, "$%d <- r%d\n", i, i); + + for (i = 0; i < 32; ++i) + fprintf (file, "$f%d <- f%d\n", i, i); + + putc ('\n', file); + + /* The .align directive fill unused space with zeroes which does not work + in code sections. We define the macro 'gcc@code@align' which uses nops + instead. Note that it assumes that code sections always have the + biggest possible alignment since . refers to the current offset from + the beginning of the section. */ + + fputs ("\t.macro gcc@code@align n\n", file); + fputs ("gcc@n@bytes = 1 << n\n", file); + fputs ("gcc@here = . % gcc@n@bytes\n", file); + fputs ("\t.if ne, gcc@here, 0\n", file); + fputs ("\t.repeat (gcc@n@bytes - gcc@here) / 4\n", file); + fputs ("\tbis r31,r31,r31\n", file); + fputs ("\t.endr\n", file); + fputs ("\t.endif\n", file); + fputs ("\t.endm gcc@code@align\n\n", file); + + /* Output extern declarations which should always be visible. */ + unicosmk_output_default_externs (file); + + /* Open a dummy section. We always need to be inside a section for the + section-switching code to work correctly. + ??? This should be a module id or something like that. I still have to + figure out what the rules for those are. */ + fputs ("\n\t.psect\t$SG00000,data\n", file); +} + +/* Output text to appear at the end of an assembler file. This includes all + pending extern declarations and DEX expressions. */ + +void +unicosmk_asm_file_end (file) + FILE *file; +{ + fputs ("\t.endp\n\n", file); + + /* Output all pending externs. */ + + unicosmk_output_externs (file); + + /* Output dex definitions used for functions whose names conflict with + register names. */ + + unicosmk_output_dex (file); + + fputs ("\t.end\t", file); + unicosmk_output_module_name (file); + putc ('\n', file); +} + +/* Output the definition of a common variable. */ + +void +unicosmk_output_common (file, name, size, align) + FILE *file; + const char *name; + int size; + int align; +{ + tree name_tree; + printf ("T3E__: common %s\n", name); + + common_section (); + fputs("\t.endp\n\n\t.psect ", file); + assemble_name(file, name); + fprintf(file, ",%d,common\n", floor_log2 (align / BITS_PER_UNIT)); + fprintf(file, "\t.byte\t0:%d\n", size); + + /* Mark the symbol as defined in this module. */ + name_tree = get_identifier (name); + TREE_ASM_WRITTEN (name_tree) = 1; +} + +#define SECTION_PUBLIC SECTION_MACH_DEP +#define SECTION_MAIN (SECTION_PUBLIC << 1) +static int current_section_align; + +static unsigned int +unicosmk_section_type_flags (decl, name, reloc) + tree decl; + const char *name; + int reloc ATTRIBUTE_UNUSED; +{ + unsigned int flags = default_section_type_flags (decl, name, reloc); + + if (!decl) + return flags; + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + current_section_align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); + if (align_functions_log > current_section_align) + current_section_align = align_functions_log; + + if (! strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "main")) + flags |= SECTION_MAIN; + } + else + current_section_align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT); + + if (TREE_PUBLIC (decl)) + flags |= SECTION_PUBLIC; + + return flags; +} + +/* Generate a section name for decl and associate it with the + declaration. */ + +void +unicosmk_unique_section (decl, reloc) + tree decl; + int reloc ATTRIBUTE_UNUSED; +{ + const char *name; + int len; + + if (!decl) + abort (); + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + STRIP_NAME_ENCODING (name, name); + len = strlen (name); + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + char *string; + + /* It is essential that we prefix the section name here because + otherwise the section names generated for constructors and + destructors confuse collect2. */ + + string = alloca (len + 6); + sprintf (string, "code@%s", name); + DECL_SECTION_NAME (decl) = build_string (len + 5, string); + } + else if (TREE_PUBLIC (decl)) + DECL_SECTION_NAME (decl) = build_string (len, name); + else + { + char *string; + + string = alloca (len + 6); + sprintf (string, "data@%s", name); + DECL_SECTION_NAME (decl) = build_string (len + 5, string); + } +} + +/* Switch to an arbitrary section NAME with attributes as specified + by FLAGS. ALIGN specifies any known alignment requirements for + the section; 0 if the default should be used. */ + +static void +unicosmk_asm_named_section (name, flags) + const char *name; + unsigned int flags; +{ + const char *kind; + + /* Close the previous section. */ + + fputs ("\t.endp\n\n", asm_out_file); + + /* Find out what kind of section we are opening. */ + + if (flags & SECTION_MAIN) + fputs ("\t.start\tmain\n", asm_out_file); + + if (flags & SECTION_CODE) + kind = "code"; + else if (flags & SECTION_PUBLIC) + kind = "common"; + else + kind = "data"; + + if (current_section_align != 0) + fprintf (asm_out_file, "\t.psect\t%s,%d,%s\n", name, + current_section_align, kind); + else + fprintf (asm_out_file, "\t.psect\t%s,%s\n", name, kind); +} + +static void +unicosmk_insert_attributes (decl, attr_ptr) + tree decl; + tree *attr_ptr ATTRIBUTE_UNUSED; +{ + if (DECL_P (decl) + && (TREE_PUBLIC (decl) || TREE_CODE (decl) == FUNCTION_DECL)) + UNIQUE_SECTION (decl, 0); +} + +/* Output an alignment directive. We have to use the macro 'gcc@code@align' + in code sections because .align fill unused space with zeroes. */ + +void +unicosmk_output_align (file, align) + FILE *file; + int align; +{ + if (inside_function) + fprintf (file, "\tgcc@code@align\t%d\n", align); + else + fprintf (file, "\t.align\t%d\n", align); +} + +/* Add a case vector to the current function's list of deferred case + vectors. Case vectors have to be put into a separate section because CAM + does not allow data definitions in code sections. */ + +void +unicosmk_defer_case_vector (lab, vec) + rtx lab; + rtx vec; +{ + struct machine_function *machine = cfun->machine; + + vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec); + machine->addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, + machine->addr_list); +} + +/* Output a case vector. */ + +static void +unicosmk_output_addr_vec (file, vec) + FILE *file; + rtx vec; +{ + rtx lab = XEXP (vec, 0); + rtx body = XEXP (vec, 1); + int vlen = XVECLEN (body, 0); + int idx; + + ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (lab)); + + for (idx = 0; idx < vlen; idx++) + { + ASM_OUTPUT_ADDR_VEC_ELT + (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); + } +} + +/* Output current function's deferred case vectors. */ + +static void +unicosmk_output_deferred_case_vectors (file) + FILE *file; +{ + struct machine_function *machine = cfun->machine; + rtx t; + + if (machine->addr_list == NULL_RTX) + return; + + data_section (); + for (t = machine->addr_list; t; t = XEXP (t, 1)) + unicosmk_output_addr_vec (file, XEXP (t, 0)); +} + +/* Set up the dynamic subprogram information block (DSIB) and update the + frame pointer register ($15) for subroutines which have a frame. If the + subroutine doesn't have a frame, simply increment $15. */ + +static void +unicosmk_gen_dsib (imaskP) + unsigned long * imaskP; +{ + if (alpha_is_stack_procedure) + { + const char *ssib_name; + rtx mem; + + /* Allocate 64 bytes for the DSIB. */ + + FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-64)))); + emit_insn (gen_blockage ()); + + /* Save the return address. */ + + mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 56)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA))); + (*imaskP) &= ~(1L << REG_RA); + + /* Save the old frame pointer. */ + + mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 48)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, hard_frame_pointer_rtx)); + (*imaskP) &= ~(1L << HARD_FRAME_POINTER_REGNUM); + + emit_insn (gen_blockage ()); + + /* Store the SSIB pointer. */ + + ssib_name = ggc_strdup (unicosmk_ssib_name ()); + mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 32)); + set_mem_alias_set (mem, alpha_sr_alias_set); + + FRP (emit_move_insn (gen_rtx_REG (DImode, 5), + gen_rtx_SYMBOL_REF (Pmode, ssib_name))); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 5))); + + /* Save the CIW index. */ + + mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 24)); + set_mem_alias_set (mem, alpha_sr_alias_set); + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 25))); + + emit_insn (gen_blockage ()); + + /* Set the new frame pointer. */ + + FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx, + stack_pointer_rtx, GEN_INT (64)))); + + } + else + { + /* Increment the frame pointer register to indicate that we do not + have a frame. */ + + FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx, + hard_frame_pointer_rtx, GEN_INT (1)))); + } +} + +#define SSIB_PREFIX "__SSIB_" +#define SSIB_PREFIX_LEN 7 + +/* Generate the name of the SSIB section for the current function. */ + +static const char * +unicosmk_ssib_name () +{ + /* This is ok since CAM won't be able to deal with names longer than that + anyway. */ + + static char name[256]; + + rtx x; + const char *fnname; + char *ssib_name; + int len; + + x = DECL_RTL (cfun->decl); + if (GET_CODE (x) != MEM) + abort (); + x = XEXP (x, 0); + if (GET_CODE (x) != SYMBOL_REF) + abort (); + fnname = XSTR (x, 0); + STRIP_NAME_ENCODING (fnname, fnname); + + len = strlen (fnname); + if (len + SSIB_PREFIX_LEN > 255) + len = 255 - SSIB_PREFIX_LEN; + + strcpy (name, SSIB_PREFIX); + strncpy (name + SSIB_PREFIX_LEN, fnname, len); + name[len + SSIB_PREFIX_LEN] = 0; + + return name; +} + +/* Output the static subroutine information block for the current + function. */ + +static void +unicosmk_output_ssib (file, fnname) + FILE *file; + const char *fnname; +{ + int len; + int i; + rtx x; + rtx ciw; + struct machine_function *machine = cfun->machine; + + ssib_section (); + fprintf (file, "\t.endp\n\n\t.psect\t%s%s,data\n", user_label_prefix, + unicosmk_ssib_name ()); + + /* Some required stuff and the function name length. */ + + len = strlen (fnname); + fprintf (file, "\t.quad\t^X20008%2.2X28\n", len); + + /* Saved registers + ??? We don't do that yet. */ + + fputs ("\t.quad\t0\n", file); + + /* Function address. */ + + fputs ("\t.quad\t", file); + assemble_name (file, fnname); + putc ('\n', file); + + fputs ("\t.quad\t0\n", file); + fputs ("\t.quad\t0\n", file); + + /* Function name. + ??? We do it the same way Cray CC does it but this could be + simplified. */ + + for( i = 0; i < len; i++ ) + fprintf (file, "\t.byte\t%d\n", (int)(fnname[i])); + if( (len % 8) == 0 ) + fputs ("\t.quad\t0\n", file); + else + fprintf (file, "\t.bits\t%d : 0\n", (8 - (len % 8))*8); + + /* All call information words used in the function. */ + + for (x = machine->first_ciw; x; x = XEXP (x, 1)) + { + ciw = XEXP (x, 0); + fprintf (file, "\t.quad\t"); +#if HOST_BITS_PER_WIDE_INT == 32 + fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + CONST_DOUBLE_HIGH (ciw), CONST_DOUBLE_LOW (ciw)); +#else + fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (ciw)); +#endif + fprintf (file, "\n"); + } +} + +/* Add a call information word (CIW) to the list of the current function's + CIWs and return its index. + + X is a CONST_INT or CONST_DOUBLE representing the CIW. */ + +rtx +unicosmk_add_call_info_word (x) + rtx x; +{ + rtx node; + struct machine_function *machine = cfun->machine; + + node = gen_rtx_EXPR_LIST (VOIDmode, x, NULL_RTX); + if (machine->first_ciw == NULL_RTX) + machine->first_ciw = node; + else + XEXP (machine->last_ciw, 1) = node; + + machine->last_ciw = node; + ++machine->ciw_count; + + return GEN_INT (machine->ciw_count + + strlen (current_function_name)/8 + 5); +} + +static char unicosmk_section_buf[100]; + +char * +unicosmk_text_section () +{ + static int count = 0; + sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@text___%d,code", + count++); + return unicosmk_section_buf; +} + +char * +unicosmk_data_section () +{ + static int count = 1; + sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@data___%d,data", + count++); + return unicosmk_section_buf; +} + +/* The Cray assembler doesn't accept extern declarations for symbols which + are defined in the same file. We have to keep track of all global + symbols which are referenced and/or defined in a source file and output + extern declarations for those which are referenced but not defined at + the end of file. */ + +/* List of identifiers for which an extern declaration might have to be + emitted. */ + +struct unicosmk_extern_list +{ + struct unicosmk_extern_list *next; + const char *name; +}; + +static struct unicosmk_extern_list *unicosmk_extern_head = 0; + +/* Output extern declarations which are required for every asm file. */ + +static void +unicosmk_output_default_externs (file) + FILE *file; +{ + static const char *externs[] = + { "__T3E_MISMATCH" }; + + int i; + int n; + + n = ARRAY_SIZE (externs); + + for (i = 0; i < n; i++) + fprintf (file, "\t.extern\t%s\n", externs[i]); +} + +/* Output extern declarations for global symbols which are have been + referenced but not defined. */ + +static void +unicosmk_output_externs (file) + FILE *file; +{ + struct unicosmk_extern_list *p; + const char *real_name; + int len; + tree name_tree; + + len = strlen (user_label_prefix); + for (p = unicosmk_extern_head; p != 0; p = p->next) + { + /* We have to strip the encoding and possibly remove user_label_prefix + from the identifier in order to handle -fleading-underscore and + explicit asm names correctly (cf. gcc.dg/asm-names-1.c). */ + STRIP_NAME_ENCODING (real_name, p->name); + if (len && p->name[0] == '*' + && !memcmp (real_name, user_label_prefix, len)) + real_name += len; + + name_tree = get_identifier (real_name); + if (! TREE_ASM_WRITTEN (name_tree)) + { + TREE_ASM_WRITTEN (name_tree) = 1; + fputs ("\t.extern\t", file); + assemble_name (file, p->name); + putc ('\n', file); + } + } +} + +/* Record an extern. */ + +void +unicosmk_add_extern (name) + const char *name; +{ + struct unicosmk_extern_list *p; + + p = (struct unicosmk_extern_list *) + permalloc (sizeof (struct unicosmk_extern_list)); + p->next = unicosmk_extern_head; + p->name = name; + unicosmk_extern_head = p; +} + +/* The Cray assembler generates incorrect code if identifiers which + conflict with register names are used as instruction operands. We have + to replace such identifiers with DEX expressions. */ + +/* Structure to collect identifiers which have been replaced by DEX + expressions. */ + +struct unicosmk_dex { + struct unicosmk_dex *next; + const char *name; +}; + +/* List of identifiers which have been replaced by DEX expressions. The DEX + number is determined by the position in the list. */ + +static struct unicosmk_dex *unicosmk_dex_list = NULL; + +/* The number of elements in the DEX list. */ + +static int unicosmk_dex_count = 0; + +/* Check if NAME must be replaced by a DEX expression. */ + +static int +unicosmk_special_name (name) + const char *name; +{ + if (name[0] == '*') + ++name; + + if (name[0] == '$') + ++name; + + if (name[0] != 'r' && name[0] != 'f' && name[0] != 'R' && name[0] != 'F') + return 0; + + switch (name[1]) + { + case '1': case '2': + return (name[2] == '\0' || (ISDIGIT (name[2]) && name[3] == '\0')); + + case '3': + return (name[2] == '\0' + || ((name[2] == '0' || name[2] == '1') && name[3] == '\0')); + + default: + return (ISDIGIT (name[1]) && name[2] == '\0'); + } +} + +/* Return the DEX number if X must be replaced by a DEX expression and 0 + otherwise. */ + +static int +unicosmk_need_dex (x) + rtx x; +{ + struct unicosmk_dex *dex; + const char *name; + int i; + + if (GET_CODE (x) != SYMBOL_REF) + return 0; + + name = XSTR (x,0); + if (! unicosmk_special_name (name)) + return 0; + + i = unicosmk_dex_count; + for (dex = unicosmk_dex_list; dex; dex = dex->next) + { + if (! strcmp (name, dex->name)) + return i; + --i; + } + + dex = (struct unicosmk_dex *) permalloc (sizeof (struct unicosmk_dex)); + dex->name = name; + dex->next = unicosmk_dex_list; + unicosmk_dex_list = dex; + + ++unicosmk_dex_count; + return unicosmk_dex_count; +} + +/* Output the DEX definitions for this file. */ + +static void +unicosmk_output_dex (file) + FILE *file; +{ + struct unicosmk_dex *dex; + int i; + + if (unicosmk_dex_list == NULL) + return; + + fprintf (file, "\t.dexstart\n"); + + i = unicosmk_dex_count; + for (dex = unicosmk_dex_list; dex; dex = dex->next) + { + fprintf (file, "\tDEX (%d) = ", i); + assemble_name (file, dex->name); + putc ('\n', file); + --i; + } + + fprintf (file, "\t.dexend\n"); +} + +#else + +static void +unicosmk_output_deferred_case_vectors (file) + FILE *file ATTRIBUTE_UNUSED; +{} + +static void +unicosmk_gen_dsib (imaskP) + unsigned long * imaskP ATTRIBUTE_UNUSED; +{} + +static void +unicosmk_output_ssib (file, fnname) + FILE * file ATTRIBUTE_UNUSED; + const char * fnname ATTRIBUTE_UNUSED; +{} + +rtx +unicosmk_add_call_info_word (x) + rtx x ATTRIBUTE_UNUSED; +{ + return NULL_RTX; +} + +static int +unicosmk_need_dex (x) + rtx x ATTRIBUTE_UNUSED; +{ + return 0; +} + +#endif /* TARGET_ABI_UNICOSMK */ diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 220eb62..3b030b2 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -179,11 +179,17 @@ extern enum alpha_fp_trap_mode alpha_fptm; /* These are for target os support and cannot be changed at runtime. */ #define TARGET_ABI_WINDOWS_NT 0 #define TARGET_ABI_OPEN_VMS 0 -#define TARGET_ABI_OSF (!TARGET_ABI_WINDOWS_NT && !TARGET_ABI_OPEN_VMS) +#define TARGET_ABI_UNICOSMK 0 +#define TARGET_ABI_OSF (!TARGET_ABI_WINDOWS_NT \ + && !TARGET_ABI_OPEN_VMS \ + && !TARGET_ABI_UNICOSMK) #ifndef TARGET_AS_CAN_SUBTRACT_LABELS #define TARGET_AS_CAN_SUBTRACT_LABELS TARGET_GAS #endif +#ifndef TARGET_AS_SLASH_BEFORE_SUFFIX +#define TARGET_AS_SLASH_BEFORE_SUFFIX TARGET_GAS +#endif #ifndef TARGET_CAN_FAULT_IN_PROLOGUE #define TARGET_CAN_FAULT_IN_PROLOGUE 0 #endif @@ -792,7 +798,9 @@ enum reg_class { NO_REGS, PV_REG, GENERAL_REGS, FLOAT_REGS, ALL_REGS, `R' is a SYMBOL_REF that has SYMBOL_REF_FLAG set or is the current function. - 'S' is a 6-bit constant (valid for a shift insn). */ + 'S' is a 6-bit constant (valid for a shift insn). + + 'U' is a symbolic operand. */ #define EXTRA_CONSTRAINT(OP, C) \ ((C) == 'Q' ? normal_memory_operand (OP, VOIDmode) \ @@ -800,6 +808,8 @@ enum reg_class { NO_REGS, PV_REG, GENERAL_REGS, FLOAT_REGS, ALL_REGS, : (C) == 'S' ? (GET_CODE (OP) == CONST_INT \ && (unsigned HOST_WIDE_INT) INTVAL (OP) < 64) \ : (C) == 'T' ? GET_CODE (OP) == HIGH \ + : (TARGET_ABI_UNICOSMK && (C) == 'U') \ + ? symbolic_operand (OP, VOIDmode) \ : 0) /* Given an rtx X being reloaded into a reg required to be @@ -2174,7 +2184,8 @@ do { \ {"hard_int_register_operand", {SUBREG, REG}}, \ {"reg_not_elim_operand", {SUBREG, REG}}, \ {"reg_no_subreg_operand", {REG}}, \ - {"addition_operation", {PLUS}}, + {"addition_operation", {PLUS}}, \ + {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, /* Define the `__builtin_va_list' type for the ABI. */ #define BUILD_VA_LIST_TYPE(VALIST) \ diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index 3cce979..34280f7 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -31,6 +31,10 @@ (UNSPEC_MSKXH 3) (UNSPEC_CVTQL 4) (UNSPEC_NT_LDA 5) + (UNSPEC_UMK_LAUM 6) + (UNSPEC_UMK_LALM 7) + (UNSPEC_UMK_LAL 8) + (UNSPEC_UMK_LOAD_CIW 9) ]) ;; UNSPEC_VOLATILE: @@ -49,6 +53,12 @@ (UNSPECV_LDGP2 10) (UNSPECV_FORCE_MOV 11) ]) + +;; Where necessary, the suffixes _le and _be are used to distinguish between +;; little-endian and big-endian patterns. +;; +;; Note that the Unicos/Mk assembler does not support the following +;; opcodes: mov, fmov, nop, fnop, unop. ;; Processor type -- this attribute must exactly match the processor_type ;; enumeration in alpha.h. @@ -904,11 +914,13 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" "" "subqv %r1,%2,%0") +;; The Unicos/Mk assembler doesn't support mull. + (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ") (match_operand:SI 2 "reg_or_8bit_operand" "rI")))] - "" + "!TARGET_ABI_UNICOSMK" "mull %r1,%2,%0" [(set_attr "type" "imul") (set_attr "opsize" "si")]) @@ -918,7 +930,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (sign_extend:DI (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ") (match_operand:SI 2 "reg_or_8bit_operand" "rI"))))] - "" + "!TARGET_ABI_UNICOSMK" "mull %r1,%2,%0" [(set_attr "type" "imul") (set_attr "opsize" "si")]) @@ -932,7 +944,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (sign_extend:DI (mult:SI (match_dup 1) (match_dup 2)))) (const_int 0))] - "" + "!TARGET_ABI_UNICOSMK" "mullv %r1,%2,%0" [(set_attr "type" "imul") (set_attr "opsize" "si")]) @@ -984,14 +996,17 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" [(set_attr "type" "imul") (set_attr "opsize" "udi")]) -;; The divide and remainder operations always take their inputs from -;; r24 and r25, put their output in r27, and clobber r23 and r28. - -;; ??? Force sign-extension here because some versions of OSF/1 don't -;; do the right thing if the inputs are not properly sign-extended. -;; But Linux, for instance, does not have this problem. Is it worth -;; the complication here to eliminate the sign extension? -;; Interix/NT has the same sign-extension problem. +;; The divide and remainder operations take their inputs from r24 and +;; r25, put their output in r27, and clobber r23 and r28 on all +;; systems except Unicos/Mk. On Unicos, the standard library provides +;; subroutines which use the standard calling convention and work on +;; DImode operands. + +;; ??? Force sign-extension here because some versions of OSF/1 and +;; Interix/NT don't do the right thing if the inputs are not properly +;; sign-extended. But Linux, for instance, does not have this +;; problem. Is it worth the complication here to eliminate the sign +;; extension? (define_expand "divsi3" [(set (reg:DI 24) @@ -1004,7 +1019,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:SI 0 "nonimmediate_operand" "") (subreg:SI (reg:DI 27) 0))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") (define_expand "udivsi3" @@ -1018,7 +1033,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:SI 0 "nonimmediate_operand" "") (subreg:SI (reg:DI 27) 0))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") (define_expand "modsi3" @@ -1032,7 +1047,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:SI 0 "nonimmediate_operand" "") (subreg:SI (reg:DI 27) 0))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") (define_expand "umodsi3" @@ -1046,7 +1061,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:SI 0 "nonimmediate_operand" "") (subreg:SI (reg:DI 27) 0))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") (define_expand "divdi3" @@ -1059,7 +1074,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI 27))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") (define_expand "udivdi3" @@ -1072,10 +1087,23 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI 27))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") (define_expand "moddi3" + [(use (match_operand:DI 0 "nonimmediate_operand" "")) + (use (match_operand:DI 1 "input_operand" "")) + (use (match_operand:DI 2 "input_operand" ""))] + "!TARGET_ABI_OPEN_VMS" +{ + if (TARGET_ABI_UNICOSMK) + emit_insn (gen_moddi3_umk (operands[0], operands[1], operands[2])); + else + emit_insn (gen_moddi3_dft (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "moddi3_dft" [(set (reg:DI 24) (match_operand:DI 1 "input_operand" "")) (set (reg:DI 25) (match_operand:DI 2 "input_operand" "")) (parallel [(set (reg:DI 27) @@ -1085,10 +1113,48 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI 27))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") +;; On Unicos/Mk, we do as the system's C compiler does: +;; compute the quotient, multiply and subtract. + +(define_expand "moddi3_umk" + [(use (match_operand:DI 0 "nonimmediate_operand" "")) + (use (match_operand:DI 1 "input_operand" "")) + (use (match_operand:DI 2 "input_operand" ""))] + "TARGET_ABI_UNICOSMK" +{ + rtx mul, div, tmp; + + mul = gen_reg_rtx (DImode); + tmp = gen_reg_rtx (DImode); + operands[1] = force_reg (DImode, operands[1]); + operands[2] = force_reg (DImode, operands[2]); + + div = expand_binop (DImode, sdiv_optab, operands[1], operands[2], + NULL_RTX, 0, OPTAB_LIB); + div = force_reg (DImode, div); + emit_insn (gen_muldi3 (mul, operands[2], div)); + emit_insn (gen_subdi3 (tmp, operands[1], mul)); + emit_move_insn (operands[0], tmp); + DONE; +}) + (define_expand "umoddi3" + [(use (match_operand:DI 0 "nonimmediate_operand" "")) + (use (match_operand:DI 1 "input_operand" "")) + (use (match_operand:DI 2 "input_operand" ""))] + "! TARGET_ABI_OPEN_VMS" +{ + if (TARGET_ABI_UNICOSMK) + emit_insn (gen_umoddi3_umk (operands[0], operands[1], operands[2])); + else + emit_insn (gen_umoddi3_dft (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "umoddi3_dft" [(set (reg:DI 24) (match_operand:DI 1 "input_operand" "")) (set (reg:DI 25) (match_operand:DI 2 "input_operand" "")) (parallel [(set (reg:DI 27) @@ -1098,9 +1164,31 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (clobber (reg:DI 28))]) (set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI 27))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "") +(define_expand "umoddi3_umk" + [(use (match_operand:DI 0 "nonimmediate_operand" "")) + (use (match_operand:DI 1 "input_operand" "")) + (use (match_operand:DI 2 "input_operand" ""))] + "TARGET_ABI_UNICOSMK" +{ + rtx mul, div, tmp; + + mul = gen_reg_rtx (DImode); + tmp = gen_reg_rtx (DImode); + operands[1] = force_reg (DImode, operands[1]); + operands[2] = force_reg (DImode, operands[2]); + + div = expand_binop (DImode, udiv_optab, operands[1], operands[2], + NULL_RTX, 1, OPTAB_LIB); + div = force_reg (DImode, div); + emit_insn (gen_muldi3 (mul, operands[2], div)); + emit_insn (gen_subdi3 (tmp, operands[1], mul)); + emit_move_insn (operands[0], tmp); + DONE; +}) + ;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as ;; expanded by the assembler. @@ -1121,7 +1209,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" [(reg:DI 24) (reg:DI 25)]))) (clobber (reg:DI 23)) (clobber (reg:DI 28))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "%E0 $24,$25,$27" [(set_attr "type" "jsr") (set_attr "length" "8")]) @@ -1143,7 +1231,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" [(reg:DI 24) (reg:DI 25)])) (clobber (reg:DI 23)) (clobber (reg:DI 28))] - "! TARGET_ABI_OPEN_VMS" + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" "%E0 $24,$25,$27" [(set_attr "type" "jsr") (set_attr "length" "8")]) @@ -1655,6 +1743,18 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" ;; ;; Operand 1 is the address + 1 (+2 for HI), operand 0 is the result. (define_expand "unaligned_extendqidi" + [(use (match_operand:QI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_extendqidi_be (operands[0], operands[1])); + else + emit_insn (gen_unaligned_extendqidi_le (operands[0], operands[1])); + DONE; +}) + +(define_expand "unaligned_extendqidi_le" [(set (match_dup 2) (match_operand:DI 1 "address_operand" "")) (set (match_dup 3) (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -1)) @@ -1667,14 +1767,51 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (const_int 3))))) (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) (ashiftrt:DI (match_dup 4) (const_int 56)))] - "" + "! WORDS_BIG_ENDIAN" +{ + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}) + +(define_expand "unaligned_extendqidi_be" + [(set (match_dup 2) (match_operand:DI 1 "address_operand" "")) + (set (match_dup 3) (plus:DI (match_dup 2) (const_int -1))) + (set (match_dup 4) + (mem:DI (and:DI (match_dup 3) + (const_int -8)))) + (set (match_dup 5) (plus:DI (match_dup 2) (const_int -2))) + (set (match_dup 6) + (ashift:DI (match_dup 4) + (ashift:DI + (and:DI + (plus:DI (match_dup 5) (const_int 1)) + (const_int 7)) + (const_int 3)))) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (ashiftrt:DI (match_dup 6) (const_int 56)))] + "WORDS_BIG_ENDIAN" { operands[2] = gen_reg_rtx (DImode); operands[3] = gen_reg_rtx (DImode); operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); + operands[6] = gen_reg_rtx (DImode); }) (define_expand "unaligned_extendhidi" + [(use (match_operand:QI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_extendhidi_be (operands[0], operands[1])); + else + emit_insn (gen_unaligned_extendhidi_le (operands[0], operands[1])); + DONE; +}) + +(define_expand "unaligned_extendhidi_le" [(set (match_dup 2) (match_operand:DI 1 "address_operand" "")) (set (match_dup 3) (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -2)) @@ -1687,13 +1824,36 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (const_int 3))))) (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) (ashiftrt:DI (match_dup 4) (const_int 48)))] - "" + "! WORDS_BIG_ENDIAN" { operands[2] = gen_reg_rtx (DImode); operands[3] = gen_reg_rtx (DImode); operands[4] = gen_reg_rtx (DImode); }) +(define_expand "unaligned_extendhidi_be" + [(set (match_dup 2) (match_operand:DI 1 "address_operand" "")) + (set (match_dup 3) (plus:DI (match_dup 2) (const_int -2))) + (set (match_dup 4) + (mem:DI (and:DI (match_dup 3) + (const_int -8)))) + (set (match_dup 5) (plus:DI (match_dup 2) (const_int -3))) + (set (match_dup 6) + (ashift:DI (match_dup 4) + (ashift:DI + (and:DI (match_dup 5) (const_int 7)) + (const_int 8)))) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (ashiftrt:DI (match_dup 6) (const_int 48)))] + "WORDS_BIG_ENDIAN" +{ + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); + operands[6] = gen_reg_rtx (DImode); +}) + (define_insn "*extxl_const" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") @@ -1703,13 +1863,26 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" "ext%M2l %r1,%s3,%0" [(set_attr "type" "shift")]) -(define_insn "extxl" +(define_insn "extxl_le" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (match_operand:DI 2 "mode_width_operand" "n") (ashift:DI (match_operand:DI 3 "reg_or_8bit_operand" "rI") (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" + "ext%M2l %r1,%3,%0" + [(set_attr "type" "shift")]) + +(define_insn "extxl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (match_operand:DI 2 "mode_width_operand" "n") + (minus:DI + (const_int 56) + (ashift:DI + (match_operand:DI 3 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" "ext%M2l %r1,%3,%0" [(set_attr "type" "shift")]) @@ -1717,26 +1890,50 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" ;; in shifts larger than a word size. So capture these patterns that it ;; should have turned into zero_extracts. -(define_insn "*extxl_1" +(define_insn "*extxl_1_le" [(set (match_operand:DI 0 "register_operand" "=r") (and:DI (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))) (match_operand:DI 3 "mode_mask_operand" "n")))] - "" + "! WORDS_BIG_ENDIAN" "ext%U3l %1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "*extql_2" +(define_insn "*extxl_1_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (lshiftrt:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))) + (match_operand:DI 3 "mode_mask_operand" "n")))] + "WORDS_BIG_ENDIAN" + "ext%U3l %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "*extql_2_le" [(set (match_operand:DI 0 "register_operand" "=r") (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" "extql %1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "extqh" +(define_insn "*extql_2_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (minus:DI (const_int 56) + (ashift:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "extql %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extqh_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") @@ -1746,11 +1943,25 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 7)) (const_int 3)))))] - "" + "! WORDS_BIG_ENDIAN" "extqh %r1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "extlh" +(define_insn "extqh_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI + (and:DI + (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 1)) + (const_int 7)) + (const_int 3))))] + "WORDS_BIG_ENDIAN" + "extqh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extlh_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") @@ -1761,11 +1972,28 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 7)) (const_int 3)))))] - "" + "! WORDS_BIG_ENDIAN" + "extlh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extlh_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI + (ashift:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI + (and:DI + (plus:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 1)) + (const_int 7)) + (const_int 3))) + (const_int 2147483647)))] + "WORDS_BIG_ENDIAN" "extlh %r1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "extwh" +(define_insn "extwh_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") @@ -1776,7 +2004,23 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 7)) (const_int 3)))))] - "" + "! WORDS_BIG_ENDIAN" + "extwh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extwh_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI + (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI + (and:DI + (plus:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 1)) + (const_int 7)) + (const_int 3))) + (const_int 65535)))] + "WORDS_BIG_ENDIAN" "extwh %r1,%2,%0" [(set_attr "type" "shift")]) @@ -1830,39 +2074,79 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" "insll %1,%s2,%0" [(set_attr "type" "shift")]) -(define_insn "insbl" +(define_insn "insbl_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" + "insbl %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insbl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" "insbl %1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "inswl" +(define_insn "inswl_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r")) (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" "inswl %1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "insll" +(define_insn "inswl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r")) + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "inswl %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insll_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" "insll %1,%2,%0" [(set_attr "type" "shift")]) -(define_insn "insql" +(define_insn "insll_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "insll %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insql_le" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (match_operand:DI 1 "register_operand" "r") (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" + "insql %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insql_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "r") + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" "insql %1,%2,%0" [(set_attr "type" "shift")]) @@ -1913,7 +2197,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" "ins%M2h %1,%3,%0" [(set_attr "type" "shift")]) -(define_insn "mskxl" +(define_insn "mskxl_le" [(set (match_operand:DI 0 "register_operand" "=r") (and:DI (not:DI (ashift:DI (match_operand:DI 2 "mode_mask_operand" "n") @@ -1921,7 +2205,20 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 3 "reg_or_8bit_operand" "rI") (const_int 3)))) (match_operand:DI 1 "reg_or_0_operand" "rJ")))] - "" + "! WORDS_BIG_ENDIAN" + "msk%U2l %r1,%3,%0" + [(set_attr "type" "shift")]) + +(define_insn "mskxl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (not:DI (ashift:DI + (match_operand:DI 2 "mode_mask_operand" "n") + (minus:DI (const_int 56) + (ashift:DI + (match_operand:DI 3 "reg_or_8bit_operand" "rI") + (const_int 3))))) + (match_operand:DI 1 "reg_or_0_operand" "rJ")))] + "WORDS_BIG_ENDIAN" "msk%U2l %r1,%3,%0" [(set_attr "type" "shift")]) @@ -2328,6 +2625,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" operands[1] = force_reg (SFmode, operands[1]); }) +;; The Unicos/Mk assembler doesn't support cvtst, but we've already +;; asserted that alpha_fptm == ALPHA_FPTM_N. + (define_insn "*extendsfdf2_ieee" [(set (match_operand:DF 0 "register_operand" "=&f") (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] @@ -2341,7 +2641,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m,f")))] "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" "@ - fmov %1,%0 + cpys %1,%1,%0 ld%, %0,%1 st%- %1,%0" [(set_attr "type" "fcpys,fld,fst")]) @@ -4164,6 +4464,16 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" ;; Here are the CALL and unconditional branch insns. Calls on NT and OSF ;; work differently, so we have different patterns for each. +;; On Unicos/Mk a call information word (CIW) must be generated for each +;; call. The CIW contains information about arguments passed in registers +;; and is stored in the caller's SSIB. Its offset relative to the beginning +;; of the SSIB is passed in $25. Handling this properly is quite complicated +;; in the presence of inlining since the CIWs for calls performed by the +;; inlined function must be stored in the SSIB of the function it is inlined +;; into as well. We encode the CIW in an unspec and append it to the list +;; of the CIWs for the current function only when the instruction for loading +;; $25 is generated. + (define_expand "call" [(use (match_operand:DI 0 "" "")) (use (match_operand 1 "" "")) @@ -4175,6 +4485,8 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" emit_call_insn (gen_call_nt (operands[0], operands[1])); else if (TARGET_ABI_OPEN_VMS) emit_call_insn (gen_call_vms (operands[0], operands[2])); + else if (TARGET_ABI_UNICOSMK) + emit_call_insn (gen_call_umk (operands[0], operands[2])); else emit_call_insn (gen_call_osf (operands[0], operands[1])); DONE; @@ -4225,6 +4537,30 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" operands[0] = force_reg (DImode, operands[0]); }) +;; Calls on Unicos/Mk are always indirect. +;; op 0: symbol ref for called function +;; op 1: CIW for $25 represented by an unspec + +(define_expand "call_umk" + [(parallel [(call (mem:DI (match_operand 0 "" "")) + (match_operand 1 "" "")) + (use (reg:DI 25)) + (clobber (reg:DI 26))])] + "" +{ + if (GET_CODE (operands[0]) != MEM) + abort (); + + /* Always load the address of the called function into a register; + load the CIW in $25. */ + + operands[0] = XEXP (operands[0], 0); + if (GET_CODE (operands[0]) != REG) + operands[0] = force_reg (DImode, operands[0]); + + emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]); +}) + ;; ;; call openvms/alpha ;; op 0: symbol ref for called function @@ -4279,6 +4615,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" else if (TARGET_ABI_OPEN_VMS) emit_call_insn (gen_call_value_vms (operands[0], operands[1], operands[3])); + else if (TARGET_ABI_UNICOSMK) + emit_call_insn (gen_call_value_umk (operands[0], operands[1], + operands[3])); else emit_call_insn (gen_call_value_osf (operands[0], operands[1], operands[2])); @@ -4369,6 +4708,24 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" } }) +(define_expand "call_value_umk" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand 1 "" "")) + (match_operand 2 "" ""))) + (use (reg:DI 25)) + (clobber (reg:DI 26))])] + "" +{ + if (GET_CODE (operands[1]) != MEM) + abort (); + + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) != REG) + operands[1] = force_reg (DImode, operands[1]); + + emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]); +}) + (define_insn "*call_osf_1_er_noreturn" [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,i")) (match_operand 1 "" "")) @@ -4455,6 +4812,15 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" [(set_attr "type" "jsr") (set_attr "length" "12,16")]) +(define_insn "*call_umk_1" + [(call (mem:DI (match_operand:DI 0 "call_operand" "r")) + (match_operand 1 "" "")) + (use (reg:DI 25)) + (clobber (reg:DI 26))] + "TARGET_ABI_UNICOSMK" + "jsr $26,(%0)" + [(set_attr "type" "jsr")]) + ;; Call subroutine returning any type. (define_expand "untyped_call" @@ -4517,58 +4883,30 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" [(set_attr "type" "ibr")]) (define_expand "tablejump" - [(use (match_operand:SI 0 "register_operand" "")) - (use (match_operand:SI 1 "" ""))] + [(parallel [(set (pc) + (match_operand 0 "register_operand" "")) + (use (label_ref:DI (match_operand 1 "" "")))])] "" { if (TARGET_ABI_WINDOWS_NT) - emit_jump_insn (gen_tablejump_nt (operands[0], operands[1])); - else if (TARGET_ABI_OPEN_VMS) - emit_jump_insn (gen_tablejump_vms (operands[0], operands[1])); - else - emit_jump_insn (gen_tablejump_osf (operands[0], operands[1])); - - DONE; + { + rtx dest = gen_reg_rtx (DImode); + emit_insn (gen_extendsidi2 (dest, operands[0])); + operands[0] = dest; + } + else if (TARGET_ABI_OSF) + { + rtx dest = gen_reg_rtx (DImode); + emit_insn (gen_extendsidi2 (dest, operands[0])); + emit_insn (gen_adddi3 (dest, gen_rtx_REG (DImode, 29), dest)); + operands[0] = dest; + } }) -(define_expand "tablejump_osf" - [(set (match_dup 3) - (sign_extend:DI (match_operand:SI 0 "register_operand" ""))) - (set (match_dup 3) - (plus:DI (reg:DI 29) (match_dup 3))) - (parallel [(set (pc) - (match_dup 3)) - (use (label_ref (match_operand 1 "" "")))])] - "" - { operands[3] = gen_reg_rtx (DImode); }) - -(define_expand "tablejump_nt" - [(set (match_dup 3) - (sign_extend:DI (match_operand:SI 0 "register_operand" ""))) - (parallel [(set (pc) - (match_dup 3)) - (use (label_ref (match_operand 1 "" "")))])] - "" - { operands[3] = gen_reg_rtx (DImode); }) - -;; -;; tablejump, openVMS way -;; op 0: offset -;; op 1: label preceding jump-table -;; -(define_expand "tablejump_vms" - [(set (match_dup 2) - (match_operand:DI 0 "register_operand" "")) - (set (pc) - (plus:DI (match_dup 2) - (label_ref (match_operand 1 "" ""))))] - "" - { operands[2] = gen_reg_rtx (DImode); }) - (define_insn "*tablejump_osf_nt_internal" [(set (pc) (match_operand:DI 0 "register_operand" "r")) - (use (label_ref (match_operand 1 "" "")))] + (use (label_ref:DI (match_operand 1 "" "")))] "(TARGET_ABI_OSF || TARGET_ABI_WINDOWS_NT) && alpha_tablejump_addr_vec (insn)" { @@ -4577,16 +4915,11 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" } [(set_attr "type" "ibr")]) -;; -;; op 0 is table offset -;; op 1 is table label -;; - -(define_insn "*tablejump_vms_internal" +(define_insn "*tablejump_internal" [(set (pc) - (plus (match_operand:DI 0 "register_operand" "r") - (label_ref (match_operand 1 "" ""))))] - "TARGET_ABI_OPEN_VMS" + (match_operand:DI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" "jmp $31,(%0),0" [(set_attr "type" "ibr")]) @@ -4613,9 +4946,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], SFmode) || reg_or_fp0_operand (operands[1], SFmode))" "@ - fmov %R1,%0 + cpys %R1,%R1,%0 ld%, %0,%1 - mov %r1,%0 + bis $31,%r1,%0 ldl %0,%1 st%, %R1,%0 stl %r1,%0" @@ -4628,9 +4961,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], SFmode) || reg_or_fp0_operand (operands[1], SFmode))" "@ - fmov %R1,%0 + cpys %R1,%R1,%0 ld%, %0,%1 - mov %r1,%0 + bis $31,%r1,%0 ldl %0,%1 st%, %R1,%0 stl %r1,%0 @@ -4645,7 +4978,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], SFmode) || reg_or_fp0_operand (operands[1], SFmode))" "@ - mov %r1,%0 + bis $31,%r1,%0 ldl %0,%1 stl %r1,%0" [(set_attr "type" "ilog,ild,ist")]) @@ -4657,9 +4990,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], DFmode) || reg_or_fp0_operand (operands[1], DFmode))" "@ - fmov %R1,%0 + cpys %R1,%R1,%0 ld%- %0,%1 - mov %r1,%0 + bis $31,%r1,%0 ldq %0,%1 st%- %R1,%0 stq %r1,%0" @@ -4672,9 +5005,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], DFmode) || reg_or_fp0_operand (operands[1], DFmode))" "@ - fmov %R1,%0 + cpys %R1,%R1,%0 ld%- %0,%1 - mov %r1,%0 + bis $31,%r1,%0 ldq %0,%1 st%- %R1,%0 stq %r1,%0 @@ -4689,7 +5022,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], DFmode) || reg_or_fp0_operand (operands[1], DFmode))" "@ - mov %r1,%0 + bis $31,%r1,%0 ldq %0,%1 stq %r1,%0" [(set_attr "type" "ilog,ild,ist")]) @@ -4749,16 +5082,16 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (define_insn "*movsi_nofix" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,*f,*f,m") (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,*fJ,m,*f"))] - "TARGET_ABI_OSF && ! TARGET_FIX + "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK) && ! TARGET_FIX && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%1($31) ldah %0,%h1($31) ldl %0,%1 stl %r1,%0 - fmov %R1,%0 + cpys %R1,%R1,%0 ld%, %0,%1 st%, %R1,%0" [(set_attr "type" "ilog,iadd,iadd,ild,ist,fcpys,fld,fst")]) @@ -4770,12 +5103,12 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%1($31) ldah %0,%h1($31) ldl %0,%1 stl %r1,%0 - fmov %R1,%0 + cpys %R1,%R1,%0 ld%, %0,%1 st%, %R1,%0 ftois %1,%0 @@ -4789,13 +5122,13 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" "@ - mov %1,%0 + bis $31,%1,%0 lda %0,%1 ldah %0,%h1 lda %0,%1 ldl %0,%1 stl %r1,%0 - fmov %R1,%0 + cpys %R1,%R1,%0 ld%, %0,%1 st%, %R1,%0" [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")]) @@ -4807,7 +5140,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%L1($31)" [(set_attr "type" "ilog,iadd")]) @@ -4818,7 +5151,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], HImode) || reg_or_0_operand (operands[1], HImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%L1($31) ldwu %0,%1 stw %r1,%0" @@ -4831,7 +5164,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%L1($31)" [(set_attr "type" "ilog,iadd")]) @@ -4842,7 +5175,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%L1($31) ldbu %0,%1 stb %r1,%0" @@ -4879,6 +5212,87 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" FAIL; }) +;; Split the load of an address into a four-insn sequence on Unicos/Mk. +;; Always generate a REG_EQUAL note for the last instruction to facilitate +;; optimisations. If the symbolic operand is a label_ref, generate REG_LABEL +;; notes and update LABEL_NUSES because this is not done automatically. +;; Labels may be incorrectly deleted if we don't do this. +;; +;; Describing what the individual instructions do correctly is too complicated +;; so use UNSPECs for each of the three parts of an address. + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "symbolic_operand" ""))] + "TARGET_ABI_UNICOSMK && reload_completed" + [(const_int 0)] +{ + rtx insn1, insn2, insn3; + + insn1 = emit_insn (gen_umk_laum (operands[0], operands[1])); + emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32))); + insn2 = emit_insn (gen_umk_lalm (operands[0], operands[0], operands[1])); + insn3 = emit_insn (gen_umk_lal (operands[0], operands[0], operands[1])); + REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], + REG_NOTES (insn3)); + if (GET_CODE (operands[1]) == LABEL_REF) + { + rtx label; + + label = XEXP (operands[1], 0); + REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn1)); + REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn2)); + REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn3)); + LABEL_NUSES (label) += 3; + } + DONE; +}) + +;; Instructions for loading the three parts of an address on Unicos/Mk. + +(define_insn "umk_laum" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_UMK_LAUM))] + "TARGET_ABI_UNICOSMK" + "laum %r0,%t1($31)" + [(set_attr "type" "iadd")]) + +(define_insn "umk_lalm" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_UMK_LALM)))] + "TARGET_ABI_UNICOSMK" + "lalm %r0,%t2(%r1)" + [(set_attr "type" "iadd")]) + +(define_insn "umk_lal" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_UMK_LAL)))] + "TARGET_ABI_UNICOSMK" + "lal %r0,%t2(%r1)" + [(set_attr "type" "iadd")]) + +;; Add a new call information word to the current function's list of CIWs +;; and load its index into $25. Doing it here ensures that the CIW will be +;; associated with the correct function even in the presence of inlining. + +(define_insn "*umk_load_ciw" + [(set (reg:DI 25) + (unspec:DI [(match_operand 0 "" "")] UNSPEC_UMK_LOAD_CIW))] + "TARGET_ABI_UNICOSMK" +{ + operands[0] = unicosmk_add_call_info_word (operands[0]); + return "lda $25,%0"; +} + [(set_attr "type" "iadd")]) + (define_insn "*movdi_er_low" [(set (match_operand:DI 0 "register_operand" "=r") (lo_sum:DI (match_operand:DI 1 "register_operand" "r") @@ -4906,23 +5320,29 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" stt %R1,%0" [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")]) +;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should +;; have been split up by the rules above but we shouldn't reject the +;; possibility of them getting through. + (define_insn "*movdi_nofix" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q") - (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f"))] - "! TARGET_EXPLICIT_RELOCS && ! TARGET_FIX + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q") + (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,m,rJ,*fJ,Q,*f"))] + "! TARGET_FIX && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%1($31) ldah %0,%h1($31) + laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0) lda %0,%1 ldq%A1 %0,%1 stq%A0 %r1,%0 - fmov %R1,%0 + cpys %R1,%R1,%0 ldt %0,%1 stt %R1,%0" - [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")]) + [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,ild,ist,fcpys,fld,fst") + (set_attr "length" "*,*,*,16,*,*,*,*,*,*")]) (define_insn "*movdi_er_fix" [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f") @@ -4953,13 +5373,13 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" "@ - mov %r1,%0 + bis $31,%r1,%0 lda %0,%1($31) ldah %0,%h1($31) lda %0,%1 ldq%A1 %0,%1 stq%A0 %r1,%0 - fmov %R1,%0 + cpys %R1,%R1,%0 ldt %0,%1 stt %R1,%0 ftoit %1,%0 @@ -5041,12 +5461,29 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" "") ;; Similar for unaligned loads, where we use the sequence from the -;; Alpha Architecture manual. +;; Alpha Architecture manual. We have to distinguish between little-endian +;; and big-endian systems as the sequences are different. ;; ;; Operand 1 is the address. Operands 2 and 3 are temporaries, where ;; operand 3 can overlap the input and output registers. (define_expand "unaligned_loadqi" + [(use (match_operand:QI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_loadqi_be (operands[0], operands[1], + operands[2], operands[3])); + else + emit_insn (gen_unaligned_loadqi_le (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_expand "unaligned_loadqi_le" [(set (match_operand:DI 2 "register_operand" "") (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") (const_int -8)))) @@ -5056,10 +5493,41 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (zero_extract:DI (match_dup 2) (const_int 8) (ashift:DI (match_dup 3) (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_loadqi_be" + [(set (match_operand:DI 2 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 3 "register_operand" "") + (match_dup 1)) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (zero_extract:DI (match_dup 2) + (const_int 8) + (minus:DI + (const_int 56) + (ashift:DI (match_dup 3) (const_int 3)))))] + "WORDS_BIG_ENDIAN" "") (define_expand "unaligned_loadhi" + [(use (match_operand:QI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_loadhi_be (operands[0], operands[1], + operands[2], operands[3])); + else + emit_insn (gen_unaligned_loadhi_le (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_expand "unaligned_loadhi_le" [(set (match_operand:DI 2 "register_operand" "") (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") (const_int -8)))) @@ -5069,7 +5537,22 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (zero_extract:DI (match_dup 2) (const_int 16) (ashift:DI (match_dup 3) (const_int 3))))] - "" + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_loadhi_be" + [(set (match_operand:DI 2 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 3 "register_operand" "") + (plus:DI (match_dup 1) (const_int 1))) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (zero_extract:DI (match_dup 2) + (const_int 16) + (minus:DI + (const_int 56) + (ashift:DI (match_dup 3) (const_int 3)))))] + "WORDS_BIG_ENDIAN" "") ;; Storing an aligned byte or word requires two temporaries. Operand 0 is the @@ -5102,6 +5585,25 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" ;; operand 2 can be that register. (define_expand "unaligned_storeqi" + [(use (match_operand:DI 0 "address_operand" "")) + (use (match_operand:QI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" "")) + (use (match_operand:DI 4 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_storeqi_be (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + else + emit_insn (gen_unaligned_storeqi_le (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + DONE; +}) + +(define_expand "unaligned_storeqi_le" [(set (match_operand:DI 3 "register_operand" "") (mem:DI (and:DI (match_operand:DI 0 "address_operand" "") (const_int -8)))) @@ -5117,10 +5619,50 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3))) (set (mem:DI (and:DI (match_dup 0) (const_int -8))) (match_dup 4))] - "" + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_storeqi_be" + [(set (match_operand:DI 3 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 0 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 2 "register_operand" "") + (match_dup 0)) + (set (match_dup 3) + (and:DI (not:DI (ashift:DI (const_int 255) + (minus:DI (const_int 56) + (ashift:DI (match_dup 2) (const_int 3))))) + (match_dup 3))) + (set (match_operand:DI 4 "register_operand" "") + (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "")) + (minus:DI (const_int 56) + (ashift:DI (match_dup 2) (const_int 3))))) + (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3))) + (set (mem:DI (and:DI (match_dup 0) (const_int -8))) + (match_dup 4))] + "WORDS_BIG_ENDIAN" "") (define_expand "unaligned_storehi" + [(use (match_operand:DI 0 "address_operand" "")) + (use (match_operand:HI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" "")) + (use (match_operand:DI 4 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_storehi_be (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + else + emit_insn (gen_unaligned_storehi_le (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + DONE; +}) + +(define_expand "unaligned_storehi_le" [(set (match_operand:DI 3 "register_operand" "") (mem:DI (and:DI (match_operand:DI 0 "address_operand" "") (const_int -8)))) @@ -5136,7 +5678,29 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3))) (set (mem:DI (and:DI (match_dup 0) (const_int -8))) (match_dup 4))] - "" + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_storehi_be" + [(set (match_operand:DI 3 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 0 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 2 "register_operand" "") + (plus:DI (match_dup 0) (const_int 1))) + (set (match_dup 3) + (and:DI (not:DI (ashift:DI + (const_int 65535) + (minus:DI (const_int 56) + (ashift:DI (match_dup 2) (const_int 3))))) + (match_dup 3))) + (set (match_operand:DI 4 "register_operand" "") + (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "")) + (minus:DI (const_int 56) + (ashift:DI (match_dup 2) (const_int 3))))) + (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3))) + (set (mem:DI (and:DI (match_dup 0) (const_int -8))) + (match_dup 4))] + "WORDS_BIG_ENDIAN" "") ;; Here are the define_expand's for QI and HI moves that use the above @@ -5356,6 +5920,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" { rtx aligned_mem, bitnum; get_aligned_mem (operands[1], &aligned_mem, &bitnum); + emit_insn (gen_aligned_loadqi (operands[0], aligned_mem, bitnum, operands[2])); DONE; @@ -5370,6 +5935,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" { rtx aligned_mem, bitnum; get_aligned_mem (operands[1], &aligned_mem, &bitnum); + emit_insn (gen_aligned_loadhi (operands[0], aligned_mem, bitnum, operands[2])); DONE; @@ -5414,6 +5980,8 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 3 "immediate_operand" "")))] "" { + int ofs; + /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */ if (INTVAL (operands[3]) % 8 != 0 || (INTVAL (operands[2]) != 16 @@ -5426,9 +5994,21 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" if (GET_CODE (operands[1]) != MEM) FAIL; + /* The bit number is relative to the mode of operand 1 which is + usually QImode (this might actually be a bug in expmed.c). Note + that the bit number is negative in big-endian mode in this case. + We have to convert that to the offset. */ + if (WORDS_BIG_ENDIAN) + ofs = GET_MODE_BITSIZE (GET_MODE (operands[1])) + - INTVAL (operands[2]) - INTVAL (operands[3]); + else + ofs = INTVAL (operands[3]); + + ofs = ofs / 8; + alpha_expand_unaligned_load (operands[0], operands[1], INTVAL (operands[2]) / 8, - INTVAL (operands[3]) / 8, 1); + ofs, 1); DONE; }) @@ -5449,13 +6029,27 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" if (GET_CODE (operands[1]) == MEM) { + int ofs; + /* Fail 8 bit fields, falling back on a simple byte load. */ if (INTVAL (operands[2]) == 8) FAIL; + /* The bit number is relative to the mode of operand 1 which is + usually QImode (this might actually be a bug in expmed.c). Note + that the bit number is negative in big-endian mode in this case. + We have to convert that to the offset. */ + if (WORDS_BIG_ENDIAN) + ofs = GET_MODE_BITSIZE (GET_MODE (operands[1])) + - INTVAL (operands[2]) - INTVAL (operands[3]); + else + ofs = INTVAL (operands[3]); + + ofs = ofs / 8; + alpha_expand_unaligned_load (operands[0], operands[1], INTVAL (operands[2]) / 8, - INTVAL (operands[3]) / 8, 0); + ofs, 0); DONE; } }) @@ -5467,6 +6061,8 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 3 "register_operand" ""))] "" { + int ofs; + /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */ if (INTVAL (operands[2]) % 8 != 0 || (INTVAL (operands[1]) != 16 @@ -5479,9 +6075,20 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" if (GET_CODE (operands[0]) != MEM) FAIL; + /* The bit number is relative to the mode of operand 1 which is + usually QImode (this might actually be a bug in expmed.c). Note + that the bit number is negative in big-endian mode in this case. + We have to convert that to the offset. */ + if (WORDS_BIG_ENDIAN) + ofs = GET_MODE_BITSIZE (GET_MODE (operands[0])) + - INTVAL (operands[1]) - INTVAL (operands[2]); + else + ofs = INTVAL (operands[2]); + + ofs = ofs / 8; + alpha_expand_unaligned_store (operands[0], operands[3], - INTVAL (operands[1]) / 8, - INTVAL (operands[2]) / 8); + INTVAL (operands[1]) / 8, ofs); DONE; }) @@ -5675,7 +6282,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" (match_operand:DI 1 "register_operand" "r")) (clobber (mem:BLK (match_operand:DI 2 "register_operand" "=r")))] "" - "mov %1,%0") + "bis $31,%1,%0") (define_expand "epilogue" [(return)] @@ -5836,6 +6443,58 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" [(set_attr "length" "16") (set_attr "type" "multi")]) +;; Load the CIW into r2 for calling __T3E_MISMATCH + +(define_expand "umk_mismatch_args" + [(set:DI (match_dup 1) (mem:DI (plus:DI (reg:DI 15) (const_int -16)))) + (set:DI (match_dup 2) (mem:DI (plus:DI (match_dup 1) (const_int -32)))) + (set:DI (reg:DI 1) (match_operand:DI 0 "const_int_operand" "")) + (set:DI (match_dup 3) (plus:DI (mult:DI (reg:DI 25) + (const_int 8)) + (match_dup 2))) + (set:DI (reg:DI 2) (mem:DI (match_dup 3)))] + "TARGET_ABI_UNICOSMK" +{ + operands[1] = gen_reg_rtx (DImode); + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); +}) + +(define_insn "arg_home_umk" + [(unspec [(const_int 0)] UNSPEC_ARG_HOME) + (use (reg:DI 1)) + (use (reg:DI 2)) + (use (reg:DI 16)) + (use (reg:DI 17)) + (use (reg:DI 18)) + (use (reg:DI 19)) + (use (reg:DI 20)) + (use (reg:DI 21)) + (use (reg:DI 48)) + (use (reg:DI 49)) + (use (reg:DI 50)) + (use (reg:DI 51)) + (use (reg:DI 52)) + (use (reg:DI 53)) + (clobber (mem:BLK (const_int 0))) + (parallel [ + (clobber (reg:DI 22)) + (clobber (reg:DI 23)) + (clobber (reg:DI 24)) + (clobber (reg:DI 0)) + (clobber (reg:DI 1)) + (clobber (reg:DI 2)) + (clobber (reg:DI 3)) + (clobber (reg:DI 4)) + (clobber (reg:DI 5)) + (clobber (reg:DI 6)) + (clobber (reg:DI 7)) + (clobber (reg:DI 8))])] + "TARGET_ABI_UNICOSMK" + "laum $4,__T3E_MISMATCH($31)\;sll $4,32,$4\;lalm $4,__T3E_MISMATCH($4)\;lal $4,__T3E_MISMATCH($4)\;jsr $3,($4)" + [(set_attr "length" "16") + (set_attr "type" "multi")]) + ;; Close the trap shadow of preceeding instructions. This is generated ;; by alpha_reorg. @@ -5847,33 +6506,51 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi" ;; No-op instructions used by machine-dependant reorg to preserve ;; alignment for instruction issue. +;; The Unicos/Mk assembler does not support these opcodes. (define_insn "nop" [(const_int 0)] "" - "nop" + "bis $31,$31,$31" [(set_attr "type" "ilog")]) (define_insn "fnop" [(const_int 1)] "TARGET_FP" - "fnop" + "cpys $f31,$f31,$f31" [(set_attr "type" "fcpys")]) (define_insn "unop" [(const_int 2)] "" - "unop") + "ldq_u $31,($31)") + +;; On Unicos/Mk we use a macro for aligning code. (define_insn "realign" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNSPECV_REALIGN)] "" - ".align %0 #realign") +{ + if (TARGET_ABI_UNICOSMK) + return "gcc@code@align %0"; + else + return ".align %0 #realign"; +}) ;; The call patterns are at the end of the file because their ;; wildcard operand0 interferes with nice recognition. +(define_insn "*call_value_umk" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "r")) + (match_operand 2 "" ""))) + (use (reg:DI 25)) + (clobber (reg:DI 26))] + "TARGET_ABI_UNICOSMK" + "jsr $26,(%1)" + [(set_attr "type" "jsr")]) + (define_insn "*call_value_osf_1_er" [(set (match_operand 0 "" "") (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,i")) diff --git a/gcc/config/alpha/t-unicosmk b/gcc/config/alpha/t-unicosmk new file mode 100644 index 0000000..9c52b98 --- /dev/null +++ b/gcc/config/alpha/t-unicosmk @@ -0,0 +1,2 @@ +# This file is empty for now. + diff --git a/gcc/config/alpha/unicosmk.h b/gcc/config/alpha/unicosmk.h new file mode 100644 index 0000000..6ecc3d2 --- /dev/null +++ b/gcc/config/alpha/unicosmk.h @@ -0,0 +1,667 @@ +/* Definitions of target machine for GNU compiler, for DEC Alpha on Cray + T3E running Unicos/Mk. + Copyright (C) 2001 + Free Software Foundation, Inc. + Contributed by Roman Lechtchinsky (rl@cs.tu-berlin.de) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#undef TARGET_ABI_UNICOSMK +#define TARGET_ABI_UNICOSMK 1 + +/* CAM requires a slash before floating-pointing instruction suffixes. */ + +#undef TARGET_AS_SLASH_BEFORE_SUFFIX +#define TARGET_AS_SLASH_BEFORE_SUFFIX 1 + +/* The following defines are necessary for the standard headers to work + correctly. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__unix=1 -D_UNICOS=205 -D_CRAY=1 -D_CRAYT3E=1 -D_CRAYMPP=1 -D_CRAYIEEE=1 -D_ADDR64=1 -D_LD64=1 -D__UNICOSMK__ -D__INT_MAX__=9223372036854775807 -D__SHRT_MAX__=2147483647" + +/* Disable software floating point emulation because it requires a 16-bit + type which we do not have. */ + +#ifndef __GNUC__ +#undef REAL_ARITHMETIC +#endif + +#define SHORT_TYPE_SIZE 32 + +#undef INT_TYPE_SIZE +#define INT_TYPE_SIZE 64 + +/* This is consistent with the definition Cray CC uses. */ +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 64 + +/* +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +*/ + +/* Alphas are operated in big endian mode on the Cray T3E. */ + +#undef BITS_BIG_ENDIAN +#undef BYTES_BIG_ENDIAN +#undef WORDS_BIG_ENDIAN +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN 1 +#define WORDS_BIG_ENDIAN 1 + + +/* Every structure's size must be a multiple of this. */ + +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 64 + +/* Allocation boundary (in *bits*) for the code of a function. Functions + should be cache-aligned on the T3E. */ + +#undef FUNCTION_BOUNDARY +#define FUNCTION_BOUNDARY 256 + +/* No data type wants to be aligned rounder than this. */ + +#undef BIGGEST_ALIGNMENT +#define BIGGEST_ALIGNMENT 256 + +/* Include the frame pointer in fixed_regs and call_used_regs as it can't be + used as a general-purpose register even in frameless functions. + ??? The global_regs hack is needed for now because -O2 sometimes tries to + eliminate $15 increments/decrements in frameless functions. */ + +#undef CONDITIONAL_REGISTER_USAGE +#define CONDITIONAL_REGISTER_USAGE \ + do { \ + fixed_regs[15] = 1; \ + call_used_regs[15] = 1; \ + global_regs[15] = 1; \ + } while(0) + +/* The stack frame grows downward. */ + +#define FRAME_GROWS_DOWNWARD + +/* Define the offset between two registers, one to be eliminated, and the + other its replacement, at the start of a routine. This is somewhat + complicated on the T3E which is why we use a function. */ + +extern int unicosmk_initial_elimination_offset PARAMS ((int, int)); + +#undef INITIAL_ELIMINATION_OFFSET +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + do { \ + (OFFSET) = unicosmk_initial_elimination_offset ((FROM), (TO)); \ + } while (0) + + +/* Define this if stack space is still allocated for a parameter passed + in a register. On the T3E, stack space is preallocated for all outgoing + arguments, including those passed in registers. To avoid problems, we + assume that at least 48 bytes (i.e. enough space for all arguments passed + in registers) are allocated. */ + +#define REG_PARM_STACK_SPACE(DECL) 48 +#define OUTGOING_REG_PARM_STACK_SPACE + +/* If an argument can't be passed in registers even though not all argument + registers have been used yet, it is passed on the stack in the space + preallocated for these registers. */ + +#define STACK_PARMS_IN_REG_PARM_AREA + +/* This evaluates to nonzero if we do not know how to pass TYPE solely in + registers. This is the case for all arguments that do not fit in two + registers. */ + +#define MUST_PASS_IN_STACK(MODE,TYPE) \ + ((TYPE) != 0 \ + && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \ + || (TREE_ADDRESSABLE (TYPE) || ALPHA_ARG_SIZE (MODE, TYPE, 0) > 2))) + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On Unicos/Mk, this is a structure that contains various information for + the static subroutine information block (SSIB) and the call information + word (CIW). */ + +typedef struct { + + /* The overall number of arguments. */ + int num_args; + + /* The overall size of the arguments in words. */ + int num_arg_words; + + /* The number of words passed in registers. */ + int num_reg_words; + + /* If an argument must be passed in the stack, all subsequent arguments + must be passed there, too. This flag indicates whether this is the + case. */ + int force_stack; + + /* This array indicates whether a word is passed in an integer register or + a floating point one. */ + + /* For each of the 6 register arguments, the corresponding flag in this + array indicates whether the argument is passed in an integer or a + floating point register. */ + int reg_args_type[6]; + +} unicosmk_arg_info; + +#undef CUMULATIVE_ARGS +#define CUMULATIVE_ARGS unicosmk_arg_info + +/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a + function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ + +#undef INIT_CUMULATIVE_ARGS +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \ + do { (CUM).num_args = 0; \ + (CUM).num_arg_words = 0; \ + (CUM).num_reg_words = 0; \ + (CUM).force_stack = 0; \ + } while(0) + +/* Update the data in CUM to advance over an argument of mode MODE and data + type TYPE. (TYPE is null for libcalls where that information may not be + available.) + + On Unicos/Mk, at most 6 words can be passed in registers. Structures + which fit in two words are passed in registers, larger structures are + passed on stack. */ + +#undef FUNCTION_ARG_ADVANCE +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ +do { \ + int size; \ + \ + size = ALPHA_ARG_SIZE (MODE, TYPE, NAMED); \ + \ + if (size > 2 || MUST_PASS_IN_STACK (MODE, TYPE) \ + || (CUM).num_reg_words + size > 6) \ + (CUM).force_stack = 1; \ + \ + if (! (CUM).force_stack) \ + { \ + int i; \ + int isfloat; \ + isfloat = (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT); \ + for (i = 0; i < size; i++) \ + { \ + (CUM).reg_args_type[(CUM).num_reg_words] = isfloat; \ + ++(CUM).num_reg_words; \ + } \ + } \ + (CUM).num_arg_words += size; \ + ++(CUM).num_args; \ +} while(0) + +/* We want the default definition for this. + ??? In fact, we should delete the definition from alpha.h as it + corresponds to the default definition for little-endian machines. */ + +#undef FUNCTION_ARG_PADDING + +/* An argument is passed either entirely in registers or entirely on stack. */ + +#undef FUNCTION_ARG_PARTIAL_NREGS +/* #define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) 0 */ + +/* Perform any needed actions needed for a function that is receiving a + variable number of arguments. + + On Unicos/Mk, the standard subroutine __T3E_MISMATCH stores all register + arguments on the stack. Unfortunately, it doesn't always store the first + one (i.e. the one that arrives in $16 or $f16). This is not a problem + with stdargs as we always have at least one named argument there. This is + not always the case when varargs.h is used, however. In such cases, we + have to store the first argument ourselves. We use the information from + the CIW to determine whether the first argument arrives in $16 or $f16. */ + +#undef SETUP_INCOMING_VARARGS +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ +{ if ((CUM).num_reg_words < 6) \ + { \ + if (! (NO_RTL)) \ + { \ + int start; \ + \ + start = (CUM).num_reg_words; \ + if (!current_function_varargs || start == 0) \ + ++start; \ + \ + emit_insn (gen_umk_mismatch_args (GEN_INT (start))); \ + if (current_function_varargs && (CUM).num_reg_words == 0) \ + { \ + rtx tmp; \ + rtx int_label, end_label; \ + \ + tmp = gen_reg_rtx (DImode); \ + emit_move_insn (tmp, \ + gen_rtx_ZERO_EXTRACT (DImode, \ + gen_rtx_REG (DImode, 2),\ + (GEN_INT (1)), \ + (GEN_INT (7)))); \ + int_label = gen_label_rtx (); \ + end_label = gen_label_rtx (); \ + emit_insn (gen_cmpdi (tmp, GEN_INT (0))); \ + emit_jump_insn (gen_beq (int_label)); \ + emit_move_insn (gen_rtx_MEM (DFmode, virtual_incoming_args_rtx),\ + gen_rtx_REG (DFmode, 48)); \ + emit_jump (end_label); \ + emit_label (int_label); \ + emit_move_insn (gen_rtx_MEM (DImode, virtual_incoming_args_rtx),\ + gen_rtx_REG (DImode, 16)); \ + emit_label (end_label); \ + } \ + emit_insn (gen_arg_home_umk ()); \ + } \ + \ + PRETEND_SIZE = 0; \ + } \ +} + +/* This ensures that $15 increments/decrements in leaf functions won't get + eliminated. */ + +#undef EPILOGUE_USES +#define EPILOGUE_USES(REGNO) ((REGNO) == 26 || (REGNO) == 15) + +/* Machine-specific function data. */ + +struct machine_function +{ + /* List of call information words for calls from this function. */ + struct rtx_def *first_ciw; + struct rtx_def *last_ciw; + int ciw_count; + + /* List of deferred case vectors. */ + struct rtx_def *addr_list; +}; + +/* Would have worked, only the stack doesn't seem to be executable +#undef TRAMPOLINE_TEMPLATE +#define TRAMPOLINE_TEMPLATE(FILE) \ +do { fprintf (FILE, "\tbr $1,0\n"); \ + fprintf (FILE, "\tldq $0,12($1)\n"); \ + fprintf (FILE, "\tldq $1,20($1)\n"); \ + fprintf (FILE, "\tjmp $31,(r0)\n"); \ + fprintf (FILE, "\tbis $31,$31,$31\n"); \ + fprintf (FILE, "\tbis $31,$31,$31\n"); \ +} while (0) */ + +/* We don't support nested functions (yet). */ + +#undef TRAMPOLINE_TEMPLATE +#define TRAMPOLINE_TEMPLATE(FILE) abort () + +/* Specify the machine mode that this machine uses for the index in the + tablejump instruction. On Unicos/Mk, we don't support relative case + vectors yet, thus the entries should be absolute addresses. */ + +#undef CASE_VECTOR_MODE +#define CASE_VECTOR_MODE DImode + +#undef CASE_VECTOR_PC_RELATIVE + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +/* #define DEFAULT_SIGNED_CHAR 1 */ + +/* The Cray assembler is really weird with respect to sections. It has only + named sections and you can't reopen a section once it has been closed. + This means that we have to generate unique names whenever we want to + reenter the text or the data section. The following is a rather bad hack + as TEXT_SECTION_ASM_OP and DATA_SECTION_ASM_OP are supposed to be + constants. */ + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP unicosmk_text_section () + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP unicosmk_data_section () + +/* There are ni read-only sections on Unicos/Mk. */ + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION data_section + +/* Define extra sections for common data and SSIBs (static subroutine + information blocks). The actual section header is output by the callers + of these functions. */ + +#undef EXTRA_SECTIONS +#undef EXTRA_SECTION_FUNCTIONS + +#define EXTRA_SECTIONS in_common, in_ssib +#define EXTRA_SECTION_FUNCTIONS \ +COMMON_SECTION \ +SSIB_SECTION + +#define COMMON_SECTION \ +void \ +common_section () \ +{ \ + in_section = in_common; \ +} + +#define SSIB_SECTION \ +void \ +ssib_section () \ +{ \ + in_section = in_ssib; \ +} + +/* A C expression which evaluates to true if declshould be placed into a + unique section for some target-specific reason. On Unicos/Mk, functions + and public variables are always placed in unique sections. */ + +/* +#define UNIQUE_SECTION_P(DECL) (TREE_PUBLIC (DECL) \ + || TREE_CODE (DECL) == FUNCTION_DECL) +*/ +#define UNIQUE_SECTION(DECL, RELOC) unicosmk_unique_section (DECL, RELOC) + +/* This outputs text to go at the start of an assembler file. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) unicosmk_asm_file_start (FILE) + +/* This outputs text to go at the end of an assembler file. */ + +#undef ASM_FILE_END +#define ASM_FILE_END(FILE) unicosmk_asm_file_end (FILE) + +/* We take care of that in ASM_FILE_START. */ + +#undef ASM_OUTPUT_SOURCE_FILENAME + +/* There is no directive for declaring a label as global. Instead, an + additional colon must be appended when the label is defined. */ + +#undef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(FILE,NAME) + +/* This is how to output a label for a jump table. Arguments are the same as + for ASM_OUTPUT_INTERNAL_LABEL, except the insn for the jump table is + passed. */ + +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN) \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#ifdef REAL_ARITHMETIC +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { long t[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \ + fprintf (FILE, "\t.quad ^X%lx%08lx\n", \ + t[0] & 0xffffffff, t[1] & 0xffffffff); \ + } while (0) +#else +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { long t[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \ + fprintf (FILE, "\t.quad ^X%x\n", t[0]); \ + } while(0) +#endif + + +/* This is how to output an assembler line defining a `long double' + constant. `long double' and `double' are the same on the Cray T3E. */ + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ + ASM_OUTPUT_DOUBLE (FILE,VALUE) + +/* This is how to output an assembler line defining a `float' constant. + ??? Somehow, REAL_VALUE_TO_TARGET_SINGLE gets confused and returns the + value in the upper bits of the int. */ + +#undef ASM_OUTPUT_FLOAT +#ifdef REAL_ARITHMETIC +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { long t; \ + REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \ + fprintf (FILE, "\t.long ^X%x\n", t & 0xffffffff);\ + } while (0) +#else +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { long t; \ + REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \ + fprintf (FILE, "\t.long ^X%x\n", (t >> 32) & 0xffffffff);\ + } while(0) +#endif + +/* CAM has some restrictions with respect to string literals. It won't + accept lines with more that 256 characters which means that we have + to split long strings. Moreover, it only accepts escape sequences of + the form \nnn in the range 0 to 127. We generate .byte directives for + escapes characters greater than 127. And finally, ` must be escaped. */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(MYFILE, MYSTRING, MYLENGTH) \ + do { \ + FILE *_hide_asm_out_file = (MYFILE); \ + const unsigned char *_hide_p = (const unsigned char *) (MYSTRING); \ + int _hide_thissize = (MYLENGTH); \ + int _size_so_far = 0; \ + { \ + FILE *asm_out_file = _hide_asm_out_file; \ + const unsigned char *p = _hide_p; \ + int thissize = _hide_thissize; \ + int in_ascii = 0; \ + int i; \ + \ + for (i = 0; i < thissize; i++) \ + { \ + register int c = p[i]; \ + \ + if (c > 127) \ + { \ + if (in_ascii) \ + { \ + fprintf (asm_out_file, "\"\n"); \ + in_ascii = 0; \ + } \ + \ + fprintf (asm_out_file, "\t.byte\t%d\n", c); \ + } \ + else \ + { \ + if (! in_ascii) \ + { \ + fprintf (asm_out_file, "\t.ascii\t\""); \ + in_ascii = 1; \ + _size_so_far = 0; \ + } \ + else if (_size_so_far >= 64) \ + { \ + fprintf (asm_out_file, "\"\n\t.ascii\t\""); \ + _size_so_far = 0; \ + } \ + \ + if (c == '\"' || c == '\\' || c == '`') \ + putc ('\\', asm_out_file); \ + if (c >= ' ') \ + putc (c, asm_out_file); \ + else \ + fprintf (asm_out_file, "\\%.3o", c); \ + ++ _size_so_far; \ + } \ + } \ + if (in_ascii) \ + fprintf (asm_out_file, "\"\n"); \ + } \ + } while(0) + +/* This is how to output an element of a case-vector that is absolute. */ + +#undef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.quad $L%d\n", (VALUE)) + +/* This is how to output an element of a case-vector that is relative. + (Unicos/Mk does not use such vectors yet). */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) abort () + +/* We can't output case vectors in the same section as the function code + because CAM doesn't allow data definitions in code sections. Thus, we + simply record the case vectors and put them in a separate section after + the function. */ + +#define ASM_OUTPUT_ADDR_VEC(LAB,VEC) \ + unicosmk_defer_case_vector ((LAB),(VEC)) + +#define ASM_OUTPUT_ADDR_DIFF_VEC(LAB,VEC) abort () + +/* This is how to output an assembler line that says to advance the location + counter to a multiple of 2**LOG bytes. Annoyingly, CAM always uses zeroes + to fill the unused space which does not work in code sections. We have to + be careful not to use the .align directive in code sections. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(STREAM,LOG) unicosmk_output_align (STREAM, LOG) + +/* This is how to advance the location counter by SIZE bytes. */ + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(STREAM,SIZE) \ + fprintf ((STREAM), "\t.byte\t0:%d\n", (SIZE)); + +/* This says how to output an assembler line to define a global common + symbol. We need the alignment information because it has to be supplied + in the section header. */ + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ + unicosmk_output_common ((FILE), (NAME), (SIZE), (ALIGN)) + +/* This says how to output an assembler line to define a local symbol. */ + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ + do { data_section (); \ + fprintf (FILE, "\t.align\t%d\n", floor_log2 ((ALIGN) / BITS_PER_UNIT));\ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf (FILE, "\t.byte 0:%d\n", SIZE); \ + } while (0) + +/* CAM does not allow us to declare a symbol as external first and then + define it in the same file later. Thus, we keep a list of all external + references, remove all symbols defined locally from it and output it at + the end of the asm file. */ + +#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) \ + unicosmk_add_extern ((NAME)) + +#define ASM_OUTPUT_EXTERNAL_LIBCALL(STREAM,SYMREF) \ + unicosmk_add_extern (XSTR ((SYMREF), 0)) + +/* This is how to declare an object. We don't have to output anything if + it is a global variable because those go into unique `common' sections + and the section name is globally visible. For local variables, we simply + output the label. In any case, we have to record that no extern + declaration should be generated for the symbol. */ + +#define ASM_DECLARE_OBJECT_NAME(STREAM,NAME,DECL) \ + do { tree name_tree; \ + name_tree = get_identifier ((NAME)); \ + TREE_ASM_WRITTEN (name_tree) = 1; \ + if (!TREE_PUBLIC (DECL)) \ + { \ + assemble_name (STREAM, NAME); \ + fputs (":\n", STREAM); \ + } \ + } while(0) + +/* +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ + unicosmk_output_section_name ((STREAM), (DECL), (NAME), (RELOC)) +*/ + +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION unicosmk_asm_named_section + +#undef ASM_OUTPUT_MAX_SKIP_ALIGN +#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM,POWER,MAXSKIP) + +/* We have to define these because we do not use the floating-point + emulation. Unfortunately, atof does not accept hex literals. */ + +#ifndef REAL_ARITHMETIC +#define REAL_VALUE_ATOF(x,s) atof(x) +#define REAL_VALUE_HTOF(x,s) atof(x) +#endif + +#undef NM_FLAGS + +#undef OBJECT_FORMAT_COFF + +/* We cannot generate debugging information on Unicos/Mk. */ + +#undef SDB_DEBUGGING_INFO +#undef MIPS_DEBUGGING_INFO +#undef DBX_DEBUGGING_INFO +#undef DWARF_DEBUGGING_INFO +#undef DWARF2_DEBUGGING_INFO +#undef DWARF2_UNWIND_INFO +#undef INCOMING_RETURN_ADDR_RTX + + +/* We use the functions provided by the system library for integer + division. */ + +#undef UDIVDI3_LIBCALL +#undef DIVDI3_LIBCALL +#define UDIVDI3_LIBCALL "$uldiv" +#define DIVDI3_LIBCALL "$sldiv" + +#undef ASM_OUTPUT_SOURCE_LINE + +/* We don't need a start file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "" + +/* These are the libraries we have to link with. + ??? The Craylibs directory should be autoconfed. */ +#undef LIB_SPEC +#define LIB_SPEC "-L/opt/ctl/craylibs/craylibs -lu -lm -lc -lsma" + +#undef BUILD_VA_LIST_TYPE +#undef EXPAND_BUILTIN_VA_START +#undef EXPAND_BUILTIN_VA_ARG + +#define EH_FRAME_IN_DATA_SECTION 1 diff --git a/gcc/fixinc/fixincl.x b/gcc/fixinc/fixincl.x index 873e481..79b3e7e 100644 --- a/gcc/fixinc/fixincl.x +++ b/gcc/fixinc/fixincl.x @@ -5,7 +5,7 @@ * files which are fixed to work correctly with ANSI C and placed in a * directory that GNU C will search. * - * This file contains 143 fixup descriptions. + * This file contains 144 fixup descriptions. * * See README for more information. * @@ -1954,7 +1954,7 @@ tSCC zHpux10_Cpp_Pow_InlineName[] = * File name selection pattern */ tSCC zHpux10_Cpp_Pow_InlineList[] = - "|math.h|"; + "|fixinc-test-limits.h|math.h|"; /* * Machine/OS name selection pattern */ @@ -5107,6 +5107,43 @@ static const char* apzUndefine_NullPatch[] = { /* * * * * * * * * * * * * * * * * * * * * * * * * * * + * Description of Unicosmk_Restrict fix + */ +tSCC zUnicosmk_RestrictName[] = + "unicosmk_restrict"; + +/* + * File name selection pattern + */ +tSCC zUnicosmk_RestrictList[] = + "|stdio.h|stdlib.h|wchar.h|"; +/* + * Machine/OS name selection pattern + */ +tSCC* apzUnicosmk_RestrictMachs[] = { + "*-*-unicosmk*", + (const char*)NULL }; + +/* + * content selection pattern - do fix if pattern found + */ +tSCC zUnicosmk_RestrictSelect0[] = + "(\\*[ \t]*)restrict([ \t]+)"; + +#define UNICOSMK_RESTRICT_TEST_CT 1 +static tTestDesc aUnicosmk_RestrictTests[] = { + { TT_EGREP, zUnicosmk_RestrictSelect0, (regex_t*)NULL }, }; + +/* + * Fix Command Arguments for Unicosmk_Restrict + */ +static const char* apzUnicosmk_RestrictPatch[] = { + "format", + "%1__restrict__%2", + (char*)NULL }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * + * * Description of Uw7_Byteorder_Fix fix */ tSCC zUw7_Byteorder_FixName[] = @@ -5577,9 +5614,9 @@ static const char* apzX11_SprintfPatch[] = { * * List of all fixes */ -#define REGEX_COUNT 150 +#define REGEX_COUNT 151 #define MACH_LIST_SIZE_LIMIT 279 -#define FIX_COUNT 143 +#define FIX_COUNT 144 /* * Enumerate the fixes @@ -5717,6 +5754,7 @@ typedef enum { ULTRIX_STATIC_FIXIDX, ULTRIX_STRINGS_FIXIDX, UNDEFINE_NULL_FIXIDX, + UNICOSMK_RESTRICT_FIXIDX, UW7_BYTEORDER_FIX_FIXIDX, VA_I960_MACRO_FIXIDX, VOID_NULL_FIXIDX, @@ -6391,6 +6429,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = { UNDEFINE_NULL_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, aUndefine_NullTests, apzUndefine_NullPatch, 0 }, + { zUnicosmk_RestrictName, zUnicosmk_RestrictList, + apzUnicosmk_RestrictMachs, + UNICOSMK_RESTRICT_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, + aUnicosmk_RestrictTests, apzUnicosmk_RestrictPatch, 0 }, + { zUw7_Byteorder_FixName, zUw7_Byteorder_FixList, apzUw7_Byteorder_FixMachs, UW7_BYTEORDER_FIX_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, diff --git a/gcc/fixinc/inclhack.def b/gcc/fixinc/inclhack.def index aedf097..40194e2 100644 --- a/gcc/fixinc/inclhack.def +++ b/gcc/fixinc/inclhack.def @@ -3102,6 +3102,23 @@ fix = { test_text = "#define NULL 0UL\r\n#define NULL\t((void*)0)\n"; }; +/* + * On Cray Unicos/Mk some standard headers use the C99 keyword "restrict" + * which must be replaced by __restrict__ for GCC. + */ +fix = { + hackname = unicosmk_restrict; + files = stdio.h; + files = stdlib.h; + files = wchar.h; + mach = "*-*-unicosmk*"; + select = "(\\*[ \t]*)restrict([ \t]+)"; + + c_fix = format; + c_fix_arg = "%1__restrict__%2"; + + test_text = "void f (char * restrict x);"; +}; /* * If arpa/inet.h prototypes are incompatible with the ones we just diff --git a/gcc/ginclude/stddef.h b/gcc/ginclude/stddef.h index 7e5075a..cce87e5 100644 --- a/gcc/ginclude/stddef.h +++ b/gcc/ginclude/stddef.h @@ -165,6 +165,7 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t; or if we want this type in particular. */ #if defined (_STDDEF_H) || defined (__need_size_t) #ifndef __size_t__ /* BeOS */ +#ifndef __SIZE_T__ /* Cray Unicos/Mk */ #ifndef _SIZE_T /* in case <sys/types.h> has defined it. */ #ifndef _SYS_SIZE_T_H #ifndef _T_SIZE_ @@ -179,6 +180,7 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t; #ifndef _SIZET_ #ifndef __size_t #define __size_t__ /* BeOS */ +#define __SIZE_T__ /* Cray Unicos/Mk */ #define _SIZE_T #define _SYS_SIZE_T_H #define _T_SIZE_ @@ -214,6 +216,7 @@ typedef long ssize_t; #endif /* _T_SIZE_ */ #endif /* _SYS_SIZE_T_H */ #endif /* _SIZE_T */ +#endif /* __SIZE_T__ */ #endif /* __size_t__ */ #undef __need_size_t #endif /* _STDDEF_H or __need_size_t. */ @@ -228,6 +231,7 @@ typedef long ssize_t; or if we want this type in particular. */ #if defined (_STDDEF_H) || defined (__need_wchar_t) #ifndef __wchar_t__ /* BeOS */ +#ifndef __WCHAR_T__ /* Cray Unicos/Mk */ #ifndef _WCHAR_T #ifndef _T_WCHAR_ #ifndef _T_WCHAR @@ -242,6 +246,7 @@ typedef long ssize_t; #ifndef __INT_WCHAR_T_H #ifndef _GCC_WCHAR_T #define __wchar_t__ /* BeOS */ +#define __WCHAR_T__ /* Cray Unicos/Mk */ #define _WCHAR_T #define _T_WCHAR_ #define _T_WCHAR @@ -300,6 +305,7 @@ typedef __WCHAR_TYPE__ wchar_t; #endif #endif #endif +#endif /* __WCHAR_T__ */ #endif /* __wchar_t__ */ #undef __need_wchar_t #endif /* _STDDEF_H or __need_wchar_t. */ |