he specializations and note in the general-purpose routine that code has been copied. Otherwise, you may find that you have copied a bug to multiple places, but fixed it only once.
Inline functions may help here. If you can put some or all of the copied code into inline functions, you can fix any bugs once and have them propagate to all of the specializations automatically without any function call overhead.
Complex code is harder to test as well. It is crucial that you specialize code only after it is working properly, to ensure that the new faster code gets the right results. Use white box directed tests to exercise each specialized routine, or at the very least compare the final outputs vs. an application-level golden output.
Not all programs can be improved by pattern matching and specialization. You may find that the code required to detect common patterns is slower (or, for memory consumption, uses no less memory) than the code it means to replace, or that the specialized versions of routines are no simpler than the original. In that case, optimization by code rewriting or data caching may be more appropriate.
Many problem domains, however, have highly variable inputs with unique processing requirements, and these often benefit greatly from pattern matching. It's a valuable skill for your programming toolbox.