[all-commits] [llvm/llvm-project] 421d29: [CIR] Lower sret returns in CallConvLowering (#201...

adams381 via All-commits all-commits at lists.llvm.org
Thu Jun 11 15:40:16 PDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 421d296893ed173846c0aceaee67cdafa67da07b
      https://github.com/llvm/llvm-project/commit/421d296893ed173846c0aceaee67cdafa67da07b
  Author: adams381 <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 (#201716)

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>

---------

Co-authored-by: Cursor <cursoragent at cursor.com>



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