It's not so much that their C compiler wasn't efficient enough, but in crucial places you need to transition from the CPU itself doing something to getting into some C code. The PDP11 interupt handler can't jump into a C routine, it simply sets the program counter to a specified value and starts executing machine code. There needs to be machine code at that location to set the machine state into a state where it can hand on into a C routine.
And then there's things like reading user space when executing in the kernel - that has to be done in machine code as it's machine level functionality.
I downloaded the disk image and SIMH ini files, and it booted first time. I was even more impressed that my code that runs happily in UnixV5 also ran first time:
link.
From testing, the only thing I've found a problem with is exec() calling /bin/sh to "shell out" to run a command. There's some difference from v5+ that I haven't worked out yet. With v5 and later you do exec("/bin/sh",("sh","-c","command line to run",0)) but on v4 that gives me: -c: cannot open.
