-chlo-legalize-to-stablehlo
Legalizza il flusso di operazioni CHLO in operazioni StableHLO e Shape
-shape-legalize-to-stablehlo
Legalizza le operazioni correlate alla forma in StableHLO.
Un pass sperimentale che legalizza le operazioni correlate alla forma per le operazioni StableHLO.
L'unione di calcoli di forme e dati tramite un passaggio facoltativo consentirà all'ecosistema StableHLO di sfruttare potenzialmente le pipeline di compilazione che utilizzano operazioni StableHLO per modellare il dinamismo.
-stablehlo-canonicalize-dynamism
Canonicalizza le operazioni StableHLO dinamiche in operazioni statiche.
Sostituisce le operazioni StableHLO dinamiche come DynamicReshapeOp con le controparti
statiche corrispondenti come DynamicReshapeOp a ReshapeOp o
DynamicBroadcastInDim a BroadcastInDim se tutti gli elementi dinamici di queste operazioni sono costanti.
%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.
Convalida le chiamate personalizzate shape_assertion.
Le asserzioni di forma convalidano i vincoli sulle dimensioni dinamiche in StableHLO.
Ad esempio, se un framework deve applicare un vincolo di DimA < 2,
potrebbe essere emesso il seguente IR:
%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" }
Dopo il passaggio, se le forme sono corrette, il stablehlo.custom_call
verrà rimosso.
Opzioni
-enable-shape-assertions : Whether shape assertions may generate errors.
-stablehlo-compatibility-expander
Expander di compatibilità per le operazioni StableHLO.
Le operazioni StableHLO vengono aggiornate o viene introdotta una nuova operazione nelle versioni più recenti. Questo pass di attivazione espande la compatibilità con le versioni precedenti di StableHLO decomponendo le operazioni StableHLO più recenti in operazioni equivalenti supportate da queste versioni precedenti.
Perché si tratta di un abbonamento ad attivazione facoltativa?
Di tanto in tanto, vengono utilizzati miglioramenti di StableHLO per semplificare notevolmente la gestione di determinati pattern comuni nell'ecosistema OpenXLA. Ciò include elementi come TanOp, che offre un elevato supporto per framework e compilatori, nonché dimensioni di batching di raccolta/distribuzione, che possono essere rappresentate utilizzando sezioni, ma rendono lo sharding molto più difficile. Per questa categoria di nuove funzionalità, non offriamo il downgrade automatico, in quanto potrebbe eliminare informazioni importanti utilizzate nelle ottimizzazioni successive. Questo passaggio può essere utilizzato per espandere queste operazioni in base a una versione target per massimizzare la compatibilità a scapito di una compilazione potenzialmente meno ottimale.
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>
}
Opzioni
-target : The target version. Must be a version of the form #.#.#.
-stablehlo-complex-math-expander
Expander per operazioni matematiche complesse di StableHLO.
Le operazioni matematiche complesse di StableHLO sono decomposizioni che utilizzano operazioni matematiche reali di StableHLO.
Questa affermazione si basa sul presupposto che non esista hardware che supporti nativamente numeri complessi o operazioni matematiche complesse. Ciò significa che i meccanismi di riserva per operazioni matematiche complesse che i compilatori possono implementare sono ridondanti. Se attivi questo passaggio, tutte le operazioni matematiche complesse di StableHLO verranno espansi.
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
Passaggio per trasformare la rappresentazione intermedia in numeri interi senza segno.
-stablehlo-legalize-composite-to-call
Sostituisce le operazioni composite con una chiamata alla loro scomposizione.
Sostituisce le operazioni composite con una chiamata alla loro scomposizione, ad esempio:
stablehlo.composite "my_namespace.my_op" %arg0, %arg1 {
decomposition = @bar,
version = 1,
composite_attributes = {
"my_attribute": "my_value"
}
}
Diventerà:
func.call @bar(%arg0, %arg1)
Un sottoinsieme di compositi può essere escluso da questa trasformazione utilizzando il flag "except", ad esempio:
stablehlo-opt --stablehlo-legalize-composite-to-call=except='foo.baz,foo.qux'
Opzioni
-except : Names of composites that should not be replaced with calls.
-stablehlo-legalize-deprecated-ops
Legalizza le operazioni ritirate in operazioni ben supportate.
La RFC relativa al ritiro di Opset StableHLO v1.0 (#2283) propone di rimuovere diverse operazioni ridondanti. Questo passaggio consente di valutare l'impatto di queste rimozioni in varie pipeline di compilazione legalizzandole con le loro controparti supportate a lungo termine.
Opzioni
-fail-on-unused : Fail on (mostly) unused ops that are deprecated without any fallback.
-stablehlo-legalize-qdq-to-quantized-op
Unire il pattern (dequantizzazione, operazione in virgola mobile e quantizzazione) nell'operazione quantizzata StableHLO
Unisci (dequantizza, operazione in virgola mobile e quantizza) il pattern nell'operazione quantizzata StableHLO Nota: il passaggio non elimina alcuna operazione preesistente. Ad esempio, il seguente programma
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>>
}
Diventerà:
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
Converti le operazioni quantizzate di StableHLO in operazioni matematiche primitive di StableHLO.
Converti i programmi StableHLO che utilizzano tipi UniformQuantized in operazioni matematiche con numeri interi semanticamente equivalenti.
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>>
}
Diventerà:
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
Decomponi l'operazione StableHLO quantizzata in uno schema (dequantizzazione, operazione in virgola mobile e quantizzazione).
Decomponi i programmi quantizzati StableHLO utilizzando operazioni di quantizzazione/dequantizzazione uniformi. Ad esempio, il seguente programma
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>>
}
Diventerà:
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
Legalizza StableHLO in VHLO.
Esegui la legalizzazione di StableHLO all'ultima versione delle operazioni in VHLO. Queste operazioni possono poi
essere eseguite il downgrade a versioni precedenti di VHLO per la compatibilità futura utilizzando
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 > The VHLO dialect per informazioni dettagliate su come VHLO viene utilizzato per preservare la compatibilità in avanti e all'indietro.
Opzioni
-allow-other-dialects : Allow serialization to use other (potentially unstable) dialects, inserts unrealized casts between dialects.
-stablehlo-refine-arguments
Perfeziona le forme degli argomenti della funzione principale.
Modifica gli argomenti della funzione principale utilizzando la firma del tipo di input.
Racchiude gli argomenti in custom_call @stablehlo.shape_refinement_operand_wrapper
per mantenere valido l'IR prima dell'esecuzione del perfezionamento della 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>
...
}
refinedTypesOption può essere utilizzato per specificare un elenco di tipi raffinati.
Può essere specificato in MLIR con --types='tensor<...>,tensor<...>' o
trasmesso al metodo di creazione della tessera. L'elenco dei tipi di perfezionamento deve specificare il tipo di ogni argomento del metodo main che viene perfezionato.
Opzioni
-types : The new types to be used for the main function's arguments, specified as an MLIR TypeRange 'tensor<1x2xf32>, ...'
-stablehlo-refine-shapes
Perfeziona le forme in un programma StableHLO.
Descrive un programma StableHLO che perfeziona le forme all'interno delle operazioni.
Il caso d'uso principale di questa passata è la specializzazione di programmi con forme dinamiche in forme statiche. Se un programma StableHLO con forma dinamica ha la struttura corretta, l'aggiornamento dei tipi di argomenti da forme dinamiche a forme statiche e l'esecuzione di questa passata propagheranno le forme statiche nel programma.
Questo passaggio rimuove custom_call @shape_refinement_operand_wrapper sostituendo gli utilizzi del risultato direttamente con l'operando e propaga le forme statiche in tutto il programma.
%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>
I moduli validi per il perfezionamento della forma devono avere le seguenti proprietà:
- Tutte le forme dinamiche dipendono solo dalle forme di input (nessuna dipendenza
della forma dai contenuti dell'array di input). Le operazioni che
dipendono transitivamente solo dalle forme di input (ad es. come indicato da
stablehlo.get_dimension_size) o da costanti globali come i valori risolti di numeri interi simbolici (ovvero tensore: A = 5) sono chiamate operazioni dimension. Tutti i valori delle dimensioni possono essere risolti in costanti tramite l'ottimizzazione delle costanti interprocedurale. - Le funzioni intermedie possono accettare un numero di argomenti token (di tipo
!stablehlo.token) all'inizio dell'elenco degli argomenti, seguiti da alcuni
argomenti costanti globali che sono scalari interi costanti, come i
valori risolti di numeri interi simbolici (ad es. tensore
: A = 5). - Alcune funzioni intermedie potrebbero restituire calcoli su costanti globali,
ad esempio
floordivsu valori symint. Queste funzioni sono indicate solo restituendo valori costanti dopo il perfezionamento. Queste funzioni sono inlined. - Tutte le chiamate a una singola funzione vengono risolte con le stesse forme di argomenti e non vengono effettuate chiamate di funzioni ricorsive / corecursive.
-stablehlo-wrap-in-composite
Racchiude un'operazione StableHLO non composita in un'operazione composita.
Esegue il wrapping delle operazioni StableHLO nelle operazioni stablehlo.composite.
Ad esempio, considera un semplice programma StableHLO:
func.func @main(%arg0 : tensor<2xf32>, %arg1 : tensor<2xf32>) -> tensor<2xf32> {
%0 = stablehlo.add %arg0, %arg1 : tensor<2xf32>
return %0 : tensor<2xf32>
}
L'applicazione di questa passata alle operazioni di avvolgimento stablehlo.add comporterà il seguente programma:
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>
}
Note:
- L'attributo
namedell'operazionestablehlo.compositegenerata sarà sempre uguale al nome dell'operazione originale sottoposta a wrapping (ad es. se esegui il wrapping di un'operazionestablehlo.add, anche l'operazione composita si chiamerà"stablehlo.add"). - La funzione privata che incapsula l'operazione originale
(a cui fa riferimento l'attributo
decompositiondell'operazionestablehlo.composite) verrà denominata utilizzando il pattern<op_name>.impl[.N], dove<op_name>è il nome dell'operazione originale eNè un identificatore intero univoco generato per evitare conflitti di denominazione all'interno del modulo.
Questa tessera può essere utilizzata in due modi distinti:
Modalità 1: utilizzo della riga di comando
Questa modalità è pensata per il debug o il test, in quanto offre un controllo minimo
sugli attributi delle operazioni stablehlo.composite generate.
Esegue il wrapping di tutte le istanze delle operazioni specificate utilizzando le opzioni op-names
(un elenco di nomi di operazioni separati da virgole). Gli attributi dell'operazione stablehlo.composite appena creata saranno gli stessi dell'operazione originale.
Esempio di utilizzo:
stablehlo-opt input.mlir --stablehlo-wrap-in-composite=op-names='stablehlo.add,stablehlo.mul' -o output.mlir
Modalità 2: wrapping programmatico a livello di modulo con gestione personalizzata degli attributi
Questa modalità estende il wrapping programmatico all'intero modulo, offrendo
un controllo granulare sulle operazioni sottoposte a wrapping e sui relativi attributi.
Ciò si ottiene utilizzando l'API createStablehloWrapInCompositePass, che accetta un CompositeAttributeProviderMap come argomento.
CompositeAttributeProviderMap è una mappa che indica quali operazioni
devono essere prese in considerazione per il wrapping e come devono essere
gestiti i relativi attributi. La sua semantica è la seguente:
- Chiavi (mlir::TypeID):
TypeIDdi un'operazione MLIR. SeTypeIDdi un'operazione corrisponde a una chiave nella mappa, diventa un candidato per il wrapping. - Valori (funzioni Lambda): funzione Lambda di tipo
std::function<std::optional<NamedAttrList>(Operation*)>. Questa funzione viene applicata a ogni operazione candidata.- Input:un
mlir::Operation*, ovvero un'istanza del tipo di operazione corrispondente alla chiaveTypeID. - Valore restituito:un
std::optional<NamedAttrList>.- Se la lambda restituisce un
NamedAttrList(racchiuso instd::optional), l'operazione viene racchiusa in un'operazionestablehlo::compositee gli attributi restituiti vengono utilizzati per impostare gli attributi del composito. - Se la lambda restituisce
std::nullopt, l'operazione non viene incapsulata. Ciò consente il wrapping selettivo in base a criteri personalizzati.
- Se la lambda restituisce un
- Input:un
Esempio (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;
}
Opzioni
-op-names : The names of the ops to wrap.
-version : The version number of the composite op.
-vhlo-legalize-to-stablehlo
Legalizzare VHLO in StableHLO.
-vhlo-to-version
Converti tra le versioni di VHLO per la compatibilità.
Esegue la conversione tra le versioni di VHLO per l'upgrade e il downgrade dell'IR per preservare la compatibilità con le versioni precedenti e successive.
"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 > The VHLO dialect per informazioni dettagliate su come VHLO viene utilizzato per preservare la compatibilità in avanti e all'indietro.
Opzioni
-target : The target version. Must be a version of the form #.#.# .