Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Test/Expect/cexec07.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3 3 3 5
48 changes: 48 additions & 0 deletions Test/cexec07.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// a counting loop whose limit changes inside it must read the limit on
// every pass (flexprop issue 119)
//
#include <stdio.h>
#include <propeller.h>

int gn = 5;
int gm = 5;

void myexit(int n)
{
putchar(0xff);
putchar(0x0);
putchar(n);
waitcnt(getcnt() + 40000000);
#ifdef __OUTPUT_BYTECODE__
_cogstop(_cogid());
#else
__asm {
cogid n
cogstop n
}
#endif
}

void lower(void) { gm = 3; }

void main() {
int c = 0, d = 0, e = 0, f = 0, i, n = 5, k = 5;
for (i = 0; i < n; i++) { // a local limit the body lowers
c++;
if (c == 2) n = 3;
}
for (i = 0; i < gn; i++) { // a global limit the body lowers
d++;
if (d == 2) gn = 3;
}
for (i = 0; i < gm; i++) { // a global limit a called function lowers
e++;
if (e == 2) lower();
}
for (i = 0; i < k; i++) { // a local limit the body leaves alone
f++;
}
printf("%d %d %d %d\n", c, d, e, f);
myexit(0);
}
37 changes: 37 additions & 0 deletions loops.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,39 @@ doHasBranch(AST *body, bool inCase)

static bool HasBranch(AST *body) { return doHasBranch(body, false); }

//
// true if the limit of a loop is the same on every pass: a constant, or a local
// whose address is not taken and which the body does not modify. The loop below
// is rewritten to count down from the limit read once, before the loop; a
// variable in memory may be changed by any function the body calls, or by
// another cog.
//
static bool
IsLoopInvariantLimit(AST *limit, AST *body)
{
Symbol *sym;

if (!limit) return false;
if (IsConstExpr(limit)) return true;
if (limit->kind == AST_OPERATOR && (limit->d.ival == '+' || limit->d.ival == '-')) {
return IsLoopInvariantLimit(limit->left, body) && IsLoopInvariantLimit(limit->right, body);
}
if (!IsIdentifier(limit)) return false;
sym = LookupAstSymbol(limit, NULL);
if (!sym) return false;
switch (sym->kind) {
case SYM_PARAMETER:
case SYM_RESULT:
case SYM_LOCALVAR:
case SYM_TEMPVAR:
if (curfunc->local_address_taken) return false;
if (limit->kind == AST_LOCAL_IDENTIFIER) limit = limit->left;
return !AstModifiesIdentifier(body, limit);
default:
return false;
}
}

//
// check for "simple" loops using increments (like "repeat i from 0 to 9") these may be further
// optimized into "repeat 10" if we discover that the loop index is not
Expand Down Expand Up @@ -1052,6 +1085,10 @@ CheckSimpleIncrementLoop(AST *stmt)
}
}

/* in C the limit is read on every pass; the rewritten loop reads it once */
if (IsCLang(curfunc->language) && !IsLoopInvariantLimit(updateLimit, body)) {
return;
}
/* check that the update is i++, and the variable is not used anywhere else */
while (update && update->kind == AST_SEQUENCE) {
if (AstUsesName(update->right, updateVar)) {
Expand Down
Loading