[flang-commits] [flang] [Flang][OpenMP] Minimize host ops remaining in device compilation (PR #137200)
Sergio Afonso via flang-commits
flang-commits at lists.llvm.org
Mon Aug 25 08:21:33 PDT 2025
================
@@ -94,12 +195,359 @@ class FunctionFilteringPass
funcOp.erase();
return WalkResult::skip();
}
+
+ if (failed(rewriteHostRegion(funcOp.getRegion()))) {
+ funcOp.emitOpError() << "could not be rewritten for target device";
+ return WalkResult::interrupt();
+ }
+
if (declareTargetOp)
declareTargetOp.setDeclareTarget(declareType,
omp::DeclareTargetCaptureClause::to);
}
return WalkResult::advance();
});
}
+
+private:
+ /// Rewrite the given host device region belonging to a function that contains
+ /// \c omp.target operations, to remove host-only operations that are not used
+ /// by device codegen.
+ ///
+ /// It is based on the expected form of the MLIR module as produced by Flang
+ /// lowering and it performs the following mutations:
+ /// - Replace all values returned by the function with \c fir.undefined.
+ /// - Operations taking map-like clauses (e.g. \c omp.target,
+ /// \c omp.target_data, etc) are moved to the end of the function. If they
+ /// are nested inside of any other operations, they are hoisted out of
+ /// them. If the region belongs to \c omp.target_data, these operations
+ /// are hoisted to its top level, rather than to the parent function.
+ /// - \c device, \c if and \c depend clauses are removed from these target
+ /// functions. Values initializing other clauses are either replaced by
+ /// placeholders as follows:
+ /// - Values defined by block arguments are replaced by placeholders only
+ /// if they are not attached to \c func.func or \c omp.target_data
+ /// operations. In that case, they are kept unmodified.
+ /// - \c arith.constant and \c fir.address_of are maintained.
+ /// - Other values are replaced by a combination of an \c fir.alloca for a
+ /// single bit and an \c fir.convert to the original type of the value.
+ /// This can be done because the code eventually generated for these
+ /// operations will be discarded, as they aren't runnable by the target
+ /// device.
+ /// - \c omp.map.info operations associated to these target regions are
+ /// preserved. These are moved above all \c omp.target and sorted to
+ /// satisfy dependencies among them.
+ /// - \c bounds arguments are removed from \c omp.map.info operations.
+ /// - \c var_ptr and \c var_ptr_ptr arguments of \c omp.map.info are
+ /// handled as follows:
+ /// - \c var_ptr_ptr is expected to be defined by a \c fir.box_offset
+ /// operation which is preserved. Otherwise, the pass will fail.
+ /// - \c var_ptr can be defined by an \c hlfir.declare which is also
+ /// preserved. Its \c memref argument is replaced by a placeholder or
+ /// maintained similarly to non-map clauses of target operations
+ /// described above. If it has \c shape or \c typeparams arguments, they
+ /// are replaced by applicable constants. \c dummy_scope arguments
+ /// are discarded.
+ /// - Every other operation not located inside of an \c omp.target is
+ /// removed.
+ /// - Whenever a value or operation that would otherwise be replaced with a
+ /// placeholder is defined outside of the region being rewritten, it is
+ /// added to the \c parentOpRewrites or \c parentValRewrites output
+ /// argument, to be later handled by the caller. This is only intended to
+ /// properly support nested \c omp.target_data and \c omp.target placed
+ /// inside of \c omp.target_data. When called for the main function, these
+ /// output arguments must not be set.
+ LogicalResult
+ rewriteHostRegion(Region ®ion,
+ llvm::SetVector<Operation *> *parentOpRewrites = nullptr,
+ llvm::SetVector<Value> *parentValRewrites = nullptr) {
+ // Extract parent op information.
+ auto [funcOp, targetDataOp] = [®ion]() {
+ Operation *parent = region.getParentOp();
+ return std::make_tuple(dyn_cast<func::FuncOp>(parent),
+ dyn_cast<omp::TargetDataOp>(parent));
+ }();
+ assert((bool)funcOp != (bool)targetDataOp &&
+ "region must be defined by either func.func or omp.target_data");
+ assert((bool)parentOpRewrites == (bool)targetDataOp &&
+ (bool)parentValRewrites == (bool)targetDataOp &&
+ "parent rewrites must be passed iff rewriting omp.target_data");
+
+ // Collect operations that have mapping information associated to them.
+ llvm::SmallVector<
----------------
skatrak wrote:
Thank you Akash for these suggestions, I was able to remove operations related to `target data`, `target enter data`, `target exit data` and `target update` as well. This also helped make things a little simpler as well, since a lot of the complexity was to keep `omp.target_data` ops around. Let me know if these changes work for you.
https://github.com/llvm/llvm-project/pull/137200
More information about the flang-commits
mailing list