All processors operate on bits, we call that machine code, and it can take on very different flavors for different reasons, building a better mouse trap to patents protecting ideas. Every processor uses some flavor of machine code from a users perspective and some internally convert that to microcode, another machine code, and others dont. When you hear x86 vs arm vs mips vs power pc, that is not just company names but they also have their own instruction sets, machine code, for their respective processors. x86 instruction sets although evolving still resemble their history and you can easily pick out x86 code from others. And that is true for all of the companies, you can see the mips legacy in mips and arm in arm, and so on.
So to run a program on a processor at some point it has to be converted into the machine code for that processor and then the processor can handle it. Various languages and tools do it various ways. It is not required for a compiler to compile from the high level language to assembly language, but it is convenient. First off you basically will need an assembler for that processor anyway so the tool is there. Second can be much easier to debug the compiler by looking at human readable assembly language rather than the bits and bytes of machine code. Some compilers like JAVA, python, the old pascal compilers have a universal machine code (each language has its own different one), universal in the sense that java on an x86 and java on an arm do the same thing to that point, then there is a target specific (x86, arm, mips) interpreter that decodes the universal bytecode and executes it on the native processor. But ultimately it has to be the machine code for the processor it is running on.
There is also some history with this method of these compiling layers, I would argue that it is the somewhat unix building block approach, make one block do the front end and another block the backend and output asm and then the asm to object is its own tool and object linked with others is its own tool. Each block can be contained and developed with controlled inputs and outputs, and at times substituted with another block that fits in the same place. Compiler classes teach this model so you will see that replicated with new compilers and new languages. parse the front end, the text of the high level language. Into an intermediate, compiler specific binary code, then on the backend take that internal code and turn it into assembly for the target processor, allowing for example with gcc and many others to change that backend so the front and middle can be reused for different targets. Then separately have an assembler, and also a separate linker, separate tools in their own right.
People keep trying to re-invent the keyboard and mouse, but folks are comfortable enough with the old way that they stick with it even if the new invention is much better. Same is true with compilers and operating systems, and so many other things, we go with what we know and with compilers they often compile to assembly languge.