From 3bbbe009de4f810f7240eae51e45d861582ecf79 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Tue, 14 Jul 2015 18:56:45 -0400 Subject: [PATCH] nios2.h (LABEL_ALIGN): Define. 2015-07-14 Sandra Loosemore Cesar Philippidis Chung-Lin Tang gcc/ * config/nios2/nios2.h (LABEL_ALIGN): Define. (REG_ALLOC_ORDER): Define. (ADJUST_REG_ALLOC_ORDER): Define. (HONOR_REG_ALLOC_ORDER): Define. (CDX_REG_P): Define. (ANDCLEAR_INT): Define. * config/nios2/nios2-protos.h (nios2_add_insn_asm): Declare. (nios2_label_align): Declare. (nios2_cdx_narrow_form_p): Declare. (nios2_adjust_reg_alloc_order): Declare. * config/nios2/nios2.c (nios2_rtx_costs): Adjust for BMX zero-extract operation. (nios2_large_unspec_reloc_p): New function, split from... (nios2_legitimate_pic_operand_p): ...here. (nios2_emit_move_sequence): Add *high/*lo_sum constant expand code. (nios2_print_operand_punct_valid_p): New. (nios2_print_operand): Add %., %!, %x, %y, %A. Remove %U. (split_mem_address): New. (split_alu_insn): New. (cdxreg): New. (cdx_add_immed, cdx_and_immed, cdx_mov_immed, cdx_shift_immed): New. (enum nios2_add_insn_kind): New. (nios2_add_insn_names, nios2_add_insn_narrow): New. (nios2_add_insn_classify): New. (nios2_add_insn_asm): New. (nios2_cdx_narrow_form_p): New. (label_align, min_labelno, max_labelno): New. (nios2_reorg): New. (nios2_label_align): New. (nios2_adjust_reg_alloc_order): New. (TARGET_PRINT_OPERAND_PUNCT_VALID_P): Define. (TARGET_MACHINE_DEPENDENT_REORG): Define. * config/nios2/constraints.md (P): New constraint. * config/nios2/predicates.md (const_and_operand): New. (and_operand): New. (stack_memory_operand): New. * config/nios2/nios2.md (SP_REGNO): Define stack pointer regno. (length): Update to use nios2_cdx_narrow_form_p(). (type): Add new insn type values. (control, alu, st, ld, shift): Update insn reservations with new insn type values. (*high, *lo_sum): Define new insn patterns for constant generation. (movqi_internal, movhi_internal, movsi_internal): Reduce alternatives, update asm template to handle CDX variants, update type attributes. (zero_extendhisi2, zero_extendqi2): Add CDX variants to asm template, update type attributes. (extendhisi2, extendqi2): Likewise. (addsi3): Change to use function for asm string. (subsi3): Add CDX notation to asm template, update type attributes. (negsi3, one_cmplsi3): Likewise. (andsi3): New pattern, specialized from logical patterns. (si3): Remove and case, combine alternatives, update asm template. (si3): Add CDX notation, update type attributes. (rotrsi3): Update type attribute. (*merge, extzv, insv): New insn patterns. (return): Change to define_expand. (simple_return): Add CDX notation, update type attributes. (indirect_jump): Add CDX notation. (jump): Update asm cases, update length attribute expression. (*call, *call_value, *sibcall, *sibcall_value): Add CDX variant. (nios2_cbranch): Update asm cases and length attribute expression to handle CDX variants. (nios2_cmp): Update asm template. (nop): Add CDX notation, update type attributes. (trap): Add CDX notation. (ctrapsi4): Update asm cases and length attribute expression to handle CDX variant. * doc/md.texi (Machine Constraints): Document P constraint. gcc/testsuite/ * gcc.target/nios2/andci.c: New. * gcc.target/nios2/bmx.c: New. * gcc.target/nios2/cdx-add.c: New. * gcc.target/nios2/cdx-branch.c: New. * gcc.target/nios2/cdx-callret.c: New. * gcc.target/nios2/cdx-loadstore.c: New. * gcc.target/nios2/cdx-logical.c: New. * gcc.target/nios2/cdx-mov.c: New. * gcc.target/nios2/cdx-shift.c: New. * gcc.target/nios2/cdx-sub.c: New. * gcc.target/nios2/nios2-trap-insn.c: Adjust pattern. Co-Authored-By: Cesar Philippidis Co-Authored-By: Chung-Lin Tang From-SVN: r225796 --- gcc/ChangeLog | 75 ++ gcc/config/nios2/constraints.md | 8 +- gcc/config/nios2/nios2-protos.h | 6 + gcc/config/nios2/nios2.c | 717 +++++++++++++++++- gcc/config/nios2/nios2.h | 21 + gcc/config/nios2/nios2.md | 325 +++++--- gcc/config/nios2/predicates.md | 20 + gcc/doc/md.texi | 3 + gcc/testsuite/ChangeLog | 16 + gcc/testsuite/gcc.target/nios2/andci.c | 18 + gcc/testsuite/gcc.target/nios2/bmx.c | 29 + gcc/testsuite/gcc.target/nios2/cdx-add.c | 24 + gcc/testsuite/gcc.target/nios2/cdx-branch.c | 44 ++ gcc/testsuite/gcc.target/nios2/cdx-callret.c | 25 + .../gcc.target/nios2/cdx-loadstore.c | 61 ++ gcc/testsuite/gcc.target/nios2/cdx-logical.c | 43 ++ gcc/testsuite/gcc.target/nios2/cdx-mov.c | 20 + gcc/testsuite/gcc.target/nios2/cdx-shift.c | 32 + gcc/testsuite/gcc.target/nios2/cdx-sub.c | 23 + .../gcc.target/nios2/nios2-trap-insn.c | 2 +- 20 files changed, 1390 insertions(+), 122 deletions(-) create mode 100644 gcc/testsuite/gcc.target/nios2/andci.c create mode 100644 gcc/testsuite/gcc.target/nios2/bmx.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-add.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-branch.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-callret.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-loadstore.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-logical.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-mov.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-shift.c create mode 100644 gcc/testsuite/gcc.target/nios2/cdx-sub.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 80b38cdb51e..418a8aaa81e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,78 @@ +2015-07-14 Sandra Loosemore + Cesar Philippidis + Chung-Lin Tang + + * config/nios2/nios2.h (LABEL_ALIGN): Define. + (REG_ALLOC_ORDER): Define. + (ADJUST_REG_ALLOC_ORDER): Define. + (HONOR_REG_ALLOC_ORDER): Define. + (CDX_REG_P): Define. + (ANDCLEAR_INT): Define. + * config/nios2/nios2-protos.h (nios2_add_insn_asm): Declare. + (nios2_label_align): Declare. + (nios2_cdx_narrow_form_p): Declare. + (nios2_adjust_reg_alloc_order): Declare. + * config/nios2/nios2.c (nios2_rtx_costs): Adjust for BMX zero-extract + operation. + (nios2_large_unspec_reloc_p): New function, split from... + (nios2_legitimate_pic_operand_p): ...here. + (nios2_emit_move_sequence): Add *high/*lo_sum constant expand code. + (nios2_print_operand_punct_valid_p): New. + (nios2_print_operand): Add %., %!, %x, %y, %A. Remove %U. + (split_mem_address): New. + (split_alu_insn): New. + (cdxreg): New. + (cdx_add_immed, cdx_and_immed, cdx_mov_immed, cdx_shift_immed): New. + (enum nios2_add_insn_kind): New. + (nios2_add_insn_names, nios2_add_insn_narrow): New. + (nios2_add_insn_classify): New. + (nios2_add_insn_asm): New. + (nios2_cdx_narrow_form_p): New. + (label_align, min_labelno, max_labelno): New. + (nios2_reorg): New. + (nios2_label_align): New. + (nios2_adjust_reg_alloc_order): New. + (TARGET_PRINT_OPERAND_PUNCT_VALID_P): Define. + (TARGET_MACHINE_DEPENDENT_REORG): Define. + * config/nios2/constraints.md (P): New constraint. + * config/nios2/predicates.md (const_and_operand): New. + (and_operand): New. + (stack_memory_operand): New. + * config/nios2/nios2.md (SP_REGNO): Define stack pointer regno. + (length): Update to use nios2_cdx_narrow_form_p(). + (type): Add new insn type values. + (control, alu, st, ld, shift): Update insn reservations with + new insn type values. + (*high, *lo_sum): Define new insn patterns for constant generation. + (movqi_internal, movhi_internal, movsi_internal): Reduce + alternatives, update asm template to handle CDX variants, update + type attributes. + (zero_extendhisi2, zero_extendqi2): Add CDX variants to asm + template, update type attributes. + (extendhisi2, extendqi2): Likewise. + (addsi3): Change to use function for asm string. + (subsi3): Add CDX notation to asm template, update type attributes. + (negsi3, one_cmplsi3): Likewise. + (andsi3): New pattern, specialized from logical patterns. + (si3): Remove and case, combine alternatives, update asm + template. + (si3): Add CDX notation, update type attributes. + (rotrsi3): Update type attribute. + (*merge, extzv, insv): New insn patterns. + (return): Change to define_expand. + (simple_return): Add CDX notation, update type attributes. + (indirect_jump): Add CDX notation. + (jump): Update asm cases, update length attribute expression. + (*call, *call_value, *sibcall, *sibcall_value): Add CDX variant. + (nios2_cbranch): Update asm cases and length attribute expression + to handle CDX variants. + (nios2_cmp): Update asm template. + (nop): Add CDX notation, update type attributes. + (trap): Add CDX notation. + (ctrapsi4): Update asm cases and length attribute expression to + handle CDX variant. + * doc/md.texi (Machine Constraints): Document P constraint. + 2015-07-14 Sandra Loosemore Cesar Philippidis Chung-Lin Tang diff --git a/gcc/config/nios2/constraints.md b/gcc/config/nios2/constraints.md index 7c7afdfb115..0ec817fd771 100644 --- a/gcc/config/nios2/constraints.md +++ b/gcc/config/nios2/constraints.md @@ -20,9 +20,10 @@ ;; We use the following constraint letters for constants ;; -;; I: -32768 to -32767 +;; I: -32768 to 32767 ;; J: 0 to 65535 ;; K: $nnnn0000 for some nnnn +;; P: Under R2, $nnnnffff or $ffffnnnn for some nnnn ;; L: 0 to 31 (for shift counts) ;; M: 0 ;; N: 0 to 255 (for custom instruction numbers) @@ -86,6 +87,11 @@ (and (match_code "const_int") (match_test "ival >= 0 && ival <= 31"))) +(define_constraint "P" + "An immediate operand for R2 andchi/andci instructions." + (and (match_code "const_int") + (match_test "TARGET_ARCH_R2 && ANDCLEAR_INT (ival)"))) + (define_constraint "S" "An immediate stored in small data, accessible by GP." (match_test "gprel_constant_p (op)")) diff --git a/gcc/config/nios2/nios2-protos.h b/gcc/config/nios2/nios2-protos.h index 52985a9d06c..617b6ab46fa 100644 --- a/gcc/config/nios2/nios2-protos.h +++ b/gcc/config/nios2/nios2-protos.h @@ -42,12 +42,18 @@ extern bool nios2_validate_fpu_compare (machine_mode, rtx *, rtx *, rtx *, extern bool nios2_fpu_insn_enabled (enum n2fpu_code); extern const char * nios2_fpu_insn_asm (enum n2fpu_code); +extern const char * nios2_add_insn_asm (rtx_insn *, rtx *); extern bool nios2_legitimate_pic_operand_p (rtx); extern bool gprel_constant_p (rtx); extern bool nios2_regno_ok_for_base_p (int, bool); extern bool nios2_unspec_reloc_p (rtx); +extern int nios2_label_align (rtx); +extern bool nios2_cdx_narrow_form_p (rtx_insn *); + +extern void nios2_adjust_reg_alloc_order (void); + #ifdef TREE_CODE #ifdef ARGS_SIZE_RTX /* expr.h defines both ARGS_SIZE_RTX and `enum direction' */ diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c index 93e0a869f32..d9fe6054b4d 100644 --- a/gcc/config/nios2/nios2.c +++ b/gcc/config/nios2/nios2.c @@ -1195,6 +1195,13 @@ nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, return false; } + case ZERO_EXTRACT: + if (TARGET_HAS_BMX) + { + *total = COSTS_N_INSNS (1); + return true; + } + default: return false; } @@ -1262,6 +1269,14 @@ nios2_unspec_reloc_p (rtx op) && ! nios2_large_offset_p (XINT (XEXP (op, 0), 1))); } +static bool +nios2_large_unspec_reloc_p (rtx op) +{ + return (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == UNSPEC + && nios2_large_offset_p (XINT (XEXP (op, 0), 1))); +} + /* Helper to generate unspec constant. */ static rtx nios2_unspec_offset (rtx loc, int unspec) @@ -1871,9 +1886,7 @@ nios2_load_pic_address (rtx sym, int unspec, rtx tmp) bool nios2_legitimate_pic_operand_p (rtx x) { - if (GET_CODE (x) == CONST - && GET_CODE (XEXP (x, 0)) == UNSPEC - && nios2_large_offset_p (XINT (XEXP (x, 0), 1))) + if (nios2_large_unspec_reloc_p (x)) return true; return ! (GET_CODE (x) == SYMBOL_REF @@ -2001,10 +2014,37 @@ nios2_emit_move_sequence (rtx *operands, machine_mode mode) from = copy_to_mode_reg (mode, from); } - if (GET_CODE (from) == SYMBOL_REF || GET_CODE (from) == LABEL_REF - || (GET_CODE (from) == CONST - && GET_CODE (XEXP (from, 0)) != UNSPEC)) - from = nios2_legitimize_constant_address (from); + if (CONSTANT_P (from)) + { + if (CONST_INT_P (from)) + { + if (!SMALL_INT (INTVAL (from)) + && !SMALL_INT_UNSIGNED (INTVAL (from)) + && !UPPER16_INT (INTVAL (from))) + { + HOST_WIDE_INT high = (INTVAL (from) + 0x8000) & ~0xffff; + HOST_WIDE_INT low = INTVAL (from) & 0xffff; + emit_move_insn (to, gen_int_mode (high, SImode)); + emit_insn (gen_add2_insn (to, gen_int_mode (low, HImode))); + set_unique_reg_note (get_last_insn (), REG_EQUAL, + copy_rtx (from)); + return true; + } + } + else if (!gprel_constant_p (from)) + { + if (!nios2_large_unspec_reloc_p (from)) + from = nios2_legitimize_constant_address (from); + if (CONSTANT_P (from)) + { + emit_insn (gen_rtx_SET (to, gen_rtx_HIGH (Pmode, from))); + emit_insn (gen_rtx_SET (to, gen_rtx_LO_SUM (Pmode, to, from))); + set_unique_reg_note (get_last_insn (), REG_EQUAL, + copy_rtx (operands[1])); + return true; + } + } + } operands[0] = to; operands[1] = from; @@ -2037,25 +2077,106 @@ nios2_adjust_call_address (rtx *call_op, rtx reg) /* Output assembly language related definitions. */ +/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */ +static bool +nios2_print_operand_punct_valid_p (unsigned char code) +{ + return (code == '.' || code == '!'); +} + + /* Print the operand OP to file stream FILE modified by LETTER. LETTER can be one of: - i: print "i" if OP is an immediate, except 0 - o: print "io" if OP is volatile - z: for const0_rtx print $0 instead of 0 + i: print i/hi/ui suffixes (used for mov instruction variants), + when OP is the appropriate immediate operand. + + u: like 'i', except without "ui" suffix case (used for cmpgeu/cmpltu) + + o: print "io" if OP needs volatile access (due to TARGET_BYPASS_CACHE + or TARGET_BYPASS_CACHE_VOLATILE). + + x: print i/hi/ci/chi suffixes for the and instruction, + when OP is the appropriate immediate operand. + + z: prints the third register immediate operand in assembly + instructions. Outputs const0_rtx as the 'zero' register + instead of '0'. + + y: same as 'z', but for specifically for logical instructions, + where the processing for immediates are slightly different. + H: for %hiadj L: for %lo - U: for upper half of 32 bit value D: for the upper 32-bits of a 64-bit double value R: prints reverse condition. + A: prints (reg) operand for ld[s]ex and st[s]ex. + + .: print .n suffix for 16-bit instructions. + !: print r.n suffix for 16-bit instructions. Used for jmpr.n. */ static void nios2_print_operand (FILE *file, rtx op, int letter) { + /* First take care of the format letters that just insert a string + into the output stream. */ switch (letter) { + case '.': + if (current_output_insn && get_attr_length (current_output_insn) == 2) + fprintf (file, ".n"); + return; + + case '!': + if (current_output_insn && get_attr_length (current_output_insn) == 2) + fprintf (file, "r.n"); + return; + + case 'x': + if (CONST_INT_P (op)) + { + HOST_WIDE_INT val = INTVAL (op); + HOST_WIDE_INT low = val & 0xffff; + HOST_WIDE_INT high = (val >> 16) & 0xffff; + + if (val != 0) + { + if (high != 0) + { + if (low != 0) + { + gcc_assert (TARGET_ARCH_R2); + if (high == 0xffff) + fprintf (file, "c"); + else if (low == 0xffff) + fprintf (file, "ch"); + else + gcc_unreachable (); + } + else + fprintf (file, "h"); + } + fprintf (file, "i"); + } + } + return; + + case 'u': case 'i': + if (CONST_INT_P (op)) + { + HOST_WIDE_INT val = INTVAL (op); + HOST_WIDE_INT low = val & 0xffff; + HOST_WIDE_INT high = (val >> 16) & 0xffff; + if (val != 0) + { + if (low == 0 && high != 0) + fprintf (file, "h"); + else if (high == 0 && (low & 0x8000) != 0 && letter != 'u') + fprintf (file, "u"); + } + } if (CONSTANT_P (op) && op != const0_rtx) fprintf (file, "i"); return; @@ -2064,13 +2185,18 @@ nios2_print_operand (FILE *file, rtx op, int letter) if (GET_CODE (op) == MEM && ((MEM_VOLATILE_P (op) && TARGET_BYPASS_CACHE_VOLATILE) || TARGET_BYPASS_CACHE)) - fprintf (file, "io"); + { + gcc_assert (current_output_insn + && get_attr_length (current_output_insn) == 4); + fprintf (file, "io"); + } return; default: break; } + /* Handle comparison operator names. */ if (comparison_operator (op, VOIDmode)) { enum rtx_code cond = GET_CODE (op); @@ -2086,10 +2212,11 @@ nios2_print_operand (FILE *file, rtx op, int letter) } } + /* Now handle the cases where we actually need to format an operand. */ switch (GET_CODE (op)) { case REG: - if (letter == 0 || letter == 'z') + if (letter == 0 || letter == 'z' || letter == 'y') { fprintf (file, "%s", reg_names[REGNO (op)]); return; @@ -2102,19 +2229,64 @@ nios2_print_operand (FILE *file, rtx op, int letter) break; case CONST_INT: - if (INTVAL (op) == 0 && letter == 'z') - { - fprintf (file, "zero"); - return; - } + { + rtx int_rtx = op; + HOST_WIDE_INT val = INTVAL (int_rtx); + HOST_WIDE_INT low = val & 0xffff; + HOST_WIDE_INT high = (val >> 16) & 0xffff; + + if (letter == 'y') + { + if (val == 0) + fprintf (file, "zero"); + else + { + if (high != 0) + { + if (low != 0) + { + gcc_assert (TARGET_ARCH_R2); + if (high == 0xffff) + /* andci. */ + int_rtx = gen_int_mode (low, SImode); + else if (low == 0xffff) + /* andchi. */ + int_rtx = gen_int_mode (high, SImode); + else + gcc_unreachable (); + } + else + /* andhi. */ + int_rtx = gen_int_mode (high, SImode); + } + else + /* andi. */ + int_rtx = gen_int_mode (low, SImode); + output_addr_const (file, int_rtx); + } + return; + } + else if (letter == 'z') + { + if (val == 0) + fprintf (file, "zero"); + else + { + if (low == 0 && high != 0) + int_rtx = gen_int_mode (high, SImode); + else if (low != 0) + { + gcc_assert (high == 0 || high == 0xffff); + int_rtx = gen_int_mode (low, high == 0 ? SImode : HImode); + } + else + gcc_unreachable (); + output_addr_const (file, int_rtx); + } + return; + } + } - if (letter == 'U') - { - HOST_WIDE_INT val = INTVAL (op); - val = (val >> 16) & 0xFFFF; - output_addr_const (file, gen_int_mode (val, SImode)); - return; - } /* Else, fall through. */ case CONST: @@ -2147,6 +2319,12 @@ nios2_print_operand (FILE *file, rtx op, int letter) case SUBREG: case MEM: + if (letter == 'A') + { + /* Address of '(reg)' form, with no index. */ + fprintf (file, "(%s)", reg_names[REGNO (XEXP (op, 0))]); + return; + } if (letter == 0) { output_address (op); @@ -3462,6 +3640,489 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, reload_completed = 0; } + +/* Utility function to break a memory address into + base register + constant offset. Return false if something + unexpected is seen. */ +static bool +split_mem_address (rtx addr, rtx *base_reg, rtx *offset) +{ + if (REG_P (addr)) + { + *base_reg = addr; + *offset = const0_rtx; + return true; + } + else if (GET_CODE (addr) == PLUS) + { + *base_reg = XEXP (addr, 0); + *offset = XEXP (addr, 1); + return true; + } + return false; +} + +/* Splits out the operands of an ALU insn, places them in *LHS, *RHS1, *RHS2. */ +static void +split_alu_insn (rtx_insn *insn, rtx *lhs, rtx *rhs1, rtx *rhs2) +{ + rtx pat = PATTERN (insn); + gcc_assert (GET_CODE (pat) == SET); + *lhs = SET_DEST (pat); + *rhs1 = XEXP (SET_SRC (pat), 0); + if (GET_RTX_CLASS (GET_CODE (SET_SRC (pat))) != RTX_UNARY) + *rhs2 = XEXP (SET_SRC (pat), 1); + return; +} + +/* Returns true if OP is a REG and assigned a CDX reg. */ +static bool +cdxreg (rtx op) +{ + return REG_P (op) && (!reload_completed || CDX_REG_P (REGNO (op))); +} + +/* Returns true if OP is within range of CDX addi.n immediates. */ +static bool +cdx_add_immed (rtx op) +{ + if (CONST_INT_P (op)) + { + HOST_WIDE_INT ival = INTVAL (op); + return ival <= 128 && ival > 0 && (ival & (ival - 1)) == 0; + } + return false; +} + +/* Returns true if OP is within range of CDX andi.n immediates. */ +static bool +cdx_and_immed (rtx op) +{ + if (CONST_INT_P (op)) + { + HOST_WIDE_INT ival = INTVAL (op); + return (ival == 1 || ival == 2 || ival == 3 || ival == 4 + || ival == 8 || ival == 0xf || ival == 0x10 + || ival == 0x10 || ival == 0x1f || ival == 0x20 + || ival == 0x3f || ival == 0x3f || ival == 0x7f + || ival == 0x80 || ival == 0xff || ival == 0x7ff + || ival == 0xff00 || ival == 0xffff); + } + return false; +} + +/* Returns true if OP is within range of CDX movi.n immediates. */ +static bool +cdx_mov_immed (rtx op) +{ + if (CONST_INT_P (op)) + { + HOST_WIDE_INT ival = INTVAL (op); + return ((ival >= 0 && ival <= 124) + || ival == 0xff || ival == -2 || ival == -1); + } + return false; +} + +/* Returns true if OP is within range of CDX slli.n/srli.n immediates. */ +static bool +cdx_shift_immed (rtx op) +{ + if (CONST_INT_P (op)) + { + HOST_WIDE_INT ival = INTVAL (op); + return (ival == 1 || ival == 2 || ival == 3 || ival == 8 + || ival == 12 || ival == 16 || ival == 24 + || ival == 31); + } + return false; +} + + + +/* Classification of different kinds of add instructions. */ +enum nios2_add_insn_kind { + nios2_add_n_kind, + nios2_addi_n_kind, + nios2_subi_n_kind, + nios2_spaddi_n_kind, + nios2_spinci_n_kind, + nios2_spdeci_n_kind, + nios2_add_kind, + nios2_addi_kind +}; + +static const char *nios2_add_insn_names[] = { + "add.n", "addi.n", "subi.n", "spaddi.n", "spinci.n", "spdeci.n", + "add", "addi" }; +static bool nios2_add_insn_narrow[] = { + true, true, true, true, true, true, + false, false}; + +/* Function to classify kinds of add instruction patterns. */ +static enum nios2_add_insn_kind +nios2_add_insn_classify (rtx_insn *insn ATTRIBUTE_UNUSED, + rtx lhs, rtx rhs1, rtx rhs2) +{ + if (TARGET_HAS_CDX) + { + if (cdxreg (lhs) && cdxreg (rhs1)) + { + if (cdxreg (rhs2)) + return nios2_add_n_kind; + if (CONST_INT_P (rhs2)) + { + HOST_WIDE_INT ival = INTVAL (rhs2); + if (ival > 0 && cdx_add_immed (rhs2)) + return nios2_addi_n_kind; + if (ival < 0 && cdx_add_immed (GEN_INT (-ival))) + return nios2_subi_n_kind; + } + } + else if (rhs1 == stack_pointer_rtx + && CONST_INT_P (rhs2)) + { + HOST_WIDE_INT imm7 = INTVAL (rhs2) >> 2; + HOST_WIDE_INT rem = INTVAL (rhs2) & 3; + if (rem == 0 && (imm7 & ~0x7f) == 0) + { + if (cdxreg (lhs)) + return nios2_spaddi_n_kind; + if (lhs == stack_pointer_rtx) + return nios2_spinci_n_kind; + } + imm7 = -INTVAL(rhs2) >> 2; + rem = -INTVAL (rhs2) & 3; + if (lhs == stack_pointer_rtx + && rem == 0 && (imm7 & ~0x7f) == 0) + return nios2_spdeci_n_kind; + } + } + return ((REG_P (rhs2) || rhs2 == const0_rtx) + ? nios2_add_kind : nios2_addi_kind); +} + +/* Emit assembly language for the different kinds of add instructions. */ +const char* +nios2_add_insn_asm (rtx_insn *insn, rtx *operands) +{ + static char buf[256]; + int ln = 256; + enum nios2_add_insn_kind kind + = nios2_add_insn_classify (insn, operands[0], operands[1], operands[2]); + if (kind == nios2_subi_n_kind) + snprintf (buf, ln, "subi.n\t%%0, %%1, %d", (int) -INTVAL (operands[2])); + else if (kind == nios2_spaddi_n_kind) + snprintf (buf, ln, "spaddi.n\t%%0, %%2"); + else if (kind == nios2_spinci_n_kind) + snprintf (buf, ln, "spinci.n\t%%2"); + else if (kind == nios2_spdeci_n_kind) + snprintf (buf, ln, "spdeci.n\t%d", (int) -INTVAL (operands[2])); + else + snprintf (buf, ln, "%s\t%%0, %%1, %%z2", nios2_add_insn_names[(int)kind]); + return buf; +} + +/* This routine, which the default "length" attribute computation is + based on, encapsulates information about all the cases where CDX + provides a narrow 2-byte instruction form. */ +bool +nios2_cdx_narrow_form_p (rtx_insn *insn) +{ + rtx pat, lhs, rhs1, rhs2; + enum attr_type type; + if (!TARGET_HAS_CDX) + return false; + type = get_attr_type (insn); + pat = PATTERN (insn); + gcc_assert (reload_completed); + switch (type) + { + case TYPE_CONTROL: + if (GET_CODE (pat) == SIMPLE_RETURN) + return true; + if (GET_CODE (pat) == PARALLEL) + pat = XVECEXP (pat, 0, 0); + if (GET_CODE (pat) == SET) + pat = SET_SRC (pat); + if (GET_CODE (pat) == IF_THEN_ELSE) + { + /* Conditional branch patterns; for these we + only check the comparison to find beqz.n/bnez.n cases. + For the 'nios2_cbranch' pattern, we cannot also check + the branch range here. That will be done at the md + pattern "length" attribute computation. */ + rtx cmp = XEXP (pat, 0); + return ((GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE) + && cdxreg (XEXP (cmp, 0)) + && XEXP (cmp, 1) == const0_rtx); + } + if (GET_CODE (pat) == TRAP_IF) + /* trap.n is always usable. */ + return true; + if (GET_CODE (pat) == CALL) + pat = XEXP (XEXP (pat, 0), 0); + if (REG_P (pat)) + /* Control instructions taking a register operand are indirect + jumps and calls. The CDX instructions have a 5-bit register + field so any reg is valid. */ + return true; + else + { + gcc_assert (!insn_variable_length_p (insn)); + return false; + } + case TYPE_ADD: + { + enum nios2_add_insn_kind kind; + split_alu_insn (insn, &lhs, &rhs1, &rhs2); + kind = nios2_add_insn_classify (insn, lhs, rhs1, rhs2); + return nios2_add_insn_narrow[(int)kind]; + } + case TYPE_LD: + { + bool ret; + HOST_WIDE_INT offset, rem = 0; + rtx addr, reg = SET_DEST (pat), mem = SET_SRC (pat); + if (GET_CODE (mem) == SIGN_EXTEND) + /* No CDX form for sign-extended load. */ + return false; + if (GET_CODE (mem) == ZERO_EXTEND) + /* The load alternatives in the zero_extend* patterns. */ + mem = XEXP (mem, 0); + if (MEM_P (mem)) + { + /* ldxio. */ + if ((MEM_VOLATILE_P (mem) && TARGET_BYPASS_CACHE_VOLATILE) + || TARGET_BYPASS_CACHE) + return false; + addr = XEXP (mem, 0); + /* GP-based references are never narrow. */ + if (gprel_constant_p (addr)) + return false; + ret = split_mem_address (addr, &rhs1, &rhs2); + gcc_assert (ret); + } + else + return false; + + offset = INTVAL (rhs2); + if (GET_MODE (mem) == SImode) + { + rem = offset & 3; + offset >>= 2; + /* ldwsp.n case. */ + if (rtx_equal_p (rhs1, stack_pointer_rtx) + && rem == 0 && (offset & ~0x1f) == 0) + return true; + } + else if (GET_MODE (mem) == HImode) + { + rem = offset & 1; + offset >>= 1; + } + /* ldbu.n, ldhu.n, ldw.n cases. */ + return (cdxreg (reg) && cdxreg (rhs1) + && rem == 0 && (offset & ~0xf) == 0); + } + case TYPE_ST: + if (GET_CODE (pat) == PARALLEL) + /* stex, stsex. */ + return false; + else + { + bool ret; + HOST_WIDE_INT offset, rem = 0; + rtx addr, reg = SET_SRC (pat), mem = SET_DEST (pat); + if (!MEM_P (mem)) + return false; + /* stxio. */ + if ((MEM_VOLATILE_P (mem) && TARGET_BYPASS_CACHE_VOLATILE) + || TARGET_BYPASS_CACHE) + return false; + addr = XEXP (mem, 0); + /* GP-based references are never narrow. */ + if (gprel_constant_p (addr)) + return false; + ret = split_mem_address (addr, &rhs1, &rhs2); + gcc_assert (ret); + offset = INTVAL (rhs2); + if (GET_MODE (mem) == SImode) + { + rem = offset & 3; + offset >>= 2; + /* stwsp.n case. */ + if (rtx_equal_p (rhs1, stack_pointer_rtx) + && rem == 0 && (offset & ~0x1f) == 0) + return true; + /* stwz.n case. */ + else if (reg == const0_rtx && cdxreg (rhs1) + && rem == 0 && (offset & ~0x3f) == 0) + return true; + } + else if (GET_MODE (mem) == HImode) + { + rem = offset & 1; + offset >>= 1; + } + else + { + gcc_assert (GET_MODE (mem) == QImode); + /* stbz.n case. */ + if (reg == const0_rtx && cdxreg (rhs1) + && (offset & ~0x3f) == 0) + return true; + } + + /* stbu.n, sthu.n, stw.n cases. */ + return (cdxreg (reg) && cdxreg (rhs1) + && rem == 0 && (offset & ~0xf) == 0); + } + case TYPE_MOV: + lhs = SET_DEST (pat); + rhs1 = SET_SRC (pat); + if (CONST_INT_P (rhs1)) + return (cdxreg (lhs) && cdx_mov_immed (rhs1)); + gcc_assert (REG_P (lhs) && REG_P (rhs1)); + return true; + + case TYPE_AND: + /* Some zero_extend* alternatives are and insns. */ + if (GET_CODE (SET_SRC (pat)) == ZERO_EXTEND) + return (cdxreg (SET_DEST (pat)) + && cdxreg (XEXP (SET_SRC (pat), 0))); + split_alu_insn (insn, &lhs, &rhs1, &rhs2); + if (CONST_INT_P (rhs2)) + return (cdxreg (lhs) && cdxreg (rhs1) && cdx_and_immed (rhs2)); + return (cdxreg (lhs) && cdxreg (rhs2) + && (!reload_completed || rtx_equal_p (lhs, rhs1))); + + case TYPE_OR: + case TYPE_XOR: + /* Note the two-address limitation for CDX form. */ + split_alu_insn (insn, &lhs, &rhs1, &rhs2); + return (cdxreg (lhs) && cdxreg (rhs2) + && (!reload_completed || rtx_equal_p (lhs, rhs1))); + + case TYPE_SUB: + split_alu_insn (insn, &lhs, &rhs1, &rhs2); + return (cdxreg (lhs) && cdxreg (rhs1) && cdxreg (rhs2)); + + case TYPE_NEG: + case TYPE_NOT: + split_alu_insn (insn, &lhs, &rhs1, NULL); + return (cdxreg (lhs) && cdxreg (rhs1)); + + case TYPE_SLL: + case TYPE_SRL: + split_alu_insn (insn, &lhs, &rhs1, &rhs2); + return (cdxreg (lhs) + && ((cdxreg (rhs1) && cdx_shift_immed (rhs2)) + || (cdxreg (rhs2) + && (!reload_completed || rtx_equal_p (lhs, rhs1))))); + case TYPE_NOP: + case TYPE_PUSH: + case TYPE_POP: + return true; + default: + break; + } + return false; +} + +/* Implement TARGET_MACHINE_DEPENDENT_REORG: + We use this hook when emitting CDX code to enforce the 4-byte + alignment requirement for labels that are used as the targets of + jmpi instructions. CDX code can otherwise contain a mix of 16-bit + and 32-bit instructions aligned on any 16-bit boundary, but functions + and jmpi labels have to be 32-bit aligned because of the way the address + is encoded in the instruction. */ + +static unsigned char *label_align; +static int min_labelno, max_labelno; + +static void +nios2_reorg (void) +{ + bool changed = true; + rtx_insn *insn; + + if (!TARGET_HAS_CDX) + return; + + /* Initialize the data structures. */ + if (label_align) + free (label_align); + max_labelno = max_label_num (); + min_labelno = get_first_label_num (); + label_align = XCNEWVEC (unsigned char, max_labelno - min_labelno + 1); + + /* Iterate on inserting alignment and adjusting branch lengths until + no more changes. */ + while (changed) + { + changed = false; + shorten_branches (get_insns ()); + + for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn)) + if (JUMP_P (insn) && insn_variable_length_p (insn)) + { + rtx label = JUMP_LABEL (insn); + /* We use the current fact that all cases of 'jmpi' + doing the actual branch in the machine description + has a computed length of 6 or 8. Length 4 and below + are all PC-relative 'br' branches without the jump-align + problem. */ + if (label && LABEL_P (label) && get_attr_length (insn) > 4) + { + int index = CODE_LABEL_NUMBER (label) - min_labelno; + if (label_align[index] != 2) + { + label_align[index] = 2; + changed = true; + } + } + } + } +} + +/* Implement LABEL_ALIGN, using the information gathered in nios2_reorg. */ +int +nios2_label_align (rtx label) +{ + int n = CODE_LABEL_NUMBER (label); + + if (label_align && n >= min_labelno && n <= max_labelno) + return MAX (label_align[n - min_labelno], align_labels_log); + return align_labels_log; +} + +/* Implement ADJUST_REG_ALLOC_ORDER. We use the default ordering + for R1 and non-CDX R2 code; for CDX we tweak thing to prefer + the registers that can be used as operands to instructions that + have 3-bit register fields. */ +void +nios2_adjust_reg_alloc_order (void) +{ + const int cdx_reg_alloc_order[] = + { + /* Call-clobbered GPRs within CDX 3-bit encoded range. */ + 2, 3, 4, 5, 6, 7, + /* Call-saved GPRs within CDX 3-bit encoded range. */ + 16, 17, + /* Other call-clobbered GPRs. */ + 8, 9, 10, 11, 12, 13, 14, 15, + /* Other call-saved GPRs. RA placed first since it is always saved. */ + 31, 18, 19, 20, 21, 22, 23, 28, + /* Fixed GPRs, not used by the register allocator. */ + 0, 1, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39 + }; + + if (TARGET_HAS_CDX) + memcpy (reg_alloc_order, cdx_reg_alloc_order, + sizeof (int) * FIRST_PSEUDO_REGISTER); +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_FUNCTION_PROLOGUE @@ -3549,6 +4210,9 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, #undef TARGET_ASM_OUTPUT_DWARF_DTPREL #define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel +#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P +#define TARGET_PRINT_OPERAND_PUNCT_VALID_P nios2_print_operand_punct_valid_p + #undef TARGET_PRINT_OPERAND #define TARGET_PRINT_OPERAND nios2_print_operand @@ -3589,6 +4253,9 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK nios2_asm_output_mi_thunk +#undef TARGET_MACHINE_DEPENDENT_REORG +#define TARGET_MACHINE_DEPENDENT_REORG nios2_reorg + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-nios2.h" diff --git a/gcc/config/nios2/nios2.h b/gcc/config/nios2/nios2.h index 58afaec69ce..ff25ade9372 100644 --- a/gcc/config/nios2/nios2.h +++ b/gcc/config/nios2/nios2.h @@ -96,6 +96,8 @@ ((TREE_CODE (EXP) == STRING_CST) \ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) +#define LABEL_ALIGN(LABEL) nios2_label_align (LABEL) + /* Layout of source language data types. */ #define INT_TYPE_SIZE 32 @@ -175,6 +177,20 @@ #define HARD_REGNO_NREGS(REGNO, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +/* Order in which to allocate registers. Each register must be + listed once. This is the default ordering for R1 and non-CDX R2 + code. For CDX, we overwrite this in ADJUST_REG_ALLOC_ORDER. */ +#define REG_ALLOC_ORDER \ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, \ + 37, 38, 39 } + +#define ADJUST_REG_ALLOC_ORDER nios2_adjust_reg_alloc_order () + +/* Caller-save costs can be less emphasized under R2 CDX, where we can + use push.n/pop.n. */ +#define HONOR_REG_ALLOC_ORDER (TARGET_HAS_CDX) + /* Register Classes. */ enum reg_class @@ -213,6 +229,9 @@ enum reg_class #define CLASS_MAX_NREGS(CLASS, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +#define CDX_REG_P(REGNO) \ + ((REGNO) == 16 || (REGNO) == 17 || (2 <= (REGNO) && (REGNO) <= 7)) + /* Tests for various kinds of constants used in the Nios II port. */ #define SMALL_INT(X) ((unsigned HOST_WIDE_INT)(X) + 0x8000 < 0x10000) @@ -222,6 +241,8 @@ enum reg_class #define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) #define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) #define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) +#define ANDCLEAR_INT(X) \ + (((X) & 0xffff) == 0xffff || (((X) >> 16) & 0xffff) == 0xffff) /* Say that the epilogue uses the return address register. Note that in the case of sibcalls, the values "used by the epilogue" are diff --git a/gcc/config/nios2/nios2.md b/gcc/config/nios2/nios2.md index 8cf2347e05c..a27df17670e 100644 --- a/gcc/config/nios2/nios2.md +++ b/gcc/config/nios2/nios2.md @@ -30,6 +30,7 @@ (TP_REGNO 23) ; Thread pointer register (GP_REGNO 26) ; Global pointer register + (SP_REGNO 27) ; Stack pointer register (FP_REGNO 28) ; Frame pointer register (EA_REGNO 29) ; Exception return address register (RA_REGNO 31) ; Return address register @@ -92,9 +93,14 @@ ; incuring a stall. ; length of an instruction (in bytes) -(define_attr "length" "" (const_int 4)) +(define_attr "length" "" + (if_then_else (match_test "nios2_cdx_narrow_form_p (insn)") + (const_int 2) + (const_int 4))) + (define_attr "type" - "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" + "unknown,complex,control,alu,cond_alu,st,ld,stwm,ldwm,push,pop,mul,div,\ + custom,add,sub,mov,and,or,xor,neg,not,sll,srl,sra,rol,ror,nop" (const_string "complex")) (define_asm_attributes @@ -118,11 +124,11 @@ "cpu") (define_insn_reservation "control" 1 - (eq_attr "type" "control") + (eq_attr "type" "control,pop") "cpu") (define_insn_reservation "alu" 1 - (eq_attr "type" "alu") + (eq_attr "type" "alu,add,sub,mov,and,or,xor,neg,not") "cpu") (define_insn_reservation "cond_alu" 1 @@ -130,7 +136,7 @@ "cpu") (define_insn_reservation "st" 1 - (eq_attr "type" "st") + (eq_attr "type" "st,stwm,push") "cpu") (define_insn_reservation "custom" 1 @@ -139,11 +145,11 @@ ; shifts, muls and lds have three cycle latency (define_insn_reservation "ld" 3 - (eq_attr "type" "ld") + (eq_attr "type" "ld,ldwm") "cpu") (define_insn_reservation "shift" 3 - (eq_attr "type" "shift") + (eq_attr "type" "sll,srl,sra,rol,ror") "cpu") (define_insn_reservation "mul" 3 @@ -171,46 +177,90 @@ DONE; }) +(define_insn "*high" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (match_operand:SI 1 "immediate_operand" "i")))] + "" + "movhi\\t%0, %H1" + [(set_attr "type" "alu")]) + +(define_insn "*lo_sum" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "addi\\t%0, %1, %L2" + [(set_attr "type" "alu")]) + (define_insn "movqi_internal" - [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") - (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r") + (match_operand:QI 1 "general_operand" "rM,m,rI"))] "(register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode))" - "@ - stb%o0\\t%z1, %0 - ldbu%o1\\t%0, %1 - mov\\t%0, %z1 - movi\\t%0, %1" - [(set_attr "type" "st,ld,alu,alu")]) + { + switch (which_alternative) + { + case 0: + if (get_attr_length (insn) != 2) + return "stb%o0\\t%z1, %0"; + else if (const_0_operand (operands[1], QImode)) + return "stbz.n\\t%z1, %0"; + else + return "stb.n\\t%z1, %0"; + case 1: + return "ldbu%o1%.\\t%0, %1"; + case 2: + return "mov%i1%.\\t%0, %z1"; + default: + gcc_unreachable (); + } + } + [(set_attr "type" "st,ld,mov")]) (define_insn "movhi_internal" - [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r") - (match_operand:HI 1 "general_operand" "rM,m,rM,I"))] + [(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\\t%0, %z1 - movi\\t%0, %1" - [(set_attr "type" "st,ld,alu,alu")]) + sth%o0%.\\t%z1, %0 + ldhu%o1%.\\t%0, %1 + mov%i1%.\\t%0, %z1" + [(set_attr "type" "st,ld,mov")]) (define_insn "movsi_internal" - [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r,r") - (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,K,S,i"))] + [(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) || reg_or_0_operand (operands[1], SImode))" - "@ - stw%o0\\t%z1, %0 - ldw%o1\\t%0, %1 - mov\\t%0, %z1 - movi\\t%0, %1 - movui\\t%0, %1 - movhi\\t%0, %H1 - addi\\t%0, gp, %%gprel(%1) - movhi\\t%0, %H1\;addi\\t%0, %0, %L1" - [(set_attr "type" "st,ld,alu,alu,alu,alu,alu,alu") - (set_attr "length" "4,4,4,4,4,4,4,8")]) + { + switch (which_alternative) + { + case 0: + if (get_attr_length (insn) != 2) + return "stw%o0\\t%z1, %0"; + else if (stack_memory_operand (operands[0], SImode)) + return "stwsp.n\\t%z1, %0"; + else if (const_0_operand (operands[1], SImode)) + return "stwz.n\\t%z1, %0"; + else + return "stw.n\\t%z1, %0"; + case 1: + if (get_attr_length (insn) != 2) + return "ldw%o1\\t%0, %1"; + else if (stack_memory_operand (operands[1], SImode)) + return "ldwsp.n\\t%0, %1"; + else + return "ldw.n\\t%0, %1"; + case 2: + return "mov%i1%.\\t%0, %z1"; + case 3: + return "addi\\t%0, gp, %%gprel(%1)"; + default: + gcc_unreachable (); + } + } + [(set_attr "type" "st,ld,mov,alu")]) (define_mode_iterator BH [QI HI]) (define_mode_iterator BHW [QI HI SI]) @@ -264,18 +314,18 @@ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] "" "@ - andi\\t%0, %1, 0xffff - ldhu%o1\\t%0, %1" - [(set_attr "type" "alu,ld")]) + andi%.\\t%0, %1, 0xffff + ldhu%o1%.\\t%0, %1" + [(set_attr "type" "and,ld")]) (define_insn "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" - [(set_attr "type" "alu,ld")]) + andi%.\\t%0, %1, 0xff + ldbu%o1%.\\t%0, %1" + [(set_attr "type" "and,ld")]) ;; Sign extension patterns @@ -285,7 +335,7 @@ "" "@ # - ldh%o1\\t%0, %1" + ldh%o1%.\\t%0, %1" [(set_attr "type" "alu,ld")]) (define_insn "extendqi2" @@ -294,7 +344,7 @@ "" "@ # - ldb%o1\\t%0, %1" + ldb%o1%.\\t%0, %1" [(set_attr "type" "alu,ld")]) ;; Split patterns for register alternative cases. @@ -331,16 +381,18 @@ (plus:SI (match_operand:SI 1 "register_operand" "%r") (match_operand:SI 2 "add_regimm_operand" "rIT")))] "" - "add%i2\\t%0, %1, %z2" - [(set_attr "type" "alu")]) +{ + return nios2_add_insn_asm (insn, operands); +} + [(set_attr "type" "add")]) (define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") (match_operand:SI 2 "register_operand" "r")))] "" - "sub\\t%0, %z1, %2" - [(set_attr "type" "alu")]) + "sub%.\\t%0, %z1, %2" + [(set_attr "type" "sub")]) (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -422,32 +474,47 @@ [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "register_operand" "r")))] "" - "sub\\t%0, zero, %1" - [(set_attr "type" "alu")]) +{ + if (get_attr_length (insn) == 2) + return "neg.n\\t%0, %1"; + else + return "sub\\t%0, zero, %1"; +} + [(set_attr "type" "neg")]) (define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_operand" "r")))] "" - "nor\\t%0, zero, %1" - [(set_attr "type" "alu")]) +{ + if (get_attr_length (insn) == 2) + return "not.n\\t%0, %1"; + else + return "nor\\t%0, zero, %1"; +} + [(set_attr "type" "not")]) ;; Integer logical Operations -(define_code_iterator LOGICAL [and ior xor]) -(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")]) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "and_operand" "rJKP")))] + "" + "and%x2%.\\t%0, %1, %y2" + [(set_attr "type" "and")]) + +(define_code_iterator LOGICAL [ior xor]) +(define_code_attr logical_asm [(ior "or") (xor "xor")]) (define_insn "si3" - [(set (match_operand:SI 0 "register_operand" "=r,r,r") - (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r") - (match_operand:SI 2 "logical_operand" "rM,J,K")))] + [(set (match_operand:SI 0 "register_operand" "=r") + (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "logical_operand" "rJK")))] "" - "@ - \\t%0, %1, %z2 - %i2\\t%0, %1, %2 - h%i2\\t%0, %1, %U2" - [(set_attr "type" "alu")]) + "%x2%.\\t%0, %1, %y2" + [(set_attr "type" "")]) (define_insn "*norsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -471,8 +538,8 @@ (SHIFT:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "shift_operand" "rL")))] "" - "%i2\\t%0, %1, %z2" - [(set_attr "type" "shift")]) + "%i2%.\\t%0, %1, %z2" + [(set_attr "type" "")]) (define_insn "rotrsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -480,7 +547,48 @@ (match_operand:SI 2 "register_operand" "r")))] "" "ror\\t%0, %1, %2" - [(set_attr "type" "shift")]) + [(set_attr "type" "ror")]) + +;; Nios II R2 Bit Manipulation Extension (BMX), provides +;; bit merge/insertion/extraction instructions. + +(define_insn "*merge" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "const_shift_operand" "L") + (match_operand:SI 2 "const_shift_operand" "L")) + (zero_extract:SI (match_operand:SI 3 "register_operand" "r") + (match_dup 1) (match_dup 2)))] + "TARGET_HAS_BMX" +{ + operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1); + return "merge\\t%0, %3, %4, %2"; +} + [(set_attr "type" "alu")]) + +(define_insn "extzv" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_shift_operand" "L") + (match_operand:SI 3 "const_shift_operand" "L")))] + "TARGET_HAS_BMX" +{ + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1); + return "extract\\t%0, %1, %4, %3"; +} + [(set_attr "type" "alu")]) + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "const_shift_operand" "L") + (match_operand:SI 2 "const_shift_operand" "L")) + (match_operand:SI 3 "reg_or_0_operand" "rM"))] + "TARGET_HAS_BMX" +{ + operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1); + return "insert\\t%0, %z3, %4, %2"; +} + [(set_attr "type" "alu")]) + ;; Floating point instructions @@ -635,15 +743,16 @@ DONE; }) -(define_insn "return" +(define_expand "return" [(simple_return)] "nios2_can_use_return_insn ()" - "ret") + "") (define_insn "simple_return" [(simple_return)] "" - "ret") + "ret%." + [(set_attr "type" "control")]) ;; Block any insns from being moved before this point, since the ;; profiling call to mcount can use various registers that aren't @@ -699,7 +808,7 @@ (define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" "c"))] "" - "jmp\\t%0" + "jmp%!\\t%0" [(set_attr "type" "control")]) (define_insn "jump" @@ -707,7 +816,9 @@ (label_ref (match_operand 0 "" "")))] "" { - if (flag_pic || get_attr_length (insn) == 4) + if (get_attr_length (insn) == 2) + return "br.n\\t%0"; + else if (get_attr_length (insn) == 4) return "br\\t%0"; else return "jmpi\\t%0"; @@ -715,11 +826,16 @@ [(set_attr "type" "control") (set (attr "length") (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -32768)) - (le (minus (match_dup 0) (pc)) (const_int 32764))) - (const_int 4) - (const_int 8)))]) - + (and (match_test "TARGET_HAS_CDX") + (and (ge (minus (match_dup 0) (pc)) (const_int -1022)) + (le (minus (match_dup 0) (pc)) (const_int 1022)))) + (const_int 2) + (if_then_else + (ior (match_test "flag_pic") + (and (ge (minus (match_dup 0) (pc)) (const_int -32764)) + (le (minus (match_dup 0) (pc)) (const_int 32764)))) + (const_int 4) + (const_int 8))))]) (define_expand "call" [(parallel [(call (match_operand 0 "" "") @@ -743,7 +859,7 @@ "" "@ call\\t%0 - callr\\t%0" + callr%.\\t%0" [(set_attr "type" "control")]) (define_insn "*call_value" @@ -754,7 +870,7 @@ "" "@ call\\t%1 - callr\\t%1" + callr%.\\t%1" [(set_attr "type" "control")]) (define_expand "sibcall" @@ -779,7 +895,7 @@ "" "@ jmpi\\t%0 - jmp\\t%0" + jmp%!\\t%0" [(set_attr "type" "control")]) (define_insn "sibcall_value_internal" @@ -790,7 +906,7 @@ "" "@ jmpi\\t%1 - jmp\\t%1" + jmp%!\\t%1" [(set_attr "type" "control")]) (define_expand "tablejump" @@ -814,7 +930,7 @@ (match_operand:SI 0 "register_operand" "c")) (use (label_ref (match_operand 1 "" "")))] "" - "jmp\\t%0" + "jmp%!\\t%0" [(set_attr "type" "control")]) @@ -868,18 +984,30 @@ (label_ref (match_operand 3 "" "")) (pc)))] "" - { - if (flag_pic || get_attr_length (insn) == 4) - return "b%0\t%z1, %z2, %l3"; - else - return "b%R0\t%z1, %z2, .+8;jmpi\t%l3"; - } +{ + if (get_attr_length (insn) == 2) + return "b%0z.n\t%z1, %l3"; + else if (get_attr_length (insn) == 4) + return "b%0\t%z1, %z2, %l3"; + else if (get_attr_length (insn) == 6) + return "b%R0z.n\t%z1, .+6;jmpi\t%l3"; + else + return "b%R0\t%z1, %z2, .+8;jmpi\t%l3"; +} [(set_attr "type" "control") (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 3) (pc)) (const_int -32768)) - (le (minus (match_dup 3) (pc)) (const_int 32764))) - (const_int 4) (const_int 8)))]) + (cond + [(and (match_test "nios2_cdx_narrow_form_p (insn)") + (ge (minus (match_dup 3) (pc)) (const_int -126)) + (le (minus (match_dup 3) (pc)) (const_int 126))) + (const_int 2) + (ior (match_test "flag_pic") + (and (ge (minus (match_dup 3) (pc)) (const_int -32764)) + (le (minus (match_dup 3) (pc)) (const_int 32764)))) + (const_int 4) + (match_test "nios2_cdx_narrow_form_p (insn)") + (const_int 6)] + (const_int 8)))]) ;; Floating point comparisons (define_code_iterator FCMP [eq ne gt ge le lt]) @@ -917,7 +1045,7 @@ (UCMP:SI (match_operand:SI 1 "reg_or_0_operand" "rM") (match_operand:SI 2 "uns_arith_operand" "rJ")))] "" - "cmp%i2\\t%0, %z1, %z2" + "cmp%u2\\t%0, %z1, %z2" [(set_attr "type" "alu")]) @@ -951,8 +1079,8 @@ (define_insn "nop" [(const_int 0)] "" - "nop" - [(set_attr "type" "alu")]) + "nop%." + [(set_attr "type" "nop")]) ;; Connect 'sync' to 'memory_barrier' standard expand name (define_expand "memory_barrier" @@ -1000,7 +1128,7 @@ (define_insn "trap" [(trap_if (const_int 1) (const_int 3))] "" - "trap\\t3" + "trap%.\\t3" [(set_attr "type" "control")]) (define_insn "ctrapsi4" @@ -1009,9 +1137,16 @@ (match_operand:SI 2 "reg_or_0_operand" "rM")]) (match_operand 3 "const_int_operand" "i"))] "" - "b%R0\\t%z1, %z2, 1f\;trap\\t%3\;1:" +{ + if (get_attr_length (insn) == 6) + return "b%R0\\t%z1, %z2, 1f\;trap.n\\t%3\;1:"; + else + return "b%R0\\t%z1, %z2, 1f\;trap\\t%3\;1:"; +} [(set_attr "type" "control") - (set_attr "length" "8")]) + (set (attr "length") + (if_then_else (match_test "nios2_cdx_narrow_form_p (insn)") + (const_int 6) (const_int 8)))]) ;; Load the GOT register. (define_insn "load_got_register" diff --git a/gcc/config/nios2/predicates.md b/gcc/config/nios2/predicates.md index fa578035cca..ccf3689082b 100644 --- a/gcc/config/nios2/predicates.md +++ b/gcc/config/nios2/predicates.md @@ -55,6 +55,16 @@ (ior (match_operand 0 "const_logical_operand") (match_operand 0 "register_operand"))) +(define_predicate "const_and_operand" + (and (match_code "const_int") + (match_test "SMALL_INT_UNSIGNED (INTVAL (op)) + || UPPER16_INT (INTVAL (op)) + || (TARGET_ARCH_R2 && ANDCLEAR_INT (INTVAL (op)))"))) + +(define_predicate "and_operand" + (ior (match_operand 0 "const_and_operand") + (match_operand 0 "register_operand"))) + (define_predicate "const_shift_operand" (and (match_code "const_int") (match_test "SHIFT_INT (INTVAL (op))"))) @@ -84,6 +94,16 @@ false)); }) +(define_predicate "stack_memory_operand" + (match_code "mem") +{ + rtx addr = XEXP (op, 0); + return ((REG_P (addr) && REGNO (addr) == SP_REGNO) + || (GET_CODE (addr) == PLUS + && REG_P (XEXP (addr, 0)) && REGNO (XEXP (addr, 0)) == SP_REGNO + && CONST_INT_P (XEXP (addr, 1)))); +}) + (define_predicate "ldstio_memory_operand" (match_code "mem") { diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 84c39a853e9..888380e9011 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -2991,6 +2991,9 @@ instead of @code{0} in the assembly output. Integer that is valid as an immediate operand for a custom instruction opcode. Range 0 to 255. +@item P +An immediate operand for R2 andchi/andci instructions. + @item S Matches immediates which are addresses in the small data section and therefore can be added to @code{gp} diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e7a38b51ecc..d090dfc70ae 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,19 @@ +2015-07-14 Sandra Loosemore + Cesar Philippidis + Chung-Lin Tang + + * gcc.target/nios2/andci.c: New. + * gcc.target/nios2/bmx.c: New. + * gcc.target/nios2/cdx-add.c: New. + * gcc.target/nios2/cdx-branch.c: New. + * gcc.target/nios2/cdx-callret.c: New. + * gcc.target/nios2/cdx-loadstore.c: New. + * gcc.target/nios2/cdx-logical.c: New. + * gcc.target/nios2/cdx-mov.c: New. + * gcc.target/nios2/cdx-shift.c: New. + * gcc.target/nios2/cdx-sub.c: New. + * gcc.target/nios2/nios2-trap-insn.c: Adjust pattern. + 2015-07-14 Andrea Azzarone PR c++/65071 diff --git a/gcc/testsuite/gcc.target/nios2/andci.c b/gcc/testsuite/gcc.target/nios2/andci.c new file mode 100644 index 00000000000..98dfb2d725f --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/andci.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2" } */ + +/* Test generation of Nios II R2 "andci" and "andchi" instructions. */ + +unsigned int f (unsigned int a) +{ + return a & 0xfffffff0; +} + +unsigned int g (unsigned int b) +{ + return b & 0xfff0ffff; +} + +/* { dg-final { scan-assembler "\tandci\t.*" } } */ +/* { dg-final { scan-assembler "\tandchi\t.*" } } */ + diff --git a/gcc/testsuite/gcc.target/nios2/bmx.c b/gcc/testsuite/gcc.target/nios2/bmx.c new file mode 100644 index 00000000000..9daa6063572 --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/bmx.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mbmx" } */ + +/* Test generation of Nios II R2 BMX instructions. */ + +struct s { + unsigned int pad1 : 3; + unsigned int bitfield : 20; + unsigned int intfield; +}; + +void f (struct s *a, struct s *b) +{ + a->bitfield = b->bitfield; +} + +void g (struct s *a, struct s *b) +{ + a->bitfield = b->intfield; +} + +void h (struct s *a, struct s *b) +{ + a->intfield = b->bitfield; +} + +/* { dg-final { scan-assembler "\tmerge\t.*, 22, 3" } } */ +/* { dg-final { scan-assembler "\tinsert\t.*, 22, 3" } } */ +/* { dg-final { scan-assembler "\textract\t.*, 22, 3" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-add.c b/gcc/testsuite/gcc.target/nios2/cdx-add.c new file mode 100644 index 00000000000..32f1986e768 --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-add.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX add.n and addi.n instructions. */ + +int f (int a, int b) +{ + return a + b; +} + +int g (int a) +{ + return a + 32; +} + +int h (int a) +{ + return a + 33; +} + +/* { dg-final { scan-assembler "\tadd\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\taddi\\.n\t.*, 32" } } */ +/* { dg-final { scan-assembler "\taddi\t.*, 33" } } */ + diff --git a/gcc/testsuite/gcc.target/nios2/cdx-branch.c b/gcc/testsuite/gcc.target/nios2/cdx-branch.c new file mode 100644 index 00000000000..3b984f2712a --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-branch.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX br.n, beqz.n, bnez.n instructions. */ + +int f (int a, int b, int c) +{ + if (a == 0) + return b; + else + return c; +} + +int g (int a, int b, int c) +{ + if (a != 0) + return b; + else + return c; +} + +extern int i (int); +extern int j (int); +extern int k (int); + +int h (int a) +{ + int x; + + /* As well as the conditional branch for the "if", there has to be + an unconditional branch from one branch of the "if" to + the return statement. We compile this testcase with -Os to + avoid insertion of a duplicate epilogue in place of the branch. */ + if (a == 1) + x = i (37); + else + x = j (42); + return x + a + k (x); +} + +/* { dg-final { scan-assembler "\tbeqz\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tbnez\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tbeq\t|\tbne\t" } } */ +/* { dg-final { scan-assembler "\tbr\\.n\t.*" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-callret.c b/gcc/testsuite/gcc.target/nios2/cdx-callret.c new file mode 100644 index 00000000000..239ec6e943e --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-callret.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX callr.n, jmpr.n, ret.n instructions. */ + +typedef int (*F) (void); + +int x (F f) +{ + f (); + + /* Note that the compiler might generate a return via pop.n or ldwm; + the test below is to make sure that it doesn't generate a 32-bit + return instruction. */ + return 3; +} + +int y (F f) +{ + return f (); +} + +/* { dg-final { scan-assembler "\tcallr\\.n\t.*" } } */ +/* { dg-final { scan-assembler-not "\tret$" } } */ +/* { dg-final { scan-assembler "\tjmpr\\.n\t.*" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-loadstore.c b/gcc/testsuite/gcc.target/nios2/cdx-loadstore.c new file mode 100644 index 00000000000..f6a67b9df3e --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-loadstore.c @@ -0,0 +1,61 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX load/store instructions. */ + +unsigned char ldb (unsigned char *p) +{ + return p[7]; +} + +unsigned short ldh (unsigned short *p) +{ + return p[7]; +} + +unsigned int ldw (unsigned int *p) +{ + return p[7]; +} + +void stb (unsigned char *p, unsigned char x) +{ + p[15] = x; +} + +void sth (unsigned short *p, unsigned short x) +{ + p[15] = x; +} + +void stw (unsigned int *p, unsigned int x) +{ + p[15] = x; +} + +void no_cdx_stb (unsigned char *p, unsigned char x) +{ + p[16] = x; +} + +void no_cdx_sth (unsigned short *p, unsigned short x) +{ + p[16] = x; +} + +void no_cdx_stw (unsigned int *p, unsigned int x) +{ + p[16] = x; +} + +/* { dg-final { scan-assembler "\tldbu\\.n\t.*, 7\\(.*\\)" } } */ +/* { dg-final { scan-assembler "\tldhu\\.n\t.*, 14\\(.*\\)" } } */ +/* { dg-final { scan-assembler "\tldw\\.n\t.*, 28\\(.*\\)" } } */ + +/* { dg-final { scan-assembler "\tstb\\.n\t.*, 15\\(.*\\)" } } */ +/* { dg-final { scan-assembler "\tsth\\.n\t.*, 30\\(.*\\)" } } */ +/* { dg-final { scan-assembler "\tstw\\.n\t.*, 60\\(.*\\)" } } */ + +/* { dg-final { scan-assembler "\tstb\t.*, 16\\(.*\\)" } } */ +/* { dg-final { scan-assembler "\tsth\t.*, 32\\(.*\\)" } } */ +/* { dg-final { scan-assembler "\tstw\t.*, 64\\(.*\\)" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-logical.c b/gcc/testsuite/gcc.target/nios2/cdx-logical.c new file mode 100644 index 00000000000..bf3819a819d --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-logical.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX and.n, andi.n, or.n, xor.n, and not.n + instructions. + + and.n, or.n, and x.n require one of the input registers to be the same + as the output register. Since the tests below want to put the result + in the return value register, they use this function to make sure that + one of the input operands is also already in the return register. */ + +extern unsigned int x (unsigned int a); + +unsigned int f (unsigned int a, unsigned int b) +{ + return x (a) & b; +} + +unsigned int g (unsigned int a) +{ + return a & 31; +} + +unsigned int h (unsigned int a, unsigned int b) +{ + return x (a) | b; +} + +unsigned int i (unsigned int a, unsigned int b) +{ + return x (a) ^ b; +} + +unsigned int j (unsigned int a) +{ + return ~a; +} + +/* { dg-final { scan-assembler "\tand\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tandi\\.n\t.*, 31" } } */ +/* { dg-final { scan-assembler "\tor\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\txor\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tnot\\.n\t.*" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-mov.c b/gcc/testsuite/gcc.target/nios2/cdx-mov.c new file mode 100644 index 00000000000..000b38bb626 --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-mov.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX mov.n and movi.n instructions. */ + +extern void f (int a, int b, int c, int d); + +int g (int x, int y, int z) +{ + f (100, x, y, z); + return -1; +} + +/* We should always get mov.n and never mov when compiling with -mcdx. */ +/* { dg-final { scan-assembler "\tmov\\.n\t.*" } } */ +/* { dg-final { scan-assembler-not "\tmov\t.*" } } */ + +/* Both of the constant loads are expressible with movi.n. */ +/* { dg-final { scan-assembler "\tmovi\\.n\t.*, 100" } } */ +/* { dg-final { scan-assembler "\tmovi\\.n\t.*, -1" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-shift.c b/gcc/testsuite/gcc.target/nios2/cdx-shift.c new file mode 100644 index 00000000000..25bf959863a --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-shift.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX and.n, andi.n, or.n, xor.n, and not.n + instructions. */ + +extern unsigned int x (unsigned int a); + +unsigned int f (unsigned int a, unsigned int b) +{ + return x (a) << b; +} + +unsigned int g (unsigned int a) +{ + return x (a) << 24; +} + +unsigned int h (unsigned int a, unsigned int b) +{ + return x (a) >> b; +} + +unsigned int i (unsigned int a, unsigned int b) +{ + return x (a) >> 24; +} + +/* { dg-final { scan-assembler "\tsll\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tslli\\.n\t.*, 24" } } */ +/* { dg-final { scan-assembler "\tsrl\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tsrli\\.n\t.*, 24" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/cdx-sub.c b/gcc/testsuite/gcc.target/nios2/cdx-sub.c new file mode 100644 index 00000000000..532a0f40e89 --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/cdx-sub.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=r2 -mcdx" } */ + +/* Check generation of R2 CDX sub.n, subi.n, and neg.n instructions. */ + +int f (int a, int b) +{ + return a - b; +} + +int g (int a) +{ + return a - 32; +} + +int h (int a) +{ + return -a; +} + +/* { dg-final { scan-assembler "\tsub\\.n\t.*" } } */ +/* { dg-final { scan-assembler "\tsubi\\.n\t.*, 32" } } */ +/* { dg-final { scan-assembler "\tneg\\.n\t.*" } } */ diff --git a/gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c b/gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c index 3f3900ffe1a..588a7f38749 100644 --- a/gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c +++ b/gcc/testsuite/gcc.target/nios2/nios2-trap-insn.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-final { scan-assembler "trap\\t3" } } */ +/* { dg-final { scan-assembler "trap\\t3|trap.n\\t3" } } */ /* Test the nios2 trap instruction */ void foo(void){ -- 2.30.2