Metal: express the intrinsic lowering as tables and small helpers - #941
Merged
Merged
Conversation
`lower_llvm_intrinsics!` handled every intrinsic in one loop body, repeating the declaration lookup, the builder setup and the type mangling for each kind of intrinsic. Map the intrinsics to AIR through tables instead, and share the code through a few helpers: `declare!` (get or create a declaration, which must have the expected type), `call_declared!`, `type_suffix`, and `lower_intrinsic_calls!`, which collects the intrinsic calls of a function and replaces each by what a lowering function returns. The minimum/maximum wrapper, copysign and is.fpclass lowerings become separate functions. The generated code is unchanged. A declaration that already exists with a different type is now an error rather than silently called with the wrong type.
`LLVM.name` of an overloaded intrinsic calls `Intrinsic::getName(ID)`, which asserts that the intrinsic isn't overloaded: LLVM builds with assertions aborted when lowering, e.g., `llvm.sqrt`. Keep the tables keyed by name, but look the calls up by the intrinsics' IDs, as before.
maleadt
force-pushed
the
tb/intrinsic-tables
branch
from
September 25, 2026 07:51
92fb5f4 to
829bc12
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #941 +/- ##
==========================================
+ Coverage 86.32% 86.42% +0.09%
==========================================
Files 29 29
Lines 5756 5672 -84
==========================================
- Hits 4969 4902 -67
+ Misses 787 770 -17 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
lower_llvm_intrinsics!handled every intrinsic in one loop body, repeating the declaration lookup, builder setup and type mangling for each kind of intrinsic. This expresses the lowering as tables plus a few small helpers:AIR_MATH_INTRINSICS,AIR_VALUE_INTRINSICS,AIR_BIT_INTRINSICSandREMOVABLE_INTRINSICSmap LLVM intrinsics to their AIR functions.declare!gets or creates a declaration, and checks that an existing one has the expected type;call_declared!andtype_suffixcover the call and the mangling.lower_intrinsic_calls!collects the intrinsic calls of a function, then replaces each by what a lowering function returns (a value,:erase, ornothingto keep the call). It doesn't iterate to a fixed point or erase anything else.copysignandis.fpclasslowerings become separate functions.fuse_minmax3!keeps its fold-and-rescan loop.The section shrinks from 435 to 334 lines of code.
One behavior change: a declaration that already exists with a different type is now an error. Before, the lowering silently called it with the wrong type.
Verification
lower_llvm_intrinsics!and of the fulllower_air!is byte-identical tomainfor Metal 3.2/AIR 2.7, 4.0/2.8, 4.0/2.9 and 4.1/2.9.lower_llvm_intrinsics!takes 60 ms instead of 87 ms. On a 200,000-instruction module without calls it's on par (100 ms vs 102 ms).metaltests pass on Julia 1.12 and 1.10.examples/flopscomp, which fails because BFloat16s isn't installed in the test environment.