From e0d801845122f3952530d8047f17cfe62bf2aafc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 10 Aug 1998 05:34:44 +0000 Subject: [PATCH] Sparc backend rewrite by rth and myself, please peruse the lengthy ChangeLog for a blow by blow account. Co-Authored-By: Richard Henderson From-SVN: r21652 --- gcc/ChangeLog | 283 +++ gcc/config/sparc/sp64-elf.h | 5 +- gcc/config/sparc/sparc.c | 2456 +++++++++--------- gcc/config/sparc/sparc.h | 165 +- gcc/config/sparc/sparc.md | 4643 ++++++++++++++++++++--------------- gcc/config/sparc/sysv4.h | 4 +- gcc/final.c | 25 + gcc/reorg.c | 7 + 8 files changed, 4265 insertions(+), 3323 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e1a6e38f248..edb3dc6392f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,286 @@ +Mon Aug 10 04:28:13 1998 David S. Miller + Richard Henderson + + Rewrite Sparc backend for better code generation and + improved sparc64 support. + * config/sparc/sp64-elf.h: Set JUMP_TABLES_IN_TEXT_SECTION to + zero. + * config/sparc/sysv4.h: Likewise. + * config/sparc/sparc.c (v8plus_regcmp_p, sparc_operand, + move_operand, v8plus_regcmp_op, emit_move_sequence, + singlemove_string, doublemove_string, mem_aligned_8, + output_move_double, output_move_quad, output_fp_move_double, + move_quad_direction, output_fp_move_quad, output_scc_insn): + Remove. + (small_int_or_double): New predicate. + (gen_compare_reg): Remove TARGET_V8PLUS cmpdi_v8plus emission. + (legitimize_pic_address): Emit movsi_{high,lo_sum}_pic instead of + old pic_{sethi,lo_sum}_si patterns. + (mem_min_alignment): New generic function to replace + mem_aligned_8, which uses REGNO_POINTER_ALIGN information when + available and can test for arbitrary alignments. All callers + changed. + (save_regs, restore_regs, build_big_number, + output_function_prologue, output_cbranch, output_return, + sparc_flat_save_restore, sparc_flat_output_function_prologue, + sparc_flat_output_function_epilogue): Prettify + insn output. + (output_function_epilogue): Likewise and add code to output + deferred case vectors. + (output_v9branch): Likewise, add new arg INSN and use it to tack + on branch prediction settings. All callers changed. + (print_operand): Likewise and output %l44 for LO_SUMs when + TARGET_CM_MEDMID. + (sparc_splitdi_legitimate): New function to make sure DImode + splits can be run properly when !arch64. + (sparc_initialize_trampoline, sparc64_initialize_trampoline): + Reformat example code in comments. + (set_extends): Remove UNSPEC/v8plus_clear_high case. + (sparc_addr_diff_list, sparc_addr_list): New statics to keep track + of deferred case vectors we need to output. + (sparc_defer_case_vector): Record a case vector. + (sparc_output_addr_vec, sparc_output_addr_diff_vec, + sparc_output_deferred_case_vectors): New functions to output them. + (sparc_emit_set_const32): New function to form 32-bit constants in + registers when that requires more than one instruction. + (safe_constDI, sparc_emit_set_const64_quick1, + sparc_emit_set_const64_quick2, sparc_emit_set_const64_longway, + analyze_64bit_constant, const64_is_2insns, + create_simple_focus_bits, sparc_emit_set_const64): New functions + which do the same for 64-bit constants when arch64. + (sparc_emit_set_symbolic_const64): New function to emit address + loading for all code models on v9. + * config/sparc/sparc.h (CONDITIONAL_REGISTER_USAGE): Do not make + %g1 fixed when arch64, unfix %g0 when TARGET_LIVE_G0. + (ALTER_HARD_SUBREG): Fix thinko, return REGNO + 1 not 1. + (SECONDARY_INPUT_RELOAD_CLASS, SECONDARY_OUTPUT_RELOAD_CLASS): Fix + inaccuracies in comments, add symbolic and text_segment operands + when TARGET_CM_MEDANY and TARGET_CM_EMBMEDANY respectively. Use + GENERAL_REGS in these cases as a temp REG is needed to load these + addresses into a register properly. + (EXTRA_CONSTRAINT): Document more accurately, remove Q case as it + is no longer used. + (GO_IF_LEGITIMATE_ADDRESS): Allow TFmode for LO_SUM on v9 since fp + quads are guarenteed to have 16-byte alignment. + (LEGITIMIZE_ADDRESS): For SYMBOL_REF, CONST, and LABEL_REF use + copy_to_suggested_reg instead of explicit LO_SUM and HIGH. + (ASM_OUTPUT_ADDR_VEC, ASM_OUTPUT_ADDR_DIFF_VEC): New macros for + deferred case vector implementation. + (ASM_OUTPUT_ADDR_VEC_ELT): Use fputc to output newline. + (ASM_OUTPUT_ADDR_DIFF_ELT): Parenthesize LABEL in macro calls. + Generate "internal label - label" instead of "label - 1b". + (PRINT_OPERAND_ADDRESS): For LO_SUM use %l44 on TARGET_CM_MEDMID. + (PREDICATE_CODES): Remove sparc_operand, move_operand, + v8plus_regcmp_op. Add small_int_or_double, input_operand, and + zero_operand. + (doublemove_string, output_block_move, output_fp_move_double, + output_fp_move_quad, output_move_double, output_move_quad, + output_scc_insn, singlemove_string, mem_aligned_8, move_operand, + sparc_operand, v8plus_regcmp_op, v8plus_regcmp_p): Remove externs. + (sparc_emit_set_const32, sparc_emit_set_const64, + sparc_emit_set_symbolic_const64, input_operand, zero_operand, + mem_min_alignment, small_int_or_double): Add externs. + * config/sparc/sparc.md: Document the many uses of UNSPEC and + UNSPEC_VOLATILE in this backend. + (define_function_unit ieu): Rename to ieu_unnamed. Add move and + unary to types which execute in it. + (define_function_unit ieu_shift): Rename to ieu0. + (define_function_unit ieu1): New, executes compare, call, and + uncond_branch type insns. + (define_function_units for type fdivs, fdivd, fsqrt): These + execute in the fpu multiply unit not the adder on UltraSparc. + (define_expand cmpdi): Disallow TARGET_V8PLUS. + (define_insn cmpsi_insn): Rename to cmpsi_insn_sp32. + (define_insn cmpsi_insn_sp64): New, same as sp32 variant except it + allows the arith_double_operand predicate and rHI constraint when + TARGET_ARCH64. + (define_insn cmpdi_sp64, cmpsf_fpe, cmpdf_fpe, cmptf_fpe, + cmpsf_fp, cmpdf_fp, cmptf_fp, sltu_insn, neg_sltu_insn, + neg_sltu_minux_x, neg_sltu_plus_x, sgeu_insn, neg_sgeu_insn, + sltu_plus_x, sltu_plus_x, sltu_plus_x_plus_y, x_minus_sltu, + sgeu_plus_x, x_minus_sgeu, movqi_cc_sp64, movhi_cc_sp64, + movsi_cc_sp64, movdi_cc_sp64, movsf_cc_sp64, movdf_cc_sp64, + movtf_cc_sp64, movqi_cc_reg_sp64, movhi_cc_reg_sp64, + movsi_cc_reg_sp64, movdi_cc_reg_sp64, movsf_cc_reg_sp64, + movdf_cc_reg_sp64, movtf_cc_reg_sp64, zero_extendhisi2_insn, + cmp_siqi_trunc, cmp_siqi_trunc_set, sign_extendhisi2_insn, + sign_extendqihi2_insn, sign_extendqisi2_insn, + sign_extendqidi2_insn, sign_extendhidi2_insn, + extendsfdf2, extendsftf2, extenddftf2, truncdfsf2, trunctfsf2, + trunctfdf2, floatsisf2, floatsidf2, floatsitf2, floatdisf2, + floatdidf2, floatditf2, fix_truncsfsi2, fix_truncdfsi2, + fix_trunctfsi2, fix_truncsfdi2, fix_truncdfdi2, fix_trunctfdi2, + adddi3_sp64, addsi3, cmp_ccx_plus, cmp_cc_plus_set, subdi_sp64, + subsi3, cmp_minus_ccx, cmp_minus_ccx_set, mulsi3, muldi3, + muldi3_v8plus, cmp_mul_set, mulsidi3, mulsidi3_v8plus, + const_mulsidi3_v8plus, mulsidi3_sp32, const_mulsidi3, + smulsi3_highpart_v8plus, unnamed subreg mult, + const_smulsi3_highpart_v8plus, smulsi3_highpart_sp32, + const_smulsi3_highpart, umulsidi3_v8plus, umulsidi3_sp32, + const_umulsidi3, const_umulsidi3_v8plus, umulsi3_highpart_v8plus, + const_umulsi3_highpart_v8plus, umulsi3_highpart_sp32, + const_umulsi3_highpart, divsi3, divdi3, cmp_sdiv_cc_set, udivsi3, + udivdi3, cmp_udiv_cc_set, smacsi, smacdi, umacdi, anddi3_sp64, + andsi3, and_not_di_sp64, and_not_si, iordi3_sp64, iorsi3, + or_not_di_sp64, or_not_si, xordi3_sp64, xorsi3, xor_not_di_sp64, + xor_not_si, cmp_cc_arith_op, cmp_ccx_arith_op, + cmp_cc_arith_op_set, cmp_ccx_arith_op_set, cmp_ccx_xor_not, + cmp_cc_xor_not_set, cmp_ccx_xor_not_set, cmp_cc_arith_op_not, + cmp_ccx_arith_op_not, cmp_cc_arith_op_not_set, + cmp_ccx_arith_op_not_set, negdi2_sp64, cmp_cc_neg, cmp_ccx_neg, + cmp_cc_set_neg, cmp_ccx_set_neg, one_cmpldi2_sp64, cmp_cc_not, + cmp_ccx_not, cmp_cc_set_not, cmp_ccx_set_not, addtf3, adddf3, + addsf3, subtf3, subdf3, subsf3, multf3, muldf3, mulsf3, + muldf3_extend, multf3_extend, divtf3, divdf3, divsf3, negtf2, + negdf2, negsf2, abstf2, absdf2, abssf2, sqrttf2, sqrtdf2, sqrtsf2, + ashlsi3, ashldi3, unnamed DI ashift, cmp_cc_ashift_1, + cmp_cc_set_ashift_1, ashrsi3, ashrdi3, unnamed DI ashiftrt, + ashrdi3_v8plus, lshrsi3, lshrdi3, unnamed DI lshiftrt, + lshrdi3_v8plus, tablejump_sp32, tablejump_sp64, call_address_sp32, + call_symbolic_sp32, call_address_sp64, call_symbolic_sp64, + call_address_struct_value_sp32, call_symbolic_struct_value_sp32, + call_address_untyped_struct_value_sp32, + call_symbolic_untyped_struct_value_sp32, call_value_address_sp32, + call_value_symbolic_sp32, call_value_address_sp64, + call_value_symbolic_sp64, branch_sp32, branch_sp64, + flush_register_windows, goto_handler_and_restore, + goto_handler_and_restore_v9, goto_handler_and_restore_v9_sp64, + flush, all ldd/std peepholes, return_qi, return_hi, return_si, + return_addsi, return_di, return_adddi, return_sf, all call+jump + peepholes, trap, unnamed trap insns): Prettify output strings. + (define_insn anddi3_sp32, and_not_di_sp32, iordi3_sp32, + or_not_di_sp32, xordi3_sp32, xor_not_di_sp32, one_cmpldi2): + Likewise and force + implement splits for integer cases. + (define_insn return_sf_no_fpu): Likewise and allow to match when + no-fpu because of our subreg SFmode splits. + (define_insn zero_extendqihi2, zero_extendqisi2_insn, + zero_extendqidi2_insn, zero_extendhidi2_insn, + zero_extendsidi2_insn, sign_extendsidi2_insn): Likewise and use + input_operand for second operand. + (cmp_minus_cc, cmp_minus_cc_set): Likewise and use + reg_or_0_operand for operand 2 so new splits can use it. + (cmp_zero_extendqisi2, cmp_zero_extendqisi2_set, cmp_cc_plus, + cmp_cc_xor_not): Likewise and don't forget to check TARGET_LIVE_G0 + too. + (cmp_zero_extract, cmp_zero_extract_sp64): Likewise and allow + CONST_DOUBLEs for operand 2. + (define_insn move_label_di): Likewise and label distance + optimization because it no longer works with new deferred case + vector scheme. To be revisited. + (define_insn x_minus_y_minus_sltu, x_minus_sltu_plus_y): Likewise + and allow reg_or_0_operand and J constraint for second operand. + (define_insn jump): Set branch predict taken on V9. + (define_insn tablejump): Emit LABEL_REF + PLUS memory address for + new deferred case vector scheme. + (define_insn pic_tablejump_32, pic_tablejump_64): Remove. + (define_insn negdi2_sp32): Force + implement splits. + (define_insn negsi2, one_cmplsi2): Rename to negsi2_not_liveg0 and + one_cmplsi2_not_liveg0 respectively, and create expander of original + names which emit special rtl for TARGET_LIVE_G0. + (define_insn cmpdi_v8plus, scc_si, scc_di): Remove. + (define_insn seq, sne, slt, sge, sle, sltu, sgeu): Don't do + gen_compare_reg, FAIL instead. + (define_insn sgtu, sleu): Likewise and check gen_s*() return + values when trying to reverse condition codes, if they FAIL then + do likewise. + (define_insn snesi_zero, neg_snesi_zero, snesi_zero_extend, + snedi_zero, neg_snedi_zero, snedi_zero_trunc, seqsi_zero, + neg_seqsi_zero, seqsi_zero_extend, seqdi_zero, neg_seqdi_zero, + seqdi_zero_trunc, x_plus_i_ne_0, x_minus_i_ne_0, x_plus_i_eq_0, + x_minus_i_eq_0): Add new splits to perform these multi-insn cases, + set output string to # to indicate they are mandatory splits. + (define_insn pic_lo_sum_si, pic_sethi_si, pic_lo_sum_di, + pic_sethi_di, move_pic_label_si): Remove. + (define_insn movsi_low_sum, movsi_high, movsi_lo_sum_pic, + movsi_high_pic, movsi_pic_label_reg): New patterns to take their + place. + (define_expand movsi_pic_label_ref, define_insn + movsi_high_pic_label_ref, movsi_lo_sum_pic_label_ref): New + expander and insns to handle PIC label references and deferred + case vectors. + (define_insn get_pc_via_rdpc): Comment out as it is no longer + used. + (define_expand movqi, movhi, movsi, movdi, movsf, movdf, movtf): + Rewrite to not use emit_move_sequence, make use of new constant + formation code, and new splits for all multi-insn cases. + (define_insn movqi_insn): Remove sethi case, it can never happen. + Use reg_or_zero_operand instead of const0_rtx explicit test, + use input_operand instead of move_operand for source, and use + general_operand now for dest. + (define_insn movhi_insn): Similar but leave sethi case. + (define_insn lo_sum_qi, store_qi, store_hi): Remove. + (define_insn sethi_hi lo_sum_hi): Rename to movhi_high and + movhi_lo_sum respectively, prettify output string. + (define_insn movsi_zero_liveg0): New pattern to put zero into a + register when needed on TARGET_LIVE_G0. + (define_insn movsi_insn): Use general_operand and input_operand + for dest and src respectively. Simplify applicability test. + Prettify output strings, and add clr alternative for J + constraint. + (define_insn movdi_sp32_v9, movdi_sp32, define_splits for + deprecated std and reg-reg DI moves): Remove and... + (define_insn movdi_insn_sp32, movdi_insn_sp64): Replace with new + implementation which uses forced splits for all non-single insn + cases. + (define_split DI move cases on !arch64): New splits to handle all + situations of 64-bit double register DImode on 32bit, and + unaligned registers and memory addresses for all subtargets. + (define_insn movsf_const_insn, movdf_const_insn, store_sf): + Remove. + (define_insn movsf_insn, movsf_no_f_insn): Use general_operand and + input_operand for dest and src respectively, prettify output + strings. + (define_insn movdf_insn, movdf_no_e_insn, store_df, + movtf_const_insn, movtf_insn, movtf_no_e_insn, store_tf): Remove + and... + (define_insn movdf_insn_sp32, movdf_no_e_insn_sp32, + movdf_insn_sp64, movdf_no_e_insn_sp64, movtf_insn, + movtf_no_e_insn_sp32, movtf_insn_hq_sp64, movtf_insn_sp64, + movtf_no_e_insn_sp64) Replace with new + implementation which uses forced splits for all non-single insn + cases. + (define_split DF move cases): New splits in similar vein to DI + move counterparts. + (define_insn sethi_di_medlow, sethi_di_medium_pic, + sethi_di_embmedany_data, sethi_di_embmedany_text, sethi_di_sp64, + movdi_sp64_insn): Remove old v9 code model and constant loading + support insns and.. + (define_insn pic_lo_sum_di, pic_sethi_di, + sethi_di_medlow_embmedany_pic, sethi_di_medlow, losum_di_medlow, + seth44, setm44, setl44, sethh, setlm, sethm, setlo, + embmedany_sethi, embmedany_losum, embmedany_brsum, + embmedany_textuhi, embmedany_texthi, embmedany_textulo, + embmedany_textlo, movdi_lo_sum_sp64_cint, movdi_lo_sum_sp64_dbl, + movdi_high_sp64_cint, movdi_high_sp64_dbl): Replace with new + scheme, using unspecs, secondary reloads, and one to one sparc + insn to rtl insn mapping for better scheduling and code gen. + (define_expand reload_indi, reload_outdi): Reload helpers for + MEDANY and EMBMEDANY symbol address loading cases which require a + temporary register. + (define_expand movsicc): Remove v8plus_regcmp cases. + (define_insn movdi_cc_sp64_trunc, movdi_cc_reg_sp64_trunc, + cmp_zero_extendqidi2, cmp_zero_extendqidi2_set, cmp_qidi_trunc, + cmp_diqi_trunc_set): New patterns used by some of the new scc + splits on arch64. + (define_insn xordi3_sp64_dbl): New pattern used for constant + formation when crossing from 32-bit targets. + (define_insn movsi_cc_reg_v8plus, v8plus_clear_high, and helper + split): Remove. + (define_insn addx, subx): Make visible and prettify. + (define_insn adddi3_insn_sp32): Likewise and force split. + (define_insn addx_extend, subx_extend, unnamed): New patterns for + 64bit scc split usage. + (define_insn unnamed plusDI zero_extend, unnamed minusDI + zero_extend, subdi3): Force and implement splits. + + * final.c (final_scan_insn): Don't output labels if target + specifies ASM_OUTPUT_ADDR_{DIFF}_VEC. Do these macro operations + instead. + + * reorg.c (dbr_schedule): When taking on BR_PRED notes at the end, + don't forget to walk inside SEQUENCESs too as these are what the + delay slot scheduler will create. + Mon Aug 10 01:21:01 1998 Richard Henderson * alpha.md (extxl+1,+2): New patterns to work around diff --git a/gcc/config/sparc/sp64-elf.h b/gcc/config/sparc/sp64-elf.h index 24828664496..a1e4ef0c252 100644 --- a/gcc/config/sparc/sp64-elf.h +++ b/gcc/config/sparc/sp64-elf.h @@ -102,9 +102,10 @@ crtbegin.o%s \ /* The medium/anywhere code model practically requires us to put jump tables in the text section as gcc is unable to distinguish LABEL_REF's of jump tables from other label refs (when we need to). */ -/* ??? Revisit this. */ +/* But we now defer the tables to the end of the function, so we make + this 0 to not confuse the branch shortening code. */ #undef JUMP_TABLES_IN_TEXT_SECTION -#define JUMP_TABLES_IN_TEXT_SECTION 1 +#define JUMP_TABLES_IN_TEXT_SECTION 0 /* System V Release 4 uses DWARF debugging info. GDB doesn't support 64 bit stabs yet and the desired debug format is DWARF diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index da7c257ba94..c4411fae5fd 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -111,6 +111,9 @@ static void build_big_number PROTO((FILE *, int, char *)); static int function_arg_slotno PROTO((const CUMULATIVE_ARGS *, enum machine_mode, tree, int, int, int *, int *)); +static void sparc_output_addr_vec PROTO((rtx)); +static void sparc_output_addr_diff_vec PROTO((rtx)); +static void sparc_output_deferred_case_vectors PROTO((void)); #ifdef DWARF2_DEBUGGING_INFO extern char *dwarf2out_cfi_label (); @@ -347,14 +350,6 @@ v9_regcmp_p (code) || code == LE || code == GT); } -/* 32 bit registers are zero extended so only zero/non-zero comparisons - work. */ -int -v8plus_regcmp_p (code) - enum rtx_code code; -{ - return (code == EQ || code == NE); -} /* Operand constraints. */ @@ -636,56 +631,6 @@ reg_or_nonsymb_mem_operand (op, mode) return 0; } -int -sparc_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - if (register_operand (op, mode) - || GET_CODE (op) == CONSTANT_P_RTX) - return 1; - if (GET_CODE (op) == CONST_INT) - return SMALL_INT (op); - if (GET_MODE (op) != mode) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) != MEM) - return 0; - - op = XEXP (op, 0); - if (GET_CODE (op) == LO_SUM) - return (GET_CODE (XEXP (op, 0)) == REG - && symbolic_operand (XEXP (op, 1), Pmode)); - return memory_address_p (mode, op); -} - -int -move_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - if (mode == DImode && arith_double_operand (op, mode)) - return 1; - if (register_operand (op, mode) - || GET_CODE (op) == CONSTANT_P_RTX) - return 1; - if (GET_CODE (op) == CONST_INT) - return SMALL_INT (op) || SPARC_SETHI_P (INTVAL (op)); - - if (GET_MODE (op) != mode) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) != MEM) - return 0; - op = XEXP (op, 0); - if (GET_CODE (op) == LO_SUM) - return (register_operand (XEXP (op, 0), Pmode) - && CONSTANT_P (XEXP (op, 1))); - return memory_address_p (mode, op); -} - int splittable_symbolic_memory_operand (op, mode) rtx op; @@ -775,17 +720,6 @@ v9_regcmp_op (op, mode) return v9_regcmp_p (code); } -/* ??? Same as eq_or_neq. */ -int -v8plus_regcmp_op (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - enum rtx_code code = GET_CODE (op); - - return (code == EQ || code == NE); -} - /* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */ int @@ -963,6 +897,18 @@ small_int (op, mode) || GET_CODE (op) == CONSTANT_P_RTX); } +int +small_int_or_double (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return ((GET_CODE (op) == CONST_INT && SMALL_INT (op)) + || (GET_CODE (op) == CONST_DOUBLE + && CONST_DOUBLE_HIGH (op) == 0 + && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))) + || GET_CODE (op) == CONSTANT_P_RTX); +} + /* Recognize operand values for the umul instruction. That instruction sign extends immediate values just like all other sparc instructions, but interprets the extended result as an unsigned number. */ @@ -976,7 +922,8 @@ uns_small_int (op, mode) /* All allowed constants will fit a CONST_INT. */ return ((GET_CODE (op) == CONST_INT && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000) - || (INTVAL (op) >= 0xFFFFF000 && INTVAL (op) < 0x100000000L))) + || (INTVAL (op) >= 0xFFFFF000 + && INTVAL (op) < 0x100000000))) || GET_CODE (op) == CONSTANT_P_RTX); #else return (((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000) @@ -1003,7 +950,792 @@ clobbered_register (op, mode) { return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]); } + +/* Return 1 if OP is const0_rtx, used for TARGET_LIVE_G0 insns. */ + +int +zero_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (op == const0_rtx || GET_CODE (op) == CONSTANT_P_RTX); +} + +/* Return 1 if OP is a valid operand for the source of a move insn. */ + +int +input_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + /* If both modes are non-void they must be the same. */ + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) + return 0; + + /* Allow any one instruction integer constant, and all CONST_INT + variants when we are working in DImode and !arch64. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_CODE (op) == CONST_INT + && ((SPARC_SETHI_P (INTVAL (op)) + && (! TARGET_ARCH64 + || (INTVAL (op) >= 0) + || mode == SImode)) + || SPARC_SIMM13_P (INTVAL (op)) + || (mode == DImode + && ! TARGET_ARCH64))) + return 1; + + /* Always match this. */ + if (GET_CODE (op) == CONSTANT_P_RTX) + return 1; + + /* If !arch64 and this is a DImode const, allow it so that + the splits can be generated. */ + if (! TARGET_ARCH64 + && mode == DImode + && GET_CODE (op) == CONST_DOUBLE) + return 1; + + if (register_operand (op, mode)) + return 1; + + /* If this is a SUBREG, look inside so that we handle + paradoxical ones. */ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* Check for valid MEM forms. */ + if (GET_CODE (op) == MEM) + { + rtx inside = XEXP (op, 0); + + if (GET_CODE (inside) == LO_SUM) + return (register_operand (XEXP (inside, 0), Pmode) + && CONSTANT_P (XEXP (inside, 1))); + return memory_address_p (mode, inside); + } + + return 0; +} + +/* We know it can't be done in one insn when we get here, + the movsi expander guarentees this. */ +void +sparc_emit_set_const32 (op0, op1) + rtx op0; + rtx op1; +{ + enum machine_mode mode = GET_MODE (op0); + rtx temp; + + if (GET_CODE (op1) == CONST_INT) + { + int value = INTVAL (op1); + + if (SPARC_SETHI_P (value) + || SPARC_SIMM13_P (value)) + abort (); + } + + /* Full 2-insn decomposition is needed. */ + if (reload_in_progress || reload_completed) + temp = op0; + else + temp = gen_reg_rtx (mode); + + emit_insn (gen_rtx_SET (mode, + temp, + gen_rtx_HIGH (mode, + op1))); + emit_insn (gen_rtx_SET (mode, + op0, + gen_rtx_LO_SUM (mode, + temp, + op1))); +} + + +/* Sparc-v9 code-model support. */ +void +sparc_emit_set_symbolic_const64 (op0, op1, temp1) + rtx op0; + rtx op1; + rtx temp1; +{ + switch (sparc_cmodel) + { + case CM_MEDLOW: + /* The range spanned by all instructions in the object is less + than 2^31 bytes (2GB) and the distance from any instruction + to the location of the label _GLOBAL_OFFSET_TABLE_ is less + than 2^31 bytes (2GB). + + The executable must be in the low 4TB of the virtual address + space. + + sethi %hi(symbol), %temp + or %temp, %lo(symbol), %reg */ + emit_insn (gen_rtx_SET (DImode, temp1, gen_rtx_HIGH (DImode, op1))); + emit_insn (gen_rtx_SET (DImode, op0, gen_rtx_LO_SUM (DImode, temp1, op1))); + break; + + case CM_MEDMID: + /* The range spanned by all instructions in the object is less + than 2^31 bytes (2GB) and the distance from any instruction + to the location of the label _GLOBAL_OFFSET_TABLE_ is less + than 2^31 bytes (2GB). + + The executable must be in the low 16TB of the virtual address + space. + + sethi %h44(symbol), %temp1 + or %temp1, %m44(symbol), %temp2 + sllx %temp2, 12, %temp3 + or %temp3, %l44(symbol), %reg */ + emit_insn (gen_seth44 (op0, op1)); + emit_insn (gen_setm44 (op0, op0, op1)); + emit_insn (gen_rtx_SET (DImode, temp1, + gen_rtx_ASHIFT (DImode, op0, GEN_INT (12)))); + emit_insn (gen_setl44 (op0, temp1, op1)); + break; + + case CM_MEDANY: + /* The range spanned by all instructions in the object is less + than 2^31 bytes (2GB) and the distance from any instruction + to the location of the label _GLOBAL_OFFSET_TABLE_ is less + than 2^31 bytes (2GB). + + The executable can be placed anywhere in the virtual address + space. + + sethi %hh(symbol), %temp1 + sethi %lm(symbol), %temp2 + or %temp1, %hm(symbol), %temp3 + or %temp2, %lo(symbol), %temp4 + sllx %temp3, 32, %temp5 + or %temp4, %temp5, %reg */ + + /* Getting this right wrt. reloading is really tricky. + We _MUST_ have a seperate temporary at this point, + if we don't barf immediately instead of generating + incorrect code. */ + if (temp1 == op0) + abort (); + + emit_insn (gen_sethh (op0, op1)); + emit_insn (gen_setlm (temp1, op1)); + emit_insn (gen_sethm (op0, op0, op1)); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_ASHIFT (DImode, op0, GEN_INT (32)))); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_PLUS (DImode, op0, temp1))); + emit_insn (gen_setlo (op0, op0, op1)); + break; + + case CM_EMBMEDANY: + /* Old old old backwards compatibility kruft here. + Essentially it is MEDLOW with a fixed 64-bit + virtual base added to all data segment addresses. + Text-segment stuff is computed like MEDANY, we can't + reuse the code above because the relocation knobs + look different. + + Data segment: sethi %hi(symbol), %temp1 + or %temp1, %lo(symbol), %temp2 + add %temp2, EMBMEDANY_BASE_REG, %reg + + Text segment: sethi %uhi(symbol), %temp1 + sethi %hi(symbol), %temp2 + or %temp1, %ulo(symbol), %temp3 + or %temp2, %lo(symbol), %temp4 + sllx %temp3, 32, %temp5 + or %temp4, %temp5, %reg */ + if (data_segment_operand (op1, GET_MODE (op1))) + { + emit_insn (gen_embmedany_sethi (temp1, op1)); + emit_insn (gen_embmedany_brsum (op0, temp1)); + emit_insn (gen_embmedany_losum (op0, op0, op1)); + } + else + { + /* Getting this right wrt. reloading is really tricky. + We _MUST_ have a seperate temporary at this point, + if we don't barf immediately instead of generating + incorrect code. */ + if (temp1 == op0) + abort (); + + emit_insn (gen_embmedany_textuhi (op0, op1)); + emit_insn (gen_embmedany_texthi (temp1, op1)); + emit_insn (gen_embmedany_textulo (op0, op0, op1)); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_ASHIFT (DImode, op0, GEN_INT (32)))); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_PLUS (DImode, op0, temp1))); + emit_insn (gen_embmedany_textlo (op0, op0, op1)); + } + break; + + default: + abort(); + } +} + +/* This avoids problems when cross compiling. */ +static rtx +safe_constDI(val) + HOST_WIDE_INT val; +{ +#if HOST_BITS_PER_WIDE_INT != 64 + if (val & 0x80000000) + return immed_double_const (val, 0, DImode); + else +#endif + return GEN_INT (val); +} + +/* Worker routines for 64-bit constant formation on arch64. + One of the key things to be doing in these emissions is + to create as many temp REGs as possible. This makes it + possible for half-built constants to be used later when + such values are similar to something required later on. + Without doing this, the optimizer cannot see such + opportunities. */ +static void +sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg) + rtx op0; + rtx temp; + unsigned int low_bits; + int is_neg; +{ + unsigned int high_bits; + + if (is_neg) + high_bits = ~low_bits; + else + high_bits = low_bits; + + emit_insn (gen_rtx_SET (DImode, temp, + gen_rtx_HIGH (DImode, + safe_constDI (high_bits)))); + if (!is_neg) + { + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_LO_SUM (DImode, temp, + safe_constDI (high_bits)))); + } + else + { /* as opposed to, say, tricky dick... */ + rtx tricky_bits = safe_constDI (-0x400 | (low_bits & 0x3ff)); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_XOR (DImode, temp, tricky_bits))); + } +} + +static void +sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_immediate, shift_count) + rtx op0; + rtx temp; + unsigned int high_bits; + unsigned int low_immediate; + int shift_count; +{ + rtx temp2 = op0; + + if ((high_bits & 0xfffffc00) != 0) + { + emit_insn (gen_rtx_SET (DImode, temp, + gen_rtx_HIGH (DImode, + safe_constDI (high_bits)))); + if ((high_bits & ~0xfffffc00) != 0) + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_LO_SUM (DImode, temp, + safe_constDI (high_bits)))); + else + temp2 = temp; + } + else + { + emit_insn (gen_rtx_SET (DImode, temp, safe_constDI (high_bits))); + temp2 = temp; + } + + /* Now shift it up into place. */ + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_ASHIFT (DImode, temp2, + GEN_INT (shift_count)))); + + /* If there is a low immediate part piece, finish up by + putting that in as well. */ + if (low_immediate != 0) + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_IOR (DImode, op0, + safe_constDI (low_immediate & 0x3ff)))); +} + +/* Full 64-bit constant decomposition. Even though this is the + 'worst' case, we still optimize a few things away. */ +static void +sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits) + rtx op0; + rtx temp; + unsigned int high_bits; + unsigned int low_bits; +{ + rtx sub_temp; + + if (reload_in_progress || reload_completed) + sub_temp = op0; + else + sub_temp = gen_reg_rtx (DImode); + + if ((high_bits & 0xfffffc00) != 0) + { + emit_insn (gen_rtx_SET (DImode, + temp, + gen_rtx_HIGH (DImode, + safe_constDI (high_bits)))); + if ((high_bits & ~0xfffffc00) != 0) + emit_insn (gen_rtx_SET (DImode, + sub_temp, + gen_rtx_LO_SUM (DImode, temp, + safe_constDI (high_bits)))); + else + sub_temp = temp; + } + else + { + emit_insn (gen_rtx_SET (DImode, temp, safe_constDI (high_bits))); + sub_temp = temp; + } + + if (!reload_in_progress && !reload_completed) + { + rtx temp2 = gen_reg_rtx (DImode); + rtx temp3 = gen_reg_rtx (DImode); + rtx temp4 = gen_reg_rtx (DImode); + + emit_insn (gen_rtx_SET (DImode, temp4, + gen_rtx_ASHIFT (DImode, sub_temp, + GEN_INT (32)))); + + /* Be careful, we must mask the bits here because otherwise + on a 32-bit host the optimizer will think we're putting + something like "-1" here and optimize it away. */ + emit_insn (gen_rtx_SET (DImode, temp2, + gen_rtx_HIGH (DImode, + safe_constDI (low_bits)))); + if ((low_bits & ~0xfffffc00) != 0) + emit_insn (gen_rtx_SET (DImode, temp3, + gen_rtx_LO_SUM (DImode, temp2, + safe_constDI (low_bits)))); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_PLUS (DImode, temp4, temp3))); + } + else + { + rtx low1 = safe_constDI ((low_bits >> (32 - 12)) & 0xfff); + rtx low2 = safe_constDI ((low_bits >> (32 - 12 - 12)) & 0xfff); + rtx low3 = safe_constDI ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff); + int to_shift = 12; + + /* We are in the middle of reload, so this is really + painful. However we do still make an attempt to + avoid emmitting truly stupid code. */ + if (low1 != const0_rtx) + { + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_ASHIFT (DImode, sub_temp, + GEN_INT(to_shift)))); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_IOR (DImode, op0, low1))); + sub_temp = op0; + to_shift = 12; + } + else + { + to_shift += 12; + } + if (low2 != const0_rtx) + { + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_ASHIFT (DImode, sub_temp, + GEN_INT (to_shift)))); + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_IOR (DImode, op0, low2))); + sub_temp = op0; + to_shift = 8; + } + else + { + to_shift += 8; + } + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_ASHIFT (DImode, sub_temp, + GEN_INT (to_shift)))); + if (low3 != const0_rtx) + emit_insn (gen_rtx_SET (DImode, op0, + gen_rtx_IOR (DImode, op0, low3))); + /* phew... */ + } +} + +/* Analyze a 64-bit constant for certain properties. */ +static void +analyze_64bit_constant (high_bits, low_bits, hbsp, lbsp, abbasp) + unsigned int high_bits, low_bits; + int *hbsp, *lbsp, *abbasp; +{ + int lowest_bit_set, highest_bit_set, all_bits_between_are_set; + int i; + + lowest_bit_set = highest_bit_set = -1; + i = 0; + do + { + if ((lowest_bit_set == -1) + && ((low_bits >> i) & 1)) + lowest_bit_set = i; + if ((highest_bit_set == -1) + && ((high_bits >> (32 - i - 1)) & 1)) + highest_bit_set = (64 - i - 1); + } + while (++i < 32 + && ((highest_bit_set == -1) + || (lowest_bit_set == -1))); + if (i == 32) + { + i = 0; + do + { + if ((lowest_bit_set == -1) + && ((high_bits >> i) & 1)) + lowest_bit_set = i + 32; + if ((highest_bit_set == -1) + && ((low_bits >> (32 - i - 1)) & 1)) + highest_bit_set = 32 - i - 1; + } + while (++i < 32 + && ((highest_bit_set == -1) + || (lowest_bit_set == -1))); + } + /* If there are no bits set this should have gone out + as one instruction! */ + if (lowest_bit_set == -1 + || highest_bit_set == -1) + abort(); + all_bits_between_are_set = 1; + for (i = lowest_bit_set; i <= highest_bit_set; i++) + { + if (i < 32) + { + if ((low_bits & (1 << i)) != 0) + continue; + } + else + { + if ((high_bits & (1 << (i - 32))) != 0) + continue; + } + all_bits_between_are_set = 0; + break; + } + *hbsp = highest_bit_set; + *lbsp = lowest_bit_set; + *abbasp = all_bits_between_are_set; +} + +static int +const64_is_2insns (high_bits, low_bits) + unsigned int high_bits, low_bits; +{ + int highest_bit_set, lowest_bit_set, all_bits_between_are_set; + + if (high_bits == 0 + || high_bits == -1) + return 1; + + analyze_64bit_constant (high_bits, low_bits, + &highest_bit_set, &lowest_bit_set, + &all_bits_between_are_set); + + if (highest_bit_set == 63 + && all_bits_between_are_set != 0) + return 1; + + if ((highest_bit_set - lowest_bit_set) < 22) + return 1; + + return 0; +} + +static unsigned int +create_simple_focus_bits (high_bits, low_bits, highest_bit_set, lowest_bit_set, shift) + unsigned int high_bits, low_bits; + int highest_bit_set, lowest_bit_set, shift; +{ + unsigned int hi, lo; + + if (lowest_bit_set < 32) + { + lo = (low_bits >> lowest_bit_set) << shift; + hi = ((high_bits << (32 - lowest_bit_set)) << shift); + } + else + { + lo = 0; + hi = ((high_bits >> (lowest_bit_set - 32)) << shift); + } + if (hi & lo) + abort(); + return (hi | lo); +} + +/* Here we are sure to be arch64 and this is an integer constant + being loaded into a register. Emit the most efficient + insn sequence possible. Detection of all the 1-insn cases + has been done already. */ +void +sparc_emit_set_const64 (op0, op1) + rtx op0; + rtx op1; +{ + unsigned int high_bits, low_bits; + int lowest_bit_set, highest_bit_set; + int all_bits_between_are_set; + int i; + rtx temp; + + /* Sanity check that we know what we are working with. */ + if (! TARGET_ARCH64 + || GET_CODE (op0) != REG + || (REGNO (op0) >= SPARC_FIRST_FP_REG + && REGNO (op0) <= SPARC_LAST_V9_FP_REG)) + abort(); + + if (GET_CODE (op1) != CONST_DOUBLE + && GET_CODE (op1) != CONST_INT) + { + if (reload_in_progress || reload_completed) + temp = op0; + else + temp = gen_reg_rtx (DImode); + return sparc_emit_set_symbolic_const64 (op0, op1, temp); + } + + if (GET_CODE (op1) == CONST_DOUBLE) + { +#if HOST_BITS_PER_WIDE_INT == 64 + high_bits = CONST_DOUBLE_LOW (op1) >> 32; + low_bits = CONST_DOUBLE_LOW (op1) & 0xffffffff; +#else + high_bits = CONST_DOUBLE_HIGH (op1); + low_bits = CONST_DOUBLE_LOW (op1); +#endif + } + else + { +#if HOST_BITS_PER_WIDE_INT == 64 + high_bits = (INTVAL (op1) >> 32); + low_bits = (INTVAL (op1) & 0xffffffff); +#else + high_bits = ((INTVAL (op1) < 0) ? + 0xffffffff : + 0x00000000); + low_bits = INTVAL (op1); +#endif + } + + /* low_bits bits 0 --> 31 + high_bits bits 32 --> 63 */ + + if (reload_in_progress || reload_completed) + temp = op0; + else + temp = gen_reg_rtx (DImode); + + analyze_64bit_constant (high_bits, low_bits, + &highest_bit_set, &lowest_bit_set, + &all_bits_between_are_set); + + /* First try for a 2-insn sequence. */ + + /* These situations are preferred because the optimizer can + * do more things with them: + * 1) mov -1, %reg + * sllx %reg, shift, %reg + * 2) mov -1, %reg + * srlx %reg, shift, %reg + * 3) mov some_small_const, %reg + * sllx %reg, shift, %reg + */ + if (((highest_bit_set == 63 + || lowest_bit_set == 0) + && all_bits_between_are_set != 0) + || ((highest_bit_set - lowest_bit_set) < 13)) + { + rtx the_const = constm1_rtx; + int shift = lowest_bit_set; + + if (highest_bit_set == lowest_bit_set) + { + /* There is no way to get here like this, because this case + can be done in one instruction. */ + if (lowest_bit_set < 32) + abort (); + the_const = const1_rtx; + } + else if (all_bits_between_are_set == 0) + { + the_const = + safe_constDI (create_simple_focus_bits (high_bits, low_bits, + highest_bit_set, + lowest_bit_set, 0)); + } + else if (lowest_bit_set == 0) + shift = -(64 - highest_bit_set); + emit_insn (gen_rtx_SET (DImode, temp, the_const)); + + if (shift > 0) + emit_insn (gen_rtx_SET (DImode, + op0, + gen_rtx_ASHIFT (DImode, + temp, + GEN_INT (shift)))); + else if (shift < 0) + emit_insn (gen_rtx_SET (DImode, + op0, + gen_rtx_ASHIFTRT (DImode, + temp, + GEN_INT (-shift)))); + else + abort (); + return; + } + + /* Now a range of 22 or less bits set somewhere. + * 1) sethi %hi(focus_bits), %reg + * sllx %reg, shift, %reg + * 2) sethi %hi(focus_bits), %reg + * srlx %reg, shift, %reg + */ + if ((highest_bit_set - lowest_bit_set) < 22) + { + unsigned int focus_bits = + create_simple_focus_bits (high_bits, low_bits, + highest_bit_set, lowest_bit_set, 10); + emit_insn (gen_rtx_SET (DImode, + temp, + gen_rtx_HIGH (DImode, safe_constDI (focus_bits)))); + + if (lowest_bit_set < 10) + emit_insn (gen_rtx_SET (DImode, + op0, + gen_rtx_ASHIFTRT (DImode, temp, + GEN_INT (10 - lowest_bit_set)))); + else if (lowest_bit_set >= 10) + emit_insn (gen_rtx_SET (DImode, + op0, + gen_rtx_ASHIFT (DImode, temp, + GEN_INT (lowest_bit_set - 10)))); + else + abort(); + return; + } + + /* 1) sethi %hi(low_bits), %reg + * or %reg, %lo(low_bits), %reg + * 2) sethi %hi(~low_bits), %reg + * xor %reg, %lo(-0x400 | (low_bits & 0x3ff)), %reg + */ + if (high_bits == 0 + || high_bits == -1) + return sparc_emit_set_const64_quick1 (op0, temp, low_bits, + (high_bits == -1)); + + /* 1) sethi %hi(high_bits), %reg + * or %reg, %lo(high_bits), %reg + * sllx %reg, 32, %reg + */ + if (low_bits == 0 + || (SPARC_SIMM13_P(low_bits) + && ((int)low_bits > 0))) + return sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_bits, 32); + + /* Now, try 3-insn sequences. But first we may be able to do something + quick when the constant is negated, so try that. */ + if (const64_is_2insns ((~high_bits) & 0xffffffff, + (~low_bits) & 0xfffffc00)) + { + unsigned int trailing_bits = (~low_bits) & 0x3ff; + + if ((((~high_bits) & 0xffffffff) == 0 + && ((~low_bits) & 0x80000000) == 0) + || (((~high_bits) & 0xffffffff) == 0xffffffff + && ((~low_bits) & 0x80000000) != 0)) + { + rtx fast_int = GEN_INT (~low_bits & 0xffffffff); + + if (input_operand (fast_int, DImode)) + emit_insn (gen_rtx_SET (DImode, temp, + safe_constDI (~low_bits & 0xffffffff))); + else + sparc_emit_set_const64 (temp, fast_int); + } + else + { + rtx negated_const; +#if HOST_BITS_PER_WIDE_INT == 64 + negated_const = GEN_INT (((~low_bits) & 0xfffffc00) | + (((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32)); +#else + negated_const = gen_rtx_CONST_DOUBLE (DImode, NULL_RTX, + (~low_bits) & 0xfffffc00, + (~high_bits) & 0xffffffff); +#endif + sparc_emit_set_const64 (temp, negated_const); + } + emit_insn (gen_rtx_SET (DImode, + op0, + gen_rtx_XOR (DImode, temp, + safe_constDI (-0x400 | trailing_bits)))); + return; + } + + /* 1) sethi %hi(xxx), %reg + * or %reg, %lo(xxx), %reg + * sllx %reg, yyy, %reg + */ + if ((highest_bit_set - lowest_bit_set) < 32) + { + unsigned int hi, lo, focus_bits; + + /* We can't get here in this state. */ + if (highest_bit_set < 32 + || lowest_bit_set >= 32) + abort(); + + /* So what we know is that the set bits straddle the + middle of the 64-bit word. */ + hi = (low_bits >> lowest_bit_set); + lo = (high_bits << (32 - lowest_bit_set)); + if (hi & lo) + abort(); + focus_bits = (hi | lo); + return sparc_emit_set_const64_quick2 (op0, temp, + focus_bits, 0, + lowest_bit_set); + } + + /* The easiest way when all else fails, is full decomposition. */ +#if 0 + printf ("sparc_emit_set_const64: Hard constant [%08lx%08lx] neg[%08lx%08lx]\n", + high_bits, low_bits, ~high_bits, ~low_bits); +#endif + sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits); +} + /* X and Y are two things to compare using CODE. Emit the compare insn and return the rtx for the cc reg in the proper mode. */ @@ -1061,15 +1793,8 @@ gen_compare_reg (code, x, y) else cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG); - if (TARGET_V8PLUS && mode == CCXmode) - { - emit_insn (gen_cmpdi_v8plus (x, y)); - } - else - { - emit_insn (gen_rtx_SET (VOIDmode, cc_reg, + emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y))); - } return cc_reg; } @@ -1474,9 +2199,8 @@ legitimize_pic_address (orig, mode, reg) won't get confused into thinking that these two instructions are loading in the true address of the symbol. If in the future a PIC rtx exists, that should be used instead. */ - emit_insn (gen_pic_sethi_si (temp_reg, orig)); - emit_insn (gen_pic_lo_sum_si (temp_reg, temp_reg, orig)); - + emit_insn (gen_movsi_high_pic (temp_reg, orig)); + emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig)); address = temp_reg; } else @@ -1533,6 +2257,8 @@ legitimize_pic_address (orig, mode, reg) } else if (GET_CODE (orig) == LABEL_REF) /* ??? Why do we do this? */ + /* Now movsi_pic_label_ref uses it, but we ought to be checking that + the register is live instead, in case it is eliminated. */ current_function_uses_pic_offset_table = 1; return orig; @@ -1611,293 +2337,36 @@ finalize_pic () emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); } -/* Emit insns to move operands[1] into operands[0]. - - Return 1 if we have written out everything that needs to be done to - do the move. Otherwise, return 0 and the caller will emit the move - normally. */ +/* Return 1 if RTX is a MEM which is known to be aligned to at + least an 8 byte boundary. */ int -emit_move_sequence (operands, mode) - rtx *operands; - enum machine_mode mode; +mem_min_alignment (mem, desired) + rtx mem; + int desired; { - register rtx operand0 = operands[0]; - register rtx operand1 = operands[1]; - - if (CONSTANT_P (operand1) && flag_pic - && pic_address_needs_scratch (operand1)) - operands[1] = operand1 = legitimize_pic_address (operand1, mode, 0); - - /* Handle most common case first: storing into a register. */ - if (register_operand (operand0, mode)) - { - /* Integer constant to FP register. */ - if (GET_CODE (operand0) == REG - && REGNO (operand0) >= 32 - && REGNO (operand0) < FIRST_PSEUDO_REGISTER - && CONSTANT_P (operand1)) - { - operand1 = validize_mem (force_const_mem (GET_MODE (operand0), operand1)); - } - - if (register_operand (operand1, mode) - || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1)) - || (GET_CODE (operand1) == CONST_DOUBLE - && arith_double_operand (operand1, DImode)) - || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode) - /* Only `general_operands' can come here, so MEM is ok. */ - || GET_CODE (operand1) == MEM) - { - /* Run this case quickly. */ - emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1)); - return 1; - } - } - else if (GET_CODE (operand0) == MEM) - { - if (register_operand (operand1, mode) - || (operand1 == const0_rtx && ! TARGET_LIVE_G0)) - { - /* Run this case quickly. */ - emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1)); - return 1; - } - if (! reload_in_progress) - { - operands[0] = validize_mem (operand0); - operands[1] = operand1 = force_reg (mode, operand1); - } - } - - if (GET_CODE (operand1) == LABEL_REF - && mode == SImode && flag_pic) - { - if (TARGET_ARCH64) - abort (); - emit_insn (gen_move_pic_label_si (operand0, operand1)); - return 1; - } - /* Non-pic LABEL_REF's in sparc64 are expensive to do the normal way, - so always use special code. */ - else if (GET_CODE (operand1) == LABEL_REF - && mode == DImode) - { - if (! TARGET_ARCH64) - abort (); - emit_insn (gen_move_label_di (operand0, operand1)); - return 1; - } - /* DImode HIGH values in sparc64 need a clobber added. */ - else if (TARGET_ARCH64 - && GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode) - { - emit_insn (gen_sethi_di_sp64 (operand0, XEXP (operand1, 0))); - return 1; - } - /* Simplify the source if we need to. */ - else if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode)) - { - if (flag_pic && symbolic_operand (operand1, mode)) - { - rtx temp_reg = reload_in_progress ? operand0 : 0; - - operands[1] = legitimize_pic_address (operand1, mode, temp_reg); - } - else if (GET_CODE (operand1) == CONST_INT - ? (! SMALL_INT (operand1) - && INTVAL (operand1) != -4096 - && ! SPARC_SETHI_P (INTVAL (operand1))) - : GET_CODE (operand1) == CONST_DOUBLE - ? ! arith_double_operand (operand1, DImode) - : 1) - { - /* For DImode values, temp must be operand0 because of the way - HI and LO_SUM work. The LO_SUM operator only copies half of - the LSW from the dest of the HI operator. If the LO_SUM dest is - not the same as the HI dest, then the MSW of the LO_SUM dest will - never be set. - - ??? The real problem here is that the ...(HI:DImode pattern emits - multiple instructions, and the ...(LO_SUM:DImode pattern emits - one instruction. This fails, because the compiler assumes that - LO_SUM copies all bits of the first operand to its dest. Better - would be to have the HI pattern emit one instruction and the - LO_SUM pattern multiple instructions. Even better would be - to use four rtl insns. */ - rtx temp = ((reload_in_progress || mode == DImode) - ? operand0 : gen_reg_rtx (mode)); - - if (mode == SImode) - { - if (GET_CODE (operand1) == CONST_INT) - operand1 = GEN_INT (INTVAL (operand1) & 0xffffffff); - else if (GET_CODE (operand1) == CONST_DOUBLE) - operand1 = GEN_INT (CONST_DOUBLE_LOW (operand1) & 0xffffffff); - } - - if (TARGET_ARCH64 && mode == DImode) - emit_insn (gen_sethi_di_sp64 (temp, operand1)); - else - emit_insn (gen_rtx_SET (VOIDmode, temp, - gen_rtx_HIGH (mode, operand1))); - - operands[1] = gen_rtx_LO_SUM (mode, temp, operand1); - } - } - - /* Now have insn-emit do whatever it normally does. */ - return 0; -} - -/* Return the best assembler insn template - for moving operands[1] into operands[0] as a 4 byte quantity. - - This isn't intended to be very smart. It is up to the caller to - choose the best way to do things. - - Note that OPERANDS may be modified to suit the returned string. */ - -char * -singlemove_string (operands) - rtx *operands; -{ - if (GET_CODE (operands[0]) == MEM) - { - if (GET_CODE (operands[1]) != MEM) - return "st %r1,%0"; - else - abort (); - } - else if (GET_CODE (operands[1]) == MEM) - return "ld %1,%0"; - else if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - REAL_VALUE_TYPE r; - long i; - - /* Must be SFmode, otherwise this doesn't make sense. */ - if (GET_MODE (operands[1]) != SFmode) - abort (); - - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); - REAL_VALUE_TO_TARGET_SINGLE (r, i); - operands[1] = GEN_INT (i); - - if (CONST_OK_FOR_LETTER_P (i, 'I')) - return "mov %1,%0"; - else if ((i & 0x000003FF) != 0) - return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; - else - return "sethi %%hi(%a1),%0"; - } - else if (GET_CODE (operands[1]) == CONST_INT) - { - /* Only consider the low 32 bits of the constant. */ - int i = INTVAL (operands[1]) & 0xffffffff; - - if (SPARC_SIMM13_P (i)) - return "mov %1,%0"; - - if (i == 4096) - return "sub %%g0,-4096,%0"; - - /* If all low order 10 bits are clear, then we only need a single - sethi insn to load the constant. */ - /* FIXME: Use SETHI_P. */ - if ((i & 0x000003FF) != 0) - return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0"; - else - return "sethi %%hi(%a1),%0"; - } - /* Operand 1 must be a register, or a 'I' type CONST_INT. */ - return "mov %1,%0"; -} - -/* Return the best assembler insn template - for moving operands[1] into operands[0] as an 8 byte quantity. - - This isn't intended to be very smart. It is up to the caller to - choose the best way to do things. - - Note that OPERANDS may be modified to suit the returned string. */ - -char * -doublemove_string (operands) - rtx *operands; -{ - rtx op0 = operands[0], op1 = operands[1]; - - if (GET_CODE (op0) == MEM) - { - if (GET_CODE (op1) == REG) - { - if (FP_REG_P (op1)) - return "std %1,%0"; - return TARGET_ARCH64 ? "stx %1,%0" : "std %1,%0"; - } - if (TARGET_ARCH64 - && (op1 == const0_rtx - || (GET_MODE (op1) != VOIDmode - && op1 == CONST0_RTX (GET_MODE (op1))))) - return "stx %r1,%0"; - abort (); - } - else if (GET_CODE (op1) == MEM) - { - if (GET_CODE (op0) != REG) - abort (); - if (FP_REG_P (op0)) - return "ldd %1,%0"; - return TARGET_ARCH64 ? "ldx %1,%0" : "ldd %1,%0"; - } - else if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - /* ??? Unfinished, and maybe not needed. */ - abort (); - } - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* ??? Unfinished, and maybe not needed. */ - abort (); - } - /* Operand 1 must be a register, or a 'I' type CONST_INT. */ - return "mov %1,%0"; -} - -/* Return non-zero if it is OK to assume that the given memory operand is - aligned at least to a 8-byte boundary. This should only be called - for memory accesses whose size is 8 bytes or larger. */ - -int -mem_aligned_8 (mem) - register rtx mem; -{ - register rtx addr; - register rtx base; - register rtx offset; + rtx addr, base, offset; + /* If it's not a MEM we can't accept it. */ if (GET_CODE (mem) != MEM) - return 0; /* It's gotta be a MEM! */ + return 0; addr = XEXP (mem, 0); - - /* Now that all misaligned double parms are copied on function entry, - we can assume any 64-bit object is 64-bit aligned except those which - are at unaligned offsets from the stack or frame pointer. If the - TARGET_UNALIGNED_DOUBLES switch is given, we do not make this - assumption. */ - - /* See what register we use in the address. */ - base = offset = 0; + base = offset = NULL_RTX; if (GET_CODE (addr) == PLUS) { - if (GET_CODE (XEXP (addr, 0)) == REG - && GET_CODE (XEXP (addr, 1)) == CONST_INT) + if (GET_CODE (XEXP (addr, 0)) == REG) { base = XEXP (addr, 0); - offset = XEXP (addr, 1); + + /* What we are saying here is that if the base + REG is aligned properly, the compiler will make + sure any REG based index upon it will be so + as well. */ + if (GET_CODE (XEXP (addr, 1)) == CONST_INT) + offset = XEXP (addr, 1); + else + offset = const0_rtx; } } else if (GET_CODE (addr) == REG) @@ -1906,767 +2375,42 @@ mem_aligned_8 (mem) offset = const0_rtx; } - /* If it's the stack or frame pointer, check offset alignment. - We can have improper alignment in the function entry code. */ - if (base - && (REGNO (base) == FRAME_POINTER_REGNUM - || REGNO (base) == STACK_POINTER_REGNUM)) + if (base != NULL_RTX) { - if (((INTVAL (offset) - SPARC_STACK_BIAS) & 0x7) == 0) - return 1; + int regno = REGNO (base); + + if (regno != FRAME_POINTER_REGNUM + && regno != STACK_POINTER_REGNUM) + { + /* Check if the compiler has recorded some information + about the alignment of the base REG. If reload has + completed, we already matched with proper alignments. */ + if (((regno_pointer_align != NULL + && REGNO_POINTER_ALIGN (regno) >= desired) + || reload_completed) + && ((INTVAL (offset) & (desired - 1)) == 0)) + return 1; + } + else + { + if (((INTVAL (offset) - SPARC_STACK_BIAS) & (desired - 1)) == 0) + return 1; + } } - /* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES - is true, in which case we can only assume that an access is aligned if - it is to a constant address, or the address involves a LO_SUM. - - We used to assume an address was aligned if MEM_IN_STRUCT_P was true. - That assumption was deleted so that gcc generated code can be used with - memory allocators that only guarantee 4 byte alignment. */ - else if (! TARGET_UNALIGNED_DOUBLES || CONSTANT_P (addr) + else if (! TARGET_UNALIGNED_DOUBLES + || CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM) - return 1; - + { + /* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES + is true, in which case we can only assume that an access is aligned if + it is to a constant address, or the address involves a LO_SUM. */ + return 1; + } + /* An obviously unaligned address. */ return 0; } -enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP }; - -/* Output assembler code to perform a doubleword move insn - with operands OPERANDS. This is very similar to the following - output_move_quad function. */ - -char * -output_move_double (operands) - rtx *operands; -{ - register rtx op0 = operands[0]; - register rtx op1 = operands[1]; - register enum optype optype0; - register enum optype optype1; - rtx latehalf[2]; - rtx addreg0 = 0; - rtx addreg1 = 0; - int highest_first = 0; - int no_addreg1_decrement = 0; - - /* First classify both operands. */ - - if (REG_P (op0)) - optype0 = REGOP; - else if (offsettable_memref_p (op0)) - optype0 = OFFSOP; - else if (GET_CODE (op0) == MEM) - optype0 = MEMOP; - else - optype0 = RNDOP; - - if (REG_P (op1)) - optype1 = REGOP; - else if (CONSTANT_P (op1)) - optype1 = CNSTOP; - else if (offsettable_memref_p (op1)) - optype1 = OFFSOP; - else if (GET_CODE (op1) == MEM) - optype1 = MEMOP; - else - optype1 = RNDOP; - - /* Check for the cases that the operand constraints are not - supposed to allow to happen. Abort if we get one, - because generating code for these cases is painful. */ - - if (optype0 == RNDOP || optype1 == RNDOP - || (optype0 == MEM && optype1 == MEM)) - abort (); - - /* If an operand is an unoffsettable memory ref, find a register - we can increment temporarily to make it refer to the second word. */ - - if (optype0 == MEMOP) - addreg0 = find_addr_reg (XEXP (op0, 0)); - - if (optype1 == MEMOP) - addreg1 = find_addr_reg (XEXP (op1, 0)); - - /* Ok, we can do one word at a time. - Set up in LATEHALF the operands to use for the - high-numbered (least significant) word and in some cases alter the - operands in OPERANDS to be suitable for the low-numbered word. */ - - if (optype0 == REGOP) - latehalf[0] = gen_rtx_REG (SImode, REGNO (op0) + 1); - else if (optype0 == OFFSOP) - latehalf[0] = adj_offsettable_operand (op0, 4); - else - latehalf[0] = op0; - - if (optype1 == REGOP) - latehalf[1] = gen_rtx_REG (SImode, REGNO (op1) + 1); - else if (optype1 == OFFSOP) - latehalf[1] = adj_offsettable_operand (op1, 4); - else if (optype1 == CNSTOP) - { - if (TARGET_ARCH64) - { - if (arith_double_operand (op1, DImode)) - { - operands[1] = GEN_INT (CONST_DOUBLE_LOW (op1)); - return "mov %1,%0"; - } - else - { - /* The only way to handle CONST_DOUBLEs or other 64 bit - constants here is to use a temporary, such as is done - for the V9 DImode sethi insn pattern. This is not - a practical solution, so abort if we reach here. - The md file should always force such constants to - memory. */ - abort (); - } - } - else - split_double (op1, &operands[1], &latehalf[1]); - } - else - latehalf[1] = op1; - - /* Easy case: try moving both words at once. Check for moving between - an even/odd register pair and a memory location. */ - if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP - && (TARGET_ARCH64 || (REGNO (op0) & 1) == 0)) - || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP - && (TARGET_ARCH64 || (REGNO (op1) & 1) == 0))) - { - register rtx mem,reg; - - if (optype0 == REGOP) - mem = op1, reg = op0; - else - mem = op0, reg = op1; - - /* In v9, ldd can be used for word aligned addresses, so technically - some of this logic is unneeded. We still avoid ldd if the address - is obviously unaligned though. - - Integer ldd/std are deprecated in V9 and are slow on UltraSPARC. - Use them only if the access is volatile or not offsettable. */ - - if ((mem_aligned_8 (mem) - && (REGNO (reg) >= 32 - || MEM_VOLATILE_P (mem) - || ! ((optype0 == OFFSOP || optype1 == OFFSOP) - && (sparc_cpu == PROCESSOR_ULTRASPARC - || sparc_cpu == PROCESSOR_V9)))) - /* If this is a floating point register higher than %f31, - then we *must* use an aligned load, since `ld' will not accept - the register number. */ - || (TARGET_V9 && REGNO (reg) >= 64) - /* Even if two instructions would otherwise be better than ldd/std, - if this insn was put in a delay slot because reorg thought it - was only one machine instruction, make sure it is only one - instruction. */ - || dbr_sequence_length () != 0) - { - if (FP_REG_P (reg) || ! TARGET_ARCH64) - return (mem == op1 ? "ldd %1,%0" : "std %1,%0"); - else - return (mem == op1 ? "ldx %1,%0" : "stx %1,%0"); - } - } - - if (TARGET_ARCH64) - { - if (optype0 == REGOP && optype1 == REGOP) - { - if (FP_REG_P (op0)) - return "fmovd %1,%0"; - else - return "mov %1,%0"; - } - } - - /* If the first move would clobber the source of the second one, - do them in the other order. */ - - /* Overlapping registers. */ - if (optype0 == REGOP && optype1 == REGOP - && REGNO (op0) == REGNO (latehalf[1])) - { - /* Do that word. */ - output_asm_insn (singlemove_string (latehalf), latehalf); - /* Do low-numbered word. */ - return singlemove_string (operands); - } - /* Loading into a register which overlaps a register used in the address. */ - else if (optype0 == REGOP && optype1 != REGOP - && reg_overlap_mentioned_p (op0, op1)) - { - /* If both halves of dest are used in the src memory address, - add the two regs and put them in the low reg (op0). - Then it works to load latehalf first. */ - if (reg_mentioned_p (op0, XEXP (op1, 0)) - && reg_mentioned_p (latehalf[0], XEXP (op1, 0))) - { - rtx xops[2]; - xops[0] = latehalf[0]; - xops[1] = op0; - output_asm_insn ("add %1,%0,%1", xops); - operands[1] = gen_rtx_MEM (DImode, op0); - latehalf[1] = adj_offsettable_operand (operands[1], 4); - addreg1 = 0; - highest_first = 1; - } - /* Only one register in the dest is used in the src memory address, - and this is the first register of the dest, so we want to do - the late half first here also. */ - else if (! reg_mentioned_p (latehalf[0], XEXP (op1, 0))) - highest_first = 1; - /* Only one register in the dest is used in the src memory address, - and this is the second register of the dest, so we want to do - the late half last. If addreg1 is set, and addreg1 is the same - register as latehalf, then we must suppress the trailing decrement, - because it would clobber the value just loaded. */ - else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0])) - no_addreg1_decrement = 1; - } - - /* Normal case: do the two words, low-numbered first. - Overlap case (highest_first set): do high-numbered word first. */ - - if (! highest_first) - output_asm_insn (singlemove_string (operands), operands); - - /* Make any unoffsettable addresses point at high-numbered word. */ - if (addreg0) - output_asm_insn ("add %0,0x4,%0", &addreg0); - if (addreg1) - output_asm_insn ("add %0,0x4,%0", &addreg1); - - /* Do that word. */ - output_asm_insn (singlemove_string (latehalf), latehalf); - - /* Undo the adds we just did. */ - if (addreg0) - output_asm_insn ("add %0,-0x4,%0", &addreg0); - if (addreg1 && ! no_addreg1_decrement) - output_asm_insn ("add %0,-0x4,%0", &addreg1); - - if (highest_first) - output_asm_insn (singlemove_string (operands), operands); - - return ""; -} - -/* Output assembler code to perform a quadword move insn - with operands OPERANDS. This is very similar to the preceding - output_move_double function. */ - -char * -output_move_quad (operands) - rtx *operands; -{ - register rtx op0 = operands[0]; - register rtx op1 = operands[1]; - register enum optype optype0; - register enum optype optype1; - rtx wordpart[4][2]; - rtx load_late[4]; - int load_late_half[2]; - rtx addreg0 = 0; - rtx addreg1 = 0; - - load_late_half[0] = 0; load_late_half[1] = 0; - load_late[0] = 0; load_late[1] = 0; load_late[2] = 0; - load_late[3] = 0; - - wordpart[0][0] = NULL; wordpart[1][0] = NULL; wordpart[2][0] = NULL; - wordpart[3][0] = NULL; - - /* First classify both operands. */ - - if (REG_P (op0)) - optype0 = REGOP; - else if (offsettable_memref_p (op0)) - optype0 = OFFSOP; - else if (GET_CODE (op0) == MEM) - optype0 = MEMOP; - else - optype0 = RNDOP; - - if (REG_P (op1)) - optype1 = REGOP; - else if (CONSTANT_P (op1)) - optype1 = CNSTOP; - else if (offsettable_memref_p (op1)) - optype1 = OFFSOP; - else if (GET_CODE (op1) == MEM) - optype1 = MEMOP; - else - optype1 = RNDOP; - - /* Check for the cases that the operand constraints are not - supposed to allow to happen. Abort if we get one, - because generating code for these cases is painful. */ - - if (optype0 == RNDOP || optype1 == RNDOP - || (optype0 == MEM && optype1 == MEM)) - abort (); - - if (optype0 == REGOP) - { - wordpart[0][0] = gen_rtx_REG (word_mode, REGNO (op0) + 0); - if (TARGET_ARCH64 && FP_REG_P (op0) - && REGNO (op0) < SPARC_FIRST_V9_FP_REG) - wordpart[1][0] = gen_rtx_REG (word_mode, REGNO (op0) + 2); - else - wordpart[1][0] = gen_rtx_REG (word_mode, REGNO (op0) + 1); - - if (TARGET_ARCH32) - { - wordpart[2][0] = gen_rtx_REG (word_mode, REGNO (op0) + 2); - wordpart[3][0] = gen_rtx_REG (word_mode, REGNO (op0) + 3); - } - - /* Loading into a register which overlaps a register used in the - address. */ - if (optype1 != REGOP && reg_overlap_mentioned_p (op0, op1)) - { - int i; - int count; - - count = 0; - - for (i = 0; i < 4 && wordpart[i][0] != NULL; i++) - { - if (reg_mentioned_p (wordpart[i][0], op1)) - { - load_late[i] = wordpart[i][0]; - load_late_half[TARGET_ARCH64 ? i : i/2] = 1; - count++; - } - } - if (count > 2) - { - /* Not sure what to do here. Multiple adds? Can't happen. */ - abort (); - } - else if (count == 2) - { - /* We have a two-address source operand, and both registers - overlap with the dest quad. Add them together and - store the result into the last register of the quad being - loaded, then generate an appropriate MEM insn. */ - rtx temp[3]; - int place = 0; - - for (i = 0; i < 4; i++) - { - if (load_late[i]) - { - temp[place++] = load_late[i]; - load_late[i] = 0; - } - } - temp[2] = wordpart[3][0]; - output_asm_insn ("add %0, %1, %2", temp); - load_late_half[0] = 0; - load_late_half[1] = 1; - op1 = gen_rtx_MEM (TFmode, wordpart[3][0]); - operands[1] = op1; - optype1 = OFFSOP; - } - } - } - - /* If an operand is an unoffsettable memory ref, find a register - we can increment temporarily to make it refer to the later words. */ - - if (optype0 == MEMOP) - addreg0 = find_addr_reg (XEXP (op0, 0)); - - if (optype1 == MEMOP) - addreg1 = find_addr_reg (XEXP (op1, 0)); - - /* Ok, we can do one word at a time. - Set up in wordpart the operands to use for each word of the arguments. */ - - if (optype0 == OFFSOP) - { - wordpart[0][0] = adj_offsettable_operand (op0, 0); - if (TARGET_ARCH32) - { - wordpart[1][0] = adj_offsettable_operand (op0, 4); - wordpart[2][0] = adj_offsettable_operand (op0, 8); - wordpart[3][0] = adj_offsettable_operand (op0, 12); - } - else - wordpart[1][0] = adj_offsettable_operand (op0, 8); - } - else if (optype0 != REGOP) - { - wordpart[0][0] = op0; - wordpart[1][0] = op0; - wordpart[2][0] = op0; - wordpart[3][0] = op0; - } - - if (optype1 == REGOP) - { - wordpart[0][1] = gen_rtx_REG (word_mode, REGNO (op1) + 0); - if (TARGET_ARCH64 && FP_REG_P (op1) - && REGNO (op1) < SPARC_FIRST_V9_FP_REG) - wordpart[1][1] = gen_rtx_REG (word_mode, REGNO (op1) + 2); - else - wordpart[1][1] = gen_rtx_REG (word_mode, REGNO (op1) + 1); - - if (TARGET_ARCH32) - { - wordpart[2][1] = gen_rtx_REG (word_mode, REGNO (op1) + 2); - wordpart[3][1] = gen_rtx_REG (word_mode, REGNO (op1) + 3); - } - } - else if (optype1 == OFFSOP) - { - wordpart[0][1] = adj_offsettable_operand (op1, 0); - if (TARGET_ARCH32) - { - wordpart[1][1] = adj_offsettable_operand (op1, 4); - wordpart[2][1] = adj_offsettable_operand (op1, 8); - wordpart[3][1] = adj_offsettable_operand (op1, 12); - } - else - wordpart[1][1] = adj_offsettable_operand (op1, 8); - } - else if (optype1 == CNSTOP) - { - REAL_VALUE_TYPE r; - long l[4]; - - /* This only works for TFmode floating point constants. */ - if (GET_CODE (op1) != CONST_DOUBLE || GET_MODE (op1) != TFmode) - abort (); - - REAL_VALUE_FROM_CONST_DOUBLE (r, op1); - REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); - - wordpart[0][1] = GEN_INT (l[0]); - wordpart[1][1] = GEN_INT (l[1]); - wordpart[2][1] = GEN_INT (l[2]); - wordpart[3][1] = GEN_INT (l[3]); - } - else - { - wordpart[0][1] = op1; - wordpart[1][1] = op1; - wordpart[2][1] = op1; - wordpart[3][1] = op1; - } - - /* Easy case: try moving the quad as two pairs. Check for moving between - an even/odd register pair and a memory location. - Also handle new v9 fp regs here. */ - /* ??? Should also handle the case of non-offsettable addresses here. - We can at least do the first pair as a ldd/std, and then do the third - and fourth words individually. */ - if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0) - || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0)) - { - rtx mem, reg; - int use_ldx; - - if (optype0 == REGOP) - mem = op1, reg = op0; - else - mem = op0, reg = op1; - - if (mem_aligned_8 (mem) - /* If this is a floating point register higher than %f31, - then we *must* use an aligned load, since `ld' will not accept - the register number. */ - || (TARGET_V9 && REGNO (reg) >= SPARC_FIRST_V9_FP_REG)) - { - static char * const mov_by_64[2][2][2] = { - { { "std %S1,%2;std %1,%0", "stx %R1,%2;stx %1,%0" }, - { "ldd %2,%S0;ldd %1,%0", "ldx %2,%R0;ldx %1,%0" } }, - { { "std %1,%0;std %S1,%2", "stx %1,%0;stx %R1,%2" }, - { "ldd %1,%0;ldd %2,%S0", "ldx %1,%0;ldx %2,%R0" } } - }; - - if (TARGET_V9 && FP_REG_P (reg) && TARGET_HARD_QUAD) - { - /* Only abort if the register # requires that we use ldq. */ - if ((REGNO (reg) & 3) == 0) - { - /* ??? Can `mem' have an inappropriate alignment here? */ - return (mem == op1 ? "ldq %1,%0" : "stq %1,%0"); - } - else - { - if (REGNO (reg) >= SPARC_FIRST_V9_FP_REG) - abort(); - } - } - operands[2] = adj_offsettable_operand (mem, 8); - - /* Do the loads in the right order; can't overwrite our address - register. */ - use_ldx = TARGET_ARCH64 && !FP_REG_P (reg); - return mov_by_64[!load_late_half[0]][mem == op1][use_ldx]; - } - } - - /* If the first move would clobber the source of the second one, - do them in the other order. */ - - /* Overlapping registers? */ - if (TARGET_ARCH32) - { - if (optype0 == REGOP && optype1 == REGOP - && (REGNO (op0) == REGNO (wordpart[1][3]) - || REGNO (op0) == REGNO (wordpart[1][2]) - || REGNO (op0) == REGNO (wordpart[1][1]))) - { - /* Do fourth word. */ - output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]); - /* Do the third word. */ - output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]); - /* Do the second word. */ - output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]); - /* Do lowest-numbered word. */ - output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]); - return ""; - } - } - else /* TARGET_ARCH64 */ - { - if (optype0 == REGOP && optype1 == REGOP - && REGNO (op0) == REGNO (wordpart[1][1])) - { - output_asm_insn ("mov %1,%0", wordpart[1]); - output_asm_insn ("mov %1,%0", wordpart[0]); - return ""; - } - } - - /* Normal case: move the words in lowest to highest address order. - There may have an overlapping register; in that case, skip and go - back. */ - - if (TARGET_ARCH32) - { - int i; - int offset = 0xc; - rtx temp[2]; - - for (i = 0; i < 4; i++) - { - if (! load_late[i]) - output_asm_insn (singlemove_string (wordpart[i]), wordpart[i]); - - if (i != 3) - { - /* Make any unoffsettable addresses point at the next word. */ - if (addreg0) - output_asm_insn ("add %0,0x4,%0", &addreg0); - if (addreg1) - output_asm_insn ("add %0,0x4,%0", &addreg1); - } - } - for (i = 0; i < 4; i++) - { - if (load_late[i]) - { - int fix = offset - i * 4; - - /* Back up to the appropriate place. */ - temp[1] = GEN_INT (-fix); - if (addreg0) - { - temp[0] = addreg0; - output_asm_insn ("add %0,%1,%0", temp); - } - if (addreg1) - { - temp[0] = addreg1; - output_asm_insn ("add %0,%1,%0", temp); - } - output_asm_insn (singlemove_string (wordpart[i]), - wordpart[i]); - /* Don't modify the register that's the destination of the - move. */ - temp[0] = GEN_INT (-(offset - fix)); - if (addreg0 && REGNO (addreg0) != REGNO (wordpart[i][0])) - { - temp[1] = addreg0; - output_asm_insn("add %0,%1,%0", temp); - } - if (addreg1 && REGNO (addreg1) != REGNO (wordpart[i][0])) - { - temp[1] = addreg1; - output_asm_insn("add %0,%1,%0",temp); - } - offset = 0; - break; - } - } - if (offset) - { - temp[1] = GEN_INT (-offset); - /* Undo the adds we just did. */ - if (addreg0) - { - temp[0] = addreg0; - output_asm_insn ("add %0,%1,%0", temp); - } - if (addreg1) - { - temp[0] = addreg1; - output_asm_insn ("add %0,%1,%0", temp); - } - } - } - else /* TARGET_ARCH64 */ - { - if (load_late_half[0]) - { - /* Load the second half first. */ - if (addreg0) - output_asm_insn ("add %0,0x8,%0", &addreg0); - if (addreg1) - output_asm_insn ("add %0,0x8,%0", &addreg1); - - output_asm_insn (doublemove_string (wordpart[1]), wordpart[1]); - - /* Undo the adds we just did. */ - if (addreg0) - output_asm_insn ("add %0,-0x8,%0", &addreg0); - if (addreg1) - output_asm_insn ("add %0,-0x8,%0", &addreg1); - - output_asm_insn (doublemove_string (wordpart[0]), wordpart[0]); - } - else - { - output_asm_insn (doublemove_string (wordpart[0]), wordpart[0]); - - if (addreg0) - output_asm_insn ("add %0,0x8,%0", &addreg0); - if (addreg1) - output_asm_insn ("add %0,0x8,%0", &addreg1); - - /* Do the second word. */ - output_asm_insn (doublemove_string (wordpart[1]), wordpart[1]); - - /* Undo the adds we just did. But don't modify the dest of - the move. */ - if (addreg0 && REGNO (addreg0) != REGNO (wordpart[1][0])) - output_asm_insn ("add %0,-0x8,%0", &addreg0); - if (addreg1 && REGNO (addreg1) != REGNO (wordpart[1][0])) - output_asm_insn ("add %0,-0x8,%0", &addreg1); - } - } - - return ""; -} - -/* Output assembler code to perform a doubleword move insn with operands - OPERANDS, one of which must be a floating point register. */ - -char * -output_fp_move_double (operands) - rtx *operands; -{ - if (FP_REG_P (operands[0])) - { - if (FP_REG_P (operands[1])) - { - if (TARGET_V9) - return "fmovd %1,%0"; - else - return "fmovs %1,%0\n\tfmovs %R1,%R0"; - } - else if (GET_CODE (operands[1]) == REG) - abort (); - else - return output_move_double (operands); - } - else if (FP_REG_P (operands[1])) - { - if (GET_CODE (operands[0]) == REG) - abort (); - else - return output_move_double (operands); - } - else abort (); -} - -/* When doing a quad-register move, determine the drection in which - the move needs to be performed. SRC and DST are the source and - destination registers. - - A value of -1 indicates that the move needs to be done from the - highest register to the lowest. */ - -static int -move_quad_direction (src, dst) - rtx src, dst; -{ - if ((REGNO (dst) > REGNO (src)) - && (REGNO (dst) < (REGNO (src) + 4))) - return -1; - else - return 1; -} - -/* Output assembler code to perform a quadword move insn with operands - OPERANDS, one of which must be a floating point register. */ - -char * -output_fp_move_quad (operands) - rtx *operands; -{ - register rtx op0 = operands[0]; - register rtx op1 = operands[1]; - - if (FP_REG_P (op0)) - { - if (FP_REG_P (op1)) - { - if (TARGET_V9 && TARGET_HARD_QUAD) - return "fmovq %1,%0"; - else if (TARGET_V9) - { - int dir = move_quad_direction (op1, op0); - if (dir > 0) - return "fmovd %1,%0\n\tfmovd %S1,%S0"; - else - return "fmovd %S1,%S0\n\tfmovd %1,%0"; - } - else - { - int dir = move_quad_direction (op0, op1); - if (dir > 0) - return "fmovs %1,%0\n\tfmovs %R1,%R0\n\tfmovs %S1,%S0\n\tfmovs %T1,%T0"; - else - return "fmovs %T1,%T0\n\tfmovs %S1,%S0\n\tfmovs %R1,%R0\n\tfmovs %1,%0"; - } - } - else if (GET_CODE (op1) == REG) - abort (); - else - return output_move_quad (operands); - } - else if (FP_REG_P (op1)) - { - if (GET_CODE (op0) == REG) - abort (); - else - return output_move_quad (operands); - } - else - abort (); -} /* Return a REG that occurs in ADDR with coefficient 1. ADDR can be effectively incremented by incrementing REG. */ @@ -2698,71 +2442,6 @@ find_addr_reg (addr) abort (); } -/* Output reasonable peephole for set-on-condition-code insns. - Note that these insns assume a particular way of defining - labels. Therefore, *both* sparc.h and this function must - be changed if a new syntax is needed. */ - -char * -output_scc_insn (operands, insn) - rtx operands[]; - rtx insn; -{ - static char string[100]; - rtx label = 0, next = insn; - int need_label = 0; - - /* This code used to be called with final_sequence nonzero (for fpcc - delay slots), but that is no longer allowed. */ - if (final_sequence) - abort (); - - /* On UltraSPARC a conditional moves blocks until 3 cycles after prior loads - complete. It might be beneficial here to use branches if any recent - instructions were loads. */ - if (TARGET_V9 && REGNO (operands[1]) == SPARC_ICC_REG) - return "mov 0,%0\n\tmov%C2 %x1,1,%0"; - - /* Try doing a jump optimization which jump.c can't do for us - because we did not expose that setcc works by using branches. - - If this scc insn is followed by an unconditional branch, then have - the jump insn emitted here jump to that location, instead of to - the end of the scc sequence as usual. */ - - do - { - if (GET_CODE (next) == CODE_LABEL) - label = next; - next = NEXT_INSN (next); - } - while (next && (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL)); - - if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next)) - label = JUMP_LABEL (next); - - /* If not optimizing, jump label fields are not set. To be safe, always - check here to whether label is still zero. */ - if (label == 0) - { - label = gen_label_rtx (); - need_label = 1; - } - - LABEL_NUSES (label) += 1; - - /* operands[3] is an unused slot. */ - operands[3] = label; - - strcpy (string, output_cbranch (operands[2], 3, 0, 1, 0)); - strcat (string, "\n\tmov 1,%0\n\tmov 0,%0"); - - if (need_label) - strcat (string, "\n%l3:"); - - return string; -} - /* Vectors to keep interesting information about registers where it can easily be got. We use to use the actual mode value as the bit number, but there are more than 32 modes now. Instead we use two tables: one indexed by @@ -2973,7 +2652,7 @@ save_regs (file, low, high, base, offset, n_regs, real_offset) { if (regs_ever_live[i] && ! call_used_regs[i]) { - fprintf (file, "\tstx %s,[%s+%d]\n", + fprintf (file, "\tstx\t%s, [%s+%d]\n", reg_names[i], base, offset + 4 * n_regs); if (dwarf2out_do_frame ()) dwarf2out_reg_save ("", i, real_offset + 4 * n_regs); @@ -2989,7 +2668,7 @@ save_regs (file, low, high, base, offset, n_regs, real_offset) { if (regs_ever_live[i+1] && ! call_used_regs[i+1]) { - fprintf (file, "\tstd %s,[%s+%d]\n", + fprintf (file, "\tstd\t%s, [%s+%d]\n", reg_names[i], base, offset + 4 * n_regs); if (dwarf2out_do_frame ()) { @@ -3001,7 +2680,7 @@ save_regs (file, low, high, base, offset, n_regs, real_offset) } else { - fprintf (file, "\tst %s,[%s+%d]\n", + fprintf (file, "\tst\t%s, [%s+%d]\n", reg_names[i], base, offset + 4 * n_regs); if (dwarf2out_do_frame ()) dwarf2out_reg_save ("", i, real_offset + 4 * n_regs); @@ -3012,7 +2691,7 @@ save_regs (file, low, high, base, offset, n_regs, real_offset) { if (regs_ever_live[i+1] && ! call_used_regs[i+1]) { - fprintf (file, "\tst %s,[%s+%d]\n", + fprintf (file, "\tst\t%s, [%s+%d]\n", reg_names[i+1], base, offset + 4 * n_regs + 4); if (dwarf2out_do_frame ()) dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4); @@ -3044,7 +2723,7 @@ restore_regs (file, low, high, base, offset, n_regs) for (i = low; i < high; i++) { if (regs_ever_live[i] && ! call_used_regs[i]) - fprintf (file, "\tldx [%s+%d], %s\n", + fprintf (file, "\tldx\t[%s+%d], %s\n", base, offset + 4 * n_regs, reg_names[i]), n_regs += 2; } @@ -3055,15 +2734,15 @@ restore_regs (file, low, high, base, offset, n_regs) { if (regs_ever_live[i] && ! call_used_regs[i]) if (regs_ever_live[i+1] && ! call_used_regs[i+1]) - fprintf (file, "\tldd [%s+%d], %s\n", + fprintf (file, "\tldd\t[%s+%d], %s\n", base, offset + 4 * n_regs, reg_names[i]), n_regs += 2; else - fprintf (file, "\tld [%s+%d],%s\n", + fprintf (file, "\tld\t[%s+%d],%s\n", base, offset + 4 * n_regs, reg_names[i]), n_regs += 2; else if (regs_ever_live[i+1] && ! call_used_regs[i+1]) - fprintf (file, "\tld [%s+%d],%s\n", + fprintf (file, "\tld\t[%s+%d],%s\n", base, offset + 4 * n_regs + 4, reg_names[i+1]), n_regs += 2; } @@ -3152,9 +2831,9 @@ build_big_number (file, num, reg) { if (num >= 0 || ! TARGET_ARCH64) { - fprintf (file, "\tsethi %%hi(%d),%s\n", num, reg); + fprintf (file, "\tsethi\t%%hi(%d), %s\n", num, reg); if ((num & 0x3ff) != 0) - fprintf (file, "\tor %s,%%lo(%d),%s\n", reg, num, reg); + fprintf (file, "\tor\t%s, %%lo(%d), %s\n", reg, num, reg); } else /* num < 0 && TARGET_ARCH64 */ { @@ -3167,7 +2846,7 @@ build_big_number (file, num, reg) int inv = ~asize; int low = -0x400 + (asize & 0x3FF); - fprintf (file, "\tsethi %%hi(%d),%s\n\txor %s,%d,%s\n", + fprintf (file, "\tsethi\t%%hi(%d), %s\n\txor\t%s, %d, %s\n", inv, reg, reg, low, reg); } } @@ -3203,16 +2882,16 @@ output_function_prologue (file, size, leaf_function) else if (! leaf_function && ! TARGET_BROKEN_SAVERESTORE) { if (actual_fsize <= 4096) - fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize); + fprintf (file, "\tsave\t%%sp, -%d, %%sp\n", actual_fsize); else if (actual_fsize <= 8192) { - fprintf (file, "\tsave %%sp,-4096,%%sp\n"); - fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096); + fprintf (file, "\tsave\t%%sp, -4096, %%sp\n"); + fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096); } else { build_big_number (file, -actual_fsize, "%g1"); - fprintf (file, "\tsave %%sp,%%g1,%%sp\n"); + fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n"); } } else if (! leaf_function && TARGET_BROKEN_SAVERESTORE) @@ -3223,31 +2902,31 @@ output_function_prologue (file, size, leaf_function) fprintf (file, "\tsave\n"); if (actual_fsize <= 4096) - fprintf (file, "\tadd %%fp,-%d,%%sp\n", actual_fsize); + fprintf (file, "\tadd\t%%fp, -%d, %%sp\n", actual_fsize); else if (actual_fsize <= 8192) { - fprintf (file, "\tadd %%fp,-4096,%%sp\n"); - fprintf (file, "\tadd %%fp,-%d,%%sp\n", actual_fsize - 4096); + fprintf (file, "\tadd\t%%fp, -4096, %%sp\n"); + fprintf (file, "\tadd\t%%fp, -%d, %%sp\n", actual_fsize - 4096); } else { build_big_number (file, -actual_fsize, "%g1"); - fprintf (file, "\tadd %%fp,%%g1,%%sp\n"); + fprintf (file, "\tadd\t%%fp, %%g1, %%sp\n"); } } else /* leaf function */ { if (actual_fsize <= 4096) - fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize); + fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize); else if (actual_fsize <= 8192) { - fprintf (file, "\tadd %%sp,-4096,%%sp\n"); - fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096); + fprintf (file, "\tadd\t%%sp, -4096, %%sp\n"); + fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096); } else { build_big_number (file, -actual_fsize, "%g1"); - fprintf (file, "\tadd %%sp,%%g1,%%sp\n"); + fprintf (file, "\tadd\t%%sp, %%g1, %%sp\n"); } } @@ -3293,7 +2972,7 @@ output_function_prologue (file, size, leaf_function) output_function_epilogue will lose (the result will get clobbered). */ build_big_number (file, offset, "%g1"); - fprintf (file, "\tadd %s,%%g1,%%g1\n", frame_base_name); + fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name); base = "%g1"; offset = 0; } @@ -3348,12 +3027,13 @@ output_function_epilogue (file, size, leaf_function) else if (current_function_epilogue_delay_list == 0) { - /* If code does not drop into the epilogue, do nothing. */ + /* If code does not drop into the epilogue, we need + do nothing except output pending case vectors. */ rtx insn = get_last_insn (); if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) - return; + goto output_vectors; } /* Restore any call saved registers. */ @@ -3366,7 +3046,7 @@ output_function_epilogue (file, size, leaf_function) if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/) { build_big_number (file, offset, "%g1"); - fprintf (file, "\tadd %s,%%g1,%%g1\n", frame_base_name); + fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name); base = "%g1"; offset = 0; } @@ -3388,9 +3068,9 @@ output_function_epilogue (file, size, leaf_function) /* Work out how to skip the caller's unimp instruction if required. */ if (leaf_function) - ret = (SKIP_CALLERS_UNIMP_P ? "jmp %o7+12" : "retl"); + ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl"); else - ret = (SKIP_CALLERS_UNIMP_P ? "jmp %i7+12" : "ret"); + ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret"); if (TARGET_EPILOGUE || leaf_label) { @@ -3411,7 +3091,7 @@ output_function_epilogue (file, size, leaf_function) final_scan_insn (insn, file, 1, 0, 1); } else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P) - fputs ("\treturn %i7+8\n\tnop\n", file); + fputs ("\treturn\t%i7+8\n\tnop\n", file); else fprintf (file, "\t%s\n\trestore\n", ret); } @@ -3433,18 +3113,21 @@ output_function_epilogue (file, size, leaf_function) else if (actual_fsize == 0) fprintf (file, "\t%s\n\tnop\n", ret); else if (actual_fsize <= 4096) - fprintf (file, "\t%s\n\tsub %%sp,-%d,%%sp\n", ret, actual_fsize); + fprintf (file, "\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize); else if (actual_fsize <= 8192) - fprintf (file, "\tsub %%sp,-4096,%%sp\n\t%s\n\tsub %%sp,-%d,%%sp\n", + fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize - 4096); else if ((actual_fsize & 0x3ff) == 0) - fprintf (file, "\tsethi %%hi(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n", + fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", actual_fsize, ret); else - fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n", + fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", actual_fsize, actual_fsize, ret); target_flags |= old_target_epilogue; } + + output_vectors: + sparc_output_deferred_case_vectors (); } /* Functions for handling argument passing. @@ -4366,16 +4049,16 @@ output_cbranch (op, label, reversed, annul, noop, insn) int reversed, annul, noop; rtx insn; { - static char string[20]; + static char string[32]; enum rtx_code code = GET_CODE (op); rtx cc_reg = XEXP (op, 0); enum machine_mode mode = GET_MODE (cc_reg); - static char v8_labelno[] = " %lX"; - static char v9_icc_labelno[] = " %%icc,%lX"; - static char v9_xcc_labelno[] = " %%xcc,%lX"; - static char v9_fcc_labelno[] = " %%fccX,%lY"; + static char v8_labelno[] = "%lX"; + static char v9_icc_labelno[] = "%%icc, %lX"; + static char v9_xcc_labelno[] = "%%xcc, %lX"; + static char v9_fcc_labelno[] = "%%fccX, %lY"; char *labelno; - int labeloff; + int labeloff, spaces = 8; /* ??? !v9: FP branches cannot be preceded by another floating point insn. Because there is currently no concept of pre-delay slots, we can fix @@ -4396,16 +4079,28 @@ output_cbranch (op, label, reversed, annul, noop, insn) { case NE: if (mode == CCFPmode || mode == CCFPEmode) - strcat (string, "fbne"); + { + strcat (string, "fbne"); + spaces -= 4; + } else - strcpy (string, "bne"); + { + strcpy (string, "bne"); + spaces -= 3; + } break; case EQ: if (mode == CCFPmode || mode == CCFPEmode) - strcat (string, "fbe"); + { + strcat (string, "fbe"); + spaces -= 3; + } else - strcpy (string, "be"); + { + strcpy (string, "be"); + spaces -= 2; + } break; case GE: @@ -4415,23 +4110,39 @@ output_cbranch (op, label, reversed, annul, noop, insn) strcat (string, "fbul"); else strcat (string, "fbge"); + spaces -= 4; } else if (mode == CC_NOOVmode) - strcpy (string, "bpos"); + { + strcpy (string, "bpos"); + spaces -= 4; + } else - strcpy (string, "bge"); + { + strcpy (string, "bge"); + spaces -= 3; + } break; case GT: if (mode == CCFPmode || mode == CCFPEmode) { if (reversed) - strcat (string, "fbule"); + { + strcat (string, "fbule"); + spaces -= 5; + } else - strcat (string, "fbg"); + { + strcat (string, "fbg"); + spaces -= 3; + } } else - strcpy (string, "bg"); + { + strcpy (string, "bg"); + spaces -= 2; + } break; case LE: @@ -4441,52 +4152,75 @@ output_cbranch (op, label, reversed, annul, noop, insn) strcat (string, "fbug"); else strcat (string, "fble"); + spaces -= 4; } else - strcpy (string, "ble"); + { + strcpy (string, "ble"); + spaces -= 3; + } break; case LT: if (mode == CCFPmode || mode == CCFPEmode) { if (reversed) - strcat (string, "fbuge"); + { + strcat (string, "fbuge"); + spaces -= 5; + } else - strcat (string, "fbl"); + { + strcat (string, "fbl"); + spaces -= 3; + } } else if (mode == CC_NOOVmode) - strcpy (string, "bneg"); + { + strcpy (string, "bneg"); + spaces -= 4; + } else - strcpy (string, "bl"); + { + strcpy (string, "bl"); + spaces -= 2; + } break; case GEU: strcpy (string, "bgeu"); + spaces -= 4; break; case GTU: strcpy (string, "bgu"); + spaces -= 3; break; case LEU: strcpy (string, "bleu"); + spaces -= 4; break; case LTU: strcpy (string, "blu"); + spaces -= 3; break; default: - break; + abort (); } /* Now add the annulling, the label, and a possible noop. */ if (annul) - strcat (string, ",a"); + { + strcat (string, ",a"); + spaces -= 2; + } if (! TARGET_V9) { - labeloff = 3; + labeloff = 2; labelno = v8_labelno; } else @@ -4494,7 +4228,11 @@ output_cbranch (op, label, reversed, annul, noop, insn) rtx note; if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) - strcat (string, INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); + { + strcat (string, + INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); + spaces -= 3; + } labeloff = 9; if (mode == CCFPmode || mode == CCFPEmode) @@ -4502,7 +4240,7 @@ output_cbranch (op, label, reversed, annul, noop, insn) labeloff = 10; labelno = v9_fcc_labelno; /* Set the char indicating the number of the fcc reg to use. */ - labelno[6] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; + labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; } else if (mode == CCXmode || mode == CCX_NOOVmode) labelno = v9_xcc_labelno; @@ -4512,6 +4250,10 @@ output_cbranch (op, label, reversed, annul, noop, insn) /* Set the char indicating the number of the operand containing the label_ref. */ labelno[labeloff] = label + '0'; + if (spaces > 0) + strcat (string, "\t"); + else + strcat (string, " "); strcat (string, labelno); if (noop) @@ -4532,15 +4274,18 @@ output_cbranch (op, label, reversed, annul, noop, insn) NOOP is non-zero if we have to follow this branch by a noop. */ char * -output_v9branch (op, reg, label, reversed, annul, noop) +output_v9branch (op, reg, label, reversed, annul, noop, insn) rtx op; int reg, label; int reversed, annul, noop; + rtx insn; { static char string[20]; enum rtx_code code = GET_CODE (op); enum machine_mode mode = GET_MODE (XEXP (op, 0)); - static char labelno[] = " %X,%lX"; + static char labelno[] = "%X, %lX"; + rtx note; + int spaces = 8; /* If not floating-point or if EQ or NE, we can just reverse the code. */ if (reversed) @@ -4556,26 +4301,32 @@ output_v9branch (op, reg, label, reversed, annul, noop) { case NE: strcpy (string, "brnz"); + spaces -= 4; break; case EQ: strcpy (string, "brz"); + spaces -= 3; break; case GE: strcpy (string, "brgez"); + spaces -= 5; break; case LT: strcpy (string, "brlz"); + spaces -= 4; break; case LE: strcpy (string, "brlez"); + spaces -= 5; break; case GT: strcpy (string, "brgz"); + spaces -= 4; break; default: @@ -4584,12 +4335,24 @@ output_v9branch (op, reg, label, reversed, annul, noop) /* Now add the annulling, reg, label, and nop. */ if (annul) - strcat (string, ",a"); + { + strcat (string, ",a"); + spaces -= 2; + } - /* ??? Optional prediction bit ",pt" or ",pf" goes here. */ + if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) + { + strcat (string, + INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); + spaces -= 3; + } - labelno[2] = reg + '0'; + labelno[1] = reg + '0'; labelno[6] = label + '0'; + if (spaces > 0) + strcat (string, "\t"); + else + strcat (string, " "); strcat (string, labelno); if (noop) @@ -4681,24 +4444,24 @@ output_return (operands) if (actual_fsize <= 4096) { if (SKIP_CALLERS_UNIMP_P) - return "jmp %%o7+12\n\tsub %%sp,-%0,%%sp"; + return "jmp\t%%o7+12\n\tsub\t%%sp, -%0, %%sp"; else - return "retl\n\tsub %%sp,-%0,%%sp"; + return "retl\n\tsub\t%%sp, -%0, %%sp"; } else if (actual_fsize <= 8192) { operands[0] = GEN_INT (actual_fsize - 4096); if (SKIP_CALLERS_UNIMP_P) - return "sub %%sp,-4096,%%sp\n\tjmp %%o7+12\n\tsub %%sp,-%0,%%sp"; + return "sub\t%%sp, -4096, %%sp\n\tjmp\t%%o7+12\n\tsub\t%%sp, -%0, %%sp"; else - return "sub %%sp,-4096,%%sp\n\tretl\n\tsub %%sp,-%0,%%sp"; + return "sub\t%%sp, -4096, %%sp\n\tretl\n\tsub\t%%sp, -%0, %%sp"; } else if (SKIP_CALLERS_UNIMP_P) { if ((actual_fsize & 0x3ff) != 0) - return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp"; + return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tjmp\t%%o7+12\n\tadd\t%%sp, %%g1, %%sp"; else - return "sethi %%hi(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp"; + return "sethi\t%%hi(%a0), %%g1\n\tjmp\t%%o7+12\n\tadd\t%%sp, %%g1, %%sp"; } else { @@ -4716,16 +4479,16 @@ output_return (operands) epilogue_renumber (&SET_SRC (PATTERN (delay))); } if (SKIP_CALLERS_UNIMP_P) - return "return %%i7+12%#"; + return "return\t%%i7+12%#"; else - return "return %%i7+8%#"; + return "return\t%%i7+8%#"; } else { if (delay) abort (); if (SKIP_CALLERS_UNIMP_P) - return "jmp %%i7+12\n\trestore"; + return "jmp\t%%i7+12\n\trestore"; else return "ret\n\trestore"; } @@ -4756,6 +4519,34 @@ order_regs_for_local_alloc () } } +/* Return 1 if REG and MEM are legitimate enough to allow the various + mem<-->reg splits to be run. */ + +int +sparc_splitdi_legitimate(reg, mem) + rtx reg; + rtx mem; +{ + rtx addr_part = XEXP (mem, 0); + + /* Punt if we are here by mistake. */ + if (! reload_completed) + abort(); + + /* We must have an offsettable memory reference. */ + if (! offsettable_memref_p (mem)) + return 0; + + /* If we have legitimate args for ldd/std, we do not want + the split to happen. */ + if ((REGNO (reg) % 2) == 0 + && mem_min_alignment (mem, 8)) + return 0; + + /* Success. */ + return 1; +} + /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1. This makes them candidates for using ldd and std insns. @@ -4886,7 +4677,7 @@ print_operand (file, x, code) case '#': /* Output a 'nop' if there's nothing for the delay slot. */ if (dbr_sequence_length () == 0) - fputs ("\n\tnop", file); + fputs ("\n\t nop", file); return; case '*': /* Output an annul flag if there's nothing for the delay slot and we @@ -4904,7 +4695,7 @@ print_operand (file, x, code) not optimizing. This is always used with '*' above. */ if (dbr_sequence_length () == 0 && ! (optimize && (int)sparc_cpu < PROCESSOR_V9)) - fputs ("\n\tnop", file); + fputs ("\n\t nop", file); return; case '_': /* Output the Embedded Medium/Anywhere code model base register. */ @@ -5106,7 +4897,10 @@ print_operand (file, x, code) else if (GET_CODE (x) == LO_SUM) { print_operand (file, XEXP (x, 0), 0); - fputs ("+%lo(", file); + if (TARGET_CM_MEDMID) + fputs ("+%l44(", file); + else + fputs ("+%lo(", file); output_addr_const (file, XEXP (x, 1)); fputc (')', file); } @@ -5355,10 +5149,10 @@ sparc_initialize_trampoline (tramp, fnaddr, cxt) { /* SPARC 32 bit trampoline: - sethi %hi(fn),%g1 - sethi %hi(static),%g2 - jmp %g1+%lo(fn) - or %g2,%lo(static),%g2 + sethi %hi(fn), %g1 + sethi %hi(static), %g2 + jmp %g1+%lo(fn) + or %g2, %lo(static), %g2 SETHI i,r = 00rr rrr1 00ii iiii iiii iiii iiii iiii JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii @@ -5407,10 +5201,10 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt) rtx tramp, fnaddr, cxt; { /* - rd %pc,%g1 - ldx [%g1+24],%g5 - jmp %g5 - ldx [%g1+16],%g5 + rd %pc, %g1 + ldx [%g1+24], %g5 + jmp %g5 + ldx [%g1+16], %g5 +16 bytes data */ @@ -5676,7 +5470,7 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, if (word_op[0] == 's') { - fprintf (file, "\t%s %s,[%s+%d]\n", + fprintf (file, "\t%s\t%s, [%s+%d]\n", doubleword_op, reg_names[regno], base_reg, offset); if (dwarf2out_do_frame ()) @@ -5688,7 +5482,7 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, } } else - fprintf (file, "\t%s [%s+%d],%s\n", + fprintf (file, "\t%s\t[%s+%d], %s\n", doubleword_op, base_reg, offset, reg_names[regno]); @@ -5699,14 +5493,14 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, { if (word_op[0] == 's') { - fprintf (file, "\t%s %s,[%s+%d]\n", + fprintf (file, "\t%s\t%s, [%s+%d]\n", word_op, reg_names[regno], base_reg, offset); if (dwarf2out_do_frame ()) dwarf2out_reg_save ("", regno, offset + base_offset); } else - fprintf (file, "\t%s [%s+%d],%s\n", + fprintf (file, "\t%s\t[%s+%d], %s\n", word_op, base_reg, offset, reg_names[regno]); offset += UNITS_PER_WORD; @@ -5723,14 +5517,14 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, { if (word_op[0] == 's') { - fprintf (file, "\t%s %s,[%s+%d]\n", + fprintf (file, "\t%s\t%s, [%s+%d]\n", word_op, reg_names[regno], base_reg, offset); if (dwarf2out_do_frame ()) dwarf2out_reg_save ("", regno, offset + base_offset); } else - fprintf (file, "\t%s [%s+%d],%s\n", + fprintf (file, "\t%s\t[%s+%d], %s\n", word_op, base_reg, offset, reg_names[regno]); offset += UNITS_PER_WORD; @@ -5802,26 +5596,26 @@ sparc_flat_output_function_prologue (file, size) { if (size <= 4096) { - fprintf (file, "\tadd %s,%d,%s\n", + fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, -size, sp_str); if (gmask & FRAME_POINTER_MASK) { - fprintf (file, "\tst %s,[%s+%d]\n", + fprintf (file, "\tst\t%s, [%s+%d]\n", fp_str, sp_str, reg_offset); - fprintf (file, "\tsub %s,%d,%s\t%s# set up frame pointer\n", + fprintf (file, "\tsub\t%s, %d, %s\t%s# set up frame pointer\n", sp_str, -size, fp_str, ASM_COMMENT_START); reg_offset += 4; } } else { - fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n", + fprintf (file, "\tset\t%d, %s\n\tsub\t%s, %s, %s\n", size, t1_str, sp_str, t1_str, sp_str); if (gmask & FRAME_POINTER_MASK) { - fprintf (file, "\tst %s,[%s+%d]\n", + fprintf (file, "\tst\t%s, [%s+%d]\n", fp_str, sp_str, reg_offset); - fprintf (file, "\tadd %s,%s,%s\t%s# set up frame pointer\n", + fprintf (file, "\tadd\t%s, %s, %s\t%s# set up frame pointer\n", sp_str, t1_str, fp_str, ASM_COMMENT_START); reg_offset += 4; } @@ -5840,7 +5634,7 @@ sparc_flat_output_function_prologue (file, size) } if (gmask & RETURN_ADDR_MASK) { - fprintf (file, "\tst %s,[%s+%d]\n", + fprintf (file, "\tst\t%s, [%s+%d]\n", reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset); if (dwarf2out_do_frame ()) dwarf2out_return_save ("", reg_offset - size); @@ -5862,11 +5656,11 @@ sparc_flat_output_function_prologue (file, size) if (size1 <= 4096) { - fprintf (file, "\tadd %s,%d,%s\n", + fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, -size1, sp_str); if (gmask & FRAME_POINTER_MASK) { - fprintf (file, "\tst %s,[%s+%d]\n\tsub %s,%d,%s\t%s# set up frame pointer\n", + fprintf (file, "\tst\t%s, [%s+%d]\n\tsub\t%s, %d, %s\t%s# set up frame pointer\n", fp_str, sp_str, offset, sp_str, -size1, fp_str, ASM_COMMENT_START); offset += 4; @@ -5874,11 +5668,11 @@ sparc_flat_output_function_prologue (file, size) } else { - fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n", + fprintf (file, "\tset\t%d, %s\n\tsub\t%s, %s, %s\n", size1, t1_str, sp_str, t1_str, sp_str); if (gmask & FRAME_POINTER_MASK) { - fprintf (file, "\tst %s,[%s+%d]\n\tadd %s,%s,%s\t%s# set up frame pointer\n", + fprintf (file, "\tst\t%s, [%s+%d]\n\tadd\t%s, %s, %s\t%s# set up frame pointer\n", fp_str, sp_str, offset, sp_str, t1_str, fp_str, ASM_COMMENT_START); offset += 4; @@ -5898,7 +5692,7 @@ sparc_flat_output_function_prologue (file, size) } if (gmask & RETURN_ADDR_MASK) { - fprintf (file, "\tst %s,[%s+%d]\n", + fprintf (file, "\tst\t%s, [%s+%d]\n", reg_names[RETURN_ADDR_REGNUM], sp_str, offset); if (dwarf2out_do_frame ()) /* offset - size1 == reg_offset - size @@ -5910,7 +5704,7 @@ sparc_flat_output_function_prologue (file, size) gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), current_frame_info.fmask, "st", "std", -size1); - fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n", + fprintf (file, "\tset\t%d, %s\n\tsub\t%s, %s, %s\n", size - size1, t1_str, sp_str, t1_str, sp_str); if (dwarf2out_do_frame ()) if (! (gmask & FRAME_POINTER_MASK)) @@ -5970,15 +5764,15 @@ sparc_flat_output_function_epilogue (file, size) delay slot if not otherwise filled by the reload sequence. */ if (size > 4095) - fprintf (file, "\tset %d,%s\n", size, t1_str); + fprintf (file, "\tset\t%d, %s\n", size, t1_str); if (frame_pointer_needed) { if (size > 4095) - fprintf (file,"\tsub %s,%s,%s\t\t%s# sp not trusted here\n", + fprintf (file,"\tsub\t%s, %s, %s\t\t%s# sp not trusted here\n", fp_str, t1_str, sp_str, ASM_COMMENT_START); else - fprintf (file,"\tsub %s,%d,%s\t\t%s# sp not trusted here\n", + fprintf (file,"\tsub\t%s, %d, %s\t\t%s# sp not trusted here\n", fp_str, size, sp_str, ASM_COMMENT_START); } @@ -5996,7 +5790,7 @@ sparc_flat_output_function_epilogue (file, size) /* Offset to register save area from %sp. */ reg_offset = size1 - reg_offset; - fprintf (file, "\tset %d,%s\n\tadd %s,%s,%s\n", + fprintf (file, "\tset\t%d, %s\n\tadd\t%s, %s, %s\n", size1, t1_str, sp_str, t1_str, sp_str); } @@ -6004,13 +5798,13 @@ sparc_flat_output_function_epilogue (file, size) because they are treated specially by the prologue output code. */ if (current_frame_info.gmask & FRAME_POINTER_MASK) { - fprintf (file, "\tld [%s+%d],%s\n", + fprintf (file, "\tld\t[%s+%d], %s\n", sp_str, reg_offset, fp_str); reg_offset += 4; } if (current_frame_info.gmask & RETURN_ADDR_MASK) { - fprintf (file, "\tld [%s+%d],%s\n", + fprintf (file, "\tld\t[%s+%d], %s\n", sp_str, reg_offset, reg_names[RETURN_ADDR_REGNUM]); reg_offset += 4; } @@ -6027,12 +5821,12 @@ sparc_flat_output_function_epilogue (file, size) { size -= size1; if (size > 4095) - fprintf (file, "\tset %d,%s\n", + fprintf (file, "\tset\t%d, %s\n", size, t1_str); } if (current_function_returns_struct) - fprintf (file, "\tjmp %%o7+12\n"); + fprintf (file, "\tjmp\t%%o7+12\n"); else fprintf (file, "\tretl\n"); @@ -6049,10 +5843,10 @@ sparc_flat_output_function_epilogue (file, size) } else if (size > 4095) - fprintf (file, "\tadd %s,%s,%s\n", sp_str, t1_str, sp_str); + fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str); else if (size > 0) - fprintf (file, "\tadd %s,%d,%s\n", sp_str, size, sp_str); + fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, size, sp_str); else fprintf (file, "\tnop\n"); @@ -6060,6 +5854,8 @@ sparc_flat_output_function_epilogue (file, size) /* Reset state info for each function. */ current_frame_info = zero_frame_info; + + sparc_output_deferred_case_vectors (); } /* Define the number of delay slots needed for the function epilogue. @@ -6342,8 +6138,6 @@ set_extends(x, insn) /* LO_SUM is used with sethi. sethi cleared the high bits and the values used with lo_sum are positive */ case LO_SUM: - /* UNSPEC is v8plus_clear_high */ - case UNSPEC: /* Store flag stores 0 or 1 */ case LT: case LTU: case GT: case GTU: @@ -6380,6 +6174,86 @@ set_extends(x, insn) } } +/* We _ought_ to have only one kind per function, but... */ +static rtx sparc_addr_diff_list; +static rtx sparc_addr_list; + +void +sparc_defer_case_vector (lab, vec, diff) + rtx lab, vec; + int diff; +{ + vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec); + if (diff) + sparc_addr_diff_list + = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list); + else + sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list); +} + +static void +sparc_output_addr_vec (vec) + rtx vec; +{ + rtx lab = XEXP (vec, 0), body = XEXP (vec, 1); + int idx, vlen = XVECLEN (body, 0); + +#ifdef ASM_OUTPUT_CASE_LABEL + ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), + NEXT_INSN (lab)); +#else + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); +#endif + + for (idx = 0; idx < vlen; idx++) + { + ASM_OUTPUT_ADDR_VEC_ELT + (asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); + } +} + +static void +sparc_output_addr_diff_vec (vec) + rtx vec; +{ + rtx lab = XEXP (vec, 0), body = XEXP (vec, 1); + rtx base = XEXP (XEXP (body, 0), 0); + int idx, vlen = XVECLEN (body, 1); + +#ifdef ASM_OUTPUT_CASE_LABEL + ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), + NEXT_INSN (lab)); +#else + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); +#endif + + for (idx = 0; idx < vlen; idx++) + { + ASM_OUTPUT_ADDR_DIFF_ELT + (asm_out_file, + body, + CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), + CODE_LABEL_NUMBER (base)); + } +} + +static void +sparc_output_deferred_case_vectors () +{ + rtx t; + + /* Align to cache line in the function's code section. */ + function_section (current_function_decl); + ASM_OUTPUT_ALIGN (asm_out_file, 5); + + for (t = sparc_addr_list; t ; t = XEXP (t, 1)) + sparc_output_addr_vec (XEXP (t, 0)); + for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1)) + sparc_output_addr_diff_vec (XEXP (t, 0)); + + sparc_addr_list = sparc_addr_diff_list = NULL_RTX; +} + /* Return 0 if the high 32 bits of X (the low word of X, if DImode) are unknown. Return 1 if the high bits are zero, -1 if the register is sign extended. */ diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 1f21659178a..9749bd1a3b6 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -916,10 +916,8 @@ do \ { \ fixed_regs[5] = 1; \ } \ - else \ - { \ - fixed_regs[1] = 1; \ - } \ + if (TARGET_LIVE_G0) \ + fixed_regs[0] = 0; \ if (! TARGET_V9) \ { \ int regno; \ @@ -982,9 +980,15 @@ while (0) /* A subreg in 64 bit mode will have the wrong offset for a floating point register. The least significant part is at offset 1, compared to 0 for - integer registers. */ + integer registers. This only applies when FMODE is a larger mode. */ #define ALTER_HARD_SUBREG(TMODE, WORD, FMODE, REGNO) \ - (TARGET_ARCH64 && (REGNO) >= 32 && (REGNO) < 96 && (TMODE) == SImode ? 1 : ((REGNO) + (WORD))) + (TARGET_ARCH64 \ + && (REGNO) >= SPARC_FIRST_FP_REG \ + && (REGNO) <= SPARC_LAST_V9_FP_REG \ + && (TMODE) == SImode \ + && !((FMODE) == QImode || (FMODE) == HImode) \ + ? ((REGNO) + 1) \ + : ((REGNO) + (WORD))) /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. See sparc.c for how we initialize this. */ @@ -1356,24 +1360,39 @@ extern char leaf_reg_remap[]; /* Return the register class of a scratch register needed to load IN into a register of class CLASS in MODE. - On the SPARC, when PIC, we need a temporary when loading some addresses - into a register. - - Also, we need a temporary when loading/storing a HImode/QImode value + We need a temporary when loading/storing a HImode/QImode value between memory and the FPU registers. This can happen when combine puts a paradoxical subreg in a float/fix conversion insn. */ #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \ - ((FP_REG_CLASS_P (CLASS) && ((MODE) == HImode || (MODE) == QImode) \ + ((FP_REG_CLASS_P (CLASS) \ + && ((MODE) == HImode || (MODE) == QImode) \ && (GET_CODE (IN) == MEM \ - || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \ - && true_regnum (IN) == -1))) ? GENERAL_REGS : NO_REGS) + || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \ + && true_regnum (IN) == -1))) \ + ? GENERAL_REGS \ + : (((TARGET_CM_MEDANY \ + && symbolic_operand ((IN), (MODE))) \ + || (TARGET_CM_EMBMEDANY \ + && text_segment_operand ((IN), (MODE)))) \ + && !flag_pic) \ + ? GENERAL_REGS \ + : NO_REGS) #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, IN) \ - ((FP_REG_CLASS_P (CLASS) && ((MODE) == HImode || (MODE) == QImode) \ - && (GET_CODE (IN) == MEM \ - || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \ - && true_regnum (IN) == -1))) ? GENERAL_REGS : NO_REGS) + ((FP_REG_CLASS_P (CLASS) \ + && ((MODE) == HImode || (MODE) == QImode) \ + && (GET_CODE (IN) == MEM \ + || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \ + && true_regnum (IN) == -1))) \ + ? GENERAL_REGS \ + : (((TARGET_CM_MEDANY \ + && symbolic_operand ((IN), (MODE))) \ + || (TARGET_CM_EMBMEDANY \ + && text_segment_operand ((IN), (MODE)))) \ + && !flag_pic) \ + ? GENERAL_REGS \ + : NO_REGS) /* On SPARC it is not possible to directly move data between GENERAL_REGS and FP_REGS. */ @@ -2263,15 +2282,13 @@ extern struct rtx_def *sparc_builtin_saveregs (); After reload, it makes no difference, since pseudo regs have been eliminated by then. */ -/* Optional extra constraints for this machine. Borrowed from romp.h. +/* Optional extra constraints for this machine. - For the SPARC, `Q' means that this is a memory operand but not a - symbolic memory operand. Note that an unassigned pseudo register - is such a memory operand. Needed because reload will generate - these things in insns and then not re-recognize the insns, causing - constrain_operands to fail. + 'T' handles memory addresses where the alignment is known to + be at least 8 bytes. - `S' handles constraints for calls. ??? So where is it? */ + `U' handles all pseudo registers or a hard even numbered + integer register, needed for ldd/std instructions. */ #ifndef REG_OK_STRICT @@ -2287,17 +2304,11 @@ extern struct rtx_def *sparc_builtin_saveregs (); /* 'T', 'U' are for aligned memory loads which aren't needed for v9. */ #define EXTRA_CONSTRAINT(OP, C) \ - ((C) == 'Q' \ - ? ((GET_CODE (OP) == MEM \ - && memory_address_p (GET_MODE (OP), XEXP (OP, 0)) \ - && ! symbolic_memory_operand (OP, VOIDmode)) \ - || (reload_in_progress && GET_CODE (OP) == REG \ - && REGNO (OP) >= FIRST_PSEUDO_REGISTER)) \ - : (! TARGET_ARCH64 && (C) == 'T') \ - ? (mem_aligned_8 (OP)) \ - : (! TARGET_ARCH64 && (C) == 'U') \ - ? (register_ok_for_ldd (OP)) \ - : 0) + ((! TARGET_ARCH64 && (C) == 'T') \ + ? (mem_min_alignment (OP, 8)) \ + : ((! TARGET_ARCH64 && (C) == 'U') \ + ? (register_ok_for_ldd (OP)) \ + : 0)) #else @@ -2307,19 +2318,14 @@ extern struct rtx_def *sparc_builtin_saveregs (); #define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) #define EXTRA_CONSTRAINT(OP, C) \ - ((C) == 'Q' \ - ? (GET_CODE (OP) == REG \ - ? (REGNO (OP) >= FIRST_PSEUDO_REGISTER \ - && reg_renumber[REGNO (OP)] < 0) \ - : GET_CODE (OP) == MEM) \ - : (! TARGET_ARCH64 && (C) == 'T') \ - ? mem_aligned_8 (OP) && strict_memory_address_p (Pmode, XEXP (OP, 0)) \ - : (! TARGET_ARCH64 && (C) == 'U') \ - ? (GET_CODE (OP) == REG \ - && (REGNO (OP) < FIRST_PSEUDO_REGISTER \ - || reg_renumber[REGNO (OP)] >= 0) \ - && register_ok_for_ldd (OP)) \ - : 0) + ((! TARGET_ARCH64 && (C) == 'T') \ + ? mem_min_alignment (OP, 8) && strict_memory_address_p (Pmode, XEXP (OP, 0)) \ + : ((! TARGET_ARCH64 && (C) == 'U') \ + ? (GET_CODE (OP) == REG \ + && (REGNO (OP) < FIRST_PSEUDO_REGISTER \ + || reg_renumber[REGNO (OP)] >= 0) \ + && register_ok_for_ldd (OP)) \ + : 0)) #endif /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression @@ -2387,8 +2393,8 @@ extern struct rtx_def *sparc_builtin_saveregs (); && CONSTANT_P (op1) \ /* We can't allow TFmode, because an offset \ greater than or equal to the alignment (8) \ - may cause the LO_SUM to overflow. */ \ - && MODE != TFmode) \ + may cause the LO_SUM to overflow if !v9. */\ + && (MODE != TFmode || TARGET_V9)) \ goto ADDR; \ } \ else if (GET_CODE (X) == CONST_INT && SMALL_INT (X)) \ @@ -2435,8 +2441,7 @@ extern struct rtx_def *legitimize_pic_address (); copy_to_mode_reg (Pmode, XEXP (X, 0))); \ else if (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST \ || GET_CODE (X) == LABEL_REF) \ - (X) = gen_rtx_LO_SUM (Pmode, \ - copy_to_mode_reg (Pmode, gen_rtx_HIGH (Pmode, X)), X); \ + (X) = copy_to_suggested_reg (X, NULL_RTX, Pmode); \ if (memory_address_p (MODE, X)) \ goto WIN; } @@ -2676,9 +2681,6 @@ extern struct rtx_def *legitimize_pic_address (); return 0; \ return 8; -/* Compute the cost of an address. For the sparc, all valid addresses are - the same cost. */ - #define ADDRESS_COST(RTX) 1 /* Compute extra cost of moving data between one register class @@ -2920,6 +2922,15 @@ extern struct rtx_def *legitimize_pic_address (); #define ASM_OUTPUT_BYTE(FILE,VALUE) \ fprintf (FILE, "\t%s\t0x%x\n", ASM_BYTE_OP, (VALUE)) +/* This is how we hook in and defer the case-vector until the end of + the function. */ + +#define ASM_OUTPUT_ADDR_VEC(LAB,VEC) \ + sparc_defer_case_vector ((LAB),(VEC), 0) + +#define ASM_OUTPUT_ADDR_DIFF_VEC(LAB,VEC) \ + sparc_defer_case_vector ((LAB),(VEC), 1) + /* This is how to output an element of a case-vector that is absolute. */ #define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ @@ -2933,7 +2944,7 @@ do { \ else \ fprintf (FILE, "\t.xword\t"); \ assemble_name (FILE, label); \ - fprintf (FILE, "\n"); \ + fputc ('\n', FILE); \ } while (0) /* This is how to output an element of a case-vector that is relative. @@ -2942,7 +2953,7 @@ do { \ #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ do { \ char label[30]; \ - ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \ + ASM_GENERATE_INTERNAL_LABEL (label, "L", (VALUE)); \ if (Pmode == SImode) \ fprintf (FILE, "\t.word\t"); \ else if (TARGET_CM_MEDLOW) \ @@ -2950,7 +2961,10 @@ do { \ else \ fprintf (FILE, "\t.xword\t"); \ assemble_name (FILE, label); \ - fprintf (FILE, "-1b\n"); \ + ASM_GENERATE_INTERNAL_LABEL (label, "L", (REL)); \ + fputc ('-', FILE); \ + assemble_name (FILE, label); \ + fputc ('\n', FILE); \ } while (0) /* This is how to output an assembler line @@ -3116,7 +3130,10 @@ do { \ else if (GET_CODE (addr) == LO_SUM) \ { \ output_operand (XEXP (addr, 0), 0); \ - fputs ("+%lo(", FILE); \ + if (TARGET_CM_MEDMID) \ + fputs ("+%l44(", FILE); \ + else \ + fputs ("+%lo(", FILE); \ output_address (XEXP (addr, 1)); \ fputc (')', FILE); \ } \ @@ -3160,15 +3177,12 @@ do { \ {"data_segment_operand", {SYMBOL_REF, PLUS, CONST}}, \ {"text_segment_operand", {LABEL_REF, SYMBOL_REF, PLUS, CONST}}, \ {"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \ -{"sparc_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, MEM}}, \ -{"move_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE, MEM}}, \ {"splittable_symbolic_memory_operand", {MEM}}, \ {"splittable_immediate_memory_operand", {MEM}}, \ {"eq_or_neq", {EQ, NE}}, \ {"normal_comp_operator", {GE, GT, LE, LT, GTU, LEU}}, \ {"noov_compare_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \ {"v9_regcmp_op", {EQ, NE, GE, LT, LE, GT}}, \ -{"v8plus_regcmp_op", {EQ, NE}}, \ {"extend_op", {SIGN_EXTEND, ZERO_EXTEND}}, \ {"cc_arithop", {AND, IOR, XOR}}, \ {"cc_arithopn", {AND, IOR}}, \ @@ -3179,9 +3193,12 @@ do { \ {"arith11_double_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE}}, \ {"arith10_double_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE}}, \ {"small_int", {CONST_INT, CONSTANT_P_RTX}}, \ +{"small_int_or_double", {CONST_INT, CONST_DOUBLE, CONSTANT_P_RTX}}, \ {"uns_small_int", {CONST_INT, CONSTANT_P_RTX}}, \ {"uns_arith_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{"clobbered_register", {REG}}, +{"clobbered_register", {REG}}, \ +{"input_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, MEM}}, \ +{"zero_operand", {CONST_INT, CONSTANT_P_RTX}}, /* The number of Pmode words for the setjmp buffer. */ @@ -3191,17 +3208,14 @@ do { \ /* Declare functions defined in sparc.c and used in templates. */ -extern char *doublemove_string (); -extern char *output_block_move (); +extern void sparc_emit_set_const32 (); +extern void sparc_emit_set_const64 (); +extern void sparc_emit_set_symbolic_const64 (); +extern int sparc_splitdi_legitimate (); + extern char *output_cbranch (); -extern char *output_fp_move_double (); -extern char *output_fp_move_quad (); -extern char *output_move_double (); -extern char *output_move_quad (); extern char *output_return (); -extern char *output_scc_insn (); extern char *output_v9branch (); -extern char *singlemove_string (); extern void emit_v9_brxx_insn (); extern void finalize_pic (); @@ -3221,6 +3235,8 @@ extern int arith11_operand (); extern int arith_double_operand (); extern int arith_operand (); extern int call_operand_address (); +extern int input_operand (); +extern int zero_operand (); extern int cc_arithop (); extern int cc_arithopn (); extern int check_pic (); @@ -3234,8 +3250,7 @@ extern int fcc_reg_operand (); extern int fp_zero_operand (); extern int icc_or_fcc_reg_operand (); extern int label_ref_operand (); -extern int mem_aligned_8 (); -extern int move_operand (); +extern int mem_min_alignment (); extern int noov_compare_op (); extern int pic_address_needs_scratch (); extern int reg_or_0_operand (); @@ -3246,11 +3261,11 @@ extern int registers_ok_for_ldd_peep (); extern int restore_operand (); extern int short_branch (); extern int small_int (); +extern int small_int_or_double (); extern int sp64_medium_pic_operand (); extern int sparc_flat_eligible_for_epilogue_delay (); extern int sparc_flat_epilogue_delay_slots (); extern int sparc_issue_rate (); -extern int sparc_operand (); extern int splittable_immediate_memory_operand (); extern int splittable_symbolic_memory_operand (); extern int supersparc_adjust_cost (); @@ -3259,8 +3274,6 @@ extern int symbolic_operand (); extern int text_segment_operand (); extern int ultrasparc_adjust_cost (); extern int uns_small_int (); -extern int v8plus_regcmp_op (); -extern int v8plus_regcmp_p (); extern int v9_regcmp_op (); extern int v9_regcmp_p (); diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 47d2d3de7ad..5cf7e807db4 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -23,6 +23,35 @@ ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;; Uses of UNSPEC and UNSPEC_VOLATILE in this file: +;; +;; UNSPEC: 0 movsi_{lo_sum,high}_pic +;; pic_lo_sum_di +;; pic_sethi_di +;; 1 update_return +;; 2 get_pc +;; 5 movsi_{,lo_sum_,high_}pic_label_ref +;; 6 seth44 +;; 7 setm44 +;; 8 setl44 +;; 9 sethh +;; 10 setlm +;; 11 embmedany_sethi, embmedany_brsum +;; 13 embmedany_textuhi +;; 14 embmedany_texthi +;; 15 embmedany_textulo +;; 16 embmedany_textlo +;; 18 sethm +;; 19 setlo +;; +;; UNSPEC_VOLATILE: 0 blockage +;; 1 flush_register_windows +;; 2 goto_handler_and_restore +;; 3 goto_handler_and_restore_v9* +;; 4 flush +;; 5 nonlocal_goto_receiver +;; + ;; The upper 32 fp regs on the v9 can't hold SFmode values. To deal with this ;; a second register class, EXTRA_FP_REGS, exists for the v9 chip. The name ;; is a bit of a misnomer as it covers all 64 fp regs. The corresponding @@ -130,7 +159,6 @@ (define_attr "leaf_function" "false,true" (const (symbol_ref "leaf_function"))) - (define_attr "in_return_delay" "false,true" (if_then_else (and (and (and (eq_attr "type" "move,load,sload,store,binary,ialu") (eq_attr "length" "1")) @@ -370,21 +398,26 @@ (eq_attr "type" "store,fpstore")) 1 1) -(define_function_unit "ieu" 1 0 +(define_function_unit "ieu_unnamed" 2 0 (and (eq_attr "cpu" "ultrasparc") - (eq_attr "type" "ialu,binary,shift,compare,cmove,call")) + (eq_attr "type" "ialu,binary,move,unary,shift,cmove,compare,call")) 1 1) -(define_function_unit "ieu_shift" 1 0 +(define_function_unit "ieu0" 1 0 (and (eq_attr "cpu" "ultrasparc") (eq_attr "type" "shift")) 1 1) -(define_function_unit "ieu_shift" 1 0 +(define_function_unit "ieu0" 1 0 (and (eq_attr "cpu" "ultrasparc") (eq_attr "type" "cmove")) 2 1) +(define_function_unit "ieu1" 1 0 + (and (eq_attr "cpu" "ultrasparc") + (eq_attr "type" "compare,call,uncond_branch")) + 1 1) + ;; Timings; throughput/latency ;; FMOV 1/1 fmov, fabs, fneg ;; FMOVcc 1/2 @@ -395,6 +428,11 @@ ;; FSQRTs 12/12 ;; FSQRTd 22/22 ;; FCMP takes 1 cycle to branch, 2 cycles to conditional move. +;; +;; ??? This is really bogus because the timings really depend upon +;; who uses the result. We should record who the user is with +;; more descriptive 'type' attribute names and account for these +;; issues in ultrasparc_adjust_cost. (define_function_unit "fadd" 1 0 (and (eq_attr "cpu" "ultrasparc") @@ -426,17 +464,17 @@ (eq_attr "type" "fpcmove")) 2 1) -(define_function_unit "fadd" 1 0 +(define_function_unit "fmul" 1 0 (and (eq_attr "cpu" "ultrasparc") (eq_attr "type" "fpdivs")) 12 12) -(define_function_unit "fadd" 1 0 +(define_function_unit "fmul" 1 0 (and (eq_attr "cpu" "ultrasparc") (eq_attr "type" "fpdivd")) 22 22) -(define_function_unit "fadd" 1 0 +(define_function_unit "fmul" 1 0 (and (eq_attr "cpu" "ultrasparc") (eq_attr "type" "fpsqrt")) 12 12) @@ -475,7 +513,7 @@ [(set (reg:CCX 100) (compare:CCX (match_operand:DI 0 "register_operand" "") (match_operand:DI 1 "arith_double_operand" "")))] - "TARGET_ARCH64 || TARGET_V8PLUS" + "TARGET_ARCH64" " { sparc_compare_op0 = operands[0]; @@ -524,12 +562,20 @@ ;; Now the compare DEFINE_INSNs. -(define_insn "*cmpsi_insn" +(define_insn "*cmpsi_insn_sp32" [(set (reg:CC 100) (compare:CC (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "arith_operand" "rI")))] - "" - "cmp %0,%1" + "TARGET_ARCH32" + "cmp\\t%0, %1" + [(set_attr "type" "compare")]) + +(define_insn "*cmpsi_insn_sp64" + [(set (reg:CC 100) + (compare:CC (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_double_operand" "rHI")))] + "TARGET_ARCH64" + "cmp\\t%0, %1" [(set_attr "type" "compare")]) (define_insn "*cmpdi_sp64" @@ -537,42 +583,9 @@ (compare:CCX (match_operand:DI 0 "register_operand" "r") (match_operand:DI 1 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "cmp %0,%1" + "cmp\\t%0, %1" [(set_attr "type" "compare")]) -(define_insn "cmpdi_v8plus" - [(set (reg:CCX 100) - (compare:CCX (match_operand:DI 0 "register_operand" "r,r,r") - (match_operand:DI 1 "arith_double_operand" "J,I,r"))) - (clobber (match_scratch:SI 2 "=&h,&h,&h")) - (clobber (match_scratch:SI 3 "=X,X,&h"))] - "TARGET_V8PLUS" - "* -{ - /* The srl can be omitted if the value in the %L0 or %L1 is already - zero extended. */ - - output_asm_insn (\"sllx %H0,32,%2\", operands); - - if (sparc_check_64 (operands[0], insn) <= 0) - output_asm_insn (\"srl %L0,0,%L0\", operands); - - switch (which_alternative) - { - case 0: - return \"orcc %L0,%2,%%g0\"; - case 1: - return \"or %L0,%2,%2\;cmp %2,%1\"; - case 2: - if (sparc_check_64 (operands[1], insn) <= 0) - output_asm_insn (\"srl %L1,0,%L1\", operands); - return \"sllx %H1,32,%3\;or %L0,%2,%2\;or %L1,%3,%3\;cmp %2,%3\"; - default: - abort(); - } -}" - [(set_attr "length" "3,4,7")]) - (define_insn "*cmpsf_fpe" [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c") (compare:CCFPE (match_operand:SF 1 "register_operand" "f") @@ -581,8 +594,8 @@ "* { if (TARGET_V9) - return \"fcmpes %0,%1,%2\"; - return \"fcmpes %1,%2\"; + return \"fcmpes\\t%0, %1, %2\"; + return \"fcmpes\\t%1, %2\"; }" [(set_attr "type" "fpcmp")]) @@ -594,8 +607,8 @@ "* { if (TARGET_V9) - return \"fcmped %0,%1,%2\"; - return \"fcmped %1,%2\"; + return \"fcmped\\t%0, %1, %2\"; + return \"fcmped\\t%1, %2\"; }" [(set_attr "type" "fpcmp")]) @@ -607,8 +620,8 @@ "* { if (TARGET_V9) - return \"fcmpeq %0,%1,%2\"; - return \"fcmpeq %1,%2\"; + return \"fcmpeq\\t%0, %1, %2\"; + return \"fcmpeq\\t%1, %2\"; }" [(set_attr "type" "fpcmp")]) @@ -620,8 +633,8 @@ "* { if (TARGET_V9) - return \"fcmps %0,%1,%2\"; - return \"fcmps %1,%2\"; + return \"fcmps\\t%0, %1, %2\"; + return \"fcmps\\t%1, %2\"; }" [(set_attr "type" "fpcmp")]) @@ -633,8 +646,8 @@ "* { if (TARGET_V9) - return \"fcmpd %0,%1,%2\"; - return \"fcmpd %1,%2\"; + return \"fcmpd\\t%0, %1, %2\"; + return \"fcmpd\\t%1, %2\"; }" [(set_attr "type" "fpcmp")]) @@ -646,8 +659,8 @@ "* { if (TARGET_V9) - return \"fcmpq %0,%1,%2\"; - return \"fcmpq %1,%2\"; + return \"fcmpq\\t%0, %1, %2\"; + return \"fcmpq\\t%1, %2\"; }" [(set_attr "type" "fpcmp")]) @@ -787,7 +800,7 @@ DONE; /* fall through */ } - operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1); + FAIL; }") ;; ??? v9: Operand 0 needs a mode, so SImode was chosen. @@ -840,7 +853,7 @@ DONE; /* fall through */ } - operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "sgt" @@ -861,7 +874,7 @@ DONE; /* fall through */ } - operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "slt" @@ -882,7 +895,7 @@ DONE; /* fall through */ } - operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "sge" @@ -903,7 +916,7 @@ DONE; /* fall through */ } - operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "sle" @@ -924,7 +937,7 @@ DONE; /* fall through */ } - operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "sgtu" @@ -935,7 +948,7 @@ { if (! TARGET_V9) { - rtx tem; + rtx tem, pat; /* We can do ltu easily, so if both operands are registers, swap them and do a LTU. */ @@ -947,7 +960,10 @@ tem = sparc_compare_op0; sparc_compare_op0 = sparc_compare_op1; sparc_compare_op1 = tem; - emit_insn (gen_sltu (operands[0])); + pat = gen_sltu (operands[0]); + if (pat == NULL_RTX) + FAIL; + emit_insn (pat); DONE; } } @@ -956,7 +972,7 @@ if (gen_v9_scc (GTU, operands)) DONE; } - operands[1] = gen_compare_reg (GTU, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "sltu" @@ -970,7 +986,8 @@ if (gen_v9_scc (LTU, operands)) DONE; } - operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1); + /* XXX less than unsigned == Carry */ + FAIL; }") (define_expand "sgeu" @@ -984,7 +1001,7 @@ if (gen_v9_scc (GEU, operands)) DONE; } - operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1); + FAIL; }") (define_expand "sleu" @@ -995,7 +1012,7 @@ { if (! TARGET_V9) { - rtx tem; + rtx tem, pat; /* We can do geu easily, so if both operands are registers, swap them and do a GEU. */ @@ -1007,7 +1024,10 @@ tem = sparc_compare_op0; sparc_compare_op0 = sparc_compare_op1; sparc_compare_op1 = tem; - emit_insn (gen_sgeu (operands[0])); + pat = gen_sgeu (operands[0]); + if (pat == NULL_RTX) + FAIL; + emit_insn (pat); DONE; } } @@ -1016,13 +1036,15 @@ if (gen_v9_scc (LEU, operands)) DONE; } - operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1); + FAIL; }") ;; Now the DEFINE_INSNs for the scc cases. ;; The SEQ and SNE patterns are special because they can be done -;; without any branching and do not involve a COMPARE. +;; without any branching and do not involve a COMPARE. We want +;; them to always use the splitz below so the results can be +;; scheduled. (define_insn "*snesi_zero" [(set (match_operand:SI 0 "register_operand" "=r") @@ -1030,9 +1052,19 @@ (const_int 0))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;addx %%g0,0,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) + "#" + [(set_attr "length" "2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (ne:SI (match_operand:SI 1 "register_operand" "") + (const_int 0))) + (clobber (reg:CC 100))] + "" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (ltu:SI (reg:CC 100) (const_int 0)))] + "") (define_insn "*neg_snesi_zero" [(set (match_operand:SI 0 "register_operand" "=r") @@ -1040,9 +1072,19 @@ (const_int 0)))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;subx %%g0,0,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) + "#" + [(set_attr "length" "2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (neg:SI (ne:SI (match_operand:SI 1 "register_operand" "") + (const_int 0)))) + (clobber (reg:CC 100))] + "" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (neg:SI (ltu:SI (reg:CC 100) (const_int 0))))] + "") (define_insn "*snesi_zero_extend" [(set (match_operand:DI 0 "register_operand" "=r") @@ -1050,46 +1092,105 @@ (const_int 0))) (clobber (reg:CC 100))] "TARGET_ARCH64" - "subcc %%g0,%1,%%g0\;addx %%g0,0,%0" + "#" [(set_attr "type" "unary") (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ne:SI (match_operand:SI 1 "register_operand" "") + (const_int 0))) + (clobber (reg:CC 100))] + "TARGET_ARCH64 + && reload_completed" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (minus (const_int 0) (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (minus:SI (minus:SI (const_int 0) (const_int 0)) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "") + (define_insn "*snedi_zero" [(set (match_operand:DI 0 "register_operand" "=&r") (ne:DI (match_operand:DI 1 "register_operand" "r") (const_int 0)))] "TARGET_ARCH64" - "mov 0,%0\;movrnz %1,1,%0" + "#" [(set_attr "type" "cmove") (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ne:DI (match_operand:DI 1 "register_operand" "") + (const_int 0)))] + "TARGET_ARCH64" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) (if_then_else:DI (ne:DI (match_dup 1) + (const_int 0)) + (const_int 1) + (match_dup 0)))] + "") + (define_insn "*neg_snedi_zero" [(set (match_operand:DI 0 "register_operand" "=&r") (neg:DI (ne:DI (match_operand:DI 1 "register_operand" "r") (const_int 0))))] "TARGET_ARCH64" - "mov 0,%0\;movrnz %1,-1,%0" + "#" [(set_attr "type" "cmove") (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (ne:DI (match_operand:DI 1 "register_operand" "") + (const_int 0))))] + "TARGET_ARCH64" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) (if_then_else:DI (ne:DI (match_dup 1) + (const_int 0)) + (const_int -1) + (match_dup 0)))] + "") + (define_insn "*snedi_zero_trunc" [(set (match_operand:SI 0 "register_operand" "=&r") (ne:DI (match_operand:DI 1 "register_operand" "r") (const_int 0)))] "TARGET_ARCH64" - "mov 0,%0\;movrnz %1,1,%0" + "#" [(set_attr "type" "cmove") (set_attr "length" "2")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (ne:DI (match_operand:DI 1 "register_operand" "") + (const_int 0)))] + "TARGET_ARCH64" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) (if_then_else:DI (ne:DI (match_dup 1) + (const_int 0)) + (const_int 1) + (match_dup 0)))] + "") + (define_insn "*seqsi_zero" [(set (match_operand:SI 0 "register_operand" "=r") (eq:SI (match_operand:SI 1 "register_operand" "r") (const_int 0))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;subx %%g0,-1,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) + "#" + [(set_attr "length" "2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (eq:SI (match_operand:SI 1 "register_operand" "") + (const_int 0))) + (clobber (reg:CC 100))] + "" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (geu:SI (reg:CC 100) (const_int 0)))] + "") (define_insn "*neg_seqsi_zero" [(set (match_operand:SI 0 "register_operand" "=r") @@ -1097,9 +1198,19 @@ (const_int 0)))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;addx %%g0,-1,%0" - [(set_attr "type" "unary") - (set_attr "length" "2")]) + "#" + [(set_attr "length" "2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (neg:SI (eq:SI (match_operand:SI 1 "register_operand" "") + (const_int 0)))) + (clobber (reg:CC 100))] + "" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (neg:SI (geu:SI (reg:CC 100) (const_int 0))))] + "") (define_insn "*seqsi_zero_extend" [(set (match_operand:DI 0 "register_operand" "=r") @@ -1107,37 +1218,85 @@ (const_int 0))) (clobber (reg:CC 100))] "TARGET_ARCH64" - "subcc %%g0,%1,%%g0\;subx %%g0,-1,%0" + "#" [(set_attr "type" "unary") (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (eq:SI (match_operand:SI 1 "register_operand" "") + (const_int 0))) + (clobber (reg:CC 100))] + "TARGET_ARCH64" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (minus:SI (const_int 0) (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (minus:SI (minus:SI (const_int 0) (const_int -1)) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "") + (define_insn "*seqdi_zero" [(set (match_operand:DI 0 "register_operand" "=&r") (eq:DI (match_operand:DI 1 "register_operand" "r") (const_int 0)))] "TARGET_ARCH64" - "mov 0,%0\;movrz %1,1,%0" + "#" [(set_attr "type" "cmove") (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (eq:DI (match_operand:DI 1 "register_operand" "") + (const_int 0)))] + "TARGET_ARCH64" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) (if_then_else:DI (eq:DI (match_dup 1) + (const_int 0)) + (const_int 1) + (match_dup 0)))] + "") + (define_insn "*neg_seqdi_zero" [(set (match_operand:DI 0 "register_operand" "=&r") (neg:DI (eq:DI (match_operand:DI 1 "register_operand" "r") (const_int 0))))] "TARGET_ARCH64" - "mov 0,%0\;movrz %1,-1,%0" + "#" [(set_attr "type" "cmove") (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (eq:DI (match_operand:DI 1 "register_operand" "") + (const_int 0))))] + "TARGET_ARCH64" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) (if_then_else:DI (eq:DI (match_dup 1) + (const_int 0)) + (const_int -1) + (match_dup 0)))] + "") + (define_insn "*seqdi_zero_trunc" [(set (match_operand:SI 0 "register_operand" "=&r") (eq:DI (match_operand:DI 1 "register_operand" "r") (const_int 0)))] "TARGET_ARCH64" - "mov 0,%0\;movrz %1,1,%0" + "#" [(set_attr "type" "cmove") (set_attr "length" "2")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (eq:DI (match_operand:DI 1 "register_operand" "") + (const_int 0)))] + "TARGET_ARCH64" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) (if_then_else:DI (eq:DI (match_dup 1) + (const_int 0)) + (const_int 1) + (match_dup 0)))] + "") + ;; We can also do (x + (i == 0)) and related, so put them in. ;; ??? The addx/subx insns use the 32 bit carry flag so there are no DImode ;; versions for v9. @@ -1149,9 +1308,22 @@ (match_operand:SI 2 "register_operand" "r"))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;addx %2,0,%0" + "#" [(set_attr "length" "2")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (ne:SI (match_operand:SI 1 "register_operand" "") + (const_int 0)) + (match_operand:SI 2 "register_operand" ""))) + (clobber (reg:CC 100))] + "! TARGET_LIVE_G0" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (plus:SI (ltu:SI (reg:CC 100) (const_int 0)) + (match_dup 2)))] + "") + (define_insn "*x_minus_i_ne_0" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 2 "register_operand" "r") @@ -1159,9 +1331,22 @@ (const_int 0)))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;subx %2,0,%0" + "#" [(set_attr "length" "2")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (minus:SI (match_operand:SI 2 "register_operand" "") + (ne:SI (match_operand:SI 1 "register_operand" "") + (const_int 0)))) + (clobber (reg:CC 100))] + "! TARGET_LIVE_G0" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (minus:SI (match_dup 2) + (ltu:SI (reg:CC 100) (const_int 0))))] + "") + (define_insn "*x_plus_i_eq_0" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (eq:SI (match_operand:SI 1 "register_operand" "r") @@ -1169,9 +1354,22 @@ (match_operand:SI 2 "register_operand" "r"))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;subx %2,-1,%0" + "#" [(set_attr "length" "2")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (eq:SI (match_operand:SI 1 "register_operand" "") + (const_int 0)) + (match_operand:SI 2 "register_operand" ""))) + (clobber (reg:CC 100))] + "! TARGET_LIVE_G0" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (plus:SI (geu:SI (reg:CC 100) (const_int 0)) + (match_dup 2)))] + "") + (define_insn "*x_minus_i_eq_0" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 2 "register_operand" "r") @@ -1179,9 +1377,22 @@ (const_int 0)))) (clobber (reg:CC 100))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%%g0\;addx %2,-1,%0" + "#" [(set_attr "length" "2")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (minus:SI (match_operand:SI 2 "register_operand" "") + (eq:SI (match_operand:SI 1 "register_operand" "") + (const_int 0)))) + (clobber (reg:CC 100))] + "! TARGET_LIVE_G0" + [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) (minus:SI (match_dup 2) + (geu:SI (reg:CC 100) (const_int 0))))] + "") + ;; We can also do GEU and LTU directly, but these operate after a compare. ;; ??? The addx/subx insns use the 32 bit carry flag so there are no DImode ;; versions for v9. @@ -1190,15 +1401,17 @@ [(set (match_operand:SI 0 "register_operand" "=r") (ltu:SI (reg:CC 100) (const_int 0)))] "! TARGET_LIVE_G0" - "addx %%g0,0,%0" - [(set_attr "type" "misc")]) + "addx\\t%%g0, 0, %0" + [(set_attr "type" "misc") + (set_attr "length" "1")]) (define_insn "*neg_sltu_insn" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (ltu:SI (reg:CC 100) (const_int 0))))] "! TARGET_LIVE_G0" - "subx %%g0,0,%0" - [(set_attr "type" "misc")]) + "subx\\t%%g0, 0, %0" + [(set_attr "type" "misc") + (set_attr "length" "1")]) ;; ??? Combine should canonicalize these next two to the same pattern. (define_insn "*neg_sltu_minus_x" @@ -1206,30 +1419,34 @@ (minus:SI (neg:SI (ltu:SI (reg:CC 100) (const_int 0))) (match_operand:SI 1 "arith_operand" "rI")))] "! TARGET_LIVE_G0" - "subx %%g0,%1,%0" - [(set_attr "type" "unary")]) + "subx\\t%%g0, %1, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) (define_insn "*neg_sltu_plus_x" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (plus:SI (ltu:SI (reg:CC 100) (const_int 0)) (match_operand:SI 1 "arith_operand" "rI"))))] "! TARGET_LIVE_G0" - "subx %%g0,%1,%0" - [(set_attr "type" "unary")]) + "subx\\t%%g0, %1, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) (define_insn "*sgeu_insn" [(set (match_operand:SI 0 "register_operand" "=r") (geu:SI (reg:CC 100) (const_int 0)))] "! TARGET_LIVE_G0" - "subx %%g0,-1,%0" - [(set_attr "type" "misc")]) + "subx\\t%%g0, -1, %0" + [(set_attr "type" "misc") + (set_attr "length" "1")]) (define_insn "*neg_sgeu_insn" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (geu:SI (reg:CC 100) (const_int 0))))] "! TARGET_LIVE_G0" - "addx %%g0,-1,%0" - [(set_attr "type" "misc")]) + "addx\\t%%g0, -1, %0" + [(set_attr "type" "misc") + (set_attr "length" "1")]) ;; We can also do (x + ((unsigned) i >= 0)) and related, so put them in. ;; ??? The addx/subx insns use the 32 bit carry flag so there are no DImode @@ -1240,8 +1457,9 @@ (plus:SI (ltu:SI (reg:CC 100) (const_int 0)) (match_operand:SI 1 "arith_operand" "rI")))] "! TARGET_LIVE_G0" - "addx %%g0,%1,%0" - [(set_attr "type" "unary")]) + "addx\\t%%g0, %1, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) (define_insn "*sltu_plus_x_plus_y" [(set (match_operand:SI 0 "register_operand" "=r") @@ -1249,64 +1467,57 @@ (plus:SI (match_operand:SI 1 "arith_operand" "%r") (match_operand:SI 2 "arith_operand" "rI"))))] "" - "addx %1,%2,%0") + "addx\\t%1, %2, %0" + [(set_attr "type" "binary") + (set_attr "length" "1")]) (define_insn "*x_minus_sltu" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 1 "register_operand" "r") (ltu:SI (reg:CC 100) (const_int 0))))] "" - "subx %1,0,%0" - [(set_attr "type" "unary")]) + "subx\\t%1, 0, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) ;; ??? Combine should canonicalize these next two to the same pattern. (define_insn "*x_minus_y_minus_sltu" [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r") + (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") (match_operand:SI 2 "arith_operand" "rI")) (ltu:SI (reg:CC 100) (const_int 0))))] "" - "subx %1,%2,%0") + "subx\\t%r1, %2, %0" + [(set_attr "type" "binary") + (set_attr "length" "1")]) (define_insn "*x_minus_sltu_plus_y" [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (match_operand:SI 1 "register_operand" "r") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") (plus:SI (ltu:SI (reg:CC 100) (const_int 0)) (match_operand:SI 2 "arith_operand" "rI"))))] "" - "subx %1,%2,%0") + "subx\\t%r1, %2, %0" + [(set_attr "type" "binary") + (set_attr "length" "1")]) (define_insn "*sgeu_plus_x" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (geu:SI (reg:CC 100) (const_int 0)) (match_operand:SI 1 "register_operand" "r")))] "" - "subx %1,-1,%0" - [(set_attr "type" "unary")]) + "subx\\t%1, -1, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) (define_insn "*x_minus_sgeu" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 1 "register_operand" "r") (geu:SI (reg:CC 100) (const_int 0))))] "" - "addx %1,-1,%0" - [(set_attr "type" "unary")]) - -;; Now we have the generic scc insns. -;; !v9: These will be done using a jump. -;; v9: Use conditional moves which are defined elsewhere. -;; We have to exclude the cases above, since we will not want combine to -;; turn something that does not require a jump into something that does. - -(define_insn "*scc_si" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operator:SI 2 "noov_compare_op" - [(match_operand 1 "icc_or_fcc_reg_operand" "") - (const_int 0)]))] - "" - "* return output_scc_insn (operands, insn); " - [(set_attr "type" "multi") - (set_attr "length" "3")]) + "addx\\t%1, -1, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) (define_split [(set (match_operand:SI 0 "register_operand" "=r") @@ -1324,15 +1535,6 @@ (match_dup 0)))] "") -(define_insn "*scc_di" - [(set (match_operand:DI 0 "register_operand" "=r") - (match_operator:DI 2 "noov_compare_op" - [(match_operand 1 "icc_or_fcc_reg_operand" "") - (const_int 0)]))] - "TARGET_ARCH64" - "* return output_scc_insn (operands, insn); " - [(set_attr "type" "multi") - (set_attr "length" "3")]) ;; These control RTL generation for conditional jump insns @@ -1526,6 +1728,7 @@ ;; Now match both normal and inverted jump. +;; XXX fpcmp nop braindamage (define_insn "*normal_branch" [(set (pc) (if_then_else (match_operator 0 "noov_compare_op" @@ -1541,6 +1744,7 @@ }" [(set_attr "type" "branch")]) +;; XXX fpcmp nop braindamage (define_insn "*inverted_branch" [(set (pc) (if_then_else (match_operator 0 "noov_compare_op" @@ -1556,6 +1760,7 @@ }" [(set_attr "type" "branch")]) +;; XXX fpcmp nop braindamage (define_insn "*normal_fp_branch" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" @@ -1572,6 +1777,7 @@ }" [(set_attr "type" "branch")]) +;; XXX fpcmp nop braindamage (define_insn "*inverted_fp_branch" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" @@ -1588,6 +1794,7 @@ }" [(set_attr "type" "branch")]) +;; XXX fpcmp nop braindamage (define_insn "*normal_fpe_branch" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" @@ -1604,6 +1811,7 @@ }" [(set_attr "type" "branch")]) +;; XXX fpcmp nop braindamage (define_insn "*inverted_fpe_branch" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" @@ -1625,6 +1833,7 @@ ;; There are no 32 bit brreg insns. +;; XXX (define_insn "*normal_int_branch_sp64" [(set (pc) (if_then_else (match_operator 0 "v9_regcmp_op" @@ -1637,10 +1846,11 @@ { return output_v9branch (operands[0], 1, 2, 0, final_sequence && INSN_ANNULLED_BRANCH_P (insn), - ! final_sequence); + ! final_sequence, insn); }" [(set_attr "type" "branch")]) +;; XXX (define_insn "*inverted_int_branch_sp64" [(set (pc) (if_then_else (match_operator 0 "v9_regcmp_op" @@ -1653,366 +1863,27 @@ { return output_v9branch (operands[0], 1, 2, 1, final_sequence && INSN_ANNULLED_BRANCH_P (insn), - ! final_sequence); + ! final_sequence, insn); }" [(set_attr "type" "branch")]) -;; Esoteric move insns (lo_sum, high, pic). - -(define_insn "*lo_sum_si" - [(set (match_operand:SI 0 "register_operand" "=r") - (lo_sum:SI (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "immediate_operand" "in")))] - "" - ;; V9 needs "add" because of the code models. We still use "or" for v8 - ;; so we can compare the old compiler with the new. - "* return TARGET_ARCH64 ? \"add %1,%%lo(%a2),%0\" : \"or %1,%%lo(%a2),%0\";" - ;; Need to set length for this arith insn because operand2 - ;; is not an "arith_operand". - [(set_attr "length" "1")]) - -;; For PIC, symbol_refs are put inside unspec so that the optimizer will not -;; confuse them with real addresses. -(define_insn "pic_lo_sum_si" - [(set (match_operand:SI 0 "register_operand" "=r") - (lo_sum:SI (match_operand:SI 1 "register_operand" "r") - (unspec:SI [(match_operand:SI 2 "immediate_operand" "in")] 0)))] - "flag_pic" - ;; V9 needs "add" because of the code models. We still use "or" for v8 - ;; so we can compare the old compiler with the new. - "* return TARGET_ARCH64 ? \"add %1,%%lo(%a2),%0\" : \"or %1,%%lo(%a2),%0\";" - ;; Need to set length for this arith insn because operand2 - ;; is not an "arith_operand". - [(set_attr "length" "1")]) - -;; The PIC version of sethi must appear before the non-pic case so that -;; the unspec will not be matched as part of the operand. -;; For PIC, symbol_refs are put inside unspec so that the optimizer will not -;; confuse them with real addresses. -(define_insn "pic_sethi_si" - [(set (match_operand:SI 0 "register_operand" "=r") - (high:SI (unspec:SI [(match_operand 1 "" "")] 0)))] - "flag_pic && check_pic (1)" - "sethi %%hi(%a1),%0" - [(set_attr "type" "move") - (set_attr "length" "1")]) - -(define_insn "pic_lo_sum_di" - [(set (match_operand:DI 0 "register_operand" "=r") - (lo_sum:SI (match_operand:DI 1 "register_operand" "r") - (unspec:SI [(match_operand:DI 2 "immediate_operand" "in")] 0)))] - "TARGET_ARCH64 && flag_pic" - "add %1,%%lo(%a2),%0" - [(set_attr "length" "1")]) - -(define_insn "pic_sethi_di" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:SI (unspec:SI [(match_operand 1 "" "")] 0)))] - "TARGET_ARCH64 && flag_pic && check_pic (1)" - "sethi %%hi(%a1),%0" - [(set_attr "type" "move") - (set_attr "length" "1")]) +;; Load program counter insns. (define_insn "get_pc" [(clobber (reg:SI 15)) (set (match_operand 0 "register_operand" "=r") (unspec [(match_operand 1 "" "") (match_operand 2 "" "")] 2))] "flag_pic && REGNO (operands[0]) == 23" - "sethi %%hi(%a1-4),%0\;call %a2\;add %0,%%lo(%a1+4),%0" + "sethi\\t%%hi(%a1-4), %0\\n\\tcall\\t%a2\\n\\tadd\\t%0, %%lo(%a1+4), %0" [(set_attr "length" "3")]) -(define_insn "get_pc_via_rdpc" - [(set (match_operand 0 "register_operand" "=r") (pc))] - "TARGET_V9" - "rd %%pc,%0" - [(set_attr "type" "move")]) +;; Currently unused... +;; (define_insn "get_pc_via_rdpc" +;; [(set (match_operand 0 "register_operand" "=r") (pc))] +;; "TARGET_V9" +;; "rd\\t%%pc, %0" +;; [(set_attr "type" "move")]) -;; Special pic pattern, for loading the address of a label into a register. -;; It clobbers o7 because the call puts the return address (i.e. pc value) -;; there. The pic tablejump pattern also uses this. - -(define_insn "move_pic_label_si" - [(set (match_operand:SI 0 "register_operand" "=r") - ; This was previously (label_ref:SI (match_operand 1 "" "")) but that - ; loses the volatil and other flags of the original label_ref. - (match_operand:SI 1 "label_ref_operand" "")) - (set (reg:SI 15) (pc))] - "flag_pic" - "* -{ - if (get_attr_length (insn) == 2) - return \"\\n1:\;call 2f\;add %%o7,%%lo(%l1-1b),%0\\n2:\"; - else - return \"\\n1:\;call 2f\;sethi %%hi(%l1-1b),%0\\n2:\\tor %0,%%lo(%l1-1b),%0\;add %0,%%o7,%0\"; -}" - [(set_attr "type" "multi") - ; 960 = 4096 bytes / 4 bytes/insn - 64 (for not always perfect length calcs) - (set (attr "length") (if_then_else (ltu (minus (match_dup 1) (pc)) - (const_int 960)) - (const_int 2) - (const_int 4)))]) - -;; Special sparc64 pattern for loading the address of a label into a register. -;; The pic and non-pic cases are the same since it's the most efficient way. -;; -;; ??? The non-pic case doesn't need to use %o7, we could use a scratch -;; instead. But the pic case doesn't need to use %o7 either. We handle them -;; both here so that when this is fixed, they can both be fixed together. -;; Don't forget that the pic jump table stuff uses %o7 (that will need to be -;; changed too). - -(define_insn "move_label_di" - [(set (match_operand:DI 0 "register_operand" "=r") - ; This was previously (label_ref:DI (match_operand 1 "" "")) but that - ; loses the volatil and other flags of the original label_ref. - (match_operand:DI 1 "label_ref_operand" "")) - (set (reg:DI 15) (pc))] - "TARGET_ARCH64" - "* -{ - if (get_attr_length (insn) == 2) - return \"\\n1:\;rd %%pc,%%o7\;add %%o7,%l1-1b,%0\"; - else - return \"\\n1:\;rd %%pc,%%o7\;sethi %%hi(%l1-1b),%0\;add %0,%%lo(%l1-1b),%0\;sra %0,0,%0\;add %0,%%o7,%0\"; -}" - [(set_attr "type" "multi") - ; 960 = 4096 bytes / 4 bytes/insn - 64 (for not always perfect length calcs) - (set (attr "length") (if_then_else (ltu (minus (match_dup 1) (pc)) - (const_int 960)) - (const_int 2) - (const_int 5)))]) - -(define_insn "*sethi_hi" - [(set (match_operand:HI 0 "register_operand" "=r") - (high:HI (match_operand 1 "" "")))] - "check_pic (1)" - "sethi %%hi(%a1),%0" - [(set_attr "type" "move") - (set_attr "length" "1")]) - -;; This must appear after the PIC sethi so that the PIC unspec will not -;; be matched as part of the operand. -(define_insn "*sethi_si" - [(set (match_operand:SI 0 "register_operand" "=r") - (high:SI (match_operand 1 "" "")))] - "check_pic (1)" - "sethi %%hi(%a1),%0" - [(set_attr "type" "move") - (set_attr "length" "1")]) - -(define_insn "*lo_sum_di_sp32" - [(set (match_operand:DI 0 "register_operand" "=r") - (lo_sum:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:DI 2 "immediate_operand" "in")))] - "! TARGET_ARCH64" - "* -{ - /* Don't output a 64 bit constant, since we can't trust the assembler to - handle it correctly. */ - if (GET_CODE (operands[2]) == CONST_DOUBLE) - operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2])); - else if (GET_CODE (operands[2]) == CONST_INT - && HOST_BITS_PER_WIDE_INT > 32 - && INTVAL (operands[2]) > 0xffffffff) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffffffff); - - return \"or %L1,%%lo(%a2),%L0\"; -}" - ;; Need to set length for this arith insn because operand2 - ;; is not an "arith_operand". - [(set_attr "length" "1")]) - -;; ??? Optimizer does not handle "or %o1,%lo(0),%o1". How about add? - -(define_insn "*lo_sum_di_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (lo_sum:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:DI 2 "immediate_operand" "in")))] - "TARGET_ARCH64" - "* -{ - /* Don't output a 64 bit constant, since we can't trust the assembler to - handle it correctly. */ - if (GET_CODE (operands[2]) == CONST_DOUBLE) - operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2])); - else if (GET_CODE (operands[2]) == CONST_INT - && HOST_BITS_PER_WIDE_INT > 32 - && INTVAL (operands[2]) > 0xffffffff) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffffffff); - - /* Note that we use add here. This is important because Medium/Anywhere - code model support depends on it. */ - return \"add %1,%%lo(%a2),%0\"; -}" - ;; Need to set length for this arith insn because operand2 - ;; is not an "arith_operand". - [(set_attr "length" "1")]) - -(define_insn "*sethi_di_sp32" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:DI (match_operand 1 "" "")))] - "! TARGET_ARCH64 && check_pic (1)" - "* -{ - rtx op0 = operands[0]; - rtx op1 = operands[1]; - - if (GET_CODE (op1) == CONST_INT) - { - operands[0] = operand_subword (op0, 1, 0, DImode); - output_asm_insn (\"sethi %%hi(%a1),%0\", operands); - - operands[0] = operand_subword (op0, 0, 0, DImode); - if (INTVAL (op1) < 0) - return \"mov -1,%0\"; - else - return \"mov 0,%0\"; - } - else if (GET_CODE (op1) == CONST_DOUBLE) - { - operands[0] = operand_subword (op0, 1, 0, DImode); - operands[1] = GEN_INT (CONST_DOUBLE_LOW (op1)); - output_asm_insn (\"sethi %%hi(%a1),%0\", operands); - - operands[0] = operand_subword (op0, 0, 0, DImode); - operands[1] = GEN_INT (CONST_DOUBLE_HIGH (op1)); - return singlemove_string (operands); - } - else - abort (); - return \"\"; -}" - [(set_attr "type" "move") - (set_attr "length" "2")]) - -;;; ??? This pattern originally clobbered a scratch register. However, this -;;; is invalid, the movdi pattern may not use a temp register because it -;;; may be called from reload to reload a DImode value. In that case, we -;;; end up with a scratch register that never gets allocated. To avoid this, -;;; we use global register 1 which is never otherwise used by gcc as a temp. -;;; The correct solution here might be to force DImode constants to memory, -;;; e.g. by using a toc like the romp and rs6000 ports do for addresses, reg -;;; 1 will then no longer need to be considered a fixed reg. - -(define_expand "sethi_di_sp64" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (high:DI (match_operand 1 "general_operand" ""))) - (clobber (reg:DI 1))])] - "TARGET_ARCH64" - "") - -(define_insn "*sethi_di_sp64_const" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:DI (match_operand 1 "const_double_operand" ""))) - (clobber (reg:DI 1))] - "TARGET_ARCH64 && check_pic (1)" - "* -{ -#if HOST_BITS_PER_WIDE_INT == 32 - rtx high, low; - - split_double (operands[1], &high, &low); - - if (high == const0_rtx) - { - operands[1] = low; - output_asm_insn (\"sethi %%hi(%a1),%0\", operands); - } - else - { - operands[1] = high; - output_asm_insn (singlemove_string (operands), operands); - - operands[1] = low; - output_asm_insn (\"sllx %0,32,%0\", operands); - if (low != const0_rtx) - output_asm_insn (\"sethi %%hi(%a1),%%g1; or %0,%%g1,%0\", operands); - } -#else - rtx op = operands[1]; - - if (! SPARC_SETHI_P (INTVAL(op))) - { - operands[1] = GEN_INT (INTVAL (op) >> 32); - output_asm_insn (singlemove_string (operands), operands); - - output_asm_insn (\"sllx %0,32,%0\", operands); - if (INTVAL (op) & 0xffffffff) - { - operands[1] = GEN_INT (INTVAL (op) & 0xffffffff); - output_asm_insn (\"sethi %%hi(%a1),%%g1; or %0,%%g1,%0\", operands); - } - } - else - { - output_asm_insn (\"sethi %%hi(%a1),%0\", operands); - } -#endif - - return \"\"; -}" - [(set_attr "type" "move") - (set_attr "length" "5")]) - -;; Most of the required support for the various code models is here. -;; We can do this because sparcs need the high insn to load the address. We -;; just need to get high to do the right thing for each code model. Then each -;; uses the same "%X+%lo(...)" in the load/store insn, though in the case of -;; the medium/middle code model "%lo" is written "%l44". - -;; When TARGET_CM_MEDLOW, assume that the upper 32 bits of symbol addresses are -;; always 0. -;; When TARGET_CM_MEDMID, the executable must be in the low 16 TB of memory. -;; This corresponds to the low 44 bits, and the %[hml]44 relocs are used. -;; ??? Not implemented yet. -;; When TARGET_CM_EMBMEDANY, the text and data segments have a maximum size of -;; 31 bits and may be located anywhere. EMBMEDANY_BASE_REG contains the start -;; address of the data segment, currently %g4. -;; When TARGET_CM_MEDANY, the text and data segments have a maximum size of 31 -;; bits and may be located anywhere. The maximum offset from any instruction -;; to the label _GLOBAL_OFFSET_TABLE_ is 31 bits. - -(define_insn "*sethi_di_medlow" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:DI (match_operand 1 "" ""))) - ;; The clobber is here because emit_move_sequence assumes the worst case. - (clobber (reg:DI 1))] - "TARGET_CM_MEDLOW && check_pic (1)" - "sethi %%hi(%a1),%0" - [(set_attr "type" "move") - (set_attr "length" "1")]) - -(define_insn "*sethi_di_medium_pic" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:DI (match_operand 1 "sp64_medium_pic_operand" "")))] - "(TARGET_CM_MEDLOW || TARGET_CM_EMBMEDANY) && check_pic (1)" - "sethi %%hi(%a1),%0" - [(set_attr "type" "move") - (set_attr "length" "1")]) - -;; WARNING: %0 gets %hi(%1)+%g4. -;; You cannot OR in %lo(%1), it must be added in. - -(define_insn "*sethi_di_embmedany_data" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:DI (match_operand 1 "data_segment_operand" ""))) - ;; The clobber is here because emit_move_sequence assumes the worst case. - (clobber (reg:DI 1))] - "TARGET_CM_EMBMEDANY && check_pic (1)" - "sethi %%hi(%a1),%0; add %0,%_,%0" - [(set_attr "type" "move") - (set_attr "length" "2")]) - -(define_insn "*sethi_di_embmedany_text" - [(set (match_operand:DI 0 "register_operand" "=r") - (high:DI (match_operand 1 "text_segment_operand" ""))) - ;; The clobber is here because emit_move_sequence assumes the worst case. - (clobber (reg:DI 1))] - "TARGET_CM_EMBMEDANY && check_pic (1)" - "sethi %%uhi(%a1),%%g1; or %%g1,%%ulo(%a1),%%g1; sllx %%g1,32,%%g1; sethi %%hi(%a1),%0; or %0,%%g1,%0" - [(set_attr "type" "move") - (set_attr "length" "5")]) ;; Move instructions @@ -2022,117 +1893,156 @@ "" " { - if (emit_move_sequence (operands, QImode)) - DONE; + /* Working with CONST_INTs is easier, so convert + a double if needed. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]) & 0xff); + } + else if (GET_CODE (operands[1]) == CONST_INT) + { + /* And further, we know for all QI cases that only the + low byte is significant, which we can always process + in a single insn. So mask it now. */ + operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff); + } + + /* Handle sets of MEM first. */ + if (GET_CODE (operands[0]) == MEM) + { + /* This checks TARGET_LIVE_G0 for us. */ + if (reg_or_0_operand (operands[1], QImode)) + goto movqi_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (QImode, operands[1]); + } + } + + /* Fixup PIC cases. */ + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], QImode, 0); + + if (symbolic_operand (operands[1], QImode)) + { + operands[1] = legitimize_pic_address (operands[1], + QImode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + goto movqi_is_ok; + } + } + + /* All QI constants require only one insn, so proceed. */ + + movqi_is_ok: }") (define_insn "*movqi_insn" - [(set (match_operand:QI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q") - (match_operand:QI 1 "move_operand" "rI,K,Q,rJ"))] - "! TARGET_LIVE_G0 - && (register_operand (operands[0], QImode) - || register_operand (operands[1], QImode) - || operands[1] == const0_rtx)" + [(set (match_operand:QI 0 "general_operand" "=r,r,m") + (match_operand:QI 1 "input_operand" "rI,m,rJ"))] + "(register_operand (operands[0], QImode) + || reg_or_0_operand (operands[1], QImode))" "@ - mov %1,%0 - sethi %%hi(%a1),%0 - ldub %1,%0 - stb %r1,%0" - [(set_attr "type" "move,move,load,store") + mov\\t%1, %0 + ldub\\t%1, %0 + stb\\t%r1, %0" + [(set_attr "type" "move,load,store") (set_attr "length" "1")]) -(define_insn "*movqi_insn_liveg0" - [(set (match_operand:QI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,Q") - (match_operand:QI 1 "move_operand" "r,J,I,K,Q,r"))] - "TARGET_LIVE_G0 - && (register_operand (operands[0], QImode) - || register_operand (operands[1], QImode))" - "@ - mov %1,%0 - and %0,0,%0 - and %0,0,%0\;or %0,%1,%0 - sethi %%hi(%a1),%0 - ldub %1,%0 - stb %1,%0" - [(set_attr "type" "move,move,move,move,load,store") - (set_attr "length" "1,1,2,1,1,1")]) - -(define_insn "*lo_sum_qi" - [(set (match_operand:QI 0 "register_operand" "=r") - (subreg:QI (lo_sum:SI (match_operand:QI 1 "register_operand" "r") - (match_operand 2 "immediate_operand" "in")) 0))] - "" - "or %1,%%lo(%a2),%0" - [(set_attr "length" "1")]) - -(define_insn "*store_qi" - [(set (mem:QI (match_operand:SI 0 "symbolic_operand" "")) - (match_operand:QI 1 "reg_or_0_operand" "rJ")) - (clobber (match_scratch:SI 2 "=&r"))] - "(reload_completed || reload_in_progress) - && ! TARGET_PTR64" - "sethi %%hi(%a0),%2\;stb %r1,[%2+%%lo(%a0)]" - [(set_attr "type" "store") - (set_attr "length" "2")]) - (define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" ""))] "" " { - if (emit_move_sequence (operands, HImode)) - DONE; + /* Working with CONST_INTs is easier, so convert + a double if needed. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + + /* Handle sets of MEM first. */ + if (GET_CODE (operands[0]) == MEM) + { + /* This checks TARGET_LIVE_G0 for us. */ + if (reg_or_0_operand (operands[1], HImode)) + goto movhi_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (HImode, operands[1]); + } + } + + /* Fixup PIC cases. */ + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], HImode, 0); + + if (symbolic_operand (operands[1], HImode)) + { + operands[1] = legitimize_pic_address (operands[1], + HImode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + goto movhi_is_ok; + } + } + + /* This makes sure we will not get rematched due to splittage. */ + if (! CONSTANT_P (operands[1]) || input_operand (operands[1], HImode)) + ; + else if (CONSTANT_P (operands[1]) + && GET_CODE (operands[1]) != HIGH + && GET_CODE (operands[1]) != LO_SUM) + { + sparc_emit_set_const32 (operands[0], operands[1]); + DONE; + } + movhi_is_ok: }") (define_insn "*movhi_insn" - [(set (match_operand:HI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q") - (match_operand:HI 1 "move_operand" "rI,K,Q,rJ"))] - "! TARGET_LIVE_G0 - && (register_operand (operands[0], HImode) - || register_operand (operands[1], HImode) - || operands[1] == const0_rtx)" + [(set (match_operand:HI 0 "general_operand" "=r,r,r,m") + (match_operand:HI 1 "input_operand" "rI,K,m,rJ"))] + "(register_operand (operands[0], HImode) + || reg_or_0_operand (operands[1], HImode))" "@ - mov %1,%0 - sethi %%hi(%a1),%0 - lduh %1,%0 - sth %r1,%0" + mov\\t%1, %0 + sethi\\t%%hi(%a1), %0 + lduh\\t%1, %0 + sth\\t%r1, %0" [(set_attr "type" "move,move,load,store") (set_attr "length" "1")]) -(define_insn "*movhi_insn_liveg0" - [(set (match_operand:HI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,Q") - (match_operand:HI 1 "move_operand" "r,J,I,K,Q,r"))] - "TARGET_LIVE_G0 - && (register_operand (operands[0], HImode) - || register_operand (operands[1], HImode))" - "@ - mov %1,%0 - and %0,0,%0 - and %0,0,%0\;or %0,%1,%0 - sethi %%hi(%a1),%0 - lduh %1,%0 - sth %1,%0" - [(set_attr "type" "move,move,move,move,load,store") - (set_attr "length" "1,1,2,1,1,1")]) - -(define_insn "*lo_sum_hi" +;; We always work with constants here, never symbols, so no need +;; for the funny PIC versions. +(define_insn "*movhi_lo_sum" [(set (match_operand:HI 0 "register_operand" "=r") (lo_sum:HI (match_operand:HI 1 "register_operand" "r") - (match_operand 2 "immediate_operand" "in")))] + (match_operand:HI 2 "immediate_operand" "in")))] "" - "or %1,%%lo(%a2),%0" - [(set_attr "length" "1")]) + "or\\t%1, %%lo(%a2), %0" + [(set_attr "type" "ialu") + (set_attr "length" "1")]) -(define_insn "*store_hi" - [(set (mem:HI (match_operand:SI 0 "symbolic_operand" "")) - (match_operand:HI 1 "reg_or_0_operand" "rJ")) - (clobber (match_scratch:SI 2 "=&r"))] - "(reload_completed || reload_in_progress) - && ! TARGET_PTR64" - "sethi %%hi(%a0),%2\;sth %r1,[%2+%%lo(%a0)]" - [(set_attr "type" "store") - (set_attr "length" "2")]) +(define_insn "*movhi_high" + [(set (match_operand:HI 0 "register_operand" "=r") + (high:HI (match_operand:SI 1 "" "")))] + "" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) (define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") @@ -2140,68 +2050,170 @@ "" " { - if (emit_move_sequence (operands, SImode)) - DONE; + /* Working with CONST_INTs is easier, so convert + a double if needed. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + + /* Handle sets of MEM first. */ + if (GET_CODE (operands[0]) == MEM) + { + /* This checks TARGET_LIVE_G0 for us. */ + if (reg_or_0_operand (operands[1], SImode)) + goto movsi_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (SImode, operands[1]); + } + } + + /* Fixup PIC cases. */ + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], SImode, 0); + + if (GET_CODE (operands[1]) == LABEL_REF) + { + /* shit */ + emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1])); + DONE; + } + + if (symbolic_operand (operands[1], SImode)) + { + operands[1] = legitimize_pic_address (operands[1], + SImode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + goto movsi_is_ok; + } + } + + /* If we are trying to toss an integer constant into the + FPU registers, force it into memory. */ + if (GET_CODE (operands[0]) == REG + && REGNO (operands[0]) >= SPARC_FIRST_FP_REG + && REGNO (operands[0]) <= SPARC_LAST_V9_FP_REG + && CONSTANT_P (operands[1])) + operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]), + operands[1])); + + /* This makes sure we will not get rematched due to splittage. */ + if (! CONSTANT_P (operands[1]) || input_operand (operands[1], SImode)) + ; + else if (CONSTANT_P (operands[1]) + && GET_CODE (operands[1]) != HIGH + && GET_CODE (operands[1]) != LO_SUM) + { + sparc_emit_set_const32 (operands[0], operands[1]); + DONE; + } + movsi_is_ok: }") -;; We must support both 'r' and 'f' registers here, because combine may -;; convert SFmode hard registers to SImode hard registers when simplifying -;; subreg sets. - -;; We cannot combine the similar 'r' and 'f' constraints, because it causes -;; problems with register allocation. Reload might try to put an integer -;; in an fp register, or an fp number is an integer register. - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,f,r,r,f,Q,Q,d") - (match_operand:SI 1 "move_operand" "rI,!f,K,Q,!Q,rJ,!f,J"))] - "! TARGET_LIVE_G0 - && (register_operand (operands[0], SImode) - || register_operand (operands[1], SImode) - || operands[1] == const0_rtx) - && (GET_CODE (operands[0]) != REG || ! CONSTANT_P (operands[1]) - || REGNO (operands[0]) < 32 - || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)" - "@ - mov %1,%0 - fmovs %1,%0 - sethi %%hi(%a1),%0 - ld %1,%0 - ld %1,%0 - st %r1,%0 - st %1,%0 - fzeros %0" - [(set_attr "type" "move,fpmove,move,load,fpload,store,fpstore,fpmove") +;; Special LIVE_G0 pattern to obtain zero in a register. +(define_insn "*movsi_zero_liveg0" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "zero_operand" "J"))] + "TARGET_LIVE_G0" + "and\\t%0, 0, %0" + [(set_attr "type" "binary") (set_attr "length" "1")]) -(define_insn "*movsi_insn_liveg0" - [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,f,r,r,f,Q,Q") - (match_operand:SI 1 "move_operand" "r,J,I,!f,K,Q,!Q,r,!f"))] - "TARGET_LIVE_G0 - && (register_operand (operands[0], SImode) - || register_operand (operands[1], SImode))" +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "general_operand" "=r,f,r,r,r,f,m,m,d") + (match_operand:SI 1 "input_operand" "rI,!f,K,J,m,!m,rJ,!f,J"))] + "(register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" "@ - mov %1,%0 - and %0,0,%0 - and %0,0,%0\;or %0,%1,%0 - fmovs %1,%0 - sethi %%hi(%a1),%0 - ld %1,%0 - ld %1,%0 - st %1,%0 - st %1,%0" - [(set_attr "type" "move,move,move,fpmove,move,load,fpload,store,fpstore") - (set_attr "length" "1,1,2,1,1,1,1,1,1")]) + mov\\t%1, %0 + fmovs\\t%1, %0 + sethi\\t%%hi(%a1), %0 + clr\\t%0 + ld\\t%1, %0 + ld\\t%1, %0 + st\\t%r1, %0 + st\\t%1, %0 + fzero\\t%0" + [(set_attr "type" "move,fpmove,move,move,load,fpload,store,fpstore,fpmove") + (set_attr "length" "1")]) -(define_insn "*store_si" - [(set (mem:SI (match_operand:SI 0 "symbolic_operand" "")) - (match_operand:SI 1 "reg_or_0_operand" "rJ")) - (clobber (match_scratch:SI 2 "=&r"))] - "(reload_completed || reload_in_progress) - && ! TARGET_PTR64" - "sethi %%hi(%a0),%2\;st %r1,[%2+%%lo(%a0)]" - [(set_attr "type" "store") - (set_attr "length" "2")]) +(define_insn "*movsi_lo_sum" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "in")))] + "" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "type" "ialu") + (set_attr "length" "1")]) + +(define_insn "*movsi_high" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (match_operand:SI 1 "immediate_operand" "in")))] + "" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +;; The next two patterns must wrap the SYMBOL_REF in an UNSPEC +;; so that CSE won't optimize the address computation away. +(define_insn "movsi_lo_sum_pic" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "r") + (unspec:SI [(match_operand:SI 2 "immediate_operand" "in")] 0)))] + "flag_pic" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "movsi_high_pic" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (unspec:SI [(match_operand 1 "" "")] 0)))] + "flag_pic && check_pic (1)" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_expand "movsi_pic_label_ref" + [(set (match_dup 3) (high:SI + (unspec:SI [(match_operand:SI 1 "label_ref_operand" "") + (match_dup 2)] 5))) + (set (match_dup 4) (lo_sum:SI (match_dup 3) + (unspec:SI [(match_dup 1) (match_dup 2)] 5))) + (set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_dup 5) (match_dup 4)))] + "flag_pic" + " +{ + current_function_uses_pic_offset_table = 1; + operands[2] = gen_rtx_SYMBOL_REF (Pmode, \"_GLOBAL_OFFSET_TABLE_\"); + operands[3] = gen_reg_rtx (SImode); + operands[4] = gen_reg_rtx (SImode); + operands[5] = pic_offset_table_rtx; +}") + +(define_insn "*movsi_high_pic_label_ref" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI + (unspec:SI [(match_operand:SI 1 "label_ref_operand" "") + (match_operand:SI 2 "" "")] 5)))] + "flag_pic" + "sethi\\t%%hi(%a2-(%a1-.)), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "*movsi_lo_sum_pic_label_ref" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "=r") + (unspec:SI [(match_operand:SI 2 "label_ref_operand" "") + (match_operand:SI 3 "" "")] 5)))] + "flag_pic" + "or\\t%1, %%lo(%a3-(%a2-.)), %0" + [(set_attr "length" "1")]) (define_expand "movdi" [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "") @@ -2209,261 +2221,601 @@ "" " { - if (emit_move_sequence (operands, DImode)) - DONE; + /* Where possible, convert CONST_DOUBLE into a CONST_INT. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE +#if HOST_BITS_PER_WIDE_INT != 64 + && ((CONST_DOUBLE_HIGH (operands[1]) == 0 + && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) == 0) + || (CONST_DOUBLE_HIGH (operands[1]) == 0xffffffff + && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0)) +#endif + ) + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + + /* Handle MEM cases first. */ + if (GET_CODE (operands[0]) == MEM) + { + /* If it's a REG, we can always do it. + The const zero case is more complex, on v9 + we can always perform it. */ + if (register_operand (operands[1], DImode) + || (TARGET_ARCH64 + && (operands[1] == const0_rtx))) + goto movdi_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (DImode, operands[1]); + } + } + + if (GET_CODE (operands[1]) == LABEL_REF) + { + if (! TARGET_ARCH64) + abort (); + /* ??? revisit this... */ + emit_insn (gen_move_label_di (operands[0], operands[1])); + DONE; + } + + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], DImode, 0); + + if (symbolic_operand (operands[1], DImode)) + { + operands[1] = legitimize_pic_address (operands[1], + DImode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + goto movdi_is_ok; + } + } + + /* If we are trying to toss an integer constant into the + FPU registers, force it into memory. */ + if (GET_CODE (operands[0]) == REG + && REGNO (operands[0]) >= SPARC_FIRST_FP_REG + && REGNO (operands[0]) <= SPARC_LAST_V9_FP_REG + && CONSTANT_P (operands[1])) + operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]), + operands[1])); + + /* This makes sure we will not get rematched due to splittage. */ + if (! CONSTANT_P (operands[1]) || input_operand (operands[1], DImode)) + ; + else if (TARGET_ARCH64 + && CONSTANT_P (operands[1]) + && GET_CODE (operands[1]) != HIGH + && GET_CODE (operands[1]) != LO_SUM) + { + sparc_emit_set_const64 (operands[0], operands[1]); + DONE; + } + + movdi_is_ok: }") -;; 32 bit V9 movdi is like regular 32 bit except: a 64 bit zero can be stored -;; to aligned memory with a single instruction, the ldd/std instructions -;; are not used, and constants can not be moved to floating point registers. +;; Be careful, fmovd does not exist when !arch64. +;; We match MEM moves directly when we have correct even +;; numbered registers, but fall into splits otherwise. +;; The constraint ordering here is really important to +;; avoid insane problems in reload, especially for patterns +;; of the form: +;; +;; (set (mem:DI (plus:SI (reg:SI 30 %fp) +;; (const_int -5016))) +;; (reg:DI 2 %g2)) +;; +(define_insn "*movdi_insn_sp32" + [(set (match_operand:DI 0 "general_operand" "=T,U,o,r,r,r,?T,?f,?f,?o,?f") + (match_operand:DI 1 "input_operand" "U,T,r,o,i,r,f,T,o,f,f"))] + "! TARGET_ARCH64 && + (register_operand (operands[0], DImode) + || register_operand (operands[1], DImode))" + "@ + std\\t%1, %0 + ldd\\t%1, %0 + # + # + # + # + std\\t%1, %0 + ldd\\t%1, %0 + # + # + #" + [(set_attr "type" "store,load,*,*,*,*,fpstore,fpload,*,*,*") + (set_attr "length" "1,1,2,2,2,2,1,1,2,2,2")]) -(define_insn "*movdi_sp32_v9" - [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,T,Q,r,r,?e,?e,?Q,?b") - (match_operand:DI 1 "general_operand" "r,J,r,Q,i,e,Q,e,J"))] - "TARGET_V9 && ! TARGET_ARCH64 - && (register_operand (operands[0], DImode) - || register_operand (operands[1], DImode) - || operands[1] == const0_rtx) - && (GET_CODE (operands[0]) != REG || ! CONSTANT_P (operands[1]) - || REGNO (operands[0]) < 32 - || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)" - "* -{ - if (which_alternative == 1) - return \"stx %%g0,%0\"; - if (which_alternative == 8) - return \"fzero %0\"; - if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) - return output_fp_move_double (operands); - return output_move_double (operands); -}" - [(set_attr "type" "move,store,store,load,multi,fp,fpload,fpstore,fpmove") - (set_attr "length" "2,1,3,3,3,2,3,3,1")]) +(define_insn "*movdi_insn_sp64" + [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,m,?e,?e,?m") + (match_operand:DI 1 "input_operand" "rI,K,J,m,rJ,e,m,e"))] + "TARGET_ARCH64 && + (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "@ + mov\\t%1, %0 + sethi\\t%%hi(%a1), %0 + clr\\t%0 + ldx\\t%1, %0 + stx\\t%r1, %0 + fmovd\\t%1, %0 + ldd\\t%1, %0 + std\\t%1, %0" + [(set_attr "type" "move,move,move,load,store,fpmove,fpload,fpstore") + (set_attr "length" "1")]) -;; SPARC V9 deprecates std. Split it here. -(define_split - [(set (match_operand:DI 0 "memory_operand" "=m") - (match_operand:DI 1 "register_operand" "r"))] - "TARGET_V9 && ! TARGET_ARCH64 && reload_completed - && REGNO (operands[1]) < 32 && ! MEM_VOLATILE_P (operands[0]) - && offsettable_memref_p (operands[0])" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] - "operands[3] = gen_highpart (SImode, operands[1]); - operands[5] = gen_lowpart (SImode, operands[1]); - operands[4] = adj_offsettable_operand (operands[0], 4); - PUT_MODE (operands[4], SImode); - operands[2] = copy_rtx (operands[0]); - PUT_MODE (operands[2], SImode);") - -;; Split register to register moves. -(define_split +;; The following two are generated by sparc_emit_set_const64 +(define_insn "*movdi_lo_sum_sp64_cint" [(set (match_operand:DI 0 "register_operand" "=r") - (match_operand:DI 1 "arith_double_operand" "rIN"))] - "! TARGET_ARCH64 - && REGNO (operands[0]) < 32 - && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32 - && ! reg_overlap_mentioned_p (operands[0], operands[1])" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] - "operands[2] = gen_highpart (SImode, operands[0]); - operands[3] = gen_lowpart (SImode, operands[0]); - operands[4] = gen_highpart (SImode, operands[1]); - operands[5] = gen_lowpart (SImode, operands[1]);") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "const_int_operand" "in")))] + "TARGET_ARCH64" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "type" "ialu") + (set_attr "length" "1")]) -(define_insn "*movdi_sp32" - [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,T,U,Q,r,r,?f,?f,?Q") - (match_operand:DI 1 "general_operand" "r,U,T,r,Q,i,f,Q,f"))] - "! TARGET_V9 - && (register_operand (operands[0], DImode) - || register_operand (operands[1], DImode) - || operands[1] == const0_rtx)" - "* -{ - if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) - return output_fp_move_double (operands); - return output_move_double (operands); -}" - [(set_attr "type" "move,store,load,store,load,multi,fp,fpload,fpstore") - (set_attr "length" "2,1,1,3,3,3,2,3,3")]) - -;;; ??? The trick used below can be extended to load any negative 32 bit -;;; constant in two instructions. Currently the compiler will use HIGH/LO_SUM -;;; for anything not matching the HIK constraints, which results in 5 -;;; instructions. Positive 32 bit constants can be loaded in the obvious way -;;; with sethi/ori. To extend the trick, in the xor instruction, use -;;; xor %o0, ((op1 & 0x3ff) | -0x400), %o0 -;;; This needs the original value of operands[1], not the inverted value. - -(define_insn "*movdi_sp64_insn" - [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q,?e,?e,?Q") - (match_operand:DI 1 "move_operand" "rI,K,Q,rJ,e,Q,e"))] +(define_insn "*movdi_lo_sum_sp64_dbl" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "const_double_operand" "")))] "TARGET_ARCH64 - && (register_operand (operands[0], DImode) - || register_operand (operands[1], DImode) - || operands[1] == const0_rtx)" + && CONST_DOUBLE_HIGH (operands[2]) == 0" "* { - switch (which_alternative) - { - case 0: - return \"mov %1,%0\"; - case 1: - /* Sethi does not sign extend, so we must use a little trickery - to use it for negative numbers. Invert the constant before - loading it in, then use a xor immediate to invert the loaded bits - (along with the upper 32 bits) to the desired constant. This - works because the sethi and immediate fields overlap. */ - - if ((INTVAL (operands[1]) & 0x80000000) == 0) - return \"sethi %%hi(%a1),%0\"; - else - { - operands[1] = GEN_INT (~INTVAL (operands[1])); - output_asm_insn (\"sethi %%hi(%a1),%0\", operands); - /* The low 10 bits are already zero, but invert the rest. - Assemblers don't accept 0x1c00, so use -0x400 instead. */ - return \"xor %0,-0x400,%0\"; - } - case 2: - return \"ldx %1,%0\"; - case 3: - return \"stx %r1,%0\"; - case 4: - return \"fmovd %1,%0\"; - case 5: - return \"ldd %1,%0\"; - case 6: - return \"std %1,%0\"; - default: - abort (); - } + operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + return \"or\\t%1, %%lo(%a2), %0\"; }" - [(set_attr "type" "move,move,load,store,fp,fpload,fpstore") - (set_attr "length" "1,2,1,1,1,1,1")]) + [(set_attr "type" "ialu") + (set_attr "length" "1")]) + +(define_insn "*movdi_high_sp64_cint" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (match_operand:DI 1 "const_int_operand" "in")))] + "TARGET_ARCH64" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "*movdi_high_sp64_dbl" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (match_operand:DI 1 "const_double_operand" "")))] + "TARGET_ARCH64 + && CONST_DOUBLE_HIGH (operands[1]) == 0" + "* +{ + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + return \"sethi\\t%%hi(%a1), %0\"; +}" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +;; ??? revisit this... +(define_insn "move_label_di" + [(set (match_operand:DI 0 "register_operand" "=r") + ; This was previously (label_ref:DI (match_operand 1 "" "")) but that + ; loses the volatil and other flags of the original label_ref. + (match_operand:DI 1 "label_ref_operand" "")) + (set (reg:DI 15) (pc))] + "TARGET_ARCH64" + "* +{ + return \"\\n1:\\trd\\t%%pc, %%o7\\n\\tsethi\\t%%hi(%l1-1b), %0\\n\\tadd\\t%0, %%lo(%l1-1b), %0\\n\\tsra\\t%0, 0, %0\\n\\tadd\\t%0, %%o7, %0\"; +}" + [(set_attr "type" "multi") + (set_attr "length" "5")]) + +;; Sparc-v9 code model support insns. See sparc_emit_set_symbolic_const64 +;; in sparc.c to see what is going on here... PIC stuff comes first. + +(define_insn "*pic_lo_sum_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:DI 1 "register_operand" "r") + (unspec:SI [(match_operand:DI 2 "immediate_operand" "in")] 0)))] + "TARGET_ARCH64 && flag_pic" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "*pic_sethi_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:SI (unspec:SI [(match_operand 1 "" "")] 0)))] + "TARGET_ARCH64 && flag_pic && check_pic (1)" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "*sethi_di_medlow_embmedany_pic" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (match_operand:DI 1 "sp64_medium_pic_operand" "")))] + "(TARGET_CM_MEDLOW || TARGET_CM_EMBMEDANY) && check_pic (1)" + "sethi\\t%%lo(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "*sethi_di_medlow" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (match_operand:DI 1 "" "")))] + "TARGET_CM_MEDLOW && check_pic (1)" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "*losum_di_medlow" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "" "")))] + "TARGET_CM_MEDLOW" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "seth44" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (unspec:DI [(match_operand:DI 1 "" "")] 6)))] + "TARGET_CM_MEDMID" + "sethi\\t%%h44(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "setm44" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "" "")] 7)))] + "TARGET_CM_MEDMID" + "or\\t%1, %%m44(%a2), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "setl44" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "symbolic_operand" "")))] + "TARGET_CM_MEDMID" + "or\\t%1, %%l44(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "sethh" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (unspec:DI [(match_operand:DI 1 "" "")] 9)))] + "TARGET_CM_MEDANY" + "sethi\\t%%hh(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "setlm" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (unspec:DI [(match_operand:DI 1 "" "")] 10)))] + "TARGET_CM_MEDANY" + "sethi\\t%%lm(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "sethm" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "" "")] 18)))] + "TARGET_CM_MEDANY" + "or\\t%1, %%hm(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "setlo" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "" "")))] + "TARGET_CM_MEDANY" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "embmedany_sethi" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (unspec:DI [(match_operand:DI 1 "data_segment_operand" "")] 11)))] + "TARGET_CM_EMBMEDANY && check_pic (1)" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "embmedany_losum" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "data_segment_operand" "")))] + "TARGET_CM_EMBMEDANY" + "add\\t%1, %%lo(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "embmedany_brsum" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r")] 11))] + "TARGET_CM_EMBMEDANY" + "add\\t%1, %_, %0" + [(set_attr "length" "1")]) + +(define_insn "embmedany_textuhi" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (unspec:DI [(match_operand:DI 1 "text_segment_operand" "")] 13)))] + "TARGET_CM_EMBMEDANY && check_pic (1)" + "sethi\\t%%uhi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "embmedany_texthi" + [(set (match_operand:DI 0 "register_operand" "=r") + (high:DI (unspec:DI [(match_operand:DI 1 "text_segment_operand" "")] 14)))] + "TARGET_CM_EMBMEDANY && check_pic (1)" + "sethi\\t%%hi(%a1), %0" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "embmedany_textulo" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "text_segment_operand" "")] 15)))] + "TARGET_CM_EMBMEDANY" + "or\\t%1, %%ulo(%a2), %0" + [(set_attr "length" "1")]) + +(define_insn "embmedany_textlo" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "text_segment_operand" "")))] + "TARGET_CM_EMBMEDANY" + "or\\t%1, %%lo(%a2), %0" + [(set_attr "length" "1")]) + +;; Now some patterns to help reload out a bit. +(define_expand "reload_indi" + [(parallel [(match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "immediate_operand" "") + (match_operand:TI 2 "register_operand" "=&r")])] + "(TARGET_CM_MEDANY + || TARGET_CM_EMBMEDANY) + && ! flag_pic" + " +{ + sparc_emit_set_symbolic_const64 (operands[0], operands[1], + gen_rtx_REG (DImode, REGNO (operands[2]))); + DONE; +}") + +(define_expand "reload_outdi" + [(parallel [(match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "immediate_operand" "") + (match_operand:TI 2 "register_operand" "=&r")])] + "(TARGET_CM_MEDANY + || TARGET_CM_EMBMEDANY) + && ! flag_pic" + " +{ + sparc_emit_set_symbolic_const64 (operands[0], operands[1], + gen_rtx_REG (DImode, REGNO (operands[2]))); + DONE; +}") + +;; Split up putting CONSTs and REGs into DI regs when !arch64 +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "! TARGET_ARCH64 && reload_completed" + [(clobber (const_int 0))] + " +{ + emit_insn (gen_movsi (gen_highpart (SImode, operands[0]), + (INTVAL (operands[1]) < 0) ? + constm1_rtx : + const0_rtx)); + emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]), + operands[1])); + DONE; +}") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "! TARGET_ARCH64 && reload_completed" + [(clobber (const_int 0))] + " +{ + emit_insn (gen_movsi (gen_highpart (SImode, operands[0]), + GEN_INT (CONST_DOUBLE_HIGH (operands[1])))); + + /* Slick... but this trick loses if this subreg constant part + can be done in one insn. */ + if (CONST_DOUBLE_LOW (operands[1]) == CONST_DOUBLE_HIGH (operands[1]) + && !(SPARC_SETHI_P (CONST_DOUBLE_HIGH (operands[1])) + || SPARC_SIMM13_P (CONST_DOUBLE_HIGH (operands[1])))) + { + emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]), + gen_highpart (SImode, operands[0]))); + } + else + { + emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]), + GEN_INT (CONST_DOUBLE_LOW (operands[1])))); + } + DONE; +}") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" ""))] + "! TARGET_ARCH64 && reload_completed" + [(clobber (const_int 0))] + " +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + if (GET_CODE (set_dest) == SUBREG) + set_dest = alter_subreg (set_dest); + if (GET_CODE (set_src) == SUBREG) + set_src = alter_subreg (set_src); + + dest1 = gen_highpart (SImode, set_dest); + dest2 = gen_lowpart (SImode, set_dest); + src1 = gen_highpart (SImode, set_src); + src2 = gen_lowpart (SImode, set_src); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (REGNO(dest1) == REGNO(src2)) + { + emit_insn (gen_movsi (dest2, src2)); + emit_insn (gen_movsi (dest1, src1)); + } + else + { + emit_insn (gen_movsi (dest1, src1)); + emit_insn (gen_movsi (dest2, src2)); + } + DONE; +}") + +;; Now handle the cases of memory moves from/to non-even +;; DI mode register pairs. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "memory_operand" ""))] + "(! TARGET_ARCH64 + && reload_completed + && sparc_splitdi_legitimate (operands[0], operands[1]))" + [(clobber (const_int 0))] + " +{ + rtx word0 = change_address (operands[1], SImode, NULL_RTX); + rtx word1 = change_address (operands[1], SImode, + plus_constant_for_output (XEXP (word0, 0), 4)); + rtx high_part = gen_highpart (SImode, operands[0]); + rtx low_part = gen_lowpart (SImode, operands[0]); + int self_reference; + + self_reference = reg_mentioned_p (operands[0], + XEXP (XEXP (word1, 0), 0)); + if (self_reference != 0 + && WORDS_BIG_ENDIAN) + { + emit_insn (gen_movsi (low_part, word1)); + emit_insn (gen_movsi (high_part, word0)); + } + else + { + emit_insn (gen_movsi (high_part, word0)); + emit_insn (gen_movsi (low_part, word1)); + } + DONE; +}") + +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "register_operand" ""))] + "(! TARGET_ARCH64 + && reload_completed + && sparc_splitdi_legitimate (operands[1], operands[0]))" + [(clobber (const_int 0))] + " +{ + rtx word0 = change_address (operands[0], SImode, NULL_RTX); + rtx word1 = change_address (operands[0], SImode, + plus_constant_for_output (XEXP (word0, 0), 4)); + rtx high_part = gen_highpart (SImode, operands[1]); + rtx low_part = gen_lowpart (SImode, operands[1]); + + emit_insn (gen_movsi (word0, high_part)); + emit_insn (gen_movsi (word1, low_part)); + DONE; +}") -;; ??? There's no symbolic (set (mem:DI ...) ...). -;; Experimentation with v9 suggested one isn't needed. ;; Floating point move insns -;; This pattern forces (set (reg:SF ...) (const_double ...)) -;; to be reloaded by putting the constant into memory. -;; It must come before the more general movsf pattern. -(define_insn "*movsf_const_insn" - [(set (match_operand:SF 0 "general_operand" "=f,d,m,?r") - (match_operand:SF 1 "" "m,G,G,?F"))] - "TARGET_FPU - && GET_CODE (operands[1]) == CONST_DOUBLE - && (GET_CODE (operands[0]) == REG - || fp_zero_operand (operands[1]))" - "* -{ - switch (which_alternative) - { - case 0: - return \"ld %1,%0\"; - case 1: - return \"fzeros %0\"; - case 2: - return \"st %%g0,%0\"; - case 3: - return singlemove_string (operands); - default: - abort (); - } -}" - [(set_attr "type" "fpload,fpmove,store,load") - (set_attr "length" "1,1,1,2")]) - (define_expand "movsf" [(set (match_operand:SF 0 "general_operand" "") (match_operand:SF 1 "general_operand" ""))] "" " { - if (emit_move_sequence (operands, SFmode)) - DONE; + /* Force SFmode constants into memory. */ + if (GET_CODE (operands[0]) == REG + && CONSTANT_P (operands[1])) + { + /* emit_group_store will send such bogosity to us when it is + not storing directly into memory. So fix this up to avoid + crashes in output_constant_pool. */ + if (operands [1] == const0_rtx) + operands[1] = CONST0_RTX (SFmode); + operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]), + operands[1])); + } + + /* Handle sets of MEM first. */ + if (GET_CODE (operands[0]) == MEM) + { + if (register_operand (operands[1], SFmode)) + goto movsf_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (SFmode, operands[1]); + } + } + + /* Fixup PIC cases. */ + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], SFmode, 0); + + if (symbolic_operand (operands[1], SFmode)) + { + operands[1] = legitimize_pic_address (operands[1], + SFmode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + } + } + + movsf_is_ok: }") (define_insn "*movsf_insn" - [(set (match_operand:SF 0 "reg_or_nonsymb_mem_operand" "=f,f,Q,r,r,Q") - (match_operand:SF 1 "reg_or_nonsymb_mem_operand" "f,Q,f,r,Q,r"))] + [(set (match_operand:SF 0 "general_operand" "=f,f,m,r,r,m") + (match_operand:SF 1 "input_operand" "f,m,f,r,m,r"))] "TARGET_FPU && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" "@ - fmovs %1,%0 - ld %1,%0 - st %1,%0 - mov %1,%0 - ld %1,%0 - st %1,%0" - [(set_attr "type" "fpmove,fpload,fpstore,move,load,store")]) + fmovs\\t%1, %0 + ld\\t%1, %0 + st\\t%1, %0 + mov\\t%1, %0 + ld\\t%1, %0 + st\\t%1, %0" + [(set_attr "type" "fpmove,fpload,fpstore,move,load,store") + (set_attr "length" "1")]) ;; Exactly the same as above, except that all `f' cases are deleted. ;; This is necessary to prevent reload from ever trying to use a `f' reg ;; when -mno-fpu. (define_insn "*movsf_no_f_insn" - [(set (match_operand:SF 0 "reg_or_nonsymb_mem_operand" "=r,r,Q") - (match_operand:SF 1 "reg_or_nonsymb_mem_operand" "r,Q,r"))] + [(set (match_operand:SF 0 "general_operand" "=r,r,m") + (match_operand:SF 1 "input_operand" "r,m,r"))] "! TARGET_FPU && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" "@ - mov %1,%0 - ld %1,%0 - st %1,%0" - [(set_attr "type" "move,load,store")]) - -(define_insn "*store_sf" - [(set (mem:SF (match_operand:SI 0 "symbolic_operand" "i")) - (match_operand:SF 1 "reg_or_0_operand" "rfG")) - (clobber (match_scratch:SI 2 "=&r"))] - "(reload_completed || reload_in_progress) - && ! TARGET_PTR64" - "sethi %%hi(%a0),%2\;st %r1,[%2+%%lo(%a0)]" - [(set_attr "type" "store") - (set_attr "length" "2")]) - -;; This pattern forces (set (reg:DF ...) (const_double ...)) -;; to be reloaded by putting the constant into memory. -;; It must come before the more general movdf pattern. - -(define_insn "*movdf_const_insn" - [(set (match_operand:DF 0 "general_operand" "=?r,e,o,d") - (match_operand:DF 1 "" "?F,m,G,G"))] - "TARGET_FPU - && GET_CODE (operands[1]) == CONST_DOUBLE - && (GET_CODE (operands[0]) == REG - || fp_zero_operand (operands[1]))" - "* -{ - switch (which_alternative) - { - case 0: - return output_move_double (operands); - case 1: - return output_fp_move_double (operands); - case 2: - if (TARGET_ARCH64 || (TARGET_V9 && mem_aligned_8 (operands[0]))) - { - return \"stx %%g0,%0\"; - } - else - { - operands[1] = adj_offsettable_operand (operands[0], 4); - return \"st %%g0,%0\;st %%g0,%1\"; - } - case 3: - return \"fzero %0\"; - default: - abort (); - } -}" - [(set_attr "type" "load,fpload,store,fpmove") - (set_attr "length" "3,3,3,1")]) + mov\\t%1, %0 + ld\\t%1, %0 + st\\t%1, %0" + [(set_attr "type" "move,load,store") + (set_attr "length" "1")]) (define_expand "movdf" [(set (match_operand:DF 0 "general_operand" "") @@ -2471,126 +2823,217 @@ "" " { - if (emit_move_sequence (operands, DFmode)) - DONE; + /* Force DFmode constants into memory. */ + if (GET_CODE (operands[0]) == REG + && CONSTANT_P (operands[1])) + { + /* emit_group_store will send such bogosity to us when it is + not storing directly into memory. So fix this up to avoid + crashes in output_constant_pool. */ + if (operands [1] == const0_rtx) + operands[1] = CONST0_RTX (DFmode); + operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]), + operands[1])); + } + + /* Handle MEM cases first. */ + if (GET_CODE (operands[0]) == MEM) + { + if (register_operand (operands[1], DFmode)) + goto movdf_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (DFmode, operands[1]); + } + } + + /* Fixup PIC cases. */ + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], DFmode, 0); + + if (symbolic_operand (operands[1], DFmode)) + { + operands[1] = legitimize_pic_address (operands[1], + DFmode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + } + } + + movdf_is_ok: }") -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=e,Q,e,T,U,r,Q,r") - (match_operand:DF 1 "reg_or_nonsymb_mem_operand" "e,e,Q,U,T,r,r,Q"))] +;; Be careful, fmovd does not exist when !arch64. +(define_insn "*movdf_insn_sp32" + [(set (match_operand:DF 0 "general_operand" "=e,T,U,T,e,r,r,o,e,o") + (match_operand:DF 1 "input_operand" "T,e,T,U,e,r,o,r,o,e"))] "TARGET_FPU + && ! TARGET_ARCH64 && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" - "* -{ - if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) - return output_fp_move_double (operands); - return output_move_double (operands); -}" - [(set_attr "type" "fpstore,fpload,fp,move,fpstore,store,fpload,load") - (set_attr "length" "1,1,2,2,3,3,3,3")]) + "@ + ldd\\t%1, %0 + std\\t%1, %0 + ldd\\t%1, %0 + std\\t%1, %0 + # + # + # + # + # + #" + [(set_attr "type" "fpload,fpstore,load,store,*,*,*,*,*,*") + (set_attr "length" "1,1,1,1,2,2,2,2,2,2")]) -;; Exactly the same as above, except that all `e' cases are deleted. -;; This is necessary to prevent reload from ever trying to use a `e' reg -;; when -mno-fpu. - -(define_insn "*movdf_no_e_insn" - [(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=T,U,r,Q,&r") - (match_operand:DF 1 "reg_or_nonsymb_mem_operand" "U,T,r,r,Q"))] +(define_insn "*movdf_no_e_insn_sp32" + [(set (match_operand:DF 0 "general_operand" "=U,T,r,r,o") + (match_operand:DF 1 "input_operand" "T,U,r,o,r"))] "! TARGET_FPU + && ! TARGET_ARCH64 && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" - "* return output_move_double (operands);" - [(set_attr "type" "store,load,move,store,load") - (set_attr "length" "1,1,2,3,3")]) + "@ + ldd\\t%1, %0 + std\\t%1, %0 + # + # + #" + [(set_attr "type" "load,store,*,*,*") + (set_attr "length" "1,1,2,2,2")]) -;; Must handle overlapping registers here, since parameters can be unaligned -;; in registers. +(define_insn "*movdf_insn_sp64" + [(set (match_operand:DF 0 "general_operand" "=e,e,m,r,r,m") + (match_operand:DF 1 "input_operand" "e,m,e,r,m,r"))] + "TARGET_FPU + && TARGET_ARCH64 + && (register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode))" + "@ + fmovd\\t%1, %0 + ldd\\t%1, %0 + std\\t%1, %0 + mov\\t%1, %0 + ldx\\t%1, %0 + stx\\t%1, %0" + [(set_attr "type" "fpmove,load,store,move,load,store") + (set_attr "length" "1")]) + +(define_insn "*movdf_no_e_insn_sp64" + [(set (match_operand:DF 0 "general_operand" "=r,r,m") + (match_operand:DF 1 "input_operand" "r,m,r"))] + "! TARGET_FPU + && TARGET_ARCH64 + && (register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode))" + "@ + mov\\t%1, %0 + ldx\\t%1, %0 + stx\\t%1, %0" + [(set_attr "type" "move,load,store") + (set_attr "length" "1")]) + +;; Ok, now the splits to handle all the multi insn and +;; mis-aligned memory address cases. +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" ""))] + "! TARGET_ARCH64 && reload_completed" + [(clobber (const_int 0))] + " +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + if (GET_CODE (set_dest) == SUBREG) + set_dest = alter_subreg (set_dest); + if (GET_CODE (set_src) == SUBREG) + set_src = alter_subreg (set_src); + + dest1 = gen_highpart (SFmode, set_dest); + dest2 = gen_lowpart (SFmode, set_dest); + src1 = gen_highpart (SFmode, set_src); + src2 = gen_lowpart (SFmode, set_src); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (REGNO(dest1) == REGNO(src2)) + { + emit_insn (gen_movsf (dest2, src2)); + emit_insn (gen_movsf (dest1, src1)); + } + else + { + emit_insn (gen_movsf (dest1, src1)); + emit_insn (gen_movsf (dest2, src2)); + } + DONE; +}") (define_split [(set (match_operand:DF 0 "register_operand" "") - (match_operand:DF 1 "register_operand" ""))] - "! TARGET_ARCH64 && reload_completed - && REGNO (operands[0]) < SPARC_FIRST_V9_FP_REG - && REGNO (operands[1]) < SPARC_FIRST_V9_FP_REG" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] + (match_operand:DF 1 "memory_operand" ""))] + "(! TARGET_ARCH64 + && (reload_completed + && (((REGNO (operands[0])) % 2) != 0 + || ! mem_min_alignment (operands[1], 8)) + && offsettable_memref_p (operands[1])))" + [(clobber (const_int 0))] " { - rtx first_set = operand_subword (operands[0], 0, 0, DFmode); - rtx second_use = operand_subword (operands[1], 1, 0, DFmode); + rtx word0 = change_address (operands[1], SFmode, NULL_RTX); + rtx word1 = change_address (operands[1], SFmode, + plus_constant_for_output (XEXP (word0, 0), 4)); + int self_reference; - if (REGNO (first_set) == REGNO (second_use)) + self_reference = reg_mentioned_p (operands[0], + XEXP (XEXP (word1, 0), 0)); + if (self_reference != 0 + && WORDS_BIG_ENDIAN) { - operands[2] = operand_subword (operands[0], 1, 0, DFmode); - operands[3] = second_use; - operands[4] = first_set; - operands[5] = operand_subword (operands[1], 0, 0, DFmode); + emit_insn (gen_movsf (gen_lowpart (SFmode, operands[0]), + word1)); + emit_insn (gen_movsf (gen_highpart (SFmode, operands[0]), + word0)); } else { - operands[2] = first_set; - operands[3] = operand_subword (operands[1], 0, 0, DFmode); - operands[4] = operand_subword (operands[0], 1, 0, DFmode); - operands[5] = second_use; + emit_insn (gen_movsf (gen_highpart (SFmode, operands[0]), + word0)); + emit_insn (gen_movsf (gen_lowpart (SFmode, operands[0]), + word1)); } + DONE; }") -(define_insn "*store_df" - [(set (mem:DF (match_operand:SI 0 "symbolic_operand" "i,i")) - (match_operand:DF 1 "reg_or_0_operand" "re,G")) - (clobber (match_scratch:SI 2 "=&r,&r"))] - "(reload_completed || reload_in_progress) - && ! TARGET_PTR64" - "* +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (match_operand:DF 1 "register_operand" ""))] + "(! TARGET_ARCH64 + && (reload_completed + && (((REGNO (operands[1])) % 2) != 0 + || ! mem_min_alignment (operands[0], 8)) + && offsettable_memref_p (operands[0])))" + [(clobber (const_int 0))] + " { - output_asm_insn (\"sethi %%hi(%a0),%2\", operands); - if (which_alternative == 0) - return \"std %1,[%2+%%lo(%a0)]\"; - else - return \"st %%g0,[%2+%%lo(%a0)]\;st %%g0,[%2+%%lo(%a0+4)]\"; -}" - [(set_attr "type" "store") - (set_attr "length" "3")]) + rtx word0 = change_address (operands[0], SFmode, NULL_RTX); + rtx word1 = change_address (operands[0], SFmode, + plus_constant_for_output (XEXP (word0, 0), 4)); -;; This pattern forces (set (reg:TF ...) (const_double ...)) -;; to be reloaded by putting the constant into memory. -;; It must come before the more general movtf pattern. -(define_insn "*movtf_const_insn" - [(set (match_operand:TF 0 "general_operand" "=?r,e,o") - (match_operand:TF 1 "" "?F,m,G"))] - "TARGET_FPU - && GET_CODE (operands[1]) == CONST_DOUBLE - && (GET_CODE (operands[0]) == REG - || fp_zero_operand (operands[1]))" - "* -{ - switch (which_alternative) - { - case 0: - return output_move_quad (operands); - case 1: - return output_fp_move_quad (operands); - case 2: - if (TARGET_ARCH64 || (TARGET_V9 && mem_aligned_8 (operands[0]))) - { - operands[1] = adj_offsettable_operand (operands[0], 8); - return \"stx %%g0,%0\;stx %%g0,%1\"; - } - else - { - /* ??? Do we run off the end of the array here? */ - operands[1] = adj_offsettable_operand (operands[0], 4); - operands[2] = adj_offsettable_operand (operands[0], 8); - operands[3] = adj_offsettable_operand (operands[0], 12); - return \"st %%g0,%0\;st %%g0,%1\;st %%g0,%2\;st %%g0,%3\"; - } - default: - abort (); - } -}" - [(set_attr "type" "load,fpload,store") - (set_attr "length" "5,5,5")]) + emit_insn (gen_movsf (word0, + gen_highpart (SFmode, operands[1]))); + emit_insn (gen_movsf (word1, + gen_lowpart (SFmode, operands[1]))); + DONE; +}") (define_expand "movtf" [(set (match_operand:TF 0 "general_operand" "") @@ -2598,63 +3041,201 @@ "" " { - if (emit_move_sequence (operands, TFmode)) - DONE; + /* Force TFmode constants into memory. */ + if (GET_CODE (operands[0]) == REG + && CONSTANT_P (operands[1])) + { + /* emit_group_store will send such bogosity to us when it is + not storing directly into memory. So fix this up to avoid + crashes in output_constant_pool. */ + if (operands [1] == const0_rtx) + operands[1] = CONST0_RTX (TFmode); + operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]), + operands[1])); + } + + /* Handle MEM cases first, note that even v9 only guarentees + 8-byte alignment for quads so... */ + if (GET_CODE (operands[0]) == MEM) + { + if (register_operand (operands[1], TFmode)) + goto movtf_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (TFmode, operands[1]); + } + } + + /* Fixup PIC cases. */ + if (flag_pic) + { + if (CONSTANT_P (operands[1]) + && pic_address_needs_scratch (operands[1])) + operands[1] = legitimize_pic_address (operands[1], TFmode, 0); + + if (symbolic_operand (operands[1], TFmode)) + { + operands[1] = legitimize_pic_address (operands[1], + TFmode, + (reload_in_progress ? + operands[0] : + NULL_RTX)); + } + } + +movtf_is_ok: }") -(define_insn "*movtf_insn" - [(set (match_operand:TF 0 "reg_or_nonsymb_mem_operand" "=e,Q,e,r,Q,r") - (match_operand:TF 1 "reg_or_nonsymb_mem_operand" "e,e,Q,r,r,Q"))] +;; Be careful, fmovq and {st,ld}{x,q} do not exist when !arch64 so +;; we must split them all. :-( +(define_insn "*movtf_insn_sp32" + [(set (match_operand:TF 0 "general_operand" "=e,m,U,o,e,r,r,o") + (match_operand:TF 1 "input_operand" "m,e,o,U,e,r,o,r"))] "TARGET_FPU + && ! TARGET_ARCH64 && (register_operand (operands[0], TFmode) || register_operand (operands[1], TFmode))" - "* -{ - if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) - return output_fp_move_quad (operands); - return output_move_quad (operands); -}" - [(set_attr "type" "fp,move,fpstore,store,fpload,load") - (set_attr "length" "4,4,5,5,5,5")]) + "#" + [(set_attr "length" "4")]) ;; Exactly the same as above, except that all `e' cases are deleted. ;; This is necessary to prevent reload from ever trying to use a `e' reg ;; when -mno-fpu. -(define_insn "*movtf_no_e_insn" - [(set (match_operand:TF 0 "reg_or_nonsymb_mem_operand" "=r,Q,&r") - (match_operand:TF 1 "reg_or_nonsymb_mem_operand" "r,r,Q"))] +(define_insn "*movtf_no_e_insn_sp32" + [(set (match_operand:TF 0 "general_operand" "=U,o,r,r,o") + (match_operand:TF 1 "input_operand" "o,U,r,o,r"))] "! TARGET_FPU + && ! TARGET_ARCH64 && (register_operand (operands[0], TFmode) || register_operand (operands[1], TFmode))" - "* -{ - if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) - return output_fp_move_quad (operands); - return output_move_quad (operands); -}" - [(set_attr "type" "move,store,load") - (set_attr "length" "4,5,5")]) + "#" + [(set_attr "length" "4")]) -;; This is disabled because it does not work. Long doubles have only 8 -;; byte alignment. Adding an offset of 8 or 12 to an 8 byte aligned %lo may -;; cause it to overflow. See also GO_IF_LEGITIMATE_ADDRESS. -(define_insn "*store_tf" - [(set (mem:TF (match_operand:SI 0 "symbolic_operand" "i,i")) - (match_operand:TF 1 "reg_or_0_operand" "re,G")) - (clobber (match_scratch:SI 2 "=&r,&r"))] - "0 && (reload_completed || reload_in_progress) - && ! TARGET_PTR64" - "* +;; Now handle the float reg cases directly when arch64, +;; hard_quad, and proper reg number alignment are all true. +(define_insn "*movtf_insn_hq_sp64" + [(set (match_operand:TF 0 "general_operand" "=e,e,m,r,r,o") + (match_operand:TF 1 "input_operand" "e,m,e,r,o,r"))] + "TARGET_FPU + && TARGET_ARCH64 + && TARGET_V9 + && TARGET_HARD_QUAD + && (register_operand (operands[0], TFmode) + || register_operand (operands[1], TFmode))" + "@ + fmovq\\t%1, %0 + ldq\\t%1, %0 + stq\\t%1, %0 + # + # + #" + [(set_attr "type" "fpmove,fpload,fpstore,*,*,*") + (set_attr "length" "1,1,1,2,2,2")]) + +;; Now we allow the integer register cases even when +;; only arch64 is true. +(define_insn "*movtf_insn_sp64" + [(set (match_operand:TF 0 "general_operand" "=e,e,o,r,r,o") + (match_operand:TF 1 "input_operand" "e,o,e,r,o,r"))] + "TARGET_FPU + && TARGET_ARCH64 + && ! TARGET_HARD_QUAD + && (register_operand (operands[0], TFmode) + || register_operand (operands[1], TFmode))" + "#" + [(set_attr "length" "2")]) + +(define_insn "*movtf_no_e_insn_sp64" + [(set (match_operand:TF 0 "general_operand" "=r,r,o") + (match_operand:TF 1 "input_operand" "r,o,r"))] + "! TARGET_FPU + && TARGET_ARCH64 + && (register_operand (operands[0], TFmode) + || register_operand (operands[1], TFmode))" + "#" + [(set_attr "length" "2")]) + +;; Now all the splits to handle multi-insn TF mode moves. +(define_split + [(set (match_operand:TF 0 "register_operand" "") + (match_operand:TF 1 "register_operand" ""))] + "reload_completed + && (! TARGET_ARCH64 + || (TARGET_FPU + && ! TARGET_HARD_QUAD))" + [(clobber (const_int 0))] + " { - output_asm_insn (\"sethi %%hi(%a0),%2\", operands); - if (which_alternative == 0) - return \"std %1,[%2+%%lo(%a0)]\;std %S1,[%2+%%lo(%a0+8)]\"; + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + if (GET_CODE (set_dest) == SUBREG) + set_dest = alter_subreg (set_dest); + if (GET_CODE (set_src) == SUBREG) + set_src = alter_subreg (set_src); + + dest1 = gen_highpart (DFmode, set_dest); + dest2 = gen_lowpart (DFmode, set_dest); + src1 = gen_highpart (DFmode, set_src); + src2 = gen_lowpart (DFmode, set_src); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (REGNO(dest1) == REGNO(src2)) + { + emit_insn (gen_movdf (dest2, src2)); + emit_insn (gen_movdf (dest1, src1)); + } else - return \"st %%g0,[%2+%%lo(%a0)]\;st %%g0,[%2+%%lo(%a0+4)]\; st %%g0,[%2+%%lo(%a0+8)]\;st %%g0,[%2+%%lo(%a0+12)]\"; -}" - [(set_attr "type" "store") - (set_attr "length" "5")]) + { + emit_insn (gen_movdf (dest1, src1)); + emit_insn (gen_movdf (dest2, src2)); + } + DONE; +}") + +(define_split + [(set (match_operand:TF 0 "register_operand" "") + (match_operand:TF 1 "memory_operand" ""))] + "(reload_completed + && offsettable_memref_p (operands[1]))" + [(clobber (const_int 0))] + " +{ + rtx word0 = change_address (operands[1], DFmode, NULL_RTX); + rtx word1 = change_address (operands[1], DFmode, + plus_constant_for_output (XEXP (word0, 0), 8)); + + emit_insn (gen_movdf (gen_highpart (DFmode, operands[0]), + word0)); + emit_insn (gen_movdf (gen_lowpart (DFmode, operands[0]), + word1)); + DONE; +}") + +(define_split + [(set (match_operand:TF 0 "memory_operand" "") + (match_operand:TF 1 "register_operand" ""))] + "(reload_completed + && offsettable_memref_p (operands[0]))" + [(clobber (const_int 0))] + " +{ + rtx word0 = change_address (operands[0], DFmode, NULL_RTX); + rtx word1 = change_address (operands[0], DFmode, + plus_constant_for_output (XEXP (word0, 0), 8)); + + emit_insn (gen_movdf (word0, + gen_highpart (DFmode, operands[1]))); + emit_insn (gen_movdf (word1, + gen_lowpart (DFmode, operands[1]))); + DONE; +}") ;; Sparc V9 conditional move instructions. @@ -2737,8 +3318,7 @@ if (sparc_compare_op1 == const0_rtx && GET_CODE (sparc_compare_op0) == REG - && ((TARGET_ARCH64 && op0_mode == DImode && v9_regcmp_p (code)) - || (op0_mode == SImode && v8plus_regcmp_p (code)))) + && (TARGET_ARCH64 && op0_mode == DImode && v9_regcmp_p (code))) { operands[1] = gen_rtx_fmt_ee (code, op0_mode, sparc_compare_op0, sparc_compare_op1); @@ -2880,9 +3460,10 @@ (match_operand:QI 4 "arith11_operand" "0,rL")))] "TARGET_V9" "@ - mov%C1 %x2,%3,%0 - mov%c1 %x2,%4,%0" - [(set_attr "type" "cmove")]) + mov%C1\\t%x2, %3, %0 + mov%c1\\t%x2, %4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) (define_insn "*movhi_cc_sp64" [(set (match_operand:HI 0 "register_operand" "=r,r") @@ -2893,9 +3474,10 @@ (match_operand:HI 4 "arith11_operand" "0,rL")))] "TARGET_V9" "@ - mov%C1 %x2,%3,%0 - mov%c1 %x2,%4,%0" - [(set_attr "type" "cmove")]) + mov%C1\\t%x2, %3, %0 + mov%c1\\t%x2, %4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) (define_insn "*movsi_cc_sp64" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -2906,9 +3488,10 @@ (match_operand:SI 4 "arith11_operand" "0,rL")))] "TARGET_V9" "@ - mov%C1 %x2,%3,%0 - mov%c1 %x2,%4,%0" - [(set_attr "type" "cmove")]) + mov%C1\\t%x2, %3, %0 + mov%c1\\t%x2, %4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) ;; ??? The constraints of operands 3,4 need work. (define_insn "*movdi_cc_sp64" @@ -2920,9 +3503,24 @@ (match_operand:DI 4 "arith11_double_operand" "0,rLH")))] "TARGET_ARCH64" "@ - mov%C1 %x2,%3,%0 - mov%c1 %x2,%4,%0" - [(set_attr "type" "cmove")]) + mov%C1\\t%x2, %3, %0 + mov%c1\\t%x2, %4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) + +(define_insn "*movdi_cc_sp64_trunc" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "icc_or_fcc_reg_operand" "X,X") + (const_int 0)]) + (match_operand:SI 3 "arith11_double_operand" "rLH,0") + (match_operand:SI 4 "arith11_double_operand" "0,rLH")))] + "TARGET_ARCH64" + "@ + mov%C1\\t%x2, %3, %0 + mov%c1\\t%x2, %4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) (define_insn "*movsf_cc_sp64" [(set (match_operand:SF 0 "register_operand" "=f,f") @@ -2933,9 +3531,10 @@ (match_operand:SF 4 "register_operand" "0,f")))] "TARGET_V9 && TARGET_FPU" "@ - fmovs%C1 %x2,%3,%0 - fmovs%c1 %x2,%4,%0" - [(set_attr "type" "fpcmove")]) + fmovs%C1\\t%x2, %3, %0 + fmovs%c1\\t%x2, %4, %0" + [(set_attr "type" "fpcmove") + (set_attr "length" "1")]) (define_insn "*movdf_cc_sp64" [(set (match_operand:DF 0 "register_operand" "=e,e") @@ -2946,9 +3545,10 @@ (match_operand:DF 4 "register_operand" "0,e")))] "TARGET_V9 && TARGET_FPU" "@ - fmovd%C1 %x2,%3,%0 - fmovd%c1 %x2,%4,%0" - [(set_attr "type" "fpcmove")]) + fmovd%C1\\t%x2, %3, %0 + fmovd%c1\\t%x2, %4, %0" + [(set_attr "type" "fpcmove") + (set_attr "length" "1")]) (define_insn "*movtf_cc_sp64" [(set (match_operand:TF 0 "register_operand" "=e,e") @@ -2959,9 +3559,10 @@ (match_operand:TF 4 "register_operand" "0,e")))] "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD" "@ - fmovq%C1 %x2,%3,%0 - fmovq%c1 %x2,%4,%0" - [(set_attr "type" "fpcmove")]) + fmovq%C1\\t%x2, %3, %0 + fmovq%c1\\t%x2, %4, %0" + [(set_attr "type" "fpcmove") + (set_attr "length" "1")]) (define_insn "*movqi_cc_reg_sp64" [(set (match_operand:QI 0 "register_operand" "=r,r") @@ -2972,9 +3573,10 @@ (match_operand:QI 4 "arith10_operand" "0,rM")))] "TARGET_ARCH64" "@ - movr%D1 %2,%r3,%0 - movr%d1 %2,%r4,%0" - [(set_attr "type" "cmove")]) + movr%D1\\t%2, %r3, %0 + movr%d1\\t%2, %r4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) (define_insn "*movhi_cc_reg_sp64" [(set (match_operand:HI 0 "register_operand" "=r,r") @@ -2985,9 +3587,10 @@ (match_operand:HI 4 "arith10_operand" "0,rM")))] "TARGET_ARCH64" "@ - movr%D1 %2,%r3,%0 - movr%d1 %2,%r4,%0" - [(set_attr "type" "cmove")]) + movr%D1\\t%2, %r3, %0 + movr%d1\\t%2, %r4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) (define_insn "*movsi_cc_reg_sp64" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -2998,60 +3601,10 @@ (match_operand:SI 4 "arith10_operand" "0,rM")))] "TARGET_ARCH64" "@ - movr%D1 %2,%r3,%0 - movr%d1 %2,%r4,%0" - [(set_attr "type" "cmove")]) - -;; On UltraSPARC this is slightly worse than cmp/mov %icc if the register -;; needs to be zero extended but better on average. -(define_insn "*movsi_cc_reg_v8plus" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (if_then_else:SI (match_operator 1 "v8plus_regcmp_op" - [(match_operand:SI 2 "register_operand" "r,r") - (const_int 0)]) - (match_operand:SI 3 "arith10_operand" "rM,0") - (match_operand:SI 4 "arith10_operand" "0,rM")))] - "TARGET_V9" - "* -{ - if (! sparc_check_64 (operands[2], insn)) - output_asm_insn (\"srl %2,0,%2\", operands); - if (which_alternative == 0) - return \"movr%D1 %2,%r3,%0\"; - return \"movr%d1 %2,%r4,%0\"; -}" + movr%D1\\t%2, %r3, %0 + movr%d1\\t%2, %r4, %0" [(set_attr "type" "cmove") - (set_attr "length" "2")]) - -;; To work well this needs to know the current insn, but that is not an -;; argument to gen_split_*. - -(define_split - [(set (match_operand:SI 0 "register_operand" "=r,r") - (if_then_else:SI (match_operator 1 "v8plus_regcmp_op" - [(match_operand:SI 2 "register_operand" "r,r") - (const_int 0)]) - (match_operand:SI 3 "arith10_operand" "rM,0") - (match_operand:SI 4 "arith10_operand" "0,rM")))] - "reload_completed" - [(set (match_dup 0) - (unspec:SI [(match_dup 1) (match_dup 3) (match_dup 4)] 9))] - "if (! sparc_check_64 (operands[2], NULL_RTX)) - emit_insn (gen_v8plus_clear_high (operands[2], operands[2]));") - -;; A conditional move with the condition argument known to be zero extended -(define_insn "" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (unspec:SI [(match_operator 1 "v8plus_regcmp_op" - [(match_operand:SI 2 "register_operand" "r,r") - (const_int 0)]) - (match_operand:SI 3 "arith10_operand" "rM,0") - (match_operand:SI 4 "arith10_operand" "0,rM")] 9))] - "TARGET_V9" - "@ - movr%D1 %2,%r3,%0 - movr%d1 %2,%r4,%0" - [(set_attr "type" "cmove")]) + (set_attr "length" "1")]) ;; ??? The constraints of operands 3,4 need work. (define_insn "*movdi_cc_reg_sp64" @@ -3063,9 +3616,24 @@ (match_operand:DI 4 "arith10_double_operand" "0,rMH")))] "TARGET_ARCH64" "@ - movr%D1 %2,%r3,%0 - movr%d1 %2,%r4,%0" - [(set_attr "type" "cmove")]) + movr%D1\\t%2, %r3, %0 + movr%d1\\t%2, %r4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) + +(define_insn "*movdi_cc_reg_sp64_trunc" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:DI (match_operator 1 "v9_regcmp_op" + [(match_operand:DI 2 "register_operand" "r,r") + (const_int 0)]) + (match_operand:SI 3 "arith10_double_operand" "rMH,0") + (match_operand:SI 4 "arith10_double_operand" "0,rMH")))] + "TARGET_ARCH64" + "@ + movr%D1\\t%2, %r3, %0 + movr%d1\\t%2, %r4, %0" + [(set_attr "type" "cmove") + (set_attr "length" "1")]) (define_insn "*movsf_cc_reg_sp64" [(set (match_operand:SF 0 "register_operand" "=f,f") @@ -3076,9 +3644,10 @@ (match_operand:SF 4 "register_operand" "0,f")))] "TARGET_ARCH64 && TARGET_FPU" "@ - fmovrs%D1 %2,%3,%0 - fmovrs%d1 %2,%4,%0" - [(set_attr "type" "fpcmove")]) + fmovrs%D1\\t%2, %3, %0 + fmovrs%d1\\t%2, %4, %0" + [(set_attr "type" "fpcmove") + (set_attr "length" "1")]) (define_insn "*movdf_cc_reg_sp64" [(set (match_operand:DF 0 "register_operand" "=e,e") @@ -3089,9 +3658,10 @@ (match_operand:DF 4 "register_operand" "0,e")))] "TARGET_ARCH64 && TARGET_FPU" "@ - fmovrd%D1 %2,%3,%0 - fmovrd%d1 %2,%4,%0" - [(set_attr "type" "fpcmove")]) + fmovrd%D1\\t%2, %3, %0 + fmovrd%d1\\t%2, %4, %0" + [(set_attr "type" "fpcmove") + (set_attr "length" "1")]) (define_insn "*movtf_cc_reg_sp64" [(set (match_operand:TF 0 "register_operand" "=e,e") @@ -3102,9 +3672,10 @@ (match_operand:TF 4 "register_operand" "0,e")))] "TARGET_ARCH64 && TARGET_FPU" "@ - fmovrq%D1 %2,%3,%0 - fmovrq%d1 %2,%4,%0" - [(set_attr "type" "fpcmove")]) + fmovrq%D1\\t%2, %3, %0 + fmovrq%d1\\t%2, %4, %0" + [(set_attr "type" "fpcmove") + (set_attr "length" "1")]) ;;- zero extension instructions @@ -3139,8 +3710,9 @@ [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] "" - "lduh %1,%0" - [(set_attr "type" "load")]) + "lduh\\t%1, %0" + [(set_attr "type" "load") + (set_attr "length" "1")]) (define_expand "zero_extendqihi2" [(set (match_operand:HI 0 "register_operand" "") @@ -3150,11 +3722,11 @@ (define_insn "*zero_extendqihi2_insn" [(set (match_operand:HI 0 "register_operand" "=r,r") - (zero_extend:HI (match_operand:QI 1 "sparc_operand" "r,Q")))] + (zero_extend:HI (match_operand:QI 1 "input_operand" "r,m")))] "GET_CODE (operands[1]) != CONST_INT" "@ - and %1,0xff,%0 - ldub %1,%0" + and\\t%1, 0xff, %0 + ldub\\t%1, %0" [(set_attr "type" "unary,load") (set_attr "length" "1")]) @@ -3166,11 +3738,11 @@ (define_insn "*zero_extendqisi2_insn" [(set (match_operand:SI 0 "register_operand" "=r,r") - (zero_extend:SI (match_operand:QI 1 "sparc_operand" "r,Q")))] + (zero_extend:SI (match_operand:QI 1 "input_operand" "r,m")))] "GET_CODE (operands[1]) != CONST_INT" "@ - and %1,0xff,%0 - ldub %1,%0" + and\\t%1, 0xff, %0 + ldub\\t%1, %0" [(set_attr "type" "unary,load") (set_attr "length" "1")]) @@ -3182,11 +3754,11 @@ (define_insn "*zero_extendqidi2_insn" [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI (match_operand:QI 1 "sparc_operand" "r,Q")))] + (zero_extend:DI (match_operand:QI 1 "input_operand" "r,m")))] "TARGET_ARCH64 && GET_CODE (operands[1]) != CONST_INT" "@ - and %1,0xff,%0 - ldub %1,%0" + and\\t%1, 0xff, %0 + ldub\\t%1, %0" [(set_attr "type" "unary,load") (set_attr "length" "1")]) @@ -3217,8 +3789,9 @@ [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (match_operand:HI 1 "memory_operand" "m")))] "TARGET_ARCH64" - "lduh %1,%0" - [(set_attr "type" "load")]) + "lduh\\t%1, %0" + [(set_attr "type" "load") + (set_attr "length" "1")]) ;; ??? Write truncdisi pattern using sra? @@ -3231,37 +3804,24 @@ (define_insn "*zero_extendsidi2_insn" [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI (match_operand:SI 1 "sparc_operand" "r,Q")))] + (zero_extend:DI (match_operand:SI 1 "input_operand" "r,m")))] "TARGET_ARCH64 && GET_CODE (operands[1]) != CONST_INT" "@ - srl %1,0,%0 - lduw %1,%0" + srl\\t%1, 0, %0 + lduw\\t%1, %0" [(set_attr "type" "unary,load") (set_attr "length" "1")]) -;; Zero extend a 32 bit value in a 64 bit register. -(define_insn "v8plus_clear_high" - [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,Q") - (unspec:SI [(match_operand:SI 1 "register_operand" "r,r")] 10))] - "TARGET_V9" - "* -if (which_alternative == 1) - return \"st %1,%0\"; -if (sparc_check_64 (operands[1], insn) > 0) - return final_sequence ? \"nop\" : \"\"; -return \"srl %1,0,%0\"; -" - [(set_attr "type" "shift,store")]) - ;; Simplify comparisons of extended values. (define_insn "*cmp_zero_extendqisi2" [(set (reg:CC 100) (compare:CC (zero_extend:SI (match_operand:QI 0 "register_operand" "r")) (const_int 0)))] - "" - "andcc %0,0xff,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "andcc\\t%0, 0xff, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_zero_extendqisi2_set" [(set (reg:CC 100) @@ -3270,18 +3830,40 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_dup 1)))] "" - "andcc %1,0xff,%0" - [(set_attr "type" "unary")]) + "andcc\\t%1, 0xff, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) -;; Similarly, handle SI->QI mode truncation followed by a compare. +(define_insn "*cmp_zero_extendqidi2" + [(set (reg:CCX 100) + (compare:CCX (zero_extend:DI (match_operand:QI 0 "register_operand" "r")) + (const_int 0)))] + "TARGET_ARCH64" + "andcc\\t%0, 0xff, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) + +(define_insn "*cmp_zero_extendqidi2_set" + [(set (reg:CCX 100) + (compare:CCX (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (match_dup 1)))] + "TARGET_ARCH64" + "andcc\\t%1, 0xff, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) + +;; Similarly, handle {SI,DI}->QI mode truncation followed by a compare. (define_insn "*cmp_siqi_trunc" [(set (reg:CC 100) (compare:CC (subreg:QI (match_operand:SI 0 "register_operand" "r") 0) (const_int 0)))] - "" - "andcc %0,0xff,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "andcc\\t%0, 0xff, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_siqi_trunc_set" [(set (reg:CC 100) @@ -3290,8 +3872,29 @@ return \"srl %1,0,%0\"; (set (match_operand:QI 0 "register_operand" "=r") (match_dup 1))] "" - "andcc %1,0xff,%0" - [(set_attr "type" "unary")]) + "andcc\\t%1, 0xff, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) + +(define_insn "*cmp_diqi_trunc" + [(set (reg:CC 100) + (compare:CC (subreg:QI (match_operand:DI 0 "register_operand" "r") 0) + (const_int 0)))] + "TARGET_ARCH64" + "andcc\\t%0, 0xff, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) + +(define_insn "*cmp_diqi_trunc_set" + [(set (reg:CC 100) + (compare:CC (subreg:QI (match_operand:DI 1 "register_operand" "r") 0) + (const_int 0))) + (set (match_operand:QI 0 "register_operand" "=r") + (match_dup 1))] + "TARGET_ARCH64" + "andcc\\t%1, 0xff, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) ;;- sign extension instructions @@ -3326,8 +3929,9 @@ return \"srl %1,0,%0\"; [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] "" - "ldsh %1,%0" - [(set_attr "type" "sload")]) + "ldsh\\t%1, %0" + [(set_attr "type" "sload") + (set_attr "length" "1")]) (define_expand "extendqihi2" [(set (match_operand:HI 0 "register_operand" "") @@ -3363,8 +3967,9 @@ return \"srl %1,0,%0\"; [(set (match_operand:HI 0 "register_operand" "=r") (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] "" - "ldsb %1,%0" - [(set_attr "type" "sload")]) + "ldsb\\t%1, %0" + [(set_attr "type" "sload") + (set_attr "length" "1")]) (define_expand "extendqisi2" [(set (match_operand:SI 0 "register_operand" "") @@ -3393,8 +3998,9 @@ return \"srl %1,0,%0\"; [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] "" - "ldsb %1,%0" - [(set_attr "type" "sload")]) + "ldsb\\t%1, %0" + [(set_attr "type" "sload") + (set_attr "length" "1")]) (define_expand "extendqidi2" [(set (match_operand:DI 0 "register_operand" "") @@ -3423,8 +4029,9 @@ return \"srl %1,0,%0\"; [(set (match_operand:DI 0 "register_operand" "=r") (sign_extend:DI (match_operand:QI 1 "memory_operand" "m")))] "TARGET_ARCH64" - "ldsb %1,%0" - [(set_attr "type" "sload")]) + "ldsb\\t%1, %0" + [(set_attr "type" "sload") + (set_attr "length" "1")]) (define_expand "extendhidi2" [(set (match_operand:DI 0 "register_operand" "") @@ -3453,8 +4060,9 @@ return \"srl %1,0,%0\"; [(set (match_operand:DI 0 "register_operand" "=r") (sign_extend:DI (match_operand:HI 1 "memory_operand" "m")))] "TARGET_ARCH64" - "ldsh %1,%0" - [(set_attr "type" "load")]) + "ldsh\\t%1, %0" + [(set_attr "type" "load") + (set_attr "length" "1")]) (define_expand "extendsidi2" [(set (match_operand:DI 0 "register_operand" "") @@ -3464,11 +4072,11 @@ return \"srl %1,0,%0\"; (define_insn "*sign_extendsidi2_insn" [(set (match_operand:DI 0 "register_operand" "=r,r") - (sign_extend:DI (match_operand:SI 1 "sparc_operand" "r,Q")))] + (sign_extend:DI (match_operand:SI 1 "input_operand" "r,m")))] "TARGET_ARCH64" "@ - sra %1,0,%0 - ldsw %1,%0" + sra\\t%1, 0, %0 + ldsw\\t%1, %0" [(set_attr "type" "unary,sload") (set_attr "length" "1")]) @@ -3479,37 +4087,59 @@ return \"srl %1,0,%0\"; [(set (reg:CC 100) (compare:CC (zero_extract:SI (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "small_int" "n") - (match_operand:SI 2 "small_int" "n")) + (match_operand:SI 1 "small_int_or_double" "n") + (match_operand:SI 2 "small_int_or_double" "n")) (const_int 0)))] - "INTVAL (operands[2]) > 19" + "! TARGET_LIVE_G0 + && ((GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 19) + || (GET_CODE (operands[2]) == CONST_DOUBLE + && CONST_DOUBLE_LOW (operands[2]) > 19))" "* { - int len = INTVAL (operands[1]); - int pos = 32 - INTVAL (operands[2]) - len; + int len = (GET_CODE (operands[1]) == CONST_INT + ? INTVAL (operands[1]) + : CONST_DOUBLE_LOW (operands[1])); + int pos = 32 - + (GET_CODE (operands[2]) == CONST_INT + ? INTVAL (operands[2]) + : CONST_DOUBLE_LOW (operands[2])) - len; unsigned mask = ((1 << len) - 1) << pos; operands[1] = GEN_INT (mask); - return \"andcc %0,%1,%%g0\"; -}") + return \"andcc\\t%0, %1, %%g0\"; +}" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_zero_extract_sp64" [(set (reg:CCX 100) (compare:CCX (zero_extract:DI (match_operand:DI 0 "register_operand" "r") - (match_operand:SI 1 "small_int" "n") - (match_operand:SI 2 "small_int" "n")) + (match_operand:SI 1 "small_int_or_double" "n") + (match_operand:SI 2 "small_int_or_double" "n")) (const_int 0)))] - "TARGET_ARCH64 && INTVAL (operands[2]) > 51" + "TARGET_ARCH64 + && ((GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 51) + || (GET_CODE (operands[2]) == CONST_DOUBLE + && CONST_DOUBLE_LOW (operands[2]) > 51))" "* { - int len = INTVAL (operands[1]); - int pos = 64 - INTVAL (operands[2]) - len; + int len = (GET_CODE (operands[1]) == CONST_INT + ? INTVAL (operands[1]) + : CONST_DOUBLE_LOW (operands[1])); + int pos = 64 - + (GET_CODE (operands[2]) == CONST_INT + ? INTVAL (operands[2]) + : CONST_DOUBLE_LOW (operands[2])) - len; unsigned HOST_WIDE_INT mask = (((unsigned HOST_WIDE_INT) 1 << len) - 1) << pos; operands[1] = GEN_INT (mask); - return \"andcc %0,%1,%%g0\"; -}") + return \"andcc\\t%0, %1, %%g0\"; +}" + [(set_attr "type" "compare") + (set_attr "length" "1")]) ;; Conversions between float, double and long double. @@ -3518,48 +4148,54 @@ return \"srl %1,0,%0\"; (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] "TARGET_FPU" - "fstod %1,%0" - [(set_attr "type" "fp")]) + "fstod\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "extendsftf2" [(set (match_operand:TF 0 "register_operand" "=e") (float_extend:TF (match_operand:SF 1 "register_operand" "f")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fstoq %1,%0" - [(set_attr "type" "fp")]) + "fstoq\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "extenddftf2" [(set (match_operand:TF 0 "register_operand" "=e") (float_extend:TF (match_operand:DF 1 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fdtoq %1,%0" - [(set_attr "type" "fp")]) + "fdtoq\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "truncdfsf2" [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "register_operand" "e")))] "TARGET_FPU" - "fdtos %1,%0" - [(set_attr "type" "fp")]) + "fdtos\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "trunctfsf2" [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:TF 1 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fqtos %1,%0" - [(set_attr "type" "fp")]) + "fqtos\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "trunctfdf2" [(set (match_operand:DF 0 "register_operand" "=e") (float_truncate:DF (match_operand:TF 1 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fqtod %1,%0" - [(set_attr "type" "fp")]) + "fqtod\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) ;; Conversion between fixed point and floating point. @@ -3567,22 +4203,25 @@ return \"srl %1,0,%0\"; [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:SI 1 "register_operand" "f")))] "TARGET_FPU" - "fitos %1,%0" - [(set_attr "type" "fp")]) + "fitos\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "floatsidf2" [(set (match_operand:DF 0 "register_operand" "=e") (float:DF (match_operand:SI 1 "register_operand" "f")))] "TARGET_FPU" - "fitod %1,%0" - [(set_attr "type" "fp")]) + "fitod\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "floatsitf2" [(set (match_operand:TF 0 "register_operand" "=e") (float:TF (match_operand:SI 1 "register_operand" "f")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fitoq %1,%0" - [(set_attr "type" "fp")]) + "fitoq\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) ;; Now the same for 64 bit sources. @@ -3590,22 +4229,25 @@ return \"srl %1,0,%0\"; [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:DI 1 "register_operand" "e")))] "TARGET_V9 && TARGET_FPU" - "fxtos %1,%0" - [(set_attr "type" "fp")]) + "fxtos\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "floatdidf2" [(set (match_operand:DF 0 "register_operand" "=e") (float:DF (match_operand:DI 1 "register_operand" "e")))] "TARGET_V9 && TARGET_FPU" - "fxtod %1,%0" - [(set_attr "type" "fp")]) + "fxtod\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "floatditf2" [(set (match_operand:TF 0 "register_operand" "=e") (float:TF (match_operand:DI 1 "register_operand" "e")))] "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD" - "fxtoq %1,%0" - [(set_attr "type" "fp")]) + "fxtoq\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) ;; Convert a float to an actual integer. ;; Truncation is performed as part of the conversion. @@ -3614,22 +4256,25 @@ return \"srl %1,0,%0\"; [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] "TARGET_FPU" - "fstoi %1,%0" - [(set_attr "type" "fp")]) + "fstoi\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "fix_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "e"))))] "TARGET_FPU" - "fdtoi %1,%0" - [(set_attr "type" "fp")]) + "fdtoi\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "fix_trunctfsi2" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))] "TARGET_FPU && TARGET_HARD_QUAD" - "fqtoi %1,%0" - [(set_attr "type" "fp")]) + "fqtoi\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) ;; Now the same, for V9 targets @@ -3637,22 +4282,25 @@ return \"srl %1,0,%0\"; [(set (match_operand:DI 0 "register_operand" "=e") (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] "TARGET_V9 && TARGET_FPU" - "fstox %1,%0" - [(set_attr "type" "fp")]) + "fstox\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "fix_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "=e") (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "e"))))] "TARGET_V9 && TARGET_FPU" - "fdtox %1,%0" - [(set_attr "type" "fp")]) + "fdtox\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "fix_trunctfdi2" [(set (match_operand:DI 0 "register_operand" "=e") (fix:DI (fix:TF (match_operand:TF 1 "register_operand" "e"))))] "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD" - "fqtox %1,%0" - [(set_attr "type" "fp")]) + "fqtox\\t%1, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) ;;- arithmetic instructions @@ -3675,39 +4323,15 @@ return \"srl %1,0,%0\"; } }") -(define_insn "*adddi3_sp32" +(define_insn "adddi3_insn_sp32" [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (match_operand:DI 1 "arith_double_operand" "%r") (match_operand:DI 2 "arith_double_operand" "rHI"))) (clobber (reg:CC 100))] "! TARGET_ARCH64" - "* -{ - rtx op2 = operands[2]; - - if (GET_CODE (op2) == CONST_INT - || GET_CODE (op2) == CONST_DOUBLE) - { - rtx xoperands[4]; - xoperands[0] = operands[0]; - xoperands[1] = operands[1]; - if (WORDS_BIG_ENDIAN) - split_double (op2, &xoperands[2], &xoperands[3]); - else - split_double (op2, &xoperands[3], &xoperands[2]); - if (xoperands[3] == const0_rtx && xoperands[0] == xoperands[1]) - output_asm_insn (\"add %H1,%2,%H0\", xoperands); - else - output_asm_insn (\"addcc %L1,%3,%L0\;addx %H1,%2,%H0\", xoperands); - return \"\"; - } - return \"addcc %L1,%L2,%L0\;addx %H1,%H2,%H0\"; -}" + "#" [(set_attr "length" "2")]) - -;; Split DImode arithmetic - (define_split [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (match_operand:DI 1 "arith_double_operand" "%r") @@ -3777,23 +4401,56 @@ return \"srl %1,0,%0\"; }") ;; LTU here means "carry set" -(define_insn "*addx" +(define_insn "addx" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (plus:SI (match_operand:SI 1 "arith_operand" "%r") (match_operand:SI 2 "arith_operand" "rI")) (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] "" - "addx %1,%2,%0" - [(set_attr "type" "unary")]) + "addx\\t%1, %2, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) -(define_insn "*subx" +(define_insn "*addx_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ") + (match_operand:SI 2 "arith_operand" "rI")) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "" + "addx\\t%r1, %2, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) + +(define_insn "subx" [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r") + (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") (match_operand:SI 2 "arith_operand" "rI")) (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] "" - "subx %1,%2,%0" - [(set_attr "type" "unary")]) + "subx\\t%r1, %2, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) + +(define_insn "*subx_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") + (match_operand:SI 2 "arith_operand" "rI")) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "" + "subx\\t%r1, %2, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) + +;; This is only for splits at the moment. +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") + (match_operand:SI 2 "arith_operand" "rI")) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "TARGET_ARCH64" + "subx\\t%r1, %2, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -3801,15 +4458,31 @@ return \"srl %1,0,%0\"; (match_operand:DI 2 "register_operand" "r"))) (clobber (reg:CC 100))] "! TARGET_ARCH64" - "addcc %L2,%1,%L0\;addx %H2,0,%H0" - [(set_attr "type" "multi")]) + "#" + [(set_attr "type" "multi") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "")) + (match_operand:DI 2 "register_operand" ""))) + (clobber (reg:CC 100))] + "! TARGET_ARCH64" + [(set (reg:CC_NOOV 100) + (compare:CC_NOOV (plus:SI (match_dup 3) (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (plus:SI (match_dup 4) (const_int 0)) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "operands[3] = gen_lowpart (SImode, operands[2]); + operands[4] = gen_highpart (SImode, operands[2]);") (define_insn "*adddi3_sp64" [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (match_operand:DI 1 "arith_double_operand" "%r") (match_operand:DI 2 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "add %1,%2,%0") + "add\\t%1, %2, %0") (define_insn "addsi3" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -3817,18 +4490,20 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI,d")))] "" "@ - add %1,%2,%0 - fpadd32s %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + add\\t%1, %2, %0 + fpadd32s\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1")]) (define_insn "*cmp_cc_plus" [(set (reg:CC_NOOV 100) (compare:CC_NOOV (plus:SI (match_operand:SI 0 "arith_operand" "%r") (match_operand:SI 1 "arith_operand" "rI")) (const_int 0)))] - "" - "addcc %0,%1,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "addcc\\t%0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_plus" [(set (reg:CCX_NOOV 100) @@ -3836,8 +4511,9 @@ return \"srl %1,0,%0\"; (match_operand:DI 1 "arith_double_operand" "rHI")) (const_int 0)))] "TARGET_ARCH64" - "addcc %0,%1,%%g0" - [(set_attr "type" "compare")]) + "addcc\\t%0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_plus_set" [(set (reg:CC_NOOV 100) @@ -3847,7 +4523,9 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] "" - "addcc %1,%2,%0") + "addcc\\t%1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_plus_set" [(set (reg:CCX_NOOV 100) @@ -3857,7 +4535,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (plus:DI (match_dup 1) (match_dup 2)))] "TARGET_ARCH64" - "addcc %1,%2,%0") + "addcc\\t%1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_expand "subdi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -3884,45 +4564,98 @@ return \"srl %1,0,%0\"; (match_operand:DI 2 "arith_double_operand" "rHI"))) (clobber (reg:CC 100))] "! TARGET_ARCH64" - "* -{ - rtx op2 = operands[2]; - - if (GET_CODE (op2) == CONST_INT - || GET_CODE (op2) == CONST_DOUBLE) - { - rtx xoperands[4]; - xoperands[0] = operands[0]; - xoperands[1] = operands[1]; - if (WORDS_BIG_ENDIAN) - split_double (op2, &xoperands[2], &xoperands[3]); - else - split_double (op2, &xoperands[3], &xoperands[2]); - if (xoperands[3] == const0_rtx && xoperands[0] == xoperands[1]) - output_asm_insn (\"sub %H1,%2,%H0\", xoperands); - else - output_asm_insn (\"subcc %L1,%3,%L0\;subx %H1,%2,%H0\", xoperands); - return \"\"; - } - return \"subcc %L1,%L2,%L0\;subx %H1,%H2,%H0\"; -}" + "#" [(set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "arith_double_operand" ""))) + (clobber (reg:CC 100))] + "! TARGET_ARCH64 + && reload_completed + && (GET_CODE (operands[2]) == CONST_INT + || GET_CODE (operands[2]) == CONST_DOUBLE)" + [(clobber (const_int 0))] + " +{ + rtx highp, lowp; + + highp = gen_highpart (SImode, operands[2]); + lowp = gen_lowpart (SImode, operands[2]); + if ((lowp == const0_rtx) + && (operands[0] == operands[1])) + { + emit_insn (gen_rtx_SET (SImode, + gen_highpart (SImode, operands[0]), + gen_rtx_MINUS (SImode, + gen_highpart (SImode, operands[1]), + highp))); + } + else + { + emit_insn (gen_cmp_minus_cc_set (gen_lowpart (SImode, operands[0]), + gen_lowpart (SImode, operands[1]), + lowp)); + emit_insn (gen_subx (gen_highpart (SImode, operands[0]), + gen_highpart (SImode, operands[1]), + highp)); + } + DONE; +}") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (reg:CC 100))] + "! TARGET_ARCH64 + && reload_completed" + [(clobber (const_int 0))] + " +{ + emit_insn (gen_cmp_minus_cc_set (gen_lowpart (SImode, operands[0]), + gen_lowpart (SImode, operands[1]), + gen_lowpart (SImode, operands[2]))); + emit_insn (gen_subx (gen_highpart (SImode, operands[0]), + gen_highpart (SImode, operands[1]), + gen_highpart (SImode, operands[2]))); + DONE; +}") + (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (minus:DI (match_operand:DI 1 "register_operand" "r") (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))) (clobber (reg:CC 100))] "! TARGET_ARCH64" - "subcc %L1,%2,%L0\;addx %H1,0,%H0" - [(set_attr "type" "multi")]) + "#" + [(set_attr "type" "multi") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "register_operand" "") + (zero_extend:DI (match_operand:SI 2 "register_operand" "")))) + (clobber (reg:CC 100))] + "! TARGET_ARCH64" + [(set (reg:CC_NOOV 100) + (compare:CC_NOOV (minus:SI (match_dup 3) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (plus:SI (match_dup 4) (const_int 0)) + (ltu:SI (reg:CC_NOOV 100) (const_int 0))))] + "operands[3] = gen_lowpart (SImode, operands[1]); + operands[4] = gen_highpart (SImode, operands[1]);") (define_insn "*subdi3_sp64" [(set (match_operand:DI 0 "register_operand" "=r") (minus:DI (match_operand:DI 1 "register_operand" "r") (match_operand:DI 2 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "sub %1,%2,%0") + "sub\\t%1, %2, %0" + [(set_attr "type" "binary") + (set_attr "length" "1")]) (define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -3930,18 +4663,20 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI,d")))] "" "@ - sub %1,%2,%0 - fpsub32s %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + sub\\t%1, %2, %0 + fpsub32s\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1")]) (define_insn "*cmp_minus_cc" [(set (reg:CC_NOOV 100) - (compare:CC_NOOV (minus:SI (match_operand:SI 0 "register_operand" "r") + (compare:CC_NOOV (minus:SI (match_operand:SI 0 "reg_or_0_operand" "rJ") (match_operand:SI 1 "arith_operand" "rI")) (const_int 0)))] - "" - "subcc %0,%1,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "subcc\\t%r0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_minus_ccx" [(set (reg:CCX_NOOV 100) @@ -3949,18 +4684,21 @@ return \"srl %1,0,%0\"; (match_operand:DI 1 "arith_double_operand" "rHI")) (const_int 0)))] "TARGET_ARCH64" - "subcc %0,%1,%%g0" - [(set_attr "type" "compare")]) + "subcc\\t%0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) -(define_insn "*cmp_minus_cc_set" +(define_insn "cmp_minus_cc_set" [(set (reg:CC_NOOV 100) - (compare:CC_NOOV (minus:SI (match_operand:SI 1 "register_operand" "r") + (compare:CC_NOOV (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") (match_operand:SI 2 "arith_operand" "rI")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_dup 1) (match_dup 2)))] "" - "subcc %1,%2,%0") + "subcc\\t%r1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_minus_ccx_set" [(set (reg:CCX_NOOV 100) @@ -3970,7 +4708,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (minus:DI (match_dup 1) (match_dup 2)))] "TARGET_ARCH64" - "subcc %1,%2,%0") + "subcc\\t%1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) ;; Integer Multiply/Divide. @@ -3983,8 +4723,9 @@ return \"srl %1,0,%0\"; (mult:SI (match_operand:SI 1 "arith_operand" "%r") (match_operand:SI 2 "arith_operand" "rI")))] "TARGET_HARD_MUL" - "smul %1,%2,%0" - [(set_attr "type" "imul")]) + "smul\\t%1, %2, %0" + [(set_attr "type" "imul") + (set_attr "length" "1")]) (define_expand "muldi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -4005,9 +4746,12 @@ return \"srl %1,0,%0\"; (mult:DI (match_operand:DI 1 "arith_double_operand" "%r") (match_operand:DI 2 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "mulx %1,%2,%0") + "mulx\\t%1, %2, %0" + [(set_attr "type" "imul") + (set_attr "length" "1")]) ;; V8plus wide multiply. +;; XXX (define_insn "muldi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=r,h") (mult:DI (match_operand:DI 1 "arith_double_operand" "%r,0") @@ -4018,15 +4762,15 @@ return \"srl %1,0,%0\"; "* { if (sparc_check_64 (operands[1], insn) <= 0) - output_asm_insn (\"srl %L1,0,%L1\", operands); + output_asm_insn (\"srl\\t%L1, 0, %L1\", operands); if (which_alternative == 1) - output_asm_insn (\"sllx %H1,32,%H1\", operands); + output_asm_insn (\"sllx\\t%H1, 32, %H1\", operands); if (sparc_check_64 (operands[2], insn) <= 0) - output_asm_insn (\"srl %L2,0,%L2\", operands); + output_asm_insn (\"srl\\t%L2, 0, %L2\", operands); if (which_alternative == 1) - return \"or %L1,%H1,%H1\;sllx %H2,32,%L1\;or %L2,%L1,%L1\;mulx %H1,%L1,%L0\;srlx %L0,32,%H0\"; + return \"or\\t%L1, %H1, %H1\\n\\tsllx\\t%H2, 32, %L1\\n\\tor\\t%L2, %L1, %L1\\n\\tmulx\\t%H1, %L1, %L0\;srlx\\t%L0, 32, %H0\"; else - return \"sllx %H1,32,%3\;sllx %H2,32,%4\;or %L1,%3,%3\;or %L2,%4,%4\;mulx %3,%4,%3\;srlx %3,32,%H0\;mov %3,%L0\"; + return \"sllx\\t%H1, 32, %3\\n\\tsllx\\t%H2, 32, %4\\n\\tor\\t%L1, %3, %3\\n\\tor\\t%L2, %4, %4\\n\\tmulx\\t%3, %4, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0\"; }" [(set_attr "length" "9,8")]) @@ -4040,8 +4784,9 @@ return \"srl %1,0,%0\"; (compare:CC_NOOV (mult:SI (match_dup 1) (match_dup 2)) (const_int 0)))] "TARGET_V8 || TARGET_SPARCLITE || TARGET_DEPRECATED_V8_INSNS" - "smulcc %1,%2,%0" - [(set_attr "type" "imul")]) + "smulcc\\t%1, %2, %0" + [(set_attr "type" "imul") + (set_attr "length" "1")]) (define_expand "mulsidi3" [(set (match_operand:DI 0 "register_operand" "") @@ -4070,6 +4815,7 @@ return \"srl %1,0,%0\"; ;; V9 puts the 64 bit product in a 64 bit register. Only out or global ;; registers can hold 64 bit values in the V8plus environment. +;; XXX (define_insn "mulsidi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=h,r") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r")) @@ -4077,10 +4823,11 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 3 "=X,&h"))] "TARGET_V8PLUS" "@ - smul %1,%2,%L0\;srlx %L0,32,%H0 - smul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0" + smul\\t%1, %2, %L0\\n\\tsrlx\\t%L0, 32, %H0 + smul\\t%1, %2, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0" [(set_attr "length" "2,3")]) +;; XXX (define_insn "const_mulsidi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=h,r") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r")) @@ -4088,10 +4835,11 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 3 "=X,&h"))] "TARGET_V8PLUS" "@ - smul %1,%2,%L0\;srlx %L0,32,%H0 - smul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0" + smul\\t%1, %2, %L0\\n\\tsrlx\\t%L0, 32, %H0 + smul\\t%1, %2, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0" [(set_attr "length" "2,3")]) +;; XXX (define_insn "*mulsidi3_sp32" [(set (match_operand:DI 0 "register_operand" "=r") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) @@ -4099,7 +4847,7 @@ return \"srl %1,0,%0\"; "TARGET_HARD_MUL32" "* { - return TARGET_SPARCLET ? \"smuld %1,%2,%L0\" : \"smul %1,%2,%L0\;rd %%y,%H0\"; + return TARGET_SPARCLET ? \"smuld\\t%1, %2, %L0\" : \"smul\\t%1, %2, %L0\\n\\trd\\t%%y, %H0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "sparclet") @@ -4107,6 +4855,7 @@ return \"srl %1,0,%0\"; ;; Extra pattern, because sign_extend of a constant isn't valid. +;; XXX (define_insn "const_mulsidi3" [(set (match_operand:DI 0 "register_operand" "=r") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) @@ -4114,7 +4863,7 @@ return \"srl %1,0,%0\"; "TARGET_HARD_MUL" "* { - return TARGET_SPARCLET ? \"smuld %1,%2,%L0\" : \"smul %1,%2,%L0\;rd %%y,%H0\"; + return TARGET_SPARCLET ? \"smuld\\t%1, %2, %L0\" : \"smul\\t%1, %2, %L0\\n\\trd\\t%%y, %H0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "sparclet") @@ -4150,6 +4899,7 @@ return \"srl %1,0,%0\"; } }") +;; XXX (define_insn "smulsi3_highpart_v8plus" [(set (match_operand:SI 0 "register_operand" "=h,r") (truncate:SI @@ -4164,6 +4914,7 @@ return \"srl %1,0,%0\"; [(set_attr "length" "2")]) ;; The combiner changes TRUNCATE in the previous pattern to SUBREG. +;; XXX (define_insn "" [(set (match_operand:SI 0 "register_operand" "=h,r") (subreg:SI @@ -4175,10 +4926,11 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 4 "=X,&h"))] "TARGET_V8PLUS" "@ - smul %1,%2,%0\;srlx %0,%3,%0 - smul %1,%2,%4\;srlx %4,%3,%0" + smul\\t%1, %2, %0\\n\\tsrlx\\t%0, %3, %0 + smul\\t%1, %2, %4\\n\\tsrlx\\t%4, %3, %0" [(set_attr "length" "2")]) +;; XXX (define_insn "const_smulsi3_highpart_v8plus" [(set (match_operand:SI 0 "register_operand" "=h,r") (truncate:SI @@ -4188,28 +4940,32 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 4 "=X,&h"))] "TARGET_V8PLUS" "@ - smul %1,%2,%0\;srlx %0,%3,%0 - smul %1,%2,%4\;srlx %4,%3,%0" + smul\\t%1, %2, %0\\n\\tsrlx\\t%0, %3, %0 + smul\\t%1, %2, %4\\n\\tsrlx\\t%4, %3, %0" [(set_attr "length" "2")]) +;; XXX (define_insn "*smulsi3_highpart_sp32" [(set (match_operand:SI 0 "register_operand" "=r") (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) (const_int 32))))] - "TARGET_HARD_MUL32" - "smul %1,%2,%%g0\;rd %%y,%0" + "TARGET_HARD_MUL32 + && ! TARGET_LIVE_G0" + "smul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0" [(set_attr "length" "2")]) +;; XXX (define_insn "const_smulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=r") (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) (match_operand:SI 2 "register_operand" "r")) (const_int 32))))] - "TARGET_HARD_MUL32" - "smul %1,%2,%%g0\;rd %%y,%0" + "TARGET_HARD_MUL32 + && ! TARGET_LIVE_G0" + "smul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0" [(set_attr "length" "2")]) (define_expand "umulsidi3" @@ -4237,6 +4993,7 @@ return \"srl %1,0,%0\"; } }") +;; XXX (define_insn "umulsidi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=h,r") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r")) @@ -4244,10 +5001,11 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 3 "=X,&h"))] "TARGET_V8PLUS" "@ - umul %1,%2,%L0\;srlx %L0,32,%H0 - umul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0" + umul\\t%1, %2, %L0\\n\\tsrlx\\t%L0, 32, %H0 + umul\\t%1, %2, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0" [(set_attr "length" "2,3")]) +;; XXX (define_insn "*umulsidi3_sp32" [(set (match_operand:DI 0 "register_operand" "=r") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) @@ -4255,7 +5013,7 @@ return \"srl %1,0,%0\"; "TARGET_HARD_MUL32" "* { - return TARGET_SPARCLET ? \"umuld %1,%2,%L0\" : \"umul %1,%2,%L0\;rd %%y,%H0\"; + return TARGET_SPARCLET ? \"umuld\\t%1, %2, %L0\" : \"umul\\t%1, %2, %L0\\n\\trd\\t%%y, %H0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "sparclet") @@ -4263,6 +5021,7 @@ return \"srl %1,0,%0\"; ;; Extra pattern, because sign_extend of a constant isn't valid. +;; XXX (define_insn "const_umulsidi3" [(set (match_operand:DI 0 "register_operand" "=r") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) @@ -4270,12 +5029,13 @@ return \"srl %1,0,%0\"; "TARGET_HARD_MUL32" "* { - return TARGET_SPARCLET ? \"umuld %1,%2,%L0\" : \"umul %1,%2,%L0\;rd %%y,%H0\"; + return TARGET_SPARCLET ? \"umuld\\t%1, %2, %L0\" : \"umul\\t%1, %2, %L0\\n\\trd\\t%%y, %H0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "sparclet") (const_int 1) (const_int 2)))]) +;; XXX (define_insn "const_umulsidi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=h,r") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r")) @@ -4283,8 +5043,8 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 3 "=X,h"))] "TARGET_V8PLUS" "@ - umul %1,%2,%L0\;srlx %L0,32,%H0 - umul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0" + umul\\t%1, %2, %L0\\n\\tsrlx\\t%L0, 32, %H0 + umul\\t%1, %2, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0" [(set_attr "length" "2,3")]) (define_expand "umulsi3_highpart" @@ -4317,6 +5077,7 @@ return \"srl %1,0,%0\"; } }") +;; XXX (define_insn "umulsi3_highpart_v8plus" [(set (match_operand:SI 0 "register_operand" "=h,r") (truncate:SI @@ -4326,10 +5087,11 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 4 "=X,h"))] "TARGET_V8PLUS" "@ - umul %1,%2,%0\;srlx %0,%3,%0 - umul %1,%2,%4\;srlx %4,%3,%0" + umul\\t%1, %2, %0\\n\\tsrlx\\t%0, %3, %0 + umul\\t%1, %2, %4\\n\\tsrlx\\t%4, %3, %0" [(set_attr "length" "2")]) +;; XXX (define_insn "const_umulsi3_highpart_v8plus" [(set (match_operand:SI 0 "register_operand" "=h,r") (truncate:SI @@ -4339,51 +5101,58 @@ return \"srl %1,0,%0\"; (clobber (match_scratch:SI 4 "=X,h"))] "TARGET_V8PLUS" "@ - umul %1,%2,%0\;srlx %0,%3,%0 - umul %1,%2,%4\;srlx %4,%3,%0" + umul\\t%1, %2, %0\\n\\tsrlx\\t%0, %3, %0 + umul\\t%1, %2, %4\\n\\tsrlx\\t%4, %3, %0" [(set_attr "length" "2")]) +;; XXX (define_insn "*umulsi3_highpart_sp32" [(set (match_operand:SI 0 "register_operand" "=r") (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) (const_int 32))))] - "TARGET_HARD_MUL32" - "umul %1,%2,%%g0\;rd %%y,%0" + "TARGET_HARD_MUL32 + && ! TARGET_LIVE_G0" + "umul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0" [(set_attr "length" "2")]) +;; XXX (define_insn "const_umulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=r") (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) (match_operand:SI 2 "uns_small_int" "")) (const_int 32))))] - "TARGET_HARD_MUL32" - "umul %1,%2,%%g0\;rd %%y,%0" + "TARGET_HARD_MUL32 + && ! TARGET_LIVE_G0" + "umul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0" [(set_attr "length" "2")]) ;; The v8 architecture specifies that there must be 3 instructions between ;; a y register write and a use of it for correct results. +;; XXX SHEESH (define_insn "divsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (div:SI (match_operand:SI 1 "register_operand" "r,r") - (match_operand:SI 2 "move_operand" "rI,m"))) + (match_operand:SI 2 "input_operand" "rI,m"))) (clobber (match_scratch:SI 3 "=&r,&r"))] - "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS" + "(TARGET_V8 + || TARGET_DEPRECATED_V8_INSNS) + && ! TARGET_LIVE_G0" "* { if (which_alternative == 0) if (TARGET_V9) - return \"sra %1,31,%3\;wr %%g0,%3,%%y\;sdiv %1,%2,%0\"; + return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tsdiv\\t%1, %2, %0\"; else - return \"sra %1,31,%3\;wr %%g0,%3,%%y\;nop\;nop\;nop\;sdiv %1,%2,%0\"; + return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tsdiv\\t%1, %2, %0\"; else if (TARGET_V9) - return \"sra %1,31,%3\;wr %%g0,%3,%%y\;ld %2,%3\;sdiv %1,%3,%0\"; + return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tld\\t%2, %3\\n\\tsdiv\\t%1, %3, %0\"; else - return \"sra %1,31,%3\;wr %%g0,%3,%%y\;ld %2,%3\;nop\;nop\;sdiv %1,%3,%0\"; + return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tld\\t%2, %3\\n\\tnop\\n\\tnop\\n\\tsdiv\\t%1, %3, %0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "v9") @@ -4394,10 +5163,11 @@ return \"srl %1,0,%0\"; (div:DI (match_operand:DI 1 "register_operand" "r") (match_operand:DI 2 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "sdivx %1,%2,%0") + "sdivx\\t%1, %2, %0") ;; It is not known whether this will match. +;; XXX I hope it doesn't fucking match... (define_insn "*cmp_sdiv_cc_set" [(set (match_operand:SI 0 "register_operand" "=r") (div:SI (match_operand:SI 1 "register_operand" "r") @@ -4406,36 +5176,41 @@ return \"srl %1,0,%0\"; (compare:CC (div:SI (match_dup 1) (match_dup 2)) (const_int 0))) (clobber (match_scratch:SI 3 "=&r"))] - "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS" + "(TARGET_V8 + || TARGET_DEPRECATED_V8_INSNS) + && ! TARGET_LIVE_G0" "* { if (TARGET_V9) - return \"sra %1,31,%3\;wr %%g0,%3,%%y\;sdivcc %1,%2,%0\"; + return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tsdivcc\\t%1, %2, %0\"; else - return \"sra %1,31,%3\;wr %%g0,%3,%%y\;nop\;nop\;nop\;sdivcc %1,%2,%0\"; + return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tsdivcc\\t%1, %2, %0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "v9") (const_int 3) (const_int 6)))]) +;; XXX (define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=r,&r,&r") (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "r,r,m") - (match_operand:SI 2 "move_operand" "rI,m,r")))] - "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS" + (match_operand:SI 2 "input_operand" "rI,m,r")))] + "(TARGET_V8 + || TARGET_DEPRECATED_V8_INSNS) + && ! TARGET_LIVE_G0" "* { - output_asm_insn (\"wr %%g0,%%g0,%%y\", operands); + output_asm_insn (\"wr\\t%%g0, %%g0, %%y\", operands); switch (which_alternative) { default: if (TARGET_V9) - return \"udiv %1,%2,%0\"; - return \"nop\;nop\;nop\;udiv %1,%2,%0\"; + return \"udiv\\t%1, %2, %0\"; + return \"nop\\n\\tnop\\n\\tnop\\n\\tudiv\\t%1, %2, %0\"; case 1: - return \"ld %2,%0\;nop\;nop\;udiv %1,%0,%0\"; + return \"ld\\t%2, %0\\n\\tnop\\n\\tnop\\n\\tudiv\\t%1, %0, %0\"; case 2: - return \"ld %1,%0\;nop\;nop\;udiv %0,%2,%0\"; + return \"ld\\t%1, %0\\n\\tnop\\n\\tnop\\n\\tudiv\\t%0, %2, %0\"; } }" [(set (attr "length") @@ -4448,10 +5223,11 @@ return \"srl %1,0,%0\"; (udiv:DI (match_operand:DI 1 "register_operand" "r") (match_operand:DI 2 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "udivx %1,%2,%0") + "udivx\\t%1, %2, %0") ;; It is not known whether this will match. +;; XXX I hope it doesn't fucking match... (define_insn "*cmp_udiv_cc_set" [(set (match_operand:SI 0 "register_operand" "=r") (udiv:SI (match_operand:SI 1 "register_operand" "r") @@ -4459,13 +5235,15 @@ return \"srl %1,0,%0\"; (set (reg:CC 100) (compare:CC (udiv:SI (match_dup 1) (match_dup 2)) (const_int 0)))] - "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS" + "(TARGET_V8 + || TARGET_DEPRECATED_V8_INSNS) + && ! TARGET_LIVE_G0" "* { if (TARGET_V9) - return \"wr %%g0,%%g0,%%y\;udivcc %1,%2,%0\"; + return \"wr\\t%%g0, %%g0, %%y\\n\\tudivcc\\t%1, %2, %0\"; else - return \"wr %%g0,%%g0,%%y\;nop\;nop\;nop\;udivcc %1,%2,%0\"; + return \"wr\\t%%g0, %%g0, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tudivcc\\t%1, %2, %0\"; }" [(set (attr "length") (if_then_else (eq_attr "isa" "v9") @@ -4479,8 +5257,9 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI")) (match_operand:SI 3 "register_operand" "0")))] "TARGET_SPARCLET" - "smac %1,%2,%0" - [(set_attr "type" "imul")]) + "smac\\t%1, %2, %0" + [(set_attr "type" "imul") + (set_attr "length" "1")]) (define_insn "*smacdi" [(set (match_operand:DI 0 "register_operand" "=r") @@ -4490,8 +5269,9 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "register_operand" "r"))) (match_operand:DI 3 "register_operand" "0")))] "TARGET_SPARCLET" - "smacd %1,%2,%L0" - [(set_attr "type" "imul")]) + "smacd\\t%1, %2, %L0" + [(set_attr "type" "imul") + (set_attr "length" "1")]) (define_insn "*umacdi" [(set (match_operand:DI 0 "register_operand" "=r") @@ -4501,8 +5281,9 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "register_operand" "r"))) (match_operand:DI 3 "register_operand" "0")))] "TARGET_SPARCLET" - "umacd %1,%2,%L0" - [(set_attr "type" "imul")]) + "umacd\\t%1, %2, %L0" + [(set_attr "type" "imul") + (set_attr "length" "1")]) ;;- Boolean instructions ;; We define DImode `and' so with DImode `not' we can get @@ -4520,36 +5301,22 @@ return \"srl %1,0,%0\"; (and:DI (match_operand:DI 1 "arith_double_operand" "%r,b") (match_operand:DI 2 "arith_double_operand" "rHI,b")))] "! TARGET_ARCH64" - "* -{ - rtx op2 = operands[2]; - - if (which_alternative == 1) - return \"fand %1,%2,%0\"; - - if (GET_CODE (op2) == CONST_INT - || GET_CODE (op2) == CONST_DOUBLE) - { - rtx xoperands[4]; - xoperands[0] = operands[0]; - xoperands[1] = operands[1]; - if (WORDS_BIG_ENDIAN) - split_double (op2, &xoperands[2], &xoperands[3]); - else - split_double (op2, &xoperands[3], &xoperands[2]); - output_asm_insn (\"and %L1,%3,%L0\;and %H1,%2,%H0\", xoperands); - return \"\"; - } - return \"and %1,%2,%0\;and %R1,%R2,%R0\"; -}" - [(set_attr "length" "2,1")]) + "@ + # + fand\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "2,1")]) (define_insn "*anddi3_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (and:DI (match_operand:DI 1 "arith_double_operand" "%r") - (match_operand:DI 2 "arith_double_operand" "rHI")))] + [(set (match_operand:DI 0 "register_operand" "=r,b") + (and:DI (match_operand:DI 1 "arith_double_operand" "%r,b") + (match_operand:DI 2 "arith_double_operand" "rHI,b")))] "TARGET_ARCH64" - "and %1,%2,%0") + "@ + and\\t%1, %2, %0 + fand\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_insn "andsi3" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -4557,9 +5324,10 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI,d")))] "" "@ - and %1,%2,%0 - fands %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + and\\t%1, %2, %0 + fands\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_split [(set (match_operand:SI 0 "register_operand" "") @@ -4582,8 +5350,10 @@ return \"srl %1,0,%0\"; (match_operator:DI 1 "cc_arithop" ; AND, IOR, XOR [(match_operand:DI 2 "register_operand" "") (match_operand:DI 3 "arith_double_operand" "")]))] - "! TARGET_ARCH64 && reload_completed - && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < 32" + "! TARGET_ARCH64 + && reload_completed + && GET_CODE (operands[0]) == REG + && REGNO (operands[0]) < 32" [(set (match_dup 4) (match_op_dup:SI 1 [(match_dup 6) (match_dup 8)])) (set (match_dup 5) (match_op_dup:SI 1 [(match_dup 7) (match_dup 9)]))] " @@ -4610,16 +5380,38 @@ return \"srl %1,0,%0\"; (match_operand:DI 2 "register_operand" "r,b")))] "! TARGET_ARCH64" "@ - andn %2,%1,%0\;andn %R2,%R1,%R0 - fandnot1 %1,%2,%0" - [(set_attr "length" "2,1")]) + # + fandnot1\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "2,1")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (not:DI (match_operand:DI 1 "register_operand" "")) + (match_operand:DI 2 "register_operand" "")))] + "! TARGET_ARCH64 + && reload_completed + && GET_CODE (operands[0]) == REG + && REGNO (operands[0]) < 32" + [(set (match_dup 3) (and:SI (not:SI (match_dup 4)) (match_dup 5))) + (set (match_dup 6) (and:SI (not:SI (match_dup 7)) (match_dup 8)))] + "operands[3] = gen_highpart (SImode, operands[0]); + operands[4] = gen_highpart (SImode, operands[1]); + operands[5] = gen_highpart (SImode, operands[2]); + operands[6] = gen_lowpart (SImode, operands[0]); + operands[7] = gen_lowpart (SImode, operands[1]); + operands[8] = gen_lowpart (SImode, operands[2]);") (define_insn "*and_not_di_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (and:DI (not:DI (match_operand:DI 1 "register_operand" "r")) - (match_operand:DI 2 "register_operand" "r")))] + [(set (match_operand:DI 0 "register_operand" "=r,b") + (and:DI (not:DI (match_operand:DI 1 "register_operand" "r,b")) + (match_operand:DI 2 "register_operand" "r,b")))] "TARGET_ARCH64" - "andn %2,%1,%0") + "@ + andn\\t%2, %1, %0 + fandnot1\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_insn "*and_not_si" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -4627,9 +5419,10 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "register_operand" "r,d")))] "" "@ - andn %2,%1,%0 - fandnot1s %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + andn\\t%2, %1, %0 + fandnot1s\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_expand "iordi3" [(set (match_operand:DI 0 "register_operand" "") @@ -4643,36 +5436,22 @@ return \"srl %1,0,%0\"; (ior:DI (match_operand:DI 1 "arith_double_operand" "%r,b") (match_operand:DI 2 "arith_double_operand" "rHI,b")))] "! TARGET_ARCH64" - "* -{ - rtx op2 = operands[2]; - - if (which_alternative == 1) - return \"for %1,%2,%0\"; - - if (GET_CODE (op2) == CONST_INT - || GET_CODE (op2) == CONST_DOUBLE) - { - rtx xoperands[4]; - xoperands[0] = operands[0]; - xoperands[1] = operands[1]; - if (WORDS_BIG_ENDIAN) - split_double (op2, &xoperands[2], &xoperands[3]); - else - split_double (op2, &xoperands[3], &xoperands[2]); - output_asm_insn (\"or %L1,%3,%L0\;or %H1,%2,%H0\", xoperands); - return \"\"; - } - return \"or %1,%2,%0\;or %R1,%R2,%R0\"; -}" - [(set_attr "length" "2,1")]) + "@ + # + for\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "2,1")]) (define_insn "*iordi3_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (ior:DI (match_operand:DI 1 "arith_double_operand" "%r") - (match_operand:DI 2 "arith_double_operand" "rHI")))] + [(set (match_operand:DI 0 "register_operand" "=r,b") + (ior:DI (match_operand:DI 1 "arith_double_operand" "%r,b") + (match_operand:DI 2 "arith_double_operand" "rHI,b")))] "TARGET_ARCH64" - "or %1,%2,%0") + "@ + or\\t%1, %2, %0 + for\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -4680,9 +5459,10 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI,d")))] "" "@ - or %1,%2,%0 - fors %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + or\\t%1, %2, %0 + fors\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_split [(set (match_operand:SI 0 "register_operand" "") @@ -4705,16 +5485,38 @@ return \"srl %1,0,%0\"; (match_operand:DI 2 "register_operand" "r,b")))] "! TARGET_ARCH64" "@ - orn %2,%1,%0\;orn %R2,%R1,%R0 - fornot1 %1,%2,%0" - [(set_attr "length" "2,1")]) + # + fornot1\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "2,1")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ior:DI (not:DI (match_operand:DI 1 "register_operand" "")) + (match_operand:DI 2 "register_operand" "")))] + "! TARGET_ARCH64 + && reload_completed + && GET_CODE (operands[0]) == REG + && REGNO (operands[0]) < 32" + [(set (match_dup 3) (ior:SI (not:SI (match_dup 4)) (match_dup 5))) + (set (match_dup 6) (ior:SI (not:SI (match_dup 7)) (match_dup 8)))] + "operands[3] = gen_highpart (SImode, operands[0]); + operands[4] = gen_highpart (SImode, operands[1]); + operands[5] = gen_highpart (SImode, operands[2]); + operands[6] = gen_lowpart (SImode, operands[0]); + operands[7] = gen_lowpart (SImode, operands[1]); + operands[8] = gen_lowpart (SImode, operands[2]);") (define_insn "*or_not_di_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r")) - (match_operand:DI 2 "register_operand" "r")))] + [(set (match_operand:DI 0 "register_operand" "=r,b") + (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r,b")) + (match_operand:DI 2 "register_operand" "r,b")))] "TARGET_ARCH64" - "orn %2,%1,%0") + "@ + orn\\t%2, %1, %0 + fornot1\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_insn "*or_not_si" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -4722,9 +5524,10 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "register_operand" "r,d")))] "" "@ - orn %2,%1,%0 - fornot1s %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + orn\\t%2, %1, %0 + fornot1s\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_expand "xordi3" [(set (match_operand:DI 0 "register_operand" "") @@ -4738,37 +5541,36 @@ return \"srl %1,0,%0\"; (xor:DI (match_operand:DI 1 "arith_double_operand" "%r,b") (match_operand:DI 2 "arith_double_operand" "rHI,b")))] "! TARGET_ARCH64" - "* -{ - rtx op2 = operands[2]; - - if (which_alternative == 1) - return \"fxor %1,%2,%0\"; - - if (GET_CODE (op2) == CONST_INT - || GET_CODE (op2) == CONST_DOUBLE) - { - rtx xoperands[4]; - xoperands[0] = operands[0]; - xoperands[1] = operands[1]; - if (WORDS_BIG_ENDIAN) - split_double (op2, &xoperands[2], &xoperands[3]); - else - split_double (op2, &xoperands[3], &xoperands[2]); - output_asm_insn (\"xor %L1,%3,%L0\;xor %H1,%2,%H0\", xoperands); - return \"\"; - } - return \"xor %1,%2,%0\;xor %R1,%R2,%R0\"; -}" + "@ + # + fxor\\t%1, %2, %0" [(set_attr "length" "2,1") (set_attr "type" "ialu,fp")]) (define_insn "*xordi3_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (xor:DI (match_operand:DI 1 "arith_double_operand" "%rJ") - (match_operand:DI 2 "arith_double_operand" "rHI")))] + [(set (match_operand:DI 0 "register_operand" "=r,b") + (xor:DI (match_operand:DI 1 "arith_double_operand" "%rJ,b") + (match_operand:DI 2 "arith_double_operand" "rHI,b")))] "TARGET_ARCH64" - "xor %r1,%2,%0") + "@ + xor\\t%r1, %2, %0 + fxor\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) + +(define_insn "*xordi3_sp64_dbl" + [(set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (match_operand:DI 1 "register_operand" "%r") + (match_operand:DI 2 "const_double_operand" "")))] + "TARGET_ARCH64 + && CONST_DOUBLE_HIGH (operands[2]) == 0" + "* +{ + operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + return \"xor\\t%1, %2, %0\"; +}" + [(set_attr "type" "ialu") + (set_attr "length" "1")]) (define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -4776,9 +5578,10 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI,d")))] "" "@ - xor %r1,%2,%0 - fxors %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + xor\\t%r1, %2, %0 + fxors\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_split [(set (match_operand:SI 0 "register_operand" "") @@ -4818,18 +5621,38 @@ return \"srl %1,0,%0\"; (match_operand:DI 2 "register_operand" "r,b"))))] "! TARGET_ARCH64" "@ - xnor %1,%2,%0\;xnor %R1,%R2,%R0 - fxnor %1,%2,%0" + # + fxnor\\t%1, %2, %0" [(set_attr "length" "2,1") (set_attr "type" "ialu,fp")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (not:DI (xor:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))))] + "! TARGET_ARCH64 + && reload_completed + && GET_CODE (operands[0]) == REG + && REGNO (operands[0]) < 32" + [(set (match_dup 3) (not:SI (xor:SI (match_dup 4) (match_dup 5)))) + (set (match_dup 6) (not:SI (xor:SI (match_dup 7) (match_dup 8))))] + "operands[3] = gen_highpart (SImode, operands[0]); + operands[4] = gen_highpart (SImode, operands[1]); + operands[5] = gen_highpart (SImode, operands[2]); + operands[6] = gen_lowpart (SImode, operands[0]); + operands[7] = gen_lowpart (SImode, operands[1]); + operands[8] = gen_lowpart (SImode, operands[2]);") + (define_insn "*xor_not_di_sp64" - [(set (match_operand:DI 0 "register_operand" "=r") - (not:DI (xor:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") - (match_operand:DI 2 "arith_double_operand" "rHI"))))] + [(set (match_operand:DI 0 "register_operand" "=r,b") + (not:DI (xor:DI (match_operand:DI 1 "reg_or_0_operand" "rJ,b") + (match_operand:DI 2 "arith_double_operand" "rHI,b"))))] "TARGET_ARCH64" - "xnor %r1,%2,%0" - [(set_attr "type" "ialu")]) + "@ + xnor\\t%r1, %2, %0 + fxnor\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) (define_insn "*xor_not_si" [(set (match_operand:SI 0 "register_operand" "=r,d") @@ -4837,9 +5660,10 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI,d"))))] "" "@ - xnor %r1,%2,%0 - fxnors %1,%2,%0" - [(set_attr "type" "ialu,fp")]) + xnor\\t%r1, %2, %0 + fxnors\\t%1, %2, %0" + [(set_attr "type" "ialu,fp") + (set_attr "length" "1,1")]) ;; These correspond to the above in the case where we also (or only) ;; want to set the condition code. @@ -4851,9 +5675,10 @@ return \"srl %1,0,%0\"; [(match_operand:SI 0 "arith_operand" "%r") (match_operand:SI 1 "arith_operand" "rI")]) (const_int 0)))] - "" - "%A2cc %0,%1,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "%A2cc\\t%0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_arith_op" [(set (reg:CCX 100) @@ -4863,8 +5688,9 @@ return \"srl %1,0,%0\"; (match_operand:DI 1 "arith_double_operand" "rHI")]) (const_int 0)))] "TARGET_ARCH64" - "%A2cc %0,%1,%%g0" - [(set_attr "type" "compare")]) + "%A2cc\\t%0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_arith_op_set" [(set (reg:CC 100) @@ -4876,7 +5702,9 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (match_dup 3))] "" - "%A3cc %1,%2,%0") + "%A3cc\\t%1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_arith_op_set" [(set (reg:CCX 100) @@ -4888,7 +5716,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (match_dup 3))] "TARGET_ARCH64" - "%A3cc %1,%2,%0") + "%A3cc\\t%1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_xor_not" [(set (reg:CC 100) @@ -4896,9 +5726,10 @@ return \"srl %1,0,%0\"; (not:SI (xor:SI (match_operand:SI 0 "reg_or_0_operand" "%rJ") (match_operand:SI 1 "arith_operand" "rI"))) (const_int 0)))] - "" - "xnorcc %r0,%1,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "xnorcc\\t%r0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_xor_not" [(set (reg:CCX 100) @@ -4907,8 +5738,9 @@ return \"srl %1,0,%0\"; (match_operand:DI 1 "arith_double_operand" "rHI"))) (const_int 0)))] "TARGET_ARCH64" - "xnorcc %r0,%1,%%g0" - [(set_attr "type" "compare")]) + "xnorcc\\t%r0, %1, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_xor_not_set" [(set (reg:CC 100) @@ -4919,7 +5751,9 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (not:SI (xor:SI (match_dup 1) (match_dup 2))))] "" - "xnorcc %r1,%2,%0") + "xnorcc\\t%r1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_xor_not_set" [(set (reg:CCX 100) @@ -4930,7 +5764,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (not:DI (xor:DI (match_dup 1) (match_dup 2))))] "TARGET_ARCH64" - "xnorcc %r1,%2,%0") + "xnorcc\\t%r1, %2, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_arith_op_not" [(set (reg:CC 100) @@ -4939,9 +5775,10 @@ return \"srl %1,0,%0\"; [(not:SI (match_operand:SI 0 "arith_operand" "rI")) (match_operand:SI 1 "reg_or_0_operand" "rJ")]) (const_int 0)))] - "" - "%B2cc %r1,%0,%%g0" - [(set_attr "type" "compare")]) + "! TARGET_LIVE_G0" + "%B2cc\\t%r1, %0, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_arith_op_not" [(set (reg:CCX 100) @@ -4951,8 +5788,9 @@ return \"srl %1,0,%0\"; (match_operand:DI 1 "reg_or_0_operand" "rJ")]) (const_int 0)))] "TARGET_ARCH64" - "%B2cc %r1,%0,%%g0" - [(set_attr "type" "compare")]) + "%B2cc\\t%r1, %0, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_arith_op_not_set" [(set (reg:CC 100) @@ -4964,7 +5802,9 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (match_dup 3))] "" - "%B3cc %r2,%1,%0") + "%B3cc\\t%r2, %1, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_arith_op_not_set" [(set (reg:CCX 100) @@ -4976,7 +5816,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (match_dup 3))] "TARGET_ARCH64" - "%B3cc %r2,%1,%0") + "%B3cc\\t%r2, %1, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) ;; We cannot use the "neg" pseudo insn because the Sun assembler ;; does not know how to make it work for constants. @@ -5002,54 +5844,81 @@ return \"srl %1,0,%0\"; [(set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_operand:DI 1 "register_operand" "r"))) (clobber (reg:CC 100))] - "! TARGET_ARCH64" - "* -{ - if (TARGET_LIVE_G0) - output_asm_insn (\"and %%g0,0,%%g0\", operands); - return \"subcc %%g0,%L1,%L0\;subx %%g0,%H1,%H0\"; -}" + "! TARGET_ARCH64 + && ! TARGET_LIVE_G0" + "#" [(set_attr "type" "unary") - ;; ??? This is wrong for TARGET_LIVE_G0 but it's not critical. (set_attr "length" "2")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (match_operand:DI 1 "register_operand" ""))) + (clobber (reg:CC 100))] + "! TARGET_ARCH64 + && ! TARGET_LIVE_G0 + && reload_completed" + [(parallel [(set (reg:CC_NOOV 100) + (compare:CC_NOOV (minus:SI (const_int 0) (match_dup 5)) + (const_int 0))) + (set (match_dup 4) (minus:SI (const_int 0) (match_dup 5)))]) + (set (match_dup 2) (minus:SI (minus:SI (const_int 0) (match_dup 3)) + (ltu:SI (reg:CC 100) (const_int 0))))] + "operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = gen_highpart (SImode, operands[1]); + operands[4] = gen_lowpart (SImode, operands[0]); + operands[5] = gen_lowpart (SImode, operands[1]);") + (define_insn "*negdi2_sp64" [(set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_operand:DI 1 "register_operand" "r")))] "TARGET_ARCH64" - "sub %%g0,%1,%0" + "sub\\t%%g0, %1, %0" [(set_attr "type" "unary") (set_attr "length" "1")]) -(define_insn "negsi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] +(define_expand "negsi2" + [(set (match_operand:SI 0 "register_operand" "") + (neg:SI (match_operand:SI 1 "arith_operand" "")))] "" - "* + " { if (TARGET_LIVE_G0) - return \"and %%g0,0,%%g0\;sub %%g0,%1,%0\"; - return \"sub %%g0,%1,%0\"; -}" + { + rtx zero_reg = gen_reg_rtx (SImode); + + emit_insn (gen_rtx_SET (SImode, zero_reg, const0_rtx)); + emit_insn (gen_rtx_SET (SImode, operands[0], + gen_rtx_MINUS (SImode, zero_reg, + operands[1]))); + DONE; + } +}") + +(define_insn "*negsi2_not_liveg0" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "! TARGET_LIVE_G0" + "sub\\t%%g0, %1, %0" [(set_attr "type" "unary") - (set (attr "length") - (if_then_else (eq_attr "live_g0" "yes") (const_int 2) (const_int 1)))]) + (set_attr "length" "1")]) (define_insn "*cmp_cc_neg" [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_operand:SI 0 "arith_operand" "rI")) (const_int 0)))] "! TARGET_LIVE_G0" - "subcc %%g0,%0,%%g0" - [(set_attr "type" "compare")]) + "subcc\\t%%g0, %0, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_neg" [(set (reg:CCX_NOOV 100) (compare:CCX_NOOV (neg:DI (match_operand:DI 0 "arith_double_operand" "rHI")) (const_int 0)))] "TARGET_ARCH64" - "subcc %%g0,%0,%%g0" - [(set_attr "type" "compare")]) + "subcc\\t%%g0, %0, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_set_neg" [(set (reg:CC_NOOV 100) @@ -5058,8 +5927,9 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] "! TARGET_LIVE_G0" - "subcc %%g0,%1,%0" - [(set_attr "type" "unary")]) + "subcc\\t%%g0, %1, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_set_neg" [(set (reg:CCX_NOOV 100) @@ -5068,8 +5938,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] "TARGET_ARCH64" - "subcc %%g0,%1,%0" - [(set_attr "type" "unary")]) + "subcc\\t%%g0, %1, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) ;; We cannot use the "not" pseudo insn because the Sun assembler ;; does not know how to make it work for constants. @@ -5084,53 +5955,93 @@ return \"srl %1,0,%0\"; (not:DI (match_operand:DI 1 "register_operand" "r,b")))] "! TARGET_ARCH64" "@ - xnor %1,0,%0\;xnor %R1,0,%R0 - fnot1 %1,%0" + # + fnot1\\t%1, %0" [(set_attr "type" "unary,fp") (set_attr "length" "2,1")]) +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (not:DI (match_operand:DI 1 "register_operand" "")))] + "! TARGET_ARCH64 + && reload_completed + && GET_CODE (operands[0]) == REG + && REGNO (operands[0]) < 32" + [(set (match_dup 2) (not:SI (xor:SI (match_dup 3) (const_int 0)))) + (set (match_dup 4) (not:SI (xor:SI (match_dup 5) (const_int 0))))] + "operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = gen_highpart (SImode, operands[1]); + operands[4] = gen_lowpart (SImode, operands[0]); + operands[5] = gen_lowpart (SImode, operands[1]);") + (define_insn "*one_cmpldi2_sp64" [(set (match_operand:DI 0 "register_operand" "=r") (not:DI (match_operand:DI 1 "arith_double_operand" "rHI")))] "TARGET_ARCH64" - "xnor %1,0,%0" - [(set_attr "type" "unary")]) + "xnor\\t%1, 0, %0" + [(set_attr "type" "unary") + (set_attr "length" "1")]) -(define_insn "one_cmplsi2" +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "") + (not:SI (match_operand:SI 1 "arith_operand" "")))] + "" + " +{ + if (TARGET_LIVE_G0 + && GET_CODE (operands[1]) == CONST_INT) + { + rtx zero_reg = gen_reg_rtx (SImode); + + emit_insn (gen_rtx_SET (SImode, zero_reg, const0_rtx)); + emit_insn (gen_rtx_SET (SImode, + operands[0], + gen_rtx_NOT (SImode, + gen_rtx_XOR (SImode, + zero_reg, + operands[1])))); + DONE; + } +}") + +(define_insn "*one_cmplsi2_not_liveg0" [(set (match_operand:SI 0 "register_operand" "=r,r,d") (not:SI (match_operand:SI 1 "arith_operand" "r,I,d")))] - "" - "* -{ - if (which_alternative == 0) - return \"xnor %1,0,%0\"; - if (which_alternative == 2) - return \"fnot1s %1,%0\"; - if (TARGET_LIVE_G0) - output_asm_insn (\"and %%g0,0,%%g0\", operands); - return \"xnor %%g0,%1,%0\"; -}" + "! TARGET_LIVE_G0" + "@ + xnor\\t%1, 0, %0 + xnor\\t%%g0, %1, %0 + fnot1s\\t%1, %0" [(set_attr "type" "unary,unary,fp") - (set_attr_alternative "length" - [(const_int 1) - (if_then_else (eq_attr "live_g0" "yes") (const_int 2) (const_int 1)) - (const_int 1)])]) + (set_attr "length" "1,1,1")]) + +(define_insn "*one_cmplsi2_liveg0" + [(set (match_operand:SI 0 "register_operand" "=r,d") + (not:SI (match_operand:SI 1 "arith_operand" "r,d")))] + "TARGET_LIVE_G0" + "@ + xnor\\t%1, 0, %0 + fnot1s\\t%1, %0" + [(set_attr "type" "unary,fp") + (set_attr "length" "1,1")]) (define_insn "*cmp_cc_not" [(set (reg:CC 100) (compare:CC (not:SI (match_operand:SI 0 "arith_operand" "rI")) (const_int 0)))] "! TARGET_LIVE_G0" - "xnorcc %%g0,%0,%%g0" - [(set_attr "type" "compare")]) + "xnorcc\\t%%g0, %0, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_not" [(set (reg:CCX 100) (compare:CCX (not:DI (match_operand:DI 0 "arith_double_operand" "rHI")) (const_int 0)))] "TARGET_ARCH64" - "xnorcc %%g0,%0,%%g0" - [(set_attr "type" "compare")]) + "xnorcc\\t%%g0, %0, %%g0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_cc_set_not" [(set (reg:CC 100) @@ -5139,8 +6050,9 @@ return \"srl %1,0,%0\"; (set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_dup 1)))] "! TARGET_LIVE_G0" - "xnorcc %%g0,%1,%0" - [(set_attr "type" "unary")]) + "xnorcc\\t%%g0, %1, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) (define_insn "*cmp_ccx_set_not" [(set (reg:CCX 100) @@ -5149,8 +6061,9 @@ return \"srl %1,0,%0\"; (set (match_operand:DI 0 "register_operand" "=r") (not:DI (match_dup 1)))] "TARGET_ARCH64" - "xnorcc %%g0,%1,%0" - [(set_attr "type" "unary")]) + "xnorcc\\t%%g0, %1, %0" + [(set_attr "type" "compare") + (set_attr "length" "1")]) ;; Floating point arithmetic instructions. @@ -5159,88 +6072,99 @@ return \"srl %1,0,%0\"; (plus:TF (match_operand:TF 1 "register_operand" "e") (match_operand:TF 2 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "faddq %1,%2,%0" - [(set_attr "type" "fp")]) + "faddq\\t%1, %2, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "adddf3" [(set (match_operand:DF 0 "register_operand" "=e") (plus:DF (match_operand:DF 1 "register_operand" "e") (match_operand:DF 2 "register_operand" "e")))] "TARGET_FPU" - "faddd %1,%2,%0" - [(set_attr "type" "fp")]) + "faddd\\t%1, %2, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "addsf3" [(set (match_operand:SF 0 "register_operand" "=f") (plus:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_FPU" - "fadds %1,%2,%0" - [(set_attr "type" "fp")]) + "fadds\\t%1, %2, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "subtf3" [(set (match_operand:TF 0 "register_operand" "=e") (minus:TF (match_operand:TF 1 "register_operand" "e") (match_operand:TF 2 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fsubq %1,%2,%0" - [(set_attr "type" "fp")]) + "fsubq\\t%1, %2, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "subdf3" [(set (match_operand:DF 0 "register_operand" "=e") (minus:DF (match_operand:DF 1 "register_operand" "e") (match_operand:DF 2 "register_operand" "e")))] "TARGET_FPU" - "fsubd %1,%2,%0" - [(set_attr "type" "fp")]) + "fsubd\\t%1, %2, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "subsf3" [(set (match_operand:SF 0 "register_operand" "=f") (minus:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_FPU" - "fsubs %1,%2,%0" - [(set_attr "type" "fp")]) + "fsubs\\t%1, %2, %0" + [(set_attr "type" "fp") + (set_attr "length" "1")]) (define_insn "multf3" [(set (match_operand:TF 0 "register_operand" "=e") (mult:TF (match_operand:TF 1 "register_operand" "e") (match_operand:TF 2 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fmulq %1,%2,%0" - [(set_attr "type" "fpmul")]) + "fmulq\\t%1, %2, %0" + [(set_attr "type" "fpmul") + (set_attr "length" "1")]) (define_insn "muldf3" [(set (match_operand:DF 0 "register_operand" "=e") (mult:DF (match_operand:DF 1 "register_operand" "e") (match_operand:DF 2 "register_operand" "e")))] "TARGET_FPU" - "fmuld %1,%2,%0" - [(set_attr "type" "fpmul")]) + "fmuld\\t%1, %2, %0" + [(set_attr "type" "fpmul") + (set_attr "length" "1")]) (define_insn "mulsf3" [(set (match_operand:SF 0 "register_operand" "=f") (mult:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_FPU" - "fmuls %1,%2,%0" - [(set_attr "type" "fpmul")]) + "fmuls\\t%1, %2, %0" + [(set_attr "type" "fpmul") + (set_attr "length" "1")]) (define_insn "*muldf3_extend" [(set (match_operand:DF 0 "register_operand" "=e") (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "f")) (float_extend:DF (match_operand:SF 2 "register_operand" "f"))))] "(TARGET_V8 || TARGET_V9) && TARGET_FPU" - "fsmuld %1,%2,%0" - [(set_attr "type" "fpmul")]) + "fsmuld\\t%1, %2, %0" + [(set_attr "type" "fpmul") + (set_attr "length" "1")]) (define_insn "*multf3_extend" [(set (match_operand:TF 0 "register_operand" "=e") (mult:TF (float_extend:TF (match_operand:DF 1 "register_operand" "e")) (float_extend:TF (match_operand:DF 2 "register_operand" "e"))))] "(TARGET_V8 || TARGET_V9) && TARGET_FPU && TARGET_HARD_QUAD" - "fdmulq %1,%2,%0" - [(set_attr "type" "fpmul")]) + "fdmulq\\t%1, %2, %0" + [(set_attr "type" "fpmul") + (set_attr "length" "1")]) ;; don't have timing for quad-prec. divide. (define_insn "divtf3" @@ -5248,25 +6172,29 @@ return \"srl %1,0,%0\"; (div:TF (match_operand:TF 1 "register_operand" "e") (match_operand:TF 2 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fdivq %1,%2,%0" - [(set_attr "type" "fpdivd")]) + "fdivq\\t%1, %2, %0" + [(set_attr "type" "fpdivd") + (set_attr "length" "1")]) (define_insn "divdf3" [(set (match_operand:DF 0 "register_operand" "=e") (div:DF (match_operand:DF 1 "register_operand" "e") (match_operand:DF 2 "register_operand" "e")))] "TARGET_FPU" - "fdivd %1,%2,%0" - [(set_attr "type" "fpdivd")]) + "fdivd\\t%1, %2, %0" + [(set_attr "type" "fpdivd") + (set_attr "length" "1")]) (define_insn "divsf3" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_FPU" - "fdivs %1,%2,%0" - [(set_attr "type" "fpdivs")]) + "fdivs\\t%1, %2, %0" + [(set_attr "type" "fpdivs") + (set_attr "length" "1")]) +;; XXX (define_insn "negtf2" [(set (match_operand:TF 0 "register_operand" "=e,e") (neg:TF (match_operand:TF 1 "register_operand" "0,e")))] @@ -5286,6 +6214,7 @@ return \"srl %1,0,%0\"; [(const_int 1) (if_then_else (eq_attr "isa" "v9") (const_int 2) (const_int 4))])]) +;; XXX (define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=e,e") (neg:DF (match_operand:DF 1 "register_operand" "0,e")))] @@ -5308,9 +6237,11 @@ return \"srl %1,0,%0\"; [(set (match_operand:SF 0 "register_operand" "=f") (neg:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_FPU" - "fnegs %1,%0" - [(set_attr "type" "fpmove")]) + "fnegs\\t%1, %0" + [(set_attr "type" "fpmove") + (set_attr "length" "1")]) +;; XXX (define_insn "abstf2" [(set (match_operand:TF 0 "register_operand" "=e,e") (abs:TF (match_operand:TF 1 "register_operand" "0,e")))] @@ -5330,6 +6261,7 @@ return \"srl %1,0,%0\"; [(const_int 1) (if_then_else (eq_attr "isa" "v9") (const_int 2) (const_int 4))])]) +;; XXX (define_insn "absdf2" [(set (match_operand:DF 0 "register_operand" "=e,e") (abs:DF (match_operand:DF 1 "register_operand" "0,e")))] @@ -5352,29 +6284,33 @@ return \"srl %1,0,%0\"; [(set (match_operand:SF 0 "register_operand" "=f") (abs:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_FPU" - "fabss %1,%0" - [(set_attr "type" "fpmove")]) + "fabss\\t%1, %0" + [(set_attr "type" "fpmove") + (set_attr "length" "1")]) (define_insn "sqrttf2" [(set (match_operand:TF 0 "register_operand" "=e") (sqrt:TF (match_operand:TF 1 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" - "fsqrtq %1,%0" - [(set_attr "type" "fpsqrt")]) + "fsqrtq\\t%1, %0" + [(set_attr "type" "fpsqrt") + (set_attr "length" "1")]) (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=e") (sqrt:DF (match_operand:DF 1 "register_operand" "e")))] "TARGET_FPU" - "fsqrtd %1,%0" - [(set_attr "type" "fpsqrt")]) + "fsqrtd\\t%1, %0" + [(set_attr "type" "fpsqrt") + (set_attr "length" "1")]) (define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f") (sqrt:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_FPU" - "fsqrts %1,%0" - [(set_attr "type" "fpsqrt")]) + "fsqrts\\t%1, %0" + [(set_attr "type" "fpsqrt") + (set_attr "length" "1")]) ;;- arithmetic shift instructions @@ -5389,9 +6325,10 @@ return \"srl %1,0,%0\"; && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - return \"sll %1,%2,%0\"; + return \"sll\\t%1, %2, %0\"; }" - [(set_attr "type" "shift")]) + [(set_attr "type" "shift") + (set_attr "length" "1")]) (define_expand "ashldi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -5420,9 +6357,12 @@ return \"srl %1,0,%0\"; && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); - return \"sllx %1,%2,%0\"; -}") + return \"sllx\\t%1, %2, %0\"; +}" + [(set_attr "type" "shift") + (set_attr "length" "1")]) +;; XXX UGH! (define_insn "ashldi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=&h,&h,r") (ashift:DI (match_operand:DI 1 "arith_operand" "rI,0,rI") @@ -5433,6 +6373,7 @@ return \"srl %1,0,%0\"; [(set_attr "length" "5,5,6")]) ;; Optimize (1LL< 31) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - return \"sra %1,%2,%0\"; + return \"sra\\t%1, %2, %0\"; }" - [(set_attr "type" "shift")]) + [(set_attr "type" "shift") + (set_attr "length" "1")]) (define_expand "ashrdi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -5487,13 +6432,15 @@ return \"srl %1,0,%0\"; (match_operand:SI 2 "arith_operand" "rI")))] "TARGET_ARCH64 || TARGET_V8PLUS" " -if (! TARGET_ARCH64) - { - if (GET_CODE (operands[2]) == CONST_INT) - FAIL; /* prefer generic code in this case */ - emit_insn (gen_ashrdi3_v8plus (operands[0], operands[1], operands[2])); - DONE; - }") +{ + if (! TARGET_ARCH64) + { + if (GET_CODE (operands[2]) == CONST_INT) + FAIL; /* prefer generic code in this case */ + emit_insn (gen_ashrdi3_v8plus (operands[0], operands[1], operands[2])); + DONE; + } +}") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -5506,9 +6453,12 @@ if (! TARGET_ARCH64) && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 63) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); - return \"srax %1,%2,%0\"; -}") + return \"srax\\t%1, %2, %0\"; +}" + [(set_attr "type" "shift") + (set_attr "length" "1")]) +;; XXX (define_insn "ashrdi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=&h,&h,r") (ashiftrt:DI (match_operand:DI 1 "arith_operand" "rI,0,rI") @@ -5529,9 +6479,10 @@ if (! TARGET_ARCH64) && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - return \"srl %1,%2,%0\"; + return \"srl\\t%1, %2, %0\"; }" - [(set_attr "type" "shift")]) + [(set_attr "type" "shift") + (set_attr "length" "1")]) (define_expand "lshrdi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -5539,13 +6490,15 @@ if (! TARGET_ARCH64) (match_operand:SI 2 "arith_operand" "rI")))] "TARGET_ARCH64 || TARGET_V8PLUS" " -if (! TARGET_ARCH64) - { - if (GET_CODE (operands[2]) == CONST_INT) - FAIL; - emit_insn (gen_lshrdi3_v8plus (operands[0], operands[1], operands[2])); - DONE; - }") +{ + if (! TARGET_ARCH64) + { + if (GET_CODE (operands[2]) == CONST_INT) + FAIL; + emit_insn (gen_lshrdi3_v8plus (operands[0], operands[1], operands[2])); + DONE; + } +}") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -5558,9 +6511,12 @@ if (! TARGET_ARCH64) && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 63) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); - return \"srlx %1,%2,%0\"; -}") + return \"srlx\\t%1, %2, %0\"; +}" + [(set_attr "type" "shift") + (set_attr "length" "1")]) +;; XXX (define_insn "lshrdi3_v8plus" [(set (match_operand:DI 0 "register_operand" "=&h,&h,r") (lshiftrt:DI (match_operand:DI 1 "arith_operand" "rI,0,rI") @@ -5589,9 +6545,9 @@ if (! TARGET_ARCH64) if (flag_delayed_branch && (insn_addresses[INSN_UID (operands[0])] == insn_addresses[INSN_UID (insn)])) - return \"b %l0%#\"; + return TARGET_V9 ? \"b,pt\\t%%xcc, %l0%#\" : \"b\\t%l0%#\"; else - return \"b%* %l0%(\"; + return TARGET_V9 ? \"b,pt%*\\t%%xcc, %l0%(\" : \"b%*\\t%l0%(\"; }" [(set_attr "type" "uncond_branch")]) @@ -5604,46 +6560,30 @@ if (! TARGET_ARCH64) if (GET_MODE (operands[0]) != Pmode) abort (); - /* We need to use the PC value in %o7 that was set up when the address - of the label was loaded into a register, so we need different RTL. */ + /* In pic mode, our address differences are against the base of the + table. Add that base value back in; CSE ought to be able to combine + the two address loads. */ if (flag_pic) { - if (!TARGET_PTR64) - emit_jump_insn (gen_pic_tablejump_32 (operands[0], operands[1])); - else - emit_jump_insn (gen_pic_tablejump_64 (operands[0], operands[1])); - DONE; + rtx tmp; + tmp = gen_rtx_LABEL_REF (Pmode, operands[1]); + tmp = gen_rtx_PLUS (Pmode, operands[0], tmp); + operands[0] = memory_address (Pmode, tmp); } }") -(define_insn "pic_tablejump_32" - [(set (pc) (match_operand:SI 0 "register_operand" "r")) - (use (label_ref (match_operand 1 "" ""))) - (use (reg:SI 15))] - "! TARGET_PTR64" - "jmp %%o7+%0%#" - [(set_attr "type" "uncond_branch")]) - -(define_insn "pic_tablejump_64" - [(set (pc) (match_operand:DI 0 "register_operand" "r")) - (use (label_ref (match_operand 1 "" ""))) - (use (reg:DI 15))] - "TARGET_PTR64" - "jmp %%o7+%0%#" - [(set_attr "type" "uncond_branch")]) - (define_insn "*tablejump_sp32" [(set (pc) (match_operand:SI 0 "address_operand" "p")) (use (label_ref (match_operand 1 "" "")))] "! TARGET_PTR64" - "jmp %a0%#" + "jmp\\t%a0%#" [(set_attr "type" "uncond_branch")]) (define_insn "*tablejump_sp64" [(set (pc) (match_operand:DI 0 "address_operand" "p")) (use (label_ref (match_operand 1 "" "")))] "TARGET_PTR64" - "jmp %a0%#" + "jmp\\t%a0%#" [(set_attr "type" "uncond_branch")]) ;; This pattern recognizes the "instruction" that appears in @@ -5652,7 +6592,7 @@ if (! TARGET_ARCH64) ;(define_insn "*unimp_insn" ; [(match_operand:SI 0 "immediate_operand" "")] ; "GET_CODE (operands[0]) == CONST_INT && INTVAL (operands[0]) > 0" -; "unimp %0" +; "unimp\\t%0" ; [(set_attr "type" "marker")]) ;;- jump to subroutine @@ -5751,7 +6691,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 1 for most machines. "! TARGET_PTR64" - "call %a0,%1%#" + "call\\t%a0, %1%#" [(set_attr "type" "call")]) (define_insn "*call_symbolic_sp32" @@ -5760,7 +6700,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 1 for most machines. "! TARGET_PTR64" - "call %a0,%1%#" + "call\\t%a0, %1%#" [(set_attr "type" "call")]) (define_insn "*call_address_sp64" @@ -5769,7 +6709,7 @@ if (! TARGET_ARCH64) (clobber (reg:DI 15))] ;;- Do not use operand 1 for most machines. "TARGET_PTR64" - "call %a0,%1%#" + "call\\t%a0, %1%#" [(set_attr "type" "call")]) (define_insn "*call_symbolic_sp64" @@ -5778,7 +6718,7 @@ if (! TARGET_ARCH64) (clobber (reg:DI 15))] ;;- Do not use operand 1 for most machines. "TARGET_PTR64" - "call %a0,%1%#" + "call\\t%a0, %1%#" [(set_attr "type" "call")]) ;; This is a call that wants a structure value. @@ -5790,7 +6730,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 1 for most machines. "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0" - "call %a0,%1\;nop\;unimp %2" + "call\\t%a0, %1\\n\\tnop\\n\\tunimp\\t%2" [(set_attr "type" "call_no_delay_slot")]) ;; This is a call that wants a structure value. @@ -5802,7 +6742,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 1 for most machines. "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0" - "call %a0,%1\;nop\;unimp %2" + "call\\t%a0, %1\\n\\tnop\\n\\tunimp\\t%2" [(set_attr "type" "call_no_delay_slot")]) ;; This is a call that may want a structure value. This is used for @@ -5814,7 +6754,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 1 for most machines. "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0" - "call %a0,%1\;nop\;nop" + "call\\t%a0, %1\\n\\tnop\\n\\tnop" [(set_attr "type" "call_no_delay_slot")]) ;; This is a call that wants a structure value. @@ -5825,7 +6765,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 1 for most machines. "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0" - "call %a0,%1\;nop\;nop" + "call\\t%a0, %1\\n\\tnop\\n\\tnop" [(set_attr "type" "call_no_delay_slot")]) (define_expand "call_value" @@ -5873,7 +6813,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 2 for most machines. "! TARGET_PTR64" - "call %a1,%2%#" + "call\\t%a1, %2%#" [(set_attr "type" "call")]) (define_insn "*call_value_symbolic_sp32" @@ -5883,7 +6823,7 @@ if (! TARGET_ARCH64) (clobber (reg:SI 15))] ;;- Do not use operand 2 for most machines. "! TARGET_PTR64" - "call %a1,%2%#" + "call\\t%a1, %2%#" [(set_attr "type" "call")]) (define_insn "*call_value_address_sp64" @@ -5893,7 +6833,7 @@ if (! TARGET_ARCH64) (clobber (reg:DI 15))] ;;- Do not use operand 2 for most machines. "TARGET_PTR64" - "call %a1,%2%#" + "call\\t%a1, %2%#" [(set_attr "type" "call")]) (define_insn "*call_value_symbolic_sp64" @@ -5903,7 +6843,7 @@ if (! TARGET_ARCH64) (clobber (reg:DI 15))] ;;- Do not use operand 2 for most machines. "TARGET_PTR64" - "call %a1,%2%#" + "call\\t%a1, %2%#" [(set_attr "type" "call")]) (define_expand "untyped_call" @@ -6008,7 +6948,7 @@ if (! TARGET_ARCH64) (parallel [(return) (use (reg:SI 31))])] "sparc_return_peephole_ok (operands[0], operands[1])" - "return %%i7+8\;mov %Y1,%Y0") + "return\\t%%i7+8\\n\\tmov\\t%Y1, %Y0") (define_insn "nop" [(const_int 0)] @@ -6023,13 +6963,13 @@ if (! TARGET_ARCH64) (define_insn "*branch_sp32" [(set (pc) (match_operand:SI 0 "address_operand" "p"))] "! TARGET_PTR64" - "jmp %a0%#" + "jmp\\t%a0%#" [(set_attr "type" "uncond_branch")]) (define_insn "*branch_sp64" [(set (pc) (match_operand:DI 0 "address_operand" "p"))] "TARGET_PTR64" - "jmp %a0%#" + "jmp\\t%a0%#" [(set_attr "type" "uncond_branch")]) ;; ??? Doesn't work with -mflat. @@ -6092,13 +7032,13 @@ if (! TARGET_ARCH64) (define_insn "flush_register_windows" [(unspec_volatile [(const_int 0)] 1)] "" - "* return TARGET_V9 ? \"flushw\" : \"ta 3\";" + "* return TARGET_V9 ? \"flushw\" : \"ta\\t3\";" [(set_attr "type" "misc")]) (define_insn "goto_handler_and_restore" [(unspec_volatile [(match_operand:SI 0 "register_operand" "=r")] 2)] "" - "jmp %0+0\;restore" + "jmp\\t%0+0\\n\\trestore" [(set_attr "type" "misc") (set_attr "length" "2")]) @@ -6108,8 +7048,8 @@ if (! TARGET_ARCH64) (match_operand:SI 2 "const_int_operand" "I,n")] 3)] "TARGET_V9 && ! TARGET_ARCH64" "@ - return %0+0\;mov %2,%Y1 - sethi %%hi(%2),%1\;return %0+0\;or %Y1,%%lo(%2),%Y1" + return\\t%0+0\\n\\tmov\\t%2, %Y1 + sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1" [(set_attr "type" "misc") (set_attr "length" "2,3")]) @@ -6119,8 +7059,8 @@ if (! TARGET_ARCH64) (match_operand:SI 2 "const_int_operand" "I,n")] 3)] "TARGET_V9 && TARGET_ARCH64" "@ - return %0+0\;mov %2,%Y1 - sethi %%hi(%2),%1\;return %0+0\;or %Y1,%%lo(%2),%Y1" + return\\t%0+0\\n\\tmov\\t%2, %Y1 + sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1" [(set_attr "type" "misc") (set_attr "length" "2,3")]) @@ -6156,9 +7096,9 @@ if (! TARGET_ARCH64) ;; Special pattern for the FLUSH instruction. (define_insn "flush" - [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 3)] + [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 4)] "" - "* return TARGET_V9 ? \"flush %f0\" : \"iflush %f0\";" + "* return TARGET_V9 ? \"flush\\t%f0\" : \"iflush\\t%f0\";" [(set_attr "type" "misc")]) ;; find first set. @@ -6168,6 +7108,7 @@ if (! TARGET_ARCH64) ;; zero also differ. It takes at least 7 instructions to get the proper ;; result. Here is an obvious 8 instruction sequence. +;; XXX (define_insn "ffssi2" [(set (match_operand:SI 0 "register_operand" "=&r") (ffs:SI (match_operand:SI 1 "register_operand" "r"))) @@ -6196,205 +7137,7 @@ if (! TARGET_ARCH64) ; "neg %1,%2\;xnor %1,%2,%2\;popc %2,%0\;movzr %1,0,%0" ; [(set_attr "type" "multi") ; (set_attr "length" "4")]) - -;; Split up troublesome insns for better scheduling. */ -;; The following patterns are straightforward. They can be applied -;; either before or after register allocation. - -(define_split - [(set (match_operand 0 "splittable_symbolic_memory_operand" "") - (match_operand 1 "reg_or_0_operand" "")) - (clobber (match_operand:SI 2 "register_operand" ""))] - "! flag_pic" - [(set (match_dup 2) (high:SI (match_dup 3))) - (set (match_dup 4) (match_dup 1))] - " -{ - operands[3] = XEXP (operands[0], 0); - operands[4] = gen_rtx_MEM (GET_MODE (operands[0]), - gen_rtx_LO_SUM (SImode, operands[2], operands[3])); - MEM_IN_STRUCT_P (operands[4]) = MEM_IN_STRUCT_P (operands[0]); - MEM_VOLATILE_P (operands[4]) = MEM_VOLATILE_P (operands[0]); - RTX_UNCHANGING_P (operands[4]) = RTX_UNCHANGING_P (operands[0]); -}") - -(define_split - [(set (match_operand 0 "splittable_immediate_memory_operand" "") - (match_operand 1 "general_operand" "")) - (clobber (match_operand:SI 2 "register_operand" ""))] - "flag_pic" - [(set (match_dup 3) (match_dup 1))] - " -{ - rtx addr = legitimize_pic_address (XEXP (operands[0], 0), - GET_MODE (operands[0]), - operands[2]); - operands[3] = gen_rtx_MEM (GET_MODE (operands[0]), addr); - MEM_IN_STRUCT_P (operands[3]) = MEM_IN_STRUCT_P (operands[0]); - MEM_VOLATILE_P (operands[3]) = MEM_VOLATILE_P (operands[0]); - RTX_UNCHANGING_P (operands[3]) = RTX_UNCHANGING_P (operands[0]); -}") - -(define_split - [(set (match_operand 0 "register_operand" "") - (match_operand 1 "splittable_immediate_memory_operand" ""))] - "flag_pic" - [(set (match_dup 0) (match_dup 2))] - " -{ - rtx addr = legitimize_pic_address (XEXP (operands[1], 0), - GET_MODE (operands[1]), - operands[0]); - operands[2] = gen_rtx_MEM (GET_MODE (operands[1]), addr); - MEM_IN_STRUCT_P (operands[2]) = MEM_IN_STRUCT_P (operands[1]); - MEM_VOLATILE_P (operands[2]) = MEM_VOLATILE_P (operands[1]); - RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); -}") - -;; Sign- and Zero-extend operations can have symbolic memory operands. - -(define_split - [(set (match_operand 0 "register_operand" "") - (match_operator 1 "extend_op" [(match_operand 2 "splittable_immediate_memory_operand" "")]))] - "flag_pic" - [(set (match_dup 0) (match_op_dup 1 [(match_dup 3)]))] - " -{ - rtx addr = legitimize_pic_address (XEXP (operands[2], 0), - GET_MODE (operands[2]), - operands[0]); - operands[3] = gen_rtx_MEM (GET_MODE (operands[2]), addr); - MEM_IN_STRUCT_P (operands[3]) = MEM_IN_STRUCT_P (operands[2]); - MEM_VOLATILE_P (operands[3]) = MEM_VOLATILE_P (operands[2]); - RTX_UNCHANGING_P (operands[3]) = RTX_UNCHANGING_P (operands[2]); -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "immediate_operand" ""))] - "! flag_pic && (GET_CODE (operands[1]) == SYMBOL_REF - || GET_CODE (operands[1]) == CONST - || GET_CODE (operands[1]) == LABEL_REF)" - [(set (match_dup 0) (high:SI (match_dup 1))) - (set (match_dup 0) - (lo_sum:SI (match_dup 0) (match_dup 1)))] - "") - -;; LABEL_REFs are not modified by `legitimize_pic_address' -;; so do not recurse infinitely in the PIC case. -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "immediate_operand" ""))] - "flag_pic && (GET_CODE (operands[1]) == SYMBOL_REF - || GET_CODE (operands[1]) == CONST)" - [(set (match_dup 0) (match_dup 1))] - " -{ - operands[1] = legitimize_pic_address (operands[1], Pmode, operands[0]); -}") - -;; These split sne/seq insns. The forms of the resulting insns are -;; somewhat bogus, but they avoid extra patterns and show data dependency. -;; Nothing will look at these in detail after splitting has occurred. - -;; ??? v9 DImode versions are missing because addc and subc use %icc. - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (ne:SI (match_operand:SI 1 "register_operand" "") - (const_int 0))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (ltu:SI (reg:CC 100) (const_int 0)))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (neg:SI (ne:SI (match_operand:SI 1 "register_operand" "") - (const_int 0)))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (neg:SI (ltu:SI (reg:CC 100) (const_int 0))))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (eq:SI (match_operand:SI 1 "register_operand" "") - (const_int 0))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (geu:SI (reg:CC 100) (const_int 0)))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (neg:SI (eq:SI (match_operand:SI 1 "register_operand" "") - (const_int 0)))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (neg:SI (geu:SI (reg:CC 100) (const_int 0))))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (ne:SI (match_operand:SI 1 "register_operand" "") - (const_int 0)) - (match_operand:SI 2 "register_operand" ""))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (plus:SI (ltu:SI (reg:CC 100) (const_int 0)) - (match_dup 2)))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_operand:SI 2 "register_operand" "") - (ne:SI (match_operand:SI 1 "register_operand" "") - (const_int 0)))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (minus:SI (match_dup 2) - (ltu:SI (reg:CC 100) (const_int 0))))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (plus:SI (eq:SI (match_operand:SI 1 "register_operand" "") - (const_int 0)) - (match_operand:SI 2 "register_operand" ""))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (plus:SI (geu:SI (reg:CC 100) (const_int 0)) - (match_dup 2)))] - "") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_operand:SI 2 "register_operand" "") - (eq:SI (match_operand:SI 1 "register_operand" "") - (const_int 0)))) - (clobber (reg:CC 100))] - "" - [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1)) - (const_int 0))) - (set (match_dup 0) (minus:SI (match_dup 2) - (geu:SI (reg:CC 100) (const_int 0))))] - "") ;; Peepholes go at the end. @@ -6408,9 +7151,10 @@ if (! TARGET_ARCH64) (set (match_operand:SI 1 "memory_operand" "") (const_int 0))] "TARGET_V9 - && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[1]) + && ! MEM_VOLATILE_P (operands[0]) + && ! MEM_VOLATILE_P (operands[1]) && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[1], 0))" - "stx %%g0,%0") + "stx\\t%%g0, %0") (define_peephole [(set (match_operand:SI 0 "memory_operand" "") @@ -6418,89 +7162,98 @@ if (! TARGET_ARCH64) (set (match_operand:SI 1 "memory_operand" "") (const_int 0))] "TARGET_V9 - && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[1]) + && ! MEM_VOLATILE_P (operands[0]) + && ! MEM_VOLATILE_P (operands[1]) && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[0], 0))" - "stx %%g0,%1") + "stx\\t%%g0, %1") (define_peephole [(set (match_operand:SI 0 "register_operand" "=rf") (match_operand:SI 1 "memory_operand" "")) (set (match_operand:SI 2 "register_operand" "=rf") (match_operand:SI 3 "memory_operand" ""))] - "registers_ok_for_ldd_peep (operands[0], operands[2]) - && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3]) + "registers_ok_for_ldd_peep (operands[0], operands[2]) + && ! MEM_VOLATILE_P (operands[1]) + && ! MEM_VOLATILE_P (operands[3]) && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))" - "ldd %1,%0") + "ldd\\t%1, %0") (define_peephole [(set (match_operand:SI 0 "memory_operand" "") (match_operand:SI 1 "register_operand" "rf")) (set (match_operand:SI 2 "memory_operand" "") (match_operand:SI 3 "register_operand" "rf"))] - "registers_ok_for_ldd_peep (operands[1], operands[3]) - && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2]) + "registers_ok_for_ldd_peep (operands[1], operands[3]) + && ! MEM_VOLATILE_P (operands[0]) + && ! MEM_VOLATILE_P (operands[2]) && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))" - "std %1,%0") + "std\\t%1, %0") (define_peephole [(set (match_operand:SF 0 "register_operand" "=fr") (match_operand:SF 1 "memory_operand" "")) (set (match_operand:SF 2 "register_operand" "=fr") (match_operand:SF 3 "memory_operand" ""))] - "registers_ok_for_ldd_peep (operands[0], operands[2]) - && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3]) + "registers_ok_for_ldd_peep (operands[0], operands[2]) + && ! MEM_VOLATILE_P (operands[1]) + && ! MEM_VOLATILE_P (operands[3]) && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))" - "ldd %1,%0") + "ldd\\t%1, %0") (define_peephole [(set (match_operand:SF 0 "memory_operand" "") (match_operand:SF 1 "register_operand" "fr")) (set (match_operand:SF 2 "memory_operand" "") (match_operand:SF 3 "register_operand" "fr"))] - "registers_ok_for_ldd_peep (operands[1], operands[3]) - && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2]) - && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))" - "std %1,%0") + "registers_ok_for_ldd_peep (operands[1], operands[3]) + && ! MEM_VOLATILE_P (operands[0]) + && ! MEM_VOLATILE_P (operands[2]) + && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))" + "std\\t%1, %0") (define_peephole [(set (match_operand:SI 0 "register_operand" "=rf") (match_operand:SI 1 "memory_operand" "")) (set (match_operand:SI 2 "register_operand" "=rf") (match_operand:SI 3 "memory_operand" ""))] - "registers_ok_for_ldd_peep (operands[2], operands[0]) - && ! MEM_VOLATILE_P (operands[3]) && ! MEM_VOLATILE_P (operands[1]) - && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))" - "ldd %3,%2") + "registers_ok_for_ldd_peep (operands[2], operands[0]) + && ! MEM_VOLATILE_P (operands[3]) + && ! MEM_VOLATILE_P (operands[1]) + && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))" + "ldd\\t%3, %2") (define_peephole [(set (match_operand:SI 0 "memory_operand" "") (match_operand:SI 1 "register_operand" "rf")) (set (match_operand:SI 2 "memory_operand" "") (match_operand:SI 3 "register_operand" "rf"))] - "registers_ok_for_ldd_peep (operands[3], operands[1]) - && ! MEM_VOLATILE_P (operands[2]) && ! MEM_VOLATILE_P (operands[0]) - && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))" - "std %3,%2") + "registers_ok_for_ldd_peep (operands[3], operands[1]) + && ! MEM_VOLATILE_P (operands[2]) + && ! MEM_VOLATILE_P (operands[0]) + && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))" + "std\\t%3, %2") (define_peephole [(set (match_operand:SF 0 "register_operand" "=fr") (match_operand:SF 1 "memory_operand" "")) (set (match_operand:SF 2 "register_operand" "=fr") (match_operand:SF 3 "memory_operand" ""))] - "registers_ok_for_ldd_peep (operands[2], operands[0]) - && ! MEM_VOLATILE_P (operands[3]) && ! MEM_VOLATILE_P (operands[1]) - && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))" - "ldd %3,%2") + "registers_ok_for_ldd_peep (operands[2], operands[0]) + && ! MEM_VOLATILE_P (operands[3]) + && ! MEM_VOLATILE_P (operands[1]) + && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))" + "ldd\\t%3, %2") (define_peephole [(set (match_operand:SF 0 "memory_operand" "") (match_operand:SF 1 "register_operand" "fr")) (set (match_operand:SF 2 "memory_operand" "") (match_operand:SF 3 "register_operand" "fr"))] - "registers_ok_for_ldd_peep (operands[3], operands[1]) - && ! MEM_VOLATILE_P (operands[2]) && ! MEM_VOLATILE_P (operands[0]) - && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))" - "std %3,%2") + "registers_ok_for_ldd_peep (operands[3], operands[1]) + && ! MEM_VOLATILE_P (operands[2]) + && ! MEM_VOLATILE_P (operands[0]) + && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))" + "std\\t%3, %2") ;; Optimize the case of following a reg-reg move with a test ;; of reg just moved. Don't allow floating point regs for operand 0 or 1. @@ -6514,8 +7267,9 @@ if (! TARGET_ARCH64) (const_int 0)))] "(rtx_equal_p (operands[2], operands[0]) || rtx_equal_p (operands[2], operands[1])) - && ! FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" - "orcc %1,0,%0") + && ! FP_REG_P (operands[0]) + && ! FP_REG_P (operands[1])" + "orcc\\t%1, 0, %0") (define_peephole [(set (match_operand:DI 0 "register_operand" "=r") @@ -6526,37 +7280,9 @@ if (! TARGET_ARCH64) "TARGET_ARCH64 && (rtx_equal_p (operands[2], operands[0]) || rtx_equal_p (operands[2], operands[1])) - && ! FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" - "orcc %1,0,%0") - -;; Floating-point move peepholes -;; ??? v9: Do we want similar ones? - -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=r") - (lo_sum:SI (match_dup 0) - (match_operand:SI 1 "immediate_operand" "i"))) - (set (match_operand:DF 2 "register_operand" "=er") - (mem:DF (match_dup 0)))] - "RTX_UNCHANGING_P (operands[1]) && reg_unused_after (operands[0], insn)" - "* -{ - /* Go by way of output_move_double in case the register in operand 2 - is not properly aligned for ldd. */ - operands[1] = gen_rtx_MEM (DFmode, - gen_rtx_LO_SUM (SImode, operands[0], operands[1])); - operands[0] = operands[2]; - return output_move_double (operands); -}") - -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=r") - (lo_sum:SI (match_dup 0) - (match_operand:SI 1 "immediate_operand" "i"))) - (set (match_operand:SF 2 "register_operand" "=fr") - (mem:SF (match_dup 0)))] - "RTX_UNCHANGING_P (operands[1]) && reg_unused_after (operands[0], insn)" - "ld [%0+%%lo(%a1)],%2") + && ! FP_REG_P (operands[0]) + && ! FP_REG_P (operands[1])" + "orcc\\t%1, 0, %0") ;; Return peepholes. First the "normal" ones. ;; These are necessary to catch insns ending up in the epilogue delay list. @@ -6569,12 +7295,12 @@ if (! TARGET_ARCH64) "* { if (! TARGET_ARCH64 && current_function_returns_struct) - return \"jmp %%i7+12\;restore %%g0,%1,%Y0\"; + return \"jmp\\t%%i7+12\\n\\trestore %%g0, %1, %Y0\"; else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT || IN_OR_GLOBAL_P (operands[1]))) - return \"return %%i7+8\;mov %Y1,%Y0\"; + return \"return\\t%%i7+8\\n\\tmov\\t%Y1, %Y0\"; else - return \"ret\;restore %%g0,%1,%Y0\"; + return \"ret\\n\\trestore %%g0, %1, %Y0\"; }" [(set_attr "type" "multi")]) @@ -6586,12 +7312,12 @@ if (! TARGET_ARCH64) "* { if (! TARGET_ARCH64 && current_function_returns_struct) - return \"jmp %%i7+12\;restore %%g0,%1,%Y0\"; + return \"jmp\\t%%i7+12\\n\\trestore %%g0, %1, %Y0\"; else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT || IN_OR_GLOBAL_P (operands[1]))) - return \"return %%i7+8\;mov %Y1,%Y0\"; + return \"return\\t%%i7+8\\n\\tmov\\t%Y1, %Y0\"; else - return \"ret\;restore %%g0,%1,%Y0\"; + return \"ret\;restore %%g0, %1, %Y0\"; }" [(set_attr "type" "multi")]) @@ -6603,31 +7329,32 @@ if (! TARGET_ARCH64) "* { if (! TARGET_ARCH64 && current_function_returns_struct) - return \"jmp %%i7+12\;restore %%g0,%1,%Y0\"; + return \"jmp\\t%%i7+12\\n\\trestore %%g0, %1, %Y0\"; else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT || IN_OR_GLOBAL_P (operands[1]))) - return \"return %%i7+8\;mov %Y1,%Y0\"; + return \"return\\t%%i7+8\\n\\tmov\\t%Y1, %Y0\"; else - return \"ret\;restore %%g0,%1,%Y0\"; + return \"ret\;restore %%g0, %1, %Y0\"; }" [(set_attr "type" "multi")]) ;; The following pattern is only generated by delayed-branch scheduling, -;; when the insn winds up in the epilogue. This can only happen when -;; ! TARGET_FPU because otherwise fp return values are in %f0. +;; when the insn winds up in the epilogue. This can happen not only when +;; ! TARGET_FPU because we move complex types around by parts using +;; SF mode SUBREGs. (define_insn "*return_sf_no_fpu" [(set (match_operand:SF 0 "restore_operand" "r") (match_operand:SF 1 "register_operand" "r")) (return)] - "! TARGET_FPU && ! TARGET_EPILOGUE && ! TARGET_LIVE_G0" + "! TARGET_EPILOGUE && ! TARGET_LIVE_G0" "* { if (! TARGET_ARCH64 && current_function_returns_struct) - return \"jmp %%i7+12\;restore %%g0,%1,%Y0\"; + return \"jmp\\t%%i7+12\\n\\trestore %%g0, %1, %Y0\"; else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1])) - return \"return %%i7+8\;mov %Y1,%Y0\"; + return \"return\\t%%i7+8\\n\\tmov\\t%Y1, %Y0\"; else - return \"ret\;restore %%g0,%1,%Y0\"; + return \"ret\;restore %%g0, %1, %Y0\"; }" [(set_attr "type" "multi")]) @@ -6640,14 +7367,14 @@ if (! TARGET_ARCH64) "* { if (! TARGET_ARCH64 && current_function_returns_struct) - return \"jmp %%i7+12\;restore %r1,%2,%Y0\"; + return \"jmp\\t%%i7+12\\n\\trestore %r1, %2, %Y0\"; /* If operands are global or in registers, can use return */ else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]) && (GET_CODE (operands[2]) == CONST_INT || IN_OR_GLOBAL_P (operands[2]))) - return \"return %%i7+8\;add %Y1,%Y2,%Y0\"; + return \"return\\t%%i7+8\\n\\tadd\\t%Y1, %Y2, %Y0\"; else - return \"ret\;restore %r1,%2,%Y0\"; + return \"ret\;restore %r1, %2, %Y0\"; }" [(set_attr "type" "multi")]) @@ -6656,7 +7383,7 @@ if (! TARGET_ARCH64) (match_operand:DI 1 "arith_double_operand" "rHI")) (return)] "TARGET_ARCH64 && ! TARGET_EPILOGUE" - "ret\;restore %%g0,%1,%Y0" + "ret\;restore %%g0, %1, %Y0" [(set_attr "type" "multi")]) (define_insn "*return_adddi" @@ -6665,7 +7392,7 @@ if (! TARGET_ARCH64) (match_operand:DI 2 "arith_double_operand" "rHI"))) (return)] "TARGET_ARCH64 && ! TARGET_EPILOGUE" - "ret\;restore %r1,%2,%Y0" + "ret\;restore %r1, %2, %Y0" [(set_attr "type" "multi")]) ;; The following pattern is only generated by delayed-branch scheduling, @@ -6675,7 +7402,7 @@ if (! TARGET_ARCH64) (match_operand:SF 0 "register_operand" "f")) (return)] "! TARGET_EPILOGUE" - "ret\;fmovs %0,%%f0" + "ret\;fmovs\\t%0, %%f0" [(set_attr "type" "multi")]) ;; Now peepholes to do a call followed by a jump. @@ -6686,16 +7413,20 @@ if (! TARGET_ARCH64) (match_operand 2 "" ""))) (clobber (reg:SI 15))]) (set (pc) (label_ref (match_operand 3 "" "")))] - "short_branch (INSN_UID (insn), INSN_UID (operands[3])) && in_same_eh_region (insn, operands[3]) && in_same_eh_region (insn, ins1)" - "call %a1,%2\;add %%o7,(%l3-.-4),%%o7") + "short_branch (INSN_UID (insn), INSN_UID (operands[3])) + && in_same_eh_region (insn, operands[3]) + && in_same_eh_region (insn, ins1)" + "call\\t%a1, %2\\n\\tadd\\t%%o7, (%l3-.-4), %%o7") (define_peephole [(parallel [(call (mem:SI (match_operand:SI 0 "call_operand_address" "ps")) (match_operand 1 "" "")) (clobber (reg:SI 15))]) (set (pc) (label_ref (match_operand 2 "" "")))] - "short_branch (INSN_UID (insn), INSN_UID (operands[2])) && in_same_eh_region (insn, operands[2]) && in_same_eh_region (insn, ins1)" - "call %a0,%1\;add %%o7,(%l2-.-4),%%o7") + "short_branch (INSN_UID (insn), INSN_UID (operands[2])) + && in_same_eh_region (insn, operands[2]) + && in_same_eh_region (insn, ins1)" + "call\\t%a0, %1\\n\\tadd\\t%%o7, (%l2-.-4), %%o7") (define_peephole [(parallel [(set (match_operand 0 "" "") @@ -6703,30 +7434,36 @@ if (! TARGET_ARCH64) (match_operand 2 "" ""))) (clobber (reg:DI 15))]) (set (pc) (label_ref (match_operand 3 "" "")))] - "TARGET_ARCH64 && short_branch (INSN_UID (insn), INSN_UID (operands[3])) && in_same_eh_region (insn, operands[3]) && in_same_eh_region (insn, ins1)" - "call %a1,%2\;add %%o7,(%l3-.-4),%%o7") + "TARGET_ARCH64 + && short_branch (INSN_UID (insn), INSN_UID (operands[3])) + && in_same_eh_region (insn, operands[3]) + && in_same_eh_region (insn, ins1)" + "call\\t%a1, %2\\n\\tadd\\t%%o7, (%l3-.-4), %%o7") (define_peephole [(parallel [(call (mem:SI (match_operand:DI 0 "call_operand_address" "ps")) (match_operand 1 "" "")) (clobber (reg:DI 15))]) (set (pc) (label_ref (match_operand 2 "" "")))] - "TARGET_ARCH64 && short_branch (INSN_UID (insn), INSN_UID (operands[2])) && in_same_eh_region (insn, operands[2]) && in_same_eh_region (insn, ins1)" - "call %a0,%1\;add %%o7,(%l2-.-4),%%o7") + "TARGET_ARCH64 + && short_branch (INSN_UID (insn), INSN_UID (operands[2])) + && in_same_eh_region (insn, operands[2]) + && in_same_eh_region (insn, ins1)" + "call\\t%a0, %1\\n\\tadd\\t%%o7, (%l2-.-4), %%o7") ;; After a nonlocal goto, we need to restore the PIC register, but only ;; if we need it. So do nothing much here, but we'll check for this in ;; finalize_pic. (define_insn "nonlocal_goto_receiver" - [(unspec_volatile [(const_int 0)] 4)] + [(unspec_volatile [(const_int 0)] 5)] "flag_pic" "") (define_insn "trap" [(trap_if (const_int 1) (const_int 5))] "" - "ta 5" + "ta\\t5" [(set_attr "type" "misc")]) (define_expand "conditional_trap" @@ -6742,13 +7479,13 @@ if (! TARGET_ARCH64) [(trap_if (match_operator 0 "noov_compare_op" [(reg:CC 100) (const_int 0)]) (match_operand:SI 1 "arith_operand" "rM"))] "" - "t%C0 %1" + "t%C0\\t%1" [(set_attr "type" "misc")]) (define_insn "" [(trap_if (match_operator 0 "noov_compare_op" [(reg:CCX 100) (const_int 0)]) (match_operand:SI 1 "arith_operand" "rM"))] "TARGET_V9" - "t%C0 %%xcc,%1" + "t%C0\\t%%xcc, %1" [(set_attr "type" "misc")]) diff --git a/gcc/config/sparc/sysv4.h b/gcc/config/sparc/sysv4.h index 7e90bdd4036..5a614e5ffa9 100644 --- a/gcc/config/sparc/sysv4.h +++ b/gcc/config/sparc/sysv4.h @@ -66,7 +66,9 @@ Boston, MA 02111-1307, USA. */ /* The native assembler can't compute differences between symbols in different sections when generating pic code, so we must put jump tables in the text section. */ -#define JUMP_TABLES_IN_TEXT_SECTION 1 +/* But we now defer the tables to the end of the function, so we make + this 0 to not confuse the branch shortening code. */ +#define JUMP_TABLES_IN_TEXT_SECTION 0 /* Pass -K to the assembler when PIC. */ #undef ASM_SPEC diff --git a/gcc/final.c b/gcc/final.c index 4b05fc70c46..e6a1d5347a6 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -2326,6 +2326,11 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) if (GET_CODE (nextbody) == ADDR_VEC || GET_CODE (nextbody) == ADDR_DIFF_VEC) { +#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) + /* In this case, the case vector is being moved by the + target, so don't output the label at all. Leave that + to the back end macros. */ +#else if (! JUMP_TABLES_IN_TEXT_SECTION) { readonly_data_section (); @@ -2343,6 +2348,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) NEXT_INSN (insn)); #else ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); +#endif #endif break; } @@ -2397,6 +2403,24 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) app_on = 0; } +#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) + if (GET_CODE (body) == ADDR_VEC) + { +#ifdef ASM_OUTPUT_ADDR_VEC + ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); +#else + abort(); +#endif + } + else + { +#ifdef ASM_OUTPUT_ADDR_DIFF_VEC + ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); +#else + abort(); +#endif + } +#else vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); for (idx = 0; idx < vlen; idx++) { @@ -2426,6 +2450,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) ASM_OUTPUT_CASE_END (file, CODE_LABEL_NUMBER (PREV_INSN (insn)), insn); +#endif #endif function_section (current_function_decl); diff --git a/gcc/reorg.c b/gcc/reorg.c index 69c43238cb5..fb855a9f221 100644 --- a/gcc/reorg.c +++ b/gcc/reorg.c @@ -4660,6 +4660,13 @@ dbr_schedule (first, file) { int pred_flags; + if (GET_CODE (insn) == INSN) + { + rtx pat = PATTERN (insn); + + if (GET_CODE (pat) == SEQUENCE) + insn = XVECEXP (pat, 0, 0); + } if (GET_CODE (insn) != JUMP_INSN) continue;