1;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
2;; Copyright (C) 2012-2018 Free Software Foundation, Inc.
3;; Contributed by Andes Technology Corporation.
4;;
5;; This file is part of GCC.
6;;
7;; GCC is free software; you can redistribute it and/or modify it
8;; under the terms of the GNU General Public License as published
9;; by the Free Software Foundation; either version 3, or (at your
10;; option) any later version.
11;;
12;; GCC is distributed in the hope that it will be useful, but WITHOUT
13;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15;; License for more details.
16;;
17;; You should have received a copy of the GNU General Public License
18;; along with GCC; see the file COPYING3.  If not see
19;; <http://www.gnu.org/licenses/>.
20
21
22;; -------------------------------------------------------------
23;; Move DImode/DFmode instructions.
24;; -------------------------------------------------------------
25
26
27(define_expand "movdi"
28  [(set (match_operand:DI 0 "general_operand" "")
29	(match_operand:DI 1 "general_operand" ""))]
30  ""
31{
32  /* Need to force register if mem <- !reg.  */
33  if (MEM_P (operands[0]) && !REG_P (operands[1]))
34    operands[1] = force_reg (DImode, operands[1]);
35})
36
37(define_expand "movdf"
38  [(set (match_operand:DF 0 "general_operand" "")
39	(match_operand:DF 1 "general_operand" ""))]
40  ""
41{
42  /* Need to force register if mem <- !reg.  */
43  if (MEM_P (operands[0]) && !REG_P (operands[1]))
44    operands[1] = force_reg (DFmode, operands[1]);
45})
46
47
48(define_insn "move_<mode>"
49  [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r,  r, r, Da, m, f, Q, f, *r, *f")
50	(match_operand:DIDF 1 "general_operand"      " r, i, Da, m,  r, r, Q, f, f, *f, *r"))]
51  "register_operand(operands[0], <MODE>mode)
52   || register_operand(operands[1], <MODE>mode)"
53{
54  switch (which_alternative)
55    {
56    case 0:
57      return "movd44\t%0, %1";
58    case 1:
59      /* reg <- const_int, we ask gcc to split instruction.  */
60      return "#";
61    case 2:
62      /* The memory format is (mem (reg)),
63	 we can generate 'lmw.bi' instruction.  */
64      return nds32_output_double (operands, true);
65    case 3:
66      /* We haven't 64-bit load instruction,
67	 we split this pattern to two SImode pattern.  */
68      return "#";
69    case 4:
70      /* The memory format is (mem (reg)),
71	 we can generate 'smw.bi' instruction.  */
72      return nds32_output_double (operands, false);
73    case 5:
74      /* We haven't 64-bit store instruction,
75	 we split this pattern to two SImode pattern.  */
76      return "#";
77    case 6:
78      return nds32_output_float_load (operands);
79    case 7:
80      return nds32_output_float_store (operands);
81    case 8:
82      return "fcpysd\t%0, %1, %1";
83    case 9:
84      return "fmfdr\t%0, %1";
85    case 10:
86      return "fmtdr\t%1, %0";
87    default:
88      gcc_unreachable ();
89    }
90}
91  [(set_attr "type"    "alu,alu,load,load,store,store,fload,fstore,fcpy,fmfdr,fmtdr")
92   (set_attr_alternative "length"
93     [
94       ;; Alternative 0
95       (if_then_else (match_test "!TARGET_16_BIT")
96		     (const_int 4)
97		     (const_int 2))
98       ;; Alternative 1
99       (const_int 16)
100       ;; Alternative 2
101       (const_int 4)
102       ;; Alternative 3
103       (const_int 8)
104       ;; Alternative 4
105       (const_int 4)
106       ;; Alternative 5
107       (const_int 8)
108       ;; Alternative 6
109       (const_int 4)
110       ;; Alternative 7
111       (const_int 4)
112       ;; Alternative 8
113       (const_int 4)
114       ;; Alternative 9
115       (const_int 4)
116       ;; Alternative 10
117       (const_int 4)
118     ])
119   (set_attr "feature" " v1, v1,  v1,  v1,   v1,   v1,    fpu,    fpu,    fpu,    fpu,    fpu")])
120
121;; Split move_di pattern when the hard register is odd.
122(define_split
123  [(set (match_operand:DIDF 0 "register_operand" "")
124	(match_operand:DIDF 1 "register_operand" ""))]
125  "(NDS32_IS_GPR_REGNUM (REGNO (operands[0]))
126    && ((REGNO (operands[0]) & 0x1) == 1))
127   || (NDS32_IS_GPR_REGNUM (REGNO (operands[1]))
128       && ((REGNO (operands[1]) & 0x1) == 1))"
129  [(set (match_dup 2) (match_dup 3))
130   (set (match_dup 4) (match_dup 5))]
131  {
132     operands[2] = gen_lowpart (SImode, operands[0]);
133     operands[4] = gen_highpart (SImode, operands[0]);
134     operands[3] = gen_lowpart (SImode, operands[1]);
135     operands[5] = gen_highpart (SImode, operands[1]);
136  }
137)
138
139(define_split
140  [(set (match_operand:DIDF 0 "register_operand"     "")
141	(match_operand:DIDF 1 "const_double_operand" ""))]
142  "reload_completed"
143  [(set (match_dup 2) (match_dup 3))
144   (set (match_dup 4) (match_dup 5))]
145{
146  /* Construct lowpart rtx.  */
147  operands[2] = gen_lowpart (SImode, operands[0]);
148  operands[3] = gen_lowpart (SImode, operands[1]);
149
150  /* Construct highpart rtx.  */
151  /* Note that operands[1] can be VOIDmode constant,
152     so we need to use gen_highpart_mode().
153     Refer to gcc/emit-rtl.c for more information.  */
154  operands[4] = gen_highpart (SImode, operands[0]);
155  operands[5] = gen_highpart_mode (SImode,
156				   GET_MODE (operands[0]), operands[1]);
157
158  /* Actually we would like to create move behavior by ourself.
159     So that movsi expander could have chance to split large constant.  */
160  emit_move_insn (operands[2], operands[3]);
161
162  unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode);
163  if ((UINTVAL (operands[3]) & mask) == (UINTVAL (operands[5]) & mask))
164    emit_move_insn (operands[4], operands[2]);
165  else
166    emit_move_insn (operands[4], operands[5]);
167  DONE;
168})
169
170;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA.
171;; We only need to split it under V2 ISA or none-16-bit code generation.
172(define_split
173  [(set (match_operand:DIDF 0 "register_operand" "")
174	(match_operand:DIDF 1 "register_operand" ""))]
175  "reload_completed
176   && (TARGET_ISA_V2 || !TARGET_16_BIT)
177   && NDS32_IS_GPR_REGNUM (REGNO (operands[0]))
178   && NDS32_IS_GPR_REGNUM (REGNO (operands[1]))"
179  [(set (match_dup 0) (match_dup 1))
180   (set (match_dup 2) (match_dup 3))]
181{
182  operands[2] = gen_highpart (SImode, operands[0]);
183  operands[3] = gen_highpart (SImode, operands[1]);
184  operands[0] = gen_lowpart (SImode, operands[0]);
185  operands[1] = gen_lowpart (SImode, operands[1]);
186
187  /* Handle a partial overlap.  */
188  if (rtx_equal_p (operands[0], operands[3]))
189    {
190      rtx tmp0 = operands[0];
191      rtx tmp1 = operands[1];
192
193      operands[0] = operands[2];
194      operands[1] = operands[3];
195      operands[2] = tmp0;
196      operands[3] = tmp1;
197    }
198})
199
200(define_split
201  [(set (match_operand:DIDF 0 "nds32_general_register_operand" "")
202	(match_operand:DIDF 1 "memory_operand" ""))]
203  "reload_completed
204   && nds32_split_double_word_load_store_p (operands, true)"
205  [(set (match_dup 2) (match_dup 3))
206   (set (match_dup 4) (match_dup 5))]
207{
208  nds32_spilt_doubleword (operands, true);
209})
210
211(define_split
212  [(set (match_operand:DIDF 0  "memory_operand" "")
213	(match_operand:DIDF 1  "nds32_general_register_operand" ""))]
214  "reload_completed
215   && nds32_split_double_word_load_store_p (operands, false)"
216  [(set (match_dup 2) (match_dup 3))
217   (set (match_dup 4) (match_dup 5))]
218{
219  nds32_spilt_doubleword (operands, false);
220})
221
222;; -------------------------------------------------------------
223;; Boolean DImode instructions.
224;; -------------------------------------------------------------
225
226;; Nowadays, the generic code is supposed to split the DImode
227;; boolean operations and have good code generation.
228;; Unless we find out some bad cases, there is no need to
229;; define DImode boolean operations by ourself.
230
231;; -------------------------------------------------------------
232