Bug Description
GlobalCopyPropagation incorrectly preserves stale constant values for variables that are subsequently modified through method calls.
When a variable is initialized with a constant and later passed as an out/inout argument to a method, the GlobalCopyPropagation pass may fail to invalidate the variable's tracked value. As a result, the optimizer can incorrectly replace the variable with its previous constant value.
For example:
bit<32> temp = 100;
m.mutate(temp);
where mutate is declared as:
void mutate(out bit<32> val);
The optimizer may transform the call into:
This is incorrect because an out argument must remain a writable lvalue.
The issue also affects member method calls such as register reads. For example:
meta.val = 10;
my_reg.read(meta.val, 0);
After the register read, meta.val no longer has the compile-time value 10. However, GlobalCopyPropagation can continue treating it as 10 and propagate the stale constant into subsequent code.
Root Cause
There are two main problems in midend/global_copyprop.cpp:
-
checkParametersForMap() uses the callee's formal parameter name instead of resolving the actual argument passed at the call site. Therefore, caller variables used as out/inout arguments are not removed from the constant-value map.
-
MethodCallExpression handling skips member methods because of the IR::Member early return. Consequently, calls such as register.read() are not considered when invalidating tracked variable values.
Impact
This can result in:
- Valid P4 programs being rejected with a type-checking error such as:
Read-only value used for out/inout parameter.
- More seriously, stale constants being propagated after a method has modified a variable, potentially resulting in incorrect generated data-plane behavior.
This is therefore a compiler correctness bug in the GlobalCopyPropagation optimization pass.
Reproduction
A minimal example is:
extern Mutator {
Mutator();
void mutate(out bit<32> val);
}
control c() {
Mutator() m;
apply {
bit<32> temp = 100;
m.mutate(temp);
}
}
Before the fix, GlobalCopyPropagation can incorrectly rewrite:
to:
which is subsequently rejected by type checking.
Expected Behavior
GlobalCopyPropagation should invalidate the tracked value of any variable passed to an out or inout parameter and must not replace such writable arguments with constants.
Member methods that modify or produce values for variables should likewise invalidate the corresponding tracked values.
Bug Description
GlobalCopyPropagationincorrectly preserves stale constant values for variables that are subsequently modified through method calls.When a variable is initialized with a constant and later passed as an
out/inoutargument to a method, theGlobalCopyPropagationpass may fail to invalidate the variable's tracked value. As a result, the optimizer can incorrectly replace the variable with its previous constant value.For example:
where
mutateis declared as:The optimizer may transform the call into:
This is incorrect because an
outargument must remain a writable lvalue.The issue also affects member method calls such as register reads. For example:
After the register read,
meta.valno longer has the compile-time value10. However,GlobalCopyPropagationcan continue treating it as10and propagate the stale constant into subsequent code.Root Cause
There are two main problems in
midend/global_copyprop.cpp:checkParametersForMap()uses the callee's formal parameter name instead of resolving the actual argument passed at the call site. Therefore, caller variables used asout/inoutarguments are not removed from the constant-value map.MethodCallExpressionhandling skips member methods because of theIR::Memberearly return. Consequently, calls such asregister.read()are not considered when invalidating tracked variable values.Impact
This can result in:
Read-only value used for out/inout parameter.This is therefore a compiler correctness bug in the
GlobalCopyPropagationoptimization pass.Reproduction
A minimal example is:
Before the fix,
GlobalCopyPropagationcan incorrectly rewrite:to:
which is subsequently rejected by type checking.
Expected Behavior
GlobalCopyPropagationshould invalidate the tracked value of any variable passed to anoutorinoutparameter and must not replace such writable arguments with constants.Member methods that modify or produce values for variables should likewise invalidate the corresponding tracked values.