Como desenvolver um novo back-end para XLA

Este guia é destinado a engenheiros de sistema que querem que o XLA gere programas destinados ao hardware de forma eficiente. O guia não é detalhado e pressupõe conhecimento de LLVM, Bazel e XLA.

O XLA fornece uma interface abstrata que uma nova arquitetura ou acelerador pode implementar para criar um back-end e executar a saída de programas de ML pelo XLA. A nova segmentação de XLA precisa ser significativamente mais simples e escalonável do que a implementação de todas as operações existentes de um framework de front-end, como PyTorch ou TensorFlow, para um novo hardware.

A maioria das implementações se enquadra em um dos seguintes cenários:

  1. Arquitetura de CPU existente que ainda não é oficialmente aceita pelo XLA, com ou sem um back-end do LLVM.
  2. Hardware que não é semelhante à CPU com um back-end LLVM já existente.
  3. Hardware semelhante a uma CPU sem um back-end LLVM já existente.

Cenário 1: a arquitetura de CPU existente ainda não é oficialmente compatível com XLA

Neste cenário, comece analisando o back-end da CPU do XLA. O XLA facilita o direcionamento a diferentes CPUs usando o LLVM, porque a principal diferença entre back-ends do XLA para CPUs é o código gerado pelo LLVM.

Se o fornecedor de hardware tiver um back-end de LLVM para o hardware, será simples vincular o back-end ao LLVM criado com XLA. No modo JIT, o back-end da CPU do XLA emite código para a CPU do host. Para compilação antecipada, o xla::AotCompilationOptions pode fornecer um triplo LLVM para configurar a arquitetura de destino.

Se não houver um back-end do LLVM, mas houver outro tipo de gerador de código, será possível reutilizar a maior parte do back-end de CPU existente.

Cenário 2: hardware que não é semelhante à CPU com um back-end LLVM já existente

É possível modelar uma nova implementação xla::Compiler nas classes xla::CPUCompiler e xla::GPUCompiler, já que elas já emitem IR LLVM. Dependendo da natureza do hardware, é possível que muitos aspectos da geração de IR do LLVM precisem ser alterados, mas muito código pode ser compartilhado com os back-ends atuais.

Um bom exemplo a seguir é o back-end de GPU do XLA. O back-end da GPU tem como alvo uma ISA que não é semelhante à CPU e, portanto, alguns aspectos da geração de código são exclusivos do domínio da GPU. Outros tipos de hardware, por exemplo, DSPs como o Hexagon (que tem um back-end LLVM upstream), podem reutilizar partes da lógica de emissão de IR do LLVM, mas outras partes serão exclusivas.

Cenário 3: hardware que não é semelhante à CPU e sem um back-end LLVM

Se não for possível usar o LLVM, a melhor opção é implementar um novo back-end para XLA para o hardware em questão. Essa opção exige o maior esforço. As classes que precisam ser implementadas são as seguintes:

  • StreamExecutor: para muitos dispositivos, nem todos os métodos de StreamExecutor são necessários. Consulte as implementações de StreamExecutor atuais para mais detalhes.
  • xla::Compiler: essa classe encapsula a compilação de um cálculo de HLO em um xla::Executable.
  • xla::Executable: essa classe é usada para iniciar um cálculo compilado na plataforma.
  • xla::TransferManager: essa classe permite que os back-ends forneçam mecanismos específicos da plataforma para construir dados literais do XLA a partir de determinados identificadores de memória do dispositivo. Em outras palavras, ele ajuda a encapsular a transferência de dados do host para o dispositivo e de volta.