From 82348675ee7757f2ef28e3e1350fd2bbd9994ad9 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Mon, 23 Oct 2017 22:35:50 -0400 Subject: [PATCH] nios2-protos.h (nios2_large_constant_p): Declare. 2017-10-23 Sandra Loosemore 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_extendqi2): Likewise. (extendhisi2, extendqi2): Likewise. From-SVN: r254033 --- gcc/ChangeLog | 30 ++++++ gcc/config/nios2/nios2-protos.h | 5 + gcc/config/nios2/nios2.c | 223 ++++++++++++++++++++++++++++++++++++++-- gcc/config/nios2/nios2.md | 81 +++++++++++++-- 4 files changed, 317 insertions(+), 22 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 77d651e..f214c8a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,35 @@ 2017-10-23 Sandra Loosemore + * 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_extendqi2): Likewise. + (extendhisi2, extendqi2): Likewise. + +2017-10-23 Sandra Loosemore + * tree-pass.h (PROP_rtl_split_insns): Define. * recog.c (pass_data_split_all_insns): Provide PROP_rtl_split_insns. diff --git a/gcc/config/nios2/nios2-protos.h b/gcc/config/nios2/nios2-protos.h index 4478334..6df65bb 100644 --- a/gcc/config/nios2/nios2-protos.h +++ b/gcc/config/nios2/nios2-protos.h @@ -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); diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c index 659250a..af1cceb 100644 --- a/gcc/config/nios2/nios2.c +++ b/gcc/config/nios2/nios2.c @@ -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); diff --git a/gcc/config/nios2/nios2.md b/gcc/config/nios2/nios2.md index 206ebce..ef2883f 100644 --- a/gcc/config/nios2/nios2.md +++ b/gcc/config/nios2/nios2.md @@ -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_extendqi2" +(define_insn_and_split "zero_extendqi2" [(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 "extendqi2" +(define_insn_and_split "extendqi2" [(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. -- 2.7.4