From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16775 invoked by alias); 14 May 2003 22:45:12 -0000 Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org Received: (qmail 16351 invoked from network); 14 May 2003 22:44:59 -0000 Received: from unknown (HELO piper.synopsys.com) (204.176.21.194) by sources.redhat.com with SMTP; 14 May 2003 22:44:59 -0000 Received: (from jbuck@localhost) by piper.synopsys.com (8.11.6/8.11.6) id h4EMitF12479 for gcc@gcc.gnu.org; Wed, 14 May 2003 15:44:55 -0700 Date: Wed, 14 May 2003 22:45:00 -0000 From: Joe Buck To: gcc@gcc.gnu.org Subject: [tree-ssa] copy propagation and the abstraction penalty Message-ID: <20030514154455.A12416@synopsys.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5.1i X-SW-Source: 2003-05/txt/msg01470.txt.bz2 Consider the code -------------------------------- struct complex { double re, im; complex(double r, double i) : re(r), im(i) {} }; inline complex operator+(const complex& a, const complex& b) { return complex(a.re+b.re, a.im+b.im); } complex addone(const complex& arg) { return arg + complex(1,0); } ------------------------------- We get really lousy code for this, in all gcc versions, including tree-ssa. The reason is that we build a temporary struct to hold the 1, 0 and don't get rid of it, so we take no advantage of the zero. Calling this foo.C, foo.C.t09.ssa gives ;; Function complex addone(const complex&) (_Z6addoneRK7complex) complex addone(const complex&) (arg) { struct complex retval.12; struct complex ; struct complex * T.8; struct complex * T.9; struct complex & T.10; struct complex T.11; { T.8_2 = &; { double i; double r; struct complex * const this; this_3 = (struct complex * const)T.8_2; r_5 = 1.0e+0; i_6 = 0.0; { this->re = 1.0e+0; this->im = 0.0; { (void)0 } } }; T.9_9 = &; T.10_10 = (struct complex &)T.9_9; { struct complex & b; struct complex ; b_11 = T.10_10; { struct complex * T.1; double T.2; double T.3; double T.4; double T.5; double T.6; double T.7; { T.1_13 = &; T.2_15 = arg->re; T.3_16 = b->re; T.4_17 = T.2_15 + T.3_16; T.5_18 = arg->im; T.6_19 = b->im; T.7_20 = T.5_18 + T.6_19; { double i; double r; struct complex * const this; this_21 = (struct complex * const)T.1_13; r_23 = T.4_17; i_24 = T.7_20; { this->re = T.4_17; this->im = T.7_20; { (void)0 } } }; { (void)0; goto ; } } }; :;; retval.12_27 = }; T.11_28 = retval.12_27; return retval.12_27; } } ------------------------------------------------------------ It would seem simple enough to eliminate all uses of the temporary struct by doing copy propagation: what we would have left is only the initialization of the struct itself; all uses of the struct would get the 1.0 and 0.0 values from its re and im fields. At this point the temporary struct should be eligible for killing. If we could do this alone, we would greatly improve C++ performance, especially on things like the Boost graph library. It seems that we have most of what we need in place, right?