https://github.com/yxsamliu updated https://github.com/llvm/llvm-project/pull/228096
>From f4d578919ca8e4a0c9eebfb27f65ad637e4ffda1 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <[email protected]> Date: Thu, 1 Oct 2026 10:17:45 -0400 Subject: [PATCH 1/4] [clang][HIP] Apply clang-cl optimization options to device code clang-cl options such as /O1, /O2, and /Ox currently optimize only host code in HIP builds, leaving device code unoptimized. Translate these options before separating host and device arguments so both compilations receive the requested optimization settings. --- clang/docs/ReleaseNotes.md | 3 + clang/include/clang/Driver/Driver.h | 3 +- clang/lib/Driver/Driver.cpp | 130 +++++++++++++++++++++- clang/lib/Driver/ToolChains/MSVC.cpp | 130 +--------------------- clang/test/Driver/cl-options.cu | 7 ++ clang/test/Driver/hip-cl-optimization.hip | 106 ++++++++++++++++++ 6 files changed, 247 insertions(+), 132 deletions(-) create mode 100644 clang/test/Driver/hip-cl-optimization.hip diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index d22874d4130eec..4fdefafccea14d 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -815,6 +815,9 @@ features cannot lower the translation-unit ABI level; #### Miscellaneous Bug Fixes +- Fixed `clang-cl` optimization options such as `/O1`, `/O2`, and + `/Ox` being ignored when compiling HIP device code. + #### Miscellaneous Clang Crashes Fixed - Fixed a crash in CTAD for type alias templates when the aggregate deduction guide could not be resolved. (#GH206994) diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 15b6fdcb8a5746..914ef62cd62fa9 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -360,7 +360,8 @@ class Driver { /// TranslateInputArgs - Create a new derived argument list from the input /// arguments, after applying the standard argument translations. llvm::opt::DerivedArgList * - TranslateInputArgs(const llvm::opt::InputArgList &Args) const; + TranslateInputArgs(const llvm::opt::InputArgList &Args, + const llvm::Triple &Triple) const; // handleArguments - All code related to claiming and printing diagnostics // related to arguments to the driver are done here. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7649941a68b1cc..07f70fbbe0128c 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -459,10 +459,128 @@ Arg *clang::driver::makeInputArg(DerivedArgList &Args, const OptTable &Opts, return A; } -DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { +static void translateMSVCOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, + bool SupportsForcingFramePointer, + const char *ExpandChar, const OptTable &Opts) { + assert(A->getOption().matches(options::OPT__SLASH_O)); + + StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + const char &OptChar = *(OptStr.data() + I); + switch (OptChar) { + default: + break; + case '1': + case '2': + case 'x': + case 'd': + // Ignore /O[12xd] flags that aren't the last one on the command line. + // Only the last one gets expanded. + if (&OptChar != ExpandChar) { + A->claim(); + break; + } + if (OptChar == 'd') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); + } else { + if (OptChar == '1') { + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + } else if (OptChar == '2' || OptChar == 'x') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); + } + if (SupportsForcingFramePointer && + !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + if (OptChar == '1' || OptChar == '2') + DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); + } + break; + case 'b': + if (I + 1 != E && isdigit(OptStr[I + 1])) { + switch (OptStr[I + 1]) { + case '0': + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); + break; + case '1': + DAL.AddFlagArg(A, + Opts.getOption(options::OPT_finline_hint_functions)); + break; + case '2': + case '3': + DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); + break; + } + ++I; + } + break; + case 'g': + A->claim(); + break; + case 'i': + if (I + 1 != E && OptStr[I + 1] == '-') { + ++I; + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); + } else { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + } + break; + case 's': + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + break; + case 't': + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); + break; + case 'y': { + bool OmitFramePointer = true; + if (I + 1 != E && OptStr[I + 1] == '-') { + OmitFramePointer = false; + ++I; + } + if (SupportsForcingFramePointer) { + if (OmitFramePointer) + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + else + DAL.AddFlagArg(A, + Opts.getOption(options::OPT_fno_omit_frame_pointer)); + } else { + // Silently accept /Oy- on x86-64 for portable clang-cl build flags. + A->claim(); + } + break; + } + } + } +} + +DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args, + const llvm::Triple &Triple) const { const llvm::opt::OptTable &Opts = getOpts(); DerivedArgList *DAL = new DerivedArgList(Args); + // Normalize MSVC optimization options before host and device arguments split. + bool TranslateMSVCOpts = Triple.isWindowsMSVCEnvironment(); + // /Oy and /Oy- do not affect the x86-64 host. + bool SupportsForcingFramePointer = Triple.getArch() != llvm::Triple::x86_64; + // Expand only the last /O[12xd], preserving overrides such as /O2 /Oy-. + const char *ExpandChar = nullptr; + if (TranslateMSVCOpts) { + for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { + StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + char OptChar = OptStr[I]; + char PrevChar = I > 0 ? OptStr[I - 1] : '0'; + if (PrevChar == 'b') { + // OptChar does not expand; it's an argument to the previous char. + continue; + } + if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || + OptChar == 'd') + ExpandChar = OptStr.data() + I; + } + } + } + bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx); bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs); @@ -480,6 +598,14 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { continue; } + if (TranslateMSVCOpts && A->getOption().matches(options::OPT__SLASH_O)) { + // Keep the original argument for unused-option diagnostics. + DAL->append(A); + translateMSVCOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, + Opts); + continue; + } + // Unfortunately, we have to parse some forwarding options (-Xassembler, // -Xlinker, -Xpreprocessor) because we either integrate their functionality // (assembler and preprocessor), or bypass a previous driver ('collect2'). @@ -1783,7 +1909,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } // Perform the default argument translations. - DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); + DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs, TC.getTriple()); // Check if the environment version is valid except wasm case. llvm::Triple Triple = TC.getTriple(); diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 25ea64a4ba5055..d32d5b9a52fc94 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -1023,103 +1023,6 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers( return Res; } -static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, - bool SupportsForcingFramePointer, - const char *ExpandChar, const OptTable &Opts) { - assert(A->getOption().matches(options::OPT__SLASH_O)); - - StringRef OptStr = A->getValue(); - for (size_t I = 0, E = OptStr.size(); I != E; ++I) { - const char &OptChar = *(OptStr.data() + I); - switch (OptChar) { - default: - break; - case '1': - case '2': - case 'x': - case 'd': - // Ignore /O[12xd] flags that aren't the last one on the command line. - // Only the last one gets expanded. - if (&OptChar != ExpandChar) { - A->claim(); - break; - } - if (OptChar == 'd') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); - } else { - if (OptChar == '1') { - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); - } else if (OptChar == '2' || OptChar == 'x') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); - } - if (SupportsForcingFramePointer && - !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); - if (OptChar == '1' || OptChar == '2') - DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); - } - break; - case 'b': - if (I + 1 != E && isdigit(OptStr[I + 1])) { - switch (OptStr[I + 1]) { - case '0': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); - break; - case '1': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); - break; - case '2': - case '3': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); - break; - } - ++I; - } - break; - case 'g': - A->claim(); - break; - case 'i': - if (I + 1 != E && OptStr[I + 1] == '-') { - ++I; - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); - } else { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - } - break; - case 's': - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); - break; - case 't': - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); - break; - case 'y': { - bool OmitFramePointer = true; - if (I + 1 != E && OptStr[I + 1] == '-') { - OmitFramePointer = false; - ++I; - } - if (SupportsForcingFramePointer) { - if (OmitFramePointer) - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_fomit_frame_pointer)); - else - DAL.AddFlagArg( - A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); - } else { - // Don't warn about /Oy- in x86-64 builds (where - // SupportsForcingFramePointer is false). The flag having no effect - // there is a compiler-internal optimization, and people shouldn't have - // to special-case their build files for x86-64 clang-cl. - A->claim(); - } - break; - } - } - } -} - static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, const OptTable &Opts) { assert(A->getOption().matches(options::OPT_D)); @@ -1154,39 +1057,8 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); - // /Oy and /Oy- don't have an effect on X86-64 - bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64; - - // The -O[12xd] flag actually expands to several flags. We must desugar the - // flags so that options embedded can be negated. For example, the '-O2' flag - // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to - // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single - // aspect of '-O2'. - // - // Note that this expansion logic only applies to the *last* of '[12xd]'. - - // First step is to search for the character we'd like to expand. - const char *ExpandChar = nullptr; - for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { - StringRef OptStr = A->getValue(); - for (size_t I = 0, E = OptStr.size(); I != E; ++I) { - char OptChar = OptStr[I]; - char PrevChar = I > 0 ? OptStr[I - 1] : '0'; - if (PrevChar == 'b') { - // OptChar does not expand; it's an argument to the previous char. - continue; - } - if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') - ExpandChar = OptStr.data() + I; - } - } - for (Arg *A : Args) { - if (A->getOption().matches(options::OPT__SLASH_O)) { - // The -O flag actually takes an amalgam of other options. For example, - // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. - TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts); - } else if (A->getOption().matches(options::OPT_D)) { + if (A->getOption().matches(options::OPT_D)) { // Translate -Dfoo#bar into -Dfoo=bar. TranslateDArg(A, *DAL, Opts); } else if (A->getOption().matches(options::OPT__SLASH_permissive)) { diff --git a/clang/test/Driver/cl-options.cu b/clang/test/Driver/cl-options.cu index b241ec6672d851..2517e7d77d4a9e 100644 --- a/clang/test/Driver/cl-options.cu +++ b/clang/test/Driver/cl-options.cu @@ -25,3 +25,10 @@ // Gd-NOT: "-fdefault-calling-conv=cdecl" // Gd: "-cc1" "-triple" // Gd: "-fdefault-calling-conv=cdecl" + +// Optimization options must continue to apply to both CUDA compilation jobs. +// RUN: not %clang_cl /c /O2 -### -nocudalib -nocudainc -- %s 2>&1 | FileCheck -check-prefix=O2 %s +// O2: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda" +// O2-SAME: "-O3" +// O2: "-cc1" "-triple" +// O2-SAME: "-O3" diff --git a/clang/test/Driver/hip-cl-optimization.hip b/clang/test/Driver/hip-cl-optimization.hip new file mode 100644 index 00000000000000..3a3720f0a5c67f --- /dev/null +++ b/clang/test/Driver/hip-cl-optimization.hip @@ -0,0 +1,106 @@ +// Check that clang-cl optimization options apply to both host and device. +// Device-specific options must still override the shared optimization level. + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=OS + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /Ox -- %s 2>&1 | FileCheck %s --check-prefix=O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /Od -- %s 2>&1 | FileCheck %s --check-prefix=O0 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 /Od -- %s 2>&1 | FileCheck %s --check-prefix=O0 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /Od /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 -clang:-O1 -- %s 2>&1 | FileCheck %s --check-prefix=O1 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 -clang:-Xarch_device -clang:-O1 -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-O1 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 /Ob0 -- %s 2>&1 | FileCheck %s --check-prefix=NOINLINE + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=OS + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /Ox -- %s 2>&1 | FileCheck %s --check-prefix=O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /Od -- %s 2>&1 | FileCheck %s --check-prefix=O0 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 /Od -- %s 2>&1 | FileCheck %s --check-prefix=O0 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /Od /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 -clang:-O1 -- %s 2>&1 | FileCheck %s --check-prefix=O1 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 -clang:-Xarch_device -clang:-O1 -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-O1 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O2 /Ob0 -- %s 2>&1 | FileCheck %s --check-prefix=NOINLINE + +// OS: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// OS-SAME: "-Os" +// OS: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// OS-SAME: "-Os" + +// O3: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// O3-SAME: "-O3" +// O3: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// O3-SAME: "-O3" + +// O0: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// O0-SAME: "-O0" +// O0: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// O0-SAME: "-O0" + +// O1: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// O1-SAME: "-O1" +// O1: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// O1-SAME: "-O1" + +// DEVICE-O1: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// DEVICE-O1-SAME: "-O1" +// DEVICE-O1: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// DEVICE-O1-SAME: "-O3" + +// NOINLINE: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// NOINLINE-SAME: "-O3" +// NOINLINE-SAME: "-fno-inline" +// NOINLINE: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// NOINLINE-SAME: "-O3" +// NOINLINE-SAME: "-fno-inline" >From c437113e897dce7106e7a3fa7ca21dbd8e19b781 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <[email protected]> Date: Fri, 2 Oct 2026 10:21:12 -0400 Subject: [PATCH 2/4] [clang] Extract shared clang-cl optimization translation Keep clang-cl optimization parsing in an internal helper while the driver normalizes options before host and device arguments are split. Select translation by clang-cl mode so Linux and MinGW host toolchains also receive the canonical optimization options. --- clang/docs/ReleaseNotes.md | 3 +- clang/lib/Driver/CMakeLists.txt | 1 + clang/lib/Driver/ClangCLArgs.cpp | 139 ++++++++++++++++++++++ clang/lib/Driver/ClangCLArgs.h | 41 +++++++ clang/lib/Driver/Driver.cpp | 127 +------------------- clang/test/Driver/cl-options.c | 9 ++ clang/test/Driver/hip-cl-optimization.hip | 13 ++ 7 files changed, 210 insertions(+), 123 deletions(-) create mode 100644 clang/lib/Driver/ClangCLArgs.cpp create mode 100644 clang/lib/Driver/ClangCLArgs.h diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 4fdefafccea14d..4d46ed3b646afc 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -816,7 +816,8 @@ features cannot lower the translation-unit ABI level; #### Miscellaneous Bug Fixes - Fixed `clang-cl` optimization options such as `/O1`, `/O2`, and - `/Ox` being ignored when compiling HIP device code. + `/Ox` being ignored when compiling HIP device code or using a non-MSVC + host toolchain. #### Miscellaneous Clang Crashes Fixed diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 506536cdc04f5f..c33dfd2471f35a 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -24,6 +24,7 @@ endif() add_clang_library(clangDriver Action.cpp + ClangCLArgs.cpp Compilation.cpp CreateASTUnitFromArgs.cpp CreateInvocationFromArgs.cpp diff --git a/clang/lib/Driver/ClangCLArgs.cpp b/clang/lib/Driver/ClangCLArgs.cpp new file mode 100644 index 00000000000000..64ff6adefd2567 --- /dev/null +++ b/clang/lib/Driver/ClangCLArgs.cpp @@ -0,0 +1,139 @@ +//===--- ClangCLArgs.cpp - clang-cl arguments -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ClangCLArgs.h" +#include "clang/Options/Options.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include "llvm/TargetParser/Triple.h" +#include <cstddef> + +using namespace clang; +using namespace clang::driver; +using namespace llvm::opt; + +ClangCLArgs::ClangCLArgs(const ArgList &Args, const llvm::Triple &HostTriple) + : SupportsForcingFramePointer(HostTriple.getArch() != + llvm::Triple::x86_64) { + // Expand only the last /O[12xd], preserving overrides such as /O2 /Oy-. + for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { + llvm::StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + char OptChar = OptStr[I]; + char PrevChar = I > 0 ? OptStr[I - 1] : '0'; + if (PrevChar == 'b') { + // OptChar does not expand; it's an argument to the previous char. + continue; + } + if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') + ExpandChar = OptStr.data() + I; + } + } +} + +bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL) const { + if (!A->getOption().matches(options::OPT__SLASH_O)) + return false; + + // Keep the original argument for unused-option diagnostics. + DAL.append(A); + const OptTable &Opts = getDriverOptTable(); + + llvm::StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + const char &OptChar = *(OptStr.data() + I); + switch (OptChar) { + default: + break; + case '1': + case '2': + case 'x': + case 'd': + // Ignore /O[12xd] flags that aren't the last one on the command line. + // Only the last one gets expanded. + if (&OptChar != ExpandChar) { + A->claim(); + break; + } + if (OptChar == 'd') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); + } else { + if (OptChar == '1') { + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + } else if (OptChar == '2' || OptChar == 'x') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); + } + if (SupportsForcingFramePointer && + !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + if (OptChar == '1' || OptChar == '2') + DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); + } + break; + case 'b': + if (I + 1 != E && llvm::isDigit(OptStr[I + 1])) { + switch (OptStr[I + 1]) { + case '0': + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); + break; + case '1': + DAL.AddFlagArg(A, + Opts.getOption(options::OPT_finline_hint_functions)); + break; + case '2': + case '3': + DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); + break; + } + ++I; + } + break; + case 'g': + A->claim(); + break; + case 'i': + if (I + 1 != E && OptStr[I + 1] == '-') { + ++I; + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); + } else { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + } + break; + case 's': + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + break; + case 't': + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); + break; + case 'y': { + bool OmitFramePointer = true; + if (I + 1 != E && OptStr[I + 1] == '-') { + OmitFramePointer = false; + ++I; + } + if (SupportsForcingFramePointer) { + if (OmitFramePointer) + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + else + DAL.AddFlagArg(A, + Opts.getOption(options::OPT_fno_omit_frame_pointer)); + } else { + // Silently accept /Oy- on x86-64 for portable clang-cl build flags. + A->claim(); + } + break; + } + } + } + return true; +} diff --git a/clang/lib/Driver/ClangCLArgs.h b/clang/lib/Driver/ClangCLArgs.h new file mode 100644 index 00000000000000..fbfd24064fa814 --- /dev/null +++ b/clang/lib/Driver/ClangCLArgs.h @@ -0,0 +1,41 @@ +//===--- ClangCLArgs.h - clang-cl arguments ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_CLANGCLARGS_H +#define LLVM_CLANG_LIB_DRIVER_CLANGCLARGS_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { +class Triple; +namespace opt { +class Arg; +class ArgList; +class DerivedArgList; +} // namespace opt +} // namespace llvm + +namespace clang::driver { + +/// Translate clang-cl options before host and device arguments are split. +class LLVM_LIBRARY_VISIBILITY ClangCLArgs { + const char *ExpandChar = nullptr; + bool SupportsForcingFramePointer; + +public: + /// The argument values must outlive this translator. + ClangCLArgs(const llvm::opt::ArgList &Args, const llvm::Triple &HostTriple); + + /// Append A and its canonical expansion to DAL. Return false without + /// modifying DAL if A is not handled. + bool translateArg(llvm::opt::Arg *A, llvm::opt::DerivedArgList &DAL) const; +}; + +} // namespace clang::driver + +#endif // LLVM_CLANG_LIB_DRIVER_CLANGCLARGS_H diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 07f70fbbe0128c..20d5520fa03b3d 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Driver.h" +#include "ClangCLArgs.h" #include "ToolChains/AIX.h" #include "ToolChains/AMDGPU.h" #include "ToolChains/AVR.h" @@ -459,127 +460,14 @@ Arg *clang::driver::makeInputArg(DerivedArgList &Args, const OptTable &Opts, return A; } -static void translateMSVCOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, - bool SupportsForcingFramePointer, - const char *ExpandChar, const OptTable &Opts) { - assert(A->getOption().matches(options::OPT__SLASH_O)); - - StringRef OptStr = A->getValue(); - for (size_t I = 0, E = OptStr.size(); I != E; ++I) { - const char &OptChar = *(OptStr.data() + I); - switch (OptChar) { - default: - break; - case '1': - case '2': - case 'x': - case 'd': - // Ignore /O[12xd] flags that aren't the last one on the command line. - // Only the last one gets expanded. - if (&OptChar != ExpandChar) { - A->claim(); - break; - } - if (OptChar == 'd') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); - } else { - if (OptChar == '1') { - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); - } else if (OptChar == '2' || OptChar == 'x') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); - } - if (SupportsForcingFramePointer && - !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); - if (OptChar == '1' || OptChar == '2') - DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); - } - break; - case 'b': - if (I + 1 != E && isdigit(OptStr[I + 1])) { - switch (OptStr[I + 1]) { - case '0': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); - break; - case '1': - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_finline_hint_functions)); - break; - case '2': - case '3': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); - break; - } - ++I; - } - break; - case 'g': - A->claim(); - break; - case 'i': - if (I + 1 != E && OptStr[I + 1] == '-') { - ++I; - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); - } else { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - } - break; - case 's': - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); - break; - case 't': - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); - break; - case 'y': { - bool OmitFramePointer = true; - if (I + 1 != E && OptStr[I + 1] == '-') { - OmitFramePointer = false; - ++I; - } - if (SupportsForcingFramePointer) { - if (OmitFramePointer) - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); - else - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_fno_omit_frame_pointer)); - } else { - // Silently accept /Oy- on x86-64 for portable clang-cl build flags. - A->claim(); - } - break; - } - } - } -} - DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args, const llvm::Triple &Triple) const { const llvm::opt::OptTable &Opts = getOpts(); DerivedArgList *DAL = new DerivedArgList(Args); - // Normalize MSVC optimization options before host and device arguments split. - bool TranslateMSVCOpts = Triple.isWindowsMSVCEnvironment(); - // /Oy and /Oy- do not affect the x86-64 host. - bool SupportsForcingFramePointer = Triple.getArch() != llvm::Triple::x86_64; - // Expand only the last /O[12xd], preserving overrides such as /O2 /Oy-. - const char *ExpandChar = nullptr; - if (TranslateMSVCOpts) { - for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { - StringRef OptStr = A->getValue(); - for (size_t I = 0, E = OptStr.size(); I != E; ++I) { - char OptChar = OptStr[I]; - char PrevChar = I > 0 ? OptStr[I - 1] : '0'; - if (PrevChar == 'b') { - // OptChar does not expand; it's an argument to the previous char. - continue; - } - if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || - OptChar == 'd') - ExpandChar = OptStr.data() + I; - } - } - } + std::optional<ClangCLArgs> CLArgs; + if (IsCLMode()) + CLArgs.emplace(Args, Triple); bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx); @@ -598,13 +486,8 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args, continue; } - if (TranslateMSVCOpts && A->getOption().matches(options::OPT__SLASH_O)) { - // Keep the original argument for unused-option diagnostics. - DAL->append(A); - translateMSVCOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, - Opts); + if (CLArgs && CLArgs->translateArg(A, *DAL)) continue; - } // Unfortunately, we have to parse some forwarding options (-Xassembler, // -Xlinker, -Xpreprocessor) because we either integrate their functionality diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 57d82622ef4de6..b1d0ccbf60f0de 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -184,6 +184,15 @@ // RUN: %clang_cl /Od -### -- %s 2>&1 | FileCheck -check-prefix=Od %s // Od: -O0 +// clang-cl optimization options are independent of the host toolchain. +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /O1 -### -- %s 2>&1 | FileCheck %s --check-prefix=CL-LINUX-OS +// CL-LINUX-OS: "-cc1" +// CL-LINUX-OS-SAME: "-Os" + +// RUN: %clang_cl --target=x86_64-w64-windows-gnu /O2 -### -- %s 2>&1 | FileCheck %s --check-prefix=CL-MINGW-O3 +// CL-MINGW-O3: "-cc1" +// CL-MINGW-O3-SAME: "-O3" + // RUN: %clang_cl /Oi- /Oi -### -- %s 2>&1 | FileCheck -check-prefix=Oi %s // Oi-NOT: -fno-builtin diff --git a/clang/test/Driver/hip-cl-optimization.hip b/clang/test/Driver/hip-cl-optimization.hip index 3a3720f0a5c67f..1fa80de854e566 100644 --- a/clang/test/Driver/hip-cl-optimization.hip +++ b/clang/test/Driver/hip-cl-optimization.hip @@ -5,6 +5,10 @@ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=OS +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=LINUX + // RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 @@ -41,6 +45,10 @@ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=OS +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=LINUX + // RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 @@ -78,6 +86,11 @@ // OS: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" // OS-SAME: "-Os" +// LINUX: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// LINUX-SAME: "-Os" +// LINUX: "-cc1" "-triple" "x86_64-unknown-linux-gnu" +// LINUX-SAME: "-Os" + // O3: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" // O3-SAME: "-O3" // O3: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" >From 21a546f5f4ea283212ebd9c708ede29e65fb4158 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <[email protected]> Date: Fri, 2 Oct 2026 12:34:42 -0400 Subject: [PATCH 3/4] [clang] Move remaining MSVC argument translation to ClangCLArgs Normalize macro separators and /permissive options for both host and device compilations, and remove MSVCToolChain::TranslateArgs. Preserve late OpenMP and Xarch arguments, optimization bundle precedence, and synthesized argument ownership during per-toolchain filtering. --- clang/docs/ReleaseNotes.md | 4 +- clang/lib/Driver/ClangCLArgs.cpp | 99 +++++++++++++--- clang/lib/Driver/ClangCLArgs.h | 24 +++- clang/lib/Driver/Compilation.cpp | 12 ++ clang/lib/Driver/Driver.cpp | 12 ++ clang/lib/Driver/ToolChain.cpp | 15 +++ clang/lib/Driver/ToolChains/MSVC.cpp | 53 --------- clang/lib/Driver/ToolChains/MSVC.h | 4 - clang/test/Driver/cl-argument-translation.c | 58 +++++++++ clang/test/Driver/cl-options.cu | 16 +++ .../Driver/hip-cl-argument-translation.hip | 107 +++++++++++++++++ .../Driver/openmp-cl-argument-translation.cpp | 111 ++++++++++++++++++ 12 files changed, 434 insertions(+), 81 deletions(-) create mode 100644 clang/test/Driver/cl-argument-translation.c create mode 100644 clang/test/Driver/hip-cl-argument-translation.hip create mode 100644 clang/test/Driver/openmp-cl-argument-translation.cpp diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 4d46ed3b646afc..f6f0e9bb88d639 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -817,7 +817,9 @@ features cannot lower the translation-unit ABI level; - Fixed `clang-cl` optimization options such as `/O1`, `/O2`, and `/Ox` being ignored when compiling HIP device code or using a non-MSVC - host toolchain. + host toolchain. Macro definitions using `#` as the value separator and + `/permissive` options are also translated consistently for host and device + compilation. #### Miscellaneous Clang Crashes Fixed diff --git a/clang/lib/Driver/ClangCLArgs.cpp b/clang/lib/Driver/ClangCLArgs.cpp index 64ff6adefd2567..a06d1983da3d54 100644 --- a/clang/lib/Driver/ClangCLArgs.cpp +++ b/clang/lib/Driver/ClangCLArgs.cpp @@ -16,6 +16,7 @@ #include "llvm/Option/Option.h" #include "llvm/TargetParser/Triple.h" #include <cstddef> +#include <string> using namespace clang; using namespace clang::driver; @@ -40,13 +41,33 @@ ClangCLArgs::ClangCLArgs(const ArgList &Args, const llvm::Triple &HostTriple) } } -bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL) const { +bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL, + const DerivedArgList *Owner) const { + const DerivedArgList &SynthesizedArgs = Owner ? *Owner : DAL; + const Arg *BaseArg = &A->getBaseArg(); + const OptTable &Opts = getDriverOptTable(); + switch (A->getOption().getID()) { + case options::OPT__SLASH_permissive: + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fdelayed_template_parsing))); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fno_operator_names))); + return true; + case options::OPT__SLASH_permissive_: + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fno_delayed_template_parsing))); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_foperator_names))); + return true; + default: + break; + } + if (!A->getOption().matches(options::OPT__SLASH_O)) return false; // Keep the original argument for unused-option diagnostics. DAL.append(A); - const OptTable &Opts = getDriverOptTable(); llvm::StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { @@ -65,34 +86,42 @@ bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL) const { break; } if (OptChar == 'd') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_O0))); } else { if (OptChar == '1') { - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + DAL.append(SynthesizedArgs.MakeJoinedArg( + BaseArg, Opts.getOption(options::OPT_O), "s")); } else if (OptChar == '2' || OptChar == 'x') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fbuiltin))); + DAL.append(SynthesizedArgs.MakeJoinedArg( + BaseArg, Opts.getOption(options::OPT_O), "3")); } if (SupportsForcingFramePointer && !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fomit_frame_pointer))); if (OptChar == '1' || OptChar == '2') - DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_ffunction_sections))); } break; case 'b': if (I + 1 != E && llvm::isDigit(OptStr[I + 1])) { switch (OptStr[I + 1]) { case '0': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fno_inline))); break; case '1': - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_finline_hint_functions)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_finline_hint_functions))); break; case '2': case '3': - DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_finline_functions))); break; } ++I; @@ -104,16 +133,20 @@ bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL) const { case 'i': if (I + 1 != E && OptStr[I + 1] == '-') { ++I; - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fno_builtin))); } else { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fbuiltin))); } break; case 's': - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + DAL.append(SynthesizedArgs.MakeJoinedArg( + BaseArg, Opts.getOption(options::OPT_O), "s")); break; case 't': - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3"); + DAL.append(SynthesizedArgs.MakeJoinedArg( + BaseArg, Opts.getOption(options::OPT_O), "3")); break; case 'y': { bool OmitFramePointer = true; @@ -123,10 +156,11 @@ bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL) const { } if (SupportsForcingFramePointer) { if (OmitFramePointer) - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fomit_frame_pointer))); else - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_fno_omit_frame_pointer)); + DAL.append(SynthesizedArgs.MakeFlagArg( + BaseArg, Opts.getOption(options::OPT_fno_omit_frame_pointer))); } else { // Silently accept /Oy- on x86-64 for portable clang-cl build flags. A->claim(); @@ -137,3 +171,30 @@ bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL) const { } return true; } + +DerivedArgList *ClangCLArgs::translateArgs(const DerivedArgList &Args, + const llvm::Triple &HostTriple, + const DerivedArgList &Owner) { + ClangCLArgs Translator(Args, HostTriple); + auto *DAL = new DerivedArgList(Args.getBaseArgs()); + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT__SLASH_O) && + A->getBaseArg().getOption().matches(options::OPT__SLASH_O)) + continue; + if (!Translator.translateArg(A, *DAL, &Owner)) + DAL->append(A); + } + return DAL; +} + +const char *ClangCLArgs::translateMacroDefinition(const char *Value, + const ArgList &Args) { + llvm::StringRef Val = Value; + size_t Hash = Val.find('#'); + if (Hash == llvm::StringRef::npos || Hash > Val.find('=')) + return Value; + + std::string NewVal = std::string(Val); + NewVal[Hash] = '='; + return Args.MakeArgString(NewVal); +} diff --git a/clang/lib/Driver/ClangCLArgs.h b/clang/lib/Driver/ClangCLArgs.h index fbfd24064fa814..c713be83a31e13 100644 --- a/clang/lib/Driver/ClangCLArgs.h +++ b/clang/lib/Driver/ClangCLArgs.h @@ -22,7 +22,7 @@ class DerivedArgList; namespace clang::driver { -/// Translate clang-cl options before host and device arguments are split. +/// Translate clang-cl options before and after offload argument filtering. class LLVM_LIBRARY_VISIBILITY ClangCLArgs { const char *ExpandChar = nullptr; bool SupportsForcingFramePointer; @@ -31,9 +31,25 @@ class LLVM_LIBRARY_VISIBILITY ClangCLArgs { /// The argument values must outlive this translator. ClangCLArgs(const llvm::opt::ArgList &Args, const llvm::Triple &HostTriple); - /// Append A and its canonical expansion to DAL. Return false without - /// modifying DAL if A is not handled. - bool translateArg(llvm::opt::Arg *A, llvm::opt::DerivedArgList &DAL) const; + /// Append the canonical translation of A to DAL. Return false without + /// modifying DAL if A is not handled. If supplied, Owner owns synthesized + /// arguments instead of DAL and must outlive its consumers. + bool translateArg(llvm::opt::Arg *A, llvm::opt::DerivedArgList &DAL, + const llvm::opt::DerivedArgList *Owner = nullptr) const; + + /// Translate a filtered list that may contain new clang-cl options, replacing + /// earlier /O expansions. The caller owns the returned list; Owner owns its + /// synthesized arguments and must outlive its consumers. + static llvm::opt::DerivedArgList * + translateArgs(const llvm::opt::DerivedArgList &Args, + const llvm::Triple &HostTriple, + const llvm::opt::DerivedArgList &Owner); + + /// Normalize MSVC's '#' macro separator, also used by Clang targeting MSVC + /// and by arguments parsed after host/device filtering. Any replacement + /// string has the lifetime of Args; otherwise return Value unchanged. + static const char *translateMacroDefinition(const char *Value, + const llvm::opt::ArgList &Args); }; } // namespace clang::driver diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index c81c4445a29f95..3ccfe60c520d92 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Compilation.h" +#include "ClangCLArgs.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/Action.h" #include "clang/Driver/CommonArgs.h" @@ -91,6 +92,17 @@ Compilation::getArgsForToolChain(const ToolChain *TC, BoundArch BA, delete OpenMPArgs; } + if (NewDAL && DeviceOffloadKind == Action::OFK_OpenMP && + (TheDriver.IsCLMode() || + DefaultToolChain.getTriple().isWindowsMSVCEnvironment())) { + // OpenMP forwarding can introduce clang-cl options after the shared + // translation. Keep synthesized arguments in the compilation-owned list. + auto *DAL = ClangCLArgs::translateArgs( + *NewDAL, DefaultToolChain.getTriple(), *TranslatedArgs); + delete NewDAL; + NewDAL = DAL; + } + if (!NewDAL) { Entry = TC->TranslateArgs(*TranslatedArgs, BA, DeviceOffloadKind); if (!Entry) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 20d5520fa03b3d..6b901118f9c7b1 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -489,6 +489,18 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args, if (CLArgs && CLArgs->translateArg(A, *DAL)) continue; + // Preserve MSVC macro syntax for Clang's other driver modes as well. + if ((CLArgs || Triple.isWindowsMSVCEnvironment()) && + A->getOption().matches(options::OPT_D)) { + const char *Value = + ClangCLArgs::translateMacroDefinition(A->getValue(), Args); + if (Value == A->getValue()) + DAL->append(A); + else + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_D), Value); + continue; + } + // Unfortunately, we have to parse some forwarding options (-Xassembler, // -Xlinker, -Xpreprocessor) because we either integrate their functionality // (assembler and preprocessor), or bypass a previous driver ('collect2'). diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 255a9c9602b540..2d7dc6e63534b2 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/ToolChain.h" +#include "ClangCLArgs.h" #include "ToolChains/Arch/AArch64.h" #include "ToolChains/Arch/AMDGPU.h" #include "ToolChains/Arch/ARM.h" @@ -2074,6 +2075,12 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( } XOpenMPTargetArg->setBaseArg(A); A = XOpenMPTargetArg.release(); + if (A->getOption().matches(options::OPT_D) && + (getDriver().IsCLMode() || + llvm::Triple(llvm::Triple::normalize(getDriver().getTargetTriple())) + .isWindowsMSVCEnvironment())) + A->getValues()[0] = + ClangCLArgs::translateMacroDefinition(A->getValue(), Args); AllocatedArgs.push_back(A); DAL->append(A); Modified = true; @@ -2154,6 +2161,14 @@ void ToolChain::TranslateXarchArgs( DAL->AddSynthesizedArg(A); else AllocatedArgs->push_back(A); + + // Forwarded macros are parsed after the shared input translation. + if (A->getOption().matches(options::OPT_D) && + (getDriver().IsCLMode() || + llvm::Triple(llvm::Triple::normalize(getDriver().getTargetTriple())) + .isWindowsMSVCEnvironment())) + A->getValues()[0] = + ClangCLArgs::translateMacroDefinition(A->getValue(), Args); } /// Match any triple recognized arch aliases. diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index d32d5b9a52fc94..8f4c8f89ce58f9 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -1023,59 +1023,6 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers( return Res; } -static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, - const OptTable &Opts) { - assert(A->getOption().matches(options::OPT_D)); - - StringRef Val = A->getValue(); - size_t Hash = Val.find('#'); - if (Hash == StringRef::npos || Hash > Val.find('=')) { - DAL.append(A); - return; - } - - std::string NewVal = std::string(Val); - NewVal[Hash] = '='; - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal); -} - -static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL, - const OptTable &Opts) { - DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_)); - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names)); -} - -static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL, - const OptTable &Opts) { - DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase)); - DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names)); -} - -llvm::opt::DerivedArgList * -MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - BoundArch BA, Action::OffloadKind OFK) const { - DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); - const OptTable &Opts = getDriver().getOpts(); - - for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_D)) { - // Translate -Dfoo#bar into -Dfoo=bar. - TranslateDArg(A, *DAL, Opts); - } else if (A->getOption().matches(options::OPT__SLASH_permissive)) { - // Expand /permissive - TranslatePermissive(A, *DAL, Opts); - } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) { - // Expand /permissive- - TranslatePermissiveMinus(A, *DAL, Opts); - } else if (OFK != Action::OFK_HIP) { - // HIP Toolchain translates input args by itself. - DAL->append(A); - } - } - - return DAL; -} - void MSVCToolChain::addClangTargetOptions( const ArgList &DriverArgs, ArgStringList &CC1Args, BoundArch BA, Action::OffloadKind DeviceOffloadKind) const { diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 8ff8b2815d8df7..90461a1443da31 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -61,10 +61,6 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, BoundArch BA, - Action::OffloadKind DeviceOffloadKind) const override; - UnwindTableLevel getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; diff --git a/clang/test/Driver/cl-argument-translation.c b/clang/test/Driver/cl-argument-translation.c new file mode 100644 index 00000000000000..e1758265fa8890 --- /dev/null +++ b/clang/test/Driver/cl-argument-translation.c @@ -0,0 +1,58 @@ +// clang-cl syntax is normalized independently of the target toolchain. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc /c -### /DFOO#7 /DBAR=a#b /DBAZ#a=b /DEMPTY# \ +// RUN: /DQUX#a#b -- %s 2>&1 | FileCheck %s --check-prefix=MACROS +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /c -### /DFOO#7 /DBAR=a#b /DBAZ#a=b /DEMPTY# \ +// RUN: /DQUX#a#b -- %s 2>&1 | FileCheck %s --check-prefix=MACROS +// RUN: %clang_cl --target=x86_64-w64-windows-gnu /c -### /DFOO#7 /DBAR=a#b /DBAZ#a=b /DEMPTY# \ +// RUN: /DQUX#a#b -- %s 2>&1 | FileCheck %s --check-prefix=MACROS +// MACROS: "-D" "FOO=7" "-D" "BAR=a#b" "-D" "BAZ=a=b" "-D" "EMPTY=" "-D" "QUX=a#b" + +// Preserve GNU-mode Clang's existing MSVC macro compatibility. +// RUN: %clang --target=x86_64-pc-windows-msvc -c -### -DFOO#7 -- %s 2>&1 | FileCheck %s --check-prefix=MSVC +// RUN: %clang --target=x86_64-unknown-linux-gnu -c -### -DFOO#7 -- %s 2>&1 | FileCheck %s --check-prefix=GNU +// MSVC: "-D" "FOO=7" +// GNU: "-D" "FOO#7" + +// Last-option precedence must include both slash and canonical options. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc /c -x c++ -### /permissive- /permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=PERMISSIVE +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /c -x c++ -### /permissive- /permissive -- %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=PERMISSIVE +// RUN: %clang_cl --target=x86_64-w64-windows-gnu /c -x c++ -### /permissive -- %s 2>&1 | FileCheck %s \ +// RUN: --check-prefix=PERMISSIVE +// PERMISSIVE: "-fno-operator-names" +// PERMISSIVE-SAME: "-fdelayed-template-parsing" + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc /c -x c++ -### /permissive /permissive- -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CONFORMING +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /c -x c++ -### /permissive /permissive- -- %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CONFORMING +// RUN: %clang_cl --target=x86_64-pc-windows-msvc /c -x c++ -### /permissive /Zc:twoPhase \ +// RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=CONFORMING +// /clang: arguments are appended after the other command-line arguments. +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /c -x c++ -### \ +// RUN: -clang:-fno-delayed-template-parsing -clang:-foperator-names /permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CONFORMING +// CONFORMING: "-cc1" +// CONFORMING-NOT: "-fno-operator-names" +// CONFORMING-NOT: "-fdelayed-template-parsing" + +// RUN: %clang --target=x86_64-pc-windows-msvc -c -### -Xarch_host -DFOO#7 -- %s 2>&1 | FileCheck %s \ +// RUN: --check-prefix=MSVC +// RUN: %clang --target=x86_64-windows-msvc -c -### -Xarch_host -DFOO#7 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=MSVC +// RUN: %clang --target=x86_64-win32 -c -### -Xarch_host -DFOO#7 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=MSVC +// RUN: %clang --target=x86_64-unknown-linux-gnu -c -### -Xarch_host -DFOO#7 -- %s 2>&1 | FileCheck %s \ +// RUN: --check-prefix=GNU +// RUN: %clang --target=x86_64-w64-windows-gnu -c -### -DFOO#7 -- %s 2>&1 | FileCheck %s --check-prefix=GNU + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /EP /DFOO#7 /DTRANSLATION_CHECK -- %s | FileCheck \ +// RUN: %s --check-prefix=PREPROCESS +// PREPROCESS: 7 +#ifdef TRANSLATION_CHECK +#if FOO != 7 +#error macro separator was not translated +#endif +FOO +#endif diff --git a/clang/test/Driver/cl-options.cu b/clang/test/Driver/cl-options.cu index 2517e7d77d4a9e..b373f4c7d0a031 100644 --- a/clang/test/Driver/cl-options.cu +++ b/clang/test/Driver/cl-options.cu @@ -32,3 +32,19 @@ // O2-SAME: "-O3" // O2: "-cc1" "-triple" // O2-SAME: "-O3" + +// Shared macros and language settings also reach CUDA without reintroducing +// the original macro alongside its translated value. +// RUN: not %clang_cl --target=x86_64-pc-windows-msvc -### /c \ +// RUN: --cuda-gpu-arch=sm_35 -nocudainc -nocudalib \ +// RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=CL-COMMON +// CL-COMMON: "-cc1" "-triple" "nvptx64-nvidia-cuda" +// CL-COMMON-SAME: "-D" "FOO=7" +// CL-COMMON-NOT: "FOO#7" +// CL-COMMON-NOT: "-fno-operator-names" +// CL-COMMON-NOT: "-fdelayed-template-parsing" +// CL-COMMON: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// CL-COMMON-SAME: "-D" "FOO=7" +// CL-COMMON-NOT: "FOO#7" +// CL-COMMON-NOT: "-fno-operator-names" +// CL-COMMON-NOT: "-fdelayed-template-parsing" diff --git a/clang/test/Driver/hip-cl-argument-translation.hip b/clang/test/Driver/hip-cl-argument-translation.hip new file mode 100644 index 00000000000000..e35201d37c2351 --- /dev/null +++ b/clang/test/Driver/hip-cl-argument-translation.hip @@ -0,0 +1,107 @@ +// Shared source-language options must reach both HIP jobs. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -- %s 2>&1 | FileCheck %s --check-prefix=PERMISSIVE + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#1 -clang:-Xarch_host -clang:-DFOO#2 -clang:-Xarch_device -clang:-DDEV#3 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=SCOPED + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ +// RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -- %s 2>&1 | FileCheck %s --check-prefix=PERMISSIVE + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#1 -clang:-Xarch_host -clang:-DFOO#2 -clang:-Xarch_device -clang:-DDEV#3 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=SCOPED + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ +// RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -- %s 2>&1 | FileCheck %s --check-prefix=PERMISSIVE + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#1 -clang:-Xarch_host -clang:-DFOO#2 -clang:-Xarch_device -clang:-DDEV#3 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=SCOPED + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ +// RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -- %s 2>&1 | FileCheck %s --check-prefix=PERMISSIVE + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /DFOO#1 -clang:-Xarch_host -clang:-DFOO#2 -clang:-Xarch_device -clang:-DDEV#3 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=SCOPED + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --no-offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ +// RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ +// RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING + +// COMMON: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// COMMON-SAME: "-D" "FOO=7" +// COMMON-NOT: "-fdelayed-template-parsing" +// COMMON-NOT: "-fno-operator-names" +// COMMON: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// COMMON-SAME: "-D" "FOO=7" +// COMMON-NOT: "-fdelayed-template-parsing" +// COMMON-NOT: "-fno-operator-names" + +// PERMISSIVE: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// PERMISSIVE-SAME: "-fno-operator-names" +// PERMISSIVE-SAME: "-fdelayed-template-parsing" +// PERMISSIVE: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// PERMISSIVE-SAME: "-fno-operator-names" +// PERMISSIVE-SAME: "-fdelayed-template-parsing" + +// SCOPED: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// SCOPED-SAME: "-D" "FOO=1" "-D" "DEV=3" +// SCOPED-NOT: "FOO=2" +// SCOPED: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// SCOPED-SAME: "-D" "FOO=1" "-D" "FOO=2" +// SCOPED-NOT: "DEV=3" + +// DEVICE-CONFORMING: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// DEVICE-CONFORMING-NOT: "-fno-operator-names" +// DEVICE-CONFORMING-NOT: "-fdelayed-template-parsing" +// DEVICE-CONFORMING: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// DEVICE-CONFORMING-SAME: "-fno-operator-names" +// DEVICE-CONFORMING-SAME: "-fdelayed-template-parsing" + +// GNU-mode offloading retains MSVC macro syntax when selected by the host. +// RUN: %clang --target=x86_64-pc-windows-msvc -### -c --offload-new-driver \ +// RUN: -x hip --offload-arch=gfx1100 -nogpuinc -nogpulib \ +// RUN: -DFOO#1 -Xarch_host -DFOO#2 -Xarch_device -DDEV#3 -- %s 2>&1 | FileCheck %s --check-prefix=SCOPED diff --git a/clang/test/Driver/openmp-cl-argument-translation.cpp b/clang/test/Driver/openmp-cl-argument-translation.cpp new file mode 100644 index 00000000000000..583db4718c9247 --- /dev/null +++ b/clang/test/Driver/openmp-cl-argument-translation.cpp @@ -0,0 +1,111 @@ +// OpenMP target arguments are parsed after the shared input translation. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:-DFOO#7 -- %s 2>&1 | FileCheck %s +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:-DFOO#7 -- %s 2>&1 | FileCheck %s +// RUN: %clang --target=x86_64-windows-msvc -### -c \ +// RUN: -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: --offload-arch=gfx1100 -nogpulib \ +// RUN: -Xopenmp-target=amdgcn-amd-amdhsa -DFOO#7 -- %s 2>&1 | FileCheck %s +// CHECK: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// CHECK-NOT: "FOO=7" +// CHECK: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// CHECK-SAME: "-D" "FOO=7" +// CHECK: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// CHECK-NOT: "FOO=7" + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=x86_64-pc-windows-msvc \ +// RUN: -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=x86_64-pc-windows-msvc -clang:/O2 \ +// RUN: -clang:-Xopenmp-target=x86_64-pc-windows-msvc -clang:/permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-O3 + +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/O2 \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-O3 + +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/O2 \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-O3 + +// DEVICE-O3: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// DEVICE-O3-NOT: "-O3" +// DEVICE-O3-NOT: "-fno-operator-names" +// DEVICE-O3: "-cc1" "-triple" "{{[^"]*}}" +// DEVICE-O3-SAME: "-O3" +// DEVICE-O3-SAME: "-fno-operator-names" +// DEVICE-O3-SAME: "-fdelayed-template-parsing" +// DEVICE-O3: "-cc1" "-triple" "x86_64-{{[^"]*}}" +// DEVICE-O3-NOT: "-O3" +// DEVICE-O3-NOT: "-fno-operator-names" +// DEVICE-O3-NOT: argument unused during compilation + +// A forwarded /Od must remove the other flags implied by shared /O2. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c /O2 /permissive \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/Od \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/permissive- -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-OD +// DEVICE-OD: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// DEVICE-OD-SAME: "-O3" +// DEVICE-OD-SAME: "-fno-operator-names" +// DEVICE-OD: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// DEVICE-OD-NOT: "-fbuiltin" +// DEVICE-OD-NOT: "-ffunction-sections" +// DEVICE-OD: "-O0" +// DEVICE-OD-NOT: "-O3" +// DEVICE-OD-NOT: "-fno-operator-names" +// DEVICE-OD-NOT: "-fdelayed-template-parsing" +// DEVICE-OD: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" + +// Repeated forwarded bundles use the last expandable option; explicit +// suboptions and canonical options still retain their parsed-list order. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/O2 \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/O1 \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/Ob0 \ +// RUN: -clang:-Xarch_device -clang:-O1 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-NATIVE +// DEVICE-NATIVE: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// DEVICE-NATIVE: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// DEVICE-NATIVE-NOT: "-Os" +// DEVICE-NATIVE-NOT: "-O3" +// DEVICE-NATIVE: "-O1" +// DEVICE-NATIVE-SAME: "-fno-inline" +// DEVICE-NATIVE: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" + +// GNU-mode Clang targeting MSVC also accepted these late slash options. +// RUN: %clang --target=x86_64-windows-msvc -### -c \ +// RUN: -fopenmp -fopenmp-targets=x86_64-pc-windows-msvc -nogpulib \ +// RUN: -Xopenmp-target=x86_64-pc-windows-msvc /O2 \ +// RUN: -Xopenmp-target=x86_64-pc-windows-msvc /permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-O3 + +// Separate device architecture argument lists retain their own overrides. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c /O2 \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100,gfx1101 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/O1 \ +// RUN: -clang:-Xarch_gfx1100 -clang:-O0 -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=MULTIARCH +// MULTIARCH: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// MULTIARCH-SAME: "-O3" +// MULTIARCH: "-cc1" "-triple" "amdgpu11.00-amd-amdhsa" +// MULTIARCH-SAME: "-O0" +// MULTIARCH: "-cc1" "-triple" "amdgpu11.01-amd-amdhsa" +// MULTIARCH-SAME: "-Os" +// MULTIARCH: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" >From 1551eb5afed5f37ba5575fc1bb2b1c7d905c6e29 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <[email protected]> Date: Sat, 3 Oct 2026 07:17:50 -0400 Subject: [PATCH 4/4] [clang] Use clang-cl mode for filtered argument translation Translate filtered argument lists in clang-cl mode regardless of the host toolchain or offload kind. Keep GNU-mode MSVC forwarded-option compatibility in the OpenMP parser using the same ClangCLArgs helper. Pass the resolved host triple to that parser so frame-pointer options respect -m32 and -m64. Add host-filter, MinGW, and architecture-override regression coverage, and let HIP tests exercise the default driver. --- clang/include/clang/Driver/ToolChain.h | 3 +- clang/lib/Driver/Compilation.cpp | 9 ++-- clang/lib/Driver/ToolChain.cpp | 17 +++++-- clang/test/Driver/cl-argument-translation.c | 18 +++++++ .../Driver/hip-cl-argument-translation.hip | 18 +++---- clang/test/Driver/hip-cl-optimization.hip | 20 ++++---- .../Driver/openmp-cl-argument-translation.cpp | 48 +++++++++++++++++++ 7 files changed, 102 insertions(+), 31 deletions(-) diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 7304ddc43b63f7..b01dbb18c483cf 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -402,8 +402,9 @@ class ToolChain { /// TranslateOpenMPTargetArgs - Create a new derived argument list for /// that contains the OpenMP target specific flags passed via /// -Xopenmp-target -opt=val OR -Xopenmp-target=<triple> -opt=val + /// HostTriple is the resolved host target, including architecture overrides. virtual llvm::opt::DerivedArgList *TranslateOpenMPTargetArgs( - const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, + const llvm::opt::DerivedArgList &Args, const llvm::Triple &HostTriple, SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const; /// Append the argument following \p A to \p DAL assuming \p A is an Xarch diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 3ccfe60c520d92..c7ddf07bedf959 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -74,9 +74,8 @@ Compilation::getArgsForToolChain(const ToolChain *TC, BoundArch BA, // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags. if (DeviceOffloadKind == Action::OFK_OpenMP) { const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>(); - bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple()); OpenMPArgs = TC->TranslateOpenMPTargetArgs( - *TranslatedArgs, SameTripleAsHost, AllocatedArgs); + *TranslatedArgs, HostTC->getTriple(), AllocatedArgs); } DerivedArgList *NewDAL = nullptr; @@ -92,10 +91,8 @@ Compilation::getArgsForToolChain(const ToolChain *TC, BoundArch BA, delete OpenMPArgs; } - if (NewDAL && DeviceOffloadKind == Action::OFK_OpenMP && - (TheDriver.IsCLMode() || - DefaultToolChain.getTriple().isWindowsMSVCEnvironment())) { - // OpenMP forwarding can introduce clang-cl options after the shared + if (NewDAL && TheDriver.IsCLMode()) { + // Forwarding can introduce clang-cl options after the shared // translation. Keep synthesized arguments in the compilation-owned list. auto *DAL = ClangCLArgs::translateArgs( *NewDAL, DefaultToolChain.getTriple(), *TranslatedArgs); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 2d7dc6e63534b2..242f75af52d7b0 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -2009,11 +2009,12 @@ ToolChain::computeMSVCVersion(const Driver *D, } llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( - const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, + const llvm::opt::DerivedArgList &Args, const llvm::Triple &HostTriple, SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); bool Modified = false; + bool SameTripleAsHost = getTriple() == HostTriple; // Handle -Xopenmp-target flags for (auto *A : Args) { @@ -2076,9 +2077,7 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( XOpenMPTargetArg->setBaseArg(A); A = XOpenMPTargetArg.release(); if (A->getOption().matches(options::OPT_D) && - (getDriver().IsCLMode() || - llvm::Triple(llvm::Triple::normalize(getDriver().getTargetTriple())) - .isWindowsMSVCEnvironment())) + (getDriver().IsCLMode() || HostTriple.isWindowsMSVCEnvironment())) A->getValues()[0] = ClangCLArgs::translateMacroDefinition(A->getValue(), Args); AllocatedArgs.push_back(A); @@ -2086,8 +2085,16 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( Modified = true; } - if (Modified) + if (Modified) { + // GNU-mode Clang targeting MSVC also accepts forwarded clang-cl options. + if (!getDriver().IsCLMode() && HostTriple.isWindowsMSVCEnvironment()) { + DerivedArgList *Translated = + ClangCLArgs::translateArgs(*DAL, HostTriple, Args); + delete DAL; + return Translated; + } return DAL; + } delete DAL; return nullptr; diff --git a/clang/test/Driver/cl-argument-translation.c b/clang/test/Driver/cl-argument-translation.c index e1758265fa8890..a297ff88b7e2df 100644 --- a/clang/test/Driver/cl-argument-translation.c +++ b/clang/test/Driver/cl-argument-translation.c @@ -13,6 +13,24 @@ // MSVC: "-D" "FOO=7" // GNU: "-D" "FOO#7" +// Filtering host arguments preserves explicit overrides of shared /O options. +// RUN: %clang_cl --target=x86_64-pc-windows-msvc /c -### /O2 /Ob0 \ +// RUN: -clang:-Xarch_host -clang:-O1 -clang:-Xarch_host -clang:-fno-builtin \ +// RUN: -- %s 2>&1 | FileCheck %s --check-prefix=FILTERED +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu /c -### /O2 /Ob0 \ +// RUN: -clang:-Xarch_host -clang:-O1 -clang:-Xarch_host -clang:-fno-builtin \ +// RUN: -- %s 2>&1 | FileCheck %s --check-prefix=FILTERED +// RUN: %clang_cl --target=x86_64-w64-windows-gnu /c -### /O2 /Ob0 \ +// RUN: -clang:-Xarch_host -clang:-O1 -clang:-Xarch_host -clang:-fno-builtin \ +// RUN: -- %s 2>&1 | FileCheck %s --check-prefix=FILTERED +// FILTERED: "-cc1" +// FILTERED-NOT: "-O3" +// FILTERED: "-O1" +// FILTERED-NOT: "-O3" +// FILTERED: "-fno-builtin" +// FILTERED-SAME: "-fno-inline" +// FILTERED-NOT: argument unused during compilation + // Last-option precedence must include both slash and canonical options. // RUN: %clang_cl --target=x86_64-pc-windows-msvc /c -x c++ -### /permissive- /permissive -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=PERMISSIVE diff --git a/clang/test/Driver/hip-cl-argument-translation.hip b/clang/test/Driver/hip-cl-argument-translation.hip index e35201d37c2351..241d265cce3eca 100644 --- a/clang/test/Driver/hip-cl-argument-translation.hip +++ b/clang/test/Driver/hip-cl-argument-translation.hip @@ -1,18 +1,18 @@ // Shared source-language options must reach both HIP jobs. -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=COMMON -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /permissive -- %s 2>&1 | FileCheck %s --check-prefix=PERMISSIVE -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /DFOO#1 -clang:-Xarch_host -clang:-DFOO#2 -clang:-Xarch_device -clang:-DDEV#3 -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=SCOPED -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ // RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING @@ -35,20 +35,20 @@ // RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ // RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING -// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /DFOO#7 /permissive- -- %s 2>&1 | FileCheck %s --check-prefix=COMMON -// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /permissive -- %s 2>&1 | FileCheck %s --check-prefix=PERMISSIVE -// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /DFOO#1 -clang:-Xarch_host -clang:-DFOO#2 -clang:-Xarch_device -clang:-DDEV#3 -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=SCOPED -// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /permissive -clang:-Xarch_device -clang:-fno-delayed-template-parsing -clang:-Xarch_device \ // RUN: -clang:-foperator-names -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-CONFORMING @@ -102,6 +102,6 @@ // DEVICE-CONFORMING-SAME: "-fdelayed-template-parsing" // GNU-mode offloading retains MSVC macro syntax when selected by the host. -// RUN: %clang --target=x86_64-pc-windows-msvc -### -c --offload-new-driver \ +// RUN: %clang --target=x86_64-pc-windows-msvc -### -c \ // RUN: -x hip --offload-arch=gfx1100 -nogpuinc -nogpulib \ // RUN: -DFOO#1 -Xarch_host -DFOO#2 -Xarch_device -DDEV#3 -- %s 2>&1 | FileCheck %s --check-prefix=SCOPED diff --git a/clang/test/Driver/hip-cl-optimization.hip b/clang/test/Driver/hip-cl-optimization.hip index 1fa80de854e566..0dc4cdd97e5924 100644 --- a/clang/test/Driver/hip-cl-optimization.hip +++ b/clang/test/Driver/hip-cl-optimization.hip @@ -1,43 +1,43 @@ // Check that clang-cl optimization options apply to both host and device. // Device-specific options must still override the shared optimization level. -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=OS -// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-unknown-linux-gnu -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O1 -- %s 2>&1 | FileCheck %s --check-prefix=LINUX -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /Ox -- %s 2>&1 | FileCheck %s --check-prefix=O3 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /Od -- %s 2>&1 | FileCheck %s --check-prefix=O0 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 /Od -- %s 2>&1 | FileCheck %s --check-prefix=O0 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /Od /O2 -- %s 2>&1 | FileCheck %s --check-prefix=O3 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 -clang:-O1 -- %s 2>&1 | FileCheck %s --check-prefix=O1 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 -clang:-Xarch_device -clang:-O1 -- %s 2>&1 | FileCheck %s --check-prefix=DEVICE-O1 -// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c --offload-new-driver \ +// RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c \ // RUN: -x hip --offload-arch=gfx1100 -clang:-nogpuinc -clang:-nogpulib \ // RUN: /O2 /Ob0 -- %s 2>&1 | FileCheck %s --check-prefix=NOINLINE diff --git a/clang/test/Driver/openmp-cl-argument-translation.cpp b/clang/test/Driver/openmp-cl-argument-translation.cpp index 583db4718c9247..5f357472377553 100644 --- a/clang/test/Driver/openmp-cl-argument-translation.cpp +++ b/clang/test/Driver/openmp-cl-argument-translation.cpp @@ -39,6 +39,13 @@ // RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/permissive -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=DEVICE-O3 +// RUN: %clang_cl --target=x86_64-w64-windows-gnu -### /c \ +// RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -clang:--offload-arch=gfx1100 -clang:-nogpulib \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/O2 \ +// RUN: -clang:-Xopenmp-target=amdgcn-amd-amdhsa -clang:/permissive -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=DEVICE-O3 + // DEVICE-O3: "-cc1" "-triple" "x86_64-{{[^"]*}}" // DEVICE-O3-NOT: "-O3" // DEVICE-O3-NOT: "-fno-operator-names" @@ -95,6 +102,47 @@ // RUN: -Xopenmp-target=x86_64-pc-windows-msvc /permissive -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=DEVICE-O3 +// Forwarded frame-pointer options use the host architecture after -m32/-m64. +// /Oy- is silently accepted on x86-64, including when bundled with /O2. +// RUN: %clang --target=i686-pc-windows-msvc -m64 -### -c -fopenmp \ +// RUN: -fopenmp-targets=x86_64-pc-windows-msvc -nogpulib \ +// RUN: -Xopenmp-target=x86_64-pc-windows-msvc /Oy- -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=FRAME64 +// RUN: %clang --target=i686-pc-windows-msvc -m64 -### -c -fopenmp \ +// RUN: -fopenmp-targets=x86_64-pc-windows-msvc -nogpulib \ +// RUN: -Xopenmp-target=x86_64-pc-windows-msvc /O2y- -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=FRAME64 +// FRAME64: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// FRAME64: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// FRAME64-SAME: "-mframe-pointer=none" + +// RUN: %clang --target=x86_64-pc-windows-msvc -m32 -### -c -fopenmp \ +// RUN: -fopenmp-targets=i386-pc-windows-msvc -nogpulib \ +// RUN: -Xopenmp-target=i386-pc-windows-msvc /Oy -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=FRAME32-OMIT +// FRAME32-OMIT: "-cc1" "-triple" "i386-pc-windows-msvc{{[^"]*}}" +// FRAME32-OMIT: "-cc1" "-triple" "i386-pc-windows-msvc{{[^"]*}}" +// FRAME32-OMIT-SAME: "-mframe-pointer=none" + +// RUN: %clang --target=x86_64-pc-windows-msvc -m32 -### -c -fopenmp \ +// RUN: -fopenmp-targets=i386-pc-windows-msvc -nogpulib \ +// RUN: -Xopenmp-target=i386-pc-windows-msvc /O2y- -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=FRAME32-KEEP +// FRAME32-KEEP: "-cc1" "-triple" "i386-pc-windows-msvc{{[^"]*}}" +// FRAME32-KEEP: "-cc1" "-triple" "i386-pc-windows-msvc{{[^"]*}}" +// FRAME32-KEEP-SAME: "-O3" +// FRAME32-KEEP-SAME: "-mframe-pointer=all" + +// A different device architecture does not change the host's /Oy- policy. +// RUN: %clang --target=i686-pc-windows-msvc -m64 -### -c -fopenmp \ +// RUN: -fopenmp-targets=i386-pc-windows-msvc -nogpulib \ +// RUN: -Xopenmp-target=i386-pc-windows-msvc /O2y- -- %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=HOST64-DEVICE32 +// HOST64-DEVICE32: "-cc1" "-triple" "x86_64-pc-windows-msvc{{[^"]*}}" +// HOST64-DEVICE32: "-cc1" "-triple" "i386-pc-windows-msvc{{[^"]*}}" +// HOST64-DEVICE32-SAME: "-O3" +// HOST64-DEVICE32-SAME: "-mframe-pointer=none" + // Separate device architecture argument lists retain their own overrides. // RUN: %clang_cl --target=x86_64-pc-windows-msvc -### /c /O2 \ // RUN: -clang:-fopenmp -clang:-fopenmp-targets=amdgcn-amd-amdhsa \ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
