[RFC, PATCH v2] Expand PARALLEL for function return and parameter passing
"H.J. Lu" <[email protected]> Tue, 4 Aug 2026 13:56:14 +0800
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CAMe9rOro2K+rWnmxVqXxw8vDGa2SLE=uOLhJEFvNYtoui1MEDQ@mail.gmail.com> |
On Wed, Jul 29, 2026 at 4:57 PM Richard Biener <[email protected]> wrote: > > On Wed, Jul 29, 2026 at 10:28 AM H.J. Lu <[email protected]> wrote: > > > > On some targets, TImode structs are placed in TImode PARALLEL for function > > return and parameter passing: > > > > (parallel:TI [ > > (expr_list:REG_DEP_TRUE (reg:DI 20 xmm0 [ arg ]) > > (const_int 0 [0])) > > (expr_list:REG_DEP_TRUE (reg:DI 21 xmm1 [ arg+8 ]) > > (const_int 8 [0x8])) > > ]) > > > > (parallel:TI [ > > (expr_list:REG_DEP_TRUE (reg:SI 5 di [ arg ]) > > (const_int 0 [0])) > > (expr_list:REG_DEP_TRUE (reg:DI 4 si [ arg+8 ]) > > (const_int 8 [0x8])) > > ]) > > > > (parallel:BLK [ > > (expr_list:REG_DEP_TRUE (reg:TI 102 [ <retval> ]) > > (const_int 0 [0])) > > ]) > > > > We generate very bad code sequences for moving between such PARALLELs > > and register or memory since the backend doesn't see the whole picture. > > Add parallel_mov optab to move between PARALLEL and register or memory. > > Implement parallel_mov patterns for TImode in x86 backend. > > Why is what you do in the x86 implementation in any way special to x86? > Can this not be done directly in the middle-end and for all targets? > Here is the v2 patch to add expand_parallel_load and expand_parallel_store. It doesn't support big-endian. Do any big-endian targets use TImode PARALLEL for function return and parameter passing? -- H.J. --- On some targets, TImode structs are placed in TImode PARALLEL for function return and parameter passing: (parallel:TI [ (expr_list:REG_DEP_TRUE (reg:DI 20 xmm0 [ arg ]) (const_int 0 [0])) (expr_list:REG_DEP_TRUE (reg:DI 21 xmm1 [ arg+8 ]) (const_int 8 [0x8])) ]) (parallel:TI [ (expr_list:REG_DEP_TRUE (reg:SI 5 di [ arg ]) (const_int 0 [0])) (expr_list:REG_DEP_TRUE (reg:DI 4 si [ arg+8 ]) (const_int 8 [0x8])) ]) (parallel:BLK [ (expr_list:REG_DEP_TRUE (reg:TI 102 [ <retval> ]) (const_int 0 [0])) ]) We generate very bad code sequences for moving between such PARALLELs and register or memory since the backend doesn't see the whole picture. Add expand_parallel_load to expand PARALLEL load for function return and add expand_parallel_store to expand PARALLEL store for function parameter passing. gcc/ PR target/114134 PR target/120588 PR target/126403 PR target/126424 * expr.cc (expand_parallel_load): New. (expand_parallel_store): Likewise. (emit_group_load): Call expand_parallel_load for PARALLEL destination in BLKmode. (emit_group_store): Call expand_parallel_store for PARALLEL source. * config/i386/sse.md (*vec_extractv2di_1 splitter): New. gcc/testsuite/ PR target/114134 PR target/120588 PR target/126403 PR target/126424 * g++.target/i386/pr126424-1.C: New test. * gcc.target/i386/pr114134-1.c: Likewise. * gcc.target/i386/pr114134-2.c: Likewise. * gcc.target/i386/pr114134-3.c: Likewise. * gcc.target/i386/pr120588-1.c: Likewise. * gcc.target/i386/pr120588-2.c: Likewise. * gcc.target/i386/pr120588-3.c: Likewise. * gcc.target/i386/pr120588-4.c: Likewise. * gcc.target/i386/pr120588-5.c: Likewise. * gcc.target/i386/pr120588-6.c: Likewise. * gcc.target/i386/pr120588-7.c: Likewise. * gcc.target/i386/pr120588-8.c: Likewise. * gcc.target/i386/pr120588-9.c: Likewise. * gcc.target/i386/pr120588-10.c: Likewise. * gcc.target/i386/pr120588-11.c: Likewise. * gcc.target/i386/pr120588-12.c: Likewise. * gcc.target/i386/pr120588-13.c: Likewise. * gcc.target/i386/pr120588-14.c: Likewise. * gcc.target/i386/pr120588-15.c: Likewise. * gcc.target/i386/pr120588-16.c: Likewise. * gcc.target/i386/pr120588-17.c: Likewise. * gcc.target/i386/pr120588-18.c: Likewise. * gcc.target/i386/pr120588-19.c: Likewise. * gcc.target/i386/pr120588-20.c: Likewise. * gcc.target/i386/pr126403-1.c: Likewise. * gcc.target/i386/pr126403-2.c: Likewise. * gcc.target/i386/pr126403-3.c: Likewise. * gcc.target/i386/pr126403-4.c: Likewise. * gcc.target/i386/zext-sse-2.c: Updated.
v2-0001-Expand-PARALLEL-for-function-return-and-parameter.patch
(text/x-patch, 44.3 KB)
From 2070c8a2c6eed53262af696714f8c8a47ecaa364 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <[email protected]> Date: Sun, 12 Jul 2026 07:59:57 +0800 Subject: [PATCH v2] Expand PARALLEL for function return and parameter passing On some targets, TImode structs are placed in TImode PARALLEL for function return and parameter passing: (parallel:TI [ (expr_list:REG_DEP_TRUE (reg:DI 20 xmm0 [ arg ]) (const_int 0 [0])) (expr_list:REG_DEP_TRUE (reg:DI 21 xmm1 [ arg+8 ]) (const_int 8 [0x8])) ]) (parallel:TI [ (expr_list:REG_DEP_TRUE (reg:SI 5 di [ arg ]) (const_int 0 [0])) (expr_list:REG_DEP_TRUE (reg:DI 4 si [ arg+8 ]) (const_int 8 [0x8])) ]) (parallel:BLK [ (expr_list:REG_DEP_TRUE (reg:TI 102 [ <retval> ]) (const_int 0 [0])) ]) We generate very bad code sequences for moving between such PARALLELs and register or memory since the backend doesn't see the whole picture. Add expand_parallel_load to expand PARALLEL load for function return and add expand_parallel_store to expand PARALLEL store for function parameter passing. gcc/ PR target/114134 PR target/120588 PR target/126403 PR target/126424 * expr.cc (expand_parallel_load): New. (expand_parallel_store): Likewise. (emit_group_load): Call expand_parallel_load for PARALLEL destination in BLKmode. (emit_group_store): Call expand_parallel_store for PARALLEL source. * config/i386/sse.md (*vec_extractv2di_1 splitter): New. gcc/testsuite/ PR target/114134 PR target/120588 PR target/126403 PR target/126424 * g++.target/i386/pr126424-1.C: New test. * gcc.target/i386/pr114134-1.c: Likewise. * gcc.target/i386/pr114134-2.c: Likewise. * gcc.target/i386/pr114134-3.c: Likewise. * gcc.target/i386/pr120588-1.c: Likewise. * gcc.target/i386/pr120588-2.c: Likewise. * gcc.target/i386/pr120588-3.c: Likewise. * gcc.target/i386/pr120588-4.c: Likewise. * gcc.target/i386/pr120588-5.c: Likewise. * gcc.target/i386/pr120588-6.c: Likewise. * gcc.target/i386/pr120588-7.c: Likewise. * gcc.target/i386/pr120588-8.c: Likewise. * gcc.target/i386/pr120588-9.c: Likewise. * gcc.target/i386/pr120588-10.c: Likewise. * gcc.target/i386/pr120588-11.c: Likewise. * gcc.target/i386/pr120588-12.c: Likewise. * gcc.target/i386/pr120588-13.c: Likewise. * gcc.target/i386/pr120588-14.c: Likewise. * gcc.target/i386/pr120588-15.c: Likewise. * gcc.target/i386/pr120588-16.c: Likewise. * gcc.target/i386/pr120588-17.c: Likewise. * gcc.target/i386/pr120588-18.c: Likewise. * gcc.target/i386/pr120588-19.c: Likewise. * gcc.target/i386/pr120588-20.c: Likewise. * gcc.target/i386/pr126403-1.c: Likewise. * gcc.target/i386/pr126403-2.c: Likewise. * gcc.target/i386/pr126403-3.c: Likewise. * gcc.target/i386/pr126403-4.c: Likewise. * gcc.target/i386/zext-sse-2.c: Updated. Signed-off-by: H.J. Lu <[email protected]> --- gcc/config/i386/sse.md | 15 + gcc/expr.cc | 458 ++++++++++++++++++++ gcc/testsuite/g++.target/i386/pr126424-1.C | 80 ++++ gcc/testsuite/gcc.target/i386/pr114134-1.c | 27 ++ gcc/testsuite/gcc.target/i386/pr114134-2.c | 22 + gcc/testsuite/gcc.target/i386/pr114134-3.c | 22 + gcc/testsuite/gcc.target/i386/pr120588-1.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-10.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-11.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-12.c | 36 ++ gcc/testsuite/gcc.target/i386/pr120588-13.c | 28 ++ gcc/testsuite/gcc.target/i386/pr120588-14.c | 28 ++ gcc/testsuite/gcc.target/i386/pr120588-15.c | 27 ++ gcc/testsuite/gcc.target/i386/pr120588-16.c | 27 ++ gcc/testsuite/gcc.target/i386/pr120588-17.c | 27 ++ gcc/testsuite/gcc.target/i386/pr120588-18.c | 35 ++ gcc/testsuite/gcc.target/i386/pr120588-19.c | 31 ++ gcc/testsuite/gcc.target/i386/pr120588-2.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-20.c | 25 ++ gcc/testsuite/gcc.target/i386/pr120588-3.c | 27 ++ gcc/testsuite/gcc.target/i386/pr120588-4.c | 29 ++ gcc/testsuite/gcc.target/i386/pr120588-5.c | 27 ++ gcc/testsuite/gcc.target/i386/pr120588-6.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-7.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-8.c | 26 ++ gcc/testsuite/gcc.target/i386/pr120588-9.c | 26 ++ gcc/testsuite/gcc.target/i386/pr126403-1.c | 31 ++ gcc/testsuite/gcc.target/i386/pr126403-2.c | 31 ++ gcc/testsuite/gcc.target/i386/pr126403-3.c | 31 ++ gcc/testsuite/gcc.target/i386/pr126403-4.c | 33 ++ gcc/testsuite/gcc.target/i386/zext-sse-2.c | 10 +- 31 files changed, 1308 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.target/i386/pr126424-1.C create mode 100644 gcc/testsuite/gcc.target/i386/pr114134-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr114134-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr114134-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-10.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-11.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-12.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-13.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-14.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-15.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-16.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-17.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-18.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-19.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-20.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-5.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-6.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-7.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-8.c create mode 100644 gcc/testsuite/gcc.target/i386/pr120588-9.c create mode 100644 gcc/testsuite/gcc.target/i386/pr126403-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr126403-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr126403-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr126403-4.c diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 7d71f8ba546..f13538a9dc2 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -22340,6 +22340,21 @@ (define_split } }) +;; Turn the second DImode extraction from V4SF and V2DF modes into +;; vec_extract*. +(define_split + [(set (match_operand:DI 0 "register_operand") + (subreg:DI (match_operand:VFH_128 1 "register_operand") 8))] + "can_create_pseudo_p () + && TARGET_SSE + && TARGET_64BIT" + [(set (match_dup 0) + (vec_select:DI (match_dup 1) + (parallel [(const_int 1)])))] +{ + operands[1] = gen_lowpart (V2DImode, operands[1]); +}) + (define_insn "*vec_concatv2si_sse4_1" [(set (match_operand:V2SI 0 "register_operand" "=Yr,*x, x, v,Yr,*x, v, v, *y,*y") diff --git a/gcc/expr.cc b/gcc/expr.cc index 210a7bc0888..8cf9d6de369 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -2929,6 +2929,454 @@ move_block_from_reg (int regno, rtx x, int nregs) } } +/* Expand TImode PARALLEL load for function return. */ + +static bool +expand_parallel_load (rtx op0, rtx op1) +{ + /* Skip the naked function to avoid trashing callee-saved registers + since they won't be preserved without prologue nor epilogue. */ + if (lookup_attribute ("naked", + DECL_ATTRIBUTES (current_function_decl))) + return false; + + /* FIXME: How to support big-endian? */ + if (BITS_BIG_ENDIAN || BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) + return false; + + if (!MEM_P (op1) || word_mode != E_DImode) + return false; + + /* Load a memory operand, like + + (mem/c:BLK (plus:DI (reg/f:DI 93 virtual-stack-vars) + (const_int -16 [0xfffffffffffffff0])) [1 D.2978+0 S12 A128]) + + into function return + + (parallel:BLK [ + (expr_list:REG_DEP_TRUE (reg:TI 98 [ <retval> ]) + (const_int 0 [0]))]) + + */ + if (GET_MODE (op1) != BLKmode + || !MEM_SIZE_KNOWN_P (op1) + || GET_CODE (op0) != PARALLEL + || XVECLEN (op0, 0) != 1) + return false; + + rtx dest = XVECEXP (op0, 0, 0); + if (GET_CODE (dest) != EXPR_LIST) + return false; + + dest = XEXP (dest, 0); + if (!REG_P (dest) || GET_MODE (dest) != TImode) + return false; + + /* Skip if this isn't function return. */ + tree reg_expr = REG_EXPR (dest); + if (!reg_expr || TREE_CODE (reg_expr) != RESULT_DECL) + return false; + + /* We can optimize a 12-byte load with an 8-byte DImode load and + a 4-byte SImode load, which zero-extends to 8 bytes, to fill a + TImode register. 9/10/11/13/14/15 byte loads require more than + 2 loads to fill a TImode register. FIXME: How can we improve + 9/10/11/13/14/15 byte loads? */ + if (!MEM_SIZE_KNOWN_P (op1)) + return false; + + poly_int64 mem_size = MEM_SIZE (op1); + if (!known_eq (mem_size, 12)) + return false; + + rtx low = simplify_gen_subreg (DImode, dest, TImode, 0); + if (!low) + return false; + rtx high = simplify_gen_subreg (SImode, dest, TImode, 8); + if (!high) + return false; + + rtx_insn *insn, *seq; + + start_sequence (); + + /* First load the first 8-byte memory into the register with a + paradoxical subreg. */ + rtx mem = adjust_address (op1, DImode, 0); + rtx src = gen_reg_rtx (DImode); + insn = emit_move_insn (src, mem); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + insn = emit_move_insn (low, src); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + /* Load the remaining 4-byte memory into the subreg. */ + mem = adjust_address (op1, SImode, 8); + src = gen_reg_rtx (SImode); + insn = emit_move_insn (src, mem); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + insn = emit_move_insn (high, src); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + seq = end_sequence (); + emit_insn (seq); + return true; +} + +/* Expand TImode PARALLEL store for function parameter passing. */ + +static bool +expand_parallel_store (rtx op0, rtx op1) +{ + /* Skip the naked function to avoid trashing callee-saved registers + since they won't be preserved without prologue nor epilogue. */ + if (lookup_attribute ("naked", + DECL_ATTRIBUTES (current_function_decl))) + return false; + + /* FIXME: How to support big-endian? */ + if (BITS_BIG_ENDIAN || BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) + return false; + + if (word_mode != E_DImode) + return false; + + /* Move a TImode function parameter in 2 hard registers: + + (parallel:TI [ + (expr_list:REG_DEP_TRUE (reg:SI 5 di [ x ]) + (const_int 0 [0])) + (expr_list:REG_DEP_TRUE (reg:DI 4 si [ x+8 ]) + (const_int 8 [0x8]))]) + + or + + (parallel:TI [ + (expr_list:REG_DEP_TRUE (reg:DI 20 xmm0 [ a ]) + (const_int 0 [0])) + (expr_list:REG_DEP_TRUE (reg:DI 21 xmm1 [ a+8 ]) + (const_int 8 [0x8])) + + into a TImode register. */ + if (!REG_P (op0) || GET_MODE (op0) != TImode) + return false; + + if (GET_CODE (op1) != PARALLEL || XVECLEN (op1, 0) != 2) + return false; + + rtx x0 = XVECEXP (op1, 0, 0); + rtx x1 = XVECEXP (op1, 0, 1); + if (GET_CODE (x0) != EXPR_LIST || GET_CODE (x1) != EXPR_LIST) + return false; + + rtx reg0 = XEXP (x0, 0); + rtx reg1 = XEXP (x1, 0); + if (!reg0 + || !REG_P (reg0) + || !HARD_REGISTER_P (reg0) + || !reg1 + || !REG_P (reg1) + || !HARD_REGISTER_P (reg1)) + return false; + + /* Skip + + (parallel:TI [ + (expr_list:REG_DEP_TRUE (reg:DI 5 di [ b ]) + (const_int 0 [0])) + (expr_list:REG_DEP_TRUE (reg:SF 20 xmm0 [ b+8 ]) + (const_int 8 [0x8]))]) + + */ + if (GET_MODE_CLASS (GET_MODE (reg0)) + != GET_MODE_CLASS (GET_MODE(reg1))) + return false; + + /* Skip if OP1 isn't a function parameter. */ + tree reg_expr = REG_EXPR (reg0); + if (!reg_expr || TREE_CODE (reg_expr) != PARM_DECL) + return false; + + /* Verify that REG0 and REG1 come from the same function parameter. */ + if (reg_expr != REG_EXPR (reg1)) + return false; + + /* Return the first field. */ + auto first_field = [] (tree field) + { + for (; field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && TREE_TYPE (field) != error_mark_node) + break; + return field; + }; + + tree type = TREE_TYPE (reg_expr); + if (!RECORD_OR_UNION_TYPE_P (type)) + return false; + + rtx off0 = XEXP (x0, 1); + rtx off1 = XEXP (x1, 1); + if (!CONST_INT_P (off0) + || UINTVAL (off0) != 0 + || !CONST_INT_P (off1) + || UINTVAL (off1) != 8) + return false; + + tree field, field_type = type; + + /* Look for the inner-most record or union. The loop isn't unbounded + since both DECL_CHAIN traversal and nesting depth are finite. */ + do + { + field = first_field (TYPE_FIELDS (field_type)); + /* Skip empty record or union. */ + if (!field) + return false; + field_type = TREE_TYPE (field); + + /* Stop if there is another field. */ + if (first_field (DECL_CHAIN (field))) + break; + } + while (RECORD_OR_UNION_TYPE_P (field_type)); + + rtx_insn *insn, *seq; + + machine_mode mode0, mode1; + if (TREE_CODE (field_type) == ARRAY_TYPE) + { + /* Skip if the record has more than 1 field. */ + if (first_field (DECL_CHAIN (field))) + return false; + + /* Support + + (parallel:TI [ + (expr_list:REG_DEP_TRUE (reg:DI 20 xmm0 [ a ]) + (const_int 0 [0])) + (expr_list:REG_DEP_TRUE (reg:DI 21 xmm1 [ a+8 ]) + (const_int 8 [0x8])) + + where A is a floating point array. */ + tree element_type = TREE_TYPE (field_type); + /* Set MODE1 to the scalar element mode. */ + mode1 = TYPE_MODE (element_type); + /* Skip if this isn't a floating point array. */ + if (GET_MODE_CLASS (mode1) != MODE_FLOAT) + return false; + + /* Skip if the array size isn't 16 bytes. */ + poly_uint64 array_size; + unsigned HOST_WIDE_INT size; + if (!poly_int_tree_p (TYPE_SIZE_UNIT (field_type), + &array_size) + || !array_size.is_constant (&size) + || size != 16) + return false; + + unsigned int s_size = GET_MODE_SIZE (mode1).to_constant (); + unsigned int nunits = 16 / s_size; + scalar_mode smode = as_a <scalar_mode> (mode1); + + /* Set MODE0 to the full vector mode and MODE1 to the half-width + vector mode if there are more than 2 elements per vector. */ + if (!mode_for_vector (smode, nunits).exists (&mode0) + || !targetm.vector_mode_supported_p (mode0) + || (nunits > 2 + && (!mode_for_vector (smode, nunits / 2).exists (&mode1) + || !targetm.vector_mode_supported_p (mode1)))) + return false; + + start_sequence (); + + /* Move the first register to the 8-byte mode. */ + rtx src0 = gen_reg_rtx (mode1); + reg0 = gen_lowpart (mode1, reg0); + insn = emit_move_insn (src0, reg0); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + /* Move the second register to the 8-byte mode. */ + rtx src1 = gen_reg_rtx (mode1); + reg1 = gen_lowpart (mode1, reg1); + insn = emit_move_insn (src1, reg1); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + /* Concatenate 2 8-byte registers into OP0. */ + rtx op = gen_rtx_VEC_CONCAT (mode0, src0, src1); + rtx dest = gen_reg_rtx (mode0); + insn = emit_move_insn (dest, op); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + op = gen_lowpart (TImode, dest); + insn = emit_move_insn (op0, op); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + seq = end_sequence (); + emit_insn (seq); + } + else + { + if (TREE_CODE (DECL_FIELD_CONTEXT (field)) == RECORD_TYPE) + { + /* Check modes on 2 fields to see if we can use SImode move, + instead of DImode move. */ + + mode0 = DECL_MODE (field); + /* C++ has VOIDmode field. */ + if (GET_MODE_CLASS (mode0) != MODE_INT) + return false; + + field = first_field (DECL_CHAIN (field)); + /* Skip if the record has only one field. */ + if (!field) + return false; + + mode1 = DECL_MODE (field); + if (GET_MODE_CLASS (mode1) != MODE_INT) + return false; + + /* Skip if the record have more than 2 fields. */ + field = first_field (DECL_CHAIN (field)); + if (field) + return false; + + /* Skip struct with 2 DImode fields: + + struct X + { + long long f1; + long long f2; + }; + + with + + (parallel:TI [ + (expr_list:REG_DEP_TRUE (reg:DI 5 di [ x ]) + (const_int 0 [0])) + (expr_list:REG_DEP_TRUE (reg:DI 4 si [ x+8 ]) + (const_int 8 [0x8]))]) + + */ + if (mode0 == DImode && mode1 == DImode) + return false; + + /* For struct fields with aligned attribute: + + struct S + { + char a __attribute__ ((aligned(4))); + char b __attribute__ ((aligned(8))); + }; + + if the field mode is narrower than SImode, use SImode to + avoid QImode and HImode register shuffle. */ + if (mode0 == QImode || mode0 == HImode) + mode0 = SImode; + if (mode1 == QImode || mode1 == HImode) + mode1 = SImode; + } + else + { + /* The two eightbytes are fixed at offsets 0 and 8. Use + DImode for bit copy, the actual union member types don't + matter. */ + mode0 = DImode; + mode1 = DImode; + } + + rtx low = simplify_gen_subreg (mode0, op0, TImode, 0); + if (!low) + return false; + rtx high = simplify_gen_subreg (mode1, op0, TImode, 8); + if (!high) + return false; + + start_sequence (); + + /* Move a TImode PARALLEL into a register. Use pseudo registers + to avoid moving a hard register to a subreg. First move the + first register into the first word in the register with a + paradoxical subreg. */ + rtx src = gen_reg_rtx (mode0); + reg0 = gen_lowpart (mode0, reg0); + insn = emit_move_insn (src, reg0); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + insn = emit_move_insn (low, src); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + /* Move the second register into the subreg. */ + src = gen_reg_rtx (mode1); + reg1 = gen_lowpart (mode1, reg1); + insn = emit_move_insn (src, reg1); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + /* NB: Use gen_rtx_SET and emit_insn to generate + + (set (subreg:DI (reg:TI 102) 8) (reg:DI 104)) + + for parameter load. */ + rtx set = gen_rtx_SET (high, src); + insn = emit_insn (set); + if (recog (PATTERN (insn), insn, nullptr) < 0) + { + end_sequence (); + return false; + } + + seq = end_sequence (); + emit_insn (seq); + } + + return true; +} + /* Generate a PARALLEL rtx for a new non-consecutive group of registers from ORIG, where ORIG is a non-consecutive group of registers represented by a PARALLEL. The clone is identical to the original except in that the @@ -3164,6 +3612,12 @@ emit_group_load (rtx dst, rtx src, tree type, poly_int64 ssize) rtx *tmps; int i; + if (GET_CODE (dst) == PARALLEL + && GET_MODE (dst) == BLKmode + && GET_MODE (src) == BLKmode + && expand_parallel_load (dst, src)) + return; + tmps = XALLOCAVEC (rtx, XVECLEN (dst, 0)); emit_group_load_1 (tmps, dst, src, type, ssize); @@ -3281,6 +3735,10 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, return; } + if (GET_CODE (src) == PARALLEL + && expand_parallel_store (orig_dst, src)) + return; + /* Check for a NULL entry, used to indicate that the parameter goes both on the stack and in registers. */ if (XEXP (XVECEXP (src, 0, 0), 0)) diff --git a/gcc/testsuite/g++.target/i386/pr126424-1.C b/gcc/testsuite/g++.target/i386/pr126424-1.C new file mode 100644 index 00000000000..ad813524fde --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr126424-1.C @@ -0,0 +1,80 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -std=c++20" } */ + +template <typename> constexpr bool is_lvalue_reference_v = true; +template <typename _Tp, typename> +concept __weakly_eq_cmp_with = requires (_Tp __t) { __t; }; +struct less +{ +}; +template <typename _Sent, typename _Iter> +concept sentinel_for = __weakly_eq_cmp_with<_Sent, _Iter>; +template <typename _Iter> +concept random_access_iterator = requires (_Iter __n) { __n; }; +struct __normal_iterator +{ + friend void operator- (__normal_iterator, __normal_iterator &); +}; +template <typename _Tp> +concept __maybe_borrowed_range = is_lvalue_reference_v<_Tp>; +struct +{ + template <__maybe_borrowed_range _Tp> + auto + operator() (_Tp __t) + { + return __t.end (); + } +} begin, end; +template <typename _Tp> +concept random_access_range = random_access_iterator<_Tp>; +struct foo1 +{ + __normal_iterator end (); +} links; +struct time_zone_link +{ + void name (); +}; +template <typename _Comp, typename _Proj> struct _Comp_proj +{ + [[no_unique_address]] _Comp _M_comp; + _Proj _M_proj; +}; +template <typename _Comp, typename _Proj> +_Comp_proj<_Comp, _Proj> __make_comp_proj (_Comp, _Proj); +template <typename _Iter, typename _Comp> +void __unguarded_partition_pivot (_Iter, _Comp); +template <typename _Iter, typename _Comp> +void +__introsort_loop (_Iter __last, _Comp __comp) +{ + _Iter __first; + __last - __first; + __unguarded_partition_pivot (__last, __comp); + __introsort_loop (__last, __comp); +} +struct +{ + template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, + typename _Comp, typename _Proj> + _Iter + operator() (_Iter _i, _Sent __last, _Comp __comp, _Proj __proj) + { + auto __comp_proj = __make_comp_proj (__comp, __proj); + __introsort_loop (__last, __comp_proj); + return _i; + } + template <random_access_range _Range, typename _Comp = less, typename _Proj> + _Range + operator() (_Range __r, _Comp __comp, _Proj __proj) + { + (*this) (begin, end (__r), __comp, __proj); + return __r; + } +} sort; +void +reload_tzdb () +{ + sort (links, {}, &time_zone_link::name); +} diff --git a/gcc/testsuite/gcc.target/i386/pr114134-1.c b/gcc/testsuite/gcc.target/i386/pr114134-1.c new file mode 100644 index 00000000000..f6d09e2d9ec --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr114134-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**Key: +**.LFB0: +** .cfi_startproc +** movupd \(%rdi\), %xmm1 +** cvttsd2sil 16\(%rdi\), %edx +** cvttpd2dq %xmm1, %xmm0 +** movq %xmm0, %rax +** ret +** .cfi_endproc +**... +*/ + +struct TVec3D { double x, y, z; }; + +struct TKey { int i, j, k; }; + +struct TKey +Key(struct TVec3D *r) +{ + return __extension__ (struct TKey) {r->x, r->y, r->z}; +} diff --git a/gcc/testsuite/gcc.target/i386/pr114134-2.c b/gcc/testsuite/gcc.target/i386/pr114134-2.c new file mode 100644 index 00000000000..c98b4668058 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr114134-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB0: +** .cfi_startproc +** cvttsd2sil %xmm0, %eax +** ret +** .cfi_endproc +**... +*/ + +struct foo { int i, j; }; + +struct foo +func (double x) +{ + return __extension__ (struct foo) {x, 0}; +} diff --git a/gcc/testsuite/gcc.target/i386/pr114134-3.c b/gcc/testsuite/gcc.target/i386/pr114134-3.c new file mode 100644 index 00000000000..95ca71fc654 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr114134-3.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB0: +** .cfi_startproc +** cvttss2sil %xmm0, %eax +** ret +** .cfi_endproc +**... +*/ + +struct foo { int i, j; }; + +struct foo +func (float x) +{ + return __extension__ (struct foo) {x, 0}; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-1.c b/gcc/testsuite/gcc.target/i386/pr120588-1.c new file mode 100644 index 00000000000..5f34dd0e71f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rsi, %rdx +** movl %edi, %eax +** ret +** .cfi_endproc +**... +*/ + +struct X { + int l1; + long long l2; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-10.c b/gcc/testsuite/gcc.target/i386/pr120588-10.c new file mode 100644 index 00000000000..ee400bc59a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-10.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** ret +** .cfi_endproc +**... +*/ + +struct S386 +{ + _Decimal64 a; + int b; +}; + +struct S386 +func (struct S386 x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-11.c b/gcc/testsuite/gcc.target/i386/pr120588-11.c new file mode 100644 index 00000000000..3ded34dfe7d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-11.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movdqa %xmm3, %xmm1 +** movdqa %xmm2, %xmm0 +** ret +** .cfi_endproc +**... +*/ + +struct S386 +{ + _Decimal64 a[2]; +}; + +struct S386 +func (struct S386 y, struct S386 x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-12.c b/gcc/testsuite/gcc.target/i386/pr120588-12.c new file mode 100644 index 00000000000..b951c73d39a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-12.c @@ -0,0 +1,36 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rsi, %rdx +** movl %edi, %eax +** ret +** .cfi_endproc +**... +*/ + +struct Y1 { + int l1; + long long l2; +}; + +struct Y2 +{ + struct Y1 y; +}; + +struct X +{ + struct Y2 y; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-13.c b/gcc/testsuite/gcc.target/i386/pr120588-13.c new file mode 100644 index 00000000000..2041fffb1ee --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-13.c @@ -0,0 +1,28 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movq %rsi, %rdx +** ret +** .cfi_endproc +**... +*/ + +struct basic_format_args +{ + int f0 : 4; + int f1 : 4; + int *_M_args; +}; + +struct basic_format_args +func (struct basic_format_args x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-14.c b/gcc/testsuite/gcc.target/i386/pr120588-14.c new file mode 100644 index 00000000000..99dc4056e28 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-14.c @@ -0,0 +1,28 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movq %rsi, %rdx +** ret +** .cfi_endproc +**... +*/ + +struct S { + union { + char addr8[16]; + int addr32[4]; + } u; +}; + +struct S +func (struct S ip6) +{ + return ip6; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-15.c b/gcc/testsuite/gcc.target/i386/pr120588-15.c new file mode 100644 index 00000000000..6a073adbc66 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-15.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movl %esi, %edx +** movl %edi, %eax +** ret +** .cfi_endproc +**... +*/ + +struct S347 +{ + int a; + char b __attribute__((aligned(8))); +}; + +struct S347 +func (struct S347 x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-16.c b/gcc/testsuite/gcc.target/i386/pr120588-16.c new file mode 100644 index 00000000000..30995b0c884 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-16.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movl %esi, %edx +** movl %edi, %eax +** ret +** .cfi_endproc +**... +*/ + +struct S347 +{ + char a __attribute__((aligned(4))); + char b __attribute__((aligned(8))); +}; + +struct S347 +func (struct S347 x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-17.c b/gcc/testsuite/gcc.target/i386/pr120588-17.c new file mode 100644 index 00000000000..6f4e375d85a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-17.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movl %esi, %edx +** ret +** .cfi_endproc +**... +*/ + +struct S347 +{ + long long a; + char b __attribute__((aligned(8))); +}; + +struct S347 +func (struct S347 x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-18.c b/gcc/testsuite/gcc.target/i386/pr120588-18.c new file mode 100644 index 00000000000..11b47cb7dcd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-18.c @@ -0,0 +1,35 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rsi, %rdx +** movq %rdi, %rax +** ret +** .cfi_endproc +**... +*/ + +struct Y1 { + int l1; + long long l2; +}; + +struct X +{ + union U + { + struct Y1 y; + int x; + } u; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-19.c b/gcc/testsuite/gcc.target/i386/pr120588-19.c new file mode 100644 index 00000000000..eb53d80f6c1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-19.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rsi, %rdx +** movq %rdi, %rax +** ret +** .cfi_endproc +**... +*/ + +struct Y1 { + int l1; + long long l2; +}; + +union U { + struct Y1 y; + int x; +}; + +union U +func (union U x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-2.c b/gcc/testsuite/gcc.target/i386/pr120588-2.c new file mode 100644 index 00000000000..2e975bdb220 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movl %esi, %edx +** ret +** .cfi_endproc +**... +*/ + +struct X { + long long l2; + int l1; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-20.c b/gcc/testsuite/gcc.target/i386/pr120588-20.c new file mode 100644 index 00000000000..a9e5f2c988c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-20.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movq %rsi, %rdx +** ret +** .cfi_endproc +**... +*/ + +struct X { + __int128 l; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-3.c b/gcc/testsuite/gcc.target/i386/pr120588-3.c new file mode 100644 index 00000000000..ca13826cbd1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-3.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movq %rsi, %rdx +** ret +** .cfi_endproc +**... +*/ + +struct X +{ + long long l1; + long long l2; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-4.c b/gcc/testsuite/gcc.target/i386/pr120588-4.c new file mode 100644 index 00000000000..51d84d59633 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-4.c @@ -0,0 +1,29 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +#include <stdbool.h> + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** cmpl %edx, %edi +** sete %al +** ret +** .cfi_endproc +**... +*/ + +struct error_condition +{ + int _M_value; + int *_M_cat; +}; + +bool +func (struct error_condition x, struct error_condition y) +{ + return x._M_value == y._M_value; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-5.c b/gcc/testsuite/gcc.target/i386/pr120588-5.c new file mode 100644 index 00000000000..a36f79032f5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-5.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movl %esi, %edx +** ret +** .cfi_endproc +**... +*/ + +struct X { + int f1; + int f2; + int f3; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-6.c b/gcc/testsuite/gcc.target/i386/pr120588-6.c new file mode 100644 index 00000000000..8e366172d44 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-6.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movl %esi, %edx +** ret +** .cfi_endproc +**... +*/ + +struct X +{ + int f1[3]; +}; + +struct X +func (struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-7.c b/gcc/testsuite/gcc.target/i386/pr120588-7.c new file mode 100644 index 00000000000..4f23eb8c976 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-7.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movq %rsi, %rdx +** ret +** .cfi_endproc +**... +*/ + +struct foo +{ + long long w[2]; +}; + +struct foo +func (struct foo x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-8.c b/gcc/testsuite/gcc.target/i386/pr120588-8.c new file mode 100644 index 00000000000..87b62fce3c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-8.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %rax +** movaps %xmm1, %xmm0 +** ret +** .cfi_endproc +**... +*/ + +struct X { + float l2; + long long l1; +}; + +struct X +func (float f, struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr120588-9.c b/gcc/testsuite/gcc.target/i386/pr120588-9.c new file mode 100644 index 00000000000..6afc936500c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120588-9.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movaps %xmm1, %xmm0 +** movq %rdi, %rax +** ret +** .cfi_endproc +**... +*/ + +struct X { + long long l1; + float l2; +}; + +struct X +func (float f, struct X x) +{ + return x; +} diff --git a/gcc/testsuite/gcc.target/i386/pr126403-1.c b/gcc/testsuite/gcc.target/i386/pr126403-1.c new file mode 100644 index 00000000000..afa394e3587 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr126403-1.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movlhps %xmm1, %xmm0 +** movlhps %xmm3, %xmm2 +** mulps %xmm0, %xmm2 +** movhlps %xmm2, %xmm1 +** movdqa %xmm2, %xmm0 +** ret +** .cfi_endproc +**... +*/ + +#define N 4 + +typedef struct { float values[N]; } vector; + +vector +func (vector a, vector b) +{ + vector r; + for (int i = 0; i < N; i++) + r.values[i] = a.values[i] * b.values[i]; + return r; +} diff --git a/gcc/testsuite/gcc.target/i386/pr126403-2.c b/gcc/testsuite/gcc.target/i386/pr126403-2.c new file mode 100644 index 00000000000..5b44b623df1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr126403-2.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** unpcklpd %xmm1, %xmm0 +** unpcklpd %xmm3, %xmm2 +** mulpd %xmm2, %xmm0 +** movapd %xmm0, %xmm1 +** unpckhpd %xmm1, %xmm1 +** ret +** .cfi_endproc +**... +*/ + +#define N 2 + +typedef struct { double values[N]; } vector; + +vector +func (vector a, vector b) +{ + vector r; + for (int i = 0; i < N; i++) + r.values[i] = a.values[i] * b.values[i]; + return r; +} diff --git a/gcc/testsuite/gcc.target/i386/pr126403-3.c b/gcc/testsuite/gcc.target/i386/pr126403-3.c new file mode 100644 index 00000000000..d72c9f85a35 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr126403-3.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64-v4 -mavx512fp16 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** vmovlhps %xmm1, %xmm0, %xmm1 +** vmovlhps %xmm3, %xmm2, %xmm3 +** vmulph %xmm3, %xmm1, %xmm1 +** vmovdqa %xmm1, %xmm0 +** vpsrldq \$8, %xmm1, %xmm1 +** ret +** .cfi_endproc +**... +*/ + +#define N 8 + +typedef struct { _Float16 values[N]; } vector; + +vector +func (vector a, vector b) +{ + vector r; + for (int i = 0; i < N; i++) + r.values[i] = a.values[i] * b.values[i]; + return r; +} diff --git a/gcc/testsuite/gcc.target/i386/pr126403-4.c b/gcc/testsuite/gcc.target/i386/pr126403-4.c new file mode 100644 index 00000000000..9b14810a78d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr126403-4.c @@ -0,0 +1,33 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -march=x86-64 -fomit-frame-pointer" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**func: +**.LFB[0-9]+: +** .cfi_startproc +** movlhps %xmm1, %xmm0 +** movlhps %xmm3, %xmm2 +** mulps %xmm0, %xmm2 +** movhlps %xmm2, %xmm1 +** movdqa %xmm2, %xmm0 +** ret +** .cfi_endproc +**... +*/ + +#define N 4 + +typedef struct { float values[N]; } vector1; +typedef struct { vector1 v; } vector2; +typedef struct { vector2 v; } vector; + +vector +func (vector a, vector b) +{ + vector r; + for (int i = 0; i < N; i++) + r.v.v.values[i] = a.v.v.values[i] * b.v.v.values[i]; + return r; +} diff --git a/gcc/testsuite/gcc.target/i386/zext-sse-2.c b/gcc/testsuite/gcc.target/i386/zext-sse-2.c index 7d917cfd5de..e8815c2515c 100644 --- a/gcc/testsuite/gcc.target/i386/zext-sse-2.c +++ b/gcc/testsuite/gcc.target/i386/zext-sse-2.c @@ -29,11 +29,10 @@ struct bar2 **func1: **.LFB[0-9]+: ** .cfi_startproc -** cvttsd2sil 16\(%rdi\), %ecx ** movupd \(%rdi\), %xmm1 +** cvttsd2sil 16\(%rdi\), %edx ** cvttpd2dq %xmm1, %xmm0 ** movq %xmm0, %rax -** movq %rcx, %rdx ** ret ** .cfi_endproc **... @@ -49,13 +48,10 @@ func1 (struct bar1 *x) **func2: **.LFB[0-9]+: ** .cfi_startproc -** cvttss2sil 8\(%rdi\), %eax ** movq \(%rdi\), %xmm0 +** cvttss2sil 8\(%rdi\), %edx ** cvttps2dq %xmm0, %xmm0 -** movq %xmm0, %rsi -** movq %rax, %rdi -** movq %rsi, %rax -** movq %rdi, %rdx +** movq %xmm0, %rax ** ret ** .cfi_endproc **... -- 2.55.0