Author: Yaxun (Sam) Liu
Date: 2026-10-21T21:55:33-04:00
New Revision: ea4c43d796c4e3fc0b51bda6234a7f2feb127c3d

URL: 
https://github.com/llvm/llvm-project/commit/ea4c43d796c4e3fc0b51bda6234a7f2feb127c3d
DIFF: 
https://github.com/llvm/llvm-project/commit/ea4c43d796c4e3fc0b51bda6234a7f2feb127c3d.diff

LOG: [clang] Normalize clang-cl options for host and device compilation 
(#228096)

clang-cl options such as `/O1`, `/O2`, and `/Ox` optimized host code in
HIP builds while leaving device code unoptimized. Translation of these
options, macro separators, and `/permissive` also depended on selecting
the MSVC toolchain.

Move this handling into a shared `ClangCLArgs` helper, selected by
`IsCLMode()`. Translate shared options before host/device filtering and
forwarded options afterward. Preserve explicit overrides, existing
GNU-mode MSVC compatibility, and the resolved host architecture for
frame-pointer options.

Added: 
    clang/lib/Driver/ClangCLArgs.cpp
    clang/lib/Driver/ClangCLArgs.h
    clang/test/Driver/cl-argument-translation.c
    clang/test/Driver/hip-cl-argument-translation.hip
    clang/test/Driver/hip-cl-optimization.hip
    clang/test/Driver/openmp-cl-argument-translation.cpp

Modified: 
    clang/docs/ReleaseNotes.md
    clang/include/clang/Driver/Driver.h
    clang/include/clang/Driver/ToolChain.h
    clang/lib/Driver/CMakeLists.txt
    clang/lib/Driver/Compilation.cpp
    clang/lib/Driver/Driver.cpp
    clang/lib/Driver/ToolChain.cpp
    clang/lib/Driver/ToolChains/MSVC.cpp
    clang/lib/Driver/ToolChains/MSVC.h
    clang/test/Driver/cl-options.c
    clang/test/Driver/cl-options.cu

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 614169f15b48ac..523af5d0351c7d 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1086,6 +1086,12 @@ documentation](CIR/index.md) for more information 
regarding ClangIR's status and
 
 #### Miscellaneous Bug Fixes
 
+- 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. Macro definitions using `#` as the value separator and
+  `/permissive` options are also translated consistently for host and device
+  compilation.
+
 #### Miscellaneous Clang Crashes Fixed
 
 - Fixed a crash in preprocessor conditionals containing `_Pragma`.

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/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/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..a06d1983da3d54
--- /dev/null
+++ b/clang/lib/Driver/ClangCLArgs.cpp
@@ -0,0 +1,200 @@
+//===--- 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>
+#include <string>
+
+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 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);
+
+  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.append(SynthesizedArgs.MakeFlagArg(
+            BaseArg, Opts.getOption(options::OPT_O0)));
+      } else {
+        if (OptChar == '1') {
+          DAL.append(SynthesizedArgs.MakeJoinedArg(
+              BaseArg, Opts.getOption(options::OPT_O), "s"));
+        } else if (OptChar == '2' || OptChar == 'x') {
+          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.append(SynthesizedArgs.MakeFlagArg(
+              BaseArg, Opts.getOption(options::OPT_fomit_frame_pointer)));
+        if (OptChar == '1' || OptChar == '2')
+          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.append(SynthesizedArgs.MakeFlagArg(
+              BaseArg, Opts.getOption(options::OPT_fno_inline)));
+          break;
+        case '1':
+          DAL.append(SynthesizedArgs.MakeFlagArg(
+              BaseArg, Opts.getOption(options::OPT_finline_hint_functions)));
+          break;
+        case '2':
+        case '3':
+          DAL.append(SynthesizedArgs.MakeFlagArg(
+              BaseArg, 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.append(SynthesizedArgs.MakeFlagArg(
+            BaseArg, Opts.getOption(options::OPT_fno_builtin)));
+      } else {
+        DAL.append(SynthesizedArgs.MakeFlagArg(
+            BaseArg, Opts.getOption(options::OPT_fbuiltin)));
+      }
+      break;
+    case 's':
+      DAL.append(SynthesizedArgs.MakeJoinedArg(
+          BaseArg, Opts.getOption(options::OPT_O), "s"));
+      break;
+    case 't':
+      DAL.append(SynthesizedArgs.MakeJoinedArg(
+          BaseArg, 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.append(SynthesizedArgs.MakeFlagArg(
+              BaseArg, Opts.getOption(options::OPT_fomit_frame_pointer)));
+        else
+          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();
+      }
+      break;
+    }
+    }
+  }
+  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
new file mode 100644
index 00000000000000..c713be83a31e13
--- /dev/null
+++ b/clang/lib/Driver/ClangCLArgs.h
@@ -0,0 +1,57 @@
+//===--- 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 and after offload argument filtering.
+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 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
+
+#endif // LLVM_CLANG_LIB_DRIVER_CLANGCLARGS_H

diff  --git a/clang/lib/Driver/Compilation.cpp 
b/clang/lib/Driver/Compilation.cpp
index c81c4445a29f95..c7ddf07bedf959 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"
@@ -73,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;
@@ -91,6 +91,15 @@ Compilation::getArgsForToolChain(const ToolChain *TC, 
BoundArch BA,
         delete OpenMPArgs;
     }
 
+    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);
+      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 75471cfb63dd02..5011c57a111083 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,10 +460,15 @@ Arg *clang::driver::makeInputArg(DerivedArgList &Args, 
const OptTable &Opts,
   return A;
 }
 
-DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
+DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args,
+                                           const llvm::Triple &Triple) const {
   const llvm::opt::OptTable &Opts = getOpts();
   DerivedArgList *DAL = new DerivedArgList(Args);
 
+  std::optional<ClangCLArgs> CLArgs;
+  if (IsCLMode())
+    CLArgs.emplace(Args, Triple);
+
   bool HasNostdlib = Args.hasArg(options::OPT_nostdlib);
   bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx);
   bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs);
@@ -480,6 +486,21 @@ DerivedArgList *Driver::TranslateInputArgs(const 
InputArgList &Args) const {
       continue;
     }
 
+    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').
@@ -1785,7 +1806,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/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 255a9c9602b540..242f75af52d7b0 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"
@@ -2008,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) {
@@ -2074,13 +2076,25 @@ llvm::opt::DerivedArgList 
*ToolChain::TranslateOpenMPTargetArgs(
     }
     XOpenMPTargetArg->setBaseArg(A);
     A = XOpenMPTargetArg.release();
+    if (A->getOption().matches(options::OPT_D) &&
+        (getDriver().IsCLMode() || HostTriple.isWindowsMSVCEnvironment()))
+      A->getValues()[0] =
+          ClangCLArgs::translateMacroDefinition(A->getValue(), Args);
     AllocatedArgs.push_back(A);
     DAL->append(A);
     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;
@@ -2154,6 +2168,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 25ea64a4ba5055..8f4c8f89ce58f9 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -1023,187 +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));
-
-  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();
-
-  // /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)) {
-      // 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..a297ff88b7e2df
--- /dev/null
+++ b/clang/test/Driver/cl-argument-translation.c
@@ -0,0 +1,76 @@
+// 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"
+
+// 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
+// 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.c b/clang/test/Driver/cl-options.c
index 7a71924c3189fb..536b93890ef71e 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/cl-options.cu b/clang/test/Driver/cl-options.cu
index b241ec6672d851..b373f4c7d0a031 100644
--- a/clang/test/Driver/cl-options.cu
+++ b/clang/test/Driver/cl-options.cu
@@ -25,3 +25,26 @@
 // 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"
+
+// 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..241d265cce3eca
--- /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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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
new file mode 100644
index 00000000000000..0dc4cdd97e5924
--- /dev/null
+++ b/clang/test/Driver/hip-cl-optimization.hip
@@ -0,0 +1,119 @@
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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 \
+// 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-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
+
+// 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"
+
+// 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{{[^"]*}}"
+// 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"

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..5f357472377553
--- /dev/null
+++ b/clang/test/Driver/openmp-cl-argument-translation.cpp
@@ -0,0 +1,159 @@
+// 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
+
+// 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"
+// 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
+
+// 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 
diff erent 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 \
+// 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{{[^"]*}}"


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to