[NDS32] Add intrinsic functions for FPU.
[official-gcc.git] / gcc / config / nds32 / nds32-intrinsic.c
blobc5435bb9dd41bee9af2eaa73504168333bfb0b12
1 /* Intrinsic functions of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2018 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/>. */
21 /* ------------------------------------------------------------------------ */
23 #define IN_TARGET_CODE 1
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "backend.h"
29 #include "target.h"
30 #include "rtl.h"
31 #include "memmodel.h"
32 #include "emit-rtl.h"
33 #include "tree.h"
34 #include "memmodel.h"
35 #include "optabs.h" /* For GEN_FCN. */
36 #include "diagnostic-core.h"
37 #include "stor-layout.h"
38 #include "expr.h"
39 #include "langhooks.h" /* For add_builtin_function(). */
40 #include "recog.h"
41 #include "explow.h"
43 /* ------------------------------------------------------------------------ */
45 /* Read the requested argument from the EXP given by INDEX.
46 Return the value as an rtx. */
47 static rtx
48 nds32_read_argument (tree exp, unsigned int index)
50 return expand_normal (CALL_EXPR_ARG (exp, index));
53 /* Return a legitimate rtx for instruction ICODE's return value. Use TARGET
54 if it's not null, has the right mode, and satisfies operand 0's
55 predicate. */
56 static rtx
57 nds32_legitimize_target (enum insn_code icode, rtx target)
59 enum machine_mode mode = insn_data[icode].operand[0].mode;
61 if (! target
62 || GET_MODE (target) != mode
63 || ! (*insn_data[icode].operand[0].predicate) (target, mode))
64 return gen_reg_rtx (mode);
65 else
66 return target;
69 /* Given that ARG is being passed as operand OPNUM to instruction ICODE,
70 check whether ARG satisfies the operand's constraints. If it doesn't,
71 copy ARG to a temporary register and return that. Otherwise return ARG
72 itself. */
73 static rtx
74 nds32_legitimize_argument (enum insn_code icode, int opnum, rtx arg)
76 enum machine_mode mode = insn_data[icode].operand[opnum].mode;
78 if ((*insn_data[icode].operand[opnum].predicate) (arg, mode))
79 return arg;
80 else if (VECTOR_MODE_P (mode) && CONST_INT_P (arg))
82 /* Handle CONST_INT covert to CONST_VECTOR. */
83 int nunits = GET_MODE_NUNITS (mode);
84 int i, shift = 0;
85 rtvec v = rtvec_alloc (nunits);
86 int val = INTVAL (arg);
87 enum machine_mode val_mode = (mode == V4QImode) ? QImode : HImode;
88 int shift_acc = (val_mode == QImode) ? 8 : 16;
89 int mask = (val_mode == QImode) ? 0xff : 0xffff;
90 int tmp_val = val;
92 if (TARGET_BIG_ENDIAN)
93 for (i = 0; i < nunits; i++)
95 tmp_val = (val >> shift) & mask;
96 RTVEC_ELT (v, nunits - i - 1) = gen_int_mode (tmp_val, val_mode);
97 shift += shift_acc;
99 else
100 for (i = 0; i < nunits; i++)
102 tmp_val = (val >> shift) & mask;
103 RTVEC_ELT (v, i) = gen_int_mode (tmp_val, val_mode);
104 shift += shift_acc;
107 return copy_to_mode_reg (mode, gen_rtx_CONST_VECTOR (mode, v));
109 else
111 rtx tmp_rtx = gen_reg_rtx (mode);
112 convert_move (tmp_rtx, arg, false);
113 return tmp_rtx;
117 /* Return true if OPVAL can be used for operand OPNUM of instruction ICODE.
118 The instruction should require a constant operand of some sort. The
119 function prints an error if OPVAL is not valid. */
120 static int
121 nds32_check_constant_argument (enum insn_code icode, int opnum, rtx opval,
122 const char *name)
124 if (GET_CODE (opval) != CONST_INT)
126 error ("invalid argument to built-in function %s", name);
127 return false;
129 if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
131 error ("constant argument out of range for %s", name);
133 return false;
135 return true;
138 /* Expand builtins that take one operand. */
139 static rtx
140 nds32_expand_unop_builtin (enum insn_code icode, tree exp, rtx target,
141 bool return_p)
143 rtx pat;
144 rtx op0 = nds32_read_argument (exp, 0);
145 int op0_num = return_p ? 1 : 0;
147 if (return_p)
148 target = nds32_legitimize_target (icode, target);
150 op0 = nds32_legitimize_argument (icode, op0_num, op0);
152 /* Emit and return the new instruction. */
153 if (return_p)
154 pat = GEN_FCN (icode) (target, op0);
155 else
156 pat = GEN_FCN (icode) (op0);
158 if (! pat)
159 return NULL_RTX;
161 emit_insn (pat);
162 return target;
165 /* Expand builtins that take one operands and the first is immediate. */
166 static rtx
167 nds32_expand_unopimm_builtin (enum insn_code icode, tree exp, rtx target,
168 bool return_p, const char *name)
170 rtx pat;
171 rtx op0 = nds32_read_argument (exp, 0);
172 int op0_num = return_p ? 1 : 0;
174 if (return_p)
175 target = nds32_legitimize_target (icode, target);
177 if (!nds32_check_constant_argument (icode, op0_num, op0, name))
178 return NULL_RTX;
180 op0 = nds32_legitimize_argument (icode, op0_num, op0);
182 /* Emit and return the new instruction. */
183 if (return_p)
184 pat = GEN_FCN (icode) (target, op0);
185 else
186 pat = GEN_FCN (icode) (op0);
188 if (! pat)
189 return NULL_RTX;
191 emit_insn (pat);
192 return target;
195 /* Expand builtins that take two operands. */
196 static rtx
197 nds32_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
198 bool return_p)
200 rtx pat;
201 rtx op0 = nds32_read_argument (exp, 0);
202 rtx op1 = nds32_read_argument (exp, 1);
203 int op0_num = return_p ? 1 : 0;
204 int op1_num = return_p ? 2 : 1;
206 if (return_p)
207 target = nds32_legitimize_target (icode, target);
209 op0 = nds32_legitimize_argument (icode, op0_num, op0);
210 op1 = nds32_legitimize_argument (icode, op1_num, op1);
212 /* Emit and return the new instruction. */
213 if (return_p)
214 pat = GEN_FCN (icode) (target, op0, op1);
215 else
216 pat = GEN_FCN (icode) (op0, op1);
218 if (! pat)
219 return NULL_RTX;
221 emit_insn (pat);
222 return target;
225 struct builtin_description
227 const enum insn_code icode;
228 const char *name;
229 enum nds32_builtins code;
230 bool return_p;
233 #define NDS32_BUILTIN(code, string, builtin) \
234 { CODE_FOR_##code, "__nds32__" string, \
235 NDS32_BUILTIN_##builtin, true },
237 #define NDS32_NO_TARGET_BUILTIN(code, string, builtin) \
238 { CODE_FOR_##code, "__nds32__" string, \
239 NDS32_BUILTIN_##builtin, false },
241 /* Intrinsics that no argument, and that return value. */
242 static struct builtin_description bdesc_noarg[] =
244 NDS32_BUILTIN(unspec_fmfcfg, "fmfcfg", FMFCFG)
245 NDS32_BUILTIN(unspec_fmfcsr, "fmfcsr", FMFCSR)
248 /* Intrinsics that take just one argument. */
249 static struct builtin_description bdesc_1arg[] =
251 NDS32_BUILTIN(unaligned_load_hw, "unaligned_load_hw", UALOAD_HW)
252 NDS32_BUILTIN(unaligned_loadsi, "unaligned_load_w", UALOAD_W)
253 NDS32_BUILTIN(unaligned_loaddi, "unaligned_load_dw", UALOAD_DW)
254 NDS32_NO_TARGET_BUILTIN(unspec_volatile_isync, "isync", ISYNC)
255 NDS32_NO_TARGET_BUILTIN(unspec_fmtcsr, "fmtcsr", FMTCSR)
258 /* Intrinsics that take just one argument. and the argument is immediate. */
259 static struct builtin_description bdesc_1argimm[] =
261 NDS32_BUILTIN(unspec_volatile_mfsr, "mfsr", MFSR)
262 NDS32_BUILTIN(unspec_volatile_mfusr, "mfsr", MFUSR)
265 /* Intrinsics that take two arguments. */
266 static struct builtin_description bdesc_2arg[] =
268 NDS32_BUILTIN(unspec_fcpynss, "fcpynss", FCPYNSS)
269 NDS32_BUILTIN(unspec_fcpyss, "fcpyss", FCPYSS)
270 NDS32_BUILTIN(unspec_fcpynsd, "fcpynsd", FCPYNSD)
271 NDS32_BUILTIN(unspec_fcpysd, "fcpysd", FCPYSD)
272 NDS32_BUILTIN(unspec_ffb, "ffb", FFB)
273 NDS32_BUILTIN(unspec_ffmism, "ffmsim", FFMISM)
274 NDS32_BUILTIN(unspec_flmism, "flmism", FLMISM)
275 NDS32_NO_TARGET_BUILTIN(unspec_volatile_mtsr, "mtsr", MTSR)
276 NDS32_NO_TARGET_BUILTIN(unspec_volatile_mtusr, "mtusr", MTUSR)
277 NDS32_NO_TARGET_BUILTIN(unaligned_store_hw, "unaligned_store_hw", UASTORE_HW)
278 NDS32_NO_TARGET_BUILTIN(unaligned_storesi, "unaligned_store_hw", UASTORE_W)
279 NDS32_NO_TARGET_BUILTIN(unaligned_storedi, "unaligned_store_hw", UASTORE_DW)
284 nds32_expand_builtin_impl (tree exp,
285 rtx target,
286 rtx subtarget ATTRIBUTE_UNUSED,
287 enum machine_mode mode ATTRIBUTE_UNUSED,
288 int ignore ATTRIBUTE_UNUSED)
290 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
291 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
292 unsigned i;
293 struct builtin_description *d;
295 switch (fcode)
297 /* FPU Register Transfer. */
298 case NDS32_BUILTIN_FMFCFG:
299 case NDS32_BUILTIN_FMFCSR:
300 case NDS32_BUILTIN_FMTCSR:
301 case NDS32_BUILTIN_FCPYNSS:
302 case NDS32_BUILTIN_FCPYSS:
303 /* Both v3s and v3f toolchains define TARGET_FPU_SINGLE. */
304 if (!TARGET_FPU_SINGLE)
306 error ("this builtin function is only available "
307 "on the v3s or v3f toolchain");
308 return NULL_RTX;
310 break;
312 /* FPU Register Transfer. */
313 case NDS32_BUILTIN_FCPYNSD:
314 case NDS32_BUILTIN_FCPYSD:
315 /* Only v3f toolchain defines TARGET_FPU_DOUBLE. */
316 if (!TARGET_FPU_DOUBLE)
318 error ("this builtin function is only available "
319 "on the v3f toolchain");
320 return NULL_RTX;
322 break;
323 /* String Extension */
324 case NDS32_BUILTIN_FFB:
325 case NDS32_BUILTIN_FFMISM:
326 case NDS32_BUILTIN_FLMISM:
327 if (!TARGET_EXT_STRING)
329 error ("don't support string extension instructions");
330 return NULL_RTX;
332 break;
334 default:
335 break;
338 /* Since there are no result and operands, we can simply emit this rtx. */
339 switch (fcode)
341 case NDS32_BUILTIN_ISB:
342 emit_insn (gen_unspec_volatile_isb ());
343 return target;
344 case NDS32_BUILTIN_SETGIE_EN:
345 emit_insn (gen_unspec_volatile_setgie_en ());
346 return target;
347 case NDS32_BUILTIN_SETGIE_DIS:
348 emit_insn (gen_unspec_volatile_setgie_dis ());
349 return target;
350 default:
351 break;
354 /* Expand groups of builtins. */
355 for (i = 0, d = bdesc_noarg; i < ARRAY_SIZE (bdesc_noarg); i++, d++)
356 if (d->code == fcode)
357 return nds32_expand_noarg_builtin (d->icode, target);
359 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
360 if (d->code == fcode)
361 return nds32_expand_unop_builtin (d->icode, exp, target, d->return_p);
363 for (i = 0, d = bdesc_1argimm; i < ARRAY_SIZE (bdesc_1argimm); i++, d++)
364 if (d->code == fcode)
365 return nds32_expand_unopimm_builtin (d->icode, exp, target,
366 d->return_p, d->name);
368 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
369 if (d->code == fcode)
370 return nds32_expand_binop_builtin (d->icode, exp, target, d->return_p);
373 return NULL_RTX;
376 static GTY(()) tree nds32_builtin_decls[NDS32_BUILTIN_COUNT];
378 /* Return the NDS32 builtin for CODE. */
379 tree
380 nds32_builtin_decl_impl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
382 if (code >= NDS32_BUILTIN_COUNT)
383 return error_mark_node;
385 return nds32_builtin_decls[code];
388 void
389 nds32_init_builtins_impl (void)
391 #define ADD_NDS32_BUILTIN0(NAME, RET_TYPE, CODE) \
392 nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
393 add_builtin_function ("__builtin_nds32_" NAME, \
394 build_function_type_list (RET_TYPE##_type_node, \
395 NULL_TREE), \
396 NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
398 #define ADD_NDS32_BUILTIN1(NAME, RET_TYPE, ARG_TYPE, CODE) \
399 nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
400 add_builtin_function ("__builtin_nds32_" NAME, \
401 build_function_type_list (RET_TYPE##_type_node, \
402 ARG_TYPE##_type_node, \
403 NULL_TREE), \
404 NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
406 #define ADD_NDS32_BUILTIN2(NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2, CODE) \
407 nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
408 add_builtin_function ("__builtin_nds32_" NAME, \
409 build_function_type_list (RET_TYPE##_type_node, \
410 ARG_TYPE1##_type_node,\
411 ARG_TYPE2##_type_node,\
412 NULL_TREE), \
413 NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
415 #define ADD_NDS32_BUILTIN3(NAME, RET_TYPE, \
416 ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, CODE) \
417 nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
418 add_builtin_function ("__builtin_nds32_" NAME, \
419 build_function_type_list (RET_TYPE##_type_node, \
420 ARG_TYPE1##_type_node,\
421 ARG_TYPE2##_type_node,\
422 ARG_TYPE3##_type_node,\
423 NULL_TREE), \
424 NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
426 /* Looking for return type and argument can be found in tree.h file. */
427 tree ptr_ushort_type_node = build_pointer_type (short_unsigned_type_node);
428 tree ptr_uint_type_node = build_pointer_type (unsigned_type_node);
429 tree ptr_ulong_type_node = build_pointer_type (long_long_unsigned_type_node);
431 /* Cache. */
432 ADD_NDS32_BUILTIN1 ("isync", void, ptr_uint, ISYNC);
433 ADD_NDS32_BUILTIN0 ("isb", void, ISB);
435 /* Register Transfer. */
436 ADD_NDS32_BUILTIN1 ("mfsr", unsigned, integer, MFSR);
437 ADD_NDS32_BUILTIN1 ("mfusr", unsigned, integer, MFUSR);
438 ADD_NDS32_BUILTIN2 ("mtsr", void, unsigned, integer, MTSR);
439 ADD_NDS32_BUILTIN2 ("mtusr", void, unsigned, integer, MTUSR);
441 /* FPU Register Transfer. */
442 ADD_NDS32_BUILTIN0 ("fmfcsr", unsigned, FMFCSR);
443 ADD_NDS32_BUILTIN1 ("fmtcsr", void, unsigned, FMTCSR);
444 ADD_NDS32_BUILTIN0 ("fmfcfg", unsigned, FMFCFG);
445 ADD_NDS32_BUILTIN2 ("fcpyss", float, float, float, FCPYSS);
446 ADD_NDS32_BUILTIN2 ("fcpynss", float, float, float, FCPYNSS);
447 ADD_NDS32_BUILTIN2 ("fcpysd", double, double, double, FCPYSD);
448 ADD_NDS32_BUILTIN2 ("fcpynsd", double, double, double, FCPYNSD);
450 /* Interrupt. */
451 ADD_NDS32_BUILTIN0 ("setgie_en", void, SETGIE_EN);
452 ADD_NDS32_BUILTIN0 ("setgie_dis", void, SETGIE_DIS);
454 /* Unaligned Load/Store */
455 ADD_NDS32_BUILTIN1 ("unaligned_load_hw", short_unsigned, ptr_ushort,
456 UALOAD_HW);
457 ADD_NDS32_BUILTIN1 ("unaligned_load_w", unsigned, ptr_uint, UALOAD_W);
458 ADD_NDS32_BUILTIN1 ("unaligned_load_dw", long_long_unsigned, ptr_ulong,
459 UALOAD_DW);
460 ADD_NDS32_BUILTIN2 ("unaligned_store_hw", void, ptr_ushort, short_unsigned,
461 UASTORE_HW);
462 ADD_NDS32_BUILTIN2 ("unaligned_store_w", void, ptr_uint, unsigned, UASTORE_W);
463 ADD_NDS32_BUILTIN2 ("unaligned_store_dw", void, ptr_ulong, long_long_unsigned,
464 UASTORE_DW);