EXLA: support custom call MLIR attributes - #1824
Conversation
|
One subtle issue: I think the LLM needs some documentation around the After context compaction, it seems to lose track of how the native library is supposed to be loaded. In particular, it refuses to use |
The LLM is correct in this case. That function is an auxiliary for We could expose it in a separate PR in |
| `name = ` (for example `{"k", "42 : i64"}`). An empty list omits the dictionary | ||
| from the op. | ||
|
|
||
| * **`operation_attributes`** — Optional `{name, attr}` pairs, default `[]`, emitted |
There was a problem hiding this comment.
| * **`operation_attributes`** — Optional `{name, attr}` pairs, default `[]`, emitted | |
| * **`mlir_attributes`** — Optional `{name, attr}` pairs, default `[]`, emitted |
Let's use mlir_attributes instead of the original suggestion? This is very coupled to the stablehlo implementation, so adding a disconnected name would be more confusing
| attributes = | ||
| Enum.map(pairs, fn | ||
| {name, attr} when is_binary(name) and is_binary(attr) -> | ||
| {String.to_atom(name), attr} |
There was a problem hiding this comment.
We shouldn't use String.to_atom blindly. This opens an attack surface for crashing the BEAM.
We should instead compare the strings against the reserved attributes
There was a problem hiding this comment.
wow. I'm surprised by this comment
There was a problem hiding this comment.
iex(1)> Enum.map(1..1_000_000, fn x -> String.to_atom("#{x}") end)
[:"1", :"2", :"3", :"4", :"5", :"6", :"7", :"8", :"9", :"10", :"11", :"12",
:"13", :"14", :"15", :"16", :"17", :"18", :"19", :"20", :"21", :"22", :"23",
:"24", :"25", :"26", :"27", :"28", :"29", :"30", :"31", :"32", :"33", :"34",
:"35", :"36", :"37", :"38", :"39", :"40", :"41", :"42", :"43", :"44", :"45",
:"46", :"47", :"48", :"49", :"50", :"51", :"52", :"53", :"54", :"55", :"56",
:"57", :"58", :"59", :"60", :"61", :"62", :"63", :"64", :"65", :"66", :"67",
:"68", :"69", :"70", :"71", :"72", :"73", :"74", :"75", :"76", :"77", :"78",
:"79", :"80", :"81", :"82", :"83", :"84", :"85", :"86", :"87", :"88", :"89",
:"90", :"91", :"92", :"93", :"94", :"95", :"96", :"97", :"98", :"99", :"100",
:"101", :"102", :"103", :"104", :"105", :"106", :"107", :"108", :"109", :"110",
:"111", :"112", :"113", :"114", :"115", :"116", :"117", :"118", :"119", :"120",
:"121", :"122", :"123", :"124", :"125", :"126", :"127", :"128", :"129", :"130",
:"131", :"132", :"133", :"134", :"135", :"136", :"137", :"138", :"139", :"140",
:"141", :"142", :"143", :"144", :"145", :"146", :"147", :"148", :"149", :"150",
:"151", :"152", :"153", :"154", :"155", :"156", :"157", :"158", :"159", :"160",
:"161", :"162", :"163", :"164", :"165", :"166", :"167", :"168", :"169", :"170",
:"171", :"172", :"173", :"174", :"175", :"176", :"177", :"178", :"179", :"180",
:"181", :"182", :"183", :"184", :"185", :"186", :"187", :"188", :"189", :"190",
:"191", :"192", :"193", :"194", :"195", :"196", :"197", :"198", :"199", :"200",
...]
iex(2)> Enum.map(1..10_000_000, fn x -> String.to_atom("#{x}") end)
no more index entries in atom_tab (max=1048576)
Crash dump is being written to: erl_crash.dump...doneYou can look this up as "BEAM Atom Table Exhaustion"
| case spec.operation_attributes do | ||
| list when is_list(list) -> | ||
| list | ||
|
|
||
| other -> | ||
| raise ArgumentError, | ||
| "EXLA.CustomCall.Spec operation_attributes must be a list of {binary_key, binary_attr} pairs, got: #{inspect(other)}" | ||
| end |
There was a problem hiding this comment.
if is_list(spec.operation_attributes)
| import Nx.Defn | ||
|
|
||
| alias EXLA.Test.QRAliasBlock | ||
| alias EXLA.MLIR.{Function, Module, Value} |
There was a problem hiding this comment.
Let's avoid single-line alias expansion in favor of 3 separate aliases
polvalente
left a comment
There was a problem hiding this comment.
Looks good overall! I just left a couple quick comments and we can merge after they're dealt with
9f26fac to
9118b6a
Compare
| |> attr_dict() | ||
| end | ||
|
|
||
| @reserved_custom_call_attrs ~w(call_target_name api_version backend_config) |
There was a problem hiding this comment.
| @reserved_custom_call_attrs ~w(call_target_name api_version backend_config) | |
| @reserved_custom_call_attrs ["call_target_name", "api_version", "backend_config"] |
| "custom_call MLIR attribute names must be unique and cannot override EXLA attributes" | ||
| end | ||
|
|
||
| Enum.map(attributes, fn {name, attr} -> {String.to_atom(name), attr} end) |
There was a problem hiding this comment.
String.to_atom is still something that can't go on here. If there's code requiring atoms that uses the results here, it needs to be adapted to accept only strings instead.
There was a problem hiding this comment.
I changed exla.cc to accept string
9118b6a to
1d42bc6
Compare
1d42bc6 to
62ecad5
Compare
EXLA.CustomCall.Spec.attributesis serialized intobackend_config, so external custom calls cannot attach compiler-visible metadata tostablehlo.custom_call.Add
mlir_attributesas{name, value}strings emitted at the operation level, while preservingattributesas handler-visible backend configuration. Duplicate and EXLA-owned attribute names are rejected. Tests cover validation, StableHLO emission, the existing backend configuration path, and the compiled execution path.The external FlashAttention-3 experiment uses this API for layout constraints and a Shardy rule. Its performance measurements do not represent an Nx optimization: this change only makes compiler metadata expressible, and the measured throughput differences are not attributed to Nx or
mlir_attributes.Closes #1823