+ x = gen_rtx_EQ (DImode, x, oldval);
+ emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+ x = gen_rtx_EQ (DImode, cond, const0_rtx);
+ }
+ emit_unlikely_jump (x, label2);
+
+ emit_move_insn (scratch, newval);
+ emit_store_conditional (mode, cond, mem, scratch);
+
+ x = gen_rtx_EQ (DImode, cond, const0_rtx);
+ emit_unlikely_jump (x, label1);
+
+ emit_insn (gen_memory_barrier ());
+ emit_label (XEXP (label2, 0));
+}
+
+void
+alpha_expand_compare_and_swap_12 (rtx dst, rtx mem, rtx oldval, rtx newval)
+{
+ enum machine_mode mode = GET_MODE (mem);
+ rtx addr, align, wdst;
+ rtx (*fn5) (rtx, rtx, rtx, rtx, rtx);
+
+ addr = force_reg (DImode, XEXP (mem, 0));
+ align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8),
+ NULL_RTX, 1, OPTAB_DIRECT);
+
+ oldval = convert_modes (DImode, mode, oldval, 1);
+ newval = emit_insxl (mode, newval, addr);
+
+ wdst = gen_reg_rtx (DImode);
+ if (mode == QImode)
+ fn5 = gen_sync_compare_and_swapqi_1;
+ else
+ fn5 = gen_sync_compare_and_swaphi_1;
+ emit_insn (fn5 (wdst, addr, oldval, newval, align));
+
+ emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+alpha_split_compare_and_swap_12 (enum machine_mode mode, rtx dest, rtx addr,
+ rtx oldval, rtx newval, rtx align,
+ rtx scratch, rtx cond)
+{
+ rtx label1, label2, mem, width, mask, x;
+
+ mem = gen_rtx_MEM (DImode, align);
+ MEM_VOLATILE_P (mem) = 1;
+
+ emit_insn (gen_memory_barrier ());
+ label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+ label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+ emit_label (XEXP (label1, 0));
+
+ emit_load_locked (DImode, scratch, mem);
+
+ width = GEN_INT (GET_MODE_BITSIZE (mode));
+ mask = GEN_INT (mode == QImode ? 0xff : 0xffff);
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_extxl_be (dest, scratch, width, addr));
+ else
+ emit_insn (gen_extxl_le (dest, scratch, width, addr));
+
+ if (oldval == const0_rtx)
+ x = gen_rtx_NE (DImode, dest, const0_rtx);
+ else
+ {
+ x = gen_rtx_EQ (DImode, dest, oldval);
+ emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+ x = gen_rtx_EQ (DImode, cond, const0_rtx);
+ }
+ emit_unlikely_jump (x, label2);
+
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_mskxl_be (scratch, scratch, mask, addr));
+ else
+ emit_insn (gen_mskxl_le (scratch, scratch, mask, addr));
+ emit_insn (gen_iordi3 (scratch, scratch, newval));
+
+ emit_store_conditional (DImode, scratch, mem, scratch);
+
+ x = gen_rtx_EQ (DImode, scratch, const0_rtx);
+ emit_unlikely_jump (x, label1);
+
+ emit_insn (gen_memory_barrier ());
+ emit_label (XEXP (label2, 0));
+}
+
+/* Expand an atomic exchange operation. */
+
+void
+alpha_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
+{
+ enum machine_mode mode = GET_MODE (mem);
+ rtx label, x, cond = gen_lowpart (DImode, scratch);
+
+ emit_insn (gen_memory_barrier ());
+
+ label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+ emit_label (XEXP (label, 0));
+
+ emit_load_locked (mode, retval, mem);
+ emit_move_insn (scratch, val);
+ emit_store_conditional (mode, cond, mem, scratch);
+
+ x = gen_rtx_EQ (DImode, cond, const0_rtx);
+ emit_unlikely_jump (x, label);
+}
+
+void
+alpha_expand_lock_test_and_set_12 (rtx dst, rtx mem, rtx val)
+{
+ enum machine_mode mode = GET_MODE (mem);
+ rtx addr, align, wdst;
+ rtx (*fn4) (rtx, rtx, rtx, rtx);
+
+ /* Force the address into a register. */
+ addr = force_reg (DImode, XEXP (mem, 0));
+
+ /* Align it to a multiple of 8. */
+ align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8),
+ NULL_RTX, 1, OPTAB_DIRECT);
+
+ /* Insert val into the correct byte location within the word. */
+ val = emit_insxl (mode, val, addr);
+
+ wdst = gen_reg_rtx (DImode);
+ if (mode == QImode)
+ fn4 = gen_sync_lock_test_and_setqi_1;
+ else
+ fn4 = gen_sync_lock_test_and_sethi_1;
+ emit_insn (fn4 (wdst, addr, val, align));
+
+ emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+alpha_split_lock_test_and_set_12 (enum machine_mode mode, rtx dest, rtx addr,
+ rtx val, rtx align, rtx scratch)
+{
+ rtx label, mem, width, mask, x;
+
+ mem = gen_rtx_MEM (DImode, align);
+ MEM_VOLATILE_P (mem) = 1;
+
+ emit_insn (gen_memory_barrier ());
+ label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+ emit_label (XEXP (label, 0));
+
+ emit_load_locked (DImode, scratch, mem);
+
+ width = GEN_INT (GET_MODE_BITSIZE (mode));
+ mask = GEN_INT (mode == QImode ? 0xff : 0xffff);
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_extxl_be (dest, scratch, width, addr));
+ emit_insn (gen_mskxl_be (scratch, scratch, mask, addr));
+ }
+ else
+ {
+ emit_insn (gen_extxl_le (dest, scratch, width, addr));
+ emit_insn (gen_mskxl_le (scratch, scratch, mask, addr));
+ }
+ emit_insn (gen_iordi3 (scratch, scratch, val));
+
+ emit_store_conditional (DImode, scratch, mem, scratch);
+
+ x = gen_rtx_EQ (DImode, scratch, const0_rtx);
+ emit_unlikely_jump (x, label);
+}
+\f
+/* Adjust the cost of a scheduling dependency. Return the new cost of
+ a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
+
+static int
+alpha_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
+{
+ enum attr_type insn_type, dep_insn_type;
+
+ /* If the dependence is an anti-dependence, there is no cost. For an
+ output dependence, there is sometimes a cost, but it doesn't seem
+ worth handling those few cases. */
+ if (REG_NOTE_KIND (link) != 0)
+ return cost;
+
+ /* If we can't recognize the insns, we can't really do anything. */
+ if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
+ return cost;
+
+ insn_type = get_attr_type (insn);
+ dep_insn_type = get_attr_type (dep_insn);
+
+ /* Bring in the user-defined memory latency. */
+ if (dep_insn_type == TYPE_ILD
+ || dep_insn_type == TYPE_FLD
+ || dep_insn_type == TYPE_LDSYM)
+ cost += alpha_memory_latency-1;
+
+ /* Everything else handled in DFA bypasses now. */
+
+ return cost;
+}
+
+/* The number of instructions that can be issued per cycle. */
+
+static int
+alpha_issue_rate (void)
+{
+ return (alpha_tune == PROCESSOR_EV4 ? 2 : 4);
+}
+
+/* How many alternative schedules to try. This should be as wide as the
+ scheduling freedom in the DFA, but no wider. Making this value too
+ large results extra work for the scheduler.
+
+ For EV4, loads can be issued to either IB0 or IB1, thus we have 2
+ alternative schedules. For EV5, we can choose between E0/E1 and
+ FA/FM. For EV6, an arithmetic insn can be issued to U0/U1/L0/L1. */
+
+static int
+alpha_multipass_dfa_lookahead (void)
+{
+ return (alpha_tune == PROCESSOR_EV6 ? 4 : 2);
+}
+\f
+/* Machine-specific function data. */
+
+struct machine_function GTY(())
+{
+ /* For unicosmk. */
+ /* List of call information words for calls from this function. */
+ struct rtx_def *first_ciw;
+ struct rtx_def *last_ciw;
+ int ciw_count;
+
+ /* List of deferred case vectors. */
+ struct rtx_def *addr_list;
+
+ /* For OSF. */
+ const char *some_ld_name;
+
+ /* For TARGET_LD_BUGGY_LDGP. */
+ struct rtx_def *gp_save_rtx;
+};
+
+/* How to allocate a 'struct machine_function'. */
+
+static struct machine_function *
+alpha_init_machine_status (void)
+{
+ return ((struct machine_function *)
+ ggc_alloc_cleared (sizeof (struct machine_function)));
+}
+
+/* Functions to save and restore alpha_return_addr_rtx. */
+
+/* Start the ball rolling with RETURN_ADDR_RTX. */
+
+rtx
+alpha_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
+{
+ if (count != 0)
+ return const0_rtx;
+
+ return get_hard_reg_initial_val (Pmode, REG_RA);
+}
+
+/* Return or create a memory slot containing the gp value for the current
+ function. Needed only if TARGET_LD_BUGGY_LDGP. */
+
+rtx
+alpha_gp_save_rtx (void)
+{
+ rtx seq, m = cfun->machine->gp_save_rtx;
+
+ if (m == NULL)
+ {
+ start_sequence ();