-chlo-legalize-to-stablehlo
Legaliza o fluxo de operações CHLO para StableHLO e operações de forma
-shape-legalize-to-stablehlo
Legalize operações relacionadas a formas para StableHLO.
Uma transmissão experimental que legaliza operações relacionadas a formas para operações do StableHLO.
Unir cálculos de forma e dados usando uma transmissão opcional vai permitir que o ecossistema StableHLO aproveite os pipelines de compilação que usam operações StableHLO para modelar o dinamismo.
-stablehlo-canonicalize-dynamism
Transforma operações dinâmicas do StableHLO em operações estáticas.
Substitui operações dinâmicas do StableHLO, como DynamicReshapeOp, pelas equivalentes estáticas correspondentes, como DynamicReshapeOp para ReshapeOp ou DynamicBroadcastInDim para BroadcastInDim, se todos os elementos dinâmicos dessas operações forem constantes.
%c = stablehlo.constant dense<16> : tensor<1xi32>
%0 = stablehlo.dynamic_broadcast_in_dim %cst, %c, dims = [] : (tensor<f32>, tensor<1xi32>) -> tensor<16xf32>
==>
%0 = stablehlo.broadcast_in_dim %cst, dims = [] : (tensor<f32>) -> tensor<16xf32>
-stablehlo-check-shape-assertions
_Verifique stablehlo.custom_call @shapeassertion ops.
Valide chamadas personalizadas de shape_assertion.
As declarações de forma validam restrições em dimensões dinâmicas no StableHLO.
Por exemplo, se uma estrutura precisasse aplicar uma restrição de DimA < 2,
a seguinte IR poderia ser emitida:
%dimA = <get_dimension_size or input arg> : tensor<i32>
%c2 = stablehlo.constant dense<2> : tensor<i32>
%is_lt = stablehlo.compare LT %dimA, %c2 : tensor<i1>
stablehlo.custom_call @shape_assertion(%is_lt) { error_message = "DimA must be less than 2" }
Depois da transmissão, se as formas estiverem corretas, o stablehlo.custom_call será removido.
Opções
-enable-shape-assertions : Whether shape assertions may generate errors.
-stablehlo-compatibility-expander
Expansor de compatibilidade para operações StableHLO.
As operações do StableHLO recebem atualizações ou uma nova operação é introduzida nas versões mais recentes. Essa transmissão de ativação expande a compatibilidade com versões anteriores do StableHLO ao decompor operações mais recentes do StableHLO em operações equivalentes compatíveis com essas versões mais antigas.
Por que esse é um passe opcional?
Ocasionalmente, melhorias na operação StableHLO são usadas para simplificar muito o processamento de determinados padrões comuns no ecossistema OpenXLA. Isso inclui coisas como TanOp, que tem suporte alto para framework e compilador, além de dimensões de lote de coleta/dispersão, que podem ser representadas usando slices, mas dificultam muito o sharding. Para essa categoria de novos recursos, não oferecemos downgrade automático, já que isso pode descartar informações importantes usadas em otimizações subsequentes. Essa transmissão pode ser usada para expandir essas operações com base em uma versão de destino e maximizar a compatibilidade, mesmo que a compilação seja menos otimizada.
func.func @tan_op_non_complex(%arg0: tensor<4xf64>) -> tensor<4xf64> {
%1 = stablehlo.tan %arg0 : tensor<4xf64>
func.return %1 : tensor<4xf64>
}
==>
func.func @tan_op_non_complex(%arg0: tensor<4xf64>) -> tensor<4xf64> {
%0 = stablehlo.sine %arg0 : tensor<4xf64>
%1 = stablehlo.cosine %arg0 : tensor<4xf64>
%2 = stablehlo.divide %0, %1 : tensor<4xf64>
return %2 : tensor<4xf64>
}
Opções
-target : The target version. Must be a version of the form #.#.#.
-stablehlo-complex-math-expander
Expansor para operações matemáticas complexas do StableHLO.
As operações matemáticas complexas do StableHLO são decomposições que usam operações matemáticas reais do StableHLO.
Essa declaração se baseia na premissa de que não existe hardware que ofereça suporte nativo a números complexos nem operações matemáticas complexas. Isso significa que os mecanismos de substituição em operações matemáticas complexas que os compiladores podem implementar são redundantes. Ao ativar essa transmissão, todas as operações matemáticas complexas do StableHLO serão expandidas.
func.func @sqrt_op_complex(%arg0: tensor<4xcomplex<f64>>) -> tensor<4xcomplex<f64>> {
%1 = stablehlo.sqrt %arg0 : tensor<4xcomplex<f64>>
func.return %1 : tensor<4xcomplex<f64>>
}
==>
func.func @sqrt_op_complex(%arg0: tensor<4xcomplex<f64>>) -> tensor<4xcomplex<f64>> {
TBD
return %2 : tensor<4xcomplex<f64>>
}
-stablehlo-convert-to-signless
Transmita para transformar a representação intermediária em números inteiros sem sinal.
-stablehlo-legalize-composite-to-call
Substitui operações compostas por uma chamada à decomposição delas.
Substitui operações compostas por uma chamada à decomposição delas, por exemplo, o seguinte:
stablehlo.composite "my_namespace.my_op" %arg0, %arg1 {
decomposition = @bar,
version = 1,
composite_attributes = {
"my_attribute": "my_value"
}
}
Vai se tornar:
func.call @bar(%arg0, %arg1)
Um subconjunto de composições pode ser excluído dessa transformação usando a flag "except", por exemplo:
stablehlo-opt --stablehlo-legalize-composite-to-call=except='foo.baz,foo.qux'
Opções
-except : Names of composites that should not be replaced with calls.
-stablehlo-legalize-deprecated-ops
Legalize operações descontinuadas para operações bem aceitas.
A RFC de descontinuações do Opset do StableHLO v1.0 (#2283) propõe remover várias operações redundantes. Essa transmissão ajuda a avaliar o impacto dessas remoções de operações em vários pipelines de compilação, legalizando-as para as contrapartes com suporte de longo prazo.
Opções
-fail-on-unused : Fail on (mostly) unused ops that are deprecated without any fallback.
-stablehlo-legalize-qdq-to-quantized-op
Fundir o padrão (desquantização, operação de ponto flutuante e quantização) em uma operação quantizada do StableHLO
Fundir o padrão (desquantizar, operação de ponto flutuante e quantizar) em uma operação quantizada do StableHLO. Observação: a transmissão não exclui nenhuma operação preexistente. Por exemplo, o programa a seguir
func.func @add(%arg0: tensor<16x16x!quant.uniform<ui8:f32, 34.0:16>>) -> tensor<16x16x!quant.uniform<ui8:f32, 34.0:16>> {
%0 = stablehlo.uniform_dequantize %arg0 : (tensor<16x16x!quant.uniform<ui8:f32, 34.0:16>>) -> tensor<16x16xf32>
%1 = stablehlo.abs %0 : tensor<16x16xf32>
%2 = stablehlo.uniform_quantize %1 : (tensor<16x16xf32>) -> tensor<16x16x!quant.uniform<ui8:f32, 34.0:16>>
func.return %2 : tensor<16x16x!quant.uniform<ui8:f32, 34.0:16>>
}
Vai se tornar:
func.func @add(%arg0: tensor<16x16x!quant.uniform<u8:f32, 3.400000e+01:16>>) -> tensor<16x16x!quant.uniform<u8:f32, 3.400000e+01:16>> {
%0 = stablehlo.uniform_dequantize %arg0 : (tensor<16x16x!quant.uniform<u8:f32, 3.400000e+01:16>>) -> tensor<16x16xf32>
%1 = stablehlo.abs %0 : tensor<16x16xf32>
%2 = stablehlo.abs %arg0 : tensor<16x16x!quant.uniform<u8:f32, 3.400000e+01:16>>
%3 = stablehlo.uniform_quantize %1 : (tensor<16x16xf32>) -> tensor<16x16x!quant.uniform<u8:f32, 3.400000e+01:16>>
return %2 : tensor<16x16x!quant.uniform<u8:f32, 3.400000e+01:16>>
}
-stablehlo-legalize-quant-to-math
Converter operações quantizadas do StableHLO em operações matemáticas primitivas do StableHLO.
Converter programas StableHLO usando tipos UniformQuantized para operações matemáticas inteiras semanticamente equivalentes.
func.func @add(%arg0: tensor<!quant.uniform<i8:f32,1.0:0>>, %arg1: tensor<!quant.uniform<i8:f32,2.0:1>>) -> tensor<!quant.uniform<i8:f32,3.0:2>> {
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<!quant.uniform<i8:f32,1.0:0>>, tensor<!quant.uniform<i8:f32,2.0:1>>) -> tensor<!quant.uniform<i8:f32,3.0:2>>
func.return %0 : tensor<!quant.uniform<i8:f32,3.0:2>>
}
Vai se tornar:
func.func @add(%arg0: tensor<i8>, %arg1: tensor<i8>) -> tensor<i8> {
%0 = stablehlo.convert %arg0 : (tensor<i8>) -> tensor<f32>
%cst = stablehlo.constant dense<0.333333343> : tensor<f32>
%1 = chlo.broadcast_multiply %0, %cst : (tensor<f32>, tensor<f32>) -> tensor<f32>
%cst_0 = stablehlo.constant dense<2.000000e+00> : tensor<f32>
%2 = chlo.broadcast_add %1, %cst_0 : (tensor<f32>, tensor<f32>) -> tensor<f32>
%3 = stablehlo.round_nearest_even %2 : tensor<f32>
%4 = stablehlo.convert %3 : (tensor<f32>) -> tensor<i32>
%5 = stablehlo.convert %arg1 : (tensor<i8>) -> tensor<f32>
%cst_1 = stablehlo.constant dense<0.666666686> : tensor<f32>
%6 = chlo.broadcast_multiply %5, %cst_1 : (tensor<f32>, tensor<f32>) -> tensor<f32>
%cst_2 = stablehlo.constant dense<1.33333337> : tensor<f32>
%7 = chlo.broadcast_add %6, %cst_2 : (tensor<f32>, tensor<f32>) -> tensor<f32>
%8 = stablehlo.round_nearest_even %7 : tensor<f32>
%9 = stablehlo.convert %8 : (tensor<f32>) -> tensor<i32>
%c = stablehlo.constant dense<2> : tensor<i32>
%10 = chlo.broadcast_add %4, %9 : (tensor<i32>, tensor<i32>) -> tensor<i32>
%11 = chlo.broadcast_subtract %10, %c : (tensor<i32>, tensor<i32>) -> tensor<i32>
%c_3 = stablehlo.constant dense<-128> : tensor<i32>
%c_4 = stablehlo.constant dense<127> : tensor<i32>
%12 = stablehlo.clamp %c_3, %11, %c_4 : tensor<i32>
%13 = stablehlo.convert %12 : (tensor<i32>) -> tensor<i8>
return %13 : tensor<i8>
}
-stablehlo-legalize-quantized-op-to-qdq
Decomponha a operação quantizada do StableHLO no padrão (desquantização, operação de ponto flutuante e quantização).
Decomponha programas quantizados do StableHLO usando operações uniformes de quantização/desquantização. Por exemplo, o programa a seguir
func.func @add(%arg0: tensor<!quant.uniform<i8:f32,1.0:0>>, %arg1: tensor<!quant.uniform<i8:f32,2.0:1>>) -> tensor<!quant.uniform<i8:f32,3.0:2>> {
%0 = "stablehlo.add"(%arg0, %arg1) : (tensor<!quant.uniform<i8:f32,1.0:0>>, tensor<!quant.uniform<i8:f32,2.0:1>>) -> tensor<!quant.uniform<i8:f32,3.0:2>>
func.return %0 : tensor<!quant.uniform<i8:f32,3.0:2>>
}
Vai se tornar:
func.func @add(%arg0: tensor<!quant.uniform<i8:f32, 1.000000e+00>>, %arg1: tensor<!quant.uniform<i8:f32, 2.000000e+00:1>>) -> tensor<!quant.uniform<i8:f32, 3.000000e+00:2>> {
%0 = stablehlo.uniform_dequantize %arg0 : (tensor<!quant.uniform<i8:f32, 1.000000e+00>>) -> tensor<f32>
%1 = stablehlo.uniform_dequantize %arg1 : (tensor<!quant.uniform<i8:f32, 2.000000e+00:1>>) -> tensor<f32>
%2 = stablehlo.add %0, %1 : tensor<f32>
%3 = stablehlo.uniform_quantize %2 : (tensor<f32>) -> tensor<!quant.uniform<i8:f32, 3.000000e+00:2>>
return %3 : tensor<!quant.uniform<i8:f32, 3.000000e+00:2>>
}
-stablehlo-legalize-to-vhlo
Legalizar o StableHLO para VHLO.
Legalizar o StableHLO para a versão mais recente de operações em VHLO. Essas operações podem ser
rebaixadas para versões mais antigas do VHLO para compatibilidade futura usando
VhloToVersionPass.
stablehlo.exponential %[[ARG0]] <{result_accuracy = DEFAULT}> : tensor<f32>
# ====>
"vhlo.exponential_v2"(%[[ARG0]]) <{result_accuracy = #vhlo.DEFAULT_v1}> : !vhlo.tensor_v1<!vhlo.f32_v1>
Consulte vhlo.md > O dialeto VHLO para mais detalhes sobre como o VHLO é usado para preservar a compatibilidade com versões anteriores e futuras.
Opções
-allow-other-dialects : Allow serialization to use other (potentially unstable) dialects, inserts unrealized casts between dialects.
-stablehlo-refine-arguments
Refina as formas de argumento da função principal.
Modifica os argumentos da função principal usando a assinatura do tipo de entrada.
Encapsula argumentos em custom_call @stablehlo.shape_refinement_operand_wrapper
para manter a IR válida antes da execução do refinamento de forma.
func.func public @main(%arg0: tensor<?xf32>) -> tensor<?xf32> {
...
}
==>
func.func public @main(%arg0: tensor<16xf32>) -> tensor<?xf32> {
%c = stablehlo.constant dense<16> : tensor<1xi64>
%0 = stablehlo.custom_call @stablehlo.shape_refinement_operand_wrapper(%arg0, %c) {...}
: (tensor<16xf32>, tensor<1xi64>) -> tensor<?xf32>
...
}
O refinedTypesOption pode ser usado para especificar uma lista de tipos refinados.
Isso pode ser especificado em MLIR com --types='tensor<...>,tensor<...>' ou
transmitido ao método de criação de transmissão. A lista de tipos de refinamento precisa especificar o tipo de cada argumento do método main que está sendo refinado.
Opções
-types : The new types to be used for the main function's arguments, specified as an MLIR TypeRange 'tensor<1x2xf32>, ...'
-stablehlo-refine-shapes
Refina formas em um programa StableHLO.
Mostra um programa StableHLO refinando formas em operações.
O principal caso de uso dessa transmissão é especializar programas com formas dinâmicas em formas estáticas. Se um programa StableHLO com formato dinâmico tiver a estrutura certa, atualizar os tipos de argumentos de formatos dinâmicos para formatos estáticos e executar essa transmissão vai propagar formatos estáticos pelo programa.
Essa transmissão remove custom_call @shape_refinement_operand_wrapper substituindo os usos do resultado pelo operando diretamente e propaga formas estáticas em todo o programa.
%c = stablehlo.constant dense<16> : tensor<1xi64>
%0 = stablehlo.custom_call @stablehlo.shape_refinement_operand_wrapper(%arg0, %c) {...}
: (tensor<16xf32>, tensor<1xi64>) -> tensor<?xf32>
%1 = stablehlo.add %0, %0 : tensor<?xf32>
==>
%1 = stablehlo.add %arg0, %arg0 : tensor<16xf32>
Os módulos válidos para refinamento de forma precisam ter as seguintes propriedades:
- Todos os formatos dinâmicos dependem apenas dos formatos de entrada (sem dependência de formato no conteúdo da matriz de entrada). As operações que dependem transitivamente apenas das formas de entrada (por exemplo, conforme fornecidas por
stablehlo.get_dimension_size) ou de constantes globais, como os valores resolvidos de números inteiros simbólicos (ou seja, tensor: A = 5), são chamadas de operações dimension. Todos os valores de dimensão podem ser resolvidos em constantes usando a redução constante interprocedural. - As funções intermediárias podem receber vários argumentos de token (do tipo !stablehlo.token) no início da lista de argumentos, seguidos por alguns argumentos de constante global que são escalares inteiros constantes, como os valores resolvidos de números inteiros simbólicos (ou seja, tensor
: A = 5). - Algumas funções intermediárias podem retornar cálculos em constantes globais, ou seja,
floordivem valores symint. Essas funções são indicadas apenas retornando valores constantes após o refinamento. Essas funções são inlinadas. - Todas as chamadas para uma única função são resolvidas com as mesmas formas de argumento, e não são feitas chamadas de função recursivas / correcursivas.
-stablehlo-wrap-in-composite
Encapsula uma operação StableHLO não composta em uma operação composta.
Encapsula operações do StableHLO em operações stablehlo.composite.
Por exemplo, considere um programa StableHLO simples:
func.func @main(%arg0 : tensor<2xf32>, %arg1 : tensor<2xf32>) -> tensor<2xf32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<2xf32>
return %0 : tensor<2xf32>
}
Aplicar essa transmissão para encapsular operações de stablehlo.add vai resultar no seguinte programa:
func.func @main(%arg0: tensor<2xf32>, %arg1: tensor<2xf32>) -> tensor<2xf32> {
%0 = stablehlo.composite "stablehlo.add" %arg0, %arg1 {decomposition = @stablehlo.add.impl} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xf32>
return %0 : tensor<2xf32>
}
func.func private @stablehlo.add.impl(%arg0: tensor<2xf32>, %arg1: tensor<2xf32>) -> tensor<2xf32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<2xf32>
return %0 : tensor<2xf32>
}
Observações:
- O atributo
nameda operaçãostablehlo.compositegerada será sempre o mesmo nome da operação original que foi encapsulada. Por exemplo, se você encapsular uma operaçãostablehlo.add, o composto também será chamado de"stablehlo.add". - A função particular que encapsula a operação original (referenciada pelo atributo
decompositionda operaçãostablehlo.composite) será nomeada usando o padrão<op_name>.impl[.N], em que<op_name>é o nome da operação original eNé um identificador inteiro exclusivo gerado para evitar conflitos de nomenclatura no módulo.
Esse cartão pode ser usado de duas maneiras distintas:
Modo 1: uso da linha de comando
Esse modo é destinado à depuração ou testes, já que oferece controle mínimo sobre os atributos das operações stablehlo.composite geradas.
Ele encapsula todas as instâncias de operações especificadas usando as opções op-names (uma lista separada por vírgulas de nomes de operações). Os atributos da operação stablehlo.composite recém-criada serão os mesmos da operação original.
Exemplo de uso:
stablehlo-opt input.mlir --stablehlo-wrap-in-composite=op-names='stablehlo.add,stablehlo.mul' -o output.mlir
Modo 2: encapsulamento programático em todo o módulo com processamento de atributos personalizado
Esse modo estende o encapsulamento programático para todo o módulo, oferecendo controle refinado sobre quais operações são encapsuladas e seus atributos.
Para isso, use a API createStablehloWrapInCompositePass, que recebe um CompositeAttributeProviderMap como argumento.
O CompositeAttributeProviderMap é um mapa que determina quais operações
devem ser consideradas para encapsulamento e como os atributos delas devem ser
processados. A semântica é a seguinte:
- Chaves (mlir::TypeID):
TypeIDde uma operação do MLIR. Se umTypeIDde uma operação corresponder a uma chave no mapa, ele se tornará um candidato para encapsulamento. - Valores (funções lambda): função lambda do tipo
std::function<std::optional<NamedAttrList>(Operation*)>. Essa função é aplicada a cada operação candidata.- Entrada:um
mlir::Operation*, que é uma instância do tipo de operação correspondente à chaveTypeID. - Valor de retorno:um
std::optional<NamedAttrList>.- Se a lambda retornar um
NamedAttrList(encapsulado emstd::optional), a operação será encapsulada em uma operaçãostablehlo::composite, e os atributos retornados serão usados para definir os atributos do elemento composto. - Se a lambda retornar
std::nullopt, a operação não será encapsulada. Isso permite o ajuste seletivo com base em critérios personalizados.
- Se a lambda retornar um
- Entrada:um
Exemplo (C++):
stablehlo::CompositeAttributeProviderMap compositeAttributeProviderMap;
compositeAttributeProviderMap[mlir::TypeID::get<mlir::stablehlo::AddOp>()] =
[](mlir::Operation* op) -> std::optional<mlir::NamedAttrList> {
// Custom logic to determine if and how to wrap the operation.
// Example: Only wrap if it's on a specific type.
if (mlir::isa<mlir::Float32Type>(op->getOperand(0).getType())) {
return mlir::NamedAttrList(op->getAttrs());
}
return std::nullopt; // Do not wrap.
};
pm.addPass(createStablehloWrapInCompositePass(compositeAttributeProviderMap, compositeVersion));
if (mlir::failed(pm.run(module))) {
return;
}
Opções
-op-names : The names of the ops to wrap.
-version : The version number of the composite op.
-vhlo-legalize-to-stablehlo
Legalize VHLO to StableHLO.
-vhlo-to-version
Converter entre versões de VHLO para compatibilidade.
Converte entre versões de VHLO para upgrade e downgrade de IR para preservar a compatibilidade com versões futuras e anteriores.
"vhlo.exponential_v2"(%[[ARG0]]) <{result_accuracy = DEFAULT}>
# ==( -target=1.0.0 )==>
"vhlo.exponential_v1"(%[[ARG0]])
# ==( -target=1.9.0 )==>
"vhlo.exponential_v2"(%[[ARG0]]) <{result_accuracy = DEFAULT}>
Consulte vhlo.md > O dialeto VHLO para mais detalhes sobre como o VHLO é usado para preservar a compatibilidade com versões anteriores e futuras.
Opções
-target : The target version. Must be a version of the form #.#.# .