LLVM is widely used for compilers (rustc, Swift, Kitten), particularly in tutorials (kaleidoscope), but it need not be a default.

All Relevant Algorithms are Well-Established

Algorithms for compiler backends are written in textbooks and are correct.

Understanding such foundations inoculates against foolishness - with register targeting, one sees that recursive function calls in (say) Standard ML are exactly as efficient as for loops in a language with mutable variables.

Eijiro Sumii:

Nowadays, there are a number of programmers who learn ML, but they often think “I will not use it since I do not understand how it works.” Or, even worse, many of them make incorrect assumptions based on arbitrary misunderstanding about implementation methods.

Compiler Backend Examples

Many compilers have their own code generators, for instance SMLNJ, GHC, Steel Bank Common Lisp, ocamlopt.

Adding support for a new architecture was 5000 lines in GHC.

LLVM is Not a Get-Out-Of-Jail-Free Card

To use my own kempe project as an example, compile times went from 18.7s to 36.2s when switching from GHC's NCG to its LLVM backend - i.e. twice as long.

Performance on benchmarks was slightly worse when compiled via LLVM.

Putatively GHC's implementation of laziness confounds LLVM optimizations, but in any case, one cannot simply bolt a LLVM backend on to any compiler and expect it to work. This surely falls short of the promise of a general-purpose compiler backend.

Performance

LLVM has been removed from compilers due to performance

LLVM is Buggy

This has hobbled Rust, for instance; its attempts to use noalias have uncovered several bugs over the past 6 years:

LLVM is honed on Clang; in fact it is limited as a general-purpose compiler backend.

Conclusion

LLVM need not be used in compilers, particularly hobby compilers.