232 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Emit OpenACC clause recipes as CIR code.10//11//===----------------------------------------------------------------------===//12 13#include "CIRGenCXXABI.h"14#include "CIRGenFunction.h"15 16#include "clang/AST/ASTContext.h"17#include "clang/AST/DeclBase.h"18#include "clang/AST/Expr.h"19#include "clang/AST/ExprCXX.h"20#include "clang/AST/TypeBase.h"21#include "clang/Basic/OpenACCKinds.h"22 23#include "mlir/Dialect/OpenACC/OpenACC.h"24 25namespace clang::CIRGen {26class OpenACCRecipeBuilderBase {27 // makes the copy of the addresses of an alloca to the previous allocation.28 void makeAllocaCopy(mlir::Location loc, mlir::Type copyType,29 mlir::Value numEltsToCopy, mlir::Value offsetPerSubarray,30 mlir::Value destAlloca, mlir::Value srcAlloca);31 // This function generates the required alloca, similar to32 // 'emitAutoVarAlloca', except for the OpenACC array/pointer types.33 mlir::Value makeBoundsAlloca(mlir::Block *block, SourceRange exprRange,34 mlir::Location loc, std::string_view allocaName,35 size_t numBounds,36 llvm::ArrayRef<QualType> boundTypes);37 38 void makeBoundsInit(mlir::Value alloca, mlir::Location loc,39 mlir::Block *block, const VarDecl *allocaDecl,40 QualType origType, bool isInitSection);41 42protected:43 CIRGen::CIRGenFunction &cgf;44 CIRGen::CIRGenBuilderTy &builder;45 46 mlir::Block *createRecipeBlock(mlir::Region ®ion, mlir::Type opTy,47 mlir::Location loc, size_t numBounds,48 bool isInit);49 // Creates a loop through an 'acc.bounds', leaving the 'insertion' point to be50 // the inside of the loop body. Traverses LB->UB UNLESS `inverse` is set.51 // Returns the 'subscriptedValue' changed with the new bounds subscript.52 std::pair<mlir::Value, mlir::Value>53 createBoundsLoop(mlir::Value subscriptedValue, mlir::Value subscriptedValue2,54 mlir::Value bound, mlir::Location loc, bool inverse);55 56 mlir::Value createBoundsLoop(mlir::Value subscriptedValue, mlir::Value bound,57 mlir::Location loc, bool inverse) {58 return createBoundsLoop(subscriptedValue, {}, bound, loc, inverse).first;59 }60 61 mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op);62 63 // This function generates the 'combiner' section for a reduction recipe. Note64 // that this function is not 'insertion point' clean, in that it alters the65 // insertion point to be inside of the 'combiner' section of the recipe, but66 // doesn't restore it aftewards.67 void createReductionRecipeCombiner(68 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,69 mlir::acc::ReductionRecipeOp recipe, size_t numBounds, QualType origType,70 llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe> combinerRecipes);71 72 void createInitRecipe(mlir::Location loc, mlir::Location locEnd,73 SourceRange exprRange, mlir::Value mainOp,74 mlir::Region &recipeInitRegion, size_t numBounds,75 llvm::ArrayRef<QualType> boundTypes,76 const VarDecl *allocaDecl, QualType origType,77 bool emitInitExpr);78 79 void createFirstprivateRecipeCopy(mlir::Location loc, mlir::Location locEnd,80 mlir::Value mainOp,81 const VarDecl *allocaDecl,82 const VarDecl *temporary,83 mlir::Region ©Region, size_t numBounds);84 85 void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,86 mlir::Value mainOp, CharUnits alignment,87 QualType origType, size_t numBounds,88 QualType baseType,89 mlir::Region &destroyRegion);90 91 OpenACCRecipeBuilderBase(CIRGen::CIRGenFunction &cgf,92 CIRGen::CIRGenBuilderTy &builder)93 : cgf(cgf), builder(builder) {}94};95 96template <typename RecipeTy>97class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {98 std::string getRecipeName(SourceRange loc, QualType baseType,99 unsigned numBounds,100 OpenACCReductionOperator reductionOp) {101 std::string recipeName;102 {103 llvm::raw_string_ostream stream(recipeName);104 105 if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {106 stream << "privatization_";107 } else if constexpr (std::is_same_v<RecipeTy,108 mlir::acc::FirstprivateRecipeOp>) {109 stream << "firstprivatization_";110 111 } else if constexpr (std::is_same_v<RecipeTy,112 mlir::acc::ReductionRecipeOp>) {113 stream << "reduction_";114 // Values here are a little weird (for bitwise and/or is 'i' prefix, and115 // logical ops with 'l'), but are chosen to be the same as the MLIR116 // dialect names as well as to match the Flang versions of these.117 switch (reductionOp) {118 case OpenACCReductionOperator::Addition:119 stream << "add_";120 break;121 case OpenACCReductionOperator::Multiplication:122 stream << "mul_";123 break;124 case OpenACCReductionOperator::Max:125 stream << "max_";126 break;127 case OpenACCReductionOperator::Min:128 stream << "min_";129 break;130 case OpenACCReductionOperator::BitwiseAnd:131 stream << "iand_";132 break;133 case OpenACCReductionOperator::BitwiseOr:134 stream << "ior_";135 break;136 case OpenACCReductionOperator::BitwiseXOr:137 stream << "xor_";138 break;139 case OpenACCReductionOperator::And:140 stream << "land_";141 break;142 case OpenACCReductionOperator::Or:143 stream << "lor_";144 break;145 case OpenACCReductionOperator::Invalid:146 llvm_unreachable("invalid reduction operator");147 }148 } else {149 static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind");150 }151 152 // The naming convention from Flang with bounds doesn't map to C++ types153 // very well, so we're just going to choose our own here.154 if (numBounds)155 stream << "_Bcnt" << numBounds << '_';156 157 MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext();158 mc.mangleCanonicalTypeName(baseType, stream);159 }160 return recipeName;161 }162 163public:164 OpenACCRecipeBuilder(CIRGen::CIRGenFunction &cgf,165 CIRGen::CIRGenBuilderTy &builder)166 : OpenACCRecipeBuilderBase(cgf, builder) {}167 RecipeTy getOrCreateRecipe(168 ASTContext &astCtx, mlir::OpBuilder::InsertPoint &insertLocation,169 const Expr *varRef, const VarDecl *varRecipe, const VarDecl *temporary,170 OpenACCReductionOperator reductionOp, DeclContext *dc, QualType origType,171 size_t numBounds, llvm::ArrayRef<QualType> boundTypes, QualType baseType,172 mlir::Value mainOp,173 llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe>174 reductionCombinerRecipes) {175 assert(!varRecipe->getType()->isSpecificBuiltinType(176 BuiltinType::ArraySection) &&177 "array section shouldn't make it to recipe creation");178 179 mlir::ModuleOp mod = builder.getBlock()180 ->getParent()181 ->template getParentOfType<mlir::ModuleOp>();182 183 std::string recipeName = getRecipeName(varRef->getSourceRange(), baseType,184 numBounds, reductionOp);185 if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName))186 return recipe;187 188 mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc());189 mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc());190 191 mlir::OpBuilder modBuilder(mod.getBodyRegion());192 if (insertLocation.isSet())193 modBuilder.restoreInsertionPoint(insertLocation);194 RecipeTy recipe;195 196 if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {197 recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType(),198 convertReductionOp(reductionOp));199 } else {200 recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType());201 }202 insertLocation = modBuilder.saveInsertionPoint();203 204 if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {205 createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,206 recipe.getInitRegion(), numBounds, boundTypes, varRecipe,207 origType, /*emitInitExpr=*/true);208 } else if constexpr (std::is_same_v<RecipeTy,209 mlir::acc::ReductionRecipeOp>) {210 createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,211 recipe.getInitRegion(), numBounds, boundTypes, varRecipe,212 origType, /*emitInitExpr=*/true);213 createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds,214 origType, reductionCombinerRecipes);215 } else {216 static_assert(std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>);217 createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,218 recipe.getInitRegion(), numBounds, boundTypes, varRecipe,219 origType, /*emitInitExpr=*/false);220 createFirstprivateRecipeCopy(loc, locEnd, mainOp, varRecipe, temporary,221 recipe.getCopyRegion(), numBounds);222 }223 224 if (origType.isDestructedType())225 createRecipeDestroySection(226 loc, locEnd, mainOp, cgf.getContext().getDeclAlign(varRecipe),227 origType, numBounds, baseType, recipe.getDestroyRegion());228 return recipe;229 }230};231} // namespace clang::CIRGen232