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