1235783Skib/* Builtins' description for AArch64 SIMD architecture. 2235783Skib Copyright (C) 2011-2015 Free Software Foundation, Inc. 3235783Skib Contributed by ARM Ltd. 4235783Skib 5235783Skib This file is part of GCC. 6235783Skib 7235783Skib GCC is free software; you can redistribute it and/or modify it 8235783Skib under the terms of the GNU General Public License as published by 9235783Skib the Free Software Foundation; either version 3, or (at your option) 10235783Skib any later version. 11235783Skib 12235783Skib GCC is distributed in the hope that it will be useful, but 13235783Skib WITHOUT ANY WARRANTY; without even the implied warranty of 14235783Skib MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15235783Skib General Public License for more details. 16235783Skib 17235783Skib You should have received a copy of the GNU General Public License 18235783Skib along with GCC; see the file COPYING3. If not see 19235783Skib <http://www.gnu.org/licenses/>. */ 20235783Skib 21235783Skib#include "config.h" 22235783Skib#include "system.h" 23235783Skib#include "coretypes.h" 24235783Skib#include "tm.h" 25235783Skib#include "rtl.h" 26235783Skib#include "hash-set.h" 27235783Skib#include "machmode.h" 28235783Skib#include "vec.h" 29235783Skib#include "double-int.h" 30235783Skib#include "input.h" 31235783Skib#include "alias.h" 32235783Skib#include "symtab.h" 33235783Skib#include "wide-int.h" 34235783Skib#include "inchash.h" 35235783Skib#include "tree.h" 36235783Skib#include "fold-const.h" 37235783Skib#include "stor-layout.h" 38235783Skib#include "stringpool.h" 39235783Skib#include "calls.h" 40235783Skib#include "hashtab.h" 41235783Skib#include "hard-reg-set.h" 42235783Skib#include "function.h" 43235783Skib#include "flags.h" 44235783Skib#include "statistics.h" 45235783Skib#include "real.h" 46235783Skib#include "fixed-value.h" 47235783Skib#include "insn-config.h" 48235783Skib#include "expmed.h" 49235783Skib#include "dojump.h" 50235783Skib#include "explow.h" 51235783Skib#include "emit-rtl.h" 52235783Skib#include "varasm.h" 53235783Skib#include "stmt.h" 54235783Skib#include "expr.h" 55235783Skib#include "tm_p.h" 56235783Skib#include "recog.h" 57235783Skib#include "langhooks.h" 58235783Skib#include "diagnostic-core.h" 59235783Skib#include "insn-codes.h" 60235783Skib#include "optabs.h" 61235783Skib#include "hash-table.h" 62235783Skib#include "ggc.h" 63235783Skib#include "predict.h" 64235783Skib#include "dominance.h" 65235783Skib#include "cfg.h" 66235783Skib#include "cfgrtl.h" 67235783Skib#include "cfganal.h" 68235783Skib#include "lcm.h" 69235783Skib#include "cfgbuild.h" 70235783Skib#include "cfgcleanup.h" 71235783Skib#include "basic-block.h" 72235783Skib#include "tree-ssa-alias.h" 73235783Skib#include "internal-fn.h" 74235783Skib#include "gimple-fold.h" 75235783Skib#include "tree-eh.h" 76235783Skib#include "gimple-expr.h" 77235783Skib#include "is-a.h" 78235783Skib#include "gimple.h" 79235783Skib#include "gimple-iterator.h" 80235783Skib 81235783Skib#define v8qi_UP V8QImode 82235783Skib#define v4hi_UP V4HImode 83235783Skib#define v2si_UP V2SImode 84235783Skib#define v2sf_UP V2SFmode 85235783Skib#define v1df_UP V1DFmode 86235783Skib#define di_UP DImode 87235783Skib#define df_UP DFmode 88235783Skib#define v16qi_UP V16QImode 89235783Skib#define v8hi_UP V8HImode 90235783Skib#define v4si_UP V4SImode 91235783Skib#define v4sf_UP V4SFmode 92235783Skib#define v2di_UP V2DImode 93235783Skib#define v2df_UP V2DFmode 94235783Skib#define ti_UP TImode 95235783Skib#define ei_UP EImode 96235783Skib#define oi_UP OImode 97235783Skib#define ci_UP CImode 98235783Skib#define xi_UP XImode 99235783Skib#define si_UP SImode 100235783Skib#define sf_UP SFmode 101235783Skib#define hi_UP HImode 102235783Skib#define qi_UP QImode 103235783Skib#define UP(X) X##_UP 104235783Skib 105235783Skib#define SIMD_MAX_BUILTIN_ARGS 5 106235783Skib 107235783Skibenum aarch64_type_qualifiers 108235783Skib{ 109235783Skib /* T foo. */ 110235783Skib qualifier_none = 0x0, 111235783Skib /* unsigned T foo. */ 112235783Skib qualifier_unsigned = 0x1, /* 1 << 0 */ 113235783Skib /* const T foo. */ 114235783Skib qualifier_const = 0x2, /* 1 << 1 */ 115235783Skib /* T *foo. */ 116235783Skib qualifier_pointer = 0x4, /* 1 << 2 */ 117235783Skib /* Used when expanding arguments if an operand could 118235783Skib be an immediate. */ 119235783Skib qualifier_immediate = 0x8, /* 1 << 3 */ 120235783Skib qualifier_maybe_immediate = 0x10, /* 1 << 4 */ 121235783Skib /* void foo (...). */ 122235783Skib qualifier_void = 0x20, /* 1 << 5 */ 123235783Skib /* Some patterns may have internal operands, this qualifier is an 124235783Skib instruction to the initialisation code to skip this operand. */ 125235783Skib qualifier_internal = 0x40, /* 1 << 6 */ 126235783Skib /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum 127235783Skib rather than using the type of the operand. */ 128235783Skib qualifier_map_mode = 0x80, /* 1 << 7 */ 129235783Skib /* qualifier_pointer | qualifier_map_mode */ 130235783Skib qualifier_pointer_map_mode = 0x84, 131235783Skib /* qualifier_const | qualifier_pointer | qualifier_map_mode */ 132235783Skib qualifier_const_pointer_map_mode = 0x86, 133235783Skib /* Polynomial types. */ 134235783Skib qualifier_poly = 0x100, 135235783Skib /* Lane indices - must be in range, and flipped for bigendian. */ 136235783Skib qualifier_lane_index = 0x200 137235783Skib}; 138235783Skib 139235783Skibtypedef struct 140235783Skib{ 141235783Skib const char *name; 142235783Skib machine_mode mode; 143235783Skib const enum insn_code code; 144235783Skib unsigned int fcode; 145235783Skib enum aarch64_type_qualifiers *qualifiers; 146235783Skib} aarch64_simd_builtin_datum; 147235783Skib 148235783Skibstatic enum aarch64_type_qualifiers 149235783Skibaarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS] 150235783Skib = { qualifier_none, qualifier_none }; 151235783Skib#define TYPES_UNOP (aarch64_types_unop_qualifiers) 152235783Skibstatic enum aarch64_type_qualifiers 153235783Skibaarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 154235783Skib = { qualifier_unsigned, qualifier_unsigned }; 155235783Skib#define TYPES_UNOPU (aarch64_types_unopu_qualifiers) 156235783Skibstatic enum aarch64_type_qualifiers 157235783Skibaarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS] 158235783Skib = { qualifier_none, qualifier_none, qualifier_maybe_immediate }; 159235783Skib#define TYPES_BINOP (aarch64_types_binop_qualifiers) 160235783Skibstatic enum aarch64_type_qualifiers 161235783Skibaarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 162235783Skib = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned }; 163235783Skib#define TYPES_BINOPU (aarch64_types_binopu_qualifiers) 164235783Skibstatic enum aarch64_type_qualifiers 165235783Skibaarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS] 166235783Skib = { qualifier_unsigned, qualifier_unsigned, qualifier_none }; 167235783Skib#define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers) 168235783Skibstatic enum aarch64_type_qualifiers 169235783Skibaarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 170235783Skib = { qualifier_none, qualifier_none, qualifier_unsigned }; 171235783Skib#define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers) 172235783Skibstatic enum aarch64_type_qualifiers 173235783Skibaarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS] 174235783Skib = { qualifier_poly, qualifier_poly, qualifier_poly }; 175235783Skib#define TYPES_BINOPP (aarch64_types_binopp_qualifiers) 176235783Skib 177235783Skibstatic enum aarch64_type_qualifiers 178235783Skibaarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS] 179235783Skib = { qualifier_none, qualifier_none, qualifier_none, qualifier_none }; 180235783Skib#define TYPES_TERNOP (aarch64_types_ternop_qualifiers) 181235783Skibstatic enum aarch64_type_qualifiers 182235783Skibaarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 183235783Skib = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index }; 184235783Skib#define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers) 185235783Skibstatic enum aarch64_type_qualifiers 186235783Skibaarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS] 187235783Skib = { qualifier_unsigned, qualifier_unsigned, 188235783Skib qualifier_unsigned, qualifier_unsigned }; 189235783Skib#define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers) 190235783Skib 191235783Skibstatic enum aarch64_type_qualifiers 192235783Skibaarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 193235783Skib = { qualifier_none, qualifier_none, qualifier_none, 194235783Skib qualifier_none, qualifier_lane_index }; 195235783Skib#define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers) 196235783Skib 197235783Skibstatic enum aarch64_type_qualifiers 198235783Skibaarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 199235783Skib = { qualifier_none, qualifier_none, qualifier_immediate }; 200235783Skib#define TYPES_GETREG (aarch64_types_binop_imm_qualifiers) 201235783Skib#define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers) 202235783Skibstatic enum aarch64_type_qualifiers 203235783Skibaarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS] 204235783Skib = { qualifier_unsigned, qualifier_none, qualifier_immediate }; 205235783Skib#define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers) 206235783Skibstatic enum aarch64_type_qualifiers 207235783Skibaarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS] 208235783Skib = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate }; 209235783Skib#define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers) 210235783Skib 211235783Skibstatic enum aarch64_type_qualifiers 212235783Skibaarch64_types_ternop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS] 213235783Skib = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate }; 214235783Skib#define TYPES_SETREG (aarch64_types_ternop_imm_qualifiers) 215235783Skib#define TYPES_SHIFTINSERT (aarch64_types_ternop_imm_qualifiers) 216235783Skib#define TYPES_SHIFTACC (aarch64_types_ternop_imm_qualifiers) 217235783Skib 218235783Skibstatic enum aarch64_type_qualifiers 219235783Skibaarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS] 220235783Skib = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned, 221235783Skib qualifier_immediate }; 222235783Skib#define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers) 223235783Skib 224235783Skib 225235783Skibstatic enum aarch64_type_qualifiers 226235783Skibaarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS] 227235783Skib = { qualifier_none, qualifier_none, qualifier_none }; 228235783Skib#define TYPES_COMBINE (aarch64_types_combine_qualifiers) 229235783Skib 230235783Skibstatic enum aarch64_type_qualifiers 231235783Skibaarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS] 232235783Skib = { qualifier_none, qualifier_const_pointer_map_mode }; 233235783Skib#define TYPES_LOAD1 (aarch64_types_load1_qualifiers) 234235783Skib#define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers) 235235783Skibstatic enum aarch64_type_qualifiers 236235783Skibaarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 237235783Skib = { qualifier_none, qualifier_const_pointer_map_mode, 238235783Skib qualifier_none, qualifier_none }; 239235783Skib#define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers) 240235783Skib 241235783Skibstatic enum aarch64_type_qualifiers 242235783Skibaarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS] 243235783Skib = { qualifier_poly, qualifier_unsigned, 244235783Skib qualifier_poly, qualifier_poly }; 245235783Skib#define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers) 246235783Skibstatic enum aarch64_type_qualifiers 247235783Skibaarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS] 248235783Skib = { qualifier_none, qualifier_unsigned, 249235783Skib qualifier_none, qualifier_none }; 250235783Skib#define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers) 251235783Skibstatic enum aarch64_type_qualifiers 252235783Skibaarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS] 253235783Skib = { qualifier_unsigned, qualifier_unsigned, 254235783Skib qualifier_unsigned, qualifier_unsigned }; 255235783Skib#define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers) 256235783Skib 257235783Skib/* The first argument (return type) of a store should be void type, 258235783Skib which we represent with qualifier_void. Their first operand will be 259235783Skib a DImode pointer to the location to store to, so we must use 260235783Skib qualifier_map_mode | qualifier_pointer to build a pointer to the 261235783Skib element type of the vector. */ 262235783Skibstatic enum aarch64_type_qualifiers 263235783Skibaarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS] 264235783Skib = { qualifier_void, qualifier_pointer_map_mode, qualifier_none }; 265235783Skib#define TYPES_STORE1 (aarch64_types_store1_qualifiers) 266235783Skib#define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers) 267235783Skibstatic enum aarch64_type_qualifiers 268235783Skibaarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS] 269235783Skib = { qualifier_void, qualifier_pointer_map_mode, 270235783Skib qualifier_none, qualifier_none }; 271235783Skib#define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers) 272235783Skib 273235783Skib#define CF0(N, X) CODE_FOR_aarch64_##N##X 274235783Skib#define CF1(N, X) CODE_FOR_##N##X##1 275235783Skib#define CF2(N, X) CODE_FOR_##N##X##2 276235783Skib#define CF3(N, X) CODE_FOR_##N##X##3 277235783Skib#define CF4(N, X) CODE_FOR_##N##X##4 278235783Skib#define CF10(N, X) CODE_FOR_##N##X 279235783Skib 280235783Skib#define VAR1(T, N, MAP, A) \ 281235783Skib {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T}, 282235783Skib#define VAR2(T, N, MAP, A, B) \ 283235783Skib VAR1 (T, N, MAP, A) \ 284235783Skib VAR1 (T, N, MAP, B) 285235783Skib#define VAR3(T, N, MAP, A, B, C) \ 286235783Skib VAR2 (T, N, MAP, A, B) \ 287235783Skib VAR1 (T, N, MAP, C) 288235783Skib#define VAR4(T, N, MAP, A, B, C, D) \ 289235783Skib VAR3 (T, N, MAP, A, B, C) \ 290235783Skib VAR1 (T, N, MAP, D) 291235783Skib#define VAR5(T, N, MAP, A, B, C, D, E) \ 292235783Skib VAR4 (T, N, MAP, A, B, C, D) \ 293235783Skib VAR1 (T, N, MAP, E) 294235783Skib#define VAR6(T, N, MAP, A, B, C, D, E, F) \ 295235783Skib VAR5 (T, N, MAP, A, B, C, D, E) \ 296235783Skib VAR1 (T, N, MAP, F) 297235783Skib#define VAR7(T, N, MAP, A, B, C, D, E, F, G) \ 298235783Skib VAR6 (T, N, MAP, A, B, C, D, E, F) \ 299235783Skib VAR1 (T, N, MAP, G) 300235783Skib#define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \ 301235783Skib VAR7 (T, N, MAP, A, B, C, D, E, F, G) \ 302235783Skib VAR1 (T, N, MAP, H) 303235783Skib#define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \ 304235783Skib VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \ 305235783Skib VAR1 (T, N, MAP, I) 306235783Skib#define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \ 307235783Skib VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \ 308235783Skib VAR1 (T, N, MAP, J) 309235783Skib#define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \ 310235783Skib VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \ 311235783Skib VAR1 (T, N, MAP, K) 312235783Skib#define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \ 313235783Skib VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \ 314235783Skib VAR1 (T, N, MAP, L) 315235783Skib 316235783Skib#include "aarch64-builtin-iterators.h" 317235783Skib 318235783Skibstatic aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = { 319235783Skib#include "aarch64-simd-builtins.def" 320235783Skib}; 321235783Skib 322235783Skib/* There's only 8 CRC32 builtins. Probably not worth their own .def file. */ 323235783Skib#define AARCH64_CRC32_BUILTINS \ 324235783Skib CRC32_BUILTIN (crc32b, QI) \ 325235783Skib CRC32_BUILTIN (crc32h, HI) \ 326235783Skib CRC32_BUILTIN (crc32w, SI) \ 327235783Skib CRC32_BUILTIN (crc32x, DI) \ 328235783Skib CRC32_BUILTIN (crc32cb, QI) \ 329235783Skib CRC32_BUILTIN (crc32ch, HI) \ 330235783Skib CRC32_BUILTIN (crc32cw, SI) \ 331235783Skib CRC32_BUILTIN (crc32cx, DI) 332235783Skib 333235783Skibtypedef struct 334235783Skib{ 335235783Skib const char *name; 336235783Skib machine_mode mode; 337235783Skib const enum insn_code icode; 338235783Skib unsigned int fcode; 339235783Skib} aarch64_crc_builtin_datum; 340235783Skib 341235783Skib#define CRC32_BUILTIN(N, M) \ 342235783Skib AARCH64_BUILTIN_##N, 343235783Skib 344235783Skib#undef VAR1 345235783Skib#define VAR1(T, N, MAP, A) \ 346235783Skib AARCH64_SIMD_BUILTIN_##T##_##N##A, 347235783Skib 348235783Skibenum aarch64_builtins 349235783Skib{ 350235783Skib AARCH64_BUILTIN_MIN, 351235783Skib 352235783Skib AARCH64_BUILTIN_GET_FPCR, 353235783Skib AARCH64_BUILTIN_SET_FPCR, 354235783Skib AARCH64_BUILTIN_GET_FPSR, 355235783Skib AARCH64_BUILTIN_SET_FPSR, 356235783Skib 357235783Skib AARCH64_SIMD_BUILTIN_BASE, 358235783Skib AARCH64_SIMD_BUILTIN_LANE_CHECK, 359235783Skib#include "aarch64-simd-builtins.def" 360235783Skib /* The first enum element which is based on an insn_data pattern. */ 361235783Skib AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1, 362235783Skib AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START 363235783Skib + ARRAY_SIZE (aarch64_simd_builtin_data) - 1, 364235783Skib AARCH64_CRC32_BUILTIN_BASE, 365235783Skib AARCH64_CRC32_BUILTINS 366235783Skib AARCH64_CRC32_BUILTIN_MAX, 367235783Skib AARCH64_BUILTIN_MAX 368235783Skib}; 369235783Skib 370235783Skib#undef CRC32_BUILTIN 371235783Skib#define CRC32_BUILTIN(N, M) \ 372235783Skib {"__builtin_aarch64_"#N, M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N}, 373235783Skib 374235783Skibstatic aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = { 375235783Skib AARCH64_CRC32_BUILTINS 376235783Skib}; 377235783Skib 378235783Skib#undef CRC32_BUILTIN 379235783Skib 380235783Skibstatic GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX]; 381235783Skib 382235783Skib#define NUM_DREG_TYPES 6 383235783Skib#define NUM_QREG_TYPES 6 384235783Skib 385235783Skib/* Internal scalar builtin types. These types are used to support 386235783Skib neon intrinsic builtins. They are _not_ user-visible types. Therefore 387235783Skib the mangling for these types are implementation defined. */ 388235783Skibconst char *aarch64_scalar_builtin_types[] = { 389235783Skib "__builtin_aarch64_simd_qi", 390235783Skib "__builtin_aarch64_simd_hi", 391235783Skib "__builtin_aarch64_simd_si", 392235783Skib "__builtin_aarch64_simd_sf", 393235783Skib "__builtin_aarch64_simd_di", 394235783Skib "__builtin_aarch64_simd_df", 395235783Skib "__builtin_aarch64_simd_poly8", 396235783Skib "__builtin_aarch64_simd_poly16", 397235783Skib "__builtin_aarch64_simd_poly64", 398235783Skib "__builtin_aarch64_simd_poly128", 399235783Skib "__builtin_aarch64_simd_ti", 400235783Skib "__builtin_aarch64_simd_uqi", 401235783Skib "__builtin_aarch64_simd_uhi", 402235783Skib "__builtin_aarch64_simd_usi", 403235783Skib "__builtin_aarch64_simd_udi", 404235783Skib "__builtin_aarch64_simd_ei", 405235783Skib "__builtin_aarch64_simd_oi", 406235783Skib "__builtin_aarch64_simd_ci", 407235783Skib "__builtin_aarch64_simd_xi", 408235783Skib NULL 409235783Skib}; 410235783Skib 411235783Skib#define ENTRY(E, M, Q, G) E, 412235783Skibenum aarch64_simd_type 413235783Skib{ 414235783Skib#include "aarch64-simd-builtin-types.def" 415235783Skib ARM_NEON_H_TYPES_LAST 416235783Skib}; 417235783Skib#undef ENTRY 418235783Skib 419235783Skibstruct aarch64_simd_type_info 420235783Skib{ 421235783Skib enum aarch64_simd_type type; 422235783Skib 423235783Skib /* Internal type name. */ 424235783Skib const char *name; 425235783Skib 426235783Skib /* Internal type name(mangled). The mangled names conform to the 427235783Skib AAPCS64 (see "Procedure Call Standard for the ARM 64-bit Architecture", 428235783Skib Appendix A). To qualify for emission with the mangled names defined in 429235783Skib that document, a vector type must not only be of the correct mode but also 430235783Skib be of the correct internal AdvSIMD vector type (e.g. __Int8x8_t); these 431235783Skib types are registered by aarch64_init_simd_builtin_types (). In other 432235783Skib words, vector types defined in other ways e.g. via vector_size attribute 433235783Skib will get default mangled names. */ 434235783Skib const char *mangle; 435235783Skib 436235783Skib /* Internal type. */ 437235783Skib tree itype; 438235783Skib 439235783Skib /* Element type. */ 440235783Skib tree eltype; 441235783Skib 442235783Skib /* Machine mode the internal type maps to. */ 443235783Skib enum machine_mode mode; 444235783Skib 445235783Skib /* Qualifiers. */ 446235783Skib enum aarch64_type_qualifiers q; 447235783Skib}; 448235783Skib 449235783Skib#define ENTRY(E, M, Q, G) \ 450235783Skib {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, M##mode, qualifier_##Q}, 451235783Skibstatic struct aarch64_simd_type_info aarch64_simd_types [] = { 452235783Skib#include "aarch64-simd-builtin-types.def" 453235783Skib}; 454235783Skib#undef ENTRY 455235783Skib 456235783Skibstatic tree aarch64_simd_intOI_type_node = NULL_TREE; 457235783Skibstatic tree aarch64_simd_intEI_type_node = NULL_TREE; 458235783Skibstatic tree aarch64_simd_intCI_type_node = NULL_TREE; 459235783Skibstatic tree aarch64_simd_intXI_type_node = NULL_TREE; 460235783Skib 461235783Skibstatic const char * 462235783Skibaarch64_mangle_builtin_scalar_type (const_tree type) 463235783Skib{ 464235783Skib int i = 0; 465235783Skib 466235783Skib while (aarch64_scalar_builtin_types[i] != NULL) 467235783Skib { 468235783Skib const char *name = aarch64_scalar_builtin_types[i]; 469235783Skib 470235783Skib if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL 471235783Skib && DECL_NAME (TYPE_NAME (type)) 472235783Skib && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name)) 473235783Skib return aarch64_scalar_builtin_types[i]; 474235783Skib i++; 475235783Skib } 476235783Skib return NULL; 477235783Skib} 478235783Skib 479235783Skibstatic const char * 480235783Skibaarch64_mangle_builtin_vector_type (const_tree type) 481235783Skib{ 482235783Skib int i; 483235783Skib int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]); 484235783Skib 485235783Skib for (i = 0; i < nelts; i++) 486235783Skib if (aarch64_simd_types[i].mode == TYPE_MODE (type) 487235783Skib && TYPE_NAME (type) 488235783Skib && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL 489235783Skib && DECL_NAME (TYPE_NAME (type)) 490235783Skib && !strcmp 491235783Skib (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), 492235783Skib aarch64_simd_types[i].name)) 493235783Skib return aarch64_simd_types[i].mangle; 494235783Skib 495235783Skib return NULL; 496235783Skib} 497235783Skib 498235783Skibconst char * 499235783Skibaarch64_mangle_builtin_type (const_tree type) 500235783Skib{ 501235783Skib const char *mangle; 502235783Skib /* Walk through all the AArch64 builtins types tables to filter out the 503235783Skib incoming type. */ 504235783Skib if ((mangle = aarch64_mangle_builtin_vector_type (type)) 505235783Skib || (mangle = aarch64_mangle_builtin_scalar_type (type))) 506235783Skib return mangle; 507235783Skib 508235783Skib return NULL; 509235783Skib} 510235783Skib 511235783Skibstatic tree 512235783Skibaarch64_simd_builtin_std_type (enum machine_mode mode, 513235783Skib enum aarch64_type_qualifiers q) 514235783Skib{ 515235783Skib#define QUAL_TYPE(M) \ 516235783Skib ((q == qualifier_none) ? int##M##_type_node : unsigned_int##M##_type_node); 517235783Skib switch (mode) 518235783Skib { 519235783Skib case QImode: 520235783Skib return QUAL_TYPE (QI); 521235783Skib case HImode: 522235783Skib return QUAL_TYPE (HI); 523235783Skib case SImode: 524235783Skib return QUAL_TYPE (SI); 525235783Skib case DImode: 526235783Skib return QUAL_TYPE (DI); 527235783Skib case TImode: 528235783Skib return QUAL_TYPE (TI); 529235783Skib case OImode: 530235783Skib return aarch64_simd_intOI_type_node; 531235783Skib case EImode: 532235783Skib return aarch64_simd_intEI_type_node; 533235783Skib case CImode: 534235783Skib return aarch64_simd_intCI_type_node; 535235783Skib case XImode: 536235783Skib return aarch64_simd_intXI_type_node; 537235783Skib case SFmode: 538235783Skib return float_type_node; 539235783Skib case DFmode: 540235783Skib return double_type_node; 541235783Skib default: 542235783Skib gcc_unreachable (); 543235783Skib } 544235783Skib#undef QUAL_TYPE 545235783Skib} 546235783Skib 547235783Skibstatic tree 548235783Skibaarch64_lookup_simd_builtin_type (enum machine_mode mode, 549235783Skib enum aarch64_type_qualifiers q) 550235783Skib{ 551235783Skib int i; 552235783Skib int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]); 553235783Skib 554235783Skib /* Non-poly scalar modes map to standard types not in the table. */ 555235783Skib if (q != qualifier_poly && !VECTOR_MODE_P (mode)) 556235783Skib return aarch64_simd_builtin_std_type (mode, q); 557235783Skib 558235783Skib for (i = 0; i < nelts; i++) 559235783Skib if (aarch64_simd_types[i].mode == mode 560235783Skib && aarch64_simd_types[i].q == q) 561235783Skib return aarch64_simd_types[i].itype; 562235783Skib 563235783Skib return NULL_TREE; 564235783Skib} 565235783Skib 566235783Skibstatic tree 567235783Skibaarch64_simd_builtin_type (enum machine_mode mode, 568235783Skib bool unsigned_p, bool poly_p) 569235783Skib{ 570235783Skib if (poly_p) 571235783Skib return aarch64_lookup_simd_builtin_type (mode, qualifier_poly); 572235783Skib else if (unsigned_p) 573235783Skib return aarch64_lookup_simd_builtin_type (mode, qualifier_unsigned); 574235783Skib else 575235783Skib return aarch64_lookup_simd_builtin_type (mode, qualifier_none); 576235783Skib} 577235783Skib 578235783Skibstatic void 579235783Skibaarch64_init_simd_builtin_types (void) 580235783Skib{ 581235783Skib int i; 582235783Skib int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]); 583235783Skib tree tdecl; 584235783Skib 585235783Skib /* Init all the element types built by the front-end. */ 586235783Skib aarch64_simd_types[Int8x8_t].eltype = intQI_type_node; 587235783Skib aarch64_simd_types[Int8x16_t].eltype = intQI_type_node; 588235783Skib aarch64_simd_types[Int16x4_t].eltype = intHI_type_node; 589235783Skib aarch64_simd_types[Int16x8_t].eltype = intHI_type_node; 590235783Skib aarch64_simd_types[Int32x2_t].eltype = intSI_type_node; 591235783Skib aarch64_simd_types[Int32x4_t].eltype = intSI_type_node; 592235783Skib aarch64_simd_types[Int64x1_t].eltype = intDI_type_node; 593235783Skib aarch64_simd_types[Int64x2_t].eltype = intDI_type_node; 594235783Skib aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node; 595235783Skib aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node; 596235783Skib aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node; 597235783Skib aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node; 598235783Skib aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node; 599235783Skib aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node; 600235783Skib aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node; 601235783Skib aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node; 602235783Skib 603235783Skib /* Poly types are a world of their own. */ 604235783Skib aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype = 605235783Skib build_distinct_type_copy (unsigned_intQI_type_node); 606235783Skib aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype = 607235783Skib build_distinct_type_copy (unsigned_intHI_type_node); 608235783Skib aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype = 609235783Skib build_distinct_type_copy (unsigned_intDI_type_node); 610235783Skib aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype = 611235783Skib build_distinct_type_copy (unsigned_intTI_type_node); 612235783Skib /* Init poly vector element types with scalar poly types. */ 613235783Skib aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype; 614235783Skib aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype; 615235783Skib aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype; 616235783Skib aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype; 617235783Skib aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype; 618235783Skib aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype; 619235783Skib 620235783Skib /* Continue with standard types. */ 621235783Skib aarch64_simd_types[Float32x2_t].eltype = float_type_node; 622235783Skib aarch64_simd_types[Float32x4_t].eltype = float_type_node; 623235783Skib aarch64_simd_types[Float64x1_t].eltype = double_type_node; 624235783Skib aarch64_simd_types[Float64x2_t].eltype = double_type_node; 625235783Skib 626235783Skib for (i = 0; i < nelts; i++) 627235783Skib { 628235783Skib tree eltype = aarch64_simd_types[i].eltype; 629235783Skib enum machine_mode mode = aarch64_simd_types[i].mode; 630235783Skib 631235783Skib if (aarch64_simd_types[i].itype == NULL) 632235783Skib { 633235783Skib aarch64_simd_types[i].itype 634235783Skib = build_distinct_type_copy 635235783Skib (build_vector_type (eltype, GET_MODE_NUNITS (mode))); 636235783Skib SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype); 637235783Skib } 638235783Skib 639235783Skib tdecl = add_builtin_type (aarch64_simd_types[i].name, 640235783Skib aarch64_simd_types[i].itype); 641235783Skib TYPE_NAME (aarch64_simd_types[i].itype) = tdecl; 642235783Skib } 643235783Skib 644235783Skib#define AARCH64_BUILD_SIGNED_TYPE(mode) \ 645235783Skib make_signed_type (GET_MODE_PRECISION (mode)); 646235783Skib aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode); 647235783Skib aarch64_simd_intEI_type_node = AARCH64_BUILD_SIGNED_TYPE (EImode); 648235783Skib aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode); 649235783Skib aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode); 650235783Skib#undef AARCH64_BUILD_SIGNED_TYPE 651235783Skib 652235783Skib tdecl = add_builtin_type 653235783Skib ("__builtin_aarch64_simd_ei" , aarch64_simd_intEI_type_node); 654235783Skib TYPE_NAME (aarch64_simd_intEI_type_node) = tdecl; 655235783Skib tdecl = add_builtin_type 656235783Skib ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node); 657235783Skib TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl; 658235783Skib tdecl = add_builtin_type 659235783Skib ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node); 660235783Skib TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl; 661235783Skib tdecl = add_builtin_type 662235783Skib ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node); 663235783Skib TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl; 664235783Skib} 665235783Skib 666235783Skibstatic void 667235783Skibaarch64_init_simd_builtin_scalar_types (void) 668235783Skib{ 669235783Skib /* Define typedefs for all the standard scalar types. */ 670235783Skib (*lang_hooks.types.register_builtin_type) (intQI_type_node, 671235783Skib "__builtin_aarch64_simd_qi"); 672235783Skib (*lang_hooks.types.register_builtin_type) (intHI_type_node, 673235783Skib "__builtin_aarch64_simd_hi"); 674235783Skib (*lang_hooks.types.register_builtin_type) (intSI_type_node, 675235783Skib "__builtin_aarch64_simd_si"); 676235783Skib (*lang_hooks.types.register_builtin_type) (float_type_node, 677235783Skib "__builtin_aarch64_simd_sf"); 678235783Skib (*lang_hooks.types.register_builtin_type) (intDI_type_node, 679235783Skib "__builtin_aarch64_simd_di"); 680235783Skib (*lang_hooks.types.register_builtin_type) (double_type_node, 681235783Skib "__builtin_aarch64_simd_df"); 682235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node, 683235783Skib "__builtin_aarch64_simd_poly8"); 684235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node, 685235783Skib "__builtin_aarch64_simd_poly16"); 686235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node, 687235783Skib "__builtin_aarch64_simd_poly64"); 688235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node, 689235783Skib "__builtin_aarch64_simd_poly128"); 690235783Skib (*lang_hooks.types.register_builtin_type) (intTI_type_node, 691235783Skib "__builtin_aarch64_simd_ti"); 692235783Skib /* Unsigned integer types for various mode sizes. */ 693235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node, 694235783Skib "__builtin_aarch64_simd_uqi"); 695235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node, 696235783Skib "__builtin_aarch64_simd_uhi"); 697235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node, 698235783Skib "__builtin_aarch64_simd_usi"); 699235783Skib (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node, 700235783Skib "__builtin_aarch64_simd_udi"); 701235783Skib} 702235783Skib 703235783Skibstatic void 704235783Skibaarch64_init_simd_builtins (void) 705235783Skib{ 706235783Skib unsigned int i, fcode = AARCH64_SIMD_PATTERN_START; 707235783Skib 708235783Skib aarch64_init_simd_builtin_types (); 709235783Skib 710235783Skib /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics. 711235783Skib Therefore we need to preserve the old __builtin scalar types. It can be 712235783Skib removed once all the intrinsics become strongly typed using the qualifier 713235783Skib system. */ 714235783Skib aarch64_init_simd_builtin_scalar_types (); 715235783Skib 716235783Skib tree lane_check_fpr = build_function_type_list (void_type_node, 717235783Skib size_type_node, 718235783Skib size_type_node, 719235783Skib intSI_type_node, 720235783Skib NULL); 721235783Skib aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] = 722235783Skib add_builtin_function ("__builtin_aarch64_im_lane_boundsi", lane_check_fpr, 723235783Skib AARCH64_SIMD_BUILTIN_LANE_CHECK, BUILT_IN_MD, 724235783Skib NULL, NULL_TREE); 725235783Skib 726235783Skib for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++) 727235783Skib { 728235783Skib bool print_type_signature_p = false; 729235783Skib char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 }; 730235783Skib aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i]; 731235783Skib char namebuf[60]; 732235783Skib tree ftype = NULL; 733235783Skib tree fndecl = NULL; 734235783Skib 735235783Skib d->fcode = fcode; 736235783Skib 737235783Skib /* We must track two variables here. op_num is 738235783Skib the operand number as in the RTL pattern. This is 739235783Skib required to access the mode (e.g. V4SF mode) of the 740235783Skib argument, from which the base type can be derived. 741235783Skib arg_num is an index in to the qualifiers data, which 742235783Skib gives qualifiers to the type (e.g. const unsigned). 743235783Skib The reason these two variables may differ by one is the 744235783Skib void return type. While all return types take the 0th entry 745235783Skib in the qualifiers array, there is no operand for them in the 746235783Skib RTL pattern. */ 747235783Skib int op_num = insn_data[d->code].n_operands - 1; 748235783Skib int arg_num = d->qualifiers[0] & qualifier_void 749235783Skib ? op_num + 1 750235783Skib : op_num; 751235783Skib tree return_type = void_type_node, args = void_list_node; 752235783Skib tree eltype; 753235783Skib 754235783Skib /* Build a function type directly from the insn_data for this 755235783Skib builtin. The build_function_type () function takes care of 756235783Skib removing duplicates for us. */ 757235783Skib for (; op_num >= 0; arg_num--, op_num--) 758235783Skib { 759235783Skib machine_mode op_mode = insn_data[d->code].operand[op_num].mode; 760235783Skib enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num]; 761235783Skib 762235783Skib if (qualifiers & qualifier_unsigned) 763235783Skib { 764235783Skib type_signature[arg_num] = 'u'; 765235783Skib print_type_signature_p = true; 766235783Skib } 767235783Skib else if (qualifiers & qualifier_poly) 768235783Skib { 769235783Skib type_signature[arg_num] = 'p'; 770235783Skib print_type_signature_p = true; 771235783Skib } 772235783Skib else 773235783Skib type_signature[arg_num] = 's'; 774235783Skib 775235783Skib /* Skip an internal operand for vget_{low, high}. */ 776235783Skib if (qualifiers & qualifier_internal) 777235783Skib continue; 778235783Skib 779235783Skib /* Some builtins have different user-facing types 780235783Skib for certain arguments, encoded in d->mode. */ 781235783Skib if (qualifiers & qualifier_map_mode) 782235783Skib op_mode = d->mode; 783235783Skib 784235783Skib /* For pointers, we want a pointer to the basic type 785235783Skib of the vector. */ 786235783Skib if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode)) 787235783Skib op_mode = GET_MODE_INNER (op_mode); 788235783Skib 789235783Skib eltype = aarch64_simd_builtin_type 790235783Skib (op_mode, 791235783Skib (qualifiers & qualifier_unsigned) != 0, 792235783Skib (qualifiers & qualifier_poly) != 0); 793235783Skib gcc_assert (eltype != NULL); 794235783Skib 795235783Skib /* Add qualifiers. */ 796235783Skib if (qualifiers & qualifier_const) 797235783Skib eltype = build_qualified_type (eltype, TYPE_QUAL_CONST); 798235783Skib 799235783Skib if (qualifiers & qualifier_pointer) 800235783Skib eltype = build_pointer_type (eltype); 801235783Skib 802235783Skib /* If we have reached arg_num == 0, we are at a non-void 803235783Skib return type. Otherwise, we are still processing 804235783Skib arguments. */ 805235783Skib if (arg_num == 0) 806235783Skib return_type = eltype; 807235783Skib else 808235783Skib args = tree_cons (NULL_TREE, eltype, args); 809235783Skib } 810235783Skib 811235783Skib ftype = build_function_type (return_type, args); 812235783Skib 813235783Skib gcc_assert (ftype != NULL); 814235783Skib 815235783Skib if (print_type_signature_p) 816235783Skib snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s", 817235783Skib d->name, type_signature); 818235783Skib else 819235783Skib snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s", 820235783Skib d->name); 821235783Skib 822235783Skib fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD, 823235783Skib NULL, NULL_TREE); 824235783Skib aarch64_builtin_decls[fcode] = fndecl; 825235783Skib } 826235783Skib} 827235783Skib 828235783Skibstatic void 829235783Skibaarch64_init_crc32_builtins () 830235783Skib{ 831235783Skib tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned); 832235783Skib unsigned int i = 0; 833235783Skib 834235783Skib for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i) 835235783Skib { 836235783Skib aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i]; 837235783Skib tree argtype = aarch64_simd_builtin_std_type (d->mode, 838235783Skib qualifier_unsigned); 839235783Skib tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE); 840235783Skib tree fndecl = add_builtin_function (d->name, ftype, d->fcode, 841235783Skib BUILT_IN_MD, NULL, NULL_TREE); 842235783Skib 843235783Skib aarch64_builtin_decls[d->fcode] = fndecl; 844235783Skib } 845235783Skib} 846235783Skib 847235783Skibvoid 848235783Skibaarch64_init_builtins (void) 849235783Skib{ 850235783Skib tree ftype_set_fpr 851235783Skib = build_function_type_list (void_type_node, unsigned_type_node, NULL); 852235783Skib tree ftype_get_fpr 853235783Skib = build_function_type_list (unsigned_type_node, NULL); 854235783Skib 855235783Skib aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR] 856235783Skib = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr, 857235783Skib AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE); 858235783Skib aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR] 859235783Skib = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr, 860235783Skib AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE); 861235783Skib aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR] 862235783Skib = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr, 863235783Skib AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE); 864235783Skib aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR] 865235783Skib = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr, 866235783Skib AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE); 867235783Skib 868235783Skib if (TARGET_SIMD) 869235783Skib aarch64_init_simd_builtins (); 870235783Skib if (TARGET_CRC32) 871235783Skib aarch64_init_crc32_builtins (); 872235783Skib} 873235783Skib 874235783Skibtree 875235783Skibaarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) 876235783Skib{ 877235783Skib if (code >= AARCH64_BUILTIN_MAX) 878235783Skib return error_mark_node; 879235783Skib 880235783Skib return aarch64_builtin_decls[code]; 881235783Skib} 882235783Skib 883235783Skibtypedef enum 884235783Skib{ 885235783Skib SIMD_ARG_COPY_TO_REG, 886235783Skib SIMD_ARG_CONSTANT, 887235783Skib SIMD_ARG_LANE_INDEX, 888235783Skib SIMD_ARG_STOP 889235783Skib} builtin_simd_arg; 890235783Skib 891235783Skibstatic rtx 892235783Skibaarch64_simd_expand_args (rtx target, int icode, int have_retval, 893235783Skib tree exp, builtin_simd_arg *args) 894235783Skib{ 895235783Skib rtx pat; 896235783Skib rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */ 897235783Skib int opc = 0; 898235783Skib 899235783Skib if (have_retval) 900235783Skib { 901235783Skib machine_mode tmode = insn_data[icode].operand[0].mode; 902235783Skib if (!target 903235783Skib || GET_MODE (target) != tmode 904235783Skib || !(*insn_data[icode].operand[0].predicate) (target, tmode)) 905235783Skib target = gen_reg_rtx (tmode); 906235783Skib op[opc++] = target; 907235783Skib } 908235783Skib 909235783Skib for (;;) 910235783Skib { 911235783Skib builtin_simd_arg thisarg = args[opc - have_retval]; 912235783Skib 913235783Skib if (thisarg == SIMD_ARG_STOP) 914235783Skib break; 915235783Skib else 916235783Skib { 917235783Skib tree arg = CALL_EXPR_ARG (exp, opc - have_retval); 918235783Skib enum machine_mode mode = insn_data[icode].operand[opc].mode; 919235783Skib op[opc] = expand_normal (arg); 920235783Skib 921235783Skib switch (thisarg) 922235783Skib { 923235783Skib case SIMD_ARG_COPY_TO_REG: 924235783Skib if (POINTER_TYPE_P (TREE_TYPE (arg))) 925235783Skib op[opc] = convert_memory_address (Pmode, op[opc]); 926235783Skib /*gcc_assert (GET_MODE (op[opc]) == mode); */ 927235783Skib if (!(*insn_data[icode].operand[opc].predicate) 928235783Skib (op[opc], mode)) 929235783Skib op[opc] = copy_to_mode_reg (mode, op[opc]); 930235783Skib break; 931235783Skib 932235783Skib case SIMD_ARG_LANE_INDEX: 933235783Skib /* Must be a previous operand into which this is an index. */ 934235783Skib gcc_assert (opc > 0); 935235783Skib if (CONST_INT_P (op[opc])) 936235783Skib { 937235783Skib machine_mode vmode = insn_data[icode].operand[opc - 1].mode; 938235783Skib aarch64_simd_lane_bounds (op[opc], 939235783Skib 0, GET_MODE_NUNITS (vmode), exp); 940235783Skib /* Keep to GCC-vector-extension lane indices in the RTL. */ 941235783Skib op[opc] = GEN_INT (ENDIAN_LANE_N (vmode, INTVAL (op[opc]))); 942235783Skib } 943235783Skib /* Fall through - if the lane index isn't a constant then 944235783Skib the next case will error. */ 945235783Skib case SIMD_ARG_CONSTANT: 946235783Skib if (!(*insn_data[icode].operand[opc].predicate) 947235783Skib (op[opc], mode)) 948235783Skib { 949235783Skib error ("%Kargument %d must be a constant immediate", 950235783Skib exp, opc + 1 - have_retval); 951235783Skib return const0_rtx; 952235783Skib } 953235783Skib break; 954235783Skib 955235783Skib case SIMD_ARG_STOP: 956235783Skib gcc_unreachable (); 957235783Skib } 958235783Skib 959235783Skib opc++; 960235783Skib } 961235783Skib } 962235783Skib 963235783Skib switch (opc) 964235783Skib { 965235783Skib case 1: 966235783Skib pat = GEN_FCN (icode) (op[0]); 967235783Skib break; 968235783Skib 969235783Skib case 2: 970235783Skib pat = GEN_FCN (icode) (op[0], op[1]); 971235783Skib break; 972 973 case 3: 974 pat = GEN_FCN (icode) (op[0], op[1], op[2]); 975 break; 976 977 case 4: 978 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); 979 break; 980 981 case 5: 982 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]); 983 break; 984 985 case 6: 986 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]); 987 break; 988 989 default: 990 gcc_unreachable (); 991 } 992 993 if (!pat) 994 return NULL_RTX; 995 996 emit_insn (pat); 997 998 return target; 999} 1000 1001/* Expand an AArch64 AdvSIMD builtin(intrinsic). */ 1002rtx 1003aarch64_simd_expand_builtin (int fcode, tree exp, rtx target) 1004{ 1005 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK) 1006 { 1007 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0)); 1008 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1)); 1009 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize) 1010 && UINTVAL (elementsize) != 0 1011 && UINTVAL (totalsize) != 0) 1012 { 1013 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2)); 1014 if (CONST_INT_P (lane_idx)) 1015 aarch64_simd_lane_bounds (lane_idx, 0, 1016 UINTVAL (totalsize) 1017 / UINTVAL (elementsize), 1018 exp); 1019 else 1020 error ("%Klane index must be a constant immediate", exp); 1021 } 1022 else 1023 error ("%Ktotal size and element size must be a non-zero constant immediate", exp); 1024 /* Don't generate any RTL. */ 1025 return const0_rtx; 1026 } 1027 aarch64_simd_builtin_datum *d = 1028 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START]; 1029 enum insn_code icode = d->code; 1030 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1]; 1031 int num_args = insn_data[d->code].n_operands; 1032 int is_void = 0; 1033 int k; 1034 1035 is_void = !!(d->qualifiers[0] & qualifier_void); 1036 1037 num_args += is_void; 1038 1039 for (k = 1; k < num_args; k++) 1040 { 1041 /* We have four arrays of data, each indexed in a different fashion. 1042 qualifiers - element 0 always describes the function return type. 1043 operands - element 0 is either the operand for return value (if 1044 the function has a non-void return type) or the operand for the 1045 first argument. 1046 expr_args - element 0 always holds the first argument. 1047 args - element 0 is always used for the return type. */ 1048 int qualifiers_k = k; 1049 int operands_k = k - is_void; 1050 int expr_args_k = k - 1; 1051 1052 if (d->qualifiers[qualifiers_k] & qualifier_lane_index) 1053 args[k] = SIMD_ARG_LANE_INDEX; 1054 else if (d->qualifiers[qualifiers_k] & qualifier_immediate) 1055 args[k] = SIMD_ARG_CONSTANT; 1056 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate) 1057 { 1058 rtx arg 1059 = expand_normal (CALL_EXPR_ARG (exp, 1060 (expr_args_k))); 1061 /* Handle constants only if the predicate allows it. */ 1062 bool op_const_int_p = 1063 (CONST_INT_P (arg) 1064 && (*insn_data[icode].operand[operands_k].predicate) 1065 (arg, insn_data[icode].operand[operands_k].mode)); 1066 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG; 1067 } 1068 else 1069 args[k] = SIMD_ARG_COPY_TO_REG; 1070 1071 } 1072 args[k] = SIMD_ARG_STOP; 1073 1074 /* The interface to aarch64_simd_expand_args expects a 0 if 1075 the function is void, and a 1 if it is not. */ 1076 return aarch64_simd_expand_args 1077 (target, icode, !is_void, exp, &args[1]); 1078} 1079 1080rtx 1081aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target) 1082{ 1083 rtx pat; 1084 aarch64_crc_builtin_datum *d 1085 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)]; 1086 enum insn_code icode = d->icode; 1087 tree arg0 = CALL_EXPR_ARG (exp, 0); 1088 tree arg1 = CALL_EXPR_ARG (exp, 1); 1089 rtx op0 = expand_normal (arg0); 1090 rtx op1 = expand_normal (arg1); 1091 machine_mode tmode = insn_data[icode].operand[0].mode; 1092 machine_mode mode0 = insn_data[icode].operand[1].mode; 1093 machine_mode mode1 = insn_data[icode].operand[2].mode; 1094 1095 if (! target 1096 || GET_MODE (target) != tmode 1097 || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) 1098 target = gen_reg_rtx (tmode); 1099 1100 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode) 1101 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode)); 1102 1103 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) 1104 op0 = copy_to_mode_reg (mode0, op0); 1105 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) 1106 op1 = copy_to_mode_reg (mode1, op1); 1107 1108 pat = GEN_FCN (icode) (target, op0, op1); 1109 if (!pat) 1110 return NULL_RTX; 1111 1112 emit_insn (pat); 1113 return target; 1114} 1115 1116/* Expand an expression EXP that calls a built-in function, 1117 with result going to TARGET if that's convenient. */ 1118rtx 1119aarch64_expand_builtin (tree exp, 1120 rtx target, 1121 rtx subtarget ATTRIBUTE_UNUSED, 1122 machine_mode mode ATTRIBUTE_UNUSED, 1123 int ignore ATTRIBUTE_UNUSED) 1124{ 1125 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); 1126 int fcode = DECL_FUNCTION_CODE (fndecl); 1127 int icode; 1128 rtx pat, op0; 1129 tree arg0; 1130 1131 switch (fcode) 1132 { 1133 case AARCH64_BUILTIN_GET_FPCR: 1134 case AARCH64_BUILTIN_SET_FPCR: 1135 case AARCH64_BUILTIN_GET_FPSR: 1136 case AARCH64_BUILTIN_SET_FPSR: 1137 if ((fcode == AARCH64_BUILTIN_GET_FPCR) 1138 || (fcode == AARCH64_BUILTIN_GET_FPSR)) 1139 { 1140 icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ? 1141 CODE_FOR_get_fpsr : CODE_FOR_get_fpcr; 1142 target = gen_reg_rtx (SImode); 1143 pat = GEN_FCN (icode) (target); 1144 } 1145 else 1146 { 1147 target = NULL_RTX; 1148 icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ? 1149 CODE_FOR_set_fpsr : CODE_FOR_set_fpcr; 1150 arg0 = CALL_EXPR_ARG (exp, 0); 1151 op0 = expand_normal (arg0); 1152 pat = GEN_FCN (icode) (op0); 1153 } 1154 emit_insn (pat); 1155 return target; 1156 } 1157 1158 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX) 1159 return aarch64_simd_expand_builtin (fcode, exp, target); 1160 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX) 1161 return aarch64_crc32_expand_builtin (fcode, exp, target); 1162 1163 gcc_unreachable (); 1164} 1165 1166tree 1167aarch64_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in) 1168{ 1169 machine_mode in_mode, out_mode; 1170 int in_n, out_n; 1171 1172 if (TREE_CODE (type_out) != VECTOR_TYPE 1173 || TREE_CODE (type_in) != VECTOR_TYPE) 1174 return NULL_TREE; 1175 1176 out_mode = TYPE_MODE (TREE_TYPE (type_out)); 1177 out_n = TYPE_VECTOR_SUBPARTS (type_out); 1178 in_mode = TYPE_MODE (TREE_TYPE (type_in)); 1179 in_n = TYPE_VECTOR_SUBPARTS (type_in); 1180 1181#undef AARCH64_CHECK_BUILTIN_MODE 1182#define AARCH64_CHECK_BUILTIN_MODE(C, N) 1 1183#define AARCH64_FIND_FRINT_VARIANT(N) \ 1184 (AARCH64_CHECK_BUILTIN_MODE (2, D) \ 1185 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \ 1186 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \ 1187 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \ 1188 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \ 1189 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \ 1190 : NULL_TREE))) 1191 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) 1192 { 1193 enum built_in_function fn = DECL_FUNCTION_CODE (fndecl); 1194 switch (fn) 1195 { 1196#undef AARCH64_CHECK_BUILTIN_MODE 1197#define AARCH64_CHECK_BUILTIN_MODE(C, N) \ 1198 (out_mode == N##Fmode && out_n == C \ 1199 && in_mode == N##Fmode && in_n == C) 1200 case BUILT_IN_FLOOR: 1201 case BUILT_IN_FLOORF: 1202 return AARCH64_FIND_FRINT_VARIANT (floor); 1203 case BUILT_IN_CEIL: 1204 case BUILT_IN_CEILF: 1205 return AARCH64_FIND_FRINT_VARIANT (ceil); 1206 case BUILT_IN_TRUNC: 1207 case BUILT_IN_TRUNCF: 1208 return AARCH64_FIND_FRINT_VARIANT (btrunc); 1209 case BUILT_IN_ROUND: 1210 case BUILT_IN_ROUNDF: 1211 return AARCH64_FIND_FRINT_VARIANT (round); 1212 case BUILT_IN_NEARBYINT: 1213 case BUILT_IN_NEARBYINTF: 1214 return AARCH64_FIND_FRINT_VARIANT (nearbyint); 1215 case BUILT_IN_SQRT: 1216 case BUILT_IN_SQRTF: 1217 return AARCH64_FIND_FRINT_VARIANT (sqrt); 1218#undef AARCH64_CHECK_BUILTIN_MODE 1219#define AARCH64_CHECK_BUILTIN_MODE(C, N) \ 1220 (out_mode == SImode && out_n == C \ 1221 && in_mode == N##Imode && in_n == C) 1222 case BUILT_IN_CLZ: 1223 { 1224 if (AARCH64_CHECK_BUILTIN_MODE (4, S)) 1225 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si]; 1226 return NULL_TREE; 1227 } 1228 case BUILT_IN_CTZ: 1229 { 1230 if (AARCH64_CHECK_BUILTIN_MODE (2, S)) 1231 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si]; 1232 else if (AARCH64_CHECK_BUILTIN_MODE (4, S)) 1233 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si]; 1234 return NULL_TREE; 1235 } 1236#undef AARCH64_CHECK_BUILTIN_MODE 1237#define AARCH64_CHECK_BUILTIN_MODE(C, N) \ 1238 (out_mode == N##Imode && out_n == C \ 1239 && in_mode == N##Fmode && in_n == C) 1240 case BUILT_IN_LFLOOR: 1241 case BUILT_IN_LFLOORF: 1242 case BUILT_IN_LLFLOOR: 1243 case BUILT_IN_IFLOORF: 1244 { 1245 enum aarch64_builtins builtin; 1246 if (AARCH64_CHECK_BUILTIN_MODE (2, D)) 1247 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di; 1248 else if (AARCH64_CHECK_BUILTIN_MODE (4, S)) 1249 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si; 1250 else if (AARCH64_CHECK_BUILTIN_MODE (2, S)) 1251 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si; 1252 else 1253 return NULL_TREE; 1254 1255 return aarch64_builtin_decls[builtin]; 1256 } 1257 case BUILT_IN_LCEIL: 1258 case BUILT_IN_LCEILF: 1259 case BUILT_IN_LLCEIL: 1260 case BUILT_IN_ICEILF: 1261 { 1262 enum aarch64_builtins builtin; 1263 if (AARCH64_CHECK_BUILTIN_MODE (2, D)) 1264 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di; 1265 else if (AARCH64_CHECK_BUILTIN_MODE (4, S)) 1266 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si; 1267 else if (AARCH64_CHECK_BUILTIN_MODE (2, S)) 1268 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si; 1269 else 1270 return NULL_TREE; 1271 1272 return aarch64_builtin_decls[builtin]; 1273 } 1274 case BUILT_IN_LROUND: 1275 case BUILT_IN_IROUNDF: 1276 { 1277 enum aarch64_builtins builtin; 1278 if (AARCH64_CHECK_BUILTIN_MODE (2, D)) 1279 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di; 1280 else if (AARCH64_CHECK_BUILTIN_MODE (4, S)) 1281 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si; 1282 else if (AARCH64_CHECK_BUILTIN_MODE (2, S)) 1283 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si; 1284 else 1285 return NULL_TREE; 1286 1287 return aarch64_builtin_decls[builtin]; 1288 } 1289 case BUILT_IN_BSWAP16: 1290#undef AARCH64_CHECK_BUILTIN_MODE 1291#define AARCH64_CHECK_BUILTIN_MODE(C, N) \ 1292 (out_mode == N##Imode && out_n == C \ 1293 && in_mode == N##Imode && in_n == C) 1294 if (AARCH64_CHECK_BUILTIN_MODE (4, H)) 1295 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi]; 1296 else if (AARCH64_CHECK_BUILTIN_MODE (8, H)) 1297 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi]; 1298 else 1299 return NULL_TREE; 1300 case BUILT_IN_BSWAP32: 1301 if (AARCH64_CHECK_BUILTIN_MODE (2, S)) 1302 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si]; 1303 else if (AARCH64_CHECK_BUILTIN_MODE (4, S)) 1304 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si]; 1305 else 1306 return NULL_TREE; 1307 case BUILT_IN_BSWAP64: 1308 if (AARCH64_CHECK_BUILTIN_MODE (2, D)) 1309 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di]; 1310 else 1311 return NULL_TREE; 1312 default: 1313 return NULL_TREE; 1314 } 1315 } 1316 1317 return NULL_TREE; 1318} 1319 1320#undef VAR1 1321#define VAR1(T, N, MAP, A) \ 1322 case AARCH64_SIMD_BUILTIN_##T##_##N##A: 1323 1324tree 1325aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args, 1326 bool ignore ATTRIBUTE_UNUSED) 1327{ 1328 int fcode = DECL_FUNCTION_CODE (fndecl); 1329 tree type = TREE_TYPE (TREE_TYPE (fndecl)); 1330 1331 switch (fcode) 1332 { 1333 BUILTIN_VDQF (UNOP, abs, 2) 1334 return fold_build1 (ABS_EXPR, type, args[0]); 1335 break; 1336 VAR1 (UNOP, floatv2si, 2, v2sf) 1337 VAR1 (UNOP, floatv4si, 2, v4sf) 1338 VAR1 (UNOP, floatv2di, 2, v2df) 1339 return fold_build1 (FLOAT_EXPR, type, args[0]); 1340 default: 1341 break; 1342 } 1343 1344 return NULL_TREE; 1345} 1346 1347bool 1348aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) 1349{ 1350 bool changed = false; 1351 gimple stmt = gsi_stmt (*gsi); 1352 tree call = gimple_call_fn (stmt); 1353 tree fndecl; 1354 gimple new_stmt = NULL; 1355 1356 if (call) 1357 { 1358 fndecl = gimple_call_fndecl (stmt); 1359 if (fndecl) 1360 { 1361 int fcode = DECL_FUNCTION_CODE (fndecl); 1362 int nargs = gimple_call_num_args (stmt); 1363 tree *args = (nargs > 0 1364 ? gimple_call_arg_ptr (stmt, 0) 1365 : &error_mark_node); 1366 1367 /* We use gimple's REDUC_(PLUS|MIN|MAX)_EXPRs for float, signed int 1368 and unsigned int; it will distinguish according to the types of 1369 the arguments to the __builtin. */ 1370 switch (fcode) 1371 { 1372 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10) 1373 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 1374 REDUC_PLUS_EXPR, args[0]); 1375 break; 1376 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10) 1377 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10) 1378 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 1379 REDUC_MAX_EXPR, args[0]); 1380 break; 1381 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10) 1382 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10) 1383 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), 1384 REDUC_MIN_EXPR, args[0]); 1385 break; 1386 1387 default: 1388 break; 1389 } 1390 } 1391 } 1392 1393 if (new_stmt) 1394 { 1395 gsi_replace (gsi, new_stmt, true); 1396 changed = true; 1397 } 1398 1399 return changed; 1400} 1401 1402void 1403aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) 1404{ 1405 const unsigned AARCH64_FE_INVALID = 1; 1406 const unsigned AARCH64_FE_DIVBYZERO = 2; 1407 const unsigned AARCH64_FE_OVERFLOW = 4; 1408 const unsigned AARCH64_FE_UNDERFLOW = 8; 1409 const unsigned AARCH64_FE_INEXACT = 16; 1410 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID 1411 | AARCH64_FE_DIVBYZERO 1412 | AARCH64_FE_OVERFLOW 1413 | AARCH64_FE_UNDERFLOW 1414 | AARCH64_FE_INEXACT); 1415 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8; 1416 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr; 1417 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr; 1418 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr; 1419 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv; 1420 1421 /* Generate the equivalence of : 1422 unsigned int fenv_cr; 1423 fenv_cr = __builtin_aarch64_get_fpcr (); 1424 1425 unsigned int fenv_sr; 1426 fenv_sr = __builtin_aarch64_get_fpsr (); 1427 1428 Now set all exceptions to non-stop 1429 unsigned int mask_cr 1430 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT); 1431 unsigned int masked_cr; 1432 masked_cr = fenv_cr & mask_cr; 1433 1434 And clear all exception flags 1435 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT; 1436 unsigned int masked_cr; 1437 masked_sr = fenv_sr & mask_sr; 1438 1439 __builtin_aarch64_set_cr (masked_cr); 1440 __builtin_aarch64_set_sr (masked_sr); */ 1441 1442 fenv_cr = create_tmp_var (unsigned_type_node); 1443 fenv_sr = create_tmp_var (unsigned_type_node); 1444 1445 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]; 1446 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]; 1447 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]; 1448 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]; 1449 1450 mask_cr = build_int_cst (unsigned_type_node, 1451 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT)); 1452 mask_sr = build_int_cst (unsigned_type_node, 1453 ~(AARCH64_FE_ALL_EXCEPT)); 1454 1455 ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node, 1456 fenv_cr, build_call_expr (get_fpcr, 0)); 1457 ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node, 1458 fenv_sr, build_call_expr (get_fpsr, 0)); 1459 1460 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr); 1461 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr); 1462 1463 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr); 1464 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr); 1465 1466 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr, 1467 hold_fnclex_sr); 1468 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr, 1469 masked_fenv_sr); 1470 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr); 1471 1472 *hold = build2 (COMPOUND_EXPR, void_type_node, 1473 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv), 1474 hold_fnclex); 1475 1476 /* Store the value of masked_fenv to clear the exceptions: 1477 __builtin_aarch64_set_fpsr (masked_fenv_sr); */ 1478 1479 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr); 1480 1481 /* Generate the equivalent of : 1482 unsigned int new_fenv_var; 1483 new_fenv_var = __builtin_aarch64_get_fpsr (); 1484 1485 __builtin_aarch64_set_fpsr (fenv_sr); 1486 1487 __atomic_feraiseexcept (new_fenv_var); */ 1488 1489 new_fenv_var = create_tmp_var (unsigned_type_node); 1490 reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node, 1491 new_fenv_var, build_call_expr (get_fpsr, 0)); 1492 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr); 1493 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); 1494 update_call = build_call_expr (atomic_feraiseexcept, 1, 1495 fold_convert (integer_type_node, new_fenv_var)); 1496 *update = build2 (COMPOUND_EXPR, void_type_node, 1497 build2 (COMPOUND_EXPR, void_type_node, 1498 reload_fenv, restore_fnenv), update_call); 1499} 1500 1501 1502#undef AARCH64_CHECK_BUILTIN_MODE 1503#undef AARCH64_FIND_FRINT_VARIANT 1504#undef CF0 1505#undef CF1 1506#undef CF2 1507#undef CF3 1508#undef CF4 1509#undef CF10 1510#undef VAR1 1511#undef VAR2 1512#undef VAR3 1513#undef VAR4 1514#undef VAR5 1515#undef VAR6 1516#undef VAR7 1517#undef VAR8 1518#undef VAR9 1519#undef VAR10 1520#undef VAR11 1521 1522#include "gt-aarch64-builtins.h" 1523