@@ -690,14 +690,14 @@ inlineOmpRegionCleanup(llvm::SmallVectorImpl<Region *> &cleanupRegions,
690690 : &builder.GetInsertBlock ()->back ();
691691 if (potentialTerminator && potentialTerminator->isTerminator ())
692692 builder.SetInsertPoint (potentialTerminator);
693- llvm::Value *prviateVarValue =
693+ llvm::Value *privateVarValue =
694694 shouldLoadCleanupRegionArg
695695 ? builder.CreateLoad (
696696 moduleTranslation.convertType (entry.getArgument (0 ).getType ()),
697697 privateVariables[i])
698698 : privateVariables[i];
699699
700- moduleTranslation.mapValue (entry.getArgument (0 ), prviateVarValue );
700+ moduleTranslation.mapValue (entry.getArgument (0 ), privateVarValue );
701701
702702 if (failed (inlineConvertOmpRegions (*cleanupRegion, regionName, builder,
703703 moduleTranslation)))
@@ -1424,35 +1424,106 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
14241424 }
14251425 };
14261426
1427- SmallVector<omp::PrivateClauseOp> privatizerClones ;
1428- SmallVector<llvm::Value *> privateVariables ;
1427+ SmallVector<omp::PrivateClauseOp> mlirPrivatizerClones ;
1428+ SmallVector<llvm::Value *> llvmPrivateVars ;
14291429
14301430 // TODO: Perform appropriate actions according to the data-sharing
14311431 // attribute (shared, private, firstprivate, ...) of variables.
14321432 // Currently shared and private are supported.
14331433 auto privCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
1434- llvm::Value &, llvm::Value &vPtr ,
1435- llvm::Value *&replacementValue ) -> InsertPointTy {
1436- replacementValue = &vPtr ;
1434+ llvm::Value &, llvm::Value &llvmOmpRegionInput ,
1435+ llvm::Value *&llvmReplacementValue ) -> InsertPointTy {
1436+ llvmReplacementValue = &llvmOmpRegionInput ;
14371437
14381438 // If this is a private value, this lambda will return the corresponding
14391439 // mlir value and its `PrivateClauseOp`. Otherwise, empty values are
14401440 // returned.
1441- auto [privVar, privatizerClone ] =
1441+ auto [mlirPrivVar, mlirPrivatizerClone ] =
14421442 [&]() -> std::pair<mlir::Value, omp::PrivateClauseOp> {
14431443 if (!opInst.getPrivateVars ().empty ()) {
1444- auto privateVars = opInst.getPrivateVars ();
1445- auto privateSyms = opInst.getPrivateSyms ();
1444+ auto mlirPrivVars = opInst.getPrivateVars ();
1445+ auto mlirPrivSyms = opInst.getPrivateSyms ();
14461446
1447- for (auto [privVar, privatizerAttr] :
1448- llvm::zip_equal (privateVars, *privateSyms)) {
1447+ // Try to find a privatizer that corresponds to the LLVM value being
1448+ // privatized.
1449+ for (auto [mlirPrivVar, mlirPrivatizerAttr] :
1450+ llvm::zip_equal (mlirPrivVars, *mlirPrivSyms)) {
14491451 // Find the MLIR private variable corresponding to the LLVM value
14501452 // being privatized.
1451- llvm::Value *llvmPrivVar = moduleTranslation.lookupValue (privVar);
1452- if (llvmPrivVar != &vPtr)
1453+ llvm::Value *mlirToLLVMPrivVar =
1454+ moduleTranslation.lookupValue (mlirPrivVar);
1455+
1456+ // Check if the LLVM value being privatized matches the LLVM value
1457+ // mapped to privVar. In some cases, this is not trivial ...
1458+ auto isMatch = [&]() {
1459+ if (mlirToLLVMPrivVar == nullptr )
1460+ return false ;
1461+
1462+ // If both values are trivially equal, we found a match.
1463+ if (mlirToLLVMPrivVar == &llvmOmpRegionInput)
1464+ return true ;
1465+
1466+ // Otherwise, we check if both llvmOmpRegionInputPtr and
1467+ // mlirToLLVMPrivVar refer to the same memory (through a load/store
1468+ // pair). This happens if a struct (i.e. multi-field value) is being
1469+ // privatized.
1470+ //
1471+ // For example, if the privatized value is defined by:
1472+ // ```
1473+ // %priv_val = alloca { ptr, i64 }, align 8
1474+ // ```
1475+ //
1476+ // The initialization of this value (outside the omp region) will be
1477+ // something like this:
1478+ //
1479+ // clang-format off
1480+ // ```
1481+ // %partially_init_priv_val = insertvalue { ptr, i64 } undef,
1482+ // ptr %some_ptr, 0
1483+ // %fully_init_priv_val = insertvalue { ptr, i64 } %partially_init_priv_val,
1484+ // i64 %some_i64, 1
1485+ // ...
1486+ // store { ptr, i64 } %fully_init_priv_val, ptr %priv_val, align 8
1487+ // ```
1488+ // clang-format on
1489+ //
1490+ // Now, we enter the OMP region, in order to access this privatized
1491+ // value, we need to load from the allocated memory:
1492+ // ```
1493+ // omp.par.entry:
1494+ // %priv_val_load = load { ptr, i64 }, ptr %priv_val, align 8
1495+ // ```
1496+ //
1497+ // The 2 LLVM values tracked here map as follows:
1498+ // - `mlirToLLVMPrivVar` -> `%fully_init_priv_val`
1499+ // - `llvmOmpRegionInputPtr` -> `%priv_val_load`
1500+ //
1501+ // Even though they eventually refer to the same memory reference
1502+ // (the memory being privatized), they are 2 distinct LLVM values.
1503+ // Therefore, we need to discover their correspondence by finding
1504+ // out if they store into and load from the same mem ref.
1505+ auto *llvmOmpRegionInputPtrLoad =
1506+ llvm::dyn_cast_if_present<llvm::LoadInst>(&llvmOmpRegionInput);
1507+
1508+ if (llvmOmpRegionInputPtrLoad == nullptr )
1509+ return false ;
1510+
1511+ for (auto &use : mlirToLLVMPrivVar->uses ()) {
1512+ auto *mlirToLLVMPrivVarStore =
1513+ llvm::dyn_cast_if_present<llvm::StoreInst>(use.getUser ());
1514+ if (mlirToLLVMPrivVarStore &&
1515+ (llvmOmpRegionInputPtrLoad->getPointerOperand () ==
1516+ mlirToLLVMPrivVarStore->getPointerOperand ()))
1517+ return true ;
1518+ }
1519+
1520+ return false ;
1521+ };
1522+
1523+ if (!isMatch ())
14531524 continue ;
14541525
1455- SymbolRefAttr privSym = llvm::cast<SymbolRefAttr>(privatizerAttr );
1526+ SymbolRefAttr privSym = llvm::cast<SymbolRefAttr>(mlirPrivatizerAttr );
14561527 omp::PrivateClauseOp privatizer =
14571528 SymbolTable::lookupNearestSymbolFrom<omp::PrivateClauseOp>(
14581529 opInst, privSym);
@@ -1480,24 +1551,24 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
14801551 counter);
14811552
14821553 clone.setSymName (cloneName);
1483- return {privVar , clone};
1554+ return {mlirPrivVar , clone};
14841555 }
14851556 }
14861557
14871558 return {mlir::Value (), omp::PrivateClauseOp ()};
14881559 }();
14891560
1490- if (privVar ) {
1491- Region &allocRegion = privatizerClone .getAllocRegion ();
1561+ if (mlirPrivVar ) {
1562+ Region &allocRegion = mlirPrivatizerClone .getAllocRegion ();
14921563
14931564 // If this is a `firstprivate` clause, prepare the `omp.private` op by:
1494- if (privatizerClone .getDataSharingType () ==
1565+ if (mlirPrivatizerClone .getDataSharingType () ==
14951566 omp::DataSharingClauseType::FirstPrivate) {
14961567 auto oldAllocBackBlock = std::prev (allocRegion.end ());
14971568 omp::YieldOp oldAllocYieldOp =
14981569 llvm::cast<omp::YieldOp>(oldAllocBackBlock->getTerminator ());
14991570
1500- Region ©Region = privatizerClone .getCopyRegion ();
1571+ Region ©Region = mlirPrivatizerClone .getCopyRegion ();
15011572
15021573 mlir::IRRewriter copyCloneBuilder (&moduleTranslation.getContext ());
15031574 // 1. Cloning the `copy` region to the end of the `alloc` region.
@@ -1524,7 +1595,7 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
15241595 // This way, the body of the privatizer will be changed from using the
15251596 // region/block argument to the value being privatized.
15261597 auto allocRegionArg = allocRegion.getArgument (0 );
1527- replaceAllUsesInRegionWith (allocRegionArg, privVar , allocRegion);
1598+ replaceAllUsesInRegionWith (allocRegionArg, mlirPrivVar , allocRegion);
15281599
15291600 auto oldIP = builder.saveIP ();
15301601 builder.restoreIP (allocaIP);
@@ -1535,15 +1606,15 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
15351606 opInst.emitError (" failed to inline `alloc` region of an `omp.private` "
15361607 " op in the parallel region" );
15371608 bodyGenStatus = failure ();
1538- privatizerClone .erase ();
1609+ mlirPrivatizerClone .erase ();
15391610 } else {
15401611 assert (yieldedValues.size () == 1 );
1541- replacementValue = yieldedValues.front ();
1612+ llvmReplacementValue = yieldedValues.front ();
15421613
15431614 // Keep the LLVM replacement value and the op clone in case we need to
15441615 // emit cleanup (i.e. deallocation) logic.
1545- privateVariables .push_back (replacementValue );
1546- privatizerClones .push_back (privatizerClone );
1616+ llvmPrivateVars .push_back (llvmReplacementValue );
1617+ mlirPrivatizerClones .push_back (mlirPrivatizerClone );
15471618 }
15481619
15491620 builder.restoreIP (oldIP);
@@ -1571,13 +1642,14 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
15711642 bodyGenStatus = failure ();
15721643
15731644 SmallVector<Region *> privateCleanupRegions;
1574- llvm::transform (privatizerClones, std::back_inserter (privateCleanupRegions),
1645+ llvm::transform (mlirPrivatizerClones,
1646+ std::back_inserter (privateCleanupRegions),
15751647 [](omp::PrivateClauseOp privatizer) {
15761648 return &privatizer.getDeallocRegion ();
15771649 });
15781650
15791651 if (failed (inlineOmpRegionCleanup (
1580- privateCleanupRegions, privateVariables , moduleTranslation, builder,
1652+ privateCleanupRegions, llvmPrivateVars , moduleTranslation, builder,
15811653 " omp.private.dealloc" , /* shouldLoadCleanupRegionArg=*/ false )))
15821654 bodyGenStatus = failure ();
15831655
@@ -1604,7 +1676,7 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
16041676 ompBuilder->createParallel (ompLoc, allocaIP, bodyGenCB, privCB, finiCB,
16051677 ifCond, numThreads, pbKind, isCancellable));
16061678
1607- for (mlir::omp::PrivateClauseOp privatizerClone : privatizerClones )
1679+ for (mlir::omp::PrivateClauseOp privatizerClone : mlirPrivatizerClones )
16081680 privatizerClone.erase ();
16091681
16101682 return bodyGenStatus;
0 commit comments