[Driver] Refactor interaction between -f(no-)?omit-frame-pointer and -m(no-)?omit-leaf-frame-pointer
Use a tri-state enum to represent shouldUseFramePointer() and
shouldUseLeafFramePointer().
This simplifies the logic and fixes PR9825:
  -fno-omit-frame-pointer doesn't imply -mno-omit-leaf-frame-pointer.
and PR24003:
  /Oy- /O2 should not omit leaf frame pointer: this matches MSVC x86-32.
  (/Oy- is a no-op on MSVC x86-64.)
and:
  when CC1 option -mdisable-fp-elim if absent, -momit-leaf-frame-pointer
  can also be omitted.
The new behavior matches GCC:
  -fomit-frame-pointer wins over -mno-omit-leaf-frame-pointer
  -fno-omit-frame-pointer loses out to -momit-leaf-frame-pointer
The behavior makes lots of sense. We have 4 states:
- 00) leaf retained, non-leaf retained
- 01) leaf retained, non-leaf omitted  (this is invalid)
- 10) leaf omitted, non-leaf retained  (what -momit-leaf-frame-pointer was designed for)
- 11) leaf omitted, non-leaf omitted
"omit" options taking precedence over "no-omit" options is the only way
to make 3 valid states representable with -f(no-)?omit-frame-pointer and
-m(no-)?omit-leaf-pointer.
Reviewed By: ychen
Differential Revision: https://reviews.llvm.org/D64294
llvm-svn: 365860
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6e2f1f3..bc54845 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -501,6 +501,8 @@
   return codegenoptions::LimitedDebugInfo;
 }
 
+enum class FramePointerKind { None, NonLeaf, All };
+
 static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
   switch (Triple.getArch()){
   default:
@@ -515,6 +517,9 @@
 
 static bool useFramePointerForTargetByDefault(const ArgList &Args,
                                               const llvm::Triple &Triple) {
+  if (Args.hasArg(options::OPT_pg))
+    return true;
+
   switch (Triple.getArch()) {
   case llvm::Triple::xcore:
   case llvm::Triple::wasm32:
@@ -574,32 +579,22 @@
   return true;
 }
 
-static bool shouldUseFramePointer(const ArgList &Args,
-                                  const llvm::Triple &Triple) {
-  if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
-                               options::OPT_fomit_frame_pointer))
-    return A->getOption().matches(options::OPT_fno_omit_frame_pointer) ||
-           mustUseNonLeafFramePointerForTarget(Triple);
-
-  if (Args.hasArg(options::OPT_pg))
-    return true;
-
-  return useFramePointerForTargetByDefault(Args, Triple);
-}
-
-static bool shouldUseLeafFramePointer(const ArgList &Args,
-                                      const llvm::Triple &Triple) {
-  if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
-                               options::OPT_momit_leaf_frame_pointer))
-    return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
-
-  if (Args.hasArg(options::OPT_pg))
-    return true;
-
-  if (Triple.isPS4CPU())
-    return false;
-
-  return useFramePointerForTargetByDefault(Args, Triple);
+static FramePointerKind getFramePointerKind(const ArgList &Args,
+                                            const llvm::Triple &Triple) {
+  Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer,
+                           options::OPT_fno_omit_frame_pointer);
+  bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer);
+  bool NoOmitFP =
+      A && A->getOption().matches(options::OPT_fno_omit_frame_pointer);
+  if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
+      (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
+    if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
+                     options::OPT_mno_omit_leaf_frame_pointer,
+                     Triple.isPS4CPU()))
+      return FramePointerKind::NonLeaf;
+    return FramePointerKind::All;
+  }
+  return FramePointerKind::None;
 }
 
 /// Add a CC1 option to specify the debug compilation directory.
@@ -3960,8 +3955,12 @@
   if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
     CmdArgs.push_back("-fdefault-calling-conv=stdcall");
 
-  if (shouldUseFramePointer(Args, RawTriple))
+  FramePointerKind FPKeepKind = getFramePointerKind(Args, RawTriple);
+  if (FPKeepKind != FramePointerKind::None) {
     CmdArgs.push_back("-mdisable-fp-elim");
+    if (FPKeepKind == FramePointerKind::NonLeaf)
+      CmdArgs.push_back("-momit-leaf-frame-pointer");
+  }
   if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
                     options::OPT_fno_zero_initialized_in_bss))
     CmdArgs.push_back("-mno-zero-initialized-in-bss");
@@ -4146,9 +4145,6 @@
     CmdArgs.push_back(A->getValue());
   }
 
-  if (!shouldUseLeafFramePointer(Args, RawTriple))
-    CmdArgs.push_back("-momit-leaf-frame-pointer");
-
   // Explicitly error on some things we know we don't support and can't just
   // ignore.
   if (!Args.hasArg(options::OPT_fallow_unsupported)) {
@@ -5503,7 +5499,7 @@
   }
 
   if (Arg *A = Args.getLastArg(options::OPT_pg))
-    if (!shouldUseFramePointer(Args, Triple))
+    if (FPKeepKind == FramePointerKind::None)
       D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
                                                       << A->getAsString(Args);