Skip to content

Commit 52c9efb

Browse files
smeenailanza
authored andcommitted
[CIR][CIRGen] Call trivial assignment operators in more cases (#1196)
Our previous logic here was matching CodeGen, which folds trivial assignment operator calls into memcpys, but we want to avoid that. Note that we still end up emitting memcpys for arrays of classes with trivial assignment operators; #1177 tracks fixing that.
1 parent 671e312 commit 52c9efb

File tree

2 files changed

+34
-13
lines changed

2 files changed

+34
-13
lines changed

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -429,20 +429,11 @@ class AssignmentMemcpyizer : public FieldMemcpyizer {
429429
}
430430
return nullptr;
431431
} else if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(S)) {
432-
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MCE->getCalleeDecl());
433-
if (!(MD && isMemcpyEquivalentSpecialMember(MD)))
434-
return nullptr;
435-
MemberExpr *IOA = dyn_cast<MemberExpr>(MCE->getImplicitObjectArgument());
436-
if (!IOA)
437-
return nullptr;
438-
FieldDecl *Field = dyn_cast<FieldDecl>(IOA->getMemberDecl());
439-
if (!Field || !isMemcpyableField(Field))
440-
return nullptr;
441-
MemberExpr *Arg0 = dyn_cast<MemberExpr>(MCE->getArg(0));
442-
if (!Arg0 || Field != dyn_cast<FieldDecl>(Arg0->getMemberDecl()))
443-
return nullptr;
444-
return Field;
432+
// We want to represent all calls explicitly for analysis purposes.
433+
return nullptr;
445434
} else if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
435+
// TODO(cir): https://github.com/llvm/clangir/issues/1177: This can result
436+
// in memcpys instead of calls to trivial member functions.
446437
FunctionDecl *FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
447438
if (!FD || FD->getBuiltinID() != Builtin::BI__builtin_memcpy)
448439
return nullptr;

clang/test/CIR/CodeGen/assign-operator.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,33 @@ struct Trivial {
191191
void copyTrivial(Trivial &a, Trivial &b) {
192192
a = b;
193193
}
194+
195+
struct ContainsTrivial {
196+
Trivial t1;
197+
Trivial t2;
198+
ContainsTrivial &operator=(const ContainsTrivial &);
199+
};
200+
201+
// We should explicitly call operator= even for trivial types.
202+
// CHECK-LABEL: cir.func @_ZN15ContainsTrivialaSERKS_(
203+
// CHECK: cir.call @_ZN7TrivialaSERKS_(
204+
// CHECK: cir.call @_ZN7TrivialaSERKS_(
205+
ContainsTrivial &ContainsTrivial::operator=(const ContainsTrivial &) = default;
206+
207+
struct ContainsTrivialArray {
208+
Trivial arr[2];
209+
ContainsTrivialArray &operator=(const ContainsTrivialArray &);
210+
};
211+
212+
// We should be calling operator= here but don't currently.
213+
// CHECK-LABEL: cir.func @_ZN20ContainsTrivialArrayaSERKS_(
214+
// CHECK: %[[#THIS_LOAD:]] = cir.load deref %[[#]]
215+
// CHECK-NEXT: %[[#THIS_ARR:]] = cir.get_member %[[#THIS_LOAD]][0] {name = "arr"}
216+
// CHECK-NEXT: %[[#THIS_ARR_CAST:]] = cir.cast(bitcast, %[[#THIS_ARR]] : !cir.ptr<!cir.array<!ty_Trivial x 2>>), !cir.ptr<!void>
217+
// CHECK-NEXT: %[[#OTHER_LOAD:]] = cir.load %[[#]]
218+
// CHECK-NEXT: %[[#OTHER_ARR:]] = cir.get_member %[[#OTHER_LOAD]][0] {name = "arr"}
219+
// CHECK-NEXT: %[[#OTHER_ARR_CAST:]] = cir.cast(bitcast, %[[#OTHER_ARR]] : !cir.ptr<!cir.array<!ty_Trivial x 2>>), !cir.ptr<!void>
220+
// CHECK-NEXT: %[[#MEMCPY_SIZE:]] = cir.const #cir.int<80> : !u64i
221+
// CHECK-NEXT: cir.libc.memcpy %[[#MEMCPY_SIZE]] bytes from %[[#OTHER_ARR_CAST]] to %[[#THIS_ARR_CAST]]
222+
ContainsTrivialArray &
223+
ContainsTrivialArray::operator=(const ContainsTrivialArray &) = default;

0 commit comments

Comments
 (0)