Commit 82348675 by Sandra Loosemore Committed by Sandra Loosemore

nios2-protos.h (nios2_large_constant_p): Declare.

2017-10-23  Sandra Loosemore  <sandra@codesourcery.com>

	gcc/
	* config/nios2/nios2-protos.h (nios2_large_constant_p): Declare.
	(nios2_symbolic_memory_operand_p): Declare.
	(nios2_split_large_constant): Declare.
	(nios2_split_symbolic_memory_operand): Declare.
	* config/nios2/nios2.c: Adjust includes.
	(nios2_symbolic_constant_allowed): New.
	(nios2_symbolic_constant_p): New.
	(nios2_plus_symbolic_constant_p): New.
	(nios2_valid_addr_expr_p): Recognize addresses involving 
	symbolic constants.
	(nios2_legitimate_address_p): Likewise, also LO_SUM.
	(nios2_symbolic_memory_operand_p): New.
	(nios2_large_constant_p): New.
	(nios2_split_large_constant): New.
	(nios2_split_plus_large_constant): New.
	(nios2_split_symbolic_memory_operand): New.
	(nios2_legitimize_address): Code refactoring.  Handle addresses
	involving symbolic constants.
	(nios2_emit_move_sequence): Likewise.
	(nios2_print_operand): Improve error output.
	(nios2_print_operand_address): Handle LO_SUM.
	(nios2_cdx_narrow_form_p): Likewise.
	* config/nios2/nios2.md (movqi_internal): Add splitter for memory
	operands involving symbolic constants.
	(movhi_internal, movsi_internal): Likewise.
	(zero_extendhisi2, zero_extendqi<mode>2): Likewise.
	(extendhisi2, extendqi<mode>2): Likewise.

From-SVN: r254033
parent 6642bfb2
2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
* config/nios2/nios2-protos.h (nios2_large_constant_p): Declare.
(nios2_symbolic_memory_operand_p): Declare.
(nios2_split_large_constant): Declare.
(nios2_split_symbolic_memory_operand): Declare.
* config/nios2/nios2.c: Adjust includes.
(nios2_symbolic_constant_allowed): New.
(nios2_symbolic_constant_p): New.
(nios2_plus_symbolic_constant_p): New.
(nios2_valid_addr_expr_p): Recognize addresses involving
symbolic constants.
(nios2_legitimate_address_p): Likewise, also LO_SUM.
(nios2_symbolic_memory_operand_p): New.
(nios2_large_constant_p): New.
(nios2_split_large_constant): New.
(nios2_split_plus_large_constant): New.
(nios2_split_symbolic_memory_operand): New.
(nios2_legitimize_address): Code refactoring. Handle addresses
involving symbolic constants.
(nios2_emit_move_sequence): Likewise.
(nios2_print_operand): Improve error output.
(nios2_print_operand_address): Handle LO_SUM.
(nios2_cdx_narrow_form_p): Likewise.
* config/nios2/nios2.md (movqi_internal): Add splitter for memory
operands involving symbolic constants.
(movhi_internal, movsi_internal): Likewise.
(zero_extendhisi2, zero_extendqi<mode>2): Likewise.
(extendhisi2, extendqi<mode>2): Likewise.
2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
* tree-pass.h (PROP_rtl_split_insns): Define.
* recog.c (pass_data_split_all_insns): Provide PROP_rtl_split_insns.
......@@ -30,6 +30,11 @@ extern bool nios2_expand_return (void);
extern void nios2_function_profiler (FILE *, int);
#ifdef RTX_CODE
extern bool nios2_large_constant_p (rtx);
extern bool nios2_symbolic_memory_operand_p (rtx);
extern rtx nios2_split_large_constant (rtx, rtx);
extern rtx nios2_split_symbolic_memory_operand (rtx);
extern bool nios2_emit_move_sequence (rtx *, machine_mode);
extern void nios2_emit_expensive_div (rtx *, machine_mode);
extern void nios2_adjust_call_address (rtx *, rtx);
......
......@@ -48,11 +48,13 @@
#include "langhooks.h"
#include "stor-layout.h"
#include "builtins.h"
#include "tree-pass.h"
/* This file should be included last. */
#include "target-def.h"
/* Forward function declarations. */
static bool nios2_symbolic_constant_p (rtx);
static bool prologue_saved_reg_p (unsigned);
static void nios2_load_pic_register (void);
static void nios2_register_custom_code (unsigned int, enum nios2_ccs_code, int);
......@@ -1902,7 +1904,52 @@ nios2_validate_compare (machine_mode mode, rtx *cmp, rtx *op1, rtx *op2)
}
/* Addressing Modes. */
/* 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.
This function returns true if in a pre-split context where these
constants are allowed. */
static bool
nios2_symbolic_constant_allowed (void)
{
/* The reload_completed check is for the benefit of
nios2_asm_output_mi_thunk and perhaps other places that try to
emulate a post-reload pass. */
return !(cfun->curr_properties & PROP_rtl_split_insns) && !reload_completed;
}
/* Return true if X is constant expression with a reference to an
"ordinary" symbol; not GOT-relative, not GP-relative, not TLS. */
static bool
nios2_symbolic_constant_p (rtx x)
{
rtx base, offset;
if (flag_pic)
return false;
if (GET_CODE (x) == LABEL_REF)
return true;
else if (CONSTANT_P (x))
{
split_const (x, &base, &offset);
return (SYMBOL_REF_P (base)
&& !SYMBOL_REF_TLS_MODEL (base)
&& !gprel_constant_p (base)
&& SMALL_INT (INTVAL (offset)));
}
return false;
}
/* Return true if X is an expression of the form
(PLUS reg symbolic_constant). */
static bool
nios2_plus_symbolic_constant_p (rtx x)
{
return (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& nios2_symbolic_constant_p (XEXP (x, 1)));
}
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
static bool
......@@ -1971,6 +2018,8 @@ nios2_valid_addr_expr_p (rtx base, rtx offset, bool strict_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_symbolic_constant_p (offset))
|| nios2_unspec_reloc_p (offset)));
}
......@@ -1993,6 +2042,11 @@ nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
/* Else, fall through. */
case LABEL_REF:
if (nios2_symbolic_constant_allowed ()
&& nios2_symbolic_constant_p (operand))
return true;
/* Else, fall through. */
case CONST_INT:
case CONST_DOUBLE:
return false;
......@@ -2007,9 +2061,28 @@ nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
rtx op0 = XEXP (operand, 0);
rtx op1 = XEXP (operand, 1);
return (nios2_valid_addr_expr_p (op0, op1, strict_p)
|| nios2_valid_addr_expr_p (op1, op0, strict_p));
if (nios2_valid_addr_expr_p (op0, op1, strict_p)
|| nios2_valid_addr_expr_p (op1, op0, strict_p))
return true;
}
break;
/* %lo(constant)(reg)
This requires a 16-bit relocation and isn't valid with R2
io-variant load/stores. */
case LO_SUM:
if (TARGET_ARCH_R2
&& (TARGET_BYPASS_CACHE || TARGET_BYPASS_CACHE_VOLATILE))
return false;
else
{
rtx op0 = XEXP (operand, 0);
rtx op1 = XEXP (operand, 1);
return (REG_P (op0)
&& nios2_regno_ok_for_base_p (REGNO (op0), strict_p)
&& nios2_large_constant_p (op1));
}
default:
break;
......@@ -2017,6 +2090,75 @@ nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
return false;
}
/* Return true if X is a MEM whose address expression involves a symbolic
constant. */
bool
nios2_symbolic_memory_operand_p (rtx x)
{
rtx addr;
if (GET_CODE (x) != MEM)
return false;
addr = XEXP (x, 0);
return (nios2_symbolic_constant_p (addr)
|| nios2_plus_symbolic_constant_p (addr));
}
/* Return true if X is something that needs to be split into a
high/lo_sum pair. */
bool
nios2_large_constant_p (rtx x)
{
return (nios2_symbolic_constant_p (x)
|| nios2_large_unspec_reloc_p (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. */
rtx
nios2_split_large_constant (rtx x, rtx temp)
{
emit_insn (gen_rtx_SET (temp, gen_rtx_HIGH (Pmode, copy_rtx (x))));
return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (x));
}
/* Split an RTX of the form
(plus op0 op1)
where op1 is a large constant into
(set temp (high op1))
(set temp (plus op0 temp))
(lo_sum temp op1)
returning the lo_sum expression as the value. */
static rtx
nios2_split_plus_large_constant (rtx op0, rtx op1)
{
rtx temp = gen_reg_rtx (Pmode);
op0 = force_reg (Pmode, op0);
emit_insn (gen_rtx_SET (temp, gen_rtx_HIGH (Pmode, copy_rtx (op1))));
emit_insn (gen_rtx_SET (temp, gen_rtx_PLUS (Pmode, op0, temp)));
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. */
rtx
nios2_split_symbolic_memory_operand (rtx op)
{
rtx addr = XEXP (op, 0);
if (nios2_symbolic_constant_p (addr))
addr = nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
else if (nios2_plus_symbolic_constant_p (addr))
addr = nios2_split_plus_large_constant (XEXP (addr, 0), XEXP (addr, 1));
else
gcc_unreachable ();
return replace_equiv_address (op, addr, false);
}
/* Return true if SECTION is a small section name. */
static bool
nios2_small_section_name_p (const char *section)
......@@ -2219,6 +2361,9 @@ nios2_legitimize_constant_address (rtx addr)
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 ()
&& nios2_symbolic_constant_p (addr))
return nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
else
return addr;
......@@ -2239,9 +2384,27 @@ static rtx
nios2_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
machine_mode mode ATTRIBUTE_UNUSED)
{
rtx op0, op1;
if (CONSTANT_P (x))
return nios2_legitimize_constant_address (x);
/* Remaining cases all involve something + a constant. */
if (GET_CODE (x) != PLUS)
return x;
op0 = XEXP (x, 0);
op1 = XEXP (x, 1);
/* We may need to split symbolic constants now. */
if (nios2_symbolic_constant_p (op1))
{
if (nios2_symbolic_constant_allowed ())
return gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), copy_rtx (op1));
else
return nios2_split_plus_large_constant (op0, op1);
}
/* For the TLS LE (Local Exec) model, the compiler may try to
combine constant offsets with unspec relocs, creating address RTXs
looking like this:
......@@ -2264,20 +2427,19 @@ nios2_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
(const_int 48 [0x30])))] UNSPEC_ADD_TLS_LE)))
Which will be output as '%tls_le(var+48)(r23)' in assembly. */
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == CONST)
else if (GET_CODE (op1) == CONST)
{
rtx unspec, offset;
split_const (XEXP (x, 1), &unspec, &offset);
split_const (op1, &unspec, &offset);
if (GET_CODE (unspec) == UNSPEC
&& !nios2_large_offset_p (XINT (unspec, 1))
&& offset != const0_rtx)
{
rtx reg = force_reg (Pmode, XEXP (x, 0));
rtx reg = force_reg (Pmode, op0);
unspec = copy_rtx (unspec);
XVECEXP (unspec, 0, 0)
= plus_constant (Pmode, XVECEXP (unspec, 0, 0), INTVAL (offset));
x = gen_rtx_PLUS (Pmode, reg, gen_rtx_CONST (Pmode, unspec));
return gen_rtx_PLUS (Pmode, reg, gen_rtx_CONST (Pmode, unspec));
}
}
......@@ -2338,10 +2500,28 @@ nios2_emit_move_sequence (rtx *operands, machine_mode mode)
return true;
}
}
else if (!gprel_constant_p (from))
else if (gprel_constant_p (from))
/* Handled directly by movsi_internal as gp + offset. */
;
else if (nios2_large_constant_p (from))
/* This case covers either a regular symbol reference or an UNSPEC
representing a 32-bit offset. We split the former
only conditionally and the latter always. */
{
if (!nios2_large_unspec_reloc_p (from))
from = nios2_legitimize_constant_address (from);
if (!nios2_symbolic_constant_allowed ()
|| nios2_large_unspec_reloc_p (from))
{
rtx lo = nios2_split_large_constant (from, to);
emit_insn (gen_rtx_SET (to, lo));
set_unique_reg_note (get_last_insn (), REG_EQUAL,
copy_rtx (operands[1]));
return true;
}
}
else
/* This is a TLS or PIC symbol. */
{
from = nios2_legitimize_constant_address (from);
if (CONSTANT_P (from))
{
emit_insn (gen_rtx_SET (to,
......@@ -2652,6 +2832,7 @@ nios2_print_operand (FILE *file, rtx op, int letter)
break;
}
debug_rtx (op);
output_operand_lossage ("Unsupported operand for code '%c'", letter);
gcc_unreachable ();
}
......@@ -2757,6 +2938,20 @@ nios2_print_operand_address (FILE *file, machine_mode mode, rtx op)
}
break;
case LO_SUM:
{
rtx op0 = XEXP (op, 0);
rtx op1 = XEXP (op, 1);
if (REG_P (op0) && CONSTANT_P (op1))
{
nios2_print_operand (file, op1, 'L');
fprintf (file, "(%s)", reg_names[REGNO (op0)]);
return;
}
}
break;
case REG:
fprintf (file, "0(%s)", reg_names[REGNO (op)]);
return;
......@@ -4329,6 +4524,9 @@ nios2_cdx_narrow_form_p (rtx_insn *insn)
/* GP-based references are never narrow. */
if (gprel_constant_p (addr))
return false;
/* %lo requires a 16-bit relocation and is never narrow. */
if (GET_CODE (addr) == LO_SUM)
return false;
ret = split_mem_address (addr, &rhs1, &rhs2);
gcc_assert (ret);
}
......@@ -4373,6 +4571,9 @@ nios2_cdx_narrow_form_p (rtx_insn *insn)
/* GP-based references are never narrow. */
if (gprel_constant_p (addr))
return false;
/* %lo requires a 16-bit relocation and is never narrow. */
if (GET_CODE (addr) == LO_SUM)
return false;
ret = split_mem_address (addr, &rhs1, &rhs2);
gcc_assert (ret);
offset = INTVAL (rhs2);
......
......@@ -201,7 +201,7 @@
"addi\\t%0, %1, %L2"
[(set_attr "type" "alu")])
(define_insn "movqi_internal"
(define_insn_and_split "movqi_internal"
[(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r")
(match_operand:QI 1 "general_operand" "rM,m,rI"))]
"(register_operand (operands[0], QImode)
......@@ -224,20 +224,47 @@
gcc_unreachable ();
}
}
"(nios2_symbolic_memory_operand_p (operands[0])
|| nios2_symbolic_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]);
else
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
}
[(set_attr "type" "st,ld,mov")])
(define_insn "movhi_internal"
(define_insn_and_split "movhi_internal"
[(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r")
(match_operand:HI 1 "general_operand" "rM,m,rI"))]
"(register_operand (operands[0], HImode)
|| reg_or_0_operand (operands[1], HImode))"
"@
sth%o0%.\\t%z1, %0
ldhu%o1%.\\t%0, %1
mov%i1%.\\t%0, %z1"
{
switch (which_alternative)
{
case 0:
return "sth%o0%.\\t%z1, %0";
case 1:
return "ldhu%o1%.\\t%0, %1";
case 2:
return "mov%i1%.\\t%0, %z1";
default:
gcc_unreachable ();
}
}
"(nios2_symbolic_memory_operand_p (operands[0])
|| nios2_symbolic_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]);
else
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
}
[(set_attr "type" "st,ld,mov")])
(define_insn "movsi_internal"
(define_insn_and_split "movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r")
(match_operand:SI 1 "general_operand" "rM,m,rIJK,S"))]
"(register_operand (operands[0], SImode)
......@@ -269,6 +296,18 @@
gcc_unreachable ();
}
}
"(nios2_symbolic_memory_operand_p (operands[0])
|| nios2_symbolic_memory_operand_p (operands[1])
|| nios2_large_constant_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]);
else if (nios2_symbolic_memory_operand_p (operands[1]))
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
else
operands[1] = nios2_split_large_constant (operands[1], operands[0]);
}
[(set_attr "type" "st,ld,mov,alu")])
(define_mode_iterator BH [QI HI])
......@@ -318,42 +357,62 @@
(define_mode_iterator QX [HI SI])
;; Zero extension patterns
(define_insn "zero_extendhisi2"
(define_insn_and_split "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
""
"@
andi%.\\t%0, %1, 0xffff
ldhu%o1%.\\t%0, %1"
"nios2_symbolic_memory_operand_p (operands[1])"
[(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
{
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
}
[(set_attr "type" "and,ld")])
(define_insn "zero_extendqi<mode>2"
(define_insn_and_split "zero_extendqi<mode>2"
[(set (match_operand:QX 0 "register_operand" "=r,r")
(zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
""
"@
andi%.\\t%0, %1, 0xff
ldbu%o1%.\\t%0, %1"
"nios2_symbolic_memory_operand_p (operands[1])"
[(set (match_dup 0) (zero_extend:QX (match_dup 1)))]
{
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
}
[(set_attr "type" "and,ld")])
;; Sign extension patterns
(define_insn "extendhisi2"
(define_insn_and_split "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
""
"@
#
ldh%o1%.\\t%0, %1"
"nios2_symbolic_memory_operand_p (operands[1])"
[(set (match_dup 0) (sign_extend:SI (match_dup 1)))]
{
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
}
[(set_attr "type" "alu,ld")])
(define_insn "extendqi<mode>2"
(define_insn_and_split "extendqi<mode>2"
[(set (match_operand:QX 0 "register_operand" "=r,r")
(sign_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
""
"@
#
ldb%o1%.\\t%0, %1"
"nios2_symbolic_memory_operand_p (operands[1])"
[(set (match_dup 0) (sign_extend:QX (match_dup 1)))]
{
operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
}
[(set_attr "type" "alu,ld")])
;; Split patterns for register alternative cases.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment