Skip to content

Commit eac2adc

Browse files
committed
[OpenMP][OMPIRBuilder] Add delayed privatization support for wsloop
Extend MLIR to LLVM lowering by adding support for `omp.wsloop` for delayed privatization. This also refactors a few bit of code to isolate the logic needed for `firstprivate` initialization in a shared util that can be used across constructs that need it.
1 parent a308530 commit eac2adc

File tree

3 files changed

+228
-140
lines changed

3 files changed

+228
-140
lines changed

mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp

Lines changed: 140 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
268268
checkAllocate(op, result);
269269
checkLinear(op, result);
270270
checkOrder(op, result);
271-
checkPrivate(op, result);
272271
})
273272
.Case([&](omp::ParallelOp op) { checkAllocate(op, result); })
274273
.Case([&](omp::SimdOp op) {
@@ -1302,6 +1301,7 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
13021301
MutableArrayRef<mlir::Value> mlirPrivateVars,
13031302
llvm::SmallVectorImpl<llvm::Value *> &llvmPrivateVars,
13041303
const llvm::OpenMPIRBuilder::InsertPointTy &allocaIP) {
1304+
llvm::IRBuilderBase::InsertPointGuard guard(builder);
13051305
// Allocate private vars
13061306
llvm::BranchInst *allocaTerminator =
13071307
llvm::cast<llvm::BranchInst>(allocaIP.getBlock()->getTerminator());
@@ -1363,6 +1363,84 @@ allocatePrivateVars(llvm::IRBuilderBase &builder,
13631363
return afterAllocas;
13641364
}
13651365

1366+
static LogicalResult
1367+
initFirstPrivateVars(llvm::IRBuilderBase &builder,
1368+
LLVM::ModuleTranslation &moduleTranslation,
1369+
SmallVectorImpl<mlir::Value> &mlirPrivateVars,
1370+
SmallVectorImpl<llvm::Value *> &llvmPrivateVars,
1371+
SmallVectorImpl<omp::PrivateClauseOp> &privateDecls,
1372+
llvm::BasicBlock *afterAllocas) {
1373+
llvm::IRBuilderBase::InsertPointGuard guard(builder);
1374+
// Apply copy region for firstprivate.
1375+
bool needsFirstprivate =
1376+
llvm::any_of(privateDecls, [](omp::PrivateClauseOp &privOp) {
1377+
return privOp.getDataSharingType() ==
1378+
omp::DataSharingClauseType::FirstPrivate;
1379+
});
1380+
1381+
if (needsFirstprivate) {
1382+
// Find the end of the allocation blocks
1383+
builder.SetInsertPoint(
1384+
afterAllocas->getSinglePredecessor()->getTerminator());
1385+
llvm::BasicBlock *copyBlock =
1386+
splitBB(builder, /*CreateBranch=*/true, "omp.private.copy");
1387+
builder.SetInsertPoint(copyBlock->getFirstNonPHIOrDbgOrAlloca());
1388+
}
1389+
1390+
for (auto [decl, mlirVar, llvmVar] :
1391+
llvm::zip_equal(privateDecls, mlirPrivateVars, llvmPrivateVars)) {
1392+
if (decl.getDataSharingType() != omp::DataSharingClauseType::FirstPrivate)
1393+
continue;
1394+
1395+
// copyRegion implements `lhs = rhs`
1396+
Region &copyRegion = decl.getCopyRegion();
1397+
1398+
// map copyRegion rhs arg
1399+
llvm::Value *nonPrivateVar = moduleTranslation.lookupValue(mlirVar);
1400+
assert(nonPrivateVar);
1401+
moduleTranslation.mapValue(decl.getCopyMoldArg(), nonPrivateVar);
1402+
1403+
// map copyRegion lhs arg
1404+
moduleTranslation.mapValue(decl.getCopyPrivateArg(), llvmVar);
1405+
1406+
// in-place convert copy region
1407+
builder.SetInsertPoint(builder.GetInsertBlock()->getTerminator());
1408+
if (failed(inlineConvertOmpRegions(copyRegion, "omp.private.copy", builder,
1409+
moduleTranslation)))
1410+
return decl.emitError("failed to inline `copy` region of `omp.private`");
1411+
1412+
// ignore unused value yielded from copy region
1413+
1414+
// clear copy region block argument mapping in case it needs to be
1415+
// re-created with different sources for reuse of the same reduction
1416+
// decl
1417+
moduleTranslation.forgetMapping(copyRegion);
1418+
}
1419+
1420+
return success();
1421+
}
1422+
1423+
static LogicalResult
1424+
cleanupPrivateVars(llvm::IRBuilderBase &builder,
1425+
LLVM::ModuleTranslation &moduleTranslation, Location loc,
1426+
SmallVectorImpl<llvm::Value *> &llvmPrivateVars,
1427+
SmallVectorImpl<omp::PrivateClauseOp> &privateDecls) {
1428+
// private variable deallocation
1429+
SmallVector<Region *> privateCleanupRegions;
1430+
llvm::transform(privateDecls, std::back_inserter(privateCleanupRegions),
1431+
[](omp::PrivateClauseOp privatizer) {
1432+
return &privatizer.getDeallocRegion();
1433+
});
1434+
1435+
if (failed(inlineOmpRegionCleanup(
1436+
privateCleanupRegions, llvmPrivateVars, moduleTranslation, builder,
1437+
"omp.private.dealloc", /*shouldLoadCleanupRegionArg=*/false)))
1438+
return mlir::emitError(loc, "failed to inline `dealloc` region of an "
1439+
"`omp.private` op in an omp.task");
1440+
1441+
return success();
1442+
}
1443+
13661444
static LogicalResult
13671445
convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder,
13681446
LLVM::ModuleTranslation &moduleTranslation) {
@@ -1622,50 +1700,10 @@ convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder,
16221700
if (handleError(afterAllocas, *taskOp).failed())
16231701
return llvm::make_error<PreviouslyReportedError>();
16241702

1625-
// Apply copy region for firstprivate
1626-
bool needsFirstPrivate =
1627-
llvm::any_of(privateDecls, [](omp::PrivateClauseOp &privOp) {
1628-
return privOp.getDataSharingType() ==
1629-
omp::DataSharingClauseType::FirstPrivate;
1630-
});
1631-
if (needsFirstPrivate) {
1632-
// Find the end of the allocation blocks
1633-
assert(afterAllocas.get()->getSinglePredecessor());
1634-
builder.SetInsertPoint(
1635-
afterAllocas.get()->getSinglePredecessor()->getTerminator());
1636-
llvm::BasicBlock *copyBlock =
1637-
splitBB(builder, /*CreateBranch=*/true, "omp.private.copy");
1638-
builder.SetInsertPoint(copyBlock->getFirstNonPHIOrDbgOrAlloca());
1639-
}
1640-
for (auto [decl, mlirVar, llvmVar] :
1641-
llvm::zip_equal(privateDecls, mlirPrivateVars, llvmPrivateVars)) {
1642-
if (decl.getDataSharingType() != omp::DataSharingClauseType::FirstPrivate)
1643-
continue;
1644-
1645-
// copyRegion implements `lhs = rhs`
1646-
Region &copyRegion = decl.getCopyRegion();
1647-
1648-
// map copyRegion rhs arg
1649-
llvm::Value *nonPrivateVar = moduleTranslation.lookupValue(mlirVar);
1650-
assert(nonPrivateVar);
1651-
moduleTranslation.mapValue(decl.getCopyMoldArg(), nonPrivateVar);
1652-
1653-
// map copyRegion lhs arg
1654-
moduleTranslation.mapValue(decl.getCopyPrivateArg(), llvmVar);
1655-
1656-
// in-place convert copy region
1657-
builder.SetInsertPoint(builder.GetInsertBlock()->getTerminator());
1658-
if (failed(inlineConvertOmpRegions(copyRegion, "omp.private.copy",
1659-
builder, moduleTranslation)))
1660-
return llvm::createStringError(
1661-
"failed to inline `copy` region of an `omp.private` op in taskOp");
1662-
1663-
// ignore unused value yielded from copy region
1664-
1665-
// clear copy region block argument mapping in case it needs to be
1666-
// re-created with different source for reuse of the same reduction decl
1667-
moduleTranslation.forgetMapping(copyRegion);
1668-
}
1703+
if (failed(initFirstPrivateVars(builder, moduleTranslation, mlirPrivateVars,
1704+
llvmPrivateVars, privateDecls,
1705+
afterAllocas.get())))
1706+
return llvm::make_error<PreviouslyReportedError>();
16691707

16701708
// translate the body of the task:
16711709
builder.restoreIP(codegenIP);
@@ -1674,19 +1712,11 @@ convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder,
16741712
if (failed(handleError(continuationBlockOrError, *taskOp)))
16751713
return llvm::make_error<PreviouslyReportedError>();
16761714

1677-
// private variable deallocation
1678-
SmallVector<Region *> privateCleanupRegions;
1679-
llvm::transform(privateDecls, std::back_inserter(privateCleanupRegions),
1680-
[](omp::PrivateClauseOp privatizer) {
1681-
return &privatizer.getDeallocRegion();
1682-
});
1683-
16841715
builder.SetInsertPoint(continuationBlockOrError.get()->getTerminator());
1685-
if (failed(inlineOmpRegionCleanup(
1686-
privateCleanupRegions, llvmPrivateVars, moduleTranslation, builder,
1687-
"omp.private.dealloc", /*shouldLoadCleanupRegionArg=*/false)))
1688-
return llvm::createStringError("failed to inline `dealloc` region of an "
1689-
"`omp.private` op in an omp.task");
1716+
1717+
if (failed(cleanupPrivateVars(builder, moduleTranslation, taskOp.getLoc(),
1718+
llvmPrivateVars, privateDecls)))
1719+
return llvm::make_error<PreviouslyReportedError>();
16901720

16911721
return llvm::Error::success();
16921722
};
@@ -1777,22 +1807,56 @@ convertOmpWsloop(Operation &opInst, llvm::IRBuilderBase &builder,
17771807
chunk = builder.CreateSExtOrTrunc(chunkVar, ivType);
17781808
}
17791809

1810+
MutableArrayRef<BlockArgument> privateBlockArgs =
1811+
cast<omp::BlockArgOpenMPOpInterface>(*wsloopOp).getPrivateBlockArgs();
1812+
SmallVector<mlir::Value> mlirPrivateVars;
1813+
SmallVector<llvm::Value *> llvmPrivateVars;
1814+
SmallVector<omp::PrivateClauseOp> privateDecls;
1815+
mlirPrivateVars.reserve(privateBlockArgs.size());
1816+
llvmPrivateVars.reserve(privateBlockArgs.size());
1817+
collectPrivatizationDecls(wsloopOp, privateDecls);
1818+
1819+
for (mlir::Value privateVar : wsloopOp.getPrivateVars())
1820+
mlirPrivateVars.push_back(privateVar);
1821+
17801822
SmallVector<omp::DeclareReductionOp> reductionDecls;
17811823
collectReductionDecls(wsloopOp, reductionDecls);
17821824
llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
17831825
findAllocaInsertPoint(builder, moduleTranslation);
17841826

17851827
SmallVector<llvm::Value *> privateReductionVariables(
17861828
wsloopOp.getNumReductionVars());
1829+
1830+
llvm::Expected<llvm::BasicBlock *> afterAllocas = allocatePrivateVars(
1831+
builder, moduleTranslation, privateBlockArgs, privateDecls,
1832+
mlirPrivateVars, llvmPrivateVars, allocaIP);
1833+
if (handleError(afterAllocas, opInst).failed())
1834+
return failure();
1835+
17871836
DenseMap<Value, llvm::Value *> reductionVariableMap;
17881837

17891838
MutableArrayRef<BlockArgument> reductionArgs =
17901839
cast<omp::BlockArgOpenMPOpInterface>(opInst).getReductionBlockArgs();
17911840

1792-
if (failed(allocAndInitializeReductionVars(
1793-
wsloopOp, reductionArgs, builder, moduleTranslation, allocaIP,
1794-
reductionDecls, privateReductionVariables, reductionVariableMap,
1795-
isByRef)))
1841+
SmallVector<DeferredStore> deferredStores;
1842+
1843+
if (failed(allocReductionVars(wsloopOp, reductionArgs, builder,
1844+
moduleTranslation, allocaIP, reductionDecls,
1845+
privateReductionVariables, reductionVariableMap,
1846+
deferredStores, isByRef)))
1847+
return failure();
1848+
1849+
if (failed(initFirstPrivateVars(builder, moduleTranslation, mlirPrivateVars,
1850+
llvmPrivateVars, privateDecls,
1851+
afterAllocas.get())))
1852+
return failure();
1853+
1854+
assert(afterAllocas.get()->getSinglePredecessor());
1855+
if (failed(initReductionVars(wsloopOp, reductionArgs, builder,
1856+
moduleTranslation,
1857+
afterAllocas.get()->getSinglePredecessor(),
1858+
reductionDecls, privateReductionVariables,
1859+
reductionVariableMap, isByRef, deferredStores)))
17961860
return failure();
17971861

17981862
// TODO: Replace this with proper composite translation support.
@@ -1899,9 +1963,13 @@ convertOmpWsloop(Operation &opInst, llvm::IRBuilderBase &builder,
18991963
builder.restoreIP(afterIP);
19001964

19011965
// Process the reductions if required.
1902-
return createReductionsAndCleanup(wsloopOp, builder, moduleTranslation,
1903-
allocaIP, reductionDecls,
1904-
privateReductionVariables, isByRef);
1966+
if (failed(createReductionsAndCleanup(wsloopOp, builder, moduleTranslation,
1967+
allocaIP, reductionDecls,
1968+
privateReductionVariables, isByRef)))
1969+
return failure();
1970+
1971+
return cleanupPrivateVars(builder, moduleTranslation, wsloopOp.getLoc(),
1972+
llvmPrivateVars, privateDecls);
19051973
}
19061974

19071975
/// Converts the OpenMP parallel operation to LLVM IR.
@@ -1959,53 +2027,12 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
19592027
deferredStores, isByRef)))
19602028
return llvm::make_error<PreviouslyReportedError>();
19612029

1962-
// Apply copy region for firstprivate.
1963-
bool needsFirstprivate =
1964-
llvm::any_of(privateDecls, [](omp::PrivateClauseOp &privOp) {
1965-
return privOp.getDataSharingType() ==
1966-
omp::DataSharingClauseType::FirstPrivate;
1967-
});
1968-
if (needsFirstprivate) {
1969-
// Find the end of the allocation blocks
1970-
assert(afterAllocas.get()->getSinglePredecessor());
1971-
builder.SetInsertPoint(
1972-
afterAllocas.get()->getSinglePredecessor()->getTerminator());
1973-
llvm::BasicBlock *copyBlock =
1974-
splitBB(builder, /*CreateBranch=*/true, "omp.private.copy");
1975-
builder.SetInsertPoint(copyBlock->getFirstNonPHIOrDbgOrAlloca());
1976-
}
1977-
1978-
for (auto [decl, mlirVar, llvmVar] :
1979-
llvm::zip_equal(privateDecls, mlirPrivateVars, llvmPrivateVars)) {
1980-
if (decl.getDataSharingType() != omp::DataSharingClauseType::FirstPrivate)
1981-
continue;
1982-
1983-
// copyRegion implements `lhs = rhs`
1984-
Region &copyRegion = decl.getCopyRegion();
1985-
1986-
// map copyRegion rhs arg
1987-
llvm::Value *nonPrivateVar = moduleTranslation.lookupValue(mlirVar);
1988-
assert(nonPrivateVar);
1989-
moduleTranslation.mapValue(decl.getCopyMoldArg(), nonPrivateVar);
1990-
1991-
// map copyRegion lhs arg
1992-
moduleTranslation.mapValue(decl.getCopyPrivateArg(), llvmVar);
1993-
1994-
// in-place convert copy region
1995-
builder.SetInsertPoint(builder.GetInsertBlock()->getTerminator());
1996-
if (failed(inlineConvertOmpRegions(copyRegion, "omp.private.copy",
1997-
builder, moduleTranslation)))
1998-
return llvm::createStringError(
1999-
"failed to inline `copy` region of `omp.private`");
2000-
2001-
// ignore unused value yielded from copy region
2002-
2003-
// clear copy region block argument mapping in case it needs to be
2004-
// re-created with different sources for reuse of the same reduction
2005-
// decl
2006-
moduleTranslation.forgetMapping(copyRegion);
2007-
}
2030+
if (failed(initFirstPrivateVars(builder, moduleTranslation, mlirPrivateVars,
2031+
llvmPrivateVars, privateDecls,
2032+
afterAllocas.get())))
2033+
return llvm::make_error<PreviouslyReportedError>();
20082034

2035+
assert(afterAllocas.get()->getSinglePredecessor());
20092036
if (failed(
20102037
initReductionVars(opInst, reductionArgs, builder, moduleTranslation,
20112038
afterAllocas.get()->getSinglePredecessor(),
@@ -2090,17 +2117,9 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
20902117
return llvm::createStringError(
20912118
"failed to inline `cleanup` region of `omp.declare_reduction`");
20922119

2093-
SmallVector<Region *> privateCleanupRegions;
2094-
llvm::transform(privateDecls, std::back_inserter(privateCleanupRegions),
2095-
[](omp::PrivateClauseOp privatizer) {
2096-
return &privatizer.getDeallocRegion();
2097-
});
2098-
2099-
if (failed(inlineOmpRegionCleanup(
2100-
privateCleanupRegions, llvmPrivateVars, moduleTranslation, builder,
2101-
"omp.private.dealloc", /*shouldLoadCleanupRegionArg=*/false)))
2102-
return llvm::createStringError(
2103-
"failed to inline `dealloc` region of `omp.private`");
2120+
if (failed(cleanupPrivateVars(builder, moduleTranslation, opInst.getLoc(),
2121+
llvmPrivateVars, privateDecls)))
2122+
return llvm::make_error<PreviouslyReportedError>();
21042123

21052124
builder.restoreIP(oldIP);
21062125
return llvm::Error::success();

mlir/test/Target/LLVMIR/openmp-todo.mlir

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -635,22 +635,3 @@ llvm.func @wsloop_order(%lb : i32, %ub : i32, %step : i32) {
635635
}
636636
llvm.return
637637
}
638-
639-
// -----
640-
641-
omp.private {type = private} @x.privatizer : !llvm.ptr alloc {
642-
^bb0(%arg0: !llvm.ptr):
643-
%0 = llvm.mlir.constant(1 : i32) : i32
644-
%1 = llvm.alloca %0 x i32 : (i32) -> !llvm.ptr
645-
omp.yield(%1 : !llvm.ptr)
646-
}
647-
llvm.func @wsloop_private(%lb : i32, %ub : i32, %step : i32, %x : !llvm.ptr) {
648-
// expected-error@below {{not yet implemented: Unhandled clause privatization in omp.wsloop operation}}
649-
// expected-error@below {{LLVM Translation failed for operation: omp.wsloop}}
650-
omp.wsloop private(@x.privatizer %x -> %arg0 : !llvm.ptr) {
651-
omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
652-
omp.yield
653-
}
654-
}
655-
llvm.return
656-
}

0 commit comments

Comments
 (0)