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