diff mbox

[3/6] New file computing regional register pressure on TREE SSA

Message ID VI1PR0802MB2176E02246AE9643D4D67034E7E20@VI1PR0802MB2176.eurprd08.prod.outlook.com
State New
Headers show

Commit Message

Bin Cheng May 12, 2017, 11:28 a.m. UTC
Hi,
This patch computes register pressure information on TREE SSA by a backward live
range data flow problem.  The major motivation is to estimate register pressure
for inner-most loop on TREE SSA, then other optimizations can use it.  So far the
information is used only in predcom later, but it could be useful to implement a
tree level scheduler in order to shrink live ranges.  Unfortunately the example
live range shrink pass I implemented doesn't have obvious impact on performance.
I think one reason is TER which effectively undoes its effect.  Maybe it will be
useful once TER/expanding is replaced with a better instruction selector, it is
not included in this patch.
One fact I need to mention is David proposed a similar patch long time ago at
https://gcc.gnu.org/ml/gcc-patches/2008-12/msg01261.html.  It tries to compute
register pressure information on tree ssa and shrink live ranges based on that
information.  Unfortunately the patch wasn't merged in the end.  There has been
quite changes in GCC implementation, I didn't use its code directly.  However,
I did read that patch and had it in mind when implementing this one.  If there
is any issue in this patch, it would be me that should be blamed.  I also sent
message to David about this patch and the possible relation with his.

Bootstrap and test on x86_64 and AArch64.  Is it OK?

Thanks,
bin

2017-05-10  Xinliang David Li  <davidxl@google.com>
	    Bin Cheng  <bin.cheng@arm.com>

	* Makefile.in (tree-ssa-regpressure.o): New object file.
	* tree-ssa-regpressure.c: New file.
	* tree-ssa-regpressure.h: New file.
From bf6e51ff68d87c372719de567d4de49d77744f77 Mon Sep 17 00:00:00 2001
From: Bin Cheng <binche01@e108451-lin.cambridge.arm.com>
Date: Mon, 8 May 2017 15:20:27 +0100
Subject: [PATCH 3/6] tree-ssa-regpressure-20170504.txt

---
 gcc/Makefile.in            |   1 +
 gcc/tree-ssa-regpressure.c | 829 +++++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-ssa-regpressure.h |  21 ++
 3 files changed, 851 insertions(+)
 create mode 100644 gcc/tree-ssa-regpressure.c
 create mode 100644 gcc/tree-ssa-regpressure.h

Comments

Jeff Law June 27, 2017, 5:40 p.m. UTC | #1
On 05/12/2017 05:28 AM, Bin Cheng wrote:
> Hi,
> This patch computes register pressure information on TREE SSA by a backward live
> range data flow problem.  The major motivation is to estimate register pressure
> for inner-most loop on TREE SSA, then other optimizations can use it.  So far the
> information is used only in predcom later, but it could be useful to implement a
> tree level scheduler in order to shrink live ranges.  Unfortunately the example
> live range shrink pass I implemented doesn't have obvious impact on performance.
> I think one reason is TER which effectively undoes its effect.  Maybe it will be
> useful once TER/expanding is replaced with a better instruction selector, it is
> not included in this patch.
> One fact I need to mention is David proposed a similar patch long time ago at
> https://gcc.gnu.org/ml/gcc-patches/2008-12/msg01261.html.  It tries to compute
> register pressure information on tree ssa and shrink live ranges based on that
> information.  Unfortunately the patch wasn't merged in the end.  There has been
> quite changes in GCC implementation, I didn't use its code directly.  However,
> I did read that patch and had it in mind when implementing this one.  If there
> is any issue in this patch, it would be me that should be blamed.  I also sent
> message to David about this patch and the possible relation with his.
> 
> Bootstrap and test on x86_64 and AArch64.  Is it OK?
> 
> Thanks,
> bin
> 
> 2017-05-10  Xinliang David Li  <davidxl@google.com>
> 	    Bin Cheng  <bin.cheng@arm.com>
> 
> 	* Makefile.in (tree-ssa-regpressure.o): New object file.
> 	* tree-ssa-regpressure.c: New file.
> 	* tree-ssa-regpressure.h: New file.
Any thoughts on tests, either end-to-end or unit testing?

At a high level does this make more sense as a pass or as a function
that is called by other passes?  I don't have a strong opinion here,
just putting the question out there for discussion.

You've got a live computation solver in here.  Is there some reason you
don't use the existing life analysis code?   I'd prefer not have have
another life analysis implementation if we can avoid it.  And if you
were using that code, I think you can easily get the coalescing data
you're using as well.

I haven't gone through all the detail in the patch as I think we need to
make sure we've got the design issues right first.  BUt there are a
couple nits noted inline below.






> 
> 
> 0003-tree-ssa-regpressure-20170504.txt
> 
> 
> From bf6e51ff68d87c372719de567d4de49d77744f77 Mon Sep 17 00:00:00 2001
> From: Bin Cheng <binche01@e108451-lin.cambridge.arm.com>
> Date: Mon, 8 May 2017 15:20:27 +0100
> Subject: [PATCH 3/6] tree-ssa-regpressure-20170504.txt
> 
> ---
>  gcc/Makefile.in            |   1 +
>  gcc/tree-ssa-regpressure.c | 829 +++++++++++++++++++++++++++++++++++++++++++++
>  gcc/tree-ssa-regpressure.h |  21 ++
>  3 files changed, 851 insertions(+)
>  create mode 100644 gcc/tree-ssa-regpressure.c
>  create mode 100644 gcc/tree-ssa-regpressure.h
> 
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 97259ac..abfd4bc 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1534,6 +1534,7 @@ OBJS = \
>  	tree-ssa-pre.o \
>  	tree-ssa-propagate.o \
>  	tree-ssa-reassoc.o \
> +	tree-ssa-regpressure.o \
>  	tree-ssa-sccvn.o \
>  	tree-ssa-scopedtables.o \
>  	tree-ssa-sink.o \
> diff --git a/gcc/tree-ssa-regpressure.c b/gcc/tree-ssa-regpressure.c
> new file mode 100644
> index 0000000..ebc6576
> --- /dev/null
> +++ b/gcc/tree-ssa-regpressure.c
> @@ -0,0 +1,829 @@
> +/* Reg Pressure Model and Live Range Shrinking Optimization on TREE SSA.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +
> +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 "backend.h"
> +#include "rtl.h"
> +#include "memmodel.h"
> +#include "ira.h"
So I suspect what we need from ira.h is fairly narrow.  Would it be
possible to pull the externalized interfaces we need for register
pressure at the gimple level into a new include file?

My worry is that as we pull in ira.h (and rtl.h and who knows what else)
into the gimple space we end up with a tangled mess of touching rtl
things in gimple which we'd like to avoid.

In fact, the first thing that jumped out at me when I scanned the patch
was the use of N_REG_CLASSES.  That's really a target property.

I must have mis-read the earlier patch to ira.c as I thought we were
only really tracking 3 classes.  Integer, float and vector.   Do we
really need to track pressure on all the classes to do a reasonable job?


+
> +/* Reg_alloc structure, coalesced from ssa variables.  */
> +typedef struct reg_alloc
> +{
> +  /* ID of this reg_alloc.  */
> +  unsigned id;
> +  /* The type of ssa variables of this reg_alloc.  */
> +  tree type;
> +  /* Ssa variables coalesced to this reg_alloc.  */
Use "SSA" rather than "Ssa".





> +      for (bsi = gsi_last_bb (bb); !gsi_end_p (bsi); gsi_prev (&bsi))
> +	{
> +	  stmt = gsi_stmt (bsi);
> +	  stmt_info = create_stmt_lr_info (region, stmt);
> +	  /* No need to compute live range information for debug stmt.  */
> +	  if (is_gimple_debug (stmt))
> +	    continue;
ISTM you'd want to test for a debug stmt before creating the stmt_lr_info?


> +
> +/* Check if PRESSURE is high according to target information about available
> +   registers.  */
> +static inline bool
> +high_reg_pressure (unsigned *pressure)
> +{
> +  int k;
> +
> +  gcc_assert (pressure != NULL);
> +
> +  for (k = 0; k < N_REG_CLASSES; k++)
> +    if (pressure[k] > 8 && pressure[k] > target_avail_regs[k])
> +      return true;
Where does the magic "8" come from?  ISTM that anytime the pressure is
greater than the available registers that the pressure is high,
regardless of the absolute number of live objects.


Jeff
Bin.Cheng June 28, 2017, 8:09 a.m. UTC | #2
On Tue, Jun 27, 2017 at 6:40 PM, Jeff Law <law@redhat.com> wrote:
> On 05/12/2017 05:28 AM, Bin Cheng wrote:
>> Hi,
>> This patch computes register pressure information on TREE SSA by a backward live
>> range data flow problem.  The major motivation is to estimate register pressure
>> for inner-most loop on TREE SSA, then other optimizations can use it.  So far the
>> information is used only in predcom later, but it could be useful to implement a
>> tree level scheduler in order to shrink live ranges.  Unfortunately the example
>> live range shrink pass I implemented doesn't have obvious impact on performance.
>> I think one reason is TER which effectively undoes its effect.  Maybe it will be
>> useful once TER/expanding is replaced with a better instruction selector, it is
>> not included in this patch.
>> One fact I need to mention is David proposed a similar patch long time ago at
>> https://gcc.gnu.org/ml/gcc-patches/2008-12/msg01261.html.  It tries to compute
>> register pressure information on tree ssa and shrink live ranges based on that
>> information.  Unfortunately the patch wasn't merged in the end.  There has been
>> quite changes in GCC implementation, I didn't use its code directly.  However,
>> I did read that patch and had it in mind when implementing this one.  If there
>> is any issue in this patch, it would be me that should be blamed.  I also sent
>> message to David about this patch and the possible relation with his.
>>
>> Bootstrap and test on x86_64 and AArch64.  Is it OK?
>>
>> Thanks,
>> bin
>>
>> 2017-05-10  Xinliang David Li  <davidxl@google.com>
>>           Bin Cheng  <bin.cheng@arm.com>
>>
>>       * Makefile.in (tree-ssa-regpressure.o): New object file.
>>       * tree-ssa-regpressure.c: New file.
>>       * tree-ssa-regpressure.h: New file.
> Any thoughts on tests, either end-to-end or unit testing?
>
> At a high level does this make more sense as a pass or as a function
> that is called by other passes?  I don't have a strong opinion here,
> just putting the question out there for discussion.
>
> You've got a live computation solver in here.  Is there some reason you
> don't use the existing life analysis code?   I'd prefer not have have
> another life analysis implementation if we can avoid it.  And if you
> were using that code, I think you can easily get the coalescing data
> you're using as well.
>
> I haven't gone through all the detail in the patch as I think we need to
> make sure we've got the design issues right first.  BUt there are a
> couple nits noted inline below.
>
>
Hi Jeff, Thanks very much for the review.  I plan to revisit this
after current tasks as well as study more benchmark cases for register
pressure.

Thanks,
bin
>
>
>
>
>>
>>
>> 0003-tree-ssa-regpressure-20170504.txt
>>
>>
>> From bf6e51ff68d87c372719de567d4de49d77744f77 Mon Sep 17 00:00:00 2001
>> From: Bin Cheng <binche01@e108451-lin.cambridge.arm.com>
>> Date: Mon, 8 May 2017 15:20:27 +0100
>> Subject: [PATCH 3/6] tree-ssa-regpressure-20170504.txt
>>
>> ---
>>  gcc/Makefile.in            |   1 +
>>  gcc/tree-ssa-regpressure.c | 829 +++++++++++++++++++++++++++++++++++++++++++++
>>  gcc/tree-ssa-regpressure.h |  21 ++
>>  3 files changed, 851 insertions(+)
>>  create mode 100644 gcc/tree-ssa-regpressure.c
>>  create mode 100644 gcc/tree-ssa-regpressure.h
>>
>> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
>> index 97259ac..abfd4bc 100644
>> --- a/gcc/Makefile.in
>> +++ b/gcc/Makefile.in
>> @@ -1534,6 +1534,7 @@ OBJS = \
>>       tree-ssa-pre.o \
>>       tree-ssa-propagate.o \
>>       tree-ssa-reassoc.o \
>> +     tree-ssa-regpressure.o \
>>       tree-ssa-sccvn.o \
>>       tree-ssa-scopedtables.o \
>>       tree-ssa-sink.o \
>> diff --git a/gcc/tree-ssa-regpressure.c b/gcc/tree-ssa-regpressure.c
>> new file mode 100644
>> index 0000000..ebc6576
>> --- /dev/null
>> +++ b/gcc/tree-ssa-regpressure.c
>> @@ -0,0 +1,829 @@
>> +/* Reg Pressure Model and Live Range Shrinking Optimization on TREE SSA.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +
>> +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 "backend.h"
>> +#include "rtl.h"
>> +#include "memmodel.h"
>> +#include "ira.h"
> So I suspect what we need from ira.h is fairly narrow.  Would it be
> possible to pull the externalized interfaces we need for register
> pressure at the gimple level into a new include file?
>
> My worry is that as we pull in ira.h (and rtl.h and who knows what else)
> into the gimple space we end up with a tangled mess of touching rtl
> things in gimple which we'd like to avoid.
>
> In fact, the first thing that jumped out at me when I scanned the patch
> was the use of N_REG_CLASSES.  That's really a target property.
>
> I must have mis-read the earlier patch to ira.c as I thought we were
> only really tracking 3 classes.  Integer, float and vector.   Do we
> really need to track pressure on all the classes to do a reasonable job?
>
>
> +
>> +/* Reg_alloc structure, coalesced from ssa variables.  */
>> +typedef struct reg_alloc
>> +{
>> +  /* ID of this reg_alloc.  */
>> +  unsigned id;
>> +  /* The type of ssa variables of this reg_alloc.  */
>> +  tree type;
>> +  /* Ssa variables coalesced to this reg_alloc.  */
> Use "SSA" rather than "Ssa".
>
>
>
>
>
>> +      for (bsi = gsi_last_bb (bb); !gsi_end_p (bsi); gsi_prev (&bsi))
>> +     {
>> +       stmt = gsi_stmt (bsi);
>> +       stmt_info = create_stmt_lr_info (region, stmt);
>> +       /* No need to compute live range information for debug stmt.  */
>> +       if (is_gimple_debug (stmt))
>> +         continue;
> ISTM you'd want to test for a debug stmt before creating the stmt_lr_info?
>
>
>> +
>> +/* Check if PRESSURE is high according to target information about available
>> +   registers.  */
>> +static inline bool
>> +high_reg_pressure (unsigned *pressure)
>> +{
>> +  int k;
>> +
>> +  gcc_assert (pressure != NULL);
>> +
>> +  for (k = 0; k < N_REG_CLASSES; k++)
>> +    if (pressure[k] > 8 && pressure[k] > target_avail_regs[k])
>> +      return true;
> Where does the magic "8" come from?  ISTM that anytime the pressure is
> greater than the available registers that the pressure is high,
> regardless of the absolute number of live objects.
>
>
> Jeff
>
Richard Biener June 28, 2017, 11:02 a.m. UTC | #3
On Wed, Jun 28, 2017 at 10:09 AM, Bin.Cheng <amker.cheng@gmail.com> wrote:
> On Tue, Jun 27, 2017 at 6:40 PM, Jeff Law <law@redhat.com> wrote:
>> On 05/12/2017 05:28 AM, Bin Cheng wrote:
>>> Hi,
>>> This patch computes register pressure information on TREE SSA by a backward live
>>> range data flow problem.  The major motivation is to estimate register pressure
>>> for inner-most loop on TREE SSA, then other optimizations can use it.  So far the
>>> information is used only in predcom later, but it could be useful to implement a
>>> tree level scheduler in order to shrink live ranges.  Unfortunately the example
>>> live range shrink pass I implemented doesn't have obvious impact on performance.
>>> I think one reason is TER which effectively undoes its effect.  Maybe it will be
>>> useful once TER/expanding is replaced with a better instruction selector, it is
>>> not included in this patch.
>>> One fact I need to mention is David proposed a similar patch long time ago at
>>> https://gcc.gnu.org/ml/gcc-patches/2008-12/msg01261.html.  It tries to compute
>>> register pressure information on tree ssa and shrink live ranges based on that
>>> information.  Unfortunately the patch wasn't merged in the end.  There has been
>>> quite changes in GCC implementation, I didn't use its code directly.  However,
>>> I did read that patch and had it in mind when implementing this one.  If there
>>> is any issue in this patch, it would be me that should be blamed.  I also sent
>>> message to David about this patch and the possible relation with his.
>>>
>>> Bootstrap and test on x86_64 and AArch64.  Is it OK?
>>>
>>> Thanks,
>>> bin
>>>
>>> 2017-05-10  Xinliang David Li  <davidxl@google.com>
>>>           Bin Cheng  <bin.cheng@arm.com>
>>>
>>>       * Makefile.in (tree-ssa-regpressure.o): New object file.
>>>       * tree-ssa-regpressure.c: New file.
>>>       * tree-ssa-regpressure.h: New file.
>> Any thoughts on tests, either end-to-end or unit testing?
>>
>> At a high level does this make more sense as a pass or as a function
>> that is called by other passes?  I don't have a strong opinion here,
>> just putting the question out there for discussion.
>>
>> You've got a live computation solver in here.  Is there some reason you
>> don't use the existing life analysis code?   I'd prefer not have have
>> another life analysis implementation if we can avoid it.  And if you
>> were using that code, I think you can easily get the coalescing data
>> you're using as well.
>>
>> I haven't gone through all the detail in the patch as I think we need to
>> make sure we've got the design issues right first.  BUt there are a
>> couple nits noted inline below.
>>
>>
> Hi Jeff, Thanks very much for the review.  I plan to revisit this
> after current tasks as well as study more benchmark cases for register
> pressure.

Please also rename the files to ssa-regpressure.h and ssa-prepressure.cc
(I think new files should get C++ extensions now).

Richard.

> Thanks,
> bin
>>
>>
>>
>>
>>>
>>>
>>> 0003-tree-ssa-regpressure-20170504.txt
>>>
>>>
>>> From bf6e51ff68d87c372719de567d4de49d77744f77 Mon Sep 17 00:00:00 2001
>>> From: Bin Cheng <binche01@e108451-lin.cambridge.arm.com>
>>> Date: Mon, 8 May 2017 15:20:27 +0100
>>> Subject: [PATCH 3/6] tree-ssa-regpressure-20170504.txt
>>>
>>> ---
>>>  gcc/Makefile.in            |   1 +
>>>  gcc/tree-ssa-regpressure.c | 829 +++++++++++++++++++++++++++++++++++++++++++++
>>>  gcc/tree-ssa-regpressure.h |  21 ++
>>>  3 files changed, 851 insertions(+)
>>>  create mode 100644 gcc/tree-ssa-regpressure.c
>>>  create mode 100644 gcc/tree-ssa-regpressure.h
>>>
>>> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
>>> index 97259ac..abfd4bc 100644
>>> --- a/gcc/Makefile.in
>>> +++ b/gcc/Makefile.in
>>> @@ -1534,6 +1534,7 @@ OBJS = \
>>>       tree-ssa-pre.o \
>>>       tree-ssa-propagate.o \
>>>       tree-ssa-reassoc.o \
>>> +     tree-ssa-regpressure.o \
>>>       tree-ssa-sccvn.o \
>>>       tree-ssa-scopedtables.o \
>>>       tree-ssa-sink.o \
>>> diff --git a/gcc/tree-ssa-regpressure.c b/gcc/tree-ssa-regpressure.c
>>> new file mode 100644
>>> index 0000000..ebc6576
>>> --- /dev/null
>>> +++ b/gcc/tree-ssa-regpressure.c
>>> @@ -0,0 +1,829 @@
>>> +/* Reg Pressure Model and Live Range Shrinking Optimization on TREE SSA.
>>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>>> +
>>> +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 "backend.h"
>>> +#include "rtl.h"
>>> +#include "memmodel.h"
>>> +#include "ira.h"
>> So I suspect what we need from ira.h is fairly narrow.  Would it be
>> possible to pull the externalized interfaces we need for register
>> pressure at the gimple level into a new include file?
>>
>> My worry is that as we pull in ira.h (and rtl.h and who knows what else)
>> into the gimple space we end up with a tangled mess of touching rtl
>> things in gimple which we'd like to avoid.
>>
>> In fact, the first thing that jumped out at me when I scanned the patch
>> was the use of N_REG_CLASSES.  That's really a target property.
>>
>> I must have mis-read the earlier patch to ira.c as I thought we were
>> only really tracking 3 classes.  Integer, float and vector.   Do we
>> really need to track pressure on all the classes to do a reasonable job?
>>
>>
>> +
>>> +/* Reg_alloc structure, coalesced from ssa variables.  */
>>> +typedef struct reg_alloc
>>> +{
>>> +  /* ID of this reg_alloc.  */
>>> +  unsigned id;
>>> +  /* The type of ssa variables of this reg_alloc.  */
>>> +  tree type;
>>> +  /* Ssa variables coalesced to this reg_alloc.  */
>> Use "SSA" rather than "Ssa".
>>
>>
>>
>>
>>
>>> +      for (bsi = gsi_last_bb (bb); !gsi_end_p (bsi); gsi_prev (&bsi))
>>> +     {
>>> +       stmt = gsi_stmt (bsi);
>>> +       stmt_info = create_stmt_lr_info (region, stmt);
>>> +       /* No need to compute live range information for debug stmt.  */
>>> +       if (is_gimple_debug (stmt))
>>> +         continue;
>> ISTM you'd want to test for a debug stmt before creating the stmt_lr_info?
>>
>>
>>> +
>>> +/* Check if PRESSURE is high according to target information about available
>>> +   registers.  */
>>> +static inline bool
>>> +high_reg_pressure (unsigned *pressure)
>>> +{
>>> +  int k;
>>> +
>>> +  gcc_assert (pressure != NULL);
>>> +
>>> +  for (k = 0; k < N_REG_CLASSES; k++)
>>> +    if (pressure[k] > 8 && pressure[k] > target_avail_regs[k])
>>> +      return true;
>> Where does the magic "8" come from?  ISTM that anytime the pressure is
>> greater than the available registers that the pressure is high,
>> regardless of the absolute number of live objects.
>>
>>
>> Jeff
>>
diff mbox

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 97259ac..abfd4bc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1534,6 +1534,7 @@  OBJS = \
 	tree-ssa-pre.o \
 	tree-ssa-propagate.o \
 	tree-ssa-reassoc.o \
+	tree-ssa-regpressure.o \
 	tree-ssa-sccvn.o \
 	tree-ssa-scopedtables.o \
 	tree-ssa-sink.o \
diff --git a/gcc/tree-ssa-regpressure.c b/gcc/tree-ssa-regpressure.c
new file mode 100644
index 0000000..ebc6576
--- /dev/null
+++ b/gcc/tree-ssa-regpressure.c
@@ -0,0 +1,829 @@ 
+/* Reg Pressure Model and Live Range Shrinking Optimization on TREE SSA.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+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 "backend.h"
+#include "rtl.h"
+#include "memmodel.h"
+#include "ira.h"
+#include "tree.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "stor-layout.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "cfgloop.h"
+#include "tree-ssa-regpressure.h"
+
+
+/* Entry for invariant hash table.  */
+struct inv_entry
+{
+  tree expr;
+  unsigned id;
+  hashval_t hash;
+};
+
+/* Helpers for invariant hash table.  */
+
+struct inv_hasher : delete_ptr_hash <inv_entry>
+{
+  static inline hashval_t hash (const inv_entry *);
+  static inline bool equal (const inv_entry *, const inv_entry *);
+};
+
+/* Hash function for invariant hash table.  */
+
+inline hashval_t
+inv_hasher::hash (const inv_entry *entry)
+{
+  return entry->hash;
+}
+
+/* Hash table equality function for invariant hash table.  */
+
+inline bool
+inv_hasher::equal (const inv_entry *entry1, const inv_entry *entry2)
+{
+  return (entry1->hash == entry2->hash
+	  && operand_equal_p (entry1->expr, entry2->expr, 0)
+	  && (TYPE_PRECISION (TREE_TYPE (entry1->expr))
+	      == TYPE_PRECISION (TREE_TYPE (entry2->expr))));
+}
+
+/* Reg_alloc structure, coalesced from ssa variables.  */
+typedef struct reg_alloc
+{
+  /* ID of this reg_alloc.  */
+  unsigned id;
+  /* The type of ssa variables of this reg_alloc.  */
+  tree type;
+  /* Ssa variables coalesced to this reg_alloc.  */
+  bitmap vars;
+}*reg_alloc_t;
+
+/* Live range information for a basic block.  */
+struct bb_lr_info
+{
+  /* Geenrated live ranges.  */
+  bitmap gen;
+  /* Killed live ranges.  */
+  bitmap kill;
+  /* In live ranges at the begining of basic block.  */
+  bitmap in;
+  /* Out live range at the end of basic block.  */
+  bitmap out;
+  /* Maximum register pressure of this basic block.  */
+  unsigned max_pressure[N_REG_CLASSES];
+};
+
+/* Live range information for a gimple stmt.  */
+struct stmt_lr_info
+{
+  /*  ID of the stmt.  */
+  unsigned id;
+  gimple *stmt;
+  /* Live ranges after the stmt.  */
+  bitmap lr_after_stmt;
+};
+
+/* Live range region structure.  */
+struct lr_region
+{
+  /* The loop from which this region is formed.  */
+  struct loop * loop;
+  /* Number of basic blocks in this region.  */
+  unsigned size;
+  /* Basic blocks of this region.  */
+  basic_block *body;
+  /* Live range information of region's basic blocks.  */
+  struct bb_lr_info *bb_lr_info;
+  /* Reg_allocs of this region.  */
+  vec<struct reg_alloc*> vallocs;
+  /* Map from ssa variable to reg_alloc id.  */
+  hash_map<tree, unsigned> *var_alloc_map;
+  /* Live out reg_allocs of this region.  */
+  bitmap live_out_allocs;
+  /* Map from basic block to its id in this region.  */
+  hash_map<basic_block, unsigned> *bb_idx_map;
+  /* Hash table recording loop invariant expressions.  This is necessary
+     because invariants are not propagated/CSEed at the stage reg pressure
+     is computed.  Otherwise it results in duplicated pressure.  */
+  hash_table<inv_hasher> *inv_table;
+  /* Map from gimple stmt to its live range information.  */
+  hash_map<gimple *, stmt_lr_info *> *stmt_lr_info_map;
+  /* Maximum register pressure of this region.  */
+  unsigned max_pressure[N_REG_CLASSES];
+};
+
+/* Call back function to free live range INFO of gimple STMT.  */
+bool
+free_stmt_lr_info (gimple *const & stmt, stmt_lr_info *const &info, void *)
+{
+  gcc_assert (info->stmt == stmt);
+  if (info->lr_after_stmt != NULL)
+    BITMAP_FREE (info->lr_after_stmt);
+
+  free (info);
+  return true;
+}
+
+/* Create and return live range region for LOOP.  */
+static struct lr_region *
+create_loop_lr_region (struct loop *loop)
+{
+  struct lr_region *region = XCNEW (struct lr_region);
+
+  region->loop = loop;
+  region->size = loop->num_nodes;
+  region->body = get_loop_body_in_dom_order (loop);
+  region->vallocs.create (20);
+  region->var_alloc_map = new hash_map <tree, unsigned> (13);
+  region->live_out_allocs = BITMAP_ALLOC (NULL);
+  region->bb_idx_map = new hash_map <basic_block, unsigned> (13);
+  region->bb_lr_info = XCNEWVEC (struct bb_lr_info, region->size);
+  region->inv_table = new hash_table<inv_hasher> (13);
+  region->stmt_lr_info_map = new hash_map<gimple *, stmt_lr_info *> (13);
+  for (unsigned i = 0; i < region->size; i++)
+    {
+      basic_block bb = region->body[i];
+      unsigned *slot = &region->bb_idx_map->get_or_insert (bb);
+      *slot = i;
+    }
+  return region;
+}
+
+/* Store basic block BB's id in REGION to IDX.
+   Return true if BB is in REGION, return false otherwisely.  */
+static bool
+get_bb_idx_in_region (struct lr_region *region, basic_block bb, unsigned *idx)
+{
+  unsigned *slot = region->bb_idx_map->get (bb);
+  if (slot == NULL)
+    return false;
+
+  *idx = *slot;
+  return true;
+}
+
+/* Free live range REGION.  */
+void
+free_lr_region (struct lr_region *region)
+{
+  unsigned i;
+
+  free (region->body);
+
+  for (i = 0; i < region->size; i++)
+    {
+      BITMAP_FREE (region->bb_lr_info[i].gen);
+      BITMAP_FREE (region->bb_lr_info[i].kill);
+      BITMAP_FREE (region->bb_lr_info[i].in);
+      BITMAP_FREE (region->bb_lr_info[i].out);
+    }
+  free (region->bb_lr_info);
+  for (i = 0; i < region->vallocs.length (); i++)
+    {
+      struct reg_alloc *ra = region->vallocs[i];
+      BITMAP_FREE (ra->vars);
+      free (ra);
+    }
+  region->vallocs.release ();
+  delete region->var_alloc_map;
+  BITMAP_FREE (region->live_out_allocs);
+  delete region->bb_idx_map;
+  delete region->inv_table;
+  region->stmt_lr_info_map->traverse<void *, free_stmt_lr_info> (NULL);
+  delete region->stmt_lr_info_map;
+  region->stmt_lr_info_map = NULL;
+}
+
+/* Create and return new reg_alloc for VAR in REGION.  */
+static struct reg_alloc *
+create_reg_alloc (struct lr_region *region, tree var)
+{
+  bool exist_p;
+  unsigned *slot;
+  struct reg_alloc *ra = XCNEW (struct reg_alloc);
+
+  ra->id = region->vallocs.length ();
+  ra->type = TREE_TYPE (var);
+  ra->vars = BITMAP_ALLOC (NULL);
+  bitmap_set_bit (ra->vars, SSA_NAME_VERSION (var));
+  region->vallocs.safe_push (ra);
+  slot = &region->var_alloc_map->get_or_insert (var, &exist_p);
+  gcc_assert (!exist_p);
+  *slot = ra->id;
+
+  return ra;
+}
+
+/* Add new VAR to reg_alloc RA in REGION.  They must have compatible types.  */
+static void
+join_reg_alloc (struct lr_region *region, struct reg_alloc *ra, tree var)
+{
+  bool exist_p;
+  unsigned *slot;
+
+  gcc_assert (types_compatible_p (TREE_TYPE (var), ra->type));
+  gcc_assert (!bitmap_bit_p (ra->vars, SSA_NAME_VERSION (var)));
+  bitmap_set_bit (ra->vars, SSA_NAME_VERSION (var));
+  slot = &region->var_alloc_map->get_or_insert (var, &exist_p);
+  gcc_assert (!exist_p);
+  *slot = ra->id;
+}
+
+/* Find and return the reg_alloc for VAR in REGION.  Return NULL if no such
+   reg_alloc.  */
+static struct reg_alloc *
+find_reg_alloc (struct lr_region *region, tree var)
+{
+  unsigned *slot = region->var_alloc_map->get (var);
+  if (!slot)
+    return NULL;
+
+  gcc_assert (*slot < region->vallocs.length ());
+  return region->vallocs[*slot];
+}
+
+/* Dump all reg_allocs in REGION.  */
+static void
+dump_reg_allocs (FILE *file, struct lr_region *region)
+{
+  unsigned i, j;
+  bitmap_iterator bi;
+  struct reg_alloc *ra;
+
+  fprintf (file, "Reg_Alloc:\n");
+  for (i = 0; i < region->vallocs.length (); i++)
+    {
+      ra = region->vallocs[i];
+      fprintf (file, "  %d: ", ra->id);
+      EXECUTE_IF_SET_IN_BITMAP (ra->vars, 0, j, bi)
+	{
+	  print_generic_expr (file, ssa_name (j), TDF_SLIM);
+	  fprintf (file, " ");
+	}
+      fprintf (file, "\n");
+    }
+}
+
+/*Record reg_alloc for invariant VAR defined by STMT in REGION.  */
+static void
+record_reg_alloc_for_inv (struct lr_region *region, tree var, gimple *stmt)
+{
+  struct inv_entry **slot;
+  struct reg_alloc *ra = find_reg_alloc (region, var);
+  if (ra != NULL)
+    return;
+
+  slot = NULL;
+  if (is_gimple_assign (stmt) && gimple_assign_single_p (stmt))
+    {
+      /* Check the invariant table.  */
+      struct inv_entry ent;
+      ent.expr = gimple_assign_rhs1 (stmt);
+      ent.hash = iterative_hash_expr (ent.expr, 0);
+      slot = region->inv_table->find_slot (&ent, INSERT);
+      /* Record stmt's rhs in hash table if not exists yet.  This is to
+	 avoid counting loop invariant constant repeatly when it is not
+	 propagated.  */
+      if (*slot != NULL)
+	{
+	  gcc_assert ((*slot)->id < region->vallocs.length ());
+	  ra = region->vallocs[(*slot)->id];
+	  join_reg_alloc (region, ra, var);
+	  return;
+	}
+      *slot = new inv_entry ();
+      (*slot)->expr = ent.expr;
+      (*slot)->hash = ent.hash;
+    }
+  ra = create_reg_alloc (region, var);
+  /* Record it in invariant table if necessary.  */
+  if (slot != NULL && *slot != NULL)
+    (*slot)->id = ra->id;
+}
+
+/* Compute live out reg_allocs for REGION.  */
+static void
+compute_live_out_reg_allocs (struct lr_region *region)
+{
+  for (unsigned i = 0; i < region->vallocs.length (); i++)
+    {
+      unsigned j;
+      bitmap_iterator bi;
+      struct reg_alloc *ra = region->vallocs[i];
+
+      EXECUTE_IF_SET_IN_BITMAP (ra->vars, 0, j, bi)
+	{
+	  tree var = ssa_name (j);
+	  use_operand_p use_p;
+	  imm_use_iterator imm_iter;
+
+	  FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
+	    {
+	      gimple *use_stmt = USE_STMT (use_p);
+	      if (is_gimple_debug (use_stmt))
+		continue;
+
+	      basic_block use_bb = gimple_bb (use_stmt);
+	      unsigned use_bb_idx;
+	      if (get_bb_idx_in_region (region, use_bb, &use_bb_idx))
+		continue;
+
+	      /* Set reg_alloc as live out if it's defined in this region
+		 but used outside.  */
+	      bitmap_set_bit (region->live_out_allocs, ra->id);
+	      break;
+	    }
+	  if (bitmap_bit_p (region->live_out_allocs, ra->id))
+	    break;
+	}
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Live out reg_allocs: \n  ");
+      dump_bitmap (dump_file, region->live_out_allocs);
+    }
+}
+
+/* Create and return live range information for STMT in REGION.  */
+static struct stmt_lr_info *
+create_stmt_lr_info (struct lr_region *region, gimple *stmt)
+{
+  bool exist_p;
+  struct stmt_lr_info **slot;
+
+  slot = &region->stmt_lr_info_map->get_or_insert (stmt, &exist_p);
+  gcc_assert (!exist_p);
+  *slot = XCNEW (struct stmt_lr_info);
+  (*slot)->stmt = stmt;
+  (*slot)->lr_after_stmt = NULL;
+  return *slot;
+}
+
+/* Compute reg_allocs for REGION by coalescing ssa variables.  */
+static void
+compute_reg_allocs (struct lr_region *region)
+{
+  unsigned i, j;
+  gimple_stmt_iterator bsi;
+
+  for (i = 0; i < region->size; i++)
+    {
+      basic_block bb = region->body[i];
+      /* First create new reg_alloc for PHIs.  */
+      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+	{
+	  gimple *phi = gsi_stmt (bsi);
+	  tree res = gimple_phi_result (phi);
+	  if (virtual_operand_p (res))
+	    continue;
+
+	  if (region->var_alloc_map->get (res) == NULL)
+	    create_reg_alloc (region, res);
+	}
+      /* Coalesce PHI args with existing reg_allocs.  This has to be done
+	 independently to avoid coalescing swapping PHIs like:
+
+	   loop_header:
+	     a = PHI <a, b>
+	     b = PHI <b, a>.  */
+      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+	{
+	  gimple *phi = gsi_stmt (bsi);
+	  tree res = gimple_phi_result (phi);
+	  if (virtual_operand_p (res))
+	    continue;
+
+	  struct reg_alloc *ra = find_reg_alloc (region, res);
+	  gcc_assert (ra != NULL);
+	  for (j = 0; j < gimple_phi_num_args (phi); j++)
+	    {
+	      tree arg = gimple_phi_arg_def (phi, j);
+	      if (TREE_CODE (arg) == SSA_NAME
+		  && (find_reg_alloc (region, arg) == NULL))
+		join_reg_alloc (region, ra, arg);
+	    }
+	}
+      /* Now process all stmts.  */
+      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+	{
+	  gimple *stmt = gsi_stmt (bsi);
+	  if (is_gimple_debug (stmt))
+	    continue;
+
+	  tree var;
+	  ssa_op_iter iter;
+	  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_DEF)
+	    {
+	      if (find_reg_alloc (region, var) == NULL)
+		create_reg_alloc (region, var);
+	    }
+	  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
+	    {
+	      unsigned def_idx;
+	      basic_block def_bb;
+	      gimple *def_stmt = SSA_NAME_DEF_STMT (var);
+	      /* Create reg_alloc for ssa_var defined outside of region.  */
+	      if (gimple_code (def_stmt) == GIMPLE_NOP
+		  || ((def_bb = gimple_bb (def_stmt)) != NULL
+		      && !get_bb_idx_in_region (region, def_bb, &def_idx)))
+		record_reg_alloc_for_inv (region, var, def_stmt);
+	    }
+	}
+    }
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    dump_reg_allocs (dump_file, region);
+
+  delete region->inv_table;
+  region->inv_table = NULL;
+}
+
+/* Update GEN/KILL bitmaps by backward executing STMT.  */
+static void
+update_gen_kill_by_stmt (struct lr_region *region, gimple *stmt,
+			 bitmap gen, bitmap kill)
+{
+  tree var;
+  ssa_op_iter iter;
+  struct reg_alloc *ra;
+
+  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_DEF)
+    {
+      ra = find_reg_alloc (region, var);
+      gcc_assert (ra != NULL);
+      if (kill != NULL)
+	bitmap_set_bit (kill, ra->id);
+      bitmap_clear_bit (gen, ra->id);
+    }
+  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
+    {
+      ra = find_reg_alloc (region, var);
+      gcc_assert (ra != NULL);
+      bitmap_set_bit (gen, ra->id);
+    }
+}
+
+/* Update GEN/KILL bitmaps by backward executing PHI.  */
+static void
+update_gen_kill_by_phi (struct lr_region *region, gimple *phi,
+			bitmap gen, bitmap kill)
+{
+  tree res = gimple_phi_result (phi);
+  if (virtual_operand_p (res))
+    return;
+
+  struct reg_alloc *ra = find_reg_alloc (region, res);
+  gcc_assert (ra != NULL);
+  bitmap_set_bit (kill, ra->id);
+  bitmap_clear_bit (gen, ra->id);
+}
+
+/* Initialize live range information for BB in REGION.  */
+static void
+initialize_bb_lr_info (struct lr_region *region, basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+  gimple_stmt_iterator gsi;
+  unsigned i, idx;
+  struct bb_lr_info *bb_info;
+  bool in_region_p = get_bb_idx_in_region (region, bb, &idx);
+
+  gcc_assert (in_region_p);
+  bb_info = &region->bb_lr_info[idx];
+  bb_info->gen = BITMAP_ALLOC (NULL);
+  bb_info->kill = BITMAP_ALLOC (NULL);
+  bb_info->in = BITMAP_ALLOC (NULL);
+  bb_info->out = BITMAP_ALLOC (NULL);
+  bitmap_copy (bb_info->out, region->live_out_allocs);
+
+  /* Handle PHI arg as use of source basic block of the incoming edge.  */
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    {
+      unsigned dst_idx;
+      basic_block dst = e->dest;
+
+      if (get_bb_idx_in_region (region, dst, &dst_idx))
+	{
+	  for (gsi = gsi_start_phis (dst); !gsi_end_p (gsi); gsi_next (&gsi))
+	    {
+	      gimple *phi = gsi_stmt (gsi);
+	      if (virtual_operand_p (gimple_phi_result (phi)))
+		continue;
+
+	      for (i = 0; i < gimple_phi_num_args (phi); i++)
+		{
+		  tree arg = gimple_phi_arg_def (phi, i);
+		  if (TREE_CODE (arg) != SSA_NAME)
+		    continue;
+
+		  struct reg_alloc *arg_ra = find_reg_alloc (region, arg);
+		  gcc_assert (arg_ra != NULL);
+		  bitmap_set_bit (bb_info->gen, arg_ra->id);
+		}
+	    }
+	}
+    }
+
+  /* Compute local gen/kill information by reversely traversing stmts.  */
+  for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      if (is_gimple_debug (stmt))
+	continue;
+
+      update_gen_kill_by_stmt (region, stmt, bb_info->gen, bb_info->kill);
+    }
+
+  /* And the phis -- the order of traversing does not matter.  */
+  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *phi = gsi_stmt (gsi);
+      update_gen_kill_by_phi (region, phi, bb_info->gen, bb_info->kill);
+    }
+}
+
+/* Update live range information for BB in REGION.  This is the update
+   function of live range data flow equation.  */
+static bool
+update_bb_lr_info (struct lr_region *region, basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+  unsigned idx, dst_idx;
+  struct bb_lr_info *bb_info, *dst_info;
+  bool in_region_p = get_bb_idx_in_region (region, bb, &idx);
+
+  gcc_assert (in_region_p);
+  bb_info = &region->bb_lr_info[idx];
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (get_bb_idx_in_region (region, e->dest, &dst_idx))
+      {
+	dst_info = &region->bb_lr_info[dst_idx];
+	(void) bitmap_ior_into (bb_info->out, dst_info->in);
+      }
+
+  return bitmap_ior_and_compl (bb_info->in, bb_info->gen,
+			       bb_info->out, bb_info->kill);
+}
+
+/* Dump live range information for REGION.  */
+static void
+dump_live_ranges (FILE *file, struct lr_region *region)
+{
+  fprintf (file, "BB Live Range Info:\n");
+  for (unsigned i = 0; i < region->size; i++)
+    {
+      basic_block bb = region->body[i];
+      struct bb_lr_info *bb_info = &region->bb_lr_info[i];
+
+      fprintf (file, "  bb %d:\n", bb->index);
+      fprintf (file, "    in: ");
+      dump_bitmap (file, bb_info->in);
+      fprintf (file, "    out: ");
+      dump_bitmap (file, bb_info->out);
+      fprintf (file, "    gen: ");
+      dump_bitmap (file, bb_info->gen);
+      fprintf (file, "    kill: ");
+      dump_bitmap (file, bb_info->kill);
+    }
+}
+
+/* Compute live range information for REGION.  */
+static void
+compute_live_ranges (struct lr_region *region)
+{
+  basic_block bb;
+  unsigned i, idx;
+  bitmap worklist = BITMAP_ALLOC (NULL);
+
+  compute_live_out_reg_allocs (region);
+
+  for (i = 0; i < region->size; i++)
+    initialize_bb_lr_info (region, region->body[i]);
+
+  /* Initialize start worklist for all exit edges.  */
+  for (i = 0; i < region->size; i++)
+    {
+      edge e;
+      edge_iterator ei;
+
+      FOR_EACH_EDGE (e, ei, region->body[i]->succs)
+	if (!get_bb_idx_in_region (region, e->dest, &idx))
+	  {
+	    bitmap_set_bit (worklist, i);
+	    break;
+	  }
+    }
+
+  /* Solve live range data flow problem.  */
+  while (!bitmap_empty_p (worklist))
+    {
+      edge e;
+      edge_iterator ei;
+
+      idx = bitmap_first_set_bit (worklist);
+      bitmap_clear_bit (worklist, idx);
+      bb = region->body[idx];
+      if (update_bb_lr_info (region, bb))
+	FOR_EACH_EDGE (e, ei, bb->preds)
+	  if (get_bb_idx_in_region (region, e->src, &idx))
+	    bitmap_set_bit (worklist, idx);
+    }
+  BITMAP_FREE (worklist);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    dump_live_ranges (dump_file, region);
+}
+
+/* Compute live range information all stmts in REGION.  */
+static void
+compute_stmt_lr_info (struct lr_region *region)
+{
+  unsigned i;
+  gimple *stmt;
+  basic_block bb;
+  gimple_stmt_iterator bsi;
+  struct stmt_lr_info *stmt_info, **slot;
+  struct bb_lr_info *bb_info;
+  bitmap live_ranges = BITMAP_ALLOC (NULL);
+
+  for (i = 0; i < region->size; i++)
+    {
+      bb = region->body[i];
+      bb_info = &region->bb_lr_info[i];
+      bitmap_copy (live_ranges, bb_info->out);
+
+      for (bsi = gsi_last_bb (bb); !gsi_end_p (bsi); gsi_prev (&bsi))
+	{
+	  stmt = gsi_stmt (bsi);
+	  stmt_info = create_stmt_lr_info (region, stmt);
+	  /* No need to compute live range information for debug stmt.  */
+	  if (is_gimple_debug (stmt))
+	    continue;
+
+	  stmt_info->lr_after_stmt = BITMAP_ALLOC (NULL);
+	  bitmap_copy (stmt_info->lr_after_stmt, live_ranges);
+	  update_gen_kill_by_stmt (region, stmt, live_ranges, NULL);
+	}
+    }
+  BITMAP_FREE (live_ranges);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Stmt Live Range:\n");
+      for (i = 0; i < region->size; i++)
+	{
+	  bb = region->body[i];
+
+	  for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+	    {
+	      stmt = gsi_stmt (bsi);
+	      if (is_gimple_debug (stmt))
+		continue;
+
+	      slot = region->stmt_lr_info_map->get (stmt);
+	      fprintf (dump_file, "  ");
+	      print_gimple_stmt (dump_file, stmt, 0, 0);
+	      fprintf (dump_file, "    ");
+	      dump_bitmap (dump_file, (*slot)->lr_after_stmt);
+	    }
+	}
+    }
+}
+
+/* Compute register pression information for REGION.  */
+static void
+compute_reg_pressure (struct lr_region *region)
+{
+  int k;
+  unsigned i, j;
+  gimple *stmt;
+  basic_block bb;
+  bitmap_iterator bi;
+  gimple_stmt_iterator bsi;
+  struct bb_lr_info *bb_info;
+  unsigned reg_pressure[N_REG_CLASSES];
+
+  for (i = 0; i < region->size; i++)
+    {
+      bb = region->body[i];
+      bb_info = &region->bb_lr_info[i];
+
+      EXECUTE_IF_SET_IN_BITMAP (bb_info->out, 0, j, bi)
+	{
+	  struct reg_alloc *ra = region->vallocs[j];
+	  unsigned reg_class = ira_mode_classes[TYPE_MODE (ra->type)];
+	  bb_info->max_pressure[reg_class]++;
+	}
+      bool last_stmt_p = true;
+      for (bsi = gsi_last_bb (bb); !gsi_end_p (bsi); gsi_prev (&bsi))
+	{
+	  stmt = gsi_stmt (bsi);
+	  if (is_gimple_debug (stmt))
+	    continue;
+
+	  if (last_stmt_p)
+	    {
+	      last_stmt_p = false;
+	      continue;
+	    }
+	  memset (reg_pressure, 0, N_REG_CLASSES * sizeof (unsigned));
+	  struct stmt_lr_info **slot = region->stmt_lr_info_map->get (stmt);
+	  gcc_assert (slot != NULL);
+	  EXECUTE_IF_SET_IN_BITMAP ((*slot)->lr_after_stmt, 0, j, bi)
+	    {
+	      struct reg_alloc *ra = region->vallocs[j];
+	      unsigned reg_class = ira_mode_classes[TYPE_MODE (ra->type)];
+	      reg_pressure[reg_class]++;
+	    }
+	  for (k = 0; k < N_REG_CLASSES; k++)
+	    if (reg_pressure[k] > bb_info->max_pressure[k])
+	      bb_info->max_pressure[k] = reg_pressure[k];
+	}
+      for (k = 0; k < N_REG_CLASSES; k++)
+	if (bb_info->max_pressure[k] > region->max_pressure[k])
+	  region->max_pressure[k] = bb_info->max_pressure[k];
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Reg Pressure:\n");
+      for (i = 0; i < region->size; i++)
+	{
+	  bb = region->body[i];
+	  bb_info = &region->bb_lr_info[i];
+	  fprintf (dump_file, "  BB %d:\n", bb->index);
+	  for (k = 0; k < N_REG_CLASSES; k++)
+	    {
+	      if (bb_info->max_pressure[k] != 0)
+		fprintf (dump_file, "    %s: %d\n",
+			 reg_class_names[k], bb_info->max_pressure[k]);
+	    }
+	}
+    }
+}
+
+/* Check if PRESSURE is high according to target information about available
+   registers.  */
+static inline bool
+high_reg_pressure (unsigned *pressure)
+{
+  int k;
+
+  gcc_assert (pressure != NULL);
+
+  for (k = 0; k < N_REG_CLASSES; k++)
+    if (pressure[k] > 8 && pressure[k] > target_avail_regs[k])
+      return true;
+
+  return false;
+}
+
+/*Compute maximum register pressure information for LOOP and store it in
+  MAX_PRESSURE.  If HIGH_PRESSURE_P is not NULL, set it to true if loop
+  has high register pressure.  */
+void
+compute_loop_reg_pressure (struct loop *loop, unsigned *max_pressure,
+			   bool *high_pressure_p)
+{
+  struct lr_region *region;
+
+  region = create_loop_lr_region (loop);
+  compute_reg_allocs (region);
+  compute_live_ranges (region);
+  compute_stmt_lr_info (region);
+  compute_reg_pressure (region);
+  if (high_pressure_p != NULL)
+    *high_pressure_p = high_reg_pressure (region->max_pressure);
+
+  gcc_assert (max_pressure != NULL);
+  memcpy (max_pressure, region->max_pressure,
+	  sizeof (unsigned) * N_REG_CLASSES);
+  free_lr_region (region);
+}
diff --git a/gcc/tree-ssa-regpressure.h b/gcc/tree-ssa-regpressure.h
new file mode 100644
index 0000000..a288921
--- /dev/null
+++ b/gcc/tree-ssa-regpressure.h
@@ -0,0 +1,21 @@ 
+/* Header file for Reg Pressure Model and Live Range Shrinking Optimization
+   on TREE SSA.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+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/>.  */
+
+extern void compute_loop_reg_pressure (struct loop*, unsigned*, bool*);