================
@@ -901,6 +901,36 @@ void 
CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) {
   assert(!cir::MissingFeatures::incrementProfileCounter());
   assert(!cir::MissingFeatures::runCleanupsScope());
 
+  // For a memcpy-equivalent assignment operator, copy the whole object, then
+  // fall through to emit the trailing `return *this`.
+  if (assignOp->isMemcpyEquivalentSpecialMember(getContext())) {
+    CanQualType recordTy =
+        getContext().getCanonicalTagType(assignOp->getParent());
+    LValue dest = makeNaturalAlignAddrLValue(loadCXXThis(), recordTy);
+    mlir::Value srcPtr = builder.createLoad(getLoc(assignOp->getLocation()),
+                                            getAddrOfLocalVar(args.back()));
+    LValue src = makeNaturalAlignAddrLValue(srcPtr, recordTy);
+    emitAggregateAssign(dest, src, recordTy);
----------------
adams381 wrote:

This block is really doing two separate jobs, and only one of them needs the 
frontend.

For a trivially-copyable struct the AST already carries the work: per-field 
assignment expressions, plus a `__builtin_memcpy` call for array members. 
Dropping the whole-object copy and just emitting the body (which the non-memcpy 
path further down already does) is exactly the "reflect the AST and let 
optimization coalesce" behavior. The 
`assert(!MissingFeatures::assignMemcpyizer())` there is only the coalescing 
step; the per-field stores stand on their own and survive `-O3`. That case 
needs no frontend change.

The union is the one that can't go through that path. Its body is empty -- just 
`return *this` -- because Sema skips union fields at the FIXME in 
`SemaDeclCXX.cpp:15474` (copy) and `:15863` (move). There are no copies to 
leave, and a memcpyizer has nothing to coalesce on an empty body. That empty 
body is the original regression here: `*++yyvsp = yylval` in `kc`, where 
`YYSTYPE` is a union, whose no-op `operator=` LLVM deletes at `-O3`. Only a 
real AST node or this synthesis fills it.

So two ways forward, and I'd like your and @andykaylor's call before touching 
shared code (same scope question I raised on the other thread Jun 16):

1. Implement the FIXME -- form an AST node for the implied union memcpy in copy 
and move assignment. That fixes classic and CIR together and lets this PR drop 
the synthesis. It is a shared-AST change: it shifts classic union copy/move 
codegen, likely reaches constexpr handling, and updates existing CodeGen tests, 
and the FIXME has been open a long time, so I don't want to start it without a 
maintainer nod.
2. If that's more than this PR should carry, narrow it to the struct/array 
lowering and `errorNYI` the union body, then handle the union in its own PR 
once the AST question is settled.

Which do you prefer?


https://github.com/llvm/llvm-project/pull/198918
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to