/* Addressing modes and constants. */
-/* Symbolic constants are split into high/lo_sum pairs during the
- split1 pass. After that, they are not considered legitimate addresses.
+/* Symbol references and other 32-bit constants are split into
+ high/lo_sum pairs during the split1 pass. After that, they are not
+ considered legitimate addresses.
This function returns true if in a pre-split context where these
constants are allowed. */
static bool
-nios2_symbolic_constant_allowed (void)
+nios2_large_constant_allowed (void)
{
/* The reload_completed check is for the benefit of
nios2_asm_output_mi_thunk and perhaps other places that try to
}
/* Return true if X is an expression of the form
- (PLUS reg symbolic_constant). */
+ (PLUS reg large_constant). */
static bool
-nios2_plus_symbolic_constant_p (rtx x)
+nios2_plus_large_constant_p (rtx x)
{
return (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
- && nios2_symbolic_constant_p (XEXP (x, 1)));
+ && nios2_large_constant_p (XEXP (x, 1)));
}
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
&& nios2_regno_ok_for_base_p (REGNO (base), strict_p)
&& (offset == NULL_RTX
|| nios2_valid_addr_offset_p (offset)
- || (nios2_symbolic_constant_allowed ()
+ || (nios2_large_constant_allowed ()
&& nios2_symbolic_constant_p (offset))
|| nios2_unspec_reloc_p (offset)));
}
/* Else, fall through. */
case LABEL_REF:
- if (nios2_symbolic_constant_allowed ()
+ if (nios2_large_constant_allowed ()
&& nios2_symbolic_constant_p (operand))
return true;
+ return false;
- /* Else, fall through. */
case CONST_INT:
+ if (r0rel_constant_p (operand))
+ return true;
+ return nios2_large_constant_allowed ();
+
case CONST_DOUBLE:
return false;
addr_space_t as ATTRIBUTE_UNUSED,
bool speed ATTRIBUTE_UNUSED)
{
- if (nios2_plus_symbolic_constant_p (address))
+ if (nios2_plus_large_constant_p (address))
return COSTS_N_INSNS (1);
- if (nios2_symbolic_constant_p (address))
+ if (nios2_large_constant_p (address))
{
if (GET_CODE (address) == CONST)
return COSTS_N_INSNS (1);
return COSTS_N_INSNS (0);
}
-/* Return true if X is a MEM whose address expression involves a symbolic
+/* Return true if X is a MEM whose address expression involves a large (32-bit)
constant. */
bool
-nios2_symbolic_memory_operand_p (rtx x)
+nios2_large_constant_memory_operand_p (rtx x)
{
rtx addr;
return false;
addr = XEXP (x, 0);
- return (nios2_symbolic_constant_p (addr)
- || nios2_plus_symbolic_constant_p (addr));
+ return (nios2_large_constant_p (addr)
+ || nios2_plus_large_constant_p (addr));
}
nios2_large_constant_p (rtx x)
{
return (nios2_symbolic_constant_p (x)
- || nios2_large_unspec_reloc_p (x));
+ || nios2_large_unspec_reloc_p (x)
+ || (CONST_INT_P (x) && !SMALL_INT (INTVAL (x))));
}
/* Given an RTX X that satisfies nios2_large_constant_p, split it into
high and lo_sum parts using TEMP as a scratch register. Emit the high
- instruction and return the lo_sum expression. */
+ instruction and return the lo_sum expression.
+ Also handle special cases involving constant integers. */
rtx
nios2_split_large_constant (rtx x, rtx temp)
{
+ if (CONST_INT_P (x))
+ {
+ HOST_WIDE_INT val = INTVAL (x);
+ if (SMALL_INT (val))
+ return x;
+ else if (SMALL_INT_UNSIGNED (val) || UPPER16_INT (val))
+ {
+ emit_move_insn (temp, x);
+ return temp;
+ }
+ else
+ {
+ HOST_WIDE_INT high = (val + 0x8000) & ~0xffff;
+ HOST_WIDE_INT low = val - high;
+ emit_move_insn (temp, gen_int_mode (high, Pmode));
+ return gen_rtx_PLUS (Pmode, temp, gen_int_mode (low, Pmode));
+ }
+ }
+
emit_insn (gen_rtx_SET (temp, gen_rtx_HIGH (Pmode, copy_rtx (x))));
return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (x));
}
return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (op1));
}
-/* Given a MEM OP with an address that includes a splittable symbol,
- emit some instructions to do the split and return a new MEM. */
+/* Given a MEM OP with an address that includes a splittable symbol or
+ other large constant, emit some instructions to do the split and
+ return a new MEM. */
rtx
-nios2_split_symbolic_memory_operand (rtx op)
+nios2_split_large_constant_memory_operand (rtx op)
{
rtx addr = XEXP (op, 0);
- if (nios2_symbolic_constant_p (addr))
+ if (nios2_large_constant_p (addr))
addr = nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
- else if (nios2_plus_symbolic_constant_p (addr))
+ else if (nios2_plus_large_constant_p (addr))
addr = nios2_split_plus_large_constant (XEXP (addr, 0), XEXP (addr, 1));
else
gcc_unreachable ();
base = nios2_legitimize_tls_address (base);
else if (flag_pic)
base = nios2_load_pic_address (base, UNSPEC_PIC_SYM, NULL_RTX);
- else if (!nios2_symbolic_constant_allowed ()
+ else if (!nios2_large_constant_allowed ()
&& nios2_symbolic_constant_p (addr))
return nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
+ else if (CONST_INT_P (addr))
+ {
+ HOST_WIDE_INT val = INTVAL (addr);
+ if (SMALL_INT (val))
+ /* Use r0-relative addressing. */
+ return addr;
+ else if (!nios2_large_constant_allowed ())
+ /* Split into high/lo pair. */
+ return nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
+ }
else
return addr;
/* We may need to split symbolic constants now. */
else if (nios2_symbolic_constant_p (op1))
{
- if (nios2_symbolic_constant_allowed ())
+ if (nios2_large_constant_allowed ())
return gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), copy_rtx (op1));
else
return nios2_split_plus_large_constant (op0, op1);
representing a 32-bit offset. We split the former
only conditionally and the latter always. */
{
- if (!nios2_symbolic_constant_allowed ()
+ if (!nios2_large_constant_allowed ()
|| nios2_large_unspec_reloc_p (from))
{
rtx lo = nios2_split_large_constant (from, to);
else if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS)
return r0rel_constant_p (XEXP (XEXP (op, 0), 0));
+ else if (GET_CODE (op) == CONST_INT
+ && SMALL_INT (INTVAL (op)))
+ return true;
return false;
}
}
else if (r0rel_constant_p (op))
{
- fprintf (file, "%%lo(");
- output_addr_const (file, op);
- fprintf (file, ")(r0)");
- return;
- }
+ if (CONST_INT_P (op))
+ {
+ output_addr_const (file, op);
+ fprintf (file, "(r0)");
+ return;
+ }
+ else
+ {
+ fprintf (file, "%%lo(");
+ output_addr_const (file, op);
+ fprintf (file, ")(r0)");
+ return;
+ }
+ }
break;
case PLUS:
gcc_unreachable ();
}
}
- "(nios2_symbolic_memory_operand_p (operands[0])
- || nios2_symbolic_memory_operand_p (operands[1]))"
+ "(nios2_large_constant_memory_operand_p (operands[0])
+ || nios2_large_constant_memory_operand_p (operands[1]))"
[(set (match_dup 0) (match_dup 1))]
{
- if (nios2_symbolic_memory_operand_p (operands[0]))
- operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+ if (nios2_large_constant_memory_operand_p (operands[0]))
+ operands[0] = nios2_split_large_constant_memory_operand (operands[0]);
else
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
}
[(set_attr "type" "st,ld,mov")])
gcc_unreachable ();
}
}
- "(nios2_symbolic_memory_operand_p (operands[0])
- || nios2_symbolic_memory_operand_p (operands[1]))"
+ "(nios2_large_constant_memory_operand_p (operands[0])
+ || nios2_large_constant_memory_operand_p (operands[1]))"
[(set (match_dup 0) (match_dup 1))]
{
- if (nios2_symbolic_memory_operand_p (operands[0]))
- operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+ if (nios2_large_constant_memory_operand_p (operands[0]))
+ operands[0] = nios2_split_large_constant_memory_operand (operands[0]);
else
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
}
[(set_attr "type" "st,ld,mov")])
gcc_unreachable ();
}
}
- "(nios2_symbolic_memory_operand_p (operands[0])
- || nios2_symbolic_memory_operand_p (operands[1])
- || nios2_large_constant_p (operands[1]))"
+ "(nios2_large_constant_memory_operand_p (operands[0])
+ || nios2_large_constant_memory_operand_p (operands[1])
+ || (nios2_large_constant_p (operands[1])
+ && !SMALL_INT_UNSIGNED (INTVAL (operands[1]))
+ && !UPPER16_INT (INTVAL (operands[1]))))"
[(set (match_dup 0) (match_dup 1))]
{
- if (nios2_symbolic_memory_operand_p (operands[0]))
- operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
- else if (nios2_symbolic_memory_operand_p (operands[1]))
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ if (nios2_large_constant_memory_operand_p (operands[0]))
+ operands[0] = nios2_split_large_constant_memory_operand (operands[0]);
+ else if (nios2_large_constant_memory_operand_p (operands[1]))
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
else
operands[1] = nios2_split_large_constant (operands[1], operands[0]);
}
"@
andi%.\\t%0, %1, 0xffff
ldhu%o1%.\\t%0, %1"
- "nios2_symbolic_memory_operand_p (operands[1])"
+ "nios2_large_constant_memory_operand_p (operands[1])"
[(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
{
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
}
[(set_attr "type" "and,ld")])
"@
andi%.\\t%0, %1, 0xff
ldbu%o1%.\\t%0, %1"
- "nios2_symbolic_memory_operand_p (operands[1])"
+ "nios2_large_constant_memory_operand_p (operands[1])"
[(set (match_dup 0) (zero_extend:QX (match_dup 1)))]
{
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
}
[(set_attr "type" "and,ld")])
"@
#
ldh%o1%.\\t%0, %1"
- "nios2_symbolic_memory_operand_p (operands[1])"
+ "nios2_large_constant_memory_operand_p (operands[1])"
[(set (match_dup 0) (sign_extend:SI (match_dup 1)))]
{
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
}
[(set_attr "type" "alu,ld")])
"@
#
ldb%o1%.\\t%0, %1"
- "nios2_symbolic_memory_operand_p (operands[1])"
+ "nios2_large_constant_memory_operand_p (operands[1])"
[(set (match_dup 0) (sign_extend:QX (match_dup 1)))]
{
- operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
}
[(set_attr "type" "alu,ld")])