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_CODEGEN_CIRGENBUILDER_H 10 #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H 11 12 #include "Address.h" 13 #include "CIRGenRecordLayout.h" 14 #include "CIRGenTypeCache.h" 15 #include "clang/CIR/Interfaces/CIRTypeInterfaces.h" 16 #include "clang/CIR/MissingFeatures.h" 17 18 #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" 19 #include "clang/CIR/MissingFeatures.h" 20 #include "llvm/ADT/APFloat.h" 21 #include "llvm/ADT/STLExtras.h" 22 23 namespace clang::CIRGen { 24 25 class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { 26 const CIRGenTypeCache &typeCache; 27 llvm::StringMap<unsigned> recordNames; 28 llvm::StringMap<unsigned> globalsVersioning; 29 30 public: CIRGenBuilderTy(mlir::MLIRContext & mlirContext,const CIRGenTypeCache & tc)31 CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc) 32 : CIRBaseBuilderTy(mlirContext), typeCache(tc) {} 33 34 /// Get a cir::ConstArrayAttr for a string literal. 35 /// Note: This is different from what is returned by 36 /// mlir::Builder::getStringAttr() which is an mlir::StringAttr. getString(llvm::StringRef str,mlir::Type eltTy,std::optional<size_t> size)37 mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy, 38 std::optional<size_t> size) { 39 size_t finalSize = size.value_or(str.size()); 40 41 size_t lastNonZeroPos = str.find_last_not_of('\0'); 42 // If the string is full of null bytes, emit a #cir.zero rather than 43 // a #cir.const_array. 44 if (lastNonZeroPos == llvm::StringRef::npos) { 45 auto arrayTy = cir::ArrayType::get(eltTy, finalSize); 46 return cir::ZeroAttr::get(arrayTy); 47 } 48 // We emit trailing zeros only if there are multiple trailing zeros. 49 size_t trailingZerosNum = 0; 50 if (finalSize > lastNonZeroPos + 2) 51 trailingZerosNum = finalSize - lastNonZeroPos - 1; 52 auto truncatedArrayTy = 53 cir::ArrayType::get(eltTy, finalSize - trailingZerosNum); 54 auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize); 55 return cir::ConstArrayAttr::get( 56 fullArrayTy, 57 mlir::StringAttr::get(str.drop_back(trailingZerosNum), 58 truncatedArrayTy), 59 trailingZerosNum); 60 } 61 getUniqueAnonRecordName()62 std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); } 63 getUniqueRecordName(const std::string & baseName)64 std::string getUniqueRecordName(const std::string &baseName) { 65 auto it = recordNames.find(baseName); 66 if (it == recordNames.end()) { 67 recordNames[baseName] = 0; 68 return baseName; 69 } 70 71 return baseName + "." + std::to_string(recordNames[baseName]++); 72 } 73 getLongDoubleTy(const llvm::fltSemantics & format)74 cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const { 75 if (&format == &llvm::APFloat::IEEEdouble()) 76 return cir::LongDoubleType::get(getContext(), typeCache.DoubleTy); 77 if (&format == &llvm::APFloat::x87DoubleExtended()) 78 return cir::LongDoubleType::get(getContext(), typeCache.FP80Ty); 79 if (&format == &llvm::APFloat::IEEEquad()) 80 return cir::LongDoubleType::get(getContext(), typeCache.FP128Ty); 81 if (&format == &llvm::APFloat::PPCDoubleDouble()) 82 llvm_unreachable("NYI: PPC double-double format for long double"); 83 llvm_unreachable("Unsupported format for long double"); 84 } 85 86 /// Get a CIR record kind from a AST declaration tag. getRecordKind(const clang::TagTypeKind kind)87 cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) { 88 switch (kind) { 89 case clang::TagTypeKind::Class: 90 return cir::RecordType::Class; 91 case clang::TagTypeKind::Struct: 92 return cir::RecordType::Struct; 93 case clang::TagTypeKind::Union: 94 return cir::RecordType::Union; 95 case clang::TagTypeKind::Interface: 96 llvm_unreachable("interface records are NYI"); 97 case clang::TagTypeKind::Enum: 98 llvm_unreachable("enums are not records"); 99 } 100 llvm_unreachable("Unsupported record kind"); 101 } 102 103 /// Get a CIR named record type. 104 /// 105 /// If a record already exists and is complete, but the client tries to fetch 106 /// it with a different set of attributes, this method will crash. getCompleteRecordTy(llvm::ArrayRef<mlir::Type> members,llvm::StringRef name,bool packed,bool padded)107 cir::RecordType getCompleteRecordTy(llvm::ArrayRef<mlir::Type> members, 108 llvm::StringRef name, bool packed, 109 bool padded) { 110 const auto nameAttr = getStringAttr(name); 111 auto kind = cir::RecordType::RecordKind::Struct; 112 assert(!cir::MissingFeatures::astRecordDeclAttr()); 113 114 // Create or get the record. 115 auto type = 116 getType<cir::RecordType>(members, nameAttr, packed, padded, kind); 117 118 // If we found an existing type, verify that either it is incomplete or 119 // it matches the requested attributes. 120 assert(!type.isIncomplete() || 121 (type.getMembers() == members && type.getPacked() == packed && 122 type.getPadded() == padded)); 123 124 // Complete an incomplete record or ensure the existing complete record 125 // matches the requested attributes. 126 type.complete(members, packed, padded); 127 128 return type; 129 } 130 131 /// Get an incomplete CIR struct type. If we have a complete record 132 /// declaration, we may create an incomplete type and then add the 133 /// members, so \p rd here may be complete. getIncompleteRecordTy(llvm::StringRef name,const clang::RecordDecl * rd)134 cir::RecordType getIncompleteRecordTy(llvm::StringRef name, 135 const clang::RecordDecl *rd) { 136 const mlir::StringAttr nameAttr = getStringAttr(name); 137 cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct; 138 if (rd) 139 kind = getRecordKind(rd->getTagKind()); 140 return getType<cir::RecordType>(nameAttr, kind); 141 } 142 143 // Return true if the value is a null constant such as null pointer, (+0.0) 144 // for floating-point or zero initializer isNullValue(mlir::Attribute attr)145 bool isNullValue(mlir::Attribute attr) const { 146 if (mlir::isa<cir::ZeroAttr>(attr)) 147 return true; 148 149 if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr)) 150 return ptrVal.isNullValue(); 151 152 if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr)) 153 return intVal.isNullValue(); 154 155 if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr)) 156 return !boolVal.getValue(); 157 158 if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) { 159 auto fpVal = fpAttr.getValue(); 160 bool ignored; 161 llvm::APFloat fv(+0.0); 162 fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven, 163 &ignored); 164 return fv.bitwiseIsEqual(fpVal); 165 } 166 167 if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) { 168 if (mlir::isa<mlir::StringAttr>(arrayVal.getElts())) 169 return false; 170 171 return llvm::all_of( 172 mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()), 173 [&](const mlir::Attribute &elt) { return isNullValue(elt); }); 174 } 175 return false; 176 } 177 178 // 179 // Type helpers 180 // ------------ 181 // getUIntNTy(int n)182 cir::IntType getUIntNTy(int n) { 183 switch (n) { 184 case 8: 185 return getUInt8Ty(); 186 case 16: 187 return getUInt16Ty(); 188 case 32: 189 return getUInt32Ty(); 190 case 64: 191 return getUInt64Ty(); 192 default: 193 return cir::IntType::get(getContext(), n, false); 194 } 195 } 196 getSIntNTy(int n)197 cir::IntType getSIntNTy(int n) { 198 switch (n) { 199 case 8: 200 return getSInt8Ty(); 201 case 16: 202 return getSInt16Ty(); 203 case 32: 204 return getSInt32Ty(); 205 case 64: 206 return getSInt64Ty(); 207 default: 208 return cir::IntType::get(getContext(), n, true); 209 } 210 } 211 getVoidTy()212 cir::VoidType getVoidTy() { return typeCache.VoidTy; } 213 getSInt8Ty()214 cir::IntType getSInt8Ty() { return typeCache.SInt8Ty; } getSInt16Ty()215 cir::IntType getSInt16Ty() { return typeCache.SInt16Ty; } getSInt32Ty()216 cir::IntType getSInt32Ty() { return typeCache.SInt32Ty; } getSInt64Ty()217 cir::IntType getSInt64Ty() { return typeCache.SInt64Ty; } 218 getUInt8Ty()219 cir::IntType getUInt8Ty() { return typeCache.UInt8Ty; } getUInt16Ty()220 cir::IntType getUInt16Ty() { return typeCache.UInt16Ty; } getUInt32Ty()221 cir::IntType getUInt32Ty() { return typeCache.UInt32Ty; } getUInt64Ty()222 cir::IntType getUInt64Ty() { return typeCache.UInt64Ty; } 223 224 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal); 225 226 cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal); 227 228 cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c); 229 230 cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t, 231 llvm::APFloat fpVal); 232 isInt8Ty(mlir::Type i)233 bool isInt8Ty(mlir::Type i) { 234 return i == typeCache.UInt8Ty || i == typeCache.SInt8Ty; 235 } isInt16Ty(mlir::Type i)236 bool isInt16Ty(mlir::Type i) { 237 return i == typeCache.UInt16Ty || i == typeCache.SInt16Ty; 238 } isInt32Ty(mlir::Type i)239 bool isInt32Ty(mlir::Type i) { 240 return i == typeCache.UInt32Ty || i == typeCache.SInt32Ty; 241 } isInt64Ty(mlir::Type i)242 bool isInt64Ty(mlir::Type i) { 243 return i == typeCache.UInt64Ty || i == typeCache.SInt64Ty; 244 } isInt(mlir::Type i)245 bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); } 246 247 // 248 // Constant creation helpers 249 // ------------------------- 250 // getSInt32(int32_t c,mlir::Location loc)251 cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) { 252 return getConstantInt(loc, getSInt32Ty(), c); 253 } 254 255 // Creates constant nullptr for pointer type ty. getNullPtr(mlir::Type ty,mlir::Location loc)256 cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) { 257 assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer()); 258 return create<cir::ConstantOp>(loc, getConstPtrAttr(ty, 0)); 259 } 260 createNeg(mlir::Value value)261 mlir::Value createNeg(mlir::Value value) { 262 263 if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) { 264 // Source is a unsigned integer: first cast it to signed. 265 if (intTy.isUnsigned()) 266 value = createIntCast(value, getSIntNTy(intTy.getWidth())); 267 return create<cir::UnaryOp>(value.getLoc(), value.getType(), 268 cir::UnaryOpKind::Minus, value); 269 } 270 271 llvm_unreachable("negation for the given type is NYI"); 272 } 273 274 // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast 275 // operations. createFloatingCast(mlir::Value v,mlir::Type destType)276 mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) { 277 assert(!cir::MissingFeatures::fpConstraints()); 278 279 return create<cir::CastOp>(v.getLoc(), destType, cir::CastKind::floating, 280 v); 281 } 282 createFSub(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)283 mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { 284 assert(!cir::MissingFeatures::metaDataNode()); 285 assert(!cir::MissingFeatures::fpConstraints()); 286 assert(!cir::MissingFeatures::fastMathFlags()); 287 288 return create<cir::BinOp>(loc, cir::BinOpKind::Sub, lhs, rhs); 289 } 290 createFAdd(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)291 mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { 292 assert(!cir::MissingFeatures::metaDataNode()); 293 assert(!cir::MissingFeatures::fpConstraints()); 294 assert(!cir::MissingFeatures::fastMathFlags()); 295 296 return create<cir::BinOp>(loc, cir::BinOpKind::Add, lhs, rhs); 297 } createFMul(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)298 mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { 299 assert(!cir::MissingFeatures::metaDataNode()); 300 assert(!cir::MissingFeatures::fpConstraints()); 301 assert(!cir::MissingFeatures::fastMathFlags()); 302 303 return create<cir::BinOp>(loc, cir::BinOpKind::Mul, lhs, rhs); 304 } createFDiv(mlir::Location loc,mlir::Value lhs,mlir::Value rhs)305 mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) { 306 assert(!cir::MissingFeatures::metaDataNode()); 307 assert(!cir::MissingFeatures::fpConstraints()); 308 assert(!cir::MissingFeatures::fastMathFlags()); 309 310 return create<cir::BinOp>(loc, cir::BinOpKind::Div, lhs, rhs); 311 } 312 createBaseClassAddr(mlir::Location loc,Address addr,mlir::Type destType,unsigned offset,bool assumeNotNull)313 Address createBaseClassAddr(mlir::Location loc, Address addr, 314 mlir::Type destType, unsigned offset, 315 bool assumeNotNull) { 316 if (destType == addr.getElementType()) 317 return addr; 318 319 auto ptrTy = getPointerTo(destType); 320 auto baseAddr = create<cir::BaseClassAddrOp>( 321 loc, ptrTy, addr.getPointer(), mlir::APInt(64, offset), assumeNotNull); 322 return Address(baseAddr, destType, addr.getAlignment()); 323 } 324 325 /// Cast the element type of the given address to a different type, 326 /// preserving information like the alignment. createElementBitCast(mlir::Location loc,Address addr,mlir::Type destType)327 Address createElementBitCast(mlir::Location loc, Address addr, 328 mlir::Type destType) { 329 if (destType == addr.getElementType()) 330 return addr; 331 332 auto ptrTy = getPointerTo(destType); 333 return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType, 334 addr.getAlignment()); 335 } 336 337 cir::LoadOp createLoad(mlir::Location loc, Address addr, 338 bool isVolatile = false) { 339 mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment()); 340 return create<cir::LoadOp>(loc, addr.getPointer(), /*isDeref=*/false, 341 align); 342 } 343 344 cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, 345 mlir::IntegerAttr align = {}) { 346 if (!align) 347 align = getAlignmentAttr(dst.getAlignment()); 348 return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align); 349 } 350 createComplexCreate(mlir::Location loc,mlir::Value real,mlir::Value imag)351 mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, 352 mlir::Value imag) { 353 auto resultComplexTy = cir::ComplexType::get(real.getType()); 354 return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag); 355 } 356 createComplexReal(mlir::Location loc,mlir::Value operand)357 mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) { 358 auto operandTy = mlir::cast<cir::ComplexType>(operand.getType()); 359 return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand); 360 } 361 createComplexImag(mlir::Location loc,mlir::Value operand)362 mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) { 363 auto operandTy = mlir::cast<cir::ComplexType>(operand.getType()); 364 return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand); 365 } 366 367 /// Create a cir.complex.real_ptr operation that derives a pointer to the real 368 /// part of the complex value pointed to by the specified pointer value. createComplexRealPtr(mlir::Location loc,mlir::Value value)369 mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) { 370 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType()); 371 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee()); 372 return create<cir::ComplexRealPtrOp>( 373 loc, getPointerTo(srcComplexTy.getElementType()), value); 374 } 375 createComplexRealPtr(mlir::Location loc,Address addr)376 Address createComplexRealPtr(mlir::Location loc, Address addr) { 377 return Address{createComplexRealPtr(loc, addr.getPointer()), 378 addr.getAlignment()}; 379 } 380 381 /// Create a cir.complex.imag_ptr operation that derives a pointer to the 382 /// imaginary part of the complex value pointed to by the specified pointer 383 /// value. createComplexImagPtr(mlir::Location loc,mlir::Value value)384 mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) { 385 auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType()); 386 auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee()); 387 return create<cir::ComplexImagPtrOp>( 388 loc, getPointerTo(srcComplexTy.getElementType()), value); 389 } 390 createComplexImagPtr(mlir::Location loc,Address addr)391 Address createComplexImagPtr(mlir::Location loc, Address addr) { 392 return Address{createComplexImagPtr(loc, addr.getPointer()), 393 addr.getAlignment()}; 394 } 395 396 /// Create a cir.ptr_stride operation to get access to an array element. 397 /// \p idx is the index of the element to access, \p shouldDecay is true if 398 /// the result should decay to a pointer to the element type. 399 mlir::Value getArrayElement(mlir::Location arrayLocBegin, 400 mlir::Location arrayLocEnd, mlir::Value arrayPtr, 401 mlir::Type eltTy, mlir::Value idx, 402 bool shouldDecay); 403 404 /// Returns a decayed pointer to the first element of the array 405 /// pointed to by \p arrayPtr. 406 mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr, 407 mlir::Type eltTy); 408 409 /// Creates a versioned global variable. If the symbol is already taken, an ID 410 /// will be appended to the symbol. The returned global must always be queried 411 /// for its name so it can be referenced correctly. 412 [[nodiscard]] cir::GlobalOp createVersionedGlobal(mlir::ModuleOp module,mlir::Location loc,mlir::StringRef name,mlir::Type type,cir::GlobalLinkageKind linkage)413 createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc, 414 mlir::StringRef name, mlir::Type type, 415 cir::GlobalLinkageKind linkage) { 416 // Create a unique name if the given name is already taken. 417 std::string uniqueName; 418 if (unsigned version = globalsVersioning[name.str()]++) 419 uniqueName = name.str() + "." + std::to_string(version); 420 else 421 uniqueName = name.str(); 422 423 return createGlobal(module, loc, uniqueName, type, linkage); 424 } 425 createSetBitfield(mlir::Location loc,mlir::Type resultType,mlir::Value dstAddr,mlir::Type storageType,mlir::Value src,const CIRGenBitFieldInfo & info,bool isLvalueVolatile,bool useVolatile)426 mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType, 427 mlir::Value dstAddr, mlir::Type storageType, 428 mlir::Value src, const CIRGenBitFieldInfo &info, 429 bool isLvalueVolatile, bool useVolatile) { 430 return create<cir::SetBitfieldOp>(loc, resultType, dstAddr, storageType, 431 src, info.name, info.size, info.offset, 432 info.isSigned, isLvalueVolatile); 433 } 434 createGetBitfield(mlir::Location loc,mlir::Type resultType,mlir::Value addr,mlir::Type storageType,const CIRGenBitFieldInfo & info,bool isLvalueVolatile,bool useVolatile)435 mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType, 436 mlir::Value addr, mlir::Type storageType, 437 const CIRGenBitFieldInfo &info, 438 bool isLvalueVolatile, bool useVolatile) { 439 return create<cir::GetBitfieldOp>(loc, resultType, addr, storageType, 440 info.name, info.size, info.offset, 441 info.isSigned, isLvalueVolatile); 442 } 443 }; 444 445 } // namespace clang::CIRGen 446 447 #endif 448