From: Chuanqi Xu Date: Wed, 28 Dec 2022 05:48:08 +0000 (+0800) Subject: [Driver] [Modules] Support -fmodule-output (1/2) X-Git-Tag: upstream/17.0.6~20859 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f89327e28bc17a1d80fd5523520e62d8dd53c1cb;p=platform%2Fupstream%2Fllvm.git [Driver] [Modules] Support -fmodule-output (1/2) Patches to support the one-phase compilation model for modules. The behavior: (1) If -o and -c is specified , the module file is in the same path within the same directory as the output the -o specified and with a new suffix .pcm. (2) Otherwise, the module file is in the same path within the working directory directory with the name of the input file with a new suffix .pcm For example, ``` Hello.cppm Use.cpp ``` A trivial one and the contents are ignored. When we run: ``` clang++ -std=c++20 -fmodule-output Hello.cppm -c ``` The directory would look like: ``` Hello.cppm Hello.o Hello.pcm Use.cpp ``` And if we run: ``` clang++ -std=c++20 -fmodule-output Hello.cppm -c -o output/Hello.o ``` Then the `output` directory may look like: ``` Hello.o Hello.pcm ``` Reviewed By: dblaikie, iains, tahonermann Differential Revision: https://reviews.llvm.org/D137058 --- diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 61b7a161..08be696 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -489,6 +489,9 @@ def err_test_module_file_extension_format : Error< "-ftest-module-file-extension argument '%0' is not of the required form " "'blockname:major:minor:hashed:user info'">; +def err_drv_module_output_with_multiple_arch : Error< + "option '-fmodule-output' can't be used with multiple arch options">; + def err_drv_extract_api_wrong_kind : Error< "header file '%0' input '%1' does not match the type of prior input " "in api extraction; use '-x %2' to override">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 6cee51f..eaaaebf 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2306,6 +2306,9 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules", PosFlag, NegFlag, BothFlags<[NoXarchOption, CC1Option]>>; +def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption, CC1Option]>, + HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">; + def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">, diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index fe9e9bb..bc70a92 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -5553,6 +5553,30 @@ const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix, return C.addTempFile(C.getArgs().MakeArgString(TmpName)); } +// Calculate the output path of the module file when compiling a module unit +// with the `-fmodule-output` option specified. The behavior is: +// - If the output object file of the module unit is specified, the output path +// of the module file should be the same with the output object file except +// the corresponding suffix. This requires both `-o` and `-c` are specified. +// - Otherwise, the output path of the module file will be the same with the +// input with the corresponding suffix. +static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA, + const char *BaseInput) { + assert(isa(JA) && JA.getType() == types::TY_ModuleFile && + C.getArgs().hasArg(options::OPT_fmodule_output)); + + SmallString<64> OutputPath; + Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); + if (FinalOutput && C.getArgs().hasArg(options::OPT_c)) + OutputPath = FinalOutput->getValue(); + else + OutputPath = BaseInput; + + const char *Extension = types::getTypeTempSuffix(JA.getType()); + llvm::sys::path::replace_extension(OutputPath, Extension); + return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA); +} + const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, StringRef OrigBoundArch, bool AtTopLevel, @@ -5609,6 +5633,16 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, &JA); } + if (MultipleArchs && C.getArgs().hasArg(options::OPT_fmodule_output)) + Diag(clang::diag::err_drv_module_output_with_multiple_arch); + + // If we're emitting a module output with the specified option + // `-fmodule-output`. + if (!AtTopLevel && isa(JA) && + JA.getType() == types::TY_ModuleFile && + C.getArgs().hasArg(options::OPT_fmodule_output)) + return GetModuleOutputPath(C, JA, BaseInput); + // Output to a temporary file? if ((!AtTopLevel && !isSaveTempsEnabled() && !C.getArgs().hasArg(options::OPT__SLASH_Fo)) || @@ -5771,9 +5805,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, else llvm::sys::path::append(BasePath, NamedOutput); return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA); - } else { - return C.addResultFile(NamedOutput, &JA); } + + return C.addResultFile(NamedOutput, &JA); } std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { diff --git a/clang/test/Driver/lit.local.cfg b/clang/test/Driver/lit.local.cfg index d29c798..21d23ff 100644 --- a/clang/test/Driver/lit.local.cfg +++ b/clang/test/Driver/lit.local.cfg @@ -1,6 +1,6 @@ from lit.llvm import llvm_config -config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95', +config.suffixes = ['.c', '.cpp', '.cppm', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95', '.cu', '.rs', '.cl', '.clcpp', '.hip', '.hipi', '.hlsl'] config.substitutions = list(config.substitutions) config.substitutions.insert(0, diff --git a/clang/test/Driver/module-output.cppm b/clang/test/Driver/module-output.cppm new file mode 100644 index 0000000..2a9fb55 --- /dev/null +++ b/clang/test/Driver/module-output.cppm @@ -0,0 +1,33 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// Tests that the .pcm file will be generated in the same directory with the specified +// output and the name of the .pcm file should be the same with the input file. +// RUN: %clang -std=c++20 %t/Hello.cppm -fmodule-output -c -o %t/output/Hello.o \ +// RUN: -### 2>&1 | FileCheck %t/Hello.cppm +// +// Tests that the output file will be generated in the input directory if the output +// file is not the corresponding object file. +// RUN: %clang -std=c++20 %t/Hello.cppm %t/AnotherModule.cppm -fmodule-output -o \ +// RUN: %t/output/a.out -### 2>&1 | FileCheck %t/AnotherModule.cppm +// +// Tests that clang will reject the command line if it specifies -fmodule-output with +// multiple archs. +// RUN: %clang %t/Hello.cppm -fmodule-output -arch i386 -arch x86_64 -### -target \ +// RUN: x86_64-apple-darwin 2>&1 | FileCheck %t/Hello.cppm -check-prefix=MULTIPLE-ARCH + +//--- Hello.cppm +export module Hello; + +// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/output/Hello.pcm" "-x" "c++" "{{.*}}/Hello.cppm" +// CHECK: "-emit-obj" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/output/Hello.o" "-x" "pcm" "{{.*}}/output/Hello.pcm" + +// MULTIPLE-ARCH: option '-fmodule-output' can't be used with multiple arch options + +//--- AnotherModule.cppm +export module AnotherModule; +// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/Hello.pcm" "-x" "c++" "{{.*}}/Hello.cppm" +// CHECK: "-emit-obj" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/Hello-{{.*}}.o" "-x" "pcm" "{{.*}}/Hello.pcm" +// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "AnotherModule.cppm" {{.*}}"-o" "{{.*}}/AnotherModule.pcm" "-x" "c++" "{{.*}}/AnotherModule.cppm" +// CHECK: "-emit-obj" {{.*}}"-main-file-name" "AnotherModule.cppm" {{.*}}"-o" "{{.*}}/AnotherModule-{{.*}}.o" "-x" "pcm" "{{.*}}/AnotherModule.pcm"