Commit 3bbbe009 by Sandra Loosemore Committed by Sandra Loosemore

nios2.h (LABEL_ALIGN): Define.

2015-07-14  Sandra Loosemore  <sandra@codesourcery.com>
	    Cesar Philippidis  <cesar@codesourcery.com>
	    Chung-Lin Tang  <cltang@codesourcery.com>

	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_extendqi<mode>2): Add CDX variants to asm
	template, update type attributes.
	(extendhisi2, extendqi<mode>2): 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.
	(<code>si3): Remove and case, combine alternatives, update asm
	template.
	(<shift_op>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<code>): 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 <cesar@codesourcery.com>
Co-Authored-By: Chung-Lin Tang <cltang@codesourcery.com>

From-SVN: r225796
parent a03c6ae3
...@@ -2,6 +2,81 @@ ...@@ -2,6 +2,81 @@
Cesar Philippidis <cesar@codesourcery.com> Cesar Philippidis <cesar@codesourcery.com>
Chung-Lin Tang <cltang@codesourcery.com> Chung-Lin Tang <cltang@codesourcery.com>
* 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_extendqi<mode>2): Add CDX variants to asm
template, update type attributes.
(extendhisi2, extendqi<mode>2): 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.
(<code>si3): Remove and case, combine alternatives, update asm
template.
(<shift_op>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<code>): 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 <sandra@codesourcery.com>
Cesar Philippidis <cesar@codesourcery.com>
Chung-Lin Tang <cltang@codesourcery.com>
* config/nios2/nios2.h (SMALL_INT12): New macro. * config/nios2/nios2.h (SMALL_INT12): New macro.
* config/nios2/nios2.c (nios2_valid_addr_offset_p): New function. * config/nios2/nios2.c (nios2_valid_addr_offset_p): New function.
(nios2_valid_addr_expr_p): Use it. (nios2_valid_addr_expr_p): Use it.
......
...@@ -20,9 +20,10 @@ ...@@ -20,9 +20,10 @@
;; We use the following constraint letters for constants ;; We use the following constraint letters for constants
;; ;;
;; I: -32768 to -32767 ;; I: -32768 to 32767
;; J: 0 to 65535 ;; J: 0 to 65535
;; K: $nnnn0000 for some nnnn ;; K: $nnnn0000 for some nnnn
;; P: Under R2, $nnnnffff or $ffffnnnn for some nnnn
;; L: 0 to 31 (for shift counts) ;; L: 0 to 31 (for shift counts)
;; M: 0 ;; M: 0
;; N: 0 to 255 (for custom instruction numbers) ;; N: 0 to 255 (for custom instruction numbers)
...@@ -86,6 +87,11 @@ ...@@ -86,6 +87,11 @@
(and (match_code "const_int") (and (match_code "const_int")
(match_test "ival >= 0 && ival <= 31"))) (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" (define_constraint "S"
"An immediate stored in small data, accessible by GP." "An immediate stored in small data, accessible by GP."
(match_test "gprel_constant_p (op)")) (match_test "gprel_constant_p (op)"))
......
...@@ -42,12 +42,18 @@ extern bool nios2_validate_fpu_compare (machine_mode, rtx *, rtx *, rtx *, ...@@ -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 bool nios2_fpu_insn_enabled (enum n2fpu_code);
extern const char * nios2_fpu_insn_asm (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 nios2_legitimate_pic_operand_p (rtx);
extern bool gprel_constant_p (rtx); extern bool gprel_constant_p (rtx);
extern bool nios2_regno_ok_for_base_p (int, bool); extern bool nios2_regno_ok_for_base_p (int, bool);
extern bool nios2_unspec_reloc_p (rtx); 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 TREE_CODE
#ifdef ARGS_SIZE_RTX #ifdef ARGS_SIZE_RTX
/* expr.h defines both ARGS_SIZE_RTX and `enum direction' */ /* expr.h defines both ARGS_SIZE_RTX and `enum direction' */
......
...@@ -1195,6 +1195,13 @@ nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, ...@@ -1195,6 +1195,13 @@ nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
return false; return false;
} }
case ZERO_EXTRACT:
if (TARGET_HAS_BMX)
{
*total = COSTS_N_INSNS (1);
return true;
}
default: default:
return false; return false;
} }
...@@ -1262,6 +1269,14 @@ nios2_unspec_reloc_p (rtx op) ...@@ -1262,6 +1269,14 @@ nios2_unspec_reloc_p (rtx op)
&& ! nios2_large_offset_p (XINT (XEXP (op, 0), 1))); && ! 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. */ /* Helper to generate unspec constant. */
static rtx static rtx
nios2_unspec_offset (rtx loc, int unspec) nios2_unspec_offset (rtx loc, int unspec)
...@@ -1871,9 +1886,7 @@ nios2_load_pic_address (rtx sym, int unspec, rtx tmp) ...@@ -1871,9 +1886,7 @@ nios2_load_pic_address (rtx sym, int unspec, rtx tmp)
bool bool
nios2_legitimate_pic_operand_p (rtx x) nios2_legitimate_pic_operand_p (rtx x)
{ {
if (GET_CODE (x) == CONST if (nios2_large_unspec_reloc_p (x))
&& GET_CODE (XEXP (x, 0)) == UNSPEC
&& nios2_large_offset_p (XINT (XEXP (x, 0), 1)))
return true; return true;
return ! (GET_CODE (x) == SYMBOL_REF return ! (GET_CODE (x) == SYMBOL_REF
...@@ -2001,10 +2014,37 @@ nios2_emit_move_sequence (rtx *operands, machine_mode mode) ...@@ -2001,10 +2014,37 @@ nios2_emit_move_sequence (rtx *operands, machine_mode mode)
from = copy_to_mode_reg (mode, from); from = copy_to_mode_reg (mode, from);
} }
if (GET_CODE (from) == SYMBOL_REF || GET_CODE (from) == LABEL_REF if (CONSTANT_P (from))
|| (GET_CODE (from) == CONST {
&& GET_CODE (XEXP (from, 0)) != UNSPEC)) if (CONST_INT_P (from))
from = nios2_legitimize_constant_address (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[0] = to;
operands[1] = from; operands[1] = from;
...@@ -2037,25 +2077,106 @@ nios2_adjust_call_address (rtx *call_op, rtx reg) ...@@ -2037,25 +2077,106 @@ nios2_adjust_call_address (rtx *call_op, rtx reg)
/* Output assembly language related definitions. */ /* 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. /* Print the operand OP to file stream FILE modified by LETTER.
LETTER can be one of: LETTER can be one of:
i: print "i" if OP is an immediate, except 0 i: print i/hi/ui suffixes (used for mov instruction variants),
o: print "io" if OP is volatile when OP is the appropriate immediate operand.
z: for const0_rtx print $0 instead of 0
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 H: for %hiadj
L: for %lo L: for %lo
U: for upper half of 32 bit value
D: for the upper 32-bits of a 64-bit double value D: for the upper 32-bits of a 64-bit double value
R: prints reverse condition. 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 static void
nios2_print_operand (FILE *file, rtx op, int letter) 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) 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': 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) if (CONSTANT_P (op) && op != const0_rtx)
fprintf (file, "i"); fprintf (file, "i");
return; return;
...@@ -2064,13 +2185,18 @@ nios2_print_operand (FILE *file, rtx op, int letter) ...@@ -2064,13 +2185,18 @@ nios2_print_operand (FILE *file, rtx op, int letter)
if (GET_CODE (op) == MEM if (GET_CODE (op) == MEM
&& ((MEM_VOLATILE_P (op) && TARGET_BYPASS_CACHE_VOLATILE) && ((MEM_VOLATILE_P (op) && TARGET_BYPASS_CACHE_VOLATILE)
|| TARGET_BYPASS_CACHE)) || TARGET_BYPASS_CACHE))
fprintf (file, "io"); {
gcc_assert (current_output_insn
&& get_attr_length (current_output_insn) == 4);
fprintf (file, "io");
}
return; return;
default: default:
break; break;
} }
/* Handle comparison operator names. */
if (comparison_operator (op, VOIDmode)) if (comparison_operator (op, VOIDmode))
{ {
enum rtx_code cond = GET_CODE (op); enum rtx_code cond = GET_CODE (op);
...@@ -2086,10 +2212,11 @@ nios2_print_operand (FILE *file, rtx op, int letter) ...@@ -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)) switch (GET_CODE (op))
{ {
case REG: case REG:
if (letter == 0 || letter == 'z') if (letter == 0 || letter == 'z' || letter == 'y')
{ {
fprintf (file, "%s", reg_names[REGNO (op)]); fprintf (file, "%s", reg_names[REGNO (op)]);
return; return;
...@@ -2102,19 +2229,64 @@ nios2_print_operand (FILE *file, rtx op, int letter) ...@@ -2102,19 +2229,64 @@ nios2_print_operand (FILE *file, rtx op, int letter)
break; break;
case CONST_INT: case CONST_INT:
if (INTVAL (op) == 0 && letter == 'z') {
{ rtx int_rtx = op;
fprintf (file, "zero"); HOST_WIDE_INT val = INTVAL (int_rtx);
return; 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. */ /* Else, fall through. */
case CONST: case CONST:
...@@ -2147,6 +2319,12 @@ nios2_print_operand (FILE *file, rtx op, int letter) ...@@ -2147,6 +2319,12 @@ nios2_print_operand (FILE *file, rtx op, int letter)
case SUBREG: case SUBREG:
case MEM: 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) if (letter == 0)
{ {
output_address (op); output_address (op);
...@@ -3462,6 +3640,489 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, ...@@ -3462,6 +3640,489 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
reload_completed = 0; 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. */ /* Initialize the GCC target structure. */
#undef TARGET_ASM_FUNCTION_PROLOGUE #undef TARGET_ASM_FUNCTION_PROLOGUE
...@@ -3549,6 +4210,9 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, ...@@ -3549,6 +4210,9 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
#undef TARGET_ASM_OUTPUT_DWARF_DTPREL #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
#define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_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 #undef TARGET_PRINT_OPERAND
#define TARGET_PRINT_OPERAND nios2_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, ...@@ -3589,6 +4253,9 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
#undef TARGET_ASM_OUTPUT_MI_THUNK #undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK nios2_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; struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-nios2.h" #include "gt-nios2.h"
...@@ -96,6 +96,8 @@ ...@@ -96,6 +96,8 @@
((TREE_CODE (EXP) == STRING_CST) \ ((TREE_CODE (EXP) == STRING_CST) \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
#define LABEL_ALIGN(LABEL) nios2_label_align (LABEL)
/* Layout of source language data types. */ /* Layout of source language data types. */
#define INT_TYPE_SIZE 32 #define INT_TYPE_SIZE 32
...@@ -175,6 +177,20 @@ ...@@ -175,6 +177,20 @@
#define HARD_REGNO_NREGS(REGNO, MODE) \ #define HARD_REGNO_NREGS(REGNO, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) ((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. */ /* Register Classes. */
enum reg_class enum reg_class
...@@ -213,6 +229,9 @@ enum reg_class ...@@ -213,6 +229,9 @@ enum reg_class
#define CLASS_MAX_NREGS(CLASS, MODE) \ #define CLASS_MAX_NREGS(CLASS, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) ((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. */ /* Tests for various kinds of constants used in the Nios II port. */
#define SMALL_INT(X) ((unsigned HOST_WIDE_INT)(X) + 0x8000 < 0x10000) #define SMALL_INT(X) ((unsigned HOST_WIDE_INT)(X) + 0x8000 < 0x10000)
...@@ -222,6 +241,8 @@ enum reg_class ...@@ -222,6 +241,8 @@ enum reg_class
#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) #define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) #define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) #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 /* Say that the epilogue uses the return address register. Note that
in the case of sibcalls, the values "used by the epilogue" are in the case of sibcalls, the values "used by the epilogue" are
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
(TP_REGNO 23) ; Thread pointer register (TP_REGNO 23) ; Thread pointer register
(GP_REGNO 26) ; Global pointer register (GP_REGNO 26) ; Global pointer register
(SP_REGNO 27) ; Stack pointer register
(FP_REGNO 28) ; Frame pointer register (FP_REGNO 28) ; Frame pointer register
(EA_REGNO 29) ; Exception return address register (EA_REGNO 29) ; Exception return address register
(RA_REGNO 31) ; Return address register (RA_REGNO 31) ; Return address register
...@@ -92,9 +93,14 @@ ...@@ -92,9 +93,14 @@
; incuring a stall. ; incuring a stall.
; length of an instruction (in bytes) ; 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" (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")) (const_string "complex"))
(define_asm_attributes (define_asm_attributes
...@@ -118,11 +124,11 @@ ...@@ -118,11 +124,11 @@
"cpu") "cpu")
(define_insn_reservation "control" 1 (define_insn_reservation "control" 1
(eq_attr "type" "control") (eq_attr "type" "control,pop")
"cpu") "cpu")
(define_insn_reservation "alu" 1 (define_insn_reservation "alu" 1
(eq_attr "type" "alu") (eq_attr "type" "alu,add,sub,mov,and,or,xor,neg,not")
"cpu") "cpu")
(define_insn_reservation "cond_alu" 1 (define_insn_reservation "cond_alu" 1
...@@ -130,7 +136,7 @@ ...@@ -130,7 +136,7 @@
"cpu") "cpu")
(define_insn_reservation "st" 1 (define_insn_reservation "st" 1
(eq_attr "type" "st") (eq_attr "type" "st,stwm,push")
"cpu") "cpu")
(define_insn_reservation "custom" 1 (define_insn_reservation "custom" 1
...@@ -139,11 +145,11 @@ ...@@ -139,11 +145,11 @@
; shifts, muls and lds have three cycle latency ; shifts, muls and lds have three cycle latency
(define_insn_reservation "ld" 3 (define_insn_reservation "ld" 3
(eq_attr "type" "ld") (eq_attr "type" "ld,ldwm")
"cpu") "cpu")
(define_insn_reservation "shift" 3 (define_insn_reservation "shift" 3
(eq_attr "type" "shift") (eq_attr "type" "sll,srl,sra,rol,ror")
"cpu") "cpu")
(define_insn_reservation "mul" 3 (define_insn_reservation "mul" 3
...@@ -171,46 +177,90 @@ ...@@ -171,46 +177,90 @@
DONE; 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" (define_insn "movqi_internal"
[(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r")
(match_operand:QI 1 "general_operand" "rM,m,rM,I"))] (match_operand:QI 1 "general_operand" "rM,m,rI"))]
"(register_operand (operands[0], QImode) "(register_operand (operands[0], QImode)
|| reg_or_0_operand (operands[1], QImode))" || reg_or_0_operand (operands[1], QImode))"
"@ {
stb%o0\\t%z1, %0 switch (which_alternative)
ldbu%o1\\t%0, %1 {
mov\\t%0, %z1 case 0:
movi\\t%0, %1" if (get_attr_length (insn) != 2)
[(set_attr "type" "st,ld,alu,alu")]) 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" (define_insn "movhi_internal"
[(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r") [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r")
(match_operand:HI 1 "general_operand" "rM,m,rM,I"))] (match_operand:HI 1 "general_operand" "rM,m,rI"))]
"(register_operand (operands[0], HImode) "(register_operand (operands[0], HImode)
|| reg_or_0_operand (operands[1], HImode))" || reg_or_0_operand (operands[1], HImode))"
"@ "@
sth%o0\\t%z1, %0 sth%o0%.\\t%z1, %0
ldhu%o1\\t%0, %1 ldhu%o1%.\\t%0, %1
mov\\t%0, %z1 mov%i1%.\\t%0, %z1"
movi\\t%0, %1" [(set_attr "type" "st,ld,mov")])
[(set_attr "type" "st,ld,alu,alu")])
(define_insn "movsi_internal" (define_insn "movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r,r") [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r")
(match_operand:SI 1 "general_operand" "rM,m,rM,I,J,K,S,i"))] (match_operand:SI 1 "general_operand" "rM,m,rIJK,S"))]
"(register_operand (operands[0], SImode) "(register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))" || reg_or_0_operand (operands[1], SImode))"
"@ {
stw%o0\\t%z1, %0 switch (which_alternative)
ldw%o1\\t%0, %1 {
mov\\t%0, %z1 case 0:
movi\\t%0, %1 if (get_attr_length (insn) != 2)
movui\\t%0, %1 return "stw%o0\\t%z1, %0";
movhi\\t%0, %H1 else if (stack_memory_operand (operands[0], SImode))
addi\\t%0, gp, %%gprel(%1) return "stwsp.n\\t%z1, %0";
movhi\\t%0, %H1\;addi\\t%0, %0, %L1" else if (const_0_operand (operands[1], SImode))
[(set_attr "type" "st,ld,alu,alu,alu,alu,alu,alu") return "stwz.n\\t%z1, %0";
(set_attr "length" "4,4,4,4,4,4,4,8")]) 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 BH [QI HI])
(define_mode_iterator BHW [QI HI SI]) (define_mode_iterator BHW [QI HI SI])
...@@ -264,18 +314,18 @@ ...@@ -264,18 +314,18 @@
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
"" ""
"@ "@
andi\\t%0, %1, 0xffff andi%.\\t%0, %1, 0xffff
ldhu%o1\\t%0, %1" ldhu%o1%.\\t%0, %1"
[(set_attr "type" "alu,ld")]) [(set_attr "type" "and,ld")])
(define_insn "zero_extendqi<mode>2" (define_insn "zero_extendqi<mode>2"
[(set (match_operand:QX 0 "register_operand" "=r,r") [(set (match_operand:QX 0 "register_operand" "=r,r")
(zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))] (zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
"" ""
"@ "@
andi\\t%0, %1, 0xff andi%.\\t%0, %1, 0xff
ldbu%o1\\t%0, %1" ldbu%o1%.\\t%0, %1"
[(set_attr "type" "alu,ld")]) [(set_attr "type" "and,ld")])
;; Sign extension patterns ;; Sign extension patterns
...@@ -285,7 +335,7 @@ ...@@ -285,7 +335,7 @@
"" ""
"@ "@
# #
ldh%o1\\t%0, %1" ldh%o1%.\\t%0, %1"
[(set_attr "type" "alu,ld")]) [(set_attr "type" "alu,ld")])
(define_insn "extendqi<mode>2" (define_insn "extendqi<mode>2"
...@@ -294,7 +344,7 @@ ...@@ -294,7 +344,7 @@
"" ""
"@ "@
# #
ldb%o1\\t%0, %1" ldb%o1%.\\t%0, %1"
[(set_attr "type" "alu,ld")]) [(set_attr "type" "alu,ld")])
;; Split patterns for register alternative cases. ;; Split patterns for register alternative cases.
...@@ -331,16 +381,18 @@ ...@@ -331,16 +381,18 @@
(plus:SI (match_operand:SI 1 "register_operand" "%r") (plus:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "add_regimm_operand" "rIT")))] (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" (define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
(match_operand:SI 2 "register_operand" "r")))] (match_operand:SI 2 "register_operand" "r")))]
"" ""
"sub\\t%0, %z1, %2" "sub%.\\t%0, %z1, %2"
[(set_attr "type" "alu")]) [(set_attr "type" "sub")])
(define_insn "mulsi3" (define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
...@@ -422,32 +474,47 @@ ...@@ -422,32 +474,47 @@
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "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" (define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "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 ;; Integer logical Operations
(define_code_iterator LOGICAL [and ior xor]) (define_insn "andsi3"
(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")]) [(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 "<code>si3" (define_insn "<code>si3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r") [(set (match_operand:SI 0 "register_operand" "=r")
(LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r") (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "logical_operand" "rM,J,K")))] (match_operand:SI 2 "logical_operand" "rJK")))]
"" ""
"@ "<logical_asm>%x2%.\\t%0, %1, %y2"
<logical_asm>\\t%0, %1, %z2 [(set_attr "type" "<logical_asm>")])
<logical_asm>%i2\\t%0, %1, %2
<logical_asm>h%i2\\t%0, %1, %U2"
[(set_attr "type" "alu")])
(define_insn "*norsi3" (define_insn "*norsi3"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
...@@ -471,8 +538,8 @@ ...@@ -471,8 +538,8 @@
(SHIFT:SI (match_operand:SI 1 "register_operand" "r") (SHIFT:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "shift_operand" "rL")))] (match_operand:SI 2 "shift_operand" "rL")))]
"" ""
"<shift_asm>%i2\\t%0, %1, %z2" "<shift_asm>%i2%.\\t%0, %1, %z2"
[(set_attr "type" "shift")]) [(set_attr "type" "<shift_asm>")])
(define_insn "rotrsi3" (define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
...@@ -480,7 +547,48 @@ ...@@ -480,7 +547,48 @@
(match_operand:SI 2 "register_operand" "r")))] (match_operand:SI 2 "register_operand" "r")))]
"" ""
"ror\\t%0, %1, %2" "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 ;; Floating point instructions
...@@ -635,15 +743,16 @@ ...@@ -635,15 +743,16 @@
DONE; DONE;
}) })
(define_insn "return" (define_expand "return"
[(simple_return)] [(simple_return)]
"nios2_can_use_return_insn ()" "nios2_can_use_return_insn ()"
"ret") "")
(define_insn "simple_return" (define_insn "simple_return"
[(simple_return)] [(simple_return)]
"" ""
"ret") "ret%."
[(set_attr "type" "control")])
;; Block any insns from being moved before this point, since the ;; Block any insns from being moved before this point, since the
;; profiling call to mcount can use various registers that aren't ;; profiling call to mcount can use various registers that aren't
...@@ -699,7 +808,7 @@ ...@@ -699,7 +808,7 @@
(define_insn "indirect_jump" (define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "c"))] [(set (pc) (match_operand:SI 0 "register_operand" "c"))]
"" ""
"jmp\\t%0" "jmp%!\\t%0"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
(define_insn "jump" (define_insn "jump"
...@@ -707,7 +816,9 @@ ...@@ -707,7 +816,9 @@
(label_ref (match_operand 0 "" "")))] (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"; return "br\\t%0";
else else
return "jmpi\\t%0"; return "jmpi\\t%0";
...@@ -715,11 +826,16 @@ ...@@ -715,11 +826,16 @@
[(set_attr "type" "control") [(set_attr "type" "control")
(set (attr "length") (set (attr "length")
(if_then_else (if_then_else
(and (ge (minus (match_dup 0) (pc)) (const_int -32768)) (and (match_test "TARGET_HAS_CDX")
(le (minus (match_dup 0) (pc)) (const_int 32764))) (and (ge (minus (match_dup 0) (pc)) (const_int -1022))
(const_int 4) (le (minus (match_dup 0) (pc)) (const_int 1022))))
(const_int 8)))]) (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" (define_expand "call"
[(parallel [(call (match_operand 0 "" "") [(parallel [(call (match_operand 0 "" "")
...@@ -743,7 +859,7 @@ ...@@ -743,7 +859,7 @@
"" ""
"@ "@
call\\t%0 call\\t%0
callr\\t%0" callr%.\\t%0"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
(define_insn "*call_value" (define_insn "*call_value"
...@@ -754,7 +870,7 @@ ...@@ -754,7 +870,7 @@
"" ""
"@ "@
call\\t%1 call\\t%1
callr\\t%1" callr%.\\t%1"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
(define_expand "sibcall" (define_expand "sibcall"
...@@ -779,7 +895,7 @@ ...@@ -779,7 +895,7 @@
"" ""
"@ "@
jmpi\\t%0 jmpi\\t%0
jmp\\t%0" jmp%!\\t%0"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
(define_insn "sibcall_value_internal" (define_insn "sibcall_value_internal"
...@@ -790,7 +906,7 @@ ...@@ -790,7 +906,7 @@
"" ""
"@ "@
jmpi\\t%1 jmpi\\t%1
jmp\\t%1" jmp%!\\t%1"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
(define_expand "tablejump" (define_expand "tablejump"
...@@ -814,7 +930,7 @@ ...@@ -814,7 +930,7 @@
(match_operand:SI 0 "register_operand" "c")) (match_operand:SI 0 "register_operand" "c"))
(use (label_ref (match_operand 1 "" "")))] (use (label_ref (match_operand 1 "" "")))]
"" ""
"jmp\\t%0" "jmp%!\\t%0"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
...@@ -868,18 +984,30 @@ ...@@ -868,18 +984,30 @@
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (pc)))]
"" ""
{ {
if (flag_pic || get_attr_length (insn) == 4) if (get_attr_length (insn) == 2)
return "b%0\t%z1, %z2, %l3"; return "b%0z.n\t%z1, %l3";
else else if (get_attr_length (insn) == 4)
return "b%R0\t%z1, %z2, .+8;jmpi\t%l3"; 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 "type" "control")
(set (attr "length") (set (attr "length")
(if_then_else (cond
(and (ge (minus (match_dup 3) (pc)) (const_int -32768)) [(and (match_test "nios2_cdx_narrow_form_p (insn)")
(le (minus (match_dup 3) (pc)) (const_int 32764))) (ge (minus (match_dup 3) (pc)) (const_int -126))
(const_int 4) (const_int 8)))]) (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 ;; Floating point comparisons
(define_code_iterator FCMP [eq ne gt ge le lt]) (define_code_iterator FCMP [eq ne gt ge le lt])
...@@ -917,7 +1045,7 @@ ...@@ -917,7 +1045,7 @@
(UCMP:SI (match_operand:SI 1 "reg_or_0_operand" "rM") (UCMP:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
(match_operand:SI 2 "uns_arith_operand" "rJ")))] (match_operand:SI 2 "uns_arith_operand" "rJ")))]
"" ""
"cmp<code>%i2\\t%0, %z1, %z2" "cmp<code>%u2\\t%0, %z1, %z2"
[(set_attr "type" "alu")]) [(set_attr "type" "alu")])
...@@ -951,8 +1079,8 @@ ...@@ -951,8 +1079,8 @@
(define_insn "nop" (define_insn "nop"
[(const_int 0)] [(const_int 0)]
"" ""
"nop" "nop%."
[(set_attr "type" "alu")]) [(set_attr "type" "nop")])
;; Connect 'sync' to 'memory_barrier' standard expand name ;; Connect 'sync' to 'memory_barrier' standard expand name
(define_expand "memory_barrier" (define_expand "memory_barrier"
...@@ -1000,7 +1128,7 @@ ...@@ -1000,7 +1128,7 @@
(define_insn "trap" (define_insn "trap"
[(trap_if (const_int 1) (const_int 3))] [(trap_if (const_int 1) (const_int 3))]
"" ""
"trap\\t3" "trap%.\\t3"
[(set_attr "type" "control")]) [(set_attr "type" "control")])
(define_insn "ctrapsi4" (define_insn "ctrapsi4"
...@@ -1009,9 +1137,16 @@ ...@@ -1009,9 +1137,16 @@
(match_operand:SI 2 "reg_or_0_operand" "rM")]) (match_operand:SI 2 "reg_or_0_operand" "rM")])
(match_operand 3 "const_int_operand" "i"))] (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 "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. ;; Load the GOT register.
(define_insn "load_got_register" (define_insn "load_got_register"
......
...@@ -55,6 +55,16 @@ ...@@ -55,6 +55,16 @@
(ior (match_operand 0 "const_logical_operand") (ior (match_operand 0 "const_logical_operand")
(match_operand 0 "register_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" (define_predicate "const_shift_operand"
(and (match_code "const_int") (and (match_code "const_int")
(match_test "SHIFT_INT (INTVAL (op))"))) (match_test "SHIFT_INT (INTVAL (op))")))
...@@ -84,6 +94,16 @@ ...@@ -84,6 +94,16 @@
false)); 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" (define_predicate "ldstio_memory_operand"
(match_code "mem") (match_code "mem")
{ {
......
...@@ -2991,6 +2991,9 @@ instead of @code{0} in the assembly output. ...@@ -2991,6 +2991,9 @@ instead of @code{0} in the assembly output.
Integer that is valid as an immediate operand for Integer that is valid as an immediate operand for
a custom instruction opcode. Range 0 to 255. a custom instruction opcode. Range 0 to 255.
@item P
An immediate operand for R2 andchi/andci instructions.
@item S @item S
Matches immediates which are addresses in the small Matches immediates which are addresses in the small
data section and therefore can be added to @code{gp} data section and therefore can be added to @code{gp}
......
2015-07-14 Sandra Loosemore <sandra@codesourcery.com>
Cesar Philippidis <cesar@codesourcery.com>
Chung-Lin Tang <cltang@codesourcery.com>
* 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 <azzaronea@gmail.com> 2015-07-14 Andrea Azzarone <azzaronea@gmail.com>
PR c++/65071 PR c++/65071
......
/* { 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.*" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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.*" } } */
/* { 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.*" } } */
/* { 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\\(.*\\)" } } */
/* { 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.*" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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.*" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-final { scan-assembler "trap\\t3" } } */ /* { dg-final { scan-assembler "trap\\t3|trap.n\\t3" } } */
/* Test the nios2 trap instruction */ /* Test the nios2 trap instruction */
void foo(void){ void foo(void){
......
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