@@ -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}
0 commit comments