From 45d5d09c3f2565da507424c62e4fd02b4340d624 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Sat, 15 Dec 2007 21:38:19 +0000 Subject: [PATCH] cris.md: Group related constants together, with comments local. * gcc/config/cris/cris.md: Group related constants together, with comments local. (CRIS_UNSPEC_PLT_GOTREL, CRIS_UNSPEC_PLT_PCREL, CRIS_UNSPEC_PCREL) (CRIS_UNSPEC_CASESI): New constants. (CRIS_UNSPEC_PLT): Remove constant. (CRIS_ACR_REGNUM): New constant. ("slottable"): New attr alternatives "has_return_slot" and "has_call_slot". ("cc"): New attr alternatives "noov32" and "rev". ((eq_attr "slottable" "has_call_slot")) ((eq_attr "slottable" "has_return_slot")): New define_delays. ("movdi", "movsi"): Adjust operands for CRIS v32. ("tstdi", "cmpdi", "adddi3", "subdi3", "uminsi3") ("indirect_jump"): Ditto. Make define_expand. ("*tstdi_non_v32", "*tstdi_v32", "*tst_cmp") ("*tst_non_cmp", "*cmpdi_non_v32", "*cmpdi_v32") ("*movdi_v32", "*adddi3_non_v32", "*adddi3_v32") ("*addsi3_non_v32", "*addsi3_v32", "*addhi3_non_v32") ("*addhi3_v32", "*addqi3_non_v32", "*addqi3_v32") ("*subdi3_non_v32", "*subdi3_v32", "*subsi3_non_v32") ("*subsi3_v32", "*sub3_nonv32", "*sub3_v32") ("*andqi3_non_v32", "*andqi3_v32", "*iorsi3_non_v32") ("*iorsi3_v32", "*iorhi3_non_v32", "*iorhi3_v32") ("*iorqi3_non_v32", "*iorqi3_v32", "*uminsi3_non_v32") ("*uminsi3_v32", "*indirect_jump_non_v32", "*indirect_jump_v32") ("*expanded_call_v32", "*expanded_call_value_v32"): New patterns, for the corresponding standard name. ("tst"): Limit to BW and make define_expand. ("tstsi"): Make separate insn, adjusting for CRIS v32. ("*cmp_swapext"): Adjust for v32. Specify "rev" for attr "cc". ("cmpsi", "cmp"): Remove special cases for zero. Specify attr "cc". ("*btst"): Don't match for TARGET_CCINIT. Replace test of register with compatible "cmpq 0". Specify attr "cc". ("*movdi_insn_non_v32"): New pattern, replacing "*movdi_insn" and define_split. (define_split for DI move): Match CRIS v32 only. ("*movsi_got_load", "*movsi_internal", "*addi"): Adjust for CRIS v32. ("load_multiple", "store_multiple", "*addsbw_v32", "*addubw_v32") ("*adds_v32", "*addu_v32", "*bound_v32") ("*casesi_jump_v32", "*expanded_andsi_v32", "*expanded_andhi_v32") ("*extopsi_v32", "*extopqihi_v32", "*andhi_lowpart_v32") ("*andqi_lowpart_v32", "cris_casesi_v32"): New patterns. ("add3"): Make addsi3, addhi3 and addqi3 define_expand. ("sub3"): Ditto subsi3, subhi3 and subqi3. ("ior3"): Ditto iorsi3, iorhi3 and iorqi3. ("*extopqihi_non_v32"): Replace "*extopqihi". ("*extopsi_non_v32"): Replace "*extopsi". ("*addxqihi_swap_non_v32"): Rename from "*extopqihi_swap", make non-v32 only. ("*extopsi_swap_non_v32"): Ditto "*extopsi_swap". ("*expanded_andsi_non_v32"): Ditto "*expanded_andsi". ("*expanded_andhi_non_v32"): Ditto "*expanded_andhi". ("*andhi_lowpart_non_v32"): Ditto "*andhi_lowpart". ("*andqi_lowpart_non_v32"): Ditto "*andqi_lowpart". ("*expanded_call_non_v32"): Ditto "*expanded_call". Change from "cris_general_operand_or_plt_symbol" to "general_operand". ("*expanded_call_value_non_v32") Ditto "*expanded_call_value". ("*casesi_adds_w", "mstep_shift", "mstep_mul") ("*expanded_call_side", "*expanded_call_value_side") (op-extend-split, op-extend-split-rx=rz, op-extend-split-swapped) (op-extend-split-swapped-rx=rz, op-extend, op-split-rx=rz) (op-split-swapped, op-split-swapped-rx=rz): Make non-v32 only. ("dstep_mul", "xorsi3", "one_cmplsi2", "si3") ("*expanded_", "*_lowpart", "ashl3") ("*ashl_lowpart", "abssi2", "clzsi2", "bswapsi2", "cris_swap_bits"): Specify "noov32" for attr "cc". ("mulsi3_highpart"): Ditto. Correct operand 0 to register_operand. ("andqi3"): Make define_expand. ("*return_expanded"): For attr "slottable", change from "has_slot" to "has_return_slot". ("cris_casesi_non_v32"): New pattern, old contents of "casesi". ("casesi"): Divert into "cris_casesi_v32" and "cris_casesi_non_v32". (moversideqi, movemsideqi, mover2side): Require TARGET_SIDE_EFFECT_PREFIXES. (gotplt-to-plt, gotplt-to-plt-side): Change from CRIS_UNSPEC_PLT to CRIS_UNSPEC_PLT_GOTREL. From-SVN: r130971 --- gcc/config/cris/cris.md | 1230 +++++++++++++++++++++++++++++++++------ 1 file changed, 1044 insertions(+), 186 deletions(-) diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md index e248d4307ed..1200a2283cb 100644 --- a/gcc/config/cris/cris.md +++ b/gcc/config/cris/cris.md @@ -54,23 +54,48 @@ ;; [rX=gotless_symbol]. ;; The movsi for a gotless symbol could be split (post reload). -;; 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 @@ -78,6 +103,7 @@ (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) @@ -100,14 +126,21 @@ ;; 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 @@ -125,19 +158,20 @@ ;; 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 @@ -147,6 +181,33 @@ (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)]) + ;; Iterator definitions. @@ -192,26 +253,70 @@ ;; 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" +(define_insn "tstsi" [(set (cc0) - (match_operand:BWD 0 "nonimmediate_operand" "r,Q>,m"))] + (match_operand:SI 0 "nonimmediate_operand" "r,Q>,m"))] "" - "test %0" +{ + if (which_alternative == 0 && TARGET_V32) + return "cmpq 0,%0"; + return "test.d %0"; +} [(set_attr "slottable" "yes,yes,no")]) +(define_expand "tst" + [(set (cc0) + (match_operand:BW 0 "nonimmediate_operand"))] + "" + "") + +(define_insn "*tst_cmp" + [(set (cc0) + (match_operand:BW 0 "nonimmediate_operand" "r,Q>,m"))] + "cris_cc0_user_requires_cmp (insn)" + "@ + cmp 0,%0 + test %0 + test %0" + [(set_attr "slottable" "no,yes,no")]) + +(define_insn "*tst_non_cmp" + [(set (cc0) + (match_operand:BW 0 "nonimmediate_operand" "r,Q>,m"))] + "!cris_cc0_user_requires_cmp (insn)" + "@ + move %0,%0 + test %0 + test %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 @@ -227,11 +332,23 @@ ;; 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 @@ -241,6 +358,18 @@ 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; @@ -281,47 +410,43 @@ [(match_operand:BW 0 "memory_operand" "Q>,m")]) (match_operand:SI 1 "register_operand" "r,r")))] "" - "cmp%e2 %0,%1" ; The function cris_notice_update_cc knows about - ; swapped operands to compares. - [(set_attr "slottable" "yes,no")]) + "cmp%e2 %0,%1" + [(set_attr "slottable" "yes,no") + (set_attr "cc" "rev")]) -;; 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" [(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 %1,%0 cmp %1,%0 - test %0 - test %0 cmp %0,%1 cmp %1,%0 - test %0 cmp %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")]) ;; Pattern matching the BTST insn. ;; It is useful for "if (i & val)" constructs, where val is an exact @@ -337,15 +462,17 @@ (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)". @@ -357,13 +484,14 @@ "@ 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")]) ;; Move insns. @@ -409,7 +537,9 @@ (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 @@ -441,18 +571,64 @@ } }) -(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);") @@ -462,6 +638,7 @@ ;; ;; 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_biap" [(set (match_operand:BW 0 "register_operand" "=r,r") @@ -800,7 +977,7 @@ 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]); @@ -819,26 +996,46 @@ 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) @@ -863,6 +1060,12 @@ 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; @@ -897,15 +1100,21 @@ (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 @@ -913,10 +1122,31 @@ 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"; @@ -958,7 +1188,8 @@ 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); @@ -970,10 +1201,18 @@ 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 (); } @@ -1218,9 +1457,69 @@ move %1,%0 move %1,%0" [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")]) + +;; 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") @@ -1421,11 +1720,21 @@ ;; 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 @@ -1433,7 +1742,29 @@ 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 "add3" + [(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") @@ -1444,7 +1775,7 @@ ;; 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) { @@ -1480,6 +1811,8 @@ 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); @@ -1492,8 +1825,9 @@ 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: @@ -1501,7 +1835,7 @@ } } case 6: - return "add.d %2,%0"; + return "add%u2 %2,%0"; case 7: return "add.d %2,%1,%0"; case 8: @@ -1511,12 +1845,38 @@ } } [(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")]) -(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 @@ -1527,11 +1887,30 @@ [(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 @@ -1542,6 +1921,26 @@ 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")]) ;; Subtract. ;; @@ -1551,11 +1950,21 @@ ;; 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 @@ -1563,12 +1972,31 @@ 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 "sub3" + [(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. @@ -1583,12 +2011,28 @@ 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")]) -(define_insn "sub3" +(define_insn "*sub3_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 %2,%0 sub %2,%0 @@ -1598,6 +2042,20 @@ sub %2,%1,%0" [(set_attr "slottable" "yes,yes,yes,yes,no,no") (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")]) + +(define_insn "*sub3_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 %2,%0 + sub %2,%0 + subq %2,%0 + addq %n2,%0 + sub %2,%0" + [(set_attr "slottable" "yes,yes,yes,yes,no") + (set_attr "cc" "normal,normal,clobber,clobber,normal")]) ;; CRIS has some add/sub-with-sign/zero-extend instructions. ;; Although these perform sign/zero-extension to SImode, they are @@ -1720,7 +2178,7 @@ ;; 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] @@ -1831,7 +2289,7 @@ ;; 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" @@ -1839,7 +2297,7 @@ (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 @@ -1849,9 +2307,22 @@ [(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 "*extopsi" +(define_insn "*extopsi_non_v32" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") (match_operator:SI 3 "cris_operand_extend_operator" @@ -1859,7 +2330,8 @@ (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)" "@ @@ -1868,21 +2340,32 @@ %x3%E4 %2,%0 %x3%E4 %2,%1,%0" [(set_attr "slottable" "yes,yes,no,no")]) - +(define_insn "*extopsi_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")]) + ;; 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 @@ -1891,7 +2374,35 @@ [(set_attr "slottable" "yes,yes,no,no") (set_attr "cc" "clobber")]) -(define_insn "*extopsi_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 "*extopsi_swap_non_v32" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") (match_operator:SI 4 "cris_plus_or_bound_operator" @@ -1899,7 +2410,8 @@ 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 %2,%0 @@ -1907,6 +2419,40 @@ %x4%E3 %2,%0 %x4%E3 %2,%1,%0" [(set_attr "slottable" "yes,yes,no,no")]) + +(define_insn "*adds_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 %2,%0 + adds %2,%0 + addo %2,%1,%0" + [(set_attr "slottable" "yes") + (set_attr "cc" "*,*,none")]) + +(define_insn "*addu_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 %2,%0" + [(set_attr "slottable" "yes")]) + +(define_insn "*bound_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 %2,%0" + [(set_attr "slottable" "yes")]) ;; This is the special case when we use what corresponds to the ;; instruction above in "casesi". Do *not* change it to use the generic @@ -1940,11 +2486,29 @@ (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")]) ;; Multiply instructions. @@ -1984,18 +2548,24 @@ ;; 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")]) @@ -2012,7 +2582,7 @@ (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")]) @@ -2030,7 +2600,8 @@ (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" @@ -2107,7 +2678,7 @@ ;; a / 1000;}" and unsigned. FIXME: Comment above was for 3.2, revisit. (define_insn "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 @@ -2139,7 +2710,8 @@ (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. ;; @@ -2161,7 +2733,8 @@ && 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")]) ;; Logical operators. @@ -2256,11 +2829,11 @@ ;; 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 @@ -2268,6 +2841,19 @@ 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")]) ;; 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 @@ -2331,7 +2917,7 @@ ;; 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")))] @@ -2341,7 +2927,7 @@ ;; pressure (worse code). That will hopefully change with an ;; improved reload pass. - "" + "!TARGET_V32" "@ andq %2,%0 and.w %2,%0 @@ -2353,14 +2939,29 @@ [(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 @@ -2370,12 +2971,34 @@ 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")]) -(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 @@ -2386,12 +3009,26 @@ [(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 @@ -2400,6 +3037,20 @@ 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")]) ;; Bitwise or. @@ -2408,11 +3059,18 @@ ;; It seems there's no need to jump through hoops to get good code such as ;; with andsi3. -(define_insn "iorsi3" +(define_expand "ior3" + [(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 @@ -2423,11 +3081,25 @@ [(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 @@ -2439,11 +3111,26 @@ [(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 @@ -2453,6 +3140,20 @@ 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")]) ;; Exclusive-or @@ -2465,7 +3166,8 @@ (match_operand:SI 2 "register_operand" "r")))] "" "xor %2,%0" - [(set_attr "slottable" "yes")]) + [(set_attr "slottable" "yes") + (set_attr "cc" "noov32")]) (define_insn "xor3" [(set (match_operand:BW 0 "register_operand" "=r") @@ -2522,7 +3224,8 @@ (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_cmpl2" [(set (match_operand:BW 0 "register_operand" "=r") @@ -2545,7 +3248,8 @@ return "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, @@ -2595,7 +3299,8 @@ (match_operand:BW 2 "register_operand" "r")))] "" " %2,%0" - [(set_attr "slottable" "yes")]) + [(set_attr "slottable" "yes") + (set_attr "cc" "noov32")]) (define_insn "*_lowpart" [(set (strict_low_part (match_operand:BW 0 "register_operand" "+r")) @@ -2603,7 +3308,8 @@ (match_operand:BW 1 "register_operand" "r")))] "" " %1,%0" - [(set_attr "slottable" "yes")]) + [(set_attr "slottable" "yes") + (set_attr "cc" "noov32")]) ;; Arithmetic/logical shift left. @@ -2624,7 +3330,7 @@ ? "lslq %2,%0" : "lsl %2,%0"); } [(set_attr "slottable" "yes") - (set_attr "cc" "normal,clobber")]) + (set_attr "cc" "noov32,clobber")]) ;; A strict_low_part matcher. @@ -2634,7 +3340,8 @@ (match_operand:HI 1 "register_operand" "r")))] "" "lsl %1,%0" - [(set_attr "slottable" "yes")]) + [(set_attr "slottable" "yes") + (set_attr "cc" "noov32")]) ;; Various strange insns that gcc likes. @@ -2652,7 +3359,8 @@ (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. @@ -2670,14 +3378,16 @@ (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 @@ -2689,7 +3399,8 @@ 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. @@ -2708,11 +3419,21 @@ ;; 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])) { @@ -2733,6 +3454,30 @@ 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")]) ;; Jump and branch insns. @@ -2748,11 +3493,25 @@ ;; 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. @@ -2777,7 +3536,7 @@ "(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)] @@ -2935,14 +3694,27 @@ ;; 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 @@ -2958,7 +3730,7 @@ (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" @@ -2979,13 +3751,12 @@ ;; 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")]) @@ -3002,10 +3773,27 @@ (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. @@ -3036,7 +3824,7 @@ ;; 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) @@ -3062,6 +3850,62 @@ 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; +}) ;; Split-patterns. Some of them have modes unspecified. This ;; should always be ok; if for no other reason sparc.md has it as @@ -3081,7 +3925,9 @@ ;; 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" "") @@ -3091,7 +3937,8 @@ (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 @@ -3120,7 +3967,8 @@ (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 @@ -3147,7 +3995,8 @@ 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 @@ -3172,7 +4021,8 @@ 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 @@ -3200,7 +4050,8 @@ 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 @@ -3223,7 +4074,8 @@ 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 @@ -3246,7 +4098,8 @@ 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)) @@ -3268,7 +4121,8 @@ 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)) @@ -3818,7 +4672,8 @@ && (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)))])] @@ -3853,7 +4708,8 @@ && (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)))])] @@ -3891,7 +4747,8 @@ && ! 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)))])] @@ -4121,9 +4978,9 @@ (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)))] "") @@ -4150,7 +5007,7 @@ (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)) @@ -4183,7 +5040,7 @@ (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)) @@ -4213,12 +5070,13 @@ (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)))] "") -- 2.30.2