rx: Split adddi3 and subdi3 after reload.
The formulation of the pre-reload pattern allows the lower_subreg pass to properly split the patterns. This also required re-writing rx_source_operand and related predicates to accept subregs. From-SVN: r168929
This commit is contained in:
parent
784f69be19
commit
8a5b544900
3 changed files with 225 additions and 51 deletions
|
@ -1,5 +1,16 @@
|
|||
2011-01-17 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/rx/predicates.md (rx_constshift_operand): Use match_test.
|
||||
(rx_restricted_mem_operand): New.
|
||||
(rx_shift_operand): Use register_operand.
|
||||
(rx_source_operand, rx_compare_operand): Likewise.
|
||||
* config/rx/rx.md (addsi3_flags): New expander.
|
||||
(adddi3): Rewrite as expander.
|
||||
(adc_internal, *adc_flags, adddi3_internal): New patterns.
|
||||
(subsi3_flags): New expander.
|
||||
(subdi3): Rewrite as expander.
|
||||
(sbb_internal, *sbb_flags, subdi3_internal): New patterns.
|
||||
|
||||
* config/rx/rx.c (RX_BUILTIN_SAT): Remove.
|
||||
(rx_init_builtins): Remove sat builtin.
|
||||
(rx_expand_builtin): Likewise.
|
||||
|
|
|
@ -37,19 +37,19 @@
|
|||
;; Only small integers or a value in a register are permitted.
|
||||
|
||||
(define_predicate "rx_shift_operand"
|
||||
(match_code "const_int,reg")
|
||||
{
|
||||
if (CONST_INT_P (op))
|
||||
return IN_RANGE (INTVAL (op), 0, 31);
|
||||
return true;
|
||||
}
|
||||
(ior (match_operand 0 "register_operand")
|
||||
(and (match_code "const_int")
|
||||
(match_test "IN_RANGE (INTVAL (op), 0, 31)")))
|
||||
)
|
||||
|
||||
(define_predicate "rx_constshift_operand"
|
||||
(match_code "const_int")
|
||||
{
|
||||
return IN_RANGE (INTVAL (op), 0, 31);
|
||||
}
|
||||
(and (match_code "const_int")
|
||||
(match_test "IN_RANGE (INTVAL (op), 0, 31)"))
|
||||
)
|
||||
|
||||
(define_predicate "rx_restricted_mem_operand"
|
||||
(and (match_code "mem")
|
||||
(match_test "rx_is_restricted_memory_address (XEXP (op, 0), mode)"))
|
||||
)
|
||||
|
||||
;; Check that the operand is suitable as the source operand
|
||||
|
@ -57,20 +57,9 @@
|
|||
;; and a restricted subset of memory addresses are allowed.
|
||||
|
||||
(define_predicate "rx_source_operand"
|
||||
(match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem")
|
||||
{
|
||||
if (CONSTANT_P (op))
|
||||
return rx_is_legitimate_constant (op);
|
||||
|
||||
if (! MEM_P (op))
|
||||
return true;
|
||||
|
||||
/* Do not allow size conversions whilst accessing memory. */
|
||||
if (GET_MODE (op) != mode)
|
||||
return false;
|
||||
|
||||
return rx_is_restricted_memory_address (XEXP (op, 0), mode);
|
||||
}
|
||||
(ior (match_operand 0 "register_operand")
|
||||
(match_operand 0 "immediate_operand")
|
||||
(match_operand 0 "rx_restricted_mem_operand"))
|
||||
)
|
||||
|
||||
;; Check that the operand is suitable as the source operand
|
||||
|
@ -79,16 +68,8 @@
|
|||
;; CONST_INTs are not.
|
||||
|
||||
(define_predicate "rx_compare_operand"
|
||||
(match_code "subreg,reg,mem")
|
||||
{
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
return REG_P (XEXP (op, 0));
|
||||
|
||||
if (! MEM_P (op))
|
||||
return true;
|
||||
|
||||
return rx_is_restricted_memory_address (XEXP (op, 0), mode);
|
||||
}
|
||||
(ior (match_operand 0 "register_operand")
|
||||
(match_operand 0 "rx_restricted_mem_operand"))
|
||||
)
|
||||
|
||||
;; Return true if OP is a store multiple operation. This looks like:
|
||||
|
|
|
@ -988,17 +988,127 @@
|
|||
(set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
|
||||
)
|
||||
|
||||
(define_insn "adddi3"
|
||||
[(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r")
|
||||
(plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0")
|
||||
(match_operand:DI 2 "rx_source_operand"
|
||||
"r,Sint08,Sint16,Sint24,i,Q")))
|
||||
;; A helper to expand the above with the CC_MODE filled in.
|
||||
(define_expand "addsi3_flags"
|
||||
[(parallel [(set (match_operand:SI 0 "register_operand")
|
||||
(plus:SI (match_operand:SI 1 "register_operand")
|
||||
(match_operand:SI 2 "rx_source_operand")))
|
||||
(set (reg:CC_ZSC CC_REG)
|
||||
(compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
|
||||
(const_int 0)))])]
|
||||
)
|
||||
|
||||
(define_insn "adc_internal"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
|
||||
(plus:SI
|
||||
(plus:SI
|
||||
(ltu:SI (reg:CC CC_REG) (const_int 0))
|
||||
(match_operand:SI 1 "register_operand" "%0,0,0,0,0,0"))
|
||||
(match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
|
||||
(clobber (reg:CC CC_REG))]
|
||||
"reload_completed"
|
||||
"adc %2,%0"
|
||||
[(set_attr "timings" "11,11,11,11,11,33")
|
||||
(set_attr "length" "3,4,5,6,7,6")]
|
||||
)
|
||||
|
||||
(define_insn "*adc_flags"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
|
||||
(plus:SI
|
||||
(plus:SI
|
||||
(ltu:SI (reg:CC CC_REG) (const_int 0))
|
||||
(match_operand:SI 1 "register_operand" "%0,0,0,0,0,0"))
|
||||
(match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
|
||||
(set (reg CC_REG)
|
||||
(compare
|
||||
(plus:SI
|
||||
(plus:SI
|
||||
(ltu:SI (reg:CC CC_REG) (const_int 0))
|
||||
(match_dup 1))
|
||||
(match_dup 2))
|
||||
(const_int 0)))]
|
||||
"reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
|
||||
"adc %2,%0"
|
||||
[(set_attr "timings" "11,11,11,11,11,33")
|
||||
(set_attr "length" "3,4,5,6,7,6")]
|
||||
)
|
||||
|
||||
(define_expand "adddi3"
|
||||
[(set (match_operand:DI 0 "register_operand" "")
|
||||
(plus:DI (match_operand:DI 1 "register_operand" "")
|
||||
(match_operand:DI 2 "rx_source_operand" "")))]
|
||||
""
|
||||
{
|
||||
rtx op0l, op0h, op1l, op1h, op2l, op2h;
|
||||
|
||||
op0l = gen_lowpart (SImode, operands[0]);
|
||||
op1l = gen_lowpart (SImode, operands[1]);
|
||||
op2l = gen_lowpart (SImode, operands[2]);
|
||||
op0h = gen_highpart (SImode, operands[0]);
|
||||
op1h = gen_highpart (SImode, operands[1]);
|
||||
op2h = gen_highpart_mode (SImode, DImode, operands[2]);
|
||||
|
||||
emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_insn_and_split "adddi3_internal"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(plus:SI (match_operand:SI 2 "register_operand" "r")
|
||||
(match_operand:SI 3 "rx_source_operand" "riQ")))
|
||||
(set (match_operand:SI 1 "register_operand" "=r")
|
||||
(plus:SI
|
||||
(plus:SI
|
||||
(ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
|
||||
(match_operand:SI 4 "register_operand" "%1"))
|
||||
(match_operand:SI 5 "rx_source_operand" "riQ")))
|
||||
(clobber (match_scratch:SI 6 "=&r"))
|
||||
(clobber (reg:CC CC_REG))]
|
||||
""
|
||||
"add\t%L2, %L0\n\tadc\t%H2, %H0"
|
||||
[(set_attr "timings" "22,22,22,22,22,44")
|
||||
(set_attr "length" "5,7,9,11,13,11")]
|
||||
)
|
||||
"#"
|
||||
"reload_completed"
|
||||
[(const_int 0)]
|
||||
{
|
||||
rtx op0l = operands[0];
|
||||
rtx op0h = operands[1];
|
||||
rtx op1l = operands[2];
|
||||
rtx op2l = operands[3];
|
||||
rtx op1h = operands[4];
|
||||
rtx op2h = operands[5];
|
||||
rtx scratch = operands[6];
|
||||
rtx x;
|
||||
|
||||
if (reg_overlap_mentioned_p (op0l, op1h))
|
||||
{
|
||||
emit_move_insn (scratch, op0l);
|
||||
op1h = scratch;
|
||||
if (reg_overlap_mentioned_p (op0l, op2h))
|
||||
op2h = scratch;
|
||||
}
|
||||
else if (reg_overlap_mentioned_p (op0l, op2h))
|
||||
{
|
||||
emit_move_insn (scratch, op0l);
|
||||
op2h = scratch;
|
||||
}
|
||||
|
||||
if (rtx_equal_p (op0l, op1l))
|
||||
;
|
||||
else if (rtx_equal_p (op0l, op2l))
|
||||
x = op1l, op1l = op2l, op2l = x;
|
||||
emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
|
||||
|
||||
if (rtx_equal_p (op0h, op1h))
|
||||
;
|
||||
else if (rtx_equal_p (op0h, op2h))
|
||||
x = op1h, op1h = op2h, op2h = x;
|
||||
else
|
||||
{
|
||||
emit_move_insn (op0h, op1h);
|
||||
op1h = op0h;
|
||||
}
|
||||
emit_insn (gen_adc_internal (op0h, op1h, op2h));
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_insn "andsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r")
|
||||
|
@ -1445,16 +1555,88 @@
|
|||
(set_attr "length" "2,2,6,3,5")]
|
||||
)
|
||||
|
||||
(define_insn "subdi3"
|
||||
[(set (match_operand:DI 0 "register_operand" "=r,r")
|
||||
(minus:DI (match_operand:DI 1 "register_operand" "0,0")
|
||||
(match_operand:DI 2 "rx_source_operand" "r,Q")))
|
||||
;; A helper to expand the above with the CC_MODE filled in.
|
||||
(define_expand "subsi3_flags"
|
||||
[(parallel [(set (match_operand:SI 0 "register_operand")
|
||||
(minus:SI (match_operand:SI 1 "register_operand")
|
||||
(match_operand:SI 2 "rx_source_operand")))
|
||||
(set (reg:CC_ZSC CC_REG)
|
||||
(compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
|
||||
(const_int 0)))])]
|
||||
)
|
||||
|
||||
(define_insn "sbb_internal"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r")
|
||||
(minus:SI
|
||||
(minus:SI
|
||||
(match_operand:SI 1 "register_operand" " 0,0")
|
||||
(match_operand:SI 2 "rx_compare_operand" " r,Q"))
|
||||
(geu:SI (reg:CC CC_REG) (const_int 0))))
|
||||
(clobber (reg:CC CC_REG))]
|
||||
"reload_completed"
|
||||
"sbb\t%2, %0"
|
||||
[(set_attr "timings" "11,33")
|
||||
(set_attr "length" "3,6")]
|
||||
)
|
||||
|
||||
(define_insn "*sbb_flags"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r")
|
||||
(minus:SI
|
||||
(minus:SI
|
||||
(match_operand:SI 1 "register_operand" " 0,0")
|
||||
(match_operand:SI 2 "rx_compare_operand" " r,Q"))
|
||||
(geu:SI (reg:CC CC_REG) (const_int 0))))
|
||||
(set (reg CC_REG)
|
||||
(compare
|
||||
(minus:SI
|
||||
(minus:SI (match_dup 1) (match_dup 2))
|
||||
(geu:SI (reg:CC CC_REG) (const_int 0)))
|
||||
(const_int 0)))]
|
||||
"reload_completed"
|
||||
"sbb\t%2, %0"
|
||||
[(set_attr "timings" "11,33")
|
||||
(set_attr "length" "3,6")]
|
||||
)
|
||||
|
||||
(define_expand "subdi3"
|
||||
[(set (match_operand:DI 0 "register_operand" "")
|
||||
(minus:DI (match_operand:DI 1 "register_operand" "")
|
||||
(match_operand:DI 2 "rx_source_operand" "")))]
|
||||
""
|
||||
{
|
||||
rtx op0l, op0h, op1l, op1h, op2l, op2h;
|
||||
|
||||
op0l = gen_lowpart (SImode, operands[0]);
|
||||
op1l = gen_lowpart (SImode, operands[1]);
|
||||
op2l = gen_lowpart (SImode, operands[2]);
|
||||
op0h = gen_highpart (SImode, operands[0]);
|
||||
op1h = gen_highpart (SImode, operands[1]);
|
||||
op2h = gen_highpart_mode (SImode, DImode, operands[2]);
|
||||
|
||||
emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_insn_and_split "subdi3_internal"
|
||||
[(set (match_operand:SI 0 "register_operand" "=&r,&r")
|
||||
(minus:SI (match_operand:SI 2 "register_operand" " 0, r")
|
||||
(match_operand:SI 3 "rx_source_operand" "rnQ, r")))
|
||||
(set (match_operand:SI 1 "register_operand" "= r, r")
|
||||
(minus:SI
|
||||
(minus:SI
|
||||
(match_operand:SI 4 "register_operand" " 1, 1")
|
||||
(match_operand:SI 5 "rx_compare_operand" " rQ,rQ"))
|
||||
(geu:SI (match_dup 2) (match_dup 3))))
|
||||
(clobber (reg:CC CC_REG))]
|
||||
""
|
||||
"sub\t%L2, %L0\n\tsbb\t%H2, %H0"
|
||||
[(set_attr "timings" "22,44")
|
||||
(set_attr "length" "5,11")]
|
||||
)
|
||||
"#"
|
||||
"reload_completed"
|
||||
[(const_int 0)]
|
||||
{
|
||||
emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));
|
||||
emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_insn "xorsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
|
||||
|
|
Loading…
Add table
Reference in a new issue