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 @@ -6555,7 +6555,7 @@ 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]>; + Flags<[CC1Option, FC1Option, NoDriverOption]>; //===----------------------------------------------------------------------===// // SYCL Options 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 @@ -140,15 +140,29 @@ // Skips the primary input file, which is the input file that the compilation // proccess will be executed upon (e.g. the host bitcode file) and - // adds the other secondary input (e.g. device bitcode files for embedding) - // to the embed offload object. This is condensed logic from the Clang driver - // for embedding offload objects during HostOffloading. - if (IsHostOffloadingAction) { - for (size_t i = 1; i < Inputs.size(); ++i) { - if (Inputs[i].getType() != types::TY_Nothing) - CmdArgs.push_back( - Args.MakeArgString("-fembed-offload-object=" + - getToolChain().getInputFilename(Inputs[i]))); + // adds other secondary input (e.g. device bitcode files for embedding to the + // -fembed-offload-object argument or the host ir file for proccessing + // during device compilation to the fopenmp-host-ir-file-path argument via + // OpenMPDeviceInput) This is condensed logic from the Clang driver + // for pushing on further input arguments needed for offloading + // during various phases of compilation. + for (size_t i = 1; i < Inputs.size(); ++i) { + if (Inputs[i].getType() == types::TY_Nothing) { + // contains nothing, so it's skippable + } else if (IsHostOffloadingAction) { + CmdArgs.push_back( + Args.MakeArgString("-fembed-offload-object=" + + getToolChain().getInputFilename(Inputs[i]))); + } else if (IsOpenMPDevice) { + if (Inputs[i].getFilename()) { + CmdArgs.push_back("-fopenmp-host-ir-file-path"); + CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); + } else { + llvm_unreachable("missing openmp host-ir file for device offloading"); + } + } else { + llvm_unreachable( + "unexpectedly given multiple inputs or given unknown input"); } } diff --git a/flang/include/flang/Frontend/LangOptions.h b/flang/include/flang/Frontend/LangOptions.h --- a/flang/include/flang/Frontend/LangOptions.h +++ b/flang/include/flang/Frontend/LangOptions.h @@ -15,6 +15,7 @@ #ifndef LLVM_FLANG_FRONTEND_LANGOPTIONS_H #define LLVM_FLANG_FRONTEND_LANGOPTIONS_H +#include namespace Fortran::frontend { /// Bitfields of LangOptions, split out from LangOptions to ensure @@ -52,6 +53,10 @@ void set##Name(Type Value) { Name = static_cast(Value); } #include "flang/Frontend/LangOptions.def" + /// Name of the IR file that contains the result of the OpenMP target + /// host code generation. + std::string OMPHostIRFile; + LangOptions(); }; diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -23,13 +23,14 @@ OffloadModuleOpts() {} OffloadModuleOpts(uint32_t OpenMPTargetDebug, bool OpenMPTeamSubscription, bool OpenMPThreadSubscription, bool OpenMPNoThreadState, - bool OpenMPNoNestedParallelism, bool OpenMPIsDevice) + bool OpenMPNoNestedParallelism, bool OpenMPIsDevice, + std::string OMPHostIRFile = {}) : OpenMPTargetDebug(OpenMPTargetDebug), OpenMPTeamSubscription(OpenMPTeamSubscription), OpenMPThreadSubscription(OpenMPThreadSubscription), OpenMPNoThreadState(OpenMPNoThreadState), OpenMPNoNestedParallelism(OpenMPNoNestedParallelism), - OpenMPIsDevice(OpenMPIsDevice) {} + OpenMPIsDevice(OpenMPIsDevice), OMPHostIRFile(OMPHostIRFile) {} OffloadModuleOpts(Fortran::frontend::LangOptions &Opts) : OpenMPTargetDebug(Opts.OpenMPTargetDebug), @@ -37,7 +38,8 @@ OpenMPThreadSubscription(Opts.OpenMPThreadSubscription), OpenMPNoThreadState(Opts.OpenMPNoThreadState), OpenMPNoNestedParallelism(Opts.OpenMPNoNestedParallelism), - OpenMPIsDevice(Opts.OpenMPIsDevice) {} + OpenMPIsDevice(Opts.OpenMPIsDevice), OMPHostIRFile(Opts.OMPHostIRFile) { + } uint32_t OpenMPTargetDebug = 0; bool OpenMPTeamSubscription = false; @@ -45,6 +47,7 @@ bool OpenMPNoThreadState = false; bool OpenMPNoNestedParallelism = false; bool OpenMPIsDevice = false; + std::string OMPHostIRFile = {}; }; // Shares assinging of the OpenMP OffloadModuleInterface and its assorted @@ -59,6 +62,9 @@ offloadMod.setFlags(Opts.OpenMPTargetDebug, Opts.OpenMPTeamSubscription, Opts.OpenMPThreadSubscription, Opts.OpenMPNoThreadState, Opts.OpenMPNoNestedParallelism); + + if (!Opts.OMPHostIRFile.empty()) + offloadMod.setHostIRFilePath(Opts.OMPHostIRFile); } } } 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 @@ -722,6 +722,16 @@ if (args.hasArg(clang::driver::options::OPT_fopenmp_is_device)) { res.getLangOpts().OpenMPIsDevice = 1; + // Get OpenMP host file path if any and report if a non existent file is + // found + if (auto *arg = args.getLastArg( + clang::driver::options::OPT_fopenmp_host_ir_file_path)) { + res.getLangOpts().OMPHostIRFile = arg->getValue(); + if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile)) + diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found) + << res.getLangOpts().OMPHostIRFile; + } + if (args.hasFlag( clang::driver::options::OPT_fopenmp_assume_teams_oversubscription, clang::driver::options:: 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 @@ -144,6 +144,8 @@ ! 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-host-ir-file-path +! HELP-FC1-NEXT: Path to the IR file produced by the frontend for the host. ! HELP-FC1-NEXT: -fopenmp-is-device Generate code only for an OpenMP target device. ! HELP-FC1-NEXT: -fopenmp-target-debug Enable debugging in the OpenMP offloading device RTL ! HELP-FC1-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code. diff --git a/flang/test/Driver/omp-frontend-forwarding.f90 b/flang/test/Driver/omp-frontend-forwarding.f90 --- a/flang/test/Driver/omp-frontend-forwarding.f90 +++ b/flang/test/Driver/omp-frontend-forwarding.f90 @@ -11,15 +11,15 @@ ! RUN: %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" -! Testing fembed-offload-object and fopenmp-is-device +! Testing appropriate flags are gnerated and appropriately assigned by the driver when offloading ! RUN: %flang -S -### %s -o %t 2>&1 \ ! RUN: -fopenmp --offload-arch=gfx90a \ ! RUN: --target=aarch64-unknown-linux-gnu \ -! RUN: | FileCheck %s --check-prefixes=CHECK-OPENMP-EMBED -! CHECK-OPENMP-EMBED: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu" {{.*}} "-fopenmp" {{.*}}.f90" -! CHECK-OPENMP-EMBED-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "amdgcn-amd-amdhsa" {{.*}} "-fopenmp" {{.*}} "-fopenmp-is-device" {{.*}}.f90" -! CHECK-OPENMP-EMBED: "{{[^"]*}}clang-offload-packager{{.*}} "--image=file={{.*}}.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp" -! CHECK-OPENMP-EMBED-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu" {{.*}} "-fopenmp" {{.*}} "-fembed-offload-object={{.*}}.out" {{.*}}.bc" +! RUN: | FileCheck %s --check-prefix=OPENMP-OFFLOAD-ARGS +! OPENMP-OFFLOAD-ARGS: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu" {{.*}} "-fopenmp" {{.*}}.f90" +! OPENMP-OFFLOAD-ARGS-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "amdgcn-amd-amdhsa" {{.*}} "-fopenmp" {{.*}} "-fopenmp-host-ir-file-path" "{{.*}}.bc" "-fopenmp-is-device" {{.*}}.f90" +! OPENMP-OFFLOAD-ARGS: "{{[^"]*}}clang-offload-packager" {{.*}} "--image=file={{.*}}.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp" +! OPENMP-OFFLOAD-ARGS-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu" {{.*}} "-fopenmp" {{.*}} "-fembed-offload-object={{.*}}.out" {{.*}}.bc" ! Test -fopenmp with offload for RTL Flag Options ! RUN: %flang -### %s -o %t 2>&1 \ diff --git a/flang/test/Lower/OpenMP/omp-host-ir-flag.f90 b/flang/test/Lower/OpenMP/omp-host-ir-flag.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-host-ir-flag.f90 @@ -0,0 +1,6 @@ +!RUN: %flang_fc1 -emit-llvm-bc -fopenmp -o %t.bc %s 2>&1 +!RUN: %flang_fc1 -emit-mlir -fopenmp -fopenmp-is-device -fopenmp-host-ir-file-path %t.bc -o - %s 2>&1 | FileCheck %s + +!CHECK: module attributes {{{.*}}, omp.host_ir_filepath = "{{.*}}.bc", omp.is_device = #omp.isdevice{{.*}}} +subroutine omp_subroutine() +end subroutine omp_subroutine \ No newline at end of file diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td @@ -71,7 +71,7 @@ InterfaceMethod< /*description=*/[{ Get the IsDeviceAttr attribute on the current module if it exists and return - its value, if it doesn't exit it returns false by default. + its value, if it doesn't exist it returns false by default. }], /*retTy=*/"bool", /*methodName=*/"getIsDevice", @@ -138,6 +138,34 @@ targetCPU.str(), targetFeatures.str())); }]>, + InterfaceMethod< + /*description=*/[{ + Set a StringAttr on the current module containing the host IR file path. This + file path is used in two-phase compilation during the device phase to generate + device side LLVM IR when lowering MLIR. + }], + /*retTy=*/"void", + /*methodName=*/"setHostIRFilePath", + (ins "std::string":$hostIRFilePath), [{}], [{ + $_op->setAttr( + mlir::StringAttr::get($_op->getContext(), llvm::Twine{"omp.host_ir_filepath"}), + mlir::StringAttr::get($_op->getContext(), hostIRFilePath)); + }]>, + InterfaceMethod< + /*description=*/[{ + Find the host-ir file path StringAttr from the current module if it exists and + return its contained value, if it doesn't exist it returns an empty string. This + file path is used in two-phase compilation during the device phase to generate + device side LLVM IR when lowering MLIR. + }], + /*retTy=*/"llvm::StringRef", + /*methodName=*/"getHostIRFilePath", + (ins), [{}], [{ + if (Attribute filepath = $_op->getAttr("omp.host_ir_filepath")) + if (filepath.isa()) + return filepath.dyn_cast().getValue(); + return {}; + }]> ]; }