1 ;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
2 ;; Copyright (C) 2012-2017 Free Software Foundation, Inc.
3 ;; Contributed by Andes Technology Corporation.
5 ;; This file is part of GCC.
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.
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.
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/>.
22 ;; -------------------------------------------------------------
23 ;; Move DImode/DFmode instructions.
24 ;; -------------------------------------------------------------
27 (define_expand "movdi"
28 [(set (match_operand:DI 0 "general_operand" "")
29 (match_operand:DI 1 "general_operand" ""))]
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]);
37 (define_expand "movdf"
38 [(set (match_operand:DF 0 "general_operand" "")
39 (match_operand:DF 1 "general_operand" ""))]
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]);
48 (define_insn "move_<mode>"
49 [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, m")
50 (match_operand:DIDF 1 "general_operand" " r, i, m, r"))]
56 switch (which_alternative)
59 return "movd44\t%0, %1";
62 /* reg <- const_int, we ask gcc to split instruction. */
66 /* Refer to nds32_legitimate_address_p() in nds32.c,
67 we only allow "reg", "symbol_ref", "const", and "reg + const_int"
68 as address rtx for DImode/DFmode memory access. */
69 addr = XEXP (operands[1], 0);
71 otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
72 otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
77 /* (reg) <- (mem (reg)) */
78 output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops);
80 else if (GET_CODE (addr) == PLUS)
82 /* (reg) <- (mem (plus (reg) (const_int))) */
83 rtx op0 = XEXP (addr, 0);
84 rtx op1 = XEXP (addr, 1);
90 otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
96 otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
99 /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */
100 if (REGNO (otherops[0]) != REGNO (otherops[2]))
102 output_asm_insn ("lwi\t%0, [%2 + (%3)]", otherops);
103 output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
107 output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
108 output_asm_insn ("lwi\t%0,[ %2 + (%3)]", otherops);
113 /* (reg) <- (mem (symbol_ref ...))
114 (reg) <- (mem (const ...)) */
115 output_asm_insn ("lwi.gp\t%0, [ + %2]", otherops);
116 output_asm_insn ("lwi.gp\t%1, [ + %2 + 4]", otherops);
119 /* We have already used output_asm_insn() by ourself,
120 so return an empty string. */
124 /* Refer to nds32_legitimate_address_p() in nds32.c,
125 we only allow "reg", "symbol_ref", "const", and "reg + const_int"
126 as address rtx for DImode/DFmode memory access. */
127 addr = XEXP (operands[0], 0);
129 otherops[0] = gen_rtx_REG (SImode, REGNO (operands[1]));
130 otherops[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
135 /* (mem (reg)) <- (reg) */
136 output_asm_insn ("smw.bi\t%0, [%2], %1, 0", otherops);
138 else if (GET_CODE (addr) == PLUS)
140 /* (mem (plus (reg) (const_int))) <- (reg) */
141 rtx op0 = XEXP (addr, 0);
142 rtx op1 = XEXP (addr, 1);
148 otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
154 otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
157 /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */
158 if (REGNO (otherops[0]) != REGNO (otherops[2]))
160 output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
161 output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
165 output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
166 output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
171 /* (mem (symbol_ref ...)) <- (reg)
172 (mem (const ...)) <- (reg) */
173 output_asm_insn ("swi.gp\t%0, [ + %2]", otherops);
174 output_asm_insn ("swi.gp\t%1, [ + %2 + 4]", otherops);
177 /* We have already used output_asm_insn() by ourself,
178 so return an empty string. */
185 [(set_attr "type" "move,move,move,move")
186 (set_attr "length" " 4, 16, 8, 8")])
189 [(set (match_operand:DIDF 0 "register_operand" "")
190 (match_operand:DIDF 1 "const_double_operand" ""))]
192 [(set (match_dup 2) (match_dup 3))
193 (set (match_dup 4) (match_dup 5))]
195 /* Construct lowpart rtx. */
196 operands[2] = gen_lowpart (SImode, operands[0]);
197 operands[3] = gen_lowpart (SImode, operands[1]);
199 /* Construct highpart rtx. */
200 /* Note that operands[1] can be VOIDmode constant,
201 so we need to use gen_highpart_mode().
202 Refer to gcc/emit-rtl.c for more information. */
203 operands[4] = gen_highpart (SImode, operands[0]);
204 operands[5] = gen_highpart_mode (SImode,
205 GET_MODE (operands[0]), operands[1]);
207 /* Actually we would like to create move behavior by ourself.
208 So that movsi expander could have chance to split large constant. */
209 emit_move_insn (operands[2], operands[3]);
210 emit_move_insn (operands[4], operands[5]);
214 ;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA.
215 ;; We only need to split it under V2 ISA or none-16-bit code generation.
217 [(set (match_operand:DIDF 0 "register_operand" "")
218 (match_operand:DIDF 1 "register_operand" ""))]
220 && (TARGET_ISA_V2 || !TARGET_16_BIT)"
221 [(set (match_dup 0) (match_dup 1))
222 (set (match_dup 2) (match_dup 3))]
224 operands[2] = gen_highpart (SImode, operands[0]);
225 operands[3] = gen_highpart (SImode, operands[1]);
226 operands[0] = gen_lowpart (SImode, operands[0]);
227 operands[1] = gen_lowpart (SImode, operands[1]);
229 /* Handle a partial overlap. */
230 if (rtx_equal_p (operands[0], operands[3]))
232 rtx tmp0 = operands[0];
233 rtx tmp1 = operands[1];
235 operands[0] = operands[2];
236 operands[1] = operands[3];
242 ;; -------------------------------------------------------------
243 ;; Boolean DImode instructions.
244 ;; -------------------------------------------------------------
246 ;; Nowadays, the generic code is supposed to split the DImode
247 ;; boolean operations and have good code generation.
248 ;; Unless we find out some bad cases, there is no need to
249 ;; define DImode boolean operations by ourself.
251 ;; -------------------------------------------------------------