Skip to content

Commit 6010df0

Browse files
authored
[OpenACC] Sema changes for +*&|^ reduction combiner recipes (#162740)
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 6fb87b2 commit 6010df0

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)