Refactor OptimizeInstructions to use visit* methods. NFC (#3678)
Refactor OptimizeInstructions to use visit* methods. NFC (#3678)

Instead of a single big optimize() method we now use separate functions
per instruction. This gives us smaller functions and less nesting in some cases,
and avoids manually casting and checking etc.

The reason this was not done originally is that this pass does repeated
applications. That is, if optimize() changed something, it would run again
on the result, perhaps further optimizing it. It did not need to run on the
children, but just on the result itself, so it didn't just do another full walk,
and so the simplest way was to just do a loop on optimize(). To replace that,
this PR modifies replaceCurrent() which the methods now call to report
that the current node can be replaced. There is some code in there now that
keeps doing more processing while changes happen. It's not trivial code as
it avoids recursion, but that slight complexity seems worthwhile in order to
simplify the bulk of the (very large) pass.
WebAssembly/binaryen,WebAssembly/binaryen,WebAssembly/binaryen,WebAssembly/binaryen,WebAssembly/binaryen