Repository navigation
Formalize syntax and evaluation of StableHLO programs #484
Description
We've made significant progress with the spec in the last two months, and it looks like soon we will have all of the core ops specced after the existing HLO semantics. There's a bunch of ops in the PR queue right now, and about a dozen more distribution and elementwise ops to go, but finishing all that looks like a matter of several weeks at this point thanks to the great work done by the team:
| Category | Ops |
|---|---|
| Control Flow | case, if, while |
| Data Movement | broadcast_in_dim, concatenate, gather, pad, reshape, reverse, scatter, slice, sort, transpose |
| Distribution | after_all, all_gather, all_reduce, all_to_all, collective_permute, infeed, outfeed, recv, reduce_scatter, replica_id, send |
| Elementwise | abs, add, and, atan2, bitcast_convert, cbrt, ceil, clamp, compare, complex, convert, cosine, count_leading_zeros, divide, exponential, exponential_minus_one, floor, imag, is_finite, log, log_plus_one, logistic, map, maximum, minimum, multiply, negate, not, or, popcnt, power, real, reduce_precision, remainder, round_nearest_afz, round_nearest_even, rsqrt, select, shift_left, shift_right_arithmetic, shift_right_logical, sign, sine, sqrt, subtract, tanh, xor |
| Extensibility | custom_call, get_tuple_element, tuple |
| Miscellaneous | batch_norm_grad, batch_norm_inference, batch_norm_training, cholesky, constant, fft, iota, optimization_barrier, return, rng, rng_bit_generator, triangular_solve |
| Reduction | convolution, dot_general, reduce, reduce_window, select_and_scatter |
This will make it possible to do something cool that wasn't possible before - express RFCs as diffs to the spec - meaning that the work on evolution beyond what's currently in HLO would become more precise:
| Category | Ops |
|---|---|
| Dynamism | compute_reshape_shape, cstr_reshapable, dynamic_broadcast_in_dim, dynamic_conv, dynamic_gather, dynamic_iota, dynamic_pad, dynamic_reshape, dynamic_slice, dynamic_update_slice, get_dimension_size, real_dynamic_slice, set_dimension_size |
| Quantization | uniform_dequantize, uniform_quantize + <new element types> |
| Sparsity | <new tensor types> |
To enable this, we're missing one key piece - framing the spec to provide self-contained syntax for StableHLO programs and self-contained rules for their evaluation. So far, we've been half-handwaving this / half-piggybacking on MLIR, but I think we're fairly close to have something truly self-contained, which will allow us to do really cool stuff.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
burmako commentedon Nov 30, 2022
Feedback from #634:
Add spec for parallel execution semantics (#634)
First step towards turning spec.md into a programming language spec (#…
sdasgup3 commentedon Mar 10, 2023
In #995 (comment), we informally talked about the scoping rules. Here is an attempt to formalize the same.
An SSA value in StableHLO is either an argument of a block or result of an operation. Each SSA value has zero or more uses. An operation defines zero or more SSA value as results, and has zero or more operands: these are uses of SSA value, which can be the results of other operations or block arguments.
For an arbitrary region
R, valueV, and blockB,parent(R): Parent operation this region is attached to.parent(B): Region to which the blockBbelongs.parent_region(op): Region to which the operationopbelongs. Forop=func.func, returnsnullptr.is_defined(V, R)= (SSA valueVis either defined by an operation in blockBor a block argument ofB) andparent(B) = R.For a use
Uof SSA valueV, we define a function,in_scope(U, R) -> bool, which evaluates totrueifUcan be used as operand of an operationopsuch thatparent_region(op) = R.in_scope(U, R)is given byfalse, ifR=nullptr,is_defined(V, R)orin_scope(U, parent_region(R)), otherwise.cc @burmako
burmako commentedon May 24, 2023
There are some ops which express
result[result_index]throughoperand[operand_index], and some ops which say stuff likeresult[i0, ..., ik,..., iR-1] = operand[i0, ..., ik',..., iR-1]where ik + ik' = dk - 1 for all dimensions k in dimensions.Might be interesting to standardize on one way of doing things. For example, the latter example (for ReverseOp) could be reformulated as:
Align the notation of spec and interpreter for Data Movement operatio…
burmako commentedon Jun 6, 2023
After #1556 landed, I'm reasonably happy with how the current version of the spec formalizes StableHLO syntax. There's more work to be done, but at least the notation is roughly consistent now across ops and is explained in the specification. Unassigning this ticket for now, to focus on the dynamism RFC.
joelberkeley commentedon Apr 5, 2025
What's the situation regarding send/recv ops? Afaik the semantics wrt channel IDs - specifically how to create channels and get their ID - is not well-defined yet. Is that correct?
sdasgup3 commentedon Apr 7, 2025
That's correct. The StableHLO specification currently defines when a
channel_idis required by certain operations but not the mechanism for creating channels or obtaining their IDs.The focus within StableHLO is on the operation's semantics:
How frameworks or runtime systems actually establish these communication channels and generate/manage the corresponding channel_id values is considered an implementation detail while drafting the specification.
joelberkeley commentedon Apr 7, 2025
Also appears to be beyond the scope of PJRT. I'm very unclear on how to create a channel. Should I use NCCL directly? I'm unclear what CUDA's PJRT plugin does already behind the scenes, and the semantics of using NCCL directly, alongside PJRT/stablehlo.
p.s. can move to discord if this isn't the right place for this
sdasgup3 commentedon Apr 7, 2025
I agree that would be the right choice (for more eyes with CUDA PJRT expertise)