diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6530,7 +6530,7 @@ def fopenmp_is_device : Flag<["-"], "fopenmp-is-device">, HelpText<"Generate code only for an OpenMP target device.">, - Flags<[CC1Option, NoDriverOption]>; + Flags<[CC1Option, FC1Option, NoDriverOption]>; def fopenmp_host_ir_file_path : Separate<["-"], "fopenmp-host-ir-file-path">, HelpText<"Path to the IR file produced by the frontend for the host.">, Flags<[CC1Option, NoDriverOption]>; diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h --- a/clang/lib/Driver/ToolChains/Flang.h +++ b/clang/lib/Driver/ToolChains/Flang.h @@ -56,6 +56,15 @@ void addTargetOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + /// Extract offload options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] JA The job action + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addOffloadOptions(const JobAction &JA, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// Extract other compilation options from the driver arguments and add them /// to the command arguments. /// diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -114,6 +114,18 @@ // TODO: Add target specific flags, ABI, mtune option etc. } +void Flang::addOffloadOptions(const JobAction &JA, const ArgList &Args, + ArgStringList &CmdArgs) const { + bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); + + if (IsOpenMPDevice) { + // -fopenmp-is-device is passed along to tell the frontend that it is + // generating code for a device, so that only the relevant declarations are + // emitted. + CmdArgs.push_back("-fopenmp-is-device"); + } +} + static void addFloatingPointOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { StringRef FPContract; @@ -311,6 +323,9 @@ // Add target args, features, etc. addTargetOptions(Args, CmdArgs); + // Offloading related options + addOffloadOptions(JA, Args, CmdArgs); + // Add other compile options addOtherOptions(Args, CmdArgs); diff --git a/clang/test/Driver/flang/flang-omp.f90 b/clang/test/Driver/flang/flang-omp.f90 new file mode 100644 --- /dev/null +++ b/clang/test/Driver/flang/flang-omp.f90 @@ -0,0 +1,12 @@ +! Check that flang -fc1 is invoked when in --driver-mode=flang +! and the relevant openmp and openmp offload flags are utilised +! and passed down correctly + +! Test regular -fopenmp with no offload +! RUN: %clang --driver-mode=flang -### -fopenmp %s 2>&1 | FileCheck --check-prefixes=CHECK-OPENMP %s +! CHECK-OPENMP: "{{[^"]*}}flang-new" "-fc1" {{.*}} "-fopenmp" {{.*}}.f90" +! CHECK-OPENMP-NOT: "{{[^"]*}}flang-new" "-fc1" {{.*}} "-fopenmp" {{.*}} "-fopenmp-is-device" {{.*}}.f90" + +! Test regular -fopenmp with offload for basic fopenmp-is-device flag addition and correct fopenmp +! RUN: %clang --driver-mode=flang -### -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa %s 2>&1 | FileCheck --check-prefixes=CHECK-OPENMP-IS-DEVICE %s +! CHECK-OPENMP-IS-DEVICE: "{{[^"]*}}flang-new" "-fc1" {{.*}} "-fopenmp" {{.*}} "-fopenmp-is-device" {{.*}}.f90" diff --git a/flang/include/flang/Frontend/LangOptions.def b/flang/include/flang/Frontend/LangOptions.def --- a/flang/include/flang/Frontend/LangOptions.def +++ b/flang/include/flang/Frontend/LangOptions.def @@ -34,6 +34,8 @@ LANGOPT(AssociativeMath, 1, false) /// Allow division operations to be reassociated LANGOPT(ReciprocalMath, 1, false) +/// Generate code only for OpenMP target device +LANGOPT(OpenMPIsDevice, 1, false) #undef LANGOPT #undef ENUM_LANGOPT diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -670,6 +670,10 @@ if (args.hasArg(clang::driver::options::OPT_fopenmp)) { res.getFrontendOpts().features.Enable( Fortran::common::LanguageFeature::OpenMP); + + if (args.hasArg(clang::driver::options::OPT_fopenmp_is_device)) { + res.getLangOpts().OpenMPIsDevice = 1; + } } // -pedantic diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -177,6 +177,13 @@ // Fetch module from lb, so we can set mlirModule = std::make_unique(lb.getModule()); + + if (ci.getInvocation().getFrontendOpts().features.IsEnabled( + Fortran::common::LanguageFeature::OpenMP)) { + mlir::omp::OpenMPDialect::setIsDevice( + *mlirModule, ci.getInvocation().getLangOpts().OpenMPIsDevice); + } + setUpTargetMachine(); const llvm::DataLayout &dl = tm->createDataLayout(); setMLIRDataLayout(*mlirModule, dl); diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -138,6 +138,7 @@ ! HELP-FC1-NEXT: -fno-signed-zeros Allow optimizations that ignore the sign of floating point zeros ! HELP-FC1-NEXT: -fno-stack-arrays Allocate array temporaries on the heap (default) ! HELP-FC1-NEXT: -fopenacc Enable OpenACC +! HELP-FC1-NEXT: -fopenmp-is-device Generate code only for an OpenMP target device. ! HELP-FC1-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code. ! HELP-FC1-NEXT: -fpass-plugin= Load pass plugin from a dynamic shared object file (only with new pass manager). ! HELP-FC1-NEXT: -freciprocal-math Allow division operations to be reassociated diff --git a/flang/test/Lower/OpenMP/omp-is-device.f90 b/flang/test/Lower/OpenMP/omp-is-device.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-is-device.f90 @@ -0,0 +1,19 @@ +!RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-is-device %s -o - | FileCheck %s --check-prefix=DEVICE +!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s --check-prefix=HOST +!RUN: %flang_fc1 -emit-fir -fopenmp-is-device %s -o - | FileCheck %s --check-prefix=DEVICE-FLAG-ONLY +!RUN: bbc -fopenmp -fopenmp-is-device -emit-fir -o - %s | FileCheck %s --check-prefix=BBC-DEVICE +!RUN: bbc -fopenmp -emit-fir -o - %s | FileCheck %s --check-prefix=BBC-HOST +!RUN: bbc -fopenmp-is-device -emit-fir -o - %s | FileCheck %s --check-prefix=BBC-DEVICE-FLAG-ONLY + +!DEVICE: module attributes {{{.*}}, omp.is_device = true{{.*}}} +!HOST: module attributes {{{.*}}, omp.is_device = false{{.*}}} +!DEVICE-FLAG-ONLY: module attributes {{{.*}}" +!DEVICE-FLAG-ONLY-NOT: , omp.is_device = {{.*}} +!DEVICE-FLAG-ONLY-SAME: } +!BBC-DEVICE: module attributes {{{.*}}, omp.is_device = true{{.*}}} +!BBC-HOST: module attributes {{{.*}}, omp.is_device = false{{.*}}} +!BBC-DEVICE-FLAG-ONLY: module attributes {fir.defaultkind = "{{.*}}", fir.kindmap = "{{.*}}", llvm.target_triple = "{{.*}}" +!BBC-DEVICE-FLAG-ONLY-NOT: , omp.is_device = {{.*}} +!BBC-DEVICE-FLAG-ONLY-SAME: } +subroutine omp_subroutine() +end subroutine omp_subroutine diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -38,6 +38,7 @@ #include "flang/Semantics/semantics.h" #include "flang/Semantics/unparse-with-symbols.h" #include "flang/Version.inc" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/AsmState.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/MLIRContext.h" @@ -122,6 +123,11 @@ llvm::cl::desc("enable openmp"), llvm::cl::init(false)); +static llvm::cl::opt + enableOpenMPDevice("fopenmp-is-device", + llvm::cl::desc("enable openmp device compilation"), + llvm::cl::init(false)); + static llvm::cl::opt enableOpenACC("fopenacc", llvm::cl::desc("enable openacc"), llvm::cl::init(false)); @@ -237,6 +243,8 @@ kindMap, loweringOptions, {}); burnside.lower(parseTree, semanticsContext); mlir::ModuleOp mlirModule = burnside.getModule(); + if (enableOpenMP) + mlir::omp::OpenMPDialect::setIsDevice(mlirModule, enableOpenMPDevice); std::error_code ec; std::string outputName = outputFilename; if (!outputName.size()) diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -28,6 +28,15 @@ let cppNamespace = "::mlir::omp"; let dependentDialects = ["::mlir::LLVM::LLVMDialect"]; let useDefaultAttributePrinterParser = 1; + + let extraClassDeclaration = [{ + // Set the omp.is_device attribute on the module with the specified boolean + static void setIsDevice(Operation* module, bool isDevice); + + // Return the value of the omp.is_device attribute stored in the module if it + // exists, otherwise return false by default + static bool getIsDevice(Operation* module); + }]; } // OmpCommon requires definition of OpenACC_Dialect. diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -1417,6 +1417,26 @@ return success(); } +//===----------------------------------------------------------------------===// +// OpenMPDialect helper functions +//===----------------------------------------------------------------------===// + +// Set the omp.is_device attribute on the module with the specified boolean +void OpenMPDialect::setIsDevice(Operation* module, bool isDevice) { + module->setAttr( + mlir::StringAttr::get(module->getContext(), llvm::Twine{"omp.is_device"}), + mlir::BoolAttr::get(module->getContext(), isDevice)); +} + +// Return the value of the omp.is_device attribute stored in the module if it +// exists, otherwise return false by default +bool OpenMPDialect::getIsDevice(Operation* module) { + if (Attribute isDevice = module->getAttr("omp.is_device")) + if (isDevice.isa()) + return isDevice.dyn_cast().getValue(); + return false; +} + #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"