Skip to content

Commit d9e78d1

Browse files
committed
Add a warning for large unrolled loops
1 parent f251371 commit d9e78d1

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

RELEASENOTES.docu

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,4 +1748,7 @@ extern typedef struct { } my_type_t;</pre> </add-note></build-id>
17481748
are themselves constant inlined method parameters (i.e. an inline method
17491749
call propagates an inline parameter to an inline method call of its own.)
17501750
</add-note></build-id>
1751+
<build-id value="next"><add-note> Added the warning `WBIGUNROLL` which is
1752+
emitted when a <tt>#select</tt> or <tt>#foreach</tt> statement is compiled
1753+
to a large unrolled loop.</add-note></build-id>
17511754
</rn>

py/dml/codegen.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3048,12 +3048,19 @@ def stmt_select(stmt, location, scope):
30483048
else_dead = True
30493049
break
30503050

3051+
iterations = len(clauses)
30513052
if else_dead:
30523053
(last_cond, last_stmt) = clauses.pop(-1)
30533054
assert last_cond.constant and last_cond.value
30543055
if_chain = last_stmt
30553056
else:
30563057
if_chain = codegen_statement(else_ast, location, scope)
3058+
if iterations > 50 and isinstance(lst, List):
3059+
report(WBIGUNROLL(stmt.site,
3060+
'#'*(stmt.site.dml_version() != (1, 2))
3061+
+ 'select',
3062+
iterations))
3063+
30573064
for (cond, stmt) in reversed(clauses):
30583065
if_chain = mkIf(cond.site, cond, stmt, if_chain)
30593066
return [if_chain]
@@ -3179,6 +3186,10 @@ def foreach_constant_list(site, itername, lst, statement, location, scope):
31793186
stmt)
31803187
spec.append(mkCompound(site, decls + [stmt]))
31813188

3189+
if len(spec) > 50 and isinstance(lst, List):
3190+
report(WBIGUNROLL(site,
3191+
'#'*(site.dml_version() != (1, 2)) + 'foreach',
3192+
len(spec)))
31823193
return [mkUnrolledLoop(site, spec,
31833194
context.label if context.used else None)]
31843195

py/dml/messages.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,28 @@ class WHOOKSEND(DMLWarning):
20112011
+ "Declarations section in the DML 1.4 reference manual for "
20122012
+ "information about the differences between 'send' and 'send_now'")
20132013

2014+
class WBIGUNROLL(DMLWarning):
2015+
"""
2016+
A `#select` or `#foreach` statement was specified which caused DMLC to
2017+
study the body and generate duplicated C code for it a large number of
2018+
times (more than 50 times.) This can dramatically increase both DMLC and
2019+
GCC compile times and code size, if not crash DMLC outright.
2020+
2021+
To address this, you have two options:
2022+
* Ensure most iterations can be entirely eliminated at compile-time by
2023+
DMLC. For `#select`, this can be done by ensuring that the `where` check
2024+
will be a constant (typically a constant equality) for most if not all
2025+
items of the specified list. For `#foreach`, encase the body in an `#if`
2026+
check that is false for most items of the specified list.
2027+
* Don't use `#select` or `#foreach`. Represent the specified compile-time
2028+
list instead as a `session` array or an `extern`ed C array, and iterate
2029+
through it using traditional `for` loops. For more information, see [the
2030+
various answers to this Stack Overflow question.](https://stackoverflow.com/questions/75073681/cannot-use-variable-index-in-a-constant-list)
2031+
"""
2032+
fmt = ("This '%s' statement compiles to an unrolled loop where the loop "
2033+
+ "body is studied and generated %s times. This may dramatically "
2034+
+ "increase both DMLC and GCC compilation times, if not crash DMLC "
2035+
+ "outright!")
20142036

20152037
class PSHA1(PortingMessage):
20162038
"""The `port-dml` script requires that the DML file has not been

test/1.2/errors/T_WBIGUNROLL.dml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
© 2023 Intel Corporation
3+
SPDX-License-Identifier: MPL-2.0
4+
*/
5+
dml 1.2;
6+
7+
device test;
8+
9+
/// COMPILE-ONLY
10+
/// NO-CC
11+
12+
data int zero = 0;
13+
14+
parameter zeroes_50 = [$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
15+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
16+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
17+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
18+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
19+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
20+
$zero, $zero];
21+
22+
// Fiftieth zero is constant
23+
parameter zeroes_51 = [$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
24+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
25+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
26+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
27+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
28+
$zero, $zero, $zero, $zero, $zero, $zero, $zero, $zero,
29+
$zero, 0, $zero];
30+
31+
bank b {
32+
register regs[i in 0..50] size 4 @ undefined;
33+
}
34+
35+
method init {
36+
local int i;
37+
38+
// no warning
39+
foreach x in ($zeroes_50) assert true;
40+
// The else branch is not considered an iteration
41+
select x in ($zeroes_50) where (x == i) {
42+
assert true;
43+
} else assert true;
44+
45+
/// WARNING WBIGUNROLL
46+
foreach x in ($zeroes_51) assert true;
47+
/// WARNING WBIGUNROLL
48+
select x in ($zeroes_51) where (x == i) {
49+
assert true;
50+
} else assert true;
51+
52+
// no warning
53+
foreach x in ($zeroes_51) {
54+
// As fiftieth bit is constant 0, DML 1.2 semantics eliminates this if
55+
// entirely, and subsequently causes that iteration to be omitted from
56+
// codegen entirely; reducing the total count to 50
57+
if (x != 0) assert true;
58+
}
59+
60+
// As fiftieth bit is constant 0, select can cut short at it, reducing the
61+
// total number of iterations to 50
62+
select x in ($zeroes_50) where (x == 0) {
63+
assert true;
64+
} else assert true;
65+
66+
// As fiftieth bit is constant 0, select can omit the check and thus
67+
// iteration for it, reducing the total number of iterations to 50
68+
select x in ($zeroes_50) where (x == 1) {
69+
assert true;
70+
} else assert true;
71+
72+
73+
// WBIGUNROLL is only reported for compile-time lists defined via list
74+
// syntax, not the object lists generated by DMLC
75+
// no warning
76+
foreach x in ($b.unmapped_registers) assert true;
77+
select x in ($b.unmapped_registers) where (i == 0) {
78+
assert true;
79+
} else assert true;
80+
}

0 commit comments

Comments
 (0)