diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index ce93a52fa578127f1eade05dbafdf52021fd61fe..945c314d31c715522e56141ef9b616e52b466261 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -87,6 +87,7 @@ enum pragma_kind {
   PRAGMA_GCC_PCH_PREPROCESS,
   PRAGMA_IVDEP,
   PRAGMA_UNROLL,
+  PRAGMA_INTERLEAVES,
   PRAGMA_NOVECTOR,
 
   PRAGMA_FIRST_EXTERNAL
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 1237ee6e62b9d501a7f9ad1cc267061ed068b920..facfb75c1eb9f184f05f4476a3aa04b45c21fd9a 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1828,6 +1828,10 @@ init_pragma (void)
     cpp_register_deferred_pragma (parse_in, "GCC", "unroll", PRAGMA_UNROLL,
 				  false, false);
 
+  if (!flag_preprocess_only)
+    cpp_register_deferred_pragma (parse_in, "GCC", "interleaves", PRAGMA_INTERLEAVES,
+				  false, false);
+
   if (!flag_preprocess_only)
     cpp_register_deferred_pragma (parse_in, "GCC", "novector", PRAGMA_NOVECTOR,
 				  false, false);
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 00f8bf4376e537e04ea8e468a05dade3c7212d8b..69b36d196bd74b494ffb6186be5240e3d2431407 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1665,11 +1665,12 @@ static tree c_parser_c99_block_statement (c_parser *, bool *,
 					  location_t * = NULL);
 static void c_parser_if_statement (c_parser *, bool *, vec<tree> *);
 static void c_parser_switch_statement (c_parser *, bool *);
-static void c_parser_while_statement (c_parser *, bool, unsigned short, bool,
-				      bool *);
-static void c_parser_do_statement (c_parser *, bool, unsigned short, bool);
-static void c_parser_for_statement (c_parser *, bool, unsigned short, bool,
-				    bool *);
+static void c_parser_while_statement (c_parser *, bool, unsigned short,
+				      unsigned short, bool, bool *);
+static void c_parser_do_statement (c_parser *, bool, unsigned short,
+				   unsigned short,bool);
+static void c_parser_for_statement (c_parser *, bool, unsigned short,
+				    unsigned short, bool, bool *);
 static tree c_parser_asm_statement (c_parser *);
 static tree c_parser_asm_operands (c_parser *);
 static tree c_parser_asm_goto_operands (c_parser *);
@@ -7603,13 +7604,13 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
 	  c_parser_switch_statement (parser, if_p);
 	  break;
 	case RID_WHILE:
-	  c_parser_while_statement (parser, false, 0, false, if_p);
+	  c_parser_while_statement (parser, false, 0, 0, false, if_p);
 	  break;
 	case RID_DO:
-	  c_parser_do_statement (parser, false, 0, false);
+	  c_parser_do_statement (parser, false, 0, 0, false);
 	  break;
 	case RID_FOR:
-	  c_parser_for_statement (parser, false, 0, false, if_p);
+	  c_parser_for_statement (parser, false, 0, 0, false, if_p);
 	  break;
 	case RID_GOTO:
 	  c_parser_consume_token (parser);
@@ -8105,7 +8106,7 @@ c_parser_switch_statement (c_parser *parser, bool *if_p)
 
 static void
 c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
-			  bool novector, bool *if_p)
+			  unsigned short interleaves, bool novector, bool *if_p)
 {
   tree block, cond, body;
   unsigned char save_in_statement;
@@ -8135,6 +8136,11 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 		   build_int_cst (integer_type_node,
 				  annot_expr_unroll_kind),
 		   build_int_cst (integer_type_node, unroll));
+  if (interleaves && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+		   build_int_cst (integer_type_node,
+				  annot_expr_interleaves_kind),
+		   build_int_cst (integer_type_node, interleaves));
   if (novector && cond != error_mark_node)
     cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
 		   build_int_cst (integer_type_node,
@@ -8172,7 +8178,7 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 
 static void
 c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
-		       bool novector)
+		       unsigned short interleaves, bool novector)
 {
   tree block, cond, body;
   unsigned char save_in_statement;
@@ -8209,6 +8215,11 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 		   build_int_cst (integer_type_node,
 				  annot_expr_unroll_kind),
  		   build_int_cst (integer_type_node, unroll));
+  if (interleaves && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+		   build_int_cst (integer_type_node,
+				  annot_expr_interleaves_kind),
+ 		   build_int_cst (integer_type_node, interleaves));
   if (novector && cond != error_mark_node)
     cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
 		   build_int_cst (integer_type_node,
@@ -8282,7 +8293,7 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 
 static void
 c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
-			bool novector, bool *if_p)
+			unsigned short interleaves, bool novector, bool *if_p)
 {
   tree block, cond, incr, body;
   unsigned char save_in_statement;
@@ -8424,6 +8435,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 					  "with %<GCC unroll%> pragma");
 		  cond = error_mark_node;
 		}
+	      else if (interleaves)
+		{
+		  c_parser_error (parser, "missing loop condition in loop "
+					  "with %<GCC interleaves%> pragma");
+		  cond = error_mark_node;
+		}
 	      else
 		{
 		  c_parser_consume_token (parser);
@@ -8446,6 +8463,11 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
  			   build_int_cst (integer_type_node,
 					  annot_expr_unroll_kind),
 			   build_int_cst (integer_type_node, unroll));
+	  if (interleaves && cond != error_mark_node)
+	    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ 			   build_int_cst (integer_type_node,
+					  annot_expr_interleaves_kind),
+			   build_int_cst (integer_type_node, interleaves));
 	  if (novector && cond && cond != error_mark_node)
 	    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
 			   build_int_cst (integer_type_node,
@@ -14466,6 +14488,37 @@ c_parser_pragma_unroll (c_parser *parser)
   return unroll;
 }
 
+static unsigned short
+c_parser_pragma_interleaves (c_parser *parser)
+{
+  unsigned short interleaves;
+  c_parser_consume_pragma (parser);
+  location_t location = c_parser_peek_token (parser)->location;
+  tree expr = c_parser_expr_no_commas (parser, NULL).value;
+  mark_exp_read (expr);
+  expr = c_fully_fold (expr, false, NULL);
+  HOST_WIDE_INT linterleaves = 0;
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+      || TREE_CODE (expr) != INTEGER_CST
+      || (linterleaves = tree_to_shwi (expr)) < 0
+      || linterleaves >= USHRT_MAX)
+    {
+      error_at (location, "%<#pragma GCC interleaves%> requires an"
+		" assignment-expression that evaluates to a non-negative"
+		" integral constant less than %u", USHRT_MAX);
+      interleaves = 0;
+    }
+  else
+    {
+      interleaves = (unsigned short)linterleaves;
+      if (interleaves == 0)
+	interleaves = 1;
+    }
+
+  c_parser_skip_to_pragma_eol (parser);
+  return interleaves;
+}
+
 /* Handle pragmas.  Some OpenMP pragmas are associated with, and therefore
    should be considered, statements.  ALLOW_STMT is true if we're within
    the context of a function and such pragmas are to be allowed.  Returns
@@ -14674,10 +14727,12 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
 
     case PRAGMA_NOVECTOR:
     case PRAGMA_UNROLL:
+    case PRAGMA_INTERLEAVES:
     case PRAGMA_IVDEP:
       {
 	bool novector = false;
 	unsigned short unroll = 0;
+	unsigned short interleaves = 0;
 	bool ivdep = false;
 
 	switch (id)
@@ -14688,6 +14743,9 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
 	  case PRAGMA_UNROLL:
 	    unroll = c_parser_pragma_unroll (parser);
 	    break;
+	  case PRAGMA_INTERLEAVES:
+	    interleaves = c_parser_pragma_interleaves (parser);
+	    break;
 	  case PRAGMA_IVDEP:
 	    ivdep = c_parse_pragma_ivdep (parser);
 	    break;
@@ -14707,6 +14765,9 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
 	      case PRAGMA_UNROLL:
 		unroll = c_parser_pragma_unroll (parser);
 		break;
+	      case PRAGMA_INTERLEAVES:
+		interleaves = c_parser_pragma_interleaves (parser);
+		break;
 	      case PRAGMA_NOVECTOR:
 		novector = c_parse_pragma_novector (parser);
 		break;
@@ -14725,11 +14786,13 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
 	    return false;
 	  }
 	if (c_parser_next_token_is_keyword (parser, RID_FOR))
-	  c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
+	  c_parser_for_statement (parser, ivdep, unroll, interleaves, novector,
+				  if_p);
 	else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
-	  c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
+	  c_parser_while_statement (parser, ivdep, unroll, interleaves,
+				    novector, if_p);
 	else
-	  c_parser_do_statement (parser, ivdep, unroll, novector);
+	  c_parser_do_statement (parser, ivdep, unroll, interleaves, novector);
       }
       return true;
 
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 30b5e40d0d999ef285d44fe4e2303969229e3498..50cb39f684979eadd1a62cffc766d2771c4f68e9 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -239,6 +239,8 @@ public:
      Other values means unroll with the given unrolling factor.  */
   unsigned short unroll;
 
+  unsigned short interleaves;
+
   /* If this loop was inlined the main clique of the callee which does
      not need remapping when copying the loop body.  */
   unsigned short owned_clique;
diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc
index 3707db2fdb39cea26ee3ec5372eccc5d28be660c..d9450dfe53c509382d378f2cb4f54f4f89274a14 100644
--- a/gcc/cfgloopmanip.cc
+++ b/gcc/cfgloopmanip.cc
@@ -1095,6 +1095,7 @@ copy_loop_info (class loop *loop, class loop *target)
   target->in_oacc_kernels_region = loop->in_oacc_kernels_region;
   target->finite_p = loop->finite_p;
   target->unroll = loop->unroll;
+  target->interleaves = loop->interleaves;
   target->owned_clique = loop->owned_clique;
 }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6206482c602dddfdb92187f90324d24d6700078b..1ef605655a164f98867a57532e12b967e62e57c6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7779,16 +7779,16 @@ extern void begin_else_clause			(tree);
 extern void finish_else_clause			(tree);
 extern void finish_if_stmt			(tree);
 extern tree begin_while_stmt			(void);
-extern void finish_while_stmt_cond	(tree, tree, bool, tree, bool);
+extern void finish_while_stmt_cond	(tree, tree, bool, tree, tree, bool);
 extern void finish_while_stmt			(tree);
 extern tree begin_do_stmt			(void);
 extern void finish_do_body			(tree);
-extern void finish_do_stmt		(tree, tree, bool, tree, bool);
+extern void finish_do_stmt		(tree, tree, bool, tree, tree, bool);
 extern tree finish_return_stmt			(tree);
 extern tree begin_for_scope			(tree *);
 extern tree begin_for_stmt			(tree, tree);
 extern void finish_init_stmt			(tree);
-extern void finish_for_cond		(tree, tree, bool, tree, bool);
+extern void finish_for_cond		(tree, tree, bool, tree, tree, bool);
 extern void finish_for_expr			(tree, tree);
 extern void finish_for_stmt			(tree);
 extern tree begin_range_for_stmt		(tree, tree);
@@ -7990,6 +7990,7 @@ extern tree finish_omp_target			(location_t, tree, tree, bool);
 extern void finish_omp_target_clauses		(location_t, tree, tree *);
 extern void maybe_warn_unparenthesized_assignment (tree, bool, tsubst_flags_t);
 extern tree cp_check_pragma_unroll		(location_t, tree);
+extern tree cp_check_pragma_interleaves		(location_t, tree);
 
 /* in tree.cc */
 extern int cp_tree_operand_length		(const_tree);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 4a7ed7f53027516174bfc948360591fa3703ee18..6960b40e14d189ce4593d29d3020994250526f3e 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4886,7 +4886,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       finish_init_stmt (for_stmt);
       finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
-		       for_stmt, false, 0, false);
+		       for_stmt, false, 0, 0, false);
       /* We used to pass this decrement to finish_for_expr; now we add it to
 	 elt_init below so it's part of the same full-expression as the
 	 initialization, and thus happens before any potentially throwing
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 0b21656ed612ebca5fd32f140783645c7da69824..ecf609585896df3cb5de2ec07b6526d6f1fa8fb5 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1656,7 +1656,7 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain)
 		      add_stmt (idx);
 		      finish_init_stmt (for_stmt);
 		      finish_for_cond (build2 (LE_EXPR, boolean_type_node, idx,
-					       maxval), for_stmt, false, 0,
+					       maxval), for_stmt, false, 0, 0,
 					       false);
 		      finish_for_expr (cp_build_unary_op (PREINCREMENT_EXPR,
 							  TARGET_EXPR_SLOT (idx),
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 779625144db405561e62da8c7553c16234324c79..67828431e74cac887fd8fe439d2b44233ba6d21e 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2451,13 +2451,13 @@ static tree cp_parser_selection_statement
 static tree cp_parser_condition
   (cp_parser *);
 static tree cp_parser_iteration_statement
-  (cp_parser *, bool *, bool, tree, bool);
+  (cp_parser *, bool *, bool, tree, tree, bool);
 static bool cp_parser_init_statement
   (cp_parser *, tree *decl);
 static tree cp_parser_for
-  (cp_parser *, bool, tree, bool);
+  (cp_parser *, bool, tree, tree, tree, bool);
 static tree cp_parser_c_for
-  (cp_parser *, tree, tree, bool, tree, bool);
+  (cp_parser *, tree, tree, bool, tree, tree, bool);
 static tree cp_parser_range_for
   (cp_parser *, tree, tree, tree, bool, tree, bool, bool);
 static void do_range_for_auto_deduction
@@ -12744,7 +12744,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 	case RID_FOR:
 	  std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
 	  statement = cp_parser_iteration_statement (parser, if_p, false,
-						     NULL_TREE, false);
+						     NULL_TREE, NULL_TREE,
+						     false);
 	  break;
 
 	case RID_BREAK:
@@ -14034,7 +14035,8 @@ cp_parser_condition (cp_parser* parser)
    not included. */
 
 static tree
-cp_parser_for (cp_parser *parser, bool ivdep, tree unroll, bool novector)
+cp_parser_for (cp_parser *parser, bool ivdep, tree interleaves, tree unroll,
+	       bool novector)
 {
   tree init, scope, decl;
   bool is_range_for;
@@ -14062,16 +14064,19 @@ cp_parser_for (cp_parser *parser, bool ivdep, tree unroll, bool novector)
   /* Parse the initialization.  */
   is_range_for = cp_parser_init_statement (parser, &decl);
 
+  /* TODO: should probably warn when interleaves is being used for a range_for?
+     or should we support that too?  */
   if (is_range_for)
     return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll,
 				novector, false);
   else
-    return cp_parser_c_for (parser, scope, init, ivdep, unroll, novector);
+    return cp_parser_c_for (parser, scope, init, ivdep, interleaves, unroll,
+			    novector);
 }
 
 static tree
 cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
-		 tree unroll, bool novector)
+		 tree interleaves, tree unroll, bool novector)
 {
   /* Normal for loop */
   tree condition = NULL_TREE;
@@ -14098,7 +14103,13 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
 		       "%<GCC unroll%> pragma");
       condition = error_mark_node;
     }
-  finish_for_cond (condition, stmt, ivdep, unroll, novector);
+  else if (interleaves)
+    {
+      cp_parser_error (parser, "missing loop condition in loop with "
+		       "%<GCC interleaves%> pragma");
+      condition = error_mark_node;
+    }
+  finish_for_cond (condition, stmt, ivdep, interleaves, unroll, novector);
   /* Look for the `;'.  */
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
@@ -14444,7 +14455,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
 				 begin, ERROR_MARK,
 				 end, ERROR_MARK,
 				 NULL_TREE, NULL, tf_warning_or_error);
-  finish_for_cond (condition, statement, ivdep, unroll, novector);
+  finish_for_cond (condition, statement, ivdep, NULL_TREE, unroll, novector);
 
   /* The new increment expression.  */
   expression = finish_unary_op_expr (input_location,
@@ -14608,7 +14619,7 @@ cp_parser_range_for_member_function (tree range, tree identifier)
 
 static tree
 cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
-			       tree unroll, bool novector)
+			       tree interleaves, tree unroll, bool novector)
 {
   cp_token *token;
   enum rid keyword;
@@ -14651,7 +14662,8 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
 	parens.require_open (parser);
 	/* Parse the condition.  */
 	condition = cp_parser_condition (parser);
-	finish_while_stmt_cond (condition, statement, ivdep, unroll, novector);
+	finish_while_stmt_cond (condition, statement, ivdep, interleaves,
+				unroll, novector);
 	/* Look for the `)'.  */
 	parens.require_close (parser);
 	/* Parse the dependent statement.  */
@@ -14686,7 +14698,8 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
 	/* Parse the expression.  */
 	expression = cp_parser_expression (parser);
 	/* We're done with the do-statement.  */
-	finish_do_stmt (expression, statement, ivdep, unroll, novector);
+	finish_do_stmt (expression, statement, ivdep, interleaves, unroll,
+			novector);
 	/* Look for the `)'.  */
 	parens.require_close (parser);
 	/* Look for the `;'.  */
@@ -14700,7 +14713,8 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
 	matching_parens parens;
 	parens.require_open (parser);
 
-	statement = cp_parser_for (parser, ivdep, unroll, novector);
+	statement = cp_parser_for (parser, ivdep, interleaves, unroll,
+				   novector);
 
 	/* Look for the `)'.  */
 	parens.require_close (parser);
@@ -51015,6 +51029,20 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok)
   return unroll;
 }
 
+/* Parse a pragma GCC interleaves.  */
+
+static tree
+cp_parser_pragma_interleaves (cp_parser *parser, cp_token *pragma_tok)
+{
+  location_t location = cp_lexer_peek_token (parser->lexer)->location;
+  tree interleaves = cp_parser_constant_expression (parser);
+  interleaves
+    = cp_check_pragma_interleaves (location,
+				   fold_non_dependent_expr (interleaves));
+  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+  return interleaves;
+}
+
 /* Parse a pragma GCC novector.  */
 
 static bool
@@ -51341,10 +51369,12 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
 
     case PRAGMA_IVDEP:
     case PRAGMA_UNROLL:
+    case PRAGMA_INTERLEAVES:
     case PRAGMA_NOVECTOR:
       {
 	bool ivdep = false;
 	tree unroll = NULL_TREE;
+	tree interleaves = NULL_TREE;
 	bool novector = false;
 	const char *pragma_str;
 
@@ -51356,6 +51386,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
 	  case PRAGMA_UNROLL:
 	    pragma_str = "unroll";
 	    break;
+	  case PRAGMA_INTERLEAVES:
+	    pragma_str = "interleaves";
+	    break;
 	  case PRAGMA_NOVECTOR:
 	    pragma_str = "novector";
 	    break;
@@ -51391,6 +51424,13 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
 		    unroll = cp_parser_pragma_unroll (parser, tok);
 		    break;
 		  }
+		case PRAGMA_INTERLEAVES:
+		  {
+		    if (tok != pragma_tok)
+		      tok = cp_lexer_consume_token (parser->lexer);
+		    interleaves = cp_parser_pragma_interleaves (parser, tok);
+		    break;
+		  }
 		case PRAGMA_NOVECTOR:
 		  {
 		    if (tok != pragma_tok)
@@ -51415,7 +51455,8 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
 	    cp_parser_error (parser, "for, while or do statement expected");
 	    return false;
 	  }
-	cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector);
+	cp_parser_iteration_statement (parser, if_p, ivdep, interleaves, unroll,
+				       novector);
 	return true;
       }
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dfce1b3c35910d8afe19ccde89b9cb11183b2cbc..66649d284a395f4a28db6cbab43071b66b2a9c62 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18638,7 +18638,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       RECUR (FOR_INIT_STMT (t));
       finish_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
-      finish_for_cond (tmp, stmt, false, 0, false);
+      finish_for_cond (tmp, stmt, false, 0, 0, false);
       tmp = RECUR (FOR_EXPR (t));
       finish_for_expr (tmp, stmt);
       {
@@ -18701,7 +18701,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case WHILE_STMT:
       stmt = begin_while_stmt ();
       tmp = RECUR (WHILE_COND (t));
-      finish_while_stmt_cond (tmp, stmt, false, 0, false);
+      finish_while_stmt_cond (tmp, stmt, false, 0, 0, false);
       {
 	bool prev = note_iteration_stmt_body_start ();
 	RECUR (WHILE_BODY (t));
@@ -18719,7 +18719,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       }
       finish_do_body (stmt);
       tmp = RECUR (DO_COND (t));
-      finish_do_stmt (tmp, stmt, false, 0, false);
+      finish_do_stmt (tmp, stmt, false, 0, 0, false);
       break;
 
     case IF_STMT:
@@ -19470,10 +19470,18 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	tree op1 = RECUR (TREE_OPERAND (t, 0));
 	tree op2 = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl);
 	tree op3 = tsubst_expr (TREE_OPERAND (t, 2), args, complain, in_decl);
-	if (TREE_CODE (op2) == INTEGER_CST
-	    && wi::to_widest (op2) == (int) annot_expr_unroll_kind)
-	  op3 = cp_check_pragma_unroll (EXPR_LOCATION (TREE_OPERAND (t, 2)),
-					op3);
+
+	if (TREE_CODE (op2) == INTEGER_CST)
+	  {
+	    if (wi::to_widest (op2) == (int) annot_expr_unroll_kind)
+	      op3 = cp_check_pragma_unroll (EXPR_LOCATION (TREE_OPERAND (t, 2)),
+					    op3);
+	    else if (wi::to_widest (op2) == (int) annot_expr_interleaves_kind)
+	      {
+		location_t loc = EXPR_LOCATION (TREE_OPERAND (t, 2));
+		op3 = cp_check_pragma_interleaves (loc, op3);
+	      }
+	  }
 	RETURN (build3_loc (EXPR_LOCATION (t), ANNOTATE_EXPR,
 			    TREE_TYPE (op1), op1, op2, op3));
       }
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f90c304a65b7709e2ab1447b94b8dd3a551a279a..ec853cd0e75f58357ba163a01d8353797793d387 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -1284,7 +1284,7 @@ begin_while_stmt (void)
 
 void
 finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
-			tree unroll, bool novector)
+			tree interleaves, tree unroll, bool novector)
 {
   cond = maybe_convert_cond (cond);
   finish_cond (&WHILE_COND (while_stmt), cond);
@@ -1303,6 +1303,13 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
 				      build_int_cst (integer_type_node,
 						     annot_expr_unroll_kind),
 				      unroll);
+  if (interleaves && cond != error_mark_node)
+    WHILE_COND (while_stmt)
+      = build3 (ANNOTATE_EXPR,
+		TREE_TYPE (WHILE_COND (while_stmt)),
+		WHILE_COND (while_stmt),
+		build_int_cst (integer_type_node, annot_expr_interleaves_kind),
+		interleaves);
   if (novector && cond != error_mark_node)
     WHILE_COND (while_stmt) = build3 (ANNOTATE_EXPR,
 				      TREE_TYPE (WHILE_COND (while_stmt)),
@@ -1356,7 +1363,7 @@ finish_do_body (tree do_stmt)
 
 void
 finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll,
-		bool novector)
+		tree interleaves, bool novector)
 {
   cond = maybe_convert_cond (cond);
   end_maybe_infinite_loop (cond);
@@ -1373,6 +1380,10 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll,
     cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
 		   build_int_cst (integer_type_node, annot_expr_unroll_kind),
 		   unroll);
+  if (interleaves && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+		   build_int_cst (integer_type_node, annot_expr_interleaves_kind),
+		   interleaves);
   if (novector && cond != error_mark_node)
     cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
 		   build_int_cst (integer_type_node, annot_expr_no_vector_kind),
@@ -1481,8 +1492,8 @@ finish_init_stmt (tree for_stmt)
    FOR_STMT.  */
 
 void
-finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree unroll,
-		 bool novector)
+finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree interleaves,
+		 tree unroll, bool novector)
 {
   cond = maybe_convert_cond (cond);
   finish_cond (&FOR_COND (for_stmt), cond);
@@ -1494,6 +1505,13 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree unroll,
 				  build_int_cst (integer_type_node,
 						 annot_expr_ivdep_kind),
 				  integer_zero_node);
+  if (interleaves && cond != error_mark_node)
+    FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR,
+				  TREE_TYPE (FOR_COND (for_stmt)),
+				  FOR_COND (for_stmt),
+				  build_int_cst (integer_type_node,
+						 annot_expr_interleaves_kind),
+				  interleaves);
   if (unroll && cond != error_mark_node)
     FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR,
 				  TREE_TYPE (FOR_COND (for_stmt)),
@@ -13342,6 +13360,36 @@ cp_build_bit_cast (location_t loc, tree type, tree arg,
   return ret;
 }
 
+/* Diagnose invalid #pragma GCC interleaves argument and adjust
+   it if needed.   */
+
+tree
+cp_check_pragma_interleaves (location_t loc, tree value)
+{
+  HOST_WIDE_INT lvalue = 0;
+  if (type_dependent_expression_p (value))
+    ;
+  else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
+	   || (!value_dependent_expression_p (value)
+	       && (!tree_fits_shwi_p (value)
+		   || (lvalue = tree_to_shwi (value)) < 0
+		   || lvalue >= USHRT_MAX
+		   || (lvalue % 2 != 0))))
+    {
+      error_at (loc, "%<#pragma GCC interleaves%> requires an"
+		" assignment-expression that evaluates to a non-negative"
+		" power of two integral constant less than %u", USHRT_MAX);
+      value = NULL_TREE;
+    }
+  else if (TREE_CODE (value) == INTEGER_CST)
+    {
+      value = fold_convert (integer_type_node, value);
+      if (integer_zerop (value))
+	value = integer_one_node;
+    }
+  return value;
+}
+
 /* Diagnose invalid #pragma GCC unroll argument and adjust
    it if needed.  */
 
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index b0ed58ed0f917bf694b34d90c7f53f7196a8e791..be24e5399aa6aa0fd8df2473abebb0a2994bd2f6 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -4582,6 +4582,7 @@ gimple_boolify (tree expr)
 	{
 	case annot_expr_ivdep_kind:
 	case annot_expr_unroll_kind:
+	case annot_expr_interleaves_kind:
 	case annot_expr_no_vector_kind:
 	case annot_expr_vector_kind:
 	case annot_expr_parallel_kind:
diff --git a/gcc/ipa-icf-gimple.cc b/gcc/ipa-icf-gimple.cc
index c25eb24710f6a785d2c739e5d5ad7c066c3e0f3d..f9c8456a7ea2d82114944824c1b2ce3d81dbb19f 100644
--- a/gcc/ipa-icf-gimple.cc
+++ b/gcc/ipa-icf-gimple.cc
@@ -541,6 +541,8 @@ func_checker::compare_loops (basic_block bb1, basic_block bb2)
     return return_false_with_msg ("finite_p");
   if (l1->unroll != l2->unroll)
     return return_false_with_msg ("unroll");
+  if (l1->interleaves != l2->interleaves)
+    return return_false_with_msg ("interleaves");
   if (!compare_variable_decl (l1->simduid, l2->simduid))
     return return_false_with_msg ("simduid");
 
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 7fb7b92966be0e54824079b193d53a92c3fb28c6..b474a0971cddf7f486a524b52af2f70bd7e56580 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -286,6 +286,10 @@ replace_loop_annotate_in_block (basic_block bb, class loop *loop)
 	    = (unsigned short) tree_to_shwi (gimple_call_arg (stmt, 2));
 	  cfun->has_unroll = true;
 	  break;
+	case annot_expr_interleaves_kind:
+	  loop->interleaves
+	    = (unsigned short) tree_to_shwi (gimple_call_arg (stmt, 2));
+	  break;
 	case annot_expr_no_vector_kind:
 	  loop->dont_vectorize = true;
 	  break;
@@ -347,6 +351,7 @@ replace_loop_annotate (void)
 	    {
 	    case annot_expr_ivdep_kind:
 	    case annot_expr_unroll_kind:
+	    case annot_expr_interleaves_kind:
 	    case annot_expr_no_vector_kind:
 	    case annot_expr_vector_kind:
 	    case annot_expr_parallel_kind:
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 9fa7434291914ce02927938441463b220ec832a7..9c7978699e33739e2e009f794927834450884108 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -980,6 +980,7 @@ enum tree_node_kind {
 enum annot_expr_kind {
   annot_expr_ivdep_kind,
   annot_expr_unroll_kind,
+  annot_expr_interleaves_kind,
   annot_expr_no_vector_kind,
   annot_expr_vector_kind,
   annot_expr_parallel_kind,
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index f9ad8562078157572a999abd93ce259c3a8d4b64..2a3feb777acd44865031c25310851d9ba6061850 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -3454,8 +3454,12 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
 	  pp_string (pp, ", ivdep");
 	  break;
 	case annot_expr_unroll_kind:
+	case annot_expr_interleaves_kind:
 	  {
-	    pp_string (pp, ", unroll ");
+	    pp_string (pp,
+		       annot_expr_unroll_kind
+		       ? ", unroll "
+		       : ", interleaves ");
 	    pp_decimal_int (pp,
 			    (int) TREE_INT_CST_LOW (TREE_OPERAND (node, 2)));
 	    break;
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index 04a9ac64df7401d3f4646e518bc41b73b3f2d036..59c6ee81f1ea225b243e9096890f751a69fe7141 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -5008,6 +5008,9 @@ vect_estimate_min_profitable_iters (loop_vec_info loop_vinfo,
 	       &vec_prologue_cost, &vec_inside_cost, &vec_epilogue_cost,
 	       suggested_unroll_factor);
 
+  if (suggested_unroll_factor && loop_vinfo->loop->interleaves > 0)
+    *suggested_unroll_factor = loop_vinfo->loop->interleaves;
+
   if (suggested_unroll_factor && *suggested_unroll_factor > 1
       && LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) != MAX_VECTORIZATION_FACTOR
       && !known_le (LOOP_VINFO_VECT_FACTOR (loop_vinfo) *
