Recognize a contiguous load whose only use is an integer widening
conversion and replace the pair with .VEC_LOAD_EXTEND when the target
supports it.  The pattern runs after the other widening patterns so
that widen_mult, dot_prod and sad still see the conversion.
VEC_LOAD_EXTEND has no masked or length-controlled form, so the pattern
is not applied to loops that may use partial vectors.  The vectorization
factor stays that of the narrower memory type.

The tests vect-epilogues-2b.c, vect-epilogues-3.c and vect-unpack-2.c are
updated because the patch fuses a load and a widening conversion into a
direct extending load.  In vect-epilogues-2b.c the epilogue is now a single
32-byte loop instead of cascaded 16-byte and 8-byte epilogues.
vect-epilogues-3.c no longer produces a 16-byte vectorized loop.
vect-unpack-2.c replaces the unpack-based vpmovsxbw sequence with fused
vpmovsxbd.  

gcc/ChangeLog:
        * tree-vect-loop.cc (vect_analyze_loop_2): Record when an epilogue
        cannot use partial vectors before pattern recognition.
        * tree-vect-patterns.cc (vect_name_used_in_pattern_p): New function.
        (vect_load_used_only_by_p): New function.
        (vect_loop_may_use_partial_vectors_p): New function.
        (vect_recog_load_extend_pattern): Recognize a widening conversion of
        a contiguous load and replace it with .VEC_LOAD_EXTEND.
        (vect_pattern_recog): Run extending-load recognition after the other
        patterns.
        * tree-vect-slp.cc (vect_build_slp_tree_3): Treat VEC_LOAD_EXTEND as
        a load.
        (vect_build_slp_tree_2): Do not require a mask on VEC_LOAD_EXTEND.
        (vect_update_slp_vf_for_node): Keep the vectorization factor required
        by the narrower memory type.
        * tree-vect-stmts.cc (vectorizable_load): Expand IFN_VEC_LOAD_EXTEND
        as a contiguous extending load.
gcc/testsuite/ChangeLog:
        * gcc.dg/vect/widening-load-u8.c: New test.
        * gcc.target/i386/vect-load-extend-1.c: New test.
        * gcc.target/i386/vect-epilogues-2b.c: Expect a 32-byte epilogue.
        * gcc.target/i386/vect-epilogues-3.c: Drop the 16-byte vector scan.
        * gcc.target/i386/vect-unpack-2.c: Expect vpmovsxbd.
---
 gcc/testsuite/gcc.dg/vect/widening-load-u8.c  |  20 ++
 .../gcc.target/i386/vect-epilogues-2b.c       |   4 +-
 .../gcc.target/i386/vect-epilogues-3.c        |   1 -
 .../gcc.target/i386/vect-load-extend-1.c      |  24 +++
 gcc/testsuite/gcc.target/i386/vect-unpack-2.c |   2 +-
 gcc/tree-vect-loop.cc                         |   9 +
 gcc/tree-vect-patterns.cc                     | 190 ++++++++++++++++++
 gcc/tree-vect-slp.cc                          |  22 +-
 gcc/tree-vect-stmts.cc                        |  59 +++++-
 9 files changed, 323 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/widening-load-u8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/vect-load-extend-1.c

diff --git a/gcc/testsuite/gcc.dg/vect/widening-load-u8.c 
b/gcc/testsuite/gcc.dg/vect/widening-load-u8.c
new file mode 100644
index 00000000000..5e85ab1659e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/widening-load-u8.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target avx512bw } } */
+/* { dg-additional-options "-mavx512f -mavx512bw --param 
vect-epilogues-nomask=0 -save-temps -fdump-tree-optimized" } */
+/* { dg-require-effective-target avx512bw } */
+
+#include <stdint.h>
+
+/* uint8 loads widened for int mul/add/shift/store.
+   Exercises load+extend fusion of widening loads.  */
+void
+widening_load_u8 (uint8_t * restrict dst, uint8_t *restrict src,
+                 uint8_t *restrict srcp, int cA, int cC, int n)
+{
+  for (int x = 0; x < n; x++)
+    dst[x] = (cA * src[x] + cC * srcp[x] + 32) >> 6;
+}
+
+/* { dg-final { scan-tree-dump "load_extend pattern recognized" "vect" } } */
+/* { dg-final { scan-tree-dump "= \\.VEC_LOAD_EXTEND \\(" "optimized" } } */
+/* { dg-final { scan-assembler "vpmovzxbw\[ \\t\]+\\\(\%" } } */
+/* { dg-final { scan-assembler-not "vpmovzxbw\[ \\t\]+%ymm" } } */
diff --git a/gcc/testsuite/gcc.target/i386/vect-epilogues-2b.c 
b/gcc/testsuite/gcc.target/i386/vect-epilogues-2b.c
index 4a58dc67bde..1f0c47e8189 100644
--- a/gcc/testsuite/gcc.target/i386/vect-epilogues-2b.c
+++ b/gcc/testsuite/gcc.target/i386/vect-epilogues-2b.c
@@ -10,6 +10,4 @@ int test (signed char *data, int n)
 }
 
 /* { dg-final { scan-tree-dump "loop vectorized using 64 byte vectors" "vect" 
} } */
-/* { dg-final { scan-tree-dump-not "loop vectorized using 32 byte vectors" 
"vect" } } */
-/* { dg-final { scan-tree-dump "loop vectorized using 16 byte vectors" "vect" 
} } */
-/* { dg-final { scan-tree-dump "loop vectorized using 8 byte vectors" "vect" { 
target { ! ia32 } } } } */
+/* { dg-final { scan-tree-dump "epilogue loop vectorized using 32 byte 
vectors" "vect" } } */
diff --git a/gcc/testsuite/gcc.target/i386/vect-epilogues-3.c 
b/gcc/testsuite/gcc.target/i386/vect-epilogues-3.c
index e88ab30c770..6ef2bac1505 100644
--- a/gcc/testsuite/gcc.target/i386/vect-epilogues-3.c
+++ b/gcc/testsuite/gcc.target/i386/vect-epilogues-3.c
@@ -11,5 +11,4 @@ int test (signed char *data, int n)
 
 /* { dg-final { scan-tree-dump "loop vectorized using 64 byte vectors" "vect" 
} } */
 /* { dg-final { scan-tree-dump "loop vectorized using 32 byte vectors" "vect" 
} } */
-/* { dg-final { scan-tree-dump "loop vectorized using 16 byte vectors" "vect" 
} } */
 /* { dg-final { scan-tree-dump "loop vectorized using 8 byte vectors" "vect" { 
target { ! ia32 } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/vect-load-extend-1.c 
b/gcc/testsuite/gcc.target/i386/vect-load-extend-1.c
new file mode 100644
index 00000000000..128b15afaf7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/vect-load-extend-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -mavx512bw -mprefer-vector-width=512 --param 
vect-epilogues-nomask=0 -fdump-tree-optimized" } */
+
+/* A widening conversion of a loaded value should become an extending load
+   from memory, keeping the vectorization factor of the narrow load.  */
+
+void
+u16_u32 (unsigned int *__restrict d, unsigned short *__restrict s, int n)
+{
+  for (int i = 0; i < n; i++)
+    d[i] = s[i];
+}
+
+void
+s8_s32 (int *__restrict d, signed char *__restrict s, int n)
+{
+  for (int i = 0; i < n; i++)
+    d[i] = s[i];
+}
+
+/* { dg-final { scan-tree-dump-times "= \\.VEC_LOAD_EXTEND \\(" 6 "optimized" 
} } */
+/* { dg-final { scan-assembler-times "vpmovzxwd\[ \\t\]+\[^\n\]*\\), %zmm" 2 } 
} */
+/* { dg-final { scan-assembler-times "vpmovsxbd\[ \\t\]+\[^\n\]*\\), %zmm" 4 } 
} */
+/* { dg-final { scan-assembler-not "vpmov\[sz\]x\[bwd\]+\[ \\t\]+%\[xyz\]mm" } 
} */
diff --git a/gcc/testsuite/gcc.target/i386/vect-unpack-2.c 
b/gcc/testsuite/gcc.target/i386/vect-unpack-2.c
index c578aa16d4c..c4a5dedc620 100644
--- a/gcc/testsuite/gcc.target/i386/vect-unpack-2.c
+++ b/gcc/testsuite/gcc.target/i386/vect-unpack-2.c
@@ -28,4 +28,4 @@ avx512bw_test ()
       abort ();
 }
 
-/* { dg-final { scan-assembler-times "vpmovsxbw\[ \\t\]+\[^\n\]*%zmm" 2 } } */
+/* { dg-final { scan-assembler-times "vpmovsxbd\[ \\t\]+\[^\n\]*%zmm" 4 } } */
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index 78bfd607c5d..c7c114f6751 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -2261,6 +2261,15 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, int 
masked_p, bool &fatal,
   if (LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
     LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
 
+  /* Record up front when an epilogue cannot use partial vectors so that
+     pattern recognition can take it into account.  This is not done for
+     the main loop since epilogue analysis consults its
+     LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P.  */
+  if (LOOP_VINFO_EPILOGUE_P (loop_vinfo)
+      && (masked_p == 0
+         || (masked_p == -1 && param_vect_partial_vector_usage == 0)))
+    LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
+
   /* The first group of checks is independent of the vector size.  */
   fatal = true;
 
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index cbe834e2aaf..7352e039057 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -6687,6 +6687,183 @@ vect_recog_mask_conversion_pattern (vec_info *vinfo,
   return pattern_stmt;
 }
 
+/* Return true if NAME is used by a pattern statement other than SKIP that
+   replaced STMT_INFO, including nested replacements in its definition
+   sequence.  */
+
+static bool
+vect_name_used_in_pattern_p (vec_info *vinfo, stmt_vec_info stmt_info,
+                            tree name, gimple *skip)
+{
+  //STMT_VINFO_IN_PATTERN_P is set when statement was rewritten by pattern
+  // recognition.If it is clear, there is no replacement to search.
+  if (!STMT_VINFO_IN_PATTERN_P (stmt_info))
+    return false;
+
+  auto uses_name_p = [name, skip] (gimple *stmt)
+    {
+      if (stmt == skip)
+       return false;
+      for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
+       if (gimple_op (stmt, i) == name)
+         return true;
+      return false;
+    };
+
+  //For a statement that is in a pattern, fetch GIMPLE of the replacement.
+  if (uses_name_p (STMT_VINFO_RELATED_STMT (stmt_info)->stmt))
+    return true;
+
+  //A pattern can also have setup statements stored on the original
+  // statement in STMT_VINFO_PATTERN_DEF_SEQ.
+  // Search through all the setup statements to see if any of them use name.
+  for (gimple_stmt_iterator gsi
+        = gsi_start (STMT_VINFO_PATTERN_DEF_SEQ (stmt_info));
+       !gsi_end_p (gsi); gsi_next (&gsi))
+    if (uses_name_p (gsi_stmt (gsi))
+       || vect_name_used_in_pattern_p (vinfo,
+                                       vinfo->lookup_stmt (gsi_stmt (gsi)),
+                                       name, skip))
+      return true;
+  return false;
+}
+
+/* Return true if STMT is the only user of NAME, the result of a load.  */
+
+static bool
+vect_load_used_only_by_p (vec_info *vinfo, tree name, gimple *stmt)
+{
+  if (!has_single_use (name))
+    return false;
+
+  for (unsigned i = 0; i < vinfo->nbbs; ++i)
+    for (auto si = gsi_start_bb (vinfo->bbs[i]); !gsi_end_p (si);
+        gsi_next (&si))
+      if (stmt_vec_info info = vinfo->lookup_stmt (gsi_stmt (si)))
+       if (vect_name_used_in_pattern_p (vinfo, info, name, stmt))
+         return false;
+
+  return true;
+}
+
+/* Return true if LOOP_VINFO might be vectorized using partial vectors.
+   IFN_VEC_LOAD_EXTEND has no masked or length-controlled form, so using
+   it there would force a loop to use full vectors only.  */
+
+static bool
+vect_loop_may_use_partial_vectors_p (loop_vec_info loop_vinfo)
+{
+  if (!LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
+    return false;
+
+  /* Epilogues that cannot use partial vectors have been marked already.  */
+  if (LOOP_VINFO_EPILOGUE_P (loop_vinfo))
+    return true;
+
+  /* The main loop follows --param vect-partial-vector-usage.  With 1 it
+     operates on full vectors unless the number of iterations is known to
+     be smaller than the vectorization factor.  */
+  if (param_vect_partial_vector_usage == 0
+      || (param_vect_partial_vector_usage == 1
+         && !LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)))
+    return false;
+
+  return true;
+}
+
+/* Recognize an integer widening conversion fed by a plain contiguous load
+   and replace the pair with an extending-load internal function.
+
+     narrow = *ptr;
+     wide = (WIDE_TYPE) narrow;
+
+   becomes
+
+     wide = .VEC_LOAD_EXTEND (ptr, alignment, (NARROW_TYPE) 0);  */
+
+static gimple *
+vect_recog_load_extend_pattern (vec_info *vinfo, stmt_vec_info stmt_info,
+                               tree *type_out)
+{
+  loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
+  if (!loop_vinfo
+      || LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
+      || vect_loop_may_use_partial_vectors_p (loop_vinfo))
+    return NULL;
+
+  gassign *convert = dyn_cast <gassign *> (stmt_info->stmt);
+  if (!convert
+      || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (convert)))
+    return NULL;
+
+  tree lhs = gimple_assign_lhs (convert);
+  tree rhs = gimple_assign_rhs1 (convert);
+  if (TREE_CODE (rhs) != SSA_NAME)
+    return NULL;
+
+  tree lhs_type = TREE_TYPE (lhs);
+  tree rhs_type = TREE_TYPE (rhs);
+  if (!INTEGRAL_TYPE_P (lhs_type) || !INTEGRAL_TYPE_P (rhs_type))
+    return NULL;
+
+  if (TYPE_PRECISION (lhs_type) <= TYPE_PRECISION (rhs_type))
+    return NULL;
+
+  stmt_vec_info load_info = vinfo->lookup_def (rhs);
+  if (!load_info || !STMT_VINFO_DATA_REF (load_info))
+    return NULL;
+
+  gassign *load = dyn_cast <gassign *> (load_info->stmt);
+  if (!load || !vect_load_used_only_by_p (vinfo, rhs, convert))
+    return NULL;
+
+  /* Access grouping is not known yet, so require a unit step to rule out
+     strided access.  */
+  data_reference *dr = STMT_VINFO_DATA_REF (load_info);
+  if (!tree_int_cst_equal (DR_STEP (dr), TYPE_SIZE_UNIT (rhs_type)))
+    return NULL;
+
+  tree result_vectype = get_vectype_for_scalar_type (vinfo, lhs_type);
+  if (!result_vectype)
+    return NULL;
+
+  poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (result_vectype);
+  tree memory_vectype
+    = get_related_vectype_for_scalar_type (TYPE_MODE (result_vectype),
+                                          rhs_type, nunits);
+  if (!memory_vectype
+      || !direct_internal_fn_supported_p
+           (IFN_VEC_LOAD_EXTEND,
+            tree_pair (result_vectype, memory_vectype),
+            OPTIMIZE_FOR_BOTH))
+    return NULL;
+
+  //Build the new pattern statement.
+  //addr= address of the data reference.
+  //alignment= alignment of the data reference.
+  //type_operand= 0.
+  tree addr = build_fold_addr_expr (DR_REF (dr));
+  tree alias_type = reference_alias_ptr_type (DR_REF (dr));
+  tree alignment = build_int_cst (alias_type, TYPE_ALIGN (rhs_type));
+  tree type_operand = build_zero_cst (rhs_type);
+  gcall *pattern_stmt
+    = gimple_build_call_internal (IFN_VEC_LOAD_EXTEND, 3,
+                                 addr, alignment, type_operand);
+  //Set the left-hand side of the new pattern statement.
+  tree pattern_lhs = vect_recog_temp_ssa_var (lhs_type, NULL);
+  gimple_call_set_lhs (pattern_stmt, pattern_lhs);
+  gimple_set_location (pattern_stmt, gimple_location (convert));
+
+  //Add the new pattern statement to the vectorization info.
+  stmt_vec_info pattern_info = vinfo->add_stmt (pattern_stmt);
+  //Copy the data reference to the new pattern statement.
+  vinfo->move_dr (pattern_info, load_info);
+
+  *type_out = result_vectype;
+  vect_pattern_detected ("vect_recog_load_extend_pattern", convert);
+  return pattern_stmt;
+}
+
 /* STMT_INFO is a load or store.  If the load or store is conditional, return
    the boolean condition under which it occurs, otherwise return null.  */
 
@@ -8034,6 +8211,19 @@ vect_pattern_recog (vec_info *vinfo)
        }
     }
 
+  /* Extending loads must be recognized after every other pattern, since
+     replacing the conversion would hide it from widening patterns such as
+     widen_mult, dot_prod and sad that consume it.  */
+  const vect_recog_func load_extend_recog
+    = { vect_recog_load_extend_pattern, "load_extend" };
+  for (unsigned i = 0; i < nbbs; ++i)
+    for (auto si = gsi_start_bb (bbs[i]); !gsi_end_p (si); gsi_next (&si))
+      {
+       stmt_vec_info stmt_info = vinfo->lookup_stmt (gsi_stmt (si));
+       if (stmt_info && STMT_VINFO_VECTORIZABLE (stmt_info))
+         vect_pattern_recog_1 (vinfo, load_extend_recog, stmt_info);
+      }
+
   /* After this no more add_stmt calls are allowed.  */
   vinfo->stmt_vec_info_ro = true;
 }
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index ae73837a76d..92ecb175a90 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -1226,7 +1226,8 @@ vect_build_slp_tree_3 (vec_info *vinfo, 
vec<stmt_vec_info> stmts,
          else
            rhs_code = CALL_EXPR;
 
-         if (cfn == CFN_GATHER_LOAD
+         if (cfn == CFN_VEC_LOAD_EXTEND
+             || cfn == CFN_GATHER_LOAD
              || cfn == CFN_SCATTER_STORE)
            ldst_p = true;
          else if (cfn == CFN_MASK_LOAD
@@ -2276,7 +2277,8 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node,
              load_permutation.quick_push (load_place);
            }
 
-         if (gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt))
+         gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt);
+         if (stmt && !gimple_call_internal_p (stmt, IFN_VEC_LOAD_EXTEND))
            {
              gcc_assert (gimple_call_internal_p (stmt, IFN_MASK_LOAD));
              bool has_gaps = false;
@@ -8758,6 +8760,22 @@ vect_update_slp_vf_for_node (slp_tree node, poly_uint64 
&vf,
                                  SLP_TREE_LANES (node));
   vf = force_common_multiple (vf, node_vf);
 
+  /* An extending load must not lower the vectorization factor below what
+     the load of the narrower memory type would have required.  */
+  stmt_vec_info rep = SLP_TREE_REPRESENTATIVE (node);
+  if (gcall *call = rep ? dyn_cast <gcall *> (rep->stmt) : NULL)
+    if (gimple_call_internal_p (call, IFN_VEC_LOAD_EXTEND))
+      {
+       tree memory_type = TREE_TYPE (gimple_call_arg (call, 2));
+       if (tree memory_vectype
+             = get_related_vectype_for_scalar_type (TYPE_MODE (vectype),
+                                                    memory_type))
+         vf = force_common_multiple
+                (vf, calculate_unrolling_factor
+                       (TYPE_VECTOR_SUBPARTS (memory_vectype),
+                        SLP_TREE_LANES (node)));
+      }
+
   /* For permute nodes that are fed from externs or constants we have to
      consider their number of lanes as well.  Likewise for store-lanes.  */
   if (SLP_TREE_PERMUTE_P (node) || node->ldst_lanes)
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index cd2300cd30d..4dc5929cdd0 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -9838,6 +9838,7 @@ vectorizable_load (vec_info *vinfo,
 
   tree mask_vectype = NULL_TREE;
   tree els = NULL_TREE; tree els_vectype = NULL_TREE;
+  bool load_extend_p = false;
 
   int mask_index = -1;
   int els_index = -1;
@@ -9869,6 +9870,7 @@ vectorizable_load (vec_info *vinfo,
       internal_fn ifn = gimple_call_internal_fn (call);
       if (!internal_load_fn_p (ifn))
        return false;
+      load_extend_p = ifn == IFN_VEC_LOAD_EXTEND;
 
       scalar_dest = gimple_call_lhs (call);
       if (!scalar_dest)
@@ -9969,6 +9971,14 @@ vectorizable_load (vec_info *vinfo,
   const poly_int64 poffset = ls.poffset;
   const vec<int> &elsvals = ls.elsvals;
 
+  if (load_extend_p)
+    {
+      if (memory_access_type != VMAT_CONTIGUOUS)
+       return false;
+      if (cost_vec)
+       vinfo->any_known_not_updated_vssa = true;
+    }
+
   int maskload_elsval = 0;
   bool need_zeroing = false;
 
@@ -10037,7 +10047,11 @@ vectorizable_load (vec_info *vinfo,
 
   if (costing_p) /* transformation not required.  */
     {
-      if (loop_vinfo
+      /* IFN_VEC_LOAD_EXTEND has no masked or length-controlled form;
+        vect_recog_load_extend_pattern is not applied to loops that may
+        use partial vectors.  */
+      if (!load_extend_p
+         && loop_vinfo
          && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
        check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
                                              VLS_LOAD, group_size, &ls,
@@ -10826,6 +10840,49 @@ vectorizable_load (vec_info *vinfo,
 
   tree vec_mask = NULL_TREE;
   tree vec_els = NULL_TREE;
+  if (load_extend_p && !costing_p)
+    {
+      gcc_assert (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo));
+
+      tree memory_type
+       = TREE_TYPE (gimple_call_arg (as_a <gcall *> (stmt_info->stmt), 2));
+      tree load_extend_memory_vectype
+       = get_related_vectype_for_scalar_type (TYPE_MODE (vectype),
+                                              memory_type, nunits);
+      dr_increment = vect_get_data_ptr_step (vinfo, dr_info,
+                                            memory_access_type);
+      dr_bump = vect_get_data_ptr_bump (vinfo, dr_info,
+                                       load_extend_memory_vectype,
+                                       memory_access_type);
+      dataref_ptr
+       = vect_create_data_ref_ptr (vinfo, stmt_info,
+                                   load_extend_memory_vectype, at_loop,
+                                   offset, &dummy, gsi, NULL, false,
+                                   dr_increment);
+
+      unsigned int align
+       = vect_known_alignment_in_bytes (dr_info, load_extend_memory_vectype);
+      tree alignment = build_int_cst (ref_type, align * BITS_PER_UNIT);
+      tree type_operand = build_zero_cst (load_extend_memory_vectype);
+
+      for (i = 0; i < vec_num; ++i)
+       {
+         if (i > 0)
+           dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, gsi,
+                                          stmt_info, dr_bump);
+
+         gcall *call
+           = gimple_build_call_internal (IFN_VEC_LOAD_EXTEND, 3,
+                                         dataref_ptr, alignment, type_operand);
+         tree lhs = make_ssa_name (vectype);
+         gimple_call_set_lhs (call, lhs);
+         gimple_call_set_nothrow (call, true);
+         vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
+         slp_node->push_vec_def (call);
+       }
+      return true;
+    }
+
   if (memory_access_type == VMAT_LOAD_STORE_LANES)
     {
       const internal_fn lanes_ifn = ls.lanes_ifn;
-- 
2.34.1

Reply via email to