1 /* Builtins' description for AArch64 SIMD architecture. 2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 3 Contributed by ARM Ltd. 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 by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public 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 #define IN_TARGET_CODE 1 22 23 #include "config.h" 24 #include "system.h" 25 #include "coretypes.h" 26 #include "tm.h" 27 #include "function.h" 28 #include "basic-block.h" 29 #include "rtl.h" 30 #include "tree.h" 31 #include "gimple.h" 32 #include "ssa.h" 33 #include "memmodel.h" 34 #include "tm_p.h" 35 #include "expmed.h" 36 #include "optabs.h" 37 #include "recog.h" 38 #include "diagnostic-core.h" 39 #include "fold-const.h" 40 #include "stor-layout.h" 41 #include "explow.h" 42 #include "expr.h" 43 #include "langhooks.h" 44 #include "gimple-iterator.h" 45 #include "case-cfn-macros.h" 46 #include "emit-rtl.h" 47 #include "stringpool.h" 48 #include "attribs.h" 49 #include "gimple-fold.h" 50 #include "builtins.h" 51 #include "aarch64-builtins.h" 52 53 #define v8qi_UP E_V8QImode 54 #define v8di_UP E_V8DImode 55 #define v4hi_UP E_V4HImode 56 #define v4hf_UP E_V4HFmode 57 #define v2si_UP E_V2SImode 58 #define v2sf_UP E_V2SFmode 59 #define v1df_UP E_V1DFmode 60 #define v1di_UP E_V1DImode 61 #define di_UP E_DImode 62 #define df_UP E_DFmode 63 #define v16qi_UP E_V16QImode 64 #define v8hi_UP E_V8HImode 65 #define v8hf_UP E_V8HFmode 66 #define v4si_UP E_V4SImode 67 #define v4sf_UP E_V4SFmode 68 #define v2di_UP E_V2DImode 69 #define v2df_UP E_V2DFmode 70 #define ti_UP E_TImode 71 #define oi_UP E_OImode 72 #define ci_UP E_CImode 73 #define xi_UP E_XImode 74 #define si_UP E_SImode 75 #define sf_UP E_SFmode 76 #define hi_UP E_HImode 77 #define hf_UP E_HFmode 78 #define qi_UP E_QImode 79 #define bf_UP E_BFmode 80 #define v4bf_UP E_V4BFmode 81 #define v8bf_UP E_V8BFmode 82 #define v2x8qi_UP E_V2x8QImode 83 #define v2x4hi_UP E_V2x4HImode 84 #define v2x4hf_UP E_V2x4HFmode 85 #define v2x4bf_UP E_V2x4BFmode 86 #define v2x2si_UP E_V2x2SImode 87 #define v2x2sf_UP E_V2x2SFmode 88 #define v2x1di_UP E_V2x1DImode 89 #define v2x1df_UP E_V2x1DFmode 90 #define v2x16qi_UP E_V2x16QImode 91 #define v2x8hi_UP E_V2x8HImode 92 #define v2x8hf_UP E_V2x8HFmode 93 #define v2x8bf_UP E_V2x8BFmode 94 #define v2x4si_UP E_V2x4SImode 95 #define v2x4sf_UP E_V2x4SFmode 96 #define v2x2di_UP E_V2x2DImode 97 #define v2x2df_UP E_V2x2DFmode 98 #define v3x8qi_UP E_V3x8QImode 99 #define v3x4hi_UP E_V3x4HImode 100 #define v3x4hf_UP E_V3x4HFmode 101 #define v3x4bf_UP E_V3x4BFmode 102 #define v3x2si_UP E_V3x2SImode 103 #define v3x2sf_UP E_V3x2SFmode 104 #define v3x1di_UP E_V3x1DImode 105 #define v3x1df_UP E_V3x1DFmode 106 #define v3x16qi_UP E_V3x16QImode 107 #define v3x8hi_UP E_V3x8HImode 108 #define v3x8hf_UP E_V3x8HFmode 109 #define v3x8bf_UP E_V3x8BFmode 110 #define v3x4si_UP E_V3x4SImode 111 #define v3x4sf_UP E_V3x4SFmode 112 #define v3x2di_UP E_V3x2DImode 113 #define v3x2df_UP E_V3x2DFmode 114 #define v4x8qi_UP E_V4x8QImode 115 #define v4x4hi_UP E_V4x4HImode 116 #define v4x4hf_UP E_V4x4HFmode 117 #define v4x4bf_UP E_V4x4BFmode 118 #define v4x2si_UP E_V4x2SImode 119 #define v4x2sf_UP E_V4x2SFmode 120 #define v4x1di_UP E_V4x1DImode 121 #define v4x1df_UP E_V4x1DFmode 122 #define v4x16qi_UP E_V4x16QImode 123 #define v4x8hi_UP E_V4x8HImode 124 #define v4x8hf_UP E_V4x8HFmode 125 #define v4x8bf_UP E_V4x8BFmode 126 #define v4x4si_UP E_V4x4SImode 127 #define v4x4sf_UP E_V4x4SFmode 128 #define v4x2di_UP E_V4x2DImode 129 #define v4x2df_UP E_V4x2DFmode 130 #define UP(X) X##_UP 131 132 #define MODE_d_bf16 E_V4BFmode 133 #define MODE_d_f16 E_V4HFmode 134 #define MODE_d_f32 E_V2SFmode 135 #define MODE_d_f64 E_V1DFmode 136 #define MODE_d_s8 E_V8QImode 137 #define MODE_d_s16 E_V4HImode 138 #define MODE_d_s32 E_V2SImode 139 #define MODE_d_s64 E_V1DImode 140 #define MODE_d_u8 E_V8QImode 141 #define MODE_d_u16 E_V4HImode 142 #define MODE_d_u32 E_V2SImode 143 #define MODE_d_u64 E_V1DImode 144 #define MODE_d_p8 E_V8QImode 145 #define MODE_d_p16 E_V4HImode 146 #define MODE_d_p64 E_V1DImode 147 #define MODE_q_bf16 E_V8BFmode 148 #define MODE_q_f16 E_V8HFmode 149 #define MODE_q_f32 E_V4SFmode 150 #define MODE_q_f64 E_V2DFmode 151 #define MODE_q_s8 E_V16QImode 152 #define MODE_q_s16 E_V8HImode 153 #define MODE_q_s32 E_V4SImode 154 #define MODE_q_s64 E_V2DImode 155 #define MODE_q_u8 E_V16QImode 156 #define MODE_q_u16 E_V8HImode 157 #define MODE_q_u32 E_V4SImode 158 #define MODE_q_u64 E_V2DImode 159 #define MODE_q_p8 E_V16QImode 160 #define MODE_q_p16 E_V8HImode 161 #define MODE_q_p64 E_V2DImode 162 #define MODE_q_p128 E_TImode 163 164 #define QUAL_bf16 qualifier_none 165 #define QUAL_f16 qualifier_none 166 #define QUAL_f32 qualifier_none 167 #define QUAL_f64 qualifier_none 168 #define QUAL_s8 qualifier_none 169 #define QUAL_s16 qualifier_none 170 #define QUAL_s32 qualifier_none 171 #define QUAL_s64 qualifier_none 172 #define QUAL_u8 qualifier_unsigned 173 #define QUAL_u16 qualifier_unsigned 174 #define QUAL_u32 qualifier_unsigned 175 #define QUAL_u64 qualifier_unsigned 176 #define QUAL_p8 qualifier_poly 177 #define QUAL_p16 qualifier_poly 178 #define QUAL_p64 qualifier_poly 179 #define QUAL_p128 qualifier_poly 180 181 #define LENGTH_d "" 182 #define LENGTH_q "q" 183 184 #define SIMD_INTR_MODE(suffix, length) MODE_##length##_##suffix 185 #define SIMD_INTR_QUAL(suffix) QUAL_##suffix 186 #define SIMD_INTR_LENGTH_CHAR(length) LENGTH_##length 187 188 #define SIMD_MAX_BUILTIN_ARGS 5 189 190 /* Flags that describe what a function might do. */ 191 const unsigned int FLAG_NONE = 0U; 192 const unsigned int FLAG_READ_FPCR = 1U << 0; 193 const unsigned int FLAG_RAISE_FP_EXCEPTIONS = 1U << 1; 194 const unsigned int FLAG_READ_MEMORY = 1U << 2; 195 const unsigned int FLAG_PREFETCH_MEMORY = 1U << 3; 196 const unsigned int FLAG_WRITE_MEMORY = 1U << 4; 197 198 /* Not all FP intrinsics raise FP exceptions or read FPCR register, 199 use this flag to suppress it. */ 200 const unsigned int FLAG_AUTO_FP = 1U << 5; 201 202 const unsigned int FLAG_FP = FLAG_READ_FPCR | FLAG_RAISE_FP_EXCEPTIONS; 203 const unsigned int FLAG_ALL = FLAG_READ_FPCR | FLAG_RAISE_FP_EXCEPTIONS 204 | FLAG_READ_MEMORY | FLAG_PREFETCH_MEMORY | FLAG_WRITE_MEMORY; 205 const unsigned int FLAG_STORE = FLAG_WRITE_MEMORY | FLAG_AUTO_FP; 206 const unsigned int FLAG_LOAD = FLAG_READ_MEMORY | FLAG_AUTO_FP; 207 208 typedef struct 209 { 210 const char *name; 211 machine_mode mode; 212 const enum insn_code code; 213 unsigned int fcode; 214 enum aarch64_type_qualifiers *qualifiers; 215 unsigned int flags; 216 } aarch64_simd_builtin_datum; 217 218 static enum aarch64_type_qualifiers 219 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS] 220 = { qualifier_none, qualifier_none }; 221 #define TYPES_UNOP (aarch64_types_unop_qualifiers) 222 static enum aarch64_type_qualifiers 223 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 224 = { qualifier_unsigned, qualifier_unsigned }; 225 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers) 226 static enum aarch64_type_qualifiers 227 aarch64_types_unopus_qualifiers[SIMD_MAX_BUILTIN_ARGS] 228 = { qualifier_unsigned, qualifier_none }; 229 #define TYPES_UNOPUS (aarch64_types_unopus_qualifiers) 230 static enum aarch64_type_qualifiers 231 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS] 232 = { qualifier_none, qualifier_none, qualifier_maybe_immediate }; 233 #define TYPES_BINOP (aarch64_types_binop_qualifiers) 234 static enum aarch64_type_qualifiers 235 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 236 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned }; 237 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers) 238 static enum aarch64_type_qualifiers 239 aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS] 240 = { qualifier_unsigned, qualifier_unsigned, qualifier_none }; 241 #define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers) 242 static enum aarch64_type_qualifiers 243 aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 244 = { qualifier_none, qualifier_none, qualifier_unsigned }; 245 #define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers) 246 static enum aarch64_type_qualifiers 247 aarch64_types_binop_uss_qualifiers[SIMD_MAX_BUILTIN_ARGS] 248 = { qualifier_unsigned, qualifier_none, qualifier_none }; 249 #define TYPES_BINOP_USS (aarch64_types_binop_uss_qualifiers) 250 static enum aarch64_type_qualifiers 251 aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS] 252 = { qualifier_poly, qualifier_poly, qualifier_poly }; 253 #define TYPES_BINOPP (aarch64_types_binopp_qualifiers) 254 static enum aarch64_type_qualifiers 255 aarch64_types_binop_ppu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 256 = { qualifier_poly, qualifier_poly, qualifier_unsigned }; 257 #define TYPES_BINOP_PPU (aarch64_types_binop_ppu_qualifiers) 258 259 static enum aarch64_type_qualifiers 260 aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS] 261 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none }; 262 #define TYPES_TERNOP (aarch64_types_ternop_qualifiers) 263 static enum aarch64_type_qualifiers 264 aarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 265 = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index }; 266 #define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers) 267 static enum aarch64_type_qualifiers 268 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 269 = { qualifier_unsigned, qualifier_unsigned, 270 qualifier_unsigned, qualifier_unsigned }; 271 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers) 272 static enum aarch64_type_qualifiers 273 aarch64_types_ternopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 274 = { qualifier_unsigned, qualifier_unsigned, 275 qualifier_unsigned, qualifier_lane_index }; 276 #define TYPES_TERNOPU_LANE (aarch64_types_ternopu_lane_qualifiers) 277 static enum aarch64_type_qualifiers 278 aarch64_types_ternopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 279 = { qualifier_unsigned, qualifier_unsigned, 280 qualifier_unsigned, qualifier_immediate }; 281 #define TYPES_TERNOPUI (aarch64_types_ternopu_imm_qualifiers) 282 static enum aarch64_type_qualifiers 283 aarch64_types_ternop_sssu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 284 = { qualifier_none, qualifier_none, qualifier_none, qualifier_unsigned }; 285 #define TYPES_TERNOP_SSSU (aarch64_types_ternop_sssu_qualifiers) 286 static enum aarch64_type_qualifiers 287 aarch64_types_ternop_ssus_qualifiers[SIMD_MAX_BUILTIN_ARGS] 288 = { qualifier_none, qualifier_none, qualifier_unsigned, qualifier_none }; 289 #define TYPES_TERNOP_SSUS (aarch64_types_ternop_ssus_qualifiers) 290 static enum aarch64_type_qualifiers 291 aarch64_types_ternop_suss_qualifiers[SIMD_MAX_BUILTIN_ARGS] 292 = { qualifier_none, qualifier_unsigned, qualifier_none, qualifier_none }; 293 #define TYPES_TERNOP_SUSS (aarch64_types_ternop_suss_qualifiers) 294 static enum aarch64_type_qualifiers 295 aarch64_types_binop_pppu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 296 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_unsigned }; 297 #define TYPES_TERNOP_PPPU (aarch64_types_binop_pppu_qualifiers) 298 299 static enum aarch64_type_qualifiers 300 aarch64_types_quadop_lane_pair_qualifiers[SIMD_MAX_BUILTIN_ARGS] 301 = { qualifier_none, qualifier_none, qualifier_none, 302 qualifier_none, qualifier_lane_pair_index }; 303 #define TYPES_QUADOP_LANE_PAIR (aarch64_types_quadop_lane_pair_qualifiers) 304 static enum aarch64_type_qualifiers 305 aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 306 = { qualifier_none, qualifier_none, qualifier_none, 307 qualifier_none, qualifier_lane_index }; 308 #define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers) 309 static enum aarch64_type_qualifiers 310 aarch64_types_quadopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 311 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned, 312 qualifier_unsigned, qualifier_lane_index }; 313 #define TYPES_QUADOPU_LANE (aarch64_types_quadopu_lane_qualifiers) 314 315 static enum aarch64_type_qualifiers 316 aarch64_types_quadopssus_lane_quadtup_qualifiers[SIMD_MAX_BUILTIN_ARGS] 317 = { qualifier_none, qualifier_none, qualifier_unsigned, 318 qualifier_none, qualifier_lane_quadtup_index }; 319 #define TYPES_QUADOPSSUS_LANE_QUADTUP \ 320 (aarch64_types_quadopssus_lane_quadtup_qualifiers) 321 static enum aarch64_type_qualifiers 322 aarch64_types_quadopsssu_lane_quadtup_qualifiers[SIMD_MAX_BUILTIN_ARGS] 323 = { qualifier_none, qualifier_none, qualifier_none, 324 qualifier_unsigned, qualifier_lane_quadtup_index }; 325 #define TYPES_QUADOPSSSU_LANE_QUADTUP \ 326 (aarch64_types_quadopsssu_lane_quadtup_qualifiers) 327 328 static enum aarch64_type_qualifiers 329 aarch64_types_quadopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 330 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned, 331 qualifier_unsigned, qualifier_immediate }; 332 #define TYPES_QUADOPUI (aarch64_types_quadopu_imm_qualifiers) 333 334 static enum aarch64_type_qualifiers 335 aarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 336 = { qualifier_none, qualifier_none, qualifier_immediate }; 337 #define TYPES_GETREG (aarch64_types_binop_imm_qualifiers) 338 #define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers) 339 static enum aarch64_type_qualifiers 340 aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS] 341 = { qualifier_unsigned, qualifier_none, qualifier_immediate }; 342 #define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers) 343 static enum aarch64_type_qualifiers 344 aarch64_types_fcvt_from_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS] 345 = { qualifier_none, qualifier_unsigned, qualifier_immediate }; 346 #define TYPES_FCVTIMM_SUS (aarch64_types_fcvt_from_unsigned_qualifiers) 347 static enum aarch64_type_qualifiers 348 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS] 349 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate }; 350 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers) 351 #define TYPES_USHIFT2IMM (aarch64_types_ternopu_imm_qualifiers) 352 static enum aarch64_type_qualifiers 353 aarch64_types_shift2_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS] 354 = { qualifier_unsigned, qualifier_unsigned, qualifier_none, qualifier_immediate }; 355 #define TYPES_SHIFT2IMM_UUSS (aarch64_types_shift2_to_unsigned_qualifiers) 356 357 static enum aarch64_type_qualifiers 358 aarch64_types_ternop_s_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 359 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate}; 360 #define TYPES_SETREG (aarch64_types_ternop_s_imm_qualifiers) 361 #define TYPES_SHIFTINSERT (aarch64_types_ternop_s_imm_qualifiers) 362 #define TYPES_SHIFTACC (aarch64_types_ternop_s_imm_qualifiers) 363 #define TYPES_SHIFT2IMM (aarch64_types_ternop_s_imm_qualifiers) 364 365 static enum aarch64_type_qualifiers 366 aarch64_types_ternop_p_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 367 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_immediate}; 368 #define TYPES_SHIFTINSERTP (aarch64_types_ternop_p_imm_qualifiers) 369 370 static enum aarch64_type_qualifiers 371 aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS] 372 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned, 373 qualifier_immediate }; 374 #define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers) 375 376 static enum aarch64_type_qualifiers 377 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS] 378 = { qualifier_none, qualifier_const_pointer_map_mode }; 379 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers) 380 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers) 381 static enum aarch64_type_qualifiers 382 aarch64_types_load1_u_qualifiers[SIMD_MAX_BUILTIN_ARGS] 383 = { qualifier_unsigned, qualifier_const_pointer_map_mode }; 384 #define TYPES_LOAD1_U (aarch64_types_load1_u_qualifiers) 385 #define TYPES_LOADSTRUCT_U (aarch64_types_load1_u_qualifiers) 386 static enum aarch64_type_qualifiers 387 aarch64_types_load1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS] 388 = { qualifier_poly, qualifier_const_pointer_map_mode }; 389 #define TYPES_LOAD1_P (aarch64_types_load1_p_qualifiers) 390 #define TYPES_LOADSTRUCT_P (aarch64_types_load1_p_qualifiers) 391 392 static enum aarch64_type_qualifiers 393 aarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 394 = { qualifier_none, qualifier_const_pointer_map_mode, 395 qualifier_none, qualifier_struct_load_store_lane_index }; 396 #define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers) 397 static enum aarch64_type_qualifiers 398 aarch64_types_loadstruct_lane_u_qualifiers[SIMD_MAX_BUILTIN_ARGS] 399 = { qualifier_unsigned, qualifier_const_pointer_map_mode, 400 qualifier_unsigned, qualifier_struct_load_store_lane_index }; 401 #define TYPES_LOADSTRUCT_LANE_U (aarch64_types_loadstruct_lane_u_qualifiers) 402 static enum aarch64_type_qualifiers 403 aarch64_types_loadstruct_lane_p_qualifiers[SIMD_MAX_BUILTIN_ARGS] 404 = { qualifier_poly, qualifier_const_pointer_map_mode, 405 qualifier_poly, qualifier_struct_load_store_lane_index }; 406 #define TYPES_LOADSTRUCT_LANE_P (aarch64_types_loadstruct_lane_p_qualifiers) 407 408 static enum aarch64_type_qualifiers 409 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS] 410 = { qualifier_poly, qualifier_unsigned, 411 qualifier_poly, qualifier_poly }; 412 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers) 413 static enum aarch64_type_qualifiers 414 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS] 415 = { qualifier_none, qualifier_unsigned, 416 qualifier_none, qualifier_none }; 417 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers) 418 static enum aarch64_type_qualifiers 419 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS] 420 = { qualifier_unsigned, qualifier_unsigned, 421 qualifier_unsigned, qualifier_unsigned }; 422 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers) 423 424 /* The first argument (return type) of a store should be void type, 425 which we represent with qualifier_void. Their first operand will be 426 a DImode pointer to the location to store to, so we must use 427 qualifier_map_mode | qualifier_pointer to build a pointer to the 428 element type of the vector. */ 429 static enum aarch64_type_qualifiers 430 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS] 431 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none }; 432 #define TYPES_STORE1 (aarch64_types_store1_qualifiers) 433 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers) 434 static enum aarch64_type_qualifiers 435 aarch64_types_store1_u_qualifiers[SIMD_MAX_BUILTIN_ARGS] 436 = { qualifier_void, qualifier_pointer_map_mode, qualifier_unsigned }; 437 #define TYPES_STORE1_U (aarch64_types_store1_u_qualifiers) 438 #define TYPES_STORESTRUCT_U (aarch64_types_store1_u_qualifiers) 439 static enum aarch64_type_qualifiers 440 aarch64_types_store1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS] 441 = { qualifier_void, qualifier_pointer_map_mode, qualifier_poly }; 442 #define TYPES_STORE1_P (aarch64_types_store1_p_qualifiers) 443 #define TYPES_STORESTRUCT_P (aarch64_types_store1_p_qualifiers) 444 445 static enum aarch64_type_qualifiers 446 aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 447 = { qualifier_void, qualifier_pointer_map_mode, 448 qualifier_none, qualifier_struct_load_store_lane_index }; 449 #define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers) 450 static enum aarch64_type_qualifiers 451 aarch64_types_storestruct_lane_u_qualifiers[SIMD_MAX_BUILTIN_ARGS] 452 = { qualifier_void, qualifier_pointer_map_mode, 453 qualifier_unsigned, qualifier_struct_load_store_lane_index }; 454 #define TYPES_STORESTRUCT_LANE_U (aarch64_types_storestruct_lane_u_qualifiers) 455 static enum aarch64_type_qualifiers 456 aarch64_types_storestruct_lane_p_qualifiers[SIMD_MAX_BUILTIN_ARGS] 457 = { qualifier_void, qualifier_pointer_map_mode, 458 qualifier_poly, qualifier_struct_load_store_lane_index }; 459 #define TYPES_STORESTRUCT_LANE_P (aarch64_types_storestruct_lane_p_qualifiers) 460 461 #define CF0(N, X) CODE_FOR_aarch64_##N##X 462 #define CF1(N, X) CODE_FOR_##N##X##1 463 #define CF2(N, X) CODE_FOR_##N##X##2 464 #define CF3(N, X) CODE_FOR_##N##X##3 465 #define CF4(N, X) CODE_FOR_##N##X##4 466 #define CF10(N, X) CODE_FOR_##N##X 467 468 /* Define cascading VAR<N> macros that are used from 469 aarch64-builtin-iterators.h to iterate over modes. These definitions 470 will end up generating a number of VAR1 expansions and code later on in the 471 file should redefine VAR1 to whatever it needs to process on a per-mode 472 basis. */ 473 #define VAR2(T, N, MAP, FLAG, A, B) \ 474 VAR1 (T, N, MAP, FLAG, A) \ 475 VAR1 (T, N, MAP, FLAG, B) 476 #define VAR3(T, N, MAP, FLAG, A, B, C) \ 477 VAR2 (T, N, MAP, FLAG, A, B) \ 478 VAR1 (T, N, MAP, FLAG, C) 479 #define VAR4(T, N, MAP, FLAG, A, B, C, D) \ 480 VAR3 (T, N, MAP, FLAG, A, B, C) \ 481 VAR1 (T, N, MAP, FLAG, D) 482 #define VAR5(T, N, MAP, FLAG, A, B, C, D, E) \ 483 VAR4 (T, N, MAP, FLAG, A, B, C, D) \ 484 VAR1 (T, N, MAP, FLAG, E) 485 #define VAR6(T, N, MAP, FLAG, A, B, C, D, E, F) \ 486 VAR5 (T, N, MAP, FLAG, A, B, C, D, E) \ 487 VAR1 (T, N, MAP, FLAG, F) 488 #define VAR7(T, N, MAP, FLAG, A, B, C, D, E, F, G) \ 489 VAR6 (T, N, MAP, FLAG, A, B, C, D, E, F) \ 490 VAR1 (T, N, MAP, FLAG, G) 491 #define VAR8(T, N, MAP, FLAG, A, B, C, D, E, F, G, H) \ 492 VAR7 (T, N, MAP, FLAG, A, B, C, D, E, F, G) \ 493 VAR1 (T, N, MAP, FLAG, H) 494 #define VAR9(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I) \ 495 VAR8 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H) \ 496 VAR1 (T, N, MAP, FLAG, I) 497 #define VAR10(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J) \ 498 VAR9 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I) \ 499 VAR1 (T, N, MAP, FLAG, J) 500 #define VAR11(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K) \ 501 VAR10 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J) \ 502 VAR1 (T, N, MAP, FLAG, K) 503 #define VAR12(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L) \ 504 VAR11 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K) \ 505 VAR1 (T, N, MAP, FLAG, L) 506 #define VAR13(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M) \ 507 VAR12 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L) \ 508 VAR1 (T, N, MAP, FLAG, M) 509 #define VAR14(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \ 510 VAR13 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M) \ 511 VAR1 (T, X, MAP, FLAG, N) 512 #define VAR15(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \ 513 VAR14 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \ 514 VAR1 (T, X, MAP, FLAG, O) 515 #define VAR16(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) \ 516 VAR15 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \ 517 VAR1 (T, X, MAP, FLAG, P) 518 519 #include "aarch64-builtin-iterators.h" 520 521 /* The builtins below should be expanded through the standard optabs 522 CODE_FOR_[u]avg<mode>3_[floor,ceil]. However the mapping scheme in 523 aarch64-simd-builtins.def does not easily allow us to have a pre-mode 524 ("uavg") and post-mode string ("_ceil") in the CODE_FOR_* construction. 525 So the builtins use a name that is natural for AArch64 instructions 526 e.g. "aarch64_srhadd<mode>" and we re-map these to the optab-related 527 CODE_FOR_ here. */ 528 #undef VAR1 529 #define VAR1(F,T1,T2,I,M) \ 530 constexpr insn_code CODE_FOR_aarch64_##F##M = CODE_FOR_##T1##M##3##T2; 531 532 BUILTIN_VDQ_BHSI (srhadd, avg, _ceil, 0) 533 BUILTIN_VDQ_BHSI (urhadd, uavg, _ceil, 0) 534 BUILTIN_VDQ_BHSI (shadd, avg, _floor, 0) 535 BUILTIN_VDQ_BHSI (uhadd, uavg, _floor, 0) 536 537 #undef VAR1 538 #define VAR1(T, N, MAP, FLAG, A) \ 539 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T, FLAG_##FLAG}, 540 541 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = { 542 #include "aarch64-simd-builtins.def" 543 }; 544 545 /* There's only 8 CRC32 builtins. Probably not worth their own .def file. */ 546 #define AARCH64_CRC32_BUILTINS \ 547 CRC32_BUILTIN (crc32b, QI) \ 548 CRC32_BUILTIN (crc32h, HI) \ 549 CRC32_BUILTIN (crc32w, SI) \ 550 CRC32_BUILTIN (crc32x, DI) \ 551 CRC32_BUILTIN (crc32cb, QI) \ 552 CRC32_BUILTIN (crc32ch, HI) \ 553 CRC32_BUILTIN (crc32cw, SI) \ 554 CRC32_BUILTIN (crc32cx, DI) 555 556 /* The next 8 FCMLA instrinsics require some special handling compared the 557 normal simd intrinsics. */ 558 #define AARCH64_SIMD_FCMLA_LANEQ_BUILTINS \ 559 FCMLA_LANEQ_BUILTIN (0, v2sf, fcmla, V2SF, false) \ 560 FCMLA_LANEQ_BUILTIN (90, v2sf, fcmla, V2SF, false) \ 561 FCMLA_LANEQ_BUILTIN (180, v2sf, fcmla, V2SF, false) \ 562 FCMLA_LANEQ_BUILTIN (270, v2sf, fcmla, V2SF, false) \ 563 FCMLA_LANEQ_BUILTIN (0, v4hf, fcmla_laneq, V4HF, true) \ 564 FCMLA_LANEQ_BUILTIN (90, v4hf, fcmla_laneq, V4HF, true) \ 565 FCMLA_LANEQ_BUILTIN (180, v4hf, fcmla_laneq, V4HF, true) \ 566 FCMLA_LANEQ_BUILTIN (270, v4hf, fcmla_laneq, V4HF, true) \ 567 568 569 /* vreinterpret intrinsics are defined for any pair of element types. 570 { _bf16 } { _bf16 } 571 { _f16 _f32 _f64 } { _f16 _f32 _f64 } 572 { _s8 _s16 _s32 _s64 } x { _s8 _s16 _s32 _s64 } 573 { _u8 _u16 _u32 _u64 } { _u8 _u16 _u32 _u64 } 574 { _p8 _p16 _p64 } { _p8 _p16 _p64 }. */ 575 #define VREINTERPRET_BUILTIN2(A, B) \ 576 VREINTERPRET_BUILTIN (A, B, d) 577 578 #define VREINTERPRET_BUILTINS1(A) \ 579 VREINTERPRET_BUILTIN2 (A, bf16) \ 580 VREINTERPRET_BUILTIN2 (A, f16) \ 581 VREINTERPRET_BUILTIN2 (A, f32) \ 582 VREINTERPRET_BUILTIN2 (A, f64) \ 583 VREINTERPRET_BUILTIN2 (A, s8) \ 584 VREINTERPRET_BUILTIN2 (A, s16) \ 585 VREINTERPRET_BUILTIN2 (A, s32) \ 586 VREINTERPRET_BUILTIN2 (A, s64) \ 587 VREINTERPRET_BUILTIN2 (A, u8) \ 588 VREINTERPRET_BUILTIN2 (A, u16) \ 589 VREINTERPRET_BUILTIN2 (A, u32) \ 590 VREINTERPRET_BUILTIN2 (A, u64) \ 591 VREINTERPRET_BUILTIN2 (A, p8) \ 592 VREINTERPRET_BUILTIN2 (A, p16) \ 593 VREINTERPRET_BUILTIN2 (A, p64) 594 595 #define VREINTERPRET_BUILTINS \ 596 VREINTERPRET_BUILTINS1 (bf16) \ 597 VREINTERPRET_BUILTINS1 (f16) \ 598 VREINTERPRET_BUILTINS1 (f32) \ 599 VREINTERPRET_BUILTINS1 (f64) \ 600 VREINTERPRET_BUILTINS1 (s8) \ 601 VREINTERPRET_BUILTINS1 (s16) \ 602 VREINTERPRET_BUILTINS1 (s32) \ 603 VREINTERPRET_BUILTINS1 (s64) \ 604 VREINTERPRET_BUILTINS1 (u8) \ 605 VREINTERPRET_BUILTINS1 (u16) \ 606 VREINTERPRET_BUILTINS1 (u32) \ 607 VREINTERPRET_BUILTINS1 (u64) \ 608 VREINTERPRET_BUILTINS1 (p8) \ 609 VREINTERPRET_BUILTINS1 (p16) \ 610 VREINTERPRET_BUILTINS1 (p64) 611 612 /* vreinterpretq intrinsics are additionally defined for p128. 613 { _bf16 } { _bf16 } 614 { _f16 _f32 _f64 } { _f16 _f32 _f64 } 615 { _s8 _s16 _s32 _s64 } x { _s8 _s16 _s32 _s64 } 616 { _u8 _u16 _u32 _u64 } { _u8 _u16 _u32 _u64 } 617 { _p8 _p16 _p64 _p128 } { _p8 _p16 _p64 _p128 }. */ 618 #define VREINTERPRETQ_BUILTIN2(A, B) \ 619 VREINTERPRET_BUILTIN (A, B, q) 620 621 #define VREINTERPRETQ_BUILTINS1(A) \ 622 VREINTERPRETQ_BUILTIN2 (A, bf16) \ 623 VREINTERPRETQ_BUILTIN2 (A, f16) \ 624 VREINTERPRETQ_BUILTIN2 (A, f32) \ 625 VREINTERPRETQ_BUILTIN2 (A, f64) \ 626 VREINTERPRETQ_BUILTIN2 (A, s8) \ 627 VREINTERPRETQ_BUILTIN2 (A, s16) \ 628 VREINTERPRETQ_BUILTIN2 (A, s32) \ 629 VREINTERPRETQ_BUILTIN2 (A, s64) \ 630 VREINTERPRETQ_BUILTIN2 (A, u8) \ 631 VREINTERPRETQ_BUILTIN2 (A, u16) \ 632 VREINTERPRETQ_BUILTIN2 (A, u32) \ 633 VREINTERPRETQ_BUILTIN2 (A, u64) \ 634 VREINTERPRETQ_BUILTIN2 (A, p8) \ 635 VREINTERPRETQ_BUILTIN2 (A, p16) \ 636 VREINTERPRETQ_BUILTIN2 (A, p64) \ 637 VREINTERPRETQ_BUILTIN2 (A, p128) 638 639 #define VREINTERPRETQ_BUILTINS \ 640 VREINTERPRETQ_BUILTINS1 (bf16) \ 641 VREINTERPRETQ_BUILTINS1 (f16) \ 642 VREINTERPRETQ_BUILTINS1 (f32) \ 643 VREINTERPRETQ_BUILTINS1 (f64) \ 644 VREINTERPRETQ_BUILTINS1 (s8) \ 645 VREINTERPRETQ_BUILTINS1 (s16) \ 646 VREINTERPRETQ_BUILTINS1 (s32) \ 647 VREINTERPRETQ_BUILTINS1 (s64) \ 648 VREINTERPRETQ_BUILTINS1 (u8) \ 649 VREINTERPRETQ_BUILTINS1 (u16) \ 650 VREINTERPRETQ_BUILTINS1 (u32) \ 651 VREINTERPRETQ_BUILTINS1 (u64) \ 652 VREINTERPRETQ_BUILTINS1 (p8) \ 653 VREINTERPRETQ_BUILTINS1 (p16) \ 654 VREINTERPRETQ_BUILTINS1 (p64) \ 655 VREINTERPRETQ_BUILTINS1 (p128) 656 657 #define AARCH64_SIMD_VREINTERPRET_BUILTINS \ 658 VREINTERPRET_BUILTINS \ 659 VREINTERPRETQ_BUILTINS 660 661 typedef struct 662 { 663 const char *name; 664 machine_mode mode; 665 const enum insn_code icode; 666 unsigned int fcode; 667 } aarch64_crc_builtin_datum; 668 669 /* Hold information about how to expand the FCMLA_LANEQ builtins. */ 670 typedef struct 671 { 672 const char *name; 673 machine_mode mode; 674 const enum insn_code icode; 675 unsigned int fcode; 676 bool lane; 677 } aarch64_fcmla_laneq_builtin_datum; 678 679 /* Hold information about how to declare SIMD intrinsics. */ 680 typedef struct 681 { 682 const char *name; 683 unsigned int fcode; 684 unsigned int op_count; 685 machine_mode op_modes[SIMD_MAX_BUILTIN_ARGS]; 686 enum aarch64_type_qualifiers qualifiers[SIMD_MAX_BUILTIN_ARGS]; 687 unsigned int flags; 688 bool skip; 689 } aarch64_simd_intrinsic_datum; 690 691 #define CRC32_BUILTIN(N, M) \ 692 AARCH64_BUILTIN_##N, 693 694 #define FCMLA_LANEQ_BUILTIN(I, N, X, M, T) \ 695 AARCH64_SIMD_BUILTIN_FCMLA_LANEQ##I##_##M, 696 697 #define VREINTERPRET_BUILTIN(A, B, L) \ 698 AARCH64_SIMD_BUILTIN_VREINTERPRET##L##_##A##_##B, 699 700 #undef VAR1 701 #define VAR1(T, N, MAP, FLAG, A) \ 702 AARCH64_SIMD_BUILTIN_##T##_##N##A, 703 704 enum aarch64_builtins 705 { 706 AARCH64_BUILTIN_MIN, 707 708 AARCH64_BUILTIN_GET_FPCR, 709 AARCH64_BUILTIN_SET_FPCR, 710 AARCH64_BUILTIN_GET_FPSR, 711 AARCH64_BUILTIN_SET_FPSR, 712 713 AARCH64_BUILTIN_GET_FPCR64, 714 AARCH64_BUILTIN_SET_FPCR64, 715 AARCH64_BUILTIN_GET_FPSR64, 716 AARCH64_BUILTIN_SET_FPSR64, 717 718 AARCH64_BUILTIN_RSQRT_DF, 719 AARCH64_BUILTIN_RSQRT_SF, 720 AARCH64_BUILTIN_RSQRT_V2DF, 721 AARCH64_BUILTIN_RSQRT_V2SF, 722 AARCH64_BUILTIN_RSQRT_V4SF, 723 AARCH64_SIMD_BUILTIN_BASE, 724 AARCH64_SIMD_BUILTIN_LANE_CHECK, 725 #include "aarch64-simd-builtins.def" 726 /* The first enum element which is based on an insn_data pattern. */ 727 AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1, 728 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START 729 + ARRAY_SIZE (aarch64_simd_builtin_data) - 1, 730 AARCH64_CRC32_BUILTIN_BASE, 731 AARCH64_CRC32_BUILTINS 732 AARCH64_CRC32_BUILTIN_MAX, 733 /* SIMD intrinsic builtins. */ 734 AARCH64_SIMD_VREINTERPRET_BUILTINS 735 /* ARMv8.3-A Pointer Authentication Builtins. */ 736 AARCH64_PAUTH_BUILTIN_AUTIA1716, 737 AARCH64_PAUTH_BUILTIN_PACIA1716, 738 AARCH64_PAUTH_BUILTIN_AUTIB1716, 739 AARCH64_PAUTH_BUILTIN_PACIB1716, 740 AARCH64_PAUTH_BUILTIN_XPACLRI, 741 /* Special cased Armv8.3-A Complex FMA by Lane quad Builtins. */ 742 AARCH64_SIMD_FCMLA_LANEQ_BUILTIN_BASE, 743 AARCH64_SIMD_FCMLA_LANEQ_BUILTINS 744 /* Builtin for Arm8.3-a Javascript conversion instruction. */ 745 AARCH64_JSCVT, 746 /* TME builtins. */ 747 AARCH64_TME_BUILTIN_TSTART, 748 AARCH64_TME_BUILTIN_TCOMMIT, 749 AARCH64_TME_BUILTIN_TTEST, 750 AARCH64_TME_BUILTIN_TCANCEL, 751 /* Armv8.5-a RNG instruction builtins. */ 752 AARCH64_BUILTIN_RNG_RNDR, 753 AARCH64_BUILTIN_RNG_RNDRRS, 754 /* MEMTAG builtins. */ 755 AARCH64_MEMTAG_BUILTIN_START, 756 AARCH64_MEMTAG_BUILTIN_IRG, 757 AARCH64_MEMTAG_BUILTIN_GMI, 758 AARCH64_MEMTAG_BUILTIN_SUBP, 759 AARCH64_MEMTAG_BUILTIN_INC_TAG, 760 AARCH64_MEMTAG_BUILTIN_SET_TAG, 761 AARCH64_MEMTAG_BUILTIN_GET_TAG, 762 AARCH64_MEMTAG_BUILTIN_END, 763 /* LS64 builtins. */ 764 AARCH64_LS64_BUILTIN_LD64B, 765 AARCH64_LS64_BUILTIN_ST64B, 766 AARCH64_LS64_BUILTIN_ST64BV, 767 AARCH64_LS64_BUILTIN_ST64BV0, 768 AARCH64_REV16, 769 AARCH64_REV16L, 770 AARCH64_REV16LL, 771 AARCH64_RBIT, 772 AARCH64_RBITL, 773 AARCH64_RBITLL, 774 /* System register builtins. */ 775 AARCH64_RSR, 776 AARCH64_RSRP, 777 AARCH64_RSR64, 778 AARCH64_RSRF, 779 AARCH64_RSRF64, 780 AARCH64_RSR128, 781 AARCH64_WSR, 782 AARCH64_WSRP, 783 AARCH64_WSR64, 784 AARCH64_WSRF, 785 AARCH64_WSRF64, 786 AARCH64_WSR128, 787 AARCH64_PLD, 788 AARCH64_PLDX, 789 AARCH64_PLI, 790 AARCH64_PLIX, 791 AARCH64_BUILTIN_MAX 792 }; 793 794 #undef CRC32_BUILTIN 795 #define CRC32_BUILTIN(N, M) \ 796 {"__builtin_aarch64_"#N, E_##M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N}, 797 798 static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = { 799 AARCH64_CRC32_BUILTINS 800 }; 801 802 803 #undef FCMLA_LANEQ_BUILTIN 804 #define FCMLA_LANEQ_BUILTIN(I, N, X, M, T) \ 805 {"__builtin_aarch64_fcmla_laneq"#I#N, E_##M##mode, CODE_FOR_aarch64_##X##I##N, \ 806 AARCH64_SIMD_BUILTIN_FCMLA_LANEQ##I##_##M, T}, 807 808 /* This structure contains how to manage the mapping form the builtin to the 809 instruction to generate in the backend and how to invoke the instruction. */ 810 static aarch64_fcmla_laneq_builtin_datum aarch64_fcmla_lane_builtin_data[] = { 811 AARCH64_SIMD_FCMLA_LANEQ_BUILTINS 812 }; 813 814 #undef VREINTERPRET_BUILTIN 815 #define VREINTERPRET_BUILTIN(A, B, L) \ 816 {"vreinterpret" SIMD_INTR_LENGTH_CHAR(L) "_" #A "_" #B, \ 817 AARCH64_SIMD_BUILTIN_VREINTERPRET##L##_##A##_##B, \ 818 2, \ 819 { SIMD_INTR_MODE(A, L), SIMD_INTR_MODE(B, L) }, \ 820 { SIMD_INTR_QUAL(A), SIMD_INTR_QUAL(B) }, \ 821 FLAG_AUTO_FP, \ 822 SIMD_INTR_MODE(A, L) == SIMD_INTR_MODE(B, L) \ 823 && SIMD_INTR_QUAL(A) == SIMD_INTR_QUAL(B) \ 824 }, 825 826 static const aarch64_simd_intrinsic_datum aarch64_simd_intrinsic_data[] = { 827 AARCH64_SIMD_VREINTERPRET_BUILTINS 828 }; 829 830 831 #undef CRC32_BUILTIN 832 833 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX]; 834 835 #define NUM_DREG_TYPES 6 836 #define NUM_QREG_TYPES 6 837 838 /* Internal scalar builtin types. These types are used to support 839 neon intrinsic builtins. They are _not_ user-visible types. Therefore 840 the mangling for these types are implementation defined. */ 841 const char *aarch64_scalar_builtin_types[] = { 842 "__builtin_aarch64_simd_qi", 843 "__builtin_aarch64_simd_hi", 844 "__builtin_aarch64_simd_si", 845 "__builtin_aarch64_simd_hf", 846 "__builtin_aarch64_simd_sf", 847 "__builtin_aarch64_simd_di", 848 "__builtin_aarch64_simd_df", 849 "__builtin_aarch64_simd_poly8", 850 "__builtin_aarch64_simd_poly16", 851 "__builtin_aarch64_simd_poly64", 852 "__builtin_aarch64_simd_poly128", 853 "__builtin_aarch64_simd_ti", 854 "__builtin_aarch64_simd_uqi", 855 "__builtin_aarch64_simd_uhi", 856 "__builtin_aarch64_simd_usi", 857 "__builtin_aarch64_simd_udi", 858 "__builtin_aarch64_simd_ei", 859 "__builtin_aarch64_simd_oi", 860 "__builtin_aarch64_simd_ci", 861 "__builtin_aarch64_simd_xi", 862 "__builtin_aarch64_simd_bf", 863 NULL 864 }; 865 866 extern GTY(()) aarch64_simd_type_info aarch64_simd_types[]; 867 868 #define ENTRY(E, M, Q, G) \ 869 {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, E_##M##mode, qualifier_##Q}, 870 struct aarch64_simd_type_info aarch64_simd_types [] = { 871 #include "aarch64-simd-builtin-types.def" 872 }; 873 #undef ENTRY 874 875 static machine_mode aarch64_simd_tuple_modes[ARM_NEON_H_TYPES_LAST][3]; 876 static GTY(()) tree aarch64_simd_tuple_types[ARM_NEON_H_TYPES_LAST][3]; 877 878 static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE; 879 static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE; 880 static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE; 881 882 /* The user-visible __fp16 type, and a pointer to that type. Used 883 across the back-end. */ 884 tree aarch64_fp16_type_node = NULL_TREE; 885 tree aarch64_fp16_ptr_type_node = NULL_TREE; 886 887 /* Back-end node type for brain float (bfloat) types. */ 888 tree aarch64_bf16_ptr_type_node = NULL_TREE; 889 890 /* Wrapper around add_builtin_function. NAME is the name of the built-in 891 function, TYPE is the function type, CODE is the function subcode 892 (relative to AARCH64_BUILTIN_GENERAL), and ATTRS is the function 893 attributes. */ 894 static tree 895 aarch64_general_add_builtin (const char *name, tree type, unsigned int code, 896 tree attrs = NULL_TREE) 897 { 898 code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL; 899 return add_builtin_function (name, type, code, BUILT_IN_MD, 900 NULL, attrs); 901 } 902 903 static tree 904 aarch64_general_simulate_builtin (const char *name, tree fntype, 905 unsigned int code, 906 tree attrs = NULL_TREE) 907 { 908 code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL; 909 return simulate_builtin_function_decl (input_location, name, fntype, 910 code, NULL, attrs); 911 } 912 913 static const char * 914 aarch64_mangle_builtin_scalar_type (const_tree type) 915 { 916 int i = 0; 917 918 while (aarch64_scalar_builtin_types[i] != NULL) 919 { 920 const char *name = aarch64_scalar_builtin_types[i]; 921 922 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL 923 && DECL_NAME (TYPE_NAME (type)) 924 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name)) 925 return aarch64_scalar_builtin_types[i]; 926 i++; 927 } 928 return NULL; 929 } 930 931 static const char * 932 aarch64_mangle_builtin_vector_type (const_tree type) 933 { 934 tree attrs = TYPE_ATTRIBUTES (type); 935 if (tree attr = lookup_attribute ("Advanced SIMD type", attrs)) 936 { 937 tree mangled_name = TREE_VALUE (TREE_VALUE (attr)); 938 return IDENTIFIER_POINTER (mangled_name); 939 } 940 941 return NULL; 942 } 943 944 const char * 945 aarch64_general_mangle_builtin_type (const_tree type) 946 { 947 const char *mangle; 948 /* Walk through all the AArch64 builtins types tables to filter out the 949 incoming type. */ 950 if ((mangle = aarch64_mangle_builtin_vector_type (type)) 951 || (mangle = aarch64_mangle_builtin_scalar_type (type))) 952 return mangle; 953 954 return NULL; 955 } 956 957 /* Helper function for aarch64_simd_builtin_type. */ 958 static tree 959 aarch64_int_or_fp_type (machine_mode mode, 960 enum aarch64_type_qualifiers qualifiers) 961 { 962 #define QUAL_TYPE(M) ((qualifiers & qualifier_unsigned) \ 963 ? unsigned_int##M##_type_node : int##M##_type_node); 964 switch (mode) 965 { 966 case E_QImode: 967 return QUAL_TYPE (QI); 968 case E_HImode: 969 return QUAL_TYPE (HI); 970 case E_SImode: 971 return QUAL_TYPE (SI); 972 case E_DImode: 973 return QUAL_TYPE (DI); 974 case E_TImode: 975 return QUAL_TYPE (TI); 976 case E_OImode: 977 return aarch64_simd_intOI_type_node; 978 case E_CImode: 979 return aarch64_simd_intCI_type_node; 980 case E_XImode: 981 return aarch64_simd_intXI_type_node; 982 case E_HFmode: 983 return aarch64_fp16_type_node; 984 case E_SFmode: 985 return float_type_node; 986 case E_DFmode: 987 return double_type_node; 988 case E_BFmode: 989 return bfloat16_type_node; 990 default: 991 gcc_unreachable (); 992 } 993 #undef QUAL_TYPE 994 } 995 996 /* Helper function for aarch64_simd_builtin_type. */ 997 static tree 998 aarch64_lookup_simd_type_in_table (machine_mode mode, 999 enum aarch64_type_qualifiers qualifiers) 1000 { 1001 int i; 1002 int nelts = ARRAY_SIZE (aarch64_simd_types); 1003 int q = qualifiers & (qualifier_poly | qualifier_unsigned); 1004 1005 for (i = 0; i < nelts; i++) 1006 { 1007 if (aarch64_simd_types[i].mode == mode 1008 && aarch64_simd_types[i].q == q) 1009 return aarch64_simd_types[i].itype; 1010 if (aarch64_simd_tuple_types[i][0] != NULL_TREE) 1011 for (int j = 0; j < 3; j++) 1012 if (aarch64_simd_tuple_modes[i][j] == mode 1013 && aarch64_simd_types[i].q == q) 1014 return aarch64_simd_tuple_types[i][j]; 1015 } 1016 1017 return NULL_TREE; 1018 } 1019 1020 /* Return a type for an operand with specified mode and qualifiers. */ 1021 static tree 1022 aarch64_simd_builtin_type (machine_mode mode, 1023 enum aarch64_type_qualifiers qualifiers) 1024 { 1025 tree type = NULL_TREE; 1026 1027 /* For pointers, we want a pointer to the basic type of the vector. */ 1028 if ((qualifiers & qualifier_pointer) && VECTOR_MODE_P (mode)) 1029 mode = GET_MODE_INNER (mode); 1030 1031 /* Non-poly scalar modes map to standard types not in the table. */ 1032 if ((qualifiers & qualifier_poly) || VECTOR_MODE_P (mode)) 1033 type = aarch64_lookup_simd_type_in_table (mode, qualifiers); 1034 else 1035 type = aarch64_int_or_fp_type (mode, qualifiers); 1036 1037 gcc_assert (type != NULL_TREE); 1038 1039 /* Add qualifiers. */ 1040 if (qualifiers & qualifier_const) 1041 type = build_qualified_type (type, TYPE_QUAL_CONST); 1042 if (qualifiers & qualifier_pointer) 1043 type = build_pointer_type (type); 1044 1045 return type; 1046 } 1047 1048 static void 1049 aarch64_init_simd_builtin_types (void) 1050 { 1051 int i; 1052 int nelts = ARRAY_SIZE (aarch64_simd_types); 1053 tree tdecl; 1054 1055 /* Init all the element types built by the front-end. */ 1056 aarch64_simd_types[Int8x8_t].eltype = intQI_type_node; 1057 aarch64_simd_types[Int8x16_t].eltype = intQI_type_node; 1058 aarch64_simd_types[Int16x4_t].eltype = intHI_type_node; 1059 aarch64_simd_types[Int16x8_t].eltype = intHI_type_node; 1060 aarch64_simd_types[Int32x2_t].eltype = intSI_type_node; 1061 aarch64_simd_types[Int32x4_t].eltype = intSI_type_node; 1062 aarch64_simd_types[Int64x1_t].eltype = intDI_type_node; 1063 aarch64_simd_types[Int64x2_t].eltype = intDI_type_node; 1064 aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node; 1065 aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node; 1066 aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node; 1067 aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node; 1068 aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node; 1069 aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node; 1070 aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node; 1071 aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node; 1072 1073 /* Poly types are a world of their own. */ 1074 aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype = 1075 build_distinct_type_copy (unsigned_intQI_type_node); 1076 /* Prevent front-ends from transforming Poly8_t arrays into string 1077 literals. */ 1078 TYPE_STRING_FLAG (aarch64_simd_types[Poly8_t].eltype) = false; 1079 1080 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype = 1081 build_distinct_type_copy (unsigned_intHI_type_node); 1082 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype = 1083 build_distinct_type_copy (unsigned_intDI_type_node); 1084 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype = 1085 build_distinct_type_copy (unsigned_intTI_type_node); 1086 /* Init poly vector element types with scalar poly types. */ 1087 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype; 1088 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype; 1089 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype; 1090 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype; 1091 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype; 1092 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype; 1093 1094 /* Continue with standard types. */ 1095 aarch64_simd_types[Float16x4_t].eltype = aarch64_fp16_type_node; 1096 aarch64_simd_types[Float16x8_t].eltype = aarch64_fp16_type_node; 1097 aarch64_simd_types[Float32x2_t].eltype = float_type_node; 1098 aarch64_simd_types[Float32x4_t].eltype = float_type_node; 1099 aarch64_simd_types[Float64x1_t].eltype = double_type_node; 1100 aarch64_simd_types[Float64x2_t].eltype = double_type_node; 1101 1102 /* Init Bfloat vector types with underlying __bf16 type. */ 1103 aarch64_simd_types[Bfloat16x4_t].eltype = bfloat16_type_node; 1104 aarch64_simd_types[Bfloat16x8_t].eltype = bfloat16_type_node; 1105 1106 for (i = 0; i < nelts; i++) 1107 { 1108 tree eltype = aarch64_simd_types[i].eltype; 1109 machine_mode mode = aarch64_simd_types[i].mode; 1110 1111 if (aarch64_simd_types[i].itype == NULL) 1112 { 1113 tree type = build_vector_type (eltype, GET_MODE_NUNITS (mode)); 1114 type = build_distinct_type_copy (type); 1115 SET_TYPE_STRUCTURAL_EQUALITY (type); 1116 1117 tree mangled_name = get_identifier (aarch64_simd_types[i].mangle); 1118 tree value = tree_cons (NULL_TREE, mangled_name, NULL_TREE); 1119 TYPE_ATTRIBUTES (type) 1120 = tree_cons (get_identifier ("Advanced SIMD type"), value, 1121 TYPE_ATTRIBUTES (type)); 1122 aarch64_simd_types[i].itype = type; 1123 } 1124 1125 tdecl = add_builtin_type (aarch64_simd_types[i].name, 1126 aarch64_simd_types[i].itype); 1127 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl; 1128 } 1129 1130 #define AARCH64_BUILD_SIGNED_TYPE(mode) \ 1131 make_signed_type (GET_MODE_PRECISION (mode)); 1132 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode); 1133 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode); 1134 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode); 1135 #undef AARCH64_BUILD_SIGNED_TYPE 1136 1137 tdecl = add_builtin_type 1138 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node); 1139 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl; 1140 tdecl = add_builtin_type 1141 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node); 1142 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl; 1143 tdecl = add_builtin_type 1144 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node); 1145 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl; 1146 } 1147 1148 static void 1149 aarch64_init_simd_builtin_scalar_types (void) 1150 { 1151 /* Define typedefs for all the standard scalar types. */ 1152 (*lang_hooks.types.register_builtin_type) (intQI_type_node, 1153 "__builtin_aarch64_simd_qi"); 1154 (*lang_hooks.types.register_builtin_type) (intHI_type_node, 1155 "__builtin_aarch64_simd_hi"); 1156 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, 1157 "__builtin_aarch64_simd_hf"); 1158 (*lang_hooks.types.register_builtin_type) (intSI_type_node, 1159 "__builtin_aarch64_simd_si"); 1160 (*lang_hooks.types.register_builtin_type) (float_type_node, 1161 "__builtin_aarch64_simd_sf"); 1162 (*lang_hooks.types.register_builtin_type) (intDI_type_node, 1163 "__builtin_aarch64_simd_di"); 1164 (*lang_hooks.types.register_builtin_type) (double_type_node, 1165 "__builtin_aarch64_simd_df"); 1166 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node, 1167 "__builtin_aarch64_simd_poly8"); 1168 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node, 1169 "__builtin_aarch64_simd_poly16"); 1170 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node, 1171 "__builtin_aarch64_simd_poly64"); 1172 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node, 1173 "__builtin_aarch64_simd_poly128"); 1174 (*lang_hooks.types.register_builtin_type) (intTI_type_node, 1175 "__builtin_aarch64_simd_ti"); 1176 (*lang_hooks.types.register_builtin_type) (bfloat16_type_node, 1177 "__builtin_aarch64_simd_bf"); 1178 /* Unsigned integer types for various mode sizes. */ 1179 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node, 1180 "__builtin_aarch64_simd_uqi"); 1181 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node, 1182 "__builtin_aarch64_simd_uhi"); 1183 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node, 1184 "__builtin_aarch64_simd_usi"); 1185 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node, 1186 "__builtin_aarch64_simd_udi"); 1187 } 1188 1189 /* Return a set of FLAG_* flags derived from FLAGS 1190 that describe what a function with result MODE could do, 1191 taking the command-line flags into account. */ 1192 static unsigned int 1193 aarch64_call_properties (unsigned int flags, machine_mode mode) 1194 { 1195 if (!(flags & FLAG_AUTO_FP) && FLOAT_MODE_P (mode)) 1196 flags |= FLAG_FP; 1197 1198 /* -fno-trapping-math means that we can assume any FP exceptions 1199 are not user-visible. */ 1200 if (!flag_trapping_math) 1201 flags &= ~FLAG_RAISE_FP_EXCEPTIONS; 1202 1203 return flags; 1204 } 1205 1206 /* Return true if calls to a function with flags F and mode MODE 1207 could modify some form of global state. */ 1208 static bool 1209 aarch64_modifies_global_state_p (unsigned int f, machine_mode mode) 1210 { 1211 unsigned int flags = aarch64_call_properties (f, mode); 1212 1213 if (flags & FLAG_RAISE_FP_EXCEPTIONS) 1214 return true; 1215 1216 if (flags & FLAG_PREFETCH_MEMORY) 1217 return true; 1218 1219 return flags & FLAG_WRITE_MEMORY; 1220 } 1221 1222 /* Return true if calls to a function with flags F and mode MODE 1223 could read some form of global state. */ 1224 static bool 1225 aarch64_reads_global_state_p (unsigned int f, machine_mode mode) 1226 { 1227 unsigned int flags = aarch64_call_properties (f, mode); 1228 1229 if (flags & FLAG_READ_FPCR) 1230 return true; 1231 1232 return flags & FLAG_READ_MEMORY; 1233 } 1234 1235 /* Return true if calls to a function with flags F and mode MODE 1236 could raise a signal. */ 1237 static bool 1238 aarch64_could_trap_p (unsigned int f, machine_mode mode) 1239 { 1240 unsigned int flags = aarch64_call_properties (f, mode); 1241 1242 if (flags & FLAG_RAISE_FP_EXCEPTIONS) 1243 return true; 1244 1245 if (flags & (FLAG_READ_MEMORY | FLAG_WRITE_MEMORY)) 1246 return true; 1247 1248 return false; 1249 } 1250 1251 /* Add attribute NAME to ATTRS. */ 1252 static tree 1253 aarch64_add_attribute (const char *name, tree attrs) 1254 { 1255 return tree_cons (get_identifier (name), NULL_TREE, attrs); 1256 } 1257 1258 /* Return the appropriate attributes for a function that has 1259 flags F and mode MODE. */ 1260 static tree 1261 aarch64_get_attributes (unsigned int f, machine_mode mode) 1262 { 1263 tree attrs = NULL_TREE; 1264 1265 if (!aarch64_modifies_global_state_p (f, mode)) 1266 { 1267 if (aarch64_reads_global_state_p (f, mode)) 1268 attrs = aarch64_add_attribute ("pure", attrs); 1269 else 1270 attrs = aarch64_add_attribute ("const", attrs); 1271 } 1272 1273 if (!flag_non_call_exceptions || !aarch64_could_trap_p (f, mode)) 1274 attrs = aarch64_add_attribute ("nothrow", attrs); 1275 1276 return aarch64_add_attribute ("leaf", attrs); 1277 } 1278 1279 /* Due to the architecture not providing lane variant of the lane instructions 1280 for fcmla we can't use the standard simd builtin expansion code, but we 1281 still want the majority of the validation that would normally be done. */ 1282 1283 void 1284 aarch64_init_fcmla_laneq_builtins (void) 1285 { 1286 unsigned int i = 0; 1287 1288 for (i = 0; i < ARRAY_SIZE (aarch64_fcmla_lane_builtin_data); ++i) 1289 { 1290 aarch64_fcmla_laneq_builtin_datum* d 1291 = &aarch64_fcmla_lane_builtin_data[i]; 1292 tree argtype = aarch64_simd_builtin_type (d->mode, qualifier_none); 1293 machine_mode quadmode = GET_MODE_2XWIDER_MODE (d->mode).require (); 1294 tree quadtype = aarch64_simd_builtin_type (quadmode, qualifier_none); 1295 tree lanetype 1296 = aarch64_simd_builtin_type (SImode, qualifier_lane_pair_index); 1297 tree ftype = build_function_type_list (argtype, argtype, argtype, 1298 quadtype, lanetype, NULL_TREE); 1299 tree attrs = aarch64_get_attributes (FLAG_FP, d->mode); 1300 tree fndecl 1301 = aarch64_general_add_builtin (d->name, ftype, d->fcode, attrs); 1302 1303 aarch64_builtin_decls[d->fcode] = fndecl; 1304 } 1305 } 1306 1307 void 1308 aarch64_init_simd_intrinsics (void) 1309 { 1310 unsigned int i = 0; 1311 1312 for (i = 0; i < ARRAY_SIZE (aarch64_simd_intrinsic_data); ++i) 1313 { 1314 auto d = &aarch64_simd_intrinsic_data[i]; 1315 1316 if (d->skip) 1317 continue; 1318 1319 tree return_type = void_type_node; 1320 tree args = void_list_node; 1321 1322 for (int op_num = d->op_count - 1; op_num >= 0; op_num--) 1323 { 1324 machine_mode op_mode = d->op_modes[op_num]; 1325 enum aarch64_type_qualifiers qualifiers = d->qualifiers[op_num]; 1326 1327 tree eltype = aarch64_simd_builtin_type (op_mode, qualifiers); 1328 1329 if (op_num == 0) 1330 return_type = eltype; 1331 else 1332 args = tree_cons (NULL_TREE, eltype, args); 1333 } 1334 1335 tree ftype = build_function_type (return_type, args); 1336 tree attrs = aarch64_get_attributes (d->flags, d->op_modes[0]); 1337 unsigned int code 1338 = (d->fcode << AARCH64_BUILTIN_SHIFT | AARCH64_BUILTIN_GENERAL); 1339 tree fndecl = simulate_builtin_function_decl (input_location, d->name, 1340 ftype, code, NULL, attrs); 1341 aarch64_builtin_decls[d->fcode] = fndecl; 1342 } 1343 } 1344 1345 void 1346 aarch64_init_simd_builtin_functions (bool called_from_pragma) 1347 { 1348 unsigned int i, fcode = AARCH64_SIMD_PATTERN_START; 1349 1350 if (!called_from_pragma) 1351 { 1352 tree lane_check_fpr = build_function_type_list (void_type_node, 1353 size_type_node, 1354 size_type_node, 1355 intSI_type_node, 1356 NULL); 1357 aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] 1358 = aarch64_general_add_builtin ("__builtin_aarch64_im_lane_boundsi", 1359 lane_check_fpr, 1360 AARCH64_SIMD_BUILTIN_LANE_CHECK); 1361 } 1362 1363 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++) 1364 { 1365 bool print_type_signature_p = false; 1366 char type_signature[SIMD_MAX_BUILTIN_ARGS + 1] = { 0 }; 1367 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i]; 1368 char namebuf[60]; 1369 tree ftype = NULL; 1370 tree fndecl = NULL; 1371 1372 d->fcode = fcode; 1373 1374 /* We must track two variables here. op_num is 1375 the operand number as in the RTL pattern. This is 1376 required to access the mode (e.g. V4SF mode) of the 1377 argument, from which the base type can be derived. 1378 arg_num is an index in to the qualifiers data, which 1379 gives qualifiers to the type (e.g. const unsigned). 1380 The reason these two variables may differ by one is the 1381 void return type. While all return types take the 0th entry 1382 in the qualifiers array, there is no operand for them in the 1383 RTL pattern. */ 1384 int op_num = insn_data[d->code].n_operands - 1; 1385 int arg_num = d->qualifiers[0] & qualifier_void 1386 ? op_num + 1 1387 : op_num; 1388 tree return_type = void_type_node, args = void_list_node; 1389 tree eltype; 1390 1391 int struct_mode_args = 0; 1392 for (int j = op_num; j >= 0; j--) 1393 { 1394 machine_mode op_mode = insn_data[d->code].operand[j].mode; 1395 if (aarch64_advsimd_struct_mode_p (op_mode)) 1396 struct_mode_args++; 1397 } 1398 1399 if ((called_from_pragma && struct_mode_args == 0) 1400 || (!called_from_pragma && struct_mode_args > 0)) 1401 continue; 1402 1403 /* Build a function type directly from the insn_data for this 1404 builtin. The build_function_type () function takes care of 1405 removing duplicates for us. */ 1406 for (; op_num >= 0; arg_num--, op_num--) 1407 { 1408 machine_mode op_mode = insn_data[d->code].operand[op_num].mode; 1409 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num]; 1410 1411 if (qualifiers & qualifier_unsigned) 1412 { 1413 type_signature[op_num] = 'u'; 1414 print_type_signature_p = true; 1415 } 1416 else if (qualifiers & qualifier_poly) 1417 { 1418 type_signature[op_num] = 'p'; 1419 print_type_signature_p = true; 1420 } 1421 else 1422 type_signature[op_num] = 's'; 1423 1424 /* Some builtins have different user-facing types 1425 for certain arguments, encoded in d->mode. */ 1426 if (qualifiers & qualifier_map_mode) 1427 op_mode = d->mode; 1428 1429 eltype = aarch64_simd_builtin_type (op_mode, qualifiers); 1430 1431 /* If we have reached arg_num == 0, we are at a non-void 1432 return type. Otherwise, we are still processing 1433 arguments. */ 1434 if (arg_num == 0) 1435 return_type = eltype; 1436 else 1437 args = tree_cons (NULL_TREE, eltype, args); 1438 } 1439 1440 ftype = build_function_type (return_type, args); 1441 1442 gcc_assert (ftype != NULL); 1443 1444 if (print_type_signature_p) 1445 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s", 1446 d->name, type_signature); 1447 else 1448 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s", 1449 d->name); 1450 1451 tree attrs = aarch64_get_attributes (d->flags, d->mode); 1452 1453 if (called_from_pragma) 1454 { 1455 unsigned int raw_code 1456 = (fcode << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL; 1457 fndecl = simulate_builtin_function_decl (input_location, namebuf, 1458 ftype, raw_code, NULL, 1459 attrs); 1460 } 1461 else 1462 fndecl = aarch64_general_add_builtin (namebuf, ftype, fcode, attrs); 1463 1464 aarch64_builtin_decls[fcode] = fndecl; 1465 } 1466 } 1467 1468 /* Register the tuple type that contains NUM_VECTORS of the AdvSIMD type 1469 indexed by TYPE_INDEX. */ 1470 static void 1471 register_tuple_type (unsigned int num_vectors, unsigned int type_index) 1472 { 1473 aarch64_simd_type_info *type = &aarch64_simd_types[type_index]; 1474 1475 /* Synthesize the name of the user-visible vector tuple type. */ 1476 const char *vector_type_name = type->name; 1477 char tuple_type_name[sizeof ("bfloat16x4x2_t")]; 1478 snprintf (tuple_type_name, sizeof (tuple_type_name), "%.*sx%d_t", 1479 (int) strlen (vector_type_name) - 4, vector_type_name + 2, 1480 num_vectors); 1481 tuple_type_name[0] = TOLOWER (tuple_type_name[0]); 1482 1483 tree vector_type = type->itype; 1484 tree array_type = build_array_type_nelts (vector_type, num_vectors); 1485 if (type->mode == DImode) 1486 { 1487 if (num_vectors == 2) 1488 SET_TYPE_MODE (array_type, V2x1DImode); 1489 else if (num_vectors == 3) 1490 SET_TYPE_MODE (array_type, V3x1DImode); 1491 else if (num_vectors == 4) 1492 SET_TYPE_MODE (array_type, V4x1DImode); 1493 } 1494 1495 unsigned int alignment 1496 = known_eq (GET_MODE_SIZE (type->mode), 16) ? 128 : 64; 1497 machine_mode tuple_mode = TYPE_MODE_RAW (array_type); 1498 gcc_assert (VECTOR_MODE_P (tuple_mode) 1499 && TYPE_MODE (array_type) == tuple_mode 1500 && TYPE_ALIGN (array_type) == alignment); 1501 1502 tree field = build_decl (input_location, FIELD_DECL, 1503 get_identifier ("val"), array_type); 1504 1505 tree t = lang_hooks.types.simulate_record_decl (input_location, 1506 tuple_type_name, 1507 make_array_slice (&field, 1508 1)); 1509 gcc_assert (TYPE_MODE_RAW (t) == TYPE_MODE (t) 1510 && (flag_pack_struct 1511 || maximum_field_alignment 1512 || (TYPE_MODE_RAW (t) == tuple_mode 1513 && TYPE_ALIGN (t) == alignment))); 1514 1515 aarch64_simd_tuple_modes[type_index][num_vectors - 2] = tuple_mode; 1516 aarch64_simd_tuple_types[type_index][num_vectors - 2] = t; 1517 } 1518 1519 static bool 1520 aarch64_scalar_builtin_type_p (aarch64_simd_type t) 1521 { 1522 return (t == Poly8_t || t == Poly16_t || t == Poly64_t || t == Poly128_t); 1523 } 1524 1525 /* Enable AARCH64_FL_* flags EXTRA_FLAGS on top of the base Advanced SIMD 1526 set. */ 1527 aarch64_simd_switcher::aarch64_simd_switcher (aarch64_feature_flags extra_flags) 1528 : m_old_asm_isa_flags (aarch64_asm_isa_flags), 1529 m_old_general_regs_only (TARGET_GENERAL_REGS_ONLY) 1530 { 1531 /* Changing the ISA flags should be enough here. We shouldn't need to 1532 pay the compile-time cost of a full target switch. */ 1533 global_options.x_target_flags &= ~MASK_GENERAL_REGS_ONLY; 1534 aarch64_set_asm_isa_flags (AARCH64_FL_FP | AARCH64_FL_SIMD | extra_flags); 1535 } 1536 1537 aarch64_simd_switcher::~aarch64_simd_switcher () 1538 { 1539 if (m_old_general_regs_only) 1540 global_options.x_target_flags |= MASK_GENERAL_REGS_ONLY; 1541 aarch64_set_asm_isa_flags (m_old_asm_isa_flags); 1542 } 1543 1544 /* Implement #pragma GCC aarch64 "arm_neon.h". 1545 1546 The types and functions defined here need to be available internally 1547 during LTO as well. */ 1548 void 1549 handle_arm_neon_h (void) 1550 { 1551 aarch64_simd_switcher simd; 1552 1553 /* Register the AdvSIMD vector tuple types. */ 1554 for (unsigned int i = 0; i < ARM_NEON_H_TYPES_LAST; i++) 1555 for (unsigned int count = 2; count <= 4; ++count) 1556 if (!aarch64_scalar_builtin_type_p (aarch64_simd_types[i].type)) 1557 register_tuple_type (count, i); 1558 1559 aarch64_init_simd_builtin_functions (true); 1560 aarch64_init_simd_intrinsics (); 1561 } 1562 1563 static void 1564 aarch64_init_simd_builtins (void) 1565 { 1566 aarch64_init_simd_builtin_types (); 1567 1568 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics. 1569 Therefore we need to preserve the old __builtin scalar types. It can be 1570 removed once all the intrinsics become strongly typed using the qualifier 1571 system. */ 1572 aarch64_init_simd_builtin_scalar_types (); 1573 1574 aarch64_init_simd_builtin_functions (false); 1575 if (in_lto_p) 1576 handle_arm_neon_h (); 1577 1578 /* Initialize the remaining fcmla_laneq intrinsics. */ 1579 aarch64_init_fcmla_laneq_builtins (); 1580 } 1581 1582 static void 1583 aarch64_init_crc32_builtins () 1584 { 1585 tree usi_type = aarch64_simd_builtin_type (SImode, qualifier_unsigned); 1586 unsigned int i = 0; 1587 1588 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i) 1589 { 1590 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i]; 1591 tree argtype = aarch64_simd_builtin_type (d->mode, qualifier_unsigned); 1592 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE); 1593 tree attrs = aarch64_get_attributes (FLAG_NONE, d->mode); 1594 tree fndecl 1595 = aarch64_general_add_builtin (d->name, ftype, d->fcode, attrs); 1596 1597 aarch64_builtin_decls[d->fcode] = fndecl; 1598 } 1599 } 1600 1601 /* Add builtins for reciprocal square root. */ 1602 1603 void 1604 aarch64_init_builtin_rsqrt (void) 1605 { 1606 tree fndecl = NULL; 1607 tree ftype = NULL; 1608 1609 tree V2SF_type_node = build_vector_type (float_type_node, 2); 1610 tree V2DF_type_node = build_vector_type (double_type_node, 2); 1611 tree V4SF_type_node = build_vector_type (float_type_node, 4); 1612 1613 struct builtin_decls_data 1614 { 1615 tree type_node; 1616 const char *builtin_name; 1617 int function_code; 1618 }; 1619 1620 builtin_decls_data bdda[] = 1621 { 1622 { double_type_node, "__builtin_aarch64_rsqrt_df", AARCH64_BUILTIN_RSQRT_DF }, 1623 { float_type_node, "__builtin_aarch64_rsqrt_sf", AARCH64_BUILTIN_RSQRT_SF }, 1624 { V2DF_type_node, "__builtin_aarch64_rsqrt_v2df", AARCH64_BUILTIN_RSQRT_V2DF }, 1625 { V2SF_type_node, "__builtin_aarch64_rsqrt_v2sf", AARCH64_BUILTIN_RSQRT_V2SF }, 1626 { V4SF_type_node, "__builtin_aarch64_rsqrt_v4sf", AARCH64_BUILTIN_RSQRT_V4SF } 1627 }; 1628 1629 builtin_decls_data *bdd = bdda; 1630 builtin_decls_data *bdd_end = bdd + (ARRAY_SIZE (bdda)); 1631 1632 for (; bdd < bdd_end; bdd++) 1633 { 1634 ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE); 1635 tree attrs = aarch64_get_attributes (FLAG_FP, TYPE_MODE (bdd->type_node)); 1636 fndecl = aarch64_general_add_builtin (bdd->builtin_name, 1637 ftype, bdd->function_code, attrs); 1638 aarch64_builtin_decls[bdd->function_code] = fndecl; 1639 } 1640 } 1641 1642 /* Initialize the backend types that support the user-visible __fp16 1643 type, also initialize a pointer to that type, to be used when 1644 forming HFAs. */ 1645 1646 static void 1647 aarch64_init_fp16_types (void) 1648 { 1649 aarch64_fp16_type_node = make_node (REAL_TYPE); 1650 TYPE_PRECISION (aarch64_fp16_type_node) = 16; 1651 layout_type (aarch64_fp16_type_node); 1652 1653 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, "__fp16"); 1654 aarch64_fp16_ptr_type_node = build_pointer_type (aarch64_fp16_type_node); 1655 } 1656 1657 /* Initialize the backend REAL_TYPE type supporting bfloat types. */ 1658 static void 1659 aarch64_init_bf16_types (void) 1660 { 1661 lang_hooks.types.register_builtin_type (bfloat16_type_node, "__bf16"); 1662 aarch64_bf16_ptr_type_node = build_pointer_type (bfloat16_type_node); 1663 } 1664 1665 /* Pointer authentication builtins that will become NOP on legacy platform. 1666 Currently, these builtins are for internal use only (libgcc EH unwinder). */ 1667 1668 void 1669 aarch64_init_pauth_hint_builtins (void) 1670 { 1671 /* Pointer Authentication builtins. */ 1672 tree ftype_pointer_auth 1673 = build_function_type_list (ptr_type_node, ptr_type_node, 1674 unsigned_intDI_type_node, NULL_TREE); 1675 tree ftype_pointer_strip 1676 = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE); 1677 1678 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIA1716] 1679 = aarch64_general_add_builtin ("__builtin_aarch64_autia1716", 1680 ftype_pointer_auth, 1681 AARCH64_PAUTH_BUILTIN_AUTIA1716); 1682 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIA1716] 1683 = aarch64_general_add_builtin ("__builtin_aarch64_pacia1716", 1684 ftype_pointer_auth, 1685 AARCH64_PAUTH_BUILTIN_PACIA1716); 1686 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIB1716] 1687 = aarch64_general_add_builtin ("__builtin_aarch64_autib1716", 1688 ftype_pointer_auth, 1689 AARCH64_PAUTH_BUILTIN_AUTIB1716); 1690 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIB1716] 1691 = aarch64_general_add_builtin ("__builtin_aarch64_pacib1716", 1692 ftype_pointer_auth, 1693 AARCH64_PAUTH_BUILTIN_PACIB1716); 1694 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI] 1695 = aarch64_general_add_builtin ("__builtin_aarch64_xpaclri", 1696 ftype_pointer_strip, 1697 AARCH64_PAUTH_BUILTIN_XPACLRI); 1698 } 1699 1700 /* Initialize the transactional memory extension (TME) builtins. */ 1701 static void 1702 aarch64_init_tme_builtins (void) 1703 { 1704 tree ftype_uint64_void 1705 = build_function_type_list (uint64_type_node, NULL); 1706 tree ftype_void_void 1707 = build_function_type_list (void_type_node, NULL); 1708 tree ftype_void_uint64 1709 = build_function_type_list (void_type_node, uint64_type_node, NULL); 1710 1711 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TSTART] 1712 = aarch64_general_simulate_builtin ("__tstart", ftype_uint64_void, 1713 AARCH64_TME_BUILTIN_TSTART); 1714 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TTEST] 1715 = aarch64_general_simulate_builtin ("__ttest", ftype_uint64_void, 1716 AARCH64_TME_BUILTIN_TTEST); 1717 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCOMMIT] 1718 = aarch64_general_simulate_builtin ("__tcommit", ftype_void_void, 1719 AARCH64_TME_BUILTIN_TCOMMIT); 1720 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCANCEL] 1721 = aarch64_general_simulate_builtin ("__tcancel", ftype_void_uint64, 1722 AARCH64_TME_BUILTIN_TCANCEL); 1723 } 1724 1725 /* Add builtins for Random Number instructions. */ 1726 1727 static void 1728 aarch64_init_rng_builtins (void) 1729 { 1730 tree unsigned_ptr_type 1731 = build_pointer_type (get_typenode_from_name (UINT64_TYPE)); 1732 tree ftype 1733 = build_function_type_list (integer_type_node, unsigned_ptr_type, NULL); 1734 aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDR] 1735 = aarch64_general_add_builtin ("__builtin_aarch64_rndr", ftype, 1736 AARCH64_BUILTIN_RNG_RNDR); 1737 aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDRRS] 1738 = aarch64_general_add_builtin ("__builtin_aarch64_rndrrs", ftype, 1739 AARCH64_BUILTIN_RNG_RNDRRS); 1740 } 1741 1742 /* Add builtins for reading system register. */ 1743 static void 1744 aarch64_init_rwsr_builtins (void) 1745 { 1746 tree fntype = NULL; 1747 tree const_char_ptr_type 1748 = build_pointer_type (build_type_variant (char_type_node, true, false)); 1749 1750 #define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \ 1751 aarch64_builtin_decls[AARCH64_##F] \ 1752 = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F); 1753 1754 fntype 1755 = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL); 1756 AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype); 1757 1758 fntype 1759 = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL); 1760 AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype); 1761 1762 fntype 1763 = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL); 1764 AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype); 1765 1766 fntype 1767 = build_function_type_list (float_type_node, const_char_ptr_type, NULL); 1768 AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype); 1769 1770 fntype 1771 = build_function_type_list (double_type_node, const_char_ptr_type, NULL); 1772 AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype); 1773 1774 fntype 1775 = build_function_type_list (uint128_type_node, const_char_ptr_type, NULL); 1776 AARCH64_INIT_RWSR_BUILTINS_DECL (RSR128, rsr128, fntype); 1777 1778 fntype 1779 = build_function_type_list (void_type_node, const_char_ptr_type, 1780 uint32_type_node, NULL); 1781 1782 AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype); 1783 1784 fntype 1785 = build_function_type_list (void_type_node, const_char_ptr_type, 1786 const_ptr_type_node, NULL); 1787 AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype); 1788 1789 fntype 1790 = build_function_type_list (void_type_node, const_char_ptr_type, 1791 uint64_type_node, NULL); 1792 AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype); 1793 1794 fntype 1795 = build_function_type_list (void_type_node, const_char_ptr_type, 1796 float_type_node, NULL); 1797 AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype); 1798 1799 fntype 1800 = build_function_type_list (void_type_node, const_char_ptr_type, 1801 double_type_node, NULL); 1802 AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype); 1803 1804 fntype 1805 = build_function_type_list (void_type_node, const_char_ptr_type, 1806 uint128_type_node, NULL); 1807 AARCH64_INIT_RWSR_BUILTINS_DECL (WSR128, wsr128, fntype); 1808 } 1809 1810 /* Add builtins for data and instrution prefetch. */ 1811 static void 1812 aarch64_init_prefetch_builtin (void) 1813 { 1814 #define AARCH64_INIT_PREFETCH_BUILTIN(INDEX, N) \ 1815 aarch64_builtin_decls[INDEX] = \ 1816 aarch64_general_add_builtin ("__builtin_aarch64_" N, ftype, INDEX) 1817 1818 tree ftype; 1819 tree cv_argtype; 1820 cv_argtype = build_qualified_type (void_type_node, TYPE_QUAL_CONST 1821 | TYPE_QUAL_VOLATILE); 1822 cv_argtype = build_pointer_type (cv_argtype); 1823 1824 ftype = build_function_type_list (void_type_node, cv_argtype, NULL); 1825 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLD, "pld"); 1826 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLI, "pli"); 1827 1828 ftype = build_function_type_list (void_type_node, unsigned_type_node, 1829 unsigned_type_node, unsigned_type_node, 1830 cv_argtype, NULL); 1831 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLDX, "pldx"); 1832 1833 ftype = build_function_type_list (void_type_node, unsigned_type_node, 1834 unsigned_type_node, cv_argtype, NULL); 1835 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLIX, "plix"); 1836 } 1837 1838 /* Initialize the memory tagging extension (MTE) builtins. */ 1839 static GTY(()) struct aarch64_mte 1840 { 1841 tree ftype; 1842 enum insn_code icode; 1843 } aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_END - 1844 AARCH64_MEMTAG_BUILTIN_START - 1]; 1845 1846 static void 1847 aarch64_init_memtag_builtins (void) 1848 { 1849 tree fntype = NULL; 1850 1851 #define AARCH64_INIT_MEMTAG_BUILTINS_DECL(F, N, I, T) \ 1852 aarch64_builtin_decls[AARCH64_MEMTAG_BUILTIN_##F] \ 1853 = aarch64_general_simulate_builtin ("__arm_mte_"#N, T, \ 1854 AARCH64_MEMTAG_BUILTIN_##F); \ 1855 aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_##F - \ 1856 AARCH64_MEMTAG_BUILTIN_START - 1] = \ 1857 {T, CODE_FOR_##I}; 1858 1859 fntype = build_function_type_list (ptr_type_node, ptr_type_node, 1860 uint64_type_node, NULL); 1861 AARCH64_INIT_MEMTAG_BUILTINS_DECL (IRG, create_random_tag, irg, fntype); 1862 1863 fntype = build_function_type_list (uint64_type_node, ptr_type_node, 1864 uint64_type_node, NULL); 1865 AARCH64_INIT_MEMTAG_BUILTINS_DECL (GMI, exclude_tag, gmi, fntype); 1866 1867 fntype = build_function_type_list (ptrdiff_type_node, ptr_type_node, 1868 ptr_type_node, NULL); 1869 AARCH64_INIT_MEMTAG_BUILTINS_DECL (SUBP, ptrdiff, subp, fntype); 1870 1871 fntype = build_function_type_list (ptr_type_node, ptr_type_node, 1872 unsigned_type_node, NULL); 1873 AARCH64_INIT_MEMTAG_BUILTINS_DECL (INC_TAG, increment_tag, addg, fntype); 1874 1875 fntype = build_function_type_list (void_type_node, ptr_type_node, NULL); 1876 AARCH64_INIT_MEMTAG_BUILTINS_DECL (SET_TAG, set_tag, stg, fntype); 1877 1878 fntype = build_function_type_list (ptr_type_node, ptr_type_node, NULL); 1879 AARCH64_INIT_MEMTAG_BUILTINS_DECL (GET_TAG, get_tag, ldg, fntype); 1880 1881 #undef AARCH64_INIT_MEMTAG_BUILTINS_DECL 1882 } 1883 1884 /* Add builtins for Load/store 64 Byte instructions. */ 1885 1886 typedef struct 1887 { 1888 const char *name; 1889 unsigned int code; 1890 tree type; 1891 } ls64_builtins_data; 1892 1893 static GTY(()) tree ls64_arm_data_t = NULL_TREE; 1894 1895 static void 1896 aarch64_init_ls64_builtins_types (void) 1897 { 1898 /* Synthesize: 1899 1900 typedef struct { 1901 uint64_t val[8]; 1902 } __arm_data512_t; */ 1903 const char *tuple_type_name = "__arm_data512_t"; 1904 tree node_type = get_typenode_from_name (UINT64_TYPE); 1905 tree array_type = build_array_type_nelts (node_type, 8); 1906 SET_TYPE_MODE (array_type, V8DImode); 1907 1908 gcc_assert (TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type)); 1909 gcc_assert (TYPE_ALIGN (array_type) == 64); 1910 1911 tree field = build_decl (input_location, FIELD_DECL, 1912 get_identifier ("val"), array_type); 1913 1914 ls64_arm_data_t = lang_hooks.types.simulate_record_decl (input_location, 1915 tuple_type_name, 1916 make_array_slice (&field, 1)); 1917 1918 gcc_assert (TYPE_MODE (ls64_arm_data_t) == V8DImode); 1919 gcc_assert (TYPE_MODE_RAW (ls64_arm_data_t) == TYPE_MODE (ls64_arm_data_t)); 1920 gcc_assert (TYPE_ALIGN (ls64_arm_data_t) == 64); 1921 } 1922 1923 static void 1924 aarch64_init_ls64_builtins (void) 1925 { 1926 aarch64_init_ls64_builtins_types (); 1927 1928 ls64_builtins_data data[4] = { 1929 {"__arm_ld64b", AARCH64_LS64_BUILTIN_LD64B, 1930 build_function_type_list (ls64_arm_data_t, 1931 const_ptr_type_node, NULL_TREE)}, 1932 {"__arm_st64b", AARCH64_LS64_BUILTIN_ST64B, 1933 build_function_type_list (void_type_node, ptr_type_node, 1934 ls64_arm_data_t, NULL_TREE)}, 1935 {"__arm_st64bv", AARCH64_LS64_BUILTIN_ST64BV, 1936 build_function_type_list (uint64_type_node, ptr_type_node, 1937 ls64_arm_data_t, NULL_TREE)}, 1938 {"__arm_st64bv0", AARCH64_LS64_BUILTIN_ST64BV0, 1939 build_function_type_list (uint64_type_node, ptr_type_node, 1940 ls64_arm_data_t, NULL_TREE)}, 1941 }; 1942 1943 for (size_t i = 0; i < ARRAY_SIZE (data); ++i) 1944 aarch64_builtin_decls[data[i].code] 1945 = aarch64_general_simulate_builtin (data[i].name, data[i].type, 1946 data[i].code); 1947 } 1948 1949 static void 1950 aarch64_init_data_intrinsics (void) 1951 { 1952 tree uint32_fntype = build_function_type_list (uint32_type_node, 1953 uint32_type_node, NULL_TREE); 1954 tree ulong_fntype = build_function_type_list (long_unsigned_type_node, 1955 long_unsigned_type_node, 1956 NULL_TREE); 1957 tree uint64_fntype = build_function_type_list (uint64_type_node, 1958 uint64_type_node, NULL_TREE); 1959 aarch64_builtin_decls[AARCH64_REV16] 1960 = aarch64_general_add_builtin ("__builtin_aarch64_rev16", uint32_fntype, 1961 AARCH64_REV16); 1962 aarch64_builtin_decls[AARCH64_REV16L] 1963 = aarch64_general_add_builtin ("__builtin_aarch64_rev16l", ulong_fntype, 1964 AARCH64_REV16L); 1965 aarch64_builtin_decls[AARCH64_REV16LL] 1966 = aarch64_general_add_builtin ("__builtin_aarch64_rev16ll", uint64_fntype, 1967 AARCH64_REV16LL); 1968 aarch64_builtin_decls[AARCH64_RBIT] 1969 = aarch64_general_add_builtin ("__builtin_aarch64_rbit", uint32_fntype, 1970 AARCH64_RBIT); 1971 aarch64_builtin_decls[AARCH64_RBITL] 1972 = aarch64_general_add_builtin ("__builtin_aarch64_rbitl", ulong_fntype, 1973 AARCH64_RBITL); 1974 aarch64_builtin_decls[AARCH64_RBITLL] 1975 = aarch64_general_add_builtin ("__builtin_aarch64_rbitll", uint64_fntype, 1976 AARCH64_RBITLL); 1977 } 1978 1979 /* Implement #pragma GCC aarch64 "arm_acle.h". */ 1980 void 1981 handle_arm_acle_h (void) 1982 { 1983 aarch64_init_ls64_builtins (); 1984 aarch64_init_tme_builtins (); 1985 aarch64_init_memtag_builtins (); 1986 } 1987 1988 /* Initialize fpsr fpcr getters and setters. */ 1989 1990 static void 1991 aarch64_init_fpsr_fpcr_builtins (void) 1992 { 1993 tree ftype_set 1994 = build_function_type_list (void_type_node, unsigned_type_node, NULL); 1995 tree ftype_get 1996 = build_function_type_list (unsigned_type_node, NULL); 1997 1998 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR] 1999 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr", 2000 ftype_get, 2001 AARCH64_BUILTIN_GET_FPCR); 2002 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR] 2003 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr", 2004 ftype_set, 2005 AARCH64_BUILTIN_SET_FPCR); 2006 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR] 2007 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr", 2008 ftype_get, 2009 AARCH64_BUILTIN_GET_FPSR); 2010 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR] 2011 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr", 2012 ftype_set, 2013 AARCH64_BUILTIN_SET_FPSR); 2014 2015 ftype_set 2016 = build_function_type_list (void_type_node, long_long_unsigned_type_node, 2017 NULL); 2018 ftype_get 2019 = build_function_type_list (long_long_unsigned_type_node, NULL); 2020 2021 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR64] 2022 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr64", 2023 ftype_get, 2024 AARCH64_BUILTIN_GET_FPCR64); 2025 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR64] 2026 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr64", 2027 ftype_set, 2028 AARCH64_BUILTIN_SET_FPCR64); 2029 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR64] 2030 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr64", 2031 ftype_get, 2032 AARCH64_BUILTIN_GET_FPSR64); 2033 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR64] 2034 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr64", 2035 ftype_set, 2036 AARCH64_BUILTIN_SET_FPSR64); 2037 } 2038 2039 /* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */ 2040 2041 void 2042 aarch64_general_init_builtins (void) 2043 { 2044 aarch64_init_fpsr_fpcr_builtins (); 2045 2046 aarch64_init_fp16_types (); 2047 2048 aarch64_init_bf16_types (); 2049 2050 { 2051 aarch64_simd_switcher simd; 2052 aarch64_init_simd_builtins (); 2053 } 2054 2055 aarch64_init_crc32_builtins (); 2056 aarch64_init_builtin_rsqrt (); 2057 aarch64_init_rng_builtins (); 2058 aarch64_init_data_intrinsics (); 2059 2060 aarch64_init_rwsr_builtins (); 2061 aarch64_init_prefetch_builtin (); 2062 2063 tree ftype_jcvt 2064 = build_function_type_list (intSI_type_node, double_type_node, NULL); 2065 aarch64_builtin_decls[AARCH64_JSCVT] 2066 = aarch64_general_add_builtin ("__builtin_aarch64_jcvtzs", ftype_jcvt, 2067 AARCH64_JSCVT); 2068 2069 /* Initialize pointer authentication builtins which are backed by instructions 2070 in NOP encoding space. 2071 2072 NOTE: these builtins are supposed to be used by libgcc unwinder only, as 2073 there is no support on return address signing under ILP32, we don't 2074 register them. */ 2075 if (!TARGET_ILP32) 2076 aarch64_init_pauth_hint_builtins (); 2077 2078 if (in_lto_p) 2079 handle_arm_acle_h (); 2080 } 2081 2082 /* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */ 2083 tree 2084 aarch64_general_builtin_decl (unsigned code, bool) 2085 { 2086 if (code >= AARCH64_BUILTIN_MAX) 2087 return error_mark_node; 2088 2089 return aarch64_builtin_decls[code]; 2090 } 2091 2092 /* True if we've already complained about attempts to use functions 2093 when the required extension is disabled. */ 2094 static bool reported_missing_extension_p; 2095 2096 /* True if we've already complained about attempts to use functions 2097 which require registers that are missing. */ 2098 static bool reported_missing_registers_p; 2099 2100 /* Report an error against LOCATION that the user has tried to use 2101 function FNDECL when extension EXTENSION is disabled. */ 2102 static void 2103 aarch64_report_missing_extension (location_t location, tree fndecl, 2104 const char *extension) 2105 { 2106 /* Avoid reporting a slew of messages for a single oversight. */ 2107 if (reported_missing_extension_p) 2108 return; 2109 2110 error_at (location, "ACLE function %qD requires ISA extension %qs", 2111 fndecl, extension); 2112 inform (location, "you can enable %qs using the command-line" 2113 " option %<-march%>, or by using the %<target%>" 2114 " attribute or pragma", extension); 2115 reported_missing_extension_p = true; 2116 } 2117 2118 /* Report an error against LOCATION that the user has tried to use 2119 function FNDECL when non-general registers are disabled. */ 2120 static void 2121 aarch64_report_missing_registers (location_t location, tree fndecl) 2122 { 2123 /* Avoid reporting a slew of messages for a single oversight. */ 2124 if (reported_missing_registers_p) 2125 return; 2126 2127 error_at (location, 2128 "ACLE function %qD is incompatible with the use of %qs", 2129 fndecl, "-mgeneral-regs-only"); 2130 reported_missing_registers_p = true; 2131 } 2132 2133 /* Check whether all the AARCH64_FL_* values in REQUIRED_EXTENSIONS are 2134 enabled, given that those extensions are required for function FNDECL. 2135 Report an error against LOCATION if not. */ 2136 bool 2137 aarch64_check_required_extensions (location_t location, tree fndecl, 2138 aarch64_feature_flags required_extensions) 2139 { 2140 if ((required_extensions & ~aarch64_isa_flags) == 0) 2141 return true; 2142 2143 auto missing_extensions = required_extensions & ~aarch64_asm_isa_flags; 2144 2145 if (missing_extensions == 0) 2146 { 2147 /* All required extensions are enabled in aarch64_asm_isa_flags, so the 2148 error must be the use of general-regs-only. */ 2149 aarch64_report_missing_registers (location, fndecl); 2150 return false; 2151 } 2152 2153 if (missing_extensions & AARCH64_FL_SM_OFF) 2154 { 2155 error_at (location, "ACLE function %qD cannot be called when" 2156 " SME streaming mode is enabled", fndecl); 2157 return false; 2158 } 2159 2160 if (missing_extensions & AARCH64_FL_SM_ON) 2161 { 2162 error_at (location, "ACLE function %qD can only be called when" 2163 " SME streaming mode is enabled", fndecl); 2164 return false; 2165 } 2166 2167 if (missing_extensions & AARCH64_FL_ZA_ON) 2168 { 2169 error_at (location, "ACLE function %qD can only be called from" 2170 " a function that has %qs state", fndecl, "za"); 2171 return false; 2172 } 2173 2174 static const struct { 2175 aarch64_feature_flags flag; 2176 const char *name; 2177 } extensions[] = { 2178 #define AARCH64_OPT_EXTENSION(EXT_NAME, IDENT, C, D, E, F) \ 2179 { AARCH64_FL_##IDENT, EXT_NAME }, 2180 #include "aarch64-option-extensions.def" 2181 }; 2182 2183 for (unsigned int i = 0; i < ARRAY_SIZE (extensions); ++i) 2184 if (missing_extensions & extensions[i].flag) 2185 { 2186 aarch64_report_missing_extension (location, fndecl, extensions[i].name); 2187 return false; 2188 } 2189 gcc_unreachable (); 2190 } 2191 2192 bool 2193 aarch64_general_check_builtin_call (location_t location, vec<location_t>, 2194 unsigned int code, tree fndecl, 2195 unsigned int nargs ATTRIBUTE_UNUSED, tree *args) 2196 { 2197 tree decl = aarch64_builtin_decls[code]; 2198 switch (code) 2199 { 2200 case AARCH64_RSR: 2201 case AARCH64_RSRP: 2202 case AARCH64_RSR64: 2203 case AARCH64_RSRF: 2204 case AARCH64_RSRF64: 2205 case AARCH64_WSR: 2206 case AARCH64_WSRP: 2207 case AARCH64_WSR64: 2208 case AARCH64_WSRF: 2209 case AARCH64_WSRF64: 2210 { 2211 tree addr = STRIP_NOPS (args[0]); 2212 if (TREE_CODE (TREE_TYPE (addr)) != POINTER_TYPE 2213 || TREE_CODE (addr) != ADDR_EXPR 2214 || TREE_CODE (TREE_OPERAND (addr, 0)) != STRING_CST) 2215 { 2216 error_at (location, 2217 "first argument to %qD must be a string literal", 2218 fndecl); 2219 return false; 2220 } 2221 break; 2222 } 2223 2224 case AARCH64_TME_BUILTIN_TSTART: 2225 case AARCH64_TME_BUILTIN_TCOMMIT: 2226 case AARCH64_TME_BUILTIN_TTEST: 2227 case AARCH64_TME_BUILTIN_TCANCEL: 2228 return aarch64_check_required_extensions (location, decl, 2229 AARCH64_FL_TME); 2230 2231 case AARCH64_LS64_BUILTIN_LD64B: 2232 case AARCH64_LS64_BUILTIN_ST64B: 2233 case AARCH64_LS64_BUILTIN_ST64BV: 2234 case AARCH64_LS64_BUILTIN_ST64BV0: 2235 return aarch64_check_required_extensions (location, decl, 2236 AARCH64_FL_LS64); 2237 2238 default: 2239 break; 2240 } 2241 2242 if (code >= AARCH64_MEMTAG_BUILTIN_START 2243 && code <= AARCH64_MEMTAG_BUILTIN_END) 2244 return aarch64_check_required_extensions (location, decl, 2245 AARCH64_FL_MEMTAG); 2246 2247 return true; 2248 } 2249 2250 typedef enum 2251 { 2252 SIMD_ARG_COPY_TO_REG, 2253 SIMD_ARG_CONSTANT, 2254 SIMD_ARG_LANE_INDEX, 2255 SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX, 2256 SIMD_ARG_LANE_PAIR_INDEX, 2257 SIMD_ARG_LANE_QUADTUP_INDEX, 2258 SIMD_ARG_STOP 2259 } builtin_simd_arg; 2260 2261 2262 static rtx 2263 aarch64_simd_expand_args (rtx target, int icode, int have_retval, 2264 tree exp, builtin_simd_arg *args, 2265 machine_mode builtin_mode) 2266 { 2267 rtx pat; 2268 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */ 2269 int opc = 0; 2270 2271 if (have_retval) 2272 { 2273 machine_mode tmode = insn_data[icode].operand[0].mode; 2274 if (!target 2275 || GET_MODE (target) != tmode 2276 || !(*insn_data[icode].operand[0].predicate) (target, tmode)) 2277 target = gen_reg_rtx (tmode); 2278 op[opc++] = target; 2279 } 2280 2281 for (;;) 2282 { 2283 builtin_simd_arg thisarg = args[opc - have_retval]; 2284 2285 if (thisarg == SIMD_ARG_STOP) 2286 break; 2287 else 2288 { 2289 tree arg = CALL_EXPR_ARG (exp, opc - have_retval); 2290 machine_mode mode = insn_data[icode].operand[opc].mode; 2291 op[opc] = expand_normal (arg); 2292 2293 switch (thisarg) 2294 { 2295 case SIMD_ARG_COPY_TO_REG: 2296 if (POINTER_TYPE_P (TREE_TYPE (arg))) 2297 op[opc] = convert_memory_address (Pmode, op[opc]); 2298 /*gcc_assert (GET_MODE (op[opc]) == mode); */ 2299 if (!(*insn_data[icode].operand[opc].predicate) 2300 (op[opc], mode)) 2301 op[opc] = copy_to_mode_reg (mode, op[opc]); 2302 break; 2303 2304 case SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX: 2305 gcc_assert (opc > 1); 2306 if (CONST_INT_P (op[opc])) 2307 { 2308 unsigned int nunits 2309 = GET_MODE_NUNITS (builtin_mode).to_constant (); 2310 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp); 2311 /* Keep to GCC-vector-extension lane indices in the RTL. */ 2312 op[opc] = aarch64_endian_lane_rtx (builtin_mode, 2313 INTVAL (op[opc])); 2314 } 2315 goto constant_arg; 2316 2317 case SIMD_ARG_LANE_INDEX: 2318 /* Must be a previous operand into which this is an index. */ 2319 gcc_assert (opc > 0); 2320 if (CONST_INT_P (op[opc])) 2321 { 2322 machine_mode vmode = insn_data[icode].operand[opc - 1].mode; 2323 unsigned int nunits 2324 = GET_MODE_NUNITS (vmode).to_constant (); 2325 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp); 2326 /* Keep to GCC-vector-extension lane indices in the RTL. */ 2327 op[opc] = aarch64_endian_lane_rtx (vmode, INTVAL (op[opc])); 2328 } 2329 /* If the lane index isn't a constant then error out. */ 2330 goto constant_arg; 2331 2332 case SIMD_ARG_LANE_PAIR_INDEX: 2333 /* Must be a previous operand into which this is an index and 2334 index is restricted to nunits / 2. */ 2335 gcc_assert (opc > 0); 2336 if (CONST_INT_P (op[opc])) 2337 { 2338 machine_mode vmode = insn_data[icode].operand[opc - 1].mode; 2339 unsigned int nunits 2340 = GET_MODE_NUNITS (vmode).to_constant (); 2341 aarch64_simd_lane_bounds (op[opc], 0, nunits / 2, exp); 2342 /* Keep to GCC-vector-extension lane indices in the RTL. */ 2343 int lane = INTVAL (op[opc]); 2344 op[opc] = gen_int_mode (ENDIAN_LANE_N (nunits / 2, lane), 2345 SImode); 2346 } 2347 /* If the lane index isn't a constant then error out. */ 2348 goto constant_arg; 2349 case SIMD_ARG_LANE_QUADTUP_INDEX: 2350 /* Must be a previous operand into which this is an index and 2351 index is restricted to nunits / 4. */ 2352 gcc_assert (opc > 0); 2353 if (CONST_INT_P (op[opc])) 2354 { 2355 machine_mode vmode = insn_data[icode].operand[opc - 1].mode; 2356 unsigned int nunits 2357 = GET_MODE_NUNITS (vmode).to_constant (); 2358 aarch64_simd_lane_bounds (op[opc], 0, nunits / 4, exp); 2359 /* Keep to GCC-vector-extension lane indices in the RTL. */ 2360 int lane = INTVAL (op[opc]); 2361 op[opc] = gen_int_mode (ENDIAN_LANE_N (nunits / 4, lane), 2362 SImode); 2363 } 2364 /* If the lane index isn't a constant then error out. */ 2365 goto constant_arg; 2366 case SIMD_ARG_CONSTANT: 2367 constant_arg: 2368 if (!(*insn_data[icode].operand[opc].predicate) 2369 (op[opc], mode)) 2370 { 2371 error_at (EXPR_LOCATION (exp), 2372 "argument %d must be a constant immediate", 2373 opc + 1 - have_retval); 2374 return const0_rtx; 2375 } 2376 break; 2377 2378 case SIMD_ARG_STOP: 2379 gcc_unreachable (); 2380 } 2381 2382 opc++; 2383 } 2384 } 2385 2386 switch (opc) 2387 { 2388 case 1: 2389 pat = GEN_FCN (icode) (op[0]); 2390 break; 2391 2392 case 2: 2393 pat = GEN_FCN (icode) (op[0], op[1]); 2394 break; 2395 2396 case 3: 2397 pat = GEN_FCN (icode) (op[0], op[1], op[2]); 2398 break; 2399 2400 case 4: 2401 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); 2402 break; 2403 2404 case 5: 2405 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]); 2406 break; 2407 2408 case 6: 2409 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]); 2410 break; 2411 2412 default: 2413 gcc_unreachable (); 2414 } 2415 2416 if (!pat) 2417 return NULL_RTX; 2418 2419 emit_insn (pat); 2420 2421 return target; 2422 } 2423 2424 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */ 2425 rtx 2426 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target) 2427 { 2428 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK) 2429 { 2430 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0)); 2431 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1)); 2432 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize) 2433 && UINTVAL (elementsize) != 0 2434 && UINTVAL (totalsize) != 0) 2435 { 2436 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2)); 2437 if (CONST_INT_P (lane_idx)) 2438 aarch64_simd_lane_bounds (lane_idx, 0, 2439 UINTVAL (totalsize) 2440 / UINTVAL (elementsize), 2441 exp); 2442 else 2443 error_at (EXPR_LOCATION (exp), 2444 "lane index must be a constant immediate"); 2445 } 2446 else 2447 error_at (EXPR_LOCATION (exp), 2448 "total size and element size must be a nonzero " 2449 "constant immediate"); 2450 /* Don't generate any RTL. */ 2451 return const0_rtx; 2452 } 2453 aarch64_simd_builtin_datum *d = 2454 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START]; 2455 enum insn_code icode = d->code; 2456 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1]; 2457 int num_args = insn_data[d->code].n_operands; 2458 int is_void = 0; 2459 int k; 2460 2461 is_void = !!(d->qualifiers[0] & qualifier_void); 2462 2463 num_args += is_void; 2464 2465 for (k = 1; k < num_args; k++) 2466 { 2467 /* We have four arrays of data, each indexed in a different fashion. 2468 qualifiers - element 0 always describes the function return type. 2469 operands - element 0 is either the operand for return value (if 2470 the function has a non-void return type) or the operand for the 2471 first argument. 2472 expr_args - element 0 always holds the first argument. 2473 args - element 0 is always used for the return type. */ 2474 int qualifiers_k = k; 2475 int operands_k = k - is_void; 2476 int expr_args_k = k - 1; 2477 2478 if (d->qualifiers[qualifiers_k] & qualifier_lane_index) 2479 args[k] = SIMD_ARG_LANE_INDEX; 2480 else if (d->qualifiers[qualifiers_k] & qualifier_lane_pair_index) 2481 args[k] = SIMD_ARG_LANE_PAIR_INDEX; 2482 else if (d->qualifiers[qualifiers_k] & qualifier_lane_quadtup_index) 2483 args[k] = SIMD_ARG_LANE_QUADTUP_INDEX; 2484 else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index) 2485 args[k] = SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX; 2486 else if (d->qualifiers[qualifiers_k] & qualifier_immediate) 2487 args[k] = SIMD_ARG_CONSTANT; 2488 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate) 2489 { 2490 rtx arg 2491 = expand_normal (CALL_EXPR_ARG (exp, 2492 (expr_args_k))); 2493 /* Handle constants only if the predicate allows it. */ 2494 bool op_const_int_p = 2495 (CONST_INT_P (arg) 2496 && (*insn_data[icode].operand[operands_k].predicate) 2497 (arg, insn_data[icode].operand[operands_k].mode)); 2498 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG; 2499 } 2500 else 2501 args[k] = SIMD_ARG_COPY_TO_REG; 2502 2503 } 2504 args[k] = SIMD_ARG_STOP; 2505 2506 /* The interface to aarch64_simd_expand_args expects a 0 if 2507 the function is void, and a 1 if it is not. */ 2508 return aarch64_simd_expand_args 2509 (target, icode, !is_void, exp, &args[1], d->mode); 2510 } 2511 2512 rtx 2513 aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target) 2514 { 2515 rtx pat; 2516 aarch64_crc_builtin_datum *d 2517 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)]; 2518 enum insn_code icode = d->icode; 2519 tree arg0 = CALL_EXPR_ARG (exp, 0); 2520 tree arg1 = CALL_EXPR_ARG (exp, 1); 2521 rtx op0 = expand_normal (arg0); 2522 rtx op1 = expand_normal (arg1); 2523 machine_mode tmode = insn_data[icode].operand[0].mode; 2524 machine_mode mode0 = insn_data[icode].operand[1].mode; 2525 machine_mode mode1 = insn_data[icode].operand[2].mode; 2526 2527 if (! target 2528 || GET_MODE (target) != tmode 2529 || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) 2530 target = gen_reg_rtx (tmode); 2531 2532 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode) 2533 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode)); 2534 2535 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) 2536 op0 = copy_to_mode_reg (mode0, op0); 2537 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) 2538 op1 = copy_to_mode_reg (mode1, op1); 2539 2540 pat = GEN_FCN (icode) (target, op0, op1); 2541 if (!pat) 2542 return NULL_RTX; 2543 2544 emit_insn (pat); 2545 return target; 2546 } 2547 2548 /* Function to expand reciprocal square root builtins. */ 2549 2550 static rtx 2551 aarch64_expand_builtin_rsqrt (int fcode, tree exp, rtx target) 2552 { 2553 tree arg0 = CALL_EXPR_ARG (exp, 0); 2554 rtx op0 = expand_normal (arg0); 2555 2556 rtx (*gen) (rtx, rtx); 2557 2558 switch (fcode) 2559 { 2560 case AARCH64_BUILTIN_RSQRT_DF: 2561 gen = gen_rsqrtdf2; 2562 break; 2563 case AARCH64_BUILTIN_RSQRT_SF: 2564 gen = gen_rsqrtsf2; 2565 break; 2566 case AARCH64_BUILTIN_RSQRT_V2DF: 2567 gen = gen_rsqrtv2df2; 2568 break; 2569 case AARCH64_BUILTIN_RSQRT_V2SF: 2570 gen = gen_rsqrtv2sf2; 2571 break; 2572 case AARCH64_BUILTIN_RSQRT_V4SF: 2573 gen = gen_rsqrtv4sf2; 2574 break; 2575 default: gcc_unreachable (); 2576 } 2577 2578 if (!target) 2579 target = gen_reg_rtx (GET_MODE (op0)); 2580 2581 emit_insn (gen (target, op0)); 2582 2583 return target; 2584 } 2585 2586 /* Expand a FCMLA lane expression EXP with code FCODE and 2587 result going to TARGET if that is convenient. */ 2588 2589 rtx 2590 aarch64_expand_fcmla_builtin (tree exp, rtx target, int fcode) 2591 { 2592 int bcode = fcode - AARCH64_SIMD_FCMLA_LANEQ_BUILTIN_BASE - 1; 2593 aarch64_fcmla_laneq_builtin_datum* d 2594 = &aarch64_fcmla_lane_builtin_data[bcode]; 2595 machine_mode quadmode = GET_MODE_2XWIDER_MODE (d->mode).require (); 2596 rtx op0 = force_reg (d->mode, expand_normal (CALL_EXPR_ARG (exp, 0))); 2597 rtx op1 = force_reg (d->mode, expand_normal (CALL_EXPR_ARG (exp, 1))); 2598 rtx op2 = force_reg (quadmode, expand_normal (CALL_EXPR_ARG (exp, 2))); 2599 tree tmp = CALL_EXPR_ARG (exp, 3); 2600 rtx lane_idx = expand_expr (tmp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); 2601 2602 /* Validate that the lane index is a constant. */ 2603 if (!CONST_INT_P (lane_idx)) 2604 { 2605 error_at (EXPR_LOCATION (exp), 2606 "argument %d must be a constant immediate", 4); 2607 return const0_rtx; 2608 } 2609 2610 /* Validate that the index is within the expected range. */ 2611 int nunits = GET_MODE_NUNITS (quadmode).to_constant (); 2612 aarch64_simd_lane_bounds (lane_idx, 0, nunits / 2, exp); 2613 2614 /* Generate the correct register and mode. */ 2615 int lane = INTVAL (lane_idx); 2616 2617 if (lane < nunits / 4) 2618 op2 = simplify_gen_subreg (d->mode, op2, quadmode, 2619 subreg_lowpart_offset (d->mode, quadmode)); 2620 else 2621 { 2622 /* Select the upper 64 bits, either a V2SF or V4HF, this however 2623 is quite messy, as the operation required even though simple 2624 doesn't have a simple RTL pattern, and seems it's quite hard to 2625 define using a single RTL pattern. The target generic version 2626 gen_highpart_mode generates code that isn't optimal. */ 2627 rtx temp1 = gen_reg_rtx (d->mode); 2628 rtx temp2 = gen_reg_rtx (DImode); 2629 temp1 = simplify_gen_subreg (d->mode, op2, quadmode, 2630 subreg_lowpart_offset (d->mode, quadmode)); 2631 temp1 = simplify_gen_subreg (V2DImode, temp1, d->mode, 0); 2632 if (BYTES_BIG_ENDIAN) 2633 emit_insn (gen_aarch64_get_lanev2di (temp2, temp1, const0_rtx)); 2634 else 2635 emit_insn (gen_aarch64_get_lanev2di (temp2, temp1, const1_rtx)); 2636 op2 = simplify_gen_subreg (d->mode, temp2, GET_MODE (temp2), 0); 2637 2638 /* And recalculate the index. */ 2639 lane -= nunits / 4; 2640 } 2641 2642 /* Keep to GCC-vector-extension lane indices in the RTL, only nunits / 4 2643 (max nunits in range check) are valid. Which means only 0-1, so we 2644 only need to know the order in a V2mode. */ 2645 lane_idx = aarch64_endian_lane_rtx (V2DImode, lane); 2646 2647 if (!target 2648 || !REG_P (target) 2649 || GET_MODE (target) != d->mode) 2650 target = gen_reg_rtx (d->mode); 2651 2652 rtx pat = NULL_RTX; 2653 2654 if (d->lane) 2655 pat = GEN_FCN (d->icode) (target, op0, op1, op2, lane_idx); 2656 else 2657 pat = GEN_FCN (d->icode) (target, op0, op1, op2); 2658 2659 if (!pat) 2660 return NULL_RTX; 2661 2662 emit_insn (pat); 2663 return target; 2664 } 2665 2666 /* Function to expand an expression EXP which calls one of the Transactional 2667 Memory Extension (TME) builtins FCODE with the result going to TARGET. */ 2668 static rtx 2669 aarch64_expand_builtin_tme (int fcode, tree exp, rtx target) 2670 { 2671 switch (fcode) 2672 { 2673 case AARCH64_TME_BUILTIN_TSTART: 2674 target = gen_reg_rtx (DImode); 2675 emit_insn (GEN_FCN (CODE_FOR_tstart) (target)); 2676 break; 2677 2678 case AARCH64_TME_BUILTIN_TTEST: 2679 target = gen_reg_rtx (DImode); 2680 emit_insn (GEN_FCN (CODE_FOR_ttest) (target)); 2681 break; 2682 2683 case AARCH64_TME_BUILTIN_TCOMMIT: 2684 emit_insn (GEN_FCN (CODE_FOR_tcommit) ()); 2685 break; 2686 2687 case AARCH64_TME_BUILTIN_TCANCEL: 2688 { 2689 tree arg0 = CALL_EXPR_ARG (exp, 0); 2690 rtx op0 = expand_normal (arg0); 2691 if (CONST_INT_P (op0) && UINTVAL (op0) <= 65536) 2692 emit_insn (GEN_FCN (CODE_FOR_tcancel) (op0)); 2693 else 2694 { 2695 error_at (EXPR_LOCATION (exp), 2696 "argument must be a 16-bit constant immediate"); 2697 return const0_rtx; 2698 } 2699 } 2700 break; 2701 2702 default : 2703 gcc_unreachable (); 2704 } 2705 return target; 2706 } 2707 2708 /* Function to expand an expression EXP which calls one of the Load/Store 2709 64 Byte extension (LS64) builtins FCODE with the result going to TARGET. */ 2710 static rtx 2711 aarch64_expand_builtin_ls64 (int fcode, tree exp, rtx target) 2712 { 2713 expand_operand ops[3]; 2714 2715 switch (fcode) 2716 { 2717 case AARCH64_LS64_BUILTIN_LD64B: 2718 { 2719 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); 2720 create_output_operand (&ops[0], target, V8DImode); 2721 create_input_operand (&ops[1], op0, DImode); 2722 expand_insn (CODE_FOR_ld64b, 2, ops); 2723 return ops[0].value; 2724 } 2725 case AARCH64_LS64_BUILTIN_ST64B: 2726 { 2727 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); 2728 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); 2729 create_input_operand (&ops[0], op0, DImode); 2730 create_input_operand (&ops[1], op1, V8DImode); 2731 expand_insn (CODE_FOR_st64b, 2, ops); 2732 return const0_rtx; 2733 } 2734 case AARCH64_LS64_BUILTIN_ST64BV: 2735 { 2736 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); 2737 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); 2738 create_output_operand (&ops[0], target, DImode); 2739 create_input_operand (&ops[1], op0, DImode); 2740 create_input_operand (&ops[2], op1, V8DImode); 2741 expand_insn (CODE_FOR_st64bv, 3, ops); 2742 return ops[0].value; 2743 } 2744 case AARCH64_LS64_BUILTIN_ST64BV0: 2745 { 2746 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); 2747 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); 2748 create_output_operand (&ops[0], target, DImode); 2749 create_input_operand (&ops[1], op0, DImode); 2750 create_input_operand (&ops[2], op1, V8DImode); 2751 expand_insn (CODE_FOR_st64bv0, 3, ops); 2752 return ops[0].value; 2753 } 2754 } 2755 2756 gcc_unreachable (); 2757 } 2758 2759 /* Expand a random number builtin EXP with code FCODE, putting the result 2760 int TARGET. If IGNORE is true the return value is ignored. */ 2761 2762 rtx 2763 aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore) 2764 { 2765 rtx pat; 2766 enum insn_code icode; 2767 if (fcode == AARCH64_BUILTIN_RNG_RNDR) 2768 icode = CODE_FOR_aarch64_rndr; 2769 else if (fcode == AARCH64_BUILTIN_RNG_RNDRRS) 2770 icode = CODE_FOR_aarch64_rndrrs; 2771 else 2772 gcc_unreachable (); 2773 2774 rtx rand = gen_reg_rtx (DImode); 2775 pat = GEN_FCN (icode) (rand); 2776 if (!pat) 2777 return NULL_RTX; 2778 2779 tree arg0 = CALL_EXPR_ARG (exp, 0); 2780 rtx res_addr = expand_normal (arg0); 2781 res_addr = convert_memory_address (Pmode, res_addr); 2782 rtx res_mem = gen_rtx_MEM (DImode, res_addr); 2783 emit_insn (pat); 2784 emit_move_insn (res_mem, rand); 2785 /* If the status result is unused don't generate the CSET code. */ 2786 if (ignore) 2787 return target; 2788 2789 rtx cc_reg = gen_rtx_REG (CC_Zmode, CC_REGNUM); 2790 rtx cmp_rtx = gen_rtx_fmt_ee (EQ, SImode, cc_reg, const0_rtx); 2791 emit_insn (gen_aarch64_cstoresi (target, cmp_rtx, cc_reg)); 2792 return target; 2793 } 2794 2795 /* Expand the read/write system register builtin EXPs. */ 2796 rtx 2797 aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode) 2798 { 2799 tree arg0, arg1; 2800 rtx const_str, input_val, subreg; 2801 enum machine_mode mode; 2802 enum insn_code icode; 2803 class expand_operand ops[2]; 2804 2805 arg0 = CALL_EXPR_ARG (exp, 0); 2806 2807 bool write_op = (fcode == AARCH64_WSR 2808 || fcode == AARCH64_WSRP 2809 || fcode == AARCH64_WSR64 2810 || fcode == AARCH64_WSRF 2811 || fcode == AARCH64_WSRF64 2812 || fcode == AARCH64_WSR128); 2813 2814 bool op128 = (fcode == AARCH64_RSR128 || fcode == AARCH64_WSR128); 2815 enum machine_mode sysreg_mode = op128 ? TImode : DImode; 2816 2817 if (op128 && !TARGET_D128) 2818 { 2819 error_at (EXPR_LOCATION (exp), "128-bit system register support requires" 2820 " the %<d128%> extension"); 2821 return const0_rtx; 2822 } 2823 2824 /* Argument 0 (system register name) must be a string literal. */ 2825 gcc_assert (TREE_CODE (arg0) == ADDR_EXPR 2826 && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE 2827 && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST); 2828 2829 const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0)); 2830 2831 tree len_tree = c_strlen (arg0, 1); 2832 if (len_tree == NULL_TREE) 2833 { 2834 error_at (EXPR_LOCATION (exp), "invalid system register name provided"); 2835 return const0_rtx; 2836 } 2837 2838 size_t len = TREE_INT_CST_LOW (len_tree); 2839 char *sysreg_name = xstrdup (name_input); 2840 2841 for (unsigned pos = 0; pos <= len; pos++) 2842 sysreg_name[pos] = TOLOWER (sysreg_name[pos]); 2843 2844 const char* name_output = aarch64_retrieve_sysreg ((const char *) sysreg_name, 2845 write_op, op128); 2846 if (name_output == NULL) 2847 { 2848 error_at (EXPR_LOCATION (exp), "invalid system register name %qs", 2849 sysreg_name); 2850 return const0_rtx; 2851 } 2852 2853 /* Assign the string corresponding to the system register name to an RTX. */ 2854 const_str = rtx_alloc (CONST_STRING); 2855 PUT_CODE (const_str, CONST_STRING); 2856 XSTR (const_str, 0) = ggc_strdup (name_output); 2857 2858 /* Set up expander operands and call instruction expansion. */ 2859 if (write_op) 2860 { 2861 arg1 = CALL_EXPR_ARG (exp, 1); 2862 mode = TYPE_MODE (TREE_TYPE (arg1)); 2863 input_val = copy_to_mode_reg (mode, expand_normal (arg1)); 2864 2865 icode = (op128 ? CODE_FOR_aarch64_write_sysregti 2866 : CODE_FOR_aarch64_write_sysregdi); 2867 2868 switch (fcode) 2869 { 2870 case AARCH64_WSR: 2871 case AARCH64_WSRP: 2872 case AARCH64_WSR64: 2873 case AARCH64_WSRF64: 2874 case AARCH64_WSR128: 2875 subreg = lowpart_subreg (sysreg_mode, input_val, mode); 2876 break; 2877 case AARCH64_WSRF: 2878 subreg = gen_lowpart_SUBREG (SImode, input_val); 2879 subreg = gen_lowpart_SUBREG (DImode, subreg); 2880 break; 2881 } 2882 2883 create_fixed_operand (&ops[0], const_str); 2884 create_input_operand (&ops[1], subreg, sysreg_mode); 2885 expand_insn (icode, 2, ops); 2886 2887 return target; 2888 } 2889 2890 /* Read operations are implied by !write_op. */ 2891 gcc_assert (call_expr_nargs (exp) == 1); 2892 2893 icode = (op128 ? CODE_FOR_aarch64_read_sysregti 2894 : CODE_FOR_aarch64_read_sysregdi); 2895 2896 /* Emit the initial read_sysregdi rtx. */ 2897 create_output_operand (&ops[0], target, sysreg_mode); 2898 create_fixed_operand (&ops[1], const_str); 2899 expand_insn (icode, 2, ops); 2900 target = ops[0].value; 2901 2902 /* Do any necessary post-processing on the result. */ 2903 switch (fcode) 2904 { 2905 case AARCH64_RSR: 2906 case AARCH64_RSRP: 2907 case AARCH64_RSR64: 2908 case AARCH64_RSRF64: 2909 case AARCH64_RSR128: 2910 return lowpart_subreg (TYPE_MODE (TREE_TYPE (exp)), target, sysreg_mode); 2911 case AARCH64_RSRF: 2912 subreg = gen_lowpart_SUBREG (SImode, target); 2913 return gen_lowpart_SUBREG (SFmode, subreg); 2914 default: 2915 gcc_unreachable (); 2916 } 2917 } 2918 2919 /* Ensure argument ARGNO in EXP represents a const-type argument in the range 2920 [MINVAL, MAXVAL). */ 2921 static HOST_WIDE_INT 2922 require_const_argument (tree exp, unsigned int argno, HOST_WIDE_INT minval, 2923 HOST_WIDE_INT maxval) 2924 { 2925 maxval--; 2926 tree arg = CALL_EXPR_ARG (exp, argno); 2927 if (TREE_CODE (arg) != INTEGER_CST) 2928 error_at (EXPR_LOCATION (exp), "Constant-type argument expected"); 2929 2930 auto argval = wi::to_widest (arg); 2931 2932 if (argval < minval || argval > maxval) 2933 error_at (EXPR_LOCATION (exp), 2934 "argument %d must be a constant immediate " 2935 "in range [%wd,%wd]", argno + 1, minval, maxval); 2936 2937 HOST_WIDE_INT retval = argval.to_shwi (); 2938 return retval; 2939 } 2940 2941 2942 /* Expand a prefetch builtin EXP. */ 2943 void 2944 aarch64_expand_prefetch_builtin (tree exp, int fcode) 2945 { 2946 int kind_id = -1; 2947 int level_id = -1; 2948 int rettn_id = -1; 2949 char prfop[11]; 2950 class expand_operand ops[2]; 2951 2952 static const char *kind_s[] = {"PLD", "PST", "PLI"}; 2953 static const char *level_s[] = {"L1", "L2", "L3", "SLC"}; 2954 static const char *rettn_s[] = {"KEEP", "STRM"}; 2955 2956 /* Each of the four prefetch builtins takes a different number of arguments, 2957 but proceeds to call the PRFM insn which requires 4 pieces of information 2958 to be fully defined. Where one of these takes less than 4 arguments, set 2959 sensible defaults. */ 2960 switch (fcode) 2961 { 2962 case AARCH64_PLDX: 2963 break; 2964 case AARCH64_PLIX: 2965 kind_id = 2; 2966 break; 2967 case AARCH64_PLI: 2968 case AARCH64_PLD: 2969 kind_id = (fcode == AARCH64_PLD) ? 0 : 2; 2970 level_id = 0; 2971 rettn_id = 0; 2972 break; 2973 default: 2974 gcc_unreachable (); 2975 } 2976 2977 /* Any -1 id variable is to be user-supplied. Here we fill these in and run 2978 bounds checks on them. "PLI" is used only implicitly by AARCH64_PLI & 2979 AARCH64_PLIX, never explicitly. */ 2980 int argno = 0; 2981 if (kind_id < 0) 2982 kind_id = require_const_argument (exp, argno++, 0, ARRAY_SIZE (kind_s) - 1); 2983 if (level_id < 0) 2984 level_id = require_const_argument (exp, argno++, 0, ARRAY_SIZE (level_s)); 2985 if (rettn_id < 0) 2986 rettn_id = require_const_argument (exp, argno++, 0, ARRAY_SIZE (rettn_s)); 2987 rtx address = expand_expr (CALL_EXPR_ARG (exp, argno), NULL_RTX, Pmode, 2988 EXPAND_NORMAL); 2989 2990 if (seen_error ()) 2991 return; 2992 2993 sprintf (prfop, "%s%s%s", kind_s[kind_id], 2994 level_s[level_id], 2995 rettn_s[rettn_id]); 2996 2997 rtx const_str = rtx_alloc (CONST_STRING); 2998 PUT_CODE (const_str, CONST_STRING); 2999 XSTR (const_str, 0) = ggc_strdup (prfop); 3000 3001 create_fixed_operand (&ops[0], const_str); 3002 create_address_operand (&ops[1], address); 3003 maybe_expand_insn (CODE_FOR_aarch64_pldx, 2, ops); 3004 } 3005 3006 /* Expand an expression EXP that calls a MEMTAG built-in FCODE 3007 with result going to TARGET. */ 3008 static rtx 3009 aarch64_expand_builtin_memtag (int fcode, tree exp, rtx target) 3010 { 3011 if (TARGET_ILP32) 3012 { 3013 error ("Memory Tagging Extension does not support %<-mabi=ilp32%>"); 3014 return const0_rtx; 3015 } 3016 3017 rtx pat = NULL; 3018 enum insn_code icode = aarch64_memtag_builtin_data[fcode - 3019 AARCH64_MEMTAG_BUILTIN_START - 1].icode; 3020 3021 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); 3022 machine_mode mode0 = GET_MODE (op0); 3023 op0 = force_reg (mode0 == VOIDmode ? DImode : mode0, op0); 3024 op0 = convert_to_mode (DImode, op0, true); 3025 3026 switch (fcode) 3027 { 3028 case AARCH64_MEMTAG_BUILTIN_IRG: 3029 case AARCH64_MEMTAG_BUILTIN_GMI: 3030 case AARCH64_MEMTAG_BUILTIN_SUBP: 3031 case AARCH64_MEMTAG_BUILTIN_INC_TAG: 3032 { 3033 if (! target 3034 || GET_MODE (target) != DImode 3035 || ! (*insn_data[icode].operand[0].predicate) (target, DImode)) 3036 target = gen_reg_rtx (DImode); 3037 3038 if (fcode == AARCH64_MEMTAG_BUILTIN_INC_TAG) 3039 { 3040 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); 3041 3042 if ((*insn_data[icode].operand[3].predicate) (op1, QImode)) 3043 { 3044 pat = GEN_FCN (icode) (target, op0, const0_rtx, op1); 3045 break; 3046 } 3047 error_at (EXPR_LOCATION (exp), 3048 "argument %d must be a constant immediate " 3049 "in range [0,15]", 2); 3050 return const0_rtx; 3051 } 3052 else 3053 { 3054 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1)); 3055 machine_mode mode1 = GET_MODE (op1); 3056 op1 = force_reg (mode1 == VOIDmode ? DImode : mode1, op1); 3057 op1 = convert_to_mode (DImode, op1, true); 3058 pat = GEN_FCN (icode) (target, op0, op1); 3059 } 3060 break; 3061 } 3062 case AARCH64_MEMTAG_BUILTIN_GET_TAG: 3063 target = op0; 3064 pat = GEN_FCN (icode) (target, op0, const0_rtx); 3065 break; 3066 case AARCH64_MEMTAG_BUILTIN_SET_TAG: 3067 pat = GEN_FCN (icode) (op0, op0, const0_rtx); 3068 break; 3069 default: 3070 gcc_unreachable(); 3071 } 3072 3073 if (!pat) 3074 return NULL_RTX; 3075 3076 emit_insn (pat); 3077 return target; 3078 } 3079 3080 /* Function to expand an expression EXP which calls one of the ACLE Data 3081 Intrinsic builtins FCODE with the result going to TARGET. */ 3082 static rtx 3083 aarch64_expand_builtin_data_intrinsic (unsigned int fcode, tree exp, rtx target) 3084 { 3085 expand_operand ops[2]; 3086 machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); 3087 create_output_operand (&ops[0], target, mode); 3088 create_input_operand (&ops[1], expand_normal (CALL_EXPR_ARG (exp, 0)), mode); 3089 enum insn_code icode; 3090 3091 switch (fcode) 3092 { 3093 case AARCH64_REV16: 3094 case AARCH64_REV16L: 3095 case AARCH64_REV16LL: 3096 icode = code_for_aarch64_rev16 (mode); 3097 break; 3098 case AARCH64_RBIT: 3099 case AARCH64_RBITL: 3100 case AARCH64_RBITLL: 3101 icode = code_for_aarch64_rbit (mode); 3102 break; 3103 default: 3104 gcc_unreachable (); 3105 } 3106 3107 expand_insn (icode, 2, ops); 3108 return ops[0].value; 3109 } 3110 3111 /* Expand an expression EXP as fpsr or fpcr setter (depending on 3112 UNSPEC) using MODE. */ 3113 static void 3114 aarch64_expand_fpsr_fpcr_setter (int unspec, machine_mode mode, tree exp) 3115 { 3116 tree arg = CALL_EXPR_ARG (exp, 0); 3117 rtx op = force_reg (mode, expand_normal (arg)); 3118 emit_insn (gen_aarch64_set (unspec, mode, op)); 3119 } 3120 3121 /* Expand a fpsr or fpcr getter (depending on UNSPEC) using MODE. 3122 Return the target. */ 3123 static rtx 3124 aarch64_expand_fpsr_fpcr_getter (enum insn_code icode, machine_mode mode, 3125 rtx target) 3126 { 3127 expand_operand op; 3128 create_output_operand (&op, target, mode); 3129 expand_insn (icode, 1, &op); 3130 return op.value; 3131 } 3132 3133 /* Expand an expression EXP that calls built-in function FCODE, 3134 with result going to TARGET if that's convenient. IGNORE is true 3135 if the result of the builtin is ignored. */ 3136 rtx 3137 aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target, 3138 int ignore) 3139 { 3140 int icode; 3141 rtx op0; 3142 tree arg0; 3143 3144 switch (fcode) 3145 { 3146 case AARCH64_BUILTIN_GET_FPCR: 3147 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpcrsi, 3148 SImode, target); 3149 case AARCH64_BUILTIN_SET_FPCR: 3150 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPCR, SImode, exp); 3151 return target; 3152 case AARCH64_BUILTIN_GET_FPSR: 3153 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpsrsi, 3154 SImode, target); 3155 case AARCH64_BUILTIN_SET_FPSR: 3156 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPSR, SImode, exp); 3157 return target; 3158 case AARCH64_BUILTIN_GET_FPCR64: 3159 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpcrdi, 3160 DImode, target); 3161 case AARCH64_BUILTIN_SET_FPCR64: 3162 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPCR, DImode, exp); 3163 return target; 3164 case AARCH64_BUILTIN_GET_FPSR64: 3165 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpsrdi, 3166 DImode, target); 3167 case AARCH64_BUILTIN_SET_FPSR64: 3168 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPSR, DImode, exp); 3169 return target; 3170 case AARCH64_PAUTH_BUILTIN_AUTIA1716: 3171 case AARCH64_PAUTH_BUILTIN_PACIA1716: 3172 case AARCH64_PAUTH_BUILTIN_AUTIB1716: 3173 case AARCH64_PAUTH_BUILTIN_PACIB1716: 3174 case AARCH64_PAUTH_BUILTIN_XPACLRI: 3175 arg0 = CALL_EXPR_ARG (exp, 0); 3176 op0 = force_reg (Pmode, expand_normal (arg0)); 3177 3178 if (fcode == AARCH64_PAUTH_BUILTIN_XPACLRI) 3179 { 3180 rtx lr = gen_rtx_REG (Pmode, R30_REGNUM); 3181 icode = CODE_FOR_xpaclri; 3182 emit_move_insn (lr, op0); 3183 emit_insn (GEN_FCN (icode) ()); 3184 return lr; 3185 } 3186 else 3187 { 3188 tree arg1 = CALL_EXPR_ARG (exp, 1); 3189 rtx op1 = force_reg (Pmode, expand_normal (arg1)); 3190 switch (fcode) 3191 { 3192 case AARCH64_PAUTH_BUILTIN_AUTIA1716: 3193 icode = CODE_FOR_autia1716; 3194 break; 3195 case AARCH64_PAUTH_BUILTIN_AUTIB1716: 3196 icode = CODE_FOR_autib1716; 3197 break; 3198 case AARCH64_PAUTH_BUILTIN_PACIA1716: 3199 icode = CODE_FOR_pacia1716; 3200 break; 3201 case AARCH64_PAUTH_BUILTIN_PACIB1716: 3202 icode = CODE_FOR_pacib1716; 3203 break; 3204 default: 3205 icode = 0; 3206 gcc_unreachable (); 3207 } 3208 3209 rtx x16_reg = gen_rtx_REG (Pmode, R16_REGNUM); 3210 rtx x17_reg = gen_rtx_REG (Pmode, R17_REGNUM); 3211 emit_move_insn (x17_reg, op0); 3212 emit_move_insn (x16_reg, op1); 3213 emit_insn (GEN_FCN (icode) ()); 3214 return x17_reg; 3215 } 3216 3217 case AARCH64_JSCVT: 3218 { 3219 expand_operand ops[2]; 3220 create_output_operand (&ops[0], target, SImode); 3221 op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); 3222 create_input_operand (&ops[1], op0, DFmode); 3223 expand_insn (CODE_FOR_aarch64_fjcvtzs, 2, ops); 3224 return ops[0].value; 3225 } 3226 3227 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ0_V2SF: 3228 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ90_V2SF: 3229 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V2SF: 3230 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V2SF: 3231 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ0_V4HF: 3232 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ90_V4HF: 3233 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V4HF: 3234 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V4HF: 3235 return aarch64_expand_fcmla_builtin (exp, target, fcode); 3236 case AARCH64_BUILTIN_RNG_RNDR: 3237 case AARCH64_BUILTIN_RNG_RNDRRS: 3238 return aarch64_expand_rng_builtin (exp, target, fcode, ignore); 3239 case AARCH64_RSR: 3240 case AARCH64_RSRP: 3241 case AARCH64_RSR64: 3242 case AARCH64_RSRF: 3243 case AARCH64_RSRF64: 3244 case AARCH64_RSR128: 3245 case AARCH64_WSR: 3246 case AARCH64_WSRP: 3247 case AARCH64_WSR64: 3248 case AARCH64_WSRF: 3249 case AARCH64_WSRF64: 3250 case AARCH64_WSR128: 3251 return aarch64_expand_rwsr_builtin (exp, target, fcode); 3252 case AARCH64_PLD: 3253 case AARCH64_PLDX: 3254 case AARCH64_PLI: 3255 case AARCH64_PLIX: 3256 aarch64_expand_prefetch_builtin (exp, fcode); 3257 return target; 3258 } 3259 3260 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX) 3261 return aarch64_simd_expand_builtin (fcode, exp, target); 3262 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX) 3263 return aarch64_crc32_expand_builtin (fcode, exp, target); 3264 3265 if (fcode == AARCH64_BUILTIN_RSQRT_DF 3266 || fcode == AARCH64_BUILTIN_RSQRT_SF 3267 || fcode == AARCH64_BUILTIN_RSQRT_V2DF 3268 || fcode == AARCH64_BUILTIN_RSQRT_V2SF 3269 || fcode == AARCH64_BUILTIN_RSQRT_V4SF) 3270 return aarch64_expand_builtin_rsqrt (fcode, exp, target); 3271 3272 if (fcode == AARCH64_TME_BUILTIN_TSTART 3273 || fcode == AARCH64_TME_BUILTIN_TCOMMIT 3274 || fcode == AARCH64_TME_BUILTIN_TTEST 3275 || fcode == AARCH64_TME_BUILTIN_TCANCEL) 3276 return aarch64_expand_builtin_tme (fcode, exp, target); 3277 3278 if (fcode == AARCH64_LS64_BUILTIN_LD64B 3279 || fcode == AARCH64_LS64_BUILTIN_ST64B 3280 || fcode == AARCH64_LS64_BUILTIN_ST64BV 3281 || fcode == AARCH64_LS64_BUILTIN_ST64BV0) 3282 return aarch64_expand_builtin_ls64 (fcode, exp, target); 3283 3284 if (fcode >= AARCH64_MEMTAG_BUILTIN_START 3285 && fcode <= AARCH64_MEMTAG_BUILTIN_END) 3286 return aarch64_expand_builtin_memtag (fcode, exp, target); 3287 if (fcode >= AARCH64_REV16 3288 && fcode <= AARCH64_RBITLL) 3289 return aarch64_expand_builtin_data_intrinsic (fcode, exp, target); 3290 3291 gcc_unreachable (); 3292 } 3293 3294 /* Return builtin for reciprocal square root. */ 3295 3296 tree 3297 aarch64_general_builtin_rsqrt (unsigned int fn) 3298 { 3299 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df) 3300 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF]; 3301 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2sf) 3302 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2SF]; 3303 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv4sf) 3304 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V4SF]; 3305 return NULL_TREE; 3306 } 3307 3308 /* Return true if the lane check can be removed as there is no 3309 error going to be emitted. */ 3310 static bool 3311 aarch64_fold_builtin_lane_check (tree arg0, tree arg1, tree arg2) 3312 { 3313 if (TREE_CODE (arg0) != INTEGER_CST) 3314 return false; 3315 if (TREE_CODE (arg1) != INTEGER_CST) 3316 return false; 3317 if (TREE_CODE (arg2) != INTEGER_CST) 3318 return false; 3319 3320 auto totalsize = wi::to_widest (arg0); 3321 auto elementsize = wi::to_widest (arg1); 3322 if (totalsize == 0 || elementsize == 0) 3323 return false; 3324 auto lane = wi::to_widest (arg2); 3325 auto high = wi::udiv_trunc (totalsize, elementsize); 3326 return wi::ltu_p (lane, high); 3327 } 3328 3329 #undef VAR1 3330 #define VAR1(T, N, MAP, FLAG, A) \ 3331 case AARCH64_SIMD_BUILTIN_##T##_##N##A: 3332 3333 #undef VREINTERPRET_BUILTIN 3334 #define VREINTERPRET_BUILTIN(A, B, L) \ 3335 case AARCH64_SIMD_BUILTIN_VREINTERPRET##L##_##A##_##B: 3336 3337 3338 /* Try to fold a call to the built-in function with subcode FCODE. The 3339 function is passed the N_ARGS arguments in ARGS and it returns a value 3340 of type TYPE. Return the new expression on success and NULL_TREE on 3341 failure. */ 3342 tree 3343 aarch64_general_fold_builtin (unsigned int fcode, tree type, 3344 unsigned int n_args ATTRIBUTE_UNUSED, tree *args) 3345 { 3346 switch (fcode) 3347 { 3348 BUILTIN_VDQF (UNOP, abs, 2, ALL) 3349 return fold_build1 (ABS_EXPR, type, args[0]); 3350 VAR1 (UNOP, floatv2si, 2, ALL, v2sf) 3351 VAR1 (UNOP, floatv4si, 2, ALL, v4sf) 3352 VAR1 (UNOP, floatv2di, 2, ALL, v2df) 3353 return fold_build1 (FLOAT_EXPR, type, args[0]); 3354 AARCH64_SIMD_VREINTERPRET_BUILTINS 3355 return fold_build1 (VIEW_CONVERT_EXPR, type, args[0]); 3356 case AARCH64_SIMD_BUILTIN_LANE_CHECK: 3357 gcc_assert (n_args == 3); 3358 if (aarch64_fold_builtin_lane_check (args[0], args[1], args[2])) 3359 return void_node; 3360 break; 3361 default: 3362 break; 3363 } 3364 3365 return NULL_TREE; 3366 } 3367 3368 enum aarch64_simd_type 3369 get_mem_type_for_load_store (unsigned int fcode) 3370 { 3371 switch (fcode) 3372 { 3373 VAR1 (LOAD1, ld1, 0, LOAD, v8qi) 3374 VAR1 (STORE1, st1, 0, STORE, v8qi) 3375 return Int8x8_t; 3376 VAR1 (LOAD1, ld1, 0, LOAD, v16qi) 3377 VAR1 (STORE1, st1, 0, STORE, v16qi) 3378 return Int8x16_t; 3379 VAR1 (LOAD1, ld1, 0, LOAD, v4hi) 3380 VAR1 (STORE1, st1, 0, STORE, v4hi) 3381 return Int16x4_t; 3382 VAR1 (LOAD1, ld1, 0, LOAD, v8hi) 3383 VAR1 (STORE1, st1, 0, STORE, v8hi) 3384 return Int16x8_t; 3385 VAR1 (LOAD1, ld1, 0, LOAD, v2si) 3386 VAR1 (STORE1, st1, 0, STORE, v2si) 3387 return Int32x2_t; 3388 VAR1 (LOAD1, ld1, 0, LOAD, v4si) 3389 VAR1 (STORE1, st1, 0, STORE, v4si) 3390 return Int32x4_t; 3391 VAR1 (LOAD1, ld1, 0, LOAD, v2di) 3392 VAR1 (STORE1, st1, 0, STORE, v2di) 3393 return Int64x2_t; 3394 VAR1 (LOAD1_U, ld1, 0, LOAD, v8qi) 3395 VAR1 (STORE1_U, st1, 0, STORE, v8qi) 3396 return Uint8x8_t; 3397 VAR1 (LOAD1_U, ld1, 0, LOAD, v16qi) 3398 VAR1 (STORE1_U, st1, 0, STORE, v16qi) 3399 return Uint8x16_t; 3400 VAR1 (LOAD1_U, ld1, 0, LOAD, v4hi) 3401 VAR1 (STORE1_U, st1, 0, STORE, v4hi) 3402 return Uint16x4_t; 3403 VAR1 (LOAD1_U, ld1, 0, LOAD, v8hi) 3404 VAR1 (STORE1_U, st1, 0, STORE, v8hi) 3405 return Uint16x8_t; 3406 VAR1 (LOAD1_U, ld1, 0, LOAD, v2si) 3407 VAR1 (STORE1_U, st1, 0, STORE, v2si) 3408 return Uint32x2_t; 3409 VAR1 (LOAD1_U, ld1, 0, LOAD, v4si) 3410 VAR1 (STORE1_U, st1, 0, STORE, v4si) 3411 return Uint32x4_t; 3412 VAR1 (LOAD1_U, ld1, 0, LOAD, v2di) 3413 VAR1 (STORE1_U, st1, 0, STORE, v2di) 3414 return Uint64x2_t; 3415 VAR1 (LOAD1_P, ld1, 0, LOAD, v8qi) 3416 VAR1 (STORE1_P, st1, 0, STORE, v8qi) 3417 return Poly8x8_t; 3418 VAR1 (LOAD1_P, ld1, 0, LOAD, v16qi) 3419 VAR1 (STORE1_P, st1, 0, STORE, v16qi) 3420 return Poly8x16_t; 3421 VAR1 (LOAD1_P, ld1, 0, LOAD, v4hi) 3422 VAR1 (STORE1_P, st1, 0, STORE, v4hi) 3423 return Poly16x4_t; 3424 VAR1 (LOAD1_P, ld1, 0, LOAD, v8hi) 3425 VAR1 (STORE1_P, st1, 0, STORE, v8hi) 3426 return Poly16x8_t; 3427 VAR1 (LOAD1_P, ld1, 0, LOAD, v2di) 3428 VAR1 (STORE1_P, st1, 0, STORE, v2di) 3429 return Poly64x2_t; 3430 VAR1 (LOAD1, ld1, 0, LOAD, v4hf) 3431 VAR1 (STORE1, st1, 0, STORE, v4hf) 3432 return Float16x4_t; 3433 VAR1 (LOAD1, ld1, 0, LOAD, v8hf) 3434 VAR1 (STORE1, st1, 0, STORE, v8hf) 3435 return Float16x8_t; 3436 VAR1 (LOAD1, ld1, 0, LOAD, v4bf) 3437 VAR1 (STORE1, st1, 0, STORE, v4bf) 3438 return Bfloat16x4_t; 3439 VAR1 (LOAD1, ld1, 0, LOAD, v8bf) 3440 VAR1 (STORE1, st1, 0, STORE, v8bf) 3441 return Bfloat16x8_t; 3442 VAR1 (LOAD1, ld1, 0, LOAD, v2sf) 3443 VAR1 (STORE1, st1, 0, STORE, v2sf) 3444 return Float32x2_t; 3445 VAR1 (LOAD1, ld1, 0, LOAD, v4sf) 3446 VAR1 (STORE1, st1, 0, STORE, v4sf) 3447 return Float32x4_t; 3448 VAR1 (LOAD1, ld1, 0, LOAD, v2df) 3449 VAR1 (STORE1, st1, 0, STORE, v2df) 3450 return Float64x2_t; 3451 default: 3452 gcc_unreachable (); 3453 break; 3454 } 3455 } 3456 3457 /* We've seen a vector load from address ADDR. Record it in 3458 vector_load_decls, if appropriate. */ 3459 static void 3460 aarch64_record_vector_load_arg (tree addr) 3461 { 3462 tree decl = aarch64_vector_load_decl (addr); 3463 if (!decl) 3464 return; 3465 if (!cfun->machine->vector_load_decls) 3466 cfun->machine->vector_load_decls = hash_set<tree>::create_ggc (31); 3467 cfun->machine->vector_load_decls->add (decl); 3468 } 3469 3470 /* Try to fold STMT, given that it's a call to the built-in function with 3471 subcode FCODE. Return the new statement on success and null on 3472 failure. */ 3473 gimple * 3474 aarch64_general_gimple_fold_builtin (unsigned int fcode, gcall *stmt, 3475 gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED) 3476 { 3477 gimple *new_stmt = NULL; 3478 unsigned nargs = gimple_call_num_args (stmt); 3479 tree *args = (nargs > 0 3480 ? gimple_call_arg_ptr (stmt, 0) 3481 : &error_mark_node); 3482 3483 /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int 3484 and unsigned int; it will distinguish according to the types of 3485 the arguments to the __builtin. */ 3486 switch (fcode) 3487 { 3488 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10, ALL) 3489 BUILTIN_VDQ_I (UNOPU, reduc_plus_scal_, 10, NONE) 3490 new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS, 3491 1, args[0]); 3492 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); 3493 break; 3494 3495 /* Lower sqrt builtins to gimple/internal function sqrt. */ 3496 BUILTIN_VHSDF_DF (UNOP, sqrt, 2, FP) 3497 new_stmt = gimple_build_call_internal (IFN_SQRT, 3498 1, args[0]); 3499 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); 3500 break; 3501 3502 BUILTIN_VDC (BINOP, combine, 0, AUTO_FP) 3503 BUILTIN_VD_I (BINOPU, combine, 0, NONE) 3504 BUILTIN_VDC_P (BINOPP, combine, 0, NONE) 3505 { 3506 tree first_part, second_part; 3507 if (BYTES_BIG_ENDIAN) 3508 { 3509 second_part = args[0]; 3510 first_part = args[1]; 3511 } 3512 else 3513 { 3514 first_part = args[0]; 3515 second_part = args[1]; 3516 } 3517 tree ret_type = gimple_call_return_type (stmt); 3518 tree ctor = build_constructor_va (ret_type, 2, NULL_TREE, first_part, 3519 NULL_TREE, second_part); 3520 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), ctor); 3521 } 3522 break; 3523 3524 /*lower store and load neon builtins to gimple. */ 3525 BUILTIN_VALL_F16 (LOAD1, ld1, 0, LOAD) 3526 BUILTIN_VDQ_I (LOAD1_U, ld1, 0, LOAD) 3527 BUILTIN_VALLP_NO_DI (LOAD1_P, ld1, 0, LOAD) 3528 /* Punt until after inlining, so that we stand more chance of 3529 recording something meaningful in vector_load_decls. */ 3530 if (!cfun->after_inlining) 3531 break; 3532 aarch64_record_vector_load_arg (args[0]); 3533 if (!BYTES_BIG_ENDIAN) 3534 { 3535 enum aarch64_simd_type mem_type 3536 = get_mem_type_for_load_store(fcode); 3537 aarch64_simd_type_info simd_type 3538 = aarch64_simd_types[mem_type]; 3539 tree elt_ptr_type = build_pointer_type_for_mode (simd_type.eltype, 3540 VOIDmode, true); 3541 tree zero = build_zero_cst (elt_ptr_type); 3542 /* Use element type alignment. */ 3543 tree access_type 3544 = build_aligned_type (simd_type.itype, 3545 TYPE_ALIGN (simd_type.eltype)); 3546 new_stmt 3547 = gimple_build_assign (gimple_get_lhs (stmt), 3548 fold_build2 (MEM_REF, 3549 access_type, 3550 args[0], zero)); 3551 gimple_set_vuse (new_stmt, gimple_vuse (stmt)); 3552 gimple_set_vdef (new_stmt, gimple_vdef (stmt)); 3553 } 3554 break; 3555 3556 BUILTIN_VALL_F16 (STORE1, st1, 0, STORE) 3557 BUILTIN_VDQ_I (STORE1_U, st1, 0, STORE) 3558 BUILTIN_VALLP_NO_DI (STORE1_P, st1, 0, STORE) 3559 if (!BYTES_BIG_ENDIAN) 3560 { 3561 enum aarch64_simd_type mem_type 3562 = get_mem_type_for_load_store(fcode); 3563 aarch64_simd_type_info simd_type 3564 = aarch64_simd_types[mem_type]; 3565 tree elt_ptr_type = build_pointer_type_for_mode (simd_type.eltype, 3566 VOIDmode, true); 3567 tree zero = build_zero_cst (elt_ptr_type); 3568 /* Use element type alignment. */ 3569 tree access_type 3570 = build_aligned_type (simd_type.itype, 3571 TYPE_ALIGN (simd_type.eltype)); 3572 new_stmt 3573 = gimple_build_assign (fold_build2 (MEM_REF, access_type, 3574 args[0], zero), 3575 args[1]); 3576 gimple_set_vuse (new_stmt, gimple_vuse (stmt)); 3577 gimple_set_vdef (new_stmt, gimple_vdef (stmt)); 3578 } 3579 break; 3580 3581 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10, ALL) 3582 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10, ALL) 3583 new_stmt = gimple_build_call_internal (IFN_REDUC_MAX, 3584 1, args[0]); 3585 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); 3586 break; 3587 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10, ALL) 3588 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10, ALL) 3589 new_stmt = gimple_build_call_internal (IFN_REDUC_MIN, 3590 1, args[0]); 3591 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); 3592 break; 3593 BUILTIN_VSDQ_I_DI (BINOP, ashl, 3, NONE) 3594 if (TREE_CODE (args[1]) == INTEGER_CST 3595 && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0]))) 3596 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3597 LSHIFT_EXPR, args[0], args[1]); 3598 break; 3599 BUILTIN_VSDQ_I_DI (BINOP, sshl, 0, NONE) 3600 BUILTIN_VSDQ_I_DI (BINOP_UUS, ushl, 0, NONE) 3601 { 3602 tree cst = args[1]; 3603 tree ctype = TREE_TYPE (cst); 3604 /* Left shifts can be both scalar or vector, e.g. uint64x1_t is 3605 treated as a scalar type not a vector one. */ 3606 if ((cst = uniform_integer_cst_p (cst)) != NULL_TREE) 3607 { 3608 wide_int wcst = wi::to_wide (cst); 3609 tree unit_ty = TREE_TYPE (cst); 3610 3611 wide_int abs_cst = wi::abs (wcst); 3612 if (wi::geu_p (abs_cst, element_precision (args[0]))) 3613 break; 3614 3615 if (wi::neg_p (wcst, TYPE_SIGN (ctype))) 3616 { 3617 tree final_cst; 3618 final_cst = wide_int_to_tree (unit_ty, abs_cst); 3619 if (TREE_CODE (cst) != INTEGER_CST) 3620 final_cst = build_uniform_cst (ctype, final_cst); 3621 3622 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3623 RSHIFT_EXPR, args[0], 3624 final_cst); 3625 } 3626 else 3627 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3628 LSHIFT_EXPR, args[0], args[1]); 3629 } 3630 } 3631 break; 3632 BUILTIN_VDQ_I (SHIFTIMM, ashr, 3, NONE) 3633 VAR1 (SHIFTIMM, ashr_simd, 0, NONE, di) 3634 BUILTIN_VDQ_I (USHIFTIMM, lshr, 3, NONE) 3635 VAR1 (USHIFTIMM, lshr_simd, 0, NONE, di) 3636 if (TREE_CODE (args[1]) == INTEGER_CST 3637 && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0]))) 3638 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3639 RSHIFT_EXPR, args[0], args[1]); 3640 break; 3641 BUILTIN_GPF (BINOP, fmulx, 0, ALL) 3642 { 3643 gcc_assert (nargs == 2); 3644 bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST; 3645 bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST; 3646 if (a0_cst_p || a1_cst_p) 3647 { 3648 if (a0_cst_p && a1_cst_p) 3649 { 3650 tree t0 = TREE_TYPE (args[0]); 3651 real_value a0 = (TREE_REAL_CST (args[0])); 3652 real_value a1 = (TREE_REAL_CST (args[1])); 3653 if (real_equal (&a1, &dconst0)) 3654 std::swap (a0, a1); 3655 /* According to real_equal (), +0 equals -0. */ 3656 if (real_equal (&a0, &dconst0) && real_isinf (&a1)) 3657 { 3658 real_value res = dconst2; 3659 res.sign = a0.sign ^ a1.sign; 3660 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3661 REAL_CST, 3662 build_real (t0, res)); 3663 } 3664 else 3665 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3666 MULT_EXPR, 3667 args[0], args[1]); 3668 } 3669 else /* a0_cst_p ^ a1_cst_p. */ 3670 { 3671 real_value const_part = a0_cst_p 3672 ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]); 3673 if (!real_equal (&const_part, &dconst0) 3674 && !real_isinf (&const_part)) 3675 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 3676 MULT_EXPR, args[0], 3677 args[1]); 3678 } 3679 } 3680 if (new_stmt) 3681 { 3682 gimple_set_vuse (new_stmt, gimple_vuse (stmt)); 3683 gimple_set_vdef (new_stmt, gimple_vdef (stmt)); 3684 } 3685 break; 3686 } 3687 case AARCH64_SIMD_BUILTIN_LANE_CHECK: 3688 if (aarch64_fold_builtin_lane_check (args[0], args[1], args[2])) 3689 { 3690 unlink_stmt_vdef (stmt); 3691 release_defs (stmt); 3692 new_stmt = gimple_build_nop (); 3693 } 3694 break; 3695 default: 3696 break; 3697 } 3698 3699 /* GIMPLE assign statements (unlike calls) require a non-null lhs. If we 3700 created an assign statement with a null lhs, then fix this by assigning 3701 to a new (and subsequently unused) variable. */ 3702 if (new_stmt && is_gimple_assign (new_stmt) && !gimple_assign_lhs (new_stmt)) 3703 { 3704 tree new_lhs = make_ssa_name (gimple_call_return_type (stmt)); 3705 gimple_assign_set_lhs (new_stmt, new_lhs); 3706 } 3707 3708 return new_stmt; 3709 } 3710 3711 void 3712 aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) 3713 { 3714 const unsigned AARCH64_FE_INVALID = 1; 3715 const unsigned AARCH64_FE_DIVBYZERO = 2; 3716 const unsigned AARCH64_FE_OVERFLOW = 4; 3717 const unsigned AARCH64_FE_UNDERFLOW = 8; 3718 const unsigned AARCH64_FE_INEXACT = 16; 3719 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID 3720 | AARCH64_FE_DIVBYZERO 3721 | AARCH64_FE_OVERFLOW 3722 | AARCH64_FE_UNDERFLOW 3723 | AARCH64_FE_INEXACT); 3724 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8; 3725 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr; 3726 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr; 3727 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr; 3728 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv; 3729 3730 /* Generate the equivalence of : 3731 unsigned int fenv_cr; 3732 fenv_cr = __builtin_aarch64_get_fpcr (); 3733 3734 unsigned int fenv_sr; 3735 fenv_sr = __builtin_aarch64_get_fpsr (); 3736 3737 Now set all exceptions to non-stop 3738 unsigned int mask_cr 3739 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT); 3740 unsigned int masked_cr; 3741 masked_cr = fenv_cr & mask_cr; 3742 3743 And clear all exception flags 3744 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT; 3745 unsigned int masked_cr; 3746 masked_sr = fenv_sr & mask_sr; 3747 3748 __builtin_aarch64_set_cr (masked_cr); 3749 __builtin_aarch64_set_sr (masked_sr); */ 3750 3751 fenv_cr = create_tmp_var_raw (unsigned_type_node); 3752 fenv_sr = create_tmp_var_raw (unsigned_type_node); 3753 3754 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]; 3755 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]; 3756 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]; 3757 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]; 3758 3759 mask_cr = build_int_cst (unsigned_type_node, 3760 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT)); 3761 mask_sr = build_int_cst (unsigned_type_node, 3762 ~(AARCH64_FE_ALL_EXCEPT)); 3763 3764 ld_fenv_cr = build4 (TARGET_EXPR, unsigned_type_node, 3765 fenv_cr, build_call_expr (get_fpcr, 0), 3766 NULL_TREE, NULL_TREE); 3767 ld_fenv_sr = build4 (TARGET_EXPR, unsigned_type_node, 3768 fenv_sr, build_call_expr (get_fpsr, 0), 3769 NULL_TREE, NULL_TREE); 3770 3771 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr); 3772 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr); 3773 3774 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr); 3775 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr); 3776 3777 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr, 3778 hold_fnclex_sr); 3779 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr, 3780 masked_fenv_sr); 3781 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr); 3782 3783 *hold = build2 (COMPOUND_EXPR, void_type_node, 3784 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv), 3785 hold_fnclex); 3786 3787 /* Store the value of masked_fenv to clear the exceptions: 3788 __builtin_aarch64_set_fpsr (masked_fenv_sr); */ 3789 3790 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr); 3791 3792 /* Generate the equivalent of : 3793 unsigned int new_fenv_var; 3794 new_fenv_var = __builtin_aarch64_get_fpsr (); 3795 3796 __builtin_aarch64_set_fpsr (fenv_sr); 3797 3798 __atomic_feraiseexcept (new_fenv_var); */ 3799 3800 new_fenv_var = create_tmp_var_raw (unsigned_type_node); 3801 reload_fenv = build4 (TARGET_EXPR, unsigned_type_node, 3802 new_fenv_var, build_call_expr (get_fpsr, 0), 3803 NULL_TREE, NULL_TREE); 3804 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr); 3805 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); 3806 update_call = build_call_expr (atomic_feraiseexcept, 1, 3807 fold_convert (integer_type_node, new_fenv_var)); 3808 *update = build2 (COMPOUND_EXPR, void_type_node, 3809 build2 (COMPOUND_EXPR, void_type_node, 3810 reload_fenv, restore_fnenv), update_call); 3811 } 3812 3813 /* Resolve overloaded MEMTAG build-in functions. */ 3814 #define AARCH64_BUILTIN_SUBCODE(F) \ 3815 (DECL_MD_FUNCTION_CODE (F) >> AARCH64_BUILTIN_SHIFT) 3816 3817 static tree 3818 aarch64_resolve_overloaded_memtag (location_t loc, 3819 tree fndecl, void *pass_params) 3820 { 3821 vec<tree, va_gc> *params = static_cast<vec<tree, va_gc> *> (pass_params); 3822 unsigned param_num = params ? params->length() : 0; 3823 unsigned int fcode = AARCH64_BUILTIN_SUBCODE (fndecl); 3824 tree inittype = aarch64_memtag_builtin_data[ 3825 fcode - AARCH64_MEMTAG_BUILTIN_START - 1].ftype; 3826 unsigned arg_num = list_length (TYPE_ARG_TYPES (inittype)) - 1; 3827 3828 if (param_num != arg_num) 3829 { 3830 TREE_TYPE (fndecl) = inittype; 3831 return NULL_TREE; 3832 } 3833 tree retype = NULL; 3834 3835 if (fcode == AARCH64_MEMTAG_BUILTIN_SUBP) 3836 { 3837 tree t0 = TREE_TYPE ((*params)[0]); 3838 tree t1 = TREE_TYPE ((*params)[1]); 3839 3840 if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE) 3841 t0 = ptr_type_node; 3842 if (t1 == error_mark_node || TREE_CODE (t1) != POINTER_TYPE) 3843 t1 = ptr_type_node; 3844 3845 if (TYPE_MODE (t0) != DImode) 3846 warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit", 3847 (int)tree_to_shwi (DECL_SIZE ((*params)[0]))); 3848 3849 if (TYPE_MODE (t1) != DImode) 3850 warning_at (loc, 1, "expected 64-bit address but argument 2 is %d-bit", 3851 (int)tree_to_shwi (DECL_SIZE ((*params)[1]))); 3852 3853 retype = build_function_type_list (ptrdiff_type_node, t0, t1, NULL); 3854 } 3855 else 3856 { 3857 tree t0 = TREE_TYPE ((*params)[0]); 3858 3859 if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE) 3860 { 3861 TREE_TYPE (fndecl) = inittype; 3862 return NULL_TREE; 3863 } 3864 3865 if (TYPE_MODE (t0) != DImode) 3866 warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit", 3867 (int)tree_to_shwi (DECL_SIZE ((*params)[0]))); 3868 3869 switch (fcode) 3870 { 3871 case AARCH64_MEMTAG_BUILTIN_IRG: 3872 retype = build_function_type_list (t0, t0, uint64_type_node, NULL); 3873 break; 3874 case AARCH64_MEMTAG_BUILTIN_GMI: 3875 retype = build_function_type_list (uint64_type_node, t0, 3876 uint64_type_node, NULL); 3877 break; 3878 case AARCH64_MEMTAG_BUILTIN_INC_TAG: 3879 retype = build_function_type_list (t0, t0, unsigned_type_node, NULL); 3880 break; 3881 case AARCH64_MEMTAG_BUILTIN_SET_TAG: 3882 retype = build_function_type_list (void_type_node, t0, NULL); 3883 break; 3884 case AARCH64_MEMTAG_BUILTIN_GET_TAG: 3885 retype = build_function_type_list (t0, t0, NULL); 3886 break; 3887 default: 3888 return NULL_TREE; 3889 } 3890 } 3891 3892 if (!retype || retype == error_mark_node) 3893 TREE_TYPE (fndecl) = inittype; 3894 else 3895 TREE_TYPE (fndecl) = retype; 3896 3897 return NULL_TREE; 3898 } 3899 3900 /* Called at aarch64_resolve_overloaded_builtin in aarch64-c.cc. */ 3901 tree 3902 aarch64_resolve_overloaded_builtin_general (location_t loc, tree function, 3903 void *pass_params) 3904 { 3905 unsigned int fcode = AARCH64_BUILTIN_SUBCODE (function); 3906 3907 if (fcode >= AARCH64_MEMTAG_BUILTIN_START 3908 && fcode <= AARCH64_MEMTAG_BUILTIN_END) 3909 return aarch64_resolve_overloaded_memtag(loc, function, pass_params); 3910 3911 return NULL_TREE; 3912 } 3913 3914 #undef AARCH64_CHECK_BUILTIN_MODE 3915 #undef AARCH64_FIND_FRINT_VARIANT 3916 #undef CF0 3917 #undef CF1 3918 #undef CF2 3919 #undef CF3 3920 #undef CF4 3921 #undef CF10 3922 #undef VAR1 3923 #undef VAR2 3924 #undef VAR3 3925 #undef VAR4 3926 #undef VAR5 3927 #undef VAR6 3928 #undef VAR7 3929 #undef VAR8 3930 #undef VAR9 3931 #undef VAR10 3932 #undef VAR11 3933 3934 #include "gt-aarch64-builtins.h" 3935