@@ -3116,6 +3116,172 @@ convertDeclareTargetAttr(Operation *op, mlir::omp::DeclareTargetAttr attribute,
31163116 return success ();
31173117}
31183118
3119+ static bool isTargetDeviceOp (Operation *op) {
3120+ // Assumes no reverse offloading
3121+ if (op->getParentOfType <omp::TargetOp>())
3122+ return true ;
3123+
3124+ if (auto parentFn = op->getParentOfType <LLVM::LLVMFuncOp>())
3125+ if (auto declareTargetIface =
3126+ llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(
3127+ parentFn.getOperation ()))
3128+ if (declareTargetIface.isDeclareTarget () &&
3129+ declareTargetIface.getDeclareTargetDeviceType () !=
3130+ mlir::omp::DeclareTargetDeviceType::host)
3131+ return true ;
3132+
3133+ return false ;
3134+ }
3135+
3136+ // / Given an OpenMP MLIR operation, create the corresponding LLVM IR
3137+ // / (including OpenMP runtime calls).
3138+ static LogicalResult
3139+ convertHostOrTargetOperation (Operation *op, llvm::IRBuilderBase &builder,
3140+ LLVM::ModuleTranslation &moduleTranslation) {
3141+
3142+ llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder ();
3143+
3144+ return llvm::TypeSwitch<Operation *, LogicalResult>(op)
3145+ .Case ([&](omp::BarrierOp) {
3146+ ompBuilder->createBarrier (builder.saveIP (), llvm::omp::OMPD_barrier);
3147+ return success ();
3148+ })
3149+ .Case ([&](omp::TaskwaitOp) {
3150+ ompBuilder->createTaskwait (builder.saveIP ());
3151+ return success ();
3152+ })
3153+ .Case ([&](omp::TaskyieldOp) {
3154+ ompBuilder->createTaskyield (builder.saveIP ());
3155+ return success ();
3156+ })
3157+ .Case ([&](omp::FlushOp) {
3158+ // No support in Openmp runtime function (__kmpc_flush) to accept
3159+ // the argument list.
3160+ // OpenMP standard states the following:
3161+ // "An implementation may implement a flush with a list by ignoring
3162+ // the list, and treating it the same as a flush without a list."
3163+ //
3164+ // The argument list is discarded so that, flush with a list is treated
3165+ // same as a flush without a list.
3166+ ompBuilder->createFlush (builder.saveIP ());
3167+ return success ();
3168+ })
3169+ .Case ([&](omp::ParallelOp op) {
3170+ return convertOmpParallel (op, builder, moduleTranslation);
3171+ })
3172+ .Case ([&](omp::ReductionOp reductionOp) {
3173+ return convertOmpReductionOp (reductionOp, builder, moduleTranslation);
3174+ })
3175+ .Case ([&](omp::MasterOp) {
3176+ return convertOmpMaster (*op, builder, moduleTranslation);
3177+ })
3178+ .Case ([&](omp::CriticalOp) {
3179+ return convertOmpCritical (*op, builder, moduleTranslation);
3180+ })
3181+ .Case ([&](omp::OrderedRegionOp) {
3182+ return convertOmpOrderedRegion (*op, builder, moduleTranslation);
3183+ })
3184+ .Case ([&](omp::OrderedOp) {
3185+ return convertOmpOrdered (*op, builder, moduleTranslation);
3186+ })
3187+ .Case ([&](omp::WsloopOp) {
3188+ return convertOmpWsloop (*op, builder, moduleTranslation);
3189+ })
3190+ .Case ([&](omp::SimdLoopOp) {
3191+ return convertOmpSimdLoop (*op, builder, moduleTranslation);
3192+ })
3193+ .Case ([&](omp::AtomicReadOp) {
3194+ return convertOmpAtomicRead (*op, builder, moduleTranslation);
3195+ })
3196+ .Case ([&](omp::AtomicWriteOp) {
3197+ return convertOmpAtomicWrite (*op, builder, moduleTranslation);
3198+ })
3199+ .Case ([&](omp::AtomicUpdateOp op) {
3200+ return convertOmpAtomicUpdate (op, builder, moduleTranslation);
3201+ })
3202+ .Case ([&](omp::AtomicCaptureOp op) {
3203+ return convertOmpAtomicCapture (op, builder, moduleTranslation);
3204+ })
3205+ .Case ([&](omp::SectionsOp) {
3206+ return convertOmpSections (*op, builder, moduleTranslation);
3207+ })
3208+ .Case ([&](omp::SingleOp op) {
3209+ return convertOmpSingle (op, builder, moduleTranslation);
3210+ })
3211+ .Case ([&](omp::TeamsOp op) {
3212+ return convertOmpTeams (op, builder, moduleTranslation);
3213+ })
3214+ .Case ([&](omp::TaskOp op) {
3215+ return convertOmpTaskOp (op, builder, moduleTranslation);
3216+ })
3217+ .Case ([&](omp::TaskgroupOp op) {
3218+ return convertOmpTaskgroupOp (op, builder, moduleTranslation);
3219+ })
3220+ .Case <omp::YieldOp, omp::TerminatorOp, omp::DeclareReductionOp,
3221+ omp::CriticalDeclareOp>([](auto op) {
3222+ // `yield` and `terminator` can be just omitted. The block structure
3223+ // was created in the region that handles their parent operation.
3224+ // `declare_reduction` will be used by reductions and is not
3225+ // converted directly, skip it.
3226+ // `critical.declare` is only used to declare names of critical
3227+ // sections which will be used by `critical` ops and hence can be
3228+ // ignored for lowering. The OpenMP IRBuilder will create unique
3229+ // name for critical section names.
3230+ return success ();
3231+ })
3232+ .Case ([&](omp::ThreadprivateOp) {
3233+ return convertOmpThreadprivate (*op, builder, moduleTranslation);
3234+ })
3235+ .Case <omp::TargetDataOp, omp::TargetEnterDataOp, omp::TargetExitDataOp,
3236+ omp::TargetUpdateOp>([&](auto op) {
3237+ return convertOmpTargetData (op, builder, moduleTranslation);
3238+ })
3239+ .Case ([&](omp::TargetOp) {
3240+ return convertOmpTarget (*op, builder, moduleTranslation);
3241+ })
3242+ .Case <omp::MapInfoOp, omp::MapBoundsOp, omp::PrivateClauseOp>(
3243+ [&](auto op) {
3244+ // No-op, should be handled by relevant owning operations e.g.
3245+ // TargetOp, TargetEnterDataOp, TargetExitDataOp, TargetDataOp etc.
3246+ // and then discarded
3247+ return success ();
3248+ })
3249+ .Default ([&](Operation *inst) {
3250+ return inst->emitError (" unsupported OpenMP operation: " )
3251+ << inst->getName ();
3252+ });
3253+ }
3254+
3255+ static LogicalResult
3256+ convertTargetDeviceOp (Operation *op, llvm::IRBuilderBase &builder,
3257+ LLVM::ModuleTranslation &moduleTranslation) {
3258+ return convertHostOrTargetOperation (op, builder, moduleTranslation);
3259+ }
3260+
3261+ static LogicalResult
3262+ convertTargetOpsInNest (Operation *op, llvm::IRBuilderBase &builder,
3263+ LLVM::ModuleTranslation &moduleTranslation) {
3264+ if (isa<omp::TargetOp>(op))
3265+ return convertOmpTarget (*op, builder, moduleTranslation);
3266+ if (isa<omp::TargetDataOp>(op))
3267+ return convertOmpTargetData (op, builder, moduleTranslation);
3268+ bool interrupted =
3269+ op->walk <WalkOrder::PreOrder>([&](Operation *oper) {
3270+ if (isa<omp::TargetOp>(oper)) {
3271+ if (failed (convertOmpTarget (*oper, builder, moduleTranslation)))
3272+ return WalkResult::interrupt ();
3273+ return WalkResult::skip ();
3274+ }
3275+ if (isa<omp::TargetDataOp>(oper)) {
3276+ if (failed (convertOmpTargetData (oper, builder, moduleTranslation)))
3277+ return WalkResult::interrupt ();
3278+ return WalkResult::skip ();
3279+ }
3280+ return WalkResult::advance ();
3281+ }).wasInterrupted ();
3282+ return failure (interrupted);
3283+ }
3284+
31193285namespace {
31203286
31213287// / Implementation of the dialect interface that converts operations belonging
@@ -3131,8 +3297,8 @@ class OpenMPDialectLLVMIRTranslationInterface
31313297 convertOperation (Operation *op, llvm::IRBuilderBase &builder,
31323298 LLVM::ModuleTranslation &moduleTranslation) const final ;
31333299
3134- // / Given an OpenMP MLIR attribute, create the corresponding LLVM-IR, runtime
3135- // / calls, or operation amendments
3300+ // / Given an OpenMP MLIR attribute, create the corresponding LLVM-IR,
3301+ // / runtime calls, or operation amendments
31363302 LogicalResult
31373303 amendOperation (Operation *op, ArrayRef<llvm::Instruction *> instructions,
31383304 NamedAttribute attribute,
@@ -3237,116 +3403,15 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
32373403 LLVM::ModuleTranslation &moduleTranslation) const {
32383404
32393405 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder ();
3406+ if (ompBuilder->Config .isTargetDevice ()) {
3407+ if (isTargetDeviceOp (op)) {
3408+ return convertTargetDeviceOp (op, builder, moduleTranslation);
3409+ } else {
3410+ return convertTargetOpsInNest (op, builder, moduleTranslation);
3411+ }
3412+ }
32403413
3241- return llvm::TypeSwitch<Operation *, LogicalResult>(op)
3242- .Case ([&](omp::BarrierOp) {
3243- ompBuilder->createBarrier (builder.saveIP (), llvm::omp::OMPD_barrier);
3244- return success ();
3245- })
3246- .Case ([&](omp::TaskwaitOp) {
3247- ompBuilder->createTaskwait (builder.saveIP ());
3248- return success ();
3249- })
3250- .Case ([&](omp::TaskyieldOp) {
3251- ompBuilder->createTaskyield (builder.saveIP ());
3252- return success ();
3253- })
3254- .Case ([&](omp::FlushOp) {
3255- // No support in Openmp runtime function (__kmpc_flush) to accept
3256- // the argument list.
3257- // OpenMP standard states the following:
3258- // "An implementation may implement a flush with a list by ignoring
3259- // the list, and treating it the same as a flush without a list."
3260- //
3261- // The argument list is discarded so that, flush with a list is treated
3262- // same as a flush without a list.
3263- ompBuilder->createFlush (builder.saveIP ());
3264- return success ();
3265- })
3266- .Case ([&](omp::ParallelOp op) {
3267- return convertOmpParallel (op, builder, moduleTranslation);
3268- })
3269- .Case ([&](omp::ReductionOp reductionOp) {
3270- return convertOmpReductionOp (reductionOp, builder, moduleTranslation);
3271- })
3272- .Case ([&](omp::MasterOp) {
3273- return convertOmpMaster (*op, builder, moduleTranslation);
3274- })
3275- .Case ([&](omp::CriticalOp) {
3276- return convertOmpCritical (*op, builder, moduleTranslation);
3277- })
3278- .Case ([&](omp::OrderedRegionOp) {
3279- return convertOmpOrderedRegion (*op, builder, moduleTranslation);
3280- })
3281- .Case ([&](omp::OrderedOp) {
3282- return convertOmpOrdered (*op, builder, moduleTranslation);
3283- })
3284- .Case ([&](omp::WsloopOp) {
3285- return convertOmpWsloop (*op, builder, moduleTranslation);
3286- })
3287- .Case ([&](omp::SimdLoopOp) {
3288- return convertOmpSimdLoop (*op, builder, moduleTranslation);
3289- })
3290- .Case ([&](omp::AtomicReadOp) {
3291- return convertOmpAtomicRead (*op, builder, moduleTranslation);
3292- })
3293- .Case ([&](omp::AtomicWriteOp) {
3294- return convertOmpAtomicWrite (*op, builder, moduleTranslation);
3295- })
3296- .Case ([&](omp::AtomicUpdateOp op) {
3297- return convertOmpAtomicUpdate (op, builder, moduleTranslation);
3298- })
3299- .Case ([&](omp::AtomicCaptureOp op) {
3300- return convertOmpAtomicCapture (op, builder, moduleTranslation);
3301- })
3302- .Case ([&](omp::SectionsOp) {
3303- return convertOmpSections (*op, builder, moduleTranslation);
3304- })
3305- .Case ([&](omp::SingleOp op) {
3306- return convertOmpSingle (op, builder, moduleTranslation);
3307- })
3308- .Case ([&](omp::TeamsOp op) {
3309- return convertOmpTeams (op, builder, moduleTranslation);
3310- })
3311- .Case ([&](omp::TaskOp op) {
3312- return convertOmpTaskOp (op, builder, moduleTranslation);
3313- })
3314- .Case ([&](omp::TaskgroupOp op) {
3315- return convertOmpTaskgroupOp (op, builder, moduleTranslation);
3316- })
3317- .Case <omp::YieldOp, omp::TerminatorOp, omp::DeclareReductionOp,
3318- omp::CriticalDeclareOp>([](auto op) {
3319- // `yield` and `terminator` can be just omitted. The block structure
3320- // was created in the region that handles their parent operation.
3321- // `declare_reduction` will be used by reductions and is not
3322- // converted directly, skip it.
3323- // `critical.declare` is only used to declare names of critical
3324- // sections which will be used by `critical` ops and hence can be
3325- // ignored for lowering. The OpenMP IRBuilder will create unique
3326- // name for critical section names.
3327- return success ();
3328- })
3329- .Case ([&](omp::ThreadprivateOp) {
3330- return convertOmpThreadprivate (*op, builder, moduleTranslation);
3331- })
3332- .Case <omp::TargetDataOp, omp::TargetEnterDataOp, omp::TargetExitDataOp,
3333- omp::TargetUpdateOp>([&](auto op) {
3334- return convertOmpTargetData (op, builder, moduleTranslation);
3335- })
3336- .Case ([&](omp::TargetOp) {
3337- return convertOmpTarget (*op, builder, moduleTranslation);
3338- })
3339- .Case <omp::MapInfoOp, omp::MapBoundsOp, omp::PrivateClauseOp>(
3340- [&](auto op) {
3341- // No-op, should be handled by relevant owning operations e.g.
3342- // TargetOp, TargetEnterDataOp, TargetExitDataOp, TargetDataOp etc.
3343- // and then discarded
3344- return success ();
3345- })
3346- .Default ([&](Operation *inst) {
3347- return inst->emitError (" unsupported OpenMP operation: " )
3348- << inst->getName ();
3349- });
3414+ return convertHostOrTargetOperation (op, builder, moduleTranslation);
33503415}
33513416
33523417void mlir::registerOpenMPDialectTranslation (DialectRegistry ®istry) {
0 commit comments