]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nds32/nds32-utils.c
1 /* Auxiliary functions for pipeline descriptions pattern of Andes
2 NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2018 Free Software Foundation, Inc.
4 Contributed by Andes Technology Corporation.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 /* ------------------------------------------------------------------------ */
24 #define IN_TARGET_CODE 1
28 #include "coretypes.h"
35 #include "optabs.h" /* For GEN_FCN. */
37 #include "tm-constrs.h"
38 #include "insn-attr.h"
43 /* Get the rtx in the PATTERN field of an insn. If INSN is not an insn,
44 the funciton doesn't change anything and returns it directly. */
46 extract_pattern_from_insn (rtx insn
)
49 return PATTERN (insn
);
54 /* Get the number of elements in a parallel rtx. */
56 parallel_elements (rtx parallel_rtx
)
58 parallel_rtx
= extract_pattern_from_insn (parallel_rtx
);
59 gcc_assert (GET_CODE (parallel_rtx
) == PARALLEL
);
61 return XVECLEN (parallel_rtx
, 0);
64 /* Extract an rtx from a parallel rtx with index NTH. If NTH is a negative
65 value, the function returns the last NTH rtx. */
67 parallel_element (rtx parallel_rtx
, int nth
)
69 parallel_rtx
= extract_pattern_from_insn (parallel_rtx
);
70 gcc_assert (GET_CODE (parallel_rtx
) == PARALLEL
);
72 int len
= parallel_elements (parallel_rtx
);
79 return XVECEXP (parallel_rtx
, 0, nth
);
86 return XVECEXP (parallel_rtx
, 0, len
+ nth
);
90 /* Functions to determine whether INSN is single-word, double-word
91 or partial-word load/store insn. */
94 load_single_p (rtx_insn
*insn
)
96 if (get_attr_type (insn
) != TYPE_LOAD
)
99 if (INSN_CODE (insn
) == CODE_FOR_move_di
||
100 INSN_CODE (insn
) == CODE_FOR_move_df
)
107 store_single_p (rtx_insn
*insn
)
109 if (get_attr_type (insn
) != TYPE_STORE
)
112 if (INSN_CODE (insn
) == CODE_FOR_move_di
||
113 INSN_CODE (insn
) == CODE_FOR_move_df
)
120 load_double_p (rtx_insn
*insn
)
122 if (get_attr_type (insn
) != TYPE_LOAD
)
125 if (INSN_CODE (insn
) != CODE_FOR_move_di
&&
126 INSN_CODE (insn
) != CODE_FOR_move_df
)
133 store_double_p (rtx_insn
*insn
)
135 if (get_attr_type (insn
) != TYPE_STORE
)
138 if (INSN_CODE (insn
) != CODE_FOR_move_di
&&
139 INSN_CODE (insn
) != CODE_FOR_move_df
)
145 /* Determine if INSN is a post update insn. */
147 post_update_insn_p (rtx_insn
*insn
)
149 if (find_post_update_rtx (insn
) == -1)
155 /* Check if the address of MEM_RTX consists of a base register and an
158 immed_offset_p (rtx mem_rtx
)
160 gcc_assert (MEM_P (mem_rtx
));
162 rtx addr_rtx
= XEXP (mem_rtx
, 0);
164 /* (mem (reg)) is equivalent to (mem (plus (reg) (const_int 0))) */
165 if (REG_P (addr_rtx
))
168 /* (mem (plus (reg) (const_int))) */
169 if (GET_CODE (addr_rtx
) == PLUS
170 && GET_CODE (XEXP (addr_rtx
, 1)) == CONST_INT
)
176 /* Find the post update rtx in INSN. If INSN is a load/store multiple insn,
177 the function returns the vector index of its parallel part. If INSN is a
178 single load/store insn, the function returns 0. If INSN is not a post-
179 update insn, the function returns -1. */
181 find_post_update_rtx (rtx_insn
*insn
)
186 switch (get_attr_type (insn
))
188 case TYPE_LOAD_MULTIPLE
:
189 case TYPE_STORE_MULTIPLE
:
190 /* Find a pattern in a parallel rtx:
191 (set (reg) (plus (reg) (const_int))) */
192 len
= parallel_elements (insn
);
193 for (i
= 0; i
< len
; ++i
)
195 rtx curr_insn
= parallel_element (insn
, i
);
197 if (GET_CODE (curr_insn
) == SET
198 && REG_P (SET_DEST (curr_insn
))
199 && GET_CODE (SET_SRC (curr_insn
)) == PLUS
)
208 mem_rtx
= extract_mem_rtx (insn
);
209 /* (mem (post_inc (reg))) */
210 switch (GET_CODE (XEXP (mem_rtx
, 0)))
226 /* Extract the MEM rtx from a load/store insn. */
228 extract_mem_rtx (rtx_insn
*insn
)
230 rtx body
= PATTERN (insn
);
232 switch (get_attr_type (insn
))
236 if (MEM_P (SET_SRC (body
)))
237 return SET_SRC (body
);
239 /* unaligned address: (unspec [(mem)]) */
240 if (GET_CODE (SET_SRC (body
)) == UNSPEC
)
242 gcc_assert (MEM_P (XVECEXP (SET_SRC (body
), 0, 0)));
243 return XVECEXP (SET_SRC (body
), 0, 0);
246 /* (sign_extend (mem)) */
247 gcc_assert (MEM_P (XEXP (SET_SRC (body
), 0)));
248 return XEXP (SET_SRC (body
), 0);
252 if (MEM_P (SET_DEST (body
)))
253 return SET_DEST (body
);
255 /* unaligned address: (unspec [(mem)]) */
256 if (GET_CODE (SET_DEST (body
)) == UNSPEC
)
258 gcc_assert (MEM_P (XVECEXP (SET_DEST (body
), 0, 0)));
259 return XVECEXP (SET_DEST (body
), 0, 0);
262 /* (sign_extend (mem)) */
263 gcc_assert (MEM_P (XEXP (SET_DEST (body
), 0)));
264 return XEXP (SET_DEST (body
), 0);
271 /* Extract the base register from load/store insns. The function returns
272 NULL_RTX if the address is not consist of any registers. */
274 extract_base_reg (rtx_insn
*insn
)
276 int post_update_rtx_index
;
280 /* Find the MEM rtx. If we can find an insn updating the base register,
281 the base register will be returned directly. */
282 switch (get_attr_type (insn
))
284 case TYPE_LOAD_MULTIPLE
:
285 post_update_rtx_index
= find_post_update_rtx (insn
);
287 if (post_update_rtx_index
!= -1)
288 return SET_DEST (parallel_element (insn
, post_update_rtx_index
));
290 mem_rtx
= SET_SRC (parallel_element (insn
, 0));
293 case TYPE_STORE_MULTIPLE
:
294 post_update_rtx_index
= find_post_update_rtx (insn
);
296 if (post_update_rtx_index
!= -1)
297 return SET_DEST (parallel_element (insn
, post_update_rtx_index
));
299 mem_rtx
= SET_DEST (parallel_element (insn
, 0));
306 mem_rtx
= extract_mem_rtx (insn
);
313 gcc_assert (MEM_P (mem_rtx
));
316 if (REG_P (XEXP (mem_rtx
, 0)))
317 return XEXP (mem_rtx
, 0);
319 plus_rtx
= XEXP (mem_rtx
, 0);
321 if (GET_CODE (plus_rtx
) == SYMBOL_REF
322 || GET_CODE (plus_rtx
) == CONST
)
325 gcc_assert (GET_CODE (plus_rtx
) == PLUS
326 || GET_CODE (plus_rtx
) == POST_INC
327 || GET_CODE (plus_rtx
) == POST_DEC
328 || GET_CODE (plus_rtx
) == POST_MODIFY
);
329 gcc_assert (REG_P (XEXP (plus_rtx
, 0)));
330 /* (mem (plus (reg) (const_int))) or
331 (mem (post_inc (reg))) or
332 (mem (post_dec (reg))) or
333 (mem (post_modify (reg) (plus (reg) (reg)))) */
334 return XEXP (plus_rtx
, 0);
337 /* Extract the register of the shift operand from an ALU_SHIFT rtx. */
339 extract_shift_reg (rtx alu_shift_rtx
)
341 alu_shift_rtx
= extract_pattern_from_insn (alu_shift_rtx
);
343 rtx alu_rtx
= SET_SRC (alu_shift_rtx
);
346 /* Various forms of ALU_SHIFT can be made by the combiner.
347 See the difference between add_slli and sub_slli in nds32.md. */
348 if (REG_P (XEXP (alu_rtx
, 0)))
349 shift_rtx
= XEXP (alu_rtx
, 1);
351 shift_rtx
= XEXP (alu_rtx
, 0);
353 return XEXP (shift_rtx
, 0);
356 /* Check if INSN is a movd44 insn. */
358 movd44_insn_p (rtx_insn
*insn
)
360 if (get_attr_type (insn
) == TYPE_ALU
361 && (INSN_CODE (insn
) == CODE_FOR_move_di
362 || INSN_CODE (insn
) == CODE_FOR_move_df
))
364 rtx body
= PATTERN (insn
);
365 gcc_assert (GET_CODE (body
) == SET
);
367 rtx src
= SET_SRC (body
);
368 rtx dest
= SET_DEST (body
);
370 if ((REG_P (src
) || GET_CODE (src
) == SUBREG
)
371 && (REG_P (dest
) || GET_CODE (dest
) == SUBREG
))
380 /* Extract the rtx representing non-accumulation operands of a MAC insn. */
382 extract_mac_non_acc_rtx (rtx_insn
*insn
)
384 rtx exp
= SET_SRC (PATTERN (insn
));
386 switch (get_attr_type (insn
))
389 if (REG_P (XEXP (exp
, 0)))
390 return XEXP (exp
, 1);
392 return XEXP (exp
, 0);