|
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