Depending on how you look at it, this issue boils down to the same as #1670.
Take the given C function:
int getValue(int *array) {
int i = 0;
while (i < 10) {
if (array[i]) {
return array[i];
}
i++;
}
return 0;
}
When looking at the C source code, or a control flow graph, it is very clear that the second load of array[i] is dominated by the first load of array[i]. However, in the RVSDG, the second load is located in a gamma node outside of the theta. Since this theta contains a return statement, it has multiple exit paths. Each exit path sends a different predicate constant to this gamma. From a design perspective it makes sense to place exit branches outside of the theta, keeping the theta lean and easier to loop analyze.
Having one load inside the theta and the other load inside one of the exit gamma regions (region 7), is preventing load forwarding, however.
If the tracer was more clever, it could somehow trace the memory state directly from the region 7 argument into the region 4 result.
The RVSDG graph is shown here:

Depending on how you look at it, this issue boils down to the same as #1670.
Take the given C function:
When looking at the C source code, or a control flow graph, it is very clear that the second load of
array[i]is dominated by the first load ofarray[i]. However, in the RVSDG, the second load is located in a gamma node outside of the theta. Since this theta contains areturnstatement, it has multiple exit paths. Each exit path sends a different predicate constant to this gamma. From a design perspective it makes sense to place exit branches outside of the theta, keeping the theta lean and easier to loop analyze.Having one load inside the theta and the other load inside one of the exit gamma regions (region 7), is preventing load forwarding, however.
If the tracer was more clever, it could somehow trace the memory state directly from the region 7 argument into the region 4 result.
The RVSDG graph is shown here:
