Compiler isn't really difficult in the way that many think it is, because it really isn't that difficult to write a basic C compiler for example, and writing a parser is pretty mechanical that there are a multitude of parser generators. The difficult part is that writing an optimized compiler is much more difficult than writing a correct compiler, and certain language features, like generics, closure, and async, propagates and touch every part of the language that the complexity grows exponentially, and it's really hard to balance performance, compile speed, and correctness against miscompiles.
You can kinda see that in the many "compile TypeScript to native via LLVM" projects that showed up a lot recently. From my testing, none of them could beat V8/Node JIT in the majority of cases, and most of them are generally 10x-40x slower.
But, we did have a great number of innovations in language design over the last decades that really closes the gap on how optimized a compiler can be over writing assembly directly: Rust's exhaustive match default null-less error handling and language level MIR, immutable data structures from functional languages to mainstream ones, TypeScript's compile time constraints as core part of the language, and Zig's `comptime` turning compile time metaprogramming to an integrated part of the language instead of C++ template metaprogramming.
Obviously, it's not really possible to beat hand optimized C/C++ or directly authored assembly, but I think a well-designed compiler/language can potentially beat idiomatic C/C++ in performance.
And this is speaking as someone who learned compiler design solely from having every one of his vibe-coded projects turn into either a compiler or a kernel for some reason.