[llvm-branch-commits] [clang] [CIR] Implement ArgKind::Expand in CallConvLowering (PR #201718)

Andy Kaylor via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Jun 15 09:46:55 PDT 2026


================
@@ -328,19 +353,75 @@ void insertArgCoercion(FunctionOpInterface funcOp,
     return;
   Block &entry = body.front();
 
-  for (auto [idx, ac] : llvm::enumerate(fc.argInfos)) {
-    unsigned blockIdx = idx + sretOffset;
-    if (blockIdx >= entry.getNumArguments())
+  // Running block argument index.  Each non-Expand classification occupies
+  // one block argument slot; each Expand classification occupies N slots
+  // (one per struct field), so the running index must be incremented by N
+  // rather than 1 after processing an Expand arg.
+  unsigned blockArgIdx = sretOffset;
+
+  for (const ArgClassification &ac : fc.argInfos) {
+    assert(blockArgIdx < entry.getNumArguments() &&
+           "classification count must not exceed entry block arguments");
+
+    if (ac.kind == ArgKind::Expand) {
+      // The block arg at blockArgIdx currently has the original struct type.
+      // Replace it with N scalar args (one per field) and store each field
+      // directly into the parameter's own alloca.
+      BlockArgument origArg = entry.getArgument(blockArgIdx);
+      auto recTy = cast<cir::RecordType>(origArg.getType());
+      assert(recTy.isStruct() &&
+             "Expand classification requires a struct type, not a union");
+      unsigned numFields = recTy.getNumElements();
+      assert(numFields > 0 &&
+             "Expand classification requires at least one struct field");
+      Location loc = funcOp.getLoc();
+
+      // CIRGen spills every by-value struct parameter into its local alloca
+      // with a single store before any other use, so the struct block arg's
+      // only use is that store.  Capture it and the destination alloca, then
+      // store the expanded fields straight into that alloca and erase the
+      // original store.  This keeps the alloca's variable name and `init`
+      // flag and avoids a reassemble-then-reload roundtrip.
+      assert(origArg.hasOneUse() &&
----------------
andykaylor wrote:

We should probably also allow no uses. It's possible DCE could have been run before this and the store may have been eliminated.

https://github.com/llvm/llvm-project/pull/201718


More information about the llvm-branch-commits mailing list