@@ -690,14 +690,14 @@ inlineOmpRegionCleanup(llvm::SmallVectorImpl<Region *> &cleanupRegions,
690
690
: &builder.GetInsertBlock ()->back ();
691
691
if (potentialTerminator && potentialTerminator->isTerminator ())
692
692
builder.SetInsertPoint (potentialTerminator);
693
- llvm::Value *prviateVarValue =
693
+ llvm::Value *privateVarValue =
694
694
shouldLoadCleanupRegionArg
695
695
? builder.CreateLoad (
696
696
moduleTranslation.convertType (entry.getArgument (0 ).getType ()),
697
697
privateVariables[i])
698
698
: privateVariables[i];
699
699
700
- moduleTranslation.mapValue (entry.getArgument (0 ), prviateVarValue );
700
+ moduleTranslation.mapValue (entry.getArgument (0 ), privateVarValue );
701
701
702
702
if (failed (inlineConvertOmpRegions (*cleanupRegion, regionName, builder,
703
703
moduleTranslation)))
@@ -1424,35 +1424,107 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
1424
1424
}
1425
1425
};
1426
1426
1427
- SmallVector<omp::PrivateClauseOp> privatizerClones ;
1428
- SmallVector<llvm::Value *> privateVariables ;
1427
+ SmallVector<omp::PrivateClauseOp> mlirPrivatizerClones ;
1428
+ SmallVector<llvm::Value *> llvmPrivateVars ;
1429
1429
1430
1430
// TODO: Perform appropriate actions according to the data-sharing
1431
1431
// attribute (shared, private, firstprivate, ...) of variables.
1432
1432
// Currently shared and private are supported.
1433
1433
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 &llvmOmpRegionInputPtr ,
1435
+ llvm::Value *&llvmReplacementValue ) -> InsertPointTy {
1436
+ llvmReplacementValue = &llvmOmpRegionInputPtr ;
1437
1437
1438
1438
// If this is a private value, this lambda will return the corresponding
1439
1439
// mlir value and its `PrivateClauseOp`. Otherwise, empty values are
1440
1440
// returned.
1441
- auto [privVar, privatizerClone ] =
1441
+ auto [mlirPrivVar, mlirPrivatizerClone ] =
1442
1442
[&]() -> std::pair<mlir::Value, omp::PrivateClauseOp> {
1443
1443
if (!opInst.getPrivateVars ().empty ()) {
1444
- auto privateVars = opInst.getPrivateVars ();
1445
- auto privateSyms = opInst.getPrivateSyms ();
1444
+ auto mlirPrivVars = opInst.getPrivateVars ();
1445
+ auto mlirPrivSyms = opInst.getPrivateSyms ();
1446
1446
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
+ // prvatized.
1449
+ for (auto [mlirPrivVar, mlirPrivatizerAttr] :
1450
+ llvm::zip_equal (mlirPrivVars, *mlirPrivSyms)) {
1449
1451
// Find the MLIR private variable corresponding to the LLVM value
1450
1452
// 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 == &llvmOmpRegionInputPtr)
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
+ // Initialized this value (outside the omp region) will be something
1477
+ // 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 the store into and load from the same mem ref.
1505
+ auto *llvmOmpRegionInputPtrLoad =
1506
+ llvm::dyn_cast_if_present<llvm::LoadInst>(
1507
+ &llvmOmpRegionInputPtr);
1508
+
1509
+ if (llvmOmpRegionInputPtrLoad == nullptr )
1510
+ return false ;
1511
+
1512
+ for (auto &use : mlirToLLVMPrivVar->uses ()) {
1513
+ auto *mlirToLLVMPrivVarStore =
1514
+ llvm::dyn_cast_if_present<llvm::StoreInst>(use.getUser ());
1515
+ if (mlirToLLVMPrivVarStore &&
1516
+ (llvmOmpRegionInputPtrLoad->getPointerOperand () ==
1517
+ mlirToLLVMPrivVarStore->getPointerOperand ()))
1518
+ return true ;
1519
+ }
1520
+
1521
+ return false ;
1522
+ };
1523
+
1524
+ if (!isMatch ())
1453
1525
continue ;
1454
1526
1455
- SymbolRefAttr privSym = llvm::cast<SymbolRefAttr>(privatizerAttr );
1527
+ SymbolRefAttr privSym = llvm::cast<SymbolRefAttr>(mlirPrivatizerAttr );
1456
1528
omp::PrivateClauseOp privatizer =
1457
1529
SymbolTable::lookupNearestSymbolFrom<omp::PrivateClauseOp>(
1458
1530
opInst, privSym);
@@ -1480,24 +1552,24 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
1480
1552
counter);
1481
1553
1482
1554
clone.setSymName (cloneName);
1483
- return {privVar , clone};
1555
+ return {mlirPrivVar , clone};
1484
1556
}
1485
1557
}
1486
1558
1487
1559
return {mlir::Value (), omp::PrivateClauseOp ()};
1488
1560
}();
1489
1561
1490
- if (privVar ) {
1491
- Region &allocRegion = privatizerClone .getAllocRegion ();
1562
+ if (mlirPrivVar ) {
1563
+ Region &allocRegion = mlirPrivatizerClone .getAllocRegion ();
1492
1564
1493
1565
// If this is a `firstprivate` clause, prepare the `omp.private` op by:
1494
- if (privatizerClone .getDataSharingType () ==
1566
+ if (mlirPrivatizerClone .getDataSharingType () ==
1495
1567
omp::DataSharingClauseType::FirstPrivate) {
1496
1568
auto oldAllocBackBlock = std::prev (allocRegion.end ());
1497
1569
omp::YieldOp oldAllocYieldOp =
1498
1570
llvm::cast<omp::YieldOp>(oldAllocBackBlock->getTerminator ());
1499
1571
1500
- Region ©Region = privatizerClone .getCopyRegion ();
1572
+ Region ©Region = mlirPrivatizerClone .getCopyRegion ();
1501
1573
1502
1574
mlir::IRRewriter copyCloneBuilder (&moduleTranslation.getContext ());
1503
1575
// 1. Cloning the `copy` region to the end of the `alloc` region.
@@ -1524,7 +1596,7 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
1524
1596
// This way, the body of the privatizer will be changed from using the
1525
1597
// region/block argument to the value being privatized.
1526
1598
auto allocRegionArg = allocRegion.getArgument (0 );
1527
- replaceAllUsesInRegionWith (allocRegionArg, privVar , allocRegion);
1599
+ replaceAllUsesInRegionWith (allocRegionArg, mlirPrivVar , allocRegion);
1528
1600
1529
1601
auto oldIP = builder.saveIP ();
1530
1602
builder.restoreIP (allocaIP);
@@ -1535,15 +1607,15 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
1535
1607
opInst.emitError (" failed to inline `alloc` region of an `omp.private` "
1536
1608
" op in the parallel region" );
1537
1609
bodyGenStatus = failure ();
1538
- privatizerClone .erase ();
1610
+ mlirPrivatizerClone .erase ();
1539
1611
} else {
1540
1612
assert (yieldedValues.size () == 1 );
1541
- replacementValue = yieldedValues.front ();
1613
+ llvmReplacementValue = yieldedValues.front ();
1542
1614
1543
1615
// Keep the LLVM replacement value and the op clone in case we need to
1544
1616
// emit cleanup (i.e. deallocation) logic.
1545
- privateVariables .push_back (replacementValue );
1546
- privatizerClones .push_back (privatizerClone );
1617
+ llvmPrivateVars .push_back (llvmReplacementValue );
1618
+ mlirPrivatizerClones .push_back (mlirPrivatizerClone );
1547
1619
}
1548
1620
1549
1621
builder.restoreIP (oldIP);
@@ -1571,13 +1643,14 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
1571
1643
bodyGenStatus = failure ();
1572
1644
1573
1645
SmallVector<Region *> privateCleanupRegions;
1574
- llvm::transform (privatizerClones, std::back_inserter (privateCleanupRegions),
1646
+ llvm::transform (mlirPrivatizerClones,
1647
+ std::back_inserter (privateCleanupRegions),
1575
1648
[](omp::PrivateClauseOp privatizer) {
1576
1649
return &privatizer.getDeallocRegion ();
1577
1650
});
1578
1651
1579
1652
if (failed (inlineOmpRegionCleanup (
1580
- privateCleanupRegions, privateVariables , moduleTranslation, builder,
1653
+ privateCleanupRegions, llvmPrivateVars , moduleTranslation, builder,
1581
1654
" omp.private.dealloc" , /* shouldLoadCleanupRegionArg=*/ false )))
1582
1655
bodyGenStatus = failure ();
1583
1656
@@ -1604,7 +1677,7 @@ convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
1604
1677
ompBuilder->createParallel (ompLoc, allocaIP, bodyGenCB, privCB, finiCB,
1605
1678
ifCond, numThreads, pbKind, isCancellable));
1606
1679
1607
- for (mlir::omp::PrivateClauseOp privatizerClone : privatizerClones )
1680
+ for (mlir::omp::PrivateClauseOp privatizerClone : mlirPrivatizerClones )
1608
1681
privatizerClone.erase ();
1609
1682
1610
1683
return bodyGenStatus;
0 commit comments