118334Speter/* Expand the basic unary and binary arithmetic operations, for GNU compiler. 290075Sobrien Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3169689Skan 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 4169689Skan Free Software Foundation, Inc. 518334Speter 690075SobrienThis file is part of GCC. 718334Speter 890075SobrienGCC is free software; you can redistribute it and/or modify it under 990075Sobrienthe terms of the GNU General Public License as published by the Free 1090075SobrienSoftware Foundation; either version 2, or (at your option) any later 1190075Sobrienversion. 1218334Speter 1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1590075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1690075Sobrienfor more details. 1718334Speter 1818334SpeterYou should have received a copy of the GNU General Public License 1990075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 21169689Skan02110-1301, USA. */ 2218334Speter 2318334Speter 2418334Speter#include "config.h" 2550397Sobrien#include "system.h" 26132718Skan#include "coretypes.h" 27132718Skan#include "tm.h" 2852284Sobrien#include "toplev.h" 2952284Sobrien 3052284Sobrien/* Include insn-config.h before expr.h so that HAVE_conditional_move 3190075Sobrien is properly defined. */ 3252284Sobrien#include "insn-config.h" 3318334Speter#include "rtl.h" 3418334Speter#include "tree.h" 3590075Sobrien#include "tm_p.h" 3618334Speter#include "flags.h" 3790075Sobrien#include "function.h" 3890075Sobrien#include "except.h" 3918334Speter#include "expr.h" 4090075Sobrien#include "optabs.h" 4190075Sobrien#include "libfuncs.h" 4218334Speter#include "recog.h" 4318334Speter#include "reload.h" 4490075Sobrien#include "ggc.h" 4590075Sobrien#include "real.h" 46110611Skan#include "basic-block.h" 47132718Skan#include "target.h" 4818334Speter 4918334Speter/* Each optab contains info on how this target machine 5018334Speter can perform a particular operation 5118334Speter for all sizes and kinds of operands. 5218334Speter 5318334Speter The operation to be performed is often specified 5418334Speter by passing one of these optabs as an argument. 5518334Speter 5618334Speter See expr.h for documentation of these optabs. */ 5718334Speter 5890075Sobrienoptab optab_table[OTI_MAX]; 5918334Speter 6090075Sobrienrtx libfunc_table[LTI_MAX]; 6118334Speter 62132718Skan/* Tables of patterns for converting one mode to another. */ 63169689Skanconvert_optab convert_optab_table[COI_MAX]; 6418334Speter 6518334Speter/* Contains the optab used for each rtx code. */ 6618334Speteroptab code_to_optab[NUM_RTX_CODE + 1]; 6718334Speter 6818334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) 6918334Speter gives the gen_function to make a branch to test that condition. */ 7018334Speter 7118334Speterrtxfun bcc_gen_fctn[NUM_RTX_CODE]; 7218334Speter 7318334Speter/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) 7418334Speter gives the insn code to make a store-condition insn 7518334Speter to test that condition. */ 7618334Speter 7718334Speterenum insn_code setcc_gen_code[NUM_RTX_CODE]; 7818334Speter 7918334Speter#ifdef HAVE_conditional_move 8018334Speter/* Indexed by the machine mode, gives the insn code to make a conditional 8118334Speter move insn. This is not indexed by the rtx-code like bcc_gen_fctn and 8218334Speter setcc_gen_code to cut down on the number of named patterns. Consider a day 8318334Speter when a lot more rtx codes are conditional (eg: for the ARM). */ 8418334Speter 8518334Speterenum insn_code movcc_gen_code[NUM_MACHINE_MODES]; 8618334Speter#endif 8718334Speter 88169689Skan/* Indexed by the machine mode, gives the insn code for vector conditional 89169689Skan operation. */ 90169689Skan 91169689Skanenum insn_code vcond_gen_code[NUM_MACHINE_MODES]; 92169689Skanenum insn_code vcondu_gen_code[NUM_MACHINE_MODES]; 93169689Skan 94117395Skan/* The insn generating function can not take an rtx_code argument. 95117395Skan TRAP_RTX is used as an rtx argument. Its code is replaced with 96117395Skan the code to be used in the trap insn and all other fields are ignored. */ 97117395Skanstatic GTY(()) rtx trap_rtx; 98117395Skan 99132718Skanstatic int add_equal_note (rtx, rtx, enum rtx_code, rtx, rtx); 100132718Skanstatic rtx widen_operand (rtx, enum machine_mode, enum machine_mode, int, 101132718Skan int); 102132718Skanstatic void prepare_cmp_insn (rtx *, rtx *, enum rtx_code *, rtx, 103132718Skan enum machine_mode *, int *, 104132718Skan enum can_compare_purpose); 105132718Skanstatic enum insn_code can_fix_p (enum machine_mode, enum machine_mode, int, 106132718Skan int *); 107132718Skanstatic enum insn_code can_float_p (enum machine_mode, enum machine_mode, int); 108132718Skanstatic optab new_optab (void); 109132718Skanstatic convert_optab new_convert_optab (void); 110132718Skanstatic inline optab init_optab (enum rtx_code); 111132718Skanstatic inline optab init_optabv (enum rtx_code); 112132718Skanstatic inline convert_optab init_convert_optab (enum rtx_code); 113132718Skanstatic void init_libfuncs (optab, int, int, const char *, int); 114132718Skanstatic void init_integral_libfuncs (optab, const char *, int); 115132718Skanstatic void init_floating_libfuncs (optab, const char *, int); 116132718Skanstatic void init_interclass_conv_libfuncs (convert_optab, const char *, 117132718Skan enum mode_class, enum mode_class); 118132718Skanstatic void init_intraclass_conv_libfuncs (convert_optab, const char *, 119132718Skan enum mode_class, bool); 120132718Skanstatic void emit_cmp_and_jump_insn_1 (rtx, rtx, enum machine_mode, 121132718Skan enum rtx_code, int, rtx); 122132718Skanstatic void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *, 123132718Skan enum machine_mode *, int *); 124132718Skanstatic rtx widen_clz (enum machine_mode, rtx, rtx); 125132718Skanstatic rtx expand_parity (enum machine_mode, rtx, rtx); 126169689Skanstatic enum rtx_code get_rtx_code (enum tree_code, bool); 127169689Skanstatic rtx vector_compare_rtx (tree, bool, enum insn_code); 128117395Skan 129117395Skan#ifndef HAVE_conditional_trap 130117395Skan#define HAVE_conditional_trap 0 131169689Skan#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX) 132117395Skan#endif 13318334Speter 134117395Skan/* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to 13518334Speter the result of operation CODE applied to OP0 (and OP1 if it is a binary 13618334Speter operation). 13718334Speter 13818334Speter If the last insn does not set TARGET, don't do anything, but return 1. 13918334Speter 14018334Speter If a previous insn sets TARGET and TARGET is one of OP0 or OP1, 14118334Speter don't add the REG_EQUAL note but return 0. Our caller can then try 14218334Speter again, ensuring that TARGET is not one of the operands. */ 14318334Speter 14418334Speterstatic int 145132718Skanadd_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1) 14618334Speter{ 147117395Skan rtx last_insn, insn, set; 14818334Speter rtx note; 14918334Speter 150169689Skan gcc_assert (insns && INSN_P (insns) && NEXT_INSN (insns)); 151117395Skan 152169689Skan if (GET_RTX_CLASS (code) != RTX_COMM_ARITH 153169689Skan && GET_RTX_CLASS (code) != RTX_BIN_ARITH 154169689Skan && GET_RTX_CLASS (code) != RTX_COMM_COMPARE 155169689Skan && GET_RTX_CLASS (code) != RTX_COMPARE 156169689Skan && GET_RTX_CLASS (code) != RTX_UNARY) 15718334Speter return 1; 15818334Speter 159117395Skan if (GET_CODE (target) == ZERO_EXTRACT) 160117395Skan return 1; 161117395Skan 162117395Skan for (last_insn = insns; 163117395Skan NEXT_INSN (last_insn) != NULL_RTX; 164117395Skan last_insn = NEXT_INSN (last_insn)) 165117395Skan ; 166117395Skan 167117395Skan set = single_set (last_insn); 168117395Skan if (set == NULL_RTX) 169117395Skan return 1; 170117395Skan 171117395Skan if (! rtx_equal_p (SET_DEST (set), target) 172132718Skan /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside it. */ 173117395Skan && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART 174132718Skan || ! rtx_equal_p (XEXP (SET_DEST (set), 0), target))) 175117395Skan return 1; 176117395Skan 17718334Speter /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET 17818334Speter besides the last insn. */ 17918334Speter if (reg_overlap_mentioned_p (target, op0) 18018334Speter || (op1 && reg_overlap_mentioned_p (target, op1))) 181117395Skan { 182117395Skan insn = PREV_INSN (last_insn); 183117395Skan while (insn != NULL_RTX) 184117395Skan { 185117395Skan if (reg_set_p (target, insn)) 186117395Skan return 0; 18718334Speter 188117395Skan insn = PREV_INSN (insn); 189117395Skan } 190117395Skan } 191117395Skan 192169689Skan if (GET_RTX_CLASS (code) == RTX_UNARY) 19350397Sobrien note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0)); 19418334Speter else 19550397Sobrien note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1)); 19618334Speter 197117395Skan set_unique_reg_note (last_insn, REG_EQUAL, note); 19818334Speter 19918334Speter return 1; 20018334Speter} 20118334Speter 20218334Speter/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP 20318334Speter says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need 204132718Skan not actually do a sign-extend or zero-extend, but can leave the 20518334Speter higher-order bits of the result rtx undefined, for example, in the case 20618334Speter of logical operations, but not right shifts. */ 20718334Speter 20818334Speterstatic rtx 209132718Skanwiden_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode, 210132718Skan int unsignedp, int no_extend) 21118334Speter{ 21218334Speter rtx result; 21318334Speter 21496263Sobrien /* If we don't have to extend and this is a constant, return it. */ 21596263Sobrien if (no_extend && GET_MODE (op) == VOIDmode) 21696263Sobrien return op; 21796263Sobrien 21896263Sobrien /* If we must extend do so. If OP is a SUBREG for a promoted object, also 21996263Sobrien extend since it will be more efficient to do so unless the signedness of 22096263Sobrien a promoted object differs from our extension. */ 22118334Speter if (! no_extend 22296263Sobrien || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op) 22396263Sobrien && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp)) 22418334Speter return convert_modes (mode, oldmode, op, unsignedp); 22518334Speter 22618334Speter /* If MODE is no wider than a single word, we return a paradoxical 22718334Speter SUBREG. */ 22818334Speter if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 22950397Sobrien return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0); 23018334Speter 23118334Speter /* Otherwise, get an object of MODE, clobber it, and set the low-order 23218334Speter part to OP. */ 23318334Speter 23418334Speter result = gen_reg_rtx (mode); 23550397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, result)); 23618334Speter emit_move_insn (gen_lowpart (GET_MODE (op), result), op); 23718334Speter return result; 23818334Speter} 23918334Speter 240169689Skan/* Return the optab used for computing the operation given by 241169689Skan the tree code, CODE. This function is not always usable (for 242169689Skan example, it cannot give complete results for multiplication 243169689Skan or division) but probably ought to be relied on more widely 244169689Skan throughout the expander. */ 245169689Skanoptab 246169689Skanoptab_for_tree_code (enum tree_code code, tree type) 24752284Sobrien{ 248169689Skan bool trapv; 249169689Skan switch (code) 25090075Sobrien { 251169689Skan case BIT_AND_EXPR: 252169689Skan return and_optab; 25390075Sobrien 254169689Skan case BIT_IOR_EXPR: 255169689Skan return ior_optab; 25652284Sobrien 257169689Skan case BIT_NOT_EXPR: 258169689Skan return one_cmpl_optab; 25952284Sobrien 260169689Skan case BIT_XOR_EXPR: 261169689Skan return xor_optab; 26252284Sobrien 263169689Skan case TRUNC_MOD_EXPR: 264169689Skan case CEIL_MOD_EXPR: 265169689Skan case FLOOR_MOD_EXPR: 266169689Skan case ROUND_MOD_EXPR: 267169689Skan return TYPE_UNSIGNED (type) ? umod_optab : smod_optab; 26852284Sobrien 269169689Skan case RDIV_EXPR: 270169689Skan case TRUNC_DIV_EXPR: 271169689Skan case CEIL_DIV_EXPR: 272169689Skan case FLOOR_DIV_EXPR: 273169689Skan case ROUND_DIV_EXPR: 274169689Skan case EXACT_DIV_EXPR: 275169689Skan return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab; 27652284Sobrien 277169689Skan case LSHIFT_EXPR: 278169689Skan return ashl_optab; 27952284Sobrien 280169689Skan case RSHIFT_EXPR: 281169689Skan return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab; 28252284Sobrien 283169689Skan case LROTATE_EXPR: 284169689Skan return rotl_optab; 28552284Sobrien 286169689Skan case RROTATE_EXPR: 287169689Skan return rotr_optab; 288132718Skan 289169689Skan case MAX_EXPR: 290169689Skan return TYPE_UNSIGNED (type) ? umax_optab : smax_optab; 29152284Sobrien 292169689Skan case MIN_EXPR: 293169689Skan return TYPE_UNSIGNED (type) ? umin_optab : smin_optab; 29452284Sobrien 295169689Skan case REALIGN_LOAD_EXPR: 296169689Skan return vec_realign_load_optab; 29752284Sobrien 298169689Skan case WIDEN_SUM_EXPR: 299169689Skan return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab; 30052284Sobrien 301169689Skan case DOT_PROD_EXPR: 302169689Skan return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab; 30352284Sobrien 304169689Skan case REDUC_MAX_EXPR: 305169689Skan return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab; 306132718Skan 307169689Skan case REDUC_MIN_EXPR: 308169689Skan return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab; 30952284Sobrien 310169689Skan case REDUC_PLUS_EXPR: 311169689Skan return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab; 31252284Sobrien 313169689Skan case VEC_LSHIFT_EXPR: 314169689Skan return vec_shl_optab; 31552284Sobrien 316169689Skan case VEC_RSHIFT_EXPR: 317169689Skan return vec_shr_optab; 31852284Sobrien 319169689Skan default: 320169689Skan break; 32152284Sobrien } 32252284Sobrien 323169689Skan trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type); 324169689Skan switch (code) 325169689Skan { 326169689Skan case PLUS_EXPR: 327169689Skan return trapv ? addv_optab : add_optab; 32852284Sobrien 329169689Skan case MINUS_EXPR: 330169689Skan return trapv ? subv_optab : sub_optab; 33152284Sobrien 332169689Skan case MULT_EXPR: 333169689Skan return trapv ? smulv_optab : smul_optab; 33452284Sobrien 335169689Skan case NEGATE_EXPR: 336169689Skan return trapv ? negv_optab : neg_optab; 33752284Sobrien 338169689Skan case ABS_EXPR: 339169689Skan return trapv ? absv_optab : abs_optab; 34052284Sobrien 341169689Skan default: 342169689Skan return NULL; 343169689Skan } 34452284Sobrien} 34552284Sobrien 34652284Sobrien 347169689Skan/* Expand vector widening operations. 34890075Sobrien 349169689Skan There are two different classes of operations handled here: 350169689Skan 1) Operations whose result is wider than all the arguments to the operation. 351169689Skan Examples: VEC_UNPACK_HI/LO_EXPR, VEC_WIDEN_MULT_HI/LO_EXPR 352169689Skan In this case OP0 and optionally OP1 would be initialized, 353169689Skan but WIDE_OP wouldn't (not relevant for this case). 354169689Skan 2) Operations whose result is of the same size as the last argument to the 355169689Skan operation, but wider than all the other arguments to the operation. 356169689Skan Examples: WIDEN_SUM_EXPR, VEC_DOT_PROD_EXPR. 357169689Skan In the case WIDE_OP, OP0 and optionally OP1 would be initialized. 358169689Skan 359169689Skan E.g, when called to expand the following operations, this is how 360169689Skan the arguments will be initialized: 361169689Skan nops OP0 OP1 WIDE_OP 362169689Skan widening-sum 2 oprnd0 - oprnd1 363169689Skan widening-dot-product 3 oprnd0 oprnd1 oprnd2 364169689Skan widening-mult 2 oprnd0 oprnd1 - 365169689Skan type-promotion (vec-unpack) 1 oprnd0 - - */ 366169689Skan 367169689Skanrtx 368169689Skanexpand_widen_pattern_expr (tree exp, rtx op0, rtx op1, rtx wide_op, rtx target, 369169689Skan int unsignedp) 370169689Skan{ 371169689Skan tree oprnd0, oprnd1, oprnd2; 372169689Skan enum machine_mode wmode = 0, tmode0, tmode1 = 0; 373169689Skan optab widen_pattern_optab; 374169689Skan int icode; 375169689Skan enum machine_mode xmode0, xmode1 = 0, wxmode = 0; 376169689Skan rtx temp; 377169689Skan rtx pat; 378169689Skan rtx xop0, xop1, wxop; 379169689Skan int nops = TREE_CODE_LENGTH (TREE_CODE (exp)); 380169689Skan 381169689Skan oprnd0 = TREE_OPERAND (exp, 0); 382169689Skan tmode0 = TYPE_MODE (TREE_TYPE (oprnd0)); 383169689Skan widen_pattern_optab = 384169689Skan optab_for_tree_code (TREE_CODE (exp), TREE_TYPE (oprnd0)); 385169689Skan icode = (int) widen_pattern_optab->handlers[(int) tmode0].insn_code; 386169689Skan gcc_assert (icode != CODE_FOR_nothing); 387169689Skan xmode0 = insn_data[icode].operand[1].mode; 388169689Skan 389169689Skan if (nops >= 2) 39090075Sobrien { 391169689Skan oprnd1 = TREE_OPERAND (exp, 1); 392169689Skan tmode1 = TYPE_MODE (TREE_TYPE (oprnd1)); 393169689Skan xmode1 = insn_data[icode].operand[2].mode; 39490075Sobrien } 395132718Skan 396169689Skan /* The last operand is of a wider mode than the rest of the operands. */ 397169689Skan if (nops == 2) 398169689Skan { 399169689Skan wmode = tmode1; 400169689Skan wxmode = xmode1; 401169689Skan } 402169689Skan else if (nops == 3) 403169689Skan { 404169689Skan gcc_assert (tmode1 == tmode0); 405169689Skan gcc_assert (op1); 406169689Skan oprnd2 = TREE_OPERAND (exp, 2); 407169689Skan wmode = TYPE_MODE (TREE_TYPE (oprnd2)); 408169689Skan wxmode = insn_data[icode].operand[3].mode; 409169689Skan } 41052284Sobrien 411169689Skan if (!wide_op) 412169689Skan wmode = wxmode = insn_data[icode].operand[0].mode; 41352284Sobrien 414169689Skan if (!target 415169689Skan || ! (*insn_data[icode].operand[0].predicate) (target, wmode)) 416169689Skan temp = gen_reg_rtx (wmode); 417169689Skan else 418169689Skan temp = target; 41952284Sobrien 420169689Skan xop0 = op0; 421169689Skan xop1 = op1; 422169689Skan wxop = wide_op; 423169689Skan 424169689Skan /* In case the insn wants input operands in modes different from 425169689Skan those of the actual operands, convert the operands. It would 426169689Skan seem that we don't need to convert CONST_INTs, but we do, so 427169689Skan that they're properly zero-extended, sign-extended or truncated 428169689Skan for their mode. */ 429169689Skan 430169689Skan if (GET_MODE (op0) != xmode0 && xmode0 != VOIDmode) 431169689Skan xop0 = convert_modes (xmode0, 432169689Skan GET_MODE (op0) != VOIDmode 433169689Skan ? GET_MODE (op0) 434169689Skan : tmode0, 435169689Skan xop0, unsignedp); 436169689Skan 437169689Skan if (op1) 438169689Skan if (GET_MODE (op1) != xmode1 && xmode1 != VOIDmode) 439169689Skan xop1 = convert_modes (xmode1, 440169689Skan GET_MODE (op1) != VOIDmode 441169689Skan ? GET_MODE (op1) 442169689Skan : tmode1, 443169689Skan xop1, unsignedp); 444169689Skan 445169689Skan if (wide_op) 446169689Skan if (GET_MODE (wide_op) != wxmode && wxmode != VOIDmode) 447169689Skan wxop = convert_modes (wxmode, 448169689Skan GET_MODE (wide_op) != VOIDmode 449169689Skan ? GET_MODE (wide_op) 450169689Skan : wmode, 451169689Skan wxop, unsignedp); 452169689Skan 453169689Skan /* Now, if insn's predicates don't allow our operands, put them into 454169689Skan pseudo regs. */ 455169689Skan 456169689Skan if (! (*insn_data[icode].operand[1].predicate) (xop0, xmode0) 457169689Skan && xmode0 != VOIDmode) 458169689Skan xop0 = copy_to_mode_reg (xmode0, xop0); 459169689Skan 460169689Skan if (op1) 46152284Sobrien { 462169689Skan if (! (*insn_data[icode].operand[2].predicate) (xop1, xmode1) 463169689Skan && xmode1 != VOIDmode) 464169689Skan xop1 = copy_to_mode_reg (xmode1, xop1); 465169689Skan 466169689Skan if (wide_op) 467169689Skan { 468169689Skan if (! (*insn_data[icode].operand[3].predicate) (wxop, wxmode) 469169689Skan && wxmode != VOIDmode) 470169689Skan wxop = copy_to_mode_reg (wxmode, wxop); 471169689Skan 472169689Skan pat = GEN_FCN (icode) (temp, xop0, xop1, wxop); 473169689Skan } 474169689Skan else 475169689Skan pat = GEN_FCN (icode) (temp, xop0, xop1); 47652284Sobrien } 47752284Sobrien else 47852284Sobrien { 479169689Skan if (wide_op) 480169689Skan { 481169689Skan if (! (*insn_data[icode].operand[2].predicate) (wxop, wxmode) 482169689Skan && wxmode != VOIDmode) 483169689Skan wxop = copy_to_mode_reg (wxmode, wxop); 484169689Skan 485169689Skan pat = GEN_FCN (icode) (temp, xop0, wxop); 486169689Skan } 487169689Skan else 488169689Skan pat = GEN_FCN (icode) (temp, xop0); 48952284Sobrien } 49052284Sobrien 491169689Skan emit_insn (pat); 492169689Skan return temp; 493169689Skan} 49452284Sobrien 495169689Skan/* Generate code to perform an operation specified by TERNARY_OPTAB 496169689Skan on operands OP0, OP1 and OP2, with result having machine-mode MODE. 49752284Sobrien 498169689Skan UNSIGNEDP is for the case where we have to widen the operands 499169689Skan to perform the operation. It says to use zero-extension. 50052284Sobrien 501169689Skan If TARGET is nonzero, the value 502169689Skan is generated there, if it is convenient to do so. 503169689Skan In all cases an rtx is returned for the locus of the value; 504169689Skan this may or may not be TARGET. */ 505169689Skan 506169689Skanrtx 507169689Skanexpand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0, 508169689Skan rtx op1, rtx op2, rtx target, int unsignedp) 509169689Skan{ 510169689Skan int icode = (int) ternary_optab->handlers[(int) mode].insn_code; 511169689Skan enum machine_mode mode0 = insn_data[icode].operand[1].mode; 512169689Skan enum machine_mode mode1 = insn_data[icode].operand[2].mode; 513169689Skan enum machine_mode mode2 = insn_data[icode].operand[3].mode; 514169689Skan rtx temp; 515169689Skan rtx pat; 516169689Skan rtx xop0 = op0, xop1 = op1, xop2 = op2; 517169689Skan 518169689Skan gcc_assert (ternary_optab->handlers[(int) mode].insn_code 519169689Skan != CODE_FOR_nothing); 520169689Skan 521169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 522169689Skan temp = gen_reg_rtx (mode); 52352284Sobrien else 524169689Skan temp = target; 52552284Sobrien 526169689Skan /* In case the insn wants input operands in modes different from 527169689Skan those of the actual operands, convert the operands. It would 528169689Skan seem that we don't need to convert CONST_INTs, but we do, so 529169689Skan that they're properly zero-extended, sign-extended or truncated 530169689Skan for their mode. */ 53152284Sobrien 532169689Skan if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) 533169689Skan xop0 = convert_modes (mode0, 534169689Skan GET_MODE (op0) != VOIDmode 535169689Skan ? GET_MODE (op0) 536169689Skan : mode, 537169689Skan xop0, unsignedp); 53852284Sobrien 539169689Skan if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) 540169689Skan xop1 = convert_modes (mode1, 541169689Skan GET_MODE (op1) != VOIDmode 542169689Skan ? GET_MODE (op1) 543169689Skan : mode, 544169689Skan xop1, unsignedp); 54552284Sobrien 546169689Skan if (GET_MODE (op2) != mode2 && mode2 != VOIDmode) 547169689Skan xop2 = convert_modes (mode2, 548169689Skan GET_MODE (op2) != VOIDmode 549169689Skan ? GET_MODE (op2) 550169689Skan : mode, 551169689Skan xop2, unsignedp); 55252284Sobrien 553169689Skan /* Now, if insn's predicates don't allow our operands, put them into 554169689Skan pseudo regs. */ 55552284Sobrien 556169689Skan if (!insn_data[icode].operand[1].predicate (xop0, mode0) 557169689Skan && mode0 != VOIDmode) 558169689Skan xop0 = copy_to_mode_reg (mode0, xop0); 55952284Sobrien 560169689Skan if (!insn_data[icode].operand[2].predicate (xop1, mode1) 561169689Skan && mode1 != VOIDmode) 562169689Skan xop1 = copy_to_mode_reg (mode1, xop1); 56352284Sobrien 564169689Skan if (!insn_data[icode].operand[3].predicate (xop2, mode2) 565169689Skan && mode2 != VOIDmode) 566169689Skan xop2 = copy_to_mode_reg (mode2, xop2); 567169689Skan 568169689Skan pat = GEN_FCN (icode) (temp, xop0, xop1, xop2); 569169689Skan 570169689Skan emit_insn (pat); 571169689Skan return temp; 572169689Skan} 573169689Skan 574169689Skan 575169689Skan/* Like expand_binop, but return a constant rtx if the result can be 576169689Skan calculated at compile time. The arguments and return value are 577169689Skan otherwise the same as for expand_binop. */ 578169689Skan 579169689Skanstatic rtx 580169689Skansimplify_expand_binop (enum machine_mode mode, optab binoptab, 581169689Skan rtx op0, rtx op1, rtx target, int unsignedp, 582169689Skan enum optab_methods methods) 583169689Skan{ 584169689Skan if (CONSTANT_P (op0) && CONSTANT_P (op1)) 58552284Sobrien { 586169689Skan rtx x = simplify_binary_operation (binoptab->code, mode, op0, op1); 58752284Sobrien 588169689Skan if (x) 589169689Skan return x; 590169689Skan } 59152284Sobrien 592169689Skan return expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods); 593169689Skan} 59452284Sobrien 595169689Skan/* Like simplify_expand_binop, but always put the result in TARGET. 596169689Skan Return true if the expansion succeeded. */ 59752284Sobrien 598169689Skanbool 599169689Skanforce_expand_binop (enum machine_mode mode, optab binoptab, 600169689Skan rtx op0, rtx op1, rtx target, int unsignedp, 601169689Skan enum optab_methods methods) 602169689Skan{ 603169689Skan rtx x = simplify_expand_binop (mode, binoptab, op0, op1, 604169689Skan target, unsignedp, methods); 605169689Skan if (x == 0) 606169689Skan return false; 607169689Skan if (x != target) 608169689Skan emit_move_insn (target, x); 609169689Skan return true; 610169689Skan} 61152284Sobrien 612169689Skan/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR. */ 613169689Skan 614169689Skanrtx 615169689Skanexpand_vec_shift_expr (tree vec_shift_expr, rtx target) 616169689Skan{ 617169689Skan enum insn_code icode; 618169689Skan rtx rtx_op1, rtx_op2; 619169689Skan enum machine_mode mode1; 620169689Skan enum machine_mode mode2; 621169689Skan enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_shift_expr)); 622169689Skan tree vec_oprnd = TREE_OPERAND (vec_shift_expr, 0); 623169689Skan tree shift_oprnd = TREE_OPERAND (vec_shift_expr, 1); 624169689Skan optab shift_optab; 625169689Skan rtx pat; 626169689Skan 627169689Skan switch (TREE_CODE (vec_shift_expr)) 628169689Skan { 629169689Skan case VEC_RSHIFT_EXPR: 630169689Skan shift_optab = vec_shr_optab; 631169689Skan break; 632169689Skan case VEC_LSHIFT_EXPR: 633169689Skan shift_optab = vec_shl_optab; 634169689Skan break; 635169689Skan default: 636169689Skan gcc_unreachable (); 63752284Sobrien } 63852284Sobrien 639169689Skan icode = (int) shift_optab->handlers[(int) mode].insn_code; 640169689Skan gcc_assert (icode != CODE_FOR_nothing); 64152284Sobrien 642169689Skan mode1 = insn_data[icode].operand[1].mode; 643169689Skan mode2 = insn_data[icode].operand[2].mode; 64452284Sobrien 645169689Skan rtx_op1 = expand_expr (vec_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL); 646169689Skan if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1) 647169689Skan && mode1 != VOIDmode) 648169689Skan rtx_op1 = force_reg (mode1, rtx_op1); 64952284Sobrien 650169689Skan rtx_op2 = expand_expr (shift_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL); 651169689Skan if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode2) 652169689Skan && mode2 != VOIDmode) 653169689Skan rtx_op2 = force_reg (mode2, rtx_op2); 65452284Sobrien 655169689Skan if (!target 656169689Skan || ! (*insn_data[icode].operand[0].predicate) (target, mode)) 657169689Skan target = gen_reg_rtx (mode); 65852284Sobrien 659169689Skan /* Emit instruction */ 660169689Skan pat = GEN_FCN (icode) (target, rtx_op1, rtx_op2); 661169689Skan gcc_assert (pat); 662169689Skan emit_insn (pat); 66352284Sobrien 664169689Skan return target; 665169689Skan} 666169689Skan 667169689Skan/* This subroutine of expand_doubleword_shift handles the cases in which 668169689Skan the effective shift value is >= BITS_PER_WORD. The arguments and return 669169689Skan value are the same as for the parent routine, except that SUPERWORD_OP1 670169689Skan is the shift count to use when shifting OUTOF_INPUT into INTO_TARGET. 671169689Skan INTO_TARGET may be null if the caller has decided to calculate it. */ 672169689Skan 673169689Skanstatic bool 674169689Skanexpand_superword_shift (optab binoptab, rtx outof_input, rtx superword_op1, 675169689Skan rtx outof_target, rtx into_target, 676169689Skan int unsignedp, enum optab_methods methods) 677169689Skan{ 678169689Skan if (into_target != 0) 679169689Skan if (!force_expand_binop (word_mode, binoptab, outof_input, superword_op1, 680169689Skan into_target, unsignedp, methods)) 681169689Skan return false; 682169689Skan 683169689Skan if (outof_target != 0) 684169689Skan { 685169689Skan /* For a signed right shift, we must fill OUTOF_TARGET with copies 686169689Skan of the sign bit, otherwise we must fill it with zeros. */ 687169689Skan if (binoptab != ashr_optab) 688169689Skan emit_move_insn (outof_target, CONST0_RTX (word_mode)); 689169689Skan else 690169689Skan if (!force_expand_binop (word_mode, binoptab, 691169689Skan outof_input, GEN_INT (BITS_PER_WORD - 1), 692169689Skan outof_target, unsignedp, methods)) 693169689Skan return false; 69452284Sobrien } 695169689Skan return true; 696169689Skan} 69752284Sobrien 698169689Skan/* This subroutine of expand_doubleword_shift handles the cases in which 699169689Skan the effective shift value is < BITS_PER_WORD. The arguments and return 700169689Skan value are the same as for the parent routine. */ 70152284Sobrien 702169689Skanstatic bool 703169689Skanexpand_subword_shift (enum machine_mode op1_mode, optab binoptab, 704169689Skan rtx outof_input, rtx into_input, rtx op1, 705169689Skan rtx outof_target, rtx into_target, 706169689Skan int unsignedp, enum optab_methods methods, 707169689Skan unsigned HOST_WIDE_INT shift_mask) 708169689Skan{ 709169689Skan optab reverse_unsigned_shift, unsigned_shift; 710169689Skan rtx tmp, carries; 71152284Sobrien 712169689Skan reverse_unsigned_shift = (binoptab == ashl_optab ? lshr_optab : ashl_optab); 713169689Skan unsigned_shift = (binoptab == ashl_optab ? ashl_optab : lshr_optab); 71452284Sobrien 715169689Skan /* The low OP1 bits of INTO_TARGET come from the high bits of OUTOF_INPUT. 716169689Skan We therefore need to shift OUTOF_INPUT by (BITS_PER_WORD - OP1) bits in 717169689Skan the opposite direction to BINOPTAB. */ 718169689Skan if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD) 719169689Skan { 720169689Skan carries = outof_input; 721169689Skan tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode); 722169689Skan tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1, 723169689Skan 0, true, methods); 724169689Skan } 72552284Sobrien else 726169689Skan { 727169689Skan /* We must avoid shifting by BITS_PER_WORD bits since that is either 728169689Skan the same as a zero shift (if shift_mask == BITS_PER_WORD - 1) or 729169689Skan has unknown behavior. Do a single shift first, then shift by the 730169689Skan remainder. It's OK to use ~OP1 as the remainder if shift counts 731169689Skan are truncated to the mode size. */ 732169689Skan carries = expand_binop (word_mode, reverse_unsigned_shift, 733169689Skan outof_input, const1_rtx, 0, unsignedp, methods); 734169689Skan if (shift_mask == BITS_PER_WORD - 1) 735169689Skan { 736169689Skan tmp = immed_double_const (-1, -1, op1_mode); 737169689Skan tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp, 738169689Skan 0, true, methods); 739169689Skan } 740169689Skan else 741169689Skan { 742169689Skan tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode); 743169689Skan tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1, 744169689Skan 0, true, methods); 745169689Skan } 746169689Skan } 747169689Skan if (tmp == 0 || carries == 0) 748169689Skan return false; 749169689Skan carries = expand_binop (word_mode, reverse_unsigned_shift, 750169689Skan carries, tmp, 0, unsignedp, methods); 751169689Skan if (carries == 0) 752169689Skan return false; 75352284Sobrien 754169689Skan /* Shift INTO_INPUT logically by OP1. This is the last use of INTO_INPUT 755169689Skan so the result can go directly into INTO_TARGET if convenient. */ 756169689Skan tmp = expand_binop (word_mode, unsigned_shift, into_input, op1, 757169689Skan into_target, unsignedp, methods); 758169689Skan if (tmp == 0) 759169689Skan return false; 76052284Sobrien 761169689Skan /* Now OR in the bits carried over from OUTOF_INPUT. */ 762169689Skan if (!force_expand_binop (word_mode, ior_optab, tmp, carries, 763169689Skan into_target, unsignedp, methods)) 764169689Skan return false; 76552284Sobrien 766169689Skan /* Use a standard word_mode shift for the out-of half. */ 767169689Skan if (outof_target != 0) 768169689Skan if (!force_expand_binop (word_mode, binoptab, outof_input, op1, 769169689Skan outof_target, unsignedp, methods)) 770169689Skan return false; 77152284Sobrien 772169689Skan return true; 773169689Skan} 77452284Sobrien 77552284Sobrien 776169689Skan#ifdef HAVE_conditional_move 777169689Skan/* Try implementing expand_doubleword_shift using conditional moves. 778169689Skan The shift is by < BITS_PER_WORD if (CMP_CODE CMP1 CMP2) is true, 779169689Skan otherwise it is by >= BITS_PER_WORD. SUBWORD_OP1 and SUPERWORD_OP1 780169689Skan are the shift counts to use in the former and latter case. All other 781169689Skan arguments are the same as the parent routine. */ 782169689Skan 783169689Skanstatic bool 784169689Skanexpand_doubleword_shift_condmove (enum machine_mode op1_mode, optab binoptab, 785169689Skan enum rtx_code cmp_code, rtx cmp1, rtx cmp2, 786169689Skan rtx outof_input, rtx into_input, 787169689Skan rtx subword_op1, rtx superword_op1, 788169689Skan rtx outof_target, rtx into_target, 789169689Skan int unsignedp, enum optab_methods methods, 790169689Skan unsigned HOST_WIDE_INT shift_mask) 791169689Skan{ 792169689Skan rtx outof_superword, into_superword; 793169689Skan 794169689Skan /* Put the superword version of the output into OUTOF_SUPERWORD and 795169689Skan INTO_SUPERWORD. */ 796169689Skan outof_superword = outof_target != 0 ? gen_reg_rtx (word_mode) : 0; 797169689Skan if (outof_target != 0 && subword_op1 == superword_op1) 798169689Skan { 799169689Skan /* The value INTO_TARGET >> SUBWORD_OP1, which we later store in 800169689Skan OUTOF_TARGET, is the same as the value of INTO_SUPERWORD. */ 801169689Skan into_superword = outof_target; 802169689Skan if (!expand_superword_shift (binoptab, outof_input, superword_op1, 803169689Skan outof_superword, 0, unsignedp, methods)) 804169689Skan return false; 805169689Skan } 80652284Sobrien else 807169689Skan { 808169689Skan into_superword = gen_reg_rtx (word_mode); 809169689Skan if (!expand_superword_shift (binoptab, outof_input, superword_op1, 810169689Skan outof_superword, into_superword, 811169689Skan unsignedp, methods)) 812169689Skan return false; 813169689Skan } 81452284Sobrien 815169689Skan /* Put the subword version directly in OUTOF_TARGET and INTO_TARGET. */ 816169689Skan if (!expand_subword_shift (op1_mode, binoptab, 817169689Skan outof_input, into_input, subword_op1, 818169689Skan outof_target, into_target, 819169689Skan unsignedp, methods, shift_mask)) 820169689Skan return false; 82152284Sobrien 822169689Skan /* Select between them. Do the INTO half first because INTO_SUPERWORD 823169689Skan might be the current value of OUTOF_TARGET. */ 824169689Skan if (!emit_conditional_move (into_target, cmp_code, cmp1, cmp2, op1_mode, 825169689Skan into_target, into_superword, word_mode, false)) 826169689Skan return false; 82752284Sobrien 828169689Skan if (outof_target != 0) 829169689Skan if (!emit_conditional_move (outof_target, cmp_code, cmp1, cmp2, op1_mode, 830169689Skan outof_target, outof_superword, 831169689Skan word_mode, false)) 832169689Skan return false; 83352284Sobrien 834169689Skan return true; 835169689Skan} 836169689Skan#endif 83752284Sobrien 838169689Skan/* Expand a doubleword shift (ashl, ashr or lshr) using word-mode shifts. 839169689Skan OUTOF_INPUT and INTO_INPUT are the two word-sized halves of the first 840169689Skan input operand; the shift moves bits in the direction OUTOF_INPUT-> 841169689Skan INTO_TARGET. OUTOF_TARGET and INTO_TARGET are the equivalent words 842169689Skan of the target. OP1 is the shift count and OP1_MODE is its mode. 843169689Skan If OP1 is constant, it will have been truncated as appropriate 844169689Skan and is known to be nonzero. 84552284Sobrien 846169689Skan If SHIFT_MASK is zero, the result of word shifts is undefined when the 847169689Skan shift count is outside the range [0, BITS_PER_WORD). This routine must 848169689Skan avoid generating such shifts for OP1s in the range [0, BITS_PER_WORD * 2). 84952284Sobrien 850169689Skan If SHIFT_MASK is nonzero, all word-mode shift counts are effectively 851169689Skan masked by it and shifts in the range [BITS_PER_WORD, SHIFT_MASK) will 852169689Skan fill with zeros or sign bits as appropriate. 85352284Sobrien 854169689Skan If SHIFT_MASK is BITS_PER_WORD - 1, this routine will synthesize 855169689Skan a doubleword shift whose equivalent mask is BITS_PER_WORD * 2 - 1. 856169689Skan Doing this preserves semantics required by SHIFT_COUNT_TRUNCATED. 857169689Skan In all other cases, shifts by values outside [0, BITS_PER_UNIT * 2) 858169689Skan are undefined. 85952284Sobrien 860169689Skan BINOPTAB, UNSIGNEDP and METHODS are as for expand_binop. This function 861169689Skan may not use INTO_INPUT after modifying INTO_TARGET, and similarly for 862169689Skan OUTOF_INPUT and OUTOF_TARGET. OUTOF_TARGET can be null if the parent 863169689Skan function wants to calculate it itself. 86452284Sobrien 865169689Skan Return true if the shift could be successfully synthesized. */ 86652284Sobrien 867169689Skanstatic bool 868169689Skanexpand_doubleword_shift (enum machine_mode op1_mode, optab binoptab, 869169689Skan rtx outof_input, rtx into_input, rtx op1, 870169689Skan rtx outof_target, rtx into_target, 871169689Skan int unsignedp, enum optab_methods methods, 872169689Skan unsigned HOST_WIDE_INT shift_mask) 873169689Skan{ 874169689Skan rtx superword_op1, tmp, cmp1, cmp2; 875169689Skan rtx subword_label, done_label; 876169689Skan enum rtx_code cmp_code; 877169689Skan 878169689Skan /* See if word-mode shifts by BITS_PER_WORD...BITS_PER_WORD * 2 - 1 will 879169689Skan fill the result with sign or zero bits as appropriate. If so, the value 880169689Skan of OUTOF_TARGET will always be (SHIFT OUTOF_INPUT OP1). Recursively call 881169689Skan this routine to calculate INTO_TARGET (which depends on both OUTOF_INPUT 882169689Skan and INTO_INPUT), then emit code to set up OUTOF_TARGET. 883169689Skan 884169689Skan This isn't worthwhile for constant shifts since the optimizers will 885169689Skan cope better with in-range shift counts. */ 886169689Skan if (shift_mask >= BITS_PER_WORD 887169689Skan && outof_target != 0 888169689Skan && !CONSTANT_P (op1)) 889169689Skan { 890169689Skan if (!expand_doubleword_shift (op1_mode, binoptab, 891169689Skan outof_input, into_input, op1, 892169689Skan 0, into_target, 893169689Skan unsignedp, methods, shift_mask)) 894169689Skan return false; 895169689Skan if (!force_expand_binop (word_mode, binoptab, outof_input, op1, 896169689Skan outof_target, unsignedp, methods)) 897169689Skan return false; 898169689Skan return true; 89952284Sobrien } 900169689Skan 901169689Skan /* Set CMP_CODE, CMP1 and CMP2 so that the rtx (CMP_CODE CMP1 CMP2) 902169689Skan is true when the effective shift value is less than BITS_PER_WORD. 903169689Skan Set SUPERWORD_OP1 to the shift count that should be used to shift 904169689Skan OUTOF_INPUT into INTO_TARGET when the condition is false. */ 905169689Skan tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode); 906169689Skan if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1) 907169689Skan { 908169689Skan /* Set CMP1 to OP1 & BITS_PER_WORD. The result is zero iff OP1 909169689Skan is a subword shift count. */ 910169689Skan cmp1 = simplify_expand_binop (op1_mode, and_optab, op1, tmp, 911169689Skan 0, true, methods); 912169689Skan cmp2 = CONST0_RTX (op1_mode); 913169689Skan cmp_code = EQ; 914169689Skan superword_op1 = op1; 915169689Skan } 91652284Sobrien else 91752284Sobrien { 918169689Skan /* Set CMP1 to OP1 - BITS_PER_WORD. */ 919169689Skan cmp1 = simplify_expand_binop (op1_mode, sub_optab, op1, tmp, 920169689Skan 0, true, methods); 921169689Skan cmp2 = CONST0_RTX (op1_mode); 922169689Skan cmp_code = LT; 923169689Skan superword_op1 = cmp1; 924169689Skan } 925169689Skan if (cmp1 == 0) 926169689Skan return false; 92752284Sobrien 928169689Skan /* If we can compute the condition at compile time, pick the 929169689Skan appropriate subroutine. */ 930169689Skan tmp = simplify_relational_operation (cmp_code, SImode, op1_mode, cmp1, cmp2); 931169689Skan if (tmp != 0 && GET_CODE (tmp) == CONST_INT) 932169689Skan { 933169689Skan if (tmp == const0_rtx) 934169689Skan return expand_superword_shift (binoptab, outof_input, superword_op1, 935169689Skan outof_target, into_target, 936169689Skan unsignedp, methods); 937169689Skan else 938169689Skan return expand_subword_shift (op1_mode, binoptab, 939169689Skan outof_input, into_input, op1, 940169689Skan outof_target, into_target, 941169689Skan unsignedp, methods, shift_mask); 942169689Skan } 94352284Sobrien 944169689Skan#ifdef HAVE_conditional_move 945169689Skan /* Try using conditional moves to generate straight-line code. */ 946169689Skan { 947169689Skan rtx start = get_last_insn (); 948169689Skan if (expand_doubleword_shift_condmove (op1_mode, binoptab, 949169689Skan cmp_code, cmp1, cmp2, 950169689Skan outof_input, into_input, 951169689Skan op1, superword_op1, 952169689Skan outof_target, into_target, 953169689Skan unsignedp, methods, shift_mask)) 954169689Skan return true; 955169689Skan delete_insns_since (start); 956169689Skan } 957169689Skan#endif 95852284Sobrien 959169689Skan /* As a last resort, use branches to select the correct alternative. */ 960169689Skan subword_label = gen_label_rtx (); 961169689Skan done_label = gen_label_rtx (); 96252284Sobrien 963169689Skan NO_DEFER_POP; 964169689Skan do_compare_rtx_and_jump (cmp1, cmp2, cmp_code, false, op1_mode, 965169689Skan 0, 0, subword_label); 966169689Skan OK_DEFER_POP; 96752284Sobrien 968169689Skan if (!expand_superword_shift (binoptab, outof_input, superword_op1, 969169689Skan outof_target, into_target, 970169689Skan unsignedp, methods)) 971169689Skan return false; 97252284Sobrien 973169689Skan emit_jump_insn (gen_jump (done_label)); 974169689Skan emit_barrier (); 975169689Skan emit_label (subword_label); 97652284Sobrien 977169689Skan if (!expand_subword_shift (op1_mode, binoptab, 978169689Skan outof_input, into_input, op1, 979169689Skan outof_target, into_target, 980169689Skan unsignedp, methods, shift_mask)) 981169689Skan return false; 982169689Skan 983169689Skan emit_label (done_label); 984169689Skan return true; 985169689Skan} 986169689Skan 987169689Skan/* Subroutine of expand_binop. Perform a double word multiplication of 988169689Skan operands OP0 and OP1 both of mode MODE, which is exactly twice as wide 989169689Skan as the target's word_mode. This function return NULL_RTX if anything 990169689Skan goes wrong, in which case it may have already emitted instructions 991169689Skan which need to be deleted. 992169689Skan 993169689Skan If we want to multiply two two-word values and have normal and widening 994169689Skan multiplies of single-word values, we can do this with three smaller 995169689Skan multiplications. Note that we do not make a REG_NO_CONFLICT block here 996169689Skan because we are not operating on one word at a time. 997169689Skan 998169689Skan The multiplication proceeds as follows: 999169689Skan _______________________ 1000169689Skan [__op0_high_|__op0_low__] 1001169689Skan _______________________ 1002169689Skan * [__op1_high_|__op1_low__] 1003169689Skan _______________________________________________ 1004169689Skan _______________________ 1005169689Skan (1) [__op0_low__*__op1_low__] 1006169689Skan _______________________ 1007169689Skan (2a) [__op0_low__*__op1_high_] 1008169689Skan _______________________ 1009169689Skan (2b) [__op0_high_*__op1_low__] 1010169689Skan _______________________ 1011169689Skan (3) [__op0_high_*__op1_high_] 1012169689Skan 1013169689Skan 1014169689Skan This gives a 4-word result. Since we are only interested in the 1015169689Skan lower 2 words, partial result (3) and the upper words of (2a) and 1016169689Skan (2b) don't need to be calculated. Hence (2a) and (2b) can be 1017169689Skan calculated using non-widening multiplication. 1018169689Skan 1019169689Skan (1), however, needs to be calculated with an unsigned widening 1020169689Skan multiplication. If this operation is not directly supported we 1021169689Skan try using a signed widening multiplication and adjust the result. 1022169689Skan This adjustment works as follows: 1023169689Skan 1024169689Skan If both operands are positive then no adjustment is needed. 1025169689Skan 1026169689Skan If the operands have different signs, for example op0_low < 0 and 1027169689Skan op1_low >= 0, the instruction treats the most significant bit of 1028169689Skan op0_low as a sign bit instead of a bit with significance 1029169689Skan 2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low 1030169689Skan with 2**BITS_PER_WORD - op0_low, and two's complements the 1031169689Skan result. Conclusion: We need to add op1_low * 2**BITS_PER_WORD to 1032169689Skan the result. 1033169689Skan 1034169689Skan Similarly, if both operands are negative, we need to add 1035169689Skan (op0_low + op1_low) * 2**BITS_PER_WORD. 1036169689Skan 1037169689Skan We use a trick to adjust quickly. We logically shift op0_low right 1038169689Skan (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to 1039169689Skan op0_high (op1_high) before it is used to calculate 2b (2a). If no 1040169689Skan logical shift exists, we do an arithmetic right shift and subtract 1041169689Skan the 0 or -1. */ 1042169689Skan 1043169689Skanstatic rtx 1044169689Skanexpand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, 1045169689Skan bool umulp, enum optab_methods methods) 1046169689Skan{ 1047169689Skan int low = (WORDS_BIG_ENDIAN ? 1 : 0); 1048169689Skan int high = (WORDS_BIG_ENDIAN ? 0 : 1); 1049169689Skan rtx wordm1 = umulp ? NULL_RTX : GEN_INT (BITS_PER_WORD - 1); 1050169689Skan rtx product, adjust, product_high, temp; 1051169689Skan 1052169689Skan rtx op0_high = operand_subword_force (op0, high, mode); 1053169689Skan rtx op0_low = operand_subword_force (op0, low, mode); 1054169689Skan rtx op1_high = operand_subword_force (op1, high, mode); 1055169689Skan rtx op1_low = operand_subword_force (op1, low, mode); 1056169689Skan 1057169689Skan /* If we're using an unsigned multiply to directly compute the product 1058169689Skan of the low-order words of the operands and perform any required 1059169689Skan adjustments of the operands, we begin by trying two more multiplications 1060169689Skan and then computing the appropriate sum. 1061169689Skan 1062169689Skan We have checked above that the required addition is provided. 1063169689Skan Full-word addition will normally always succeed, especially if 1064169689Skan it is provided at all, so we don't worry about its failure. The 1065169689Skan multiplication may well fail, however, so we do handle that. */ 1066169689Skan 1067169689Skan if (!umulp) 1068169689Skan { 1069169689Skan /* ??? This could be done with emit_store_flag where available. */ 1070169689Skan temp = expand_binop (word_mode, lshr_optab, op0_low, wordm1, 1071169689Skan NULL_RTX, 1, methods); 1072169689Skan if (temp) 1073169689Skan op0_high = expand_binop (word_mode, add_optab, op0_high, temp, 1074169689Skan NULL_RTX, 0, OPTAB_DIRECT); 1075169689Skan else 1076169689Skan { 1077169689Skan temp = expand_binop (word_mode, ashr_optab, op0_low, wordm1, 1078169689Skan NULL_RTX, 0, methods); 1079169689Skan if (!temp) 1080169689Skan return NULL_RTX; 1081169689Skan op0_high = expand_binop (word_mode, sub_optab, op0_high, temp, 1082169689Skan NULL_RTX, 0, OPTAB_DIRECT); 1083169689Skan } 1084169689Skan 1085169689Skan if (!op0_high) 1086169689Skan return NULL_RTX; 108752284Sobrien } 108852284Sobrien 1089169689Skan adjust = expand_binop (word_mode, smul_optab, op0_high, op1_low, 1090169689Skan NULL_RTX, 0, OPTAB_DIRECT); 1091169689Skan if (!adjust) 1092169689Skan return NULL_RTX; 109352284Sobrien 1094169689Skan /* OP0_HIGH should now be dead. */ 109552284Sobrien 1096169689Skan if (!umulp) 1097169689Skan { 1098169689Skan /* ??? This could be done with emit_store_flag where available. */ 1099169689Skan temp = expand_binop (word_mode, lshr_optab, op1_low, wordm1, 1100169689Skan NULL_RTX, 1, methods); 1101169689Skan if (temp) 1102169689Skan op1_high = expand_binop (word_mode, add_optab, op1_high, temp, 1103169689Skan NULL_RTX, 0, OPTAB_DIRECT); 1104169689Skan else 1105169689Skan { 1106169689Skan temp = expand_binop (word_mode, ashr_optab, op1_low, wordm1, 1107169689Skan NULL_RTX, 0, methods); 1108169689Skan if (!temp) 1109169689Skan return NULL_RTX; 1110169689Skan op1_high = expand_binop (word_mode, sub_optab, op1_high, temp, 1111169689Skan NULL_RTX, 0, OPTAB_DIRECT); 1112169689Skan } 111352284Sobrien 1114169689Skan if (!op1_high) 1115169689Skan return NULL_RTX; 1116169689Skan } 111752284Sobrien 1118169689Skan temp = expand_binop (word_mode, smul_optab, op1_high, op0_low, 1119169689Skan NULL_RTX, 0, OPTAB_DIRECT); 1120169689Skan if (!temp) 1121169689Skan return NULL_RTX; 112252284Sobrien 1123169689Skan /* OP1_HIGH should now be dead. */ 112452284Sobrien 1125169689Skan adjust = expand_binop (word_mode, add_optab, adjust, temp, 1126169689Skan adjust, 0, OPTAB_DIRECT); 112752284Sobrien 1128169689Skan if (target && !REG_P (target)) 1129169689Skan target = NULL_RTX; 1130169689Skan 1131169689Skan if (umulp) 1132169689Skan product = expand_binop (mode, umul_widen_optab, op0_low, op1_low, 1133169689Skan target, 1, OPTAB_DIRECT); 1134169689Skan else 1135169689Skan product = expand_binop (mode, smul_widen_optab, op0_low, op1_low, 1136169689Skan target, 1, OPTAB_DIRECT); 1137169689Skan 1138169689Skan if (!product) 1139169689Skan return NULL_RTX; 1140169689Skan 1141169689Skan product_high = operand_subword (product, high, 1, mode); 1142169689Skan adjust = expand_binop (word_mode, add_optab, product_high, adjust, 1143169689Skan REG_P (product_high) ? product_high : adjust, 1144169689Skan 0, OPTAB_DIRECT); 1145169689Skan emit_move_insn (product_high, adjust); 1146169689Skan return product; 114752284Sobrien} 114852284Sobrien 114990075Sobrien/* Wrapper around expand_binop which takes an rtx code to specify 115090075Sobrien the operation to perform, not an optab pointer. All other 115190075Sobrien arguments are the same. */ 115290075Sobrienrtx 1153132718Skanexpand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0, 1154132718Skan rtx op1, rtx target, int unsignedp, 1155132718Skan enum optab_methods methods) 115690075Sobrien{ 1157117395Skan optab binop = code_to_optab[(int) code]; 1158169689Skan gcc_assert (binop); 115990075Sobrien 116090075Sobrien return expand_binop (mode, binop, op0, op1, target, unsignedp, methods); 116190075Sobrien} 116290075Sobrien 1163169689Skan/* Return whether OP0 and OP1 should be swapped when expanding a commutative 1164169689Skan binop. Order them according to commutative_operand_precedence and, if 1165169689Skan possible, try to put TARGET or a pseudo first. */ 1166169689Skanstatic bool 1167169689Skanswap_commutative_operands_with_target (rtx target, rtx op0, rtx op1) 1168169689Skan{ 1169169689Skan int op0_prec = commutative_operand_precedence (op0); 1170169689Skan int op1_prec = commutative_operand_precedence (op1); 1171169689Skan 1172169689Skan if (op0_prec < op1_prec) 1173169689Skan return true; 1174169689Skan 1175169689Skan if (op0_prec > op1_prec) 1176169689Skan return false; 1177169689Skan 1178169689Skan /* With equal precedence, both orders are ok, but it is better if the 1179169689Skan first operand is TARGET, or if both TARGET and OP0 are pseudos. */ 1180169689Skan if (target == 0 || REG_P (target)) 1181169689Skan return (REG_P (op1) && !REG_P (op0)) || target == op1; 1182169689Skan else 1183169689Skan return rtx_equal_p (op1, target); 1184169689Skan} 1185169689Skan 1186169689Skan 118718334Speter/* Generate code to perform an operation specified by BINOPTAB 118818334Speter on operands OP0 and OP1, with result having machine-mode MODE. 118918334Speter 119018334Speter UNSIGNEDP is for the case where we have to widen the operands 119118334Speter to perform the operation. It says to use zero-extension. 119218334Speter 119318334Speter If TARGET is nonzero, the value 119418334Speter is generated there, if it is convenient to do so. 119518334Speter In all cases an rtx is returned for the locus of the value; 119618334Speter this may or may not be TARGET. */ 119718334Speter 119818334Speterrtx 1199132718Skanexpand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, 1200132718Skan rtx target, int unsignedp, enum optab_methods methods) 120118334Speter{ 120218334Speter enum optab_methods next_methods 120318334Speter = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN 120418334Speter ? OPTAB_WIDEN : methods); 120518334Speter enum mode_class class; 120618334Speter enum machine_mode wider_mode; 120790075Sobrien rtx temp; 120818334Speter int commutative_op = 0; 1209117395Skan int shift_op = (binoptab->code == ASHIFT 121018334Speter || binoptab->code == ASHIFTRT 121118334Speter || binoptab->code == LSHIFTRT 121218334Speter || binoptab->code == ROTATE 121318334Speter || binoptab->code == ROTATERT); 121418334Speter rtx entry_last = get_last_insn (); 121518334Speter rtx last; 1216169689Skan bool first_pass_p = true; 121718334Speter 121818334Speter class = GET_MODE_CLASS (mode); 121918334Speter 122018334Speter /* If subtracting an integer constant, convert this into an addition of 122118334Speter the negated constant. */ 122218334Speter 122318334Speter if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT) 122418334Speter { 122518334Speter op1 = negate_rtx (mode, op1); 122618334Speter binoptab = add_optab; 122718334Speter } 122818334Speter 1229169689Skan /* If we are inside an appropriately-short loop and we are optimizing, 1230169689Skan force expensive constants into a register. */ 1231169689Skan if (CONSTANT_P (op0) && optimize 123290075Sobrien && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1)) 1233169689Skan { 1234169689Skan if (GET_MODE (op0) != VOIDmode) 1235169689Skan op0 = convert_modes (mode, VOIDmode, op0, unsignedp); 1236169689Skan op0 = force_reg (mode, op0); 1237169689Skan } 123818334Speter 1239169689Skan if (CONSTANT_P (op1) && optimize 124090075Sobrien && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1)) 1241169689Skan { 1242169689Skan if (GET_MODE (op1) != VOIDmode) 1243169689Skan op1 = convert_modes (mode, VOIDmode, op1, unsignedp); 1244169689Skan op1 = force_reg (mode, op1); 1245169689Skan } 124618334Speter 124718334Speter /* Record where to delete back to if we backtrack. */ 124818334Speter last = get_last_insn (); 124918334Speter 125018334Speter /* If operation is commutative, 125118334Speter try to make the first operand a register. 125218334Speter Even better, try to make it the same as the target. 125318334Speter Also try to make the last operand a constant. */ 1254169689Skan if (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH 125518334Speter || binoptab == smul_widen_optab 125618334Speter || binoptab == umul_widen_optab 125718334Speter || binoptab == smul_highpart_optab 125818334Speter || binoptab == umul_highpart_optab) 125918334Speter { 126018334Speter commutative_op = 1; 126118334Speter 1262169689Skan if (swap_commutative_operands_with_target (target, op0, op1)) 126318334Speter { 126418334Speter temp = op1; 126518334Speter op1 = op0; 126618334Speter op0 = temp; 126718334Speter } 126818334Speter } 126918334Speter 1270169689Skan retry: 1271169689Skan 127218334Speter /* If we can do it with a three-operand insn, do so. */ 127318334Speter 127418334Speter if (methods != OPTAB_MUST_WIDEN 127518334Speter && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 127618334Speter { 127718334Speter int icode = (int) binoptab->handlers[(int) mode].insn_code; 127890075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 127990075Sobrien enum machine_mode mode1 = insn_data[icode].operand[2].mode; 128018334Speter rtx pat; 128118334Speter rtx xop0 = op0, xop1 = op1; 128218334Speter 128318334Speter if (target) 128418334Speter temp = target; 128518334Speter else 128618334Speter temp = gen_reg_rtx (mode); 128718334Speter 128818334Speter /* If it is a commutative operator and the modes would match 128950397Sobrien if we would swap the operands, we can save the conversions. */ 129018334Speter if (commutative_op) 129118334Speter { 129218334Speter if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 129318334Speter && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) 129418334Speter { 129590075Sobrien rtx tmp; 129618334Speter 129718334Speter tmp = op0; op0 = op1; op1 = tmp; 129818334Speter tmp = xop0; xop0 = xop1; xop1 = tmp; 129918334Speter } 130018334Speter } 130118334Speter 130218334Speter /* In case the insn wants input operands in modes different from 1303103445Skan those of the actual operands, convert the operands. It would 1304103445Skan seem that we don't need to convert CONST_INTs, but we do, so 1305110611Skan that they're properly zero-extended, sign-extended or truncated 1306110611Skan for their mode. */ 130718334Speter 1308117395Skan if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) 130990075Sobrien xop0 = convert_modes (mode0, 131090075Sobrien GET_MODE (op0) != VOIDmode 131190075Sobrien ? GET_MODE (op0) 1312103445Skan : mode, 131390075Sobrien xop0, unsignedp); 131418334Speter 1315117395Skan if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) 131690075Sobrien xop1 = convert_modes (mode1, 131790075Sobrien GET_MODE (op1) != VOIDmode 131890075Sobrien ? GET_MODE (op1) 1319110611Skan : mode, 132090075Sobrien xop1, unsignedp); 132118334Speter 132218334Speter /* Now, if insn's predicates don't allow our operands, put them into 132318334Speter pseudo regs. */ 132418334Speter 1325169689Skan if (!insn_data[icode].operand[1].predicate (xop0, mode0) 132618334Speter && mode0 != VOIDmode) 132718334Speter xop0 = copy_to_mode_reg (mode0, xop0); 132818334Speter 1329169689Skan if (!insn_data[icode].operand[2].predicate (xop1, mode1) 133018334Speter && mode1 != VOIDmode) 133118334Speter xop1 = copy_to_mode_reg (mode1, xop1); 133218334Speter 1333169689Skan if (!insn_data[icode].operand[0].predicate (temp, mode)) 133418334Speter temp = gen_reg_rtx (mode); 133518334Speter 133618334Speter pat = GEN_FCN (icode) (temp, xop0, xop1); 133718334Speter if (pat) 133818334Speter { 1339117395Skan /* If PAT is composed of more than one insn, try to add an appropriate 134018334Speter REG_EQUAL note to it. If we can't because TEMP conflicts with an 134118334Speter operand, call ourselves again, this time without a target. */ 1342117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX 134318334Speter && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) 134418334Speter { 134518334Speter delete_insns_since (last); 134618334Speter return expand_binop (mode, binoptab, op0, op1, NULL_RTX, 134718334Speter unsignedp, methods); 134818334Speter } 134918334Speter 135018334Speter emit_insn (pat); 135118334Speter return temp; 135218334Speter } 135318334Speter else 135418334Speter delete_insns_since (last); 135518334Speter } 135618334Speter 1357169689Skan /* If we were trying to rotate by a constant value, and that didn't 1358169689Skan work, try rotating the other direction before falling back to 1359169689Skan shifts and bitwise-or. */ 1360169689Skan if (first_pass_p 1361169689Skan && (binoptab == rotl_optab || binoptab == rotr_optab) 1362169689Skan && class == MODE_INT 1363169689Skan && GET_CODE (op1) == CONST_INT 1364169689Skan && INTVAL (op1) > 0 1365169689Skan && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode)) 1366169689Skan { 1367169689Skan first_pass_p = false; 1368169689Skan op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1)); 1369169689Skan binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab; 1370169689Skan goto retry; 1371169689Skan } 1372169689Skan 137318334Speter /* If this is a multiply, see if we can do a widening operation that 137418334Speter takes operands of this mode and makes a wider mode. */ 137518334Speter 1376169689Skan if (binoptab == smul_optab 1377169689Skan && GET_MODE_WIDER_MODE (mode) != VOIDmode 137818334Speter && (((unsignedp ? umul_widen_optab : smul_widen_optab) 137918334Speter ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code) 138018334Speter != CODE_FOR_nothing)) 138118334Speter { 138218334Speter temp = expand_binop (GET_MODE_WIDER_MODE (mode), 138318334Speter unsignedp ? umul_widen_optab : smul_widen_optab, 138418334Speter op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT); 138518334Speter 138618334Speter if (temp != 0) 138718334Speter { 1388169689Skan if (GET_MODE_CLASS (mode) == MODE_INT 1389169689Skan && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), 1390169689Skan GET_MODE_BITSIZE (GET_MODE (temp)))) 139118334Speter return gen_lowpart (mode, temp); 139218334Speter else 139318334Speter return convert_to_mode (mode, temp, unsignedp); 139418334Speter } 139518334Speter } 139618334Speter 139718334Speter /* Look for a wider mode of the same class for which we think we 139818334Speter can open-code the operation. Check for a widening multiply at the 139918334Speter wider mode as well. */ 140018334Speter 1401169689Skan if (CLASS_HAS_WIDER_MODES_P (class) 140218334Speter && methods != OPTAB_DIRECT && methods != OPTAB_LIB) 1403169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 1404169689Skan wider_mode != VOIDmode; 140518334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 140618334Speter { 140718334Speter if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing 140818334Speter || (binoptab == smul_optab 140918334Speter && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode 141018334Speter && (((unsignedp ? umul_widen_optab : smul_widen_optab) 141118334Speter ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code) 141218334Speter != CODE_FOR_nothing))) 141318334Speter { 141418334Speter rtx xop0 = op0, xop1 = op1; 141518334Speter int no_extend = 0; 141618334Speter 141718334Speter /* For certain integer operations, we need not actually extend 141818334Speter the narrow operands, as long as we will truncate 141990075Sobrien the results to the same narrowness. */ 142018334Speter 142118334Speter if ((binoptab == ior_optab || binoptab == and_optab 142218334Speter || binoptab == xor_optab 142318334Speter || binoptab == add_optab || binoptab == sub_optab 142418334Speter || binoptab == smul_optab || binoptab == ashl_optab) 142518334Speter && class == MODE_INT) 142618334Speter no_extend = 1; 142718334Speter 142818334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend); 142918334Speter 143018334Speter /* The second operand of a shift must always be extended. */ 143118334Speter xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, 143218334Speter no_extend && binoptab != ashl_optab); 143318334Speter 143418334Speter temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, 143518334Speter unsignedp, OPTAB_DIRECT); 143618334Speter if (temp) 143718334Speter { 1438169689Skan if (class != MODE_INT 1439169689Skan || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), 1440169689Skan GET_MODE_BITSIZE (wider_mode))) 144118334Speter { 144218334Speter if (target == 0) 144318334Speter target = gen_reg_rtx (mode); 144418334Speter convert_move (target, temp, 0); 144518334Speter return target; 144618334Speter } 144718334Speter else 144818334Speter return gen_lowpart (mode, temp); 144918334Speter } 145018334Speter else 145118334Speter delete_insns_since (last); 145218334Speter } 145318334Speter } 145418334Speter 145518334Speter /* These can be done a word at a time. */ 145618334Speter if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab) 145718334Speter && class == MODE_INT 145818334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 145918334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 146018334Speter { 146118334Speter int i; 146218334Speter rtx insns; 146318334Speter rtx equiv_value; 146418334Speter 146518334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 146618334Speter won't be accurate, so use a new target. */ 146718334Speter if (target == 0 || target == op0 || target == op1) 146818334Speter target = gen_reg_rtx (mode); 146918334Speter 147018334Speter start_sequence (); 147118334Speter 147218334Speter /* Do the actual arithmetic. */ 147318334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 147418334Speter { 147518334Speter rtx target_piece = operand_subword (target, i, 1, mode); 147618334Speter rtx x = expand_binop (word_mode, binoptab, 147718334Speter operand_subword_force (op0, i, mode), 147818334Speter operand_subword_force (op1, i, mode), 147918334Speter target_piece, unsignedp, next_methods); 148018334Speter 148118334Speter if (x == 0) 148218334Speter break; 148318334Speter 148418334Speter if (target_piece != x) 148518334Speter emit_move_insn (target_piece, x); 148618334Speter } 148718334Speter 148818334Speter insns = get_insns (); 148918334Speter end_sequence (); 149018334Speter 149118334Speter if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD) 149218334Speter { 149318334Speter if (binoptab->code != UNKNOWN) 149418334Speter equiv_value 149550397Sobrien = gen_rtx_fmt_ee (binoptab->code, mode, 149650397Sobrien copy_rtx (op0), copy_rtx (op1)); 149718334Speter else 149818334Speter equiv_value = 0; 149918334Speter 150018334Speter emit_no_conflict_block (insns, target, op0, op1, equiv_value); 150118334Speter return target; 150218334Speter } 150318334Speter } 150418334Speter 150518334Speter /* Synthesize double word shifts from single word shifts. */ 150618334Speter if ((binoptab == lshr_optab || binoptab == ashl_optab 150718334Speter || binoptab == ashr_optab) 150818334Speter && class == MODE_INT 1509169689Skan && (GET_CODE (op1) == CONST_INT || !optimize_size) 151018334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 151118334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 151218334Speter && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 151318334Speter && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 151418334Speter { 1515169689Skan unsigned HOST_WIDE_INT shift_mask, double_shift_mask; 1516169689Skan enum machine_mode op1_mode; 151718334Speter 1518169689Skan double_shift_mask = targetm.shift_truncation_mask (mode); 1519169689Skan shift_mask = targetm.shift_truncation_mask (word_mode); 1520169689Skan op1_mode = GET_MODE (op1) != VOIDmode ? GET_MODE (op1) : word_mode; 152118334Speter 1522169689Skan /* Apply the truncation to constant shifts. */ 1523169689Skan if (double_shift_mask > 0 && GET_CODE (op1) == CONST_INT) 1524169689Skan op1 = GEN_INT (INTVAL (op1) & double_shift_mask); 152518334Speter 1526169689Skan if (op1 == CONST0_RTX (op1_mode)) 1527169689Skan return op0; 152818334Speter 1529169689Skan /* Make sure that this is a combination that expand_doubleword_shift 1530169689Skan can handle. See the comments there for details. */ 1531169689Skan if (double_shift_mask == 0 1532169689Skan || (shift_mask == BITS_PER_WORD - 1 1533169689Skan && double_shift_mask == BITS_PER_WORD * 2 - 1)) 153418334Speter { 1535169689Skan rtx insns, equiv_value; 1536169689Skan rtx into_target, outof_target; 1537169689Skan rtx into_input, outof_input; 1538169689Skan int left_shift, outof_word; 153918334Speter 1540169689Skan /* If TARGET is the same as one of the operands, the REG_EQUAL note 1541169689Skan won't be accurate, so use a new target. */ 1542169689Skan if (target == 0 || target == op0 || target == op1) 1543169689Skan target = gen_reg_rtx (mode); 154418334Speter 1545169689Skan start_sequence (); 154618334Speter 1547169689Skan /* OUTOF_* is the word we are shifting bits away from, and 1548169689Skan INTO_* is the word that we are shifting bits towards, thus 1549169689Skan they differ depending on the direction of the shift and 1550169689Skan WORDS_BIG_ENDIAN. */ 155118334Speter 1552169689Skan left_shift = binoptab == ashl_optab; 1553169689Skan outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; 155418334Speter 1555169689Skan outof_target = operand_subword (target, outof_word, 1, mode); 1556169689Skan into_target = operand_subword (target, 1 - outof_word, 1, mode); 155718334Speter 1558169689Skan outof_input = operand_subword_force (op0, outof_word, mode); 1559169689Skan into_input = operand_subword_force (op0, 1 - outof_word, mode); 156018334Speter 1561169689Skan if (expand_doubleword_shift (op1_mode, binoptab, 1562169689Skan outof_input, into_input, op1, 1563169689Skan outof_target, into_target, 1564169689Skan unsignedp, next_methods, shift_mask)) 1565169689Skan { 1566169689Skan insns = get_insns (); 1567169689Skan end_sequence (); 156818334Speter 1569169689Skan equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1); 1570169689Skan emit_no_conflict_block (insns, target, op0, op1, equiv_value); 1571169689Skan return target; 1572169689Skan } 1573169689Skan end_sequence (); 157418334Speter } 157518334Speter } 157618334Speter 157718334Speter /* Synthesize double word rotates from single word shifts. */ 157818334Speter if ((binoptab == rotl_optab || binoptab == rotr_optab) 157918334Speter && class == MODE_INT 158018334Speter && GET_CODE (op1) == CONST_INT 158118334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 158218334Speter && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 158318334Speter && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 158418334Speter { 1585161651Skan rtx insns; 158618334Speter rtx into_target, outof_target; 158718334Speter rtx into_input, outof_input; 158818334Speter rtx inter; 158918334Speter int shift_count, left_shift, outof_word; 159018334Speter 159118334Speter /* If TARGET is the same as one of the operands, the REG_EQUAL note 1592169689Skan won't be accurate, so use a new target. Do this also if target is not 1593169689Skan a REG, first because having a register instead may open optimization 1594169689Skan opportunities, and second because if target and op0 happen to be MEMs 1595169689Skan designating the same location, we would risk clobbering it too early 1596169689Skan in the code sequence we generate below. */ 1597169689Skan if (target == 0 || target == op0 || target == op1 || ! REG_P (target)) 159818334Speter target = gen_reg_rtx (mode); 159918334Speter 160018334Speter start_sequence (); 160118334Speter 160218334Speter shift_count = INTVAL (op1); 160318334Speter 160418334Speter /* OUTOF_* is the word we are shifting bits away from, and 160518334Speter INTO_* is the word that we are shifting bits towards, thus 160618334Speter they differ depending on the direction of the shift and 160718334Speter WORDS_BIG_ENDIAN. */ 160818334Speter 160918334Speter left_shift = (binoptab == rotl_optab); 161018334Speter outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; 161118334Speter 161218334Speter outof_target = operand_subword (target, outof_word, 1, mode); 161318334Speter into_target = operand_subword (target, 1 - outof_word, 1, mode); 161418334Speter 161518334Speter outof_input = operand_subword_force (op0, outof_word, mode); 161618334Speter into_input = operand_subword_force (op0, 1 - outof_word, mode); 161718334Speter 161818334Speter if (shift_count == BITS_PER_WORD) 161918334Speter { 162018334Speter /* This is just a word swap. */ 162118334Speter emit_move_insn (outof_target, into_input); 162218334Speter emit_move_insn (into_target, outof_input); 162318334Speter inter = const0_rtx; 162418334Speter } 162518334Speter else 162618334Speter { 162718334Speter rtx into_temp1, into_temp2, outof_temp1, outof_temp2; 162818334Speter rtx first_shift_count, second_shift_count; 162918334Speter optab reverse_unsigned_shift, unsigned_shift; 163018334Speter 163118334Speter reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) 163218334Speter ? lshr_optab : ashl_optab); 163318334Speter 163418334Speter unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) 163518334Speter ? ashl_optab : lshr_optab); 163618334Speter 163718334Speter if (shift_count > BITS_PER_WORD) 163818334Speter { 163918334Speter first_shift_count = GEN_INT (shift_count - BITS_PER_WORD); 1640117395Skan second_shift_count = GEN_INT (2 * BITS_PER_WORD - shift_count); 164118334Speter } 164218334Speter else 164318334Speter { 164418334Speter first_shift_count = GEN_INT (BITS_PER_WORD - shift_count); 164518334Speter second_shift_count = GEN_INT (shift_count); 164618334Speter } 164718334Speter 164818334Speter into_temp1 = expand_binop (word_mode, unsigned_shift, 164918334Speter outof_input, first_shift_count, 165018334Speter NULL_RTX, unsignedp, next_methods); 165118334Speter into_temp2 = expand_binop (word_mode, reverse_unsigned_shift, 165218334Speter into_input, second_shift_count, 1653117395Skan NULL_RTX, unsignedp, next_methods); 165418334Speter 165518334Speter if (into_temp1 != 0 && into_temp2 != 0) 165618334Speter inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2, 165718334Speter into_target, unsignedp, next_methods); 165818334Speter else 165918334Speter inter = 0; 166018334Speter 166118334Speter if (inter != 0 && inter != into_target) 166218334Speter emit_move_insn (into_target, inter); 166318334Speter 166418334Speter outof_temp1 = expand_binop (word_mode, unsigned_shift, 166518334Speter into_input, first_shift_count, 166618334Speter NULL_RTX, unsignedp, next_methods); 166718334Speter outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift, 166818334Speter outof_input, second_shift_count, 1669117395Skan NULL_RTX, unsignedp, next_methods); 167018334Speter 167118334Speter if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0) 167218334Speter inter = expand_binop (word_mode, ior_optab, 167318334Speter outof_temp1, outof_temp2, 167418334Speter outof_target, unsignedp, next_methods); 167518334Speter 167618334Speter if (inter != 0 && inter != outof_target) 167718334Speter emit_move_insn (outof_target, inter); 167818334Speter } 167918334Speter 168018334Speter insns = get_insns (); 168118334Speter end_sequence (); 168218334Speter 168318334Speter if (inter != 0) 168418334Speter { 1685169689Skan /* One may be tempted to wrap the insns in a REG_NO_CONFLICT 1686169689Skan block to help the register allocator a bit. But a multi-word 1687169689Skan rotate will need all the input bits when setting the output 1688169689Skan bits, so there clearly is a conflict between the input and 1689169689Skan output registers. So we can't use a no-conflict block here. */ 1690161651Skan emit_insn (insns); 169118334Speter return target; 169218334Speter } 169318334Speter } 169418334Speter 169518334Speter /* These can be done a word at a time by propagating carries. */ 169618334Speter if ((binoptab == add_optab || binoptab == sub_optab) 169718334Speter && class == MODE_INT 169818334Speter && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD 169918334Speter && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 170018334Speter { 1701117395Skan unsigned int i; 170218334Speter optab otheroptab = binoptab == add_optab ? sub_optab : add_optab; 1703117395Skan const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; 170452284Sobrien rtx carry_in = NULL_RTX, carry_out = NULL_RTX; 1705102780Skan rtx xop0, xop1, xtarget; 170618334Speter 170718334Speter /* We can handle either a 1 or -1 value for the carry. If STORE_FLAG 170818334Speter value is one of those, use it. Otherwise, use 1 since it is the 170918334Speter one easiest to get. */ 171018334Speter#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1 171118334Speter int normalizep = STORE_FLAG_VALUE; 171218334Speter#else 171318334Speter int normalizep = 1; 171418334Speter#endif 171518334Speter 171618334Speter /* Prepare the operands. */ 171718334Speter xop0 = force_reg (mode, op0); 171818334Speter xop1 = force_reg (mode, op1); 171918334Speter 1720102780Skan xtarget = gen_reg_rtx (mode); 172118334Speter 1722169689Skan if (target == 0 || !REG_P (target)) 1723102780Skan target = xtarget; 1724102780Skan 172518334Speter /* Indicate for flow that the entire target reg is being set. */ 1726169689Skan if (REG_P (target)) 1727102780Skan emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget)); 172818334Speter 172918334Speter /* Do the actual arithmetic. */ 173018334Speter for (i = 0; i < nwords; i++) 173118334Speter { 173218334Speter int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i); 1733102780Skan rtx target_piece = operand_subword (xtarget, index, 1, mode); 173418334Speter rtx op0_piece = operand_subword_force (xop0, index, mode); 173518334Speter rtx op1_piece = operand_subword_force (xop1, index, mode); 173618334Speter rtx x; 173718334Speter 173818334Speter /* Main add/subtract of the input operands. */ 173918334Speter x = expand_binop (word_mode, binoptab, 174018334Speter op0_piece, op1_piece, 174118334Speter target_piece, unsignedp, next_methods); 174218334Speter if (x == 0) 174318334Speter break; 174418334Speter 174518334Speter if (i + 1 < nwords) 174618334Speter { 174718334Speter /* Store carry from main add/subtract. */ 174818334Speter carry_out = gen_reg_rtx (word_mode); 174950397Sobrien carry_out = emit_store_flag_force (carry_out, 175050397Sobrien (binoptab == add_optab 175190075Sobrien ? LT : GT), 175250397Sobrien x, op0_piece, 175350397Sobrien word_mode, 1, normalizep); 175418334Speter } 175518334Speter 175618334Speter if (i > 0) 175718334Speter { 175890075Sobrien rtx newx; 1759132718Skan 176018334Speter /* Add/subtract previous carry to main result. */ 176190075Sobrien newx = expand_binop (word_mode, 176290075Sobrien normalizep == 1 ? binoptab : otheroptab, 176390075Sobrien x, carry_in, 176490075Sobrien NULL_RTX, 1, next_methods); 176518334Speter 176618334Speter if (i + 1 < nwords) 176718334Speter { 176818334Speter /* Get out carry from adding/subtracting carry in. */ 176990075Sobrien rtx carry_tmp = gen_reg_rtx (word_mode); 177050397Sobrien carry_tmp = emit_store_flag_force (carry_tmp, 177190075Sobrien (binoptab == add_optab 177290075Sobrien ? LT : GT), 177390075Sobrien newx, x, 177450397Sobrien word_mode, 1, normalizep); 177518334Speter 177618334Speter /* Logical-ior the two poss. carry together. */ 177718334Speter carry_out = expand_binop (word_mode, ior_optab, 177818334Speter carry_out, carry_tmp, 177918334Speter carry_out, 0, next_methods); 178018334Speter if (carry_out == 0) 178118334Speter break; 178218334Speter } 178390075Sobrien emit_move_insn (target_piece, newx); 178418334Speter } 1785169689Skan else 1786169689Skan { 1787169689Skan if (x != target_piece) 1788169689Skan emit_move_insn (target_piece, x); 1789169689Skan } 179018334Speter 179118334Speter carry_in = carry_out; 1792132718Skan } 179318334Speter 1794117395Skan if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD) 179518334Speter { 1796132718Skan if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing 1797132718Skan || ! rtx_equal_p (target, xtarget)) 179850397Sobrien { 1799102780Skan rtx temp = emit_move_insn (target, xtarget); 180018334Speter 180152284Sobrien set_unique_reg_note (temp, 1802132718Skan REG_EQUAL, 180352284Sobrien gen_rtx_fmt_ee (binoptab->code, mode, 180452284Sobrien copy_rtx (xop0), 180552284Sobrien copy_rtx (xop1))); 180650397Sobrien } 1807117395Skan else 1808117395Skan target = xtarget; 180990075Sobrien 181018334Speter return target; 181118334Speter } 181290075Sobrien 181318334Speter else 181418334Speter delete_insns_since (last); 181518334Speter } 181618334Speter 1817169689Skan /* Attempt to synthesize double word multiplies using a sequence of word 1818169689Skan mode multiplications. We first attempt to generate a sequence using a 1819169689Skan more efficient unsigned widening multiply, and if that fails we then 1820169689Skan try using a signed widening multiply. */ 182118334Speter 182218334Speter if (binoptab == smul_optab 182318334Speter && class == MODE_INT 182418334Speter && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD 182518334Speter && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing 1826169689Skan && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 182718334Speter { 1828169689Skan rtx product = NULL_RTX; 182918334Speter 1830169689Skan if (umul_widen_optab->handlers[(int) mode].insn_code 1831169689Skan != CODE_FOR_nothing) 183218334Speter { 1833169689Skan product = expand_doubleword_mult (mode, op0, op1, target, 1834169689Skan true, methods); 1835169689Skan if (!product) 183618334Speter delete_insns_since (last); 183718334Speter } 183818334Speter 1839169689Skan if (product == NULL_RTX 184018334Speter && smul_widen_optab->handlers[(int) mode].insn_code 1841169689Skan != CODE_FOR_nothing) 184218334Speter { 1843169689Skan product = expand_doubleword_mult (mode, op0, op1, target, 1844169689Skan false, methods); 1845169689Skan if (!product) 1846169689Skan delete_insns_since (last); 184718334Speter } 184818334Speter 1849169689Skan if (product != NULL_RTX) 185018334Speter { 1851169689Skan if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 185218334Speter { 1853169689Skan temp = emit_move_insn (target ? target : product, product); 1854169689Skan set_unique_reg_note (temp, 1855169689Skan REG_EQUAL, 1856169689Skan gen_rtx_fmt_ee (MULT, mode, 1857169689Skan copy_rtx (op0), 1858169689Skan copy_rtx (op1))); 185918334Speter } 1860169689Skan return product; 186118334Speter } 186218334Speter } 186318334Speter 186418334Speter /* It can't be open-coded in this mode. 186518334Speter Use a library call if one is available and caller says that's ok. */ 186618334Speter 186718334Speter if (binoptab->handlers[(int) mode].libfunc 186818334Speter && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN)) 186918334Speter { 187018334Speter rtx insns; 187118334Speter rtx op1x = op1; 187218334Speter enum machine_mode op1_mode = mode; 187318334Speter rtx value; 187418334Speter 187518334Speter start_sequence (); 187618334Speter 187718334Speter if (shift_op) 187818334Speter { 187918334Speter op1_mode = word_mode; 188018334Speter /* Specify unsigned here, 188118334Speter since negative shift counts are meaningless. */ 188218334Speter op1x = convert_to_mode (word_mode, op1, 1); 188318334Speter } 188418334Speter 188518334Speter if (GET_MODE (op0) != VOIDmode 188618334Speter && GET_MODE (op0) != mode) 188718334Speter op0 = convert_to_mode (mode, op0, unsignedp); 188818334Speter 188918334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 189018334Speter if the libcall is cse'd or moved. */ 189118334Speter value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc, 189290075Sobrien NULL_RTX, LCT_CONST, mode, 2, 189318334Speter op0, mode, op1x, op1_mode); 189418334Speter 189518334Speter insns = get_insns (); 189618334Speter end_sequence (); 189718334Speter 189818334Speter target = gen_reg_rtx (mode); 189918334Speter emit_libcall_block (insns, target, value, 190050397Sobrien gen_rtx_fmt_ee (binoptab->code, mode, op0, op1)); 190118334Speter 190218334Speter return target; 190318334Speter } 190418334Speter 190518334Speter delete_insns_since (last); 190618334Speter 190718334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 190818334Speter 190918334Speter if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN 191018334Speter || methods == OPTAB_MUST_WIDEN)) 191118334Speter { 191218334Speter /* Caller says, don't even try. */ 191318334Speter delete_insns_since (entry_last); 191418334Speter return 0; 191518334Speter } 191618334Speter 191718334Speter /* Compute the value of METHODS to pass to recursive calls. 191818334Speter Don't allow widening to be tried recursively. */ 191918334Speter 192018334Speter methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT); 192118334Speter 192218334Speter /* Look for a wider mode of the same class for which it appears we can do 192318334Speter the operation. */ 192418334Speter 1925169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 192618334Speter { 1927169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 1928169689Skan wider_mode != VOIDmode; 192918334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 193018334Speter { 193118334Speter if ((binoptab->handlers[(int) wider_mode].insn_code 193218334Speter != CODE_FOR_nothing) 193318334Speter || (methods == OPTAB_LIB 193418334Speter && binoptab->handlers[(int) wider_mode].libfunc)) 193518334Speter { 193618334Speter rtx xop0 = op0, xop1 = op1; 193718334Speter int no_extend = 0; 193818334Speter 193918334Speter /* For certain integer operations, we need not actually extend 194018334Speter the narrow operands, as long as we will truncate 194118334Speter the results to the same narrowness. */ 194218334Speter 194318334Speter if ((binoptab == ior_optab || binoptab == and_optab 194418334Speter || binoptab == xor_optab 194518334Speter || binoptab == add_optab || binoptab == sub_optab 194618334Speter || binoptab == smul_optab || binoptab == ashl_optab) 194718334Speter && class == MODE_INT) 194818334Speter no_extend = 1; 194918334Speter 195018334Speter xop0 = widen_operand (xop0, wider_mode, mode, 195118334Speter unsignedp, no_extend); 195218334Speter 195318334Speter /* The second operand of a shift must always be extended. */ 195418334Speter xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, 195518334Speter no_extend && binoptab != ashl_optab); 195618334Speter 195718334Speter temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, 195818334Speter unsignedp, methods); 195918334Speter if (temp) 196018334Speter { 1961169689Skan if (class != MODE_INT 1962169689Skan || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), 1963169689Skan GET_MODE_BITSIZE (wider_mode))) 196418334Speter { 196518334Speter if (target == 0) 196618334Speter target = gen_reg_rtx (mode); 196718334Speter convert_move (target, temp, 0); 196818334Speter return target; 196918334Speter } 197018334Speter else 197118334Speter return gen_lowpart (mode, temp); 197218334Speter } 197318334Speter else 197418334Speter delete_insns_since (last); 197518334Speter } 197618334Speter } 197718334Speter } 197818334Speter 197918334Speter delete_insns_since (entry_last); 198018334Speter return 0; 198118334Speter} 198218334Speter 198318334Speter/* Expand a binary operator which has both signed and unsigned forms. 198418334Speter UOPTAB is the optab for unsigned operations, and SOPTAB is for 198518334Speter signed operations. 198618334Speter 198718334Speter If we widen unsigned operands, we may use a signed wider operation instead 198818334Speter of an unsigned wider operation, since the result would be the same. */ 198918334Speter 199018334Speterrtx 1991132718Skansign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab, 1992132718Skan rtx op0, rtx op1, rtx target, int unsignedp, 1993132718Skan enum optab_methods methods) 199418334Speter{ 199590075Sobrien rtx temp; 199618334Speter optab direct_optab = unsignedp ? uoptab : soptab; 199718334Speter struct optab wide_soptab; 199818334Speter 199918334Speter /* Do it without widening, if possible. */ 200018334Speter temp = expand_binop (mode, direct_optab, op0, op1, target, 200118334Speter unsignedp, OPTAB_DIRECT); 200218334Speter if (temp || methods == OPTAB_DIRECT) 200318334Speter return temp; 200418334Speter 200518334Speter /* Try widening to a signed int. Make a fake signed optab that 200618334Speter hides any signed insn for direct use. */ 200718334Speter wide_soptab = *soptab; 200818334Speter wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing; 200918334Speter wide_soptab.handlers[(int) mode].libfunc = 0; 201018334Speter 201118334Speter temp = expand_binop (mode, &wide_soptab, op0, op1, target, 201218334Speter unsignedp, OPTAB_WIDEN); 201318334Speter 201418334Speter /* For unsigned operands, try widening to an unsigned int. */ 201518334Speter if (temp == 0 && unsignedp) 201618334Speter temp = expand_binop (mode, uoptab, op0, op1, target, 201718334Speter unsignedp, OPTAB_WIDEN); 201818334Speter if (temp || methods == OPTAB_WIDEN) 201918334Speter return temp; 202018334Speter 202118334Speter /* Use the right width lib call if that exists. */ 202218334Speter temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB); 202318334Speter if (temp || methods == OPTAB_LIB) 202418334Speter return temp; 202518334Speter 202618334Speter /* Must widen and use a lib call, use either signed or unsigned. */ 202718334Speter temp = expand_binop (mode, &wide_soptab, op0, op1, target, 202818334Speter unsignedp, methods); 202918334Speter if (temp != 0) 203018334Speter return temp; 203118334Speter if (unsignedp) 203218334Speter return expand_binop (mode, uoptab, op0, op1, target, 203318334Speter unsignedp, methods); 203418334Speter return 0; 203518334Speter} 203618334Speter 2037169689Skan/* Generate code to perform an operation specified by UNOPPTAB 2038169689Skan on operand OP0, with two results to TARG0 and TARG1. 2039169689Skan We assume that the order of the operands for the instruction 2040169689Skan is TARG0, TARG1, OP0. 2041169689Skan 2042169689Skan Either TARG0 or TARG1 may be zero, but what that means is that 2043169689Skan the result is not actually wanted. We will generate it into 2044169689Skan a dummy pseudo-reg and discard it. They may not both be zero. 2045169689Skan 2046169689Skan Returns 1 if this operation can be performed; 0 if not. */ 2047169689Skan 2048169689Skanint 2049169689Skanexpand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1, 2050169689Skan int unsignedp) 2051169689Skan{ 2052169689Skan enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); 2053169689Skan enum mode_class class; 2054169689Skan enum machine_mode wider_mode; 2055169689Skan rtx entry_last = get_last_insn (); 2056169689Skan rtx last; 2057169689Skan 2058169689Skan class = GET_MODE_CLASS (mode); 2059169689Skan 2060169689Skan if (!targ0) 2061169689Skan targ0 = gen_reg_rtx (mode); 2062169689Skan if (!targ1) 2063169689Skan targ1 = gen_reg_rtx (mode); 2064169689Skan 2065169689Skan /* Record where to go back to if we fail. */ 2066169689Skan last = get_last_insn (); 2067169689Skan 2068169689Skan if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 2069169689Skan { 2070169689Skan int icode = (int) unoptab->handlers[(int) mode].insn_code; 2071169689Skan enum machine_mode mode0 = insn_data[icode].operand[2].mode; 2072169689Skan rtx pat; 2073169689Skan rtx xop0 = op0; 2074169689Skan 2075169689Skan if (GET_MODE (xop0) != VOIDmode 2076169689Skan && GET_MODE (xop0) != mode0) 2077169689Skan xop0 = convert_to_mode (mode0, xop0, unsignedp); 2078169689Skan 2079169689Skan /* Now, if insn doesn't accept these operands, put them into pseudos. */ 2080169689Skan if (!insn_data[icode].operand[2].predicate (xop0, mode0)) 2081169689Skan xop0 = copy_to_mode_reg (mode0, xop0); 2082169689Skan 2083169689Skan /* We could handle this, but we should always be called with a pseudo 2084169689Skan for our targets and all insns should take them as outputs. */ 2085169689Skan gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode)); 2086169689Skan gcc_assert (insn_data[icode].operand[1].predicate (targ1, mode)); 2087169689Skan 2088169689Skan pat = GEN_FCN (icode) (targ0, targ1, xop0); 2089169689Skan if (pat) 2090169689Skan { 2091169689Skan emit_insn (pat); 2092169689Skan return 1; 2093169689Skan } 2094169689Skan else 2095169689Skan delete_insns_since (last); 2096169689Skan } 2097169689Skan 2098169689Skan /* It can't be done in this mode. Can we do it in a wider mode? */ 2099169689Skan 2100169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 2101169689Skan { 2102169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2103169689Skan wider_mode != VOIDmode; 2104169689Skan wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 2105169689Skan { 2106169689Skan if (unoptab->handlers[(int) wider_mode].insn_code 2107169689Skan != CODE_FOR_nothing) 2108169689Skan { 2109169689Skan rtx t0 = gen_reg_rtx (wider_mode); 2110169689Skan rtx t1 = gen_reg_rtx (wider_mode); 2111169689Skan rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp); 2112169689Skan 2113169689Skan if (expand_twoval_unop (unoptab, cop0, t0, t1, unsignedp)) 2114169689Skan { 2115169689Skan convert_move (targ0, t0, unsignedp); 2116169689Skan convert_move (targ1, t1, unsignedp); 2117169689Skan return 1; 2118169689Skan } 2119169689Skan else 2120169689Skan delete_insns_since (last); 2121169689Skan } 2122169689Skan } 2123169689Skan } 2124169689Skan 2125169689Skan delete_insns_since (entry_last); 2126169689Skan return 0; 2127169689Skan} 2128169689Skan 212918334Speter/* Generate code to perform an operation specified by BINOPTAB 213018334Speter on operands OP0 and OP1, with two results to TARG1 and TARG2. 213118334Speter We assume that the order of the operands for the instruction 213218334Speter is TARG0, OP0, OP1, TARG1, which would fit a pattern like 213318334Speter [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))]. 213418334Speter 213518334Speter Either TARG0 or TARG1 may be zero, but what that means is that 213650397Sobrien the result is not actually wanted. We will generate it into 213718334Speter a dummy pseudo-reg and discard it. They may not both be zero. 213818334Speter 213918334Speter Returns 1 if this operation can be performed; 0 if not. */ 214018334Speter 214118334Speterint 2142132718Skanexpand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1, 2143132718Skan int unsignedp) 214418334Speter{ 214518334Speter enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); 214618334Speter enum mode_class class; 214718334Speter enum machine_mode wider_mode; 214818334Speter rtx entry_last = get_last_insn (); 214918334Speter rtx last; 215018334Speter 215118334Speter class = GET_MODE_CLASS (mode); 215218334Speter 2153169689Skan /* If we are inside an appropriately-short loop and we are optimizing, 2154169689Skan force expensive constants into a register. */ 2155169689Skan if (CONSTANT_P (op0) && optimize 215690075Sobrien && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1)) 215718334Speter op0 = force_reg (mode, op0); 215818334Speter 2159169689Skan if (CONSTANT_P (op1) && optimize 216090075Sobrien && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1)) 216118334Speter op1 = force_reg (mode, op1); 216218334Speter 2163169689Skan if (!targ0) 216418334Speter targ0 = gen_reg_rtx (mode); 2165169689Skan if (!targ1) 216618334Speter targ1 = gen_reg_rtx (mode); 216718334Speter 216818334Speter /* Record where to go back to if we fail. */ 216918334Speter last = get_last_insn (); 217018334Speter 217118334Speter if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 217218334Speter { 217318334Speter int icode = (int) binoptab->handlers[(int) mode].insn_code; 217490075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 217590075Sobrien enum machine_mode mode1 = insn_data[icode].operand[2].mode; 217618334Speter rtx pat; 217718334Speter rtx xop0 = op0, xop1 = op1; 217818334Speter 2179117395Skan /* In case the insn wants input operands in modes different from 2180117395Skan those of the actual operands, convert the operands. It would 2181117395Skan seem that we don't need to convert CONST_INTs, but we do, so 2182117395Skan that they're properly zero-extended, sign-extended or truncated 2183117395Skan for their mode. */ 218418334Speter 2185117395Skan if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) 2186117395Skan xop0 = convert_modes (mode0, 2187117395Skan GET_MODE (op0) != VOIDmode 2188117395Skan ? GET_MODE (op0) 2189117395Skan : mode, 2190117395Skan xop0, unsignedp); 219118334Speter 2192117395Skan if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) 2193117395Skan xop1 = convert_modes (mode1, 2194117395Skan GET_MODE (op1) != VOIDmode 2195117395Skan ? GET_MODE (op1) 2196117395Skan : mode, 2197117395Skan xop1, unsignedp); 2198117395Skan 219918334Speter /* Now, if insn doesn't accept these operands, put them into pseudos. */ 2200169689Skan if (!insn_data[icode].operand[1].predicate (xop0, mode0)) 220118334Speter xop0 = copy_to_mode_reg (mode0, xop0); 220218334Speter 2203169689Skan if (!insn_data[icode].operand[2].predicate (xop1, mode1)) 220418334Speter xop1 = copy_to_mode_reg (mode1, xop1); 220518334Speter 220618334Speter /* We could handle this, but we should always be called with a pseudo 220718334Speter for our targets and all insns should take them as outputs. */ 2208169689Skan gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode)); 2209169689Skan gcc_assert (insn_data[icode].operand[3].predicate (targ1, mode)); 2210132718Skan 221118334Speter pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1); 221218334Speter if (pat) 221318334Speter { 221418334Speter emit_insn (pat); 221518334Speter return 1; 221618334Speter } 221718334Speter else 221818334Speter delete_insns_since (last); 221918334Speter } 222018334Speter 222118334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 222218334Speter 2223169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 222418334Speter { 2225169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2226169689Skan wider_mode != VOIDmode; 222718334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 222818334Speter { 222918334Speter if (binoptab->handlers[(int) wider_mode].insn_code 223018334Speter != CODE_FOR_nothing) 223118334Speter { 223290075Sobrien rtx t0 = gen_reg_rtx (wider_mode); 223390075Sobrien rtx t1 = gen_reg_rtx (wider_mode); 223490075Sobrien rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp); 223590075Sobrien rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp); 223618334Speter 223790075Sobrien if (expand_twoval_binop (binoptab, cop0, cop1, 223818334Speter t0, t1, unsignedp)) 223918334Speter { 224018334Speter convert_move (targ0, t0, unsignedp); 224118334Speter convert_move (targ1, t1, unsignedp); 224218334Speter return 1; 224318334Speter } 224418334Speter else 224518334Speter delete_insns_since (last); 224618334Speter } 224718334Speter } 224818334Speter } 224918334Speter 225018334Speter delete_insns_since (entry_last); 225118334Speter return 0; 225218334Speter} 2253169689Skan 2254169689Skan/* Expand the two-valued library call indicated by BINOPTAB, but 2255169689Skan preserve only one of the values. If TARG0 is non-NULL, the first 2256169689Skan value is placed into TARG0; otherwise the second value is placed 2257169689Skan into TARG1. Exactly one of TARG0 and TARG1 must be non-NULL. The 2258169689Skan value stored into TARG0 or TARG1 is equivalent to (CODE OP0 OP1). 2259169689Skan This routine assumes that the value returned by the library call is 2260169689Skan as if the return value was of an integral mode twice as wide as the 2261169689Skan mode of OP0. Returns 1 if the call was successful. */ 2262169689Skan 2263169689Skanbool 2264169689Skanexpand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1, 2265169689Skan rtx targ0, rtx targ1, enum rtx_code code) 2266169689Skan{ 2267169689Skan enum machine_mode mode; 2268169689Skan enum machine_mode libval_mode; 2269169689Skan rtx libval; 2270169689Skan rtx insns; 2271169689Skan 2272169689Skan /* Exactly one of TARG0 or TARG1 should be non-NULL. */ 2273169689Skan gcc_assert (!targ0 != !targ1); 2274169689Skan 2275169689Skan mode = GET_MODE (op0); 2276169689Skan if (!binoptab->handlers[(int) mode].libfunc) 2277169689Skan return false; 2278169689Skan 2279169689Skan /* The value returned by the library function will have twice as 2280169689Skan many bits as the nominal MODE. */ 2281169689Skan libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode), 2282169689Skan MODE_INT); 2283169689Skan start_sequence (); 2284169689Skan libval = emit_library_call_value (binoptab->handlers[(int) mode].libfunc, 2285169689Skan NULL_RTX, LCT_CONST, 2286169689Skan libval_mode, 2, 2287169689Skan op0, mode, 2288169689Skan op1, mode); 2289169689Skan /* Get the part of VAL containing the value that we want. */ 2290169689Skan libval = simplify_gen_subreg (mode, libval, libval_mode, 2291169689Skan targ0 ? 0 : GET_MODE_SIZE (mode)); 2292169689Skan insns = get_insns (); 2293169689Skan end_sequence (); 2294169689Skan /* Move the into the desired location. */ 2295169689Skan emit_libcall_block (insns, targ0 ? targ0 : targ1, libval, 2296169689Skan gen_rtx_fmt_ee (code, mode, op0, op1)); 2297169689Skan 2298169689Skan return true; 2299169689Skan} 2300169689Skan 230118334Speter 230290075Sobrien/* Wrapper around expand_unop which takes an rtx code to specify 230390075Sobrien the operation to perform, not an optab pointer. All other 230490075Sobrien arguments are the same. */ 230590075Sobrienrtx 2306132718Skanexpand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0, 2307132718Skan rtx target, int unsignedp) 230890075Sobrien{ 2309117395Skan optab unop = code_to_optab[(int) code]; 2310169689Skan gcc_assert (unop); 231190075Sobrien 231290075Sobrien return expand_unop (mode, unop, op0, target, unsignedp); 231390075Sobrien} 231490075Sobrien 2315132718Skan/* Try calculating 2316132718Skan (clz:narrow x) 2317132718Skan as 2318132718Skan (clz:wide (zero_extend:wide x)) - ((width wide) - (width narrow)). */ 2319132718Skanstatic rtx 2320132718Skanwiden_clz (enum machine_mode mode, rtx op0, rtx target) 2321132718Skan{ 2322132718Skan enum mode_class class = GET_MODE_CLASS (mode); 2323169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 2324132718Skan { 2325132718Skan enum machine_mode wider_mode; 2326169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2327169689Skan wider_mode != VOIDmode; 2328132718Skan wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 2329132718Skan { 2330132718Skan if (clz_optab->handlers[(int) wider_mode].insn_code 2331132718Skan != CODE_FOR_nothing) 2332132718Skan { 2333132718Skan rtx xop0, temp, last; 2334132718Skan 2335132718Skan last = get_last_insn (); 2336132718Skan 2337132718Skan if (target == 0) 2338132718Skan target = gen_reg_rtx (mode); 2339132718Skan xop0 = widen_operand (op0, wider_mode, mode, true, false); 2340132718Skan temp = expand_unop (wider_mode, clz_optab, xop0, NULL_RTX, true); 2341132718Skan if (temp != 0) 2342132718Skan temp = expand_binop (wider_mode, sub_optab, temp, 2343132718Skan GEN_INT (GET_MODE_BITSIZE (wider_mode) 2344132718Skan - GET_MODE_BITSIZE (mode)), 2345132718Skan target, true, OPTAB_DIRECT); 2346132718Skan if (temp == 0) 2347132718Skan delete_insns_since (last); 2348132718Skan 2349132718Skan return temp; 2350132718Skan } 2351132718Skan } 2352132718Skan } 2353132718Skan return 0; 2354132718Skan} 2355132718Skan 2356132718Skan/* Try calculating (parity x) as (and (popcount x) 1), where 2357132718Skan popcount can also be done in a wider mode. */ 2358132718Skanstatic rtx 2359132718Skanexpand_parity (enum machine_mode mode, rtx op0, rtx target) 2360132718Skan{ 2361132718Skan enum mode_class class = GET_MODE_CLASS (mode); 2362169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 2363132718Skan { 2364132718Skan enum machine_mode wider_mode; 2365132718Skan for (wider_mode = mode; wider_mode != VOIDmode; 2366132718Skan wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 2367132718Skan { 2368132718Skan if (popcount_optab->handlers[(int) wider_mode].insn_code 2369132718Skan != CODE_FOR_nothing) 2370132718Skan { 2371132718Skan rtx xop0, temp, last; 2372132718Skan 2373132718Skan last = get_last_insn (); 2374132718Skan 2375132718Skan if (target == 0) 2376132718Skan target = gen_reg_rtx (mode); 2377132718Skan xop0 = widen_operand (op0, wider_mode, mode, true, false); 2378132718Skan temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX, 2379132718Skan true); 2380132718Skan if (temp != 0) 2381169689Skan temp = expand_binop (wider_mode, and_optab, temp, const1_rtx, 2382132718Skan target, true, OPTAB_DIRECT); 2383132718Skan if (temp == 0) 2384132718Skan delete_insns_since (last); 2385132718Skan 2386132718Skan return temp; 2387132718Skan } 2388132718Skan } 2389132718Skan } 2390132718Skan return 0; 2391132718Skan} 2392132718Skan 2393169689Skan/* Extract the OMODE lowpart from VAL, which has IMODE. Under certain 2394169689Skan conditions, VAL may already be a SUBREG against which we cannot generate 2395169689Skan a further SUBREG. In this case, we expect forcing the value into a 2396169689Skan register will work around the situation. */ 2397169689Skan 2398169689Skanstatic rtx 2399169689Skanlowpart_subreg_maybe_copy (enum machine_mode omode, rtx val, 2400169689Skan enum machine_mode imode) 2401169689Skan{ 2402169689Skan rtx ret; 2403169689Skan ret = lowpart_subreg (omode, val, imode); 2404169689Skan if (ret == NULL) 2405169689Skan { 2406169689Skan val = force_reg (imode, val); 2407169689Skan ret = lowpart_subreg (omode, val, imode); 2408169689Skan gcc_assert (ret != NULL); 2409169689Skan } 2410169689Skan return ret; 2411169689Skan} 2412169689Skan 2413169689Skan/* Expand a floating point absolute value or negation operation via a 2414169689Skan logical operation on the sign bit. */ 2415169689Skan 2416169689Skanstatic rtx 2417169689Skanexpand_absneg_bit (enum rtx_code code, enum machine_mode mode, 2418169689Skan rtx op0, rtx target) 2419169689Skan{ 2420169689Skan const struct real_format *fmt; 2421169689Skan int bitpos, word, nwords, i; 2422169689Skan enum machine_mode imode; 2423169689Skan HOST_WIDE_INT hi, lo; 2424169689Skan rtx temp, insns; 2425169689Skan 2426169689Skan /* The format has to have a simple sign bit. */ 2427169689Skan fmt = REAL_MODE_FORMAT (mode); 2428169689Skan if (fmt == NULL) 2429169689Skan return NULL_RTX; 2430169689Skan 2431169689Skan bitpos = fmt->signbit_rw; 2432169689Skan if (bitpos < 0) 2433169689Skan return NULL_RTX; 2434169689Skan 2435169689Skan /* Don't create negative zeros if the format doesn't support them. */ 2436169689Skan if (code == NEG && !fmt->has_signed_zero) 2437169689Skan return NULL_RTX; 2438169689Skan 2439169689Skan if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 2440169689Skan { 2441169689Skan imode = int_mode_for_mode (mode); 2442169689Skan if (imode == BLKmode) 2443169689Skan return NULL_RTX; 2444169689Skan word = 0; 2445169689Skan nwords = 1; 2446169689Skan } 2447169689Skan else 2448169689Skan { 2449169689Skan imode = word_mode; 2450169689Skan 2451169689Skan if (FLOAT_WORDS_BIG_ENDIAN) 2452169689Skan word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD; 2453169689Skan else 2454169689Skan word = bitpos / BITS_PER_WORD; 2455169689Skan bitpos = bitpos % BITS_PER_WORD; 2456169689Skan nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD; 2457169689Skan } 2458169689Skan 2459169689Skan if (bitpos < HOST_BITS_PER_WIDE_INT) 2460169689Skan { 2461169689Skan hi = 0; 2462169689Skan lo = (HOST_WIDE_INT) 1 << bitpos; 2463169689Skan } 2464169689Skan else 2465169689Skan { 2466169689Skan hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); 2467169689Skan lo = 0; 2468169689Skan } 2469169689Skan if (code == ABS) 2470169689Skan lo = ~lo, hi = ~hi; 2471169689Skan 2472169689Skan if (target == 0 || target == op0) 2473169689Skan target = gen_reg_rtx (mode); 2474169689Skan 2475169689Skan if (nwords > 1) 2476169689Skan { 2477169689Skan start_sequence (); 2478169689Skan 2479169689Skan for (i = 0; i < nwords; ++i) 2480169689Skan { 2481169689Skan rtx targ_piece = operand_subword (target, i, 1, mode); 2482169689Skan rtx op0_piece = operand_subword_force (op0, i, mode); 2483169689Skan 2484169689Skan if (i == word) 2485169689Skan { 2486169689Skan temp = expand_binop (imode, code == ABS ? and_optab : xor_optab, 2487169689Skan op0_piece, 2488169689Skan immed_double_const (lo, hi, imode), 2489169689Skan targ_piece, 1, OPTAB_LIB_WIDEN); 2490169689Skan if (temp != targ_piece) 2491169689Skan emit_move_insn (targ_piece, temp); 2492169689Skan } 2493169689Skan else 2494169689Skan emit_move_insn (targ_piece, op0_piece); 2495169689Skan } 2496169689Skan 2497169689Skan insns = get_insns (); 2498169689Skan end_sequence (); 2499169689Skan 2500169689Skan temp = gen_rtx_fmt_e (code, mode, copy_rtx (op0)); 2501169689Skan emit_no_conflict_block (insns, target, op0, NULL_RTX, temp); 2502169689Skan } 2503169689Skan else 2504169689Skan { 2505169689Skan temp = expand_binop (imode, code == ABS ? and_optab : xor_optab, 2506169689Skan gen_lowpart (imode, op0), 2507169689Skan immed_double_const (lo, hi, imode), 2508169689Skan gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN); 2509169689Skan target = lowpart_subreg_maybe_copy (mode, temp, imode); 2510169689Skan 2511169689Skan set_unique_reg_note (get_last_insn (), REG_EQUAL, 2512169689Skan gen_rtx_fmt_e (code, mode, copy_rtx (op0))); 2513169689Skan } 2514169689Skan 2515169689Skan return target; 2516169689Skan} 2517169689Skan 251818334Speter/* Generate code to perform an operation specified by UNOPTAB 251918334Speter on operand OP0, with result having machine-mode MODE. 252018334Speter 252118334Speter UNSIGNEDP is for the case where we have to widen the operands 252218334Speter to perform the operation. It says to use zero-extension. 252318334Speter 252418334Speter If TARGET is nonzero, the value 252518334Speter is generated there, if it is convenient to do so. 252618334Speter In all cases an rtx is returned for the locus of the value; 252718334Speter this may or may not be TARGET. */ 252818334Speter 252918334Speterrtx 2530132718Skanexpand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, 2531132718Skan int unsignedp) 253218334Speter{ 253318334Speter enum mode_class class; 253418334Speter enum machine_mode wider_mode; 253590075Sobrien rtx temp; 253618334Speter rtx last = get_last_insn (); 253718334Speter rtx pat; 253818334Speter 253918334Speter class = GET_MODE_CLASS (mode); 254018334Speter 254118334Speter if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 254218334Speter { 254318334Speter int icode = (int) unoptab->handlers[(int) mode].insn_code; 254490075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 254518334Speter rtx xop0 = op0; 254618334Speter 254718334Speter if (target) 254818334Speter temp = target; 254918334Speter else 255018334Speter temp = gen_reg_rtx (mode); 255118334Speter 255218334Speter if (GET_MODE (xop0) != VOIDmode 255318334Speter && GET_MODE (xop0) != mode0) 255418334Speter xop0 = convert_to_mode (mode0, xop0, unsignedp); 255518334Speter 255618334Speter /* Now, if insn doesn't accept our operand, put it into a pseudo. */ 255718334Speter 2558169689Skan if (!insn_data[icode].operand[1].predicate (xop0, mode0)) 255918334Speter xop0 = copy_to_mode_reg (mode0, xop0); 256018334Speter 2561169689Skan if (!insn_data[icode].operand[0].predicate (temp, mode)) 256218334Speter temp = gen_reg_rtx (mode); 256318334Speter 256418334Speter pat = GEN_FCN (icode) (temp, xop0); 256518334Speter if (pat) 256618334Speter { 2567117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX 256818334Speter && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX)) 256918334Speter { 257018334Speter delete_insns_since (last); 257118334Speter return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp); 257218334Speter } 257318334Speter 257418334Speter emit_insn (pat); 2575132718Skan 257618334Speter return temp; 257718334Speter } 257818334Speter else 257918334Speter delete_insns_since (last); 258018334Speter } 258118334Speter 258218334Speter /* It can't be done in this mode. Can we open-code it in a wider mode? */ 258318334Speter 2584132718Skan /* Widening clz needs special treatment. */ 2585132718Skan if (unoptab == clz_optab) 2586132718Skan { 2587132718Skan temp = widen_clz (mode, op0, target); 2588132718Skan if (temp) 2589132718Skan return temp; 2590132718Skan else 2591132718Skan goto try_libcall; 2592132718Skan } 2593132718Skan 2594169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 2595169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2596169689Skan wider_mode != VOIDmode; 259718334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 259818334Speter { 259918334Speter if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) 260018334Speter { 260118334Speter rtx xop0 = op0; 260218334Speter 260318334Speter /* For certain operations, we need not actually extend 260418334Speter the narrow operand, as long as we will truncate the 260518334Speter results to the same narrowness. */ 260618334Speter 260718334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 260818334Speter (unoptab == neg_optab 260918334Speter || unoptab == one_cmpl_optab) 261018334Speter && class == MODE_INT); 2611132718Skan 261218334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 261318334Speter unsignedp); 261418334Speter 261518334Speter if (temp) 261618334Speter { 2617169689Skan if (class != MODE_INT 2618169689Skan || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), 2619169689Skan GET_MODE_BITSIZE (wider_mode))) 262018334Speter { 262118334Speter if (target == 0) 262218334Speter target = gen_reg_rtx (mode); 262318334Speter convert_move (target, temp, 0); 262418334Speter return target; 262518334Speter } 262618334Speter else 262718334Speter return gen_lowpart (mode, temp); 262818334Speter } 262918334Speter else 263018334Speter delete_insns_since (last); 263118334Speter } 263218334Speter } 263318334Speter 263418334Speter /* These can be done a word at a time. */ 263518334Speter if (unoptab == one_cmpl_optab 263618334Speter && class == MODE_INT 263718334Speter && GET_MODE_SIZE (mode) > UNITS_PER_WORD 263818334Speter && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) 263918334Speter { 264018334Speter int i; 264118334Speter rtx insns; 264218334Speter 264318334Speter if (target == 0 || target == op0) 264418334Speter target = gen_reg_rtx (mode); 264518334Speter 264618334Speter start_sequence (); 264718334Speter 264818334Speter /* Do the actual arithmetic. */ 264918334Speter for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) 265018334Speter { 265118334Speter rtx target_piece = operand_subword (target, i, 1, mode); 265218334Speter rtx x = expand_unop (word_mode, unoptab, 265318334Speter operand_subword_force (op0, i, mode), 265418334Speter target_piece, unsignedp); 265590075Sobrien 265618334Speter if (target_piece != x) 265718334Speter emit_move_insn (target_piece, x); 265818334Speter } 265918334Speter 266018334Speter insns = get_insns (); 266118334Speter end_sequence (); 266218334Speter 266318334Speter emit_no_conflict_block (insns, target, op0, NULL_RTX, 266450397Sobrien gen_rtx_fmt_e (unoptab->code, mode, 266550397Sobrien copy_rtx (op0))); 266618334Speter return target; 266718334Speter } 266818334Speter 2669169689Skan if (unoptab->code == NEG) 267018334Speter { 2671169689Skan /* Try negating floating point values by flipping the sign bit. */ 2672169689Skan if (SCALAR_FLOAT_MODE_P (mode)) 2673169689Skan { 2674169689Skan temp = expand_absneg_bit (NEG, mode, op0, target); 2675169689Skan if (temp) 2676169689Skan return temp; 2677169689Skan } 267818334Speter 2679169689Skan /* If there is no negation pattern, and we have no negative zero, 2680169689Skan try subtracting from zero. */ 2681169689Skan if (!HONOR_SIGNED_ZEROS (mode)) 2682132718Skan { 2683169689Skan temp = expand_binop (mode, (unoptab == negv_optab 2684169689Skan ? subv_optab : sub_optab), 2685169689Skan CONST0_RTX (mode), op0, target, 2686169689Skan unsignedp, OPTAB_DIRECT); 2687169689Skan if (temp) 2688169689Skan return temp; 2689169689Skan } 2690132718Skan } 2691132718Skan 2692132718Skan /* Try calculating parity (x) as popcount (x) % 2. */ 2693132718Skan if (unoptab == parity_optab) 2694132718Skan { 2695132718Skan temp = expand_parity (mode, op0, target); 2696132718Skan if (temp) 2697132718Skan return temp; 2698132718Skan } 2699132718Skan 2700132718Skan try_libcall: 270118334Speter /* Now try a library call in this mode. */ 270218334Speter if (unoptab->handlers[(int) mode].libfunc) 270318334Speter { 270418334Speter rtx insns; 270518334Speter rtx value; 2706132718Skan enum machine_mode outmode = mode; 270718334Speter 2708132718Skan /* All of these functions return small values. Thus we choose to 2709132718Skan have them return something that isn't a double-word. */ 2710132718Skan if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab 2711132718Skan || unoptab == popcount_optab || unoptab == parity_optab) 2712132718Skan outmode 2713132718Skan = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node))); 2714132718Skan 271518334Speter start_sequence (); 271618334Speter 271718334Speter /* Pass 1 for NO_QUEUE so we don't lose any increments 271818334Speter if the libcall is cse'd or moved. */ 271918334Speter value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc, 2720132718Skan NULL_RTX, LCT_CONST, outmode, 2721132718Skan 1, op0, mode); 272218334Speter insns = get_insns (); 272318334Speter end_sequence (); 272418334Speter 2725132718Skan target = gen_reg_rtx (outmode); 272618334Speter emit_libcall_block (insns, target, value, 2727169689Skan gen_rtx_fmt_e (unoptab->code, outmode, op0)); 272818334Speter 272918334Speter return target; 273018334Speter } 273118334Speter 273218334Speter /* It can't be done in this mode. Can we do it in a wider mode? */ 273318334Speter 2734169689Skan if (CLASS_HAS_WIDER_MODES_P (class)) 273518334Speter { 2736169689Skan for (wider_mode = GET_MODE_WIDER_MODE (mode); 2737169689Skan wider_mode != VOIDmode; 273818334Speter wider_mode = GET_MODE_WIDER_MODE (wider_mode)) 273918334Speter { 274018334Speter if ((unoptab->handlers[(int) wider_mode].insn_code 274118334Speter != CODE_FOR_nothing) 274218334Speter || unoptab->handlers[(int) wider_mode].libfunc) 274318334Speter { 274418334Speter rtx xop0 = op0; 274518334Speter 274618334Speter /* For certain operations, we need not actually extend 274718334Speter the narrow operand, as long as we will truncate the 274818334Speter results to the same narrowness. */ 274918334Speter 275018334Speter xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, 275118334Speter (unoptab == neg_optab 275218334Speter || unoptab == one_cmpl_optab) 275318334Speter && class == MODE_INT); 2754132718Skan 275518334Speter temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, 275618334Speter unsignedp); 275718334Speter 2758132718Skan /* If we are generating clz using wider mode, adjust the 2759132718Skan result. */ 2760132718Skan if (unoptab == clz_optab && temp != 0) 2761132718Skan temp = expand_binop (wider_mode, sub_optab, temp, 2762132718Skan GEN_INT (GET_MODE_BITSIZE (wider_mode) 2763132718Skan - GET_MODE_BITSIZE (mode)), 2764132718Skan target, true, OPTAB_DIRECT); 2765132718Skan 276618334Speter if (temp) 276718334Speter { 276818334Speter if (class != MODE_INT) 276918334Speter { 277018334Speter if (target == 0) 277118334Speter target = gen_reg_rtx (mode); 277218334Speter convert_move (target, temp, 0); 277318334Speter return target; 277418334Speter } 277518334Speter else 277618334Speter return gen_lowpart (mode, temp); 277718334Speter } 277818334Speter else 277918334Speter delete_insns_since (last); 278018334Speter } 278118334Speter } 278218334Speter } 278318334Speter 2784169689Skan /* One final attempt at implementing negation via subtraction, 2785169689Skan this time allowing widening of the operand. */ 2786169689Skan if (unoptab->code == NEG && !HONOR_SIGNED_ZEROS (mode)) 2787132718Skan { 278818334Speter rtx temp; 278990075Sobrien temp = expand_binop (mode, 279090075Sobrien unoptab == negv_optab ? subv_optab : sub_optab, 279190075Sobrien CONST0_RTX (mode), op0, 279290075Sobrien target, unsignedp, OPTAB_LIB_WIDEN); 279318334Speter if (temp) 2794169689Skan return temp; 279518334Speter } 2796132718Skan 279718334Speter return 0; 279818334Speter} 279918334Speter 280018334Speter/* Emit code to compute the absolute value of OP0, with result to 280118334Speter TARGET if convenient. (TARGET may be 0.) The return value says 280218334Speter where the result actually is to be found. 280318334Speter 280418334Speter MODE is the mode of the operand; the mode of the result is 280518334Speter different but can be deduced from MODE. 280618334Speter 280752284Sobrien */ 280818334Speter 280918334Speterrtx 2810132718Skanexpand_abs_nojump (enum machine_mode mode, rtx op0, rtx target, 2811132718Skan int result_unsignedp) 281218334Speter{ 2813132718Skan rtx temp; 281418334Speter 281590075Sobrien if (! flag_trapv) 281690075Sobrien result_unsignedp = 1; 281790075Sobrien 281818334Speter /* First try to do it with a special abs instruction. */ 281990075Sobrien temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab, 282090075Sobrien op0, target, 0); 282118334Speter if (temp != 0) 282218334Speter return temp; 282318334Speter 2824132718Skan /* For floating point modes, try clearing the sign bit. */ 2825169689Skan if (SCALAR_FLOAT_MODE_P (mode)) 2826132718Skan { 2827169689Skan temp = expand_absneg_bit (ABS, mode, op0, target); 2828169689Skan if (temp) 2829169689Skan return temp; 2830132718Skan } 2831132718Skan 283290075Sobrien /* If we have a MAX insn, we can do this as MAX (x, -x). */ 2833169689Skan if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing 2834169689Skan && !HONOR_SIGNED_ZEROS (mode)) 283590075Sobrien { 283690075Sobrien rtx last = get_last_insn (); 283790075Sobrien 283890075Sobrien temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0); 283990075Sobrien if (temp != 0) 284090075Sobrien temp = expand_binop (mode, smax_optab, op0, temp, target, 0, 284190075Sobrien OPTAB_WIDEN); 284290075Sobrien 284390075Sobrien if (temp != 0) 284490075Sobrien return temp; 284590075Sobrien 284690075Sobrien delete_insns_since (last); 284790075Sobrien } 284890075Sobrien 284918334Speter /* If this machine has expensive jumps, we can do integer absolute 285018334Speter value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)), 285118334Speter where W is the width of MODE. */ 285218334Speter 285318334Speter if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2) 285418334Speter { 285518334Speter rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, 285618334Speter size_int (GET_MODE_BITSIZE (mode) - 1), 285718334Speter NULL_RTX, 0); 285818334Speter 285918334Speter temp = expand_binop (mode, xor_optab, extended, op0, target, 0, 286018334Speter OPTAB_LIB_WIDEN); 286118334Speter if (temp != 0) 286290075Sobrien temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab, 286390075Sobrien temp, extended, target, 0, OPTAB_LIB_WIDEN); 286418334Speter 286518334Speter if (temp != 0) 286618334Speter return temp; 286718334Speter } 286818334Speter 2869132718Skan return NULL_RTX; 2870132718Skan} 2871132718Skan 2872132718Skanrtx 2873132718Skanexpand_abs (enum machine_mode mode, rtx op0, rtx target, 2874132718Skan int result_unsignedp, int safe) 2875132718Skan{ 2876132718Skan rtx temp, op1; 2877132718Skan 2878132718Skan if (! flag_trapv) 2879132718Skan result_unsignedp = 1; 2880132718Skan 2881132718Skan temp = expand_abs_nojump (mode, op0, target, result_unsignedp); 2882132718Skan if (temp != 0) 2883132718Skan return temp; 2884132718Skan 288518334Speter /* If that does not win, use conditional jump and negate. */ 288650397Sobrien 288750397Sobrien /* It is safe to use the target if it is the same 288850397Sobrien as the source if this is also a pseudo register */ 2889169689Skan if (op0 == target && REG_P (op0) 289050397Sobrien && REGNO (op0) >= FIRST_PSEUDO_REGISTER) 289150397Sobrien safe = 1; 289250397Sobrien 289318334Speter op1 = gen_label_rtx (); 289418334Speter if (target == 0 || ! safe 289518334Speter || GET_MODE (target) != mode 2896169689Skan || (MEM_P (target) && MEM_VOLATILE_P (target)) 2897169689Skan || (REG_P (target) 289818334Speter && REGNO (target) < FIRST_PSEUDO_REGISTER)) 289918334Speter target = gen_reg_rtx (mode); 290018334Speter 290118334Speter emit_move_insn (target, op0); 290218334Speter NO_DEFER_POP; 290318334Speter 2904169689Skan do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, 2905169689Skan NULL_RTX, NULL_RTX, op1); 290618334Speter 290790075Sobrien op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab, 290890075Sobrien target, target, 0); 290918334Speter if (op0 != target) 291018334Speter emit_move_insn (target, op0); 291118334Speter emit_label (op1); 291218334Speter OK_DEFER_POP; 291318334Speter return target; 291418334Speter} 291518334Speter 2916169689Skan/* A subroutine of expand_copysign, perform the copysign operation using the 2917169689Skan abs and neg primitives advertised to exist on the target. The assumption 2918169689Skan is that we have a split register file, and leaving op0 in fp registers, 2919169689Skan and not playing with subregs so much, will help the register allocator. */ 292018334Speter 2921169689Skanstatic rtx 2922169689Skanexpand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target, 2923169689Skan int bitpos, bool op0_is_abs) 292418334Speter{ 2925169689Skan enum machine_mode imode; 2926169689Skan HOST_WIDE_INT hi, lo; 2927169689Skan int word; 2928169689Skan rtx label; 292918334Speter 2930169689Skan if (target == op1) 2931169689Skan target = NULL_RTX; 293218334Speter 2933169689Skan if (!op0_is_abs) 2934169689Skan { 2935169689Skan op0 = expand_unop (mode, abs_optab, op0, target, 0); 2936169689Skan if (op0 == NULL) 2937169689Skan return NULL_RTX; 2938169689Skan target = op0; 2939169689Skan } 2940169689Skan else 2941169689Skan { 2942169689Skan if (target == NULL_RTX) 2943169689Skan target = copy_to_reg (op0); 2944169689Skan else 2945169689Skan emit_move_insn (target, op0); 2946169689Skan } 294718334Speter 2948169689Skan if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 2949169689Skan { 2950169689Skan imode = int_mode_for_mode (mode); 2951169689Skan if (imode == BLKmode) 2952169689Skan return NULL_RTX; 2953169689Skan op1 = gen_lowpart (imode, op1); 2954169689Skan } 2955169689Skan else 2956169689Skan { 2957169689Skan imode = word_mode; 2958169689Skan if (FLOAT_WORDS_BIG_ENDIAN) 2959169689Skan word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD; 2960169689Skan else 2961169689Skan word = bitpos / BITS_PER_WORD; 2962169689Skan bitpos = bitpos % BITS_PER_WORD; 2963169689Skan op1 = operand_subword_force (op1, word, mode); 2964169689Skan } 296518334Speter 2966169689Skan if (bitpos < HOST_BITS_PER_WIDE_INT) 296718334Speter { 2968169689Skan hi = 0; 2969169689Skan lo = (HOST_WIDE_INT) 1 << bitpos; 297018334Speter } 2971169689Skan else 2972169689Skan { 2973169689Skan hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); 2974169689Skan lo = 0; 2975169689Skan } 297618334Speter 2977169689Skan op1 = expand_binop (imode, and_optab, op1, 2978169689Skan immed_double_const (lo, hi, imode), 2979169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 298018334Speter 2981169689Skan label = gen_label_rtx (); 2982169689Skan emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, imode, 1, label); 298318334Speter 2984169689Skan if (GET_CODE (op0) == CONST_DOUBLE) 2985169689Skan op0 = simplify_unary_operation (NEG, mode, op0, mode); 2986169689Skan else 2987169689Skan op0 = expand_unop (mode, neg_optab, op0, target, 0); 2988169689Skan if (op0 != target) 2989169689Skan emit_move_insn (target, op0); 299090075Sobrien 2991169689Skan emit_label (label); 299218334Speter 2993169689Skan return target; 2994169689Skan} 299518334Speter 299618334Speter 2997169689Skan/* A subroutine of expand_copysign, perform the entire copysign operation 2998169689Skan with integer bitmasks. BITPOS is the position of the sign bit; OP0_IS_ABS 2999169689Skan is true if op0 is known to have its sign bit clear. */ 300018334Speter 3001169689Skanstatic rtx 3002169689Skanexpand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target, 3003169689Skan int bitpos, bool op0_is_abs) 3004169689Skan{ 3005169689Skan enum machine_mode imode; 3006169689Skan HOST_WIDE_INT hi, lo; 3007169689Skan int word, nwords, i; 3008169689Skan rtx temp, insns; 300918334Speter 3010169689Skan if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) 3011169689Skan { 3012169689Skan imode = int_mode_for_mode (mode); 3013169689Skan if (imode == BLKmode) 3014169689Skan return NULL_RTX; 3015169689Skan word = 0; 3016169689Skan nwords = 1; 3017169689Skan } 3018169689Skan else 3019169689Skan { 3020169689Skan imode = word_mode; 302118334Speter 3022169689Skan if (FLOAT_WORDS_BIG_ENDIAN) 3023169689Skan word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD; 302418334Speter else 3025169689Skan word = bitpos / BITS_PER_WORD; 3026169689Skan bitpos = bitpos % BITS_PER_WORD; 3027169689Skan nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD; 302818334Speter } 302918334Speter 3030169689Skan if (bitpos < HOST_BITS_PER_WIDE_INT) 3031169689Skan { 3032169689Skan hi = 0; 3033169689Skan lo = (HOST_WIDE_INT) 1 << bitpos; 3034169689Skan } 3035169689Skan else 3036169689Skan { 3037169689Skan hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); 3038169689Skan lo = 0; 3039169689Skan } 304018334Speter 3041169689Skan if (target == 0 || target == op0 || target == op1) 3042169689Skan target = gen_reg_rtx (mode); 3043169689Skan 3044169689Skan if (nwords > 1) 304518334Speter { 3046169689Skan start_sequence (); 3047169689Skan 3048169689Skan for (i = 0; i < nwords; ++i) 304918334Speter { 3050169689Skan rtx targ_piece = operand_subword (target, i, 1, mode); 3051169689Skan rtx op0_piece = operand_subword_force (op0, i, mode); 305218334Speter 3053169689Skan if (i == word) 3054169689Skan { 3055169689Skan if (!op0_is_abs) 3056169689Skan op0_piece = expand_binop (imode, and_optab, op0_piece, 3057169689Skan immed_double_const (~lo, ~hi, imode), 3058169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 305918334Speter 3060169689Skan op1 = expand_binop (imode, and_optab, 3061169689Skan operand_subword_force (op1, i, mode), 3062169689Skan immed_double_const (lo, hi, imode), 3063169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 3064169689Skan 3065169689Skan temp = expand_binop (imode, ior_optab, op0_piece, op1, 3066169689Skan targ_piece, 1, OPTAB_LIB_WIDEN); 3067169689Skan if (temp != targ_piece) 3068169689Skan emit_move_insn (targ_piece, temp); 306918334Speter } 307018334Speter else 3071169689Skan emit_move_insn (targ_piece, op0_piece); 307218334Speter } 3073169689Skan 3074169689Skan insns = get_insns (); 3075169689Skan end_sequence (); 3076169689Skan 3077169689Skan emit_no_conflict_block (insns, target, op0, op1, NULL_RTX); 307818334Speter } 3079169689Skan else 308018334Speter { 3081169689Skan op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1), 3082169689Skan immed_double_const (lo, hi, imode), 3083169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 308418334Speter 3085169689Skan op0 = gen_lowpart (imode, op0); 3086169689Skan if (!op0_is_abs) 3087169689Skan op0 = expand_binop (imode, and_optab, op0, 3088169689Skan immed_double_const (~lo, ~hi, imode), 3089169689Skan NULL_RTX, 1, OPTAB_LIB_WIDEN); 309018334Speter 3091169689Skan temp = expand_binop (imode, ior_optab, op0, op1, 3092169689Skan gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN); 3093169689Skan target = lowpart_subreg_maybe_copy (mode, temp, imode); 3094169689Skan } 309518334Speter 3096169689Skan return target; 3097169689Skan} 309818334Speter 3099169689Skan/* Expand the C99 copysign operation. OP0 and OP1 must be the same 3100169689Skan scalar floating point mode. Return NULL if we do not know how to 3101169689Skan expand the operation inline. */ 310218334Speter 3103169689Skanrtx 3104169689Skanexpand_copysign (rtx op0, rtx op1, rtx target) 3105169689Skan{ 3106169689Skan enum machine_mode mode = GET_MODE (op0); 3107169689Skan const struct real_format *fmt; 3108169689Skan bool op0_is_abs; 3109169689Skan rtx temp; 311018334Speter 3111169689Skan gcc_assert (SCALAR_FLOAT_MODE_P (mode)); 3112169689Skan gcc_assert (GET_MODE (op1) == mode); 311318334Speter 3114169689Skan /* First try to do it with a special instruction. */ 3115169689Skan temp = expand_binop (mode, copysign_optab, op0, op1, 3116169689Skan target, 0, OPTAB_DIRECT); 3117169689Skan if (temp) 3118169689Skan return temp; 311918334Speter 3120169689Skan fmt = REAL_MODE_FORMAT (mode); 3121169689Skan if (fmt == NULL || !fmt->has_signed_zero) 3122169689Skan return NULL_RTX; 312318334Speter 3124169689Skan op0_is_abs = false; 3125169689Skan if (GET_CODE (op0) == CONST_DOUBLE) 3126169689Skan { 3127169689Skan if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0))) 3128169689Skan op0 = simplify_unary_operation (ABS, mode, op0, mode); 3129169689Skan op0_is_abs = true; 313018334Speter } 313118334Speter 3132169689Skan if (fmt->signbit_ro >= 0 3133169689Skan && (GET_CODE (op0) == CONST_DOUBLE 3134169689Skan || (neg_optab->handlers[mode].insn_code != CODE_FOR_nothing 3135169689Skan && abs_optab->handlers[mode].insn_code != CODE_FOR_nothing))) 313618334Speter { 3137169689Skan temp = expand_copysign_absneg (mode, op0, op1, target, 3138169689Skan fmt->signbit_ro, op0_is_abs); 3139169689Skan if (temp) 3140169689Skan return temp; 314118334Speter } 314218334Speter 3143169689Skan if (fmt->signbit_rw < 0) 3144169689Skan return NULL_RTX; 3145169689Skan return expand_copysign_bit (mode, op0, op1, target, 3146169689Skan fmt->signbit_rw, op0_is_abs); 314718334Speter} 314818334Speter 314918334Speter/* Generate an instruction whose insn-code is INSN_CODE, 315018334Speter with two operands: an output TARGET and an input OP0. 315118334Speter TARGET *must* be nonzero, and the output is always stored there. 315218334Speter CODE is an rtx code such that (CODE OP0) is an rtx that describes 315318334Speter the value that is stored into TARGET. */ 315418334Speter 315518334Spetervoid 3156132718Skanemit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code) 315718334Speter{ 315890075Sobrien rtx temp; 315990075Sobrien enum machine_mode mode0 = insn_data[icode].operand[1].mode; 316018334Speter rtx pat; 316118334Speter 3162169689Skan temp = target; 316318334Speter 316418334Speter /* Now, if insn does not accept our operands, put them into pseudos. */ 316518334Speter 3166169689Skan if (!insn_data[icode].operand[1].predicate (op0, mode0)) 316718334Speter op0 = copy_to_mode_reg (mode0, op0); 316818334Speter 3169169689Skan if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp))) 317018334Speter temp = gen_reg_rtx (GET_MODE (temp)); 317118334Speter 317218334Speter pat = GEN_FCN (icode) (temp, op0); 317318334Speter 3174117395Skan if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN) 317518334Speter add_equal_note (pat, temp, code, op0, NULL_RTX); 3176132718Skan 317718334Speter emit_insn (pat); 317818334Speter 317918334Speter if (temp != target) 318018334Speter emit_move_insn (target, temp); 318118334Speter} 318218334Speter 3183169689Skanstruct no_conflict_data 3184169689Skan{ 3185169689Skan rtx target, first, insn; 3186169689Skan bool must_stay; 3187169689Skan}; 3188169689Skan 3189169689Skan/* Called via note_stores by emit_no_conflict_block and emit_libcall_block. 3190169689Skan Set P->must_stay if the currently examined clobber / store has to stay 3191169689Skan in the list of insns that constitute the actual no_conflict block / 3192169689Skan libcall block. */ 3193169689Skanstatic void 3194169689Skanno_conflict_move_test (rtx dest, rtx set, void *p0) 3195169689Skan{ 3196169689Skan struct no_conflict_data *p= p0; 3197169689Skan 3198169689Skan /* If this inns directly contributes to setting the target, it must stay. */ 3199169689Skan if (reg_overlap_mentioned_p (p->target, dest)) 3200169689Skan p->must_stay = true; 3201169689Skan /* If we haven't committed to keeping any other insns in the list yet, 3202169689Skan there is nothing more to check. */ 3203169689Skan else if (p->insn == p->first) 3204169689Skan return; 3205169689Skan /* If this insn sets / clobbers a register that feeds one of the insns 3206169689Skan already in the list, this insn has to stay too. */ 3207169689Skan else if (reg_overlap_mentioned_p (dest, PATTERN (p->first)) 3208169689Skan || (CALL_P (p->first) && (find_reg_fusage (p->first, USE, dest))) 3209169689Skan || reg_used_between_p (dest, p->first, p->insn) 3210169689Skan /* Likewise if this insn depends on a register set by a previous 3211169689Skan insn in the list, or if it sets a result (presumably a hard 3212169689Skan register) that is set or clobbered by a previous insn. 3213169689Skan N.B. the modified_*_p (SET_DEST...) tests applied to a MEM 3214169689Skan SET_DEST perform the former check on the address, and the latter 3215169689Skan check on the MEM. */ 3216169689Skan || (GET_CODE (set) == SET 3217169689Skan && (modified_in_p (SET_SRC (set), p->first) 3218169689Skan || modified_in_p (SET_DEST (set), p->first) 3219169689Skan || modified_between_p (SET_SRC (set), p->first, p->insn) 3220169689Skan || modified_between_p (SET_DEST (set), p->first, p->insn)))) 3221169689Skan p->must_stay = true; 3222169689Skan} 3223169689Skan 3224169689Skan/* Encapsulate the block starting at FIRST and ending with LAST, which is 3225169689Skan logically equivalent to EQUIV, so it gets manipulated as a unit if it 3226169689Skan is possible to do so. */ 3227169689Skan 3228169689Skanstatic void 3229169689Skanmaybe_encapsulate_block (rtx first, rtx last, rtx equiv) 3230169689Skan{ 3231169689Skan if (!flag_non_call_exceptions || !may_trap_p (equiv)) 3232169689Skan { 3233169689Skan /* We can't attach the REG_LIBCALL and REG_RETVAL notes when the 3234169689Skan encapsulated region would not be in one basic block, i.e. when 3235169689Skan there is a control_flow_insn_p insn between FIRST and LAST. */ 3236169689Skan bool attach_libcall_retval_notes = true; 3237169689Skan rtx insn, next = NEXT_INSN (last); 3238169689Skan 3239169689Skan for (insn = first; insn != next; insn = NEXT_INSN (insn)) 3240169689Skan if (control_flow_insn_p (insn)) 3241169689Skan { 3242169689Skan attach_libcall_retval_notes = false; 3243169689Skan break; 3244169689Skan } 3245169689Skan 3246169689Skan if (attach_libcall_retval_notes) 3247169689Skan { 3248169689Skan REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, 3249169689Skan REG_NOTES (first)); 3250169689Skan REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, 3251169689Skan REG_NOTES (last)); 3252169689Skan } 3253169689Skan } 3254169689Skan} 3255169689Skan 325618334Speter/* Emit code to perform a series of operations on a multi-word quantity, one 325718334Speter word at a time. 325818334Speter 325918334Speter Such a block is preceded by a CLOBBER of the output, consists of multiple 326018334Speter insns, each setting one word of the output, and followed by a SET copying 326118334Speter the output to itself. 326218334Speter 326318334Speter Each of the insns setting words of the output receives a REG_NO_CONFLICT 326418334Speter note indicating that it doesn't conflict with the (also multi-word) 326518334Speter inputs. The entire block is surrounded by REG_LIBCALL and REG_RETVAL 326618334Speter notes. 326718334Speter 326818334Speter INSNS is a block of code generated to perform the operation, not including 326918334Speter the CLOBBER and final copy. All insns that compute intermediate values 3270132718Skan are first emitted, followed by the block as described above. 327118334Speter 327218334Speter TARGET, OP0, and OP1 are the output and inputs of the operations, 327318334Speter respectively. OP1 may be zero for a unary operation. 327418334Speter 3275117395Skan EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note 327618334Speter on the last insn. 327718334Speter 327818334Speter If TARGET is not a register, INSNS is simply emitted with no special 327918334Speter processing. Likewise if anything in INSNS is not an INSN or if 328018334Speter there is a libcall block inside INSNS. 328118334Speter 328218334Speter The final insn emitted is returned. */ 328318334Speter 328418334Speterrtx 3285132718Skanemit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv) 328618334Speter{ 328718334Speter rtx prev, next, first, last, insn; 328818334Speter 3289169689Skan if (!REG_P (target) || reload_in_progress) 3290117395Skan return emit_insn (insns); 329118334Speter else 329218334Speter for (insn = insns; insn; insn = NEXT_INSN (insn)) 3293169689Skan if (!NONJUMP_INSN_P (insn) 329418334Speter || find_reg_note (insn, REG_LIBCALL, NULL_RTX)) 3295117395Skan return emit_insn (insns); 329618334Speter 329718334Speter /* First emit all insns that do not store into words of the output and remove 329818334Speter these from the list. */ 329918334Speter for (insn = insns; insn; insn = next) 330018334Speter { 3301169689Skan rtx note; 3302169689Skan struct no_conflict_data data; 330318334Speter 330418334Speter next = NEXT_INSN (insn); 330518334Speter 3306132718Skan /* Some ports (cris) create a libcall regions at their own. We must 330796263Sobrien avoid any potential nesting of LIBCALLs. */ 330896263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 330996263Sobrien remove_note (insn, note); 331096263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 331196263Sobrien remove_note (insn, note); 331296263Sobrien 3313169689Skan data.target = target; 3314169689Skan data.first = insns; 3315169689Skan data.insn = insn; 3316169689Skan data.must_stay = 0; 3317169689Skan note_stores (PATTERN (insn), no_conflict_move_test, &data); 3318169689Skan if (! data.must_stay) 331918334Speter { 332018334Speter if (PREV_INSN (insn)) 332118334Speter NEXT_INSN (PREV_INSN (insn)) = next; 332218334Speter else 332318334Speter insns = next; 332418334Speter 332518334Speter if (next) 332618334Speter PREV_INSN (next) = PREV_INSN (insn); 332718334Speter 332818334Speter add_insn (insn); 332918334Speter } 333018334Speter } 333118334Speter 333218334Speter prev = get_last_insn (); 333318334Speter 333418334Speter /* Now write the CLOBBER of the output, followed by the setting of each 333518334Speter of the words, followed by the final copy. */ 333618334Speter if (target != op0 && target != op1) 333750397Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); 333818334Speter 333918334Speter for (insn = insns; insn; insn = next) 334018334Speter { 334118334Speter next = NEXT_INSN (insn); 334218334Speter add_insn (insn); 334318334Speter 3344169689Skan if (op1 && REG_P (op1)) 334550397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1, 334650397Sobrien REG_NOTES (insn)); 334718334Speter 3348169689Skan if (op0 && REG_P (op0)) 334950397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0, 335050397Sobrien REG_NOTES (insn)); 335118334Speter } 335218334Speter 335318334Speter if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 335418334Speter != CODE_FOR_nothing) 335518334Speter { 335618334Speter last = emit_move_insn (target, target); 335718334Speter if (equiv) 335852284Sobrien set_unique_reg_note (last, REG_EQUAL, equiv); 335918334Speter } 336018334Speter else 336190075Sobrien { 336290075Sobrien last = get_last_insn (); 336318334Speter 336490075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 336590075Sobrien be mistaken for a note referring to the full contents of the 336690075Sobrien alleged libcall value when found together with the REG_RETVAL 336790075Sobrien note added below. An existing note can come from an insn 336890075Sobrien expansion at "last". */ 336990075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 337090075Sobrien } 337190075Sobrien 337218334Speter if (prev == 0) 337318334Speter first = get_insns (); 337418334Speter else 337518334Speter first = NEXT_INSN (prev); 337618334Speter 3377169689Skan maybe_encapsulate_block (first, last, equiv); 337818334Speter 337918334Speter return last; 338018334Speter} 338118334Speter 338218334Speter/* Emit code to make a call to a constant function or a library call. 338318334Speter 338418334Speter INSNS is a list containing all insns emitted in the call. 338518334Speter These insns leave the result in RESULT. Our block is to copy RESULT 338618334Speter to TARGET, which is logically equivalent to EQUIV. 338718334Speter 338818334Speter We first emit any insns that set a pseudo on the assumption that these are 338918334Speter loading constants into registers; doing so allows them to be safely cse'ed 339018334Speter between blocks. Then we emit all the other insns in the block, followed by 339118334Speter an insn to move RESULT to TARGET. This last insn will have a REQ_EQUAL 339218334Speter note with an operand of EQUIV. 339318334Speter 339418334Speter Moving assignments to pseudos outside of the block is done to improve 339518334Speter the generated code, but is not required to generate correct code, 339618334Speter hence being unable to move an assignment is not grounds for not making 339718334Speter a libcall block. There are two reasons why it is safe to leave these 339818334Speter insns inside the block: First, we know that these pseudos cannot be 339918334Speter used in generated RTL outside the block since they are created for 340018334Speter temporary purposes within the block. Second, CSE will not record the 340118334Speter values of anything set inside a libcall block, so we know they must 340218334Speter be dead at the end of the block. 340318334Speter 340418334Speter Except for the first group of insns (the ones setting pseudos), the 340518334Speter block is delimited by REG_RETVAL and REG_LIBCALL notes. */ 340618334Speter 340718334Spetervoid 3408132718Skanemit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv) 340918334Speter{ 341070635Sobrien rtx final_dest = target; 341118334Speter rtx prev, next, first, last, insn; 341218334Speter 341370635Sobrien /* If this is a reg with REG_USERVAR_P set, then it could possibly turn 341470635Sobrien into a MEM later. Protect the libcall block from this change. */ 341570635Sobrien if (! REG_P (target) || REG_USERVAR_P (target)) 341670635Sobrien target = gen_reg_rtx (GET_MODE (target)); 3417132718Skan 341890075Sobrien /* If we're using non-call exceptions, a libcall corresponding to an 341990075Sobrien operation that may trap may also trap. */ 342090075Sobrien if (flag_non_call_exceptions && may_trap_p (equiv)) 342190075Sobrien { 342290075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 3423169689Skan if (CALL_P (insn)) 342490075Sobrien { 342590075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 3426132718Skan 342790075Sobrien if (note != 0 && INTVAL (XEXP (note, 0)) <= 0) 342890075Sobrien remove_note (insn, note); 342990075Sobrien } 343090075Sobrien } 343190075Sobrien else 343252284Sobrien /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION 343390075Sobrien reg note to indicate that this call cannot throw or execute a nonlocal 343490075Sobrien goto (unless there is already a REG_EH_REGION note, in which case 343590075Sobrien we update it). */ 343690075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 3437169689Skan if (CALL_P (insn)) 343890075Sobrien { 343990075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 3440132718Skan 344190075Sobrien if (note != 0) 3442169689Skan XEXP (note, 0) = constm1_rtx; 344390075Sobrien else 3444169689Skan REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, 344590075Sobrien REG_NOTES (insn)); 344690075Sobrien } 344752284Sobrien 344818334Speter /* First emit all insns that set pseudos. Remove them from the list as 344918334Speter we go. Avoid insns that set pseudos which were referenced in previous 345018334Speter insns. These can be generated by move_by_pieces, for example, 345118334Speter to update an address. Similarly, avoid insns that reference things 345218334Speter set in previous insns. */ 345318334Speter 345418334Speter for (insn = insns; insn; insn = next) 345518334Speter { 345618334Speter rtx set = single_set (insn); 345796263Sobrien rtx note; 345818334Speter 3459132718Skan /* Some ports (cris) create a libcall regions at their own. We must 346096263Sobrien avoid any potential nesting of LIBCALLs. */ 346196263Sobrien if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL) 346296263Sobrien remove_note (insn, note); 346396263Sobrien if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) 346496263Sobrien remove_note (insn, note); 346596263Sobrien 346618334Speter next = NEXT_INSN (insn); 346718334Speter 3468169689Skan if (set != 0 && REG_P (SET_DEST (set)) 3469169689Skan && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER) 347018334Speter { 3471169689Skan struct no_conflict_data data; 347218334Speter 3473169689Skan data.target = const0_rtx; 3474169689Skan data.first = insns; 3475169689Skan data.insn = insn; 3476169689Skan data.must_stay = 0; 3477169689Skan note_stores (PATTERN (insn), no_conflict_move_test, &data); 3478169689Skan if (! data.must_stay) 3479169689Skan { 3480169689Skan if (PREV_INSN (insn)) 3481169689Skan NEXT_INSN (PREV_INSN (insn)) = next; 3482169689Skan else 3483169689Skan insns = next; 348418334Speter 3485169689Skan if (next) 3486169689Skan PREV_INSN (next) = PREV_INSN (insn); 3487169689Skan 3488169689Skan add_insn (insn); 3489169689Skan } 349018334Speter } 3491132718Skan 3492132718Skan /* Some ports use a loop to copy large arguments onto the stack. 3493132718Skan Don't move anything outside such a loop. */ 3494169689Skan if (LABEL_P (insn)) 3495132718Skan break; 349618334Speter } 349718334Speter 349818334Speter prev = get_last_insn (); 349918334Speter 350018334Speter /* Write the remaining insns followed by the final copy. */ 350118334Speter 350218334Speter for (insn = insns; insn; insn = next) 350318334Speter { 350418334Speter next = NEXT_INSN (insn); 350518334Speter 350618334Speter add_insn (insn); 350718334Speter } 350818334Speter 350918334Speter last = emit_move_insn (target, result); 351050397Sobrien if (mov_optab->handlers[(int) GET_MODE (target)].insn_code 351150397Sobrien != CODE_FOR_nothing) 351252284Sobrien set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv)); 351390075Sobrien else 351490075Sobrien { 351590075Sobrien /* Remove any existing REG_EQUAL note from "last", or else it will 351690075Sobrien be mistaken for a note referring to the full contents of the 351790075Sobrien libcall value when found together with the REG_RETVAL note added 351890075Sobrien below. An existing note can come from an insn expansion at 351990075Sobrien "last". */ 352090075Sobrien remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX)); 352190075Sobrien } 352218334Speter 352370635Sobrien if (final_dest != target) 352470635Sobrien emit_move_insn (final_dest, target); 352570635Sobrien 352618334Speter if (prev == 0) 352718334Speter first = get_insns (); 352818334Speter else 352918334Speter first = NEXT_INSN (prev); 353018334Speter 3531169689Skan maybe_encapsulate_block (first, last, equiv); 353218334Speter} 353318334Speter 353490075Sobrien/* Nonzero if we can perform a comparison of mode MODE straightforwardly. 353590075Sobrien PURPOSE describes how this comparison will be used. CODE is the rtx 353690075Sobrien comparison code we will be using. 353718334Speter 353890075Sobrien ??? Actually, CODE is slightly weaker than that. A target is still 3539132718Skan required to implement all of the normal bcc operations, but not 354090075Sobrien required to implement all (or any) of the unordered bcc operations. */ 3541132718Skan 354290075Sobrienint 3543132718Skancan_compare_p (enum rtx_code code, enum machine_mode mode, 3544132718Skan enum can_compare_purpose purpose) 354590075Sobrien{ 354690075Sobrien do 354790075Sobrien { 3548117395Skan if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 354990075Sobrien { 355090075Sobrien if (purpose == ccp_jump) 3551117395Skan return bcc_gen_fctn[(int) code] != NULL; 355290075Sobrien else if (purpose == ccp_store_flag) 3553117395Skan return setcc_gen_code[(int) code] != CODE_FOR_nothing; 355490075Sobrien else 355590075Sobrien /* There's only one cmov entry point, and it's allowed to fail. */ 355690075Sobrien return 1; 355790075Sobrien } 355890075Sobrien if (purpose == ccp_jump 3559117395Skan && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 356090075Sobrien return 1; 356190075Sobrien if (purpose == ccp_cmov 3562117395Skan && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 356390075Sobrien return 1; 356490075Sobrien if (purpose == ccp_store_flag 3565117395Skan && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) 356690075Sobrien return 1; 356790075Sobrien mode = GET_MODE_WIDER_MODE (mode); 356890075Sobrien } 356990075Sobrien while (mode != VOIDmode); 357090075Sobrien 357190075Sobrien return 0; 357290075Sobrien} 357390075Sobrien 357490075Sobrien/* This function is called when we are going to emit a compare instruction that 357590075Sobrien compares the values found in *PX and *PY, using the rtl operator COMPARISON. 357690075Sobrien 357790075Sobrien *PMODE is the mode of the inputs (in case they are const_int). 357890075Sobrien *PUNSIGNEDP nonzero says that the operands are unsigned; 357918334Speter this matters if they need to be widened. 358018334Speter 358190075Sobrien If they have mode BLKmode, then SIZE specifies the size of both operands. 358218334Speter 358390075Sobrien This function performs all the setup necessary so that the caller only has 358490075Sobrien to emit a single comparison insn. This setup can involve doing a BLKmode 358590075Sobrien comparison or emitting a library call to perform the comparison if no insn 358690075Sobrien is available to handle it. 358790075Sobrien The values which are passed in through pointers can be modified; the caller 3588169689Skan should perform the comparison on the modified values. Constant 3589169689Skan comparisons must have already been folded. */ 359018334Speter 359190075Sobrienstatic void 3592132718Skanprepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size, 3593132718Skan enum machine_mode *pmode, int *punsignedp, 3594132718Skan enum can_compare_purpose purpose) 359518334Speter{ 359690075Sobrien enum machine_mode mode = *pmode; 359790075Sobrien rtx x = *px, y = *py; 359890075Sobrien int unsignedp = *punsignedp; 359918334Speter 3600169689Skan /* If we are inside an appropriately-short loop and we are optimizing, 3601169689Skan force expensive constants into a register. */ 3602169689Skan if (CONSTANT_P (x) && optimize 360390075Sobrien && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1)) 360418334Speter x = force_reg (mode, x); 360518334Speter 3606169689Skan if (CONSTANT_P (y) && optimize 360790075Sobrien && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1)) 360818334Speter y = force_reg (mode, y); 360918334Speter 361052284Sobrien#ifdef HAVE_cc0 3611169689Skan /* Make sure if we have a canonical comparison. The RTL 3612169689Skan documentation states that canonical comparisons are required only 3613169689Skan for targets which have cc0. */ 3614169689Skan gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y)); 361552284Sobrien#endif 361652284Sobrien 361718334Speter /* Don't let both operands fail to indicate the mode. */ 361818334Speter if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode) 361918334Speter x = force_reg (mode, x); 362018334Speter 362118334Speter /* Handle all BLKmode compares. */ 362218334Speter 362318334Speter if (mode == BLKmode) 362418334Speter { 3625132718Skan enum machine_mode cmp_mode, result_mode; 3626132718Skan enum insn_code cmp_code; 3627132718Skan tree length_type; 3628132718Skan rtx libfunc; 362990075Sobrien rtx result; 3630132718Skan rtx opalign 363190075Sobrien = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT); 363290075Sobrien 3633169689Skan gcc_assert (size); 3634132718Skan 3635132718Skan /* Try to use a memory block compare insn - either cmpstr 3636132718Skan or cmpmem will do. */ 3637132718Skan for (cmp_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); 3638132718Skan cmp_mode != VOIDmode; 3639132718Skan cmp_mode = GET_MODE_WIDER_MODE (cmp_mode)) 364018334Speter { 3641132718Skan cmp_code = cmpmem_optab[cmp_mode]; 3642132718Skan if (cmp_code == CODE_FOR_nothing) 3643132718Skan cmp_code = cmpstr_optab[cmp_mode]; 3644132718Skan if (cmp_code == CODE_FOR_nothing) 3645169689Skan cmp_code = cmpstrn_optab[cmp_mode]; 3646169689Skan if (cmp_code == CODE_FOR_nothing) 3647132718Skan continue; 3648132718Skan 3649132718Skan /* Must make sure the size fits the insn's mode. */ 3650132718Skan if ((GET_CODE (size) == CONST_INT 3651132718Skan && INTVAL (size) >= (1 << GET_MODE_BITSIZE (cmp_mode))) 3652132718Skan || (GET_MODE_BITSIZE (GET_MODE (size)) 3653132718Skan > GET_MODE_BITSIZE (cmp_mode))) 3654132718Skan continue; 3655132718Skan 3656132718Skan result_mode = insn_data[cmp_code].operand[0].mode; 365790075Sobrien result = gen_reg_rtx (result_mode); 3658132718Skan size = convert_to_mode (cmp_mode, size, 1); 3659132718Skan emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign)); 3660132718Skan 3661132718Skan *px = result; 3662132718Skan *py = const0_rtx; 3663132718Skan *pmode = result_mode; 3664132718Skan return; 366518334Speter } 3666132718Skan 3667169689Skan /* Otherwise call a library function, memcmp. */ 3668132718Skan libfunc = memcmp_libfunc; 3669132718Skan length_type = sizetype; 3670132718Skan result_mode = TYPE_MODE (integer_type_node); 3671132718Skan cmp_mode = TYPE_MODE (length_type); 3672132718Skan size = convert_to_mode (TYPE_MODE (length_type), size, 3673169689Skan TYPE_UNSIGNED (length_type)); 367450397Sobrien 3675132718Skan result = emit_library_call_value (libfunc, 0, LCT_PURE_MAKE_BLOCK, 3676132718Skan result_mode, 3, 3677132718Skan XEXP (x, 0), Pmode, 3678132718Skan XEXP (y, 0), Pmode, 3679132718Skan size, cmp_mode); 368090075Sobrien *px = result; 368190075Sobrien *py = const0_rtx; 368290075Sobrien *pmode = result_mode; 368318334Speter return; 368418334Speter } 368518334Speter 3686132718Skan /* Don't allow operands to the compare to trap, as that can put the 3687132718Skan compare and branch in different basic blocks. */ 3688132718Skan if (flag_non_call_exceptions) 3689132718Skan { 3690132718Skan if (may_trap_p (x)) 3691132718Skan x = force_reg (mode, x); 3692132718Skan if (may_trap_p (y)) 3693132718Skan y = force_reg (mode, y); 3694132718Skan } 3695132718Skan 369690075Sobrien *px = x; 369790075Sobrien *py = y; 369890075Sobrien if (can_compare_p (*pcomparison, mode, purpose)) 369990075Sobrien return; 370018334Speter 370118334Speter /* Handle a lib call just for the mode we are using. */ 370218334Speter 3703169689Skan if (cmp_optab->handlers[(int) mode].libfunc && !SCALAR_FLOAT_MODE_P (mode)) 370418334Speter { 370518334Speter rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; 370650397Sobrien rtx result; 370750397Sobrien 370818334Speter /* If we want unsigned, and this mode has a distinct unsigned 370918334Speter comparison routine, use that. */ 371018334Speter if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc) 371118334Speter libfunc = ucmp_optab->handlers[(int) mode].libfunc; 371218334Speter 3713117395Skan result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK, 3714117395Skan word_mode, 2, x, mode, y, mode); 371518334Speter 3716169689Skan /* There are two kinds of comparison routines. Biased routines 3717169689Skan return 0/1/2, and unbiased routines return -1/0/1. Other parts 3718169689Skan of gcc expect that the comparison operation is equivalent 3719169689Skan to the modified comparison. For signed comparisons compare the 3720169689Skan result against 1 in the biased case, and zero in the unbiased 3721169689Skan case. For unsigned comparisons always compare against 1 after 3722169689Skan biasing the unbiased result by adding 1. This gives us a way to 3723169689Skan represent LTU. */ 372490075Sobrien *px = result; 3725169689Skan *pmode = word_mode; 372690075Sobrien *py = const1_rtx; 3727169689Skan 3728169689Skan if (!TARGET_LIB_INT_CMP_BIASED) 3729169689Skan { 3730169689Skan if (*punsignedp) 3731169689Skan *px = plus_constant (result, 1); 3732169689Skan else 3733169689Skan *py = const0_rtx; 3734169689Skan } 373518334Speter return; 373618334Speter } 373718334Speter 3738169689Skan gcc_assert (SCALAR_FLOAT_MODE_P (mode)); 3739169689Skan prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp); 374018334Speter} 374118334Speter 374290075Sobrien/* Before emitting an insn with code ICODE, make sure that X, which is going 374390075Sobrien to be used for operand OPNUM of the insn, is converted from mode MODE to 374490075Sobrien WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and 374590075Sobrien that it is accepted by the operand predicate. Return the new value. */ 374690075Sobrien 3747169689Skanstatic rtx 3748132718Skanprepare_operand (int icode, rtx x, int opnum, enum machine_mode mode, 3749132718Skan enum machine_mode wider_mode, int unsignedp) 375090075Sobrien{ 375190075Sobrien if (mode != wider_mode) 375290075Sobrien x = convert_modes (wider_mode, mode, x, unsignedp); 375390075Sobrien 3754169689Skan if (!insn_data[icode].operand[opnum].predicate 375590075Sobrien (x, insn_data[icode].operand[opnum].mode)) 3756119256Skan { 3757119256Skan if (no_new_pseudos) 3758119256Skan return NULL_RTX; 3759119256Skan x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x); 3760119256Skan } 3761119256Skan 376290075Sobrien return x; 376390075Sobrien} 376490075Sobrien 376590075Sobrien/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know 376690075Sobrien we can do the comparison. 376790075Sobrien The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may 376890075Sobrien be NULL_RTX which indicates that only a comparison is to be generated. */ 376990075Sobrien 377090075Sobrienstatic void 3771132718Skanemit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode, 3772132718Skan enum rtx_code comparison, int unsignedp, rtx label) 377390075Sobrien{ 377490075Sobrien rtx test = gen_rtx_fmt_ee (comparison, mode, x, y); 377590075Sobrien enum mode_class class = GET_MODE_CLASS (mode); 377690075Sobrien enum machine_mode wider_mode = mode; 377790075Sobrien 377890075Sobrien /* Try combined insns first. */ 377990075Sobrien do 378090075Sobrien { 378190075Sobrien enum insn_code icode; 378290075Sobrien PUT_MODE (test, wider_mode); 378390075Sobrien 378490075Sobrien if (label) 3785132718Skan { 3786117395Skan icode = cbranch_optab->handlers[(int) wider_mode].insn_code; 3787132718Skan 378890075Sobrien if (icode != CODE_FOR_nothing 3789169689Skan && insn_data[icode].operand[0].predicate (test, wider_mode)) 379090075Sobrien { 379190075Sobrien x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp); 379290075Sobrien y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp); 379390075Sobrien emit_jump_insn (GEN_FCN (icode) (test, x, y, label)); 379490075Sobrien return; 379590075Sobrien } 379690075Sobrien } 379790075Sobrien 379890075Sobrien /* Handle some compares against zero. */ 379990075Sobrien icode = (int) tst_optab->handlers[(int) wider_mode].insn_code; 380090075Sobrien if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing) 380190075Sobrien { 380290075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 380390075Sobrien emit_insn (GEN_FCN (icode) (x)); 380490075Sobrien if (label) 3805169689Skan emit_jump_insn (bcc_gen_fctn[(int) comparison] (label)); 380690075Sobrien return; 380790075Sobrien } 380890075Sobrien 380990075Sobrien /* Handle compares for which there is a directly suitable insn. */ 381090075Sobrien 381190075Sobrien icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code; 381290075Sobrien if (icode != CODE_FOR_nothing) 381390075Sobrien { 381490075Sobrien x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 381590075Sobrien y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp); 381690075Sobrien emit_insn (GEN_FCN (icode) (x, y)); 381790075Sobrien if (label) 3818169689Skan emit_jump_insn (bcc_gen_fctn[(int) comparison] (label)); 381990075Sobrien return; 382090075Sobrien } 382190075Sobrien 3822169689Skan if (!CLASS_HAS_WIDER_MODES_P (class)) 382390075Sobrien break; 382490075Sobrien 382590075Sobrien wider_mode = GET_MODE_WIDER_MODE (wider_mode); 3826117395Skan } 3827117395Skan while (wider_mode != VOIDmode); 382890075Sobrien 3829169689Skan gcc_unreachable (); 383090075Sobrien} 383190075Sobrien 383252284Sobrien/* Generate code to compare X with Y so that the condition codes are 383352284Sobrien set and to jump to LABEL if the condition is true. If X is a 383452284Sobrien constant and Y is not a constant, then the comparison is swapped to 383552284Sobrien ensure that the comparison RTL has the canonical form. 383652284Sobrien 383752284Sobrien UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they 383852284Sobrien need to be widened by emit_cmp_insn. UNSIGNEDP is also used to select 383952284Sobrien the proper branch condition code. 384052284Sobrien 384190075Sobrien If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y. 384252284Sobrien 384352284Sobrien MODE is the mode of the inputs (in case they are const_int). 384452284Sobrien 384552284Sobrien COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). It will 384652284Sobrien be passed unchanged to emit_cmp_insn, then potentially converted into an 384752284Sobrien unsigned variant based on UNSIGNEDP to select a proper jump instruction. */ 384852284Sobrien 384952284Sobrienvoid 3850132718Skanemit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size, 3851132718Skan enum machine_mode mode, int unsignedp, rtx label) 385252284Sobrien{ 385390075Sobrien rtx op0 = x, op1 = y; 385490075Sobrien 385590075Sobrien /* Swap operands and condition to ensure canonical RTL. */ 385690075Sobrien if (swap_commutative_operands_p (x, y)) 385752284Sobrien { 385890075Sobrien /* If we're not emitting a branch, this means some caller 385990075Sobrien is out of sync. */ 3860169689Skan gcc_assert (label); 386190075Sobrien 386290075Sobrien op0 = y, op1 = x; 386352284Sobrien comparison = swap_condition (comparison); 386452284Sobrien } 386552284Sobrien 386652284Sobrien#ifdef HAVE_cc0 3867169689Skan /* If OP0 is still a constant, then both X and Y must be constants. 3868169689Skan Force X into a register to create canonical RTL. */ 386952284Sobrien if (CONSTANT_P (op0)) 387052284Sobrien op0 = force_reg (mode, op0); 387152284Sobrien#endif 387252284Sobrien 387352284Sobrien if (unsignedp) 387452284Sobrien comparison = unsigned_condition (comparison); 387590075Sobrien 387690075Sobrien prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, 387790075Sobrien ccp_jump); 387890075Sobrien emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label); 387952284Sobrien} 388052284Sobrien 388190075Sobrien/* Like emit_cmp_and_jump_insns, but generate only the comparison. */ 388252284Sobrien 388390075Sobrienvoid 3884132718Skanemit_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size, 3885132718Skan enum machine_mode mode, int unsignedp) 388618334Speter{ 388790075Sobrien emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0); 388818334Speter} 388918334Speter 389018334Speter/* Emit a library call comparison between floating point X and Y. 389118334Speter COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ 389218334Speter 389390075Sobrienstatic void 3894132718Skanprepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison, 3895132718Skan enum machine_mode *pmode, int *punsignedp) 389618334Speter{ 389790075Sobrien enum rtx_code comparison = *pcomparison; 3898132718Skan enum rtx_code swapped = swap_condition (comparison); 3899169689Skan enum rtx_code reversed = reverse_condition_maybe_unordered (comparison); 3900169689Skan rtx x = *px; 3901169689Skan rtx y = *py; 3902132718Skan enum machine_mode orig_mode = GET_MODE (x); 3903132718Skan enum machine_mode mode; 3904132718Skan rtx value, target, insns, equiv; 390518334Speter rtx libfunc = 0; 3906169689Skan bool reversed_p = false; 390718334Speter 3908169689Skan for (mode = orig_mode; 3909169689Skan mode != VOIDmode; 3910169689Skan mode = GET_MODE_WIDER_MODE (mode)) 3911132718Skan { 3912132718Skan if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc)) 391318334Speter break; 391418334Speter 3915132718Skan if ((libfunc = code_to_optab[swapped]->handlers[mode].libfunc)) 3916132718Skan { 3917132718Skan rtx tmp; 3918132718Skan tmp = x; x = y; y = tmp; 3919132718Skan comparison = swapped; 3920132718Skan break; 3921132718Skan } 3922169689Skan 3923169689Skan if ((libfunc = code_to_optab[reversed]->handlers[mode].libfunc) 3924169689Skan && FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, reversed)) 3925169689Skan { 3926169689Skan comparison = reversed; 3927169689Skan reversed_p = true; 3928169689Skan break; 3929169689Skan } 3930132718Skan } 393118334Speter 3932169689Skan gcc_assert (mode != VOIDmode); 393318334Speter 3934132718Skan if (mode != orig_mode) 3935132718Skan { 3936132718Skan x = convert_to_mode (mode, x, 0); 3937132718Skan y = convert_to_mode (mode, y, 0); 3938132718Skan } 393918334Speter 3940132718Skan /* Attach a REG_EQUAL note describing the semantics of the libcall to 3941132718Skan the RTL. The allows the RTL optimizers to delete the libcall if the 3942132718Skan condition can be determined at compile-time. */ 3943132718Skan if (comparison == UNORDERED) 3944132718Skan { 3945132718Skan rtx temp = simplify_gen_relational (NE, word_mode, mode, x, x); 3946132718Skan equiv = simplify_gen_relational (NE, word_mode, mode, y, y); 3947132718Skan equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode, 3948132718Skan temp, const_true_rtx, equiv); 3949132718Skan } 3950132718Skan else 3951132718Skan { 3952132718Skan equiv = simplify_gen_relational (comparison, word_mode, mode, x, y); 3953132718Skan if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) 3954132718Skan { 3955132718Skan rtx true_rtx, false_rtx; 395618334Speter 3957132718Skan switch (comparison) 3958132718Skan { 3959132718Skan case EQ: 3960132718Skan true_rtx = const0_rtx; 3961132718Skan false_rtx = const_true_rtx; 3962132718Skan break; 396350397Sobrien 3964132718Skan case NE: 3965132718Skan true_rtx = const_true_rtx; 3966132718Skan false_rtx = const0_rtx; 3967132718Skan break; 396890075Sobrien 3969132718Skan case GT: 3970132718Skan true_rtx = const1_rtx; 3971132718Skan false_rtx = const0_rtx; 3972132718Skan break; 397318334Speter 3974132718Skan case GE: 3975132718Skan true_rtx = const0_rtx; 3976132718Skan false_rtx = constm1_rtx; 3977132718Skan break; 397818334Speter 3979132718Skan case LT: 3980132718Skan true_rtx = constm1_rtx; 3981132718Skan false_rtx = const0_rtx; 3982132718Skan break; 398318334Speter 3984132718Skan case LE: 3985132718Skan true_rtx = const0_rtx; 3986132718Skan false_rtx = const1_rtx; 3987132718Skan break; 398818334Speter 3989132718Skan default: 3990169689Skan gcc_unreachable (); 3991132718Skan } 3992132718Skan equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode, 3993132718Skan equiv, true_rtx, false_rtx); 3994132718Skan } 3995132718Skan } 399618334Speter 3997132718Skan start_sequence (); 3998132718Skan value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, 3999132718Skan word_mode, 2, x, mode, y, mode); 4000132718Skan insns = get_insns (); 4001132718Skan end_sequence (); 400250397Sobrien 4003132718Skan target = gen_reg_rtx (word_mode); 4004132718Skan emit_libcall_block (insns, target, value, equiv); 400590075Sobrien 4006132718Skan if (comparison == UNORDERED 4007132718Skan || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison)) 4008169689Skan comparison = reversed_p ? EQ : NE; 400918334Speter 4010132718Skan *px = target; 401190075Sobrien *py = const0_rtx; 401290075Sobrien *pmode = word_mode; 4013132718Skan *pcomparison = comparison; 401490075Sobrien *punsignedp = 0; 401518334Speter} 401618334Speter 401718334Speter/* Generate code to indirectly jump to a location given in the rtx LOC. */ 401818334Speter 401918334Spetervoid 4020132718Skanemit_indirect_jump (rtx loc) 402118334Speter{ 4022169689Skan if (!insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate 4023169689Skan (loc, Pmode)) 402418334Speter loc = copy_to_mode_reg (Pmode, loc); 402518334Speter 402618334Speter emit_jump_insn (gen_indirect_jump (loc)); 402718334Speter emit_barrier (); 402818334Speter} 402918334Speter 403018334Speter#ifdef HAVE_conditional_move 403118334Speter 403218334Speter/* Emit a conditional move instruction if the machine supports one for that 403318334Speter condition and machine mode. 403418334Speter 403518334Speter OP0 and OP1 are the operands that should be compared using CODE. CMODE is 403618334Speter the mode to use should they be constants. If it is VOIDmode, they cannot 403718334Speter both be constants. 403818334Speter 403918334Speter OP2 should be stored in TARGET if the comparison is true, otherwise OP3 404018334Speter should be stored there. MODE is the mode to use should they be constants. 404118334Speter If it is VOIDmode, they cannot both be constants. 404218334Speter 404318334Speter The result is either TARGET (perhaps modified) or NULL_RTX if the operation 404418334Speter is not supported. */ 404518334Speter 404618334Speterrtx 4047132718Skanemit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, 4048132718Skan enum machine_mode cmode, rtx op2, rtx op3, 4049132718Skan enum machine_mode mode, int unsignedp) 405018334Speter{ 405118334Speter rtx tem, subtarget, comparison, insn; 405218334Speter enum insn_code icode; 405390075Sobrien enum rtx_code reversed; 405418334Speter 405518334Speter /* If one operand is constant, make it the second one. Only do this 405618334Speter if the other operand is not constant as well. */ 405718334Speter 405890075Sobrien if (swap_commutative_operands_p (op0, op1)) 405918334Speter { 406018334Speter tem = op0; 406118334Speter op0 = op1; 406218334Speter op1 = tem; 406318334Speter code = swap_condition (code); 406418334Speter } 406518334Speter 406690075Sobrien /* get_condition will prefer to generate LT and GT even if the old 406790075Sobrien comparison was against zero, so undo that canonicalization here since 406890075Sobrien comparisons against zero are cheaper. */ 4069132718Skan if (code == LT && op1 == const1_rtx) 407090075Sobrien code = LE, op1 = const0_rtx; 4071132718Skan else if (code == GT && op1 == constm1_rtx) 407290075Sobrien code = GE, op1 = const0_rtx; 407390075Sobrien 407418334Speter if (cmode == VOIDmode) 407518334Speter cmode = GET_MODE (op0); 407618334Speter 407790075Sobrien if (swap_commutative_operands_p (op2, op3) 407890075Sobrien && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) 407990075Sobrien != UNKNOWN)) 408018334Speter { 408118334Speter tem = op2; 408218334Speter op2 = op3; 408318334Speter op3 = tem; 408490075Sobrien code = reversed; 408518334Speter } 408618334Speter 408718334Speter if (mode == VOIDmode) 408818334Speter mode = GET_MODE (op2); 408918334Speter 409018334Speter icode = movcc_gen_code[mode]; 409118334Speter 409218334Speter if (icode == CODE_FOR_nothing) 409318334Speter return 0; 409418334Speter 4095169689Skan if (!target) 409618334Speter target = gen_reg_rtx (mode); 409718334Speter 409818334Speter subtarget = target; 409918334Speter 410018334Speter /* If the insn doesn't accept these operands, put them in pseudos. */ 410118334Speter 4102169689Skan if (!insn_data[icode].operand[0].predicate 410390075Sobrien (subtarget, insn_data[icode].operand[0].mode)) 410490075Sobrien subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); 410518334Speter 4106169689Skan if (!insn_data[icode].operand[2].predicate 410790075Sobrien (op2, insn_data[icode].operand[2].mode)) 410890075Sobrien op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); 410918334Speter 4110169689Skan if (!insn_data[icode].operand[3].predicate 411190075Sobrien (op3, insn_data[icode].operand[3].mode)) 411290075Sobrien op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); 411318334Speter 411418334Speter /* Everything should now be in the suitable form, so emit the compare insn 411518334Speter and then the conditional move. */ 411618334Speter 4117132718Skan comparison 411890075Sobrien = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); 411918334Speter 412018334Speter /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ 412190075Sobrien /* We can get const0_rtx or const_true_rtx in some circumstances. Just 412290075Sobrien return NULL and let the caller figure out how best to deal with this 412390075Sobrien situation. */ 412418334Speter if (GET_CODE (comparison) != code) 412590075Sobrien return NULL_RTX; 4126132718Skan 412718334Speter insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); 412818334Speter 412918334Speter /* If that failed, then give up. */ 413018334Speter if (insn == 0) 413118334Speter return 0; 413218334Speter 413318334Speter emit_insn (insn); 413418334Speter 413518334Speter if (subtarget != target) 413618334Speter convert_move (target, subtarget, 0); 413718334Speter 413818334Speter return target; 413918334Speter} 414018334Speter 4141117395Skan/* Return nonzero if a conditional move of mode MODE is supported. 414218334Speter 414318334Speter This function is for combine so it can tell whether an insn that looks 414418334Speter like a conditional move is actually supported by the hardware. If we 414518334Speter guess wrong we lose a bit on optimization, but that's it. */ 414618334Speter/* ??? sparc64 supports conditionally moving integers values based on fp 414718334Speter comparisons, and vice versa. How do we handle them? */ 414818334Speter 414918334Speterint 4150132718Skancan_conditionally_move_p (enum machine_mode mode) 415118334Speter{ 415218334Speter if (movcc_gen_code[mode] != CODE_FOR_nothing) 415318334Speter return 1; 415418334Speter 415518334Speter return 0; 415618334Speter} 415718334Speter 415818334Speter#endif /* HAVE_conditional_move */ 4159132718Skan 4160132718Skan/* Emit a conditional addition instruction if the machine supports one for that 4161132718Skan condition and machine mode. 4162132718Skan 4163132718Skan OP0 and OP1 are the operands that should be compared using CODE. CMODE is 4164132718Skan the mode to use should they be constants. If it is VOIDmode, they cannot 4165132718Skan both be constants. 4166132718Skan 4167132718Skan OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3 4168132718Skan should be stored there. MODE is the mode to use should they be constants. 4169132718Skan If it is VOIDmode, they cannot both be constants. 4170132718Skan 4171132718Skan The result is either TARGET (perhaps modified) or NULL_RTX if the operation 4172132718Skan is not supported. */ 4173132718Skan 4174132718Skanrtx 4175132718Skanemit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1, 4176132718Skan enum machine_mode cmode, rtx op2, rtx op3, 4177132718Skan enum machine_mode mode, int unsignedp) 4178132718Skan{ 4179132718Skan rtx tem, subtarget, comparison, insn; 4180132718Skan enum insn_code icode; 4181132718Skan enum rtx_code reversed; 4182132718Skan 4183132718Skan /* If one operand is constant, make it the second one. Only do this 4184132718Skan if the other operand is not constant as well. */ 4185132718Skan 4186132718Skan if (swap_commutative_operands_p (op0, op1)) 4187132718Skan { 4188132718Skan tem = op0; 4189132718Skan op0 = op1; 4190132718Skan op1 = tem; 4191132718Skan code = swap_condition (code); 4192132718Skan } 4193132718Skan 4194132718Skan /* get_condition will prefer to generate LT and GT even if the old 4195132718Skan comparison was against zero, so undo that canonicalization here since 4196132718Skan comparisons against zero are cheaper. */ 4197132718Skan if (code == LT && op1 == const1_rtx) 4198132718Skan code = LE, op1 = const0_rtx; 4199132718Skan else if (code == GT && op1 == constm1_rtx) 4200132718Skan code = GE, op1 = const0_rtx; 4201132718Skan 4202132718Skan if (cmode == VOIDmode) 4203132718Skan cmode = GET_MODE (op0); 4204132718Skan 4205132718Skan if (swap_commutative_operands_p (op2, op3) 4206132718Skan && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) 4207132718Skan != UNKNOWN)) 4208132718Skan { 4209132718Skan tem = op2; 4210132718Skan op2 = op3; 4211132718Skan op3 = tem; 4212132718Skan code = reversed; 4213132718Skan } 4214132718Skan 4215132718Skan if (mode == VOIDmode) 4216132718Skan mode = GET_MODE (op2); 4217132718Skan 4218132718Skan icode = addcc_optab->handlers[(int) mode].insn_code; 4219132718Skan 4220132718Skan if (icode == CODE_FOR_nothing) 4221132718Skan return 0; 4222132718Skan 4223169689Skan if (!target) 4224132718Skan target = gen_reg_rtx (mode); 4225132718Skan 4226132718Skan /* If the insn doesn't accept these operands, put them in pseudos. */ 4227132718Skan 4228169689Skan if (!insn_data[icode].operand[0].predicate 4229169689Skan (target, insn_data[icode].operand[0].mode)) 4230132718Skan subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode); 4231169689Skan else 4232169689Skan subtarget = target; 4233132718Skan 4234169689Skan if (!insn_data[icode].operand[2].predicate 4235132718Skan (op2, insn_data[icode].operand[2].mode)) 4236132718Skan op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2); 4237132718Skan 4238169689Skan if (!insn_data[icode].operand[3].predicate 4239132718Skan (op3, insn_data[icode].operand[3].mode)) 4240132718Skan op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3); 4241132718Skan 4242132718Skan /* Everything should now be in the suitable form, so emit the compare insn 4243132718Skan and then the conditional move. */ 4244132718Skan 4245132718Skan comparison 4246132718Skan = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX); 4247132718Skan 4248132718Skan /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */ 4249132718Skan /* We can get const0_rtx or const_true_rtx in some circumstances. Just 4250132718Skan return NULL and let the caller figure out how best to deal with this 4251132718Skan situation. */ 4252132718Skan if (GET_CODE (comparison) != code) 4253132718Skan return NULL_RTX; 4254132718Skan 4255132718Skan insn = GEN_FCN (icode) (subtarget, comparison, op2, op3); 4256132718Skan 4257132718Skan /* If that failed, then give up. */ 4258132718Skan if (insn == 0) 4259132718Skan return 0; 4260132718Skan 4261132718Skan emit_insn (insn); 4262132718Skan 4263132718Skan if (subtarget != target) 4264132718Skan convert_move (target, subtarget, 0); 4265132718Skan 4266132718Skan return target; 4267132718Skan} 426818334Speter 4269132718Skan/* These functions attempt to generate an insn body, rather than 4270132718Skan emitting the insn, but if the gen function already emits them, we 4271169689Skan make no attempt to turn them back into naked patterns. */ 427218334Speter 427318334Speter/* Generate and return an insn body to add Y to X. */ 427418334Speter 427518334Speterrtx 4276132718Skangen_add2_insn (rtx x, rtx y) 427718334Speter{ 4278132718Skan int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 427918334Speter 4280169689Skan gcc_assert (insn_data[icode].operand[0].predicate 4281169689Skan (x, insn_data[icode].operand[0].mode)); 4282169689Skan gcc_assert (insn_data[icode].operand[1].predicate 4283169689Skan (x, insn_data[icode].operand[1].mode)); 4284169689Skan gcc_assert (insn_data[icode].operand[2].predicate 4285169689Skan (y, insn_data[icode].operand[2].mode)); 428618334Speter 4287169689Skan return GEN_FCN (icode) (x, x, y); 428818334Speter} 428918334Speter 429090075Sobrien/* Generate and return an insn body to add r1 and c, 429190075Sobrien storing the result in r0. */ 429290075Sobrienrtx 4293132718Skangen_add3_insn (rtx r0, rtx r1, rtx c) 429490075Sobrien{ 429590075Sobrien int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code; 429690075Sobrien 4297117395Skan if (icode == CODE_FOR_nothing 4298169689Skan || !(insn_data[icode].operand[0].predicate 4299169689Skan (r0, insn_data[icode].operand[0].mode)) 4300169689Skan || !(insn_data[icode].operand[1].predicate 4301169689Skan (r1, insn_data[icode].operand[1].mode)) 4302169689Skan || !(insn_data[icode].operand[2].predicate 4303169689Skan (c, insn_data[icode].operand[2].mode))) 430490075Sobrien return NULL_RTX; 430590075Sobrien 4306169689Skan return GEN_FCN (icode) (r0, r1, c); 430790075Sobrien} 430890075Sobrien 430918334Speterint 4310132718Skanhave_add2_insn (rtx x, rtx y) 431118334Speter{ 431290075Sobrien int icode; 431390075Sobrien 4314169689Skan gcc_assert (GET_MODE (x) != VOIDmode); 431590075Sobrien 4316132718Skan icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 431790075Sobrien 431890075Sobrien if (icode == CODE_FOR_nothing) 431990075Sobrien return 0; 432090075Sobrien 4321169689Skan if (!(insn_data[icode].operand[0].predicate 4322169689Skan (x, insn_data[icode].operand[0].mode)) 4323169689Skan || !(insn_data[icode].operand[1].predicate 4324169689Skan (x, insn_data[icode].operand[1].mode)) 4325169689Skan || !(insn_data[icode].operand[2].predicate 4326169689Skan (y, insn_data[icode].operand[2].mode))) 432790075Sobrien return 0; 432890075Sobrien 432990075Sobrien return 1; 433018334Speter} 433118334Speter 433218334Speter/* Generate and return an insn body to subtract Y from X. */ 433318334Speter 433418334Speterrtx 4335132718Skangen_sub2_insn (rtx x, rtx y) 433618334Speter{ 4337132718Skan int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 433818334Speter 4339169689Skan gcc_assert (insn_data[icode].operand[0].predicate 4340169689Skan (x, insn_data[icode].operand[0].mode)); 4341169689Skan gcc_assert (insn_data[icode].operand[1].predicate 4342169689Skan (x, insn_data[icode].operand[1].mode)); 4343169689Skan gcc_assert (insn_data[icode].operand[2].predicate 4344169689Skan (y, insn_data[icode].operand[2].mode)); 434518334Speter 4346169689Skan return GEN_FCN (icode) (x, x, y); 434718334Speter} 434818334Speter 434990075Sobrien/* Generate and return an insn body to subtract r1 and c, 435090075Sobrien storing the result in r0. */ 435190075Sobrienrtx 4352132718Skangen_sub3_insn (rtx r0, rtx r1, rtx c) 435390075Sobrien{ 435490075Sobrien int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code; 435590075Sobrien 4356117395Skan if (icode == CODE_FOR_nothing 4357169689Skan || !(insn_data[icode].operand[0].predicate 4358169689Skan (r0, insn_data[icode].operand[0].mode)) 4359169689Skan || !(insn_data[icode].operand[1].predicate 4360169689Skan (r1, insn_data[icode].operand[1].mode)) 4361169689Skan || !(insn_data[icode].operand[2].predicate 4362169689Skan (c, insn_data[icode].operand[2].mode))) 436390075Sobrien return NULL_RTX; 436490075Sobrien 4365169689Skan return GEN_FCN (icode) (r0, r1, c); 436690075Sobrien} 436790075Sobrien 436818334Speterint 4369132718Skanhave_sub2_insn (rtx x, rtx y) 437018334Speter{ 437190075Sobrien int icode; 437290075Sobrien 4373169689Skan gcc_assert (GET_MODE (x) != VOIDmode); 437490075Sobrien 4375132718Skan icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 437690075Sobrien 437790075Sobrien if (icode == CODE_FOR_nothing) 437890075Sobrien return 0; 437990075Sobrien 4380169689Skan if (!(insn_data[icode].operand[0].predicate 4381169689Skan (x, insn_data[icode].operand[0].mode)) 4382169689Skan || !(insn_data[icode].operand[1].predicate 4383169689Skan (x, insn_data[icode].operand[1].mode)) 4384169689Skan || !(insn_data[icode].operand[2].predicate 4385169689Skan (y, insn_data[icode].operand[2].mode))) 438690075Sobrien return 0; 438790075Sobrien 438890075Sobrien return 1; 438918334Speter} 439018334Speter 439118334Speter/* Generate the body of an instruction to copy Y into X. 4392117395Skan It may be a list of insns, if one insn isn't enough. */ 439318334Speter 439418334Speterrtx 4395132718Skangen_move_insn (rtx x, rtx y) 439618334Speter{ 439718334Speter rtx seq; 439818334Speter 439918334Speter start_sequence (); 440018334Speter emit_move_insn_1 (x, y); 4401117395Skan seq = get_insns (); 440218334Speter end_sequence (); 440318334Speter return seq; 440418334Speter} 440518334Speter 440618334Speter/* Return the insn code used to extend FROM_MODE to TO_MODE. 440718334Speter UNSIGNEDP specifies zero-extension instead of sign-extension. If 440818334Speter no such operation exists, CODE_FOR_nothing will be returned. */ 440918334Speter 441018334Speterenum insn_code 4411132718Skancan_extend_p (enum machine_mode to_mode, enum machine_mode from_mode, 4412132718Skan int unsignedp) 441318334Speter{ 4414132718Skan convert_optab tab; 441590075Sobrien#ifdef HAVE_ptr_extend 441690075Sobrien if (unsignedp < 0) 441790075Sobrien return CODE_FOR_ptr_extend; 441890075Sobrien#endif 4419132718Skan 4420132718Skan tab = unsignedp ? zext_optab : sext_optab; 4421132718Skan return tab->handlers[to_mode][from_mode].insn_code; 442218334Speter} 442318334Speter 442418334Speter/* Generate the body of an insn to extend Y (with mode MFROM) 442518334Speter into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ 442618334Speter 442718334Speterrtx 4428132718Skangen_extend_insn (rtx x, rtx y, enum machine_mode mto, 4429132718Skan enum machine_mode mfrom, int unsignedp) 443018334Speter{ 4431132718Skan enum insn_code icode = can_extend_p (mto, mfrom, unsignedp); 4432132718Skan return GEN_FCN (icode) (x, y); 443318334Speter} 443418334Speter 443518334Speter/* can_fix_p and can_float_p say whether the target machine 443618334Speter can directly convert a given fixed point type to 443718334Speter a given floating point type, or vice versa. 443818334Speter The returned value is the CODE_FOR_... value to use, 443918334Speter or CODE_FOR_nothing if these modes cannot be directly converted. 444018334Speter 444118334Speter *TRUNCP_PTR is set to 1 if it is necessary to output 444218334Speter an explicit FTRUNC insn before the fix insn; otherwise 0. */ 444318334Speter 444418334Speterstatic enum insn_code 4445132718Skancan_fix_p (enum machine_mode fixmode, enum machine_mode fltmode, 4446132718Skan int unsignedp, int *truncp_ptr) 444718334Speter{ 4448132718Skan convert_optab tab; 4449132718Skan enum insn_code icode; 445018334Speter 4451132718Skan tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab; 4452132718Skan icode = tab->handlers[fixmode][fltmode].insn_code; 4453132718Skan if (icode != CODE_FOR_nothing) 445418334Speter { 4455132718Skan *truncp_ptr = 0; 4456132718Skan return icode; 4457132718Skan } 4458132718Skan 4459169689Skan /* FIXME: This requires a port to define both FIX and FTRUNC pattern 4460169689Skan for this to work. We need to rework the fix* and ftrunc* patterns 4461169689Skan and documentation. */ 4462132718Skan tab = unsignedp ? ufix_optab : sfix_optab; 4463132718Skan icode = tab->handlers[fixmode][fltmode].insn_code; 4464132718Skan if (icode != CODE_FOR_nothing 4465132718Skan && ftrunc_optab->handlers[fltmode].insn_code != CODE_FOR_nothing) 4466132718Skan { 446718334Speter *truncp_ptr = 1; 4468132718Skan return icode; 446918334Speter } 4470132718Skan 4471132718Skan *truncp_ptr = 0; 447218334Speter return CODE_FOR_nothing; 447318334Speter} 447418334Speter 447518334Speterstatic enum insn_code 4476132718Skancan_float_p (enum machine_mode fltmode, enum machine_mode fixmode, 4477132718Skan int unsignedp) 447818334Speter{ 4479132718Skan convert_optab tab; 4480132718Skan 4481132718Skan tab = unsignedp ? ufloat_optab : sfloat_optab; 4482132718Skan return tab->handlers[fltmode][fixmode].insn_code; 448318334Speter} 448418334Speter 448518334Speter/* Generate code to convert FROM to floating point 448618334Speter and store in TO. FROM must be fixed point and not VOIDmode. 448718334Speter UNSIGNEDP nonzero means regard FROM as unsigned. 448818334Speter Normally this is done by correcting the final value 448918334Speter if it is negative. */ 449018334Speter 449118334Spetervoid 4492132718Skanexpand_float (rtx to, rtx from, int unsignedp) 449318334Speter{ 449418334Speter enum insn_code icode; 449590075Sobrien rtx target = to; 449618334Speter enum machine_mode fmode, imode; 4497169689Skan bool can_do_signed = false; 449818334Speter 449918334Speter /* Crash now, because we won't be able to decide which mode to use. */ 4500169689Skan gcc_assert (GET_MODE (from) != VOIDmode); 450118334Speter 450218334Speter /* Look for an insn to do the conversion. Do it in the specified 450318334Speter modes if possible; otherwise convert either input, output or both to 450418334Speter wider mode. If the integer mode is wider than the mode of FROM, 450518334Speter we can do the conversion signed even if the input is unsigned. */ 450618334Speter 4507117395Skan for (fmode = GET_MODE (to); fmode != VOIDmode; 4508117395Skan fmode = GET_MODE_WIDER_MODE (fmode)) 4509117395Skan for (imode = GET_MODE (from); imode != VOIDmode; 4510117395Skan imode = GET_MODE_WIDER_MODE (imode)) 451118334Speter { 451218334Speter int doing_unsigned = unsignedp; 451318334Speter 451490075Sobrien if (fmode != GET_MODE (to) 451590075Sobrien && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from))) 451690075Sobrien continue; 451790075Sobrien 451818334Speter icode = can_float_p (fmode, imode, unsignedp); 4519169689Skan if (icode == CODE_FOR_nothing && unsignedp) 4520169689Skan { 4521169689Skan enum insn_code scode = can_float_p (fmode, imode, 0); 4522169689Skan if (scode != CODE_FOR_nothing) 4523169689Skan can_do_signed = true; 4524169689Skan if (imode != GET_MODE (from)) 4525169689Skan icode = scode, doing_unsigned = 0; 4526169689Skan } 452718334Speter 452818334Speter if (icode != CODE_FOR_nothing) 452918334Speter { 453018334Speter if (imode != GET_MODE (from)) 453118334Speter from = convert_to_mode (imode, from, unsignedp); 453218334Speter 453318334Speter if (fmode != GET_MODE (to)) 453418334Speter target = gen_reg_rtx (fmode); 453518334Speter 453618334Speter emit_unop_insn (icode, target, from, 453718334Speter doing_unsigned ? UNSIGNED_FLOAT : FLOAT); 453818334Speter 453918334Speter if (target != to) 454018334Speter convert_move (to, target, 0); 454118334Speter return; 454218334Speter } 4543117395Skan } 454418334Speter 4545169689Skan /* Unsigned integer, and no way to convert directly. For binary 4546169689Skan floating point modes, convert as signed, then conditionally adjust 4547169689Skan the result. */ 4548169689Skan if (unsignedp && can_do_signed && !DECIMAL_FLOAT_MODE_P (GET_MODE (to))) 454918334Speter { 455018334Speter rtx label = gen_label_rtx (); 455118334Speter rtx temp; 455218334Speter REAL_VALUE_TYPE offset; 455318334Speter 455418334Speter /* Look for a usable floating mode FMODE wider than the source and at 455518334Speter least as wide as the target. Using FMODE will avoid rounding woes 455618334Speter with unsigned values greater than the signed maximum value. */ 455718334Speter 455818334Speter for (fmode = GET_MODE (to); fmode != VOIDmode; 455918334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 456018334Speter if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode) 456118334Speter && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing) 456218334Speter break; 456318334Speter 456418334Speter if (fmode == VOIDmode) 456518334Speter { 456618334Speter /* There is no such mode. Pretend the target is wide enough. */ 456718334Speter fmode = GET_MODE (to); 456818334Speter 456950397Sobrien /* Avoid double-rounding when TO is narrower than FROM. */ 457018334Speter if ((significand_size (fmode) + 1) 457118334Speter < GET_MODE_BITSIZE (GET_MODE (from))) 457218334Speter { 457318334Speter rtx temp1; 457418334Speter rtx neglabel = gen_label_rtx (); 457518334Speter 4576132718Skan /* Don't use TARGET if it isn't a register, is a hard register, 457718334Speter or is the wrong mode. */ 4578169689Skan if (!REG_P (target) 457918334Speter || REGNO (target) < FIRST_PSEUDO_REGISTER 458018334Speter || GET_MODE (target) != fmode) 458118334Speter target = gen_reg_rtx (fmode); 458218334Speter 458318334Speter imode = GET_MODE (from); 458418334Speter do_pending_stack_adjust (); 458518334Speter 458618334Speter /* Test whether the sign bit is set. */ 458790075Sobrien emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode, 458890075Sobrien 0, neglabel); 458918334Speter 459018334Speter /* The sign bit is not set. Convert as signed. */ 459118334Speter expand_float (target, from, 0); 459218334Speter emit_jump_insn (gen_jump (label)); 459318334Speter emit_barrier (); 459418334Speter 459518334Speter /* The sign bit is set. 459618334Speter Convert to a usable (positive signed) value by shifting right 459718334Speter one bit, while remembering if a nonzero bit was shifted 459818334Speter out; i.e., compute (from & 1) | (from >> 1). */ 459918334Speter 460018334Speter emit_label (neglabel); 460118334Speter temp = expand_binop (imode, and_optab, from, const1_rtx, 460218334Speter NULL_RTX, 1, OPTAB_LIB_WIDEN); 460318334Speter temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node, 460418334Speter NULL_RTX, 1); 4605132718Skan temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1, 460618334Speter OPTAB_LIB_WIDEN); 460718334Speter expand_float (target, temp, 0); 460818334Speter 460918334Speter /* Multiply by 2 to undo the shift above. */ 461018334Speter temp = expand_binop (fmode, add_optab, target, target, 4611117395Skan target, 0, OPTAB_LIB_WIDEN); 461218334Speter if (temp != target) 461318334Speter emit_move_insn (target, temp); 461418334Speter 461518334Speter do_pending_stack_adjust (); 461618334Speter emit_label (label); 461718334Speter goto done; 461818334Speter } 461918334Speter } 462018334Speter 462118334Speter /* If we are about to do some arithmetic to correct for an 462218334Speter unsigned operand, do it in a pseudo-register. */ 462318334Speter 462418334Speter if (GET_MODE (to) != fmode 4625169689Skan || !REG_P (to) || REGNO (to) < FIRST_PSEUDO_REGISTER) 462618334Speter target = gen_reg_rtx (fmode); 462718334Speter 462818334Speter /* Convert as signed integer to floating. */ 462918334Speter expand_float (target, from, 0); 463018334Speter 463118334Speter /* If FROM is negative (and therefore TO is negative), 463218334Speter correct its value by 2**bitwidth. */ 463318334Speter 463418334Speter do_pending_stack_adjust (); 463552284Sobrien emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 463690075Sobrien 0, label); 463718334Speter 4638132718Skan 4639117395Skan real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from))); 464018334Speter temp = expand_binop (fmode, add_optab, target, 464118334Speter CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode), 464218334Speter target, 0, OPTAB_LIB_WIDEN); 464318334Speter if (temp != target) 464418334Speter emit_move_insn (target, temp); 464518334Speter 464618334Speter do_pending_stack_adjust (); 464718334Speter emit_label (label); 464818334Speter goto done; 464918334Speter } 465018334Speter 4651132718Skan /* No hardware instruction available; call a library routine. */ 465218334Speter { 4653132718Skan rtx libfunc; 465418334Speter rtx insns; 465518334Speter rtx value; 4656132718Skan convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab; 465718334Speter 465818334Speter if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) 465918334Speter from = convert_to_mode (SImode, from, unsignedp); 466018334Speter 4661132718Skan libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc; 4662169689Skan gcc_assert (libfunc); 466318334Speter 466418334Speter start_sequence (); 466518334Speter 4666132718Skan value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, 466790075Sobrien GET_MODE (to), 1, from, 466890075Sobrien GET_MODE (from)); 466918334Speter insns = get_insns (); 467018334Speter end_sequence (); 467118334Speter 467218334Speter emit_libcall_block (insns, target, value, 467350397Sobrien gen_rtx_FLOAT (GET_MODE (to), from)); 467418334Speter } 467518334Speter 467618334Speter done: 467718334Speter 467818334Speter /* Copy result to requested destination 467918334Speter if we have been computing in a temp location. */ 468018334Speter 468118334Speter if (target != to) 468218334Speter { 468318334Speter if (GET_MODE (target) == GET_MODE (to)) 468418334Speter emit_move_insn (to, target); 468518334Speter else 468618334Speter convert_move (to, target, 0); 468718334Speter } 468818334Speter} 468918334Speter 4690169689Skan/* Generate code to convert FROM to fixed point and store in TO. FROM 4691169689Skan must be floating point. */ 469218334Speter 469318334Spetervoid 4694132718Skanexpand_fix (rtx to, rtx from, int unsignedp) 469518334Speter{ 469618334Speter enum insn_code icode; 469790075Sobrien rtx target = to; 469818334Speter enum machine_mode fmode, imode; 469918334Speter int must_trunc = 0; 470018334Speter 470118334Speter /* We first try to find a pair of modes, one real and one integer, at 470218334Speter least as wide as FROM and TO, respectively, in which we can open-code 470318334Speter this conversion. If the integer mode is wider than the mode of TO, 470418334Speter we can do the conversion either signed or unsigned. */ 470518334Speter 470690075Sobrien for (fmode = GET_MODE (from); fmode != VOIDmode; 470790075Sobrien fmode = GET_MODE_WIDER_MODE (fmode)) 470890075Sobrien for (imode = GET_MODE (to); imode != VOIDmode; 470990075Sobrien imode = GET_MODE_WIDER_MODE (imode)) 471018334Speter { 471118334Speter int doing_unsigned = unsignedp; 471218334Speter 471318334Speter icode = can_fix_p (imode, fmode, unsignedp, &must_trunc); 471418334Speter if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp) 471518334Speter icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0; 471618334Speter 471718334Speter if (icode != CODE_FOR_nothing) 471818334Speter { 471918334Speter if (fmode != GET_MODE (from)) 472018334Speter from = convert_to_mode (fmode, from, 0); 472118334Speter 472218334Speter if (must_trunc) 4723169689Skan { 4724169689Skan rtx temp = gen_reg_rtx (GET_MODE (from)); 4725169689Skan from = expand_unop (GET_MODE (from), ftrunc_optab, from, 4726169689Skan temp, 0); 4727169689Skan } 472818334Speter 472918334Speter if (imode != GET_MODE (to)) 473018334Speter target = gen_reg_rtx (imode); 473118334Speter 473218334Speter emit_unop_insn (icode, target, from, 473318334Speter doing_unsigned ? UNSIGNED_FIX : FIX); 473418334Speter if (target != to) 473518334Speter convert_move (to, target, unsignedp); 473618334Speter return; 473718334Speter } 473818334Speter } 473918334Speter 474018334Speter /* For an unsigned conversion, there is one more way to do it. 474118334Speter If we have a signed conversion, we generate code that compares 474218334Speter the real value to the largest representable positive number. If if 474318334Speter is smaller, the conversion is done normally. Otherwise, subtract 474418334Speter one plus the highest signed number, convert, and add it back. 474518334Speter 474618334Speter We only need to check all real modes, since we know we didn't find 4747132718Skan anything with a wider integer mode. 474818334Speter 4749132718Skan This code used to extend FP value into mode wider than the destination. 4750132718Skan This is not needed. Consider, for instance conversion from SFmode 4751132718Skan into DImode. 4752132718Skan 4753169689Skan The hot path through the code is dealing with inputs smaller than 2^63 4754132718Skan and doing just the conversion, so there is no bits to lose. 4755132718Skan 4756132718Skan In the other path we know the value is positive in the range 2^63..2^64-1 4757132718Skan inclusive. (as for other imput overflow happens and result is undefined) 4758132718Skan So we know that the most important bit set in mantissa corresponds to 4759132718Skan 2^63. The subtraction of 2^63 should not generate any rounding as it 4760132718Skan simply clears out that bit. The rest is trivial. */ 4761132718Skan 476218334Speter if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT) 476318334Speter for (fmode = GET_MODE (from); fmode != VOIDmode; 476418334Speter fmode = GET_MODE_WIDER_MODE (fmode)) 4765132718Skan if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, 4766132718Skan &must_trunc)) 476718334Speter { 476818334Speter int bitsize; 476918334Speter REAL_VALUE_TYPE offset; 477018334Speter rtx limit, lab1, lab2, insn; 477118334Speter 477218334Speter bitsize = GET_MODE_BITSIZE (GET_MODE (to)); 4773117395Skan real_2expN (&offset, bitsize - 1); 477418334Speter limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode); 477518334Speter lab1 = gen_label_rtx (); 477618334Speter lab2 = gen_label_rtx (); 477718334Speter 477818334Speter if (fmode != GET_MODE (from)) 477918334Speter from = convert_to_mode (fmode, from, 0); 478018334Speter 478118334Speter /* See if we need to do the subtraction. */ 478218334Speter do_pending_stack_adjust (); 478352284Sobrien emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from), 478490075Sobrien 0, lab1); 478518334Speter 478618334Speter /* If not, do the signed "fix" and branch around fixup code. */ 478718334Speter expand_fix (to, from, 0); 478818334Speter emit_jump_insn (gen_jump (lab2)); 478918334Speter emit_barrier (); 479018334Speter 479118334Speter /* Otherwise, subtract 2**(N-1), convert to signed number, 479218334Speter then add 2**(N-1). Do the addition using XOR since this 479318334Speter will often generate better code. */ 479418334Speter emit_label (lab1); 479518334Speter target = expand_binop (GET_MODE (from), sub_optab, from, limit, 479618334Speter NULL_RTX, 0, OPTAB_LIB_WIDEN); 479718334Speter expand_fix (to, target, 0); 479818334Speter target = expand_binop (GET_MODE (to), xor_optab, to, 4799117395Skan gen_int_mode 4800117395Skan ((HOST_WIDE_INT) 1 << (bitsize - 1), 4801117395Skan GET_MODE (to)), 480218334Speter to, 1, OPTAB_LIB_WIDEN); 480318334Speter 480418334Speter if (target != to) 480518334Speter emit_move_insn (to, target); 480618334Speter 480718334Speter emit_label (lab2); 480818334Speter 480950397Sobrien if (mov_optab->handlers[(int) GET_MODE (to)].insn_code 481050397Sobrien != CODE_FOR_nothing) 481150397Sobrien { 481250397Sobrien /* Make a place for a REG_NOTE and add it. */ 481350397Sobrien insn = emit_move_insn (to, to); 481452284Sobrien set_unique_reg_note (insn, 481552284Sobrien REG_EQUAL, 481652284Sobrien gen_rtx_fmt_e (UNSIGNED_FIX, 481752284Sobrien GET_MODE (to), 481852284Sobrien copy_rtx (from))); 481950397Sobrien } 482090075Sobrien 482118334Speter return; 482218334Speter } 482318334Speter 482418334Speter /* We can't do it with an insn, so use a library call. But first ensure 482518334Speter that the mode of TO is at least as wide as SImode, since those are the 482618334Speter only library calls we know about. */ 482718334Speter 482818334Speter if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode)) 482918334Speter { 483018334Speter target = gen_reg_rtx (SImode); 483118334Speter 483218334Speter expand_fix (target, from, unsignedp); 483318334Speter } 483418334Speter else 483518334Speter { 483618334Speter rtx insns; 483718334Speter rtx value; 4838132718Skan rtx libfunc; 4839169689Skan 4840132718Skan convert_optab tab = unsignedp ? ufix_optab : sfix_optab; 4841132718Skan libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc; 4842169689Skan gcc_assert (libfunc); 484318334Speter 484418334Speter start_sequence (); 484518334Speter 4846132718Skan value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, 484790075Sobrien GET_MODE (to), 1, from, 484890075Sobrien GET_MODE (from)); 484918334Speter insns = get_insns (); 485018334Speter end_sequence (); 485118334Speter 485218334Speter emit_libcall_block (insns, target, value, 485350397Sobrien gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX, 485450397Sobrien GET_MODE (to), from)); 485518334Speter } 4856132718Skan 485750397Sobrien if (target != to) 485850397Sobrien { 485950397Sobrien if (GET_MODE (to) == GET_MODE (target)) 486050397Sobrien emit_move_insn (to, target); 486150397Sobrien else 486250397Sobrien convert_move (to, target, 0); 486350397Sobrien } 486418334Speter} 486518334Speter 486690075Sobrien/* Report whether we have an instruction to perform the operation 486790075Sobrien specified by CODE on operands of mode MODE. */ 486890075Sobrienint 4869132718Skanhave_insn_for (enum rtx_code code, enum machine_mode mode) 487018334Speter{ 487190075Sobrien return (code_to_optab[(int) code] != 0 487290075Sobrien && (code_to_optab[(int) code]->handlers[(int) mode].insn_code 487390075Sobrien != CODE_FOR_nothing)); 487490075Sobrien} 487590075Sobrien 487690075Sobrien/* Create a blank optab. */ 487790075Sobrienstatic optab 4878132718Skannew_optab (void) 487990075Sobrien{ 488018334Speter int i; 4881132718Skan optab op = ggc_alloc (sizeof (struct optab)); 488218334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 488318334Speter { 488418334Speter op->handlers[i].insn_code = CODE_FOR_nothing; 488518334Speter op->handlers[i].libfunc = 0; 488618334Speter } 488718334Speter 488890075Sobrien return op; 488990075Sobrien} 489018334Speter 4891132718Skanstatic convert_optab 4892132718Skannew_convert_optab (void) 4893132718Skan{ 4894132718Skan int i, j; 4895132718Skan convert_optab op = ggc_alloc (sizeof (struct convert_optab)); 4896132718Skan for (i = 0; i < NUM_MACHINE_MODES; i++) 4897132718Skan for (j = 0; j < NUM_MACHINE_MODES; j++) 4898132718Skan { 4899132718Skan op->handlers[i][j].insn_code = CODE_FOR_nothing; 4900132718Skan op->handlers[i][j].libfunc = 0; 4901132718Skan } 4902132718Skan return op; 4903132718Skan} 4904132718Skan 490590075Sobrien/* Same, but fill in its code as CODE, and write it into the 490690075Sobrien code_to_optab table. */ 490790075Sobrienstatic inline optab 4908132718Skaninit_optab (enum rtx_code code) 490990075Sobrien{ 491090075Sobrien optab op = new_optab (); 491190075Sobrien op->code = code; 491290075Sobrien code_to_optab[(int) code] = op; 491318334Speter return op; 491418334Speter} 491518334Speter 491690075Sobrien/* Same, but fill in its code as CODE, and do _not_ write it into 491790075Sobrien the code_to_optab table. */ 491890075Sobrienstatic inline optab 4919132718Skaninit_optabv (enum rtx_code code) 492090075Sobrien{ 492190075Sobrien optab op = new_optab (); 492290075Sobrien op->code = code; 492390075Sobrien return op; 492490075Sobrien} 492590075Sobrien 4926132718Skan/* Conversion optabs never go in the code_to_optab table. */ 4927132718Skanstatic inline convert_optab 4928132718Skaninit_convert_optab (enum rtx_code code) 4929132718Skan{ 4930132718Skan convert_optab op = new_convert_optab (); 4931132718Skan op->code = code; 4932132718Skan return op; 4933132718Skan} 4934132718Skan 493518334Speter/* Initialize the libfunc fields of an entire group of entries in some 493618334Speter optab. Each entry is set equal to a string consisting of a leading 493718334Speter pair of underscores followed by a generic operation name followed by 4938132718Skan a mode name (downshifted to lowercase) followed by a single character 493918334Speter representing the number of operands for the given operation (which is 494018334Speter usually one of the characters '2', '3', or '4'). 494118334Speter 494218334Speter OPTABLE is the table in which libfunc fields are to be initialized. 494318334Speter FIRST_MODE is the first machine mode index in the given optab to 494418334Speter initialize. 494518334Speter LAST_MODE is the last machine mode index in the given optab to 494618334Speter initialize. 494718334Speter OPNAME is the generic (string) name of the operation. 494818334Speter SUFFIX is the character which specifies the number of operands for 494918334Speter the given generic operation. 495018334Speter*/ 495118334Speter 495218334Speterstatic void 4953132718Skaninit_libfuncs (optab optable, int first_mode, int last_mode, 4954132718Skan const char *opname, int suffix) 495518334Speter{ 495690075Sobrien int mode; 495790075Sobrien unsigned opname_len = strlen (opname); 495818334Speter 495918334Speter for (mode = first_mode; (int) mode <= (int) last_mode; 496018334Speter mode = (enum machine_mode) ((int) mode + 1)) 496118334Speter { 4962117395Skan const char *mname = GET_MODE_NAME (mode); 496390075Sobrien unsigned mname_len = strlen (mname); 496490075Sobrien char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1); 496590075Sobrien char *p; 496690075Sobrien const char *q; 496718334Speter 496818334Speter p = libfunc_name; 496918334Speter *p++ = '_'; 497018334Speter *p++ = '_'; 497118334Speter for (q = opname; *q; ) 497218334Speter *p++ = *q++; 497318334Speter for (q = mname; *q; q++) 497490075Sobrien *p++ = TOLOWER (*q); 497518334Speter *p++ = suffix; 497690075Sobrien *p = '\0'; 497790075Sobrien 497818334Speter optable->handlers[(int) mode].libfunc 4979132718Skan = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name)); 498018334Speter } 498118334Speter} 498218334Speter 498318334Speter/* Initialize the libfunc fields of an entire group of entries in some 498418334Speter optab which correspond to all integer mode operations. The parameters 498518334Speter have the same meaning as similarly named ones for the `init_libfuncs' 498618334Speter routine. (See above). */ 498718334Speter 498818334Speterstatic void 4989132718Skaninit_integral_libfuncs (optab optable, const char *opname, int suffix) 499018334Speter{ 4991132718Skan int maxsize = 2*BITS_PER_WORD; 4992132718Skan if (maxsize < LONG_LONG_TYPE_SIZE) 4993132718Skan maxsize = LONG_LONG_TYPE_SIZE; 4994132718Skan init_libfuncs (optable, word_mode, 4995132718Skan mode_for_size (maxsize, MODE_INT, 0), 4996132718Skan opname, suffix); 499718334Speter} 499818334Speter 499918334Speter/* Initialize the libfunc fields of an entire group of entries in some 500018334Speter optab which correspond to all real mode operations. The parameters 500118334Speter have the same meaning as similarly named ones for the `init_libfuncs' 500218334Speter routine. (See above). */ 500318334Speter 500418334Speterstatic void 5005132718Skaninit_floating_libfuncs (optab optable, const char *opname, int suffix) 500618334Speter{ 5007132718Skan init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix); 5008169689Skan init_libfuncs (optable, MIN_MODE_DECIMAL_FLOAT, MAX_MODE_DECIMAL_FLOAT, 5009169689Skan opname, suffix); 501018334Speter} 501118334Speter 5012132718Skan/* Initialize the libfunc fields of an entire group of entries of an 5013132718Skan inter-mode-class conversion optab. The string formation rules are 5014132718Skan similar to the ones for init_libfuncs, above, but instead of having 5015132718Skan a mode name and an operand count these functions have two mode names 5016132718Skan and no operand count. */ 5017132718Skanstatic void 5018132718Skaninit_interclass_conv_libfuncs (convert_optab tab, const char *opname, 5019132718Skan enum mode_class from_class, 5020132718Skan enum mode_class to_class) 5021132718Skan{ 5022132718Skan enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class); 5023132718Skan enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class); 5024132718Skan size_t opname_len = strlen (opname); 5025132718Skan size_t max_mname_len = 0; 5026132718Skan 5027132718Skan enum machine_mode fmode, tmode; 5028132718Skan const char *fname, *tname; 5029132718Skan const char *q; 5030132718Skan char *libfunc_name, *suffix; 5031132718Skan char *p; 5032132718Skan 5033132718Skan for (fmode = first_from_mode; 5034132718Skan fmode != VOIDmode; 5035132718Skan fmode = GET_MODE_WIDER_MODE (fmode)) 5036132718Skan max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode))); 5037132718Skan 5038132718Skan for (tmode = first_to_mode; 5039132718Skan tmode != VOIDmode; 5040132718Skan tmode = GET_MODE_WIDER_MODE (tmode)) 5041132718Skan max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode))); 5042132718Skan 5043132718Skan libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1); 5044132718Skan libfunc_name[0] = '_'; 5045132718Skan libfunc_name[1] = '_'; 5046132718Skan memcpy (&libfunc_name[2], opname, opname_len); 5047132718Skan suffix = libfunc_name + opname_len + 2; 5048132718Skan 5049132718Skan for (fmode = first_from_mode; fmode != VOIDmode; 5050132718Skan fmode = GET_MODE_WIDER_MODE (fmode)) 5051132718Skan for (tmode = first_to_mode; tmode != VOIDmode; 5052132718Skan tmode = GET_MODE_WIDER_MODE (tmode)) 5053132718Skan { 5054132718Skan fname = GET_MODE_NAME (fmode); 5055132718Skan tname = GET_MODE_NAME (tmode); 5056132718Skan 5057132718Skan p = suffix; 5058132718Skan for (q = fname; *q; p++, q++) 5059132718Skan *p = TOLOWER (*q); 5060132718Skan for (q = tname; *q; p++, q++) 5061132718Skan *p = TOLOWER (*q); 5062132718Skan 5063132718Skan *p = '\0'; 5064132718Skan 5065132718Skan tab->handlers[tmode][fmode].libfunc 5066132718Skan = init_one_libfunc (ggc_alloc_string (libfunc_name, 5067132718Skan p - libfunc_name)); 5068132718Skan } 5069132718Skan} 5070132718Skan 5071132718Skan/* Initialize the libfunc fields of an entire group of entries of an 5072132718Skan intra-mode-class conversion optab. The string formation rules are 5073132718Skan similar to the ones for init_libfunc, above. WIDENING says whether 5074132718Skan the optab goes from narrow to wide modes or vice versa. These functions 5075132718Skan have two mode names _and_ an operand count. */ 5076132718Skanstatic void 5077132718Skaninit_intraclass_conv_libfuncs (convert_optab tab, const char *opname, 5078132718Skan enum mode_class class, bool widening) 5079132718Skan{ 5080132718Skan enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class); 5081132718Skan size_t opname_len = strlen (opname); 5082132718Skan size_t max_mname_len = 0; 5083132718Skan 5084132718Skan enum machine_mode nmode, wmode; 5085132718Skan const char *nname, *wname; 5086132718Skan const char *q; 5087132718Skan char *libfunc_name, *suffix; 5088132718Skan char *p; 5089132718Skan 5090132718Skan for (nmode = first_mode; nmode != VOIDmode; 5091132718Skan nmode = GET_MODE_WIDER_MODE (nmode)) 5092132718Skan max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode))); 5093132718Skan 5094132718Skan libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1); 5095132718Skan libfunc_name[0] = '_'; 5096132718Skan libfunc_name[1] = '_'; 5097132718Skan memcpy (&libfunc_name[2], opname, opname_len); 5098132718Skan suffix = libfunc_name + opname_len + 2; 5099132718Skan 5100132718Skan for (nmode = first_mode; nmode != VOIDmode; 5101132718Skan nmode = GET_MODE_WIDER_MODE (nmode)) 5102132718Skan for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode; 5103132718Skan wmode = GET_MODE_WIDER_MODE (wmode)) 5104132718Skan { 5105132718Skan nname = GET_MODE_NAME (nmode); 5106132718Skan wname = GET_MODE_NAME (wmode); 5107132718Skan 5108132718Skan p = suffix; 5109132718Skan for (q = widening ? nname : wname; *q; p++, q++) 5110132718Skan *p = TOLOWER (*q); 5111132718Skan for (q = widening ? wname : nname; *q; p++, q++) 5112132718Skan *p = TOLOWER (*q); 5113132718Skan 5114132718Skan *p++ = '2'; 5115132718Skan *p = '\0'; 5116132718Skan 5117132718Skan tab->handlers[widening ? wmode : nmode] 5118132718Skan [widening ? nmode : wmode].libfunc 5119132718Skan = init_one_libfunc (ggc_alloc_string (libfunc_name, 5120132718Skan p - libfunc_name)); 5121132718Skan } 5122132718Skan} 5123132718Skan 5124132718Skan 512590075Sobrienrtx 5126132718Skaninit_one_libfunc (const char *name) 512790075Sobrien{ 5128132718Skan rtx symbol; 5129132718Skan 5130117395Skan /* Create a FUNCTION_DECL that can be passed to 5131117395Skan targetm.encode_section_info. */ 513290075Sobrien /* ??? We don't have any type information except for this is 513390075Sobrien a function. Pretend this is "int foo()". */ 513490075Sobrien tree decl = build_decl (FUNCTION_DECL, get_identifier (name), 513590075Sobrien build_function_type (integer_type_node, NULL_TREE)); 513690075Sobrien DECL_ARTIFICIAL (decl) = 1; 513790075Sobrien DECL_EXTERNAL (decl) = 1; 513890075Sobrien TREE_PUBLIC (decl) = 1; 513918334Speter 5140132718Skan symbol = XEXP (DECL_RTL (decl), 0); 5141132718Skan 5142132718Skan /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with 5143132718Skan are the flags assigned by targetm.encode_section_info. */ 5144169689Skan SET_SYMBOL_REF_DECL (symbol, 0); 5145132718Skan 5146132718Skan return symbol; 514790075Sobrien} 514890075Sobrien 5149132718Skan/* Call this to reset the function entry for one optab (OPTABLE) in mode 5150132718Skan MODE to NAME, which should be either 0 or a string constant. */ 5151132718Skanvoid 5152132718Skanset_optab_libfunc (optab optable, enum machine_mode mode, const char *name) 5153132718Skan{ 5154132718Skan if (name) 5155132718Skan optable->handlers[mode].libfunc = init_one_libfunc (name); 5156132718Skan else 5157132718Skan optable->handlers[mode].libfunc = 0; 5158132718Skan} 5159132718Skan 5160132718Skan/* Call this to reset the function entry for one conversion optab 5161132718Skan (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be 5162132718Skan either 0 or a string constant. */ 5163132718Skanvoid 5164132718Skanset_conv_libfunc (convert_optab optable, enum machine_mode tmode, 5165132718Skan enum machine_mode fmode, const char *name) 5166132718Skan{ 5167132718Skan if (name) 5168132718Skan optable->handlers[tmode][fmode].libfunc = init_one_libfunc (name); 5169132718Skan else 5170132718Skan optable->handlers[tmode][fmode].libfunc = 0; 5171132718Skan} 5172132718Skan 517318334Speter/* Call this once to initialize the contents of the optabs 517418334Speter appropriately for the current target machine. */ 517518334Speter 517618334Spetervoid 5177132718Skaninit_optabs (void) 517818334Speter{ 5179132718Skan unsigned int i; 518050397Sobrien 518118334Speter /* Start by initializing all tables to contain CODE_FOR_nothing. */ 518218334Speter 518318334Speter for (i = 0; i < NUM_RTX_CODE; i++) 518418334Speter setcc_gen_code[i] = CODE_FOR_nothing; 518518334Speter 518618334Speter#ifdef HAVE_conditional_move 518718334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 518818334Speter movcc_gen_code[i] = CODE_FOR_nothing; 518918334Speter#endif 519018334Speter 5191169689Skan for (i = 0; i < NUM_MACHINE_MODES; i++) 5192169689Skan { 5193169689Skan vcond_gen_code[i] = CODE_FOR_nothing; 5194169689Skan vcondu_gen_code[i] = CODE_FOR_nothing; 5195169689Skan } 5196169689Skan 519718334Speter add_optab = init_optab (PLUS); 519890075Sobrien addv_optab = init_optabv (PLUS); 519918334Speter sub_optab = init_optab (MINUS); 520090075Sobrien subv_optab = init_optabv (MINUS); 520118334Speter smul_optab = init_optab (MULT); 520290075Sobrien smulv_optab = init_optabv (MULT); 520318334Speter smul_highpart_optab = init_optab (UNKNOWN); 520418334Speter umul_highpart_optab = init_optab (UNKNOWN); 520518334Speter smul_widen_optab = init_optab (UNKNOWN); 520618334Speter umul_widen_optab = init_optab (UNKNOWN); 5207169689Skan usmul_widen_optab = init_optab (UNKNOWN); 520818334Speter sdiv_optab = init_optab (DIV); 520990075Sobrien sdivv_optab = init_optabv (DIV); 521018334Speter sdivmod_optab = init_optab (UNKNOWN); 521118334Speter udiv_optab = init_optab (UDIV); 521218334Speter udivmod_optab = init_optab (UNKNOWN); 521318334Speter smod_optab = init_optab (MOD); 521418334Speter umod_optab = init_optab (UMOD); 5215169689Skan fmod_optab = init_optab (UNKNOWN); 5216169689Skan drem_optab = init_optab (UNKNOWN); 521718334Speter ftrunc_optab = init_optab (UNKNOWN); 521818334Speter and_optab = init_optab (AND); 521918334Speter ior_optab = init_optab (IOR); 522018334Speter xor_optab = init_optab (XOR); 522118334Speter ashl_optab = init_optab (ASHIFT); 522218334Speter ashr_optab = init_optab (ASHIFTRT); 522318334Speter lshr_optab = init_optab (LSHIFTRT); 522418334Speter rotl_optab = init_optab (ROTATE); 522518334Speter rotr_optab = init_optab (ROTATERT); 522618334Speter smin_optab = init_optab (SMIN); 522718334Speter smax_optab = init_optab (SMAX); 522818334Speter umin_optab = init_optab (UMIN); 522918334Speter umax_optab = init_optab (UMAX); 5230132718Skan pow_optab = init_optab (UNKNOWN); 5231132718Skan atan2_optab = init_optab (UNKNOWN); 523290075Sobrien 523390075Sobrien /* These three have codes assigned exclusively for the sake of 523490075Sobrien have_insn_for. */ 523590075Sobrien mov_optab = init_optab (SET); 523690075Sobrien movstrict_optab = init_optab (STRICT_LOW_PART); 523790075Sobrien cmp_optab = init_optab (COMPARE); 523890075Sobrien 523918334Speter ucmp_optab = init_optab (UNKNOWN); 524018334Speter tst_optab = init_optab (UNKNOWN); 5241132718Skan 5242132718Skan eq_optab = init_optab (EQ); 5243132718Skan ne_optab = init_optab (NE); 5244132718Skan gt_optab = init_optab (GT); 5245132718Skan ge_optab = init_optab (GE); 5246132718Skan lt_optab = init_optab (LT); 5247132718Skan le_optab = init_optab (LE); 5248132718Skan unord_optab = init_optab (UNORDERED); 5249132718Skan 525018334Speter neg_optab = init_optab (NEG); 525190075Sobrien negv_optab = init_optabv (NEG); 525218334Speter abs_optab = init_optab (ABS); 525390075Sobrien absv_optab = init_optabv (ABS); 5254132718Skan addcc_optab = init_optab (UNKNOWN); 525518334Speter one_cmpl_optab = init_optab (NOT); 525618334Speter ffs_optab = init_optab (FFS); 5257132718Skan clz_optab = init_optab (CLZ); 5258132718Skan ctz_optab = init_optab (CTZ); 5259132718Skan popcount_optab = init_optab (POPCOUNT); 5260132718Skan parity_optab = init_optab (PARITY); 526118334Speter sqrt_optab = init_optab (SQRT); 5262132718Skan floor_optab = init_optab (UNKNOWN); 5263169689Skan lfloor_optab = init_optab (UNKNOWN); 5264132718Skan ceil_optab = init_optab (UNKNOWN); 5265169689Skan lceil_optab = init_optab (UNKNOWN); 5266132718Skan round_optab = init_optab (UNKNOWN); 5267132718Skan btrunc_optab = init_optab (UNKNOWN); 5268132718Skan nearbyint_optab = init_optab (UNKNOWN); 5269169689Skan rint_optab = init_optab (UNKNOWN); 5270169689Skan lrint_optab = init_optab (UNKNOWN); 5271169689Skan sincos_optab = init_optab (UNKNOWN); 527218334Speter sin_optab = init_optab (UNKNOWN); 5273169689Skan asin_optab = init_optab (UNKNOWN); 527418334Speter cos_optab = init_optab (UNKNOWN); 5275169689Skan acos_optab = init_optab (UNKNOWN); 5276117395Skan exp_optab = init_optab (UNKNOWN); 5277169689Skan exp10_optab = init_optab (UNKNOWN); 5278169689Skan exp2_optab = init_optab (UNKNOWN); 5279169689Skan expm1_optab = init_optab (UNKNOWN); 5280169689Skan ldexp_optab = init_optab (UNKNOWN); 5281169689Skan logb_optab = init_optab (UNKNOWN); 5282169689Skan ilogb_optab = init_optab (UNKNOWN); 5283117395Skan log_optab = init_optab (UNKNOWN); 5284169689Skan log10_optab = init_optab (UNKNOWN); 5285169689Skan log2_optab = init_optab (UNKNOWN); 5286169689Skan log1p_optab = init_optab (UNKNOWN); 5287132718Skan tan_optab = init_optab (UNKNOWN); 5288132718Skan atan_optab = init_optab (UNKNOWN); 5289169689Skan copysign_optab = init_optab (UNKNOWN); 5290169689Skan 529118334Speter strlen_optab = init_optab (UNKNOWN); 529290075Sobrien cbranch_optab = init_optab (UNKNOWN); 529390075Sobrien cmov_optab = init_optab (UNKNOWN); 529490075Sobrien cstore_optab = init_optab (UNKNOWN); 529590075Sobrien push_optab = init_optab (UNKNOWN); 529618334Speter 5297169689Skan reduc_smax_optab = init_optab (UNKNOWN); 5298169689Skan reduc_umax_optab = init_optab (UNKNOWN); 5299169689Skan reduc_smin_optab = init_optab (UNKNOWN); 5300169689Skan reduc_umin_optab = init_optab (UNKNOWN); 5301169689Skan reduc_splus_optab = init_optab (UNKNOWN); 5302169689Skan reduc_uplus_optab = init_optab (UNKNOWN); 5303169689Skan 5304169689Skan ssum_widen_optab = init_optab (UNKNOWN); 5305169689Skan usum_widen_optab = init_optab (UNKNOWN); 5306169689Skan sdot_prod_optab = init_optab (UNKNOWN); 5307169689Skan udot_prod_optab = init_optab (UNKNOWN); 5308169689Skan 5309132718Skan vec_extract_optab = init_optab (UNKNOWN); 5310132718Skan vec_set_optab = init_optab (UNKNOWN); 5311132718Skan vec_init_optab = init_optab (UNKNOWN); 5312169689Skan vec_shl_optab = init_optab (UNKNOWN); 5313169689Skan vec_shr_optab = init_optab (UNKNOWN); 5314169689Skan vec_realign_load_optab = init_optab (UNKNOWN); 5315169689Skan movmisalign_optab = init_optab (UNKNOWN); 5316169689Skan 5317169689Skan powi_optab = init_optab (UNKNOWN); 5318169689Skan 5319132718Skan /* Conversions. */ 5320132718Skan sext_optab = init_convert_optab (SIGN_EXTEND); 5321132718Skan zext_optab = init_convert_optab (ZERO_EXTEND); 5322132718Skan trunc_optab = init_convert_optab (TRUNCATE); 5323132718Skan sfix_optab = init_convert_optab (FIX); 5324132718Skan ufix_optab = init_convert_optab (UNSIGNED_FIX); 5325132718Skan sfixtrunc_optab = init_convert_optab (UNKNOWN); 5326132718Skan ufixtrunc_optab = init_convert_optab (UNKNOWN); 5327132718Skan sfloat_optab = init_convert_optab (FLOAT); 5328132718Skan ufloat_optab = init_convert_optab (UNSIGNED_FLOAT); 5329132718Skan 533018334Speter for (i = 0; i < NUM_MACHINE_MODES; i++) 533118334Speter { 5332169689Skan movmem_optab[i] = CODE_FOR_nothing; 5333132718Skan cmpstr_optab[i] = CODE_FOR_nothing; 5334169689Skan cmpstrn_optab[i] = CODE_FOR_nothing; 5335132718Skan cmpmem_optab[i] = CODE_FOR_nothing; 5336169689Skan setmem_optab[i] = CODE_FOR_nothing; 533718334Speter 5338169689Skan sync_add_optab[i] = CODE_FOR_nothing; 5339169689Skan sync_sub_optab[i] = CODE_FOR_nothing; 5340169689Skan sync_ior_optab[i] = CODE_FOR_nothing; 5341169689Skan sync_and_optab[i] = CODE_FOR_nothing; 5342169689Skan sync_xor_optab[i] = CODE_FOR_nothing; 5343169689Skan sync_nand_optab[i] = CODE_FOR_nothing; 5344169689Skan sync_old_add_optab[i] = CODE_FOR_nothing; 5345169689Skan sync_old_sub_optab[i] = CODE_FOR_nothing; 5346169689Skan sync_old_ior_optab[i] = CODE_FOR_nothing; 5347169689Skan sync_old_and_optab[i] = CODE_FOR_nothing; 5348169689Skan sync_old_xor_optab[i] = CODE_FOR_nothing; 5349169689Skan sync_old_nand_optab[i] = CODE_FOR_nothing; 5350169689Skan sync_new_add_optab[i] = CODE_FOR_nothing; 5351169689Skan sync_new_sub_optab[i] = CODE_FOR_nothing; 5352169689Skan sync_new_ior_optab[i] = CODE_FOR_nothing; 5353169689Skan sync_new_and_optab[i] = CODE_FOR_nothing; 5354169689Skan sync_new_xor_optab[i] = CODE_FOR_nothing; 5355169689Skan sync_new_nand_optab[i] = CODE_FOR_nothing; 5356169689Skan sync_compare_and_swap[i] = CODE_FOR_nothing; 5357169689Skan sync_compare_and_swap_cc[i] = CODE_FOR_nothing; 5358169689Skan sync_lock_test_and_set[i] = CODE_FOR_nothing; 5359169689Skan sync_lock_release[i] = CODE_FOR_nothing; 5360169689Skan 536118334Speter reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing; 536218334Speter } 536318334Speter 536418334Speter /* Fill in the optabs with the insns we support. */ 536518334Speter init_all_optabs (); 536618334Speter 536718334Speter /* Initialize the optabs with the names of the library functions. */ 536818334Speter init_integral_libfuncs (add_optab, "add", '3'); 536918334Speter init_floating_libfuncs (add_optab, "add", '3'); 537090075Sobrien init_integral_libfuncs (addv_optab, "addv", '3'); 537190075Sobrien init_floating_libfuncs (addv_optab, "add", '3'); 537218334Speter init_integral_libfuncs (sub_optab, "sub", '3'); 537318334Speter init_floating_libfuncs (sub_optab, "sub", '3'); 537490075Sobrien init_integral_libfuncs (subv_optab, "subv", '3'); 537590075Sobrien init_floating_libfuncs (subv_optab, "sub", '3'); 537618334Speter init_integral_libfuncs (smul_optab, "mul", '3'); 537718334Speter init_floating_libfuncs (smul_optab, "mul", '3'); 537890075Sobrien init_integral_libfuncs (smulv_optab, "mulv", '3'); 537990075Sobrien init_floating_libfuncs (smulv_optab, "mul", '3'); 538018334Speter init_integral_libfuncs (sdiv_optab, "div", '3'); 538190075Sobrien init_floating_libfuncs (sdiv_optab, "div", '3'); 538290075Sobrien init_integral_libfuncs (sdivv_optab, "divv", '3'); 538318334Speter init_integral_libfuncs (udiv_optab, "udiv", '3'); 538418334Speter init_integral_libfuncs (sdivmod_optab, "divmod", '4'); 538518334Speter init_integral_libfuncs (udivmod_optab, "udivmod", '4'); 538618334Speter init_integral_libfuncs (smod_optab, "mod", '3'); 538718334Speter init_integral_libfuncs (umod_optab, "umod", '3'); 538818334Speter init_floating_libfuncs (ftrunc_optab, "ftrunc", '2'); 538918334Speter init_integral_libfuncs (and_optab, "and", '3'); 539018334Speter init_integral_libfuncs (ior_optab, "ior", '3'); 539118334Speter init_integral_libfuncs (xor_optab, "xor", '3'); 539218334Speter init_integral_libfuncs (ashl_optab, "ashl", '3'); 539318334Speter init_integral_libfuncs (ashr_optab, "ashr", '3'); 539418334Speter init_integral_libfuncs (lshr_optab, "lshr", '3'); 539518334Speter init_integral_libfuncs (smin_optab, "min", '3'); 539618334Speter init_floating_libfuncs (smin_optab, "min", '3'); 539718334Speter init_integral_libfuncs (smax_optab, "max", '3'); 539818334Speter init_floating_libfuncs (smax_optab, "max", '3'); 539918334Speter init_integral_libfuncs (umin_optab, "umin", '3'); 540018334Speter init_integral_libfuncs (umax_optab, "umax", '3'); 540118334Speter init_integral_libfuncs (neg_optab, "neg", '2'); 540218334Speter init_floating_libfuncs (neg_optab, "neg", '2'); 540390075Sobrien init_integral_libfuncs (negv_optab, "negv", '2'); 540490075Sobrien init_floating_libfuncs (negv_optab, "neg", '2'); 540518334Speter init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2'); 540618334Speter init_integral_libfuncs (ffs_optab, "ffs", '2'); 5407132718Skan init_integral_libfuncs (clz_optab, "clz", '2'); 5408132718Skan init_integral_libfuncs (ctz_optab, "ctz", '2'); 5409132718Skan init_integral_libfuncs (popcount_optab, "popcount", '2'); 5410132718Skan init_integral_libfuncs (parity_optab, "parity", '2'); 541118334Speter 5412169689Skan /* Comparison libcalls for integers MUST come in pairs, 5413169689Skan signed/unsigned. */ 541418334Speter init_integral_libfuncs (cmp_optab, "cmp", '2'); 541518334Speter init_integral_libfuncs (ucmp_optab, "ucmp", '2'); 541618334Speter init_floating_libfuncs (cmp_optab, "cmp", '2'); 541718334Speter 5418132718Skan /* EQ etc are floating point only. */ 5419132718Skan init_floating_libfuncs (eq_optab, "eq", '2'); 5420132718Skan init_floating_libfuncs (ne_optab, "ne", '2'); 5421132718Skan init_floating_libfuncs (gt_optab, "gt", '2'); 5422132718Skan init_floating_libfuncs (ge_optab, "ge", '2'); 5423132718Skan init_floating_libfuncs (lt_optab, "lt", '2'); 5424132718Skan init_floating_libfuncs (le_optab, "le", '2'); 5425132718Skan init_floating_libfuncs (unord_optab, "unord", '2'); 542618334Speter 5427169689Skan init_floating_libfuncs (powi_optab, "powi", '2'); 5428169689Skan 5429132718Skan /* Conversions. */ 5430169689Skan init_interclass_conv_libfuncs (sfloat_optab, "float", 5431169689Skan MODE_INT, MODE_FLOAT); 5432169689Skan init_interclass_conv_libfuncs (sfloat_optab, "float", 5433169689Skan MODE_INT, MODE_DECIMAL_FLOAT); 5434169689Skan init_interclass_conv_libfuncs (ufloat_optab, "floatun", 5435169689Skan MODE_INT, MODE_FLOAT); 5436169689Skan init_interclass_conv_libfuncs (ufloat_optab, "floatun", 5437169689Skan MODE_INT, MODE_DECIMAL_FLOAT); 5438169689Skan init_interclass_conv_libfuncs (sfix_optab, "fix", 5439169689Skan MODE_FLOAT, MODE_INT); 5440169689Skan init_interclass_conv_libfuncs (sfix_optab, "fix", 5441169689Skan MODE_DECIMAL_FLOAT, MODE_INT); 5442169689Skan init_interclass_conv_libfuncs (ufix_optab, "fixuns", 5443169689Skan MODE_FLOAT, MODE_INT); 5444169689Skan init_interclass_conv_libfuncs (ufix_optab, "fixuns", 5445169689Skan MODE_DECIMAL_FLOAT, MODE_INT); 5446169689Skan init_interclass_conv_libfuncs (ufloat_optab, "floatuns", 5447169689Skan MODE_INT, MODE_DECIMAL_FLOAT); 544818334Speter 5449132718Skan /* sext_optab is also used for FLOAT_EXTEND. */ 5450132718Skan init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true); 5451169689Skan init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, true); 5452169689Skan init_interclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, MODE_DECIMAL_FLOAT); 5453169689Skan init_interclass_conv_libfuncs (sext_optab, "extend", MODE_DECIMAL_FLOAT, MODE_FLOAT); 5454132718Skan init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false); 5455169689Skan init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, false); 5456169689Skan init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, MODE_DECIMAL_FLOAT); 5457169689Skan init_interclass_conv_libfuncs (trunc_optab, "trunc", MODE_DECIMAL_FLOAT, MODE_FLOAT); 545818334Speter 5459132718Skan /* Use cabs for double complex abs, since systems generally have cabs. 5460132718Skan Don't define any libcall for float complex, so that cabs will be used. */ 5461132718Skan if (complex_double_type_node) 5462132718Skan abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc 5463132718Skan = init_one_libfunc ("cabs"); 546418334Speter 546518334Speter /* The ffs function operates on `int'. */ 546690075Sobrien ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc 546790075Sobrien = init_one_libfunc ("ffs"); 546818334Speter 546996263Sobrien abort_libfunc = init_one_libfunc ("abort"); 547090075Sobrien memcpy_libfunc = init_one_libfunc ("memcpy"); 547190075Sobrien memmove_libfunc = init_one_libfunc ("memmove"); 547290075Sobrien memcmp_libfunc = init_one_libfunc ("memcmp"); 547390075Sobrien memset_libfunc = init_one_libfunc ("memset"); 5474132718Skan setbits_libfunc = init_one_libfunc ("__setbits"); 547518334Speter 547650397Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 547790075Sobrien setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); 547890075Sobrien longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); 547950397Sobrien#else 548090075Sobrien setjmp_libfunc = init_one_libfunc ("setjmp"); 548190075Sobrien longjmp_libfunc = init_one_libfunc ("longjmp"); 548250397Sobrien#endif 548390075Sobrien unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register"); 548490075Sobrien unwind_sjlj_unregister_libfunc 548590075Sobrien = init_one_libfunc ("_Unwind_SjLj_Unregister"); 548618334Speter 548752284Sobrien /* For function entry/exit instrumentation. */ 548852284Sobrien profile_function_entry_libfunc 548990075Sobrien = init_one_libfunc ("__cyg_profile_func_enter"); 549052284Sobrien profile_function_exit_libfunc 549190075Sobrien = init_one_libfunc ("__cyg_profile_func_exit"); 549252284Sobrien 5493132718Skan gcov_flush_libfunc = init_one_libfunc ("__gcov_flush"); 5494132718Skan 5495117395Skan if (HAVE_conditional_trap) 5496117395Skan trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX); 549750397Sobrien 549818334Speter /* Allow the target to add more libcalls or rename some, etc. */ 5499132718Skan targetm.init_libfuncs (); 550018334Speter} 5501169689Skan 5502169689Skan#ifdef DEBUG 5503169689Skan 5504169689Skan/* Print information about the current contents of the optabs on 5505169689Skan STDERR. */ 5506169689Skan 5507169689Skanstatic void 5508169689Skandebug_optab_libfuncs (void) 5509169689Skan{ 5510169689Skan int i; 5511169689Skan int j; 5512169689Skan int k; 5513169689Skan 5514169689Skan /* Dump the arithmetic optabs. */ 5515169689Skan for (i = 0; i != (int) OTI_MAX; i++) 5516169689Skan for (j = 0; j < NUM_MACHINE_MODES; ++j) 5517169689Skan { 5518169689Skan optab o; 5519169689Skan struct optab_handlers *h; 5520169689Skan 5521169689Skan o = optab_table[i]; 5522169689Skan h = &o->handlers[j]; 5523169689Skan if (h->libfunc) 5524169689Skan { 5525169689Skan gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF); 5526169689Skan fprintf (stderr, "%s\t%s:\t%s\n", 5527169689Skan GET_RTX_NAME (o->code), 5528169689Skan GET_MODE_NAME (j), 5529169689Skan XSTR (h->libfunc, 0)); 5530169689Skan } 5531169689Skan } 5532169689Skan 5533169689Skan /* Dump the conversion optabs. */ 5534169689Skan for (i = 0; i < (int) COI_MAX; ++i) 5535169689Skan for (j = 0; j < NUM_MACHINE_MODES; ++j) 5536169689Skan for (k = 0; k < NUM_MACHINE_MODES; ++k) 5537169689Skan { 5538169689Skan convert_optab o; 5539169689Skan struct optab_handlers *h; 5540169689Skan 5541169689Skan o = &convert_optab_table[i]; 5542169689Skan h = &o->handlers[j][k]; 5543169689Skan if (h->libfunc) 5544169689Skan { 5545169689Skan gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF); 5546169689Skan fprintf (stderr, "%s\t%s\t%s:\t%s\n", 5547169689Skan GET_RTX_NAME (o->code), 5548169689Skan GET_MODE_NAME (j), 5549169689Skan GET_MODE_NAME (k), 5550169689Skan XSTR (h->libfunc, 0)); 5551169689Skan } 5552169689Skan } 5553169689Skan} 5554169689Skan 5555169689Skan#endif /* DEBUG */ 5556169689Skan 555750397Sobrien 555850397Sobrien/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition 555950397Sobrien CODE. Return 0 on failure. */ 556050397Sobrien 556150397Sobrienrtx 5562132718Skangen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1, 5563132718Skan rtx op2 ATTRIBUTE_UNUSED, rtx tcode ATTRIBUTE_UNUSED) 556450397Sobrien{ 556550397Sobrien enum machine_mode mode = GET_MODE (op1); 5566117395Skan enum insn_code icode; 5567117395Skan rtx insn; 556850397Sobrien 5569117395Skan if (!HAVE_conditional_trap) 5570117395Skan return 0; 5571117395Skan 557250397Sobrien if (mode == VOIDmode) 557350397Sobrien return 0; 557450397Sobrien 5575117395Skan icode = cmp_optab->handlers[(int) mode].insn_code; 5576117395Skan if (icode == CODE_FOR_nothing) 5577117395Skan return 0; 5578117395Skan 5579117395Skan start_sequence (); 5580117395Skan op1 = prepare_operand (icode, op1, 0, mode, mode, 0); 5581119256Skan op2 = prepare_operand (icode, op2, 1, mode, mode, 0); 5582119256Skan if (!op1 || !op2) 5583119256Skan { 5584119256Skan end_sequence (); 5585119256Skan return 0; 5586119256Skan } 5587117395Skan emit_insn (GEN_FCN (icode) (op1, op2)); 5588117395Skan 5589117395Skan PUT_CODE (trap_rtx, code); 5590169689Skan gcc_assert (HAVE_conditional_trap); 5591117395Skan insn = gen_conditional_trap (trap_rtx, tcode); 5592117395Skan if (insn) 559350397Sobrien { 5594117395Skan emit_insn (insn); 5595117395Skan insn = get_insns (); 559650397Sobrien } 5597117395Skan end_sequence (); 559850397Sobrien 5599117395Skan return insn; 560050397Sobrien} 5601117395Skan 5602169689Skan/* Return rtx code for TCODE. Use UNSIGNEDP to select signed 5603169689Skan or unsigned operation code. */ 5604169689Skan 5605169689Skanstatic enum rtx_code 5606169689Skanget_rtx_code (enum tree_code tcode, bool unsignedp) 5607169689Skan{ 5608169689Skan enum rtx_code code; 5609169689Skan switch (tcode) 5610169689Skan { 5611169689Skan case EQ_EXPR: 5612169689Skan code = EQ; 5613169689Skan break; 5614169689Skan case NE_EXPR: 5615169689Skan code = NE; 5616169689Skan break; 5617169689Skan case LT_EXPR: 5618169689Skan code = unsignedp ? LTU : LT; 5619169689Skan break; 5620169689Skan case LE_EXPR: 5621169689Skan code = unsignedp ? LEU : LE; 5622169689Skan break; 5623169689Skan case GT_EXPR: 5624169689Skan code = unsignedp ? GTU : GT; 5625169689Skan break; 5626169689Skan case GE_EXPR: 5627169689Skan code = unsignedp ? GEU : GE; 5628169689Skan break; 5629169689Skan 5630169689Skan case UNORDERED_EXPR: 5631169689Skan code = UNORDERED; 5632169689Skan break; 5633169689Skan case ORDERED_EXPR: 5634169689Skan code = ORDERED; 5635169689Skan break; 5636169689Skan case UNLT_EXPR: 5637169689Skan code = UNLT; 5638169689Skan break; 5639169689Skan case UNLE_EXPR: 5640169689Skan code = UNLE; 5641169689Skan break; 5642169689Skan case UNGT_EXPR: 5643169689Skan code = UNGT; 5644169689Skan break; 5645169689Skan case UNGE_EXPR: 5646169689Skan code = UNGE; 5647169689Skan break; 5648169689Skan case UNEQ_EXPR: 5649169689Skan code = UNEQ; 5650169689Skan break; 5651169689Skan case LTGT_EXPR: 5652169689Skan code = LTGT; 5653169689Skan break; 5654169689Skan 5655169689Skan default: 5656169689Skan gcc_unreachable (); 5657169689Skan } 5658169689Skan return code; 5659169689Skan} 5660169689Skan 5661169689Skan/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or 5662169689Skan unsigned operators. Do not generate compare instruction. */ 5663169689Skan 5664169689Skanstatic rtx 5665169689Skanvector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode) 5666169689Skan{ 5667169689Skan enum rtx_code rcode; 5668169689Skan tree t_op0, t_op1; 5669169689Skan rtx rtx_op0, rtx_op1; 5670169689Skan 5671169689Skan /* This is unlikely. While generating VEC_COND_EXPR, auto vectorizer 5672169689Skan ensures that condition is a relational operation. */ 5673169689Skan gcc_assert (COMPARISON_CLASS_P (cond)); 5674169689Skan 5675169689Skan rcode = get_rtx_code (TREE_CODE (cond), unsignedp); 5676169689Skan t_op0 = TREE_OPERAND (cond, 0); 5677169689Skan t_op1 = TREE_OPERAND (cond, 1); 5678169689Skan 5679169689Skan /* Expand operands. */ 5680169689Skan rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1); 5681169689Skan rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1); 5682169689Skan 5683169689Skan if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0)) 5684169689Skan && GET_MODE (rtx_op0) != VOIDmode) 5685169689Skan rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0); 5686169689Skan 5687169689Skan if (!insn_data[icode].operand[5].predicate (rtx_op1, GET_MODE (rtx_op1)) 5688169689Skan && GET_MODE (rtx_op1) != VOIDmode) 5689169689Skan rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1); 5690169689Skan 5691169689Skan return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1); 5692169689Skan} 5693169689Skan 5694169689Skan/* Return insn code for VEC_COND_EXPR EXPR. */ 5695169689Skan 5696169689Skanstatic inline enum insn_code 5697169689Skanget_vcond_icode (tree expr, enum machine_mode mode) 5698169689Skan{ 5699169689Skan enum insn_code icode = CODE_FOR_nothing; 5700169689Skan 5701169689Skan if (TYPE_UNSIGNED (TREE_TYPE (expr))) 5702169689Skan icode = vcondu_gen_code[mode]; 5703169689Skan else 5704169689Skan icode = vcond_gen_code[mode]; 5705169689Skan return icode; 5706169689Skan} 5707169689Skan 5708169689Skan/* Return TRUE iff, appropriate vector insns are available 5709169689Skan for vector cond expr expr in VMODE mode. */ 5710169689Skan 5711169689Skanbool 5712169689Skanexpand_vec_cond_expr_p (tree expr, enum machine_mode vmode) 5713169689Skan{ 5714169689Skan if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing) 5715169689Skan return false; 5716169689Skan return true; 5717169689Skan} 5718169689Skan 5719169689Skan/* Generate insns for VEC_COND_EXPR. */ 5720169689Skan 5721169689Skanrtx 5722169689Skanexpand_vec_cond_expr (tree vec_cond_expr, rtx target) 5723169689Skan{ 5724169689Skan enum insn_code icode; 5725169689Skan rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1; 5726169689Skan enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr)); 5727169689Skan bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr)); 5728169689Skan 5729169689Skan icode = get_vcond_icode (vec_cond_expr, mode); 5730169689Skan if (icode == CODE_FOR_nothing) 5731169689Skan return 0; 5732169689Skan 5733169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 5734169689Skan target = gen_reg_rtx (mode); 5735169689Skan 5736169689Skan /* Get comparison rtx. First expand both cond expr operands. */ 5737169689Skan comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0), 5738169689Skan unsignedp, icode); 5739169689Skan cc_op0 = XEXP (comparison, 0); 5740169689Skan cc_op1 = XEXP (comparison, 1); 5741169689Skan /* Expand both operands and force them in reg, if required. */ 5742169689Skan rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1), 5743169689Skan NULL_RTX, VOIDmode, EXPAND_NORMAL); 5744169689Skan if (!insn_data[icode].operand[1].predicate (rtx_op1, mode) 5745169689Skan && mode != VOIDmode) 5746169689Skan rtx_op1 = force_reg (mode, rtx_op1); 5747169689Skan 5748169689Skan rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2), 5749169689Skan NULL_RTX, VOIDmode, EXPAND_NORMAL); 5750169689Skan if (!insn_data[icode].operand[2].predicate (rtx_op2, mode) 5751169689Skan && mode != VOIDmode) 5752169689Skan rtx_op2 = force_reg (mode, rtx_op2); 5753169689Skan 5754169689Skan /* Emit instruction! */ 5755169689Skan emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, 5756169689Skan comparison, cc_op0, cc_op1)); 5757169689Skan 5758169689Skan return target; 5759169689Skan} 5760169689Skan 5761169689Skan 5762169689Skan/* This is an internal subroutine of the other compare_and_swap expanders. 5763169689Skan MEM, OLD_VAL and NEW_VAL are as you'd expect for a compare-and-swap 5764169689Skan operation. TARGET is an optional place to store the value result of 5765169689Skan the operation. ICODE is the particular instruction to expand. Return 5766169689Skan the result of the operation. */ 5767169689Skan 5768169689Skanstatic rtx 5769169689Skanexpand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val, 5770169689Skan rtx target, enum insn_code icode) 5771169689Skan{ 5772169689Skan enum machine_mode mode = GET_MODE (mem); 5773169689Skan rtx insn; 5774169689Skan 5775169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 5776169689Skan target = gen_reg_rtx (mode); 5777169689Skan 5778169689Skan if (GET_MODE (old_val) != VOIDmode && GET_MODE (old_val) != mode) 5779169689Skan old_val = convert_modes (mode, GET_MODE (old_val), old_val, 1); 5780169689Skan if (!insn_data[icode].operand[2].predicate (old_val, mode)) 5781169689Skan old_val = force_reg (mode, old_val); 5782169689Skan 5783169689Skan if (GET_MODE (new_val) != VOIDmode && GET_MODE (new_val) != mode) 5784169689Skan new_val = convert_modes (mode, GET_MODE (new_val), new_val, 1); 5785169689Skan if (!insn_data[icode].operand[3].predicate (new_val, mode)) 5786169689Skan new_val = force_reg (mode, new_val); 5787169689Skan 5788169689Skan insn = GEN_FCN (icode) (target, mem, old_val, new_val); 5789169689Skan if (insn == NULL_RTX) 5790169689Skan return NULL_RTX; 5791169689Skan emit_insn (insn); 5792169689Skan 5793169689Skan return target; 5794169689Skan} 5795169689Skan 5796169689Skan/* Expand a compare-and-swap operation and return its value. */ 5797169689Skan 5798169689Skanrtx 5799169689Skanexpand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) 5800169689Skan{ 5801169689Skan enum machine_mode mode = GET_MODE (mem); 5802169689Skan enum insn_code icode = sync_compare_and_swap[mode]; 5803169689Skan 5804169689Skan if (icode == CODE_FOR_nothing) 5805169689Skan return NULL_RTX; 5806169689Skan 5807169689Skan return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode); 5808169689Skan} 5809169689Skan 5810169689Skan/* Expand a compare-and-swap operation and store true into the result if 5811169689Skan the operation was successful and false otherwise. Return the result. 5812169689Skan Unlike other routines, TARGET is not optional. */ 5813169689Skan 5814169689Skanrtx 5815169689Skanexpand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) 5816169689Skan{ 5817169689Skan enum machine_mode mode = GET_MODE (mem); 5818169689Skan enum insn_code icode; 5819169689Skan rtx subtarget, label0, label1; 5820169689Skan 5821169689Skan /* If the target supports a compare-and-swap pattern that simultaneously 5822169689Skan sets some flag for success, then use it. Otherwise use the regular 5823169689Skan compare-and-swap and follow that immediately with a compare insn. */ 5824169689Skan icode = sync_compare_and_swap_cc[mode]; 5825169689Skan switch (icode) 5826169689Skan { 5827169689Skan default: 5828169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val, 5829169689Skan NULL_RTX, icode); 5830169689Skan if (subtarget != NULL_RTX) 5831169689Skan break; 5832169689Skan 5833169689Skan /* FALLTHRU */ 5834169689Skan case CODE_FOR_nothing: 5835169689Skan icode = sync_compare_and_swap[mode]; 5836169689Skan if (icode == CODE_FOR_nothing) 5837169689Skan return NULL_RTX; 5838169689Skan 5839169689Skan /* Ensure that if old_val == mem, that we're not comparing 5840169689Skan against an old value. */ 5841169689Skan if (MEM_P (old_val)) 5842169689Skan old_val = force_reg (mode, old_val); 5843169689Skan 5844169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val, 5845169689Skan NULL_RTX, icode); 5846169689Skan if (subtarget == NULL_RTX) 5847169689Skan return NULL_RTX; 5848169689Skan 5849169689Skan emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true); 5850169689Skan } 5851169689Skan 5852169689Skan /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a 5853169689Skan setcc instruction from the beginning. We don't work too hard here, 5854169689Skan but it's nice to not be stupid about initial code gen either. */ 5855169689Skan if (STORE_FLAG_VALUE == 1) 5856169689Skan { 5857169689Skan icode = setcc_gen_code[EQ]; 5858169689Skan if (icode != CODE_FOR_nothing) 5859169689Skan { 5860169689Skan enum machine_mode cmode = insn_data[icode].operand[0].mode; 5861169689Skan rtx insn; 5862169689Skan 5863169689Skan subtarget = target; 5864169689Skan if (!insn_data[icode].operand[0].predicate (target, cmode)) 5865169689Skan subtarget = gen_reg_rtx (cmode); 5866169689Skan 5867169689Skan insn = GEN_FCN (icode) (subtarget); 5868169689Skan if (insn) 5869169689Skan { 5870169689Skan emit_insn (insn); 5871169689Skan if (GET_MODE (target) != GET_MODE (subtarget)) 5872169689Skan { 5873169689Skan convert_move (target, subtarget, 1); 5874169689Skan subtarget = target; 5875169689Skan } 5876169689Skan return subtarget; 5877169689Skan } 5878169689Skan } 5879169689Skan } 5880169689Skan 5881169689Skan /* Without an appropriate setcc instruction, use a set of branches to 5882169689Skan get 1 and 0 stored into target. Presumably if the target has a 5883169689Skan STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt. */ 5884169689Skan 5885169689Skan label0 = gen_label_rtx (); 5886169689Skan label1 = gen_label_rtx (); 5887169689Skan 5888169689Skan emit_jump_insn (bcc_gen_fctn[EQ] (label0)); 5889169689Skan emit_move_insn (target, const0_rtx); 5890169689Skan emit_jump_insn (gen_jump (label1)); 5891169689Skan emit_barrier (); 5892169689Skan emit_label (label0); 5893169689Skan emit_move_insn (target, const1_rtx); 5894169689Skan emit_label (label1); 5895169689Skan 5896169689Skan return target; 5897169689Skan} 5898169689Skan 5899169689Skan/* This is a helper function for the other atomic operations. This function 5900169689Skan emits a loop that contains SEQ that iterates until a compare-and-swap 5901169689Skan operation at the end succeeds. MEM is the memory to be modified. SEQ is 5902169689Skan a set of instructions that takes a value from OLD_REG as an input and 5903169689Skan produces a value in NEW_REG as an output. Before SEQ, OLD_REG will be 5904169689Skan set to the current contents of MEM. After SEQ, a compare-and-swap will 5905169689Skan attempt to update MEM with NEW_REG. The function returns true when the 5906169689Skan loop was generated successfully. */ 5907169689Skan 5908169689Skanstatic bool 5909169689Skanexpand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq) 5910169689Skan{ 5911169689Skan enum machine_mode mode = GET_MODE (mem); 5912169689Skan enum insn_code icode; 5913169689Skan rtx label, cmp_reg, subtarget; 5914169689Skan 5915169689Skan /* The loop we want to generate looks like 5916169689Skan 5917169689Skan cmp_reg = mem; 5918169689Skan label: 5919169689Skan old_reg = cmp_reg; 5920169689Skan seq; 5921169689Skan cmp_reg = compare-and-swap(mem, old_reg, new_reg) 5922169689Skan if (cmp_reg != old_reg) 5923169689Skan goto label; 5924169689Skan 5925169689Skan Note that we only do the plain load from memory once. Subsequent 5926169689Skan iterations use the value loaded by the compare-and-swap pattern. */ 5927169689Skan 5928169689Skan label = gen_label_rtx (); 5929169689Skan cmp_reg = gen_reg_rtx (mode); 5930169689Skan 5931169689Skan emit_move_insn (cmp_reg, mem); 5932169689Skan emit_label (label); 5933169689Skan emit_move_insn (old_reg, cmp_reg); 5934169689Skan if (seq) 5935169689Skan emit_insn (seq); 5936169689Skan 5937169689Skan /* If the target supports a compare-and-swap pattern that simultaneously 5938169689Skan sets some flag for success, then use it. Otherwise use the regular 5939169689Skan compare-and-swap and follow that immediately with a compare insn. */ 5940169689Skan icode = sync_compare_and_swap_cc[mode]; 5941169689Skan switch (icode) 5942169689Skan { 5943169689Skan default: 5944169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg, 5945169689Skan cmp_reg, icode); 5946169689Skan if (subtarget != NULL_RTX) 5947169689Skan { 5948169689Skan gcc_assert (subtarget == cmp_reg); 5949169689Skan break; 5950169689Skan } 5951169689Skan 5952169689Skan /* FALLTHRU */ 5953169689Skan case CODE_FOR_nothing: 5954169689Skan icode = sync_compare_and_swap[mode]; 5955169689Skan if (icode == CODE_FOR_nothing) 5956169689Skan return false; 5957169689Skan 5958169689Skan subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg, 5959169689Skan cmp_reg, icode); 5960169689Skan if (subtarget == NULL_RTX) 5961169689Skan return false; 5962169689Skan if (subtarget != cmp_reg) 5963169689Skan emit_move_insn (cmp_reg, subtarget); 5964169689Skan 5965169689Skan emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true); 5966169689Skan } 5967169689Skan 5968169689Skan /* ??? Mark this jump predicted not taken? */ 5969169689Skan emit_jump_insn (bcc_gen_fctn[NE] (label)); 5970169689Skan 5971169689Skan return true; 5972169689Skan} 5973169689Skan 5974169689Skan/* This function generates the atomic operation MEM CODE= VAL. In this 5975169689Skan case, we do not care about any resulting value. Returns NULL if we 5976169689Skan cannot generate the operation. */ 5977169689Skan 5978169689Skanrtx 5979169689Skanexpand_sync_operation (rtx mem, rtx val, enum rtx_code code) 5980169689Skan{ 5981169689Skan enum machine_mode mode = GET_MODE (mem); 5982169689Skan enum insn_code icode; 5983169689Skan rtx insn; 5984169689Skan 5985169689Skan /* Look to see if the target supports the operation directly. */ 5986169689Skan switch (code) 5987169689Skan { 5988169689Skan case PLUS: 5989169689Skan icode = sync_add_optab[mode]; 5990169689Skan break; 5991169689Skan case IOR: 5992169689Skan icode = sync_ior_optab[mode]; 5993169689Skan break; 5994169689Skan case XOR: 5995169689Skan icode = sync_xor_optab[mode]; 5996169689Skan break; 5997169689Skan case AND: 5998169689Skan icode = sync_and_optab[mode]; 5999169689Skan break; 6000169689Skan case NOT: 6001169689Skan icode = sync_nand_optab[mode]; 6002169689Skan break; 6003169689Skan 6004169689Skan case MINUS: 6005169689Skan icode = sync_sub_optab[mode]; 6006169689Skan if (icode == CODE_FOR_nothing) 6007169689Skan { 6008169689Skan icode = sync_add_optab[mode]; 6009169689Skan if (icode != CODE_FOR_nothing) 6010169689Skan { 6011169689Skan val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1); 6012169689Skan code = PLUS; 6013169689Skan } 6014169689Skan } 6015169689Skan break; 6016169689Skan 6017169689Skan default: 6018169689Skan gcc_unreachable (); 6019169689Skan } 6020169689Skan 6021169689Skan /* Generate the direct operation, if present. */ 6022169689Skan if (icode != CODE_FOR_nothing) 6023169689Skan { 6024169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6025169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6026169689Skan if (!insn_data[icode].operand[1].predicate (val, mode)) 6027169689Skan val = force_reg (mode, val); 6028169689Skan 6029169689Skan insn = GEN_FCN (icode) (mem, val); 6030169689Skan if (insn) 6031169689Skan { 6032169689Skan emit_insn (insn); 6033169689Skan return const0_rtx; 6034169689Skan } 6035169689Skan } 6036169689Skan 6037169689Skan /* Failing that, generate a compare-and-swap loop in which we perform the 6038169689Skan operation with normal arithmetic instructions. */ 6039169689Skan if (sync_compare_and_swap[mode] != CODE_FOR_nothing) 6040169689Skan { 6041169689Skan rtx t0 = gen_reg_rtx (mode), t1; 6042169689Skan 6043169689Skan start_sequence (); 6044169689Skan 6045169689Skan t1 = t0; 6046169689Skan if (code == NOT) 6047169689Skan { 6048169689Skan t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true); 6049169689Skan code = AND; 6050169689Skan } 6051169689Skan t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, 6052169689Skan true, OPTAB_LIB_WIDEN); 6053169689Skan 6054169689Skan insn = get_insns (); 6055169689Skan end_sequence (); 6056169689Skan 6057169689Skan if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn)) 6058169689Skan return const0_rtx; 6059169689Skan } 6060169689Skan 6061169689Skan return NULL_RTX; 6062169689Skan} 6063169689Skan 6064169689Skan/* This function generates the atomic operation MEM CODE= VAL. In this 6065169689Skan case, we do care about the resulting value: if AFTER is true then 6066169689Skan return the value MEM holds after the operation, if AFTER is false 6067169689Skan then return the value MEM holds before the operation. TARGET is an 6068169689Skan optional place for the result value to be stored. */ 6069169689Skan 6070169689Skanrtx 6071169689Skanexpand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code, 6072169689Skan bool after, rtx target) 6073169689Skan{ 6074169689Skan enum machine_mode mode = GET_MODE (mem); 6075169689Skan enum insn_code old_code, new_code, icode; 6076169689Skan bool compensate; 6077169689Skan rtx insn; 6078169689Skan 6079169689Skan /* Look to see if the target supports the operation directly. */ 6080169689Skan switch (code) 6081169689Skan { 6082169689Skan case PLUS: 6083169689Skan old_code = sync_old_add_optab[mode]; 6084169689Skan new_code = sync_new_add_optab[mode]; 6085169689Skan break; 6086169689Skan case IOR: 6087169689Skan old_code = sync_old_ior_optab[mode]; 6088169689Skan new_code = sync_new_ior_optab[mode]; 6089169689Skan break; 6090169689Skan case XOR: 6091169689Skan old_code = sync_old_xor_optab[mode]; 6092169689Skan new_code = sync_new_xor_optab[mode]; 6093169689Skan break; 6094169689Skan case AND: 6095169689Skan old_code = sync_old_and_optab[mode]; 6096169689Skan new_code = sync_new_and_optab[mode]; 6097169689Skan break; 6098169689Skan case NOT: 6099169689Skan old_code = sync_old_nand_optab[mode]; 6100169689Skan new_code = sync_new_nand_optab[mode]; 6101169689Skan break; 6102169689Skan 6103169689Skan case MINUS: 6104169689Skan old_code = sync_old_sub_optab[mode]; 6105169689Skan new_code = sync_new_sub_optab[mode]; 6106169689Skan if (old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing) 6107169689Skan { 6108169689Skan old_code = sync_old_add_optab[mode]; 6109169689Skan new_code = sync_new_add_optab[mode]; 6110169689Skan if (old_code != CODE_FOR_nothing || new_code != CODE_FOR_nothing) 6111169689Skan { 6112169689Skan val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1); 6113169689Skan code = PLUS; 6114169689Skan } 6115169689Skan } 6116169689Skan break; 6117169689Skan 6118169689Skan default: 6119169689Skan gcc_unreachable (); 6120169689Skan } 6121169689Skan 6122169689Skan /* If the target does supports the proper new/old operation, great. But 6123169689Skan if we only support the opposite old/new operation, check to see if we 6124169689Skan can compensate. In the case in which the old value is supported, then 6125169689Skan we can always perform the operation again with normal arithmetic. In 6126169689Skan the case in which the new value is supported, then we can only handle 6127169689Skan this in the case the operation is reversible. */ 6128169689Skan compensate = false; 6129169689Skan if (after) 6130169689Skan { 6131169689Skan icode = new_code; 6132169689Skan if (icode == CODE_FOR_nothing) 6133169689Skan { 6134169689Skan icode = old_code; 6135169689Skan if (icode != CODE_FOR_nothing) 6136169689Skan compensate = true; 6137169689Skan } 6138169689Skan } 6139169689Skan else 6140169689Skan { 6141169689Skan icode = old_code; 6142169689Skan if (icode == CODE_FOR_nothing 6143169689Skan && (code == PLUS || code == MINUS || code == XOR)) 6144169689Skan { 6145169689Skan icode = new_code; 6146169689Skan if (icode != CODE_FOR_nothing) 6147169689Skan compensate = true; 6148169689Skan } 6149169689Skan } 6150169689Skan 6151169689Skan /* If we found something supported, great. */ 6152169689Skan if (icode != CODE_FOR_nothing) 6153169689Skan { 6154169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 6155169689Skan target = gen_reg_rtx (mode); 6156169689Skan 6157169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6158169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6159169689Skan if (!insn_data[icode].operand[2].predicate (val, mode)) 6160169689Skan val = force_reg (mode, val); 6161169689Skan 6162169689Skan insn = GEN_FCN (icode) (target, mem, val); 6163169689Skan if (insn) 6164169689Skan { 6165169689Skan emit_insn (insn); 6166169689Skan 6167169689Skan /* If we need to compensate for using an operation with the 6168169689Skan wrong return value, do so now. */ 6169169689Skan if (compensate) 6170169689Skan { 6171169689Skan if (!after) 6172169689Skan { 6173169689Skan if (code == PLUS) 6174169689Skan code = MINUS; 6175169689Skan else if (code == MINUS) 6176169689Skan code = PLUS; 6177169689Skan } 6178169689Skan 6179169689Skan if (code == NOT) 6180169689Skan target = expand_simple_unop (mode, NOT, target, NULL_RTX, true); 6181169689Skan target = expand_simple_binop (mode, code, target, val, NULL_RTX, 6182169689Skan true, OPTAB_LIB_WIDEN); 6183169689Skan } 6184169689Skan 6185169689Skan return target; 6186169689Skan } 6187169689Skan } 6188169689Skan 6189169689Skan /* Failing that, generate a compare-and-swap loop in which we perform the 6190169689Skan operation with normal arithmetic instructions. */ 6191169689Skan if (sync_compare_and_swap[mode] != CODE_FOR_nothing) 6192169689Skan { 6193169689Skan rtx t0 = gen_reg_rtx (mode), t1; 6194169689Skan 6195169689Skan if (!target || !register_operand (target, mode)) 6196169689Skan target = gen_reg_rtx (mode); 6197169689Skan 6198169689Skan start_sequence (); 6199169689Skan 6200169689Skan if (!after) 6201169689Skan emit_move_insn (target, t0); 6202169689Skan t1 = t0; 6203169689Skan if (code == NOT) 6204169689Skan { 6205169689Skan t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true); 6206169689Skan code = AND; 6207169689Skan } 6208169689Skan t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, 6209169689Skan true, OPTAB_LIB_WIDEN); 6210169689Skan if (after) 6211169689Skan emit_move_insn (target, t1); 6212169689Skan 6213169689Skan insn = get_insns (); 6214169689Skan end_sequence (); 6215169689Skan 6216169689Skan if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn)) 6217169689Skan return target; 6218169689Skan } 6219169689Skan 6220169689Skan return NULL_RTX; 6221169689Skan} 6222169689Skan 6223169689Skan/* This function expands a test-and-set operation. Ideally we atomically 6224169689Skan store VAL in MEM and return the previous value in MEM. Some targets 6225169689Skan may not support this operation and only support VAL with the constant 1; 6226169689Skan in this case while the return value will be 0/1, but the exact value 6227169689Skan stored in MEM is target defined. TARGET is an option place to stick 6228169689Skan the return value. */ 6229169689Skan 6230169689Skanrtx 6231169689Skanexpand_sync_lock_test_and_set (rtx mem, rtx val, rtx target) 6232169689Skan{ 6233169689Skan enum machine_mode mode = GET_MODE (mem); 6234169689Skan enum insn_code icode; 6235169689Skan rtx insn; 6236169689Skan 6237169689Skan /* If the target supports the test-and-set directly, great. */ 6238169689Skan icode = sync_lock_test_and_set[mode]; 6239169689Skan if (icode != CODE_FOR_nothing) 6240169689Skan { 6241169689Skan if (!target || !insn_data[icode].operand[0].predicate (target, mode)) 6242169689Skan target = gen_reg_rtx (mode); 6243169689Skan 6244169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6245169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6246169689Skan if (!insn_data[icode].operand[2].predicate (val, mode)) 6247169689Skan val = force_reg (mode, val); 6248169689Skan 6249169689Skan insn = GEN_FCN (icode) (target, mem, val); 6250169689Skan if (insn) 6251169689Skan { 6252169689Skan emit_insn (insn); 6253169689Skan return target; 6254169689Skan } 6255169689Skan } 6256169689Skan 6257169689Skan /* Otherwise, use a compare-and-swap loop for the exchange. */ 6258169689Skan if (sync_compare_and_swap[mode] != CODE_FOR_nothing) 6259169689Skan { 6260169689Skan if (!target || !register_operand (target, mode)) 6261169689Skan target = gen_reg_rtx (mode); 6262169689Skan if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) 6263169689Skan val = convert_modes (mode, GET_MODE (val), val, 1); 6264169689Skan if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX)) 6265169689Skan return target; 6266169689Skan } 6267169689Skan 6268169689Skan return NULL_RTX; 6269169689Skan} 6270169689Skan 6271117395Skan#include "gt-optabs.h" 6272