+2001-09-09 Richard Henderson <rth@redhat.com>
+
+ * config/alpha/alpha.c (alpha_next_sequence_number): New.
+ (alpha_this_literal_sequence_number): New.
+ (alpha_this_gpdisp_sequence_number): New.
+ (some_operand, input_operand): Add HIGH.
+ (local_symbolic_operand): New.
+ (alpha_encode_section_info): New.
+ (alpha_legitimate_address_p): Allow LO_SUM.
+ (alpha_legitimize_address): Generate HIGH+LO_SUM.
+ (alpha_expand_mov): Likewise.
+ (secondary_reload_class): Check memory_operand not general_operand
+ for FP_REGS test.
+ (alpha_expand_unaligned_load): Force LO_SUM addresses into a register.
+ (alpha_expand_unaligned_store): Likewise.
+ (alpha_expand_unaligned_load_words): Likewise.
+ (alpha_expand_unaligned_store_words): Likewise.
+ (alpha_expand_block_clear): Likewise.
+ (print_operand): Handle %#, %*, %H.
+ (print_operand_address): Handle LO_SUM.
+ (find_lo_sum): New.
+ (alpha_does_function_need_gp): Use it.
+ (alpha_expand_block_move): Fix signed compare warnings.
+ (alpha_sa_mask, alpha_align_insns): Likewise.
+ * config/alpha/alpha-protos.h: Update.
+ * config/alpha/alpha.h (TARGET_EXPLICIT_RELOCS): New.
+ (MASK_EXPLICIT_RELOCS): New.
+ (TARGET_SWITCHES): Add -mexplicit-relocs.
+ (EXTRA_CONSTRAINT): Add 'T'.
+ (PREFERRED_RELOAD_CLASS): HIGH goes in GENERAL_REGS.
+ (ASM_APP_ON, ASM_APP_OFF): Turn on and off asm macro expansion.
+ (ENCODE_SECTION_INFO): Out line.
+ (REDO_SECTION_INFO_P): New.
+ (STRIP_NAME_ENCODING): New.
+ (ASM_OUTPUT_LABELREF): New.
+ (PRINT_OPERAND_PUNCT_VALID_P): Add #, *.
+ (PREDICATE_CODES): Update.
+ * config/alpha/alpha.md (divmodsi_internal_er, divmoddi_internal_er,
+ call_osf_1_er_noreturn, call_osf_1_er, movdi_er_low, movdi_er_nofix,
+ movdi_er_fix, prologue_ldgp_1_er, builtin_setjmp_receiver_sub_label_er,
+ builtin_setjmp_receiver_er, exception_receiver_1_er,
+ call_value_osf_1_er): New patterns.
+ (sibcall_osf_1, sibcall_value_osf_1): Remove register alternative.
+ (movqi, movhi, movsi): Add explicit $31 base register to lda.
+ * config/alpha/elf.h (ASM_FILE_START): Set nomacro if explicit relocs.
+ (FINAL_PRESCAN_INSN): New.
+
Sat Sep 8 22:00:55 CEST 2001 Jan Hubicka <jh@suse.cz>
* reg-stack.c (subst_stack_regs_pat): Fix fcmov reversal code.
extern int some_ni_operand PARAMS ((rtx, enum machine_mode));
extern int input_operand PARAMS ((rtx, enum machine_mode));
extern int current_file_function_operand PARAMS ((rtx, enum machine_mode));
+extern int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
extern int call_operand PARAMS ((rtx, enum machine_mode));
extern int alpha_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int alpha_zero_comparison_operator PARAMS ((rtx, enum machine_mode));
#endif
extern void alpha_start_function PARAMS ((FILE *, const char *, tree));
extern void alpha_end_function PARAMS ((FILE *, const char *, tree));
+extern void alpha_encode_section_info PARAMS ((tree));
#endif /* TREE CODE */
static const char *alpha_fnname;
+/* The next explicit relocation sequence number. */
+int alpha_next_sequence_number = 1;
+
+/* The literal and gpdisp sequence numbers for this insn, as printed
+ by %# and %* respectively. */
+int alpha_this_literal_sequence_number;
+int alpha_this_gpdisp_sequence_number;
+
/* Declarations of static functions. */
static void alpha_set_memflags_1
PARAMS ((rtx, int, int, int));
PARAMS ((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
static void alpha_sa_mask
PARAMS ((unsigned long *imaskP, unsigned long *fmaskP));
+static int find_lo_sum
+ PARAMS ((rtx *, void *));
static int alpha_does_function_need_gp
PARAMS ((void));
static int alpha_ra_ever_killed
switch (GET_CODE (op))
{
case REG: case MEM: case CONST_DOUBLE: case CONST_INT: case LABEL_REF:
- case SYMBOL_REF: case CONST:
+ case SYMBOL_REF: case CONST: case HIGH:
return 1;
case SUBREG:
case CONSTANT_P_RTX:
return 1;
+ case HIGH:
+ return (TARGET_EXPLICIT_RELOCS
+ && local_symbolic_operand (XEXP (op, 0), mode));
+
default:
break;
}
|| op == XEXP (DECL_RTL (current_function_decl), 0)));
}
+/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
+ known to be defined in this file. */
+
+int
+local_symbolic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ const char *str;
+
+ if (GET_CODE (op) == LABEL_REF)
+ return 1;
+
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+ op = XEXP (XEXP (op, 0), 0);
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+
+ str = XSTR (op, 0);
+
+ /* ??? SYMBOL_REF_FLAG is set for local function symbols, but we
+ run into problems with the rtl inliner in that the symbol was
+ once external, but is local after inlining, which results in
+ unrecognizable insns. */
+
+ return (CONSTANT_POOL_ADDRESS_P (op)
+ /* If @, then ENCODE_SECTION_INFO sez it's local. */
+ || str[0] == '@'
+ /* If *$, then ASM_GENERATE_INTERNAL_LABEL sez it's local. */
+ || (str[0] == '*' && str[1] == '$'));
+}
+
/* Return 1 if OP is a valid operand for the MEM of a CALL insn. */
int
return best_label ? best_label : const0_rtx;
}
\f
+/* If we are referencing a function that is static, make the SYMBOL_REF
+ special. We use this to see indicate we can branch to this function
+ without setting PV or restoring GP.
+
+ If this is a variable that is known to be defined locally, add "@v"
+ to the name. If in addition the variable is to go in .sdata/.sbss,
+ then add "@s" instead. */
+
+void
+alpha_encode_section_info (decl)
+ tree decl;
+{
+ const char *symbol_str;
+ bool is_local, is_small;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ if (! TREE_PUBLIC (decl))
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+ return;
+ }
+
+ /* Early out if we're not going to do anything with this data. */
+ if (! TARGET_EXPLICIT_RELOCS)
+ return;
+
+ /* Careful not to prod global register variables. */
+ if (TREE_CODE (decl) != VAR_DECL
+ || GET_CODE (DECL_RTL (decl)) != MEM
+ || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
+ return;
+
+ symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+
+ /* A variable is considered "local" if it is defined in this module. */
+
+ if (DECL_EXTERNAL (decl))
+ is_local = false;
+ /* Linkonce and weak data is never local. */
+ else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+ is_local = false;
+ else if (! TREE_PUBLIC (decl))
+ is_local = true;
+ /* If PIC, then assume that any global name can be overridden by
+ symbols resolved from other modules. */
+ else if (flag_pic)
+ is_local = false;
+ /* Uninitialized COMMON variable may be unified with symbols
+ resolved from other modules. */
+ else if (DECL_COMMON (decl)
+ && (DECL_INITIAL (decl) == NULL
+ || DECL_INITIAL (decl) == error_mark_node))
+ is_local = false;
+ /* Otherwise we're left with initialized (or non-common) global data
+ which is of necessity defined locally. */
+ else
+ is_local = true;
+
+ /* Determine if DECL will wind up in .sdata/.sbss. */
+
+ is_small = false;
+ if (DECL_SECTION_NAME (decl))
+ {
+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (strcmp (section, ".sdata") == 0
+ || strcmp (section, ".sbss") == 0)
+ is_small = true;
+ }
+ else
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+ /* If the variable has already been defined in the output file, then it
+ is too late to put it in sdata if it wasn't put there in the first
+ place. The test is here rather than above, because if it is already
+ in sdata, then it can stay there. */
+
+ if (TREE_ASM_WRITTEN (decl))
+ ;
+
+ /* If this is an incomplete type with size 0, then we can't put it in
+ sdata because it might be too big when completed. */
+ else if (size > 0 && size <= g_switch_value)
+ is_small = true;
+ }
+
+ /* Finally, encode this into the symbol string. */
+ if (is_local)
+ {
+ const char *string;
+ char *newstr;
+ size_t len;
+
+ if (symbol_str[0] == '@')
+ {
+ if (symbol_str[1] == (is_small ? 's' : 'v'))
+ return;
+ symbol_str += 2;
+ }
+
+ len = strlen (symbol_str) + 1;
+ newstr = alloca (len + 2);
+
+ newstr[0] = '@';
+ newstr[1] = (is_small ? 's' : 'v');
+ memcpy (newstr + 2, symbol_str, len);
+
+ string = ggc_alloc_string (newstr, len + 2 - 1);
+ XSTR (XEXP (DECL_RTL (decl), 0), 0) = string;
+ }
+ else if (symbol_str[0] == '@')
+ abort ();
+}
+
/* legitimate_address_p recognizes an RTL expression that is a valid
memory address for an instruction. The MODE argument is the
machine mode for the MEM expression that wants to use this address.
return true;
}
+ /* If we're managing explicit relocations, LO_SUM is valid. */
+ else if (TARGET_EXPLICIT_RELOCS && GET_CODE (x) == LO_SUM)
+ {
+ rtx ofs = XEXP (x, 1);
+ x = XEXP (x, 0);
+
+ /* Discard non-paradoxical subregs. */
+ if (GET_CODE (x) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ x = SUBREG_REG (x);
+
+ /* Must have a valid base register. */
+ if (! (REG_P (x)
+ && (strict
+ ? STRICT_REG_OK_FOR_BASE_P (x)
+ : NONSTRICT_REG_OK_FOR_BASE_P (x))))
+ return false;
+
+ /* The symbol must be local. */
+ if (local_symbolic_operand (ofs, Pmode))
+ return true;
+ }
+
return false;
}
goto split_addend;
}
+ /* If this is a local symbol, split the address into HIGH/LO_SUM parts. */
+ if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, Pmode))
+ {
+ rtx temp = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (Pmode, x)));
+ return gen_rtx_LO_SUM (Pmode, temp, x);
+ }
+
return NULL;
split_addend:
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
return GENERAL_REGS;
- if (in && INTEGRAL_MODE_P (mode) && ! general_operand (x, mode))
+ if (in && INTEGRAL_MODE_P (mode)
+ && ! (memory_operand (x, mode) || x == const0_rtx))
return GENERAL_REGS;
}
&& ! reg_or_0_operand (operands[1], mode))
operands[1] = force_reg (mode, operands[1]);
+ if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (operands[1], mode))
+ {
+ rtx scratch = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (VOIDmode, scratch,
+ gen_rtx_HIGH (Pmode, operands[1])));
+ operands[1] = gen_rtx_LO_SUM (Pmode, scratch, operands[1]);
+ return false;
+ }
+
/* Early out for non-constants and valid constants. */
if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode))
return false;
HOST_WIDE_INT size, ofs;
int sign;
{
- rtx meml, memh, addr, extl, exth, tmp;
+ rtx meml, memh, addr, extl, exth, tmp, mema;
enum machine_mode mode;
meml = gen_reg_rtx (DImode);
extl = gen_reg_rtx (DImode);
exth = gen_reg_rtx (DImode);
+ mema = XEXP (mem, 0);
+ if (GET_CODE (mema) == LO_SUM)
+ mema = force_reg (Pmode, mema);
+
/* AND addresses cannot be in any alias set, since they may implicitly
alias surrounding code. Ideally we'd have some alias set that
covered all types except those with alignment 8 or higher. */
tmp = change_address (mem, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (mem, 0), ofs),
+ plus_constant (mema, ofs),
GEN_INT (-8)));
set_mem_alias_set (tmp, 0);
emit_move_insn (meml, tmp);
tmp = change_address (mem, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (mem, 0),
- ofs + size - 1),
+ plus_constant (mema, ofs + size - 1),
GEN_INT (-8)));
set_mem_alias_set (tmp, 0);
emit_move_insn (memh, tmp);
if (sign && size == 2)
{
- emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs+2));
+ emit_move_insn (addr, plus_constant (mema, ofs+2));
emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
emit_insn (gen_extqh (exth, memh, addr));
}
else
{
- emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs));
+ emit_move_insn (addr, plus_constant (mema, ofs));
emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr));
switch ((int) size)
{
rtx dst, src;
HOST_WIDE_INT size, ofs;
{
- rtx dstl, dsth, addr, insl, insh, meml, memh;
+ rtx dstl, dsth, addr, insl, insh, meml, memh, dsta;
dstl = gen_reg_rtx (DImode);
dsth = gen_reg_rtx (DImode);
insl = gen_reg_rtx (DImode);
insh = gen_reg_rtx (DImode);
+ dsta = XEXP (dst, 0);
+ if (GET_CODE (dsta) == LO_SUM)
+ dsta = force_reg (Pmode, dsta);
+
/* AND addresses cannot be in any alias set, since they may implicitly
alias surrounding code. Ideally we'd have some alias set that
covered all types except those with alignment 8 or higher. */
meml = change_address (dst, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (dst, 0), ofs),
+ plus_constant (dsta, ofs),
GEN_INT (-8)));
set_mem_alias_set (meml, 0);
memh = change_address (dst, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (dst, 0),
- ofs+size-1),
+ plus_constant (dsta, ofs + size - 1),
GEN_INT (-8)));
set_mem_alias_set (memh, 0);
emit_move_insn (dsth, memh);
emit_move_insn (dstl, meml);
- addr = copy_addr_to_reg (plus_constant (XEXP (dst, 0), ofs));
+ addr = copy_addr_to_reg (plus_constant (dsta, ofs));
if (src != const0_rtx)
{
rtx const im8 = GEN_INT (-8);
rtx const i64 = GEN_INT (64);
rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1];
- rtx sreg, areg, tmp;
+ rtx sreg, areg, tmp, smema;
HOST_WIDE_INT i;
+ smema = XEXP (smem, 0);
+ if (GET_CODE (smema) == LO_SUM)
+ smema = force_reg (Pmode, smema);
+
/* Generate all the tmp registers we need. */
for (i = 0; i < words; ++i)
{
{
tmp = change_address (smem, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP(smem,0), 8*i),
+ plus_constant (smema, 8*i),
im8));
set_mem_alias_set (tmp, 0);
emit_move_insn (data_regs[i], tmp);
tmp = change_address (smem, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP(smem,0), 8*words - 1),
+ plus_constant (smema, 8*words - 1),
im8));
set_mem_alias_set (tmp, 0);
emit_move_insn (data_regs[words], tmp);
extxh with offset zero a noop instead of zeroing the register, so
we must take care of that edge condition ourselves with cmov. */
- sreg = copy_addr_to_reg (XEXP (smem, 0));
+ sreg = copy_addr_to_reg (smema);
areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL,
1, OPTAB_WIDEN);
for (i = 0; i < words; ++i)
#endif
rtx ins_tmps[MAX_MOVE_WORDS];
rtx st_tmp_1, st_tmp_2, dreg;
- rtx st_addr_1, st_addr_2;
+ rtx st_addr_1, st_addr_2, dmema;
HOST_WIDE_INT i;
+ dmema = XEXP (dmem, 0);
+ if (GET_CODE (dmema) == LO_SUM)
+ dmema = force_reg (Pmode, dmema);
+
/* Generate all the tmp registers we need. */
if (data_regs != NULL)
for (i = 0; i < words; ++i)
st_addr_2 = change_address (dmem, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP(dmem,0),
- words*8 - 1),
+ plus_constant (dmema, words*8 - 1),
im8));
set_mem_alias_set (st_addr_2, 0);
st_addr_1 = change_address (dmem, DImode,
- gen_rtx_AND (DImode,
- XEXP (dmem, 0),
- im8));
+ gen_rtx_AND (DImode, dmema, im8));
set_mem_alias_set (st_addr_1, 0);
/* Load up the destination end bits. */
emit_move_insn (st_tmp_1, st_addr_1);
/* Shift the input data into place. */
- dreg = copy_addr_to_reg (XEXP (dmem, 0));
+ dreg = copy_addr_to_reg (dmema);
if (data_regs != NULL)
{
for (i = words-1; i >= 0; --i)
{
rtx tmp = change_address (dmem, DImode,
gen_rtx_AND (DImode,
- plus_constant(XEXP (dmem,0), i*8),
+ plus_constant(dmema, i*8),
im8));
set_mem_alias_set (tmp, 0);
emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx);
rtx orig_dst = operands[0];
rtx data_regs[2 * MAX_MOVE_WORDS + 16];
rtx tmp;
- int i, words, ofs, nregs = 0;
+ unsigned int i, words, ofs, nregs = 0;
if (orig_bytes <= 0)
return 1;
words = bytes / 8;
for (i = 0; i < words; ++i)
- emit_move_insn (adjust_address(orig_dst, DImode, ofs + i * 8),
+ emit_move_insn (adjust_address (orig_dst, DImode, ofs + i * 8),
const0_rtx);
bytes -= words * 8;
if (align >= 32 && bytes > 16)
{
+ rtx orig_dsta;
+
emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx);
bytes -= 4;
ofs += 4;
+ orig_dsta = XEXP (orig_dst, 0);
+ if (GET_CODE (orig_dsta) == LO_SUM)
+ orig_dsta = force_reg (Pmode, orig_dsta);
+
words = bytes / 8;
for (i = 0; i < words; ++i)
{
rtx mem
= change_address (orig_dst, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs + i*8),
+ plus_constant (orig_dsta, ofs + i*8),
GEN_INT (-8)));
set_mem_alias_set (mem, 0);
emit_move_insn (mem, const0_rtx);
fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file);
break;
+ case '#':
+ if (alpha_this_literal_sequence_number == 0)
+ alpha_this_literal_sequence_number = alpha_next_sequence_number++;
+ fprintf (file, "%d", alpha_this_literal_sequence_number);
+ break;
+
+ case '*':
+ if (alpha_this_gpdisp_sequence_number == 0)
+ alpha_this_gpdisp_sequence_number = alpha_next_sequence_number++;
+ fprintf (file, "%d", alpha_this_gpdisp_sequence_number);
+ break;
+
+ case 'H':
+ if (GET_CODE (x) == HIGH)
+ {
+ output_addr_const (file, XEXP (x, 0));
+ fputs ("($29)\t\t!gprelhigh", file);
+ }
+ else
+ output_operand_lossage ("invalid %%H value");
+ break;
+
case 'r':
/* If this operand is the constant zero, write it as "$31". */
if (GET_CODE (x) == REG)
fprintf (file, "$31");
else
output_operand_lossage ("invalid %%r value");
-
break;
case 'R':
fprintf (file, "$f31");
else
output_operand_lossage ("invalid %%R value");
-
break;
case 'N':
offset = INTVAL (XEXP (addr, 1));
addr = XEXP (addr, 0);
}
+
+ if (GET_CODE (addr) == LO_SUM)
+ {
+ output_addr_const (file, XEXP (addr, 1));
+ if (offset)
+ {
+ fputc ('+', file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
+ }
+
+ addr = XEXP (addr, 0);
+ if (GET_CODE (addr) == REG)
+ basereg = REGNO (addr);
+ else if (GET_CODE (addr) == SUBREG
+ && GET_CODE (SUBREG_REG (addr)) == REG)
+ basereg = subreg_regno (addr);
+ else
+ abort ();
+ fprintf (file, "($%d)\t\t!gprellow", basereg);
+ return;
+ }
+
if (GET_CODE (addr) == REG)
basereg = REGNO (addr);
else if (GET_CODE (addr) == SUBREG
&& GET_CODE (SUBREG_REG (addr)) == REG)
- basereg = REGNO (SUBREG_REG (addr))
- + SUBREG_BYTE (addr) / GET_MODE_SIZE (GET_MODE (addr));
+ basereg = subreg_regno (addr);
else if (GET_CODE (addr) == CONST_INT)
offset = INTVAL (addr);
else
{
unsigned long imask = 0;
unsigned long fmask = 0;
- int i;
+ unsigned int i;
#ifdef ASM_OUTPUT_MI_THUNK
if (!current_function_is_thunk)
#endif
static int
+find_lo_sum (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return GET_CODE (*px) == LO_SUM;
+}
+
+static int
alpha_does_function_need_gp ()
{
rtx insn;
enum attr_type type = get_attr_type (insn);
if (type == TYPE_LDSYM || type == TYPE_JSR)
return 1;
+ if (TARGET_EXPLICIT_RELOCS
+ && for_each_rtx (&PATTERN (insn), find_lo_sum, NULL) > 0)
+ return 1;
}
return 0;
/* If the known alignment is smaller than the recognized insn group,
realign the output. */
- else if (align < len)
+ else if ((int) align < len)
{
unsigned int new_log_align = len > 8 ? 4 : 3;
rtx where;
can make use of the knowledge of what sorts of instructions
were issued in the previous group to make sure that all of
the added nops are really free. */
- else if (ofs + len > align)
+ else if (ofs + len > (int) align)
{
int nop_count = (align - ofs) / 4;
rtx where;
#define MASK_CIX (1 << 11)
#define TARGET_CIX (target_flags & MASK_CIX)
+/* This means use !literal style explicit relocations. */
+#define MASK_EXPLICIT_RELOCS (1 << 12)
+#define TARGET_EXPLICIT_RELOCS (target_flags & MASK_EXPLICIT_RELOCS)
+
/* This means that the processor is an EV5, EV56, or PCA56.
Unlike alpha_cpu this is not affected by -mtune= setting. */
#define MASK_CPU_EV5 (1 << 28)
{"no-fix", -MASK_FIX, ""}, \
{"cix", MASK_CIX, N_("Emit code for the counting ISA extension")}, \
{"no-cix", -MASK_CIX, ""}, \
+ {"explicit-relocs", MASK_EXPLICIT_RELOCS, \
+ N_("Emit code using explicit relocation directives")}, \
+ {"no-explicit-relocs", -MASK_EXPLICIT_RELOCS, ""}, \
{"", TARGET_DEFAULT | TARGET_CPU_DEFAULT, ""} }
#define TARGET_DEFAULT MASK_FP|MASK_FPREGS
: (C) == 'R' ? current_file_function_operand (OP, Pmode) \
: (C) == 'S' ? (GET_CODE (OP) == CONST_INT \
&& (unsigned HOST_WIDE_INT) INTVAL (OP) < 64) \
+ : (C) == 'T' ? GET_CODE (OP) == HIGH \
: 0)
/* Given an rtx X being reloaded into a reg required to be
register via memory. */
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
- (CONSTANT_P (X) && (X) != const0_rtx && (X) != CONST0_RTX (GET_MODE (X)) \
- ? ((CLASS) == FLOAT_REGS || (CLASS) == NO_REGS ? NO_REGS : GENERAL_REGS)\
+ (GET_CODE (X) == HIGH ? GENERAL_REGS \
+ : CONSTANT_P (X) && (X) != const0_rtx && (X) != CONST0_RTX (GET_MODE (X)) \
+ ? ((CLASS) == FLOAT_REGS || (CLASS) == NO_REGS ? NO_REGS : GENERAL_REGS) \
: (CLASS))
/* Loading and storing HImode or QImode values to and from memory
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
-
-#define ASM_APP_ON ""
+#define ASM_APP_ON (TARGET_EXPLICIT_RELOCS ? "\t.set\tmacro\n" : "")
/* Output to assembler file text saying following lines
no longer contain unusual constructs. */
-
-#define ASM_APP_OFF ""
+#define ASM_APP_OFF (TARGET_EXPLICIT_RELOCS ? "\t.set\tnomacro\n" : "")
#define TEXT_SECTION_ASM_OP "\t.text"
#define READONLY_DATA_SECTION literal_section
-/* If we are referencing a function that is static, make the SYMBOL_REF
- special. We use this to see indicate we can branch to this function
- without setting PV or restoring GP. */
+/* Define this macro if references to a symbol must be treated differently
+ depending on something about the variable or function named by the symbol
+ (such as what section it is in). */
+
+#define ENCODE_SECTION_INFO(DECL) alpha_encode_section_info (DECL)
+
+/* If a variable is weakened, made one only or moved into a different
+ section, it may be necessary to redo the section info to move the
+ variable out of sdata. */
+
+#define REDO_SECTION_INFO_P(DECL) \
+ ((TREE_CODE (DECL) == VAR_DECL) \
+ && (DECL_ONE_ONLY (DECL) || DECL_WEAK (DECL) || DECL_COMMON (DECL) \
+ || DECL_SECTION_NAME (DECL) != 0))
-#define ENCODE_SECTION_INFO(DECL) \
- if (TREE_CODE (DECL) == FUNCTION_DECL && ! TREE_PUBLIC (DECL)) \
- SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1;
+#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
+do { \
+ (VAR) = (SYMBOL_NAME); \
+ if ((VAR)[0] == '@') \
+ (VAR) += 2; \
+ if ((VAR)[0] == '*') \
+ (VAR)++; \
+} while (0)
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+/* Strip name encoding when emitting labels. */
+
+#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+do { \
+ const char *name_ = NAME; \
+ if (*name_ == '@') \
+ name_ += 2; \
+ if (*name_ == '*') \
+ name_++; \
+ else \
+ fputs (user_label_prefix, STREAM); \
+ fputs (name_, STREAM); \
+} while (0)
+
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
*/
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
- ((CODE) == '/' || (CODE) == ',' || (CODE) == '-' || (CODE) == '~')
+ ((CODE) == '/' || (CODE) == ',' || (CODE) == '-' || (CODE) == '~' \
+ || (CODE) == '#' || (CODE) == '*')
\f
/* Print a memory address as an operand to reference that memory location. */
{"divmod_operator", {DIV, MOD, UDIV, UMOD}}, \
{"fp0_operand", {CONST_DOUBLE}}, \
{"current_file_function_operand", {SYMBOL_REF}}, \
+ {"local_symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \
{"call_operand", {REG, SYMBOL_REF}}, \
{"input_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
- SYMBOL_REF, CONST, LABEL_REF}}, \
+ SYMBOL_REF, CONST, LABEL_REF, HIGH, LO_SUM}}, \
{"some_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
- SYMBOL_REF, CONST, LABEL_REF}}, \
+ SYMBOL_REF, CONST, LABEL_REF, HIGH, LO_SUM}}, \
{"some_ni_operand", {SUBREG, REG, MEM}}, \
{"aligned_memory_operand", {MEM}}, \
{"unaligned_memory_operand", {MEM}}, \
;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as
;; expanded by the assembler.
+
+(define_insn "*divmodsi_internal_er"
+ [(set (reg:DI 27)
+ (sign_extend:DI (match_operator:SI 0 "divmod_operator"
+ [(reg:DI 24) (reg:DI 25)])))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS"
+ "ldq $27,__%E0($29)\t\t!literal!%#\;jsr $23,($27),__%E0\t\t!lituse_jsr!%#"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "8")])
+
(define_insn "*divmodsi_internal"
[(set (reg:DI 27)
(sign_extend:DI (match_operator:SI 0 "divmod_operator"
[(set_attr "type" "jsr")
(set_attr "length" "8")])
+(define_insn "*divmoddi_internal_er"
+ [(set (reg:DI 27)
+ (match_operator:DI 0 "divmod_operator"
+ [(reg:DI 24) (reg:DI 25)]))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS"
+ "ldq $27,__%E0($29)\t\t!literal!%#\;jsr $23,($27),__%E0\t\t!lituse_jsr!%#"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "8")])
+
(define_insn "*divmoddi_internal"
[(set (reg:DI 27)
(match_operator:DI 0 "divmod_operator"
}
})
+(define_insn "*call_osf_1_er_noreturn"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,i"))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 27))
+ (clobber (reg:DI 26))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ "@
+ jsr $26,($27),0
+ bsr $26,$%0..ng
+ ldq $27,%0($29)\t\t!literal!%#\;jsr $26,($27),%0\t\t!lituse_jsr!%#"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,*,8")])
+
+(define_insn "*call_osf_1_er"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,i"))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 27))
+ (clobber (reg:DI 26))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ jsr $26,($27),0\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*
+ bsr $26,$%0..ng
+ ldq $27,%0($29)\t\t!literal!%#\;jsr $26,($27),%0\t\t!lituse_jsr!%#\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,*,16")])
+
(define_insn "*call_osf_1_noreturn"
[(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,i"))
(match_operand 1 "" ""))
(set_attr "length" "12,*,16")])
(define_insn "*sibcall_osf_1"
- [(call (mem:DI (match_operand:DI 0 "call_operand" "R,i"))
+ [(call (mem:DI (match_operand:DI 0 "current_file_function_operand" "R"))
(match_operand 1 "" ""))]
"TARGET_ABI_OSF"
- "@
- br $31,$%0..ng
- jmp $31,%0"
- [(set_attr "type" "jsr")
- (set_attr "length" "*,8")])
+ "br $31,$%0..ng"
+ [(set_attr "type" "jsr")])
(define_insn "*call_nt_1"
[(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,i"))
|| reg_or_0_operand (operands[1], SImode))"
"@
mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ lda %0,%1($31)
+ ldah %0,%h1($31)
ldl %0,%1
stl %r1,%0
fmov %R1,%0
|| reg_or_0_operand (operands[1], SImode))"
"@
mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ lda %0,%1($31)
+ ldah %0,%h1($31)
ldl %0,%1
stl %r1,%0
fmov %R1,%0
|| register_operand (operands[1], HImode))"
"@
mov %r1,%0
- lda %0,%L1"
+ lda %0,%L1($31)"
[(set_attr "type" "ilog,iadd")])
(define_insn "*movhi_bwx"
|| reg_or_0_operand (operands[1], HImode))"
"@
mov %r1,%0
- lda %0,%L1
+ lda %0,%L1($31)
ldwu %0,%1
stw %r1,%0"
[(set_attr "type" "ilog,iadd,ild,ist")])
|| register_operand (operands[1], QImode))"
"@
mov %r1,%0
- lda %0,%L1"
+ lda %0,%L1($31)"
[(set_attr "type" "ilog,iadd")])
(define_insn "*movqi_bwx"
|| reg_or_0_operand (operands[1], QImode))"
"@
mov %r1,%0
- lda %0,%L1
+ lda %0,%L1($31)
ldbu %0,%1
stb %r1,%0"
[(set_attr "type" "ilog,iadd,ild,ist")])
FAIL;
})
+(define_insn "*movdi_er_low"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "local_symbolic_operand" "")))]
+ "TARGET_EXPLICIT_RELOCS"
+ "lda %0,%2(%1)\t\t!gprellow")
+
+(define_insn "*movdi_er_nofix"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,m,rJ,*fJ,Q,*f"))]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
+ && (register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))
+ && ! local_symbolic_operand (operands[1], DImode)"
+ "@
+ mov %r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
+ ldah %0,%H1
+ ldq %0,%1($29)\t\t!literal
+ ldq%A1 %0,%1
+ stq%A0 %r1,%0
+ fmov %R1,%0
+ ldt %0,%1
+ stt %R1,%0"
+ [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
+
(define_insn "*movdi_nofix"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q")
(match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f"))]
- "! TARGET_FIX
+ "! TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
"@
mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ lda %0,%1($31)
+ ldah %0,%h1($31)
lda %0,%1
ldq%A1 %0,%1
stq%A0 %r1,%0
stt %R1,%0"
[(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
+(define_insn "*movdi_er_fix"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,m,rJ,*fJ,Q,*f,*f,r"))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_FIX
+ && (register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))
+ && ! local_symbolic_operand (operands[1], DImode)"
+ "@
+ mov %r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
+ ldah %0,%H1
+ ldq %0,%1($29)\t\t!literal
+ ldq%A1 %0,%1
+ stq%A0 %r1,%0
+ fmov %R1,%0
+ ldt %0,%1
+ stt %R1,%0
+ ftoit %1,%0
+ itoft %1,%0"
+ [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")])
+
(define_insn "*movdi_fix"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q,r,*f")
(match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f,*f,r"))]
- "TARGET_FIX
+ "! TARGET_EXPLICIT_RELOCS && TARGET_FIX
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
"@
mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ lda %0,%1($31)
+ ldah %0,%h1($31)
lda %0,%1
ldq%A1 %0,%1
stq%A0 %r1,%0
""
"")
+(define_insn "*prologue_ldgp_1_er"
+ [(unspec_volatile [(const_int 0)] UNSPECV_LDGP1)]
+ "TARGET_EXPLICIT_RELOCS"
+ "ldah $29,0($27)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*\n$%~..ng:")
+
(define_insn "*prologue_ldgp_1"
[(unspec_volatile [(const_int 0)] UNSPECV_LDGP1)]
""
"jmp $31,(%0),0"
[(set_attr "type" "ibr")])
+(define_insn "*builtin_setjmp_receiver_sub_label_er"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && TARGET_AS_CAN_SUBTRACT_LABELS"
+ "\n$LSJ%=:\;ldah $29,0($27)\t\t!gpdisp!%*\;lda $29,$LSJ%=-%l0($29)\t\t!gpdisp!%*"
+ [(set_attr "length" "8")
+ (set_attr "type" "multi")])
+
(define_insn "*builtin_setjmp_receiver_sub_label"
[(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
"TARGET_ABI_OSF && TARGET_AS_CAN_SUBTRACT_LABELS"
[(set_attr "length" "8")
(set_attr "type" "multi")])
+(define_insn "*builtin_setjmp_receiver_er"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "br $29,$LSJ%=\n$LSJ%=:\;ldah $29,0($29)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"
+ [(set_attr "length" "12")
+ (set_attr "type" "multi")])
+
(define_insn "builtin_setjmp_receiver"
[(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
"TARGET_ABI_OSF"
operands[0] = const0_rtx;
})
+(define_insn "*exception_receiver_1_er"
+ [(unspec_volatile [(const_int 0)] UNSPECV_EHR)]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_LD_BUGGY_LDGP"
+ "ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"
+ [(set_attr "length" "8")
+ (set_attr "type" "multi")])
+
(define_insn "*exception_receiver_1"
[(unspec_volatile [(const_int 0)] UNSPECV_EHR)]
"! TARGET_LD_BUGGY_LDGP"
;; The call patterns are at the end of the file because their
;; wildcard operand0 interferes with nice recognition.
+(define_insn "*call_value_osf_1_er"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,i"))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 27))
+ (clobber (reg:DI 26))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ jsr $26,($27),0\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*
+ bsr $26,$%1..ng
+ ldq $27,%1($29)\t\t!literal!%#\;jsr $26,($27),%1\t\t!lituse_jsr!%#\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,*,16")])
+
(define_insn "*call_value_osf_1"
[(set (match_operand 0 "" "")
(call (mem:DI (match_operand:DI 1 "call_operand" "c,R,i"))
(define_insn "*sibcall_value_osf_1"
[(set (match_operand 0 "" "")
- (call (mem:DI (match_operand:DI 1 "call_operand" "R,i"))
+ (call (mem:DI (match_operand:DI 1 "current_file_function_operand" "R"))
(match_operand 2 "" "")))]
"TARGET_ABI_OSF"
- "@
- br $31,$%1..ng
- jmp $31,%1"
- [(set_attr "type" "jsr")
- (set_attr "length" "*,8")])
+ "br $31,$%1..ng"
+ [(set_attr "type" "jsr")])
(define_insn "*call_value_nt_1"
[(set (match_operand 0 "" "")
} \
fprintf (FILE, "\t.set noat\n"); \
fprintf (FILE, "\t.set noreorder\n"); \
+ if (TARGET_EXPLICIT_RELOCS) \
+ fprintf (FILE, "\t.set nomacro\n"); \
if (TARGET_BWX | TARGET_MAX | TARGET_FIX | TARGET_CIX) \
{ \
fprintf (FILE, "\t.arch %s\n", \
only EH sections. */
#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
(((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4)
+
+/* If defined, a C statement to be executed just prior to the output of
+ assembler code for INSN. */
+#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \
+ (alpha_this_literal_sequence_number = 0, \
+ alpha_this_gpdisp_sequence_number = 0)
+extern int alpha_this_literal_sequence_number;
+extern int alpha_this_gpdisp_sequence_number;