* [C/C++] Add support for #pragma GCC unroll v3
@ 2017-11-25 15:31 Eric Botcazou
2017-11-30 19:18 ` Joseph Myers
2017-12-27 7:32 ` [testsuite, committed] Use relative line number in unroll-5.c Tom de Vries
0 siblings, 2 replies; 3+ messages in thread
From: Eric Botcazou @ 2017-11-25 15:31 UTC (permalink / raw)
To: gcc-patches; +Cc: Joseph Myers, Jason Merrill
[-- Attachment #1: Type: text/plain, Size: 3198 bytes --]
Hi,
this is the (hopefully) final implementation of the support for the unrolling
pragma in the C and C++ front-ends. It contains a couple of fixes for the C++
front-ends to make it correctly handle unroll and ivdep for the same loop.
Tested on x86_64-suse-linux, OK for the mainline?
2017-11-25 Mike Stump <mikestump@comcast.net>
Eric Botcazou <ebotcazou@adacore.com>
ChangeLog/
* doc/extend.texi (Loop-Specific Pragmas): Document pragma GCC unroll.
c-family/ChangeLog:
* c-pragma.c (init_pragma): Register pragma GCC unroll.
* c-pragma.h (enum pragma_kind): Add PRAGMA_UNROLL.
c/ChangeLog:
* c-parser.c (c_parser_while_statement): Add unroll parameter and
build ANNOTATE_EXPR if present. Add 3rd operand to ANNOTATE_EXPR.
(c_parser_do_statement): Likewise.
(c_parser_for_statement): Likewise.
(c_parser_statement_after_labels): Adjust calls to above.
(c_parse_pragma_ivdep): New static function.
(c_parser_pragma_unroll): Likewise.
(c_parser_pragma) <PRAGMA_IVDEP>: Add support for pragma Unroll.
<PRAGMA_UNROLL>: New case.
cp/ChangeLog:
* constexpr.c (cxx_eval_constant_expression) <ANNOTATE_EXPR>: Remove
assertion on 2nd operand.
(potential_constant_expression_1): Likewise.
* cp-array-notation.c (create_an_loop): Adjut call to finish_for_cond.
* cp-tree.h (cp_convert_range_for): Adjust prototype.
(finish_while_stmt_cond): Likewise.
(finish_do_stmt): Likewise.
(finish_for_cond): Likewise.
* init.c (build_vec_init): Adjut call to finish_for_cond.
* parser.c (cp_parser_statement): Adjust call to
cp_parser_iteration_statement.
(cp_parser_for): Add unroll parameter and pass it in calls to
cp_parser_range_for and cp_parser_c_for.
(cp_parser_c_for): Add unroll parameter and pass it in call to
finish_for_cond.
(cp_parser_range_for): Add unroll parameter and pass it in call to
cp_convert_range_for.
(cp_convert_range_for): Add unroll parameter and pass it in call to
finish_for_cond.
(cp_parser_iteration_statement): Add unroll parameter and pass it in
calls to finish_while_stmt_cond, finish_do_stmt and cp_parser_for.
(cp_parser_pragma_ivdep): New static function.
(cp_parser_pragma_unroll): Likewise.
(cp_parser_pragma) <PRAGMA_IVDEP>: Add support for pragma Unroll.
<PRAGMA_UNROLL>: New case.
* pt.c (tsubst_expr): Adjut calls to finish_for_cond,
cp_convert_range_for, finish_while_stmt_cond and finish_do_stmt.
<ANNOTATE_EXPR>: Propagate 3rd operand.
* semantics.c (finish_while_stmt_cond): Add unroll parameter and
build ANNOTATE_EXPR if present. Add 3rd operand to ANNOTATE_EXPR.
(finish_do_stmt): Likewise.
(finish_for_cond): Likewise.
testsuite/ChangeLog:
* c-c++-common/unroll-1.c: New test.
* c-c++-common/unroll-2.c: Likewise.
* c-c++-common/unroll-3.c: Likewise.
* c-c++-common/unroll-4.c: Likewise.
* c-c++-common/unroll-5.c: Likewise.
--
Eric Botcazou
[-- Attachment #2: p.diff --]
[-- Type: text/x-patch, Size: 35141 bytes --]
Index: doc/extend.texi
===================================================================
--- doc/extend.texi (revision 255147)
+++ doc/extend.texi (working copy)
@@ -22343,9 +22343,7 @@ function. The parenthesis around the op
The @code{#pragma GCC target} pragma is presently implemented for
x86, ARM, AArch64, PowerPC, S/390, and Nios II targets only.
-@end table
-@table @code
@item #pragma GCC optimize (@var{"string"}...)
@cindex pragma GCC optimize
@@ -22356,9 +22354,7 @@ if @code{attribute((optimize("STRING")))
function. The parenthesis around the options is optional.
@xref{Function Attributes}, for more information about the
@code{optimize} attribute and the attribute syntax.
-@end table
-@table @code
@item #pragma GCC push_options
@itemx #pragma GCC pop_options
@cindex pragma GCC push_options
@@ -22369,15 +22365,14 @@ options. It is intended for include fil
to switch to using a different @samp{#pragma GCC target} or
@samp{#pragma GCC optimize} and then to pop back to the previous
options.
-@end table
-@table @code
@item #pragma GCC reset_options
@cindex pragma GCC reset_options
This pragma clears the current @code{#pragma GCC target} and
@code{#pragma GCC optimize} to use the default switches as specified
on the command line.
+
@end table
@node Loop-Specific Pragmas
@@ -22386,7 +22381,6 @@ on the command line.
@table @code
@item #pragma GCC ivdep
@cindex pragma GCC ivdep
-@end table
With this pragma, the programmer asserts that there are no loop-carried
dependencies which would prevent consecutive iterations of
@@ -22421,6 +22415,16 @@ void ignore_vec_dep (int *a, int k, int
@}
@end smallexample
+@item #pragma GCC unroll @var{n}
+@cindex pragma GCC unroll @var{n}
+
+You can use this pragma to control how many times a loop should be unrolled.
+It must be placed immediately before a @code{for}, @code{while} or @code{do}
+loop or a @code{#pragma GCC ivdep}, and applies only to the loop that follows.
+@var{n} is an integer constant expression specifying the unrolling factor.
+The values of @math{0} and @math{1} block any unrolling of the loop.
+
+@end table
@node Unnamed Fields
@section Unnamed Structure and Union Fields
Index: c/c-parser.c
===================================================================
--- c/c-parser.c (revision 255147)
+++ c/c-parser.c (working copy)
@@ -1410,9 +1410,9 @@ static tree c_parser_c99_block_statement
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, bool *);
-static void c_parser_do_statement (c_parser *, bool);
-static void c_parser_for_statement (c_parser *, bool, bool *);
+static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *);
+static void c_parser_do_statement (c_parser *, bool, unsigned short);
+static void c_parser_for_statement (c_parser *, bool, unsigned short, 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 *);
@@ -5499,13 +5499,13 @@ c_parser_statement_after_labels (c_parse
c_parser_switch_statement (parser, if_p);
break;
case RID_WHILE:
- c_parser_while_statement (parser, false, if_p);
+ c_parser_while_statement (parser, false, 0, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false);
+ c_parser_do_statement (parser, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, if_p);
+ c_parser_for_statement (parser, false, 0, if_p);
break;
case RID_CILK_FOR:
if (!flag_cilkplus)
@@ -6039,7 +6039,8 @@ c_parser_switch_statement (c_parser *par
implement -Wparentheses. */
static void
-c_parser_while_statement (c_parser *parser, bool ivdep, bool *if_p)
+c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool *if_p)
{
tree block, cond, body, save_break, save_cont;
location_t loc;
@@ -6059,6 +6060,11 @@ c_parser_while_statement (c_parser *pars
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
@@ -6093,7 +6099,7 @@ c_parser_while_statement (c_parser *pars
*/
static void
-c_parser_do_statement (c_parser *parser, bool ivdep)
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
{
tree block, cond, body, save_break, save_cont, new_break, new_cont;
location_t loc;
@@ -6125,6 +6131,11 @@ c_parser_do_statement (c_parser *parser,
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
@@ -6191,7 +6202,8 @@ c_parser_do_statement (c_parser *parser,
implement -Wparentheses. */
static void
-c_parser_for_statement (c_parser *parser, bool ivdep, bool *if_p)
+c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool *if_p)
{
tree block, cond, incr, save_break, save_cont, body;
/* The following are only used when parsing an ObjC foreach statement. */
@@ -6312,6 +6324,12 @@ c_parser_for_statement (c_parser *parser
"%<GCC ivdep%> pragma");
cond = error_mark_node;
}
+ else if (unroll)
+ {
+ c_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC unroll%> pragma");
+ cond = error_mark_node;
+ }
else
{
c_parser_consume_token (parser);
@@ -6333,6 +6351,11 @@ c_parser_for_statement (c_parser *parser
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
@@ -11042,6 +11065,49 @@ c_parser_objc_at_dynamic_declaration (c_
}
\f
+/* Parse a pragma GCC ivdep. */
+
+static bool
+c_parse_pragma_ivdep (c_parser *parser)
+{
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ return true;
+}
+
+/* Parse a pragma GCC unroll. */
+
+static unsigned short
+c_parser_pragma_unroll (c_parser *parser)
+{
+ unsigned short unroll;
+ 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 lunroll = 0;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ || TREE_CODE (expr) != INTEGER_CST
+ || (lunroll = tree_to_shwi (expr)) < 0
+ || lunroll > USHRT_MAX)
+ {
+ error_at (location, "%<#pragma GCC unroll%> requires an"
+ " assignment-expression that evaluates to a non-negative"
+ " integral constant less than or equal to %u", USHRT_MAX);
+ unroll = 0;
+ }
+ else
+ {
+ unroll = (unsigned short)lunroll;
+ if (unroll == 0)
+ unroll = 1;
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+ return unroll;
+}
+
/* 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
@@ -11184,21 +11250,51 @@ c_parser_pragma (c_parser *parser, enum
return c_parser_omp_ordered (parser, context, if_p);
case PRAGMA_IVDEP:
- c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (parser);
- if (!c_parser_next_token_is_keyword (parser, RID_FOR)
- && !c_parser_next_token_is_keyword (parser, RID_WHILE)
- && !c_parser_next_token_is_keyword (parser, RID_DO))
- {
- c_parser_error (parser, "for, while or do statement expected");
- return false;
- }
- if (c_parser_next_token_is_keyword (parser, RID_FOR))
- c_parser_for_statement (parser, true, if_p);
- else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, true, if_p);
- else
- c_parser_do_statement (parser, true);
+ {
+ const bool ivdep = c_parse_pragma_ivdep (parser);
+ unsigned short unroll;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL)
+ unroll = c_parser_pragma_unroll (parser);
+ else
+ unroll = 0;
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, ivdep, unroll, if_p);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, ivdep, unroll, if_p);
+ else
+ c_parser_do_statement (parser, ivdep, unroll);
+ }
+ return false;
+
+ case PRAGMA_UNROLL:
+ {
+ unsigned short unroll = c_parser_pragma_unroll (parser);
+ bool ivdep;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP)
+ ivdep = c_parse_pragma_ivdep (parser);
+ else
+ ivdep = false;
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, ivdep, unroll, if_p);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, ivdep, unroll, if_p);
+ else
+ c_parser_do_statement (parser, ivdep, unroll);
+ }
return false;
case PRAGMA_GCC_PCH_PREPROCESS:
Index: c-family/c-pragma.c
===================================================================
--- c-family/c-pragma.c (revision 255147)
+++ c-family/c-pragma.c (working copy)
@@ -1544,6 +1544,10 @@ init_pragma (void)
cpp_register_deferred_pragma (parse_in, "GCC", "ivdep", PRAGMA_IVDEP, false,
false);
+ if (!flag_preprocess_only)
+ cpp_register_deferred_pragma (parse_in, "GCC", "unroll", PRAGMA_UNROLL,
+ false, false);
+
if (flag_cilkplus)
cpp_register_deferred_pragma (parse_in, "cilk", "grainsize",
PRAGMA_CILK_GRAINSIZE, true, false);
Index: c-family/c-pragma.h
===================================================================
--- c-family/c-pragma.h (revision 255147)
+++ c-family/c-pragma.h (working copy)
@@ -75,6 +75,7 @@ enum pragma_kind {
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
+ PRAGMA_UNROLL,
PRAGMA_FIRST_EXTERNAL
};
Index: cp/constexpr.c
===================================================================
--- cp/constexpr.c (revision 255147)
+++ cp/constexpr.c (working copy)
@@ -4674,7 +4674,6 @@ cxx_eval_constant_expression (const cons
return t;
case ANNOTATE_EXPR:
- gcc_assert (tree_to_uhwi (TREE_OPERAND (t, 1)) == annot_expr_ivdep_kind);
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
lval,
non_constant_p, overflow_p,
@@ -5923,7 +5922,6 @@ potential_constant_expression_1 (tree t,
}
case ANNOTATE_EXPR:
- gcc_assert (tree_to_uhwi (TREE_OPERAND (t, 1)) == annot_expr_ivdep_kind);
return RECUR (TREE_OPERAND (t, 0), rval);
default:
Index: cp/cp-array-notation.c
===================================================================
--- cp/cp-array-notation.c (revision 255147)
+++ cp/cp-array-notation.c (working copy)
@@ -67,7 +67,7 @@ create_an_loop (tree init, tree cond, tr
finish_expr_stmt (init);
for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
finish_init_stmt (for_stmt);
- finish_for_cond (cond, for_stmt, false);
+ finish_for_cond (cond, for_stmt, false, 0);
finish_for_expr (incr, for_stmt);
finish_expr_stmt (body);
finish_for_stmt (for_stmt);
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 255147)
+++ cp/cp-tree.h (working copy)
@@ -6409,7 +6409,8 @@ extern tree implicitly_declare_fn
extern bool maybe_clone_body (tree);
/* In parser.c */
-extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool);
+extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool,
+ unsigned short);
extern bool parsing_nsdmi (void);
extern bool parsing_default_capturing_generic_lambda_in_template (void);
extern void inject_this_parameter (tree, cp_cv_quals);
@@ -6694,16 +6695,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);
+extern void finish_while_stmt_cond (tree, tree, bool, unsigned short);
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);
+extern void finish_do_stmt (tree, tree, bool, unsigned short);
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);
+extern void finish_for_cond (tree, tree, bool, unsigned short);
extern void finish_for_expr (tree, tree);
extern void finish_for_stmt (tree);
extern tree begin_range_for_stmt (tree, tree);
Index: cp/init.c
===================================================================
--- cp/init.c (revision 255147)
+++ cp/init.c (working copy)
@@ -4319,7 +4319,7 @@ build_vec_init (tree base, tree maxindex
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);
+ for_stmt, false, 0);
elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
complain);
if (elt_init == error_mark_node)
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 255147)
+++ cp/parser.c (working copy)
@@ -2121,15 +2121,15 @@ static tree cp_parser_selection_statemen
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
- (cp_parser *, bool *, bool);
+ (cp_parser *, bool *, bool, unsigned short);
static bool cp_parser_init_statement
(cp_parser *, tree *decl);
static tree cp_parser_for
- (cp_parser *, bool);
+ (cp_parser *, bool, unsigned short);
static tree cp_parser_c_for
- (cp_parser *, tree, tree, bool);
+ (cp_parser *, tree, tree, bool, unsigned short);
static tree cp_parser_range_for
- (cp_parser *, tree, tree, tree, bool);
+ (cp_parser *, tree, tree, tree, bool, unsigned short);
static void do_range_for_auto_deduction
(tree, tree);
static tree cp_parser_perform_range_for_lookup
@@ -10878,7 +10878,7 @@ cp_parser_statement (cp_parser* parser,
case RID_WHILE:
case RID_DO:
case RID_FOR:
- statement = cp_parser_iteration_statement (parser, if_p, false);
+ statement = cp_parser_iteration_statement (parser, if_p, false, 0);
break;
case RID_CILK_FOR:
@@ -11745,7 +11745,7 @@ cp_parser_condition (cp_parser* parser)
not included. */
static tree
-cp_parser_for (cp_parser *parser, bool ivdep)
+cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll)
{
tree init, scope, decl;
bool is_range_for;
@@ -11757,13 +11757,14 @@ cp_parser_for (cp_parser *parser, bool i
is_range_for = cp_parser_init_statement (parser, &decl);
if (is_range_for)
- return cp_parser_range_for (parser, scope, init, decl, ivdep);
+ return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll);
else
- return cp_parser_c_for (parser, scope, init, ivdep);
+ return cp_parser_c_for (parser, scope, init, ivdep, unroll);
}
static tree
-cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
+cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
+ unsigned short unroll)
{
/* Normal for loop */
tree condition = NULL_TREE;
@@ -11784,7 +11785,13 @@ cp_parser_c_for (cp_parser *parser, tree
"%<GCC ivdep%> pragma");
condition = error_mark_node;
}
- finish_for_cond (condition, stmt, ivdep);
+ else if (unroll)
+ {
+ cp_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC unroll%> pragma");
+ condition = error_mark_node;
+ }
+ finish_for_cond (condition, stmt, ivdep, unroll);
/* Look for the `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
@@ -11808,7 +11815,7 @@ cp_parser_c_for (cp_parser *parser, tree
static tree
cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
- bool ivdep)
+ bool ivdep, unsigned short unroll)
{
tree stmt, range_expr;
auto_vec <cxx_binding *, 16> bindings;
@@ -11877,6 +11884,8 @@ cp_parser_range_for (cp_parser *parser,
stmt = begin_range_for_stmt (scope, init);
if (ivdep)
RANGE_FOR_IVDEP (stmt) = 1;
+ if (unroll)
+ /* TODO */(void)0;
finish_range_for_decl (stmt, range_decl, range_expr);
if (!type_dependent_expression_p (range_expr)
/* do_auto_deduction doesn't mess with template init-lists. */
@@ -11887,7 +11896,8 @@ cp_parser_range_for (cp_parser *parser,
{
stmt = begin_for_stmt (scope, init);
stmt = cp_convert_range_for (stmt, range_decl, range_expr,
- decomp_first_name, decomp_cnt, ivdep);
+ decomp_first_name, decomp_cnt, ivdep,
+ unroll);
}
return stmt;
}
@@ -11981,7 +11991,7 @@ do_range_for_auto_deduction (tree decl,
tree
cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
tree decomp_first_name, unsigned int decomp_cnt,
- bool ivdep)
+ bool ivdep, unsigned short unroll)
{
tree begin, end;
tree iter_type, begin_expr, end_expr;
@@ -12042,7 +12052,7 @@ cp_convert_range_for (tree statement, tr
begin, ERROR_MARK,
end, ERROR_MARK,
NULL, tf_warning_or_error);
- finish_for_cond (condition, statement, ivdep);
+ finish_for_cond (condition, statement, ivdep, unroll);
/* The new increment expression. */
expression = finish_unary_op_expr (input_location,
@@ -12217,7 +12227,8 @@ cp_parser_range_for_member_function (tre
Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT. */
static tree
-cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep)
+cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
+ unsigned short unroll)
{
cp_token *token;
enum rid keyword;
@@ -12251,7 +12262,7 @@ cp_parser_iteration_statement (cp_parser
parens.require_open (parser);
/* Parse the condition. */
condition = cp_parser_condition (parser);
- finish_while_stmt_cond (condition, statement, ivdep);
+ finish_while_stmt_cond (condition, statement, ivdep, unroll);
/* Look for the `)'. */
parens.require_close (parser);
/* Parse the dependent statement. */
@@ -12282,7 +12293,7 @@ cp_parser_iteration_statement (cp_parser
/* Parse the expression. */
expression = cp_parser_expression (parser);
/* We're done with the do-statement. */
- finish_do_stmt (expression, statement, ivdep);
+ finish_do_stmt (expression, statement, ivdep, unroll);
/* Look for the `)'. */
parens.require_close (parser);
/* Look for the `;'. */
@@ -12296,7 +12307,7 @@ cp_parser_iteration_statement (cp_parser
matching_parens parens;
parens.require_open (parser);
- statement = cp_parser_for (parser, ivdep);
+ statement = cp_parser_for (parser, ivdep, unroll);
/* Look for the `)'. */
parens.require_close (parser);
@@ -38749,6 +38760,45 @@ cp_parser_cilk_grainsize (cp_parser *par
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
}
+/* Parse a pragma GCC ivdep. */
+
+static bool
+cp_parser_pragma_ivdep (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return true;
+}
+
+/* Parse a pragma GCC unroll. */
+
+static unsigned short
+cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok)
+{
+ location_t location = cp_lexer_peek_token (parser->lexer)->location;
+ tree expr = cp_parser_constant_expression (parser);
+ unsigned short unroll;
+ expr = maybe_constant_value (expr);
+ HOST_WIDE_INT lunroll = 0;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ || TREE_CODE (expr) != INTEGER_CST
+ || (lunroll = tree_to_shwi (expr)) < 0
+ || lunroll > USHRT_MAX)
+ {
+ error_at (location, "%<#pragma GCC unroll%> requires an"
+ " assignment-expression that evaluates to a non-negative"
+ " integral constant less than or equal to %u", USHRT_MAX);
+ unroll = 0;
+ }
+ else
+ {
+ unroll = (unsigned short)lunroll;
+ if (unroll == 0)
+ unroll = 1;
+ }
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return unroll;
+}
+
/* Normal parsing of a pragma token. Here we can (and must) use the
regular lexer. */
@@ -38990,17 +39040,60 @@ cp_parser_pragma (cp_parser *parser, enu
"%<#pragma GCC ivdep%> must be inside a function");
break;
}
- cp_parser_skip_to_pragma_eol (parser, pragma_tok);
- cp_token *tok;
- tok = cp_lexer_peek_token (the_parser->lexer);
+ const bool ivdep = cp_parser_pragma_ivdep (parser, pragma_tok);
+ unsigned short unroll;
+ cp_token *tok = cp_lexer_peek_token (the_parser->lexer);
+ if (tok->type == CPP_PRAGMA
+ && cp_parser_pragma_kind (tok) == PRAGMA_UNROLL)
+ {
+ tok = cp_lexer_consume_token (parser->lexer);
+ unroll = cp_parser_pragma_unroll (parser, tok);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ }
+ else
+ unroll = 0;
+ if (tok->type != CPP_KEYWORD
+ || (tok->keyword != RID_FOR
+ && tok->keyword != RID_WHILE
+ && tok->keyword != RID_DO))
+ {
+ cp_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ cp_parser_iteration_statement (parser, if_p, ivdep, unroll);
+ return true;
+ }
+
+ case PRAGMA_UNROLL:
+ {
+ if (context == pragma_external)
+ {
+ error_at (pragma_tok->location,
+ "%<#pragma GCC unroll%> must be inside a function");
+ break;
+ }
+ const unsigned short unroll
+ = cp_parser_pragma_unroll (parser, pragma_tok);
+ bool ivdep;
+ cp_token *tok = cp_lexer_peek_token (the_parser->lexer);
+ if (tok->type == CPP_PRAGMA
+ && cp_parser_pragma_kind (tok) == PRAGMA_IVDEP)
+ {
+ tok = cp_lexer_consume_token (parser->lexer);
+ ivdep = cp_parser_pragma_ivdep (parser, tok);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ }
+ else
+ ivdep = false;
if (tok->type != CPP_KEYWORD
- || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE
+ || (tok->keyword != RID_FOR
+ && tok->keyword != RID_WHILE
&& tok->keyword != RID_DO))
{
cp_parser_error (parser, "for, while or do statement expected");
return false;
}
- cp_parser_iteration_statement (parser, if_p, true);
+ cp_parser_iteration_statement (parser, if_p, ivdep, unroll);
return true;
}
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 255147)
+++ cp/pt.c (working copy)
@@ -16119,7 +16119,7 @@ tsubst_expr (tree t, tree args, tsubst_f
RECUR (FOR_INIT_STMT (t));
finish_init_stmt (stmt);
tmp = RECUR (FOR_COND (t));
- finish_for_cond (tmp, stmt, false);
+ finish_for_cond (tmp, stmt, false, 0);
tmp = RECUR (FOR_EXPR (t));
finish_for_expr (tmp, stmt);
RECUR (FOR_BODY (t));
@@ -16141,11 +16141,11 @@ tsubst_expr (tree t, tree args, tsubst_f
decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args,
complain, in_decl, &first, &cnt);
stmt = cp_convert_range_for (stmt, decl, expr, first, cnt,
- RANGE_FOR_IVDEP (t));
+ RANGE_FOR_IVDEP (t), 0);
}
else
stmt = cp_convert_range_for (stmt, decl, expr, NULL_TREE, 0,
- RANGE_FOR_IVDEP (t));
+ RANGE_FOR_IVDEP (t), 0);
RECUR (RANGE_FOR_BODY (t));
finish_for_stmt (stmt);
}
@@ -16154,7 +16154,7 @@ tsubst_expr (tree t, tree args, tsubst_f
case WHILE_STMT:
stmt = begin_while_stmt ();
tmp = RECUR (WHILE_COND (t));
- finish_while_stmt_cond (tmp, stmt, false);
+ finish_while_stmt_cond (tmp, stmt, false, 0);
RECUR (WHILE_BODY (t));
finish_while_stmt (stmt);
break;
@@ -16164,7 +16164,7 @@ tsubst_expr (tree t, tree args, tsubst_f
RECUR (DO_BODY (t));
finish_do_body (stmt);
tmp = RECUR (DO_COND (t));
- finish_do_stmt (tmp, stmt, false);
+ finish_do_stmt (tmp, stmt, false, 0);
break;
case IF_STMT:
Index: cp/semantics.c
===================================================================
--- cp/semantics.c (revision 255147)
+++ cp/semantics.c (working copy)
@@ -802,7 +802,8 @@ begin_while_stmt (void)
WHILE_STMT. */
void
-finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep)
+finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
+ unsigned short unroll)
{
if (check_no_cilk (cond,
"Cilk array notation cannot be used as a condition for while statement",
@@ -818,6 +819,14 @@ finish_while_stmt_cond (tree cond, tree
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && 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_unroll_kind),
+ build_int_cst (integer_type_node,
+ unroll));
simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
}
@@ -862,7 +871,7 @@ finish_do_body (tree do_stmt)
COND is as indicated. */
void
-finish_do_stmt (tree cond, tree do_stmt, bool ivdep)
+finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll)
{
if (check_no_cilk (cond,
"Cilk array notation cannot be used as a condition for a do-while statement",
@@ -874,6 +883,10 @@ finish_do_stmt (tree cond, tree do_stmt,
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node, annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node, annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
DO_COND (do_stmt) = cond;
}
@@ -982,7 +995,7 @@ finish_init_stmt (tree for_stmt)
FOR_STMT. */
void
-finish_for_cond (tree cond, tree for_stmt, bool ivdep)
+finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll)
{
if (check_no_cilk (cond,
"Cilk array notation cannot be used in a condition for a for-loop",
@@ -998,6 +1011,14 @@ finish_for_cond (tree cond, tree for_stm
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && 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_unroll_kind),
+ build_int_cst (integer_type_node,
+ unroll));
simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
}
Index: testsuite/c-c++-common/unroll-1.c
===================================================================
--- testsuite/c-c++-common/unroll-1.c (revision 0)
+++ testsuite/c-c++-common/unroll-1.c (working copy)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cunrolli-details -fdump-rtl-loop2_unroll-details" } */
+
+extern void bar (int);
+
+int j;
+
+void test (void)
+{
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+ /* { dg-final { scan-tree-dump "11:.*: note: loop with 8 iterations completely unrolled" "cunrolli" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 7; ++i)
+ bar(i);
+ /* { dg-final { scan-tree-dump "16:.*: note: loop with 7 iterations completely unrolled" "cunrolli" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 15; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "21:.*: note: loop unrolled 7 times" "loop2_unroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "26:.*: note: loop unrolled 7 times" "loop2_unroll" } } */
+
+ #pragma GCC unroll 7
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "31:.*: note: loop unrolled 3 times" "loop2_unroll" } } */
+
+ unsigned long i = 0;
+ #pragma GCC unroll 3
+ do {
+ bar(i);
+ } while (++i < 9);
+ /* { dg-final { scan-rtl-dump "3\[79\]:.*: note: loop unrolled 2 times" "loop2_unroll" } } */
+}
Index: testsuite/c-c++-common/unroll-2.c
===================================================================
--- testsuite/c-c++-common/unroll-2.c (revision 0)
+++ testsuite/c-c++-common/unroll-2.c (working copy)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-cunroll-details -fdump-rtl-loop2_unroll-details" } */
+
+extern void bar (int);
+
+int j;
+
+void test (void)
+{
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+ /* { dg-final { scan-tree-dump "11:.*: note: loop with 7 iterations completely unrolled" "cunroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 7; ++i)
+ bar(i);
+ /* { dg-final { scan-tree-dump "16:.*: note: loop with 6 iterations completely unrolled" "cunroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 15; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "21:.*: note: loop unrolled 7 times" "loop2_unroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "26:.*: note: loop unrolled 7 times" "loop2_unroll" } } */
+
+ #pragma GCC unroll 7
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "31:.*: note: loop unrolled 3 times" "loop2_unroll" } } */
+
+ unsigned long i = 0;
+ #pragma GCC unroll 3
+ do {
+ bar(i);
+ } while (++i < 9);
+ /* { dg-final { scan-rtl-dump "3\[79\]:.*: note: loop unrolled 2 times" "loop2_unroll" } } */
+}
Index: testsuite/c-c++-common/unroll-3.c
===================================================================
--- testsuite/c-c++-common/unroll-3.c (revision 0)
+++ testsuite/c-c++-common/unroll-3.c (working copy)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdisable-tree-cunroll -fdump-rtl-loop2_unroll-details" } */
+
+extern void bar (int);
+
+int j;
+
+void test (void)
+{
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump-not "11:.*: note: loop unrolled" "loop2_unroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 7; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump-not "16:.*: note: loop unrolled" "loop2_unroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= 15; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "21:.*: note: loop unrolled 7 times" "loop2_unroll" } } */
+
+ #pragma GCC unroll 8
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "26:.*: note: loop unrolled 7 times" "loop2_unroll" } } */
+
+ #pragma GCC unroll 7
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+ /* { dg-final { scan-rtl-dump "31:.*: note: loop unrolled 3 times" "loop2_unroll" } } */
+
+ unsigned long i = 0;
+ #pragma GCC unroll 3
+ do {
+ bar(i);
+ } while (++i < 9);
+ /* { dg-final { scan-rtl-dump "3\[79\]:.*: note: loop unrolled 2 times" "loop2_unroll" } } */
+}
Index: testsuite/c-c++-common/unroll-4.c
===================================================================
--- testsuite/c-c++-common/unroll-4.c (revision 0)
+++ testsuite/c-c++-common/unroll-4.c (working copy)
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -funroll-all-loops -fdump-rtl-loop2_unroll-details -fdump-tree-cunrolli-details" } */
+
+extern void bar (int);
+
+int j;
+
+void test (void)
+{
+ #pragma GCC unroll 0
+ #pragma GCC ivdep
+ for (unsigned long i = 1; i <= 3; ++i)
+ bar(i);
+
+ #pragma GCC ivdep
+ #pragma GCC unroll 0
+ for (unsigned long i = 1; i <= j; ++i)
+ bar(i);
+
+ /* { dg-final { scan-tree-dump "Not unrolling loop .: user didn't want it unrolled completely" "cunrolli" } } */
+ /* { dg-final { scan-rtl-dump-times "Not unrolling loop, user didn't want it unrolled" 2 "loop2_unroll" } } */
+}
Index: testsuite/c-c++-common/unroll-5.c
===================================================================
--- testsuite/c-c++-common/unroll-5.c (revision 0)
+++ testsuite/c-c++-common/unroll-5.c (working copy)
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+
+extern void bar (int);
+
+int j;
+
+void test (void)
+{
+ #pragma GCC unroll 4+4
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+
+ #pragma GCC unroll -1 /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+
+ #pragma GCC unroll 20000000000 /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+
+ #pragma GCC unroll j /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
+ /* { dg-error "cannot appear in a constant-expression|is not usable in a constant expression" "" { target c++ } 21 } */
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+
+ #pragma GCC unroll 4.2 /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
+ for (unsigned long i = 1; i <= 8; ++i)
+ bar(i);
+}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [C/C++] Add support for #pragma GCC unroll v3
2017-11-25 15:31 [C/C++] Add support for #pragma GCC unroll v3 Eric Botcazou
@ 2017-11-30 19:18 ` Joseph Myers
2017-12-27 7:32 ` [testsuite, committed] Use relative line number in unroll-5.c Tom de Vries
1 sibling, 0 replies; 3+ messages in thread
From: Joseph Myers @ 2017-11-30 19:18 UTC (permalink / raw)
To: Eric Botcazou; +Cc: gcc-patches, Jason Merrill
On Sat, 25 Nov 2017, Eric Botcazou wrote:
> Hi,
>
> this is the (hopefully) final implementation of the support for the unrolling
> pragma in the C and C++ front-ends. It contains a couple of fixes for the C++
> front-ends to make it correctly handle unroll and ivdep for the same loop.
>
> Tested on x86_64-suse-linux, OK for the mainline?
The C front-end changes are OK.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 3+ messages in thread
* [testsuite, committed] Use relative line number in unroll-5.c
2017-11-25 15:31 [C/C++] Add support for #pragma GCC unroll v3 Eric Botcazou
2017-11-30 19:18 ` Joseph Myers
@ 2017-12-27 7:32 ` Tom de Vries
1 sibling, 0 replies; 3+ messages in thread
From: Tom de Vries @ 2017-12-27 7:32 UTC (permalink / raw)
To: Eric Botcazou, gcc-patches; +Cc: Joseph Myers, Jason Merrill
[-- Attachment #1: Type: text/plain, Size: 1685 bytes --]
[ was: Re: [C/C++] Add support for #pragma GCC unroll v3 ]
On 11/25/2017 11:15 AM, Eric Botcazou wrote:
> Index: testsuite/c-c++-common/unroll-5.c
> ===================================================================
> --- testsuite/c-c++-common/unroll-5.c (revision 0)
> +++ testsuite/c-c++-common/unroll-5.c (working copy)
> @@ -0,0 +1,29 @@
> +/* { dg-do compile } */
> +
> +extern void bar (int);
> +
> +int j;
> +
> +void test (void)
> +{
> + #pragma GCC unroll 4+4
> + for (unsigned long i = 1; i <= 8; ++i)
> + bar(i);
> +
> + #pragma GCC unroll -1 /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
> + for (unsigned long i = 1; i <= 8; ++i)
> + bar(i);
> +
> + #pragma GCC unroll 20000000000 /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
> + for (unsigned long i = 1; i <= 8; ++i)
> + bar(i);
> +
> + #pragma GCC unroll j /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
> + /* { dg-error "cannot appear in a constant-expression|is not usable in a constant expression" "" { target c++ } 21 } */
> + for (unsigned long i = 1; i <= 8; ++i)
> + bar(i);
> +
> + #pragma GCC unroll 4.2 /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than or equal to" } */
> + for (unsigned long i = 1; i <= 8; ++i)
> + bar(i);
> +}
Hi,
this patch changes the absolute line number into a relative one.
Tested on x86_64 and committed.
Thanks,
- Tom
[-- Attachment #2: 0002-Use-relative-line-number-in-unroll-5.c.patch --]
[-- Type: text/x-patch, Size: 990 bytes --]
Use relative line number in unroll-5.c
2017-12-26 Tom de Vries <tom@codesourcery.com>
* c-c++-common/unroll-5.c: Use relative line number.
---
gcc/testsuite/c-c++-common/unroll-5.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gcc/testsuite/c-c++-common/unroll-5.c b/gcc/testsuite/c-c++-common/unroll-5.c
index 754f3b1..b728066 100644
--- a/gcc/testsuite/c-c++-common/unroll-5.c
+++ b/gcc/testsuite/c-c++-common/unroll-5.c
@@ -19,7 +19,7 @@ void test (void)
bar(i);
#pragma GCC unroll j /* { dg-error "requires an assignment-expression that evaluates to a non-negative integral constant less than" } */
- /* { dg-error "cannot appear in a constant-expression|is not usable in a constant expression" "" { target c++ } 21 } */
+ /* { dg-error "cannot appear in a constant-expression|is not usable in a constant expression" "" { target c++ } .-1 } */
for (unsigned long i = 1; i <= 8; ++i)
bar(i);
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2017-12-27 7:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-25 15:31 [C/C++] Add support for #pragma GCC unroll v3 Eric Botcazou
2017-11-30 19:18 ` Joseph Myers
2017-12-27 7:32 ` [testsuite, committed] Use relative line number in unroll-5.c Tom de Vries
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).