From 3cb40b1b5201760cefb26d99a4dc05acd2ed2131 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 21 May 2018 11:31:23 -0400
Subject: [PATCH 54/61] FIXME: 'magic_bool' musings

---
 gcc/Makefile.in          |   1 +
 gcc/magic-bool.cc        | 210 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 4 files changed, 213 insertions(+)
 create mode 100644 gcc/magic-bool.cc

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 473290c..a834344 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1415,6 +1415,7 @@ OBJS = \
 	lto-section-out.o \
 	lto-opts.o \
 	lto-compress.o \
+	magic-bool.o \
 	mcf.o \
 	mode-switching.o \
 	modulo-sched.o \
diff --git a/gcc/magic-bool.cc b/gcc/magic-bool.cc
new file mode 100644
index 0000000..26b9724
--- /dev/null
+++ b/gcc/magic-bool.cc
@@ -0,0 +1,210 @@
+/* FIXME.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "options.h"
+#include "opts.h"
+#include "selftest.h"
+
+//#include <memory>
+#include <string>
+
+/* Idea for instrumented gate functions.
+
+   Want to be able to take e.g. (from pass_complete_unroll::execute):
+
+  unsigned int val = tree_unroll_loops_completely (flag_unroll_loops
+						   || flag_peel_loops
+						   || optimize >= 3, true);
+
+   Note the boolean expression:
+
+     flag_unroll_loops
+     || flag_peel_loops
+     || optimize >= 3
+
+   which becomes the "may_increase_size" parameter which gets passed
+   around.
+
+   This eventually hits:
+*/
+#if 0
+  if (loop->unroll > 1)
+    ul = UL_ALL;
+  else if (may_increase_size && optimize_loop_nest_for_speed_p (loop)
+      /* Unroll outermost loops only if asked to do so or they do
+	 not cause code growth.  */
+      && (unroll_outer || loop_outer (loop_father)))
+    ul = UL_ALL;
+  else
+    ul = UL_NO_GROWTH;
+#endif
+
+/* or, more simply, for gate functions:
+
+   e.g.
+     virtual bool gate (function *) { return flag_tree_ccp != 0; }
+
+   Maybe have this become:
+
+     virtual magic_bool gate (function *) { return MAGIC_BOOL(flag_tree_ccp, "-ftree-ccp"); }
+
+   or somesuch.
+
+   The point is so the user can ask "why didn't this optimization fire?"
+   and get some useful feedback (e.g. you need to supply "-ftree-ccp").
+
+   Similar ideas in the inlining: maybe not just an enum, but potentially
+   a "rich" string:
+      e.g. "can't find definition of <FUNCTION>", i.e. tell the user
+      which one
+   Similarly with vectorization: tell the user which thing is causing the
+   problem, not just that there is a problem.
+ */
+
+class magic_bool
+{
+public:
+  magic_bool (bool value, std::string reason)
+  : m_value (value), m_reason (reason)
+  {}
+
+  operator bool () const { return m_value; }
+  std::string get_reason () const { return m_reason; }
+
+private:
+  bool m_value;
+
+  // FIXME: how to make this fast for the no-instrumentation case?
+  std::string m_reason;
+  //std::shared_ptr<std::string> m_reason;
+};
+
+magic_bool operator|| (const magic_bool &lhs, const magic_bool &rhs)
+{
+  // FIXME: early eval?
+  return magic_bool (bool (lhs) || bool (rhs),
+		     lhs.get_reason () + " || " + rhs.get_reason ());
+}
+
+magic_bool operator&& (const magic_bool &lhs, const magic_bool &rhs);
+magic_bool operator! (const magic_bool &lhs);
+
+template <typename T>
+class gcc_option
+{
+public:
+  typedef T option_t;
+
+  gcc_option (option_t *val_ptr) : m_val_ptr (val_ptr) {}
+
+#if 0
+  operator T& () const { return *m_val_ptr; }
+#endif
+
+  operator magic_bool () const
+  {
+    return magic_bool (*m_val_ptr, to_string ());
+  }
+
+  const T& value () const { return *m_val_ptr; }
+
+  const cl_option *get_cl_option () const
+  {
+    for (unsigned i = 0; i < cl_options_count; i++)
+      {
+	void *addr = option_flag_var (i, &global_options);
+	if (m_val_ptr == addr)
+	  return &cl_options[i];
+      }
+
+    return NULL;
+  }
+
+  std::string to_string () const
+  {
+    // FIXME: this is non-trivial:
+    const cl_option *opt = get_cl_option ();
+
+    if (opt)
+      return (std::string (opt->opt_text)
+	      + " (" + std::to_string (*m_val_ptr) + ")");
+    else
+      return std::to_string (*m_val_ptr);
+  }
+
+
+private:
+  option_t *m_val_ptr;
+};
+
+template <typename T>
+magic_bool operator!= (gcc_option<T> lhs, int rhs)
+{
+  return magic_bool (lhs.value () != rhs,
+		     lhs.to_string () + " != " + std::to_string (rhs));
+}
+
+template <typename T>
+magic_bool operator>= (gcc_option<T> lhs, int rhs)
+{
+  return magic_bool (lhs.value () >= rhs,
+		     lhs.to_string () + " >= " + std::to_string (rhs));
+}
+
+#define GCC_OPTION(X) (gcc_option<int> (&(X)))
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+magic_bool_cc_tests ()
+{
+  {
+    magic_bool cond = (GCC_OPTION (flag_tree_ccp) != 0);
+    ASSERT_STREQ (cond.get_reason ().c_str (), "-ftree-ccp (0) != 0");
+  }
+
+  {
+    magic_bool cond = (GCC_OPTION (flag_unroll_loops)
+		       || GCC_OPTION (flag_peel_loops));
+    ASSERT_STREQ (cond.get_reason ().c_str (),
+		  "-funroll-loops (0) || -fpeel-loops (0)");
+  }
+
+  {
+    magic_bool cond = (GCC_OPTION (flag_unroll_loops)
+		       || GCC_OPTION (flag_peel_loops)
+		       || GCC_OPTION (optimize) >= 3);
+    ASSERT_STREQ (cond.get_reason ().c_str (),
+		  "-funroll-loops (0) || -fpeel-loops (0) || 0 >= 3");
+    // FIXME: string for "optimize"
+  }
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index d587748..5393fc8 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -77,6 +77,7 @@ selftest::run_tests ()
   optinfo_emit_diagnostics_cc_tests ();
   optinfo_emit_json_cc_tests ();
   opt_problem_cc_tests ();
+  magic_bool_cc_tests ();
 
   /* Mid-level data structures.  */
   diagram_cc_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 43d06d6..c76efea 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -237,6 +237,7 @@ extern void hash_map_tests_c_tests ();
 extern void hash_set_tests_c_tests ();
 extern void input_c_tests ();
 extern void json_cc_tests ();
+extern void magic_bool_cc_tests ();
 extern void opt_problem_cc_tests ();
 extern void optinfo_cc_tests ();
 extern void optinfo_emit_diagnostics_cc_tests ();
-- 
1.8.5.3

