From bda6bcfcf40dde33526e4a9dcb25393a5af1b5da Mon Sep 17 00:00:00 2001 From: David Rivera Date: Mon, 29 Sep 2025 11:05:44 -0400 Subject: [PATCH 1/6] [CIR] Upstream AddressSpace casting support --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 9 +++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 41 +++++++---- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 19 +++++- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 22 ++++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 ++ clang/lib/CIR/CodeGen/CIRGenModule.cpp | 17 +++++ clang/lib/CIR/CodeGen/CIRGenModule.h | 6 ++ clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 2 +- clang/lib/CIR/CodeGen/TargetInfo.cpp | 13 ++++ clang/lib/CIR/CodeGen/TargetInfo.h | 13 ++++ clang/test/CIR/address-space-conversion.cpp | 68 +++++++++++++++++++ 11 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 clang/test/CIR/address-space-conversion.cpp diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index b4c24d7e4a8aa..2eb66ad0512e3 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -456,6 +456,15 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return createCompare(ptr.getLoc(), cir::CmpOpKind::eq, ptr, nullPtr); } + mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src, + mlir::Type newTy) { + return createCast(loc, cir::CastKind::address_space, src, newTy); + } + + mlir::Value createAddrSpaceCast(mlir::Value src, mlir::Type newTy) { + return createAddrSpaceCast(src.getLoc(), src, newTy); + } + //===--------------------------------------------------------------------===// // Binary Operators //===--------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 4cfa91e09efb4..f97dff445873f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -58,6 +58,24 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, return RValue::get(result); } +// Initialize the alloca with the given size and alignment according to the lang +// opts. Supporting only the trivial non-initialization for now. +static void initializeAlloca(CIRGenFunction &CGF, + [[maybe_unused]] mlir::Value AllocaAddr, + [[maybe_unused]] mlir::Value Size, + [[maybe_unused]] CharUnits AlignmentInBytes) { + + switch (CGF.getLangOpts().getTrivialAutoVarInit()) { + case LangOptions::TrivialAutoVarInitKind::Uninitialized: + // Nothing to initialize. + return; + case LangOptions::TrivialAutoVarInitKind::Zero: + case LangOptions::TrivialAutoVarInitKind::Pattern: + assert(false && "unexpected trivial auto var init kind NYI"); + return; + } +} + RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) { mlir::Value input = emitScalarExpr(e->getArg(0)); mlir::Value amount = emitScalarExpr(e->getArg(1)); @@ -172,21 +190,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, builder.getUInt8Ty(), "bi_alloca", suitableAlignmentInBytes, size); // Initialize the allocated buffer if required. - if (builtinID != Builtin::BI__builtin_alloca_uninitialized) { - // Initialize the alloca with the given size and alignment according to - // the lang opts. Only the trivial non-initialization is supported for - // now. - - switch (getLangOpts().getTrivialAutoVarInit()) { - case LangOptions::TrivialAutoVarInitKind::Uninitialized: - // Nothing to initialize. - break; - case LangOptions::TrivialAutoVarInitKind::Zero: - case LangOptions::TrivialAutoVarInitKind::Pattern: - cgm.errorNYI("trivial auto var init"); - break; - } - } + if (builtinID != Builtin::BI__builtin_alloca_uninitialized) + initializeAlloca(*this, allocaAddr, size, suitableAlignmentInBytes); // An alloca will always return a pointer to the alloca (stack) address // space. This address space need not be the same as the AST / Language @@ -194,6 +199,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, // the AST level this is handled within CreateTempAlloca et al., but for the // builtin / dynamic alloca we have to handle it here. assert(!cir::MissingFeatures::addressSpace()); + cir::AddressSpace aas = getCIRAllocaAddressSpace(); + cir::AddressSpace eas = cir::toCIRAddressSpace( + e->getType()->getPointeeType().getAddressSpace()); + if (eas != aas) { + assert(false && "Non-default address space for alloca NYI"); + } // Bitcast the alloca to the expected type. return RValue::get( diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 4897c29b58a1f..27329ce9bd3cf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1197,7 +1197,19 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_AtomicToNonAtomic: case CK_ToUnion: case CK_BaseToDerived: - case CK_AddressSpaceConversion: + case CK_AddressSpaceConversion: { + LValue lv = emitLValue(e->getSubExpr()); + QualType destTy = getContext().getPointerType(e->getType()); + cir::AddressSpace srcAS = + cir::toCIRAddressSpace(e->getSubExpr()->getType().getAddressSpace()); + cir::AddressSpace destAS = + cir::toCIRAddressSpace(e->getType().getAddressSpace()); + mlir::Value V = getTargetHooks().performAddrSpaceCast( + *this, lv.getPointer(), srcAS, destAS, convertType(destTy)); + return makeAddrLValue(Address(V, convertTypeForMem(e->getType()), + lv.getAddress().getAlignment()), + e->getType(), lv.getBaseInfo()); + } case CK_ObjCObjectLValueCast: case CK_VectorSplat: case CK_ConstructorConversion: @@ -2289,7 +2301,10 @@ Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align, // be different from the type defined by the language. For example, // in C++ the auto variables are in the default address space. Therefore // cast alloca to the default address space when necessary. - assert(!cir::MissingFeatures::addressSpace()); + if (auto astAS = cir::toCIRAddressSpace(cgm.getLangTempAllocaAddressSpace()); + getCIRAllocaAddressSpace() != astAS) { + llvm_unreachable("Requires address space cast which is NYI"); + } return Address(v, ty, align); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 637f9ef65c88f..0be57dbfc84b4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -87,6 +87,7 @@ class ScalarExprEmitter : public StmtVisitor { //===--------------------------------------------------------------------===// // Utilities //===--------------------------------------------------------------------===// + mlir::Type convertType(QualType ty) { return cgf.convertType(ty); } mlir::Value emitComplexToScalarConversion(mlir::Location loc, mlir::Value value, CastKind kind, @@ -1871,6 +1872,27 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { return cgf.getBuilder().createBitcast(cgf.getLoc(subExpr->getSourceRange()), src, dstTy); } + case CK_AddressSpaceConversion: { + Expr::EvalResult result; + if (subExpr->EvaluateAsRValue(result, cgf.getContext()) && + result.Val.isNullPointer()) { + // If E has side effect, it is emitted even if its final result is a + // null pointer. In that case, a DCE pass should be able to + // eliminate the useless instructions emitted during translating E. + if (result.HasSideEffects) + Visit(subExpr); + return cgf.cgm.emitNullConstant(destTy, + cgf.getLoc(subExpr->getExprLoc())); + } + // Since target may map different address spaces in AST to the same address + // space, an address space conversion may end up as a bitcast. + cir::AddressSpace srcAS = cir::toCIRAddressSpace( + subExpr->getType()->getPointeeType().getAddressSpace()); + cir::AddressSpace destAS = + cir::toCIRAddressSpace(destTy->getPointeeType().getAddressSpace()); + return cgf.cgm.getTargetCIRGenInfo().performAddrSpaceCast( + cgf, Visit(subExpr), srcAS, destAS, convertType(destTy)); + } case CK_AtomicToNonAtomic: { cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(), diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 0d64c31f01668..c4fbc26723b13 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -184,6 +184,10 @@ class CIRGenFunction : public CIRGenTypeCache { const TargetInfo &getTarget() const { return cgm.getTarget(); } mlir::MLIRContext &getMLIRContext() { return cgm.getMLIRContext(); } + const TargetCIRGenInfo &getTargetHooks() const { + return cgm.getTargetCIRGenInfo(); + } + // --------------------- // Opaque value handling // --------------------- diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 57c7a440c8a2e..9f695cfe9c467 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1424,6 +1424,23 @@ CIRGenModule::getAddrOfConstantStringFromLiteral(const StringLiteral *s, return builder.getGlobalViewAttr(ptrTy, gv); } +// TODO(cir): this could be a common AST helper for both CIR and LLVM codegen. +LangAS CIRGenModule::getLangTempAllocaAddressSpace() const { + if (getLangOpts().OpenCL) + return LangAS::opencl_private; + + // For temporaries inside functions, CUDA treats them as normal variables. + // LangAS::cuda_device, on the other hand, is reserved for those variables + // explicitly marked with __device__. + if (getLangOpts().CUDAIsDevice) + return LangAS::Default; + + if (getLangOpts().SYCLIsDevice || + (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice)) + llvm_unreachable("NYI"); + return LangAS::Default; +} + void CIRGenModule::emitExplicitCastExprType(const ExplicitCastExpr *e, CIRGenFunction *cgf) { if (cgf && e->getType()->isVariablyModifiedType()) diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 690f0ed0e9bde..672cd811acede 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -297,6 +297,12 @@ class CIRGenModule : public CIRGenTypeCache { getAddrOfConstantStringFromLiteral(const StringLiteral *s, llvm::StringRef name = ".str"); + /// Returns the address space for temporary allocations in the language. This + /// ensures that the allocated variable's address space matches the + /// expectations of the AST, rather than using the target's allocation address + /// space, which may lead to type mismatches in other parts of the IR. + LangAS getLangTempAllocaAddressSpace() const; + /// Set attributes which are common to any form of a global definition (alias, /// Objective-C method, function, global variable). /// diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index d1b91d0c73c04..d493a10966e1f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -404,7 +404,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) { const ReferenceType *refTy = cast(ty); QualType elemTy = refTy->getPointeeType(); auto pointeeType = convertTypeForMem(elemTy); - resultType = builder.getPointerTo(pointeeType); + resultType = builder.getPointerTo(pointeeType, elemTy.getAddressSpace()); assert(resultType && "Cannot get pointer type?"); break; } diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 62a8c59abe604..34a66da466dd7 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -1,5 +1,7 @@ #include "TargetInfo.h" #include "ABIInfo.h" +#include "CIRGenFunction.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" using namespace clang; using namespace clang::CIRGen; @@ -68,3 +70,14 @@ bool TargetCIRGenInfo::isNoProtoCallVariadic( // For everything else, we just prefer false unless we opt out. return false; } + +mlir::Value TargetCIRGenInfo::performAddrSpaceCast( + CIRGenFunction &cgf, mlir::Value src, cir::AddressSpace srcAS, + cir::AddressSpace destAS, mlir::Type destTy, bool isNonNull) const { + // Since target may map different address spaces in AST to the same address + // space, an address space conversion may end up as a bitcast. + if (cir::GlobalOp globalOp = src.getDefiningOp()) + llvm_unreachable("Global ops addrspace cast NYI"); + // Try to preserve the source's name to make IR more readable. + return cgf.getBuilder().createAddrSpaceCast(src, destTy); +} diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index dbb0312c76040..0052aae3388cd 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -33,6 +33,8 @@ bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd); /// if the [[no_unique_address]] attribute would have made them empty. bool isEmptyRecordForLayout(const ASTContext &context, QualType t); +class CIRGenFunction; + class TargetCIRGenInfo { std::unique_ptr info; @@ -48,6 +50,17 @@ class TargetCIRGenInfo { virtual cir::TargetAddressSpaceAttr getCIRAllocaAddressSpace() const { return {}; } + /// Perform address space cast of an expression of pointer type. + /// \param V is the value to be casted to another address space. + /// \param SrcAddr is the CIR address space of \p V. + /// \param DestAddr is the targeted CIR address space. + /// \param DestTy is the destination pointer type. + /// \param IsNonNull is the flag indicating \p V is known to be non null. + virtual mlir::Value performAddrSpaceCast(CIRGenFunction &cgf, mlir::Value v, + cir::AddressSpace srcAS, + cir::AddressSpace destAS, + mlir::Type destTy, + bool isNonNull = false) const; /// Determine whether a call to an unprototyped functions under /// the given calling convention should use the variadic diff --git a/clang/test/CIR/address-space-conversion.cpp b/clang/test/CIR/address-space-conversion.cpp new file mode 100644 index 0000000000000..0f600e52d24da --- /dev/null +++ b/clang/test/CIR/address-space-conversion.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +using pi1_t = int __attribute__((address_space(1))) *; +using pi2_t = int __attribute__((address_space(2))) *; + +using ri1_t = int __attribute__((address_space(1))) &; +using ri2_t = int __attribute__((address_space(2))) &; + +// CIR: cir.func dso_local @{{.*test_ptr.*}} +// LLVM: define dso_local void @{{.*test_ptr.*}} +void test_ptr() { + pi1_t ptr1; + pi2_t ptr2 = (pi2_t)ptr1; + // CIR: %[[#PTR1:]] = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr)>), !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: %[[#PTR1:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#PTR1]] to ptr addrspace(2) + // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 +} + +// CIR: cir.func dso_local @{{.*test_ref.*}} +// LLVM: define dso_local void @{{.*test_ref.*}} +void test_ref() { + pi1_t ptr; + ri1_t ref1 = *ptr; + ri2_t ref2 = (ri2_t)ref1; + // CIR: %[[#DEREF:]] = cir.load deref{{.*}} %{{[0-9]+}} : !cir.ptr)>>, !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#DEREF]], %[[#ALLOCAREF1:]] : !cir.ptr)>, !cir.ptr)>> + // CIR-NEXT: %[[#REF1:]] = cir.load{{.*}} %[[#ALLOCAREF1]] : !cir.ptr)>>, !cir.ptr)> + // CIR-NEXT: %[[#CAST:]] = cir.cast(address_space, %[[#REF1]] : !cir.ptr)>), !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: %[[#DEREF:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: store ptr addrspace(1) %[[#DEREF]], ptr %[[#ALLOCAREF1:]], align 8 + // LLVM-NEXT: %[[#REF1:]] = load ptr addrspace(1), ptr %[[#ALLOCAREF1]], align 8 + // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#REF1]] to ptr addrspace(2) + // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 +} + +// CIR: cir.func dso_local @{{.*test_nullptr.*}} +// LLVM: define dso_local void @{{.*test_nullptr.*}} +void test_nullptr() { + constexpr pi1_t null1 = nullptr; + pi2_t ptr = (pi2_t)null1; + // CIR: %[[#NULL1:]] = cir.const #cir.ptr : !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL1]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + // CIR-NEXT: %[[#NULL2:]] = cir.const #cir.ptr : !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL2]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: store ptr addrspace(1) null, ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 +} + +void test_side_effect(pi1_t b) { + pi2_t p = (pi2_t)(*b++, (int*)0); + // CIR: %{{[0-9]+}} = cir.ptr_stride(%{{[0-9]+}} : !cir.ptr)>, %{{[0-9]+}} : !s32i), !cir.ptr)> + // CIR: %[[#CAST:]] = cir.const #cir.ptr : !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: %{{[0-9]+}} = getelementptr i32, ptr addrspace(1) %{{[0-9]+}}, i64 1 + // LLVM: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 + +} From 1848705984416c8f931f4813a01824ba29315de7 Mon Sep 17 00:00:00 2001 From: David Rivera Date: Mon, 29 Sep 2025 11:45:27 -0400 Subject: [PATCH 2/6] Verify bitcast does not contain address space conversion --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 5 ++++- clang/test/CIR/IR/invalid-addrspace.cir | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 7af3dc1f84955..4289b26c97238 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -428,7 +428,10 @@ LogicalResult cir::CastOp::verify() { auto resPtrTy = mlir::dyn_cast(resType); if (srcPtrTy && resPtrTy) { - return success(); + if (srcPtrTy.getAddrSpace() != resPtrTy.getAddrSpace()) { + return emitOpError() << "result type address space does not match the " + "address space of the operand"; + } } return success(); diff --git a/clang/test/CIR/IR/invalid-addrspace.cir b/clang/test/CIR/IR/invalid-addrspace.cir index 8f188b840bdec..4b6a388b1e4a8 100644 --- a/clang/test/CIR/IR/invalid-addrspace.cir +++ b/clang/test/CIR/IR/invalid-addrspace.cir @@ -24,4 +24,3 @@ cir.func @address_space2(%p : !cir.ptr) { cir.func @address_space3(%p : !cir.ptr) { cir.return } - From 4d2dc7651dc462ea2b4489fbeb2d222148c8bf5c Mon Sep 17 00:00:00 2001 From: David Rivera Date: Tue, 30 Sep 2025 16:05:06 -0400 Subject: [PATCH 3/6] address comments --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 17 ++-- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 2 + clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 2 +- clang/lib/CIR/CodeGen/TargetInfo.cpp | 2 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 15 +++- .../CIR/CodeGen/address-space-conversion.cpp | 89 +++++++++++++++++++ 7 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 clang/test/CIR/CodeGen/address-space-conversion.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index f97dff445873f..0f6b7e0f02a1d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -60,18 +60,18 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, // Initialize the alloca with the given size and alignment according to the lang // opts. Supporting only the trivial non-initialization for now. -static void initializeAlloca(CIRGenFunction &CGF, - [[maybe_unused]] mlir::Value AllocaAddr, - [[maybe_unused]] mlir::Value Size, - [[maybe_unused]] CharUnits AlignmentInBytes) { +static void initializeAlloca(CIRGenFunction &cgf, + [[maybe_unused]] mlir::Value allocaAddr, + [[maybe_unused]] mlir::Value size, + [[maybe_unused]] CharUnits alignmentInBytes) { - switch (CGF.getLangOpts().getTrivialAutoVarInit()) { + switch (cgf.getLangOpts().getTrivialAutoVarInit()) { case LangOptions::TrivialAutoVarInitKind::Uninitialized: // Nothing to initialize. return; case LangOptions::TrivialAutoVarInitKind::Zero: case LangOptions::TrivialAutoVarInitKind::Pattern: - assert(false && "unexpected trivial auto var init kind NYI"); + cgf.cgm.errorNYI("trivial auto var init"); return; } } @@ -198,17 +198,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, // default (e.g. in C / C++ auto vars are in the generic address space). At // the AST level this is handled within CreateTempAlloca et al., but for the // builtin / dynamic alloca we have to handle it here. - assert(!cir::MissingFeatures::addressSpace()); cir::AddressSpace aas = getCIRAllocaAddressSpace(); cir::AddressSpace eas = cir::toCIRAddressSpace( e->getType()->getPointeeType().getAddressSpace()); if (eas != aas) { - assert(false && "Non-default address space for alloca NYI"); + cgm.errorNYI(e->getSourceRange(), "Non-default address space for alloca"); } // Bitcast the alloca to the expected type. return RValue::get( - builder.createBitcast(allocaAddr, builder.getVoidPtrTy())); + builder.createBitcast(allocaAddr, builder.getVoidPtrTy(aas))); } case Builtin::BIcos: diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 27329ce9bd3cf..dd43e09984723 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -2287,6 +2287,8 @@ Address CIRGenFunction::createTempAllocaWithoutCast( /// This creates a alloca and inserts it into the entry block. The alloca is /// casted to default address space if necessary. +// TODO(cir): Implement address space casting to match classic codegen's +// CreateTempAlloca behavior with DestLangAS parameter Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc, const Twine &name, mlir::Value arraySize, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 0be57dbfc84b4..47b0f8e89c598 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1876,7 +1876,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { Expr::EvalResult result; if (subExpr->EvaluateAsRValue(result, cgf.getContext()) && result.Val.isNullPointer()) { - // If E has side effect, it is emitted even if its final result is a + // If e has side effect, it is emitted even if its final result is a // null pointer. In that case, a DCE pass should be able to // eliminate the useless instructions emitted during translating E. if (result.HasSideEffects) diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 9f695cfe9c467..bd4adfaa2a9bf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1437,7 +1437,7 @@ LangAS CIRGenModule::getLangTempAllocaAddressSpace() const { if (getLangOpts().SYCLIsDevice || (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice)) - llvm_unreachable("NYI"); + errorNYI("SYCL or OpenMP temp address space"); return LangAS::Default; } diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 34a66da466dd7..e622a5afa0185 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -77,7 +77,7 @@ mlir::Value TargetCIRGenInfo::performAddrSpaceCast( // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. if (cir::GlobalOp globalOp = src.getDefiningOp()) - llvm_unreachable("Global ops addrspace cast NYI"); + cgf.cgm.errorNYI("Global op addrspace cast"); // Try to preserve the source's name to make IR more readable. return cgf.getBuilder().createAddrSpaceCast(src, destTy); } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 4289b26c97238..8875fd09f2016 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -383,6 +383,16 @@ LogicalResult cir::CastOp::verify() { mlir::Type resType = getType(); mlir::Type srcType = getSrc().getType(); + // Verify address space casts for pointer types. given that + // casts for within a different address space are illegal. + auto srcPtrTy = mlir::dyn_cast(srcType); + auto resPtrTy = mlir::dyn_cast(resType); + if (srcPtrTy && resPtrTy && (getKind() != cir::CastKind::address_space)) + if (srcPtrTy.getAddrSpace() != resPtrTy.getAddrSpace()) { + return emitOpError() << "result type address space does not match the " + "address space of the operand"; + } + if (mlir::isa(srcType) && mlir::isa(resType)) { // Use the element type of the vector to verify the cast kind. (Except for @@ -428,10 +438,7 @@ LogicalResult cir::CastOp::verify() { auto resPtrTy = mlir::dyn_cast(resType); if (srcPtrTy && resPtrTy) { - if (srcPtrTy.getAddrSpace() != resPtrTy.getAddrSpace()) { - return emitOpError() << "result type address space does not match the " - "address space of the operand"; - } + return success(); } return success(); diff --git a/clang/test/CIR/CodeGen/address-space-conversion.cpp b/clang/test/CIR/CodeGen/address-space-conversion.cpp new file mode 100644 index 0000000000000..ac635136cb7d6 --- /dev/null +++ b/clang/test/CIR/CodeGen/address-space-conversion.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +using pi1_t = int __attribute__((address_space(1))) *; +using pi2_t = int __attribute__((address_space(2))) *; + +using ri1_t = int __attribute__((address_space(1))) &; +using ri2_t = int __attribute__((address_space(2))) &; + +// CIR: cir.func dso_local @{{.*test_ptr.*}} +// LLVM: define dso_local void @{{.*test_ptr.*}} +// OGCG: define dso_local void @{{.*test_ptr.*}} +void test_ptr() { + pi1_t ptr1; + pi2_t ptr2 = (pi2_t)ptr1; + // CIR: %[[#PTR1:]] = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr)>), !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: %[[#PTR1:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#PTR1]] to ptr addrspace(2) + // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 + + // OGCG: %{{.*}} = load ptr addrspace(1), ptr %{{.*}}, align 8 + // OGCG-NEXT: %{{.*}} = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(2) + // OGCG-NEXT: store ptr addrspace(2) %{{.*}}, ptr %{{.*}}, align 8 +} + +// CIR: cir.func dso_local @{{.*test_ref.*}} +// LLVM: define dso_local void @{{.*test_ref.*}} +// OGCG: define dso_local void @{{.*test_ref.*}} +void test_ref() { + pi1_t ptr; + ri1_t ref1 = *ptr; + ri2_t ref2 = (ri2_t)ref1; + // CIR: %[[#DEREF:]] = cir.load deref{{.*}} %{{[0-9]+}} : !cir.ptr)>>, !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#DEREF]], %[[#ALLOCAREF1:]] : !cir.ptr)>, !cir.ptr)>> + // CIR-NEXT: %[[#REF1:]] = cir.load{{.*}} %[[#ALLOCAREF1]] : !cir.ptr)>>, !cir.ptr)> + // CIR-NEXT: %[[#CAST:]] = cir.cast(address_space, %[[#REF1]] : !cir.ptr)>), !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: %[[#DEREF:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: store ptr addrspace(1) %[[#DEREF]], ptr %[[#ALLOCAREF1:]], align 8 + // LLVM-NEXT: %[[#REF1:]] = load ptr addrspace(1), ptr %[[#ALLOCAREF1]], align 8 + // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#REF1]] to ptr addrspace(2) + // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 + + // OGCG: %{{.*}} = load ptr addrspace(1), ptr %{{.*}}, align 8 + // OGCG-NEXT: store ptr addrspace(1) %{{.*}}, ptr %{{.*}}, align 8 + // OGCG-NEXT: %{{.*}} = load ptr addrspace(1), ptr %{{.*}}, align 8 + // OGCG-NEXT: %{{.*}} = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(2) + // OGCG-NEXT: store ptr addrspace(2) %{{.*}}, ptr %{{.*}}, align 8 +} + +// CIR: cir.func dso_local @{{.*test_nullptr.*}} +// LLVM: define dso_local void @{{.*test_nullptr.*}} +// OGCG: define dso_local void @{{.*test_nullptr.*}} +void test_nullptr() { + constexpr pi1_t null1 = nullptr; + pi2_t ptr = (pi2_t)null1; + // CIR: %[[#NULL1:]] = cir.const #cir.ptr : !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL1]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + // CIR-NEXT: %[[#NULL2:]] = cir.const #cir.ptr : !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL2]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: store ptr addrspace(1) null, ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 + + // OGCG: store ptr addrspace(1) null, ptr %{{.*}}, align 8 + // OGCG-NEXT: store ptr addrspace(2) null, ptr %{{.*}}, align 8 +} + +void test_side_effect(pi1_t b) { + pi2_t p = (pi2_t)(*b++, (int*)0); + // CIR: %{{[0-9]+}} = cir.ptr_stride(%{{[0-9]+}} : !cir.ptr)>, %{{[0-9]+}} : !s32i), !cir.ptr)> + // CIR: %[[#CAST:]] = cir.const #cir.ptr : !cir.ptr)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + + // LLVM: %{{[0-9]+}} = getelementptr i32, ptr addrspace(1) %{{[0-9]+}}, i64 1 + // LLVM: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 + + // OGCG: %{{.*}} = getelementptr{{.*}} i32, ptr addrspace(1) %{{.*}}, i32 1 + // OGCG: store ptr addrspace(2) null, ptr %{{.*}}, align 8 + +} From 2304ff47a0b8267e1961f59f1a6790d3ddb581cf Mon Sep 17 00:00:00 2001 From: David Rivera Date: Thu, 2 Oct 2025 21:25:15 -0400 Subject: [PATCH 4/6] Refactor address space handling based on TargetSpaceAttr and update performAddrSpaceCast --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 16 +++-- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 27 +++++--- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 6 +- clang/lib/CIR/CodeGen/TargetInfo.cpp | 11 +-- clang/lib/CIR/CodeGen/TargetInfo.h | 4 -- .../CIR/CodeGen/address-space-conversion.cpp | 41 +++++------ clang/test/CIR/address-space-conversion.cpp | 68 ------------------- 7 files changed, 56 insertions(+), 117 deletions(-) delete mode 100644 clang/test/CIR/address-space-conversion.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 0f6b7e0f02a1d..f134412dbfde5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -198,16 +198,20 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, // default (e.g. in C / C++ auto vars are in the generic address space). At // the AST level this is handled within CreateTempAlloca et al., but for the // builtin / dynamic alloca we have to handle it here. - cir::AddressSpace aas = getCIRAllocaAddressSpace(); - cir::AddressSpace eas = cir::toCIRAddressSpace( - e->getType()->getPointeeType().getAddressSpace()); - if (eas != aas) { + + LangAS allocaAddrSpace = clang::LangAS::Default; + if (getCIRAllocaAddressSpace()) { + allocaAddrSpace = clang::getLangASFromTargetAS( + getCIRAllocaAddressSpace().getValue().getUInt()); + } + LangAS exprAddrSpace = e->getType()->getPointeeType().getAddressSpace(); + if (exprAddrSpace != allocaAddrSpace) { cgm.errorNYI(e->getSourceRange(), "Non-default address space for alloca"); } // Bitcast the alloca to the expected type. - return RValue::get( - builder.createBitcast(allocaAddr, builder.getVoidPtrTy(aas))); + return RValue::get(builder.createBitcast( + allocaAddr, builder.getVoidPtrTy(allocaAddrSpace))); } case Builtin::BIcos: diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index dd43e09984723..6c6a4b8115cb2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -22,6 +22,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/TargetInfo.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/MissingFeatures.h" #include @@ -1200,13 +1202,10 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_AddressSpaceConversion: { LValue lv = emitLValue(e->getSubExpr()); QualType destTy = getContext().getPointerType(e->getType()); - cir::AddressSpace srcAS = - cir::toCIRAddressSpace(e->getSubExpr()->getType().getAddressSpace()); - cir::AddressSpace destAS = - cir::toCIRAddressSpace(e->getType().getAddressSpace()); - mlir::Value V = getTargetHooks().performAddrSpaceCast( - *this, lv.getPointer(), srcAS, destAS, convertType(destTy)); - return makeAddrLValue(Address(V, convertTypeForMem(e->getType()), + mlir::Value v = getTargetHooks().performAddrSpaceCast( + *this, lv.getPointer(), convertType(destTy)); + + return makeAddrLValue(Address(v, convertTypeForMem(e->getType()), lv.getAddress().getAlignment()), e->getType(), lv.getBaseInfo()); } @@ -2303,9 +2302,17 @@ Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align, // be different from the type defined by the language. For example, // in C++ the auto variables are in the default address space. Therefore // cast alloca to the default address space when necessary. - if (auto astAS = cir::toCIRAddressSpace(cgm.getLangTempAllocaAddressSpace()); - getCIRAllocaAddressSpace() != astAS) { - llvm_unreachable("Requires address space cast which is NYI"); + + LangAS allocaAS = cgm.getLangTempAllocaAddressSpace(); + LangAS dstTyAS = clang::LangAS::Default; + if (getCIRAllocaAddressSpace()) { + dstTyAS = clang::getLangASFromTargetAS( + getCIRAllocaAddressSpace().getValue().getUInt()); + } + + if (dstTyAS != allocaAS) { + getTargetHooks().performAddrSpaceCast(*this, v, + builder.getPointerTo(ty, dstTyAS)); } return Address(v, ty, align); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 47b0f8e89c598..8b9d7f6a777fd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1886,12 +1886,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { } // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. - cir::AddressSpace srcAS = cir::toCIRAddressSpace( - subExpr->getType()->getPointeeType().getAddressSpace()); - cir::AddressSpace destAS = - cir::toCIRAddressSpace(destTy->getPointeeType().getAddressSpace()); return cgf.cgm.getTargetCIRGenInfo().performAddrSpaceCast( - cgf, Visit(subExpr), srcAS, destAS, convertType(destTy)); + cgf, Visit(subExpr), convertType(destTy)); } case CK_AtomicToNonAtomic: { diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index e622a5afa0185..7379cb2128b8a 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -71,13 +71,14 @@ bool TargetCIRGenInfo::isNoProtoCallVariadic( return false; } -mlir::Value TargetCIRGenInfo::performAddrSpaceCast( - CIRGenFunction &cgf, mlir::Value src, cir::AddressSpace srcAS, - cir::AddressSpace destAS, mlir::Type destTy, bool isNonNull) const { +mlir::Value TargetCIRGenInfo::performAddrSpaceCast(CIRGenFunction &cgf, + mlir::Value v, + mlir::Type destTy, + bool isNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. - if (cir::GlobalOp globalOp = src.getDefiningOp()) + if (cir::GlobalOp globalOp = v.getDefiningOp()) cgf.cgm.errorNYI("Global op addrspace cast"); // Try to preserve the source's name to make IR more readable. - return cgf.getBuilder().createAddrSpaceCast(src, destTy); + return cgf.getBuilder().createAddrSpaceCast(v, destTy); } diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index 0052aae3388cd..c6855d484638b 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -52,13 +52,9 @@ class TargetCIRGenInfo { } /// Perform address space cast of an expression of pointer type. /// \param V is the value to be casted to another address space. - /// \param SrcAddr is the CIR address space of \p V. - /// \param DestAddr is the targeted CIR address space. /// \param DestTy is the destination pointer type. /// \param IsNonNull is the flag indicating \p V is known to be non null. virtual mlir::Value performAddrSpaceCast(CIRGenFunction &cgf, mlir::Value v, - cir::AddressSpace srcAS, - cir::AddressSpace destAS, mlir::Type destTy, bool isNonNull = false) const; diff --git a/clang/test/CIR/CodeGen/address-space-conversion.cpp b/clang/test/CIR/CodeGen/address-space-conversion.cpp index ac635136cb7d6..ed341024f8640 100644 --- a/clang/test/CIR/CodeGen/address-space-conversion.cpp +++ b/clang/test/CIR/CodeGen/address-space-conversion.cpp @@ -17,9 +17,9 @@ using ri2_t = int __attribute__((address_space(2))) &; void test_ptr() { pi1_t ptr1; pi2_t ptr2 = (pi2_t)ptr1; - // CIR: %[[#PTR1:]] = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr)>), !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + // CIR: %[[#PTR1:]] = cir.load align(8) %{{[0-9]+}} : !cir.ptr>, !cir.ptr + // CIR-NEXT: %[[#CAST:]] = cir.cast address_space %[[#PTR1]] : !cir.ptr -> !cir.ptr + // CIR-NEXT: cir.store align(8) %[[#CAST]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> // LLVM: %[[#PTR1:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#PTR1]] to ptr addrspace(2) @@ -37,15 +37,15 @@ void test_ref() { pi1_t ptr; ri1_t ref1 = *ptr; ri2_t ref2 = (ri2_t)ref1; - // CIR: %[[#DEREF:]] = cir.load deref{{.*}} %{{[0-9]+}} : !cir.ptr)>>, !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#DEREF]], %[[#ALLOCAREF1:]] : !cir.ptr)>, !cir.ptr)>> - // CIR-NEXT: %[[#REF1:]] = cir.load{{.*}} %[[#ALLOCAREF1]] : !cir.ptr)>>, !cir.ptr)> - // CIR-NEXT: %[[#CAST:]] = cir.cast(address_space, %[[#REF1]] : !cir.ptr)>), !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + // CIR: %[[#DEREF:]] = cir.load deref align(8) %{{[0-9]+}} : !cir.ptr>, !cir.ptr + // CIR-NEXT: cir.store align(8) %[[#DEREF]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> + // CIR-NEXT: %[[#REF1:]] = cir.load %{{[0-9]+}} : !cir.ptr>, !cir.ptr + // CIR-NEXT: %[[#CAST:]] = cir.cast address_space %[[#REF1]] : !cir.ptr -> !cir.ptr + // CIR-NEXT: cir.store align(8) %[[#CAST]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> // LLVM: %[[#DEREF:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 - // LLVM-NEXT: store ptr addrspace(1) %[[#DEREF]], ptr %[[#ALLOCAREF1:]], align 8 - // LLVM-NEXT: %[[#REF1:]] = load ptr addrspace(1), ptr %[[#ALLOCAREF1]], align 8 + // LLVM-NEXT: store ptr addrspace(1) %[[#DEREF]], ptr %{{[0-9]+}}, align 8 + // LLVM-NEXT: %[[#REF1:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#REF1]] to ptr addrspace(2) // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 @@ -62,10 +62,10 @@ void test_ref() { void test_nullptr() { constexpr pi1_t null1 = nullptr; pi2_t ptr = (pi2_t)null1; - // CIR: %[[#NULL1:]] = cir.const #cir.ptr : !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#NULL1]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> - // CIR-NEXT: %[[#NULL2:]] = cir.const #cir.ptr : !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#NULL2]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + // CIR: %[[#NULL1:]] = cir.const #cir.ptr : !cir.ptr + // CIR-NEXT: cir.store align(8) %[[#NULL1]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> + // CIR-NEXT: %[[#NULL2:]] = cir.const #cir.ptr : !cir.ptr + // CIR-NEXT: cir.store align(8) %[[#NULL2]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> // LLVM: store ptr addrspace(1) null, ptr %{{[0-9]+}}, align 8 // LLVM-NEXT: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 @@ -74,16 +74,19 @@ void test_nullptr() { // OGCG-NEXT: store ptr addrspace(2) null, ptr %{{.*}}, align 8 } +// CIR: cir.func dso_local @{{.*test_side_effect.*}} +// LLVM: define dso_local void @{{.*test_side_effect.*}} +// OGCG: define dso_local void @{{.*test_side_effect.*}} void test_side_effect(pi1_t b) { pi2_t p = (pi2_t)(*b++, (int*)0); - // CIR: %{{[0-9]+}} = cir.ptr_stride(%{{[0-9]+}} : !cir.ptr)>, %{{[0-9]+}} : !s32i), !cir.ptr)> - // CIR: %[[#CAST:]] = cir.const #cir.ptr : !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> + // CIR: %[[#DEREF:]] = cir.load deref align(8) %{{[0-9]+}} : !cir.ptr>, !cir.ptr + // CIR: %[[#STRIDE:]] = cir.ptr_stride(%[[#DEREF]] : !cir.ptr, %{{[0-9]+}} : !s32i), !cir.ptr + // CIR: %[[#NULL:]] = cir.const #cir.ptr : !cir.ptr + // CIR-NEXT: cir.store align(8) %[[#NULL]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> - // LLVM: %{{[0-9]+}} = getelementptr i32, ptr addrspace(1) %{{[0-9]+}}, i64 1 + // LLVM: %{{[0-9]+}} = getelementptr {{.*}}i32, ptr addrspace(1) %{{[0-9]+}}, i{{32|64}} 1 // LLVM: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 // OGCG: %{{.*}} = getelementptr{{.*}} i32, ptr addrspace(1) %{{.*}}, i32 1 // OGCG: store ptr addrspace(2) null, ptr %{{.*}}, align 8 - } diff --git a/clang/test/CIR/address-space-conversion.cpp b/clang/test/CIR/address-space-conversion.cpp deleted file mode 100644 index 0f600e52d24da..0000000000000 --- a/clang/test/CIR/address-space-conversion.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR -// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM - -using pi1_t = int __attribute__((address_space(1))) *; -using pi2_t = int __attribute__((address_space(2))) *; - -using ri1_t = int __attribute__((address_space(1))) &; -using ri2_t = int __attribute__((address_space(2))) &; - -// CIR: cir.func dso_local @{{.*test_ptr.*}} -// LLVM: define dso_local void @{{.*test_ptr.*}} -void test_ptr() { - pi1_t ptr1; - pi2_t ptr2 = (pi2_t)ptr1; - // CIR: %[[#PTR1:]] = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr)>), !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> - - // LLVM: %[[#PTR1:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 - // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#PTR1]] to ptr addrspace(2) - // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 -} - -// CIR: cir.func dso_local @{{.*test_ref.*}} -// LLVM: define dso_local void @{{.*test_ref.*}} -void test_ref() { - pi1_t ptr; - ri1_t ref1 = *ptr; - ri2_t ref2 = (ri2_t)ref1; - // CIR: %[[#DEREF:]] = cir.load deref{{.*}} %{{[0-9]+}} : !cir.ptr)>>, !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#DEREF]], %[[#ALLOCAREF1:]] : !cir.ptr)>, !cir.ptr)>> - // CIR-NEXT: %[[#REF1:]] = cir.load{{.*}} %[[#ALLOCAREF1]] : !cir.ptr)>>, !cir.ptr)> - // CIR-NEXT: %[[#CAST:]] = cir.cast(address_space, %[[#REF1]] : !cir.ptr)>), !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> - - // LLVM: %[[#DEREF:]] = load ptr addrspace(1), ptr %{{[0-9]+}}, align 8 - // LLVM-NEXT: store ptr addrspace(1) %[[#DEREF]], ptr %[[#ALLOCAREF1:]], align 8 - // LLVM-NEXT: %[[#REF1:]] = load ptr addrspace(1), ptr %[[#ALLOCAREF1]], align 8 - // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#REF1]] to ptr addrspace(2) - // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{[0-9]+}}, align 8 -} - -// CIR: cir.func dso_local @{{.*test_nullptr.*}} -// LLVM: define dso_local void @{{.*test_nullptr.*}} -void test_nullptr() { - constexpr pi1_t null1 = nullptr; - pi2_t ptr = (pi2_t)null1; - // CIR: %[[#NULL1:]] = cir.const #cir.ptr : !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#NULL1]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> - // CIR-NEXT: %[[#NULL2:]] = cir.const #cir.ptr : !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#NULL2]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> - - // LLVM: store ptr addrspace(1) null, ptr %{{[0-9]+}}, align 8 - // LLVM-NEXT: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 -} - -void test_side_effect(pi1_t b) { - pi2_t p = (pi2_t)(*b++, (int*)0); - // CIR: %{{[0-9]+}} = cir.ptr_stride(%{{[0-9]+}} : !cir.ptr)>, %{{[0-9]+}} : !s32i), !cir.ptr)> - // CIR: %[[#CAST:]] = cir.const #cir.ptr : !cir.ptr)> - // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr)>, !cir.ptr)>> - - // LLVM: %{{[0-9]+}} = getelementptr i32, ptr addrspace(1) %{{[0-9]+}}, i64 1 - // LLVM: store ptr addrspace(2) null, ptr %{{[0-9]+}}, align 8 - -} From 57443a97345d1c90fed285e2bdcddff905486fa8 Mon Sep 17 00:00:00 2001 From: David Rivera Date: Tue, 7 Oct 2025 08:43:35 -0400 Subject: [PATCH 5/6] Fix tests --- clang/test/CIR/CodeGen/address-space-conversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CIR/CodeGen/address-space-conversion.cpp b/clang/test/CIR/CodeGen/address-space-conversion.cpp index ed341024f8640..9e7b45951ae5f 100644 --- a/clang/test/CIR/CodeGen/address-space-conversion.cpp +++ b/clang/test/CIR/CodeGen/address-space-conversion.cpp @@ -80,7 +80,7 @@ void test_nullptr() { void test_side_effect(pi1_t b) { pi2_t p = (pi2_t)(*b++, (int*)0); // CIR: %[[#DEREF:]] = cir.load deref align(8) %{{[0-9]+}} : !cir.ptr>, !cir.ptr - // CIR: %[[#STRIDE:]] = cir.ptr_stride(%[[#DEREF]] : !cir.ptr, %{{[0-9]+}} : !s32i), !cir.ptr + // CIR: %[[#STRIDE:]] = cir.ptr_stride %[[#DEREF]], %{{[0-9]+}} : (!cir.ptr, !s32i) -> !cir.ptr // CIR: %[[#NULL:]] = cir.const #cir.ptr : !cir.ptr // CIR-NEXT: cir.store align(8) %[[#NULL]], %{{[0-9]+}} : !cir.ptr, !cir.ptr> From 979c034cefeabc22f99321e7c79128ebf08904e0 Mon Sep 17 00:00:00 2001 From: David Rivera Date: Thu, 16 Oct 2025 06:43:39 -0400 Subject: [PATCH 6/6] Update AddrCast to match OG and address other nits --- clang/include/clang/CIR/Dialect/IR/CIRTypes.h | 11 +++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 46 +++++++------------ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 30 +++++++----- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 9 +++- clang/lib/CIR/CodeGen/TargetInfo.cpp | 8 ++-- clang/lib/CIR/CodeGen/TargetInfo.h | 3 ++ clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 26 +++++++++++ 7 files changed, 88 insertions(+), 45 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index 45f646f1c9dfa..939e774a6ea67 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -13,7 +13,9 @@ #ifndef CLANG_CIR_DIALECT_IR_CIRTYPES_H #define CLANG_CIR_DIALECT_IR_CIRTYPES_H +#include "mlir/IR/Attributes.h" #include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/MLIRContext.h" #include "mlir/IR/Types.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" #include "clang/Basic/AddressSpaces.h" @@ -38,6 +40,15 @@ bool isValidFundamentalIntWidth(unsigned width); /// void, or abstract types. bool isSized(mlir::Type ty); +//===----------------------------------------------------------------------===// +// AddressSpace helpers +//===----------------------------------------------------------------------===// +cir::TargetAddressSpaceAttr toCIRTargetAddressSpace(mlir::MLIRContext &context, + clang::LangAS langAS); + +bool isMatchingAddressSpace(cir::TargetAddressSpaceAttr cirAS, + clang::LangAS as); + } // namespace cir //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index f134412dbfde5..52825ae563b9b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "CIRGenCall.h" -#include "CIRGenConstantEmitter.h" #include "CIRGenFunction.h" #include "CIRGenModule.h" #include "CIRGenValue.h" @@ -22,6 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/GlobalDecl.h" #include "clang/Basic/Builtins.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/Support/ErrorHandling.h" @@ -58,24 +58,6 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, return RValue::get(result); } -// Initialize the alloca with the given size and alignment according to the lang -// opts. Supporting only the trivial non-initialization for now. -static void initializeAlloca(CIRGenFunction &cgf, - [[maybe_unused]] mlir::Value allocaAddr, - [[maybe_unused]] mlir::Value size, - [[maybe_unused]] CharUnits alignmentInBytes) { - - switch (cgf.getLangOpts().getTrivialAutoVarInit()) { - case LangOptions::TrivialAutoVarInitKind::Uninitialized: - // Nothing to initialize. - return; - case LangOptions::TrivialAutoVarInitKind::Zero: - case LangOptions::TrivialAutoVarInitKind::Pattern: - cgf.cgm.errorNYI("trivial auto var init"); - return; - } -} - RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) { mlir::Value input = emitScalarExpr(e->getArg(0)); mlir::Value amount = emitScalarExpr(e->getArg(1)); @@ -190,8 +172,18 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, builder.getUInt8Ty(), "bi_alloca", suitableAlignmentInBytes, size); // Initialize the allocated buffer if required. - if (builtinID != Builtin::BI__builtin_alloca_uninitialized) - initializeAlloca(*this, allocaAddr, size, suitableAlignmentInBytes); + if (builtinID != Builtin::BI__builtin_alloca_uninitialized) { + + switch (getLangOpts().getTrivialAutoVarInit()) { + case LangOptions::TrivialAutoVarInitKind::Uninitialized: + // Nothing to initialize. + break; + case LangOptions::TrivialAutoVarInitKind::Zero: + case LangOptions::TrivialAutoVarInitKind::Pattern: + cgm.errorNYI("trivial auto var init"); + break; + } + } // An alloca will always return a pointer to the alloca (stack) address // space. This address space need not be the same as the AST / Language @@ -199,19 +191,15 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, // the AST level this is handled within CreateTempAlloca et al., but for the // builtin / dynamic alloca we have to handle it here. - LangAS allocaAddrSpace = clang::LangAS::Default; - if (getCIRAllocaAddressSpace()) { - allocaAddrSpace = clang::getLangASFromTargetAS( - getCIRAllocaAddressSpace().getValue().getUInt()); - } - LangAS exprAddrSpace = e->getType()->getPointeeType().getAddressSpace(); - if (exprAddrSpace != allocaAddrSpace) { + if (!cir::isMatchingAddressSpace( + getCIRAllocaAddressSpace(), + e->getType()->getPointeeType().getAddressSpace())) { cgm.errorNYI(e->getSourceRange(), "Non-default address space for alloca"); } // Bitcast the alloca to the expected type. return RValue::get(builder.createBitcast( - allocaAddr, builder.getVoidPtrTy(allocaAddrSpace))); + allocaAddr, builder.getVoidPtrTy(getCIRAllocaAddressSpace()))); } case Builtin::BIcos: diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 6c6a4b8115cb2..22fde08f327fa 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -24,7 +24,9 @@ #include "clang/AST/ExprCXX.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/TargetInfo.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include @@ -1199,16 +1201,6 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_AtomicToNonAtomic: case CK_ToUnion: case CK_BaseToDerived: - case CK_AddressSpaceConversion: { - LValue lv = emitLValue(e->getSubExpr()); - QualType destTy = getContext().getPointerType(e->getType()); - mlir::Value v = getTargetHooks().performAddrSpaceCast( - *this, lv.getPointer(), convertType(destTy)); - - return makeAddrLValue(Address(v, convertTypeForMem(e->getType()), - lv.getAddress().getAlignment()), - e->getType(), lv.getBaseInfo()); - } case CK_ObjCObjectLValueCast: case CK_VectorSplat: case CK_ConstructorConversion: @@ -1222,7 +1214,23 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { return {}; } + case CK_AddressSpaceConversion: { + LValue lv = emitLValue(e->getSubExpr()); + QualType destTy = getContext().getPointerType(e->getType()); + + clang::LangAS srcLangAS = e->getSubExpr()->getType().getAddressSpace(); + cir::TargetAddressSpaceAttr srcAS; + if (clang::isTargetAddressSpace(srcLangAS)) { + srcAS = cir::toCIRTargetAddressSpace(getMLIRContext(), srcLangAS); + } + + mlir::Value v = getTargetHooks().performAddrSpaceCast( + *this, lv.getPointer(), srcAS, convertType(destTy)); + return makeAddrLValue(Address(v, convertTypeForMem(e->getType()), + lv.getAddress().getAlignment()), + e->getType(), lv.getBaseInfo()); + } case CK_LValueBitCast: { // This must be a reinterpret_cast (or c-style equivalent). const auto *ce = cast(e); @@ -2311,7 +2319,7 @@ Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align, } if (dstTyAS != allocaAS) { - getTargetHooks().performAddrSpaceCast(*this, v, + getTargetHooks().performAddrSpaceCast(*this, v, getCIRAllocaAddressSpace(), builder.getPointerTo(ty, dstTyAS)); } return Address(v, ty, align); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 8b9d7f6a777fd..cd6ee58ac4eac 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -15,6 +15,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/StmtVisitor.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include "mlir/IR/Location.h" @@ -1884,10 +1885,16 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { return cgf.cgm.emitNullConstant(destTy, cgf.getLoc(subExpr->getExprLoc())); } + + clang::LangAS srcLangAS = subExpr->getType().getAddressSpace(); + cir::TargetAddressSpaceAttr subExprAS; + if (clang::isTargetAddressSpace(srcLangAS)) { + subExprAS = cir::toCIRTargetAddressSpace(cgf.getMLIRContext(), srcLangAS); + } // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. return cgf.cgm.getTargetCIRGenInfo().performAddrSpaceCast( - cgf, Visit(subExpr), convertType(destTy)); + cgf, Visit(subExpr), subExprAS, convertType(destTy)); } case CK_AtomicToNonAtomic: { diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 7379cb2128b8a..377c532e492d9 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -1,6 +1,7 @@ #include "TargetInfo.h" #include "ABIInfo.h" #include "CIRGenFunction.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" using namespace clang; @@ -71,10 +72,9 @@ bool TargetCIRGenInfo::isNoProtoCallVariadic( return false; } -mlir::Value TargetCIRGenInfo::performAddrSpaceCast(CIRGenFunction &cgf, - mlir::Value v, - mlir::Type destTy, - bool isNonNull) const { +mlir::Value TargetCIRGenInfo::performAddrSpaceCast( + CIRGenFunction &cgf, mlir::Value v, cir::TargetAddressSpaceAttr srcAddr, + mlir::Type destTy, bool isNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. if (cir::GlobalOp globalOp = v.getDefiningOp()) diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index c6855d484638b..72682641a460b 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -17,6 +17,7 @@ #include "ABIInfo.h" #include "CIRGenTypes.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" #include #include @@ -53,8 +54,10 @@ class TargetCIRGenInfo { /// Perform address space cast of an expression of pointer type. /// \param V is the value to be casted to another address space. /// \param DestTy is the destination pointer type. + /// \param srcAS is theaddress space of \p V. /// \param IsNonNull is the flag indicating \p V is known to be non null. virtual mlir::Value performAddrSpaceCast(CIRGenFunction &cgf, mlir::Value v, + cir::TargetAddressSpaceAttr srcAddr, mlir::Type destTy, bool isNonNull = false) const; diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 5897352829891..9451212f99b32 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -12,11 +12,16 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/DialectImplementation.h" +#include "mlir/IR/MLIRContext.h" +#include "clang/Basic/AddressSpaces.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypesDetails.h" #include "clang/CIR/MissingFeatures.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/TypeSwitch.h" //===----------------------------------------------------------------------===// @@ -807,6 +812,27 @@ mlir::LogicalResult cir::VectorType::verify( // TargetAddressSpace definitions //===----------------------------------------------------------------------===// +cir::TargetAddressSpaceAttr +cir::toCIRTargetAddressSpace(mlir::MLIRContext &context, clang::LangAS langAS) { + return cir::TargetAddressSpaceAttr::get( + &context, + IntegerAttr::get(&context, + llvm::APSInt(clang::toTargetAddressSpace(langAS)))); +} + +bool cir::isMatchingAddressSpace(cir::TargetAddressSpaceAttr cirAS, + clang::LangAS as) { + // If there is no CIR target attr, consider it "default" and only match + // when the AST address space is LangAS::Default. + if (!cirAS) + return as == clang::LangAS::Default; + + if (!isTargetAddressSpace(as)) + return false; + + return cirAS.getValue().getUInt() == toTargetAddressSpace(as); +} + mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr) { if (failed(p.parseKeyword("target_address_space")))