[all-commits] [llvm/llvm-project] 2fef02: [CIR] Lower sret returns in CallConvLowering
adams381 via All-commits
all-commits at lists.llvm.org
Thu Jun 11 15:13:54 PDT 2026
Branch: refs/heads/users/adams381/cir-callconv-lowering-indirect-sret
Home: https://github.com/llvm/llvm-project
Commit: 2fef028edd0ad38c5ebbc7e8d6335592a6a66dca
https://github.com/llvm/llvm-project/commit/2fef028edd0ad38c5ebbc7e8d6335592a6a66dca
Author: Adam Smith <adams at nvidia.com>
Date: 2026-06-11 (Thu, 11 Jun 2026)
Changed paths:
M clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
M clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.h
A clang/test/CIR/Transforms/abi-lowering/indirect-return-sret.cir
Log Message:
-----------
[CIR] Lower sret returns in CallConvLowering
Functions that return an aggregate by value classify their return as
ArgKind::Indirect, but CallConvLowering reached an errorNYI for that
case, so the whole CallConv pass refused to lower any struct-returning
function.
rewriteFunctionDefinition now recognizes an Indirect return: the wire
return type becomes void, a hidden sret pointer is prepended as block
argument 0, and every cir.return is routed through that pointer. Rather
than storing the loaded return value through the sret pointer (a
byte-copy that breaks non-trivially-copyable types -- libstdc++'s SSO
std::string keeps a _M_p pointer into its own _M_local_buf, so a
byte-copy leaves the destination aliasing the source's dying stack
storage), insertSRetStores rewires the __retval alloca to the sret
pointer so construction flows directly into the caller's slot, matching
classic CodeGen's "construct into %agg.result" pattern. CIRGen emits one
cir.load __retval / cir.return pair per return statement, all reading the
single __retval alloca, so the alloca is rewired once and every return is
collapsed to a bare return. That cir.return (cir.load <alloca>) shape is
treated as an invariant and asserted with cast<> rather than guarded by a
fallback. The sret parameter carries sret(T) align A writable
dead_on_unwind, plus noalias on definitions.
rewriteCallSite prepends the return slot, makes the call return void,
and reads the result back. When the result has a single store-into-dest
use whose destination dominates the call, it reuses that destination as
the sret slot and drops the redundant store, so the callee writes
straight into the local with no copy; otherwise it allocates a fresh slot
and loads the value out. The slot's
per-argument attributes go through the same updateArgAttrs path as the
non-sret case, so sret composes with Extend (signext/zeroext) and Ignore
arguments.
byval indirect arguments and Expand are still errorNYI.
Co-authored-by: Cursor <cursoragent at cursor.com>
Commit: c92ec244a5574e505ef6dc38e7093cc710b3dda6
https://github.com/llvm/llvm-project/commit/c92ec244a5574e505ef6dc38e7093cc710b3dda6
Author: Adam Smith <adams at nvidia.com>
Date: 2026-06-11 (Thu, 11 Jun 2026)
Changed paths:
M clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
Log Message:
-----------
[CIR] Fix namespace, naming, and assert in sret
Remove `using namespace mlir;` from CIRABIRewriteContext.cpp
and qualify all MLIR-namespaced types explicitly with `mlir::`.
Rename `sretOffset` to `hasSRetArg` (bool) -- the name now
reflects that the value is either 0 or 1 and acts as a
presence flag, not an arbitrary offset. Rename `rewriter` to
`builder` throughout for consistency with the rest of the
calling-convention lowering code.
Assert in `insertSRetStores` that every `cir.return` in an sret
function carries an operand. CIRGen guarantees the invariant
`cir.return (cir.load %__retval)` for all returns in an
aggregate-returning function; a bare return would indicate the
sret slot was never written, which is a bug. The previous
`continue` silently ignored that case.
Add an explanatory comment at the `replaceAllUsesWith` call so
it is clear why erasing the alloca immediately after is safe,
and add a comment at the void `ReturnOp::create` call noting
that the operand-free return is intentional -- the sret pointer
now carries the value.
Commit: ebae861b381deb3abd4fb701649c2cd4f9c77bf9
https://github.com/llvm/llvm-project/commit/ebae861b381deb3abd4fb701649c2cd4f9c77bf9
Author: Adam Smith <adams at nvidia.com>
Date: 2026-06-11 (Thu, 11 Jun 2026)
Changed paths:
M clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
M clang/test/CIR/Transforms/abi-lowering/indirect-return-sret.cir
Log Message:
-----------
[CIR] NFC: Address sret review feedback in CallConvLowering
Apply andykaylor's second-round feedback on the sret lowering.
All source changes are behavior-preserving:
- Use llvm::append_range when copying arg_attrs into the sret
call's and the definition's attribute lists.
- Replace the manual pad loop in applySretSlotAttrs with an
assert plus resize to the rewritten operand count.
- Rename the Ignore-drop loop's index variables so the outer
one (argInfoIdx) indexes fc.argInfos and the inner one
(blockIdx) is the real block-argument index, matching the
convention insertArgCoercion already uses.
- Clarify the "hidden pointer" comments: the sret pointer is
synthesized by the ABI and is not part of the source-level
signature.
- Note why the llvm.sret attribute must carry the return type
explicitly, since LLVM pointers are opaque once lowered.
Extend the sret test: bind the a/b destination allocas in the
multi-use caller so the loaded value's stores are unambiguous,
anchor the argument-attribute dictionary braces, and add a
multi-return function whose value is constructed in place via a
call into __retval, so both returns route through the sret
pointer with no store to the sret slot.
Commit: 4877b5b31a3e621e7ba8848cd9649bd3b467148e
https://github.com/llvm/llvm-project/commit/4877b5b31a3e621e7ba8848cd9649bd3b467148e
Author: Adam Smith <adams at nvidia.com>
Date: 2026-06-11 (Thu, 11 Jun 2026)
Changed paths:
M clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
Log Message:
-----------
[CIR] NFC: Extract rewriteIndirectReturnCall helper
The sret call-site rewrite was a large block inside rewriteCallSite.
Move it into a dedicated rewriteIndirectReturnCall helper in the
anonymous namespace, leaving rewriteCallSite to dispatch to it when the
return is indirect.
Pure code motion: the Indirect-and-has-result guard stays at the call
site (the moved block dereferences the call result, so the guard cannot
fold into the helper), and the helper derives its MLIR context from the
call. No behavior change.
Commit: 2f1ba3d1d12249af90734e10d4e01ec8a64aa8ed
https://github.com/llvm/llvm-project/commit/2f1ba3d1d12249af90734e10d4e01ec8a64aa8ed
Author: Adam Smith <adams at nvidia.com>
Date: 2026-06-11 (Thu, 11 Jun 2026)
Changed paths:
M clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
M clang/test/CIR/Transforms/abi-lowering/indirect-return-sret.cir
Log Message:
-----------
[CIR] NFC: Drop redundant llvm:: qualifiers in sret lowering
Restore `using namespace mlir;` in CIRABIRewriteContext.cpp so the LLVM
ADT names re-exported into the mlir namespace (SmallVector, ArrayRef,
StringRef, SmallPtrSet, function_ref) are in scope without an explicit
llvm:: qualifier. An earlier review fixup had removed the directive and
qualified every ADT type with llvm::, over-applying the qualifier to
unambiguous names.
llvm:: is kept on the free functions mlir does not re-export (enumerate,
any_of, append_range), and mlir:: stays explicit on MLIR types. No
functional change.
Compare: https://github.com/llvm/llvm-project/compare/2c18daee8c46...2f1ba3d1d122
To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications
More information about the All-commits
mailing list