123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506 |
- /*@@ Fix lossage on folding division of big integers. */
- /*@@ This file should be rewritten to use an arbitary precision
- @@ representation for "struct tree_int_cst" and "struct tree_real_cst".
- @@ Perhaps the routines could also be used for bc/dc, and made a lib.
- @@ The routines that translate from the ap rep should
- @@ warn if precision et. al. is lost.
- @@ This would also make life easier when this technology is used
- @@ for cross-compilers. */
- /* Fold a constant sub-tree into a single node for C-compiler
- Copyright (C) 1987, 1988 Free Software Foundation, Inc.
- This file is part of GNU CC.
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU CC General Public
- License for full details.
- Everyone is granted permission to copy, modify and redistribute
- GNU CC, but only under the conditions described in the
- GNU CC General Public License. A copy of this license is
- supposed to have been given to you along with GNU CC so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
- /* There are only two entry points in this file:
- fold and combine.
- fold takes a tree as argument and returns a simplified tree.
- combine takes a tree code for an arithmetic operation
- and two operands that are trees for constant values
- and returns the result of the specified operation on those values,
- also as a tree. */
-
- #include <stdio.h>
- #include "config.h"
- #include "tree.h"
- static void lshift_double ();
- static void rshift_double ();
- static void lrotate_double ();
- static void rrotate_double ();
- /* To do constant folding on INTEGER_CST nodes requires 64-bit arithmetic.
- We do that by representing the 64-bit integer as 8 shorts,
- with only 8 bits stored in each short, as a positive number. */
- /* Unpack a 64-bit integer into 8 shorts.
- LOW and HI are the integer, as two `int' pieces.
- SHORTS points to the array of shorts. */
- static void
- encode (shorts, low, hi)
- short *shorts;
- int low, hi;
- {
- shorts[0] = low & 0xff;
- shorts[1] = (low >> 8) & 0xff;
- shorts[2] = (low >> 16) & 0xff;
- shorts[3] = (low >> 24) & 0xff;
- shorts[4] = hi & 0xff;
- shorts[5] = (hi >> 8) & 0xff;
- shorts[6] = (hi >> 16) & 0xff;
- shorts[7] = (hi >> 24) & 0xff;
- }
- /* Pack an array of 8 shorts into a 64-bit integer.
- SHORTS points to the array of shorts.
- The integer is stored into *LOW and *HI as two `int' pieces. */
- static void
- decode (shorts, low, hi)
- short *shorts;
- int *low, *hi;
- {
- *low = (shorts[3] << 24) | (shorts[2] << 16) | (shorts[1] << 8) | shorts[0];
- *hi = (shorts[7] << 24) | (shorts[6] << 16) | (shorts[5] << 8) | shorts[4];
- }
- /* Make the integer constant T valid for its type
- by setting to 0 or 1 all the bits in the constant
- that don't belong in the type. */
- static void
- force_fit_type (t)
- tree t;
- {
- register int prec = TYPE_PRECISION (TREE_TYPE (t));
- if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
- prec = BITS_PER_WORD;
- /* First clear all bits that are beyond the type's precision. */
- if (prec > HOST_BITS_PER_INT)
- {
- TREE_INT_CST_HIGH (t)
- &= ~((-1) << (prec - HOST_BITS_PER_INT));
- }
- else
- {
- TREE_INT_CST_HIGH (t) = 0;
- if (prec < HOST_BITS_PER_INT)
- TREE_INT_CST_LOW (t)
- &= ~((-1) << prec);
- }
- /* If it's a signed type and value's sign bit is set, extend the sign. */
- if (! TREE_UNSIGNED (TREE_TYPE (t))
- && (prec > HOST_BITS_PER_INT
- ? TREE_INT_CST_HIGH (t) & (1 << (prec - HOST_BITS_PER_INT - 1))
- : TREE_INT_CST_LOW (t) & (1 << (prec - 1))))
- {
- /* Value is negative:
- set to 1 all the bits that are outside this type's precision. */
- if (prec > HOST_BITS_PER_INT)
- {
- TREE_INT_CST_HIGH (t)
- |= ((-1) << (prec - HOST_BITS_PER_INT));
- }
- else
- {
- TREE_INT_CST_HIGH (t) = -1;
- if (prec < HOST_BITS_PER_INT)
- TREE_INT_CST_LOW (t)
- |= ((-1) << prec);
- }
- }
- }
- /* Add two 64-bit integers with 64-bit result.
- Each argument is given as two `int' pieces.
- One argument is L1 and H1; the other, L2 and H2.
- The value is stored as two `int' pieces in *LV and *HV.
- We use the 8-shorts representation internally. */
- static void
- add_double (l1, h1, l2, h2, lv, hv)
- int l1, h1, l2, h2;
- int *lv, *hv;
- {
- short arg1[8];
- short arg2[8];
- register int carry = 0;
- register int i;
- encode (arg1, l1, h1);
- encode (arg2, l2, h2);
- for (i = 0; i < 8; i++)
- {
- carry += arg1[i] + arg2[i];
- arg1[i] = carry & 0xff;
- carry >>= 8;
- }
- decode (arg1, lv, hv);
- }
- /* Negate a 64-bit integers with 64-bit result.
- The argument is given as two `int' pieces in L1 and H1.
- The value is stored as two `int' pieces in *LV and *HV.
- We use the 8-shorts representation internally. */
- static void
- neg_double (l1, h1, lv, hv)
- int l1, h1;
- int *lv, *hv;
- {
- if (l1 == 0)
- {
- *lv = 0;
- *hv = - h1;
- }
- else
- {
- *lv = - l1;
- *hv = ~ h1;
- }
- }
- /* Multiply two 64-bit integers with 64-bit result.
- Each argument is given as two `int' pieces.
- One argument is L1 and H1; the other, L2 and H2.
- The value is stored as two `int' pieces in *LV and *HV.
- We use the 8-shorts representation internally. */
- static void
- mul_double (l1, h1, l2, h2, lv, hv)
- int l1, h1, l2, h2;
- int *lv, *hv;
- {
- short arg1[8];
- short arg2[8];
- short prod[16];
- register int carry = 0;
- register int i, j, k;
- encode (arg1, l1, h1);
- encode (arg2, l2, h2);
- bzero (prod, sizeof prod);
- for (i = 0; i < 8; i++)
- for (j = 0; j < 8; j++)
- {
- k = i + j;
- carry = arg1[i] * arg2[j];
- while (carry)
- {
- carry += prod[k];
- prod[k] = carry & 0xff;
- carry >>= 8;
- k++;
- }
- }
- decode (prod, lv, hv); /* @@decode ignores prod[8] -> prod[15] */
- }
- /* Shift the 64-bit integer in L1, H1 left by COUNT places
- keeping only PREC bits of result.
- Shift right if COUNT is negative.
- ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
- Store the value as two `int' pieces in *LV and *HV. */
- static void
- lshift_double (l1, h1, count, prec, lv, hv, arith)
- int l1, h1, count, prec;
- int *lv, *hv;
- int arith;
- {
- short arg1[8];
- register int i;
- register int carry;
- if (count < 0)
- {
- rshift_double (l1, h1, - count, prec, lv, hv, arith);
- return;
- }
- encode (arg1, l1, h1);
- if (prec < HOST_BITS_PER_INT)
- count &= (1 << prec) - 1;
- while (count > 0)
- {
- carry = 0;
- for (i = 0; i < 8; i++)
- {
- carry += arg1[i] << 1;
- arg1[i] = carry & 0xff;
- carry >>= 8;
- }
- count--;
- }
- decode (arg1, lv, hv);
- }
- /* Shift the 64-bit integer in L1, H1 right by COUNT places
- keeping only PREC bits of result. COUNT must be positive.
- ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
- Store the value as two `int' pieces in *LV and *HV. */
- static void
- rshift_double (l1, h1, count, prec, lv, hv, arith)
- int l1, h1, count, prec;
- int *lv, *hv;
- int arith;
- {
- short arg1[8];
- register int i;
- register int carry;
- encode (arg1, l1, h1);
- if (prec < HOST_BITS_PER_INT)
- count &= (1 << prec) - 1;
- carry = arith && arg1[7] >> 7;
- while (count > 0)
- {
- for (i = 7; i >= 0; i--)
- {
- carry <<= 8;
- carry += arg1[i];
- arg1[i] = (carry >> 1) & 0xff;
- }
- count--;
- }
- decode (arg1, lv, hv);
- }
- /* Rotate the 64-bit integer in L1, H1 left by COUNT places
- keeping only PREC bits of result.
- Rotate right if COUNT is negative.
- Store the value as two `int' pieces in *LV and *HV. */
- static void
- lrotate_double (l1, h1, count, prec, lv, hv)
- int l1, h1, count, prec;
- int *lv, *hv;
- {
- short arg1[8];
- register int i;
- register int carry;
- if (count < 0)
- {
- rrotate_double (l1, h1, - count, prec, lv, hv);
- return;
- }
- encode (arg1, l1, h1);
- if (prec < HOST_BITS_PER_INT)
- count &= (1 << prec) - 1;
- carry = arg1[7] >> 7;
- while (count > 0)
- {
- for (i = 0; i < 8; i++)
- {
- carry += arg1[i] << 1;
- arg1[i] = carry & 0xff;
- carry >>= 8;
- }
- count--;
- }
- decode (arg1, lv, hv);
- }
- /* Rotate the 64-bit integer in L1, H1 left by COUNT places
- keeping only PREC bits of result. COUNT must be positive.
- Store the value as two `int' pieces in *LV and *HV. */
- static void
- rrotate_double (l1, h1, count, prec, lv, hv)
- int l1, h1, count, prec;
- int *lv, *hv;
- {
- short arg1[8];
- register int i;
- register int carry;
- encode (arg1, l1, h1);
- if (prec < HOST_BITS_PER_INT)
- count &= (1 << prec) - 1;
- carry = arg1[0] & 1;
- while (count > 0)
- {
- for (i = 7; i >= 0; i--)
- {
- carry <<= 8;
- carry += arg1[i];
- arg1[i] = (carry >> 1) & 0xff;
- }
- count--;
- }
- decode (arg1, lv, hv);
- }
- /* Divide 64 bit integer LNUM, HNUM by 64 bit integer LDEN, HDEN
- for a quotient (stored in *LQUO, *HQUO) and remainder (in *LREM, *HREM).
- CODE is a tree code for a kind of division, one of
- TRUNC_DIV_EXPR, FLOOR_DIV_EXPR, CEIL_DIV_EXPR and ROUND_DIV_EXPR.
- It controls how the quotient is rounded to a integer.
- UNS nonzero says do unsigned division. */
- static void
- div_and_round_double (code, uns,
- lnum_orig, hnum_orig, lden_orig, hden_orig,
- lquo, hquo, lrem, hrem)
- enum tree_code code;
- int uns;
- int lnum_orig, hnum_orig; /* num == numerator == dividend */
- int lden_orig, hden_orig; /* den == denominator == divisor */
- int *lquo, *hquo, *lrem, *hrem;
- {
- int quo_neg = 0;
- short num[9], den[8], quo[8]; /* extra element for scaling. */
- register int i, j, work;
- register int carry = 0;
- int lnum = lnum_orig, hnum = hnum_orig;
- int lden = lden_orig, hden = hden_orig;
- if ((hden == 0) && (lden == 0)) {
- *hquo = *lquo = *hrem = *lrem = 0;
- error
- ("divide by 0 in constant folding - quotient and remainder set to 0.");
- return;
- }
- /* calculate quotient sign and convert operands to unsigned. */
- if (!uns)
- {
- if (hden < 0)
- {
- quo_neg = ~ quo_neg;
- neg_double (lden, hden, &lden, &hden);
- }
- if (hnum < 0)
- {
- quo_neg = ~ quo_neg;
- neg_double (lnum, hnum, &lnum, &hnum);
- }
- }
- if (hnum == 0 && hden == 0)
- { /* single precision */
- *hquo = *hrem = 0;
- *lquo = (unsigned) lnum / lden; /* rounds toward zero since positive args */
- goto finish_up;
- }
- if (hnum == 0)
- { /* trivial case: dividend < divisor */
- /* hden != 0 already checked. */
- *hquo = *lquo = 0;
- *hrem = hnum;
- *lrem = lnum;
- goto finish_up;
- }
- bzero (quo, sizeof quo);
- bzero (num, sizeof num); /* to zero 9th element */
- bzero (den, sizeof den);
- encode (num, lnum, hnum);
- encode (den, lden, hden);
- if (hden == 0)
- { /* simpler algorithm */
- /* hnum != 0 already checked. */
- for (i = 7; i >= 0; i--)
- {
- work = num[i] + (carry << 8);
- quo[i] = work / lden;
- carry = work % lden;
- }
- }
- else { /* full double precision,
- with thanks to Don Knuth's
- "Semi-Numericial Algorithms". */
- #define BASE 256
- int quo_est, scale, num_hi_sig, den_hi_sig, quo_hi_sig;
- /* Find the highest non-zero divisor digit. */
- for (i = 7; ; i--)
- if (den[i] != 0) {
- den_hi_sig = i;
- break;
- }
- for (i = 7; ; i--)
- if (num[i] != 0) {
- num_hi_sig = i;
- break;
- }
- quo_hi_sig = num_hi_sig - den_hi_sig + 1;
- /* Insure that the first digit of the divisor is at least BASE/2.
- This is required by the quotient digit estimation algorithm. */
- scale = BASE / (den[den_hi_sig] + 1);
- if (scale > 1) { /* scale divisor and dividend */
- carry = 0;
- for (i = 0; i <= 8; i++) {
- work = (num[i] * scale) + carry;
- num[i] = work & 0xff;
- carry = work >> 8;
- if (num[i] != 0) num_hi_sig = i;
- }
- carry = 0;
- for (i = 0; i <= 7; i++) {
- work = (den[i] * scale) + carry;
- den[i] = work & 0xff;
- carry = work >> 8;
- if (den[i] != 0) den_hi_sig = i;
- }
- }
- /* Main loop */
- for (i = quo_hi_sig; i > 0; i--) {
- /* quess the next quotient digit, quo_est, by dividing the first
- two remaining dividend digits by the high order quotient digit.
- quo_est is never low and is at most 2 high. */
- int num_hi; /* index of highest remaining dividend digit */
- num_hi = i + den_hi_sig;
- work = (num[num_hi] * BASE) + (num_hi ? 0 : num[num_hi - 1]);
- if (num[num_hi] != den[den_hi_sig]) {
- quo_est = work / den[den_hi_sig];
- }
- else {
- quo_est = BASE - 1;
- }
- /* refine quo_est so it's usually correct, and at most one high. */
- while ((den[den_hi_sig - 1] * quo_est)
- > (((work - (quo_est * den[den_hi_sig])) * BASE)
- + ((num_hi - 1) ? 0 : num[num_hi - 2]))) {
- quo_est--;
- }
- /* try quo_est as the quotient digit, by multiplying the
- divisor by quo_est and subtracting from the remaining dividend. */
- carry = 0;
- for (j = 0; j <= den_hi_sig; j++) {
- int digit;
- work = num[i + j] - (quo_est * den[j]) + carry;
- digit = work & 0xff;
- carry = work >> 8;
- if (digit < 0) {
- digit += BASE;
- carry--;
- }
- num[i + j] = digit;
- }
- /* if quo_est was high by one, then num[i] went negative and
- we need to correct things. */
- if (num[num_hi] < 0) {
- quo_est--;
- carry = 0; /* add divisor back in */
- for (j = 0; j <= den_hi_sig; j++) {
- work = num[i + j] + den[j] + carry;
- if (work > BASE) {
- work -= BASE;
- carry = 1;
- }
- else {
- carry = 0;
- }
- num[i + j] = work;
- }
- num [num_hi] += carry;
- }
- /* store the quotient digit. */
- quo[i - 1] = quo_est;
- }
- }
- decode (quo, lquo, hquo);
- finish_up:
- /* if result is negative, make it so. */
- if (quo_neg)
- neg_double (*lquo, *hquo, lquo, hquo);
- /* compute trial remainder: rem = num - (quo * den) */
- mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
- neg_double (*lrem, *hrem, lrem, hrem);
- add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
- switch (code)
- {
- case TRUNC_DIV_EXPR:
- case TRUNC_MOD_EXPR: /* round toward zero */
- return;
- case FLOOR_DIV_EXPR:
- case FLOOR_MOD_EXPR: /* round toward negative infinity */
- if (quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio < 0 && rem != 0 */
- {
- /* quo = quo - 1; */
- add_double (*lquo, *hquo, -1, -1, lquo, hquo);
- }
- else return;
- break;
- case CEIL_DIV_EXPR:
- case CEIL_MOD_EXPR: /* round toward positive infinity */
- if (!quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio > 0 && rem != 0 */
- {
- add_double (*lquo, *hquo, 1, 0, lquo, hquo);
- }
- else return;
- break;
-
- case ROUND_DIV_EXPR:
- case ROUND_MOD_EXPR: /* round to closest integer */
- {
- int labs_rem = *lrem, habs_rem = *hrem;
- int labs_den = lden, habs_den = hden, ltwice, htwice;
- /* get absolute values */
- if (*hrem < 0) neg_double(*lrem, *hrem, &labs_rem, &habs_rem);
- if (hden < 0) neg_double(lden, hden, &labs_den, &habs_den);
- /* if (2 * abs (lrem) >= abs (lden)) */
- mul_double(2, 0, labs_rem, habs_rem, <wice, &htwice);
- if (((unsigned) habs_den < (unsigned) htwice)
- || (((unsigned) habs_den == (unsigned) htwice)
- && ((unsigned) labs_den < (unsigned) ltwice)))
- {
- if (*hquo < 0)
- /* quo = quo - 1; */
- add_double (*lquo, *hquo, -1, -1, lquo, hquo);
- else
- /* quo = quo + 1; */
- add_double (*lquo, *hquo, 1, 0, lquo, hquo);
- }
- else return;
- }
- break;
- default:
- abort ();
- }
- /* compute true remainder: rem = num - (quo * den) */
- mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
- neg_double (*lrem, *hrem, lrem, hrem);
- add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
- }
- /* Split a tree IN into a constant and a variable part
- that could be combined with CODE to make IN.
- CODE must be a commutative arithmetic operation.
- Store the constant part into *CONP and the variable in &VARP.
- Return 1 if this was done; zero means the tree IN did not decompose
- this way.
- If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR.
- Therefore, we must tell the caller whether the variable part
- was subtracted. We do this by storing 1 or -1 into *VARSIGNP.
- The value stored is the coefficient for the variable term.
- The constant term we return should always be added;
- we negate it if necessary. */
- static int
- split_tree (in, code, varp, conp, varsignp)
- tree in;
- enum tree_code code;
- tree *varp, *conp;
- int *varsignp;
- {
- register tree outtype = TREE_TYPE (in);
- *varp = 0;
- *conp = 0;
- /* Strip any conversions that don't change the machine mode. */
- while ((TREE_CODE (in) == NOP_EXPR
- || TREE_CODE (in) == CONVERT_EXPR)
- && (TYPE_MODE (TREE_TYPE (in))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0)))))
- in = TREE_OPERAND (in, 0);
- if (TREE_CODE (in) == code
- || (TREE_CODE (TREE_TYPE (in)) != REAL_TYPE
- /* We can associate addition and subtraction together
- (even though the C standard doesn't say so)
- for integers because the value is not affected.
- For reals, the value might be affected, so we can't. */
- &&
- ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
- || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
- {
- enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0));
- if (code == INTEGER_CST || code == REAL_CST)
- {
- *conp = TREE_OPERAND (in, 0);
- *varp = TREE_OPERAND (in, 1);
- if (TREE_TYPE (*varp) != outtype)
- *varp = convert (outtype, *varp);
- *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
- return 1;
- }
- if (TREE_LITERAL (TREE_OPERAND (in, 1)))
- {
- *conp = TREE_OPERAND (in, 1);
- *varp = TREE_OPERAND (in, 0);
- *varsignp = 1;
- if (TREE_TYPE (*varp) != outtype)
- *varp = convert (outtype, *varp);
- if (TREE_CODE (in) == MINUS_EXPR)
- {
- /* If operation is subtraction and constant is second,
- must negate it to get an additive constant.
- And this cannot be done unless it is a manifest constant.
- It could also be the address of a static variable.
- We cannot negate that, so give up. */
- if (TREE_CODE (*conp) == INTEGER_CST
- || TREE_CODE (*conp) == REAL_CST)
- *conp = combine (MINUS_EXPR, integer_zero_node, *conp);
- else
- return 0;
- }
- return 1;
- }
- if (TREE_LITERAL (TREE_OPERAND (in, 0)))
- {
- *conp = TREE_OPERAND (in, 0);
- *varp = TREE_OPERAND (in, 1);
- if (TREE_TYPE (*varp) != outtype)
- *varp = convert (outtype, *varp);
- *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
- return 1;
- }
- }
- return 0;
- }
- /* Combine two constants NUM and ARG2 under operation CODE
- to produce a new constant.
- We assume ARG1 and ARG2 have the same data type,
- or at least are the same kind of constant and the same machine mode. */
- tree
- combine (code, arg1, arg2)
- enum tree_code code;
- register tree arg1, arg2;
- {
- if (TREE_CODE (arg1) == INTEGER_CST)
- {
- register int int1l = TREE_INT_CST_LOW (arg1);
- register int int1h = TREE_INT_CST_HIGH (arg1);
- int int2l = TREE_INT_CST_LOW (arg2);
- int int2h = TREE_INT_CST_HIGH (arg2);
- int low, hi;
- int garbagel, garbageh;
- register tree t;
- int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
- switch (code)
- {
- case BIT_IOR_EXPR:
- t = build_int_2 (int1l | int2l, int1h | int2h);
- break;
- case BIT_XOR_EXPR:
- t = build_int_2 (int1l ^ int2l, int1h ^ int2h);
- break;
- case BIT_AND_EXPR:
- t = build_int_2 (int1l & int2l, int1h & int2h);
- break;
- case BIT_ANDTC_EXPR:
- t = build_int_2 (int1l & ~int2l, int1h & ~int2h);
- break;
- case RSHIFT_EXPR:
- int2l = - int2l;
- case LSHIFT_EXPR:
- lshift_double (int1l, int1h, int2l,
- TYPE_PRECISION (TREE_TYPE (arg1)),
- &low, &hi,
- !uns);
- t = build_int_2 (low, hi);
- break;
- case RROTATE_EXPR:
- int2l = - int2l;
- case LROTATE_EXPR:
- lrotate_double (int1l, int1h, int2l,
- TYPE_PRECISION (TREE_TYPE (arg1)),
- &low, &hi);
- t = build_int_2 (low, hi);
- break;
- case PLUS_EXPR:
- add_double (int1l, int1h, int2l, int2h, &low, &hi);
- t = build_int_2 (low, hi);
- break;
- case MINUS_EXPR:
- neg_double (int2l, int2h, &int2l, &int2h);
- add_double (int1l, int1h, int2l, int2h, &low, &hi);
- t = build_int_2 (low, hi);
- break;
- case MULT_EXPR:
- mul_double (int1l, int1h, int2l, int2h, &low, &hi);
- t = build_int_2 (low, hi);
- break;
- case TRUNC_DIV_EXPR: case ROUND_DIV_EXPR:
- case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
- div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
- &low, &hi, &garbagel, &garbageh);
- t = build_int_2 (low, hi);
- break;
- case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR:
- case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
- div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
- &garbagel, &garbageh, &low, &hi);
- t = build_int_2 (low, hi);
- break;
- case MIN_EXPR:
- case MAX_EXPR:
- if (uns)
- {
- low = (((unsigned) int1h < (unsigned) int2h)
- || (((unsigned) int1h == (unsigned) int2h)
- && ((unsigned) int1l < (unsigned) int2l)));
- }
- else
- {
- low = ((int1h < int2h)
- || ((int1h == int2h)
- && ((unsigned) int1l < (unsigned) int2l)));
- }
- if (low == (code == MIN_EXPR))
- t = build_int_2 (int1l, int1h);
- else
- t = build_int_2 (int2l, int2h);
- break;
- default:
- abort ();
- }
- TREE_TYPE (t) = TREE_TYPE (arg1);
- force_fit_type (t);
- return t;
- }
- if (TREE_CODE (arg1) == REAL_CST)
- {
- register double d1 = TREE_REAL_CST (arg1);
- register double d2 = TREE_REAL_CST (arg2);
- register tree t;
- switch (code)
- {
- case PLUS_EXPR:
- t = build_real (d1 + d2);
- break;
- case MINUS_EXPR:
- t = build_real (d1 - d2);
- break;
- case MULT_EXPR:
- t = build_real (d1 * d2);
- break;
- case RDIV_EXPR:
- if (d2 == 0)
- return 0;
- t = build_real (d1 / d2);
- break;
- case MIN_EXPR:
- if (d1 < d2)
- t = build_real (d1);
- t = build_real (d2);
- break;
- case MAX_EXPR:
- if (d1 > d2)
- t = build_real (d1);
- t = build_real (d2);
- break;
- default:
- abort ();
- }
- TREE_TYPE (t) = TREE_TYPE (arg1);
- return t;
- }
- if (TREE_CODE (arg1) == COMPLEX_CST)
- {
- register tree r1 = TREE_REALPART (arg1);
- register tree i1 = TREE_IMAGPART (arg1);
- register tree r2 = TREE_REALPART (arg2);
- register tree i2 = TREE_IMAGPART (arg2);
- register tree t;
- switch (code)
- {
- case PLUS_EXPR:
- t = build_complex (combine (PLUS_EXPR, r1, r2),
- combine (PLUS_EXPR, i1, i2));
- break;
- case MINUS_EXPR:
- t = build_complex (combine (MINUS_EXPR, r1, r2),
- combine (MINUS_EXPR, i1, i2));
- break;
- case MULT_EXPR:
- t = build_complex (combine (MINUS_EXPR,
- combine (MULT_EXPR, r1, r2),
- combine (MULT_EXPR, i1, i2)),
- combine (PLUS_EXPR,
- combine (MULT_EXPR, r1, i2),
- combine (MULT_EXPR, i1, r2)));
- break;
- case RDIV_EXPR:
- {
- register tree magsquared
- = combine (PLUS_EXPR,
- combine (MULT_EXPR, r2, r2),
- combine (MULT_EXPR, i2, i2));
- t = build_complex (combine (RDIV_EXPR,
- combine (PLUS_EXPR,
- combine (MULT_EXPR, r1, r2),
- combine (MULT_EXPR, i1, i2)),
- magsquared),
- combine (RDIV_EXPR,
- combine (MINUS_EXPR,
- combine (MULT_EXPR, i1, r2),
- combine (MULT_EXPR, r1, i2)),
- magsquared));
- }
- break;
- default:
- abort ();
- }
- TREE_TYPE (t) = TREE_TYPE (arg1);
- return t;
- }
- return 0;
- }
- /* Given T, a tree representing type conversion of a constant,
- return a constant tree representing the result of conversion. */
- static tree
- fold_convert (t)
- register tree t;
- {
- register tree arg1 = TREE_OPERAND (t, 0);
- register tree type = TREE_TYPE (t);
- if (TREE_CODE (type) == POINTER_TYPE
- || TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- {
- if (TREE_CODE (arg1) == INTEGER_CST)
- {
- /* Given an integer constant, make new constant with new type,
- appropriately sign-extended or truncated. */
- register int inprec;
- register int outprec;
- if (TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE)
- inprec = BITS_PER_WORD;
- else
- inprec = TYPE_PRECISION (TREE_TYPE (arg1));
- if (TREE_CODE (type) == POINTER_TYPE)
- outprec = BITS_PER_WORD;
- else
- outprec = TYPE_PRECISION (type);
- t = build_int_2 (TREE_INT_CST_LOW (arg1),
- TREE_INT_CST_HIGH (arg1));
- TREE_TYPE (t) = type;
- force_fit_type (t);
- }
- else if (TREE_CODE (arg1) == REAL_CST)
- t = build_int_2 ((int) TREE_REAL_CST (arg1),
- (int) (TREE_REAL_CST (arg1) / 0x10000 / 0x10000));
- }
- else if (TREE_CODE (type) == REAL_TYPE)
- {
- if (TREE_CODE (arg1) == INTEGER_CST)
- t = build_real_from_int_cst (arg1);
- else if (TREE_CODE (arg1) == REAL_CST)
- t = build_real (TREE_REAL_CST (arg1));
- }
- TREE_TYPE (t) = type;
- TREE_LITERAL (t) = 1;
- return t;
- }
- /* Return nonzero if two constants (that are not manifest constants)
- are necessarily equal. It detects only the easiest, common case of
- equality. */
- static int
- operand_equal_p (arg0, arg1)
- tree arg0, arg1;
- {
- while ((TREE_CODE (arg0) == NOP_EXPR
- || TREE_CODE (arg0) == CONVERT_EXPR)
- && TYPE_MODE (TREE_TYPE (arg0)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg0, 0))))
- arg0 = TREE_OPERAND (arg0, 0);
- while ((TREE_CODE (arg1) == NOP_EXPR
- || TREE_CODE (arg1) == CONVERT_EXPR)
- && TYPE_MODE (TREE_TYPE (arg1)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg1, 0))))
- arg1 = TREE_OPERAND (arg1, 0);
- if (TREE_CODE (arg0) == TREE_CODE (arg1)
- && TREE_CODE (arg0) == ADDR_EXPR
- && TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0))
- return 1;
- return 0;
- }
- /* Perform constant folding and related simplification of EXPR.
- The related simplifications include x*1 => x, x*0 => 0, etc.,
- and application of the associative law.
- NOP_EXPR conversions may be removed freely (as long as we
- are careful not to change the C type of the overall expression)
- We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR,
- but we can constant-fold them if they have constant operands. */
- tree
- fold (expr)
- tree expr;
- {
- register tree t = expr;
- register tree arg0, arg1;
- register enum tree_code code = TREE_CODE (t);
- register int kind;
- /* WINS will be nonzero when the switch is done
- if all operands are constant.
- LOSES will be nonzero when the switch is done
- if any operand is volatile.
- This inhibits optimizations such as (foo () * 0) => 0.
- But identity-element optimizations such as
- (foo () * 1) => (foo ()) can be done even if LOSES is set. */
- int wins = 1;
- int loses = 0;
- /* Return right away if already constant. */
- if (TREE_LITERAL (t))
- {
- if (code == CONST_DECL)
- return DECL_INITIAL (t);
- return t;
- }
-
- kind = *tree_code_type[(int) code];
- if (kind == 'e' || kind == 'r')
- {
- register int len = tree_code_length[(int) code];
- register int i;
- for (i = 0; i < len; i++)
- {
- if (TREE_OPERAND (t, i) == 0)
- continue; /* Valid for CALL_EXPR, at least. */
- if (TREE_CODE (TREE_OPERAND (t, i)) != INTEGER_CST
- && TREE_CODE (TREE_OPERAND (t, i)) != REAL_CST)
- /* Note that TREE_LITERAL isn't enough:
- static var addresses are constant but we can't
- do arithmetic on them. */
- wins = 0;
- if (TREE_VOLATILE (TREE_OPERAND (t, i)))
- loses = 1;
- }
- arg0 = TREE_OPERAND (t, 0);
- if (len > 1)
- arg1 = TREE_OPERAND (t, 1);
- }
- /* Now WINS and LOSES are set as described above,
- ARG0 is the first operand of EXPR,
- and ARG1 is the second operand (if it has more than one operand). */
- switch (code)
- {
- case INTEGER_CST:
- case REAL_CST:
- case STRING_CST:
- case COMPLEX_CST:
- case CONSTRUCTOR:
- return t;
- case CONST_DECL:
- return fold (DECL_INITIAL (t));
- case NOP_EXPR:
- case FLOAT_EXPR:
- case CONVERT_EXPR:
- case FIX_TRUNC_EXPR:
- /* Other kinds of FIX are not handled properly by fold_convert. */
- if (!wins)
- {
- TREE_LITERAL (t) = TREE_LITERAL (arg0);
- return t;
- }
- return fold_convert (t);
- case RANGE_EXPR:
- TREE_LITERAL (t) = wins;
- return t;
- case NEGATE_EXPR:
- if (wins)
- {
- if (TREE_CODE (arg0) == INTEGER_CST)
- {
- if (TREE_INT_CST_LOW (arg0) == 0)
- t = build_int_2 (0, - TREE_INT_CST_HIGH (arg0));
- else
- t = build_int_2 (- TREE_INT_CST_LOW (arg0),
- ~ TREE_INT_CST_HIGH (arg0));
- force_fit_type (t);
- }
- else if (TREE_CODE (arg0) == REAL_CST)
- t = build_real (- TREE_REAL_CST (arg0));
- TREE_TYPE (t) = TREE_TYPE (expr);
- }
- return t;
- case ABS_EXPR:
- if (wins)
- {
- if (TREE_CODE (arg0) == INTEGER_CST)
- {
- if (! TREE_UNSIGNED (TREE_TYPE (expr))
- || TREE_INT_CST_HIGH (arg0) < 0)
- {
- if (TREE_INT_CST_LOW (arg0) == 0)
- t = build_int_2 (0, - TREE_INT_CST_HIGH (arg0));
- else
- t = build_int_2 (- TREE_INT_CST_LOW (arg0),
- ~ TREE_INT_CST_HIGH (arg0));
- }
- }
- else if (TREE_CODE (arg0) == REAL_CST)
- {
- if (TREE_REAL_CST (arg0) < 0)
- t = build_real (- TREE_REAL_CST (arg0));
- }
- TREE_TYPE (t) = TREE_TYPE (expr);
- }
- return t;
- case BIT_NOT_EXPR:
- if (wins)
- {
- if (TREE_CODE (arg0) == INTEGER_CST)
- t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
- ~ TREE_INT_CST_HIGH (arg0));
- TREE_TYPE (t) = TREE_TYPE (expr);
- force_fit_type (t);
- }
- return t;
- case PLUS_EXPR:
- if (integer_zerop (arg0))
- return convert (TREE_TYPE (expr), arg1);
- if (integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg0);
- associate:
- /* In most languages, can't associate operations on floats
- through parentheses. Rather than remember where the parentheses
- were, we don't associate floats at all. It shouldn't matter much. */
- if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
- goto binary;
- /* The varsign == -1 cases happen only for addition and subtraction.
- It says that the arg that was split was really CON minus VAR.
- The rest of the code applies to all associative operations. */
- if (!wins)
- {
- tree var, con, tem;
- int varsign;
- tree inner_arg;
- if (split_tree (arg0, code, &var, &con, &varsign))
- {
- if (varsign == -1)
- {
- /* EXPR is (CON-VAR) +- ARG1. */
- /* If it is + and VAR==ARG1, return just CONST. */
- if (code == PLUS_EXPR && operand_equal_p (var, arg1))
- return con;
-
- /* Otherwise return (CON +- ARG1) - VAR. */
- TREE_SET_CODE (t, MINUS_EXPR);
- TREE_OPERAND (t, 1) = var;
- TREE_OPERAND (t, 0)
- = fold (build (code, TREE_TYPE (t), con, arg1));
- }
- else
- {
- /* EXPR is (VAR+CON) +- ARG1. */
- /* If it is - and VAR==ARG1, return just CONST. */
- if (code == MINUS_EXPR && operand_equal_p (var, arg1))
- return con;
-
- /* Otherwise return VAR +- (ARG1 +- CON). */
- TREE_OPERAND (t, 1) = tem
- = fold (build (code, TREE_TYPE (t), arg1, con));
- TREE_OPERAND (t, 0) = var;
- if (integer_zerop (tem)
- && (code == PLUS_EXPR || code == MINUS_EXPR))
- return var;
- /* If we have x +/- (c - d) [c an explicit integer]
- change it to x -/+ (d - c) since if d is relocatable
- then the latter can be a single immediate insn
- and the former cannot. */
- if (TREE_CODE (tem) == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (tem, 0)) == INTEGER_CST)
- {
- tree tem1 = TREE_OPERAND (tem, 1);
- TREE_OPERAND (tem, 1) = TREE_OPERAND (tem, 0);
- TREE_OPERAND (tem, 0) = tem1;
- TREE_SET_CODE (t,
- (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
- }
- }
- return t;
- }
- if (split_tree (arg1, code, &var, &con, &varsign))
- {
- /* EXPR is ARG0 +- (CON +- VAR). */
- if (varsign == -1)
- TREE_SET_CODE (t,
- (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
- if (TREE_CODE (t) == MINUS_EXPR && operand_equal_p (var, arg0))
- return con;
- TREE_OPERAND (t, 0)
- = fold (build (code, TREE_TYPE (t), arg0, con));
- TREE_OPERAND (t, 1) = var;
- if (integer_zerop (TREE_OPERAND (t, 0))
- && TREE_CODE (t) == PLUS_EXPR)
- return var;
- return t;
- }
- }
- binary:
- {
- register tree t1 = NULL_TREE;
- if (wins)
- t1 = combine (code, arg0, arg1);
- if (t1 != NULL_TREE) return t1;
- return t;
- }
- case MINUS_EXPR:
- if (! wins && integer_zerop (arg0))
- return build (NEGATE_EXPR, TREE_TYPE (expr), arg1);
- if (integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg0);
- /* Fold &x - &x. This can happen from &x.foo - &x. */
- if (operand_equal_p (arg0, arg1))
- return convert (TREE_TYPE (t), integer_zero_node);
- goto associate;
- case MULT_EXPR:
- if (!loses && integer_zerop (arg0))
- return convert (TREE_TYPE (expr), arg0);
- if (!loses && integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg1);
- if (integer_onep (arg0))
- return convert (TREE_TYPE (expr), arg1);
- if (integer_onep (arg1))
- return convert (TREE_TYPE (expr), arg0);
- goto associate;
- case BIT_IOR_EXPR:
- if (!loses && integer_all_onesp (arg0))
- return convert (TREE_TYPE (expr), arg0);
- if (!loses && integer_all_onesp (arg1))
- return convert (TREE_TYPE (expr), arg1);
- case BIT_XOR_EXPR:
- if (integer_zerop (arg0))
- return convert (TREE_TYPE (expr), arg1);
- if (integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg0);
- goto associate;
- case BIT_AND_EXPR:
- if (integer_all_onesp (arg0))
- return convert (TREE_TYPE (expr), arg1);
- if (integer_all_onesp (arg1))
- return convert (TREE_TYPE (expr), arg0);
- if (!loses && integer_zerop (arg0))
- return convert (TREE_TYPE (expr), arg0);
- if (!loses && integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg1);
- /* Simplify (int)((unsigned char)x & 0x377) into (int)(unsigned char)x. */
- if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == NOP_EXPR
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0))))
- {
- int prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)));
- if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_INT
- && (~TREE_INT_CST_LOW (arg0) & ((1 << prec) - 1)) == 0)
- return convert (TREE_TYPE (expr), arg1);
- }
- if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
- {
- int prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
- if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_INT
- && (~TREE_INT_CST_LOW (arg1) & ((1 << prec) - 1)) == 0)
- return convert (TREE_TYPE (expr), arg0);
- }
- goto associate;
- case BIT_ANDTC_EXPR:
- if (integer_all_onesp (arg0))
- return convert (TREE_TYPE (expr), arg1);
- if (integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg0);
- if (!loses && integer_zerop (arg0))
- return convert (TREE_TYPE (expr), arg0);
- if (!loses && integer_all_onesp (arg1))
- return combine (code, arg1, arg1);
- goto binary;
- case TRUNC_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case RDIV_EXPR:
- if (integer_onep (arg1))
- return convert (TREE_TYPE (expr), arg0);
- goto binary;
- case CEIL_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- case ROUND_MOD_EXPR:
- case TRUNC_MOD_EXPR:
- if (!loses && integer_onep (arg1))
- return combine (code, arg1, arg1);
- goto binary;
- case LSHIFT_EXPR:
- case RSHIFT_EXPR:
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- if (integer_zerop (arg1))
- return convert (TREE_TYPE (expr), arg0);
- goto binary;
- case MIN_EXPR: case MAX_EXPR:
- goto associate;
- case TRUTH_NOT_EXPR:
- if (wins)
- {
- if (TREE_CODE (arg0) == INTEGER_CST)
- {
- t = build_int_2 ((TREE_INT_CST_LOW (arg0) == 0
- && TREE_INT_CST_HIGH (arg0) == 0),
- 0);
- TREE_TYPE (t) = integer_type_node;
- }
- if (TREE_CODE (arg0) == REAL_CST)
- {
- t = build_int_2 (TREE_REAL_CST (arg0) == 0, 0);
- TREE_TYPE (t) = integer_type_node;
- }
- }
- return t;
- case TRUTH_AND_EXPR:
- case TRUTH_ANDIF_EXPR:
- if (wins)
- {
- if (TREE_CODE (arg0) == INTEGER_CST
- && TREE_CODE (arg1) == INTEGER_CST)
- t = build_int_2 (((TREE_INT_CST_LOW (arg0) || TREE_INT_CST_HIGH (arg0))
- && (TREE_INT_CST_LOW (arg1) || TREE_INT_CST_HIGH (arg1))),
- 0);
- if (TREE_CODE (arg0) == REAL_CST
- && TREE_CODE (arg1) == REAL_CST)
- t = build_int_2 ((TREE_REAL_CST (arg0) && TREE_REAL_CST (arg1)),
- 0);
- TREE_TYPE (t) = TREE_TYPE (expr);
- }
- return t;
- case TRUTH_OR_EXPR:
- case TRUTH_ORIF_EXPR:
- if (wins)
- {
- if (TREE_CODE (arg0) == INTEGER_CST
- && TREE_CODE (arg1) == INTEGER_CST)
- t = build_int_2 (((TREE_INT_CST_LOW (arg0) || TREE_INT_CST_HIGH (arg0))
- || (TREE_INT_CST_LOW (arg1) || TREE_INT_CST_HIGH (arg1))),
- 0);
- if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
- t = build_int_2 ((TREE_REAL_CST (arg0) || TREE_REAL_CST (arg1)),
- 0);
- TREE_TYPE (t) = TREE_TYPE (expr);
- }
- return t;
- case EQ_EXPR:
- case NE_EXPR:
- case LT_EXPR:
- case GT_EXPR:
- case LE_EXPR:
- case GE_EXPR:
- /* Convert foo++ == CONST into ++foo == CONST + INCR.
- First, see if one arg is constant; find the constant arg
- and the other one. */
- {
- tree constop = 0, varop;
- tree *constoploc;
- if (TREE_LITERAL (arg1))
- constoploc = &TREE_OPERAND (t, 1), constop = arg1, varop = arg0;
- if (TREE_LITERAL (arg0))
- constoploc = &TREE_OPERAND (t, 0), constop = arg0, varop = arg1;
- if (constop && TREE_CODE (varop) == POSTINCREMENT_EXPR)
- {
- tree newconst
- = fold (build (PLUS_EXPR, TREE_TYPE (t),
- constop, TREE_OPERAND (varop, 1)));
- /* This optimization is invalid for ordered comparisons
- if CONST+INCR overflows!
- We can assume that address + integer will not overflow. */
- if (TREE_CODE (newconst) != INTEGER_CST
- || ! tree_int_cst_lt (newconst, constop)
- || code == EQ_EXPR || code == NE_EXPR)
- {
- TREE_CODE (varop) = PREINCREMENT_EXPR;
- *constoploc = newconst;
- return t;
- }
- }
- else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
- {
- tree newconst
- = fold (build (MINUS_EXPR, TREE_TYPE (t),
- constop, TREE_OPERAND (varop, 1)));
- if (TREE_CODE (newconst) != INTEGER_CST
- || tree_int_cst_lt (newconst, constop)
- || code == EQ_EXPR || code == NE_EXPR)
- {
- TREE_CODE (varop) = PREDECREMENT_EXPR;
- *constoploc = newconst;
- return t;
- }
- }
- }
- /* To compute GT, swap the arguments and do LT.
- To compute GE, do LT and invert the result.
- To compute LE, swap the arguments, do LT and invert the result.
- To compute NE, do EQ and invert the result. */
- if (code == LE_EXPR || code == GT_EXPR)
- {
- register tree temp = arg0;
- arg0 = arg1;
- arg1 = temp;
- }
- /* Compute a result for LT or EQ if args permit. */
- if (TREE_CODE (arg0) == INTEGER_CST
- && TREE_CODE (arg1) == INTEGER_CST)
- {
- if (code == EQ_EXPR || code == NE_EXPR)
- t = build_int_2
- (TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1)
- && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1),
- 0);
- else
- t = build_int_2 ((TREE_UNSIGNED (TREE_TYPE (arg0))
- ? INT_CST_LT_UNSIGNED (arg0, arg1)
- : INT_CST_LT (arg0, arg1)),
- 0);
- }
- else if (TREE_CODE (arg0) == REAL_CST
- && TREE_CODE (arg1) == REAL_CST)
- {
- if (code == EQ_EXPR || code == NE_EXPR)
- t = build_int_2 (TREE_REAL_CST (arg0) == TREE_REAL_CST (arg1), 0);
- else
- t = build_int_2 (TREE_REAL_CST (arg0) < TREE_REAL_CST (arg1), 0);
- }
- else
- return t;
- /* If we wanted ...-or-equal, invert the result. */
- if (code == GE_EXPR || code == LE_EXPR || code == NE_EXPR)
- TREE_INT_CST_LOW (t) ^= 1;
- TREE_TYPE (t) = TREE_TYPE (expr);
- return t;
- COND_EXPR:
- if (TREE_LITERAL (arg0))
- return TREE_OPERAND (expr, (integer_zerop (arg0) ? 2 : 1));
- return t;
- default:
- return t;
- } /* switch (code) */
- }
|