Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: for loops no longer execute once when condition is already met #1248

Merged
merged 10 commits into from
Jun 27, 2024

Conversation

mhasel
Copy link
Member

@mhasel mhasel commented Jun 17, 2024

This PR fixes for loops executing once when the predicate already should not be met for decrementing loops. I have also re-implemented the codegen logic for for-loops, resulting in fewer branches and hopefully more readable IR.

Resolves #1207

@mhasel mhasel force-pushed the for-loops branch 2 times, most recently from 9c26969 to af55a2d Compare June 17, 2024 12:28
This PR fixes for loops executing once when the predicate already should not be met for decrementing loops.
I have also re-implemented the codegen logic for for-loops, resulting in fewer predecessors and hopefully more
readable IR.

Resolves #1207
@mhasel mhasel marked this pull request as ready for review June 18, 2024 14:34
@mhasel mhasel changed the title fix: for loop predicate fix: for loops no longer execute once when condition is already met Jun 18, 2024
@mhasel mhasel requested review from riederm, ghaith and volsa June 18, 2024 14:54
volsa
volsa previously approved these changes Jun 20, 2024
Copy link
Member

@volsa volsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very sexy! I just have some nits, but as always feel free to ignore them if you don't agree :)

src/codegen/generators/statement_generator.rs Outdated Show resolved Hide resolved
src/codegen/generators/statement_generator.rs Outdated Show resolved Hide resolved
src/codegen/generators/statement_generator.rs Show resolved Hide resolved
Comment on lines +543 to +559
FUNCTION main : DINT
VAR
i, step, temp, iteration: DINT;
END_VAR
step := 1;
iteration := 0;

FOR i := 3 TO 10 BY step DO
step := (step + 1) * -2;

// i: 3, -1, 5, -9, 17
// step: -4, 5, -14, 26
iteration := iteration + 1;
END_FOR

main := iteration;
END_FUNCTION
Copy link
Member Author

@mhasel mhasel Jun 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added two tests with edge cases, were the STEP variable changes signage in the loop body. Do we expect the loop to continue until COUNTER >= END if the loop is determined as incrementing (current behaviour)?
Should we also exit the loop if COUNTER <= START for initially incrementing loops (in which case we'd only expect 1 iteration in the test above)?
Instead of determining if the loop is incrementing/decrementing via the STEP value, should we instead check if START > END and vice versa? i.e.:
incrementing

IF start < end AND counter <= end THEN loop

and decrementing

IF start > end AND counter >= end THEN loop

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I would just mimic what the C language would do in these edge-cases; I suspect it will just check for the condition COUNTER >= END and only stop if it becomes true

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of interest, what is codesys doing in these cases? is the step by constant? It might be that we always have to invert the check based on the sign.
C has the exit condition defined in the for loop, so it's not the same case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, mimicking C is not an ideal solution here unfortunately. I have already tried changing the predicate dynamically based on the sign. This results in most loops executing once, e.g.:

FOR i := 0 TO 10 BY x DO
    invert x and check

If x starts out as let's say 2, upon second iteration the check will be IF 2 >= 10. The exception here is if step is larger than the absolute difference between start and end.
I think checking codesys behaviour is the way to go here, too.
Is this a blocker for this story? I don't think this was accounted for previously and might be out of scope for this bug fix. I'd suggest tracking it separately. @ghaith @volsa thoughts?

@mhasel mhasel merged commit ef09b87 into master Jun 27, 2024
19 checks passed
@mhasel mhasel deleted the for-loops branch June 27, 2024 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

for loop executes once when condition is already met
3 participants