clang: lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

16

24#include "llvm/Support/Casting.h"

25

26#include

27

28using namespace llvm;

29using namespace clang;

31

32namespace {

33

34

35

36

37struct CIRRecordLowering final {

38

39

40

41

42 struct MemberInfo final {

43 CharUnits offset;

44 enum class InfoKind { VFPtr, Field, Base, VBase } kind;

45 mlir::Type data;

46 union {

49 };

50 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,

51 const FieldDecl *fieldDecl = nullptr)

53 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,

54 const CXXRecordDecl *rd)

55 : offset{offset}, kind{kind}, data{data}, cxxRecordDecl{rd} {}

56

57 bool operator<(const MemberInfo &other) const {

58 return offset < other.offset;

59 }

60 };

61

62 CIRRecordLowering(CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,

63 bool packed);

64

65

66 MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data) {

67 return MemberInfo(offset, MemberInfo::InfoKind::Field, data);

68 }

69

70

71 void setBitFieldInfo(const FieldDecl *fd, CharUnits startOffset,

72 mlir::Type storageType);

73

74 void lower(bool NonVirtualBaseType);

75 void lowerUnion();

76

77

78 void determinePacked(bool nvBaseType);

79

80 void insertPadding();

81

82 void computeVolatileBitfields();

83 void accumulateBases();

84 void accumulateVPtrs();

85 void accumulateVBases();

86 void accumulateFields();

90

91 mlir::Type getVFPtrType();

92

94 return astContext.getTargetInfo().getABI().starts_with("aapcs");

95 }

96

97

98 bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }

99

100

101

102

103

104 bool isOverlappingVBaseABI() {

105 return !astContext.getTargetInfo().getCXXABI().isMicrosoft();

106 }

107

108

109 bool hasOwnStorage(const CXXRecordDecl *decl, const CXXRecordDecl *query);

110

111

112

113

114

115

116 bool isDiscreteBitFieldABI() {

117 return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||

118 recordDecl->isMsStruct(astContext);

119 }

120

121 CharUnits bitsToCharUnits(uint64_t bitOffset) {

122 return astContext.toCharUnitsFromBits(bitOffset);

123 }

124

125 void calculateZeroInit();

126

127 CharUnits getSize(mlir::Type Ty) {

129 }

130 CharUnits getSizeInBits(mlir::Type ty) {

132 }

133 CharUnits getAlignment(mlir::Type Ty) {

135 }

136

137 bool isZeroInitializable(const FieldDecl *fd) {

138 return cirGenTypes.isZeroInitializable(fd->getType());

139 }

140 bool isZeroInitializable(const RecordDecl *rd) {

141 return cirGenTypes.isZeroInitializable(rd);

142 }

143

144

145 mlir::Type getUIntNType(uint64_t numBits) {

146 unsigned alignedBits = llvm::PowerOf2Ceil(numBits);

147 alignedBits = std::max(8u, alignedBits);

148 return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,

149 false);

150 }

151

152 mlir::Type getCharType() {

153 return cir::IntType::get(&cirGenTypes.getMLIRContext(),

154 astContext.getCharWidth(),

155 false);

156 }

157

158 mlir::Type getByteArrayType(CharUnits numberOfChars) {

159 assert(!numberOfChars.isZero() && "Empty byte arrays aren't allowed.");

160 mlir::Type type = getCharType();

163 : cir::ArrayType::get(type, numberOfChars.getQuantity());

164 }

165

166

167 mlir::Type getStorageType(const CXXRecordDecl *RD) {

168 return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();

169 }

170

171

172

173 mlir::Type getBitfieldStorageType(unsigned numBits) {

174 unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());

176 return builder.getUIntNTy(alignedBits);

177

178 mlir::Type type = getCharType();

179 return cir::ArrayType::get(type, alignedBits / astContext.getCharWidth());

180 }

181

182 mlir::Type getStorageType(const FieldDecl *fieldDecl) {

183 mlir::Type type = cirGenTypes.convertTypeForMem(fieldDecl->getType());

185 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),

186 "getStorageType for bitfields");

187 }

189 }

190

192 return astRecordLayout.getFieldOffset(fieldDecl->getFieldIndex());

193 }

194

195

196 void fillOutputFields();

197

198 void appendPaddingBytes(CharUnits size) {

199 if (!size.isZero()) {

200 fieldTypes.push_back(getByteArrayType(size));

201 padded = true;

202 }

203 }

204

205 CIRGenTypes &cirGenTypes;

206 CIRGenBuilderTy &builder;

207 const ASTContext &astContext;

208 const RecordDecl *recordDecl;

209 const CXXRecordDecl *cxxRecordDecl;

210 const ASTRecordLayout &astRecordLayout;

211

212 std::vector members;

213

214 llvm::SmallVector<mlir::Type, 16> fieldTypes;

215 llvm::DenseMap<const FieldDecl *, CIRGenBitFieldInfo> bitFields;

216 llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;

217 llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;

218 llvm::DenseMap<const CXXRecordDecl *, unsigned> virtualBases;

219 cir::CIRDataLayout dataLayout;

220

221 LLVM_PREFERRED_TYPE(bool)

222 unsigned zeroInitializable : 1;

223 LLVM_PREFERRED_TYPE(bool)

224 unsigned zeroInitializableAsBase : 1;

225 LLVM_PREFERRED_TYPE(bool)

226 unsigned packed : 1;

227 LLVM_PREFERRED_TYPE(bool)

228 unsigned padded : 1;

229

230private:

231 CIRRecordLowering(const CIRRecordLowering &) = delete;

232 void operator=(const CIRRecordLowering &) = delete;

233};

234}

235

236CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes,

238 : cirGenTypes{cirGenTypes}, builder{cirGenTypes.getBuilder()},

241 astRecordLayout{

242 cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)},

243 dataLayout{cirGenTypes.getCGModule().getModule()},

244 zeroInitializable{true}, zeroInitializableAsBase{true}, packed{packed},

246

247void CIRRecordLowering::setBitFieldInfo(const FieldDecl *fd,

249 mlir::Type storageType) {

250 CIRGenBitFieldInfo &info = bitFields[fd->getCanonicalDecl()];

253 (unsigned)(getFieldBitOffset(fd) - astContext.toBits(startOffset));

255 info.storageSize = getSizeInBits(storageType).getQuantity();

259

262

263

264

265

268

272}

273

274void CIRRecordLowering::lower(bool nonVirtualBaseType) {

276 lowerUnion();

277 computeVolatileBitfields();

278 return;

279 }

280

281 CharUnits size = nonVirtualBaseType ? astRecordLayout.getNonVirtualSize()

282 : astRecordLayout.getSize();

283

284 accumulateFields();

285

287 accumulateVPtrs();

288 accumulateBases();

289 if (members.empty()) {

290 appendPaddingBytes(size);

291 computeVolatileBitfields();

292 return;

293 }

294 if (!nonVirtualBaseType)

295 accumulateVBases();

296 }

297

298 llvm::stable_sort(members);

299

301

302 members.push_back(makeStorageInfo(size, getUIntNType(8)));

303 determinePacked(nonVirtualBaseType);

304 insertPadding();

305 members.pop_back();

306

307 calculateZeroInit();

308 fillOutputFields();

309 computeVolatileBitfields();

310}

311

312void CIRRecordLowering::fillOutputFields() {

313 for (const MemberInfo &member : members) {

315 fieldTypes.push_back(member.data);

316 if (member.kind == MemberInfo::InfoKind::Field) {

317 if (member.fieldDecl)

318 fieldIdxMap[member.fieldDecl->getCanonicalDecl()] =

319 fieldTypes.size() - 1;

320

322 assert(member.fieldDecl &&

323 "member.data is a nullptr so member.fieldDecl should not be");

324 setBitFieldInfo(member.fieldDecl, member.offset, fieldTypes.back());

325 }

326 } else if (member.kind == MemberInfo::InfoKind::Base) {

327 nonVirtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;

328 } else if (member.kind == MemberInfo::InfoKind::VBase) {

329 virtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;

330 }

331 }

332}

333

337 if (isDiscreteBitFieldABI()) {

338

339

340

341

342

344

345

346

347 uint64_t startBitOffset, tail = 0;

348 for (; field != fieldEnd && field->isBitField(); ++field) {

349

350 if (field->isZeroLengthBitField()) {

351 run = fieldEnd;

352 continue;

353 }

354 uint64_t bitOffset = getFieldBitOffset(*field);

356

357

358 if (run == fieldEnd || bitOffset >= tail) {

359 run = field;

360 startBitOffset = bitOffset;

362

363

364

365 members.push_back(

366 makeStorageInfo(bitsToCharUnits(startBitOffset), type));

367 }

368

369

370 members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),

371 MemberInfo::InfoKind::Field, nullptr,

372 *field));

373 }

374 return field;

375 }

376

377 CharUnits regSize =

379 unsigned charBits = astContext.getCharWidth();

380

381

382

383

384

385

386

388 CharUnits beginOffset;

390

391

392

393

394

395

397 CharUnits bestEndOffset;

398 bool bestClipped;

399

400 for (;;) {

401

402

403

404

405 bool atAlignedBoundary = false;

406 bool barrier = false;

407 if (field != fieldEnd && field->isBitField()) {

408 uint64_t bitOffset = getFieldBitOffset(*field);

409 if (begin == fieldEnd) {

410

411 begin = field;

412 bestEnd = begin;

413

414 assert((bitOffset % charBits) == 0 && "Not at start of char");

415 beginOffset = bitsToCharUnits(bitOffset);

416 bitSizeSinceBegin = 0;

417 } else if ((bitOffset % charBits) != 0) {

418

419

420

421

422

423

424 assert(bitOffset ==

425 astContext.toBits(beginOffset) + bitSizeSinceBegin &&

426 "Concatenating non-contiguous bitfields");

427 } else {

428

429

430

431 if (field->isZeroLengthBitField())

433 atAlignedBoundary = true;

434 }

435 } else {

436

437

438 if (begin == fieldEnd)

439 break;

440

442 atAlignedBoundary = true;

443 }

444

445

446

447

448 bool installBest = false;

449 if (atAlignedBoundary) {

450

451

452

453

454

455 CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1);

456 if (bestEnd == begin) {

457

458

459 bestEnd = field;

460 bestEndOffset = beginOffset + accessSize;

461

462 bestClipped = true;

463 if (!bitSizeSinceBegin)

464

465

466 installBest = true;

467 } else if (accessSize > regSize) {

468

469

470 installBest = true;

471 }

472

473 if (!installBest) {

474

475

476 mlir::Type type = getUIntNType(astContext.toBits(accessSize));

479 field->getSourceRange(), "NYI CheapUnalignedBitFieldAccess");

480

481 if (!installBest) {

482

483

484

485

486 CharUnits limitOffset;

487 for (auto probe = field; probe != fieldEnd; ++probe)

489

490 assert((getFieldBitOffset(*probe) % charBits) == 0 &&

491 "Next storage is not byte-aligned");

492 limitOffset = bitsToCharUnits(getFieldBitOffset(*probe));

493 goto FoundLimit;

494 }

497

498 FoundLimit:

499 CharUnits typeSize = getSize(type);

500 if (beginOffset + typeSize <= limitOffset) {

501

502

503 bestEndOffset = beginOffset + typeSize;

504 bestEnd = field;

505 bestClipped = false;

506 }

508

509 installBest = true;

512 .FineGrainedBitfieldAccesses) {

513 installBest = true;

514 } else {

515

516

517

518 bitSizeSinceBegin = astContext.toBits(limitOffset - beginOffset);

519 }

520 }

521 }

522 }

523

524 if (installBest) {

525 assert((field == fieldEnd || !field->isBitField() ||

526 (getFieldBitOffset(*field) % charBits) == 0) &&

527 "Installing but not at an aligned bitfield or limit");

528 CharUnits accessSize = bestEndOffset - beginOffset;

529 if (!accessSize.isZero()) {

530

531

532

533 mlir::Type type;

534 if (bestClipped) {

535 assert(getSize(getUIntNType(astContext.toBits(accessSize))) >

536 accessSize &&

537 "Clipped access need not be clipped");

538 type = getByteArrayType(accessSize);

539 } else {

540 type = getUIntNType(astContext.toBits(accessSize));

541 assert(getSize(type) == accessSize &&

542 "Unclipped access must be clipped");

543 }

544 members.push_back(makeStorageInfo(beginOffset, type));

545 for (; begin != bestEnd; ++begin)

546 if (!begin->isZeroLengthBitField())

547 members.push_back(MemberInfo(

548 beginOffset, MemberInfo::InfoKind::Field, nullptr, *begin));

549 }

550

551 field = bestEnd;

552 begin = fieldEnd;

553 } else {

554 assert(field != fieldEnd && field->isBitField() &&

555 "Accumulating past end of bitfields");

556 assert(barrier && "Accumulating across barrier");

557

558 bitSizeSinceBegin += field->getBitWidthValue();

559 ++field;

560 }

561 }

562

563 return field;

564}

565

566void CIRRecordLowering::accumulateFields() {

569 field != fieldEnd;) {

570 if (field->isBitField()) {

571 field = accumulateBitFields(field, fieldEnd);

572 assert((field == fieldEnd || !field->isBitField()) &&

573 "Failed to accumulate all the bitfields");

574 } else if (!field->isZeroSize(astContext)) {

575 members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(*field)),

576 MemberInfo::InfoKind::Field,

577 getStorageType(*field), *field));

578 ++field;

579 } else {

580

582 ++field;

583 }

584 }

585}

586

587void CIRRecordLowering::calculateZeroInit() {

588 for (const MemberInfo &member : members) {

589 if (member.kind == MemberInfo::InfoKind::Field) {

590 if (member.fieldDecl || isZeroInitializable(member.fieldDecl))

591 continue;

592 zeroInitializable = zeroInitializableAsBase = false;

593 return;

594 } else if (member.kind == MemberInfo::InfoKind::Base ||

595 member.kind == MemberInfo::InfoKind::VBase) {

596 if (isZeroInitializable(member.cxxRecordDecl))

597 continue;

598 zeroInitializable = false;

599 if (member.kind == MemberInfo::InfoKind::Base)

600 zeroInitializableAsBase = false;

601 }

602 }

603}

604

605void CIRRecordLowering::determinePacked(bool nvBaseType) {

606 if (packed)

607 return;

613

614 for (const MemberInfo &member : members) {

616 continue;

617

618

619 if (member.offset.isMultipleOf(getAlignment(member.data)))

620 packed = true;

621 if (member.offset < nvSize)

622 nvAlignment = std::max(nvAlignment, getAlignment(member.data));

623 alignment = std::max(alignment, getAlignment(member.data));

624 }

625

626

627 if (!members.back().offset.isMultipleOf(alignment))

628 packed = true;

629

630

631

633 packed = true;

634

635 if (!packed)

636 members.back().data = getUIntNType(astContext.toBits(alignment));

637}

638

639void CIRRecordLowering::insertPadding() {

640 std::vector<std::pair<CharUnits, CharUnits>> padding;

642 for (const MemberInfo &member : members) {

644 continue;

645 CharUnits offset = member.offset;

646 assert(offset >= size);

647

648 if (offset !=

650 padding.push_back(std::make_pair(size, offset - size));

651 size = offset + getSize(member.data);

652 }

653 if (padding.empty())

654 return;

655 padded = true;

656

657 for (const std::pair<CharUnits, CharUnits> &paddingPair : padding)

658 members.push_back(makeStorageInfo(paddingPair.first,

659 getByteArrayType(paddingPair.second)));

660 llvm::stable_sort(members);

661}

662

663std::unique_ptr

665 CIRRecordLowering lowering(*this, rd, false);

666 assert(ty->isIncomplete() && "recomputing record layout?");

667 lowering.lower(false);

668

669

670 cir::RecordType baseTy;

671 if (llvm::isa(rd) && !rd->isUnion() &&

672 !rd->hasAttr()) {

673 baseTy = *ty;

675 lowering.astRecordLayout.getSize()) {

676 CIRRecordLowering baseLowering(*this, rd, lowering.packed);

677 baseLowering.lower(true);

679 baseTy = builder.getCompleteNamedRecordType(

680 baseLowering.fieldTypes, baseLowering.packed, baseLowering.padded,

681 baseIdentifier);

682

683

684

685

686 assert(lowering.packed == baseLowering.packed &&

687 "Non-virtual and complete types must agree on packedness");

688 }

689 }

690

691

692

693

695 ty->complete(lowering.fieldTypes, lowering.packed, lowering.padded);

696

697 auto rl = std::make_unique(

698 ty ? *ty : cir::RecordType{}, baseTy ? baseTy : cir::RecordType{},

699 (bool)lowering.zeroInitializable, (bool)lowering.zeroInitializableAsBase);

700

701 rl->nonVirtualBases.swap(lowering.nonVirtualBases);

702 rl->completeObjectVirtualBases.swap(lowering.virtualBases);

703

704

705 rl->fieldIdxMap.swap(lowering.fieldIdxMap);

706

707 rl->bitFields.swap(lowering.bitFields);

708

709

710 if (getASTContext().getLangOpts().DumpRecordLayouts) {

711 llvm::outs() << "\n*** Dumping CIRgen Record Layout\n";

712 llvm::outs() << "Record: ";

713 rd->dump(llvm::outs());

714 llvm::outs() << "\nLayout: ";

715 rl->print(llvm::outs());

716 }

717

718

719 return rl;

720}

721

723 os << "<CIRecordLayout\n";

724 os << " CIR Type:" << completeObjectType << "\n";

725 if (baseSubobjectType)

726 os << " NonVirtualBaseCIRType:" << baseSubobjectType << "\n";

727 os << " IsZeroInitializable:" << zeroInitializable << "\n";

728 os << " BitFields:[\n";

729 std::vector<std::pair<unsigned, const CIRGenBitFieldInfo *>> bitInfo;

730 for (auto &[decl, info] : bitFields) {

732 unsigned index = 0;

735 bitInfo.push_back(std::make_pair(index, &info));

736 }

737 llvm::array_pod_sort(bitInfo.begin(), bitInfo.end());

738 for (std::pair<unsigned, const CIRGenBitFieldInfo *> &info : bitInfo) {

739 os.indent(4);

740 info.second->print(os);

741 os << "\n";

742 }

743 os << " ]>\n";

744}

745

747 os << "<CIRBitFieldInfo" << " name:" << name << " offset:" << offset

748 << " size:" << size << " isSigned:" << isSigned

750 << " storageOffset:" << storageOffset.getQuantity()

754}

755

757

759

760void CIRRecordLowering::lowerUnion() {

762 mlir::Type storageType = nullptr;

763 bool seenNamedMember = false;

764

765

766

768 mlir::Type fieldType;

769 if (field->isBitField()) {

770 if (field->isZeroLengthBitField())

771 continue;

772 fieldType = getBitfieldStorageType(field->getBitWidthValue());

774 } else {

775 fieldType = getStorageType(field);

776 }

777

778

779 fieldIdxMap[field->getCanonicalDecl()] = 0;

780

781

782

783

784

785

786

787 if (!seenNamedMember) {

788 seenNamedMember = field->getIdentifier();

789 if (!seenNamedMember)

790 if (const RecordDecl *fieldRD = field->getType()->getAsRecordDecl())

791 seenNamedMember = fieldRD->findFirstNamedDataMember();

792 if (seenNamedMember && !isZeroInitializable(field)) {

793 zeroInitializable = zeroInitializableAsBase = false;

794 storageType = fieldType;

795 }

796 }

797

798

799

800 if (!zeroInitializable)

801 continue;

802

803

804 if (!storageType || getAlignment(fieldType) > getAlignment(storageType) ||

805 (getAlignment(fieldType) == getAlignment(storageType) &&

806 getSize(fieldType) > getSize(storageType)))

807 storageType = fieldType;

808

809

810

811 fieldTypes.push_back(fieldType);

812 }

813

814 if (!storageType)

816 "No-storage Union NYI");

817

818 if (layoutSize < getSize(storageType))

819 storageType = getByteArrayType(layoutSize);

820 else

821 appendPaddingBytes(layoutSize - getSize(storageType));

822

823

824 if (!layoutSize.isMultipleOf(getAlignment(storageType)))

825 packed = true;

826}

827

828bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,

829 const CXXRecordDecl *query) {

832 return false;

833 for (const auto &base : decl->bases())

834 if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))

835 return false;

836 return true;

837}

838

839

840

841

842

843

844

845

846

847

848

849

850

851

852void CIRRecordLowering::computeVolatileBitfields() {

855 return;

856

857 for (auto &[field, info] : bitFields) {

858 mlir::Type resLTy = cirGenTypes.convertTypeForMem(field->getType());

859

861 getSizeInBits(resLTy).getQuantity())

862 continue;

863

864

865

866

867

868

869 const unsigned oldOffset =

871 : info.offset;

872

873 const unsigned absoluteOffset =

875

876

877 const unsigned storageSize = getSizeInBits(resLTy).getQuantity();

878

879

880 if (info.storageSize == storageSize && (oldOffset % storageSize == 0))

881 continue;

882

883

884 unsigned offset = absoluteOffset & (storageSize - 1);

885

886

887

888

889 if (offset + info.size > storageSize)

890 continue;

891

892

893 if (isBigEndian())

894 offset = storageSize - (offset + info.size);

895

896 const CharUnits storageOffset =

898 const CharUnits end = storageOffset +

901

902 const ASTRecordLayout &layout =

904

905 const CharUnits recordSize = layout.getSize();

906 if (end >= recordSize)

907 continue;

908

909

910 bool conflict = false;

911 for (const auto *f : recordDecl->fields()) {

912

913 if (f->isBitField() && !f->isZeroLengthBitField())

914 continue;

915

918

919

920

921

922

923 if (f->isZeroLengthBitField()) {

924 if (end > fOffset && storageOffset < fOffset) {

925 conflict = true;

926 break;

927 }

928 }

929

930 const CharUnits fEnd =

931 fOffset +

934 .getQuantity()) -

936

937 if (end < fOffset || fEnd < storageOffset)

938 continue;

939

940

941 conflict = true;

942 break;

943 }

944

945 if (conflict)

946 continue;

947

948

949

951 storageOffset /

955 }

956}

957

958void CIRRecordLowering::accumulateBases() {

959

961 const CXXRecordDecl *baseDecl = astRecordLayout.getPrimaryBase();

962 members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::InfoKind::Base,

963 getStorageType(baseDecl), baseDecl));

964 }

965

966

967 for (const auto &base : cxxRecordDecl->bases()) {

968 if (base.isVirtual())

969 continue;

970

971

972 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();

973 if (!baseDecl->isEmpty() &&

975 members.push_back(MemberInfo(astRecordLayout.getBaseClassOffset(baseDecl),

976 MemberInfo::InfoKind::Base,

977 getStorageType(baseDecl), baseDecl));

978 }

979 }

980}

981

982void CIRRecordLowering::accumulateVBases() {

983 for (const auto &base : cxxRecordDecl->vbases()) {

984 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();

986 continue;

988

989

990 if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(baseDecl) &&

992 members.push_back(

993 MemberInfo(offset, MemberInfo::InfoKind::VBase, nullptr, baseDecl));

994 continue;

995 }

996

998 .find(baseDecl)

999 ->second.hasVtorDisp())

1001 getUIntNType(32)));

1002 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,

1003 getStorageType(baseDecl), baseDecl));

1004 }

1005}

1006

1007void CIRRecordLowering::accumulateVPtrs() {

1009 members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,

1010 getVFPtrType()));

1011

1014 "accumulateVPtrs: hasOwnVBPtr");

1015}

1016

1017mlir::Type CIRRecordLowering::getVFPtrType() {

1018 return cir::VPtrType::get(builder.getContext());

1019}

Defines the clang::ASTContext interface.

static bool isAAPCS(const TargetInfo &targetInfo)

Helper method to check if the underlying ABI is AAPCS.

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)

llvm::TypeSize getTypeAllocSizeInBits(mlir::Type ty) const

Returns the offset in bits between successive objects of the specified type, including alignment padd...

const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const

Get or compute information about the layout of the specified record (struct/union/class) D,...

bool isNearlyEmpty(const CXXRecordDecl *RD) const

int64_t toBits(CharUnits CharSize) const

Convert a size in characters to a size in bits.

const TargetInfo & getTargetInfo() const

CharUnits toCharUnitsFromBits(int64_t BitSize) const

Convert a size in bits to a size in characters.

uint64_t getCharWidth() const

Return the size of the character type, in bits.

bool hasOwnVFPtr() const

hasOwnVFPtr - Does this class provide its own virtual-function table pointer, rather than inheriting ...

CharUnits getAlignment() const

getAlignment - Get the record alignment in characters.

bool hasOwnVBPtr() const

hasOwnVBPtr - Does this class provide its own virtual-base table pointer, rather than inheriting one ...

CharUnits getSize() const

getSize - Get the record size in characters.

uint64_t getFieldOffset(unsigned FieldNo) const

getFieldOffset - Get the offset of the given field index, in bits.

CharUnits getDataSize() const

getDataSize() - Get the record data size, which is the record size without tail padding,...

CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const

getBaseClassOffset - Get the offset, in chars, for the given base class.

CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const

getVBaseClassOffset - Get the offset, in chars, for the given base class.

const VBaseOffsetsMapTy & getVBaseOffsetsMap() const

const CXXRecordDecl * getPrimaryBase() const

getPrimaryBase - Get the primary base for this record.

bool isPrimaryBaseVirtual() const

isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not.

CharUnits getNonVirtualSize() const

getNonVirtualSize - Get the non-virtual size (in chars) of an object, which is the size of the object...

DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)

Helpers to emit "not yet implemented" error diagnostics.

const clang::CodeGenOptions & getCodeGenOpts() const

LLVM_DUMP_METHOD void dump() const

Definition CIRGenRecordLayoutBuilder.cpp:756

void print(raw_ostream &os) const

Definition CIRGenRecordLayoutBuilder.cpp:722

This class organizes the cross-module state that is used while lowering AST types to CIR types.

CIRGenModule & getCGModule() const

std::string getRecordTypeName(const clang::RecordDecl *, llvm::StringRef suffix)

clang::ASTContext & getASTContext() const

std::unique_ptr< CIRGenRecordLayout > computeRecordLayout(const clang::RecordDecl *rd, cir::RecordType *ty)

Definition CIRGenRecordLayoutBuilder.cpp:664

mlir::Type convertTypeForMem(clang::QualType, bool forBitField=false)

Convert type T into an mlir::Type.

Represents a C++ struct/union/class.

bool isEmpty() const

Determine whether this is an empty class in the sense of (C++11 [meta.unary.prop]).

CharUnits - This is an opaque type for sizes expressed in character units.

bool isZero() const

isZero - Test whether the quantity equals zero.

QuantityType getQuantity() const

getQuantity - Get the raw integer representation of this quantity.

static CharUnits One()

One - Construct a CharUnits quantity of one.

bool isMultipleOf(CharUnits N) const

Test whether this is a multiple of the other value.

static CharUnits fromQuantity(QuantityType Quantity)

fromQuantity - Construct a CharUnits quantity from a raw integer type.

CharUnits alignTo(const CharUnits &Align) const

alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...

static CharUnits Zero()

Zero - Construct a CharUnits quantity of zero.

Represents a member of a struct/union/class.

unsigned getBitWidthValue() const

Computes the bit width of this field, if this is a bit field.

FieldDecl * getCanonicalDecl() override

Retrieves the canonical declaration of this field.

StringRef getName() const

Get the name of identifier for this declaration as a StringRef.

Represents a struct/union/class.

specific_decl_iterator< FieldDecl > field_iterator

field_iterator field_begin() const

virtual unsigned getRegisterWidth() const

Return the "preferred" register width on this target.

bool hasCheapUnalignedBitFieldAccess() const

Return true iff unaligned accesses are cheap.

bool isSignedIntegerOrEnumerationType() const

Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...

bool isValidFundamentalIntWidth(unsigned width)

bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd)

isEmptyFieldForLayout - Return true if the field is "empty", that is, either a zero-width bit-field o...

bool isEmptyRecordForLayout(const ASTContext &context, QualType t)

isEmptyRecordForLayout - Return true if a structure contains only empty base classes (per isEmptyReco...

const internal::VariadicAllOfMatcher< Type > type

Matches Types in the clang AST.

const internal::VariadicDynCastAllOfMatcher< Decl, FieldDecl > fieldDecl

Matches field declarations.

const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl

Matches C++ class declarations.

const internal::VariadicAllOfMatcher< Decl > decl

Matches declarations.

const internal::VariadicDynCastAllOfMatcher< Decl, RecordDecl > recordDecl

Matches class, struct, and union declarations.

RangeSelector member(std::string ID)

Given a MemberExpr, selects the member token. ID is the node's binding in the match result.

Stencil run(MatchConsumer< std::string > C)

Wraps a MatchConsumer in a Stencil, so that it can be used in a Stencil.

The JSON file list parser is used to communicate input to InstallAPI.

bool operator<(DeclarationName LHS, DeclarationName RHS)

Ordering on two declaration names.

Diagnostic wrappers for TextAPI types for error reporting.

void __ovld __conv barrier(cl_mem_fence_flags)

All work-items in a work-group executing the kernel on a processor must execute this function before ...

static bool zeroSizeRecordMembers()

static bool checkBitfieldClipping()

static bool astRecordDeclAttr()

unsigned offset

The offset within a contiguous run of bitfields that are represented as a single "field" within the c...

void print(llvm::raw_ostream &os) const

Definition CIRGenRecordLayoutBuilder.cpp:746

LLVM_DUMP_METHOD void dump() const

Definition CIRGenRecordLayoutBuilder.cpp:758

unsigned storageSize

The storage size in bits which should be used when accessing this bitfield.

unsigned volatileStorageSize

The storage size in bits which should be used when accessing this bitfield.

clang::CharUnits storageOffset

The offset of the bitfield storage from the start of the record.

unsigned size

The total size of the bit-field, in bits.

unsigned isSigned

Whether the bit-field is signed.

clang::CharUnits volatileStorageOffset

The offset of the bitfield storage from the start of the record.

unsigned volatileOffset

The offset within a contiguous run of bitfields that are represented as a single "field" within the c...

llvm::StringRef name

The name of a bitfield.