Skip to content

Commit 014a603

Browse files
committed
[OpenACC] Sema changes for +*&|^ reduction combiner recipes
As a followup to the previous AST changes, the next step is to generate the proper expressions in Sema. This patch does so for +,*,&,|,^ by modeling them as compound operators. This also causes the legality of some expressions to change, as these have to be legal operations, but were previously unchecked, so there are some test changes. This does not yet generate any CIR, that will happen in the next patch.
1 parent 82a4277 commit 014a603

17 files changed

+775
-1898
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13662,6 +13662,11 @@ def warn_acc_var_referenced_lacks_op
1366213662
"reference has no effect">,
1366313663
InGroup<DiagGroup<"openacc-var-lacks-operation">>,
1366413664
DefaultError;
13665+
def err_acc_reduction_recipe_no_op
13666+
: Error<"variable of type %0 referenced in OpenACC 'reduction' clause does "
13667+
"not have a valid operation available">;
13668+
def note_acc_reduction_recipe_noop_field
13669+
: Note<"while forming combiner for compound type %0">;
1366513670

1366613671
// AMDGCN builtins diagnostics
1366713672
def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">;

clang/include/clang/Sema/SemaOpenACC.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ class SemaOpenACC : public SemaBase {
228228

229229
bool DiagnoseAllowedClauses(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
230230
SourceLocation ClauseLoc);
231+
bool CreateReductionCombinerRecipe(
232+
SourceLocation loc, OpenACCReductionOperator ReductionOperator,
233+
QualType VarTy,
234+
llvm::SmallVectorImpl<OpenACCReductionRecipe::CombinerRecipe>
235+
&CombinerRecipes);
231236

232237
public:
233238
// Needed from the visitor, so should be public.

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2898,6 +2898,15 @@ OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe(
28982898
dyn_cast<ArraySectionExpr>(VarExpr->IgnoreParenImpCasts()))
28992899
VarTy = ArraySectionExpr::getBaseOriginalType(ASE);
29002900

2901+
llvm::SmallVector<OpenACCReductionRecipe::CombinerRecipe, 1> CombinerRecipes;
2902+
2903+
// We use the 'set-ness' of the alloca-decl to determine whether the combiner
2904+
// is 'set' or not, so we can skip any attempts at it if we're going to fail
2905+
// at any of the combiners.
2906+
if (CreateReductionCombinerRecipe(VarExpr->getBeginLoc(), ReductionOperator,
2907+
VarTy, CombinerRecipes))
2908+
return OpenACCReductionRecipe::Empty();
2909+
29012910
VarDecl *AllocaDecl = CreateAllocaDecl(
29022911
getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
29032912
&getASTContext().Idents.get("openacc.reduction.init"), VarTy);
@@ -2946,5 +2955,161 @@ OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe(
29462955
AllocaDecl->setInit(Init.get());
29472956
AllocaDecl->setInitStyle(VarDecl::CallInit);
29482957
}
2949-
return OpenACCReductionRecipe(AllocaDecl, {});
2958+
2959+
return OpenACCReductionRecipe(AllocaDecl, CombinerRecipes);
2960+
}
2961+
2962+
bool SemaOpenACC::CreateReductionCombinerRecipe(
2963+
SourceLocation Loc, OpenACCReductionOperator ReductionOperator,
2964+
QualType VarTy,
2965+
llvm::SmallVectorImpl<OpenACCReductionRecipe::CombinerRecipe>
2966+
&CombinerRecipes) {
2967+
// Now we can try to generate the 'combiner' recipe. This is a little
2968+
// complicated in that if the 'VarTy' is an array type, we want to take its
2969+
// element type so we can generate that. Additionally, if this is a struct,
2970+
// we have two options: If there is overloaded operators, we want to take
2971+
// THOSE, else we want to do the individual elements.
2972+
2973+
BinaryOperatorKind BinOp;
2974+
switch (ReductionOperator) {
2975+
case OpenACCReductionOperator::Invalid:
2976+
// This can only happen when there is an error, and since these inits
2977+
// are used for code generation, we can just ignore/not bother doing any
2978+
// initialization here.
2979+
CombinerRecipes.push_back({nullptr, nullptr, nullptr});
2980+
return false;
2981+
case OpenACCReductionOperator::Addition:
2982+
BinOp = BinaryOperatorKind::BO_AddAssign;
2983+
break;
2984+
case OpenACCReductionOperator::Multiplication:
2985+
BinOp = BinaryOperatorKind::BO_MulAssign;
2986+
break;
2987+
case OpenACCReductionOperator::BitwiseAnd:
2988+
BinOp = BinaryOperatorKind::BO_AndAssign;
2989+
break;
2990+
case OpenACCReductionOperator::BitwiseOr:
2991+
BinOp = BinaryOperatorKind::BO_OrAssign;
2992+
break;
2993+
case OpenACCReductionOperator::BitwiseXOr:
2994+
BinOp = BinaryOperatorKind::BO_XorAssign;
2995+
break;
2996+
2997+
case OpenACCReductionOperator::Max:
2998+
case OpenACCReductionOperator::Min:
2999+
case OpenACCReductionOperator::And:
3000+
case OpenACCReductionOperator::Or:
3001+
// We just want a 'NYI' error in the backend, so leave an empty combiner
3002+
// recipe, and claim success.
3003+
CombinerRecipes.push_back({nullptr, nullptr, nullptr});
3004+
return false;
3005+
}
3006+
3007+
// If VarTy is an array type, at the top level only, we want to do our
3008+
// compares/decomp/etc at the element level.
3009+
if (VarTy->isArrayType())
3010+
VarTy = QualType{VarTy->getPointeeOrArrayElementType(), 0};
3011+
3012+
auto tryCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE,
3013+
bool IncludeTrap) {
3014+
// TODO: OpenACC: we have to figure out based on the bin-op how to do the
3015+
// ones that we can't just use compound operators for. So &&, ||, max, and
3016+
// min aren't really clear what we could do here.
3017+
if (IncludeTrap) {
3018+
// Trap all of the errors here, we'll emit our own at the end.
3019+
Sema::TentativeAnalysisScope Trap{SemaRef};
3020+
3021+
return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE,
3022+
RHSDRE,
3023+
/*ForFoldExpr=*/false);
3024+
} else {
3025+
return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE,
3026+
RHSDRE,
3027+
/*ForFoldExpr=*/false);
3028+
}
3029+
};
3030+
3031+
struct CombinerAttemptTy {
3032+
VarDecl *LHS;
3033+
DeclRefExpr *LHSDRE;
3034+
VarDecl *RHS;
3035+
DeclRefExpr *RHSDRE;
3036+
Expr *Op;
3037+
};
3038+
3039+
auto formCombiner = [&, this](QualType Ty) -> CombinerAttemptTy {
3040+
VarDecl *LHSDecl = CreateAllocaDecl(
3041+
getASTContext(), SemaRef.getCurContext(), Loc,
3042+
&getASTContext().Idents.get("openacc.reduction.combiner.lhs"), Ty);
3043+
auto *LHSDRE = DeclRefExpr::Create(
3044+
getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, LHSDecl,
3045+
/*ReferstoEnclosingVariableOrCapture=*/false,
3046+
DeclarationNameInfo{DeclarationName{LHSDecl->getDeclName()},
3047+
LHSDecl->getBeginLoc()},
3048+
Ty, clang::VK_LValue, LHSDecl, nullptr, NOUR_None);
3049+
VarDecl *RHSDecl = CreateAllocaDecl(
3050+
getASTContext(), SemaRef.getCurContext(), Loc,
3051+
&getASTContext().Idents.get("openacc.reduction.combiner.lhs"), Ty);
3052+
auto *RHSDRE = DeclRefExpr::Create(
3053+
getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, RHSDecl,
3054+
/*ReferstoEnclosingVariableOrCapture=*/false,
3055+
DeclarationNameInfo{DeclarationName{RHSDecl->getDeclName()},
3056+
RHSDecl->getBeginLoc()},
3057+
Ty, clang::VK_LValue, RHSDecl, nullptr, NOUR_None);
3058+
3059+
ExprResult BinOpResult = tryCombiner(LHSDRE, RHSDRE, /*IncludeTrap=*/true);
3060+
3061+
return {LHSDecl, LHSDRE, RHSDecl, RHSDRE, BinOpResult.get()};
3062+
};
3063+
3064+
CombinerAttemptTy TopLevelCombinerInfo = formCombiner(VarTy);
3065+
3066+
if (TopLevelCombinerInfo.Op) {
3067+
if (!TopLevelCombinerInfo.Op->containsErrors() &&
3068+
TopLevelCombinerInfo.Op->isInstantiationDependent()) {
3069+
// If this is instantiation dependent, we're just going to 'give up' here
3070+
// and count on us to get it right during instantaition.
3071+
CombinerRecipes.push_back({nullptr, nullptr, nullptr});
3072+
return false;
3073+
} else if (!TopLevelCombinerInfo.Op->containsErrors()) {
3074+
// Else, we succeeded, we can just return this combiner.
3075+
CombinerRecipes.push_back({TopLevelCombinerInfo.LHS,
3076+
TopLevelCombinerInfo.RHS,
3077+
TopLevelCombinerInfo.Op});
3078+
return false;
3079+
}
3080+
}
3081+
3082+
// Since the 'root' level didn't fail, the only thing that could be successful
3083+
// is a struct that we decompose on its individual fields.
3084+
3085+
RecordDecl *RD = VarTy->getAsRecordDecl();
3086+
if (!RD) {
3087+
Diag(Loc, diag::err_acc_reduction_recipe_no_op) << VarTy;
3088+
tryCombiner(TopLevelCombinerInfo.LHSDRE, TopLevelCombinerInfo.RHSDRE,
3089+
/*IncludeTrap=*/false);
3090+
return true;
3091+
}
3092+
3093+
for (const FieldDecl *FD : RD->fields()) {
3094+
CombinerAttemptTy FieldCombinerInfo = formCombiner(FD->getType());
3095+
3096+
if (!FieldCombinerInfo.Op || FieldCombinerInfo.Op->containsErrors()) {
3097+
Diag(Loc, diag::err_acc_reduction_recipe_no_op) << FD->getType();
3098+
Diag(FD->getBeginLoc(), diag::note_acc_reduction_recipe_noop_field) << RD;
3099+
tryCombiner(FieldCombinerInfo.LHSDRE, FieldCombinerInfo.RHSDRE,
3100+
/*IncludeTrap=*/false);
3101+
return true;
3102+
}
3103+
3104+
if (FieldCombinerInfo.Op->isInstantiationDependent()) {
3105+
// If this is instantiation dependent, we're just going to 'give up' here
3106+
// and count on us to get it right during instantaition.
3107+
CombinerRecipes.push_back({nullptr, nullptr, nullptr});
3108+
} else {
3109+
CombinerRecipes.push_back(
3110+
{FieldCombinerInfo.LHS, FieldCombinerInfo.RHS, FieldCombinerInfo.Op});
3111+
}
3112+
}
3113+
3114+
return false;
29503115
}

clang/lib/Sema/SemaOpenACCClause.cpp

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,30 +1975,26 @@ ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind,
19751975
Diag(Loc, PD);
19761976

19771977
Diag(VarLoc, diag::note_acc_reduction_type_summary);
1978+
return ExprError();
19781979
};
19791980

19801981
// If the type is already scalar, or is dependent, just give up.
19811982
if (IsValidMemberOfComposite(CurType)) {
19821983
// Nothing to do here, is valid.
19831984
} else if (auto *RD = CurType->getAsRecordDecl()) {
1984-
if (!RD->isStruct() && !RD->isClass()) {
1985-
EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
1986-
<< RD << diag::OACCReductionTy::NotClassStruct);
1987-
return ExprError();
1988-
}
1985+
if (!RD->isStruct() && !RD->isClass())
1986+
return EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
1987+
<< RD
1988+
<< diag::OACCReductionTy::NotClassStruct);
19891989

1990-
if (!RD->isCompleteDefinition()) {
1991-
EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
1992-
<< RD << diag::OACCReductionTy::NotComplete);
1993-
return ExprError();
1994-
}
1990+
if (!RD->isCompleteDefinition())
1991+
return EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
1992+
<< RD << diag::OACCReductionTy::NotComplete);
19951993

19961994
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
1997-
CXXRD && !CXXRD->isAggregate()) {
1998-
EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
1999-
<< CXXRD << diag::OACCReductionTy::NotAgg);
2000-
return ExprError();
2001-
}
1995+
CXXRD && !CXXRD->isAggregate())
1996+
return EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
1997+
<< CXXRD << diag::OACCReductionTy::NotAgg);
20021998

20031999
for (FieldDecl *FD : RD->fields()) {
20042000
if (!IsValidMemberOfComposite(FD->getType())) {
@@ -2007,15 +2003,15 @@ ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind,
20072003
<< FD->getName() << RD->getName();
20082004
Notes.push_back({FD->getBeginLoc(), PD});
20092005
// TODO: member here.note_acc_reduction_member_of_composite
2010-
EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
2011-
<< FD->getType()
2012-
<< diag::OACCReductionTy::MemberNotScalar);
2013-
return ExprError();
2006+
return EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
2007+
<< FD->getType()
2008+
<< diag::OACCReductionTy::MemberNotScalar);
20142009
}
20152010
}
20162011
} else {
2017-
EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
2018-
<< CurType << diag::OACCReductionTy::NotScalar);
2012+
return EmitDiags(VarLoc, PDiag(diag::err_acc_reduction_type)
2013+
<< CurType
2014+
<< diag::OACCReductionTy::NotScalar);
20192015
}
20202016

20212017
// OpenACC3.3: 2.9.11: Reduction clauses on nested constructs for the same

0 commit comments

Comments
 (0)