brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.3 KiB · 85b3812 Raw
639 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_CODEGEN_CIRGENBUILDER_H10#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H11 12#include "Address.h"13#include "CIRGenRecordLayout.h"14#include "CIRGenTypeCache.h"15#include "mlir/IR/Attributes.h"16#include "mlir/IR/BuiltinAttributes.h"17#include "mlir/Support/LLVM.h"18#include "clang/CIR/Dialect/IR/CIRDataLayout.h"19#include "clang/CIR/MissingFeatures.h"20 21#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"22#include "clang/CIR/MissingFeatures.h"23#include "llvm/ADT/APFloat.h"24#include "llvm/ADT/STLExtras.h"25 26namespace clang::CIRGen {27 28class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {29  const CIRGenTypeCache &typeCache;30  llvm::StringMap<unsigned> recordNames;31  llvm::StringMap<unsigned> globalsVersioning;32 33public:34  CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)35      : CIRBaseBuilderTy(mlirContext), typeCache(tc) {}36 37  /// Get a cir::ConstArrayAttr for a string literal.38  /// Note: This is different from what is returned by39  /// mlir::Builder::getStringAttr() which is an mlir::StringAttr.40  mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,41                            std::optional<size_t> size) {42    size_t finalSize = size.value_or(str.size());43 44    size_t lastNonZeroPos = str.find_last_not_of('\0');45    // If the string is full of null bytes, emit a #cir.zero rather than46    // a #cir.const_array.47    if (lastNonZeroPos == llvm::StringRef::npos) {48      auto arrayTy = cir::ArrayType::get(eltTy, finalSize);49      return cir::ZeroAttr::get(arrayTy);50    }51    // We emit trailing zeros only if there are multiple trailing zeros.52    size_t trailingZerosNum = 0;53    if (finalSize > lastNonZeroPos + 2)54      trailingZerosNum = finalSize - lastNonZeroPos - 1;55    auto truncatedArrayTy =56        cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);57    auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);58    return cir::ConstArrayAttr::get(59        fullArrayTy,60        mlir::StringAttr::get(str.drop_back(trailingZerosNum),61                              truncatedArrayTy),62        trailingZerosNum);63  }64 65  cir::ConstArrayAttr getConstArray(mlir::Attribute attrs,66                                    cir::ArrayType arrayTy) const {67    return cir::ConstArrayAttr::get(arrayTy, attrs);68  }69 70  mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,71                                           bool packed = false,72                                           bool padded = false,73                                           mlir::Type type = {});74 75  cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr,76                                          bool packed = false,77                                          bool padded = false,78                                          mlir::Type ty = {}) {79    llvm::SmallVector<mlir::Type, 4> members;80    for (auto &f : arrayAttr) {81      auto ta = mlir::cast<mlir::TypedAttr>(f);82      members.push_back(ta.getType());83    }84 85    if (!ty)86      ty = getAnonRecordTy(members, packed, padded);87 88    auto sTy = mlir::cast<cir::RecordType>(ty);89    return cir::ConstRecordAttr::get(sTy, arrayAttr);90  }91 92  cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {93    cir::ConstRecordAttr anonRecord = getAnonConstRecord(fieldsAttr);94    return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);95  }96 97  std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }98 99  std::string getUniqueRecordName(const std::string &baseName) {100    auto it = recordNames.find(baseName);101    if (it == recordNames.end()) {102      recordNames[baseName] = 0;103      return baseName;104    }105 106    return baseName + "." + std::to_string(recordNames[baseName]++);107  }108 109  cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {110    if (&format == &llvm::APFloat::IEEEdouble())111      return cir::LongDoubleType::get(getContext(), typeCache.doubleTy);112    if (&format == &llvm::APFloat::x87DoubleExtended())113      return cir::LongDoubleType::get(getContext(), typeCache.fP80Ty);114    if (&format == &llvm::APFloat::IEEEquad())115      return cir::LongDoubleType::get(getContext(), typeCache.fP128Ty);116    if (&format == &llvm::APFloat::PPCDoubleDouble())117      llvm_unreachable("NYI: PPC double-double format for long double");118    llvm_unreachable("Unsupported format for long double");119  }120 121  mlir::Type getPtrToVPtrType() {122    return getPointerTo(cir::VPtrType::get(getContext()));123  }124 125  cir::FuncType getFuncType(llvm::ArrayRef<mlir::Type> params, mlir::Type retTy,126                            bool isVarArg = false) {127    return cir::FuncType::get(params, retTy, isVarArg);128  }129 130  /// Get a CIR record kind from a AST declaration tag.131  cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {132    switch (kind) {133    case clang::TagTypeKind::Class:134      return cir::RecordType::Class;135    case clang::TagTypeKind::Struct:136      return cir::RecordType::Struct;137    case clang::TagTypeKind::Union:138      return cir::RecordType::Union;139    case clang::TagTypeKind::Interface:140      llvm_unreachable("interface records are NYI");141    case clang::TagTypeKind::Enum:142      llvm_unreachable("enums are not records");143    }144    llvm_unreachable("Unsupported record kind");145  }146 147  /// Get a CIR named record type.148  ///149  /// If a record already exists and is complete, but the client tries to fetch150  /// it with a different set of attributes, this method will crash.151  cir::RecordType getCompleteNamedRecordType(llvm::ArrayRef<mlir::Type> members,152                                             bool packed, bool padded,153                                             llvm::StringRef name) {154    const auto nameAttr = getStringAttr(name);155    auto kind = cir::RecordType::RecordKind::Struct;156    assert(!cir::MissingFeatures::astRecordDeclAttr());157 158    // Create or get the record.159    auto type =160        getType<cir::RecordType>(members, nameAttr, packed, padded, kind);161 162    // If we found an existing type, verify that either it is incomplete or163    // it matches the requested attributes.164    assert(!type.isIncomplete() ||165           (type.getMembers() == members && type.getPacked() == packed &&166            type.getPadded() == padded));167 168    // Complete an incomplete record or ensure the existing complete record169    // matches the requested attributes.170    type.complete(members, packed, padded);171 172    return type;173  }174 175  cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields,176                                        bool packed = false,177                                        bool padded = false,178                                        llvm::StringRef name = "");179 180  /// Get an incomplete CIR struct type. If we have a complete record181  /// declaration, we may create an incomplete type and then add the182  /// members, so \p rd here may be complete.183  cir::RecordType getIncompleteRecordTy(llvm::StringRef name,184                                        const clang::RecordDecl *rd) {185    const mlir::StringAttr nameAttr = getStringAttr(name);186    cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;187    if (rd)188      kind = getRecordKind(rd->getTagKind());189    return getType<cir::RecordType>(nameAttr, kind);190  }191 192  // Return true if the value is a null constant such as null pointer, (+0.0)193  // for floating-point or zero initializer194  bool isNullValue(mlir::Attribute attr) const {195    if (mlir::isa<cir::ZeroAttr>(attr))196      return true;197 198    if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))199      return ptrVal.isNullValue();200 201    if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))202      return intVal.isNullValue();203 204    if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))205      return !boolVal.getValue();206 207    if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {208      auto fpVal = fpAttr.getValue();209      bool ignored;210      llvm::APFloat fv(+0.0);211      fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,212                 &ignored);213      return fv.bitwiseIsEqual(fpVal);214    }215    if (const auto recordVal = mlir::dyn_cast<cir::ConstRecordAttr>(attr)) {216      for (const auto elt : recordVal.getMembers()) {217        // FIXME(cir): the record's ID should not be considered a member.218        if (mlir::isa<mlir::StringAttr>(elt))219          continue;220        if (!isNullValue(elt))221          return false;222      }223      return true;224    }225 226    if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {227      if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))228        return false;229 230      return llvm::all_of(231          mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),232          [&](const mlir::Attribute &elt) { return isNullValue(elt); });233    }234    return false;235  }236 237  //238  // Type helpers239  // ------------240  //241  cir::IntType getUIntNTy(int n) {242    switch (n) {243    case 8:244      return getUInt8Ty();245    case 16:246      return getUInt16Ty();247    case 32:248      return getUInt32Ty();249    case 64:250      return getUInt64Ty();251    default:252      return cir::IntType::get(getContext(), n, false);253    }254  }255 256  cir::IntType getSIntNTy(int n) {257    switch (n) {258    case 8:259      return getSInt8Ty();260    case 16:261      return getSInt16Ty();262    case 32:263      return getSInt32Ty();264    case 64:265      return getSInt64Ty();266    default:267      return cir::IntType::get(getContext(), n, true);268    }269  }270 271  cir::VoidType getVoidTy() { return typeCache.voidTy; }272 273  cir::IntType getSInt8Ty() { return typeCache.sInt8Ty; }274  cir::IntType getSInt16Ty() { return typeCache.sInt16Ty; }275  cir::IntType getSInt32Ty() { return typeCache.sInt32Ty; }276  cir::IntType getSInt64Ty() { return typeCache.sInt64Ty; }277 278  cir::IntType getUInt8Ty() { return typeCache.uInt8Ty; }279  cir::IntType getUInt16Ty() { return typeCache.uInt16Ty; }280  cir::IntType getUInt32Ty() { return typeCache.uInt32Ty; }281  cir::IntType getUInt64Ty() { return typeCache.uInt64Ty; }282 283  cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);284 285  cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal);286 287  cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);288 289  cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,290                             llvm::APFloat fpVal);291 292  bool isInt8Ty(mlir::Type i) {293    return i == typeCache.uInt8Ty || i == typeCache.sInt8Ty;294  }295  bool isInt16Ty(mlir::Type i) {296    return i == typeCache.uInt16Ty || i == typeCache.sInt16Ty;297  }298  bool isInt32Ty(mlir::Type i) {299    return i == typeCache.uInt32Ty || i == typeCache.sInt32Ty;300  }301  bool isInt64Ty(mlir::Type i) {302    return i == typeCache.uInt64Ty || i == typeCache.sInt64Ty;303  }304  bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }305 306  // Fetch the type representing a pointer to unsigned int8 values.307  cir::PointerType getUInt8PtrTy() { return typeCache.uInt8PtrTy; }308 309  /// Get a CIR anonymous record type.310  cir::RecordType getAnonRecordTy(llvm::ArrayRef<mlir::Type> members,311                                  bool packed = false, bool padded = false) {312    assert(!cir::MissingFeatures::astRecordDeclAttr());313    auto kind = cir::RecordType::RecordKind::Struct;314    return getType<cir::RecordType>(members, packed, padded, kind);315  }316 317  //318  // Constant creation helpers319  // -------------------------320  //321  cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {322    return getConstantInt(loc, getSInt32Ty(), c);323  }324  cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc) {325    return getConstantInt(loc, getUInt32Ty(), c);326  }327  cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc) {328    return getConstantInt(loc, getSInt64Ty(), c);329  }330  cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc) {331    return getConstantInt(loc, getUInt64Ty(), c);332  }333 334  mlir::Value createNeg(mlir::Value value) {335 336    if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {337      // Source is a unsigned integer: first cast it to signed.338      if (intTy.isUnsigned())339        value = createIntCast(value, getSIntNTy(intTy.getWidth()));340      return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),341                                  cir::UnaryOpKind::Minus, value);342    }343 344    llvm_unreachable("negation for the given type is NYI");345  }346 347  cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,348                                   cir::FPClassTest flags) {349    return cir::IsFPClassOp::create(*this, loc, src, flags);350  }351 352  // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast353  // operations.354  mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {355    assert(!cir::MissingFeatures::fpConstraints());356 357    return cir::CastOp::create(*this, v.getLoc(), destType,358                               cir::CastKind::floating, v);359  }360 361  mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {362    assert(!cir::MissingFeatures::metaDataNode());363    assert(!cir::MissingFeatures::fpConstraints());364    assert(!cir::MissingFeatures::fastMathFlags());365 366    return cir::BinOp::create(*this, loc, cir::BinOpKind::Sub, lhs, rhs);367  }368 369  mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {370    assert(!cir::MissingFeatures::metaDataNode());371    assert(!cir::MissingFeatures::fpConstraints());372    assert(!cir::MissingFeatures::fastMathFlags());373 374    return cir::BinOp::create(*this, loc, cir::BinOpKind::Add, lhs, rhs);375  }376  mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {377    assert(!cir::MissingFeatures::metaDataNode());378    assert(!cir::MissingFeatures::fpConstraints());379    assert(!cir::MissingFeatures::fastMathFlags());380 381    return cir::BinOp::create(*this, loc, cir::BinOpKind::Mul, lhs, rhs);382  }383  mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {384    assert(!cir::MissingFeatures::metaDataNode());385    assert(!cir::MissingFeatures::fpConstraints());386    assert(!cir::MissingFeatures::fastMathFlags());387 388    return cir::BinOp::create(*this, loc, cir::BinOpKind::Div, lhs, rhs);389  }390 391  mlir::Value createDynCast(mlir::Location loc, mlir::Value src,392                            cir::PointerType destType, bool isRefCast,393                            cir::DynamicCastInfoAttr info) {394    auto castKind =395        isRefCast ? cir::DynamicCastKind::Ref : cir::DynamicCastKind::Ptr;396    return cir::DynamicCastOp::create(*this, loc, destType, castKind, src, info,397                                      /*relative_layout=*/false);398  }399 400  mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src,401                                  bool vtableUseRelativeLayout) {402    // TODO(cir): consider address space here.403    assert(!cir::MissingFeatures::addressSpace());404    cir::PointerType destTy = getVoidPtrTy();405    return cir::DynamicCastOp::create(406        *this, loc, destTy, cir::DynamicCastKind::Ptr, src,407        cir::DynamicCastInfoAttr{}, vtableUseRelativeLayout);408  }409 410  Address createBaseClassAddr(mlir::Location loc, Address addr,411                              mlir::Type destType, unsigned offset,412                              bool assumeNotNull) {413    if (destType == addr.getElementType())414      return addr;415 416    auto ptrTy = getPointerTo(destType);417    auto baseAddr =418        cir::BaseClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),419                                     mlir::APInt(64, offset), assumeNotNull);420    return Address(baseAddr, destType, addr.getAlignment());421  }422 423  Address createDerivedClassAddr(mlir::Location loc, Address addr,424                                 mlir::Type destType, unsigned offset,425                                 bool assumeNotNull) {426    if (destType == addr.getElementType())427      return addr;428 429    cir::PointerType ptrTy = getPointerTo(destType);430    auto derivedAddr =431        cir::DerivedClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),432                                        mlir::APInt(64, offset), assumeNotNull);433    return Address(derivedAddr, destType, addr.getAlignment());434  }435 436  mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,437                                 mlir::Value addr, uint64_t offset) {438    return cir::VTTAddrPointOp::create(*this, loc, retTy,439                                       mlir::FlatSymbolRefAttr{}, addr, offset);440  }441 442  mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,443                                 mlir::FlatSymbolRefAttr sym, uint64_t offset) {444    return cir::VTTAddrPointOp::create(*this, loc, retTy, sym, mlir::Value{},445                                       offset);446  }447 448  /// Cast the element type of the given address to a different type,449  /// preserving information like the alignment.450  Address createElementBitCast(mlir::Location loc, Address addr,451                               mlir::Type destType) {452    if (destType == addr.getElementType())453      return addr;454 455    auto ptrTy = getPointerTo(destType);456    return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,457                   addr.getAlignment());458  }459 460  cir::LoadOp createLoad(mlir::Location loc, Address addr,461                         bool isVolatile = false) {462    mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());463    return cir::LoadOp::create(*this, loc, addr.getPointer(), /*isDeref=*/false,464                               isVolatile, /*alignment=*/align,465                               /*mem_order=*/cir::MemOrderAttr{});466  }467 468  cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty,469                                mlir::Value ptr, llvm::MaybeAlign align) {470    if (ty != mlir::cast<cir::PointerType>(ptr.getType()).getPointee())471      ptr = createPtrBitcast(ptr, ty);472    uint64_t alignment = align ? align->value() : 0;473    mlir::IntegerAttr alignAttr = getAlignmentAttr(alignment);474    return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,475                               /*isVolatile=*/false, alignAttr,476                               /*mem_order=*/cir::MemOrderAttr{});477  }478 479  cir::LoadOp480  createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr,481                    clang::CharUnits align = clang::CharUnits::One()) {482    return createAlignedLoad(loc, ty, ptr, align.getAsAlign());483  }484 485  cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,486                           bool isVolatile = false,487                           mlir::IntegerAttr align = {},488                           cir::MemOrderAttr order = {}) {489    if (!align)490      align = getAlignmentAttr(dst.getAlignment());491    return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), isVolatile,492                                         align, order);493  }494 495  /// Create a cir.complex.real_ptr operation that derives a pointer to the real496  /// part of the complex value pointed to by the specified pointer value.497  mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {498    auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());499    auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());500    return cir::ComplexRealPtrOp::create(501        *this, loc, getPointerTo(srcComplexTy.getElementType()), value);502  }503 504  Address createComplexRealPtr(mlir::Location loc, Address addr) {505    return Address{createComplexRealPtr(loc, addr.getPointer()),506                   addr.getAlignment()};507  }508 509  /// Create a cir.complex.imag_ptr operation that derives a pointer to the510  /// imaginary part of the complex value pointed to by the specified pointer511  /// value.512  mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {513    auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());514    auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());515    return cir::ComplexImagPtrOp::create(516        *this, loc, getPointerTo(srcComplexTy.getElementType()), value);517  }518 519  Address createComplexImagPtr(mlir::Location loc, Address addr) {520    return Address{createComplexImagPtr(loc, addr.getPointer()),521                   addr.getAlignment()};522  }523 524  /// Create a cir.ptr_stride operation to get access to an array element.525  /// \p idx is the index of the element to access, \p shouldDecay is true if526  /// the result should decay to a pointer to the element type.527  mlir::Value getArrayElement(mlir::Location arrayLocBegin,528                              mlir::Location arrayLocEnd, mlir::Value arrayPtr,529                              mlir::Type eltTy, mlir::Value idx,530                              bool shouldDecay);531 532  /// Returns a decayed pointer to the first element of the array533  /// pointed to by \p arrayPtr.534  mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,535                                   mlir::Type eltTy);536 537  // Convert byte offset to sequence of high-level indices suitable for538  // GlobalViewAttr. Ideally we shouldn't deal with low-level offsets at all539  // but currently some parts of Clang AST, which we don't want to touch just540  // yet, return them.541  void computeGlobalViewIndicesFromFlatOffset(542      int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,543      llvm::SmallVectorImpl<int64_t> &indices);544 545  /// Creates a versioned global variable. If the symbol is already taken, an ID546  /// will be appended to the symbol. The returned global must always be queried547  /// for its name so it can be referenced correctly.548  [[nodiscard]] cir::GlobalOp549  createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,550                        mlir::StringRef name, mlir::Type type, bool isConstant,551                        cir::GlobalLinkageKind linkage) {552    // Create a unique name if the given name is already taken.553    std::string uniqueName;554    if (unsigned version = globalsVersioning[name.str()]++)555      uniqueName = name.str() + "." + std::to_string(version);556    else557      uniqueName = name.str();558 559    return createGlobal(module, loc, uniqueName, type, isConstant, linkage);560  }561 562  cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {563    return cir::StackSaveOp::create(*this, loc, ty);564  }565 566  cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {567    return cir::StackRestoreOp::create(*this, loc, v);568  }569 570  mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,571                                Address dstAddr, mlir::Type storageType,572                                mlir::Value src, const CIRGenBitFieldInfo &info,573                                bool isLvalueVolatile, bool useVolatile) {574    unsigned offset = useVolatile ? info.volatileOffset : info.offset;575 576    // If using AAPCS and the field is volatile, load with the size of the577    // declared field578    storageType =579        useVolatile ? cir::IntType::get(storageType.getContext(),580                                        info.volatileStorageSize, info.isSigned)581                    : storageType;582    return cir::SetBitfieldOp::create(583        *this, loc, resultType, dstAddr.getPointer(), storageType, src,584        info.name, info.size, offset, info.isSigned, isLvalueVolatile,585        dstAddr.getAlignment().getAsAlign().value());586  }587 588  mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,589                                Address addr, mlir::Type storageType,590                                const CIRGenBitFieldInfo &info,591                                bool isLvalueVolatile, bool useVolatile) {592    unsigned offset = useVolatile ? info.volatileOffset : info.offset;593 594    // If using AAPCS and the field is volatile, load with the size of the595    // declared field596    storageType =597        useVolatile ? cir::IntType::get(storageType.getContext(),598                                        info.volatileStorageSize, info.isSigned)599                    : storageType;600    return cir::GetBitfieldOp::create(*this, loc, resultType, addr.getPointer(),601                                      storageType, info.name, info.size, offset,602                                      info.isSigned, isLvalueVolatile,603                                      addr.getAlignment().getAsAlign().value());604  }605 606  cir::VecShuffleOp607  createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,608                   llvm::ArrayRef<mlir::Attribute> maskAttrs) {609    auto vecType = mlir::cast<cir::VectorType>(vec1.getType());610    auto resultTy = cir::VectorType::get(getContext(), vecType.getElementType(),611                                         maskAttrs.size());612    return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,613                                     getArrayAttr(maskAttrs));614  }615 616  cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,617                                     mlir::Value vec2,618                                     llvm::ArrayRef<int64_t> mask) {619    auto maskAttrs = llvm::to_vector_of<mlir::Attribute>(620        llvm::map_range(mask, [&](int32_t idx) {621          return cir::IntAttr::get(getSInt32Ty(), idx);622        }));623    return createVecShuffle(loc, vec1, vec2, maskAttrs);624  }625 626  cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,627                                     llvm::ArrayRef<int64_t> mask) {628    /// Create a unary shuffle. The second vector operand of the IR instruction629    /// is poison.630    cir::ConstantOp poison =631        getConstant(loc, cir::PoisonAttr::get(vec1.getType()));632    return createVecShuffle(loc, vec1, poison, mask);633  }634};635 636} // namespace clang::CIRGen637 638#endif639