1;; Machine Description for shared bits common to IWMMXT and Neon. 2;; Copyright (C) 2006-2021 Free Software Foundation, Inc. 3;; Written by CodeSourcery. 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;; Vector Moves 22 23(define_expand "mov<mode>" 24 [(set (match_operand:VNIM1 0 "nonimmediate_operand") 25 (match_operand:VNIM1 1 "general_operand"))] 26 "TARGET_NEON 27 || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode)) 28 || (TARGET_HAVE_MVE && VALID_MVE_SI_MODE (<MODE>mode)) 29 || (TARGET_HAVE_MVE_FLOAT && VALID_MVE_SF_MODE (<MODE>mode))" 30 { 31 gcc_checking_assert (aligned_operand (operands[0], <MODE>mode)); 32 gcc_checking_assert (aligned_operand (operands[1], <MODE>mode)); 33 if (can_create_pseudo_p ()) 34 { 35 if (!REG_P (operands[0])) 36 operands[1] = force_reg (<MODE>mode, operands[1]); 37 else if ((TARGET_NEON || TARGET_HAVE_MVE || TARGET_HAVE_MVE_FLOAT) 38 && (CONSTANT_P (operands[1]))) 39 { 40 operands[1] = neon_make_constant (operands[1]); 41 gcc_assert (operands[1] != NULL_RTX); 42 } 43 } 44}) 45 46(define_expand "mov<mode>" 47 [(set (match_operand:VNINOTM1 0 "nonimmediate_operand") 48 (match_operand:VNINOTM1 1 "general_operand"))] 49 "TARGET_NEON 50 || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))" 51{ 52 gcc_checking_assert (aligned_operand (operands[0], <MODE>mode)); 53 gcc_checking_assert (aligned_operand (operands[1], <MODE>mode)); 54 if (can_create_pseudo_p ()) 55 { 56 if (!REG_P (operands[0])) 57 operands[1] = force_reg (<MODE>mode, operands[1]); 58 else if (TARGET_NEON && CONSTANT_P (operands[1])) 59 { 60 operands[1] = neon_make_constant (operands[1]); 61 gcc_assert (operands[1] != NULL_RTX); 62 } 63 } 64}) 65 66(define_expand "movv8hf" 67 [(set (match_operand:V8HF 0 "s_register_operand") 68 (match_operand:V8HF 1 "s_register_operand"))] 69 "TARGET_NEON || TARGET_HAVE_MVE_FLOAT" 70{ 71 gcc_checking_assert (aligned_operand (operands[0], E_V8HFmode)); 72 gcc_checking_assert (aligned_operand (operands[1], E_V8HFmode)); 73 if (can_create_pseudo_p ()) 74 { 75 if (!REG_P (operands[0])) 76 operands[1] = force_reg (E_V8HFmode, operands[1]); 77 else if (TARGET_HAVE_MVE_FLOAT && CONSTANT_P (operands[1])) 78 { 79 operands[1] = neon_make_constant (operands[1]); 80 gcc_assert (operands[1] != NULL_RTX); 81 } 82 } 83}) 84 85;; Vector arithmetic. Expanders are blank, then unnamed insns implement 86;; patterns separately for Neon, IWMMXT and MVE. 87 88(define_expand "add<mode>3" 89 [(set (match_operand:VDQ 0 "s_register_operand") 90 (plus:VDQ (match_operand:VDQ 1 "s_register_operand") 91 (match_operand:VDQ 2 "s_register_operand")))] 92 "ARM_HAVE_<MODE>_ARITH" 93) 94 95(define_expand "sub<mode>3" 96 [(set (match_operand:VDQ 0 "s_register_operand") 97 (minus:VDQ (match_operand:VDQ 1 "s_register_operand") 98 (match_operand:VDQ 2 "s_register_operand")))] 99 "ARM_HAVE_<MODE>_ARITH" 100) 101 102(define_expand "mul<mode>3" 103 [(set (match_operand:VDQWH 0 "s_register_operand") 104 (mult:VDQWH (match_operand:VDQWH 1 "s_register_operand") 105 (match_operand:VDQWH 2 "s_register_operand")))] 106 "ARM_HAVE_<MODE>_ARITH 107 && (!TARGET_REALLY_IWMMXT 108 || <MODE>mode == V4HImode 109 || <MODE>mode == V2SImode)" 110) 111 112(define_expand "smin<mode>3" 113 [(set (match_operand:VALLW 0 "s_register_operand") 114 (smin:VALLW (match_operand:VALLW 1 "s_register_operand") 115 (match_operand:VALLW 2 "s_register_operand")))] 116 "ARM_HAVE_<MODE>_ARITH" 117) 118 119(define_expand "umin<mode>3" 120 [(set (match_operand:VINTW 0 "s_register_operand") 121 (umin:VINTW (match_operand:VINTW 1 "s_register_operand") 122 (match_operand:VINTW 2 "s_register_operand")))] 123 "ARM_HAVE_<MODE>_ARITH" 124) 125 126(define_expand "smax<mode>3" 127 [(set (match_operand:VALLW 0 "s_register_operand") 128 (smax:VALLW (match_operand:VALLW 1 "s_register_operand") 129 (match_operand:VALLW 2 "s_register_operand")))] 130 "ARM_HAVE_<MODE>_ARITH" 131) 132 133(define_expand "umax<mode>3" 134 [(set (match_operand:VINTW 0 "s_register_operand") 135 (umax:VINTW (match_operand:VINTW 1 "s_register_operand") 136 (match_operand:VINTW 2 "s_register_operand")))] 137 "ARM_HAVE_<MODE>_ARITH" 138) 139 140(define_expand "vec_perm<mode>" 141 [(match_operand:VE 0 "s_register_operand") 142 (match_operand:VE 1 "s_register_operand") 143 (match_operand:VE 2 "s_register_operand") 144 (match_operand:VE 3 "s_register_operand")] 145 "TARGET_NEON && !BYTES_BIG_ENDIAN" 146{ 147 arm_expand_vec_perm (operands[0], operands[1], operands[2], operands[3]); 148 DONE; 149}) 150 151(define_expand "vec_extract<mode><V_elem_l>" 152 [(match_operand:<V_elem> 0 "nonimmediate_operand") 153 (match_operand:VQX_NOBF 1 "s_register_operand") 154 (match_operand:SI 2 "immediate_operand")] 155 "TARGET_NEON || TARGET_HAVE_MVE" 156{ 157 if (TARGET_NEON) 158 emit_insn (gen_neon_vec_extract<mode><V_elem_l> (operands[0], operands[1], 159 operands[2])); 160 else if (TARGET_HAVE_MVE) 161 emit_insn (gen_mve_vec_extract<mode><V_elem_l> (operands[0], operands[1], 162 operands[2])); 163 else 164 gcc_unreachable (); 165 DONE; 166}) 167 168(define_expand "vec_set<mode>" 169 [(match_operand:VQX_NOBF 0 "s_register_operand" "") 170 (match_operand:<V_elem> 1 "s_register_operand" "") 171 (match_operand:SI 2 "immediate_operand" "")] 172 "TARGET_NEON || TARGET_HAVE_MVE" 173{ 174 HOST_WIDE_INT elem = HOST_WIDE_INT_1 << INTVAL (operands[2]); 175 if (TARGET_NEON) 176 emit_insn (gen_vec_set<mode>_internal (operands[0], operands[1], 177 GEN_INT (elem), operands[0])); 178 else 179 emit_insn (gen_mve_vec_set<mode>_internal (operands[0], operands[1], 180 GEN_INT (elem), operands[0])); 181 DONE; 182}) 183 184(define_expand "and<mode>3" 185 [(set (match_operand:VDQ 0 "s_register_operand" "") 186 (and:VDQ (match_operand:VDQ 1 "s_register_operand" "") 187 (match_operand:VDQ 2 "neon_inv_logic_op2" "")))] 188 "ARM_HAVE_<MODE>_ARITH" 189) 190 191(define_expand "ior<mode>3" 192 [(set (match_operand:VDQ 0 "s_register_operand" "") 193 (ior:VDQ (match_operand:VDQ 1 "s_register_operand" "") 194 (match_operand:VDQ 2 "neon_logic_op2" "")))] 195 "ARM_HAVE_<MODE>_ARITH" 196) 197 198(define_expand "xor<mode>3" 199 [(set (match_operand:VDQ 0 "s_register_operand" "") 200 (xor:VDQ (match_operand:VDQ 1 "s_register_operand" "") 201 (match_operand:VDQ 2 "s_register_operand" "")))] 202 "ARM_HAVE_<MODE>_ARITH" 203) 204 205(define_expand "one_cmpl<mode>2" 206 [(set (match_operand:VDQ 0 "s_register_operand") 207 (not:VDQ (match_operand:VDQ 1 "s_register_operand")))] 208 "ARM_HAVE_<MODE>_ARITH && !TARGET_REALLY_IWMMXT" 209) 210 211(define_expand "neg<mode>2" 212 [(set (match_operand:VDQWH 0 "s_register_operand" "") 213 (neg:VDQWH (match_operand:VDQWH 1 "s_register_operand" "")))] 214 "ARM_HAVE_<MODE>_ARITH && !TARGET_REALLY_IWMMXT" 215) 216 217(define_expand "cadd<rot><mode>3" 218 [(set (match_operand:VF 0 "register_operand") 219 (unspec:VF [(match_operand:VF 1 "register_operand") 220 (match_operand:VF 2 "register_operand")] 221 VCADD))] 222 "(TARGET_COMPLEX || (TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT 223 && ARM_HAVE_<MODE>_ARITH)) && !BYTES_BIG_ENDIAN" 224) 225 226;; The complex mul operations always need to expand to two instructions. 227;; The first operation does half the computation and the second does the 228;; remainder. Because of this, expand early. 229(define_expand "cmul<conj_op><mode>3" 230 [(set (match_operand:VQ_HSF 0 "register_operand") 231 (unspec:VQ_HSF [(match_operand:VQ_HSF 1 "register_operand") 232 (match_operand:VQ_HSF 2 "register_operand")] 233 VCMUL_OP))] 234 "(TARGET_COMPLEX || (TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT)) 235 && !BYTES_BIG_ENDIAN" 236{ 237 rtx res1 = gen_reg_rtx (<MODE>mode); 238 if (TARGET_COMPLEX) 239 { 240 rtx tmp = force_reg (<MODE>mode, CONST0_RTX (<MODE>mode)); 241 emit_insn (gen_arm_vcmla<rotsplit1><mode> (res1, tmp, 242 operands[2], operands[1])); 243 } 244 else 245 emit_insn (gen_arm_vcmla<rotsplit1><mode> (res1, CONST0_RTX (<MODE>mode), 246 operands[2], operands[1])); 247 248 emit_insn (gen_arm_vcmla<rotsplit2><mode> (operands[0], res1, 249 operands[2], operands[1])); 250 DONE; 251}) 252 253(define_expand "arm_vcmla<rot><mode>" 254 [(set (match_operand:VF 0 "register_operand") 255 (plus:VF (match_operand:VF 1 "register_operand") 256 (unspec:VF [(match_operand:VF 2 "register_operand") 257 (match_operand:VF 3 "register_operand")] 258 VCMLA)))] 259 "(TARGET_COMPLEX || (TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT 260 && ARM_HAVE_<MODE>_ARITH)) && !BYTES_BIG_ENDIAN" 261) 262 263;; The complex mla/mls operations always need to expand to two instructions. 264;; The first operation does half the computation and the second does the 265;; remainder. Because of this, expand early. 266(define_expand "cml<fcmac1><conj_op><mode>4" 267 [(set (match_operand:VF 0 "register_operand") 268 (plus:VF (match_operand:VF 1 "register_operand") 269 (unspec:VF [(match_operand:VF 2 "register_operand") 270 (match_operand:VF 3 "register_operand")] 271 VCMLA_OP)))] 272 "(TARGET_COMPLEX || (TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT 273 && ARM_HAVE_<MODE>_ARITH)) && !BYTES_BIG_ENDIAN" 274{ 275 rtx tmp = gen_reg_rtx (<MODE>mode); 276 emit_insn (gen_arm_vcmla<rotsplit1><mode> (tmp, operands[1], 277 operands[3], operands[2])); 278 emit_insn (gen_arm_vcmla<rotsplit2><mode> (operands[0], tmp, 279 operands[3], operands[2])); 280 DONE; 281}) 282 283(define_expand "movmisalign<mode>" 284 [(set (match_operand:VDQX 0 "neon_perm_struct_or_reg_operand") 285 (unspec:VDQX [(match_operand:VDQX 1 "neon_perm_struct_or_reg_operand")] 286 UNSPEC_MISALIGNED_ACCESS))] 287 "ARM_HAVE_<MODE>_LDST && !BYTES_BIG_ENDIAN 288 && unaligned_access && !TARGET_REALLY_IWMMXT" 289{ 290 rtx adjust_mem; 291 /* This pattern is not permitted to fail during expansion: if both arguments 292 are non-registers (e.g. memory := constant, which can be created by the 293 auto-vectorizer), force operand 1 into a register. */ 294 if (!s_register_operand (operands[0], <MODE>mode) 295 && !s_register_operand (operands[1], <MODE>mode)) 296 operands[1] = force_reg (<MODE>mode, operands[1]); 297 298 if (s_register_operand (operands[0], <MODE>mode)) 299 adjust_mem = operands[1]; 300 else 301 adjust_mem = operands[0]; 302 303 /* Legitimize address. */ 304 if (!neon_vector_mem_operand (adjust_mem, 2, true)) 305 XEXP (adjust_mem, 0) = force_reg (Pmode, XEXP (adjust_mem, 0)); 306}) 307 308(define_insn "mve_vshlq_<supf><mode>" 309 [(set (match_operand:VDQIW 0 "s_register_operand" "=w,w") 310 (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w,w") 311 (match_operand:VDQIW 2 "imm_lshift_or_reg_neon" "w,Ds")] 312 VSHLQ))] 313 "ARM_HAVE_<MODE>_ARITH && !TARGET_REALLY_IWMMXT" 314 "@ 315 vshl.<supf>%#<V_sz_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2 316 * return neon_output_shift_immediate (\"vshl\", 'i', &operands[2], <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode), true);" 317 [(set_attr "type" "neon_shift_reg<q>, neon_shift_imm<q>")] 318) 319 320(define_expand "vashl<mode>3" 321 [(set (match_operand:VDQIW 0 "s_register_operand" "") 322 (ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "") 323 (match_operand:VDQIW 2 "imm_lshift_or_reg_neon" "")))] 324 "ARM_HAVE_<MODE>_ARITH && !TARGET_REALLY_IWMMXT" 325{ 326 emit_insn (gen_mve_vshlq_u<mode> (operands[0], operands[1], operands[2])); 327 DONE; 328}) 329 330;; When operand 2 is an immediate, use the normal expansion to match 331;; gen_vashr<mode>3_imm for Neon and gen_mve_vshrq_n_s<mode>_imm for 332;; MVE. 333(define_expand "vashr<mode>3" 334 [(set (match_operand:VDQIW 0 "s_register_operand") 335 (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand") 336 (match_operand:VDQIW 2 "imm_rshift_or_reg_neon")))] 337 "ARM_HAVE_<MODE>_ARITH && !TARGET_REALLY_IWMMXT" 338{ 339 if (s_register_operand (operands[2], <MODE>mode)) 340 { 341 rtx neg = gen_reg_rtx (<MODE>mode); 342 emit_insn (gen_neg<mode>2 (neg, operands[2])); 343 emit_insn (gen_mve_vshlq_s<mode> (operands[0], operands[1], neg)); 344 DONE; 345 } 346}) 347 348;; When operand 2 is an immediate, use the normal expansion to match 349;; gen_vashr<mode>3_imm for Neon and gen_mve_vshrq_n_u<mode>_imm for 350;; MVE. 351(define_expand "vlshr<mode>3" 352 [(set (match_operand:VDQIW 0 "s_register_operand") 353 (lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand") 354 (match_operand:VDQIW 2 "imm_rshift_or_reg_neon")))] 355 "ARM_HAVE_<MODE>_ARITH && !TARGET_REALLY_IWMMXT" 356{ 357 if (s_register_operand (operands[2], <MODE>mode)) 358 { 359 rtx neg = gen_reg_rtx (<MODE>mode); 360 emit_insn (gen_neg<mode>2 (neg, operands[2])); 361 emit_insn (gen_mve_vshlq_u<mode> (operands[0], operands[1], neg)); 362 DONE; 363 } 364}) 365