-chlo-legalize-to-stablehlo
Legaliza el flujo de operaciones de CHLO a operaciones de StableHLO y Shape
-shape-legalize-to-stablehlo
Legaliza las operaciones relacionadas con la forma en StableHLO.
Es un pase experimental que legaliza las operaciones relacionadas con la forma para las operaciones de StableHLO.
Unir los cálculos de datos y de formas a través de un paso opcional permitirá que el ecosistema de StableHLO aproveche potencialmente las canalizaciones de compilación que usan operaciones de StableHLO para modelar el dinamismo.
-stablehlo-canonicalize-dynamism
Canoniza las operaciones dinámicas de StableHLO en operaciones estáticas.
Reemplaza las operaciones dinámicas de StableHLO, como DynamicReshapeOp, por las contrapartes estáticas correspondientes, como DynamicReshapeOp a ReshapeOp o DynamicBroadcastInDim a BroadcastInDim, si todos los elementos dinámicos de estas operaciones son 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
_Verifica las operaciones de aserción @shape de stablehlo.custom_call.assertion ops.
Valida las llamadas personalizadas shape_assertion.
Las aserciones de forma validan las restricciones sobre las dimensiones dinámicas en StableHLO.
Por ejemplo, si un framework necesitaba aplicar una restricción de DimA < 2, se podría emitir el siguiente RI:
%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" }
Después de la pasada, si las formas son correctas, se quitará el stablehlo.custom_call.
Opciones
-enable-shape-assertions : Whether shape assertions may generate errors.
-stablehlo-compatibility-expander
Expansor de compatibilidad para operaciones de StableHLO.
Las operaciones de StableHLO reciben actualizaciones o se introducen nuevas operaciones en las versiones más recientes. Este pase de habilitación expande la retrocompatibilidad con versiones anteriores de StableHLO descomponiendo las operaciones más recientes de StableHLO en operaciones equivalentes compatibles con esas versiones anteriores.
¿Por qué es un pase opcional?
En ocasiones, las mejoras en las operaciones de StableHLO se usan para simplificar en gran medida el manejo de ciertos patrones comunes en el ecosistema de OpenXLA. Esto incluye elementos como TanOp, que tiene una gran compatibilidad con el framework y el compilador, así como dimensiones de procesamiento por lotes de recopilación y dispersión, que se pueden representar con segmentos, pero dificultan mucho la fragmentación. Para esta categoría de funciones nuevas, no ofrecemos la opción de revertir automáticamente a la versión anterior, ya que se podría descartar información importante que se usa en optimizaciones posteriores. Este paso se puede usar para expandir estas operaciones en función de una versión objetivo para maximizar la compatibilidad a expensas de una compilación potencialmente menos óptima.
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>
}
Opciones
-target : The target version. Must be a version of the form #.#.#.
-stablehlo-complex-math-expander
Expansor para operaciones matemáticas complejas de StableHLO.
Las operaciones matemáticas complejas de StableHLO son descomposiciones que usan operaciones matemáticas reales de StableHLO.
Esta afirmación se basa en la suposición de que no existe hardware que admita números complejos ni operaciones matemáticas complejas de forma nativa. Esto significa que los mecanismos de resguardo en operaciones matemáticas complejas que los compiladores pueden implementar son redundantes. Si se habilita este pase, se expandirán todas las operaciones matemáticas complejas de StableHLO.
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
Pasa para transformar el IR en números enteros sin signo.
-stablehlo-legalize-composite-to-call
Reemplaza las operaciones compuestas por una llamada a su descomposición.
Reemplaza las operaciones compuestas por una llamada a su descomposición, p.ej., lo siguiente:
stablehlo.composite "my_namespace.my_op" %arg0, %arg1 {
decomposition = @bar,
version = 1,
composite_attributes = {
"my_attribute": "my_value"
}
}
Se convertirá en lo siguiente:
func.call @bar(%arg0, %arg1)
Se puede excluir un subconjunto de elementos compuestos de esta transformación con la marca "except", p.ej.:
stablehlo-opt --stablehlo-legalize-composite-to-call=except='foo.baz,foo.qux'
Opciones
-except : Names of composites that should not be replaced with calls.
-stablehlo-legalize-deprecated-ops
Legaliza las operaciones obsoletas para que sean operaciones bien admitidas.
La RFC de baja de Opset de StableHLO v1.0 (nº 2283) propone quitar varias operaciones redundantes. Este paso ayuda a evaluar el impacto de estas eliminaciones de operaciones en varios canales de compilación, ya que las legaliza para que coincidan con sus contrapartes compatibles a largo plazo.
Opciones
-fail-on-unused : Fail on (mostly) unused ops that are deprecated without any fallback.
-stablehlo-legalize-qdq-to-quantized-op
Fusión del patrón (descuantificación, operación de punto flotante y cuantificación) en la operación cuantificada de StableHLO
Fusiona el patrón (descuantificación, operación de punto flotante y cuantificación) en la operación cuantificada de StableHLO. Nota: El pase no borra ninguna operación preexistente. Por ejemplo, el siguiente programa
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>>
}
Se convertirá en lo siguiente:
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
Convierte las operaciones cuantificadas de StableHLO en operaciones matemáticas primitivas de StableHLO.
Convierte programas de StableHLO que usan tipos UniformQuantized en operaciones matemáticas de números enteros semánticamente 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>>
}
Se convertirá en lo siguiente:
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
Descompone la operación de StableHLO cuantificada en un patrón de (descuantificación, operación de punto flotante y cuantificación).
Descompón los programas cuantificados de StableHLO con operaciones uniformes de cuantificación y decuantificación. Por ejemplo, el siguiente programa
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>>
}
Se convertirá en lo siguiente:
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
Legaliza StableHLO a VHLO.
Legaliza StableHLO a la versión más reciente de las operaciones en VHLO. Luego, estas operaciones se pueden pasar a versiones anteriores de VHLO para lograr compatibilidad con versiones futuras 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>
Consulta vhlo.md > El dialecto de VHLO para obtener todos los detalles sobre cómo se usa VHLO para preservar la compatibilidad hacia adelante y hacia atrás.
Opciones
-allow-other-dialects : Allow serialization to use other (potentially unstable) dialects, inserts unrealized casts between dialects.
-stablehlo-refine-arguments
Refina las formas de los argumentos de la función principal.
Modifica los argumentos de la función principal con la firma del tipo de entrada.
Encapsula los argumentos en custom_call @stablehlo.shape_refinement_operand_wrapper para mantener la validez de la RI antes de que se ejecute el perfeccionamiento de la 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>
...
}
El refinedTypesOption se puede usar para especificar una lista de tipos refinados.
Esto se puede especificar en MLIR con --types='tensor<...>,tensor<...>' o pasar al método de creación de pases. La lista de tipos de refinamiento debe especificar el tipo de cada argumento para el método main que se refina.
Opciones
-types : The new types to be used for the main function's arguments, specified as an MLIR TypeRange 'tensor<1x2xf32>, ...'
-stablehlo-refine-shapes
Refina las formas en un programa de StableHLO.
Explica un programa de StableHLO que define mejor las formas dentro de las operaciones.
El caso de uso principal de este pase es especializar programas con formas dinámicas en formas estáticas. Si un programa de StableHLO con formas dinámicas tiene la estructura correcta, actualizar sus tipos de argumentos de formas dinámicas a formas estáticas y ejecutar este paso propagará las formas estáticas en todo el programa.
Este paso quita custom_call @shape_refinement_operand_wrapper reemplazando los usos del resultado con el operando directamente y propaga las formas estáticas en todo el 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>
Los módulos válidos para el perfeccionamiento de la forma deben tener las siguientes propiedades:
- Todas las formas dinámicas dependen solo de las formas de entrada (no hay dependencia de forma en el contenido del array de entrada). Nos referimos a las operaciones que dependen de forma transitiva solo de las formas de entrada (p. ej., como las que proporciona
stablehlo.get_dimension_size) o de constantes globales, como los valores resueltos de números enteros simbólicos (es decir, tensor: A = 5), como operaciones dimension. Todos los valores de dimensión se pueden resolver en constantes a través del plegado de constantes interprocedimental. - Las funciones intermedias pueden tomar una cantidad de argumentos de token (de tipo !stablehlo.token) al comienzo de la lista de argumentos, seguidos de algunos argumentos constantes globales que son escalares enteros constantes, como los valores resueltos de números enteros simbólicos (es decir, tensor
: A = 5). - Algunas funciones intermedias pueden devolver cálculos sobre constantes globales, es decir,
floordiven valores de symint. Estas funciones se indican solo devolviendo valores constantes después del perfeccionamiento. Estas funciones se insertan en el código. - Todas las llamadas a una sola función se resuelven en las mismas formas de argumentos, y no se realizan llamadas a funciones recursivas o correcursivas.
-stablehlo-wrap-in-composite
Encapsula una operación de StableHLO no compuesta en una operación compuesta.
Envuelve las operaciones de StableHLO en operaciones de stablehlo.composite.
Por ejemplo, considera un programa simple de StableHLO:
func.func @main(%arg0 : tensor<2xf32>, %arg1 : tensor<2xf32>) -> tensor<2xf32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<2xf32>
return %0 : tensor<2xf32>
}
Si se aplica este pase para envolver las operaciones de stablehlo.add, se generará el siguiente 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>
}
Notas:
- El atributo
namede la operaciónstablehlo.compositegenerada siempre será el mismo que el nombre de la operación original que se encapsuló (p.ej., si encapsulas una operaciónstablehlo.add, el compuesto también se llamará"stablehlo.add"). - La función privada que encapsula la operación original (a la que hace referencia el atributo
decompositionde la operaciónstablehlo.composite) se denominará con el patrón<op_name>.impl[.N], en el que<op_name>es el nombre de la operación original yNes un identificador entero único que se genera para evitar conflictos de nombres dentro del módulo.
Este pase se puede usar de dos maneras distintas:
Modo 1: Uso de la línea de comandos
Este modo está diseñado para la depuración o las pruebas, ya que ofrece un control mínimo sobre los atributos de las operaciones stablehlo.composite generadas.
Encapsula todas las instancias de las operaciones especificadas con las opciones de op-names (una lista de nombres de operaciones separada por comas). Los atributos de la operación stablehlo.composite recién creada serán los mismos que los de la operación original.
Ejemplo de uso:
stablehlo-opt input.mlir --stablehlo-wrap-in-composite=op-names='stablehlo.add,stablehlo.mul' -o output.mlir
Modo 2: Ajuste programático en todo el módulo con control de atributos personalizado
Este modo extiende el ajuste programático a todo el módulo y ofrece un control detallado sobre qué operaciones se ajustan y sus atributos.
Esto se logra con la API de createStablehloWrapInCompositePass, que toma un CompositeAttributeProviderMap como argumento.
El CompositeAttributeProviderMap es un mapa que indica qué operaciones se deben considerar para la adaptación y cómo se deben controlar sus atributos. Su semántica es la siguiente:
- Claves (mlir::TypeID):
TypeIDde una operación de MLIR. Si elTypeIDde una operación coincide con una clave del mapa, se convierte en candidato para la adaptación. - Valores (funciones lambda): Función lambda de tipo
std::function<std::optional<NamedAttrList>(Operation*)>. Esta función se aplica a cada operación candidata.- Entrada: Un
mlir::Operation*, que es una instancia del tipo de operación correspondiente a la claveTypeID. - Valor que se devuelve: Un
std::optional<NamedAttrList>.- Si la expresión lambda devuelve un
NamedAttrList(incluido enstd::optional), la operación se incluye en una operaciónstablehlo::composite, y los atributos devueltos se usan para establecer los atributos del elemento compuesto. - Si la expresión lambda devuelve
std::nullopt, la operación no se encapsula. Esto permite el ajuste selectivo según criterios personalizados.
- Si la expresión lambda devuelve un
- Entrada: Un
Ejemplo (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;
}
Opciones
-op-names : The names of the ops to wrap.
-version : The version number of the composite op.
-vhlo-legalize-to-stablehlo
Legaliza VHLO a StableHLO.
-vhlo-to-version
Convierte entre versiones de VHLO para garantizar la compatibilidad.
Realiza conversiones entre versiones de VHLO para actualizar o degradar el IR y conservar la compatibilidad con versiones anteriores y posteriores.
"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}>
Consulta vhlo.md > El dialecto de VHLO para obtener todos los detalles sobre cómo se usa VHLO para preservar la compatibilidad hacia adelante y hacia atrás.
Opciones
-target : The target version. Must be a version of the form #.#.# .