llvm: improve IR attributes and cast flags for better optimization#21
Conversation
Emit several attributes and instruction flags that Clang emits for equivalent C/C++ but Zig was leaving on the table, allowing LLVM to perform optimizations it currently cannot: - `*T` / `*const T` parameters: add `dereferenceable(N)` (and `dereferenceable_or_null(N)` for `?*T`). Enables speculative loads, branch-to-select, and loop vectorization on conditional field reads. - by-ref / by-ref-mut aggregate parameters: add `noundef`, `align(N)`, `dereferenceable(N)`. The compiler synthesizes these pointers, so validity is guaranteed. - sret parameter: add `noundef`, `align(N)`, `dereferenceable(N)`, `writable`, `dead_on_unwind` (new in Builder). Enables call-slot elimination of the temporary alloca+memcpy. - `@intCast` in unchecked builds: stop emitting `llvm.assume(icmp ...)`, which strips `memory(none)` from any function containing a cast. Instead emit `trunc nuw/nsw` and `zext nneg` (new in Builder), which carry the same range guarantee with no side effects. - `fneg` under `@setFloatMode(.optimized)`: forward the `fast` flag. - `@branchHint(.cold)` at function scope: also add `optsize`, matching Clang's treatment of cold functions. - non-byte `@memset` open-coded loop: emit an index-counted loop instead of pointer-phi, giving SCEV a clean trip count. - anonymous unnamed_addr constants >= 16 bytes: over-align to 16 so memcpy lowering can use vector moves. Builder.zig gains the `writable`/`dead_on_unwind` parameter attributes and `trunc nuw/nsw`/`zext nneg` instruction tags (with bitcode encoding). Adds llvm_ir test cases for each.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
Disabled knowledge base sources:
WalkthroughAdds LLVM parameter attributes Changes
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/std/zig/llvm/ir.zig`:
- Around line 1537-1541: The packed struct named flags currently uses generic
field names bit0/bit1 which are easy to misuse; rename those fields to semantic
names (e.g., nuw and nsw) and add either a brief comment noting the special-case
mapping for zext (bit0 represents nneg) or add small helper accessors on the
flags type (e.g., isNuw(), isNsw(), isNneg()) so callers use semantic APIs
instead of raw bitN; update all uses of flags.bit0/bit1 to the new names or
helpers to keep opcode→bit mapping clear and maintainable.
In `@test/llvm_ir.zig`:
- Around line 160-175: Add a new test case that exercises the combined trunc
flags by calling cases.addMatches with a unique name like "intCast trunc nuw
nsw", using an export fn entry(x: i64) i32 { return `@intCast`(x); } (or an
appropriate signed/unsigned signature that triggers both nuw and nsw) and
include the expected LLVM match string "trunc nuw nsw i64" in the match array;
place it alongside the existing "intCast trunc nuw" and "intCast trunc nsw"
blocks so the .@"trunc nuw nsw" branch in src/codegen/llvm.zig is covered.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9494e6cb-b9e2-44c5-8b5f-2905f24a9620
📒 Files selected for processing (4)
lib/std/zig/llvm/Builder.ziglib/std/zig/llvm/ir.zigsrc/codegen/llvm.zigtest/llvm_ir.zig
| /// trunc: bit0 = nuw, bit1 = nsw. zext: bit0 = nneg. | ||
| flags: packed struct(u2) { | ||
| bit0: bool, | ||
| bit1: bool, | ||
| }, |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider naming cast flag bits semantically.
bit0 / bit1 are correct but easy to misuse later. Using semantic names (or a small helper type) would make opcode→bit mapping safer to maintain.
Optional readability tweak
- /// trunc: bit0 = nuw, bit1 = nsw. zext: bit0 = nneg.
- flags: packed struct(u2) {
- bit0: bool,
- bit1: bool,
- },
+ /// trunc: low = nuw, high = nsw. zext: low = nneg.
+ flags: packed struct(u2) {
+ low: bool,
+ high: bool,
+ },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /// trunc: bit0 = nuw, bit1 = nsw. zext: bit0 = nneg. | |
| flags: packed struct(u2) { | |
| bit0: bool, | |
| bit1: bool, | |
| }, | |
| /// trunc: low = nuw, high = nsw. zext: low = nneg. | |
| flags: packed struct(u2) { | |
| low: bool, | |
| high: bool, | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/std/zig/llvm/ir.zig` around lines 1537 - 1541, The packed struct named
flags currently uses generic field names bit0/bit1 which are easy to misuse;
rename those fields to semantic names (e.g., nuw and nsw) and add either a brief
comment noting the special-case mapping for zext (bit0 represents nneg) or add
small helper accessors on the flags type (e.g., isNuw(), isNsw(), isNneg()) so
callers use semantic APIs instead of raw bitN; update all uses of
flags.bit0/bit1 to the new names or helpers to keep opcode→bit mapping clear and
maintainable.
Picks up oven-sh/zig#21 which adds: - dereferenceable(N) on *T pointer params and by-ref aggregate params - writable/dead_on_unwind/noundef/align on sret - trunc nuw/nsw and zext nneg for unchecked @intcast (replaces llvm.assume so functions stay memory(none)) - fneg fast under @setFloatMode(.optimized) - optsize for @branchHint(.cold) functions - index-counted @Memset loop for non-byte elements - 16-byte over-align for large anonymous constants
Summary
Emit several LLVM IR attributes and instruction flags that Clang emits for equivalent C/C++ but Zig currently omits. Each was verified to produce measurably better optimized IR/asm (branch-to-select, vectorization, call-slot elimination, function purity).
dereferenceable(N)/dereferenceable_or_null(N)on*T/?*Tparamsnoundef+align+dereferenceableon by-ref aggregate params and sretwritable+dead_on_unwindon sret (new Builder attrs)trunc nuw/nsw/zext nnegfor unchecked@intCastinstead ofllvm.assume(keepsmemory(none))fastflag onfnegunder.optimizedfloat modeoptsizealongsidecoldfor@branchHint(.cold)functions@memset(SCEV-friendly)Test plan
zig build test-llvm-ir(13 existing + 10 new cases)llvm-disconfirms new attrs/flags encode correctly