From 4353a916b6861e65f235c1b3ff8465c7f6e024ee Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 21 Apr 2016 17:37:05 -0400
Subject: [PATCH 107/117] FIXME: get dfinit.rtl working

---
 gcc/cfgexpand.c                                  |  2 +-
 gcc/function.c                                   | 38 +++++-----
 gcc/function.h                                   |  2 +-
 gcc/read-rtl.c                                   | 77 ++++++++++++--------
 gcc/rtl/rtl-frontend.c                           |  9 ++-
 gcc/testsuite/rtl.dg/dfinit.rtl                  | 90 ++++++++++++++++++++++++
 gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl |  4 ++
 gcc/tree-dfa.c                                   |  5 ++
 8 files changed, 178 insertions(+), 49 deletions(-)
 create mode 100644 gcc/testsuite/rtl.dg/dfinit.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 1341c14..fb1cbd8 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -6222,7 +6222,7 @@ pass_expand::execute (function *fun)
     }
 
   /* Set up parameters and prepare for return, for the function.  */
-  expand_function_start (current_function_decl);
+  expand_function_start (current_function_decl, true);
 
   /* If we emitted any instructions for setting up the variables,
      emit them before the FUNCTION_START note.  */
diff --git a/gcc/function.c b/gcc/function.c
index 0186a89..9a22672 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -5083,10 +5083,12 @@ stack_protect_epilogue (void)
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
    PARMS_HAVE_CLEANUPS is nonzero if there are cleanups associated with
-   the function's parameters, which must be run at any return statement.  */
+   the function's parameters, which must be run at any return statement.
+   EMIT_INSNS is true if instructions are to emitted, false to avoid this
+   (for use by the RTL frontend).  */
 
 void
-expand_function_start (tree subr)
+expand_function_start (tree subr, bool emit_insns)
 {
   /* Make sure volatile mem refs aren't considered
      valid operands of arithmetic insns.  */
@@ -5102,7 +5104,8 @@ expand_function_start (tree subr)
   /* Make the label for return statements to jump to.  Do not special
      case machines with special return instructions -- they will be
      handled later during jump, ifcvt, or epilogue creation.  */
-  return_label = gen_label_rtx ();
+  if (emit_insns)
+    return_label = gen_label_rtx ();
 
   /* Initialize rtx used to return the value.  */
   /* Do this before assign_parms so that we copy the struct value address
@@ -5128,7 +5131,7 @@ expand_function_start (tree subr)
 	  /* Expect to be passed the address of a place to store the value.
 	     If it is passed as an argument, assign_parms will take care of
 	     it.  */
-	  if (sv)
+	  if (sv && emit_insns)
 	    {
 	      value_address = gen_reg_rtx (Pmode);
 	      emit_move_insn (value_address, sv);
@@ -5205,7 +5208,7 @@ expand_function_start (tree subr)
   assign_parms (subr);
 
   /* If function gets a static chain arg, store it.  */
-  if (cfun->static_chain_decl)
+  if (cfun->static_chain_decl && emit_insns)
     {
       tree parm = cfun->static_chain_decl;
       rtx local, chain;
@@ -5249,7 +5252,7 @@ expand_function_start (tree subr)
 
   /* If the function receives a non-local goto, then store the
      bits we need to restore the frame pointer.  */
-  if (cfun->nonlocal_goto_save_area)
+  if (cfun->nonlocal_goto_save_area && emit_insns)
     {
       tree t_save;
       rtx r_save;
@@ -5272,22 +5275,25 @@ expand_function_start (tree subr)
      The move is supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
-  emit_note (NOTE_INSN_FUNCTION_BEG);
+  if (emit_insns)
+    {
+      emit_note (NOTE_INSN_FUNCTION_BEG);
 
-  gcc_assert (NOTE_P (get_last_insn ()));
+      gcc_assert (NOTE_P (get_last_insn ()));
 
-  parm_birth_insn = get_last_insn ();
+      parm_birth_insn = get_last_insn ();
 
-  if (crtl->profile)
-    {
+      if (crtl->profile)
+	{
 #ifdef PROFILE_HOOK
-      PROFILE_HOOK (current_function_funcdef_no);
+	  PROFILE_HOOK (current_function_funcdef_no);
 #endif
-    }
+	}
 
-  /* If we are doing generic stack checking, the probe should go here.  */
-  if (flag_stack_check == GENERIC_STACK_CHECK)
-    stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+      /* If we are doing generic stack checking, the probe should go here.  */
+      if (flag_stack_check == GENERIC_STACK_CHECK)
+	stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+    }
 }
 
 void
diff --git a/gcc/function.h b/gcc/function.h
index 4ed41e4..d622fdb 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -647,7 +647,7 @@ extern void pop_dummy_function (void);
 extern void init_dummy_function_start (void);
 extern void init_function_start (tree);
 extern void stack_protect_epilogue (void);
-extern void expand_function_start (tree);
+extern void expand_function_start (tree, bool);
 extern void expand_dummy_function_end (void);
 
 extern void thread_prologue_and_epilogue_insns (void);
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index ba9f029..59208fa 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -1839,6 +1839,42 @@ read_rtx_code (const char *code_name)
 
 #ifndef GENERATOR_FILE
 
+/* FIXME.  Helper function for consolidate_singletons.  */
+
+static rtx
+lookup_global_register (int regno)
+{
+  /* FIXME: do we need to check for Pmode? */
+  switch (regno)
+    {
+    case STACK_POINTER_REGNUM:
+      return stack_pointer_rtx;
+    case FRAME_POINTER_REGNUM:
+      return frame_pointer_rtx;
+    case HARD_FRAME_POINTER_REGNUM:
+      return hard_frame_pointer_rtx;
+    case ARG_POINTER_REGNUM:
+      return arg_pointer_rtx;
+    case VIRTUAL_INCOMING_ARGS_REGNUM:
+      return virtual_incoming_args_rtx;
+    case VIRTUAL_STACK_VARS_REGNUM:
+      return virtual_stack_vars_rtx;
+    case VIRTUAL_STACK_DYNAMIC_REGNUM:
+      return virtual_stack_dynamic_rtx;
+    case VIRTUAL_OUTGOING_ARGS_REGNUM:
+      return virtual_outgoing_args_rtx;
+    case VIRTUAL_CFA_REGNUM:
+      return virtual_cfa_rtx;
+    case VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM:
+      return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+    case RETURN_ADDRESS_POINTER_REGNUM:
+      return return_address_pointer_rtx;
+#endif
+    }
+  return NULL;
+}
+
 /* When running in the RTL frontend, we must consolidate some
    rtx so that we use singletons where singletons are expected
    (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
@@ -1867,35 +1903,6 @@ consolidate_singletons (rtx x)
   if (GET_CODE (x) == REG)
     {
       unsigned int regno = REGNO (x);
-      /* FIXME: do we need to check for Pmode? */
-      switch (regno)
-	{
-	case STACK_POINTER_REGNUM:
-	  return stack_pointer_rtx;
-	case FRAME_POINTER_REGNUM:
-	  return frame_pointer_rtx;
-	case HARD_FRAME_POINTER_REGNUM:
-	  return hard_frame_pointer_rtx;
-	case ARG_POINTER_REGNUM:
-	  return arg_pointer_rtx;
-	case VIRTUAL_INCOMING_ARGS_REGNUM:
-	  return virtual_incoming_args_rtx;
-	case VIRTUAL_STACK_VARS_REGNUM:
-	  return virtual_stack_vars_rtx;
-	case VIRTUAL_STACK_DYNAMIC_REGNUM:
-	  return virtual_stack_dynamic_rtx;
-	case VIRTUAL_OUTGOING_ARGS_REGNUM:
-	  return virtual_outgoing_args_rtx;
-	case VIRTUAL_CFA_REGNUM:
-	  return virtual_cfa_rtx;
-	case VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM:
-	  return virtual_preferred_stack_boundary_rtx;
-#ifdef RETURN_ADDRESS_POINTER_REGNUM
-	case RETURN_ADDRESS_POINTER_REGNUM:
-	  return return_address_pointer_rtx;
-#endif
-	}
-
       /* Normally REG instances are created by gen_reg_rtx which updates
 	 regno_reg_rtx, growing it as necessary.
 	 The REG instances created from the dumpfile weren't created this
@@ -1918,6 +1925,18 @@ consolidate_singletons (rtx x)
 	  crtl->emit.regno_pointer_align_length = old_size * 2;
 	}
       gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+
+      if (reg_rtx_no < regno + 1)
+	reg_rtx_no = regno + 1;
+
+      /* Some register numbers have their rtx created in init_emit_regs
+	 e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
+	 Consolidate on this.  */
+      rtx global_reg = lookup_global_register (regno);
+      if (global_reg)
+	return global_reg;
+      /* FIXME: */
+
       /* Populate regno_reg_rtx if necessary.  */
       if (regno_reg_rtx[regno] == NULL)
 	regno_reg_rtx[regno] = x;
diff --git a/gcc/rtl/rtl-frontend.c b/gcc/rtl/rtl-frontend.c
index 9dce07d..b24eb7f 100644
--- a/gcc/rtl/rtl-frontend.c
+++ b/gcc/rtl/rtl-frontend.c
@@ -609,6 +609,13 @@ function_reader::create_function ()
   allocate_struct_function (fndecl, false);
   /* This sets cfun.  */
 
+  /* Normally, various state gets set up by expand_function_start, e.g.
+     crtl->return_rtx, based on DECL_RESULT (fndecl).
+     We call it here to ensure the state is set up, with emit_insns as
+     false, so no new instructions are emitted.  */
+  current_function_decl = fndecl;
+  expand_function_start (fndecl, false);
+
   //struct function *fn = ; // DECL_STRUCT_FUNCTION (node->decl);
   //push_cfun (fn);
 
@@ -911,8 +918,6 @@ rtl_langhook_parse_file (void)
     crtl->emit.x_cur_insn_uid = max_uid + 1;
   }
 
-  /* FIXME: should we be setting reg_rtx_no to the maximum regno seen? */
-
   /* If -froundtrip=FILENAME was provided, immediately dump the
      result, so that the testsuite can compare it against the
      input dump.  */
diff --git a/gcc/testsuite/rtl.dg/dfinit.rtl b/gcc/testsuite/rtl.dg/dfinit.rtl
new file mode 100644
index 0000000..e885e1e
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/dfinit.rtl
@@ -0,0 +1,90 @@
+/* { dg-options "-fsingle-pass=rtl-dfinit -fdump-rtl-dfinit" } */
+
+/* Lightly-modified dump of test-loop.c.247r.split1.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/test-loop.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/test-loop.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/test-loop.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/test-loop.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/test-loop.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/test-loop.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/test-loop.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-loop.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/test-loop.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/test-loop.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-loop.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/test-loop.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/test-loop.c:7 -1
+     (nil))
+
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl b/gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl
new file mode 100644
index 0000000..faa88fb
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl
@@ -0,0 +1,4 @@
+(insn 1 0 0 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/test-loop.c:2 -1
+     (nil))
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0e98056..9775ccd 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -305,6 +305,11 @@ ssa_default_def (struct function *fn, tree var)
   gcc_assert (TREE_CODE (var) == VAR_DECL
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL);
+
+  /* Always NULL_TREE for rtl1.  */
+  if (!fn->gimple_df)
+    return NULL_TREE;
+
   in.var = (tree)&ind;
   ind.uid = DECL_UID (var);
   return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));
-- 
1.8.5.3

