-chlo-legalize-to-stablehlo
Légalise le flux d'opérations CHLO vers les opérations StableHLO et Shape
-shape-legalize-to-stablehlo
Légaliser les opérations liées aux formes dans StableHLO.
Pass expérimental qui légalise les opérations liées à la forme en opérations StableHLO.
En combinant les calculs de forme et de données via un pass facultatif, l'écosystème StableHLO pourra potentiellement exploiter les pipelines de compilation qui utilisent des opérations StableHLO pour modéliser le dynamisme.
-stablehlo-canonicalize-dynamism
Canonicalise les opérations StableHLO dynamiques en opérations statiques.
Remplace les opérations StableHLO dynamiques telles que DynamicReshapeOp par les opérations statiques correspondantes, comme DynamicReshapeOp par ReshapeOp ou DynamicBroadcastInDim par BroadcastInDim, si tous les éléments dynamiques de ces opérations sont en fait des 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
_Check stablehlo.custom_call @shapeassertion ops.
Validez les appels personnalisés shape_assertion.
Les assertions de forme valident les contraintes sur les dimensions dynamiques dans StableHLO.
Par exemple, si un framework devait appliquer une contrainte de DimA < 2, l'IR suivante pourrait être émise :
%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" }
Une fois le pass terminé, si les formes sont correctes, le stablehlo.custom_call sera supprimé.
Options
-enable-shape-assertions : Whether shape assertions may generate errors.
-stablehlo-compatibility-expander
Expander de compatibilité pour les opérations StableHLO.
Les opérations StableHLO sont mises à jour ou une nouvelle opération est introduite dans les dernières versions. Ce pass d'activation étend la rétrocompatibilité avec les anciennes versions de StableHLO en décomposant les opérations StableHLO plus récentes en opérations équivalentes compatibles avec ces anciennes versions.
Pourquoi s'agit-il d'un pass facultatif ?
Parfois, des améliorations des opérations StableHLO sont utilisées pour simplifier considérablement la gestion de certains modèles courants dans l'écosystème OpenXLA. Cela inclut des éléments tels que TanOp, qui bénéficie d'une compatibilité élevée avec le framework et le compilateur, ainsi que les dimensions de batching gather/scatter, qui peuvent être représentées à l'aide de tranches, mais qui rendent le partitionnement beaucoup plus difficile. Pour cette catégorie de nouvelles fonctionnalités, nous ne proposons pas de rétrogradation automatique, car cela pourrait supprimer des informations importantes utilisées dans les optimisations ultérieures. Ce pass peut être utilisé pour étendre ces opérations en fonction d'une version cible afin de maximiser la compatibilité au détriment d'une compilation potentiellement moins optimale.
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>
}
Options
-target : The target version. Must be a version of the form #.#.#.
-stablehlo-complex-math-expander
Expander pour les opérations mathématiques complexes StableHLO.
Les opérations mathématiques complexes StableHLO sont des décompositions utilisant des opérations mathématiques réelles StableHLO.
Cette affirmation repose sur l'hypothèse qu'aucun matériel n'existe qui prend en charge les nombres complexes ni les opérations mathématiques complexes de manière native. Cela signifie que les mécanismes de secours pour les opérations mathématiques complexes que les compilateurs peuvent implémenter sont redondants. Si vous activez ce pass, toutes les opérations mathématiques complexes StableHLO seront développées.
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
Transmettez pour transformer l'IR en nombres entiers non signés.
-stablehlo-legalize-composite-to-call
Remplace les opérations composites par un appel à leur décomposition.
Remplace les opérations composites par un appel à leur décomposition, par exemple :
stablehlo.composite "my_namespace.my_op" %arg0, %arg1 {
decomposition = @bar,
version = 1,
composite_attributes = {
"my_attribute": "my_value"
}
}
Deviendra :
func.call @bar(%arg0, %arg1)
Un sous-ensemble de composites peut être exclu de cette transformation à l'aide de l'indicateur "except" (sauf), par exemple :
stablehlo-opt --stablehlo-legalize-composite-to-call=except='foo.baz,foo.qux'
Options
-except : Names of composites that should not be replaced with calls.
-stablehlo-legalize-deprecated-ops
Légalisez les opérations obsolètes en opérations bien acceptées.
La RFC 2283 sur l'obsolescence de l'opset StableHLO v1.0 propose de supprimer plusieurs opérations redondantes. Ce pass permet d'évaluer l'impact de ces suppressions d'opérations dans différents pipelines de compilation en les légalisant avec leurs homologues compatibles à long terme.
Options
-fail-on-unused : Fail on (mostly) unused ops that are deprecated without any fallback.
-stablehlo-legalize-qdq-to-quantized-op
Fusionner le modèle (déquantifier, opération à virgule flottante et quantifier) dans l'opération quantifiée StableHLO
Fusionner le modèle (déquantifier, opération à virgule flottante et quantifier) dans l'opération quantifiée StableHLO Remarque : Le pass ne supprime aucune opération préexistante. Par exemple, le programme suivant
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>>
}
Deviendra :
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
Convertissez les opérations quantifiées StableHLO en opérations mathématiques primitives StableHLO.
Convertissez les programmes StableHLO utilisant des types UniformQuantized en opérations mathématiques sur des entiers sémantiquement équivalentes.
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>>
}
Deviendra :
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
Décomposer l'opération StableHLO quantifiée en un modèle (déquantifier, opération à virgule flottante et quantifier).
Décompose les programmes StableHLO quantifiés à l'aide d'opérations de quantification/déquantification uniformes. Par exemple, le programme suivant
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>>
}
Deviendra :
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
Légalisez StableHLO en VHLO.
Légalisez StableHLO vers la dernière version des opérations dans VHLO. Ces opérations peuvent ensuite être rétrogradées vers d'anciennes versions de VHLO pour assurer la compatibilité ascendante à l'aide de VhloToVersionPass.
stablehlo.exponential %[[ARG0]] <{result_accuracy = DEFAULT}> : tensor<f32>
# ====>
"vhlo.exponential_v2"(%[[ARG0]]) <{result_accuracy = #vhlo.DEFAULT_v1}> : !vhlo.tensor_v1<!vhlo.f32_v1>
Consultez vhlo.md > The VHLO dialect (vhlo.md > Le dialecte VHLO) pour en savoir plus sur l'utilisation de VHLO pour préserver la compatibilité ascendante et descendante.
Options
-allow-other-dialects : Allow serialization to use other (potentially unstable) dialects, inserts unrealized casts between dialects.
-stablehlo-refine-arguments
Affine les formes des arguments de la fonction principale.
Modifie les arguments de la fonction principale à l'aide de la signature du type d'entrée.
Encapsule les arguments dans custom_call @stablehlo.shape_refinement_operand_wrapper
pour que l'IR reste valide avant l'exécution de l'affinage de la forme.
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>
...
}
refinedTypesOption peut être utilisé pour spécifier une liste de types affinés.
Cela peut être spécifié dans MLIR avec --types='tensor<...>,tensor<...>' ou transmis à la méthode de création du pass. La liste des types d'affinements doit spécifier le type de chaque argument de la méthode main affinée.
Options
-types : The new types to be used for the main function's arguments, specified as an MLIR TypeRange 'tensor<1x2xf32>, ...'
-stablehlo-refine-shapes
Affine les formes dans un programme StableHLO.
Parcourt un programme StableHLO en affinant les formes dans les opérations.
Le cas d'utilisation phare de ce pass est la spécialisation des programmes à formes dynamiques en formes statiques. Si un programme StableHLO à forme dynamique présente la bonne structure, la mise à jour de ses types d'arguments de formes dynamiques à formes statiques et l'exécution de ce pass propageront les formes statiques dans l'ensemble du programme.
Ce pass supprime custom_call @shape_refinement_operand_wrapper en remplaçant les utilisations du résultat par l'opérande directement et propage les formes statiques dans tout le programme.
%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>
Les modules valides pour l'affinage de la forme doivent présenter les propriétés suivantes :
- Toutes les formes dynamiques dépendent uniquement des formes d'entrée (aucune dépendance de forme sur le contenu du tableau d'entrée). Nous appelons
dimensionles opérations qui ne dépendent transitivement que des formes d'entrée (par exemple, telles qu'indiquées parstablehlo.get_dimension_size) ou des constantes globales telles que les valeurs résolues des entiers symboliques (c'est-à-dire le Tensor: A = 5). Toutes les valeurs de dimension peuvent être résolues en constantes grâce au pliage de constantes interprocédural. - Les fonctions intermédiaires peuvent prendre un certain nombre d'arguments de jeton (de type !stablehlo.token) au début de la liste d'arguments, suivis de certains arguments constants globaux qui sont des scalaires entiers constants, tels que les valeurs résolues des entiers symboliques (c'est-à-dire tensor
: A = 5). - Certaines fonctions intermédiaires peuvent renvoyer des calculs sur des constantes globales, c'est-à-dire
floordivsur les valeurs symint. Ces fonctions sont indiquées par le fait qu'elles ne renvoient que des valeurs constantes après affinement. Ces fonctions sont intégrées. - Tous les appels à une même fonction sont résolus avec les mêmes formes d'arguments, et aucun appel de fonction récursif / corécursif n'est effectué.
-stablehlo-wrap-in-composite
Encapsule une opération StableHLO non composite dans une opération composite.
Encapsule les opérations StableHLO dans des opérations stablehlo.composite.
Par exemple, considérons un programme StableHLO simple :
func.func @main(%arg0 : tensor<2xf32>, %arg1 : tensor<2xf32>) -> tensor<2xf32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<2xf32>
return %0 : tensor<2xf32>
}
L'application de ce pass pour encapsuler les opérations stablehlo.add entraînera le programme suivant :
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>
}
Remarques :
- L'attribut
namede l'opérationstablehlo.compositegénérée sera toujours le même que le nom de l'opération d'origine qui a été encapsulée (par exemple, si vous encapsulez une opérationstablehlo.add, le composite sera également nommé"stablehlo.add"). - La fonction privée qui encapsule l'opération d'origine (référencée par l'attribut
decompositionde l'opérationstablehlo.composite) sera nommée selon le modèle<op_name>.impl[.N], où<op_name>est le nom de l'opération d'origine etNest un identifiant entier unique généré pour éviter les conflits de dénomination dans le module.
Ce pass peut être utilisé de deux manières distinctes :
Mode 1 : Utilisation de la ligne de commande
Ce mode est destiné au débogage ou aux tests, car il offre un contrôle minimal sur les attributs des opérations stablehlo.composite générées.
Il encapsule toutes les instances des opérations spécifiées à l'aide des options op-names (liste de noms d'opérations séparés par une virgule). Les attributs de l'opération stablehlo.composite nouvellement créée seront les mêmes que ceux de l'opération d'origine.
Exemple d'utilisation :
stablehlo-opt input.mlir --stablehlo-wrap-in-composite=op-names='stablehlo.add,stablehlo.mul' -o output.mlir
Mode 2 : Enveloppement programmatique à l'échelle du module avec gestion personnalisée des attributs
Ce mode étend l'encapsulation programmatique à l'ensemble du module, offrant un contrôle précis sur les opérations encapsulées et leurs attributs.
Pour ce faire, utilisez l'API createStablehloWrapInCompositePass, qui prend un CompositeAttributeProviderMap comme argument.
CompositeAttributeProviderMap est une carte qui indique les opérations à prendre en compte pour l'encapsulation et la manière dont leurs attributs doivent être gérés. Voici sa sémantique :
- Clés (mlir::TypeID) :
TypeIDd'une opération MLIR. Si leTypeIDd'une opération correspond à une clé du mappage, il devient un candidat à l'encapsulation. - Valeurs (fonctions lambda) : fonction lambda de type
std::function<std::optional<NamedAttrList>(Operation*)>. Cette fonction est appliquée à chaque opération candidate.- Entrée :
mlir::Operation*, qui est une instance du type d'opération correspondant à la cléTypeID. - Valeur renvoyée :
std::optional<NamedAttrList>.- Si le lambda renvoie un
NamedAttrList(encapsulé dansstd::optional), l'opération est encapsulée dans une opérationstablehlo::composite, et les attributs renvoyés sont utilisés pour définir les attributs du composite. - Si le lambda renvoie
std::nullopt, l'opération n'est pas encapsulée. Cela permet un encapsulage sélectif basé sur des critères personnalisés.
- Si le lambda renvoie un
- Entrée :
Exemple (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;
}
Options
-op-names : The names of the ops to wrap.
-version : The version number of the composite op.
-vhlo-legalize-to-stablehlo
Légaliser VHLO en StableHLO.
-vhlo-to-version
Convertissez les versions de VHLO pour assurer la compatibilité.
Convertit les versions de VHLO pour la mise à niveau et la rétrogradation de l'IR afin de préserver la compatibilité ascendante et descendante.
"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}>
Consultez vhlo.md > The VHLO dialect (vhlo.md > Le dialecte VHLO) pour en savoir plus sur l'utilisation de VHLO pour préserver la compatibilité ascendante et descendante.
Options
-target : The target version. Must be a version of the form #.#.# .