Depends. Do you intend to keep maintaining the generated source code, or not?
If you do, you might run into some problems:
Many optimizations can make source less readable. For example, optimizations on loops, like loop fission, loop fusion, loop inversion, loop interchange, loop reversal, loop unrolling (yes, I'm just going through the list of optimizations article on Wikipedia), etc.
Also, optimizations that need to first desugar language-level constructs can be represented back in source code, but if the result cannot be "re-sugared", it will increase verbosity a lot.
- Correctness after further changes to the optimized source
Some optimizations are only valid depending on subtle preconditions in your program, that the compiler was able to prove. Representing the result of those optimizations back in source code does not document the information that these preconditions exist.
If you try to modify the optimized generated code even just a little, by say modifying the value a constant, then maybe now the code does something wildly different and unexpected, because the optimized code has been specialized for the previous value of that constant.
The fact that compilers work only one way on a given program was a guarantee that all those readability-destroying optimizations were safe to perform. Not true anymore if you want to generate maintainable source code.
Ad even if you don't intend to keep maintaining the generated source code, having to preserve source code as a target will severely limit the kind of optimizations that you can do.
When working on data of any kind, its representation matters a lot, and compilers are no exception. They represent programs in various ways, with sometimes multiple levels of Intermediate Representations that can be the place of choice for optimizations.
For example, most optimizations that operate on machine code cannot be represented back in source code form. Anything that operates on assembly instructions or registers will just not be available to a source-to-source optimizer.
All that being said, there is a greater than zero number of optimizations that you could do:
Some transformations that are high-level enough, like common sub-expression elimination, constant folding and constant propagation, and some source-level inlining... (With the big above caveat about readability and brittleness of correctness w.r.t. change!)
And maybe even higher-level transformations that might be specific to your program, which you'll have to hardcode in your optimizing compiler...
But there are other, better ways of expressing those than writing a
source-to-source compiler. Some languages let you write macros, which
could play this role instead, while keeping your code more readable.