blob: 3b0b17319878750a40bd8ec2e9e9514d97d608f2 [file] [log] [blame]
Akira Hatanaka7275da02018-02-28 07:15:55 +00001//===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines functions to generate various special functions for C
11// structs.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CodeGenFunction.h"
16#include "CodeGenModule.h"
17#include "llvm/Support/ScopedPrinter.h"
18#include <array>
19
20using namespace clang;
21using namespace CodeGen;
22
23// Return the size of a field in number of bits.
24static uint64_t getFieldSize(const FieldDecl *FD, ASTContext &Ctx) {
25 if (FD->isBitField())
26 return FD->getBitWidthValue(Ctx);
27 return Ctx.getTypeSize(FD->getType());
28}
29
30namespace {
31enum { DstIdx = 0, SrcIdx = 1 };
32const char *ValNameStr[2] = {"dst", "src"};
33
34template <class Derived, class RetTy = void> struct DestructedTypeVisitor {
35 template <class... Ts> RetTy visit(QualType FT, Ts &&... Args) {
36 return asDerived().visit(FT.isDestructedType(), FT,
37 std::forward<Ts>(Args)...);
38 }
39
40 template <class... Ts>
41 RetTy visit(QualType::DestructionKind DK, QualType FT, Ts &&... Args) {
42 if (asDerived().getContext().getAsArrayType(FT))
43 return asDerived().visitArray(DK, FT, std::forward<Ts>(Args)...);
44
45 switch (DK) {
46 case QualType::DK_objc_strong_lifetime:
47 return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
48 case QualType::DK_nontrivial_c_struct:
49 return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
50 case QualType::DK_none:
51 return asDerived().visitTrivial(FT, std::forward<Ts>(Args)...);
52 case QualType::DK_cxx_destructor:
53 return asDerived().visitCXXDestructor(FT, std::forward<Ts>(Args)...);
54 case QualType::DK_objc_weak_lifetime:
55 return asDerived().visitARCWeak(FT, std::forward<Ts>(Args)...);
56 }
57
58 llvm_unreachable("unknown destruction kind");
59 }
60
61 Derived &asDerived() { return static_cast<Derived &>(*this); }
62};
63
64template <class Derived, class RetTy = void>
65struct DefaultInitializedTypeVisitor {
66 template <class... Ts> RetTy visit(QualType FT, Ts &&... Args) {
67 return asDerived().visit(FT.isNonTrivialToPrimitiveDefaultInitialize(), FT,
68 std::forward<Ts>(Args)...);
69 }
70
71 template <class... Ts>
72 RetTy visit(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
73 Ts &&... Args) {
74 if (asDerived().getContext().getAsArrayType(FT))
75 return asDerived().visitArray(PDIK, FT, std::forward<Ts>(Args)...);
76
77 switch (PDIK) {
78 case QualType::PDIK_ARCStrong:
79 return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
80 case QualType::PDIK_Struct:
81 return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
82 case QualType::PDIK_Trivial:
83 return asDerived().visitTrivial(FT, std::forward<Ts>(Args)...);
84 }
85
86 llvm_unreachable("unknown default-initialize kind");
87 }
88
89 Derived &asDerived() { return static_cast<Derived &>(*this); }
90};
91
92template <class Derived, bool IsMove, class RetTy = void>
93struct CopiedTypeVisitor {
94 template <class... Ts> RetTy visit(QualType FT, Ts &&... Args) {
95 QualType::PrimitiveCopyKind PCK =
96 IsMove ? FT.isNonTrivialToPrimitiveDestructiveMove()
97 : FT.isNonTrivialToPrimitiveCopy();
98 return asDerived().visit(PCK, FT, std::forward<Ts>(Args)...);
99 }
100
101 template <class... Ts>
102 RetTy visit(QualType::PrimitiveCopyKind PCK, QualType FT, Ts &&... Args) {
103 asDerived().preVisit(PCK, FT, std::forward<Ts>(Args)...);
104
105 if (asDerived().getContext().getAsArrayType(FT))
106 return asDerived().visitArray(PCK, FT, std::forward<Ts>(Args)...);
107
108 switch (PCK) {
109 case QualType::PCK_ARCStrong:
110 return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
111 case QualType::PCK_Struct:
112 return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
113 case QualType::PCK_Trivial:
114 return asDerived().visitTrivial(FT, std::forward<Ts>(Args)...);
115 case QualType::PCK_VolatileTrivial:
116 return asDerived().visitVolatileTrivial(FT, std::forward<Ts>(Args)...);
117 }
118
119 llvm_unreachable("unknown primitive copy kind");
120 }
121
122 Derived &asDerived() { return static_cast<Derived &>(*this); }
123};
124
125template <class Derived> struct StructVisitor {
126 StructVisitor(ASTContext &Ctx) : Ctx(Ctx) {}
127
128 template <class... Ts>
129 void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) {
130 const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
131
132 // Iterate over the fields of the struct.
133 for (const FieldDecl *FD : RD->fields()) {
134 QualType FT = FD->getType();
135 FT = QT.isVolatileQualified() ? FT.withVolatile() : FT;
136 asDerived().visit(FT, FD, CurStructOffset, Args...);
137 }
138
139 asDerived().flushTrivialFields(Args...);
140 }
141
142 template <class... Ts> void visitTrivial(Ts... Args) {}
143
Akira Hatanakabe7daa32018-03-12 17:05:06 +0000144 template <class... Ts> void visitARCWeak(Ts... Args) {
145 // FIXME: remove this when visitARCWeak is implemented in the subclasses.
146 llvm_unreachable("weak field is not expected");
147 }
148
Akira Hatanaka7275da02018-02-28 07:15:55 +0000149 template <class... Ts> void visitCXXDestructor(Ts... Args) {
150 llvm_unreachable("field of a C++ struct type is not expected");
151 }
152
153 template <class... Ts> void flushTrivialFields(Ts... Args) {}
154
155 uint64_t getFieldOffsetInBits(const FieldDecl *FD) {
156 return FD ? Ctx.getASTRecordLayout(FD->getParent())
157 .getFieldOffset(FD->getFieldIndex())
158 : 0;
159 }
160
161 CharUnits getFieldOffset(const FieldDecl *FD) {
162 return Ctx.toCharUnitsFromBits(getFieldOffsetInBits(FD));
163 }
164
165 Derived &asDerived() { return static_cast<Derived &>(*this); }
166
167 ASTContext &getContext() { return Ctx; }
168 ASTContext &Ctx;
169};
170
171template <class Derived, bool IsMove>
172struct CopyStructVisitor : StructVisitor<Derived>,
173 CopiedTypeVisitor<Derived, IsMove> {
174 using StructVisitor<Derived>::asDerived;
175
176 CopyStructVisitor(ASTContext &Ctx) : StructVisitor<Derived>(Ctx) {}
177
178 template <class... Ts>
179 void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,
180 const FieldDecl *FD, CharUnits CurStructOffsset,
181 Ts &&... Args) {
182 if (PCK)
183 asDerived().flushTrivialFields(std::forward<Ts>(Args)...);
184 }
185
186 template <class... Ts>
187 void visitTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset,
188 Ts... Args) {
189 assert(!FT.isVolatileQualified() && "volatile field not expected");
190 ASTContext &Ctx = asDerived().getContext();
191 uint64_t FieldSize = getFieldSize(FD, Ctx);
192
193 // Ignore zero-sized fields.
194 if (FieldSize == 0)
195 return;
196
197 uint64_t FStartInBits = asDerived().getFieldOffsetInBits(FD);
198 uint64_t FEndInBits = FStartInBits + FieldSize;
199 uint64_t RoundedFEnd = llvm::alignTo(FEndInBits, Ctx.getCharWidth());
200
201 // Set Start if this is the first field of a sequence of trivial fields.
202 if (Start == End)
203 Start = CurStructOffset + Ctx.toCharUnitsFromBits(FStartInBits);
204 End = CurStructOffset + Ctx.toCharUnitsFromBits(RoundedFEnd);
205 }
206
207 CharUnits Start = CharUnits::Zero(), End = CharUnits::Zero();
208};
209
210// This function creates the mangled name of a special function of a non-trivial
211// C struct. Since there is no ODR in C, the function is mangled based on the
212// struct contents and not the name. The mangled name has the following
213// structure:
214//
215// <function-name> ::= <prefix> <alignment-info> "_" <struct-field-info>
216// <prefix> ::= "__destructor_" | "__default_constructor_" |
217// "__copy_constructor_" | "__move_constructor_" |
218// "__copy_assignment_" | "__move_assignment_"
219// <alignment-info> ::= <dst-alignment> ["_" <src-alignment>]
220// <struct-field-info> ::= <field-info>+
221// <field-info> ::= <struct-or-scalar-field-info> | <array-field-info>
222// <struct-or-scalar-field-info> ::= <struct-field-info> | <strong-field-info> |
223// <trivial-field-info>
224// <array-field-info> ::= "_AB" <array-offset> "s" <element-size> "n"
225// <num-elements> <innermost-element-info> "_AE"
226// <innermost-element-info> ::= <struct-or-scalar-field-info>
227// <strong-field-info> ::= "_s" ["b"] ["v"] <field-offset>
228// <trivial-field-info> ::= "_t" ["v"] <field-offset> "_" <field-size>
229
230template <class Derived> struct GenFuncNameBase {
231 std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) {
232 std::string S;
233 if (IsVolatile)
234 S = "v";
235 S += llvm::to_string(Offset.getQuantity());
236 return S;
237 }
238
239 void visitARCStrong(QualType FT, const FieldDecl *FD,
240 CharUnits CurStructOffset) {
241 appendStr("_s");
242 if (FT->isBlockPointerType())
243 appendStr("b");
244 CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
245 appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
246 }
247
248 void visitStruct(QualType QT, const FieldDecl *FD,
249 CharUnits CurStructOffset) {
250 CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
251 asDerived().visitStructFields(QT, FieldOffset);
252 }
253
254 template <class FieldKind>
255 void visitArray(FieldKind FK, QualType QT, const FieldDecl *FD,
256 CharUnits CurStructOffset) {
257 // String for non-volatile trivial fields is emitted when
258 // flushTrivialFields is called.
259 if (!FK)
260 return asDerived().visitTrivial(QT, FD, CurStructOffset);
261
262 CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
263 ASTContext &Ctx = asDerived().getContext();
264 const auto *AT = Ctx.getAsConstantArrayType(QT);
265 unsigned NumElts = Ctx.getConstantArrayElementCount(AT);
266 QualType EltTy = Ctx.getBaseElementType(AT);
267 CharUnits EltSize = Ctx.getTypeSizeInChars(EltTy);
268 appendStr("_AB" + llvm::to_string(FieldOffset.getQuantity()) + "s" +
269 llvm::to_string(EltSize.getQuantity()) + "n" +
270 llvm::to_string(NumElts));
271 EltTy = QT.isVolatileQualified() ? EltTy.withVolatile() : EltTy;
272 asDerived().visit(FK, EltTy, nullptr, FieldOffset);
273 appendStr("_AE");
274 }
275
276 void appendStr(StringRef Str) { Name += Str; }
277
278 std::string getName(QualType QT, bool IsVolatile) {
279 QT = IsVolatile ? QT.withVolatile() : QT;
280 asDerived().visitStructFields(QT, CharUnits::Zero());
281 return Name;
282 }
283
284 Derived &asDerived() { return static_cast<Derived &>(*this); }
285
286 std::string Name;
287};
288
289template <class Derived>
290struct GenUnaryFuncName : StructVisitor<Derived>, GenFuncNameBase<Derived> {
291 GenUnaryFuncName(StringRef Prefix, CharUnits DstAlignment, ASTContext &Ctx)
292 : StructVisitor<Derived>(Ctx) {
293 this->appendStr(Prefix);
294 this->appendStr(llvm::to_string(DstAlignment.getQuantity()));
295 }
296};
297
298// Helper function to create a null constant.
299static llvm::Constant *getNullForVariable(Address Addr) {
300 llvm::Type *Ty = Addr.getElementType();
301 return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(Ty));
302}
303
304template <bool IsMove>
305struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,
306 GenFuncNameBase<GenBinaryFuncName<IsMove>> {
307
308 GenBinaryFuncName(StringRef Prefix, CharUnits DstAlignment,
309 CharUnits SrcAlignment, ASTContext &Ctx)
310 : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>(Ctx) {
311 this->appendStr(Prefix);
312 this->appendStr(llvm::to_string(DstAlignment.getQuantity()));
313 this->appendStr("_" + llvm::to_string(SrcAlignment.getQuantity()));
314 }
315
316 void flushTrivialFields() {
317 if (this->Start == this->End)
318 return;
319
320 this->appendStr("_t" + llvm::to_string(this->Start.getQuantity()) + "w" +
321 llvm::to_string((this->End - this->Start).getQuantity()));
322
323 this->Start = this->End = CharUnits::Zero();
324 }
325
326 void visitVolatileTrivial(QualType FT, const FieldDecl *FD,
327 CharUnits CurStackOffset) {
328 // Because volatile fields can be bit-fields and are individually copied,
329 // their offset and width are in bits.
330 uint64_t OffsetInBits =
331 this->Ctx.toBits(CurStackOffset) + this->getFieldOffsetInBits(FD);
332 this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +
333 llvm::to_string(getFieldSize(FD, this->Ctx)));
334 }
335};
336
337struct GenDefaultInitializeFuncName
338 : GenUnaryFuncName<GenDefaultInitializeFuncName>,
339 DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName> {
340 GenDefaultInitializeFuncName(CharUnits DstAlignment, ASTContext &Ctx)
341 : GenUnaryFuncName<GenDefaultInitializeFuncName>("__default_constructor_",
342 DstAlignment, Ctx) {}
343};
344
345struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>,
346 DestructedTypeVisitor<GenDestructorFuncName> {
347 GenDestructorFuncName(CharUnits DstAlignment, ASTContext &Ctx)
348 : GenUnaryFuncName<GenDestructorFuncName>("__destructor_", DstAlignment,
349 Ctx) {}
350};
351
352// Helper function that creates CGFunctionInfo for an N-ary special function.
353template <size_t N>
354static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM,
355 FunctionArgList &Args) {
356 ASTContext &Ctx = CGM.getContext();
357 llvm::SmallVector<ImplicitParamDecl *, N> Params;
358 QualType ParamTy = Ctx.getPointerType(Ctx.VoidPtrTy);
359
360 for (unsigned I = 0; I < N; ++I)
361 Params.push_back(ImplicitParamDecl::Create(
362 Ctx, nullptr, SourceLocation(), &Ctx.Idents.get(ValNameStr[I]), ParamTy,
363 ImplicitParamDecl::Other));
364
365 for (auto &P : Params)
366 Args.push_back(P);
367
368 return CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
369}
370
371// Template classes that are used as bases for classes that emit special
372// functions.
373template <class Derived> struct GenFuncBase {
374 template <size_t N>
375 void visitStruct(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset,
376 std::array<Address, N> Addrs) {
377 this->asDerived().callSpecialFunction(
378 FT, CurStackOffset + asDerived().getFieldOffset(FD), Addrs);
379 }
380
381 template <class FieldKind, size_t N>
382 void visitArray(FieldKind FK, QualType QT, const FieldDecl *FD,
383 CharUnits CurStackOffset, std::array<Address, N> Addrs) {
384 // Non-volatile trivial fields are copied when flushTrivialFields is called.
385 if (!FK)
386 return asDerived().visitTrivial(QT, FD, CurStackOffset, Addrs);
387
388 CodeGenFunction &CGF = *this->CGF;
389 ASTContext &Ctx = CGF.getContext();
390
391 // Compute the end address.
392 QualType BaseEltQT;
393 std::array<Address, N> StartAddrs = Addrs;
394 for (unsigned I = 0; I < N; ++I)
395 StartAddrs[I] = getAddrWithOffset(Addrs[I], CurStackOffset, FD);
396 Address DstAddr = StartAddrs[DstIdx];
397 llvm::Value *NumElts =
398 CGF.emitArrayLength(Ctx.getAsArrayType(QT), BaseEltQT, DstAddr);
399 unsigned BaseEltSize = Ctx.getTypeSizeInChars(BaseEltQT).getQuantity();
400 llvm::Value *BaseEltSizeVal =
401 llvm::ConstantInt::get(NumElts->getType(), BaseEltSize);
402 llvm::Value *SizeInBytes =
403 CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts);
404 Address BC = CGF.Builder.CreateBitCast(DstAddr, CGF.CGM.Int8PtrTy);
405 llvm::Value *DstArrayEnd =
406 CGF.Builder.CreateInBoundsGEP(BC.getPointer(), SizeInBytes);
407 DstArrayEnd = CGF.Builder.CreateBitCast(DstArrayEnd, CGF.CGM.Int8PtrPtrTy,
408 "dstarray.end");
409 llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock();
410
411 // Create the header block and insert the phi instructions.
412 llvm::BasicBlock *HeaderBB = CGF.createBasicBlock("loop.header");
413 CGF.EmitBlock(HeaderBB);
414 llvm::PHINode *PHIs[N];
415
416 for (unsigned I = 0; I < N; ++I) {
417 PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur");
418 PHIs[I]->addIncoming(StartAddrs[I].getPointer(), PreheaderBB);
419 }
420
421 // Create the exit and loop body blocks.
422 llvm::BasicBlock *ExitBB = CGF.createBasicBlock("loop.exit");
423 llvm::BasicBlock *LoopBB = CGF.createBasicBlock("loop.body");
424
425 // Emit the comparison and conditional branch instruction that jumps to
426 // either the exit or the loop body.
427 llvm::Value *Done =
428 CGF.Builder.CreateICmpEQ(PHIs[DstIdx], DstArrayEnd, "done");
429 CGF.Builder.CreateCondBr(Done, ExitBB, LoopBB);
430
431 // Visit the element of the array in the loop body.
432 CGF.EmitBlock(LoopBB);
433 QualType EltQT = Ctx.getAsArrayType(QT)->getElementType();
434 CharUnits EltSize = Ctx.getTypeSizeInChars(EltQT);
435 std::array<Address, N> NewAddrs = Addrs;
436
437 for (unsigned I = 0; I < N; ++I)
438 NewAddrs[I] = Address(
439 PHIs[I], StartAddrs[I].getAlignment().alignmentAtOffset(EltSize));
440
441 EltQT = QT.isVolatileQualified() ? EltQT.withVolatile() : EltQT;
442 this->asDerived().visit(EltQT, nullptr, CharUnits::Zero(), NewAddrs);
443
444 LoopBB = CGF.Builder.GetInsertBlock();
445
446 for (unsigned I = 0; I < N; ++I) {
447 // Instrs to update the destination and source addresses.
448 // Update phi instructions.
449 NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize);
450 PHIs[I]->addIncoming(NewAddrs[I].getPointer(), LoopBB);
451 }
452
453 // Insert an unconditional branch to the header block.
454 CGF.Builder.CreateBr(HeaderBB);
455 CGF.EmitBlock(ExitBB);
456 }
457
458 /// Return an address with the specified offset from the passed address.
459 Address getAddrWithOffset(Address Addr, CharUnits Offset) {
460 assert(Addr.isValid() && "invalid address");
461 if (Offset.getQuantity() == 0)
462 return Addr;
463 Addr = CGF->Builder.CreateBitCast(Addr, CGF->CGM.Int8PtrTy);
464 Addr = CGF->Builder.CreateConstInBoundsGEP(Addr, Offset.getQuantity(),
465 CharUnits::One());
466 return CGF->Builder.CreateBitCast(Addr, CGF->CGM.Int8PtrPtrTy);
467 }
468
469 Address getAddrWithOffset(Address Addr, CharUnits StructFieldOffset,
470 const FieldDecl *FD) {
471 return getAddrWithOffset(Addr, StructFieldOffset +
472 asDerived().getFieldOffset(FD));
473 }
474
475 template <size_t N>
476 llvm::Function *
477 getFunction(StringRef FuncName, QualType QT, std::array<Address, N> Addrs,
478 std::array<CharUnits, N> Alignments, CodeGenModule &CGM) {
479 // If the special function already exists in the module, return it.
480 if (llvm::Function *F = CGM.getModule().getFunction(FuncName)) {
481 bool WrongType = false;
482 if (!F->getReturnType()->isVoidTy())
483 WrongType = true;
484 else {
485 for (const llvm::Argument &Arg : F->args())
486 if (Arg.getType() != CGM.Int8PtrPtrTy)
487 WrongType = true;
488 }
489
490 if (WrongType) {
491 std::string FuncName = F->getName();
492 SourceLocation Loc = QT->castAs<RecordType>()->getDecl()->getLocation();
493 CGM.Error(Loc, "special function " + FuncName +
494 " for non-trivial C struct has incorrect type");
495 return nullptr;
496 }
497 return F;
498 }
499
500 ASTContext &Ctx = CGM.getContext();
501 FunctionArgList Args;
502 const CGFunctionInfo &FI = getFunctionInfo<N>(CGM, Args);
503 llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);
504 llvm::Function *F =
505 llvm::Function::Create(FuncTy, llvm::GlobalValue::LinkOnceODRLinkage,
506 FuncName, &CGM.getModule());
507 F->setVisibility(llvm::GlobalValue::HiddenVisibility);
508 CGM.SetLLVMFunctionAttributes(nullptr, FI, F);
509 CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F);
510 IdentifierInfo *II = &Ctx.Idents.get(FuncName);
511 FunctionDecl *FD = FunctionDecl::Create(
512 Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
513 II, Ctx.VoidTy, nullptr, SC_PrivateExtern, false, false);
514 CodeGenFunction NewCGF(CGM);
515 setCGF(&NewCGF);
516 CGF->StartFunction(FD, Ctx.VoidTy, F, FI, Args);
517
518 for (unsigned I = 0; I < N; ++I) {
519 llvm::Value *V = CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[I]));
520 Addrs[I] = Address(V, Alignments[I]);
521 }
522
523 asDerived().visitStructFields(QT, CharUnits::Zero(), Addrs);
524 CGF->FinishFunction();
525 return F;
526 }
527
528 template <size_t N>
529 void callFunc(StringRef FuncName, QualType QT, std::array<Address, N> Addrs,
530 CodeGenFunction &CallerCGF) {
531 std::array<CharUnits, N> Alignments;
532 llvm::Value *Ptrs[N];
533
534 for (unsigned I = 0; I < N; ++I) {
535 Alignments[I] = Addrs[I].getAlignment();
536 Ptrs[I] =
537 CallerCGF.Builder.CreateBitCast(Addrs[I], CallerCGF.CGM.Int8PtrPtrTy)
538 .getPointer();
539 }
540
541 if (llvm::Function *F =
542 getFunction(FuncName, QT, Addrs, Alignments, CallerCGF.CGM))
543 CallerCGF.EmitNounwindRuntimeCall(F, Ptrs);
544 }
545
546 Derived &asDerived() { return static_cast<Derived &>(*this); }
547
548 void setCGF(CodeGenFunction *F) { CGF = F; }
549
550 CodeGenFunction *CGF = nullptr;
551};
552
553template <class Derived, bool IsMove>
554struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,
555 GenFuncBase<Derived> {
556 GenBinaryFunc(ASTContext &Ctx) : CopyStructVisitor<Derived, IsMove>(Ctx) {}
557
558 void flushTrivialFields(std::array<Address, 2> Addrs) {
559 CharUnits Size = this->End - this->Start;
560
561 if (Size.getQuantity() == 0)
562 return;
563
564 Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], this->Start);
565 Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], this->Start);
566
567 // Emit memcpy.
568 if (Size.getQuantity() >= 16 || !llvm::isPowerOf2_32(Size.getQuantity())) {
569 llvm::Value *SizeVal =
570 llvm::ConstantInt::get(this->CGF->SizeTy, Size.getQuantity());
571 DstAddr =
572 this->CGF->Builder.CreateElementBitCast(DstAddr, this->CGF->Int8Ty);
573 SrcAddr =
574 this->CGF->Builder.CreateElementBitCast(SrcAddr, this->CGF->Int8Ty);
575 this->CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, false);
576 } else {
577 llvm::Type *Ty = llvm::Type::getIntNTy(
578 this->CGF->getLLVMContext(),
579 Size.getQuantity() * this->CGF->getContext().getCharWidth());
580 DstAddr = this->CGF->Builder.CreateElementBitCast(DstAddr, Ty);
581 SrcAddr = this->CGF->Builder.CreateElementBitCast(SrcAddr, Ty);
582 llvm::Value *SrcVal = this->CGF->Builder.CreateLoad(SrcAddr, false);
583 this->CGF->Builder.CreateStore(SrcVal, DstAddr, false);
584 }
585
586 this->Start = this->End = CharUnits::Zero();
587 }
588
589 template <class... Ts>
590 void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits Offset,
591 std::array<Address, 2> Addrs) {
592 QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0);
593 llvm::PointerType *PtrTy = this->CGF->ConvertType(RT)->getPointerTo();
594 Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset);
595 LValue DstBase = this->CGF->MakeAddrLValue(
596 this->CGF->Builder.CreateBitCast(DstAddr, PtrTy), FT);
597 LValue DstLV = this->CGF->EmitLValueForField(DstBase, FD);
598 Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], Offset);
599 LValue SrcBase = this->CGF->MakeAddrLValue(
600 this->CGF->Builder.CreateBitCast(SrcAddr, PtrTy), FT);
601 LValue SrcLV = this->CGF->EmitLValueForField(SrcBase, FD);
602 RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());
603 this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);
604 }
605};
606
607// These classes that emit the special functions for a non-trivial struct.
608struct GenDestructor : StructVisitor<GenDestructor>,
609 GenFuncBase<GenDestructor>,
610 DestructedTypeVisitor<GenDestructor> {
611 GenDestructor(ASTContext &Ctx) : StructVisitor<GenDestructor>(Ctx) {}
612 void visitARCStrong(QualType QT, const FieldDecl *FD,
613 CharUnits CurStackOffset, std::array<Address, 1> Addrs) {
614 CGF->destroyARCStrongImprecise(
615 *CGF, getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
616 }
617
618 void callSpecialFunction(QualType FT, CharUnits Offset,
619 std::array<Address, 1> Addrs) {
620 CGF->callCStructDestructor(
621 CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));
622 }
623};
624
625struct GenDefaultInitialize
626 : StructVisitor<GenDefaultInitialize>,
627 GenFuncBase<GenDefaultInitialize>,
628 DefaultInitializedTypeVisitor<GenDefaultInitialize> {
629 typedef GenFuncBase<GenDefaultInitialize> GenFuncBaseTy;
630 GenDefaultInitialize(ASTContext &Ctx)
631 : StructVisitor<GenDefaultInitialize>(Ctx) {}
632
633 void visitARCStrong(QualType QT, const FieldDecl *FD,
634 CharUnits CurStackOffset, std::array<Address, 1> Addrs) {
635 CGF->EmitNullInitialization(
636 getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
637 }
638
639 template <class FieldKind, size_t... Is>
640 void visitArray(FieldKind FK, QualType QT, const FieldDecl *FD,
641 CharUnits CurStackOffset, std::array<Address, 1> Addrs) {
642 if (!FK)
643 return visitTrivial(QT, FD, CurStackOffset, Addrs);
644
645 ASTContext &Ctx = getContext();
646 CharUnits Size = Ctx.getTypeSizeInChars(QT);
647 QualType EltTy = Ctx.getBaseElementType(QT);
648
649 if (Size < CharUnits::fromQuantity(16) || EltTy->getAs<RecordType>()) {
650 GenFuncBaseTy::visitArray(FK, QT, FD, CurStackOffset, Addrs);
651 return;
652 }
653
654 llvm::Constant *SizeVal = CGF->Builder.getInt64(Size.getQuantity());
655 Address DstAddr = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
656 Address Loc = CGF->Builder.CreateElementBitCast(DstAddr, CGF->Int8Ty);
657 CGF->Builder.CreateMemSet(Loc, CGF->Builder.getInt8(0), SizeVal,
658 QT.isVolatileQualified());
659 }
660
661 void callSpecialFunction(QualType FT, CharUnits Offset,
662 std::array<Address, 1> Addrs) {
663 CGF->callCStructDefaultConstructor(
664 CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));
665 }
666};
667
668struct GenCopyConstructor : GenBinaryFunc<GenCopyConstructor, false> {
669 GenCopyConstructor(ASTContext &Ctx)
670 : GenBinaryFunc<GenCopyConstructor, false>(Ctx) {}
671
672 void visitARCStrong(QualType QT, const FieldDecl *FD,
673 CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
674 Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
675 Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
676 llvm::Value *SrcVal = CGF->EmitLoadOfScalar(
677 Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());
678 llvm::Value *Val = CGF->EmitARCRetain(QT, SrcVal);
679 CGF->EmitStoreOfScalar(Val, CGF->MakeAddrLValue(Addrs[DstIdx], QT), true);
680 }
681 void callSpecialFunction(QualType FT, CharUnits Offset,
682 std::array<Address, 2> Addrs) {
683 CGF->callCStructCopyConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
684 CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
685 }
686};
687
688struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> {
689 GenMoveConstructor(ASTContext &Ctx)
690 : GenBinaryFunc<GenMoveConstructor, true>(Ctx) {}
691
692 void visitARCStrong(QualType QT, const FieldDecl *FD,
693 CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
694 Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
695 Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
696 LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
697 llvm::Value *SrcVal =
698 CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
699 CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
700 CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT),
701 /* isInitialization */ true);
702 }
703 void callSpecialFunction(QualType FT, CharUnits Offset,
704 std::array<Address, 2> Addrs) {
705 CGF->callCStructMoveConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
706 CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
707 }
708};
709
710struct GenCopyAssignment : GenBinaryFunc<GenCopyAssignment, false> {
711 GenCopyAssignment(ASTContext &Ctx)
712 : GenBinaryFunc<GenCopyAssignment, false>(Ctx) {}
713
714 void visitARCStrong(QualType QT, const FieldDecl *FD,
715 CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
716 Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
717 Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
718 llvm::Value *SrcVal = CGF->EmitLoadOfScalar(
719 Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());
720 CGF->EmitARCStoreStrong(CGF->MakeAddrLValue(Addrs[DstIdx], QT), SrcVal,
721 false);
722 }
723 void callSpecialFunction(QualType FT, CharUnits Offset,
724 std::array<Address, 2> Addrs) {
725 CGF->callCStructCopyAssignmentOperator(
726 CGF->MakeAddrLValue(Addrs[DstIdx], FT),
727 CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
728 }
729};
730
731struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> {
732 GenMoveAssignment(ASTContext &Ctx)
733 : GenBinaryFunc<GenMoveAssignment, true>(Ctx) {}
734
735 void visitARCStrong(QualType QT, const FieldDecl *FD,
736 CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
737 Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
738 Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
739 LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
740 llvm::Value *SrcVal =
741 CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
742 CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
743 LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT);
744 llvm::Value *DstVal =
745 CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();
746 CGF->EmitStoreOfScalar(SrcVal, DstLV);
747 CGF->EmitARCRelease(DstVal, ARCImpreciseLifetime);
748 }
749
Akira Hatanaka7275da02018-02-28 07:15:55 +0000750 void callSpecialFunction(QualType FT, CharUnits Offset,
751 std::array<Address, 2> Addrs) {
752 CGF->callCStructMoveAssignmentOperator(
753 CGF->MakeAddrLValue(Addrs[DstIdx], FT),
754 CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
755 }
756};
757
758} // namespace
759
760void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF,
761 Address Addr, QualType Type) {
762 CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Type));
763}
764
765// Default-initialize a variable that is a non-trivial struct or an array of
766// such structure.
767void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) {
768 GenDefaultInitialize Gen(getContext());
769 Address DstPtr = Builder.CreateBitCast(Dst.getAddress(), CGM.Int8PtrPtrTy);
770 Gen.setCGF(this);
771 QualType QT = Dst.getType();
772 QT = Dst.isVolatile() ? QT.withVolatile() : QT;
773 Gen.visit(QT, nullptr, CharUnits::Zero(), std::array<Address, 1>({{DstPtr}}));
774}
775
776template <class G, size_t N>
777static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT,
778 bool IsVolatile, CodeGenFunction &CGF,
779 std::array<Address, N> Addrs) {
780 for (unsigned I = 0; I < N; ++I)
781 Addrs[I] = CGF.Builder.CreateBitCast(Addrs[I], CGF.CGM.Int8PtrPtrTy);
782 QT = IsVolatile ? QT.withVolatile() : QT;
783 Gen.callFunc(FuncName, QT, Addrs, CGF);
784}
785
786// Functions to emit calls to the special functions of a non-trivial C struct.
787void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) {
788 bool IsVolatile = Dst.isVolatile();
789 Address DstPtr = Dst.getAddress();
790 QualType QT = Dst.getType();
791 GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext());
792 std::string FuncName = GenName.getName(QT, IsVolatile);
793 callSpecialFunction(GenDefaultInitialize(getContext()), FuncName, QT,
794 IsVolatile, *this, std::array<Address, 1>({{DstPtr}}));
795}
796
797void CodeGenFunction::callCStructDestructor(LValue Dst) {
798 bool IsVolatile = Dst.isVolatile();
799 Address DstPtr = Dst.getAddress();
800 QualType QT = Dst.getType();
801 GenDestructorFuncName GenName(DstPtr.getAlignment(), getContext());
802 std::string FuncName = GenName.getName(QT, IsVolatile);
803 callSpecialFunction(GenDestructor(getContext()), FuncName, QT, IsVolatile,
804 *this, std::array<Address, 1>({{DstPtr}}));
805}
806
807void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) {
808 bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
809 Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
810 QualType QT = Dst.getType();
811 GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(),
812 SrcPtr.getAlignment(), getContext());
813 std::string FuncName = GenName.getName(QT, IsVolatile);
814 callSpecialFunction(GenCopyConstructor(getContext()), FuncName, QT,
815 IsVolatile, *this,
816 std::array<Address, 2>({{DstPtr, SrcPtr}}));
817}
818
819void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src
820
821) {
822 bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
823 Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
824 QualType QT = Dst.getType();
825 GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(),
826 SrcPtr.getAlignment(), getContext());
827 std::string FuncName = GenName.getName(QT, IsVolatile);
828 callSpecialFunction(GenCopyAssignment(getContext()), FuncName, QT, IsVolatile,
829 *this, std::array<Address, 2>({{DstPtr, SrcPtr}}));
830}
831
832void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) {
833 bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
834 Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
835 QualType QT = Dst.getType();
836 GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(),
837 SrcPtr.getAlignment(), getContext());
838 std::string FuncName = GenName.getName(QT, IsVolatile);
839 callSpecialFunction(GenMoveConstructor(getContext()), FuncName, QT,
840 IsVolatile, *this,
841 std::array<Address, 2>({{DstPtr, SrcPtr}}));
842}
843
844void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src
845
846) {
847 bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
848 Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
849 QualType QT = Dst.getType();
850 GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(),
851 SrcPtr.getAlignment(), getContext());
852 std::string FuncName = GenName.getName(QT, IsVolatile);
853 callSpecialFunction(GenMoveAssignment(getContext()), FuncName, QT, IsVolatile,
854 *this, std::array<Address, 2>({{DstPtr, SrcPtr}}));
855}