;; [rX=gotless_symbol].
;; The movsi for a gotless symbol could be split (post reload).
\f
-;; UNSPEC Usage:
-;; 0 PLT reference from call expansion: operand 0 is the address,
-;; the mode is VOIDmode. Always wrapped in CONST.
-;; 1 Stack frame deallocation barrier.
-;; 2 The address of the global offset table as a source operand.
-;; 3 The address of a global-offset-table-relative symbol + offset.
-;; 4 The offset within GOT of a symbol.
-;; 5 The offset within GOT of a symbol that has a PLT.
-
-(define_constants ; FIXME: reorder sanely.
- [(CRIS_UNSPEC_PLT 0)
- (CRIS_UNSPEC_FRAME_DEALLOC 1)
+
+(define_constants
+ [
+ ;; PLT reference from call expansion: operand 0 is the address,
+ ;; the mode is VOIDmode. Always wrapped in CONST.
+ ;; The value is relative to the GOT.
+ (CRIS_UNSPEC_PLT_GOTREL 0)
+
+ ;; PLT reference from call expansion: operand 0 is the address,
+ ;; the mode is VOIDmode. Always wrapped in CONST.
+ ;; The value is relative to the PC. It's arch-dependent whether
+ ;; the offset counts from the start or the end of the current item.
+ (CRIS_UNSPEC_PLT_PCREL 1)
+
+ ;; The address of the global offset table as a source operand.
(CRIS_UNSPEC_GOT 2)
+
+ ;; The offset from the global offset table to the operand.
(CRIS_UNSPEC_GOTREL 3)
- (CRIS_UNSPEC_GOTREAD 4)
- (CRIS_UNSPEC_PLTGOTREAD 5)
- (CRIS_UNSPEC_SWAP_BITS 6)])
+
+ ;; The PC-relative offset to the operand. It's arch-dependent whether
+ ;; the offset counts from the start or the end of the current item.
+ (CRIS_UNSPEC_PCREL 4)
+
+ ;; The index into the global offset table of a symbol, while
+ ;; also generating a GOT entry for the symbol.
+ (CRIS_UNSPEC_GOTREAD 5)
+
+ ;; Similar to CRIS_UNSPEC_GOTREAD, but also generating a PLT entry.
+ (CRIS_UNSPEC_PLTGOTREAD 6)
+
+ ;; Condition for v32 casesi jump, since it needs to have if_then_else
+ ;; form with register as one branch and default label as other.
+ ;; Operand 0 is const_int 0.
+ (CRIS_UNSPEC_CASESI 7)
+
+ ;; Stack frame deallocation barrier.
+ (CRIS_UNSPEC_FRAME_DEALLOC 8)
+
+ ;; Swap all 32 bits of the operand; 31 <=> 0, 30 <=> 1...
+ (CRIS_UNSPEC_SWAP_BITS 9)
+ ])
;; Register numbers.
(define_constants
(CRIS_STATIC_CHAIN_REGNUM 7)
(CRIS_FP_REGNUM 8)
(CRIS_SP_REGNUM 14)
+ (CRIS_ACR_REGNUM 15)
(CRIS_SRP_REGNUM 16)
(CRIS_MOF_REGNUM 17)
(CRIS_AP_REGNUM 18)
;; In short, any "slottable" instruction must be 16 bit and not refer
;; to pc, or alter it.
;;
-;; The possible values are "yes", "no" and "has_slot". Yes/no means if
-;; the insn is slottable or not. Has_slot means that the insn is a
-;; return insn or branch insn (which are not considered slottable since
-;; that is generally true). Having the seemingly illogical value
-;; "has_slot" means we do not have to add another attribute just to say
-;; that an insn has a delay-slot, since it also infers that it is not
-;; slottable. Better names for the attribute were found to be longer and
-;; not add readability to the machine description.
+;; The possible values are "yes", "no", "has_slot", "has_return_slot"
+;; and "has_call_slot".
+;; Yes/no tells whether the insn is slottable or not. Has_call_slot means
+;; that the insn is a call insn, which for CRIS v32 has a delay-slot.
+;; Of special concern is that no RTX_FRAME_RELATED insn must go in that
+;; call delay slot, as it's located in the address *after* the call insn,
+;; and the unwind machinery doesn't know about delay slots.
+;; Has_slot means that the insn is a branch insn (which are
+;; not considered slottable since that is generally true). Having the
+;; seemingly illogical value "has_slot" means we do not have to add
+;; another attribute just to say that an insn has a delay-slot, since it
+;; also infers that it is not slottable. Better names for the attribute
+;; were found to be longer and not add readability to the machine
+;; description.
+;; Has_return_slot is similar, for the return insn.
;;
;; The default that is defined here for this attribute is "no", not
;; slottable, not having a delay-slot, so there's no need to worry about
;; constraint pattern for the slottable pattern. An alternative using
;; only "r" constraints is most often slottable.
-(define_attr "slottable" "no,yes,has_slot" (const_string "no"))
+(define_attr "slottable" "no,yes,has_slot,has_return_slot,has_call_slot"
+ (const_string "no"))
;; We also need attributes to sanely determine the condition code
;; state. See cris_notice_update_cc for how this is used.
-(define_attr "cc" "none,clobber,normal" (const_string "normal"))
+(define_attr "cc" "none,clobber,normal,noov32,rev" (const_string "normal"))
;; At the moment, this attribute is just used to help bb-reorder do its
;; work; the default 0 doesn't help it. Many insns have other lengths,
;; though none are shorter.
(define_attr "length" "" (const_int 2))
-;; A branch or return has one delay-slot. The instruction in the
+;; A branch has one delay-slot. The instruction in the
;; delay-slot is always executed, independent of whether the branch is
;; taken or not. Note that besides setting "slottable" to "has_slot",
;; there also has to be a "%#" at the end of a "delayed" instruction
(define_delay (eq_attr "slottable" "has_slot")
[(eq_attr "slottable" "yes") (nil) (nil)])
+
+;; We can't put prologue insns in call-insn delay-slots when
+;; DWARF2 unwind info is emitted, because the unwinder matches the
+;; address after the insn. It must see the return address of a call at
+;; a position at least *one byte after* the insn, or it'll think that
+;; the insn hasn't been executed. If the insn is in a delay-slot of a
+;; call, it's just *exactly* after the insn.
+
+(define_delay (eq_attr "slottable" "has_call_slot")
+ [(and (eq_attr "slottable" "yes")
+ (ior (eq (symbol_ref "RTX_FRAME_RELATED_P (insn)")
+ (const_int 0))
+ (eq (symbol_ref "flag_exceptions")
+ (const_int 0))))
+ (nil) (nil)])
+
+;; The insn in the return insn slot must not be the
+;; return-address-register restore. FIXME: Use has_slot and express
+;; as a parallel with a use of the return-address-register (currently
+;; only SRP). However, this requires an amount of fixing tests for
+;; naked RETURN in middle-end.
+(define_delay (eq_attr "slottable" "has_return_slot")
+ [(and (eq_attr "slottable" "yes")
+ (eq (symbol_ref "dead_or_set_regno_p (insn, CRIS_SRP_REGNUM)")
+ (const_int 0)))
+ (nil) (nil)])
+
\f
;; Iterator definitions.
;; Allow register and offsettable mem operands only; post-increment is
;; not worth the trouble.
-(define_insn "tstdi"
+(define_expand "tstdi"
+ [(set (cc0) (match_operand:DI 0 "nonimmediate_operand"))]
+ ""
+{
+ if (TARGET_V32 && MEM_P (operands[0]))
+ operands[0] = force_reg (DImode, operands[0]);
+})
+
+(define_insn "*tstdi_non_v32"
[(set (cc0)
(match_operand:DI 0 "nonimmediate_operand" "r,o"))]
- ""
+ "!TARGET_V32"
"test.d %M0\;ax\;test.d %H0")
+(define_insn "*tstdi_v32"
+ [(set (cc0)
+ (match_operand:DI 0 "register_operand" "r"))]
+ "TARGET_V32"
+ "cmpq 0,%M0\;ax\;cmpq 0,%H0")
+
;; No test insns with side-effect on the mem addressing.
;;
;; See note on cmp-insns with side-effects (or lack of them)
;; Normal named test patterns from SI on.
-;; FIXME: Seems they should change to be in order smallest..largest.
-(define_insn "tst<mode>"
+(define_insn "tstsi"
[(set (cc0)
- (match_operand:BWD 0 "nonimmediate_operand" "r,Q>,m"))]
+ (match_operand:SI 0 "nonimmediate_operand" "r,Q>,m"))]
""
- "test<m> %0"
+{
+ if (which_alternative == 0 && TARGET_V32)
+ return "cmpq 0,%0";
+ return "test.d %0";
+}
[(set_attr "slottable" "yes,yes,no")])
+(define_expand "tst<mode>"
+ [(set (cc0)
+ (match_operand:BW 0 "nonimmediate_operand"))]
+ ""
+ "")
+
+(define_insn "*tst<mode>_cmp"
+ [(set (cc0)
+ (match_operand:BW 0 "nonimmediate_operand" "r,Q>,m"))]
+ "cris_cc0_user_requires_cmp (insn)"
+ "@
+ cmp<m> 0,%0
+ test<m> %0
+ test<m> %0"
+ [(set_attr "slottable" "no,yes,no")])
+
+(define_insn "*tst<mode>_non_cmp"
+ [(set (cc0)
+ (match_operand:BW 0 "nonimmediate_operand" "r,Q>,m"))]
+ "!cris_cc0_user_requires_cmp (insn)"
+ "@
+ move<m> %0,%0
+ test<m> %0
+ test<m> %0"
+ [(set_attr "slottable" "yes,yes,no")
+ (set_attr "cc" "noov32,*,*")])
+
;; It seems that the position of the sign-bit and the fact that 0.0 is
;; all 0-bits would make "tstsf" a straight-forward implementation;
;; either "test.d" it for positive/negative or "btstq 30,r" it for
;; DImode for anything else but a structure/block-mode. Just do the
;; obvious stuff for the straight-forward constraint letters.
-(define_insn "cmpdi"
+(define_expand "cmpdi"
+ [(set (cc0)
+ (compare (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" "")))]
+ ""
+{
+ if (TARGET_V32 && !REG_P (operands[0]))
+ operands[0] = force_reg (DImode, operands[0]);
+ if (TARGET_V32 && MEM_P (operands[1]))
+ operands[1] = force_reg (DImode, operands[1]);
+})
+
+(define_insn "*cmpdi_non_v32"
[(set (cc0)
(compare (match_operand:DI 0 "nonimmediate_operand" "r,r,r,r,r,r,o")
(match_operand:DI 1 "general_operand" "K,I,P,n,r,o,r")))]
- ""
+ "!TARGET_V32"
"@
cmpq %1,%M0\;ax\;cmpq 0,%H0
cmpq %1,%M0\;ax\;cmpq -1,%H0
cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
cmp.d %M0,%M1\;ax\;cmp.d %H0,%H1")
+(define_insn "*cmpdi_v32"
+ [(set (cc0)
+ (compare (match_operand:DI 0 "register_operand" "r,r,r,r,r")
+ (match_operand:DI 1 "nonmemory_operand" "K,I,P,n,r")))]
+ "TARGET_V32"
+ "@
+ cmpq %1,%M0\;ax\;cmpq 0,%H0
+ cmpq %1,%M0\;ax\;cmpq -1,%H0
+ cmp%e1.%z1 %1,%M0\;ax\;cmpq %H1,%H0
+ cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
+ cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0")
+
;; Note that compare insns with side effect addressing mode (e.g.):
;;
;; cmp.S [rx=ry+i],rz;
[(match_operand:BW 0 "memory_operand" "Q>,m")])
(match_operand:SI 1 "register_operand" "r,r")))]
""
- "cmp%e2<m> %0,%1" ; The function cris_notice_update_cc knows about
- ; swapped operands to compares.
- [(set_attr "slottable" "yes,no")])
+ "cmp%e2<m> %0,%1"
+ [(set_attr "slottable" "yes,no")
+ (set_attr "cc" "rev")])
\f
-;; The "normal" compare patterns, from SI on.
+;; The "normal" compare patterns, from SI on. Special-cases with zero
+;; should not happen.
(define_insn "cmpsi"
[(set (cc0)
(compare
- (match_operand:SI 0 "nonimmediate_operand" "r,r,r, r,Q>,Q>,r,r,m,m")
- (match_operand:SI 1 "general_operand" "I,r,Q>,M,M, r, P,g,M,r")))]
+ (match_operand:SI 0 "nonimmediate_operand" "r,r,r, Q>,r,r,m")
+ (match_operand:SI 1 "general_operand" "I,r,Q>,r, P,g,r")))]
""
"@
cmpq %1,%0
cmp.d %1,%0
cmp.d %1,%0
- test.d %0
- test.d %0
cmp.d %0,%1
cmp%e1.%z1 %1,%0
cmp.d %1,%0
- test.d %0
cmp.d %0,%1"
- [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no")])
+ [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")
+ (set_attr "cc" "normal,normal,normal,rev,normal,normal,rev")])
(define_insn "cmp<mode>"
[(set (cc0)
- (compare
- (match_operand:BW 0 "nonimmediate_operand" "r,r, r,Q>,Q>,r,m,m")
- (match_operand:BW 1 "general_operand" "r,Q>,M,M, r, g,M,r")))]
+ (compare (match_operand:BW 0 "nonimmediate_operand" "r,r, Q>,r,m")
+ (match_operand:BW 1 "general_operand" "r,Q>,r, g,r")))]
""
"@
cmp<m> %1,%0
cmp<m> %1,%0
- test<m> %0
- test<m> %0
cmp<m> %0,%1
cmp<m> %1,%0
- test<m> %0
cmp<m> %0,%1"
- [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+ [(set_attr "slottable" "yes,yes,yes,no,no")
+ (set_attr "cc" "normal,normal,rev,normal,rev")])
\f
;; Pattern matching the BTST insn.
;; It is useful for "if (i & val)" constructs, where val is an exact
(match_operand:SI 1 "const_int_operand" "K,n,K,n,K,n,n")
(match_operand:SI 2 "nonmemory_operand" "M,M,K,n,r,r,r")))]
;; Either it is a single bit, or consecutive ones starting at 0.
+ ;; The btst ones depend on stuff in NOTICE_UPDATE_CC.
"CONST_INT_P (operands[1])
&& (operands[1] == const1_rtx || operands[2] == const0_rtx)
&& (REG_S_P (operands[0])
|| (operands[1] == const1_rtx
&& REG_S_P (operands[2])
&& CONST_INT_P (operands[0])
- && exact_log2 (INTVAL (operands[0])) >= 0))"
+ && exact_log2 (INTVAL (operands[0])) >= 0))
+ && !TARGET_CCINIT"
-;; The last "&&" condition above should be caught by some kind of
+;; The next-to-last "&&" condition above should be caught by some kind of
;; canonicalization in gcc, but we can easily help with it here.
;; It results from expressions of the type
;; "power_of_2_value & (1 << y)".
"@
btstq (%1-1),%0
- test.d %0
+ cmpq 0,%0
btstq %2,%0
clearf nz
btst %2,%0
clearf nz
cmpq %p0,%2"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
\f
;; Move insns.
(match_operand:DI 1 "general_operand" ""))]
""
{
- if (MEM_P (operands[0]) && operands[1] != const0_rtx)
+ if (MEM_P (operands[0])
+ && operands[1] != const0_rtx
+ && (!TARGET_V32 || (!REG_P (operands[1]) && can_create_pseudo_p ())))
operands[1] = copy_to_mode_reg (DImode, operands[1]);
/* Some other ports (as of 2001-09-10 for example mcore and romp) also
}
})
-(define_insn "*movdi_insn"
+(define_insn_and_split "*movdi_insn_non_v32"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,rx,m")
- (match_operand:DI 1 "general_operand" "rx,g,rxM"))]
- "register_operand (operands[0], DImode)
- || register_operand (operands[1], DImode)
- || operands[1] == const0_rtx"
- "#")
+ (match_operand:DI 1 "general_operand" "rx,g,rxM"))]
+ "(register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode)
+ || operands[1] == const0_rtx)
+ && !TARGET_V32"
+ "#"
+ "&& reload_completed"
+ [(match_dup 2)]
+ "operands[2] = cris_split_movdx (operands);")
+;; Overlapping (but non-identical) source memory address and destination
+;; register would be a compiler bug, so we don't have to specify that.
+(define_insn "*movdi_v32"
+ [(set
+ (match_operand:DI 0 "nonimmediate_operand" "=r,rx,&r,>, m,r,x,m")
+ (match_operand:DI 1 "general_operand" "rxi,r>,m, rx,r,m,m,x"))]
+ "TARGET_V32"
+{
+ switch (which_alternative)
+ {
+ /* FIXME: 1) Use autoincrement where possible. 2) Have peephole2,
+ particularly for cases where the address register is dead. */
+ case 5:
+ if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0)))
+ return "addq 4,%L1\;move.d %1,%H0\;subq 4,%L1\;move.d %1,%M0";
+ gcc_assert (REGNO (operands[0]) + 1 == REGNO (XEXP (operands[1], 0)));
+ return "move.d [%L1+],%M0\;move.d [%L1],%H0";
+ case 2:
+ /* We could do away with the addq if we knew the address-register
+ isn't ACR. If we knew the address-register is dead, we could do
+ away with the subq too. */
+ return "move.d [%L1],%M0\;addq 4,%L1\;move.d [%L1],%H0\;subq 4,%L1";
+ case 4:
+ return "move.d %M1,[%L0]\;addq 4,%L0\;move.d %H1,[%L0]\;subq 4,%L0";
+ case 6:
+ return "move [%L1],%M0\;addq 4,%L1\;move [%L1],%H0\;subq 4,%L1";
+ case 7:
+ return "move %M1,[%L0]\;addq 4,%L0\;move %H1,[%L0]\;subq 4,%L0";
+
+ default:
+ return "#";
+ }
+}
+ ;; The non-split cases clobber cc0 because of their adds and subs.
+ ;; Beware that NOTICE_UPDATE_CC is called before the forced split happens.
+ [(set_attr "cc" "*,*,clobber,*,clobber,clobber,*,*")])
+
+;; Much like "*movdi_insn_non_v32". Overlapping registers and constants
+;; is handled so much better in cris_split_movdx.
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
- "reload_completed"
+ "TARGET_V32
+ && reload_completed
+ && (!MEM_P (operands[0]) || !REG_P (XEXP (operands[0], 0)))
+ && (!MEM_P (operands[1]) || !REG_P (XEXP (operands[1], 0)))"
[(match_dup 2)]
"operands[2] = cris_split_movdx (operands);")
\f
;;
;; move.S1 [rx=ry+rz.S],rw avoiding when rx is ry, or rw is rx
;; FIXME: These could have anonymous mode for operand 0.
+;; FIXME: Special registers' alternatives too.
(define_insn "*mov_side<mode>_biap"
[(set (match_operand:BW 0 "register_operand" "=r,r")
offset? */
if (flag_pic
&& CONSTANT_ADDRESS_P (operands[1])
- && !cris_valid_pic_const (operands[1]))
+ && !cris_valid_pic_const (operands[1], false))
{
enum cris_pic_symbol_type t = cris_pic_symbol_type_of (operands[1]);
destination register for the symbol. It might not be
worth it. Measure. */
current_function_uses_pic_offset_table = 1;
- if (t == cris_gotrel_symbol)
+ if (t == cris_rel_symbol)
{
/* Change a "move.d sym(+offs),rN" into (allocate register rM)
+ for pre-v32:
+ "move.d (const (plus (unspec [sym]
+ CRIS_UNSPEC_GOTREL) offs)),rM" "add.d rPIC,rM,rN"
+ and for v32:
"move.d (const (plus (unspec [sym]
- CRIS_UNSPEC_GOTREL) offs)),rM" "add.d rPIC,rM,rN" */
+ CRIS_UNSPEC_PCREL) offs)),rN". */
rtx tem, rm, rn = operands[0];
rtx sym = GET_CODE (operands[1]) != CONST
? operands[1] : get_related_value (operands[1]);
HOST_WIDE_INT offs = get_integer_term (operands[1]);
gcc_assert (can_create_pseudo_p ());
- tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
- CRIS_UNSPEC_GOTREL);
- if (offs != 0)
- tem = plus_constant (tem, offs);
- rm = gen_reg_rtx (Pmode);
- emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
- if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
- rn, 0, OPTAB_LIB_WIDEN) != rn)
- internal_error ("expand_binop failed in movsi gotrel");
+
+ if (TARGET_V32)
+ {
+ tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
+ CRIS_UNSPEC_PCREL);
+ if (offs != 0)
+ tem = plus_constant (tem, offs);
+ rm = rn;
+ emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+ }
+ else
+ {
+ /* We still uses GOT-relative addressing for
+ pre-v32. */
+ current_function_uses_pic_offset_table = 1;
+ tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
+ CRIS_UNSPEC_GOTREL);
+ if (offs != 0)
+ tem = plus_constant (tem, offs);
+ rm = gen_reg_rtx (Pmode);
+ emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+ if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
+ rn, 0, OPTAB_LIB_WIDEN) != rn)
+ internal_error ("expand_binop failed in movsi gotrel");
+ }
DONE;
}
else if (t == cris_got_symbol)
aliases other same symbols is unimportant. */
set_mem_alias_set (mem, new_alias_set ());
MEM_NOTRAP_P (mem) = 1;
+
+ /* We can set the GOT memory read of a non-called symbol
+ to readonly, but not that of a call symbol, as those
+ are subject to lazy evaluation and usually have the value
+ changed from the first call to the second (but
+ constant thereafter). */
MEM_READONLY_P (mem) = 1;
emit_move_insn (rn, mem);
DONE;
(define_insn "*movsi_got_load"
[(set (reg:SI CRIS_GOT_REGNUM) (unspec:SI [(const_int 0)] CRIS_UNSPEC_GOT))]
"flag_pic"
- "move.d $pc,%:\;sub.d .:GOTOFF,%:"
+{
+ return TARGET_V32
+ ? "lapc _GLOBAL_OFFSET_TABLE_,%:"
+ : "move.d $pc,%:\;sub.d .:GOTOFF,%:";
+}
[(set_attr "cc" "clobber")])
(define_insn "*movsi_internal"
[(set
- (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x, m,x")
+ (match_operand:SI 0 "nonimmediate_operand"
+ "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x, m,x")
+ (match_operand:SI 1 "cris_general_operand_or_pic_source"
+ "r,Q>,M,M, I,r, M,n,!S,g,r,x, rQ>,x,gi"))]
;; Note that we prefer not to use the S alternative (if for some reason
- ;; it competes with others), but g matches S.
- (match_operand:SI 1 "general_operand" "r,Q>,M,M, I,r, M,n,!S,g,r,x, rQ>,x,gi"))]
+ ;; it competes with others) above, but g matches S.
""
{
/* Better to have c-switch here; it is worth it to optimize the size of
letters. FIXME: Check again. It seems this could shrink a bit. */
switch (which_alternative)
{
+ case 9:
+ if (TARGET_V32)
+ {
+ if (!flag_pic
+ && (GET_CODE (operands[1]) == SYMBOL_REF
+ || GET_CODE (operands[1]) == LABEL_REF
+ || GET_CODE (operands[1]) == CONST))
+ {
+ /* FIXME: Express this through (set_attr cc none) instead,
+ since we can't express the ``none'' at this point. FIXME:
+ Use lapc for everything except const_int and when next cc0
+ user would want the flag setting. */
+ CC_STATUS_INIT;
+ return "lapc %1,%0";
+ }
+ if (flag_pic == 1
+ && GET_CODE (operands[1]) == CONST
+ && GET_CODE (XEXP (operands[1], 0)) == UNSPEC
+ && XINT (XEXP (operands[1], 0), 1) == CRIS_UNSPEC_GOTREAD)
+ return "movu.w %1,%0";
+ }
+ /* FALLTHROUGH */
case 0:
case 1:
case 5:
- case 9:
case 10:
return "move.d %1,%0";
tem = XEXP (tem, 0);
if (GET_CODE (tem) == PLUS
&& GET_CODE (XEXP (tem, 0)) == UNSPEC
- && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
+ && (XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
+ || XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_PCREL)
&& CONST_INT_P (XEXP (tem, 1)))
tem = XEXP (tem, 0);
gcc_assert (GET_CODE (tem) == UNSPEC);
indexed addressing mode. */
if (flag_pic == 1)
return "movs.w %1,%0";
+ return "move.d %1,%0";
+
case CRIS_UNSPEC_GOTREL:
- case CRIS_UNSPEC_PLT:
+ case CRIS_UNSPEC_PLT_GOTREL:
+ gcc_assert (!TARGET_V32);
return "move.d %1,%0";
+ case CRIS_UNSPEC_PCREL:
+ case CRIS_UNSPEC_PLT_PCREL:
+ gcc_assert (TARGET_V32);
+ return "lapc %1,%0";
+
default:
gcc_unreachable ();
}
move %1,%0
move %1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
+\f
+;; Movem patterns. Primarily for use in function prologue and epilogue.
+;; The V32 variants have an ordering matching the expectations of the
+;; standard names "load_multiple" and "store_multiple"; pre-v32 movem
+;; store R0 in the highest memory location.
+
+(define_expand "load_multiple"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "memory_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")]
+ "TARGET_V32"
+{
+ rtx indreg;
+
+ /* Apparently the predicate isn't checked, so we need to do so
+ manually. Once happened for libstdc++-v3 locale_facets.tcc. */
+ if (!MEM_P (operands[1]))
+ FAIL;
+
+ indreg = XEXP (operands[1], 0);
+
+ if (GET_CODE (indreg) == POST_INC)
+ indreg = XEXP (indreg, 0);
+ if (!REG_P (indreg)
+ || GET_CODE (operands[2]) != CONST_INT
+ || !REG_P (operands[0])
+ || REGNO (operands[0]) != 0
+ || INTVAL (operands[2]) > CRIS_SP_REGNUM
+ || (int) REGNO (indreg) < INTVAL (operands[2]))
+ FAIL;
+ gcc_unreachable ();
+ emit_insn (cris_gen_movem_load (operands[1], operands[2], 0));
+ DONE;
+})
+
+(define_expand "store_multiple"
+ [(match_operand:SI 0 "memory_operand" "")
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")]
+ "TARGET_V32"
+{
+ rtx indreg;
+
+ /* See load_multiple. */
+ if (!MEM_P (operands[0]))
+ FAIL;
+
+ indreg = XEXP (operands[0], 0);
+
+ if (GET_CODE (indreg) == POST_INC)
+ indreg = XEXP (indreg, 0);
+ if (!REG_P (indreg)
+ || GET_CODE (operands[2]) != CONST_INT
+ || !REG_P (operands[1])
+ || REGNO (operands[1]) != 0
+ || INTVAL (operands[2]) > CRIS_SP_REGNUM
+ || (int) REGNO (indreg) < INTVAL (operands[2]))
+ FAIL;
+ gcc_unreachable ();
+ cris_emit_movem_store (operands[0], operands[2], 0, false);
+ DONE;
+})
-;; Note that the memory layout of the registers is the reverse of that
-;; of the standard patterns "load_multiple" and "store_multiple".
(define_insn "*cris_load_multiple"
[(match_parallel 0 "cris_load_multiple_op"
[(set (match_operand:SI 1 "register_operand" "=r,r")
;; Note that for the 'P' constraint, the high part can be -1 or 0. We
;; output the insn through the 'A' output modifier as "adds.w" and "addq",
;; respectively.
-(define_insn "adddi3"
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand")
+ (plus:DI (match_operand:DI 1 "register_operand")
+ (match_operand:DI 2 "general_operand")))]
+ ""
+{
+ if (MEM_P (operands[2]) && TARGET_V32)
+ operands[2] = force_reg (DImode, operands[2]);
+})
+
+(define_insn "*adddi3_non_v32"
[(set (match_operand:DI 0 "register_operand" "=r,r,r,&r,&r")
(plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,r")
(match_operand:DI 2 "general_operand" "J,N,P,g,!To")))]
- ""
+ "!TARGET_V32"
"@
addq %2,%M0\;ax\;addq 0,%H0
subq %n2,%M0\;ax\;subq 0,%H0
add.d %M2,%M0\;ax\;add.d %H2,%H0
add.d %M2,%M1,%M0\;ax\;add.d %H2,%H1,%H0")
-(define_insn "addsi3"
+; It seems no use allowing a memory operand for this one, because we'd
+; need a scratch register for incrementing the address.
+(define_insn "*adddi3_v32"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0")
+ (match_operand:DI 2 "nonmemory_operand" "J,N,P,r,n")))]
+ "TARGET_V32"
+ "@
+ addq %2,%M0\;addc 0,%H0
+ subq %n2,%M0\;ax\;subq 0,%H0
+ add%e2.%z2 %2,%M0\;addc %H2,%H0
+ add.d %M2,%M0\;addc %H2,%H0
+ add.d %M2,%M0\;addc %H2,%H0")
+
+(define_expand "add<mode>3"
+ [(set (match_operand:BWD 0 "register_operand")
+ (plus:BWD
+ (match_operand:BWD 1 "register_operand")
+ (match_operand:BWD 2 "general_operand")))]
+ ""
+ "")
+
+(define_insn "*addsi3_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r, r,r, r")
(plus:SI
(match_operand:SI 1 "register_operand" "%0,0, 0,0,0,0, 0,r, r")
;; register as in destination. This will happen after insn splitting.
;; gcc <= 2.7.2. FIXME: Check for gcc-2.9x
- ""
+ "!TARGET_V32"
{
switch (which_alternative)
{
tem = XEXP (tem, 0);
if (GET_CODE (tem) == PLUS
&& GET_CODE (XEXP (tem, 0)) == UNSPEC
+ /* We don't allow CRIS_UNSPEC_PCREL here; we can't have a
+ pc-relative operand in an add insn. */
&& XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
&& CONST_INT_P (XEXP (tem, 1)))
tem = XEXP (tem, 0);
indexed addressing mode. */
if (flag_pic == 1)
return "adds.w %2,%0";
- /* Fall through. */
- case CRIS_UNSPEC_PLT:
+ return "add.d %2,%0";
+
+ case CRIS_UNSPEC_PLT_GOTREL:
case CRIS_UNSPEC_GOTREL:
return "add.d %2,%0";
default:
}
}
case 6:
- return "add.d %2,%0";
+ return "add%u2 %2,%0";
case 7:
return "add.d %2,%1,%0";
case 8:
}
}
[(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no,yes")])
+
+; FIXME: Check what's best: having the three-operand ACR alternative
+; before or after the corresponding-operand2 alternative. Check for
+; *all* insns. FIXME: constant constraint letter for -128..127.
+(define_insn "*addsi3_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,!a,r,!a, r,r,!a,r,!a,r,r,r,!a")
+ (plus:SI
+ (match_operand:SI 1 "register_operand" "%0,r, 0, r, 0,0,r, 0,r, 0,0,0,r")
+ (match_operand:SI 2 "general_operand" "r, r, Q>,Q>,J,N,NJ,L,L, P,n,g,g")))]
+ "TARGET_V32"
+ "@
+ add.d %2,%0
+ addi %2.b,%1,%0
+ add.d %2,%0
+ addo.d %2,%1,%0
+ addq %2,%0
+ subq %n2,%0
+ addoq %2,%1,%0
+ adds.w %2,%0
+ addo %2,%1,%0
+ addu.w %2,%0
+ add.d %2,%0
+ add%u2 %2,%0
+ addo.%Z2 %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,yes,no,no,no,no,no,no")
+ (set_attr "cc" "*,none,*,none,*,*,none,*,*,*,*,*,none")])
\f
-(define_insn "addhi3"
+(define_insn "*addhi3_non_v32"
[(set (match_operand:HI 0 "register_operand" "=r,r, r,r,r,r")
(plus:HI (match_operand:HI 1 "register_operand" "%0,0, 0,0,0,r")
(match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
- ""
+ "!TARGET_V32"
"@
add.w %2,%0
add.w %2,%0
[(set_attr "slottable" "yes,yes,yes,yes,no,no")
(set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
-(define_insn "addqi3"
+(define_insn "*addhi3_v32"
+ [(set (match_operand:HI 0 "register_operand" "=r, !a,r,!a, r,r,!a,r,!a")
+ (plus:HI
+ (match_operand:HI 1 "register_operand" "%0,r, 0, r, 0,0,r, 0,r")
+ (match_operand:HI 2 "general_operand" "r, r, Q>,Q>,J,N,NJ,g,g")))]
+ "TARGET_V32"
+ "@
+ add.w %2,%0
+ addi %2.b,%1,%0
+ add.w %2,%0
+ addo.w %2,%1,%0
+ addq %2,%0
+ subq %n2,%0
+ addoq %2,%1,%0
+ add.w %2,%0
+ addo.w %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,yes,no,no")
+ (set_attr "cc" "*,none,*,none,clobber,clobber,none,*,none")])
+
+(define_insn "*addqi3_non_v32"
[(set (match_operand:QI 0 "register_operand" "=r,r, r,r,r,r,r")
(plus:QI (match_operand:QI 1 "register_operand" "%0,0, 0,0,0,0,r")
(match_operand:QI 2 "general_operand" "r,Q>,J,N,O,g,!To")))]
- ""
+ "!TARGET_V32"
"@
add.b %2,%0
add.b %2,%0
add.b %2,%1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no")
(set_attr "cc" "normal,normal,clobber,clobber,clobber,normal,normal")])
+
+(define_insn "*addqi3_v32"
+ [(set (match_operand:QI 0 "register_operand" "=r,!a,r,!a, r,r,!a,r,r,!a")
+ (plus:QI
+ (match_operand:QI 1 "register_operand" "%0,r, 0, r, 0,0,r, 0,0,r")
+ (match_operand:QI 2 "general_operand" "r,r, Q>,Q>,J,N,NJ,O,g,g")))]
+ "TARGET_V32"
+ "@
+ add.b %2,%0
+ addi %2.b,%1,%0
+ add.b %2,%0
+ addo.b %2,%1,%0
+ addq %2,%0
+ subq %n2,%0
+ addoq %2,%1,%0
+ subQ -%b2,%0
+ add.b %2,%0
+ addo.b %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,yes,yes,no,no")
+ (set_attr "cc" "*,none,*,none,clobber,clobber,none,clobber,*,none")])
\f
;; Subtract.
;;
;; Note that for the 'P' constraint, the high part can be -1 or 0. We
;; output the insn through the 'D' output modifier as "subs.w" and "subq",
;; respectively.
-(define_insn "subdi3"
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand")
+ (minus:DI (match_operand:DI 1 "register_operand")
+ (match_operand:DI 2 "general_operand")))]
+ ""
+{
+ if (TARGET_V32 && MEM_P (operands[2]))
+ operands[2] = force_reg (DImode, operands[2]);
+})
+
+(define_insn "*subdi3_non_v32"
[(set (match_operand:DI 0 "register_operand" "=r,r,r,&r,&r")
(minus:DI (match_operand:DI 1 "register_operand" "0,0,0,0,r")
(match_operand:DI 2 "general_operand" "J,N,P,g,!To")))]
- ""
+ "!TARGET_V32"
"@
subq %2,%M0\;ax\;subq 0,%H0
addq %n2,%M0\;ax\;addq 0,%H0
sub.d %M2,%M0\;ax\;sub.d %H2,%H0
sub.d %M2,%M1,%M0\;ax\;sub.d %H2,%H1,%H0")
-(define_insn "subsi3"
+(define_insn "*subdi3_v32"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r,&r")
+ (minus:DI (match_operand:DI 1 "register_operand" "0,0,0,0")
+ (match_operand:DI 2 "nonmemory_operand" "J,N,P,r")))]
+ "TARGET_V32"
+ "@
+ subq %2,%M0\;ax\;subq 0,%H0
+ addq %n2,%M0\;ax\;addq 0,%H0
+ sub%e2.%z2 %2,%M0\;ax\;%D2 %H2,%H0
+ sub.d %M2,%M0\;ax\;sub.d %H2,%H0")
+
+(define_expand "sub<mode>3"
+ [(set (match_operand:BWD 0 "register_operand")
+ (minus:BWD
+ (match_operand:BWD 1 "register_operand")
+ (match_operand:BWD 2 "general_operand")))]
+ ""
+ "")
+
+(define_insn "*subsi3_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r,r,r")
(minus:SI
(match_operand:SI 1 "register_operand" "0,0, 0,0,0,0,0,r")
(match_operand:SI 2 "general_operand" "r,Q>,J,N,P,n,g,!To")))]
- ""
+ "!TARGET_V32"
;; This does not do the optimal: "addu.w 65535,r0" when %2 is negative.
;; But then again, %2 should not be negative.
sub.d %2,%0
sub.d %2,%1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no")])
+
+(define_insn "*subsi3_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
+ (minus:SI
+ (match_operand:SI 1 "register_operand" "0,0,0,0,0,0,0")
+ (match_operand:SI 2 "general_operand" "r,Q>,J,N,P,n,g")))]
+ "TARGET_V32"
+ "@
+ sub.d %2,%0
+ sub.d %2,%0
+ subq %2,%0
+ addq %n2,%0
+ sub%e2.%z2 %2,%0
+ sub.d %2,%0
+ sub.d %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")])
\f
-(define_insn "sub<mode>3"
+(define_insn "*sub<mode>3_nonv32"
[(set (match_operand:BW 0 "register_operand" "=r,r, r,r,r,r")
(minus:BW (match_operand:BW 1 "register_operand" "0,0, 0,0,0,r")
(match_operand:BW 2 "general_operand" "r,Q>,J,N,g,!To")))]
- ""
+ "!TARGET_V32"
"@
sub<m> %2,%0
sub<m> %2,%0
sub<m> %2,%1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,no,no")
(set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
+
+(define_insn "*sub<mode>3_v32"
+ [(set (match_operand:BW 0 "register_operand" "=r,r,r,r,r")
+ (minus:BW (match_operand:BW 1 "register_operand" "0,0,0,0,0")
+ (match_operand:BW 2 "general_operand" "r,Q>,J,N,g")))]
+ "TARGET_V32"
+ "@
+ sub<m> %2,%0
+ sub<m> %2,%0
+ subq %2,%0
+ addq %n2,%0
+ sub<m> %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,no")
+ (set_attr "cc" "normal,normal,clobber,clobber,normal")])
\f
;; CRIS has some add/sub-with-sign/zero-extend instructions.
;; Although these perform sign/zero-extension to SImode, they are
\f
;; As with op.S we may have to add special pattern to match commuted
-;; operands to adds/addu and bound
+;; operands to adds/addu and bound
;;
;; adds/addu/bound [rx=ry+rz.S]
;; QImode to HImode
;; FIXME: GCC should widen.
-(define_insn "*extopqihi"
+(define_insn "*extopqihi_non_v32"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
(match_operator:HI
3 "cris_additive_operand_extend_operator"
(match_operator:HI
4 "cris_extend_operator"
[(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
- "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+ "!TARGET_V32 && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
&& (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
"@
%x3%E4.%m4 %2,%0
[(set_attr "slottable" "yes,yes,no,no")
(set_attr "cc" "clobber")])
+(define_insn "*extopqihi_v32"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (match_operator:HI
+ 3 "cris_additive_operand_extend_operator"
+ [(match_operand:HI 1 "register_operand" "0,0")
+ (match_operator:HI
+ 4 "cris_extend_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "r,m")])]))]
+ "TARGET_V32"
+ "%x3%e4.%m4 %2,%0"
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "clobber")])
+
;; QImode to SImode
-(define_insn "*extop<mode>si"
+(define_insn "*extop<mode>si_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(match_operator:SI
3 "cris_operand_extend_operator"
(match_operator:SI
4 "cris_extend_operator"
[(match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
- "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+ "!TARGET_V32
+ && (GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
&& (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
"@
%x3%E4<m> %2,%0
%x3%E4<m> %2,%1,%0"
[(set_attr "slottable" "yes,yes,no,no")])
-\f
+(define_insn "*extop<mode>si_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (match_operator:SI
+ 3 "cris_additive_operand_extend_operator"
+ [(match_operand:SI 1 "register_operand" "0,0")
+ (match_operator:SI
+ 4 "cris_extend_operator"
+ [(match_operand:BW 2 "nonimmediate_operand" "r,m")])]))]
+ "TARGET_V32"
+ "%x3%e4.%m4 %2,%0"
+ [(set_attr "slottable" "yes")])
+\f
;; As with the side-effect patterns, may have to have swapped operands for add.
-;; FIXME: *should* be redundant to gcc.
+;; For commutative operands, these are the canonical forms.
;; QImode to HImode
-(define_insn "*extopqihi_swap"
+(define_insn "*addxqihi_swap_non_v32"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
(plus:HI
(match_operator:HI
3 "cris_extend_operator"
[(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])
(match_operand:HI 1 "register_operand" "0,0,0,r")))]
- "operands[1] != frame_pointer_rtx"
+ "!TARGET_V32 && operands[1] != frame_pointer_rtx"
"@
add%e3.b %2,%0
add%e3.b %2,%0
[(set_attr "slottable" "yes,yes,no,no")
(set_attr "cc" "clobber")])
-(define_insn "*extop<mode>si_swap"
+;; A case for v32, to catch the "addo" insn in addition to "adds". We
+;; only care to match the canonical form; there should be no other.
+
+(define_insn "*addsbw_v32"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,!a")
+ (plus:HI
+ (sign_extend:HI
+ (match_operand:QI 2 "nonimmediate_operand" "r,m,m"))
+ (match_operand:HI 1 "register_operand" "0,0,r")))]
+ "TARGET_V32"
+ "@
+ adds.b %2,%0
+ adds.b %2,%0
+ addo.b %2,%1,%0"
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "clobber,clobber,none")])
+
+(define_insn "*addubw_v32"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (plus:HI
+ (zero_extend:HI
+ (match_operand:QI 2 "nonimmediate_operand" "r,m"))
+ (match_operand:HI 1 "register_operand" "0,0")))]
+ "TARGET_V32"
+ "addu.b %2,%0"
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*extop<mode>si_swap_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(match_operator:SI
4 "cris_plus_or_bound_operator"
3 "cris_extend_operator"
[(match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To")])
(match_operand:SI 1 "register_operand" "0,0,0,r")]))]
- "(GET_CODE (operands[4]) != UMIN || GET_CODE (operands[3]) == ZERO_EXTEND)
+ "!TARGET_V32
+ && (GET_CODE (operands[4]) != UMIN || GET_CODE (operands[3]) == ZERO_EXTEND)
&& operands[1] != frame_pointer_rtx"
"@
%x4%E3<m> %2,%0
%x4%E3<m> %2,%0
%x4%E3<m> %2,%1,%0"
[(set_attr "slottable" "yes,yes,no,no")])
+
+(define_insn "*adds<mode>_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,!a")
+ (plus:SI
+ (sign_extend:SI
+ (match_operand:BW 2 "nonimmediate_operand" "r,m,m"))
+ (match_operand:SI 1 "register_operand" "0,0,r")))]
+ "TARGET_V32"
+ "@
+ adds<m> %2,%0
+ adds<m> %2,%0
+ addo<m> %2,%1,%0"
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "*,*,none")])
+
+(define_insn "*addu<mode>_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI
+ (zero_extend:SI
+ (match_operand:BW 2 "nonimmediate_operand" "r,m"))
+ (match_operand:SI 1 "register_operand" "0,0")))]
+ "TARGET_V32 && operands[1] != frame_pointer_rtx"
+ "addu<m> %2,%0"
+ [(set_attr "slottable" "yes")])
+
+(define_insn "*bound<mode>_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (umin:SI
+ (zero_extend:SI
+ (match_operand:BW 2 "register_operand" "r"))
+ (match_operand:SI 1 "register_operand" "0")))]
+ "TARGET_V32 && operands[1] != frame_pointer_rtx"
+ "bound<m> %2,%0"
+ [(set_attr "slottable" "yes")])
\f
;; This is the special case when we use what corresponds to the
;; instruction above in "casesi". Do *not* change it to use the generic
(pc))
(label_ref (match_operand 2 "" ""))))
(use (label_ref (match_operand 3 "" "")))]
-
- "operands[0] != frame_pointer_rtx"
-
+ "!TARGET_V32 && operands[0] != frame_pointer_rtx"
"adds.w [$pc+%0.w],$pc"
[(set_attr "cc" "clobber")])
+
+;; For V32, we just have a jump, but we need to mark the table as used,
+;; and the jump insn must have the if_then_else form expected by core
+;; GCC. Since we don't want to prolong the lifetime of the original
+;; index value, we compare against "unspec 0". It's a pity we have to
+;; jump through to get the default label in place and to keep the jump
+;; table around. FIXME: Look into it some time.
+
+(define_insn "*casesi_jump_v32"
+ [(set (pc)
+ (if_then_else
+ (ltu (unspec [(const_int 0)] CRIS_UNSPEC_CASESI)
+ (match_operand:SI 0 "const_int_operand" "n"))
+ (match_operand:SI 1 "register_operand" "r")
+ (label_ref (match_operand 2 "" ""))))
+ (use (label_ref (match_operand 3 "" "")))]
+ "TARGET_V32"
+ "jump %1%#"
+ [(set_attr "cc" "clobber")
+ (set_attr "slottable" "has_slot")])
\f
;; Multiply instructions.
;; The addi insn as it is normally used.
+;; Make the the ACR alternative taste bad enough to not choose it as a
+;; preference to avoid spilling problems (unwind-dw2-fde.c at build).
+;; FIXME: Revisit for new register allocator.
+
(define_insn "*addi"
- [(set (match_operand:SI 0 "register_operand" "=r")
+ [(set (match_operand:SI 0 "register_operand" "=r,!a")
(plus:SI
- (mult:SI (match_operand:SI 2 "register_operand" "r")
- (match_operand:SI 3 "const_int_operand" "n"))
- (match_operand:SI 1 "register_operand" "0")))]
+ (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+ (match_operand:SI 3 "const_int_operand" "n,n"))
+ (match_operand:SI 1 "register_operand" "0,r")))]
"operands[0] != frame_pointer_rtx
&& operands[1] != frame_pointer_rtx
&& CONST_INT_P (operands[3])
&& (INTVAL (operands[3]) == 1
|| INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)"
- "addi %2%T3,%0"
+ "@
+ addi %2%T3,%0
+ addi %2%T3,%1,%0"
[(set_attr "slottable" "yes")
(set_attr "cc" "none")])
(match_operand:SI 2 "register_operand" "r"))
(ashift:SI (match_operand:SI 3 "register_operand" "0")
(const_int 1))))]
- ""
+ "!TARGET_V32"
"mstep %2,%0"
[(set_attr "slottable" "yes")])
(match_operand:SI 2 "register_operand" "r"))
(mult:SI (match_operand:SI 3 "register_operand" "0")
(const_int 2))))]
- "operands[0] != frame_pointer_rtx
+ "!TARGET_V32
+ && operands[0] != frame_pointer_rtx
&& operands[1] != frame_pointer_rtx
&& operands[2] != frame_pointer_rtx
&& operands[3] != frame_pointer_rtx"
;; a / 1000;}" and unsigned. FIXME: Comment above was for 3.2, revisit.
(define_insn "<su>mulsi3_highpart"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=h,h,?r,?r")
+ [(set (match_operand:SI 0 "register_operand" "=h,h,?r,?r")
(truncate:SI
(lshiftrt:DI
(mult:DI
(const_int 1))))]
""
"dstep %2,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
;; Here's a variant with mult instead of ashift.
;;
&& operands[2] != frame_pointer_rtx
&& operands[3] != frame_pointer_rtx"
"dstep %2,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
\f
;; Logical operators.
;; pressure (worse code). That will hopefully change with an
;; improved reload pass.
-(define_insn "*expanded_andsi"
+(define_insn "*expanded_andsi_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r,r, r,r")
(and:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0,r")
(match_operand:SI 2 "general_operand" "I,r,Q>,g,!To")))]
- ""
+ "!TARGET_V32"
"@
andq %2,%0
and.d %2,%0
and.d %2,%0
and.d %2,%1,%0"
[(set_attr "slottable" "yes,yes,yes,no,no")])
+
+(define_insn "*expanded_andsi_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "I,r,Q>,g")))]
+ "TARGET_V32"
+ "@
+ andq %2,%0
+ and.d %2,%0
+ and.d %2,%0
+ and.d %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,no")
+ (set_attr "cc" "noov32")])
\f
;; For both QI and HI we may use the quick patterns. This results in
;; useless condition codes, but that is used rarely enough for it to
;; Catch-all andhi3 pattern.
-(define_insn "*expanded_andhi"
+(define_insn "*expanded_andhi_non_v32"
[(set (match_operand:HI 0 "register_operand" "=r,r,r, r,r,r,r")
(and:HI (match_operand:HI 1 "register_operand" "%0,0,0, 0,0,0,r")
(match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
;; pressure (worse code). That will hopefully change with an
;; improved reload pass.
- ""
+ "!TARGET_V32"
"@
andq %2,%0
and.w %2,%0
[(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
(set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
+(define_insn "*expanded_andhi_v32"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+ (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
+ (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g")))]
+ "TARGET_V32"
+ "@
+ andq %2,%0
+ and.w %2,%0
+ and.w %2,%0
+ and.w %2,%0
+ anDq %b2,%0
+ and.w %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,no,yes,no")
+ (set_attr "cc" "clobber,noov32,noov32,noov32,clobber,noov32")])
+
;; A strict_low_part pattern.
-(define_insn "*andhi_lowpart"
+(define_insn "*andhi_lowpart_non_v32"
[(set (strict_low_part
(match_operand:HI 0 "register_operand" "=r,r, r,r,r,r"))
(and:HI (match_operand:HI 1 "register_operand" "%0,0, 0,0,0,r")
(match_operand:HI 2 "general_operand" "r,Q>,L,O,g,!To")))]
- ""
+ "!TARGET_V32"
"@
and.w %2,%0
and.w %2,%0
and.w %2,%1,%0"
[(set_attr "slottable" "yes,yes,no,yes,no,no")
(set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
+
+(define_insn "*andhi_lowpart_v32"
+ [(set (strict_low_part
+ (match_operand:HI 0 "register_operand" "=r,r,r,r,r"))
+ (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0")
+ (match_operand:HI 2 "general_operand" "r,Q>,L,O,g")))]
+ "TARGET_V32"
+ "@
+ and.w %2,%0
+ and.w %2,%0
+ and.w %2,%0
+ anDq %b2,%0
+ and.w %2,%0"
+ [(set_attr "slottable" "yes,yes,no,yes,no")
+ (set_attr "cc" "noov32,noov32,noov32,clobber,noov32")])
\f
-(define_insn "andqi3"
+(define_expand "andqi3"
+ [(set (match_operand:QI 0 "register_operand")
+ (and:QI (match_operand:QI 1 "register_operand")
+ (match_operand:QI 2 "general_operand")))]
+ ""
+ "")
+
+(define_insn "*andqi3_non_v32"
[(set (match_operand:QI 0 "register_operand" "=r,r,r, r,r,r")
(and:QI (match_operand:QI 1 "register_operand" "%0,0,0, 0,0,r")
(match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
- ""
+ "!TARGET_V32"
"@
andq %2,%0
and.b %2,%0
[(set_attr "slottable" "yes,yes,yes,yes,no,no")
(set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
-(define_insn "*andqi_lowpart"
+(define_insn "*andqi3_v32"
+ [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
+ (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0")
+ (match_operand:QI 2 "general_operand" "I,r,Q>,O,g")))]
+ "TARGET_V32"
+ "@
+ andq %2,%0
+ and.b %2,%0
+ and.b %2,%0
+ andQ %b2,%0
+ and.b %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,no")
+ (set_attr "cc" "clobber,noov32,noov32,clobber,noov32")])
+
+(define_insn "*andqi_lowpart_non_v32"
[(set (strict_low_part
(match_operand:QI 0 "register_operand" "=r,r, r,r,r"))
(and:QI (match_operand:QI 1 "register_operand" "%0,0, 0,0,r")
(match_operand:QI 2 "general_operand" "r,Q>,O,g,!To")))]
- ""
+ "!TARGET_V32"
"@
and.b %2,%0
and.b %2,%0
and.b %2,%1,%0"
[(set_attr "slottable" "yes,yes,yes,no,no")
(set_attr "cc" "normal,normal,clobber,normal,normal")])
+
+(define_insn "*andqi_lowpart_v32"
+ [(set (strict_low_part
+ (match_operand:QI 0 "register_operand" "=r,r,r,r"))
+ (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0")
+ (match_operand:QI 2 "general_operand" "r,Q>,O,g")))]
+ "TARGET_V32"
+ "@
+ and.b %2,%0
+ and.b %2,%0
+ andQ %b2,%0
+ and.b %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,no")
+ (set_attr "cc" "noov32,noov32,clobber,noov32")])
\f
;; Bitwise or.
;; It seems there's no need to jump through hoops to get good code such as
;; with andsi3.
-(define_insn "iorsi3"
+(define_expand "ior<mode>3"
+ [(set (match_operand:BWD 0 "register_operand")
+ (ior:BWD (match_operand:BWD 1 "register_operand")
+ (match_operand:BWD 2 "general_operand")))]
+ ""
+ "")
+
+(define_insn "*iorsi3_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r,r, r,r,r")
(ior:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0,0,r")
(match_operand:SI 2 "general_operand" "I, r,Q>,n,g,!To")))]
- ""
+ "!TARGET_V32"
"@
orq %2,%0
or.d %2,%0
[(set_attr "slottable" "yes,yes,yes,no,no,no")
(set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
-(define_insn "iorhi3"
+(define_insn "*iorsi3_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0")
+ (match_operand:SI 2 "general_operand" "I,r,Q>,n,g")))]
+ "TARGET_V32"
+ "@
+ orq %2,%0
+ or.d %2,%0
+ or.d %2,%0
+ oR.%s2 %2,%0
+ or.d %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,no,no")
+ (set_attr "cc" "noov32,noov32,noov32,clobber,noov32")])
+
+(define_insn "*iorhi3_non_v32"
[(set (match_operand:HI 0 "register_operand" "=r,r,r, r,r,r,r")
(ior:HI (match_operand:HI 1 "register_operand" "%0,0,0, 0,0,0,r")
(match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
- ""
+ "!TARGET_V32"
"@
orq %2,%0
or.w %2,%0
[(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
(set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
-(define_insn "iorqi3"
+(define_insn "*iorhi3_v32"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+ (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
+ (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g")))]
+ "TARGET_V32"
+ "@
+ orq %2,%0
+ or.w %2,%0
+ or.w %2,%0
+ or.w %2,%0
+ oRq %b2,%0
+ or.w %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,no,yes,no")
+ (set_attr "cc" "clobber,noov32,noov32,noov32,clobber,noov32")])
+
+(define_insn "*iorqi3_non_v32"
[(set (match_operand:QI 0 "register_operand" "=r,r,r, r,r,r")
(ior:QI (match_operand:QI 1 "register_operand" "%0,0,0, 0,0,r")
(match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
- ""
+ "!TARGET_V32"
"@
orq %2,%0
or.b %2,%0
or.b %2,%1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,no,no")
(set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
+
+(define_insn "*iorqi3_v32"
+ [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
+ (ior:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0")
+ (match_operand:QI 2 "general_operand" "I,r,Q>,O,g")))]
+ "TARGET_V32"
+ "@
+ orq %2,%0
+ or.b %2,%0
+ or.b %2,%0
+ orQ %b2,%0
+ or.b %2,%0"
+ [(set_attr "slottable" "yes,yes,yes,yes,no")
+ (set_attr "cc" "clobber,noov32,noov32,clobber,noov32")])
\f
;; Exclusive-or
(match_operand:SI 2 "register_operand" "r")))]
""
"xor %2,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
(define_insn "xor<mode>3"
[(set (match_operand:BW 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "0")))]
""
"not %0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
(define_insn "one_cmpl<mode>2"
[(set (match_operand:BW 0 "register_operand" "=r")
return "<slr>q %2,%0";
}
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
;; Since gcc gets lost, and forgets to zero-extend the source (or mask
;; the destination) when it changes shifts of lower modes into SImode,
(match_operand:BW 2 "register_operand" "r")))]
""
"<slr><m> %2,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
(define_insn "*<shlr><mode>_lowpart"
[(set (strict_low_part (match_operand:BW 0 "register_operand" "+r"))
(match_operand:BW 1 "register_operand" "r")))]
""
"<slr><m> %1,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
\f
;; Arithmetic/logical shift left.
? "lslq %2,%0" : "lsl<m> %2,%0");
}
[(set_attr "slottable" "yes")
- (set_attr "cc" "normal,clobber")])
+ (set_attr "cc" "noov32,clobber")])
;; A strict_low_part matcher.
(match_operand:HI 1 "register_operand" "r")))]
""
"lsl<m> %1,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
\f
;; Various strange insns that gcc likes.
(abs:SI (match_operand:SI 1 "register_operand" "r")))]
""
"abs %1,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
;; FIXME: GCC should be able to do these expansions itself.
(clz:SI (match_operand:SI 1 "register_operand" "r")))]
"TARGET_HAS_LZ"
"lz %1,%0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
(define_insn "bswapsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(bswap:SI (match_operand:SI 1 "register_operand" "0")))]
"TARGET_HAS_SWAP"
"swapwb %0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
;; This instruction swaps all bits in a register.
;; That means that the most significant bit is put in the place
CRIS_UNSPEC_SWAP_BITS))]
"TARGET_HAS_SWAP"
"swapwbr %0"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+ (set_attr "cc" "noov32")])
;; Implement ctz using two instructions, one for bit swap and one for clz.
;; Defines a scratch register to avoid clobbering input.
;; operation supported by gcc. Used in casesi, but used now and then in
;; normal code too.
-(define_insn "uminsi3"
+(define_expand "uminsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (umin:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "general_operand" "")))]
+ ""
+{
+ if (MEM_P (operands[2]) && TARGET_V32)
+ operands[2] = force_reg (SImode, operands[2]);
+})
+
+(define_insn "*uminsi3_non_v32"
[(set (match_operand:SI 0 "register_operand" "=r,r, r,r")
(umin:SI (match_operand:SI 1 "register_operand" "%0,0, 0,r")
(match_operand:SI 2 "general_operand" "r,Q>,g,!To")))]
- ""
+ "!TARGET_V32"
{
if (CONST_INT_P (operands[2]))
{
return "bound.d %2,%0";
}
[(set_attr "slottable" "yes,yes,no,no")])
+
+(define_insn "*uminsi3_v32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (umin:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+ "TARGET_V32"
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ /* Constant operands are zero-extended, so only 32-bit operands
+ may be negative. */
+ if (INTVAL (operands[2]) >= 0)
+ {
+ if (INTVAL (operands[2]) < 256)
+ return "bound.b %2,%0";
+
+ if (INTVAL (operands[2]) < 65536)
+ return "bound.w %2,%0";
+ }
+ }
+
+ return "bound.d %2,%0";
+}
+ [(set_attr "slottable" "yes,no")])
\f
;; Jump and branch insns.
;; jmp_uses_reg_or_mem used by computed_jump_p. Perhaps it is a kludge to
;; change from general_operand to nonimmediate_operand (at least the docs
;; should be changed), but then again the pattern is called indirect_jump.
-(define_insn "indirect_jump"
- [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
+(define_expand "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand"))]
""
+{
+ if (TARGET_V32 && MEM_P (operands[0]))
+ operands[0] = force_reg (SImode, operands[0]);
+})
+
+(define_insn "*indirect_jump_non_v32"
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
+ "!TARGET_V32"
"jump %0")
+(define_insn "*indirect_jump_v32"
+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
+ "TARGET_V32"
+ "jump %0%#"
+ [(set_attr "slottable" "has_slot")])
+
;; Return insn. Used whenever the epilogue is very simple; if it is only
;; a single ret or jump [sp+]. No allocated stack space or saved
;; registers are allowed.
"(cris_return_address_on_stack_for_return ())")
(const_int 0))
(const_string "no")
- (const_string "has_slot")))])
+ (const_string "has_return_slot")))])
(define_expand "prologue"
[(const_int 0)]
;; Accept *anything* as operand 1. Accept operands for operand 0 in
;; order of preference.
-(define_insn "*expanded_call"
- [(call (mem:QI (match_operand:SI
- 0 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
+(define_insn "*expanded_call_non_v32"
+ [(call (mem:QI (match_operand:SI 0 "general_operand" "r,Q>,g"))
(match_operand 1 "" ""))
(clobber (reg:SI CRIS_SRP_REGNUM))]
- ""
+ "!TARGET_V32"
"jsr %0")
+(define_insn "*expanded_call_v32"
+ [(call
+ (mem:QI
+ (match_operand:SI 0 "cris_nonmemory_operand_or_callable_symbol" "n,r,U,i"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI CRIS_SRP_REGNUM))]
+ "TARGET_V32"
+ "@
+ jsr %0%#
+ jsr %0%#
+ bsr %0%#
+ bsr %0%#"
+ [(set_attr "slottable" "has_call_slot")])
+
;; Parallel when calculating and reusing address of indirect pointer
;; with simple offset. (Makes most sense with PIC.) It looks a bit
;; wrong not to have the clobber last, but that's the way combine
(set (match_operand:SI 3 "register_operand" "=*0,r,r")
(plus:SI (match_dup 0)
(match_dup 1)))]
- "! TARGET_AVOID_GOTPLT"
+ "!TARGET_AVOID_GOTPLT && !TARGET_V32"
"jsr [%3=%0%S1]")
(define_expand "call_value"
;; We also accept a PLT symbol. We output it as [rPIC+sym:GOTPLT] rather
;; than requiring getting rPIC + sym:PLT into a register.
-(define_insn "*expanded_call_value"
+(define_insn "*expanded_call_value_non_v32"
[(set (match_operand 0 "nonimmediate_operand" "=g,g,g")
- (call (mem:QI (match_operand:SI
- 1 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
+ (call (mem:QI (match_operand:SI 1 "general_operand" "r,Q>,g"))
(match_operand 2 "" "")))
(clobber (reg:SI CRIS_SRP_REGNUM))]
- ""
+ "!TARGET_V32"
"Jsr %1"
[(set_attr "cc" "clobber")])
(set (match_operand:SI 4 "register_operand" "=*1,r,r")
(plus:SI (match_dup 1)
(match_dup 2)))]
- "! TARGET_AVOID_GOTPLT"
+ "!TARGET_AVOID_GOTPLT && !TARGET_V32"
"Jsr [%4=%1%S2]"
[(set_attr "cc" "clobber")])
+(define_insn "*expanded_call_value_v32"
+ [(set
+ (match_operand 0 "nonimmediate_operand" "=g,g,g,g")
+ (call
+ (mem:QI
+ (match_operand:SI 1 "cris_nonmemory_operand_or_callable_symbol" "n,r,U,i"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 16))]
+ "TARGET_V32"
+ "@
+ Jsr %1%#
+ Jsr %1%#
+ Bsr %1%#
+ Bsr %1%#"
+ [(set_attr "cc" "clobber")
+ (set_attr "slottable" "has_call_slot")])
+
;; Used in debugging. No use for the direct pattern; unfilled
;; delayed-branches are taken care of by other means.
;; this expansion, you must change the macro ASM_OUTPUT_CASE_END
;; accordingly, to add the default case at the end of the jump-table.
-(define_expand "casesi"
+(define_expand "cris_casesi_non_v32"
[(set (match_dup 5) (match_operand:SI 0 "general_operand" ""))
(set (match_dup 6)
(minus:SI (match_dup 5)
operands[6] = gen_reg_rtx (SImode);
operands[7] = gen_reg_rtx (SImode);
})
+
+;; FIXME: Check effect of not JUMP_TABLES_IN_TEXT_SECTION.
+(define_expand "cris_casesi_v32"
+ [(set (match_dup 5) (match_operand:SI 0 "general_operand"))
+ (set (match_dup 6)
+ (minus:SI (match_dup 5)
+ (match_operand:SI 1 "const_int_operand")))
+ (set (match_dup 7)
+ (umin:SI (match_dup 6)
+ (match_operand:SI 2 "const_int_operand")))
+ (set (match_dup 8) (match_dup 11))
+ (set (match_dup 9)
+ (plus:SI (mult:SI (match_dup 7) (const_int 2))
+ (match_dup 8)))
+ (set (match_dup 10)
+ (plus:SI (sign_extend:SI (mem:HI (match_dup 9)))
+ (match_dup 9)))
+ (parallel
+ [(set (pc)
+ (if_then_else
+ (ltu (unspec [(const_int 0)] CRIS_UNSPEC_CASESI) (match_dup 2))
+ (match_dup 10)
+ (label_ref (match_operand 4 "" ""))))
+ (use (label_ref (match_dup 3)))])]
+ "TARGET_V32"
+{
+ int i;
+ rtx xlabel = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
+ for (i = 5; i <= 10; i++)
+ operands[i] = gen_reg_rtx (SImode);
+ operands[2] = plus_constant (operands[2], 1);
+
+ /* Don't forget to decorate labels too, for PIC. */
+ operands[11] = flag_pic
+ ? gen_rtx_CONST (Pmode,
+ gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xlabel),
+ CRIS_UNSPEC_PCREL))
+ : xlabel;
+})
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "general_operand")
+ (match_operand:SI 1 "const_int_operand")
+ (match_operand:SI 2 "const_int_operand")
+ (match_operand 3 "" "")
+ (match_operand 4 "" "")]
+ ""
+{
+ if (TARGET_V32)
+ emit_insn (gen_cris_casesi_v32 (operands[0], operands[1], operands[2],
+ operands[3], operands[4]));
+ else
+ emit_insn (gen_cris_casesi_non_v32 (operands[0], operands[1], operands[2],
+ operands[3], operands[4]));
+ DONE;
+})
\f
;; Split-patterns. Some of them have modes unspecified. This
;; should always be ok; if for no other reason sparc.md has it as
;; move ry,rz
;; op [rx],rz
;; Lose if rz=ry or rx=rz.
-;; Call this op-extend-split
+;; Call this op-extend-split.
+;; Do not match for V32; the addo and addi shouldn't be split
+;; up.
(define_split
[(set (match_operand 0 "register_operand" "")
(match_operator
3 "cris_extend_operator"
[(match_operand 2 "memory_operand" "")])]))]
- "REG_P (operands[0])
+ "!TARGET_V32
+ && REG_P (operands[0])
&& REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
(match_operator
3 "cris_extend_operator"
[(match_operand 2 "memory_operand" "")])]))]
- "REG_P (operands[0])
+ "!TARGET_V32
+ && REG_P (operands[0])
&& REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
3 "cris_extend_operator"
[(match_operand 2 "memory_operand" "")])
(match_operand 1 "register_operand" "")]))]
- "REG_P (operands[0])
+ "!TARGET_V32
+ && REG_P (operands[0])
&& REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
3 "cris_extend_operator"
[(match_operand 2 "memory_operand" "")])
(match_operand 1 "register_operand" "")]))]
- "REG_P (operands[0])
+ "!TARGET_V32
+ && REG_P (operands[0])
&& REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
3 "cris_orthogonal_operator"
[(match_operand 1 "register_operand" "")
(match_operand 2 "memory_operand" "")]))]
- "REG_P (operands[0])
+ "!TARGET_V32
+ && REG_P (operands[0])
&& REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
3 "cris_commutative_orth_op"
[(match_operand 2 "memory_operand" "")
(match_operand 1 "register_operand" "")]))]
- "REG_P (operands[0])
+ "!TARGET_V32
+ && REG_P (operands[0])
&& REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
3 "cris_commutative_orth_op"
[(match_operand 1 "register_operand" "")
(match_operand 2 "memory_operand" "")]))]
- "REG_P (operands[0]) && REG_P (operands[1])
+ "!TARGET_V32
+ && REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
&& REG_P (XEXP (operands[2], 0))
3 "cris_orthogonal_operator"
[(match_operand 2 "memory_operand" "")
(match_operand 1 "register_operand" "")]))]
- "REG_P (operands[0]) && REG_P (operands[1])
+ "!TARGET_V32
+ && REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[1]) != REGNO (operands[0])
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
&& REG_P (XEXP (operands[2], 0))
&& (BASE_P (operands[1]) || BASE_P (operands[2]))
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
- && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
+ && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)
+ && TARGET_SIDE_EFFECT_PREFIXES"
[(parallel
[(set (match_dup 3) (match_dup 5))
(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
&& (BASE_P (operands[1]) || BASE_P (operands[2]))
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
- && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
+ && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)
+ && TARGET_SIDE_EFFECT_PREFIXES"
[(parallel
[(set (match_dup 5) (match_dup 4))
(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
&& INTVAL (operands[2]) >= -128
- && INTVAL (operands[2]) <= 127"
+ && INTVAL (operands[2]) <= 127
+ && TARGET_SIDE_EFFECT_PREFIXES"
[(parallel
[(set (match_dup 3) (match_op_dup 4 [(match_dup 3) (match_dup 6)]))
(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
(unspec:SI [(match_operand:SI 2 "cris_general_operand_or_symbol" "")]
CRIS_UNSPEC_PLTGOTREAD)))]))]
"flag_pic
- && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+ && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
&& REGNO_REG_CLASS (REGNO (operands[0])) == REGNO_REG_CLASS (0)"
- [(set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT)))
+ [(set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT_GOTREL)))
(set (match_dup 0) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
"")
(match_operand 4 "" ""))
(clobber (reg:SI CRIS_SRP_REGNUM))])]
"flag_pic
- && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+ && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
&& peep2_reg_dead_p (2, operands[0])"
[(parallel [(call (mem:QI (match_dup 1))
(match_dup 4))
(match_operand 4 "" "")))
(clobber (reg:SI CRIS_SRP_REGNUM))])]
"flag_pic
- && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+ && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
&& peep2_reg_dead_p (2, operands[0])"
[(parallel [(set (match_dup 5)
(call (mem:QI (match_dup 1))
(const:SI
(unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])]
"flag_pic
- && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+ && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
&& REGNO_REG_CLASS (REGNO (operands[0])) == REGNO_REG_CLASS (0)"
[(set (match_dup 3)
(const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD)))
(set (match_dup 3) (plus:SI (match_dup 3) (reg:SI CRIS_GOT_REGNUM)))
- (set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT)))
+ (set (match_dup 0)
+ (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT_GOTREL)))
(set (match_dup 0) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
"")
\f