-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[OpenMP 6.0 ]Codegen for Reduction over private variables with reduction clause #134709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
a05af19
4e6eea6
18e1708
59ab4be
e45c30a
980bc06
a103dfa
526314c
c77fb0e
f202eaa
9d2370b
0ca2f86
9335af1
e1a1998
efd69bb
c01671e
ad0d2f0
4df2910
2468be3
9576c87
7e324bd
262a861
a0d29ab
0c2978c
384cd4a
76db75a
0b59740
694e241
4c36ba7
b146a1a
3bb17c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4899,6 +4899,151 @@ void CGOpenMPRuntime::emitSingleReductionCombiner(CodeGenFunction &CGF, | |
} | ||
} | ||
|
||
void CGOpenMPRuntime::emitPrivateReduction( | ||
CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> Privates, | ||
ArrayRef<const Expr *> LHSExprs, ArrayRef<const Expr *> RHSExprs, | ||
ArrayRef<const Expr *> ReductionOps) { | ||
|
||
if (LHSExprs.empty() || Privates.empty() || ReductionOps.empty()) | ||
return; | ||
|
||
if (LHSExprs.size() != Privates.size() || | ||
LHSExprs.size() != ReductionOps.size()) | ||
return; | ||
|
||
QualType PrivateType = Privates[0]->getType(); | ||
llvm::Type *LLVMType = CGF.ConvertTypeForMem(PrivateType); | ||
|
||
BinaryOperatorKind MainBO = BO_Comma; | ||
if (const auto *BinOp = dyn_cast<BinaryOperator>(ReductionOps[0])) { | ||
if (const auto *RHSExpr = BinOp->getRHS()) { | ||
if (const auto *BORHS = | ||
dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) { | ||
MainBO = BORHS->getOpcode(); | ||
} | ||
} | ||
} | ||
|
||
llvm::Constant *InitVal = llvm::Constant::getNullValue(LLVMType); | ||
const Expr *Private = Privates[0]; | ||
|
||
if (const auto *DRE = dyn_cast<DeclRefExpr>(Private)) { | ||
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { | ||
if (const Expr *Init = VD->getInit()) { | ||
if (Init->isConstantInitializer(CGF.getContext(), false)) { | ||
Expr::EvalResult Result; | ||
if (Init->EvaluateAsRValue(Result, CGF.getContext())) { | ||
APValue &InitValue = Result.Val; | ||
if (InitValue.isInt()) { | ||
InitVal = llvm::ConstantInt::get(LLVMType, InitValue.getInt()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Create an internal shared variable | ||
std::string SharedName = getName({"internal_private_var"}); | ||
llvm::GlobalVariable *SharedVar = new llvm::GlobalVariable( | ||
CGM.getModule(), LLVMType, false, llvm::GlobalValue::CommonLinkage, | ||
InitVal, ".omp.reduction." + SharedName, nullptr, | ||
llvm::GlobalVariable::NotThreadLocal); | ||
|
||
SharedVar->setAlignment( | ||
llvm::MaybeAlign(CGF.getContext().getTypeAlign(PrivateType) / 8)); | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Address SharedResult(SharedVar, SharedVar->getValueType(), | ||
CGF.getContext().getTypeAlignInChars(PrivateType)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use CGF.MakeNaturalAlignRawAddrLValue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done !! |
||
|
||
llvm::Value *ThreadId = getThreadID(CGF, Loc); | ||
llvm::Value *BarrierLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE); | ||
llvm::Value *BarrierArgs[] = {BarrierLoc, ThreadId}; | ||
|
||
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( | ||
CGM.getModule(), OMPRTL___kmpc_barrier), | ||
BarrierArgs); | ||
|
||
llvm::BasicBlock *InitBB = CGF.createBasicBlock("init"); | ||
llvm::BasicBlock *InitEndBB = CGF.createBasicBlock("init.end"); | ||
|
||
llvm::Value *IsWorker = CGF.Builder.CreateICmpEQ( | ||
ThreadId, llvm::ConstantInt::get(ThreadId->getType(), 0)); | ||
CGF.Builder.CreateCondBr(IsWorker, InitBB, InitEndBB); | ||
|
||
CGF.EmitBlock(InitBB); | ||
CGF.Builder.CreateStore(InitVal, SharedResult); | ||
CGF.Builder.CreateBr(InitEndBB); | ||
|
||
CGF.EmitBlock(InitEndBB); | ||
|
||
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( | ||
CGM.getModule(), OMPRTL___kmpc_barrier), | ||
BarrierArgs); | ||
|
||
for (unsigned I : | ||
llvm::seq<unsigned>(std::min(ReductionOps.size(), LHSExprs.size()))) { | ||
if (I >= LHSExprs.size()) { | ||
break; | ||
} | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const auto *BinOp = dyn_cast<BinaryOperator>(ReductionOps[I]); | ||
if (!BinOp || BinOp->getOpcode() != BO_Assign) | ||
continue; | ||
|
||
const Expr *RHSExpr = BinOp->getRHS(); | ||
if (!RHSExpr) | ||
continue; | ||
|
||
BinaryOperatorKind BO = BO_Comma; | ||
if (const auto *BORHS = | ||
dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) { | ||
BO = BORHS->getOpcode(); | ||
} | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType); | ||
LValue LHSLV = CGF.EmitLValue(LHSExprs[I]); | ||
RValue PrivateRV = CGF.EmitLoadOfLValue(LHSLV, Loc); | ||
auto UpdateOp = [&](RValue OldVal) { | ||
if (BO == BO_Mul) { | ||
llvm::Value *OldScalar = OldVal.getScalarVal(); | ||
llvm::Value *PrivateScalar = PrivateRV.getScalarVal(); | ||
llvm::Value *Result = CGF.Builder.CreateMul(OldScalar, PrivateScalar); | ||
return RValue::get(Result); | ||
} else { | ||
OpaqueValueExpr OVE(BinOp->getLHS()->getExprLoc(), | ||
BinOp->getLHS()->getType(), | ||
ExprValueKind::VK_PRValue); | ||
CodeGenFunction::OpaqueValueMapping OldValMapping(CGF, &OVE, OldVal); | ||
return CGF.EmitAnyExpr(BinOp->getRHS()); | ||
} | ||
}; | ||
|
||
(void)CGF.EmitOMPAtomicSimpleUpdateExpr( | ||
SharedLV, PrivateRV, BO, true, | ||
llvm::AtomicOrdering::SequentiallyConsistent, Loc, UpdateOp); | ||
} | ||
|
||
// Final barrier | ||
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( | ||
CGM.getModule(), OMPRTL___kmpc_barrier), | ||
BarrierArgs); | ||
|
||
// Broadcast final result | ||
llvm::Value *FinalResult = CGF.Builder.CreateLoad(SharedResult); | ||
|
||
// Update private variables with final result | ||
for (unsigned I : llvm::seq<unsigned>(Privates.size())) { | ||
LValue LHSLV = CGF.EmitLValue(LHSExprs[I]); | ||
CGF.Builder.CreateStore(FinalResult, LHSLV.getAddress()); | ||
} | ||
|
||
// Final synchronization | ||
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( | ||
CGM.getModule(), OMPRTL___kmpc_barrier), | ||
BarrierArgs); | ||
} | ||
|
||
void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, | ||
ArrayRef<const Expr *> Privates, | ||
ArrayRef<const Expr *> LHSExprs, | ||
|
@@ -5201,6 +5346,8 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, | |
|
||
CGF.EmitBranch(DefaultBB); | ||
CGF.EmitBlock(DefaultBB, /*IsFinished=*/true); | ||
if (Options.IsPrivateVarReduction) | ||
emitPrivateReduction(CGF, Loc, Privates, LHSExprs, RHSExprs, ReductionOps); | ||
} | ||
|
||
/// Generates unique name for artificial threadprivate variables. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1470,6 +1470,7 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( | |
llvm::SmallVector<const Expr *, 8> LHSExprs; | ||
llvm::SmallVector<const Expr *, 8> RHSExprs; | ||
llvm::SmallVector<const Expr *, 8> ReductionOps; | ||
llvm::SmallVector<bool, 8> IsPrivate; | ||
bool HasAtLeastOneReduction = false; | ||
bool IsReductionWithTaskMod = false; | ||
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) { | ||
|
@@ -1480,6 +1481,8 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( | |
Privates.append(C->privates().begin(), C->privates().end()); | ||
LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end()); | ||
RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end()); | ||
IsPrivate.append(C->private_var_reduction_flags().begin(), | ||
C->private_var_reduction_flags().end()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if there is a mix of private and non-private reductions in a single construct? IsPrivateVarReduction flag is set for all reduced value, not matter if they are private or not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing, I have fixed it now. Mix of private of non-private reduction is now correctly populating. |
||
ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end()); | ||
IsReductionWithTaskMod = | ||
IsReductionWithTaskMod || C->getModifier() == OMPC_REDUCTION_task; | ||
|
@@ -1499,9 +1502,11 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( | |
bool SimpleReduction = ReductionKind == OMPD_simd; | ||
// Emit nowait reduction if nowait clause is present or directive is a | ||
// parallel directive (it always has implicit barrier). | ||
bool IsPrivateVarReduction = | ||
llvm::any_of(IsPrivate, [](bool IsPriv) { return IsPriv; }); | ||
CGM.getOpenMPRuntime().emitReduction( | ||
*this, D.getEndLoc(), Privates, LHSExprs, RHSExprs, ReductionOps, | ||
{WithNowait, SimpleReduction, ReductionKind}); | ||
{WithNowait, SimpleReduction, IsPrivateVarReduction, ReductionKind}); | ||
} | ||
} | ||
|
||
|
@@ -3943,7 +3948,8 @@ static void emitScanBasedDirective( | |
PrivScope.Privatize(); | ||
CGF.CGM.getOpenMPRuntime().emitReduction( | ||
CGF, S.getEndLoc(), Privates, LHSs, RHSs, ReductionOps, | ||
{/*WithNowait=*/true, /*SimpleReduction=*/true, OMPD_unknown}); | ||
{/*WithNowait=*/true, /*SimpleReduction=*/true, | ||
/*IsPrivateVarReduction */ false, OMPD_unknown}); | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
llvm::Value *NextIVal = | ||
CGF.Builder.CreateNUWSub(IVal, llvm::ConstantInt::get(CGF.SizeTy, 1)); | ||
|
@@ -5747,7 +5753,7 @@ void CodeGenFunction::EmitOMPScanDirective(const OMPScanDirective &S) { | |
} | ||
CGM.getOpenMPRuntime().emitReduction( | ||
*this, ParentDir.getEndLoc(), Privates, LHSs, RHSs, ReductionOps, | ||
{/*WithNowait=*/true, /*SimpleReduction=*/true, OMPD_simd}); | ||
{/*WithNowait=*/true, /*SimpleReduction=*/true, false, OMPD_simd}); | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) { | ||
const Expr *PrivateExpr = Privates[I]; | ||
LValue DestLVal; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.