|
14 | 14 |
|
15 | 15 | #include "CIRGenCXXABI.h"
|
16 | 16 | #include "CIRGenFunction.h"
|
| 17 | +#include "CIRGenOpenACCRecipe.h" |
17 | 18 |
|
18 | 19 | #include "clang/AST/ExprCXX.h"
|
19 | 20 |
|
@@ -356,299 +357,6 @@ class OpenACCClauseCIREmitter final
|
356 | 357 | }
|
357 | 358 | }
|
358 | 359 |
|
359 |
| - template <typename RecipeTy> |
360 |
| - std::string getRecipeName(SourceRange loc, QualType baseType, |
361 |
| - OpenACCReductionOperator reductionOp) { |
362 |
| - std::string recipeName; |
363 |
| - { |
364 |
| - llvm::raw_string_ostream stream(recipeName); |
365 |
| - |
366 |
| - if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) { |
367 |
| - stream << "privatization_"; |
368 |
| - } else if constexpr (std::is_same_v<RecipeTy, |
369 |
| - mlir::acc::FirstprivateRecipeOp>) { |
370 |
| - stream << "firstprivatization_"; |
371 |
| - |
372 |
| - } else if constexpr (std::is_same_v<RecipeTy, |
373 |
| - mlir::acc::ReductionRecipeOp>) { |
374 |
| - stream << "reduction_"; |
375 |
| - // Values here are a little weird (for bitwise and/or is 'i' prefix, and |
376 |
| - // logical ops with 'l'), but are chosen to be the same as the MLIR |
377 |
| - // dialect names as well as to match the Flang versions of these. |
378 |
| - switch (reductionOp) { |
379 |
| - case OpenACCReductionOperator::Addition: |
380 |
| - stream << "add_"; |
381 |
| - break; |
382 |
| - case OpenACCReductionOperator::Multiplication: |
383 |
| - stream << "mul_"; |
384 |
| - break; |
385 |
| - case OpenACCReductionOperator::Max: |
386 |
| - stream << "max_"; |
387 |
| - break; |
388 |
| - case OpenACCReductionOperator::Min: |
389 |
| - stream << "min_"; |
390 |
| - break; |
391 |
| - case OpenACCReductionOperator::BitwiseAnd: |
392 |
| - stream << "iand_"; |
393 |
| - break; |
394 |
| - case OpenACCReductionOperator::BitwiseOr: |
395 |
| - stream << "ior_"; |
396 |
| - break; |
397 |
| - case OpenACCReductionOperator::BitwiseXOr: |
398 |
| - stream << "xor_"; |
399 |
| - break; |
400 |
| - case OpenACCReductionOperator::And: |
401 |
| - stream << "land_"; |
402 |
| - break; |
403 |
| - case OpenACCReductionOperator::Or: |
404 |
| - stream << "lor_"; |
405 |
| - break; |
406 |
| - case OpenACCReductionOperator::Invalid: |
407 |
| - llvm_unreachable("invalid reduction operator"); |
408 |
| - } |
409 |
| - } else { |
410 |
| - static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind"); |
411 |
| - } |
412 |
| - |
413 |
| - MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext(); |
414 |
| - mc.mangleCanonicalTypeName(baseType, stream); |
415 |
| - } |
416 |
| - return recipeName; |
417 |
| - } |
418 |
| - |
419 |
| - void createFirstprivateRecipeCopy( |
420 |
| - mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp, |
421 |
| - CIRGenFunction::AutoVarEmission tempDeclEmission, |
422 |
| - mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe, |
423 |
| - const VarDecl *temporary) { |
424 |
| - mlir::Block *block = builder.createBlock( |
425 |
| - &recipe.getCopyRegion(), recipe.getCopyRegion().end(), |
426 |
| - {mainOp.getType(), mainOp.getType()}, {loc, loc}); |
427 |
| - builder.setInsertionPointToEnd(&recipe.getCopyRegion().back()); |
428 |
| - CIRGenFunction::LexicalScope ls(cgf, loc, block); |
429 |
| - |
430 |
| - mlir::BlockArgument fromArg = block->getArgument(0); |
431 |
| - mlir::BlockArgument toArg = block->getArgument(1); |
432 |
| - |
433 |
| - mlir::Type elementTy = |
434 |
| - mlir::cast<cir::PointerType>(mainOp.getType()).getPointee(); |
435 |
| - |
436 |
| - // Set the address of the emission to be the argument, so that we initialize |
437 |
| - // that instead of the variable in the other block. |
438 |
| - tempDeclEmission.setAllocatedAddress( |
439 |
| - Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)}); |
440 |
| - tempDeclEmission.EmittedAsOffload = true; |
441 |
| - |
442 |
| - CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary}; |
443 |
| - cgf.setAddrOfLocalVar( |
444 |
| - temporary, |
445 |
| - Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)}); |
446 |
| - |
447 |
| - cgf.emitAutoVarInit(tempDeclEmission); |
448 |
| - mlir::acc::YieldOp::create(builder, locEnd); |
449 |
| - } |
450 |
| - |
451 |
| - // Create the 'init' section of the recipe, including the 'copy' section for |
452 |
| - // 'firstprivate'. Note that this function is not 'insertion point' clean, in |
453 |
| - // that it alters the insertion point to be inside of the 'destroy' section of |
454 |
| - // the recipe, but doesn't restore it aftewards. |
455 |
| - template <typename RecipeTy> |
456 |
| - void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd, |
457 |
| - SourceRange exprRange, mlir::Value mainOp, |
458 |
| - RecipeTy recipe, const VarDecl *varRecipe, |
459 |
| - const VarDecl *temporary) { |
460 |
| - assert(varRecipe && "Required recipe variable not set?"); |
461 |
| - |
462 |
| - CIRGenFunction::AutoVarEmission tempDeclEmission{ |
463 |
| - CIRGenFunction::AutoVarEmission::invalid()}; |
464 |
| - CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe}; |
465 |
| - |
466 |
| - // Do the 'init' section of the recipe IR, which does an alloca, then the |
467 |
| - // initialization (except for firstprivate). |
468 |
| - mlir::Block *block = builder.createBlock(&recipe.getInitRegion(), |
469 |
| - recipe.getInitRegion().end(), |
470 |
| - {mainOp.getType()}, {loc}); |
471 |
| - builder.setInsertionPointToEnd(&recipe.getInitRegion().back()); |
472 |
| - CIRGenFunction::LexicalScope ls(cgf, loc, block); |
473 |
| - |
474 |
| - tempDeclEmission = |
475 |
| - cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint()); |
476 |
| - |
477 |
| - // 'firstprivate' doesn't do its initialization in the 'init' section, |
478 |
| - // instead does it in the 'copy' section. SO only do init here. |
479 |
| - // 'reduction' appears to use it too (rather than a 'copy' section), so |
480 |
| - // we probably have to do it here too, but we can do that when we get to |
481 |
| - // reduction implementation. |
482 |
| - if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) { |
483 |
| - // We are OK with no init for builtins, arrays of builtins, or pointers, |
484 |
| - // else we should NYI so we know to go look for these. |
485 |
| - if (cgf.getContext().getLangOpts().CPlusPlus && |
486 |
| - !varRecipe->getType() |
487 |
| - ->getPointeeOrArrayElementType() |
488 |
| - ->isBuiltinType() && |
489 |
| - !varRecipe->getType()->isPointerType() && !varRecipe->getInit()) { |
490 |
| - // If we don't have any initialization recipe, we failed during Sema to |
491 |
| - // initialize this correctly. If we disable the |
492 |
| - // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll |
493 |
| - // emit an error to tell us. However, emitting those errors during |
494 |
| - // production is a violation of the standard, so we cannot do them. |
495 |
| - cgf.cgm.errorNYI(exprRange, "private default-init recipe"); |
496 |
| - } |
497 |
| - cgf.emitAutoVarInit(tempDeclEmission); |
498 |
| - } else if constexpr (std::is_same_v<RecipeTy, |
499 |
| - mlir::acc::ReductionRecipeOp>) { |
500 |
| - // Unlike Private, the recipe here is always required as it has to do |
501 |
| - // init, not just 'default' init. |
502 |
| - if (!varRecipe->getInit()) |
503 |
| - cgf.cgm.errorNYI(exprRange, "reduction init recipe"); |
504 |
| - cgf.emitAutoVarInit(tempDeclEmission); |
505 |
| - } |
506 |
| - |
507 |
| - mlir::acc::YieldOp::create(builder, locEnd); |
508 |
| - |
509 |
| - if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) { |
510 |
| - if (!varRecipe->getInit()) { |
511 |
| - // If we don't have any initialization recipe, we failed during Sema to |
512 |
| - // initialize this correctly. If we disable the |
513 |
| - // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll |
514 |
| - // emit an error to tell us. However, emitting those errors during |
515 |
| - // production is a violation of the standard, so we cannot do them. |
516 |
| - cgf.cgm.errorNYI( |
517 |
| - exprRange, "firstprivate copy-init recipe not properly generated"); |
518 |
| - } |
519 |
| - |
520 |
| - createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission, |
521 |
| - recipe, varRecipe, temporary); |
522 |
| - } |
523 |
| - } |
524 |
| - |
525 |
| - // This function generates the 'combiner' section for a reduction recipe. Note |
526 |
| - // that this function is not 'insertion point' clean, in that it alters the |
527 |
| - // insertion point to be inside of the 'combiner' section of the recipe, but |
528 |
| - // doesn't restore it aftewards. |
529 |
| - void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd, |
530 |
| - mlir::Value mainOp, |
531 |
| - mlir::acc::ReductionRecipeOp recipe) { |
532 |
| - mlir::Block *block = builder.createBlock( |
533 |
| - &recipe.getCombinerRegion(), recipe.getCombinerRegion().end(), |
534 |
| - {mainOp.getType(), mainOp.getType()}, {loc, loc}); |
535 |
| - builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back()); |
536 |
| - CIRGenFunction::LexicalScope ls(cgf, loc, block); |
537 |
| - |
538 |
| - mlir::BlockArgument lhsArg = block->getArgument(0); |
539 |
| - |
540 |
| - mlir::acc::YieldOp::create(builder, locEnd, lhsArg); |
541 |
| - } |
542 |
| - |
543 |
| - // This function generates the 'destroy' section for a recipe. Note |
544 |
| - // that this function is not 'insertion point' clean, in that it alters the |
545 |
| - // insertion point to be inside of the 'destroy' section of the recipe, but |
546 |
| - // doesn't restore it aftewards. |
547 |
| - void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd, |
548 |
| - mlir::Value mainOp, CharUnits alignment, |
549 |
| - QualType baseType, |
550 |
| - mlir::Region &destroyRegion) { |
551 |
| - mlir::Block *block = |
552 |
| - builder.createBlock(&destroyRegion, destroyRegion.end(), |
553 |
| - {mainOp.getType(), mainOp.getType()}, {loc, loc}); |
554 |
| - builder.setInsertionPointToEnd(&destroyRegion.back()); |
555 |
| - CIRGenFunction::LexicalScope ls(cgf, loc, block); |
556 |
| - |
557 |
| - mlir::Type elementTy = |
558 |
| - mlir::cast<cir::PointerType>(mainOp.getType()).getPointee(); |
559 |
| - // The destroy region has a signature of "original item, privatized item". |
560 |
| - // So the 2nd item is the one that needs destroying, the former is just for |
561 |
| - // reference and we don't really have a need for it at the moment. |
562 |
| - Address addr{block->getArgument(1), elementTy, alignment}; |
563 |
| - cgf.emitDestroy(addr, baseType, |
564 |
| - cgf.getDestroyer(QualType::DK_cxx_destructor)); |
565 |
| - |
566 |
| - mlir::acc::YieldOp::create(builder, locEnd); |
567 |
| - } |
568 |
| - |
569 |
| - mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op) { |
570 |
| - switch (op) { |
571 |
| - case OpenACCReductionOperator::Addition: |
572 |
| - return mlir::acc::ReductionOperator::AccAdd; |
573 |
| - case OpenACCReductionOperator::Multiplication: |
574 |
| - return mlir::acc::ReductionOperator::AccMul; |
575 |
| - case OpenACCReductionOperator::Max: |
576 |
| - return mlir::acc::ReductionOperator::AccMax; |
577 |
| - case OpenACCReductionOperator::Min: |
578 |
| - return mlir::acc::ReductionOperator::AccMin; |
579 |
| - case OpenACCReductionOperator::BitwiseAnd: |
580 |
| - return mlir::acc::ReductionOperator::AccIand; |
581 |
| - case OpenACCReductionOperator::BitwiseOr: |
582 |
| - return mlir::acc::ReductionOperator::AccIor; |
583 |
| - case OpenACCReductionOperator::BitwiseXOr: |
584 |
| - return mlir::acc::ReductionOperator::AccXor; |
585 |
| - case OpenACCReductionOperator::And: |
586 |
| - return mlir::acc::ReductionOperator::AccLand; |
587 |
| - case OpenACCReductionOperator::Or: |
588 |
| - return mlir::acc::ReductionOperator::AccLor; |
589 |
| - case OpenACCReductionOperator::Invalid: |
590 |
| - llvm_unreachable("invalid reduction operator"); |
591 |
| - } |
592 |
| - |
593 |
| - llvm_unreachable("invalid reduction operator"); |
594 |
| - } |
595 |
| - |
596 |
| - template <typename RecipeTy> |
597 |
| - RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef, |
598 |
| - const VarDecl *varRecipe, const VarDecl *temporary, |
599 |
| - OpenACCReductionOperator reductionOp, |
600 |
| - DeclContext *dc, QualType baseType, |
601 |
| - mlir::Value mainOp) { |
602 |
| - |
603 |
| - if (baseType->isPointerType() || |
604 |
| - (baseType->isArrayType() && !baseType->isConstantArrayType())) { |
605 |
| - // It is clear that the use of pointers/VLAs in a recipe are not properly |
606 |
| - // generated/don't do what they are supposed to do. In the case where we |
607 |
| - // have 'bounds', we can actually figure out what we want to |
608 |
| - // initialize/copy/destroy/compare/etc, but we haven't figured out how |
609 |
| - // that looks yet, both between the IR and generation code. For now, we |
610 |
| - // will do an NYI error no it. |
611 |
| - cgf.cgm.errorNYI( |
612 |
| - varRef->getSourceRange(), |
613 |
| - "OpenACC recipe generation for pointer/non-constant arrays"); |
614 |
| - } |
615 |
| - |
616 |
| - mlir::ModuleOp mod = builder.getBlock() |
617 |
| - ->getParent() |
618 |
| - ->template getParentOfType<mlir::ModuleOp>(); |
619 |
| - |
620 |
| - std::string recipeName = getRecipeName<RecipeTy>(varRef->getSourceRange(), |
621 |
| - baseType, reductionOp); |
622 |
| - if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName)) |
623 |
| - return recipe; |
624 |
| - |
625 |
| - mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc()); |
626 |
| - mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc()); |
627 |
| - |
628 |
| - mlir::OpBuilder modBuilder(mod.getBodyRegion()); |
629 |
| - RecipeTy recipe; |
630 |
| - |
631 |
| - if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) { |
632 |
| - recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType(), |
633 |
| - convertReductionOp(reductionOp)); |
634 |
| - } else { |
635 |
| - recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType()); |
636 |
| - } |
637 |
| - |
638 |
| - createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp, recipe, |
639 |
| - varRecipe, temporary); |
640 |
| - |
641 |
| - if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) { |
642 |
| - createReductionRecipeCombiner(loc, locEnd, mainOp, recipe); |
643 |
| - } |
644 |
| - |
645 |
| - if (varRecipe && varRecipe->needsDestruction(cgf.getContext())) |
646 |
| - createRecipeDestroySection(loc, locEnd, mainOp, |
647 |
| - cgf.getContext().getDeclAlign(varRecipe), |
648 |
| - baseType, recipe.getDestroyRegion()); |
649 |
| - return recipe; |
650 |
| - } |
651 |
| - |
652 | 360 | public:
|
653 | 361 | OpenACCClauseCIREmitter(OpTy &operation, CIRGen::CIRGenFunction &cgf,
|
654 | 362 | CIRGen::CIRGenBuilderTy &builder,
|
@@ -1287,11 +995,13 @@ class OpenACCClauseCIREmitter final
|
1287 | 995 | allocaDecl->setInit(varRecipe.InitExpr);
|
1288 | 996 | allocaDecl->setInitStyle(VarDecl::CallInit);
|
1289 | 997 |
|
1290 |
| - auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>( |
1291 |
| - cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr, |
1292 |
| - OpenACCReductionOperator::Invalid, |
1293 |
| - Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, |
1294 |
| - privateOp.getResult()); |
| 998 | + auto recipe = |
| 999 | + OpenACCRecipeBuilder<mlir::acc::PrivateRecipeOp>(cgf, builder) |
| 1000 | + .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl, |
| 1001 | + /*temporary=*/nullptr, |
| 1002 | + OpenACCReductionOperator::Invalid, |
| 1003 | + Decl::castToDeclContext(cgf.curFuncDecl), |
| 1004 | + opInfo.baseType, privateOp.getResult()); |
1295 | 1005 | // TODO: OpenACC: The dialect is going to change in the near future to
|
1296 | 1006 | // have these be on a different operation, so when that changes, we
|
1297 | 1007 | // probably need to change these here.
|
@@ -1329,11 +1039,15 @@ class OpenACCClauseCIREmitter final
|
1329 | 1039 | allocaDecl->setInit(varRecipe.InitExpr);
|
1330 | 1040 | allocaDecl->setInitStyle(VarDecl::CallInit);
|
1331 | 1041 |
|
1332 |
| - auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>( |
1333 |
| - cgf.getContext(), varExpr, allocaDecl, |
1334 |
| - varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid, |
1335 |
| - Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, |
1336 |
| - firstPrivateOp.getResult()); |
| 1042 | + auto recipe = |
| 1043 | + OpenACCRecipeBuilder<mlir::acc::FirstprivateRecipeOp>(cgf, |
| 1044 | + builder) |
| 1045 | + .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl, |
| 1046 | + varRecipe.InitFromTemporary, |
| 1047 | + OpenACCReductionOperator::Invalid, |
| 1048 | + Decl::castToDeclContext(cgf.curFuncDecl), |
| 1049 | + opInfo.baseType, |
| 1050 | + firstPrivateOp.getResult()); |
1337 | 1051 |
|
1338 | 1052 | // TODO: OpenACC: The dialect is going to change in the near future to
|
1339 | 1053 | // have these be on a different operation, so when that changes, we
|
@@ -1373,11 +1087,13 @@ class OpenACCClauseCIREmitter final
|
1373 | 1087 | allocaDecl->setInit(varRecipe.InitExpr);
|
1374 | 1088 | allocaDecl->setInitStyle(VarDecl::CallInit);
|
1375 | 1089 |
|
1376 |
| - auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>( |
1377 |
| - cgf.getContext(), varExpr, allocaDecl, |
1378 |
| - /*temporary=*/nullptr, clause.getReductionOp(), |
1379 |
| - Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, |
1380 |
| - reductionOp.getResult()); |
| 1090 | + auto recipe = |
| 1091 | + OpenACCRecipeBuilder<mlir::acc::ReductionRecipeOp>(cgf, builder) |
| 1092 | + .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl, |
| 1093 | + /*temporary=*/nullptr, |
| 1094 | + clause.getReductionOp(), |
| 1095 | + Decl::castToDeclContext(cgf.curFuncDecl), |
| 1096 | + opInfo.baseType, reductionOp.getResult()); |
1381 | 1097 |
|
1382 | 1098 | operation.addReduction(builder.getContext(), reductionOp, recipe);
|
1383 | 1099 | }
|
|
0 commit comments