O LLVM é de nível inferior ao das VMs típicas, como JVM e CLR. Por exemplo, embora tenha ganchos para um coletor de lixo, ele não fornece um coletor de lixo propriamente dito.
Da mesma forma, a JVM possui um compilador JIT integrado (exceto em versões realmente antigas). O LLVM possui alguns compiladores JIT para o LLVM IR, mas ainda cabe ao desenvolvedor juntar as coisas e, na verdade, JIT o código.
Quando a JVM encontra um externo não resolvido, sai e encontra a classe certa para satisfazê-lo, e sabe procurar arquivos .class diretamente no sistema de arquivos e nos arquivos .jar 1 . Os compiladores JIT do LLVM têm ganchos onde você pode decidir como essas coisas são tratadas. Como seria de esperar, algumas pessoas escreveram algumas versões padrão, para que ele possa fazer as coisas aproximadamente na mesma ordem que a JVM - mas você também pode ignorá-las e fazer as coisas de maneira diferente, se quiser.
Simplificando, se você estiver desenvolvendo um compilador (ou algo nessa ordem), ele possui muitas ferramentas para facilitar sua vida. Em vez de se preocupar muito com a otimização, você pode fazer praticamente a tradução mais simples que pode gerenciar do código-fonte para o LLVM IR e, em seguida, usar as bibliotecas do LLVM para gerenciar a otimização, JITing, vinculação etc. Mesmo assim, são bibliotecas - fornece algumas funções realmente úteis para que você não precise lidar com todos os detalhes, mas elas ainda funcionam e você ainda está escrevendo código para invocá-las. Não é um produto acabado, apenas ferramentas úteis para criar produtos de forma relativamente rápida e fácil.
1 Tecnicamente, nem tudo isso é incorporado à JVM. Ele especifica o que geralmente é chamado de carregador de classe primordial como parte da JVM adequada e, em seguida, há carregadores de classe de usuário especificados em java.util.ClassLoader que tratam de outras coisas. Alguns carregadores de classes são incluídos por padrão e, se você desejar o suficiente, poderá complementá-los definindo seus próprios.