llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> This change upstreams the CIR implementation of global variable replacement handling for cases where the global was used in a cir.global_view operation, either as an initializer for another global or as a constant ptr. --- Full diff: https://github.com/llvm/llvm-project/pull/186168.diff 5 Files Affected: - (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+12) - (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.cpp (+22) - (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+5) - (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+100-2) - (modified) clang/test/CIR/CodeGen/replace-global.cpp (+48-1) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index f51bea894d2ae..a7984175ac1ce 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -326,6 +326,18 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return cir::GlobalViewAttr::get(type, symbol, indices); } + /// Get constant address of a global variable as an MLIR attribute. + /// This overload converts raw int64_t indices to an ArrayAttr. + cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type, + cir::GlobalOp globalOp, + llvm::ArrayRef<int64_t> indices) { + llvm::SmallVector<mlir::Attribute> attrs; + for (int64_t ind : indices) + attrs.push_back(getI64IntegerAttr(ind)); + mlir::ArrayAttr arAttr = mlir::ArrayAttr::get(getContext(), attrs); + return getGlobalViewAttr(type, globalOp, arAttr); + } + mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global, bool threadLocal = false) { assert(!cir::MissingFeatures::addressSpace()); diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index e8298e8231f05..7953a648715b2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp @@ -147,6 +147,28 @@ void CIRGenBuilderTy::computeGlobalViewIndicesFromFlatOffset( computeGlobalViewIndicesFromFlatOffset(offset, subType, layout, indices); } +uint64_t CIRGenBuilderTy::computeOffsetFromGlobalViewIndices( + const cir::CIRDataLayout &layout, mlir::Type ty, + llvm::ArrayRef<int64_t> indices) { + int64_t offset = 0; + for (int64_t idx : indices) { + if (auto recordTy = dyn_cast<cir::RecordType>(ty)) { + offset += recordTy.getElementOffset(layout.layout, idx); + const llvm::Align tyAlign = llvm::Align( + recordTy.getPacked() ? 1 : layout.layout.getTypeABIAlignment(ty)); + offset = llvm::alignTo(offset, tyAlign); + assert(idx < (int64_t)recordTy.getMembers().size()); + ty = recordTy.getMembers()[idx]; + } else if (auto arrayTy = dyn_cast<cir::ArrayType>(ty)) { + ty = arrayTy.getElementType(); + offset += layout.getTypeAllocSize(ty) * idx; + } else { + llvm_unreachable("unexpected type"); + } + } + return offset; +} + cir::RecordType clang::CIRGen::CIRGenBuilderTy::getCompleteRecordType( mlir::ArrayAttr fields, bool packed, bool padded, llvm::StringRef name) { assert(!cir::MissingFeatures::astRecordDeclAttr()); diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 7cd1bdcf491be..c08e1cacb15c6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -691,6 +691,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { int64_t offset, mlir::Type ty, cir::CIRDataLayout layout, llvm::SmallVectorImpl<int64_t> &indices); + // Convert high-level indices (e.g. from GlobalViewAttr) to byte offset. + uint64_t computeOffsetFromGlobalViewIndices(const cir::CIRDataLayout &layout, + mlir::Type ty, + llvm::ArrayRef<int64_t> indices); + /// Creates a versioned global variable. If the symbol is already taken, an ID /// will be appended to the symbol. The returned global must always be queried /// for its name so it can be referenced correctly. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 25fa4c7c86a89..d48d6b9efe7c4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -687,6 +687,92 @@ static void setLinkageForGV(cir::GlobalOp &gv, const NamedDecl *nd) { gv.setLinkage(cir::GlobalLinkageKind::ExternalWeakLinkage); } +static llvm::SmallVector<int64_t> indexesOfArrayAttr(mlir::ArrayAttr indexes) { + llvm::SmallVector<int64_t> inds; + for (mlir::Attribute i : indexes) { + auto ind = mlir::cast<mlir::IntegerAttr>(i); + inds.push_back(ind.getValue().getSExtValue()); + } + return inds; +} + +static bool isViewOnGlobal(cir::GlobalOp glob, cir::GlobalViewAttr view) { + return view.getSymbol().getValue() == glob.getSymName(); +} + +static cir::GlobalViewAttr createNewGlobalView(CIRGenModule &cgm, + cir::GlobalOp newGlob, + cir::GlobalViewAttr attr, + mlir::Type oldTy) { + // If the attribute does not require indexes or it is not a global view on + // the global we're replacing, keep the original attribute. + if (!attr.getIndices() || !isViewOnGlobal(newGlob, attr)) + return attr; + + llvm::SmallVector<int64_t> oldInds = indexesOfArrayAttr(attr.getIndices()); + llvm::SmallVector<int64_t> newInds; + CIRGenBuilderTy &bld = cgm.getBuilder(); + const cir::CIRDataLayout &layout = cgm.getDataLayout(); + mlir::Type newTy = newGlob.getSymType(); + + uint64_t offset = + bld.computeOffsetFromGlobalViewIndices(layout, oldTy, oldInds); + bld.computeGlobalViewIndicesFromFlatOffset(offset, newTy, layout, newInds); + cir::PointerType newPtrTy; + + if (isa<cir::RecordType>(oldTy)) + newPtrTy = cir::PointerType::get(newTy); + else if (isa<cir::ArrayType>(oldTy)) + newPtrTy = dyn_cast<cir::PointerType>(attr.getType()); + + if (newPtrTy) + return bld.getGlobalViewAttr(newPtrTy, newGlob, newInds); + + // This may be unreachable in practice, but keep it as errorNYI while CIR + // is still under development. + cgm.errorNYI("Unhandled type in createNewGlobalView"); + return {}; +} + +static mlir::Attribute getNewInitValue(CIRGenModule &cgm, cir::GlobalOp newGlob, + mlir::Type oldTy, cir::GlobalOp user, + mlir::Attribute oldInit) { + if (auto oldView = mlir::dyn_cast<cir::GlobalViewAttr>(oldInit)) + return createNewGlobalView(cgm, newGlob, oldView, oldTy); + + auto getNewInitElements = + [&](mlir::ArrayAttr oldElements) -> mlir::ArrayAttr { + llvm::SmallVector<mlir::Attribute> newElements; + for (mlir::Attribute elt : oldElements) { + if (auto view = mlir::dyn_cast<cir::GlobalViewAttr>(elt)) + newElements.push_back(createNewGlobalView(cgm, newGlob, view, oldTy)); + else if (mlir::isa<cir::ConstArrayAttr, cir::ConstRecordAttr>(elt)) + newElements.push_back(getNewInitValue(cgm, newGlob, oldTy, user, elt)); + else + newElements.push_back(elt); + } + return mlir::ArrayAttr::get(cgm.getBuilder().getContext(), newElements); + }; + + if (auto oldArray = mlir::dyn_cast<cir::ConstArrayAttr>(oldInit)) { + mlir::Attribute newElements = + getNewInitElements(mlir::dyn_cast<mlir::ArrayAttr>(oldArray.getElts())); + return cgm.getBuilder().getConstArray( + newElements, mlir::cast<cir::ArrayType>(oldArray.getType())); + } + if (auto oldRecord = mlir::dyn_cast<cir::ConstRecordAttr>(oldInit)) { + mlir::ArrayAttr newMembers = getNewInitElements(oldRecord.getMembers()); + auto recordTy = mlir::cast<cir::RecordType>(oldRecord.getType()); + return cgm.getBuilder().getConstRecordOrZeroAttr( + newMembers, recordTy.getPacked(), recordTy.getPadded(), recordTy); + } + + // This may be unreachable in practice, but keep it as errorNYI while CIR + // is still under development. + cgm.errorNYI("Unhandled type in getNewInitValue"); + return {}; +} + // We want to replace a global value, but because of CIR's typed pointers, // we need to update the existing uses to reflect the new type, not just replace // them directly. @@ -720,8 +806,20 @@ void CIRGenModule::replaceGlobal(cir::GlobalOp oldGV, cir::GlobalOp newGV) { mlir::Value cast = builder.createBitcast(getGlobalOp->getLoc(), useOpResultValue, ptrTy); useOpResultValue.replaceAllUsesExcept(cast, cast.getDefiningOp()); - } else { - errorNYI(userOp->getLoc(), "Replace global op use in global view attr"); + } else if (auto glob = dyn_cast<cir::GlobalOp>(userOp)) { + if (auto init = glob.getInitialValue()) { + mlir::Attribute nw = + getNewInitValue(*this, newGV, oldTy, glob, init.value()); + glob.setInitialValueAttr(nw); + } + } else if (auto c = dyn_cast<cir::ConstantOp>(userOp)) { + mlir::Attribute init = + getNewInitValue(*this, newGV, oldTy, newGV, c.getValue()); + auto typedAttr = mlir::cast<mlir::TypedAttr>(init); + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointAfter(c); + auto newUser = cir::ConstantOp::create(builder, c.getLoc(), typedAttr); + c.replaceAllUsesWith(newUser.getOperation()); } } diff --git a/clang/test/CIR/CodeGen/replace-global.cpp b/clang/test/CIR/CodeGen/replace-global.cpp index b6c22d5562801..709956d412873 100644 --- a/clang/test/CIR/CodeGen/replace-global.cpp +++ b/clang/test/CIR/CodeGen/replace-global.cpp @@ -13,25 +13,72 @@ void use(void*); static S gS = {{0x50, 0x4B, 0x03, 0x04}}; +S* ptrToS = &gS; + struct R { R() { use(&gS); } }; static R gR; +void use_as_constant() { + constexpr S *ptrToS = &gS; +} + +// This is just here to force ptrToS to be emitted. +S *get_ptr_to_s() { + return ptrToS; +} + +// Multi-index case: ptrToElement = &gSMulti.arr[5] creates a GlobalViewAttr with +// indices (struct member 0 = arr, array index 5). With extern gSMulti declared +// before the use, gSMulti is created when evaluating ptrToElement's initializer, +// then replaced when gSMulti is defined, so createNewGlobalView runs with multiple +// indices. Definition has external linkage to match the extern declaration. +extern S gSMulti; +char *ptrToElement = &gSMulti.arr[5]; +S gSMulti = {{0x50, 0x4B, 0x03, 0x04}}; + +char *get_ptr_to_element() { return ptrToElement; } + +// CIR: cir.global {{.*}} @_ZL2gS = #cir.const_record<{#cir.const_record<{#cir.int<80> : !s8i, #cir.int<75> : !s8i, #cir.int<3> : !s8i, #cir.int<4> : !s8i, #cir.zero : !cir.array<!s8i x 24>}> : !rec_anon_struct}> : !rec_anon_struct1 +// CIR: cir.global {{.*}} @ptrToS = #cir.global_view<@_ZL2gS> : !cir.ptr<!rec_S> + // CIR: cir.func {{.*}} @_ZN1RC2Ev // CIR: %[[GS_PTR:.*]] = cir.get_global @_ZL2gS : !cir.ptr<!rec_anon_struct1> // CIR: %[[GS_AS_S:.*]] = cir.cast bitcast %[[GS_PTR]] : !cir.ptr<!rec_anon_struct1> -> !cir.ptr<!rec_S> // CIR: %[[GS_AS_VOID:.*]] = cir.cast bitcast %[[GS_AS_S]] : !cir.ptr<!rec_S> -> !cir.ptr<!void> // CIR: cir.call @_Z3usePv(%[[GS_AS_VOID]]) : (!cir.ptr<!void> {{.*}}) -> () -// CIR: cir.global {{.*}} @_ZL2gS = #cir.const_record<{#cir.const_record<{#cir.int<80> : !s8i, #cir.int<75> : !s8i, #cir.int<3> : !s8i, #cir.int<4> : !s8i, #cir.zero : !cir.array<!s8i x 24>}> : !rec_anon_struct}> : !rec_anon_struct1 +// Multi-index case: ptrToElement = &gSMulti.arr[5] produces a global_view with +// multiple indices, exercising createNewGlobalView. +// CIR: cir.global {{.*}} @gSMulti = #cir.const_record< +// CIR: cir.global {{.*}} @ptrToElement = #cir.global_view<@gSMulti, [0, 4, 1]> : !cir.ptr< + +// CIR: cir.func {{.*}} @_Z15use_as_constantv() +// CIR: %[[PTR_TO_S:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["ptrToS", init, const] +// CIR: %[[GLOBAL_PTR:.*]] = cir.const #cir.global_view<@_ZL2gS> : !cir.ptr<!rec_S> +// CIR: cir.store{{.*}} %[[GLOBAL_PTR]], %[[PTR_TO_S]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> // LLVM: @_ZL2gS = internal global { <{ i8, i8, i8, i8, [24 x i8] }> } { <{ i8, i8, i8, i8, [24 x i8] }> <{ i8 80, i8 75, i8 3, i8 4, [24 x i8] zeroinitializer }> }, align 1 +// LLVM: @ptrToS = global ptr @_ZL2gS, align 8 +// LLVM: @gSMulti = global {{.*}} align 1 +// LLVM: @ptrToElement = global ptr getelementptr // LLVM: define {{.*}} void @_ZN1RC2Ev // LLVM: call void @_Z3usePv(ptr noundef @_ZL2gS) +// LLVM: define {{.*}} void @_Z15use_as_constantv() +// LLVM: %[[PTR_TO_S:.*]] = alloca ptr +// LLVM: store ptr @_ZL2gS, ptr %[[PTR_TO_S]] + +// OGCG: @ptrToS = global ptr @_ZL2gS, align 8 +// OGCG: @ptrToElement = global ptr {{.*}} align 8 +// OGCG: @gSMulti = global {{.*}} align 1 // OGCG: @_ZL2gS = internal global { <{ i8, i8, i8, i8, [24 x i8] }> } { <{ i8, i8, i8, i8, [24 x i8] }> <{ i8 80, i8 75, i8 3, i8 4, [24 x i8] zeroinitializer }> }, align 1 +// OGCG: define {{.*}} void @_Z15use_as_constantv() +// OGCG: %[[PTR_TO_S:.*]] = alloca ptr +// OGCG: store ptr @_ZL2gS, ptr %[[PTR_TO_S]] + // OGCG: define {{.*}} void @_ZN1RC2Ev // OGCG: call void @_Z3usePv(ptr noundef @_ZL2gS) `````````` </details> https://github.com/llvm/llvm-project/pull/186168 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
