Skip to content

Metal: express the intrinsic lowering as tables and small helpers - #941

Merged
maleadt merged 2 commits into
mainfrom
tb/intrinsic-tables
Sep 25, 2026
Merged

maleadt merged 2 commits into
mainfrom
tb/intrinsic-tables

Conversation

@maleadt

@maleadt maleadt commented Sep 24, 2026

Copy link
Copy Markdown
Member

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_INTRINSICS and REMOVABLE_INTRINSICS map LLVM intrinsics to their AIR functions.
  • declare! gets or creates a declaration, and checks that an existing one has the expected type; call_declared! and type_suffix cover 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, or nothing to keep the call). It doesn't iterate to a fixed point or erase anything else.
  • The minimum/maximum wrapper, copysign and is.fpclass lowerings 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

  • The generated code is unchanged: on a corpus of intrinsic calls (the math, value and bit intrinsics, minimum/maximum, copysign and is.fpclass, in scalar, vector and bfloat variants, with and without fast-math flags, and chained min/max), the output of lower_llvm_intrinsics! and of the full lower_air! is byte-identical to main for Metal 3.2/AIR 2.7, 4.0/2.8, 4.0/2.9 and 4.1/2.9.
  • It's also a bit faster: on a module with 19,000 instructions of intrinsic calls, 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).
  • GPUCompiler's metal tests pass on Julia 1.12 and 1.10.
  • Metal.jl's full test suite passes against this branch, except for examples/flopscomp, which fails because BFloat16s isn't installed in the test environment.

`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
maleadt force-pushed the tb/intrinsic-tables branch from 92fb5f4 to 829bc12 Compare September 25, 2026 07:51
@codecov

codecov Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.30769% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.42%. Comparing base (70ad652) to head (829bc12).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/metal.jl 92.30% 18 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@maleadt
maleadt merged commit 0f498ba into main Sep 25, 2026
31 of 33 checks passed
@maleadt
maleadt deleted the tb/intrinsic-tables branch September 25, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant