216 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H10#define LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H11 12#include "clang/AST/Decl.h"13#include "clang/CIR/Dialect/IR/CIRTypes.h"14 15namespace clang::CIRGen {16 17/// Record with information about how a bitfield should be accessed. This is18/// very similar to what LLVM codegen does, once CIR evolves it's possible we19/// can use a more higher level representation.20///21/// Often we lay out a sequence of bitfields as a contiguous sequence of bits.22/// When the AST record layout does this, we represent it in CIR as a23/// `!cir.record` type, which directly reflects the structure's layout,24/// including bitfield packing and padding, using CIR types such as25/// `!cir.bool`, `!s8i`, `!u16i`.26///27/// To access a particular bitfield in CIR, we use the operations28/// `cir.get_bitfield` (`GetBitfieldOp`) or `cir.set_bitfield`29/// (`SetBitfieldOp`). These operations rely on the `bitfield_info`30/// attribute, which provides detailed metadata required for access,31/// such as the size and offset of the bitfield, the type and size of32/// the underlying storage, and whether the value is signed.33/// The CIRGenRecordLayout also has a bitFields map which encodes which34/// byte-sequence this bitfield falls within. Let's assume the following C35/// struct:36///37/// struct S {38/// char a, b, c;39/// unsigned bits : 3;40/// unsigned more_bits : 4;41/// unsigned still_more_bits : 7;42/// };43///44/// This will end up as the following cir.record. The bitfield members are45/// represented by one !u16i value, and the array provides padding to align the46/// struct to a 4-byte alignment.47///48/// !rec_S = !cir.record<struct "S" padded {!s8i, !s8i, !s8i, !u16i,49/// !cir.array<!u8i x 3>}>50///51/// When generating code to access more_bits, we'll generate something52/// essentially like this:53///54/// #bfi_more_bits = #cir.bitfield_info<name = "more_bits", storage_type =55/// !u16i, size = 4, offset = 3, is_signed = false>56///57/// cir.func @store_field() {58/// %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s"] {alignment = 4 : i64}59/// %1 = cir.const #cir.int<2> : !s32i60/// %2 = cir.cast integral %1 : !s32i -> !u32i61/// %3 = cir.get_member %0[3] {name = "more_bits"} : !cir.ptr<!rec_S> ->62/// !cir.ptr<!u16i>63/// %4 = cir.set_bitfield(#bfi_more_bits, %3 :64/// !cir.ptr<!u16i>, %2 : !u32i) -> !u32i65/// cir.return66/// }67///68struct CIRGenBitFieldInfo {69 /// The offset within a contiguous run of bitfields that are represented as70 /// a single "field" within the cir.record type. This offset is in bits.71 unsigned offset : 16;72 73 /// The total size of the bit-field, in bits.74 unsigned size : 15;75 76 /// Whether the bit-field is signed.77 unsigned isSigned : 1;78 79 /// The storage size in bits which should be used when accessing this80 /// bitfield.81 unsigned storageSize;82 83 /// The offset of the bitfield storage from the start of the record.84 clang::CharUnits storageOffset;85 86 /// The offset within a contiguous run of bitfields that are represented as a87 /// single "field" within the cir.record type, taking into account the AAPCS88 /// rules for volatile bitfields. This offset is in bits.89 unsigned volatileOffset : 16;90 91 /// The storage size in bits which should be used when accessing this92 /// bitfield.93 unsigned volatileStorageSize;94 95 /// The offset of the bitfield storage from the start of the record.96 clang::CharUnits volatileStorageOffset;97 98 /// The name of a bitfield99 llvm::StringRef name;100 101 // The actual storage type for the bitfield102 mlir::Type storageType;103 104 CIRGenBitFieldInfo()105 : offset(), size(), isSigned(), storageSize(), volatileOffset(),106 volatileStorageSize() {}107 108 CIRGenBitFieldInfo(unsigned offset, unsigned size, bool isSigned,109 unsigned storageSize, clang::CharUnits storageOffset)110 : offset(offset), size(size), isSigned(isSigned),111 storageSize(storageSize), storageOffset(storageOffset) {}112 113 void print(llvm::raw_ostream &os) const;114 LLVM_DUMP_METHOD void dump() const;115};116 117/// This class handles record and union layout info while lowering AST types118/// to CIR types.119///120/// These layout objects are only created on demand as CIR generation requires.121class CIRGenRecordLayout {122 friend class CIRGenTypes;123 124 CIRGenRecordLayout(const CIRGenRecordLayout &) = delete;125 void operator=(const CIRGenRecordLayout &) = delete;126 127private:128 /// The CIR type corresponding to this record layout; used when laying it out129 /// as a complete object.130 cir::RecordType completeObjectType;131 132 /// The CIR type for the non-virtual part of this record layout; used when133 /// laying it out as a base subobject.134 cir::RecordType baseSubobjectType;135 136 /// Map from (non-bit-field) record field to the corresponding cir record type137 /// field no. This info is populated by the record builder.138 llvm::DenseMap<const clang::FieldDecl *, unsigned> fieldIdxMap;139 140 // FIXME: Maybe we could use CXXBaseSpecifier as the key and use a single map141 // for both virtual and non-virtual bases.142 llvm::DenseMap<const clang::CXXRecordDecl *, unsigned> nonVirtualBases;143 144 /// Map from virtual bases to their field index in the complete object.145 llvm::DenseMap<const clang::CXXRecordDecl *, unsigned>146 completeObjectVirtualBases;147 148 /// Map from (bit-field) record field to the corresponding CIR record type149 /// field no. This info is populated by record builder.150 llvm::DenseMap<const clang::FieldDecl *, CIRGenBitFieldInfo> bitFields;151 152 /// False if any direct or indirect subobject of this class, when considered153 /// as a complete object, requires a non-zero bitpattern when154 /// zero-initialized.155 LLVM_PREFERRED_TYPE(bool)156 unsigned zeroInitializable : 1;157 158 /// False if any direct or indirect subobject of this class, when considered159 /// as a base subobject, requires a non-zero bitpattern when zero-initialized.160 LLVM_PREFERRED_TYPE(bool)161 unsigned zeroInitializableAsBase : 1;162 163public:164 CIRGenRecordLayout(cir::RecordType completeObjectType,165 cir::RecordType baseSubobjectType, bool zeroInitializable,166 bool zeroInitializableAsBase)167 : completeObjectType(completeObjectType),168 baseSubobjectType(baseSubobjectType),169 zeroInitializable(zeroInitializable),170 zeroInitializableAsBase(zeroInitializableAsBase) {}171 172 /// Return the "complete object" LLVM type associated with173 /// this record.174 cir::RecordType getCIRType() const { return completeObjectType; }175 176 /// Return the "base subobject" LLVM type associated with177 /// this record.178 cir::RecordType getBaseSubobjectCIRType() const { return baseSubobjectType; }179 180 /// Return cir::RecordType element number that corresponds to the field FD.181 unsigned getCIRFieldNo(const clang::FieldDecl *fd) const {182 fd = fd->getCanonicalDecl();183 assert(fieldIdxMap.count(fd) && "Invalid field for record!");184 return fieldIdxMap.lookup(fd);185 }186 187 unsigned getNonVirtualBaseCIRFieldNo(const CXXRecordDecl *rd) const {188 assert(nonVirtualBases.count(rd) && "Invalid non-virtual base!");189 return nonVirtualBases.lookup(rd);190 }191 192 /// Check whether this struct can be C++ zero-initialized193 /// with a zeroinitializer.194 bool isZeroInitializable() const { return zeroInitializable; }195 196 /// Check whether this struct can be C++ zero-initialized197 /// with a zeroinitializer when considered as a base subobject.198 bool isZeroInitializableAsBase() const { return zeroInitializableAsBase; }199 200 /// Return the BitFieldInfo that corresponds to the field FD.201 const CIRGenBitFieldInfo &getBitFieldInfo(const clang::FieldDecl *fd) const {202 fd = fd->getCanonicalDecl();203 assert(fd->isBitField() && "Invalid call for non-bit-field decl!");204 llvm::DenseMap<const clang::FieldDecl *, CIRGenBitFieldInfo>::const_iterator205 it = bitFields.find(fd);206 assert(it != bitFields.end() && "Unable to find bitfield info");207 return it->second;208 }209 void print(raw_ostream &os) const;210 LLVM_DUMP_METHOD void dump() const;211};212 213} // namespace clang::CIRGen214 215#endif216