Change gtExtractSideEffList to use GenTreeVisitor (#18257)
* Change gtExtractSideEffList to use GenTreeVisitor
The tree traversal logic in gtExtractSideEffList is basically an incomplete duplicate of GenTreeVisitor's traversal logic. It lacks handling for GT_ARR_ELEM and GT_ARR_OFFSET so if this are encountered any side effects their children may have are silently dropped.
In addition, side effect ordering was not always preserved. The comma list is built by prepending nodes to it so side effects have to be visited in reverse execution order. The old code did this only for simple opers, for special nodes such as GT_ARR_BOUNDS_CHECK normal execution order was used.
This actually complicates a bit the GenTreeVisitor implementation as side effects need to be first stored in an array. The number of side effects is usually small (<= 4) so this shouldn't be a problem.
* Use GTF_SIDE_EFFECT in optPrepareTreeForReplacement
Assertion propagation doesn't have any way to ensure that it is safe to remove class constructor calls so GTF_PERSISTENT_SIDE_EFFECTS_IN_CSE should not be used here.
Likewise, GTF_EXCEPT side effects must be preserved as well. VN doesn't always propagate exceptions so it's possible to end up with a tree that has a constant VN and contains exception side effects.
* Add tests for 18232
* CR feedback