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