Author: Andy Kaylor Date: 2026-03-04T13:50:54-08:00 New Revision: 954e5e7aa2e23d315a13fc052807d6600b182341
URL: https://github.com/llvm/llvm-project/commit/954e5e7aa2e23d315a13fc052807d6600b182341 DIFF: https://github.com/llvm/llvm-project/commit/954e5e7aa2e23d315a13fc052807d6600b182341.diff LOG: [CIR] Upstream global variable replacement (#184686) This change upstreams the CIR implementation of global variable replacement. When we get a call to get or create a global variable using a type that does not match the previous type for a variable of the same name, we need to replace the old definition with the new one. In classic codegen that was as simple as replaceAllUses+eraseFromParent, but in CIR because we have typed pointers, we need to visit the uses and update them with bitcasts to reflect the new type. Added: clang/test/CIR/CodeGen/replace-global.cpp Modified: clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenModule.h Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 3ef487465ab80..c9df1499ea453 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -674,6 +674,47 @@ static void setLinkageForGV(cir::GlobalOp &gv, const NamedDecl *nd) { gv.setLinkage(cir::GlobalLinkageKind::ExternalWeakLinkage); } +// 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. +void CIRGenModule::replaceGlobal(cir::GlobalOp oldGV, cir::GlobalOp newGV) { + assert(oldGV.getSymName() == newGV.getSymName() && "symbol names must match"); + + mlir::Type oldTy = oldGV.getSymType(); + mlir::Type newTy = newGV.getSymType(); + + assert(!cir::MissingFeatures::addressSpace()); + + // If the type didn't change, why are we here? + assert(oldTy != newTy && "expected type change in replaceGlobal"); + + // Visit all uses and add handling to fix up the types. + std::optional<mlir::SymbolTable::UseRange> oldSymUses = + oldGV.getSymbolUses(theModule); + for (mlir::SymbolTable::SymbolUse use : *oldSymUses) { + mlir::Operation *userOp = use.getUser(); + assert( + (mlir::isa<cir::GetGlobalOp, cir::GlobalOp, cir::ConstantOp>(userOp)) && + "Unexpected user for global op"); + + if (auto getGlobalOp = dyn_cast<cir::GetGlobalOp>(use.getUser())) { + mlir::Value useOpResultValue = getGlobalOp.getAddr(); + useOpResultValue.setType(cir::PointerType::get(newTy)); + + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointAfter(getGlobalOp); + mlir::Type ptrTy = builder.getPointerTo(oldTy); + 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"); + } + } + + oldGV.erase(); +} + /// If the specified mangled name is not in the module, /// create and return an mlir GlobalOp with the specified type (TODO(cir): /// address space). @@ -748,6 +789,11 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty, CIRGenModule::createGlobalOp(*this, loc, mangledName, ty, isConstant, /*insertPoint=*/entry.getOperation()); + // If we already created a global with the same mangled name (but diff erent + // type) before, remove it from its parent. + if (entry) + replaceGlobal(entry, gv); + // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 0f456f1f39ceb..48bb1f2ae20d9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -613,6 +613,10 @@ class CIRGenModule : public CIRGenTypeCache { // related attributes. bool shouldEmitCUDAGlobalVar(const VarDecl *global) const; + /// Replace all uses of the old global with the new global, updating types + /// and references as needed. Erases the old global when done. + void replaceGlobal(cir::GlobalOp oldGV, cir::GlobalOp newGV); + void replaceUsesOfNonProtoTypeWithRealFunction(mlir::Operation *old, cir::FuncOp newFn); diff --git a/clang/test/CIR/CodeGen/replace-global.cpp b/clang/test/CIR/CodeGen/replace-global.cpp new file mode 100644 index 0000000000000..b6c22d5562801 --- /dev/null +++ b/clang/test/CIR/CodeGen/replace-global.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct S { + char arr[28]; +}; + +void use(void*); + +static S gS = {{0x50, 0x4B, 0x03, 0x04}}; + +struct R { + R() { use(&gS); } +}; +static R gR; + +// 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 + +// 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: define {{.*}} void @_ZN1RC2Ev +// LLVM: call void @_Z3usePv(ptr noundef @_ZL2gS) + +// 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 @_ZN1RC2Ev +// OGCG: call void @_Z3usePv(ptr noundef @_ZL2gS) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
