[llvm-branch-commits] [flang] [mlir] [mlir][OpenMP] Pack task private variables into a heap-allocated context struct (PR #125307)
Sergio Afonso via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Feb 6 03:38:00 PST 2025
================
@@ -1794,37 +1909,118 @@ convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder,
moduleTranslation, allocaIP);
// Allocate and initialize private variables
- // TODO: package private variables up in a structure
builder.SetInsertPoint(initBlock->getTerminator());
- for (auto [privDecl, mlirPrivVar, blockArg] :
- llvm::zip_equal(privateDecls, mlirPrivateVars, privateBlockArgs)) {
- llvm::Type *llvmAllocType =
- moduleTranslation.convertType(privDecl.getType());
- // Allocations:
- builder.SetInsertPoint(allocaIP.getBlock()->getTerminator());
- llvm::Value *llvmPrivateVar = builder.CreateAlloca(
- llvmAllocType, /*ArraySize=*/nullptr, "omp.private.alloc");
+ // Create task variable structure
+ taskStructMgr.generateTaskContextStruct();
+ // GEPs so that we can initialize the variables. Don't use these GEPs inside
+ // of the body otherwise it will be the GEP not the struct which is fowarded
+ // to the outlined function. GEPs forwarded in this way are passed in a
+ // stack-allocated (by OpenMPIRBuilder) structure which is not safe for tasks
+ // which may not be executed until after the current stack frame goes out of
+ // scope.
+ taskStructMgr.createGEPsToPrivateVars();
+
+ for (auto [privDecl, mlirPrivVar, blockArg, llvmPrivateVarAlloc] :
+ llvm::zip_equal(privateDecls, mlirPrivateVars, privateBlockArgs,
+ taskStructMgr.getLLVMPrivateVarGEPs())) {
+ if (!privDecl.readsFromMold())
+ // to be handled inside the task
+ continue;
+ assert(llvmPrivateVarAlloc &&
+ "reads from mold so shouldn't have been skipped");
- auto err =
+ llvm::Expected<llvm::Value *> privateVarOrErr =
initPrivateVar(builder, moduleTranslation, privDecl, mlirPrivVar,
- blockArg, llvmPrivateVar, llvmPrivateVars, initBlock);
- if (err)
+ blockArg, llvmPrivateVarAlloc, initBlock);
+ if (auto err = privateVarOrErr.takeError())
return handleError(std::move(err), *taskOp.getOperation());
+
+ llvm::IRBuilderBase::InsertPointGuard guard(builder);
+ builder.SetInsertPoint(builder.GetInsertBlock()->getTerminator());
+
+ // TODO: this is a bit of a hack for Fortran character boxes.
+ // Character boxes are passed by value into the init region and then the
+ // initialized character box is yielded by value. Here we need to store the
+ // yielded value into the private allocation, and load the private
+ // allocation to match the type expected by region block arguments.
+ if ((privateVarOrErr.get() != llvmPrivateVarAlloc) &&
+ !mlir::isa<LLVM::LLVMPointerType>(blockArg.getType())) {
+ builder.CreateStore(privateVarOrErr.get(), llvmPrivateVarAlloc);
+ // Load it so we have the value pointed to by the GEP
+ llvmPrivateVarAlloc = builder.CreateLoad(privateVarOrErr.get()->getType(),
+ llvmPrivateVarAlloc);
+ }
+ assert(llvmPrivateVarAlloc->getType() ==
+ moduleTranslation.convertType(blockArg.getType()));
+
+ // Mapping blockArg -> llvmPrivateVarAlloc is done inside the body callback
+ // so that OpenMPIRBuilder doesn't try to pass each GEP address through a
+ // stack allocated structure.
}
// firstprivate copy region
if (failed(initFirstPrivateVars(builder, moduleTranslation, mlirPrivateVars,
- llvmPrivateVars, privateDecls, copyBlock)))
+ taskStructMgr.getLLVMPrivateVarGEPs(),
+ privateDecls, copyBlock)))
return llvm::failure();
// Set up for call to createTask()
builder.SetInsertPoint(taskStartBlock);
auto bodyCB = [&](InsertPointTy allocaIP,
InsertPointTy codegenIP) -> llvm::Error {
+ // Save the alloca insertion point on ModuleTranslation stack for use in
+ // nested regions.
+ LLVM::ModuleTranslation::SaveStack<OpenMPAllocaStackFrame> frame(
+ moduleTranslation, allocaIP);
+
// translate the body of the task:
builder.restoreIP(codegenIP);
+
+ llvm::BasicBlock *privInitBlock = nullptr;
+ for (auto [blockArg, privDecl, mlirPrivVar] :
+ llvm::zip_equal(privateBlockArgs, privateDecls, mlirPrivateVars)) {
+ if (privDecl.readsFromMold())
+ // This is handled before the task executes
+ continue;
+
+ auto codegenInsertionPt = builder.saveIP();
+ llvm::Type *llvmAllocType =
+ moduleTranslation.convertType(privDecl.getType());
+ builder.SetInsertPoint(allocaIP.getBlock()->getTerminator());
+ llvm::Value *llvmPrivateVar = builder.CreateAlloca(
+ llvmAllocType, /*ArraySize=*/nullptr, "omp.private.alloc");
+
+ llvm::Expected<llvm::Value *> privateVarOrError =
+ initPrivateVar(builder, moduleTranslation, privDecl, mlirPrivVar,
+ blockArg, llvmPrivateVar, privInitBlock);
+ if (auto err = privateVarOrError.takeError())
+ return err;
+ moduleTranslation.mapValue(blockArg, privateVarOrError.get());
+ builder.restoreIP(codegenInsertionPt);
+ }
+
+ // Find and map the addresses of each variable within the task context
+ // structure
+ taskStructMgr.createGEPsToPrivateVars();
+ llvm::copy(taskStructMgr.getLLVMPrivateVarGEPs(),
+ std::back_inserter(llvmPrivateVars));
----------------
skatrak wrote:
Could this cause `null` pointer dereferences on other uses of `llvmPrivateVars` after the new loop introduced below? For example, that list is passed to `cleanupPrivateVars`, which doesn't seem to check for `null` elements.
https://github.com/llvm/llvm-project/pull/125307
More information about the llvm-branch-commits
mailing list