Author: Konstantinos Parasyris Date: 2026-10-05T22:58:17Z New Revision: 546e4f93c36bb8e9e383cac71972c293e0f08998
URL: https://github.com/llvm/llvm-project/commit/546e4f93c36bb8e9e383cac71972c293e0f08998 DIFF: https://github.com/llvm/llvm-project/commit/546e4f93c36bb8e9e383cac71972c293e0f08998.diff LOG: [CIR] Lower language address spaces nested in record members (#228934) TargetLowering now derives from RecordRewritingTypeConverter, so it rebuilds records whose members reach a language address space and keeps the rest. This fixes "member type mismatch" for OpenCL and SYCL records with address-space qualified pointer members. Added: clang/test/CIR/CodeGenOpenCL/record-address-space.cl clang/test/CIR/CodeGenSYCL/record-address-space.cpp Modified: clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp index 52c355c340519..8f14bada8957c 100644 --- a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp +++ b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp @@ -108,8 +108,58 @@ RecordRewritingTypeConverter::convertRecordMemberTypes(cir::RecordType type) { return loweredMemberTypes; } +bool RecordRewritingTypeConverter::reachesChangingType( + mlir::Type type, llvm::SmallPtrSetImpl<mlir::Type> &visiting) const { + if (typeMayChange(type)) + return true; + + // The sub-element walk skips record members. Stop on cycles. + if (auto rt = mlir::dyn_cast<cir::RecordType>(type)) { + if (!visiting.insert(type).second) + return false; + for (mlir::Type member : rt.getMembers()) + if (reachesChangingType(member, visiting)) + return true; + if (auto u = mlir::dyn_cast<cir::UnionType>(type)) + if (mlir::Type pad = u.getPadding()) + return reachesChangingType(pad, visiting); + return false; + } + + bool found = false; + type.walkImmediateSubElements([](mlir::Attribute) {}, + [&](mlir::Type sub) { + found = found || + reachesChangingType(sub, visiting); + }); + return found; +} + +bool RecordRewritingTypeConverter::recordNeedsConversion(cir::RecordType type) { + { + std::shared_lock<decltype(recordNeedsConversionMutex)> lock( + recordNeedsConversionMutex); + auto it = recordNeedsConversionCache.find(type); + if (it != recordNeedsConversionCache.end()) + return it->second; + } + + // Nested results may be partial inside a cycle, so cache only this one. + llvm::SmallPtrSet<mlir::Type, 8> visiting; + bool result = reachesChangingType(type, visiting); + + std::unique_lock<decltype(recordNeedsConversionMutex)> lock( + recordNeedsConversionMutex); + recordNeedsConversionCache[type] = result; + return result; +} + cir::RecordType RecordRewritingTypeConverter::convertRecordType(cir::RecordType type) { + // Keep records that reach no changing type, including through nested ones. + if (!recordNeedsConversion(type)) + return type; + // Unnamed record types can't be referred to recursively, so we can just // convert this one. It also doesn't have uniqueness problems, so we can // just do a conversion on it. diff --git a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h index 1b7b1fbc1ad34..569a96a604e33 100644 --- a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h +++ b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h @@ -17,6 +17,7 @@ #include "mlir/Transforms/DialectConversion.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/RWMutex.h" @@ -36,6 +37,8 @@ namespace cir { /// Subclasses add conversions for the types they rewrite. The type converter /// tries the most recently added conversion first, so a subclass can also /// replace one of the conversions registered here. +/// +/// Every record is rebuilt unless typeMayChange() is overridden. class RecordRewritingTypeConverter : public mlir::TypeConverter { public: explicit RecordRewritingTypeConverter(mlir::MLIRContext &context); @@ -44,7 +47,15 @@ class RecordRewritingTypeConverter : public mlir::TypeConverter { /// Remove the temporary name of every record rebuilt by this converter. void restoreRecordTypeNames(); +protected: + /// Whether \p type itself, ignoring nested types, may change. Records are + /// rebuilt only if some type they reach returns true. + virtual bool typeMayChange(mlir::Type type) const { return true; } + private: + bool recordNeedsConversion(cir::RecordType type); + bool reachesChangingType(mlir::Type type, + llvm::SmallPtrSetImpl<mlir::Type> &visiting) const; cir::RecordType convertRecordType(cir::RecordType type); llvm::SmallVector<mlir::Type> convertRecordMemberTypes(cir::RecordType type); llvm::SmallVector<cir::RecordType> &getCurrentThreadRecursiveStack(); @@ -64,6 +75,10 @@ class RecordRewritingTypeConverter : public mlir::TypeConverter { // functions. llvm::SmallVector<cir::RecordType> convertedRecordTypes; llvm::sys::SmartRWMutex<true> recordTypeMutex; + + // Cached results of recordNeedsConversion(). + llvm::DenseMap<mlir::Type, bool> recordNeedsConversionCache; + llvm::sys::SmartRWMutex<true> recordNeedsConversionMutex; }; } // namespace cir diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp index 769df5572f285..76ca7114ee5ce 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp @@ -10,9 +10,11 @@ // //===----------------------------------------------------------------------===// +#include "RecordTypeConverter.h" #include "TargetLowering/LowerModule.h" #include "TargetLowering/TargetLoweringInfo.h" +#include "mlir/IR/AttrTypeSubElements.h" #include "mlir/IR/PatternMatch.h" #include "mlir/Support/LLVM.h" #include "mlir/Transforms/DialectConversion.h" @@ -38,13 +40,72 @@ struct TargetLoweringPass void runOnOperation() override; }; +/// Converts LangAddressSpaceAttr → TargetAddressSpaceAttr inside types, +/// rebuilding only records that reach a language address space. +class TargetLoweringTypeConverter : public cir::RecordRewritingTypeConverter { +public: + TargetLoweringTypeConverter(mlir::MLIRContext &ctx, + const cir::TargetLoweringInfo &targetInfo) + : RecordRewritingTypeConverter(ctx), targetInfo(targetInfo) { + addConversion([this](cir::PointerType type) -> mlir::Type { + mlir::Type pointee = convertType(type.getPointee()); + if (!pointee) + return {}; + mlir::ptr::MemorySpaceAttrInterface addrSpace = type.getAddrSpace(); + if (auto langAS = + mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace)) + addrSpace = lowerAddrSpace(type.getContext(), langAS); + return cir::PointerType::get(type.getContext(), pointee, addrSpace); + }); + } + + mlir::ptr::MemorySpaceAttrInterface + lowerAddrSpace(mlir::MLIRContext *ctx, + cir::LangAddressSpaceAttr langAS) const { + unsigned targetAS = + targetInfo.getTargetAddrSpaceFromCIRAddrSpace(langAS.getValue()); + if (targetAS == 0) + return {}; + return cir::TargetAddressSpaceAttr::get(ctx, targetAS); + } + + /// Convert the types nested in \p attr, e.g. the type of a constant. + mlir::Attribute convertAttr(mlir::Attribute attr) const { + return attrReplacer.replace(attr); + } + +protected: + bool typeMayChange(mlir::Type type) const override { + auto ptrTy = mlir::dyn_cast<cir::PointerType>(type); + return ptrTy && mlir::isa_and_present<cir::LangAddressSpaceAttr>( + ptrTy.getAddrSpace()); + } + +private: + const cir::TargetLoweringInfo &targetInfo; + mutable mlir::AttrTypeReplacer attrReplacer = [this] { + mlir::AttrTypeReplacer replacer; + replacer.addReplacement( + [this](mlir::Type type) + -> std::optional<std::pair<mlir::Type, mlir::WalkResult>> { + mlir::Type converted = convertType(type); + if (!converted) + return std::nullopt; + // Already converted; don't walk into it. + return std::make_pair(converted, mlir::WalkResult::skip()); + }); + return replacer; + }(); +}; + /// A generic target lowering pattern that matches any CIR op whose operand or /// result types need address space conversion. Clones the op with converted /// types. class CIRGenericTargetLoweringPattern : public mlir::ConversionPattern { public: - CIRGenericTargetLoweringPattern(mlir::MLIRContext *context, - const mlir::TypeConverter &typeConverter) + CIRGenericTargetLoweringPattern( + mlir::MLIRContext *context, + const TargetLoweringTypeConverter &typeConverter) : mlir::ConversionPattern(typeConverter, MatchAnyOpTypeTag(), /*benefit=*/1, context) {} @@ -73,9 +134,7 @@ class CIRGenericTargetLoweringPattern : public mlir::ConversionPattern { mlir::OperationState loweredOpState(op->getLoc(), op->getName()); loweredOpState.addOperands(operands); - // Preserve auxiliary metadata verbatim. Convert only inherent TypeAttrs and - // pointer constants so address-space-bearing operation semantics (e.g. - // AllocaOp's allocaType) stay in sync with the converted result types. + // Preserve auxiliary metadata verbatim. loweredOpState.propertiesAttr = op->getPropertiesAsAttribute(); loweredOpState.addAttributes(op->getDiscardableAttrDictionary().getValue()); @@ -96,15 +155,13 @@ class CIRGenericTargetLoweringPattern : public mlir::ConversionPattern { } mlir::Operation *loweredOp = rewriter.create(loweredOpState); + // Keep inherent attributes (e.g. allocaType, constants) in sync with the + // converted types. + const auto *tlTypeConverter = + static_cast<const TargetLoweringTypeConverter *>(typeConverter); loweredOp->getName().walkInherentAttrs( loweredOp, [&](llvm::StringRef, mlir::Attribute &attr) { - if (auto typeAttr = mlir::dyn_cast<mlir::TypeAttr>(attr)) - attr = mlir::TypeAttr::get( - typeConverter->convertType(typeAttr.getValue())); - else if (auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(attr)) - attr = cir::ConstPtrAttr::get( - typeConverter->convertType(ptrAttr.getType()), - ptrAttr.getValue()); + attr = tlTypeConverter->convertAttr(attr); }); rewriter.replaceOp(op, loweredOp); return mlir::success(); @@ -116,34 +173,26 @@ class CIRGenericTargetLoweringPattern : public mlir::ConversionPattern { /// TypeConverter won't reach it automatically. class CIRGlobalOpTargetLowering : public mlir::OpConversionPattern<cir::GlobalOp> { - const cir::TargetLoweringInfo &targetInfo; - public: CIRGlobalOpTargetLowering(mlir::MLIRContext *context, - const mlir::TypeConverter &typeConverter, - const cir::TargetLoweringInfo &targetInfo) + const TargetLoweringTypeConverter &typeConverter) : mlir::OpConversionPattern<cir::GlobalOp>(typeConverter, context, - /*benefit=*/1), - targetInfo(targetInfo) {} + /*benefit=*/1) {} mlir::LogicalResult matchAndRewrite(cir::GlobalOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { - mlir::Type loweredSymTy = getTypeConverter()->convertType(op.getSymType()); + const auto *typeConverter = + static_cast<const TargetLoweringTypeConverter *>(getTypeConverter()); + mlir::Type loweredSymTy = typeConverter->convertType(op.getSymType()); if (!loweredSymTy) return mlir::failure(); // Convert the addr_space attribute. mlir::ptr::MemorySpaceAttrInterface addrSpace = op.getAddrSpaceAttr(); if (auto langAS = - mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace)) { - unsigned targetAS = - targetInfo.getTargetAddrSpaceFromCIRAddrSpace(langAS.getValue()); - addrSpace = - targetAS == 0 - ? nullptr - : cir::TargetAddressSpaceAttr::get(op.getContext(), targetAS); - } + mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace)) + addrSpace = typeConverter->lowerAddrSpace(op.getContext(), langAS); // Only rewrite if something actually changed. if (loweredSymTy == op.getSymType() && addrSpace == op.getAddrSpaceAttr()) @@ -152,6 +201,8 @@ class CIRGlobalOpTargetLowering auto newOp = mlir::cast<cir::GlobalOp>(rewriter.clone(*op.getOperation())); newOp.setSymType(loweredSymTy); newOp.setAddrSpaceAttr(addrSpace); + if (mlir::Attribute init = newOp.getInitialValueAttr()) + newOp.setInitialValueAttr(typeConverter->convertAttr(init)); rewriter.replaceOp(op, newOp); return mlir::success(); } @@ -218,55 +269,6 @@ static void convertSyncScopeIfPresent(mlir::Operation *op, } } -/// Prepare the type converter for the target lowering pass. -/// Converts LangAddressSpaceAttr → TargetAddressSpaceAttr inside pointer types. -static void -prepareTargetLoweringTypeConverter(mlir::TypeConverter &converter, - const cir::TargetLoweringInfo &targetInfo) { - converter.addConversion([](mlir::Type type) { return type; }); - - converter.addConversion([&converter, - &targetInfo](cir::PointerType type) -> mlir::Type { - mlir::Type pointee = converter.convertType(type.getPointee()); - if (!pointee) - return {}; - auto addrSpace = type.getAddrSpace(); - if (auto langAS = - mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace)) { - unsigned targetAS = - targetInfo.getTargetAddrSpaceFromCIRAddrSpace(langAS.getValue()); - addrSpace = - targetAS == 0 - ? nullptr - : cir::TargetAddressSpaceAttr::get(type.getContext(), targetAS); - } - return cir::PointerType::get(type.getContext(), pointee, addrSpace); - }); - - converter.addConversion([&converter](cir::ArrayType type) -> mlir::Type { - mlir::Type loweredElementType = - converter.convertType(type.getElementType()); - if (!loweredElementType) - return {}; - return cir::ArrayType::get(loweredElementType, type.getSize()); - }); - - converter.addConversion([&converter](cir::FuncType type) -> mlir::Type { - llvm::SmallVector<mlir::Type> loweredInputTypes; - loweredInputTypes.reserve(type.getNumInputs()); - if (mlir::failed( - converter.convertTypes(type.getInputs(), loweredInputTypes))) - return {}; - - mlir::Type loweredReturnType = converter.convertType(type.getReturnType()); - if (!loweredReturnType) - return {}; - - return cir::FuncType::get(loweredInputTypes, loweredReturnType, - /*isVarArg=*/type.getVarArg()); - }); -} - static void populateTargetLoweringConversionTarget(mlir::ConversionTarget &target, const mlir::TypeConverter &tc) { @@ -311,12 +313,10 @@ void TargetLoweringPass::runOnOperation() { }); // Address space conversion: LangAddressSpaceAttr → TargetAddressSpaceAttr. - mlir::TypeConverter typeConverter; - prepareTargetLoweringTypeConverter(typeConverter, targetInfo); + TargetLoweringTypeConverter typeConverter(*mod.getContext(), targetInfo); mlir::RewritePatternSet patterns(mod.getContext()); - patterns.add<CIRGlobalOpTargetLowering>(mod.getContext(), typeConverter, - targetInfo); + patterns.add<CIRGlobalOpTargetLowering>(mod.getContext(), typeConverter); patterns.add<CIRFuncOpTargetLowering>(typeConverter, mod.getContext()); patterns.add<CIRGenericTargetLoweringPattern>(mod.getContext(), typeConverter); @@ -330,6 +330,8 @@ void TargetLoweringPass::runOnOperation() { if (failed(mlir::applyPartialConversion(ops, target, std::move(patterns)))) signalPassFailure(); + + typeConverter.restoreRecordTypeNames(); } std::unique_ptr<Pass> mlir::createTargetLoweringPass() { diff --git a/clang/test/CIR/CodeGenOpenCL/record-address-space.cl b/clang/test/CIR/CodeGenOpenCL/record-address-space.cl new file mode 100644 index 0000000000000..8ce869a47a3b1 --- /dev/null +++ b/clang/test/CIR/CodeGenOpenCL/record-address-space.cl @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -cl-std=CL2.0 -fclangir \ +// RUN: -emit-cir -mmlir --mlir-print-ir-before=cir-target-lowering %s \ +// RUN: -o %t.cir 2> %t.pre.cir +// RUN: FileCheck %s --check-prefix=PRE --input-file=%t.pre.cir +// RUN: FileCheck %s --check-prefix=POST --input-file=%t.cir +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -cl-std=CL2.0 -fclangir \ +// RUN: -emit-llvm -O0 %s -o %t-cir.ll +// RUN: FileCheck %s --check-prefixes=LLVM,CIR-LLVM --input-file=%t-cir.ll +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -cl-std=CL2.0 \ +// RUN: -emit-llvm -O0 %s -o %t.ll +// RUN: FileCheck %s --check-prefixes=LLVM,OGCG --input-file=%t.ll + +// Language address spaces in record members are lowered; other records are +// kept. + +struct S { __global int *p; int n; }; +struct Outer { struct S s; __local int *lp; }; +struct Node { __global struct Node *next; int v; }; +union U { __global int *p; long l; }; +struct Plain { int a; float b; }; + +// PRE-DAG: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, lang_address_space(offload_global)>, data !s32i}> +// PRE-DAG: !rec_Outer = !cir.struct<"Outer" {data !rec_S, data !cir.ptr<!s32i, lang_address_space(offload_local)>}> +// PRE-DAG: !rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">, lang_address_space(offload_global)>, data !s32i}> +// PRE-DAG: !rec_U = !cir.union<"U" {data !cir.ptr<!s32i, lang_address_space(offload_global)>, data !s64i}> +// PRE-DAG: !rec_Plain = !cir.struct<"Plain" {data !s32i, data !cir.float}> + +// POST-DAG: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, target_address_space(1)>, data !s32i}> +// POST-DAG: !rec_Outer = !cir.struct<"Outer" {data !rec_S, data !cir.ptr<!s32i, target_address_space(3)>}> +// POST-DAG: !rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">, target_address_space(1)>, data !s32i}> +// POST-DAG: !rec_U = !cir.union<"U" {data !cir.ptr<!s32i, target_address_space(1)>, data !s64i}> +// POST-DAG: !rec_Plain = !cir.struct<"Plain" {data !s32i, data !cir.float}> + +// LLVM-DAG: %struct.S = type { ptr addrspace(1), i32 } +// LLVM-DAG: %struct.Outer = type { %struct.S, ptr addrspace(3) } +// LLVM-DAG: %struct.Node = type { ptr addrspace(1), i32 } +// LLVM-DAG: %union.U = type { ptr addrspace(1) } +// LLVM-DAG: %struct.Plain = type { i32, float } + +__global int gi; +__global struct S gs = {&gi, 4}; + +// The initializer type follows the record. + +// POST: cir.global external target_address_space(1) @gs = #cir.const_record<{#cir.global_view<@gi> : !cir.ptr<!s32i, target_address_space(1)>, #cir.int<4> : !s32i}> : !rec_S + +// CIR-LLVM: @gs = addrspace(1) global %struct.S { ptr addrspace(1) @gi, i32 4 }, align 8 +// OGCG: @gs = addrspace(1) global { ptr addrspace(1), i32, [4 x i8] } { ptr addrspace(1) @gi, i32 4, [4 x i8] zeroinitializer }, align 8 + +kernel void k(__global int *g, __local int *l, __global struct Node *n) { + struct S s; + s.p = g; + struct Outer o; + o.lp = l; + struct Node node; + node.next = n; + union U u; + u.p = g; + struct Plain plain; + plain.a = 1; +} + +// POST: cir.get_member %{{.*}}[0] {name = "p"} : !cir.ptr<!rec_S> -> !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>> +// POST: cir.get_member %{{.*}}[1] {name = "lp"} : !cir.ptr<!rec_Outer> -> !cir.ptr<!cir.ptr<!s32i, target_address_space(3)>> +// POST: cir.get_member %{{.*}}[0] {name = "next"} : !cir.ptr<!rec_Node> -> !cir.ptr<!cir.ptr<!rec_Node, target_address_space(1)>> +// POST: cir.get_member %{{.*}}[0] {name = "p"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>> +// POST: cir.get_member %{{.*}}[0] {name = "a"} : !cir.ptr<!rec_Plain> -> !cir.ptr<!s32i> + +// LLVM: %[[P:.*]] = getelementptr inbounds nuw %struct.S, ptr %{{.*}}, i32 0, i32 0 +// LLVM: store ptr addrspace(1) %{{.*}}, ptr %[[P]], align 8 +// LLVM: %[[LP:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %{{.*}}, i32 0, i32 1 +// LLVM: store ptr addrspace(3) %{{.*}}, ptr %[[LP]], align 8 +// LLVM: %[[NEXT:.*]] = getelementptr inbounds nuw %struct.Node, ptr %{{.*}}, i32 0, i32 0 +// LLVM: store ptr addrspace(1) %{{.*}}, ptr %[[NEXT]], align 8 +// LLVM: store ptr addrspace(1) %{{.*}}, ptr %{{.*}}, align 8 +// LLVM: %[[A:.*]] = getelementptr inbounds nuw %struct.Plain, ptr %{{.*}}, i32 0, i32 0 +// LLVM: store i32 1, ptr %[[A]], align 4 diff --git a/clang/test/CIR/CodeGenSYCL/record-address-space.cpp b/clang/test/CIR/CodeGenSYCL/record-address-space.cpp new file mode 100644 index 0000000000000..292aab806d942 --- /dev/null +++ b/clang/test/CIR/CodeGenSYCL/record-address-space.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown \ +// RUN: -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-target-lowering \ +// RUN: %s -o %t.cir 2> %t.pre.cir +// RUN: FileCheck %s --check-prefix=PRE --input-file=%t.pre.cir +// RUN: FileCheck %s --check-prefix=POST --input-file=%t.cir +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown \ +// RUN: -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck %s --check-prefix=LLVM --input-file=%t-cir.ll +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown \ +// RUN: -emit-llvm %s -o %t.ll +// RUN: FileCheck %s --check-prefix=LLVM --input-file=%t.ll + +// Language address spaces in record members are lowered. + +struct S { + __attribute__((opencl_global)) int *p; + int n; +}; + +// PRE: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, lang_address_space(offload_global)>, data !s32i}> +// POST: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, target_address_space(1)>, data !s32i}> +// LLVM: %struct.S = type { ptr addrspace(1), i32 } + +[[clang::sycl_external]] void store_member(__attribute__((opencl_global)) int *g) { + S s; + s.p = g; +} + +// POST-LABEL: cir.func {{.*}}@_Z12store_memberPU3AS1i +// POST: cir.get_member %{{.*}}[0] {name = "p"} : !cir.ptr<!rec_S> -> !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>> + +// LLVM-LABEL: define {{.*}}@_Z12store_memberPU3AS1i +// LLVM: %[[P:.*]] = getelementptr inbounds nuw %struct.S, ptr {{.*}}, i32 0, i32 0 +// LLVM: store ptr addrspace(1) %{{.*}}, ptr {{.*}}%[[P]], align 8 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
