-
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 9 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,238 @@ 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); | ||
|
||
llvm::Constant *InitVal = nullptr; | ||
const OMPDeclareReductionDecl *UDR = getReductionInit(ReductionOps[0]); | ||
|
||
if (!UDR) { | ||
InitVal = llvm::Constant::getNullValue(LLVMType); | ||
if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates[0])) { | ||
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { | ||
const Expr *InitExpr = VD->getInit(); | ||
if (InitExpr && !PrivateType->isAggregateType() && | ||
!PrivateType->isAnyComplexType()) { | ||
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. Complex types should be supported, the compiler should not drop it silently 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 .. Added support for all types. 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. Add at least a runtime test with complex types, if possible 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. Updated runtime test case a complex type test. |
||
Expr::EvalResult Result; | ||
if (InitExpr->EvaluateAsRValue(Result, CGF.getContext())) { | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
APValue &InitValue = Result.Val; | ||
if (InitValue.isInt()) { | ||
InitVal = llvm::ConstantInt::get(LLVMType, InitValue.getInt()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
InitVal = llvm::Constant::getNullValue(LLVMType); | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// 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)); | ||
chandraghale marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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); | ||
|
||
if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates[0])) { | ||
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { | ||
const Expr *InitExpr = VD->getInit(); | ||
if (InitExpr && | ||
(PrivateType->isAggregateType() || PrivateType->isAnyComplexType())) { | ||
CGF.EmitAnyExprToMem(InitExpr, SharedResult, | ||
PrivateType.getQualifiers(), true); | ||
} else if (!InitVal->isNullValue()) { | ||
CGF.EmitStoreOfScalar(InitVal, | ||
CGF.MakeAddrLValue(SharedResult, PrivateType)); | ||
} else { | ||
CGF.EmitNullInitialization(SharedResult, PrivateType); | ||
} | ||
} else { | ||
CGF.EmitNullInitialization(SharedResult, PrivateType); | ||
} | ||
} else { | ||
CGF.EmitNullInitialization(SharedResult, PrivateType); | ||
} | ||
|
||
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()))) { | ||
|
||
const Expr *ReductionOp = ReductionOps[I]; | ||
LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType); | ||
LValue LHSLV = CGF.EmitLValue(LHSExprs[I]); | ||
// If UDR | ||
const OMPDeclareReductionDecl *CurrentUDR = | ||
getReductionInit(ReductionOps[I]); | ||
if (CurrentUDR) { | ||
auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) { | ||
Action.Enter(CGF); | ||
std::pair<llvm::Function *, llvm::Function *> ReductionFnPair = | ||
getUserDefinedReduction(CurrentUDR); | ||
llvm::Function *CombinerFn = ReductionFnPair.first; | ||
if (const auto *CE = dyn_cast<CallExpr>(ReductionOp)) { | ||
if (CE && CombinerFn) { | ||
const auto *CE = cast<CallExpr>(ReductionOps[I]); | ||
const auto *OutDRE = cast<DeclRefExpr>( | ||
cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts()) | ||
->getSubExpr()); | ||
const auto *InDRE = cast<DeclRefExpr>( | ||
cast<UnaryOperator>(CE->getArg(1)->IgnoreParenImpCasts()) | ||
->getSubExpr()); | ||
CodeGenFunction::OMPPrivateScope LocalScope(CGF); | ||
LocalScope.addPrivate(cast<VarDecl>(OutDRE->getDecl()), | ||
SharedLV.getAddress()); | ||
LocalScope.addPrivate(cast<VarDecl>(InDRE->getDecl()), | ||
LHSLV.getAddress()); | ||
(void)LocalScope.Privatize(); | ||
emitReductionCombiner(CGF, ReductionOp); | ||
} | ||
} | ||
}; | ||
std::string CriticalName = getName({"reduction_critical"}); | ||
emitCriticalRegion(CGF, CriticalName, ReductionGen, Loc); | ||
} else { | ||
// Built-in Operator Combination | ||
const Expr *ReductionClauseExpr = ReductionOp->IgnoreParenCasts(); | ||
if (const auto *Cleanup = dyn_cast<ExprWithCleanups>(ReductionClauseExpr)) | ||
ReductionClauseExpr = Cleanup->getSubExpr()->IgnoreParenCasts(); | ||
const Expr *AssignRHS = nullptr; | ||
if (const auto *BinOp = dyn_cast<BinaryOperator>(ReductionClauseExpr)) { | ||
if (BinOp->getOpcode() == BO_Assign) | ||
AssignRHS = BinOp->getRHS(); | ||
} else if (const auto *OpCall = | ||
dyn_cast<CXXOperatorCallExpr>(ReductionClauseExpr)) { | ||
if (OpCall->getOperator() == OO_Equal) | ||
AssignRHS = OpCall->getArg(1); | ||
} | ||
if (!AssignRHS) | ||
continue; | ||
const Expr *ReductionCombinerExpr = AssignRHS->IgnoreParenImpCasts(); | ||
if (const auto *MTE = | ||
dyn_cast<MaterializeTemporaryExpr>(ReductionCombinerExpr)) | ||
ReductionCombinerExpr = MTE->getSubExpr()->IgnoreParenImpCasts(); | ||
|
||
BinaryOperatorKind BO = BO_Assign; | ||
RValue PrivateRV = CGF.EmitLoadOfLValue(LHSLV, Loc); | ||
if (const auto *BinOp = dyn_cast<BinaryOperator>(ReductionCombinerExpr)) { | ||
BO = BinOp->getOpcode(); | ||
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); | ||
} else if (dyn_cast<CXXOperatorCallExpr>(ReductionClauseExpr)) { | ||
// Implicit Reduction Identifiers ( openmp 6.0 sec 7.6.5 ) | ||
auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) { | ||
Action.Enter(CGF); | ||
const auto *OmpOutDRE = | ||
dyn_cast<DeclRefExpr>(LHSExprs[I]->IgnoreParenImpCasts()); | ||
const auto *OmpInDRE = | ||
dyn_cast<DeclRefExpr>(RHSExprs[I]->IgnoreParenImpCasts()); | ||
|
||
if (!OmpOutDRE || !OmpInDRE) { | ||
return; | ||
} | ||
const VarDecl *OmpOutVD = cast<VarDecl>(OmpOutDRE->getDecl()); | ||
const VarDecl *OmpInVD = cast<VarDecl>(OmpInDRE->getDecl()); | ||
CodeGenFunction::OMPPrivateScope LocalScope(CGF); | ||
LocalScope.addPrivate(OmpOutVD, SharedLV.getAddress()); | ||
LocalScope.addPrivate(OmpInVD, LHSLV.getAddress()); | ||
(void)LocalScope.Privatize(); | ||
CGF.EmitIgnoredExpr(ReductionOp); | ||
}; | ||
std::string CriticalName = getName({"reduction_critical"}); | ||
emitCriticalRegion(CGF, CriticalName, ReductionGen, Loc); | ||
} | ||
} | ||
} | ||
// Final barrier | ||
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( | ||
CGM.getModule(), OMPRTL___kmpc_barrier), | ||
BarrierArgs); | ||
|
||
// Broadcast final result | ||
bool IsAggregate = PrivateType->isAggregateType(); | ||
llvm::Value *FinalResultVal = nullptr; | ||
LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType); | ||
Address FinalResultAddr = Address::invalid(); | ||
if (IsAggregate) { | ||
FinalResultAddr = SharedResult; | ||
} else { | ||
FinalResultVal = CGF.EmitLoadOfScalar(SharedLV, Loc); | ||
} | ||
|
||
for (unsigned I : llvm::seq<unsigned>(Privates.size())) { | ||
LValue TargetLHSLV = CGF.EmitLValue(LHSExprs[I]); | ||
if (IsAggregate) { | ||
CGF.EmitAggregateCopy(TargetLHSLV, | ||
CGF.MakeAddrLValue(FinalResultAddr, PrivateType), | ||
PrivateType, AggValueSlot::DoesNotOverlap, false); | ||
} else { | ||
CGF.EmitStoreOfScalar(FinalResultVal, TargetLHSLV); | ||
} | ||
} | ||
|
||
// 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 +5433,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. | ||
|
Uh oh!
There was an error while loading. Please reload this page.