simplify-rtx.c revision 117395
190075Sobrien/* RTL simplification functions for GNU compiler. 290075Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3117395Skan 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 490075Sobrien 590075SobrienThis file is part of GCC. 690075Sobrien 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU General Public License as published by the Free 990075SobrienSoftware Foundation; either version 2, or (at your option) any later 1090075Sobrienversion. 1190075Sobrien 1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590075Sobrienfor more details. 1690075Sobrien 1790075SobrienYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090075Sobrien02111-1307, USA. */ 2190075Sobrien 2290075Sobrien 2390075Sobrien#include "config.h" 2490075Sobrien#include "system.h" 2590075Sobrien#include "rtl.h" 26117395Skan#include "tree.h" 2790075Sobrien#include "tm_p.h" 2890075Sobrien#include "regs.h" 2990075Sobrien#include "hard-reg-set.h" 3090075Sobrien#include "flags.h" 3190075Sobrien#include "real.h" 3290075Sobrien#include "insn-config.h" 3390075Sobrien#include "recog.h" 3490075Sobrien#include "function.h" 3590075Sobrien#include "expr.h" 3690075Sobrien#include "toplev.h" 3790075Sobrien#include "output.h" 3890075Sobrien#include "ggc.h" 3990075Sobrien 4090075Sobrien/* Simplification and canonicalization of RTL. */ 4190075Sobrien 4290075Sobrien/* Nonzero if X has the form (PLUS frame-pointer integer). We check for 4390075Sobrien virtual regs here because the simplify_*_operation routines are called 4490075Sobrien by integrate.c, which is called before virtual register instantiation. 4590075Sobrien 46117395Skan ?!? NONZERO_BASE_PLUS_P needs to move into 4790075Sobrien a header file so that their definitions can be shared with the 4890075Sobrien simplification routines in simplify-rtx.c. Until then, do not 49117395Skan change this macro without also changing the copy in simplify-rtx.c. */ 5090075Sobrien 51117395Skan/* Allows reference to the stack pointer. 5290075Sobrien 5390075Sobrien This used to include FIXED_BASE_PLUS_P, however, we can't assume that 5490075Sobrien arg_pointer_rtx by itself is nonzero, because on at least one machine, 5590075Sobrien the i960, the arg pointer is zero when it is unused. */ 5690075Sobrien 5790075Sobrien#define NONZERO_BASE_PLUS_P(X) \ 5890075Sobrien ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \ 5990075Sobrien || (X) == virtual_stack_vars_rtx \ 6090075Sobrien || (X) == virtual_incoming_args_rtx \ 6190075Sobrien || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ 6290075Sobrien && (XEXP (X, 0) == frame_pointer_rtx \ 6390075Sobrien || XEXP (X, 0) == hard_frame_pointer_rtx \ 6490075Sobrien || ((X) == arg_pointer_rtx \ 6590075Sobrien && fixed_regs[ARG_POINTER_REGNUM]) \ 6690075Sobrien || XEXP (X, 0) == virtual_stack_vars_rtx \ 6790075Sobrien || XEXP (X, 0) == virtual_incoming_args_rtx)) \ 6890075Sobrien || (X) == stack_pointer_rtx \ 6990075Sobrien || (X) == virtual_stack_dynamic_rtx \ 7090075Sobrien || (X) == virtual_outgoing_args_rtx \ 7190075Sobrien || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ 7290075Sobrien && (XEXP (X, 0) == stack_pointer_rtx \ 7390075Sobrien || XEXP (X, 0) == virtual_stack_dynamic_rtx \ 7490075Sobrien || XEXP (X, 0) == virtual_outgoing_args_rtx)) \ 7590075Sobrien || GET_CODE (X) == ADDRESSOF) 7690075Sobrien 7790075Sobrien/* Much code operates on (low, high) pairs; the low value is an 7890075Sobrien unsigned wide int, the high value a signed wide int. We 7990075Sobrien occasionally need to sign extend from low to high as if low were a 8090075Sobrien signed wide int. */ 8190075Sobrien#define HWI_SIGN_EXTEND(low) \ 8290075Sobrien ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0)) 8390075Sobrien 8490075Sobrienstatic rtx neg_const_int PARAMS ((enum machine_mode, rtx)); 8590075Sobrienstatic int simplify_plus_minus_op_data_cmp PARAMS ((const void *, 8690075Sobrien const void *)); 8790075Sobrienstatic rtx simplify_plus_minus PARAMS ((enum rtx_code, 8896263Sobrien enum machine_mode, rtx, 8996263Sobrien rtx, int)); 9090075Sobrien 9190075Sobrien/* Negate a CONST_INT rtx, truncating (because a conversion from a 9290075Sobrien maximally negative number can overflow). */ 9390075Sobrienstatic rtx 9490075Sobrienneg_const_int (mode, i) 9590075Sobrien enum machine_mode mode; 9690075Sobrien rtx i; 9790075Sobrien{ 98117395Skan return gen_int_mode (- INTVAL (i), mode); 9990075Sobrien} 10090075Sobrien 10190075Sobrien 102117395Skan/* Make a binary operation by properly ordering the operands and 10390075Sobrien seeing if the expression folds. */ 10490075Sobrien 10590075Sobrienrtx 10690075Sobriensimplify_gen_binary (code, mode, op0, op1) 10790075Sobrien enum rtx_code code; 10890075Sobrien enum machine_mode mode; 10990075Sobrien rtx op0, op1; 11090075Sobrien{ 11190075Sobrien rtx tem; 11290075Sobrien 11390075Sobrien /* Put complex operands first and constants second if commutative. */ 11490075Sobrien if (GET_RTX_CLASS (code) == 'c' 11590075Sobrien && swap_commutative_operands_p (op0, op1)) 11690075Sobrien tem = op0, op0 = op1, op1 = tem; 11790075Sobrien 11890075Sobrien /* If this simplifies, do it. */ 11990075Sobrien tem = simplify_binary_operation (code, mode, op0, op1); 12090075Sobrien if (tem) 12190075Sobrien return tem; 12290075Sobrien 12396263Sobrien /* Handle addition and subtraction specially. Otherwise, just form 12496263Sobrien the operation. */ 12590075Sobrien 12696263Sobrien if (code == PLUS || code == MINUS) 12790075Sobrien { 12896263Sobrien tem = simplify_plus_minus (code, mode, op0, op1, 1); 12996263Sobrien if (tem) 13096263Sobrien return tem; 13190075Sobrien } 13296263Sobrien 13396263Sobrien return gen_rtx_fmt_ee (code, mode, op0, op1); 13490075Sobrien} 13590075Sobrien 13690075Sobrien/* If X is a MEM referencing the constant pool, return the real value. 13790075Sobrien Otherwise return X. */ 13890075Sobrienrtx 13990075Sobrienavoid_constant_pool_reference (x) 14090075Sobrien rtx x; 14190075Sobrien{ 14290075Sobrien rtx c, addr; 14390075Sobrien enum machine_mode cmode; 14490075Sobrien 14590075Sobrien if (GET_CODE (x) != MEM) 14690075Sobrien return x; 14790075Sobrien addr = XEXP (x, 0); 14890075Sobrien 149117395Skan if (GET_CODE (addr) == LO_SUM) 150117395Skan addr = XEXP (addr, 1); 151117395Skan 15290075Sobrien if (GET_CODE (addr) != SYMBOL_REF 15390075Sobrien || ! CONSTANT_POOL_ADDRESS_P (addr)) 15490075Sobrien return x; 15590075Sobrien 15690075Sobrien c = get_pool_constant (addr); 15790075Sobrien cmode = get_pool_mode (addr); 15890075Sobrien 15990075Sobrien /* If we're accessing the constant in a different mode than it was 16090075Sobrien originally stored, attempt to fix that up via subreg simplifications. 16190075Sobrien If that fails we have no choice but to return the original memory. */ 16290075Sobrien if (cmode != GET_MODE (x)) 16390075Sobrien { 16490075Sobrien c = simplify_subreg (GET_MODE (x), c, cmode, 0); 16590075Sobrien return c ? c : x; 16690075Sobrien } 16790075Sobrien 16890075Sobrien return c; 16990075Sobrien} 17090075Sobrien 17190075Sobrien/* Make a unary operation by first seeing if it folds and otherwise making 17290075Sobrien the specified operation. */ 17390075Sobrien 17490075Sobrienrtx 17590075Sobriensimplify_gen_unary (code, mode, op, op_mode) 17690075Sobrien enum rtx_code code; 17790075Sobrien enum machine_mode mode; 17890075Sobrien rtx op; 17990075Sobrien enum machine_mode op_mode; 18090075Sobrien{ 18190075Sobrien rtx tem; 18290075Sobrien 18390075Sobrien /* If this simplifies, use it. */ 18490075Sobrien if ((tem = simplify_unary_operation (code, mode, op, op_mode)) != 0) 18590075Sobrien return tem; 18690075Sobrien 18790075Sobrien return gen_rtx_fmt_e (code, mode, op); 18890075Sobrien} 18990075Sobrien 19090075Sobrien/* Likewise for ternary operations. */ 19190075Sobrien 19290075Sobrienrtx 19390075Sobriensimplify_gen_ternary (code, mode, op0_mode, op0, op1, op2) 19490075Sobrien enum rtx_code code; 19590075Sobrien enum machine_mode mode, op0_mode; 19690075Sobrien rtx op0, op1, op2; 19790075Sobrien{ 19890075Sobrien rtx tem; 19990075Sobrien 20090075Sobrien /* If this simplifies, use it. */ 20190075Sobrien if (0 != (tem = simplify_ternary_operation (code, mode, op0_mode, 20290075Sobrien op0, op1, op2))) 20390075Sobrien return tem; 20490075Sobrien 20590075Sobrien return gen_rtx_fmt_eee (code, mode, op0, op1, op2); 20690075Sobrien} 20790075Sobrien 20890075Sobrien/* Likewise, for relational operations. 20990075Sobrien CMP_MODE specifies mode comparison is done in. 21090075Sobrien */ 21190075Sobrien 21290075Sobrienrtx 21390075Sobriensimplify_gen_relational (code, mode, cmp_mode, op0, op1) 21490075Sobrien enum rtx_code code; 21590075Sobrien enum machine_mode mode; 21690075Sobrien enum machine_mode cmp_mode; 21790075Sobrien rtx op0, op1; 21890075Sobrien{ 21990075Sobrien rtx tem; 22090075Sobrien 22190075Sobrien if ((tem = simplify_relational_operation (code, cmp_mode, op0, op1)) != 0) 22290075Sobrien return tem; 22390075Sobrien 224117395Skan /* For the following tests, ensure const0_rtx is op1. */ 225117395Skan if (op0 == const0_rtx && swap_commutative_operands_p (op0, op1)) 226117395Skan tem = op0, op0 = op1, op1 = tem, code = swap_condition (code); 227117395Skan 228117395Skan /* If op0 is a compare, extract the comparison arguments from it. */ 229117395Skan if (GET_CODE (op0) == COMPARE && op1 == const0_rtx) 230117395Skan op1 = XEXP (op0, 1), op0 = XEXP (op0, 0); 231117395Skan 232117395Skan /* If op0 is a comparison, extract the comparison arguments form it. */ 233117395Skan if (code == NE && op1 == const0_rtx 234117395Skan && GET_RTX_CLASS (GET_CODE (op0)) == '<') 235117395Skan return op0; 236117395Skan else if (code == EQ && op1 == const0_rtx) 237117395Skan { 238117395Skan /* The following tests GET_RTX_CLASS (GET_CODE (op0)) == '<'. */ 239117395Skan enum rtx_code new = reversed_comparison_code (op0, NULL_RTX); 240117395Skan if (new != UNKNOWN) 241117395Skan { 242117395Skan code = new; 243117395Skan mode = cmp_mode; 244117395Skan op1 = XEXP (op0, 1); 245117395Skan op0 = XEXP (op0, 0); 246117395Skan } 247117395Skan } 248117395Skan 24990075Sobrien /* Put complex operands first and constants second. */ 25090075Sobrien if (swap_commutative_operands_p (op0, op1)) 25190075Sobrien tem = op0, op0 = op1, op1 = tem, code = swap_condition (code); 25290075Sobrien 25390075Sobrien return gen_rtx_fmt_ee (code, mode, op0, op1); 25490075Sobrien} 25590075Sobrien 25690075Sobrien/* Replace all occurrences of OLD in X with NEW and try to simplify the 25790075Sobrien resulting RTX. Return a new RTX which is as simplified as possible. */ 25890075Sobrien 25990075Sobrienrtx 26090075Sobriensimplify_replace_rtx (x, old, new) 26190075Sobrien rtx x; 26290075Sobrien rtx old; 26390075Sobrien rtx new; 26490075Sobrien{ 26590075Sobrien enum rtx_code code = GET_CODE (x); 26690075Sobrien enum machine_mode mode = GET_MODE (x); 26790075Sobrien 26890075Sobrien /* If X is OLD, return NEW. Otherwise, if this is an expression, try 26990075Sobrien to build a new expression substituting recursively. If we can't do 27090075Sobrien anything, return our input. */ 27190075Sobrien 27290075Sobrien if (x == old) 27390075Sobrien return new; 27490075Sobrien 27590075Sobrien switch (GET_RTX_CLASS (code)) 27690075Sobrien { 27790075Sobrien case '1': 27890075Sobrien { 27990075Sobrien enum machine_mode op_mode = GET_MODE (XEXP (x, 0)); 28090075Sobrien rtx op = (XEXP (x, 0) == old 28190075Sobrien ? new : simplify_replace_rtx (XEXP (x, 0), old, new)); 28290075Sobrien 28390075Sobrien return simplify_gen_unary (code, mode, op, op_mode); 28490075Sobrien } 28590075Sobrien 28690075Sobrien case '2': 28790075Sobrien case 'c': 28890075Sobrien return 28990075Sobrien simplify_gen_binary (code, mode, 29090075Sobrien simplify_replace_rtx (XEXP (x, 0), old, new), 29190075Sobrien simplify_replace_rtx (XEXP (x, 1), old, new)); 29290075Sobrien case '<': 29390075Sobrien { 29490075Sobrien enum machine_mode op_mode = (GET_MODE (XEXP (x, 0)) != VOIDmode 29590075Sobrien ? GET_MODE (XEXP (x, 0)) 29690075Sobrien : GET_MODE (XEXP (x, 1))); 29790075Sobrien rtx op0 = simplify_replace_rtx (XEXP (x, 0), old, new); 29890075Sobrien rtx op1 = simplify_replace_rtx (XEXP (x, 1), old, new); 29990075Sobrien 30090075Sobrien return 30190075Sobrien simplify_gen_relational (code, mode, 30290075Sobrien (op_mode != VOIDmode 30390075Sobrien ? op_mode 30490075Sobrien : GET_MODE (op0) != VOIDmode 30590075Sobrien ? GET_MODE (op0) 30690075Sobrien : GET_MODE (op1)), 30790075Sobrien op0, op1); 30890075Sobrien } 30990075Sobrien 31090075Sobrien case '3': 31190075Sobrien case 'b': 31290075Sobrien { 31390075Sobrien enum machine_mode op_mode = GET_MODE (XEXP (x, 0)); 31490075Sobrien rtx op0 = simplify_replace_rtx (XEXP (x, 0), old, new); 31590075Sobrien 31690075Sobrien return 317117395Skan simplify_gen_ternary (code, mode, 31890075Sobrien (op_mode != VOIDmode 31990075Sobrien ? op_mode 32090075Sobrien : GET_MODE (op0)), 32190075Sobrien op0, 32290075Sobrien simplify_replace_rtx (XEXP (x, 1), old, new), 32390075Sobrien simplify_replace_rtx (XEXP (x, 2), old, new)); 32490075Sobrien } 32590075Sobrien 32690075Sobrien case 'x': 32790075Sobrien /* The only case we try to handle is a SUBREG. */ 32890075Sobrien if (code == SUBREG) 32990075Sobrien { 33090075Sobrien rtx exp; 33190075Sobrien exp = simplify_gen_subreg (GET_MODE (x), 33290075Sobrien simplify_replace_rtx (SUBREG_REG (x), 33390075Sobrien old, new), 33490075Sobrien GET_MODE (SUBREG_REG (x)), 33590075Sobrien SUBREG_BYTE (x)); 33690075Sobrien if (exp) 33790075Sobrien x = exp; 33890075Sobrien } 33990075Sobrien return x; 34090075Sobrien 341117395Skan case 'o': 342117395Skan if (code == MEM) 343117395Skan return replace_equiv_address_nv (x, 344117395Skan simplify_replace_rtx (XEXP (x, 0), 345117395Skan old, new)); 346117395Skan else if (code == LO_SUM) 347117395Skan { 348117395Skan rtx op0 = simplify_replace_rtx (XEXP (x, 0), old, new); 349117395Skan rtx op1 = simplify_replace_rtx (XEXP (x, 1), old, new); 35090075Sobrien 351117395Skan /* (lo_sum (high x) x) -> x */ 352117395Skan if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1)) 353117395Skan return op1; 35490075Sobrien 355117395Skan return gen_rtx_LO_SUM (mode, op0, op1); 356117395Skan } 357117395Skan else if (code == REG) 35890075Sobrien { 359117395Skan if (REG_P (old) && REGNO (x) == REGNO (old)) 360117395Skan return new; 36190075Sobrien } 36290075Sobrien 363117395Skan return x; 364117395Skan 365117395Skan default: 366117395Skan return x; 36790075Sobrien } 368117395Skan return x; 36990075Sobrien} 370117395Skan 37190075Sobrien/* Try to simplify a unary operation CODE whose output mode is to be 37290075Sobrien MODE with input operand OP whose mode was originally OP_MODE. 37390075Sobrien Return zero if no simplification can be made. */ 37490075Sobrienrtx 37590075Sobriensimplify_unary_operation (code, mode, op, op_mode) 37690075Sobrien enum rtx_code code; 37790075Sobrien enum machine_mode mode; 37890075Sobrien rtx op; 37990075Sobrien enum machine_mode op_mode; 38090075Sobrien{ 38190075Sobrien unsigned int width = GET_MODE_BITSIZE (mode); 38290075Sobrien rtx trueop = avoid_constant_pool_reference (op); 38390075Sobrien 384117395Skan if (code == VEC_DUPLICATE) 385117395Skan { 386117395Skan if (!VECTOR_MODE_P (mode)) 387117395Skan abort (); 388117395Skan if (GET_MODE (trueop) != VOIDmode 389117395Skan && !VECTOR_MODE_P (GET_MODE (trueop)) 390117395Skan && GET_MODE_INNER (mode) != GET_MODE (trueop)) 391117395Skan abort (); 392117395Skan if (GET_MODE (trueop) != VOIDmode 393117395Skan && VECTOR_MODE_P (GET_MODE (trueop)) 394117395Skan && GET_MODE_INNER (mode) != GET_MODE_INNER (GET_MODE (trueop))) 395117395Skan abort (); 396117395Skan if (GET_CODE (trueop) == CONST_INT || GET_CODE (trueop) == CONST_DOUBLE 397117395Skan || GET_CODE (trueop) == CONST_VECTOR) 398117395Skan { 399117395Skan int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode)); 400117395Skan unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size); 401117395Skan rtvec v = rtvec_alloc (n_elts); 402117395Skan unsigned int i; 403117395Skan 404117395Skan if (GET_CODE (trueop) != CONST_VECTOR) 405117395Skan for (i = 0; i < n_elts; i++) 406117395Skan RTVEC_ELT (v, i) = trueop; 407117395Skan else 408117395Skan { 409117395Skan enum machine_mode inmode = GET_MODE (trueop); 410117395Skan int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode)); 411117395Skan unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size); 412117395Skan 413117395Skan if (in_n_elts >= n_elts || n_elts % in_n_elts) 414117395Skan abort (); 415117395Skan for (i = 0; i < n_elts; i++) 416117395Skan RTVEC_ELT (v, i) = CONST_VECTOR_ELT (trueop, i % in_n_elts); 417117395Skan } 418117395Skan return gen_rtx_CONST_VECTOR (mode, v); 419117395Skan } 420117395Skan } 421117395Skan 42290075Sobrien /* The order of these tests is critical so that, for example, we don't 42390075Sobrien check the wrong mode (input vs. output) for a conversion operation, 42490075Sobrien such as FIX. At some point, this should be simplified. */ 42590075Sobrien 42690075Sobrien if (code == FLOAT && GET_MODE (trueop) == VOIDmode 42790075Sobrien && (GET_CODE (trueop) == CONST_DOUBLE || GET_CODE (trueop) == CONST_INT)) 42890075Sobrien { 42990075Sobrien HOST_WIDE_INT hv, lv; 43090075Sobrien REAL_VALUE_TYPE d; 43190075Sobrien 43290075Sobrien if (GET_CODE (trueop) == CONST_INT) 43390075Sobrien lv = INTVAL (trueop), hv = HWI_SIGN_EXTEND (lv); 43490075Sobrien else 43590075Sobrien lv = CONST_DOUBLE_LOW (trueop), hv = CONST_DOUBLE_HIGH (trueop); 43690075Sobrien 43790075Sobrien REAL_VALUE_FROM_INT (d, lv, hv, mode); 43890075Sobrien d = real_value_truncate (mode, d); 43990075Sobrien return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); 44090075Sobrien } 44190075Sobrien else if (code == UNSIGNED_FLOAT && GET_MODE (trueop) == VOIDmode 44290075Sobrien && (GET_CODE (trueop) == CONST_DOUBLE 44390075Sobrien || GET_CODE (trueop) == CONST_INT)) 44490075Sobrien { 44590075Sobrien HOST_WIDE_INT hv, lv; 44690075Sobrien REAL_VALUE_TYPE d; 44790075Sobrien 44890075Sobrien if (GET_CODE (trueop) == CONST_INT) 44990075Sobrien lv = INTVAL (trueop), hv = HWI_SIGN_EXTEND (lv); 45090075Sobrien else 45190075Sobrien lv = CONST_DOUBLE_LOW (trueop), hv = CONST_DOUBLE_HIGH (trueop); 45290075Sobrien 45390075Sobrien if (op_mode == VOIDmode) 45490075Sobrien { 45590075Sobrien /* We don't know how to interpret negative-looking numbers in 45690075Sobrien this case, so don't try to fold those. */ 45790075Sobrien if (hv < 0) 45890075Sobrien return 0; 45990075Sobrien } 46090075Sobrien else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2) 46190075Sobrien ; 46290075Sobrien else 46390075Sobrien hv = 0, lv &= GET_MODE_MASK (op_mode); 46490075Sobrien 46590075Sobrien REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode); 46690075Sobrien d = real_value_truncate (mode, d); 46790075Sobrien return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); 46890075Sobrien } 46990075Sobrien 47090075Sobrien if (GET_CODE (trueop) == CONST_INT 47190075Sobrien && width <= HOST_BITS_PER_WIDE_INT && width > 0) 47290075Sobrien { 47390075Sobrien HOST_WIDE_INT arg0 = INTVAL (trueop); 47490075Sobrien HOST_WIDE_INT val; 47590075Sobrien 47690075Sobrien switch (code) 47790075Sobrien { 47890075Sobrien case NOT: 47990075Sobrien val = ~ arg0; 48090075Sobrien break; 48190075Sobrien 48290075Sobrien case NEG: 48390075Sobrien val = - arg0; 48490075Sobrien break; 48590075Sobrien 48690075Sobrien case ABS: 48790075Sobrien val = (arg0 >= 0 ? arg0 : - arg0); 48890075Sobrien break; 48990075Sobrien 49090075Sobrien case FFS: 49190075Sobrien /* Don't use ffs here. Instead, get low order bit and then its 49290075Sobrien number. If arg0 is zero, this will return 0, as desired. */ 49390075Sobrien arg0 &= GET_MODE_MASK (mode); 49490075Sobrien val = exact_log2 (arg0 & (- arg0)) + 1; 49590075Sobrien break; 49690075Sobrien 49790075Sobrien case TRUNCATE: 49890075Sobrien val = arg0; 49990075Sobrien break; 50090075Sobrien 50190075Sobrien case ZERO_EXTEND: 50296263Sobrien /* When zero-extending a CONST_INT, we need to know its 50396263Sobrien original mode. */ 50490075Sobrien if (op_mode == VOIDmode) 50596263Sobrien abort (); 50690075Sobrien if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT) 50790075Sobrien { 50890075Sobrien /* If we were really extending the mode, 50990075Sobrien we would have to distinguish between zero-extension 51090075Sobrien and sign-extension. */ 51190075Sobrien if (width != GET_MODE_BITSIZE (op_mode)) 51290075Sobrien abort (); 51390075Sobrien val = arg0; 51490075Sobrien } 51590075Sobrien else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT) 51690075Sobrien val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode)); 51790075Sobrien else 51890075Sobrien return 0; 51990075Sobrien break; 52090075Sobrien 52190075Sobrien case SIGN_EXTEND: 52290075Sobrien if (op_mode == VOIDmode) 52390075Sobrien op_mode = mode; 52490075Sobrien if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT) 52590075Sobrien { 52690075Sobrien /* If we were really extending the mode, 52790075Sobrien we would have to distinguish between zero-extension 52890075Sobrien and sign-extension. */ 52990075Sobrien if (width != GET_MODE_BITSIZE (op_mode)) 53090075Sobrien abort (); 53190075Sobrien val = arg0; 53290075Sobrien } 53390075Sobrien else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT) 53490075Sobrien { 53590075Sobrien val 53690075Sobrien = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode)); 53790075Sobrien if (val 53890075Sobrien & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1))) 53990075Sobrien val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode); 54090075Sobrien } 54190075Sobrien else 54290075Sobrien return 0; 54390075Sobrien break; 54490075Sobrien 54590075Sobrien case SQRT: 54690075Sobrien case FLOAT_EXTEND: 54790075Sobrien case FLOAT_TRUNCATE: 54890075Sobrien case SS_TRUNCATE: 54990075Sobrien case US_TRUNCATE: 55090075Sobrien return 0; 55190075Sobrien 55290075Sobrien default: 55390075Sobrien abort (); 55490075Sobrien } 55590075Sobrien 55690075Sobrien val = trunc_int_for_mode (val, mode); 55790075Sobrien 55890075Sobrien return GEN_INT (val); 55990075Sobrien } 56090075Sobrien 56190075Sobrien /* We can do some operations on integer CONST_DOUBLEs. Also allow 56290075Sobrien for a DImode operation on a CONST_INT. */ 56396263Sobrien else if (GET_MODE (trueop) == VOIDmode 56496263Sobrien && width <= HOST_BITS_PER_WIDE_INT * 2 56590075Sobrien && (GET_CODE (trueop) == CONST_DOUBLE 56690075Sobrien || GET_CODE (trueop) == CONST_INT)) 56790075Sobrien { 56890075Sobrien unsigned HOST_WIDE_INT l1, lv; 56990075Sobrien HOST_WIDE_INT h1, hv; 57090075Sobrien 57190075Sobrien if (GET_CODE (trueop) == CONST_DOUBLE) 57290075Sobrien l1 = CONST_DOUBLE_LOW (trueop), h1 = CONST_DOUBLE_HIGH (trueop); 57390075Sobrien else 57490075Sobrien l1 = INTVAL (trueop), h1 = HWI_SIGN_EXTEND (l1); 57590075Sobrien 57690075Sobrien switch (code) 57790075Sobrien { 57890075Sobrien case NOT: 57990075Sobrien lv = ~ l1; 58090075Sobrien hv = ~ h1; 58190075Sobrien break; 58290075Sobrien 58390075Sobrien case NEG: 58490075Sobrien neg_double (l1, h1, &lv, &hv); 58590075Sobrien break; 58690075Sobrien 58790075Sobrien case ABS: 58890075Sobrien if (h1 < 0) 58990075Sobrien neg_double (l1, h1, &lv, &hv); 59090075Sobrien else 59190075Sobrien lv = l1, hv = h1; 59290075Sobrien break; 59390075Sobrien 59490075Sobrien case FFS: 59590075Sobrien hv = 0; 59690075Sobrien if (l1 == 0) 59790075Sobrien lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1; 59890075Sobrien else 59990075Sobrien lv = exact_log2 (l1 & (-l1)) + 1; 60090075Sobrien break; 60190075Sobrien 60290075Sobrien case TRUNCATE: 60390075Sobrien /* This is just a change-of-mode, so do nothing. */ 60490075Sobrien lv = l1, hv = h1; 60590075Sobrien break; 60690075Sobrien 60790075Sobrien case ZERO_EXTEND: 60896263Sobrien if (op_mode == VOIDmode) 60996263Sobrien abort (); 61096263Sobrien 61196263Sobrien if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT) 61290075Sobrien return 0; 61390075Sobrien 61490075Sobrien hv = 0; 61590075Sobrien lv = l1 & GET_MODE_MASK (op_mode); 61690075Sobrien break; 61790075Sobrien 61890075Sobrien case SIGN_EXTEND: 61990075Sobrien if (op_mode == VOIDmode 62090075Sobrien || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT) 62190075Sobrien return 0; 62290075Sobrien else 62390075Sobrien { 62490075Sobrien lv = l1 & GET_MODE_MASK (op_mode); 62590075Sobrien if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT 62690075Sobrien && (lv & ((HOST_WIDE_INT) 1 62790075Sobrien << (GET_MODE_BITSIZE (op_mode) - 1))) != 0) 62890075Sobrien lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode); 62990075Sobrien 63090075Sobrien hv = HWI_SIGN_EXTEND (lv); 63190075Sobrien } 63290075Sobrien break; 63390075Sobrien 63490075Sobrien case SQRT: 63590075Sobrien return 0; 63690075Sobrien 63790075Sobrien default: 63890075Sobrien return 0; 63990075Sobrien } 64090075Sobrien 64190075Sobrien return immed_double_const (lv, hv, mode); 64290075Sobrien } 64390075Sobrien 64490075Sobrien else if (GET_CODE (trueop) == CONST_DOUBLE 64590075Sobrien && GET_MODE_CLASS (mode) == MODE_FLOAT) 64690075Sobrien { 647117395Skan REAL_VALUE_TYPE d; 648117395Skan REAL_VALUE_FROM_CONST_DOUBLE (d, trueop); 64990075Sobrien 650117395Skan switch (code) 651117395Skan { 652117395Skan case SQRT: 653117395Skan /* We don't attempt to optimize this. */ 654117395Skan return 0; 65590075Sobrien 656117395Skan case ABS: 657117395Skan d = REAL_VALUE_ABS (d); 658117395Skan break; 659117395Skan case NEG: 660117395Skan d = REAL_VALUE_NEGATE (d); 661117395Skan break; 662117395Skan case FLOAT_TRUNCATE: 663117395Skan d = real_value_truncate (mode, d); 664117395Skan break; 665117395Skan case FLOAT_EXTEND: 666117395Skan /* All this does is change the mode. */ 667117395Skan break; 668117395Skan case FIX: 669117395Skan real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL); 670117395Skan break; 671117395Skan 672117395Skan default: 673117395Skan abort (); 674117395Skan } 675117395Skan return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); 67690075Sobrien } 67790075Sobrien 67890075Sobrien else if (GET_CODE (trueop) == CONST_DOUBLE 67990075Sobrien && GET_MODE_CLASS (GET_MODE (trueop)) == MODE_FLOAT 68090075Sobrien && GET_MODE_CLASS (mode) == MODE_INT 68190075Sobrien && width <= HOST_BITS_PER_WIDE_INT && width > 0) 68290075Sobrien { 683117395Skan HOST_WIDE_INT i; 684117395Skan REAL_VALUE_TYPE d; 685117395Skan REAL_VALUE_FROM_CONST_DOUBLE (d, trueop); 686117395Skan switch (code) 687117395Skan { 688117395Skan case FIX: i = REAL_VALUE_FIX (d); break; 689117395Skan case UNSIGNED_FIX: i = REAL_VALUE_UNSIGNED_FIX (d); break; 690117395Skan default: 691117395Skan abort (); 692117395Skan } 693117395Skan return gen_int_mode (i, mode); 694117395Skan } 69590075Sobrien 69690075Sobrien /* This was formerly used only for non-IEEE float. 69790075Sobrien eggert@twinsun.com says it is safe for IEEE also. */ 69890075Sobrien else 69990075Sobrien { 70090075Sobrien enum rtx_code reversed; 70190075Sobrien /* There are some simplifications we can do even if the operands 70290075Sobrien aren't constant. */ 70390075Sobrien switch (code) 70490075Sobrien { 70590075Sobrien case NOT: 70690075Sobrien /* (not (not X)) == X. */ 70790075Sobrien if (GET_CODE (op) == NOT) 70890075Sobrien return XEXP (op, 0); 70990075Sobrien 71090075Sobrien /* (not (eq X Y)) == (ne X Y), etc. */ 71190075Sobrien if (mode == BImode && GET_RTX_CLASS (GET_CODE (op)) == '<' 71290075Sobrien && ((reversed = reversed_comparison_code (op, NULL_RTX)) 71390075Sobrien != UNKNOWN)) 71490075Sobrien return gen_rtx_fmt_ee (reversed, 71590075Sobrien op_mode, XEXP (op, 0), XEXP (op, 1)); 71690075Sobrien break; 71790075Sobrien 71890075Sobrien case NEG: 71990075Sobrien /* (neg (neg X)) == X. */ 72090075Sobrien if (GET_CODE (op) == NEG) 72190075Sobrien return XEXP (op, 0); 72290075Sobrien break; 72390075Sobrien 72490075Sobrien case SIGN_EXTEND: 72590075Sobrien /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2)))) 72690075Sobrien becomes just the MINUS if its mode is MODE. This allows 72790075Sobrien folding switch statements on machines using casesi (such as 72890075Sobrien the VAX). */ 72990075Sobrien if (GET_CODE (op) == TRUNCATE 73090075Sobrien && GET_MODE (XEXP (op, 0)) == mode 73190075Sobrien && GET_CODE (XEXP (op, 0)) == MINUS 73290075Sobrien && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF 73390075Sobrien && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF) 73490075Sobrien return XEXP (op, 0); 73590075Sobrien 73690075Sobrien#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) 73790075Sobrien if (! POINTERS_EXTEND_UNSIGNED 73890075Sobrien && mode == Pmode && GET_MODE (op) == ptr_mode 73990075Sobrien && (CONSTANT_P (op) 74090075Sobrien || (GET_CODE (op) == SUBREG 74190075Sobrien && GET_CODE (SUBREG_REG (op)) == REG 74290075Sobrien && REG_POINTER (SUBREG_REG (op)) 74390075Sobrien && GET_MODE (SUBREG_REG (op)) == Pmode))) 74490075Sobrien return convert_memory_address (Pmode, op); 74590075Sobrien#endif 74690075Sobrien break; 74790075Sobrien 74890075Sobrien#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) 74990075Sobrien case ZERO_EXTEND: 75090075Sobrien if (POINTERS_EXTEND_UNSIGNED > 0 75190075Sobrien && mode == Pmode && GET_MODE (op) == ptr_mode 75290075Sobrien && (CONSTANT_P (op) 75390075Sobrien || (GET_CODE (op) == SUBREG 75490075Sobrien && GET_CODE (SUBREG_REG (op)) == REG 75590075Sobrien && REG_POINTER (SUBREG_REG (op)) 75690075Sobrien && GET_MODE (SUBREG_REG (op)) == Pmode))) 75790075Sobrien return convert_memory_address (Pmode, op); 75890075Sobrien break; 75990075Sobrien#endif 760117395Skan 76190075Sobrien default: 76290075Sobrien break; 76390075Sobrien } 76490075Sobrien 76590075Sobrien return 0; 76690075Sobrien } 76790075Sobrien} 76890075Sobrien 76990075Sobrien/* Simplify a binary operation CODE with result mode MODE, operating on OP0 77090075Sobrien and OP1. Return 0 if no simplification is possible. 77190075Sobrien 77290075Sobrien Don't use this for relational operations such as EQ or LT. 77390075Sobrien Use simplify_relational_operation instead. */ 77490075Sobrienrtx 77590075Sobriensimplify_binary_operation (code, mode, op0, op1) 77690075Sobrien enum rtx_code code; 77790075Sobrien enum machine_mode mode; 77890075Sobrien rtx op0, op1; 77990075Sobrien{ 78090075Sobrien HOST_WIDE_INT arg0, arg1, arg0s, arg1s; 78190075Sobrien HOST_WIDE_INT val; 78290075Sobrien unsigned int width = GET_MODE_BITSIZE (mode); 78390075Sobrien rtx tem; 78490075Sobrien rtx trueop0 = avoid_constant_pool_reference (op0); 78590075Sobrien rtx trueop1 = avoid_constant_pool_reference (op1); 78690075Sobrien 78790075Sobrien /* Relational operations don't work here. We must know the mode 78890075Sobrien of the operands in order to do the comparison correctly. 78990075Sobrien Assuming a full word can give incorrect results. 79090075Sobrien Consider comparing 128 with -128 in QImode. */ 79190075Sobrien 79290075Sobrien if (GET_RTX_CLASS (code) == '<') 79390075Sobrien abort (); 79490075Sobrien 79590075Sobrien /* Make sure the constant is second. */ 79690075Sobrien if (GET_RTX_CLASS (code) == 'c' 79790075Sobrien && swap_commutative_operands_p (trueop0, trueop1)) 79890075Sobrien { 79990075Sobrien tem = op0, op0 = op1, op1 = tem; 80090075Sobrien tem = trueop0, trueop0 = trueop1, trueop1 = tem; 80190075Sobrien } 80290075Sobrien 80390075Sobrien if (GET_MODE_CLASS (mode) == MODE_FLOAT 80490075Sobrien && GET_CODE (trueop0) == CONST_DOUBLE 80590075Sobrien && GET_CODE (trueop1) == CONST_DOUBLE 80690075Sobrien && mode == GET_MODE (op0) && mode == GET_MODE (op1)) 80790075Sobrien { 808117395Skan REAL_VALUE_TYPE f0, f1, value; 80990075Sobrien 810117395Skan REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0); 811117395Skan REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1); 812117395Skan f0 = real_value_truncate (mode, f0); 813117395Skan f1 = real_value_truncate (mode, f1); 814117395Skan 815117395Skan if (code == DIV 816117395Skan && !MODE_HAS_INFINITIES (mode) 817117395Skan && REAL_VALUES_EQUAL (f1, dconst0)) 818117395Skan return 0; 819117395Skan 820117395Skan REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1); 821117395Skan 822117395Skan value = real_value_truncate (mode, value); 823117395Skan return CONST_DOUBLE_FROM_REAL_VALUE (value, mode); 82490075Sobrien } 82590075Sobrien 82690075Sobrien /* We can fold some multi-word operations. */ 82790075Sobrien if (GET_MODE_CLASS (mode) == MODE_INT 82890075Sobrien && width == HOST_BITS_PER_WIDE_INT * 2 82990075Sobrien && (GET_CODE (trueop0) == CONST_DOUBLE 83090075Sobrien || GET_CODE (trueop0) == CONST_INT) 83190075Sobrien && (GET_CODE (trueop1) == CONST_DOUBLE 83290075Sobrien || GET_CODE (trueop1) == CONST_INT)) 83390075Sobrien { 83490075Sobrien unsigned HOST_WIDE_INT l1, l2, lv; 83590075Sobrien HOST_WIDE_INT h1, h2, hv; 83690075Sobrien 83790075Sobrien if (GET_CODE (trueop0) == CONST_DOUBLE) 83890075Sobrien l1 = CONST_DOUBLE_LOW (trueop0), h1 = CONST_DOUBLE_HIGH (trueop0); 83990075Sobrien else 84090075Sobrien l1 = INTVAL (trueop0), h1 = HWI_SIGN_EXTEND (l1); 84190075Sobrien 84290075Sobrien if (GET_CODE (trueop1) == CONST_DOUBLE) 84390075Sobrien l2 = CONST_DOUBLE_LOW (trueop1), h2 = CONST_DOUBLE_HIGH (trueop1); 84490075Sobrien else 84590075Sobrien l2 = INTVAL (trueop1), h2 = HWI_SIGN_EXTEND (l2); 84690075Sobrien 84790075Sobrien switch (code) 84890075Sobrien { 84990075Sobrien case MINUS: 85090075Sobrien /* A - B == A + (-B). */ 85190075Sobrien neg_double (l2, h2, &lv, &hv); 85290075Sobrien l2 = lv, h2 = hv; 85390075Sobrien 85490075Sobrien /* .. fall through ... */ 85590075Sobrien 85690075Sobrien case PLUS: 85790075Sobrien add_double (l1, h1, l2, h2, &lv, &hv); 85890075Sobrien break; 85990075Sobrien 86090075Sobrien case MULT: 86190075Sobrien mul_double (l1, h1, l2, h2, &lv, &hv); 86290075Sobrien break; 86390075Sobrien 86490075Sobrien case DIV: case MOD: case UDIV: case UMOD: 86590075Sobrien /* We'd need to include tree.h to do this and it doesn't seem worth 86690075Sobrien it. */ 86790075Sobrien return 0; 86890075Sobrien 86990075Sobrien case AND: 87090075Sobrien lv = l1 & l2, hv = h1 & h2; 87190075Sobrien break; 87290075Sobrien 87390075Sobrien case IOR: 87490075Sobrien lv = l1 | l2, hv = h1 | h2; 87590075Sobrien break; 87690075Sobrien 87790075Sobrien case XOR: 87890075Sobrien lv = l1 ^ l2, hv = h1 ^ h2; 87990075Sobrien break; 88090075Sobrien 88190075Sobrien case SMIN: 88290075Sobrien if (h1 < h2 88390075Sobrien || (h1 == h2 88490075Sobrien && ((unsigned HOST_WIDE_INT) l1 88590075Sobrien < (unsigned HOST_WIDE_INT) l2))) 88690075Sobrien lv = l1, hv = h1; 88790075Sobrien else 88890075Sobrien lv = l2, hv = h2; 88990075Sobrien break; 89090075Sobrien 89190075Sobrien case SMAX: 89290075Sobrien if (h1 > h2 89390075Sobrien || (h1 == h2 89490075Sobrien && ((unsigned HOST_WIDE_INT) l1 89590075Sobrien > (unsigned HOST_WIDE_INT) l2))) 89690075Sobrien lv = l1, hv = h1; 89790075Sobrien else 89890075Sobrien lv = l2, hv = h2; 89990075Sobrien break; 90090075Sobrien 90190075Sobrien case UMIN: 90290075Sobrien if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2 90390075Sobrien || (h1 == h2 90490075Sobrien && ((unsigned HOST_WIDE_INT) l1 90590075Sobrien < (unsigned HOST_WIDE_INT) l2))) 90690075Sobrien lv = l1, hv = h1; 90790075Sobrien else 90890075Sobrien lv = l2, hv = h2; 90990075Sobrien break; 91090075Sobrien 91190075Sobrien case UMAX: 91290075Sobrien if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2 91390075Sobrien || (h1 == h2 91490075Sobrien && ((unsigned HOST_WIDE_INT) l1 91590075Sobrien > (unsigned HOST_WIDE_INT) l2))) 91690075Sobrien lv = l1, hv = h1; 91790075Sobrien else 91890075Sobrien lv = l2, hv = h2; 91990075Sobrien break; 92090075Sobrien 92190075Sobrien case LSHIFTRT: case ASHIFTRT: 92290075Sobrien case ASHIFT: 92390075Sobrien case ROTATE: case ROTATERT: 92490075Sobrien#ifdef SHIFT_COUNT_TRUNCATED 92590075Sobrien if (SHIFT_COUNT_TRUNCATED) 92690075Sobrien l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0; 92790075Sobrien#endif 92890075Sobrien 92990075Sobrien if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode)) 93090075Sobrien return 0; 93190075Sobrien 93290075Sobrien if (code == LSHIFTRT || code == ASHIFTRT) 93390075Sobrien rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 93490075Sobrien code == ASHIFTRT); 93590075Sobrien else if (code == ASHIFT) 93690075Sobrien lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1); 93790075Sobrien else if (code == ROTATE) 93890075Sobrien lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv); 93990075Sobrien else /* code == ROTATERT */ 94090075Sobrien rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv); 94190075Sobrien break; 94290075Sobrien 94390075Sobrien default: 94490075Sobrien return 0; 94590075Sobrien } 94690075Sobrien 94790075Sobrien return immed_double_const (lv, hv, mode); 94890075Sobrien } 94990075Sobrien 95090075Sobrien if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT 95190075Sobrien || width > HOST_BITS_PER_WIDE_INT || width == 0) 95290075Sobrien { 95390075Sobrien /* Even if we can't compute a constant result, 95490075Sobrien there are some cases worth simplifying. */ 95590075Sobrien 95690075Sobrien switch (code) 95790075Sobrien { 95890075Sobrien case PLUS: 959117395Skan /* Maybe simplify x + 0 to x. The two expressions are equivalent 960117395Skan when x is NaN, infinite, or finite and nonzero. They aren't 961117395Skan when x is -0 and the rounding mode is not towards -infinity, 962117395Skan since (-0) + 0 is then 0. */ 963117395Skan if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode)) 96490075Sobrien return op0; 96590075Sobrien 966117395Skan /* ((-a) + b) -> (b - a) and similarly for (a + (-b)). These 967117395Skan transformations are safe even for IEEE. */ 96890075Sobrien if (GET_CODE (op0) == NEG) 96990075Sobrien return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0)); 97090075Sobrien else if (GET_CODE (op1) == NEG) 97190075Sobrien return simplify_gen_binary (MINUS, mode, op0, XEXP (op1, 0)); 97290075Sobrien 97390075Sobrien /* (~a) + 1 -> -a */ 97490075Sobrien if (INTEGRAL_MODE_P (mode) 97590075Sobrien && GET_CODE (op0) == NOT 97690075Sobrien && trueop1 == const1_rtx) 97790075Sobrien return gen_rtx_NEG (mode, XEXP (op0, 0)); 97890075Sobrien 97990075Sobrien /* Handle both-operands-constant cases. We can only add 98090075Sobrien CONST_INTs to constants since the sum of relocatable symbols 98190075Sobrien can't be handled by most assemblers. Don't add CONST_INT 98290075Sobrien to CONST_INT since overflow won't be computed properly if wider 98390075Sobrien than HOST_BITS_PER_WIDE_INT. */ 98490075Sobrien 98590075Sobrien if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode 98690075Sobrien && GET_CODE (op1) == CONST_INT) 98790075Sobrien return plus_constant (op0, INTVAL (op1)); 98890075Sobrien else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode 98990075Sobrien && GET_CODE (op0) == CONST_INT) 99090075Sobrien return plus_constant (op1, INTVAL (op0)); 99190075Sobrien 99290075Sobrien /* See if this is something like X * C - X or vice versa or 99390075Sobrien if the multiplication is written as a shift. If so, we can 99490075Sobrien distribute and make a new multiply, shift, or maybe just 99590075Sobrien have X (if C is 2 in the example above). But don't make 99690075Sobrien real multiply if we didn't have one before. */ 99790075Sobrien 99890075Sobrien if (! FLOAT_MODE_P (mode)) 99990075Sobrien { 100090075Sobrien HOST_WIDE_INT coeff0 = 1, coeff1 = 1; 100190075Sobrien rtx lhs = op0, rhs = op1; 100290075Sobrien int had_mult = 0; 100390075Sobrien 100490075Sobrien if (GET_CODE (lhs) == NEG) 100590075Sobrien coeff0 = -1, lhs = XEXP (lhs, 0); 100690075Sobrien else if (GET_CODE (lhs) == MULT 100790075Sobrien && GET_CODE (XEXP (lhs, 1)) == CONST_INT) 100890075Sobrien { 100990075Sobrien coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0); 101090075Sobrien had_mult = 1; 101190075Sobrien } 101290075Sobrien else if (GET_CODE (lhs) == ASHIFT 101390075Sobrien && GET_CODE (XEXP (lhs, 1)) == CONST_INT 101490075Sobrien && INTVAL (XEXP (lhs, 1)) >= 0 101590075Sobrien && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT) 101690075Sobrien { 101790075Sobrien coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1)); 101890075Sobrien lhs = XEXP (lhs, 0); 101990075Sobrien } 102090075Sobrien 102190075Sobrien if (GET_CODE (rhs) == NEG) 102290075Sobrien coeff1 = -1, rhs = XEXP (rhs, 0); 102390075Sobrien else if (GET_CODE (rhs) == MULT 102490075Sobrien && GET_CODE (XEXP (rhs, 1)) == CONST_INT) 102590075Sobrien { 102690075Sobrien coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0); 102790075Sobrien had_mult = 1; 102890075Sobrien } 102990075Sobrien else if (GET_CODE (rhs) == ASHIFT 103090075Sobrien && GET_CODE (XEXP (rhs, 1)) == CONST_INT 103190075Sobrien && INTVAL (XEXP (rhs, 1)) >= 0 103290075Sobrien && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT) 103390075Sobrien { 103490075Sobrien coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)); 103590075Sobrien rhs = XEXP (rhs, 0); 103690075Sobrien } 103790075Sobrien 103890075Sobrien if (rtx_equal_p (lhs, rhs)) 103990075Sobrien { 104090075Sobrien tem = simplify_gen_binary (MULT, mode, lhs, 104190075Sobrien GEN_INT (coeff0 + coeff1)); 104290075Sobrien return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem; 104390075Sobrien } 104490075Sobrien } 104590075Sobrien 104690075Sobrien /* If one of the operands is a PLUS or a MINUS, see if we can 1047117395Skan simplify this by the associative law. 104890075Sobrien Don't use the associative law for floating point. 104990075Sobrien The inaccuracy makes it nonassociative, 105090075Sobrien and subtle programs can break if operations are associated. */ 105190075Sobrien 105290075Sobrien if (INTEGRAL_MODE_P (mode) 105390075Sobrien && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS 105490075Sobrien || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS 105590075Sobrien || (GET_CODE (op0) == CONST 105690075Sobrien && GET_CODE (XEXP (op0, 0)) == PLUS) 105790075Sobrien || (GET_CODE (op1) == CONST 105890075Sobrien && GET_CODE (XEXP (op1, 0)) == PLUS)) 105996263Sobrien && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0) 106090075Sobrien return tem; 106190075Sobrien break; 106290075Sobrien 106390075Sobrien case COMPARE: 106490075Sobrien#ifdef HAVE_cc0 106590075Sobrien /* Convert (compare FOO (const_int 0)) to FOO unless we aren't 106690075Sobrien using cc0, in which case we want to leave it as a COMPARE 106790075Sobrien so we can distinguish it from a register-register-copy. 106890075Sobrien 106990075Sobrien In IEEE floating point, x-0 is not the same as x. */ 107090075Sobrien 107190075Sobrien if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT 107290075Sobrien || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations) 107390075Sobrien && trueop1 == CONST0_RTX (mode)) 107490075Sobrien return op0; 107590075Sobrien#endif 107690075Sobrien 107790075Sobrien /* Convert (compare (gt (flags) 0) (lt (flags) 0)) to (flags). */ 107890075Sobrien if (((GET_CODE (op0) == GT && GET_CODE (op1) == LT) 107990075Sobrien || (GET_CODE (op0) == GTU && GET_CODE (op1) == LTU)) 108090075Sobrien && XEXP (op0, 1) == const0_rtx && XEXP (op1, 1) == const0_rtx) 108190075Sobrien { 108290075Sobrien rtx xop00 = XEXP (op0, 0); 108390075Sobrien rtx xop10 = XEXP (op1, 0); 108490075Sobrien 108590075Sobrien#ifdef HAVE_cc0 108690075Sobrien if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0) 108790075Sobrien#else 108890075Sobrien if (GET_CODE (xop00) == REG && GET_CODE (xop10) == REG 108990075Sobrien && GET_MODE (xop00) == GET_MODE (xop10) 109090075Sobrien && REGNO (xop00) == REGNO (xop10) 109190075Sobrien && GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC 109290075Sobrien && GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC) 109390075Sobrien#endif 109490075Sobrien return xop00; 109590075Sobrien } 1096117395Skan break; 109790075Sobrien 109890075Sobrien case MINUS: 109990075Sobrien /* We can't assume x-x is 0 even with non-IEEE floating point, 110090075Sobrien but since it is zero except in very strange circumstances, we 110190075Sobrien will treat it as zero with -funsafe-math-optimizations. */ 110290075Sobrien if (rtx_equal_p (trueop0, trueop1) 110390075Sobrien && ! side_effects_p (op0) 110490075Sobrien && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)) 110590075Sobrien return CONST0_RTX (mode); 110690075Sobrien 1107117395Skan /* Change subtraction from zero into negation. (0 - x) is the 1108117395Skan same as -x when x is NaN, infinite, or finite and nonzero. 1109117395Skan But if the mode has signed zeros, and does not round towards 1110117395Skan -infinity, then 0 - 0 is 0, not -0. */ 1111117395Skan if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode)) 111290075Sobrien return gen_rtx_NEG (mode, op1); 111390075Sobrien 111490075Sobrien /* (-1 - a) is ~a. */ 111590075Sobrien if (trueop0 == constm1_rtx) 111690075Sobrien return gen_rtx_NOT (mode, op1); 111790075Sobrien 1118117395Skan /* Subtracting 0 has no effect unless the mode has signed zeros 1119117395Skan and supports rounding towards -infinity. In such a case, 1120117395Skan 0 - 0 is -0. */ 1121117395Skan if (!(HONOR_SIGNED_ZEROS (mode) 1122117395Skan && HONOR_SIGN_DEPENDENT_ROUNDING (mode)) 1123117395Skan && trueop1 == CONST0_RTX (mode)) 112490075Sobrien return op0; 112590075Sobrien 112690075Sobrien /* See if this is something like X * C - X or vice versa or 112790075Sobrien if the multiplication is written as a shift. If so, we can 112890075Sobrien distribute and make a new multiply, shift, or maybe just 112990075Sobrien have X (if C is 2 in the example above). But don't make 113090075Sobrien real multiply if we didn't have one before. */ 113190075Sobrien 113290075Sobrien if (! FLOAT_MODE_P (mode)) 113390075Sobrien { 113490075Sobrien HOST_WIDE_INT coeff0 = 1, coeff1 = 1; 113590075Sobrien rtx lhs = op0, rhs = op1; 113690075Sobrien int had_mult = 0; 113790075Sobrien 113890075Sobrien if (GET_CODE (lhs) == NEG) 113990075Sobrien coeff0 = -1, lhs = XEXP (lhs, 0); 114090075Sobrien else if (GET_CODE (lhs) == MULT 114190075Sobrien && GET_CODE (XEXP (lhs, 1)) == CONST_INT) 114290075Sobrien { 114390075Sobrien coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0); 114490075Sobrien had_mult = 1; 114590075Sobrien } 114690075Sobrien else if (GET_CODE (lhs) == ASHIFT 114790075Sobrien && GET_CODE (XEXP (lhs, 1)) == CONST_INT 114890075Sobrien && INTVAL (XEXP (lhs, 1)) >= 0 114990075Sobrien && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT) 115090075Sobrien { 115190075Sobrien coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1)); 115290075Sobrien lhs = XEXP (lhs, 0); 115390075Sobrien } 115490075Sobrien 115590075Sobrien if (GET_CODE (rhs) == NEG) 115690075Sobrien coeff1 = - 1, rhs = XEXP (rhs, 0); 115790075Sobrien else if (GET_CODE (rhs) == MULT 115890075Sobrien && GET_CODE (XEXP (rhs, 1)) == CONST_INT) 115990075Sobrien { 116090075Sobrien coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0); 116190075Sobrien had_mult = 1; 116290075Sobrien } 116390075Sobrien else if (GET_CODE (rhs) == ASHIFT 116490075Sobrien && GET_CODE (XEXP (rhs, 1)) == CONST_INT 116590075Sobrien && INTVAL (XEXP (rhs, 1)) >= 0 116690075Sobrien && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT) 116790075Sobrien { 116890075Sobrien coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)); 116990075Sobrien rhs = XEXP (rhs, 0); 117090075Sobrien } 117190075Sobrien 117290075Sobrien if (rtx_equal_p (lhs, rhs)) 117390075Sobrien { 117490075Sobrien tem = simplify_gen_binary (MULT, mode, lhs, 117590075Sobrien GEN_INT (coeff0 - coeff1)); 117690075Sobrien return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem; 117790075Sobrien } 117890075Sobrien } 117990075Sobrien 1180117395Skan /* (a - (-b)) -> (a + b). True even for IEEE. */ 118190075Sobrien if (GET_CODE (op1) == NEG) 118290075Sobrien return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0)); 118390075Sobrien 118490075Sobrien /* If one of the operands is a PLUS or a MINUS, see if we can 1185117395Skan simplify this by the associative law. 118690075Sobrien Don't use the associative law for floating point. 118790075Sobrien The inaccuracy makes it nonassociative, 118890075Sobrien and subtle programs can break if operations are associated. */ 118990075Sobrien 119090075Sobrien if (INTEGRAL_MODE_P (mode) 119190075Sobrien && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS 119290075Sobrien || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS 119390075Sobrien || (GET_CODE (op0) == CONST 119490075Sobrien && GET_CODE (XEXP (op0, 0)) == PLUS) 119590075Sobrien || (GET_CODE (op1) == CONST 119690075Sobrien && GET_CODE (XEXP (op1, 0)) == PLUS)) 119796263Sobrien && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0) 119890075Sobrien return tem; 119990075Sobrien 120090075Sobrien /* Don't let a relocatable value get a negative coeff. */ 120190075Sobrien if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode) 120290075Sobrien return simplify_gen_binary (PLUS, mode, 120390075Sobrien op0, 120490075Sobrien neg_const_int (mode, op1)); 120590075Sobrien 120690075Sobrien /* (x - (x & y)) -> (x & ~y) */ 120790075Sobrien if (GET_CODE (op1) == AND) 120890075Sobrien { 120990075Sobrien if (rtx_equal_p (op0, XEXP (op1, 0))) 121090075Sobrien return simplify_gen_binary (AND, mode, op0, 121190075Sobrien gen_rtx_NOT (mode, XEXP (op1, 1))); 121290075Sobrien if (rtx_equal_p (op0, XEXP (op1, 1))) 121390075Sobrien return simplify_gen_binary (AND, mode, op0, 121490075Sobrien gen_rtx_NOT (mode, XEXP (op1, 0))); 121590075Sobrien } 121690075Sobrien break; 121790075Sobrien 121890075Sobrien case MULT: 121990075Sobrien if (trueop1 == constm1_rtx) 122090075Sobrien { 122190075Sobrien tem = simplify_unary_operation (NEG, mode, op0, mode); 122290075Sobrien 122390075Sobrien return tem ? tem : gen_rtx_NEG (mode, op0); 122490075Sobrien } 122590075Sobrien 1226117395Skan /* Maybe simplify x * 0 to 0. The reduction is not valid if 1227117395Skan x is NaN, since x * 0 is then also NaN. Nor is it valid 1228117395Skan when the mode has signed zeros, since multiplying a negative 1229117395Skan number by 0 will give -0, not 0. */ 1230117395Skan if (!HONOR_NANS (mode) 1231117395Skan && !HONOR_SIGNED_ZEROS (mode) 123290075Sobrien && trueop1 == CONST0_RTX (mode) 123390075Sobrien && ! side_effects_p (op0)) 123490075Sobrien return op1; 123590075Sobrien 1236117395Skan /* In IEEE floating point, x*1 is not equivalent to x for 1237117395Skan signalling NaNs. */ 1238117395Skan if (!HONOR_SNANS (mode) 1239117395Skan && trueop1 == CONST1_RTX (mode)) 124090075Sobrien return op0; 124190075Sobrien 124290075Sobrien /* Convert multiply by constant power of two into shift unless 124390075Sobrien we are still generating RTL. This test is a kludge. */ 124490075Sobrien if (GET_CODE (trueop1) == CONST_INT 124590075Sobrien && (val = exact_log2 (INTVAL (trueop1))) >= 0 124690075Sobrien /* If the mode is larger than the host word size, and the 124790075Sobrien uppermost bit is set, then this isn't a power of two due 124890075Sobrien to implicit sign extension. */ 124990075Sobrien && (width <= HOST_BITS_PER_WIDE_INT 125090075Sobrien || val != HOST_BITS_PER_WIDE_INT - 1) 125190075Sobrien && ! rtx_equal_function_value_matters) 125290075Sobrien return gen_rtx_ASHIFT (mode, op0, GEN_INT (val)); 125390075Sobrien 1254117395Skan /* x*2 is x+x and x*(-1) is -x */ 125590075Sobrien if (GET_CODE (trueop1) == CONST_DOUBLE 1256117395Skan && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT 1257117395Skan && GET_MODE (op0) == mode) 125890075Sobrien { 1259117395Skan REAL_VALUE_TYPE d; 1260117395Skan REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1); 126190075Sobrien 1262117395Skan if (REAL_VALUES_EQUAL (d, dconst2)) 126390075Sobrien return gen_rtx_PLUS (mode, op0, copy_rtx (op0)); 126490075Sobrien 1265117395Skan if (REAL_VALUES_EQUAL (d, dconstm1)) 126690075Sobrien return gen_rtx_NEG (mode, op0); 126790075Sobrien } 126890075Sobrien break; 126990075Sobrien 127090075Sobrien case IOR: 127190075Sobrien if (trueop1 == const0_rtx) 127290075Sobrien return op0; 127390075Sobrien if (GET_CODE (trueop1) == CONST_INT 127490075Sobrien && ((INTVAL (trueop1) & GET_MODE_MASK (mode)) 127590075Sobrien == GET_MODE_MASK (mode))) 127690075Sobrien return op1; 127790075Sobrien if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) 127890075Sobrien return op0; 127990075Sobrien /* A | (~A) -> -1 */ 128090075Sobrien if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1)) 128190075Sobrien || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0))) 128290075Sobrien && ! side_effects_p (op0) 128390075Sobrien && GET_MODE_CLASS (mode) != MODE_CC) 128490075Sobrien return constm1_rtx; 128590075Sobrien break; 128690075Sobrien 128790075Sobrien case XOR: 128890075Sobrien if (trueop1 == const0_rtx) 128990075Sobrien return op0; 129090075Sobrien if (GET_CODE (trueop1) == CONST_INT 129190075Sobrien && ((INTVAL (trueop1) & GET_MODE_MASK (mode)) 129290075Sobrien == GET_MODE_MASK (mode))) 129390075Sobrien return gen_rtx_NOT (mode, op0); 129490075Sobrien if (trueop0 == trueop1 && ! side_effects_p (op0) 129590075Sobrien && GET_MODE_CLASS (mode) != MODE_CC) 129690075Sobrien return const0_rtx; 129790075Sobrien break; 129890075Sobrien 129990075Sobrien case AND: 130090075Sobrien if (trueop1 == const0_rtx && ! side_effects_p (op0)) 130190075Sobrien return const0_rtx; 130290075Sobrien if (GET_CODE (trueop1) == CONST_INT 130390075Sobrien && ((INTVAL (trueop1) & GET_MODE_MASK (mode)) 130490075Sobrien == GET_MODE_MASK (mode))) 130590075Sobrien return op0; 130690075Sobrien if (trueop0 == trueop1 && ! side_effects_p (op0) 130790075Sobrien && GET_MODE_CLASS (mode) != MODE_CC) 130890075Sobrien return op0; 130990075Sobrien /* A & (~A) -> 0 */ 131090075Sobrien if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1)) 131190075Sobrien || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0))) 131290075Sobrien && ! side_effects_p (op0) 131390075Sobrien && GET_MODE_CLASS (mode) != MODE_CC) 131490075Sobrien return const0_rtx; 131590075Sobrien break; 131690075Sobrien 131790075Sobrien case UDIV: 131890075Sobrien /* Convert divide by power of two into shift (divide by 1 handled 131990075Sobrien below). */ 132090075Sobrien if (GET_CODE (trueop1) == CONST_INT 132190075Sobrien && (arg1 = exact_log2 (INTVAL (trueop1))) > 0) 132290075Sobrien return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1)); 132390075Sobrien 132490075Sobrien /* ... fall through ... */ 132590075Sobrien 132690075Sobrien case DIV: 132790075Sobrien if (trueop1 == CONST1_RTX (mode)) 132890075Sobrien { 132990075Sobrien /* On some platforms DIV uses narrower mode than its 133090075Sobrien operands. */ 133190075Sobrien rtx x = gen_lowpart_common (mode, op0); 133290075Sobrien if (x) 133390075Sobrien return x; 133490075Sobrien else if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode) 133590075Sobrien return gen_lowpart_SUBREG (mode, op0); 133690075Sobrien else 133790075Sobrien return op0; 133890075Sobrien } 133990075Sobrien 1340117395Skan /* Maybe change 0 / x to 0. This transformation isn't safe for 1341117395Skan modes with NaNs, since 0 / 0 will then be NaN rather than 0. 1342117395Skan Nor is it safe for modes with signed zeros, since dividing 1343117395Skan 0 by a negative number gives -0, not 0. */ 1344117395Skan if (!HONOR_NANS (mode) 1345117395Skan && !HONOR_SIGNED_ZEROS (mode) 134690075Sobrien && trueop0 == CONST0_RTX (mode) 134790075Sobrien && ! side_effects_p (op1)) 134890075Sobrien return op0; 134990075Sobrien 135090075Sobrien /* Change division by a constant into multiplication. Only do 135190075Sobrien this with -funsafe-math-optimizations. */ 135290075Sobrien else if (GET_CODE (trueop1) == CONST_DOUBLE 135390075Sobrien && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT 135490075Sobrien && trueop1 != CONST0_RTX (mode) 135590075Sobrien && flag_unsafe_math_optimizations) 135690075Sobrien { 135790075Sobrien REAL_VALUE_TYPE d; 135890075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1); 135990075Sobrien 136090075Sobrien if (! REAL_VALUES_EQUAL (d, dconst0)) 136190075Sobrien { 136290075Sobrien REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d); 1363117395Skan return gen_rtx_MULT (mode, op0, 136490075Sobrien CONST_DOUBLE_FROM_REAL_VALUE (d, mode)); 136590075Sobrien } 136690075Sobrien } 136790075Sobrien break; 136890075Sobrien 136990075Sobrien case UMOD: 137090075Sobrien /* Handle modulus by power of two (mod with 1 handled below). */ 137190075Sobrien if (GET_CODE (trueop1) == CONST_INT 137290075Sobrien && exact_log2 (INTVAL (trueop1)) > 0) 137390075Sobrien return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1)); 137490075Sobrien 137590075Sobrien /* ... fall through ... */ 137690075Sobrien 137790075Sobrien case MOD: 137890075Sobrien if ((trueop0 == const0_rtx || trueop1 == const1_rtx) 137990075Sobrien && ! side_effects_p (op0) && ! side_effects_p (op1)) 138090075Sobrien return const0_rtx; 138190075Sobrien break; 138290075Sobrien 138390075Sobrien case ROTATERT: 138490075Sobrien case ROTATE: 138590075Sobrien /* Rotating ~0 always results in ~0. */ 138690075Sobrien if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT 138790075Sobrien && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode) 138890075Sobrien && ! side_effects_p (op1)) 138990075Sobrien return op0; 139090075Sobrien 139190075Sobrien /* ... fall through ... */ 139290075Sobrien 139390075Sobrien case ASHIFT: 139490075Sobrien case ASHIFTRT: 139590075Sobrien case LSHIFTRT: 139690075Sobrien if (trueop1 == const0_rtx) 139790075Sobrien return op0; 139890075Sobrien if (trueop0 == const0_rtx && ! side_effects_p (op1)) 139990075Sobrien return op0; 140090075Sobrien break; 140190075Sobrien 140290075Sobrien case SMIN: 1403117395Skan if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (trueop1) == CONST_INT 140490075Sobrien && INTVAL (trueop1) == (HOST_WIDE_INT) 1 << (width -1) 140590075Sobrien && ! side_effects_p (op0)) 140690075Sobrien return op1; 140790075Sobrien else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) 140890075Sobrien return op0; 140990075Sobrien break; 1410117395Skan 141190075Sobrien case SMAX: 141290075Sobrien if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (trueop1) == CONST_INT 141390075Sobrien && ((unsigned HOST_WIDE_INT) INTVAL (trueop1) 141490075Sobrien == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1) 141590075Sobrien && ! side_effects_p (op0)) 141690075Sobrien return op1; 141790075Sobrien else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) 141890075Sobrien return op0; 141990075Sobrien break; 142090075Sobrien 142190075Sobrien case UMIN: 142290075Sobrien if (trueop1 == const0_rtx && ! side_effects_p (op0)) 142390075Sobrien return op1; 142490075Sobrien else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) 142590075Sobrien return op0; 142690075Sobrien break; 1427117395Skan 142890075Sobrien case UMAX: 142990075Sobrien if (trueop1 == constm1_rtx && ! side_effects_p (op0)) 143090075Sobrien return op1; 143190075Sobrien else if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) 143290075Sobrien return op0; 143390075Sobrien break; 143490075Sobrien 143590075Sobrien case SS_PLUS: 143690075Sobrien case US_PLUS: 143790075Sobrien case SS_MINUS: 143890075Sobrien case US_MINUS: 143990075Sobrien /* ??? There are simplifications that can be done. */ 144090075Sobrien return 0; 144190075Sobrien 1442117395Skan case VEC_SELECT: 1443117395Skan case VEC_CONCAT: 1444117395Skan return 0; 1445117395Skan 144690075Sobrien default: 144790075Sobrien abort (); 144890075Sobrien } 1449117395Skan 145090075Sobrien return 0; 145190075Sobrien } 145290075Sobrien 145390075Sobrien /* Get the integer argument values in two forms: 145490075Sobrien zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */ 145590075Sobrien 145690075Sobrien arg0 = INTVAL (trueop0); 145790075Sobrien arg1 = INTVAL (trueop1); 145890075Sobrien 145990075Sobrien if (width < HOST_BITS_PER_WIDE_INT) 146090075Sobrien { 146190075Sobrien arg0 &= ((HOST_WIDE_INT) 1 << width) - 1; 146290075Sobrien arg1 &= ((HOST_WIDE_INT) 1 << width) - 1; 146390075Sobrien 146490075Sobrien arg0s = arg0; 146590075Sobrien if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1))) 146690075Sobrien arg0s |= ((HOST_WIDE_INT) (-1) << width); 146790075Sobrien 146890075Sobrien arg1s = arg1; 146990075Sobrien if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1))) 147090075Sobrien arg1s |= ((HOST_WIDE_INT) (-1) << width); 147190075Sobrien } 147290075Sobrien else 147390075Sobrien { 147490075Sobrien arg0s = arg0; 147590075Sobrien arg1s = arg1; 147690075Sobrien } 147790075Sobrien 147890075Sobrien /* Compute the value of the arithmetic. */ 147990075Sobrien 148090075Sobrien switch (code) 148190075Sobrien { 148290075Sobrien case PLUS: 148390075Sobrien val = arg0s + arg1s; 148490075Sobrien break; 148590075Sobrien 148690075Sobrien case MINUS: 148790075Sobrien val = arg0s - arg1s; 148890075Sobrien break; 148990075Sobrien 149090075Sobrien case MULT: 149190075Sobrien val = arg0s * arg1s; 149290075Sobrien break; 149390075Sobrien 149490075Sobrien case DIV: 149590075Sobrien if (arg1s == 0 149690075Sobrien || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) 149790075Sobrien && arg1s == -1)) 149890075Sobrien return 0; 149990075Sobrien val = arg0s / arg1s; 150090075Sobrien break; 150190075Sobrien 150290075Sobrien case MOD: 150390075Sobrien if (arg1s == 0 150490075Sobrien || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) 150590075Sobrien && arg1s == -1)) 150690075Sobrien return 0; 150790075Sobrien val = arg0s % arg1s; 150890075Sobrien break; 150990075Sobrien 151090075Sobrien case UDIV: 151190075Sobrien if (arg1 == 0 151290075Sobrien || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) 151390075Sobrien && arg1s == -1)) 151490075Sobrien return 0; 151590075Sobrien val = (unsigned HOST_WIDE_INT) arg0 / arg1; 151690075Sobrien break; 151790075Sobrien 151890075Sobrien case UMOD: 151990075Sobrien if (arg1 == 0 152090075Sobrien || (arg0s == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1) 152190075Sobrien && arg1s == -1)) 152290075Sobrien return 0; 152390075Sobrien val = (unsigned HOST_WIDE_INT) arg0 % arg1; 152490075Sobrien break; 152590075Sobrien 152690075Sobrien case AND: 152790075Sobrien val = arg0 & arg1; 152890075Sobrien break; 152990075Sobrien 153090075Sobrien case IOR: 153190075Sobrien val = arg0 | arg1; 153290075Sobrien break; 153390075Sobrien 153490075Sobrien case XOR: 153590075Sobrien val = arg0 ^ arg1; 153690075Sobrien break; 153790075Sobrien 153890075Sobrien case LSHIFTRT: 153990075Sobrien /* If shift count is undefined, don't fold it; let the machine do 154090075Sobrien what it wants. But truncate it if the machine will do that. */ 154190075Sobrien if (arg1 < 0) 154290075Sobrien return 0; 154390075Sobrien 154490075Sobrien#ifdef SHIFT_COUNT_TRUNCATED 154590075Sobrien if (SHIFT_COUNT_TRUNCATED) 154690075Sobrien arg1 %= width; 154790075Sobrien#endif 154890075Sobrien 154990075Sobrien val = ((unsigned HOST_WIDE_INT) arg0) >> arg1; 155090075Sobrien break; 155190075Sobrien 155290075Sobrien case ASHIFT: 155390075Sobrien if (arg1 < 0) 155490075Sobrien return 0; 155590075Sobrien 155690075Sobrien#ifdef SHIFT_COUNT_TRUNCATED 155790075Sobrien if (SHIFT_COUNT_TRUNCATED) 155890075Sobrien arg1 %= width; 155990075Sobrien#endif 156090075Sobrien 156190075Sobrien val = ((unsigned HOST_WIDE_INT) arg0) << arg1; 156290075Sobrien break; 156390075Sobrien 156490075Sobrien case ASHIFTRT: 156590075Sobrien if (arg1 < 0) 156690075Sobrien return 0; 156790075Sobrien 156890075Sobrien#ifdef SHIFT_COUNT_TRUNCATED 156990075Sobrien if (SHIFT_COUNT_TRUNCATED) 157090075Sobrien arg1 %= width; 157190075Sobrien#endif 157290075Sobrien 157390075Sobrien val = arg0s >> arg1; 157490075Sobrien 157590075Sobrien /* Bootstrap compiler may not have sign extended the right shift. 157690075Sobrien Manually extend the sign to insure bootstrap cc matches gcc. */ 157790075Sobrien if (arg0s < 0 && arg1 > 0) 157890075Sobrien val |= ((HOST_WIDE_INT) -1) << (HOST_BITS_PER_WIDE_INT - arg1); 157990075Sobrien 158090075Sobrien break; 158190075Sobrien 158290075Sobrien case ROTATERT: 158390075Sobrien if (arg1 < 0) 158490075Sobrien return 0; 158590075Sobrien 158690075Sobrien arg1 %= width; 158790075Sobrien val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1)) 158890075Sobrien | (((unsigned HOST_WIDE_INT) arg0) >> arg1)); 158990075Sobrien break; 159090075Sobrien 159190075Sobrien case ROTATE: 159290075Sobrien if (arg1 < 0) 159390075Sobrien return 0; 159490075Sobrien 159590075Sobrien arg1 %= width; 159690075Sobrien val = ((((unsigned HOST_WIDE_INT) arg0) << arg1) 159790075Sobrien | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1))); 159890075Sobrien break; 159990075Sobrien 160090075Sobrien case COMPARE: 160190075Sobrien /* Do nothing here. */ 160290075Sobrien return 0; 160390075Sobrien 160490075Sobrien case SMIN: 160590075Sobrien val = arg0s <= arg1s ? arg0s : arg1s; 160690075Sobrien break; 160790075Sobrien 160890075Sobrien case UMIN: 160990075Sobrien val = ((unsigned HOST_WIDE_INT) arg0 161090075Sobrien <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1); 161190075Sobrien break; 161290075Sobrien 161390075Sobrien case SMAX: 161490075Sobrien val = arg0s > arg1s ? arg0s : arg1s; 161590075Sobrien break; 161690075Sobrien 161790075Sobrien case UMAX: 161890075Sobrien val = ((unsigned HOST_WIDE_INT) arg0 161990075Sobrien > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1); 162090075Sobrien break; 162190075Sobrien 162290075Sobrien default: 162390075Sobrien abort (); 162490075Sobrien } 162590075Sobrien 162690075Sobrien val = trunc_int_for_mode (val, mode); 162790075Sobrien 162890075Sobrien return GEN_INT (val); 162990075Sobrien} 163090075Sobrien 163190075Sobrien/* Simplify a PLUS or MINUS, at least one of whose operands may be another 163290075Sobrien PLUS or MINUS. 163390075Sobrien 163490075Sobrien Rather than test for specific case, we do this by a brute-force method 163590075Sobrien and do all possible simplifications until no more changes occur. Then 1636117395Skan we rebuild the operation. 163790075Sobrien 1638117395Skan If FORCE is true, then always generate the rtx. This is used to 163996263Sobrien canonicalize stuff emitted from simplify_gen_binary. Note that this 164096263Sobrien can still fail if the rtx is too complex. It won't fail just because 164196263Sobrien the result is not 'simpler' than the input, however. */ 164296263Sobrien 164390075Sobrienstruct simplify_plus_minus_op_data 164490075Sobrien{ 164590075Sobrien rtx op; 164690075Sobrien int neg; 164790075Sobrien}; 164890075Sobrien 164990075Sobrienstatic int 165090075Sobriensimplify_plus_minus_op_data_cmp (p1, p2) 165190075Sobrien const void *p1; 165290075Sobrien const void *p2; 165390075Sobrien{ 165490075Sobrien const struct simplify_plus_minus_op_data *d1 = p1; 165590075Sobrien const struct simplify_plus_minus_op_data *d2 = p2; 165690075Sobrien 165790075Sobrien return (commutative_operand_precedence (d2->op) 165890075Sobrien - commutative_operand_precedence (d1->op)); 165990075Sobrien} 166090075Sobrien 166190075Sobrienstatic rtx 166296263Sobriensimplify_plus_minus (code, mode, op0, op1, force) 166390075Sobrien enum rtx_code code; 166490075Sobrien enum machine_mode mode; 166590075Sobrien rtx op0, op1; 166696263Sobrien int force; 166790075Sobrien{ 166890075Sobrien struct simplify_plus_minus_op_data ops[8]; 166990075Sobrien rtx result, tem; 167090075Sobrien int n_ops = 2, input_ops = 2, input_consts = 0, n_consts; 167190075Sobrien int first, negate, changed; 167290075Sobrien int i, j; 167390075Sobrien 167490075Sobrien memset ((char *) ops, 0, sizeof ops); 1675117395Skan 167690075Sobrien /* Set up the two operands and then expand them until nothing has been 167790075Sobrien changed. If we run out of room in our array, give up; this should 167890075Sobrien almost never happen. */ 167990075Sobrien 168090075Sobrien ops[0].op = op0; 168190075Sobrien ops[0].neg = 0; 168290075Sobrien ops[1].op = op1; 168390075Sobrien ops[1].neg = (code == MINUS); 168490075Sobrien 168590075Sobrien do 168690075Sobrien { 168790075Sobrien changed = 0; 168890075Sobrien 168990075Sobrien for (i = 0; i < n_ops; i++) 169090075Sobrien { 169190075Sobrien rtx this_op = ops[i].op; 169290075Sobrien int this_neg = ops[i].neg; 169390075Sobrien enum rtx_code this_code = GET_CODE (this_op); 169490075Sobrien 169590075Sobrien switch (this_code) 169690075Sobrien { 169790075Sobrien case PLUS: 169890075Sobrien case MINUS: 169990075Sobrien if (n_ops == 7) 170096263Sobrien return NULL_RTX; 170190075Sobrien 170290075Sobrien ops[n_ops].op = XEXP (this_op, 1); 170390075Sobrien ops[n_ops].neg = (this_code == MINUS) ^ this_neg; 170490075Sobrien n_ops++; 170590075Sobrien 170690075Sobrien ops[i].op = XEXP (this_op, 0); 170790075Sobrien input_ops++; 170890075Sobrien changed = 1; 170990075Sobrien break; 171090075Sobrien 171190075Sobrien case NEG: 171290075Sobrien ops[i].op = XEXP (this_op, 0); 171390075Sobrien ops[i].neg = ! this_neg; 171490075Sobrien changed = 1; 171590075Sobrien break; 171690075Sobrien 171790075Sobrien case CONST: 171896263Sobrien if (n_ops < 7 171996263Sobrien && GET_CODE (XEXP (this_op, 0)) == PLUS 172096263Sobrien && CONSTANT_P (XEXP (XEXP (this_op, 0), 0)) 172196263Sobrien && CONSTANT_P (XEXP (XEXP (this_op, 0), 1))) 172296263Sobrien { 172396263Sobrien ops[i].op = XEXP (XEXP (this_op, 0), 0); 172496263Sobrien ops[n_ops].op = XEXP (XEXP (this_op, 0), 1); 172596263Sobrien ops[n_ops].neg = this_neg; 172696263Sobrien n_ops++; 172796263Sobrien input_consts++; 172896263Sobrien changed = 1; 172996263Sobrien } 173090075Sobrien break; 173190075Sobrien 173290075Sobrien case NOT: 173390075Sobrien /* ~a -> (-a - 1) */ 173490075Sobrien if (n_ops != 7) 173590075Sobrien { 173690075Sobrien ops[n_ops].op = constm1_rtx; 173790075Sobrien ops[n_ops++].neg = this_neg; 173890075Sobrien ops[i].op = XEXP (this_op, 0); 173990075Sobrien ops[i].neg = !this_neg; 174090075Sobrien changed = 1; 174190075Sobrien } 174290075Sobrien break; 174390075Sobrien 174490075Sobrien case CONST_INT: 174590075Sobrien if (this_neg) 174690075Sobrien { 174790075Sobrien ops[i].op = neg_const_int (mode, this_op); 174890075Sobrien ops[i].neg = 0; 174990075Sobrien changed = 1; 175090075Sobrien } 175190075Sobrien break; 175290075Sobrien 175390075Sobrien default: 175490075Sobrien break; 175590075Sobrien } 175690075Sobrien } 175790075Sobrien } 175890075Sobrien while (changed); 175990075Sobrien 176090075Sobrien /* If we only have two operands, we can't do anything. */ 176196263Sobrien if (n_ops <= 2 && !force) 176290075Sobrien return NULL_RTX; 176390075Sobrien 176496263Sobrien /* Count the number of CONSTs we didn't split above. */ 176596263Sobrien for (i = 0; i < n_ops; i++) 176696263Sobrien if (GET_CODE (ops[i].op) == CONST) 176796263Sobrien input_consts++; 176896263Sobrien 176990075Sobrien /* Now simplify each pair of operands until nothing changes. The first 177090075Sobrien time through just simplify constants against each other. */ 177190075Sobrien 177290075Sobrien first = 1; 177390075Sobrien do 177490075Sobrien { 177590075Sobrien changed = first; 177690075Sobrien 177790075Sobrien for (i = 0; i < n_ops - 1; i++) 177890075Sobrien for (j = i + 1; j < n_ops; j++) 177990075Sobrien { 178090075Sobrien rtx lhs = ops[i].op, rhs = ops[j].op; 178190075Sobrien int lneg = ops[i].neg, rneg = ops[j].neg; 178290075Sobrien 178390075Sobrien if (lhs != 0 && rhs != 0 178490075Sobrien && (! first || (CONSTANT_P (lhs) && CONSTANT_P (rhs)))) 178590075Sobrien { 178690075Sobrien enum rtx_code ncode = PLUS; 178790075Sobrien 178890075Sobrien if (lneg != rneg) 178990075Sobrien { 179090075Sobrien ncode = MINUS; 179190075Sobrien if (lneg) 179290075Sobrien tem = lhs, lhs = rhs, rhs = tem; 179390075Sobrien } 179490075Sobrien else if (swap_commutative_operands_p (lhs, rhs)) 179590075Sobrien tem = lhs, lhs = rhs, rhs = tem; 179690075Sobrien 179790075Sobrien tem = simplify_binary_operation (ncode, mode, lhs, rhs); 179890075Sobrien 1799117395Skan /* Reject "simplifications" that just wrap the two 180090075Sobrien arguments in a CONST. Failure to do so can result 180190075Sobrien in infinite recursion with simplify_binary_operation 180290075Sobrien when it calls us to simplify CONST operations. */ 180390075Sobrien if (tem 180490075Sobrien && ! (GET_CODE (tem) == CONST 180590075Sobrien && GET_CODE (XEXP (tem, 0)) == ncode 180690075Sobrien && XEXP (XEXP (tem, 0), 0) == lhs 180790075Sobrien && XEXP (XEXP (tem, 0), 1) == rhs) 180890075Sobrien /* Don't allow -x + -1 -> ~x simplifications in the 180990075Sobrien first pass. This allows us the chance to combine 181090075Sobrien the -1 with other constants. */ 181190075Sobrien && ! (first 181290075Sobrien && GET_CODE (tem) == NOT 181390075Sobrien && XEXP (tem, 0) == rhs)) 181490075Sobrien { 181590075Sobrien lneg &= rneg; 181690075Sobrien if (GET_CODE (tem) == NEG) 181790075Sobrien tem = XEXP (tem, 0), lneg = !lneg; 181890075Sobrien if (GET_CODE (tem) == CONST_INT && lneg) 181990075Sobrien tem = neg_const_int (mode, tem), lneg = 0; 182090075Sobrien 182190075Sobrien ops[i].op = tem; 182290075Sobrien ops[i].neg = lneg; 182390075Sobrien ops[j].op = NULL_RTX; 182490075Sobrien changed = 1; 182590075Sobrien } 182690075Sobrien } 182790075Sobrien } 182890075Sobrien 182990075Sobrien first = 0; 183090075Sobrien } 183190075Sobrien while (changed); 183290075Sobrien 183390075Sobrien /* Pack all the operands to the lower-numbered entries. */ 183490075Sobrien for (i = 0, j = 0; j < n_ops; j++) 183590075Sobrien if (ops[j].op) 183690075Sobrien ops[i++] = ops[j]; 183790075Sobrien n_ops = i; 183890075Sobrien 183990075Sobrien /* Sort the operations based on swap_commutative_operands_p. */ 184090075Sobrien qsort (ops, n_ops, sizeof (*ops), simplify_plus_minus_op_data_cmp); 184190075Sobrien 184290075Sobrien /* We suppressed creation of trivial CONST expressions in the 184390075Sobrien combination loop to avoid recursion. Create one manually now. 184490075Sobrien The combination loop should have ensured that there is exactly 184590075Sobrien one CONST_INT, and the sort will have ensured that it is last 184690075Sobrien in the array and that any other constant will be next-to-last. */ 184790075Sobrien 184890075Sobrien if (n_ops > 1 184990075Sobrien && GET_CODE (ops[n_ops - 1].op) == CONST_INT 185090075Sobrien && CONSTANT_P (ops[n_ops - 2].op)) 185190075Sobrien { 185290075Sobrien rtx value = ops[n_ops - 1].op; 185390075Sobrien if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg) 185490075Sobrien value = neg_const_int (mode, value); 185590075Sobrien ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value)); 185690075Sobrien n_ops--; 185790075Sobrien } 185890075Sobrien 185990075Sobrien /* Count the number of CONSTs that we generated. */ 186090075Sobrien n_consts = 0; 186190075Sobrien for (i = 0; i < n_ops; i++) 186290075Sobrien if (GET_CODE (ops[i].op) == CONST) 186390075Sobrien n_consts++; 186490075Sobrien 186590075Sobrien /* Give up if we didn't reduce the number of operands we had. Make 186690075Sobrien sure we count a CONST as two operands. If we have the same 186790075Sobrien number of operands, but have made more CONSTs than before, this 186890075Sobrien is also an improvement, so accept it. */ 186996263Sobrien if (!force 187096263Sobrien && (n_ops + n_consts > input_ops 1871117395Skan || (n_ops + n_consts == input_ops && n_consts <= input_consts))) 187290075Sobrien return NULL_RTX; 187390075Sobrien 187490075Sobrien /* Put a non-negated operand first. If there aren't any, make all 187590075Sobrien operands positive and negate the whole thing later. */ 187690075Sobrien 187790075Sobrien negate = 0; 187890075Sobrien for (i = 0; i < n_ops && ops[i].neg; i++) 187990075Sobrien continue; 188090075Sobrien if (i == n_ops) 188190075Sobrien { 188290075Sobrien for (i = 0; i < n_ops; i++) 188390075Sobrien ops[i].neg = 0; 188490075Sobrien negate = 1; 188590075Sobrien } 188690075Sobrien else if (i != 0) 188790075Sobrien { 188890075Sobrien tem = ops[0].op; 188990075Sobrien ops[0] = ops[i]; 189090075Sobrien ops[i].op = tem; 189190075Sobrien ops[i].neg = 1; 189290075Sobrien } 189390075Sobrien 189490075Sobrien /* Now make the result by performing the requested operations. */ 189590075Sobrien result = ops[0].op; 189690075Sobrien for (i = 1; i < n_ops; i++) 189790075Sobrien result = gen_rtx_fmt_ee (ops[i].neg ? MINUS : PLUS, 189890075Sobrien mode, result, ops[i].op); 189990075Sobrien 190090075Sobrien return negate ? gen_rtx_NEG (mode, result) : result; 190190075Sobrien} 190290075Sobrien 190390075Sobrien/* Like simplify_binary_operation except used for relational operators. 190490075Sobrien MODE is the mode of the operands, not that of the result. If MODE 190590075Sobrien is VOIDmode, both operands must also be VOIDmode and we compare the 190690075Sobrien operands in "infinite precision". 190790075Sobrien 190890075Sobrien If no simplification is possible, this function returns zero. Otherwise, 190990075Sobrien it returns either const_true_rtx or const0_rtx. */ 191090075Sobrien 191190075Sobrienrtx 191290075Sobriensimplify_relational_operation (code, mode, op0, op1) 191390075Sobrien enum rtx_code code; 191490075Sobrien enum machine_mode mode; 191590075Sobrien rtx op0, op1; 191690075Sobrien{ 191790075Sobrien int equal, op0lt, op0ltu, op1lt, op1ltu; 191890075Sobrien rtx tem; 191990075Sobrien rtx trueop0; 192090075Sobrien rtx trueop1; 192190075Sobrien 192290075Sobrien if (mode == VOIDmode 192390075Sobrien && (GET_MODE (op0) != VOIDmode 192490075Sobrien || GET_MODE (op1) != VOIDmode)) 192590075Sobrien abort (); 192690075Sobrien 192790075Sobrien /* If op0 is a compare, extract the comparison arguments from it. */ 192890075Sobrien if (GET_CODE (op0) == COMPARE && op1 == const0_rtx) 192990075Sobrien op1 = XEXP (op0, 1), op0 = XEXP (op0, 0); 193090075Sobrien 193190075Sobrien trueop0 = avoid_constant_pool_reference (op0); 193290075Sobrien trueop1 = avoid_constant_pool_reference (op1); 193390075Sobrien 193490075Sobrien /* We can't simplify MODE_CC values since we don't know what the 193590075Sobrien actual comparison is. */ 193690075Sobrien if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC 193790075Sobrien#ifdef HAVE_cc0 193890075Sobrien || op0 == cc0_rtx 193990075Sobrien#endif 194090075Sobrien ) 194190075Sobrien return 0; 194290075Sobrien 194390075Sobrien /* Make sure the constant is second. */ 194490075Sobrien if (swap_commutative_operands_p (trueop0, trueop1)) 194590075Sobrien { 194690075Sobrien tem = op0, op0 = op1, op1 = tem; 194790075Sobrien tem = trueop0, trueop0 = trueop1, trueop1 = tem; 194890075Sobrien code = swap_condition (code); 194990075Sobrien } 195090075Sobrien 195190075Sobrien /* For integer comparisons of A and B maybe we can simplify A - B and can 195290075Sobrien then simplify a comparison of that with zero. If A and B are both either 195390075Sobrien a register or a CONST_INT, this can't help; testing for these cases will 195490075Sobrien prevent infinite recursion here and speed things up. 195590075Sobrien 195690075Sobrien If CODE is an unsigned comparison, then we can never do this optimization, 195790075Sobrien because it gives an incorrect result if the subtraction wraps around zero. 195890075Sobrien ANSI C defines unsigned operations such that they never overflow, and 195990075Sobrien thus such cases can not be ignored. */ 196090075Sobrien 196190075Sobrien if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx 196290075Sobrien && ! ((GET_CODE (op0) == REG || GET_CODE (trueop0) == CONST_INT) 196390075Sobrien && (GET_CODE (op1) == REG || GET_CODE (trueop1) == CONST_INT)) 196490075Sobrien && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1)) 196590075Sobrien && code != GTU && code != GEU && code != LTU && code != LEU) 196690075Sobrien return simplify_relational_operation (signed_condition (code), 196790075Sobrien mode, tem, const0_rtx); 196890075Sobrien 196990075Sobrien if (flag_unsafe_math_optimizations && code == ORDERED) 197090075Sobrien return const_true_rtx; 197190075Sobrien 197290075Sobrien if (flag_unsafe_math_optimizations && code == UNORDERED) 197390075Sobrien return const0_rtx; 197490075Sobrien 1975117395Skan /* For modes without NaNs, if the two operands are equal, we know the 1976117395Skan result. Nevertheless, don't discard them if they have side-effects. */ 1977117395Skan if (!HONOR_NANS (GET_MODE (trueop0)) 1978117395Skan && rtx_equal_p (trueop0, trueop1) 1979117395Skan && ! side_effects_p (trueop0)) 198090075Sobrien equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0; 198190075Sobrien 198290075Sobrien /* If the operands are floating-point constants, see if we can fold 198390075Sobrien the result. */ 198490075Sobrien else if (GET_CODE (trueop0) == CONST_DOUBLE 198590075Sobrien && GET_CODE (trueop1) == CONST_DOUBLE 198690075Sobrien && GET_MODE_CLASS (GET_MODE (trueop0)) == MODE_FLOAT) 198790075Sobrien { 1988117395Skan REAL_VALUE_TYPE d0, d1; 198990075Sobrien 1990117395Skan REAL_VALUE_FROM_CONST_DOUBLE (d0, trueop0); 1991117395Skan REAL_VALUE_FROM_CONST_DOUBLE (d1, trueop1); 199290075Sobrien 1993117395Skan /* Comparisons are unordered iff at least one of the values is NaN. */ 1994117395Skan if (REAL_VALUE_ISNAN (d0) || REAL_VALUE_ISNAN (d1)) 199590075Sobrien switch (code) 199690075Sobrien { 199790075Sobrien case UNEQ: 199890075Sobrien case UNLT: 199990075Sobrien case UNGT: 200090075Sobrien case UNLE: 200190075Sobrien case UNGE: 200290075Sobrien case NE: 200390075Sobrien case UNORDERED: 200490075Sobrien return const_true_rtx; 200590075Sobrien case EQ: 200690075Sobrien case LT: 200790075Sobrien case GT: 200890075Sobrien case LE: 200990075Sobrien case GE: 201090075Sobrien case LTGT: 201190075Sobrien case ORDERED: 201290075Sobrien return const0_rtx; 201390075Sobrien default: 201490075Sobrien return 0; 201590075Sobrien } 201690075Sobrien 2017117395Skan equal = REAL_VALUES_EQUAL (d0, d1); 2018117395Skan op0lt = op0ltu = REAL_VALUES_LESS (d0, d1); 2019117395Skan op1lt = op1ltu = REAL_VALUES_LESS (d1, d0); 202090075Sobrien } 202190075Sobrien 202290075Sobrien /* Otherwise, see if the operands are both integers. */ 202390075Sobrien else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode) 202490075Sobrien && (GET_CODE (trueop0) == CONST_DOUBLE 202590075Sobrien || GET_CODE (trueop0) == CONST_INT) 202690075Sobrien && (GET_CODE (trueop1) == CONST_DOUBLE 202790075Sobrien || GET_CODE (trueop1) == CONST_INT)) 202890075Sobrien { 202990075Sobrien int width = GET_MODE_BITSIZE (mode); 203090075Sobrien HOST_WIDE_INT l0s, h0s, l1s, h1s; 203190075Sobrien unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u; 203290075Sobrien 203390075Sobrien /* Get the two words comprising each integer constant. */ 203490075Sobrien if (GET_CODE (trueop0) == CONST_DOUBLE) 203590075Sobrien { 203690075Sobrien l0u = l0s = CONST_DOUBLE_LOW (trueop0); 203790075Sobrien h0u = h0s = CONST_DOUBLE_HIGH (trueop0); 203890075Sobrien } 203990075Sobrien else 204090075Sobrien { 204190075Sobrien l0u = l0s = INTVAL (trueop0); 204290075Sobrien h0u = h0s = HWI_SIGN_EXTEND (l0s); 204390075Sobrien } 2044117395Skan 204590075Sobrien if (GET_CODE (trueop1) == CONST_DOUBLE) 204690075Sobrien { 204790075Sobrien l1u = l1s = CONST_DOUBLE_LOW (trueop1); 204890075Sobrien h1u = h1s = CONST_DOUBLE_HIGH (trueop1); 204990075Sobrien } 205090075Sobrien else 205190075Sobrien { 205290075Sobrien l1u = l1s = INTVAL (trueop1); 205390075Sobrien h1u = h1s = HWI_SIGN_EXTEND (l1s); 205490075Sobrien } 205590075Sobrien 205690075Sobrien /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT, 205790075Sobrien we have to sign or zero-extend the values. */ 205890075Sobrien if (width != 0 && width < HOST_BITS_PER_WIDE_INT) 205990075Sobrien { 206090075Sobrien l0u &= ((HOST_WIDE_INT) 1 << width) - 1; 206190075Sobrien l1u &= ((HOST_WIDE_INT) 1 << width) - 1; 206290075Sobrien 206390075Sobrien if (l0s & ((HOST_WIDE_INT) 1 << (width - 1))) 206490075Sobrien l0s |= ((HOST_WIDE_INT) (-1) << width); 206590075Sobrien 206690075Sobrien if (l1s & ((HOST_WIDE_INT) 1 << (width - 1))) 206790075Sobrien l1s |= ((HOST_WIDE_INT) (-1) << width); 206890075Sobrien } 206990075Sobrien if (width != 0 && width <= HOST_BITS_PER_WIDE_INT) 207090075Sobrien h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s); 207190075Sobrien 207290075Sobrien equal = (h0u == h1u && l0u == l1u); 207390075Sobrien op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u)); 207490075Sobrien op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u)); 207590075Sobrien op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u)); 207690075Sobrien op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u)); 207790075Sobrien } 207890075Sobrien 207990075Sobrien /* Otherwise, there are some code-specific tests we can make. */ 208090075Sobrien else 208190075Sobrien { 208290075Sobrien switch (code) 208390075Sobrien { 208490075Sobrien case EQ: 208590075Sobrien /* References to the frame plus a constant or labels cannot 208690075Sobrien be zero, but a SYMBOL_REF can due to #pragma weak. */ 208790075Sobrien if (((NONZERO_BASE_PLUS_P (op0) && trueop1 == const0_rtx) 208890075Sobrien || GET_CODE (trueop0) == LABEL_REF) 208990075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM 209090075Sobrien /* On some machines, the ap reg can be 0 sometimes. */ 209190075Sobrien && op0 != arg_pointer_rtx 209290075Sobrien#endif 209390075Sobrien ) 209490075Sobrien return const0_rtx; 209590075Sobrien break; 209690075Sobrien 209790075Sobrien case NE: 209890075Sobrien if (((NONZERO_BASE_PLUS_P (op0) && trueop1 == const0_rtx) 209990075Sobrien || GET_CODE (trueop0) == LABEL_REF) 210090075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM 210190075Sobrien && op0 != arg_pointer_rtx 210290075Sobrien#endif 210390075Sobrien ) 210490075Sobrien return const_true_rtx; 210590075Sobrien break; 210690075Sobrien 210790075Sobrien case GEU: 210890075Sobrien /* Unsigned values are never negative. */ 210990075Sobrien if (trueop1 == const0_rtx) 211090075Sobrien return const_true_rtx; 211190075Sobrien break; 211290075Sobrien 211390075Sobrien case LTU: 211490075Sobrien if (trueop1 == const0_rtx) 211590075Sobrien return const0_rtx; 211690075Sobrien break; 211790075Sobrien 211890075Sobrien case LEU: 211990075Sobrien /* Unsigned values are never greater than the largest 212090075Sobrien unsigned value. */ 212190075Sobrien if (GET_CODE (trueop1) == CONST_INT 212290075Sobrien && (unsigned HOST_WIDE_INT) INTVAL (trueop1) == GET_MODE_MASK (mode) 212390075Sobrien && INTEGRAL_MODE_P (mode)) 212490075Sobrien return const_true_rtx; 212590075Sobrien break; 212690075Sobrien 212790075Sobrien case GTU: 212890075Sobrien if (GET_CODE (trueop1) == CONST_INT 212990075Sobrien && (unsigned HOST_WIDE_INT) INTVAL (trueop1) == GET_MODE_MASK (mode) 213090075Sobrien && INTEGRAL_MODE_P (mode)) 213190075Sobrien return const0_rtx; 213290075Sobrien break; 2133117395Skan 2134117395Skan case LT: 2135117395Skan /* Optimize abs(x) < 0.0. */ 2136117395Skan if (trueop1 == CONST0_RTX (mode) && !HONOR_SNANS (mode)) 2137117395Skan { 2138117395Skan tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0) 2139117395Skan : trueop0; 2140117395Skan if (GET_CODE (tem) == ABS) 2141117395Skan return const0_rtx; 2142117395Skan } 2143117395Skan break; 2144117395Skan 2145117395Skan case GE: 2146117395Skan /* Optimize abs(x) >= 0.0. */ 2147117395Skan if (trueop1 == CONST0_RTX (mode) && !HONOR_NANS (mode)) 2148117395Skan { 2149117395Skan tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0) 2150117395Skan : trueop0; 2151117395Skan if (GET_CODE (tem) == ABS) 2152117395Skan return const1_rtx; 2153117395Skan } 2154117395Skan break; 2155117395Skan 215690075Sobrien default: 215790075Sobrien break; 215890075Sobrien } 215990075Sobrien 216090075Sobrien return 0; 216190075Sobrien } 216290075Sobrien 216390075Sobrien /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set 216490075Sobrien as appropriate. */ 216590075Sobrien switch (code) 216690075Sobrien { 216790075Sobrien case EQ: 216890075Sobrien case UNEQ: 216990075Sobrien return equal ? const_true_rtx : const0_rtx; 217090075Sobrien case NE: 217190075Sobrien case LTGT: 217290075Sobrien return ! equal ? const_true_rtx : const0_rtx; 217390075Sobrien case LT: 217490075Sobrien case UNLT: 217590075Sobrien return op0lt ? const_true_rtx : const0_rtx; 217690075Sobrien case GT: 217790075Sobrien case UNGT: 217890075Sobrien return op1lt ? const_true_rtx : const0_rtx; 217990075Sobrien case LTU: 218090075Sobrien return op0ltu ? const_true_rtx : const0_rtx; 218190075Sobrien case GTU: 218290075Sobrien return op1ltu ? const_true_rtx : const0_rtx; 218390075Sobrien case LE: 218490075Sobrien case UNLE: 218590075Sobrien return equal || op0lt ? const_true_rtx : const0_rtx; 218690075Sobrien case GE: 218790075Sobrien case UNGE: 218890075Sobrien return equal || op1lt ? const_true_rtx : const0_rtx; 218990075Sobrien case LEU: 219090075Sobrien return equal || op0ltu ? const_true_rtx : const0_rtx; 219190075Sobrien case GEU: 219290075Sobrien return equal || op1ltu ? const_true_rtx : const0_rtx; 219390075Sobrien case ORDERED: 219490075Sobrien return const_true_rtx; 219590075Sobrien case UNORDERED: 219690075Sobrien return const0_rtx; 219790075Sobrien default: 219890075Sobrien abort (); 219990075Sobrien } 220090075Sobrien} 220190075Sobrien 220290075Sobrien/* Simplify CODE, an operation with result mode MODE and three operands, 220390075Sobrien OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became 220490075Sobrien a constant. Return 0 if no simplifications is possible. */ 220590075Sobrien 220690075Sobrienrtx 220790075Sobriensimplify_ternary_operation (code, mode, op0_mode, op0, op1, op2) 220890075Sobrien enum rtx_code code; 220990075Sobrien enum machine_mode mode, op0_mode; 221090075Sobrien rtx op0, op1, op2; 221190075Sobrien{ 221290075Sobrien unsigned int width = GET_MODE_BITSIZE (mode); 221390075Sobrien 221490075Sobrien /* VOIDmode means "infinite" precision. */ 221590075Sobrien if (width == 0) 221690075Sobrien width = HOST_BITS_PER_WIDE_INT; 221790075Sobrien 221890075Sobrien switch (code) 221990075Sobrien { 222090075Sobrien case SIGN_EXTRACT: 222190075Sobrien case ZERO_EXTRACT: 222290075Sobrien if (GET_CODE (op0) == CONST_INT 222390075Sobrien && GET_CODE (op1) == CONST_INT 222490075Sobrien && GET_CODE (op2) == CONST_INT 222590075Sobrien && ((unsigned) INTVAL (op1) + (unsigned) INTVAL (op2) <= width) 222690075Sobrien && width <= (unsigned) HOST_BITS_PER_WIDE_INT) 222790075Sobrien { 222890075Sobrien /* Extracting a bit-field from a constant */ 222990075Sobrien HOST_WIDE_INT val = INTVAL (op0); 223090075Sobrien 223190075Sobrien if (BITS_BIG_ENDIAN) 223290075Sobrien val >>= (GET_MODE_BITSIZE (op0_mode) 223390075Sobrien - INTVAL (op2) - INTVAL (op1)); 223490075Sobrien else 223590075Sobrien val >>= INTVAL (op2); 223690075Sobrien 223790075Sobrien if (HOST_BITS_PER_WIDE_INT != INTVAL (op1)) 223890075Sobrien { 223990075Sobrien /* First zero-extend. */ 224090075Sobrien val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1; 224190075Sobrien /* If desired, propagate sign bit. */ 224290075Sobrien if (code == SIGN_EXTRACT 224390075Sobrien && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1)))) 224490075Sobrien val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1); 224590075Sobrien } 224690075Sobrien 224790075Sobrien /* Clear the bits that don't belong in our mode, 224890075Sobrien unless they and our sign bit are all one. 224990075Sobrien So we get either a reasonable negative value or a reasonable 225090075Sobrien unsigned value for this mode. */ 225190075Sobrien if (width < HOST_BITS_PER_WIDE_INT 225290075Sobrien && ((val & ((HOST_WIDE_INT) (-1) << (width - 1))) 225390075Sobrien != ((HOST_WIDE_INT) (-1) << (width - 1)))) 225490075Sobrien val &= ((HOST_WIDE_INT) 1 << width) - 1; 225590075Sobrien 225690075Sobrien return GEN_INT (val); 225790075Sobrien } 225890075Sobrien break; 225990075Sobrien 226090075Sobrien case IF_THEN_ELSE: 226190075Sobrien if (GET_CODE (op0) == CONST_INT) 226290075Sobrien return op0 != const0_rtx ? op1 : op2; 226390075Sobrien 226490075Sobrien /* Convert a == b ? b : a to "a". */ 226590075Sobrien if (GET_CODE (op0) == NE && ! side_effects_p (op0) 2266117395Skan && !HONOR_NANS (mode) 226790075Sobrien && rtx_equal_p (XEXP (op0, 0), op1) 226890075Sobrien && rtx_equal_p (XEXP (op0, 1), op2)) 226990075Sobrien return op1; 227090075Sobrien else if (GET_CODE (op0) == EQ && ! side_effects_p (op0) 2271117395Skan && !HONOR_NANS (mode) 227290075Sobrien && rtx_equal_p (XEXP (op0, 1), op1) 227390075Sobrien && rtx_equal_p (XEXP (op0, 0), op2)) 227490075Sobrien return op2; 227590075Sobrien else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0)) 227690075Sobrien { 227790075Sobrien enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode 227890075Sobrien ? GET_MODE (XEXP (op0, 1)) 227990075Sobrien : GET_MODE (XEXP (op0, 0))); 228090075Sobrien rtx temp; 228190075Sobrien if (cmp_mode == VOIDmode) 228290075Sobrien cmp_mode = op0_mode; 228390075Sobrien temp = simplify_relational_operation (GET_CODE (op0), cmp_mode, 228490075Sobrien XEXP (op0, 0), XEXP (op0, 1)); 228590075Sobrien 228690075Sobrien /* See if any simplifications were possible. */ 228790075Sobrien if (temp == const0_rtx) 228890075Sobrien return op2; 228990075Sobrien else if (temp == const1_rtx) 229090075Sobrien return op1; 229190075Sobrien else if (temp) 229290075Sobrien op0 = temp; 229390075Sobrien 229490075Sobrien /* Look for happy constants in op1 and op2. */ 229590075Sobrien if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT) 229690075Sobrien { 229790075Sobrien HOST_WIDE_INT t = INTVAL (op1); 229890075Sobrien HOST_WIDE_INT f = INTVAL (op2); 2299117395Skan 230090075Sobrien if (t == STORE_FLAG_VALUE && f == 0) 230190075Sobrien code = GET_CODE (op0); 230290075Sobrien else if (t == 0 && f == STORE_FLAG_VALUE) 230390075Sobrien { 230490075Sobrien enum rtx_code tmp; 230590075Sobrien tmp = reversed_comparison_code (op0, NULL_RTX); 230690075Sobrien if (tmp == UNKNOWN) 230790075Sobrien break; 230890075Sobrien code = tmp; 230990075Sobrien } 231090075Sobrien else 231190075Sobrien break; 231290075Sobrien 231390075Sobrien return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1)); 231490075Sobrien } 231590075Sobrien } 231690075Sobrien break; 2317117395Skan case VEC_MERGE: 2318117395Skan if (GET_MODE (op0) != mode 2319117395Skan || GET_MODE (op1) != mode 2320117395Skan || !VECTOR_MODE_P (mode)) 2321117395Skan abort (); 2322117395Skan op0 = avoid_constant_pool_reference (op0); 2323117395Skan op1 = avoid_constant_pool_reference (op1); 2324117395Skan op2 = avoid_constant_pool_reference (op2); 2325117395Skan if (GET_CODE (op0) == CONST_VECTOR 2326117395Skan && GET_CODE (op1) == CONST_VECTOR 2327117395Skan && GET_CODE (op2) == CONST_INT) 2328117395Skan { 2329117395Skan int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode)); 2330117395Skan unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size); 2331117395Skan rtvec v = rtvec_alloc (n_elts); 2332117395Skan unsigned int i; 233390075Sobrien 2334117395Skan for (i = 0; i < n_elts; i++) 2335117395Skan RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i) 2336117395Skan ? CONST_VECTOR_ELT (op0, i) 2337117395Skan : CONST_VECTOR_ELT (op1, i)); 2338117395Skan return gen_rtx_CONST_VECTOR (mode, v); 2339117395Skan } 2340117395Skan break; 2341117395Skan 234290075Sobrien default: 234390075Sobrien abort (); 234490075Sobrien } 234590075Sobrien 234690075Sobrien return 0; 234790075Sobrien} 234890075Sobrien 234990075Sobrien/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE) 235090075Sobrien Return 0 if no simplifications is possible. */ 235190075Sobrienrtx 235290075Sobriensimplify_subreg (outermode, op, innermode, byte) 235390075Sobrien rtx op; 235490075Sobrien unsigned int byte; 235590075Sobrien enum machine_mode outermode, innermode; 235690075Sobrien{ 235790075Sobrien /* Little bit of sanity checking. */ 235890075Sobrien if (innermode == VOIDmode || outermode == VOIDmode 235990075Sobrien || innermode == BLKmode || outermode == BLKmode) 236090075Sobrien abort (); 236190075Sobrien 236290075Sobrien if (GET_MODE (op) != innermode 236390075Sobrien && GET_MODE (op) != VOIDmode) 236490075Sobrien abort (); 236590075Sobrien 236690075Sobrien if (byte % GET_MODE_SIZE (outermode) 236790075Sobrien || byte >= GET_MODE_SIZE (innermode)) 236890075Sobrien abort (); 236990075Sobrien 237090075Sobrien if (outermode == innermode && !byte) 237190075Sobrien return op; 237290075Sobrien 2373117395Skan /* Simplify subregs of vector constants. */ 2374117395Skan if (GET_CODE (op) == CONST_VECTOR) 2375117395Skan { 2376117395Skan int elt_size = GET_MODE_SIZE (GET_MODE_INNER (innermode)); 2377117395Skan const unsigned int offset = byte / elt_size; 2378117395Skan rtx elt; 2379117395Skan 2380117395Skan if (GET_MODE_INNER (innermode) == outermode) 2381117395Skan { 2382117395Skan elt = CONST_VECTOR_ELT (op, offset); 2383117395Skan 2384117395Skan /* ?? We probably don't need this copy_rtx because constants 2385117395Skan can be shared. ?? */ 2386117395Skan 2387117395Skan return copy_rtx (elt); 2388117395Skan } 2389117395Skan else if (GET_MODE_INNER (innermode) == GET_MODE_INNER (outermode) 2390117395Skan && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (outermode)) 2391117395Skan { 2392117395Skan return (gen_rtx_CONST_VECTOR 2393117395Skan (outermode, 2394117395Skan gen_rtvec_v (GET_MODE_NUNITS (outermode), 2395117395Skan &CONST_VECTOR_ELT (op, offset)))); 2396117395Skan } 2397117395Skan else if (GET_MODE_CLASS (outermode) == MODE_INT 2398117395Skan && (GET_MODE_SIZE (outermode) % elt_size == 0)) 2399117395Skan { 2400117395Skan /* This happens when the target register size is smaller then 2401117395Skan the vector mode, and we synthesize operations with vectors 2402117395Skan of elements that are smaller than the register size. */ 2403117395Skan HOST_WIDE_INT sum = 0, high = 0; 2404117395Skan unsigned n_elts = (GET_MODE_SIZE (outermode) / elt_size); 2405117395Skan unsigned i = BYTES_BIG_ENDIAN ? offset : offset + n_elts - 1; 2406117395Skan unsigned step = BYTES_BIG_ENDIAN ? 1 : -1; 2407117395Skan int shift = BITS_PER_UNIT * elt_size; 2408117395Skan 2409117395Skan for (; n_elts--; i += step) 2410117395Skan { 2411117395Skan elt = CONST_VECTOR_ELT (op, i); 2412117395Skan if (GET_CODE (elt) == CONST_DOUBLE 2413117395Skan && GET_MODE_CLASS (GET_MODE (elt)) == MODE_FLOAT) 2414117395Skan { 2415117395Skan elt = gen_lowpart_common (int_mode_for_mode (GET_MODE (elt)), 2416117395Skan elt); 2417117395Skan if (! elt) 2418117395Skan return NULL_RTX; 2419117395Skan } 2420117395Skan if (GET_CODE (elt) != CONST_INT) 2421117395Skan return NULL_RTX; 2422117395Skan /* Avoid overflow. */ 2423117395Skan if (high >> (HOST_BITS_PER_WIDE_INT - shift)) 2424117395Skan return NULL_RTX; 2425117395Skan high = high << shift | sum >> (HOST_BITS_PER_WIDE_INT - shift); 2426117395Skan sum = (sum << shift) + INTVAL (elt); 2427117395Skan } 2428117395Skan if (GET_MODE_BITSIZE (outermode) <= HOST_BITS_PER_WIDE_INT) 2429117395Skan return GEN_INT (trunc_int_for_mode (sum, outermode)); 2430117395Skan else if (GET_MODE_BITSIZE (outermode) == 2* HOST_BITS_PER_WIDE_INT) 2431117395Skan return immed_double_const (sum, high, outermode); 2432117395Skan else 2433117395Skan return NULL_RTX; 2434117395Skan } 2435117395Skan else if (GET_MODE_CLASS (outermode) == MODE_INT 2436117395Skan && (elt_size % GET_MODE_SIZE (outermode) == 0)) 2437117395Skan { 2438117395Skan enum machine_mode new_mode 2439117395Skan = int_mode_for_mode (GET_MODE_INNER (innermode)); 2440117395Skan int subbyte = byte % elt_size; 2441117395Skan 2442117395Skan op = simplify_subreg (new_mode, op, innermode, byte - subbyte); 2443117395Skan if (! op) 2444117395Skan return NULL_RTX; 2445117395Skan return simplify_subreg (outermode, op, new_mode, subbyte); 2446117395Skan } 2447117395Skan else if (GET_MODE_CLASS (outermode) == MODE_INT) 2448117395Skan /* This shouldn't happen, but let's not do anything stupid. */ 2449117395Skan return NULL_RTX; 2450117395Skan } 2451117395Skan 245290075Sobrien /* Attempt to simplify constant to non-SUBREG expression. */ 245390075Sobrien if (CONSTANT_P (op)) 245490075Sobrien { 245590075Sobrien int offset, part; 245690075Sobrien unsigned HOST_WIDE_INT val = 0; 245790075Sobrien 2458117395Skan if (GET_MODE_CLASS (outermode) == MODE_VECTOR_INT 2459117395Skan || GET_MODE_CLASS (outermode) == MODE_VECTOR_FLOAT) 2460117395Skan { 2461117395Skan /* Construct a CONST_VECTOR from individual subregs. */ 2462117395Skan enum machine_mode submode = GET_MODE_INNER (outermode); 2463117395Skan int subsize = GET_MODE_UNIT_SIZE (outermode); 2464117395Skan int i, elts = GET_MODE_NUNITS (outermode); 2465117395Skan rtvec v = rtvec_alloc (elts); 2466117395Skan rtx elt; 2467117395Skan 2468117395Skan for (i = 0; i < elts; i++, byte += subsize) 2469117395Skan { 2470117395Skan /* This might fail, e.g. if taking a subreg from a SYMBOL_REF. */ 2471117395Skan /* ??? It would be nice if we could actually make such subregs 2472117395Skan on targets that allow such relocations. */ 2473117395Skan if (byte >= GET_MODE_UNIT_SIZE (innermode)) 2474117395Skan elt = CONST0_RTX (submode); 2475117395Skan else 2476117395Skan elt = simplify_subreg (submode, op, innermode, byte); 2477117395Skan if (! elt) 2478117395Skan return NULL_RTX; 2479117395Skan RTVEC_ELT (v, i) = elt; 2480117395Skan } 2481117395Skan return gen_rtx_CONST_VECTOR (outermode, v); 2482117395Skan } 2483117395Skan 248490075Sobrien /* ??? This code is partly redundant with code below, but can handle 248590075Sobrien the subregs of floats and similar corner cases. 248690075Sobrien Later it we should move all simplification code here and rewrite 248790075Sobrien GEN_LOWPART_IF_POSSIBLE, GEN_HIGHPART, OPERAND_SUBWORD and friends 248890075Sobrien using SIMPLIFY_SUBREG. */ 2489117395Skan if (subreg_lowpart_offset (outermode, innermode) == byte 2490117395Skan && GET_CODE (op) != CONST_VECTOR) 249190075Sobrien { 249290075Sobrien rtx new = gen_lowpart_if_possible (outermode, op); 249390075Sobrien if (new) 249490075Sobrien return new; 249590075Sobrien } 249690075Sobrien 249790075Sobrien /* Similar comment as above apply here. */ 249890075Sobrien if (GET_MODE_SIZE (outermode) == UNITS_PER_WORD 249990075Sobrien && GET_MODE_SIZE (innermode) > UNITS_PER_WORD 250090075Sobrien && GET_MODE_CLASS (outermode) == MODE_INT) 250190075Sobrien { 250290075Sobrien rtx new = constant_subword (op, 250390075Sobrien (byte / UNITS_PER_WORD), 250490075Sobrien innermode); 250590075Sobrien if (new) 250690075Sobrien return new; 250790075Sobrien } 250890075Sobrien 2509117395Skan if (GET_MODE_CLASS (outermode) != MODE_INT 2510117395Skan && GET_MODE_CLASS (outermode) != MODE_CC) 2511117395Skan { 2512117395Skan enum machine_mode new_mode = int_mode_for_mode (outermode); 2513117395Skan 2514117395Skan if (new_mode != innermode || byte != 0) 2515117395Skan { 2516117395Skan op = simplify_subreg (new_mode, op, innermode, byte); 2517117395Skan if (! op) 2518117395Skan return NULL_RTX; 2519117395Skan return simplify_subreg (outermode, op, new_mode, 0); 2520117395Skan } 2521117395Skan } 2522117395Skan 252390075Sobrien offset = byte * BITS_PER_UNIT; 252490075Sobrien switch (GET_CODE (op)) 252590075Sobrien { 252690075Sobrien case CONST_DOUBLE: 252790075Sobrien if (GET_MODE (op) != VOIDmode) 252890075Sobrien break; 252990075Sobrien 253090075Sobrien /* We can't handle this case yet. */ 253190075Sobrien if (GET_MODE_BITSIZE (outermode) >= HOST_BITS_PER_WIDE_INT) 253290075Sobrien return NULL_RTX; 253390075Sobrien 253490075Sobrien part = offset >= HOST_BITS_PER_WIDE_INT; 253590075Sobrien if ((BITS_PER_WORD > HOST_BITS_PER_WIDE_INT 253690075Sobrien && BYTES_BIG_ENDIAN) 253790075Sobrien || (BITS_PER_WORD <= HOST_BITS_PER_WIDE_INT 253890075Sobrien && WORDS_BIG_ENDIAN)) 253990075Sobrien part = !part; 254090075Sobrien val = part ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op); 254190075Sobrien offset %= HOST_BITS_PER_WIDE_INT; 254290075Sobrien 2543117395Skan /* We've already picked the word we want from a double, so 254490075Sobrien pretend this is actually an integer. */ 254590075Sobrien innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); 254690075Sobrien 254790075Sobrien /* FALLTHROUGH */ 254890075Sobrien case CONST_INT: 254990075Sobrien if (GET_CODE (op) == CONST_INT) 255090075Sobrien val = INTVAL (op); 255190075Sobrien 255290075Sobrien /* We don't handle synthetizing of non-integral constants yet. */ 255390075Sobrien if (GET_MODE_CLASS (outermode) != MODE_INT) 255490075Sobrien return NULL_RTX; 255590075Sobrien 255690075Sobrien if (BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) 255790075Sobrien { 255890075Sobrien if (WORDS_BIG_ENDIAN) 255990075Sobrien offset = (GET_MODE_BITSIZE (innermode) 256090075Sobrien - GET_MODE_BITSIZE (outermode) - offset); 256190075Sobrien if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN 256290075Sobrien && GET_MODE_SIZE (outermode) < UNITS_PER_WORD) 256390075Sobrien offset = (offset + BITS_PER_WORD - GET_MODE_BITSIZE (outermode) 256490075Sobrien - 2 * (offset % BITS_PER_WORD)); 256590075Sobrien } 256690075Sobrien 256790075Sobrien if (offset >= HOST_BITS_PER_WIDE_INT) 256890075Sobrien return ((HOST_WIDE_INT) val < 0) ? constm1_rtx : const0_rtx; 256990075Sobrien else 257090075Sobrien { 257190075Sobrien val >>= offset; 257290075Sobrien if (GET_MODE_BITSIZE (outermode) < HOST_BITS_PER_WIDE_INT) 257390075Sobrien val = trunc_int_for_mode (val, outermode); 257490075Sobrien return GEN_INT (val); 257590075Sobrien } 257690075Sobrien default: 257790075Sobrien break; 257890075Sobrien } 257990075Sobrien } 258090075Sobrien 258190075Sobrien /* Changing mode twice with SUBREG => just change it once, 258290075Sobrien or not at all if changing back op starting mode. */ 258390075Sobrien if (GET_CODE (op) == SUBREG) 258490075Sobrien { 258590075Sobrien enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op)); 258690075Sobrien int final_offset = byte + SUBREG_BYTE (op); 258790075Sobrien rtx new; 258890075Sobrien 258990075Sobrien if (outermode == innermostmode 259090075Sobrien && byte == 0 && SUBREG_BYTE (op) == 0) 259190075Sobrien return SUBREG_REG (op); 259290075Sobrien 259390075Sobrien /* The SUBREG_BYTE represents offset, as if the value were stored 259490075Sobrien in memory. Irritating exception is paradoxical subreg, where 259590075Sobrien we define SUBREG_BYTE to be 0. On big endian machines, this 259690075Sobrien value should be negative. For a moment, undo this exception. */ 259790075Sobrien if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) 259890075Sobrien { 259990075Sobrien int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)); 260090075Sobrien if (WORDS_BIG_ENDIAN) 260190075Sobrien final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; 260290075Sobrien if (BYTES_BIG_ENDIAN) 260390075Sobrien final_offset += difference % UNITS_PER_WORD; 260490075Sobrien } 260590075Sobrien if (SUBREG_BYTE (op) == 0 260690075Sobrien && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode)) 260790075Sobrien { 260890075Sobrien int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode)); 260990075Sobrien if (WORDS_BIG_ENDIAN) 261090075Sobrien final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; 261190075Sobrien if (BYTES_BIG_ENDIAN) 261290075Sobrien final_offset += difference % UNITS_PER_WORD; 261390075Sobrien } 261490075Sobrien 261590075Sobrien /* See whether resulting subreg will be paradoxical. */ 261690075Sobrien if (GET_MODE_SIZE (innermostmode) > GET_MODE_SIZE (outermode)) 261790075Sobrien { 261890075Sobrien /* In nonparadoxical subregs we can't handle negative offsets. */ 261990075Sobrien if (final_offset < 0) 262090075Sobrien return NULL_RTX; 262190075Sobrien /* Bail out in case resulting subreg would be incorrect. */ 262290075Sobrien if (final_offset % GET_MODE_SIZE (outermode) 262390075Sobrien || (unsigned) final_offset >= GET_MODE_SIZE (innermostmode)) 262490075Sobrien return NULL_RTX; 262590075Sobrien } 262690075Sobrien else 262790075Sobrien { 262890075Sobrien int offset = 0; 262990075Sobrien int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode)); 263090075Sobrien 263190075Sobrien /* In paradoxical subreg, see if we are still looking on lower part. 263290075Sobrien If so, our SUBREG_BYTE will be 0. */ 263390075Sobrien if (WORDS_BIG_ENDIAN) 263490075Sobrien offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; 263590075Sobrien if (BYTES_BIG_ENDIAN) 263690075Sobrien offset += difference % UNITS_PER_WORD; 263790075Sobrien if (offset == final_offset) 263890075Sobrien final_offset = 0; 263990075Sobrien else 264090075Sobrien return NULL_RTX; 264190075Sobrien } 264290075Sobrien 264390075Sobrien /* Recurse for futher possible simplifications. */ 264490075Sobrien new = simplify_subreg (outermode, SUBREG_REG (op), 264590075Sobrien GET_MODE (SUBREG_REG (op)), 264690075Sobrien final_offset); 264790075Sobrien if (new) 264890075Sobrien return new; 264990075Sobrien return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset); 265090075Sobrien } 265190075Sobrien 265290075Sobrien /* SUBREG of a hard register => just change the register number 265390075Sobrien and/or mode. If the hard register is not valid in that mode, 265490075Sobrien suppress this simplification. If the hard register is the stack, 265590075Sobrien frame, or argument pointer, leave this as a SUBREG. */ 265690075Sobrien 265790075Sobrien if (REG_P (op) 265890075Sobrien && (! REG_FUNCTION_VALUE_P (op) 265990075Sobrien || ! rtx_equal_function_value_matters) 2660117395Skan && REGNO (op) < FIRST_PSEUDO_REGISTER 2661117395Skan#ifdef CANNOT_CHANGE_MODE_CLASS 2662117395Skan && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), innermode, outermode) 266390075Sobrien && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT 2664117395Skan && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT) 266590075Sobrien#endif 266690075Sobrien && ((reload_completed && !frame_pointer_needed) 266790075Sobrien || (REGNO (op) != FRAME_POINTER_REGNUM 266890075Sobrien#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM 266990075Sobrien && REGNO (op) != HARD_FRAME_POINTER_REGNUM 267090075Sobrien#endif 267190075Sobrien )) 267290075Sobrien#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM 267390075Sobrien && REGNO (op) != ARG_POINTER_REGNUM 267490075Sobrien#endif 267590075Sobrien && REGNO (op) != STACK_POINTER_REGNUM) 267690075Sobrien { 267790075Sobrien int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte), 267890075Sobrien 0); 267990075Sobrien 268090075Sobrien /* ??? We do allow it if the current REG is not valid for 268190075Sobrien its mode. This is a kludge to work around how float/complex 2682117395Skan arguments are passed on 32-bit SPARC and should be fixed. */ 268390075Sobrien if (HARD_REGNO_MODE_OK (final_regno, outermode) 268490075Sobrien || ! HARD_REGNO_MODE_OK (REGNO (op), innermode)) 268590075Sobrien { 268690075Sobrien rtx x = gen_rtx_REG (outermode, final_regno); 268790075Sobrien 268890075Sobrien /* Propagate original regno. We don't have any way to specify 268990075Sobrien the offset inside orignal regno, so do so only for lowpart. 269090075Sobrien The information is used only by alias analysis that can not 269190075Sobrien grog partial register anyway. */ 269290075Sobrien 269390075Sobrien if (subreg_lowpart_offset (outermode, innermode) == byte) 269490075Sobrien ORIGINAL_REGNO (x) = ORIGINAL_REGNO (op); 269590075Sobrien return x; 269690075Sobrien } 269790075Sobrien } 269890075Sobrien 269990075Sobrien /* If we have a SUBREG of a register that we are replacing and we are 270090075Sobrien replacing it with a MEM, make a new MEM and try replacing the 270190075Sobrien SUBREG with it. Don't do this if the MEM has a mode-dependent address 270290075Sobrien or if we would be widening it. */ 270390075Sobrien 270490075Sobrien if (GET_CODE (op) == MEM 270590075Sobrien && ! mode_dependent_address_p (XEXP (op, 0)) 270690075Sobrien /* Allow splitting of volatile memory references in case we don't 270790075Sobrien have instruction to move the whole thing. */ 270890075Sobrien && (! MEM_VOLATILE_P (op) 270990075Sobrien || ! have_insn_for (SET, innermode)) 271090075Sobrien && GET_MODE_SIZE (outermode) <= GET_MODE_SIZE (GET_MODE (op))) 271190075Sobrien return adjust_address_nv (op, outermode, byte); 271290075Sobrien 271390075Sobrien /* Handle complex values represented as CONCAT 271490075Sobrien of real and imaginary part. */ 271590075Sobrien if (GET_CODE (op) == CONCAT) 271690075Sobrien { 271790075Sobrien int is_realpart = byte < GET_MODE_UNIT_SIZE (innermode); 271890075Sobrien rtx part = is_realpart ? XEXP (op, 0) : XEXP (op, 1); 271990075Sobrien unsigned int final_offset; 272090075Sobrien rtx res; 272190075Sobrien 272290075Sobrien final_offset = byte % (GET_MODE_UNIT_SIZE (innermode)); 272390075Sobrien res = simplify_subreg (outermode, part, GET_MODE (part), final_offset); 272490075Sobrien if (res) 272590075Sobrien return res; 272690075Sobrien /* We can at least simplify it by referring directly to the relevant part. */ 272790075Sobrien return gen_rtx_SUBREG (outermode, part, final_offset); 272890075Sobrien } 272990075Sobrien 273090075Sobrien return NULL_RTX; 273190075Sobrien} 273290075Sobrien/* Make a SUBREG operation or equivalent if it folds. */ 273390075Sobrien 273490075Sobrienrtx 273590075Sobriensimplify_gen_subreg (outermode, op, innermode, byte) 273690075Sobrien rtx op; 273790075Sobrien unsigned int byte; 273890075Sobrien enum machine_mode outermode, innermode; 273990075Sobrien{ 274090075Sobrien rtx new; 274190075Sobrien /* Little bit of sanity checking. */ 274290075Sobrien if (innermode == VOIDmode || outermode == VOIDmode 274390075Sobrien || innermode == BLKmode || outermode == BLKmode) 274490075Sobrien abort (); 274590075Sobrien 274690075Sobrien if (GET_MODE (op) != innermode 274790075Sobrien && GET_MODE (op) != VOIDmode) 274890075Sobrien abort (); 274990075Sobrien 275090075Sobrien if (byte % GET_MODE_SIZE (outermode) 275190075Sobrien || byte >= GET_MODE_SIZE (innermode)) 275290075Sobrien abort (); 275390075Sobrien 275490075Sobrien if (GET_CODE (op) == QUEUED) 275590075Sobrien return NULL_RTX; 275690075Sobrien 275790075Sobrien new = simplify_subreg (outermode, op, innermode, byte); 275890075Sobrien if (new) 275990075Sobrien return new; 276090075Sobrien 276190075Sobrien if (GET_CODE (op) == SUBREG || GET_MODE (op) == VOIDmode) 276290075Sobrien return NULL_RTX; 276390075Sobrien 276490075Sobrien return gen_rtx_SUBREG (outermode, op, byte); 276590075Sobrien} 276690075Sobrien/* Simplify X, an rtx expression. 276790075Sobrien 276890075Sobrien Return the simplified expression or NULL if no simplifications 276990075Sobrien were possible. 277090075Sobrien 277190075Sobrien This is the preferred entry point into the simplification routines; 277290075Sobrien however, we still allow passes to call the more specific routines. 277390075Sobrien 277490075Sobrien Right now GCC has three (yes, three) major bodies of RTL simplficiation 277590075Sobrien code that need to be unified. 277690075Sobrien 277790075Sobrien 1. fold_rtx in cse.c. This code uses various CSE specific 277890075Sobrien information to aid in RTL simplification. 277990075Sobrien 278090075Sobrien 2. simplify_rtx in combine.c. Similar to fold_rtx, except that 278190075Sobrien it uses combine specific information to aid in RTL 278290075Sobrien simplification. 278390075Sobrien 278490075Sobrien 3. The routines in this file. 278590075Sobrien 278690075Sobrien 278790075Sobrien Long term we want to only have one body of simplification code; to 278890075Sobrien get to that state I recommend the following steps: 278990075Sobrien 279090075Sobrien 1. Pour over fold_rtx & simplify_rtx and move any simplifications 279190075Sobrien which are not pass dependent state into these routines. 279290075Sobrien 279390075Sobrien 2. As code is moved by #1, change fold_rtx & simplify_rtx to 279490075Sobrien use this routine whenever possible. 279590075Sobrien 279690075Sobrien 3. Allow for pass dependent state to be provided to these 279790075Sobrien routines and add simplifications based on the pass dependent 279890075Sobrien state. Remove code from cse.c & combine.c that becomes 279990075Sobrien redundant/dead. 280090075Sobrien 280190075Sobrien It will take time, but ultimately the compiler will be easier to 280290075Sobrien maintain and improve. It's totally silly that when we add a 280390075Sobrien simplification that it needs to be added to 4 places (3 for RTL 280490075Sobrien simplification and 1 for tree simplification. */ 2805117395Skan 280690075Sobrienrtx 280790075Sobriensimplify_rtx (x) 280890075Sobrien rtx x; 280990075Sobrien{ 281090075Sobrien enum rtx_code code = GET_CODE (x); 281190075Sobrien enum machine_mode mode = GET_MODE (x); 281290075Sobrien 281390075Sobrien switch (GET_RTX_CLASS (code)) 281490075Sobrien { 281590075Sobrien case '1': 281690075Sobrien return simplify_unary_operation (code, mode, 281790075Sobrien XEXP (x, 0), GET_MODE (XEXP (x, 0))); 281890075Sobrien case 'c': 281990075Sobrien if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))) 282090075Sobrien { 282190075Sobrien rtx tem; 282290075Sobrien 282390075Sobrien tem = XEXP (x, 0); 282490075Sobrien XEXP (x, 0) = XEXP (x, 1); 282590075Sobrien XEXP (x, 1) = tem; 282690075Sobrien return simplify_binary_operation (code, mode, 282790075Sobrien XEXP (x, 0), XEXP (x, 1)); 282890075Sobrien } 282990075Sobrien 283090075Sobrien case '2': 283190075Sobrien return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1)); 283290075Sobrien 283390075Sobrien case '3': 283490075Sobrien case 'b': 283590075Sobrien return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)), 283690075Sobrien XEXP (x, 0), XEXP (x, 1), 283790075Sobrien XEXP (x, 2)); 283890075Sobrien 283990075Sobrien case '<': 284090075Sobrien return simplify_relational_operation (code, 284190075Sobrien ((GET_MODE (XEXP (x, 0)) 284290075Sobrien != VOIDmode) 284390075Sobrien ? GET_MODE (XEXP (x, 0)) 284490075Sobrien : GET_MODE (XEXP (x, 1))), 284590075Sobrien XEXP (x, 0), XEXP (x, 1)); 284690075Sobrien case 'x': 284790075Sobrien /* The only case we try to handle is a SUBREG. */ 284890075Sobrien if (code == SUBREG) 2849117395Skan return simplify_gen_subreg (mode, SUBREG_REG (x), 285090075Sobrien GET_MODE (SUBREG_REG (x)), 285190075Sobrien SUBREG_BYTE (x)); 285290075Sobrien return NULL; 285390075Sobrien default: 285490075Sobrien return NULL; 285590075Sobrien } 285690075Sobrien} 2857