The following shows all the major steps associated with the compilation of any given langauge.
IRs allow for massive abstractions such as, they allow you to pipeline your code to any already present IR and you then no need to worry about further implementations! Code Gen, for example IR \to Machine Code, will not be required to be handled by you, since it shall already exist.
Bytecode always requires a VM to work upon.
Optimizing compilers is a deep deep trench. Many people are found lost in there.
As a theorist, you may hate OOPs but guess what, unlike Haskell, they are useful! Yay! (I love Haskell, don't kill me).
Compilers v/s Interpreters
Compilers convert your source code to another language without executing. Now this new language may or may not low-level language like Machine Code.
Interpreters, on the other hand, take in source code and executes it immediately.
LLVM and why do I care?
"A compiler infrastructure is useful whenever you need to do stuff with programs."
We are interested in reasoning about programs.
Understand compilation and related techniques.
Requirement of architecture simulation.
Automated Verification (✓) and Theorem Proving (‽).
Understanding LLVM IR
Modules contain Functions, which contain BasicBlocks, which contain Instructions.
Everything but Module descends from Value.
A basic block is a straight-line code sequence with no branches in except to the entry and no branches out except at the exit — which makes it easy to analyze.
As seen above the passes are where we optimize a current IR at hand.
We mostly do not have to care about Front End (parsing and analysis) and Back End (code generation). For most cases, we shall be mostly concerned about the Middle End with optimizations and writing passes.