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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H 10 #define LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H 11 12 #include "clang/AST/Decl.h" 13 #include "clang/CIR/Dialect/IR/CIRTypes.h" 14 15 namespace clang::CIRGen { 16 17 /// Record with information about how a bitfield should be accessed. This is 18 /// very similar to what LLVM codegen does, once CIR evolves it's possible we 19 /// 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 a 23 /// `!cir.record` type, which directly reflects the structure's layout, 24 /// including bitfield packing and padding, using CIR types such as 25 /// `!cir.bool`, `!s8i`, `!u16i`. 26 /// 27 /// To access a particular bitfield in CIR, we use the operations 28 /// `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 of 32 /// the underlying storage, and whether the value is signed. 33 /// The CIRGenRecordLayout also has a bitFields map which encodes which 34 /// byte-sequence this bitfield falls within. Let's assume the following C 35 /// 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 are 45 /// represented by one !u16i value, and the array provides padding to align the 46 /// 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 something 52 /// 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> : !s32i 60 /// %2 = cir.cast(integral, %1 : !s32i), !u32i 61 /// %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) -> !u32i 65 /// cir.return 66 /// } 67 /// 68 struct CIRGenBitFieldInfo { 69 /// The offset within a contiguous run of bitfields that are represented as 70 /// 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 this 80 /// 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 a 87 /// single "field" within the cir.record type, taking into account the AAPCS 88 /// 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 this 92 /// 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 bitfield 99 llvm::StringRef name; 100 101 // The actual storage type for the bitfield 102 mlir::Type storageType; 103 CIRGenBitFieldInfoCIRGenBitFieldInfo104 CIRGenBitFieldInfo() 105 : offset(), size(), isSigned(), storageSize(), volatileOffset(), 106 volatileStorageSize() {} 107 CIRGenBitFieldInfoCIRGenBitFieldInfo108 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 types 118 /// to CIR types. 119 /// 120 /// These layout objects are only created on demand as CIR generation requires. 121 class CIRGenRecordLayout { 122 friend class CIRGenTypes; 123 124 CIRGenRecordLayout(const CIRGenRecordLayout &) = delete; 125 void operator=(const CIRGenRecordLayout &) = delete; 126 127 private: 128 /// The CIR type corresponding to this record layout; used when laying it out 129 /// as a complete object. 130 cir::RecordType completeObjectType; 131 132 /// The CIR type for the non-virtual part of this record layout; used when 133 /// 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 type 137 /// 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 map 141 // for both virtual and non-virtual bases. 142 llvm::DenseMap<const clang::CXXRecordDecl *, unsigned> nonVirtualBases; 143 144 /// Map from (bit-field) record field to the corresponding CIR record type 145 /// field no. This info is populated by record builder. 146 llvm::DenseMap<const clang::FieldDecl *, CIRGenBitFieldInfo> bitFields; 147 148 /// False if any direct or indirect subobject of this class, when considered 149 /// as a complete object, requires a non-zero bitpattern when 150 /// zero-initialized. 151 LLVM_PREFERRED_TYPE(bool) 152 unsigned zeroInitializable : 1; 153 154 /// False if any direct or indirect subobject of this class, when considered 155 /// as a base subobject, requires a non-zero bitpattern when zero-initialized. 156 LLVM_PREFERRED_TYPE(bool) 157 unsigned zeroInitializableAsBase : 1; 158 159 public: CIRGenRecordLayout(cir::RecordType completeObjectType,cir::RecordType baseSubobjectType,bool zeroInitializable,bool zeroInitializableAsBase)160 CIRGenRecordLayout(cir::RecordType completeObjectType, 161 cir::RecordType baseSubobjectType, bool zeroInitializable, 162 bool zeroInitializableAsBase) 163 : completeObjectType(completeObjectType), 164 baseSubobjectType(baseSubobjectType), 165 zeroInitializable(zeroInitializable), 166 zeroInitializableAsBase(zeroInitializableAsBase) {} 167 168 /// Return the "complete object" LLVM type associated with 169 /// this record. getCIRType()170 cir::RecordType getCIRType() const { return completeObjectType; } 171 172 /// Return the "base subobject" LLVM type associated with 173 /// this record. getBaseSubobjectCIRType()174 cir::RecordType getBaseSubobjectCIRType() const { return baseSubobjectType; } 175 176 /// Return cir::RecordType element number that corresponds to the field FD. getCIRFieldNo(const clang::FieldDecl * fd)177 unsigned getCIRFieldNo(const clang::FieldDecl *fd) const { 178 fd = fd->getCanonicalDecl(); 179 assert(fieldIdxMap.count(fd) && "Invalid field for record!"); 180 return fieldIdxMap.lookup(fd); 181 } 182 183 /// Check whether this struct can be C++ zero-initialized 184 /// with a zeroinitializer. isZeroInitializable()185 bool isZeroInitializable() const { return zeroInitializable; } 186 187 /// Check whether this struct can be C++ zero-initialized 188 /// with a zeroinitializer when considered as a base subobject. isZeroInitializableAsBase()189 bool isZeroInitializableAsBase() const { return zeroInitializableAsBase; } 190 191 /// Return the BitFieldInfo that corresponds to the field FD. getBitFieldInfo(const clang::FieldDecl * fd)192 const CIRGenBitFieldInfo &getBitFieldInfo(const clang::FieldDecl *fd) const { 193 fd = fd->getCanonicalDecl(); 194 assert(fd->isBitField() && "Invalid call for non-bit-field decl!"); 195 llvm::DenseMap<const clang::FieldDecl *, CIRGenBitFieldInfo>::const_iterator 196 it = bitFields.find(fd); 197 assert(it != bitFields.end() && "Unable to find bitfield info"); 198 return it->second; 199 } 200 void print(raw_ostream &os) const; 201 LLVM_DUMP_METHOD void dump() const; 202 }; 203 204 } // namespace clang::CIRGen 205 206 #endif 207