[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