Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenBuilder.h
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H9#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H1011#include "Address.h"12#include "CIRGenRecordLayout.h"13#include "CIRGenTypeCache.h"14#include "clang/CIR/Interfaces/CIRTypeInterfaces.h"15#include "clang/CIR/MissingFeatures.h"1617#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"18#include "clang/CIR/MissingFeatures.h"19#include "llvm/ADT/APFloat.h"20#include "llvm/ADT/STLExtras.h"2122namespace clang::CIRGen {2324class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {25const CIRGenTypeCache &typeCache;26llvm::StringMap<unsigned> recordNames;27llvm::StringMap<unsigned> globalsVersioning;2829public:30CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)31: CIRBaseBuilderTy(mlirContext), typeCache(tc) {}3233/// Get a cir::ConstArrayAttr for a string literal.34/// Note: This is different from what is returned by35/// mlir::Builder::getStringAttr() which is an mlir::StringAttr.36mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,37std::optional<size_t> size) {38size_t finalSize = size.value_or(str.size());3940size_t lastNonZeroPos = str.find_last_not_of('\0');41// If the string is full of null bytes, emit a #cir.zero rather than42// a #cir.const_array.43if (lastNonZeroPos == llvm::StringRef::npos) {44auto arrayTy = cir::ArrayType::get(eltTy, finalSize);45return cir::ZeroAttr::get(arrayTy);46}47// We emit trailing zeros only if there are multiple trailing zeros.48size_t trailingZerosNum = 0;49if (finalSize > lastNonZeroPos + 2)50trailingZerosNum = finalSize - lastNonZeroPos - 1;51auto truncatedArrayTy =52cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);53auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);54return cir::ConstArrayAttr::get(55fullArrayTy,56mlir::StringAttr::get(str.drop_back(trailingZerosNum),57truncatedArrayTy),58trailingZerosNum);59}6061std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }6263std::string getUniqueRecordName(const std::string &baseName) {64auto it = recordNames.find(baseName);65if (it == recordNames.end()) {66recordNames[baseName] = 0;67return baseName;68}6970return baseName + "." + std::to_string(recordNames[baseName]++);71}7273cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {74if (&format == &llvm::APFloat::IEEEdouble())75return cir::LongDoubleType::get(getContext(), typeCache.DoubleTy);76if (&format == &llvm::APFloat::x87DoubleExtended())77return cir::LongDoubleType::get(getContext(), typeCache.FP80Ty);78if (&format == &llvm::APFloat::IEEEquad())79return cir::LongDoubleType::get(getContext(), typeCache.FP128Ty);80if (&format == &llvm::APFloat::PPCDoubleDouble())81llvm_unreachable("NYI: PPC double-double format for long double");82llvm_unreachable("Unsupported format for long double");83}8485/// Get a CIR record kind from a AST declaration tag.86cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {87switch (kind) {88case clang::TagTypeKind::Class:89return cir::RecordType::Class;90case clang::TagTypeKind::Struct:91return cir::RecordType::Struct;92case clang::TagTypeKind::Union:93return cir::RecordType::Union;94case clang::TagTypeKind::Interface:95llvm_unreachable("interface records are NYI");96case clang::TagTypeKind::Enum:97llvm_unreachable("enums are not records");98}99llvm_unreachable("Unsupported record kind");100}101102/// Get a CIR named record type.103///104/// If a record already exists and is complete, but the client tries to fetch105/// it with a different set of attributes, this method will crash.106cir::RecordType getCompleteRecordTy(llvm::ArrayRef<mlir::Type> members,107llvm::StringRef name, bool packed,108bool padded) {109const auto nameAttr = getStringAttr(name);110auto kind = cir::RecordType::RecordKind::Struct;111assert(!cir::MissingFeatures::astRecordDeclAttr());112113// Create or get the record.114auto type =115getType<cir::RecordType>(members, nameAttr, packed, padded, kind);116117// If we found an existing type, verify that either it is incomplete or118// it matches the requested attributes.119assert(!type.isIncomplete() ||120(type.getMembers() == members && type.getPacked() == packed &&121type.getPadded() == padded));122123// Complete an incomplete record or ensure the existing complete record124// matches the requested attributes.125type.complete(members, packed, padded);126127return type;128}129130/// Get an incomplete CIR struct type. If we have a complete record131/// declaration, we may create an incomplete type and then add the132/// members, so \p rd here may be complete.133cir::RecordType getIncompleteRecordTy(llvm::StringRef name,134const clang::RecordDecl *rd) {135const mlir::StringAttr nameAttr = getStringAttr(name);136cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;137if (rd)138kind = getRecordKind(rd->getTagKind());139return getType<cir::RecordType>(nameAttr, kind);140}141142// Return true if the value is a null constant such as null pointer, (+0.0)143// for floating-point or zero initializer144bool isNullValue(mlir::Attribute attr) const {145if (mlir::isa<cir::ZeroAttr>(attr))146return true;147148if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))149return ptrVal.isNullValue();150151if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))152return intVal.isNullValue();153154if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))155return !boolVal.getValue();156157if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {158auto fpVal = fpAttr.getValue();159bool ignored;160llvm::APFloat fv(+0.0);161fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,162&ignored);163return fv.bitwiseIsEqual(fpVal);164}165166if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {167if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))168return false;169170return llvm::all_of(171mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),172[&](const mlir::Attribute &elt) { return isNullValue(elt); });173}174return false;175}176177//178// Type helpers179// ------------180//181cir::IntType getUIntNTy(int n) {182switch (n) {183case 8:184return getUInt8Ty();185case 16:186return getUInt16Ty();187case 32:188return getUInt32Ty();189case 64:190return getUInt64Ty();191default:192return cir::IntType::get(getContext(), n, false);193}194}195196cir::IntType getSIntNTy(int n) {197switch (n) {198case 8:199return getSInt8Ty();200case 16:201return getSInt16Ty();202case 32:203return getSInt32Ty();204case 64:205return getSInt64Ty();206default:207return cir::IntType::get(getContext(), n, true);208}209}210211cir::VoidType getVoidTy() { return typeCache.VoidTy; }212213cir::IntType getSInt8Ty() { return typeCache.SInt8Ty; }214cir::IntType getSInt16Ty() { return typeCache.SInt16Ty; }215cir::IntType getSInt32Ty() { return typeCache.SInt32Ty; }216cir::IntType getSInt64Ty() { return typeCache.SInt64Ty; }217218cir::IntType getUInt8Ty() { return typeCache.UInt8Ty; }219cir::IntType getUInt16Ty() { return typeCache.UInt16Ty; }220cir::IntType getUInt32Ty() { return typeCache.UInt32Ty; }221cir::IntType getUInt64Ty() { return typeCache.UInt64Ty; }222223cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);224225cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal);226227cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);228229cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,230llvm::APFloat fpVal);231232bool isInt8Ty(mlir::Type i) {233return i == typeCache.UInt8Ty || i == typeCache.SInt8Ty;234}235bool isInt16Ty(mlir::Type i) {236return i == typeCache.UInt16Ty || i == typeCache.SInt16Ty;237}238bool isInt32Ty(mlir::Type i) {239return i == typeCache.UInt32Ty || i == typeCache.SInt32Ty;240}241bool isInt64Ty(mlir::Type i) {242return i == typeCache.UInt64Ty || i == typeCache.SInt64Ty;243}244bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }245246//247// Constant creation helpers248// -------------------------249//250cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {251return getConstantInt(loc, getSInt32Ty(), c);252}253254// Creates constant nullptr for pointer type ty.255cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {256assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());257return create<cir::ConstantOp>(loc, getConstPtrAttr(ty, 0));258}259260mlir::Value createNeg(mlir::Value value) {261262if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {263// Source is a unsigned integer: first cast it to signed.264if (intTy.isUnsigned())265value = createIntCast(value, getSIntNTy(intTy.getWidth()));266return create<cir::UnaryOp>(value.getLoc(), value.getType(),267cir::UnaryOpKind::Minus, value);268}269270llvm_unreachable("negation for the given type is NYI");271}272273// TODO: split this to createFPExt/createFPTrunc when we have dedicated cast274// operations.275mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {276assert(!cir::MissingFeatures::fpConstraints());277278return create<cir::CastOp>(v.getLoc(), destType, cir::CastKind::floating,279v);280}281282mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {283assert(!cir::MissingFeatures::metaDataNode());284assert(!cir::MissingFeatures::fpConstraints());285assert(!cir::MissingFeatures::fastMathFlags());286287return create<cir::BinOp>(loc, cir::BinOpKind::Sub, lhs, rhs);288}289290mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {291assert(!cir::MissingFeatures::metaDataNode());292assert(!cir::MissingFeatures::fpConstraints());293assert(!cir::MissingFeatures::fastMathFlags());294295return create<cir::BinOp>(loc, cir::BinOpKind::Add, lhs, rhs);296}297mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {298assert(!cir::MissingFeatures::metaDataNode());299assert(!cir::MissingFeatures::fpConstraints());300assert(!cir::MissingFeatures::fastMathFlags());301302return create<cir::BinOp>(loc, cir::BinOpKind::Mul, lhs, rhs);303}304mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {305assert(!cir::MissingFeatures::metaDataNode());306assert(!cir::MissingFeatures::fpConstraints());307assert(!cir::MissingFeatures::fastMathFlags());308309return create<cir::BinOp>(loc, cir::BinOpKind::Div, lhs, rhs);310}311312Address createBaseClassAddr(mlir::Location loc, Address addr,313mlir::Type destType, unsigned offset,314bool assumeNotNull) {315if (destType == addr.getElementType())316return addr;317318auto ptrTy = getPointerTo(destType);319auto baseAddr = create<cir::BaseClassAddrOp>(320loc, ptrTy, addr.getPointer(), mlir::APInt(64, offset), assumeNotNull);321return Address(baseAddr, destType, addr.getAlignment());322}323324/// Cast the element type of the given address to a different type,325/// preserving information like the alignment.326Address createElementBitCast(mlir::Location loc, Address addr,327mlir::Type destType) {328if (destType == addr.getElementType())329return addr;330331auto ptrTy = getPointerTo(destType);332return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,333addr.getAlignment());334}335336cir::LoadOp createLoad(mlir::Location loc, Address addr,337bool isVolatile = false) {338mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());339return create<cir::LoadOp>(loc, addr.getPointer(), /*isDeref=*/false,340align);341}342343cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,344mlir::IntegerAttr align = {}) {345if (!align)346align = getAlignmentAttr(dst.getAlignment());347return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);348}349350mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,351mlir::Value imag) {352auto resultComplexTy = cir::ComplexType::get(real.getType());353return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);354}355356mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {357auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());358return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);359}360361mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {362auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());363return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);364}365366/// Create a cir.complex.real_ptr operation that derives a pointer to the real367/// part of the complex value pointed to by the specified pointer value.368mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {369auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());370auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());371return create<cir::ComplexRealPtrOp>(372loc, getPointerTo(srcComplexTy.getElementType()), value);373}374375Address createComplexRealPtr(mlir::Location loc, Address addr) {376return Address{createComplexRealPtr(loc, addr.getPointer()),377addr.getAlignment()};378}379380/// Create a cir.complex.imag_ptr operation that derives a pointer to the381/// imaginary part of the complex value pointed to by the specified pointer382/// value.383mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {384auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());385auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());386return create<cir::ComplexImagPtrOp>(387loc, getPointerTo(srcComplexTy.getElementType()), value);388}389390Address createComplexImagPtr(mlir::Location loc, Address addr) {391return Address{createComplexImagPtr(loc, addr.getPointer()),392addr.getAlignment()};393}394395/// Create a cir.ptr_stride operation to get access to an array element.396/// \p idx is the index of the element to access, \p shouldDecay is true if397/// the result should decay to a pointer to the element type.398mlir::Value getArrayElement(mlir::Location arrayLocBegin,399mlir::Location arrayLocEnd, mlir::Value arrayPtr,400mlir::Type eltTy, mlir::Value idx,401bool shouldDecay);402403/// Returns a decayed pointer to the first element of the array404/// pointed to by \p arrayPtr.405mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,406mlir::Type eltTy);407408/// Creates a versioned global variable. If the symbol is already taken, an ID409/// will be appended to the symbol. The returned global must always be queried410/// for its name so it can be referenced correctly.411[[nodiscard]] cir::GlobalOp412createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,413mlir::StringRef name, mlir::Type type,414cir::GlobalLinkageKind linkage) {415// Create a unique name if the given name is already taken.416std::string uniqueName;417if (unsigned version = globalsVersioning[name.str()]++)418uniqueName = name.str() + "." + std::to_string(version);419else420uniqueName = name.str();421422return createGlobal(module, loc, uniqueName, type, linkage);423}424425mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,426mlir::Value dstAddr, mlir::Type storageType,427mlir::Value src, const CIRGenBitFieldInfo &info,428bool isLvalueVolatile, bool useVolatile) {429return create<cir::SetBitfieldOp>(loc, resultType, dstAddr, storageType,430src, info.name, info.size, info.offset,431info.isSigned, isLvalueVolatile);432}433434mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,435mlir::Value addr, mlir::Type storageType,436const CIRGenBitFieldInfo &info,437bool isLvalueVolatile, bool useVolatile) {438return create<cir::GetBitfieldOp>(loc, resultType, addr, storageType,439info.name, info.size, info.offset,440info.isSigned, isLvalueVolatile);441}442};443444} // namespace clang::CIRGen445446#endif447448449