rl78-real.md (movqi_from_es): New pattern.
authorNick Clifton <nickc@redhat.com>
Fri, 21 Nov 2014 10:32:06 +0000 (10:32 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Fri, 21 Nov 2014 10:32:06 +0000 (10:32 +0000)
* config/rl78/rl78-real.md (movqi_from_es): New pattern.
* config/rl78/rl78.c (struct machine_function): Add uses_es field.
(rl78_expand_prologue): Save the ES register in interrupt handlers
that use it.
(rl78_expand_epilogue): Restore the ES register if necessary.
(rl78_start_function): Mention if the function uses the ES
register.
(rl78_lo16): Record the use of the ES register.
(transcode_memory_rtx): Likewise.

From-SVN: r217911

gcc/ChangeLog
gcc/config/rl78/rl78-real.md
gcc/config/rl78/rl78.c

index 3235ba0da4521eddeb91752bf0f0706b127fd6d6..f9f8ecba20ca62c2ae6ca55ad76f8cc2a5d246fe 100644 (file)
@@ -1,3 +1,15 @@
+2014-11-21  Nick Clifton  <nickc@redhat.com>
+
+       * config/rl78/rl78-real.md (movqi_from_es): New pattern.
+       * config/rl78/rl78.c (struct machine_function): Add uses_es field.
+       (rl78_expand_prologue): Save the ES register in interrupt handlers
+       that use it.
+       (rl78_expand_epilogue): Restore the ES register if necessary.
+       (rl78_start_function): Mention if the function uses the ES
+       register.
+       (rl78_lo16): Record the use of the ES register.
+       (transcode_memory_rtx): Likewise.
+
 2014-11-21  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/61773
index 00b8c9f22ad8176e96c01b0dc0c996c31de3ceed..6fac2a3f65c52835d7f6344a53f88f0533a88d67 100644 (file)
   "mov\tes, %0"
 )
 
+(define_insn "movqi_from_es"
+  [(set (match_operand:QI 0 "register_operand" "=a")
+       (reg:QI ES_REG))]
+  ""
+  "mov\t%0, es"
+)
+
 (define_insn "movqi_cs"
   [(set (reg:QI CS_REG)
        (match_operand:QI 0 "register_operand" "a"))]
index 86d2992c38e5c88c13ee573db77d82b106b73f23..c7520aaac6b84280b09547bdeaaf43bb4b0cf326 100644 (file)
@@ -118,6 +118,9 @@ struct GTY(()) machine_function
   int virt_insns_ok;
   /* Set if the current function needs to clean up any trampolines.  */
   int trampolines_used;
+  /* True if the ES register is used and hence
+     needs to be saved inside interrupt handlers.  */
+  bool uses_es;
 };
 
 /* This is our init_machine_status, as set in
@@ -136,38 +139,36 @@ rl78_init_machine_status (void)
 /* This pass converts virtual instructions using virtual registers, to
    real instructions using real registers.  Rather than run it as
    reorg, we reschedule it before vartrack to help with debugging.  */
-namespace {
-
-const pass_data pass_data_rl78_devirt =
-{
-  RTL_PASS, /* type */
-  "devirt", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_MACH_DEP, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
+namespace
+{
+  const pass_data pass_data_rl78_devirt =
+    {
+      RTL_PASS, /* type */
+      "devirt", /* name */
+      OPTGROUP_NONE, /* optinfo_flags */
+      TV_MACH_DEP, /* tv_id */
+      0, /* properties_required */
+      0, /* properties_provided */
+      0, /* properties_destroyed */
+      0, /* todo_flags_start */
+      0, /* todo_flags_finish */
+    };
 
-class pass_rl78_devirt : public rtl_opt_pass
-{
-public:
-  pass_rl78_devirt(gcc::context *ctxt)
-    : rtl_opt_pass(pass_data_rl78_devirt, ctxt)
+  class pass_rl78_devirt : public rtl_opt_pass
   {
-  }
+  public:
+    pass_rl78_devirt (gcc::context *ctxt)
+      : rtl_opt_pass (pass_data_rl78_devirt, ctxt)
+      {
+      }
 
-  /* opt_pass methods: */
-  virtual unsigned int execute (function *)
+    /* opt_pass methods: */
+    virtual unsigned int execute (function *)
     {
       rl78_reorg ();
       return 0;
     }
-
-};
-
+  };
 } // anon namespace
 
 rtl_opt_pass *
@@ -203,8 +204,7 @@ move_elim_pass (void)
         can eliminate the second SET.  */
       if (prev
          && rtx_equal_p (SET_DEST (prev), SET_SRC (set))
-         && rtx_equal_p (SET_DEST (set), SET_SRC (prev))
-         )       
+         && rtx_equal_p (SET_DEST (set), SET_SRC (prev)))
        {
          if (dump_file)
            fprintf (dump_file, " Delete insn %d because it is redundant\n",
@@ -216,40 +216,39 @@ move_elim_pass (void)
       else
        prev = set;
     }
-  
+
   if (dump_file)
     print_rtl_with_bb (dump_file, get_insns (), 0);
 
   return 0;
 }
 
-namespace {
-
-const pass_data pass_data_rl78_move_elim =
+namespace
 {
-  RTL_PASS, /* type */
-  "move_elim", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_MACH_DEP, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
+  const pass_data pass_data_rl78_move_elim =
+    {
+      RTL_PASS, /* type */
+      "move_elim", /* name */
+      OPTGROUP_NONE, /* optinfo_flags */
+      TV_MACH_DEP, /* tv_id */
+      0, /* properties_required */
+      0, /* properties_provided */
+      0, /* properties_destroyed */
+      0, /* todo_flags_start */
+      0, /* todo_flags_finish */
+    };
 
-class pass_rl78_move_elim : public rtl_opt_pass
-{
-public:
-  pass_rl78_move_elim(gcc::context *ctxt)
-    : rtl_opt_pass(pass_data_rl78_move_elim, ctxt)
+  class pass_rl78_move_elim : public rtl_opt_pass
   {
-  }
-
-  /* opt_pass methods: */
-  virtual unsigned int execute (function *) { return move_elim_pass (); }
-};
+  public:
+    pass_rl78_move_elim (gcc::context *ctxt)
+      : rtl_opt_pass (pass_data_rl78_move_elim, ctxt)
+      {
+      }
 
+    /* opt_pass methods: */
+    virtual unsigned int execute (function *) { return move_elim_pass (); }
+  };
 } // anon namespace
 
 rtl_opt_pass *
@@ -832,6 +831,7 @@ rl78_far_p (rtx x)
 /* Return the appropriate mode for a named address pointer.  */
 #undef  TARGET_ADDR_SPACE_POINTER_MODE
 #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
+
 static machine_mode
 rl78_addr_space_pointer_mode (addr_space_t addrspace)
 {
@@ -849,6 +849,7 @@ rl78_addr_space_pointer_mode (addr_space_t addrspace)
 /* Returns TRUE for valid addresses.  */
 #undef  TARGET_VALID_POINTER_MODE
 #define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
+
 static bool
 rl78_valid_pointer_mode (machine_mode m)
 {
@@ -858,6 +859,7 @@ rl78_valid_pointer_mode (machine_mode m)
 /* Return the appropriate mode for a named address address.  */
 #undef  TARGET_ADDR_SPACE_ADDRESS_MODE
 #define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
+
 static machine_mode
 rl78_addr_space_address_mode (addr_space_t addrspace)
 {
@@ -936,6 +938,7 @@ rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
 /* Determine if one named address space is a subset of another.  */
 #undef  TARGET_ADDR_SPACE_SUBSET_P
 #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
+
 static bool
 rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
 {
@@ -951,6 +954,7 @@ rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
 
 #undef  TARGET_ADDR_SPACE_CONVERT
 #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
+
 /* Convert from one address space to another.  */
 static rtx
 rl78_addr_space_convert (rtx op, tree from_type, tree to_type)
@@ -1008,6 +1012,34 @@ rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED,
   return V_REGS;
 }
 
+/* Typical stack layout should looks like this after the function's prologue:
+
+                            |    |
+                              --                       ^
+                            |    | \                   |
+                            |    |   arguments saved   | Increasing
+                            |    |   on the stack      |  addresses
+    PARENT   arg pointer -> |    | /
+  -------------------------- ---- -------------------
+    CHILD                   |ret |   return address
+                              --
+                            |    | \
+                            |    |   call saved
+                            |    |   registers
+       frame pointer ->    |    | /
+                              --
+                            |    | \
+                            |    |   local
+                            |    |   variables
+                            |    | /
+                              --
+                            |    | \
+                            |    |   outgoing          | Decreasing
+                            |    |   arguments         |  addresses
+   current stack pointer -> |    | /                   |
+  -------------------------- ---- ------------------   V
+                            |    |                 */
+
 /* Implements INITIAL_ELIMINATION_OFFSET.  The frame layout is
    described in the machine_Function struct definition, above.  */
 int
@@ -1082,7 +1114,8 @@ rl78_expand_prologue (void)
       {
        if (TARGET_G10)
          {
-           emit_move_insn (gen_rtx_REG (HImode, 0), gen_rtx_REG (HImode, i*2));
+           if (i != 0)
+             emit_move_insn (gen_rtx_REG (HImode, 0), gen_rtx_REG (HImode, i * 2));
            F (emit_insn (gen_push (gen_rtx_REG (HImode, 0))));
          }
        else
@@ -1101,6 +1134,13 @@ rl78_expand_prologue (void)
   if (rb != 0)
     emit_insn (gen_sel_rb (GEN_INT (0)));
 
+  /* Save ES register inside interrupt functions if it is used.  */
+  if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
+    {
+      emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode, A_REG)));
+      F (emit_insn (gen_push (gen_rtx_REG (HImode, AX_REG))));
+    }
+
   if (frame_pointer_needed)
     {
       F (emit_move_insn (gen_rtx_REG (HImode, AX_REG),
@@ -1148,6 +1188,12 @@ rl78_expand_epilogue (void)
        }
     }
 
+  if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
+    {
+      emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG)));
+      emit_insn (gen_movqi_es (gen_rtx_REG (QImode, A_REG)));
+    }
+
   for (i = 15; i >= 0; i--)
     if (cfun->machine->need_to_push [i])
       {
@@ -1234,6 +1280,9 @@ rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
   if (cfun->machine->framesize_outgoing)
     fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing,
             cfun->machine->framesize_outgoing == 1 ? "" : "s");
+
+  if (cfun->machine->uses_es)
+    fprintf (file, "\t; uses ES register\n");
 }
 
 /* Return an RTL describing where a function return value of type RET_TYPE
@@ -2170,7 +2219,7 @@ rl78_es_base (rtx addr)
    carefully to ensure that all the constraint information is accurate
    for the newly matched insn.  */
 static bool
-insn_ok_now (rtx_insn *insn)
+insn_ok_now (rtx_insn * insn)
 {
   rtx pattern = PATTERN (insn);
   int i;
@@ -2234,7 +2283,7 @@ insn_ok_now (rtx_insn *insn)
 #if DEBUG_ALLOC
 #define WORKED      fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
 #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
-#define FAILED      fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable()
+#define FAILED      fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
 #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
 #else
@@ -2308,6 +2357,7 @@ rl78_lo16 (rtx addr)
     r = rl78_subreg (HImode, addr, SImode, 0);
 
   r = gen_es_addr (r);
+  cfun->machine->uses_es = true;
 
   return r;
 }
@@ -2496,7 +2546,10 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
   debug_rtx (m);
 #endif
   if (need_es)
-    m = change_address (m, GET_MODE (m), gen_es_addr (base));
+    {
+      m = change_address (m, GET_MODE (m), gen_es_addr (base));
+      cfun->machine->uses_es = true;
+    }
   else
     m = change_address (m, GET_MODE (m), base);
 #if DEBUG_ALLOC
@@ -2642,7 +2695,7 @@ move_to_de (int opno, rtx before)
 
 /* Devirtualize an insn of the form (SET (op) (unop (op))).  */
 static void
-rl78_alloc_physical_registers_op1 (rtx_insn *insn)
+rl78_alloc_physical_registers_op1 (rtx_insn * insn)
 {
   /* op[0] = func op[1] */
 
@@ -2721,7 +2774,7 @@ has_constraint (unsigned int opnum, enum constraint_num constraint)
 
 /* Devirtualize an insn of the form (SET (op) (binop (op) (op))).  */
 static void
-rl78_alloc_physical_registers_op2 (rtx_insn *insn)
+rl78_alloc_physical_registers_op2 (rtx_insn * insn)
 {
   rtx prev;
   rtx first;
@@ -2875,7 +2928,7 @@ rl78_alloc_physical_registers_op2 (rtx_insn *insn)
 
 /* Devirtualize an insn of the form SET (PC) (MEM/REG).  */
 static void
-rl78_alloc_physical_registers_ro1 (rtx_insn *insn)
+rl78_alloc_physical_registers_ro1 (rtx_insn * insn)
 {
   OP (0) = transcode_memory_rtx (OP (0), BC, insn);
 
@@ -2888,7 +2941,7 @@ rl78_alloc_physical_registers_ro1 (rtx_insn *insn)
 
 /* Devirtualize a compare insn.  */
 static void
-rl78_alloc_physical_registers_cmp (rtx_insn *insn)
+rl78_alloc_physical_registers_cmp (rtx_insn * insn)
 {
   int tmp_id;
   rtx saved_op1;
@@ -2981,7 +3034,7 @@ rl78_alloc_physical_registers_cmp (rtx_insn *insn)
 
 /* Like op2, but AX = A * X.  */
 static void
-rl78_alloc_physical_registers_umul (rtx_insn *insn)
+rl78_alloc_physical_registers_umul (rtx_insn * insn)
 {
   rtx prev = prev_nonnote_nondebug_insn (insn);
   rtx first;
@@ -3045,7 +3098,7 @@ rl78_alloc_physical_registers_umul (rtx_insn *insn)
 }
 
 static void
-rl78_alloc_address_registers_macax (rtx_insn *insn)
+rl78_alloc_address_registers_macax (rtx_insn * insn)
 {
   int which, op;
   bool replace_in_op0 = false;