# --- T2-COPYRIGHT-BEGIN --- # t2/package/*/gcc/ia64-v4sf-regpair.patch.ia64 # Copyright (C) 2026 The T2 SDE Project # SPDX-License-Identifier: GPL-2.0 or patched project license # --- T2-COPYRIGHT-END --- --- a/gcc/config/ia64/ia64.cc +++ b/gcc/config/ia64/ia64.cc @@ -1428,15 +1428,32 @@ May return an insn which is to be emitted after the moves. */ static rtx -ia64_split_tmode (rtx out[2], rtx in, bool reversed, bool dead) +ia64_split_tmode (rtx out[2], rtx in, bool reversed, bool dead, + machine_mode hmode) { rtx fixup = 0; switch (GET_CODE (in)) { case REG: - out[reversed] = gen_rtx_REG (DImode, REGNO (in)); - out[!reversed] = gen_rtx_REG (DImode, REGNO (in) + 1); + out[reversed] = gen_rtx_REG (hmode, REGNO (in)); + out[!reversed] = gen_rtx_REG (hmode, REGNO (in) + 1); + break; + + case CONST_VECTOR: + /* Cannot occur reversed. */ + gcc_assert (!reversed); + { + int n = GET_MODE_NUNITS (GET_MODE (in)) / 2; + rtvec lo = rtvec_alloc (n), hi = rtvec_alloc (n); + for (int k = 0; k < n; k++) + { + RTVEC_ELT (lo, k) = CONST_VECTOR_ELT (in, k); + RTVEC_ELT (hi, k) = CONST_VECTOR_ELT (in, k + n); + } + out[0] = gen_rtx_CONST_VECTOR (hmode, lo); + out[1] = gen_rtx_CONST_VECTOR (hmode, hi); + } break; case CONST_INT: @@ -1481,9 +1498,9 @@ if (!reversed) { out[0] = adjust_automodify_address - (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); + (in, hmode, gen_rtx_POST_INC (Pmode, base), 0); out[1] = adjust_automodify_address - (in, DImode, dead ? 0 : gen_rtx_POST_DEC (Pmode, base), 8); + (in, hmode, dead ? 0 : gen_rtx_POST_DEC (Pmode, base), 8); } else { @@ -1491,8 +1508,8 @@ be done as a separate insn. */ emit_insn (gen_adddi3 (base, base, GEN_INT (8))); out[0] = adjust_automodify_address - (in, DImode, gen_rtx_POST_DEC (Pmode, base), 8); - out[1] = adjust_address (in, DImode, 0); + (in, hmode, gen_rtx_POST_DEC (Pmode, base), 8); + out[1] = adjust_address (in, hmode, 0); } break; @@ -1500,8 +1517,8 @@ gcc_assert (!reversed && !dead); /* Just do the increment in two steps. */ - out[0] = adjust_automodify_address (in, DImode, 0, 0); - out[1] = adjust_automodify_address (in, DImode, 0, 8); + out[0] = adjust_automodify_address (in, hmode, 0, 0); + out[1] = adjust_automodify_address (in, hmode, 0, 8); break; case POST_DEC: @@ -1510,9 +1527,9 @@ /* Add 8, subtract 24. */ base = XEXP (base, 0); out[0] = adjust_automodify_address - (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); + (in, hmode, gen_rtx_POST_INC (Pmode, base), 0); out[1] = adjust_automodify_address - (in, DImode, + (in, hmode, gen_rtx_POST_MODIFY (Pmode, base, plus_constant (Pmode, base, -24)), 8); @@ -1530,13 +1547,13 @@ base = XEXP (base, 0); out[0] = adjust_automodify_address - (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); + (in, hmode, gen_rtx_POST_INC (Pmode, base), 0); if (GET_CODE (XEXP (offset, 1)) == REG) { /* Can't adjust the postmodify to match. Emit the original, then a separate addition insn. */ - out[1] = adjust_automodify_address (in, DImode, 0, 8); + out[1] = adjust_automodify_address (in, hmode, 0, 8); fixup = gen_adddi3 (base, base, GEN_INT (-8)); } else @@ -1548,7 +1565,7 @@ but in this case it's more efficient to get rid of the postmodify entirely and fix up with an add insn. */ - out[1] = adjust_automodify_address (in, DImode, base, 8); + out[1] = adjust_automodify_address (in, hmode, base, 8); fixup = gen_adddi3 (base, base, GEN_INT (INTVAL (XEXP (offset, 1)) - 8)); } @@ -1557,7 +1574,7 @@ /* Combined offset still fits in the displacement field. (We cannot overflow it at the high end.) */ out[1] = adjust_automodify_address - (in, DImode, gen_rtx_POST_MODIFY + (in, hmode, gen_rtx_POST_MODIFY (Pmode, base, gen_rtx_PLUS (Pmode, base, GEN_INT (INTVAL (XEXP (offset, 1)) - 8))), @@ -1618,8 +1635,11 @@ && REGNO (operands[0]) == REGNO (operands[1]) + 1) reversed = true; - fixup[0] = ia64_split_tmode (in, operands[1], reversed, dead); - fixup[1] = ia64_split_tmode (out, operands[0], reversed, dead); + machine_mode hmode + = GET_MODE (operands[0]) == V4SFmode ? V2SFmode : DImode; + + fixup[0] = ia64_split_tmode (in, operands[1], reversed, dead, hmode); + fixup[1] = ia64_split_tmode (out, operands[0], reversed, dead, hmode); #define MAYBE_ADD_REG_INC_NOTE(INSN, EXP) \ if (GET_CODE (EXP) == MEM \ @@ -4707,6 +4727,44 @@ return VOIDmode; } +/* True if MODE is a vector mode too wide for a single register, and so is + held in a register pair. */ + +static bool +ia64_wide_vector_mode_p (machine_mode mode) +{ + return VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) > UNITS_PER_WORD; +} + +/* Number of registers a wide vector mode occupies. */ + +static int +ia64_wide_vector_nregs (machine_mode mode) +{ + return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD); +} + +/* True if a wide vector argument of MODE should be kept out of the FP + argument path. + + By default it must be: that path assigns one FR register per argument, + so consecutive wide-vector arguments would overlap. Passing them in + general registers is also exactly what happened before these modes + became register-allocatable, so the calling convention is unchanged and + objects built with and without that change interoperate. + + -mfloat-vector-args instead passes them in FR register *pairs*, with the + slot accounting corrected below. That removes the setf.sig/getf.sig + pairs at call boundaries, but it is a different calling convention: + every caller and callee of a function taking such an argument must + agree on the flag. */ + +static bool +ia64_vector_arg_in_gr_p (machine_mode mode) +{ + return ia64_wide_vector_mode_p (mode) && !TARGET_FLOAT_VECTOR_ARGS; +} + /* Return the number of words required to hold a quantity of TYPE and MODE when passed as an argument. */ static int @@ -4887,7 +4945,8 @@ happen when we have a SFmode HFA. */ else if (arg.mode == TFmode || arg.mode == TCmode || !FLOAT_MODE_P (arg.mode) - || cum->fp_regs == MAX_ARGUMENT_SLOTS) + || ia64_vector_arg_in_gr_p (arg.mode) + || cum->fp_regs >= MAX_ARGUMENT_SLOTS) { int byte_size = arg.promoted_size_in_bytes (); if (BYTES_BIG_ENDIAN @@ -5081,7 +5140,8 @@ general registers. This can happen when we have a SFmode HFA. */ else if (arg.mode == TFmode || arg.mode == TCmode || !FLOAT_MODE_P (arg.mode) - || cum->fp_regs == MAX_ARGUMENT_SLOTS) + || ia64_vector_arg_in_gr_p (arg.mode) + || cum->fp_regs >= MAX_ARGUMENT_SLOTS) cum->int_regs = cum->words; /* If there is a prototype, then FP values go in a FR register when @@ -5093,7 +5153,9 @@ else /* ??? Complex types should not reach here. */ cum->fp_regs - += (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT ? 2 : 1); + += (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT ? 2 + : ia64_wide_vector_mode_p (arg.mode) + ? ia64_wide_vector_nregs (arg.mode) : 1); } /* If there is no prototype, then FP values go in both FR and GR registers. */ @@ -5101,7 +5163,9 @@ { /* ??? Complex types should not reach here. */ cum->fp_regs - += (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT ? 2 : 1); + += (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT ? 2 + : ia64_wide_vector_mode_p (arg.mode) + ? ia64_wide_vector_nregs (arg.mode) : 1); cum->int_regs = cum->words; } } @@ -11168,6 +11232,15 @@ return true; case E_V2SFmode: + + /* V4SF is not a native machine mode: it is held in a *pair* of FR + registers, each holding one packed single-precision pair, and every + operation on it is split into two V2SF operations. Claiming it here + is what keeps 16-byte float vectors out of memory -- otherwise + vector_type_mode falls back to BLKmode, which has no registers at + all. This does not affect the calling convention; see + ia64_pass_vector_in_fr_p. */ + case E_V4SFmode: return true; default: @@ -11843,6 +11916,12 @@ if (vmode != op_mode) return false; + /* The permutation expanders below only understand the one-register + vector modes. Wider vector modes are held in a register pair and + have no permute instructions; let the generic code lower them. */ + if (GET_MODE_SIZE (vmode) > UNITS_PER_WORD) + return false; + struct expand_vec_perm_d d; unsigned char perm[MAX_VECT_LEN]; unsigned int i, nelt, which; --- a/gcc/config/ia64/vect.md +++ b/gcc/config/ia64/vect.md @@ -1552,3 +1552,126 @@ ;; Missing operations ;; fprcpa ;; fpsqrta + +;; :::::::::::::::::::: +;; :: +;; :: 128-bit single-precision vectors +;; :: +;; :::::::::::::::::::: +;; +;; V4SF is not a native machine mode: it is held in a *pair* of FR +;; registers, each holding one packed single-precision pair, and every +;; operation on it is performed one half at a time. Making the mode +;; register-allocatable (rather than letting vector_type_mode fall back +;; to BLKmode) is what keeps 16-byte float vectors out of memory; the +;; tree-level vector lowering pass already knows how to split each +;; operation into two V2SF operations, and now does so on subregs of a +;; register instead of BIT_FIELD_REFs of a stack slot. + +(define_expand "movv4sf" + [(set (match_operand:V4SF 0 "general_operand" "") + (match_operand:V4SF 1 "general_operand" ""))] + "" +{ + rtx op1 = ia64_expand_move (operands[0], operands[1]); + if (!op1) + DONE; + operands[1] = op1; +}) + +(define_insn_and_split "*movv4sf_internal" + [(set (match_operand:V4SF 0 "destination_operand" "=f,f,Q,f ,*r,*r,*r, m") + (match_operand:V4SF 1 "general_operand" " f,Q,f,*r,f ,*r, m,*r"))] + "ia64_move_ok (operands[0], operands[1])" + "#" + "reload_completed" + [(const_int 0)] +{ + ia64_split_tmode_move (operands); + DONE; +} + [(set_attr "itanium_class" "unknown")]) + +;; Build a V4SF from its two V2SF halves. This is the pattern +;; store_constructor looks for when tree vector lowering rebuilds a +;; V4SF value out of the two halves it computed. + +(define_expand "vec_initv4sfv2sf" + [(match_operand:V4SF 0 "register_operand" "") + (match_operand 1 "" "")] + "" +{ + rtx lo = XVECEXP (operands[1], 0, 0); + rtx hi = XVECEXP (operands[1], 0, 1); + + if (!register_operand (lo, V2SFmode)) + lo = force_reg (V2SFmode, lo); + if (!register_operand (hi, V2SFmode)) + hi = force_reg (V2SFmode, hi); + + /* Byte offsets are in memory order; simplify_gen_subreg maps them onto + the correct half for either endianness. */ + emit_move_insn (simplify_gen_subreg (V2SFmode, operands[0], V4SFmode, 0), + lo); + emit_move_insn (simplify_gen_subreg (V2SFmode, operands[0], V4SFmode, 8), + hi); + DONE; +}) + +(define_expand "vec_initv4sfsf" + [(match_operand:V4SF 0 "register_operand" "") + (match_operand 1 "" "")] + "" +{ + rtx half[2]; + int i; + + for (i = 0; i < 2; i++) + { + rtx a = XVECEXP (operands[1], 0, 2 * i); + rtx b = XVECEXP (operands[1], 0, 2 * i + 1); + + if (!fr_reg_or_fp01_operand (a, SFmode)) + a = force_reg (SFmode, a); + if (!fr_reg_or_fp01_operand (b, SFmode)) + b = force_reg (SFmode, b); + + half[i] = gen_reg_rtx (V2SFmode); + emit_insn (gen_fpack (half[i], a, b)); + } + + emit_move_insn (simplify_gen_subreg (V2SFmode, operands[0], V4SFmode, 0), + half[0]); + emit_move_insn (simplify_gen_subreg (V2SFmode, operands[0], V4SFmode, 8), + half[1]); + DONE; +}) + +(define_expand "vec_extractv4sfv2sf" + [(match_operand:V2SF 0 "register_operand" "") + (match_operand:V4SF 1 "register_operand" "") + (match_operand:DI 2 "const_int_operand" "")] + "" +{ + emit_move_insn (operands[0], + simplify_gen_subreg (V2SFmode, operands[1], V4SFmode, + INTVAL (operands[2]) * 8)); + DONE; +}) + +(define_expand "vec_extractv4sfsf" + [(match_operand:SF 0 "register_operand" "") + (match_operand:V4SF 1 "register_operand" "") + (match_operand:DI 2 "const_int_operand" "")] + "" +{ + HOST_WIDE_INT elt = INTVAL (operands[2]); + rtx half = simplify_gen_subreg (V2SFmode, operands[1], V4SFmode, + (elt / 2) * 8); + + if (!register_operand (half, V2SFmode)) + half = force_reg (V2SFmode, half); + + emit_insn (gen_vec_extractv2sfsf (operands[0], half, GEN_INT (elt & 1))); + DONE; +}) --- a/gcc/config/ia64/ia64.opt +++ b/gcc/config/ia64/ia64.opt @@ -193,4 +193,8 @@ Target Var(mflag_sel_sched_dont_check_control_spec) Init(0) Don't generate checks for control speculation in selective scheduling. +mfloat-vector-args +Target Mask(FLOAT_VECTOR_ARGS) +Pass 128-bit floating-point vector arguments in FR register pairs. This changes the calling convention. + ; This comment is to ensure we retain the blank line above. --- a/gcc/config/ia64/ia64.opt.urls +++ b/gcc/config/ia64/ia64.opt.urls @@ -117,3 +117,5 @@ msel-sched-dont-check-control-spec UrlSuffix(gcc/IA-64-Options.html#index-msel-sched-dont-check-control-spec) +mfloat-vector-args +UrlSuffix(gcc/IA-64-Options.html#index-mfloat-vector-args)