predicates.md (qi_mask_operand, [...]): New predicates.

* config/mips/predicates.md (qi_mask_operand, hi_mask_operand,
	si_mask_operand, and_load_operand, low_bitmask_operand,
	and_reg_operand, and_operand): New predicates.
	* config/mips/constraints.md (Yb, Yh, Yw, Yz): New constraints.
	* config/mips/mips.c (and_operands_ok): New function.
	* config/mips/mips-protos.h (and_operands_ok): Declare it.
	* config/mips/mips.md (move_type): Add ext_ins and logical.
	(type): Handle them.
	(and<mode>3): Use and_reg_operand as the second operand's
	predicate.
	(*and<mode>3): Add alternatives for lbu, lhu, lwu, <d>ext and
	shift_shift.  Remove commutative constraint modifier.
	(*and<mode>3_mips16): Add alternatives for lbu, lhu, lwu and
	shift_shift.
	(*clear_upper32_dext): Remove define_insn_and_split.
	(*clear_upper32): Turn this define_insn_and_split ...
	(splitter for ANDing register with 0xffff_ffff): .. into this.

testsuite/
	* gcc.target/mips/ext-5.c: New test.
	* gcc.target/mips/ext-6.c: New test.
	* gcc.target/mips/ext-7.c: New test.
	* gcc.target/mips/ext-8.c: New test.
	* gcc.target/mips/extend-2.c: New test.

From-SVN: r150657
This commit is contained in:
Adam Nemet 2009-08-11 17:41:09 +00:00 committed by Adam Nemet
parent 842e098c5f
commit b2c9d70fd7
12 changed files with 238 additions and 54 deletions

View File

@ -1,3 +1,23 @@
2009-08-11 Adam Nemet <anemet@caviumnetworks.com>
* config/mips/predicates.md (qi_mask_operand, hi_mask_operand,
si_mask_operand, and_load_operand, low_bitmask_operand,
and_reg_operand, and_operand): New predicates.
* config/mips/constraints.md (Yb, Yh, Yw, Yz): New constraints.
* config/mips/mips.c (and_operands_ok): New function.
* config/mips/mips-protos.h (and_operands_ok): Declare it.
* config/mips/mips.md (move_type): Add ext_ins and logical.
(type): Handle them.
(and<mode>3): Use and_reg_operand as the second operand's
predicate.
(*and<mode>3): Add alternatives for lbu, lhu, lwu, <d>ext and
shift_shift. Remove commutative constraint modifier.
(*and<mode>3_mips16): Add alternatives for lbu, lhu, lwu and
shift_shift.
(*clear_upper32_dext): Remove define_insn_and_split.
(*clear_upper32): Turn this define_insn_and_split ...
(splitter for ANDing register with 0xffff_ffff): .. into this.
2009-08-11 Adam Nemet <anemet@caviumnetworks.com>
* combine.c (try_widen_shift_mode): Factor out code to check if an

View File

@ -215,3 +215,19 @@
A signed 10-bit constant."
(and (match_code "const_int")
(match_test "IMM10_OPERAND (ival)")))
(define_constraint "Yb"
"@internal"
(match_operand 0 "qi_mask_operand"))
(define_constraint "Yh"
"@internal"
(match_operand 0 "hi_mask_operand"))
(define_constraint "Yw"
"@internal"
(match_operand 0 "si_mask_operand"))
(define_constraint "Yx"
"@internal"
(match_operand 0 "low_bitmask_operand"))

View File

@ -316,6 +316,7 @@ extern bool mips16e_save_restore_pattern_p (rtx, HOST_WIDE_INT,
extern bool mask_low_and_shift_p (enum machine_mode, rtx, rtx, int);
extern int mask_low_and_shift_len (enum machine_mode, rtx, rtx);
extern bool and_operands_ok (enum machine_mode, rtx, rtx);
union mips_gen_fn_ptrs
{

View File

@ -6786,6 +6786,18 @@ mask_low_and_shift_p (enum machine_mode mode, rtx mask, rtx shift, int maxlen)
return IN_RANGE (mask_low_and_shift_len (mode, mask, shift), 1, maxlen);
}
/* Return true iff OP1 and OP2 are valid operands together for the
*and<MODE>3 and *and<MODE>3_mips16 patterns. For the cases to consider,
see the table in the comment before the pattern. */
bool
and_operands_ok (enum machine_mode mode, rtx op1, rtx op2)
{
return (memory_operand (op1, mode)
? and_load_operand (op2, mode)
: and_reg_operand (op2, mode));
}
/* The canonical form of a mask-low-and-shift-left operation is
(and (ashift X SHIFT) MASK) where MASK has the lower SHIFT number of bits
cleared. Thus we need to shift MASK to the right before checking if it

View File

@ -301,6 +301,7 @@
;; sll0 "sll DEST,SRC,0", which on 64-bit targets is guaranteed
;; to produce a sign-extended DEST, even if SRC is not
;; properly sign-extended
;; ext_ins EXT, DEXT, INS or DINS instruction
;; andi a single ANDI instruction
;; loadpool move a constant into a MIPS16 register by loading it
;; from the pool
@ -313,7 +314,8 @@
;; scheduling type to be "multi" instead.
(define_attr "move_type"
"unknown,load,fpload,store,fpstore,mtc,mfc,mthilo,mfhilo,move,fmove,
const,constN,signext,arith,sll0,andi,loadpool,shift_shift,lui_movf"
const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool,
shift_shift,lui_movf"
(const_string "unknown"))
;; Main data type used by the insn
@ -408,7 +410,9 @@
(eq_attr "move_type" "fmove") (const_string "fmove")
(eq_attr "move_type" "loadpool") (const_string "load")
(eq_attr "move_type" "signext") (const_string "signext")
(eq_attr "move_type" "ext_ins") (const_string "arith")
(eq_attr "move_type" "arith") (const_string "arith")
(eq_attr "move_type" "logical") (const_string "logical")
(eq_attr "move_type" "sll0") (const_string "shift")
(eq_attr "move_type" "andi") (const_string "logical")
@ -2561,31 +2565,91 @@
(define_expand "and<mode>3"
[(set (match_operand:GPR 0 "register_operand")
(and:GPR (match_operand:GPR 1 "register_operand")
(match_operand:GPR 2 "uns_arith_operand")))]
""
{
if (TARGET_MIPS16)
operands[2] = force_reg (<MODE>mode, operands[2]);
})
(match_operand:GPR 2 "and_reg_operand")))])
;; The middle-end is not allowed to convert ANDing with 0xffff_ffff into a
;; zero_extendsidi2 because of TRULY_NOOP_TRUNCATION, so handle these here.
;; Note that this variant does not trigger for SI mode because we require
;; a 64-bit HOST_WIDE_INT and 0xffff_ffff wouldn't be a canonical
;; sign-extended SImode value.
;;
;; These are possible combinations for operand 1 and 2. The table
;; includes both MIPS and MIPS16 cases. (r=register, mem=memory,
;; 16=MIPS16, x=match, S=split):
;;
;; \ op1 r/EXT r/!EXT mem r/16 mem/16
;; op2
;;
;; andi x x
;; 0xff x x x x
;; 0xffff x x x x
;; 0xffff_ffff x S x S x
;; low-bitmask x
;; register x x
;; register =op1 x
(define_insn "*and<mode>3"
[(set (match_operand:GPR 0 "register_operand" "=d,d")
(and:GPR (match_operand:GPR 1 "register_operand" "%d,d")
(match_operand:GPR 2 "uns_arith_operand" "d,K")))]
"!TARGET_MIPS16"
"@
and\t%0,%1,%2
andi\t%0,%1,%x2"
[(set_attr "type" "logical")
[(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
(match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
"!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
{
int len;
switch (which_alternative)
{
case 0:
operands[1] = gen_lowpart (QImode, operands[1]);
return "lbu\t%0,%1";
case 1:
operands[1] = gen_lowpart (HImode, operands[1]);
return "lhu\t%0,%1";
case 2:
operands[1] = gen_lowpart (SImode, operands[1]);
return "lwu\t%0,%1";
case 3:
return "andi\t%0,%1,%x2";
case 4:
len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
operands[2] = GEN_INT (len);
return "<d>ext\t%0,%1,0,%2";
case 5:
return "#";
case 6:
return "and\t%0,%1,%2";
default:
gcc_unreachable ();
}
}
[(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
(set_attr "mode" "<MODE>")])
(define_insn "*and<mode>3_mips16"
[(set (match_operand:GPR 0 "register_operand" "=d")
(and:GPR (match_operand:GPR 1 "register_operand" "%0")
(match_operand:GPR 2 "register_operand" "d")))]
"TARGET_MIPS16"
"and\t%0,%2"
[(set_attr "type" "logical")
[(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%o,o,W,d,0")
(match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d")))]
"TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
{
switch (which_alternative)
{
case 0:
operands[1] = gen_lowpart (QImode, operands[1]);
return "lbu\t%0,%1";
case 1:
operands[1] = gen_lowpart (HImode, operands[1]);
return "lhu\t%0,%1";
case 2:
operands[1] = gen_lowpart (SImode, operands[1]);
return "lwu\t%0,%1";
case 3:
return "#";
case 4:
return "and\t%0,%2";
default:
gcc_unreachable ();
}
}
[(set_attr "move_type" "load,load,load,shift_shift,logical")
(set_attr "mode" "<MODE>")])
(define_expand "ior<mode>3"
@ -2778,44 +2842,18 @@
[(set_attr "move_type" "arith,load")
(set_attr "mode" "DI")])
;; Combine is not allowed to convert this insn into a zero_extendsidi2
;; because of TRULY_NOOP_TRUNCATION.
;; See the comment before the *and<mode>3 pattern why this is generated by
;; combine.
(define_insn_and_split "*clear_upper32"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(and:DI (match_operand:DI 1 "nonimmediate_operand" "d,W")
(define_split
[(set (match_operand:DI 0 "register_operand")
(and:DI (match_operand:DI 1 "register_operand")
(const_int 4294967295)))]
"TARGET_64BIT && !ISA_HAS_EXT_INS"
{
if (which_alternative == 0)
return "#";
operands[1] = gen_lowpart (SImode, operands[1]);
return "lwu\t%0,%1";
}
"&& reload_completed && REG_P (operands[1])"
"TARGET_64BIT && !ISA_HAS_EXT_INS && reload_completed"
[(set (match_dup 0)
(ashift:DI (match_dup 1) (const_int 32)))
(set (match_dup 0)
(lshiftrt:DI (match_dup 0) (const_int 32)))]
""
[(set_attr "move_type" "shift_shift,load")
(set_attr "mode" "DI")])
(define_insn "*clear_upper32_dext"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(and:DI (match_operand:DI 1 "nonimmediate_operand" "d,W")
(const_int 4294967295)))]
"TARGET_64BIT && ISA_HAS_EXT_INS"
{
if (which_alternative == 0)
return "dext\t%0,%1,0,32";
operands[1] = gen_lowpart (SImode, operands[1]);
return "lwu\t%0,%1";
}
[(set_attr "move_type" "arith,load")
(set_attr "mode" "DI")])
(lshiftrt:DI (match_dup 0) (const_int 32)))])
(define_expand "zero_extend<SHORT:mode><GPR:mode>2"
[(set (match_operand:GPR 0 "register_operand")

View File

@ -76,6 +76,39 @@
(ior (match_test "op == CONST0_RTX (GET_MODE (op))")
(match_test "op == CONST1_RTX (GET_MODE (op))"))))
(define_predicate "qi_mask_operand"
(and (match_code "const_int")
(match_test "UINTVAL (op) == 0xff")))
(define_predicate "hi_mask_operand"
(and (match_code "const_int")
(match_test "UINTVAL (op) == 0xffff")))
(define_predicate "si_mask_operand"
(and (match_code "const_int")
(match_test "UINTVAL (op) == 0xffffffff")))
(define_predicate "and_load_operand"
(ior (match_operand 0 "qi_mask_operand")
(match_operand 0 "hi_mask_operand")
(match_operand 0 "si_mask_operand")))
(define_predicate "low_bitmask_operand"
(and (match_test "ISA_HAS_EXT_INS")
(match_code "const_int")
(match_test "low_bitmask_len (mode, INTVAL (op)) > 16")))
(define_predicate "and_reg_operand"
(ior (match_operand 0 "register_operand")
(and (match_test "!TARGET_MIPS16")
(match_operand 0 "const_uns_arith_operand"))
(match_operand 0 "low_bitmask_operand")
(match_operand 0 "si_mask_operand")))
(define_predicate "and_operand"
(ior (match_operand 0 "and_load_operand")
(match_operand 0 "and_reg_operand")))
(define_predicate "d_operand"
(and (match_code "reg")
(match_test "TARGET_MIPS16

View File

@ -1,3 +1,11 @@
2009-08-11 Adam Nemet <anemet@caviumnetworks.com>
* gcc.target/mips/ext-5.c: New test.
* gcc.target/mips/ext-6.c: New test.
* gcc.target/mips/ext-7.c: New test.
* gcc.target/mips/ext-8.c: New test.
* gcc.target/mips/extend-2.c: New test.
2009-08-10 Jason Merrill <jason@redhat.com>
* g++.dg/other/linkage2.C: New test for types-without-linkage

View File

@ -0,0 +1,11 @@
/* For MIPS32r2 use EXT when ANDing with low-order bitmasks. */
/* { dg-do compile } */
/* { dg-options "-O isa_rev>=2" } */
/* { dg-final { scan-assembler "\text\t" } } */
/* { dg-final { scan-assembler-not "\tandi?\t" } } */
NOMIPS16 unsigned
f (unsigned i)
{
return i & 0x7ffffff;
}

View File

@ -0,0 +1,11 @@
/* For MIPS64r2 use DEXT when ANDing with low-order bitmasks. */
/* { dg-do compile } */
/* { dg-options "-O isa_rev>=2 -mgp64" } */
/* { dg-final { scan-assembler "\tdext\t" } } */
/* { dg-final { scan-assembler-not "\tandi?\t" } } */
NOMIPS16 unsigned long long
f (unsigned long long i)
{
return i & 0x7ffffffffff;
}

View File

@ -0,0 +1,11 @@
/* No need to use ext if we can use andi. */
/* { dg-do compile } */
/* { dg-options "-O isa_rev>=2" } */
/* { dg-final { scan-assembler "\tandi\t" } } */
/* { dg-final { scan-assembler-not "\td?ext\t" } } */
NOMIPS16 unsigned
f (unsigned i)
{
return i & 0x7fff;
}

View File

@ -0,0 +1,11 @@
/* Also make sure we don't use ext for MIPS*r1. */
/* { dg-do compile } */
/* { dg-options "-O isa_rev<=1" } */
/* { dg-final { scan-assembler "\tand\t" } } */
/* { dg-final { scan-assembler-not "\td?ext\t" } } */
unsigned
f (unsigned i)
{
return i & 0x7fffff;
}

View File

@ -0,0 +1,12 @@
/* Check the shift_shift alternative of the AND patterns. */
/* { dg-do compile } */
/* { dg-options "-O isa_rev<=1 -mgp64" } */
/* { dg-final { scan-assembler "\tdsrl\t" } } */
/* { dg-final { scan-assembler "\tdsll\t" } } */
/* { dg-final { scan-assembler-not "\td?ext\t" } } */
unsigned long long
f (unsigned long long i)
{
return i & 0xffffffff;
}