Overview
Array constraint handling addresses how reads and writes to arrays are represented in a constraint store. The motivating problem is that an array update can affect the value seen by later reads, especially when two array indices may alias, i.e. refer to the same element.
The cited work contrasts a direct element-wise translation with specialized array-handling strategies. In an SSA-like construction, each assignment to one element of an array of size n introduces 2n - 1 element constraints: two constraints for each of the n - 1 elements not assigned, plus one for the assigned element. For a memory addressed by 24-bit index registers, this leads to a very large number of constraints and is described as impractical in the ST processor setting.
Solver-level read and write constraints
One proposed strategy is to introduce an array type directly in the solver, together with two constraints for array access:
tabRead, for read access to array elements;tabWrite, for write access to array elements.
These constraints are responsible for maintaining consistency between index relationships and value relationships. The paper describes propagation in both directions, from equal indices to equal array values and from equal array values to index equality:
i = j => T[i] = T[j]
T[i] = T[j] => i = j
For example, in a sequence that reads mem[X], writes mem[Y] = 2, and then reads mem[X] again, if Y is equal to X, the second read of mem[X] must reflect the write. This requires two tabRead constraints and one tabWrite constraint in the store.
The drawback of this direct solver-level approach is order dependence: the order of accesses in the original code must be preserved, which conflicts with the usual order-independent nature of constraint solving. The paper also notes that static dependency analysis is limited because index relationships are only known dynamically.
Alias-based two-step strategy
The alternative strategy separates array manipulation into two steps:
- fix equality or inequality relationships between indices; then
- post constraints that enforce the chosen relationships.
In the example with three array accesses, the relevant question is which accesses alias the same memory location. The number of possible equality relationships among n indices is the number of partitions of an n-element set, i.e. the nth Bell number. Although Bell numbers grow exponentially, the cited work argues that this is acceptable in context because the solver searches for only a correct combination of index relationships.
This strategy enables an alias coverage criterion, which can estimate how well the different choices of index relationships have been covered. The paper specifically motivates this criterion with self-referential memory expressions such as mem[mem[i]] when mem[i] = i.
Benefits and limitations
The alias-based approach has two stated advantages:
- variable independence can be analyzed so that the constraint store can be split into independent groups of variables;
- graph analysis can be used to infer heuristics for variable ordering, improving solving performance.
Its main drawback is that a chosen set of index relationships may be inconsistent with other constraints already in the store. The cited work relies on the constraint solver's backtracking mechanism to recover from such failures, and notes that symbolic solving can avoid inconsistent choices in many cases.