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
27 #include "coretypes.h"
35 #include "optabs.h" /* For GEN_FCN. */
36 #include "diagnostic-core.h"
37 #include "stor-layout.h"
39 #include "langhooks.h" /* For add_builtin_function(). */
43 /* ------------------------------------------------------------------------ */
45 /* Read the requested argument from the EXP given by INDEX.
46 Return the value as an 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
57 nds32_legitimize_target (enum insn_code icode
, rtx target
)
59 enum machine_mode mode
= insn_data
[icode
].operand
[0].mode
;
62 || GET_MODE (target
) != mode
63 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, mode
))
64 return gen_reg_rtx (mode
);
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
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
))
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
);
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;
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
);
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
);
107 return copy_to_mode_reg (mode
, gen_rtx_CONST_VECTOR (mode
, v
));
111 rtx tmp_rtx
= gen_reg_rtx (mode
);
112 convert_move (tmp_rtx
, arg
, false);
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. */
121 nds32_check_constant_argument (enum insn_code icode
, int opnum
, rtx opval
,
124 if (GET_CODE (opval
) != CONST_INT
)
126 error ("invalid argument to built-in function %s", name
);
129 if (! (*insn_data
[icode
].operand
[opnum
].predicate
) (opval
, VOIDmode
))
131 error ("constant argument out of range for %s", name
);
138 /* Expand builtins that take one operand. */
140 nds32_expand_unop_builtin (enum insn_code icode
, tree exp
, rtx target
,
144 rtx op0
= nds32_read_argument (exp
, 0);
145 int op0_num
= return_p
? 1 : 0;
148 target
= nds32_legitimize_target (icode
, target
);
150 op0
= nds32_legitimize_argument (icode
, op0_num
, op0
);
152 /* Emit and return the new instruction. */
154 pat
= GEN_FCN (icode
) (target
, op0
);
156 pat
= GEN_FCN (icode
) (op0
);
165 /* Expand builtins that take one operands and the first is immediate. */
167 nds32_expand_unopimm_builtin (enum insn_code icode
, tree exp
, rtx target
,
168 bool return_p
, const char *name
)
171 rtx op0
= nds32_read_argument (exp
, 0);
172 int op0_num
= return_p
? 1 : 0;
175 target
= nds32_legitimize_target (icode
, target
);
177 if (!nds32_check_constant_argument (icode
, op0_num
, op0
, name
))
180 op0
= nds32_legitimize_argument (icode
, op0_num
, op0
);
182 /* Emit and return the new instruction. */
184 pat
= GEN_FCN (icode
) (target
, op0
);
186 pat
= GEN_FCN (icode
) (op0
);
195 /* Expand builtins that take two operands. */
197 nds32_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
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;
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. */
214 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
216 pat
= GEN_FCN (icode
) (op0
, op1
);
225 struct builtin_description
227 const enum insn_code icode
;
229 enum nds32_builtins code
;
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
,
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
);
293 struct builtin_description
*d
;
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");
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");
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");
338 /* Since there are no result and operands, we can simply emit this rtx. */
341 case NDS32_BUILTIN_ISB
:
342 emit_insn (gen_unspec_volatile_isb ());
344 case NDS32_BUILTIN_SETGIE_EN
:
345 emit_insn (gen_unspec_volatile_setgie_en ());
347 case NDS32_BUILTIN_SETGIE_DIS
:
348 emit_insn (gen_unspec_volatile_setgie_dis ());
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
);
376 static GTY(()) tree nds32_builtin_decls
[NDS32_BUILTIN_COUNT
];
378 /* Return the NDS32 builtin for CODE. */
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
];
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, \
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, \
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,\
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,\
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
);
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
);
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
,
457 ADD_NDS32_BUILTIN1 ("unaligned_load_w", unsigned, ptr_uint
, UALOAD_W
);
458 ADD_NDS32_BUILTIN1 ("unaligned_load_dw", long_long_unsigned
, ptr_ulong
,
460 ADD_NDS32_BUILTIN2 ("unaligned_store_hw", void, ptr_ushort
, short_unsigned
,
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
,