Skip to content

Commit 9fbd5f4

Browse files
committed
Reapply "[OpenACC] Sema changes for +*&|^ reduction combiner recipes (… (#162920)
This reverts commit 8d9aecc. Additionally, this refactors how we're doing the AST storage to put it all in the trailing storage, which will hopefully prevent it from leaking.
1 parent 92e6fa8 commit 9fbd5f4

16 files changed

+759
-1876
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

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

1366913674
// AMDGCN builtins diagnostics
1367013675
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: 168 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 = ASE->getElementType();
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,163 @@ 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 (auto *AT = getASTContext().getAsArrayType(VarTy))
3010+
VarTy = AT->getElementType();
3011+
3012+
assert(!VarTy->isArrayType() && "Only 1 level of array allowed");
3013+
3014+
auto tryCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE,
3015+
bool IncludeTrap) {
3016+
// TODO: OpenACC: we have to figure out based on the bin-op how to do the
3017+
// ones that we can't just use compound operators for. So &&, ||, max, and
3018+
// min aren't really clear what we could do here.
3019+
if (IncludeTrap) {
3020+
// Trap all of the errors here, we'll emit our own at the end.
3021+
Sema::TentativeAnalysisScope Trap{SemaRef};
3022+
3023+
return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE,
3024+
RHSDRE,
3025+
/*ForFoldExpr=*/false);
3026+
} else {
3027+
return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE,
3028+
RHSDRE,
3029+
/*ForFoldExpr=*/false);
3030+
}
3031+
};
3032+
3033+
struct CombinerAttemptTy {
3034+
VarDecl *LHS;
3035+
DeclRefExpr *LHSDRE;
3036+
VarDecl *RHS;
3037+
DeclRefExpr *RHSDRE;
3038+
Expr *Op;
3039+
};
3040+
3041+
auto formCombiner = [&, this](QualType Ty) -> CombinerAttemptTy {
3042+
VarDecl *LHSDecl = CreateAllocaDecl(
3043+
getASTContext(), SemaRef.getCurContext(), Loc,
3044+
&getASTContext().Idents.get("openacc.reduction.combiner.lhs"), Ty);
3045+
auto *LHSDRE = DeclRefExpr::Create(
3046+
getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, LHSDecl,
3047+
/*ReferstoEnclosingVariableOrCapture=*/false,
3048+
DeclarationNameInfo{DeclarationName{LHSDecl->getDeclName()},
3049+
LHSDecl->getBeginLoc()},
3050+
Ty, clang::VK_LValue, LHSDecl, nullptr, NOUR_None);
3051+
VarDecl *RHSDecl = CreateAllocaDecl(
3052+
getASTContext(), SemaRef.getCurContext(), Loc,
3053+
&getASTContext().Idents.get("openacc.reduction.combiner.lhs"), Ty);
3054+
auto *RHSDRE = DeclRefExpr::Create(
3055+
getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, RHSDecl,
3056+
/*ReferstoEnclosingVariableOrCapture=*/false,
3057+
DeclarationNameInfo{DeclarationName{RHSDecl->getDeclName()},
3058+
RHSDecl->getBeginLoc()},
3059+
Ty, clang::VK_LValue, RHSDecl, nullptr, NOUR_None);
3060+
3061+
ExprResult BinOpResult = tryCombiner(LHSDRE, RHSDRE, /*IncludeTrap=*/true);
3062+
3063+
return {LHSDecl, LHSDRE, RHSDecl, RHSDRE, BinOpResult.get()};
3064+
};
3065+
3066+
CombinerAttemptTy TopLevelCombinerInfo = formCombiner(VarTy);
3067+
3068+
if (TopLevelCombinerInfo.Op) {
3069+
if (!TopLevelCombinerInfo.Op->containsErrors() &&
3070+
TopLevelCombinerInfo.Op->isInstantiationDependent()) {
3071+
// If this is instantiation dependent, we're just going to 'give up' here
3072+
// and count on us to get it right during instantaition.
3073+
CombinerRecipes.push_back({nullptr, nullptr, nullptr});
3074+
return false;
3075+
} else if (!TopLevelCombinerInfo.Op->containsErrors()) {
3076+
// Else, we succeeded, we can just return this combiner.
3077+
CombinerRecipes.push_back({TopLevelCombinerInfo.LHS,
3078+
TopLevelCombinerInfo.RHS,
3079+
TopLevelCombinerInfo.Op});
3080+
return false;
3081+
}
3082+
}
3083+
3084+
// Since the 'root' level didn't fail, the only thing that could be successful
3085+
// is a struct that we decompose on its individual fields.
3086+
3087+
RecordDecl *RD = VarTy->getAsRecordDecl();
3088+
if (!RD) {
3089+
Diag(Loc, diag::err_acc_reduction_recipe_no_op) << VarTy;
3090+
tryCombiner(TopLevelCombinerInfo.LHSDRE, TopLevelCombinerInfo.RHSDRE,
3091+
/*IncludeTrap=*/false);
3092+
return true;
3093+
}
3094+
3095+
for (const FieldDecl *FD : RD->fields()) {
3096+
CombinerAttemptTy FieldCombinerInfo = formCombiner(FD->getType());
3097+
3098+
if (!FieldCombinerInfo.Op || FieldCombinerInfo.Op->containsErrors()) {
3099+
Diag(Loc, diag::err_acc_reduction_recipe_no_op) << FD->getType();
3100+
Diag(FD->getBeginLoc(), diag::note_acc_reduction_recipe_noop_field) << RD;
3101+
tryCombiner(FieldCombinerInfo.LHSDRE, FieldCombinerInfo.RHSDRE,
3102+
/*IncludeTrap=*/false);
3103+
return true;
3104+
}
3105+
3106+
if (FieldCombinerInfo.Op->isInstantiationDependent()) {
3107+
// If this is instantiation dependent, we're just going to 'give up' here
3108+
// and count on us to get it right during instantaition.
3109+
CombinerRecipes.push_back({nullptr, nullptr, nullptr});
3110+
} else {
3111+
CombinerRecipes.push_back(
3112+
{FieldCombinerInfo.LHS, FieldCombinerInfo.RHS, FieldCombinerInfo.Op});
3113+
}
3114+
}
3115+
3116+
return false;
29503117
}

0 commit comments

Comments
 (0)