This patch adds a new internal function IFN_VEC_LOAD_EXTEND with its
optab, and the x86 sse.md patterns that implement it. 
Nothing generates the internal function yet, so this patch does not
change code generation.

gcc/ChangeLog:

        * config/i386/sse.md (vec_widen_<s>load<load_ext_src_lower><mode>): New 
expander.
        (vec_widen_<s>load<load_ext_qi_src_lower><mode>): New expander.
        * internal-fn.cc (load_extend_direct): New direct optab.
        (expand_load_extend_optab_fn): New expander.
        (direct_load_extend_optab_supported_p): New supported optab.
        (internal_load_fn_p): New internal load function.
        * internal-fn.def (VEC_LOAD_EXTEND): New internal load function.
        * optabs.def (OPTAB_CD): New optab.
---
 gcc/config/i386/sse.md | 30 ++++++++++++++++++++++++++++++
 gcc/internal-fn.cc     | 23 +++++++++++++++++++++++
 gcc/internal-fn.def    |  3 +++
 gcc/optabs.def         |  2 ++
 4 files changed, 58 insertions(+)

diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 3a445c9746d..8c40e523d2f 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -24978,6 +24978,36 @@
    (set_attr "prefix" "orig,orig,vex")
    (set_attr "mode" "TI")])
 
+;; Same-lane vector extending loads.  SImode vectors can be loaded from
+;; both QImode and HImode elements, so the 2x and 4x widenings need
+;; separate expanders.
+(define_mode_iterator VI24_LOAD_EXT
+  [V8HI (V16HI "TARGET_AVX2") (V32HI "TARGET_AVX512BW")
+   V4SI (V8SI "TARGET_AVX2") (V16SI "TARGET_AVX512F")])
+(define_mode_attr load_ext_src
+  [(V8HI "V8QI") (V16HI "V16QI") (V32HI "V32QI")
+   (V4SI "V4HI") (V8SI "V8HI") (V16SI "V16HI")])
+(define_mode_attr load_ext_src_lower
+  [(V8HI "v8qi") (V16HI "v16qi") (V32HI "v32qi")
+   (V4SI "v4hi") (V8SI "v8hi") (V16SI "v16hi")])
+
+(define_expand "vec_widen_<s>load<load_ext_src_lower><mode>"
+  [(set (match_operand:VI24_LOAD_EXT 0 "register_operand")
+       (any_extend:VI24_LOAD_EXT
+         (match_operand:<load_ext_src> 1 "memory_operand")))]
+  "TARGET_SSE4_1")
+
+(define_mode_attr load_ext_qi_src
+  [(V4SI "V4QI") (V8SI "V8QI") (V16SI "V16QI")])
+(define_mode_attr load_ext_qi_src_lower
+  [(V4SI "v4qi") (V8SI "v8qi") (V16SI "v16qi")])
+
+(define_expand "vec_widen_<s>load<load_ext_qi_src_lower><mode>"
+  [(set (match_operand:VI4_AVX512F 0 "register_operand")
+       (any_extend:VI4_AVX512F
+         (match_operand:<load_ext_qi_src> 1 "memory_operand")))]
+  "TARGET_SSE4_1")
+
 (define_insn "avx2_<code>v16qiv16hi2<mask_name>"
   [(set (match_operand:V16HI 0 "register_operand" "=Yw")
        (any_extend:V16HI
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index d277a07eaf7..3f117d1bbe2 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -158,6 +158,7 @@ init_internal_fns ()
    direct_internal_fn.  */
 #define not_direct { -2, -2, false, 0, 0 }
 #define mask_load_direct { -1, 2, false, 4, 4 }
+#define load_extend_direct { -1, 2, false, 3, 3 }
 #define load_lanes_direct { -1, -1, false, 1, 1 }
 #define mask_load_lanes_direct { -1, -1, false, 4, 4 }
 #define mask_len_load_lanes_direct { -1, -1, false, 6, 6 }
@@ -3223,6 +3224,26 @@ expand_partial_load_optab_fn (internal_fn ifn, gcall 
*stmt, convert_optab optab)
   assign_call_lhs (lhs, target, &ops[0]);
 }
 
+/* Expand VEC_LOAD_EXTEND call STMT using OPTAB.  */
+
+static void
+expand_load_extend_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
+{
+  class expand_operand ops[2];
+  tree lhs = gimple_call_lhs (stmt);
+  tree result_type = TREE_TYPE (lhs);
+  tree memory_type = TREE_TYPE (gimple_call_arg (stmt, 2));
+  tree rhs = expand_call_mem_ref (memory_type, stmt, 0);
+  rtx mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_MEMORY);
+  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+  create_call_lhs_operand (&ops[0], target, TYPE_MODE (result_type));
+  create_fixed_operand (&ops[1], mem);
+  expand_insn (convert_optab_handler (optab, TYPE_MODE (result_type),
+                                    TYPE_MODE (memory_type)),
+              2, ops);
+  assign_call_lhs (lhs, target, &ops[0]);
+}
+
 #define expand_mask_load_optab_fn expand_partial_load_optab_fn
 #define expand_mask_load_lanes_optab_fn expand_mask_load_optab_fn
 #define expand_mask_len_load_lanes_optab_fn expand_mask_load_optab_fn
@@ -4485,6 +4506,7 @@ multi_vector_optab_supported_p (convert_optab optab, 
tree_pair types,
 #define direct_cond_len_ternary_optab_supported_p direct_optab_supported_p
 #define direct_crc_optab_supported_p convert_optab_supported_p
 #define direct_mask_load_optab_supported_p convert_optab_supported_p
+#define direct_load_extend_optab_supported_p convert_optab_supported_p
 #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
 #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
 #define direct_mask_len_load_lanes_optab_supported_p \
@@ -5215,6 +5237,7 @@ internal_load_fn_p (internal_fn fn)
   switch (fn)
     {
     case IFN_MASK_LOAD:
+    case IFN_VEC_LOAD_EXTEND:
     case IFN_LOAD_LANES:
     case IFN_MASK_LOAD_LANES:
     case IFN_MASK_LEN_LOAD_LANES:
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 7626836ba64..68108865a35 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3.  If not see
 
    - fold_left: for scalar = FN (scalar, vector), keyed off the vector mode
    - check_ptrs: used for check_{raw,war}_ptrs
+   - load_extend: an extending load, keyed off the result and memory modes
 
    - cond_len_unary: a conditional unary optab, such as cond_len_neg<mode>
    - cond_len_binary: a conditional binary optab, such as cond_len_add<mode>
@@ -232,6 +233,8 @@ along with GCC; see the file COPYING3.  If not see
 DEF_INTERNAL_OPTAB_FN (CRC, ECF_CONST | ECF_NOTHROW, crc, crc)
 DEF_INTERNAL_OPTAB_FN (CRC_REV, ECF_CONST | ECF_NOTHROW, crc_rev, crc)
 DEF_INTERNAL_OPTAB_FN (MASK_LOAD, ECF_PURE, maskload, mask_load)
+DEF_INTERNAL_SIGNED_OPTAB_FN (VEC_LOAD_EXTEND, ECF_PURE, second,
+                             vec_widen_sload, vec_widen_uload, load_extend)
 DEF_INTERNAL_OPTAB_FN (LOAD_LANES, ECF_CONST, vec_load_lanes, load_lanes)
 DEF_INTERNAL_OPTAB_FN (MASK_LOAD_LANES, ECF_PURE,
                       vec_mask_load_lanes, mask_load_lanes)
diff --git a/gcc/optabs.def b/gcc/optabs.def
index d6806a6156a..0bf127e1e89 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -95,6 +95,8 @@ OPTAB_CD(vec_mask_load_lanes_optab, "vec_mask_load_lanes$a$b")
 OPTAB_CD(vec_mask_store_lanes_optab, "vec_mask_store_lanes$a$b")
 OPTAB_CD(vec_mask_len_load_lanes_optab, "vec_mask_len_load_lanes$a$b")
 OPTAB_CD(vec_mask_len_store_lanes_optab, "vec_mask_len_store_lanes$a$b")
+OPTAB_CD(vec_widen_sload_optab, "vec_widen_sload$b$a")
+OPTAB_CD(vec_widen_uload_optab, "vec_widen_uload$b$a")
 OPTAB_CD(vcond_mask_optab, "vcond_mask_$a$b")
 OPTAB_CD(vec_cmp_optab, "vec_cmp$a$b")
 OPTAB_CD(vec_cmpu_optab, "vec_cmpu$a$b")
-- 
2.34.1

Reply via email to