Skip to content

Commit 1fb74ef

Browse files
mborlandwchilders-nvidia
authored andcommitted
Add support for GNU loop pragmas [GH #174]
1 parent 7915434 commit 1fb74ef

281 files changed

Lines changed: 177 additions & 3242 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎doc/source/code_style.rst‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,3 +707,16 @@ instead of:
707707
.. code:: cpp
708708
709709
f(a, b, c, d, /*is_foo_bar=*/FALSE, /*needs_more_squirrels=*/VERY_FALSE);
710+
711+
Wrapping Array Subscripts
712+
-------------------------
713+
714+
Array subscripts that cause the line length to exceed 79 characters are
715+
wrapped like a function call whose argument cannot fit: the line is broken
716+
after the "``[``" and the continuation is right-aligned to column 79, including
717+
the closing "``]``" and any punctuation that follows it:
718+
719+
.. code:: cpp
720+
721+
pkdp = pragma_description_for_pragma_kind[
722+
/* something very long (right-aligned to column 79) */];

‎src/Changes‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
Version 7.1
22

3+
10/21/26 [GH #174]
4+
C-generating back end: placement of GCC loop pragmas
5+
6+
The GCC loop pragmas "#pragma GCC unroll", "#pragma GCC ivdep", and
7+
"#pragma GCC novector" were previously recorded in the IL as pragmas of the
8+
enclosing block and so were emitted by the C-generating back end at the start
9+
of that block, rather than immediately in front of the loop to which they
10+
apply. The back-end compiler then rejected the generated code. For example:
11+
12+
void h();
13+
void f(char *first, char *last) {
14+
h();
15+
#pragma GCC unroll 4 // Previously emitted in front of the call of h,
16+
while (first != last) // causing a "for, while or do statement expected"
17+
++first; // error from the back-end compiler.
18+
}
19+
20+
321
10/21/26 [GH #335]
422
Type transformations of qualified function types
523

‎src/il_alloc.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4475,6 +4475,7 @@ pointer to it.
44754475
#if GNU_EXTENSIONS_ALLOWED
44764476
case pk_gcc_immediate:
44774477
case pk_gcc_next_token:
4478+
case pk_gcc_next_statement:
44784479
clear_gcc_pragma_descr(&pp->variant.gcc);
44794480
break;
44804481
#if GNU_VECTOR_TYPES_ALLOWED && BUILTIN_FUNCTIONS_ENABLED

‎src/il_def.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6723,6 +6723,7 @@ enum a_pragma_kind : a_byte {
67236723
#if GNU_EXTENSIONS_ALLOWED
67246724
pk_gcc_immediate, /* GCC pragmas (handled immediately). */
67256725
pk_gcc_next_token, /* GCC pragmas (handled as next token). */
6726+
pk_gcc_next_statement,/* GCC pragmas (bound to the next statement). */
67266727
#if GNU_VECTOR_TYPES_ALLOWED && BUILTIN_FUNCTIONS_ENABLED
67276728
pk_gnu_riscv, /* GCC RISC-V intrinsics. */
67286729
pk_clang_riscv, /* Clang RISC-V intrinsics. */
@@ -6834,6 +6835,7 @@ EXTERN_CONSTINIT_ARRAY(a_const_char*, pragma_ids, pk_last + 1)
68346835
#if GNU_EXTENSIONS_ALLOWED
68356836
/* pk_gcc_immediate */ "GCC",
68366837
/* pk_gcc_next_token */ "GCC",
6838+
/* pk_gcc_next_statement */ "GCC",
68376839
#if GNU_VECTOR_TYPES_ALLOWED && BUILTIN_FUNCTIONS_ENABLED
68386840
/* pk_gnu_riscv */ "riscv",
68396841
/* pk_clang_riscv */ "clang",

‎src/lower_c99.c‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4483,10 +4483,15 @@ Do C99 lowering on an stmk_for statement.
44834483
} else {
44844484
/* The C99 case: move the initialization code out into a
44854485
block surrounding the for loop. Note that this is particularly
4486-
desirable when there is a VLA declaration in the initialization. */
4486+
desirable when there is a VLA declaration in the initialization.
4487+
Any pragmas attached to the for loop (e.g., "#pragma GCC unroll")
4488+
must stay with the for loop. */
44874489
an_insert_location insert_location;
44884490
flp->initialization = NULL;
4489-
turn_statement_into_block(for_stmt, &insert_location, &for_stmt);
4491+
turn_statement_into_block_transferring_pragma(for_stmt,
4492+
&insert_location,
4493+
&for_stmt,
4494+
curr_context->scope);
44904495
reinsert_for_loop_initialization(init_stmt, &insert_location);
44914496
} /* if */
44924497
} /* if */

‎src/lower_il.c‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18407,7 +18407,7 @@ the try-block has been rewritten).
1840718407
} /* put_block_around_try_block */
1840818408

1840918409

18410-
static void turn_statement_into_block_transferring_pragma(
18410+
void turn_statement_into_block_transferring_pragma(
1841118411
a_statement_ptr statement,
1841218412
an_insert_location_ptr insert_location,
1841318413
a_statement_ptr *orig_statement,
@@ -19763,9 +19763,12 @@ If the "for" statement has an associated "break" label, lower it also.
1976319763
break_label_stmt->next = NULL;
1976419764
} /* if */
1976519765
/* Put a block statement around the for-loop and attach the scope
19766-
to that block. */
19766+
to that block. Any pragmas attached to the for-loop (e.g., a
19767+
"#pragma GCC unroll") stay with the for-loop. */
1976719768
block_stmt = for_stmt;
19768-
turn_statement_into_block(for_stmt, &insert_location, &for_stmt);
19769+
turn_statement_into_block_transferring_pragma(for_stmt, &insert_location,
19770+
&for_stmt,
19771+
curr_context->scope);
1976919772
if (break_label_stmt != NULL) {
1977019773
/* Re-attach the break label after the "for" statement entry. */
1977119774
check_assertion(for_stmt->next == NULL);
@@ -19795,7 +19798,10 @@ If the "for" statement has an associated "break" label, lower it also.
1979519798
/* Put a block around the for loop if we didn't previously. */
1979619799
if (block_stmt == NULL) {
1979719800
block_stmt = for_stmt;
19798-
turn_statement_into_block(for_stmt, &insert_location, &for_stmt);
19801+
turn_statement_into_block_transferring_pragma(for_stmt,
19802+
&insert_location,
19803+
&for_stmt,
19804+
curr_context->scope);
1979919805
} /* if */
1980019806
reinsert_for_loop_initialization(init_stmt, &insert_location);
1980119807
} /* if */
@@ -19895,11 +19901,14 @@ the following lowered C code is generated:
1989519901
push_context(&range_based_for_context, range_based_for_scope,
1989619902
(an_object_lifetime_ptr)NULL);
1989719903
/* Put a block statement around the range-based-for and attach the
19898-
range_based_for scope to that block. Note that any pragmas attached to
19899-
the range-based-for statement will now be associated with the block. */
19904+
range_based_for scope to that block. Any pragmas attached to the
19905+
range-based-for statement (e.g., a "#pragma GCC unroll") stay with the
19906+
statement, which becomes the lowered "for" loop. */
1990019907
outer_block = range_based_for_stmt;
19901-
turn_statement_into_block(range_based_for_stmt, &outer_insert_location,
19902-
&range_based_for_stmt);
19908+
turn_statement_into_block_transferring_pragma(range_based_for_stmt,
19909+
&outer_insert_location,
19910+
&range_based_for_stmt,
19911+
curr_context->scope);
1990319912
outer_block->variant.block.extra_info->assoc_scope = range_based_for_scope;
1990419913
range_based_for_scope->assoc_block = outer_block;
1990519914
if (range_based_for_scope->lifetime != NULL) {

‎src/lower_il.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,12 @@ extern void turn_statement_into_block(a_statement_ptr statement,
12001200
an_insert_location_ptr insert_location,
12011201
a_statement_ptr *orig_statement);
12021202

1203+
extern void turn_statement_into_block_transferring_pragma(
1204+
a_statement_ptr statement,
1205+
an_insert_location_ptr insert_location,
1206+
a_statement_ptr *orig_statement,
1207+
a_scope_ptr scope);
1208+
12031209
extern void put_block_around_try_block(a_statement_ptr statement,
12041210
an_insert_location_ptr insert_location,
12051211
a_statement_ptr *orig_statement);

‎src/pragma.c‎

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ Construct a pending pragma with the given pragma kind description.
351351
#if GNU_EXTENSIONS_ALLOWED
352352
case pk_gcc_immediate:
353353
case pk_gcc_next_token:
354+
case pk_gcc_next_statement:
354355
clear_gcc_pragma_descr(&this->variant.gcc);
355356
break;
356357
#if GNU_VECTOR_TYPES_ALLOWED && BUILTIN_FUNCTIONS_ENABLED
@@ -1857,11 +1858,28 @@ Initialize the pragma description table.
18571858
#endif /* SUN_EXTENSIONS_ALLOWED */
18581859
#if GNU_EXTENSIONS_ALLOWED
18591860
if (gnu_mode && gnu_version >= 40200) {
1860-
/* "GCC" pragmas are handled by pk_gcc_next_token or pk_gcc_immediate
1861-
depending on the specific variety of "GCC" pragma. Currently
1862-
"GCC diagnostic" pragmas are pk_gcc_next_token and all others are
1863-
pk_gcc_immediate. Note that the order of these next two calls is
1861+
/* "GCC" pragmas are handled by pk_gcc_next_statement, pk_gcc_next_token,
1862+
or pk_gcc_immediate depending on the specific variety of "GCC" pragma.
1863+
Currently "GCC unroll", "GCC ivdep", and "GCC novector" pragmas
1864+
(which apply to the loop that follows them) are pk_gcc_next_statement,
1865+
"GCC diagnostic" pragmas are pk_gcc_next_token, and all others are
1866+
pk_gcc_immediate. Note that the order of these next three calls is
18641867
important (look_up_pragma_id relies on it). */
1868+
(void)add_next_construct_pragma_kind_description
1869+
((a_pragma_kind)pk_gcc_next_statement,
1870+
(a_function_number)fn_null,
1871+
/*is_pseudo_pragma=*/FALSE,
1872+
/*may_bind_to_decl=*/FALSE,
1873+
/*may_bind_to_stmt=*/TRUE,
1874+
/*automatically_include_in_il=*/TRUE,
1875+
/*record_pragma_text=*/TRUE,
1876+
/*expand_macros=*/FALSE,
1877+
/*processing_C_code=*/TRUE,
1878+
/*fetch_pp_tokens=*/FALSE,
1879+
/*ignore_in_back_end=*/FALSE,
1880+
/*il_info_is_complete=*/TRUE,
1881+
/*read_string_as_header_name=*/FALSE,
1882+
es_warning);
18651883
(void)add_next_token_pragma_kind_description
18661884
((a_pragma_kind)pk_gcc_next_token,
18671885
fn_for_function(gcc_pragma),

‎src/preproc.c‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3262,6 +3262,31 @@ only, only preprocessing immediate pragmas are actually processed.
32623262
} /* if */
32633263
} /* record_pragma */
32643264

3265+
#if GNU_EXTENSIONS_ALLOWED
3266+
3267+
static a_boolean is_gcc_loop_pragma_name(a_const_char *ptr)
3268+
/*
3269+
Return TRUE if the characters at ptr are the name of one of the "GCC" pragmas
3270+
that must immediately precede, and apply to a loop statement.
3271+
Currently supported: "unroll", "ivdep", and "novector".
3272+
*/
3273+
{
3274+
static a_const_char *const loop_pragma_names[] = {
3275+
"unroll", "ivdep", "novector"
3276+
};
3277+
a_boolean is_loop_pragma = FALSE;
3278+
3279+
for (a_const_char *name : loop_pragma_names) {
3280+
size_t len = strlen(name);
3281+
if (strncmp(ptr, name, len) == 0 && !is_id_char[ptr[len]-CHAR_MIN]) {
3282+
is_loop_pragma = TRUE;
3283+
break;
3284+
} /* if */
3285+
} /* for */
3286+
return is_loop_pragma;
3287+
} /* is_gcc_loop_pragma_name */
3288+
3289+
#endif /* GNU_EXTENSIONS_ALLOWED */
32653290

32663291
a_pragma_kind_description_ptr look_up_pragma_id(
32673292
a_source_position *id_position)
@@ -3297,8 +3322,8 @@ The position of the pragma ID is returned in id_position;
32973322
if (curr_id_matches_pragma_id(pkdp->kind)) {
32983323
#if GNU_EXTENSIONS_ALLOWED
32993324
/* We found a match. If we're processing a GCC pragma, see if we
3300-
should treat it as an immediate pragma or a next_token pragma
3301-
based on the token that follows "GCC". */
3325+
should treat it as an immediate pragma, a next_token pragma, or
3326+
a next_statement pragma based on the token that follows "GCC". */
33023327
if (pkdp->kind == (a_pragma_kind)pk_gcc_immediate) {
33033328
/* We want to look ahead to see if "diagnostic" is next, but
33043329
being that we're in a preprocessing directive, next_token
@@ -3311,6 +3336,10 @@ The position of the pragma ID is returned in id_position;
33113336
/* Treat all "GCC diagnostic" pragmas as next_token. */
33123337
pkdp = pkdp->next;
33133338
check_assertion(pkdp->kind == (a_pragma_kind)pk_gcc_next_token);
3339+
} else if (is_gcc_loop_pragma_name(curr_char_loc)) {
3340+
/* Bind the GCC loop pragmas to the statement that follows. */
3341+
pkdp = pragma_description_for_pragma_kind[
3342+
(int)pk_gcc_next_statement];
33143343
} /* if */
33153344
#if GNU_VECTOR_TYPES_ALLOWED && BUILTIN_FUNCTIONS_ENABLED
33163345
} else if (pkdp->kind == pk_clang_riscv) {

‎tests/expectations/edg_x86_64/imported.log‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4161,7 +4161,6 @@ gnu/c/torture/no-callee-saved-run-1a.sft.c:rp:-DTEST_NUMBER=1:FAIL(COMPILE):
41614161
gnu/c/torture/pr100329.sft.c:s:-DTEST_NUMBER=1 -w:SKIPPED:
41624162
gnu/c/torture/pr100519.sft.c:s:-DTEST_NUMBER=1 -w:SKIPPED:
41634163
gnu/c/torture/pr100778.sft.c:rp:-DTEST_NUMBER=1:FAIL(COMPILE):
4164-
gnu/c/torture/pr101173.sft.c:rp:-DTEST_NUMBER=1:BADC(COMPILE):
41654164
gnu/c/torture/pr101512.sft.c:fp:-DTEST_NUMBER=1 -w:FAIL:
41664165
gnu/c/torture/pr103181.sft.c:rp:-DTEST_NUMBER=1:FAIL(COMPILE):
41674166
gnu/c/torture/pr103596.sft.c:s:-DTEST_NUMBER=1:SKIPPED:
@@ -4225,7 +4224,6 @@ gnu/c/torture/pr77646.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42254224
gnu/c/torture/pr79536.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42264225
gnu/c/torture/pr79908.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42274226
gnu/c/torture/pr79970.sft.c:fn:-DTEST_NUMBER=1:FAIL:
4228-
gnu/c/torture/pr80304.sft.c:rp:-DTEST_NUMBER=1:BADC(COMPILE):
42294227
gnu/c/torture/pr80612.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42304228
gnu/c/torture/pr80764.sft.c:fp:-DTEST_NUMBER=1:FAIL:
42314229
gnu/c/torture/pr8081.sft.c:rp:-DTEST_NUMBER=1:FAIL(COMPILE):
@@ -7410,7 +7408,6 @@ gnu/cpp/ext/pr84724-1.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
74107408
gnu/cpp/ext/pr84724-2.sft.cpp:fp:-DTEST_NUMBER=1 -w:FAIL:
74117409
gnu/cpp/ext/pr84828.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
74127410
gnu/cpp/ext/pr85503.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
7413-
gnu/cpp/ext/pragma-unroll-lambda-lto.sft.cpp:lp:-DTEST_NUMBER=1 --c++11:BADC:
74147411
gnu/cpp/ext/restrict2.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
74157412
gnu/cpp/ext/selectany1.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
74167413
gnu/cpp/ext/spe1.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
@@ -8973,7 +8970,6 @@ gnu/cpp/torture/darwin-cfstring-3.sft.cpp:fp:-DTEST_NUMBER=1:CATASTROPHE:
89738970
gnu/cpp/torture/phi-1.sft.cpp:s:-DTEST_NUMBER=1 --c++11:SKIPPED:
89748971
gnu/cpp/torture/pr101373.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
89758972
gnu/cpp/torture/pr103669.sft.cpp:s:-DTEST_NUMBER=1:SKIPPED:
8976-
gnu/cpp/torture/pr104601.sft.cpp:rp:-DTEST_NUMBER=1 --c++17:BADC(COMPILE):
89778973
gnu/cpp/torture/pr109262.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
89788974
gnu/cpp/torture/pr111465.sft.cpp:s:-DTEST_NUMBER=1 --no_exceptions:SKIPPED:
89798975
gnu/cpp/torture/pr115694.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
@@ -8995,7 +8991,6 @@ gnu/cpp/torture/pr64312.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
89958991
gnu/cpp/torture/pr69355.sft.cpp:rp:-DTEST_NUMBER=1:FAIL(COMPILE):
89968992
gnu/cpp/torture/pr77919-2.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
89978993
gnu/cpp/torture/pr79905.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
8998-
gnu/cpp/torture/pr81877.sft.cpp:rp:-DTEST_NUMBER=1:BADC(COMPILE):
89998994
gnu/cpp/torture/pr82985.sft.cpp:fp:-DTEST_NUMBER=1 -w:FAIL:
90008995
gnu/cpp/torture/pr84961-1.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
90018996
gnu/cpp/torture/pr85013.sft.cpp:s:-DTEST_NUMBER=1 --c++14:SKIPPED:

0 commit comments

Comments
 (0)