I'd indeed start with "Engineering a Compiler" by Keith Cooper and Linda Torczon. I also like "Modern Compiler Design" by Dick Grune, Kees van Reeuwijk, Henri E. Bal, Ceriel J.H. Jacobs, and Koen G. Langendoen (https://dickgrune.com/Books/MCD_2nd_Edition/). Some chapters are better in one than the other, so you may read some of both to see if you like another explanation.
For more on the analysis & compiler optimization side, "SSA-based Compiler Design" (http://ssabook.gforge.inria.fr/latest/; GitHub Mirror: https://github.com/pfalcon/ssabook) is a good follow-up.
Further readings: Book recommendations in https://github.com/MattPD/cpplinks/blob/master/compilers.md#books as well as program analysis resources (in particular lattice theory, type systems and programming languages theory, related notation): https://gist.github.com/MattPD/00573ee14bf85ccac6bed3c0678ddbef#program-analysis-resources
The CS 6120 course (see below)
blog is a great resource for writeups on techniques and papers:
https://www.cs.cornell.edu/courses/cs6120/2020fa/blog/
I can recommend the following: https://github.com/MattPD/cpplinks/blob/master/compilers.md#courses
Particularly (in alphabetical order--I think these are all great, so including highlights of what I've liked about them):
Cornell CS 6120: Advanced Compilers - The Self-Guided Online Course - Adrian Sampson (great lecturer, interesting selection of topics--including LLVM, dynamic compilers, and program synthesis--not frequently seen together in a single course)
IU P423/P523: Compilers (Programming Language Implementation) - Jeremy Siek, with the course book "Essentials of Compilation: An Incremental Approach" (pretty interesting approach, with programming language features developed incrementally having a fully working compiler at each step, cf. http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf; implementation language Racket),
KAIST CS420: Compiler Design - Jeehoon Kang (good modern treatment of SSA representation itself, including the use of block arguments, https://mlir.llvm.org/docs/Rationale/Rationale/#block-arguments-vs-phi-nodes, as well as SSA-based analysis and optimization; Rust as an implementation language),
UFMG DCC888: Static Program Analysis - Fernando Magno Quintão Pereira (a more advanced course particularly relevant for the middle-end optimizations as well select backend topics: really good SSA coverage--the lecturer has done some great research in this area--and even includes modern topics relevant for SIMD optimizations or GPU compilers like divergence analysis)
UCSD CSE 131: Compiler Construction - Joseph Gibbs Politz, Ranjit Jhala (great lecturers, both Haskell and OCaml edition were interesting; fun extra: one of the Fall 2019 lectures (11/26) has an interesting discussion of the trade-offs between traditional OOP and FP compiler implementation),
UCSD CSE 231: Advanced Compiler Design - Sorin Lerner (after UCSD CSE 131: for more on analysis & optimization--data flow analysis, lattice theory, SSA, optimization; fun extra: the final Winter 2018 lecture highlighted one of my favorite papers, https://pldi15.sigplan.org/details/pldi2015-papers/31/Provably-Correct-Peephole-Optimizations-with-Alive),
UW CSE CSEP 501: Compilers - Hal Perkins (nice balanced introduction, including x86-64 assembly code generation, with the aforementioned "Engineering a Compiler" used as the course textbook).
you can also check https://www3.nd.edu/~dthain/compilerbook/ for quick overview all the topics you mentioned.
Also Check:
Stanford course on compilers by Alex Klein
https://archive.org/details/academictorrents_e31e54905c7b2669c81fe164de2859be4697013a
https://www.amazon.com/Engineering-Compiler-Keith-Cooper/dp/155860698X
very approachable Crafting Interpreters book.
I also recommend the "Dragon Book", which is pretty much the textbook on compiler design. Reading this book was absolutely eye-opening, because it presents a bunch of very basic and general information that everybody in language design just assumes you know.
’ll suggest my 3-part tutorial that I wrote for my students. They’ve said they go through it in a single day and have a working compiler at the end that they know enough about to extend with other features. I think it’s a good starting point before committing to a long tutorial or textbook.
LLVM is not exactly simple or good as a starting point for learning about compilers.
“Kaleidoscope: Implementing a Language with LLVM” https://llvm.org/docs/tutorial/
'm surprised nobody has mentioned "make-a-lisp/MAL": https://github.com/kanaka/mal
I would recommend that as a good source of getting into lisp compilers, then reading the nanopass papers, looking at the Indiana University compiler class, then even reading the Chez Scheme source code. It's not too bad once you get used to it.
A Retargetable C Compiler, Design and Implementation: https://www.amazon.com/Retargetable-Compiler-Design-Implementation/dp/0805316701
Writing Compilers and Interpreters : https://www.amazon.com/Writing-Compilers-Interpreters-Software-Engineering-ebook/dp/B004S82O40
Writing A Compiler In Go: https://www.amazon.com/Writing-Compiler-Go-Thorsten-Ball/dp/398201610X, comparable to https://craftinginterpreters.com/contents.html
Compiler Construction
(free): https://people.inf.ethz.ch/wirth/CompilerConstruction/CompilerConstruction1.pdf
Here is the link: https://craftinginterpreters.com/contents.html. It's more about interpreters and virtual machines, not compilers (i.e. a lot of important compiler topics are missing)